appium 2.0.0-beta.20 → 2.0.0-beta.24

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 (90) hide show
  1. package/README.md +1 -2
  2. package/build/check-npm-pack-files.js +23 -0
  3. package/build/commands-yml/parse.js +319 -0
  4. package/build/commands-yml/validator.js +130 -0
  5. package/build/index.js +19 -0
  6. package/build/lib/appium.js +22 -7
  7. package/build/lib/cli/args.js +13 -15
  8. package/build/lib/cli/npm.js +27 -16
  9. package/build/lib/cli/parser.js +7 -3
  10. package/build/lib/config.js +27 -47
  11. package/build/lib/extension-config.js +1 -1
  12. package/build/lib/main.js +29 -28
  13. package/build/lib/plugin-config.js +2 -2
  14. package/build/lib/plugins.js +4 -2
  15. package/build/lib/schema/appium-config-schema.js +3 -2
  16. package/build/lib/schema/arg-spec.js +5 -3
  17. package/build/lib/schema/cli-args.js +25 -16
  18. package/build/lib/schema/keywords.js +14 -4
  19. package/build/lib/schema/schema.js +80 -9
  20. package/build/lib/utils.js +16 -36
  21. package/build/postinstall.js +90 -0
  22. package/build/test/cli/cli-e2e-specs.js +221 -0
  23. package/build/test/cli/cli-helpers.js +86 -0
  24. package/build/test/cli/cli-specs.js +71 -0
  25. package/build/test/cli/fixtures/test-driver/package.json +27 -0
  26. package/build/test/cli/schema-args-specs.js +48 -0
  27. package/build/test/cli/schema-e2e-specs.js +47 -0
  28. package/build/test/config-e2e-specs.js +112 -0
  29. package/build/test/config-file-e2e-specs.js +209 -0
  30. package/build/test/config-file-specs.js +281 -0
  31. package/build/test/config-specs.js +246 -0
  32. package/build/test/driver-e2e-specs.js +435 -0
  33. package/build/test/driver-specs.js +386 -0
  34. package/build/test/ext-config-io-specs.js +181 -0
  35. package/build/test/extension-config-specs.js +365 -0
  36. package/build/test/fixtures/allow-feat.txt +5 -0
  37. package/build/test/fixtures/caps.json +3 -0
  38. package/build/test/fixtures/config/allow-insecure.txt +3 -0
  39. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +5 -0
  40. package/build/test/fixtures/config/appium.config.bad.json +32 -0
  41. package/build/test/fixtures/config/appium.config.ext-good.json +9 -0
  42. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +10 -0
  43. package/build/test/fixtures/config/appium.config.good.js +40 -0
  44. package/build/test/fixtures/config/appium.config.good.json +33 -0
  45. package/build/test/fixtures/config/appium.config.good.yaml +30 -0
  46. package/build/test/fixtures/config/appium.config.invalid.json +31 -0
  47. package/build/test/fixtures/config/appium.config.security-array.json +5 -0
  48. package/build/test/fixtures/config/appium.config.security-delimited.json +5 -0
  49. package/build/test/fixtures/config/appium.config.security-path.json +5 -0
  50. package/build/test/fixtures/config/driver-fake.config.json +8 -0
  51. package/build/test/fixtures/config/nodeconfig.json +3 -0
  52. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  53. package/build/test/fixtures/default-args.js +35 -0
  54. package/build/test/fixtures/deny-feat.txt +5 -0
  55. package/build/test/fixtures/driver.schema.js +20 -0
  56. package/build/test/fixtures/extensions.yaml +27 -0
  57. package/build/test/fixtures/flattened-schema.js +532 -0
  58. package/build/test/fixtures/plugin.schema.js +20 -0
  59. package/build/test/fixtures/schema-with-extensions.js +28 -0
  60. package/build/test/grid-register-specs.js +74 -0
  61. package/build/test/helpers.js +75 -0
  62. package/build/test/logger-specs.js +76 -0
  63. package/build/test/npm-specs.js +20 -0
  64. package/build/test/parser-specs.js +319 -0
  65. package/build/test/plugin-e2e-specs.js +316 -0
  66. package/build/test/schema/arg-spec-specs.js +70 -0
  67. package/build/test/schema/cli-args-specs.js +408 -0
  68. package/build/test/schema/schema-specs.js +407 -0
  69. package/build/test/utils-specs.js +288 -0
  70. package/index.js +11 -0
  71. package/lib/appium-config.schema.json +2 -1
  72. package/lib/appium.js +51 -8
  73. package/lib/cli/args.js +17 -14
  74. package/lib/cli/npm.js +68 -6
  75. package/lib/cli/parser.js +5 -2
  76. package/lib/config.js +72 -54
  77. package/lib/extension-config.js +1 -1
  78. package/lib/main.js +93 -40
  79. package/lib/plugin-config.js +1 -1
  80. package/lib/plugins.js +2 -0
  81. package/lib/schema/appium-config-schema.js +1 -0
  82. package/lib/schema/arg-spec.js +12 -2
  83. package/lib/schema/cli-args.js +22 -34
  84. package/lib/schema/keywords.js +20 -4
  85. package/lib/schema/schema.js +142 -22
  86. package/lib/utils.js +28 -29
  87. package/package.json +10 -14
  88. package/types/types.d.ts +5 -0
  89. package/build/lib/cli/argparse-actions.js +0 -104
  90. package/lib/cli/argparse-actions.js +0 -77
