@appium/support 2.54.2 → 2.55.3

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.
Files changed (43) hide show
  1. package/build/lib/fs.js +1 -1
  2. package/build/lib/image-util.js +17 -10
  3. package/build/lib/index.js +98 -0
  4. package/build/lib/log-internal.js +1 -1
  5. package/build/lib/logging.js +4 -3
  6. package/build/lib/net.js +6 -4
  7. package/build/lib/plist.js +4 -4
  8. package/build/lib/system.js +3 -3
  9. package/build/lib/tempdir.js +1 -1
  10. package/build/lib/timing.js +1 -1
  11. package/build/lib/util.js +17 -17
  12. package/build/lib/zip.js +25 -15
  13. package/build/test/assets/sample_binary.plist +0 -0
  14. package/build/test/assets/sample_text.plist +28 -0
  15. package/build/test/fs-specs.js +264 -0
  16. package/build/test/helpers.js +35 -0
  17. package/build/test/image-util-e2e-specs.js +227 -0
  18. package/build/test/index-specs.js +49 -0
  19. package/build/test/log-internals-specs.js +97 -0
  20. package/build/test/logger/helpers.js +71 -0
  21. package/build/test/logger/logger-force-specs.js +41 -0
  22. package/build/test/logger/logger-normal-specs.js +113 -0
  23. package/build/test/logger/logger-test-specs.js +40 -0
  24. package/build/test/mjpeg-e2e-specs.js +96 -0
  25. package/build/test/net-e2e-specs.js +32 -0
  26. package/build/test/node-e2e-specs.js +22 -0
  27. package/build/test/plist-specs.js +54 -0
  28. package/build/test/process-specs.js +104 -0
  29. package/build/test/system-specs.js +136 -0
  30. package/build/test/tempdir-specs.js +86 -0
  31. package/build/test/timing-specs.js +125 -0
  32. package/build/test/util-e2e-specs.js +136 -0
  33. package/build/test/util-specs.js +537 -0
  34. package/build/test/zip-e2e-specs.js +233 -0
  35. package/index.js +1 -28
  36. package/lib/image-util.js +15 -7
  37. package/lib/index.js +28 -0
  38. package/lib/log-internal.js +1 -1
  39. package/lib/logging.js +1 -1
  40. package/lib/net.js +5 -4
  41. package/lib/zip.js +45 -31
  42. package/package.json +9 -15
  43. package/build/index.js +0 -98
