@appium/driver-test-support 0.2.0 → 0.3.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.
@@ -1,551 +1,567 @@
1
1
  "use strict";
2
-
3
- var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
-
5
- Object.defineProperty(exports, "__esModule", {
6
- value: true
7
- });
8
- exports.driverUnitTestSuite = driverUnitTestSuite;
9
-
10
- require("source-map-support/register");
11
-
12
- var _lodash = _interopRequireDefault(require("lodash"));
13
-
14
- var _bluebird = _interopRequireDefault(require("bluebird"));
15
-
16
- var _sinon = require("sinon");
17
-
18
- var _chai = _interopRequireDefault(require("chai"));
19
-
20
- const should = _chai.default.should();
21
-
22
- const {
23
- expect
24
- } = _chai.default;
25
-
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.driverUnitTestSuite = void 0;
7
+ const lodash_1 = __importDefault(require("lodash"));
8
+ const bluebird_1 = __importDefault(require("bluebird"));
9
+ const sinon_1 = require("sinon");
10
+ const chai_1 = __importDefault(require("chai"));
11
+ const should = chai_1.default.should();
12
+ const { expect } = chai_1.default;
13
+ // wrap these tests in a function so we can export the tests and re-use them
14
+ // for actual driver implementations
15
+ /**
16
+ * Creates unit test suites for a driver.
17
+ * @param {DriverClass} DriverClass
18
+ * @param {Partial<BaseNSCapabilities>} [defaultCaps]
19
+ */
26
20
  function driverUnitTestSuite(DriverClass, defaultCaps = {}) {
27
- const className = DriverClass.name ?? '(unknown driver)';
28
- describe(`BaseDriver unit suite (as ${className})`, function () {
29
- let d;
30
- let w3cCaps;
31
- let sandbox;
32
- beforeEach(function () {
33
- sandbox = (0, _sinon.createSandbox)();
34
- d = new DriverClass();
35
- w3cCaps = {
36
- alwaysMatch: { ...defaultCaps,
37
- platformName: 'Fake',
38
- 'appium:deviceName': 'Commodore 64'
39
- },
40
- firstMatch: [{}]
41
- };
42
- });
43
- afterEach(async function () {
44
- sandbox.restore();
45
- await d.deleteSession();
46
- });
47
- describe('static property', function () {
48
- describe('baseVersion', function () {
49
- it('should exist', function () {
50
- DriverClass.baseVersion.should.exist;
51
- });
52
- });
53
- });
54
- describe('Log prefix', function () {
55
- it('should setup log prefix', async function () {
56
- const d = new DriverClass();
57
- const previousPrefix = d.log.prefix;
58
- await d.createSession({
59
- alwaysMatch: { ...defaultCaps,
60
- platformName: 'Fake',
61
- 'appium:deviceName': 'Commodore 64'
62
- },
63
- firstMatch: [{}]
21
+ // to display the driver under test in report
22
+ const className = DriverClass.name ?? '(unknown driver)';
23
+ describe(`BaseDriver unit suite (as ${className})`, function () {
24
+ /** @type {InstanceType<typeof DriverClass>} */
25
+ let d;
26
+ /** @type {W3CCapabilities} */
27
+ let w3cCaps;
28
+ /** @type {import('sinon').SinonSandbox} */
29
+ let sandbox;
30
+ beforeEach(function () {
31
+ sandbox = (0, sinon_1.createSandbox)();
32
+ d = new DriverClass();
33
+ w3cCaps = {
34
+ alwaysMatch: {
35
+ ...defaultCaps,
36
+ platformName: 'Fake',
37
+ 'appium:deviceName': 'Commodore 64',
38
+ },
39
+ firstMatch: [{}],
40
+ };
41
+ });
42
+ afterEach(async function () {
43
+ sandbox.restore();
44
+ await d.deleteSession();
45
+ });
46
+ describe('static property', function () {
47
+ describe('baseVersion', function () {
48
+ it('should exist', function () {
49
+ DriverClass.baseVersion.should.exist;
50
+ });
51
+ });
52
+ });
53
+ describe('Log prefix', function () {
54
+ it('should setup log prefix', async function () {
55
+ const d = new DriverClass();
56
+ const previousPrefix = d.log.prefix;
57
+ await d.createSession({
58
+ alwaysMatch: { ...defaultCaps, platformName: 'Fake', 'appium:deviceName': 'Commodore 64' },
59
+ firstMatch: [{}],
60
+ });
61
+ try {
62
+ expect(previousPrefix).not.to.eql(d.log.prefix);
63
+ }
64
+ finally {
65
+ await d.deleteSession();
66
+ expect(previousPrefix).to.eql(d.log.prefix);
67
+ }
68
+ });
69
+ });
70
+ it('should return an empty status object', async function () {
71
+ let status = await d.getStatus();
72
+ status.should.eql({});
73
+ });
74
+ it('should return a sessionId from createSession', async function () {
75
+ let [sessId] = await d.createSession(w3cCaps);
76
+ should.exist(sessId);
77
+ sessId.should.be.a('string');
78
+ sessId.length.should.be.above(5);
79
+ });
80
+ it('should not be able to start two sessions without closing the first', async function () {
81
+ await d.createSession(lodash_1.default.cloneDeep(w3cCaps));
82
+ await d.createSession(lodash_1.default.cloneDeep(w3cCaps)).should.be.rejectedWith('session');
83
+ });
84
+ it('should be able to delete a session', async function () {
85
+ let sessionId1 = await d.createSession(lodash_1.default.cloneDeep(w3cCaps));
86
+ await d.deleteSession();
87
+ should.equal(d.sessionId, null);
88
+ let sessionId2 = await d.createSession(lodash_1.default.cloneDeep(w3cCaps));
89
+ sessionId1.should.not.eql(sessionId2);
90
+ });
91
+ it('should get the current session', async function () {
92
+ let [, caps] = await d.createSession(w3cCaps);
93
+ caps.should.equal(await d.getSession());
94
+ });
95
+ it('should return sessions if no session exists', async function () {
96
+ let sessions = await d.getSessions();
97
+ sessions.length.should.equal(0);
98
+ });
99
+ it('should return sessions', async function () {
100
+ const caps = lodash_1.default.cloneDeep(w3cCaps);
101
+ await d.createSession(caps);
102
+ let sessions = await d.getSessions();
103
+ sessions.length.should.equal(1);
104
+ sessions[0].should.include({
105
+ id: d.sessionId,
106
+ });
107
+ sessions[0].capabilities.should.include({
108
+ deviceName: 'Commodore 64',
109
+ platformName: 'Fake',
110
+ });
111
+ });
112
+ it('should fulfill an unexpected driver quit promise', async function () {
113
+ // make a command that will wait a bit so we can crash while it's running
114
+ sandbox.stub(d, 'getStatus').callsFake(async () => {
115
+ await bluebird_1.default.delay(1000);
116
+ return 'good status';
117
+ });
118
+ let cmdPromise = d.executeCommand('getStatus');
119
+ await bluebird_1.default.delay(10);
120
+ const p = new bluebird_1.default((resolve, reject) => {
121
+ setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
122
+ d.onUnexpectedShutdown(resolve);
123
+ });
124
+ d.startUnexpectedShutdown(new Error('We crashed'));
125
+ await cmdPromise.should.be.rejectedWith(/We crashed/);
126
+ await p;
127
+ });
128
+ it('should not allow commands in middle of unexpected shutdown', async function () {
129
+ // make a command that will wait a bit so we can crash while it's running
130
+ sandbox.stub(d, 'deleteSession').callsFake(async function () {
131
+ await bluebird_1.default.delay(100);
132
+ DriverClass.prototype.deleteSession.call(this);
133
+ });
134
+ await d.createSession(w3cCaps);
135
+ const p = new bluebird_1.default((resolve, reject) => {
136
+ setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
137
+ d.onUnexpectedShutdown(resolve);
138
+ });
139
+ d.startUnexpectedShutdown(new Error('We crashed'));
140
+ await p;
141
+ await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
142
+ });
143
+ it('should allow new commands after done shutting down', async function () {
144
+ // make a command that will wait a bit so we can crash while it's running
145
+ sandbox.stub(d, 'deleteSession').callsFake(async function () {
146
+ await bluebird_1.default.delay(100);
147
+ DriverClass.prototype.deleteSession.call(this);
148
+ });
149
+ await d.createSession(lodash_1.default.cloneDeep(w3cCaps));
150
+ const p = new bluebird_1.default((resolve, reject) => {
151
+ setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
152
+ d.onUnexpectedShutdown(resolve);
153
+ });
154
+ d.startUnexpectedShutdown(new Error('We crashed'));
155
+ await p;
156
+ await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
157
+ await bluebird_1.default.delay(500);
158
+ await d.executeCommand('createSession', null, null, lodash_1.default.cloneDeep(w3cCaps));
159
+ await d.deleteSession();
160
+ });
161
+ it('should distinguish between W3C and JSONWP session', async function () {
162
+ // Test W3C (leave first 2 args null because those are the JSONWP args)
163
+ await d.executeCommand('createSession', null, null, {
164
+ alwaysMatch: {
165
+ ...defaultCaps,
166
+ platformName: 'Fake',
167
+ 'appium:deviceName': 'Commodore 64',
168
+ },
169
+ firstMatch: [{}],
170
+ });
171
+ expect(d.protocol).to.equal('W3C');
172
+ });
173
+ describe('protocol detection', function () {
174
+ it('should use W3C if only W3C caps are provided', async function () {
175
+ await d.createSession({
176
+ alwaysMatch: lodash_1.default.clone(defaultCaps),
177
+ firstMatch: [{}],
178
+ });
179
+ expect(d.protocol).to.equal('W3C');
180
+ });
181
+ });
182
+ it('should have a method to get driver for a session', async function () {
183
+ let [sessId] = await d.createSession(w3cCaps);
184
+ expect(d.driverForSession(sessId)).to.eql(d);
185
+ });
186
+ describe('command queue', function () {
187
+ /** @type {InstanceType<DriverClass>} */
188
+ let d;
189
+ let waitMs = 10;
190
+ beforeEach(function () {
191
+ d = new DriverClass();
192
+ sandbox.stub(d, 'getStatus').callsFake(async () => {
193
+ await bluebird_1.default.delay(waitMs);
194
+ return Date.now();
195
+ });
196
+ sandbox.stub(d, 'getSessions').callsFake(async () => {
197
+ await bluebird_1.default.delay(waitMs);
198
+ throw new Error('multipass');
199
+ });
200
+ });
201
+ afterEach(async function () {
202
+ await d.clearNewCommandTimeout();
203
+ });
204
+ it('should queue commands and.executeCommand/respond in the order received', async function () {
205
+ let numCmds = 10;
206
+ let cmds = [];
207
+ for (let i = 0; i < numCmds; i++) {
208
+ cmds.push(d.executeCommand('getStatus'));
209
+ }
210
+ let results = await bluebird_1.default.all(cmds);
211
+ for (let i = 1; i < numCmds; i++) {
212
+ if (results[i] <= results[i - 1]) {
213
+ throw new Error('Got result out of order');
214
+ }
215
+ }
216
+ });
217
+ it('should handle errors correctly when queuing', async function () {
218
+ let numCmds = 10;
219
+ let cmds = [];
220
+ for (let i = 0; i < numCmds; i++) {
221
+ if (i === 5) {
222
+ cmds.push(d.executeCommand('getSessions'));
223
+ }
224
+ else {
225
+ cmds.push(d.executeCommand('getStatus'));
226
+ }
227
+ }
228
+ let results = /** @type {PromiseFulfilledResult<any>[]} */ (
229
+ // eslint-disable-next-line promise/no-native
230
+ await Promise.allSettled(cmds));
231
+ for (let i = 1; i < 5; i++) {
232
+ if (results[i].value <= results[i - 1].value) {
233
+ throw new Error('Got result out of order');
234
+ }
235
+ }
236
+ /** @type {PromiseRejectedResult} */ (
237
+ /** @type {unknown} */ (results[5])).reason.message.should.contain('multipass');
238
+ for (let i = 7; i < numCmds; i++) {
239
+ if (results[i].value <= results[i - 1].value) {
240
+ throw new Error('Got result out of order');
241
+ }
242
+ }
243
+ });
244
+ it('should not care if queue empties for a bit', async function () {
245
+ let numCmds = 10;
246
+ let cmds = [];
247
+ for (let i = 0; i < numCmds; i++) {
248
+ cmds.push(d.executeCommand('getStatus'));
249
+ }
250
+ let results = await bluebird_1.default.all(cmds);
251
+ cmds = [];
252
+ for (let i = 0; i < numCmds; i++) {
253
+ cmds.push(d.executeCommand('getStatus'));
254
+ }
255
+ results = await bluebird_1.default.all(cmds);
256
+ for (let i = 1; i < numCmds; i++) {
257
+ if (results[i] <= results[i - 1]) {
258
+ throw new Error('Got result out of order');
259
+ }
260
+ }
261
+ });
262
+ });
263
+ describe('timeouts', function () {
264
+ before(async function () {
265
+ await d.createSession(w3cCaps);
266
+ });
267
+ describe('command', function () {
268
+ it('should exist by default', function () {
269
+ d.newCommandTimeoutMs.should.equal(60000);
270
+ });
271
+ it('should be settable through `timeouts`', async function () {
272
+ await d.timeouts('command', 20);
273
+ d.newCommandTimeoutMs.should.equal(20);
274
+ });
275
+ });
276
+ describe('implicit', function () {
277
+ it('should not exist by default', function () {
278
+ d.implicitWaitMs.should.equal(0);
279
+ });
280
+ it('should be settable through `timeouts`', async function () {
281
+ await d.timeouts('implicit', 20);
282
+ d.implicitWaitMs.should.equal(20);
283
+ });
284
+ });
285
+ });
286
+ describe('timeouts (W3C)', function () {
287
+ beforeEach(async function () {
288
+ await d.createSession(w3cCaps);
289
+ });
290
+ afterEach(async function () {
291
+ await d.deleteSession();
292
+ });
293
+ it('should get timeouts that we set', async function () {
294
+ // @ts-expect-error
295
+ await d.timeouts(undefined, undefined, undefined, undefined, 1000);
296
+ await d.getTimeouts().should.eventually.have.property('implicit', 1000);
297
+ await d.timeouts('command', 2000);
298
+ await d.getTimeouts().should.eventually.deep.equal({
299
+ implicit: 1000,
300
+ command: 2000,
301
+ });
302
+ // @ts-expect-error
303
+ await d.timeouts(undefined, undefined, undefined, undefined, 3000);
304
+ await d.getTimeouts().should.eventually.deep.equal({
305
+ implicit: 3000,
306
+ command: 2000,
307
+ });
308
+ });
309
+ });
310
+ describe('reset compatibility', function () {
311
+ it('should not allow both fullReset and noReset to be true', async function () {
312
+ const newCaps = {
313
+ alwaysMatch: {
314
+ ...defaultCaps,
315
+ platformName: 'Fake',
316
+ 'appium:deviceName': 'Commodore 64',
317
+ 'appium:fullReset': true,
318
+ 'appium:noReset': true,
319
+ },
320
+ firstMatch: [{}],
321
+ };
322
+ await d.createSession(newCaps).should.be.rejectedWith(/noReset.+fullReset/);
323
+ });
324
+ });
325
+ describe('proxying', function () {
326
+ let sessId;
327
+ beforeEach(async function () {
328
+ [sessId] = await d.createSession(w3cCaps);
329
+ });
330
+ describe('#proxyActive', function () {
331
+ it('should exist', function () {
332
+ d.proxyActive.should.be.an.instanceof(Function);
333
+ });
334
+ it('should return false', function () {
335
+ d.proxyActive(sessId).should.be.false;
336
+ });
337
+ it('should throw an error when sessionId is wrong', function () {
338
+ (() => {
339
+ d.proxyActive('aaa');
340
+ }).should.throw;
341
+ });
342
+ });
343
+ describe('#getProxyAvoidList', function () {
344
+ it('should exist', function () {
345
+ d.getProxyAvoidList.should.be.an.instanceof(Function);
346
+ });
347
+ it('should return an array', function () {
348
+ d.getProxyAvoidList(sessId).should.be.an.instanceof(Array);
349
+ });
350
+ it('should throw an error when sessionId is wrong', function () {
351
+ (() => {
352
+ d.getProxyAvoidList('aaa');
353
+ }).should.throw;
354
+ });
355
+ });
356
+ describe('#canProxy', function () {
357
+ it('should have a #canProxy method', function () {
358
+ d.canProxy.should.be.an.instanceof(Function);
359
+ });
360
+ it('should return a boolean from #canProxy', function () {
361
+ d.canProxy(sessId).should.be.a('boolean');
362
+ });
363
+ it('should throw an error when sessionId is wrong', function () {
364
+ (() => {
365
+ d.canProxy();
366
+ }).should.throw;
367
+ });
368
+ });
369
+ describe('#proxyRouteIsAvoided', function () {
370
+ it('should validate form of avoidance list', function () {
371
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
372
+ // @ts-expect-error
373
+ avoidStub.returns([['POST', /\/foo/], ['GET']]);
374
+ (() => {
375
+ // @ts-expect-error
376
+ d.proxyRouteIsAvoided();
377
+ }).should.throw;
378
+ avoidStub.returns([
379
+ ['POST', /\/foo/],
380
+ // @ts-expect-error
381
+ ['GET', /^foo/, 'bar'],
382
+ ]);
383
+ (() => {
384
+ // @ts-expect-error
385
+ d.proxyRouteIsAvoided();
386
+ }).should.throw;
387
+ });
388
+ it('should reject bad http methods', function () {
389
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
390
+ avoidStub.returns([
391
+ ['POST', /^foo/],
392
+ // @ts-expect-error
393
+ ['BAZETE', /^bar/],
394
+ ]);
395
+ (() => {
396
+ // @ts-expect-error
397
+ d.proxyRouteIsAvoided();
398
+ }).should.throw;
399
+ });
400
+ it('should reject non-regex routes', function () {
401
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
402
+ avoidStub.returns([
403
+ ['POST', /^foo/],
404
+ // @ts-expect-error
405
+ ['GET', '/bar'],
406
+ ]);
407
+ (() => {
408
+ // @ts-expect-error
409
+ d.proxyRouteIsAvoided();
410
+ }).should.throw;
411
+ });
412
+ it('should return true for routes in the avoid list', function () {
413
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
414
+ avoidStub.returns([['POST', /^\/foo/]]);
415
+ d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
416
+ });
417
+ it('should strip away any wd/hub prefix', function () {
418
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
419
+ avoidStub.returns([['POST', /^\/foo/]]);
420
+ d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
421
+ });
422
+ it('should return false for routes not in the avoid list', function () {
423
+ const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
424
+ avoidStub.returns([['POST', /^\/foo/]]);
425
+ d.proxyRouteIsAvoided('foo', 'GET', '/foo/bar').should.be.false;
426
+ d.proxyRouteIsAvoided('foo', 'POST', '/boo').should.be.false;
427
+ });
428
+ });
429
+ });
430
+ describe('event timing framework', function () {
431
+ let beforeStartTime;
432
+ beforeEach(async function () {
433
+ beforeStartTime = Date.now();
434
+ d.shouldValidateCaps = false;
435
+ await d.executeCommand('createSession', null, null, {
436
+ alwaysMatch: { ...defaultCaps },
437
+ firstMatch: [{}],
438
+ });
439
+ });
440
+ describe('#eventHistory', function () {
441
+ it('should have an eventHistory property', function () {
442
+ should.exist(d.eventHistory);
443
+ should.exist(d.eventHistory.commands);
444
+ });
445
+ it('should have a session start timing after session start', function () {
446
+ let { newSessionRequested, newSessionStarted } = d.eventHistory;
447
+ newSessionRequested.should.have.length(1);
448
+ newSessionStarted.should.have.length(1);
449
+ newSessionRequested[0].should.be.a('number');
450
+ newSessionStarted[0].should.be.a('number');
451
+ (newSessionRequested[0] >= beforeStartTime).should.be.true;
452
+ (newSessionStarted[0] >= newSessionRequested[0]).should.be.true;
453
+ });
454
+ it('should include a commands list', async function () {
455
+ await d.executeCommand('getStatus', []);
456
+ d.eventHistory.commands.length.should.equal(2);
457
+ d.eventHistory.commands[1].cmd.should.equal('getStatus');
458
+ d.eventHistory.commands[1].startTime.should.be.a('number');
459
+ d.eventHistory.commands[1].endTime.should.be.a('number');
460
+ });
461
+ });
462
+ describe('#logEvent', function () {
463
+ it('should allow logging arbitrary events', function () {
464
+ d.logEvent('foo');
465
+ d.eventHistory.foo[0].should.be.a('number');
466
+ (d.eventHistory.foo[0] >= beforeStartTime).should.be.true;
467
+ });
468
+ it('should not allow reserved or oddly formed event names', function () {
469
+ (() => {
470
+ d.logEvent('commands');
471
+ }).should.throw();
472
+ (() => {
473
+ // @ts-expect-error
474
+ d.logEvent(1);
475
+ }).should.throw();
476
+ (() => {
477
+ // @ts-expect-error
478
+ d.logEvent({});
479
+ }).should.throw();
480
+ });
481
+ });
482
+ it('should allow logging the same event multiple times', function () {
483
+ d.logEvent('bar');
484
+ d.logEvent('bar');
485
+ d.eventHistory.bar.should.have.length(2);
486
+ d.eventHistory.bar[1].should.be.a('number');
487
+ (d.eventHistory.bar[1] >= d.eventHistory.bar[0]).should.be.true;
488
+ });
489
+ describe('getSession decoration', function () {
490
+ it('should decorate getSession response if opt-in cap is provided', async function () {
491
+ let res = await d.getSession();
492
+ should.not.exist(res.events);
493
+ lodash_1.default.set(d, 'caps.eventTimings', true);
494
+ res = await d.getSession();
495
+ should.exist(res.events);
496
+ should.exist(res.events?.newSessionRequested);
497
+ expect(res.events?.newSessionRequested[0]).to.be.a('number');
498
+ });
499
+ });
500
+ });
501
+ describe('.reset', function () {
502
+ it('should reset as W3C if the original session was W3C', async function () {
503
+ const caps = {
504
+ alwaysMatch: {
505
+ 'appium:app': 'Fake',
506
+ 'appium:deviceName': 'Fake',
507
+ 'appium:automationName': 'Fake',
508
+ platformName: 'Fake',
509
+ ...defaultCaps,
510
+ },
511
+ firstMatch: [{}],
512
+ };
513
+ await d.createSession(caps);
514
+ expect(d.protocol).to.equal('W3C');
515
+ await d.reset();
516
+ expect(d.protocol).to.equal('W3C');
517
+ });
64
518
  });
65
-
66
- try {
67
- expect(previousPrefix).not.to.eql(d.log.prefix);
68
- } finally {
69
- await d.deleteSession();
70
- expect(previousPrefix).to.eql(d.log.prefix);
71
- }
72
- });
73
- });
74
- it('should return an empty status object', async function () {
75
- let status = await d.getStatus();
76
- status.should.eql({});
77
- });
78
- it('should return a sessionId from createSession', async function () {
79
- let [sessId] = await d.createSession(w3cCaps);
80
- should.exist(sessId);
81
- sessId.should.be.a('string');
82
- sessId.length.should.be.above(5);
83
- });
84
- it('should not be able to start two sessions without closing the first', async function () {
85
- await d.createSession(_lodash.default.cloneDeep(w3cCaps));
86
- await d.createSession(_lodash.default.cloneDeep(w3cCaps)).should.be.rejectedWith('session');
87
- });
88
- it('should be able to delete a session', async function () {
89
- let sessionId1 = await d.createSession(_lodash.default.cloneDeep(w3cCaps));
90
- await d.deleteSession();
91
- should.equal(d.sessionId, null);
92
- let sessionId2 = await d.createSession(_lodash.default.cloneDeep(w3cCaps));
93
- sessionId1.should.not.eql(sessionId2);
94
- });
95
- it('should get the current session', async function () {
96
- let [, caps] = await d.createSession(w3cCaps);
97
- caps.should.equal(await d.getSession());
98
- });
99
- it('should return sessions if no session exists', async function () {
100
- let sessions = await d.getSessions();
101
- sessions.length.should.equal(0);
102
- });
103
- it('should return sessions', async function () {
104
- const caps = _lodash.default.cloneDeep(w3cCaps);
105
-
106
- await d.createSession(caps);
107
- let sessions = await d.getSessions();
108
- sessions.length.should.equal(1);
109
- sessions[0].should.include({
110
- id: d.sessionId
111
- });
112
- sessions[0].capabilities.should.include({
113
- deviceName: 'Commodore 64',
114
- platformName: 'Fake'
115
- });
116
- });
117
- it('should fulfill an unexpected driver quit promise', async function () {
118
- sandbox.stub(d, 'getStatus').callsFake(async () => {
119
- await _bluebird.default.delay(1000);
120
- return 'good status';
121
- });
122
- let cmdPromise = d.executeCommand('getStatus');
123
- await _bluebird.default.delay(10);
124
- const p = new _bluebird.default((resolve, reject) => {
125
- setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
126
- d.onUnexpectedShutdown(resolve);
127
- });
128
- d.startUnexpectedShutdown(new Error('We crashed'));
129
- await cmdPromise.should.be.rejectedWith(/We crashed/);
130
- await p;
131
- });
132
- it('should not allow commands in middle of unexpected shutdown', async function () {
133
- sandbox.stub(d, 'deleteSession').callsFake(async function () {
134
- await _bluebird.default.delay(100);
135
- DriverClass.prototype.deleteSession.call(this);
136
- });
137
- await d.createSession(w3cCaps);
138
- const p = new _bluebird.default((resolve, reject) => {
139
- setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
140
- d.onUnexpectedShutdown(resolve);
141
- });
142
- d.startUnexpectedShutdown(new Error('We crashed'));
143
- await p;
144
- await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
145
- });
146
- it('should allow new commands after done shutting down', async function () {
147
- sandbox.stub(d, 'deleteSession').callsFake(async function () {
148
- await _bluebird.default.delay(100);
149
- DriverClass.prototype.deleteSession.call(this);
150
- });
151
- await d.createSession(_lodash.default.cloneDeep(w3cCaps));
152
- const p = new _bluebird.default((resolve, reject) => {
153
- setTimeout(() => reject(new Error('onUnexpectedShutdown event is expected to be fired within 5 seconds timeout')), 5000);
154
- d.onUnexpectedShutdown(resolve);
155
- });
156
- d.startUnexpectedShutdown(new Error('We crashed'));
157
- await p;
158
- await d.executeCommand('getSession').should.be.rejectedWith(/shut down/);
159
- await _bluebird.default.delay(500);
160
- await d.executeCommand('createSession', null, null, _lodash.default.cloneDeep(w3cCaps));
161
- await d.deleteSession();
162
- });
163
- it('should distinguish between W3C and JSONWP session', async function () {
164
- await d.executeCommand('createSession', null, null, {
165
- alwaysMatch: { ...defaultCaps,
166
- platformName: 'Fake',
167
- 'appium:deviceName': 'Commodore 64'
168
- },
169
- firstMatch: [{}]
170
- });
171
- expect(d.protocol).to.equal('W3C');
172
519
  });
173
- describe('protocol detection', function () {
174
- it('should use W3C if only W3C caps are provided', async function () {
175
- await d.createSession({
176
- alwaysMatch: _lodash.default.clone(defaultCaps),
177
- firstMatch: [{}]
520
+ describe('.isFeatureEnabled', function () {
521
+ let d;
522
+ beforeEach(function () {
523
+ d = new DriverClass();
524
+ });
525
+ it('should say a feature is enabled when it is explicitly allowed', function () {
526
+ d.allowInsecure = ['foo', 'bar'];
527
+ d.isFeatureEnabled('foo').should.be.true;
528
+ d.isFeatureEnabled('bar').should.be.true;
529
+ d.isFeatureEnabled('baz').should.be.false;
530
+ });
531
+ it('should say a feature is not enabled if it is not enabled', function () {
532
+ d.allowInsecure = [];
533
+ d.isFeatureEnabled('foo').should.be.false;
534
+ });
535
+ it('should prefer denyInsecure to allowInsecure', function () {
536
+ d.allowInsecure = ['foo', 'bar'];
537
+ d.denyInsecure = ['foo'];
538
+ d.isFeatureEnabled('foo').should.be.false;
539
+ d.isFeatureEnabled('bar').should.be.true;
540
+ d.isFeatureEnabled('baz').should.be.false;
541
+ });
542
+ it('should allow global setting for insecurity', function () {
543
+ d.relaxedSecurityEnabled = true;
544
+ d.isFeatureEnabled('foo').should.be.true;
545
+ d.isFeatureEnabled('bar').should.be.true;
546
+ d.isFeatureEnabled('baz').should.be.true;
547
+ });
548
+ it('global setting should be overrideable', function () {
549
+ d.relaxedSecurityEnabled = true;
550
+ d.denyInsecure = ['foo', 'bar'];
551
+ d.isFeatureEnabled('foo').should.be.false;
552
+ d.isFeatureEnabled('bar').should.be.false;
553
+ d.isFeatureEnabled('baz').should.be.true;
178
554
  });
179
- expect(d.protocol).to.equal('W3C');
180
- });
181
555
  });
182
- it('should have a method to get driver for a session', async function () {
183
- let [sessId] = await d.createSession(w3cCaps);
184
- expect(d.driverForSession(sessId)).to.eql(d);
185
- });
186
- describe('command queue', function () {
187
- let d;
188
- let waitMs = 10;
189
- beforeEach(function () {
190
- d = new DriverClass();
191
- sandbox.stub(d, 'getStatus').callsFake(async () => {
192
- await _bluebird.default.delay(waitMs);
193
- return Date.now();
194
- });
195
- sandbox.stub(d, 'getSessions').callsFake(async () => {
196
- await _bluebird.default.delay(waitMs);
197
- throw new Error('multipass');
198
- });
199
- });
200
- afterEach(async function () {
201
- await d.clearNewCommandTimeout();
202
- });
203
- it('should queue commands and.executeCommand/respond in the order received', async function () {
204
- let numCmds = 10;
205
- let cmds = [];
206
-
207
- for (let i = 0; i < numCmds; i++) {
208
- cmds.push(d.executeCommand('getStatus'));
209
- }
210
-
211
- let results = await _bluebird.default.all(cmds);
212
-
213
- for (let i = 1; i < numCmds; i++) {
214
- if (results[i] <= results[i - 1]) {
215
- throw new Error('Got result out of order');
216
- }
217
- }
218
- });
219
- it('should handle errors correctly when queuing', async function () {
220
- let numCmds = 10;
221
- let cmds = [];
222
-
223
- for (let i = 0; i < numCmds; i++) {
224
- if (i === 5) {
225
- cmds.push(d.executeCommand('getSessions'));
226
- } else {
227
- cmds.push(d.executeCommand('getStatus'));
228
- }
229
- }
230
-
231
- let results = await Promise.allSettled(cmds);
232
-
233
- for (let i = 1; i < 5; i++) {
234
- if (results[i].value <= results[i - 1].value) {
235
- throw new Error('Got result out of order');
236
- }
237
- }
238
-
239
- results[5].reason.message.should.contain('multipass');
240
-
241
- for (let i = 7; i < numCmds; i++) {
242
- if (results[i].value <= results[i - 1].value) {
243
- throw new Error('Got result out of order');
244
- }
245
- }
246
- });
247
- it('should not care if queue empties for a bit', async function () {
248
- let numCmds = 10;
249
- let cmds = [];
250
-
251
- for (let i = 0; i < numCmds; i++) {
252
- cmds.push(d.executeCommand('getStatus'));
253
- }
254
-
255
- let results = await _bluebird.default.all(cmds);
256
- cmds = [];
257
-
258
- for (let i = 0; i < numCmds; i++) {
259
- cmds.push(d.executeCommand('getStatus'));
260
- }
261
-
262
- results = await _bluebird.default.all(cmds);
263
-
264
- for (let i = 1; i < numCmds; i++) {
265
- if (results[i] <= results[i - 1]) {
266
- throw new Error('Got result out of order');
267
- }
268
- }
269
- });
270
- });
271
- describe('timeouts', function () {
272
- before(async function () {
273
- await d.createSession(w3cCaps);
274
- });
275
- describe('command', function () {
276
- it('should exist by default', function () {
277
- d.newCommandTimeoutMs.should.equal(60000);
278
- });
279
- it('should be settable through `timeouts`', async function () {
280
- await d.timeouts('command', 20);
281
- d.newCommandTimeoutMs.should.equal(20);
282
- });
283
- });
284
- describe('implicit', function () {
285
- it('should not exist by default', function () {
286
- d.implicitWaitMs.should.equal(0);
287
- });
288
- it('should be settable through `timeouts`', async function () {
289
- await d.timeouts('implicit', 20);
290
- d.implicitWaitMs.should.equal(20);
291
- });
292
- });
293
- });
294
- describe('timeouts (W3C)', function () {
295
- beforeEach(async function () {
296
- await d.createSession(w3cCaps);
297
- });
298
- afterEach(async function () {
299
- await d.deleteSession();
300
- });
301
- it('should get timeouts that we set', async function () {
302
- await d.timeouts(undefined, undefined, undefined, undefined, 1000);
303
- await d.getTimeouts().should.eventually.have.property('implicit', 1000);
304
- await d.timeouts('command', 2000);
305
- await d.getTimeouts().should.eventually.deep.equal({
306
- implicit: 1000,
307
- command: 2000
308
- });
309
- await d.timeouts(undefined, undefined, undefined, undefined, 3000);
310
- await d.getTimeouts().should.eventually.deep.equal({
311
- implicit: 3000,
312
- command: 2000
313
- });
314
- });
315
- });
316
- describe('reset compatibility', function () {
317
- it('should not allow both fullReset and noReset to be true', async function () {
318
- const newCaps = {
319
- alwaysMatch: { ...defaultCaps,
320
- platformName: 'Fake',
321
- 'appium:deviceName': 'Commodore 64',
322
- 'appium:fullReset': true,
323
- 'appium:noReset': true
324
- },
325
- firstMatch: [{}]
326
- };
327
- await d.createSession(newCaps).should.be.rejectedWith(/noReset.+fullReset/);
328
- });
329
- });
330
- describe('proxying', function () {
331
- let sessId;
332
- beforeEach(async function () {
333
- [sessId] = await d.createSession(w3cCaps);
334
- });
335
- describe('#proxyActive', function () {
336
- it('should exist', function () {
337
- d.proxyActive.should.be.an.instanceof(Function);
338
- });
339
- it('should return false', function () {
340
- d.proxyActive(sessId).should.be.false;
341
- });
342
- it('should throw an error when sessionId is wrong', function () {
343
- (() => {
344
- d.proxyActive('aaa');
345
- }).should.throw;
346
- });
347
- });
348
- describe('#getProxyAvoidList', function () {
349
- it('should exist', function () {
350
- d.getProxyAvoidList.should.be.an.instanceof(Function);
351
- });
352
- it('should return an array', function () {
353
- d.getProxyAvoidList(sessId).should.be.an.instanceof(Array);
354
- });
355
- it('should throw an error when sessionId is wrong', function () {
356
- (() => {
357
- d.getProxyAvoidList('aaa');
358
- }).should.throw;
359
- });
360
- });
361
- describe('#canProxy', function () {
362
- it('should have a #canProxy method', function () {
363
- d.canProxy.should.be.an.instanceof(Function);
364
- });
365
- it('should return a boolean from #canProxy', function () {
366
- d.canProxy(sessId).should.be.a('boolean');
367
- });
368
- it('should throw an error when sessionId is wrong', function () {
369
- (() => {
370
- d.canProxy();
371
- }).should.throw;
372
- });
373
- });
374
- describe('#proxyRouteIsAvoided', function () {
375
- it('should validate form of avoidance list', function () {
376
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
377
- avoidStub.returns([['POST', /\/foo/], ['GET']]);
378
- (() => {
379
- d.proxyRouteIsAvoided();
380
- }).should.throw;
381
- avoidStub.returns([['POST', /\/foo/], ['GET', /^foo/, 'bar']]);
382
- (() => {
383
- d.proxyRouteIsAvoided();
384
- }).should.throw;
385
- });
386
- it('should reject bad http methods', function () {
387
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
388
- avoidStub.returns([['POST', /^foo/], ['BAZETE', /^bar/]]);
389
- (() => {
390
- d.proxyRouteIsAvoided();
391
- }).should.throw;
392
- });
393
- it('should reject non-regex routes', function () {
394
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
395
- avoidStub.returns([['POST', /^foo/], ['GET', '/bar']]);
396
- (() => {
397
- d.proxyRouteIsAvoided();
398
- }).should.throw;
399
- });
400
- it('should return true for routes in the avoid list', function () {
401
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
402
- avoidStub.returns([['POST', /^\/foo/]]);
403
- d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
404
- });
405
- it('should strip away any wd/hub prefix', function () {
406
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
407
- avoidStub.returns([['POST', /^\/foo/]]);
408
- d.proxyRouteIsAvoided('foo', 'POST', '/foo/bar').should.be.true;
409
- });
410
- it('should return false for routes not in the avoid list', function () {
411
- const avoidStub = sandbox.stub(d, 'getProxyAvoidList');
412
- avoidStub.returns([['POST', /^\/foo/]]);
413
- d.proxyRouteIsAvoided('foo', 'GET', '/foo/bar').should.be.false;
414
- d.proxyRouteIsAvoided('foo', 'POST', '/boo').should.be.false;
415
- });
416
- });
417
- });
418
- describe('event timing framework', function () {
419
- let beforeStartTime;
420
- beforeEach(async function () {
421
- beforeStartTime = Date.now();
422
- d.shouldValidateCaps = false;
423
- await d.executeCommand('createSession', null, null, {
424
- alwaysMatch: { ...defaultCaps
425
- },
426
- firstMatch: [{}]
427
- });
428
- });
429
- describe('#eventHistory', function () {
430
- it('should have an eventHistory property', function () {
431
- should.exist(d.eventHistory);
432
- should.exist(d.eventHistory.commands);
433
- });
434
- it('should have a session start timing after session start', function () {
435
- let {
436
- newSessionRequested,
437
- newSessionStarted
438
- } = d.eventHistory;
439
- newSessionRequested.should.have.length(1);
440
- newSessionStarted.should.have.length(1);
441
- newSessionRequested[0].should.be.a('number');
442
- newSessionStarted[0].should.be.a('number');
443
- (newSessionRequested[0] >= beforeStartTime).should.be.true;
444
- (newSessionStarted[0] >= newSessionRequested[0]).should.be.true;
445
- });
446
- it('should include a commands list', async function () {
447
- await d.executeCommand('getStatus', []);
448
- d.eventHistory.commands.length.should.equal(2);
449
- d.eventHistory.commands[1].cmd.should.equal('getStatus');
450
- d.eventHistory.commands[1].startTime.should.be.a('number');
451
- d.eventHistory.commands[1].endTime.should.be.a('number');
452
- });
453
- });
454
- describe('#logEvent', function () {
455
- it('should allow logging arbitrary events', function () {
456
- d.logEvent('foo');
457
- d.eventHistory.foo[0].should.be.a('number');
458
- (d.eventHistory.foo[0] >= beforeStartTime).should.be.true;
459
- });
460
- it('should not allow reserved or oddly formed event names', function () {
461
- (() => {
462
- d.logEvent('commands');
463
- }).should.throw();
464
- (() => {
465
- d.logEvent(1);
466
- }).should.throw();
467
- (() => {
468
- d.logEvent({});
469
- }).should.throw();
470
- });
471
- });
472
- it('should allow logging the same event multiple times', function () {
473
- d.logEvent('bar');
474
- d.logEvent('bar');
475
- d.eventHistory.bar.should.have.length(2);
476
- d.eventHistory.bar[1].should.be.a('number');
477
- (d.eventHistory.bar[1] >= d.eventHistory.bar[0]).should.be.true;
478
- });
479
- describe('getSession decoration', function () {
480
- it('should decorate getSession response if opt-in cap is provided', async function () {
481
- var _res$events, _res$events2;
482
-
483
- let res = await d.getSession();
484
- should.not.exist(res.events);
485
-
486
- _lodash.default.set(d, 'caps.eventTimings', true);
487
-
488
- res = await d.getSession();
489
- should.exist(res.events);
490
- should.exist((_res$events = res.events) === null || _res$events === void 0 ? void 0 : _res$events.newSessionRequested);
491
- expect((_res$events2 = res.events) === null || _res$events2 === void 0 ? void 0 : _res$events2.newSessionRequested[0]).to.be.a('number');
492
- });
493
- });
494
- });
495
- describe('.reset', function () {
496
- it('should reset as W3C if the original session was W3C', async function () {
497
- const caps = {
498
- alwaysMatch: {
499
- 'appium:app': 'Fake',
500
- 'appium:deviceName': 'Fake',
501
- 'appium:automationName': 'Fake',
502
- platformName: 'Fake',
503
- ...defaultCaps
504
- },
505
- firstMatch: [{}]
506
- };
507
- await d.createSession(caps);
508
- expect(d.protocol).to.equal('W3C');
509
- await d.reset();
510
- expect(d.protocol).to.equal('W3C');
511
- });
512
- });
513
- });
514
- describe('.isFeatureEnabled', function () {
515
- let d;
516
- beforeEach(function () {
517
- d = new DriverClass();
518
- });
519
- it('should say a feature is enabled when it is explicitly allowed', function () {
520
- d.allowInsecure = ['foo', 'bar'];
521
- d.isFeatureEnabled('foo').should.be.true;
522
- d.isFeatureEnabled('bar').should.be.true;
523
- d.isFeatureEnabled('baz').should.be.false;
524
- });
525
- it('should say a feature is not enabled if it is not enabled', function () {
526
- d.allowInsecure = [];
527
- d.isFeatureEnabled('foo').should.be.false;
528
- });
529
- it('should prefer denyInsecure to allowInsecure', function () {
530
- d.allowInsecure = ['foo', 'bar'];
531
- d.denyInsecure = ['foo'];
532
- d.isFeatureEnabled('foo').should.be.false;
533
- d.isFeatureEnabled('bar').should.be.true;
534
- d.isFeatureEnabled('baz').should.be.false;
535
- });
536
- it('should allow global setting for insecurity', function () {
537
- d.relaxedSecurityEnabled = true;
538
- d.isFeatureEnabled('foo').should.be.true;
539
- d.isFeatureEnabled('bar').should.be.true;
540
- d.isFeatureEnabled('baz').should.be.true;
541
- });
542
- it('global setting should be overrideable', function () {
543
- d.relaxedSecurityEnabled = true;
544
- d.denyInsecure = ['foo', 'bar'];
545
- d.isFeatureEnabled('foo').should.be.false;
546
- d.isFeatureEnabled('bar').should.be.false;
547
- d.isFeatureEnabled('baz').should.be.true;
548
- });
549
- });
550
556
  }
551
- //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJzaG91bGQiLCJjaGFpIiwiZXhwZWN0IiwiZHJpdmVyVW5pdFRlc3RTdWl0ZSIsIkRyaXZlckNsYXNzIiwiZGVmYXVsdENhcHMiLCJjbGFzc05hbWUiLCJuYW1lIiwiZGVzY3JpYmUiLCJkIiwidzNjQ2FwcyIsInNhbmRib3giLCJiZWZvcmVFYWNoIiwiY3JlYXRlU2FuZGJveCIsImFsd2F5c01hdGNoIiwicGxhdGZvcm1OYW1lIiwiZmlyc3RNYXRjaCIsImFmdGVyRWFjaCIsInJlc3RvcmUiLCJkZWxldGVTZXNzaW9uIiwiaXQiLCJiYXNlVmVyc2lvbiIsImV4aXN0IiwicHJldmlvdXNQcmVmaXgiLCJsb2ciLCJwcmVmaXgiLCJjcmVhdGVTZXNzaW9uIiwibm90IiwidG8iLCJlcWwiLCJzdGF0dXMiLCJnZXRTdGF0dXMiLCJzZXNzSWQiLCJiZSIsImEiLCJsZW5ndGgiLCJhYm92ZSIsIl8iLCJjbG9uZURlZXAiLCJyZWplY3RlZFdpdGgiLCJzZXNzaW9uSWQxIiwiZXF1YWwiLCJzZXNzaW9uSWQiLCJzZXNzaW9uSWQyIiwiY2FwcyIsImdldFNlc3Npb24iLCJzZXNzaW9ucyIsImdldFNlc3Npb25zIiwiaW5jbHVkZSIsImlkIiwiY2FwYWJpbGl0aWVzIiwiZGV2aWNlTmFtZSIsInN0dWIiLCJjYWxsc0Zha2UiLCJCIiwiZGVsYXkiLCJjbWRQcm9taXNlIiwiZXhlY3V0ZUNvbW1hbmQiLCJwIiwicmVzb2x2ZSIsInJlamVjdCIsInNldFRpbWVvdXQiLCJFcnJvciIsIm9uVW5leHBlY3RlZFNodXRkb3duIiwic3RhcnRVbmV4cGVjdGVkU2h1dGRvd24iLCJwcm90b3R5cGUiLCJjYWxsIiwicHJvdG9jb2wiLCJjbG9uZSIsImRyaXZlckZvclNlc3Npb24iLCJ3YWl0TXMiLCJEYXRlIiwibm93IiwiY2xlYXJOZXdDb21tYW5kVGltZW91dCIsIm51bUNtZHMiLCJjbWRzIiwiaSIsInB1c2giLCJyZXN1bHRzIiwiYWxsIiwiUHJvbWlzZSIsImFsbFNldHRsZWQiLCJ2YWx1ZSIsInJlYXNvbiIsIm1lc3NhZ2UiLCJjb250YWluIiwiYmVmb3JlIiwibmV3Q29tbWFuZFRpbWVvdXRNcyIsInRpbWVvdXRzIiwiaW1wbGljaXRXYWl0TXMiLCJ1bmRlZmluZWQiLCJnZXRUaW1lb3V0cyIsImV2ZW50dWFsbHkiLCJoYXZlIiwicHJvcGVydHkiLCJkZWVwIiwiaW1wbGljaXQiLCJjb21tYW5kIiwibmV3Q2FwcyIsInByb3h5QWN0aXZlIiwiYW4iLCJpbnN0YW5jZW9mIiwiRnVuY3Rpb24iLCJmYWxzZSIsInRocm93IiwiZ2V0UHJveHlBdm9pZExpc3QiLCJBcnJheSIsImNhblByb3h5IiwiYXZvaWRTdHViIiwicmV0dXJucyIsInByb3h5Um91dGVJc0F2b2lkZWQiLCJ0cnVlIiwiYmVmb3JlU3RhcnRUaW1lIiwic2hvdWxkVmFsaWRhdGVDYXBzIiwiZXZlbnRIaXN0b3J5IiwiY29tbWFuZHMiLCJuZXdTZXNzaW9uUmVxdWVzdGVkIiwibmV3U2Vzc2lvblN0YXJ0ZWQiLCJjbWQiLCJzdGFydFRpbWUiLCJlbmRUaW1lIiwibG9nRXZlbnQiLCJmb28iLCJiYXIiLCJyZXMiLCJldmVudHMiLCJzZXQiLCJyZXNldCIsImFsbG93SW5zZWN1cmUiLCJpc0ZlYXR1cmVFbmFibGVkIiwiZGVueUluc2VjdXJlIiwicmVsYXhlZFNlY3VyaXR5RW5hYmxlZCJdLCJzb3VyY2VzIjpbIi4uLy4uL2xpYi91bml0LXN1aXRlLmpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgQiBmcm9tICdibHVlYmlyZCc7XG5pbXBvcnQge2NyZWF0ZVNhbmRib3h9IGZyb20gJ3Npbm9uJztcblxuaW1wb3J0IGNoYWkgZnJvbSAnY2hhaSc7XG5cbmNvbnN0IHNob3VsZCA9IGNoYWkuc2hvdWxkKCk7XG5jb25zdCB7ZXhwZWN0fSA9IGNoYWk7XG5cbi8vIHdyYXAgdGhlc2UgdGVzdHMgaW4gYSBmdW5jdGlvbiBzbyB3ZSBjYW4gZXhwb3J0IHRoZSB0ZXN0cyBhbmQgcmUtdXNlIHRoZW1cbi8vIGZvciBhY3R1YWwgZHJpdmVyIGltcGxlbWVudGF0aW9uc1xuXG4vKipcbiAqIENyZWF0ZXMgdW5pdCB0ZXN0IHN1aXRlcyBmb3IgYSBkcml2ZXIuXG4gKiBAcGFyYW0ge0RyaXZlckNsYXNzfSBEcml2ZXJDbGFzc1xuICogQHBhcmFtIHtBcHBpdW1XM0NDYXBhYmlsaXRpZXN9IFtkZWZhdWx0Q2Fwc11cbiAqL1xuXG5leHBvcnQgZnVuY3Rpb24gZHJpdmVyVW5pdFRlc3RTdWl0ZShEcml2ZXJDbGFzcywgZGVmYXVsdENhcHMgPSB7fSkge1xuICAvLyB0byBkaXNwbGF5IHRoZSBkcml2ZXIgdW5kZXIgdGVzdCBpbiByZXBvcnRcbiAgY29uc3QgY2xhc3NOYW1lID0gRHJpdmVyQ2xhc3MubmFtZSA/PyAnKHVua25vd24gZHJpdmVyKSc7XG5cbiAgZGVzY3JpYmUoYEJhc2VEcml2ZXIgdW5pdCBzdWl0ZSAoYXMgJHtjbGFzc05hbWV9KWAsIGZ1bmN0aW9uICgpIHtcbiAgICAvKiogQHR5cGUge0luc3RhbmNlVHlwZTx0eXBlb2YgRHJpdmVyQ2xhc3M+fSAqL1xuICAgIGxldCBkO1xuICAgIC8qKiBAdHlwZSB7VzNDQ2FwYWJpbGl0aWVzfSAqL1xuICAgIGxldCB3M2NDYXBzO1xuICAgIC8qKiBAdHlwZSB7aW1wb3J0KCdzaW5vbicpLlNpbm9uU2FuZGJveH0gKi9cbiAgICBsZXQgc2FuZGJveDtcblxuICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgc2FuZGJveCA9IGNyZWF0ZVNhbmRib3goKTtcbiAgICAgIGQgPSBuZXcgRHJpdmVyQ2xhc3MoKTtcbiAgICAgIHczY0NhcHMgPSB7XG4gICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgLi4uZGVmYXVsdENhcHMsXG4gICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgJ2FwcGl1bTpkZXZpY2VOYW1lJzogJ0NvbW1vZG9yZSA2NCcsXG4gICAgICAgIH0sXG4gICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICB9O1xuICAgIH0pO1xuICAgIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBzYW5kYm94LnJlc3RvcmUoKTtcbiAgICAgIGF3YWl0IGQuZGVsZXRlU2Vzc2lvbigpO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ3N0YXRpYyBwcm9wZXJ0eScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGRlc2NyaWJlKCdiYXNlVmVyc2lvbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBleGlzdCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBEcml2ZXJDbGFzcy5iYXNlVmVyc2lvbi5zaG91bGQuZXhpc3Q7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnTG9nIHByZWZpeCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgc2V0dXAgbG9nIHByZWZpeCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgZCA9IG5ldyBEcml2ZXJDbGFzcygpO1xuICAgICAgICBjb25zdCBwcmV2aW91c1ByZWZpeCA9IGQubG9nLnByZWZpeDtcbiAgICAgICAgYXdhaXQgZC5jcmVhdGVTZXNzaW9uKHtcbiAgICAgICAgICBhbHdheXNNYXRjaDogey4uLmRlZmF1bHRDYXBzLCBwbGF0Zm9ybU5hbWU6ICdGYWtlJywgJ2FwcGl1bTpkZXZpY2VOYW1lJzogJ0NvbW1vZG9yZSA2NCd9LFxuICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICAgIH0pO1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGV4cGVjdChwcmV2aW91c1ByZWZpeCkubm90LnRvLmVxbChkLmxvZy5wcmVmaXgpO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGF3YWl0IGQuZGVsZXRlU2Vzc2lvbigpO1xuICAgICAgICAgIGV4cGVjdChwcmV2aW91c1ByZWZpeCkudG8uZXFsKGQubG9nLnByZWZpeCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gYW4gZW1wdHkgc3RhdHVzIG9iamVjdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBzdGF0dXMgPSBhd2FpdCBkLmdldFN0YXR1cygpO1xuICAgICAgc3RhdHVzLnNob3VsZC5lcWwoe30pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZXR1cm4gYSBzZXNzaW9uSWQgZnJvbSBjcmVhdGVTZXNzaW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IFtzZXNzSWRdID0gYXdhaXQgZC5jcmVhdGVTZXNzaW9uKHczY0NhcHMpO1xuICAgICAgc2hvdWxkLmV4aXN0KHNlc3NJZCk7XG4gICAgICBzZXNzSWQuc2hvdWxkLmJlLmEoJ3N0cmluZycpO1xuICAgICAgc2Vzc0lkLmxlbmd0aC5zaG91bGQuYmUuYWJvdmUoNSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBiZSBhYmxlIHRvIHN0YXJ0IHR3byBzZXNzaW9ucyB3aXRob3V0IGNsb3NpbmcgdGhlIGZpcnN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgZC5jcmVhdGVTZXNzaW9uKF8uY2xvbmVEZWVwKHczY0NhcHMpKTtcbiAgICAgIGF3YWl0IGQuY3JlYXRlU2Vzc2lvbihfLmNsb25lRGVlcCh3M2NDYXBzKSkuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgnc2Vzc2lvbicpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBiZSBhYmxlIHRvIGRlbGV0ZSBhIHNlc3Npb24nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgc2Vzc2lvbklkMSA9IGF3YWl0IGQuY3JlYXRlU2Vzc2lvbihfLmNsb25lRGVlcCh3M2NDYXBzKSk7XG4gICAgICBhd2FpdCBkLmRlbGV0ZVNlc3Npb24oKTtcbiAgICAgIHNob3VsZC5lcXVhbChkLnNlc3Npb25JZCwgbnVsbCk7XG4gICAgICBsZXQgc2Vzc2lvbklkMiA9IGF3YWl0IGQuY3JlYXRlU2Vzc2lvbihfLmNsb25lRGVlcCh3M2NDYXBzKSk7XG4gICAgICBzZXNzaW9uSWQxLnNob3VsZC5ub3QuZXFsKHNlc3Npb25JZDIpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBnZXQgdGhlIGN1cnJlbnQgc2Vzc2lvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBbLCBjYXBzXSA9IGF3YWl0IGQuY3JlYXRlU2Vzc2lvbih3M2NDYXBzKTtcbiAgICAgIGNhcHMuc2hvdWxkLmVxdWFsKGF3YWl0IGQuZ2V0U2Vzc2lvbigpKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmV0dXJuIHNlc3Npb25zIGlmIG5vIHNlc3Npb24gZXhpc3RzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNlc3Npb25zID0gYXdhaXQgZC5nZXRTZXNzaW9ucygpO1xuICAgICAgc2Vzc2lvbnMubGVuZ3RoLnNob3VsZC5lcXVhbCgwKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgcmV0dXJuIHNlc3Npb25zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgY2FwcyA9IF8uY2xvbmVEZWVwKHczY0NhcHMpO1xuICAgICAgYXdhaXQgZC5jcmVhdGVTZXNzaW9uKGNhcHMpO1xuICAgICAgbGV0IHNlc3Npb25zID0gYXdhaXQgZC5nZXRTZXNzaW9ucygpO1xuXG4gICAgICBzZXNzaW9ucy5sZW5ndGguc2hvdWxkLmVxdWFsKDEpO1xuICAgICAgc2Vzc2lvbnNbMF0uc2hvdWxkLmluY2x1ZGUoe1xuICAgICAgICBpZDogZC5zZXNzaW9uSWQsXG4gICAgICB9KTtcbiAgICAgIHNlc3Npb25zWzBdLmNhcGFiaWxpdGllcy5zaG91bGQuaW5jbHVkZSh7XG4gICAgICAgIGRldmljZU5hbWU6ICdDb21tb2RvcmUgNjQnLFxuICAgICAgICBwbGF0Zm9ybU5hbWU6ICdGYWtlJyxcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBmdWxmaWxsIGFuIHVuZXhwZWN0ZWQgZHJpdmVyIHF1aXQgcHJvbWlzZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8vIG1ha2UgYSBjb21tYW5kIHRoYXQgd2lsbCB3YWl0IGEgYml0IHNvIHdlIGNhbiBjcmFzaCB3aGlsZSBpdCdzIHJ1bm5pbmdcbiAgICAgIHNhbmRib3guc3R1YihkLCAnZ2V0U3RhdHVzJykuY2FsbHNGYWtlKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgQi5kZWxheSgxMDAwKTtcbiAgICAgICAgcmV0dXJuICdnb29kIHN0YXR1cyc7XG4gICAgICB9KTtcbiAgICAgIGxldCBjbWRQcm9taXNlID0gZC5leGVjdXRlQ29tbWFuZCgnZ2V0U3RhdHVzJyk7XG4gICAgICBhd2FpdCBCLmRlbGF5KDEwKTtcbiAgICAgIGNvbnN0IHAgPSBuZXcgQigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICAgKCkgPT5cbiAgICAgICAgICAgIHJlamVjdChcbiAgICAgICAgICAgICAgbmV3IEVycm9yKFxuICAgICAgICAgICAgICAgICdvblVuZXhwZWN0ZWRTaHV0ZG93biBldmVudCBpcyBleHBlY3RlZCB0byBiZSBmaXJlZCB3aXRoaW4gNSBzZWNvbmRzIHRpbWVvdXQnXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICksXG4gICAgICAgICAgNTAwMFxuICAgICAgICApO1xuICAgICAgICBkLm9uVW5leHBlY3RlZFNodXRkb3duKHJlc29sdmUpO1xuICAgICAgfSk7XG4gICAgICBkLnN0YXJ0VW5leHBlY3RlZFNodXRkb3duKG5ldyBFcnJvcignV2UgY3Jhc2hlZCcpKTtcbiAgICAgIGF3YWl0IGNtZFByb21pc2Uuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvV2UgY3Jhc2hlZC8pO1xuICAgICAgYXdhaXQgcDtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgbm90IGFsbG93IGNvbW1hbmRzIGluIG1pZGRsZSBvZiB1bmV4cGVjdGVkIHNodXRkb3duJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gbWFrZSBhIGNvbW1hbmQgdGhhdCB3aWxsIHdhaXQgYSBiaXQgc28gd2UgY2FuIGNyYXNoIHdoaWxlIGl0J3MgcnVubmluZ1xuICAgICAgc2FuZGJveC5zdHViKGQsICdkZWxldGVTZXNzaW9uJykuY2FsbHNGYWtlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgQi5kZWxheSgxMDApO1xuICAgICAgICBEcml2ZXJDbGFzcy5wcm90b3R5cGUuZGVsZXRlU2Vzc2lvbi5jYWxsKHRoaXMpO1xuICAgICAgfSk7XG4gICAgICBhd2FpdCBkLmNyZWF0ZVNlc3Npb24odzNjQ2Fwcyk7XG4gICAgICBjb25zdCBwID0gbmV3IEIoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICgpID0+XG4gICAgICAgICAgICByZWplY3QoXG4gICAgICAgICAgICAgIG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAnb25VbmV4cGVjdGVkU2h1dGRvd24gZXZlbnQgaXMgZXhwZWN0ZWQgdG8gYmUgZmlyZWQgd2l0aGluIDUgc2Vjb25kcyB0aW1lb3V0J1xuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApLFxuICAgICAgICAgIDUwMDBcbiAgICAgICAgKTtcbiAgICAgICAgZC5vblVuZXhwZWN0ZWRTaHV0ZG93bihyZXNvbHZlKTtcbiAgICAgIH0pO1xuICAgICAgZC5zdGFydFVuZXhwZWN0ZWRTaHV0ZG93bihuZXcgRXJyb3IoJ1dlIGNyYXNoZWQnKSk7XG4gICAgICBhd2FpdCBwO1xuICAgICAgYXdhaXQgZC5leGVjdXRlQ29tbWFuZCgnZ2V0U2Vzc2lvbicpLnNob3VsZC5iZS5yZWplY3RlZFdpdGgoL3NodXQgZG93bi8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhbGxvdyBuZXcgY29tbWFuZHMgYWZ0ZXIgZG9uZSBzaHV0dGluZyBkb3duJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gbWFrZSBhIGNvbW1hbmQgdGhhdCB3aWxsIHdhaXQgYSBiaXQgc28gd2UgY2FuIGNyYXNoIHdoaWxlIGl0J3MgcnVubmluZ1xuICAgICAgc2FuZGJveC5zdHViKGQsICdkZWxldGVTZXNzaW9uJykuY2FsbHNGYWtlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgQi5kZWxheSgxMDApO1xuICAgICAgICBEcml2ZXJDbGFzcy5wcm90b3R5cGUuZGVsZXRlU2Vzc2lvbi5jYWxsKHRoaXMpO1xuICAgICAgfSk7XG5cbiAgICAgIGF3YWl0IGQuY3JlYXRlU2Vzc2lvbihfLmNsb25lRGVlcCh3M2NDYXBzKSk7XG4gICAgICBjb25zdCBwID0gbmV3IEIoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICgpID0+XG4gICAgICAgICAgICByZWplY3QoXG4gICAgICAgICAgICAgIG5ldyBFcnJvcihcbiAgICAgICAgICAgICAgICAnb25VbmV4cGVjdGVkU2h1dGRvd24gZXZlbnQgaXMgZXhwZWN0ZWQgdG8gYmUgZmlyZWQgd2l0aGluIDUgc2Vjb25kcyB0aW1lb3V0J1xuICAgICAgICAgICAgICApXG4gICAgICAgICAgICApLFxuICAgICAgICAgIDUwMDBcbiAgICAgICAgKTtcbiAgICAgICAgZC5vblVuZXhwZWN0ZWRTaHV0ZG93bihyZXNvbHZlKTtcbiAgICAgIH0pO1xuICAgICAgZC5zdGFydFVuZXhwZWN0ZWRTaHV0ZG93bihuZXcgRXJyb3IoJ1dlIGNyYXNoZWQnKSk7XG4gICAgICBhd2FpdCBwO1xuXG4gICAgICBhd2FpdCBkLmV4ZWN1dGVDb21tYW5kKCdnZXRTZXNzaW9uJykuc2hvdWxkLmJlLnJlamVjdGVkV2l0aCgvc2h1dCBkb3duLyk7XG4gICAgICBhd2FpdCBCLmRlbGF5KDUwMCk7XG5cbiAgICAgIGF3YWl0IGQuZXhlY3V0ZUNvbW1hbmQoJ2NyZWF0ZVNlc3Npb24nLCBudWxsLCBudWxsLCBfLmNsb25lRGVlcCh3M2NDYXBzKSk7XG4gICAgICBhd2FpdCBkLmRlbGV0ZVNlc3Npb24oKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgZGlzdGluZ3Vpc2ggYmV0d2VlbiBXM0MgYW5kIEpTT05XUCBzZXNzaW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVGVzdCBXM0MgKGxlYXZlIGZpcnN0IDIgYXJncyBudWxsIGJlY2F1c2UgdGhvc2UgYXJlIHRoZSBKU09OV1AgYXJncylcbiAgICAgIGF3YWl0IGQuZXhlY3V0ZUNvbW1hbmQoJ2NyZWF0ZVNlc3Npb24nLCBudWxsLCBudWxsLCB7XG4gICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgLi4uZGVmYXVsdENhcHMsXG4gICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgJ2FwcGl1bTpkZXZpY2VOYW1lJzogJ0NvbW1vZG9yZSA2NCcsXG4gICAgICAgIH0sXG4gICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KGQucHJvdG9jb2wpLnRvLmVxdWFsKCdXM0MnKTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdwcm90b2NvbCBkZXRlY3Rpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIHVzZSBXM0MgaWYgb25seSBXM0MgY2FwcyBhcmUgcHJvdmlkZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGF3YWl0IGQuY3JlYXRlU2Vzc2lvbih7XG4gICAgICAgICAgYWx3YXlzTWF0Y2g6IF8uY2xvbmUoZGVmYXVsdENhcHMpLFxuICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICAgIH0pO1xuICAgICAgICBleHBlY3QoZC5wcm90b2NvbCkudG8uZXF1YWwoJ1czQycpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGhhdmUgYSBtZXRob2QgdG8gZ2V0IGRyaXZlciBmb3IgYSBzZXNzaW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IFtzZXNzSWRdID0gYXdhaXQgZC5jcmVhdGVTZXNzaW9uKHczY0NhcHMpO1xuICAgICAgZXhwZWN0KGQuZHJpdmVyRm9yU2Vzc2lvbihzZXNzSWQpKS50by5lcWwoZCk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnY29tbWFuZCBxdWV1ZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIC8qKiBAdHlwZSB7SW5zdGFuY2VUeXBlPERyaXZlckNsYXNzPn0gKi9cbiAgICAgIGxldCBkO1xuICAgICAgbGV0IHdhaXRNcyA9IDEwO1xuXG4gICAgICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZCA9IG5ldyBEcml2ZXJDbGFzcygpO1xuICAgICAgICBzYW5kYm94LnN0dWIoZCwgJ2dldFN0YXR1cycpLmNhbGxzRmFrZShhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgQi5kZWxheSh3YWl0TXMpO1xuICAgICAgICAgIHJldHVybiBEYXRlLm5vdygpO1xuICAgICAgICB9KTtcbiAgICAgICAgc2FuZGJveC5zdHViKGQsICdnZXRTZXNzaW9ucycpLmNhbGxzRmFrZShhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgQi5kZWxheSh3YWl0TXMpO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcignbXVsdGlwYXNzJyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGF3YWl0IGQuY2xlYXJOZXdDb21tYW5kVGltZW91dCgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgcXVldWUgY29tbWFuZHMgYW5kLmV4ZWN1dGVDb21tYW5kL3Jlc3BvbmQgaW4gdGhlIG9yZGVyIHJlY2VpdmVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgbnVtQ21kcyA9IDEwO1xuICAgICAgICBsZXQgY21kcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bUNtZHM7IGkrKykge1xuICAgICAgICAgIGNtZHMucHVzaChkLmV4ZWN1dGVDb21tYW5kKCdnZXRTdGF0dXMnKSk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlc3VsdHMgPSBhd2FpdCBCLmFsbChjbWRzKTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDE7IGkgPCBudW1DbWRzOyBpKyspIHtcbiAgICAgICAgICBpZiAocmVzdWx0c1tpXSA8PSByZXN1bHRzW2kgLSAxXSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdHb3QgcmVzdWx0IG91dCBvZiBvcmRlcicpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgaGFuZGxlIGVycm9ycyBjb3JyZWN0bHkgd2hlbiBxdWV1aW5nJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgbnVtQ21kcyA9IDEwO1xuICAgICAgICBsZXQgY21kcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bUNtZHM7IGkrKykge1xuICAgICAgICAgIGlmIChpID09PSA1KSB7XG4gICAgICAgICAgICBjbWRzLnB1c2goZC5leGVjdXRlQ29tbWFuZCgnZ2V0U2Vzc2lvbnMnKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNtZHMucHVzaChkLmV4ZWN1dGVDb21tYW5kKCdnZXRTdGF0dXMnKSk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGxldCByZXN1bHRzID0gLyoqIEB0eXBlIHtQcm9taXNlRnVsZmlsbGVkUmVzdWx0PGFueT5bXX0gKi8gKFxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBwcm9taXNlL25vLW5hdGl2ZVxuICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChjbWRzKVxuICAgICAgICApO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IDU7IGkrKykge1xuICAgICAgICAgIGlmIChyZXN1bHRzW2ldLnZhbHVlIDw9IHJlc3VsdHNbaSAtIDFdLnZhbHVlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0dvdCByZXN1bHQgb3V0IG9mIG9yZGVyJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8qKiBAdHlwZSB7UHJvbWlzZVJlamVjdGVkUmVzdWx0fSAqLyAoXG4gICAgICAgICAgLyoqIEB0eXBlIHt1bmtub3dufSAqLyAocmVzdWx0c1s1XSlcbiAgICAgICAgKS5yZWFzb24ubWVzc2FnZS5zaG91bGQuY29udGFpbignbXVsdGlwYXNzJyk7XG4gICAgICAgIGZvciAobGV0IGkgPSA3OyBpIDwgbnVtQ21kczsgaSsrKSB7XG4gICAgICAgICAgaWYgKHJlc3VsdHNbaV0udmFsdWUgPD0gcmVzdWx0c1tpIC0gMV0udmFsdWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignR290IHJlc3VsdCBvdXQgb2Ygb3JkZXInKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIG5vdCBjYXJlIGlmIHF1ZXVlIGVtcHRpZXMgZm9yIGEgYml0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgbnVtQ21kcyA9IDEwO1xuICAgICAgICBsZXQgY21kcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bUNtZHM7IGkrKykge1xuICAgICAgICAgIGNtZHMucHVzaChkLmV4ZWN1dGVDb21tYW5kKCdnZXRTdGF0dXMnKSk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJlc3VsdHMgPSBhd2FpdCBCLmFsbChjbWRzKTtcbiAgICAgICAgY21kcyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IG51bUNtZHM7IGkrKykge1xuICAgICAgICAgIGNtZHMucHVzaChkLmV4ZWN1dGVDb21tYW5kKCdnZXRTdGF0dXMnKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmVzdWx0cyA9IGF3YWl0IEIuYWxsKGNtZHMpO1xuICAgICAgICBmb3IgKGxldCBpID0gMTsgaSA8IG51bUNtZHM7IGkrKykge1xuICAgICAgICAgIGlmIChyZXN1bHRzW2ldIDw9IHJlc3VsdHNbaSAtIDFdKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0dvdCByZXN1bHQgb3V0IG9mIG9yZGVyJyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCd0aW1lb3V0cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGF3YWl0IGQuY3JlYXRlU2Vzc2lvbih3M2NDYXBzKTtcbiAgICAgIH0pO1xuICAgICAgZGVzY3JpYmUoJ2NvbW1hbmQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgZXhpc3QgYnkgZGVmYXVsdCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBkLm5ld0NvbW1hbmRUaW1lb3V0TXMuc2hvdWxkLmVxdWFsKDYwMDAwKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGl0KCdzaG91bGQgYmUgc2V0dGFibGUgdGhyb3VnaCBgdGltZW91dHNgJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IGQudGltZW91dHMoJ2NvbW1hbmQnLCAyMCk7XG4gICAgICAgICAgZC5uZXdDb21tYW5kVGltZW91dE1zLnNob3VsZC5lcXVhbCgyMCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgICBkZXNjcmliZSgnaW1wbGljaXQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgbm90IGV4aXN0IGJ5IGRlZmF1bHQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZC5pbXBsaWNpdFdhaXRNcy5zaG91bGQuZXF1YWwoMCk7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIGJlIHNldHRhYmxlIHRocm91Z2ggYHRpbWVvdXRzYCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBhd2FpdCBkLnRpbWVvdXRzKCdpbXBsaWNpdCcsIDIwKTtcbiAgICAgICAgICBkLmltcGxpY2l0V2FpdE1zLnNob3VsZC5lcXVhbCgyMCk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgndGltZW91dHMgKFczQyknLCBmdW5jdGlvbiAoKSB7XG4gICAgICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgZC5jcmVhdGVTZXNzaW9uKHczY0NhcHMpO1xuICAgICAgfSk7XG4gICAgICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBhd2FpdCBkLmRlbGV0ZVNlc3Npb24oKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCBnZXQgdGltZW91dHMgdGhhdCB3ZSBzZXQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgYXdhaXQgZC50aW1lb3V0cyh1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIDEwMDApO1xuICAgICAgICBhd2FpdCBkLmdldFRpbWVvdXRzKCkuc2hvdWxkLmV2ZW50dWFsbHkuaGF2ZS5wcm9wZXJ0eSgnaW1wbGljaXQnLCAxMDAwKTtcbiAgICAgICAgYXdhaXQgZC50aW1lb3V0cygnY29tbWFuZCcsIDIwMDApO1xuICAgICAgICBhd2FpdCBkLmdldFRpbWVvdXRzKCkuc2hvdWxkLmV2ZW50dWFsbHkuZGVlcC5lcXVhbCh7XG4gICAgICAgICAgaW1wbGljaXQ6IDEwMDAsXG4gICAgICAgICAgY29tbWFuZDogMjAwMCxcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgYXdhaXQgZC50aW1lb3V0cyh1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIDMwMDApO1xuICAgICAgICBhd2FpdCBkLmdldFRpbWVvdXRzKCkuc2hvdWxkLmV2ZW50dWFsbHkuZGVlcC5lcXVhbCh7XG4gICAgICAgICAgaW1wbGljaXQ6IDMwMDAsXG4gICAgICAgICAgY29tbWFuZDogMjAwMCxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcblxuICAgIGRlc2NyaWJlKCdyZXNldCBjb21wYXRpYmlsaXR5JywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCBub3QgYWxsb3cgYm90aCBmdWxsUmVzZXQgYW5kIG5vUmVzZXQgdG8gYmUgdHJ1ZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgbmV3Q2FwcyA9IHtcbiAgICAgICAgICBhbHdheXNNYXRjaDoge1xuICAgICAgICAgICAgLi4uZGVmYXVsdENhcHMsXG4gICAgICAgICAgICBwbGF0Zm9ybU5hbWU6ICdGYWtlJyxcbiAgICAgICAgICAgICdhcHBpdW06ZGV2aWNlTmFtZSc6ICdDb21tb2RvcmUgNjQnLFxuICAgICAgICAgICAgJ2FwcGl1bTpmdWxsUmVzZXQnOiB0cnVlLFxuICAgICAgICAgICAgJ2FwcGl1bTpub1Jlc2V0JzogdHJ1ZSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICAgIH07XG4gICAgICAgIGF3YWl0IGQuY3JlYXRlU2Vzc2lvbihuZXdDYXBzKS5zaG91bGQuYmUucmVqZWN0ZWRXaXRoKC9ub1Jlc2V0LitmdWxsUmVzZXQvKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ3Byb3h5aW5nJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IHNlc3NJZDtcbiAgICAgIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBbc2Vzc0lkXSA9IGF3YWl0IGQuY3JlYXRlU2Vzc2lvbih3M2NDYXBzKTtcbiAgICAgIH0pO1xuICAgICAgZGVzY3JpYmUoJyNwcm94eUFjdGl2ZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBleGlzdCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBkLnByb3h5QWN0aXZlLnNob3VsZC5iZS5hbi5pbnN0YW5jZW9mKEZ1bmN0aW9uKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGl0KCdzaG91bGQgcmV0dXJuIGZhbHNlJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGQucHJveHlBY3RpdmUoc2Vzc0lkKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHRocm93IGFuIGVycm9yIHdoZW4gc2Vzc2lvbklkIGlzIHdyb25nJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICgoKSA9PiB7XG4gICAgICAgICAgICBkLnByb3h5QWN0aXZlKCdhYWEnKTtcbiAgICAgICAgICB9KS5zaG91bGQudGhyb3c7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCcjZ2V0UHJveHlBdm9pZExpc3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgZXhpc3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZC5nZXRQcm94eUF2b2lkTGlzdC5zaG91bGQuYmUuYW4uaW5zdGFuY2VvZihGdW5jdGlvbik7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHJldHVybiBhbiBhcnJheScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBkLmdldFByb3h5QXZvaWRMaXN0KHNlc3NJZCkuc2hvdWxkLmJlLmFuLmluc3RhbmNlb2YoQXJyYXkpO1xuICAgICAgICB9KTtcbiAgICAgICAgaXQoJ3Nob3VsZCB0aHJvdyBhbiBlcnJvciB3aGVuIHNlc3Npb25JZCBpcyB3cm9uZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAoKCkgPT4ge1xuICAgICAgICAgICAgZC5nZXRQcm94eUF2b2lkTGlzdCgnYWFhJyk7XG4gICAgICAgICAgfSkuc2hvdWxkLnRocm93O1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnI2NhblByb3h5JywgZnVuY3Rpb24gKCkge1xuICAgICAgICBpdCgnc2hvdWxkIGhhdmUgYSAjY2FuUHJveHkgbWV0aG9kJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGQuY2FuUHJveHkuc2hvdWxkLmJlLmFuLmluc3RhbmNlb2YoRnVuY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gYSBib29sZWFuIGZyb20gI2NhblByb3h5JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGQuY2FuUHJveHkoc2Vzc0lkKS5zaG91bGQuYmUuYSgnYm9vbGVhbicpO1xuICAgICAgICB9KTtcbiAgICAgICAgaXQoJ3Nob3VsZCB0aHJvdyBhbiBlcnJvciB3aGVuIHNlc3Npb25JZCBpcyB3cm9uZycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAoKCkgPT4ge1xuICAgICAgICAgICAgZC5jYW5Qcm94eSgpO1xuICAgICAgICAgIH0pLnNob3VsZC50aHJvdztcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJyNwcm94eVJvdXRlSXNBdm9pZGVkJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBpdCgnc2hvdWxkIHZhbGlkYXRlIGZvcm0gb2YgYXZvaWRhbmNlIGxpc3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgYXZvaWRTdHViID0gc2FuZGJveC5zdHViKGQsICdnZXRQcm94eUF2b2lkTGlzdCcpO1xuICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbWydQT1NUJywgL1xcL2Zvby9dLCBbJ0dFVCddXSk7XG4gICAgICAgICAgKCgpID0+IHtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgICAgIGQucHJveHlSb3V0ZUlzQXZvaWRlZCgpO1xuICAgICAgICAgIH0pLnNob3VsZC50aHJvdztcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbXG4gICAgICAgICAgICBbJ1BPU1QnLCAvXFwvZm9vL10sXG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gICAgICAgICAgICBbJ0dFVCcsIC9eZm9vLywgJ2JhciddLFxuICAgICAgICAgIF0pO1xuICAgICAgICAgICgoKSA9PiB7XG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gICAgICAgICAgICBkLnByb3h5Um91dGVJc0F2b2lkZWQoKTtcbiAgICAgICAgICB9KS5zaG91bGQudGhyb3c7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHJlamVjdCBiYWQgaHR0cCBtZXRob2RzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGF2b2lkU3R1YiA9IHNhbmRib3guc3R1YihkLCAnZ2V0UHJveHlBdm9pZExpc3QnKTtcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbXG4gICAgICAgICAgICBbJ1BPU1QnLCAvXmZvby9dLFxuICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvclxuICAgICAgICAgICAgWydCQVpFVEUnLCAvXmJhci9dLFxuICAgICAgICAgIF0pO1xuICAgICAgICAgICgoKSA9PiB7XG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gICAgICAgICAgICBkLnByb3h5Um91dGVJc0F2b2lkZWQoKTtcbiAgICAgICAgICB9KS5zaG91bGQudGhyb3c7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHJlamVjdCBub24tcmVnZXggcm91dGVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGF2b2lkU3R1YiA9IHNhbmRib3guc3R1YihkLCAnZ2V0UHJveHlBdm9pZExpc3QnKTtcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbXG4gICAgICAgICAgICBbJ1BPU1QnLCAvXmZvby9dLFxuICAgICAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvclxuICAgICAgICAgICAgWydHRVQnLCAnL2JhciddLFxuICAgICAgICAgIF0pO1xuICAgICAgICAgICgoKSA9PiB7XG4gICAgICAgICAgICAvLyBAdHMtZXhwZWN0LWVycm9yXG4gICAgICAgICAgICBkLnByb3h5Um91dGVJc0F2b2lkZWQoKTtcbiAgICAgICAgICB9KS5zaG91bGQudGhyb3c7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIHJldHVybiB0cnVlIGZvciByb3V0ZXMgaW4gdGhlIGF2b2lkIGxpc3QnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgY29uc3QgYXZvaWRTdHViID0gc2FuZGJveC5zdHViKGQsICdnZXRQcm94eUF2b2lkTGlzdCcpO1xuICAgICAgICAgIGF2b2lkU3R1Yi5yZXR1cm5zKFtbJ1BPU1QnLCAvXlxcL2Zvby9dXSk7XG4gICAgICAgICAgZC5wcm94eVJvdXRlSXNBdm9pZGVkKCdmb28nLCAnUE9TVCcsICcvZm9vL2JhcicpLnNob3VsZC5iZS50cnVlO1xuICAgICAgICB9KTtcbiAgICAgICAgaXQoJ3Nob3VsZCBzdHJpcCBhd2F5IGFueSB3ZC9odWIgcHJlZml4JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGF2b2lkU3R1YiA9IHNhbmRib3guc3R1YihkLCAnZ2V0UHJveHlBdm9pZExpc3QnKTtcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbWydQT1NUJywgL15cXC9mb28vXV0pO1xuICAgICAgICAgIGQucHJveHlSb3V0ZUlzQXZvaWRlZCgnZm9vJywgJ1BPU1QnLCAnL2Zvby9iYXInKS5zaG91bGQuYmUudHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIGl0KCdzaG91bGQgcmV0dXJuIGZhbHNlIGZvciByb3V0ZXMgbm90IGluIHRoZSBhdm9pZCBsaXN0JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGF2b2lkU3R1YiA9IHNhbmRib3guc3R1YihkLCAnZ2V0UHJveHlBdm9pZExpc3QnKTtcbiAgICAgICAgICBhdm9pZFN0dWIucmV0dXJucyhbWydQT1NUJywgL15cXC9mb28vXV0pO1xuICAgICAgICAgIGQucHJveHlSb3V0ZUlzQXZvaWRlZCgnZm9vJywgJ0dFVCcsICcvZm9vL2JhcicpLnNob3VsZC5iZS5mYWxzZTtcbiAgICAgICAgICBkLnByb3h5Um91dGVJc0F2b2lkZWQoJ2ZvbycsICdQT1NUJywgJy9ib28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnZXZlbnQgdGltaW5nIGZyYW1ld29yaycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBiZWZvcmVTdGFydFRpbWU7XG4gICAgICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYmVmb3JlU3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICAgICAgZC5zaG91bGRWYWxpZGF0ZUNhcHMgPSBmYWxzZTtcbiAgICAgICAgYXdhaXQgZC5leGVjdXRlQ29tbWFuZCgnY3JlYXRlU2Vzc2lvbicsIG51bGwsIG51bGwsIHtcbiAgICAgICAgICBhbHdheXNNYXRjaDogey4uLmRlZmF1bHRDYXBzfSxcbiAgICAgICAgICBmaXJzdE1hdGNoOiBbe31dLFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgZGVzY3JpYmUoJyNldmVudEhpc3RvcnknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgaGF2ZSBhbiBldmVudEhpc3RvcnkgcHJvcGVydHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgc2hvdWxkLmV4aXN0KGQuZXZlbnRIaXN0b3J5KTtcbiAgICAgICAgICBzaG91bGQuZXhpc3QoZC5ldmVudEhpc3RvcnkuY29tbWFuZHMpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIGhhdmUgYSBzZXNzaW9uIHN0YXJ0IHRpbWluZyBhZnRlciBzZXNzaW9uIHN0YXJ0JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGxldCB7bmV3U2Vzc2lvblJlcXVlc3RlZCwgbmV3U2Vzc2lvblN0YXJ0ZWR9ID0gZC5ldmVudEhpc3Rvcnk7XG4gICAgICAgICAgbmV3U2Vzc2lvblJlcXVlc3RlZC5zaG91bGQuaGF2ZS5sZW5ndGgoMSk7XG4gICAgICAgICAgbmV3U2Vzc2lvblN0YXJ0ZWQuc2hvdWxkLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgICAgIG5ld1Nlc3Npb25SZXF1ZXN0ZWRbMF0uc2hvdWxkLmJlLmEoJ251bWJlcicpO1xuICAgICAgICAgIG5ld1Nlc3Npb25TdGFydGVkWzBdLnNob3VsZC5iZS5hKCdudW1iZXInKTtcbiAgICAgICAgICAobmV3U2Vzc2lvblJlcXVlc3RlZFswXSA+PSBiZWZvcmVTdGFydFRpbWUpLnNob3VsZC5iZS50cnVlO1xuICAgICAgICAgIChuZXdTZXNzaW9uU3RhcnRlZFswXSA+PSBuZXdTZXNzaW9uUmVxdWVzdGVkWzBdKS5zaG91bGQuYmUudHJ1ZTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBpbmNsdWRlIGEgY29tbWFuZHMgbGlzdCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBhd2FpdCBkLmV4ZWN1dGVDb21tYW5kKCdnZXRTdGF0dXMnLCBbXSk7XG4gICAgICAgICAgZC5ldmVudEhpc3RvcnkuY29tbWFuZHMubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICAgICAgICBkLmV2ZW50SGlzdG9yeS5jb21tYW5kc1sxXS5jbWQuc2hvdWxkLmVxdWFsKCdnZXRTdGF0dXMnKTtcbiAgICAgICAgICBkLmV2ZW50SGlzdG9yeS5jb21tYW5kc1sxXS5zdGFydFRpbWUuc2hvdWxkLmJlLmEoJ251bWJlcicpO1xuICAgICAgICAgIGQuZXZlbnRIaXN0b3J5LmNvbW1hbmRzWzFdLmVuZFRpbWUuc2hvdWxkLmJlLmEoJ251bWJlcicpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgZGVzY3JpYmUoJyNsb2dFdmVudCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBhbGxvdyBsb2dnaW5nIGFyYml0cmFyeSBldmVudHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZC5sb2dFdmVudCgnZm9vJyk7XG4gICAgICAgICAgZC5ldmVudEhpc3RvcnkuZm9vWzBdLnNob3VsZC5iZS5hKCdudW1iZXInKTtcbiAgICAgICAgICAoZC5ldmVudEhpc3RvcnkuZm9vWzBdID49IGJlZm9yZVN0YXJ0VGltZSkuc2hvdWxkLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgICBpdCgnc2hvdWxkIG5vdCBhbGxvdyByZXNlcnZlZCBvciBvZGRseSBmb3JtZWQgZXZlbnQgbmFtZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgKCgpID0+IHtcbiAgICAgICAgICAgIGQubG9nRXZlbnQoJ2NvbW1hbmRzJyk7XG4gICAgICAgICAgfSkuc2hvdWxkLnRocm93KCk7XG4gICAgICAgICAgKCgpID0+IHtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgICAgIGQubG9nRXZlbnQoMSk7XG4gICAgICAgICAgfSkuc2hvdWxkLnRocm93KCk7XG4gICAgICAgICAgKCgpID0+IHtcbiAgICAgICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3JcbiAgICAgICAgICAgIGQubG9nRXZlbnQoe30pO1xuICAgICAgICAgIH0pLnNob3VsZC50aHJvdygpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCBhbGxvdyBsb2dnaW5nIHRoZSBzYW1lIGV2ZW50IG11bHRpcGxlIHRpbWVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBkLmxvZ0V2ZW50KCdiYXInKTtcbiAgICAgICAgZC5sb2dFdmVudCgnYmFyJyk7XG4gICAgICAgIGQuZXZlbnRIaXN0b3J5LmJhci5zaG91bGQuaGF2ZS5sZW5ndGgoMik7XG4gICAgICAgIGQuZXZlbnRIaXN0b3J5LmJhclsxXS5zaG91bGQuYmUuYSgnbnVtYmVyJyk7XG4gICAgICAgIChkLmV2ZW50SGlzdG9yeS5iYXJbMV0gPj0gZC5ldmVudEhpc3RvcnkuYmFyWzBdKS5zaG91bGQuYmUudHJ1ZTtcbiAgICAgIH0pO1xuICAgICAgZGVzY3JpYmUoJ2dldFNlc3Npb24gZGVjb3JhdGlvbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBkZWNvcmF0ZSBnZXRTZXNzaW9uIHJlc3BvbnNlIGlmIG9wdC1pbiBjYXAgaXMgcHJvdmlkZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgbGV0IHJlcyA9IGF3YWl0IGQuZ2V0U2Vzc2lvbigpO1xuICAgICAgICAgIHNob3VsZC5ub3QuZXhpc3QocmVzLmV2ZW50cyk7XG5cbiAgICAgICAgICBfLnNldChkLCAnY2Fwcy5ldmVudFRpbWluZ3MnLCB0cnVlKTtcbiAgICAgICAgICByZXMgPSBhd2FpdCBkLmdldFNlc3Npb24oKTtcbiAgICAgICAgICBzaG91bGQuZXhpc3QocmVzLmV2ZW50cyk7XG4gICAgICAgICAgc2hvdWxkLmV4aXN0KHJlcy5ldmVudHM/Lm5ld1Nlc3Npb25SZXF1ZXN0ZWQpO1xuICAgICAgICAgIGV4cGVjdChyZXMuZXZlbnRzPy5uZXdTZXNzaW9uUmVxdWVzdGVkWzBdKS50by5iZS5hKCdudW1iZXInKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnLnJlc2V0JywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCByZXNldCBhcyBXM0MgaWYgdGhlIG9yaWdpbmFsIHNlc3Npb24gd2FzIFczQycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgY2FwcyA9IHtcbiAgICAgICAgICBhbHdheXNNYXRjaDoge1xuICAgICAgICAgICAgJ2FwcGl1bTphcHAnOiAnRmFrZScsXG4gICAgICAgICAgICAnYXBwaXVtOmRldmljZU5hbWUnOiAnRmFrZScsXG4gICAgICAgICAgICAnYXBwaXVtOmF1dG9tYXRpb25OYW1lJzogJ0Zha2UnLFxuICAgICAgICAgICAgcGxhdGZvcm1OYW1lOiAnRmFrZScsXG4gICAgICAgICAgICAuLi5kZWZhdWx0Q2FwcyxcbiAgICAgICAgICB9LFxuXG4gICAgICAgICAgZmlyc3RNYXRjaDogW3t9XSxcbiAgICAgICAgfTtcbiAgICAgICAgYXdhaXQgZC5jcmVhdGVTZXNzaW9uKGNhcHMpO1xuICAgICAgICBleHBlY3QoZC5wcm90b2NvbCkudG8uZXF1YWwoJ1czQycpO1xuICAgICAgICBhd2FpdCBkLnJlc2V0KCk7XG4gICAgICAgIGV4cGVjdChkLnByb3RvY29sKS50by5lcXVhbCgnVzNDJyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJy5pc0ZlYXR1cmVFbmFibGVkJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBkO1xuXG4gICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBkID0gbmV3IERyaXZlckNsYXNzKCk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHNheSBhIGZlYXR1cmUgaXMgZW5hYmxlZCB3aGVuIGl0IGlzIGV4cGxpY2l0bHkgYWxsb3dlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGQuYWxsb3dJbnNlY3VyZSA9IFsnZm9vJywgJ2JhciddO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdmb28nKS5zaG91bGQuYmUudHJ1ZTtcbiAgICAgIGQuaXNGZWF0dXJlRW5hYmxlZCgnYmFyJykuc2hvdWxkLmJlLnRydWU7XG4gICAgICBkLmlzRmVhdHVyZUVuYWJsZWQoJ2JheicpLnNob3VsZC5iZS5mYWxzZTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgc2F5IGEgZmVhdHVyZSBpcyBub3QgZW5hYmxlZCBpZiBpdCBpcyBub3QgZW5hYmxlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGQuYWxsb3dJbnNlY3VyZSA9IFtdO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdmb28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHByZWZlciBkZW55SW5zZWN1cmUgdG8gYWxsb3dJbnNlY3VyZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGQuYWxsb3dJbnNlY3VyZSA9IFsnZm9vJywgJ2JhciddO1xuICAgICAgZC5kZW55SW5zZWN1cmUgPSBbJ2ZvbyddO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdmb28nKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgICBkLmlzRmVhdHVyZUVuYWJsZWQoJ2JhcicpLnNob3VsZC5iZS50cnVlO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdiYXonKS5zaG91bGQuYmUuZmFsc2U7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFsbG93IGdsb2JhbCBzZXR0aW5nIGZvciBpbnNlY3VyaXR5JywgZnVuY3Rpb24gKCkge1xuICAgICAgZC5yZWxheGVkU2VjdXJpdHlFbmFibGVkID0gdHJ1ZTtcbiAgICAgIGQuaXNGZWF0dXJlRW5hYmxlZCgnZm9vJykuc2hvdWxkLmJlLnRydWU7XG4gICAgICBkLmlzRmVhdHVyZUVuYWJsZWQoJ2JhcicpLnNob3VsZC5iZS50cnVlO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdiYXonKS5zaG91bGQuYmUudHJ1ZTtcbiAgICB9KTtcblxuICAgIGl0KCdnbG9iYWwgc2V0dGluZyBzaG91bGQgYmUgb3ZlcnJpZGVhYmxlJywgZnVuY3Rpb24gKCkge1xuICAgICAgZC5yZWxheGVkU2VjdXJpdHlFbmFibGVkID0gdHJ1ZTtcbiAgICAgIGQuZGVueUluc2VjdXJlID0gWydmb28nLCAnYmFyJ107XG4gICAgICBkLmlzRmVhdHVyZUVuYWJsZWQoJ2ZvbycpLnNob3VsZC5iZS5mYWxzZTtcbiAgICAgIGQuaXNGZWF0dXJlRW5hYmxlZCgnYmFyJykuc2hvdWxkLmJlLmZhbHNlO1xuICAgICAgZC5pc0ZlYXR1cmVFbmFibGVkKCdiYXonKS5zaG91bGQuYmUudHJ1ZTtcbiAgICB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogQHR5cGVkZWYge2ltcG9ydCgnQGFwcGl1bS90eXBlcycpLkRyaXZlckNsYXNzfSBEcml2ZXJDbGFzc1xuICogQHR5cGVkZWYge2ltcG9ydCgnQGFwcGl1bS90eXBlcycpLlczQ0NhcGFiaWxpdGllc30gVzNDQ2FwYWJpbGl0aWVzXG4gKiBAdHlwZWRlZiB7aW1wb3J0KCdAYXBwaXVtL3R5cGVzJykuQXBwaXVtVzNDQ2FwYWJpbGl0aWVzfSBBcHBpdW1XM0NDYXBhYmlsaXRpZXNcbiAqL1xuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUVBOztBQUVBLE1BQU1BLE1BQU0sR0FBR0MsYUFBQSxDQUFLRCxNQUFMLEVBQWY7O0FBQ0EsTUFBTTtFQUFDRTtBQUFELElBQVdELGFBQWpCOztBQVdPLFNBQVNFLG1CQUFULENBQTZCQyxXQUE3QixFQUEwQ0MsV0FBVyxHQUFHLEVBQXhELEVBQTREO0VBRWpFLE1BQU1DLFNBQVMsR0FBR0YsV0FBVyxDQUFDRyxJQUFaLElBQW9CLGtCQUF0QztFQUVBQyxRQUFRLENBQUUsNkJBQTRCRixTQUFVLEdBQXhDLEVBQTRDLFlBQVk7SUFFOUQsSUFBSUcsQ0FBSjtJQUVBLElBQUlDLE9BQUo7SUFFQSxJQUFJQyxPQUFKO0lBRUFDLFVBQVUsQ0FBQyxZQUFZO01BQ3JCRCxPQUFPLEdBQUcsSUFBQUUsb0JBQUEsR0FBVjtNQUNBSixDQUFDLEdBQUcsSUFBSUwsV0FBSixFQUFKO01BQ0FNLE9BQU8sR0FBRztRQUNSSSxXQUFXLEVBQUUsRUFDWCxHQUFHVCxXQURRO1VBRVhVLFlBQVksRUFBRSxNQUZIO1VBR1gscUJBQXFCO1FBSFYsQ0FETDtRQU1SQyxVQUFVLEVBQUUsQ0FBQyxFQUFEO01BTkosQ0FBVjtJQVFELENBWFMsQ0FBVjtJQVlBQyxTQUFTLENBQUMsa0JBQWtCO01BQzFCTixPQUFPLENBQUNPLE9BQVI7TUFDQSxNQUFNVCxDQUFDLENBQUNVLGFBQUYsRUFBTjtJQUNELENBSFEsQ0FBVDtJQUtBWCxRQUFRLENBQUMsaUJBQUQsRUFBb0IsWUFB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
557
+ exports.driverUnitTestSuite = driverUnitTestSuite;
558
+ /**
559
+ * @typedef {import('@appium/types').DriverClass} DriverClass
560
+ * @typedef {import('@appium/types').BaseNSCapabilities} BaseNSCapabilities
561
+ */
562
+ /**
563
+ * @template {import('@appium/types').Constraints} [C=import('@appium/types').BaseDriverCapConstraints]
564
+ * @template {import('@appium/types').StringRecord|void} [Extra=void]
565
+ * @typedef {import('@appium/types').W3CCapabilities<C, Extra>} W3CCapabilities
566
+ */
567
+ //# sourceMappingURL=unit-suite.js.map