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,386 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _baseDriver = require("@appium/base-driver");
8
+
9
+ var _fakeDriver = require("@appium/fake-driver");
10
+
11
+ var _asyncbox = require("asyncbox");
12
+
13
+ var _lodash = _interopRequireDefault(require("lodash"));
14
+
15
+ var _sinon = _interopRequireDefault(require("sinon"));
16
+
17
+ var _appium = require("../lib/appium");
18
+
19
+ var _schema = require("../lib/schema/schema");
20
+
21
+ var _utils = require("../lib/utils");
22
+
23
+ var _helpers = require("./helpers");
24
+
25
+ const SESSION_ID = 1;
26
+ describe('AppiumDriver', function () {
27
+ beforeEach(function () {
28
+ (0, _schema.resetSchema)();
29
+ (0, _schema.finalizeSchema)();
30
+ });
31
+ describe('instance method', function () {
32
+ function getDriverAndFakeDriver(appiumArgs = {}, DriverClass = _fakeDriver.FakeDriver) {
33
+ const appium = new _appium.AppiumDriver(appiumArgs);
34
+ const fakeDriver = new DriverClass();
35
+
36
+ const mockFakeDriver = _sinon.default.mock(fakeDriver);
37
+
38
+ mockFakeDriver._fakeDriver = fakeDriver;
39
+
40
+ const mockedDriverReturnerClass = function Driver() {
41
+ return fakeDriver;
42
+ };
43
+
44
+ appium._findMatchingDriver = function () {
45
+ return {
46
+ driver: mockedDriverReturnerClass,
47
+ version: '1.2.3',
48
+ driverName: 'fake'
49
+ };
50
+ };
51
+
52
+ return [appium, mockFakeDriver];
53
+ }
54
+
55
+ describe('createSession', function () {
56
+ let appium;
57
+ let mockFakeDriver;
58
+ beforeEach(function () {
59
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
60
+ });
61
+ afterEach(async function () {
62
+ mockFakeDriver.restore();
63
+ await appium.deleteSession(SESSION_ID);
64
+ });
65
+ it(`should call inner driver's createSession with desired capabilities`, async function () {
66
+ mockFakeDriver.expects('createSession').once().withExactArgs(null, null, _helpers.W3C_CAPS, []).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
67
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
68
+ mockFakeDriver.verify();
69
+ });
70
+ it(`should call inner driver's createSession with desired and default capabilities`, async function () {
71
+ let defaultCaps = {
72
+ 'appium:someCap': 'hello'
73
+ };
74
+ let allCaps = { ..._helpers.W3C_CAPS,
75
+ alwaysMatch: { ..._helpers.W3C_CAPS.alwaysMatch,
76
+ ...defaultCaps
77
+ }
78
+ };
79
+ appium.args.defaultCapabilities = defaultCaps;
80
+ mockFakeDriver.expects('createSession').once().withArgs(null, null, allCaps).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(allCaps.alwaysMatch)]);
81
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
82
+ mockFakeDriver.verify();
83
+ });
84
+ it(`should call inner driver's createSession with desired and default capabilities without overriding caps`, async function () {
85
+ let defaultCaps = {
86
+ platformName: 'Ersatz'
87
+ };
88
+ appium.args.defaultCapabilities = defaultCaps;
89
+ mockFakeDriver.expects('createSession').once().withArgs(null, null, _helpers.W3C_CAPS).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
90
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
91
+ mockFakeDriver.verify();
92
+ });
93
+ it('should kill all other sessions if sessionOverride is on', async function () {
94
+ appium.args.sessionOverride = true;
95
+ let fakeDrivers = [new _fakeDriver.FakeDriver(), new _fakeDriver.FakeDriver(), new _fakeDriver.FakeDriver()];
96
+
97
+ let mockFakeDrivers = _lodash.default.map(fakeDrivers, fd => _sinon.default.mock(fd));
98
+
99
+ mockFakeDrivers[0].expects('deleteSession').once();
100
+ mockFakeDrivers[1].expects('deleteSession').once().throws('Cannot shut down Android driver; it has already shut down');
101
+ mockFakeDrivers[2].expects('deleteSession').once();
102
+ appium.sessions['abc-123-xyz'] = fakeDrivers[0];
103
+ appium.sessions['xyz-321-abc'] = fakeDrivers[1];
104
+ appium.sessions['123-abc-xyz'] = fakeDrivers[2];
105
+ let sessions = await appium.getSessions();
106
+ sessions.should.have.length(3);
107
+ mockFakeDriver.expects('createSession').once().withExactArgs(null, null, _helpers.W3C_CAPS, []).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
108
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
109
+ sessions = await appium.getSessions();
110
+ sessions.should.have.length(1);
111
+
112
+ for (let mfd of mockFakeDrivers) {
113
+ mfd.verify();
114
+ }
115
+
116
+ mockFakeDriver.verify();
117
+ });
118
+ it('should call "createSession" with W3C capabilities argument, if provided', async function () {
119
+ mockFakeDriver.expects('createSession').once().withArgs(null, undefined, _helpers.W3C_CAPS).returns([SESSION_ID, _helpers.BASE_CAPS]);
120
+ await appium.createSession(undefined, undefined, _helpers.W3C_CAPS);
121
+ mockFakeDriver.verify();
122
+ });
123
+ it('should call "createSession" with W3C capabilities argument with additional provided parameters', async function () {
124
+ let w3cCaps = { ..._helpers.W3C_CAPS,
125
+ alwaysMatch: { ..._helpers.W3C_CAPS.alwaysMatch,
126
+ 'appium:someOtherParm': 'someOtherParm'
127
+ }
128
+ };
129
+ mockFakeDriver.expects('createSession').once().withArgs(null, undefined, {
130
+ alwaysMatch: { ...w3cCaps.alwaysMatch,
131
+ 'appium:someOtherParm': 'someOtherParm'
132
+ },
133
+ firstMatch: [{}]
134
+ }).returns([SESSION_ID, (0, _utils.insertAppiumPrefixes)(_helpers.BASE_CAPS)]);
135
+ await appium.createSession(undefined, undefined, w3cCaps);
136
+ mockFakeDriver.verify();
137
+ });
138
+ it('should not call "createSession" with JSONWP capabilities if W3C has incomplete capabilities', async function () {
139
+ const w3cCaps = { ..._helpers.W3C_CAPS,
140
+ alwaysMatch: {
141
+ 'appium:someOtherParm': 'someOtherParm'
142
+ }
143
+ };
144
+ const jsonwpCaps = { ..._helpers.BASE_CAPS,
145
+ automationName: 'Fake',
146
+ someOtherParam: 'someOtherParam'
147
+ };
148
+ mockFakeDriver.expects('createSession').never();
149
+ await appium.createSession(jsonwpCaps, undefined, w3cCaps);
150
+ mockFakeDriver.verify();
151
+ });
152
+ it('should assign args to property `cliArgs`', async function () {
153
+ class ArgsDriver extends _baseDriver.BaseDriver {}
154
+
155
+ const args = {
156
+ driver: {
157
+ fake: {
158
+ randomArg: 1234
159
+ }
160
+ }
161
+ };
162
+ [appium, mockFakeDriver] = getDriverAndFakeDriver(args, ArgsDriver);
163
+ const {
164
+ value
165
+ } = await appium.createSession(undefined, undefined, _helpers.W3C_CAPS);
166
+
167
+ try {
168
+ mockFakeDriver._fakeDriver.cliArgs.should.eql({
169
+ randomArg: 1234
170
+ });
171
+ } finally {
172
+ await appium.deleteSession(value[0]);
173
+ }
174
+ });
175
+ });
176
+ describe('deleteSession', function () {
177
+ let appium;
178
+ let mockFakeDriver;
179
+ beforeEach(function () {
180
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
181
+ });
182
+ afterEach(function () {
183
+ mockFakeDriver.restore();
184
+ });
185
+ it('should remove the session if it is found', async function () {
186
+ let [sessionId] = (await appium.createSession(null, null, _helpers.W3C_CAPS)).value;
187
+ let sessions = await appium.getSessions();
188
+ sessions.should.have.length(1);
189
+ await appium.deleteSession(sessionId);
190
+ sessions = await appium.getSessions();
191
+ sessions.should.have.length(0);
192
+ });
193
+ it('should call inner driver\'s deleteSession method', async function () {
194
+ const [sessionId] = (await appium.createSession(null, null, _helpers.W3C_CAPS)).value;
195
+ mockFakeDriver.expects('deleteSession').once().withExactArgs(sessionId, []).returns();
196
+ await appium.deleteSession(sessionId);
197
+ mockFakeDriver.verify();
198
+ await mockFakeDriver.object.deleteSession();
199
+ });
200
+ });
201
+ describe('getSessions', function () {
202
+ let appium, mockFakeDriver;
203
+ let sessions;
204
+ before(function () {
205
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
206
+ });
207
+ afterEach(async function () {
208
+ for (let session of sessions) {
209
+ await appium.deleteSession(session.id);
210
+ }
211
+
212
+ mockFakeDriver.restore();
213
+ });
214
+ it('should return an empty array of sessions', async function () {
215
+ sessions = await appium.getSessions();
216
+ sessions.should.be.an('array');
217
+ sessions.should.be.empty;
218
+ });
219
+ it('should return sessions created', async function () {
220
+ let caps1 = {
221
+ alwaysMatch: { ..._helpers.W3C_PREFIXED_CAPS,
222
+ 'appium:cap': 'value'
223
+ }
224
+ };
225
+ let caps2 = {
226
+ alwaysMatch: { ..._helpers.W3C_PREFIXED_CAPS,
227
+ 'appium:cap': 'other value'
228
+ }
229
+ };
230
+ mockFakeDriver.expects('createSession').once().returns(['fake-session-id-1', (0, _utils.removeAppiumPrefixes)(caps1.alwaysMatch)]);
231
+ let [session1Id, session1Caps] = (await appium.createSession(null, null, caps1)).value;
232
+ mockFakeDriver.expects('createSession').once().returns(['fake-session-id-2', (0, _utils.removeAppiumPrefixes)(caps2.alwaysMatch)]);
233
+ let [session2Id, session2Caps] = (await appium.createSession(null, null, caps2)).value;
234
+ sessions = await appium.getSessions();
235
+ sessions.should.be.an('array');
236
+ sessions.should.have.length(2);
237
+ sessions[0].id.should.equal(session1Id);
238
+ (0, _utils.removeAppiumPrefixes)(caps1.alwaysMatch).should.eql(session1Caps);
239
+ sessions[1].id.should.equal(session2Id);
240
+ (0, _utils.removeAppiumPrefixes)(caps2.alwaysMatch).should.eql(session2Caps);
241
+ });
242
+ });
243
+ describe('getStatus', function () {
244
+ let appium;
245
+ before(function () {
246
+ appium = new _appium.AppiumDriver({});
247
+ });
248
+ it('should return a status', async function () {
249
+ let status = await appium.getStatus();
250
+ status.build.should.exist;
251
+ status.build.version.should.exist;
252
+ });
253
+ });
254
+ describe('sessionExists', function () {});
255
+ describe('attachUnexpectedShutdownHandler', function () {
256
+ let appium;
257
+ let mockFakeDriver;
258
+ beforeEach(function () {
259
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
260
+ });
261
+ afterEach(async function () {
262
+ await mockFakeDriver.object.deleteSession();
263
+ mockFakeDriver.restore();
264
+ appium.args.defaultCapabilities = {};
265
+ });
266
+ it('should remove session if inner driver unexpectedly exits with an error', async function () {
267
+ let [sessionId] = (await appium.createSession(null, null, _lodash.default.clone(_helpers.W3C_CAPS))).value;
268
+
269
+ _lodash.default.keys(appium.sessions).should.contain(sessionId);
270
+
271
+ appium.sessions[sessionId].eventEmitter.emit('onUnexpectedShutdown', new Error('Oops'));
272
+ await (0, _asyncbox.sleep)(1);
273
+
274
+ _lodash.default.keys(appium.sessions).should.not.contain(sessionId);
275
+ });
276
+ it('should remove session if inner driver unexpectedly exits with no error', async function () {
277
+ let [sessionId] = (await appium.createSession(null, null, _lodash.default.clone(_helpers.W3C_CAPS))).value;
278
+
279
+ _lodash.default.keys(appium.sessions).should.contain(sessionId);
280
+
281
+ appium.sessions[sessionId].eventEmitter.emit('onUnexpectedShutdown');
282
+ await (0, _asyncbox.sleep)(1);
283
+
284
+ _lodash.default.keys(appium.sessions).should.not.contain(sessionId);
285
+ });
286
+ });
287
+ describe('createPluginInstances', function () {
288
+ class NoArgsPlugin {}
289
+
290
+ NoArgsPlugin.pluginName = 'noargs';
291
+
292
+ class ArgsPlugin {}
293
+
294
+ ArgsPlugin.pluginName = 'args';
295
+
296
+ class ArrayArgPlugin {}
297
+
298
+ ArrayArgPlugin.pluginName = 'arrayarg';
299
+ beforeEach(function () {
300
+ (0, _schema.resetSchema)();
301
+ (0, _schema.registerSchema)('plugin', ArgsPlugin.pluginName, {
302
+ type: 'object',
303
+ properties: {
304
+ randomArg: {
305
+ type: 'number',
306
+ default: 2000
307
+ }
308
+ }
309
+ });
310
+ (0, _schema.registerSchema)('plugin', ArrayArgPlugin.pluginName, {
311
+ type: 'object',
312
+ properties: {
313
+ arr: {
314
+ type: 'array',
315
+ default: []
316
+ }
317
+ }
318
+ });
319
+ (0, _schema.finalizeSchema)();
320
+ });
321
+ describe('when args are not present', function () {
322
+ it('should not set CLI args', function () {
323
+ const appium = new _appium.AppiumDriver({});
324
+ appium.pluginClasses = [NoArgsPlugin, ArgsPlugin];
325
+
326
+ for (const plugin of appium.createPluginInstances()) {
327
+ should.not.exist(plugin.cliArgs);
328
+ }
329
+ });
330
+ });
331
+ describe('when args are equal to the schema defaults', function () {
332
+ it('should not set CLI args', function () {
333
+ const appium = new _appium.AppiumDriver({
334
+ plugin: {
335
+ [ArgsPlugin.pluginName]: {
336
+ randomArg: 2000
337
+ }
338
+ }
339
+ });
340
+ appium.pluginClasses = [NoArgsPlugin, ArgsPlugin];
341
+
342
+ for (const plugin of appium.createPluginInstances()) {
343
+ should.not.exist(plugin.cliArgs);
344
+ }
345
+ });
346
+ describe('when the default is an "object"', function () {
347
+ it('should not set CLI args', function () {
348
+ const appium = new _appium.AppiumDriver({
349
+ plugin: {
350
+ [ArrayArgPlugin.pluginName]: {
351
+ arr: []
352
+ }
353
+ }
354
+ });
355
+ appium.pluginClasses = [NoArgsPlugin, ArgsPlugin, ArrayArgPlugin];
356
+
357
+ for (const plugin of appium.createPluginInstances()) {
358
+ should.not.exist(plugin.cliArgs);
359
+ }
360
+ });
361
+ });
362
+ });
363
+ describe('when args are not equal to the schema defaults', function () {
364
+ it('should add cliArgs to the plugin', function () {
365
+ const appium = new _appium.AppiumDriver({
366
+ plugin: {
367
+ args: {
368
+ randomArg: 1234
369
+ }
370
+ }
371
+ });
372
+ appium.pluginClasses = [ArgsPlugin];
373
+
374
+ const plugin = _lodash.default.first(appium.createPluginInstances());
375
+
376
+ plugin.cliArgs.should.eql({
377
+ randomArg: 1234
378
+ });
379
+ });
380
+ });
381
+ });
382
+ });
383
+ });require('source-map-support').install();
384
+
385
+
386
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZHJpdmVyLXNwZWNzLmpzIl0sIm5hbWVzIjpbIlNFU1NJT05fSUQiLCJkZXNjcmliZSIsImJlZm9yZUVhY2giLCJnZXREcml2ZXJBbmRGYWtlRHJpdmVyIiwiYXBwaXVtQXJncyIsIkRyaXZlckNsYXNzIiwiRmFrZURyaXZlciIsImFwcGl1bSIsIkFwcGl1bURyaXZlciIsImZha2VEcml2ZXIiLCJtb2NrRmFrZURyaXZlciIsInNpbm9uIiwibW9jayIsIl9mYWtlRHJpdmVyIiwibW9ja2VkRHJpdmVyUmV0dXJuZXJDbGFzcyIsIkRyaXZlciIsIl9maW5kTWF0Y2hpbmdEcml2ZXIiLCJkcml2ZXIiLCJ2ZXJzaW9uIiwiZHJpdmVyTmFtZSIsImFmdGVyRWFjaCIsInJlc3RvcmUiLCJkZWxldGVTZXNzaW9uIiwiaXQiLCJleHBlY3RzIiwib25jZSIsIndpdGhFeGFjdEFyZ3MiLCJXM0NfQ0FQUyIsInJldHVybnMiLCJXM0NfUFJFRklYRURfQ0FQUyIsImNyZWF0ZVNlc3Npb24iLCJ2ZXJpZnkiLCJkZWZhdWx0Q2FwcyIsImFsbENhcHMiLCJhbHdheXNNYXRjaCIsImFyZ3MiLCJkZWZhdWx0Q2FwYWJpbGl0aWVzIiwid2l0aEFyZ3MiLCJwbGF0Zm9ybU5hbWUiLCJzZXNzaW9uT3ZlcnJpZGUiLCJmYWtlRHJpdmVycyIsIm1vY2tGYWtlRHJpdmVycyIsIl8iLCJtYXAiLCJmZCIsInRocm93cyIsInNlc3Npb25zIiwiZ2V0U2Vzc2lvbnMiLCJzaG91bGQiLCJoYXZlIiwibGVuZ3RoIiwibWZkIiwidW5kZWZpbmVkIiwiQkFTRV9DQVBTIiwidzNjQ2FwcyIsImZpcnN0TWF0Y2giLCJqc29ud3BDYXBzIiwiYXV0b21hdGlvbk5hbWUiLCJzb21lT3RoZXJQYXJhbSIsIm5ldmVyIiwiQXJnc0RyaXZlciIsIkJhc2VEcml2ZXIiLCJmYWtlIiwicmFuZG9tQXJnIiwidmFsdWUiLCJjbGlBcmdzIiwiZXFsIiwic2Vzc2lvbklkIiwib2JqZWN0IiwiYmVmb3JlIiwic2Vzc2lvbiIsImlkIiwiYmUiLCJhbiIsImVtcHR5IiwiY2FwczEiLCJjYXBzMiIsInNlc3Npb24xSWQiLCJzZXNzaW9uMUNhcHMiLCJzZXNzaW9uMklkIiwic2Vzc2lvbjJDYXBzIiwiZXF1YWwiLCJzdGF0dXMiLCJnZXRTdGF0dXMiLCJidWlsZCIsImV4aXN0IiwiY2xvbmUiLCJrZXlzIiwiY29udGFpbiIsImV2ZW50RW1pdHRlciIsImVtaXQiLCJFcnJvciIsIm5vdCIsIk5vQXJnc1BsdWdpbiIsInBsdWdpbk5hbWUiLCJBcmdzUGx1Z2luIiwiQXJyYXlBcmdQbHVnaW4iLCJ0eXBlIiwicHJvcGVydGllcyIsImRlZmF1bHQiLCJhcnIiLCJwbHVnaW5DbGFzc2VzIiwicGx1Z2luIiwiY3JlYXRlUGx1Z2luSW5zdGFuY2VzIiwiZmlyc3QiXSwibWFwcGluZ3MiOiI7Ozs7OztBQUVBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUdBLE1BQU1BLFVBQVUsR0FBRyxDQUFuQjtBQUVBQyxRQUFRLENBQUMsY0FBRCxFQUFpQixZQUFZO0FBQ25DQyxFQUFBQSxVQUFVLENBQUMsWUFBWTtBQUNyQjtBQUNBO0FBQ0QsR0FIUyxDQUFWO0FBSUFELEVBQUFBLFFBQVEsQ0FBQyxpQkFBRCxFQUFvQixZQUFZO0FBQ3RDLGFBQVNFLHNCQUFULENBQWlDQyxVQUFVLEdBQUcsRUFBOUMsRUFBa0RDLFdBQVcsR0FBR0Msc0JBQWhFLEVBQTRFO0FBQzFFLFlBQU1DLE1BQU0sR0FBRyxJQUFJQyxvQkFBSixDQUFpQkosVUFBakIsQ0FBZjtBQUNBLFlBQU1LLFVBQVUsR0FBRyxJQUFJSixXQUFKLEVBQW5COztBQUNBLFlBQU1LLGNBQWMsR0FBR0MsZUFBTUMsSUFBTixDQUFXSCxVQUFYLENBQXZCOztBQUNBQyxNQUFBQSxjQUFjLENBQUNHLFdBQWYsR0FBNkJKLFVBQTdCOztBQUNBLFlBQU1LLHlCQUF5QixHQUFHLFNBQVNDLE1BQVQsR0FBbUI7QUFDbkQsZUFBT04sVUFBUDtB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RjtBQU9ELFNBUk8sQ0FBUjtBQVNELE9BbEJPLENBQVI7QUFvQkFoRSxNQUFBQSxRQUFRLENBQUMsZ0RBQUQsRUFBbUQsWUFBWTtBQUNyRXNCLFFBQUFBLEVBQUUsQ0FBQyxrQ0FBRCxFQUFxQyxZQUFZO0FBQ2pELGdCQUFNaEIsTUFBTSxHQUFHLElBQUlDLG9CQUFKLENBQWlCO0FBQUM4RixZQUFBQSxNQUFNLEVBQUU7QUFBQ25FLGNBQUFBLElBQUksRUFBRTtBQUFDNEIsZ0JBQUFBLFNBQVMsRUFBRTtBQUFaO0FBQVA7QUFBVCxXQUFqQixDQUFmO0FBQ0F4RCxVQUFBQSxNQUFNLENBQUM4RixhQUFQLEdBQXVCLENBQUNOLFVBQUQsQ0FBdkI7O0FBQ0EsZ0JBQU1PLE1BQU0sR0FBRzVELGdCQUFFOEQsS0FBRixDQUFRakcsTUFBTSxDQUFDZ0cscUJBQVAsRUFBUixDQUFmOztBQUNBRCxVQUFBQSxNQUFNLENBQUNyQyxPQUFQLENBQWVqQixNQUFmLENBQXNCa0IsR0FBdEIsQ0FBMEI7QUFBQ0gsWUFBQUEsU0FBUyxFQUFFO0FBQVosV0FBMUI7QUFDRCxTQUxDLENBQUY7QUFNRCxPQVBPLENBQVI7QUFRRCxLQTFFTyxDQUFSO0FBMkVELEdBalZPLENBQVI7QUFrVkQsQ0F2Vk8sQ0FBUiIsInNvdXJjZXNDb250ZW50IjpbIi8vIHRyYW5zcGlsZTptb2NoYVxuXG5pbXBvcnQgeyBCYXNlRHJpdmVyIH0gZnJvbSAnQGFwcGl1bS9iYXNlLWRyaXZlcic7XG5pbXBvcnQgeyBGYWtlRHJpdmVyIH0gZnJvbSAnQGFwcGl1bS9mYWtlLWRyaXZlcic7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gJ2FzeW5jYm94JztcbmltcG9ydCBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgc2lub24gZnJvbSAnc2lub24nO1xuaW1wb3J0IHsgQXBwaXVtRHJpdmVyIH0gZnJvbSAnLi4vbGliL2FwcGl1bSc7XG5pbXBvcnQgeyBmaW5hbGl6ZVNjaGVtYSwgcmVnaXN0ZXJTY2hlbWEsIHJlc2V0U2NoZW1hIH0gZnJvbSAnLi4vbGliL3NjaGVtYS9zY2hlbWEnO1xuaW1wb3J0IHsgaW5zZXJ0QXBwaXVtUHJlZml4ZXMsIHJlbW92ZUFwcGl1bVByZWZpeGVzIH0gZnJvbSAnLi4vbGliL3V0aWxzJztcbmltcG9ydCB7IEJBU0VfQ0FQUywgVzNDX0NBUFMsIFczQ19QUkVGSVhFRF9DQVBTIH0gZnJvbSAnLi9oZWxwZXJzJztcblxuXG5jb25zdCBTRVNTSU9OX0lEID0gMTtcblxuZGVzY3JpYmUoJ0FwcGl1bURyaXZlcicsIGZ1bmN0aW9uICgpIHtcbiAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgcmVzZXRTY2hlbWEoKTtcbiAgICBmaW5hbGl6ZVNjaGVtYSgpO1xuICB9KTtcbiAgZGVzY3JpYmUoJ2luc3RhbmNlIG1ldGhvZCcsIGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBnZXREcml2ZXJBbmRGYWtlRHJpdmVyIChhcHBpdW1BcmdzID0ge30sIERyaXZlckNsYXNzID0gRmFrZURyaXZlcikge1xuICAgICAgY29uc3QgYXBwaXVtID0gbmV3IEFwcGl1bURyaXZlcihhcHBpdW1BcmdzKTtcbiAgICAgIGNvbnN0IGZha2VEcml2ZXIgPSBuZXcgRHJpdmVyQ2xhc3MoKTtcbiAgICAgIGNvbnN0IG1vY2tGYWtlRHJpdmVyID0gc2lub24ubW9jayhmYWtlRHJpdmVyKTtcbiAgICAgIG1vY2tGYWtlRHJpdmVyLl9mYWtlRHJpdmVyID0gZmFrZURyaXZlcjtcbiAgICAgIGNvbnN0IG1vY2tlZERyaXZlclJldHVybmVyQ2xhc3MgPSBmdW5jdGlvbiBEcml2ZXIgKCkge1xuICAgICAgICByZXR1cm4gZmFrZURyaXZlcjtcbiAgICAgIH07XG5cbiAgICAgIGFwcGl1bS5fZmluZE1hdGNoaW5nRHJpdmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgIGRyaXZlcjogbW9ja2VkRHJpdmVyUmV0dXJuZXJDbGFzcyxcbiAgICAgICAgICB2ZXJzaW9uOiAnMS4yLjMnLFxuICAgICAgICAgIGRyaXZlck5hbWU6ICdmYWtlJyxcbiAgICAgICAgfTtcbiAgICAgIH07XG4gICAgICByZXR1cm4gW2FwcGl1bSwgbW9ja0Zha2VEcml2ZXJdO1xuICAgIH1cbiAgICBkZXNjcmliZSgnY3JlYXRlU2Vzc2lvbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBhcHBpdW07XG4gICAgICBsZXQgbW9ja0Zha2VEcml2ZXI7XG4gICAgICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgW2FwcGl1bSwgbW9ja0Zha2VEcml2ZXJdID0gZ2V0RHJpdmVyQW5kRmFrZURyaXZlcigpO1xuICAgICAgfSk7XG4gICAgICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBtb2NrRmFrZURyaXZlci5yZXN0b3JlKCk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5kZWxldGVTZXNzaW9uKFNFU1NJT05fSUQpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KGBzaG91bGQgY2FsbCBpbm5lciBkcml2ZXIncyBjcmVhdGVTZXNzaW9uIHdpdGggZGVzaXJlZCBjYXBhYmlsaXRpZXNgLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCkud2l0aEV4YWN0QXJncyhudWxsLCBudWxsLCBXM0NfQ0FQUywgW10pXG4gICAgICAgICAgLnJldHVybnMoW1NFU1NJT05fSUQsIHJlbW92ZUFwcGl1bVByZWZpeGVzKFczQ19QUkVGSVhFRF9DQVBTKV0pO1xuICAgICAgICBhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBXM0NfQ0FQUyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdChgc2hvdWxkIGNhbGwgaW5uZXIgZHJpdmVyJ3MgY3JlYXRlU2Vzc2lvbiB3aXRoIGRlc2lyZWQgYW5kIGRlZmF1bHQgY2FwYWJpbGl0aWVzYCwgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgZGVmYXVsdENhcHMgPSB7J2FwcGl1bTpzb21lQ2FwJzogJ2hlbGxvJ307XG4gICAgICAgIGxldCBhbGxDYXBzID0gey4uLlczQ19DQVBTLCBhbHdheXNNYXRjaDogey4uLlczQ19DQVBTLmFsd2F5c01hdGNoLCAuLi5kZWZhdWx0Q2Fwc319O1xuICAgICAgICBhcHBpdW0uYXJncy5kZWZhdWx0Q2FwYWJpbGl0aWVzID0gZGVmYXVsdENhcHM7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCkud2l0aEFyZ3MobnVsbCwgbnVsbCwgYWxsQ2FwcylcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoYWxsQ2Fwcy5hbHdheXNNYXRjaCldKTtcbiAgICAgICAgYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24obnVsbCwgbnVsbCwgVzNDX0NBUFMpO1xuICAgICAgICBtb2NrRmFrZURyaXZlci52ZXJpZnkoKTtcbiAgICAgIH0pO1xuICAgICAgaXQoYHNob3VsZCBjYWxsIGlubmVyIGRyaXZlcidzIGNyZWF0ZVNlc3Npb24gd2l0aCBkZXNpcmVkIGFuZCBkZWZhdWx0IGNhcGFiaWxpdGllcyB3aXRob3V0IG92ZXJyaWRpbmcgY2Fwc2AsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gYSBkZWZhdWx0IGNhcGFiaWxpdHkgd2l0aCB0aGUgc2FtZSBrZXkgYXMgYSBkZXNpcmVkIGNhcGFiaWxpdHlcbiAgICAgICAgLy8gc2hvdWxkIGRvIG5vdGhpbmdcbiAgICAgICAgbGV0IGRlZmF1bHRDYXBzID0ge3BsYXRmb3JtTmFtZTogJ0Vyc2F0eid9O1xuICAgICAgICBhcHBpdW0uYXJncy5kZWZhdWx0Q2FwYWJpbGl0aWVzID0gZGVmYXVsdENhcHM7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCkud2l0aEFyZ3MobnVsbCwgbnVsbCwgVzNDX0NBUFMpXG4gICAgICAgICAgLnJldHVybnMoW1NFU1NJT05fSUQsIHJlbW92ZUFwcGl1bVByZWZpeGVzKFczQ19QUkVGSVhFRF9DQVBTKV0pO1xuICAgICAgICBhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBXM0NfQ0FQUyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIGtpbGwgYWxsIG90aGVyIHNlc3Npb25zIGlmIHNlc3Npb25PdmVycmlkZSBpcyBvbicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXBwaXVtLmFyZ3Muc2Vzc2lvbk92ZXJyaWRlID0gdHJ1ZTtcblxuICAgICAgICAvLyBtb2NrIHRocmVlIHNlc3Npb25zIHRoYXQgc2hvdWxkIGJlIHJlbW92ZWQgd2hlbiB0aGUgbmV3IG9uZSBpcyBjcmVhdGVkXG4gICAgICAgIGxldCBmYWtlRHJpdmVycyA9IFtcbiAgICAgICAgICBuZXcgRmFrZURyaXZlcigpLFxuICAgICAgICAgIG5ldyBGYWtlRHJpdmVyKCksXG4gICAgICAgICAgbmV3IEZha2VEcml2ZXIoKSxcbiAgICAgICAgXTtcbiAgICAgICAgbGV0IG1vY2tGYWtlRHJpdmVycyA9IF8ubWFwKGZha2VEcml2ZXJzLCAoZmQpID0+IHNpbm9uLm1vY2soZmQpKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXJzWzBdLmV4cGVjdHMoJ2RlbGV0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyc1sxXS5leHBlY3RzKCdkZWxldGVTZXNzaW9uJylcbiAgICAgICAgICAub25jZSgpXG4gICAgICAgICAgLnRocm93cygnQ2Fubm90IHNodXQgZG93biBBbmRyb2lkIGRyaXZlcjsgaXQgaGFzIGFscmVhZHkgc2h1dCBkb3duJyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyc1syXS5leHBlY3RzKCdkZWxldGVTZXNzaW9uJylcbiAgICAgICAgICAub25jZSgpO1xuICAgICAgICBhcHBpdW0uc2Vzc2lvbnNbJ2FiYy0xMjMteHl6J10gPSBmYWtlRHJpdmVyc1swXTtcbiAgICAgICAgYXBwaXVtLnNlc3Npb25zWyd4eXotMzIxLWFiYyddID0gZmFrZURyaXZlcnNbMV07XG4gICAgICAgIGFwcGl1bS5zZXNzaW9uc1snMTIzLWFiYy14eXonXSA9IGZha2VEcml2ZXJzWzJdO1xuXG4gICAgICAgIGxldCBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuaGF2ZS5sZW5ndGgoMyk7XG5cbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoRXhhY3RBcmdzKG51bGwsIG51bGwsIFczQ19DQVBTLCBbXSlcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoVzNDX1BSRUZJWEVEX0NBUFMpXSk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIFczQ19DQVBTKTtcblxuICAgICAgICBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuaGF2ZS5sZW5ndGgoMSk7XG5cbiAgICAgICAgZm9yIChsZXQgbWZkIG9mIG1vY2tGYWtlRHJpdmVycykge1xuICAgICAgICAgIG1mZC52ZXJpZnkoKTtcbiAgICAgICAgfVxuICAgICAgICBtb2NrRmFrZURyaXZlci52ZXJpZnkoKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCBjYWxsIFwiY3JlYXRlU2Vzc2lvblwiIHdpdGggVzNDIGNhcGFiaWxpdGllcyBhcmd1bWVudCwgaWYgcHJvdmlkZWQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCkud2l0aEFyZ3MobnVsbCwgdW5kZWZpbmVkLCBXM0NfQ0FQUylcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgQkFTRV9DQVBTXSk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBXM0NfQ0FQUyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIGNhbGwgXCJjcmVhdGVTZXNzaW9uXCIgd2l0aCBXM0MgY2FwYWJpbGl0aWVzIGFyZ3VtZW50IHdpdGggYWRkaXRpb25hbCBwcm92aWRlZCBwYXJhbWV0ZXJzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgdzNjQ2FwcyA9IHtcbiAgICAgICAgICAuLi5XM0NfQ0FQUyxcbiAgICAgICAgICBhbHdheXNNYXRjaDoge1xuICAgICAgICAgICAgLi4uVzNDX0NBUFMuYWx3YXlzTWF0Y2gsXG4gICAgICAgICAgICAnYXBwaXVtOnNvbWVPdGhlclBhcm0nOiAnc29tZU90aGVyUGFybScsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoQXJncyhudWxsLCB1bmRlZmluZWQsIHtcbiAgICAgICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgICAgIC4uLnczY0NhcHMuYWx3YXlzTWF0Y2gsXG4gICAgICAgICAgICAgICdhcHBpdW06c29tZU90aGVyUGFybSc6ICdzb21lT3RoZXJQYXJtJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmaXJzdE1hdGNoOiBbe31dLFxuICAgICAgICAgIH0pXG4gICAgICAgICAgLnJldHVybnMoW1NFU1NJT05fSUQsIGluc2VydEFwcGl1bVByZWZpeGVzKEJBU0VfQ0FQUyldKTtcblxuICAgICAgICBhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbih1bmRlZmluZWQsIHVuZGVmaW5lZCwgdzNjQ2Fwcyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIG5vdCBjYWxsIFwiY3JlYXRlU2Vzc2lvblwiIHdpdGggSlNPTldQIGNhcGFiaWxpdGllcyBpZiBXM0MgaGFzIGluY29tcGxldGUgY2FwYWJpbGl0aWVzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCB3M2NDYXBzID0ge1xuICAgICAgICAgIC4uLlczQ19DQVBTLFxuICAgICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgICAnYXBwaXVtOnNvbWVPdGhlclBhcm0nOiAnc29tZU90aGVyUGFybScsXG4gICAgICAgICAgfSxcbiAgICAgICAgfTtcblxuICAgICAgICBjb25zdCBqc29ud3BDYXBzID0ge1xuICAgICAgICAgIC4uLkJBU0VfQ0FQUyxcbiAgICAgICAgICBhdXRvbWF0aW9uTmFtZTogJ0Zha2UnLFxuICAgICAgICAgIHNvbWVPdGhlclBhcmFtOiAnc29tZU90aGVyUGFyYW0nLFxuICAgICAgICB9O1xuXG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKS5uZXZlcigpO1xuICAgICAgICBhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihqc29ud3BDYXBzLCB1bmRlZmluZWQsIHczY0NhcHMpO1xuICAgICAgICBtb2NrRmFrZURyaXZlci52ZXJpZnkoKTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIGFzc2lnbiBhcmdzIHRvIHByb3BlcnR5IGBjbGlBcmdzYCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY2xhc3MgQXJnc0RyaXZlciBleHRlbmRzIEJhc2VEcml2ZXIge1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFyZ3MgPSB7ZHJpdmVyOiB7ZmFrZToge3JhbmRvbUFyZzogMTIzNH19fTtcbiAgICAgICAgW2FwcGl1bSwgbW9ja0Zha2VEcml2ZXJdID0gZ2V0RHJpdmVyQW5kRmFrZURyaXZlcihhcmdzLCBBcmdzRHJpdmVyKTtcbiAgICAgICAgY29uc3Qge3ZhbHVlfSA9IGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBXM0NfQ0FQUyk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgbW9ja0Zha2VEcml2ZXIuX2Zha2VEcml2ZXIuY2xpQXJncy5zaG91bGQuZXFsKHtyYW5kb21Bcmc6IDEyMzR9KTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICBhd2FpdCBhcHBpdW0uZGVsZXRlU2Vzc2lvbih2YWx1ZVswXSk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGRlc2NyaWJlKCdkZWxldGVTZXNzaW9uJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGFwcGl1bTtcbiAgICAgIGxldCBtb2NrRmFrZURyaXZlcjtcbiAgICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBbYXBwaXVtLCBtb2NrRmFrZURyaXZlcl0gPSBnZXREcml2ZXJBbmRGYWtlRHJpdmVyKCk7XG4gICAgICB9KTtcbiAgICAgIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnJlc3RvcmUoKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCByZW1vdmUgdGhlIHNlc3Npb24gaWYgaXQgaXMgZm91bmQnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCBbc2Vzc2lvbklkXSA9IChhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBXM0NfQ0FQUykpLnZhbHVlO1xuICAgICAgICBsZXQgc2Vzc2lvbnMgPSBhd2FpdCBhcHBpdW0uZ2V0U2Vzc2lvbnMoKTtcbiAgICAgICAgc2Vzc2lvbnMuc2hvdWxkLmhhdmUubGVuZ3RoKDEpO1xuICAgICAgICBhd2FpdCBhcHBpdW0uZGVsZXRlU2Vzc2lvbihzZXNzaW9uSWQpO1xuICAgICAgICBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuaGF2ZS5sZW5ndGgoMCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgY2FsbCBpbm5lciBkcml2ZXJcXCdzIGRlbGV0ZVNlc3Npb24gbWV0aG9kJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBbc2Vzc2lvbklkXSA9IChhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBXM0NfQ0FQUykpLnZhbHVlO1xuICAgICAgICBtb2NrRmFrZURyaXZlci5leHBlY3RzKCdkZWxldGVTZXNzaW9uJylcbiAgICAgICAgICAub25jZSgpLndpdGhFeGFjdEFyZ3Moc2Vzc2lvbklkLCBbXSlcbiAgICAgICAgICAucmV0dXJucygpO1xuICAgICAgICBhd2FpdCBhcHBpdW0uZGVsZXRlU2Vzc2lvbihzZXNzaW9uSWQpO1xuICAgICAgICBtb2NrRmFrZURyaXZlci52ZXJpZnkoKTtcblxuICAgICAgICAvLyBjbGVhbnVwLCBzaW5jZSB3ZSBmYWtlZCB0aGUgZGVsZXRlIHNlc3Npb24gY2FsbFxuICAgICAgICBhd2FpdCBtb2NrRmFrZURyaXZlci5vYmplY3QuZGVsZXRlU2Vzc2lvbigpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gICAgZGVzY3JpYmUoJ2dldFNlc3Npb25zJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGFwcGl1bSwgbW9ja0Zha2VEcml2ZXI7XG4gICAgICBsZXQgc2Vzc2lvbnM7XG4gICAgICBiZWZvcmUoZnVuY3Rpb24gKCkge1xuICAgICAgICBbYXBwaXVtLCBtb2NrRmFrZURyaXZlcl0gPSBnZXREcml2ZXJBbmRGYWtlRHJpdmVyKCk7XG4gICAgICB9KTtcbiAgICAgIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGZvciAobGV0IHNlc3Npb24gb2Ygc2Vzc2lvbnMpIHtcbiAgICAgICAgICBhd2FpdCBhcHBpdW0uZGVsZXRlU2Vzc2lvbihzZXNzaW9uLmlkKTtcbiAgICAgICAgfVxuICAgICAgICBtb2NrRmFrZURyaXZlci5yZXN0b3JlKCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIGFuIGVtcHR5IGFycmF5IG9mIHNlc3Npb25zJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuYmUuYW4oJ2FycmF5Jyk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5iZS5lbXB0eTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gc2Vzc2lvbnMgY3JlYXRlZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbGV0IGNhcHMxID0ge2Fsd2F5c01hdGNoOiB7Li4uVzNDX1BSRUZJWEVEX0NBUFMsICdhcHBpdW06Y2FwJzogJ3ZhbHVlJ319O1xuICAgICAgICBsZXQgY2FwczIgPSB7YWx3YXlzTWF0Y2g6IHsuLi5XM0NfUFJFRklYRURfQ0FQUywgJ2FwcGl1bTpjYXAnOiAnb3RoZXIgdmFsdWUnfX07XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKS5vbmNlKClcbiAgICAgICAgICAucmV0dXJucyhbJ2Zha2Utc2Vzc2lvbi1pZC0xJywgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoY2FwczEuYWx3YXlzTWF0Y2gpXSk7XG4gICAgICAgIGxldCBbc2Vzc2lvbjFJZCwgc2Vzc2lvbjFDYXBzXSA9IChhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBjYXBzMSkpLnZhbHVlO1xuICAgICAgICBtb2NrRmFrZURyaXZlci5leHBlY3RzKCdjcmVhdGVTZXNzaW9uJykub25jZSgpXG4gICAgICAgICAgLnJldHVybnMoWydmYWtlLXNlc3Npb24taWQtMicsIHJlbW92ZUFwcGl1bVByZWZpeGVzKGNhcHMyLmFsd2F5c01hdGNoKV0pO1xuICAgICAgICBsZXQgW3Nlc3Npb24ySWQsIHNlc3Npb24yQ2Fwc10gPSAoYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24obnVsbCwgbnVsbCwgY2FwczIpKS52YWx1ZTtcblxuICAgICAgICBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuYmUuYW4oJ2FycmF5Jyk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5oYXZlLmxlbmd0aCgyKTtcbiAgICAgICAgc2Vzc2lvbnNbMF0uaWQuc2hvdWxkLmVxdWFsKHNlc3Npb24xSWQpO1xuICAgICAgICByZW1vdmVBcHBpdW1QcmVmaXhlcyhjYXBzMS5hbHdheXNNYXRjaCkuc2hvdWxkLmVxbChzZXNzaW9uMUNhcHMpO1xuICAgICAgICBzZXNzaW9uc1sxXS5pZC5zaG91bGQuZXF1YWwoc2Vzc2lvbjJJZCk7XG4gICAgICAgIHJlbW92ZUFwcGl1bVByZWZpeGVzKGNhcHMyLmFsd2F5c01hdGNoKS5zaG91bGQuZXFsKHNlc3Npb24yQ2Fwcyk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnZ2V0U3RhdHVzJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGFwcGl1bTtcbiAgICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIGFwcGl1bSA9IG5ldyBBcHBpdW1Ecml2ZXIoe30pO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIHJldHVybiBhIHN0YXR1cycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbGV0IHN0YXR1cyA9IGF3YWl0IGFwcGl1bS5nZXRTdGF0dXMoKTtcbiAgICAgICAgc3RhdHVzLmJ1aWxkLnNob3VsZC5leGlzdDtcbiAgICAgICAgc3RhdHVzLmJ1aWxkLnZlcnNpb24uc2hvdWxkLmV4aXN0O1xuICAgICAgfSk7XG4gICAgfSk7XG4gICAgZGVzY3JpYmUoJ3Nlc3Npb25FeGlzdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgfSk7XG4gICAgZGVzY3JpYmUoJ2F0dGFjaFVuZXhwZWN0ZWRTaHV0ZG93bkhhbmRsZXInLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgYXBwaXVtO1xuICAgICAgbGV0IG1vY2tGYWtlRHJpdmVyO1xuICAgICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIFthcHBpdW0sIG1vY2tGYWtlRHJpdmVyXSA9IGdldERyaXZlckFuZEZha2VEcml2ZXIoKTtcbiAgICAgIH0pO1xuICAgICAgYWZ0ZXJFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXdhaXQgbW9ja0Zha2VEcml2ZXIub2JqZWN0LmRlbGV0ZVNlc3Npb24oKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIucmVzdG9yZSgpO1xuICAgICAgICBhcHBpdW0uYXJncy5kZWZhdWx0Q2FwYWJpbGl0aWVzID0ge307XG4gICAgICB9KTtcblxuICAgICAgaXQoJ3Nob3VsZCByZW1vdmUgc2Vzc2lvbiBpZiBpbm5lciBkcml2ZXIgdW5leHBlY3RlZGx5IGV4aXRzIHdpdGggYW4gZXJyb3InLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCBbc2Vzc2lvbklkLF0gPSAoYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24obnVsbCwgbnVsbCwgXy5jbG9uZShXM0NfQ0FQUykpKS52YWx1ZTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBjb21tYS1zcGFjaW5nXG4gICAgICAgIF8ua2V5cyhhcHBpdW0uc2Vzc2lvbnMpLnNob3VsZC5jb250YWluKHNlc3Npb25JZCk7XG4gICAgICAgIGFwcGl1bS5zZXNzaW9uc1tzZXNzaW9uSWRdLmV2ZW50RW1pdHRlci5lbWl0KCdvblVuZXhwZWN0ZWRTaHV0ZG93bicsIG5ldyBFcnJvcignT29wcycpKTtcbiAgICAgICAgLy8gbGV0IGV2ZW50IGxvb3Agc3BpbiBzbyByZWplY3Rpb24gaXMgaGFuZGxlZFxuICAgICAgICBhd2FpdCBzbGVlcCgxKTtcbiAgICAgICAgXy5rZXlzKGFwcGl1bS5zZXNzaW9ucykuc2hvdWxkLm5vdC5jb250YWluKHNlc3Npb25JZCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgcmVtb3ZlIHNlc3Npb24gaWYgaW5uZXIgZHJpdmVyIHVuZXhwZWN0ZWRseSBleGl0cyB3aXRoIG5vIGVycm9yJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgW3Nlc3Npb25JZCxdID0gKGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIF8uY2xvbmUoVzNDX0NBUFMpKSkudmFsdWU7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgY29tbWEtc3BhY2luZ1xuICAgICAgICBfLmtleXMoYXBwaXVtLnNlc3Npb25zKS5zaG91bGQuY29udGFpbihzZXNzaW9uSWQpO1xuICAgICAgICBhcHBpdW0uc2Vzc2lvbnNbc2Vzc2lvbklkXS5ldmVudEVtaXR0ZXIuZW1pdCgnb25VbmV4cGVjdGVkU2h1dGRvd24nKTtcbiAgICAgICAgLy8gbGV0IGV2ZW50IGxvb3Agc3BpbiBzbyByZWplY3Rpb24gaXMgaGFuZGxlZFxuICAgICAgICBhd2FpdCBzbGVlcCgxKTtcbiAgICAgICAgXy5rZXlzKGFwcGl1bS5zZXNzaW9ucykuc2hvdWxkLm5vdC5jb250YWluKHNlc3Npb25JZCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnY3JlYXRlUGx1Z2luSW5zdGFuY2VzJywgZnVuY3Rpb24gKCkge1xuICAgICAgY2xhc3MgTm9BcmdzUGx1Z2luIHt9XG4gICAgICBOb0FyZ3NQbHVnaW4ucGx1Z2luTmFtZSA9ICdub2FyZ3MnO1xuXG4gICAgICBjbGFzcyBBcmdzUGx1Z2luIHt9XG4gICAgICBBcmdzUGx1Z2luLnBsdWdpbk5hbWUgPSAnYXJncyc7XG5cbiAgICAgIGNsYXNzIEFycmF5QXJnUGx1Z2luIHt9XG4gICAgICBBcnJheUFyZ1BsdWdpbi5wbHVnaW5OYW1lID0gJ2FycmF5YXJnJztcblxuICAgICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJlc2V0U2NoZW1hKCk7XG4gICAgICAgIC8vIHRvIGVzdGFibGlzaCBkZWZhdWx0cywgd2UgbmVlZCB0byByZWdpc3RlciBhIHNjaGVtYSBmb3IgdGhlIHBsdWdpbi5cbiAgICAgICAgLy8gbm90ZSB0aGF0IHRoZSBgbm9hcmdzYCBwbHVnaW4gZG9lcyBub3QgbmVlZCBhIHNjaGVtYSwgYmVjYXVzZSBpdFxuICAgICAgICAvLyBhY2NlcHRzIG5vIGFyZ3VtZW50cy5cbiAgICAgICAgcmVnaXN0ZXJTY2hlbWEoJ3BsdWdpbicsIEFyZ3NQbHVnaW4ucGx1Z2luTmFtZSwge1xuICAgICAgICAgIHR5cGU6ICdvYmplY3QnLFxuICAgICAgICAgIHByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIHJhbmRvbUFyZzoge1xuICAgICAgICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgICAgICAgZGVmYXVsdDogMjAwMFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJlZ2lzdGVyU2NoZW1hKCdwbHVnaW4nLCBBcnJheUFyZ1BsdWdpbi5wbHVnaW5OYW1lLCB7XG4gICAgICAgICAgdHlwZTogJ29iamVjdCcsXG4gICAgICAgICAgcHJvcGVydGllczoge1xuICAgICAgICAgICAgYXJyOiB7XG4gICAgICAgICAgICAgIHR5cGU6ICdhcnJheScsXG4gICAgICAgICAgICAgIGRlZmF1bHQ6IFtdXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgZmluYWxpemVTY2hlbWEoKTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnd2hlbiBhcmdzIGFyZSBub3QgcHJlc2VudCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBub3Qgc2V0IENMSSBhcmdzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGFwcGl1bSA9IG5ldyBBcHBpdW1Ecml2ZXIoe30pO1xuICAgICAgICAgIGFwcGl1bS5wbHVnaW5DbGFzc2VzID0gW05vQXJnc1BsdWdpbiwgQXJnc1BsdWdpbl07XG4gICAgICAgICAgZm9yIChjb25zdCBwbHVnaW4gb2YgYXBwaXVtLmNyZWF0ZVBsdWdpbkluc3RhbmNlcygpKSB7XG4gICAgICAgICAgICBzaG91bGQubm90LmV4aXN0KHBsdWdpbi5jbGlBcmdzKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIGFyZ3MgYXJlIGVxdWFsIHRvIHRoZSBzY2hlbWEgZGVmYXVsdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgbm90IHNldCBDTEkgYXJncycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBjb25zdCBhcHBpdW0gPSBuZXcgQXBwaXVtRHJpdmVyKHtwbHVnaW46IHtbQXJnc1BsdWdpbi5wbHVnaW5OYW1lXToge3JhbmRvbUFyZzogMjAwMH19fSk7XG4gICAgICAgICAgYXBwaXVtLnBsdWdpbkNsYXNzZXMgPSBbTm9BcmdzUGx1Z2luLCBBcmdzUGx1Z2luXTtcbiAgICAgICAgICBmb3IgKGNvbnN0IHBsdWdpbiBvZiBhcHBpdW0uY3JlYXRlUGx1Z2luSW5zdGFuY2VzKCkpIHtcbiAgICAgICAgICAgIHNob3VsZC5ub3QuZXhpc3QocGx1Z2luLmNsaUFyZ3MpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgZGVzY3JpYmUoJ3doZW4gdGhlIGRlZmF1bHQgaXMgYW4gXCJvYmplY3RcIicsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpdCgnc2hvdWxkIG5vdCBzZXQgQ0xJIGFyZ3MnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjb25zdCBhcHBpdW0gPSBuZXcgQXBwaXVtRHJpdmVyKHtwbHVnaW46IHtbQXJyYXlBcmdQbHVnaW4ucGx1Z2luTmFtZV06IHthcnI6IFtdfX19KTtcbiAgICAgICAgICAgIGFwcGl1bS5wbHVnaW5DbGFzc2VzID0gW05vQXJnc1BsdWdpbiwgQXJnc1BsdWdpbiwgQXJyYXlBcmdQbHVnaW5dO1xuICAgICAgICAgICAgZm9yIChjb25zdCBwbHVnaW4gb2YgYXBwaXVtLmNyZWF0ZVBsdWdpbkluc3RhbmNlcygpKSB7XG4gICAgICAgICAgICAgIHNob3VsZC5ub3QuZXhpc3QocGx1Z2luLmNsaUFyZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnd2hlbiBhcmdzIGFyZSBub3QgZXF1YWwgdG8gdGhlIHNjaGVtYSBkZWZhdWx0cycsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBhZGQgY2xpQXJncyB0byB0aGUgcGx1Z2luJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGNvbnN0IGFwcGl1bSA9IG5ldyBBcHBpdW1Ecml2ZXIoe3BsdWdpbjoge2FyZ3M6IHtyYW5kb21Bcmc6IDEyMzR9fX0pO1xuICAgICAgICAgIGFwcGl1bS5wbHVnaW5DbGFzc2VzID0gW0FyZ3NQbHVnaW5dO1xuICAgICAgICAgIGNvbnN0IHBsdWdpbiA9IF8uZmlyc3QoYXBwaXVtLmNyZWF0ZVBsdWdpbkluc3RhbmNlcygpKTtcbiAgICAgICAgICBwbHVnaW4uY2xpQXJncy5zaG91bGQuZXFsKHtyYW5kb21Bcmc6IDEyMzR9KTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG59KTtcbiJdLCJmaWxlIjoidGVzdC9kcml2ZXItc3BlY3MuanMiLCJzb3VyY2VSb290IjoiLi4vLi4ifQ==