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.

314 lines 44 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 auth_app_1 = require("@octokit/auth-app"); const core_1 = require("@octokit/core"); 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'); } // 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 core_1.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 core_1.Octokit({ baseUrl, authStrategy: auth_app_1.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 app = (await appOctokit.request('GET /app')).data; 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 core_1.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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RhdHVzLmxhbWJkYS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9zdGF0dXMubGFtYmRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBbUhBLDBCQXdPQztBQTNWRCwwRUFBb0c7QUFDcEcsb0RBQXVGO0FBQ3ZGLG9EQUF1RTtBQUN2RSxvREFBaUc7QUFDakcsZ0RBQWtEO0FBQ2xELHdDQUF3QztBQUV4QyxtREFBbUU7QUFDbkUscURBQXNFO0FBRXRFLE1BQU0sR0FBRyxHQUFHLElBQUksNENBQW9CLEVBQUUsQ0FBQztBQUN2QyxNQUFNLEdBQUcsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUM1QixNQUFNLEdBQUcsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUM1QixNQUFNLEVBQUUsR0FBRyxJQUFJLHNCQUFTLEVBQUUsQ0FBQztBQUUzQixTQUFTLGNBQWMsQ0FBQyxHQUFXO0lBQ2pDLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyx3RUFBd0U7SUFDdEcsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLE1BQU0sUUFBUSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUMxQixNQUFNLElBQUksR0FBRyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxRQUFRLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFFMUQsT0FBTyxXQUFXLE1BQU0sc0RBQXNELE1BQU0sa0JBQWtCLElBQUksRUFBRSxDQUFDO0FBQy9HLENBQUM7QUFFRCxTQUFTLGNBQWMsQ0FBQyxHQUFXO0lBQ2pDLE1BQU0sS0FBSyxHQUFHLEdBQUcsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxzREFBc0Q7SUFDcEYsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3hCLE1BQU0sSUFB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QUFDLG1CQUFtQixDQUFDLENBQUM7WUFDakUsQ0FBQztRQUNILENBQUM7UUFBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ1gsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLGtDQUFrQyxDQUFDO1lBQy9ELE9BQU8sZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN4QyxDQUFDO1FBRUQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztRQUVqQyx1QkFBdUI7UUFDdkIsSUFBSSxDQUFDO1lBQ0gsTUFBTSxRQUFRLEdBQUcsTUFBTSxVQUFVLENBQUMsT0FBTyxDQUFDLHNCQUFzQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBRXRFLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDbEQsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxHQUFHLHlDQUF5QyxDQUFDO1lBQzNFLENBQUM7aUJBQU0sQ0FBQztnQkFDTixtRUFBbUU7Z0JBQ25FLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyx1REFBdUQsQ0FBQztZQUN6RixDQUFDO1FBQ0gsQ0FBQztRQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7WUFDWCxNQUFNLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEdBQUcsc0NBQXNDLENBQUMsRUFBRSxDQUFDO1lBQ3pFLE9BQU8sZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztRQUN4QyxDQUFDO0lBQ0gsQ0FBQztJQUVELE9BQU8sZUFBZSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQztBQUN4QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ2xvdWRGb3JtYXRpb25DbGllbnQsIERlc2NyaWJlU3RhY2tSZXNvdXJjZUNvbW1hbmQgfSBmcm9tICdAYXdzLXNkay9jbGllbnQtY2xvdWRmb3JtYXRpb24nO1xuaW1wb3J0IHsgRGVzY3JpYmVMYXVuY2hUZW1wbGF0ZVZlcnNpb25zQ29tbWFuZCwgRUMyQ2xpZW50IH0gZnJvbSAnQGF3cy1zZGsvY2xpZW50LWVjMic7XG5pbXBvcnQgeyBFQ1JDbGllbnQsIERlc2NyaWJlSW1hZ2VzQ29tbWFuZCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1lY3InO1xuaW1wb3J0IHsgRGVzY3JpYmVFeGVjdXRpb25Db21tYW5kLCBMaXN0RXhlY3V0aW9uc0NvbW1hbmQsIFNGTkNsaWVudCB9IGZyb20gJ0Bhd3Mtc2RrL2NsaWVudC1zZm4nO1xuaW1wb3J0IHsgY3JlYXRlQXBwQXV0aCB9IGZyb20gJ0BvY3Rva2l0L2F1dGgtYXBwJztcbmltcG9ydCB7IE9jdG9raXQgfSBmcm9tICdAb2N0b2tpdC9jb3JlJztcbmltcG9ydCAqIGFzIEFXU0xhbWJkYSBmcm9tICdhd3MtbGFtYmRhJztcbmltcG9ydCB7IGJhc2VVcmxGcm9tRG9tYWluLCBHaXRIdWJTZWNyZXRzIH0gZnJvbSAnLi9sYW1iZGEtZ2l0aHViJztcbmltcG9ydCB7IGdldFNlY3JldEpzb25WYWx1ZSwgZ2V0U2VjcmV0VmFsdWUgfSBmcm9tICcuL2xhbWJkYS1oZWxwZXJzJztcblxuY29uc3QgY2ZuID0gbmV3IENsb3VkRm9ybWF0aW9uQ2xpZW50KCk7XG5jb25zdCBlYzIgPSBuZXcgRUMyQ2xpZW50KCk7XG5jb25zdCBlY3IgPSBuZXcgRUNSQ2xpZW50KCk7XG5jb25zdCBzZiA9IG5ldyBTRk5DbGllbnQoKTtcblxuZnVuY3Rpb24gc2VjcmV0QXJuVG9VcmwoYXJuOiBzdHJpbmcpIHtcbiAgY29uc3QgcGFydHMgPSBhcm4uc3BsaXQoJzonKTsgLy8gYXJuOmF3czpzZWNyZXRzbWFuYWdlcjp1cy1lYXN0LTE6MTIzNDU2Nzg6c2VjcmV0OnNlY3JldC1uYW1lLVJFVklTSU9OXG4gIGNvbnN0IHJlZ2lvbiA9IHBhcnRzWzNdO1xuICBjb25zdCBmdWxsTmFtZSA9IHBhcnRzWzZdO1xuICBjb25zdCBuYW1lID0gZnVsbE5hbWUuc2xpY2UoMCwgZnVsbE5hbWUubGFzdEluZGV4T2YoJy0nKSk7XG5cbiAgcmV0dXJuIGBodHRwczovLyR7cmVnaW9ufS5jb25zb2xlLmF3cy5hbWF6b24uY29tL3NlY3JldHNtYW5hZ2VyL2hvbWU/cmVnaW9uPSR7cmVnaW9ufSMhL3NlY3JldD9uYW1lPSR7bmFtZX1gO1xufVxuXG5mdW5jdGlvbiBsYW1iZGFBcm5Ub1VybChhcm46IHN0cmluZykge1xuICBjb25zdCBwYXJ0cyA9IGFybi5zcGxpdCgnOicpOyAvLyBhcm46YXdzOmxhbWJkYTp1cy1lYXN0LTE6MTIzNDU2Nzg6ZnVuY3Rpb246bmFtZS1YWVpcbiAgY29uc3QgcmVnaW9uID0gcGFydHNbM107XG4gIGNvbnN0IG5hbWUgPSBwYXJ0c1s2XTtcblxuICByZXR1cm4gYGh0dHBzOi8vJHtyZWdpb259LmNvbnNvbGUuYXdzLmFtYXpvbi5jb20vbGFtYmRhL2hvbWU/cmVnaW9uPSR7cmVnaW9ufSMvZnVuY3Rpb25zLyR7bmFtZX0/dGFiPW1vbml0b3JpbmdgO1xufVxuXG5mdW5jdGlvbiBsYW1iZGFBcm5Ub0xvZ0dyb3VwKGFybjogc3RyaW5nKSB7XG4gIGNvbnN0IHBhcnRzID0gYXJuLnNwbGl0KCc6Jyk7IC8vIGFybjphd3M6bGFtYmRhOnVzLWVhc3QtMToxMjM0NTY3ODpmdW5jdGlvbjpuYW1lLVhZWlxuICBjb25zdCBuYW1lID0gcGFydHNbNl07XG5cbiAgcmV0dXJuIGAvYXdzL2xhbWJkYS8ke25hbWV9YDtcbn1cblxuZnVuY3Rpb24gc3RlcEZ1bmN0aW9uQXJuVG9VcmwoYXJuOiBzdHJpbmcpIHtcbiAgY29uc3QgcGFydHMgPSBhcm4uc3BsaXQoJzonKTsgLy8gYXJuOmF3czpzdGF0ZXM6dXMtZWFzdC0xOjEyMzQ1Njc4OnN0YXRlTWFjaGluZTpuYW1lLVhZWlxuICBjb25zdCByZWdpb24gPSBwYXJ0c1szXTtcblxuICByZXR1cm4gYGh0dHBzOi8vJHtyZWdpb259LmNvbnNvbGUuYXdzLmFtYXpvbi5jb20vc3RhdGVzL2hvbWU/cmVnaW9uPSR7cmVnaW9ufSMvc3RhdGVtYWNoaW5lcy92aWV3LyR7YXJufWA7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGdlbmVyYXRlUHJvdmlkZXJzU3RhdHVzKHN0YWNrOiBzdHJpbmcsIGxvZ2ljYWxJZDogc3RyaW5nKSB7XG4gIGNvbnN0IHJlc291cmNlID0gYXdhaXQgY2ZuLnNlbmQobmV3IERlc2NyaWJlU3RhY2tSZXNvdXJjZUNvbW1hbmQoeyBTdGFja05hbWU6IHN0YWNrLCBMb2dpY2FsUmVzb3VyY2VJZDogbG9naWNhbElkIH0pKTtcbiAgY29uc3QgcHJvdmlkZXJzID0gSlNPTi5wYXJzZShyZXNvdXJjZS5TdGFja1Jlc291cmNlRGV0YWlsPy5NZXRhZGF0YSA/PyAne30nKS5wcm92aWRlcnMgYXMgYW55W10gfCB1bmRlZmluZWQ7XG5cbiAgaWYgKCFwcm92aWRlcnMpIHtcbiAgICByZXR1cm4ge307XG4gIH1cblxuICByZXR1cm4gUHJvbWlzZS5hbGwocHJvdmlkZXJzLm1hcChhc3luYyAocCkgPT4ge1xuICAgIC8vIGFkZCBFQ1IgZGF0YSwgaWYgaW1hZ2UgaXMgZnJvbSBFQ1JcbiAgICBpZiAocC5pbWFnZT8uaW1hZ2VSZXBvc2l0b3J5Py5tYXRjaCgvWzAtOV0rXFwuZGtyXFwuZWNyXFwuW2EtejAtOVxcLV0rXFwuYW1hem9uYXdzXFwuY29tXFwvLisvKSkge1xuICAgICAgY29uc3QgdGFncyA9IGF3YWl0IGVjci5zZW5kKG5ldyBEZXNjcmliZUltYWdlc0NvbW1hbmQoe1xuICAgICAgICByZXBvc2l0b3J5TmFtZTogcC5pbWFnZS5pbWFnZVJlcG9zaXRvcnkuc3BsaXQoJy8nKVsxXSxcbiAgICAgICAgZmlsdGVyOiB7XG4gICAgICAgICAgdGFnU3RhdHVzOiAnVEFHR0VEJyxcbiAgICAgICAgfSxcbiAgICAgICAgbWF4UmVzdWx0czogMSxcbiAgICAgIH0pKTtcbiAgICAgIGlmICh0YWdzLmltYWdlRGV0YWlscyAmJiB0YWdzLmltYWdlRGV0YWlscz8ubGVuZ3RoID49IDEpIHtcbiAgICAgICAgcC5pbWFnZS5sYXRlc3RJbWFnZSA9IHtcbiAgICAgICAgICB0YWdzOiB0YWdzLmltYWdlRGV0YWlsc1swXS5pbWFnZVRhZ3MsXG4gICAgICAgICAgZGlnZXN0OiB0YWdzLmltYWdlRGV0YWlsc1swXS5pbWFnZURpZ2VzdCxcbiAgICAgICAgICBkYXRlOiB0YWdzLmltYWdlRGV0YWlsc1swXS5pbWFnZVB1c2hlZEF0LFxuICAgICAgICB9O1xuICAgICAgfVxuICAgIH1cbiAgICAvLyBhZGQgQU1JIGRhdGEsIGlmIGltYWdlIGlzIEFNSVxuICAgIGlmIChwLmFtaT8ubGF1bmNoVGVtcGxhdGUpIHtcbiAgICAgIGNvbnN0IHZlcnNpb25zID0gYXdhaXQgZWMyLnNlbmQobmV3IERlc2NyaWJlTGF1bmNoVGVtcGxhdGVWZXJzaW9uc0NvbW1hbmQoe1xuICAgICAgICBMYXVuY2hUZW1wbGF0ZUlkOiBwLmFtaS5sYXVuY2hUZW1wbGF0ZSxcbiAgICAgICAgVmVyc2lvbnM6IFsnJERlZmF1bHQnXSxcbiAgICAgIH0pKTtcbiAgICAgIGlmICh2ZXJzaW9ucy5MYXVuY2hUZW1wbGF0ZVZlcnNpb25zICYmIHZlcnNpb25zLkxhdW5jaFRlbXBsYXRlVmVyc2lvbnMubGVuZ3RoID49IDEpIHtcbiAgICAgICAgcC5hbWkubGF0ZXN0QW1pID0gdmVyc2lvbnMuTGF1bmNoVGVtcGxhdGVWZXJzaW9uc1swXS5MYXVuY2hUZW1wbGF0ZURhdGE/LkltYWdlSWQ7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBwO1xuICB9KSk7XG59XG5cbmludGVyZmFjZSBBcHBJbnN0YWxsYXRpb24ge1xuICByZWFkb25seSBpZDogbnVtYmVyO1xuICByZWFkb25seSB1cmw6IHN0cmluZztcbiAgcmVhZG9ubHkgc3RhdHVzOiBzdHJpbmc7XG4gIHJlYWRvbmx5IHJlcG9zaXRvcmllczogc3RyaW5nW107XG59XG5cbmludGVyZmFjZSBSZWNlbnRSdW4ge1xuICByZWFkb25seSBvd25lcj86IHN0cmluZztcbiAgcmVhZG9ubHkgcmVwbz86IHN0cmluZztcbiAgcmVhZG9ubHkgam9iSWQ/OiBzdHJpbmc7XG4gIHJlYWRvbmx5IGV4ZWN1dGlvbkFybj86IHN0cmluZztcbiAgcmVhZG9ubHkgc3RhdHVzOiBzdHJpbmc7XG59XG5cbmZ1bmN0aW9uIHNhZmVSZXR1cm5WYWx1ZShldmVudDogUGFydGlhbDxBV1NMYW1iZGEuQVBJR2F0ZXdheVByb3h5RXZlbnQ+LCBzdGF0dXM6IGFueSkge1xuICBpZiAoZXZlbnQucGF0aCkge1xuICAgIHJldHVybiB7XG4gICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICBoZWFkZXJzOiB7XG4gICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICB9LFxuICAgICAgYm9keTogSlNPTi5zdHJpbmdpZnkoc3RhdHVzKSxcbiAgICB9O1xuICB9XG5cbiAgcmV0dXJuIHN0YXR1cztcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGhhbmRsZXIoZXZlbnQ6IFBhcnRpYWw8QVdTTGFtYmRhLkFQSUdhdGV3YXlQcm94eUV2ZW50Pikge1xuICAvLyBjb25maXJtIHJlcXVpcmVkIGVudmlyb25tZW50IHZhcmlhYmxlc1xuICBpZiAoIXByb2Nlc3MuZW52LldFQkhPT0tfU0VDUkVUX0FSTiB8fCAhcHJvY2Vzcy5lbnYuR0lUSFVCX1NFQ1JFVF9BUk4gfHwgIXByb2Nlc3MuZW52LkdJVEhVQl9QUklWQVRFX0tFWV9TRUNSRVRfQVJOIHx8ICFwcm9jZXNzLmVudi5MT0dJQ0FMX0lEIHx8XG4gICAgICAhcHJvY2Vzcy5lbnYuV0VCSE9PS19IQU5ETEVSX0FSTiB8fCAhcHJvY2Vzcy5lbnYuU1RFUF9GVU5DVElPTl9BUk4gfHwgIXByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4gfHxcbiAgICAgICFwcm9jZXNzLmVudi5TVEFDS19OQU1FKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGVudmlyb25tZW50IHZhcmlhYmxlcycpO1xuICB9XG5cbiAgLy8gYmFzZSBzdGF0dXNcbiAgY29uc3Qgc3RhdHVzID0ge1xuICAgIGdpdGh1Yjoge1xuICAgICAgc2V0dXA6IHtcbiAgICAgICAgc3RhdHVzOiAnVW5rbm93bicsXG4gICAgICAgIHVybDogJycsXG4gICAgICAgIHNlY3JldEFybjogcHJvY2Vzcy5lbnYuU0VUVVBfU0VDUkVUX0FSTixcbiAgICAgICAgc2VjcmV0VXJsOiBzZWNyZXRBcm5Ub1VybChwcm9jZXNzLmVudi5TRVRVUF9TRUNSRVRfQVJOKSxcbiAgICAgIH0sXG4gICAgICBkb21haW46ICdVbmtub3duJyxcbiAgICAgIHJ1bm5lckxldmVsOiAnVW5rbm93bicsXG4gICAgICB3ZWJob29rOiB7XG4gICAgICAgIHVybDogcHJvY2Vzcy5lbnYuV0VCSE9PS19VUkwsXG4gICAgICAgIHN0YXR1czogJ1VuYWJsZSB0byBjaGVjaycsXG4gICAgICAgIHNlY3JldEFybjogcHJvY2Vzcy5lbnYuV0VCSE9PS19TRUNSRVRfQVJOLFxuICAgICAgICBzZWNyZXRVcmw6IHNlY3JldEFyblRvVXJsKHByb2Nlc3MuZW52LldFQkhPT0tfU0VDUkVUX0FSTiksXG4gICAgICB9LFxuICAgICAgYXV0aDoge1xuICAgICAgICB0eXBlOiAnVW5rbm93bicsXG4gICAgICAgIHN0YXR1czogJ1Vua25vd24nLFxuICAgICAgICBzZWNyZXRBcm46IHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOLFxuICAgICAgICBzZWNyZXRVcmw6IHNlY3JldEFyblRvVXJsKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOKSxcbiAgICAgICAgcHJpdmF0ZUtleVNlY3JldEFybjogcHJvY2Vzcy5lbnYuR0lUSFVCX1BSSVZBVEVfS0VZX1NFQ1JFVF9BUk4sXG4gICAgICAgIHByaXZhdGVLZXlTZWNyZXRVcmw6IHNlY3JldEFyblRvVXJsKHByb2Nlc3MuZW52LkdJVEhVQl9QUklWQVRFX0tFWV9TRUNSRVRfQVJOKSxcbiAgICAgICAgYXBwOiB7XG4gICAgICAgICAgaWQ6IC0xLFxuICAgICAgICAgIHVybDogJycsXG4gICAgICAgICAgaW5zdGFsbGF0aW9uczogW10gYXMgQXBwSW5zdGFsbGF0aW9uW10sXG4gICAgICAgIH0sXG4gICAgICAgIHBlcnNvbmFsQXV0aFRva2VuOiAnJyxcbiAgICAgIH0sXG4gICAgfSxcbiAgICBwcm92aWRlcnM6IGF3YWl0IGdlbmVyYXRlUHJvdmlkZXJzU3RhdHVzKHByb2Nlc3MuZW52LlNUQUNLX05BTUUsIHByb2Nlc3MuZW52LkxPR0lDQUxfSUQpLFxuICAgIHRyb3VibGVzaG9vdGluZzoge1xuICAgICAgd2ViaG9va0hhbmRsZXJBcm46IHByb2Nlc3MuZW52LldFQkhPT0tfSEFORExFUl9BUk4sXG4gICAgICB3ZWJob29rSGFuZGxlclVybDogbGFtYmRhQXJuVG9VcmwocHJvY2Vzcy5lbnYuV0VCSE9PS19IQU5ETEVSX0FSTiksXG4gICAgICB3ZWJob29rSGFuZGxlckxvZ0dyb3VwOiBsYW1iZGFBcm5Ub0xvZ0dyb3VwKHByb2Nlc3MuZW52LldFQkhPT0tfSEFORExFUl9BUk4pLFxuICAgICAgc3RlcEZ1bmN0aW9uQXJuOiBwcm9jZXNzLmVudi5TVEVQX0ZVTkNUSU9OX0FSTixcbiAgICAgIHN0ZXBGdW5jdGlvblVybDogc3RlcEZ1bmN0aW9uQXJuVG9VcmwocHJvY2Vzcy5lbnYuU1RFUF9GVU5DVElPTl9BUk4pLFxuICAgICAgc3RlcEZ1bmN0aW9uTG9nR3JvdXA6IHByb2Nlc3MuZW52LlNURVBfRlVOQ1RJT05fTE9HX0dST1VQLFxuICAgICAgcmVjZW50UnVuczogW10gYXMgUmVjZW50UnVuW10sXG4gICAgfSxcbiAgfTtcblxuICAvLyBzZXR1cCB1cmxcbiAgaWYgKHByb2Nlc3MuZW52LlNFVFVQX0ZVTkNUSU9OX1VSTCkge1xuICAgIGNvbnN0IHNldHVwVG9rZW4gPSAoYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LlNFVFVQX1NFQ1JFVF9BUk4pKS50b2tlbjtcbiAgICBpZiAoc2V0dXBUb2tlbikge1xuICAgICAgc3RhdHVzLmdpdGh1Yi5zZXR1cC5zdGF0dXMgPSAnUGVuZGluZyc7XG4gICAgICBzdGF0dXMuZ2l0aHViLnNldHVwLnVybCA9IGAke3Byb2Nlc3MuZW52LlNFVFVQX0ZVTkNUSU9OX1VSTH0/dG9rZW49JHtzZXR1cFRva2VufWA7XG4gICAgfSBlbHNlIHtcbiAgICAgIHN0YXR1cy5naXRodWIuc2V0dXAuc3RhdHVzID0gJ0NvbXBsZXRlJztcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgc3RhdHVzLmdpdGh1Yi5zZXR1cC5zdGF0dXMgPSAnRGlzYWJsZWQnO1xuICB9XG5cbiAgLy8gbGlzdCBsYXN0IDEwIGV4ZWN1dGlvbnMgYW5kIHRoZWlyIHN0YXR1c1xuICB0cnkge1xuICAgIGNvbnN0IGV4ZWN1dGlvbnMgPSBhd2FpdCBzZi5zZW5kKG5ldyBMaXN0RXhlY3V0aW9uc0NvbW1hbmQoe1xuICAgICAgc3RhdGVNYWNoaW5lQXJuOiBwcm9jZXNzLmVudi5TVEVQX0ZVTkNUSU9OX0FSTixcbiAgICAgIG1heFJlc3VsdHM6IDEwLFxuICAgIH0pKTtcbiAgICBmb3IgKGNvbnN0IGV4ZWN1dGlvbiBvZiBleGVjdXRpb25zLmV4ZWN1dGlvbnMgPz8gW10pIHtcbiAgICAgIGNvbnN0IGV4ZWN1dGlvbkRldGFpbHMgPSBhd2FpdCBzZi5zZW5kKG5ldyBEZXNjcmliZUV4ZWN1dGlvbkNvbW1hbmQoe1xuICAgICAgICBleGVjdXRpb25Bcm46IGV4ZWN1dGlvbi5leGVjdXRpb25Bcm4sXG4gICAgICB9KSk7XG4gICAgICBjb25zdCBpbnB1dCA9IEpTT04ucGFyc2UoZXhlY3V0aW9uRGV0YWlscy5pbnB1dCB8fCAne30nKTtcblxuICAgICAgc3RhdHVzLnRyb3VibGVzaG9vdGluZy5yZWNlbnRSdW5zLnB1c2goe1xuICAgICAgICBleGVjdXRpb25Bcm46IGV4ZWN1dGlvbi5leGVjdXRpb25Bcm4sXG4gICAgICAgIHN0YXR1czogZXhlY3V0aW9uLnN0YXR1cyA/PyAnPHVua25vd24+JyxcbiAgICAgICAgb3duZXI6IGlucHV0Lm93bmVyLFxuICAgICAgICByZXBvOiBpbnB1dC5yZXBvLFxuICAgICAgICBqb2JJZDogaW5wdXQuam9iSWQsXG4gICAgICB9KTtcbiAgICB9XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBzdGF0dXMudHJvdWJsZXNob290aW5nLnJlY2VudFJ1bnMucHVzaCh7IHN0YXR1czogYEVycm9yIGdldHRpbmcgZXhlY3V0aW9uczogJHtlfWAgfSk7XG4gIH1cblxuICAvLyBnZXQgc2VjcmV0c1xuICBsZXQgZ2l0aHViU2VjcmV0czogR2l0SHViU2VjcmV0cztcbiAgdHJ5IHtcbiAgICBnaXRodWJTZWNyZXRzID0gYXdhaXQgZ2V0U2VjcmV0SnNvblZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9TRUNSRVRfQVJOKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIHJlYWQgc2VjcmV0OiAke2V9YDtcbiAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICB9XG5cbiAgbGV0IHByaXZhdGVLZXk7XG4gIHRyeSB7XG4gICAgcHJpdmF0ZUtleSA9IGF3YWl0IGdldFNlY3JldFZhbHVlKHByb2Nlc3MuZW52LkdJVEhVQl9QUklWQVRFX0tFWV9TRUNSRVRfQVJOKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIHJlYWQgcHJpdmF0ZSBrZXkgc2VjcmV0OiAke2V9YDtcbiAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICB9XG5cbiAgLy8gY2FsY3VsYXRlIGJhc2UgdXJsXG4gIGxldCBiYXNlVXJsID0gYmFzZVVybEZyb21Eb21haW4oZ2l0aHViU2VjcmV0cy5kb21haW4pO1xuICBzdGF0dXMuZ2l0aHViLmRvbWFpbiA9IGdpdGh1YlNlY3JldHMuZG9tYWluO1xuXG4gIC8vIGNvcHkgcnVubmVyIGxldmVsXG4gIHN0YXR1cy5naXRodWIucnVubmVyTGV2ZWwgPSBnaXRodWJTZWNyZXRzLnJ1bm5lckxldmVsID8/ICdyZXBvJztcblxuICBpZiAoZ2l0aHViU2VjcmV0cy5wZXJzb25hbEF1dGhUb2tlbikge1xuICAgIC8vIHRyeSBhdXRoZW50aWNhdGluZyB3aXRoIHBlcnNvbmFsIGFjY2VzcyB0b2tlblxuICAgIHN0YXR1cy5naXRodWIuYXV0aC50eXBlID0gJ1BlcnNvbmFsIEFjY2VzcyBUb2tlbic7XG4gICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnBlcnNvbmFsQXV0aFRva2VuID0gJypyZWRhY3RlZConO1xuXG4gICAgbGV0IG9jdG9raXQ7XG4gICAgdHJ5IHtcbiAgICAgIG9jdG9raXQgPSBuZXcgT2N0b2tpdCh7IGJhc2VVcmwsIGF1dGg6IGdpdGh1YlNlY3JldHMucGVyc29uYWxBdXRoVG9rZW4gfSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIHVzaW5nIHBlcnNvbmFsIGF1dGggdG9rZW46ICR7ZX1gO1xuICAgICAgcmV0dXJuIHNhZmVSZXR1cm5WYWx1ZShldmVudCwgc3RhdHVzKTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgY29uc3QgdXNlciA9IGF3YWl0IG9jdG9raXQucmVxdWVzdCgnR0VUIC91c2VyJyk7XG4gICAgICBzdGF0dXMuZ2l0aHViLmF1dGgucGVyc29uYWxBdXRoVG9rZW4gPSBgdXNlcm5hbWU6ICR7dXNlci5kYXRhLmxvZ2lufWA7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9IGBVbmFibGUgdG8gY2FsbCAvdXNlciB3aXRoIHBlcnNvbmFsIGF1dGggdG9rZW46ICR7ZX1gO1xuICAgICAgcmV0dXJuIHNhZmVSZXR1cm5WYWx1ZShldmVudCwgc3RhdHVzKTtcbiAgICB9XG5cbiAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gJ09LJztcbiAgICBzdGF0dXMuZ2l0aHViLndlYmhvb2suc3RhdHVzID0gJ1VuYWJsZSB0byB2ZXJpZnkgYXV0b21hdGljYWxseSc7XG4gIH0gZWxzZSB7XG4gICAgLy8gdHJ5IGF1dGhlbnRpY2F0aW5nIHdpdGggR2l0SHViIGFwcFxuICAgIHN0YXR1cy5naXRodWIuYXV0aC50eXBlID0gJ0dpdEh1YiBBcHAnO1xuICAgIHN0YXR1cy5naXRodWIuYXV0aC5hcHAuaWQgPSBnaXRodWJTZWNyZXRzLmFwcElkO1xuXG4gICAgbGV0IGFwcE9jdG9raXQ7XG4gICAgdHJ5IHtcbiAgICAgIGFwcE9jdG9raXQgPSBuZXcgT2N0b2tpdCh7XG4gICAgICAgIGJhc2VVcmwsXG4gICAgICAgIGF1dGhTdHJhdGVneTogY3JlYXRlQXBwQXV0aCxcbiAgICAgICAgYXV0aDoge1xuICAgICAgICAgIGFwcElkOiBnaXRodWJTZWNyZXRzLmFwcElkLFxuICAgICAgICAgIHByaXZhdGVLZXk6IHByaXZhdGVLZXksXG4gICAgICAgIH0sXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gYFVuYWJsZSB0byBhdXRoZW50aWNhdGUgYXBwOiAke2V9YDtcbiAgICAgIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG4gICAgfVxuXG4gICAgLy8gZ2V0IGFwcCB1cmxcbiAgICB0cnkge1xuICAgICAgY29uc3QgYXBwID0gKGF3YWl0IGFwcE9jdG9raXQucmVxdWVzdCgnR0VUIC9hcHAnKSkuZGF0YTtcbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5hcHAudXJsID0gYXBwLmh0bWxfdXJsO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHN0YXR1cy5naXRodWIuYXV0aC5zdGF0dXMgPSBgVW5hYmxlIHRvIGdldCBhcHAgZGV0YWlsczogJHtlfWA7XG4gICAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICAgIH1cblxuICAgIC8vIGxpc3QgYWxsIGFwcCBpbnN0YWxsYXRpb25zXG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IGluc3RhbGxhdGlvbnMgPSAoYXdhaXQgYXBwT2N0b2tpdC5yZXF1ZXN0KCdHRVQgL2FwcC9pbnN0YWxsYXRpb25zJykpLmRhdGE7XG4gICAgICBmb3IgKGNvbnN0IGluc3RhbGxhdGlvbiBvZiBpbnN0YWxsYXRpb25zKSB7XG4gICAgICAgIGxldCBpbnN0YWxsYXRpb25EZXRhaWxzID0ge1xuICAgICAgICAgIGlkOiBpbnN0YWxsYXRpb24uaWQsXG4gICAgICAgICAgdXJsOiBpbnN0YWxsYXRpb24uaHRtbF91cmwsXG4gICAgICAgICAgc3RhdHVzOiAnVW5hYmxlIHRvIHF1ZXJ5JyxcbiAgICAgICAgICByZXBvc2l0b3JpZXM6IFtdIGFzIHN0cmluZ1tdLFxuICAgICAgICB9O1xuXG4gICAgICAgIGxldCB0b2tlbjtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB0b2tlbiA9IChhd2FpdCBhcHBPY3Rva2l0LmF1dGgoe1xuICAgICAgICAgICAgdHlwZTogJ2luc3RhbGxhdGlvbicsXG4gICAgICAgICAgICBpbnN0YWxsYXRpb25JZDogaW5zdGFsbGF0aW9uLmlkLFxuICAgICAgICAgIH0pIGFzIGFueSkudG9rZW47XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIGFwcCBpbnN0YWxsYXRpb246ICR7ZX1gO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IG9jdG9raXQ7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgb2N0b2tpdCA9IG5ldyBPY3Rva2l0KHsgYmFzZVVybCwgYXV0aDogdG9rZW4gfSk7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnN0YXR1cyA9IGBVbmFibGUgdG8gYXV0aGVudGljYXRlIHVzaW5nIGFwcDogJHtlfWA7XG4gICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB0cnkge1xuICAgICAgICAgIGNvbnN0IHJlcG9zaXRvcmllcyA9IChhd2FpdCBvY3Rva2l0LnJlcXVlc3QoJ0dFVCAvaW5zdGFsbGF0aW9uL3JlcG9zaXRvcmllcycpKS5kYXRhLnJlcG9zaXRvcmllcztcbiAgICAgICAgICBmb3IgKGNvbnN0IHJlcG8gb2YgcmVwb3NpdG9yaWVzKSB7XG4gICAgICAgICAgICBpbnN0YWxsYXRpb25EZXRhaWxzLnJlcG9zaXRvcmllcy5wdXNoKHJlcG8uZnVsbF9uYW1lIGFzIHN0cmluZyk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgaW5zdGFsbGF0aW9uRGV0YWlscy5zdGF0dXMgPSBgVW5hYmxlIHRvIGF1dGhlbnRpY2F0ZSB1c2luZyBpbnN0YWxsYXRpb24gdG9rZW46ICR7ZX1gO1xuICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaW5zdGFsbGF0aW9uRGV0YWlscy5zdGF0dXMgPSAnT0snO1xuICAgICAgICBzdGF0dXMuZ2l0aHViLmF1dGguYXBwLmluc3RhbGxhdGlvbnMucHVzaChpbnN0YWxsYXRpb25EZXRhaWxzKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLmF1dGguc3RhdHVzID0gJ1VuYWJsZSB0byBsaXN0IGFwcCBpbnN0YWxsYXRpb25zJztcbiAgICAgIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG4gICAgfVxuXG4gICAgc3RhdHVzLmdpdGh1Yi5hdXRoLnN0YXR1cyA9ICdPSyc7XG5cbiAgICAvLyBjaGVjayB3ZWJob29rIGNvbmZpZ1xuICAgIHRyeSB7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGFwcE9jdG9raXQucmVxdWVzdCgnR0VUIC9hcHAvaG9vay9jb25maWcnLCB7fSk7XG5cbiAgICAgIGlmIChyZXNwb25zZS5kYXRhLnVybCAhPT0gcHJvY2Vzcy5lbnYuV0VCSE9PS19VUkwpIHtcbiAgICAgICAgc3RhdHVzLmdpdGh1Yi53ZWJob29rLnN0YXR1cyA9ICdHaXRIdWIgaGFzIHdyb25nIHdlYmhvb2sgVVJMIGNvbmZpZ3VyZWQnO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVE9ETyBjaGVjayBzZWNyZXQgYnkgZG9pbmcgYSBkdW1teSBkZWxpdmVyeT8gZm9yY2UgYXBwbHkgc2VjcmV0P1xuICAgICAgICBzdGF0dXMuZ2l0aHViLndlYmhvb2suc3RhdHVzID0gJ09LIChub3RlIHRoYXQgc2VjcmV0IGNhbm5vdCBiZSBjaGVja2VkIGF1dG9tYXRpY2FsbHkpJztcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBzdGF0dXMuZ2l0aHViLndlYmhvb2suc3RhdHVzID0gYFVuYWJsZSB0byBjaGVjayBhcHAgY29uZmlndXJhdGlvbjogJHtlfWA7XG4gICAgICByZXR1cm4gc2FmZVJldHVyblZhbHVlKGV2ZW50LCBzdGF0dXMpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBzYWZlUmV0dXJuVmFsdWUoZXZlbnQsIHN0YXR1cyk7XG59XG4iXX0=