@aws-cdk/aws-lambda
Version:
The CDK Construct Library for AWS::Lambda
146 lines • 21 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.VERSION_LOCKED = exports.trimFromStart = exports.calculateFunctionHash = void 0;
const crypto = require("crypto");
const core_1 = require("@aws-cdk/core");
const cx_api_1 = require("@aws-cdk/cx-api");
const function_1 = require("./function");
function calculateFunctionHash(fn) {
const stack = core_1.Stack.of(fn);
const functionResource = fn.node.defaultChild;
// render the cloudformation resource from this function
const config = stack.resolve(functionResource._toCloudFormation());
// config is of the shape: { Resources: { LogicalId: { Type: 'Function', Properties: { ... } }}}
const resources = config.Resources;
const resourceKeys = Object.keys(resources);
if (resourceKeys.length !== 1) {
throw new Error(`Expected one rendered CloudFormation resource but found ${resourceKeys.length}`);
}
const logicalId = resourceKeys[0];
const properties = resources[logicalId].Properties;
let stringifiedConfig;
if (core_1.FeatureFlags.of(fn).isEnabled(cx_api_1.LAMBDA_RECOGNIZE_VERSION_PROPS)) {
const updatedProps = sortProperties(filterUsefulKeys(properties));
stringifiedConfig = JSON.stringify(updatedProps);
}
else {
const sorted = sortProperties(properties);
config.Resources[logicalId].Properties = sorted;
stringifiedConfig = JSON.stringify(config);
}
if (core_1.FeatureFlags.of(fn).isEnabled(cx_api_1.LAMBDA_RECOGNIZE_LAYER_VERSION)) {
stringifiedConfig = stringifiedConfig + calculateLayersHash(fn._layers);
}
const hash = crypto.createHash('md5');
hash.update(stringifiedConfig);
return hash.digest('hex');
}
exports.calculateFunctionHash = calculateFunctionHash;
function trimFromStart(s, maxLength) {
const desiredLength = Math.min(maxLength, s.length);
const newStart = s.length - desiredLength;
return s.substring(newStart);
}
exports.trimFromStart = trimFromStart;
/*
* The list of properties found in CfnFunction (or AWS::Lambda::Function).
* They are classified as "locked" to a Function Version or not.
* When a property is locked, any change to that property will not take effect on previously created Versions.
* Instead, a new Version must be generated for the change to take effect.
* Similarly, if a property that's not locked to a Version is modified, a new Version
* must not be generated.
*
* Adding a new property to this list - If the property is part of the UpdateFunctionConfiguration
* API or UpdateFunctionCode API, then it must be classified as true, otherwise false.
* See https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionConfiguration.html and
* https://docs.aws.amazon.com/lambda/latest/dg/API_UpdateFunctionConfiguration.html
*/
exports.VERSION_LOCKED = {
// locked to the version
Architectures: true,
Code: true,
DeadLetterConfig: true,
Description: true,
Environment: true,
EphemeralStorage: true,
FileSystemConfigs: true,
FunctionName: true,
Handler: true,
ImageConfig: true,
KmsKeyArn: true,
Layers: true,
MemorySize: true,
PackageType: true,
Role: true,
Runtime: true,
RuntimeManagementConfig: true,
SnapStart: true,
Timeout: true,
TracingConfig: true,
VpcConfig: true,
// not locked to the version
CodeSigningConfigArn: false,
ReservedConcurrentExecutions: false,
Tags: false,
};
function filterUsefulKeys(properties) {
const versionProps = { ...exports.VERSION_LOCKED, ...function_1.Function._VER_PROPS };
const unclassified = Object.entries(properties)
.filter(([k, v]) => v != null && !Object.keys(versionProps).includes(k))
.map(([k, _]) => k);
if (unclassified.length > 0) {
throw new Error(`The following properties are not recognized as version properties: [${unclassified}].`
+ ' See the README of the aws-lambda module to learn more about this and to fix it.');
}
const notLocked = Object.entries(versionProps).filter(([_, v]) => !v).map(([k, _]) => k);
notLocked.forEach(p => delete properties[p]);
const ret = {};
Object.entries(properties).filter(([k, _]) => versionProps[k]).forEach(([k, v]) => ret[k] = v);
return ret;
}
function sortProperties(properties) {
const ret = {};
// We take all required properties in the order that they were historically,
// to make sure the hash we calculate is stable.
// There cannot be more required properties added in the future,
// as that would be a backwards-incompatible change.
const requiredProperties = ['Code', 'Handler', 'Role', 'Runtime'];
for (const requiredProperty of requiredProperties) {
ret[requiredProperty] = properties[requiredProperty];
}
// then, add all of the non-required properties,
// in the original order
for (const property of Object.keys(properties)) {
if (requiredProperties.indexOf(property) === -1) {
ret[property] = properties[property];
}
}
return ret;
}
function calculateLayersHash(layers) {
const layerConfig = {};
for (const layer of layers) {
const stack = core_1.Stack.of(layer);
const layerResource = layer.node.defaultChild;
// if there is no layer resource, then the layer was imported
// and we will include the layer arn and runtimes in the hash
if (layerResource === undefined) {
layerConfig[layer.layerVersionArn] = layer.compatibleRuntimes;
continue;
}
const config = stack.resolve(layerResource._toCloudFormation());
const resources = config.Resources;
const resourceKeys = Object.keys(resources);
if (resourceKeys.length !== 1) {
throw new Error(`Expected one rendered CloudFormation resource but found ${resourceKeys.length}`);
}
const logicalId = resourceKeys[0];
const properties = resources[logicalId].Properties;
// all properties require replacement, so they are all version locked.
layerConfig[layer.node.id] = properties;
}
const hash = crypto.createHash('md5');
hash.update(JSON.stringify(layerConfig));
return hash.digest('hex');
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb24taGFzaC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImZ1bmN0aW9uLWhhc2gudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsaUNBQWlDO0FBQ2pDLHdDQUFpRTtBQUNqRSw0Q0FBaUc7QUFDakcseUNBQXdEO0FBR3hELFNBQWdCLHFCQUFxQixDQUFDLEVBQWtCO0lBQ3RELE1BQU0sS0FBSyxHQUFHLFlBQUssQ0FBQyxFQUFFLENBQUMsRUFBRSxDQUFDLENBQUM7SUFFM0IsTUFBTSxnQkFBZ0IsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFlBQTJCLENBQUM7SUFFN0Qsd0RBQXdEO0lBQ3hELE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQUUsZ0JBQXdCLENBQUMsaUJBQWlCLEVBQUUsQ0FBQyxDQUFDO0lBQzVFLGdHQUFnRztJQUNoRyxNQUFNLFNBQVMsR0FBRyxNQUFNLENBQUMsU0FBUyxDQUFDO0lBQ25DLE1BQU0sWUFBWSxHQUFHLE1BQU0sQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDNUMsSUFBSSxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtRQUM3QixNQUFNLElBQUksS0FBSyxDQUFDLDJEQUEyRCxZQUFZLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQztLQUNuRztJQUNELE1BQU0sU0FBUyxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUNsQyxNQUFNLFVBQVUsR0FBRyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsVUFBVSxDQUFDO0lBRW5ELElBQUksaUJBQWlCLENBQUM7SUFDdEIsSUFBSSxtQkFBWSxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxTQUFTLENBQUMsdUNBQThCLENBQUMsRUFBRTtRQUNqRSxNQUFNLFlBQVksR0FBRyxjQUFjLENBQUMsZ0JBQWdCLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztRQUNsRSxpQkFBaUIsR0FBRyxJQUFJLENBQUMs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RyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsVUFBVSxDQUFDO1FBQ25ELHNFQUFzRTtRQUN0RSxXQUFXLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsR0FBRyxVQUFVLENBQUM7S0FDekM7SUFFRCxNQUFNLElBQUksR0FBRyxNQUFNLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3RDLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDO0lBQ3pDLE9BQU8sSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUM1QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgY3J5cHRvIGZyb20gJ2NyeXB0byc7XG5pbXBvcnQgeyBDZm5SZXNvdXJjZSwgRmVhdHVyZUZsYWdzLCBTdGFjayB9IGZyb20gJ0Bhd3MtY2RrL2NvcmUnO1xuaW1wb3J0IHsgTEFNQkRBX1JFQ09HTklaRV9MQVlFUl9WRVJTSU9OLCBMQU1CREFfUkVDT0dOSVpFX1ZFUlNJT05fUFJPUFMgfSBmcm9tICdAYXdzLWNkay9jeC1hcGknO1xuaW1wb3J0IHsgRnVuY3Rpb24gYXMgTGFtYmRhRnVuY3Rpb24gfSBmcm9tICcuL2Z1bmN0aW9uJztcbmltcG9ydCB7IElMYXllclZlcnNpb24gfSBmcm9tICcuL2xheWVycyc7XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWxjdWxhdGVGdW5jdGlvbkhhc2goZm46IExhbWJkYUZ1bmN0aW9uKSB7XG4gIGNvbnN0IHN0YWNrID0gU3RhY2sub2YoZm4pO1xuXG4gIGNvbnN0IGZ1bmN0aW9uUmVzb3VyY2UgPSBmbi5ub2RlLmRlZmF1bHRDaGlsZCBhcyBDZm5SZXNvdXJjZTtcblxuICAvLyByZW5kZXIgdGhlIGNsb3VkZm9ybWF0aW9uIHJlc291cmNlIGZyb20gdGhpcyBmdW5jdGlvblxuICBjb25zdCBjb25maWcgPSBzdGFjay5yZXNvbHZlKChmdW5jdGlvblJlc291cmNlIGFzIGFueSkuX3RvQ2xvdWRGb3JtYXRpb24oKSk7XG4gIC8vIGNvbmZpZyBpcyBvZiB0aGUgc2hhcGU6IHsgUmVzb3VyY2VzOiB7IExvZ2ljYWxJZDogeyBUeXBlOiAnRnVuY3Rpb24nLCBQcm9wZXJ0aWVzOiB7IC4uLiB9IH19fVxuICBjb25zdCByZXNvdXJjZXMgPSBjb25maWcuUmVzb3VyY2VzO1xuICBjb25zdCByZXNvdXJjZUtleXMgPSBPYmplY3Qua2V5cyhyZXNvdXJjZXMpO1xuICBpZiAocmVzb3VyY2VLZXlzLmxlbmd0aCAhPT0gMSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRXhwZWN0ZWQgb25lIHJlbmRlcmVkIENsb3VkRm9ybWF0aW9uIHJlc291cmNlIGJ1dCBmb3VuZCAke3Jlc291cmNlS2V5cy5sZW5ndGh9YCk7XG4gIH1cbiAgY29uc3QgbG9naWNhbElkID0gcmVzb3VyY2VLZXlzWzBdO1xuICBjb25zdCBwcm9wZXJ0aWVzID0gcmVzb3VyY2VzW2xvZ2ljYWxJZF0uUHJvcGVydGllcztcblxuICBsZXQgc3RyaW5naWZpZWRDb25maWc7XG4gIGlmIChGZWF0dXJlRmxhZ3Mub2YoZm4pLmlzRW5hYmxlZChMQU1CREFfUkVDT0dOSVpFX1ZFUlNJT05fUFJPUFMpKSB7XG4gICAgY29uc3QgdXBkYXRlZFByb3BzID0gc29ydFByb3BlcnRpZXMoZmlsdGVyVXNlZnVsS2V5cyhwcm9wZXJ0aWVzKSk7XG4gICAgc3RyaW5naWZpZWRDb25maWcgPSBKU09OLnN0cmluZ2lmeSh1cGRhdGVkUHJvcHMpO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHNvcnRlZCA9IHNvcnRQcm9wZXJ0aWVzKHByb3BlcnRpZXMpO1xuICAgIGNvbmZpZy5SZXNvdXJjZXNbbG9naWNhbElkXS5Qcm9wZXJ0aWVzID0gc29ydGVkO1xuICAgIHN0cmluZ2lmaWVkQ29uZmlnID0gSlNPTi5zdHJpbmdpZnkoY29uZmlnKTtcbiAgfVxuXG4gIGlmIChGZWF0dXJlRmxhZ3Mub2YoZm4pLmlzRW5hYmxlZChMQU1CREFfUkVDT0dOSVpFX0xBWUVSX1ZFUlNJT04pKSB7XG4gICAgc3RyaW5naWZpZWRDb25maWcgPSBzdHJpbmdpZmllZENvbmZpZyArIGNhbGN1bGF0ZUxheWVyc0hhc2goZm4uX2xheWVycyk7XG4gIH1cblxuICBjb25zdCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goJ21kNScpO1xuICBoYXNoLnVwZGF0ZShzdHJpbmdpZmllZENvbmZpZyk7XG4gIHJldHVybiBoYXNoLmRpZ2VzdCgnaGV4Jyk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiB0cmltRnJvbVN0YXJ0KHM6IHN0cmluZywgbWF4TGVuZ3RoOiBudW1iZXIpIHtcbiAgY29uc3QgZGVzaXJlZExlbmd0aCA9IE1hdGgubWluKG1heExlbmd0aCwgcy5sZW5ndGgpO1xuICBjb25zdCBuZXdTdGFydCA9IHMubGVuZ3RoIC0gZGVzaXJlZExlbmd0aDtcbiAgcmV0dXJuIHMuc3Vic3RyaW5nKG5ld1N0YXJ0KTtcbn1cblxuLypcbiAqIFRoZSBsaXN0IG9mIHByb3BlcnRpZXMgZm91bmQgaW4gQ2ZuRnVuY3Rpb24gKG9yIEFXUzo6TGFtYmRhOjpGdW5jdGlvbikuXG4gKiBUaGV5IGFyZSBjbGFzc2lmaWVkIGFzIFwibG9ja2VkXCIgdG8gYSBGdW5jdGlvbiBWZXJzaW9uIG9yIG5vdC5cbiAqIFdoZW4gYSBwcm9wZXJ0eSBpcyBsb2NrZWQsIGFueSBjaGFuZ2UgdG8gdGhhdCBwcm9wZXJ0eSB3aWxsIG5vdCB0YWtlIGVmZmVjdCBvbiBwcmV2aW91c2x5IGNyZWF0ZWQgVmVyc2lvbnMuXG4gKiBJbnN0ZWFkLCBhIG5ldyBWZXJzaW9uIG11c3QgYmUgZ2VuZXJhdGVkIGZvciB0aGUgY2hhbmdlIHRvIHRha2UgZWZmZWN0LlxuICogU2ltaWxhcmx5LCBpZiBhIHByb3BlcnR5IHRoYXQncyBub3QgbG9ja2VkIHRvIGEgVmVyc2lvbiBpcyBtb2RpZmllZCwgYSBuZXcgVmVyc2lvblxuICogbXVzdCBub3QgYmUgZ2VuZXJhdGVkLlxuICpcbiAqIEFkZGluZyBhIG5ldyBwcm9wZXJ0eSB0byB0aGlzIGxpc3QgLSBJZiB0aGUgcHJvcGVydHkgaXMgcGFydCBvZiB0aGUgVXBkYXRlRnVuY3Rpb25Db25maWd1cmF0aW9uXG4gKiBBUEkgb3IgVXBkYXRlRnVuY3Rpb25Db2RlIEFQSSwgdGhlbiBpdCBtdXN0IGJlIGNsYXNzaWZpZWQgYXMgdHJ1ZSwgb3RoZXJ3aXNlIGZhbHNlLlxuICogU2VlIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL0FQSV9VcGRhdGVGdW5jdGlvbkNvbmZpZ3VyYXRpb24uaHRtbCBhbmRcbiAqIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9sYW1iZGEvbGF0ZXN0L2RnL0FQSV9VcGRhdGVGdW5jdGlvbkNvbmZpZ3VyYXRpb24uaHRtbFxuICovXG5leHBvcnQgY29uc3QgVkVSU0lPTl9MT0NLRUQ6IHsgW2tleTogc3RyaW5nXTogYm9vbGVhbiB9ID0ge1xuICAvLyBsb2NrZWQgdG8gdGhlIHZlcnNpb25cbiAgQXJjaGl0ZWN0dXJlczogdHJ1ZSxcbiAgQ29kZTogdHJ1ZSxcbiAgRGVhZExldHRlckNvbmZpZzogdHJ1ZSxcbiAgRGVzY3JpcHRpb246IHRydWUsXG4gIEVudmlyb25tZW50OiB0cnVlLFxuICBFcGhlbWVyYWxTdG9yYWdlOiB0cnVlLFxuICBGaWxlU3lzdGVtQ29uZmlnczogdHJ1ZSxcbiAgRnVuY3Rpb25OYW1lOiB0cnVlLFxuICBIYW5kbGVyOiB0cnVlLFxuICBJbWFnZUNvbmZpZzogdHJ1ZSxcbiAgS21zS2V5QXJuOiB0cnVlLFxuICBMYXllcnM6IHRydWUsXG4gIE1lbW9yeVNpemU6IHRydWUsXG4gIFBhY2thZ2VUeXBlOiB0cnVlLFxuICBSb2xlOiB0cnVlLFxuICBSdW50aW1lOiB0cnVlLFxuICBSdW50aW1lTWFuYWdlbWVudENvbmZpZzogdHJ1ZSxcbiAgU25hcFN0YXJ0OiB0cnVlLFxuICBUaW1lb3V0OiB0cnVlLFxuICBUcmFjaW5nQ29uZmlnOiB0cnVlLFxuICBWcGNDb25maWc6IHRydWUsXG5cbiAgLy8gbm90IGxvY2tlZCB0byB0aGUgdmVyc2lvblxuICBDb2RlU2lnbmluZ0NvbmZpZ0FybjogZmFsc2UsXG4gIFJlc2VydmVkQ29uY3VycmVudEV4ZWN1dGlvbnM6IGZhbHNlLFxuICBUYWdzOiBmYWxzZSxcbn07XG5cbmZ1bmN0aW9uIGZpbHRlclVzZWZ1bEtleXMocHJvcGVydGllczogYW55KSB7XG4gIGNvbnN0IHZlcnNpb25Qcm9wcyA9IHsgLi4uVkVSU0lPTl9MT0NLRUQsIC4uLkxhbWJkYUZ1bmN0aW9uLl9WRVJfUFJPUFMgfTtcbiAgY29uc3QgdW5jbGFzc2lmaWVkID0gT2JqZWN0LmVudHJpZXMocHJvcGVydGllcylcbiAgICAuZmlsdGVyKChbaywgdl0pID0+IHYgIT0gbnVsbCAmJiAhT2JqZWN0LmtleXModmVyc2lvblByb3BzKS5pbmNsdWRlcyhrKSlcbiAgICAubWFwKChbaywgX10pID0+IGspO1xuICBpZiAodW5jbGFzc2lmaWVkLmxlbmd0aCA+IDApIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYFRoZSBmb2xsb3dpbmcgcHJvcGVydGllcyBhcmUgbm90IHJlY29nbml6ZWQgYXMgdmVyc2lvbiBwcm9wZXJ0aWVzOiBbJHt1bmNsYXNzaWZpZWR9XS5gXG4gICAgICArICcgU2VlIHRoZSBSRUFETUUgb2YgdGhlIGF3cy1sYW1iZGEgbW9kdWxlIHRvIGxlYXJuIG1vcmUgYWJvdXQgdGhpcyBhbmQgdG8gZml4IGl0LicpO1xuICB9XG4gIGNvbnN0IG5vdExvY2tlZCA9IE9iamVjdC5lbnRyaWVzKHZlcnNpb25Qcm9wcykuZmlsdGVyKChbXywgdl0pID0+ICF2KS5tYXAoKFtrLCBfXSkgPT4gayk7XG4gIG5vdExvY2tlZC5mb3JFYWNoKHAgPT4gZGVsZXRlIHByb3BlcnRpZXNbcF0pO1xuXG4gIGNvbnN0IHJldDogeyBba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBPYmplY3QuZW50cmllcyhwcm9wZXJ0aWVzKS5maWx0ZXIoKFtrLCBfXSkgPT4gdmVyc2lvblByb3BzW2tdKS5mb3JFYWNoKChbaywgdl0pID0+IHJldFtrXSA9IHYpO1xuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBzb3J0UHJvcGVydGllcyhwcm9wZXJ0aWVzOiBhbnkpIHtcbiAgY29uc3QgcmV0OiBhbnkgPSB7fTtcbiAgLy8gV2UgdGFrZSBhbGwgcmVxdWlyZWQgcHJvcGVydGllcyBpbiB0aGUgb3JkZXIgdGhhdCB0aGV5IHdlcmUgaGlzdG9yaWNhbGx5LFxuICAvLyB0byBtYWtlIHN1cmUgdGhlIGhhc2ggd2UgY2FsY3VsYXRlIGlzIHN0YWJsZS5cbiAgLy8gVGhlcmUgY2Fubm90IGJlIG1vcmUgcmVxdWlyZWQgcHJvcGVydGllcyBhZGRlZCBpbiB0aGUgZnV0dXJlLFxuICAvLyBhcyB0aGF0IHdvdWxkIGJlIGEgYmFja3dhcmRzLWluY29tcGF0aWJsZSBjaGFuZ2UuXG4gIGNvbnN0IHJlcXVpcmVkUHJvcGVydGllcyA9IFsnQ29kZScsICdIYW5kbGVyJywgJ1JvbGUnLCAnUnVudGltZSddO1xuICBmb3IgKGNvbnN0IHJlcXVpcmVkUHJvcGVydHkgb2YgcmVxdWlyZWRQcm9wZXJ0aWVzKSB7XG4gICAgcmV0W3JlcXVpcmVkUHJvcGVydHldID0gcHJvcGVydGllc1tyZXF1aXJlZFByb3BlcnR5XTtcbiAgfVxuICAvLyB0aGVuLCBhZGQgYWxsIG9mIHRoZSBub24tcmVxdWlyZWQgcHJvcGVydGllcyxcbiAgLy8gaW4gdGhlIG9yaWdpbmFsIG9yZGVyXG4gIGZvciAoY29uc3QgcHJvcGVydHkgb2YgT2JqZWN0LmtleXMocHJvcGVydGllcykpIHtcbiAgICBpZiAocmVxdWlyZWRQcm9wZXJ0aWVzLmluZGV4T2YocHJvcGVydHkpID09PSAtMSkge1xuICAgICAgcmV0W3Byb3BlcnR5XSA9IHByb3BlcnRpZXNbcHJvcGVydHldO1xuICAgIH1cbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBjYWxjdWxhdGVMYXllcnNIYXNoKGxheWVyczogSUxheWVyVmVyc2lvbltdKTogc3RyaW5nIHtcbiAgY29uc3QgbGF5ZXJDb25maWc6IHtba2V5OiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBmb3IgKGNvbnN0IGxheWVyIG9mIGxheWVycykge1xuICAgIGNvbnN0IHN0YWNrID0gU3RhY2sub2YobGF5ZXIpO1xuICAgIGNvbnN0IGxheWVyUmVzb3VyY2UgPSBsYXllci5ub2RlLmRlZmF1bHRDaGlsZCBhcyBDZm5SZXNvdXJjZTtcbiAgICAvLyBpZiB0aGVyZSBpcyBubyBsYXllciByZXNvdXJjZSwgdGhlbiB0aGUgbGF5ZXIgd2FzIGltcG9ydGVkXG4gICAgLy8gYW5kIHdlIHdpbGwgaW5jbHVkZSB0aGUgbGF5ZXIgYXJuIGFuZCBydW50aW1lcyBpbiB0aGUgaGFzaFxuICAgIGlmIChsYXllclJlc291cmNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgIGxheWVyQ29uZmlnW2xheWVyLmxheWVyVmVyc2lvbkFybl0gPSBsYXllci5jb21wYXRpYmxlUnVudGltZXM7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgY29uZmlnID0gc3RhY2sucmVzb2x2ZSgobGF5ZXJSZXNvdXJjZSBhcyBhbnkpLl90b0Nsb3VkRm9ybWF0aW9uKCkpO1xuICAgIGNvbnN0IHJlc291cmNlcyA9IGNvbmZpZy5SZXNvdXJjZXM7XG4gICAgY29uc3QgcmVzb3VyY2VLZXlzID0gT2JqZWN0LmtleXMocmVzb3VyY2VzKTtcbiAgICBpZiAocmVzb3VyY2VLZXlzLmxlbmd0aCAhPT0gMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBFeHBlY3RlZCBvbmUgcmVuZGVyZWQgQ2xvdWRGb3JtYXRpb24gcmVzb3VyY2UgYnV0IGZvdW5kICR7cmVzb3VyY2VLZXlzLmxlbmd0aH1gKTtcbiAgICB9XG4gICAgY29uc3QgbG9naWNhbElkID0gcmVzb3VyY2VLZXlzWzBdO1xuICAgIGNvbnN0IHByb3BlcnRpZXMgPSByZXNvdXJjZXNbbG9naWNhbElkXS5Qcm9wZXJ0aWVzO1xuICAgIC8vIGFsbCBwcm9wZXJ0aWVzIHJlcXVpcmUgcmVwbGFjZW1lbnQsIHNvIHRoZXkgYXJlIGFsbCB2ZXJzaW9uIGxvY2tlZC5cbiAgICBsYXllckNvbmZpZ1tsYXllci5ub2RlLmlkXSA9IHByb3BlcnRpZXM7XG4gIH1cblxuICBjb25zdCBoYXNoID0gY3J5cHRvLmNyZWF0ZUhhc2goJ21kNScpO1xuICBoYXNoLnVwZGF0ZShKU09OLnN0cmluZ2lmeShsYXllckNvbmZpZykpO1xuICByZXR1cm4gaGFzaC5kaWdlc3QoJ2hleCcpO1xufVxuIl19