@@ -0,0 +1,264 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _index = require("../lib/index.js");
8
+
9
+ var _path = _interopRequireDefault(require("path"));
10
+
11
+ var _teen_process = require("teen_process");
12
+
13
+ var _bluebird = _interopRequireDefault(require("bluebird"));
14
+
15
+ var _lodash = _interopRequireDefault(require("lodash"));
16
+
17
+ const MOCHA_TIMEOUT = 20000;
18
+ describe('fs', function () {
19
+ this.timeout(MOCHA_TIMEOUT);
20
+
21
+ const existingPath = _path.default.resolve(__dirname, 'fs-specs.js');
22
+
23
+ it('should have expected methods', function () {
24
+ should.exist(_index.fs.open);
25
+ should.exist(_index.fs.close);
26
+ should.exist(_index.fs.access);
27
+ should.exist(_index.fs.mkdir);
28
+ should.exist(_index.fs.readlink);
29
+ should.exist(_index.fs.exists);
30
+ should.exist(_index.fs.rimraf);
31
+ should.exist(_index.fs.rimrafSync);
32
+ should.exist(_index.fs.readFile);
33
+ should.exist(_index.fs.writeFile);
34
+ should.exist(_index.fs.lstat);
35
+ should.exist(_index.fs.mv);
36
+ });
37
+ describe('mkdir', function () {
38
+ let dirName = _path.default.resolve(__dirname, 'tmp');
39
+
40
+ it('should make a directory that does not exist', async function () {
41
+ await _index.fs.rimraf(dirName);
42
+ await _index.fs.mkdir(dirName);
43
+ let exists = await _index.fs.hasAccess(dirName);
44
+ exists.should.be.true;
45
+ });
46
+ it('should not complain if the dir already exists', async function () {
47
+ let exists = await _index.fs.hasAccess(dirName);
48
+ exists.should.be.true;
49
+ await _index.fs.mkdir(dirName);
50
+ });
51
+ it('should still throw an error if something else goes wrong', async function () {
52
+ await _index.fs.mkdir('/bin/foo').should.be.rejected;
53
+ });
54
+ });
55
+ it('hasAccess', async function () {
56
+ (await _index.fs.exists(existingPath)).should.be.ok;
57
+
58
+ let nonExistingPath = _path.default.resolve(__dirname, 'wrong-specs.js');
59
+
60
+ (await _index.fs.hasAccess(nonExistingPath)).should.not.be.ok;
61
+ });
62
+ it('exists', async function () {
63
+ (await _index.fs.exists(existingPath)).should.be.ok;
64
+
65
+ let nonExistingPath = _path.default.resolve(__dirname, 'wrong-specs.js');
66
+
67
+ (await _index.fs.exists(nonExistingPath)).should.not.be.ok;
68
+ });
69
+ it('readFile', async function () {
70
+ (await _index.fs.readFile(existingPath, 'utf8')).should.contain('readFile');
71
+ });
72
+ describe('copyFile', function () {
73
+ it('should be able to copy a file', async function () {
74
+ let newPath = _path.default.resolve(await _index.tempDir.openDir(), 'fs-specs.js');
75
+
76
+ await _index.fs.copyFile(existingPath, newPath);
77
+ (await _index.fs.readFile(newPath, 'utf8')).should.contain('readFile');
78
+ });
79
+ it('should throw an error if the source does not exist', async function () {
80
+ await _index.fs.copyFile('/sdfsdfsdfsdf', '/tmp/bla').should.eventually.be.rejected;
81
+ });
82
+ });
83
+ it('rimraf', async function () {
84
+ let newPath = _path.default.resolve(await _index.tempDir.openDir(), 'fs-specs.js');
85
+
86
+ await _index.fs.copyFile(existingPath, newPath);
87
+ (await _index.fs.exists(newPath)).should.be.true;
88
+ await _index.fs.rimraf(newPath);
89
+ (await _index.fs.exists(newPath)).should.be.false;
90
+ });
91
+ it('sanitizeName', function () {
92
+ _index.fs.sanitizeName(':file?.txt', {
93
+ replacement: '-'
94
+ }).should.eql('-file-.txt');
95
+ });
96
+ it('rimrafSync', async function () {
97
+ let newPath = _path.default.resolve(await _index.tempDir.openDir(), 'fs-specs.js');
98
+
99
+ await _index.fs.copyFile(existingPath, newPath);
100
+ (await _index.fs.exists(newPath)).should.be.true;
101
+
102
+ _index.fs.rimrafSync(newPath);
103
+
104
+ (await _index.fs.exists(newPath)).should.be.false;
105
+ });
106
+ describe('md5', function () {
107
+ this.timeout(1200000);
108
+ let smallFilePath;
109
+ let bigFilePath;
110
+ before(async function () {
111
+ smallFilePath = existingPath;
112
+ bigFilePath = _path.default.resolve(await _index.tempDir.openDir(), 'enormous.txt');
113
+ let file = await _index.fs.open(bigFilePath, 'w');
114
+ let fileData = '';
115
+
116
+ for (let i = 0; i < 4096; i++) {
117
+ fileData += '1';
118
+ }
119
+
120
+ for (let i = 0; i < 40000; i++) {
121
+ await _index.fs.write(file, fileData);
122
+ }
123
+
124
+ await _index.fs.close(file);
125
+ });
126
+ after(async function () {
127
+ await _index.fs.unlink(bigFilePath);
128
+ });
129
+ it('should calculate hash of correct length', async function () {
130
+ (await _index.fs.md5(smallFilePath)).should.have.length(32);
131
+ });
132
+ it('should be able to run on huge file', async function () {
133
+ (await _index.fs.md5(bigFilePath)).should.have.length(32);
134
+ });
135
+ });
136
+ describe('hash', function () {
137
+ it('should calculate sha1 hash', async function () {
138
+ (await _index.fs.hash(existingPath, 'sha1')).should.have.length(40);
139
+ });
140
+ it('should calculate md5 hash', async function () {
141
+ (await _index.fs.hash(existingPath, 'md5')).should.have.length(32);
142
+ });
143
+ });
144
+ it('stat', async function () {
145
+ let stat = await _index.fs.stat(existingPath);
146
+ stat.should.have.property('atime');
147
+ });
148
+ describe('which', function () {
149
+ it('should find correct executable', async function () {
150
+ let systemNpmPath = (await (0, _teen_process.exec)('which', ['npm'])).stdout.trim();
151
+ let npmPath = await _index.fs.which('npm');
152
+ npmPath.should.equal(systemNpmPath);
153
+ });
154
+ it('should fail gracefully', async function () {
155
+ await _index.fs.which('something_that_does_not_exist').should.eventually.be.rejected;
156
+ });
157
+ });
158
+ it('glob', async function () {
159
+ let glob = '*-specs.js';
160
+ let tests = await _index.fs.glob(glob, {
161
+ cwd: __dirname
162
+ });
163
+ tests.should.be.an('array');
164
+ tests.should.have.length.above(2);
165
+ });
166
+ describe('walkDir', function () {
167
+ it('walkDir recursive', async function () {
168
+ let inCallback = 0;
169
+ const filePath = await _index.fs.walkDir(__dirname, true, async item => {
170
+ if (item.endsWith('logger/helpers.js')) {
171
+ ++inCallback;
172
+ await _bluebird.default.delay(500);
173
+ --inCallback;
174
+ return true;
175
+ }
176
+ });
177
+ inCallback.should.equal(0);
178
+ filePath.should.not.be.null;
179
+ });
180
+ it('should walk all elements recursive', async function () {
181
+ let inCallback = 0;
182
+ const filePath = await _index.fs.walkDir(__dirname, true, async () => {
183
+ ++inCallback;
184
+ await _bluebird.default.delay(500);
185
+ --inCallback;
186
+ });
187
+ inCallback.should.equal(0);
188
+ _lodash.default.isNil(filePath).should.be.true;
189
+ });
190
+ it('should throw error through callback', async function () {
191
+ let processed = 0;
192
+ await chai.expect(_index.fs.walkDir(__dirname, true, () => {
193
+ ++processed;
194
+ throw 'Callback error';
195
+ })).to.be.rejectedWith('Callback error');
196
+ processed.should.equal(1);
197
+ });
198
+ it('should traverse non-recursively', async function () {
199
+ const filePath = await _index.fs.walkDir(__dirname, false, item => item.endsWith('logger/helpers.js'));
200
+ _lodash.default.isNil(filePath).should.be.true;
201
+ });
202
+ });
203
+ describe('findRoot()', function () {
204
+ describe('when not provided an argument', function () {
205
+ it('should throw', function () {
206
+ (() => _index.fs.findRoot()).should.throw(TypeError);
207
+ });
208
+ });
209
+ describe('when provided a relative path', function () {
210
+ it('should throw', function () {
211
+ (() => _index.fs.findRoot('./foo')).should.throw(TypeError);
212
+ });
213
+ });
214
+ describe('when provided an empty string', function () {
215
+ it('should throw', function () {
216
+ (() => _index.fs.findRoot('')).should.throw(TypeError);
217
+ });
218
+ });
219
+ describe('when provided an absolute path', function () {
220
+ describe('when the path has a parent `package.json`', function () {
221
+ it('should locate the dir with the closest `package.json`', function () {
222
+ _index.fs.findRoot(__dirname).should.be.a('string');
223
+ });
224
+ });
225
+ describe('when the path does not have a parent `package.json`', function () {
226
+ it('should throw', function () {
227
+ (() => _index.fs.findRoot('/')).should.throw(Error);
228
+ });
229
+ });
230
+ });
231
+ });
232
+ describe('readPackageJsonFrom()', function () {
233
+ describe('when not provided an argument', function () {
234
+ it('should throw', function () {
235
+ (() => _index.fs.readPackageJsonFrom()).should.throw(TypeError, /non-empty, absolute path/);
236
+ });
237
+ });
238
+ describe('when provided a relative path', function () {
239
+ it('should throw', function () {
240
+ (() => _index.fs.readPackageJsonFrom('./foo')).should.throw(TypeError);
241
+ });
242
+ });
243
+ describe('when provided an empty string', function () {
244
+ it('should throw', function () {
245
+ (() => _index.fs.readPackageJsonFrom('')).should.throw(TypeError);
246
+ });
247
+ });
248
+ describe('when provided an absolute path', function () {
249
+ describe('when the path does not have a parent `package.json`', function () {
250
+ it('should throw', function () {
251
+ (() => _index.fs.readPackageJsonFrom('/')).should.throw(Error);
252
+ });
253
+ });
254
+ describe('when the path has a parent `package.json`', function () {
255
+ it('should read the `package.json` found in the root dir', function () {
256
+ _index.fs.readPackageJsonFrom(__dirname).should.be.an('object');
257
+ });
258
+ });
259
+ });
260
+ });
261
+ });require('source-map-support').install();
262
+
263
+
264
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZnMtc3BlY3MuanMiXSwibmFtZXMiOlsiTU9DSEFfVElNRU9VVCIsImRlc2NyaWJlIiwidGltZW91dCIsImV4aXN0aW5nUGF0aCIsInBhdGgiLCJyZXNvbHZlIiwiX19kaXJuYW1lIiwiaXQiLCJzaG91bGQiLCJleGlzdCIsImZzIiwib3BlbiIsImNsb3NlIiwiYWNjZXNzIiwibWtkaXIiLCJyZWFkbGluayIsImV4aXN0cyIsInJpbXJhZiIsInJpbXJhZlN5bmMiLCJyZWFkRmlsZSIsIndyaXRlRmlsZSIsImxzdGF0IiwibXYiLCJkaXJOYW1lIiwiaGFzQWNjZXNzIiwiYmUiLCJ0cnVlIiwicmVqZWN0ZWQiLCJvayIsIm5vbkV4aXN0aW5nUGF0aCIsIm5vdCIsImNvbnRhaW4iLCJuZXdQYXRoIiwidGVtcERpciIsIm9wZW5EaXIiLCJjb3B5RmlsZSIsImV2ZW50dWFsbHkiLCJmYWxzZSIsInNhbml0aXplTmFtZSIsInJlcGxhY2VtZW50IiwiZXFsIiwic21hbGxGaWxlUGF0aCIsImJpZ0ZpbGVQYXRoIiwiYmVmb3JlIiwiZmlsZSIsImZpbGVEYXRhIiwiaSIsIndyaXRlIiwiYWZ0ZXIiLCJ1bmxpbmsiLCJtZDUiLCJoYXZlIiwibGVuZ3RoIiwiaGFzaCIsInN0YXQiLCJwcm9wZXJ0eSIsInN5c3RlbU5wbVBhdGgiLCJzdGRvdXQiLCJ0cmltIiwibnBtUGF0aCIsIndoaWNoIiwiZXF1YWwiLCJnbG9iIiwidGVzdHMiLCJjd2QiLCJhbiIsImFib3ZlIiwiaW5DYWxsYmFjayIsImZpbGVQYXRoIiwid2Fsa0RpciIsIml0ZW0iLCJlbmRzV2l0aCIsIkIiLCJkZWxheSIsIm51bGwiLCJfIiwiaXNOaWwiLCJwcm9jZXNzZWQiLCJjaGFpIiwiZXhwZWN0IiwidG8iLCJyZWplY3RlZFdpdGgiLCJmaW5kUm9vdCIsInRocm93IiwiVHlwZUVycm9yIiwiYSIsIkVycm9yIiwicmVhZFBhY2thZ2VKc29uRnJvbSJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FB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Qy9FLE1BQXhDLENBQStDMkUsS0FBL0MsQ0FBcURDLFNBQXJEO0FBQ0QsT0FGQyxDQUFGO0FBR0QsS0FKTyxDQUFSO0FBTUFuRixJQUFBQSxRQUFRLENBQUMsK0JBQUQsRUFBa0MsWUFBWTtBQUNwRE0sTUFBQUEsRUFBRSxDQUFDLGNBQUQsRUFBaUIsWUFBWTtBQUM3QixTQUFDLE1BQU1HLFVBQUc2RSxtQkFBSCxDQUF1QixFQUF2QixDQUFQLEVBQW1DL0UsTUFBbkMsQ0FBMEMyRSxLQUExQyxDQUFnREMsU0FBaEQ7QUFDRCxPQUZDLENBQUY7QUFHRCxLQUpPLENBQVI7QUFNQW5GLElBQUFBLFFBQVEsQ0FBQyxnQ0FBRCxFQUFtQyxZQUFZO0FBQ3JEQSxNQUFBQSxRQUFRLENBQUMscURBQUQsRUFBd0QsWUFBWTtBQUMxRU0sUUFBQUEsRUFBRSxDQUFDLGNBQUQsRUFBaUIsWUFBWTtBQUM3QixXQUFDLE1BQU1HLFVBQUc2RSxtQkFBSCxDQUF1QixHQUF2QixDQUFQLEVBQW9DL0UsTUFBcEMsQ0FBMkMyRSxLQUEzQyxDQUFpREcsS0FBakQ7QUFDRCxTQUZDLENBQUY7QUFHRCxPQUpPLENBQVI7QUFNQXJGLE1BQUFBLFFBQVEsQ0FBQywyQ0FBRCxFQUE4QyxZQUFZO0FBQ2hFTSxRQUFBQSxFQUFFLENBQUMsc0RBQUQsRUFBeUQsWUFBWTtBQUNyRUcsb0JBQUc2RSxtQkFBSCxDQUF1QmpGLFNBQXZCLEVBQWtDRSxNQUFsQyxDQUF5Q2lCLEVBQXpDLENBQTRDd0MsRUFBNUMsQ0FBK0MsUUFBL0M7QUFDRCxTQUZDLENBQUY7QUFHRCxPQUpPLENBQVI7QUFLRCxLQVpPLENBQVI7QUFhRCxHQWhDTyxDQUFSO0FBaUNELENBOVBPLENBQVIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBmcywgdGVtcERpciB9IGZyb20gJy4uL2xpYi9pbmRleC5qcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcbmltcG9ydCB7IGV4ZWMgfSBmcm9tICd0ZWVuX3Byb2Nlc3MnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcblxuXG5jb25zdCBNT0NIQV9USU1FT1VUID0gMjAwMDA7XG5cbmRlc2NyaWJlKCdmcycsIGZ1bmN0aW9uICgpIHtcbiAgdGhpcy50aW1lb3V0KE1PQ0hBX1RJTUVPVVQpO1xuXG4gIGNvbnN0IGV4aXN0aW5nUGF0aCA9IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICdmcy1zcGVjcy5qcycpO1xuXG4gIGl0KCdzaG91bGQgaGF2ZSBleHBlY3RlZCBtZXRob2RzJywgZnVuY3Rpb24gKCkge1xuICAgIHNob3VsZC5leGlzdChmcy5vcGVuKTtcbiAgICBzaG91bGQuZXhpc3QoZnMuY2xvc2UpO1xuICAgIHNob3VsZC5leGlzdChmcy5hY2Nlc3MpO1xuICAgIHNob3VsZC5leGlzdChmcy5ta2Rpcik7XG4gICAgc2hvdWxkLmV4aXN0KGZzLnJlYWRsaW5rKTtcbiAgICBzaG91bGQuZXhpc3QoZnMuZXhpc3RzKTtcbiAgICBzaG91bGQuZXhpc3QoZnMucmltcmFmKTtcbiAgICBzaG91bGQuZXhpc3QoZnMucmltcmFmU3luYyk7XG4gICAgc2hvdWxkLmV4aXN0KGZzLnJlYWRGaWxlKTtcbiAgICBzaG91bGQuZXhpc3QoZnMud3JpdGVGaWxlKTtcbiAgICBzaG91bGQuZXhpc3QoZnMubHN0YXQpO1xuICAgIHNob3VsZC5leGlzdChmcy5tdik7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdta2RpcicsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgZGlyTmFtZSA9IHBhdGgucmVzb2x2ZShfX2Rpcm5hbWUsICd0bXAnKTtcblxuICAgIGl0KCdzaG91bGQgbWFrZSBhIGRpcmVjdG9yeSB0aGF0IGRvZXMgbm90IGV4aXN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgZnMucmltcmFmKGRpck5hbWUpO1xuICAgICAgYXdhaXQgZnMubWtkaXIoZGlyTmFtZSk7XG4gICAgICBsZXQgZXhpc3RzID0gYXdhaXQgZnMuaGFzQWNjZXNzKGRpck5hbWUpO1xuICAgICAgZXhpc3RzLnNob3VsZC5iZS50cnVlO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBub3QgY29tcGxhaW4gaWYgdGhlIGRpciBhbHJlYWR5IGV4aXN0cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBleGlzdHMgPSBhd2FpdCBmcy5oYXNBY2Nlc3MoZGlyTmFtZSk7XG4gICAgICBleGlzdHMuc2hvdWxkLmJlLnRydWU7XG4gICAgICBhd2FpdCBmcy5ta2RpcihkaXJOYW1lKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc3RpbGwgdGhyb3cgYW4gZXJyb3IgaWYgc29tZXRoaW5nIGVsc2UgZ29lcyB3cm9uZycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGZzLm1rZGlyKCcvYmluL2ZvbycpLnNob3VsZC5iZS5yZWplY3RlZDtcbiAgICB9KTtcbiAgfSk7XG5cbiAgaXQoJ2hhc0FjY2VzcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAoYXdhaXQgZnMuZXhpc3RzKGV4aXN0aW5nUGF0aCkpLnNob3VsZC5iZS5vaztcbiAgICBsZXQgbm9uRXhpc3RpbmdQYXRoID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJ3dyb25nLXNwZWNzLmpzJyk7XG4gICAgKGF3YWl0IGZzLmhhc0FjY2Vzcyhub25FeGlzdGluZ1BhdGgpKS5zaG91bGQubm90LmJlLm9rO1xuICB9KTtcbiAgaXQoJ2V4aXN0cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAoYXdhaXQgZnMuZXhpc3RzKGV4aXN0aW5nUGF0aCkpLnNob3VsZC5iZS5vaztcbiAgICBsZXQgbm9uRXhpc3RpbmdQYXRoID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJ3dyb25nLXNwZWNzLmpzJyk7XG4gICAgKGF3YWl0IGZzLmV4aXN0cyhub25FeGlzdGluZ1BhdGgpKS5zaG91bGQubm90LmJlLm9rO1xuICB9KTtcbiAgaXQoJ3JlYWRGaWxlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIChhd2FpdCBmcy5yZWFkRmlsZShleGlzdGluZ1BhdGgsICd1dGY4JykpLnNob3VsZC5jb250YWluKCdyZWFkRmlsZScpO1xuICB9KTtcblxuICBkZXNjcmliZSgnY29weUZpbGUnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBiZSBhYmxlIHRvIGNvcHkgYSBmaWxlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IG5ld1BhdGggPSBwYXRoLnJlc29sdmUoYXdhaXQgdGVtcERpci5vcGVuRGlyKCksICdmcy1zcGVjcy5qcycpO1xuICAgICAgYXdhaXQgZnMuY29weUZpbGUoZXhpc3RpbmdQYXRoLCBuZXdQYXRoKTtcbiAgICAgIChhd2FpdCBmcy5yZWFkRmlsZShuZXdQYXRoLCAndXRmOCcpKS5zaG91bGQuY29udGFpbigncmVhZEZpbGUnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdGhyb3cgYW4gZXJyb3IgaWYgdGhlIHNvdXJjZSBkb2VzIG5vdCBleGlzdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGZzLmNvcHlGaWxlKCcvc2Rmc2Rmc2Rmc2RmJywgJy90bXAvYmxhJykuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWQ7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGl0KCdyaW1yYWYnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgbGV0IG5ld1BhdGggPSBwYXRoLnJlc29sdmUoYXdhaXQgdGVtcERpci5vcGVuRGlyKCksICdmcy1zcGVjcy5qcycpO1xuICAgIGF3YWl0IGZzLmNvcHlGaWxlKGV4aXN0aW5nUGF0aCwgbmV3UGF0aCk7XG4gICAgKGF3YWl0IGZzLmV4aXN0cyhuZXdQYXRoKSkuc2hvdWxkLmJlLnRydWU7XG4gICAgYXdhaXQgZnMucmltcmFmKG5ld1BhdGgpO1xuICAgIChhd2FpdCBmcy5leGlzdHMobmV3UGF0aCkpLnNob3VsZC5iZS5mYWxzZTtcbiAgfSk7XG4gIGl0KCdzYW5pdGl6ZU5hbWUnLCBmdW5jdGlvbiAoKSB7XG4gICAgZnMuc2FuaXRpemVOYW1lKCc6ZmlsZT8udHh0Jywge1xuICAgICAgcmVwbGFjZW1lbnQ6ICctJyxcbiAgICB9KS5zaG91bGQuZXFsKCctZmlsZS0udHh0Jyk7XG4gIH0pO1xuICBpdCgncmltcmFmU3luYycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgbmV3UGF0aCA9IHBhdGgucmVzb2x2ZShhd2FpdCB0ZW1wRGlyLm9wZW5EaXIoKSwgJ2ZzLXNwZWNzLmpzJyk7XG4gICAgYXdhaXQgZnMuY29weUZpbGUoZXhpc3RpbmdQYXRoLCBuZXdQYXRoKTtcbiAgICAoYXdhaXQgZnMuZXhpc3RzKG5ld1BhdGgpKS5zaG91bGQuYmUudHJ1ZTtcbiAgICBmcy5yaW1yYWZTeW5jKG5ld1BhdGgpO1xuICAgIChhd2FpdCBmcy5leGlzdHMobmV3UGF0aCkpLnNob3VsZC5iZS5mYWxzZTtcbiAgfSk7XG4gIGRlc2NyaWJlKCdtZDUnLCBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy50aW1lb3V0KDEyMDAwMDApO1xuICAgIGxldCBzbWFsbEZpbGVQYXRoO1xuICAgIGxldCBiaWdGaWxlUGF0aDtcbiAgICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gZ2V0IHRoZSBwYXRoIG9mIGEgc21hbGwgZmlsZSAodGhpcyBzb3VyY2UgZmlsZSlcbiAgICAgIHNtYWxsRmlsZVBhdGggPSBleGlzdGluZ1BhdGg7XG5cbiAgICAgIC8vIGNyZWF0ZSBhIGxhcmdlIGZpbGUgdG8gdGVzdCwgYWJvdXQgMTYzODQwMDAwIGJ5dGVzXG4gICAgICBiaWdGaWxlUGF0aCA9IHBhdGgucmVzb2x2ZShhd2FpdCB0ZW1wRGlyLm9wZW5EaXIoKSwgJ2Vub3Jtb3VzLnR4dCcpO1xuICAgICAgbGV0IGZpbGUgPSBhd2FpdCBmcy5vcGVuKGJpZ0ZpbGVQYXRoLCAndycpO1xuICAgICAgbGV0IGZpbGVEYXRhID0gJyc7XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQwOTY7IGkrKykge1xuICAgICAgICBmaWxlRGF0YSArPSAnMSc7XG4gICAgICB9XG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IDQwMDAwOyBpKyspIHtcbiAgICAgICAgYXdhaXQgZnMud3JpdGUoZmlsZSwgZmlsZURhdGEpO1xuICAgICAgfVxuICAgICAgYXdhaXQgZnMuY2xvc2UoZmlsZSk7XG4gICAgfSk7XG4gICAgYWZ0ZXIoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgZnMudW5saW5rKGJpZ0ZpbGVQYXRoKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGNhbGN1bGF0ZSBoYXNoIG9mIGNvcnJlY3QgbGVuZ3RoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgKGF3YWl0IGZzLm1kNShzbWFsbEZpbGVQYXRoKSkuc2hvdWxkLmhhdmUubGVuZ3RoKDMyKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGJlIGFibGUgdG8gcnVuIG9uIGh1Z2UgZmlsZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIChhd2FpdCBmcy5tZDUoYmlnRmlsZVBhdGgpKS5zaG91bGQuaGF2ZS5sZW5ndGgoMzIpO1xuICAgIH0pO1xuICB9KTtcbiAgZGVzY3JpYmUoJ2hhc2gnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBjYWxjdWxhdGUgc2hhMSBoYXNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgKGF3YWl0IGZzLmhhc2goZXhpc3RpbmdQYXRoLCAnc2hhMScpKS5zaG91bGQuaGF2ZS5sZW5ndGgoNDApO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgY2FsY3VsYXRlIG1kNSBoYXNoJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgKGF3YWl0IGZzLmhhc2goZXhpc3RpbmdQYXRoLCAnbWQ1JykpLnNob3VsZC5oYXZlLmxlbmd0aCgzMik7XG4gICAgfSk7XG4gIH0pO1xuICBpdCgnc3RhdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgc3RhdCA9IGF3YWl0IGZzLnN0YXQoZXhpc3RpbmdQYXRoKTtcbiAgICBzdGF0LnNob3VsZC5oYXZlLnByb3BlcnR5KCdhdGltZScpO1xuICB9KTtcbiAgZGVzY3JpYmUoJ3doaWNoJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZmluZCBjb3JyZWN0IGV4ZWN1dGFibGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgc3lzdGVtTnBtUGF0aCA9IChhd2FpdCBleGVjKCd3aGljaCcsIFsnbnBtJ10pKS5zdGRvdXQudHJpbSgpO1xuICAgICAgbGV0IG5wbVBhdGggPSBhd2FpdCBmcy53aGljaCgnbnBtJyk7XG4gICAgICBucG1QYXRoLnNob3VsZC5lcXVhbChzeXN0ZW1OcG1QYXRoKTtcbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGZhaWwgZ3JhY2VmdWxseScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGF3YWl0IGZzLndoaWNoKCdzb21ldGhpbmdfdGhhdF9kb2VzX25vdF9leGlzdCcpXG4gICAgICAgIC5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZDtcbiAgICB9KTtcbiAgfSk7XG4gIGl0KCdnbG9iJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGxldCBnbG9iID0gJyotc3BlY3MuanMnO1xuICAgIGxldCB0ZXN0cyA9IGF3YWl0IGZzLmdsb2IoZ2xvYiwge2N3ZDogX19kaXJuYW1lfSk7XG4gICAgdGVzdHMuc2hvdWxkLmJlLmFuKCdhcnJheScpO1xuICAgIHRlc3RzLnNob3VsZC5oYXZlLmxlbmd0aC5hYm92ZSgyKTtcbiAgfSk7XG4gIGRlc2NyaWJlKCd3YWxrRGlyJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCd3YWxrRGlyIHJlY3Vyc2l2ZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBpbkNhbGxiYWNrID0gMDtcbiAgICAgIGNvbnN0IGZpbGVQYXRoID0gYXdhaXQgZnMud2Fsa0RpcihfX2Rpcm5hbWUsIHRydWUsIGFzeW5jIChpdGVtKSA9PiB7XG4gICAgICAgIGlmIChpdGVtLmVuZHNXaXRoKCdsb2dnZXIvaGVscGVycy5qcycpKSB7XG4gICAgICAgICAgKytpbkNhbGxiYWNrO1xuICAgICAgICAgIC8vIFRoaXMgaXMgdG8gdmVyaWZ5IHByb3BlciBhd2FpdCBmdW5jdGlvbmFsaXR5IG9mIHRoZVxuICAgICAgICAgIC8vIGNhbGxiYWNrIGludm9jYXRpb24gaW5zaWRlIHRoZSBmaWxlIHN5c3RlbSB3YWxrZXJcbiAgICAgICAgICBhd2FpdCBCLmRlbGF5KDUwMCk7XG4gICAgICAgICAgLS1pbkNhbGxiYWNrO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGluQ2FsbGJhY2suc2hvdWxkLmVxdWFsKDApO1xuICAgICAgZmlsZVBhdGguc2hvdWxkLm5vdC5iZS5udWxsO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgd2FsayBhbGwgZWxlbWVudHMgcmVjdXJzaXZlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGluQ2FsbGJhY2sgPSAwO1xuICAgICAgY29uc3QgZmlsZVBhdGggPSBhd2FpdCBmcy53YWxrRGlyKF9fZGlybmFtZSwgdHJ1ZSwgYXN5bmMgKCkgPT4ge1xuICAgICAgICArK2luQ2FsbGJhY2s7XG4gICAgICAgIGF3YWl0IEIuZGVsYXkoNTAwKTtcbiAgICAgICAgLS1pbkNhbGxiYWNrO1xuXG4gICAgICB9KTtcbiAgICAgIGluQ2FsbGJhY2suc2hvdWxkLmVxdWFsKDApO1xuICAgICAgXy5pc05pbChmaWxlUGF0aCkuc2hvdWxkLmJlLnRydWU7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCB0aHJvdyBlcnJvciB0aHJvdWdoIGNhbGxiYWNrJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHByb2Nlc3NlZCA9IDA7XG4gICAgICBhd2FpdCBjaGFpLmV4cGVjdChmcy53YWxrRGlyKF9fZGlybmFtZSwgdHJ1ZSxcbiAgICAgICAgKCkgPT4ge1xuICAgICAgICAgICsrcHJvY2Vzc2VkO1xuICAgICAgICAgIHRocm93ICdDYWxsYmFjayBlcnJvcic7XG4gICAgICAgIH0pKS50by5iZS5yZWplY3RlZFdpdGgoJ0NhbGxiYWNrIGVycm9yJyk7XG4gICAgICBwcm9jZXNzZWQuc2hvdWxkLmVxdWFsKDEpO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgdHJhdmVyc2Ugbm9uLXJlY3Vyc2l2ZWx5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgZmlsZVBhdGggPSBhd2FpdCBmcy53YWxrRGlyKF9fZGlybmFtZSwgZmFsc2UsIChpdGVtKSA9PiBpdGVtLmVuZHNXaXRoKCdsb2dnZXIvaGVscGVycy5qcycpKTtcbiAgICAgIF8uaXNOaWwoZmlsZVBhdGgpLnNob3VsZC5iZS50cnVlO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnZmluZFJvb3QoKScsIGZ1bmN0aW9uICgpIHtcbiAgICBkZXNjcmliZSgnd2hlbiBub3QgcHJvdmlkZWQgYW4gYXJndW1lbnQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIHRocm93JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAoKCkgPT4gZnMuZmluZFJvb3QoKSkuc2hvdWxkLnRocm93KFR5cGVFcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCd3aGVuIHByb3ZpZGVkIGEgcmVsYXRpdmUgcGF0aCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgdGhyb3cnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICgoKSA9PiBmcy5maW5kUm9vdCgnLi9mb28nKSkuc2hvdWxkLnRocm93KFR5cGVFcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCd3aGVuIHByb3ZpZGVkIGFuIGVtcHR5IHN0cmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgdGhyb3cnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICgoKSA9PiBmcy5maW5kUm9vdCgnJykpLnNob3VsZC50aHJvdyhUeXBlRXJyb3IpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBwcm92aWRlZCBhbiBhYnNvbHV0ZSBwYXRoJywgZnVuY3Rpb24gKCkge1xuICAgICAgZGVzY3JpYmUoJ3doZW4gdGhlIHBhdGggaGFzIGEgcGFyZW50IGBwYWNrYWdlLmpzb25gJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBpdCgnc2hvdWxkIGxvY2F0ZSB0aGUgZGlyIHdpdGggdGhlIGNsb3Nlc3QgYHBhY2thZ2UuanNvbmAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZnMuZmluZFJvb3QoX19kaXJuYW1lKS5zaG91bGQuYmUuYSgnc3RyaW5nJyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIHRoZSBwYXRoIGRvZXMgbm90IGhhdmUgYSBwYXJlbnQgYHBhY2thZ2UuanNvbmAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgdGhyb3cnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgKCgpID0+IGZzLmZpbmRSb290KCcvJykpLnNob3VsZC50aHJvdyhFcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdyZWFkUGFja2FnZUpzb25Gcm9tKCknLCBmdW5jdGlvbiAoKSB7XG4gICAgZGVzY3JpYmUoJ3doZW4gbm90IHByb3ZpZGVkIGFuIGFyZ3VtZW50JywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCB0aHJvdycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgKCgpID0+IGZzLnJlYWRQYWNrYWdlSnNvbkZyb20oKSkuc2hvdWxkLnRocm93KFR5cGVFcnJvciwgL25vbi1lbXB0eSwgYWJzb2x1dGUgcGF0aC8pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBwcm92aWRlZCBhIHJlbGF0aXZlIHBhdGgnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIHRocm93JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAoKCkgPT4gZnMucmVhZFBhY2thZ2VKc29uRnJvbSgnLi9mb28nKSkuc2hvdWxkLnRocm93KFR5cGVFcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCd3aGVuIHByb3ZpZGVkIGFuIGVtcHR5IHN0cmluZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgdGhyb3cnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICgoKSA9PiBmcy5yZWFkUGFja2FnZUpzb25Gcm9tKCcnKSkuc2hvdWxkLnRocm93KFR5cGVFcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCd3aGVuIHByb3ZpZGVkIGFuIGFic29sdXRlIHBhdGgnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBkZXNjcmliZSgnd2hlbiB0aGUgcGF0aCBkb2VzIG5vdCBoYXZlIGEgcGFyZW50IGBwYWNrYWdlLmpzb25gJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBpdCgnc2hvdWxkIHRocm93JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICgoKSA9PiBmcy5yZWFkUGFja2FnZUpzb25Gcm9tKCcvJykpLnNob3VsZC50aHJvdyhFcnJvcik7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIHRoZSBwYXRoIGhhcyBhIHBhcmVudCBgcGFja2FnZS5qc29uYCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCByZWFkIHRoZSBgcGFja2FnZS5qc29uYCBmb3VuZCBpbiB0aGUgcm9vdCBkaXInLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZnMucmVhZFBhY2thZ2VKc29uRnJvbShfX2Rpcm5hbWUpLnNob3VsZC5iZS5hbignb2JqZWN0Jyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXSwiZmlsZSI6InRlc3QvZnMtc3BlY3MuanMiLCJzb3VyY2VSb290IjoiLi4vLi4ifQ==
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.MockReadWriteStream = void 0;
7
+
8
+ require("source-map-support/register");
9
+
10
+ var _events = require("events");
11
+
12
+ class MockReadWriteStream extends _events.EventEmitter {
13
+ resume() {}
14
+
15
+ pause() {}
16
+
17
+ setEncoding() {}
18
+
19
+ flush() {}
20
+
21
+ write(msg) {
22
+ this.emit('data', msg);
23
+ }
24
+
25
+ end() {
26
+ this.emit('end');
27
+ this.emit('finish');
28
+ }
29
+
30
+ }
31
+
32
+ exports.MockReadWriteStream = MockReadWriteStream;require('source-map-support').install();
33
+
34
+
35
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaGVscGVycy5qcyJdLCJuYW1lcyI6WyJNb2NrUmVhZFdyaXRlU3RyZWFtIiwiRXZlbnRFbWl0dGVyIiwicmVzdW1lIiwicGF1c2UiLCJzZXRFbmNvZGluZyIsImZsdXNoIiwid3JpdGUiLCJtc2ciLCJlbWl0IiwiZW5kIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQTs7QUFFQSxNQUFNQSxtQkFBTixTQUFrQ0Msb0JBQWxDLENBQStDO0FBQzdDQyxFQUFBQSxNQUFNLEdBQUksQ0FBRTs7QUFFWkMsRUFBQUEsS0FBSyxHQUFJLENBQUU7O0FBRVhDLEVBQUFBLFdBQVcsR0FBSSxDQUFFOztBQUVqQkMsRUFBQUEsS0FBSyxHQUFJLENBQUU7O0FBRVhDLEVBQUFBLEtBQUssQ0FBRUMsR0FBRixFQUFPO0FBQ1YsU0FBS0MsSUFBTCxDQUFVLE1BQVYsRUFBa0JELEdBQWxCO0FBQ0Q7O0FBRURFLEVBQUFBLEdBQUcsR0FBSTtBQUNMLFNBQUtELElBQUwsQ0FBVSxLQUFWO0FBQ0EsU0FBS0EsSUFBTCxDQUFVLFFBQVY7QUFDRDs7QUFoQjRDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRXZlbnRFbWl0dGVyIH0gZnJvbSAnZXZlbnRzJztcblxuY2xhc3MgTW9ja1JlYWRXcml0ZVN0cmVhbSBleHRlbmRzIEV2ZW50RW1pdHRlciB7XG4gIHJlc3VtZSAoKSB7fVxuXG4gIHBhdXNlICgpIHt9XG5cbiAgc2V0RW5jb2RpbmcgKCkge31cblxuICBmbHVzaCAoKSB7fVxuXG4gIHdyaXRlIChtc2cpIHtcbiAgICB0aGlzLmVtaXQoJ2RhdGEnLCBtc2cpO1xuICB9XG5cbiAgZW5kICgpIHtcbiAgICB0aGlzLmVtaXQoJ2VuZCcpO1xuICAgIHRoaXMuZW1pdCgnZmluaXNoJyk7XG4gIH1cbn1cblxuZXhwb3J0IHsgTW9ja1JlYWRXcml0ZVN0cmVhbSB9O1xuIl0sImZpbGUiOiJ0ZXN0L2hlbHBlcnMuanMiLCJzb3VyY2VSb290IjoiLi4vLi4ifQ==
@@ -0,0 +1,227 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _imageUtil = require("../lib/image-util");
8
+
9
+ var _path = _interopRequireDefault(require("path"));
10
+
11
+ var _lodash = _interopRequireDefault(require("lodash"));
12
+
13
+ var _lib = require("../lib");
14
+
15
+ const FIXTURES_ROOT = _path.default.resolve(__dirname, '..', '..', 'test', 'images');
16
+
17
+ async function getImage(name) {
18
+ const imagePath = _path.default.resolve(FIXTURES_ROOT, name);
19
+
20
+ return await _lib.fs.readFile(imagePath, 'utf8');
21
+ }
22
+
23
+ describe('image-util', function () {
24
+ before(function () {
25
+ return this.skip();
26
+ });
27
+ describe('cropBase64Image', function () {
28
+ let originalImage = null;
29
+ before(async function () {
30
+ const originalImage64 = await getImage('full-image.b64');
31
+ originalImage = await (0, _imageUtil.base64ToImage)(originalImage64);
32
+ originalImage.width.should.be.equal(640, 'unexpected width');
33
+ originalImage.height.should.be.equal(1136, 'unexpected height');
34
+ });
35
+ it('should verify that an image is cropped correctly', async function () {
36
+ const croppedImage = await (0, _imageUtil.cropImage)(originalImage, {
37
+ left: 35,
38
+ top: 107,
39
+ width: 323,
40
+ height: 485
41
+ });
42
+ croppedImage.width.should.be.equal(323, 'unexpected width');
43
+ croppedImage.height.should.be.equal(485, 'unexpected height');
44
+ const croppedImageShouldBe = await getImage('cropped-image.b64');
45
+ const croppedImage64 = await (0, _imageUtil.imageToBase64)(croppedImage);
46
+ croppedImage64.should.be.equal(croppedImageShouldBe);
47
+ });
48
+ });
49
+ describe('OpenCV helpers', function () {
50
+ this.timeout(120000);
51
+ let imgFixture = null;
52
+ let fullImage = null;
53
+ let partialImage = null;
54
+ let originalImage = null;
55
+ let changedImage = null;
56
+ let rotatedImage = null;
57
+ let numberImage = null;
58
+ before(async function () {
59
+ const imagePath = _path.default.resolve(FIXTURES_ROOT, 'full-image.b64');
60
+
61
+ imgFixture = Buffer.from(await _lib.fs.readFile(imagePath, 'binary'), 'base64');
62
+ fullImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'findwaldo.jpg'));
63
+ partialImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'waldo.jpg'));
64
+ originalImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'cc1.png'));
65
+ changedImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'cc2.png'));
66
+ numberImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'number5.png'));
67
+ rotatedImage = await _lib.fs.readFile(_path.default.resolve(FIXTURES_ROOT, 'cc_rotated.png'));
68
+ });
69
+ describe('getImagesMatches', function () {
70
+ it('should calculate the number of matches between two images', async function () {
71
+ for (const detectorName of ['AKAZE', 'ORB']) {
72
+ const {
73
+ count,
74
+ totalCount
75
+ } = await (0, _imageUtil.getImagesMatches)(fullImage, fullImage, {
76
+ detectorName
77
+ });
78
+ count.should.be.above(0);
79
+ totalCount.should.eql(count);
80
+ }
81
+ });
82
+ it('should visualize matches between two images', async function () {
83
+ const {
84
+ visualization
85
+ } = await (0, _imageUtil.getImagesMatches)(fullImage, fullImage, {
86
+ visualize: true
87
+ });
88
+ visualization.should.not.be.empty;
89
+ });
90
+ it('should visualize matches between two images and apply goodMatchesFactor', async function () {
91
+ const {
92
+ visualization,
93
+ points1,
94
+ rect1,
95
+ points2,
96
+ rect2
97
+ } = await (0, _imageUtil.getImagesMatches)(rotatedImage, originalImage, {
98
+ visualize: true,
99
+ matchFunc: 'BruteForceHamming',
100
+ goodMatchesFactor: 40
101
+ });
102
+ visualization.should.not.be.empty;
103
+ points1.length.should.be.above(4);
104
+ rect1.x.should.be.above(0);
105
+ rect1.y.should.be.above(0);
106
+ rect1.width.should.be.above(0);
107
+ rect1.height.should.be.above(0);
108
+ points2.length.should.be.above(4);
109
+ rect2.x.should.be.above(0);
110
+ rect2.y.should.be.above(0);
111
+ rect2.width.should.be.above(0);
112
+ rect2.height.should.be.above(0);
113
+ });
114
+ });
115
+ describe('getImagesSimilarity', function () {
116
+ it('should calculate the similarity score between two images', async function () {
117
+ const {
118
+ score
119
+ } = await (0, _imageUtil.getImagesSimilarity)(imgFixture, imgFixture);
120
+ score.should.be.above(0);
121
+ });
122
+ it('should visualize the similarity between two images', async function () {
123
+ const {
124
+ visualization
125
+ } = await (0, _imageUtil.getImagesSimilarity)(originalImage, changedImage, {
126
+ visualize: true
127
+ });
128
+ visualization.should.not.be.empty;
129
+ });
130
+ });
131
+ describe('getImageOccurrence', function () {
132
+ it('should calculate the partial image position in the full image', async function () {
133
+ const {
134
+ rect,
135
+ score
136
+ } = await (0, _imageUtil.getImageOccurrence)(fullImage, partialImage);
137
+ rect.x.should.be.above(0);
138
+ rect.y.should.be.above(0);
139
+ rect.width.should.be.above(0);
140
+ rect.height.should.be.above(0);
141
+ score.should.be.above(0);
142
+ });
143
+ it('should reject matches that fall below a threshold', async function () {
144
+ await (0, _imageUtil.getImageOccurrence)(fullImage, partialImage, {
145
+ threshold: 1.0
146
+ }).should.eventually.be.rejectedWith(/threshold/);
147
+ });
148
+ it('should visualize the partial image position in the full image', async function () {
149
+ const {
150
+ visualization
151
+ } = await (0, _imageUtil.getImageOccurrence)(fullImage, partialImage, {
152
+ visualize: true
153
+ });
154
+ visualization.should.not.be.empty;
155
+ });
156
+ describe('multiple', function () {
157
+ it('should return matches in the full image', async function () {
158
+ const {
159
+ multiple
160
+ } = await (0, _imageUtil.getImageOccurrence)(originalImage, numberImage, {
161
+ threshold: 0.8,
162
+ multiple: true
163
+ });
164
+ multiple.length.should.be.eq(3);
165
+
166
+ for (const result of multiple) {
167
+ result.rect.x.should.be.above(0);
168
+ result.rect.y.should.be.above(0);
169
+ result.rect.width.should.be.above(0);
170
+ result.rect.height.should.be.above(0);
171
+ result.score.should.be.above(0);
172
+ }
173
+ });
174
+ it('should reject matches that fall below a threshold', async function () {
175
+ await (0, _imageUtil.getImageOccurrence)(originalImage, numberImage, {
176
+ threshold: 1.0,
177
+ multiple: true
178
+ }).should.eventually.be.rejectedWith(/threshold/);
179
+ });
180
+ it('should visualize the partial image position in the full image', async function () {
181
+ const {
182
+ multiple
183
+ } = await (0, _imageUtil.getImageOccurrence)(originalImage, numberImage, {
184
+ visualize: true,
185
+ multiple: true
186
+ });
187
+
188
+ for (const result of multiple) {
189
+ result.visualization.should.not.be.empty;
190
+ }
191
+ });
192
+ });
193
+ });
194
+ });
195
+ describe('Jimp helpers', function () {
196
+ it('should get a jimp object using image buffer', async function () {
197
+ const base64Image = await getImage('cropped-image.b64');
198
+ const imageBuffer = Buffer.from(base64Image, 'base64');
199
+ const jimpImg = await (0, _imageUtil.getJimpImage)(imageBuffer);
200
+ jimpImg.hash().should.eql('80000000000');
201
+ jimpImg.bitmap.height.should.eql(485);
202
+ jimpImg.bitmap.width.should.eql(323);
203
+ });
204
+ it('should get a jimp object using b64 string', async function () {
205
+ const base64Image = await getImage('cropped-image.b64');
206
+ const jimpImg = await (0, _imageUtil.getJimpImage)(base64Image);
207
+ jimpImg.hash().should.eql('80000000000');
208
+ jimpImg.bitmap.height.should.eql(485);
209
+ jimpImg.bitmap.width.should.eql(323);
210
+ });
211
+ it('should error with incorrect data type', async function () {
212
+ await (0, _imageUtil.getJimpImage)(1234).should.eventually.be.rejectedWith(/string or buffer/);
213
+ });
214
+ it('should error with incorrect image data', async function () {
215
+ await (0, _imageUtil.getJimpImage)('foo').should.eventually.be.rejectedWith(/Could not find MIME for Buffer/);
216
+ });
217
+ it('should get an image buffer via the overridden getBuffer method', async function () {
218
+ const base64Image = await getImage('cropped-image.b64');
219
+ const jimpImg = await (0, _imageUtil.getJimpImage)(base64Image);
220
+ const buf = await jimpImg.getBuffer(_imageUtil.MIME_PNG);
221
+ _lodash.default.isBuffer(buf).should.be.true;
222
+ });
223
+ });
224
+ });require('source-map-support').install();
225
+
226
+
227
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvaW1hZ2UtdXRpbC1lMmUtc3BlY3MuanMiXSwibmFtZXMiOlsiRklYVFVSRVNfUk9PVCIsInBhdGgiLCJyZXNvbHZlIiwiX19kaXJuYW1lIiwiZ2V0SW1hZ2UiLCJuYW1lIiwiaW1hZ2VQYXRoIiwiZnMiLCJyZWFkRmlsZSIsImRlc2NyaWJlIiwiYmVmb3JlIiwic2tpcCIsIm9yaWdpbmFsSW1hZ2UiLCJvcmlnaW5hbEltYWdlNjQiLCJ3aWR0aCIsInNob3VsZCIsImJlIiwiZXF1YWwiLCJoZWlnaHQiLCJpdCIsImNyb3BwZWRJbWFnZSIsImxlZnQiLCJ0b3AiLCJjcm9wcGVkSW1hZ2VTaG91bGRCZSIsImNyb3BwZWRJbWFnZTY0IiwidGltZW91dCIsImltZ0ZpeHR1cmUiLCJmdWxsSW1hZ2UiLCJwYXJ0aWFsSW1hZ2UiLCJjaGFuZ2VkSW1hZ2UiLCJyb3RhdGVkSW1hZ2UiLCJudW1iZXJJbWFnZSIsIkJ1ZmZlciIsImZyb20iLCJkZXRlY3Rvck5hbWUiLCJjb3VudCIsInRvdGFsQ291bnQiLCJhYm92ZSIsImVxbCIsInZpc3VhbGl6YXRpb24iLCJ2aXN1YWxpemUiLCJub3QiLCJlbXB0eSIsInBvaW50czEiLCJyZWN0MSIsInBvaW50czIiLCJyZWN0MiIsIm1hdGNoRnVuYyIsImdvb2RNYXRjaGVzRmFjdG9yIiwibGVuZ3RoIiwieCIsInkiLCJzY29yZSIsInJlY3QiLCJ0aHJlc2hvbGQiLCJldmVudHVhbGx5IiwicmVqZWN0ZWRXaXRoIiwibXVsdGlwbGUiLCJlcSIsInJlc3VsdCIsImJhc2U2NEltYWdlIiwiaW1hZ2VCdWZmZXIiLCJqaW1wSW1nIiwiaGFzaCIsImJpdG1hcCIsImJ1ZiIsImdldEJ1ZmZlciIsIk1JTUVfUE5HIiwiXyIsImlzQnVmZmVyIiwidHJ1ZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7O0FBS0E7O0FBQ0E7O0FBQ0E7O0FBR0EsTUFBTUEsYUFBYSxHQUFHQyxjQUFLQyxPQUFMLENBQWFDLFNBQWIsRUFBd0IsSUFBeEIs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QXJDLElBQUFBLEVBQUUsQ0FBQyx3Q0FBRCxFQUEyQyxrQkFBa0I7QUFDN0QsWUFBTSw2QkFBYSxLQUFiLEVBQW9CSixNQUFwQixDQUEyQndDLFVBQTNCLENBQXNDdkMsRUFBdEMsQ0FBeUN3QyxZQUF6QyxDQUFzRCxnQ0FBdEQsQ0FBTjtBQUNELEtBRkMsQ0FBRjtBQUdBckMsSUFBQUEsRUFBRSxDQUFDLGdFQUFELEVBQW1FLGtCQUFrQjtBQUNyRixZQUFNeUMsV0FBVyxHQUFHLE1BQU14RCxRQUFRLENBQUMsbUJBQUQsQ0FBbEM7QUFDQSxZQUFNMEQsT0FBTyxHQUFHLE1BQU0sNkJBQWFGLFdBQWIsQ0FBdEI7QUFDQSxZQUFNSyxHQUFHLEdBQUcsTUFBTUgsT0FBTyxDQUFDSSxTQUFSLENBQWtCQyxtQkFBbEIsQ0FBbEI7QUFDQUMsc0JBQUVDLFFBQUYsQ0FBV0osR0FBWCxFQUFnQmxELE1BQWhCLENBQXVCQyxFQUF2QixDQUEwQnNELElBQTFCO0FBQ0QsS0FMQyxDQUFGO0FBTUQsR0E1Qk8sQ0FBUjtBQTZCRCxDQXBMTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcbiAgYmFzZTY0VG9JbWFnZSwgaW1hZ2VUb0Jhc2U2NCwgY3JvcEltYWdlLFxuICBnZXRJbWFnZXNNYXRjaGVzLCBnZXRJbWFnZXNTaW1pbGFyaXR5LCBnZXRJbWFnZU9jY3VycmVuY2UsXG4gIGdldEppbXBJbWFnZSwgTUlNRV9QTkcsXG59IGZyb20gJy4uL2xpYi9pbWFnZS11dGlsJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCB7IGZzIH0gZnJvbSAnLi4vbGliJztcblxuXG5jb25zdCBGSVhUVVJFU19ST09UID0gcGF0aC5yZXNvbHZlKF9fZGlybmFtZSwgJy4uJywgJy4uJywgJ3Rlc3QnLCAnaW1hZ2VzJyk7XG5cbmFzeW5jIGZ1bmN0aW9uIGdldEltYWdlIChuYW1lKSB7XG4gIGNvbnN0IGltYWdlUGF0aCA9IHBhdGgucmVzb2x2ZShGSVhUVVJFU19ST09ULCBuYW1lKTtcbiAgcmV0dXJuIGF3YWl0IGZzLnJlYWRGaWxlKGltYWdlUGF0aCwgJ3V0ZjgnKTtcbn1cblxuZGVzY3JpYmUoJ2ltYWdlLXV0aWwnLCBmdW5jdGlvbiAoKSB7XG4gIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgLy8gVE9ETzogcmVtb3ZlIHdoZW4gb3BlbmN2NG5vZGVqcyBpcyBmaXhlZFxuICAgIHJldHVybiB0aGlzLnNraXAoKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2Nyb3BCYXNlNjRJbWFnZScsIGZ1bmN0aW9uICgpIHtcbiAgICBsZXQgb3JpZ2luYWxJbWFnZSA9IG51bGw7XG5cbiAgICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qgb3JpZ2luYWxJbWFnZTY0ID0gYXdhaXQgZ2V0SW1hZ2UoJ2Z1bGwtaW1hZ2UuYjY0Jyk7XG4gICAgICBvcmlnaW5hbEltYWdlID0gYXdhaXQgYmFzZTY0VG9JbWFnZShvcmlnaW5hbEltYWdlNjQpO1xuXG4gICAgICAvLyB2ZXJpZnkgb3JpZ2luYWwgaW1hZ2Ugc2l6ZSwgdG8gYmUgc3VyZSB0aGF0IG9yaWdpbmFsIGltYWdlIGlzIGNvcnJlY3RcbiAgICAgIG9yaWdpbmFsSW1hZ2Uud2lkdGguc2hvdWxkLmJlLmVxdWFsKDY0MCwgJ3VuZXhwZWN0ZWQgd2lkdGgnKTtcbiAgICAgIG9yaWdpbmFsSW1hZ2UuaGVpZ2h0LnNob3VsZC5iZS5lcXVhbCgxMTM2LCAndW5leHBlY3RlZCBoZWlnaHQnKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgdmVyaWZ5IHRoYXQgYW4gaW1hZ2UgaXMgY3JvcHBlZCBjb3JyZWN0bHknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBjcm9wcGVkSW1hZ2UgPSBhd2FpdCBjcm9wSW1hZ2Uob3JpZ2luYWxJbWFnZSwge2xlZnQ6IDM1LCB0b3A6IDEwNywgd2lkdGg6IDMyMywgaGVpZ2h0OiA0ODV9KTtcblxuICAgICAgLy8gdmVyaWZ5IGNyb3BwZWQgaW1hZ2Ugc2l6ZSwgaXQgc2hvdWxkIGJlIGxlc3MgdGhhbiBvcmlnaW5hbCBpbWFnZSBhY2NvcmRpbmcgdG8gY3JvcCByZWdpb25cbiAgICAgIGNyb3BwZWRJbWFnZS53aWR0aC5zaG91bGQuYmUuZXF1YWwoMzIzLCAndW5leHBlY3RlZCB3aWR0aCcpO1xuICAgICAgY3JvcHBlZEltYWdlLmhlaWdodC5zaG91bGQuYmUuZXF1YWwoNDg1LCAndW5leHBlY3RlZCBoZWlnaHQnKTtcblxuICAgICAgLy8gdmVyaWZ5IHRoYXQgaW1hZ2UgY3JvcHBlZCwgY29tcGFyZSBiYXNlNjQgcmVwcmVzZW50YXRpb25cbiAgICAgIGNvbnN0IGNyb3BwZWRJbWFnZVNob3VsZEJlID0gYXdhaXQgZ2V0SW1hZ2UoJ2Nyb3BwZWQtaW1hZ2UuYjY0Jyk7XG4gICAgICBjb25zdCBjcm9wcGVkSW1hZ2U2NCA9IGF3YWl0IGltYWdlVG9CYXNlNjQoY3JvcHBlZEltYWdlKTtcbiAgICAgIGNyb3BwZWRJbWFnZTY0LnNob3VsZC5iZS5lcXVhbChjcm9wcGVkSW1hZ2VTaG91bGRCZSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdPcGVuQ1YgaGVscGVycycsIGZ1bmN0aW9uICgpIHtcbiAgICAvLyBPcGVuQ1YgbmVlZHMgc2V2ZXJhbCBzZWNvbmRzIGZvciBpbml0aWFsaXphdGlvblxuICAgIHRoaXMudGltZW91dCgxMjAwMDApO1xuXG4gICAgbGV0IGltZ0ZpeHR1cmUgPSBudWxsO1xuICAgIGxldCBmdWxsSW1hZ2UgPSBudWxsO1xuICAgIGxldCBwYXJ0aWFsSW1hZ2UgPSBudWxsO1xuICAgIGxldCBvcmlnaW5hbEltYWdlID0gbnVsbDtcbiAgICBsZXQgY2hhbmdlZEltYWdlID0gbnVsbDtcbiAgICBsZXQgcm90YXRlZEltYWdlID0gbnVsbDtcbiAgICBsZXQgbnVtYmVySW1hZ2UgPSBudWxsO1xuXG4gICAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGltYWdlUGF0aCA9IHBhdGgucmVzb2x2ZShGSVhUVVJFU19ST09ULCAnZnVsbC1pbWFnZS5iNjQnKTtcbiAgICAgIGltZ0ZpeHR1cmUgPSBCdWZmZXIuZnJvbShhd2FpdCBmcy5yZWFkRmlsZShpbWFnZVBhdGgsICdiaW5hcnknKSwgJ2Jhc2U2NCcpO1xuICAgICAgZnVsbEltYWdlID0gYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKEZJWFRVUkVTX1JPT1QsICdmaW5kd2FsZG8uanBnJykpO1xuICAgICAgcGFydGlhbEltYWdlID0gYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKEZJWFRVUkVTX1JPT1QsICd3YWxkby5qcGcnKSk7XG4gICAgICBvcmlnaW5hbEltYWdlID0gYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKEZJWFRVUkVTX1JPT1QsICdjYzEucG5nJykpO1xuICAgICAgY2hhbmdlZEltYWdlID0gYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKEZJWFRVUkVTX1JPT1QsICdjYzIucG5nJykpO1xuICAgICAgbnVtYmVySW1hZ2UgPSBhd2FpdCBmcy5yZWFkRmlsZShwYXRoLnJlc29sdmUoRklYVFVSRVNfUk9PVCwgJ251bWJlcjUucG5nJykpO1xuICAgICAgcm90YXRlZEltYWdlID0gYXdhaXQgZnMucmVhZEZpbGUocGF0aC5yZXNvbHZlKEZJWFRVUkVTX1JPT1QsICdjY19yb3RhdGVkLnBuZycpKTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdnZXRJbWFnZXNNYXRjaGVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiBtYXRjaGVzIGJldHdlZW4gdHdvIGltYWdlcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZm9yIChjb25zdCBkZXRlY3Rvck5hbWUgb2YgWydBS0FaRScsICdPUkInXSkge1xuICAgICAgICAgIGNvbnN0IHtjb3VudCwgdG90YWxDb3VudH0gPSBhd2FpdCBnZXRJbWFnZXNNYXRjaGVzKGZ1bGxJbWFnZSwgZnVsbEltYWdlLCB7ZGV0ZWN0b3JOYW1lfSk7XG4gICAgICAgICAgY291bnQuc2hvdWxkLmJlLmFib3ZlKDApO1xuICAgICAgICAgIHRvdGFsQ291bnQuc2hvdWxkLmVxbChjb3VudCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHZpc3VhbGl6ZSBtYXRjaGVzIGJldHdlZW4gdHdvIGltYWdlcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qge3Zpc3VhbGl6YXRpb259ID0gYXdhaXQgZ2V0SW1hZ2VzTWF0Y2hlcyhmdWxsSW1hZ2UsIGZ1bGxJbWFnZSwge3Zpc3VhbGl6ZTogdHJ1ZX0pO1xuICAgICAgICB2aXN1YWxpemF0aW9uLnNob3VsZC5ub3QuYmUuZW1wdHk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCB2aXN1YWxpemUgbWF0Y2hlcyBiZXR3ZWVuIHR3byBpbWFnZXMgYW5kIGFwcGx5IGdvb2RNYXRjaGVzRmFjdG9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7dmlzdWFsaXphdGlvbiwgcG9pbnRzMSwgcmVjdDEsIHBvaW50czIsIHJlY3QyfSA9IGF3YWl0IGdldEltYWdlc01hdGNoZXMocm90YXRlZEltYWdlLCBvcmlnaW5hbEltYWdlLCB7XG4gICAgICAgICAgdmlzdWFsaXplOiB0cnVlLFxuICAgICAgICAgIG1hdGNoRnVuYzogJ0JydXRlRm9yY2VIYW1taW5nJyxcbiAgICAgICAgICBnb29kTWF0Y2hlc0ZhY3RvcjogNDBcbiAgICAgICAgfSk7XG4gICAgICAgIHZpc3VhbGl6YXRpb24uc2hvdWxkLm5vdC5iZS5lbXB0eTtcbiAgICAgICAgcG9pbnRzMS5sZW5ndGguc2hvdWxkLmJlLmFib3ZlKDQpO1xuICAgICAgICByZWN0MS54LnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgcmVjdDEueS5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgIHJlY3QxLndpZHRoLnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgcmVjdDEuaGVpZ2h0LnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgcG9pbnRzMi5sZW5ndGguc2hvdWxkLmJlLmFib3ZlKDQpO1xuICAgICAgICByZWN0Mi54LnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgcmVjdDIueS5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgIHJlY3QyLndpZHRoLnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgcmVjdDIuaGVpZ2h0LnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ2dldEltYWdlc1NpbWlsYXJpdHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIGNhbGN1bGF0ZSB0aGUgc2ltaWxhcml0eSBzY29yZSBiZXR3ZWVuIHR3byBpbWFnZXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHtzY29yZX0gPSBhd2FpdCBnZXRJbWFnZXNTaW1pbGFyaXR5KGltZ0ZpeHR1cmUsIGltZ0ZpeHR1cmUpO1xuICAgICAgICBzY29yZS5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCB2aXN1YWxpemUgdGhlIHNpbWlsYXJpdHkgYmV0d2VlbiB0d28gaW1hZ2VzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7dmlzdWFsaXphdGlvbn0gPSBhd2FpdCBnZXRJbWFnZXNTaW1pbGFyaXR5KG9yaWdpbmFsSW1hZ2UsIGNoYW5nZWRJbWFnZSwge3Zpc3VhbGl6ZTogdHJ1ZX0pO1xuICAgICAgICB2aXN1YWxpemF0aW9uLnNob3VsZC5ub3QuYmUuZW1wdHk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdnZXRJbWFnZU9jY3VycmVuY2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIGNhbGN1bGF0ZSB0aGUgcGFydGlhbCBpbWFnZSBwb3NpdGlvbiBpbiB0aGUgZnVsbCBpbWFnZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3Qge3JlY3QsIHNjb3JlfSA9IGF3YWl0IGdldEltYWdlT2NjdXJyZW5jZShmdWxsSW1hZ2UsIHBhcnRpYWxJbWFnZSk7XG4gICAgICAgIHJlY3QueC5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgIHJlY3QueS5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgIHJlY3Qud2lkdGguc2hvdWxkLmJlLmFib3ZlKDApO1xuICAgICAgICByZWN0LmhlaWdodC5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgIHNjb3JlLnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHJlamVjdCBtYXRjaGVzIHRoYXQgZmFsbCBiZWxvdyBhIHRocmVzaG9sZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgZ2V0SW1hZ2VPY2N1cnJlbmNlKGZ1bGxJbWFnZSwgcGFydGlhbEltYWdlLCB7dGhyZXNob2xkOiAxLjB9KVxuICAgICAgICAgIC5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZFdpdGgoL3RocmVzaG9sZC8pO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgdmlzdWFsaXplIHRoZSBwYXJ0aWFsIGltYWdlIHBvc2l0aW9uIGluIHRoZSBmdWxsIGltYWdlJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB7dmlzdWFsaXphdGlvbn0gPSBhd2FpdCBnZXRJbWFnZU9jY3VycmVuY2UoZnVsbEltYWdlLCBwYXJ0aWFsSW1hZ2UsIHt2aXN1YWxpemU6IHRydWV9KTtcbiAgICAgICAgdmlzdWFsaXphdGlvbi5zaG91bGQubm90LmJlLmVtcHR5O1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCdtdWx0aXBsZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gbWF0Y2hlcyBpbiB0aGUgZnVsbCBpbWFnZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCB7IG11bHRpcGxlIH0gPSBhd2FpdCBnZXRJbWFnZU9jY3VycmVuY2Uob3JpZ2luYWxJbWFnZSwgbnVtYmVySW1hZ2UsIHt0aHJlc2hvbGQ6IDAuOCwgbXVsdGlwbGU6IHRydWV9KTtcbiAgICAgICAgICBtdWx0aXBsZS5sZW5ndGguc2hvdWxkLmJlLmVxKDMpO1xuXG4gICAgICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgbXVsdGlwbGUpIHtcbiAgICAgICAgICAgIHJlc3VsdC5yZWN0Lnguc2hvdWxkLmJlLmFib3ZlKDApO1xuICAgICAgICAgICAgcmVzdWx0LnJlY3QueS5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgICAgICByZXN1bHQucmVjdC53aWR0aC5zaG91bGQuYmUuYWJvdmUoMCk7XG4gICAgICAgICAgICByZXN1bHQucmVjdC5oZWlnaHQuc2hvdWxkLmJlLmFib3ZlKDApO1xuICAgICAgICAgICAgcmVzdWx0LnNjb3JlLnNob3VsZC5iZS5hYm92ZSgwKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgcmVqZWN0IG1hdGNoZXMgdGhhdCBmYWxsIGJlbG93IGEgdGhyZXNob2xkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IGdldEltYWdlT2NjdXJyZW5jZShvcmlnaW5hbEltYWdlLCBudW1iZXJJbWFnZSwge3RocmVzaG9sZDogMS4wLCBtdWx0aXBsZTogdHJ1ZX0pXG4gICAgICAgICAgICAuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWRXaXRoKC90aHJlc2hvbGQvKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCB2aXN1YWxpemUgdGhlIHBhcnRpYWwgaW1hZ2UgcG9zaXRpb24gaW4gdGhlIGZ1bGwgaW1hZ2UnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgeyBtdWx0aXBsZSB9ID0gYXdhaXQgZ2V0SW1hZ2VPY2N1cnJlbmNlKG9yaWdpbmFsSW1hZ2UsIG51bWJlckltYWdlLCB7dmlzdWFsaXplOiB0cnVlLCBtdWx0aXBsZTogdHJ1ZX0pO1xuXG4gICAgICAgICAgZm9yIChjb25zdCByZXN1bHQgb2YgbXVsdGlwbGUpIHtcbiAgICAgICAgICAgIHJlc3VsdC52aXN1YWxpemF0aW9uLnNob3VsZC5ub3QuYmUuZW1wdHk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnSmltcCBoZWxwZXJzJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgZ2V0IGEgamltcCBvYmplY3QgdXNpbmcgaW1hZ2UgYnVmZmVyJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYmFzZTY0SW1hZ2UgPSBhd2FpdCBnZXRJbWFnZSgnY3JvcHBlZC1pbWFnZS5iNjQnKTtcbiAgICAgIGNvbnN0IGltYWdlQnVmZmVyID0gQnVmZmVyLmZyb20oYmFzZTY0SW1hZ2UsICdiYXNlNjQnKTtcbiAgICAgIGNvbnN0IGppbXBJbWcgPSBhd2FpdCBnZXRKaW1wSW1hZ2UoaW1hZ2VCdWZmZXIpO1xuICAgICAgamltcEltZy5oYXNoKCkuc2hvdWxkLmVxbCgnODAwMDAwMDAwMDAnKTtcbiAgICAgIGppbXBJbWcuYml0bWFwLmhlaWdodC5zaG91bGQuZXFsKDQ4NSk7XG4gICAgICBqaW1wSW1nLmJpdG1hcC53aWR0aC5zaG91bGQuZXFsKDMyMyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBnZXQgYSBqaW1wIG9iamVjdCB1c2luZyBiNjQgc3RyaW5nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgYmFzZTY0SW1hZ2UgPSBhd2FpdCBnZXRJbWFnZSgnY3JvcHBlZC1pbWFnZS5iNjQnKTtcbiAgICAgIGNvbnN0IGppbXBJbWcgPSBhd2FpdCBnZXRKaW1wSW1hZ2UoYmFzZTY0SW1hZ2UpO1xuICAgICAgamltcEltZy5oYXNoKCkuc2hvdWxkLmVxbCgnODAwMDAwMDAwMDAnKTtcbiAgICAgIGppbXBJbWcuYml0bWFwLmhlaWdodC5zaG91bGQuZXFsKDQ4NSk7XG4gICAgICBqaW1wSW1nLmJpdG1hcC53aWR0aC5zaG91bGQuZXFsKDMyMyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBlcnJvciB3aXRoIGluY29ycmVjdCBkYXRhIHR5cGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBnZXRKaW1wSW1hZ2UoMTIzNCkuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWRXaXRoKC9zdHJpbmcgb3IgYnVmZmVyLyk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCBlcnJvciB3aXRoIGluY29ycmVjdCBpbWFnZSBkYXRhJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgZ2V0SmltcEltYWdlKCdmb28nKS5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZFdpdGgoL0NvdWxkIG5vdCBmaW5kIE1JTUUgZm9yIEJ1ZmZlci8pO1xuICAgIH0pO1xuICAgIGl0KCdzaG91bGQgZ2V0IGFuIGltYWdlIGJ1ZmZlciB2aWEgdGhlIG92ZXJyaWRkZW4gZ2V0QnVmZmVyIG1ldGhvZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGJhc2U2NEltYWdlID0gYXdhaXQgZ2V0SW1hZ2UoJ2Nyb3BwZWQtaW1hZ2UuYjY0Jyk7XG4gICAgICBjb25zdCBqaW1wSW1nID0gYXdhaXQgZ2V0SmltcEltYWdlKGJhc2U2NEltYWdlKTtcbiAgICAgIGNvbnN0IGJ1ZiA9IGF3YWl0IGppbXBJbWcuZ2V0QnVmZmVyKE1JTUVfUE5HKTtcbiAgICAgIF8uaXNCdWZmZXIoYnVmKS5zaG91bGQuYmUudHJ1ZTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdLCJmaWxlIjoidGVzdC9pbWFnZS11dGlsLWUyZS1zcGVjcy5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLiJ9