aws-delivlib
Version:
A fabulous library for defining continuous pipelines for building, testing and releasing code libraries.
227 lines • 40.9 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AutoPullRequest = void 0;
const aws_cdk_lib_1 = require("aws-cdk-lib");
const constructs_1 = require("constructs");
const build_env_1 = require("../build-env");
const permissions = __importStar(require("../permissions"));
/**
* Creates a CodeBuild job that, when triggered, opens a GitHub Pull Request.
*/
class AutoPullRequest extends constructs_1.Construct {
constructor(parent, id, props) {
super(parent, id);
this.props = props;
this.baseBranch = props.base?.name ?? 'master';
this.headSource = props.head.source ?? this.baseBranch;
this.exports = props.exports ?? {};
for (const ex of Object.keys(this.exports)) {
if (this.headSource.includes(`\${${ex}}`) || this.headSource.includes(`\$${ex}`)) {
throw new Error(`head source (${this.headSource}) cannot contain dynamic exports: ${ex}`);
}
}
const sshKeySecret = props.repo.sshKeySecret;
const commitEmail = props.repo.commitEmail;
const commitUsername = props.repo.commitUsername;
const cloneDepth = props.cloneDepth === undefined ? 0 : props.cloneDepth;
const needsGitHubTokenSecret = !this.props.pushOnly || !!this.props.skipIfOpenPrsWithLabels;
let commands = [
...this.configureSshAccess(),
// when the job is triggered as a CodePipeline action, the working directory
// is populated with the output artifact of the CodeCommitSourceAction, which doesn't include
// the .git directory in the zipped s3 archive. (Yeah, fun stuff).
// see https://itnext.io/how-to-access-git-metadata-in-codebuild-when-using-codepipeline-codecommit-ceacf2c5c1dc
...this.cloneIfNeeded(),
];
if (this.props.condition) {
// there's no way to stop a BuildSpec execution halfway through without throwing an error. Believe me, I
// checked the code. Instead we define a variable that we will switch all other lines on/off.
commands.push(`${this.props.condition} ` +
'&& { echo \'Skip condition is met, skipping...\' && export SKIP=true; } ' +
'|| { echo \'Skip condition is not met, continuing...\' && export SKIP=false; }');
}
// read the token
if (needsGitHubTokenSecret) {
commands.push(`export GITHUB_TOKEN=$(aws secretsmanager get-secret-value --secret-id "${this.props.repo.tokenSecretArn}" --output=text --query=SecretString)`);
}
if (this.props.skipIfOpenPrsWithLabels) {
commands.push(...this.skipIfOpenPrs(this.props.skipIfOpenPrsWithLabels));
}
commands.push(...this.createHead(), ...this.pushHead());
if (!this.props.pushOnly) {
commands.push(...this.createPullRequest());
}
// toggle all commands according to the SKIP variable.
commands = commands.map((command) => `$SKIP || { ${command} ; }`);
// intially all commands are enabled.
commands.unshift('export SKIP=false');
this.project = new aws_cdk_lib_1.aws_codebuild.Project(this, 'PullRequest', {
source: props.repo.createBuildSource(this, false, { cloneDepth }),
description: props.projectDescription,
environment: (0, build_env_1.createBuildEnvironment)(props.build ?? {}),
buildSpec: aws_cdk_lib_1.aws_codebuild.BuildSpec.fromObject({
version: '0.2',
phases: {
pre_build: {
commands: [
`git config --global user.email "${commitEmail}"`,
`git config --global user.name "${commitUsername}"`,
],
},
build: { commands },
},
}),
ssmSessionPermissions: true,
});
// Always exists as the project is not a reference
const projectRole = this.project.role;
projectRole.addManagedPolicy(aws_cdk_lib_1.aws_iam.ManagedPolicy.fromAwsManagedPolicyName('AmazonElasticContainerRegistryPublicReadOnly'));
permissions.grantSecretRead(sshKeySecret, projectRole);
if (needsGitHubTokenSecret) {
permissions.grantSecretRead({ secretArn: props.repo.tokenSecretArn }, projectRole);
}
if (props.scheduleExpression) {
const schedule = aws_cdk_lib_1.aws_events.Schedule.expression(props.scheduleExpression);
new aws_cdk_lib_1.aws_events.Rule(this, 'Scheduler', {
description: 'Schedules an automatic Pull Request for this repository',
schedule,
targets: [new aws_cdk_lib_1.aws_events_targets.CodeBuildProject(this.project)],
});
}
this.alarm = this.project.metricFailedBuilds({ period: aws_cdk_lib_1.Duration.seconds(300) }).createAlarm(this, 'AutoPullRequestFailedAlarm', {
threshold: 1,
evaluationPeriods: 1,
treatMissingData: aws_cdk_lib_1.aws_cloudwatch.TreatMissingData.IGNORE,
});
}
createHead() {
return [
// check if head branch exists
`git rev-parse --verify origin/${this.props.head.name} ` +
// checkout and merge if it does (this might fail due to merge conflicts)
`&& { git checkout ${this.props.head.name} && git merge ${this.headSource} && ${this.runCommands()}; } ` +
// create if it doesnt. we initially use 'temp' to allow using exports in the head branch name. (e.g bump/$VERSION)
`|| { git checkout ${this.headSource} && git checkout -b temp && ${this.runCommands()} && git branch -M ${this.props.head.name}; }`,
];
}
cloneIfNeeded() {
return [
// check if .git exist
'ls .git ' +
// all good
'&& { echo ".git directory exists"; } ' +
// clone if it doesn't
`|| { echo ".git directory doesnot exist - cloning..." && git init . && git remote add origin git@github.com:${this.props.repo.owner}/${this.props.repo.repo}.git && git fetch && git reset --hard origin/${this.baseBranch} && git branch -M ${this.baseBranch} && git clean -fqdx; }`,
];
}
runCommands() {
const userCommands = this.props.commands ?? [];
const exports = Object.entries(this.exports).map(entry => `export ${entry[0]}=$(${entry[1]})`);
return [
...userCommands,
// exports should be executed immediately after the user commands (not before)
// because they might need access to artifacts produced by them (e.g version file).
...exports,
'echo Finished running user commands',
].join(' && ');
}
configureSshAccess() {
return [
'aws secretsmanager get-secret-value '
+ `--secret-id "${this.props.repo.sshKeySecret.secretArn}" `
+ '--output=text --query=SecretString > ~/.ssh/id_rsa',
'mkdir -p ~/.ssh',
'chmod 0600 ~/.ssh/id_rsa ~/.ssh/config',
'ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts',
];
}
pushHead() {
// We will do nothing and set `SKIP=true` if the head ref is an ancestor of the base branch (no PR could be created)
return [
`git merge-base --is-ancestor ${this.props.head.name} origin/${this.baseBranch}`
+ ` && { echo "Skipping: ${this.props.head.name} is an ancestor of origin/${this.baseBranch}"; export SKIP=true; }`
+ ` || { echo "Pushing: ${this.props.head.name} is ahead of origin/${this.baseBranch}"; export SKIP=false; }`,
`git remote add origin_ssh ${this.props.repo.repositoryUrlSsh}`,
// Need `--atomic`, otherwise `git push` might successfully push the tags but not to `main`.
`git push --atomic --follow-tags origin_ssh ${this.props.head.name}:${this.props.head.name}`,
];
}
skipIfOpenPrs(labels) {
const filters = [
`repo:${this.props.repo.owner}/${this.props.repo.repo}`,
'is:pr',
'is:open',
...labels.map(l => `label:${l}`),
];
return [
`${this.githubCurlGet(`/search/issues?q=${encodeURIComponent(filters.join(' '))}`, '-o search.json')}`,
'node -e \'process.exitCode = require("./search.json").total_count\''
+ ` || { echo "Found open PRs with label ${labels}, skipping PR."; export SKIP=true; }`,
];
}
createPullRequest() {
const head = this.props.head.name;
const base = this.baseBranch;
if (head === base) {
throw new Error(`Head branch ("${base}") is the same as the base branch ("${head}")`);
}
const props = this.props;
const title = props.title ?? `Merge ${head} to ${base}`;
const body = this.props.body ?? '';
const createRequest = { title, base, head };
const commands = [];
// create the PR
commands.push(`${this.githubCurl('/pulls', '-X POST -o pr.json', createRequest)} && export PR_NUMBER=$(node -p 'require("./pr.json").number')`);
// update the body
commands.push(this.githubCurl('/pulls/$PR_NUMBER', '-X PATCH', { body: body }));
if (this.props.labels && this.props.labels.length > 0) {
// apply labels.
commands.push(this.githubCurl('/issues/$PR_NUMBER/labels', '-X POST', { labels: this.props.labels }));
}
return commands;
}
githubCurl(uri, command, request) {
return [
'curl --fail',
command,
'--header "Authorization: token $GITHUB_TOKEN"',
'--header "Content-Type: application/json"',
`-d ${JSON.stringify(JSON.stringify(request))}`,
`https://api.github.com/repos/${this.props.repo.owner}/${this.props.repo.repo}${uri}`,
].join(' ');
}
githubCurlGet(uri, command) {
return [
'curl --fail',
command,
'--header "Authorization: token $GITHUB_TOKEN"',
'--header "Content-Type: application/json"',
`'https://api.github.com${uri}'`,
].join(' ');
}
}
exports.AutoPullRequest = AutoPullRequest;
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJwci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBLDZDQU9xQjtBQUNyQiwyQ0FBdUM7QUFDdkMsNENBQTZFO0FBQzdFLDREQUE4QztBQTJMOUM7O0dBRUc7QUFDSCxNQUFhLGVBQWdCLFNBQVEsc0JBQVM7SUFrQjVDLFlBQVksTUFBaUIsRUFBRSxFQUFVLEVBQUUsS0FBMkI7UUFDcEUsS0FBSyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUMsQ0FBQztRQUVsQixJQUFJLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztRQUVuQixJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsSUFBSSxJQUFJLFFBQVEsQ0FBQztRQUMvQyxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUM7UUFDdkQsSUFBSSxDQUFDLE9BQU8sR0FBRyxLQUFLLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUVuQyxLQUFLLE1BQU0sRUFBRSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFO1lBQzFDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsRUFBRTtnQkFDaEYsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsSUFBSSxDQUFDLFVBQVUscUNBQXFDLEVBQUUsRUFBRSxDQUFDLENBQUM7YUFDM0Y7U0FDRjtRQUVELE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBQzdDLE1BQU0sV0FBVyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDO1FB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Q0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLDJCQUEyQixFQUFFLFNBQVMsRUFBRSxFQUFFLE1BQU0sRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsQ0FBQztTQUN2RztRQUVELE9BQU8sUUFBUSxDQUFDO0lBRWxCLENBQUM7SUFFTyxVQUFVLENBQUMsR0FBVyxFQUFFLE9BQWUsRUFBRSxPQUFZO1FBQzNELE9BQU87WUFDTCxhQUFhO1lBQ2IsT0FBTztZQUNQLCtDQUErQztZQUMvQywyQ0FBMkM7WUFDM0MsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLENBQUMsRUFBRTtZQUMvQyxnQ0FBZ0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLElBQUksR0FBRyxHQUFHLEVBQUU7U0FDdEYsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDZCxDQUFDO0lBRU8sYUFBYSxDQUFDLEdBQVcsRUFBRSxPQUFlO1FBQ2hELE9BQU87WUFDTCxhQUFhO1lBQ2IsT0FBTztZQUNQLCtDQUErQztZQUMvQywyQ0FBMkM7WUFDM0MsMEJBQTBCLEdBQUcsR0FBRztTQUNqQyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNkLENBQUM7Q0FFRjtBQTdRRCwwQ0E2UUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBEdXJhdGlvbixcbiAgYXdzX2Nsb3Vkd2F0Y2ggYXMgY2xvdWR3YXRjaCxcbiAgYXdzX2NvZGVidWlsZCBhcyBjYnVpbGQsXG4gIGF3c19ldmVudHMgYXMgZXZlbnRzLFxuICBhd3NfZXZlbnRzX3RhcmdldHMgYXMgZXZlbnRzX3RhcmdldHMsXG4gIGF3c19pYW0gYXMgaWFtLFxufSBmcm9tICdhd3MtY2RrLWxpYic7XG5pbXBvcnQgeyBDb25zdHJ1Y3QgfSBmcm9tICdjb25zdHJ1Y3RzJztcbmltcG9ydCB7IEJ1aWxkRW52aXJvbm1lbnRQcm9wcywgY3JlYXRlQnVpbGRFbnZpcm9ubWVudCB9IGZyb20gJy4uL2J1aWxkLWVudic7XG5pbXBvcnQgKiBhcyBwZXJtaXNzaW9ucyBmcm9tICcuLi9wZXJtaXNzaW9ucyc7XG5pbXBvcnQgeyBXcml0YWJsZUdpdEh1YlJlcG8gfSBmcm9tICcuLi9yZXBvJztcblxuLyoqXG4gKiBQcm9wZXJ0aWVzIGZvciBjcmVhdGluZyBhIFB1bGwgUmVxdWVzdCBKb2IuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXV0b1B1bGxSZXF1ZXN0T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgYmFzZSBicmFuY2ggb2YgdGhlIFBSLlxuICAgKlxuICAgKiBAZGVmYXVsdCAnbWFzdGVyJ1xuICAgKi9cbiAgYmFzZT86IEJhc2U7XG5cbiAgLyoqXG4gICAqIFRydWUgaWYgeW91IG9ubHkgd2FudCB0byBwdXNoIHRoZSBoZWFkIGJyYW5jaCB3aXRob3V0IGNyZWF0aW5nIGEgUFIuXG4gICAqIFVzZWZ1bCB3aGVuIHVzZWQgYWxvbmcgd2l0aCAnY29tbWl0cycgdG8gZXhlY3V0ZSBhIGNvbW1pdC1hbmQtcHVzaCBhdXRvbWF0aWNhbGx5LlxuICAgKlxuICAgKiAvLyBUT0RPOiBDb25zaWRlciBtb3ZpbmcgdGhpcyBmdW5jdGlvbmFsaXR5IHRvIGEgc2VwYXJhdGUgY29uc3RydWN0LlxuICAgKlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgcmVhZG9ubHkgcHVzaE9ubHk/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBUaXRsZSBvZiB0aGUgUFIuXG4gICAqXG4gICAqIEBkZWZhdWx0IGBNZXJnZSAke2hlYWR9IHRvICR7YmFzZX1gXG4gICAqL1xuICB0aXRsZT86IHN0cmluZztcblxuICAvKipcbiAgICogQm9keSB0aGUgUFIuIE5vdGUgdGhhdCB0aGUgYm9keSBpcyB1cGRhdGVkIHBvc3QgUFIgY3JlYXRpb24sXG4gICAqIHRoaXMgbWVhbnMgeW91IGNhbiB1c2UgdGhlICRQUl9OVU1CRVIgZW52IHZhcmlhYmxlIHRvIHJlZmVyIHRvIHRoZSBQUiBpdHNlbGYuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gYm9keS5cbiAgICovXG4gIGJvZHk/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIExhYmVscyBhcHBsaWVkIHRvIHRoZSBQUi5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBsYWJlbHMuXG4gICAqL1xuICBsYWJlbHM/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogQnVpbGQgZW52aXJvbm1lbnQgZm9yIHRoZSBDb2RlQnVpbGQgam9iLlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIGRlZmF1bHQgY29uZmlndXJhdGlvbi5cbiAgICovXG4gIGJ1aWxkPzogQnVpbGRFbnZpcm9ubWVudFByb3BzO1xuXG4gIC8qKlxuICAgKiBHaXQgY2xvbmUgZGVwdGguXG4gICAqXG4gICAqIEBkZWZhdWx0IDAgKGNsb25lcyB0aGUgZW50aXJlIHJlcG9zaXRvcnkgcmV2aXNpb25zKVxuICAgKi9cbiAgY2xvbmVEZXB0aD86IG51bWJlcjtcblxuICAvKipcbiAgICogS2V5IHZhbHVlIHBhaXJzIG9mIHZhcmlhYmxlcyB0byBleHBvcnQuIFRoZXNlIHZhcmlhYmxlcyB3aWxsIGJlIGF2YWlsYWJsZSBmb3IgZHluYW1pYyBldmFsdWF0aW9uIGluIGFueVxuICAgKiBzdWJzZXF1ZW50IGNvbW1hbmQuXG4gICAqXG4gICAqIEtleSAtIFZhcmlhYmxlIG5hbWUgKGUuZyBWRVJTSU9OKVxuICAgKiBWYWx1ZSAtIENvbW1hbmQgdGhhdCBldmFsdWF0ZXMgdG8gdGhlIHZhbHVlIG9mIHRoZSB2YXJpYWJsZSAoZS5nICdnaXQgZGVzY3JpYmUnKVxuICAgKlxuICAgKiBFeGFtcGxlOlxuICAgKlxuICAgKiBDb25maWd1cmUgYW4gZXhwb3J0IGluIHRoZSBmb3JtIG9mOlxuICAgKlxuICAgKiB7ICdWRVJTSU9OJzogJ2dpdCBkZXNjcmliZScgfVxuICAgKlxuICAgKiBVc2UgdGhlICRWRVJTSU9OIHZhcmlhYmxlIGluIHRoZSBQUiB0aXRsZTogJ2Nob3JlKHJlbGVhc2UpOiAkVkVSU0lPTidcbiAgICpcbiAgICogTm90ZSB0aGF0IHRoZXNlIGV4cG9ydHMgYXJlIGV4ZWN1dGVkIGFmdGVyIHRoZSBgY29tbWFuZHNgIGV4ZWN1dGlvbixcbiAgICogc28gdGhleSBoYXZlIGFjY2VzcyB0byB0aGUgYXJ0aWZhY3RzIHNhaWQgY29tbWFuZHMgcHJvZHVjZSAoZS5nIHZlcnNpb24gYnVtcCkuXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gZXhwb3J0c1xuICAgKi9cbiAgZXhwb3J0cz86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgLyoqXG4gICAqIFRoZSBzY2hlZHVsZSB0byBwcm9kdWNlIGFuIGF1dG9tYXRpYyBQUi5cbiAgICpcbiAgICogVGhlIGV4cHJlc3Npb24gY2FuIGJlIG9uZSBvZjpcbiAgICpcbiAgICogIC0gY3JvbiBleHByZXNzaW9uLCBzdWNoIGFzIFwiY3JvbigwIDEyICogKiA/ICopXCIgd2lsbCB0cmlnZ2VyIGV2ZXJ5IGRheSBhdCAxMnBtIFVUQ1xuICAgKiAgLSByYXRlIGV4cHJlc3Npb24sIHN1Y2ggYXMgXCJyYXRlKDEgZGF5KVwiIHdpbGwgdHJpZ2dlciBldmVyeSAyNCBob3VycyBmcm9tIHRoZSB0aW1lIG9mIGRlcGxveW1lbnRcbiAgICpcbiAgICogQHNlZSBodHRwczovL2RvY3MuYXdzLmFtYXpvbi5jb20vQW1hem9uQ2xvdWRXYXRjaC9sYXRlc3QvZXZlbnRzL1NjaGVkdWxlZEV2ZW50cy5odG1sXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gc2NoZWR1bGUsIHNob3VsZCBiZSB0cmlnZ2VyZWQgbWFudWFsbHkuXG4gICAqL1xuICBzY2hlZHVsZUV4cHJlc3Npb24/OiBzdHJpbmc7XG5cbn1cblxuZXhwb3J0IGludGVyZmFjZSBBdXRvUHVsbFJlcXVlc3RQcm9wcyBleHRlbmRzIEF1dG9QdWxsUmVxdWVzdE9wdGlvbnMge1xuICAvKipcbiAgICogVGhlIHJlcG9zaXRvcnkgdG8gY3JlYXRlIGEgUFIgaW4uXG4gICAqL1xuICByZXBvOiBXcml0YWJsZUdpdEh1YlJlcG87XG5cbiAgLyoqXG4gICAqIEEgc2V0IG9mIGNvbW1hbmRzIHRvIHJ1biBhZ2FpbnN0IHRoZSBoZWFkIGJyYW5jaC5cbiAgICogVXNlZnVsIGZvciB0aGluZ3MgbGlrZSB2ZXJzaW9uIGJ1bXBzIG9yIGFueSBhdXRvLWdlbmVyYXRlZCBjb21taXRzLlxuICAgKlxuICAgKiBOb3RlIHRoYXQgeW91IGNhbm5vdCB1c2UgZXhwb3J0IGtleXMgaW4gdGhlc2UgY29tbWFuZHMgKFNlZSBgZXhwb3J0c2AgcHJvcGVydHkpXG4gICAqXG4gICAqIEBkZWZhdWx0IC0gbm8gY29tbWFuZHMuXG4gICAqL1xuICBjb21tYW5kcz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBUaGUgaGVhZCBicmFuY2ggb2YgdGhlIFBSLlxuICAgKi9cbiAgaGVhZDogSGVhZDtcblxuICAvKipcbiAgICogVGhlIGV4aXQgY29kZSBvZiB0aGlzIGNvbW1hbmQgZGV0ZXJtaW5lcyB3aGV0aGVyIG9yIG5vdCB0byBwcm9jZWVkIHdpdGggdGhlXG4gICAqIFBSIGNyZWF0aW9uLiBJZiBjb25maWd1cmVkLCB0aGlzIGNvbW1hbmQgaXMgdGhlIGZpcnN0IG9uZSB0byBydW4sIGFuZCBpZiBpdCBmYWlscywgYWxsXG4gICAqIG90aGVyIGNvbW1hbmRzIHdpbGwgYmUgc2tpcHBlZC5cbiAgICpcbiAgICogVGhpcyBjb21tYW5kIGlzIHRoZSBmaXJzdCB0byBleGVjdXRlLCBhbmQgc2hvdWxkIG5vdCBhc3N1bWUgYW55IHByZS1leGlzdGluZyBzdGF0ZS5cbiAgICpcbiAgICogQGRlZmF1bHQgLSBubyBjb25kaXRpb25cbiAgICovXG4gIGNvbmRpdGlvbj86IHN0cmluZztcblxuICAvKipcbiAgICogSWYgYW55IFBSIGxhYmVsZWQgd2l0aCB0aGUgZ2l2ZW4gbGFiZWxzIGlzIHN0aWxsIG9wZW4sIG5vIG5ldyBQUiB3aWxsIGJlIGNyZWF0ZWRcbiAgICpcbiAgICogQGRlZmF1bHQgLSBkb24ndCBsb29rIGF0IG9wZW4gUFJzXG4gICAqL1xuICByZWFkb25seSBza2lwSWZPcGVuUHJzV2l0aExhYmVscz86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBEZXNjcmlwdGlvbiBzdHJpbmcgZm9yIHRoZSBDb2RlQnVpbGQgcHJvamVjdFxuICAgKlxuICAgKiBAZGVmYXVsdCAtIE5vIGRlc2NyaXB0aW9uXG4gICAqL1xuICByZWFkb25seSBwcm9qZWN0RGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUHJvcGVydGllcyBmb3IgY29uZmlndXJpbmcgdGhlIGJhc2UgYnJhbmNoIG9mIHRoZSBQUi5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCYXNlIHtcblxuICAvKipcbiAgICogQnJhbmNoIG5hbWUuXG4gICAqXG4gICAqIFRoaXMgYnJhbmNoIG11c3QgZXhpc3QuXG4gICAqXG4gICAqIEBkZWZhdWx0ICdtYXN0ZXInXG4gICAqL1xuICByZWFkb25seSBuYW1lPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIFByb3BlcnRpZXMgZm9yIGNvbmZpZ3VyaW5nIHRoZSBoZWFkIGJyYW5jaCBvZiB0aGUgUFIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGVhZCB7XG5cbiAgLyoqXG4gICAqIEJyYW5jaCBuYW1lLlxuICAgKlxuICAgKiBUaGlzIGJyYW5jaCB3aWxsIGJlIGNyZWF0ZWQgaWYgaXQgZG9lc24ndCBleGlzdC5cbiAgICovXG4gIHJlYWRvbmx5IG5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHNvdXJjZSBzaGEgb2YgdGhlIGJyYW5jaC5cbiAgICpcbiAgICogSWYgdGhlIGdpdmVuIGJyYW5jaCBhbHJlYWR5IGV4aXN0cywgdGhpcyBzaGEgd2lsbCBiZSBhdXRvLW1lcmdlZCBvbnRvIGl0LiBOb3RlIHRoYXQgaW4gc3VjaCBhIGNhc2UsXG4gICAqIHRoZSBQUiBjcmVhdGlvbiBtaWdodCBmYWlsIGluIGNhc2UgdGhlcmUgYXJlIG1lcmdlIGNvbmZsaWN0cy5cbiAgICpcbiAgICogSWYgdGhlIGdpdmVuIGJyYW5jaCBkb2Vzbid0IGV4aXN0LCB0aGUgbmV3bHkgY3JlYXRlZCBicmFuY2ggd2lsbCBiZSBiYXNlZCBvZiB0aGlzIGhhc2guXG4gICAqXG4gICAqIE5vdGUgdGhhdCBkeW5hbWljIGV4cG9ydHMgYXJlIG5vdCBhbGxvd2VkIGZvciB0aGlzIHByb3BlcnR5LlxuICAgKlxuICAgKiBAZGVmYXVsdCAtIHRoZSBiYXNlIGJyYW5jaCBvZiB0aGUgcHIuXG4gICAqL1xuICByZWFkb25seSBzb3VyY2U/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIENvZGVCdWlsZCBqb2IgdGhhdCwgd2hlbiB0cmlnZ2VyZWQsIG9wZW5zIGEgR2l0SHViIFB1bGwgUmVxdWVzdC5cbiAqL1xuZXhwb3J0IGNsYXNzIEF1dG9QdWxsUmVxdWVzdCBleHRlbmRzIENvbnN0cnVjdCB7XG5cbiAgLyoqXG4gICAqIENsb3VkV2F0Y2ggYWxhcm0gdGhhdCB3aWxsIGJlIHRyaWdnZXJlZCBpZiB0aGUgam9iIGZhaWxzLlxuICAgKi9cbiAgcHVibGljIHJlYWRvbmx5IGFsYXJtOiBjbG91ZHdhdGNoLkFsYXJtO1xuXG4gIC8qKlxuICAgKiBUaGUgQ29kZUJ1aWxkIHByb2plY3QgdGhpcyBjb25zdHJ1Y3QgY3JlYXRlcy5cbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBwcm9qZWN0OiBjYnVpbGQuSVByb2plY3Q7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBwcm9wczogQXV0b1B1bGxSZXF1ZXN0UHJvcHM7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBiYXNlQnJhbmNoOiBzdHJpbmc7XG4gIHByaXZhdGUgcmVhZG9ubHkgaGVhZFNvdXJjZTogc3RyaW5nO1xuICBwcml2YXRlIHJlYWRvbmx5IGV4cG9ydHM6IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG5cbiAgY29uc3RydWN0b3IocGFyZW50OiBDb25zdHJ1Y3QsIGlkOiBzdHJpbmcsIHByb3BzOiBBdXRvUHVsbFJlcXVlc3RQcm9wcykge1xuICAgIHN1cGVyKHBhcmVudCwgaWQpO1xuXG4gICAgdGhpcy5wcm9wcyA9IHByb3BzO1xuXG4gICAgdGhpcy5iYXNlQnJhbmNoID0gcHJvcHMuYmFzZT8ubmFtZSA/PyAnbWFzdGVyJztcbiAgICB0aGlzLmhlYWRTb3VyY2UgPSBwcm9wcy5oZWFkLnNvdXJjZSA/PyB0aGlzLmJhc2VCcmFuY2g7XG4gICAgdGhpcy5leHBvcnRzID0gcHJvcHMuZXhwb3J0cyA/PyB7fTtcblxuICAgIGZvciAoY29uc3QgZXggb2YgT2JqZWN0LmtleXModGhpcy5leHBvcnRzKSkge1xuICAgICAgaWYgKHRoaXMuaGVhZFNvdXJjZS5pbmNsdWRlcyhgXFwkeyR7ZXh9fWApIHx8IHRoaXMuaGVhZFNvdXJjZS5pbmNsdWRlcyhgXFwkJHtleH1gKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYGhlYWQgc291cmNlICgke3RoaXMuaGVhZFNvdXJjZX0pIGNhbm5vdCBjb250YWluIGR5bmFtaWMgZXhwb3J0czogJHtleH1gKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzc2hLZXlTZWNyZXQgPSBwcm9wcy5yZXBvLnNzaEtleVNlY3JldDtcbiAgICBjb25zdCBjb21taXRFbWFpbCA9IHByb3BzLnJlcG8uY29tbWl0RW1haWw7XG4gICAgY29uc3QgY29tbWl0VXNlcm5hbWUgPSBwcm9wcy5yZXBvLmNvbW1pdFVzZXJuYW1lO1xuICAgIGNvbnN0IGNsb25lRGVwdGggPSBwcm9wcy5jbG9uZURlcHRoID09PSB1bmRlZmluZWQgPyAwIDogcHJvcHMuY2xvbmVEZXB0aDtcblxuICAgIGNvbnN0IG5lZWRzR2l0SHViVG9rZW5TZWNyZXQgPSAhdGhpcy5wcm9wcy5wdXNoT25seSB8fCAhIXRoaXMucHJvcHMuc2tpcElmT3BlblByc1dpdGhMYWJlbHM7XG5cbiAgICBsZXQgY29tbWFuZHM6IHN0cmluZ1tdID0gW1xuXG4gICAgICAuLi50aGlzLmNvbmZpZ3VyZVNzaEFjY2VzcygpLFxuXG4gICAgICAvLyB3aGVuIHRoZSBqb2IgaXMgdHJpZ2dlcmVkIGFzIGEgQ29kZVBpcGVsaW5lIGFjdGlvbiwgdGhlIHdvcmtpbmcgZGlyZWN0b3J5XG4gICAgICAvLyBpcyBwb3B1bGF0ZWQgd2l0aCB0aGUgb3V0cHV0IGFydGlmYWN0IG9mIHRoZSBDb2RlQ29tbWl0U291cmNlQWN0aW9uLCB3aGljaCBkb2Vzbid0IGluY2x1ZGVcbiAgICAgIC8vIHRoZSAuZ2l0IGRpcmVjdG9yeSBpbiB0aGUgemlwcGVkIHMzIGFyY2hpdmUuIChZZWFoLCBmdW4gc3R1ZmYpLlxuICAgICAgLy8gc2VlIGh0dHBzOi8vaXRuZXh0LmlvL2hvdy10by1hY2Nlc3MtZ2l0LW1ldGFkYXRhLWluLWNvZGVidWlsZC13aGVuLXVzaW5nLWNvZGVwaXBlbGluZS1jb2RlY29tbWl0LWNlYWNmMmM1YzFkY1xuICAgICAgLi4udGhpcy5jbG9uZUlmTmVlZGVkKCksXG4gICAgXTtcblxuICAgIGlmICh0aGlzLnByb3BzLmNvbmRpdGlvbikge1xuICAgICAgLy8gdGhlcmUncyBubyB3YXkgdG8gc3RvcCBhIEJ1aWxkU3BlYyBleGVjdXRpb24gaGFsZndheSB0aHJvdWdoIHdpdGhvdXQgdGhyb3dpbmcgYW4gZXJyb3IuIEJlbGlldmUgbWUsIElcbiAgICAgIC8vIGNoZWNrZWQgdGhlIGNvZGUuIEluc3RlYWQgd2UgZGVmaW5lIGEgdmFyaWFibGUgdGhhdCB3ZSB3aWxsIHN3aXRjaCBhbGwgb3RoZXIgbGluZXMgb24vb2ZmLlxuICAgICAgY29tbWFuZHMucHVzaChgJHt0aGlzLnByb3BzLmNvbmRpdGlvbn0gYCArXG4gICAgICAnJiYgeyBlY2hvIFxcJ1NraXAgY29uZGl0aW9uIGlzIG1ldCwgc2tpcHBpbmcuLi5cXCcgJiYgZXhwb3J0IFNLSVA9dHJ1ZTsgfSAnICtcbiAgICAgICd8fCB7IGVjaG8gXFwnU2tpcCBjb25kaXRpb24gaXMgbm90IG1ldCwgY29udGludWluZy4uLlxcJyAmJiBleHBvcnQgU0tJUD1mYWxzZTsgfScpO1xuICAgIH1cblxuICAgIC8vIHJlYWQgdGhlIHRva2VuXG4gICAgaWYgKG5lZWRzR2l0SHViVG9rZW5TZWNyZXQpIHtcbiAgICAgIGNvbW1hbmRzLnB1c2goYGV4cG9ydCBHSVRIVUJfVE9LRU49JChhd3Mgc2VjcmV0c21hbmFnZXIgZ2V0LXNlY3JldC12YWx1ZSAtLXNlY3JldC1pZCBcIiR7dGhpcy5wcm9wcy5yZXBvLnRva2VuU2VjcmV0QXJufVwiIC0tb3V0cHV0PXRleHQgLS1xdWVyeT1TZWNyZXRTdHJpbmcpYCk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMucHJvcHMuc2tpcElmT3BlblByc1dpdGhMYWJlbHMpIHtcbiAgICAgIGNvbW1hbmRzLnB1c2goLi4udGhpcy5za2lwSWZPcGVuUHJzKHRoaXMucHJvcHMuc2tpcElmT3BlblByc1dpdGhMYWJlbHMpKTtcbiAgICB9XG5cbiAgICBjb21tYW5kcy5wdXNoKFxuICAgICAgLi4udGhpcy5jcmVhdGVIZWFkKCksXG4gICAgICAuLi50aGlzLnB1c2hIZWFkKCksXG4gICAgKTtcblxuICAgIGlmICghdGhpcy5wcm9wcy5wdXNoT25seSkge1xuICAgICAgY29tbWFuZHMucHVzaCguLi50aGlzLmNyZWF0ZVB1bGxSZXF1ZXN0KCkpO1xuICAgIH1cblxuICAgIC8vIHRvZ2dsZSBhbGwgY29tbWFuZHMgYWNjb3JkaW5nIHRvIHRoZSBTS0lQIHZhcmlhYmxlLlxuICAgIGNvbW1hbmRzID0gY29tbWFuZHMubWFwKChjb21tYW5kOiBzdHJpbmcpID0+IGAkU0tJUCB8fCB7ICR7Y29tbWFuZH0gOyB9YCk7XG5cbiAgICAvLyBpbnRpYWxseSBhbGwgY29tbWFuZHMgYXJlIGVuYWJsZWQuXG4gICAgY29tbWFuZHMudW5zaGlmdCgnZXhwb3J0IFNLSVA9ZmFsc2UnKTtcblxuICAgIHRoaXMucHJvamVjdCA9IG5ldyBjYnVpbGQuUHJvamVjdCh0aGlzLCAnUHVsbFJlcXVlc3QnLCB7XG4gICAgICBzb3VyY2U6IHByb3BzLnJlcG8uY3JlYXRlQnVpbGRTb3VyY2UodGhpcywgZmFsc2UsIHsgY2xvbmVEZXB0aCB9KSxcbiAgICAgIGRlc2NyaXB0aW9uOiBwcm9wcy5wcm9qZWN0RGVzY3JpcHRpb24sXG4gICAgICBlbnZpcm9ubWVudDogY3JlYXRlQnVpbGRFbnZpcm9ubWVudChwcm9wcy5idWlsZCA/PyB7fSksXG4gICAgICBidWlsZFNwZWM6IGNidWlsZC5CdWlsZFNwZWMuZnJvbU9iamVjdCh7XG4gICAgICAgIHZlcnNpb246ICcwLjInLFxuICAgICAgICBwaGFzZXM6IHtcbiAgICAgICAgICBwcmVfYnVpbGQ6IHtcbiAgICAgICAgICAgIGNvbW1hbmRzOiBbXG4gICAgICAgICAgICAgIGBnaXQgY29uZmlnIC0tZ2xvYmFsIHVzZXIuZW1haWwgXCIke2NvbW1pdEVtYWlsfVwiYCxcbiAgICAgICAgICAgICAgYGdpdCBjb25maWcgLS1nbG9iYWwgdXNlci5uYW1lIFwiJHtjb21taXRVc2VybmFtZX1cImAsXG4gICAgICAgICAgICBdLFxuICAgICAgICAgIH0sXG4gICAgICAgICAgYnVpbGQ6IHsgY29tbWFuZHMgfSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuICAgICAgc3NtU2Vzc2lvblBlcm1pc3Npb25zOiB0cnVlLFxuICAgIH0pO1xuXG4gICAgLy8gQWx3YXlzIGV4aXN0cyBhcyB0aGUgcHJvamVjdCBpcyBub3QgYSByZWZlcmVuY2VcbiAgICBjb25zdCBwcm9qZWN0Um9sZSA9IHRoaXMucHJvamVjdC5yb2xlITtcbiAgICBwcm9qZWN0Um9sZS5hZGRNYW5hZ2VkUG9saWN5KGlhbS5NYW5hZ2VkUG9saWN5LmZyb21Bd3NNYW5hZ2VkUG9saWN5TmFtZSgnQW1hem9uRWxhc3RpY0NvbnRhaW5lclJlZ2lzdHJ5UHVibGljUmVhZE9ubHknKSk7XG4gICAgcGVybWlzc2lvbnMuZ3JhbnRTZWNyZXRSZWFkKHNzaEtleVNlY3JldCwgcHJvamVjdFJvbGUpO1xuICAgIGlmIChuZWVkc0dpdEh1YlRva2VuU2VjcmV0KSB7XG4gICAgICBwZXJtaXNzaW9ucy5ncmFudFNlY3JldFJlYWQoeyBzZWNyZXRBcm46IHByb3BzLnJlcG8udG9rZW5TZWNyZXRBcm4gfSwgcHJvamVjdFJvbGUpO1xuICAgIH1cblxuICAgIGlmIChwcm9wcy5zY2hlZHVsZUV4cHJlc3Npb24pIHtcbiAgICAgIGNvbnN0IHNjaGVkdWxlID0gZXZlbnRzLlNjaGVkdWxlLmV4cHJlc3Npb24ocHJvcHMuc2NoZWR1bGVFeHByZXNzaW9uKTtcbiAgICAgIG5ldyBldmVudHMuUnVsZSh0aGlzLCAnU2NoZWR1bGVyJywge1xuICAgICAgICBkZXNjcmlwdGlvbjogJ1NjaGVkdWxlcyBhbiBhdXRvbWF0aWMgUHVsbCBSZXF1ZXN0IGZvciB0aGlzIHJlcG9zaXRvcnknLFxuICAgICAgICBzY2hlZHVsZSxcbiAgICAgICAgdGFyZ2V0czogW25ldyBldmVudHNfdGFyZ2V0cy5Db2RlQnVpbGRQcm9qZWN0KHRoaXMucHJvamVjdCldLFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgdGhpcy5hbGFybSA9IHRoaXMucHJvamVjdC5tZXRyaWNGYWlsZWRCdWlsZHMoeyBwZXJpb2Q6IER1cmF0aW9uLnNlY29uZHMoMzAwKSB9KS5jcmVhdGVBbGFybSh0aGlzLCAnQXV0b1B1bGxSZXF1ZXN0RmFpbGVkQWxhcm0nLCB7XG4gICAgICB0aHJlc2hvbGQ6IDEsXG4gICAgICBldmFsdWF0aW9uUGVyaW9kczogMSxcbiAgICAgIHRyZWF0TWlzc2luZ0RhdGE6IGNsb3Vkd2F0Y2guVHJlYXRNaXNzaW5nRGF0YS5JR05PUkUsXG4gICAgfSk7XG4gIH1cbiAgcHJpdmF0ZSBjcmVhdGVIZWFkKCk6IHN0cmluZ1tdIHtcblxuICAgIHJldHVybiBbXG4gICAgICAvLyBjaGVjayBpZiBoZWFkIGJyYW5jaCBleGlzdHNcbiAgICAgIGBnaXQgcmV2LXBhcnNlIC0tdmVyaWZ5IG9yaWdpbi8ke3RoaXMucHJvcHMuaGVhZC5uYW1lfSBgICtcblxuICAgICAgLy8gY2hlY2tvdXQgYW5kIG1lcmdlIGlmIGl0IGRvZXMgKHRoaXMgbWlnaHQgZmFpbCBkdWUgdG8gbWVyZ2UgY29uZmxpY3RzKVxuICAgICAgYCYmIHsgZ2l0IGNoZWNrb3V0ICR7dGhpcy5wcm9wcy5oZWFkLm5hbWV9ICYmIGdpdCBtZXJnZSAke3RoaXMuaGVhZFNvdXJjZX0gJiYgJHt0aGlzLnJ1bkNvbW1hbmRzKCl9OyAgfSBgICtcblxuICAgICAgLy8gY3JlYXRlIGlmIGl0IGRvZXNudC4gd2UgaW5pdGlhbGx5IHVzZSAndGVtcCcgdG8gYWxsb3cgdXNpbmcgZXhwb3J0cyBpbiB0aGUgaGVhZCBicmFuY2ggbmFtZS4gKGUuZyBidW1wLyRWRVJTSU9OKVxuICAgICAgYHx8IHsgZ2l0IGNoZWNrb3V0ICR7dGhpcy5oZWFkU291cmNlfSAmJiBnaXQgY2hlY2tvdXQgLWIgdGVtcCAmJiAke3RoaXMucnVuQ29tbWFuZHMoKX0gJiYgZ2l0IGJyYW5jaCAtTSAke3RoaXMucHJvcHMuaGVhZC5uYW1lfTsgfWAsXG5cbiAgICBdO1xuXG4gIH1cblxuICBwcml2YXRlIGNsb25lSWZOZWVkZWQoKTogc3RyaW5nW10ge1xuXG4gICAgcmV0dXJuIFtcbiAgICAgIC8vIGNoZWNrIGlmIC5naXQgZXhpc3RcbiAgICAgICdscyAuZ2l0ICcgK1xuXG4gICAgICAvLyBhbGwgZ29vZFxuICAgICAgJyYmIHsgZWNobyBcIi5naXQgZGlyZWN0b3J5IGV4aXN0c1wiOyAgfSAnICtcblxuICAgICAgLy8gY2xvbmUgaWYgaXQgZG9lc24ndFxuICAgICAgYHx8IHsgZWNobyBcIi5naXQgZGlyZWN0b3J5IGRvZXNub3QgZXhpc3QgLSBjbG9uaW5nLi4uXCIgJiYgZ2l0IGluaXQgLiAmJiBnaXQgcmVtb3RlIGFkZCBvcmlnaW4gZ2l0QGdpdGh1Yi5jb206JHt0aGlzLnByb3BzLnJlcG8ub3duZXJ9LyR7dGhpcy5wcm9wcy5yZXBvLnJlcG99LmdpdCAmJiBnaXQgZmV0Y2ggJiYgZ2l0IHJlc2V0IC0taGFyZCBvcmlnaW4vJHt0aGlzLmJhc2VCcmFuY2h9ICYmIGdpdCBicmFuY2ggLU0gJHt0aGlzLmJhc2VCcmFuY2h9ICYmIGdpdCBjbGVhbiAtZnFkeDsgfWAsXG5cbiAgICBdO1xuXG4gIH1cblxuICBwcml2YXRlIHJ1bkNvbW1hbmRzKCk6IHN0cmluZyB7XG5cbiAgICBjb25zdCB1c2VyQ29tbWFuZHMgPSB0aGlzLnByb3BzLmNvbW1hbmRzID8/IFtdO1xuICAgIGNvbnN0IGV4cG9ydHMgPSBPYmplY3QuZW50cmllcyh0aGlzLmV4cG9ydHMpLm1hcChlbnRyeSA9PiBgZXhwb3J0ICR7ZW50cnlbMF19PSQoJHtlbnRyeVsxXX0pYCk7XG5cbiAgICByZXR1cm4gW1xuXG4gICAgICAuLi51c2VyQ29tbWFuZHMsXG5cbiAgICAgIC8vIGV4cG9ydHMgc2hvdWxkIGJlIGV4ZWN1dGVkIGltbWVkaWF0ZWx5IGFmdGVyIHRoZSB1c2VyIGNvbW1hbmRzIChub3QgYmVmb3JlKVxuICAgICAgLy8gYmVjYXVzZSB0aGV5IG1pZ2h0IG5lZWQgYWNjZXNzIHRvIGFydGlmYWN0cyBwcm9kdWNlZCBieSB0aGVtIChlLmcgdmVyc2lvbiBmaWxlKS5cbiAgICAgIC4uLmV4cG9ydHMsXG5cbiAgICAgICdlY2hvIEZpbmlzaGVkIHJ1bm5pbmcgdXNlciBjb21tYW5kcycsXG4gICAgXS5qb2luKCcgJiYgJyk7XG5cbiAgfVxuXG4gIHByaXZhdGUgY29uZmlndXJlU3NoQWNjZXNzKCk6IHN0cmluZ1tdIHtcblxuICAgIHJldHVybiBbXG4gICAgICAnYXdzIHNlY3JldHNtYW5hZ2VyIGdldC1zZWNyZXQtdmFsdWUgJ1xuICAgICAgICArIGAtLXNlY3JldC1pZCBcIiR7dGhpcy5wcm9wcy5yZXBvLnNzaEtleVNlY3JldC5zZWNyZXRBcm59XCIgYFxuICAgICAgICArICctLW91dHB1dD10ZXh0IC0tcXVlcnk9U2VjcmV0U3RyaW5nID4gfi8uc3NoL2lkX3JzYScsXG4gICAgICAnbWtkaXIgLXAgfi8uc3NoJyxcbiAgICAgICdjaG1vZCAwNjAwIH4vLnNzaC9pZF9yc2Egfi8uc3NoL2NvbmZpZycsXG4gICAgICAnc3NoLWtleXNjYW4gLXQgcnNhIGdpdGh1Yi5jb20gPj4gfi8uc3NoL2tub3duX2hvc3RzJyxcbiAgICBdO1xuXG4gIH1cblxuICBwcml2YXRlIHB1c2hIZWFkKCk6IHN0cmluZ1tdIHtcbiAgICAvLyBXZSB3aWxsIGRvIG5vdGhpbmcgYW5kIHNldCBgU0tJUD10cnVlYCBpZiB0aGUgaGVhZCByZWYgaXMgYW4gYW5jZXN0b3Igb2YgdGhlIGJhc2UgYnJhbmNoIChubyBQUiBjb3VsZCBiZSBjcmVhdGVkKVxuICAgIHJldHVybiBbXG4gICAgICBgZ2l0IG1lcmdlLWJhc2UgLS1pcy1hbmNlc3RvciAke3RoaXMucHJvcHMuaGVhZC5uYW1lfSBvcmlnaW4vJHt0aGlzLmJhc2VCcmFuY2h9YFxuICAgICAgICArIGAgJiYgeyBlY2hvIFwiU2tpcHBpbmc6ICR7dGhpcy5wcm9wcy5oZWFkLm5hbWV9IGlzIGFuIGFuY2VzdG9yIG9mIG9yaWdpbi8ke3RoaXMuYmFzZUJyYW5jaH1cIjsgZXhwb3J0IFNLSVA9dHJ1ZTsgfWBcbiAgICAgICAgKyBgIHx8IHsgZWNobyBcIlB1c2hpbmc6ICR7dGhpcy5wcm9wcy5oZWFkLm5hbWV9IGlzIGFoZWFkIG9mIG9yaWdpbi8ke3RoaXMuYmFzZUJyYW5jaH1cIjsgZXhwb3J0IFNLSVA9ZmFsc2U7IH1gLFxuICAgICAgYGdpdCByZW1vdGUgYWRkIG9yaWdpbl9zc2ggJHt0aGlzLnByb3BzLnJlcG8ucmVwb3NpdG9yeVVybFNzaH1gLFxuICAgICAgLy8gTmVlZCBgLS1hdG9taWNgLCBvdGhlcndpc2UgYGdpdCBwdXNoYCBtaWdodCBzdWNjZXNzZnVsbHkgcHVzaCB0aGUgdGFncyBidXQgbm90IHRvIGBtYWluYC5cbiAgICAgIGBnaXQgcHVzaCAtLWF0b21pYyAtLWZvbGxvdy10YWdzIG9yaWdpbl9zc2ggJHt0aGlzLnByb3BzLmhlYWQubmFtZX06JHt0aGlzLnByb3BzLmhlYWQubmFtZX1gLFxuICAgIF07XG4gIH1cblxuICBwcml2YXRlIHNraXBJZk9wZW5QcnMobGFiZWxzOiBzdHJpbmdbXSk6IHN0cmluZ1tdIHtcbiAgICBjb25zdCBmaWx0ZXJzID0gW1xuICAgICAgYHJlcG86JHt0aGlzLnByb3BzLnJlcG8ub3duZXJ9LyR7dGhpcy5wcm9wcy5yZXBvLnJlcG99YCxcbiAgICAgICdpczpwcicsXG4gICAgICAnaXM6b3BlbicsXG4gICAgICAuLi5sYWJlbHMubWFwKGwgPT4gYGxhYmVsOiR7bH1gKSxcbiAgICBdO1xuXG4gICAgcmV0dXJuIFtcbiAgICAgIGAke3RoaXMuZ2l0aHViQ3VybEdldChgL3NlYXJjaC9pc3N1ZXM/cT0ke2VuY29kZVVSSUNvbXBvbmVudChmaWx0ZXJzLmpvaW4oJyAnKSl9YCwgJy1vIHNlYXJjaC5qc29uJyl9YCxcbiAgICAgICdub2RlIC1lIFxcJ3Byb2Nlc3MuZXhpdENvZGUgPSByZXF1aXJlKFwiLi9zZWFyY2guanNvblwiKS50b3RhbF9jb3VudFxcJydcbiAgICAgICAgKyBgIHx8IHsgZWNobyBcIkZvdW5kIG9wZW4gUFJzIHdpdGggbGFiZWwgJHtsYWJlbHN9LCBza2lwcGluZyBQUi5cIjsgZXhwb3J0IFNLSVA9dHJ1ZTsgfWAsXG4gICAgXTtcbiAgfVxuXG5cbiAgcHJpdmF0ZSBjcmVhdGVQdWxsUmVxdWVzdCgpOiBzdHJpbmdbXSB7XG5cbiAgICBjb25zdCBoZWFkID0gdGhpcy5wcm9wcy5oZWFkLm5hbWU7XG4gICAgY29uc3QgYmFzZSA9IHRoaXMuYmFzZUJyYW5jaDtcblxuICAgIGlmIChoZWFkID09PSBiYXNlKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEhlYWQgYnJhbmNoIChcIiR7YmFzZX1cIikgaXMgdGhlIHNhbWUgYXMgdGhlIGJhc2UgYnJhbmNoIChcIiR7aGVhZH1cIilgKTtcbiAgICB9XG5cbiAgICBjb25zdCBwcm9wcyA9IHRoaXMucHJvcHM7XG4gICAgY29uc3QgdGl0bGUgPSBwcm9wcy50aXRsZSA/PyBgTWVyZ2UgJHtoZWFkfSB0byAke2Jhc2V9YDtcbiAgICBjb25zdCBib2R5ID0gdGhpcy5wcm9wcy5ib2R5ID8/ICcnO1xuXG4gICAgY29uc3QgY3JlYXRlUmVxdWVzdCA9IHsgdGl0bGUsIGJhc2UsIGhlYWQgfTtcblxuICAgIGNvbnN0IGNvbW1hbmRzID0gW107XG5cbiAgICAvLyBjcmVhdGUgdGhlIFBSXG4gICAgY29tbWFuZHMucHVzaChgJHt0aGlzLmdpdGh1YkN1cmwoJy9wdWxscycsICctWCBQT1NUIC1vIHByLmpzb24nLCBjcmVhdGVSZXF1ZXN0KX0gJiYgZXhwb3J0IFBSX05VTUJFUj0kKG5vZGUgLXAgJ3JlcXVpcmUoXCIuL3ByLmpzb25cIikubnVtYmVyJylgKTtcblxuICAgIC8vIHVwZGF0ZSB0aGUgYm9keVxuICAgIGNvbW1hbmRzLnB1c2godGhpcy5naXRodWJDdXJsKCcvcHVsbHMvJFBSX05VTUJFUicsICctWCBQQVRDSCcsIHsgYm9keTogYm9keSB9KSk7XG5cbiAgICBpZiAodGhpcy5wcm9wcy5sYWJlbHMgJiYgdGhpcy5wcm9wcy5sYWJlbHMubGVuZ3RoID4gMCkge1xuICAgIC8vIGFwcGx5IGxhYmVscy5cbiAgICAgIGNvbW1hbmRzLnB1c2godGhpcy5naXRodWJDdXJsKCcvaXNzdWVzLyRQUl9OVU1CRVIvbGFiZWxzJywgJy1YIFBPU1QnLCB7IGxhYmVsczogdGhpcy5wcm9wcy5sYWJlbHMgfSkpO1xuICAgIH1cblxuICAgIHJldHVybiBjb21tYW5kcztcblxuICB9XG5cbiAgcHJpdmF0ZSBnaXRodWJDdXJsKHVyaTogc3RyaW5nLCBjb21tYW5kOiBzdHJpbmcsIHJlcXVlc3Q6IGFueSk6IHN0cmluZyB7XG4gICAgcmV0dXJuIFtcbiAgICAgICdjdXJsIC0tZmFpbCcsXG4gICAgICBjb21tYW5kLFxuICAgICAgJy0taGVhZGVyIFwiQXV0aG9yaXphdGlvbjogdG9rZW4gJEdJVEhVQl9UT0tFTlwiJyxcbiAgICAgICctLWhlYWRlciBcIkNvbnRlbnQtVHlwZTogYXBwbGljYXRpb24vanNvblwiJyxcbiAgICAgIGAtZCAke0pTT04uc3RyaW5naWZ5KEpTT04uc3RyaW5naWZ5KHJlcXVlc3QpKX1gLFxuICAgICAgYGh0dHBzOi8vYXBpLmdpdGh1Yi5jb20vcmVwb3MvJHt0aGlzLnByb3BzLnJlcG8ub3duZXJ9LyR7dGhpcy5wcm9wcy5yZXBvLnJlcG99JHt1cml9YCxcbiAgICBdLmpvaW4oJyAnKTtcbiAgfVxuXG4gIHByaXZhdGUgZ2l0aHViQ3VybEdldCh1cmk6IHN0cmluZywgY29tbWFuZDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICByZXR1cm4gW1xuICAgICAgJ2N1cmwgLS1mYWlsJyxcbiAgICAgIGNvbW1hbmQsXG4gICAgICAnLS1oZWFkZXIgXCJBdXRob3JpemF0aW9uOiB0b2tlbiAkR0lUSFVCX1RPS0VOXCInLFxuICAgICAgJy0taGVhZGVyIFwiQ29udGVudC1UeXBlOiBhcHBsaWNhdGlvbi9qc29uXCInLFxuICAgICAgYCdodHRwczovL2FwaS5naXRodWIuY29tJHt1cml9J2AsXG4gICAgXS5qb2luKCcgJyk7XG4gIH1cblxufVxuXG4iXX0=