/ cloudformation-templates / node_modules / aws-cdk / test / api / sdk-provider.test.js
sdk-provider.test.js
  1  "use strict";
  2  Object.defineProperty(exports, "__esModule", { value: true });
  3  const os = require("os");
  4  const cxapi = require("@aws-cdk/cx-api");
  5  const AWS = require("aws-sdk");
  6  const promptly = require("promptly");
  7  const uuid = require("uuid");
  8  const aws_auth_1 = require("../../lib/api/aws-auth");
  9  const logging = require("../../lib/logging");
 10  const plugin_1 = require("../../lib/plugin");
 11  const bockfs = require("../bockfs");
 12  const util_1 = require("../util");
 13  const fake_sts_1 = require("./fake-sts");
 14  jest.mock('promptly', () => ({
 15      prompt: jest.fn().mockResolvedValue('1234'),
 16  }));
 17  const defaultCredOptions = {
 18      ec2creds: false,
 19      containerCreds: false,
 20  };
 21  let uid;
 22  let pluginQueried = false;
 23  beforeEach(() => {
 24      // Cache busters!
 25      // We prefix everything with UUIDs because:
 26      //
 27      // - We have a cache from account# -> credentials
 28      // - We have a cache from access key -> account
 29      uid = `(${uuid.v4()})`;
 30      logging.setLogLevel(2 /* TRACE */);
 31      plugin_1.PluginHost.instance.credentialProviderSources.splice(0);
 32      plugin_1.PluginHost.instance.credentialProviderSources.push({
 33          isAvailable() { return Promise.resolve(true); },
 34          canProvideCredentials(account) { return Promise.resolve(account === uniq('99999')); },
 35          getProvider() {
 36              pluginQueried = true;
 37              return Promise.resolve(new AWS.Credentials({
 38                  accessKeyId: `${uid}plugin_key`,
 39                  secretAccessKey: 'plugin_secret',
 40                  sessionToken: 'plugin_token',
 41              }));
 42          },
 43          name: 'test plugin',
 44      });
 45      // Make sure these point to nonexistant files to start, if we don't call
 46      // prepare() then we don't accidentally want to fall back to system config.
 47      process.env.AWS_CONFIG_FILE = '/dev/null';
 48      process.env.AWS_SHARED_CREDENTIALS_FILE = '/dev/null';
 49  });
 50  afterEach(() => {
 51      bockfs.restore();
 52  });
 53  function uniq(account) {
 54      return `${uid}${account}`;
 55  }
 56  function env(account) {
 57      return cxapi.EnvironmentUtils.make(account, 'def');
 58  }
 59  describe('with intercepted network calls', () => {
 60      // Most tests will use intercepted network calls, except one test that tests
 61      // that the right HTTP `Agent` is used.
 62      let fakeSts;
 63      beforeEach(() => {
 64          fakeSts = new fake_sts_1.FakeSts();
 65          fakeSts.begin();
 66          // Make sure the KeyID returned by the plugin is recognized
 67          fakeSts.registerUser(uniq('99999'), uniq('plugin_key'));
 68      });
 69      afterEach(() => {
 70          fakeSts.restore();
 71      });
 72      // Set of tests where the CDK will not trigger assume-role
 73      // (the INI file might still do assume-role)
 74      describe('when CDK does not AssumeRole', () => {
 75          test('uses default credentials by default', async () => {
 76              // WHEN
 77              prepareCreds({
 78                  fakeSts,
 79                  credentials: {
 80                      default: { aws_access_key_id: 'access', $account: '11111', $fakeStsOptions: { partition: 'aws-here' } },
 81                  },
 82                  config: {
 83                      default: { region: 'eu-bla-5' },
 84                  },
 85              });
 86              const provider = await providerFromProfile(undefined);
 87              // THEN
 88              expect(provider.defaultRegion).toEqual('eu-bla-5');
 89              await expect(provider.defaultAccount()).resolves.toEqual({ accountId: uniq('11111'), partition: 'aws-here' });
 90              // Ask for a different region
 91              const sdk = await provider.forEnvironment({ ...env(uniq('11111')), region: 'rgn' }, aws_auth_1.Mode.ForReading);
 92              expect(sdkConfig(sdk).credentials.accessKeyId).toEqual(uniq('access'));
 93              expect(sdk.currentRegion).toEqual('rgn');
 94          });
 95          test('throws if profile credentials are not for the right account', async () => {
 96              // WHEN
 97              prepareCreds({
 98                  fakeSts,
 99                  config: {
100                      'profile boo': { aws_access_key_id: 'access', $account: '11111' },
101                  },
102              });
103              const provider = await providerFromProfile('boo');
104              await expect(provider.forEnvironment(env(uniq('some_account_#')), aws_auth_1.Mode.ForReading)).rejects.toThrow('Need to perform AWS calls');
105          });
106          test('use profile acct/region if agnostic env requested', async () => {
107              // WHEN
108              prepareCreds({
109                  fakeSts,
110                  credentials: {
111                      default: { aws_access_key_id: 'access', $account: '11111' },
112                  },
113                  config: {
114                      default: { region: 'eu-bla-5' },
115                  },
116              });
117              const provider = await providerFromProfile(undefined);
118              // THEN
119              const sdk = await provider.forEnvironment(cxapi.EnvironmentUtils.make(cxapi.UNKNOWN_ACCOUNT, cxapi.UNKNOWN_REGION), aws_auth_1.Mode.ForReading);
120              expect(sdkConfig(sdk).credentials.accessKeyId).toEqual(uniq('access'));
121              expect((await sdk.currentAccount()).accountId).toEqual(uniq('11111'));
122              expect(sdk.currentRegion).toEqual('eu-bla-5');
123          });
124          test('passing profile skips EnvironmentCredentials', async () => {
125              // GIVEN
126              prepareCreds({
127                  fakeSts,
128                  credentials: {
129                      foo: { aws_access_key_id: 'access', $account: '11111' },
130                  },
131              });
132              const provider = await providerFromProfile('foo');
133              const environmentCredentialsPrototype = (new AWS.EnvironmentCredentials('AWS')).constructor.prototype;
134              await util_1.withMocked(environmentCredentialsPrototype, 'refresh', async (refresh) => {
135                  var _a;
136                  refresh.mockImplementation((callback) => callback(new Error('This function should not have been called')));
137                  // WHEN
138                  expect((_a = (await provider.defaultAccount())) === null || _a === void 0 ? void 0 : _a.accountId).toEqual(uniq('11111'));
139                  expect(refresh).not.toHaveBeenCalled();
140              });
141          });
142          test('supports profile spread over config_file and credentials_file', async () => {
143              // WHEN
144              prepareCreds({
145                  fakeSts,
146                  credentials: {
147                      foo: { aws_access_key_id: 'fooccess', $account: '22222' },
148                  },
149                  config: {
150                      'default': { region: 'eu-bla-5' },
151                      'profile foo': { region: 'eu-west-1' },
152                  },
153              });
154              const provider = await aws_auth_1.SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile: 'foo' });
155              // THEN
156              expect(provider.defaultRegion).toEqual('eu-west-1');
157              await expect(provider.defaultAccount()).resolves.toEqual({ accountId: uniq('22222'), partition: 'aws' });
158              const sdk = await provider.forEnvironment(env(uniq('22222')), aws_auth_1.Mode.ForReading);
159              expect(sdkConfig(sdk).credentials.accessKeyId).toEqual(uniq('fooccess'));
160          });
161          test('supports profile only in config_file', async () => {
162              // WHEN
163              prepareCreds({
164                  fakeSts,
165                  config: {
166                      'default': { region: 'eu-bla-5' },
167                      'profile foo': { aws_access_key_id: 'fooccess', $account: '22222' },
168                  },
169              });
170              const provider = await providerFromProfile('foo');
171              // THEN
172              expect(provider.defaultRegion).toEqual('eu-bla-5'); // Fall back to default config
173              await expect(provider.defaultAccount()).resolves.toEqual({ accountId: uniq('22222'), partition: 'aws' });
174              const sdk = await provider.forEnvironment(env(uniq('22222')), aws_auth_1.Mode.ForReading);
175              expect(sdkConfig(sdk).credentials.accessKeyId).toEqual(uniq('fooccess'));
176          });
177          test('can assume-role configured in config', async () => {
178              // GIVEN
179              prepareCreds({
180                  fakeSts,
181                  credentials: {
182                      assumer: { aws_access_key_id: 'assumer', $account: '11111' },
183                  },
184                  config: {
185                      'default': { region: 'eu-bla-5' },
186                      'profile assumer': { region: 'us-east-2' },
187                      'profile assumable': {
188                          role_arn: 'arn:aws:iam::66666:role/Assumable',
189                          source_profile: 'assumer',
190                          $account: '66666',
191                          $fakeStsOptions: { allowedAccounts: ['11111'] },
192                      },
193                  },
194              });
195              const provider = await providerFromProfile('assumable');
196              // WHEN
197              const sdk = await provider.forEnvironment(env(uniq('66666')), aws_auth_1.Mode.ForReading);
198              // THEN
199              expect((await sdk.currentAccount()).accountId).toEqual(uniq('66666'));
200          });
201          test('can assume role even if [default] profile is missing', async () => {
202              var _a;
203              // GIVEN
204              prepareCreds({
205                  fakeSts,
206                  credentials: {
207                      assumer: { aws_access_key_id: 'assumer', $account: '22222' },
208                      assumable: { role_arn: 'arn:aws:iam::12356789012:role/Assumable', source_profile: 'assumer', $account: '22222' },
209                  },
210                  config: {
211                      'profile assumable': { region: 'eu-bla-5' },
212                  },
213              });
214              // WHEN
215              const provider = await providerFromProfile('assumable');
216              // THEN
217              expect((_a = (await provider.defaultAccount())) === null || _a === void 0 ? void 0 : _a.accountId).toEqual(uniq('22222'));
218          });
219          test('mfa_serial in profile will ask user for token', async () => {
220              // GIVEN
221              prepareCreds({
222                  fakeSts,
223                  credentials: {
224                      assumer: { aws_access_key_id: 'assumer', $account: '66666' },
225                  },
226                  config: {
227                      'default': { region: 'eu-bla-5' },
228                      'profile assumer': { region: 'us-east-2' },
229                      'profile mfa-role': {
230                          role_arn: 'arn:aws:iam::66666:role/Assumable',
231                          source_profile: 'assumer',
232                          mfa_serial: 'arn:aws:iam::account:mfa/user',
233                          $account: '66666',
234                      },
235                  },
236              });
237              const provider = await providerFromProfile('mfa-role');
238              const promptlyMockCalls = promptly.prompt.mock.calls.length;
239              // THEN
240              const sdk = await provider.forEnvironment(env(uniq('66666')), aws_auth_1.Mode.ForReading);
241              expect((await sdk.currentAccount()).accountId).toEqual(uniq('66666'));
242              expect(fakeSts.assumedRoles[0]).toEqual(expect.objectContaining({
243                  roleArn: 'arn:aws:iam::66666:role/Assumable',
244                  serialNumber: 'arn:aws:iam::account:mfa/user',
245                  tokenCode: '1234',
246              }));
247              // Mock response was set to fail to make sure we don't call STS
248              // Make sure the MFA mock was called during this test
249              expect(promptly.prompt.mock.calls.length).toBe(promptlyMockCalls + 1);
250          });
251      });
252      // For DefaultSynthesis we will do an assume-role after having gotten base credentials
253      describe('when CDK AssumeRoles', () => {
254          beforeEach(() => {
255              // All these tests share that 'arn:aws:role' is a role into account 88888 which can be assumed from 11111
256              fakeSts.registerRole(uniq('88888'), 'arn:aws:role', { allowedAccounts: [uniq('11111')] });
257          });
258          test('error we get from assuming a role is useful', async () => {
259              // GIVEN
260              prepareCreds({
261                  fakeSts,
262                  config: {
263                      default: { aws_access_key_id: 'foo' },
264                  },
265              });
266              const provider = await providerFromProfile(undefined);
267              // WHEN
268              const promise = provider.forEnvironment(env(uniq('88888')), aws_auth_1.Mode.ForReading, {
269                  assumeRoleArn: 'doesnotexist.role.arn',
270              });
271              // THEN - error message contains both a helpful hint and the underlying AssumeRole message
272              await expect(promise).rejects.toThrow('(re)-bootstrap the environment');
273              await expect(promise).rejects.toThrow('doesnotexist.role.arn');
274          });
275          test('assuming a role sanitizes the username into the session name', async () => {
276              // GIVEN
277              prepareCreds({
278                  fakeSts,
279                  config: {
280                      default: { aws_access_key_id: 'foo', $account: '11111' },
281                  },
282              });
283              await util_1.withMocked(os, 'userInfo', async (userInfo) => {
284                  userInfo.mockReturnValue({ username: 'skål', uid: 1, gid: 1, homedir: '/here', shell: '/bin/sh' });
285                  // WHEN
286                  const provider = await providerFromProfile(undefined);
287                  const sdk = await provider.forEnvironment(env(uniq('88888')), aws_auth_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' });
288                  await sdk.currentAccount();
289                  // THEN
290                  expect(fakeSts.assumedRoles[0]).toEqual(expect.objectContaining({
291                      roleSessionName: 'aws-cdk-sk@l',
292                  }));
293              });
294          });
295          test('even if current credentials are for the wrong account, we will still use them to AssumeRole', async () => {
296              // GIVEN
297              prepareCreds({
298                  fakeSts,
299                  config: {
300                      default: { aws_access_key_id: 'foo', $account: '11111' },
301                  },
302              });
303              const provider = await providerFromProfile(undefined);
304              // WHEN
305              const sdk = await provider.forEnvironment(env(uniq('88888')), aws_auth_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' });
306              // THEN
307              expect((await sdk.currentAccount()).accountId).toEqual(uniq('88888'));
308          });
309          test('if AssumeRole fails but current credentials are for the right account, we will still use them', async () => {
310              // GIVEN
311              prepareCreds({
312                  fakeSts,
313                  config: {
314                      default: { aws_access_key_id: 'foo', $account: '88888' },
315                  },
316              });
317              const provider = await providerFromProfile(undefined);
318              // WHEN - assumeRole fails because the role can only be assumed from account 11111
319              const sdk = await provider.forEnvironment(env(uniq('88888')), aws_auth_1.Mode.ForReading, { assumeRoleArn: 'arn:aws:role' });
320              // THEN
321              expect((await sdk.currentAccount()).accountId).toEqual(uniq('88888'));
322          });
323      });
324      describe('Plugins', () => {
325          test('does not use plugins if current credentials are for expected account', async () => {
326              prepareCreds({
327                  fakeSts,
328                  config: {
329                      default: { aws_access_key_id: 'foo', $account: '11111' },
330                  },
331              });
332              const provider = await providerFromProfile(undefined);
333              await provider.forEnvironment(env(uniq('11111')), aws_auth_1.Mode.ForReading);
334              expect(pluginQueried).toEqual(false);
335          });
336          test('uses plugin for account 99999', async () => {
337              const provider = await providerFromProfile(undefined);
338              await provider.forEnvironment(env(uniq('99999')), aws_auth_1.Mode.ForReading);
339              expect(pluginQueried).toEqual(true);
340          });
341          test('can assume role with credentials from plugin', async () => {
342              fakeSts.registerRole(uniq('99999'), 'arn:aws:iam::99999:role/Assumable');
343              const provider = await providerFromProfile(undefined);
344              await provider.forEnvironment(env(uniq('99999')), aws_auth_1.Mode.ForReading, {
345                  assumeRoleArn: 'arn:aws:iam::99999:role/Assumable',
346              });
347              expect(fakeSts.assumedRoles[0]).toEqual(expect.objectContaining({
348                  roleArn: 'arn:aws:iam::99999:role/Assumable',
349              }));
350              expect(pluginQueried).toEqual(true);
351          });
352          test('even if AssumeRole fails but current credentials are from a plugin, we will still use them', async () => {
353              const provider = await providerFromProfile(undefined);
354              const sdk = await provider.forEnvironment(env(uniq('99999')), aws_auth_1.Mode.ForReading, { assumeRoleArn: 'does:not:exist' });
355              // THEN
356              expect((await sdk.currentAccount()).accountId).toEqual(uniq('99999'));
357          });
358          test('plugins are still queried even if current credentials are expired (or otherwise invalid)', async () => {
359              // GIVEN
360              process.env.AWS_ACCESS_KEY_ID = `${uid}akid`;
361              process.env.AWS_SECRET_ACCESS_KEY = 'sekrit';
362              const provider = await providerFromProfile(undefined);
363              // WHEN
364              await provider.forEnvironment(env(uniq('99999')), aws_auth_1.Mode.ForReading);
365              // THEN
366              expect(pluginQueried).toEqual(true);
367          });
368      });
369      describe('support for credential_source', () => {
370          test('can assume role with ecs credentials', async () => {
371              return util_1.withMocked(AWS.ECSCredentials.prototype, 'needsRefresh', async (needsRefresh) => {
372                  // GIVEN
373                  prepareCreds({
374                      config: {
375                          'profile ecs': { role_arn: 'arn:aws:iam::12356789012:role/Assumable', credential_source: 'EcsContainer', $account: '22222' },
376                      },
377                  });
378                  const provider = await providerFromProfile('ecs');
379                  // WHEN
380                  await provider.defaultAccount();
381                  // THEN
382                  expect(needsRefresh).toHaveBeenCalled();
383              });
384          });
385          test('can assume role with ec2 credentials', async () => {
386              return util_1.withMocked(AWS.EC2MetadataCredentials.prototype, 'needsRefresh', async (needsRefresh) => {
387                  // GIVEN
388                  prepareCreds({
389                      config: {
390                          'profile ecs': { role_arn: 'arn:aws:iam::12356789012:role/Assumable', credential_source: 'Ec2InstanceMetadata', $account: '22222' },
391                      },
392                  });
393                  const provider = await providerFromProfile('ecs');
394                  // WHEN
395                  await provider.defaultAccount();
396                  // THEN
397                  expect(needsRefresh).toHaveBeenCalled();
398              });
399          });
400          test('can assume role with env credentials', async () => {
401              return util_1.withMocked(AWS.EnvironmentCredentials.prototype, 'needsRefresh', async (needsRefresh) => {
402                  // GIVEN
403                  prepareCreds({
404                      config: {
405                          'profile ecs': { role_arn: 'arn:aws:iam::12356789012:role/Assumable', credential_source: 'Environment', $account: '22222' },
406                      },
407                  });
408                  const provider = await providerFromProfile('ecs');
409                  // WHEN
410                  await provider.defaultAccount();
411                  // THEN
412                  expect(needsRefresh).toHaveBeenCalled();
413              });
414          });
415          test('assume fails with unsupported credential_source', async () => {
416              // GIVEN
417              prepareCreds({
418                  config: {
419                      'profile ecs': { role_arn: 'arn:aws:iam::12356789012:role/Assumable', credential_source: 'unsupported', $account: '22222' },
420                  },
421              });
422              const provider = await providerFromProfile('ecs');
423              // WHEN
424              const account = await provider.defaultAccount();
425              // THEN
426              expect(account === null || account === void 0 ? void 0 : account.accountId).toEqual(undefined);
427          });
428      });
429      test('defaultAccount returns undefined if STS call fails', async () => {
430          // GIVEN
431          process.env.AWS_ACCESS_KEY_ID = `${uid}akid`;
432          process.env.AWS_SECRET_ACCESS_KEY = 'sekrit';
433          // WHEN
434          const provider = await providerFromProfile(undefined);
435          // THEN
436          await expect(provider.defaultAccount()).resolves.toBe(undefined);
437      });
438  });
439  test('even when using a profile to assume another profile, STS calls goes through the proxy', async () => {
440      prepareCreds({
441          credentials: {
442              assumer: { aws_access_key_id: 'assumer' },
443          },
444          config: {
445              'default': { region: 'eu-bla-5' },
446              'profile assumable': { role_arn: 'arn:aws:iam::66666:role/Assumable', source_profile: 'assumer', $account: '66666' },
447              'profile assumer': { region: 'us-east-2' },
448          },
449      });
450      // Messy mocking
451      let called = false;
452      jest.mock('proxy-agent', () => {
453          // eslint-disable-next-line @typescript-eslint/no-require-imports
454          class FakeAgent extends require('https').Agent {
455              addRequest(_, __) {
456                  // FIXME: this error takes 6 seconds to be completely handled. It
457                  // might be retries in the SDK somewhere, or something about the Node
458                  // event loop. I've spent an hour trying to figure it out and I can't,
459                  // and I gave up. We'll just have to live with this until someone gets
460                  // inspired.
461                  const error = new Error('ABORTED BY TEST');
462                  error.code = 'RequestAbortedError';
463                  error.retryable = false;
464                  called = true;
465                  throw error;
466              }
467          }
468          return FakeAgent;
469      });
470      // WHEN
471      const provider = await aws_auth_1.SdkProvider.withAwsCliCompatibleDefaults({
472          ...defaultCredOptions,
473          profile: 'assumable',
474          httpOptions: {
475              proxyAddress: 'http://DOESNTMATTER/',
476          },
477      });
478      await provider.defaultAccount();
479      // THEN -- the fake proxy agent got called, we don't care about the result
480      expect(called).toEqual(true);
481  });
482  /**
483   * Use object hackery to get the credentials out of the SDK object
484   */
485  function sdkConfig(sdk) {
486      return sdk.config;
487  }
488  /**
489   * Fixture for SDK auth for this test suite
490   *
491   * Has knowledge of the cache buster, will write proper fake config files and
492   * register users and roles in FakeSts at the same time.
493   */
494  function prepareCreds(options) {
495      function convertSections(sections) {
496          var _a, _b, _c, _d, _e, _f;
497          const ret = [];
498          for (const [profile, user] of Object.entries(sections !== null && sections !== void 0 ? sections : {})) {
499              ret.push(`[${profile}]`);
500              if (isProfileRole(user)) {
501                  ret.push(`role_arn=${user.role_arn}`);
502                  if ('source_profile' in user) {
503                      ret.push(`source_profile=${user.source_profile}`);
504                  }
505                  if ('credential_source' in user) {
506                      ret.push(`credential_source=${user.credential_source}`);
507                  }
508                  if (user.mfa_serial) {
509                      ret.push(`mfa_serial=${user.mfa_serial}`);
510                  }
511                  (_a = options.fakeSts) === null || _a === void 0 ? void 0 : _a.registerRole(uniq((_b = user.$account) !== null && _b !== void 0 ? _b : '00000'), user.role_arn, {
512                      ...user.$fakeStsOptions,
513                      allowedAccounts: (_d = (_c = user.$fakeStsOptions) === null || _c === void 0 ? void 0 : _c.allowedAccounts) === null || _d === void 0 ? void 0 : _d.map(uniq),
514                  });
515              }
516              else {
517                  if (user.aws_access_key_id) {
518                      ret.push(`aws_access_key_id=${uniq(user.aws_access_key_id)}`);
519                      ret.push('aws_secret_access_key=secret');
520                      (_e = options.fakeSts) === null || _e === void 0 ? void 0 : _e.registerUser(uniq((_f = user.$account) !== null && _f !== void 0 ? _f : '00000'), uniq(user.aws_access_key_id), user.$fakeStsOptions);
521                  }
522              }
523              if (user.region) {
524                  ret.push(`region=${user.region}`);
525              }
526          }
527          return ret.join('\n');
528      }
529      bockfs({
530          '/home/me/.bxt/credentials': convertSections(options.credentials),
531          '/home/me/.bxt/config': convertSections(options.config),
532      });
533      // Set environment variables that we want
534      process.env.AWS_CONFIG_FILE = bockfs.path('/home/me/.bxt/config');
535      process.env.AWS_SHARED_CREDENTIALS_FILE = bockfs.path('/home/me/.bxt/credentials');
536  }
537  function isProfileRole(x) {
538      return 'role_arn' in x;
539  }
540  function providerFromProfile(profile) {
541      return aws_auth_1.SdkProvider.withAwsCliCompatibleDefaults({ ...defaultCredOptions, profile });
542  }
543  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2RrLXByb3ZpZGVyLnRlc3QuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJzZGstcHJvdmlkZXIudGVzdC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHlCQUF5QjtBQUN6Qix5Q0FBeUM7QUFDekMsK0JBQStCO0FBRS9CLHFDQUFxQztBQUNyQyw2QkFBNkI7QUFDN0IscURBQXNFO0FBQ3RFLDZDQUE2QztBQUM3Qyw2Q0FBOEM7QUFDOUMsb0NBQW9DO0FBQ3BDLGtDQUFxQztBQUNyQyx5Q0FBK0U7QUFFL0UsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUMzQixNQUFNLEVBQUUsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDLGlCQUFpQixDQUFDLE1BQU0sQ0FBQztDQUM1QyxDQUFDLENBQUMsQ0FBQztBQUVKLE1BQU0sa0JBQWtCLEdBQUc7SUFDekIsUUFBUSxFQUFFLEtBQUs7SUFDZixjQUFjLEVBQUUsS0FBSztDQUN0QixDQUFDO0FBRUYsSUFBSSxHQUFXLENBQUM7QUFDaEIsSUFBSSxhQUFhLEdBQUcsS0FBSyxDQUFDO0FBRTFCLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxpQkFBaUI7SUFDakIsMkNBQTJDO0lBQzNDLEVBQUU7SUFDRixpREFBaUQ7SUFDakQsK0NBQStDO0lBQy9DLEdBQUcsR0FBRyxJQUFJLElBQUksQ0FBQyxFQUFFLEVBQUUsR0FBRyxDQUFDO0lBRXZCLE9BQU8sQ0FBQyxXQUFXLGVBQXdCLENBQUM7SUFFNUMsbUJBQVUsQ0FBQyxRQUFRLENBQUMseUJBQXlCLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hELG1CQUFVLENBQUMsUUFBUSxDQUFDLHlCQUF5QixDQUFDLElBQUksQ0FBQztRQUNqRCxXQUFXLEtBQUssT0FBTyxPQUFPLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUMvQyxxQkFBcUIsQ0FBQyxPQUFPLElB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QztvQkFDekMsTUFBQSxPQUFPLENBQUMsT0FBTywwQ0FBRSxZQUFZLENBQUMsSUFBSSxPQUFDLElBQUksQ0FBQyxRQUFRLG1DQUFJLE9BQU8sQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsaUJBQWlCLENBQUMsRUFBRSxJQUFJLENBQUMsZUFBZSxFQUFFO2lCQUNuSDthQUNGO1lBRUQsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFO2dCQUNmLEdBQUcsQ0FBQyxJQUFJLENBQUMsVUFBVSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQzthQUNuQztTQUNGO1FBQ0QsT0FBTyxHQUFHLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFRCxNQUFNLENBQUM7UUFDTCwyQkFBMkIsRUFBRSxlQUFlLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQztRQUNqRSxzQkFBc0IsRUFBRSxlQUFlLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztLQUN4RCxDQUFDLENBQUM7SUFFSCx5Q0FBeUM7SUFDekMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0lBQ2xFLE9BQU8sQ0FBQyxHQUFHLENBQUMsMkJBQTJCLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0FBQ3JGLENBQUM7QUFrQ0QsU0FBUyxhQUFhLENBQUMsQ0FBNEI7SUFDakQsT0FBTyxVQUFVLElBQUksQ0FBQyxDQUFDO0FBQ3pCLENBQUM7QUFFRCxTQUFTLG1CQUFtQixDQUFDLE9BQTJCO0lBQ3RELE9BQU8sc0JBQVcsQ0FBQyw0QkFBNEIsQ0FBQyxFQUFFLEdBQUcsa0JBQWtCLEVBQUUsT0FBTyxFQUFFLENBQUMsQ0FBQztBQUN0RixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgb3MgZnJvbSAnb3MnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCAqIGFzIEFXUyBmcm9tICdhd3Mtc2RrJztcbmltcG9ydCB0eXBlIHsgQ29uZmlndXJhdGlvbk9wdGlvbnMgfSBmcm9tICdhd3Mtc2RrL2xpYi9jb25maWctYmFzZSc7XG5pbXBvcnQgKiBhcyBwcm9tcHRseSBmcm9tICdwcm9tcHRseSc7XG5pbXBvcnQgKiBhcyB1dWlkIGZyb20gJ3V1aWQnO1xuaW1wb3J0IHsgSVNESywgTW9kZSwgU0RLLCBTZGtQcm92aWRlciB9IGZyb20gJy4uLy4uL2xpYi9hcGkvYXdzLWF1dGgnO1xuaW1wb3J0ICogYXMgbG9nZ2luZyBmcm9tICcuLi8uLi9saWIvbG9nZ2luZyc7XG5pbXBvcnQgeyBQbHVnaW5Ib3N0IH0gZnJvbSAnLi4vLi4vbGliL3BsdWdpbic7XG5pbXBvcnQgKiBhcyBib2NrZnMgZnJvbSAnLi4vYm9ja2ZzJztcbmltcG9ydCB7IHdpdGhNb2NrZWQgfSBmcm9tICcuLi91dGlsJztcbmltcG9ydCB7IEZha2VTdHMsIFJlZ2lzdGVyUm9sZU9wdGlvbnMsIFJlZ2lzdGVyVXNlck9wdGlvbnMgfSBmcm9tICcuL2Zha2Utc3RzJztcblxuamVzdC5tb2NrKCdwcm9tcHRseScsICgpID0+ICh7XG4gIHByb21wdDogamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKCcxMjM0JyksXG59KSk7XG5cbmNvbnN0IGRlZmF1bHRDcmVkT3B0aW9ucyA9IHtcbiAgZWMyY3JlZHM6IGZhbHNlLFxuICBjb250YWluZXJDcmVkczogZmFsc2UsXG59O1xuXG5sZXQgdWlkOiBzdHJpbmc7XG5sZXQgcGx1Z2luUXVlcmllZCA9IGZhbHNlO1xuXG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgLy8gQ2FjaGUgYnVzdGVycyFcbiAgLy8gV2UgcHJlZml4IGV2ZXJ5dGhpbmcgd2l0aCBVVUlEcyBiZWNhdXNlOlxuICAvL1xuICAvLyAtIFdlIGhhdmUgYSBjYWNoZSBmcm9tIGFjY291bnQjIC0+IGNyZWRlbnRpYWxzXG4gIC8vIC0gV2UgaGF2ZSBhIGNhY2hlIGZyb20gYWNjZXNzIGtleSAtPiBhY2NvdW50XG4gIHVpZCA9IGAoJHt1dWlkLnY0KCl9KWA7XG5cbiAgbG9nZ2luZy5zZXRMb2dMZXZlbChsb2dnaW5nLkxvZ0xldmVsLlRSQUNFKTtcblxuICBQbHVnaW5Ib3N0Lmluc3RhbmNlLmNyZWRlbnRpYWxQcm92aWRlclNvdXJjZXMuc3BsaWNlKDApO1xuICBQbHVnaW5Ib3N0Lmluc3RhbmNlLmNyZWRlbnRpYWxQcm92aWRlclNvdXJjZXMucHVzaCh7XG4gICAgaXNBdmFpbGFibGUoKSB7IHJldHVybiBQcm9taXNlLnJlc29sdmUodHJ1ZSk7IH0sXG4gICAgY2FuUHJvdmlkZUNyZWRlbnRpYWxzKGFjY291bnQpIHsgcmV0dXJuIFByb21pc2UucmVzb2x2ZShhY2NvdW50ID09PSB1bmlxKCc5OTk5OScpKTsgfSxcbiAgICBnZXRQcm92aWRlcigpIHtcbiAgICAgIHBsdWdpblF1ZXJpZWQgPSB0cnVlO1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShuZXcgQVdTLkNyZWRlbnRpYWxzKHtcbiAgICAgICAgYWNjZXNzS2V5SWQ6IGAke3VpZH1wbHVnaW5fa2V5YCxcbiAgICAgICAgc2VjcmV0QWNjZXNzS2V5OiAncGx1Z2luX3NlY3JldCcsXG4gICAgICAgIHNlc3Npb25Ub2tlbjogJ3BsdWdpbl90b2tlbicsXG4gICAgICB9KSk7XG4gICAgfSxcbiAgICBuYW1lOiAndGVzdCBwbHVnaW4nLFxuICB9KTtcblxuICAvLyBNYWtlIHN1cmUgdGhlc2UgcG9pbnQgdG8gbm9uZXhpc3RhbnQgZmlsZXMgdG8gc3RhcnQsIGlmIHdlIGRvbid0IGNhbGxcbiAgLy8gcHJlcGFyZSgpIHRoZW4gd2UgZG9uJ3QgYWNjaWRlbnRhbGx5IHdhbnQgdG8gZmFsbCBiYWNrIHRvIHN5c3RlbSBjb25maWcuXG4gIHByb2Nlc3MuZW52LkFXU19DT05GSUdfRklMRSA9ICcvZGV2L251bGwnO1xuICBwcm9jZXNzLmVudi5BV1NfU0hBUkVEX0NSRURFTlRJQUxTX0ZJTEUgPSAnL2Rldi9udWxsJztcbn0pO1xuXG5hZnRlckVhY2goKCkgPT4ge1xuICBib2NrZnMucmVzdG9yZSgpO1xufSk7XG5cbmZ1bmN0aW9uIHVuaXEoYWNjb3VudDogc3RyaW5nKSB7XG4gIHJldHVybiBgJHt1aWR9JHthY2NvdW50fWA7XG59XG5cbmZ1bmN0aW9uIGVudihhY2NvdW50OiBzdHJpbmcpIHtcbiAgcmV0dXJuIGN4YXBpLkVudmlyb25tZW50VXRpbHMubWFrZShhY2NvdW50LCAnZGVmJyk7XG59XG5cbmRlc2NyaWJlKCd3aXRoIGludGVyY2VwdGVkIG5ldHdvcmsgY2FsbHMnLCAoKSA9PiB7XG4gIC8vIE1vc3QgdGVzdHMgd2lsbCB1c2UgaW50ZXJjZXB0ZWQgbmV0d29yayBjYWxscywgZXhjZXB0IG9uZSB0ZXN0IHRoYXQgdGVzdHNcbiAgLy8gdGhhdCB0aGUgcmlnaHQgSFRUUCBgQWdlbnRgIGlzIHVzZWQuXG5cbiAgbGV0IGZha2VTdHM6IEZha2VTdHM7XG4gIGJlZm9yZUVhY2goKCkgPT4ge1xuICAgIGZha2VTdHMgPSBuZXcgRmFrZVN0cygpO1xuICAgIGZha2VTdHMuYmVnaW4oKTtcblxuICAgIC8vIE1ha2Ugc3VyZSB0aGUgS2V5SUQgcmV0dXJuZWQgYnkgdGhlIHBsdWdpbiBpcyByZWNvZ25pemVkXG4gICAgZmFrZVN0cy5yZWdpc3RlclVzZXIodW5pcSgnOTk5OTknKSwgdW5pcSgncGx1Z2luX2tleScpKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBmYWtlU3RzLnJlc3RvcmUoKTtcbiAgfSk7XG5cbiAgLy8gU2V0IG9mIHRlc3RzIHdoZXJlIHRoZSBDREsgd2lsbCBub3QgdHJpZ2dlciBhc3N1bWUtcm9sZVxuICAvLyAodGhlIElOSSBmaWxlIG1pZ2h0IHN0aWxsIGRvIGFzc3VtZS1yb2xlKVxuICBkZXNjcmliZSgnd2hlbiBDREsgZG9lcyBub3QgQXNzdW1lUm9sZScsICgpID0+IHtcbiAgICB0ZXN0KCd1c2VzIGRlZmF1bHQgY3JlZGVudGlhbHMgYnkgZGVmYXVsdCcsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFdIRU5cbiAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgIGZha2VTdHMsXG4gICAgICAgIGNyZWRlbnRpYWxzOiB7XG4gICAgICAgICAgZGVmYXVsdDogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2FjY2VzcycsICRhY2NvdW50OiAnMTExMTEnLCAkZmFrZVN0c09wdGlvbnM6IHsgcGFydGl0aW9uOiAnYXdzLWhlcmUnIH0gfSxcbiAgICAgICAgfSxcbiAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgZGVmYXVsdDogeyByZWdpb246ICdldS1ibGEtNScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG5cbiAgICAgIC8vIFRIRU5cbiAgICAgIGV4cGVjdChwcm92aWRlci5kZWZhdWx0UmVnaW9uKS50b0VxdWFsKCdldS1ibGEtNScpO1xuICAgICAgYXdhaXQgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRBY2NvdW50KCkpLnJlc29sdmVzLnRvRXF1YWwoeyBhY2NvdW50SWQ6IHVuaXEoJzExMTExJyksIHBhcnRpdGlvbjogJ2F3cy1oZXJlJyB9KTtcblxuICAgICAgLy8gQXNrIGZvciBhIGRpZmZlcmVudCByZWdpb25cbiAgICAgIGNvbnN0IHNkayA9IGF3YWl0IHByb3ZpZGVyLmZvckVudmlyb25tZW50KHsgLi4uZW52KHVuaXEoJzExMTExJykpLCByZWdpb246ICdyZ24nIH0sIE1vZGUuRm9yUmVhZGluZyk7XG4gICAgICBleHBlY3Qoc2RrQ29uZmlnKHNkaykuY3JlZGVudGlhbHMhLmFjY2Vzc0tleUlkKS50b0VxdWFsKHVuaXEoJ2FjY2VzcycpKTtcbiAgICAgIGV4cGVjdChzZGsuY3VycmVudFJlZ2lvbikudG9FcXVhbCgncmduJyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCd0aHJvd3MgaWYgcHJvZmlsZSBjcmVkZW50aWFscyBhcmUgbm90IGZvciB0aGUgcmlnaHQgYWNjb3VudCcsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIFdIRU5cbiAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgIGZha2VTdHMsXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICdwcm9maWxlIGJvbyc6IHsgYXdzX2FjY2Vzc19rZXlfaWQ6ICdhY2Nlc3MnLCAkYWNjb3VudDogJzExMTExJyB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUoJ2JvbycpO1xuXG4gICAgICBhd2FpdCBleHBlY3QocHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJ3NvbWVfYWNjb3VudF8jJykpLCBNb2RlLkZvclJlYWRpbmcpKS5yZWplY3RzLnRvVGhyb3coJ05lZWQgdG8gcGVyZm9ybSBBV1MgY2FsbHMnKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3VzZSBwcm9maWxlIGFjY3QvcmVnaW9uIGlmIGFnbm9zdGljIGVudiByZXF1ZXN0ZWQnLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBXSEVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICAgIGRlZmF1bHQ6IHsgYXdzX2FjY2Vzc19rZXlfaWQ6ICdhY2Nlc3MnLCAkYWNjb3VudDogJzExMTExJyB9LFxuICAgICAgICB9LFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBkZWZhdWx0OiB7IHJlZ2lvbjogJ2V1LWJsYS01JyB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUodW5kZWZpbmVkKTtcblxuICAgICAgLy8gVEhFTlxuICAgICAgY29uc3Qgc2RrID0gYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoY3hhcGkuRW52aXJvbm1lbnRVdGlscy5tYWtlKGN4YXBpLlVOS05PV05fQUNDT1VOVCwgY3hhcGkuVU5LTk9XTl9SRUdJT04pLCBNb2RlLkZvclJlYWRpbmcpO1xuICAgICAgZXhwZWN0KHNka0NvbmZpZyhzZGspLmNyZWRlbnRpYWxzIS5hY2Nlc3NLZXlJZCkudG9FcXVhbCh1bmlxKCdhY2Nlc3MnKSk7XG4gICAgICBleHBlY3QoKGF3YWl0IHNkay5jdXJyZW50QWNjb3VudCgpKS5hY2NvdW50SWQpLnRvRXF1YWwodW5pcSgnMTExMTEnKSk7XG4gICAgICBleHBlY3Qoc2RrLmN1cnJlbnRSZWdpb24pLnRvRXF1YWwoJ2V1LWJsYS01Jyk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdwYXNzaW5nIHByb2ZpbGUgc2tpcHMgRW52aXJvbm1lbnRDcmVkZW50aWFscycsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEdJVkVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjcmVkZW50aWFsczoge1xuICAgICAgICAgIGZvbzogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2FjY2VzcycsICRhY2NvdW50OiAnMTExMTEnIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvdmlkZXJGcm9tUHJvZmlsZSgnZm9vJyk7XG5cbiAgICAgIGNvbnN0IGVudmlyb25tZW50Q3JlZGVudGlhbHNQcm90b3R5cGUgPSAobmV3IEFXUy5FbnZpcm9ubWVudENyZWRlbnRpYWxzKCdBV1MnKSkuY29uc3RydWN0b3IucHJvdG90eXBlO1xuXG4gICAgICBhd2FpdCB3aXRoTW9ja2VkKGVudmlyb25tZW50Q3JlZGVudGlhbHNQcm90b3R5cGUsICdyZWZyZXNoJywgYXN5bmMgKHJlZnJlc2gpID0+IHtcbiAgICAgICAgcmVmcmVzaC5tb2NrSW1wbGVtZW50YXRpb24oKGNhbGxiYWNrOiAoZXJyPzogRXJyb3IpID0+IHZvaWQpID0+IGNhbGxiYWNrKG5ldyBFcnJvcignVGhpcyBmdW5jdGlvbiBzaG91bGQgbm90IGhhdmUgYmVlbiBjYWxsZWQnKSkpO1xuXG4gICAgICAgIC8vIFdIRU5cbiAgICAgICAgZXhwZWN0KChhd2FpdCBwcm92aWRlci5kZWZhdWx0QWNjb3VudCgpKT8uYWNjb3VudElkKS50b0VxdWFsKHVuaXEoJzExMTExJykpO1xuXG4gICAgICAgIGV4cGVjdChyZWZyZXNoKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdzdXBwb3J0cyBwcm9maWxlIHNwcmVhZCBvdmVyIGNvbmZpZ19maWxlIGFuZCBjcmVkZW50aWFsc19maWxlJywgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gV0hFTlxuICAgICAgcHJlcGFyZUNyZWRzKHtcbiAgICAgICAgZmFrZVN0cyxcbiAgICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgICBmb286IHsgYXdzX2FjY2Vzc19rZXlfaWQ6ICdmb29jY2VzcycsICRhY2NvdW50OiAnMjIyMjInIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICdkZWZhdWx0JzogeyByZWdpb246ICdldS1ibGEtNScgfSxcbiAgICAgICAgICAncHJvZmlsZSBmb28nOiB7IHJlZ2lvbjogJ2V1LXdlc3QtMScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBTZGtQcm92aWRlci53aXRoQXdzQ2xpQ29tcGF0aWJsZURlZmF1bHRzKHsgLi4uZGVmYXVsdENyZWRPcHRpb25zLCBwcm9maWxlOiAnZm9vJyB9KTtcblxuICAgICAgLy8gVEhFTlxuICAgICAgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRSZWdpb24pLnRvRXF1YWwoJ2V1LXdlc3QtMScpO1xuICAgICAgYXdhaXQgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRBY2NvdW50KCkpLnJlc29sdmVzLnRvRXF1YWwoeyBhY2NvdW50SWQ6IHVuaXEoJzIyMjIyJyksIHBhcnRpdGlvbjogJ2F3cycgfSk7XG5cbiAgICAgIGNvbnN0IHNkayA9IGF3YWl0IHByb3ZpZGVyLmZvckVudmlyb25tZW50KGVudih1bmlxKCcyMjIyMicpKSwgTW9kZS5Gb3JSZWFkaW5nKTtcbiAgICAgIGV4cGVjdChzZGtDb25maWcoc2RrKS5jcmVkZW50aWFscyEuYWNjZXNzS2V5SWQpLnRvRXF1YWwodW5pcSgnZm9vY2Nlc3MnKSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdzdXBwb3J0cyBwcm9maWxlIG9ubHkgaW4gY29uZmlnX2ZpbGUnLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBXSEVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICAnZGVmYXVsdCc6IHsgcmVnaW9uOiAnZXUtYmxhLTUnIH0sXG4gICAgICAgICAgJ3Byb2ZpbGUgZm9vJzogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2Zvb2NjZXNzJywgJGFjY291bnQ6ICcyMjIyMicgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKCdmb28nKTtcblxuICAgICAgLy8gVEhFTlxuICAgICAgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRSZWdpb24pLnRvRXF1YWwoJ2V1LWJsYS01Jyk7IC8vIEZhbGwgYmFjayB0byBkZWZhdWx0IGNvbmZpZ1xuICAgICAgYXdhaXQgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRBY2NvdW50KCkpLnJlc29sdmVzLnRvRXF1YWwoeyBhY2NvdW50SWQ6IHVuaXEoJzIyMjIyJyksIHBhcnRpdGlvbjogJ2F3cycgfSk7XG5cbiAgICAgIGNvbnN0IHNkayA9IGF3YWl0IHByb3ZpZGVyLmZvckVudmlyb25tZW50KGVudih1bmlxKCcyMjIyMicpKSwgTW9kZS5Gb3JSZWFkaW5nKTtcbiAgICAgIGV4cGVjdChzZGtDb25maWcoc2RrKS5jcmVkZW50aWFscyEuYWNjZXNzS2V5SWQpLnRvRXF1YWwodW5pcSgnZm9vY2Nlc3MnKSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdjYW4gYXNzdW1lLXJvbGUgY29uZmlndXJlZCBpbiBjb25maWcnLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBHSVZFTlxuICAgICAgcHJlcGFyZUNyZWRzKHtcbiAgICAgICAgZmFrZVN0cyxcbiAgICAgICAgY3JlZGVudGlhbHM6IHtcbiAgICAgICAgICBhc3N1bWVyOiB7IGF3c19hY2Nlc3Nfa2V5X2lkOiAnYXNzdW1lcicsICRhY2NvdW50OiAnMTExMTEnIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICdkZWZhdWx0JzogeyByZWdpb246ICdldS1ibGEtNScgfSxcbiAgICAgICAgICAncHJvZmlsZSBhc3N1bWVyJzogeyByZWdpb246ICd1cy1lYXN0LTInIH0sXG4gICAgICAgICAgJ3Byb2ZpbGUgYXNzdW1hYmxlJzoge1xuICAgICAgICAgICAgcm9sZV9hcm46ICdhcm46YXdzOmlhbTo6NjY2NjY6cm9sZS9Bc3N1bWFibGUnLFxuICAgICAgICAgICAgc291cmNlX3Byb2ZpbGU6ICdhc3N1bWVyJyxcbiAgICAgICAgICAgICRhY2NvdW50OiAnNjY2NjYnLFxuICAgICAgICAgICAgJGZha2VTdHNPcHRpb25zOiB7IGFsbG93ZWRBY2NvdW50czogWycxMTExMSddIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKCdhc3N1bWFibGUnKTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgY29uc3Qgc2RrID0gYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJzY2NjY2JykpLCBNb2RlLkZvclJlYWRpbmcpO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QoKGF3YWl0IHNkay5jdXJyZW50QWNjb3VudCgpKS5hY2NvdW50SWQpLnRvRXF1YWwodW5pcSgnNjY2NjYnKSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdjYW4gYXNzdW1lIHJvbGUgZXZlbiBpZiBbZGVmYXVsdF0gcHJvZmlsZSBpcyBtaXNzaW5nJywgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR0lWRU5cbiAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgIGZha2VTdHMsXG4gICAgICAgIGNyZWRlbnRpYWxzOiB7XG4gICAgICAgICAgYXNzdW1lcjogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2Fzc3VtZXInLCAkYWNjb3VudDogJzIyMjIyJyB9LFxuICAgICAgICAgIGFzc3VtYWJsZTogeyByb2xlX2FybjogJ2Fybjphd3M6aWFtOjoxMjM1Njc4OTAxMjpyb2xlL0Fzc3VtYWJsZScsIHNvdXJjZV9wcm9maWxlOiAnYXNzdW1lcicsICRhY2NvdW50OiAnMjIyMjInIH0sXG4gICAgICAgIH0sXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgICdwcm9maWxlIGFzc3VtYWJsZSc6IHsgcmVnaW9uOiAnZXUtYmxhLTUnIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKCdhc3N1bWFibGUnKTtcblxuICAgICAgLy8gVEhFTlxuICAgICAgZXhwZWN0KChhd2FpdCBwcm92aWRlci5kZWZhdWx0QWNjb3VudCgpKT8uYWNjb3VudElkKS50b0VxdWFsKHVuaXEoJzIyMjIyJykpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnbWZhX3NlcmlhbCBpbiBwcm9maWxlIHdpbGwgYXNrIHVzZXIgZm9yIHRva2VuJywgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR0lWRU5cbiAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgIGZha2VTdHMsXG4gICAgICAgIGNyZWRlbnRpYWxzOiB7XG4gICAgICAgICAgYXNzdW1lcjogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2Fzc3VtZXInLCAkYWNjb3VudDogJzY2NjY2JyB9LFxuICAgICAgICB9LFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICAnZGVmYXVsdCc6IHsgcmVnaW9uOiAnZXUtYmxhLTUnIH0sXG4gICAgICAgICAgJ3Byb2ZpbGUgYXNzdW1lcic6IHsgcmVnaW9uOiAndXMtZWFzdC0yJyB9LFxuICAgICAgICAgICdwcm9maWxlIG1mYS1yb2xlJzoge1xuICAgICAgICAgICAgcm9sZV9hcm46ICdhcm46YXdzOmlhbTo6NjY2NjY6cm9sZS9Bc3N1bWFibGUnLFxuICAgICAgICAgICAgc291cmNlX3Byb2ZpbGU6ICdhc3N1bWVyJyxcbiAgICAgICAgICAgIG1mYV9zZXJpYWw6ICdhcm46YXdzOmlhbTo6YWNjb3VudDptZmEvdXNlcicsXG4gICAgICAgICAgICAkYWNjb3VudDogJzY2NjY2JyxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUoJ21mYS1yb2xlJyk7XG5cbiAgICAgIGNvbnN0IHByb21wdGx5TW9ja0NhbGxzID0gKHByb21wdGx5LnByb21wdCBhcyBqZXN0Lk1vY2spLm1vY2suY2FsbHMubGVuZ3RoO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBjb25zdCBzZGsgPSBhd2FpdCBwcm92aWRlci5mb3JFbnZpcm9ubWVudChlbnYodW5pcSgnNjY2NjYnKSksIE1vZGUuRm9yUmVhZGluZyk7XG4gICAgICBleHBlY3QoKGF3YWl0IHNkay5jdXJyZW50QWNjb3VudCgpKS5hY2NvdW50SWQpLnRvRXF1YWwodW5pcSgnNjY2NjYnKSk7XG4gICAgICBleHBlY3QoZmFrZVN0cy5hc3N1bWVkUm9sZXNbMF0pLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICByb2xlQXJuOiAnYXJuOmF3czppYW06OjY2NjY2OnJvbGUvQXNzdW1hYmxlJyxcbiAgICAgICAgc2VyaWFsTnVtYmVyOiAnYXJuOmF3czppYW06OmFjY291bnQ6bWZhL3VzZXInLFxuICAgICAgICB0b2tlbkNvZGU6ICcxMjM0JyxcbiAgICAgIH0pKTtcblxuICAgICAgLy8gTW9jayByZXNwb25zZSB3YXMgc2V0IHRvIGZhaWwgdG8gbWFrZSBzdXJlIHdlIGRvbid0IGNhbGwgU1RTXG4gICAgICAvLyBNYWtlIHN1cmUgdGhlIE1GQSBtb2NrIHdhcyBjYWxsZWQgZHVyaW5nIHRoaXMgdGVzdFxuICAgICAgZXhwZWN0KChwcm9tcHRseS5wcm9tcHQgYXMgamVzdC5Nb2NrKS5tb2NrLmNhbGxzLmxlbmd0aCkudG9CZShwcm9tcHRseU1vY2tDYWxscyArIDEpO1xuICAgIH0pO1xuICB9KTtcblxuICAvLyBGb3IgRGVmYXVsdFN5bnRoZXNpcyB3ZSB3aWxsIGRvIGFuIGFzc3VtZS1yb2xlIGFmdGVyIGhhdmluZyBnb3R0ZW4gYmFzZSBjcmVkZW50aWFsc1xuICBkZXNjcmliZSgnd2hlbiBDREsgQXNzdW1lUm9sZXMnLCAoKSA9PiB7XG4gICAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgICAvLyBBbGwgdGhlc2UgdGVzdHMgc2hhcmUgdGhhdCAnYXJuOmF3czpyb2xlJyBpcyBhIHJvbGUgaW50byBhY2NvdW50IDg4ODg4IHdoaWNoIGNhbiBiZSBhc3N1bWVkIGZyb20gMTExMTFcbiAgICAgIGZha2VTdHMucmVnaXN0ZXJSb2xlKHVuaXEoJzg4ODg4JyksICdhcm46YXdzOnJvbGUnLCB7IGFsbG93ZWRBY2NvdW50czogW3VuaXEoJzExMTExJyldIH0pO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnZXJyb3Igd2UgZ2V0IGZyb20gYXNzdW1pbmcgYSByb2xlIGlzIHVzZWZ1bCcsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEdJVkVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBkZWZhdWx0OiB7IGF3c19hY2Nlc3Nfa2V5X2lkOiAnZm9vJyB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUodW5kZWZpbmVkKTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgY29uc3QgcHJvbWlzZSA9IHByb3ZpZGVyLmZvckVudmlyb25tZW50KGVudih1bmlxKCc4ODg4OCcpKSwgTW9kZS5Gb3JSZWFkaW5nLCB7XG4gICAgICAgIGFzc3VtZVJvbGVBcm46ICdkb2Vzbm90ZXhpc3Qucm9sZS5hcm4nLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFRIRU4gLSBlcnJvciBtZXNzYWdlIGNvbnRhaW5zIGJvdGggYSBoZWxwZnVsIGhpbnQgYW5kIHRoZSB1bmRlcmx5aW5nIEFzc3VtZVJvbGUgbWVzc2FnZVxuICAgICAgYXdhaXQgZXhwZWN0KHByb21pc2UpLnJlamVjdHMudG9UaHJvdygnKHJlKS1ib290c3RyYXAgdGhlIGVudmlyb25tZW50Jyk7XG4gICAgICBhd2FpdCBleHBlY3QocHJvbWlzZSkucmVqZWN0cy50b1Rocm93KCdkb2Vzbm90ZXhpc3Qucm9sZS5hcm4nKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ2Fzc3VtaW5nIGEgcm9sZSBzYW5pdGl6ZXMgdGhlIHVzZXJuYW1lIGludG8gdGhlIHNlc3Npb24gbmFtZScsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEdJVkVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBkZWZhdWx0OiB7IGF3c19hY2Nlc3Nfa2V5X2lkOiAnZm9vJywgJGFjY291bnQ6ICcxMTExMScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCB3aXRoTW9ja2VkKG9zLCAndXNlckluZm8nLCBhc3luYyAodXNlckluZm8pID0+IHtcbiAgICAgICAgdXNlckluZm8ubW9ja1JldHVyblZhbHVlKHsgdXNlcm5hbWU6ICdza8OlbCcsIHVpZDogMSwgZ2lkOiAxLCBob21lZGlyOiAnL2hlcmUnLCBzaGVsbDogJy9iaW4vc2gnIH0pO1xuXG4gICAgICAgIC8vIFdIRU5cbiAgICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG5cbiAgICAgICAgY29uc3Qgc2RrID0gYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJzg4ODg4JykpLCBNb2RlLkZvclJlYWRpbmcsIHsgYXNzdW1lUm9sZUFybjogJ2Fybjphd3M6cm9sZScgfSkgYXMgU0RLO1xuICAgICAgICBhd2FpdCBzZGsuY3VycmVudEFjY291bnQoKTtcblxuICAgICAgICAvLyBUSEVOXG4gICAgICAgIGV4cGVjdChmYWtlU3RzLmFzc3VtZWRSb2xlc1swXSkudG9FcXVhbChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgcm9sZVNlc3Npb25OYW1lOiAnYXdzLWNkay1za0BsJyxcbiAgICAgICAgfSkpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdldmVuIGlmIGN1cnJlbnQgY3JlZGVudGlhbHMgYXJlIGZvciB0aGUgd3JvbmcgYWNjb3VudCwgd2Ugd2lsbCBzdGlsbCB1c2UgdGhlbSB0byBBc3N1bWVSb2xlJywgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR0lWRU5cbiAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgIGZha2VTdHMsXG4gICAgICAgIGNvbmZpZzoge1xuICAgICAgICAgIGRlZmF1bHQ6IHsgYXdzX2FjY2Vzc19rZXlfaWQ6ICdmb28nLCAkYWNjb3VudDogJzExMTExJyB9LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUodW5kZWZpbmVkKTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgY29uc3Qgc2RrID0gYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJzg4ODg4JykpLCBNb2RlLkZvclJlYWRpbmcsIHsgYXNzdW1lUm9sZUFybjogJ2Fybjphd3M6cm9sZScgfSkgYXMgU0RLO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QoKGF3YWl0IHNkay5jdXJyZW50QWNjb3VudCgpKS5hY2NvdW50SWQpLnRvRXF1YWwodW5pcSgnODg4ODgnKSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdpZiBBc3N1bWVSb2xlIGZhaWxzIGJ1dCBjdXJyZW50IGNyZWRlbnRpYWxzIGFyZSBmb3IgdGhlIHJpZ2h0IGFjY291bnQsIHdlIHdpbGwgc3RpbGwgdXNlIHRoZW0nLCBhc3luYyAoKSA9PiB7XG4gICAgICAvLyBHSVZFTlxuICAgICAgcHJlcGFyZUNyZWRzKHtcbiAgICAgICAgZmFrZVN0cyxcbiAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgZGVmYXVsdDogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2ZvbycsICRhY2NvdW50OiAnODg4ODgnIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvdmlkZXJGcm9tUHJvZmlsZSh1bmRlZmluZWQpO1xuXG4gICAgICAvLyBXSEVOIC0gYXNzdW1lUm9sZSBmYWlscyBiZWNhdXNlIHRoZSByb2xlIGNhbiBvbmx5IGJlIGFzc3VtZWQgZnJvbSBhY2NvdW50IDExMTExXG4gICAgICBjb25zdCBzZGsgPSBhd2FpdCBwcm92aWRlci5mb3JFbnZpcm9ubWVudChlbnYodW5pcSgnODg4ODgnKSksIE1vZGUuRm9yUmVhZGluZywgeyBhc3N1bWVSb2xlQXJuOiAnYXJuOmF3czpyb2xlJyB9KSBhcyBTREs7XG5cbiAgICAgIC8vIFRIRU5cbiAgICAgIGV4cGVjdCgoYXdhaXQgc2RrLmN1cnJlbnRBY2NvdW50KCkpLmFjY291bnRJZCkudG9FcXVhbCh1bmlxKCc4ODg4OCcpKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ1BsdWdpbnMnLCAoKSA9PiB7XG4gICAgdGVzdCgnZG9lcyBub3QgdXNlIHBsdWdpbnMgaWYgY3VycmVudCBjcmVkZW50aWFscyBhcmUgZm9yIGV4cGVjdGVkIGFjY291bnQnLCBhc3luYyAoKSA9PiB7XG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBmYWtlU3RzLFxuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICBkZWZhdWx0OiB7IGF3c19hY2Nlc3Nfa2V5X2lkOiAnZm9vJywgJGFjY291bnQ6ICcxMTExMScgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG4gICAgICBhd2FpdCBwcm92aWRlci5mb3JFbnZpcm9ubWVudChlbnYodW5pcSgnMTExMTEnKSksIE1vZGUuRm9yUmVhZGluZyk7XG4gICAgICBleHBlY3QocGx1Z2luUXVlcmllZCkudG9FcXVhbChmYWxzZSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCd1c2VzIHBsdWdpbiBmb3IgYWNjb3VudCA5OTk5OScsIGFzeW5jICgpID0+IHtcbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvdmlkZXJGcm9tUHJvZmlsZSh1bmRlZmluZWQpO1xuICAgICAgYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJzk5OTk5JykpLCBNb2RlLkZvclJlYWRpbmcpO1xuICAgICAgZXhwZWN0KHBsdWdpblF1ZXJpZWQpLnRvRXF1YWwodHJ1ZSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdjYW4gYXNzdW1lIHJvbGUgd2l0aCBjcmVkZW50aWFscyBmcm9tIHBsdWdpbicsIGFzeW5jICgpID0+IHtcbiAgICAgIGZha2VTdHMucmVnaXN0ZXJSb2xlKHVuaXEoJzk5OTk5JyksICdhcm46YXdzOmlhbTo6OTk5OTk6cm9sZS9Bc3N1bWFibGUnKTtcblxuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG4gICAgICBhd2FpdCBwcm92aWRlci5mb3JFbnZpcm9ubWVudChlbnYodW5pcSgnOTk5OTknKSksIE1vZGUuRm9yUmVhZGluZywge1xuICAgICAgICBhc3N1bWVSb2xlQXJuOiAnYXJuOmF3czppYW06Ojk5OTk5OnJvbGUvQXNzdW1hYmxlJyxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QoZmFrZVN0cy5hc3N1bWVkUm9sZXNbMF0pLnRvRXF1YWwoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICByb2xlQXJuOiAnYXJuOmF3czppYW06Ojk5OTk5OnJvbGUvQXNzdW1hYmxlJyxcbiAgICAgIH0pKTtcbiAgICAgIGV4cGVjdChwbHVnaW5RdWVyaWVkKS50b0VxdWFsKHRydWUpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnZXZlbiBpZiBBc3N1bWVSb2xlIGZhaWxzIGJ1dCBjdXJyZW50IGNyZWRlbnRpYWxzIGFyZSBmcm9tIGEgcGx1Z2luLCB3ZSB3aWxsIHN0aWxsIHVzZSB0aGVtJywgYXN5bmMgKCkgPT4ge1xuICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG4gICAgICBjb25zdCBzZGsgPSBhd2FpdCBwcm92aWRlci5mb3JFbnZpcm9ubWVudChlbnYodW5pcSgnOTk5OTknKSksIE1vZGUuRm9yUmVhZGluZywgeyBhc3N1bWVSb2xlQXJuOiAnZG9lczpub3Q6ZXhpc3QnIH0pO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QoKGF3YWl0IHNkay5jdXJyZW50QWNjb3VudCgpKS5hY2NvdW50SWQpLnRvRXF1YWwodW5pcSgnOTk5OTknKSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdwbHVnaW5zIGFyZSBzdGlsbCBxdWVyaWVkIGV2ZW4gaWYgY3VycmVudCBjcmVkZW50aWFscyBhcmUgZXhwaXJlZCAob3Igb3RoZXJ3aXNlIGludmFsaWQpJywgYXN5bmMgKCkgPT4ge1xuICAgICAgLy8gR0lWRU5cbiAgICAgIHByb2Nlc3MuZW52LkFXU19BQ0NFU1NfS0VZX0lEID0gYCR7dWlkfWFraWRgO1xuICAgICAgcHJvY2Vzcy5lbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZID0gJ3Nla3JpdCc7XG4gICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUodW5kZWZpbmVkKTtcblxuICAgICAgLy8gV0hFTlxuICAgICAgYXdhaXQgcHJvdmlkZXIuZm9yRW52aXJvbm1lbnQoZW52KHVuaXEoJzk5OTk5JykpLCBNb2RlLkZvclJlYWRpbmcpO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QocGx1Z2luUXVlcmllZCkudG9FcXVhbCh0cnVlKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ3N1cHBvcnQgZm9yIGNyZWRlbnRpYWxfc291cmNlJywgKCkgPT4ge1xuICAgIHRlc3QoJ2NhbiBhc3N1bWUgcm9sZSB3aXRoIGVjcyBjcmVkZW50aWFscycsIGFzeW5jICgpID0+IHtcbiAgICAgIHJldHVybiB3aXRoTW9ja2VkKEFXUy5FQ1NDcmVkZW50aWFscy5wcm90b3R5cGUsICduZWVkc1JlZnJlc2gnLCBhc3luYyAobmVlZHNSZWZyZXNoKSA9PiB7XG4gICAgICAgIC8vIEdJVkVOXG4gICAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgICAncHJvZmlsZSBlY3MnOiB7IHJvbGVfYXJuOiAnYXJuOmF3czppYW06OjEyMzU2Nzg5MDEyOnJvbGUvQXNzdW1hYmxlJywgY3JlZGVudGlhbF9zb3VyY2U6ICdFY3NDb250YWluZXInLCAkYWNjb3VudDogJzIyMjIyJyB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCBwcm92aWRlciA9IGF3YWl0IHByb3ZpZGVyRnJvbVByb2ZpbGUoJ2VjcycpO1xuXG4gICAgICAgIC8vIFdIRU5cbiAgICAgICAgYXdhaXQgcHJvdmlkZXIuZGVmYXVsdEFjY291bnQoKTtcblxuICAgICAgICAvLyBUSEVOXG4gICAgICAgIGV4cGVjdChuZWVkc1JlZnJlc2gpLnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgICAgIH0pO1xuXG4gICAgfSk7XG5cbiAgICB0ZXN0KCdjYW4gYXNzdW1lIHJvbGUgd2l0aCBlYzIgY3JlZGVudGlhbHMnLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gd2l0aE1vY2tlZChBV1MuRUMyTWV0YWRhdGFDcmVkZW50aWFscy5wcm90b3R5cGUsICduZWVkc1JlZnJlc2gnLCBhc3luYyAobmVlZHNSZWZyZXNoKSA9PiB7XG4gICAgICAgIC8vIEdJVkVOXG4gICAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgICAncHJvZmlsZSBlY3MnOiB7IHJvbGVfYXJuOiAnYXJuOmF3czppYW06OjEyMzU2Nzg5MDEyOnJvbGUvQXNzdW1hYmxlJywgY3JlZGVudGlhbF9zb3VyY2U6ICdFYzJJbnN0YW5jZU1ldGFkYXRhJywgJGFjY291bnQ6ICcyMjIyMicgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKCdlY3MnKTtcblxuICAgICAgICAvLyBXSEVOXG4gICAgICAgIGF3YWl0IHByb3ZpZGVyLmRlZmF1bHRBY2NvdW50KCk7XG5cbiAgICAgICAgLy8gVEhFTlxuICAgICAgICBleHBlY3QobmVlZHNSZWZyZXNoKS50b0hhdmVCZWVuQ2FsbGVkKCk7XG5cbiAgICAgIH0pO1xuXG4gICAgfSk7XG5cbiAgICB0ZXN0KCdjYW4gYXNzdW1lIHJvbGUgd2l0aCBlbnYgY3JlZGVudGlhbHMnLCBhc3luYyAoKSA9PiB7XG4gICAgICByZXR1cm4gd2l0aE1vY2tlZChBV1MuRW52aXJvbm1lbnRDcmVkZW50aWFscy5wcm90b3R5cGUsICduZWVkc1JlZnJlc2gnLCBhc3luYyAobmVlZHNSZWZyZXNoKSA9PiB7XG4gICAgICAgIC8vIEdJVkVOXG4gICAgICAgIHByZXBhcmVDcmVkcyh7XG4gICAgICAgICAgY29uZmlnOiB7XG4gICAgICAgICAgICAncHJvZmlsZSBlY3MnOiB7IHJvbGVfYXJuOiAnYXJuOmF3czppYW06OjEyMzU2Nzg5MDEyOnJvbGUvQXNzdW1hYmxlJywgY3JlZGVudGlhbF9zb3VyY2U6ICdFbnZpcm9ubWVudCcsICRhY2NvdW50OiAnMjIyMjInIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSk7XG4gICAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvdmlkZXJGcm9tUHJvZmlsZSgnZWNzJyk7XG5cbiAgICAgICAgLy8gV0hFTlxuICAgICAgICBhd2FpdCBwcm92aWRlci5kZWZhdWx0QWNjb3VudCgpO1xuXG4gICAgICAgIC8vIFRIRU5cbiAgICAgICAgZXhwZWN0KG5lZWRzUmVmcmVzaCkudG9IYXZlQmVlbkNhbGxlZCgpO1xuICAgICAgfSk7XG4gICAgfSk7XG5cbiAgICB0ZXN0KCdhc3N1bWUgZmFpbHMgd2l0aCB1bnN1cHBvcnRlZCBjcmVkZW50aWFsX3NvdXJjZScsIGFzeW5jICgpID0+IHtcbiAgICAgIC8vIEdJVkVOXG4gICAgICBwcmVwYXJlQ3JlZHMoe1xuICAgICAgICBjb25maWc6IHtcbiAgICAgICAgICAncHJvZmlsZSBlY3MnOiB7IHJvbGVfYXJuOiAnYXJuOmF3czppYW06OjEyMzU2Nzg5MDEyOnJvbGUvQXNzdW1hYmxlJywgY3JlZGVudGlhbF9zb3VyY2U6ICd1bnN1cHBvcnRlZCcsICRhY2NvdW50OiAnMjIyMjInIH0sXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICAgIGNvbnN0IHByb3ZpZGVyID0gYXdhaXQgcHJvdmlkZXJGcm9tUHJvZmlsZSgnZWNzJyk7XG5cbiAgICAgIC8vIFdIRU5cbiAgICAgIGNvbnN0IGFjY291bnQgPSBhd2FpdCBwcm92aWRlci5kZWZhdWx0QWNjb3VudCgpO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QoYWNjb3VudD8uYWNjb3VudElkKS50b0VxdWFsKHVuZGVmaW5lZCk7XG4gICAgfSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2RlZmF1bHRBY2NvdW50IHJldHVybnMgdW5kZWZpbmVkIGlmIFNUUyBjYWxsIGZhaWxzJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgcHJvY2Vzcy5lbnYuQVdTX0FDQ0VTU19LRVlfSUQgPSBgJHt1aWR9YWtpZGA7XG4gICAgcHJvY2Vzcy5lbnYuQVdTX1NFQ1JFVF9BQ0NFU1NfS0VZID0gJ3Nla3JpdCc7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBwcm92aWRlckZyb21Qcm9maWxlKHVuZGVmaW5lZCk7XG5cbiAgICAvLyBUSEVOXG4gICAgYXdhaXQgZXhwZWN0KHByb3ZpZGVyLmRlZmF1bHRBY2NvdW50KCkpLnJlc29sdmVzLnRvQmUodW5kZWZpbmVkKTtcbiAgfSk7XG59KTtcblxudGVzdCgnZXZlbiB3aGVuIHVzaW5nIGEgcHJvZmlsZSB0byBhc3N1bWUgYW5vdGhlciBwcm9maWxlLCBTVFMgY2FsbHMgZ29lcyB0aHJvdWdoIHRoZSBwcm94eScsIGFzeW5jICgpID0+IHtcbiAgcHJlcGFyZUNyZWRzKHtcbiAgICBjcmVkZW50aWFsczoge1xuICAgICAgYXNzdW1lcjogeyBhd3NfYWNjZXNzX2tleV9pZDogJ2Fzc3VtZXInIH0sXG4gICAgfSxcbiAgICBjb25maWc6IHtcbiAgICAgICdkZWZhdWx0JzogeyByZWdpb246ICdldS1ibGEtNScgfSxcbiAgICAgICdwcm9maWxlIGFzc3VtYWJsZSc6IHsgcm9sZV9hcm46ICdhcm46YXdzOmlhbTo6NjY2NjY6cm9sZS9Bc3N1bWFibGUnLCBzb3VyY2VfcHJvZmlsZTogJ2Fzc3VtZXInLCAkYWNjb3VudDogJzY2NjY2JyB9LFxuICAgICAgJ3Byb2ZpbGUgYXNzdW1lcic6IHsgcmVnaW9uOiAndXMtZWFzdC0yJyB9LFxuICAgIH0sXG4gIH0pO1xuXG4gIC8vIE1lc3N5IG1vY2tpbmdcbiAgbGV0IGNhbGxlZCA9IGZhbHNlO1xuICBqZXN0Lm1vY2soJ3Byb3h5LWFnZW50JywgKCkgPT4ge1xuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tcmVxdWlyZS1pbXBvcnRzXG4gICAgY2xhc3MgRmFrZUFnZW50IGV4dGVuZHMgcmVxdWlyZSgnaHR0cHMnKS5BZ2VudCB7XG4gICAgICBwdWJsaWMgYWRkUmVxdWVzdChfOiBhbnksIF9fOiBhbnkpIHtcbiAgICAgICAgLy8gRklYTUU6IHRoaXMgZXJyb3IgdGFrZXMgNiBzZWNvbmRzIHRvIGJlIGNvbXBsZXRlbHkgaGFuZGxlZC4gSXRcbiAgICAgICAgLy8gbWlnaHQgYmUgcmV0cmllcyBpbiB0aGUgU0RLIHNvbWV3aGVyZSwgb3Igc29tZXRoaW5nIGFib3V0IHRoZSBOb2RlXG4gICAgICAgIC8vIGV2ZW50IGxvb3AuIEkndmUgc3BlbnQgYW4gaG91ciB0cnlpbmcgdG8gZmlndXJlIGl0IG91dCBhbmQgSSBjYW4ndCxcbiAgICAgICAgLy8gYW5kIEkgZ2F2ZSB1cC4gV2UnbGwganVzdCBoYXZlIHRvIGxpdmUgd2l0aCB0aGlzIHVudGlsIHNvbWVvbmUgZ2V0c1xuICAgICAgICAvLyBpbnNwaXJlZC5cbiAgICAgICAgY29uc3QgZXJyb3IgPSBuZXcgRXJyb3IoJ0FCT1JURUQgQlkgVEVTVCcpO1xuICAgICAgICAoZXJyb3IgYXMgYW55KS5jb2RlID0gJ1JlcXVlc3RBYm9ydGVkRXJyb3InO1xuICAgICAgICAoZXJyb3IgYXMgYW55KS5yZXRyeWFibGUgPSBmYWxzZTtcbiAgICAgICAgY2FsbGVkID0gdHJ1ZTtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBGYWtlQWdlbnQ7XG4gIH0pO1xuXG4gIC8vIFdIRU5cbiAgY29uc3QgcHJvdmlkZXIgPSBhd2FpdCBTZGtQcm92aWRlci53aXRoQXdzQ2xpQ29tcGF0aWJsZURlZmF1bHRzKHtcbiAgICAuLi5kZWZhdWx0Q3JlZE9wdGlvbnMsXG4gICAgcHJvZmlsZTogJ2Fzc3VtYWJsZScsXG4gICAgaHR0cE9wdGlvbnM6IHtcbiAgICAgIHByb3h5QWRkcmVzczogJ2h0dHA6Ly9ET0VTTlRNQVRURVIvJyxcbiAgICB9LFxuICB9KTtcblxuICBhd2FpdCBwcm92aWRlci5kZWZhdWx0QWNjb3VudCgpO1xuXG4gIC8vIFRIRU4gLS0gdGhlIGZha2UgcHJveHkgYWdlbnQgZ290IGNhbGxlZCwgd2UgZG9uJ3QgY2FyZSBhYm91dCB0aGUgcmVzdWx0XG4gIGV4cGVjdChjYWxsZWQpLnRvRXF1YWwodHJ1ZSk7XG59KTtcblxuLyoqXG4gKiBVc2Ugb2JqZWN0IGhhY2tlcnkgdG8gZ2V0IHRoZSBjcmVkZW50aWFscyBvdXQgb2YgdGhlIFNESyBvYmplY3RcbiAqL1xuZnVuY3Rpb24gc2RrQ29uZmlnKHNkazogSVNESyk6IENvbmZpZ3VyYXRpb25PcHRpb25zIHtcbiAgcmV0dXJuIChzZGsgYXMgYW55KS5jb25maWc7XG59XG5cbi8qKlxuICogRml4dHVyZSBmb3IgU0RLIGF1dGggZm9yIHRoaXMgdGVzdCBzdWl0ZVxuICpcbiAqIEhhcyBrbm93bGVkZ2Ugb2YgdGhlIGNhY2hlIGJ1c3Rlciwgd2lsbCB3cml0ZSBwcm9wZXIgZmFrZSBjb25maWcgZmlsZXMgYW5kXG4gKiByZWdpc3RlciB1c2VycyBhbmQgcm9sZXMgaW4gRmFrZVN0cyBhdCB0aGUgc2FtZSB0aW1lLlxuICovXG5mdW5jdGlvbiBwcmVwYXJlQ3JlZHMob3B0aW9uczogUHJlcGFyZUNyZWRzT3B0aW9ucykge1xuICBmdW5jdGlvbiBjb252ZXJ0U2VjdGlvbnMoc2VjdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCBQcm9maWxlVXNlciB8IFByb2ZpbGVSb2xlPikge1xuICAgIGNvbnN0IHJldCA9IFtdO1xuICAgIGZvciAoY29uc3QgW3Byb2ZpbGUsIHVzZXJdIG9mIE9iamVjdC5lbnRyaWVzKHNlY3Rpb25zID8/IHt9KSkge1xuICAgICAgcmV0LnB1c2goYFske3Byb2ZpbGV9XWApO1xuXG4gICAgICBpZiAoaXNQcm9maWxlUm9sZSh1c2VyKSkge1xuICAgICAgICByZXQucHVzaChgcm9sZV9hcm49JHt1c2VyLnJvbGVfYXJufWApO1xuICAgICAgICBpZiAoJ3NvdXJjZV9wcm9maWxlJyBpbiB1c2VyKSB7XG4gICAgICAgICAgcmV0LnB1c2goYHNvdXJjZV9wcm9maWxlPSR7dXNlci5zb3VyY2VfcHJvZmlsZX1gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoJ2NyZWRlbnRpYWxfc291cmNlJyBpbiB1c2VyKSB7XG4gICAgICAgICAgcmV0LnB1c2goYGNyZWRlbnRpYWxfc291cmNlPSR7dXNlci5jcmVkZW50aWFsX3NvdXJjZX1gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodXNlci5tZmFfc2VyaWFsKSB7XG4gICAgICAgICAgcmV0LnB1c2goYG1mYV9zZXJpYWw9JHt1c2VyLm1mYV9zZXJpYWx9YCk7XG4gICAgICAgIH1cbiAgICAgICAgb3B0aW9ucy5mYWtlU3RzPy5yZWdpc3RlclJvbGUodW5pcSh1c2VyLiRhY2NvdW50ID8/ICcwMDAwMCcpLCB1c2VyLnJvbGVfYXJuLCB7XG4gICAgICAgICAgLi4udXNlci4kZmFrZVN0c09wdGlvbnMsXG4gICAgICAgICAgYWxsb3dlZEFjY291bnRzOiB1c2VyLiRmYWtlU3RzT3B0aW9ucz8uYWxsb3dlZEFjY291bnRzPy5tYXAodW5pcSksXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHVzZXIuYXdzX2FjY2Vzc19rZXlfaWQpIHtcbiAgICAgICAgICByZXQucHVzaChgYXdzX2FjY2Vzc19rZXlfaWQ9JHt1bmlxKHVzZXIuYXdzX2FjY2Vzc19rZXlfaWQpfWApO1xuICAgICAgICAgIHJldC5wdXNoKCdhd3Nfc2VjcmV0X2FjY2Vzc19rZXk9c2VjcmV0Jyk7XG4gICAgICAgICAgb3B0aW9ucy5mYWtlU3RzPy5yZWdpc3RlclVzZXIodW5pcSh1c2VyLiRhY2NvdW50ID8/ICcwMDAwMCcpLCB1bmlxKHVzZXIuYXdzX2FjY2Vzc19rZXlfaWQpLCB1c2VyLiRmYWtlU3RzT3B0aW9ucyk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgaWYgKHVzZXIucmVnaW9uKSB7XG4gICAgICAgIHJldC5wdXNoKGByZWdpb249JHt1c2VyLnJlZ2lvbn1gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJldC5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIGJvY2tmcyh7XG4gICAgJy9ob21lL21lLy5ieHQvY3JlZGVudGlhbHMnOiBjb252ZXJ0U2VjdGlvbnMob3B0aW9ucy5jcmVkZW50aWFscyksXG4gICAgJy9ob21lL21lLy5ieHQvY29uZmlnJzogY29udmVydFNlY3Rpb25zKG9wdGlvbnMuY29uZmlnKSxcbiAgfSk7XG5cbiAgLy8gU2V0IGVudmlyb25tZW50IHZhcmlhYmxlcyB0aGF0IHdlIHdhbnRcbiAgcHJvY2Vzcy5lbnYuQVdTX0NPTkZJR19GSUxFID0gYm9ja2ZzLnBhdGgoJy9ob21lL21lLy5ieHQvY29uZmlnJyk7XG4gIHByb2Nlc3MuZW52LkFXU19TSEFSRURfQ1JFREVOVElBTFNfRklMRSA9IGJvY2tmcy5wYXRoKCcvaG9tZS9tZS8uYnh0L2NyZWRlbnRpYWxzJyk7XG59XG5cbmludGVyZmFjZSBQcmVwYXJlQ3JlZHNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdyaXRlIHRoZSBhd3MvY3JlZGVudGlhbHMgZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgY3JlZGVudGlhbHM/OiBSZWNvcmQ8c3RyaW5nLCBQcm9maWxlVXNlciB8IFByb2ZpbGVSb2xlPjtcblxuICAvKipcbiAgICogV3JpdGUgdGhlIGF3cy9jb25maWcgZmlsZVxuICAgKi9cbiAgcmVhZG9ubHkgY29uZmlnPzogUmVjb3JkPHN0cmluZywgUHJvZmlsZVVzZXIgfCBQcm9maWxlUm9sZT47XG5cbiAgLyoqXG4gICAqIElmIGdpdmVuLCBhZGQgdXNlcnMgdG8gRmFrZVNUU1xuICAgKi9cbiAgcmVhZG9ubHkgZmFrZVN0cz86IEZha2VTdHM7XG59XG5cbmludGVyZmFjZSBQcm9maWxlVXNlciB7XG4gIHJlYWRvbmx5IGF3c19hY2Nlc3Nfa2V5X2lkPzogc3RyaW5nO1xuICByZWFkb25seSAkYWNjb3VudD86IHN0cmluZztcbiAgcmVhZG9ubHkgcmVnaW9uPzogc3RyaW5nO1xuICByZWFkb25seSAkZmFrZVN0c09wdGlvbnM/OiBSZWdpc3RlclVzZXJPcHRpb25zO1xufVxuXG50eXBlIFByb2ZpbGVSb2xlID0ge1xuICByZWFkb25seSByb2xlX2Fybjogc3RyaW5nO1xuICByZWFkb25seSBtZmFfc2VyaWFsPzogc3RyaW5nO1xuICByZWFkb25seSAkYWNjb3VudDogc3RyaW5nO1xuICByZWFkb25seSByZWdpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5ICRmYWtlU3RzT3B0aW9ucz86IFJlZ2lzdGVyUm9sZU9wdGlvbnM7XG59ICYgKHsgcmVhZG9ubHkgc291cmNlX3Byb2ZpbGU6IHN0cmluZyB9IHwgeyByZWFkb25seSBjcmVkZW50aWFsX3NvdXJjZTogc3RyaW5nIH0pO1xuXG5mdW5jdGlvbiBpc1Byb2ZpbGVSb2xlKHg6IFByb2ZpbGVVc2VyIHwgUHJvZmlsZVJvbGUpOiB4IGlzIFByb2ZpbGVSb2xlIHtcbiAgcmV0dXJuICdyb2xlX2FybicgaW4geDtcbn1cblxuZnVuY3Rpb24gcHJvdmlkZXJGcm9tUHJvZmlsZShwcm9maWxlOiBzdHJpbmcgfCB1bmRlZmluZWQpIHtcbiAgcmV0dXJuIFNka1Byb3ZpZGVyLndpdGhBd3NDbGlDb21wYXRpYmxlRGVmYXVsdHMoeyAuLi5kZWZhdWx0Q3JlZE9wdGlvbnMsIHByb2ZpbGUgfSk7XG59Il19