/ cloudformation-templates / node_modules / aws-cdk / test / api / bootstrap2.test.js
bootstrap2.test.js
  1  "use strict";
  2  Object.defineProperty(exports, "__esModule", { value: true });
  3  const mockDeployStack = jest.fn();
  4  jest.mock('../../lib/api/deploy-stack', () => ({
  5      deployStack: mockDeployStack,
  6  }));
  7  const api_1 = require("../../lib/api");
  8  const mock_sdk_1 = require("../util/mock-sdk");
  9  let bootstrapper;
 10  beforeEach(() => {
 11      bootstrapper = new api_1.Bootstrapper({ source: 'default' });
 12  });
 13  function mockTheToolkitInfo(stackProps) {
 14      const sdk = new mock_sdk_1.MockSdk();
 15      api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.fromStack(mock_sdk_1.mockBootstrapStack(sdk, stackProps), sdk));
 16  }
 17  describe('Bootstrapping v2', () => {
 18      const env = {
 19          account: '123456789012',
 20          region: 'us-east-1',
 21          name: 'mock',
 22      };
 23      let sdk;
 24      beforeEach(() => {
 25          sdk = new mock_sdk_1.MockSdkProvider({ realSdk: false });
 26          // By default, we'll return a non-found toolkit info
 27          api_1.ToolkitInfo.lookup = jest.fn().mockResolvedValue(api_1.ToolkitInfo.bootstraplessDeploymentsOnly(sdk.sdk));
 28      });
 29      afterEach(() => {
 30          mockDeployStack.mockClear();
 31      });
 32      test('passes the bucket name as a CFN parameter', async () => {
 33          await bootstrapper.bootstrapEnvironment(env, sdk, {
 34              parameters: {
 35                  bucketName: 'my-bucket-name',
 36                  cloudFormationExecutionPolicies: ['arn:policy'],
 37              },
 38          });
 39          expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
 40              parameters: expect.objectContaining({
 41                  FileAssetsBucketName: 'my-bucket-name',
 42                  PublicAccessBlockConfiguration: 'true',
 43              }),
 44          }));
 45      });
 46      test('passes the KMS key ID as a CFN parameter', async () => {
 47          await bootstrapper.bootstrapEnvironment(env, sdk, {
 48              parameters: {
 49                  cloudFormationExecutionPolicies: ['arn:policy'],
 50                  kmsKeyId: 'my-kms-key-id',
 51              },
 52          });
 53          expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
 54              parameters: expect.objectContaining({
 55                  FileAssetsBucketKmsKeyId: 'my-kms-key-id',
 56                  PublicAccessBlockConfiguration: 'true',
 57              }),
 58          }));
 59      });
 60      test('passes false to PublicAccessBlockConfiguration', async () => {
 61          await bootstrapper.bootstrapEnvironment(env, sdk, {
 62              parameters: {
 63                  cloudFormationExecutionPolicies: ['arn:policy'],
 64                  publicAccessBlockConfiguration: false,
 65              },
 66          });
 67          expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
 68              parameters: expect.objectContaining({
 69                  PublicAccessBlockConfiguration: 'false',
 70              }),
 71          }));
 72      });
 73      test('passing trusted accounts without CFN managed policies results in an error', async () => {
 74          await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
 75              parameters: {
 76                  trustedAccounts: ['123456789012'],
 77              },
 78          }))
 79              .rejects
 80              .toThrow(/--cloudformation-execution-policies/);
 81      });
 82      test('passing trusted accounts without CFN managed policies on the existing stack results in an error', async () => {
 83          mockTheToolkitInfo({
 84              Parameters: [
 85                  {
 86                      ParameterKey: 'CloudFormationExecutionPolicies',
 87                      ParameterValue: '',
 88                  },
 89              ],
 90          });
 91          await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
 92              parameters: {
 93                  trustedAccounts: ['123456789012'],
 94              },
 95          }))
 96              .rejects
 97              .toThrow(/--cloudformation-execution-policies/);
 98      });
 99      test('passing no CFN managed policies without trusted accounts is okay', async () => {
100          await bootstrapper.bootstrapEnvironment(env, sdk, {
101              parameters: {},
102          });
103          expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
104              parameters: expect.objectContaining({
105                  CloudFormationExecutionPolicies: '',
106              }),
107          }));
108      });
109      test('passing trusted accounts for lookup generates the correct stack parameter', async () => {
110          await bootstrapper.bootstrapEnvironment(env, sdk, {
111              parameters: {
112                  trustedAccountsForLookup: ['123456789012'],
113                  cloudFormationExecutionPolicies: ['aws://foo'],
114              },
115          });
116          expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
117              parameters: expect.objectContaining({
118                  TrustedAccountsForLookup: '123456789012',
119              }),
120          }));
121      });
122      test('allow adding trusted account if there was already a policy on the stack', async () => {
123          // GIVEN
124          mockTheToolkitInfo({
125              Parameters: [
126                  {
127                      ParameterKey: 'CloudFormationExecutionPolicies',
128                      ParameterValue: 'arn:aws:something',
129                  },
130              ],
131          });
132          await bootstrapper.bootstrapEnvironment(env, sdk, {
133              parameters: {
134                  trustedAccounts: ['123456789012'],
135              },
136          });
137          // Did not throw
138      });
139      test('Do not allow downgrading bootstrap stack version', async () => {
140          // GIVEN
141          mockTheToolkitInfo({
142              Outputs: [
143                  {
144                      OutputKey: 'BootstrapVersion',
145                      OutputValue: '999',
146                  },
147              ],
148          });
149          await expect(bootstrapper.bootstrapEnvironment(env, sdk, {
150              parameters: {
151                  cloudFormationExecutionPolicies: ['arn:policy'],
152              },
153          }))
154              .rejects.toThrow('Not downgrading existing bootstrap stack');
155      });
156      test('bootstrap template has the right exports', async () => {
157          var _a;
158          let template;
159          mockDeployStack.mockImplementation((args) => {
160              template = args.stack.template;
161          });
162          await bootstrapper.bootstrapEnvironment(env, sdk, {
163              parameters: {
164                  cloudFormationExecutionPolicies: ['arn:policy'],
165              },
166          });
167          const exports = Object.values((_a = template.Outputs) !== null && _a !== void 0 ? _a : {})
168              .filter((o) => o.Export !== undefined)
169              .map((o) => o.Export.Name);
170          expect(exports).toEqual([
171              // This used to be used by aws-s3-assets
172              { 'Fn::Sub': 'CdkBootstrap-${Qualifier}-FileAssetKeyArn' },
173          ]);
174      });
175      describe('termination protection', () => {
176          test('stack is not termination protected by default', async () => {
177              await bootstrapper.bootstrapEnvironment(env, sdk, {
178                  parameters: {
179                      cloudFormationExecutionPolicies: ['arn:policy'],
180                  },
181              });
182              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
183                  stack: expect.objectContaining({
184                      terminationProtection: false,
185                  }),
186              }));
187          });
188          test('stack is termination protected when option is set', async () => {
189              await bootstrapper.bootstrapEnvironment(env, sdk, {
190                  terminationProtection: true,
191                  parameters: {
192                      cloudFormationExecutionPolicies: ['arn:policy'],
193                  },
194              });
195              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
196                  stack: expect.objectContaining({
197                      terminationProtection: true,
198                  }),
199              }));
200          });
201          test('termination protection is left alone when option is not given', async () => {
202              mockTheToolkitInfo({
203                  EnableTerminationProtection: true,
204              });
205              await bootstrapper.bootstrapEnvironment(env, sdk, {
206                  parameters: {
207                      cloudFormationExecutionPolicies: ['arn:policy'],
208                  },
209              });
210              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
211                  stack: expect.objectContaining({
212                      terminationProtection: true,
213                  }),
214              }));
215          });
216          test('termination protection can be switched off', async () => {
217              mockTheToolkitInfo({
218                  EnableTerminationProtection: true,
219              });
220              await bootstrapper.bootstrapEnvironment(env, sdk, {
221                  terminationProtection: false,
222                  parameters: {
223                      cloudFormationExecutionPolicies: ['arn:policy'],
224                  },
225              });
226              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
227                  stack: expect.objectContaining({
228                      terminationProtection: false,
229                  }),
230              }));
231          });
232      });
233      describe('KMS key', () => {
234          test.each([
235              // Default case
236              [undefined, 'AWS_MANAGED_KEY'],
237              // Create a new key
238              [true, ''],
239              // Don't create a new key
240              [false, 'AWS_MANAGED_KEY'],
241          ])('(new stack) createCustomerMasterKey=%p => parameter becomes %p ', async (createCustomerMasterKey, paramKeyId) => {
242              // GIVEN: no existing stack
243              // WHEN
244              await bootstrapper.bootstrapEnvironment(env, sdk, {
245                  parameters: {
246                      createCustomerMasterKey,
247                      cloudFormationExecutionPolicies: ['arn:booh'],
248                  },
249              });
250              // THEN
251              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
252                  parameters: expect.objectContaining({
253                      FileAssetsBucketKmsKeyId: paramKeyId,
254                  }),
255              }));
256          });
257          test.each([
258              // Old bootstrap stack being upgraded to new one
259              [undefined, undefined, 'AWS_MANAGED_KEY'],
260              // There is a value, user doesn't request a change
261              ['arn:aws:key', undefined, undefined],
262              // Switch off existing key
263              ['arn:aws:key', false, 'AWS_MANAGED_KEY'],
264              // Switch on existing key
265              ['AWS_MANAGED_KEY', true, ''],
266          ])('(upgrading) current param %p, createCustomerMasterKey=%p => parameter becomes %p ', async (currentKeyId, createCustomerMasterKey, paramKeyId) => {
267              // GIVEN
268              mockTheToolkitInfo({
269                  Parameters: currentKeyId ? [
270                      {
271                          ParameterKey: 'FileAssetsBucketKmsKeyId',
272                          ParameterValue: currentKeyId,
273                      },
274                  ] : undefined,
275              });
276              // WHEN
277              await bootstrapper.bootstrapEnvironment(env, sdk, {
278                  parameters: {
279                      createCustomerMasterKey,
280                      cloudFormationExecutionPolicies: ['arn:booh'],
281                  },
282              });
283              // THEN
284              expect(mockDeployStack).toHaveBeenCalledWith(expect.objectContaining({
285                  parameters: expect.objectContaining({
286                      FileAssetsBucketKmsKeyId: paramKeyId,
287                  }),
288              }));
289          });
290      });
291  });
292  //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYm9vdHN0cmFwMi50ZXN0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiYm9vdHN0cmFwMi50ZXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBQUEsTUFBTSxlQUFlLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0FBRWxDLElBQUksQ0FBQyxJQUFJLENBQUMsNEJBQTRCLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUM3QyxXQUFXLEVBQUUsZUFBZTtDQUM3QixDQUFDLENBQUMsQ0FBQztBQUVKLHVDQUE4RTtBQUM5RSwrQ0FBZ0Y7QUFFaEYsSUFBSSxZQUEwQixDQUFDO0FBQy9CLFVBQVUsQ0FBQyxHQUFHLEVBQUU7SUFDZCxZQUFZLEdBQUcsSUFBSSxrQkFBWSxDQUFDLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxDQUFDLENBQUM7QUFDekQsQ0FBQyxDQUFDLENBQUM7QUFFSCxTQUFTLGtCQUFrQixDQUFDLFVBQTZDO0lBQ3ZFLE1BQU0sR0FBRyxHQUFHLElBQUksa0JBQU8sRUFBRSxDQUFDO0lBQ3pCLGlCQUFtQixDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsaUJBQWlCLENBQUMsaUJBQVcsQ0FBQyxTQUFTLENBQUMsNkJBQWtCLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7QUFDN0gsQ0FBQztBQUVELFFBQVEsQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLEVBQUU7SUFDaEMsTUFBTSxHQUFHLEdBQUc7UUFDVixPQUFPLEVBQUUsY0FBYztRQUN2QixNQUFNLEVBQUUsV0FBVztRQUNuQixJQUFJLEVBQUUsTUFBTTtLQUNiLENBQUM7SUFFRixJQUFJLEdBQW9CLENBQUM7SUFDekIsVUFBVSxDQUFDLEdBQUcsRUFBRTtRQUNkLEdBQUcsR0FBRyxJQUFJLDBCQUFlLENBQUMsRUFBRSxPQUFPLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztRQUM5QyxvREFBb0Q7UUFDbkQsaUJBQW1CLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQyxFQUFFLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxpQkFBVyxDQUFDLDRCQUE0QixDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBQy9HLENBQUMsQ0FBQyxDQUFDO0lBRUgsU0FBUyxDQUFDLEdBQUcsRUFBRTtRQUNiLGVBQWUsQ0FBQyxTQUFTLEVBQUUsQ0FBQztJQUM5QixDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQywyQ0FBMkMsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMzRCxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1lBQ2hELFVBQVUsRUFBRTtnQkFDVixVQUFVLEVBQUUsZ0JBQWdCO2dCQUM1QiwrQkFBK0IsRUFBRSxDQUFDLFlBQVksQ0FBQzthQUNoRDtTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7WUFDbkUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbEMsb0JBQW9CLEVBQUUsZ0JBQWdCO2dCQUN0Qyw4QkFBOEIsRUFBRSxNQUFNO2FBQ3ZDLENBQUM7U0FDSCxDQUFDLENBQUMsQ0FBQztJQUNOLENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDLDBDQUEwQyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQzFELE1BQU0sWUFBWSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUU7WUFDaEQsVUFBVSxFQUFFO2dCQUNWLCtCQUErQixFQUFFLENBQUMsWUFBWSxDQUFDO2dCQUMvQyxRQUFRLEVBQUUsZUFBZTthQUMxQjtTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7WUFDbkUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbEMsd0JBQXdCLEVBQUUsZUFBZTtnQkFDekMsOEJBQThCLEVBQUUsTUFBTTthQUN2QyxDQUFDO1NBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQyxnREFBZ0QsRUFBRSxLQUFLLElBQUksRUFBRTtRQUNoRSxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1lBQ2hELFVBQVUsRUFBRTtnQkFDViwrQkFBK0IsRUFBRSxDQUFDLFlBQVksQ0FBQztnQkFDL0MsOEJBQThCLEVBQUUsS0FBSzthQUN0QztTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7WUFDbkUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbEMsOEJBQThCLEVBQUUsT0FBTzthQUN4QyxDQUFDO1NBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQywyRUFBMkUsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMzRixNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtZQUN2RCxVQUFVLEVBQUU7Z0JBQ1YsZUFBZSxFQUFFLENBQUMsY0FBYyxDQUFDO2FBQ2xDO1NBQ0YsQ0FBQyxDQUFDO2FBQ0EsT0FBTzthQUNQLE9BQU8sQ0FBQyxxQ0FBcUMsQ0FBQyxDQUFDO0lBQ3BELENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDLGlHQUFpRyxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ2pILGtCQUFrQixDQUFDO1lBQ2pCLFVBQVUsRUFBRTtnQkFDVjtvQkFDRSxZQUFZLEVBQUUsaUNBQWlDO29CQUMvQyxjQUFjLEVBQUUsRUFBRTtpQkFDbkI7YUFDRjtTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sTUFBTSxDQUFDLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1lBQ3ZELFVBQVUsRUFBRTtnQkFDVixlQUFlLEVBQUUsQ0FBQyxjQUFjLENBQUM7YUFDbEM7U0FDRixDQUFDLENBQUM7YUFDQSxPQUFPO2FBQ1AsT0FBTyxDQUFDLHFDQUFxQyxDQUFDLENBQUM7SUFDcEQsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsa0VBQWtFLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDbEYsTUFBTSxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtZQUNoRCxVQUFVLEVBQUUsRUFBRTtTQUNmLENBQUMsQ0FBQztRQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7WUFDbkUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbEMsK0JBQStCLEVBQUUsRUFBRTthQUNwQyxDQUFDO1NBQ0gsQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDLENBQUMsQ0FBQztJQUVILElBQUksQ0FBQywyRUFBMkUsRUFBRSxLQUFLLElBQUksRUFBRTtRQUMzRixNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1lBQ2hELFVBQVUsRUFBRTtnQkFDVix3QkFBd0IsRUFBRSxDQUFDLGNBQWMsQ0FBQztnQkFDMUMsK0JBQStCLEVBQUUsQ0FBQyxXQUFXLENBQUM7YUFDL0M7U0FDRixDQUFDLENBQUM7UUFFSCxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDO1lBQ25FLFVBQVUsRUFBRSxNQUFNLENBQUMsZ0JBQWdCLENBQUM7Z0JBQ2xDLHdCQUF3QixFQUFFLGNBQWM7YUFDekMsQ0FBQztTQUNILENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMseUVBQXlFLEVBQUUsS0FBSyxJQUFJLEVBQUU7UUFDekYsUUFBUTtRQUNSLGtCQUFrQixDQUFDO1lBQ2pCLFVBQVUsRUFBRTtnQkFDVjtvQkFDRSxZQUFZLEVBQUUsaUNBQWlDO29CQUMvQyxjQUFjLEVBQUUsbUJBQW1CO2lCQUNwQzthQUNGO1NBQ0YsQ0FBQyxDQUFDO1FBRUgsTUFBTSxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtZQUNoRCxVQUFVLEVBQUU7Z0JBQ1YsZUFBZSxFQUFFLENBQUMsY0FBYyxDQUFDO2FBQ2xDO1NBQ0YsQ0FBQyxDQUFDO1FBQ0gsZ0JBQWdCO0lBQ2xCLENBQUMsQ0FBQyxDQUFDO0lBRUgsSUFBSSxDQUFDLGtEQUFrRCxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ2xFLFFBQVE7UUFDUixrQkFBa0IsQ0FBQztZQUNqQixPQUFPLEVBQUU7Z0JBQ1A7b0JBQ0UsU0FBUyxFQUFFLGtCQUFrQjtvQkFDN0IsV0FBVyxFQUFFLEtBQUs7aUJBQ25CO2FBQ0Y7U0FDRixDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sQ0FBQyxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtZQUN2RCxVQUFVLEVBQUU7Z0JBQ1YsK0JBQStCLEVBQUUsQ0FBQyxZQUFZLENBQUM7YUFDaEQ7U0FDRixDQUFDLENBQUM7YUFDQSxPQUFPLENBQUMsT0FBTyxDQUFDLDBDQUEwQyxDQUFDLENBQUM7SUFDakUsQ0FBQyxDQUFDLENBQUM7SUFFSCxJQUFJLENBQUMsMENBQTBDLEVBQUUsS0FBSyxJQUFJLEVBQUU7O1FBQzFELElBQUksUUFBYSxDQUFDO1FBQ2xCLGVBQWUsQ0FBQyxrQkFBa0IsQ0FBQyxDQUFDLElBQXdCLEVBQUUsRUFBRTtZQUM5RCxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUM7UUFDakMsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO1lBQ2hELFVBQVUsRUFBRTtnQkFDViwrQkFBK0IsRUFBRSxDQUFDLFlBQVksQ0FBQzthQUNoRDtTQUNGLENBQUMsQ0FBQztRQUVILE1BQU0sT0FBTyxHQUFHLE1BQU0sQ0FBQyxNQUFNLE9BQUMsUUFBUSxDQUFDLE9BQU8sbUNBQUksRUFBRSxDQUFDO2FBQ2xELE1BQU0sQ0FBQyxDQUFDLENBQU0sRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLE1BQU0sS0FBSyxTQUFTLENBQUM7YUFDMUMsR0FBRyxDQUFDLENBQUMsQ0FBTSxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBRWxDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDdEIsd0NBQXdDO1lBQ3hDLEVBQUUsU0FBUyxFQUFFLDJDQUEyQyxFQUFFO1NBQzNELENBQUMsQ0FBQztJQUNMLENBQUMsQ0FBQyxDQUFDO0lBRUgsUUFBUSxDQUFDLHdCQUF3QixFQUFFLEdBQUcsRUFBRTtRQUN0QyxJQUFJLENBQUMsK0NBQStDLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDL0QsTUFBTSxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtnQkFDaEQsVUFBVSxFQUFFO29CQUNWLCtCQUErQixFQUFFLENBQUMsWUFBWSxDQUFDO2lCQUNoRDthQUNGLENBQUMsQ0FBQztZQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7Z0JBQ25FLEtBQUssRUFBRSxNQUFNLENBQUMsZ0JBQWdCLENBQUM7b0JBQzdCLHFCQUFxQixFQUFFLEtBQUs7aUJBQzdCLENBQUM7YUFDSCxDQUFDLENBQUMsQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO1FBRUgsSUFBSSxDQUFDLG1EQUFtRCxFQUFFLEtBQUssSUFBSSxFQUFFO1lBQ25FLE1BQU0sWUFBWSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUU7Z0JBQ2hELHFCQUFxQixFQUFFLElBQUk7Z0JBQzNCLFVBQVUsRUFBRTtvQkFDViwrQkFBK0IsRUFBRSxDQUFDLFlBQVksQ0FBQztpQkFDaEQ7YUFDRixDQUFDLENBQUM7WUFFSCxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDO2dCQUNuRSxLQUFLLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDO29CQUM3QixxQkFBcUIsRUFBRSxJQUFJO2lCQUM1QixDQUFDO2FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTixDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQywrREFBK0QsRUFBRSxLQUFLLElBQUksRUFBRTtZQUMvRSxrQkFBa0IsQ0FBQztnQkFDakIsMkJBQTJCLEVBQUUsSUFBSTthQUNsQyxDQUFDLENBQUM7WUFFSCxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO2dCQUNoRCxVQUFVLEVBQUU7b0JBQ1YsK0JBQStCLEVBQUUsQ0FBQyxZQUFZLENBQUM7aUJBQ2hEO2FBQ0YsQ0FBQyxDQUFDO1lBRUgsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbkUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDN0IscUJBQXFCLEVBQUUsSUFBSTtpQkFDNUIsQ0FBQzthQUNILENBQUMsQ0FBQyxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7UUFFSCxJQUFJLENBQUMsNENBQTRDLEVBQUUsS0FBSyxJQUFJLEVBQUU7WUFDNUQsa0JBQWtCLENBQUM7Z0JBQ2pCLDJCQUEyQixFQUFFLElBQUk7YUFDbEMsQ0FBQyxDQUFDO1lBRUgsTUFBTSxZQUFZLENBQUMsb0JBQW9CLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRTtnQkFDaEQscUJBQXFCLEVBQUUsS0FBSztnQkFDNUIsVUFBVSxFQUFFO29CQUNWLCtCQUErQixFQUFFLENBQUMsWUFBWSxDQUFDO2lCQUNoRDthQUNGLENBQUMsQ0FBQztZQUVILE1BQU0sQ0FBQyxlQUFlLENBQUMsQ0FBQyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUM7Z0JBQ25FLEtBQUssRUFBRSxNQUFNLENBQUMsZ0JBQWdCLENBQUM7b0JBQzdCLHFCQUFxQixFQUFFLEtBQUs7aUJBQzdCLENBQUM7YUFDSCxDQUFDLENBQUMsQ0FBQztRQUNOLENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQyxDQUFDLENBQUM7SUFFSCxRQUFRLENBQUMsU0FBUyxFQUFFLEdBQUcsRUFBRTtRQUN2QixJQUFJLENBQUMsSUFBSSxDQUFDO1lBQ1IsZUFBZTtZQUNmLENBQUMsU0FBUyxFQUFFLGlCQUFpQixDQUFDO1lBQzlCLG1CQUFtQjtZQUNuQixDQUFDLElBQUksRUFBRSxFQUFFLENBQUM7WUFDVix5QkFBeUI7WUFDekIsQ0FBQyxLQUFLLEVBQUUsaUJBQWlCLENBQUM7U0FDM0IsQ0FBQyxDQUFDLGlFQUFpRSxFQUFFLEtBQUssRUFBRSx1QkFBdUIsRUFBRSxVQUFVLEVBQUUsRUFBRTtZQUNsSCwyQkFBMkI7WUFFM0IsT0FBTztZQUNQLE1BQU0sWUFBWSxDQUFDLG9CQUFvQixDQUFDLEdBQUcsRUFBRSxHQUFHLEVBQUU7Z0JBQ2hELFVBQVUsRUFBRTtvQkFDVix1QkFBdUI7b0JBQ3ZCLCtCQUErQixFQUFFLENBQUMsVUFBVSxDQUFDO2lCQUM5QzthQUNGLENBQUMsQ0FBQztZQUVILE9BQU87WUFDUCxNQUFNLENBQUMsZUFBZSxDQUFDLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDO2dCQUNuRSxVQUFVLEVBQUUsTUFBTSxDQUFDLGdCQUFnQixDQUFDO29CQUNsQyx3QkFBd0IsRUFBRSxVQUFVO2lCQUNyQyxDQUFDO2FBQ0gsQ0FBQyxDQUFDLENBQUM7UUFDTixDQUFDLENBQUMsQ0FBQztRQUVILElBQUksQ0FBQyxJQUFJLENBQUM7WUFDUixnREFBZ0Q7WUFDaEQsQ0FBQyxTQUFTLEVBQUUsU0FBUyxFQUFFLGlCQUFpQixDQUFDO1lBQ3pDLGtEQUFrRDtZQUNsRCxDQUFDLGFBQWEsRUFBRSxTQUFTLEVBQUUsU0FBUyxDQUFDO1lBQ3JDLDBCQUEwQjtZQUMxQixDQUFDLGFBQWEsRUFBRSxLQUFLLEVBQUUsaUJBQWlCLENBQUM7WUFDekMseUJBQXlCO1lBQ3pCLENBQUMsaUJBQWlCLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQztTQUM5QixDQUFDLENBQUMsbUZBQW1GLEVBQUUsS0FBSyxFQUFFLFlBQVksRUFBRSx1QkFBdUIsRUFBRSxVQUFVLEVBQUUsRUFBRTtZQUNsSixRQUFRO1lBQ1Isa0JBQWtCLENBQUM7Z0JBQ2pCLFVBQVUsRUFBRSxZQUFZLENBQUMsQ0FBQyxDQUFDO29CQUN6Qjt3QkFDRSxZQUFZLEVBQUUsMEJBQTBCO3dCQUN4QyxjQUFjLEVBQUUsWUFBWTtxQkFDN0I7aUJBQ0YsQ0FBQyxDQUFDLENBQUMsU0FBUzthQUNkLENBQUMsQ0FBQztZQUVILE9BQU87WUFDUCxNQUFNLFlBQVksQ0FBQyxvQkFBb0IsQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFO2dCQUNoRCxVQUFVLEVBQUU7b0JBQ1YsdUJBQXVCO29CQUN2QiwrQkFBK0IsRUFBRSxDQUFDLFVBQVUsQ0FBQztpQkFDOUM7YUFDRixDQUFDLENBQUM7WUFFSCxPQUFPO1lBQ1AsTUFBTSxDQUFDLGVBQWUsQ0FBQyxDQUFDLG9CQUFvQixDQUFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztnQkFDbkUsVUFBVSxFQUFFLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztvQkFDbEMsd0JBQXdCLEVBQUUsVUFBVTtpQkFDckMsQ0FBQzthQUNILENBQUMsQ0FBQyxDQUFDO1FBQ04sQ0FBQyxDQUFDLENBQUM7SUFDTCxDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiY29uc3QgbW9ja0RlcGxveVN0YWNrID0gamVzdC5mbigpO1xuXG5qZXN0Lm1vY2soJy4uLy4uL2xpYi9hcGkvZGVwbG95LXN0YWNrJywgKCkgPT4gKHtcbiAgZGVwbG95U3RhY2s6IG1vY2tEZXBsb3lTdGFjayxcbn0pKTtcblxuaW1wb3J0IHsgQm9vdHN0cmFwcGVyLCBEZXBsb3lTdGFja09wdGlvbnMsIFRvb2xraXRJbmZvIH0gZnJvbSAnLi4vLi4vbGliL2FwaSc7XG5pbXBvcnQgeyBtb2NrQm9vdHN0cmFwU3RhY2ssIE1vY2tTZGssIE1vY2tTZGtQcm92aWRlciB9IGZyb20gJy4uL3V0aWwvbW9jay1zZGsnO1xuXG5sZXQgYm9vdHN0cmFwcGVyOiBCb290c3RyYXBwZXI7XG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgYm9vdHN0cmFwcGVyID0gbmV3IEJvb3RzdHJhcHBlcih7IHNvdXJjZTogJ2RlZmF1bHQnIH0pO1xufSk7XG5cbmZ1bmN0aW9uIG1vY2tUaGVUb29sa2l0SW5mbyhzdGFja1Byb3BzOiBQYXJ0aWFsPEFXUy5DbG91ZEZvcm1hdGlvbi5TdGFjaz4pIHtcbiAgY29uc3Qgc2RrID0gbmV3IE1vY2tTZGsoKTtcbiAgKFRvb2xraXRJbmZvIGFzIGFueSkubG9va3VwID0gamVzdC5mbigpLm1vY2tSZXNvbHZlZFZhbHVlKFRvb2xraXRJbmZvLmZyb21TdGFjayhtb2NrQm9vdHN0cmFwU3RhY2soc2RrLCBzdGFja1Byb3BzKSwgc2RrKSk7XG59XG5cbmRlc2NyaWJlKCdCb290c3RyYXBwaW5nIHYyJywgKCkgPT4ge1xuICBjb25zdCBlbnYgPSB7XG4gICAgYWNjb3VudDogJzEyMzQ1Njc4OTAxMicsXG4gICAgcmVnaW9uOiAndXMtZWFzdC0xJyxcbiAgICBuYW1lOiAnbW9jaycsXG4gIH07XG5cbiAgbGV0IHNkazogTW9ja1Nka1Byb3ZpZGVyO1xuICBiZWZvcmVFYWNoKCgpID0+IHtcbiAgICBzZGsgPSBuZXcgTW9ja1Nka1Byb3ZpZGVyKHsgcmVhbFNkazogZmFsc2UgfSk7XG4gICAgLy8gQnkgZGVmYXVsdCwgd2UnbGwgcmV0dXJuIGEgbm9uLWZvdW5kIHRvb2xraXQgaW5mb1xuICAgIChUb29sa2l0SW5mbyBhcyBhbnkpLmxvb2t1cCA9IGplc3QuZm4oKS5tb2NrUmVzb2x2ZWRWYWx1ZShUb29sa2l0SW5mby5ib290c3RyYXBsZXNzRGVwbG95bWVudHNPbmx5KHNkay5zZGspKTtcbiAgfSk7XG5cbiAgYWZ0ZXJFYWNoKCgpID0+IHtcbiAgICBtb2NrRGVwbG95U3RhY2subW9ja0NsZWFyKCk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyB0aGUgYnVja2V0IG5hbWUgYXMgYSBDRk4gcGFyYW1ldGVyJywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBidWNrZXROYW1lOiAnbXktYnVja2V0LW5hbWUnLFxuICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBwYXJhbWV0ZXJzOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIEZpbGVBc3NldHNCdWNrZXROYW1lOiAnbXktYnVja2V0LW5hbWUnLFxuICAgICAgICBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246ICd0cnVlJyxcbiAgICAgIH0pLFxuICAgIH0pKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2VzIHRoZSBLTVMga2V5IElEIGFzIGEgQ0ZOIHBhcmFtZXRlcicsIGFzeW5jICgpID0+IHtcbiAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46cG9saWN5J10sXG4gICAgICAgIGttc0tleUlkOiAnbXkta21zLWtleS1pZCcsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBGaWxlQXNzZXRzQnVja2V0S21zS2V5SWQ6ICdteS1rbXMta2V5LWlkJyxcbiAgICAgICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiAndHJ1ZScsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NlcyBmYWxzZSB0byBQdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb24nLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgICBwdWJsaWNBY2Nlc3NCbG9ja0NvbmZpZ3VyYXRpb246IGZhbHNlLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgUHVibGljQWNjZXNzQmxvY2tDb25maWd1cmF0aW9uOiAnZmFsc2UnLFxuICAgICAgfSksXG4gICAgfSkpO1xuICB9KTtcblxuICB0ZXN0KCdwYXNzaW5nIHRydXN0ZWQgYWNjb3VudHMgd2l0aG91dCBDRk4gbWFuYWdlZCBwb2xpY2llcyByZXN1bHRzIGluIGFuIGVycm9yJywgYXN5bmMgKCkgPT4ge1xuICAgIGF3YWl0IGV4cGVjdChib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgdHJ1c3RlZEFjY291bnRzOiBbJzEyMzQ1Njc4OTAxMiddLFxuICAgICAgfSxcbiAgICB9KSlcbiAgICAgIC5yZWplY3RzXG4gICAgICAudG9UaHJvdygvLS1jbG91ZGZvcm1hdGlvbi1leGVjdXRpb24tcG9saWNpZXMvKTtcbiAgfSk7XG5cbiAgdGVzdCgncGFzc2luZyB0cnVzdGVkIGFjY291bnRzIHdpdGhvdXQgQ0ZOIG1hbmFnZWQgcG9saWNpZXMgb24gdGhlIGV4aXN0aW5nIHN0YWNrIHJlc3VsdHMgaW4gYW4gZXJyb3InLCBhc3luYyAoKSA9PiB7XG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXMnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnJyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50czogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgIH0sXG4gICAgfSkpXG4gICAgICAucmVqZWN0c1xuICAgICAgLnRvVGhyb3coLy0tY2xvdWRmb3JtYXRpb24tZXhlY3V0aW9uLXBvbGljaWVzLyk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3Npbmcgbm8gQ0ZOIG1hbmFnZWQgcG9saWNpZXMgd2l0aG91dCB0cnVzdGVkIGFjY291bnRzIGlzIG9rYXknLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7fSxcbiAgICB9KTtcblxuICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgQ2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogJycsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ3Bhc3NpbmcgdHJ1c3RlZCBhY2NvdW50cyBmb3IgbG9va3VwIGdlbmVyYXRlcyB0aGUgY29ycmVjdCBzdGFjayBwYXJhbWV0ZXInLCBhc3luYyAoKSA9PiB7XG4gICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIHRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogWycxMjM0NTY3ODkwMTInXSxcbiAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhd3M6Ly9mb28nXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICBwYXJhbWV0ZXJzOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIFRydXN0ZWRBY2NvdW50c0Zvckxvb2t1cDogJzEyMzQ1Njc4OTAxMicsXG4gICAgICB9KSxcbiAgICB9KSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2FsbG93IGFkZGluZyB0cnVzdGVkIGFjY291bnQgaWYgdGhlcmUgd2FzIGFscmVhZHkgYSBwb2xpY3kgb24gdGhlIHN0YWNrJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIFBhcmFtZXRlcnM6IFtcbiAgICAgICAge1xuICAgICAgICAgIFBhcmFtZXRlcktleTogJ0Nsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXMnLFxuICAgICAgICAgIFBhcmFtZXRlclZhbHVlOiAnYXJuOmF3czpzb21ldGhpbmcnLFxuICAgICAgICB9LFxuICAgICAgXSxcbiAgICB9KTtcblxuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICB0cnVzdGVkQWNjb3VudHM6IFsnMTIzNDU2Nzg5MDEyJ10sXG4gICAgICB9LFxuICAgIH0pO1xuICAgIC8vIERpZCBub3QgdGhyb3dcbiAgfSk7XG5cbiAgdGVzdCgnRG8gbm90IGFsbG93IGRvd25ncmFkaW5nIGJvb3RzdHJhcCBzdGFjayB2ZXJzaW9uJywgYXN5bmMgKCkgPT4ge1xuICAgIC8vIEdJVkVOXG4gICAgbW9ja1RoZVRvb2xraXRJbmZvKHtcbiAgICAgIE91dHB1dHM6IFtcbiAgICAgICAge1xuICAgICAgICAgIE91dHB1dEtleTogJ0Jvb3RzdHJhcFZlcnNpb24nLFxuICAgICAgICAgIE91dHB1dFZhbHVlOiAnOTk5JyxcbiAgICAgICAgfSxcbiAgICAgIF0sXG4gICAgfSk7XG5cbiAgICBhd2FpdCBleHBlY3QoYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgfSxcbiAgICB9KSlcbiAgICAgIC5yZWplY3RzLnRvVGhyb3coJ05vdCBkb3duZ3JhZGluZyBleGlzdGluZyBib290c3RyYXAgc3RhY2snKTtcbiAgfSk7XG5cbiAgdGVzdCgnYm9vdHN0cmFwIHRlbXBsYXRlIGhhcyB0aGUgcmlnaHQgZXhwb3J0cycsIGFzeW5jICgpID0+IHtcbiAgICBsZXQgdGVtcGxhdGU6IGFueTtcbiAgICBtb2NrRGVwbG95U3RhY2subW9ja0ltcGxlbWVudGF0aW9uKChhcmdzOiBEZXBsb3lTdGFja09wdGlvbnMpID0+IHtcbiAgICAgIHRlbXBsYXRlID0gYXJncy5zdGFjay50ZW1wbGF0ZTtcbiAgICB9KTtcblxuICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBleHBvcnRzID0gT2JqZWN0LnZhbHVlcyh0ZW1wbGF0ZS5PdXRwdXRzID8/IHt9KVxuICAgICAgLmZpbHRlcigobzogYW55KSA9PiBvLkV4cG9ydCAhPT0gdW5kZWZpbmVkKVxuICAgICAgLm1hcCgobzogYW55KSA9PiBvLkV4cG9ydC5OYW1lKTtcblxuICAgIGV4cGVjdChleHBvcnRzKS50b0VxdWFsKFtcbiAgICAgIC8vIFRoaXMgdXNlZCB0byBiZSB1c2VkIGJ5IGF3cy1zMy1hc3NldHNcbiAgICAgIHsgJ0ZuOjpTdWInOiAnQ2RrQm9vdHN0cmFwLSR7UXVhbGlmaWVyfS1GaWxlQXNzZXRLZXlBcm4nIH0sXG4gICAgXSk7XG4gIH0pO1xuXG4gIGRlc2NyaWJlKCd0ZXJtaW5hdGlvbiBwcm90ZWN0aW9uJywgKCkgPT4ge1xuICAgIHRlc3QoJ3N0YWNrIGlzIG5vdCB0ZXJtaW5hdGlvbiBwcm90ZWN0ZWQgYnkgZGVmYXVsdCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46cG9saWN5J10sXG4gICAgICAgIH0sXG4gICAgICB9KTtcblxuICAgICAgZXhwZWN0KG1vY2tEZXBsb3lTdGFjaykudG9IYXZlQmVlbkNhbGxlZFdpdGgoZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICBzdGFjazogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIHRlcm1pbmF0aW9uUHJvdGVjdGlvbjogZmFsc2UsXG4gICAgICAgIH0pLFxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGVzdCgnc3RhY2sgaXMgdGVybWluYXRpb24gcHJvdGVjdGVkIHdoZW4gb3B0aW9uIGlzIHNldCcsIGFzeW5jICgpID0+IHtcbiAgICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IHRydWUsXG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHN0YWNrOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiB0cnVlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3Rlcm1pbmF0aW9uIHByb3RlY3Rpb24gaXMgbGVmdCBhbG9uZSB3aGVuIG9wdGlvbiBpcyBub3QgZ2l2ZW4nLCBhc3luYyAoKSA9PiB7XG4gICAgICBtb2NrVGhlVG9vbGtpdEluZm8oe1xuICAgICAgICBFbmFibGVUZXJtaW5hdGlvblByb3RlY3Rpb246IHRydWUsXG4gICAgICB9KTtcblxuICAgICAgYXdhaXQgYm9vdHN0cmFwcGVyLmJvb3RzdHJhcEVudmlyb25tZW50KGVudiwgc2RrLCB7XG4gICAgICAgIHBhcmFtZXRlcnM6IHtcbiAgICAgICAgICBjbG91ZEZvcm1hdGlvbkV4ZWN1dGlvblBvbGljaWVzOiBbJ2Fybjpwb2xpY3knXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHN0YWNrOiBleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiB0cnVlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcblxuICAgIHRlc3QoJ3Rlcm1pbmF0aW9uIHByb3RlY3Rpb24gY2FuIGJlIHN3aXRjaGVkIG9mZicsIGFzeW5jICgpID0+IHtcbiAgICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICAgIEVuYWJsZVRlcm1pbmF0aW9uUHJvdGVjdGlvbjogdHJ1ZSxcbiAgICAgIH0pO1xuXG4gICAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgICAgdGVybWluYXRpb25Qcm90ZWN0aW9uOiBmYWxzZSxcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOnBvbGljeSddLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgc3RhY2s6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICB0ZXJtaW5hdGlvblByb3RlY3Rpb246IGZhbHNlLFxuICAgICAgICB9KSxcbiAgICAgIH0pKTtcbiAgICB9KTtcbiAgfSk7XG5cbiAgZGVzY3JpYmUoJ0tNUyBrZXknLCAoKSA9PiB7XG4gICAgdGVzdC5lYWNoKFtcbiAgICAgIC8vIERlZmF1bHQgY2FzZVxuICAgICAgW3VuZGVmaW5lZCwgJ0FXU19NQU5BR0VEX0tFWSddLFxuICAgICAgLy8gQ3JlYXRlIGEgbmV3IGtleVxuICAgICAgW3RydWUsICcnXSxcbiAgICAgIC8vIERvbid0IGNyZWF0ZSBhIG5ldyBrZXlcbiAgICAgIFtmYWxzZSwgJ0FXU19NQU5BR0VEX0tFWSddLFxuICAgIF0pKCcobmV3IHN0YWNrKSBjcmVhdGVDdXN0b21lck1hc3RlcktleT0lcCA9PiBwYXJhbWV0ZXIgYmVjb21lcyAlcCAnLCBhc3luYyAoY3JlYXRlQ3VzdG9tZXJNYXN0ZXJLZXksIHBhcmFtS2V5SWQpID0+IHtcbiAgICAgIC8vIEdJVkVOOiBubyBleGlzdGluZyBzdGFja1xuXG4gICAgICAvLyBXSEVOXG4gICAgICBhd2FpdCBib290c3RyYXBwZXIuYm9vdHN0cmFwRW52aXJvbm1lbnQoZW52LCBzZGssIHtcbiAgICAgICAgcGFyYW1ldGVyczoge1xuICAgICAgICAgIGNyZWF0ZUN1c3RvbWVyTWFzdGVyS2V5LFxuICAgICAgICAgIGNsb3VkRm9ybWF0aW9uRXhlY3V0aW9uUG9saWNpZXM6IFsnYXJuOmJvb2gnXSxcbiAgICAgICAgfSxcbiAgICAgIH0pO1xuXG4gICAgICAvLyBUSEVOXG4gICAgICBleHBlY3QobW9ja0RlcGxveVN0YWNrKS50b0hhdmVCZWVuQ2FsbGVkV2l0aChleHBlY3Qub2JqZWN0Q29udGFpbmluZyh7XG4gICAgICAgIHBhcmFtZXRlcnM6IGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgICBGaWxlQXNzZXRzQnVja2V0S21zS2V5SWQ6IHBhcmFtS2V5SWQsXG4gICAgICAgIH0pLFxuICAgICAgfSkpO1xuICAgIH0pO1xuXG4gICAgdGVzdC5lYWNoKFtcbiAgICAgIC8vIE9sZCBib290c3RyYXAgc3RhY2sgYmVpbmcgdXBncmFkZWQgdG8gbmV3IG9uZVxuICAgICAgW3VuZGVmaW5lZCwgdW5kZWZpbmVkLCAnQVdTX01BTkFHRURfS0VZJ10sXG4gICAgICAvLyBUaGVyZSBpcyBhIHZhbHVlLCB1c2VyIGRvZXNuJ3QgcmVxdWVzdCBhIGNoYW5nZVxuICAgICAgWydhcm46YXdzOmtleScsIHVuZGVmaW5lZCwgdW5kZWZpbmVkXSxcbiAgICAgIC8vIFN3aXRjaCBvZmYgZXhpc3Rpbmcga2V5XG4gICAgICBbJ2Fybjphd3M6a2V5JywgZmFsc2UsICdBV1NfTUFOQUdFRF9LRVknXSxcbiAgICAgIC8vIFN3aXRjaCBvbiBleGlzdGluZyBrZXlcbiAgICAgIFsnQVdTX01BTkFHRURfS0VZJywgdHJ1ZSwgJyddLFxuICAgIF0pKCcodXBncmFkaW5nKSBjdXJyZW50IHBhcmFtICVwLCBjcmVhdGVDdXN0b21lck1hc3RlcktleT0lcCA9PiBwYXJhbWV0ZXIgYmVjb21lcyAlcCAnLCBhc3luYyAoY3VycmVudEtleUlkLCBjcmVhdGVDdXN0b21lck1hc3RlcktleSwgcGFyYW1LZXlJZCkgPT4ge1xuICAgICAgLy8gR0lWRU5cbiAgICAgIG1vY2tUaGVUb29sa2l0SW5mbyh7XG4gICAgICAgIFBhcmFtZXRlcnM6IGN1cnJlbnRLZXlJZCA/IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBQYXJhbWV0ZXJLZXk6ICdGaWxlQXNzZXRzQnVja2V0S21zS2V5SWQnLFxuICAgICAgICAgICAgUGFyYW1ldGVyVmFsdWU6IGN1cnJlbnRLZXlJZCxcbiAgICAgICAgICB9LFxuICAgICAgICBdIDogdW5kZWZpbmVkLFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFdIRU5cbiAgICAgIGF3YWl0IGJvb3RzdHJhcHBlci5ib290c3RyYXBFbnZpcm9ubWVudChlbnYsIHNkaywge1xuICAgICAgICBwYXJhbWV0ZXJzOiB7XG4gICAgICAgICAgY3JlYXRlQ3VzdG9tZXJNYXN0ZXJLZXksXG4gICAgICAgICAgY2xvdWRGb3JtYXRpb25FeGVjdXRpb25Qb2xpY2llczogWydhcm46Ym9vaCddLFxuICAgICAgICB9LFxuICAgICAgfSk7XG5cbiAgICAgIC8vIFRIRU5cbiAgICAgIGV4cGVjdChtb2NrRGVwbG95U3RhY2spLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKGV4cGVjdC5vYmplY3RDb250YWluaW5nKHtcbiAgICAgICAgcGFyYW1ldGVyczogZXhwZWN0Lm9iamVjdENvbnRhaW5pbmcoe1xuICAgICAgICAgIEZpbGVBc3NldHNCdWNrZXRLbXNLZXlJZDogcGFyYW1LZXlJZCxcbiAgICAgICAgfSksXG4gICAgICB9KSk7XG4gICAgfSk7XG4gIH0pO1xufSk7Il19