aws-cdk 2.19.0 → 2.20.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.
Files changed (47) hide show
  1. package/README.md +59 -11
  2. package/build-info.json +2 -2
  3. package/does-not-exist.json +1 -1
  4. package/lib/api/bootstrap/bootstrap-template.yaml +3 -1
  5. package/lib/api/cloudformation-deployments.d.ts +12 -1
  6. package/lib/api/cloudformation-deployments.js +31 -8
  7. package/lib/api/deploy-stack.d.ts +24 -0
  8. package/lib/api/deploy-stack.js +35 -8
  9. package/lib/api/evaluate-cloudformation-template.js +3 -2
  10. package/lib/api/hotswap/common.js +2 -2
  11. package/lib/api/util/cloudformation/stack-activity-monitor.js +7 -6
  12. package/lib/api/util/cloudformation/stack-status.js +2 -2
  13. package/lib/api/util/cloudformation.d.ts +3 -0
  14. package/lib/api/util/cloudformation.js +1 -1
  15. package/lib/api/util/display.d.ts +2 -0
  16. package/lib/api/util/display.js +15 -2
  17. package/lib/cdk-toolkit.d.ts +44 -21
  18. package/lib/cdk-toolkit.js +68 -1
  19. package/lib/cli.js +46 -3
  20. package/lib/commands/doctor.js +2 -2
  21. package/lib/import.d.ts +151 -0
  22. package/lib/import.js +245 -0
  23. package/lib/index.js +2296 -815
  24. package/lib/settings.js +3 -2
  25. package/lib/util/asset-publishing.d.ts +7 -1
  26. package/lib/util/asset-publishing.js +13 -6
  27. package/lib/version.js +2 -2
  28. package/package.json +10 -10
  29. package/test/api/hotswap/state-machine-hotswap-deployments.test.js +75 -1
  30. package/test/api/util/display.test.d.ts +1 -0
  31. package/test/api/util/display.test.js +34 -0
  32. package/test/bockfs.js +2 -2
  33. package/test/cdk-toolkit.test.js +4 -2
  34. package/test/import.test.d.ts +1 -0
  35. package/test/import.test.js +189 -0
  36. package/test/integ/cli/app/app.js +25 -0
  37. package/test/integ/cli/app/docker/Dockerfile +1 -1
  38. package/test/integ/cli/app/docker/Dockerfile.Custom +1 -1
  39. package/test/integ/cli/cli.integtest.js +33 -1
  40. package/test/integ/cli-regression-patches/v1.64.0/cdk-helpers.js +1 -1
  41. package/test/integ/cli-regression-patches/v1.64.1/cdk-helpers.js +1 -1
  42. package/test/integ/cli-regression-patches/v1.67.0/cdk-helpers.js +1 -1
  43. package/test/integ/helpers/cdk.js +4 -5
  44. package/test/integ/helpers/test-helpers.js +1 -3
  45. package/test/settings.test.js +10 -1
  46. package/test/util/mock-sdk.d.ts +2 -0
  47. package/test/util/mock-sdk.js +8 -2
