UNPKG

@aws-cdk/cloudformation-diff

Version:

Utilities to diff CDK stacks against CloudFormation templates

122 lines 21.4 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.TemplateAndChangeSetDiffMerger = void 0; const types = require("../diff/types"); /** * The purpose of this class is to include differences from the ChangeSet to differences in the TemplateDiff. */ class TemplateAndChangeSetDiffMerger { static determineChangeSetReplacementMode(propertyChange) { if (propertyChange.Target?.RequiresRecreation === undefined) { // We can't determine if the resource will be replaced or not. That's what conditionally means. return 'Conditionally'; } if (propertyChange.Target.RequiresRecreation === 'Always') { switch (propertyChange.Evaluation) { case 'Static': return 'Always'; case 'Dynamic': // If Evaluation is 'Dynamic', then this may cause replacement, or it may not. // see 'Replacement': https://docs.aws.amazon.com/AWSCloudFormation/latest/APIReference/API_ResourceChange.html return 'Conditionally'; } } return propertyChange.Target.RequiresRecreation; } constructor(props) { this.changeSet = props.changeSet; this.changeSetResources = props.changeSetResources ?? this.convertDescribeChangeSetOutputToChangeSetResources(this.changeSet); } /** * Read resources from the changeSet, extracting information into ChangeSetResources. */ convertDescribeChangeSetOutputToChangeSetResources(changeSet) { const changeSetResources = {}; for (const resourceChange of changeSet.Changes ?? []) { if (resourceChange.ResourceChange?.LogicalResourceId === undefined) { continue; // Being defensive, here. } const propertyReplacementModes = {}; for (const propertyChange of resourceChange.ResourceChange.Details ?? []) { // Details is only included if resourceChange.Action === 'Modify' if (propertyChange.Target?.Attribute === 'Properties' && propertyChange.Target.Name) { propertyReplacementModes[propertyChange.Target.Name] = { replacementMode: TemplateAndChangeSetDiffMerger.determineChangeSetReplacementMode(propertyChange), }; } } changeSetResources[resourceChange.ResourceChange.LogicalResourceId] = { resourceWasReplaced: resourceChange.ResourceChange.Replacement === 'True', resourceType: resourceChange.ResourceChange.ResourceType ?? TemplateAndChangeSetDiffMerger.UNKNOWN_RESOURCE_TYPE, // DescribeChangeSet doesn't promise to have the ResourceType... propertyReplacementModes: propertyReplacementModes, }; } return changeSetResources; } /** * This is writing over the "ChangeImpact" that was computed from the template difference, and instead using the ChangeImpact that is included from the ChangeSet. * Using the ChangeSet ChangeImpact is more accurate. The ChangeImpact tells us what the consequence is of changing the field. If changing the field causes resource * replacement (e.g., changing the name of an IAM role requires deleting and replacing the role), then ChangeImpact is "Always". */ overrideDiffResourceChangeImpactWithChangeSetChangeImpact(logicalId, change) { // resourceType getter throws an error if resourceTypeChanged if ((change.resourceTypeChanged === true) || change.resourceType?.includes('AWS::Serverless')) { // CFN applies the SAM transform before creating the changeset, so the changeset contains no information about SAM resources return; } change.forEachDifference((type, name, value) => { if (type === 'Property') { if (!this.changeSetResources[logicalId]) { value.changeImpact = types.ResourceImpact.NO_CHANGE; value.isDifferent = false; return; } const changingPropertyCausesResourceReplacement = (this.changeSetResources[logicalId].propertyReplacementModes ?? {})[name]?.replacementMode; switch (changingPropertyCausesResourceReplacement) { case 'Always': value.changeImpact = types.ResourceImpact.WILL_REPLACE; break; case 'Never': value.changeImpact = types.ResourceImpact.WILL_UPDATE; break; case 'Conditionally': value.changeImpact = types.ResourceImpact.MAY_REPLACE; break; case undefined: value.changeImpact = types.ResourceImpact.NO_CHANGE; value.isDifferent = false; break; // otherwise, defer to the changeImpact from the template diff } } else if (type === 'Other') { switch (name) { case 'Metadata': // we want to ignore metadata changes in the diff, so compare newValue against newValue. change.setOtherChange('Metadata', new types.Difference(value.newValue, value.newValue)); break; } } }); } addImportInformationFromChangeset(resourceDiffs) { const imports = this.findResourceImports(); resourceDiffs.forEachDifference((logicalId, change) => { if (imports.includes(logicalId)) { change.isImport = true; } }); } findResourceImports() { const importedResourceLogicalIds = []; for (const resourceChange of this.changeSet?.Changes ?? []) { if (resourceChange.ResourceChange?.Action === 'Import') { importedResourceLogicalIds.push(resourceChange.ResourceChange.LogicalResourceId); } } return importedResourceLogicalIds; } } exports.TemplateAndChangeSetDiffMerger = TemplateAndChangeSetDiffMerger; // If we somehow cannot find the resourceType, then we'll mark it as UNKNOWN, so that can be seen in the diff. TemplateAndChangeSetDiffMerger.UNKNOWN_RESOURCE_TYPE = 'UNKNOWN_RESOURCE_TYPE'; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVtcGxhdGUtYW5kLWNoYW5nZXNldC1kaWZmLW1lcmdlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbInRlbXBsYXRlLWFuZC1jaGFuZ2VzZXQtZGlmZi1tZXJnZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBR0EsdUNBQXVDO0FBc0J2Qzs7R0FFRztBQUNILE1BQWEsOEJBQThCO0lBQ2xDLE1BQU0sQ0FBQyxpQ0FBaUMsQ0FBQyxjQUE2QztRQUMzRixJQUFJLGNBQWMsQ0FBQyxNQUFNLEVBQUUsa0JBQWtCLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDNUQsK0ZBQStGO1lBQy9GLE9BQU8sZUFBZSxDQUFDO1FBQ3pCLENBQUM7UUFFRCxJQUFJLGNBQWMsQ0FBQyxNQUFNLENBQUMsa0JBQWtCLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDMUQsUUFBUSxjQUFjLENBQUMsVUFBVSxFQUFFLENBQUM7Z0JBQ2xDLEtBQUssUUFBUTtvQkFDWCxPQUFPLFFBQVEsQ0FBQztnQkFDbEIsS0FBSyxTQUFTO29CQUNaLDhFQUE4RTtvQkFDOUUsK0dBQStHO29CQUMvRyxPQUFPLGVBQWUsQ0FBQztZQUMzQixDQUFDO1FBQ0gsQ0FBQztRQUVELE9BQU8sY0FBYyxDQUFDLE1BQU0sQ0FBQyxrQkFBNEMsQ0FBQztJQUM1RSxDQUFDO0lBUUQsWUFBWSxLQUEwQztRQUNwRCxJQUFJLENBQUMsU0FBUyxHQUFHLEtBQUssQ0FBQyxTQUFTLENBQUM7UUFDakMsSUFBSSxDQUFDLGtCQUFrQixHQUFHLEtBQUssQ0FBQyxrQkFBa0IsSUFBSSxJQUFJLENBQUMsa0RBQWtELENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ2hJLENBQUM7SUFFRDs7T0FFRztJQUNLLGtEQUFrRCxDQUFDLFNBQWtDO1FBQzNGLE1BQU0sa0JBQWtCLEdBQTZCLEVBQUUsQ0FBQztRQUN4RCxLQUFLLE1BQU0sY0FBYyxJQUFJLFNBQVMsQ0FBQyxPQUFPLElBQUksRUFBRSxFQUFFLENB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QUFFLENBQUM7b0JBQ2IsS0FBSyxVQUFVO3dCQUNiLHdGQUF3Rjt3QkFDeEYsTUFBTSxDQUFDLGNBQWMsQ0FBQyxVQUFVLEVBQUUsSUFBSSxLQUFLLENBQUMsVUFBVSxDQUFTLEtBQUssQ0FBQyxRQUFRLEVBQUUsS0FBSyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUM7d0JBQ2hHLE1BQU07Z0JBQ1YsQ0FBQztZQUNILENBQUM7UUFDSCxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxpQ0FBaUMsQ0FBQyxhQUFtRjtRQUMxSCxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsbUJBQW1CLEVBQUUsQ0FBQztRQUMzQyxhQUFhLENBQUMsaUJBQWlCLENBQUMsQ0FBQyxTQUFpQixFQUFFLE1BQWdDLEVBQUUsRUFBRTtZQUN0RixJQUFJLE9BQU8sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQztnQkFDaEMsTUFBTSxDQUFDLFFBQVEsR0FBRyxJQUFJLENBQUM7WUFDekIsQ0FBQztRQUNILENBQUMsQ0FBQyxDQUFDO0lBQ0wsQ0FBQztJQUVNLG1CQUFtQjtRQUN4QixNQUFNLDBCQUEwQixHQUFHLEVBQUUsQ0FBQztRQUN0QyxLQUFLLE1BQU0sY0FBYyxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsT0FBTyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQzNELElBQUksY0FBYyxDQUFDLGNBQWMsRUFBRSxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7Z0JBQ3ZELDBCQUEwQixDQUFDLElBQUksQ0FBQyxjQUFjLENBQUMsY0FBYyxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDbkYsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLDBCQUEwQixDQUFDO0lBQ3BDLENBQUM7O0FBOUhILHdFQStIQztBQTFHQyw4R0FBOEc7QUFDL0Ysb0RBQXFCLEdBQUcsdUJBQXVCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvLyBUaGUgU0RLIGlzIG9ubHkgdXNlZCB0byByZWZlcmVuY2UgYERlc2NyaWJlQ2hhbmdlU2V0T3V0cHV0YCwgc28gdGhlIFNESyBpcyBhZGRlZCBhcyBhIGRldkRlcGVuZGVuY3kuXG4vLyBUaGUgU0RLIHNob3VsZCBub3QgbWFrZSBuZXR3b3JrIGNhbGxzIGhlcmVcbmltcG9ydCB0eXBlIHsgRGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXQgYXMgRGVzY3JpYmVDaGFuZ2VTZXQsIFJlc291cmNlQ2hhbmdlRGV0YWlsIGFzIFJDRCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1jbG91ZGZvcm1hdGlvbic7XG5pbXBvcnQgKiBhcyB0eXBlcyBmcm9tICcuLi9kaWZmL3R5cGVzJztcblxuZXhwb3J0IHR5cGUgRGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXQgPSBEZXNjcmliZUNoYW5nZVNldDtcbnR5cGUgQ2hhbmdlU2V0UmVzb3VyY2VDaGFuZ2VEZXRhaWwgPSBSQ0Q7XG5cbmludGVyZmFjZSBUZW1wbGF0ZUFuZENoYW5nZVNldERpZmZNZXJnZXJPcHRpb25zIHtcbiAgLypcbiAgICogT25seSBzcGVjaWZpYWJsZSBmb3IgdGVzdGluZy4gT3RoZXJ3aXNlLCB0aGlzIGlzIHRoZSBkYXRhc3RydWN0dXJlIHRoYXQgdGhlIGNoYW5nZVNldCBpcyBjb252ZXJ0ZWQgaW50byBzb1xuICAgKiB0aGF0IHdlIG9ubHkgcGF5IGF0dGVudGlvbiB0byB0aGUgc3Vic2V0IG9mIGNoYW5nZVNldCBwcm9wZXJ0aWVzIHRoYXQgYXJlIHJlbGV2YW50IGZvciBjb21wdXRpbmcgdGhlIGRpZmYuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gdGhlIGNoYW5nZVNldCBpcyBjb252ZXJ0ZWQgaW50byB0aGlzIGRhdGFzdHJ1Y3R1cmUuXG4gICovXG4gIHJlYWRvbmx5IGNoYW5nZVNldFJlc291cmNlcz86IHR5cGVzLkNoYW5nZVNldFJlc291cmNlcztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBUZW1wbGF0ZUFuZENoYW5nZVNldERpZmZNZXJnZXJQcm9wcyBleHRlbmRzIFRlbXBsYXRlQW5kQ2hhbmdlU2V0RGlmZk1lcmdlck9wdGlvbnMge1xuICAvKlxuICAgKiBUaGUgY2hhbmdlc2V0IHRoYXQgd2lsbCBiZSByZWFkIGFuZCBtZXJnZWQgaW50byB0aGUgdGVtcGxhdGUgZGlmZi5cbiAgKi9cbiAgcmVhZG9ubHkgY2hhbmdlU2V0OiBEZXNjcmliZUNoYW5nZVNldE91dHB1dDtcbn1cblxuLyoqXG4gKiBUaGUgcHVycG9zZSBvZiB0aGlzIGNsYXNzIGlzIHRvIGluY2x1ZGUgZGlmZmVyZW5jZXMgZnJvbSB0aGUgQ2hhbmdlU2V0IHRvIGRpZmZlcmVuY2VzIGluIHRoZSBUZW1wbGF0ZURpZmYuXG4gKi9cbmV4cG9ydCBjbGFzcyBUZW1wbGF0ZUFuZENoYW5nZVNldERpZmZNZXJnZXIge1xuICBwdWJsaWMgc3RhdGljIGRldGVybWluZUNoYW5nZVNldFJlcGxhY2VtZW50TW9kZShwcm9wZXJ0eUNoYW5nZTogQ2hhbmdlU2V0UmVzb3VyY2VDaGFuZ2VEZXRhaWwpOiB0eXBlcy5SZXBsYWNlbWVudE1vZGVzIHtcbiAgICBpZiAocHJvcGVydHlDaGFuZ2UuVGFyZ2V0Py5SZXF1aXJlc1JlY3JlYXRpb24gPT09IHVuZGVmaW5lZCkge1xuICAgICAgLy8gV2UgY2FuJ3QgZGV0ZXJtaW5lIGlmIHRoZSByZXNvdXJjZSB3aWxsIGJlIHJlcGxhY2VkIG9yIG5vdC4gVGhhdCdzIHdoYXQgY29uZGl0aW9uYWxseSBtZWFucy5cbiAgICAgIHJldHVybiAnQ29uZGl0aW9uYWxseSc7XG4gICAgfVxuXG4gICAgaWYgKHByb3BlcnR5Q2hhbmdlLlRhcmdldC5SZXF1aXJlc1JlY3JlYXRpb24gPT09ICdBbHdheXMnKSB7XG4gICAgICBzd2l0Y2ggKHByb3BlcnR5Q2hhbmdlLkV2YWx1YXRpb24pIHtcbiAgICAgICAgY2FzZSAnU3RhdGljJzpcbiAgICAgICAgICByZXR1cm4gJ0Fsd2F5cyc7XG4gICAgICAgIGNhc2UgJ0R5bmFtaWMnOlxuICAgICAgICAgIC8vIElmIEV2YWx1YXRpb24gaXMgJ0R5bmFtaWMnLCB0aGVuIHRoaXMgbWF5IGNhdXNlIHJlcGxhY2VtZW50LCBvciBpdCBtYXkgbm90LlxuICAgICAgICAgIC8vIHNlZSAnUmVwbGFjZW1lbnQnOiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L0FQSVJlZmVyZW5jZS9BUElfUmVzb3VyY2VDaGFuZ2UuaHRtbFxuICAgICAgICAgIHJldHVybiAnQ29uZGl0aW9uYWxseSc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHByb3BlcnR5Q2hhbmdlLlRhcmdldC5SZXF1aXJlc1JlY3JlYXRpb24gYXMgdHlwZXMuUmVwbGFjZW1lbnRNb2RlcztcbiAgfVxuXG4gIC8vIElmIHdlIHNvbWVob3cgY2Fubm90IGZpbmQgdGhlIHJlc291cmNlVHlwZSwgdGhlbiB3ZSdsbCBtYXJrIGl0IGFzIFVOS05PV04sIHNvIHRoYXQgY2FuIGJlIHNlZW4gaW4gdGhlIGRpZmYuXG4gIHByaXZhdGUgc3RhdGljIFVOS05PV05fUkVTT1VSQ0VfVFlQRSA9ICdVTktOT1dOX1JFU09VUkNFX1RZUEUnO1xuXG4gIHB1YmxpYyBjaGFuZ2VTZXQ6IERlc2NyaWJlQ2hhbmdlU2V0T3V0cHV0IHwgdW5kZWZpbmVkO1xuICBwdWJsaWMgY2hhbmdlU2V0UmVzb3VyY2VzOiB0eXBlcy5DaGFuZ2VTZXRSZXNvdXJjZXM7XG5cbiAgY29uc3RydWN0b3IocHJvcHM6IFRlbXBsYXRlQW5kQ2hhbmdlU2V0RGlmZk1lcmdlclByb3BzKSB7XG4gICAgdGhpcy5jaGFuZ2VTZXQgPSBwcm9wcy5jaGFuZ2VTZXQ7XG4gICAgdGhpcy5jaGFuZ2VTZXRSZXNvdXJjZXMgPSBwcm9wcy5jaGFuZ2VTZXRSZXNvdXJjZXMgPz8gdGhpcy5jb252ZXJ0RGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXRUb0NoYW5nZVNldFJlc291cmNlcyh0aGlzLmNoYW5nZVNldCk7XG4gIH1cblxuICAvKipcbiAgICogUmVhZCByZXNvdXJjZXMgZnJvbSB0aGUgY2hhbmdlU2V0LCBleHRyYWN0aW5nIGluZm9ybWF0aW9uIGludG8gQ2hhbmdlU2V0UmVzb3VyY2VzLlxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0RGVzY3JpYmVDaGFuZ2VTZXRPdXRwdXRUb0NoYW5nZVNldFJlc291cmNlcyhjaGFuZ2VTZXQ6IERlc2NyaWJlQ2hhbmdlU2V0T3V0cHV0KTogdHlwZXMuQ2hhbmdlU2V0UmVzb3VyY2VzIHtcbiAgICBjb25zdCBjaGFuZ2VTZXRSZXNvdXJjZXM6IHR5cGVzLkNoYW5nZVNldFJlc291cmNlcyA9IHt9O1xuICAgIGZvciAoY29uc3QgcmVzb3VyY2VDaGFuZ2Ugb2YgY2hhbmdlU2V0LkNoYW5nZXMgPz8gW10pIHtcbiAgICAgIGlmIChyZXNvdXJjZUNoYW5nZS5SZXNvdXJjZUNoYW5nZT8uTG9naWNhbFJlc291cmNlSWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTsgLy8gQmVpbmcgZGVmZW5zaXZlLCBoZXJlLlxuICAgICAgfVxuXG4gICAgICBjb25zdCBwcm9wZXJ0eVJlcGxhY2VtZW50TW9kZXM6IHR5cGVzLlByb3BlcnR5UmVwbGFjZW1lbnRNb2RlTWFwID0ge307XG4gICAgICBmb3IgKGNvbnN0IHByb3BlcnR5Q2hhbmdlIG9mIHJlc291cmNlQ2hhbmdlLlJlc291cmNlQ2hhbmdlLkRldGFpbHMgPz8gW10pIHsgLy8gRGV0YWlscyBpcyBvbmx5IGluY2x1ZGVkIGlmIHJlc291cmNlQ2hhbmdlLkFjdGlvbiA9PT0gJ01vZGlmeSdcbiAgICAgICAgaWYgKHByb3BlcnR5Q2hhbmdlLlRhcmdldD8uQXR0cmlidXRlID09PSAnUHJvcGVydGllcycgJiYgcHJvcGVydHlDaGFuZ2UuVGFyZ2V0Lk5hbWUpIHtcbiAgICAgICAgICBwcm9wZXJ0eVJlcGxhY2VtZW50TW9kZXNbcHJvcGVydHlDaGFuZ2UuVGFyZ2V0Lk5hbWVdID0ge1xuICAgICAgICAgICAgcmVwbGFjZW1lbnRNb2RlOiBUZW1wbGF0ZUFuZENoYW5nZVNldERpZmZNZXJnZXIuZGV0ZXJtaW5lQ2hhbmdlU2V0UmVwbGFjZW1lbnRNb2RlKHByb3BlcnR5Q2hhbmdlKSxcbiAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGNoYW5nZVNldFJlc291cmNlc1tyZXNvdXJjZUNoYW5nZS5SZXNvdXJjZUNoYW5nZS5Mb2dpY2FsUmVzb3VyY2VJZF0gPSB7XG4gICAgICAgIHJlc291cmNlV2FzUmVwbGFjZWQ6IHJlc291cmNlQ2hhbmdlLlJlc291cmNlQ2hhbmdlLlJlcGxhY2VtZW50ID09PSAnVHJ1ZScsXG4gICAgICAgIHJlc291cmNlVHlwZTogcmVzb3VyY2VDaGFuZ2UuUmVzb3VyY2VDaGFuZ2UuUmVzb3VyY2VUeXBlID8/IFRlbXBsYXRlQW5kQ2hhbmdlU2V0RGlmZk1lcmdlci5VTktOT1dOX1JFU09VUkNFX1RZUEUsIC8vIERlc2NyaWJlQ2hhbmdlU2V0IGRvZXNuJ3QgcHJvbWlzZSB0byBoYXZlIHRoZSBSZXNvdXJjZVR5cGUuLi5cbiAgICAgICAgcHJvcGVydHlSZXBsYWNlbWVudE1vZGVzOiBwcm9wZXJ0eVJlcGxhY2VtZW50TW9kZXMsXG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBjaGFuZ2VTZXRSZXNvdXJjZXM7XG4gIH1cblxuICAvKipcbiAgICogVGhpcyBpcyB3cml0aW5nIG92ZXIgdGhlIFwiQ2hhbmdlSW1wYWN0XCIgdGhhdCB3YXMgY29tcHV0ZWQgZnJvbSB0aGUgdGVtcGxhdGUgZGlmZmVyZW5jZSwgYW5kIGluc3RlYWQgdXNpbmcgdGhlIENoYW5nZUltcGFjdCB0aGF0IGlzIGluY2x1ZGVkIGZyb20gdGhlIENoYW5nZVNldC5cbiAgICogVXNpbmcgdGhlIENoYW5nZVNldCBDaGFuZ2VJbXBhY3QgaXMgbW9yZSBhY2N1cmF0ZS4gVGhlIENoYW5nZUltcGFjdCB0ZWxscyB1cyB3aGF0IHRoZSBjb25zZXF1ZW5jZSBpcyBvZiBjaGFuZ2luZyB0aGUgZmllbGQuIElmIGNoYW5naW5nIHRoZSBmaWVsZCBjYXVzZXMgcmVzb3VyY2VcbiAgICogcmVwbGFjZW1lbnQgKGUuZy4sIGNoYW5naW5nIHRoZSBuYW1lIG9mIGFuIElBTSByb2xlIHJlcXVpcmVzIGRlbGV0aW5nIGFuZCByZXBsYWNpbmcgdGhlIHJvbGUpLCB0aGVuIENoYW5nZUltcGFjdCBpcyBcIkFsd2F5c1wiLlxuICAgKi9cbiAgcHVibGljIG92ZXJyaWRlRGlmZlJlc291cmNlQ2hhbmdlSW1wYWN0V2l0aENoYW5nZVNldENoYW5nZUltcGFjdChsb2dpY2FsSWQ6IHN0cmluZywgY2hhbmdlOiB0eXBlcy5SZXNvdXJjZURpZmZlcmVuY2UpIHtcbiAgICAvLyByZXNvdXJjZVR5cGUgZ2V0dGVyIHRocm93cyBhbiBlcnJvciBpZiByZXNvdXJjZVR5cGVDaGFuZ2VkXG4gICAgaWYgKChjaGFuZ2UucmVzb3VyY2VUeXBlQ2hhbmdlZCA9PT0gdHJ1ZSkgfHwgY2hhbmdlLnJlc291cmNlVHlwZT8uaW5jbHVkZXMoJ0FXUzo6U2VydmVybGVzcycpKSB7XG4gICAgICAvLyBDRk4gYXBwbGllcyB0aGUgU0FNIHRyYW5zZm9ybSBiZWZvcmUgY3JlYXRpbmcgdGhlIGNoYW5nZXNldCwgc28gdGhlIGNoYW5nZXNldCBjb250YWlucyBubyBpbmZvcm1hdGlvbiBhYm91dCBTQU0gcmVzb3VyY2VzXG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGNoYW5nZS5mb3JFYWNoRGlmZmVyZW5jZSgodHlwZTogJ1Byb3BlcnR5JyB8ICdPdGhlcicsIG5hbWU6IHN0cmluZywgdmFsdWU6IHR5cGVzLkRpZmZlcmVuY2U8YW55PiB8IHR5cGVzLlByb3BlcnR5RGlmZmVyZW5jZTxhbnk+KSA9PiB7XG4gICAgICBpZiAodHlwZSA9PT0gJ1Byb3BlcnR5Jykge1xuICAgICAgICBpZiAoIXRoaXMuY2hhbmdlU2V0UmVzb3VyY2VzW2xvZ2ljYWxJZF0pIHtcbiAgICAgICAgICAodmFsdWUgYXMgdHlwZXMuUHJvcGVydHlEaWZmZXJlbmNlPGFueT4pLmNoYW5nZUltcGFjdCA9IHR5cGVzLlJlc291cmNlSW1wYWN0Lk5PX0NIQU5HRTtcbiAgICAgICAgICAodmFsdWUgYXMgdHlwZXMuUHJvcGVydHlEaWZmZXJlbmNlPGFueT4pLmlzRGlmZmVyZW50ID0gZmFsc2U7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3QgY2hhbmdpbmdQcm9wZXJ0eUNhdXNlc1Jlc291cmNlUmVwbGFjZW1lbnQgPSAodGhpcy5jaGFuZ2VTZXRSZXNvdXJjZXNbbG9naWNhbElkXS5wcm9wZXJ0eVJlcGxhY2VtZW50TW9kZXMgPz8ge30pW25hbWVdPy5yZXBsYWNlbWVudE1vZGU7XG4gICAgICAgIHN3aXRjaCAoY2hhbmdpbmdQcm9wZXJ0eUNhdXNlc1Jlc291cmNlUmVwbGFjZW1lbnQpIHtcbiAgICAgICAgICBjYXNlICdBbHdheXMnOlxuICAgICAgICAgICAgKHZhbHVlIGFzIHR5cGVzLlByb3BlcnR5RGlmZmVyZW5jZTxhbnk+KS5jaGFuZ2VJbXBhY3QgPSB0eXBlcy5SZXNvdXJjZUltcGFjdC5XSUxMX1JFUExBQ0U7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlICdOZXZlcic6XG4gICAgICAgICAgICAodmFsdWUgYXMgdHlwZXMuUHJvcGVydHlEaWZmZXJlbmNlPGFueT4pLmNoYW5nZUltcGFjdCA9IHR5cGVzLlJlc291cmNlSW1wYWN0LldJTExfVVBEQVRFO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgY2FzZSAnQ29uZGl0aW9uYWxseSc6XG4gICAgICAgICAgICAodmFsdWUgYXMgdHlwZXMuUHJvcGVydHlEaWZmZXJlbmNlPGFueT4pLmNoYW5nZUltcGFjdCA9IHR5cGVzLlJlc291cmNlSW1wYWN0Lk1BWV9SRVBMQUNFO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgY2FzZSB1bmRlZmluZWQ6XG4gICAgICAgICAgICAodmFsdWUgYXMgdHlwZXMuUHJvcGVydHlEaWZmZXJlbmNlPGFueT4pLmNoYW5nZUltcGFjdCA9IHR5cGVzLlJlc291cmNlSW1wYWN0Lk5PX0NIQU5HRTtcbiAgICAgICAgICAgICh2YWx1ZSBhcyB0eXBlcy5Qcm9wZXJ0eURpZmZlcmVuY2U8YW55PikuaXNEaWZmZXJlbnQgPSBmYWxzZTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIC8vIG90aGVyd2lzZSwgZGVmZXIgdG8gdGhlIGNoYW5nZUltcGFjdCBmcm9tIHRoZSB0ZW1wbGF0ZSBkaWZmXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ090aGVyJykge1xuICAgICAgICBzd2l0Y2ggKG5hbWUpIHtcbiAgICAgICAgICBjYXNlICdNZXRhZGF0YSc6XG4gICAgICAgICAgICAvLyB3ZSB3YW50IHRvIGlnbm9yZSBtZXRhZGF0YSBjaGFuZ2VzIGluIHRoZSBkaWZmLCBzbyBjb21wYXJlIG5ld1ZhbHVlIGFnYWluc3QgbmV3VmFsdWUuXG4gICAgICAgICAgICBjaGFuZ2Uuc2V0T3RoZXJDaGFuZ2UoJ01ldGFkYXRhJywgbmV3IHR5cGVzLkRpZmZlcmVuY2U8c3RyaW5nPih2YWx1ZS5uZXdWYWx1ZSwgdmFsdWUubmV3VmFsdWUpKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gIH1cblxuICBwdWJsaWMgYWRkSW1wb3J0SW5mb3JtYXRpb25Gcm9tQ2hhbmdlc2V0KHJlc291cmNlRGlmZnM6IHR5cGVzLkRpZmZlcmVuY2VDb2xsZWN0aW9uPHR5cGVzLlJlc291cmNlLCB0eXBlcy5SZXNvdXJjZURpZmZlcmVuY2U+KSB7XG4gICAgY29uc3QgaW1wb3J0cyA9IHRoaXMuZmluZFJlc291cmNlSW1wb3J0cygpO1xuICAgIHJlc291cmNlRGlmZnMuZm9yRWFjaERpZmZlcmVuY2UoKGxvZ2ljYWxJZDogc3RyaW5nLCBjaGFuZ2U6IHR5cGVzLlJlc291cmNlRGlmZmVyZW5jZSkgPT4ge1xuICAgICAgaWYgKGltcG9ydHMuaW5jbHVkZXMobG9naWNhbElkKSkge1xuICAgICAgICBjaGFuZ2UuaXNJbXBvcnQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG5cbiAgcHVibGljIGZpbmRSZXNvdXJjZUltcG9ydHMoKTogKHN0cmluZyB8IHVuZGVmaW5lZClbXSB7XG4gICAgY29uc3QgaW1wb3J0ZWRSZXNvdXJjZUxvZ2ljYWxJZHMgPSBbXTtcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlQ2hhbmdlIG9mIHRoaXMuY2hhbmdlU2V0Py5DaGFuZ2VzID8/IFtdKSB7XG4gICAgICBpZiAocmVzb3VyY2VDaGFuZ2UuUmVzb3VyY2VDaGFuZ2U/LkFjdGlvbiA9PT0gJ0ltcG9ydCcpIHtcbiAgICAgICAgaW1wb3J0ZWRSZXNvdXJjZUxvZ2ljYWxJZHMucHVzaChyZXNvdXJjZUNoYW5nZS5SZXNvdXJjZUNoYW5nZS5Mb2dpY2FsUmVzb3VyY2VJZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGltcG9ydGVkUmVzb3VyY2VMb2dpY2FsSWRzO1xuICB9XG59XG4iXX0=