gitlab-ci-local
Version:
Tired of pushing to test your .gitlab-ci.yml?
218 lines • 34 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) {
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGF0YS1leHBhbmRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbImRhdGEtZXhwYW5kZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE1BQU0sT0FBTyxDQUFDO0FBQzFCLE9BQU8sVUFBVSxNQUFNLGFBQWEsQ0FBQztBQUNyQyxPQUFPLE1BQU0sRUFBRSxFQUFDLGNBQWMsRUFBQyxNQUFNLFFBQVEsQ0FBQztBQUM5QyxPQUFPLEVBQUMsR0FBRyxFQUFPLE1BQU0sVUFBVSxDQUFDO0FBQ25DLE9BQU8sRUFBQyxRQUFRLEVBQUMsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQyxPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sWUFBWSxDQUFDO0FBRWpDLE1BQU0sZUFBZSxHQUFHLEVBQUUsQ0FBQztBQUMzQixNQUFNLGNBQWMsR0FBRyxDQUFDLFVBQWUsRUFBRSxPQUFlLEVBQUUsT0FBWSxFQUFFLE9BQWMsRUFBRSxLQUFhLEVBQUUsRUFBRTtJQUNyRyxNQUFNLENBQUMsS0FBSyxHQUFHLGVBQWUsRUFBRSxLQUFLLENBQUEsZUFBZSxPQUFPLGdEQUFnRCxDQUFDLENBQUM7SUFDN0csS0FBSyxFQUFFLENBQUM7SUFFUixPQUFPLENBQUMsT0FBTyxHQUFHLE9BQU8sT0FBTyxDQUFDLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDO0lBQzVGLE9BQU8sQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDLE9BQU8sSUFBSSxFQUFFLENBQUM7SUFFeEMsS0FBSyxNQUFNLFVBQVUsSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7UUFDdkMsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQzFDLE1BQU0sQ0FBQyxVQUFVLElBQUksSUFBSSxFQUFFLEtBQUssQ0FBQSxlQUFlLFVBQVUseUNBQXlDLE9B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RCxJQUFJLE1BQU0sSUFBSSxJQUFJLElBQUksR0FBRyxJQUFJLElBQUksSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDeEQsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDNUIsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxDQUFBLHdEQUF3RCxJQUFJLENBQUMsUUFBUSw0RUFBNEUsQ0FBQyxDQUFDO1FBQ3JNLENBQUM7SUFDTCxDQUFDLEVBQUUsRUFBQyxhQUFhLEVBQUUsSUFBSSxFQUFDLENBQUMsQ0FBQztBQUM5QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IGRlZXBFeHRlbmQgZnJvbSBcImRlZXAtZXh0ZW5kXCI7XG5pbXBvcnQgYXNzZXJ0LCB7QXNzZXJ0aW9uRXJyb3J9IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7Sm9iLCBOZWVkfSBmcm9tIFwiLi9qb2IuanNcIjtcbmltcG9ydCB7dHJhdmVyc2V9IGZyb20gXCJvYmplY3QtdHJhdmVyc2FsXCI7XG5pbXBvcnQge1V0aWxzfSBmcm9tIFwiLi91dGlscy5qc1wiO1xuXG5jb25zdCBleHRlbmRzTWF4RGVwdGggPSAxMTtcbmNvbnN0IGV4dGVuZHNSZWN1cnNlID0gKGdpdGxhYkRhdGE6IGFueSwgam9iTmFtZTogc3RyaW5nLCBqb2JEYXRhOiBhbnksIHBhcmVudHM6IGFueVtdLCBkZXB0aDogbnVtYmVyKSA9PiB7XG4gICAgYXNzZXJ0KGRlcHRoIDwgZXh0ZW5kc01heERlcHRoLCBjaGFsa2B7Ymx1ZUJyaWdodCAke2pvYk5hbWV9fTogY2lyY3VsYXIgZGVwZW5kZW5jeSBkZXRlY3RlZCBpbiBcXGBleHRlbmRzXFxgYCk7XG4gICAgZGVwdGgrKztcblxuICAgIGpvYkRhdGEuZXh0ZW5kcyA9IHR5cGVvZiBqb2JEYXRhLmV4dGVuZHMgPT09IFwic3RyaW5nXCIgPyBbam9iRGF0YS5leHRlbmRzXSA6IGpvYkRhdGEuZXh0ZW5kcztcbiAgICBqb2JEYXRhLmV4dGVuZHMgPSBqb2JEYXRhLmV4dGVuZHMgPz8gW107XG5cbiAgICBmb3IgKGNvbnN0IHBhcmVudE5hbWUgb2Ygam9iRGF0YS5leHRlbmRzKSB7XG4gICAgICAgIGNvbnN0IHBhcmVudERhdGEgPSBnaXRsYWJEYXRhW3BhcmVudE5hbWVdO1xuICAgICAgICBhc3NlcnQocGFyZW50RGF0YSAhPSBudWxsLCBjaGFsa2B7Ymx1ZUJyaWdodCAke3BhcmVudE5hbWV9fSBpcyB1bnNwZWNpZmllZCwgdXNlZCBieSB7Ymx1ZUJyaWdodCAke2pvYk5hbWV9fSBleHRlbmRzYCk7XG4gICAgICAgIGV4dGVuZHNSZWN1cnNlKGdpdGxhYkRhdGEsIHBhcmVudE5hbWUsIHBhcmVudERhdGEsIHBhcmVudHMsIGRlcHRoKTtcbiAgICAgICAgcGFyZW50cy5wdXNoKHBhcmVudERhdGEpO1xuICAgIH1cbiAgICByZXR1cm4gcGFyZW50cztcbn07XG5cbmV4cG9ydCBmdW5jdGlvbiBqb2JFeHRlbmRzIChnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSkgY29udGludWU7XG4gICAgICAgIGlmICghVXRpbHMuaXNPYmplY3Qoam9iRGF0YSkpIGNvbnRpbnVlO1xuICAgICAgICBjb25zdCBwYXJlbnREYXRhcyA9IGV4dGVuZHNSZWN1cnNlKGdpdGxhYkRhdGEsIGpvYk5hbWUsIGpvYkRhdGEsIFtdLCAwKTtcbiAgICAgICAgZ2l0bGFiRGF0YVtqb2JOYW1lXSA9IGRlZXBFeHRlbmQoe30sIC4uLnBhcmVudERhdGFzLCBqb2JEYXRhKTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSkgY29udGludWU7XG4gICAgICAgIGlmICghVXRpbHMuaXNPYmplY3Qoam9iRGF0YSkpIGNvbnRpbnVlO1xuICAgICAgICBkZWxldGUgam9iRGF0YS5leHRlbmRzO1xuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHJlZmVyZW5jZSAoZ2l0bGFiRGF0YTogYW55LCByZWN1cnNlRGF0YTogYW55KSB7XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihyZWN1cnNlRGF0YSB8fCB7fSkpIHtcbiAgICAgICAgaWYgKHZhbHVlPy5yZWZlcmVuY2VEYXRhKSB7XG4gICAgICAgICAgICByZWN1cnNlRGF0YVtrZXldID0gZ2V0U3ViRGF0YUJ5UmVmZXJlbmNlKGdpdGxhYkRhdGEsIHZhbHVlLnJlZmVyZW5jZURhdGEpO1xuICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgcmVmZXJlbmNlKGdpdGxhYkRhdGEsIHZhbHVlKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChoYXNDaXJjdWxhckNoYWluKHJlY3Vyc2VEYXRhKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEFzc2VydGlvbkVycm9yKHttZXNzYWdlOiBgIXJlZmVyZW5jZSBjaXJjdWxhciBjaGFpbiBkZXRlY3RlZCBbJHt2YWx1ZS5yZWZlcmVuY2VEYXRhfV1gfSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmNvbnN0IGdldFN1YkRhdGFCeVJlZmVyZW5jZSA9IChnaXRsYWJEYXRhOiBhbnksIHJlZmVyZW5jZURhdGE6IHN0cmluZ1tdKSA9PiB7XG4gICAgbGV0IGdpdGxhYlN1YkRhdGEgPSBnaXRsYWJEYXRhO1xuICAgIHJlZmVyZW5jZURhdGEuZm9yRWFjaCgocmVmZXJlbmNlUG9pbnRlcikgPT4ge1xuICAgICAgICBhc3NlcnQoZ2l0bGFiU3ViRGF0YVtyZWZlcmVuY2VQb2ludGVyXSAhPSBudWxsLCBgIXJlZmVyZW5jZSBbJHtyZWZlcmVuY2VEYXRhLmpvaW4oXCIsIFwiKX1dIGlzIHVuZGVmaW5lZGApO1xuICAgICAgICBnaXRsYWJTdWJEYXRhID0gZ2l0bGFiU3ViRGF0YVtyZWZlcmVuY2VQb2ludGVyXTtcbiAgICB9KTtcbiAgICByZXR1cm4gZ2l0bGFiU3ViRGF0YTtcbn07XG5cbmZ1bmN0aW9uIGhhc0NpcmN1bGFyQ2hhaW4gKGRhdGE6IGFueSkge1xuICAgIHRyeSB7XG4gICAgICAgIEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgaWYgKGUgaW5zdGFuY2VvZiBUeXBlRXJyb3IgJiYgZS5tZXNzYWdlLnN0YXJ0c1dpdGgoXCJDb252ZXJ0aW5nIGNpcmN1bGFyIHN0cnVjdHVyZSB0byBKU09OXCIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICBUcmFuc2Zvcm0gdGhlIGdsb2JhbGx5IGRlZmluZWQgW1wiaW1hZ2VcIiwgXCJzZXJ2aWNlc1wiLCBcImNhY2hlXCIsIFwiYmVmb3JlX3NjcmlwdFwiLCBcImFmdGVyX3NjcmlwdFwiXSBpbnRvIHRoZSBkZWZhdWx0Lnggc3ludGF4XG4gIGh0dHBzOi8vZG9jcy5naXRsYWIuY29tL2VlL2NpL3lhbWwvaW5kZXguaHRtbCNnbG9iYWxseS1kZWZpbmVkLWltYWdlLXNlcnZpY2VzLWNhY2hlLWJlZm9yZV9zY3JpcHQtYWZ0ZXJfc2NyaXB0XG4qL1xuZXhwb3J0IGZ1bmN0aW9uIHRyYW5zZm9ybURlcHJlY2F0ZWRHbG9iYWxEZWZhdWx0U3ludGF4IChnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBjb25zdCBHSVRMQUJfREVQUkVDQVRFRF9HTE9CQUxMWV9ERUZJTkVEX0tFWVdPUkRTID0gW1wiaW1hZ2VcIiwgXCJzZXJ2aWNlc1wiLCBcImNhY2hlXCIsIFwiYmVmb3JlX3NjcmlwdFwiLCBcImFmdGVyX3NjcmlwdFwiXTtcblxuICAgIGdpdGxhYkRhdGEuZGVmYXVsdCA9IGdpdGxhYkRhdGEuZGVmYXVsdCA/PyB7fTtcbiAgICBmb3IgKGNvbnN0IGcgb2YgR0lUTEFCX0RFUFJFQ0FURURfR0xPQkFMTFlfREVGSU5FRF9LRVlXT1JEUykge1xuICAgICAgICBpZiAoZ2l0bGFiRGF0YVtnXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBnaXRsYWJEYXRhLmRlZmF1bHRbZ10gPSBnaXRsYWJEYXRhW2ddO1xuICAgICAgICAgICAgZGVsZXRlIGdpdGxhYkRhdGFbZ107IC8vIFNpbmNlIHRoaXMgaXMgZGVwcmVjYXRlZCwgZGVsZXRpbmcgaXQgdG8gcHJldmVudCB1cyBmcm9tIHVzaW5nIGl0IGludGVybmFsbHlcbiAgICAgICAgfVxuICAgIH1cbn1cblxuZXhwb3J0IGZ1bmN0aW9uIG5vcm1hbGl6ZSAoZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgbm9ybWFsaXplR2xvYmFsVmFyaWFibGVzKGdpdGxhYkRhdGEpO1xuXG4gICAgZm9yIChjb25zdCBbam9iTmFtZSwgam9iRGF0YV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhKSkge1xuICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkgfHwgam9iTmFtZS5zdGFydHNXaXRoKFwiLlwiKSkgY29udGludWU7XG4gICAgICAgIG5lZWRzRWFjaChqb2JOYW1lLCBnaXRsYWJEYXRhKTtcbiAgICAgICAgY2FjaGVFYWNoKGpvYk5hbWUsIGdpdGxhYkRhdGEpO1xuICAgICAgICBzZXJ2aWNlc0VhY2goam9iTmFtZSwgZ2l0bGFiRGF0YSk7XG4gICAgICAgIGltYWdlRWFjaChqb2JOYW1lLCBnaXRsYWJEYXRhKTtcblxuICAgICAgICBqb2JEYXRhLmFmdGVyX3NjcmlwdCA9ICh0eXBlb2Ygam9iRGF0YS5hZnRlcl9zY3JpcHQgPT09IFwic3RyaW5nXCIgJiYgam9iRGF0YS5hZnRlcl9zY3JpcHQgIT09IFwiXCIpID8gW2pvYkRhdGEuYWZ0ZXJfc2NyaXB0XSA6IGpvYkRhdGEuYWZ0ZXJfc2NyaXB0O1xuICAgICAgICBqb2JEYXRhLmJlZm9yZV9zY3JpcHQgPSAodHlwZW9mIGpvYkRhdGEuYmVmb3JlX3NjcmlwdCA9PT0gXCJzdHJpbmdcIiAmJiBqb2JEYXRhLmJlZm9yZV9zY3JpcHQgIT09IFwiXCIpID8gW2pvYkRhdGEuYmVmb3JlX3NjcmlwdF0gOiBqb2JEYXRhLmJlZm9yZV9zY3JpcHQ7XG4gICAgICAgIGpvYkRhdGEuc2NyaXB0ID0gKHR5cGVvZiBqb2JEYXRhLnNjcmlwdCA9PT0gXCJzdHJpbmdcIiAmJiBqb2JEYXRhLnNjcmlwdCAhPT0gXCJcIikgPyBbam9iRGF0YS5zY3JpcHRdIDogam9iRGF0YS5zY3JpcHQ7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gbmVlZHNDb21wbGV4IChkYXRhOiBhbnkpIHtcbiAgICBjb25zdCBuZWVkczogTmVlZCA9IHtcbiAgICAgICAgam9iOiBkYXRhLmpvYiA/PyBkYXRhLFxuICAgICAgICBhcnRpZmFjdHM6IGRhdGEuYXJ0aWZhY3RzID8/IHRydWUsXG4gICAgICAgIC4uLihkYXRhLnBpcGVsaW5lID8ge3BpcGVsaW5lOiBkYXRhLnBpcGVsaW5lfSA6IHt9KSxcbiAgICAgICAgLi4uKGRhdGEucHJvamVjdCA/IHtwcm9qZWN0OiBkYXRhLnByb2plY3R9IDoge30pLFxuICAgICAgICAuLi4oZGF0YS5yZWYgPyB7cmVmOiBkYXRhLnJlZn0gOiB7fSksXG4gICAgICAgIC4uLihkYXRhLm9wdGlvbmFsID8ge29wdGlvbmFsOiBkYXRhLm9wdGlvbmFsfSA6IHt9KSxcbiAgICB9O1xuXG4gICAgLy8gSW4gbmVlZHM6cHJvamVjdC9uZWVkczpwaXBlbGluZSwgYG9wdGlvbmFsYCBpcyBub3QgYW4gYWxsb3dlZCBwcm9wZXJ0eVxuICAgIGlmICghZGF0YS5wcm9qZWN0ICYmICFkYXRhLnBpcGVsaW5lICYmIGRhdGEub3B0aW9uYWwgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBuZWVkcy5vcHRpb25hbCA9IGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gbmVlZHM7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBuZWVkc0VhY2ggKGpvYk5hbWU6IHN0cmluZywgZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgY29uc3Qgam9iRGF0YSA9IGdpdGxhYkRhdGFbam9iTmFtZV07XG4gICAgaWYgKCFqb2JEYXRhLm5lZWRzKSByZXR1cm47XG5cbiAgICBmb3IgKGNvbnN0IFtpLCBuXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGpvYkRhdGEubmVlZHMpKSB7XG4gICAgICAgIGpvYkRhdGEubmVlZHNbaV0gPSBuZWVkc0NvbXBsZXgobik7XG4gICAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gY2FjaGVDb21wbGV4IChkYXRhOiBhbnkpIHtcbiAgICByZXR1cm4ge1xuICAgICAgICBrZXk6IGRhdGEua2V5LFxuICAgICAgICBwYXRoczogZGF0YS5wYXRocyxcbiAgICAgICAgcG9saWN5OiBkYXRhLnBvbGljeSA/PyBcInB1bGwtcHVzaFwiLFxuICAgICAgICB3aGVuOiBkYXRhLndoZW4gPz8gXCJvbl9zdWNjZXNzXCIsXG4gICAgfTtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGNhY2hlRWFjaCAoam9iTmFtZTogc3RyaW5nLCBnaXRsYWJEYXRhOiBhbnkpIHtcbiAgICBjb25zdCBqb2JEYXRhID0gZ2l0bGFiRGF0YVtqb2JOYW1lXTtcbiAgICBjb25zdCBjYWNoZSA9IGpvYkRhdGEuY2FjaGU7XG4gICAgaWYgKCFjYWNoZSkgcmV0dXJuO1xuXG4gICAgam9iRGF0YS5jYWNoZSA9IEFycmF5LmlzQXJyYXkoY2FjaGUpID8gY2FjaGUgOiBbY2FjaGVdO1xuICAgIGZvciAoY29uc3QgW2ksIGNdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oam9iRGF0YS5jYWNoZSkpIHtcbiAgICAgICAgaWYgKGMua2V5Py5maWxlcyBpbnN0YW5jZW9mIEFycmF5KSB7XG4gICAgICAgICAgICBhc3NlcnQoYy5rZXkuZmlsZXMubGVuZ3RoID09PSAxIHx8IGMua2V5LmZpbGVzLmxlbmd0aCA9PT0gMiwgYGNhY2hlOmtleTpmaWxlcyBzaG91bGQgYmUgYW4gYXJyYXkgb2Ygb25lIG9yIHR3byBmaWxlIHBhdGhzLiBHb3QgJHtjLmtleS5maWxlcy5sZW5ndGh9YCk7XG4gICAgICAgIH1cbiAgICAgICAgam9iRGF0YS5jYWNoZVtpXSA9IGNhY2hlQ29tcGxleChjKTtcbiAgICB9XG5cbiAgICAvLyBSZW1vdmUgY2FjaGUgZWxlbWVudHMgd2l0aCBlbXB0eSBwYXRocyBhcnJheSAoZ2l0bGFiLmNvbSB3b3JrcyB0aGUgc2FtZSB3YXkuKVxuICAgIGpvYkRhdGEuY2FjaGUgPSBqb2JEYXRhLmNhY2hlLmZpbHRlcigoYzogYW55KSA9PiBjLnBhdGhzPy5sZW5ndGggIT09IHVuZGVmaW5lZCk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXJ2aWNlc0NvbXBsZXggKGRhdGE6IGFueSkge1xuICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiID8gZGF0YSA6IGRhdGEubmFtZSxcbiAgICAgICAgZW50cnlwb2ludDogZGF0YS5lbnRyeXBvaW50LFxuICAgICAgICBjb21tYW5kOiBkYXRhLmNvbW1hbmQsXG4gICAgICAgIGFsaWFzOiBkYXRhLmFsaWFzLFxuICAgICAgICB2YXJpYWJsZXM6IGRhdGEudmFyaWFibGVzLFxuICAgIH07XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXJ2aWNlc0VhY2ggKGpvYk5hbWU6IHN0cmluZywgZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgY29uc3Qgam9iRGF0YSA9IGdpdGxhYkRhdGFbam9iTmFtZV07XG4gICAgY29uc3Qgc2VydmljZXMgPSBqb2JEYXRhLnNlcnZpY2VzO1xuICAgIGlmICghc2VydmljZXMpIHJldHVybjtcblxuICAgIGpvYkRhdGEuc2VydmljZXMgPSBBcnJheS5pc0FycmF5KHNlcnZpY2VzKSA/IHNlcnZpY2VzIDogW3NlcnZpY2VzXTtcblxuICAgIGZvciAoY29uc3QgW2ksIHNdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oam9iRGF0YS5zZXJ2aWNlcykpIHtcbiAgICAgICAgam9iRGF0YS5zZXJ2aWNlc1tpXSA9IHNlcnZpY2VzQ29tcGxleChzKTtcbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBpbWFnZUNvbXBsZXggKGRhdGE6IGFueSkge1xuICAgIGlmIChkYXRhID09IG51bGwpIHJldHVybiBkYXRhO1xuICAgIHJldHVybiB7XG4gICAgICAgIG5hbWU6IHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiID8gZGF0YSA6IGRhdGEubmFtZSxcbiAgICAgICAgZW50cnlwb2ludDogZGF0YS5lbnRyeXBvaW50LFxuICAgICAgICAuLi4oZGF0YS5kb2NrZXI/LnVzZXIgPyB7ZG9ja2VyOiB7dXNlcjogZGF0YS5kb2NrZXI/LnVzZXJ9fSA6IHt9KSxcbiAgICB9O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaW1hZ2VFYWNoIChqb2JOYW1lOiBzdHJpbmcsIGdpdGxhYkRhdGE6IGFueSkge1xuICAgIGNvbnN0IGpvYkRhdGEgPSBnaXRsYWJEYXRhW2pvYk5hbWVdO1xuICAgIGNvbnN0IGltYWdlID0gam9iRGF0YS5pbWFnZTtcbiAgICBpZiAoIWltYWdlKSByZXR1cm47XG5cbiAgICBqb2JEYXRhLmltYWdlID0gaW1hZ2VDb21wbGV4KGpvYkRhdGEuaW1hZ2UpO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gaW5oZXJpdERlZmF1bHQgKGdpdGxhYkRhdGE6IGFueSkge1xuICAgIGZvciAoY29uc3QgW2pvYk5hbWUsIGpvYkRhdGFdIG9mIE9iamVjdC5lbnRyaWVzPGFueT4oZ2l0bGFiRGF0YSkpIHtcbiAgICAgICAgaWYgKGpvYkRhdGEuaW5oZXJpdD8uZGVmYXVsdCA9PT0gZmFsc2UpIGNvbnRpbnVlO1xuXG4gICAgICAgIGlmIChKb2IuaWxsZWdhbEpvYk5hbWVzLmhhcyhqb2JOYW1lKSB8fCBqb2JOYW1lLnN0YXJ0c1dpdGgoXCIuXCIpKSB7XG4gICAgICAgICAgICAvLyBza2lwIGhpZGRlbiBqb2JzIGFzIHRoZXkgbWlnaHQganVzdCBjb250YWluIHNoYXJlZCB5YW1sXG4gICAgICAgICAgICAvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2ZpcmVjb3cvZ2l0bGFiLWNpLWxvY2FsL2lzc3Vlcy8xMjc3XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGtleXdvcmRzVG9Jbmhlcml0RnJvbSA9IChBcnJheS5pc0FycmF5KGpvYkRhdGEuaW5oZXJpdD8uZGVmYXVsdCkpXG4gICAgICAgICAgICA/IGpvYkRhdGEuaW5oZXJpdC5kZWZhdWx0XG4gICAgICAgICAgICA6IFtcImFydGlmYWN0c1wiLCBcImNhY2hlXCIsIFwic2VydmljZXNcIiwgXCJpbWFnZVwiLCBcImJlZm9yZV9zY3JpcHRcIiwgXCJhZnRlcl9zY3JpcHRcIl07XG5cbiAgICAgICAgZm9yIChjb25zdCBrZXl3b3JkIG9mIGtleXdvcmRzVG9Jbmhlcml0RnJvbSkge1xuICAgICAgICAgICAgaWYgKGdpdGxhYkRhdGEuZGVmYXVsdFtrZXl3b3JkXSAhPT0gdW5kZWZpbmVkKSBqb2JEYXRhW2tleXdvcmRdID0gam9iRGF0YVtrZXl3b3JkXSA/PyBnaXRsYWJEYXRhLmRlZmF1bHRba2V5d29yZF07XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZUdsb2JhbFZhcmlhYmxlcyAoZ2l0bGFiRGF0YTogYW55KSB7XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXM8YW55PihnaXRsYWJEYXRhLnZhcmlhYmxlcyA/PyB7fSkpIHtcbiAgICAgICAgaWYgKHZhbHVlID09PSBudWxsKSB7XG4gICAgICAgICAgICBnaXRsYWJEYXRhLnZhcmlhYmxlc1trZXldID0gXCJcIjsgLy8gdmFyaWFibGUncyB2YWx1ZXMgYXJlIG51bGxhYmxlXG4gICAgICAgIH0gZWxzZSBpZiAoVXRpbHMuaXNPYmplY3QodmFsdWUpKSB7XG4gICAgICAgICAgICBnaXRsYWJEYXRhLnZhcmlhYmxlc1trZXldID0gU3RyaW5nKHZhbHVlW1widmFsdWVcIl0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZ2l0bGFiRGF0YS52YXJpYWJsZXNba2V5XSA9IFN0cmluZyh2YWx1ZSk7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmbGF0dGVuTGlzdHMgKGdpdGxhYkRhdGE6IGFueSkge1xuICAgIHRyYXZlcnNlKGdpdGxhYkRhdGEsICh7cGFyZW50LCBrZXksIHZhbHVlLCBtZXRhfSkgPT4ge1xuICAgICAgICBpZiAocGFyZW50ICE9IG51bGwgJiYga2V5ICE9IG51bGwgJiYgQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIHBhcmVudFtrZXldID0gdmFsdWUuZmxhdCg5KTtcbiAgICAgICAgICAgIGFzc2VydCghcGFyZW50W2tleV0uc29tZShBcnJheS5pc0FycmF5KSwgY2hhbGtgVGhpcyBHaXRsYWIgQ0kgY29uZmlndXJhdGlvbiBpcyBpbnZhbGlkOiB7Ymx1ZUJyaWdodCAke21ldGEubm9kZVBhdGh9fSBjb25maWcgc2hvdWxkIGJlIHN0cmluZyBvciBhIG5lc3RlZCBhcnJheSBvZiBzdHJpbmdzIHVwIHRvIDEwIGxldmVsIGRlZXBgKTtcbiAgICAgICAgfVxuICAgIH0sIHtjeWNsZUhhbmRsaW5nOiB0cnVlfSk7XG59XG4iXX0=