aws-cdk 2.1.0 → 2.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/NOTICE +1 -1
- package/README.md +5 -1
- package/build-info.json +2 -2
- package/lib/api/aws-auth/sdk-provider.js +11 -21
- package/lib/api/aws-auth/sdk.d.ts +2 -0
- package/lib/api/aws-auth/sdk.js +4 -1
- package/lib/api/bootstrap/bootstrap-template.yaml +3 -1
- package/lib/api/deploy-stack.js +7 -1
- package/lib/api/hotswap/code-build-projects.d.ts +3 -0
- package/lib/api/hotswap/code-build-projects.js +53 -0
- package/lib/api/hotswap/common.d.ts +17 -1
- package/lib/api/hotswap/common.js +30 -6
- package/lib/api/hotswap/ecs-services.js +4 -18
- package/lib/api/hotswap/evaluate-cloudformation-template.d.ts +1 -0
- package/lib/api/hotswap/evaluate-cloudformation-template.js +6 -1
- package/lib/api/hotswap/lambda-functions.d.ts +2 -2
- package/lib/api/hotswap/lambda-functions.js +171 -46
- package/lib/api/hotswap/s3-bucket-deployments.d.ts +8 -0
- package/lib/api/hotswap/s3-bucket-deployments.js +106 -0
- package/lib/api/hotswap/stepfunctions-state-machines.js +11 -7
- package/lib/api/hotswap-deployments.d.ts +0 -7
- package/lib/api/hotswap-deployments.js +86 -12
- package/lib/cdk-toolkit.js +50 -16
- package/lib/commands/docs.js +2 -2
- package/lib/context-providers/index.d.ts +10 -5
- package/lib/context-providers/index.js +32 -19
- package/lib/context-providers/provider.d.ts +1 -0
- package/lib/context-providers/provider.js +6 -1
- package/lib/init.js +2 -1
- package/lib/plugin.d.ts +20 -0
- package/lib/plugin.js +28 -1
- package/lib/util/asset-publishing.js +9 -2
- package/lib/util/npm.d.ts +1 -0
- package/lib/util/npm.js +21 -0
- package/lib/version.d.ts +1 -1
- package/lib/version.js +22 -19
- package/npm-shrinkwrap.json +176 -43
- package/package.json +16 -16
- package/test/api/cloud-executable.test.js +3 -3
- package/test/api/hotswap/{lambda-hotswap-deployments.test.d.ts → code-build-projects-hotswap-deployments.test.d.ts} +0 -0
- package/test/api/hotswap/code-build-projects-hotswap-deployments.test.js +576 -0
- package/test/api/hotswap/hotswap-deployments.test.js +4 -2
- package/test/api/hotswap/hotswap-test-setup.d.ts +4 -1
- package/test/api/hotswap/hotswap-test-setup.js +13 -4
- package/test/api/hotswap/lambda-functions-hotswap-deployments.test.d.ts +1 -0
- package/test/api/hotswap/lambda-functions-hotswap-deployments.test.js +502 -0
- package/test/api/hotswap/lambda-versions-aliases-hotswap-deployments.test.d.ts +1 -0
- package/test/api/hotswap/lambda-versions-aliases-hotswap-deployments.test.js +197 -0
- package/test/api/hotswap/s3-bucket-hotswap-deployments.test.d.ts +1 -0
- package/test/api/hotswap/s3-bucket-hotswap-deployments.test.js +678 -0
- package/test/api/hotswap/state-machine-hotswap-deployments.test.js +12 -11
- package/test/cdk-toolkit.test.js +11 -4
- package/test/context-providers/generic.test.js +40 -7
- package/test/init.test.js +5 -4
- package/test/integ/cli/app/app.js +17 -2
- package/test/integ/cli/cli.integtest.js +13 -1
- package/test/integ/helpers/cdk.js +2 -1
- package/test/util/mock-sdk.d.ts +2 -0
- package/test/util/mock-sdk.js +5 -1
- package/test/version.test.js +45 -3
- package/test/api/hotswap/lambda-hotswap-deployments.test.js +0 -418
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const s3_bucket_deployments_1 = require("../../../lib/api/hotswap/s3-bucket-deployments");
|
|
4
|
+
const setup = require("./hotswap-test-setup");
|
|
5
|
+
let mockLambdaInvoke;
|
|
6
|
+
let hotswapMockSdkProvider;
|
|
7
|
+
const payloadWithoutCustomResProps = {
|
|
8
|
+
RequestType: 'Update',
|
|
9
|
+
ResponseURL: s3_bucket_deployments_1.REQUIRED_BY_CFN,
|
|
10
|
+
PhysicalResourceId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
|
|
11
|
+
StackId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
|
|
12
|
+
RequestId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
|
|
13
|
+
LogicalResourceId: s3_bucket_deployments_1.REQUIRED_BY_CFN,
|
|
14
|
+
};
|
|
15
|
+
beforeEach(() => {
|
|
16
|
+
hotswapMockSdkProvider = setup.setupHotswapTests();
|
|
17
|
+
mockLambdaInvoke = jest.fn();
|
|
18
|
+
hotswapMockSdkProvider.setInvokeLambdaMock(mockLambdaInvoke);
|
|
19
|
+
});
|
|
20
|
+
test('calls the lambdaInvoke() API when it receives only an asset difference in an S3 bucket deployment and evaluates CFN expressions in S3 Deployment Properties', async () => {
|
|
21
|
+
// GIVEN
|
|
22
|
+
setup.setCurrentCfnStackTemplate({
|
|
23
|
+
Resources: {
|
|
24
|
+
S3Deployment: {
|
|
25
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
26
|
+
Properties: {
|
|
27
|
+
ServiceToken: 'a-lambda-arn',
|
|
28
|
+
SourceBucketNames: ['src-bucket'],
|
|
29
|
+
SourceObjectKeys: ['src-key-old'],
|
|
30
|
+
DestinationBucketName: 'dest-bucket',
|
|
31
|
+
DestinationBucketKeyPrefix: 'my-key/some-old-prefix',
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
37
|
+
template: {
|
|
38
|
+
Resources: {
|
|
39
|
+
S3Deployment: {
|
|
40
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
41
|
+
Properties: {
|
|
42
|
+
ServiceToken: 'a-lambda-arn',
|
|
43
|
+
SourceBucketNames: ['src-bucket'],
|
|
44
|
+
SourceObjectKeys: {
|
|
45
|
+
'Fn::Split': [
|
|
46
|
+
'-',
|
|
47
|
+
'key1-key2-key3',
|
|
48
|
+
],
|
|
49
|
+
},
|
|
50
|
+
DestinationBucketName: 'dest-bucket',
|
|
51
|
+
DestinationBucketKeyPrefix: 'my-key/some-new-prefix',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
// WHEN
|
|
58
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
59
|
+
// THEN
|
|
60
|
+
expect(deployStackResult).not.toBeUndefined();
|
|
61
|
+
expect(mockLambdaInvoke).toHaveBeenCalledWith({
|
|
62
|
+
FunctionName: 'a-lambda-arn',
|
|
63
|
+
Payload: JSON.stringify({
|
|
64
|
+
...payloadWithoutCustomResProps,
|
|
65
|
+
ResourceProperties: {
|
|
66
|
+
SourceBucketNames: ['src-bucket'],
|
|
67
|
+
SourceObjectKeys: ['key1', 'key2', 'key3'],
|
|
68
|
+
DestinationBucketName: 'dest-bucket',
|
|
69
|
+
DestinationBucketKeyPrefix: 'my-key/some-new-prefix',
|
|
70
|
+
},
|
|
71
|
+
}),
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
test('does not call the invoke() API when a resource with type that is not Custom::CDKBucketDeployment but has the same properties is changed', async () => {
|
|
75
|
+
// GIVEN
|
|
76
|
+
setup.setCurrentCfnStackTemplate({
|
|
77
|
+
Resources: {
|
|
78
|
+
S3Deployment: {
|
|
79
|
+
Type: 'Custom::NotCDKBucketDeployment',
|
|
80
|
+
Properties: {
|
|
81
|
+
SourceObjectKeys: ['src-key-old'],
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
});
|
|
86
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
87
|
+
template: {
|
|
88
|
+
Resources: {
|
|
89
|
+
S3Deployment: {
|
|
90
|
+
Type: 'Custom::NotCDKBucketDeployment',
|
|
91
|
+
Properties: {
|
|
92
|
+
SourceObjectKeys: ['src-key-new'],
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
});
|
|
98
|
+
// WHEN
|
|
99
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
100
|
+
// THEN
|
|
101
|
+
expect(deployStackResult).toBeUndefined();
|
|
102
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
103
|
+
});
|
|
104
|
+
test('does not call the invokeLambda() api if the updated Policy has no Roles', async () => {
|
|
105
|
+
// GIVEN
|
|
106
|
+
setup.setCurrentCfnStackTemplate({
|
|
107
|
+
Parameters: {
|
|
108
|
+
WebsiteBucketParamOld: { Type: 'String' },
|
|
109
|
+
WebsiteBucketParamNew: { Type: 'String' },
|
|
110
|
+
},
|
|
111
|
+
Resources: {
|
|
112
|
+
S3Deployment: {
|
|
113
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
114
|
+
Properties: {
|
|
115
|
+
ServiceToken: 'a-lambda-arn',
|
|
116
|
+
SourceObjectKeys: ['src-key-old'],
|
|
117
|
+
},
|
|
118
|
+
},
|
|
119
|
+
Policy: {
|
|
120
|
+
Type: 'AWS::IAM::Policy',
|
|
121
|
+
Properties: {
|
|
122
|
+
PolicyName: 'my-policy',
|
|
123
|
+
PolicyDocument: {
|
|
124
|
+
Statement: [
|
|
125
|
+
{
|
|
126
|
+
Action: ['s3:GetObject*'],
|
|
127
|
+
Effect: 'Allow',
|
|
128
|
+
Resource: {
|
|
129
|
+
Ref: 'WebsiteBucketParamOld',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
],
|
|
133
|
+
},
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
139
|
+
template: {
|
|
140
|
+
Parameters: {
|
|
141
|
+
WebsiteBucketParamOld: { Type: 'String' },
|
|
142
|
+
WebsiteBucketParamNew: { Type: 'String' },
|
|
143
|
+
},
|
|
144
|
+
Resources: {
|
|
145
|
+
S3Deployment: {
|
|
146
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
147
|
+
Properties: {
|
|
148
|
+
ServiceToken: 'a-lambda-arn',
|
|
149
|
+
SourceObjectKeys: ['src-key-new'],
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
Policy: {
|
|
153
|
+
Type: 'AWS::IAM::Policy',
|
|
154
|
+
Properties: {
|
|
155
|
+
PolicyName: 'my-policy',
|
|
156
|
+
PolicyDocument: {
|
|
157
|
+
Statement: [
|
|
158
|
+
{
|
|
159
|
+
Action: ['s3:GetObject*'],
|
|
160
|
+
Effect: 'Allow',
|
|
161
|
+
Resource: {
|
|
162
|
+
Ref: 'WebsiteBucketParamNew',
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
},
|
|
167
|
+
},
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
});
|
|
172
|
+
// WHEN
|
|
173
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
174
|
+
// THEN
|
|
175
|
+
expect(deployStackResult).toBeUndefined();
|
|
176
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
177
|
+
});
|
|
178
|
+
test('throws an error when the serviceToken fails evaluation in the template', async () => {
|
|
179
|
+
// GIVEN
|
|
180
|
+
setup.setCurrentCfnStackTemplate({
|
|
181
|
+
Resources: {
|
|
182
|
+
S3Deployment: {
|
|
183
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
184
|
+
Properties: {
|
|
185
|
+
ServiceToken: {
|
|
186
|
+
Ref: 'BadLamba',
|
|
187
|
+
},
|
|
188
|
+
SourceBucketNames: ['src-bucket'],
|
|
189
|
+
SourceObjectKeys: ['src-key-old'],
|
|
190
|
+
DestinationBucketName: 'dest-bucket',
|
|
191
|
+
},
|
|
192
|
+
},
|
|
193
|
+
},
|
|
194
|
+
});
|
|
195
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
196
|
+
template: {
|
|
197
|
+
Resources: {
|
|
198
|
+
S3Deployment: {
|
|
199
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
200
|
+
Properties: {
|
|
201
|
+
ServiceToken: {
|
|
202
|
+
Ref: 'BadLamba',
|
|
203
|
+
},
|
|
204
|
+
SourceBucketNames: ['src-bucket'],
|
|
205
|
+
SourceObjectKeys: ['src-key-new'],
|
|
206
|
+
DestinationBucketName: 'dest-bucket',
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
},
|
|
210
|
+
},
|
|
211
|
+
});
|
|
212
|
+
// WHEN
|
|
213
|
+
await expect(() => hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact)).rejects.toThrow(/Parameter or resource 'BadLamba' could not be found for evaluation/);
|
|
214
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
215
|
+
});
|
|
216
|
+
describe('old-style synthesis', () => {
|
|
217
|
+
const parameters = {
|
|
218
|
+
WebsiteBucketParamOld: { Type: 'String' },
|
|
219
|
+
WebsiteBucketParamNew: { Type: 'String' },
|
|
220
|
+
DifferentBucketParamNew: { Type: 'String' },
|
|
221
|
+
};
|
|
222
|
+
const serviceRole = {
|
|
223
|
+
Type: 'AWS::IAM::Role',
|
|
224
|
+
Properties: {
|
|
225
|
+
AssumeRolePolicyDocument: {
|
|
226
|
+
Statement: [
|
|
227
|
+
{
|
|
228
|
+
Action: 'sts:AssumeRole',
|
|
229
|
+
Effect: 'Allow',
|
|
230
|
+
Principal: {
|
|
231
|
+
Service: 'lambda.amazonaws.com',
|
|
232
|
+
},
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
Version: '2012-10-17',
|
|
236
|
+
},
|
|
237
|
+
},
|
|
238
|
+
};
|
|
239
|
+
const policyOld = {
|
|
240
|
+
Type: 'AWS::IAM::Policy',
|
|
241
|
+
Properties: {
|
|
242
|
+
PolicyName: 'my-policy-old',
|
|
243
|
+
Roles: [
|
|
244
|
+
{ Ref: 'ServiceRole' },
|
|
245
|
+
],
|
|
246
|
+
PolicyDocument: {
|
|
247
|
+
Statement: [
|
|
248
|
+
{
|
|
249
|
+
Action: ['s3:GetObject*'],
|
|
250
|
+
Effect: 'Allow',
|
|
251
|
+
Resource: {
|
|
252
|
+
Ref: 'WebsiteBucketParamOld',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
],
|
|
256
|
+
},
|
|
257
|
+
},
|
|
258
|
+
};
|
|
259
|
+
const policyNew = {
|
|
260
|
+
Type: 'AWS::IAM::Policy',
|
|
261
|
+
Properties: {
|
|
262
|
+
PolicyName: 'my-policy-new',
|
|
263
|
+
Roles: [
|
|
264
|
+
{ Ref: 'ServiceRole' },
|
|
265
|
+
],
|
|
266
|
+
PolicyDocument: {
|
|
267
|
+
Statement: [
|
|
268
|
+
{
|
|
269
|
+
Action: ['s3:GetObject*'],
|
|
270
|
+
Effect: 'Allow',
|
|
271
|
+
Resource: {
|
|
272
|
+
Ref: 'WebsiteBucketParamNew',
|
|
273
|
+
},
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
const policy2Old = {
|
|
280
|
+
Type: 'AWS::IAM::Policy',
|
|
281
|
+
Properties: {
|
|
282
|
+
PolicyName: 'my-policy-old-2',
|
|
283
|
+
Roles: [
|
|
284
|
+
{ Ref: 'ServiceRole' },
|
|
285
|
+
],
|
|
286
|
+
PolicyDocument: {
|
|
287
|
+
Statement: [
|
|
288
|
+
{
|
|
289
|
+
Action: ['s3:GetObject*'],
|
|
290
|
+
Effect: 'Allow',
|
|
291
|
+
Resource: {
|
|
292
|
+
Ref: 'WebsiteBucketParamOld',
|
|
293
|
+
},
|
|
294
|
+
},
|
|
295
|
+
],
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
const policy2New = {
|
|
300
|
+
Type: 'AWS::IAM::Policy',
|
|
301
|
+
Properties: {
|
|
302
|
+
PolicyName: 'my-policy-new-2',
|
|
303
|
+
Roles: [
|
|
304
|
+
{ Ref: 'ServiceRole2' },
|
|
305
|
+
],
|
|
306
|
+
PolicyDocument: {
|
|
307
|
+
Statement: [
|
|
308
|
+
{
|
|
309
|
+
Action: ['s3:GetObject*'],
|
|
310
|
+
Effect: 'Allow',
|
|
311
|
+
Resource: {
|
|
312
|
+
Ref: 'DifferentBucketParamOld',
|
|
313
|
+
},
|
|
314
|
+
},
|
|
315
|
+
],
|
|
316
|
+
},
|
|
317
|
+
},
|
|
318
|
+
};
|
|
319
|
+
const deploymentLambda = {
|
|
320
|
+
Type: 'AWS::Lambda::Function',
|
|
321
|
+
Role: {
|
|
322
|
+
'Fn::GetAtt': [
|
|
323
|
+
'ServiceRole',
|
|
324
|
+
'Arn',
|
|
325
|
+
],
|
|
326
|
+
},
|
|
327
|
+
};
|
|
328
|
+
const s3DeploymentOld = {
|
|
329
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
330
|
+
Properties: {
|
|
331
|
+
ServiceToken: {
|
|
332
|
+
'Fn::GetAtt': [
|
|
333
|
+
'S3DeploymentLambda',
|
|
334
|
+
'Arn',
|
|
335
|
+
],
|
|
336
|
+
},
|
|
337
|
+
SourceBucketNames: ['src-bucket-old'],
|
|
338
|
+
SourceObjectKeys: ['src-key-old'],
|
|
339
|
+
DestinationBucketName: 'WebsiteBucketOld',
|
|
340
|
+
},
|
|
341
|
+
};
|
|
342
|
+
const s3DeploymentNew = {
|
|
343
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
344
|
+
Properties: {
|
|
345
|
+
ServiceToken: {
|
|
346
|
+
'Fn::GetAtt': [
|
|
347
|
+
'S3DeploymentLambda',
|
|
348
|
+
'Arn',
|
|
349
|
+
],
|
|
350
|
+
},
|
|
351
|
+
SourceBucketNames: ['src-bucket-new'],
|
|
352
|
+
SourceObjectKeys: ['src-key-new'],
|
|
353
|
+
DestinationBucketName: 'WebsiteBucketNew',
|
|
354
|
+
},
|
|
355
|
+
};
|
|
356
|
+
beforeEach(() => {
|
|
357
|
+
setup.pushStackResourceSummaries(setup.stackSummaryOf('S3DeploymentLambda', 'AWS::Lambda::Function', 'my-deployment-lambda'), setup.stackSummaryOf('ServiceRole', 'AWS::IAM::Role', 'my-service-role'));
|
|
358
|
+
});
|
|
359
|
+
test('calls the lambdaInvoke() API when it receives an asset difference in an S3 bucket deployment and an IAM Policy difference using old-style synthesis', async () => {
|
|
360
|
+
// GIVEN
|
|
361
|
+
setup.setCurrentCfnStackTemplate({
|
|
362
|
+
Resources: {
|
|
363
|
+
Parameters: parameters,
|
|
364
|
+
ServiceRole: serviceRole,
|
|
365
|
+
Policy: policyOld,
|
|
366
|
+
S3DeploymentLambda: deploymentLambda,
|
|
367
|
+
S3Deployment: s3DeploymentOld,
|
|
368
|
+
},
|
|
369
|
+
});
|
|
370
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
371
|
+
template: {
|
|
372
|
+
Resources: {
|
|
373
|
+
Parameters: parameters,
|
|
374
|
+
ServiceRole: serviceRole,
|
|
375
|
+
Policy: policyNew,
|
|
376
|
+
S3DeploymentLambda: deploymentLambda,
|
|
377
|
+
S3Deployment: s3DeploymentNew,
|
|
378
|
+
},
|
|
379
|
+
},
|
|
380
|
+
});
|
|
381
|
+
// WHEN
|
|
382
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact, { WebsiteBucketParamOld: 'WebsiteBucketOld', WebsiteBucketParamNew: 'WebsiteBucketNew' });
|
|
383
|
+
// THEN
|
|
384
|
+
expect(deployStackResult).not.toBeUndefined();
|
|
385
|
+
expect(mockLambdaInvoke).toHaveBeenCalledWith({
|
|
386
|
+
FunctionName: 'arn:aws:lambda:here:123456789012:function:my-deployment-lambda',
|
|
387
|
+
Payload: JSON.stringify({
|
|
388
|
+
...payloadWithoutCustomResProps,
|
|
389
|
+
ResourceProperties: {
|
|
390
|
+
SourceBucketNames: ['src-bucket-new'],
|
|
391
|
+
SourceObjectKeys: ['src-key-new'],
|
|
392
|
+
DestinationBucketName: 'WebsiteBucketNew',
|
|
393
|
+
},
|
|
394
|
+
}),
|
|
395
|
+
});
|
|
396
|
+
});
|
|
397
|
+
test('does not call the lambdaInvoke() API when the difference in the S3 deployment is referred to in one IAM policy change but not another', async () => {
|
|
398
|
+
// GIVEN
|
|
399
|
+
setup.setCurrentCfnStackTemplate({
|
|
400
|
+
Resources: {
|
|
401
|
+
ServiceRole: serviceRole,
|
|
402
|
+
Policy1: policyOld,
|
|
403
|
+
Policy2: policy2Old,
|
|
404
|
+
S3DeploymentLambda: deploymentLambda,
|
|
405
|
+
S3Deployment: s3DeploymentOld,
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
409
|
+
template: {
|
|
410
|
+
Resources: {
|
|
411
|
+
ServiceRole: serviceRole,
|
|
412
|
+
Policy1: policyNew,
|
|
413
|
+
Policy2: {
|
|
414
|
+
Properties: {
|
|
415
|
+
Roles: [
|
|
416
|
+
{ Ref: 'ServiceRole' },
|
|
417
|
+
'different-role',
|
|
418
|
+
],
|
|
419
|
+
PolicyDocument: {
|
|
420
|
+
Statement: [
|
|
421
|
+
{
|
|
422
|
+
Action: ['s3:GetObject*'],
|
|
423
|
+
Effect: 'Allow',
|
|
424
|
+
Resource: {
|
|
425
|
+
'Fn::GetAtt': [
|
|
426
|
+
'DifferentBucketNew',
|
|
427
|
+
'Arn',
|
|
428
|
+
],
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
},
|
|
433
|
+
},
|
|
434
|
+
},
|
|
435
|
+
S3DeploymentLambda: deploymentLambda,
|
|
436
|
+
S3Deployment: s3DeploymentNew,
|
|
437
|
+
},
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
// WHEN
|
|
441
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
442
|
+
// THEN
|
|
443
|
+
expect(deployStackResult).toBeUndefined();
|
|
444
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
445
|
+
});
|
|
446
|
+
test('does not call the lambdaInvoke() API when the lambda that references the role is referred to by something other than an S3 deployment', async () => {
|
|
447
|
+
// GIVEN
|
|
448
|
+
setup.setCurrentCfnStackTemplate({
|
|
449
|
+
Resources: {
|
|
450
|
+
ServiceRole: serviceRole,
|
|
451
|
+
Policy: policyOld,
|
|
452
|
+
S3DeploymentLambda: deploymentLambda,
|
|
453
|
+
S3Deployment: s3DeploymentOld,
|
|
454
|
+
Endpoint: {
|
|
455
|
+
Type: 'AWS::Lambda::Permission',
|
|
456
|
+
Properties: {
|
|
457
|
+
Action: 'lambda:InvokeFunction',
|
|
458
|
+
FunctionName: {
|
|
459
|
+
'Fn::GetAtt': [
|
|
460
|
+
'S3DeploymentLambda',
|
|
461
|
+
'Arn',
|
|
462
|
+
],
|
|
463
|
+
},
|
|
464
|
+
Principal: 'apigateway.amazonaws.com',
|
|
465
|
+
},
|
|
466
|
+
},
|
|
467
|
+
},
|
|
468
|
+
});
|
|
469
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
470
|
+
template: {
|
|
471
|
+
Resources: {
|
|
472
|
+
ServiceRole: serviceRole,
|
|
473
|
+
Policy: policyNew,
|
|
474
|
+
S3DeploymentLambda: deploymentLambda,
|
|
475
|
+
S3Deployment: s3DeploymentNew,
|
|
476
|
+
Endpoint: {
|
|
477
|
+
Type: 'AWS::Lambda::Permission',
|
|
478
|
+
Properties: {
|
|
479
|
+
Action: 'lambda:InvokeFunction',
|
|
480
|
+
FunctionName: {
|
|
481
|
+
'Fn::GetAtt': [
|
|
482
|
+
'S3DeploymentLambda',
|
|
483
|
+
'Arn',
|
|
484
|
+
],
|
|
485
|
+
},
|
|
486
|
+
Principal: 'apigateway.amazonaws.com',
|
|
487
|
+
},
|
|
488
|
+
},
|
|
489
|
+
},
|
|
490
|
+
},
|
|
491
|
+
});
|
|
492
|
+
// WHEN
|
|
493
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
494
|
+
// THEN
|
|
495
|
+
expect(deployStackResult).toBeUndefined();
|
|
496
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
497
|
+
});
|
|
498
|
+
test('calls the lambdaInvoke() API when it receives an asset difference in two S3 bucket deployments and IAM Policy differences using old-style synthesis', async () => {
|
|
499
|
+
// GIVEN
|
|
500
|
+
const s3Deployment2Old = {
|
|
501
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
502
|
+
Properties: {
|
|
503
|
+
ServiceToken: {
|
|
504
|
+
'Fn::GetAtt': [
|
|
505
|
+
'S3DeploymentLambda2',
|
|
506
|
+
'Arn',
|
|
507
|
+
],
|
|
508
|
+
},
|
|
509
|
+
SourceBucketNames: ['src-bucket-old'],
|
|
510
|
+
SourceObjectKeys: ['src-key-old'],
|
|
511
|
+
DestinationBucketName: 'DifferentBucketOld',
|
|
512
|
+
},
|
|
513
|
+
};
|
|
514
|
+
const s3Deployment2New = {
|
|
515
|
+
Type: 'Custom::CDKBucketDeployment',
|
|
516
|
+
Properties: {
|
|
517
|
+
ServiceToken: {
|
|
518
|
+
'Fn::GetAtt': [
|
|
519
|
+
'S3DeploymentLambda2',
|
|
520
|
+
'Arn',
|
|
521
|
+
],
|
|
522
|
+
},
|
|
523
|
+
SourceBucketNames: ['src-bucket-new'],
|
|
524
|
+
SourceObjectKeys: ['src-key-new'],
|
|
525
|
+
DestinationBucketName: 'DifferentBucketNew',
|
|
526
|
+
},
|
|
527
|
+
};
|
|
528
|
+
setup.setCurrentCfnStackTemplate({
|
|
529
|
+
Resources: {
|
|
530
|
+
ServiceRole: serviceRole,
|
|
531
|
+
ServiceRole2: serviceRole,
|
|
532
|
+
Policy1: policyOld,
|
|
533
|
+
Policy2: policy2Old,
|
|
534
|
+
S3DeploymentLambda: deploymentLambda,
|
|
535
|
+
S3DeploymentLambda2: deploymentLambda,
|
|
536
|
+
S3Deployment: s3DeploymentOld,
|
|
537
|
+
S3Deployment2: s3Deployment2Old,
|
|
538
|
+
},
|
|
539
|
+
});
|
|
540
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
541
|
+
template: {
|
|
542
|
+
Resources: {
|
|
543
|
+
Parameters: parameters,
|
|
544
|
+
ServiceRole: serviceRole,
|
|
545
|
+
ServiceRole2: serviceRole,
|
|
546
|
+
Policy1: policyNew,
|
|
547
|
+
Policy2: policy2New,
|
|
548
|
+
S3DeploymentLambda: deploymentLambda,
|
|
549
|
+
S3DeploymentLambda2: deploymentLambda,
|
|
550
|
+
S3Deployment: s3DeploymentNew,
|
|
551
|
+
S3Deployment2: s3Deployment2New,
|
|
552
|
+
},
|
|
553
|
+
},
|
|
554
|
+
});
|
|
555
|
+
// WHEN
|
|
556
|
+
setup.pushStackResourceSummaries(setup.stackSummaryOf('S3DeploymentLambda2', 'AWS::Lambda::Function', 'my-deployment-lambda-2'), setup.stackSummaryOf('ServiceRole2', 'AWS::IAM::Role', 'my-service-role-2'));
|
|
557
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact, {
|
|
558
|
+
WebsiteBucketParamOld: 'WebsiteBucketOld',
|
|
559
|
+
WebsiteBucketParamNew: 'WebsiteBucketNew',
|
|
560
|
+
DifferentBucketParamNew: 'WebsiteBucketNew',
|
|
561
|
+
});
|
|
562
|
+
// THEN
|
|
563
|
+
expect(deployStackResult).not.toBeUndefined();
|
|
564
|
+
expect(mockLambdaInvoke).toHaveBeenCalledWith({
|
|
565
|
+
FunctionName: 'arn:aws:lambda:here:123456789012:function:my-deployment-lambda',
|
|
566
|
+
Payload: JSON.stringify({
|
|
567
|
+
...payloadWithoutCustomResProps,
|
|
568
|
+
ResourceProperties: {
|
|
569
|
+
SourceBucketNames: ['src-bucket-new'],
|
|
570
|
+
SourceObjectKeys: ['src-key-new'],
|
|
571
|
+
DestinationBucketName: 'WebsiteBucketNew',
|
|
572
|
+
},
|
|
573
|
+
}),
|
|
574
|
+
});
|
|
575
|
+
expect(mockLambdaInvoke).toHaveBeenCalledWith({
|
|
576
|
+
FunctionName: 'arn:aws:lambda:here:123456789012:function:my-deployment-lambda-2',
|
|
577
|
+
Payload: JSON.stringify({
|
|
578
|
+
...payloadWithoutCustomResProps,
|
|
579
|
+
ResourceProperties: {
|
|
580
|
+
SourceBucketNames: ['src-bucket-new'],
|
|
581
|
+
SourceObjectKeys: ['src-key-new'],
|
|
582
|
+
DestinationBucketName: 'DifferentBucketNew',
|
|
583
|
+
},
|
|
584
|
+
}),
|
|
585
|
+
});
|
|
586
|
+
});
|
|
587
|
+
test('does not call the lambdaInvoke() API when it receives an asset difference in an S3 bucket deployment that references two different policies', async () => {
|
|
588
|
+
// GIVEN
|
|
589
|
+
setup.setCurrentCfnStackTemplate({
|
|
590
|
+
Resources: {
|
|
591
|
+
ServiceRole: serviceRole,
|
|
592
|
+
Policy1: policyOld,
|
|
593
|
+
Policy2: policy2Old,
|
|
594
|
+
S3DeploymentLambda: deploymentLambda,
|
|
595
|
+
S3Deployment: s3DeploymentOld,
|
|
596
|
+
},
|
|
597
|
+
});
|
|
598
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
599
|
+
template: {
|
|
600
|
+
Resources: {
|
|
601
|
+
ServiceRole: serviceRole,
|
|
602
|
+
Policy1: policyNew,
|
|
603
|
+
Policy2: {
|
|
604
|
+
Properties: {
|
|
605
|
+
Roles: [
|
|
606
|
+
{ Ref: 'ServiceRole' },
|
|
607
|
+
],
|
|
608
|
+
PolicyDocument: {
|
|
609
|
+
Statement: [
|
|
610
|
+
{
|
|
611
|
+
Action: ['s3:GetObject*'],
|
|
612
|
+
Effect: 'Allow',
|
|
613
|
+
Resource: {
|
|
614
|
+
'Fn::GetAtt': [
|
|
615
|
+
'DifferentBucketNew',
|
|
616
|
+
'Arn',
|
|
617
|
+
],
|
|
618
|
+
},
|
|
619
|
+
},
|
|
620
|
+
],
|
|
621
|
+
},
|
|
622
|
+
},
|
|
623
|
+
},
|
|
624
|
+
S3DeploymentLambda: deploymentLambda,
|
|
625
|
+
S3Deployment: s3DeploymentNew,
|
|
626
|
+
},
|
|
627
|
+
},
|
|
628
|
+
});
|
|
629
|
+
// WHEN
|
|
630
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
631
|
+
// THEN
|
|
632
|
+
expect(deployStackResult).toBeUndefined();
|
|
633
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
634
|
+
});
|
|
635
|
+
test('does not call the lambdaInvoke() API when a policy is referenced by a resource that is not an S3 deployment', async () => {
|
|
636
|
+
// GIVEN
|
|
637
|
+
setup.setCurrentCfnStackTemplate({
|
|
638
|
+
Resources: {
|
|
639
|
+
ServiceRole: serviceRole,
|
|
640
|
+
Policy1: policyOld,
|
|
641
|
+
S3DeploymentLambda: deploymentLambda,
|
|
642
|
+
S3Deployment: s3DeploymentOld,
|
|
643
|
+
NotADeployment: {
|
|
644
|
+
Type: 'AWS::Not::S3Deployment',
|
|
645
|
+
Properties: {
|
|
646
|
+
Prop: {
|
|
647
|
+
Ref: 'ServiceRole',
|
|
648
|
+
},
|
|
649
|
+
},
|
|
650
|
+
},
|
|
651
|
+
},
|
|
652
|
+
});
|
|
653
|
+
const cdkStackArtifact = setup.cdkStackArtifactOf({
|
|
654
|
+
template: {
|
|
655
|
+
Resources: {
|
|
656
|
+
ServiceRole: serviceRole,
|
|
657
|
+
Policy1: policyNew,
|
|
658
|
+
S3DeploymentLambda: deploymentLambda,
|
|
659
|
+
S3Deployment: s3DeploymentNew,
|
|
660
|
+
NotADeployment: {
|
|
661
|
+
Type: 'AWS::Not::S3Deployment',
|
|
662
|
+
Properties: {
|
|
663
|
+
Prop: {
|
|
664
|
+
Ref: 'ServiceRole',
|
|
665
|
+
},
|
|
666
|
+
},
|
|
667
|
+
},
|
|
668
|
+
},
|
|
669
|
+
},
|
|
670
|
+
});
|
|
671
|
+
// WHEN
|
|
672
|
+
const deployStackResult = await hotswapMockSdkProvider.tryHotswapDeployment(cdkStackArtifact);
|
|
673
|
+
// THEN
|
|
674
|
+
expect(deployStackResult).toBeUndefined();
|
|
675
|
+
expect(mockLambdaInvoke).not.toHaveBeenCalled();
|
|
676
|
+
});
|
|
677
|
+
});
|
|
678
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMtYnVja2V0LWhvdHN3YXAtZGVwbG95bWVudHMudGVzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInMzLWJ1Y2tldC1ob3Rzd2FwLWRlcGxveW1lbnRzLnRlc3QudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFDQSwwRkFBaUY7QUFDakYsOENBQThDO0FBRTlDLElBQUksZ0JBQTZGLENBQUM7QUFDbEcsSUFBSSxzQkFBb0QsQ0FBQztBQUV6RCxNQUFNLDRCQUE0QixHQUFHO0lBQ25DLFdBQVcsRUFBRSxRQUFRO0lBQ3JCLFdBQVcsRUFBRSx1Q0FBZTtJQUM1QixrQkFBa0IsRUFBRSx1Q0FBZTtJQUNuQyxPQUFPLEVBQUUsdUNBQWU7SUFDeEIsU0FBUyxFQUFFLHVDQUFlO0lBQzFCLGlCQUFpQixFQUFFLHVDQUFlO0NBQ25DLENBQUM7QUFFRixVQUFVLENBQUMsR0FBRyxFQUFFO0lBQ2Qsc0JBQXNCLEdBQUcsS0FBSyxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDbkQsZ0JBQWdCLEdBQUcsSUFBSSxDQUFDLEVBQUUsRUFBRSxDQUFDO0lBQzdCLHNCQUFzQixDQUFDLG1CQUFtQixDQUFDLGdCQUFnQixDQUFDLENBQUM7QUFDL0QsQ0FBQyxDQUFDLENBQUM7QUFFSCxJQUFJLENBQUMsNkpBQTZKLEVBQUUsS0FBSyxJQUFJLEVBQUU7SUFDN0ssUUFBUTtJQUNSLEtBQUssQ0FBQywwQkFBMEIsQ0FBQztRQUMvQixTQUFTLEVBQUU7WUFDVCxZQUFZLEVBQUU7Z0JBQ1osSUFBSSxFQUFFLDZCQUE2QjtnQkFDbkMsVUFBVSxFQUFFO29CQUNWLFlBQVksRUFBRSxjQUFjO29CQUM1QixpQkFBaUIsRUFBRSxDQUFDLFlBQVksQ0FBQztvQkFDakMsZ0JBQWdCLEVBQUUsQ0FBQyxhQUFhLENBQUM7b0JBQ2pDLHFCQUFxQixFQUFFLGFBQWE7b0JBQ3BDLDBCQUEwQixFQUFFLHdCQUF3QjtpQkFDckQ7YUFDRjtTQUNGO0tBQ0YsQ0FBQyxDQUFDO0lBQ0gs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QUFnQixDQUFDLENBQUM7UUFFOUYsT0FBTztRQUNQLE1BQU0sQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQzFDLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO0lBQ2xELENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBMYW1iZGEgfSBmcm9tICdhd3Mtc2RrJztcbmltcG9ydCB7IFJFUVVJUkVEX0JZX0NGTiB9IGZyb20gJy4uLy4uLy4uL2xpYi9hcGkvaG90c3dhcC9zMy1idWNrZXQtZGVwbG95bWVudHMnO1xuaW1wb3J0ICogYXMgc2V0dXAgZnJvbSAnLi9ob3Rzd2FwLXRlc3Qtc2V0dXAnO1xuXG5sZXQgbW9ja0xhbWJkYUludm9rZTogKHBhcmFtczogTGFtYmRhLlR5cGVzLkludm9jYXRpb25SZXF1ZXN0KSA9PiBMYW1iZGEuVHlwZXMuSW52b2NhdGlvblJlc3BvbnNlO1xubGV0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXI6IHNldHVwLkhvdHN3YXBNb2NrU2RrUHJvdmlkZXI7XG5cbmNvbnN0IHBheWxvYWRXaXRob3V0Q3VzdG9tUmVzUHJvcHMgPSB7XG4gIFJlcXVlc3RUeXBlOiAnVXBkYXRlJyxcbiAgUmVzcG9uc2VVUkw6IFJFUVVJUkVEX0JZX0NGTixcbiAgUGh5c2ljYWxSZXNvdXJjZUlkOiBSRVFVSVJFRF9CWV9DRk4sXG4gIFN0YWNrSWQ6IFJFUVVJUkVEX0JZX0NGTixcbiAgUmVxdWVzdElkOiBSRVFVSVJFRF9CWV9DRk4sXG4gIExvZ2ljYWxSZXNvdXJjZUlkOiBSRVFVSVJFRF9CWV9DRk4sXG59O1xuXG5iZWZvcmVFYWNoKCgpID0+IHtcbiAgaG90c3dhcE1vY2tTZGtQcm92aWRlciA9IHNldHVwLnNldHVwSG90c3dhcFRlc3RzKCk7XG4gIG1vY2tMYW1iZGFJbnZva2UgPSBqZXN0LmZuKCk7XG4gIGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIuc2V0SW52b2tlTGFtYmRhTW9jayhtb2NrTGFtYmRhSW52b2tlKTtcbn0pO1xuXG50ZXN0KCdjYWxscyB0aGUgbGFtYmRhSW52b2tlKCkgQVBJIHdoZW4gaXQgcmVjZWl2ZXMgb25seSBhbiBhc3NldCBkaWZmZXJlbmNlIGluIGFuIFMzIGJ1Y2tldCBkZXBsb3ltZW50IGFuZCBldmFsdWF0ZXMgQ0ZOIGV4cHJlc3Npb25zIGluIFMzIERlcGxveW1lbnQgUHJvcGVydGllcycsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgc2V0dXAuc2V0Q3VycmVudENmblN0YWNrVGVtcGxhdGUoe1xuICAgIFJlc291cmNlczoge1xuICAgICAgUzNEZXBsb3ltZW50OiB7XG4gICAgICAgIFR5cGU6ICdDdXN0b206OkNES0J1Y2tldERlcGxveW1lbnQnLFxuICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgU2VydmljZVRva2VuOiAnYS1sYW1iZGEtYXJuJyxcbiAgICAgICAgICBTb3VyY2VCdWNrZXROYW1lczogWydzcmMtYnVja2V0J10sXG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW9sZCddLFxuICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ2Rlc3QtYnVja2V0JyxcbiAgICAgICAgICBEZXN0aW5hdGlvbkJ1Y2tldEtleVByZWZpeDogJ215LWtleS9zb21lLW9sZC1wcmVmaXgnLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KTtcbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHNldHVwLmNka1N0YWNrQXJ0aWZhY3RPZih7XG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBTM0RlcGxveW1lbnQ6IHtcbiAgICAgICAgICBUeXBlOiAnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50JyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBTZXJ2aWNlVG9rZW46ICdhLWxhbWJkYS1hcm4nLFxuICAgICAgICAgICAgU291cmNlQnVja2V0TmFtZXM6IFsnc3JjLWJ1Y2tldCddLFxuICAgICAgICAgICAgU291cmNlT2JqZWN0S2V5czoge1xuICAgICAgICAgICAgICAnRm46OlNwbGl0JzogW1xuICAgICAgICAgICAgICAgICctJyxcbiAgICAgICAgICAgICAgICAna2V5MS1rZXkyLWtleTMnLFxuICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ2Rlc3QtYnVja2V0JyxcbiAgICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0S2V5UHJlZml4OiAnbXkta2V5L3NvbWUtbmV3LXByZWZpeCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLm5vdC50b0JlVW5kZWZpbmVkKCk7XG5cbiAgZXhwZWN0KG1vY2tMYW1iZGFJbnZva2UpLnRvSGF2ZUJlZW5DYWxsZWRXaXRoKHtcbiAgICBGdW5jdGlvbk5hbWU6ICdhLWxhbWJkYS1hcm4nLFxuICAgIFBheWxvYWQ6IEpTT04uc3RyaW5naWZ5KHtcbiAgICAgIC4uLnBheWxvYWRXaXRob3V0Q3VzdG9tUmVzUHJvcHMsXG4gICAgICBSZXNvdXJjZVByb3BlcnRpZXM6IHtcbiAgICAgICAgU291cmNlQnVja2V0TmFtZXM6IFsnc3JjLWJ1Y2tldCddLFxuICAgICAgICBTb3VyY2VPYmplY3RLZXlzOiBbJ2tleTEnLCAna2V5MicsICdrZXkzJ10sXG4gICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ2Rlc3QtYnVja2V0JyxcbiAgICAgICAgRGVzdGluYXRpb25CdWNrZXRLZXlQcmVmaXg6ICdteS1rZXkvc29tZS1uZXctcHJlZml4JyxcbiAgICAgIH0sXG4gICAgfSksXG4gIH0pO1xufSk7XG5cbnRlc3QoJ2RvZXMgbm90IGNhbGwgdGhlIGludm9rZSgpIEFQSSB3aGVuIGEgcmVzb3VyY2Ugd2l0aCB0eXBlIHRoYXQgaXMgbm90IEN1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCBidXQgaGFzIHRoZSBzYW1lIHByb3BlcnRpZXMgaXMgY2hhbmdlZCcsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgc2V0dXAuc2V0Q3VycmVudENmblN0YWNrVGVtcGxhdGUoe1xuICAgIFJlc291cmNlczoge1xuICAgICAgUzNEZXBsb3ltZW50OiB7XG4gICAgICAgIFR5cGU6ICdDdXN0b206Ok5vdENES0J1Y2tldERlcGxveW1lbnQnLFxuICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW9sZCddLFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9LFxuICB9KTtcbiAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHNldHVwLmNka1N0YWNrQXJ0aWZhY3RPZih7XG4gICAgdGVtcGxhdGU6IHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBTM0RlcGxveW1lbnQ6IHtcbiAgICAgICAgICBUeXBlOiAnQ3VzdG9tOjpOb3RDREtCdWNrZXREZXBsb3ltZW50JyxcbiAgICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgICBTb3VyY2VPYmplY3RLZXlzOiBbJ3NyYy1rZXktbmV3J10sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tMYW1iZGFJbnZva2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG59KTtcblxudGVzdCgnZG9lcyBub3QgY2FsbCB0aGUgaW52b2tlTGFtYmRhKCkgYXBpIGlmIHRoZSB1cGRhdGVkIFBvbGljeSBoYXMgbm8gUm9sZXMnLCBhc3luYyAoKSA9PiB7XG4gIC8vIEdJVkVOXG4gIHNldHVwLnNldEN1cnJlbnRDZm5TdGFja1RlbXBsYXRlKHtcbiAgICBQYXJhbWV0ZXJzOiB7XG4gICAgICBXZWJzaXRlQnVja2V0UGFyYW1PbGQ6IHsgVHlwZTogJ1N0cmluZycgfSxcbiAgICAgIFdlYnNpdGVCdWNrZXRQYXJhbU5ldzogeyBUeXBlOiAnU3RyaW5nJyB9LFxuICAgIH0sXG4gICAgUmVzb3VyY2VzOiB7XG4gICAgICBTM0RlcGxveW1lbnQ6IHtcbiAgICAgICAgVHlwZTogJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsXG4gICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICBTZXJ2aWNlVG9rZW46ICdhLWxhbWJkYS1hcm4nLFxuICAgICAgICAgIFNvdXJjZU9iamVjdEtleXM6IFsnc3JjLWtleS1vbGQnXSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgICBQb2xpY3k6IHtcbiAgICAgICAgVHlwZTogJ0FXUzo6SUFNOjpQb2xpY3knLFxuICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgUG9saWN5TmFtZTogJ215LXBvbGljeScsXG4gICAgICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgICAgIFN0YXRlbWVudDogW1xuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgQWN0aW9uOiBbJ3MzOkdldE9iamVjdConXSxcbiAgICAgICAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgIFJlZjogJ1dlYnNpdGVCdWNrZXRQYXJhbU9sZCcsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG4gIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgIHRlbXBsYXRlOiB7XG4gICAgICBQYXJhbWV0ZXJzOiB7XG4gICAgICAgIFdlYnNpdGVCdWNrZXRQYXJhbU9sZDogeyBUeXBlOiAnU3RyaW5nJyB9LFxuICAgICAgICBXZWJzaXRlQnVja2V0UGFyYW1OZXc6IHsgVHlwZTogJ1N0cmluZycgfSxcbiAgICAgIH0sXG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgUzNEZXBsb3ltZW50OiB7XG4gICAgICAgICAgVHlwZTogJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgU2VydmljZVRva2VuOiAnYS1sYW1iZGEtYXJuJyxcbiAgICAgICAgICAgIFNvdXJjZU9iamVjdEtleXM6IFsnc3JjLWtleS1uZXcnXSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgICBQb2xpY3k6IHtcbiAgICAgICAgICBUeXBlOiAnQVdTOjpJQU06OlBvbGljeScsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgUG9saWN5TmFtZTogJ215LXBvbGljeScsXG4gICAgICAgICAgICBQb2xpY3lEb2N1bWVudDoge1xuICAgICAgICAgICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBBY3Rpb246IFsnczM6R2V0T2JqZWN0KiddLFxuICAgICAgICAgICAgICAgICAgRWZmZWN0OiAnQWxsb3cnLFxuICAgICAgICAgICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgUmVmOiAnV2Vic2l0ZUJ1Y2tldFBhcmFtTmV3JyxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gV0hFTlxuICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCk7XG5cbiAgLy8gVEhFTlxuICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgZXhwZWN0KG1vY2tMYW1iZGFJbnZva2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG59KTtcblxudGVzdCgndGhyb3dzIGFuIGVycm9yIHdoZW4gdGhlIHNlcnZpY2VUb2tlbiBmYWlscyBldmFsdWF0aW9uIGluIHRoZSB0ZW1wbGF0ZScsIGFzeW5jICgpID0+IHtcbiAgLy8gR0lWRU5cbiAgc2V0dXAuc2V0Q3VycmVudENmblN0YWNrVGVtcGxhdGUoe1xuICAgIFJlc291cmNlczoge1xuICAgICAgUzNEZXBsb3ltZW50OiB7XG4gICAgICAgIFR5cGU6ICdDdXN0b206OkNES0J1Y2tldERlcGxveW1lbnQnLFxuICAgICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgICAgU2VydmljZVRva2VuOiB7XG4gICAgICAgICAgICBSZWY6ICdCYWRMYW1iYScsXG4gICAgICAgICAgfSxcbiAgICAgICAgICBTb3VyY2VCdWNrZXROYW1lczogWydzcmMtYnVja2V0J10sXG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW9sZCddLFxuICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ2Rlc3QtYnVja2V0JyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG4gIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgIHRlbXBsYXRlOiB7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgUzNEZXBsb3ltZW50OiB7XG4gICAgICAgICAgVHlwZTogJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgU2VydmljZVRva2VuOiB7XG4gICAgICAgICAgICAgIFJlZjogJ0JhZExhbWJhJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBTb3VyY2VCdWNrZXROYW1lczogWydzcmMtYnVja2V0J10sXG4gICAgICAgICAgICBTb3VyY2VPYmplY3RLZXlzOiBbJ3NyYy1rZXktbmV3J10sXG4gICAgICAgICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6ICdkZXN0LWJ1Y2tldCcsXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfSk7XG5cbiAgLy8gV0hFTlxuICBhd2FpdCBleHBlY3QoKCkgPT5cbiAgICBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpLFxuICApLnJlamVjdHMudG9UaHJvdygvUGFyYW1ldGVyIG9yIHJlc291cmNlICdCYWRMYW1iYScgY291bGQgbm90IGJlIGZvdW5kIGZvciBldmFsdWF0aW9uLyk7XG5cbiAgZXhwZWN0KG1vY2tMYW1iZGFJbnZva2UpLm5vdC50b0hhdmVCZWVuQ2FsbGVkKCk7XG59KTtcblxuZGVzY3JpYmUoJ29sZC1zdHlsZSBzeW50aGVzaXMnLCAoKSA9PiB7XG4gIGNvbnN0IHBhcmFtZXRlcnMgPSB7XG4gICAgV2Vic2l0ZUJ1Y2tldFBhcmFtT2xkOiB7IFR5cGU6ICdTdHJpbmcnIH0sXG4gICAgV2Vic2l0ZUJ1Y2tldFBhcmFtTmV3OiB7IFR5cGU6ICdTdHJpbmcnIH0sXG4gICAgRGlmZmVyZW50QnVja2V0UGFyYW1OZXc6IHsgVHlwZTogJ1N0cmluZycgfSxcbiAgfTtcblxuICBjb25zdCBzZXJ2aWNlUm9sZSA9IHtcbiAgICBUeXBlOiAnQVdTOjpJQU06OlJvbGUnLFxuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIEFzc3VtZVJvbGVQb2xpY3lEb2N1bWVudDoge1xuICAgICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBBY3Rpb246ICdzdHM6QXNzdW1lUm9sZScsXG4gICAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgICBQcmluY2lwYWw6IHtcbiAgICAgICAgICAgICAgU2VydmljZTogJ2xhbWJkYS5hbWF6b25hd3MuY29tJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgICAgVmVyc2lvbjogJzIwMTItMTAtMTcnLFxuICAgICAgfSxcbiAgICB9LFxuICB9O1xuXG4gIGNvbnN0IHBvbGljeU9sZCA9IHtcbiAgICBUeXBlOiAnQVdTOjpJQU06OlBvbGljeScsXG4gICAgUHJvcGVydGllczoge1xuICAgICAgUG9saWN5TmFtZTogJ215LXBvbGljeS1vbGQnLFxuICAgICAgUm9sZXM6IFtcbiAgICAgICAgeyBSZWY6ICdTZXJ2aWNlUm9sZScgfSxcbiAgICAgIF0sXG4gICAgICBQb2xpY3lEb2N1bWVudDoge1xuICAgICAgICBTdGF0ZW1lbnQ6IFtcbiAgICAgICAgICB7XG4gICAgICAgICAgICBBY3Rpb246IFsnczM6R2V0T2JqZWN0KiddLFxuICAgICAgICAgICAgRWZmZWN0OiAnQWxsb3cnLFxuICAgICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgUmVmOiAnV2Vic2l0ZUJ1Y2tldFBhcmFtT2xkJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfTtcblxuICBjb25zdCBwb2xpY3lOZXcgPSB7XG4gICAgVHlwZTogJ0FXUzo6SUFNOjpQb2xpY3knLFxuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIFBvbGljeU5hbWU6ICdteS1wb2xpY3ktbmV3JyxcbiAgICAgIFJvbGVzOiBbXG4gICAgICAgIHsgUmVmOiAnU2VydmljZVJvbGUnIH0sXG4gICAgICBdLFxuICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgQWN0aW9uOiBbJ3MzOkdldE9iamVjdConXSxcbiAgICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICAgIFJlc291cmNlOiB7XG4gICAgICAgICAgICAgIFJlZjogJ1dlYnNpdGVCdWNrZXRQYXJhbU5ldycsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgIH0sXG4gIH07XG5cbiAgY29uc3QgcG9saWN5Mk9sZCA9IHtcbiAgICBUeXBlOiAnQVdTOjpJQU06OlBvbGljeScsXG4gICAgUHJvcGVydGllczoge1xuICAgICAgUG9saWN5TmFtZTogJ215LXBvbGljeS1vbGQtMicsXG4gICAgICBSb2xlczogW1xuICAgICAgICB7IFJlZjogJ1NlcnZpY2VSb2xlJyB9LFxuICAgICAgXSxcbiAgICAgIFBvbGljeURvY3VtZW50OiB7XG4gICAgICAgIFN0YXRlbWVudDogW1xuICAgICAgICAgIHtcbiAgICAgICAgICAgIEFjdGlvbjogWydzMzpHZXRPYmplY3QqJ10sXG4gICAgICAgICAgICBFZmZlY3Q6ICdBbGxvdycsXG4gICAgICAgICAgICBSZXNvdXJjZToge1xuICAgICAgICAgICAgICBSZWY6ICdXZWJzaXRlQnVja2V0UGFyYW1PbGQnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICB9LFxuICB9O1xuXG4gIGNvbnN0IHBvbGljeTJOZXcgPSB7XG4gICAgVHlwZTogJ0FXUzo6SUFNOjpQb2xpY3knLFxuICAgIFByb3BlcnRpZXM6IHtcbiAgICAgIFBvbGljeU5hbWU6ICdteS1wb2xpY3ktbmV3LTInLFxuICAgICAgUm9sZXM6IFtcbiAgICAgICAgeyBSZWY6ICdTZXJ2aWNlUm9sZTInIH0sXG4gICAgICBdLFxuICAgICAgUG9saWN5RG9jdW1lbnQ6IHtcbiAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgQWN0aW9uOiBbJ3MzOkdldE9iamVjdConXSxcbiAgICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICAgIFJlc291cmNlOiB7XG4gICAgICAgICAgICAgIFJlZjogJ0RpZmZlcmVudEJ1Y2tldFBhcmFtT2xkJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgfSxcbiAgfTtcblxuICBjb25zdCBkZXBsb3ltZW50TGFtYmRhID0ge1xuICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLFxuICAgIFJvbGU6IHtcbiAgICAgICdGbjo6R2V0QXR0JzogW1xuICAgICAgICAnU2VydmljZVJvbGUnLFxuICAgICAgICAnQXJuJyxcbiAgICAgIF0sXG4gICAgfSxcbiAgfTtcblxuICBjb25zdCBzM0RlcGxveW1lbnRPbGQgPSB7XG4gICAgVHlwZTogJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsXG4gICAgUHJvcGVydGllczoge1xuICAgICAgU2VydmljZVRva2VuOiB7XG4gICAgICAgICdGbjo6R2V0QXR0JzogW1xuICAgICAgICAgICdTM0RlcGxveW1lbnRMYW1iZGEnLFxuICAgICAgICAgICdBcm4nLFxuICAgICAgICBdLFxuICAgICAgfSxcbiAgICAgIFNvdXJjZUJ1Y2tldE5hbWVzOiBbJ3NyYy1idWNrZXQtb2xkJ10sXG4gICAgICBTb3VyY2VPYmplY3RLZXlzOiBbJ3NyYy1rZXktb2xkJ10sXG4gICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6ICdXZWJzaXRlQnVja2V0T2xkJyxcbiAgICB9LFxuICB9O1xuXG4gIGNvbnN0IHMzRGVwbG95bWVudE5ldyA9IHtcbiAgICBUeXBlOiAnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50JyxcbiAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICBTZXJ2aWNlVG9rZW46IHtcbiAgICAgICAgJ0ZuOjpHZXRBdHQnOiBbXG4gICAgICAgICAgJ1MzRGVwbG95bWVudExhbWJkYScsXG4gICAgICAgICAgJ0FybicsXG4gICAgICAgIF0sXG4gICAgICB9LFxuICAgICAgU291cmNlQnVja2V0TmFtZXM6IFsnc3JjLWJ1Y2tldC1uZXcnXSxcbiAgICAgIFNvdXJjZU9iamVjdEtleXM6IFsnc3JjLWtleS1uZXcnXSxcbiAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ1dlYnNpdGVCdWNrZXROZXcnLFxuICAgIH0sXG4gIH07XG5cbiAgYmVmb3JlRWFjaCgoKSA9PiB7XG4gICAgc2V0dXAucHVzaFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoXG4gICAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignUzNEZXBsb3ltZW50TGFtYmRhJywgJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicsICdteS1kZXBsb3ltZW50LWxhbWJkYScpLFxuICAgICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ1NlcnZpY2VSb2xlJywgJ0FXUzo6SUFNOjpSb2xlJywgJ215LXNlcnZpY2Utcm9sZScpLFxuICAgICk7XG4gIH0pO1xuXG4gIHRlc3QoJ2NhbGxzIHRoZSBsYW1iZGFJbnZva2UoKSBBUEkgd2hlbiBpdCByZWNlaXZlcyBhbiBhc3NldCBkaWZmZXJlbmNlIGluIGFuIFMzIGJ1Y2tldCBkZXBsb3ltZW50IGFuZCBhbiBJQU0gUG9saWN5IGRpZmZlcmVuY2UgdXNpbmcgb2xkLXN0eWxlIHN5bnRoZXNpcycsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIHNldHVwLnNldEN1cnJlbnRDZm5TdGFja1RlbXBsYXRlKHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBQYXJhbWV0ZXJzOiBwYXJhbWV0ZXJzLFxuICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgIFBvbGljeTogcG9saWN5T2xkLFxuICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGE6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgIFMzRGVwbG95bWVudDogczNEZXBsb3ltZW50T2xkLFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgICAgdGVtcGxhdGU6IHtcbiAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgUGFyYW1ldGVyczogcGFyYW1ldGVycyxcbiAgICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgICAgUG9saWN5OiBwb2xpY3lOZXcsXG4gICAgICAgICAgUzNEZXBsb3ltZW50TGFtYmRhOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICAgIFMzRGVwbG95bWVudDogczNEZXBsb3ltZW50TmV3LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIC8vIFdIRU5cbiAgICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCwgeyBXZWJzaXRlQnVja2V0UGFyYW1PbGQ6ICdXZWJzaXRlQnVja2V0T2xkJywgV2Vic2l0ZUJ1Y2tldFBhcmFtTmV3OiAnV2Vic2l0ZUJ1Y2tldE5ldycgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgZXhwZWN0KGRlcGxveVN0YWNrUmVzdWx0KS5ub3QudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdChtb2NrTGFtYmRhSW52b2tlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgICBGdW5jdGlvbk5hbWU6ICdhcm46YXdzOmxhbWJkYTpoZXJlOjEyMzQ1Njc4OTAxMjpmdW5jdGlvbjpteS1kZXBsb3ltZW50LWxhbWJkYScsXG4gICAgICBQYXlsb2FkOiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIC4uLnBheWxvYWRXaXRob3V0Q3VzdG9tUmVzUHJvcHMsXG4gICAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICAgIFNvdXJjZUJ1Y2tldE5hbWVzOiBbJ3NyYy1idWNrZXQtbmV3J10sXG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW5ldyddLFxuICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ1dlYnNpdGVCdWNrZXROZXcnLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgfSk7XG4gIH0pO1xuXG4gIHRlc3QoJ2RvZXMgbm90IGNhbGwgdGhlIGxhbWJkYUludm9rZSgpIEFQSSB3aGVuIHRoZSBkaWZmZXJlbmNlIGluIHRoZSBTMyBkZXBsb3ltZW50IGlzIHJlZmVycmVkIHRvIGluIG9uZSBJQU0gcG9saWN5IGNoYW5nZSBidXQgbm90IGFub3RoZXInLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBzZXR1cC5zZXRDdXJyZW50Q2ZuU3RhY2tUZW1wbGF0ZSh7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgU2VydmljZVJvbGU6IHNlcnZpY2VSb2xlLFxuICAgICAgICBQb2xpY3kxOiBwb2xpY3lPbGQsXG4gICAgICAgIFBvbGljeTI6IHBvbGljeTJPbGQsXG4gICAgICAgIFMzRGVwbG95bWVudExhbWJkYTogZGVwbG95bWVudExhbWJkYSxcbiAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnRPbGQsXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHNldHVwLmNka1N0YWNrQXJ0aWZhY3RPZih7XG4gICAgICB0ZW1wbGF0ZToge1xuICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgICAgUG9saWN5MTogcG9saWN5TmV3LFxuICAgICAgICAgIFBvbGljeTI6IHtcbiAgICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgICAgUm9sZXM6IFtcbiAgICAgICAgICAgICAgICB7IFJlZjogJ1NlcnZpY2VSb2xlJyB9LFxuICAgICAgICAgICAgICAgICdkaWZmZXJlbnQtcm9sZScsXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIFBvbGljeURvY3VtZW50OiB7XG4gICAgICAgICAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIEFjdGlvbjogWydzMzpHZXRPYmplY3QqJ10sXG4gICAgICAgICAgICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICAgICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICdEaWZmZXJlbnRCdWNrZXROZXcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ0FybicsXG4gICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGE6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnROZXcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGRlcGxveVN0YWNrUmVzdWx0ID0gYXdhaXQgaG90c3dhcE1vY2tTZGtQcm92aWRlci50cnlIb3Rzd2FwRGVwbG95bWVudChjZGtTdGFja0FydGlmYWN0KTtcblxuICAgIC8vIFRIRU5cbiAgICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QobW9ja0xhbWJkYUludm9rZSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgfSk7XG5cbiAgdGVzdCgnZG9lcyBub3QgY2FsbCB0aGUgbGFtYmRhSW52b2tlKCkgQVBJIHdoZW4gdGhlIGxhbWJkYSB0aGF0IHJlZmVyZW5jZXMgdGhlIHJvbGUgaXMgcmVmZXJyZWQgdG8gYnkgc29tZXRoaW5nIG90aGVyIHRoYW4gYW4gUzMgZGVwbG95bWVudCcsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIHNldHVwLnNldEN1cnJlbnRDZm5TdGFja1RlbXBsYXRlKHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgIFBvbGljeTogcG9saWN5T2xkLFxuICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGE6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgIFMzRGVwbG95bWVudDogczNEZXBsb3ltZW50T2xkLFxuICAgICAgICBFbmRwb2ludDoge1xuICAgICAgICAgIFR5cGU6ICdBV1M6OkxhbWJkYTo6UGVybWlzc2lvbicsXG4gICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgQWN0aW9uOiAnbGFtYmRhOkludm9rZUZ1bmN0aW9uJyxcbiAgICAgICAgICAgIEZ1bmN0aW9uTmFtZToge1xuICAgICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAgICAnUzNEZXBsb3ltZW50TGFtYmRhJyxcbiAgICAgICAgICAgICAgICAnQXJuJyxcbiAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBQcmluY2lwYWw6ICdhcGlnYXRld2F5LmFtYXpvbmF3cy5jb20nLFxuICAgICAgICAgIH0sXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgY29uc3QgY2RrU3RhY2tBcnRpZmFjdCA9IHNldHVwLmNka1N0YWNrQXJ0aWZhY3RPZih7XG4gICAgICB0ZW1wbGF0ZToge1xuICAgICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgICAgUG9saWN5OiBwb2xpY3lOZXcsXG4gICAgICAgICAgUzNEZXBsb3ltZW50TGFtYmRhOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICAgIFMzRGVwbG95bWVudDogczNEZXBsb3ltZW50TmV3LFxuICAgICAgICAgIEVuZHBvaW50OiB7XG4gICAgICAgICAgICBUeXBlOiAnQVdTOjpMYW1iZGE6OlBlcm1pc3Npb24nLFxuICAgICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgICBBY3Rpb246ICdsYW1iZGE6SW52b2tlRnVuY3Rpb24nLFxuICAgICAgICAgICAgICBGdW5jdGlvbk5hbWU6IHtcbiAgICAgICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAgICAgICdTM0RlcGxveW1lbnRMYW1iZGEnLFxuICAgICAgICAgICAgICAgICAgJ0FybicsXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgUHJpbmNpcGFsOiAnYXBpZ2F0ZXdheS5hbWF6b25hd3MuY29tJyxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChkZXBsb3lTdGFja1Jlc3VsdCkudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdChtb2NrTGFtYmRhSW52b2tlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICB9KTtcblxuICB0ZXN0KCdjYWxscyB0aGUgbGFtYmRhSW52b2tlKCkgQVBJIHdoZW4gaXQgcmVjZWl2ZXMgYW4gYXNzZXQgZGlmZmVyZW5jZSBpbiB0d28gUzMgYnVja2V0IGRlcGxveW1lbnRzIGFuZCBJQU0gUG9saWN5IGRpZmZlcmVuY2VzIHVzaW5nIG9sZC1zdHlsZSBzeW50aGVzaXMnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBjb25zdCBzM0RlcGxveW1lbnQyT2xkID0ge1xuICAgICAgVHlwZTogJ0N1c3RvbTo6Q0RLQnVja2V0RGVwbG95bWVudCcsXG4gICAgICBQcm9wZXJ0aWVzOiB7XG4gICAgICAgIFNlcnZpY2VUb2tlbjoge1xuICAgICAgICAgICdGbjo6R2V0QXR0JzogW1xuICAgICAgICAgICAgJ1MzRGVwbG95bWVudExhbWJkYTInLFxuICAgICAgICAgICAgJ0FybicsXG4gICAgICAgICAgXSxcbiAgICAgICAgfSxcbiAgICAgICAgU291cmNlQnVja2V0TmFtZXM6IFsnc3JjLWJ1Y2tldC1vbGQnXSxcbiAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW9sZCddLFxuICAgICAgICBEZXN0aW5hdGlvbkJ1Y2tldE5hbWU6ICdEaWZmZXJlbnRCdWNrZXRPbGQnLFxuICAgICAgfSxcbiAgICB9O1xuXG4gICAgY29uc3QgczNEZXBsb3ltZW50Mk5ldyA9IHtcbiAgICAgIFR5cGU6ICdDdXN0b206OkNES0J1Y2tldERlcGxveW1lbnQnLFxuICAgICAgUHJvcGVydGllczoge1xuICAgICAgICBTZXJ2aWNlVG9rZW46IHtcbiAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICdTM0RlcGxveW1lbnRMYW1iZGEyJyxcbiAgICAgICAgICAgICdBcm4nLFxuICAgICAgICAgIF0sXG4gICAgICAgIH0sXG4gICAgICAgIFNvdXJjZUJ1Y2tldE5hbWVzOiBbJ3NyYy1idWNrZXQtbmV3J10sXG4gICAgICAgIFNvdXJjZU9iamVjdEtleXM6IFsnc3JjLWtleS1uZXcnXSxcbiAgICAgICAgRGVzdGluYXRpb25CdWNrZXROYW1lOiAnRGlmZmVyZW50QnVja2V0TmV3JyxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIHNldHVwLnNldEN1cnJlbnRDZm5TdGFja1RlbXBsYXRlKHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgIFNlcnZpY2VSb2xlMjogc2VydmljZVJvbGUsXG4gICAgICAgIFBvbGljeTE6IHBvbGljeU9sZCxcbiAgICAgICAgUG9saWN5MjogcG9saWN5Mk9sZCxcbiAgICAgICAgUzNEZXBsb3ltZW50TGFtYmRhOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGEyOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICBTM0RlcGxveW1lbnQ6IHMzRGVwbG95bWVudE9sZCxcbiAgICAgICAgUzNEZXBsb3ltZW50MjogczNEZXBsb3ltZW50Mk9sZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBjZGtTdGFja0FydGlmYWN0ID0gc2V0dXAuY2RrU3RhY2tBcnRpZmFjdE9mKHtcbiAgICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIFJlc291cmNlczoge1xuICAgICAgICAgIFBhcmFtZXRlcnM6IHBhcmFtZXRlcnMsXG4gICAgICAgICAgU2VydmljZVJvbGU6IHNlcnZpY2VSb2xlLFxuICAgICAgICAgIFNlcnZpY2VSb2xlMjogc2VydmljZVJvbGUsXG4gICAgICAgICAgUG9saWN5MTogcG9saWN5TmV3LFxuICAgICAgICAgIFBvbGljeTI6IHBvbGljeTJOZXcsXG4gICAgICAgICAgUzNEZXBsb3ltZW50TGFtYmRhOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICAgIFMzRGVwbG95bWVudExhbWJkYTI6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnROZXcsXG4gICAgICAgICAgUzNEZXBsb3ltZW50MjogczNEZXBsb3ltZW50Mk5ldyxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgc2V0dXAucHVzaFN0YWNrUmVzb3VyY2VTdW1tYXJpZXMoXG4gICAgICBzZXR1cC5zdGFja1N1bW1hcnlPZignUzNEZXBsb3ltZW50TGFtYmRhMicsICdBV1M6OkxhbWJkYTo6RnVuY3Rpb24nLCAnbXktZGVwbG95bWVudC1sYW1iZGEtMicpLFxuICAgICAgc2V0dXAuc3RhY2tTdW1tYXJ5T2YoJ1NlcnZpY2VSb2xlMicsICdBV1M6OklBTTo6Um9sZScsICdteS1zZXJ2aWNlLXJvbGUtMicpLFxuICAgICk7XG5cbiAgICBjb25zdCBkZXBsb3lTdGFja1Jlc3VsdCA9IGF3YWl0IGhvdHN3YXBNb2NrU2RrUHJvdmlkZXIudHJ5SG90c3dhcERlcGxveW1lbnQoY2RrU3RhY2tBcnRpZmFjdCwge1xuICAgICAgV2Vic2l0ZUJ1Y2tldFBhcmFtT2xkOiAnV2Vic2l0ZUJ1Y2tldE9sZCcsXG4gICAgICBXZWJzaXRlQnVja2V0UGFyYW1OZXc6ICdXZWJzaXRlQnVja2V0TmV3JyxcbiAgICAgIERpZmZlcmVudEJ1Y2tldFBhcmFtTmV3OiAnV2Vic2l0ZUJ1Y2tldE5ldycsXG4gICAgfSk7XG5cbiAgICAvLyBUSEVOXG4gICAgZXhwZWN0KGRlcGxveVN0YWNrUmVzdWx0KS5ub3QudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdChtb2NrTGFtYmRhSW52b2tlKS50b0hhdmVCZWVuQ2FsbGVkV2l0aCh7XG4gICAgICBGdW5jdGlvbk5hbWU6ICdhcm46YXdzOmxhbWJkYTpoZXJlOjEyMzQ1Njc4OTAxMjpmdW5jdGlvbjpteS1kZXBsb3ltZW50LWxhbWJkYScsXG4gICAgICBQYXlsb2FkOiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIC4uLnBheWxvYWRXaXRob3V0Q3VzdG9tUmVzUHJvcHMsXG4gICAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICAgIFNvdXJjZUJ1Y2tldE5hbWVzOiBbJ3NyYy1idWNrZXQtbmV3J10sXG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW5ldyddLFxuICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ1dlYnNpdGVCdWNrZXROZXcnLFxuICAgICAgICB9LFxuICAgICAgfSksXG4gICAgfSk7XG5cbiAgICBleHBlY3QobW9ja0xhbWJkYUludm9rZSkudG9IYXZlQmVlbkNhbGxlZFdpdGgoe1xuICAgICAgRnVuY3Rpb25OYW1lOiAnYXJuOmF3czpsYW1iZGE6aGVyZToxMjM0NTY3ODkwMTI6ZnVuY3Rpb246bXktZGVwbG95bWVudC1sYW1iZGEtMicsXG4gICAgICBQYXlsb2FkOiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgIC4uLnBheWxvYWRXaXRob3V0Q3VzdG9tUmVzUHJvcHMsXG4gICAgICAgIFJlc291cmNlUHJvcGVydGllczoge1xuICAgICAgICAgIFNvdXJjZUJ1Y2tldE5hbWVzOiBbJ3NyYy1idWNrZXQtbmV3J10sXG4gICAgICAgICAgU291cmNlT2JqZWN0S2V5czogWydzcmMta2V5LW5ldyddLFxuICAgICAgICAgIERlc3RpbmF0aW9uQnVja2V0TmFtZTogJ0RpZmZlcmVudEJ1Y2tldE5ldycsXG4gICAgICAgIH0sXG4gICAgICB9KSxcbiAgICB9KTtcbiAgfSk7XG5cbiAgdGVzdCgnZG9lcyBub3QgY2FsbCB0aGUgbGFtYmRhSW52b2tlKCkgQVBJIHdoZW4gaXQgcmVjZWl2ZXMgYW4gYXNzZXQgZGlmZmVyZW5jZSBpbiBhbiBTMyBidWNrZXQgZGVwbG95bWVudCB0aGF0IHJlZmVyZW5jZXMgdHdvIGRpZmZlcmVudCBwb2xpY2llcycsIGFzeW5jICgpID0+IHtcbiAgICAvLyBHSVZFTlxuICAgIHNldHVwLnNldEN1cnJlbnRDZm5TdGFja1RlbXBsYXRlKHtcbiAgICAgIFJlc291cmNlczoge1xuICAgICAgICBTZXJ2aWNlUm9sZTogc2VydmljZVJvbGUsXG4gICAgICAgIFBvbGljeTE6IHBvbGljeU9sZCxcbiAgICAgICAgUG9saWN5MjogcG9saWN5Mk9sZCxcbiAgICAgICAgUzNEZXBsb3ltZW50TGFtYmRhOiBkZXBsb3ltZW50TGFtYmRhLFxuICAgICAgICBTM0RlcGxveW1lbnQ6IHMzRGVwbG95bWVudE9sZCxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICBjb25zdCBjZGtTdGFja0FydGlmYWN0ID0gc2V0dXAuY2RrU3RhY2tBcnRpZmFjdE9mKHtcbiAgICAgIHRlbXBsYXRlOiB7XG4gICAgICAgIFJlc291cmNlczoge1xuICAgICAgICAgIFNlcnZpY2VSb2xlOiBzZXJ2aWNlUm9sZSxcbiAgICAgICAgICBQb2xpY3kxOiBwb2xpY3lOZXcsXG4gICAgICAgICAgUG9saWN5Mjoge1xuICAgICAgICAgICAgUHJvcGVydGllczoge1xuICAgICAgICAgICAgICBSb2xlczogW1xuICAgICAgICAgICAgICAgIHsgUmVmOiAnU2VydmljZVJvbGUnIH0sXG4gICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgIFBvbGljeURvY3VtZW50OiB7XG4gICAgICAgICAgICAgICAgU3RhdGVtZW50OiBbXG4gICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIEFjdGlvbjogWydzMzpHZXRPYmplY3QqJ10sXG4gICAgICAgICAgICAgICAgICAgIEVmZmVjdDogJ0FsbG93JyxcbiAgICAgICAgICAgICAgICAgICAgUmVzb3VyY2U6IHtcbiAgICAgICAgICAgICAgICAgICAgICAnRm46OkdldEF0dCc6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICdEaWZmZXJlbnRCdWNrZXROZXcnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ0FybicsXG4gICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGE6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnROZXcsXG4gICAgICAgIH0sXG4gICAgICB9LFxuICAgIH0pO1xuXG4gICAgLy8gV0hFTlxuICAgIGNvbnN0IGRlcGxveVN0YWNrUmVzdWx0ID0gYXdhaXQgaG90c3dhcE1vY2tTZGtQcm92aWRlci50cnlIb3Rzd2FwRGVwbG95bWVudChjZGtTdGFja0FydGlmYWN0KTtcblxuICAgIC8vIFRIRU5cbiAgICBleHBlY3QoZGVwbG95U3RhY2tSZXN1bHQpLnRvQmVVbmRlZmluZWQoKTtcbiAgICBleHBlY3QobW9ja0xhbWJkYUludm9rZSkubm90LnRvSGF2ZUJlZW5DYWxsZWQoKTtcbiAgfSk7XG5cbiAgdGVzdCgnZG9lcyBub3QgY2FsbCB0aGUgbGFtYmRhSW52b2tlKCkgQVBJIHdoZW4gYSBwb2xpY3kgaXMgcmVmZXJlbmNlZCBieSBhIHJlc291cmNlIHRoYXQgaXMgbm90IGFuIFMzIGRlcGxveW1lbnQnLCBhc3luYyAoKSA9PiB7XG4gICAgLy8gR0lWRU5cbiAgICBzZXR1cC5zZXRDdXJyZW50Q2ZuU3RhY2tUZW1wbGF0ZSh7XG4gICAgICBSZXNvdXJjZXM6IHtcbiAgICAgICAgU2VydmljZVJvbGU6IHNlcnZpY2VSb2xlLFxuICAgICAgICBQb2xpY3kxOiBwb2xpY3lPbGQsXG4gICAgICAgIFMzRGVwbG95bWVudExhbWJkYTogZGVwbG95bWVudExhbWJkYSxcbiAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnRPbGQsXG4gICAgICAgIE5vdEFEZXBsb3ltZW50OiB7XG4gICAgICAgICAgVHlwZTogJ0FXUzo6Tm90OjpTM0RlcGxveW1lbnQnLFxuICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgIFByb3A6IHtcbiAgICAgICAgICAgICAgUmVmOiAnU2VydmljZVJvbGUnLFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICB9LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGNka1N0YWNrQXJ0aWZhY3QgPSBzZXR1cC5jZGtTdGFja0FydGlmYWN0T2Yoe1xuICAgICAgdGVtcGxhdGU6IHtcbiAgICAgICAgUmVzb3VyY2VzOiB7XG4gICAgICAgICAgU2VydmljZVJvbGU6IHNlcnZpY2VSb2xlLFxuICAgICAgICAgIFBvbGljeTE6IHBvbGljeU5ldyxcbiAgICAgICAgICBTM0RlcGxveW1lbnRMYW1iZGE6IGRlcGxveW1lbnRMYW1iZGEsXG4gICAgICAgICAgUzNEZXBsb3ltZW50OiBzM0RlcGxveW1lbnROZXcsXG4gICAgICAgICAgTm90QURlcGxveW1lbnQ6IHtcbiAgICAgICAgICAgIFR5cGU6ICdBV1M6Ok5vdDo6UzNEZXBsb3ltZW50JyxcbiAgICAgICAgICAgIFByb3BlcnRpZXM6IHtcbiAgICAgICAgICAgICAgUHJvcDoge1xuICAgICAgICAgICAgICAgIFJlZjogJ1NlcnZpY2VSb2xlJyxcbiAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfSxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfSk7XG5cbiAgICAvLyBXSEVOXG4gICAgY29uc3QgZGVwbG95U3RhY2tSZXN1bHQgPSBhd2FpdCBob3Rzd2FwTW9ja1Nka1Byb3ZpZGVyLnRyeUhvdHN3YXBEZXBsb3ltZW50KGNka1N0YWNrQXJ0aWZhY3QpO1xuXG4gICAgLy8gVEhFTlxuICAgIGV4cGVjdChkZXBsb3lTdGFja1Jlc3VsdCkudG9CZVVuZGVmaW5lZCgpO1xuICAgIGV4cGVjdChtb2NrTGFtYmRhSW52b2tlKS5ub3QudG9IYXZlQmVlbkNhbGxlZCgpO1xuICB9KTtcbn0pOyJdfQ==
|