gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
224 lines • 35 kB
JavaScript
import chalk from "chalk";
import deepExtend from "deep-extend";
import assert, { AssertionError } from "assert";
import { Job } from "./job.js";
import { traverse } from "object-traversal";
import { Utils } from "./utils.js";
const extendsMaxDepth = 11;
const extendsRecurse = (gitlabData, jobName, jobData, parents, depth) => {
assert(depth < extendsMaxDepth, chalk `{blueBright ${jobName}}: circular dependency detected in \`extends\``);
depth++;
jobData.extends = typeof jobData.extends === "string" ? [jobData.extends] : jobData.extends;
jobData.extends = jobData.extends ?? [];
for (const parentName of jobData.extends) {
const parentData = gitlabData[parentName];
assert(parentData != null, chalk `{blueBright ${parentName}} is unspecified, used by {blueBright ${jobName}} extends`);
extendsRecurse(gitlabData, parentName, parentData, parents, depth);
parents.push(parentData);
}
return parents;
};
export function jobExtends(gitlabData) {
for (const [jobName, jobData] of Object.entries(gitlabData)) {
if (Job.illegalJobNames.has(jobName))
continue;
if (!Utils.isObject(jobData))
continue;
const parentDatas = extendsRecurse(gitlabData, jobName, jobData, [], 0);
gitlabData[jobName] = deepExtend({}, ...parentDatas, jobData);
}
for (const [jobName, jobData] of Object.entries(gitlabData)) {
if (Job.illegalJobNames.has(jobName))
continue;
if (!Utils.isObject(jobData))
continue;
delete jobData.extends;
}
}
export function reference(gitlabData, recurseData) {
for (const [key, value] of Object.entries(recurseData || {})) {
if (value?.referenceData) {
if (Object.keys(value).length > 1) {
recurseData[key] = { ...getSubDataByReference(gitlabData, value.referenceData), ...recurseData[key] };
delete recurseData[key].referenceData;
}
else {
recurseData[key] = getSubDataByReference(gitlabData, value.referenceData);
}
}
else if (typeof value === "object") {
reference(gitlabData, value);
}
if (hasCircularChain(recurseData)) {
throw new AssertionError({ message: `!reference circular chain detected [${value.referenceData}]` });
}
}
}
const getSubDataByReference = (gitlabData, referenceData) => {
let gitlabSubData = gitlabData;
referenceData.forEach((referencePointer) => {
assert(gitlabSubData[referencePointer] != null, `!reference [${referenceData.join(", ")}] is undefined`);
gitlabSubData = gitlabSubData[referencePointer];
});
return gitlabSubData;
};
function hasCircularChain(data) {
try {
JSON.stringify(data);
}
catch (e) {
if (e instanceof TypeError && e.message.startsWith("Converting circular structure to JSON")) {
return true;
}
}
return false;
}
/**
Transform the globally defined ["image", "services", "cache", "before_script", "after_script"] into the default.x syntax
https://docs.gitlab.com/ee/ci/yaml/index.html#globally-defined-image-services-cache-before_script-after_script
*/
export function transformDeprecatedGlobalDefaultSyntax(gitlabData) {
const GITLAB_DEPRECATED_GLOBALLY_DEFINED_KEYWORDS = ["image", "services", "cache", "before_script", "after_script"];
gitlabData.default = gitlabData.default ?? {};
for (const g of GITLAB_DEPRECATED_GLOBALLY_DEFINED_KEYWORDS) {
if (gitlabData[g] !== undefined) {
gitlabData.default[g] = gitlabData[g];
delete gitlabData[g]; // Since this is deprecated, deleting it to prevent us from using it internally
}
}
}
export function normalize(gitlabData) {
normalizeGlobalVariables(gitlabData);
for (const [jobName, jobData] of Object.entries(gitlabData)) {
if (Job.illegalJobNames.has(jobName) || jobName.startsWith("."))
continue;
needsEach(jobName, gitlabData);
cacheEach(jobName, gitlabData);
servicesEach(jobName, gitlabData);
imageEach(jobName, gitlabData);
jobData.after_script = (typeof jobData.after_script === "string" && jobData.after_script !== "") ? [jobData.after_script] : jobData.after_script;
jobData.before_script = (typeof jobData.before_script === "string" && jobData.before_script !== "") ? [jobData.before_script] : jobData.before_script;
jobData.script = (typeof jobData.script === "string" && jobData.script !== "") ? [jobData.script] : jobData.script;
}
}
export function needsComplex(data) {
const needs = {
job: data.job ?? data,
artifacts: data.artifacts ?? true,
...(data.pipeline ? { pipeline: data.pipeline } : {}),
...(data.project ? { project: data.project } : {}),
...(data.ref ? { ref: data.ref } : {}),
...(data.optional ? { optional: data.optional } : {}),
};
// In needs:project/needs:pipeline, `optional` is not an allowed property
if (!data.project && !data.pipeline && data.optional === undefined) {
needs.optional = false;
}
return needs;
}
export function needsEach(jobName, gitlabData) {
const jobData = gitlabData[jobName];
if (!jobData.needs)
return;
for (const [i, n] of Object.entries(jobData.needs)) {
jobData.needs[i] = needsComplex(n);
}
}
export function cacheComplex(data) {
return {
key: data.key,
paths: data.paths,
policy: data.policy ?? "pull-push",
when: data.when ?? "on_success",
};
}
export function cacheEach(jobName, gitlabData) {
const jobData = gitlabData[jobName];
const cache = jobData.cache;
if (!cache)
return;
jobData.cache = Array.isArray(cache) ? cache : [cache];
for (const [i, c] of Object.entries(jobData.cache)) {
if (c.key?.files instanceof Array) {
assert(c.key.files.length === 1 || c.key.files.length === 2, `cache:key:files should be an array of one or two file paths. Got ${c.key.files.length}`);
}
jobData.cache[i] = cacheComplex(c);
}
// Remove cache elements with empty paths array (gitlab.com works the same way.)
jobData.cache = jobData.cache.filter((c) => c.paths?.length !== undefined);
}
export function servicesComplex(data) {
return {
name: typeof data === "string" ? data : data.name,
entrypoint: data.entrypoint,
command: data.command,
alias: data.alias,
variables: data.variables,
};
}
export function servicesEach(jobName, gitlabData) {
const jobData = gitlabData[jobName];
const services = jobData.services;
if (!services)
return;
jobData.services = Array.isArray(services) ? services : [services];
for (const [i, s] of Object.entries(jobData.services)) {
jobData.services[i] = servicesComplex(s);
}
}
export function imageComplex(data) {
if (data == null)
return data;
return {
name: typeof data === "string" ? data : data.name,
entrypoint: data.entrypoint,
...(data.docker?.user ? { docker: { user: data.docker?.user } } : {}),
};
}
export function imageEach(jobName, gitlabData) {
const jobData = gitlabData[jobName];
const image = jobData.image;
if (!image)
return;
jobData.image = imageComplex(jobData.image);
}
export function inheritDefault(gitlabData) {
for (const [jobName, jobData] of Object.entries(gitlabData)) {
if (jobData.inherit?.default === false)
continue;
if (Job.illegalJobNames.has(jobName) || jobName.startsWith(".")) {
// skip hidden jobs as they might just contain shared yaml
// see https://github.com/firecow/gitlab-ci-local/issues/1277
continue;
}
const keywordsToInheritFrom = (Array.isArray(jobData.inherit?.default)) ?
jobData.inherit.default :
["artifacts", "cache", "services", "image", "before_script", "after_script"];
for (const keyword of keywordsToInheritFrom) {
if (gitlabData.default[keyword] !== undefined)
jobData[keyword] = jobData[keyword] ?? gitlabData.default[keyword];
}
}
}
function normalizeGlobalVariables(gitlabData) {
for (const [key, value] of Object.entries(gitlabData.variables ?? {})) {
if (value === null) {
gitlabData.variables[key] = ""; // variable's values are nullable
}
else if (Utils.isObject(value)) {
gitlabData.variables[key] = String(value["value"]);
}
else {
gitlabData.variables[key] = String(value);
}
}
}
export function flattenLists(gitlabData) {
traverse(gitlabData, ({ parent, key, value, meta }) => {
if (parent != null && key != null && Array.isArray(value)) {
parent[key] = value.flat(9);
assert(!parent[key].some(Array.isArray), chalk `This Gitlab CI configuration is invalid: {blueBright ${meta.nodePath}} config should be string or a nested array of strings up to 10 level deep`);
}
}, { cycleHandling: true });
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1leHBhbmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRhdGEtZXhwYW5kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sVUFBVSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLE1BQU0sRUFBRSxFQUFDLGNBQWMsRUFBQyxNQUFNLFFBQVEsQ0FBQztBQUM5QyxPQUFPLEVBQUMsR0FBRyxFQUFPLE1BQU0sVUFBVSxDQUFDO0FBQ25DLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQyxPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBRWpDLE1BQU0sZUFBZSxHQUFHLEVBQUUsQ0FBQztBQUMzQixNQUFNLGNBQWMsR0FBRyxDQUFDLFVBQWUsRUFBRSxPQUFlLEVBQUUsT0FBWSxFQUFFLE9BQWMsRUFBRSxLQUFhLEVBQUUsRUFBRTtJQUNyRyxNQUFNLENBQUMsS0FBSyxHQUFHLGVBQWUsRUFBRSxLQUFLLENBQUEsZUFBZSxPQUFPLGdEQUFnRCxDQUFDLENBQUM7SUFDN0csS0FBSyxFQUFFLENBQUM7SUFFUixPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sT0FBTyxDQUFDLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO0lBQzVGLE9BQU8sQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7SUFFeEMsS0FBSyxNQUFNLFVBQVUsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDdkMsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sQ0FBQyxVQUFVLElBQUksSUFBSSxFQUFFLEtBQUssQ0FBQSxlQUFlLFVBQVUseUNBQXlDLE9BQU8sV0FBVyxDQUFDLENBQUM7UUFDdEgsY0FBYyxDQUFDLFVBQVUsRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNuRSxPQUFPLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBQzdCLENBQUM7SUFDRCxPQUFPLE9BQU8sQ0FBQztBQUNuQixDQUFDLENBQUM7QUFFRixNQUFNLFVBQVUsVUFBVSxDQUFFLFVBQWU7SUFDdkMsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvRCxJQUFJLEdBQUcsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQztZQUFFLFNBQVM7UUFDL0MsSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO1lBQUUsU0FBUztRQUN2QyxNQUFNLFdBQVcsR0FBRyxjQUFjLENBQUMsVUFBVSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQ3hFLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBRyxVQUFVLENBQUMsRUFBRSxFQUFFLEdBQUcsV0FBVyxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ2xFLENBQUM7SUFFRCxLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBTSxVQUFVLENBQUMsRUFBRSxDQUFDO1FBQy9ELElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDO1lBQUUsU0FBUztRQUMvQyxJQUFJLENBQUMsS0FBSyxDQUFDLFFBQVEsQ0FBQyxPQUFPLENBQUM7WUFBRSxTQUFTO1FBQ3ZDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQztJQUMzQixDQUFDO0FBQ0wsQ0FBQztBQUVELE1BQU0sVUFBVSxTQUFTLENBQUUsVUFBZSxFQUFFLFdBQWdCO0lBQ3hELEtBQUssTUFBTSxDQUFDLEdBQUcsRUFBRSxLQUFLLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFNLFdBQVcsSUFBSSxFQUFFLENBQUMsRUFBRSxDQUFDO1FBQ2hFLElBQUksS0FBSyxFQUFFLGFBQWEsRUFBRSxDQUFDO1lBQ3ZCLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ2hDLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFDLEdBQUcscUJBQXFCLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxhQUFhLENBQUMsRUFBRSxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsRUFBQyxDQUFDO2dCQUNwRyxPQUFPLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxhQUFhLENBQUM7WUFDMUMsQ0FBQztpQkFBTSxDQUFDO2dCQUNKLFdBQVcsQ0FBQyxHQUFHLENBQUMsR0FBRyxxQkFBcUIsQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1lBQzlFLENBQUM7UUFDTCxDQUFDO2FBQU0sSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNuQyxTQUFTLENBQUMsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ2pDLENBQUM7UUFFRCxJQUFJLGdCQUFnQixDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7WUFDaEMsTUFBTSxJQUFJLGNBQWMsQ0FBQyxFQUFDLE9BQU8sRUFBRSx1Q0FBdUMsS0FBSyxDQUFDLGFBQWEsR0FBRyxFQUFDLENBQUMsQ0FBQztRQUN2RyxDQUFDO0lBQ0wsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLHFCQUFxQixHQUFHLENBQUMsVUFBZSxFQUFFLGFBQXVCLEVBQUUsRUFBRTtJQUN2RSxJQUFJLGFBQWEsR0FBRyxVQUFVLENBQUM7SUFDL0IsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDLGdCQUFnQixFQUFFLEVBQUU7UUFDdkMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLElBQUksRUFBRSxlQUFlLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDekcsYUFBYSxHQUFHLGFBQWEsQ0FBQyxnQkFBZ0IsQ0FBQyxDQUFDO0lBQ3BELENBQUMsQ0FBQyxDQUFDO0lBQ0gsT0FBTyxhQUFhLENBQUM7QUFDekIsQ0FBQyxDQUFDO0FBRUYsU0FBUyxnQkFBZ0IsQ0FBRSxJQUFTO0lBQ2hDLElBQUksQ0FBQztRQUNELElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekIsQ0FBQztJQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDVCxJQUFJLENBQUMsWUFBWSxTQUFTLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsdUNBQXVDLENBQUMsRUFBRSxDQUFDO1lBQzFGLE9BQU8sSUFBSSxDQUFDO1FBQ2hCLENBQUM7SUFDTCxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDakIsQ0FBQztBQUVEOzs7RUFHRTtBQUNGLE1BQU0sVUFBVSxzQ0FBc0MsQ0FBRSxVQUFlO0lBQ25FLE1BQU0sMkNBQTJDLEdBQUcsQ0FBQyxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sRUFBRSxlQUFlLEVBQUUsY0FBYyxDQUFDLENBQUM7SUFFcEgsVUFBVSxDQUFDLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxJQUFJLEVBQUUsQ0FBQztJQUM5QyxLQUFLLE1BQU0sQ0FBQyxJQUFJLDJDQUEyQyxFQUFFLENBQUM7UUFDMUQsSUFBSSxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDOUIsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsR0FBRyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDdEMsT0FBTyxVQUFVLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQywrRUFBK0U7UUFDekcsQ0FBQztJQUNMLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxVQUFVLFNBQVMsQ0FBRSxVQUFlO0lBQ3RDLHdCQUF3QixDQUFDLFVBQVUsQ0FBQyxDQUFDO0lBRXJDLEtBQUssTUFBTSxDQUFDLE9BQU8sRUFBRSxPQUFPLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFNLFVBQVUsQ0FBQyxFQUFFLENBQUM7UUFDL0QsSUFBSSxHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztZQUFFLFNBQVM7UUFDMUUsU0FBUyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUMvQixTQUFTLENBQUMsT0FBTyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBQy9CLFlBQVksQ0FBQyxPQUFPLEVBQUUsVUFBVSxDQUFDLENBQUM7UUFDbEMsU0FBUyxDQUFDLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztRQUUvQixPQUFPLENBQUMsWUFBWSxHQUFHLENBQUMsT0FBTyxPQUFPLENBQUMsWUFBWSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsWUFBWSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQztRQUNqSixPQUFPLENBQUMsYUFBYSxHQUFHLENBQUMsT0FBTyxPQUFPLENBQUMsYUFBYSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsYUFBYSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxhQUFhLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLGFBQWEsQ0FBQztRQUN0SixPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsT0FBTyxPQUFPLENBQUMsTUFBTSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUN2SCxDQUFDO0FBQ0wsQ0FBQztBQUVELE1BQU0sVUFBVSxZQUFZLENBQUUsSUFBUztJQUNuQyxNQUFNLEtBQUssR0FBUztRQUNoQixHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsSUFBSSxJQUFJO1FBQ3JCLFNBQVMsRUFBRSxJQUFJLENBQUMsU0FBUyxJQUFJLElBQUk7UUFDakMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ25ELEdBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxFQUFDLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTyxFQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUNoRCxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUcsRUFBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDcEMsR0FBRyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3RELENBQUM7SUFFRix5RUFBeUU7SUFDekUsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUMsUUFBUSxJQUFJLElBQUksQ0FBQyxRQUFRLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDakUsS0FBSyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUM7SUFDM0IsQ0FBQztJQUNELE9BQU8sS0FBSyxDQUFDO0FBQ2pCLENBQUM7QUFFRCxNQUFNLFVBQVUsU0FBUyxDQUFFLE9BQWUsRUFBRSxVQUFlO0lBQ3ZELE1BQU0sT0FBTyxHQUFHLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNwQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUs7UUFBRSxPQUFPO0lBRTNCLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFNLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3RELE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEdBQUcsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQ3ZDLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBRSxJQUFTO0lBQ25DLE9BQU87UUFDSCxHQUFHLEVBQUUsSUFBSSxDQUFDLEdBQUc7UUFDYixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7UUFDakIsTUFBTSxFQUFFLElBQUksQ0FBQyxNQUFNLElBQUksV0FBVztRQUNsQyxJQUFJLEVBQUUsSUFBSSxDQUFDLElBQUksSUFBSSxZQUFZO0tBQ2xDLENBQUM7QUFDTixDQUFDO0FBRUQsTUFBTSxVQUFVLFNBQVMsQ0FBRSxPQUFlLEVBQUUsVUFBZTtJQUN2RCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztJQUM1QixJQUFJLENBQUMsS0FBSztRQUFFLE9BQU87SUFFbkIsT0FBTyxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkQsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDdEQsSUFBSSxDQUFDLENBQUMsR0FBRyxFQUFFLEtBQUssWUFBWSxLQUFLLEVBQUUsQ0FBQztZQUNoQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFLG9FQUFvRSxDQUFDLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1FBQzNKLENBQUM7UUFDRCxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxHQUFHLFlBQVksQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN2QyxDQUFDO0lBRUQsZ0ZBQWdGO0lBQ2hGLE9BQU8sQ0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFNLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLEVBQUUsTUFBTSxLQUFLLFNBQVMsQ0FBQyxDQUFDO0FBQ3BGLENBQUM7QUFFRCxNQUFNLFVBQVUsZUFBZSxDQUFFLElBQVM7SUFDdEMsT0FBTztRQUNILElBQUksRUFBRSxPQUFPLElBQUksS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsSUFBSSxDQUFDLElBQUk7UUFDakQsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVO1FBQzNCLE9BQU8sRUFBRSxJQUFJLENBQUMsT0FBTztRQUNyQixLQUFLLEVBQUUsSUFBSSxDQUFDLEtBQUs7UUFDakIsU0FBUyxFQUFFLElBQUksQ0FBQyxTQUFTO0tBQzVCLENBQUM7QUFDTixDQUFDO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBRSxPQUFlLEVBQUUsVUFBZTtJQUMxRCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEMsTUFBTSxRQUFRLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQztJQUNsQyxJQUFJLENBQUMsUUFBUTtRQUFFLE9BQU87SUFFdEIsT0FBTyxDQUFDLFFBQVEsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsUUFBUSxDQUFDLENBQUM7SUFFbkUsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7UUFDekQsT0FBTyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsR0FBRyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDN0MsQ0FBQztBQUNMLENBQUM7QUFFRCxNQUFNLFVBQVUsWUFBWSxDQUFFLElBQVM7SUFDbkMsSUFBSSxJQUFJLElBQUksSUFBSTtRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzlCLE9BQU87UUFDSCxJQUFJLEVBQUUsT0FBTyxJQUFJLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJO1FBQ2pELFVBQVUsRUFBRSxJQUFJLENBQUMsVUFBVTtRQUMzQixHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUMsTUFBTSxFQUFFLEVBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxNQUFNLEVBQUUsSUFBSSxFQUFDLEVBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0tBQ3BFLENBQUM7QUFDTixDQUFDO0FBRUQsTUFBTSxVQUFVLFNBQVMsQ0FBRSxPQUFlLEVBQUUsVUFBZTtJQUN2RCxNQUFNLE9BQU8sR0FBRyxVQUFVLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDcEMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQztJQUM1QixJQUFJLENBQUMsS0FBSztRQUFFLE9BQU87SUFFbkIsT0FBTyxDQUFDLEtBQUssR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ2hELENBQUM7QUFFRCxNQUFNLFVBQVUsY0FBYyxDQUFFLFVBQWU7SUFDM0MsS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQU0sVUFBVSxDQUFDLEVBQUUsQ0FBQztRQUMvRCxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsT0FBTyxLQUFLLEtBQUs7WUFBRSxTQUFTO1FBRWpELElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQzlELDBEQUEwRDtZQUMxRCw2REFBNkQ7WUFDN0QsU0FBUztRQUNiLENBQUM7UUFFRCxNQUFNLHFCQUFxQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUNyRSxPQUFPLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ3pCLENBQUMsV0FBVyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsT0FBTyxFQUFFLGVBQWUsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUVqRixLQUFLLE1BQU0sT0FBTyxJQUFJLHFCQUFxQixFQUFFLENBQUM7WUFDMUMsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxLQUFLLFNBQVM7Z0JBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxVQUFVLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ3RILENBQUM7SUFDTCxDQUFDO0FBQ0wsQ0FBQztBQUVELFNBQVMsd0JBQXdCLENBQUUsVUFBZTtJQUM5QyxLQUFLLE1BQU0sQ0FBQyxHQUFHLEVBQUUsS0FBSyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBTSxVQUFVLENBQUMsU0FBUyxJQUFJLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDekUsSUFBSSxLQUFLLEtBQUssSUFBSSxFQUFFLENBQUM7WUFDakIsVUFBVSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxpQ0FBaUM7UUFDckUsQ0FBQzthQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQy9CLFVBQVUsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDO1FBQ3ZELENBQUM7YUFBTSxDQUFDO1lBQ0osVUFBVSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsR0FBRyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUMsQ0FBQztJQUNMLENBQUM7QUFDTCxDQUFDO0FBRUQsTUFBTSxVQUFVLFlBQVksQ0FBRSxVQUFlO0lBQ3pDLFFBQVEsQ0FBQyxVQUFVLEVBQUUsQ0FBQyxFQUFDLE1BQU0sRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBQyxFQUFFLEVBQUU7UUFDaEQsSUFBSSxNQUFNLElBQUksSUFBSSxJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3hELE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzVCLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssQ0FBQSx3REFBd0QsSUFBSSxDQUFDLFFBQVEsNEVBQTRFLENBQUMsQ0FBQztRQUNyTSxDQUFDO0lBQ0wsQ0FBQyxFQUFFLEVBQUMsYUFBYSxFQUFFLElBQUksRUFBQyxDQUFDLENBQUM7QUFDOUIsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjaGFsayBmcm9tIFwiY2hhbGtcIjtcbmltcG9ydCBkZWVwRXh0ZW5kIGZyb20gXCJkZWVwLWV4dGVuZFwiO1xuaW1wb3J0IGFzc2VydCwge0Fzc2VydGlvbkVycm9yfSBmcm9tIFwiYXNzZXJ0XCI7XG5pbXBvcnQge0pvYiwgTmVlZH0gZnJvbSBcIi4vam9iLmpzXCI7XG5pbXBvcnQge3RyYXZlcnNlfSBmcm9tIFwib2JqZWN0LXRyYXZlcnNhbFwiO1xuaW1wb3J0IHtVdGlsc30gZnJvbSBcIi4vdXRpbHMuanNcIjtcblxuY29uc3QgZXh0ZW5kc01heERlcHRoID0gMTE7XG5jb25zdCBleHRlbmRzUmVjdXJzZSA9IChnaXRsYWJEYXRhOiBhbnksIGpvYk5hbWU6IHN0cmluZywgam9iRGF0YTogYW55LCBwYXJlbnRzOiBhbnlbXSwgZGVwdGg6IG51bWJlcikgPT4ge1xuICAgIGFzc2VydChkZXB0aCA8IGV4dGVuZHNNYXhEZXB0aCwgY2hhbGtge2JsdWVCcmlnaHQgJHtqb2JOYW1lfX06IGNpcmN1bGFyIGRlcGVuZGVuY3kgZGV0ZWN0ZWQgaW4gXFxgZXh0ZW5kc1xcYGApO1xuICAgIGRlcHRoKys7XG5cbiAgICBqb2JEYXRhLmV4dGVuZHMgPSB0eXBlb2Ygam9iRGF0YS5leHRlbmRzID09PSBcInN0cmluZ1wiID8gW2pvYkRhdGEuZXh0ZW5kc10gOiBqb2JEYXRhLmV4dGVuZHM7XG4gICAgam9iRGF0YS5leHRlbmRzID0gam9iRGF0YS5leHRlbmRzID8/IFtdO1xuXG4gICAgZm9yIChjb25zdCBwYXJlbnROYW1lIG9mIGpvYkRhdGEuZXh0ZW5kcykge1xuICAgICAgICBjb25zdCBwYXJlbnREYXRhID0gZ2l0bGFiRGF0YVtwYXJlbnROYW1lXTtcbiAgICAgICAgYXNzZXJ0KHBhcmVudERhdGEgIT0gbnVsbCwgY2hhbGtge2JsdWVCcmlnaHQgJHtwYXJlbnROYW1lfX0gaXMgdW5zcGVjaWZpZWQsIHVzZWQgYnkge2JsdWVCcmlnaHQgJHtqb2JOYW1lfX0gZXh0ZW5kc2ApO1xuICAgICAgICBleHRlbmRzUmVjdXJzZShnaXRsYWJEYXRhLCBwYXJlbnROYW1lLCBwYXJlbnREYXRhLCBwYXJlbnRzLCBkZXB0aCk7XG4gICAgICAgIHBhcmVudHMucHVzaChwYXJlbnREYXRhKTtcbiAgICB9XG4gICAgcmV0dXJuIHBhcmVudHM7XG59O1xuXG5leHBvcnQgZnVuY3Rpb24gam9iRXh0ZW5kcyAoZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhKSkge1xuICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkpIGNvbnRpbnVlO1xuICAgICAgICBpZiAoIVV0aWxzLmlzT2JqZWN0KGpvYkRhdGEpKSBjb250aW51ZTtcbiAgICAgICAgY29uc3QgcGFyZW50RGF0YXMgPSBleHRlbmRzUmVjdXJzZShnaXRsYWJEYXRhLCBqb2JOYW1lLCBqb2JEYXRhLCBbXSwgMCk7XG4gICAgICAgIGdpdGxhYkRhdGFbam9iTmFtZV0gPSBkZWVwRXh0ZW5kKHt9LCAuLi5wYXJlbnREYXRhcywgam9iRGF0YSk7XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhKSkge1xuICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkpIGNvbnRpbnVlO1xuICAgICAgICBpZiAoIVV0aWxzLmlzT2JqZWN0KGpvYkRhdGEpKSBjb250aW51ZTtcbiAgICAgICAgZGVsZXRlIGpvYkRhdGEuZXh0ZW5kcztcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZWZlcmVuY2UgKGdpdGxhYkRhdGE6IGFueSwgcmVjdXJzZURhdGE6IGFueSkge1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4ocmVjdXJzZURhdGEgfHwge30pKSB7XG4gICAgICAgIGlmICh2YWx1ZT8ucmVmZXJlbmNlRGF0YSkge1xuICAgICAgICAgICAgaWYgKE9iamVjdC5rZXlzKHZhbHVlKS5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgcmVjdXJzZURhdGFba2V5XSA9IHsuLi5nZXRTdWJEYXRhQnlSZWZlcmVuY2UoZ2l0bGFiRGF0YSwgdmFsdWUucmVmZXJlbmNlRGF0YSksIC4uLnJlY3Vyc2VEYXRhW2tleV19O1xuICAgICAgICAgICAgICAgIGRlbGV0ZSByZWN1cnNlRGF0YVtrZXldLnJlZmVyZW5jZURhdGE7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHJlY3Vyc2VEYXRhW2tleV0gPSBnZXRTdWJEYXRhQnlSZWZlcmVuY2UoZ2l0bGFiRGF0YSwgdmFsdWUucmVmZXJlbmNlRGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICByZWZlcmVuY2UoZ2l0bGFiRGF0YSwgdmFsdWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGhhc0NpcmN1bGFyQ2hhaW4ocmVjdXJzZURhdGEpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgQXNzZXJ0aW9uRXJyb3Ioe21lc3NhZ2U6IGAhcmVmZXJlbmNlIGNpcmN1bGFyIGNoYWluIGRldGVjdGVkIFske3ZhbHVlLnJlZmVyZW5jZURhdGF9XWB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuY29uc3QgZ2V0U3ViRGF0YUJ5UmVmZXJlbmNlID0gKGdpdGxhYkRhdGE6IGFueSwgcmVmZXJlbmNlRGF0YTogc3RyaW5nW10pID0+IHtcbiAgICBsZXQgZ2l0bGFiU3ViRGF0YSA9IGdpdGxhYkRhdGE7XG4gICAgcmVmZXJlbmNlRGF0YS5mb3JFYWNoKChyZWZlcmVuY2VQb2ludGVyKSA9PiB7XG4gICAgICAgIGFzc2VydChnaXRsYWJTdWJEYXRhW3JlZmVyZW5jZVBvaW50ZXJdICE9IG51bGwsIGAhcmVmZXJlbmNlIFske3JlZmVyZW5jZURhdGEuam9pbihcIiwgXCIpfV0gaXMgdW5kZWZpbmVkYCk7XG4gICAgICAgIGdpdGxhYlN1YkRhdGEgPSBnaXRsYWJTdWJEYXRhW3JlZmVyZW5jZVBvaW50ZXJdO1xuICAgIH0pO1xuICAgIHJldHVybiBnaXRsYWJTdWJEYXRhO1xufTtcblxuZnVuY3Rpb24gaGFzQ2lyY3VsYXJDaGFpbiAoZGF0YTogYW55KSB7XG4gICAgdHJ5IHtcbiAgICAgICAgSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBpZiAoZSBpbnN0YW5jZW9mIFR5cGVFcnJvciAmJiBlLm1lc3NhZ2Uuc3RhcnRzV2l0aChcIkNvbnZlcnRpbmcgY2lyY3VsYXIgc3RydWN0dXJlIHRvIEpTT05cIikpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gIFRyYW5zZm9ybSB0aGUgZ2xvYmFsbHkgZGVmaW5lZCBbXCJpbWFnZVwiLCBcInNlcnZpY2VzXCIsIFwiY2FjaGVcIiwgXCJiZWZvcmVfc2NyaXB0XCIsIFwiYWZ0ZXJfc2NyaXB0XCJdIGludG8gdGhlIGRlZmF1bHQueCBzeW50YXhcbiAgaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvY2kveWFtbC9pbmRleC5odG1sI2dsb2JhbGx5LWRlZmluZWQtaW1hZ2Utc2VydmljZXMtY2FjaGUtYmVmb3JlX3NjcmlwdC1hZnRlcl9zY3JpcHRcbiovXG5leHBvcnQgZnVuY3Rpb24gdHJhbnNmb3JtRGVwcmVjYXRlZEdsb2JhbERlZmF1bHRTeW50YXggKGdpdGxhYkRhdGE6IGFueSkge1xuICAgIGNvbnN0IEdJVExBQl9ERVBSRUNBVEVEX0dMT0JBTExZX0RFRklORURfS0VZV09SRFMgPSBbXCJpbWFnZVwiLCBcInNlcnZpY2VzXCIsIFwiY2FjaGVcIiwgXCJiZWZvcmVfc2NyaXB0XCIsIFwiYWZ0ZXJfc2NyaXB0XCJdO1xuXG4gICAgZ2l0bGFiRGF0YS5kZWZhdWx0ID0gZ2l0bGFiRGF0YS5kZWZhdWx0ID8/IHt9O1xuICAgIGZvciAoY29uc3QgZyBvZiBHSVRMQUJfREVQUkVDQVRFRF9HTE9CQUxMWV9ERUZJTkVEX0tFWVdPUkRTKSB7XG4gICAgICAgIGlmIChnaXRsYWJEYXRhW2ddICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGdpdGxhYkRhdGEuZGVmYXVsdFtnXSA9IGdpdGxhYkRhdGFbZ107XG4gICAgICAgICAgICBkZWxldGUgZ2l0bGFiRGF0YVtnXTsgLy8gU2luY2UgdGhpcyBpcyBkZXByZWNhdGVkLCBkZWxldGluZyBpdCB0byBwcmV2ZW50IHVzIGZyb20gdXNpbmcgaXQgaW50ZXJuYWxseVxuICAgICAgICB9XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbm9ybWFsaXplIChnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBub3JtYWxpemVHbG9iYWxWYXJpYWJsZXMoZ2l0bGFiRGF0YSk7XG5cbiAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSB8fCBqb2JOYW1lLnN0YXJ0c1dpdGgoXCIuXCIpKSBjb250aW51ZTtcbiAgICAgICAgbmVlZHNFYWNoKGpvYk5hbWUsIGdpdGxhYkRhdGEpO1xuICAgICAgICBjYWNoZUVhY2goam9iTmFtZSwgZ2l0bGFiRGF0YSk7XG4gICAgICAgIHNlcnZpY2VzRWFjaChqb2JOYW1lLCBnaXRsYWJEYXRhKTtcbiAgICAgICAgaW1hZ2VFYWNoKGpvYk5hbWUsIGdpdGxhYkRhdGEpO1xuXG4gICAgICAgIGpvYkRhdGEuYWZ0ZXJfc2NyaXB0ID0gKHR5cGVvZiBqb2JEYXRhLmFmdGVyX3NjcmlwdCA9PT0gXCJzdHJpbmdcIiAmJiBqb2JEYXRhLmFmdGVyX3NjcmlwdCAhPT0gXCJcIikgPyBbam9iRGF0YS5hZnRlcl9zY3JpcHRdIDogam9iRGF0YS5hZnRlcl9zY3JpcHQ7XG4gICAgICAgIGpvYkRhdGEuYmVmb3JlX3NjcmlwdCA9ICh0eXBlb2Ygam9iRGF0YS5iZWZvcmVfc2NyaXB0ID09PSBcInN0cmluZ1wiICYmIGpvYkRhdGEuYmVmb3JlX3NjcmlwdCAhPT0gXCJcIikgPyBbam9iRGF0YS5iZWZvcmVfc2NyaXB0XSA6IGpvYkRhdGEuYmVmb3JlX3NjcmlwdDtcbiAgICAgICAgam9iRGF0YS5zY3JpcHQgPSAodHlwZW9mIGpvYkRhdGEuc2NyaXB0ID09PSBcInN0cmluZ1wiICYmIGpvYkRhdGEuc2NyaXB0ICE9PSBcIlwiKSA/IFtqb2JEYXRhLnNjcmlwdF0gOiBqb2JEYXRhLnNjcmlwdDtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBuZWVkc0NvbXBsZXggKGRhdGE6IGFueSkge1xuICAgIGNvbnN0IG5lZWRzOiBOZWVkID0ge1xuICAgICAgICBqb2I6IGRhdGEuam9iID8/IGRhdGEsXG4gICAgICAgIGFydGlmYWN0czogZGF0YS5hcnRpZmFjdHMgPz8gdHJ1ZSxcbiAgICAgICAgLi4uKGRhdGEucGlwZWxpbmUgPyB7cGlwZWxpbmU6IGRhdGEucGlwZWxpbmV9IDoge30pLFxuICAgICAgICAuLi4oZGF0YS5wcm9qZWN0ID8ge3Byb2plY3Q6IGRhdGEucHJvamVjdH0gOiB7fSksXG4gICAgICAgIC4uLihkYXRhLnJlZiA/IHtyZWY6IGRhdGEucmVmfSA6IHt9KSxcbiAgICAgICAgLi4uKGRhdGEub3B0aW9uYWwgPyB7b3B0aW9uYWw6IGRhdGEub3B0aW9uYWx9IDoge30pLFxuICAgIH07XG5cbiAgICAvLyBJbiBuZWVkczpwcm9qZWN0L25lZWRzOnBpcGVsaW5lLCBgb3B0aW9uYWxgIGlzIG5vdCBhbiBhbGxvd2VkIHByb3BlcnR5XG4gICAgaWYgKCFkYXRhLnByb2plY3QgJiYgIWRhdGEucGlwZWxpbmUgJiYgZGF0YS5vcHRpb25hbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIG5lZWRzLm9wdGlvbmFsID0gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiBuZWVkcztcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5lZWRzRWFjaCAoam9iTmFtZTogc3RyaW5nLCBnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBjb25zdCBqb2JEYXRhID0gZ2l0bGFiRGF0YVtqb2JOYW1lXTtcbiAgICBpZiAoIWpvYkRhdGEubmVlZHMpIHJldHVybjtcblxuICAgIGZvciAoY29uc3QgW2ksIG5dIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oam9iRGF0YS5uZWVkcykpIHtcbiAgICAgICAgam9iRGF0YS5uZWVkc1tpXSA9IG5lZWRzQ29tcGxleChuKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYWNoZUNvbXBsZXggKGRhdGE6IGFueSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIGtleTogZGF0YS5rZXksXG4gICAgICAgIHBhdGhzOiBkYXRhLnBhdGhzLFxuICAgICAgICBwb2xpY3k6IGRhdGEucG9saWN5ID8/IFwicHVsbC1wdXNoXCIsXG4gICAgICAgIHdoZW46IGRhdGEud2hlbiA/PyBcIm9uX3N1Y2Nlc3NcIixcbiAgICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FjaGVFYWNoIChqb2JOYW1lOiBzdHJpbmcsIGdpdGxhYkRhdGE6IGFueSkge1xuICAgIGNvbnN0IGpvYkRhdGEgPSBnaXRsYWJEYXRhW2pvYk5hbWVdO1xuICAgIGNvbnN0IGNhY2hlID0gam9iRGF0YS5jYWNoZTtcbiAgICBpZiAoIWNhY2hlKSByZXR1cm47XG5cbiAgICBqb2JEYXRhLmNhY2hlID0gQXJyYXkuaXNBcnJheShjYWNoZSkgPyBjYWNoZSA6IFtjYWNoZV07XG4gICAgZm9yIChjb25zdCBbaSwgY10gb2YgT2JqZWN0LmVudHJpZXM8YW55Pihqb2JEYXRhLmNhY2hlKSkge1xuICAgICAgICBpZiAoYy5rZXk/LmZpbGVzIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgIGFzc2VydChjLmtleS5maWxlcy5sZW5ndGggPT09IDEgfHwgYy5rZXkuZmlsZXMubGVuZ3RoID09PSAyLCBgY2FjaGU6a2V5OmZpbGVzIHNob3VsZCBiZSBhbiBhcnJheSBvZiBvbmUgb3IgdHdvIGZpbGUgcGF0aHMuIEdvdCAke2Mua2V5LmZpbGVzLmxlbmd0aH1gKTtcbiAgICAgICAgfVxuICAgICAgICBqb2JEYXRhLmNhY2hlW2ldID0gY2FjaGVDb21wbGV4KGMpO1xuICAgIH1cblxuICAgIC8vIFJlbW92ZSBjYWNoZSBlbGVtZW50cyB3aXRoIGVtcHR5IHBhdGhzIGFycmF5IChnaXRsYWIuY29tIHdvcmtzIHRoZSBzYW1lIHdheS4pXG4gICAgam9iRGF0YS5jYWNoZSA9IGpvYkRhdGEuY2FjaGUuZmlsdGVyKChjOiBhbnkpID0+IGMucGF0aHM/Lmxlbmd0aCAhPT0gdW5kZWZpbmVkKTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNlcnZpY2VzQ29tcGxleCAoZGF0YTogYW55KSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogdHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgPyBkYXRhIDogZGF0YS5uYW1lLFxuICAgICAgICBlbnRyeXBvaW50OiBkYXRhLmVudHJ5cG9pbnQsXG4gICAgICAgIGNvbW1hbmQ6IGRhdGEuY29tbWFuZCxcbiAgICAgICAgYWxpYXM6IGRhdGEuYWxpYXMsXG4gICAgICAgIHZhcmlhYmxlczogZGF0YS52YXJpYWJsZXMsXG4gICAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNlcnZpY2VzRWFjaCAoam9iTmFtZTogc3RyaW5nLCBnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBjb25zdCBqb2JEYXRhID0gZ2l0bGFiRGF0YVtqb2JOYW1lXTtcbiAgICBjb25zdCBzZXJ2aWNlcyA9IGpvYkRhdGEuc2VydmljZXM7XG4gICAgaWYgKCFzZXJ2aWNlcykgcmV0dXJuO1xuXG4gICAgam9iRGF0YS5zZXJ2aWNlcyA9IEFycmF5LmlzQXJyYXkoc2VydmljZXMpID8gc2VydmljZXMgOiBbc2VydmljZXNdO1xuXG4gICAgZm9yIChjb25zdCBbaSwgc10gb2YgT2JqZWN0LmVudHJpZXM8YW55Pihqb2JEYXRhLnNlcnZpY2VzKSkge1xuICAgICAgICBqb2JEYXRhLnNlcnZpY2VzW2ldID0gc2VydmljZXNDb21wbGV4KHMpO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGltYWdlQ29tcGxleCAoZGF0YTogYW55KSB7XG4gICAgaWYgKGRhdGEgPT0gbnVsbCkgcmV0dXJuIGRhdGE7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgbmFtZTogdHlwZW9mIGRhdGEgPT09IFwic3RyaW5nXCIgPyBkYXRhIDogZGF0YS5uYW1lLFxuICAgICAgICBlbnRyeXBvaW50OiBkYXRhLmVudHJ5cG9pbnQsXG4gICAgICAgIC4uLihkYXRhLmRvY2tlcj8udXNlciA/IHtkb2NrZXI6IHt1c2VyOiBkYXRhLmRvY2tlcj8udXNlcn19IDoge30pLFxuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpbWFnZUVhY2ggKGpvYk5hbWU6IHN0cmluZywgZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgY29uc3Qgam9iRGF0YSA9IGdpdGxhYkRhdGFbam9iTmFtZV07XG4gICAgY29uc3QgaW1hZ2UgPSBqb2JEYXRhLmltYWdlO1xuICAgIGlmICghaW1hZ2UpIHJldHVybjtcblxuICAgIGpvYkRhdGEuaW1hZ2UgPSBpbWFnZUNvbXBsZXgoam9iRGF0YS5pbWFnZSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpbmhlcml0RGVmYXVsdCAoZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhKSkge1xuICAgICAgICBpZiAoam9iRGF0YS5pbmhlcml0Py5kZWZhdWx0ID09PSBmYWxzZSkgY29udGludWU7XG5cbiAgICAgICAgaWYgKEpvYi5pbGxlZ2FsSm9iTmFtZXMuaGFzKGpvYk5hbWUpIHx8IGpvYk5hbWUuc3RhcnRzV2l0aChcIi5cIikpIHtcbiAgICAgICAgICAgIC8vIHNraXAgaGlkZGVuIGpvYnMgYXMgdGhleSBtaWdodCBqdXN0IGNvbnRhaW4gc2hhcmVkIHlhbWxcbiAgICAgICAgICAgIC8vIHNlZSBodHRwczovL2dpdGh1Yi5jb20vZmlyZWNvdy9naXRsYWItY2ktbG9jYWwvaXNzdWVzLzEyNzdcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgY29uc3Qga2V5d29yZHNUb0luaGVyaXRGcm9tID0gKEFycmF5LmlzQXJyYXkoam9iRGF0YS5pbmhlcml0Py5kZWZhdWx0KSkgP1xuICAgICAgICAgICAgam9iRGF0YS5pbmhlcml0LmRlZmF1bHQgOlxuICAgICAgICAgICAgW1wiYXJ0aWZhY3RzXCIsIFwiY2FjaGVcIiwgXCJzZXJ2aWNlc1wiLCBcImltYWdlXCIsIFwiYmVmb3JlX3NjcmlwdFwiLCBcImFmdGVyX3NjcmlwdFwiXTtcblxuICAgICAgICBmb3IgKGNvbnN0IGtleXdvcmQgb2Yga2V5d29yZHNUb0luaGVyaXRGcm9tKSB7XG4gICAgICAgICAgICBpZiAoZ2l0bGFiRGF0YS5kZWZhdWx0W2tleXdvcmRdICE9PSB1bmRlZmluZWQpIGpvYkRhdGFba2V5d29yZF0gPSBqb2JEYXRhW2tleXdvcmRdID8/IGdpdGxhYkRhdGEuZGVmYXVsdFtrZXl3b3JkXTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplR2xvYmFsVmFyaWFibGVzIChnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEudmFyaWFibGVzID8/IHt9KSkge1xuICAgICAgICBpZiAodmFsdWUgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGdpdGxhYkRhdGEudmFyaWFibGVzW2tleV0gPSBcIlwiOyAvLyB2YXJpYWJsZSdzIHZhbHVlcyBhcmUgbnVsbGFibGVcbiAgICAgICAgfSBlbHNlIGlmIChVdGlscy5pc09iamVjdCh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGdpdGxhYkRhdGEudmFyaWFibGVzW2tleV0gPSBTdHJpbmcodmFsdWVbXCJ2YWx1ZVwiXSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBnaXRsYWJEYXRhLnZhcmlhYmxlc1trZXldID0gU3RyaW5nKHZhbHVlKTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGZsYXR0ZW5MaXN0cyAoZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgdHJhdmVyc2UoZ2l0bGFiRGF0YSwgKHtwYXJlbnQsIGtleSwgdmFsdWUsIG1ldGF9KSA9PiB7XG4gICAgICAgIGlmIChwYXJlbnQgIT0gbnVsbCAmJiBrZXkgIT0gbnVsbCAmJiBBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgcGFyZW50W2tleV0gPSB2YWx1ZS5mbGF0KDkpO1xuICAgICAgICAgICAgYXNzZXJ0KCFwYXJlbnRba2V5XS5zb21lKEFycmF5LmlzQXJyYXkpLCBjaGFsa2BUaGlzIEdpdGxhYiBDSSBjb25maWd1cmF0aW9uIGlzIGludmFsaWQ6IHtibHVlQnJpZ2h0ICR7bWV0YS5ub2RlUGF0aH19IGNvbmZpZyBzaG91bGQgYmUgc3RyaW5nIG9yIGEgbmVzdGVkIGFycmF5IG9mIHN0cmluZ3MgdXAgdG8gMTAgbGV2ZWwgZGVlcGApO1xuICAgICAgICB9XG4gICAgfSwge2N5Y2xlSGFuZGxpbmc6IHRydWV9KTtcbn1cbiJdfQ==