@@ -0,0 +1,435 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _lodash = _interopRequireDefault(require("lodash"));
8
+
9
+ var _path = _interopRequireDefault(require("path"));
10
+
11
+ var _bluebird = _interopRequireDefault(require("bluebird"));
12
+
13
+ var _axios = _interopRequireDefault(require("axios"));
14
+
15
+ var _webdriverio = require("webdriverio");
16
+
17
+ var _main = require("../lib/main");
18
+
19
+ var _extensionConfig = require("../lib/extension-config");
20
+
21
+ var _helpers = require("./helpers");
22
+
23
+ var _baseDriver = require("@appium/base-driver");
24
+
25
+ var _driverConfig = _interopRequireDefault(require("../lib/driver-config"));
26
+
27
+ var _extension = require("../lib/cli/extension");
28
+
29
+ var _utils = require("../lib/utils");
30
+
31
+ var _sinon = _interopRequireDefault(require("sinon"));
32
+
33
+ let TEST_SERVER;
34
+ let TEST_PORT;
35
+ const sillyWebServerPort = 1234;
36
+ const sillyWebServerHost = 'hey';
37
+ const FAKE_ARGS = {
38
+ sillyWebServerPort,
39
+ sillyWebServerHost
40
+ };
41
+ const FAKE_DRIVER_ARGS = {
42
+ driver: {
43
+ fake: FAKE_ARGS
44
+ }
45
+ };
46
+ const shouldStartServer = process.env.USE_RUNNING_SERVER !== '0';
47
+ const caps = _helpers.W3C_PREFIXED_CAPS;
48
+ const wdOpts = {
49
+ hostname: _helpers.TEST_HOST,
50
+ port: null,
51
+ connectionRetryCount: 0
52
+ };
53
+ describe('FakeDriver - via HTTP', function () {
54
+ let server = null;
55
+ const appiumHome = _extensionConfig.DEFAULT_APPIUM_HOME;
56
+ let FakeDriver = null;
57
+ let baseUrl;
58
+
59
+ const FAKE_DRIVER_DIR = _path.default.join(_helpers.PROJECT_ROOT, 'packages', 'fake-driver');
60
+
61
+ before(async function () {
62
+ wdOpts.port = TEST_PORT = await (0, _helpers.getTestPort)();
63
+ TEST_SERVER = `http://${_helpers.TEST_HOST}:${TEST_PORT}`;
64
+ baseUrl = `${TEST_SERVER}/session`;
65
+ const driverList = await (0, _extension.runExtensionCommand)({
66
+ appiumHome,
67
+ driverCommand: 'list',
68
+ showInstalled: true
69
+ }, _extensionConfig.DRIVER_TYPE);
70
+
71
+ if (!_lodash.default.has(driverList, 'fake')) {
72
+ await (0, _extension.runExtensionCommand)({
73
+ appiumHome,
74
+ driverCommand: 'install',
75
+ driver: FAKE_DRIVER_DIR,
76
+ installType: _extensionConfig.INSTALL_TYPE_LOCAL
77
+ }, _extensionConfig.DRIVER_TYPE);
78
+ }
79
+
80
+ const config = _driverConfig.default.getInstance(appiumHome);
81
+
82
+ FakeDriver = config.require('fake');
83
+ await serverStart();
84
+ });
85
+ after(async function () {
86
+ await serverClose();
87
+ });
88
+
89
+ async function serverStart(args = {}) {
90
+ args = {
91
+ port: TEST_PORT,
92
+ host: _helpers.TEST_HOST,
93
+ appiumHome,
94
+ ...args
95
+ };
96
+
97
+ if (shouldStartServer) {
98
+ server = await (0, _main.main)(args);
99
+ }
100
+ }
101
+
102
+ async function serverClose() {
103
+ if (server) {
104
+ await server.close();
105
+ }
106
+ }
107
+
108
+ describe('server updating', function () {
109
+ it('should allow drivers to update the server in arbitrary ways', async function () {
110
+ const {
111
+ data
112
+ } = await _axios.default.get(`${TEST_SERVER}/fakedriver`);
113
+ data.should.eql({
114
+ fakedriver: 'fakeResponse'
115
+ });
116
+ });
117
+ });
118
+ describe('cli args handling for empty args', function () {
119
+ it('should not recieve user cli args if none passed in', async function () {
120
+ let driver = await (0, _webdriverio.remote)({ ...wdOpts,
121
+ capabilities: caps
122
+ });
123
+ const {
124
+ sessionId
125
+ } = driver;
126
+
127
+ try {
128
+ const {
129
+ data
130
+ } = await _axios.default.get(`${baseUrl}/${sessionId}/fakedriverargs`);
131
+ should.not.exist(data.value.sillyWebServerPort);
132
+ should.not.exist(data.value.sillyWebServerHost);
133
+ } finally {
134
+ await driver.deleteSession();
135
+ }
136
+ });
137
+ });
138
+ describe('cli args handling for passed in args', function () {
139
+ before(async function () {
140
+ await serverClose();
141
+ await serverStart(FAKE_DRIVER_ARGS);
142
+ });
143
+ after(async function () {
144
+ await serverClose();
145
+ await serverStart();
146
+ });
147
+ it('should receive user cli args from a driver if arguments were passed in', async function () {
148
+ let driver = await (0, _webdriverio.remote)({ ...wdOpts,
149
+ capabilities: caps
150
+ });
151
+ const {
152
+ sessionId
153
+ } = driver;
154
+
155
+ try {
156
+ const {
157
+ data
158
+ } = await _axios.default.get(`${baseUrl}/${sessionId}/fakedriverargs`);
159
+ data.value.sillyWebServerPort.should.eql(sillyWebServerPort);
160
+ data.value.sillyWebServerHost.should.eql(sillyWebServerHost);
161
+ } finally {
162
+ await driver.deleteSession();
163
+ }
164
+ });
165
+ });
166
+ describe('session handling', function () {
167
+ it('should start and stop a session and not allow commands after session stopped', async function () {
168
+ let driver = await (0, _webdriverio.remote)({ ...wdOpts,
169
+ capabilities: caps
170
+ });
171
+ should.exist(driver.sessionId);
172
+ driver.sessionId.should.be.a('string');
173
+ await driver.deleteSession();
174
+ await driver.getTitle().should.eventually.be.rejectedWith(/terminated/);
175
+ });
176
+ it('should be able to run two FakeDriver sessions simultaneously', async function () {
177
+ let driver1 = await (0, _webdriverio.remote)({ ...wdOpts,
178
+ capabilities: caps
179
+ });
180
+ should.exist(driver1.sessionId);
181
+ driver1.sessionId.should.be.a('string');
182
+ let driver2 = await (0, _webdriverio.remote)({ ...wdOpts,
183
+ capabilities: caps
184
+ });
185
+ should.exist(driver2.sessionId);
186
+ driver2.sessionId.should.be.a('string');
187
+ driver2.sessionId.should.not.equal(driver1.sessionId);
188
+ await driver1.deleteSession();
189
+ await driver2.deleteSession();
190
+ });
191
+ it('should not be able to run two FakeDriver sessions simultaneously when one is unique', async function () {
192
+ let uniqueCaps = _lodash.default.clone(caps);
193
+
194
+ uniqueCaps['appium:uniqueApp'] = true;
195
+ let driver1 = await (0, _webdriverio.remote)({ ...wdOpts,
196
+ capabilities: uniqueCaps
197
+ });
198
+ should.exist(driver1.sessionId);
199
+ driver1.sessionId.should.be.a('string');
200
+ await (0, _webdriverio.remote)({ ...wdOpts,
201
+ capabilities: caps
202
+ }).should.eventually.be.rejected;
203
+ await driver1.deleteSession();
204
+ });
205
+ it('should use the newCommandTimeout of the inner Driver on session creation', async function () {
206
+ let localCaps = Object.assign({
207
+ 'appium:newCommandTimeout': 0.25
208
+ }, caps);
209
+ let driver = await (0, _webdriverio.remote)({ ...wdOpts,
210
+ capabilities: localCaps
211
+ });
212
+ should.exist(driver.sessionId);
213
+ await _bluebird.default.delay(250);
214
+ await driver.getPageSource().should.eventually.be.rejectedWith(/terminated/);
215
+ });
216
+ it('should accept valid W3C capabilities and start a W3C session', async function () {
217
+ const w3cCaps = {
218
+ capabilities: {
219
+ alwaysMatch: {
220
+ 'appium:automationName': 'Fake',
221
+ platformName: 'Fake'
222
+ },
223
+ firstMatch: [{
224
+ 'appium:deviceName': 'Fake',
225
+ 'appium:app': _helpers.TEST_FAKE_APP
226
+ }]
227
+ }
228
+ };
229
+ const {
230
+ status,
231
+ value,
232
+ sessionId
233
+ } = (await _axios.default.post(baseUrl, w3cCaps)).data;
234
+
235
+ try {
236
+ should.not.exist(status);
237
+ should.not.exist(sessionId);
238
+ value.sessionId.should.be.a.string;
239
+ value.should.exist;
240
+ value.capabilities.should.deep.equal({
241
+ automationName: 'Fake',
242
+ platformName: 'Fake',
243
+ deviceName: 'Fake',
244
+ app: _helpers.TEST_FAKE_APP
245
+ });
246
+ const {
247
+ status: screenshotStatus,
248
+ value: screenshotValue
249
+ } = (await (0, _axios.default)({
250
+ url: `${baseUrl}/${value.sessionId}/screenshot`
251
+ })).data;
252
+ should.not.exist(screenshotStatus);
253
+ screenshotValue.should.match(/^iVBOR/);
254
+ await _axios.default.post(`${baseUrl}/${value.sessionId}/execute/async`, {
255
+ script: '',
256
+ args: ['a']
257
+ }).should.eventually.be.rejectedWith(/405/);
258
+ } finally {
259
+ await _axios.default.delete(`${baseUrl}/${value.sessionId}`);
260
+ }
261
+ });
262
+ it('should reject invalid W3C capabilities and respond with a 400 Bad Parameters error', async function () {
263
+ const badW3Ccaps = {
264
+ capabilities: {
265
+ alwaysMatch: {},
266
+ firstMatch: [{
267
+ 'appium:deviceName': 'Fake',
268
+ 'appium:app': _helpers.TEST_FAKE_APP
269
+ }]
270
+ }
271
+ };
272
+ await _axios.default.post(baseUrl, badW3Ccaps).should.eventually.be.rejectedWith(/400/);
273
+ });
274
+ it('should accept a combo of W3C and JSONWP capabilities but completely ignore JSONWP', async function () {
275
+ const combinedCaps = {
276
+ 'desiredCapabilities': { ...caps,
277
+ jsonwpParam: 'jsonwpParam'
278
+ },
279
+ 'capabilities': {
280
+ 'alwaysMatch': { ...caps
281
+ },
282
+ 'firstMatch': [{
283
+ 'appium:w3cParam': 'w3cParam'
284
+ }]
285
+ }
286
+ };
287
+ const {
288
+ status,
289
+ value,
290
+ sessionId
291
+ } = (await _axios.default.post(baseUrl, combinedCaps)).data;
292
+
293
+ try {
294
+ should.not.exist(status);
295
+ should.not.exist(sessionId);
296
+ value.sessionId.should.exist;
297
+ value.capabilities.should.deep.equal({ ...(0, _utils.removeAppiumPrefixes)(caps),
298
+ w3cParam: 'w3cParam'
299
+ });
300
+ } finally {
301
+ await _axios.default.delete(`${baseUrl}/${value.sessionId}`);
302
+ }
303
+ });
304
+ it('should reject bad automation name with an appropriate error', async function () {
305
+ const w3cCaps = {
306
+ capabilities: {
307
+ alwaysMatch: { ...caps,
308
+ 'appium:automationName': 'BadAutomationName'
309
+ }
310
+ }
311
+ };
312
+ await _axios.default.post(baseUrl, w3cCaps).should.eventually.be.rejectedWith(/500/);
313
+ });
314
+ it('should accept capabilities that are provided in the firstMatch array', async function () {
315
+ const w3cCaps = {
316
+ capabilities: {
317
+ alwaysMatch: {},
318
+ firstMatch: [{}, { ...caps
319
+ }]
320
+ }
321
+ };
322
+ const {
323
+ value,
324
+ sessionId,
325
+ status
326
+ } = (await _axios.default.post(baseUrl, w3cCaps)).data;
327
+
328
+ try {
329
+ should.not.exist(status);
330
+ should.not.exist(sessionId);
331
+ value.capabilities.should.deep.equal((0, _utils.removeAppiumPrefixes)(caps));
332
+ } finally {
333
+ await _axios.default.delete(`${baseUrl}/${value.sessionId}`);
334
+ }
335
+ });
336
+ it('should not fall back to MJSONWP if w3c caps are invalid', async function () {
337
+ const combinedCaps = {
338
+ desiredCapabilities: { ...caps
339
+ },
340
+ capabilities: {
341
+ alwaysMatch: {},
342
+ firstMatch: [{}, { ...caps,
343
+ platformName: null,
344
+ 'appium:automationName': null,
345
+ 'appium:deviceName': null
346
+ }]
347
+ }
348
+ };
349
+ const res = await _axios.default.post(baseUrl, combinedCaps, {
350
+ validateStatus: null
351
+ });
352
+ res.status.should.eql(400);
353
+ res.data.value.error.should.match(/invalid argument/);
354
+ });
355
+ it('should not fall back to MJSONWP even if Inner Driver is not ready for W3C', async function () {
356
+ const combinedCaps = {
357
+ desiredCapabilities: { ...caps
358
+ },
359
+ capabilities: {
360
+ alwaysMatch: { ...caps,
361
+ 'appium:deviceName': 'Fake'
362
+ }
363
+ }
364
+ };
365
+
366
+ const createSessionStub = _sinon.default.stub(FakeDriver.prototype, 'createSession').callsFake(async function (jsonwpCaps) {
367
+ const res = await _baseDriver.BaseDriver.prototype.createSession.call(this, jsonwpCaps);
368
+ this.protocol.should.equal('MJSONWP');
369
+ return res;
370
+ });
371
+
372
+ const res = await _axios.default.post(baseUrl, combinedCaps, {
373
+ validateStatus: null
374
+ });
375
+ const {
376
+ data,
377
+ status
378
+ } = res;
379
+ status.should.eql(500);
380
+ data.value.message.should.match(/older capabilities/);
381
+ createSessionStub.restore();
382
+ });
383
+ it('should allow drivers to update the method map with new routes and commands', async function () {
384
+ let driver = await (0, _webdriverio.remote)({ ...wdOpts,
385
+ capabilities: caps
386
+ });
387
+ const {
388
+ sessionId
389
+ } = driver;
390
+
391
+ try {
392
+ await _axios.default.post(`${baseUrl}/${sessionId}/fakedriver`, {
393
+ thing: {
394
+ yes: 'lolno'
395
+ }
396
+ });
397
+ (await _axios.default.get(`${baseUrl}/${sessionId}/fakedriver`)).data.value.should.eql({
398
+ yes: 'lolno'
399
+ });
400
+ } finally {
401
+ await driver.deleteSession();
402
+ }
403
+ });
404
+ });
405
+ });
406
+ describe.skip('Logsink', function () {
407
+ let server = null;
408
+ let logs = [];
409
+
410
+ let logHandler = function (level, message) {
411
+ logs.push([level, message]);
412
+ };
413
+
414
+ let args = {
415
+ port: TEST_PORT,
416
+ host: _helpers.TEST_HOST,
417
+ appiumHome: _extensionConfig.DEFAULT_APPIUM_HOME,
418
+ logHandler
419
+ };
420
+ before(async function () {
421
+ server = await (0, _main.main)(args);
422
+ });
423
+ after(async function () {
424
+ await server.close();
425
+ });
426
+ it('should send logs to a logHandler passed in by a parent package', function () {
427
+ logs.length.should.be.above(1);
428
+ let welcomeIndex = logs[0][1].includes('versions of node') ? 1 : 0;
429
+ logs[welcomeIndex].length.should.equal(2);
430
+ logs[welcomeIndex][1].should.include('Welcome to Appium');
431
+ });
432
+ });require('source-map-support').install();
433
+
434
+
435
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZHJpdmVyLWUyZS1zcGVjcy5qcyJdLCJuYW1lcyI6WyJURVNUX1NFUlZFUiIsIlRFU1RfUE9SVCIsInNpbGx5V2ViU2VydmVyUG9ydCIsInNpbGx5V2ViU2VydmVySG9zdCIsIkZBS0VfQVJHUyIsIkZBS0VfRFJJVkVSX0FSR1MiLCJkcml2ZXIiLCJmYWtlIiwic2hvdWxkU3RhcnRTZXJ2ZXIiLCJwcm9jZXNzIiwiZW52IiwiVVNFX1JVTk5JTkdfU0VSVkVSIiwiY2FwcyIsIlczQ19QUkVGSVhFRF9DQVBTIiwid2RPcHRzIiwiaG9zdG5hbWUiLCJURVNUX0hPU1QiLCJwb3J0IiwiY29ubmVjdGlvblJldHJ5Q291bnQiLCJkZXNjcmliZSIsInNlcnZlciIsImFwcGl1bUhvbWUiLCJERUZBVUxUX0FQUElVTV9IT01FIiwiRmFrZURyaXZlciIsImJhc2VVcmwiLCJGQUtFX0RSSVZFUl9ESVIiLCJwYXRoIiwiam9pbiIsIlBST0pFQ1RfUk9PVCIsImJlZm9yZSIsImRyaXZlckxpc3QiLCJkcml2ZXJDb21tYW5kIiwic2hvd0luc3RhbGxlZCIsIkRSSVZFUl9UWVBFIiwiXyIsImhhcyIsImluc3RhbGxUeXBlIiwiSU5TVEFMTF9UWVBFX0xPQ0FMIiwiY29uZmlnIiwiRHJpdmVyQ29uZmlnIiwiZ2V0SW5zdGFuY2UiLCJyZXF1aXJlIiwic2VydmVyU3RhcnQiLCJhZnRlciIsInNlcnZlckNsb3NlIiwiYXJncyIsImhvc3QiLCJjbG9zZSIsIml0IiwiZGF0YSIsImF4aW9zIiwiZ2V0Iiwic2hvdWxkIiwiZXFsIiwiZmFrZWRyaXZlciIsImNhcGFiaWxpdGllcyIsInNlc3Npb25JZCIsIm5vdCIsImV4aXN0IiwidmFsdWUiLCJkZWxldGVTZXNzaW9uIiwiYmUiLCJhIiwiZ2V0VGl0bGUiLCJldmVudHVhbGx5IiwicmVqZWN0ZWRXaXRoIiwiZHJpdmVyMSIsImRyaXZlcjIiLCJlcXVhbCIsInVuaXF1ZUNhcHMiLCJjbG9uZSIsInJlamVjdGVkIiwibG9jYWxDYXBzIiwiT2JqZWN0IiwiYXNzaWduIiwiQiIsImRlbGF5IiwiZ2V0UGFnZVNvdXJjZSIsInczY0NhcHMiLCJhbHdheXNNYXRjaCIsInBsYXRmb3JtTmFtZSIsImZpcnN0TWF0Y2giLCJURVNUX0ZBS0VfQVBQIiwic3RhdHVzIiwicG9zdCIsInN0cmluZyIsImRlZXAiLCJhdXRvbWF0aW9uTmFtZSIsImRldmljZU5hbWUiLCJhcHAiLCJzY3JlZW5zaG90U3RhdHVzIiwic2NyZWVuc2hvdFZhbHVlIiwidXJsIiwibWF0Y2giLCJzY3JpcHQiLCJkZWxldGUiLCJiYWRXM0NjYXBzIiwiY29tYmluZWRDYXBzIiwianNvbndwUGFyYW0iLCJ3M2NQYXJhbSIsImRlc2lyZWRDYXBhYmlsaXRpZXMiLCJyZXMiLCJ2YWxpZGF0ZVN0YXR1cyIsImVycm9yIiwiY3JlYXRlU2Vzc2lvblN0dWIiLCJzaW5vbiIsInN0dWIiLCJwcm90b3R5cGUiLCJjYWxsc0Zha2UiLCJqc29ud3BDYXBzIiwiQmFzZURyaXZlciIsImNyZWF0ZVNlc3Npb24iLCJjYWxsIiwicHJvdG9jb2wiLCJtZXNzYWdlIiwicmVzdG9yZSIsInRoaW5nIiwieWVzIiwic2tpcCIsImxvZ3MiLCJsb2dIYW5kbGVyIiwibGV2ZWwiLCJwdXNoIiwibGVuZ3RoIiwiYWJvdmUiLCJ3ZWxjb21lSW5kZXgiLCJpbmNsdWRlcyIsImluY2x1ZGUiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUVBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUdBLElBQUlBLFdBQUo7QUFDQSxJQUFJQyxTQUFKO0FBQ0EsTUFBTUMsa0JBQWtCLEdBQUcsSUFBM0I7QUFDQSxNQUFNQyxrQkFBa0IsR0FBRyxLQUEzQjtBQUNBLE1BQU1DLFNBQVMsR0FBRztBQUFDRixFQUFBQSxrQkFBRDtBQUFxQkMsRUFBQUE7QUFBckIsQ0FBbEI7QUFDQSxNQUFNRSxnQkFBZ0IsR0FBRztBQUFDQyxFQUFBQSxNQUFN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Q0QsR0FMQyxDQUFGO0FBTUQsQ0EzQkQiLCJzb3VyY2VzQ29udGVudCI6WyIvLyB0cmFuc3BpbGU6bW9jaGFcblxuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IEIgZnJvbSAnYmx1ZWJpcmQnO1xuaW1wb3J0IGF4aW9zIGZyb20gJ2F4aW9zJztcbmltcG9ydCB7IHJlbW90ZSBhcyB3ZGlvIH0gZnJvbSAnd2ViZHJpdmVyaW8nO1xuaW1wb3J0IHsgbWFpbiBhcyBhcHBpdW1TZXJ2ZXIgfSBmcm9tICcuLi9saWIvbWFpbic7XG5pbXBvcnQgeyBERUZBVUxUX0FQUElVTV9IT01FLCBJTlNUQUxMX1RZUEVfTE9DQUwsIERSSVZFUl9UWVBFIH0gZnJvbSAnLi4vbGliL2V4dGVuc2lvbi1jb25maWcnO1xuaW1wb3J0IHsgVzNDX1BSRUZJWEVEX0NBUFMsIFRFU1RfRkFLRV9BUFAsIFRFU1RfSE9TVCwgZ2V0VGVzdFBvcnQsIFBST0pFQ1RfUk9PVCB9IGZyb20gJy4vaGVscGVycyc7XG5pbXBvcnQgeyBCYXNlRHJpdmVyIH0gZnJvbSAnQGFwcGl1bS9iYXNlLWRyaXZlcic7XG5pbXBvcnQgRHJpdmVyQ29uZmlnIGZyb20gJy4uL2xpYi9kcml2ZXItY29uZmlnJztcbmltcG9ydCB7IHJ1bkV4dGVuc2lvbkNvbW1hbmQgfSBmcm9tICcuLi9saWIvY2xpL2V4dGVuc2lvbic7XG5pbXBvcnQgeyByZW1vdmVBcHBpdW1QcmVmaXhlcyB9IGZyb20gJy4uL2xpYi91dGlscyc7XG5pbXBvcnQgc2lub24gZnJvbSAnc2lub24nO1xuXG5cbmxldCBURVNUX1NFUlZFUjtcbmxldCBURVNUX1BPUlQ7XG5jb25zdCBzaWxseVdlYlNlcnZlclBvcnQgPSAxMjM0O1xuY29uc3Qgc2lsbHlXZWJTZXJ2ZXJIb3N0ID0gJ2hleSc7XG5jb25zdCBGQUtFX0FSR1MgPSB7c2lsbHlXZWJTZXJ2ZXJQb3J0LCBzaWxseVdlYlNlcnZlckhvc3R9O1xuY29uc3QgRkFLRV9EUklWRVJfQVJHUyA9IHtkcml2ZXI6IHtmYWtlOiBGQUtFX0FSR1N9fTtcbmNvbnN0IHNob3VsZFN0YXJ0U2VydmVyID0gcHJvY2Vzcy5lbnYuVVNFX1JVTk5JTkdfU0VSVkVSICE9PSAnMCc7XG5jb25zdCBjYXBzID0gVzNDX1BSRUZJWEVEX0NBUFM7XG5jb25zdCB3ZE9wdHMgPSB7XG4gIGhvc3RuYW1lOiBURVNUX0hPU1QsXG4gIHBvcnQ6IG51bGwsXG4gIGNvbm5lY3Rpb25SZXRyeUNvdW50OiAwLFxufTtcblxuZGVzY3JpYmUoJ0Zha2VEcml2ZXIgLSB2aWEgSFRUUCcsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IHNlcnZlciA9IG51bGw7XG4gIGNvbnN0IGFwcGl1bUhvbWUgPSBERUZBVUxUX0FQUElVTV9IT01FO1xuICAvLyBzaW5jZSB3ZSB1cGRhdGUgdGhlIEZha2VEcml2ZXIucHJvdG90eXBlIGJlbG93LCBtYWtlIHN1cmUgd2UgdXBkYXRlIHRoZSBGYWtlRHJpdmVyIHdoaWNoIGlzXG4gIC8vIGFjdHVhbGx5IGdvaW5nIHRvIGJlIHJlcXVpcmVkIGJ5IEFwcGl1bVxuICBsZXQgRmFrZURyaXZlciA9IG51bGw7XG4gIGxldCBiYXNlVXJsO1xuICBjb25zdCBGQUtFX0RSSVZFUl9ESVIgPSBwYXRoLmpvaW4oUFJPSkVDVF9ST09ULCAncGFja2FnZXMnLCAnZmFrZS1kcml2ZXInKTtcbiAgYmVmb3JlKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICB3ZE9wdHMucG9ydCA9IFRFU1RfUE9SVCA9IGF3YWl0IGdldFRlc3RQb3J0KCk7XG4gICAgVEVTVF9TRVJWRVIgPSBgaHR0cDovLyR7VEVTVF9IT1NUfToke1RFU1RfUE9SVH1gO1xuICAgIGJhc2VVcmwgPSBgJHtURVNUX1NFUlZFUn0vc2Vzc2lvbmA7XG4gICAgLy8gZmlyc3QgZW5zdXJlIHdlIGhhdmUgZmFrZWRyaXZlciBpbnN0YWxsZWRcbiAgICBjb25zdCBkcml2ZXJMaXN0ID0gYXdhaXQgcnVuRXh0ZW5zaW9uQ29tbWFuZCh7XG4gICAgICBhcHBpdW1Ib21lLFxuICAgICAgZHJpdmVyQ29tbWFuZDogJ2xpc3QnLFxuICAgICAgc2hvd0luc3RhbGxlZDogdHJ1ZSxcbiAgICB9LCBEUklWRVJfVFlQRSk7XG4gICAgaWYgKCFfLmhhcyhkcml2ZXJMaXN0LCAnZmFrZScpKSB7XG4gICAgICBhd2FpdCBydW5FeHRlbnNpb25Db21tYW5kKHtcbiAgICAgICAgYXBwaXVtSG9tZSxcbiAgICAgICAgZHJpdmVyQ29tbWFuZDogJ2luc3RhbGwnLFxuICAgICAgICBkcml2ZXI6IEZBS0VfRFJJVkVSX0RJUixcbiAgICAgICAgaW5zdGFsbFR5cGU6IElOU1RBTExfVFlQRV9MT0NBTCxcbiAgICAgIH0sIERSSVZFUl9UWVBFKTtcbiAgICB9XG5cbiAgICBjb25zdCBjb25maWcgPSBEcml2ZXJDb25maWcuZ2V0SW5zdGFuY2UoYXBwaXVtSG9tZSk7XG4gICAgRmFrZURyaXZlciA9IGNvbmZpZy5yZXF1aXJlKCdmYWtlJyk7XG4gICAgLy8gdGhlbiBzdGFydCBzZXJ2ZXIgaWYgd2UgbmVlZCB0b1xuICAgIGF3YWl0IHNlcnZlclN0YXJ0KCk7XG4gIH0pO1xuXG4gIGFmdGVyKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICBhd2FpdCBzZXJ2ZXJDbG9zZSgpO1xuICB9KTtcblxuICBhc3luYyBmdW5jdGlvbiBzZXJ2ZXJTdGFydCAoYXJncyA9IHt9KSB7XG4gICAgYXJncyA9IHtwb3J0OiBURVNUX1BPUlQsIGhvc3Q6IFRFU1RfSE9TVCwgYXBwaXVtSG9tZSwgLi4uYXJnc307XG4gICAgaWYgKHNob3VsZFN0YXJ0U2VydmVyKSB7XG4gICAgICBzZXJ2ZXIgPSBhd2FpdCBhcHBpdW1TZXJ2ZXIoYXJncyk7XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgZnVuY3Rpb24gc2VydmVyQ2xvc2UgKCkge1xuICAgIGlmIChzZXJ2ZXIpIHtcbiAgICAgIGF3YWl0IHNlcnZlci5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIGRlc2NyaWJlKCdzZXJ2ZXIgdXBkYXRpbmcnLCBmdW5jdGlvbiAoKSB7XG4gICAgaXQoJ3Nob3VsZCBhbGxvdyBkcml2ZXJzIHRvIHVwZGF0ZSB0aGUgc2VydmVyIGluIGFyYml0cmFyeSB3YXlzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3Qge2RhdGF9ID0gYXdhaXQgYXhpb3MuZ2V0KGAke1RFU1RfU0VSVkVSfS9mYWtlZHJpdmVyYCk7XG4gICAgICBkYXRhLnNob3VsZC5lcWwoe2Zha2Vkcml2ZXI6ICdmYWtlUmVzcG9uc2UnfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdjbGkgYXJncyBoYW5kbGluZyBmb3IgZW1wdHkgYXJncycsIGZ1bmN0aW9uICgpIHtcbiAgICBpdCgnc2hvdWxkIG5vdCByZWNpZXZlIHVzZXIgY2xpIGFyZ3MgaWYgbm9uZSBwYXNzZWQgaW4nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgZHJpdmVyID0gYXdhaXQgd2Rpbyh7Li4ud2RPcHRzLCBjYXBhYmlsaXRpZXM6IGNhcHN9KTtcbiAgICAgIGNvbnN0IHtzZXNzaW9uSWR9ID0gZHJpdmVyO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qge2RhdGF9ID0gYXdhaXQgYXhpb3MuZ2V0KGAke2Jhc2VVcmx9LyR7c2Vzc2lvbklkfS9mYWtlZHJpdmVyYXJnc2ApO1xuICAgICAgICBzaG91bGQubm90LmV4aXN0KGRhdGEudmFsdWUuc2lsbHlXZWJTZXJ2ZXJQb3J0KTtcbiAgICAgICAgc2hvdWxkLm5vdC5leGlzdChkYXRhLnZhbHVlLnNpbGx5V2ViU2VydmVySG9zdCk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICBhd2FpdCBkcml2ZXIuZGVsZXRlU2Vzc2lvbigpO1xuICAgICAgfVxuICAgIH0pO1xuICB9KTtcblxuICBkZXNjcmliZSgnY2xpIGFyZ3MgaGFuZGxpbmcgZm9yIHBhc3NlZCBpbiBhcmdzJywgZnVuY3Rpb24gKCkge1xuICAgIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBhd2FpdCBzZXJ2ZXJDbG9zZSgpO1xuICAgICAgYXdhaXQgc2VydmVyU3RhcnQoRkFLRV9EUklWRVJfQVJHUyk7XG4gICAgfSk7XG4gICAgYWZ0ZXIoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgYXdhaXQgc2VydmVyQ2xvc2UoKTtcbiAgICAgIGF3YWl0IHNlcnZlclN0YXJ0KCk7XG4gICAgfSk7XG4gICAgaXQoJ3Nob3VsZCByZWNlaXZlIHVzZXIgY2xpIGFyZ3MgZnJvbSBhIGRyaXZlciBpZiBhcmd1bWVudHMgd2VyZSBwYXNzZWQgaW4nLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgZHJpdmVyID0gYXdhaXQgd2Rpbyh7Li4ud2RPcHRzLCBjYXBhYmlsaXRpZXM6IGNhcHN9KTtcbiAgICAgIGNvbnN0IHtzZXNzaW9uSWR9ID0gZHJpdmVyO1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3Qge2RhdGF9ID0gYXdhaXQgYXhpb3MuZ2V0KGAke2Jhc2VVcmx9LyR7c2Vzc2lvbklkfS9mYWtlZHJpdmVyYXJnc2ApO1xuICAgICAgICBkYXRhLnZhbHVlLnNpbGx5V2ViU2VydmVyUG9ydC5zaG91bGQuZXFsKHNpbGx5V2ViU2VydmVyUG9ydCk7XG4gICAgICAgIGRhdGEudmFsdWUuc2lsbHlXZWJTZXJ2ZXJIb3N0LnNob3VsZC5lcWwoc2lsbHlXZWJTZXJ2ZXJIb3N0KTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGRyaXZlci5kZWxldGVTZXNzaW9uKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCdzZXNzaW9uIGhhbmRsaW5nJywgZnVuY3Rpb24gKCkge1xuICAgIGl0KCdzaG91bGQgc3RhcnQgYW5kIHN0b3AgYSBzZXNzaW9uIGFuZCBub3QgYWxsb3cgY29tbWFuZHMgYWZ0ZXIgc2Vzc2lvbiBzdG9wcGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGRyaXZlciA9IGF3YWl0IHdkaW8oey4uLndkT3B0cywgY2FwYWJpbGl0aWVzOiBjYXBzfSk7XG4gICAgICBzaG91bGQuZXhpc3QoZHJpdmVyLnNlc3Npb25JZCk7XG4gICAgICBkcml2ZXIuc2Vzc2lvbklkLnNob3VsZC5iZS5hKCdzdHJpbmcnKTtcbiAgICAgIGF3YWl0IGRyaXZlci5kZWxldGVTZXNzaW9uKCk7XG4gICAgICBhd2FpdCBkcml2ZXIuZ2V0VGl0bGUoKS5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZFdpdGgoL3Rlcm1pbmF0ZWQvKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgYmUgYWJsZSB0byBydW4gdHdvIEZha2VEcml2ZXIgc2Vzc2lvbnMgc2ltdWx0YW5lb3VzbHknLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgZHJpdmVyMSA9IGF3YWl0IHdkaW8oey4uLndkT3B0cywgY2FwYWJpbGl0aWVzOiBjYXBzfSk7XG4gICAgICBzaG91bGQuZXhpc3QoZHJpdmVyMS5zZXNzaW9uSWQpO1xuICAgICAgZHJpdmVyMS5zZXNzaW9uSWQuc2hvdWxkLmJlLmEoJ3N0cmluZycpO1xuICAgICAgbGV0IGRyaXZlcjIgPSBhd2FpdCB3ZGlvKHsuLi53ZE9wdHMsIGNhcGFiaWxpdGllczogY2Fwc30pO1xuICAgICAgc2hvdWxkLmV4aXN0KGRyaXZlcjIuc2Vzc2lvbklkKTtcbiAgICAgIGRyaXZlcjIuc2Vzc2lvbklkLnNob3VsZC5iZS5hKCdzdHJpbmcnKTtcbiAgICAgIGRyaXZlcjIuc2Vzc2lvbklkLnNob3VsZC5ub3QuZXF1YWwoZHJpdmVyMS5zZXNzaW9uSWQpO1xuICAgICAgYXdhaXQgZHJpdmVyMS5kZWxldGVTZXNzaW9uKCk7XG4gICAgICBhd2FpdCBkcml2ZXIyLmRlbGV0ZVNlc3Npb24oKTtcbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgbm90IGJlIGFibGUgdG8gcnVuIHR3byBGYWtlRHJpdmVyIHNlc3Npb25zIHNpbXVsdGFuZW91c2x5IHdoZW4gb25lIGlzIHVuaXF1ZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCB1bmlxdWVDYXBzID0gXy5jbG9uZShjYXBzKTtcbiAgICAgIHVuaXF1ZUNhcHNbJ2FwcGl1bTp1bmlxdWVBcHAnXSA9IHRydWU7XG4gICAgICBsZXQgZHJpdmVyMSA9IGF3YWl0IHdkaW8oey4uLndkT3B0cywgY2FwYWJpbGl0aWVzOiB1bmlxdWVDYXBzfSk7XG4gICAgICBzaG91bGQuZXhpc3QoZHJpdmVyMS5zZXNzaW9uSWQpO1xuICAgICAgZHJpdmVyMS5zZXNzaW9uSWQuc2hvdWxkLmJlLmEoJ3N0cmluZycpO1xuICAgICAgYXdhaXQgd2Rpbyh7Li4ud2RPcHRzLCBjYXBhYmlsaXRpZXM6IGNhcHN9KS5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZDtcbiAgICAgIGF3YWl0IGRyaXZlcjEuZGVsZXRlU2Vzc2lvbigpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCB1c2UgdGhlIG5ld0NvbW1hbmRUaW1lb3V0IG9mIHRoZSBpbm5lciBEcml2ZXIgb24gc2Vzc2lvbiBjcmVhdGlvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBsb2NhbENhcHMgPSBPYmplY3QuYXNzaWduKHtcbiAgICAgICAgJ2FwcGl1bTpuZXdDb21tYW5kVGltZW91dCc6IDAuMjUsXG4gICAgICB9LCBjYXBzKTtcbiAgICAgIGxldCBkcml2ZXIgPSBhd2FpdCB3ZGlvKHsuLi53ZE9wdHMsIGNhcGFiaWxpdGllczogbG9jYWxDYXBzfSk7XG4gICAgICBzaG91bGQuZXhpc3QoZHJpdmVyLnNlc3Npb25JZCk7XG5cbiAgICAgIGF3YWl0IEIuZGVsYXkoMjUwKTtcbiAgICAgIGF3YWl0IGRyaXZlci5nZXRQYWdlU291cmNlKCkuc2hvdWxkLmV2ZW50dWFsbHkuYmUucmVqZWN0ZWRXaXRoKC90ZXJtaW5hdGVkLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFjY2VwdCB2YWxpZCBXM0MgY2FwYWJpbGl0aWVzIGFuZCBzdGFydCBhIFczQyBzZXNzaW9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgLy8gVHJ5IHdpdGggdmFsaWQgY2FwYWJpbGl0aWVzIGFuZCBjaGVjayB0aGF0IGl0IHJldHVybnMgYSBzZXNzaW9uIElEXG4gICAgICBjb25zdCB3M2NDYXBzID0ge1xuICAgICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgICBhbHdheXNNYXRjaDogeydhcHBpdW06YXV0b21hdGlvbk5hbWUnOiAnRmFrZScsIHBsYXRmb3JtTmFtZTogJ0Zha2UnfSxcbiAgICAgICAgICBmaXJzdE1hdGNoOiBbeydhcHBpdW06ZGV2aWNlTmFtZSc6ICdGYWtlJywgJ2FwcGl1bTphcHAnOiBURVNUX0ZBS0VfQVBQfV0sXG4gICAgICAgIH1cbiAgICAgIH07XG5cbiAgICAgIC8vIENyZWF0ZSB0aGUgc2Vzc2lvblxuICAgICAgY29uc3Qge3N0YXR1cywgdmFsdWUsIHNlc3Npb25JZH0gPSAoYXdhaXQgYXhpb3MucG9zdChiYXNlVXJsLCB3M2NDYXBzKSkuZGF0YTtcbiAgICAgIHRyeSB7XG4gICAgICAgIHNob3VsZC5ub3QuZXhpc3Qoc3RhdHVzKTsgLy8gVGVzdCB0aGF0IGl0J3MgYSBXM0Mgc2Vzc2lvbiBieSBjaGVja2luZyB0aGF0ICdzdGF0dXMnIGlzIG5vdCBpbiB0aGUgcmVzcG9uc2VcbiAgICAgICAgc2hvdWxkLm5vdC5leGlzdChzZXNzaW9uSWQpO1xuICAgICAgICB2YWx1ZS5zZXNzaW9uSWQuc2hvdWxkLmJlLmEuc3RyaW5nO1xuICAgICAgICB2YWx1ZS5zaG91bGQuZXhpc3Q7XG4gICAgICAgIHZhbHVlLmNhcGFiaWxpdGllcy5zaG91bGQuZGVlcC5lcXVhbCh7XG4gICAgICAgICAgYXV0b21hdGlvbk5hbWU6ICdGYWtlJyxcbiAgICAgICAgICBwbGF0Zm9ybU5hbWU6ICdGYWtlJyxcbiAgICAgICAgICBkZXZpY2VOYW1lOiAnRmFrZScsXG4gICAgICAgICAgYXBwOiBURVNUX0ZBS0VfQVBQLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBOb3cgdXNlIHRoYXQgc2Vzc2lvbklkIHRvIGNhbGwgL3NjcmVlbnNob3RcbiAgICAgICAgY29uc3Qge3N0YXR1czogc2NyZWVuc2hvdFN0YXR1cywgdmFsdWU6IHNjcmVlbnNob3RWYWx1ZX0gPSAoYXdhaXQgYXhpb3Moe3VybDogYCR7YmFzZVVybH0vJHt2YWx1ZS5zZXNzaW9uSWR9L3NjcmVlbnNob3RgfSkpLmRhdGE7XG4gICAgICAgIHNob3VsZC5ub3QuZXhpc3Qoc2NyZWVuc2hvdFN0YXR1cyk7XG4gICAgICAgIHNjcmVlbnNob3RWYWx1ZS5zaG91bGQubWF0Y2goL15pVkJPUi8pOyAvLyBzaG91bGQgYmUgYSBwbmdcblxuICAgICAgICAvLyBOb3cgdXNlIHRoYXQgc2Vzc2lvbklEIHRvIGNhbGwgYW4gYXJiaXRyYXJ5IFczQy1vbmx5IGVuZHBvaW50IHRoYXQgaXNuJ3QgaW1wbGVtZW50ZWQgdG8gc2VlIGlmIGl0IHJlc3BvbmRzIHdpdGggY29ycmVjdCBlcnJvclxuICAgICAgICBhd2FpdCBheGlvcy5wb3N0KFxuICAgICAgICAgIGAke2Jhc2VVcmx9LyR7dmFsdWUuc2Vzc2lvbklkfS9leGVjdXRlL2FzeW5jYCxcbiAgICAgICAgICB7c2NyaXB0OiAnJywgYXJnczogWydhJ119KS5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZFdpdGgoLzQwNS8pO1xuICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgLy8gRW5kIHNlc3Npb25cbiAgICAgICAgYXdhaXQgYXhpb3MuZGVsZXRlKGAke2Jhc2VVcmx9LyR7dmFsdWUuc2Vzc2lvbklkfWApO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCByZWplY3QgaW52YWxpZCBXM0MgY2FwYWJpbGl0aWVzIGFuZCByZXNwb25kIHdpdGggYSA0MDAgQmFkIFBhcmFtZXRlcnMgZXJyb3InLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBiYWRXM0NjYXBzID0ge1xuICAgICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgICBhbHdheXNNYXRjaDoge30sXG4gICAgICAgICAgZmlyc3RNYXRjaDogW3snYXBwaXVtOmRldmljZU5hbWUnOiAnRmFrZScsICdhcHBpdW06YXBwJzogVEVTVF9GQUtFX0FQUH1dLFxuICAgICAgICB9XG4gICAgICB9O1xuXG4gICAgICBhd2FpdCBheGlvcy5wb3N0KGJhc2VVcmwsIGJhZFczQ2NhcHMpLnNob3VsZC5ldmVudHVhbGx5LmJlLnJlamVjdGVkV2l0aCgvNDAwLyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIGFjY2VwdCBhIGNvbWJvIG9mIFczQyBhbmQgSlNPTldQIGNhcGFiaWxpdGllcyBidXQgY29tcGxldGVseSBpZ25vcmUgSlNPTldQJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgY29tYmluZWRDYXBzID0ge1xuICAgICAgICAnZGVzaXJlZENhcGFiaWxpdGllcyc6IHtcbiAgICAgICAgICAuLi5jYXBzLFxuICAgICAgICAgIGpzb253cFBhcmFtOiAnanNvbndwUGFyYW0nLFxuICAgICAgICB9LFxuICAgICAgICAnY2FwYWJpbGl0aWVzJzoge1xuICAgICAgICAgICdhbHdheXNNYXRjaCc6IHsuLi5jYXBzfSxcbiAgICAgICAgICAnZmlyc3RNYXRjaCc6IFt7XG4gICAgICAgICAgICAnYXBwaXVtOnczY1BhcmFtJzogJ3czY1BhcmFtJyxcbiAgICAgICAgICB9XSxcbiAgICAgICAgfVxuICAgICAgfTtcblxuICAgICAgY29uc3Qge3N0YXR1cywgdmFsdWUsIHNlc3Npb25JZH0gPSAoYXdhaXQgYXhpb3MucG9zdChiYXNlVXJsLCBjb21iaW5lZENhcHMpKS5kYXRhO1xuICAgICAgdHJ5IHtcbiAgICAgICAgc2hvdWxkLm5vdC5leGlzdChzdGF0dXMpOyAvLyBJZiBpdCdzIGEgVzNDIHNlc3Npb24sIHNob3VsZCBub3QgcmVzcG9uZCB3aXRoICdzdGF0dXMnXG4gICAgICAgIHNob3VsZC5ub3QuZXhpc3Qoc2Vzc2lvbklkKTtcbiAgICAgICAgdmFsdWUuc2Vzc2lvbklkLnNob3VsZC5leGlzdDtcbiAgICAgICAgdmFsdWUuY2FwYWJpbGl0aWVzLnNob3VsZC5kZWVwLmVxdWFsKHtcbiAgICAgICAgICAuLi5yZW1vdmVBcHBpdW1QcmVmaXhlcyhjYXBzKSxcbiAgICAgICAgICB3M2NQYXJhbTogJ3czY1BhcmFtJyxcbiAgICAgICAgfSk7XG4gICAgICB9IGZpbmFsbHkge1xuICAgICAgICAvLyBFbmQgc2Vzc2lvblxuICAgICAgICBhd2FpdCBheGlvcy5kZWxldGUoYCR7YmFzZVVybH0vJHt2YWx1ZS5zZXNzaW9uSWR9YCk7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIHJlamVjdCBiYWQgYXV0b21hdGlvbiBuYW1lIHdpdGggYW4gYXBwcm9wcmlhdGUgZXJyb3InLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCB3M2NDYXBzID0ge1xuICAgICAgICBjYXBhYmlsaXRpZXM6IHtcbiAgICAgICAgICBhbHdheXNNYXRjaDoge1xuICAgICAgICAgICAgLi4uY2FwcyxcbiAgICAgICAgICAgICdhcHBpdW06YXV0b21hdGlvbk5hbWUnOiAnQmFkQXV0b21hdGlvbk5hbWUnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgYXdhaXQgYXhpb3MucG9zdChiYXNlVXJsLCB3M2NDYXBzKS5zaG91bGQuZXZlbnR1YWxseS5iZS5yZWplY3RlZFdpdGgoLzUwMC8pO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhY2NlcHQgY2FwYWJpbGl0aWVzIHRoYXQgYXJlIHByb3ZpZGVkIGluIHRoZSBmaXJzdE1hdGNoIGFycmF5JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgdzNjQ2FwcyA9IHtcbiAgICAgICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICAgICAgYWx3YXlzTWF0Y2g6IHt9LFxuICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fSwge1xuICAgICAgICAgICAgLi4uY2Fwc1xuICAgICAgICAgIH1dLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICAgIGNvbnN0IHt2YWx1ZSwgc2Vzc2lvbklkLCBzdGF0dXN9ID0gKGF3YWl0IGF4aW9zLnBvc3QoYmFzZVVybCwgdzNjQ2FwcykpLmRhdGE7XG4gICAgICB0cnkge1xuICAgICAgICBzaG91bGQubm90LmV4aXN0KHN0YXR1cyk7XG4gICAgICAgIHNob3VsZC5ub3QuZXhpc3Qoc2Vzc2lvbklkKTtcbiAgICAgICAgdmFsdWUuY2FwYWJpbGl0aWVzLnNob3VsZC5kZWVwLmVxdWFsKHJlbW92ZUFwcGl1bVByZWZpeGVzKGNhcHMpKTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIC8vIEVuZCBzZXNzaW9uXG4gICAgICAgIGF3YWl0IGF4aW9zLmRlbGV0ZShgJHtiYXNlVXJsfS8ke3ZhbHVlLnNlc3Npb25JZH1gKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGl0KCdzaG91bGQgbm90IGZhbGwgYmFjayB0byBNSlNPTldQIGlmIHczYyBjYXBzIGFyZSBpbnZhbGlkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgY29uc3QgY29tYmluZWRDYXBzID0ge1xuICAgICAgICBkZXNpcmVkQ2FwYWJpbGl0aWVzOiB7XG4gICAgICAgICAgLi4uY2FwcyxcbiAgICAgICAgfSxcbiAgICAgICAgY2FwYWJpbGl0aWVzOiB7XG4gICAgICAgICAgYWx3YXlzTWF0Y2g6IHt9LFxuICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fSwge1xuICAgICAgICAgICAgLi4uY2FwcyxcbiAgICAgICAgICAgIHBsYXRmb3JtTmFtZTogbnVsbCxcbiAgICAgICAgICAgICdhcHBpdW06YXV0b21hdGlvbk5hbWUnOiBudWxsLFxuICAgICAgICAgICAgJ2FwcGl1bTpkZXZpY2VOYW1lJzogbnVsbCxcbiAgICAgICAgICB9XSxcbiAgICAgICAgfSxcbiAgICAgIH07XG4gICAgICBjb25zdCByZXMgPSAoYXdhaXQgYXhpb3MucG9zdChiYXNlVXJsLCBjb21iaW5lZENhcHMsIHt2YWxpZGF0ZVN0YXR1czogbnVsbH0pKTtcbiAgICAgIHJlcy5zdGF0dXMuc2hvdWxkLmVxbCg0MDApO1xuICAgICAgcmVzLmRhdGEudmFsdWUuZXJyb3Iuc2hvdWxkLm1hdGNoKC9pbnZhbGlkIGFyZ3VtZW50Lyk7XG4gICAgfSk7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBmYWxsIGJhY2sgdG8gTUpTT05XUCBldmVuIGlmIElubmVyIERyaXZlciBpcyBub3QgcmVhZHkgZm9yIFczQycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGNvbWJpbmVkQ2FwcyA9IHtcbiAgICAgICAgZGVzaXJlZENhcGFiaWxpdGllczoge1xuICAgICAgICAgIC4uLmNhcHMsXG4gICAgICAgIH0sXG4gICAgICAgIGNhcGFiaWxpdGllczoge1xuICAgICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgICAuLi5jYXBzLFxuICAgICAgICAgICAgJ2FwcGl1bTpkZXZpY2VOYW1lJzogJ0Zha2UnLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgICAgY29uc3QgY3JlYXRlU2Vzc2lvblN0dWIgPSBzaW5vbi5zdHViKEZha2VEcml2ZXIucHJvdG90eXBlLCAnY3JlYXRlU2Vzc2lvbicpLmNhbGxzRmFrZShhc3luYyBmdW5jdGlvbiAoanNvbndwQ2Fwcykge1xuICAgICAgICBjb25zdCByZXMgPSBhd2FpdCBCYXNlRHJpdmVyLnByb3RvdHlwZS5jcmVhdGVTZXNzaW9uLmNhbGwodGhpcywganNvbndwQ2Fwcyk7XG4gICAgICAgIHRoaXMucHJvdG9jb2wuc2hvdWxkLmVxdWFsKCdNSlNPTldQJyk7XG4gICAgICAgIHJldHVybiByZXM7XG4gICAgICB9KTtcblxuICAgICAgY29uc3QgcmVzID0gKGF3YWl0IGF4aW9zLnBvc3QoYmFzZVVybCwgY29tYmluZWRDYXBzLCB7dmFsaWRhdGVTdGF0dXM6IG51bGx9KSk7XG4gICAgICBjb25zdCB7ZGF0YSwgc3RhdHVzfSA9IHJlcztcbiAgICAgIHN0YXR1cy5zaG91bGQuZXFsKDUwMCk7XG4gICAgICBkYXRhLnZhbHVlLm1lc3NhZ2Uuc2hvdWxkLm1hdGNoKC9vbGRlciBjYXBhYmlsaXRpZXMvKTtcblxuICAgICAgY3JlYXRlU2Vzc2lvblN0dWIucmVzdG9yZSgpO1xuICAgIH0pO1xuXG4gICAgaXQoJ3Nob3VsZCBhbGxvdyBkcml2ZXJzIHRvIHVwZGF0ZSB0aGUgbWV0aG9kIG1hcCB3aXRoIG5ldyByb3V0ZXMgYW5kIGNvbW1hbmRzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGRyaXZlciA9IGF3YWl0IHdkaW8oey4uLndkT3B0cywgY2FwYWJpbGl0aWVzOiBjYXBzfSk7XG4gICAgICBjb25zdCB7c2Vzc2lvbklkfSA9IGRyaXZlcjtcbiAgICAgIHRyeSB7XG4gICAgICAgIGF3YWl0IGF4aW9zLnBvc3QoYCR7YmFzZVVybH0vJHtzZXNzaW9uSWR9L2Zha2Vkcml2ZXJgLCB7dGhpbmc6IHt5ZXM6ICdsb2xubyd9fSk7XG4gICAgICAgIChhd2FpdCBheGlvcy5nZXQoYCR7YmFzZVVybH0vJHtzZXNzaW9uSWR9L2Zha2Vkcml2ZXJgKSkuZGF0YS52YWx1ZS5zaG91bGQuZXFsKHt5ZXM6ICdsb2xubyd9KTtcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGF3YWl0IGRyaXZlci5kZWxldGVTZXNzaW9uKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0pO1xufSk7XG5cbi8vIFRPRE8gdGhpcyB0ZXN0IG9ubHkgd29ya3MgaWYgdGhlIGxvZyBoYXMgbm90IHByZXZpb3VzbHkgYmVlbiBpbml0aWFsaXplZCBpbiB0aGUgc2FtZSBwcm9jZXNzLlxuLy8gdGhlcmUgc2VlbXMgdG8gYmUgc29tZSBnbG9iYWwgc3RhdGUgdGhhdCBpcyBub3QgY2xlYW5lZCB1cCBiZXR3ZWVuIHRlc3RzLlxuZGVzY3JpYmUuc2tpcCgnTG9nc2luaycsIGZ1bmN0aW9uICgpIHtcbiAgbGV0IHNlcnZlciA9IG51bGw7XG4gIGxldCBsb2dzID0gW107XG4gIGxldCBsb2dIYW5kbGVyID0gZnVuY3Rpb24gKGxldmVsLCBtZXNzYWdlKSB7XG4gICAgbG9ncy5wdXNoKFtsZXZlbCwgbWVzc2FnZV0pO1xuICB9O1xuICBsZXQgYXJncyA9IHtcbiAgICBwb3J0OiBURVNUX1BPUlQsXG4gICAgaG9zdDogVEVTVF9IT1NULFxuICAgIGFwcGl1bUhvbWU6IERFRkFVTFRfQVBQSVVNX0hPTUUsXG4gICAgbG9nSGFuZGxlcixcbiAgfTtcblxuICBiZWZvcmUoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIHNlcnZlciA9IGF3YWl0IGFwcGl1bVNlcnZlcihhcmdzKTtcbiAgfSk7XG5cbiAgYWZ0ZXIoYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgIGF3YWl0IHNlcnZlci5jbG9zZSgpO1xuICB9KTtcblxuICBpdCgnc2hvdWxkIHNlbmQgbG9ncyB0byBhIGxvZ0hhbmRsZXIgcGFzc2VkIGluIGJ5IGEgcGFyZW50IHBhY2thZ2UnLCBmdW5jdGlvbiAoKSB7XG4gICAgbG9ncy5sZW5ndGguc2hvdWxkLmJlLmFib3ZlKDEpO1xuICAgIGxldCB3ZWxjb21lSW5kZXggPSBsb2dzWzBdWzFdLmluY2x1ZGVzKCd2ZXJzaW9ucyBvZiBub2RlJykgPyAxIDogMDtcbiAgICBsb2dzW3dlbGNvbWVJbmRleF0ubGVuZ3RoLnNob3VsZC5lcXVhbCgyKTtcbiAgICBsb2dzW3dlbGNvbWVJbmRleF1bMV0uc2hvdWxkLmluY2x1ZGUoJ1dlbGNvbWUgdG8gQXBwaXVtJyk7XG4gIH0pO1xufSk7XG4iXSwiZmlsZSI6InRlc3QvZHJpdmVyLWUyZS1zcGVjcy5qcyIsInNvdXJjZVJvb3QiOiIuLi8uLiJ9