UNPKG

aws-cdk

Version:

AWS CDK CLI, the command line tool for CDK apps

297 lines 48.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.isHotswappableLambdaFunctionChange = isHotswappableLambdaFunctionChange; const stream_1 = require("stream"); const common_1 = require("./common"); const api_1 = require("../../../../@aws-cdk/tmp-toolkit-helpers/src/api"); const util_1 = require("../../util"); const cloudformation_1 = require("../cloudformation"); // namespace object imports won't work in the bundle for function exports // eslint-disable-next-line @typescript-eslint/no-require-imports const archiver = require('archiver'); async function isHotswappableLambdaFunctionChange(logicalId, change, evaluateCfnTemplate) { // if the change is for a Lambda Version, we just ignore it // we will publish a new version when we get to hotswapping the actual Function this Version points to // (Versions can't be changed in CloudFormation anyway, they're immutable) if (change.newValue.Type === 'AWS::Lambda::Version') { return []; } // we handle Aliases specially too // the actual alias update will happen if we change the function if (change.newValue.Type === 'AWS::Lambda::Alias') { return classifyAliasChanges(change); } if (change.newValue.Type !== 'AWS::Lambda::Function') { return []; } const ret = []; const classifiedChanges = (0, common_1.classifyChanges)(change, ['Code', 'Environment', 'Description']); classifiedChanges.reportNonHotswappablePropertyChanges(ret); const functionName = await evaluateCfnTemplate.establishResourcePhysicalName(logicalId, change.newValue.Properties?.FunctionName); const namesOfHotswappableChanges = Object.keys(classifiedChanges.hotswappableProps); if (functionName && namesOfHotswappableChanges.length > 0) { const lambdaCodeChange = await evaluateLambdaFunctionProps(classifiedChanges.hotswappableProps, change.newValue.Properties?.Runtime, evaluateCfnTemplate); // nothing to do here if (lambdaCodeChange === undefined) { return ret; } const dependencies = await dependantResources(logicalId, functionName, evaluateCfnTemplate); ret.push({ change: { cause: change, resources: [ { logicalId, resourceType: change.newValue.Type, physicalName: functionName, metadata: evaluateCfnTemplate.metadataFor(logicalId), }, ...dependencies, ], }, hotswappable: true, service: 'lambda', apply: async (sdk) => { const lambda = sdk.lambda(); const operations = []; if (lambdaCodeChange.code !== undefined || lambdaCodeChange.configurations !== undefined) { if (lambdaCodeChange.code !== undefined) { const updateFunctionCodeResponse = await lambda.updateFunctionCode({ FunctionName: functionName, S3Bucket: lambdaCodeChange.code.s3Bucket, S3Key: lambdaCodeChange.code.s3Key, ImageUri: lambdaCodeChange.code.imageUri, ZipFile: lambdaCodeChange.code.functionCodeZip, S3ObjectVersion: lambdaCodeChange.code.s3ObjectVersion, }); await waitForLambdasPropertiesUpdateToFinish(updateFunctionCodeResponse, lambda, functionName); } if (lambdaCodeChange.configurations !== undefined) { const updateRequest = { FunctionName: functionName, }; if (lambdaCodeChange.configurations.description !== undefined) { updateRequest.Description = lambdaCodeChange.configurations.description; } if (lambdaCodeChange.configurations.environment !== undefined) { updateRequest.Environment = lambdaCodeChange.configurations.environment; } const updateFunctionCodeResponse = await lambda.updateFunctionConfiguration(updateRequest); await waitForLambdasPropertiesUpdateToFinish(updateFunctionCodeResponse, lambda, functionName); } // only if the code changed is there any point in publishing a new Version const versions = dependencies.filter((d) => d.resourceType === 'AWS::Lambda::Version'); if (versions.length) { const publishVersionPromise = lambda.publishVersion({ FunctionName: functionName, }); const aliases = dependencies.filter((d) => d.resourceType === 'AWS::Lambda::Alias'); if (aliases.length) { // we need to wait for the Version to finish publishing const versionUpdate = await publishVersionPromise; for (const alias of aliases) { operations.push(lambda.updateAlias({ FunctionName: functionName, Name: alias.physicalName, FunctionVersion: versionUpdate.Version, })); } } else { operations.push(publishVersionPromise); } } } // run all of our updates in parallel // Limited set of updates per function // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism await Promise.all(operations); }, }); } return ret; } /** * Determines which changes to this Alias are hotswappable or not */ function classifyAliasChanges(change) { const ret = []; const classifiedChanges = (0, common_1.classifyChanges)(change, ['FunctionVersion']); classifiedChanges.reportNonHotswappablePropertyChanges(ret); // we only want to report not hotswappable changes to aliases // the actual alias update will happen if we change the function return ret; } /** * Evaluates the hotswappable properties of an AWS::Lambda::Function and * Returns a `LambdaFunctionChange` if the change is hotswappable. * Returns `undefined` if the change is not hotswappable. */ async function evaluateLambdaFunctionProps(hotswappablePropChanges, runtime, evaluateCfnTemplate) { /* * At first glance, we would want to initialize these using the "previous" values (change.oldValue), * in case only one of them changed, like the key, and the Bucket stayed the same. * However, that actually fails for old-style synthesis, which uses CFN Parameters! * Because the names of the Parameters depend on the hash of the Asset, * the Parameters used for the "old" values no longer exist in `assetParams` at this point, * which means we don't have the correct values available to evaluate the CFN expression with. * Fortunately, the diff will always include both the s3Bucket and s3Key parts of the Lambda's Code property, * even if only one of them was actually changed, * which means we don't need the "old" values at all, and we can safely initialize these with just `''`. */ let code = undefined; let description = undefined; let environment = undefined; for (const updatedPropName in hotswappablePropChanges) { const updatedProp = hotswappablePropChanges[updatedPropName]; switch (updatedPropName) { case 'Code': let s3Bucket, s3Key, s3ObjectVersion, imageUri, functionCodeZip; for (const newPropName in updatedProp.newValue) { switch (newPropName) { case 'S3Bucket': s3Bucket = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'S3Key': s3Key = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'S3ObjectVersion': s3ObjectVersion = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'ImageUri': imageUri = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); break; case 'ZipFile': // We must create a zip package containing a file with the inline code const functionCode = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue[newPropName]); const functionRuntime = await evaluateCfnTemplate.evaluateCfnExpression(runtime); if (!functionRuntime) { return undefined; } // file extension must be chosen depending on the runtime const codeFileExt = determineCodeFileExtFromRuntime(functionRuntime); functionCodeZip = await zipString(`index.${codeFileExt}`, functionCode); break; } } code = { s3Bucket, s3Key, s3ObjectVersion, imageUri, functionCodeZip, }; break; case 'Description': description = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue); break; case 'Environment': environment = await evaluateCfnTemplate.evaluateCfnExpression(updatedProp.newValue); break; default: // we will never get here, but just in case we do throw an error throw new api_1.ToolkitError('while apply()ing, found a property that cannot be hotswapped. Please report this at github.com/aws/aws-cdk/issues/new/choose'); } } const configurations = description || environment ? { description, environment } : undefined; return code || configurations ? { code, configurations } : undefined; } /** * Compress a string as a file, returning a promise for the zip buffer * https://github.com/archiverjs/node-archiver/issues/342 */ function zipString(fileName, rawString) { return new Promise((resolve, reject) => { const buffers = []; const converter = new stream_1.Writable(); converter._write = (chunk, _, callback) => { buffers.push(chunk); process.nextTick(callback); }; converter.on('finish', () => { resolve(Buffer.concat(buffers)); }); const archive = archiver('zip'); archive.on('error', (err) => { reject(err); }); archive.pipe(converter); archive.append(rawString, { name: fileName, date: new Date('1980-01-01T00:00:00.000Z'), // Add date to make resulting zip file deterministic }); void archive.finalize(); }); } /** * After a Lambda Function is updated, it cannot be updated again until the * `State=Active` and the `LastUpdateStatus=Successful`. * * Depending on the configuration of the Lambda Function this could happen relatively quickly * or very slowly. For example, Zip based functions _not_ in a VPC can take ~1 second whereas VPC * or Container functions can take ~25 seconds (and 'idle' VPC functions can take minutes). */ async function waitForLambdasPropertiesUpdateToFinish(currentFunctionConfiguration, lambda, functionName) { const functionIsInVpcOrUsesDockerForCode = currentFunctionConfiguration.VpcConfig?.VpcId || currentFunctionConfiguration.PackageType === 'Image'; // if the function is deployed in a VPC or if it is a container image function // then the update will take much longer and we can wait longer between checks // otherwise, the update will be quick, so a 1-second delay is fine const delaySeconds = functionIsInVpcOrUsesDockerForCode ? 5 : 1; await lambda.waitUntilFunctionUpdated(delaySeconds, { FunctionName: functionName, }); } /** * Get file extension from Lambda runtime string. * We use this extension to create a deployment package from Lambda inline code. */ function determineCodeFileExtFromRuntime(runtime) { if (runtime.startsWith('node')) { return 'js'; } if (runtime.startsWith('python')) { return 'py'; } // Currently inline code only supports Node.js and Python, ignoring other runtimes. // https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-lambda-function-code.html#aws-properties-lambda-function-code-properties throw new cloudformation_1.CfnEvaluationException(`runtime ${runtime} is unsupported, only node.js and python runtimes are currently supported.`); } /** * Finds all Versions that reference an AWS::Lambda::Function with logical ID `logicalId` * and Aliases that reference those Versions. */ async function versionsAndAliases(logicalId, evaluateCfnTemplate) { // find all Lambda Versions that reference this Function const versionsReferencingFunction = evaluateCfnTemplate .findReferencesTo(logicalId) .filter((r) => r.Type === 'AWS::Lambda::Version'); // find all Lambda Aliases that reference the above Versions const aliasesReferencingVersions = (0, util_1.flatMap)(versionsReferencingFunction, v => evaluateCfnTemplate.findReferencesTo(v.LogicalId)); return { versionsReferencingFunction, aliasesReferencingVersions }; } async function dependantResources(logicalId, functionName, evaluateCfnTemplate) { const candidates = await versionsAndAliases(logicalId, evaluateCfnTemplate); // Limited set of updates per function // eslint-disable-next-line @cdklabs/promiseall-no-unbounded-parallelism const aliases = await Promise.all(candidates.aliasesReferencingVersions.map(async (a) => { const name = await evaluateCfnTemplate.evaluateCfnExpression(a.Properties?.Name); return { logicalId: a.LogicalId, resourceType: a.Type, physicalName: name, description: `${a.Type} '${name}' for AWS::Lambda::Function '${functionName}'`, metadata: evaluateCfnTemplate.metadataFor(a.LogicalId), }; })); const versions = candidates.versionsReferencingFunction.map((v) => ({ logicalId: v.LogicalId, resourceType: v.Type, description: `${v.Type} for AWS::Lambda::Function '${functionName}'`, metadata: evaluateCfnTemplate.metadataFor(v.LogicalId), })); return [ ...versions, ...aliases, ]; } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGFtYmRhLWZ1bmN0aW9ucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImxhbWJkYS1mdW5jdGlvbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7QUFlQSxnRkErSEM7QUE5SUQsbUNBQWtDO0FBSWxDLHFDQUEyQztBQUMzQywwRUFBZ0Y7QUFFaEYscUNBQXFDO0FBRXJDLHNEQUFnRztBQUVoRyx5RUFBeUU7QUFDekUsaUVBQWlFO0FBQ2pFLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztBQUU5QixLQUFLLFVBQVUsa0NBQWtDLENBQ3RELFNBQWlCLEVBQ2pCLE1BQXNCLEVBQ3RCLG1CQUFtRDtJQUVuRCwyREFBMkQ7SUFDM0Qsc0dBQXNHO0lBQ3RHLDBFQUEwRTtJQUMxRSxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLHNCQUFzQixFQUFFLENBQUM7UUFDcEQsT0FBTyxFQUFFLENBQUM7SUFDWixDQUFDO0lBRUQsa0NBQWtDO0lBQ2xDLGdFQUFnRTtJQUNoRSxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxLQUFLLG9CQUFvQixFQUFFLENBQUM7UUFDbEQsT0FBTyxvQkFBb0IsQ0FBQyxNQUFNLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLElBQUksS0FBSyx1QkFBdUIsRUFBRSxDQUFDO1FBQ3JELE9BQU8sRUFBRSxDQUFDO0lBQ1osQ0FBQztJQUVELE1BQU0sR0FBRyxHQUFvQixFQUFFLENBQUM7SUFDaEMsTUFBTSxpQkFBaUIsR0FBRyxJQUFBLHdCQUFlLEVBQUMsTUFBTSxFQUFFLENBQUMsTUFBTSxFQUFFLGFBQWEsRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO0lBQzFGLGlCQUFpQixDQUFDLG9DQUFvQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRTVELE1BQU0sWUFBWSxHQUFHLE1BQU0sbUJBQW1CLENBQUMsNkJBQTZCLENBQzFFLFNBQVMs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QUMsQ0FBQyxTQUFTO1lBQ3RCLFlBQVksRUFBRSxDQUFDLENBQUMsSUFBSTtZQUNwQixZQUFZLEVBQUUsSUFBSTtZQUNsQixXQUFXLEVBQUUsR0FBRyxDQUFDLENBQUMsSUFBSSxLQUFLLElBQUksZ0NBQWdDLFlBQVksR0FBRztZQUM5RSxRQUFRLEVBQUUsbUJBQW1CLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7U0FDdkQsQ0FBQztJQUNKLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFFSixNQUFNLFFBQVEsR0FBRyxVQUFVLENBQUMsMkJBQTJCLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUNqRTtRQUNFLFNBQVMsRUFBRSxDQUFDLENBQUMsU0FBUztRQUN0QixZQUFZLEVBQUUsQ0FBQyxDQUFDLElBQUk7UUFDcEIsV0FBVyxFQUFFLEdBQUcsQ0FBQyxDQUFDLElBQUksK0JBQStCLFlBQVksR0FBRztRQUNwRSxRQUFRLEVBQUUsbUJBQW1CLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7S0FDdkQsQ0FDRixDQUFDLENBQUM7SUFFSCxPQUFPO1FBQ0wsR0FBRyxRQUFRO1FBQ1gsR0FBRyxPQUFPO0tBQ1gsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBXcml0YWJsZSB9IGZyb20gJ3N0cmVhbSc7XG5pbXBvcnQgdHlwZSB7IFByb3BlcnR5RGlmZmVyZW5jZSB9IGZyb20gJ0Bhd3MtY2RrL2Nsb3VkZm9ybWF0aW9uLWRpZmYnO1xuaW1wb3J0IHR5cGUgeyBGdW5jdGlvbkNvbmZpZ3VyYXRpb24sIFVwZGF0ZUZ1bmN0aW9uQ29uZmlndXJhdGlvbkNvbW1hbmRJbnB1dCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1sYW1iZGEnO1xuaW1wb3J0IHR5cGUgeyBIb3Rzd2FwQ2hhbmdlIH0gZnJvbSAnLi9jb21tb24nO1xuaW1wb3J0IHsgY2xhc3NpZnlDaGFuZ2VzIH0gZnJvbSAnLi9jb21tb24nO1xuaW1wb3J0IHsgVG9vbGtpdEVycm9yIH0gZnJvbSAnLi4vLi4vLi4vLi4vQGF3cy1jZGsvdG1wLXRvb2xraXQtaGVscGVycy9zcmMvYXBpJztcbmltcG9ydCB0eXBlIHsgQWZmZWN0ZWRSZXNvdXJjZSwgUmVzb3VyY2VDaGFuZ2UgfSBmcm9tICcuLi8uLi8uLi8uLi9AYXdzLWNkay90bXAtdG9vbGtpdC1oZWxwZXJzL3NyYy9hcGkvaW8vcGF5bG9hZHMvaG90c3dhcCc7XG5pbXBvcnQgeyBmbGF0TWFwIH0gZnJvbSAnLi4vLi4vdXRpbCc7XG5pbXBvcnQgdHlwZSB7IElMYW1iZGFDbGllbnQsIFNESyB9IGZyb20gJy4uL2F3cy1hdXRoJztcbmltcG9ydCB7IENmbkV2YWx1YXRpb25FeGNlcHRpb24sIHR5cGUgRXZhbHVhdGVDbG91ZEZvcm1hdGlvblRlbXBsYXRlIH0gZnJvbSAnLi4vY2xvdWRmb3JtYXRpb24nO1xuXG4vLyBuYW1lc3BhY2Ugb2JqZWN0IGltcG9ydHMgd29uJ3Qgd29yayBpbiB0aGUgYnVuZGxlIGZvciBmdW5jdGlvbiBleHBvcnRzXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXJlcXVpcmUtaW1wb3J0c1xuY29uc3QgYXJjaGl2ZXIgPSByZXF1aXJlKCdhcmNoaXZlcicpO1xuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNIb3Rzd2FwcGFibGVMYW1iZGFGdW5jdGlvbkNoYW5nZShcbiAgbG9naWNhbElkOiBzdHJpbmcsXG4gIGNoYW5nZTogUmVzb3VyY2VDaGFuZ2UsXG4gIGV2YWx1YXRlQ2ZuVGVtcGxhdGU6IEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSxcbik6IFByb21pc2U8SG90c3dhcENoYW5nZVtdPiB7XG4gIC8vIGlmIHRoZSBjaGFuZ2UgaXMgZm9yIGEgTGFtYmRhIFZlcnNpb24sIHdlIGp1c3QgaWdub3JlIGl0XG4gIC8vIHdlIHdpbGwgcHVibGlzaCBhIG5ldyB2ZXJzaW9uIHdoZW4gd2UgZ2V0IHRvIGhvdHN3YXBwaW5nIHRoZSBhY3R1YWwgRnVuY3Rpb24gdGhpcyBWZXJzaW9uIHBvaW50cyB0b1xuICAvLyAoVmVyc2lvbnMgY2FuJ3QgYmUgY2hhbmdlZCBpbiBDbG91ZEZvcm1hdGlvbiBhbnl3YXksIHRoZXkncmUgaW1tdXRhYmxlKVxuICBpZiAoY2hhbmdlLm5ld1ZhbHVlLlR5cGUgPT09ICdBV1M6OkxhbWJkYTo6VmVyc2lvbicpIHtcbiAgICByZXR1cm4gW107XG4gIH1cblxuICAvLyB3ZSBoYW5kbGUgQWxpYXNlcyBzcGVjaWFsbHkgdG9vXG4gIC8vIHRoZSBhY3R1YWwgYWxpYXMgdXBkYXRlIHdpbGwgaGFwcGVuIGlmIHdlIGNoYW5nZSB0aGUgZnVuY3Rpb25cbiAgaWYgKGNoYW5nZS5uZXdWYWx1ZS5UeXBlID09PSAnQVdTOjpMYW1iZGE6OkFsaWFzJykge1xuICAgIHJldHVybiBjbGFzc2lmeUFsaWFzQ2hhbmdlcyhjaGFuZ2UpO1xuICB9XG5cbiAgaWYgKGNoYW5nZS5uZXdWYWx1ZS5UeXBlICE9PSAnQVdTOjpMYW1iZGE6OkZ1bmN0aW9uJykge1xuICAgIHJldHVybiBbXTtcbiAgfVxuXG4gIGNvbnN0IHJldDogSG90c3dhcENoYW5nZVtdID0gW107XG4gIGNvbnN0IGNsYXNzaWZpZWRDaGFuZ2VzID0gY2xhc3NpZnlDaGFuZ2VzKGNoYW5nZSwgWydDb2RlJywgJ0Vudmlyb25tZW50JywgJ0Rlc2NyaXB0aW9uJ10pO1xuICBjbGFzc2lmaWVkQ2hhbmdlcy5yZXBvcnROb25Ib3Rzd2FwcGFibGVQcm9wZXJ0eUNoYW5nZXMocmV0KTtcblxuICBjb25zdCBmdW5jdGlvbk5hbWUgPSBhd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmVzdGFibGlzaFJlc291cmNlUGh5c2ljYWxOYW1lKFxuICAgIGxvZ2ljYWxJZCxcbiAgICBjaGFuZ2UubmV3VmFsdWUuUHJvcGVydGllcz8uRnVuY3Rpb25OYW1lLFxuICApO1xuICBjb25zdCBuYW1lc09mSG90c3dhcHBhYmxlQ2hhbmdlcyA9IE9iamVjdC5rZXlzKGNsYXNzaWZpZWRDaGFuZ2VzLmhvdHN3YXBwYWJsZVByb3BzKTtcbiAgaWYgKGZ1bmN0aW9uTmFtZSAmJiBuYW1lc09mSG90c3dhcHBhYmxlQ2hhbmdlcy5sZW5ndGggPiAwKSB7XG4gICAgY29uc3QgbGFtYmRhQ29kZUNoYW5nZSA9IGF3YWl0IGV2YWx1YXRlTGFtYmRhRnVuY3Rpb25Qcm9wcyhcbiAgICAgIGNsYXNzaWZpZWRDaGFuZ2VzLmhvdHN3YXBwYWJsZVByb3BzLFxuICAgICAgY2hhbmdlLm5ld1ZhbHVlLlByb3BlcnRpZXM/LlJ1bnRpbWUsXG4gICAgICBldmFsdWF0ZUNmblRlbXBsYXRlLFxuICAgICk7XG5cbiAgICAvLyBub3RoaW5nIHRvIGRvIGhlcmVcbiAgICBpZiAobGFtYmRhQ29kZUNoYW5nZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICByZXR1cm4gcmV0O1xuICAgIH1cblxuICAgIGNvbnN0IGRlcGVuZGVuY2llcyA9IGF3YWl0IGRlcGVuZGFudFJlc291cmNlcyhsb2dpY2FsSWQsIGZ1bmN0aW9uTmFtZSwgZXZhbHVhdGVDZm5UZW1wbGF0ZSk7XG5cbiAgICByZXQucHVzaCh7XG4gICAgICBjaGFuZ2U6IHtcbiAgICAgICAgY2F1c2U6IGNoYW5nZSxcbiAgICAgICAgcmVzb3VyY2VzOiBbXG4gICAgICAgICAge1xuICAgICAgICAgICAgbG9naWNhbElkLFxuICAgICAgICAgICAgcmVzb3VyY2VUeXBlOiBjaGFuZ2UubmV3VmFsdWUuVHlwZSxcbiAgICAgICAgICAgIHBoeXNpY2FsTmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgbWV0YWRhdGE6IGV2YWx1YXRlQ2ZuVGVtcGxhdGUubWV0YWRhdGFGb3IobG9naWNhbElkKSxcbiAgICAgICAgICB9LFxuICAgICAgICAgIC4uLmRlcGVuZGVuY2llcyxcbiAgICAgICAgXSxcbiAgICAgIH0sXG4gICAgICBob3Rzd2FwcGFibGU6IHRydWUsXG4gICAgICBzZXJ2aWNlOiAnbGFtYmRhJyxcbiAgICAgIGFwcGx5OiBhc3luYyAoc2RrOiBTREspID0+IHtcbiAgICAgICAgY29uc3QgbGFtYmRhID0gc2RrLmxhbWJkYSgpO1xuICAgICAgICBjb25zdCBvcGVyYXRpb25zOiBQcm9taXNlPGFueT5bXSA9IFtdO1xuXG4gICAgICAgIGlmIChsYW1iZGFDb2RlQ2hhbmdlLmNvZGUgIT09IHVuZGVmaW5lZCB8fCBsYW1iZGFDb2RlQ2hhbmdlLmNvbmZpZ3VyYXRpb25zICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBpZiAobGFtYmRhQ29kZUNoYW5nZS5jb2RlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZUZ1bmN0aW9uQ29kZVJlc3BvbnNlID0gYXdhaXQgbGFtYmRhLnVwZGF0ZUZ1bmN0aW9uQ29kZSh7XG4gICAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgICBTM0J1Y2tldDogbGFtYmRhQ29kZUNoYW5nZS5jb2RlLnMzQnVja2V0LFxuICAgICAgICAgICAgICBTM0tleTogbGFtYmRhQ29kZUNoYW5nZS5jb2RlLnMzS2V5LFxuICAgICAgICAgICAgICBJbWFnZVVyaTogbGFtYmRhQ29kZUNoYW5nZS5jb2RlLmltYWdlVXJpLFxuICAgICAgICAgICAgICBaaXBGaWxlOiBsYW1iZGFDb2RlQ2hhbmdlLmNvZGUuZnVuY3Rpb25Db2RlWmlwLFxuICAgICAgICAgICAgICBTM09iamVjdFZlcnNpb246IGxhbWJkYUNvZGVDaGFuZ2UuY29kZS5zM09iamVjdFZlcnNpb24sXG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgYXdhaXQgd2FpdEZvckxhbWJkYXNQcm9wZXJ0aWVzVXBkYXRlVG9GaW5pc2godXBkYXRlRnVuY3Rpb25Db2RlUmVzcG9uc2UsIGxhbWJkYSwgZnVuY3Rpb25OYW1lKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAobGFtYmRhQ29kZUNoYW5nZS5jb25maWd1cmF0aW9ucyAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBjb25zdCB1cGRhdGVSZXF1ZXN0OiBVcGRhdGVGdW5jdGlvbkNvbmZpZ3VyYXRpb25Db21tYW5kSW5wdXQgPSB7XG4gICAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmIChsYW1iZGFDb2RlQ2hhbmdlLmNvbmZpZ3VyYXRpb25zLmRlc2NyaXB0aW9uICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgdXBkYXRlUmVxdWVzdC5EZXNjcmlwdGlvbiA9IGxhbWJkYUNvZGVDaGFuZ2UuY29uZmlndXJhdGlvbnMuZGVzY3JpcHRpb247XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobGFtYmRhQ29kZUNoYW5nZS5jb25maWd1cmF0aW9ucy5lbnZpcm9ubWVudCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgIHVwZGF0ZVJlcXVlc3QuRW52aXJvbm1lbnQgPSBsYW1iZGFDb2RlQ2hhbmdlLmNvbmZpZ3VyYXRpb25zLmVudmlyb25tZW50O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgdXBkYXRlRnVuY3Rpb25Db2RlUmVzcG9uc2UgPSBhd2FpdCBsYW1iZGEudXBkYXRlRnVuY3Rpb25Db25maWd1cmF0aW9uKHVwZGF0ZVJlcXVlc3QpO1xuICAgICAgICAgICAgYXdhaXQgd2FpdEZvckxhbWJkYXNQcm9wZXJ0aWVzVXBkYXRlVG9GaW5pc2godXBkYXRlRnVuY3Rpb25Db2RlUmVzcG9uc2UsIGxhbWJkYSwgZnVuY3Rpb25OYW1lKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBvbmx5IGlmIHRoZSBjb2RlIGNoYW5nZWQgaXMgdGhlcmUgYW55IHBvaW50IGluIHB1Ymxpc2hpbmcgYSBuZXcgVmVyc2lvblxuICAgICAgICAgIGNvbnN0IHZlcnNpb25zID0gZGVwZW5kZW5jaWVzLmZpbHRlcigoZCkgPT4gZC5yZXNvdXJjZVR5cGUgPT09ICdBV1M6OkxhbWJkYTo6VmVyc2lvbicpO1xuICAgICAgICAgIGlmICh2ZXJzaW9ucy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IHB1Ymxpc2hWZXJzaW9uUHJvbWlzZSA9IGxhbWJkYS5wdWJsaXNoVmVyc2lvbih7XG4gICAgICAgICAgICAgIEZ1bmN0aW9uTmFtZTogZnVuY3Rpb25OYW1lLFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNvbnN0IGFsaWFzZXMgPSBkZXBlbmRlbmNpZXMuZmlsdGVyKChkKSA9PiBkLnJlc291cmNlVHlwZSA9PT0gJ0FXUzo6TGFtYmRhOjpBbGlhcycpO1xuICAgICAgICAgICAgaWYgKGFsaWFzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgIC8vIHdlIG5lZWQgdG8gd2FpdCBmb3IgdGhlIFZlcnNpb24gdG8gZmluaXNoIHB1Ymxpc2hpbmdcbiAgICAgICAgICAgICAgY29uc3QgdmVyc2lvblVwZGF0ZSA9IGF3YWl0IHB1Ymxpc2hWZXJzaW9uUHJvbWlzZTtcbiAgICAgICAgICAgICAgZm9yIChjb25zdCBhbGlhcyBvZiBhbGlhc2VzKSB7XG4gICAgICAgICAgICAgICAgb3BlcmF0aW9ucy5wdXNoKFxuICAgICAgICAgICAgICAgICAgbGFtYmRhLnVwZGF0ZUFsaWFzKHtcbiAgICAgICAgICAgICAgICAgICAgRnVuY3Rpb25OYW1lOiBmdW5jdGlvbk5hbWUsXG4gICAgICAgICAgICAgICAgICAgIE5hbWU6IGFsaWFzLnBoeXNpY2FsTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgRnVuY3Rpb25WZXJzaW9uOiB2ZXJzaW9uVXBkYXRlLlZlcnNpb24sXG4gICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBvcGVyYXRpb25zLnB1c2gocHVibGlzaFZlcnNpb25Qcm9taXNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBydW4gYWxsIG9mIG91ciB1cGRhdGVzIGluIHBhcmFsbGVsXG4gICAgICAgIC8vIExpbWl0ZWQgc2V0IG9mIHVwZGF0ZXMgcGVyIGZ1bmN0aW9uXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAY2RrbGFicy9wcm9taXNlYWxsLW5vLXVuYm91bmRlZC1wYXJhbGxlbGlzbVxuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChvcGVyYXRpb25zKTtcbiAgICAgIH0sXG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIERldGVybWluZXMgd2hpY2ggY2hhbmdlcyB0byB0aGlzIEFsaWFzIGFyZSBob3Rzd2FwcGFibGUgb3Igbm90XG4gKi9cbmZ1bmN0aW9uIGNsYXNzaWZ5QWxpYXNDaGFuZ2VzKGNoYW5nZTogUmVzb3VyY2VDaGFuZ2UpOiBIb3Rzd2FwQ2hhbmdlW10ge1xuICBjb25zdCByZXQ6IEhvdHN3YXBDaGFuZ2VbXSA9IFtdO1xuICBjb25zdCBjbGFzc2lmaWVkQ2hhbmdlcyA9IGNsYXNzaWZ5Q2hhbmdlcyhjaGFuZ2UsIFsnRnVuY3Rpb25WZXJzaW9uJ10pO1xuICBjbGFzc2lmaWVkQ2hhbmdlcy5yZXBvcnROb25Ib3Rzd2FwcGFibGVQcm9wZXJ0eUNoYW5nZXMocmV0KTtcblxuICAvLyB3ZSBvbmx5IHdhbnQgdG8gcmVwb3J0IG5vdCBob3Rzd2FwcGFibGUgY2hhbmdlcyB0byBhbGlhc2VzXG4gIC8vIHRoZSBhY3R1YWwgYWxpYXMgdXBkYXRlIHdpbGwgaGFwcGVuIGlmIHdlIGNoYW5nZSB0aGUgZnVuY3Rpb25cblxuICByZXR1cm4gcmV0O1xufVxuXG4vKipcbiAqIEV2YWx1YXRlcyB0aGUgaG90c3dhcHBhYmxlIHByb3BlcnRpZXMgb2YgYW4gQVdTOjpMYW1iZGE6OkZ1bmN0aW9uIGFuZFxuICogUmV0dXJucyBhIGBMYW1iZGFGdW5jdGlvbkNoYW5nZWAgaWYgdGhlIGNoYW5nZSBpcyBob3Rzd2FwcGFibGUuXG4gKiBSZXR1cm5zIGB1bmRlZmluZWRgIGlmIHRoZSBjaGFuZ2UgaXMgbm90IGhvdHN3YXBwYWJsZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZXZhbHVhdGVMYW1iZGFGdW5jdGlvblByb3BzKFxuICBob3Rzd2FwcGFibGVQcm9wQ2hhbmdlczogUmVjb3JkPHN0cmluZywgUHJvcGVydHlEaWZmZXJlbmNlPGFueT4+LFxuICBydW50aW1lOiBzdHJpbmcsXG4gIGV2YWx1YXRlQ2ZuVGVtcGxhdGU6IEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSxcbik6IFByb21pc2U8TGFtYmRhRnVuY3Rpb25DaGFuZ2UgfCB1bmRlZmluZWQ+IHtcbiAgLypcbiAgICogQXQgZmlyc3QgZ2xhbmNlLCB3ZSB3b3VsZCB3YW50IHRvIGluaXRpYWxpemUgdGhlc2UgdXNpbmcgdGhlIFwicHJldmlvdXNcIiB2YWx1ZXMgKGNoYW5nZS5vbGRWYWx1ZSksXG4gICAqIGluIGNhc2Ugb25seSBvbmUgb2YgdGhlbSBjaGFuZ2VkLCBsaWtlIHRoZSBrZXksIGFuZCB0aGUgQnVja2V0IHN0YXllZCB0aGUgc2FtZS5cbiAgICogSG93ZXZlciwgdGhhdCBhY3R1YWxseSBmYWlscyBmb3Igb2xkLXN0eWxlIHN5bnRoZXNpcywgd2hpY2ggdXNlcyBDRk4gUGFyYW1ldGVycyFcbiAgICogQmVjYXVzZSB0aGUgbmFtZXMgb2YgdGhlIFBhcmFtZXRlcnMgZGVwZW5kIG9uIHRoZSBoYXNoIG9mIHRoZSBBc3NldCxcbiAgICogdGhlIFBhcmFtZXRlcnMgdXNlZCBmb3IgdGhlIFwib2xkXCIgdmFsdWVzIG5vIGxvbmdlciBleGlzdCBpbiBgYXNzZXRQYXJhbXNgIGF0IHRoaXMgcG9pbnQsXG4gICAqIHdoaWNoIG1lYW5zIHdlIGRvbid0IGhhdmUgdGhlIGNvcnJlY3QgdmFsdWVzIGF2YWlsYWJsZSB0byBldmFsdWF0ZSB0aGUgQ0ZOIGV4cHJlc3Npb24gd2l0aC5cbiAgICogRm9ydHVuYXRlbHksIHRoZSBkaWZmIHdpbGwgYWx3YXlzIGluY2x1ZGUgYm90aCB0aGUgczNCdWNrZXQgYW5kIHMzS2V5IHBhcnRzIG9mIHRoZSBMYW1iZGEncyBDb2RlIHByb3BlcnR5LFxuICAgKiBldmVuIGlmIG9ubHkgb25lIG9mIHRoZW0gd2FzIGFjdHVhbGx5IGNoYW5nZWQsXG4gICAqIHdoaWNoIG1lYW5zIHdlIGRvbid0IG5lZWQgdGhlIFwib2xkXCIgdmFsdWVzIGF0IGFsbCwgYW5kIHdlIGNhbiBzYWZlbHkgaW5pdGlhbGl6ZSB0aGVzZSB3aXRoIGp1c3QgYCcnYC5cbiAgICovXG4gIGxldCBjb2RlOiBMYW1iZGFGdW5jdGlvbkNvZGUgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGxldCBkZXNjcmlwdGlvbjogc3RyaW5nIHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkO1xuICBsZXQgZW52aXJvbm1lbnQ6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH0gfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG5cbiAgZm9yIChjb25zdCB1cGRhdGVkUHJvcE5hbWUgaW4gaG90c3dhcHBhYmxlUHJvcENoYW5nZXMpIHtcbiAgICBjb25zdCB1cGRhdGVkUHJvcCA9IGhvdHN3YXBwYWJsZVByb3BDaGFuZ2VzW3VwZGF0ZWRQcm9wTmFtZV07XG5cbiAgICBzd2l0Y2ggKHVwZGF0ZWRQcm9wTmFtZSkge1xuICAgICAgY2FzZSAnQ29kZSc6XG4gICAgICAgIGxldCBzM0J1Y2tldCwgczNLZXksIHMzT2JqZWN0VmVyc2lvbiwgaW1hZ2VVcmksIGZ1bmN0aW9uQ29kZVppcDtcblxuICAgICAgICBmb3IgKGNvbnN0IG5ld1Byb3BOYW1lIGluIHVwZGF0ZWRQcm9wLm5ld1ZhbHVlKSB7XG4gICAgICAgICAgc3dpdGNoIChuZXdQcm9wTmFtZSkge1xuICAgICAgICAgICAgY2FzZSAnUzNCdWNrZXQnOlxuICAgICAgICAgICAgICBzM0J1Y2tldCA9IGF3YWl0IGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZXZhbHVhdGVDZm5FeHByZXNzaW9uKHVwZGF0ZWRQcm9wLm5ld1ZhbHVlW25ld1Byb3BOYW1lXSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnUzNLZXknOlxuICAgICAgICAgICAgICBzM0tleSA9IGF3YWl0IGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZXZhbHVhdGVDZm5FeHByZXNzaW9uKHVwZGF0ZWRQcm9wLm5ld1ZhbHVlW25ld1Byb3BOYW1lXSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSAnUzNPYmplY3RWZXJzaW9uJzpcbiAgICAgICAgICAgICAgczNPYmplY3RWZXJzaW9uID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5ldmFsdWF0ZUNmbkV4cHJlc3Npb24odXBkYXRlZFByb3AubmV3VmFsdWVbbmV3UHJvcE5hbWVdKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdJbWFnZVVyaSc6XG4gICAgICAgICAgICAgIGltYWdlVXJpID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5ldmFsdWF0ZUNmbkV4cHJlc3Npb24odXBkYXRlZFByb3AubmV3VmFsdWVbbmV3UHJvcE5hbWVdKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdaaXBGaWxlJzpcbiAgICAgICAgICAgICAgLy8gV2UgbXVzdCBjcmVhdGUgYSB6aXAgcGFja2FnZSBjb250YWluaW5nIGEgZmlsZSB3aXRoIHRoZSBpbmxpbmUgY29kZVxuICAgICAgICAgICAgICBjb25zdCBmdW5jdGlvbkNvZGUgPSBhd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmV2YWx1YXRlQ2ZuRXhwcmVzc2lvbih1cGRhdGVkUHJvcC5uZXdWYWx1ZVtuZXdQcm9wTmFtZV0pO1xuICAgICAgICAgICAgICBjb25zdCBmdW5jdGlvblJ1bnRpbWUgPSBhd2FpdCBldmFsdWF0ZUNmblRlbXBsYXRlLmV2YWx1YXRlQ2ZuRXhwcmVzc2lvbihydW50aW1lKTtcbiAgICAgICAgICAgICAgaWYgKCFmdW5jdGlvblJ1bnRpbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIC8vIGZpbGUgZXh0ZW5zaW9uIG11c3QgYmUgY2hvc2VuIGRlcGVuZGluZyBvbiB0aGUgcnVudGltZVxuICAgICAgICAgICAgICBjb25zdCBjb2RlRmlsZUV4dCA9IGRldGVybWluZUNvZGVGaWxlRXh0RnJvbVJ1bnRpbWUoZnVuY3Rpb25SdW50aW1lKTtcbiAgICAgICAgICAgICAgZnVuY3Rpb25Db2RlWmlwID0gYXdhaXQgemlwU3RyaW5nKGBpbmRleC4ke2NvZGVGaWxlRXh0fWAsIGZ1bmN0aW9uQ29kZSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb2RlID0ge1xuICAgICAgICAgIHMzQnVja2V0LFxuICAgICAgICAgIHMzS2V5LFxuICAgICAgICAgIHMzT2JqZWN0VmVyc2lvbixcbiAgICAgICAgICBpbWFnZVVyaSxcbiAgICAgICAgICBmdW5jdGlvbkNvZGVaaXAsXG4gICAgICAgIH07XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAnRGVzY3JpcHRpb24nOlxuICAgICAgICBkZXNjcmlwdGlvbiA9IGF3YWl0IGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZXZhbHVhdGVDZm5FeHByZXNzaW9uKHVwZGF0ZWRQcm9wLm5ld1ZhbHVlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlICdFbnZpcm9ubWVudCc6XG4gICAgICAgIGVudmlyb25tZW50ID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5ldmFsdWF0ZUNmbkV4cHJlc3Npb24odXBkYXRlZFByb3AubmV3VmFsdWUpO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIC8vIHdlIHdpbGwgbmV2ZXIgZ2V0IGhlcmUsIGJ1dCBqdXN0IGluIGNhc2Ugd2UgZG8gdGhyb3cgYW4gZXJyb3JcbiAgICAgICAgdGhyb3cgbmV3IFRvb2xraXRFcnJvcihcbiAgICAgICAgICAnd2hpbGUgYXBwbHkoKWluZywgZm91bmQgYSBwcm9wZXJ0eSB0aGF0IGNhbm5vdCBiZSBob3Rzd2FwcGVkLiBQbGVhc2UgcmVwb3J0IHRoaXMgYXQgZ2l0aHViLmNvbS9hd3MvYXdzLWNkay9pc3N1ZXMvbmV3L2Nob29zZScsXG4gICAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgY29uc3QgY29uZmlndXJhdGlvbnMgPSBkZXNjcmlwdGlvbiB8fCBlbnZpcm9ubWVudCA/IHsgZGVzY3JpcHRpb24sIGVudmlyb25tZW50IH0gOiB1bmRlZmluZWQ7XG4gIHJldHVybiBjb2RlIHx8IGNvbmZpZ3VyYXRpb25zID8geyBjb2RlLCBjb25maWd1cmF0aW9ucyB9IDogdW5kZWZpbmVkO1xufVxuXG5pbnRlcmZhY2UgTGFtYmRhRnVuY3Rpb25Db2RlIHtcbiAgcmVhZG9ubHkgczNCdWNrZXQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHMzS2V5Pzogc3RyaW5nO1xuICByZWFkb25seSBzM09iamVjdFZlcnNpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGltYWdlVXJpPzogc3RyaW5nO1xuICByZWFkb25seSBmdW5jdGlvbkNvZGVaaXA/OiBCdWZmZXI7XG59XG5cbmludGVyZmFjZSBMYW1iZGFGdW5jdGlvbkNvbmZpZ3VyYXRpb25zIHtcbiAgcmVhZG9ubHkgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGVudmlyb25tZW50PzogeyBba2V5OiBzdHJpbmddOiBzdHJpbmcgfTtcbn1cblxuaW50ZXJmYWNlIExhbWJkYUZ1bmN0aW9uQ2hhbmdlIHtcbiAgcmVhZG9ubHkgY29kZT86IExhbWJkYUZ1bmN0aW9uQ29kZTtcbiAgcmVhZG9ubHkgY29uZmlndXJhdGlvbnM/OiBMYW1iZGFGdW5jdGlvbkNvbmZpZ3VyYXRpb25zO1xufVxuXG4vKipcbiAqIENvbXByZXNzIGEgc3RyaW5nIGFzIGEgZmlsZSwgcmV0dXJuaW5nIGEgcHJvbWlzZSBmb3IgdGhlIHppcCBidWZmZXJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9hcmNoaXZlcmpzL25vZGUtYXJjaGl2ZXIvaXNzdWVzLzM0MlxuICovXG5mdW5jdGlvbiB6aXBTdHJpbmcoZmlsZU5hbWU6IHN0cmluZywgcmF3U3RyaW5nOiBzdHJpbmcpOiBQcm9taXNlPEJ1ZmZlcj4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IGJ1ZmZlcnM6IEJ1ZmZlcltdID0gW107XG5cbiAgICBjb25zdCBjb252ZXJ0ZXIgPSBuZXcgV3JpdGFibGUoKTtcblxuICAgIGNvbnZlcnRlci5fd3JpdGUgPSAoY2h1bms6IEJ1ZmZlciwgXzogc3RyaW5nLCBjYWxsYmFjazogKCkgPT4gdm9pZCkgPT4ge1xuICAgICAgYnVmZmVycy5wdXNoKGNodW5rKTtcbiAgICAgIHByb2Nlc3MubmV4dFRpY2soY2FsbGJhY2spO1xuICAgIH07XG5cbiAgICBjb252ZXJ0ZXIub24oJ2ZpbmlzaCcsICgpID0+IHtcbiAgICAgIHJlc29sdmUoQnVmZmVyLmNvbmNhdChidWZmZXJzKSk7XG4gICAgfSk7XG5cbiAgICBjb25zdCBhcmNoaXZlID0gYXJjaGl2ZXIoJ3ppcCcpO1xuXG4gICAgYXJjaGl2ZS5vbignZXJyb3InLCAoZXJyOiBhbnkpID0+IHtcbiAgICAgIHJlamVjdChlcnIpO1xuICAgIH0pO1xuXG4gICAgYXJjaGl2ZS5waXBlKGNvbnZlcnRlcik7XG5cbiAgICBhcmNoaXZlLmFwcGVuZChyYXdTdHJpbmcsIHtcbiAgICAgIG5hbWU6IGZpbGVOYW1lLFxuICAgICAgZGF0ZTogbmV3IERhdGUoJzE5ODAtMDEtMDFUMDA6MDA6MDAuMDAwWicpLCAvLyBBZGQgZGF0ZSB0byBtYWtlIHJlc3VsdGluZyB6aXAgZmlsZSBkZXRlcm1pbmlzdGljXG4gICAgfSk7XG5cbiAgICB2b2lkIGFyY2hpdmUuZmluYWxpemUoKTtcbiAgfSk7XG59XG5cbi8qKlxuICogQWZ0ZXIgYSBMYW1iZGEgRnVuY3Rpb24gaXMgdXBkYXRlZCwgaXQgY2Fubm90IGJlIHVwZGF0ZWQgYWdhaW4gdW50aWwgdGhlXG4gKiBgU3RhdGU9QWN0aXZlYCBhbmQgdGhlIGBMYXN0VXBkYXRlU3RhdHVzPVN1Y2Nlc3NmdWxgLlxuICpcbiAqIERlcGVuZGluZyBvbiB0aGUgY29uZmlndXJhdGlvbiBvZiB0aGUgTGFtYmRhIEZ1bmN0aW9uIHRoaXMgY291bGQgaGFwcGVuIHJlbGF0aXZlbHkgcXVpY2tseVxuICogb3IgdmVyeSBzbG93bHkuIEZvciBleGFtcGxlLCBaaXAgYmFzZWQgZnVuY3Rpb25zIF9ub3RfIGluIGEgVlBDIGNhbiB0YWtlIH4xIHNlY29uZCB3aGVyZWFzIFZQQ1xuICogb3IgQ29udGFpbmVyIGZ1bmN0aW9ucyBjYW4gdGFrZSB+MjUgc2Vjb25kcyAoYW5kICdpZGxlJyBWUEMgZnVuY3Rpb25zIGNhbiB0YWtlIG1pbnV0ZXMpLlxuICovXG5hc3luYyBmdW5jdGlvbiB3YWl0Rm9yTGFtYmRhc1Byb3BlcnRpZXNVcGRhdGVUb0ZpbmlzaChcbiAgY3VycmVudEZ1bmN0aW9uQ29uZmlndXJhdGlvbjogRnVuY3Rpb25Db25maWd1cmF0aW9uLFxuICBsYW1iZGE6IElMYW1iZGFDbGllbnQsXG4gIGZ1bmN0aW9uTmFtZTogc3RyaW5nLFxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGZ1bmN0aW9uSXNJblZwY09yVXNlc0RvY2tlckZvckNvZGUgPVxuICAgIGN1cnJlbnRGdW5jdGlvbkNvbmZpZ3VyYXRpb24uVnBjQ29uZmlnPy5WcGNJZCB8fCBjdXJyZW50RnVuY3Rpb25Db25maWd1cmF0aW9uLlBhY2thZ2VUeXBlID09PSAnSW1hZ2UnO1xuXG4gIC8vIGlmIHRoZSBmdW5jdGlvbiBpcyBkZXBsb3llZCBpbiBhIFZQQyBvciBpZiBpdCBpcyBhIGNvbnRhaW5lciBpbWFnZSBmdW5jdGlvblxuICAvLyB0aGVuIHRoZSB1cGRhdGUgd2lsbCB0YWtlIG11Y2ggbG9uZ2VyIGFuZCB3ZSBjYW4gd2FpdCBsb25nZXIgYmV0d2VlbiBjaGVja3NcbiAgLy8gb3RoZXJ3aXNlLCB0aGUgdXBkYXRlIHdpbGwgYmUgcXVpY2ssIHNvIGEgMS1zZWNvbmQgZGVsYXkgaXMgZmluZVxuICBjb25zdCBkZWxheVNlY29uZHMgPSBmdW5jdGlvbklzSW5WcGNPclVzZXNEb2NrZXJGb3JDb2RlID8gNSA6IDE7XG5cbiAgYXdhaXQgbGFtYmRhLndhaXRVbnRpbEZ1bmN0aW9uVXBkYXRlZChkZWxheVNlY29uZHMsIHtcbiAgICBGdW5jdGlvbk5hbWU6IGZ1bmN0aW9uTmFtZSxcbiAgfSk7XG59XG5cbi8qKlxuICogR2V0IGZpbGUgZXh0ZW5zaW9uIGZyb20gTGFtYmRhIHJ1bnRpbWUgc3RyaW5nLlxuICogV2UgdXNlIHRoaXMgZXh0ZW5zaW9uIHRvIGNyZWF0ZSBhIGRlcGxveW1lbnQgcGFja2FnZSBmcm9tIExhbWJkYSBpbmxpbmUgY29kZS5cbiAqL1xuZnVuY3Rpb24gZGV0ZXJtaW5lQ29kZUZpbGVFeHRGcm9tUnVudGltZShydW50aW1lOiBzdHJpbmcpOiBzdHJpbmcge1xuICBpZiAocnVudGltZS5zdGFydHNXaXRoKCdub2RlJykpIHtcbiAgICByZXR1cm4gJ2pzJztcbiAgfVxuICBpZiAocnVudGltZS5zdGFydHNXaXRoKCdweXRob24nKSkge1xuICAgIHJldHVybiAncHknO1xuICB9XG4gIC8vIEN1cnJlbnRseSBpbmxpbmUgY29kZSBvbmx5IHN1cHBvcnRzIE5vZGUuanMgYW5kIFB5dGhvbiwgaWdub3Jpbmcgb3RoZXIgcnVudGltZXMuXG4gIC8vIGh0dHBzOi8vZG9jcy5hd3MuYW1hem9uLmNvbS9BV1NDbG91ZEZvcm1hdGlvbi9sYXRlc3QvVXNlckd1aWRlL2F3cy1wcm9wZXJ0aWVzLWxhbWJkYS1mdW5jdGlvbi1jb2RlLmh0bWwjYXdzLXByb3BlcnRpZXMtbGFtYmRhLWZ1bmN0aW9uLWNvZGUtcHJvcGVydGllc1xuICB0aHJvdyBuZXcgQ2ZuRXZhbHVhdGlvbkV4Y2VwdGlvbihcbiAgICBgcnVudGltZSAke3J1bnRpbWV9IGlzIHVuc3VwcG9ydGVkLCBvbmx5IG5vZGUuanMgYW5kIHB5dGhvbiBydW50aW1lcyBhcmUgY3VycmVudGx5IHN1cHBvcnRlZC5gLFxuICApO1xufVxuXG4vKipcbiAqIEZpbmRzIGFsbCBWZXJzaW9ucyB0aGF0IHJlZmVyZW5jZSBhbiBBV1M6OkxhbWJkYTo6RnVuY3Rpb24gd2l0aCBsb2dpY2FsIElEIGBsb2dpY2FsSWRgXG4gKiBhbmQgQWxpYXNlcyB0aGF0IHJlZmVyZW5jZSB0aG9zZSBWZXJzaW9ucy5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gdmVyc2lvbnNBbmRBbGlhc2VzKGxvZ2ljYWxJZDogc3RyaW5nLCBldmFsdWF0ZUNmblRlbXBsYXRlOiBFdmFsdWF0ZUNsb3VkRm9ybWF0aW9uVGVtcGxhdGUpIHtcbiAgLy8gZmluZCBhbGwgTGFtYmRhIFZlcnNpb25zIHRoYXQgcmVmZXJlbmNlIHRoaXMgRnVuY3Rpb25cbiAgY29uc3QgdmVyc2lvbnNSZWZlcmVuY2luZ0Z1bmN0aW9uID0gZXZhbHVhdGVDZm5UZW1wbGF0ZVxuICAgIC5maW5kUmVmZXJlbmNlc1RvKGxvZ2ljYWxJZClcbiAgICAuZmlsdGVyKChyKSA9PiByLlR5cGUgPT09ICdBV1M6OkxhbWJkYTo6VmVyc2lvbicpO1xuICAvLyBmaW5kIGFsbCBMYW1iZGEgQWxpYXNlcyB0aGF0IHJlZmVyZW5jZSB0aGUgYWJvdmUgVmVyc2lvbnNcbiAgY29uc3QgYWxpYXNlc1JlZmVyZW5jaW5nVmVyc2lvbnMgPSBmbGF0TWFwKHZlcnNpb25zUmVmZXJlbmNpbmdGdW5jdGlvbiwgdiA9PlxuICAgIGV2YWx1YXRlQ2ZuVGVtcGxhdGUuZmluZFJlZmVyZW5jZXNUbyh2LkxvZ2ljYWxJZCkpO1xuXG4gIHJldHVybiB7IHZlcnNpb25zUmVmZXJlbmNpbmdGdW5jdGlvbiwgYWxpYXNlc1JlZmVyZW5jaW5nVmVyc2lvbnMgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gZGVwZW5kYW50UmVzb3VyY2VzKFxuICBsb2dpY2FsSWQ6IHN0cmluZyxcbiAgZnVuY3Rpb25OYW1lOiBzdHJpbmcsXG4gIGV2YWx1YXRlQ2ZuVGVtcGxhdGU6IEV2YWx1YXRlQ2xvdWRGb3JtYXRpb25UZW1wbGF0ZSxcbik6IFByb21pc2U8QXJyYXk8QWZmZWN0ZWRSZXNvdXJjZT4+IHtcbiAgY29uc3QgY2FuZGlkYXRlcyA9IGF3YWl0IHZlcnNpb25zQW5kQWxpYXNlcyhsb2dpY2FsSWQsIGV2YWx1YXRlQ2ZuVGVtcGxhdGUpO1xuXG4gIC8vIExpbWl0ZWQgc2V0IG9mIHVwZGF0ZXMgcGVyIGZ1bmN0aW9uXG4gIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAY2RrbGFicy9wcm9taXNlYWxsLW5vLXVuYm91bmRlZC1wYXJhbGxlbGlzbVxuICBjb25zdCBhbGlhc2VzID0gYXdhaXQgUHJvbWlzZS5hbGwoY2FuZGlkYXRlcy5hbGlhc2VzUmVmZXJlbmNpbmdWZXJzaW9ucy5tYXAoYXN5bmMgKGEpID0+IHtcbiAgICBjb25zdCBuYW1lID0gYXdhaXQgZXZhbHVhdGVDZm5UZW1wbGF0ZS5ldmFsdWF0ZUNmbkV4cHJlc3Npb24oYS5Qcm9wZXJ0aWVzPy5OYW1lKTtcbiAgICByZXR1cm4ge1xuICAgICAgbG9naWNhbElkOiBhLkxvZ2ljYWxJZCxcbiAgICAgIHJlc291cmNlVHlwZTogYS5UeXBlLFxuICAgICAgcGh5c2ljYWxOYW1lOiBuYW1lLFxuICAgICAgZGVzY3JpcHRpb246IGAke2EuVHlwZX0gJyR7bmFtZX0nIGZvciBBV1M6OkxhbWJkYTo6RnVuY3Rpb24gJyR7ZnVuY3Rpb25OYW1lfSdgLFxuICAgICAgbWV0YWRhdGE6IGV2YWx1YXRlQ2ZuVGVtcGxhdGUubWV0YWRhdGFGb3IoYS5Mb2dpY2FsSWQpLFxuICAgIH07XG4gIH0pKTtcblxuICBjb25zdCB2ZXJzaW9ucyA9IGNhbmRpZGF0ZXMudmVyc2lvbnNSZWZlcmVuY2luZ0Z1bmN0aW9uLm1hcCgodikgPT4gKFxuICAgIHtcbiAgICAgIGxvZ2ljYWxJZDogdi5Mb2dpY2FsSWQsXG4gICAgICByZXNvdXJjZVR5cGU6IHYuVHlwZSxcbiAgICAgIGRlc2NyaXB0aW9uOiBgJHt2LlR5cGV9IGZvciBBV1M6OkxhbWJkYTo6RnVuY3Rpb24gJyR7ZnVuY3Rpb25OYW1lfSdgLFxuICAgICAgbWV0YWRhdGE6IGV2YWx1YXRlQ2ZuVGVtcGxhdGUubWV0YWRhdGFGb3Iodi5Mb2dpY2FsSWQpLFxuICAgIH1cbiAgKSk7XG5cbiAgcmV0dXJuIFtcbiAgICAuLi52ZXJzaW9ucyxcbiAgICAuLi5hbGlhc2VzLFxuICBdO1xufVxuIl19