@@ -0,0 +1,151 @@
1
+ import { ResourceDifference } from '@aws-cdk/cloudformation-diff';
2
+ import * as cxapi from '@aws-cdk/cx-api';
3
+ import { CloudFormationDeployments, DeployStackOptions } from './api/cloudformation-deployments';
4
+ import { ResourceIdentifierProperties } from './api/util/cloudformation';
5
+ /**
6
+ * Parameters that uniquely identify a physical resource of a given type
7
+ * for the import operation, example:
8
+ *
9
+ * ```
10
+ * {
11
+ * "AWS::S3::Bucket": ["BucketName"],
12
+ * "AWS::IAM::Role": ["RoleName"],
13
+ * "AWS::EC2::VPC": ["VpcId"]
14
+ * }
15
+ * ```
16
+ */
17
+ export declare type ResourceIdentifiers = {
18
+ [resourceType: string]: string[];
19
+ };
20
+ /**
21
+ * Mapping of CDK resources (L1 constructs) to physical resources to be imported
22
+ * in their place, example:
23
+ *
24
+ * ```
25
+ * {
26
+ * "MyStack/MyS3Bucket/Resource": {
27
+ * "BucketName": "my-manually-created-s3-bucket"
28
+ * },
29
+ * "MyStack/MyVpc/Resource": {
30
+ * "VpcId": "vpc-123456789"
31
+ * }
32
+ * }
33
+ * ```
34
+ */
35
+ export declare type ResourceMap = {
36
+ [logicalResource: string]: ResourceIdentifierProperties;
37
+ };
38
+ export interface ResourceImporterOptions {
39
+ /**
40
+ * Name of toolkit stack if non-default
41
+ *
42
+ * @default - Default toolkit stack name
43
+ */
44
+ readonly toolkitStackName?: string;
45
+ }
46
+ /**
47
+ * Resource importing utility class
48
+ *
49
+ * - Determines the resources added to a template (compared to the deployed version)
50
+ * - Look up the identification information
51
+ * - Load them from a file, or
52
+ * - Ask the user, based on information supplied to us by CloudFormation's GetTemplateSummary
53
+ * - Translate the input to a structure expected by CloudFormation, update the template to add the
54
+ * importable resources, then run an IMPORT changeset.
55
+ */
56
+ export declare class ResourceImporter {
57
+ private readonly stack;
58
+ private readonly cfn;
59
+ private readonly options;
60
+ private _currentTemplate;
61
+ constructor(stack: cxapi.CloudFormationStackArtifact, cfn: CloudFormationDeployments, options?: ResourceImporterOptions);
62
+ /**
63
+ * Ask the user for resources to import
64
+ */
65
+ askForResourceIdentifiers(available: ImportableResource[]): Promise<ImportMap>;
66
+ /**
67
+ * Load the resources to import from a file
68
+ */
69
+ loadResourceIdentifiers(available: ImportableResource[], filename: string): Promise<ImportMap>;
70
+ /**
71
+ * Based on the provided resource mapping, prepare CFN structures for import (template,
72
+ * ResourcesToImport structure) and perform the import operation (CloudFormation deployment)
73
+ *
74
+ * @param resourceMap Mapping from CDK construct tree path to physical resource import identifiers
75
+ * @param options Options to pass to CloudFormation deploy operation
76
+ */
77
+ importResources(importMap: ImportMap, options: DeployStackOptions): Promise<void>;
78
+ /**
79
+ * Perform a diff between the currently running and the new template, enusre that it is valid
80
+ * for importing and return a list of resources that are being added in the new version
81
+ *
82
+ * @return mapping logicalResourceId -> resourceDifference
83
+ */
84
+ discoverImportableResources(allowNonAdditions?: boolean): Promise<DiscoverImportableResourcesResult>;
85
+ /**
86
+ * Get currently deployed template of the given stack (SINGLETON)
87
+ *
88
+ * @returns Currently deployed CloudFormation template
89
+ */
90
+ private currentTemplate;
91
+ /**
92
+ * Return teh current template, with the given resources added to it
93
+ */
94
+ private currentTemplateWithAdditions;
95
+ /**
96
+ * Get a list of import identifiers for all resource types used in the given
97
+ * template that do support the import operation (SINGLETON)
98
+ *
99
+ * @returns a mapping from a resource type to a list of property names that together identify the resource for import
100
+ */
101
+ private resourceIdentifiers;
102
+ private askForResourceIdentifier;
103
+ /**
104
+ * Convert the internal "resource mapping" structure to CloudFormation accepted "ResourcesToImport" structure
105
+ */
106
+ private makeResourcesToImport;
107
+ /**
108
+ * Convert CloudFormation logical resource ID to CDK construct tree path
109
+ *
110
+ * @param logicalId CloudFormation logical ID of the resource (the key in the template's Resources section)
111
+ * @returns Forward-slash separated path of the resource in CDK construct tree, e.g. MyStack/MyBucket/Resource
112
+ */
113
+ private describeResource;
114
+ }
115
+ /**
116
+ * Information about a resource in the template that is importable
117
+ */
118
+ export interface ImportableResource {
119
+ /**
120
+ * The logical ID of the resource
121
+ */
122
+ readonly logicalId: string;
123
+ /**
124
+ * The resource definition in the new template
125
+ */
126
+ readonly resourceDefinition: any;
127
+ /**
128
+ * The diff as reported by `cloudformation-diff`.
129
+ */
130
+ readonly resourceDiff: ResourceDifference;
131
+ }
132
+ /**
133
+ * The information necessary to execute an import operation
134
+ */
135
+ export interface ImportMap {
136
+ /**
137
+ * Mapping logical IDs to physical names
138
+ */
139
+ readonly resourceMap: ResourceMap;
140
+ /**
141
+ * The selection of resources we are actually importing
142
+ *
143
+ * For each of the resources in this list, there is a corresponding entry in
144
+ * the `resourceMap` map.
145
+ */
146
+ readonly importResources: ImportableResource[];
147
+ }
148
+ export interface DiscoverImportableResourcesResult {
149
+ readonly additions: ImportableResource[];
150
+ readonly hasNonAdditions: boolean;
151
+ }
package/lib/import.js ADDED
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ResourceImporter = void 0;
4
+ const cfnDiff = require("@aws-cdk/cloudformation-diff");
5
+ const chalk = require("chalk");
6
+ const fs = require("fs-extra");
7
+ const promptly = require("promptly");
8
+ const logging_1 = require("./logging");
9
+ /**
10
+ * Resource importing utility class
11
+ *
12
+ * - Determines the resources added to a template (compared to the deployed version)
13
+ * - Look up the identification information
14
+ * - Load them from a file, or
15
+ * - Ask the user, based on information supplied to us by CloudFormation's GetTemplateSummary
16
+ * - Translate the input to a structure expected by CloudFormation, update the template to add the
17
+ * importable resources, then run an IMPORT changeset.
18
+ */
19
+ class ResourceImporter {
20
+ constructor(stack, cfn, options = {}) {
21
+ this.stack = stack;
22
+ this.cfn = cfn;
23
+ this.options = options;
24
+ }
25
+ /**
26
+ * Ask the user for resources to import
27
+ */
28
+ async askForResourceIdentifiers(available) {
29
+ const ret = { importResources: [], resourceMap: {} };
30
+ const resourceIdentifiers = await this.resourceIdentifiers();
31
+ for (const resource of available) {
32
+ const identifier = await this.askForResourceIdentifier(resourceIdentifiers, resource);
33
+ if (!identifier) {
34
+ continue;
35
+ }
36
+ ret.importResources.push(resource);
37
+ ret.resourceMap[resource.logicalId] = identifier;
38
+ }
39
+ return ret;
40
+ }
41
+ /**
42
+ * Load the resources to import from a file
43
+ */
44
+ async loadResourceIdentifiers(available, filename) {
45
+ const contents = await fs.readJson(filename);
46
+ const ret = { importResources: [], resourceMap: {} };
47
+ for (const resource of available) {
48
+ const descr = this.describeResource(resource.logicalId);
49
+ const idProps = contents[resource.logicalId];
50
+ if (idProps) {
51
+ logging_1.print('%s: importing using %s', chalk.blue(descr), chalk.blue(fmtdict(idProps)));
52
+ ret.importResources.push(resource);
53
+ ret.resourceMap[resource.logicalId] = idProps;
54
+ delete contents[resource.logicalId];
55
+ }
56
+ else {
57
+ logging_1.print('%s: skipping', chalk.blue(descr));
58
+ }
59
+ }
60
+ const unknown = Object.keys(contents);
61
+ if (unknown.length > 0) {
62
+ logging_1.warning(`Unrecognized resource identifiers in mapping file: ${unknown.join(', ')}`);
63
+ }
64
+ return ret;
65
+ }
66
+ /**
67
+ * Based on the provided resource mapping, prepare CFN structures for import (template,
68
+ * ResourcesToImport structure) and perform the import operation (CloudFormation deployment)
69
+ *
70
+ * @param resourceMap Mapping from CDK construct tree path to physical resource import identifiers
71
+ * @param options Options to pass to CloudFormation deploy operation
72
+ */
73
+ async importResources(importMap, options) {
74
+ const resourcesToImport = await this.makeResourcesToImport(importMap);
75
+ const updatedTemplate = await this.currentTemplateWithAdditions(importMap.importResources);
76
+ try {
77
+ const result = await this.cfn.deployStack({
78
+ ...options,
79
+ overrideTemplate: updatedTemplate,
80
+ resourcesToImport,
81
+ });
82
+ const message = result.noOp
83
+ ? ' ✅ %s (no changes)'
84
+ : ' ✅ %s';
85
+ logging_1.success('\n' + message, options.stack.displayName);
86
+ }
87
+ catch (e) {
88
+ logging_1.error('\n ❌ %s failed: %s', chalk.bold(options.stack.displayName), e);
89
+ throw e;
90
+ }
91
+ }
92
+ /**
93
+ * Perform a diff between the currently running and the new template, enusre that it is valid
94
+ * for importing and return a list of resources that are being added in the new version
95
+ *
96
+ * @return mapping logicalResourceId -> resourceDifference
97
+ */
98
+ async discoverImportableResources(allowNonAdditions = false) {
99
+ const currentTemplate = await this.currentTemplate();
100
+ const diff = cfnDiff.diffTemplate(currentTemplate, this.stack.template);
101
+ // Ignore changes to CDKMetadata
102
+ const resourceChanges = Object.entries(diff.resources.changes)
103
+ .filter(([logicalId, _]) => logicalId !== 'CDKMetadata');
104
+ // Split the changes into additions and non-additions. Imports only make sense
105
+ // for newly-added resources.
106
+ const nonAdditions = resourceChanges.filter(([_, dif]) => !dif.isAddition);
107
+ const additions = resourceChanges.filter(([_, dif]) => dif.isAddition);
108
+ if (nonAdditions.length) {
109
+ const offendingResources = nonAdditions.map(([logId, _]) => this.describeResource(logId));
110
+ if (allowNonAdditions) {
111
+ logging_1.warning(`Ignoring updated/deleted resources (--force): ${offendingResources.join(', ')}`);
112
+ }
113
+ else {
114
+ throw new Error('No resource updates or deletes are allowed on import operation. Make sure to resolve pending changes ' +
115
+ `to existing resources, before attempting an import. Updated/deleted resources: ${offendingResources.join(', ')} (--force to override)`);
116
+ }
117
+ }
118
+ // Resources in the new template, that are not present in the current template, are a potential import candidates
119
+ return {
120
+ additions: additions.map(([logicalId, resourceDiff]) => {
121
+ var _a, _b, _c;
122
+ return ({
123
+ logicalId,
124
+ resourceDiff,
125
+ resourceDefinition: addDefaultDeletionPolicy((_c = (_b = (_a = this.stack.template) === null || _a === void 0 ? void 0 : _a.Resources) === null || _b === void 0 ? void 0 : _b[logicalId]) !== null && _c !== void 0 ? _c : {}),
126
+ });
127
+ }),
128
+ hasNonAdditions: nonAdditions.length > 0,
129
+ };
130
+ }
131
+ /**
132
+ * Get currently deployed template of the given stack (SINGLETON)
133
+ *
134
+ * @returns Currently deployed CloudFormation template
135
+ */
136
+ async currentTemplate() {
137
+ if (!this._currentTemplate) {
138
+ this._currentTemplate = await this.cfn.readCurrentTemplate(this.stack);
139
+ }
140
+ return this._currentTemplate;
141
+ }
142
+ /**
143
+ * Return teh current template, with the given resources added to it
144
+ */
145
+ async currentTemplateWithAdditions(additions) {
146
+ const template = await this.currentTemplate();
147
+ if (!template.Resources) {
148
+ template.Resources = {};
149
+ }
150
+ for (const add of additions) {
151
+ template.Resources[add.logicalId] = add.resourceDefinition;
152
+ }
153
+ return template;
154
+ }
155
+ /**
156
+ * Get a list of import identifiers for all resource types used in the given
157
+ * template that do support the import operation (SINGLETON)
158
+ *
159
+ * @returns a mapping from a resource type to a list of property names that together identify the resource for import
160
+ */
161
+ async resourceIdentifiers() {
162
+ const ret = {};
163
+ const resourceIdentifierSummaries = await this.cfn.resourceIdentifierSummaries(this.stack, this.options.toolkitStackName);
164
+ for (const summary of resourceIdentifierSummaries) {
165
+ if ('ResourceType' in summary && summary.ResourceType && 'ResourceIdentifiers' in summary && summary.ResourceIdentifiers) {
166
+ ret[summary.ResourceType] = summary.ResourceIdentifiers;
167
+ }
168
+ }
169
+ return ret;
170
+ }
171
+ async askForResourceIdentifier(resourceIdentifiers, chg) {
172
+ var _a;
173
+ const resourceName = this.describeResource(chg.logicalId);
174
+ // Skip resources that do not support importing
175
+ const resourceType = chg.resourceDiff.newResourceType;
176
+ if (resourceType === undefined || !(resourceType in resourceIdentifiers)) {
177
+ logging_1.warning(`${resourceName}: unsupported resource type ${resourceType}, skipping import.`);
178
+ return undefined;
179
+ }
180
+ const idProps = resourceIdentifiers[resourceType];
181
+ const resourceProps = (_a = chg.resourceDefinition.Properties) !== null && _a !== void 0 ? _a : {};
182
+ const fixedIdProps = idProps.filter(p => resourceProps[p]);
183
+ const fixedIdInput = Object.fromEntries(fixedIdProps.map(p => [p, resourceProps[p]]));
184
+ const missingIdProps = idProps.filter(p => !resourceProps[p]);
185
+ if (missingIdProps.length === 0) {
186
+ // We can auto-import this, but ask the user to confirm
187
+ const props = fmtdict(fixedIdInput);
188
+ if (!await promptly.confirm(`${chalk.blue(resourceName)} (${resourceType}): import with ${chalk.yellow(props)} (yes/no) [default: yes]? `, { default: 'yes' })) {
189
+ logging_1.print(chalk.grey(`Skipping import of ${resourceName}`));
190
+ return undefined;
191
+ }
192
+ }
193
+ // Ask the user to provide missing props
194
+ const userInput = {};
195
+ for (const missingIdProp of missingIdProps) {
196
+ const response = (await promptly.prompt(`${chalk.blue(resourceName)} (${resourceType}): enter ${chalk.blue(missingIdProp)} to import (empty to skip):`, { default: '', trim: true }));
197
+ if (!response) {
198
+ logging_1.print(chalk.grey(`Skipping import of ${resourceName}`));
199
+ return undefined;
200
+ }
201
+ userInput[missingIdProp] = response;
202
+ }
203
+ return {
204
+ ...fixedIdInput,
205
+ ...userInput,
206
+ };
207
+ }
208
+ /**
209
+ * Convert the internal "resource mapping" structure to CloudFormation accepted "ResourcesToImport" structure
210
+ */
211
+ async makeResourcesToImport(resourceMap) {
212
+ return resourceMap.importResources.map(res => ({
213
+ LogicalResourceId: res.logicalId,
214
+ ResourceType: res.resourceDiff.newResourceType,
215
+ ResourceIdentifier: resourceMap.resourceMap[res.logicalId],
216
+ }));
217
+ }
218
+ /**
219
+ * Convert CloudFormation logical resource ID to CDK construct tree path
220
+ *
221
+ * @param logicalId CloudFormation logical ID of the resource (the key in the template's Resources section)
222
+ * @returns Forward-slash separated path of the resource in CDK construct tree, e.g. MyStack/MyBucket/Resource
223
+ */
224
+ describeResource(logicalId) {
225
+ var _a, _b, _c, _d, _e;
226
+ return (_e = (_d = (_c = (_b = (_a = this.stack.template) === null || _a === void 0 ? void 0 : _a.Resources) === null || _b === void 0 ? void 0 : _b[logicalId]) === null || _c === void 0 ? void 0 : _c.Metadata) === null || _d === void 0 ? void 0 : _d['aws:cdk:path']) !== null && _e !== void 0 ? _e : logicalId;
227
+ }
228
+ }
229
+ exports.ResourceImporter = ResourceImporter;
230
+ function fmtdict(xs) {
231
+ return Object.entries(xs).map(([k, v]) => `${k}=${v}`).join(', ');
232
+ }
233
+ /**
234
+ * Add a default 'Delete' policy, which is required to make the import succeed
235
+ */
236
+ function addDefaultDeletionPolicy(resource) {
237
+ if (resource.DeletionPolicy) {
238
+ return resource;
239
+ }
240
+ return {
241
+ ...resource,
242
+ DeletionPolicy: 'Delete',
243
+ };
244
+ }
245
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW1wb3J0LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiaW1wb3J0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHdEQUF3RDtBQUd4RCwrQkFBK0I7QUFDL0IsK0JBQStCO0FBQy9CLHFDQUFxQztBQUdyQyx1Q0FBMkQ7QUEwQzNEOzs7Ozs7Ozs7R0FTRztBQUNILE1BQWEsZ0JBQWdCO0lBRzNCLFlBQ21CLEtBQXdDLEVBQ3hDLEdBQThCLEVBQzlCLFVBQW1DLEVBQUU7UUFGckMsVUFBSyxHQUFMLEtBQUssQ0FBbUM7UUFDeEMsUUFBRyxHQUFILEdBQUcsQ0FBMkI7UUFDOUIsWUFBTyxHQUFQLE9BQU8sQ0FBOEI7SUFBSSxDQUFDO0lBRTdEOztPQUVHO0lBQ0ksS0FBSyxDQUFDLHlCQUF5QixDQUFDLFNBQStCO1FBQ3BFLE1BQU0sR0FBRyxHQUFjLEVBQUUsZUFBZSxFQUFFLEVBQUUsRUFBRSxXQUFXLEVBQUUsRUFBRSxFQUFFLENBQUM7UUFDaEUsTUFBTSxtQkFBbUIsR0FBRyxNQUFNLElBQUksQ0FBQyxtQkFBbUIsRUFBRSxDQUFDO1FBRTdELEtBQUssTUFBTSxRQUFRLElBQUksU0FBUyxFQUFFO1lBQ2hDLE1BQU0sVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLHdCQUF3QixDQUFDLG1CQUFtQixFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ3RGLElBQUksQ0FBQyxVQUFVLEVBQUU7Z0JBQ2YsU0FBUzthQUNWO1lBRUQsR0FBRyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkMsR0FBRyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEdBQUcsVUFBVSxDQUFDO1NBQ2xEO1FBRUQsT0FBTyxHQUFHLENBQUM7SUFDYixDQUFDO0lBRUQ7O09BRUc7SUFDSSxLQUFLLENBQUMsdUJBQXVCLENBQUMsU0FBK0IsRUFBRSxRQUFnQjtRQUNwRixNQUFNLFFBQVEsR0FBRyxNQUFNLEVBQUUsQ0FBQyxR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SUFDSixDQUFDO0lBRUQ7O09BRUc7SUFDSyxLQUFLLENBQUMscUJBQXFCLENBQUMsV0FBc0I7UUFDeEQsT0FBTyxXQUFXLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDN0MsaUJBQWlCLEVBQUUsR0FBRyxDQUFDLFNBQVM7WUFDaEMsWUFBWSxFQUFFLEdBQUcsQ0FBQyxZQUFZLENBQUMsZUFBZ0I7WUFDL0Msa0JBQWtCLEVBQUUsV0FBVyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDO1NBQzNELENBQUMsQ0FBQyxDQUFDO0lBQ04sQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ssZ0JBQWdCLENBQUMsU0FBaUI7O1FBQ3hDLHFDQUFPLElBQUksQ0FBQyxLQUFLLENBQUMsUUFBUSwwQ0FBRSxTQUFTLDBDQUFHLFNBQVMsMkNBQUcsUUFBUSwwQ0FBRyxjQUFjLG9DQUFLLFNBQVMsQ0FBQztJQUM5RixDQUFDO0NBQ0Y7QUF2UEQsNENBdVBDO0FBd0NELFNBQVMsT0FBTyxDQUFJLEVBQXFCO0lBQ3ZDLE9BQU8sTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7QUFDcEUsQ0FBQztBQUVEOztHQUVHO0FBQ0gsU0FBUyx3QkFBd0IsQ0FBQyxRQUFhO0lBQzdDLElBQUksUUFBUSxDQUFDLGNBQWMsRUFBRTtRQUFFLE9BQU8sUUFBUSxDQUFDO0tBQUU7SUFFakQsT0FBTztRQUNMLEdBQUcsUUFBUTtRQUNYLGNBQWMsRUFBRSxRQUFRO0tBQ3pCLENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY2ZuRGlmZiBmcm9tICdAYXdzLWNkay9jbG91ZGZvcm1hdGlvbi1kaWZmJztcbmltcG9ydCB7IFJlc291cmNlRGlmZmVyZW5jZSB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkZm9ybWF0aW9uLWRpZmYnO1xuaW1wb3J0ICogYXMgY3hhcGkgZnJvbSAnQGF3cy1jZGsvY3gtYXBpJztcbmltcG9ydCAqIGFzIGNoYWxrIGZyb20gJ2NoYWxrJztcbmltcG9ydCAqIGFzIGZzIGZyb20gJ2ZzLWV4dHJhJztcbmltcG9ydCAqIGFzIHByb21wdGx5IGZyb20gJ3Byb21wdGx5JztcbmltcG9ydCB7IENsb3VkRm9ybWF0aW9uRGVwbG95bWVudHMsIERlcGxveVN0YWNrT3B0aW9ucyB9IGZyb20gJy4vYXBpL2Nsb3VkZm9ybWF0aW9uLWRlcGxveW1lbnRzJztcbmltcG9ydCB7IFJlc291cmNlSWRlbnRpZmllclByb3BlcnRpZXMsIFJlc291cmNlc1RvSW1wb3J0IH0gZnJvbSAnLi9hcGkvdXRpbC9jbG91ZGZvcm1hdGlvbic7XG5pbXBvcnQgeyBlcnJvciwgcHJpbnQsIHN1Y2Nlc3MsIHdhcm5pbmcgfSBmcm9tICcuL2xvZ2dpbmcnO1xuXG4vKipcbiAqIFBhcmFtZXRlcnMgdGhhdCB1bmlxdWVseSBpZGVudGlmeSBhIHBoeXNpY2FsIHJlc291cmNlIG9mIGEgZ2l2ZW4gdHlwZVxuICogZm9yIHRoZSBpbXBvcnQgb3BlcmF0aW9uLCBleGFtcGxlOlxuICpcbiAqIGBgYFxuICoge1xuICogICBcIkFXUzo6UzM6OkJ1Y2tldFwiOiBbXCJCdWNrZXROYW1lXCJdLFxuICogICBcIkFXUzo6SUFNOjpSb2xlXCI6IFtcIlJvbGVOYW1lXCJdLFxuICogICBcIkFXUzo6RUMyOjpWUENcIjogW1wiVnBjSWRcIl1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgdHlwZSBSZXNvdXJjZUlkZW50aWZpZXJzID0geyBbcmVzb3VyY2VUeXBlOiBzdHJpbmddOiBzdHJpbmdbXSB9O1xuXG4vKipcbiAqIE1hcHBpbmcgb2YgQ0RLIHJlc291cmNlcyAoTDEgY29uc3RydWN0cykgdG8gcGh5c2ljYWwgcmVzb3VyY2VzIHRvIGJlIGltcG9ydGVkXG4gKiBpbiB0aGVpciBwbGFjZSwgZXhhbXBsZTpcbiAqXG4gKiBgYGBcbiAqIHtcbiAqICAgXCJNeVN0YWNrL015UzNCdWNrZXQvUmVzb3VyY2VcIjoge1xuICogICAgIFwiQnVja2V0TmFtZVwiOiBcIm15LW1hbnVhbGx5LWNyZWF0ZWQtczMtYnVja2V0XCJcbiAqICAgfSxcbiAqICAgXCJNeVN0YWNrL015VnBjL1Jlc291cmNlXCI6IHtcbiAqICAgICBcIlZwY0lkXCI6IFwidnBjLTEyMzQ1Njc4OVwiXG4gKiAgIH1cbiAqIH1cbiAqIGBgYFxuICovXG5leHBvcnQgdHlwZSBSZXNvdXJjZU1hcCA9IHsgW2xvZ2ljYWxSZXNvdXJjZTogc3RyaW5nXTogUmVzb3VyY2VJZGVudGlmaWVyUHJvcGVydGllcyB9O1xuXG5leHBvcnQgaW50ZXJmYWNlIFJlc291cmNlSW1wb3J0ZXJPcHRpb25zIHtcbiAgLyoqXG4gICAqIE5hbWUgb2YgdG9vbGtpdCBzdGFjayBpZiBub24tZGVmYXVsdFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIERlZmF1bHQgdG9vbGtpdCBzdGFjayBuYW1lXG4gICAqL1xuICByZWFkb25seSB0b29sa2l0U3RhY2tOYW1lPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFJlc291cmNlIGltcG9ydGluZyB1dGlsaXR5IGNsYXNzXG4gKlxuICogLSBEZXRlcm1pbmVzIHRoZSByZXNvdXJjZXMgYWRkZWQgdG8gYSB0ZW1wbGF0ZSAoY29tcGFyZWQgdG8gdGhlIGRlcGxveWVkIHZlcnNpb24pXG4gKiAtIExvb2sgdXAgdGhlIGlkZW50aWZpY2F0aW9uIGluZm9ybWF0aW9uXG4gKiAgIC0gTG9hZCB0aGVtIGZyb20gYSBmaWxlLCBvclxuICogICAtIEFzayB0aGUgdXNlciwgYmFzZWQgb24gaW5mb3JtYXRpb24gc3VwcGxpZWQgdG8gdXMgYnkgQ2xvdWRGb3JtYXRpb24ncyBHZXRUZW1wbGF0ZVN1bW1hcnlcbiAqIC0gVHJhbnNsYXRlIHRoZSBpbnB1dCB0byBhIHN0cnVjdHVyZSBleHBlY3RlZCBieSBDbG91ZEZvcm1hdGlvbiwgdXBkYXRlIHRoZSB0ZW1wbGF0ZSB0byBhZGQgdGhlXG4gKiAgIGltcG9ydGFibGUgcmVzb3VyY2VzLCB0aGVuIHJ1biBhbiBJTVBPUlQgY2hhbmdlc2V0LlxuICovXG5leHBvcnQgY2xhc3MgUmVzb3VyY2VJbXBvcnRlciB7XG4gIHByaXZhdGUgX2N1cnJlbnRUZW1wbGF0ZTogYW55O1xuXG4gIGNvbnN0cnVjdG9yKFxuICAgIHByaXZhdGUgcmVhZG9ubHkgc3RhY2s6IGN4YXBpLkNsb3VkRm9ybWF0aW9uU3RhY2tBcnRpZmFjdCxcbiAgICBwcml2YXRlIHJlYWRvbmx5IGNmbjogQ2xvdWRGb3JtYXRpb25EZXBsb3ltZW50cyxcbiAgICBwcml2YXRlIHJlYWRvbmx5IG9wdGlvbnM6IFJlc291cmNlSW1wb3J0ZXJPcHRpb25zID0ge30pIHsgfVxuXG4gIC8qKlxuICAgKiBBc2sgdGhlIHVzZXIgZm9yIHJlc291cmNlcyB0byBpbXBvcnRcbiAgICovXG4gIHB1YmxpYyBhc3luYyBhc2tGb3JSZXNvdXJjZUlkZW50aWZpZXJzKGF2YWlsYWJsZTogSW1wb3J0YWJsZVJlc291cmNlW10pOiBQcm9taXNlPEltcG9ydE1hcD4ge1xuICAgIGNvbnN0IHJldDogSW1wb3J0TWFwID0geyBpbXBvcnRSZXNvdXJjZXM6IFtdLCByZXNvdXJjZU1hcDoge30gfTtcbiAgICBjb25zdCByZXNvdXJjZUlkZW50aWZpZXJzID0gYXdhaXQgdGhpcy5yZXNvdXJjZUlkZW50aWZpZXJzKCk7XG5cbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGF2YWlsYWJsZSkge1xuICAgICAgY29uc3QgaWRlbnRpZmllciA9IGF3YWl0IHRoaXMuYXNrRm9yUmVzb3VyY2VJZGVudGlmaWVyKHJlc291cmNlSWRlbnRpZmllcnMsIHJlc291cmNlKTtcbiAgICAgIGlmICghaWRlbnRpZmllcikge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgcmV0LmltcG9ydFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcbiAgICAgIHJldC5yZXNvdXJjZU1hcFtyZXNvdXJjZS5sb2dpY2FsSWRdID0gaWRlbnRpZmllcjtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIExvYWQgdGhlIHJlc291cmNlcyB0byBpbXBvcnQgZnJvbSBhIGZpbGVcbiAgICovXG4gIHB1YmxpYyBhc3luYyBsb2FkUmVzb3VyY2VJZGVudGlmaWVycyhhdmFpbGFibGU6IEltcG9ydGFibGVSZXNvdXJjZVtdLCBmaWxlbmFtZTogc3RyaW5nKTogUHJvbWlzZTxJbXBvcnRNYXA+IHtcbiAgICBjb25zdCBjb250ZW50cyA9IGF3YWl0IGZzLnJlYWRKc29uKGZpbGVuYW1lKTtcblxuICAgIGNvbnN0IHJldDogSW1wb3J0TWFwID0geyBpbXBvcnRSZXNvdXJjZXM6IFtdLCByZXNvdXJjZU1hcDoge30gfTtcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGF2YWlsYWJsZSkge1xuICAgICAgY29uc3QgZGVzY3IgPSB0aGlzLmRlc2NyaWJlUmVzb3VyY2UocmVzb3VyY2UubG9naWNhbElkKTtcbiAgICAgIGNvbnN0IGlkUHJvcHMgPSBjb250ZW50c1tyZXNvdXJjZS5sb2dpY2FsSWRdO1xuICAgICAgaWYgKGlkUHJvcHMpIHtcbiAgICAgICAgcHJpbnQoJyVzOiBpbXBvcnRpbmcgdXNpbmcgJXMnLCBjaGFsay5ibHVlKGRlc2NyKSwgY2hhbGsuYmx1ZShmbXRkaWN0KGlkUHJvcHMpKSk7XG5cbiAgICAgICAgcmV0LmltcG9ydFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcbiAgICAgICAgcmV0LnJlc291cmNlTWFwW3Jlc291cmNlLmxvZ2ljYWxJZF0gPSBpZFByb3BzO1xuICAgICAgICBkZWxldGUgY29udGVudHNbcmVzb3VyY2UubG9naWNhbElkXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHByaW50KCclczogc2tpcHBpbmcnLCBjaGFsay5ibHVlKGRlc2NyKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgdW5rbm93biA9IE9iamVjdC5rZXlzKGNvbnRlbnRzKTtcbiAgICBpZiAodW5rbm93bi5sZW5ndGggPiAwKSB7XG4gICAgICB3YXJuaW5nKGBVbnJlY29nbml6ZWQgcmVzb3VyY2UgaWRlbnRpZmllcnMgaW4gbWFwcGluZyBmaWxlOiAke3Vua25vd24uam9pbignLCAnKX1gKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLyoqXG4gICAqIEJhc2VkIG9uIHRoZSBwcm92aWRlZCByZXNvdXJjZSBtYXBwaW5nLCBwcmVwYXJlIENGTiBzdHJ1Y3R1cmVzIGZvciBpbXBvcnQgKHRlbXBsYXRlLFxuICAgKiBSZXNvdXJjZXNUb0ltcG9ydCBzdHJ1Y3R1cmUpIGFuZCBwZXJmb3JtIHRoZSBpbXBvcnQgb3BlcmF0aW9uIChDbG91ZEZvcm1hdGlvbiBkZXBsb3ltZW50KVxuICAgKlxuICAgKiBAcGFyYW0gcmVzb3VyY2VNYXAgTWFwcGluZyBmcm9tIENESyBjb25zdHJ1Y3QgdHJlZSBwYXRoIHRvIHBoeXNpY2FsIHJlc291cmNlIGltcG9ydCBpZGVudGlmaWVyc1xuICAgKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zIHRvIHBhc3MgdG8gQ2xvdWRGb3JtYXRpb24gZGVwbG95IG9wZXJhdGlvblxuICAgKi9cbiAgcHVibGljIGFzeW5jIGltcG9ydFJlc291cmNlcyhpbXBvcnRNYXA6IEltcG9ydE1hcCwgb3B0aW9uczogRGVwbG95U3RhY2tPcHRpb25zKSB7XG4gICAgY29uc3QgcmVzb3VyY2VzVG9JbXBvcnQ6IFJlc291cmNlc1RvSW1wb3J0ID0gYXdhaXQgdGhpcy5tYWtlUmVzb3VyY2VzVG9JbXBvcnQoaW1wb3J0TWFwKTtcbiAgICBjb25zdCB1cGRhdGVkVGVtcGxhdGUgPSBhd2FpdCB0aGlzLmN1cnJlbnRUZW1wbGF0ZVdpdGhBZGRpdGlvbnMoaW1wb3J0TWFwLmltcG9ydFJlc291cmNlcyk7XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5jZm4uZGVwbG95U3RhY2soe1xuICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICBvdmVycmlkZVRlbXBsYXRlOiB1cGRhdGVkVGVtcGxhdGUsXG4gICAgICAgIHJlc291cmNlc1RvSW1wb3J0LFxuICAgICAgfSk7XG5cbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSByZXN1bHQubm9PcFxuICAgICAgICA/ICcg4pyFICAlcyAobm8gY2hhbmdlcyknXG4gICAgICAgIDogJyDinIUgICVzJztcblxuICAgICAgc3VjY2VzcygnXFxuJyArIG1lc3NhZ2UsIG9wdGlvbnMuc3RhY2suZGlzcGxheU5hbWUpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIGVycm9yKCdcXG4g4p2MICAlcyBmYWlsZWQ6ICVzJywgY2hhbGsuYm9sZChvcHRpb25zLnN0YWNrLmRpc3BsYXlOYW1lKSwgZSk7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQZXJmb3JtIGEgZGlmZiBiZXR3ZWVuIHRoZSBjdXJyZW50bHkgcnVubmluZyBhbmQgdGhlIG5ldyB0ZW1wbGF0ZSwgZW51c3JlIHRoYXQgaXQgaXMgdmFsaWRcbiAgICogZm9yIGltcG9ydGluZyBhbmQgcmV0dXJuIGEgbGlzdCBvZiByZXNvdXJjZXMgdGhhdCBhcmUgYmVpbmcgYWRkZWQgaW4gdGhlIG5ldyB2ZXJzaW9uXG4gICAqXG4gICAqIEByZXR1cm4gbWFwcGluZyBsb2dpY2FsUmVzb3VyY2VJZCAtPiByZXNvdXJjZURpZmZlcmVuY2VcbiAgICovXG4gIHB1YmxpYyBhc3luYyBkaXNjb3ZlckltcG9ydGFibGVSZXNvdXJjZXMoYWxsb3dOb25BZGRpdGlvbnMgPSBmYWxzZSk6IFByb21pc2U8RGlzY292ZXJJbXBvcnRhYmxlUmVzb3VyY2VzUmVzdWx0PiB7XG4gICAgY29uc3QgY3VycmVudFRlbXBsYXRlID0gYXdhaXQgdGhpcy5jdXJyZW50VGVtcGxhdGUoKTtcblxuICAgIGNvbnN0IGRpZmYgPSBjZm5EaWZmLmRpZmZUZW1wbGF0ZShjdXJyZW50VGVtcGxhdGUsIHRoaXMuc3RhY2sudGVtcGxhdGUpO1xuXG4gICAgLy8gSWdub3JlIGNoYW5nZXMgdG8gQ0RLTWV0YWRhdGFcbiAgICBjb25zdCByZXNvdXJjZUNoYW5nZXMgPSBPYmplY3QuZW50cmllcyhkaWZmLnJlc291cmNlcy5jaGFuZ2VzKVxuICAgICAgLmZpbHRlcigoW2xvZ2ljYWxJZCwgX10pID0+IGxvZ2ljYWxJZCAhPT0gJ0NES01ldGFkYXRhJyk7XG5cbiAgICAvLyBTcGxpdCB0aGUgY2hhbmdlcyBpbnRvIGFkZGl0aW9ucyBhbmQgbm9uLWFkZGl0aW9ucy4gSW1wb3J0cyBvbmx5IG1ha2Ugc2Vuc2VcbiAgICAvLyBmb3IgbmV3bHktYWRkZWQgcmVzb3VyY2VzLlxuICAgIGNvbnN0IG5vbkFkZGl0aW9ucyA9IHJlc291cmNlQ2hhbmdlcy5maWx0ZXIoKFtfLCBkaWZdKSA9PiAhZGlmLmlzQWRkaXRpb24pO1xuICAgIGNvbnN0IGFkZGl0aW9ucyA9IHJlc291cmNlQ2hhbmdlcy5maWx0ZXIoKFtfLCBkaWZdKSA9PiBkaWYuaXNBZGRpdGlvbik7XG5cbiAgICBpZiAobm9uQWRkaXRpb25zLmxlbmd0aCkge1xuICAgICAgY29uc3Qgb2ZmZW5kaW5nUmVzb3VyY2VzID0gbm9uQWRkaXRpb25zLm1hcCgoW2xvZ0lkLCBfXSkgPT4gdGhpcy5kZXNjcmliZVJlc291cmNlKGxvZ0lkKSk7XG5cbiAgICAgIGlmIChhbGxvd05vbkFkZGl0aW9ucykge1xuICAgICAgICB3YXJuaW5nKGBJZ25vcmluZyB1cGRhdGVkL2RlbGV0ZWQgcmVzb3VyY2VzICgtLWZvcmNlKTogJHtvZmZlbmRpbmdSZXNvdXJjZXMuam9pbignLCAnKX1gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignTm8gcmVzb3VyY2UgdXBkYXRlcyBvciBkZWxldGVzIGFyZSBhbGxvd2VkIG9uIGltcG9ydCBvcGVyYXRpb24uIE1ha2Ugc3VyZSB0byByZXNvbHZlIHBlbmRpbmcgY2hhbmdlcyAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgIGB0byBleGlzdGluZyByZXNvdXJjZXMsIGJlZm9yZSBhdHRlbXB0aW5nIGFuIGltcG9ydC4gVXBkYXRlZC9kZWxldGVkIHJlc291cmNlczogJHtvZmZlbmRpbmdSZXNvdXJjZXMuam9pbignLCAnKX0gKC0tZm9yY2UgdG8gb3ZlcnJpZGUpYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVzb3VyY2VzIGluIHRoZSBuZXcgdGVtcGxhdGUsIHRoYXQgYXJlIG5vdCBwcmVzZW50IGluIHRoZSBjdXJyZW50IHRlbXBsYXRlLCBhcmUgYSBwb3RlbnRpYWwgaW1wb3J0IGNhbmRpZGF0ZXNcbiAgICByZXR1cm4ge1xuICAgICAgYWRkaXRpb25zOiBhZGRpdGlvbnMubWFwKChbbG9naWNhbElkLCByZXNvdXJjZURpZmZdKSA9PiAoe1xuICAgICAgICBsb2dpY2FsSWQsXG4gICAgICAgIHJlc291cmNlRGlmZixcbiAgICAgICAgcmVzb3VyY2VEZWZpbml0aW9uOiBhZGREZWZhdWx0RGVsZXRpb25Qb2xpY3kodGhpcy5zdGFjay50ZW1wbGF0ZT8uUmVzb3VyY2VzPy5bbG9naWNhbElkXSA/PyB7fSksXG4gICAgICB9KSksXG4gICAgICBoYXNOb25BZGRpdGlvbnM6IG5vbkFkZGl0aW9ucy5sZW5ndGggPiAwLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogR2V0IGN1cnJlbnRseSBkZXBsb3llZCB0ZW1wbGF0ZSBvZiB0aGUgZ2l2ZW4gc3RhY2sgKFNJTkdMRVRPTilcbiAgICpcbiAgICogQHJldHVybnMgQ3VycmVudGx5IGRlcGxveWVkIENsb3VkRm9ybWF0aW9uIHRlbXBsYXRlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGN1cnJlbnRUZW1wbGF0ZSgpOiBQcm9taXNlPGFueT4ge1xuICAgIGlmICghdGhpcy5fY3VycmVudFRlbXBsYXRlKSB7XG4gICAgICB0aGlzLl9jdXJyZW50VGVtcGxhdGUgPSBhd2FpdCB0aGlzLmNmbi5yZWFkQ3VycmVudFRlbXBsYXRlKHRoaXMuc3RhY2spO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5fY3VycmVudFRlbXBsYXRlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0ZWggY3VycmVudCB0ZW1wbGF0ZSwgd2l0aCB0aGUgZ2l2ZW4gcmVzb3VyY2VzIGFkZGVkIHRvIGl0XG4gICAqL1xuICBwcml2YXRlIGFzeW5jIGN1cnJlbnRUZW1wbGF0ZVdpdGhBZGRpdGlvbnMoYWRkaXRpb25zOiBJbXBvcnRhYmxlUmVzb3VyY2VbXSk6IFByb21pc2U8YW55PiB7XG4gICAgY29uc3QgdGVtcGxhdGUgPSBhd2FpdCB0aGlzLmN1cnJlbnRUZW1wbGF0ZSgpO1xuICAgIGlmICghdGVtcGxhdGUuUmVzb3VyY2VzKSB7XG4gICAgICB0ZW1wbGF0ZS5SZXNvdXJjZXMgPSB7fTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGFkZCBvZiBhZGRpdGlvbnMpIHtcbiAgICAgIHRlbXBsYXRlLlJlc291cmNlc1thZGQubG9naWNhbElkXSA9IGFkZC5yZXNvdXJjZURlZmluaXRpb247XG4gICAgfVxuXG4gICAgcmV0dXJuIHRlbXBsYXRlO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCBhIGxpc3Qgb2YgaW1wb3J0IGlkZW50aWZpZXJzIGZvciBhbGwgcmVzb3VyY2UgdHlwZXMgdXNlZCBpbiB0aGUgZ2l2ZW5cbiAgICogdGVtcGxhdGUgdGhhdCBkbyBzdXBwb3J0IHRoZSBpbXBvcnQgb3BlcmF0aW9uIChTSU5HTEVUT04pXG4gICAqXG4gICAqIEByZXR1cm5zIGEgbWFwcGluZyBmcm9tIGEgcmVzb3VyY2UgdHlwZSB0byBhIGxpc3Qgb2YgcHJvcGVydHkgbmFtZXMgdGhhdCB0b2dldGhlciBpZGVudGlmeSB0aGUgcmVzb3VyY2UgZm9yIGltcG9ydFxuICAgKi9cbiAgcHJpdmF0ZSBhc3luYyByZXNvdXJjZUlkZW50aWZpZXJzKCk6IFByb21pc2U8UmVzb3VyY2VJZGVudGlmaWVycz4ge1xuICAgIGNvbnN0IHJldDogUmVzb3VyY2VJZGVudGlmaWVycyA9IHt9O1xuICAgIGNvbnN0IHJlc291cmNlSWRlbnRpZmllclN1bW1hcmllcyA9IGF3YWl0IHRoaXMuY2ZuLnJlc291cmNlSWRlbnRpZmllclN1bW1hcmllcyh0aGlzLnN0YWNrLCB0aGlzLm9wdGlvbnMudG9vbGtpdFN0YWNrTmFtZSk7XG4gICAgZm9yIChjb25zdCBzdW1tYXJ5IG9mIHJlc291cmNlSWRlbnRpZmllclN1bW1hcmllcykge1xuICAgICAgaWYgKCdSZXNvdXJjZVR5cGUnIGluIHN1bW1hcnkgJiYgc3VtbWFyeS5SZXNvdXJjZVR5cGUgJiYgJ1Jlc291cmNlSWRlbnRpZmllcnMnIGluIHN1bW1hcnkgJiYgc3VtbWFyeS5SZXNvdXJjZUlkZW50aWZpZXJzKSB7XG4gICAgICAgIHJldFtzdW1tYXJ5LlJlc291cmNlVHlwZV0gPSBzdW1tYXJ5LlJlc291cmNlSWRlbnRpZmllcnM7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiByZXQ7XG4gIH1cblxuICBwcml2YXRlIGFzeW5jIGFza0ZvclJlc291cmNlSWRlbnRpZmllcihcbiAgICByZXNvdXJjZUlkZW50aWZpZXJzOiBSZXNvdXJjZUlkZW50aWZpZXJzLFxuICAgIGNoZzogSW1wb3J0YWJsZVJlc291cmNlLFxuICApOiBQcm9taXNlPFJlc291cmNlSWRlbnRpZmllclByb3BlcnRpZXMgfCB1bmRlZmluZWQ+IHtcbiAgICBjb25zdCByZXNvdXJjZU5hbWUgPSB0aGlzLmRlc2NyaWJlUmVzb3VyY2UoY2hnLmxvZ2ljYWxJZCk7XG5cbiAgICAvLyBTa2lwIHJlc291cmNlcyB0aGF0IGRvIG5vdCBzdXBwb3J0IGltcG9ydGluZ1xuICAgIGNvbnN0IHJlc291cmNlVHlwZSA9IGNoZy5yZXNvdXJjZURpZmYubmV3UmVzb3VyY2VUeXBlO1xuICAgIGlmIChyZXNvdXJjZVR5cGUgPT09IHVuZGVmaW5lZCB8fCAhKHJlc291cmNlVHlwZSBpbiByZXNvdXJjZUlkZW50aWZpZXJzKSkge1xuICAgICAgd2FybmluZyhgJHtyZXNvdXJjZU5hbWV9OiB1bnN1cHBvcnRlZCByZXNvdXJjZSB0eXBlICR7cmVzb3VyY2VUeXBlfSwgc2tpcHBpbmcgaW1wb3J0LmApO1xuICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG5cbiAgICBjb25zdCBpZFByb3BzID0gcmVzb3VyY2VJZGVudGlmaWVyc1tyZXNvdXJjZVR5cGVdO1xuICAgIGNvbnN0IHJlc291cmNlUHJvcHMgPSBjaGcucmVzb3VyY2VEZWZpbml0aW9uLlByb3BlcnRpZXMgPz8ge307XG5cbiAgICBjb25zdCBmaXhlZElkUHJvcHMgPSBpZFByb3BzLmZpbHRlcihwID0+IHJlc291cmNlUHJvcHNbcF0pO1xuICAgIGNvbnN0IGZpeGVkSWRJbnB1dDogUmVzb3VyY2VJZGVudGlmaWVyUHJvcGVydGllcyA9IE9iamVjdC5mcm9tRW50cmllcyhmaXhlZElkUHJvcHMubWFwKHAgPT4gW3AsIHJlc291cmNlUHJvcHNbcF1dKSk7XG5cbiAgICBjb25zdCBtaXNzaW5nSWRQcm9wcyA9IGlkUHJvcHMuZmlsdGVyKHAgPT4gIXJlc291cmNlUHJvcHNbcF0pO1xuXG4gICAgaWYgKG1pc3NpbmdJZFByb3BzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgLy8gV2UgY2FuIGF1dG8taW1wb3J0IHRoaXMsIGJ1dCBhc2sgdGhlIHVzZXIgdG8gY29uZmlybVxuICAgICAgY29uc3QgcHJvcHMgPSBmbXRkaWN0KGZpeGVkSWRJbnB1dCk7XG5cbiAgICAgIGlmICghYXdhaXQgcHJvbXB0bHkuY29uZmlybShcbiAgICAgICAgYCR7Y2hhbGsuYmx1ZShyZXNvdXJjZU5hbWUpfSAoJHtyZXNvdXJjZVR5cGV9KTogaW1wb3J0IHdpdGggJHtjaGFsay55ZWxsb3cocHJvcHMpfSAoeWVzL25vKSBbZGVmYXVsdDogeWVzXT8gYCxcbiAgICAgICAgeyBkZWZhdWx0OiAneWVzJyB9LFxuICAgICAgKSkge1xuICAgICAgICBwcmludChjaGFsay5ncmV5KGBTa2lwcGluZyBpbXBvcnQgb2YgJHtyZXNvdXJjZU5hbWV9YCkpO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFzayB0aGUgdXNlciB0byBwcm92aWRlIG1pc3NpbmcgcHJvcHNcbiAgICBjb25zdCB1c2VySW5wdXQ6IFJlc291cmNlSWRlbnRpZmllclByb3BlcnRpZXMgPSB7fTtcbiAgICBmb3IgKGNvbnN0IG1pc3NpbmdJZFByb3Agb2YgbWlzc2luZ0lkUHJvcHMpIHtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gKGF3YWl0IHByb21wdGx5LnByb21wdChcbiAgICAgICAgYCR7Y2hhbGsuYmx1ZShyZXNvdXJjZU5hbWUpfSAoJHtyZXNvdXJjZVR5cGV9KTogZW50ZXIgJHtjaGFsay5ibHVlKG1pc3NpbmdJZFByb3ApfSB0byBpbXBvcnQgKGVtcHR5IHRvIHNraXApOmAsXG4gICAgICAgIHsgZGVmYXVsdDogJycsIHRyaW06IHRydWUgfSxcbiAgICAgICkpO1xuICAgICAgaWYgKCFyZXNwb25zZSkge1xuICAgICAgICBwcmludChjaGFsay5ncmV5KGBTa2lwcGluZyBpbXBvcnQgb2YgJHtyZXNvdXJjZU5hbWV9YCkpO1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgfVxuICAgICAgdXNlcklucHV0W21pc3NpbmdJZFByb3BdID0gcmVzcG9uc2U7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIC4uLmZpeGVkSWRJbnB1dCxcbiAgICAgIC4uLnVzZXJJbnB1dCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgdGhlIGludGVybmFsIFwicmVzb3VyY2UgbWFwcGluZ1wiIHN0cnVjdHVyZSB0byBDbG91ZEZvcm1hdGlvbiBhY2NlcHRlZCBcIlJlc291cmNlc1RvSW1wb3J0XCIgc3RydWN0dXJlXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIG1ha2VSZXNvdXJjZXNUb0ltcG9ydChyZXNvdXJjZU1hcDogSW1wb3J0TWFwKTogUHJvbWlzZTxSZXNvdXJjZXNUb0ltcG9ydD4ge1xuICAgIHJldHVybiByZXNvdXJjZU1hcC5pbXBvcnRSZXNvdXJjZXMubWFwKHJlcyA9PiAoe1xuICAgICAgTG9naWNhbFJlc291cmNlSWQ6IHJlcy5sb2dpY2FsSWQsXG4gICAgICBSZXNvdXJjZVR5cGU6IHJlcy5yZXNvdXJjZURpZmYubmV3UmVzb3VyY2VUeXBlISxcbiAgICAgIFJlc291cmNlSWRlbnRpZmllcjogcmVzb3VyY2VNYXAucmVzb3VyY2VNYXBbcmVzLmxvZ2ljYWxJZF0sXG4gICAgfSkpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZlcnQgQ2xvdWRGb3JtYXRpb24gbG9naWNhbCByZXNvdXJjZSBJRCB0byBDREsgY29uc3RydWN0IHRyZWUgcGF0aFxuICAgKlxuICAgKiBAcGFyYW0gbG9naWNhbElkIENsb3VkRm9ybWF0aW9uIGxvZ2ljYWwgSUQgb2YgdGhlIHJlc291cmNlICh0aGUga2V5IGluIHRoZSB0ZW1wbGF0ZSdzIFJlc291cmNlcyBzZWN0aW9uKVxuICAgKiBAcmV0dXJucyBGb3J3YXJkLXNsYXNoIHNlcGFyYXRlZCBwYXRoIG9mIHRoZSByZXNvdXJjZSBpbiBDREsgY29uc3RydWN0IHRyZWUsIGUuZy4gTXlTdGFjay9NeUJ1Y2tldC9SZXNvdXJjZVxuICAgKi9cbiAgcHJpdmF0ZSBkZXNjcmliZVJlc291cmNlKGxvZ2ljYWxJZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gdGhpcy5zdGFjay50ZW1wbGF0ZT8uUmVzb3VyY2VzPy5bbG9naWNhbElkXT8uTWV0YWRhdGE/LlsnYXdzOmNkazpwYXRoJ10gPz8gbG9naWNhbElkO1xuICB9XG59XG5cbi8qKlxuICogSW5mb3JtYXRpb24gYWJvdXQgYSByZXNvdXJjZSBpbiB0aGUgdGVtcGxhdGUgdGhhdCBpcyBpbXBvcnRhYmxlXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSW1wb3J0YWJsZVJlc291cmNlIHtcbiAgLyoqXG4gICAqIFRoZSBsb2dpY2FsIElEIG9mIHRoZSByZXNvdXJjZVxuICAgKi9cbiAgcmVhZG9ubHkgbG9naWNhbElkOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSByZXNvdXJjZSBkZWZpbml0aW9uIGluIHRoZSBuZXcgdGVtcGxhdGVcbiAgICovXG4gIHJlYWRvbmx5IHJlc291cmNlRGVmaW5pdGlvbjogYW55O1xuXG4gIC8qKlxuICAgKiBUaGUgZGlmZiBhcyByZXBvcnRlZCBieSBgY2xvdWRmb3JtYXRpb24tZGlmZmAuXG4gICAqL1xuICByZWFkb25seSByZXNvdXJjZURpZmY6IFJlc291cmNlRGlmZmVyZW5jZTtcbn1cblxuLyoqXG4gKiBUaGUgaW5mb3JtYXRpb24gbmVjZXNzYXJ5IHRvIGV4ZWN1dGUgYW4gaW1wb3J0IG9wZXJhdGlvblxuICovXG5leHBvcnQgaW50ZXJmYWNlIEltcG9ydE1hcCB7XG4gIC8qKlxuICAgKiBNYXBwaW5nIGxvZ2ljYWwgSURzIHRvIHBoeXNpY2FsIG5hbWVzXG4gICAqL1xuICByZWFkb25seSByZXNvdXJjZU1hcDogUmVzb3VyY2VNYXA7XG5cbiAgLyoqXG4gICAqIFRoZSBzZWxlY3Rpb24gb2YgcmVzb3VyY2VzIHdlIGFyZSBhY3R1YWxseSBpbXBvcnRpbmdcbiAgICpcbiAgICogRm9yIGVhY2ggb2YgdGhlIHJlc291cmNlcyBpbiB0aGlzIGxpc3QsIHRoZXJlIGlzIGEgY29ycmVzcG9uZGluZyBlbnRyeSBpblxuICAgKiB0aGUgYHJlc291cmNlTWFwYCBtYXAuXG4gICAqL1xuICByZWFkb25seSBpbXBvcnRSZXNvdXJjZXM6IEltcG9ydGFibGVSZXNvdXJjZVtdO1xufVxuXG5mdW5jdGlvbiBmbXRkaWN0PEE+KHhzOiBSZWNvcmQ8c3RyaW5nLCBBPikge1xuICByZXR1cm4gT2JqZWN0LmVudHJpZXMoeHMpLm1hcCgoW2ssIHZdKSA9PiBgJHtrfT0ke3Z9YCkuam9pbignLCAnKTtcbn1cblxuLyoqXG4gKiBBZGQgYSBkZWZhdWx0ICdEZWxldGUnIHBvbGljeSwgd2hpY2ggaXMgcmVxdWlyZWQgdG8gbWFrZSB0aGUgaW1wb3J0IHN1Y2NlZWRcbiAqL1xuZnVuY3Rpb24gYWRkRGVmYXVsdERlbGV0aW9uUG9saWN5KHJlc291cmNlOiBhbnkpOiBhbnkge1xuICBpZiAocmVzb3VyY2UuRGVsZXRpb25Qb2xpY3kpIHsgcmV0dXJuIHJlc291cmNlOyB9XG5cbiAgcmV0dXJuIHtcbiAgICAuLi5yZXNvdXJjZSxcbiAgICBEZWxldGlvblBvbGljeTogJ0RlbGV0ZScsXG4gIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGlzY292ZXJJbXBvcnRhYmxlUmVzb3VyY2VzUmVzdWx0IHtcbiAgcmVhZG9ubHkgYWRkaXRpb25zOiBJbXBvcnRhYmxlUmVzb3VyY2VbXTtcbiAgcmVhZG9ubHkgaGFzTm9uQWRkaXRpb25zOiBib29sZWFuO1xufSJdfQ==