UNPKG

@cloudsnorkel/cdk-github-runners

Version:

CDK construct to create GitHub Actions self-hosted runners. Creates ephemeral runners on demand. Easy to deploy and highly customizable.

323 lines 45.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.handler = handler; const client_cloudformation_1 = require("@aws-sdk/client-cloudformation"); const client_ec2_1 = require("@aws-sdk/client-ec2"); const client_ecr_1 = require("@aws-sdk/client-ecr"); const client_sfn_1 = require("@aws-sdk/client-sfn"); const lambda_github_1 = require("./lambda-github"); const lambda_helpers_1 = require("./lambda-helpers"); const cfn = new client_cloudformation_1.CloudFormationClient(); const ec2 = new client_ec2_1.EC2Client(); const ecr = new client_ecr_1.ECRClient(); const sf = new client_sfn_1.SFNClient(); function secretArnToUrl(arn) { const parts = arn.split(':'); // arn:aws:secretsmanager:us-east-1:12345678:secret:secret-name-REVISION const region = parts[3]; const fullName = parts[6]; const name = fullName.slice(0, fullName.lastIndexOf('-')); return `https://${region}.console.aws.amazon.com/secretsmanager/home?region=${region}#!/secret?name=${name}`; } function lambdaArnToUrl(arn) { const parts = arn.split(':'); // arn:aws:lambda:us-east-1:12345678:function:name-XYZ const region = parts[3]; const name = parts[6]; return `https://${region}.console.aws.amazon.com/lambda/home?region=${region}#/functions/${name}?tab=monitoring`; } function lambdaArnToLogGroup(arn) { const parts = arn.split(':'); // arn:aws:lambda:us-east-1:12345678:function:name-XYZ const name = parts[6]; return `/aws/lambda/${name}`; } function stepFunctionArnToUrl(arn) { const parts = arn.split(':'); // arn:aws:states:us-east-1:12345678:stateMachine:name-XYZ const region = parts[3]; return `https://${region}.console.aws.amazon.com/states/home?region=${region}#/statemachines/view/${arn}`; } async function generateProvidersStatus(stack, logicalId) { const resource = await cfn.send(new client_cloudformation_1.DescribeStackResourceCommand({ StackName: stack, LogicalResourceId: logicalId })); const providers = JSON.parse(resource.StackResourceDetail?.Metadata ?? '{}').providers; if (!providers) { return {}; } return Promise.all(providers.map(async (p) => { // add ECR data, if image is from ECR if (p.image?.imageRepository?.match(/[0-9]+\.dkr\.ecr\.[a-z0-9\-]+\.amazonaws\.com\/.+/)) { const tags = await ecr.send(new client_ecr_1.DescribeImagesCommand({ repositoryName: p.image.imageRepository.split('/')[1], filter: { tagStatus: 'TAGGED', }, maxResults: 1, })); if (tags.imageDetails && tags.imageDetails?.length >= 1) { p.image.latestImage = { tags: tags.imageDetails[0].imageTags, digest: tags.imageDetails[0].imageDigest, date: tags.imageDetails[0].imagePushedAt, }; } } // add AMI data, if image is AMI if (p.ami?.launchTemplate) { const versions = await ec2.send(new client_ec2_1.DescribeLaunchTemplateVersionsCommand({ LaunchTemplateId: p.ami.launchTemplate, Versions: ['$Default'], })); if (versions.LaunchTemplateVersions && versions.LaunchTemplateVersions.length >= 1) { p.ami.latestAmi = versions.LaunchTemplateVersions[0].LaunchTemplateData?.ImageId; } } return p; })); } function safeReturnValue(event, status) { if (event.path) { return { statusCode: 200, headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(status), }; } return status; } async function handler(event) { // confirm required environment variables if (!process.env.WEBHOOK_SECRET_ARN || !process.env.GITHUB_SECRET_ARN || !process.env.GITHUB_PRIVATE_KEY_SECRET_ARN || !process.env.LOGICAL_ID || !process.env.WEBHOOK_HANDLER_ARN || !process.env.STEP_FUNCTION_ARN || !process.env.SETUP_SECRET_ARN || !process.env.STACK_NAME) { throw new Error('Missing environment variables'); } const [core, authApp] = await Promise.all([ (0, lambda_github_1.loadOctokitCore)(), (0, lambda_github_1.loadOctokitAuthApp)(), ]); const { Octokit } = core; const { createAppAuth } = authApp; // base status const status = { github: { setup: { status: 'Unknown', url: '', secretArn: process.env.SETUP_SECRET_ARN, secretUrl: secretArnToUrl(process.env.SETUP_SECRET_ARN), }, domain: 'Unknown', runnerLevel: 'Unknown', webhook: { url: process.env.WEBHOOK_URL, status: 'Unable to check', secretArn: process.env.WEBHOOK_SECRET_ARN, secretUrl: secretArnToUrl(process.env.WEBHOOK_SECRET_ARN), }, auth: { type: 'Unknown', status: 'Unknown', secretArn: process.env.GITHUB_SECRET_ARN, secretUrl: secretArnToUrl(process.env.GITHUB_SECRET_ARN), privateKeySecretArn: process.env.GITHUB_PRIVATE_KEY_SECRET_ARN, privateKeySecretUrl: secretArnToUrl(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN), app: { id: -1, url: '', installations: [], }, personalAuthToken: '', }, }, providers: await generateProvidersStatus(process.env.STACK_NAME, process.env.LOGICAL_ID), troubleshooting: { webhookHandlerArn: process.env.WEBHOOK_HANDLER_ARN, webhookHandlerUrl: lambdaArnToUrl(process.env.WEBHOOK_HANDLER_ARN), webhookHandlerLogGroup: lambdaArnToLogGroup(process.env.WEBHOOK_HANDLER_ARN), stepFunctionArn: process.env.STEP_FUNCTION_ARN, stepFunctionUrl: stepFunctionArnToUrl(process.env.STEP_FUNCTION_ARN), stepFunctionLogGroup: process.env.STEP_FUNCTION_LOG_GROUP, recentRuns: [], }, }; // setup url if (process.env.SETUP_FUNCTION_URL) { const setupToken = (await (0, lambda_helpers_1.getSecretJsonValue)(process.env.SETUP_SECRET_ARN)).token; if (setupToken) { status.github.setup.status = 'Pending'; status.github.setup.url = `${process.env.SETUP_FUNCTION_URL}?token=${setupToken}`; } else { status.github.setup.status = 'Complete'; } } else { status.github.setup.status = 'Disabled'; } // list last 10 executions and their status try { const executions = await sf.send(new client_sfn_1.ListExecutionsCommand({ stateMachineArn: process.env.STEP_FUNCTION_ARN, maxResults: 10, })); for (const execution of executions.executions ?? []) { const executionDetails = await sf.send(new client_sfn_1.DescribeExecutionCommand({ executionArn: execution.executionArn, })); const input = JSON.parse(executionDetails.input || '{}'); status.troubleshooting.recentRuns.push({ executionArn: execution.executionArn, status: execution.status ?? '<unknown>', owner: input.owner, repo: input.repo, jobId: input.jobId, }); } } catch (e) { status.troubleshooting.recentRuns.push({ status: `Error getting executions: ${e}` }); } // get secrets let githubSecrets; try { githubSecrets = await (0, lambda_helpers_1.getSecretJsonValue)(process.env.GITHUB_SECRET_ARN); } catch (e) { status.github.auth.status = `Unable to read secret: ${e}`; return safeReturnValue(event, status); } let privateKey; try { privateKey = await (0, lambda_helpers_1.getSecretValue)(process.env.GITHUB_PRIVATE_KEY_SECRET_ARN); } catch (e) { status.github.auth.status = `Unable to read private key secret: ${e}`; return safeReturnValue(event, status); } // calculate base url let baseUrl = (0, lambda_github_1.baseUrlFromDomain)(githubSecrets.domain); status.github.domain = githubSecrets.domain; // copy runner level status.github.runnerLevel = githubSecrets.runnerLevel ?? 'repo'; if (githubSecrets.personalAuthToken) { // try authenticating with personal access token status.github.auth.type = 'Personal Access Token'; status.github.auth.personalAuthToken = '*redacted*'; let octokit; try { octokit = new Octokit({ baseUrl, auth: githubSecrets.personalAuthToken }); } catch (e) { status.github.auth.status = `Unable to authenticate using personal auth token: ${e}`; return safeReturnValue(event, status); } try { const user = await octokit.request('GET /user'); status.github.auth.personalAuthToken = `username: ${user.data.login}`; } catch (e) { status.github.auth.status = `Unable to call /user with personal auth token: ${e}`; return safeReturnValue(event, status); } status.github.auth.status = 'OK'; status.github.webhook.status = 'Unable to verify automatically'; } else { // try authenticating with GitHub app status.github.auth.type = 'GitHub App'; status.github.auth.app.id = githubSecrets.appId; let appOctokit; try { appOctokit = new Octokit({ baseUrl, authStrategy: createAppAuth, auth: { appId: githubSecrets.appId, privateKey: privateKey, }, }); } catch (e) { status.github.auth.status = `Unable to authenticate app: ${e}`; return safeReturnValue(event, status); } // get app url try { const appRes = await appOctokit.request('GET /app'); const app = appRes.data; if (!app) { status.github.auth.status = `Unable to get app: ${appRes}`; return safeReturnValue(event, status); } status.github.auth.app.url = app.html_url; } catch (e) { status.github.auth.status = `Unable to get app details: ${e}`; return safeReturnValue(event, status); } // list all app installations try { const installations = (await appOctokit.request('GET /app/installations')).data; for (const installation of installations) { let installationDetails = { id: installation.id, url: installation.html_url, status: 'Unable to query', repositories: [], }; let token; try { token = (await appOctokit.auth({ type: 'installation', installationId: installation.id, })).token; } catch (e) { installationDetails.status = `Unable to authenticate app installation: ${e}`; continue; } let octokit; try { octokit = new Octokit({ baseUrl, auth: token }); } catch (e) { installationDetails.status = `Unable to authenticate using app: ${e}`; continue; } try { const repositories = (await octokit.request('GET /installation/repositories')).data.repositories; for (const repo of repositories) { installationDetails.repositories.push(repo.full_name); } } catch (e) { installationDetails.status = `Unable to authenticate using installation token: ${e}`; continue; } installationDetails.status = 'OK'; status.github.auth.app.installations.push(installationDetails); } } catch (e) { status.github.auth.status = 'Unable to list app installations'; return safeReturnValue(event, status); } status.github.auth.status = 'OK'; // check webhook config try { const response = await appOctokit.request('GET /app/hook/config', {}); if (response.data.url !== process.env.WEBHOOK_URL) { status.github.webhook.status = 'GitHub has wrong webhook URL configured'; } else { // TODO check secret by doing a dummy delivery? force apply secret? status.github.webhook.status = 'OK (note that secret cannot be checked automatically)'; } } catch (e) { status.github.webhook.status = `Unable to check app configuration: ${e}`; return safeReturnValue(event, status); } } return safeReturnValue(event, status); } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdHVzLmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zdGF0dXMubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBaUhBLDBCQW9QQztBQXJXRCwwRUFBb0c7QUFDcEcsb0RBQXVGO0FBQ3ZGLG9EQUF1RTtBQUN2RSxvREFBaUc7QUFFakcsbURBQXdHO0FBQ3hHLHFEQUFzRTtBQUV0RSxNQUFNLEdBQUcsR0FBRyxJQUFJLDRDQUFvQixFQUFFLENBQUM7QUFDdkMsTUFBTSxHQUFHLEdBQUcsSUFBSSxzQkFBUyxFQUFFLENBQUM7QUFDNUIsTUFBTSxHQUFHLEdBQUcsSUFBSSxzQkFBUyxFQUFFLENBQUM7QUFDNUIsTUFBTSxFQUFFLEdBQUcsSUFBSSxzQkFBUyxFQUFFLENBQUM7QUFFM0IsU0FBUyxjQUFjLENBQUMsR0FBVztJQUNqQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsd0VBQXdFO0lBQ3RHLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QixNQUFNLFFBQVEsR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDMUIsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDO0lBRTFELE9BQU8sV0FBVyxNQUFNLHNEQUFzRCxNQUFNLGtCQUFrQixJQUFJLEVBQUUsQ0FBQztBQUMvRyxDQUFDO0FBRUQsU0FBUyxjQUFjLENBQUMsR0FBVztJQUNqQyxNQUFNLEtBQUssR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsc0RBQXNEO0lBQ3BGLE1BQU0sTUFBTSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4QixNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFD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QyxNQUFNLEdBQUcsdURBQXVELENBQUM7WUFDekYsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLHNDQUFzQyxDQUFDLEVBQUUsQ0FBQztZQUN6RSxPQUFPLGVBQWUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDeEMsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLGVBQWUsQ0FBQyxLQUFLLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDeEMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENsb3VkRm9ybWF0aW9uQ2xpZW50LCBEZXNjcmliZVN0YWNrUmVzb3VyY2VDb21tYW5kIH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWNsb3VkZm9ybWF0aW9uJztcbmltcG9ydCB7IERlc2NyaWJlTGF1bmNoVGVtcGxhdGVWZXJzaW9uc0NvbW1hbmQsIEVDMkNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lYzInO1xuaW1wb3J0IHsgRUNSQ2xpZW50LCBEZXNjcmliZUltYWdlc0NvbW1hbmQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtZWNyJztcbmltcG9ydCB7IERlc2NyaWJlRXhlY3V0aW9uQ29tbWFuZCwgTGlzdEV4ZWN1dGlvbnNDb21tYW5kLCBTRk5DbGllbnQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtc2ZuJztcbmltcG9ydCAqIGFzIEFXU0xhbWJkYSBmcm9tICdhd3MtbGFtYmRhJztcbmltcG9ydCB7IGJhc2VVcmxGcm9tRG9tYWluLCBHaXRIdWJTZWNyZXRzLCBsb2FkT2N0b2tpdEF1dGhBcHAsIGxvYWRPY3Rva2l0Q29yZSB9IGZyb20gJy4vbGFtYmRhLWdpdGh1Yic7XG5pbXBvcnQgeyBnZXRTZWNyZXRKc29uVmFsdWUsIGdldFNlY3JldFZhbHVlIH0gZnJvbSAnLi9sYW1iZGEtaGVscGVycyc7XG5cbmNvbnN0IGNmbiA9IG5ldyBDbG91ZEZvcm1hdGlvbkNsaWVudCgpO1xuY29uc3QgZWMyID0gbmV3IEVDMkNsaWVudCgpO1xuY29uc3QgZWNyID0gbmV3IEVDUkNsaWVudCgpO1xuY29uc3Qgc2YgPSBuZXcgU0ZOQ2xpZW50KCk7XG5cbmZ1bmN0aW9uIHNlY3JldEFyblRvVXJsKGFybjogc3RyaW5nKSB7XG4gIGNvbnN0IHBhcnRzID0gYXJuLnNwbGl0KCc6Jyk7IC8vIGFybjphd3M6c2VjcmV0c21hbmFnZXI6dXMtZWFzdC0xOjEyMzQ1Njc4OnNlY3JldDpzZWNyZXQtbmFtZS1SRVZJU0lPTlxuICBjb25zdCByZWdpb24gPSBwYXJ0c1szXTtcbiAgY29uc3QgZnVsbE5hbWUgPSBwYXJ0c1s2XTtcbiAgY29uc3QgbmFtZSA9IGZ1bGxOYW1lLnNsaWNlKDAsIGZ1bGxOYW1lLmxhc3RJbmRleE9mKCctJykpO1xuXG4gIHJldHVybiBgaHR0cHM6Ly8ke3JlZ2lvbn0uY29uc29sZS5hd3MuYW1hem9uLmNvbS9zZWNyZXRzbWFuYWdlci9ob21lP3JlZ2lvbj0ke3JlZ2lvbn0jIS9zZWNyZXQ/bmFtZT0ke25hbWV9YDtcbn1cblxuZnVuY3Rpb24gbGFtYmRhQXJuVG9VcmwoYXJuOiBzdHJpbmcpIHtcbiAgY29uc3QgcGFydHMgPSBhcm4uc3BsaXQoJzonKTsgLy8gYXJuOmF3czpsYW1iZGE6dXMtZWFzdC0xOjEyMzQ1Njc4OmZ1bmN0aW9uOm5hbWUtWFlaXG4gIGNvbnN0IHJlZ2lvbiA9IHBhcnRzWzNdO1xuICBjb25zdCBuYW1lID0gcGFydHNbNl07XG5cbiAgcmV0dXJuIGBodHRwczovLyR7cmVnaW9ufS5jb25zb2xlLmF3cy5hbWF6b24uY29tL2xhbWJkYS9ob21lP3JlZ2lvbj0ke3JlZ2lvbn0jL2Z1bmN0aW9ucy8ke25hbWV9P3RhYj1tb25pdG9yaW5nYDtcbn1cblxuZnVuY3Rpb24gbGFtYmRhQXJuVG9Mb2dHcm91cChhcm46IHN0cmluZykge1xuICBjb25zdCBwYXJ0cyA9IGFybi5zcGxpdCgnOicpOyAvLyBhcm46YXdzOmxhbWJkYTp1cy1lYXN0LTE6MTIzNDU2Nzg6ZnVuY3Rpb246bmFtZS1YWVpcbiAgY29uc3QgbmFtZSA9IHBhcnRzWzZdO1xuXG4gIHJldHVybiBgL2F3cy9sYW1iZGEvJHtuYW1lfWA7XG59XG5cbmZ1bmN0aW9uIHN0ZXBGdW5jdGlvbkFyblRvVXJsKGFybjogc3RyaW5nKSB7XG4gIGNvbnN0IHBhcnRzID0gYXJuLnNwbGl0KCc6Jyk7IC8vIGFybjphd3M6c3RhdGVzOnVzLWVhc3QtMToxMjM0NTY3ODpzdGF0ZU1hY2hpbmU6bmFtZS1YWVpcbiAgY29uc3QgcmVnaW9uID0gcGFydHNbM107XG5cbiAgcmV0dXJuIGBodHRwczovLyR7cmVnaW9ufS5jb25zb2xlLmF3cy5hbWF6b24uY29tL3N0YXRlcy9ob21lP3JlZ2lvbj0ke3JlZ2lvbn0jL3N0YXRlbWFjaGluZXMvdmlldy8ke2Fybn1gO1xufVxuXG5hc3luYyBmdW5jdGlvbiBnZW5lcmF0ZVByb3ZpZGVyc1N0YXR1cyhzdGFjazogc3RyaW5nLCBsb2dpY2FsSWQ6IHN0cmluZykge1xuICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IGNmbi5zZW5kKG5ldyBEZXNjcmliZVN0YWNrUmVzb3VyY2VDb21tYW5kKHsgU3RhY2tOYW1lOiBzdGFjaywgTG9naWNhbFJlc291cmNlSWQ6IGxvZ2ljYWxJZCB9KSk7XG4gIGNvbnN0IHByb3ZpZGVycyA9IEpTT04ucGFyc2UocmVzb3VyY2UuU3RhY2tSZXNvdXJjZURldGFpbD8uTWV0YWRhdGEgPz8gJ3t9JykucHJvdmlkZXJzIGFzIGFueVtdIHwgdW5kZWZpbmVkO1xuXG4gIGlmICghcHJvdmlkZXJzKSB7XG4gICAgcmV0dXJuIHt9O1xuICB9XG5cbiAgcmV0dXJuIFByb21pc2UuYWxsKHByb3ZpZGVycy5tYXAoYXN5bmMgKHApID0+IHtcbiAgICAvLyBhZGQgRUNSIGRhdGEsIGlmIGltYWdlIGlzIGZyb20gRUNSXG4gICAgaWYgKHAuaW1hZ2U/LmltYWdlUmVwb3NpdG9yeT8ubWF0Y2goL1swLTldK1xcLmRrclxcLmVjclxcLlthLXowLTlcXC1dK1xcLmFtYXpvbmF3c1xcLmNvbVxcLy4rLykpIHtcbiAgICAgIGNvbnN0IHRhZ3MgPSBhd2FpdCBlY3Iuc2VuZChuZXcgRGVzY3JpYmVJbWFnZXNDb21tYW5kKHtcbiAgICAgICAgcmVwb3NpdG9yeU5hbWU6IHAuaW1hZ2UuaW1hZ2VSZXBvc2l0b3J5LnNwbGl0KCcvJylbMV0sXG4gICAgICAgIGZpbHRlcjoge1xuICAgICAgICAgIHRhZ1N0YXR1czogJ1RBR0dFRCcsXG4gICAgICAgIH0sXG4gICAgICAgIG1heFJlc3VsdHM6IDEsXG4gICAgICB9KSk7XG4gICAgICBpZiAodGFncy5pbWFnZURldGFpbHMgJiYgdGFncy5pbWFnZURldGFpbHM/Lmxlbmd0aCA+PSAxKSB7XG4gICAgICAgIHAuaW1hZ2UubGF0ZXN0SW1hZ2UgPSB7XG4gICAgICAgICAgdGFnczogdGFncy5pbWFnZURldGFpbHNbMF0uaW1hZ2VUYWdzLFxuICAgICAgICAgIGRpZ2VzdDogdGFncy5pbWFnZURldGFpbHNbMF0uaW1hZ2VEaWdlc3QsXG4gICAgICAgICAgZGF0ZTogdGFncy5pbWFnZURldGFpbHNbMF0uaW1hZ2VQdXNoZWRBdCxcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG4gICAgLy8gYWRkIEFNSSBkYXRhLCBpZiBpbWFnZSBpcyBBTUlcbiAgICBpZiAocC5hbWk/LmxhdW5jaFRlbXBsYXRlKSB7XG4gICAgICBjb25zdCB2ZXJzaW9ucyA9IGF3YWl0IGVjMi5zZW5kKG5ldyBEZXNjcmliZUxhdW5jaFRlbXBsYXRlVmVyc2lvbnNDb21tYW5kKHtcbiAgICAgICAgTGF1bmNoVGVtcGxhdGVJZDogcC5hbWkubGF1bmNoVGVtcGxhdGUsXG4gICAgICAgIFZlcnNpb25zOiBbJyREZWZhdWx0J10sXG4gICAgICB9KSk7XG4gICAgICBpZiAodmVyc2lvbnMuTGF1bmNoVGVtcGxhdGVWZXJzaW9ucyAmJiB2ZXJzaW9ucy5MYXVuY2hUZW1wbGF0ZVZlcnNpb25zLmxlbmd0aCA+PSAxKSB7XG4gICAgICAgIHAuYW1pLmxhdGVzdEFtaSA9IHZlcnNpb25zLkxhdW5jaFRlbXBsYXRlVmVyc2lvbnNbMF0uTGF1bmNoVGVtcGxhdGVEYXRhPy5JbWFnZUlkO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcDtcbiAgfSkpO1xufVxuXG5pbnRlcmZhY2UgQXBwSW5zdGFsbGF0aW9uIHtcbiAgcmVhZG9ubHkgaWQ6IG51bWJlcjtcbiAgcmVhZG9ubHkgdXJsOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN0YXR1czogc3RyaW5nO1xuICByZWFkb25seSByZXBvc2l0b3JpZXM6IHN0cmluZ1tdO1xufVxuXG5pbnRlcmZhY2UgUmVjZW50UnVuIHtcbiAgcmVhZG9ubHkgb3duZXI/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJlcG8/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGpvYklkPzogc3RyaW5nO1xuICByZWFkb25seSBleGVjdXRpb25Bcm4/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IHN0YXR1czogc3RyaW5nO1xufVxuXG5mdW5jdGlvbiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQ6IFBhcnRpYWw8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eUV2ZW50Piwgc3RhdHVzOiBhbnkpIHtcbiAgaWYgKGV2ZW50LnBhdGgpIHtcbiAgICByZXR1cm4ge1xuICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgaGVhZGVyczoge1xuICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgfSxcbiAgICAgIGJvZHk6IEpTT04uc3RyaW5naWZ5KHN0YXR1cyksXG4gICAgfTtcbiAgfVxuXG4gIHJldHVybiBzdGF0dXM7XG59XG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBoYW5kbGVyKGV2ZW50OiBQYXJ0aWFsPEFXU0xhbWJkYS5BUElHYXRld2F5UHJveHlFdmVudD4pIHtcbiAgLy8gY29uZmlybSByZXF1aXJlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbiAgaWYgKCFwcm9jZXNzLmVudi5XRUJIT09LX1NFQ1JFVF9BUk4gfHwgIXByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOIHx8ICFwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTiB8fCAhcHJvY2Vzcy5lbnYuTE9HSUNBTF9JRCB8fFxuICAgICAgIXByb2Nlc3MuZW52LldFQkhPT0tfSEFORExFUl9BUk4gfHwgIXByb2Nlc3MuZW52LlNURVBfRlVOQ1RJT05fQVJOIHx8ICFwcm9jZXNzLmVudi5TRVRVUF9TRUNSRVRfQVJOIHx8XG4gICAgICAhcHJvY2Vzcy5lbnYuU1RBQ0tfTkFNRSkge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBlbnZpcm9ubWVudCB2YXJpYWJsZXMnKTtcbiAgfVxuXG4gIGNvbnN0IFtjb3JlLCBhdXRoQXBwXSA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBsb2FkT2N0b2tpdENvcmUoKSxcbiAgICBsb2FkT2N0b2tpdEF1dGhBcHAoKSxcbiAgXSk7XG4gIGNvbnN0IHsgT2N0b2tpdCB9ID0gY29yZTtcbiAgY29uc3QgeyBjcmVhdGVBcHBBdXRoIH0gPSBhdXRoQXBwO1xuXG4gIC8vIGJhc2Ugc3RhdHVzXG4gIGNvbnN0IHN0YXR1cyA9IHtcbiAgICBnaXRodWI6IHtcbiAgICAgIHNldHVwOiB7XG4gICAgICAgIHN0YXR1czogJ1Vua25vd24nLFxuICAgICAgICB1cmw6ICcnLFxuICAgICAgICBzZWNyZXRBcm46IHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4sXG4gICAgICAgIHNlY3JldFVybDogc2VjcmV0QXJuVG9VcmwocHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTiksXG4gICAgICB9LFxuICAgICAgZG9tYWluOiAnVW5rbm93bicsXG4gICAgICBydW5uZXJMZXZlbDogJ1Vua25vd24nLFxuICAgICAgd2ViaG9vazoge1xuICAgICAgICB1cmw6IHByb2Nlc3MuZW52LldFQkhPT0tfVVJMLFxuICAgICAgICBzdGF0dXM6ICdVbmFibGUgdG8gY2hlY2snLFxuICAgICAgICBzZWNyZXRBcm46IHByb2Nlc3MuZW52LldFQkhPT0tfU0VDUkVUX0FSTixcbiAgICAgICAgc2VjcmV0VXJsOiBzZWNyZXRBcm5Ub1VybChwcm9jZXNzLmVudi5XRUJIT09LX1NFQ1JFVF9BUk4pLFxuICAgICAgfSxcbiAgICAgIGF1dGg6IHtcbiAgICAgICAgdHlwZTogJ1Vua25vd24nLFxuICAgICAgICBzdGF0dXM6ICdVbmtub3duJyxcbiAgICAgICAgc2VjcmV0QXJuOiBwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTixcbiAgICAgICAgc2VjcmV0VXJsOiBzZWNyZXRBcm5Ub1VybChwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTiksXG4gICAgICAgIHByaXZhdGVLZXlTZWNyZXRBcm46IHByb2Nlc3MuZW52LkdJVEhVQl9QUklWQVRFX0tFWV9TRUNSRVRfQVJOLFxuICAgICAgICBwcml2YXRlS2V5U2VjcmV0VXJsOiBzZWNyZXRBcm5Ub1VybChwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTiksXG4gICAgICAgIGFwcDoge1xuICAgICAgICAgIGlkOiAtMSxcbiAgICAgICAgICB1cmw6ICcnLFxuICAgICAgICAgIGluc3RhbGxhdGlvbnM6IFtdIGFzIEFwcEluc3RhbGxhdGlvbltdLFxuICAgICAgICB9LFxuICAgICAgICBwZXJzb25hbEF1dGhUb2tlbjogJycsXG4gICAgICB9LFxuICAgIH0sXG4gICAgcHJvdmlkZXJzOiBhd2FpdCBnZW5lcmF0ZVByb3ZpZGVyc1N0YXR1cyhwcm9jZXNzLmVudi5TVEFDS19OQU1FLCBwcm9jZXNzLmVudi5MT0dJQ0FMX0lEKSxcbiAgICB0cm91Ymxlc2hvb3Rpbmc6IHtcbiAgICAgIHdlYmhvb2tIYW5kbGVyQXJuOiBwcm9jZXNzLmVudi5XRUJIT09LX0hBTkRMRVJfQVJOLFxuICAgICAgd2ViaG9va0hhbmRsZXJVcmw6IGxhbWJkYUFyblRvVXJsKHByb2Nlc3MuZW52LldFQkhPT0tfSEFORExFUl9BUk4pLFxuICAgICAgd2ViaG9va0hhbmRsZXJMb2dHcm91cDogbGFtYmRhQXJuVG9Mb2dHcm91cChwcm9jZXNzLmVudi5XRUJIT09LX0hBTkRMRVJfQVJOKSxcbiAgICAgIHN0ZXBGdW5jdGlvbkFybjogcHJvY2Vzcy5lbnYuU1RFUF9GVU5DVElPTl9BUk4sXG4gICAgICBzdGVwRnVuY3Rpb25Vcmw6IHN0ZXBGdW5jdGlvbkFyblRvVXJsKHByb2Nlc3MuZW52LlNURVBfRlVOQ1RJT05fQVJOKSxcbiAgICAgIHN0ZXBGdW5jdGlvbkxvZ0dyb3VwOiBwcm9jZXNzLmVudi5TVEVQX0ZVTkNUSU9OX0xPR19HUk9VUCxcbiAgICAgIHJlY2VudFJ1bnM6IFtdIGFzIFJlY2VudFJ1bltdLFxuICAgIH0sXG4gIH07XG5cbiAgLy8gc2V0dXAgdXJsXG4gIGlmIChwcm9jZXNzLmVudi5TRVRVUF9GVU5DVElPTl9VUkwpIHtcbiAgICBjb25zdCBzZXR1cFRva2VuID0gKGF3YWl0IGdldFNlY3JldEpzb25WYWx1ZShwcm9jZXNzLmVudi5TRVRVUF9TRUNSRVRfQVJOKSkudG9rZW47XG4gICAgaWYgKHNldHVwVG9rZW4pIHtcbiAgICAgIHN0YXR1cy5naXRodWIuc2V0dXAuc3RhdHVzID0gJ1BlbmRpbmcnO1xuICAgICAgc3RhdHVzLmdpdGh1Yi5zZXR1cC51cmwgPSBgJHtwcm9jZXNzLmVudi5TRVRVUF9GVU5DVElPTl9VUkx9P3Rva2VuPSR7c2V0dXBUb2tlbn1gO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLnNldHVwLnN0YXR1cyA9ICdDb21wbGV0ZSc7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIHN0YXR1cy5naXRodWIuc2V0dXAuc3RhdHVzID0gJ0Rpc2FibGVkJztcbiAgfVxuXG4gIC8vIGxpc3QgbGFzdCAxMCBleGVjdXRpb25zIGFuZCB0aGVpciBzdGF0dXNcbiAgdHJ5IHtcbiAgICBjb25zdCBleGVjdXRpb25zID0gYXdhaXQgc2Yuc2VuZChuZXcgTGlzdEV4ZWN1dGlvbnNDb21tYW5kKHtcbiAgICAgIHN0YXRlTWFjaGluZUFybjogcHJvY2Vzcy5lbnYuU1RFUF9GVU5DVElPTl9BUk4sXG4gICAgICBtYXhSZXN1bHRzOiAxMCxcbiAgICB9KSk7XG4gICAgZm9yIChjb25zdCBleGVjdXRpb24gb2YgZXhlY3V0aW9ucy5leGVjdXRpb25zID8/IFtdKSB7XG4gICAgICBjb25zdCBleGVjdXRpb25EZXRhaWxzID0gYXdhaXQgc2Yuc2VuZChuZXcgRGVzY3JpYmVFeGVjdXRpb25Db21tYW5kKHtcbiAgICAgICAgZXhlY3V0aW9uQXJuOiBleGVjdXRpb24uZXhlY3V0aW9uQXJuLFxuICAgICAgfSkpO1xuICAgICAgY29uc3QgaW5wdXQgPSBKU09OLnBhcnNlKGV4ZWN1dGlvbkRldGFpbHMuaW5wdXQgfHwgJ3t9Jyk7XG5cbiAgICAgIHN0YXR1cy50cm91Ymxlc2hvb3RpbmcucmVjZW50UnVucy5wdXNoKHtcbiAgICAgICAgZXhlY3V0aW9uQXJuOiBleGVjdXRpb24uZXhlY3V0aW9uQXJuLFxuICAgICAgICBzdGF0dXM6IGV4ZWN1dGlvbi5zdGF0dXMgPz8gJzx1bmtub3duPicsXG4gICAgICAgIG93bmVyOiBpbnB1dC5vd25lcixcbiAgICAgICAgcmVwbzogaW5wdXQucmVwbyxcbiAgICAgICAgam9iSWQ6IGlucHV0LmpvYklkLFxuICAgICAgfSk7XG4gICAgfVxuICB9IGNhdGNoIChlKSB7XG4gICAgc3RhdHVzLnRyb3VibGVzaG9vdGluZy5yZWNlbnRSdW5zLnB1c2goeyBzdGF0dXM6IGBFcnJvciBnZXR0aW5nIGV4ZWN1dGlvbnM6ICR7ZX1gIH0pO1xuICB9XG5cbiAgLy8gZ2V0IHNlY3JldHNcbiAgbGV0IGdpdGh1YlNlY3JldHM6IEdpdEh1YlNlY3JldHM7XG4gIHRyeSB7XG4gICAgZ2l0aHViU2VjcmV0cyA9IGF3YWl0IGdldFNlY3JldEpzb25WYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfU0VDUkVUX0FSTik7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gYFVuYWJsZSB0byByZWFkIHNlY3JldDogJHtlfWA7XG4gICAgcmV0dXJuIHNhZmVSZXR1cm5WYWx1ZShldmVudCwgc3RhdHVzKTtcbiAgfVxuXG4gIGxldCBwcml2YXRlS2V5O1xuICB0cnkge1xuICAgIHByaXZhdGVLZXkgPSBhd2FpdCBnZXRTZWNyZXRWYWx1ZShwcm9jZXNzLmVudi5HSVRIVUJfUFJJVkFURV9LRVlfU0VDUkVUX0FSTik7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gYFVuYWJsZSB0byByZWFkIHByaXZhdGUga2V5IHNlY3JldDogJHtlfWA7XG4gICAgcmV0dXJuIHNhZmVSZXR1cm5WYWx1ZShldmVudCwgc3RhdHVzKTtcbiAgfVxuXG4gIC8vIGNhbGN1bGF0ZSBiYXNlIHVybFxuICBsZXQgYmFzZVVybCA9IGJhc2VVcmxGcm9tRG9tYWluKGdpdGh1YlNlY3JldHMuZG9tYWluKTtcbiAgc3RhdHVzLmdpdGh1Yi5kb21haW4gPSBnaXRodWJTZWNyZXRzLmRvbWFpbjtcblxuICAvLyBjb3B5IHJ1bm5lciBsZXZlbFxuICBzdGF0dXMuZ2l0aHViLnJ1bm5lckxldmVsID0gZ2l0aHViU2VjcmV0cy5ydW5uZXJMZXZlbCA/PyAncmVwbyc7XG5cbiAgaWYgKGdpdGh1YlNlY3JldHMucGVyc29uYWxBdXRoVG9rZW4pIHtcbiAgICAvLyB0cnkgYXV0aGVudGljYXRpbmcgd2l0aCBwZXJzb25hbCBhY2Nlc3MgdG9rZW5cbiAgICBzdGF0dXMuZ2l0aHViLmF1dGgudHlwZSA9ICdQZXJzb25hbCBBY2Nlc3MgVG9rZW4nO1xuICAgIHN0YXR1cy5naXRodWIuYXV0aC5wZXJzb25hbEF1dGhUb2tlbiA9ICcqcmVkYWN0ZWQqJztcblxuICAgIGxldCBvY3Rva2l0O1xuICAgIHRyeSB7XG4gICAgICBvY3Rva2l0ID0gbmV3IE9jdG9raXQoeyBiYXNlVXJsLCBhdXRoOiBnaXRodWJTZWNyZXRzLnBlcnNvbmFsQXV0aFRva2VuIH0pO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIGF1dGhlbnRpY2F0ZSB1c2luZyBwZXJzb25hbCBhdXRoIHRva2VuOiAke2V9YDtcbiAgICAgIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG4gICAgfVxuXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHVzZXIgPSBhd2FpdCBvY3Rva2l0LnJlcXVlc3QoJ0dFVCAvdXNlcicpO1xuICAgICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnBlcnNvbmFsQXV0aFRva2VuID0gYHVzZXJuYW1lOiAke3VzZXIuZGF0YS5sb2dpbn1gO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIGNhbGwgL3VzZXIgd2l0aCBwZXJzb25hbCBhdXRoIHRva2VuOiAke2V9YDtcbiAgICAgIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG4gICAgfVxuXG4gICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9ICdPSyc7XG4gICAgc3RhdHVzLmdpdGh1Yi53ZWJob29rLnN0YXR1cyA9ICdVbmFibGUgdG8gdmVyaWZ5IGF1dG9tYXRpY2FsbHknO1xuICB9IGVsc2Uge1xuICAgIC8vIHRyeSBhdXRoZW50aWNhdGluZyB3aXRoIEdpdEh1YiBhcHBcbiAgICBzdGF0dXMuZ2l0aHViLmF1dGgudHlwZSA9ICdHaXRIdWIgQXBwJztcbiAgICBzdGF0dXMuZ2l0aHViLmF1dGguYXBwLmlkID0gZ2l0aHViU2VjcmV0cy5hcHBJZDtcblxuICAgIGxldCBhcHBPY3Rva2l0O1xuICAgIHRyeSB7XG4gICAgICBhcHBPY3Rva2l0ID0gbmV3IE9jdG9raXQoe1xuICAgICAgICBiYXNlVXJsLFxuICAgICAgICBhdXRoU3RyYXRlZ3k6IGNyZWF0ZUFwcEF1dGgsXG4gICAgICAgIGF1dGg6IHtcbiAgICAgICAgICBhcHBJZDogZ2l0aHViU2VjcmV0cy5hcHBJZCxcbiAgICAgICAgICBwcml2YXRlS2V5OiBwcml2YXRlS2V5LFxuICAgICAgICB9LFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIGFwcDogJHtlfWA7XG4gICAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICAgIH1cblxuICAgIC8vIGdldCBhcHAgdXJsXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGFwcFJlcyA9IGF3YWl0IGFwcE9jdG9raXQucmVxdWVzdCgnR0VUIC9hcHAnKTtcbiAgICAgIGNvbnN0IGFwcCA9IGFwcFJlcy5kYXRhO1xuICAgICAgaWYgKCFhcHApIHtcbiAgICAgICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9IGBVbmFibGUgdG8gZ2V0IGFwcDogJHthcHBSZXN9YDtcbiAgICAgICAgcmV0dXJuIHNhZmVSZXR1cm5WYWx1ZShldmVudCwgc3RhdHVzKTtcbiAgICAgIH1cbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5hcHAudXJsID0gYXBwLmh0bWxfdXJsO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIGdldCBhcHAgZGV0YWlsczogJHtlfWA7XG4gICAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICAgIH1cblxuICAgIC8vIGxpc3QgYWxsIGFwcCBpbnN0YWxsYXRpb25zXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGluc3RhbGxhdGlvbnMgPSAoYXdhaXQgYXBwT2N0b2tpdC5yZXF1ZXN0KCdHRVQgL2FwcC9pbnN0YWxsYXRpb25zJykpLmRhdGE7XG4gICAgICBmb3IgKGNvbnN0IGluc3RhbGxhdGlvbiBvZiBpbnN0YWxsYXRpb25zKSB7XG4gICAgICAgIGxldCBpbnN0YWxsYXRpb25EZXRhaWxzID0ge1xuICAgICAgICAgIGlkOiBpbnN0YWxsYXRpb24uaWQsXG4gICAgICAgICAgdXJsOiBpbnN0YWxsYXRpb24uaHRtbF91cmwsXG4gICAgICAgICAgc3RhdHVzOiAnVW5hYmxlIHRvIHF1ZXJ5JyxcbiAgICAgICAgICByZXBvc2l0b3JpZXM6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgICB9O1xuXG4gICAgICAgIGxldCB0b2tlbjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0b2tlbiA9IChhd2FpdCBhcHBPY3Rva2l0LmF1dGgoe1xuICAgICAgICAgICAgdHlwZTogJ2luc3RhbGxhdGlvbicsXG4gICAgICAgICAgICBpbnN0YWxsYXRpb25JZDogaW5zdGFsbGF0aW9uLmlkLFxuICAgICAgICAgIH0pIGFzIGFueSkudG9rZW47XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIGFwcCBpbnN0YWxsYXRpb246ICR7ZX1gO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG9jdG9raXQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgb2N0b2tpdCA9IG5ldyBPY3Rva2l0KHsgYmFzZVVybCwgYXV0aDogdG9rZW4gfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIHVzaW5nIGFwcDogJHtlfWA7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlcG9zaXRvcmllcyA9IChhd2FpdCBvY3Rva2l0LnJlcXVlc3QoJ0dFVCAvaW5zdGFsbGF0aW9uL3JlcG9zaXRvcmllcycpKS5kYXRhLnJlcG9zaXRvcmllcztcbiAgICAgICAgICBmb3IgKGNvbnN0IHJlcG8gb2YgcmVwb3NpdG9yaWVzKSB7XG4gICAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnJlcG9zaXRvcmllcy5wdXNoKHJlcG8uZnVsbF9uYW1lIGFzIHN0cmluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgaW5zdGFsbGF0aW9uRGV0YWlscy5zdGF0dXMgPSBgVW5hYmxlIHRvIGF1dGhlbnRpY2F0ZSB1c2luZyBpbnN0YWxsYXRpb24gdG9rZW46ICR7ZX1gO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5zdGFsbGF0aW9uRGV0YWlscy5zdGF0dXMgPSAnT0snO1xuICAgICAgICBzdGF0dXMuZ2l0aHViLmF1dGguYXBwLmluc3RhbGxhdGlvbnMucHVzaChpbnN0YWxsYXRpb25EZXRhaWxzKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gJ1VuYWJsZSB0byBsaXN0IGFwcCBpbnN0YWxsYXRpb25zJztcbiAgICAgIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG4gICAgfVxuXG4gICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9ICdPSyc7XG5cbiAgICAvLyBjaGVjayB3ZWJob29rIGNvbmZpZ1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGFwcE9jdG9raXQucmVxdWVzdCgnR0VUIC9hcHAvaG9vay9jb25maWcnLCB7fSk7XG5cbiAgICAgIGlmIChyZXNwb25zZS5kYXRhLnVybCAhPT0gcHJvY2Vzcy5lbnYuV0VCSE9PS19VUkwpIHtcbiAgICAgICAgc3RhdHVzLmdpdGh1Yi53ZWJob29rLnN0YXR1cyA9ICdHaXRIdWIgaGFzIHdyb25nIHdlYmhvb2sgVVJMIGNvbmZpZ3VyZWQnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVE9ETyBjaGVjayBzZWNyZXQgYnkgZG9pbmcgYSBkdW1teSBkZWxpdmVyeT8gZm9yY2UgYXBwbHkgc2VjcmV0P1xuICAgICAgICBzdGF0dXMuZ2l0aHViLndlYmhvb2suc3RhdHVzID0gJ09LIChub3RlIHRoYXQgc2VjcmV0IGNhbm5vdCBiZSBjaGVja2VkIGF1dG9tYXRpY2FsbHkpJztcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLndlYmhvb2suc3RhdHVzID0gYFVuYWJsZSB0byBjaGVjayBhcHAgY29uZmlndXJhdGlvbjogJHtlfWA7XG4gICAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG59XG4iXX0=