UNPKG

@aws-cdk/aws-lambda

Version:

The CDK Construct Library for AWS::Lambda

146 lines 21 kB
"use strict"; 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