appium 2.0.0-beta.2 → 2.0.0-beta.23

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 (122) hide show
  1. package/README.md +9 -9
  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-config.schema.json +0 -0
  7. package/build/lib/appium.js +160 -53
  8. package/build/lib/cli/args.js +115 -279
  9. package/build/lib/cli/driver-command.js +11 -1
  10. package/build/lib/cli/extension-command.js +60 -8
  11. package/build/lib/cli/extension.js +30 -7
  12. package/build/lib/cli/npm.js +43 -29
  13. package/build/lib/cli/parser.js +156 -89
  14. package/build/lib/cli/plugin-command.js +11 -1
  15. package/build/lib/cli/utils.js +29 -3
  16. package/build/lib/config-file.js +141 -0
  17. package/build/lib/config.js +53 -65
  18. package/build/lib/driver-config.js +42 -19
  19. package/build/lib/drivers.js +8 -4
  20. package/build/lib/ext-config-io.js +165 -0
  21. package/build/lib/extension-config.js +130 -61
  22. package/build/lib/grid-register.js +22 -24
  23. package/build/lib/logger.js +3 -3
  24. package/build/lib/logsink.js +11 -13
  25. package/build/lib/main.js +197 -77
  26. package/build/lib/plugin-config.js +21 -11
  27. package/build/lib/plugins.js +4 -2
  28. package/build/lib/schema/appium-config-schema.js +253 -0
  29. package/build/lib/schema/arg-spec.js +120 -0
  30. package/build/lib/schema/cli-args.js +188 -0
  31. package/build/lib/schema/cli-transformers.js +76 -0
  32. package/build/lib/schema/index.js +36 -0
  33. package/build/lib/schema/keywords.js +72 -0
  34. package/build/lib/schema/schema.js +357 -0
  35. package/build/lib/utils.js +44 -99
  36. package/build/postinstall.js +90 -0
  37. package/build/test/cli/cli-e2e-specs.js +221 -0
  38. package/build/test/cli/cli-helpers.js +86 -0
  39. package/build/test/cli/cli-specs.js +71 -0
  40. package/build/test/cli/fixtures/test-driver/package.json +27 -0
  41. package/build/test/cli/schema-args-specs.js +48 -0
  42. package/build/test/cli/schema-e2e-specs.js +47 -0
  43. package/build/test/config-e2e-specs.js +112 -0
  44. package/build/test/config-file-e2e-specs.js +209 -0
  45. package/build/test/config-file-specs.js +281 -0
  46. package/build/test/config-specs.js +159 -0
  47. package/build/test/driver-e2e-specs.js +435 -0
  48. package/build/test/driver-specs.js +321 -0
  49. package/build/test/ext-config-io-specs.js +181 -0
  50. package/build/test/extension-config-specs.js +365 -0
  51. package/build/test/fixtures/allow-feat.txt +5 -0
  52. package/build/test/fixtures/caps.json +3 -0
  53. package/build/test/fixtures/config/allow-insecure.txt +3 -0
  54. package/build/test/fixtures/config/appium.config.bad-nodeconfig.json +5 -0
  55. package/build/test/fixtures/config/appium.config.bad.json +32 -0
  56. package/build/test/fixtures/config/appium.config.ext-good.json +9 -0
  57. package/build/test/fixtures/config/appium.config.ext-unknown-props.json +10 -0
  58. package/build/test/fixtures/config/appium.config.good.js +40 -0
  59. package/build/test/fixtures/config/appium.config.good.json +33 -0
  60. package/build/test/fixtures/config/appium.config.good.yaml +30 -0
  61. package/build/test/fixtures/config/appium.config.invalid.json +31 -0
  62. package/build/test/fixtures/config/appium.config.security-array.json +5 -0
  63. package/build/test/fixtures/config/appium.config.security-delimited.json +5 -0
  64. package/build/test/fixtures/config/appium.config.security-path.json +5 -0
  65. package/build/test/fixtures/config/driver-fake.config.json +8 -0
  66. package/build/test/fixtures/config/nodeconfig.json +3 -0
  67. package/build/test/fixtures/config/plugin-fake.config.json +0 -0
  68. package/build/test/fixtures/default-args.js +35 -0
  69. package/build/test/fixtures/deny-feat.txt +5 -0
  70. package/build/test/fixtures/driver.schema.js +20 -0
  71. package/build/test/fixtures/extensions.yaml +27 -0
  72. package/build/test/fixtures/flattened-schema.js +504 -0
  73. package/build/test/fixtures/plugin.schema.js +20 -0
  74. package/build/test/fixtures/schema-with-extensions.js +28 -0
  75. package/build/test/grid-register-specs.js +74 -0
  76. package/build/test/helpers.js +75 -0
  77. package/build/test/logger-specs.js +76 -0
  78. package/build/test/npm-specs.js +20 -0
  79. package/build/test/parser-specs.js +314 -0
  80. package/build/test/plugin-e2e-specs.js +316 -0
  81. package/build/test/schema/arg-spec-specs.js +70 -0
  82. package/build/test/schema/cli-args-specs.js +431 -0
  83. package/build/test/schema/schema-specs.js +389 -0
  84. package/build/test/utils-specs.js +266 -0
  85. package/index.js +11 -0
  86. package/lib/appium-config.schema.json +278 -0
  87. package/lib/appium.js +207 -65
  88. package/lib/cli/args.js +174 -375
  89. package/lib/cli/driver-command.js +4 -0
  90. package/lib/cli/extension-command.js +70 -5
  91. package/lib/cli/extension.js +25 -5
  92. package/lib/cli/npm.js +86 -18
  93. package/lib/cli/parser.js +257 -79
  94. package/lib/cli/plugin-command.js +4 -0
  95. package/lib/cli/utils.js +21 -1
  96. package/lib/config-file.js +227 -0
  97. package/lib/config.js +84 -63
  98. package/lib/driver-config.js +66 -11
  99. package/lib/drivers.js +4 -1
  100. package/lib/ext-config-io.js +287 -0
  101. package/lib/extension-config.js +225 -67
  102. package/lib/grid-register.js +27 -24
  103. package/lib/logger.js +1 -1
  104. package/lib/logsink.js +10 -7
  105. package/lib/main.js +214 -77
  106. package/lib/plugin-config.js +35 -6
  107. package/lib/plugins.js +1 -0
  108. package/lib/schema/appium-config-schema.js +287 -0
  109. package/lib/schema/arg-spec.js +222 -0
  110. package/lib/schema/cli-args.js +285 -0
  111. package/lib/schema/cli-transformers.js +123 -0
  112. package/lib/schema/index.js +2 -0
  113. package/lib/schema/keywords.js +135 -0
  114. package/lib/schema/schema.js +577 -0
  115. package/lib/utils.js +42 -88
  116. package/package.json +55 -84
  117. package/postinstall.js +71 -0
  118. package/types/appium-config.d.ts +197 -0
  119. package/types/types.d.ts +201 -0
  120. package/CHANGELOG.md +0 -3515
  121. package/build/lib/cli/parser-helpers.js +0 -82
  122. package/lib/cli/parser-helpers.js +0 -79
