cdk-nextjs-standalone
Version:
Deploy a NextJS app to AWS using CDK and OpenNext.
345 lines • 49.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.handler = void 0;
/* eslint-disable import/no-extraneous-dependencies */
const node_fs_1 = require("node:fs");
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const node_stream_1 = require("node:stream");
const client_s3_1 = require("@aws-sdk/client-s3");
const lib_storage_1 = require("@aws-sdk/lib-storage");
// @ts-ignore jsii doesn't support esModuleInterop
// eslint-disable-next-line no-duplicate-imports
const jszip_1 = require("jszip");
const micromatch = require("micromatch");
const mime = require("mime-types");
const JSZip = jszip_1.default;
const s3 = new client_s3_1.S3Client({});
const handler = async (event, context) => {
debug({ event });
let responseStatus = 'SUCCESS';
try {
if (event.RequestType === 'Create' || event.RequestType === 'Update') {
const props = getProperties(event);
let tmpDir = '';
const { assetsTmpDir, sourceDirPath, sourceZipFilePath } = initDirectories();
tmpDir = assetsTmpDir;
debug('Downloading zip');
await downloadFile({
bucket: props.sourceBucketName,
key: props.sourceKeyPrefix,
localDestinationPath: sourceZipFilePath,
});
debug('Extracting zip');
await extractZip({ sourceZipFilePath, destinationDirPath: sourceDirPath });
const filePaths = listFilePaths(sourceDirPath);
if (props.substitutionConfig && Object.keys(props.substitutionConfig).length) {
debug('Replacing environment variables: ' + JSON.stringify(props.substitutionConfig));
substitute({ config: props.substitutionConfig, filePaths });
}
// must find old object keys before uploading new objects so we know which objects to prune
const oldObjectKeys = await listOldObjectKeys({
bucketName: props.destinationBucketName,
keyPrefix: props.destinationKeyPrefix,
});
if (!props.zip) {
debug('Uploading objects to: ' + props.destinationBucketName);
await uploadObjects({
bucket: props.destinationBucketName,
keyPrefix: props.destinationKeyPrefix,
filePaths,
baseLocalDir: sourceDirPath,
putConfig: props.putConfig,
queueSize: props.queueSize,
});
if (props.prune) {
debug('Emptying/pruning bucket: ' + props.destinationBucketName);
await pruneBucket({
bucketName: props.destinationBucketName,
filePaths,
baseLocalDir: sourceDirPath,
keyPrefix: props.destinationKeyPrefix,
oldObjectKeys,
});
}
}
else {
debug('Uploading zip to: ' + props.destinationBucketName);
const zipBuffer = await zipObjects({ tmpDir: sourceDirPath });
await uploadZip({
zipBuffer,
bucket: props.destinationBucketName,
keyPrefix: props.destinationKeyPrefix,
});
}
if (tmpDir.length) {
debug('Removing temp directory');
(0, node_fs_1.rmSync)(tmpDir, { force: true, recursive: true });
}
responseStatus = 'SUCCESS';
}
}
catch (err) {
console.error(err);
responseStatus = 'FAILED';
}
await cfnResponse({ event, context, responseStatus });
};
exports.handler = handler;
function debug(value) {
if (process.env.DEBUG)
console.log(JSON.stringify(value, null, 2));
}
function getProperties(event) {
const props = event.ResourceProperties;
return {
...props,
prune: props.prune === 'true',
zip: props.zip === 'true',
};
}
function initDirectories() {
const assetsTmpDir = (0, node_fs_1.mkdtempSync)((0, node_path_1.resolve)((0, node_os_1.tmpdir)(), 'assets-'));
const sourceZipDirPath = (0, node_path_1.resolve)(assetsTmpDir, 'source-zip');
(0, node_fs_1.mkdirSync)(sourceZipDirPath);
const sourceZipFilePath = (0, node_path_1.resolve)(sourceZipDirPath, 'temp.zip');
// trailing slash expected by adm-zip's `extractAllTo` method
const sourceDirPath = (0, node_path_1.resolve)(assetsTmpDir, 'source') + '/';
(0, node_fs_1.mkdirSync)(sourceDirPath);
return { assetsTmpDir, sourceZipFilePath, sourceDirPath };
}
async function downloadFile({ bucket, key, localDestinationPath, }) {
const data = await s3.send(new client_s3_1.GetObjectCommand({ Bucket: bucket, Key: key }));
return new Promise(async (resolve, reject) => {
const body = data.Body;
if (body instanceof node_stream_1.Readable) {
const writeStream = (0, node_fs_1.createWriteStream)(localDestinationPath);
body
.pipe(writeStream)
.on('error', (err) => reject(err))
.on('close', () => resolve(null));
}
});
}
async function extractZip({ sourceZipFilePath, destinationDirPath, }) {
const zipBuffer = (0, node_fs_1.readFileSync)(sourceZipFilePath);
const archive = await JSZip.loadAsync(zipBuffer);
for (const [zipRelativePath, zipObject] of Object.entries(archive.files)) {
if (!zipObject.dir) {
const absPath = (0, node_path_1.resolve)(destinationDirPath, zipRelativePath);
const pathDirname = (0, node_path_1.dirname)(absPath);
if (!(0, node_fs_1.existsSync)(pathDirname)) {
(0, node_fs_1.mkdirSync)(pathDirname, { recursive: true });
}
const fileContents = await zipObject.async('nodebuffer');
let isSymLink = false;
const unixPermissions = zipObject?.unixPermissions;
if (typeof unixPermissions === 'number') {
// https://github.com/twolfson/grunt-zip/pull/52/files
// eslint-disable-next-line no-bitwise
isSymLink = (unixPermissions & 0xf000) === 0xa000;
}
if (isSymLink) {
(0, node_fs_1.symlinkSync)(fileContents, absPath);
}
else {
(0, node_fs_1.writeFileSync)(absPath, fileContents);
}
}
}
}
/**
* Given path of directory, returns array of all file paths within directory
*/
function listFilePaths(dirPath) {
const filePaths = [];
const directory = (0, node_fs_1.readdirSync)(dirPath, { withFileTypes: true });
for (const d of directory) {
const filePath = (0, node_path_1.resolve)(dirPath, d.name);
if (d.isDirectory()) {
filePaths.push(...listFilePaths(filePath));
}
else {
filePaths.push(filePath);
}
}
return filePaths;
}
function substitute({ filePaths, config }) {
const findRegExp = new RegExp(Object.keys(config).join('|'), 'g');
for (const filePath of filePaths) {
if (filePath.includes('node_modules'))
continue;
const fileContents = (0, node_fs_1.readFileSync)(filePath, { encoding: 'utf8' });
const newFileContents = fileContents.replace(findRegExp, (matched) => {
const matchedEnvVar = config[matched];
if (matchedEnvVar) {
return matchedEnvVar;
}
else {
console.warn(`Could not find matched value: ${matched} in environment object. Substituting ''`);
return '';
}
});
if (fileContents !== newFileContents) {
(0, node_fs_1.writeFileSync)(filePath, newFileContents);
}
}
}
async function listOldObjectKeys({ bucketName, keyPrefix, }) {
const oldObjectKeys = [];
let nextToken = undefined;
do {
const cmd = { Bucket: bucketName, Prefix: keyPrefix };
if (nextToken) {
cmd.ContinuationToken = nextToken;
}
const res = await s3.send(new client_s3_1.ListObjectsV2Command(cmd));
const contents = res.Contents;
nextToken = res.NextContinuationToken;
if (contents?.length) {
for (const { Key: key } of contents) {
if (key) {
oldObjectKeys.push(key);
}
}
}
} while (nextToken);
return oldObjectKeys;
}
/**
* Create S3 Key given local path
*/
function createS3Key({ keyPrefix, path, baseLocalDir }) {
const objectKeyParts = [];
if (keyPrefix)
objectKeyParts.push(keyPrefix);
objectKeyParts.push((0, node_path_1.relative)(baseLocalDir, path));
return (0, node_path_1.join)(...objectKeyParts);
}
async function* chunkArray(array, chunkSize) {
for (let i = 0; i < array.length; i += chunkSize) {
yield array.slice(i, i + chunkSize);
}
}
async function uploadObjects({ bucket, keyPrefix, filePaths, baseLocalDir, putConfig = {}, queueSize, }) {
for await (const filePathChunk of chunkArray(filePaths, 100)) {
const putObjectInputs = filePathChunk.map((path) => {
const contentType = mime.lookup(path) || undefined;
const putObjectOptions = getPutObjectOptions({ path, putConfig });
const key = createS3Key({ keyPrefix, path, baseLocalDir });
return {
ContentType: contentType,
...putObjectOptions,
Bucket: bucket,
Key: key,
Body: (0, node_fs_1.createReadStream)(path),
};
});
// Call put objects serially, prevents XAmzContentSHA256Mismatch errors
// This seems to be a bug within the lib storage package, I have opened an issue here: https://github.com/aws/aws-sdk-js-v3/issues/6940
await putObjectInputs.reduce(async (acc, params) => {
await acc;
const opts = {
client: s3,
params,
};
if (queueSize) {
opts.queueSize = queueSize;
}
const upload = new lib_storage_1.Upload(opts);
console.log('uploading', params);
return upload.done();
}, Promise.resolve(null));
}
}
/**
* Zips objects taking into account symlinks
* @see https://github.com/Stuk/jszip/issues/386#issuecomment-634773343
*/
function zipObjects({ tmpDir }) {
const zip = new JSZip();
const filePaths = listFilePaths(tmpDir);
for (const filePath of filePaths) {
const relativePath = (0, node_path_1.relative)(tmpDir, filePath);
const stat = (0, node_fs_1.lstatSync)(filePath);
if (stat.isSymbolicLink()) {
zip.file(relativePath, (0, node_fs_1.readlinkSync)(filePath), {
dir: stat.isDirectory(),
unixPermissions: parseInt('120755', 8),
});
}
else {
zip.file(relativePath, (0, node_fs_1.readFileSync)(filePath), { dir: stat.isDirectory(), unixPermissions: stat.mode });
}
}
return zip.generateAsync({
type: 'nodebuffer',
platform: 'UNIX',
compression: 'STORE',
});
}
async function uploadZip({ bucket, keyPrefix, zipBuffer, }) {
return s3.send(new client_s3_1.PutObjectCommand({
Bucket: bucket,
Key: keyPrefix,
Body: zipBuffer,
ContentType: 'application/zip',
}));
}
function getPutObjectOptions({ path, putConfig = {}, }) {
let putObjectOptions = {};
for (const [key, value] of Object.entries(putConfig)) {
if (micromatch.isMatch(path, key)) {
putObjectOptions = { ...putObjectOptions, ...value };
}
}
return putObjectOptions;
}
async function pruneBucket({ bucketName, filePaths, baseLocalDir, keyPrefix, oldObjectKeys, }) {
const newObjectKeys = filePaths.map((path) => createS3Key({ keyPrefix, path, baseLocalDir }));
// find old objects that are not currently in new objects to prune.
const oldObjectKeysToBeDeleted = [];
for (const key of oldObjectKeys) {
if (!newObjectKeys.includes(key)) {
oldObjectKeysToBeDeleted.push(key);
}
}
if (oldObjectKeysToBeDeleted.length) {
const deletePromises = [];
// AWS limits S3 delete commands to 1000 keys per call
const deleteCommandLimit = 1000;
for (let i = 0; i < oldObjectKeysToBeDeleted.length; i += deleteCommandLimit) {
const objectChunk = oldObjectKeysToBeDeleted.slice(i, i + deleteCommandLimit);
deletePromises.push(s3.send(new client_s3_1.DeleteObjectsCommand({
Bucket: bucketName,
Delete: { Objects: objectChunk.map((k) => ({ Key: k })) },
})));
}
await Promise.all(deletePromises);
debug(`Objects pruned in ${bucketName}: ${oldObjectKeysToBeDeleted.join(', ')}`);
}
else {
debug(`No objects to prune`);
}
}
/**
* Inspired by: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cfn-lambda-function-code-cfnresponsemodule.html
*/
function cfnResponse(props) {
const body = JSON.stringify({
Status: props.responseStatus,
Reason: 'See the details in CloudWatch Log Stream: ' + props.context.logStreamName,
PhysicalResourceId: props.physicalResourceId || props.context.logStreamName,
StackId: props.event.StackId,
RequestId: props.event.RequestId,
LogicalResourceId: props.event.LogicalResourceId,
Data: props.responseData,
});
return fetch(props.event.ResponseURL, {
method: 'PUT',
body,
headers: { 'content-type': '', 'content-length': body.length.toString() },
});
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmV4dGpzLWJ1Y2tldC1kZXBsb3ltZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL2xhbWJkYXMvbmV4dGpzLWJ1Y2tldC1kZXBsb3ltZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHNEQUFzRDtBQUN0RCxxQ0FhaUI7QUFDakIscUNBQWlDO0FBQ2pDLHlDQUE0RTtBQUM1RSw2Q0FBdUM7QUFDdkMsa0RBUTRCO0FBQzVCLHNEQUF1RDtBQUd2RCxrREFBa0Q7QUFDbEQsZ0RBQWdEO0FBQ2hELGlDQUEyQjtBQUMzQix5Q0FBeUM7QUFDekMsbUNBQW1DO0FBRW5DLE1BQU0sS0FBSyxHQUFHLGVBQW1CLENBQUM7QUFFbEMsTUFBTSxFQUFFLEdBQUcsSUFBSSxvQkFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDO0FBRXJCLE1BQU0sT0FBTyxHQUF3QyxLQUFLLEVBQUUsS0FBSyxFQUFFLE9BQU8sRUFBRSxFQUFFO0lBQ25GLEtBQUssQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDakIsSUFBSSxjQUFjLEdBQXlCLFNBQVMsQ0FBQztJQUNyRCxJQUFJLENBQUM7UUFDSCxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxJQUFJLEtBQUssQ0FBQyxXQUFXLEtBQUssUUFBUSxFQUFFLENBQUM7WUFDckUsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ25DLElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztZQUNoQixNQUFNLEVBQUUsWUFBWSxFQUFFLGFBQWEsRUFBRSxpQkFBaUIsRUFBRSxHQUFHLGVBQWUsRUFBRSxDQUFDO1lBQzdFLE1BQU0sR0FBRyxZQUFZLENBQUM7WUFDdEIsS0FBSyxDQUFDLGlCQUFpQixDQUFDLENBQUM7WUFDekIsTUFBTSxZQUFZLENBQUM7Z0JBQ2pCLE1BQU0sRUFBRSxLQUFLLENBQUMsZ0JBQWdCO2dCQUM5QixHQUFHLEVBQUUsS0FBSyxDQUFDLGVB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RSxFQUFFLEVBQUUsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsRUFBRTtLQUMxRSxDQUFDLENBQUM7QUFDTCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgaW1wb3J0L25vLWV4dHJhbmVvdXMtZGVwZW5kZW5jaWVzICovXG5pbXBvcnQge1xuICBjcmVhdGVSZWFkU3RyZWFtLFxuICBjcmVhdGVXcml0ZVN0cmVhbSxcbiAgZXhpc3RzU3luYyxcbiAgbHN0YXRTeW5jLFxuICBta2RpclN5bmMsXG4gIG1rZHRlbXBTeW5jLFxuICByZWFkZGlyU3luYyxcbiAgcmVhZEZpbGVTeW5jLFxuICByZWFkbGlua1N5bmMsXG4gIHJtU3luYyxcbiAgc3ltbGlua1N5bmMsXG4gIHdyaXRlRmlsZVN5bmMsXG59IGZyb20gJ25vZGU6ZnMnO1xuaW1wb3J0IHsgdG1wZGlyIH0gZnJvbSAnbm9kZTpvcyc7XG5pbXBvcnQgeyBkaXJuYW1lLCBqb2luLCByZWxhdGl2ZSwgcmVzb2x2ZSBhcyByZXNvbHZlUGF0aCB9IGZyb20gJ25vZGU6cGF0aCc7XG5pbXBvcnQgeyBSZWFkYWJsZSB9IGZyb20gJ25vZGU6c3RyZWFtJztcbmltcG9ydCB7XG4gIERlbGV0ZU9iamVjdHNDb21tYW5kLFxuICBHZXRPYmplY3RDb21tYW5kLFxuICBMaXN0T2JqZWN0c1YyQ29tbWFuZCxcbiAgdHlwZSBMaXN0T2JqZWN0c1YyQ29tbWFuZElucHV0LFxuICBQdXRPYmplY3RDb21tYW5kLFxuICB0eXBlIFB1dE9iamVjdENvbW1hbmRJbnB1dCxcbiAgUzNDbGllbnQsXG59IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zMyc7XG5pbXBvcnQgeyBPcHRpb25zLCBVcGxvYWQgfSBmcm9tICdAYXdzLXNkay9saWItc3RvcmFnZSc7XG5pbXBvcnQgdHlwZSB7IENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VIYW5kbGVyIH0gZnJvbSAnYXdzLWxhbWJkYSc7XG5pbXBvcnQgdHlwZSAqIGFzIEpTWmlwVHlwZSBmcm9tICdqc3ppcCc7XG4vLyBAdHMtaWdub3JlIGpzaWkgZG9lc24ndCBzdXBwb3J0IGVzTW9kdWxlSW50ZXJvcFxuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWR1cGxpY2F0ZS1pbXBvcnRzXG5pbXBvcnQgX0pTWmlwIGZyb20gJ2pzemlwJztcbmltcG9ydCAqIGFzIG1pY3JvbWF0Y2ggZnJvbSAnbWljcm9tYXRjaCc7XG5pbXBvcnQgKiBhcyBtaW1lIGZyb20gJ21pbWUtdHlwZXMnO1xuaW1wb3J0IHR5cGUgeyBDdXN0b21SZXNvdXJjZVByb3BlcnRpZXMsIE5leHRqc0J1Y2tldERlcGxveW1lbnRQcm9wcyB9IGZyb20gJy4uL05leHRqc0J1Y2tldERlcGxveW1lbnQnO1xuY29uc3QgSlNaaXAgPSBfSlNaaXAgYXMgSlNaaXBUeXBlO1xuXG5jb25zdCBzMyA9IG5ldyBTM0NsaWVudCh7fSk7XG5cbmV4cG9ydCBjb25zdCBoYW5kbGVyOiBDbG91ZEZvcm1hdGlvbkN1c3RvbVJlc291cmNlSGFuZGxlciA9IGFzeW5jIChldmVudCwgY29udGV4dCkgPT4ge1xuICBkZWJ1Zyh7IGV2ZW50IH0pO1xuICBsZXQgcmVzcG9uc2VTdGF0dXM6ICdTVUNDRVNTJyB8ICdGQUlMRUQnID0gJ1NVQ0NFU1MnO1xuICB0cnkge1xuICAgIGlmIChldmVudC5SZXF1ZXN0VHlwZSA9PT0gJ0NyZWF0ZScgfHwgZXZlbnQuUmVxdWVzdFR5cGUgPT09ICdVcGRhdGUnKSB7XG4gICAgICBjb25zdCBwcm9wcyA9IGdldFByb3BlcnRpZXMoZXZlbnQpO1xuICAgICAgbGV0IHRtcERpciA9ICcnO1xuICAgICAgY29uc3QgeyBhc3NldHNUbXBEaXIsIHNvdXJjZURpclBhdGgsIHNvdXJjZVppcEZpbGVQYXRoIH0gPSBpbml0RGlyZWN0b3JpZXMoKTtcbiAgICAgIHRtcERpciA9IGFzc2V0c1RtcERpcjtcbiAgICAgIGRlYnVnKCdEb3dubG9hZGluZyB6aXAnKTtcbiAgICAgIGF3YWl0IGRvd25sb2FkRmlsZSh7XG4gICAgICAgIGJ1Y2tldDogcHJvcHMuc291cmNlQnVja2V0TmFtZSxcbiAgICAgICAga2V5OiBwcm9wcy5zb3VyY2VLZXlQcmVmaXgsXG4gICAgICAgIGxvY2FsRGVzdGluYXRpb25QYXRoOiBzb3VyY2VaaXBGaWxlUGF0aCxcbiAgICAgIH0pO1xuICAgICAgZGVidWcoJ0V4dHJhY3RpbmcgemlwJyk7XG4gICAgICBhd2FpdCBleHRyYWN0WmlwKHsgc291cmNlWmlwRmlsZVBhdGgsIGRlc3RpbmF0aW9uRGlyUGF0aDogc291cmNlRGlyUGF0aCB9KTtcbiAgICAgIGNvbnN0IGZpbGVQYXRocyA9IGxpc3RGaWxlUGF0aHMoc291cmNlRGlyUGF0aCk7XG4gICAgICBpZiAocHJvcHMuc3Vic3RpdHV0aW9uQ29uZmlnICYmIE9iamVjdC5rZXlzKHByb3BzLnN1YnN0aXR1dGlvbkNvbmZpZykubGVuZ3RoKSB7XG4gICAgICAgIGRlYnVnKCdSZXBsYWNpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzOiAnICsgSlNPTi5zdHJpbmdpZnkocHJvcHMuc3Vic3RpdHV0aW9uQ29uZmlnKSk7XG4gICAgICAgIHN1YnN0aXR1dGUoeyBjb25maWc6IHByb3BzLnN1YnN0aXR1dGlvbkNvbmZpZywgZmlsZVBhdGhzIH0pO1xuICAgICAgfVxuICAgICAgLy8gbXVzdCBmaW5kIG9sZCBvYmplY3Qga2V5cyBiZWZvcmUgdXBsb2FkaW5nIG5ldyBvYmplY3RzIHNvIHdlIGtub3cgd2hpY2ggb2JqZWN0cyB0byBwcnVuZVxuICAgICAgY29uc3Qgb2xkT2JqZWN0S2V5cyA9IGF3YWl0IGxpc3RPbGRPYmplY3RLZXlzKHtcbiAgICAgICAgYnVja2V0TmFtZTogcHJvcHMuZGVzdGluYXRpb25CdWNrZXROYW1lLFxuICAgICAgICBrZXlQcmVmaXg6IHByb3BzLmRlc3RpbmF0aW9uS2V5UHJlZml4LFxuICAgICAgfSk7XG4gICAgICBpZiAoIXByb3BzLnppcCkge1xuICAgICAgICBkZWJ1ZygnVXBsb2FkaW5nIG9iamVjdHMgdG86ICcgKyBwcm9wcy5kZXN0aW5hdGlvbkJ1Y2tldE5hbWUpO1xuICAgICAgICBhd2FpdCB1cGxvYWRPYmplY3RzKHtcbiAgICAgICAgICBidWNrZXQ6IHByb3BzLmRlc3RpbmF0aW9uQnVja2V0TmFtZSxcbiAgICAgICAgICBrZXlQcmVmaXg6IHByb3BzLmRlc3RpbmF0aW9uS2V5UHJlZml4LFxuICAgICAgICAgIGZpbGVQYXRocyxcbiAgICAgICAgICBiYXNlTG9jYWxEaXI6IHNvdXJjZURpclBhdGgsXG4gICAgICAgICAgcHV0Q29uZmlnOiBwcm9wcy5wdXRDb25maWcsXG4gICAgICAgICAgcXVldWVTaXplOiBwcm9wcy5xdWV1ZVNpemUsXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAocHJvcHMucHJ1bmUpIHtcbiAgICAgICAgICBkZWJ1ZygnRW1wdHlpbmcvcHJ1bmluZyBidWNrZXQ6ICcgKyBwcm9wcy5kZXN0aW5hdGlvbkJ1Y2tldE5hbWUpO1xuICAgICAgICAgIGF3YWl0IHBydW5lQnVja2V0KHtcbiAgICAgICAgICAgIGJ1Y2tldE5hbWU6IHByb3BzLmRlc3RpbmF0aW9uQnVja2V0TmFtZSxcbiAgICAgICAgICAgIGZpbGVQYXRocyxcbiAgICAgICAgICAgIGJhc2VMb2NhbERpcjogc291cmNlRGlyUGF0aCxcbiAgICAgICAgICAgIGtleVByZWZpeDogcHJvcHMuZGVzdGluYXRpb25LZXlQcmVmaXgsXG4gICAgICAgICAgICBvbGRPYmplY3RLZXlzLFxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkZWJ1ZygnVXBsb2FkaW5nIHppcCB0bzogJyArIHByb3BzLmRlc3RpbmF0aW9uQnVja2V0TmFtZSk7XG4gICAgICAgIGNvbnN0IHppcEJ1ZmZlciA9IGF3YWl0IHppcE9iamVjdHMoeyB0bXBEaXI6IHNvdXJjZURpclBhdGggfSk7XG4gICAgICAgIGF3YWl0IHVwbG9hZFppcCh7XG4gICAgICAgICAgemlwQnVmZmVyLFxuICAgICAgICAgIGJ1Y2tldDogcHJvcHMuZGVzdGluYXRpb25CdWNrZXROYW1lLFxuICAgICAgICAgIGtleVByZWZpeDogcHJvcHMuZGVzdGluYXRpb25LZXlQcmVmaXgsXG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgICAgaWYgKHRtcERpci5sZW5ndGgpIHtcbiAgICAgICAgZGVidWcoJ1JlbW92aW5nIHRlbXAgZGlyZWN0b3J5Jyk7XG4gICAgICAgIHJtU3luYyh0bXBEaXIsIHsgZm9yY2U6IHRydWUsIHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcbiAgICAgIH1cbiAgICAgIHJlc3BvbnNlU3RhdHVzID0gJ1NVQ0NFU1MnO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyKSB7XG4gICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgIHJlc3BvbnNlU3RhdHVzID0gJ0ZBSUxFRCc7XG4gIH1cbiAgYXdhaXQgY2ZuUmVzcG9uc2UoeyBldmVudCwgY29udGV4dCwgcmVzcG9uc2VTdGF0dXMgfSk7XG59O1xuXG5mdW5jdGlvbiBkZWJ1Zyh2YWx1ZTogdW5rbm93bikge1xuICBpZiAocHJvY2Vzcy5lbnYuREVCVUcpIGNvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KHZhbHVlLCBudWxsLCAyKSk7XG59XG5cbmZ1bmN0aW9uIGdldFByb3BlcnRpZXMoZXZlbnQ6IFBhcmFtZXRlcnM8Q2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUhhbmRsZXI+WzBdKSB7XG4gIGNvbnN0IHByb3BzID0gZXZlbnQuUmVzb3VyY2VQcm9wZXJ0aWVzO1xuICByZXR1cm4ge1xuICAgIC4uLnByb3BzLFxuICAgIHBydW5lOiBwcm9wcy5wcnVuZSA9PT0gJ3RydWUnLFxuICAgIHppcDogcHJvcHMuemlwID09PSAndHJ1ZScsXG4gIH0gYXMgQ3VzdG9tUmVzb3VyY2VQcm9wZXJ0aWVzICYgeyBTZXJ2aWNlVG9rZW46IHN0cmluZyB9O1xufVxuXG5mdW5jdGlvbiBpbml0RGlyZWN0b3JpZXMoKSB7XG4gIGNvbnN0IGFzc2V0c1RtcERpciA9IG1rZHRlbXBTeW5jKHJlc29sdmVQYXRoKHRtcGRpcigpLCAnYXNzZXRzLScpKTtcbiAgY29uc3Qgc291cmNlWmlwRGlyUGF0aCA9IHJlc29sdmVQYXRoKGFzc2V0c1RtcERpciwgJ3NvdXJjZS16aXAnKTtcbiAgbWtkaXJTeW5jKHNvdXJjZVppcERpclBhdGgpO1xuICBjb25zdCBzb3VyY2VaaXBGaWxlUGF0aCA9IHJlc29sdmVQYXRoKHNvdXJjZVppcERpclBhdGgsICd0ZW1wLnppcCcpO1xuICAvLyB0cmFpbGluZyBzbGFzaCBleHBlY3RlZCBieSBhZG0temlwJ3MgYGV4dHJhY3RBbGxUb2AgbWV0aG9kXG4gIGNvbnN0IHNvdXJjZURpclBhdGggPSByZXNvbHZlUGF0aChhc3NldHNUbXBEaXIsICdzb3VyY2UnKSArICcvJztcbiAgbWtkaXJTeW5jKHNvdXJjZURpclBhdGgpO1xuICByZXR1cm4geyBhc3NldHNUbXBEaXIsIHNvdXJjZVppcEZpbGVQYXRoLCBzb3VyY2VEaXJQYXRoIH07XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGRvd25sb2FkRmlsZSh7XG4gIGJ1Y2tldCxcbiAga2V5LFxuICBsb2NhbERlc3RpbmF0aW9uUGF0aCxcbn06IHtcbiAgYnVja2V0OiBzdHJpbmc7XG4gIGtleT86IHN0cmluZyB8IHVuZGVmaW5lZDtcbiAgbG9jYWxEZXN0aW5hdGlvblBhdGg6IHN0cmluZztcbn0pIHtcbiAgY29uc3QgZGF0YSA9IGF3YWl0IHMzLnNlbmQobmV3IEdldE9iamVjdENvbW1hbmQoeyBCdWNrZXQ6IGJ1Y2tldCwgS2V5OiBrZXkgfSkpO1xuICByZXR1cm4gbmV3IFByb21pc2UoYXN5bmMgKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IGJvZHkgPSBkYXRhLkJvZHk7XG4gICAgaWYgKGJvZHkgaW5zdGFuY2VvZiBSZWFkYWJsZSkge1xuICAgICAgY29uc3Qgd3JpdGVTdHJlYW0gPSBjcmVhdGVXcml0ZVN0cmVhbShsb2NhbERlc3RpbmF0aW9uUGF0aCk7XG4gICAgICBib2R5XG4gICAgICAgIC5waXBlKHdyaXRlU3RyZWFtKVxuICAgICAgICAub24oJ2Vycm9yJywgKGVycikgPT4gcmVqZWN0KGVycikpXG4gICAgICAgIC5vbignY2xvc2UnLCAoKSA9PiByZXNvbHZlKG51bGwpKTtcbiAgICB9XG4gIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiBleHRyYWN0WmlwKHtcbiAgc291cmNlWmlwRmlsZVBhdGgsXG4gIGRlc3RpbmF0aW9uRGlyUGF0aCxcbn06IHtcbiAgc291cmNlWmlwRmlsZVBhdGg6IHN0cmluZztcbiAgZGVzdGluYXRpb25EaXJQYXRoOiBzdHJpbmc7XG59KSB7XG4gIGNvbnN0IHppcEJ1ZmZlciA9IHJlYWRGaWxlU3luYyhzb3VyY2VaaXBGaWxlUGF0aCk7XG4gIGNvbnN0IGFyY2hpdmUgPSBhd2FpdCBKU1ppcC5sb2FkQXN5bmMoemlwQnVmZmVyKTtcbiAgZm9yIChjb25zdCBbemlwUmVsYXRpdmVQYXRoLCB6aXBPYmplY3RdIG9mIE9iamVjdC5lbnRyaWVzKGFyY2hpdmUuZmlsZXMpKSB7XG4gICAgaWYgKCF6aXBPYmplY3QuZGlyKSB7XG4gICAgICBjb25zdCBhYnNQYXRoID0gcmVzb2x2ZVBhdGgoZGVzdGluYXRpb25EaXJQYXRoLCB6aXBSZWxhdGl2ZVBhdGgpO1xuICAgICAgY29uc3QgcGF0aERpcm5hbWUgPSBkaXJuYW1lKGFic1BhdGgpO1xuICAgICAgaWYgKCFleGlzdHNTeW5jKHBhdGhEaXJuYW1lKSkge1xuICAgICAgICBta2RpclN5bmMocGF0aERpcm5hbWUsIHsgcmVjdXJzaXZlOiB0cnVlIH0pO1xuICAgICAgfVxuICAgICAgY29uc3QgZmlsZUNvbnRlbnRzID0gYXdhaXQgemlwT2JqZWN0LmFzeW5jKCdub2RlYnVmZmVyJyk7XG4gICAgICBsZXQgaXNTeW1MaW5rID0gZmFsc2U7XG4gICAgICBjb25zdCB1bml4UGVybWlzc2lvbnMgPSB6aXBPYmplY3Q/LnVuaXhQZXJtaXNzaW9ucztcbiAgICAgIGlmICh0eXBlb2YgdW5peFBlcm1pc3Npb25zID09PSAnbnVtYmVyJykge1xuICAgICAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vdHdvbGZzb24vZ3J1bnQtemlwL3B1bGwvNTIvZmlsZXNcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLWJpdHdpc2VcbiAgICAgICAgaXNTeW1MaW5rID0gKHVuaXhQZXJtaXNzaW9ucyAmIDB4ZjAwMCkgPT09IDB4YTAwMDtcbiAgICAgIH1cbiAgICAgIGlmIChpc1N5bUxpbmspIHtcbiAgICAgICAgc3ltbGlua1N5bmMoZmlsZUNvbnRlbnRzLCBhYnNQYXRoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHdyaXRlRmlsZVN5bmMoYWJzUGF0aCwgZmlsZUNvbnRlbnRzKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBHaXZlbiBwYXRoIG9mIGRpcmVjdG9yeSwgcmV0dXJucyBhcnJheSBvZiBhbGwgZmlsZSBwYXRocyB3aXRoaW4gZGlyZWN0b3J5XG4gKi9cbmZ1bmN0aW9uIGxpc3RGaWxlUGF0aHMoZGlyUGF0aDogc3RyaW5nKTogc3RyaW5nW10ge1xuICBjb25zdCBmaWxlUGF0aHM6IHN0cmluZ1tdID0gW107XG4gIGNvbnN0IGRpcmVjdG9yeSA9IHJlYWRkaXJTeW5jKGRpclBhdGgsIHsgd2l0aEZpbGVUeXBlczogdHJ1ZSB9KTtcbiAgZm9yIChjb25zdCBkIG9mIGRpcmVjdG9yeSkge1xuICAgIGNvbnN0IGZpbGVQYXRoID0gcmVzb2x2ZVBhdGgoZGlyUGF0aCwgZC5uYW1lKTtcbiAgICBpZiAoZC5pc0RpcmVjdG9yeSgpKSB7XG4gICAgICBmaWxlUGF0aHMucHVzaCguLi5saXN0RmlsZVBhdGhzKGZpbGVQYXRoKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGZpbGVQYXRocy5wdXNoKGZpbGVQYXRoKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGZpbGVQYXRocztcbn1cblxuZnVuY3Rpb24gc3Vic3RpdHV0ZSh7IGZpbGVQYXRocywgY29uZmlnIH06IHsgZmlsZVBhdGhzOiBzdHJpbmdbXTsgY29uZmlnOiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+IH0pIHtcbiAgY29uc3QgZmluZFJlZ0V4cCA9IG5ldyBSZWdFeHAoT2JqZWN0LmtleXMoY29uZmlnKS5qb2luKCd8JyksICdnJyk7XG4gIGZvciAoY29uc3QgZmlsZVBhdGggb2YgZmlsZVBhdGhzKSB7XG4gICAgaWYgKGZpbGVQYXRoLmluY2x1ZGVzKCdub2RlX21vZHVsZXMnKSkgY29udGludWU7XG4gICAgY29uc3QgZmlsZUNvbnRlbnRzID0gcmVhZEZpbGVTeW5jKGZpbGVQYXRoLCB7IGVuY29kaW5nOiAndXRmOCcgfSk7XG4gICAgY29uc3QgbmV3RmlsZUNvbnRlbnRzID0gZmlsZUNvbnRlbnRzLnJlcGxhY2UoZmluZFJlZ0V4cCwgKG1hdGNoZWQpID0+IHtcbiAgICAgIGNvbnN0IG1hdGNoZWRFbnZWYXIgPSBjb25maWdbbWF0Y2hlZF07XG4gICAgICBpZiAobWF0Y2hlZEVudlZhcikge1xuICAgICAgICByZXR1cm4gbWF0Y2hlZEVudlZhcjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUud2FybihgQ291bGQgbm90IGZpbmQgbWF0Y2hlZCB2YWx1ZTogJHttYXRjaGVkfSBpbiBlbnZpcm9ubWVudCBvYmplY3QuIFN1YnN0aXR1dGluZyAnJ2ApO1xuICAgICAgICByZXR1cm4gJyc7XG4gICAgICB9XG4gICAgfSk7XG4gICAgaWYgKGZpbGVDb250ZW50cyAhPT0gbmV3RmlsZUNvbnRlbnRzKSB7XG4gICAgICB3cml0ZUZpbGVTeW5jKGZpbGVQYXRoLCBuZXdGaWxlQ29udGVudHMpO1xuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBsaXN0T2xkT2JqZWN0S2V5cyh7XG4gIGJ1Y2tldE5hbWUsXG4gIGtleVByZWZpeCxcbn06IHtcbiAgYnVja2V0TmFtZTogc3RyaW5nO1xuICBrZXlQcmVmaXg/OiBzdHJpbmc7XG59KTogUHJvbWlzZTxzdHJpbmdbXT4ge1xuICBjb25zdCBvbGRPYmplY3RLZXlzOiBzdHJpbmdbXSA9IFtdO1xuICBsZXQgbmV4dFRva2VuOiBzdHJpbmcgfCB1bmRlZmluZWQgPSB1bmRlZmluZWQ7XG4gIGRvIHtcbiAgICBjb25zdCBjbWQ6IExpc3RPYmplY3RzVjJDb21tYW5kSW5wdXQgPSB7IEJ1Y2tldDogYnVja2V0TmFtZSwgUHJlZml4OiBrZXlQcmVmaXggfTtcbiAgICBpZiAobmV4dFRva2VuKSB7XG4gICAgICBjbWQuQ29udGludWF0aW9uVG9rZW4gPSBuZXh0VG9rZW47XG4gICAgfVxuICAgIGNvbnN0IHJlcyA9IGF3YWl0IHMzLnNlbmQobmV3IExpc3RPYmplY3RzVjJDb21tYW5kKGNtZCkpO1xuICAgIGNvbnN0IGNvbnRlbnRzID0gcmVzLkNvbnRlbnRzO1xuICAgIG5leHRUb2tlbiA9IHJlcy5OZXh0Q29udGludWF0aW9uVG9rZW47XG4gICAgaWYgKGNvbnRlbnRzPy5sZW5ndGgpIHtcbiAgICAgIGZvciAoY29uc3QgeyBLZXk6IGtleSB9IG9mIGNvbnRlbnRzKSB7XG4gICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICBvbGRPYmplY3RLZXlzLnB1c2goa2V5KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSB3aGlsZSAobmV4dFRva2VuKTtcbiAgcmV0dXJuIG9sZE9iamVjdEtleXM7XG59XG5cbi8qKlxuICogQ3JlYXRlIFMzIEtleSBnaXZlbiBsb2NhbCBwYXRoXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZVMzS2V5KHsga2V5UHJlZml4LCBwYXRoLCBiYXNlTG9jYWxEaXIgfTogeyBrZXlQcmVmaXg/OiBzdHJpbmc7IHBhdGg6IHN0cmluZzsgYmFzZUxvY2FsRGlyOiBzdHJpbmcgfSkge1xuICBjb25zdCBvYmplY3RLZXlQYXJ0czogc3RyaW5nW10gPSBbXTtcbiAgaWYgKGtleVByZWZpeCkgb2JqZWN0S2V5UGFydHMucHVzaChrZXlQcmVmaXgpO1xuICBvYmplY3RLZXlQYXJ0cy5wdXNoKHJlbGF0aXZlKGJhc2VMb2NhbERpciwgcGF0aCkpO1xuICByZXR1cm4gam9pbiguLi5vYmplY3RLZXlQYXJ0cyk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uKiBjaHVua0FycmF5KGFycmF5OiBzdHJpbmdbXSwgY2h1bmtTaXplOiBudW1iZXIpIHtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkgKz0gY2h1bmtTaXplKSB7XG4gICAgeWllbGQgYXJyYXkuc2xpY2UoaSwgaSArIGNodW5rU2l6ZSk7XG4gIH1cbn1cblxuYXN5bmMgZnVuY3Rpb24gdXBsb2FkT2JqZWN0cyh7XG4gIGJ1Y2tldCxcbiAga2V5UHJlZml4LFxuICBmaWxlUGF0aHMsXG4gIGJhc2VMb2NhbERpcixcbiAgcHV0Q29uZmlnID0ge30sXG4gIHF1ZXVlU2l6ZSxcbn06IHtcbiAgYnVja2V0OiBDdXN0b21SZXNvdXJjZVByb3BlcnRpZXNbJ2Rlc3RpbmF0aW9uQnVja2V0TmFtZSddO1xuICBrZXlQcmVmaXg/OiBDdXN0b21SZXNvdXJjZVByb3BlcnRpZXNbJ2Rlc3RpbmF0aW9uS2V5UHJlZml4J107XG4gIGZpbGVQYXRoczogc3RyaW5nW107XG4gIGJhc2VMb2NhbERpcjogc3RyaW5nO1xuICBwdXRDb25maWc6IEN1c3RvbVJlc291cmNlUHJvcGVydGllc1sncHV0Q29uZmlnJ107XG4gIHF1ZXVlU2l6ZTogQ3VzdG9tUmVzb3VyY2VQcm9wZXJ0aWVzWydxdWV1ZVNpemUnXTtcbn0pIHtcbiAgZm9yIGF3YWl0IChjb25zdCBmaWxlUGF0aENodW5rIG9mIGNodW5rQXJyYXkoZmlsZVBhdGhzLCAxMDApKSB7XG4gICAgY29uc3QgcHV0T2JqZWN0SW5wdXRzOiBQdXRPYmplY3RDb21tYW5kSW5wdXRbXSA9IGZpbGVQYXRoQ2h1bmsubWFwKChwYXRoKSA9PiB7XG4gICAgICBjb25zdCBjb250ZW50VHlwZSA9IG1pbWUubG9va3VwKHBhdGgpIHx8IHVuZGVmaW5lZDtcbiAgICAgIGNvbnN0IHB1dE9iamVjdE9wdGlvbnMgPSBnZXRQdXRPYmplY3RPcHRpb25zKHsgcGF0aCwgcHV0Q29uZmlnIH0pO1xuICAgICAgY29uc3Qga2V5ID0gY3JlYXRlUzNLZXkoeyBrZXlQcmVmaXgsIHBhdGgsIGJhc2VMb2NhbERpciB9KTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIENvbnRlbnRUeXBlOiBjb250ZW50VHlwZSxcbiAgICAgICAgLi4ucHV0T2JqZWN0T3B0aW9ucyxcbiAgICAgICAgQnVja2V0OiBidWNrZXQsXG4gICAgICAgIEtleToga2V5LFxuICAgICAgICBCb2R5OiBjcmVhdGVSZWFkU3RyZWFtKHBhdGgpLFxuICAgICAgfTtcbiAgICB9KTtcblxuICAgIC8vIENhbGwgcHV0IG9iamVjdHMgc2VyaWFsbHksIHByZXZlbnRzIFhBbXpDb250ZW50U0hBMjU2TWlzbWF0Y2ggZXJyb3JzXG4gICAgLy8gVGhpcyBzZWVtcyB0byBiZSBhIGJ1ZyB3aXRoaW4gdGhlIGxpYiBzdG9yYWdlIHBhY2thZ2UsIEkgaGF2ZSBvcGVuZWQgYW4gaXNzdWUgaGVyZTogaHR0cHM6Ly9naXRodWIuY29tL2F3cy9hd3Mtc2RrLWpzLXYzL2lzc3Vlcy82OTQwXG4gICAgYXdhaXQgcHV0T2JqZWN0SW5wdXRzLnJlZHVjZShhc3luYyAoYWNjLCBwYXJhbXMpID0+IHtcbiAgICAgIGF3YWl0IGFjYztcbiAgICAgIGNvbnN0IG9wdHM6IE9wdGlvbnMgPSB7XG4gICAgICAgIGNsaWVudDogczMsXG4gICAgICAgIHBhcmFtcyxcbiAgICAgIH07XG4gICAgICBpZiAocXVldWVTaXplKSB7XG4gICAgICAgIG9wdHMucXVldWVTaXplID0gcXVldWVTaXplO1xuICAgICAgfVxuICAgICAgY29uc3QgdXBsb2FkID0gbmV3IFVwbG9hZChvcHRzKTtcbiAgICAgIGNvbnNvbGUubG9nKCd1cGxvYWRpbmcnLCBwYXJhbXMpO1xuICAgICAgcmV0dXJuIHVwbG9hZC5kb25lKCk7XG4gICAgfSwgUHJvbWlzZS5yZXNvbHZlPGFueT4obnVsbCkpO1xuICB9XG59XG5cbi8qKlxuICogWmlwcyBvYmplY3RzIHRha2luZyBpbnRvIGFjY291bnQgc3ltbGlua3NcbiAqIEBzZWUgaHR0cHM6Ly9naXRodWIuY29tL1N0dWsvanN6aXAvaXNzdWVzLzM4NiNpc3N1ZWNvbW1lbnQtNjM0NzczMzQzXG4gKi9cbmZ1bmN0aW9uIHppcE9iamVjdHMoeyB0bXBEaXIgfTogeyB0bXBEaXI6IHN0cmluZyB9KTogUHJvbWlzZTxCdWZmZXI+IHtcbiAgY29uc3QgemlwID0gbmV3IEpTWmlwKCk7XG4gIGNvbnN0IGZpbGVQYXRocyA9IGxpc3RGaWxlUGF0aHModG1wRGlyKTtcbiAgZm9yIChjb25zdCBmaWxlUGF0aCBvZiBmaWxlUGF0aHMpIHtcbiAgICBjb25zdCByZWxhdGl2ZVBhdGggPSByZWxhdGl2ZSh0bXBEaXIsIGZpbGVQYXRoKTtcbiAgICBjb25zdCBzdGF0ID0gbHN0YXRTeW5jKGZpbGVQYXRoKTtcbiAgICBpZiAoc3RhdC5pc1N5bWJvbGljTGluaygpKSB7XG4gICAgICB6aXAuZmlsZShyZWxhdGl2ZVBhdGgsIHJlYWRsaW5rU3luYyhmaWxlUGF0aCksIHtcbiAgICAgICAgZGlyOiBzdGF0LmlzRGlyZWN0b3J5KCksXG4gICAgICAgIHVuaXhQZXJtaXNzaW9uczogcGFyc2VJbnQoJzEyMDc1NScsIDgpLFxuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHppcC5maWxlKHJlbGF0aXZlUGF0aCwgcmVhZEZpbGVTeW5jKGZpbGVQYXRoKSwgeyBkaXI6IHN0YXQuaXNEaXJlY3RvcnkoKSwgdW5peFBlcm1pc3Npb25zOiBzdGF0Lm1vZGUgfSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB6aXAuZ2VuZXJhdGVBc3luYyh7XG4gICAgdHlwZTogJ25vZGVidWZmZXInLFxuICAgIHBsYXRmb3JtOiAnVU5JWCcsXG4gICAgY29tcHJlc3Npb246ICdTVE9SRScsXG4gIH0pO1xufVxuXG5hc3luYyBmdW5jdGlvbiB1cGxvYWRaaXAoe1xuICBidWNrZXQsXG4gIGtleVByZWZpeCxcbiAgemlwQnVmZmVyLFxufToge1xuICBidWNrZXQ6IEN1c3RvbVJlc291cmNlUHJvcGVydGllc1snZGVzdGluYXRpb25CdWNrZXROYW1lJ107XG4gIGtleVByZWZpeD86IEN1c3RvbVJlc291cmNlUHJvcGVydGllc1snZGVzdGluYXRpb25LZXlQcmVmaXgnXTtcbiAgemlwQnVmZmVyOiBCdWZmZXI7XG59KSB7XG4gIHJldHVybiBzMy5zZW5kKFxuICAgIG5ldyBQdXRPYmplY3RDb21tYW5kKHtcbiAgICAgIEJ1Y2tldDogYnVja2V0LFxuICAgICAgS2V5OiBrZXlQcmVmaXgsXG4gICAgICBCb2R5OiB6aXBCdWZmZXIsXG4gICAgICBDb250ZW50VHlwZTogJ2FwcGxpY2F0aW9uL3ppcCcsXG4gICAgfSlcbiAgKTtcbn1cblxuZnVuY3Rpb24gZ2V0UHV0T2JqZWN0T3B0aW9ucyh7XG4gIHBhdGgsXG4gIHB1dENvbmZpZyA9IHt9LFxufToge1xuICBwYXRoOiBzdHJpbmc7XG4gIHB1dENvbmZpZzogTmV4dGpzQnVja2V0RGVwbG95bWVudFByb3BzWydwdXRDb25maWcnXTtcbn0pOiBQYXJ0aWFsPFB1dE9iamVjdENvbW1hbmRJbnB1dD4ge1xuICBsZXQgcHV0T2JqZWN0T3B0aW9uczogUGFydGlhbDxQdXRPYmplY3RDb21tYW5kSW5wdXQ+ID0ge307XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHB1dENvbmZpZykpIHtcbiAgICBpZiAobWljcm9tYXRjaC5pc01hdGNoKHBhdGgsIGtleSkpIHtcbiAgICAgIHB1dE9iamVjdE9wdGlvbnMgPSB7IC4uLnB1dE9iamVjdE9wdGlvbnMsIC4uLnZhbHVlIH07XG4gICAgfVxuICB9XG4gIHJldHVybiBwdXRPYmplY3RPcHRpb25zO1xufVxuXG5hc3luYyBmdW5jdGlvbiBwcnVuZUJ1Y2tldCh7XG4gIGJ1Y2tldE5hbWUsXG4gIGZpbGVQYXRocyxcbiAgYmFzZUxvY2FsRGlyLFxuICBrZXlQcmVmaXgsXG4gIG9sZE9iamVjdEtleXMsXG59OiB7XG4gIGJ1Y2tldE5hbWU6IHN0cmluZztcbiAgZmlsZVBhdGhzOiBzdHJpbmdbXTtcbiAgYmFzZUxvY2FsRGlyOiBzdHJpbmc7XG4gIGtleVByZWZpeD86IHN0cmluZztcbiAgb2xkT2JqZWN0S2V5czogc3RyaW5nW107XG59KSB7XG4gIGNvbnN0IG5ld09iamVjdEtleXMgPSBmaWxlUGF0aHMubWFwKChwYXRoKSA9PiBjcmVhdGVTM0tleSh7IGtleVByZWZpeCwgcGF0aCwgYmFzZUxvY2FsRGlyIH0pKTtcbiAgLy8gZmluZCBvbGQgb2JqZWN0cyB0aGF0IGFyZSBub3QgY3VycmVudGx5IGluIG5ldyBvYmplY3RzIHRvIHBydW5lLlxuICBjb25zdCBvbGRPYmplY3RLZXlzVG9CZURlbGV0ZWQ6IHN0cmluZ1tdID0gW107XG4gIGZvciAoY29uc3Qga2V5IG9mIG9sZE9iamVjdEtleXMpIHtcbiAgICBpZiAoIW5ld09iamVjdEtleXMuaW5jbHVkZXMoa2V5KSkge1xuICAgICAgb2xkT2JqZWN0S2V5c1RvQmVEZWxldGVkLnB1c2goa2V5KTtcbiAgICB9XG4gIH1cbiAgaWYgKG9sZE9iamVjdEtleXNUb0JlRGVsZXRlZC5sZW5ndGgpIHtcbiAgICBjb25zdCBkZWxldGVQcm9taXNlcyA9IFtdO1xuXG4gICAgLy8gQVdTIGxpbWl0cyBTMyBkZWxldGUgY29tbWFuZHMgdG8gMTAwMCBrZXlzIHBlciBjYWxsXG4gICAgY29uc3QgZGVsZXRlQ29tbWFuZExpbWl0ID0gMTAwMDtcblxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgb2xkT2JqZWN0S2V5c1RvQmVEZWxldGVkLmxlbmd0aDsgaSArPSBkZWxldGVDb21tYW5kTGltaXQpIHtcbiAgICAgIGNvbnN0IG9iamVjdENodW5rID0gb2xkT2JqZWN0S2V5c1RvQmVEZWxldGVkLnNsaWNlKGksIGkgKyBkZWxldGVDb21tYW5kTGltaXQpO1xuXG4gICAgICBkZWxldGVQcm9taXNlcy5wdXNoKFxuICAgICAgICBzMy5zZW5kKFxuICAgICAgICAgIG5ldyBEZWxldGVPYmplY3RzQ29tbWFuZCh7XG4gICAgICAgICAgICBCdWNrZXQ6IGJ1Y2tldE5hbWUsXG4gICAgICAgICAgICBEZWxldGU6IHsgT2JqZWN0czogb2JqZWN0Q2h1bmsubWFwKChrKSA9PiAoeyBLZXk6IGsgfSkpIH0sXG4gICAgICAgICAgfSlcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICBhd2FpdCBQcm9taXNlLmFsbChkZWxldGVQcm9taXNlcyk7XG5cbiAgICBkZWJ1ZyhgT2JqZWN0cyBwcnVuZWQgaW4gJHtidWNrZXROYW1lfTogJHtvbGRPYmplY3RLZXlzVG9CZURlbGV0ZWQuam9pbignLCAnKX1gKTtcbiAgfSBlbHNlIHtcbiAgICBkZWJ1ZyhgTm8gb2JqZWN0cyB0byBwcnVuZWApO1xuICB9XG59XG5cbmludGVyZmFjZSBDZm5SZXNwb25zZVByb3BzIHtcbiAgZXZlbnQ6IFBhcmFtZXRlcnM8Q2xvdWRGb3JtYXRpb25DdXN0b21SZXNvdXJjZUhhbmRsZXI+WzBdO1xuICBjb250ZXh0OiBQYXJhbWV0ZXJzPENsb3VkRm9ybWF0aW9uQ3VzdG9tUmVzb3VyY2VIYW5kbGVyPlsxXTtcbiAgcmVzcG9uc2VTdGF0dXM6ICdTVUNDRVNTJyB8ICdGQUlMRUQnO1xuICByZXNwb25zZURhdGE/OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICBwaHlzaWNhbFJlc291cmNlSWQ/OiBzdHJpbmc7XG59XG4vKipcbiAqIEluc3BpcmVkIGJ5OiBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQVdTQ2xvdWRGb3JtYXRpb24vbGF0ZXN0L1VzZXJHdWlkZS9jZm4tbGFtYmRhLWZ1bmN0aW9uLWNvZGUtY2ZucmVzcG9uc2Vtb2R1bGUuaHRtbFxuICovXG5mdW5jdGlvbiBjZm5SZXNwb25zZShwcm9wczogQ2ZuUmVzcG9uc2VQcm9wcykge1xuICBjb25zdCBib2R5ID0gSlNPTi5zdHJpbmdpZnkoe1xuICAgIFN0YXR1czogcHJvcHMucmVzcG9uc2VTdGF0dXMsXG4gICAgUmVhc29uOiAnU2VlIHRoZSBkZXRhaWxzIGluIENsb3VkV2F0Y2ggTG9nIFN0cmVhbTogJyArIHByb3BzLmNvbnRleHQubG9nU3RyZWFtTmFtZSxcbiAgICBQaHlzaWNhbFJlc291cmNlSWQ6IHByb3BzLnBoeXNpY2FsUmVzb3VyY2VJZCB8fCBwcm9wcy5jb250ZXh0LmxvZ1N0cmVhbU5hbWUsXG4gICAgU3RhY2tJZDogcHJvcHMuZXZlbnQuU3RhY2tJZCxcbiAgICBSZXF1ZXN0SWQ6IHByb3BzLmV2ZW50LlJlcXVlc3RJZCxcbiAgICBMb2dpY2FsUmVzb3VyY2VJZDogcHJvcHMuZXZlbnQuTG9naWNhbFJlc291cmNlSWQsXG4gICAgRGF0YTogcHJvcHMucmVzcG9uc2VEYXRhLFxuICB9KTtcbiAgcmV0dXJuIGZldGNoKHByb3BzLmV2ZW50LlJlc3BvbnNlVVJMLCB7XG4gICAgbWV0aG9kOiAnUFVUJyxcbiAgICBib2R5LFxuICAgIGhlYWRlcnM6IHsgJ2NvbnRlbnQtdHlwZSc6ICcnLCAnY29udGVudC1sZW5ndGgnOiBib2R5Lmxlbmd0aC50b1N0cmluZygpIH0sXG4gIH0pO1xufVxuIl19