UNPKG

aws-cdk

Version:

CDK Toolkit, the command line tool for CDK apps

108 lines 17.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isHotswappableS3BucketDeploymentChange = exports.REQUIRED_BY_CFN = void 0; const common_1 = require("./common"); /** * This means that the value is required to exist by CloudFormation's Custom Resource API (or our S3 Bucket Deployment Lambda's API) * but the actual value specified is irrelevant */ exports.REQUIRED_BY_CFN = 'required-to-be-present-by-cfn'; async function isHotswappableS3BucketDeploymentChange(logicalId, change, evaluateCfnTemplate) { // In old-style synthesis, the policy used by the lambda to copy assets Ref's the assets directly, // meaning that the changes made to the Policy are artifacts that can be safely ignored const ret = []; if (change.newValue.Type === 'AWS::IAM::Policy') { return changeIsForS3DeployCustomResourcePolicy(logicalId, change, evaluateCfnTemplate); } if (change.newValue.Type !== 'Custom::CDKBucketDeployment') { return []; } // no classification to be done here; all the properties of this custom resource thing are hotswappable const customResourceProperties = await evaluateCfnTemplate.evaluateCfnExpression({ ...change.newValue.Properties, ServiceToken: undefined, }); ret.push({ hotswappable: true, resourceType: change.newValue.Type, propsChanged: ['*'], service: 'custom-s3-deployment', resourceNames: [`Contents of S3 Bucket '${customResourceProperties.DestinationBucketName}'`], apply: async (sdk) => { // note that this gives the ARN of the lambda, not the name. This is fine though, the invoke() sdk call will take either const functionName = await evaluateCfnTemplate.evaluateCfnExpression(change.newValue.Properties?.ServiceToken); if (!functionName) { return; } await sdk.lambda().invoke({ FunctionName: functionName, // Lambda refuses to take a direct JSON object and requires it to be stringify()'d Payload: JSON.stringify({ RequestType: 'Update', ResponseURL: exports.REQUIRED_BY_CFN, PhysicalResourceId: exports.REQUIRED_BY_CFN, StackId: exports.REQUIRED_BY_CFN, RequestId: exports.REQUIRED_BY_CFN, LogicalResourceId: exports.REQUIRED_BY_CFN, ResourceProperties: stringifyObject(customResourceProperties), // JSON.stringify() doesn't turn the actual objects to strings, but the lambda expects strings }), }).promise(); }, }); return ret; } exports.isHotswappableS3BucketDeploymentChange = isHotswappableS3BucketDeploymentChange; async function changeIsForS3DeployCustomResourcePolicy(iamPolicyLogicalId, change, evaluateCfnTemplate) { const roles = change.newValue.Properties?.Roles; if (!roles) { return (0, common_1.reportNonHotswappableResource)(change, 'This IAM Policy does not have have any Roles'); } for (const role of roles) { const roleArn = await evaluateCfnTemplate.evaluateCfnExpression(role); const roleLogicalId = await evaluateCfnTemplate.findLogicalIdForPhysicalName(roleArn); if (!roleLogicalId) { return (0, common_1.reportNonHotswappableResource)(change, `could not find logicalId for role with name '${roleArn}'`); } const roleRefs = evaluateCfnTemplate.findReferencesTo(roleLogicalId); for (const roleRef of roleRefs) { if (roleRef.Type === 'AWS::Lambda::Function') { const lambdaRefs = evaluateCfnTemplate.findReferencesTo(roleRef.LogicalId); for (const lambdaRef of lambdaRefs) { // If S3Deployment -> Lambda -> Role and IAM::Policy -> Role, then this IAM::Policy change is an // artifact of old-style synthesis if (lambdaRef.Type !== 'Custom::CDKBucketDeployment') { return (0, common_1.reportNonHotswappableResource)(change, `found an AWS::IAM::Policy that has Role '${roleLogicalId}' that is referred to by AWS::Lambda::Function '${roleRef.LogicalId}' that is referred to by ${lambdaRef.Type} '${lambdaRef.LogicalId}', which does not have type 'Custom::CDKBucketDeployment'`); } } } else if (roleRef.Type === 'AWS::IAM::Policy') { if (roleRef.LogicalId !== iamPolicyLogicalId) { return (0, common_1.reportNonHotswappableResource)(change, `found an AWS::IAM::Policy that has Role '${roleLogicalId}' that is referred to by AWS::IAM::Policy '${roleRef.LogicalId}' that is not the policy of the s3 bucket deployment`); } } else { return (0, common_1.reportNonHotswappableResource)(change, `found a resource which refers to the role '${roleLogicalId}' that is not of type AWS::Lambda::Function or AWS::IAM::Policy, so the bucket deployment cannot be hotswapped`); } } } // this doesn't block the hotswap, but it also isn't a hotswappable change by itself. Return // an empty change to signify this. return []; } function stringifyObject(obj) { if (obj == null) { return obj; } if (Array.isArray(obj)) { return obj.map(stringifyObject); } if (typeof obj !== 'object') { return obj.toString(); } const ret = {}; for (const [k, v] of Object.entries(obj)) { ret[k] = stringifyObject(v); } return ret; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiczMtYnVja2V0LWRlcGxveW1lbnRzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiczMtYnVja2V0LWRlcGxveW1lbnRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFDQUEyRztBQUkzRzs7O0dBR0c7QUFDVSxRQUFBLGVBQWUsR0FBRywrQkFBK0IsQ0FBQztBQUV4RCxLQUFLLFVBQVUsc0NBQXNDLENBQzFELFNBQWlCLEVBQUUsTUFBbUMsRUFBRSxtQkFBbUQ7SUFFM0csa0dBQWtHO0lBQ2xHLHVGQUF1RjtJQUN2RixNQUFNLEdBQUcsR0FBd0IsRUFBRSxDQUFDO0lBQ3BDLElBQUksTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEtBQUssa0JBQWtCLEVBQUU7UUFDL0MsT0FBTyx1Q0FBdUMsQ0FBQyxTQUFTLEVBQUUsTUFBTSxFQUFFLG1CQUFtQixDQUFDLENBQUM7S0FDeEY7SUFFRCxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLDZCQUE2QixFQUFFO1FBQzFELE9BQU8sRUFBRSxDQUFDO0tBQ1g7SUFFRCx1R0FBdUc7SUFDdkcsTUFBTSx3QkFBd0IsR0FBRyxNQUFNLG1CQUFtQixDQUFDLHFCQUFxQixDQUFDO1FBQy9FLEdBQUcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxVQUFVO1FBQzdCLFlBQVksRUFBRSxTQUFTO0tBQ3hCLENBQUMsQ0FBQztJQUVILEdBQUcsQ0FBQyxJQUFJLENBQUM7UUFDUCxZQUFZLEVBQUUsSUFBSTtRQUNsQixZQUFZLEVBQUUsTUFBTSxDQUFDLFFBQVEsQ0FBQyxJQUFJO1FBQ2xDLFlBQVksRUFBRSxDQUFDLEdBQUcsQ0FBQztRQUNuQixPQUFPLEVBQUUsc0JBQXNCO1FBQy9CLGFBQWEsRUFBRSxDQUFDLDBCQUEwQix3QkFBd0IsQ0FBQyxxQkFBcUIsR0FBRyxDQUFDO1FBQzVGLEtBQUssRUFBRSxLQUFLLEVBQUUsR0FBUyxFQUFFLEVBQUU7WUFDekIsd0hBQXdIO1lBQ3hILE1BQU0sWUFB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RUFBRSxDQUFDO0FBQ1osQ0FBQztBQUVELFNBQVMsZUFBZSxDQUFDLEdBQVE7SUFDL0IsSUFBSSxHQUFHLElBQUksSUFBSSxFQUFFO1FBQ2YsT0FBTyxHQUFHLENBQUM7S0FDWjtJQUNELElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRTtRQUN0QixPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUMsZUFBZSxDQUFDLENBQUM7S0FDakM7SUFDRCxJQUFJLE9BQU8sR0FBRyxLQUFLLFFBQVEsRUFBRTtRQUMzQixPQUFPLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztLQUN2QjtJQUVELE1BQU0sR0FBRyxHQUF5QixFQUFFLENBQUM7SUFDckMsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7UUFDeEMsR0FBRyxDQUFDLENBQUMsQ0FBQyxHQUFHLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQztLQUM3QjtJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENoYW5nZUhvdHN3YXBSZXN1bHQsIEhvdHN3YXBwYWJsZUNoYW5nZUNhbmRpZGF0ZSwgcmVwb3J0Tm9uSG90c3dhcHBhYmxlUmVzb3VyY2UgfSBmcm9tICcuL2NvbW1vbic7XG5pbXBvcnQgeyBJU0RLIH0gZnJvbSAnLi4vYXdzLWF1dGgnO1xuaW1wb3J0IHsgRXZhbHVhdGVDbG91ZEZvcm1hdGlvblRlbXBsYXRlIH0gZnJvbSAnLi4vZXZhbHVhdGUtY2xvdWRmb3JtYXRpb24tdGVtcGxhdGUnO1xuXG4vKipcbiAqIFRoaXMgbWVhbnMgdGhhdCB0aGUgdmFsdWUgaXMgcmVxdWlyZWQgdG8gZXhpc3QgYnkgQ2xvdWRGb3JtYXRpb24ncyBDdXN0b20gUmVzb3VyY2UgQVBJIChvciBvdXIgUzMgQnVja2V0IERlcGxveW1lbnQgTGFtYmRhJ3MgQVBJKVxuICogYnV0IHRoZSBhY3R1YWwgdmFsdWUgc3BlY2lmaWVkIGlzIGlycmVsZXZhbnRcbiAqL1xuZXhwb3J0IGNvbnN0IFJFUVVJUkVEX0JZX0NGTiA9ICdyZXF1aXJlZC10by1iZS1wcmVzZW50LWJ5LWNmbic7XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpc0hvdHN3YXBwYWJsZVMzQnVja2V0RGVwbG95bWVudENoYW5nZShcbiAgbG9naWNhbElkOiBzdHJpbmcsIGNoYW5nZTogSG90c3dhcHBhYmxlQ2hhbmdlQ2FuZGlkYXRlLCBldmFsdWF0ZUNmblRlbXBsYXRlOiBFdmFsdWF0ZUNsb3VkRm9ybWF0aW9uVGVtcGxhdGUsXG4pOiBQcm9taXNlPENoYW5nZUhvdHN3YXBSZXN1bHQ+IHtcbiAgLy8gSW4gb2xkLXN0eWxlIHN5bnRoZXNpcywgdGhlIHBvbGljeSB1c2VkIGJ5IHRoZSBsYW1iZGEgdG8gY29weSBhc3NldHMgUmVmJ3MgdGhlIGFzc2V0cyBkaXJlY3RseSxcbiAgLy8gbWVhbmluZyB0aGF0IHRoZSBjaGFuZ2VzIG1hZGUgdG8gdGhlIFBvbGljeSBhcmUgYXJ0aWZhY3RzIHRoYXQgY2FuIGJlIHNhZmVseSBpZ25vcmVkXG4gIGNvbnN0IHJldDogQ2hhbmdlSG90c3dhcFJlc3VsdCA9IFtdO1xuICBpZiAoY2hhbmdlLm5ld1ZhbHVlLlR5cGUgPT09ICdBV1M6OklBTTo6UG9saWN5Jykge1xuICAgIHJldHVybiBjaGFuZ2VJc0ZvclMzRGVwbG95Q3VzdG9tUmVzb3VyY2VQb2xpY3kobG9naWNhbElkLCBjaGFuZ2UsIGV2YWx1YXRlQ2ZuVGVtcGxhdGUpO1xuICB9XG5cbiAgaWYgKGNoYW5nZS5uZXdWYWx1ZS5UeXBlICE9PSAnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50Jykge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIC8vIG5vIGNsYXNzaWZpY2F0aW9uIHRvIGJlIGRvbmUgaGVyZTsgYWxsIHRoZSBwcm9wZXJ0aWVzIG9mIHRoaXMgY3VzdG9tIHJlc291cmNlIHRoaW5nIGFyZSBob3Rzd2FwcGFibGVcbiAgY29uc3QgY3VzdG9tUmVzb3VyY2VQcm9wZXJ0aWVzID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5ldmFsdWF0ZUNmbkV4cHJlc3Npb24oe1xuICAgIC4uLmNoYW5nZS5uZXdWYWx1ZS5Qcm9wZXJ0aWVzLFxuICAgIFNlcnZpY2VUb2tlbjogdW5kZWZpbmVkLFxuICB9KTtcblxuICByZXQucHVzaCh7XG4gICAgaG90c3dhcHBhYmxlOiB0cnVlLFxuICAgIHJlc291cmNlVHlwZTogY2hhbmdlLm5ld1ZhbHVlLlR5cGUsXG4gICAgcHJvcHNDaGFuZ2VkOiBbJyonXSxcbiAgICBzZXJ2aWNlOiAnY3VzdG9tLXMzLWRlcGxveW1lbnQnLFxuICAgIHJlc291cmNlTmFtZXM6IFtgQ29udGVudHMgb2YgUzMgQnVja2V0ICcke2N1c3RvbVJlc291cmNlUHJvcGVydGllcy5EZXN0aW5hdGlvbkJ1Y2tldE5hbWV9J2BdLFxuICAgIGFwcGx5OiBhc3luYyAoc2RrOiBJU0RLKSA9PiB7XG4gICAgICAvLyBub3RlIHRoYXQgdGhpcyBnaXZlcyB0aGUgQVJOIG9mIHRoZSBsYW1iZGEsIG5vdCB0aGUgbmFtZS4gVGhpcyBpcyBmaW5lIHRob3VnaCwgdGhlIGludm9rZSgpIHNkayBjYWxsIHdpbGwgdGFrZSBlaXRoZXJcbiAgICAgIGNvbnN0IGZ1bmN0aW9uTmFtZSA9IGF3YWl0IGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZXZhbHVhdGVDZm5FeHByZXNzaW9uKGNoYW5nZS5uZXdWYWx1ZS5Qcm9wZXJ0aWVzPy5TZXJ2aWNlVG9rZW4pO1xuICAgICAgaWYgKCFmdW5jdGlvbk5hbWUpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBhd2FpdCBzZGsubGFtYmRhKCkuaW52b2tlKHtcbiAgICAgICAgRnVuY3Rpb25OYW1lOiBmdW5jdGlvbk5hbWUsXG4gICAgICAgIC8vIExhbWJkYSByZWZ1c2VzIHRvIHRha2UgYSBkaXJlY3QgSlNPTiBvYmplY3QgYW5kIHJlcXVpcmVzIGl0IHRvIGJlIHN0cmluZ2lmeSgpJ2RcbiAgICAgICAgUGF5bG9hZDogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgIFJlcXVlc3RUeXBlOiAnVXBkYXRlJyxcbiAgICAgICAgICBSZXNwb25zZVVSTDogUkVRVUlSRURfQllfQ0ZOLFxuICAgICAgICAgIFBoeXNpY2FsUmVzb3VyY2VJZDogUkVRVUlSRURfQllfQ0ZOLFxuICAgICAgICAgIFN0YWNrSWQ6IFJFUVVJUkVEX0JZX0NGTixcbiAgICAgICAgICBSZXF1ZXN0SWQ6IFJFUVVJUkVEX0JZX0NGTixcbiAgICAgICAgICBMb2dpY2FsUmVzb3VyY2VJZDogUkVRVUlSRURfQllfQ0ZOLFxuICAgICAgICAgIFJlc291cmNlUHJvcGVydGllczogc3RyaW5naWZ5T2JqZWN0KGN1c3RvbVJlc291cmNlUHJvcGVydGllcyksIC8vIEpTT04uc3RyaW5naWZ5KCkgZG9lc24ndCB0dXJuIHRoZSBhY3R1YWwgb2JqZWN0cyB0byBzdHJpbmdzLCBidXQgdGhlIGxhbWJkYSBleHBlY3RzIHN0cmluZ3NcbiAgICAgICAgfSksXG4gICAgICB9KS5wcm9taXNlKCk7XG4gICAgfSxcbiAgfSk7XG5cbiAgcmV0dXJuIHJldDtcbn1cblxuYXN5bmMgZnVuY3Rpb24gY2hhbmdlSXNGb3JTM0RlcGxveUN1c3RvbVJlc291cmNlUG9saWN5KFxuICBpYW1Qb2xpY3lMb2dpY2FsSWQ6IHN0cmluZywgY2hhbmdlOiBIb3Rzd2FwcGFibGVDaGFuZ2VDYW5kaWRhdGUsIGV2YWx1YXRlQ2ZuVGVtcGxhdGU6IEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSxcbik6IFByb21pc2U8Q2hhbmdlSG90c3dhcFJlc3VsdD4ge1xuICBjb25zdCByb2xlcyA9IGNoYW5nZS5uZXdWYWx1ZS5Qcm9wZXJ0aWVzPy5Sb2xlcztcbiAgaWYgKCFyb2xlcykge1xuICAgIHJldHVybiByZXBvcnROb25Ib3Rzd2FwcGFibGVSZXNvdXJjZShcbiAgICAgIGNoYW5nZSxcbiAgICAgICdUaGlzIElBTSBQb2xpY3kgZG9lcyBub3QgaGF2ZSBoYXZlIGFueSBSb2xlcycsXG4gICAgKTtcbiAgfVxuXG4gIGZvciAoY29uc3Qgcm9sZSBvZiByb2xlcykge1xuICAgIGNvbnN0IHJvbGVBcm4gPSBhd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmV2YWx1YXRlQ2ZuRXhwcmVzc2lvbihyb2xlKTtcbiAgICBjb25zdCByb2xlTG9naWNhbElkID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5maW5kTG9naWNhbElkRm9yUGh5c2ljYWxOYW1lKHJvbGVBcm4pO1xuICAgIGlmICghcm9sZUxvZ2ljYWxJZCkge1xuICAgICAgcmV0dXJuIHJlcG9ydE5vbkhvdHN3YXBwYWJsZVJlc291cmNlKFxuICAgICAgICBjaGFuZ2UsXG4gICAgICAgIGBjb3VsZCBub3QgZmluZCBsb2dpY2FsSWQgZm9yIHJvbGUgd2l0aCBuYW1lICcke3JvbGVBcm59J2AsXG4gICAgICApO1xuICAgIH1cblxuICAgIGNvbnN0IHJvbGVSZWZzID0gZXZhbHVhdGVDZm5UZW1wbGF0ZS5maW5kUmVmZXJlbmNlc1RvKHJvbGVMb2dpY2FsSWQpO1xuICAgIGZvciAoY29uc3Qgcm9sZVJlZiBvZiByb2xlUmVmcykge1xuICAgICAgaWYgKHJvbGVSZWYuVHlwZSA9PT0gJ0FXUzo6TGFtYmRhOjpGdW5jdGlvbicpIHtcbiAgICAgICAgY29uc3QgbGFtYmRhUmVmcyA9IGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZmluZFJlZmVyZW5jZXNUbyhyb2xlUmVmLkxvZ2ljYWxJZCk7XG4gICAgICAgIGZvciAoY29uc3QgbGFtYmRhUmVmIG9mIGxhbWJkYVJlZnMpIHtcbiAgICAgICAgICAvLyBJZiBTM0RlcGxveW1lbnQgLT4gTGFtYmRhIC0+IFJvbGUgYW5kIElBTTo6UG9saWN5IC0+IFJvbGUsIHRoZW4gdGhpcyBJQU06OlBvbGljeSBjaGFuZ2UgaXMgYW5cbiAgICAgICAgICAvLyBhcnRpZmFjdCBvZiBvbGQtc3R5bGUgc3ludGhlc2lzXG4gICAgICAgICAgaWYgKGxhbWJkYVJlZi5UeXBlICE9PSAnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50Jykge1xuICAgICAgICAgICAgcmV0dXJuIHJlcG9ydE5vbkhvdHN3YXBwYWJsZVJlc291cmNlKFxuICAgICAgICAgICAgICBjaGFuZ2UsXG4gICAgICAgICAgICAgIGBmb3VuZCBhbiBBV1M6OklBTTo6UG9saWN5IHRoYXQgaGFzIFJvbGUgJyR7cm9sZUxvZ2ljYWxJZH0nIHRoYXQgaXMgcmVmZXJyZWQgdG8gYnkgQVdTOjpMYW1iZGE6OkZ1bmN0aW9uICcke3JvbGVSZWYuTG9naWNhbElkfScgdGhhdCBpcyByZWZlcnJlZCB0byBieSAke2xhbWJkYVJlZi5UeXBlfSAnJHtsYW1iZGFSZWYuTG9naWNhbElkfScsIHdoaWNoIGRvZXMgbm90IGhhdmUgdHlwZSAnQ3VzdG9tOjpDREtCdWNrZXREZXBsb3ltZW50J2AsXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIGlmIChyb2xlUmVmLlR5cGUgPT09ICdBV1M6OklBTTo6UG9saWN5Jykge1xuICAgICAgICBpZiAocm9sZVJlZi5Mb2dpY2FsSWQgIT09IGlhbVBvbGljeUxvZ2ljYWxJZCkge1xuICAgICAgICAgIHJldHVybiByZXBvcnROb25Ib3Rzd2FwcGFibGVSZXNvdXJjZShcbiAgICAgICAgICAgIGNoYW5nZSxcbiAgICAgICAgICAgIGBmb3VuZCBhbiBBV1M6OklBTTo6UG9saWN5IHRoYXQgaGFzIFJvbGUgJyR7cm9sZUxvZ2ljYWxJZH0nIHRoYXQgaXMgcmVmZXJyZWQgdG8gYnkgQVdTOjpJQU06OlBvbGljeSAnJHtyb2xlUmVmLkxvZ2ljYWxJZH0nIHRoYXQgaXMgbm90IHRoZSBwb2xpY3kgb2YgdGhlIHMzIGJ1Y2tldCBkZXBsb3ltZW50YCxcbiAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gcmVwb3J0Tm9uSG90c3dhcHBhYmxlUmVzb3VyY2UoXG4gICAgICAgICAgY2hhbmdlLFxuICAgICAgICAgIGBmb3VuZCBhIHJlc291cmNlIHdoaWNoIHJlZmVycyB0byB0aGUgcm9sZSAnJHtyb2xlTG9naWNhbElkfScgdGhhdCBpcyBub3Qgb2YgdHlwZSBBV1M6OkxhbWJkYTo6RnVuY3Rpb24gb3IgQVdTOjpJQU06OlBvbGljeSwgc28gdGhlIGJ1Y2tldCBkZXBsb3ltZW50IGNhbm5vdCBiZSBob3Rzd2FwcGVkYCxcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyB0aGlzIGRvZXNuJ3QgYmxvY2sgdGhlIGhvdHN3YXAsIGJ1dCBpdCBhbHNvIGlzbid0IGEgaG90c3dhcHBhYmxlIGNoYW5nZSBieSBpdHNlbGYuIFJldHVyblxuICAvLyBhbiBlbXB0eSBjaGFuZ2UgdG8gc2lnbmlmeSB0aGlzLlxuICByZXR1cm4gW107XG59XG5cbmZ1bmN0aW9uIHN0cmluZ2lmeU9iamVjdChvYmo6IGFueSk6IGFueSB7XG4gIGlmIChvYmogPT0gbnVsbCkge1xuICAgIHJldHVybiBvYmo7XG4gIH1cbiAgaWYgKEFycmF5LmlzQXJyYXkob2JqKSkge1xuICAgIHJldHVybiBvYmoubWFwKHN0cmluZ2lmeU9iamVjdCk7XG4gIH1cbiAgaWYgKHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIG9iai50b1N0cmluZygpO1xuICB9XG5cbiAgY29uc3QgcmV0OiB7IFtrOiBzdHJpbmddOiBhbnkgfSA9IHt9O1xuICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhvYmopKSB7XG4gICAgcmV0W2tdID0gc3RyaW5naWZ5T2JqZWN0KHYpO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG4iXX0=