projen
Version:
CDK for software projects
272 lines • 40.8 kB
JavaScript
"use strict";
var _a;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BuildWorkflow = void 0;
const JSII_RTTI_SYMBOL_1 = Symbol.for("jsii.rtti");
const path = require("path");
const component_1 = require("../component");
const github_1 = require("../github");
const constants_1 = require("../github/constants");
const util_1 = require("../github/private/util");
const workflow_actions_1 = require("../github/workflow-actions");
const workflows_model_1 = require("../github/workflows-model");
const javascript_1 = require("../javascript");
const runner_options_1 = require("../runner-options");
const consts_1 = require("./private/consts");
const name_1 = require("../util/name");
const path_1 = require("../util/path");
class BuildWorkflow extends component_1.Component {
constructor(project, options) {
super(project);
this._postBuildJobs = [];
const github = github_1.GitHub.of(this.project.root);
if (!github) {
throw new Error("BuildWorkflow is currently only supported for GitHub projects");
}
this.github = github;
this.preBuildSteps = options.preBuildSteps ?? [];
this.postBuildSteps = options.postBuildSteps ?? [];
this.gitIdentity = options.gitIdentity ?? constants_1.DEFAULT_GITHUB_ACTIONS_USER;
this.buildTask = options.buildTask;
this.artifactsDirectory =
options.artifactsDirectory ?? consts_1.DEFAULT_ARTIFACTS_DIRECTORY;
(0, util_1.ensureNotHiddenPath)(this.artifactsDirectory, "artifactsDirectory");
this.name = options.name ?? (0, name_1.workflowNameForProject)("build", this.project);
const mutableBuilds = options.mutableBuild ?? true;
this.workflow = new github_1.GithubWorkflow(github, this.name);
this.workflow.on(options.workflowTriggers ?? {
pullRequest: {},
workflowDispatch: {}, // allow manual triggering
});
this.addBuildJob(options);
if (mutableBuilds) {
this.addSelfMutationJob(options);
}
if (project instanceof javascript_1.NodeProject) {
project.addPackageIgnore(constants_1.PERMISSION_BACKUP_FILE);
}
}
addBuildJob(options) {
const projectPathRelativeToRoot = path.relative(this.project.root.outdir, this.project.outdir);
const jobConfig = {
...(0, runner_options_1.filteredRunsOnOptions)(options.runsOn, options.runsOnGroup),
container: options.containerImage
? { image: options.containerImage }
: undefined,
env: {
CI: "true",
...options.env,
},
permissions: {
contents: workflows_model_1.JobPermission.WRITE,
...options.permissions,
},
defaults: this.project.parent // is subproject,
? {
run: {
workingDirectory: (0, path_1.ensureRelativePathStartsWithDot)(projectPathRelativeToRoot),
},
}
: undefined,
steps: (() => this.renderBuildSteps(projectPathRelativeToRoot)),
outputs: {
[consts_1.SELF_MUTATION_HAPPENED_OUTPUT]: {
stepId: consts_1.SELF_MUTATION_STEP,
outputName: consts_1.SELF_MUTATION_HAPPENED_OUTPUT,
},
},
};
this.workflow.addJob(consts_1.BUILD_JOBID, jobConfig);
}
/**
* Returns a list of job IDs that are part of the build.
*/
get buildJobIds() {
return [consts_1.BUILD_JOBID, ...this._postBuildJobs];
}
/**
* Adds steps that are executed after the build.
* @param steps The job steps
*/
addPostBuildSteps(...steps) {
this.postBuildSteps.push(...steps);
}
/**
* Adds another job to the build workflow which is executed after the build
* job succeeded.
*
* Jobs are executed _only_ if the build did NOT self mutate. If the build
* self-mutate, the branch will either be updated or the build will fail (in
* forks), so there is no point in executing the post-build job.
*
* @param id The id of the new job
* @param job The job specification
*/
addPostBuildJob(id, job) {
const steps = [];
steps.push({
name: "Download build artifacts",
uses: "actions/download-artifact@v5",
with: {
name: constants_1.BUILD_ARTIFACT_NAME,
path: this.artifactsDirectory,
},
}, {
name: "Restore build artifact permissions",
continueOnError: true,
run: [
`cd ${this.artifactsDirectory} && setfacl --restore=${constants_1.PERMISSION_BACKUP_FILE}`,
].join("\n"),
});
steps.push(...(job.steps ?? []));
this.workflow.addJob(id, {
needs: [consts_1.BUILD_JOBID],
// only run if build did not self-mutate
if: `\${{ !${consts_1.SELF_MUTATION_CONDITION} }}`,
...job,
steps: steps,
});
// add to the list of build job IDs
this._postBuildJobs.push(id);
}
/**
* Run a task as a job within the build workflow which is executed after the
* build job succeeded.
*
* The job will have access to build artifacts and will install project
* dependencies in order to be able to run any commands used in the tasks.
*
* Jobs are executed _only_ if the build did NOT self mutate. If the build
* self-mutate, the branch will either be updated or the build will fail (in
* forks), so there is no point in executing the post-build job.
*
* @param options Specify tools and other options
*/
addPostBuildJobTask(task, options = {}) {
this.addPostBuildJobCommands(`post-build-${task.name}`, [`${this.project.projenCommand} ${task.name}`], {
checkoutRepo: true,
installDeps: true,
tools: options.tools,
...(0, runner_options_1.filteredRunsOnOptions)(options.runsOn, options.runsOnGroup),
});
}
/**
* Run a sequence of commands as a job within the build workflow which is
* executed after the build job succeeded.
*
* Jobs are executed _only_ if the build did NOT self mutate. If the build
* self-mutate, the branch will either be updated or the build will fail (in
* forks), so there is no point in executing the post-build job.
*
* @param options Specify tools and other options
*/
addPostBuildJobCommands(id, commands, options) {
const steps = [];
if (options?.checkoutRepo) {
steps.push(github_1.WorkflowSteps.checkout({
with: {
ref: consts_1.PULL_REQUEST_REF,
repository: consts_1.PULL_REQUEST_REPOSITORY,
...(this.github.downloadLfs ? { lfs: true } : {}),
},
}));
}
if (options?.checkoutRepo &&
options?.installDeps &&
this.project instanceof javascript_1.NodeProject) {
steps.push({
name: "Install dependencies",
run: `${this.project.package.installCommand}`,
});
}
steps.push({ run: commands.join("\n") });
this.addPostBuildJob(id, {
permissions: {
contents: workflows_model_1.JobPermission.READ,
},
tools: options?.tools,
...(0, runner_options_1.filteredRunsOnOptions)(options?.runsOn, options?.runsOnGroup),
steps,
});
}
addSelfMutationJob(options) {
this.workflow.addJob("self-mutation", {
...(0, runner_options_1.filteredRunsOnOptions)(options.runsOn, options.runsOnGroup),
permissions: {
contents: workflows_model_1.JobPermission.WRITE,
},
needs: [consts_1.BUILD_JOBID],
if: `always() && ${consts_1.SELF_MUTATION_CONDITION} && ${consts_1.NOT_FORK}`,
steps: [
...this.workflow.projenCredentials.setupSteps,
...workflow_actions_1.WorkflowActions.checkoutWithPatch({
// we need to use a PAT so that our push will trigger the build workflow
token: this.workflow.projenCredentials.tokenRef,
ref: consts_1.PULL_REQUEST_REF,
repository: consts_1.PULL_REQUEST_REPOSITORY,
lfs: this.github.downloadLfs,
}),
github_1.WorkflowSteps.setupGitIdentity({ gitIdentity: this.gitIdentity }),
{
name: "Push changes",
env: {
PULL_REQUEST_REF: consts_1.PULL_REQUEST_REF,
},
run: [
"git add .",
'git commit -s -m "chore: self mutation"',
`git push origin "HEAD:$PULL_REQUEST_REF"`,
].join("\n"),
},
],
});
}
/**
* Called (lazily) during synth to render the build job steps.
*/
renderBuildSteps(projectPathRelativeToRoot) {
return [
github_1.WorkflowSteps.checkout({
with: {
ref: consts_1.PULL_REQUEST_REF,
repository: consts_1.PULL_REQUEST_REPOSITORY,
...(this.github.downloadLfs ? { lfs: true } : {}),
},
}),
...this.preBuildSteps,
{
name: this.buildTask.name,
run: this.github.project.runTaskCommand(this.buildTask),
},
...this.postBuildSteps,
// check for mutations and upload a git patch file as an artifact
...workflow_actions_1.WorkflowActions.uploadGitPatch({
stepId: consts_1.SELF_MUTATION_STEP,
outputName: consts_1.SELF_MUTATION_HAPPENED_OUTPUT,
mutationError: "Files were changed during build (see build log). If this was triggered from a fork, you will need to update your branch.",
}),
// upload the build artifact only if we have post-build jobs (otherwise, there's no point)
...(this._postBuildJobs.length == 0
? []
: [
{
name: "Backup artifact permissions",
continueOnError: true,
run: `cd ${this.artifactsDirectory} && getfacl -R . > ${constants_1.PERMISSION_BACKUP_FILE}`,
},
github_1.WorkflowSteps.uploadArtifact({
with: {
name: constants_1.BUILD_ARTIFACT_NAME,
path: this.project.parent
? `${projectPathRelativeToRoot}/${this.artifactsDirectory}`
: this.artifactsDirectory,
},
}),
]),
];
}
}
exports.BuildWorkflow = BuildWorkflow;
_a = JSII_RTTI_SYMBOL_1;
BuildWorkflow[_a] = { fqn: "projen.build.BuildWorkflow", version: "0.98.32" };
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYnVpbGQtd29ya2Zsb3cuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvYnVpbGQvYnVpbGQtd29ya2Zsb3cudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBQSw2QkFBNkI7QUFFN0IsNENBQXlDO0FBQ3pDLHNDQU1tQjtBQUNuQixtREFJNkI7QUFDN0IsaURBQTZEO0FBQzdELGlFQUE2RDtBQUM3RCwrREFPbUM7QUFDbkMsOENBQTRDO0FBRTVDLHNEQUE4RTtBQUM5RSw2Q0FTMEI7QUFDMUIsdUNBQXNEO0FBQ3RELHVDQUErRDtBQWlHL0QsTUFBYSxhQUFjLFNBQVEscUJBQVM7SUFnQjFDLFlBQVksT0FBZ0IsRUFBRSxPQUE2QjtRQUN6RCxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUM7UUFIQSxtQkFBYyxHQUFhLEVBQUUsQ0FBQztRQUs3QyxNQUFNLE1BQU0sR0FBRyxlQUFNLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDNUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxJQUFJLEtBQUssQ0FDYiwrREFBK0QsQ0FDaEUsQ0FBQztRQUNKLENBQUM7UUFFRCxJQUFJLENBQUMsTUFBTSxHQUFHLE1BQU0sQ0FBQztRQUNyQixJQUFJLENBQUMsYUFBYSxHQUFHLE9BQU8sQ0FBQyxhQUFhLElBQUksRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxjQUFjLEdBQUcsT0FBTyxDQUFDLGNBQWMsSUFBSSxFQUFFLENBQUM7UUFDbkQsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJLHVDQUEyQixDQUFDO1FBQ3RFLElBQUksQ0FBQyxTQUFTLEdBQUcsT0FBTyxDQUFDLFNBQVMsQ0FBQztRQUNuQyxJQUFJLENBQUMsa0JBQWtCO1lBQ3JCLE9BQU8sQ0FBQyxrQkFBa0IsSUFBSSxvQ0FBMkIsQ0FBQztRQUM1RCxJQUFBLDBCQUFtQixFQUFDLElBQUksQ0FBQyxrQkFBa0IsRUFBRSxvQkFBb0IsQ0FBQyxDQUFDO1FBQ25FLElBQUksQ0FBQyxJQUFJLEdBQUcsT0FBTyxDQUFDLElBQUksSUFBSSxJQUFBLDZCQUFzQixFQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDMUUsTUFBTSxhQUFhLEdBQUcsT0FBTyxDQUFDLFlBQVksSUFBSSxJQUFJLENBQUM7UUFFbkQsSUFBSSxDQUFDLFFBQVEsR0FBRyxJQUFJLHVCQUFjLENBQUMsTUFBTSxFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FDZCxPQUFPLENBQUMsZ0JBQWdCLElBQUk7WUFDMUIsV0FBVyxFQUFFLEVBQUU7WUFDZixnQkFBZ0IsRUFBRSxFQUFFLEVBQUUsMEJBQTBCO1NBQ2pELENBQ0YsQ0FBQztRQUVGLElBQUksQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUM7UUFFMUIsSUFBSSxhQUFhLEVBQUUsQ0FBQztZQUNsQixJQUFJLENBQUMsa0JBQWtCLENBQUMsT0FBTyxDQUFDLENBQUM7UUFDbkMsQ0FBQztRQUVELElBQUksT0FBTyxZQUFZLHdCQUFXLEVBQUUsQ0FBQztZQUNuQyxPQUFPLENBQUMsZ0JBQWdCLENBQUMsa0NBQXNCLENBQUMsQ0FBQztRQUNuRCxDQUFDO0lBQ0gsQ0FBQztJQUVPLFdBQVcsQ0FBQyxPQUE2QjtRQUMvQyxNQUFNLHlCQUF5QixHQUFHLElBQUksQ0FBQyxRQUFRLENBQzdDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFDeEIsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQ3BCLENBQUM7UUFDRixNQUFNLFNBQVMsR0FBa0I7WUFDL0IsR0FBRyxJQUFBLHNDQUFxQixFQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLFdBQVcsQ0FBQztZQUM3RCxTQUFTLEVBQUUsT0FBTyxDQUFDLGNBQWM7Z0JBQy9CLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxPQUFPLENBQUMsY0FBYyxFQUFFO2dCQUNuQyxDQUFDLENBQUMsU0FBUztZQUNiLEdBQUcsRUFBRTtnQkFDSCxFQUFFLEVBQUUsTUFBTTtnQkFDVixHQUFHLE9BQU8sQ0FBQyxHQUFHO2FBQ2Y7WUFDRCxXQUFXLEVBQUU7Z0JBQ1gsUUFBUSxFQUFFLCtCQUFhLENBQUMsS0FBSztnQkFDN0IsR0FBRyxPQUFPLENBQUMsV0FBVzthQUN2QjtZQUNELFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxpQkFBaUI7Z0JBQzdDLENBQUMsQ0FBQztvQkFDRSxHQUFHLEVBQUU7d0JBQ0gsZ0JBQWdCLEVBQUUsSUFBQSxzQ0FBK0IsRUFDL0MseUJBQXlCLENBQzFCO3FCQUNGO2lCQUNGO2dCQUNILENBQUMsQ0FBQyxTQUFTO1lBQ2IsS0FBSyxFQUFFLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLHlCQUF5QixDQUFDLENBQVE7WUFDdEUsT0FBTyxFQUFFO2dCQUNQLENBQUMsc0NBQTZCLENBQUMsRUFBRTtvQkFDL0IsTUFBTSxFQUFFLDJCQUFrQjtvQkFDMUIsVUFBVSxFQUFFLHNDQUE2QjtpQkFDMUM7YUFDRjtTQUNGLENBQUM7UUFFRixJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxvQkFBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRDs7T0FFRztJQUNILElBQVcsV0FBVztRQUNwQixPQUFPLENBQUMsb0JBQVcsRUFBRSxHQUFHLElBQUksQ0FBQyxjQUFjLENBQUMsQ0FBQztJQUMvQyxDQUFDO0lBRUQ7OztPQUdHO0lBQ0ksaUJBQWlCLENBQUMsR0FBRyxLQUFnQjtRQUMxQyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxHQUFHLEtBQUssQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0ksZUFBZSxDQUFDLEVBQVUsRUFBRSxHQUFRO1FBQ3pDLE1BQU0sS0FBSyxHQUFHLEVBQUUsQ0FBQztRQUVqQixLQUFLLENBQUMsSUFBSSxDQUNSO1lBQ0UsSUFBSSxFQUFFLDBCQUEwQjtZQUNoQyxJQUFJLEVBQUUsOEJBQThCO1lBQ3BDLElBQUksRUFBRTtnQkFDSixJQUFJLEVBQUUsK0JBQW1CO2dCQUN6QixJQUFJLEVBQUUsSUFBSSxDQUFDLGtCQUFrQjthQUM5QjtTQUNGLEVBQ0Q7WUFDRSxJQUFJLEVBQUUsb0NBQW9DO1lBQzFDLGVBQWUsRUFBRSxJQUFJO1lBQ3JCLEdBQUcsRUFBRTtnQkFDSCxNQUFNLElBQUksQ0FBQyxrQkFBa0IseUJBQXlCLGtDQUFzQixFQUFFO2FBQy9FLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztTQUNiLENBQ0YsQ0FBQztRQUVGLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxLQUFLLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQztRQUVqQyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUU7WUFDdkIsS0FBSyxFQUFFLENBQUMsb0JBQVcsQ0FBQztZQUNwQix3Q0FBd0M7WUFDeEMsRUFBRSxFQUFFLFNBQVMsZ0NBQXVCLEtBQUs7WUFDekMsR0FBRyxHQUFHO1lBQ04sS0FBSyxFQUFFLEtBQUs7U0FDYixDQUFDLENBQUM7UUFFSCxtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDL0IsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7T0FZRztJQUNJLG1CQUFtQixDQUN4QixJQUFVLEVBQ1YsVUFBc0MsRUFBRTtRQUV4QyxJQUFJLENBQUMsdUJBQXVCLENBQzFCLGNBQWMsSUFBSSxDQUFDLElBQUksRUFBRSxFQUN6QixDQUFDLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxhQUFhLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLEVBQzlDO1lBQ0UsWUFBWSxFQUFFLElBQUk7WUFDbEIsV0FBVyxFQUFFLElBQUk7WUFDakIsS0FBSyxFQUFFLE9BQU8sQ0FBQyxLQUFLO1lBQ3BCLEdBQUcsSUFBQSxzQ0FBcUIsRUFBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUM7U0FDOUQsQ0FDRixDQUFDO0lBQ0osQ0FBQztJQUVEOzs7Ozs7Ozs7T0FTRztJQUNJLHVCQUF1QixDQUM1QixFQUFVLEVBQ1YsUUFBa0IsRUFDbEIsT0FBd0M7UUFFeEMsTUFBTSxLQUFLLEdBQUcsRUFBRSxDQUFDO1FBRWpCLElBQUksT0FBTyxFQUFFLFlBQVksRUFBRSxDQUFDO1lBQzFCLEtBQUssQ0FBQyxJQUFJLENBQ1Isc0JBQWEsQ0FBQyxRQUFRLENBQUM7Z0JBQ3JCLElBQUksRUFBRTtvQkFDSixHQUFHLEVBQUUseUJBQWdCO29CQUNyQixVQUFVLEVBQUUsZ0NBQXVCO29CQUNuQyxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxXQUFXLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7aUJBQ2xEO2FBQ0YsQ0FBQyxDQUNILENBQUM7UUFDSixDQUFDO1FBRUQsSUFDRSxPQUFPLEVBQUUsWUFBWTtZQUNyQixPQUFPLEVBQUUsV0FBVztZQUNwQixJQUFJLENBQUMsT0FBTyxZQUFZLHdCQUFXLEVBQ25DLENBQUM7WUFDRCxLQUFLLENBQUMsSUFBSSxDQUFDO2dCQUNULElBQUksRUFBRSxzQkFBc0I7Z0JBQzVCLEdBQUcsRUFBRSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLGNBQWMsRUFBRTthQUM5QyxDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLEdBQUcsRUFBRSxRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUV6QyxJQUFJLENBQUMsZUFBZSxDQUFDLEVBQUUsRUFBRTtZQUN2QixXQUFXLEVBQUU7Z0JBQ1gsUUFBUSxFQUFFLCtCQUFhLENBQUMsSUFBSTthQUM3QjtZQUNELEtBQUssRUFBRSxPQUFPLEVBQUUsS0FBSztZQUNyQixHQUFHLElBQUEsc0NBQXFCLEVBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsV0FBVyxDQUFDO1lBQy9ELEtBQUs7U0FDTixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRU8sa0JBQWtCLENBQUMsT0FBNkI7UUFDdEQsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsZUFBZSxFQUFFO1lBQ3BDLEdBQUcsSUFBQSxzQ0FBcUIsRUFBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQyxXQUFXLENBQUM7WUFDN0QsV0FBVyxFQUFFO2dCQUNYLFFBQVEsRUFBRSwrQkFBYSxDQUFDLEtBQUs7YUFDOUI7WUFDRCxLQUFLLEVBQUUsQ0FBQyxvQkFBVyxDQUFDO1lBQ3BCLEVBQUUsRUFBRSxlQUFlLGdDQUF1QixPQUFPLGlCQUFRLEVBQUU7WUFDM0QsS0FBSyxFQUFFO2dCQUNMLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxpQkFBaUIsQ0FBQyxVQUFVO2dCQUM3QyxHQUFHLGtDQUFlLENBQUMsaUJBQWlCLENBQUM7b0JBQ25DLHdFQUF3RTtvQkFDeEUsS0FBSyxFQUFFLElBQUksQ0FBQyxRQUFRLENBQUMsaUJBQWlCLENBQUMsUUFBUTtvQkFDL0MsR0FBRyxFQUFFLHlCQUFnQjtvQkFDckIsVUFBVSxFQUFFLGdDQUF1QjtvQkFDbkMsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVztpQkFDN0IsQ0FBQztnQkFDRixzQkFBYSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsV0FBVyxFQUFFLElBQUksQ0FBQyxXQUFXLEVBQUUsQ0FBQztnQkFDakU7b0JBQ0UsSUFBSSxFQUFFLGNBQWM7b0JBQ3BCLEdBQUcsRUFBRTt3QkFDSCxnQkFBZ0IsRUFBaEIseUJBQWdCO3FCQUNqQjtvQkFDRCxHQUFHLEVBQUU7d0JBQ0gsV0FBVzt3QkFDWCx5Q0FBeUM7d0JBQ3pDLDBDQUEwQztxQkFDM0MsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2lCQUNiO2FBQ0Y7U0FDRixDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxnQkFBZ0IsQ0FBQyx5QkFBaUM7UUFDeEQsT0FBTztZQUNMLHNCQUFhLENBQUMsUUFBUSxDQUFDO2dCQUNyQixJQUFJLEVBQUU7b0JBQ0osR0FBRyxFQUFFLHlCQUFnQjtvQkFDckIsVUFBVSxFQUFFLGdDQUF1QjtvQkFDbkMsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUMsQ0FBQyxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO2lCQUNsRDthQUNGLENBQUM7WUFFRixHQUFHLElBQUksQ0FBQyxhQUFhO1lBRXJCO2dCQUNFLElBQUksRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUk7Z0JBQ3pCLEdBQUcsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQzthQUN4RDtZQUVELEdBQUcsSUFBSSxDQUFDLGNBQWM7WUFFdEIsaUVBQWlFO1lBQ2pFLEdBQUcsa0NBQWUsQ0FBQyxjQUFjLENBQUM7Z0JBQ2hDLE1BQU0sRUFBRSwyQkFBa0I7Z0JBQzFCLFVBQVUsRUFBRSxzQ0FBNkI7Z0JBQ3pDLGFBQWEsRUFDWCwwSEFBMEg7YUFDN0gsQ0FBQztZQUVGLDBGQUEwRjtZQUMxRixHQUFHLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxNQUFNLElBQUksQ0FBQztnQkFDakMsQ0FBQyxDQUFDLEVBQUU7Z0JBQ0osQ0FBQyxDQUFDO29CQUNFO3dCQUNFLElBQUksRUFBRSw2QkFBNkI7d0JBQ25DLGVBQWUsRUFBRSxJQUFJO3dCQUNyQixHQUFHLEVBQUUsTUFBTSxJQUFJLENBQUMsa0JBQWtCLHNCQUFzQixrQ0FBc0IsRUFBRTtxQkFDakY7b0JBQ0Qsc0JBQWEsQ0FBQyxjQUFjLENBQUM7d0JBQzNCLElBQUksRUFBRTs0QkFDSixJQUFJLEVBQUUsK0JBQW1COzRCQUN6QixJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNO2dDQUN2QixDQUFDLENBQUMsR0FBRyx5QkFBeUIsSUFBSSxJQUFJLENBQUMsa0JBQWtCLEVBQUU7Z0NBQzNELENBQUMsQ0FBQyxJQUFJLENBQUMsa0JBQWtCO3lCQUM1QjtxQkFDRixDQUFDO2lCQUNILENBQUM7U0FDUCxDQUFDO0lBQ0osQ0FBQzs7QUEvVEgsc0NBZ1VDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0ICogYXMgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHsgVGFzayB9IGZyb20gXCIuLlwiO1xuaW1wb3J0IHsgQ29tcG9uZW50IH0gZnJvbSBcIi4uL2NvbXBvbmVudFwiO1xuaW1wb3J0IHtcbiAgR2l0SHViLFxuICBHaXRodWJXb3JrZmxvdyxcbiAgR2l0SWRlbnRpdHksXG4gIHdvcmtmbG93cyxcbiAgV29ya2Zsb3dTdGVwcyxcbn0gZnJvbSBcIi4uL2dpdGh1YlwiO1xuaW1wb3J0IHtcbiAgQlVJTERfQVJUSUZBQ1RfTkFNRSxcbiAgREVGQVVMVF9HSVRIVUJfQUNUSU9OU19VU0VSLFxuICBQRVJNSVNTSU9OX0JBQ0tVUF9GSUxFLFxufSBmcm9tIFwiLi4vZ2l0aHViL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgZW5zdXJlTm90SGlkZGVuUGF0aCB9IGZyb20gXCIuLi9naXRodWIvcHJpdmF0ZS91dGlsXCI7XG5pbXBvcnQgeyBXb3JrZmxvd0FjdGlvbnMgfSBmcm9tIFwiLi4vZ2l0aHViL3dvcmtmbG93LWFjdGlvbnNcIjtcbmltcG9ydCB7XG4gIEpvYixcbiAgSm9iUGVybWlzc2lvbixcbiAgSm9iUGVybWlzc2lvbnMsXG4gIEpvYlN0ZXAsXG4gIFRvb2xzLFxuICBUcmlnZ2Vycyxcbn0gZnJvbSBcIi4uL2dpdGh1Yi93b3JrZmxvd3MtbW9kZWxcIjtcbmltcG9ydCB7IE5vZGVQcm9qZWN0IH0gZnJvbSBcIi4uL2phdmFzY3JpcHRcIjtcbmltcG9ydCB7IFByb2plY3QgfSBmcm9tIFwiLi4vcHJvamVjdFwiO1xuaW1wb3J0IHsgR3JvdXBSdW5uZXJPcHRpb25zLCBmaWx0ZXJlZFJ1bnNPbk9wdGlvbnMgfSBmcm9tIFwiLi4vcnVubmVyLW9wdGlvbnNcIjtcbmltcG9ydCB7XG4gIEJVSUxEX0pPQklELFxuICBERUZBVUxUX0FSVElGQUNUU19ESVJFQ1RPUlksXG4gIE5PVF9GT1JLLFxuICBQVUxMX1JFUVVFU1RfUkVGLFxuICBQVUxMX1JFUVVFU1RfUkVQT1NJVE9SWSxcbiAgU0VMRl9NVVRBVElPTl9DT05ESVRJT04sXG4gIFNFTEZfTVVUQVRJT05fSEFQUEVORURfT1VUUFVULFxuICBTRUxGX01VVEFUSU9OX1NURVAsXG59IGZyb20gXCIuL3ByaXZhdGUvY29uc3RzXCI7XG5pbXBvcnQgeyB3b3JrZmxvd05hbWVGb3JQcm9qZWN0IH0gZnJvbSBcIi4uL3V0aWwvbmFtZVwiO1xuaW1wb3J0IHsgZW5zdXJlUmVsYXRpdmVQYXRoU3RhcnRzV2l0aERvdCB9IGZyb20gXCIuLi91dGlsL3BhdGhcIjtcblxuZXhwb3J0IGludGVyZmFjZSBCdWlsZFdvcmtmbG93Q29tbW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBOYW1lIG9mIHRoZSBidWlsZGZpbGUgKGUuZy4gXCJidWlsZFwiIGJlY29tZXMgXCJidWlsZC55bWxcIikuXG4gICAqXG4gICAqIEBkZWZhdWx0IFwiYnVpbGRcIlxuICAgKi9cbiAgcmVhZG9ubHkgbmFtZT86IHN0cmluZztcblxuICAvKipcbiAgICogU3RlcHMgdG8gZXhlY3V0ZSBiZWZvcmUgdGhlIGJ1aWxkLlxuICAgKiBAZGVmYXVsdCBbXVxuICAgKi9cbiAgcmVhZG9ubHkgcHJlQnVpbGRTdGVwcz86IEpvYlN0ZXBbXTtcblxuICAvKipcbiAgICogQnVpbGQgd29ya2Zsb3cgdHJpZ2dlcnNcbiAgICogQGRlZmF1bHQgXCJ7IHB1bGxSZXF1ZXN0OiB7fSwgd29ya2Zsb3dEaXNwYXRjaDoge30gfVwiXG4gICAqL1xuICByZWFkb25seSB3b3JrZmxvd1RyaWdnZXJzPzogVHJpZ2dlcnM7XG5cbiAgLyoqXG4gICAqIFBlcm1pc3Npb25zIGdyYW50ZWQgdG8gdGhlIGJ1aWxkIGpvYlxuICAgKiBUbyBsaW1pdCBqb2IgcGVybWlzc2lvbnMgZm9yIGBjb250ZW50c2AsIHRoZSBkZXNpcmVkIHBlcm1pc3Npb25zIGhhdmUgdG8gYmUgZXhwbGljaXRseSBzZXQsIGUuZy46IGB7IGNvbnRlbnRzOiBKb2JQZXJtaXNzaW9uLk5PTkUgfWBcbiAgICogQGRlZmF1bHQgYHsgY29udGVudHM6IEpvYlBlcm1pc3Npb24uV1JJVEUgfWBcbiAgICovXG4gIHJlYWRvbmx5IHBlcm1pc3Npb25zPzogSm9iUGVybWlzc2lvbnM7XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAgICogQGRlZmF1bHQge31cbiAgICovXG4gIHJlYWRvbmx5IGVudj86IHsgW2tleTogc3RyaW5nXTogc3RyaW5nIH07XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQnVpbGRXb3JrZmxvd09wdGlvbnMgZXh0ZW5kcyBCdWlsZFdvcmtmbG93Q29tbW9uT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBUaGUgdGFzayB0byBleGVjdXRlIGluIG9yZGVyIHRvIGJ1aWxkIHRoZSBwcm9qZWN0LlxuICAgKi9cbiAgcmVhZG9ubHkgYnVpbGRUYXNrOiBUYXNrO1xuXG4gIC8qKlxuICAgKiBBIG5hbWUgb2YgYSBkaXJlY3RvcnkgdGhhdCBpbmNsdWRlcyBidWlsZCBhcnRpZmFjdHMuXG4gICAqIEBkZWZhdWx0IFwiZGlzdFwiXG4gICAqL1xuICByZWFkb25seSBhcnRpZmFjdHNEaXJlY3Rvcnk/OiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBjb250YWluZXIgaW1hZ2UgdG8gdXNlIGZvciBidWlsZHMuXG4gICAqIEBkZWZhdWx0IC0gdGhlIGRlZmF1bHQgd29ya2Zsb3cgY29udGFpbmVyXG4gICAqL1xuICByZWFkb25seSBjb250YWluZXJJbWFnZT86IHN0cmluZztcblxuICAvKipcbiAgICogQXV0b21hdGljYWxseSB1cGRhdGUgZmlsZXMgbW9kaWZpZWQgZHVyaW5nIGJ1aWxkcyB0byBwdWxsLXJlcXVlc3QgYnJhbmNoZXMuXG4gICAqIFRoaXMgbWVhbnMgdGhhdCBhbnkgZmlsZXMgc3ludGhlc2l6ZWQgYnkgcHJvamVuIG9yIGUuZy4gdGVzdCBzbmFwc2hvdHMgd2lsbFxuICAgKiBhbHdheXMgYmUgdXAtdG8tZGF0ZSBiZWZvcmUgYSBQUiBpcyBtZXJnZWQuXG4gICAqXG4gICAqIEltcGxpZXMgdGhhdCBQUiBidWlsZHMgZG8gbm90IGhhdmUgYW50aS10YW1wZXIgY2hlY2tzLlxuICAgKlxuICAgKiBUaGlzIGlzIGVuYWJsZWQgYnkgZGVmYXVsdCBvbmx5IGlmIGBnaXRodWJUb2tlblNlY3JldGAgaXMgc2V0LiBPdGhlcndpc2UgaXRcbiAgICogaXMgZGlzYWJsZWQsIHdoaWNoIGltcGxpZXMgdGhhdCBmaWxlIGNoYW5nZXMgdGhhdCBoYXBwZW4gZHVyaW5nIGJ1aWxkIHdpbGxcbiAgICogbm90IGJlIHB1c2hlZCBiYWNrIHRvIHRoZSBicmFuY2guXG4gICAqXG4gICAqIEBkZWZhdWx0IHRydWVcbiAgICovXG4gIHJlYWRvbmx5IG11dGFibGVCdWlsZD86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFN0ZXBzIHRvIGV4ZWN1dGUgYWZ0ZXIgYnVpbGQuXG4gICAqIEBkZWZhdWx0IFtdXG4gICAqL1xuICByZWFkb25seSBwb3N0QnVpbGRTdGVwcz86IEpvYlN0ZXBbXTtcblxuICAvKipcbiAgICogR2l0IGlkZW50aXR5IHRvIHVzZSBmb3IgdGhlIHdvcmtmbG93LlxuICAgKiBAZGVmYXVsdCAtIGRlZmF1bHQgR2l0SHViIEFjdGlvbnMgdXNlclxuICAgKi9cbiAgcmVhZG9ubHkgZ2l0SWRlbnRpdHk/OiBHaXRJZGVudGl0eTtcblxuICAvKipcbiAgICogR2l0aHViIFJ1bm5lciBzZWxlY3Rpb24gbGFiZWxzXG4gICAqIEBkZWZhdWx0IFtcInVidW50dS1sYXRlc3RcIl1cbiAgICogQGRlc2NyaXB0aW9uIERlZmluZXMgYSB0YXJnZXQgUnVubmVyIGJ5IGxhYmVsc1xuICAgKiBAdGhyb3dzIHtFcnJvcn0gaWYgYm90aCBgcnVuc09uYCBhbmQgYHJ1bnNPbkdyb3VwYCBhcmUgc3BlY2lmaWVkXG4gICAqL1xuICByZWFkb25seSBydW5zT24/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogR2l0aHViIFJ1bm5lciBHcm91cCBzZWxlY3Rpb24gb3B0aW9uc1xuICAgKiBAZGVzY3JpcHRpb24gRGVmaW5lcyBhIHRhcmdldCBSdW5uZXIgR3JvdXAgYnkgbmFtZSBhbmQvb3IgbGFiZWxzXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBpZiBib3RoIGBydW5zT25gIGFuZCBgcnVuc09uR3JvdXBgIGFyZSBzcGVjaWZpZWRcbiAgICovXG4gIHJlYWRvbmx5IHJ1bnNPbkdyb3VwPzogR3JvdXBSdW5uZXJPcHRpb25zO1xufVxuXG5leHBvcnQgY2xhc3MgQnVpbGRXb3JrZmxvdyBleHRlbmRzIENvbXBvbmVudCB7XG4gIC8qKlxuICAgKiBOYW1lIG9mIGdlbmVyYXRlZCBnaXRodWIgd29ya2Zsb3dcbiAgICovXG4gIHB1YmxpYyByZWFkb25seSBuYW1lOiBzdHJpbmc7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBwb3N0QnVpbGRTdGVwczogSm9iU3RlcFtdO1xuICBwcml2YXRlIHJlYWRvbmx5IHByZUJ1aWxkU3RlcHM6IEpvYlN0ZXBbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBnaXRJZGVudGl0eTogR2l0SWRlbnRpdHk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYnVpbGRUYXNrOiBUYXNrO1xuICBwcml2YXRlIHJlYWRvbmx5IGdpdGh1YjogR2l0SHViO1xuICBwcml2YXRlIHJlYWRvbmx5IHdvcmtmbG93OiBHaXRodWJXb3JrZmxvdztcbiAgcHJpdmF0ZSByZWFkb25seSBhcnRpZmFjdHNEaXJlY3Rvcnk6IHN0cmluZztcblxuICBwcml2YXRlIHJlYWRvbmx5IF9wb3N0QnVpbGRKb2JzOiBzdHJpbmdbXSA9IFtdO1xuXG4gIGNvbnN0cnVjdG9yKHByb2plY3Q6IFByb2plY3QsIG9wdGlvbnM6IEJ1aWxkV29ya2Zsb3dPcHRpb25zKSB7XG4gICAgc3VwZXIocHJvamVjdCk7XG5cbiAgICBjb25zdCBnaXRodWIgPSBHaXRIdWIub2YodGhpcy5wcm9qZWN0LnJvb3QpO1xuICAgIGlmICghZ2l0aHViKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIFwiQnVpbGRXb3JrZmxvdyBpcyBjdXJyZW50bHkgb25seSBzdXBwb3J0ZWQgZm9yIEdpdEh1YiBwcm9qZWN0c1wiXG4gICAgICApO1xuICAgIH1cblxuICAgIHRoaXMuZ2l0aHViID0gZ2l0aHViO1xuICAgIHRoaXMucHJlQnVpbGRTdGVwcyA9IG9wdGlvbnMucHJlQnVpbGRTdGVwcyA/PyBbXTtcbiAgICB0aGlzLnBvc3RCdWlsZFN0ZXBzID0gb3B0aW9ucy5wb3N0QnVpbGRTdGVwcyA/PyBbXTtcbiAgICB0aGlzLmdpdElkZW50aXR5ID0gb3B0aW9ucy5naXRJZGVudGl0eSA/PyBERUZBVUxUX0dJVEhVQl9BQ1RJT05TX1VTRVI7XG4gICAgdGhpcy5idWlsZFRhc2sgPSBvcHRpb25zLmJ1aWxkVGFzaztcbiAgICB0aGlzLmFydGlmYWN0c0RpcmVjdG9yeSA9XG4gICAgICBvcHRpb25zLmFydGlmYWN0c0RpcmVjdG9yeSA/PyBERUZBVUxUX0FSVElGQUNUU19ESVJFQ1RPUlk7XG4gICAgZW5zdXJlTm90SGlkZGVuUGF0aCh0aGlzLmFydGlmYWN0c0RpcmVjdG9yeSwgXCJhcnRpZmFjdHNEaXJlY3RvcnlcIik7XG4gICAgdGhpcy5uYW1lID0gb3B0aW9ucy5uYW1lID8/IHdvcmtmbG93TmFtZUZvclByb2plY3QoXCJidWlsZFwiLCB0aGlzLnByb2plY3QpO1xuICAgIGNvbnN0IG11dGFibGVCdWlsZHMgPSBvcHRpb25zLm11dGFibGVCdWlsZCA/PyB0cnVlO1xuXG4gICAgdGhpcy53b3JrZmxvdyA9IG5ldyBHaXRodWJXb3JrZmxvdyhnaXRodWIsIHRoaXMubmFtZSk7XG4gICAgdGhpcy53b3JrZmxvdy5vbihcbiAgICAgIG9wdGlvbnMud29ya2Zsb3dUcmlnZ2VycyA/PyB7XG4gICAgICAgIHB1bGxSZXF1ZXN0OiB7fSxcbiAgICAgICAgd29ya2Zsb3dEaXNwYXRjaDoge30sIC8vIGFsbG93IG1hbnVhbCB0cmlnZ2VyaW5nXG4gICAgICB9XG4gICAgKTtcblxuICAgIHRoaXMuYWRkQnVpbGRKb2Iob3B0aW9ucyk7XG5cbiAgICBpZiAobXV0YWJsZUJ1aWxkcykge1xuICAgICAgdGhpcy5hZGRTZWxmTXV0YXRpb25Kb2Iob3B0aW9ucyk7XG4gICAgfVxuXG4gICAgaWYgKHByb2plY3QgaW5zdGFuY2VvZiBOb2RlUHJvamVjdCkge1xuICAgICAgcHJvamVjdC5hZGRQYWNrYWdlSWdub3JlKFBFUk1JU1NJT05fQkFDS1VQX0ZJTEUpO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYWRkQnVpbGRKb2Iob3B0aW9uczogQnVpbGRXb3JrZmxvd09wdGlvbnMpIHtcbiAgICBjb25zdCBwcm9qZWN0UGF0aFJlbGF0aXZlVG9Sb290ID0gcGF0aC5yZWxhdGl2ZShcbiAgICAgIHRoaXMucHJvamVjdC5yb290Lm91dGRpcixcbiAgICAgIHRoaXMucHJvamVjdC5vdXRkaXJcbiAgICApO1xuICAgIGNvbnN0IGpvYkNvbmZpZzogd29ya2Zsb3dzLkpvYiA9IHtcbiAgICAgIC4uLmZpbHRlcmVkUnVuc09uT3B0aW9ucyhvcHRpb25zLnJ1bnNPbiwgb3B0aW9ucy5ydW5zT25Hcm91cCksXG4gICAgICBjb250YWluZXI6IG9wdGlvbnMuY29udGFpbmVySW1hZ2VcbiAgICAgICAgPyB7IGltYWdlOiBvcHRpb25zLmNvbnRhaW5lckltYWdlIH1cbiAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICBlbnY6IHtcbiAgICAgICAgQ0k6IFwidHJ1ZVwiLFxuICAgICAgICAuLi5vcHRpb25zLmVudixcbiAgICAgIH0sXG4gICAgICBwZXJtaXNzaW9uczoge1xuICAgICAgICBjb250ZW50czogSm9iUGVybWlzc2lvbi5XUklURSxcbiAgICAgICAgLi4ub3B0aW9ucy5wZXJtaXNzaW9ucyxcbiAgICAgIH0sXG4gICAgICBkZWZhdWx0czogdGhpcy5wcm9qZWN0LnBhcmVudCAvLyBpcyBzdWJwcm9qZWN0LFxuICAgICAgICA/IHtcbiAgICAgICAgICAgIHJ1bjoge1xuICAgICAgICAgICAgICB3b3JraW5nRGlyZWN0b3J5OiBlbnN1cmVSZWxhdGl2ZVBhdGhTdGFydHNXaXRoRG90KFxuICAgICAgICAgICAgICAgIHByb2plY3RQYXRoUmVsYXRpdmVUb1Jvb3RcbiAgICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgfVxuICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgIHN0ZXBzOiAoKCkgPT4gdGhpcy5yZW5kZXJCdWlsZFN0ZXBzKHByb2plY3RQYXRoUmVsYXRpdmVUb1Jvb3QpKSBhcyBhbnksXG4gICAgICBvdXRwdXRzOiB7XG4gICAgICAgIFtTRUxGX01VVEFUSU9OX0hBUFBFTkVEX09VVFBVVF06IHtcbiAgICAgICAgICBzdGVwSWQ6IFNFTEZfTVVUQVRJT05fU1RFUCxcbiAgICAgICAgICBvdXRwdXROYW1lOiBTRUxGX01VVEFUSU9OX0hBUFBFTkVEX09VVFBVVCxcbiAgICAgICAgfSxcbiAgICAgIH0sXG4gICAgfTtcblxuICAgIHRoaXMud29ya2Zsb3cuYWRkSm9iKEJVSUxEX0pPQklELCBqb2JDb25maWcpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybnMgYSBsaXN0IG9mIGpvYiBJRHMgdGhhdCBhcmUgcGFydCBvZiB0aGUgYnVpbGQuXG4gICAqL1xuICBwdWJsaWMgZ2V0IGJ1aWxkSm9iSWRzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gW0JVSUxEX0pPQklELCAuLi50aGlzLl9wb3N0QnVpbGRKb2JzXTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIHN0ZXBzIHRoYXQgYXJlIGV4ZWN1dGVkIGFmdGVyIHRoZSBidWlsZC5cbiAgICogQHBhcmFtIHN0ZXBzIFRoZSBqb2Igc3RlcHNcbiAgICovXG4gIHB1YmxpYyBhZGRQb3N0QnVpbGRTdGVwcyguLi5zdGVwczogSm9iU3RlcFtdKTogdm9pZCB7XG4gICAgdGhpcy5wb3N0QnVpbGRTdGVwcy5wdXNoKC4uLnN0ZXBzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGRzIGFub3RoZXIgam9iIHRvIHRoZSBidWlsZCB3b3JrZmxvdyB3aGljaCBpcyBleGVjdXRlZCBhZnRlciB0aGUgYnVpbGRcbiAgICogam9iIHN1Y2NlZWRlZC5cbiAgICpcbiAgICogSm9icyBhcmUgZXhlY3V0ZWQgX29ubHlfIGlmIHRoZSBidWlsZCBkaWQgTk9UIHNlbGYgbXV0YXRlLiBJZiB0aGUgYnVpbGRcbiAgICogc2VsZi1tdXRhdGUsIHRoZSBicmFuY2ggd2lsbCBlaXRoZXIgYmUgdXBkYXRlZCBvciB0aGUgYnVpbGQgd2lsbCBmYWlsIChpblxuICAgKiBmb3JrcyksIHNvIHRoZXJlIGlzIG5vIHBvaW50IGluIGV4ZWN1dGluZyB0aGUgcG9zdC1idWlsZCBqb2IuXG4gICAqXG4gICAqIEBwYXJhbSBpZCBUaGUgaWQgb2YgdGhlIG5ldyBqb2JcbiAgICogQHBhcmFtIGpvYiBUaGUgam9iIHNwZWNpZmljYXRpb25cbiAgICovXG4gIHB1YmxpYyBhZGRQb3N0QnVpbGRKb2IoaWQ6IHN0cmluZywgam9iOiBKb2IpIHtcbiAgICBjb25zdCBzdGVwcyA9IFtdO1xuXG4gICAgc3RlcHMucHVzaChcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJEb3dubG9hZCBidWlsZCBhcnRpZmFjdHNcIixcbiAgICAgICAgdXNlczogXCJhY3Rpb25zL2Rvd25sb2FkLWFydGlmYWN0QHY1XCIsXG4gICAgICAgIHdpdGg6IHtcbiAgICAgICAgICBuYW1lOiBCVUlMRF9BUlRJRkFDVF9OQU1FLFxuICAgICAgICAgIHBhdGg6IHRoaXMuYXJ0aWZhY3RzRGlyZWN0b3J5LFxuICAgICAgICB9LFxuICAgICAgfSxcbiAgICAgIHtcbiAgICAgICAgbmFtZTogXCJSZXN0b3JlIGJ1aWxkIGFydGlmYWN0IHBlcm1pc3Npb25zXCIsXG4gICAgICAgIGNvbnRpbnVlT25FcnJvcjogdHJ1ZSxcbiAgICAgICAgcnVuOiBbXG4gICAgICAgICAgYGNkICR7dGhpcy5hcnRpZmFjdHNEaXJlY3Rvcnl9ICYmIHNldGZhY2wgLS1yZXN0b3JlPSR7UEVSTUlTU0lPTl9CQUNLVVBfRklMRX1gLFxuICAgICAgICBdLmpvaW4oXCJcXG5cIiksXG4gICAgICB9XG4gICAgKTtcblxuICAgIHN0ZXBzLnB1c2goLi4uKGpvYi5zdGVwcyA/PyBbXSkpO1xuXG4gICAgdGhpcy53b3JrZmxvdy5hZGRKb2IoaWQsIHtcbiAgICAgIG5lZWRzOiBbQlVJTERfSk9CSURdLFxuICAgICAgLy8gb25seSBydW4gaWYgYnVpbGQgZGlkIG5vdCBzZWxmLW11dGF0ZVxuICAgICAgaWY6IGBcXCR7eyAhJHtTRUxGX01VVEFUSU9OX0NPTkRJVElPTn0gfX1gLFxuICAgICAgLi4uam9iLFxuICAgICAgc3RlcHM6IHN0ZXBzLFxuICAgIH0pO1xuXG4gICAgLy8gYWRkIHRvIHRoZSBsaXN0IG9mIGJ1aWxkIGpvYiBJRHNcbiAgICB0aGlzLl9wb3N0QnVpbGRKb2JzLnB1c2goaWQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJ1biBhIHRhc2sgYXMgYSBqb2Igd2l0aGluIHRoZSBidWlsZCB3b3JrZmxvdyB3aGljaCBpcyBleGVjdXRlZCBhZnRlciB0aGVcbiAgICogYnVpbGQgam9iIHN1Y2NlZWRlZC5cbiAgICpcbiAgICogVGhlIGpvYiB3aWxsIGhhdmUgYWNjZXNzIHRvIGJ1aWxkIGFydGlmYWN0cyBhbmQgd2lsbCBpbnN0YWxsIHByb2plY3RcbiAgICogZGVwZW5kZW5jaWVzIGluIG9yZGVyIHRvIGJlIGFibGUgdG8gcnVuIGFueSBjb21tYW5kcyB1c2VkIGluIHRoZSB0YXNrcy5cbiAgICpcbiAgICogSm9icyBhcmUgZXhlY3V0ZWQgX29ubHlfIGlmIHRoZSBidWlsZCBkaWQgTk9UIHNlbGYgbXV0YXRlLiBJZiB0aGUgYnVpbGRcbiAgICogc2VsZi1tdXRhdGUsIHRoZSBicmFuY2ggd2lsbCBlaXRoZXIgYmUgdXBkYXRlZCBvciB0aGUgYnVpbGQgd2lsbCBmYWlsIChpblxuICAgKiBmb3JrcyksIHNvIHRoZXJlIGlzIG5vIHBvaW50IGluIGV4ZWN1dGluZyB0aGUgcG9zdC1idWlsZCBqb2IuXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zIFNwZWNpZnkgdG9vbHMgYW5kIG90aGVyIG9wdGlvbnNcbiAgICovXG4gIHB1YmxpYyBhZGRQb3N0QnVpbGRKb2JUYXNrKFxuICAgIHRhc2s6IFRhc2ssXG4gICAgb3B0aW9uczogQWRkUG9zdEJ1aWxkSm9iVGFza09wdGlvbnMgPSB7fVxuICApIHtcbiAgICB0aGlzLmFkZFBvc3RCdWlsZEpvYkNvbW1hbmRzKFxuICAgICAgYHBvc3QtYnVpbGQtJHt0YXNrLm5hbWV9YCxcbiAgICAgIFtgJHt0aGlzLnByb2plY3QucHJvamVuQ29tbWFuZH0gJHt0YXNrLm5hbWV9YF0sXG4gICAgICB7XG4gICAgICAgIGNoZWNrb3V0UmVwbzogdHJ1ZSxcbiAgICAgICAgaW5zdGFsbERlcHM6IHRydWUsXG4gICAgICAgIHRvb2xzOiBvcHRpb25zLnRvb2xzLFxuICAgICAgICAuLi5maWx0ZXJlZFJ1bnNPbk9wdGlvbnMob3B0aW9ucy5ydW5zT24sIG9wdGlvbnMucnVuc09uR3JvdXApLFxuICAgICAgfVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogUnVuIGEgc2VxdWVuY2Ugb2YgY29tbWFuZHMgYXMgYSBqb2Igd2l0aGluIHRoZSBidWlsZCB3b3JrZmxvdyB3aGljaCBpc1xuICAgKiBleGVjdXRlZCBhZnRlciB0aGUgYnVpbGQgam9iIHN1Y2NlZWRlZC5cbiAgICpcbiAgICogSm9icyBhcmUgZXhlY3V0ZWQgX29ubHlfIGlmIHRoZSBidWlsZCBkaWQgTk9UIHNlbGYgbXV0YXRlLiBJZiB0aGUgYnVpbGRcbiAgICogc2VsZi1tdXRhdGUsIHRoZSBicmFuY2ggd2lsbCBlaXRoZXIgYmUgdXBkYXRlZCBvciB0aGUgYnVpbGQgd2lsbCBmYWlsIChpblxuICAgKiBmb3JrcyksIHNvIHRoZXJlIGlzIG5vIHBvaW50IGluIGV4ZWN1dGluZyB0aGUgcG9zdC1idWlsZCBqb2IuXG4gICAqXG4gICAqIEBwYXJhbSBvcHRpb25zIFNwZWNpZnkgdG9vbHMgYW5kIG90aGVyIG9wdGlvbnNcbiAgICovXG4gIHB1YmxpYyBhZGRQb3N0QnVpbGRKb2JDb21tYW5kcyhcbiAgICBpZDogc3RyaW5nLFxuICAgIGNvbW1hbmRzOiBzdHJpbmdbXSxcbiAgICBvcHRpb25zPzogQWRkUG9zdEJ1aWxkSm9iQ29tbWFuZHNPcHRpb25zXG4gICkge1xuICAgIGNvbnN0IHN0ZXBzID0gW107XG5cbiAgICBpZiAob3B0aW9ucz8uY2hlY2tvdXRSZXBvKSB7XG4gICAgICBzdGVwcy5wdXNoKFxuICAgICAgICBXb3JrZmxvd1N0ZXBzLmNoZWNrb3V0KHtcbiAgICAgICAgICB3aXRoOiB7XG4gICAgICAgICAgICByZWY6IFBVTExfUkVRVUVTVF9SRUYsXG4gICAgICAgICAgICByZXBvc2l0b3J5OiBQVUxMX1JFUVVFU1RfUkVQT1NJVE9SWSxcbiAgICAgICAgICAgIC4uLih0aGlzLmdpdGh1Yi5kb3dubG9hZExmcyA/IHsgbGZzOiB0cnVlIH0gOiB7fSksXG4gICAgICAgICAgfSxcbiAgICAgICAgfSlcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgb3B0aW9ucz8uY2hlY2tvdXRSZXBvICYmXG4gICAgICBvcHRpb25zPy5pbnN0YWxsRGVwcyAmJlxuICAgICAgdGhpcy5wcm9qZWN0IGluc3RhbmNlb2YgTm9kZVByb2plY3RcbiAgICApIHtcbiAgICAgIHN0ZXBzLnB1c2goe1xuICAgICAgICBuYW1lOiBcIkluc3RhbGwgZGVwZW5kZW5jaWVzXCIsXG4gICAgICAgIHJ1bjogYCR7dGhpcy5wcm9qZWN0LnBhY2thZ2UuaW5zdGFsbENvbW1hbmR9YCxcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0ZXBzLnB1c2goeyBydW46IGNvbW1hbmRzLmpvaW4oXCJcXG5cIikgfSk7XG5cbiAgICB0aGlzLmFkZFBvc3RCdWlsZEpvYihpZCwge1xuICAgICAgcGVybWlzc2lvbnM6IHtcbiAgICAgICAgY29udGVudHM6IEpvYlBlcm1pc3Npb24uUkVBRCxcbiAgICAgIH0sXG4gICAgICB0b29sczogb3B0aW9ucz8udG9vbHMsXG4gICAgICAuLi5maWx0ZXJlZFJ1bnNPbk9wdGlvbnMob3B0aW9ucz8ucnVuc09uLCBvcHRpb25zPy5ydW5zT25Hcm91cCksXG4gICAgICBzdGVwcyxcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgYWRkU2VsZk11dGF0aW9uSm9iKG9wdGlvbnM6IEJ1aWxkV29ya2Zsb3dPcHRpb25zKSB7XG4gICAgdGhpcy53b3JrZmxvdy5hZGRKb2IoXCJzZWxmLW11dGF0aW9uXCIsIHtcbiAgICAgIC4uLmZpbHRlcmVkUnVuc09uT3B0aW9ucyhvcHRpb25zLnJ1bnNPbiwgb3B0aW9ucy5ydW5zT25Hcm91cCksXG4gICAgICBwZXJtaXNzaW9uczoge1xuICAgICAgICBjb250ZW50czogSm9iUGVybWlzc2lvbi5XUklURSxcbiAgICAgIH0sXG4gICAgICBuZWVkczogW0JVSUxEX0pPQklEXSxcbiAgICAgIGlmOiBgYWx3YXlzKCkgJiYgJHtTRUxGX01VVEFUSU9OX0NPTkRJVElPTn0gJiYgJHtOT1RfRk9SS31gLFxuICAgICAgc3RlcHM6IFtcbiAgICAgICAgLi4udGhpcy53b3JrZmxvdy5wcm9qZW5DcmVkZW50aWFscy5zZXR1cFN0ZXBzLFxuICAgICAgICAuLi5Xb3JrZmxvd0FjdGlvbnMuY2hlY2tvdXRXaXRoUGF0Y2goe1xuICAgICAgICAgIC8vIHdlIG5lZWQgdG8gdXNlIGEgUEFUIHNvIHRoYXQgb3VyIHB1c2ggd2lsbCB0cmlnZ2VyIHRoZSBidWlsZCB3b3JrZmxvd1xuICAgICAgICAgIHRva2VuOiB0aGlzLndvcmtmbG93LnByb2plbkNyZWRlbnRpYWxzLnRva2VuUmVmLFxuICAgICAgICAgIHJlZjogUFVMTF9SRVFVRVNUX1JFRixcbiAgICAgICAgICByZXBvc2l0b3J5OiBQVUxMX1JFUVVFU1RfUkVQT1NJVE9SWSxcbiAgICAgICAgICBsZnM6IHRoaXMuZ2l0aHViLmRvd25sb2FkTGZzLFxuICAgICAgICB9KSxcbiAgICAgICAgV29ya2Zsb3dTdGVwcy5zZXR1cEdpdElkZW50aXR5KHsgZ2l0SWRlbnRpdHk6IHRoaXMuZ2l0SWRlbnRpdHkgfSksXG4gICAgICAgIHtcbiAgICAgICAgICBuYW1lOiBcIlB1c2ggY2hhbmdlc1wiLFxuICAgICAgICAgIGVudjoge1xuICAgICAgICAgICAgUFVMTF9SRVFVRVNUX1JFRixcbiAgICAgICAgICB9LFxuICAgICAgICAgIHJ1bjogW1xuICAgICAgICAgICAgXCJnaXQgYWRkIC5cIixcbiAgICAgICAgICAgICdnaXQgY29tbWl0IC1zIC1tIFwiY2hvcmU6IHNlbGYgbXV0YXRpb25cIicsXG4gICAgICAgICAgICBgZ2l0IHB1c2ggb3JpZ2luIFwiSEVBRDokUFVMTF9SRVFVRVNUX1JFRlwiYCxcbiAgICAgICAgICBdLmpvaW4oXCJcXG5cIiksXG4gICAgICAgIH0sXG4gICAgICBdLFxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIENhbGxlZCAobGF6aWx5KSBkdXJpbmcgc3ludGggdG8gcmVuZGVyIHRoZSBidWlsZCBqb2Igc3RlcHMuXG4gICAqL1xuICBwcml2YXRlIHJlbmRlckJ1aWxkU3RlcHMocHJvamVjdFBhdGhSZWxhdGl2ZVRvUm9vdDogc3RyaW5nKTogSm9iU3RlcFtdIHtcbiAgICByZXR1cm4gW1xuICAgICAgV29ya2Zsb3dTdGVwcy5jaGVja291dCh7XG4gICAgICAgIHdpdGg6IHtcbiAgICAgICAgICByZWY6IFBVTExfUkVRVUVTVF9SRUYsXG4gICAgICAgICAgcmVwb3NpdG9yeTogUFVMTF9SRVFVRVNUX1JFUE9TSVRPUlksXG4gICAgICAgICAgLi4uKHRoaXMuZ2l0aHViLmRvd25sb2FkTGZzID8geyBsZnM6IHRydWUgfSA6IHt9KSxcbiAgICAgICAgfSxcbiAgICAgIH0pLFxuXG4gICAgICAuLi50aGlzLnByZUJ1aWxkU3RlcHMsXG5cbiAgICAgIHtcbiAgICAgICAgbmFtZTogdGhpcy5idWlsZFRhc2submFtZSxcbiAgICAgICAgcnVuOiB0aGlzLmdpdGh1Yi5wcm9qZWN0LnJ1blRhc2tDb21tYW5kKHRoaXMuYnVpbGRUYXNrKSxcbiAgICAgIH0sXG5cbiAgICAgIC4uLnRoaXMucG9zdEJ1aWxkU3RlcHMsXG5cbiAgICAgIC8vIGNoZWNrIGZvciBtdXRhdGlvbnMgYW5kIHVwbG9hZCBhIGdpdCBwYXRjaCBmaWxlIGFzIGFuIGFydGlmYWN0XG4gICAgICAuLi5Xb3JrZmxvd0FjdGlvbnMudXBsb2FkR2l0UGF0Y2goe1xuICAgICAgICBzdGVwSWQ6IFNFTEZfTVVUQVRJT05fU1RFUCxcbiAgICAgICAgb3V0cHV0TmFtZTogU0VMRl9NVVRBVElPTl9IQVBQRU5FRF9PVVRQVVQsXG4gICAgICAgIG11dGF0aW9uRXJyb3I6XG4gICAgICAgICAgXCJGaWxlcyB3ZXJlIGNoYW5nZWQgZHVyaW5nIGJ1aWxkIChzZWUgYnVpbGQgbG9nKS4gSWYgdGhpcyB3YXMgdHJpZ2dlcmVkIGZyb20gYSBmb3JrLCB5b3Ugd2lsbCBuZWVkIHRvIHVwZGF0ZSB5b3VyIGJyYW5jaC5cIixcbiAgICAgIH0pLFxuXG4gICAgICAvLyB1cGxvYWQgdGhlIGJ1aWxkIGFydGlmYWN0IG9ubHkgaWYgd2UgaGF2ZSBwb3N0LWJ1aWxkIGpvYnMgKG90aGVyd2lzZSwgdGhlcmUncyBubyBwb2ludClcbiAgICAgIC4uLih0aGlzLl9wb3N0QnVpbGRKb2JzLmxlbmd0aCA9PSAwXG4gICAgICAgID8gW11cbiAgICAgICAgOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIG5hbWU6IFwiQmFja3VwIGFydGlmYWN0IHBlcm1pc3Npb25zXCIsXG4gICAgICAgICAgICAgIGNvbnRpbnVlT25FcnJvcjogdHJ1ZSxcbiAgICAgICAgICAgICAgcnVuOiBgY2QgJHt0aGlzLmFydGlmYWN0c0RpcmVjdG9yeX0gJiYgZ2V0ZmFjbCAtUiAuID4gJHtQRVJNSVNTSU9OX0JBQ0tVUF9GSUxFfWAsXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgV29ya2Zsb3dTdGVwcy51cGxvYWRBcnRpZmFjdCh7XG4gICAgICAgICAgICAgIHdpdGg6IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBCVUlMRF9BUlRJRkFDVF9OQU1FLFxuICAgICAgICAgICAgICAgIHBhdGg6IHRoaXMucHJvamVjdC5wYXJlbnRcbiAgICAgICAgICAgICAgICAgID8gYCR7cHJvamVjdFBhdGhSZWxhdGl2ZVRvUm9vdH0vJHt0aGlzLmFydGlmYWN0c0RpcmVjdG9yeX1gXG4gICAgICAgICAgICAgICAgICA6IHRoaXMuYXJ0aWZhY3RzRGlyZWN0b3J5LFxuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgXSksXG4gICAgXTtcbiAgfVxufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIGBCdWlsZFdvcmtmbG93LmFkZFBvc3RCdWlsZEpvYlRhc2tgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQWRkUG9zdEJ1aWxkSm9iVGFza09wdGlvbnMge1xuICAvKipcbiAgICogVG9vbHMgdGhhdCBzaG91bGQgYmUgaW5zdGFsbGVkIGJlZm9yZSB0aGUgdGFzayBpcyBydW4uXG4gICAqL1xuICByZWFkb25seSB0b29scz86IFRvb2xzO1xuXG4gIC8qKlxuICAgKiBHaXRodWIgUnVubmVyIHNlbGVjdGlvbiBsYWJlbHNcbiAgICogQGRlZmF1bHQgW1widWJ1bnR1LWxhdGVzdFwiXVxuICAgKiBAZGVzY3JpcHRpb24gRGVmaW5lcyBhIHRhcmdldCBSdW5uZXIgYnkgbGFiZWxzXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBpZiBib3RoIGBydW5zT25gIGFuZCBgcnVuc09uR3JvdXBgIGFyZSBzcGVjaWZpZWRcbiAgICovXG4gIHJlYWRvbmx5IHJ1bnNPbj86IHN0cmluZ1tdO1xuXG4gIC8qKlxuICAgKiBHaXRodWIgUnVubmVyIEdyb3VwIHNlbGVjdGlvbiBvcHRpb25zXG4gICAqIEBkZXNjcmlwdGlvbiBEZWZpbmVzIGEgdGFyZ2V0IFJ1bm5lciBHcm91cCBieSBuYW1lIGFuZC9vciBsYWJlbHNcbiAgICogQHRocm93cyB7RXJyb3J9IGlmIGJvdGggYHJ1bnNPbmAgYW5kIGBydW5zT25Hcm91cGAgYXJlIHNwZWNpZmllZFxuICAgKi9cbiAgcmVhZG9ubHkgcnVuc09uR3JvdXA/OiBHcm91cFJ1bm5lck9wdGlvbnM7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYEJ1aWxkV29ya2Zsb3cuYWRkUG9zdEJ1aWxkSm9iQ29tbWFuZHNgXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQWRkUG9zdEJ1aWxkSm9iQ29tbWFuZHNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRvb2xzIHRoYXQgc2hvdWxkIGJlIGluc3RhbGxlZCBiZWZvcmUgdGhlIGNvbW1hbmRzIGFyZSBydW4uXG4gICAqL1xuICByZWFkb25seSB0b29scz86IFRvb2xzO1xuXG4gIC8qKlxuICAgKiBDaGVjayBvdXQgdGhlIHJlcG9zaXRvcnkgYXQgdGhlIHB1bGwgcmVxdWVzdCBicmFuY2ggYmVmb3JlIGNvbW1hbmRzIGFyZVxuICAgKiBydW4uXG4gICAqXG4gICAqIEBkZWZhdWx0IGZhbHNlXG4gICAqL1xuICByZWFkb25seSBjaGVja291dFJlcG8/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBJbnN0YWxsIHByb2plY3QgZGVwZW5kZW5jaWVzIGJlZm9yZSBydW5uaW5nIGNvbW1hbmRzLiBgY2hlY2tvdXRSZXBvYCBtdXN0XG4gICAqIGFsc28gYmUgc2V0IHRvIHRydWUuXG4gICAqXG4gICAqIEN1cnJlbnRseSBvbmx5IHN1cHBvcnRlZCBmb3IgYE5vZGVQcm9qZWN0YC5cbiAgICpcbiAgICogQGRlZmF1bHQgZmFsc2VcbiAgICovXG4gIHJlYWRvbmx5IGluc3RhbGxEZXBzPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogR2l0aHViIFJ1bm5lciBzZWxlY3Rpb24gbGFiZWxzXG4gICAqIEBkZWZhdWx0IFtcInVidW50dS1sYXRlc3RcIl1cbiAgICogQGRlc2NyaXB0aW9uIERlZmluZXMgYSB0YXJnZXQgUnVubmVyIGJ5IGxhYmVsc1xuICAgKiBAdGhyb3dzIHtFcnJvcn0gaWYgYm90aCBgcnVuc09uYCBhbmQgYHJ1bnNPbkdyb3VwYCBhcmUgc3BlY2lmaWVkXG4gICAqL1xuICByZWFkb25seSBydW5zT24/OiBzdHJpbmdbXTtcblxuICAvKipcbiAgICogR2l0aHViIFJ1bm5lciBHcm91cCBzZWxlY3Rpb24gb3B0aW9uc1xuICAgKiBAZGVzY3JpcHRpb24gRGVmaW5lcyBhIHRhcmdldCBSdW5uZXIgR3JvdXAgYnkgbmFtZSBhbmQvb3IgbGFiZWxzXG4gICAqIEB0aHJvd3Mge0Vycm9yfSBpZiBib3RoIGBydW5zT25gIGFuZCBgcnVuc09uR3JvdXBgIGFyZSBzcGVjaWZpZWRcbiAgICovXG4gIHJlYWRvbmx5IHJ1bnNPbkdyb3VwPzogR3JvdXBSdW5uZXJPcHRpb25zO1xufVxuIl19