appium 2.0.0-beta.24 → 2.0.0-beta.27

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 (124) hide show
  1. package/build/lib/appium-config.schema.json +278 -0
  2. package/build/lib/appium.js +45 -66
  3. package/build/lib/cli/args.js +19 -39
  4. package/build/lib/cli/driver-command.js +5 -9
  5. package/build/lib/cli/extension-command.js +73 -64
  6. package/build/lib/cli/extension.js +10 -23
  7. package/build/lib/cli/parser.js +9 -19
  8. package/build/lib/cli/plugin-command.js +5 -9
  9. package/build/lib/cli/utils.js +2 -4
  10. package/build/lib/config-file.js +5 -10
  11. package/build/lib/config.js +50 -20
  12. package/build/lib/constants.js +60 -0
  13. package/build/lib/extension/driver-config.js +190 -0
  14. package/build/lib/extension/extension-config.js +297 -0
  15. package/build/lib/extension/index.js +77 -0
  16. package/build/lib/extension/manifest.js +246 -0
  17. package/build/lib/extension/package-changed.js +68 -0
  18. package/build/lib/extension/plugin-config.js +87 -0
  19. package/build/lib/grid-register.js +2 -4
  20. package/build/lib/logger.js +2 -4
  21. package/build/lib/logsink.js +2 -4
  22. package/build/lib/main.js +42 -71
  23. package/build/lib/schema/appium-config-schema.js +2 -4
  24. package/build/lib/schema/arg-spec.js +11 -14
  25. package/build/lib/schema/cli-args.js +2 -4
  26. package/build/lib/schema/cli-transformers.js +2 -4
  27. package/build/lib/schema/index.js +2 -4
  28. package/build/lib/schema/keywords.js +2 -4
  29. package/build/lib/schema/schema.js +61 -37
  30. package/build/lib/utils.js +1 -32
  31. package/lib/appium.js +50 -68
  32. package/lib/cli/args.js +19 -23
  33. package/lib/cli/driver-command.js +10 -2
  34. package/lib/cli/extension-command.js +216 -135
  35. package/lib/cli/extension.js +7 -15
  36. package/lib/cli/parser.js +6 -14
  37. package/lib/cli/plugin-command.js +1 -2
  38. package/lib/config-file.js +12 -15
  39. package/lib/config.js +55 -24
  40. package/lib/constants.js +79 -0
  41. package/lib/extension/driver-config.js +230 -0
  42. package/lib/extension/extension-config.js +459 -0
  43. package/lib/extension/index.js +103 -0
  44. package/lib/extension/manifest.js +590 -0
  45. package/lib/extension/package-changed.js +64 -0
  46. package/lib/extension/plugin-config.js +111 -0
  47. package/lib/grid-register.js +4 -4
  48. package/lib/main.js +57 -93
  49. package/lib/schema/arg-spec.js +3 -3
  50. package/lib/schema/cli-args.js +1 -0
  51. package/lib/schema/keywords.js +1 -1
  52. package/lib/schema/schema.js +67 -29
  53. package/lib/utils.js +2 -32
  54. package/package.json +29 -21
  55. package/{postinstall.js → scripts/postinstall.js} +1 -1
  56. package/types/types.d.ts +70 -31
  57. package/bin/ios-webkit-debug-proxy-launcher.js +0 -71
  58. package/build/check-npm-pack-files.js +0 -23
  59. package/build/commands-yml/parse.js +0 -319
  60. package/build/commands-yml/validator.js +0 -130
  61. package/build/index.js +0 -19
  62. package/build/lib/cli/npm.js +0 -220
  63. package/build/lib/driver-config.js +0 -100
  64. package/build/lib/drivers.js +0 -100
  65. package/build/lib/ext-config-io.js +0 -165
  66. package/build/lib/extension-config.js +0 -320
  67. package/build/lib/plugin-config.js +0 -69
  68. package/build/lib/plugins.js +0 -18
  69. package/build/postinstall.js +0 -90
  70. package/build/test/cli/cli-e2e-specs.js +0 -221
  71. package/build/test/cli/cli-helpers.js +0 -86
  72. package/build/test/cli/cli-specs.js +0 -71
  73. package/build/test/cli/fixtures/test-driver/package.json +0 -27
  74. package/build/test/cli/schema-args-specs.js +0 -48
  75. package/build/test/cli/schema-e2e-specs.js +0 -47
  76. package/build/test/config-e2e-specs.js +0 -112
  77. package/build/test/config-file-e2e-specs.js +0 -209
  78. package/build/test/config-file-specs.js +0 -281
  79. package/build/test/config-specs.js +0 -246
  80. package/build/test/driver-e2e-specs.js +0 -435
  81. package/build/test/driver-specs.js +0 -386
  82. package/build/test/ext-config-io-specs.js +0 -181
  83. package/build/test/extension-config-specs.js +0 -365
  84. package/build/test/fixtures/allow-feat.txt +0 -5
  85. package/build/test/fixtures/caps.json +0 -3
  86. package/build/test/fixtures/config/allow-insecure.txt +0 -3
  87. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +0 -5
  88. package/build/test/fixtures/config/appium.config.bad.json +0 -32
  89. package/build/test/fixtures/config/appium.config.ext-good.json +0 -9
  90. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +0 -10
  91. package/build/test/fixtures/config/appium.config.good.js +0 -40
  92. package/build/test/fixtures/config/appium.config.good.json +0 -33
  93. package/build/test/fixtures/config/appium.config.good.yaml +0 -30
  94. package/build/test/fixtures/config/appium.config.invalid.json +0 -31
  95. package/build/test/fixtures/config/appium.config.security-array.json +0 -5
  96. package/build/test/fixtures/config/appium.config.security-delimited.json +0 -5
  97. package/build/test/fixtures/config/appium.config.security-path.json +0 -5
  98. package/build/test/fixtures/config/driver-fake.config.json +0 -8
  99. package/build/test/fixtures/config/nodeconfig.json +0 -3
  100. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  101. package/build/test/fixtures/default-args.js +0 -35
  102. package/build/test/fixtures/deny-feat.txt +0 -5
  103. package/build/test/fixtures/driver.schema.js +0 -20
  104. package/build/test/fixtures/extensions.yaml +0 -27
  105. package/build/test/fixtures/flattened-schema.js +0 -532
  106. package/build/test/fixtures/plugin.schema.js +0 -20
  107. package/build/test/fixtures/schema-with-extensions.js +0 -28
  108. package/build/test/grid-register-specs.js +0 -74
  109. package/build/test/helpers.js +0 -75
  110. package/build/test/logger-specs.js +0 -76
  111. package/build/test/npm-specs.js +0 -20
  112. package/build/test/parser-specs.js +0 -319
  113. package/build/test/plugin-e2e-specs.js +0 -316
  114. package/build/test/schema/arg-spec-specs.js +0 -70
  115. package/build/test/schema/cli-args-specs.js +0 -408
  116. package/build/test/schema/schema-specs.js +0 -407
  117. package/build/test/utils-specs.js +0 -288
  118. package/lib/cli/npm.js +0 -251
  119. package/lib/driver-config.js +0 -101
  120. package/lib/drivers.js +0 -84
  121. package/lib/ext-config-io.js +0 -287
  122. package/lib/extension-config.js +0 -366
  123. package/lib/plugin-config.js +0 -63
  124. package/lib/plugins.js +0 -13
@@ -1,435 +0,0 @@
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