@@ -0,0 +1,321 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _appium = require("../lib/appium");
8
+
9
+ var _baseDriver = require("@appium/base-driver");
10
+
11
+ var _fakeDriver = require("@appium/fake-driver");
12
+
13
+ var _helpers = require("./helpers");
14
+
15
+ var _schema = require("../lib/schema/schema");
16
+
17
+ var _lodash = _interopRequireDefault(require("lodash"));
18
+
19
+ var _sinon = _interopRequireDefault(require("sinon"));
20
+
21
+ var _asyncbox = require("asyncbox");
22
+
23
+ var _utils = require("../lib/utils");
24
+
25
+ const SESSION_ID = 1;
26
+ describe('AppiumDriver', function () {
27
+ beforeEach(function () {
28
+ (0, _schema.resetSchema)();
29
+ });
30
+ describe('AppiumDriver', function () {
31
+ function getDriverAndFakeDriver(appiumArgs = {}, DriverClass = _fakeDriver.FakeDriver) {
32
+ const appium = new _appium.AppiumDriver(appiumArgs);
33
+ const fakeDriver = new DriverClass();
34
+
35
+ const mockFakeDriver = _sinon.default.mock(fakeDriver);
36
+
37
+ mockFakeDriver._fakeDriver = fakeDriver;
38
+
39
+ const mockedDriverReturnerClass = function Driver() {
40
+ return fakeDriver;
41
+ };
42
+
43
+ appium._findMatchingDriver = function () {
44
+ return {
45
+ driver: mockedDriverReturnerClass,
46
+ version: '1.2.3',
47
+ driverName: 'fake'
48
+ };
49
+ };
50
+
51
+ return [appium, mockFakeDriver];
52
+ }
53
+
54
+ describe('createSession', function () {
55
+ let appium;
56
+ let mockFakeDriver;
57
+ beforeEach(function () {
58
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
59
+ });
60
+ afterEach(async function () {
61
+ mockFakeDriver.restore();
62
+ await appium.deleteSession(SESSION_ID);
63
+ });
64
+ it(`should call inner driver's createSession with desired capabilities`, async function () {
65
+ mockFakeDriver.expects('createSession').once().withExactArgs(null, null, _helpers.W3C_CAPS, []).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
66
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
67
+ mockFakeDriver.verify();
68
+ });
69
+ it(`should call inner driver's createSession with desired and default capabilities`, async function () {
70
+ let defaultCaps = {
71
+ 'appium:someCap': 'hello'
72
+ };
73
+ let allCaps = { ..._helpers.W3C_CAPS,
74
+ alwaysMatch: { ..._helpers.W3C_CAPS.alwaysMatch,
75
+ ...defaultCaps
76
+ }
77
+ };
78
+ appium.args.defaultCapabilities = defaultCaps;
79
+ mockFakeDriver.expects('createSession').once().withArgs(null, null, allCaps).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(allCaps.alwaysMatch)]);
80
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
81
+ mockFakeDriver.verify();
82
+ });
83
+ it(`should call inner driver's createSession with desired and default capabilities without overriding caps`, async function () {
84
+ let defaultCaps = {
85
+ platformName: 'Ersatz'
86
+ };
87
+ appium.args.defaultCapabilities = defaultCaps;
88
+ mockFakeDriver.expects('createSession').once().withArgs(null, null, _helpers.W3C_CAPS).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
89
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
90
+ mockFakeDriver.verify();
91
+ });
92
+ it('should kill all other sessions if sessionOverride is on', async function () {
93
+ appium.args.sessionOverride = true;
94
+ let fakeDrivers = [new _fakeDriver.FakeDriver(), new _fakeDriver.FakeDriver(), new _fakeDriver.FakeDriver()];
95
+
96
+ let mockFakeDrivers = _lodash.default.map(fakeDrivers, fd => _sinon.default.mock(fd));
97
+
98
+ mockFakeDrivers[0].expects('deleteSession').once();
99
+ mockFakeDrivers[1].expects('deleteSession').once().throws('Cannot shut down Android driver; it has already shut down');
100
+ mockFakeDrivers[2].expects('deleteSession').once();
101
+ appium.sessions['abc-123-xyz'] = fakeDrivers[0];
102
+ appium.sessions['xyz-321-abc'] = fakeDrivers[1];
103
+ appium.sessions['123-abc-xyz'] = fakeDrivers[2];
104
+ let sessions = await appium.getSessions();
105
+ sessions.should.have.length(3);
106
+ mockFakeDriver.expects('createSession').once().withExactArgs(null, null, _helpers.W3C_CAPS, []).returns([SESSION_ID, (0, _utils.removeAppiumPrefixes)(_helpers.W3C_PREFIXED_CAPS)]);
107
+ await appium.createSession(null, null, _helpers.W3C_CAPS);
108
+ sessions = await appium.getSessions();
109
+ sessions.should.have.length(1);
110
+
111
+ for (let mfd of mockFakeDrivers) {
112
+ mfd.verify();
113
+ }
114
+
115
+ mockFakeDriver.verify();
116
+ });
117
+ it('should call "createSession" with W3C capabilities argument, if provided', async function () {
118
+ mockFakeDriver.expects('createSession').once().withArgs(null, undefined, _helpers.W3C_CAPS).returns([SESSION_ID, _helpers.BASE_CAPS]);
119
+ await appium.createSession(undefined, undefined, _helpers.W3C_CAPS);
120
+ mockFakeDriver.verify();
121
+ });
122
+ it('should call "createSession" with W3C capabilities argument with additional provided parameters', async function () {
123
+ let w3cCaps = { ..._helpers.W3C_CAPS,
124
+ alwaysMatch: { ..._helpers.W3C_CAPS.alwaysMatch,
125
+ 'appium:someOtherParm': 'someOtherParm'
126
+ }
127
+ };
128
+ mockFakeDriver.expects('createSession').once().withArgs(null, undefined, {
129
+ alwaysMatch: { ...w3cCaps.alwaysMatch,
130
+ 'appium:someOtherParm': 'someOtherParm'
131
+ },
132
+ firstMatch: [{}]
133
+ }).returns([SESSION_ID, (0, _utils.insertAppiumPrefixes)(_helpers.BASE_CAPS)]);
134
+ await appium.createSession(undefined, undefined, w3cCaps);
135
+ mockFakeDriver.verify();
136
+ });
137
+ it('should not call "createSession" with JSONWP capabilities if W3C has incomplete capabilities', async function () {
138
+ const w3cCaps = { ..._helpers.W3C_CAPS,
139
+ alwaysMatch: {
140
+ 'appium:someOtherParm': 'someOtherParm'
141
+ }
142
+ };
143
+ const jsonwpCaps = { ..._helpers.BASE_CAPS,
144
+ automationName: 'Fake',
145
+ someOtherParam: 'someOtherParam'
146
+ };
147
+ mockFakeDriver.expects('createSession').never();
148
+ await appium.createSession(jsonwpCaps, undefined, w3cCaps);
149
+ mockFakeDriver.verify();
150
+ });
151
+ it('should assign args to property `cliArgs`', async function () {
152
+ class ArgsDriver extends _baseDriver.BaseDriver {}
153
+
154
+ const args = {
155
+ driver: {
156
+ fake: {
157
+ randomArg: 1234
158
+ }
159
+ }
160
+ };
161
+ [appium, mockFakeDriver] = getDriverAndFakeDriver(args, ArgsDriver);
162
+ const {
163
+ value
164
+ } = await appium.createSession(undefined, undefined, _helpers.W3C_CAPS);
165
+
166
+ try {
167
+ mockFakeDriver._fakeDriver.cliArgs.should.eql({
168
+ randomArg: 1234
169
+ });
170
+ } finally {
171
+ await appium.deleteSession(value[0]);
172
+ }
173
+ });
174
+ });
175
+ describe('deleteSession', function () {
176
+ let appium;
177
+ let mockFakeDriver;
178
+ beforeEach(function () {
179
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
180
+ });
181
+ afterEach(function () {
182
+ mockFakeDriver.restore();
183
+ });
184
+ it('should remove the session if it is found', async function () {
185
+ let [sessionId] = (await appium.createSession(null, null, _helpers.W3C_CAPS)).value;
186
+ let sessions = await appium.getSessions();
187
+ sessions.should.have.length(1);
188
+ await appium.deleteSession(sessionId);
189
+ sessions = await appium.getSessions();
190
+ sessions.should.have.length(0);
191
+ });
192
+ it('should call inner driver\'s deleteSession method', async function () {
193
+ const [sessionId] = (await appium.createSession(null, null, _helpers.W3C_CAPS)).value;
194
+ mockFakeDriver.expects('deleteSession').once().withExactArgs(sessionId, []).returns();
195
+ await appium.deleteSession(sessionId);
196
+ mockFakeDriver.verify();
197
+ await mockFakeDriver.object.deleteSession();
198
+ });
199
+ });
200
+ describe('getSessions', function () {
201
+ let appium, mockFakeDriver;
202
+ let sessions;
203
+ before(function () {
204
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
205
+ });
206
+ afterEach(async function () {
207
+ for (let session of sessions) {
208
+ await appium.deleteSession(session.id);
209
+ }
210
+
211
+ mockFakeDriver.restore();
212
+ });
213
+ it('should return an empty array of sessions', async function () {
214
+ sessions = await appium.getSessions();
215
+ sessions.should.be.an('array');
216
+ sessions.should.be.empty;
217
+ });
218
+ it('should return sessions created', async function () {
219
+ let caps1 = {
220
+ alwaysMatch: { ..._helpers.W3C_PREFIXED_CAPS,
221
+ 'appium:cap': 'value'
222
+ }
223
+ };
224
+ let caps2 = {
225
+ alwaysMatch: { ..._helpers.W3C_PREFIXED_CAPS,
226
+ 'appium:cap': 'other value'
227
+ }
228
+ };
229
+ mockFakeDriver.expects('createSession').once().returns(['fake-session-id-1', (0, _utils.removeAppiumPrefixes)(caps1.alwaysMatch)]);
230
+ let [session1Id, session1Caps] = (await appium.createSession(null, null, caps1)).value;
231
+ mockFakeDriver.expects('createSession').once().returns(['fake-session-id-2', (0, _utils.removeAppiumPrefixes)(caps2.alwaysMatch)]);
232
+ let [session2Id, session2Caps] = (await appium.createSession(null, null, caps2)).value;
233
+ sessions = await appium.getSessions();
234
+ sessions.should.be.an('array');
235
+ sessions.should.have.length(2);
236
+ sessions[0].id.should.equal(session1Id);
237
+ (0, _utils.removeAppiumPrefixes)(caps1.alwaysMatch).should.eql(session1Caps);
238
+ sessions[1].id.should.equal(session2Id);
239
+ (0, _utils.removeAppiumPrefixes)(caps2.alwaysMatch).should.eql(session2Caps);
240
+ });
241
+ });
242
+ describe('getStatus', function () {
243
+ let appium;
244
+ before(function () {
245
+ appium = new _appium.AppiumDriver({});
246
+ });
247
+ it('should return a status', async function () {
248
+ let status = await appium.getStatus();
249
+ status.build.should.exist;
250
+ status.build.version.should.exist;
251
+ });
252
+ });
253
+ describe('sessionExists', function () {});
254
+ describe('attachUnexpectedShutdownHandler', function () {
255
+ let appium;
256
+ let mockFakeDriver;
257
+ beforeEach(function () {
258
+ [appium, mockFakeDriver] = getDriverAndFakeDriver();
259
+ });
260
+ afterEach(async function () {
261
+ await mockFakeDriver.object.deleteSession();
262
+ mockFakeDriver.restore();
263
+ appium.args.defaultCapabilities = {};
264
+ });
265
+ it('should remove session if inner driver unexpectedly exits with an error', async function () {
266
+ let [sessionId] = (await appium.createSession(null, null, _lodash.default.clone(_helpers.W3C_CAPS))).value;
267
+
268
+ _lodash.default.keys(appium.sessions).should.contain(sessionId);
269
+
270
+ appium.sessions[sessionId].eventEmitter.emit('onUnexpectedShutdown', new Error('Oops'));
271
+ await (0, _asyncbox.sleep)(1);
272
+
273
+ _lodash.default.keys(appium.sessions).should.not.contain(sessionId);
274
+ });
275
+ it('should remove session if inner driver unexpectedly exits with no error', async function () {
276
+ let [sessionId] = (await appium.createSession(null, null, _lodash.default.clone(_helpers.W3C_CAPS))).value;
277
+
278
+ _lodash.default.keys(appium.sessions).should.contain(sessionId);
279
+
280
+ appium.sessions[sessionId].eventEmitter.emit('onUnexpectedShutdown');
281
+ await (0, _asyncbox.sleep)(1);
282
+
283
+ _lodash.default.keys(appium.sessions).should.not.contain(sessionId);
284
+ });
285
+ });
286
+ });
287
+ describe('#createPluginInstances', function () {
288
+ class NoArgsPlugin {}
289
+
290
+ NoArgsPlugin.pluginName = 'noargs';
291
+
292
+ class ArgsPlugin {}
293
+
294
+ ArgsPlugin.pluginName = 'args';
295
+ it('should not set CLI args if none are sent', function () {
296
+ const appium = new _appium.AppiumDriver({});
297
+ appium.pluginClasses = [NoArgsPlugin, ArgsPlugin];
298
+
299
+ for (const plugin of appium.createPluginInstances()) {
300
+ should.not.exist(plugin.cliArgs);
301
+ }
302
+ });
303
+ it('should add cliArgs to the plugin once validated', function () {
304
+ const appium = new _appium.AppiumDriver({
305
+ plugin: {
306
+ args: {
307
+ randomArg: 1234
308
+ }
309
+ }
310
+ });
311
+ appium.pluginClasses = [ArgsPlugin];
312
+ const plugin = appium.createPluginInstances()[0];
313
+ plugin.cliArgs.should.eql({
314
+ randomArg: 1234
315
+ });
316
+ });
317
+ });
318
+ });require('source-map-support').install();
319
+
320
+
321
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZHJpdmVyLXNwZWNzLmpzIl0sIm5hbWVzIjpbIlNFU1NJT05fSUQiLCJkZXNjcmliZSIsImJlZm9yZUVhY2giLCJnZXREcml2ZXJBbmRGYWtlRHJpdmVyIiwiYXBwaXVtQXJncyIsIkRyaXZlckNsYXNzIiwiRmFrZURyaXZlciIsImFwcGl1bSIsIkFwcGl1bURyaXZlciIsImZha2VEcml2ZXIiLCJtb2NrRmFrZURyaXZlciIsInNpbm9uIiwibW9jayIsIl9mYWtlRHJpdmVyIiwibW9ja2VkRHJpdmVyUmV0dXJuZXJDbGFzcyIsIkRyaXZlciIsIl9maW5kTWF0Y2hpbmdEcml2ZXIiLCJkcml2ZXIiLCJ2ZXJzaW9uIiwiZHJpdmVyTmFtZSIsImFmdGVyRWFjaCIsInJlc3RvcmUiLCJkZWxldGVTZXNzaW9uIiwiaXQiLCJleHBlY3RzIiwib25jZSIsIndpdGhFeGFjdEFyZ3MiLCJXM0NfQ0FQUyIsInJldHVybnMiLCJXM0NfUFJFRklYRURfQ0FQUyIsImNyZWF0ZVNlc3Npb24iLCJ2ZXJpZnkiLCJkZWZhdWx0Q2FwcyIsImFsbENhcHMiLCJhbHdheXNNYXRjaCIsImFyZ3MiLCJkZWZhdWx0Q2FwYWJpbGl0aWVzIiwid2l0aEFyZ3MiLCJwbGF0Zm9ybU5hbWUiLCJzZXNzaW9uT3ZlcnJpZGUiLCJmYWtlRHJpdmVycyIsIm1vY2tGYWtlRHJpdmVycyIsIl8iLCJtYXAiLCJmZCIsInRocm93cyIsInNlc3Npb25zIiwiZ2V0U2Vzc2lvbnMiLCJzaG91bGQiLCJoYXZlIiwibGVuZ3RoIiwibWZkIiwidW5kZWZpbmVkIiwiQkFTRV9DQVBTIiwidzNjQ2FwcyIsImZpcnN0TWF0Y2giLCJqc29ud3BDYXBzIiwiYXV0b21hdGlvbk5hbWUiLCJzb21lT3RoZXJQYXJhbSIsIm5ldmVyIiwiQXJnc0RyaXZlciIsIkJhc2VEcml2ZXIiLCJmYWtlIiwicmFuZG9tQXJnIiwidmFsdWUiLCJjbGlBcmdzIiwiZXFsIiwic2Vzc2lvbklkIiwib2JqZWN0IiwiYmVmb3JlIiwic2Vzc2lvbiIsImlkIiwiYmUiLCJhbiIsImVtcHR5IiwiY2FwczEiLCJjYXBzMiIsInNlc3Npb24xSWQiLCJzZXNzaW9uMUNhcHMiLCJzZXNzaW9uMklkIiwic2Vzc2lvbjJDYXBzIiwiZXF1YWwiLCJzdGF0dXMiLCJnZXRTdGF0dXMiLCJidWlsZCIsImV4aXN0IiwiY2xvbmUiLCJrZXlzIiwiY29udGFpbiIsImV2ZW50RW1pdHRlciIsImVtaXQiLCJFcnJvciIsIm5vdCIsIk5vQXJnc1BsdWdpbiIsInBsdWdpbk5hbWUiLCJBcmdzUGx1Z2luIiwicGx1Z2luQ2xhc3NlcyIsInBsdWdpbiIsImNyZWF0ZVBsdWdpbkluc3RhbmNlcyJdLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBRUE7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBQ0E7O0FBR0EsTUFBTUEsVUFBVSxHQUFHLENBQW5CO0FBRUFDLFFBQVEsQ0FBQyxjQUFELEVBQWlCLFlBQVk7QUFDbkNDLEVBQUFBLFVBQVUsQ0FBQyxZQUFZO0FBQ3JCO0FBQ0QsR0FGUyxDQUFWO0FBR0FELEVBQUFBLFFBQVEsQ0FBQyxjQUFELEVBQWlCLFlBQVk7QUFDbkMsYUFBU0Usc0JBQVQsQ0FBaUNDLFVBQVUsR0FBRyxFQUE5QyxFQUFrREMsV0FBVyxHQUFHQyxzQkFBaEUsRUFBNEU7QUFDMUUsWUFBTUMsTUFBTSxHQUFHLElBQUlDLG9CQUFKLENBQWlCSixVQUFqQixDQUFmO0FBQ0EsWUFBTUssVUFBVSxHQUFHLElBQUlKLFdBQUosRUFBbkI7O0FBQ0EsWUFBTUssY0FBYyxHQUFHQyxlQUFNQyxJQUFOLENBQVdILFVBQVgsQ0FBdkI7O0FBQ0FDLE1BQUFBLGNBQWMsQ0FBQ0csV0FBZixHQUE2QkosVUFBN0I7O0FBQ0EsWUFBTUsseUJBQXlCLEdBQUcsU0FBU0MsTUFBVCxHQUFtQjtBQUNuRCxlQUFPTixVQUFQO0FBQ0QsT0FGRDs7QUFJQUYsTUFBQUEsTUFBTSxDQUFDUyxtQkFBUCxHQUE2QixZQUFZO0FBQ3ZDLGVBQU87QUFDTEMsVUFBQUEsTUFBTSxFQUFFSCx5QkFESDtBQUVMSSxVQUFBQSxPQUFPLEVBQUUsT0FGSjtBQUdMQyxVQUFBQSxVQUFVLEVBQUU7QUFIUCxTQUFQO0FBS0QsT0FORDs7QUFPQSxhQUFPLENBQUNaLE1BQUQsRUFBU0csY0FBVCxDQUFQO0FBQ0Q7O0FBQ0RULElBQUFBLFFBQVEsQ0FBQyxlQUFELEVBQWtCLFlBQVk7QUFDcEMsVUFBSU0sTUFBSjtBQUNBLFVBQUlHLGNBQUo7QUFDQVIsTUFBQUEsVUFBVSxDQUFDLFlBQVk7QUFDckIsU0FBQ0ssTUFBRCxFQUFTRyxjQUFULElBQTJCUCxzQkFBc0IsRUFBakQ7QUFDRCxPQUZTLENBQVY7QUFHQWlCLE1BQUFBLFNBQVMsQ0FBQyxrQkFBa0I7QUFDMUJWLFFBQUFBLGNBQWMsQ0FBQ1csT0FBZjtBQUNBLGNBQU1kLE1BQU0sQ0FBQ2UsYUFBUCxDQUFxQnRCLFVBQXJCLENBQU47QUFDRCxPQUhRLENBQVQ7QUFLQXVCLE1BQUFBLEVBQUUsQ0FBRSxvRUFBRixFQUF1RSxrQkFBa0I7QUFDekZiLFFBQUFBLGNBQWMsQ0FBQ2MsT0FBZixDQUF1QixlQUF2QixFQUNHQyxJQURILEdBQ1VDLGFBRFYsQ0FDd0IsSUFEeEIsRUFDOEIsSUFEOUIsRUFDb0NDLGlCQURwQyxFQUM4QyxFQUQ5QyxFQUVHQyxPQUZILENBRVcsQ0FBQzVCLFVBQUQsRUFBYSxpQ0FBcUI2QiwwQkFBckIsQ0FBYixDQUZYO0FBR0EsY0FBTXRCLE1BQU0sQ0FBQ3VCLGFBQVAsQ0FBcUIsSUFBckIsRUFBMkIsSUFBM0IsRUFBaUNILGlCQUFqQyxDQUFOO0FBQ0FqQixRQUFBQSxjQUFjLENBQUNxQixNQUFmO0FBQ0QsT0FOQyxDQUFGO0FBT0FSLE1BQUFBLEVBQUUsQ0FBRSxnRkFBRixFQUFtRixrQkFBa0I7QUFDckcsWUFBSVMsV0FBVyxHQUFHO0FBQUMsNEJBQWtCO0FBQW5CLFNBQWxCO0FBQ0EsWUFBSUMsT0FBTyxHQUFHLEVBQUMsR0FBR04saUJBQUo7QUFBY08sVUFBQUEsV0FBVyxFQUFFLEVBQUMsR0FBR1Asa0JBQVNPLFdBQWI7QUFBMEIsZUFBR0Y7QUFBN0I7QUFBM0IsU0FBZDtBQUNBekIsUUFBQUEsTUFBTSxDQUFDNEIsSUFBUCxDQUFZQyxtQkFBWixHQUFrQ0osV0FBbEM7QUFDQXRCLFFBQUFBLGNBQWMsQ0FBQ2MsT0FBZixDQUF1QixlQUF2QixFQUNHQyxJQURILEdBQ1VZLFFBRFYsQ0FDbUIsSUFEbkIsRUFDeUIsSUFEekIsRUFDK0JKLE9BRC9CLEVBRUdMLE9BRkgsQ0FFVyxDQUFDNUIsVUFBRCxFQUFhLGlDQUFxQmlDLE9BQU8sQ0FBQ0MsV0FBN0IsQ0FBYixDQUZYO0FBR0EsY0FBTTNCLE1BQU0sQ0FBQ3VCLGFBQVAsQ0FBcUIsSUFBckIsRUFBMkIsSUFBM0IsRUFBaUNILGlCQUFqQyxDQUFOO0FBQ0FqQixRQUFBQSxjQUFjLENBQUNxQixNQUFmO0FBQ0QsT0FUQyxDQUFGO0FBVUFSLE1BQUFBLEVBQUUsQ0FBRSx3R0FBRixFQUEyRyxrQkFBa0I7QUFHN0gsWUFBSVMsV0FBVyxHQUFHO0FBQUNNLFVBQUFBLFlBQVksRUFBRTtBQUFmLFNBQWxCO0FBQ0EvQixRQUFBQSxNQUFNLENBQUM0QixJQUFQLENBQVlDLG1CQUFaLEdBQWtDSixXQUFsQztBQUNBdEIsUUFBQUEsY0FBYyxDQUFDYyxPQUFmLENBQXVCLGVBQXZCLEVBQ0dDLElBREgsR0FDVVksUUFEVixDQUNtQixJQURuQixFQUN5QixJQUR6QixFQUMrQlYsaUJBRC9CLEVBRUdDLE9BRkgsQ0FFVyxDQUFDNUIsVUFBRCxFQUFhLGlDQUFxQjZCLDBCQUFyQixDQUFiLENBRlg7QUFHQSxjQUFNdEIsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQixJQUFyQixFQUEyQixJQUEzQixFQUFpQ0gsaUJBQWpDLENBQU47QUFDQWpCLFFBQUFBLGNBQWMsQ0FBQ3FCLE1BQWY7QUFDRCxPQVZDLENBQUY7QUFXQVIsTUFBQUEsRUFBRSxDQUFDLHlEQUFELEVBQTRELGtCQUFrQjtBQUM5RWhCLFFBQUFBLE1BQU0sQ0FBQzRCLElBQVAsQ0FBWUksZUFBWixHQUE4QixJQUE5QjtBQUdBLFlBQUlDLFdBQVcsR0FBRyxDQUNoQixJQUFJbEMsc0JBQUosRUFEZ0IsRUFFaEIsSUFBSUEsc0JBQUosRUFGZ0IsRUFHaEIsSUFBSUEsc0JBQUosRUFIZ0IsQ0FBbEI7O0FBS0EsWUFBSW1DLGVBQWUsR0FBR0MsZ0JBQUVDLEdBQUYsQ0FBTUgsV0FBTixFQUFvQkksRUFBRCxJQUFRakMsZUFBTUMsSUFBTixDQUFXZ0MsRUFBWCxDQUEzQixDQUF0Qjs7QUFDQUgsUUFBQUEsZUFBZSxDQUFDLENBQUQsQ0FBZixDQUFtQmpCLE9BQW5CLENBQTJCLGVBQTNCLEVBQ0dDLElBREg7QUFFQWdCLFFBQUFBLGVBQWUsQ0FBQyxDQUFELENBQWYsQ0FBbUJqQixPQUFuQixDQUEyQixlQUEzQixFQUNHQyxJQURILEdBRUdvQixNQUZILENBRVUsMkRBRlY7QUFHQUosUUFBQUEsZUFBZSxDQUFDLENBQUQsQ0FBZixDQUFtQmpCLE9BQW5CLENBQTJCLGVBQTNCLEVBQ0dDLElBREg7QUFFQWxCLFFBQUFBLE1BQU0sQ0FBQ3VDLFFBQVAsQ0FBZ0IsYUFBaEIsSUFBaUNOLFdBQVcsQ0FBQyxDQUFELENBQTVDO0FBQ0FqQyxRQUFBQSxNQUFNLENBQUN1QyxRQUFQLENBQWdCLGFBQWhCLElBQWlDTixXQUFXLENBQUMsQ0FBRCxDQUE1QztBQUNBakMsUUFBQUEsTUFBTSxDQUFDdUMsUUFBUCxDQUFnQixhQUFoQixJQUFpQ04sV0FBVyxDQUFDLENBQUQsQ0FBNUM7QUFFQSxZQUFJTSxRQUFRLEdBQUcsTUFBTXZDLE1BQU0sQ0FBQ3dDLFdBQVAsRUFBckI7QUFDQUQsUUFBQUEsUUFBUSxDQUFDRSxNQUFULENBQWdCQyxJQUFoQixDQUFxQkMsTUFBckIsQ0FBNEIsQ0FBNUI7QUFFQXhDLFFBQUFBLGNBQWMsQ0FBQ2MsT0FBZixDQUF1QixlQUF2QixFQUNHQyxJQURILEdBQ1VDLGFBRFYsQ0FDd0IsSUFEeEIsRUFDOEIsSUFEOUIsRUFDb0NDLGlCQURwQyxFQUM4QyxFQUQ5QyxFQUVHQyxPQUZILENBRVcsQ0FBQzVCLFVBQUQsRUFBYSxpQ0FBcUI2QiwwQkFBckIsQ0FBYixDQUZYO0FBR0EsY0FBTXRCLE1BQU0sQ0FBQ3VCLGFBQVAsQ0FBcUIsSUFBckIsRUFBMkIsSUFBM0IsRUFBaUNILGlCQUFqQyxDQUFOO0FBRUFtQixRQUFBQSxRQUFRLEdBQUcsTUFBTXZDLE1BQU0sQ0FBQ3dDLFdBQVAsRUFBakI7QUFDQUQsUUFBQUEsUUFBUSxDQUFDRSxNQUFULENBQWdCQyxJQUFoQixDQUFxQkMsTUFBckIsQ0FBNEIsQ0FBNUI7O0FBRUEsYUFBSyxJQUFJQyxHQUFULElBQWdCVixlQUFoQixFQUFpQztBQUMvQlUsVUFBQUEsR0FBRyxDQUFDcEIsTUFBSjtBQUNEOztBQUNEckIsUUFBQUEsY0FBYyxDQUFDcUIsTUFBZjtBQUNELE9BcENDLENBQUY7QUFxQ0FSLE1BQUFBLEVBQUUsQ0FBQyx5RUFBRCxFQUE0RSxrQkFBa0I7QUFDOUZiLFFBQUFBLGNBQWMsQ0FBQ2MsT0FBZixDQUF1QixlQUF2QixFQUNHQyxJQURILEdBQ1VZLFFBRFYsQ0FDbUIsSUFEbkIsRUFDeUJlLFNBRHpCLEVBQ29DekIsaUJBRHBDLEVBRUdDLE9BRkgsQ0FFVyxDQUFDNUIsVUFBRCxFQUFhcUQsa0JBQWIsQ0FGWDtBQUdBLGNBQU05QyxNQUFNLENBQUN1QixhQUFQLENBQXFCc0IsU0FBckIsRUFBZ0NBLFNBQWhDLEVBQTJDekIsaUJBQTNDLENBQU47QUFDQWpCLFFBQUFBLGNBQWMsQ0FBQ3FCLE1BQWY7QUFDRCxPQU5DLENBQUY7QUFPQVIsTUFBQUEsRUFBRSxDQUFDLGdHQUFELEVBQW1HLGtCQUFrQjtBQUNySCxZQUFJK0IsT0FBTyxHQUFHLEVBQ1osR0FBRzNCLGlCQURTO0FBRVpPLFVBQUFBLFdBQVcsRUFBRSxFQUNYLEdBQUdQLGtCQUFTTyxXQUREO0FBRVgsb0NBQXdCO0FBRmI7QUFGRCxTQUFkO0FBT0F4QixRQUFBQSxjQUFjLENBQUNjLE9BQWYsQ0FBdUIsZUFBdkIsRUFDR0MsSUFESCxHQUNVWSxRQURWLENBQ21CLElBRG5CLEVBQ3lCZSxTQUR6QixFQUNvQztBQUNoQ2xCLFVBQUFBLFdBQVcsRUFBRSxFQUNYLEdBQUdvQixPQUFPLENBQUNwQixXQURBO0FBRVgsb0NBQXdCO0FBRmIsV0FEbUI7QUFLaENxQixVQUFBQSxVQUFVLEVBQUUsQ0FBQyxFQUFEO0FBTG9CLFNBRHBDLEVBUUczQixPQVJILENBUVcsQ0FBQzVCLFVBQUQsRUFBYSxpQ0FBcUJxRCxrQkFBckIsQ0FBYixDQVJYO0FBVUEsY0FBTTlDLE1BQU0sQ0FBQ3VCLGFBQVAsQ0FBcUJzQixTQUFyQixFQUFnQ0EsU0FBaEMsRUFBMkNFLE9BQTNDLENBQU47QUFDQTVDLFFBQUFBLGNBQWMsQ0FBQ3FCLE1BQWY7QUFDRCxPQXBCQyxDQUFGO0FBcUJBUixNQUFBQSxFQUFFLENBQUMsNkZBQUQsRUFBZ0csa0JBQWtCO0FBQ2xILGNBQU0rQixPQUFPLEdBQUcsRUFDZCxHQUFHM0IsaUJBRFc7QUFFZE8sVUFBQUEsV0FBVyxFQUFFO0FBQ1gsb0NBQXdCO0FBRGI7QUFGQyxTQUFoQjtBQU9BLGNBQU1zQixVQUFVLEdBQUcsRUFDakIsR0FBR0gsa0JBRGM7QUFFakJJLFVBQUFBLGNBQWMsRUFBRSxNQUZDO0FBR2pCQyxVQUFBQSxjQUFjLEVBQUU7QUFIQyxTQUFuQjtBQU1BaEQsUUFBQUEsY0FBYyxDQUFDYyxPQUFmLENBQXVCLGVBQXZCLEVBQXdDbUMsS0FBeEM7QUFDQSxjQUFNcEQsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQjBCLFVBQXJCLEVBQWlDSixTQUFqQyxFQUE0Q0UsT0FBNUMsQ0FBTjtBQUNBNUMsUUFBQUEsY0FBYyxDQUFDcUIsTUFBZjtBQUNELE9BakJDLENBQUY7QUFtQkFSLE1BQUFBLEVBQUUsQ0FBQywwQ0FBRCxFQUE2QyxrQkFBa0I7QUFDL0QsY0FBTXFDLFVBQU4sU0FBeUJDLHNCQUF6QixDQUFvQzs7QUFFcEMsY0FBTTFCLElBQUksR0FBRztBQUFDbEIsVUFBQUEsTUFBTSxFQUFFO0FBQUM2QyxZQUFBQSxJQUFJLEVBQUU7QUFBQ0MsY0FBQUEsU0FBUyxFQUFFO0FBQVo7QUFBUDtBQUFULFNBQWI7QUFDQSxTQUFDeEQsTUFBRCxFQUFTRyxjQUFULElBQTJCUCxzQkFBc0IsQ0FBQ2dDLElBQUQsRUFBT3lCLFVBQVAsQ0FBakQ7QUFDQSxjQUFNO0FBQUNJLFVBQUFBO0FBQUQsWUFBVSxNQUFNekQsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQnNCLFNBQXJCLEVBQWdDQSxTQUFoQyxFQUEyQ3pCLGlCQUEzQyxDQUF0Qjs7QUFDQSxZQUFJO0FBQ0ZqQixVQUFBQSxjQUFjLENBQUNHLFdBQWYsQ0FBMkJvRCxPQUEzQixDQUFtQ2pCLE1BQW5DLENBQTBDa0IsR0FBMUMsQ0FBOEM7QUFBQ0gsWUFBQUEsU0FBUyxFQUFFO0FBQVosV0FBOUM7QUFDRCxTQUZELFNBRVU7QUFDUixnQkFBTXhELE1BQU0sQ0FBQ2UsYUFBUCxDQUFxQjBDLEtBQUssQ0FBQyxDQUFELENBQTFCLENBQU47QUFDRDtBQUNGLE9BWEMsQ0FBRjtBQVlELEtBdklPLENBQVI7QUF3SUEvRCxJQUFBQSxRQUFRLENBQUMsZUFBRCxFQUFrQixZQUFZO0FBQ3BDLFVBQUlNLE1BQUo7QUFDQSxVQUFJRyxjQUFKO0FBQ0FSLE1BQUFBLFVBQVUsQ0FBQyxZQUFZO0FBQ3JCLFNBQUNLLE1BQUQsRUFBU0csY0FBVCxJQUEyQlAsc0JBQXNCLEVBQWpEO0FBQ0QsT0FGUyxDQUFWO0FBR0FpQixNQUFBQSxTQUFTLENBQUMsWUFBWTtBQUNwQlYsUUFBQUEsY0FBYyxDQUFDVyxPQUFmO0FBQ0QsT0FGUSxDQUFUO0FBR0FFLE1BQUFBLEVBQUUsQ0FBQywwQ0FBRCxFQUE2QyxrQkFBa0I7QUFDL0QsWUFBSSxDQUFDNEMsU0FBRCxJQUFjLENBQUMsTUFBTTVELE1BQU0sQ0FBQ3VCLGFBQVAsQ0FBcUIsSUFBckIsRUFBMkIsSUFBM0IsRUFBaUNILGlCQUFqQyxDQUFQLEVBQW1EcUMsS0FBckU7QUFDQSxZQUFJbEIsUUFBUSxHQUFHLE1BQU12QyxNQUFNLENBQUN3QyxXQUFQLEVBQXJCO0FBQ0FELFFBQUFBLFFBQVEsQ0FBQ0UsTUFBVCxDQUFnQkMsSUFBaEIsQ0FBcUJDLE1BQXJCLENBQTRCLENBQTVCO0FBQ0EsY0FBTTNDLE1BQU0sQ0FBQ2UsYUFBUCxDQUFxQjZDLFNBQXJCLENBQU47QUFDQXJCLFFBQUFBLFFBQVEsR0FBRyxNQUFNdkMsTUFBTSxDQUFDd0MsV0FBUCxFQUFqQjtBQUNBRCxRQUFBQSxRQUFRLENBQUNFLE1BQVQsQ0FBZ0JDLElBQWhCLENBQXFCQyxNQUFyQixDQUE0QixDQUE1QjtBQUNELE9BUEMsQ0FBRjtBQVFBM0IsTUFBQUEsRUFBRSxDQUFDLGtEQUFELEVBQXFELGtCQUFrQjtBQUN2RSxjQUFNLENBQUM0QyxTQUFELElBQWMsQ0FBQyxNQUFNNUQsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQixJQUFyQixFQUEyQixJQUEzQixFQUFpQ0gsaUJBQWpDLENBQVAsRUFBbURxQyxLQUF2RTtBQUNBdEQsUUFBQUEsY0FBYyxDQUFDYyxPQUFmLENBQXVCLGVBQXZCLEVBQ0dDLElBREgsR0FDVUMsYUFEVixDQUN3QnlDLFNBRHhCLEVBQ21DLEVBRG5DLEVBRUd2QyxPQUZIO0FBR0EsY0FBTXJCLE1BQU0sQ0FBQ2UsYUFBUCxDQUFxQjZDLFNBQXJCLENBQU47QUFDQXpELFFBQUFBLGNBQWMsQ0FBQ3FCLE1BQWY7QUFHQSxjQUFNckIsY0FBYyxDQUFDMEQsTUFBZixDQUFzQjlDLGFBQXRCLEVBQU47QUFDRCxPQVZDLENBQUY7QUFXRCxLQTVCTyxDQUFSO0FBNkJBckIsSUFBQUEsUUFBUSxDQUFDLGFBQUQsRUFBZ0IsWUFBWTtBQUNsQyxVQUFJTSxNQUFKLEVBQVlHLGNBQVo7QUFDQSxVQUFJb0MsUUFBSjtBQUNBdUIsTUFBQUEsTUFBTSxDQUFDLFlBQVk7QUFDakIsU0FBQzlELE1BQUQsRUFBU0csY0FBVCxJQUEyQlAsc0JBQXNCLEVBQWpEO0FBQ0QsT0FGSyxDQUFOO0FBR0FpQixNQUFBQSxTQUFTLENBQUMsa0JBQWtCO0FBQzFCLGFBQUssSUFBSWtELE9BQVQsSUFBb0J4QixRQUFwQixFQUE4QjtBQUM1QixnQkFBTXZDLE1BQU0sQ0FBQ2UsYUFBUCxDQUFxQmdELE9BQU8sQ0FBQ0MsRUFBN0IsQ0FBTjtBQUNEOztBQUNEN0QsUUFBQUEsY0FBYyxDQUFDVyxPQUFmO0FBQ0QsT0FMUSxDQUFUO0FBTUFFLE1BQUFBLEVBQUUsQ0FBQywwQ0FBRCxFQUE2QyxrQkFBa0I7QUFDL0R1QixRQUFBQSxRQUFRLEdBQUcsTUFBTXZDLE1BQU0sQ0FBQ3dDLFdBQVAsRUFBakI7QUFDQUQsUUFBQUEsUUFBUSxDQUFDRSxNQUFULENBQWdCd0IsRUFBaEIsQ0FBbUJDLEVBQW5CLENBQXNCLE9BQXRCO0FBQ0EzQixRQUFBQSxRQUFRLENBQUNFLE1BQVQsQ0FBZ0J3QixFQUFoQixDQUFtQkUsS0FBbkI7QUFDRCxPQUpDLENBQUY7QUFLQW5ELE1BQUFBLEVBQUUsQ0FBQyxnQ0FBRCxFQUFtQyxrQkFBa0I7QUFDckQsWUFBSW9ELEtBQUssR0FBRztBQUFDekMsVUFBQUEsV0FBVyxFQUFFLEVBQUMsR0FBR0wsMEJBQUo7QUFBdUIsMEJBQWM7QUFBckM7QUFBZCxTQUFaO0FBQ0EsWUFBSStDLEtBQUssR0FBRztBQUFDMUMsVUFBQUEsV0FBVyxFQUFFLEVBQUMsR0FBR0wsMEJBQUo7QUFBdUIsMEJBQWM7QUFBckM7QUFBZCxTQUFaO0FBQ0FuQixRQUFBQSxjQUFjLENBQUNjLE9BQWYsQ0FBdUIsZUFBdkIsRUFBd0NDLElBQXhDLEdBQ0dHLE9BREgsQ0FDVyxDQUFDLG1CQUFELEVBQXNCLGlDQUFxQitDLEtBQUssQ0FBQ3pDLFdBQTNCLENBQXRCLENBRFg7QUFFQSxZQUFJLENBQUMyQyxVQUFELEVBQWFDLFlBQWIsSUFBNkIsQ0FBQyxNQUFNdkUsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQixJQUFyQixFQUEyQixJQUEzQixFQUFpQzZDLEtBQWpDLENBQVAsRUFBZ0RYLEtBQWpGO0FBQ0F0RCxRQUFBQSxjQUFjLENBQUNjLE9BQWYsQ0FBdUIsZUFBdkIsRUFBd0NDLElBQXhDLEdBQ0dHLE9BREgsQ0FDVyxDQUFDLG1CQUFELEVBQXNCLGlDQUFxQmdELEtBQUssQ0FBQzFDLFdBQTNCLENBQXRCLENBRFg7QUFFQSxZQUFJLENBQUM2QyxVQUFELEVBQWFDLFlBQWIsSUFBNkIsQ0FBQyxNQUFNekUsTUFBTSxDQUFDdUIsYUFBUCxDQUFxQixJQUFyQixFQUEyQixJQUEzQixFQUFpQzhDLEtBQWpDLENBQVAsRUFBZ0RaLEtBQWpGO0FBRUFsQixRQUFBQSxRQUFRLEdBQUcsTUFBTXZDLE1BQU0sQ0FBQ3dDLFdBQVAsRUFBakI7QUFDQUQsUUFBQUEsUUFBUSxDQUFDRSxNQUFULENBQWdCd0IsRUFBaEIsQ0FBbUJDLEVBQW5CLENBQXNCLE9BQXRCO0FBQ0EzQixRQUFBQSxRQUFRLENBQUNFLE1BQVQsQ0FBZ0JDLElBQWhCLENBQXFCQyxNQUFyQixDQUE0QixDQUE1QjtBQUNBSixRQUFBQSxRQUFRLENBQUMsQ0FBRCxDQUFSLENBQVl5QixFQUFaLENBQWV2QixNQUFmLENBQXNCaUMsS0FBdEIsQ0FBNEJKLFVBQTVCO0FBQ0EseUNBQXFCRixLQUFLLENBQUN6QyxXQUEzQixFQUF3Q2MsTUFBeEMsQ0FBK0NrQixHQUEvQyxDQUFtRFksWUFBbkQ7QUFDQWhDLFFBQUFBLFFBQVEsQ0FBQyxDQUFELENBQVIsQ0FBWXlCLEVBQVosQ0FBZXZCLE1BQWYsQ0FBc0JpQyxLQUF0QixDQUE0QkYsVUFBNUI7QUFDQSx5Q0FBcUJILEtBQUssQ0FBQzFDLFdBQTNCLEVBQXdDYyxNQUF4QyxDQUErQ2tCLEdBQS9DLENBQW1EYyxZQUFuRDtBQUNELE9BakJDLENBQUY7QUFrQkQsS0FuQ08sQ0FBUjtBQW9DQS9FLElBQUFBLFFBQVEsQ0FBQyxXQUFELEVBQWMsWUFBWTtBQUNoQyxVQUFJTSxNQUFKO0FBQ0E4RCxNQUFBQSxNQUFNLENBQUMsWUFBWTtBQUNqQjlELFFBQUFBLE1BQU0sR0FBRyxJQUFJQyxvQkFBSixDQUFpQixFQUFqQixDQUFUO0FBQ0QsT0FGSyxDQUFOO0FBR0FlLE1BQUFBLEVBQUUsQ0FBQyx3QkFBRCxFQUEyQixrQkFBa0I7QUFDN0MsWUFBSTJELE1BQU0sR0FBRyxNQUFNM0UsTUFBTSxDQUFDNEUsU0FBUCxFQUFuQjtBQUNBRCxRQUFBQSxNQUFNLENBQUNFLEtBQVAsQ0FBYXBDLE1BQWIsQ0FBb0JxQyxLQUFwQjtBQUNBSCxRQUFBQSxNQUFNLENBQUNFLEtBQVAsQ0FBYWxFLE9BQWIsQ0FBcUI4QixNQUFyQixDQUE0QnFDLEtBQTVCO0FBQ0QsT0FKQyxDQUFGO0FBS0QsS0FWTyxDQUFSO0FBV0FwRixJQUFBQSxRQUFRLENBQUMsZUFBRCxFQUFrQixZQUFZLENBQ3JDLENBRE8sQ0FBUjtBQUVBQSxJQUFBQSxRQUFRLENBQUMsaUNBQUQsRUFBb0MsWUFBWTtBQUN0RCxVQUFJTSxNQUFKO0FBQ0EsVUFBSUcsY0FBSjtBQUNBUixNQUFBQSxVQUFVLENBQUMsWUFBWTtBQUNyQixTQUFDSyxNQUFELEVBQVNHLGNBQVQsSUFBMkJQLHNCQUFzQixFQUFqRDtBQUNELE9BRlMsQ0FBVjtBQUdBaUIsTUFBQUEsU0FBUyxDQUFDLGtCQUFrQjtBQUMxQixjQUFNVixjQUFjLENBQUMwRCxNQUFmLENBQXNCOUMsYUFBdEIsRUFBTjtBQUNBWixRQUFBQSxjQUFjLENBQUNXLE9BQWY7QUFDQWQsUUFBQUEsTUFBTSxDQUFDNEIsSUFBUCxDQUFZQyxtQkFBWixHQUFrQyxFQUFsQztBQUNELE9BSlEsQ0FBVDtBQU1BYixNQUFBQSxFQUFFLENBQUMsd0VBQUQsRUFBMkUsa0JBQWtCO0FBQzdGLFlBQUksQ0FBQzRDLFNBQUQsSUFBZSxDQUFDLE1BQU01RCxNQUFNLENBQUN1QixhQUFQLENBQXFCLElBQXJCLEVBQTJCLElBQTNCLEVBQWlDWSxnQkFBRTRDLEtBQUYsQ0FBUTNELGlCQUFSLENBQWpDLENBQVAsRUFBNERxQyxLQUEvRTs7QUFDQXRCLHdCQUFFNkMsSUFBRixDQUFPaEYsTUFBTSxDQUFDdUMsUUFBZCxFQUF3QkUsTUFBeEIsQ0FBK0J3QyxPQUEvQixDQUF1Q3JCLFNBQXZDOztBQUNBNUQsUUFBQUEsTUFBTSxDQUFDdUMsUUFBUCxDQUFnQnFCLFNBQWhCLEVBQTJCc0IsWUFBM0IsQ0FBd0NDLElBQXhDLENBQTZDLHNCQUE3QyxFQUFxRSxJQUFJQyxLQUFKLENBQVUsTUFBVixDQUFyRTtBQUVBLGNBQU0scUJBQU0sQ0FBTixDQUFOOztBQUNBakQsd0JBQUU2QyxJQUFGLENBQU9oRixNQUFNLENBQUN1QyxRQUFkLEVBQXdCRSxNQUF4QixDQUErQjRDLEdBQS9CLENBQW1DSixPQUFuQyxDQUEyQ3JCLFNBQTNDO0FBQ0QsT0FQQyxDQUFGO0FBUUE1QyxNQUFBQSxFQUFFLENBQUMsd0VBQUQsRUFBMkUsa0JBQWtCO0FBQzdGLFlBQUksQ0FBQzRDLFNBQUQsSUFBZSxDQUFDLE1BQU01RCxNQUFNLENBQUN1QixhQUFQLENBQXFCLElBQXJCLEVBQTJCLElBQTNCLEVBQWlDWSxnQkFBRTRDLEtBQUYsQ0FBUTNELGlCQUFSLENBQWpDLENBQVAsRUFBNERxQyxLQUEvRTs7QUFDQXRCLHdCQUFFNkMsSUFBRixDQUFPaEYsTUFBTSxDQUFDdUMsUUFBZCxFQUF3QkUsTUFBeEIsQ0FBK0J3QyxPQUEvQixDQUF1Q3JCLFNBQXZDOztBQUNBNUQsUUFBQUEsTUFBTSxDQUFDdUMsUUFBUCxDQUFnQnFCLFNBQWhCLEVBQTJCc0IsWUFBM0IsQ0FBd0NDLElBQXhDLENBQTZDLHNCQUE3QztBQUVBLGNBQU0scUJBQU0sQ0FBTixDQUFOOztBQUNBaEQsd0JBQUU2QyxJQUFGLENBQU9oRixNQUFNLENBQUN1QyxRQUFkLEVBQXdCRSxNQUF4QixDQUErQjRDLEdBQS9CLENBQW1DSixPQUFuQyxDQUEyQ3JCLFNBQTNDO0FBQ0QsT0FQQyxDQUFGO0FBUUQsS0E1Qk8sQ0FBUjtBQTZCRCxHQXRRTyxDQUFSO0FBdVFBbEUsRUFBQUEsUUFBUSxDQUFDLHdCQUFELEVBQTJCLFlBQVk7QUFDN0MsVUFBTTRGLFlBQU4sQ0FBbUI7O0FBQ25CQSxJQUFBQSxZQUFZLENBQUNDLFVBQWIsR0FBMEIsUUFBMUI7O0FBRUEsVUFBTUMsVUFBTixDQUFpQjs7QUFDakJBLElBQUFBLFVBQVUsQ0FBQ0QsVUFBWCxHQUF3QixNQUF4QjtBQUVBdkUsSUFBQUEsRUFBRSxDQUFDLDBDQUFELEVBQTZDLFlBQVk7QUFDekQsWUFBTWhCLE1BQU0sR0FBRyxJQUFJQyxvQkFBSixDQUFpQixFQUFqQixDQUFmO0FBQ0FELE1BQUFBLE1BQU0sQ0FBQ3lGLGFBQVAsR0FBdUIsQ0FBQ0gsWUFBRCxFQUFlRSxVQUFmLENBQXZCOztBQUNBLFdBQUssTUFBTUUsTUFBWCxJQUFxQjFGLE1BQU0sQ0FBQzJGLHFCQUFQLEVBQXJCLEVBQXFEO0FBQ25EbEQsUUFBQUEsTUFBTSxDQUFDNEMsR0FBUCxDQUFXUCxLQUFYLENBQWlCWSxNQUFNLENBQUNoQyxPQUF4QjtBQUNEO0FBQ0YsS0FOQyxDQUFGO0FBT0ExQyxJQUFBQSxFQUFFLENBQUMsaURBQUQsRUFBb0QsWUFBWTtBQUNoRSxZQUFNaEIsTUFBTSxHQUFHLElBQUlDLG9CQUFKLENBQWlCO0FBQUN5RixRQUFBQSxNQUFNLEVBQUU7QUFBQzlELFVBQUFBLElBQUksRUFBRTtBQUFDNEIsWUFBQUEsU0FBUyxFQUFFO0FBQVo7QUFBUDtBQUFULE9BQWpCLENBQWY7QUFDQXhELE1BQUFBLE1BQU0sQ0FBQ3lGLGFBQVAsR0FBdUIsQ0FBQ0QsVUFBRCxDQUF2QjtBQUNBLFlBQU1FLE1BQU0sR0FBRzFGLE1BQU0sQ0FBQzJGLHFCQUFQLEdBQStCLENBQS9CLENBQWY7QUFDQUQsTUFBQUEsTUFBTSxDQUFDaEMsT0FBUCxDQUFlakIsTUFBZixDQUFzQmtCLEdBQXRCLENBQTBCO0FBQUNILFFBQUFBLFNBQVMsRUFBRTtBQUFaLE9BQTFCO0FBQ0QsS0FMQyxDQUFGO0FBTUQsR0FwQk8sQ0FBUjtBQXFCRCxDQWhTTyxDQUFSIiwic291cmNlc0NvbnRlbnQiOlsiLy8gdHJhbnNwaWxlOm1vY2hhXG5cbmltcG9ydCB7IEFwcGl1bURyaXZlciB9IGZyb20gJy4uL2xpYi9hcHBpdW0nO1xuaW1wb3J0IHsgQmFzZURyaXZlciB9IGZyb20gJ0BhcHBpdW0vYmFzZS1kcml2ZXInO1xuaW1wb3J0IHsgRmFrZURyaXZlciB9IGZyb20gJ0BhcHBpdW0vZmFrZS1kcml2ZXInO1xuaW1wb3J0IHsgQkFTRV9DQVBTLCBXM0NfQ0FQUywgVzNDX1BSRUZJWEVEX0NBUFMgfSBmcm9tICcuL2hlbHBlcnMnO1xuaW1wb3J0IHtyZXNldFNjaGVtYX0gZnJvbSAnLi4vbGliL3NjaGVtYS9zY2hlbWEnO1xuaW1wb3J0IF8gZnJvbSAnbG9kYXNoJztcbmltcG9ydCBzaW5vbiBmcm9tICdzaW5vbic7XG5pbXBvcnQgeyBzbGVlcCB9IGZyb20gJ2FzeW5jYm94JztcbmltcG9ydCB7IGluc2VydEFwcGl1bVByZWZpeGVzLCByZW1vdmVBcHBpdW1QcmVmaXhlcyB9IGZyb20gJy4uL2xpYi91dGlscyc7XG5cblxuY29uc3QgU0VTU0lPTl9JRCA9IDE7XG5cbmRlc2NyaWJlKCdBcHBpdW1Ecml2ZXInLCBmdW5jdGlvbiAoKSB7XG4gIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgIHJlc2V0U2NoZW1hKCk7XG4gIH0pO1xuICBkZXNjcmliZSgnQXBwaXVtRHJpdmVyJywgZnVuY3Rpb24gKCkge1xuICAgIGZ1bmN0aW9uIGdldERyaXZlckFuZEZha2VEcml2ZXIgKGFwcGl1bUFyZ3MgPSB7fSwgRHJpdmVyQ2xhc3MgPSBGYWtlRHJpdmVyKSB7XG4gICAgICBjb25zdCBhcHBpdW0gPSBuZXcgQXBwaXVtRHJpdmVyKGFwcGl1bUFyZ3MpO1xuICAgICAgY29uc3QgZmFrZURyaXZlciA9IG5ldyBEcml2ZXJDbGFzcygpO1xuICAgICAgY29uc3QgbW9ja0Zha2VEcml2ZXIgPSBzaW5vbi5tb2NrKGZha2VEcml2ZXIpO1xuICAgICAgbW9ja0Zha2VEcml2ZXIuX2Zha2VEcml2ZXIgPSBmYWtlRHJpdmVyO1xuICAgICAgY29uc3QgbW9ja2VkRHJpdmVyUmV0dXJuZXJDbGFzcyA9IGZ1bmN0aW9uIERyaXZlciAoKSB7XG4gICAgICAgIHJldHVybiBmYWtlRHJpdmVyO1xuICAgICAgfTtcblxuICAgICAgYXBwaXVtLl9maW5kTWF0Y2hpbmdEcml2ZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZHJpdmVyOiBtb2NrZWREcml2ZXJSZXR1cm5lckNsYXNzLFxuICAgICAgICAgIHZlcnNpb246ICcxLjIuMycsXG4gICAgICAgICAgZHJpdmVyTmFtZTogJ2Zha2UnLFxuICAgICAgICB9O1xuICAgICAgfTtcbiAgICAgIHJldHVybiBbYXBwaXVtLCBtb2NrRmFrZURyaXZlcl07XG4gICAgfVxuICAgIGRlc2NyaWJlKCdjcmVhdGVTZXNzaW9uJywgZnVuY3Rpb24gKCkge1xuICAgICAgbGV0IGFwcGl1bTtcbiAgICAgIGxldCBtb2NrRmFrZURyaXZlcjtcbiAgICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBbYXBwaXVtLCBtb2NrRmFrZURyaXZlcl0gPSBnZXREcml2ZXJBbmRGYWtlRHJpdmVyKCk7XG4gICAgICB9KTtcbiAgICAgIGFmdGVyRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnJlc3RvcmUoKTtcbiAgICAgICAgYXdhaXQgYXBwaXVtLmRlbGV0ZVNlc3Npb24oU0VTU0lPTl9JRCk7XG4gICAgICB9KTtcblxuICAgICAgaXQoYHNob3VsZCBjYWxsIGlubmVyIGRyaXZlcidzIGNyZWF0ZVNlc3Npb24gd2l0aCBkZXNpcmVkIGNhcGFiaWxpdGllc2AsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoRXhhY3RBcmdzKG51bGwsIG51bGwsIFczQ19DQVBTLCBbXSlcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoVzNDX1BSRUZJWEVEX0NBUFMpXSk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIFczQ19DQVBTKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIudmVyaWZ5KCk7XG4gICAgICB9KTtcbiAgICAgIGl0KGBzaG91bGQgY2FsbCBpbm5lciBkcml2ZXIncyBjcmVhdGVTZXNzaW9uIHdpdGggZGVzaXJlZCBhbmQgZGVmYXVsdCBjYXBhYmlsaXRpZXNgLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCBkZWZhdWx0Q2FwcyA9IHsnYXBwaXVtOnNvbWVDYXAnOiAnaGVsbG8nfTtcbiAgICAgICAgbGV0IGFsbENhcHMgPSB7Li4uVzNDX0NBUFMsIGFsd2F5c01hdGNoOiB7Li4uVzNDX0NBUFMuYWx3YXlzTWF0Y2gsIC4uLmRlZmF1bHRDYXBzfX07XG4gICAgICAgIGFwcGl1bS5hcmdzLmRlZmF1bHRDYXBhYmlsaXRpZXMgPSBkZWZhdWx0Q2FwcztcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoQXJncyhudWxsLCBudWxsLCBhbGxDYXBzKVxuICAgICAgICAgIC5yZXR1cm5zKFtTRVNTSU9OX0lELCByZW1vdmVBcHBpdW1QcmVmaXhlcyhhbGxDYXBzLmFsd2F5c01hdGNoKV0pO1xuICAgICAgICBhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBXM0NfQ0FQUyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdChgc2hvdWxkIGNhbGwgaW5uZXIgZHJpdmVyJ3MgY3JlYXRlU2Vzc2lvbiB3aXRoIGRlc2lyZWQgYW5kIGRlZmF1bHQgY2FwYWJpbGl0aWVzIHdpdGhvdXQgb3ZlcnJpZGluZyBjYXBzYCwgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBhIGRlZmF1bHQgY2FwYWJpbGl0eSB3aXRoIHRoZSBzYW1lIGtleSBhcyBhIGRlc2lyZWQgY2FwYWJpbGl0eVxuICAgICAgICAvLyBzaG91bGQgZG8gbm90aGluZ1xuICAgICAgICBsZXQgZGVmYXVsdENhcHMgPSB7cGxhdGZvcm1OYW1lOiAnRXJzYXR6J307XG4gICAgICAgIGFwcGl1bS5hcmdzLmRlZmF1bHRDYXBhYmlsaXRpZXMgPSBkZWZhdWx0Q2FwcztcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoQXJncyhudWxsLCBudWxsLCBXM0NfQ0FQUylcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoVzNDX1BSRUZJWEVEX0NBUFMpXSk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIFczQ19DQVBTKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIudmVyaWZ5KCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQga2lsbCBhbGwgb3RoZXIgc2Vzc2lvbnMgaWYgc2Vzc2lvbk92ZXJyaWRlIGlzIG9uJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBhcHBpdW0uYXJncy5zZXNzaW9uT3ZlcnJpZGUgPSB0cnVlO1xuXG4gICAgICAgIC8vIG1vY2sgdGhyZWUgc2Vzc2lvbnMgdGhhdCBzaG91bGQgYmUgcmVtb3ZlZCB3aGVuIHRoZSBuZXcgb25lIGlzIGNyZWF0ZWRcbiAgICAgICAgbGV0IGZha2VEcml2ZXJzID0gW1xuICAgICAgICAgIG5ldyBGYWtlRHJpdmVyKCksXG4gICAgICAgICAgbmV3IEZha2VEcml2ZXIoKSxcbiAgICAgICAgICBuZXcgRmFrZURyaXZlcigpLFxuICAgICAgICBdO1xuICAgICAgICBsZXQgbW9ja0Zha2VEcml2ZXJzID0gXy5tYXAoZmFrZURyaXZlcnMsIChmZCkgPT4gc2lub24ubW9jayhmZCkpO1xuICAgICAgICBtb2NrRmFrZURyaXZlcnNbMF0uZXhwZWN0cygnZGVsZXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXJzWzFdLmV4cGVjdHMoJ2RlbGV0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKClcbiAgICAgICAgICAudGhyb3dzKCdDYW5ub3Qgc2h1dCBkb3duIEFuZHJvaWQgZHJpdmVyOyBpdCBoYXMgYWxyZWFkeSBzaHV0IGRvd24nKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXJzWzJdLmV4cGVjdHMoJ2RlbGV0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCk7XG4gICAgICAgIGFwcGl1bS5zZXNzaW9uc1snYWJjLTEyMy14eXonXSA9IGZha2VEcml2ZXJzWzBdO1xuICAgICAgICBhcHBpdW0uc2Vzc2lvbnNbJ3h5ei0zMjEtYWJjJ10gPSBmYWtlRHJpdmVyc1sxXTtcbiAgICAgICAgYXBwaXVtLnNlc3Npb25zWycxMjMtYWJjLXh5eiddID0gZmFrZURyaXZlcnNbMl07XG5cbiAgICAgICAgbGV0IHNlc3Npb25zID0gYXdhaXQgYXBwaXVtLmdldFNlc3Npb25zKCk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5oYXZlLmxlbmd0aCgzKTtcblxuICAgICAgICBtb2NrRmFrZURyaXZlci5leHBlY3RzKCdjcmVhdGVTZXNzaW9uJylcbiAgICAgICAgICAub25jZSgpLndpdGhFeGFjdEFyZ3MobnVsbCwgbnVsbCwgVzNDX0NBUFMsIFtdKVxuICAgICAgICAgIC5yZXR1cm5zKFtTRVNTSU9OX0lELCByZW1vdmVBcHBpdW1QcmVmaXhlcyhXM0NfUFJFRklYRURfQ0FQUyldKTtcbiAgICAgICAgYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24obnVsbCwgbnVsbCwgVzNDX0NBUFMpO1xuXG4gICAgICAgIHNlc3Npb25zID0gYXdhaXQgYXBwaXVtLmdldFNlc3Npb25zKCk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5oYXZlLmxlbmd0aCgxKTtcblxuICAgICAgICBmb3IgKGxldCBtZmQgb2YgbW9ja0Zha2VEcml2ZXJzKSB7XG4gICAgICAgICAgbWZkLnZlcmlmeSgpO1xuICAgICAgICB9XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIGNhbGwgXCJjcmVhdGVTZXNzaW9uXCIgd2l0aCBXM0MgY2FwYWJpbGl0aWVzIGFyZ3VtZW50LCBpZiBwcm92aWRlZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpXG4gICAgICAgICAgLm9uY2UoKS53aXRoQXJncyhudWxsLCB1bmRlZmluZWQsIFczQ19DQVBTKVxuICAgICAgICAgIC5yZXR1cm5zKFtTRVNTSU9OX0lELCBCQVNFX0NBUFNdKTtcbiAgICAgICAgYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFczQ19DQVBTKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIudmVyaWZ5KCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgY2FsbCBcImNyZWF0ZVNlc3Npb25cIiB3aXRoIFczQyBjYXBhYmlsaXRpZXMgYXJndW1lbnQgd2l0aCBhZGRpdGlvbmFsIHByb3ZpZGVkIHBhcmFtZXRlcnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCB3M2NDYXBzID0ge1xuICAgICAgICAgIC4uLlczQ19DQVBTLFxuICAgICAgICAgIGFsd2F5c01hdGNoOiB7XG4gICAgICAgICAgICAuLi5XM0NfQ0FQUy5hbHdheXNNYXRjaCxcbiAgICAgICAgICAgICdhcHBpdW06c29tZU90aGVyUGFybSc6ICdzb21lT3RoZXJQYXJtJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuICAgICAgICBtb2NrRmFrZURyaXZlci5leHBlY3RzKCdjcmVhdGVTZXNzaW9uJylcbiAgICAgICAgICAub25jZSgpLndpdGhBcmdzKG51bGwsIHVuZGVmaW5lZCwge1xuICAgICAgICAgICAgYWx3YXlzTWF0Y2g6IHtcbiAgICAgICAgICAgICAgLi4udzNjQ2Fwcy5hbHdheXNNYXRjaCxcbiAgICAgICAgICAgICAgJ2FwcGl1bTpzb21lT3RoZXJQYXJtJzogJ3NvbWVPdGhlclBhcm0nLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZpcnN0TWF0Y2g6IFt7fV0sXG4gICAgICAgICAgfSlcbiAgICAgICAgICAucmV0dXJucyhbU0VTU0lPTl9JRCwgaW5zZXJ0QXBwaXVtUHJlZml4ZXMoQkFTRV9DQVBTKV0pO1xuXG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB3M2NDYXBzKTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIudmVyaWZ5KCk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgbm90IGNhbGwgXCJjcmVhdGVTZXNzaW9uXCIgd2l0aCBKU09OV1AgY2FwYWJpbGl0aWVzIGlmIFczQyBoYXMgaW5jb21wbGV0ZSBjYXBhYmlsaXRpZXMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IHczY0NhcHMgPSB7XG4gICAgICAgICAgLi4uVzNDX0NBUFMsXG4gICAgICAgICAgYWx3YXlzTWF0Y2g6IHtcbiAgICAgICAgICAgICdhcHBpdW06c29tZU90aGVyUGFybSc6ICdzb21lT3RoZXJQYXJtJyxcbiAgICAgICAgICB9LFxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IGpzb253cENhcHMgPSB7XG4gICAgICAgICAgLi4uQkFTRV9DQVBTLFxuICAgICAgICAgIGF1dG9tYXRpb25OYW1lOiAnRmFrZScsXG4gICAgICAgICAgc29tZU90aGVyUGFyYW06ICdzb21lT3RoZXJQYXJhbScsXG4gICAgICAgIH07XG5cbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpLm5ldmVyKCk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKGpzb253cENhcHMsIHVuZGVmaW5lZCwgdzNjQ2Fwcyk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuICAgICAgfSk7XG5cbiAgICAgIGl0KCdzaG91bGQgYXNzaWduIGFyZ3MgdG8gcHJvcGVydHkgYGNsaUFyZ3NgJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBjbGFzcyBBcmdzRHJpdmVyIGV4dGVuZHMgQmFzZURyaXZlciB7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYXJncyA9IHtkcml2ZXI6IHtmYWtlOiB7cmFuZG9tQXJnOiAxMjM0fX19O1xuICAgICAgICBbYXBwaXVtLCBtb2NrRmFrZURyaXZlcl0gPSBnZXREcml2ZXJBbmRGYWtlRHJpdmVyKGFyZ3MsIEFyZ3NEcml2ZXIpO1xuICAgICAgICBjb25zdCB7dmFsdWV9ID0gYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24odW5kZWZpbmVkLCB1bmRlZmluZWQsIFczQ19DQVBTKTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBtb2NrRmFrZURyaXZlci5fZmFrZURyaXZlci5jbGlBcmdzLnNob3VsZC5lcWwoe3JhbmRvbUFyZzogMTIzNH0pO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIGF3YWl0IGFwcGl1bS5kZWxldGVTZXNzaW9uKHZhbHVlWzBdKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSk7XG4gICAgZGVzY3JpYmUoJ2RlbGV0ZVNlc3Npb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgYXBwaXVtO1xuICAgICAgbGV0IG1vY2tGYWtlRHJpdmVyO1xuICAgICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIFthcHBpdW0sIG1vY2tGYWtlRHJpdmVyXSA9IGdldERyaXZlckFuZEZha2VEcml2ZXIoKTtcbiAgICAgIH0pO1xuICAgICAgYWZ0ZXJFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIucmVzdG9yZSgpO1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIHJlbW92ZSB0aGUgc2Vzc2lvbiBpZiBpdCBpcyBmb3VuZCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbGV0IFtzZXNzaW9uSWRdID0gKGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIFczQ19DQVBTKSkudmFsdWU7XG4gICAgICAgIGxldCBzZXNzaW9ucyA9IGF3YWl0IGFwcGl1bS5nZXRTZXNzaW9ucygpO1xuICAgICAgICBzZXNzaW9ucy5zaG91bGQuaGF2ZS5sZW5ndGgoMSk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5kZWxldGVTZXNzaW9uKHNlc3Npb25JZCk7XG4gICAgICAgIHNlc3Npb25zID0gYXdhaXQgYXBwaXVtLmdldFNlc3Npb25zKCk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5oYXZlLmxlbmd0aCgwKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCBjYWxsIGlubmVyIGRyaXZlclxcJ3MgZGVsZXRlU2Vzc2lvbiBtZXRob2QnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IFtzZXNzaW9uSWRdID0gKGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIFczQ19DQVBTKSkudmFsdWU7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2RlbGV0ZVNlc3Npb24nKVxuICAgICAgICAgIC5vbmNlKCkud2l0aEV4YWN0QXJncyhzZXNzaW9uSWQsIFtdKVxuICAgICAgICAgIC5yZXR1cm5zKCk7XG4gICAgICAgIGF3YWl0IGFwcGl1bS5kZWxldGVTZXNzaW9uKHNlc3Npb25JZCk7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnZlcmlmeSgpO1xuXG4gICAgICAgIC8vIGNsZWFudXAsIHNpbmNlIHdlIGZha2VkIHRoZSBkZWxldGUgc2Vzc2lvbiBjYWxsXG4gICAgICAgIGF3YWl0IG1vY2tGYWtlRHJpdmVyLm9iamVjdC5kZWxldGVTZXNzaW9uKCk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnZ2V0U2Vzc2lvbnMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgYXBwaXVtLCBtb2NrRmFrZURyaXZlcjtcbiAgICAgIGxldCBzZXNzaW9ucztcbiAgICAgIGJlZm9yZShmdW5jdGlvbiAoKSB7XG4gICAgICAgIFthcHBpdW0sIG1vY2tGYWtlRHJpdmVyXSA9IGdldERyaXZlckFuZEZha2VEcml2ZXIoKTtcbiAgICAgIH0pO1xuICAgICAgYWZ0ZXJFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZm9yIChsZXQgc2Vzc2lvbiBvZiBzZXNzaW9ucykge1xuICAgICAgICAgIGF3YWl0IGFwcGl1bS5kZWxldGVTZXNzaW9uKHNlc3Npb24uaWQpO1xuICAgICAgICB9XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLnJlc3RvcmUoKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gYW4gZW1wdHkgYXJyYXkgb2Ygc2Vzc2lvbnMnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNlc3Npb25zID0gYXdhaXQgYXBwaXVtLmdldFNlc3Npb25zKCk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5iZS5hbignYXJyYXknKTtcbiAgICAgICAgc2Vzc2lvbnMuc2hvdWxkLmJlLmVtcHR5O1xuICAgICAgfSk7XG4gICAgICBpdCgnc2hvdWxkIHJldHVybiBzZXNzaW9ucyBjcmVhdGVkJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgY2FwczEgPSB7YWx3YXlzTWF0Y2g6IHsuLi5XM0NfUFJFRklYRURfQ0FQUywgJ2FwcGl1bTpjYXAnOiAndmFsdWUnfX07XG4gICAgICAgIGxldCBjYXBzMiA9IHthbHdheXNNYXRjaDogey4uLlczQ19QUkVGSVhFRF9DQVBTLCAnYXBwaXVtOmNhcCc6ICdvdGhlciB2YWx1ZSd9fTtcbiAgICAgICAgbW9ja0Zha2VEcml2ZXIuZXhwZWN0cygnY3JlYXRlU2Vzc2lvbicpLm9uY2UoKVxuICAgICAgICAgIC5yZXR1cm5zKFsnZmFrZS1zZXNzaW9uLWlkLTEnLCByZW1vdmVBcHBpdW1QcmVmaXhlcyhjYXBzMS5hbHdheXNNYXRjaCldKTtcbiAgICAgICAgbGV0IFtzZXNzaW9uMUlkLCBzZXNzaW9uMUNhcHNdID0gKGF3YWl0IGFwcGl1bS5jcmVhdGVTZXNzaW9uKG51bGwsIG51bGwsIGNhcHMxKSkudmFsdWU7XG4gICAgICAgIG1vY2tGYWtlRHJpdmVyLmV4cGVjdHMoJ2NyZWF0ZVNlc3Npb24nKS5vbmNlKClcbiAgICAgICAgICAucmV0dXJucyhbJ2Zha2Utc2Vzc2lvbi1pZC0yJywgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoY2FwczIuYWx3YXlzTWF0Y2gpXSk7XG4gICAgICAgIGxldCBbc2Vzc2lvbjJJZCwgc2Vzc2lvbjJDYXBzXSA9IChhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBjYXBzMikpLnZhbHVlO1xuXG4gICAgICAgIHNlc3Npb25zID0gYXdhaXQgYXBwaXVtLmdldFNlc3Npb25zKCk7XG4gICAgICAgIHNlc3Npb25zLnNob3VsZC5iZS5hbignYXJyYXknKTtcbiAgICAgICAgc2Vzc2lvbnMuc2hvdWxkLmhhdmUubGVuZ3RoKDIpO1xuICAgICAgICBzZXNzaW9uc1swXS5pZC5zaG91bGQuZXF1YWwoc2Vzc2lvbjFJZCk7XG4gICAgICAgIHJlbW92ZUFwcGl1bVByZWZpeGVzKGNhcHMxLmFsd2F5c01hdGNoKS5zaG91bGQuZXFsKHNlc3Npb24xQ2Fwcyk7XG4gICAgICAgIHNlc3Npb25zWzFdLmlkLnNob3VsZC5lcXVhbChzZXNzaW9uMklkKTtcbiAgICAgICAgcmVtb3ZlQXBwaXVtUHJlZml4ZXMoY2FwczIuYWx3YXlzTWF0Y2gpLnNob3VsZC5lcWwoc2Vzc2lvbjJDYXBzKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICAgIGRlc2NyaWJlKCdnZXRTdGF0dXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBsZXQgYXBwaXVtO1xuICAgICAgYmVmb3JlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYXBwaXVtID0gbmV3IEFwcGl1bURyaXZlcih7fSk7XG4gICAgICB9KTtcbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIGEgc3RhdHVzJywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBsZXQgc3RhdHVzID0gYXdhaXQgYXBwaXVtLmdldFN0YXR1cygpO1xuICAgICAgICBzdGF0dXMuYnVpbGQuc2hvdWxkLmV4aXN0O1xuICAgICAgICBzdGF0dXMuYnVpbGQudmVyc2lvbi5zaG91bGQuZXhpc3Q7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnc2Vzc2lvbkV4aXN0cycsIGZ1bmN0aW9uICgpIHtcbiAgICB9KTtcbiAgICBkZXNjcmliZSgnYXR0YWNoVW5leHBlY3RlZFNodXRkb3duSGFuZGxlcicsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGxldCBhcHBpdW07XG4gICAgICBsZXQgbW9ja0Zha2VEcml2ZXI7XG4gICAgICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgW2FwcGl1bSwgbW9ja0Zha2VEcml2ZXJdID0gZ2V0RHJpdmVyQW5kRmFrZURyaXZlcigpO1xuICAgICAgfSk7XG4gICAgICBhZnRlckVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICBhd2FpdCBtb2NrRmFrZURyaXZlci5vYmplY3QuZGVsZXRlU2Vzc2lvbigpO1xuICAgICAgICBtb2NrRmFrZURyaXZlci5yZXN0b3JlKCk7XG4gICAgICAgIGFwcGl1bS5hcmdzLmRlZmF1bHRDYXBhYmlsaXRpZXMgPSB7fTtcbiAgICAgIH0pO1xuXG4gICAgICBpdCgnc2hvdWxkIHJlbW92ZSBzZXNzaW9uIGlmIGlubmVyIGRyaXZlciB1bmV4cGVjdGVkbHkgZXhpdHMgd2l0aCBhbiBlcnJvcicsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbGV0IFtzZXNzaW9uSWQsXSA9IChhd2FpdCBhcHBpdW0uY3JlYXRlU2Vzc2lvbihudWxsLCBudWxsLCBfLmNsb25lKFczQ19DQVBTKSkpLnZhbHVlOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIGNvbW1hLXNwYWNpbmdcbiAgICAgICAgXy5rZXlzKGFwcGl1bS5zZXNzaW9ucykuc2hvdWxkLmNvbnRhaW4oc2Vzc2lvbklkKTtcbiAgICAgICAgYXBwaXVtLnNlc3Npb25zW3Nlc3Npb25JZF0uZXZlbnRFbWl0dGVyLmVtaXQoJ29uVW5leHBlY3RlZFNodXRkb3duJywgbmV3IEVycm9yKCdPb3BzJykpO1xuICAgICAgICAvLyBsZXQgZXZlbnQgbG9vcCBzcGluIHNvIHJlamVjdGlvbiBpcyBoYW5kbGVkXG4gICAgICAgIGF3YWl0IHNsZWVwKDEpO1xuICAgICAgICBfLmtleXMoYXBwaXVtLnNlc3Npb25zKS5zaG91bGQubm90LmNvbnRhaW4oc2Vzc2lvbklkKTtcbiAgICAgIH0pO1xuICAgICAgaXQoJ3Nob3VsZCByZW1vdmUgc2Vzc2lvbiBpZiBpbm5lciBkcml2ZXIgdW5leHBlY3RlZGx5IGV4aXRzIHdpdGggbm8gZXJyb3InLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGxldCBbc2Vzc2lvbklkLF0gPSAoYXdhaXQgYXBwaXVtLmNyZWF0ZVNlc3Npb24obnVsbCwgbnVsbCwgXy5jbG9uZShXM0NfQ0FQUykpKS52YWx1ZTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBjb21tYS1zcGFjaW5nXG4gICAgICAgIF8ua2V5cyhhcHBpdW0uc2Vzc2lvbnMpLnNob3VsZC5jb250YWluKHNlc3Npb25JZCk7XG4gICAgICAgIGFwcGl1bS5zZXNzaW9uc1tzZXNzaW9uSWRdLmV2ZW50RW1pdHRlci5lbWl0KCdvblVuZXhwZWN0ZWRTaHV0ZG93bicpO1xuICAgICAgICAvLyBsZXQgZXZlbnQgbG9vcCBzcGluIHNvIHJlamVjdGlvbiBpcyBoYW5kbGVkXG4gICAgICAgIGF3YWl0IHNsZWVwKDEpO1xuICAgICAgICBfLmtleXMoYXBwaXVtLnNlc3Npb25zKS5zaG91bGQubm90LmNvbnRhaW4oc2Vzc2lvbklkKTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbiAgZGVzY3JpYmUoJyNjcmVhdGVQbHVnaW5JbnN0YW5jZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgY2xhc3MgTm9BcmdzUGx1Z2luIHt9XG4gICAgTm9BcmdzUGx1Z2luLnBsdWdpbk5hbWUgPSAnbm9hcmdzJztcblxuICAgIGNsYXNzIEFyZ3NQbHVnaW4ge31cbiAgICBBcmdzUGx1Z2luLnBsdWdpbk5hbWUgPSAnYXJncyc7XG5cbiAgICBpdCgnc2hvdWxkIG5vdCBzZXQgQ0xJIGFyZ3MgaWYgbm9uZSBhcmUgc2VudCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGNvbnN0IGFwcGl1bSA9IG5ldyBBcHBpdW1Ecml2ZXIoe30pO1xuICAgICAgYXBwaXVtLnBsdWdpbkNsYXNzZXMgPSBbTm9BcmdzUGx1Z2luLCBBcmdzUGx1Z2luXTtcbiAgICAgIGZvciAoY29uc3QgcGx1Z2luIG9mIGFwcGl1bS5jcmVhdGVQbHVnaW5JbnN0YW5jZXMoKSkge1xuICAgICAgICBzaG91bGQubm90LmV4aXN0KHBsdWdpbi5jbGlBcmdzKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICBpdCgnc2hvdWxkIGFkZCBjbGlBcmdzIHRvIHRoZSBwbHVnaW4gb25jZSB2YWxpZGF0ZWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBjb25zdCBhcHBpdW0gPSBuZXcgQXBwaXVtRHJpdmVyKHtwbHVnaW46IHthcmdzOiB7cmFuZG9tQXJnOiAxMjM0fX19KTtcbiAgICAgIGFwcGl1bS5wbHVnaW5DbGFzc2VzID0gW0FyZ3NQbHVnaW5dO1xuICAgICAgY29uc3QgcGx1Z2luID0gYXBwaXVtLmNyZWF0ZVBsdWdpbkluc3RhbmNlcygpWzBdO1xuICAgICAgcGx1Z2luLmNsaUFyZ3Muc2hvdWxkLmVxbCh7cmFuZG9tQXJnOiAxMjM0fSk7XG4gICAgfSk7XG4gIH0pO1xufSk7XG4iXSwiZmlsZSI6InRlc3QvZHJpdmVyLXNwZWNzLmpzIiwic291cmNlUm9vdCI6Ii4uLy4uIn0=
@@ -0,0 +1,181 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ require("source-map-support/register");
6
+
7
+ var _fs = require("fs");
8
+
9
+ var _path = _interopRequireDefault(require("path"));
10
+
11
+ var _sinon = _interopRequireDefault(require("sinon"));
12
+
13
+ var _yaml = _interopRequireDefault(require("yaml"));
14
+
15
+ var _helpers = require("./helpers");
16
+
17
+ const expect = chai.expect;
18
+ describe('ExtensionConfigIO', function () {
19
+ let sandbox;
20
+ let yamlFixture;
21
+ before(async function () {
22
+ yamlFixture = await _fs.promises.readFile(_path.default.join(__dirname, 'fixtures', 'extensions.yaml'), 'utf8');
23
+ });
24
+ let getExtConfigIOInstance;
25
+ let mocks;
26
+ beforeEach(function () {
27
+ sandbox = _sinon.default.createSandbox();
28
+ mocks = {
29
+ '@appium/support': {
30
+ fs: {
31
+ readFile: sandbox.stub().resolves(yamlFixture),
32
+ writeFile: sandbox.stub().resolves(true)
33
+ },
34
+ mkdirp: sandbox.stub().resolves()
35
+ }
36
+ };
37
+ getExtConfigIOInstance = _helpers.rewiremock.proxy('../lib/ext-config-io', mocks).getExtConfigIOInstance;
38
+ });
39
+ afterEach(function () {
40
+ sandbox.restore();
41
+ getExtConfigIOInstance.cache = new Map();
42
+ });
43
+ describe('instantiation', function () {
44
+ describe('when called twice with the same `appiumHome` value', function () {
45
+ it('should return the same object both times', function () {
46
+ const firstInstance = getExtConfigIOInstance('/some/path');
47
+ const secondInstance = getExtConfigIOInstance('/some/path');
48
+ expect(firstInstance).to.equal(secondInstance);
49
+ });
50
+ });
51
+ describe('when called twice with different `appiumHome` values', function () {
52
+ it('should return different objects', function () {
53
+ const firstInstance = getExtConfigIOInstance('/some/path');
54
+ const secondInstance = getExtConfigIOInstance('/some/other/path');
55
+ expect(firstInstance).to.not.equal(secondInstance);
56
+ });
57
+ });
58
+ });
59
+ describe('property', function () {
60
+ describe('filepath', function () {
61
+ it('should not be writable', function () {
62
+ const instance = getExtConfigIOInstance('/some/path');
63
+ expect(() => {
64
+ instance.filepath = '/some/other/path';
65
+ }).to.throw(TypeError);
66
+ });
67
+ });
68
+ });
69
+ describe('read()', function () {
70
+ let io;
71
+ beforeEach(function () {
72
+ io = getExtConfigIOInstance('/some/path');
73
+ });
74
+ describe('when called with a valid extension type', function () {
75
+ describe('when the file does not yet exist', function () {
76
+ beforeEach(async function () {
77
+ const err = new Error();
78
+ err.code = 'ENOENT';
79
+ mocks['@appium/support'].fs.readFile.rejects(err);
80
+ await io.read('driver');
81
+ });
82
+ it('should create a new file', function () {
83
+ expect(mocks['@appium/support'].fs.writeFile).to.be.calledOnceWith(io.filepath, _yaml.default.stringify({
84
+ drivers: {},
85
+ plugins: {},
86
+ schemaRev: 2
87
+ }), 'utf8');
88
+ });
89
+ });
90
+ describe('when the file already exists', function () {
91
+ beforeEach(async function () {
92
+ await io.read('driver');
93
+ });
94
+ it('should attempt to create the `appiumHome` directory', function () {
95
+ expect(mocks['@appium/support'].mkdirp).to.have.been.calledOnceWith('/some/path');
96
+ });
97
+ it('should attempt to read the file at `filepath`', function () {
98
+ expect(mocks['@appium/support'].fs.readFile).to.have.been.calledOnceWith(io.filepath, 'utf8');
99
+ });
100
+ });
101
+ });
102
+ describe('when called with an unknown extension type`', function () {
103
+ it('should reject', async function () {
104
+ const promise = io.read('unknown');
105
+ return await expect(promise).to.be.rejectedWith(TypeError, /invalid extension type/i);
106
+ });
107
+ });
108
+ describe('when called twice with the same `extensionType`', function () {
109
+ it('should return the same object both times', async function () {
110
+ const firstInstance = await io.read('driver');
111
+ const secondInstance = await io.read('driver');
112
+ expect(firstInstance).to.equal(secondInstance);
113
+ });
114
+ });
115
+ });
116
+ describe('write()', function () {
117
+ let io;
118
+ let driverData;
119
+ beforeEach(function () {
120
+ io = getExtConfigIOInstance('/some/path');
121
+ });
122
+ describe('when called after `read()`', function () {
123
+ beforeEach(async function () {
124
+ driverData = await io.read('driver');
125
+ });
126
+ describe('when called without modifying the data', function () {
127
+ it('should not write the file', async function () {
128
+ expect(await io.write()).to.be.false;
129
+ });
130
+ });
131
+ describe('when called after adding a property', function () {
132
+ beforeEach(function () {
133
+ driverData.foo = {
134
+ name: 'foo',
135
+ version: '1.0.0',
136
+ path: '/foo/path'
137
+ };
138
+ });
139
+ it('should write the file', async function () {
140
+ expect(await io.write()).to.be.true;
141
+ });
142
+ });
143
+ describe('when called after deleting a property', function () {
144
+ beforeEach(function () {
145
+ driverData.foo = {
146
+ name: 'foo',
147
+ version: '1.0.0',
148
+ path: '/foo/path'
149
+ };
150
+ io._dirty = false;
151
+ delete driverData.foo;
152
+ });
153
+ it('should write the file', async function () {
154
+ expect(await io.write()).to.be.true;
155
+ });
156
+ });
157
+ describe('when the config file could not be written', function () {
158
+ beforeEach(function () {
159
+ mocks['@appium/support'].fs.writeFile = sandbox.stub().rejects(new Error());
160
+ io._dirty = true;
161
+ });
162
+ it('should reject', async function () {
163
+ await expect(io.write()).to.be.rejectedWith(Error, /Appium could not parse or write/i);
164
+ });
165
+ });
166
+ });
167
+ describe('when called before `read()`', function () {
168
+ it('should return `false`', async function () {
169
+ expect(await io.write()).to.be.false;
170
+ });
171
+ describe('when called with `force: true`', function () {
172
+ it('should reject', async function () {
173
+ await expect(io.write(true)).to.be.rejectedWith(ReferenceError, 'No data to write. Call `read()` first');
174
+ });
175
+ });
176
+ });
177
+ });
178
+ });require('source-map-support').install();
179
+
180
+
181
+ //# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbInRlc3QvZXh0LWNvbmZpZy1pby1zcGVjcy5qcyJdLCJuYW1lcyI6WyJleHBlY3QiLCJjaGFpIiwiZGVzY3JpYmUiLCJzYW5kYm94IiwieWFtbEZpeHR1cmUiLCJiZWZvcmUiLCJmcyIsInJlYWRGaWxlIiwicGF0aCIsImpvaW4iLCJfX2Rpcm5hbWUiLCJnZXRFeHRDb25maWdJT0luc3RhbmNlIiwibW9ja3MiLCJiZWZvcmVFYWNoIiwic2lub24iLCJjcmVhdGVTYW5kYm94Iiwic3R1YiIsInJlc29sdmVzIiwid3JpdGVGaWxlIiwibWtkaXJwIiwicmV3aXJlbW9jayIsInByb3h5IiwiYWZ0ZXJFYWNoIiwicmVzdG9yZSIsImNhY2hlIiwiTWFwIiwiaXQiLCJmaXJzdEluc3RhbmNlIiwic2Vjb25kSW5zdGFuY2UiLCJ0byIsImVxdWFsIiwibm90IiwiaW5zdGFuY2UiLCJmaWxlcGF0aCIsInRocm93IiwiVHlwZUVycm9yIiwiaW8iLCJlcnIiLCJFcnJvciIsImNvZGUiLCJyZWplY3RzIiwicmVhZCIsImJlIiwiY2FsbGVkT25jZVdpdGgiLCJZQU1MIiwic3RyaW5naWZ5IiwiZHJpdmVycyIsInBsdWdpbnMiLCJzY2hlbWFSZXYiLCJoYXZlIiwiYmVlbiIsInByb21pc2UiLCJyZWplY3RlZFdpdGgiLCJkcml2ZXJEYXRhIiwid3JpdGUiLCJmYWxzZSIsImZvbyIsIm5hbWUiLCJ2ZXJzaW9uIiwidHJ1ZSIsIl9kaXJ0eSIsIlJlZmVyZW5jZUVycm9yIl0sIm1hcHBpbmdzIjoiOzs7Ozs7QUFFQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQTs7QUFDQSxNQUFNQSxNQUFNLEdBQUdDLElBQUksQ0FBQ0QsTUFBcEI7QUFFQUUsUUFBUSxDQUFDLG1CQUFELEVBQXNCLFlBQVk7QUFJeEMsTUFBSUMsT0FBSjtBQUdBLE1BQUlDLFdBQUo7QUFFQUMsRUFBQUEsTUFBTSxDQUFDLGtCQUFrQjtBQUN2QkQsSUFBQUEsV0FBVyxHQUFHLE1BQU1FLGFBQUdDLFFBQUgsQ0FDbEJD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QUFzREFwQyxJQUFBQSxRQUFRLENBQUMsNkJBQUQsRUFBZ0MsWUFBWTtBQUNsRHdCLE1BQUFBLEVBQUUsQ0FBQyx1QkFBRCxFQUEwQixrQkFBa0I7QUFDNUMxQixRQUFBQSxNQUFNLENBQUMsTUFBTW9DLEVBQUUsQ0FBQ2tCLEtBQUgsRUFBUCxDQUFOLENBQXlCekIsRUFBekIsQ0FBNEJhLEVBQTVCLENBQStCYSxLQUEvQjtBQUNELE9BRkMsQ0FBRjtBQUlBckQsTUFBQUEsUUFBUSxDQUFDLGdDQUFELEVBQW1DLFlBQVk7QUFDckR3QixRQUFBQSxFQUFFLENBQUMsZUFBRCxFQUFrQixrQkFBa0I7QUFDcEMsZ0JBQU0xQixNQUFNLENBQUNvQyxFQUFFLENBQUNrQixLQUFILENBQVMsSUFBVCxDQUFELENBQU4sQ0FBdUJ6QixFQUF2QixDQUEwQmEsRUFBMUIsQ0FBNkJVLFlBQTdCLENBQTBDUyxjQUExQyxFQUEwRCx1Q0FBMUQsQ0FBTjtBQUNELFNBRkMsQ0FBRjtBQUdELE9BSk8sQ0FBUjtBQUtELEtBVk8sQ0FBUjtBQVdELEdBekVPLENBQVI7QUEwRUQsQ0F2Tk8sQ0FBUiIsInNvdXJjZXNDb250ZW50IjpbIi8vIEB0cy1jaGVja1xuXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmcyB9IGZyb20gJ2ZzJztcbmltcG9ydCBwYXRoIGZyb20gJ3BhdGgnO1xuaW1wb3J0IHNpbm9uIGZyb20gJ3Npbm9uJztcbmltcG9ydCBZQU1MIGZyb20gJ3lhbWwnO1xuaW1wb3J0IHsgcmV3aXJlbW9jayB9IGZyb20gJy4vaGVscGVycyc7XG5jb25zdCBleHBlY3QgPSBjaGFpLmV4cGVjdDtcblxuZGVzY3JpYmUoJ0V4dGVuc2lvbkNvbmZpZ0lPJywgZnVuY3Rpb24gKCkge1xuICAvKipcbiAgICogQHR5cGUge2ltcG9ydCgnc2lub24nKS5TaW5vblNhbmRib3h9XG4gICAqL1xuICBsZXQgc2FuZGJveDtcblxuICAvKiogQHR5cGUge3N0cmluZ30gKi9cbiAgbGV0IHlhbWxGaXh0dXJlO1xuXG4gIGJlZm9yZShhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgeWFtbEZpeHR1cmUgPSBhd2FpdCBmcy5yZWFkRmlsZShcbiAgICAgIHBhdGguam9pbihfX2Rpcm5hbWUsICdmaXh0dXJlcycsICdleHRlbnNpb25zLnlhbWwnKSxcbiAgICAgICd1dGY4JyxcbiAgICApO1xuICB9KTtcblxuICAvKipcbiAgICogQHR5cGUge3R5cGVvZiBpbXBvcnQoJy4uL2xpYi9leHQtY29uZmlnLWlvJykuZ2V0RXh0Q29uZmlnSU9JbnN0YW5jZX1cbiAgICovXG4gIGxldCBnZXRFeHRDb25maWdJT0luc3RhbmNlO1xuXG4gIGxldCBtb2NrcztcblxuICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICBzYW5kYm94ID0gc2lub24uY3JlYXRlU2FuZGJveCgpO1xuICAgIG1vY2tzID0ge1xuICAgICAgJ0BhcHBpdW0vc3VwcG9ydCc6IHtcbiAgICAgICAgZnM6IHtcbiAgICAgICAgICByZWFkRmlsZTogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoeWFtbEZpeHR1cmUpLFxuICAgICAgICAgIHdyaXRlRmlsZTogc2FuZGJveC5zdHViKCkucmVzb2x2ZXModHJ1ZSksXG4gICAgICAgIH0sXG4gICAgICAgIG1rZGlycDogc2FuZGJveC5zdHViKCkucmVzb2x2ZXMoKSxcbiAgICAgIH0sXG4gICAgfTtcbiAgICBnZXRFeHRDb25maWdJT0luc3RhbmNlID0gcmV3aXJlbW9jay5wcm94eShcbiAgICAgICcuLi9saWIvZXh0LWNvbmZpZy1pbycsXG4gICAgICBtb2NrcyxcbiAgICApLmdldEV4dENvbmZpZ0lPSW5zdGFuY2U7XG4gIH0pO1xuXG4gIGFmdGVyRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgc2FuZGJveC5yZXN0b3JlKCk7XG4gICAgZ2V0RXh0Q29uZmlnSU9JbnN0YW5jZS5jYWNoZSA9IG5ldyBNYXAoKTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ2luc3RhbnRpYXRpb24nLCBmdW5jdGlvbiAoKSB7XG4gICAgZGVzY3JpYmUoJ3doZW4gY2FsbGVkIHR3aWNlIHdpdGggdGhlIHNhbWUgYGFwcGl1bUhvbWVgIHZhbHVlJywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gdGhlIHNhbWUgb2JqZWN0IGJvdGggdGltZXMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnN0IGZpcnN0SW5zdGFuY2UgPSBnZXRFeHRDb25maWdJT0luc3RhbmNlKCcvc29tZS9wYXRoJyk7XG4gICAgICAgIGNvbnN0IHNlY29uZEluc3RhbmNlID0gZ2V0RXh0Q29uZmlnSU9JbnN0YW5jZSgnL3NvbWUvcGF0aCcpO1xuICAgICAgICBleHBlY3QoZmlyc3RJbnN0YW5jZSkudG8uZXF1YWwoc2Vjb25kSW5zdGFuY2UpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgdHdpY2Ugd2l0aCBkaWZmZXJlbnQgYGFwcGl1bUhvbWVgIHZhbHVlcycsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgcmV0dXJuIGRpZmZlcmVudCBvYmplY3RzJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBmaXJzdEluc3RhbmNlID0gZ2V0RXh0Q29uZmlnSU9JbnN0YW5jZSgnL3NvbWUvcGF0aCcpO1xuICAgICAgICBjb25zdCBzZWNvbmRJbnN0YW5jZSA9IGdldEV4dENvbmZpZ0lPSW5zdGFuY2UoJy9zb21lL290aGVyL3BhdGgnKTtcbiAgICAgICAgZXhwZWN0KGZpcnN0SW5zdGFuY2UpLnRvLm5vdC5lcXVhbChzZWNvbmRJbnN0YW5jZSk7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3Byb3BlcnR5JywgZnVuY3Rpb24gKCkge1xuICAgIGRlc2NyaWJlKCdmaWxlcGF0aCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgbm90IGJlIHdyaXRhYmxlJywgZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25zdCBpbnN0YW5jZSA9IGdldEV4dENvbmZpZ0lPSW5zdGFuY2UoJy9zb21lL3BhdGgnKTtcbiAgICAgICAgZXhwZWN0KCgpID0+IHtcbiAgICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgICAgaW5zdGFuY2UuZmlsZXBhdGggPSAnL3NvbWUvb3RoZXIvcGF0aCc7XG4gICAgICAgIH0pLnRvLnRocm93KFR5cGVFcnJvcik7XG4gICAgICB9KTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3JlYWQoKScsIGZ1bmN0aW9uICgpIHtcbiAgICAvKiogQHR5cGUge2ltcG9ydCgnLi4vbGliL2V4dC1jb25maWctaW8nKS5FeHRlbnNpb25Db25maWdJT30gKi9cbiAgICBsZXQgaW87XG5cbiAgICBiZWZvcmVFYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIGlvID0gZ2V0RXh0Q29uZmlnSU9JbnN0YW5jZSgnL3NvbWUvcGF0aCcpO1xuICAgIH0pO1xuXG4gICAgZGVzY3JpYmUoJ3doZW4gY2FsbGVkIHdpdGggYSB2YWxpZCBleHRlbnNpb24gdHlwZScsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGRlc2NyaWJlKCd3aGVuIHRoZSBmaWxlIGRvZXMgbm90IHlldCBleGlzdCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYmVmb3JlRWFjaChhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgLyoqIEB0eXBlIHtOb2RlSlMuRXJybm9FeGNlcHRpb259ICovXG4gICAgICAgICAgY29uc3QgZXJyID0gbmV3IEVycm9yKCk7XG4gICAgICAgICAgZXJyLmNvZGUgPSAnRU5PRU5UJztcbiAgICAgICAgICBtb2Nrc1snQGFwcGl1bS9zdXBwb3J0J10uZnMucmVhZEZpbGUucmVqZWN0cyhlcnIpO1xuICAgICAgICAgIGF3YWl0IGlvLnJlYWQoJ2RyaXZlcicpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIGNyZWF0ZSBhIG5ldyBmaWxlJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGV4cGVjdChtb2Nrc1snQGFwcGl1bS9zdXBwb3J0J10uZnMud3JpdGVGaWxlKS50by5iZS5jYWxsZWRPbmNlV2l0aChcbiAgICAgICAgICAgIGlvLmZpbGVwYXRoLFxuICAgICAgICAgICAgWUFNTC5zdHJpbmdpZnkoe2RyaXZlcnM6IHt9LCBwbHVnaW5zOiB7fSwgc2NoZW1hUmV2OiAyfSksXG4gICAgICAgICAgICAndXRmOCcsXG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJ3doZW4gdGhlIGZpbGUgYWxyZWFkeSBleGlzdHMnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJlZm9yZUVhY2goYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IGlvLnJlYWQoJ2RyaXZlcicpO1xuICAgICAgICB9KTtcblxuICAgICAgICBpdCgnc2hvdWxkIGF0dGVtcHQgdG8gY3JlYXRlIHRoZSBgYXBwaXVtSG9tZWAgZGlyZWN0b3J5JywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGV4cGVjdChtb2Nrc1snQGFwcGl1bS9zdXBwb3J0J10ubWtkaXJwKS50by5oYXZlLmJlZW4uY2FsbGVkT25jZVdpdGgoXG4gICAgICAgICAgICAnL3NvbWUvcGF0aCcsXG4gICAgICAgICAgKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCBhdHRlbXB0IHRvIHJlYWQgdGhlIGZpbGUgYXQgYGZpbGVwYXRoYCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBleHBlY3QoXG4gICAgICAgICAgICBtb2Nrc1snQGFwcGl1bS9zdXBwb3J0J10uZnMucmVhZEZpbGUsXG4gICAgICAgICAgKS50by5oYXZlLmJlZW4uY2FsbGVkT25jZVdpdGgoaW8uZmlsZXBhdGgsICd1dGY4Jyk7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgd2l0aCBhbiB1bmtub3duIGV4dGVuc2lvbiB0eXBlYCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgIGl0KCdzaG91bGQgcmVqZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBAdHMtaWdub3JlXG4gICAgICAgIGNvbnN0IHByb21pc2UgPSBpby5yZWFkKCd1bmtub3duJyk7XG4gICAgICAgIHJldHVybiBhd2FpdCBleHBlY3QocHJvbWlzZSkudG8uYmUucmVqZWN0ZWRXaXRoKFxuICAgICAgICAgIFR5cGVFcnJvcixcbiAgICAgICAgICAvaW52YWxpZCBleHRlbnNpb24gdHlwZS9pLFxuICAgICAgICApO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgdHdpY2Ugd2l0aCB0aGUgc2FtZSBgZXh0ZW5zaW9uVHlwZWAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpdCgnc2hvdWxkIHJldHVybiB0aGUgc2FtZSBvYmplY3QgYm90aCB0aW1lcycsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY29uc3QgZmlyc3RJbnN0YW5jZSA9IGF3YWl0IGlvLnJlYWQoJ2RyaXZlcicpO1xuICAgICAgICBjb25zdCBzZWNvbmRJbnN0YW5jZSA9IGF3YWl0IGlvLnJlYWQoJ2RyaXZlcicpO1xuICAgICAgICBleHBlY3QoZmlyc3RJbnN0YW5jZSkudG8uZXF1YWwoc2Vjb25kSW5zdGFuY2UpO1xuICAgICAgfSk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd3cml0ZSgpJywgZnVuY3Rpb24gKCkge1xuICAgIGxldCBpbztcbiAgICBsZXQgZHJpdmVyRGF0YTtcblxuICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgaW8gPSBnZXRFeHRDb25maWdJT0luc3RhbmNlKCcvc29tZS9wYXRoJyk7XG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgYWZ0ZXIgYHJlYWQoKWAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICBiZWZvcmVFYWNoKGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZHJpdmVyRGF0YSA9IGF3YWl0IGlvLnJlYWQoJ2RyaXZlcicpO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIGNhbGxlZCB3aXRob3V0IG1vZGlmeWluZyB0aGUgZGF0YScsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaXQoJ3Nob3VsZCBub3Qgd3JpdGUgdGhlIGZpbGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZXhwZWN0KGF3YWl0IGlvLndyaXRlKCkpLnRvLmJlLmZhbHNlO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgYWZ0ZXIgYWRkaW5nIGEgcHJvcGVydHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGRyaXZlckRhdGEuZm9vID0ge1xuICAgICAgICAgICAgbmFtZTogJ2ZvbycsXG4gICAgICAgICAgICB2ZXJzaW9uOiAnMS4wLjAnLFxuICAgICAgICAgICAgcGF0aDogJy9mb28vcGF0aCcsXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgaXQoJ3Nob3VsZCB3cml0ZSB0aGUgZmlsZScsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBleHBlY3QoYXdhaXQgaW8ud3JpdGUoKSkudG8uYmUudHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICB9KTtcblxuICAgICAgZGVzY3JpYmUoJ3doZW4gY2FsbGVkIGFmdGVyIGRlbGV0aW5nIGEgcHJvcGVydHknLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGJlZm9yZUVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGRyaXZlckRhdGEuZm9vID0ge1xuICAgICAgICAgICAgbmFtZTogJ2ZvbycsXG4gICAgICAgICAgICB2ZXJzaW9uOiAnMS4wLjAnLFxuICAgICAgICAgICAgcGF0aDogJy9mb28vcGF0aCcsXG4gICAgICAgICAgfTtcbiAgICAgICAgICBpby5fZGlydHkgPSBmYWxzZTtcbiAgICAgICAgICBkZWxldGUgZHJpdmVyRGF0YS5mb287XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgd3JpdGUgdGhlIGZpbGUnLCBhc3luYyBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgZXhwZWN0KGF3YWl0IGlvLndyaXRlKCkpLnRvLmJlLnRydWU7XG4gICAgICAgIH0pO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIHRoZSBjb25maWcgZmlsZSBjb3VsZCBub3QgYmUgd3JpdHRlbicsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgYmVmb3JlRWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgbW9ja3NbJ0BhcHBpdW0vc3VwcG9ydCddLmZzLndyaXRlRmlsZSA9IHNhbmRib3guc3R1YigpLnJlamVjdHMobmV3IEVycm9yKCkpO1xuICAgICAgICAgIGlvLl9kaXJ0eSA9IHRydWU7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGl0KCdzaG91bGQgcmVqZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IGV4cGVjdChpby53cml0ZSgpKS50by5iZS5yZWplY3RlZFdpdGgoRXJyb3IsIC9BcHBpdW0gY291bGQgbm90IHBhcnNlIG9yIHdyaXRlL2kpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgfSk7XG5cbiAgICBkZXNjcmliZSgnd2hlbiBjYWxsZWQgYmVmb3JlIGByZWFkKClgJywgZnVuY3Rpb24gKCkge1xuICAgICAgaXQoJ3Nob3VsZCByZXR1cm4gYGZhbHNlYCcsIGFzeW5jIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgZXhwZWN0KGF3YWl0IGlvLndyaXRlKCkpLnRvLmJlLmZhbHNlO1xuICAgICAgfSk7XG5cbiAgICAgIGRlc2NyaWJlKCd3aGVuIGNhbGxlZCB3aXRoIGBmb3JjZTogdHJ1ZWAnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGl0KCdzaG91bGQgcmVqZWN0JywgYXN5bmMgZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGF3YWl0IGV4cGVjdChpby53cml0ZSh0cnVlKSkudG8uYmUucmVqZWN0ZWRXaXRoKFJlZmVyZW5jZUVycm9yLCAnTm8gZGF0YSB0byB3cml0ZS4gQ2FsbCBgcmVhZCgpYCBmaXJzdCcpO1xuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH0pO1xuICB9KTtcbn0pO1xuIl0sImZpbGUiOiJ0ZXN0L2V4dC1jb25maWctaW8tc3BlY3MuanMiLCJzb3VyY2VSb290IjoiLi4vLi4ifQ==