@tricoteuses/assemblee
Version:
Retrieve, clean up & handle French Assemblée nationale's open data
414 lines (411 loc) • 67 kB
JavaScript
var _LectureMapping;
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); }
import commandLineArgs from "command-line-args";
import commandLineUsage from "command-line-usage";
import assert from "assert";
import { load, getFiles } from "../file_systems.mjs";
function parseArgs(argv) {
const optionsDefinitions = [{
description: "pathname to a JSON file or a glob pattern to JSON files",
defaultOption: true,
multiple: true,
name: "data",
type: String
}, {
name: "no-sanity-checks",
type: Boolean,
description: "Do not perform sanity checks."
}, {
name: "verbose",
type: Boolean,
description: "increase verbosity"
}, {
name: "help",
description: "Print this usage guide."
}];
const sections = [{
header: "Aide à la documentation du dossier législatif",
content: "Génère une hiérarchie des actes législatifs"
}, {
header: "Options",
optionList: optionsDefinitions
}];
const options = commandLineArgs(optionsDefinitions, {
argv: argv
});
if (!("help" in options) && !("data" in options)) {
console.error("--data is mandatory");
options.help = true;
}
if ("help" in options) {
const usage = commandLineUsage(sections);
console.warn(usage);
return null;
}
return options;
}
function eqSet(as, bs) {
if (as.size !== bs.size) return false;
for (var a of as) if (!bs.has(a)) return false;
return true;
}
class Code2Pattern {
constructor(pattern, children) {
_defineProperty(this, "_pattern_", void 0);
_defineProperty(this, "_match_count_", void 0);
this._pattern_ = pattern;
this._match_count_ = 0;
Object.assign(this, children);
}
}
class Code2PatternComFond extends Code2Pattern {
constructor() {
super("^/SAISIE/(/NOMIN/)*(/REUNION/)*(/RAPPORT/)*$", {});
}
}
class LectureMapping {
constructor() {
_defineProperty(this, "libelle", {});
_defineProperty(this, "codes", new Set());
}
static isLecture(acte) {
return acte.codeActe.match(LectureMapping.codes_lecture_regexp);
}
static getType(acte) {
if (acte.codeActe.match(/^AN/)) return "AN";else if (acte.codeActe.match(/^SN/)) return "SN";else throw Error(`${acte.codeActe} does not start with AN or SN`);
}
static map(codeActe) {
return codeActe.replace(LectureMapping.codes_lecture_regexp, `lecture$1`);
}
static getCodeActe(acte) {
if (!LectureMapping.isLecture(acte)) return;
return LectureMapping.map(acte.codeActe);
}
add(acte) {
this.codes.add(acte.codeActe);
const type = LectureMapping.getType(acte);
if (!(acte.libelleActe.nomCanonique in this.libelle)) this.libelle[acte.libelleActe.nomCanonique] = new Set();
this.libelle[acte.libelleActe.nomCanonique].add(type);
}
remap(acte, codeActe) {
acte.codeActe = codeActe;
let types = this.libelle[acte.libelleActe.nomCanonique];
if (!(types.has("SN") && types.has("AN"))) {
if (types.has("SN")) acte.libelleActe.nomCanonique += " (Sénat)";else if (types.has("AN")) acte.libelleActe.nomCanonique += " (Assemblée Nationale)";
}
}
mergeCodes(codes) {
for (const c of Array.from(this.codes)) codes.add(c);
}
printAnchors() {
for (const code of Array.from(this.codes)) console.log(`.. _${code}:`);
}
getCodes() {
return Array.from(this.codes).join(",");
}
}
_LectureMapping = LectureMapping;
_defineProperty(LectureMapping, "codes_lecture", ["AN1", "SN1", "ANNLEC", "SNNLEC", "ANLDEF", "AN2", "SN2", "SN3"]);
_defineProperty(LectureMapping, "codes_lecture_regexp", new RegExp("^(?:" + _LectureMapping.codes_lecture.join("|") + ")(-.*)?$"));
class LectureMapper {
constructor() {
_defineProperty(this, "mapping", {});
}
has(codeActe) {
return codeActe in this.mapping;
}
collect(acte) {
const codeActe = LectureMapping.getCodeActe(acte);
if (codeActe != undefined) {
let lectures = this.mapping;
if (!(codeActe in lectures)) lectures[codeActe] = new LectureMapping();
lectures[codeActe].add(acte);
}
}
remap(acte) {
const codeActe = LectureMapping.getCodeActe(acte);
if (codeActe != undefined) this.mapping[codeActe].remap(acte, codeActe);
}
mergeCodes(codes, codeActe) {
this.mapping[codeActe].mergeCodes(codes);
}
printAnchors(codeActe) {
this.mapping[codeActe].printAnchors();
}
getCodes(codeActe) {
return this.mapping[codeActe].getCodes();
}
}
class ActesDocumentation {
constructor(sanityChecks, verbose = false) {
_defineProperty(this, "verbose", void 0);
_defineProperty(this, "sanityChecks", void 0);
_defineProperty(this, "lectureMapper", new LectureMapper());
_defineProperty(this, "remappedProcedures", {});
_defineProperty(this, "anchorsPrinted", {});
_defineProperty(this, "anchors", new Set());
_defineProperty(this, "codes", {});
_defineProperty(this, "procedures", null);
_defineProperty(this, "code2pattern", new Code2Pattern(null, {
"Procédure législative": new Code2Pattern("^(((/lecture/)+)|((/lecture/)+/CMP/(/lecture/)*))(/CC/)?(/PROM/)?(/AN-APPLI/)?$", {
lecture: new Code2Pattern("^(/DEPOT/)?(/DPTLETTRECT/)?(/ETI/)?(/AVCE/)?(/DGVT/)?(/ACIN/)?(/MOTION/)*(/PROCACC/)?(/COM/)?((/DEBATS/)+)?(/RTRINI/)?$", {
"lecture-COM": new Code2Pattern("^(/FOND/|/AVIS/)+$", {
"lecture-COM-FOND": new Code2PatternComFond(),
"lecture-COM-AVIS": new Code2PatternComFond()
}),
"lecture-DEBATS": new Code2Pattern("^(/SEANCE/)*((/MOTION/)?(/MOTION-VOTE/)+)?(/DEC/)?$", {})
}),
CMP: new Code2Pattern("^(/DEPOT/|/SAISIE/){1,2}(/COM/)?(/DEC/)?(/DEBATS-AN//DEBATS-SN/)?", {
"CMP-COM": new Code2Pattern("^(/NOMIN/)?(/RAPPORT-AN/|/RAPPORT-SN/){2}$", {}),
"CMP-DEBATS-AN": new Code2Pattern("^(/SEANCE/)*(/DEC/)?$", {}),
"CMP-DEBATS-SN": new Code2Pattern("^(/SEANCE/)*(/DEC/)?$", {})
}),
CC: new Code2Pattern("^(/SAISIE/)+(/CONCLUSION/)?$", {}),
PROM: new Code2Pattern("^(/PUB/)?$", {}),
"AN-APPLI": new Code2Pattern("^(/RAPPORT/)?$", {})
}),
"Allocution du Président de l'Assemblée nationale": new Code2Pattern("^/AN21/$", {
AN21: new Code2Pattern("^(/APAN/)?$", {})
}),
"Résolution Article 34-1": new Code2Pattern("^(/ANLUNI/)?$", {
ANLUNI: new Code2Pattern("^(/DEPOT/)?(/DEBATS/)?(/RTRINI/)?$", {
"ANLUNI-DEBATS": new Code2Pattern("^(/SEANCE/)+(/DEC/)?$", {})
})
}),
Résolution: new Code2Pattern("^(/ANLUNI/)?(/CC/)?$", {
ANLUNI: new Code2Pattern("^(/DEPOT/)?(/COM/)?(/DEBATS/|/RTRINI/)?$", {
"ANLUNI-COM": new Code2Pattern("^(/CAE/)?(/FOND/)?$", {
"ANLUNI-COM-FOND": new Code2PatternComFond(),
"ANLUNI-COM-CAE": new Code2Pattern("^(/SAISIE/)?(/NOMIN/)?(/REUNION/)?(/RAPPORT/)?(/DEC/)?$", {})
}),
"ANLUNI-DEBATS": new Code2Pattern("^(/SEANCE/)*(/DEC/)?$", {})
}),
CC: new Code2Pattern("^(/SAISIE/)?(/CONCLUSION/)?$", {})
}),
"Rapport d'information sans mission": new Code2Pattern("^(/AN20/)?(/EU/)?$", {
AN20: new Code2Pattern("^(/RAPPORT/)?$", {}),
EU: new Code2Pattern("^(/DEC/)+$", {})
}),
"Mission d'information": new Code2Pattern("^(/AN20/)?$", {
AN20: new Code2Pattern("^(/MISINF/)?$", {
"AN20-MISINF": new Code2Pattern("^(/CREA/)?(/NOMIN/)?(/RAPPORT/)?$", {})
})
}),
"Commission d'enquête": new Code2Pattern("^(/AN20/)?$", {
AN20: new Code2Pattern("^(/COMENQ/)?$", {
"AN20-COMENQ": new Code2Pattern("^(/CREA/)?(/NOMIN/)?(/RAPPORT/)?$", {})
})
}),
"Engagement de la responsabilité gouvernementale": new Code2Pattern("^/AN21/$", {
AN21: new Code2Pattern("^(((/MOTION/)*/DEBATS/)|(/DGVT/)){1,2}$", {
"AN21-DEBATS": new Code2Pattern("^(/SEANCE/)*(/MOTION-VOTE/)*$", {})
})
}),
"Motion référendaire": new Code2Pattern("^(/lecture/)+$", {
lecture: new Code2Pattern("^(/DEPOT/)?(/COM/)?(/DEBATS/)?$", {
"lecture-COM": new Code2Pattern("^(/FOND/)?$", {
"lecture-COM-FOND": new Code2Pattern("^(/SAISIE/)?(/NOMIN/)*(/RAPPORT/)*$", {})
}),
"lecture-DEBATS": new Code2Pattern("^(/DEC/)?$", {})
})
}),
Immunité: new Code2Pattern("^(/ANLUNI/)+$", {
ANLUNI: new Code2Pattern("^(/DEPOT/)?(/COM/)?(/DEBATS/)?(/RTRINI/)?$", {
"ANLUNI-COM": new Code2Pattern("^(/FOND/)?$", {
"ANLUNI-COM-FOND": new Code2Pattern("^(/SAISIE/)?(/NOMIN/)*(/RAPPORT/)*$", {})
}),
"ANLUNI-DEBATS": new Code2Pattern("^(/SEANCE/)?(/DEC/)$", {})
})
}),
"Responsabilité pénale du président de la république": new Code2Pattern("^/lecture/$", {
lecture: new Code2Pattern("^(/DEPOT/)?(/RECBUREAU/)?$", {})
}),
"Proposition de loi présentée en application de l'article 11 de la Constitution": new Code2Pattern("^/lecture/$", {
lecture: new Code2Pattern("^(/DEPOT/)?$", {})
})
}));
this.verbose = verbose;
this.sanityChecks = sanityChecks;
this.procedures = {};
this.code2pattern._match_count_++;
}
walkFiles(data, action) {
for (const file of getFiles(data)) {
const dossier = load(file);
let procedure = this.remapProcedure(dossier.procedureParlementaire.libelle);
if (!(procedure in this.procedures)) this.procedures[procedure] = {};
action(this.procedures[procedure], dossier.actesLegislatifs, this.code2pattern[procedure], null);
}
}
collectFiles(data) {
this.walkFiles(data, (_actes, actesLegislatifs, _c2p, _parent) => {
this.collect(actesLegislatifs);
});
}
processFiles(data) {
this.walkFiles(data, (actes, actesLegislatifs, c2p, parent) => {
this.merge(actes, actesLegislatifs, c2p, parent);
});
if (this.sanityChecks) this.validate();
}
remapActes(actes) {
let results = [];
for (const acte of actes) {
this.lectureMapper.remap(acte);
// CC-SAISIE- suffix does not imply a hierarchy
acte.codeActe = acte.codeActe.replace(/^CC-SAISIE.*/, "CC-SAISIE");
results.push(acte);
}
return results;
}
collectActes(actes) {
let results = [];
for (const acte of actes) {
this.lectureMapper.collect(acte);
results.push(acte);
}
return results;
}
remapProcedure(procedure) {
const merge_procedures = new Map([["Proposition de loi ordinaire", "Procédure législative"], ["Projet de loi ordinaire", "Procédure législative"], ["Projet de ratification des traités et conventions", "Procédure législative"], ["Projet ou proposition de loi organique", "Procédure législative"], ["Projet ou proposition de loi constitutionnelle", "Procédure législative"], ["Projet de loi de finances de l'année", "Procédure législative"], ["Projet de loi de finances rectificative", "Procédure législative"], ["Projet de loi de financement de la sécurité sociale", "Procédure législative"]]);
if (merge_procedures.has(procedure)) {
this.remappedProcedures[procedure] = null;
return merge_procedures.get(procedure);
} else {
return procedure;
}
}
// return the codeActes in the same order they appear in the regexp
orderedCodes(codes, c2p, parent) {
codes = new Set(codes);
if (!this.sanityChecks) return codes;
let ordered = c2p["_pattern_"].match(new RegExp("/.*?/", "g"));
ordered = ordered.map(x => x.replace(new RegExp("/(.*)/"), "$1"));
if (parent != null) ordered = ordered.map(x => `${parent}-${x}`);
ordered = new Set(ordered);
assert(eqSet(ordered, codes), `${[...ordered]} != ${[...codes]}`);
return ordered;
}
validateChronology(actesLegislatifs, c2p, parent) {
const pattern = c2p["_pattern_"];
const sequence = actesLegislatifs.map(x => `/${x.codeActe}/`.replace(`/${parent}-`, "/")).join("");
assert(sequence.match(new RegExp(pattern)), `${pattern} does not match ${sequence}`);
c2p._match_count_++;
}
mergeActe(actes, acte, c2p, parent) {
let code = acte.codeActe;
let shortCode = code.replace(new RegExp(`^${parent}-`), "");
shortCode = shortCode.replace(/-(AN|SN)$/, "");
this.codes[shortCode] = null;
let name = acte.libelleActe.nomCanonique;
if (!(code in actes)) {
actes[code] = {
type: acte.xsiType,
name: new Set([name]),
shortCode: shortCode,
actes: {}
};
} else {
actes[code].name.add(name);
}
if ("actesLegislatifs" in acte) this.merge(actes[code].actes, acte.actesLegislatifs, c2p[code], code);
}
merge(actes, actesLegislatifs, c2p, parent) {
const l = this.remapActes(actesLegislatifs);
this.validateChronology(l, c2p, parent);
for (const acte of l) this.mergeActe(actes, acte, c2p, parent);
}
collect(actesLegislatifs) {
for (const acte of this.collectActes(actesLegislatifs)) if ("actesLegislatifs" in acte) this.collect(acte.actesLegislatifs);
}
validateLevel(c2p, path) {
assert(c2p._match_count_ > 0, `${path} is never used`);
for (const [key, value] of Object.entries(c2p)) {
if (value != null && value.constructor.name == "Code2Pattern") this.validateLevel(value, path.concat([key]));
}
}
validate() {
this.validateLevel(this.code2pattern, []);
}
printEntry(sections, entry, codes) {
const title = `\`${entry}\`__`;
console.log(title);
const underline = new Array(title.length + 1).join(sections[0]);
console.log(underline);
console.log(codes);
}
addAnchors(key) {
if (key in this.anchorsPrinted) return;
if (this.lectureMapper.has(key)) this.lectureMapper.mergeCodes(this.anchors, key);else this.anchors.add(key);
}
printAnchors(key) {
if (key in this.anchorsPrinted) return;
this.anchorsPrinted[key] = null;
if (this.lectureMapper.has(key)) this.lectureMapper.printAnchors(key);else console.log(`.. _${key}:`);
}
getCodes(key, shortCode) {
if (key in this.anchorsPrinted) return `cf \\*${shortCode}\\*`;
if (this.lectureMapper.has(key)) return this.lectureMapper.getCodes(key);else return key;
}
renameCMP(key, name) {
if (key.startsWith("CMP")) {
if (key.endsWith("-SN")) return `${name} (Sénat)`;else if (key.endsWith("-AN")) return `${name} (Assemblée Nationale)`;else return name;
} else return name;
}
printLevel(actes, sections, c2p, parent) {
const keys = this.orderedCodes(Object.keys(actes), c2p, parent);
for (const key of keys) {
const value = actes[key];
let name = Array.from(value.name).join(", ");
name = this.renameCMP(key, name);
const codes = this.getCodes(key, value.shortCode);
this.addAnchors(key);
this.printAnchors(key);
console.log("");
this.printEntry(sections, `${name} <${value.shortCode}TOC_>`, codes);
console.log("");
if (Object.keys(value.actes).length > 0) this.printLevel(value.actes, sections.substring(1), c2p[key], key);
}
}
printCodes() {
for (const key of Object.keys(this.codes)) console.log(`.. _${key}TOC: http://`);
}
printAnchorsIndex() {
for (const code of Array.from(this.anchors)) console.log(`* :ref:\`${code} <${code}>\``);
}
getAggregated(procedure) {
if (procedure == "Procédure législative") {
const remapped = Object.keys(this.remappedProcedures).join(", ");
return ` (agrégation de ${remapped})`;
} else return "";
}
print() {
this.anchorsPrinted = {};
for (const [key, actes] of Object.entries(this.procedures)) {
const code = key.replace(/ +/g, "_");
this.codes[code] = null;
const aggregated = this.getAggregated(key);
const title = `\`${key} <${code}TOC_>\`__${aggregated}`;
console.log(title);
const underline = new Array(title.length + 1).join("=");
console.log(underline);
this.printLevel(actes, "-~.'", this.code2pattern[key], null);
}
this.printCodes();
this.printAnchorsIndex();
}
}
function main(argv) {
const options = parseArgs(argv);
if (options === null) return 1;
let doc = new ActesDocumentation(!options["no-sanity-checks"], options.verbose);
doc.collectFiles(options.data);
doc.processFiles(options.data);
doc.print();
return 0;
}
/* istanbul ignore if */
if (process.argv[1].endsWith("document_dossiers_legislatifs.ts")) process.exit(main(process.argv));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJjb21tYW5kTGluZUFyZ3MiLCJjb21tYW5kTGluZVVzYWdlIiwiYXNzZXJ0IiwibG9hZCIsImdldEZpbGVzIiwicGFyc2VBcmdzIiwiYXJndiIsIm9wdGlvbnNEZWZpbml0aW9ucyIsImRlc2NyaXB0aW9uIiwiZGVmYXVsdE9wdGlvbiIsIm11bHRpcGxlIiwibmFtZSIsInR5cGUiLCJTdHJpbmciLCJCb29sZWFuIiwic2VjdGlvbnMiLCJoZWFkZXIiLCJjb250ZW50Iiwib3B0aW9uTGlzdCIsIm9wdGlvbnMiLCJjb25zb2xlIiwiZXJyb3IiLCJoZWxwIiwidXNhZ2UiLCJ3YXJuIiwiZXFTZXQiLCJhcyIsImJzIiwic2l6ZSIsImEiLCJoYXMiLCJDb2RlMlBhdHRlcm4iLCJjb25zdHJ1Y3RvciIsInBhdHRlcm4iLCJjaGlsZHJlbiIsIl9kZWZpbmVQcm9wZXJ0eSIsIl9wYXR0ZXJuXyIsIl9tYXRjaF9jb3VudF8iLCJPYmplY3QiLCJhc3NpZ24iLCJDb2RlMlBhdHRlcm5Db21Gb25kIiwiTGVjdHVyZU1hcHBpbmciLCJTZXQiLCJpc0xlY3R1cmUiLCJhY3RlIiwiY29kZUFjdGUiLCJtYXRjaCIsImNvZGVzX2xlY3R1cmVfcmVnZXhwIiwiZ2V0VHlwZSIsIkVycm9yIiwibWFwIiwicmVwbGFjZSIsImdldENvZGVBY3RlIiwiYWRkIiwiY29kZXMiLCJsaWJlbGxlQWN0ZSIsIm5vbUNhbm9uaXF1ZSIsImxpYmVsbGUiLCJyZW1hcCIsInR5cGVzIiwibWVyZ2VDb2RlcyIsImMiLCJBcnJheSIsImZyb20iLCJwcmludEFuY2hvcnMiLCJjb2RlIiwibG9nIiwiZ2V0Q29kZXMiLCJqb2luIiwiX0xlY3R1cmVNYXBwaW5nIiwiUmVnRXhwIiwiY29kZXNfbGVjdHVyZSIsIkxlY3R1cmVNYXBwZXIiLCJtYXBwaW5nIiwiY29sbGVjdCIsInVuZGVmaW5lZCIsImxlY3R1cmVzIiwiQWN0ZXNEb2N1bWVudGF0aW9uIiwic2FuaXR5Q2hlY2tzIiwidmVyYm9zZSIsImxlY3R1cmUiLCJDTVAiLCJDQyIsIlBST00iLCJBTjIxIiwiQU5MVU5JIiwiUsOpc29sdXRpb24iLCJBTjIwIiwiRVUiLCJJbW11bml0w6kiLCJwcm9jZWR1cmVzIiwiY29kZTJwYXR0ZXJuIiwid2Fsa0ZpbGVzIiwiZGF0YSIsImFjdGlvbiIsImZpbGUiLCJkb3NzaWVyIiwicHJvY2VkdXJlIiwicmVtYXBQcm9jZWR1cmUiLCJwcm9jZWR1cmVQYXJsZW1lbnRhaXJlIiwiYWN0ZXNMZWdpc2xhdGlmcyIsImNvbGxlY3RGaWxlcyIsIl9hY3RlcyIsIl9jMnAiLCJfcGFyZW50IiwicHJvY2Vzc0ZpbGVzIiwiYWN0ZXMiLCJjMnAiLCJwYXJlbnQiLCJtZXJnZSIsInZhbGlkYXRlIiwicmVtYXBBY3RlcyIsInJlc3VsdHMiLCJsZWN0dXJlTWFwcGVyIiwicHVzaCIsImNvbGxlY3RBY3RlcyIsIm1lcmdlX3Byb2NlZHVyZXMiLCJNYXAiLCJyZW1hcHBlZFByb2NlZHVyZXMiLCJnZXQiLCJvcmRlcmVkQ29kZXMiLCJvcmRlcmVkIiwieCIsInZhbGlkYXRlQ2hyb25vbG9neSIsInNlcXVlbmNlIiwibWVyZ2VBY3RlIiwic2hvcnRDb2RlIiwieHNpVHlwZSIsImwiLCJ2YWxpZGF0ZUxldmVsIiwicGF0aCIsImtleSIsInZhbHVlIiwiZW50cmllcyIsImNvbmNhdCIsInByaW50RW50cnkiLCJlbnRyeSIsInRpdGxlIiwidW5kZXJsaW5lIiwibGVuZ3RoIiwiYWRkQW5jaG9ycyIsImFuY2hvcnNQcmludGVkIiwiYW5jaG9ycyIsInJlbmFtZUNNUCIsInN0YXJ0c1dpdGgiLCJlbmRzV2l0aCIsInByaW50TGV2ZWwiLCJrZXlzIiwic3Vic3RyaW5nIiwicHJpbnRDb2RlcyIsInByaW50QW5jaG9yc0luZGV4IiwiZ2V0QWdncmVnYXRlZCIsInJlbWFwcGVkIiwicHJpbnQiLCJhZ2dyZWdhdGVkIiwibWFpbiIsImRvYyIsInByb2Nlc3MiLCJleGl0Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmlwdHMvZG9jdW1lbnRfZG9zc2llcnNfbGVnaXNsYXRpZnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IGNvbW1hbmRMaW5lQXJncyBmcm9tIFwiY29tbWFuZC1saW5lLWFyZ3NcIlxuaW1wb3J0IGNvbW1hbmRMaW5lVXNhZ2UgZnJvbSBcImNvbW1hbmQtbGluZS11c2FnZVwiXG5pbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIlxuaW1wb3J0IHsgbG9hZCwgZ2V0RmlsZXMgfSBmcm9tIFwiLi4vZmlsZV9zeXN0ZW1zXCJcblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKTogYW55IHtcbiAgY29uc3Qgb3B0aW9uc0RlZmluaXRpb25zID0gW1xuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcInBhdGhuYW1lIHRvIGEgSlNPTiBmaWxlIG9yIGEgZ2xvYiBwYXR0ZXJuIHRvIEpTT04gZmlsZXNcIixcbiAgICAgIGRlZmF1bHRPcHRpb246IHRydWUsXG4gICAgICBtdWx0aXBsZTogdHJ1ZSxcbiAgICAgIG5hbWU6IFwiZGF0YVwiLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0sXG4gICAge1xuICAgICAgbmFtZTogXCJuby1zYW5pdHktY2hlY2tzXCIsXG4gICAgICB0eXBlOiBCb29sZWFuLFxuICAgICAgZGVzY3JpcHRpb246IFwiRG8gbm90IHBlcmZvcm0gc2FuaXR5IGNoZWNrcy5cIixcbiAgICB9LFxuICAgIHtcbiAgICAgIG5hbWU6IFwidmVyYm9zZVwiLFxuICAgICAgdHlwZTogQm9vbGVhbixcbiAgICAgIGRlc2NyaXB0aW9uOiBcImluY3JlYXNlIHZlcmJvc2l0eVwiLFxuICAgIH0sXG4gICAge1xuICAgICAgbmFtZTogXCJoZWxwXCIsXG4gICAgICBkZXNjcmlwdGlvbjogXCJQcmludCB0aGlzIHVzYWdlIGd1aWRlLlwiLFxuICAgIH0sXG4gIF1cbiAgY29uc3Qgc2VjdGlvbnMgPSBbXG4gICAge1xuICAgICAgaGVhZGVyOiBcIkFpZGUgw6AgbGEgZG9jdW1lbnRhdGlvbiBkdSBkb3NzaWVyIGzDqWdpc2xhdGlmXCIsXG4gICAgICBjb250ZW50OiBcIkfDqW7DqHJlIHVuZSBoacOpcmFyY2hpZSBkZXMgYWN0ZXMgbMOpZ2lzbGF0aWZzXCIsXG4gICAgfSxcbiAgICB7XG4gICAgICBoZWFkZXI6IFwiT3B0aW9uc1wiLFxuICAgICAgb3B0aW9uTGlzdDogb3B0aW9uc0RlZmluaXRpb25zLFxuICAgIH0sXG4gIF1cbiAgY29uc3Qgb3B0aW9ucyA9IGNvbW1hbmRMaW5lQXJncyhvcHRpb25zRGVmaW5pdGlvbnMsIHtcbiAgICBhcmd2OiBhcmd2LFxuICB9KVxuICBpZiAoIShcImhlbHBcIiBpbiBvcHRpb25zKSAmJiAhKFwiZGF0YVwiIGluIG9wdGlvbnMpKSB7XG4gICAgY29uc29sZS5lcnJvcihcIi0tZGF0YSBpcyBtYW5kYXRvcnlcIilcbiAgICBvcHRpb25zLmhlbHAgPSB0cnVlXG4gIH1cbiAgaWYgKFwiaGVscFwiIGluIG9wdGlvbnMpIHtcbiAgICBjb25zdCB1c2FnZSA9IGNvbW1hbmRMaW5lVXNhZ2Uoc2VjdGlvbnMpXG4gICAgY29uc29sZS53YXJuKHVzYWdlKVxuICAgIHJldHVybiBudWxsXG4gIH1cbiAgcmV0dXJuIG9wdGlvbnNcbn1cblxuZnVuY3Rpb24gZXFTZXQoYXM6IFNldDxzdHJpbmc+LCBiczogU2V0PHN0cmluZz4pOiBib29sZWFuIHtcbiAgaWYgKGFzLnNpemUgIT09IGJzLnNpemUpIHJldHVybiBmYWxzZVxuICBmb3IgKHZhciBhIG9mIGFzKSBpZiAoIWJzLmhhcyhhKSkgcmV0dXJuIGZhbHNlXG4gIHJldHVybiB0cnVlXG59XG5cbmNsYXNzIENvZGUyUGF0dGVybiB7XG4gIF9wYXR0ZXJuXzogYW55XG4gIF9tYXRjaF9jb3VudF86IG51bWJlclxuICBjb25zdHJ1Y3RvcihwYXR0ZXJuOiBhbnksIGNoaWxkcmVuOiBhbnkpIHtcbiAgICB0aGlzLl9wYXR0ZXJuXyA9IHBhdHRlcm5cbiAgICB0aGlzLl9tYXRjaF9jb3VudF8gPSAwXG4gICAgT2JqZWN0LmFzc2lnbih0aGlzLCBjaGlsZHJlbilcbiAgfVxufVxuXG5jbGFzcyBDb2RlMlBhdHRlcm5Db21Gb25kIGV4dGVuZHMgQ29kZTJQYXR0ZXJuIHtcbiAgY29uc3RydWN0b3IoKSB7XG4gICAgc3VwZXIoXCJeL1NBSVNJRS8oL05PTUlOLykqKC9SRVVOSU9OLykqKC9SQVBQT1JULykqJFwiLCB7fSlcbiAgfVxufVxuXG5jbGFzcyBMZWN0dXJlTWFwcGluZyB7XG4gIGxpYmVsbGU6IGFueSA9IHt9XG4gIGNvZGVzOiBhbnkgPSBuZXcgU2V0KClcblxuICBzdGF0aWMgY29kZXNfbGVjdHVyZTogc3RyaW5nW10gPSBbXG4gICAgXCJBTjFcIixcbiAgICBcIlNOMVwiLFxuICAgIFwiQU5OTEVDXCIsXG4gICAgXCJTTk5MRUNcIixcbiAgICBcIkFOTERFRlwiLFxuICAgIFwiQU4yXCIsXG4gICAgXCJTTjJcIixcbiAgICBcIlNOM1wiLFxuICBdXG4gIHN0YXRpYyBjb2Rlc19sZWN0dXJlX3JlZ2V4cDogYW55ID0gbmV3IFJlZ0V4cChcbiAgICBcIl4oPzpcIiArIExlY3R1cmVNYXBwaW5nLmNvZGVzX2xlY3R1cmUuam9pbihcInxcIikgKyBcIikoLS4qKT8kXCIsXG4gIClcblxuICBzdGF0aWMgaXNMZWN0dXJlKGFjdGU6IGFueSkge1xuICAgIHJldHVybiBhY3RlLmNvZGVBY3RlLm1hdGNoKExlY3R1cmVNYXBwaW5nLmNvZGVzX2xlY3R1cmVfcmVnZXhwKVxuICB9XG5cbiAgc3RhdGljIGdldFR5cGUoYWN0ZTogYW55KSB7XG4gICAgaWYgKGFjdGUuY29kZUFjdGUubWF0Y2goL15BTi8pKSByZXR1cm4gXCJBTlwiXG4gICAgZWxzZSBpZiAoYWN0ZS5jb2RlQWN0ZS5tYXRjaCgvXlNOLykpIHJldHVybiBcIlNOXCJcbiAgICBlbHNlIHRocm93IEVycm9yKGAke2FjdGUuY29kZUFjdGV9IGRvZXMgbm90IHN0YXJ0IHdpdGggQU4gb3IgU05gKVxuICB9XG5cbiAgc3RhdGljIG1hcChjb2RlQWN0ZTogYW55KSB7XG4gICAgcmV0dXJuIGNvZGVBY3RlLnJlcGxhY2UoTGVjdHVyZU1hcHBpbmcuY29kZXNfbGVjdHVyZV9yZWdleHAsIGBsZWN0dXJlJDFgKVxuICB9XG5cbiAgc3RhdGljIGdldENvZGVBY3RlKGFjdGU6IGFueSkge1xuICAgIGlmICghTGVjdHVyZU1hcHBpbmcuaXNMZWN0dXJlKGFjdGUpKSByZXR1cm5cblxuICAgIHJldHVybiBMZWN0dXJlTWFwcGluZy5tYXAoYWN0ZS5jb2RlQWN0ZSlcbiAgfVxuXG4gIGFkZChhY3RlOiBhbnkpIHtcbiAgICB0aGlzLmNvZGVzLmFkZChhY3RlLmNvZGVBY3RlKVxuXG4gICAgY29uc3QgdHlwZSA9IExlY3R1cmVNYXBwaW5nLmdldFR5cGUoYWN0ZSlcblxuICAgIGlmICghKGFjdGUubGliZWxsZUFjdGUubm9tQ2Fub25pcXVlIGluIHRoaXMubGliZWxsZSkpXG4gICAgICB0aGlzLmxpYmVsbGVbYWN0ZS5saWJlbGxlQWN0ZS5ub21DYW5vbmlxdWVdID0gbmV3IFNldCgpXG4gICAgdGhpcy5saWJlbGxlW2FjdGUubGliZWxsZUFjdGUubm9tQ2Fub25pcXVlXS5hZGQodHlwZSlcbiAgfVxuXG4gIHJlbWFwKGFjdGU6IGFueSwgY29kZUFjdGU6IHN0cmluZykge1xuICAgIGFjdGUuY29kZUFjdGUgPSBjb2RlQWN0ZVxuXG4gICAgbGV0IHR5cGVzID0gdGhpcy5saWJlbGxlW2FjdGUubGliZWxsZUFjdGUubm9tQ2Fub25pcXVlXVxuICAgIGlmICghKHR5cGVzLmhhcyhcIlNOXCIpICYmIHR5cGVzLmhhcyhcIkFOXCIpKSkge1xuICAgICAgaWYgKHR5cGVzLmhhcyhcIlNOXCIpKSBhY3RlLmxpYmVsbGVBY3RlLm5vbUNhbm9uaXF1ZSArPSBcIiAoU8OpbmF0KVwiXG4gICAgICBlbHNlIGlmICh0eXBlcy5oYXMoXCJBTlwiKSlcbiAgICAgICAgYWN0ZS5saWJlbGxlQWN0ZS5ub21DYW5vbmlxdWUgKz0gXCIgKEFzc2VtYmzDqWUgTmF0aW9uYWxlKVwiXG4gICAgfVxuICB9XG5cbiAgbWVyZ2VDb2Rlcyhjb2RlczogYW55KSB7XG4gICAgZm9yIChjb25zdCBjIG9mIEFycmF5LmZyb20odGhpcy5jb2RlcykpIGNvZGVzLmFkZChjKVxuICB9XG5cbiAgcHJpbnRBbmNob3JzKCkge1xuICAgIGZvciAoY29uc3QgY29kZSBvZiBBcnJheS5mcm9tKHRoaXMuY29kZXMpKSBjb25zb2xlLmxvZyhgLi4gXyR7Y29kZX06YClcbiAgfVxuXG4gIGdldENvZGVzKCkge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuY29kZXMpLmpvaW4oXCIsXCIpXG4gIH1cbn1cblxuY2xhc3MgTGVjdHVyZU1hcHBlciB7XG4gIG1hcHBpbmc6IGFueSA9IHt9XG5cbiAgaGFzKGNvZGVBY3RlOiBzdHJpbmcpIHtcbiAgICByZXR1cm4gY29kZUFjdGUgaW4gdGhpcy5tYXBwaW5nXG4gIH1cblxuICBjb2xsZWN0KGFjdGU6IGFueSkge1xuICAgIGNvbnN0IGNvZGVBY3RlID0gTGVjdHVyZU1hcHBpbmcuZ2V0Q29kZUFjdGUoYWN0ZSlcbiAgICBpZiAoY29kZUFjdGUgIT0gdW5kZWZpbmVkKSB7XG4gICAgICBsZXQgbGVjdHVyZXMgPSB0aGlzLm1hcHBpbmdcbiAgICAgIGlmICghKGNvZGVBY3RlIGluIGxlY3R1cmVzKSkgbGVjdHVyZXNbY29kZUFjdGVdID0gbmV3IExlY3R1cmVNYXBwaW5nKClcbiAgICAgIGxlY3R1cmVzW2NvZGVBY3RlXS5hZGQoYWN0ZSlcbiAgICB9XG4gIH1cblxuICByZW1hcChhY3RlOiBhbnkpIHtcbiAgICBjb25zdCBjb2RlQWN0ZSA9IExlY3R1cmVNYXBwaW5nLmdldENvZGVBY3RlKGFjdGUpXG4gICAgaWYgKGNvZGVBY3RlICE9IHVuZGVmaW5lZCkgdGhpcy5tYXBwaW5nW2NvZGVBY3RlXS5yZW1hcChhY3RlLCBjb2RlQWN0ZSlcbiAgfVxuXG4gIG1lcmdlQ29kZXMoY29kZXM6IGFueSwgY29kZUFjdGU6IHN0cmluZykge1xuICAgIHRoaXMubWFwcGluZ1tjb2RlQWN0ZV0ubWVyZ2VDb2Rlcyhjb2RlcylcbiAgfVxuXG4gIHByaW50QW5jaG9ycyhjb2RlQWN0ZTogc3RyaW5nKSB7XG4gICAgdGhpcy5tYXBwaW5nW2NvZGVBY3RlXS5wcmludEFuY2hvcnMoKVxuICB9XG5cbiAgZ2V0Q29kZXMoY29kZUFjdGU6IHN0cmluZykge1xuICAgIHJldHVybiB0aGlzLm1hcHBpbmdbY29kZUFjdGVdLmdldENvZGVzKClcbiAgfVxufVxuXG5jbGFzcyBBY3Rlc0RvY3VtZW50YXRpb24ge1xuICB2ZXJib3NlOiBib29sZWFuXG4gIHNhbml0eUNoZWNrczogYm9vbGVhblxuICBsZWN0dXJlTWFwcGVyOiBhbnkgPSBuZXcgTGVjdHVyZU1hcHBlcigpXG4gIHJlbWFwcGVkUHJvY2VkdXJlczogYW55ID0ge31cbiAgYW5jaG9yc1ByaW50ZWQ6IGFueSA9IHt9XG4gIGFuY2hvcnM6IGFueSA9IG5ldyBTZXQoKVxuICBjb2RlczogYW55ID0ge31cbiAgcHJvY2VkdXJlczogYW55ID0gbnVsbFxuICBjb2RlMnBhdHRlcm46IGFueSA9IG5ldyBDb2RlMlBhdHRlcm4obnVsbCwge1xuICAgIFwiUHJvY8OpZHVyZSBsw6lnaXNsYXRpdmVcIjogbmV3IENvZGUyUGF0dGVybihcbiAgICAgIFwiXigoKC9sZWN0dXJlLykrKXwoKC9sZWN0dXJlLykrL0NNUC8oL2xlY3R1cmUvKSopKSgvQ0MvKT8oL1BST00vKT8oL0FOLUFQUExJLyk/JFwiLFxuICAgICAge1xuICAgICAgICBsZWN0dXJlOiBuZXcgQ29kZTJQYXR0ZXJuKFxuICAgICAgICAgIFwiXigvREVQT1QvKT8oL0RQVExFVFRSRUNULyk/KC9FVEkvKT8oL0FWQ0UvKT8oL0RHVlQvKT8oL0FDSU4vKT8oL01PVElPTi8pKigvUFJPQ0FDQy8pPygvQ09NLyk/KCgvREVCQVRTLykrKT8oL1JUUklOSS8pPyRcIixcbiAgICAgICAgICB7XG4gICAgICAgICAgICBcImxlY3R1cmUtQ09NXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9GT05EL3wvQVZJUy8pKyRcIiwge1xuICAgICAgICAgICAgICBcImxlY3R1cmUtQ09NLUZPTkRcIjogbmV3IENvZGUyUGF0dGVybkNvbUZvbmQoKSxcbiAgICAgICAgICAgICAgXCJsZWN0dXJlLUNPTS1BVklTXCI6IG5ldyBDb2RlMlBhdHRlcm5Db21Gb25kKCksXG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIFwibGVjdHVyZS1ERUJBVFNcIjogbmV3IENvZGUyUGF0dGVybihcbiAgICAgICAgICAgICAgXCJeKC9TRUFOQ0UvKSooKC9NT1RJT04vKT8oL01PVElPTi1WT1RFLykrKT8oL0RFQy8pPyRcIixcbiAgICAgICAgICAgICAge30sXG4gICAgICAgICAgICApLFxuICAgICAgICAgIH0sXG4gICAgICAgICksXG4gICAgICAgIENNUDogbmV3IENvZGUyUGF0dGVybihcbiAgICAgICAgICBcIl4oL0RFUE9UL3wvU0FJU0lFLyl7MSwyfSgvQ09NLyk/KC9ERUMvKT8oL0RFQkFUUy1BTi8vREVCQVRTLVNOLyk/XCIsXG4gICAgICAgICAge1xuICAgICAgICAgICAgXCJDTVAtQ09NXCI6IG5ldyBDb2RlMlBhdHRlcm4oXG4gICAgICAgICAgICAgIFwiXigvTk9NSU4vKT8oL1JBUFBPUlQtQU4vfC9SQVBQT1JULVNOLyl7Mn0kXCIsXG4gICAgICAgICAgICAgIHt9LFxuICAgICAgICAgICAgKSxcbiAgICAgICAgICAgIFwiQ01QLURFQkFUUy1BTlwiOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvU0VBTkNFLykqKC9ERUMvKT8kXCIsIHt9KSxcbiAgICAgICAgICAgIFwiQ01QLURFQkFUUy1TTlwiOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvU0VBTkNFLykqKC9ERUMvKT8kXCIsIHt9KSxcbiAgICAgICAgICB9LFxuICAgICAgICApLFxuICAgICAgICBDQzogbmV3IENvZGUyUGF0dGVybihcIl4oL1NBSVNJRS8pKygvQ09OQ0xVU0lPTi8pPyRcIiwge30pLFxuICAgICAgICBQUk9NOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvUFVCLyk/JFwiLCB7fSksXG4gICAgICAgIFwiQU4tQVBQTElcIjogbmV3IENvZGUyUGF0dGVybihcIl4oL1JBUFBPUlQvKT8kXCIsIHt9KSxcbiAgICAgIH0sXG4gICAgKSxcbiAgICBcIkFsbG9jdXRpb24gZHUgUHLDqXNpZGVudCBkZSBsJ0Fzc2VtYmzDqWUgbmF0aW9uYWxlXCI6IG5ldyBDb2RlMlBhdHRlcm4oXG4gICAgICBcIl4vQU4yMS8kXCIsXG4gICAgICB7XG4gICAgICAgIEFOMjE6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9BUEFOLyk/JFwiLCB7fSksXG4gICAgICB9LFxuICAgICksXG4gICAgXCJSw6lzb2x1dGlvbiBBcnRpY2xlIDM0LTFcIjogbmV3IENvZGUyUGF0dGVybihcIl4oL0FOTFVOSS8pPyRcIiwge1xuICAgICAgQU5MVU5JOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvREVQT1QvKT8oL0RFQkFUUy8pPygvUlRSSU5JLyk/JFwiLCB7XG4gICAgICAgIFwiQU5MVU5JLURFQkFUU1wiOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvU0VBTkNFLykrKC9ERUMvKT8kXCIsIHt9KSxcbiAgICAgIH0pLFxuICAgIH0pLFxuICAgIFLDqXNvbHV0aW9uOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvQU5MVU5JLyk/KC9DQy8pPyRcIiwge1xuICAgICAgQU5MVU5JOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvREVQT1QvKT8oL0NPTS8pPygvREVCQVRTL3wvUlRSSU5JLyk/JFwiLCB7XG4gICAgICAgIFwiQU5MVU5JLUNPTVwiOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvQ0FFLyk/KC9GT05ELyk/JFwiLCB7XG4gICAgICAgICAgXCJBTkxVTkktQ09NLUZPTkRcIjogbmV3IENvZGUyUGF0dGVybkNvbUZvbmQoKSxcbiAgICAgICAgICBcIkFOTFVOSS1DT00tQ0FFXCI6IG5ldyBDb2RlMlBhdHRlcm4oXG4gICAgICAgICAgICBcIl4oL1NBSVNJRS8pPygvTk9NSU4vKT8oL1JFVU5JT04vKT8oL1JBUFBPUlQvKT8oL0RFQy8pPyRcIixcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICksXG4gICAgICAgIH0pLFxuICAgICAgICBcIkFOTFVOSS1ERUJBVFNcIjogbmV3IENvZGUyUGF0dGVybihcIl4oL1NFQU5DRS8pKigvREVDLyk/JFwiLCB7fSksXG4gICAgICB9KSxcbiAgICAgIENDOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvU0FJU0lFLyk/KC9DT05DTFVTSU9OLyk/JFwiLCB7fSksXG4gICAgfSksXG4gICAgXCJSYXBwb3J0IGQnaW5mb3JtYXRpb24gc2FucyBtaXNzaW9uXCI6IG5ldyBDb2RlMlBhdHRlcm4oXG4gICAgICBcIl4oL0FOMjAvKT8oL0VVLyk/JFwiLFxuICAgICAge1xuICAgICAgICBBTjIwOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvUkFQUE9SVC8pPyRcIiwge30pLFxuICAgICAgICBFVTogbmV3IENvZGUyUGF0dGVybihcIl4oL0RFQy8pKyRcIiwge30pLFxuICAgICAgfSxcbiAgICApLFxuICAgIFwiTWlzc2lvbiBkJ2luZm9ybWF0aW9uXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9BTjIwLyk/JFwiLCB7XG4gICAgICBBTjIwOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvTUlTSU5GLyk/JFwiLCB7XG4gICAgICAgIFwiQU4yMC1NSVNJTkZcIjogbmV3IENvZGUyUGF0dGVybihcbiAgICAgICAgICBcIl4oL0NSRUEvKT8oL05PTUlOLyk/KC9SQVBQT1JULyk/JFwiLFxuICAgICAgICAgIHt9LFxuICAgICAgICApLFxuICAgICAgfSksXG4gICAgfSksXG4gICAgXCJDb21taXNzaW9uIGQnZW5xdcOqdGVcIjogbmV3IENvZGUyUGF0dGVybihcIl4oL0FOMjAvKT8kXCIsIHtcbiAgICAgIEFOMjA6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9DT01FTlEvKT8kXCIsIHtcbiAgICAgICAgXCJBTjIwLUNPTUVOUVwiOiBuZXcgQ29kZTJQYXR0ZXJuKFxuICAgICAgICAgIFwiXigvQ1JFQS8pPygvTk9NSU4vKT8oL1JBUFBPUlQvKT8kXCIsXG4gICAgICAgICAge30sXG4gICAgICAgICksXG4gICAgICB9KSxcbiAgICB9KSxcbiAgICBcIkVuZ2FnZW1lbnQgZGUgbGEgcmVzcG9uc2FiaWxpdMOpIGdvdXZlcm5lbWVudGFsZVwiOiBuZXcgQ29kZTJQYXR0ZXJuKFxuICAgICAgXCJeL0FOMjEvJFwiLFxuICAgICAge1xuICAgICAgICBBTjIxOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigoKC9NT1RJT04vKSovREVCQVRTLyl8KC9ER1ZULykpezEsMn0kXCIsIHtcbiAgICAgICAgICBcIkFOMjEtREVCQVRTXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9TRUFOQ0UvKSooL01PVElPTi1WT1RFLykqJFwiLCB7fSksXG4gICAgICAgIH0pLFxuICAgICAgfSxcbiAgICApLFxuICAgIFwiTW90aW9uIHLDqWbDqXJlbmRhaXJlXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9sZWN0dXJlLykrJFwiLCB7XG4gICAgICBsZWN0dXJlOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvREVQT1QvKT8oL0NPTS8pPygvREVCQVRTLyk/JFwiLCB7XG4gICAgICAgIFwibGVjdHVyZS1DT01cIjogbmV3IENvZGUyUGF0dGVybihcIl4oL0ZPTkQvKT8kXCIsIHtcbiAgICAgICAgICBcImxlY3R1cmUtQ09NLUZPTkRcIjogbmV3IENvZGUyUGF0dGVybihcbiAgICAgICAgICAgIFwiXigvU0FJU0lFLyk/KC9OT01JTi8pKigvUkFQUE9SVC8pKiRcIixcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICksXG4gICAgICAgIH0pLFxuICAgICAgICBcImxlY3R1cmUtREVCQVRTXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9ERUMvKT8kXCIsIHt9KSxcbiAgICAgIH0pLFxuICAgIH0pLFxuICAgIEltbXVuaXTDqTogbmV3IENvZGUyUGF0dGVybihcIl4oL0FOTFVOSS8pKyRcIiwge1xuICAgICAgQU5MVU5JOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvREVQT1QvKT8oL0NPTS8pPygvREVCQVRTLyk/KC9SVFJJTkkvKT8kXCIsIHtcbiAgICAgICAgXCJBTkxVTkktQ09NXCI6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9GT05ELyk/JFwiLCB7XG4gICAgICAgICAgXCJBTkxVTkktQ09NLUZPTkRcIjogbmV3IENvZGUyUGF0dGVybihcbiAgICAgICAgICAgIFwiXigvU0FJU0lFLyk/KC9OT01JTi8pKigvUkFQUE9SVC8pKiRcIixcbiAgICAgICAgICAgIHt9LFxuICAgICAgICAgICksXG4gICAgICAgIH0pLFxuICAgICAgICBcIkFOTFVOSS1ERUJBVFNcIjogbmV3IENvZGUyUGF0dGVybihcIl4oL1NFQU5DRS8pPygvREVDLykkXCIsIHt9KSxcbiAgICAgIH0pLFxuICAgIH0pLFxuICAgIFwiUmVzcG9uc2FiaWxpdMOpIHDDqW5hbGUgZHUgcHLDqXNpZGVudCBkZSBsYSByw6lwdWJsaXF1ZVwiOiBuZXcgQ29kZTJQYXR0ZXJuKFxuICAgICAgXCJeL2xlY3R1cmUvJFwiLFxuICAgICAge1xuICAgICAgICBsZWN0dXJlOiBuZXcgQ29kZTJQYXR0ZXJuKFwiXigvREVQT1QvKT8oL1JFQ0JVUkVBVS8pPyRcIiwge30pLFxuICAgICAgfSxcbiAgICApLFxuICAgIFwiUHJvcG9zaXRpb24gZGUgbG9pIHByw6lzZW50w6llIGVuIGFwcGxpY2F0aW9uIGRlIGwnYXJ0aWNsZSAxMSBkZSBsYSBDb25zdGl0dXRpb25cIjpcbiAgICAgIG5ldyBDb2RlMlBhdHRlcm4oXCJeL2xlY3R1cmUvJFwiLCB7XG4gICAgICAgIGxlY3R1cmU6IG5ldyBDb2RlMlBhdHRlcm4oXCJeKC9ERVBPVC8pPyRcIiwge30pLFxuICAgICAgfSksXG4gIH0pXG5cbiAgY29uc3RydWN0b3Ioc2FuaXR5Q2hlY2tzOiBib29sZWFuLCB2ZXJib3NlOiBib29sZWFuID0gZmFsc2UpIHtcbiAgICB0aGlzLnZlcmJvc2UgPSB2ZXJib3NlXG4gICAgdGhpcy5zYW5pdHlDaGVja3MgPSBzYW5pdHlDaGVja3NcbiAgICB0aGlzLnByb2NlZHVyZXMgPSB7fVxuICAgIHRoaXMuY29kZTJwYXR0ZXJuLl9tYXRjaF9jb3VudF8rK1xuICB9XG5cbiAgd2Fsa0ZpbGVzKGRhdGE6IHN0cmluZ1tdLCBhY3Rpb246IGFueSkge1xuICAgIGZvciAoY29uc3QgZmlsZSBvZiBnZXRGaWxlcyhkYXRhKSkge1xuICAgICAgY29uc3QgZG9zc2llciA9IGxvYWQoZmlsZSlcbiAgICAgIGxldCBwcm9jZWR1cmU6IHN0cmluZyA9IHRoaXMucmVtYXBQcm9jZWR1cmUoXG4gICAgICAgIGRvc3NpZXIucHJvY2VkdXJlUGFybGVtZW50YWlyZS5saWJlbGxlLFxuICAgICAgKVxuICAgICAgaWYgKCEocHJvY2VkdXJlIGluIHRoaXMucHJvY2VkdXJlcykpIHRoaXMucHJvY2VkdXJlc1twcm9jZWR1cmVdID0ge31cbiAgICAgIGFjdGlvbihcbiAgICAgICAgdGhpcy5wcm9jZWR1cmVzW3Byb2NlZHVyZV0sXG4gICAgICAgIGRvc3NpZXIuYWN0ZXNMZWdpc2xhdGlmcyxcbiAgICAgICAgdGhpcy5jb2RlMnBhdHRlcm5bcHJvY2VkdXJlXSxcbiAgICAgICAgbnVsbCxcbiAgICAgIClcbiAgICB9XG4gIH1cblxuICBjb2xsZWN0RmlsZXMoZGF0YTogc3RyaW5nW10pIHtcbiAgICB0aGlzLndhbGtGaWxlcyhcbiAgICAgIGRhdGEsXG4gICAgICAoX2FjdGVzOiBhbnksIGFjdGVzTGVnaXNsYXRpZnM6IGFueSwgX2MycDogYW55LCBfcGFyZW50OiBzdHJpbmcpID0+IHtcbiAgICAgICAgdGhpcy5jb2xsZWN0KGFjdGVzTGVnaXNsYXRpZnMpXG4gICAgICB9LFxuICAgIClcbiAgfVxuXG4gIHByb2Nlc3NGaWxlcyhkYXRhOiBzdHJpbmdbXSkge1xuICAgIHRoaXMud2Fsa0ZpbGVzKFxuICAgICAgZGF0YSxcbiAgICAgIChhY3RlczogYW55LCBhY3Rlc0xlZ2lzbGF0aWZzOiBhbnksIGMycDogYW55LCBwYXJlbnQ6IHN0cmluZykgPT4ge1xuICAgICAgICB0aGlzLm1lcmdlKGFjdGVzLCBhY3Rlc0xlZ2lzbGF0aWZzLCBjMnAsIHBhcmVudClcbiAgICAgIH0sXG4gICAgKVxuICAgIGlmICh0aGlzLnNhbml0eUNoZWNrcykgdGhpcy52YWxpZGF0ZSgpXG4gIH1cblxuICByZW1hcEFjdGVzKGFjdGVzOiBhbnkpOiBhbnkge1xuICAgIGxldCByZXN1bHRzID0gW11cbiAgICBmb3IgKGNvbnN0IGFjdGUgb2YgYWN0ZXMpIHtcbiAgICAgIHRoaXMubGVjdHVyZU1hcHBlci5yZW1hcChhY3RlKVxuXG4gICAgICAvLyBDQy1TQUlTSUUtIHN1ZmZpeCBkb2VzIG5vdCBpbXBseSBhIGhpZXJhcmNoeVxuICAgICAgYWN0ZS5jb2RlQWN0ZSA9IGFjdGUuY29kZUFjdGUucmVwbGFjZSgvXkNDLVNBSVNJRS4qLywgXCJDQy1TQUlTSUVcIilcblxuICAgICAgcmVzdWx0cy5wdXNoKGFjdGUpXG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzXG4gIH1cblxuICBjb2xsZWN0QWN0ZXMoYWN0ZXM6IGFueSk6IGFueSB7XG4gICAgbGV0IHJlc3VsdHMgPSBbXVxuICAgIGZvciAoY29uc3QgYWN0ZSBvZiBhY3Rlcykge1xuICAgICAgdGhpcy5sZWN0dXJlTWFwcGVyLmNvbGxlY3QoYWN0ZSlcblxuICAgICAgcmVzdWx0cy5wdXNoKGFjdGUpXG4gICAgfVxuICAgIHJldHVybiByZXN1bHRzXG4gIH1cblxuICByZW1hcFByb2NlZHVyZShwcm9jZWR1cmU6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgbWVyZ2VfcHJvY2VkdXJlczogTWFwPHN0cmluZywgYW55PiA9IG5ldyBNYXAoW1xuICAgICAgW1wiUHJvcG9zaXRpb24gZGUgbG9pIG9yZGluYWlyZVwiLCBcIlByb2PDqWR1cmUgbMOpZ2lzbGF0aXZlXCJdLFxuICAgICAgW1wiUHJvamV0IGRlIGxvaSBvcmRpbmFpcmVcIiwgXCJQcm9jw6lkdXJlIGzDqWdpc2xhdGl2ZVwiXSxcbiAgICAgIFtcbiAgICAgICAgXCJQcm9qZXQgZGUgcmF0aWZpY2F0aW9uIGRlcyB0cmFpdMOpcyBldCBjb252ZW50aW9uc1wiLFxuICAgICAgICBcIlByb2PDqWR1cmUgbMOpZ2lzbGF0aXZlXCIsXG4gICAgICBdLFxuICAgICAgW1wiUHJvamV0IG91IHByb3Bvc2l0aW9uIGRlIGxvaSBvcmdhbmlxdWVcIiwgXCJQcm9jw6lkdXJlIGzDqWdpc2xhdGl2ZVwiXSxcbiAgICAgIFtcbiAgICAgICAgXCJQcm9qZXQgb3UgcHJvcG9zaXRpb24gZGUgbG9pIGNvbnN0aXR1dGlvbm5lbGxlXCIsXG4gICAgICAgIFwiUHJvY8OpZHVyZSBsw6lnaXNsYXRpdmVcIixcbiAgICAgIF0sXG4gICAgICBbXCJQcm9qZXQgZGUgbG9pIGRlIGZpbmFuY2VzIGRlIGwnYW5uw6llXCIsIFwiUHJvY8OpZHVyZSBsw6lnaXNsYXRpdmVcIl0sXG4gICAgICBbXCJQcm9qZXQgZGUgbG9pIGRlIGZpbmFuY2VzIHJlY3RpZmljYXRpdmVcIiwgXCJQcm9jw6lkdXJlIGzDqWdpc2xhdGl2ZVwiXSxcbiAgICAgIFtcbiAgICAgICAgXCJQcm9qZXQgZGUgbG9pIGRlIGZpbmFuY2VtZW50IGRlIGxhIHPDqWN1cml0w6kgc29jaWFsZVwiLFxuICAgICAgICBcIlByb2PDqWR1cmUgbMOpZ2lzbGF0aXZlXCIsXG4gICAgICBdLFxuICAgIF0pXG4gICAgaWYgKG1lcmdlX3Byb2NlZHVyZXMuaGFzKHByb2NlZHVyZSkpIHtcbiAgICAgIHRoaXMucmVtYXBwZWRQcm9jZWR1cmVzW3Byb2NlZHVyZV0gPSBudWxsXG4gICAgICByZXR1cm4gbWVyZ2VfcHJvY2VkdXJlcy5nZXQocHJvY2VkdXJlKVxuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcHJvY2VkdXJlXG4gICAgfVxuICB9XG5cbiAgLy8gcmV0dXJuIHRoZSBjb2RlQWN0ZXMgaW4gdGhlIHNhbWUgb3JkZXIgdGhleSBhcHBlYXIgaW4gdGhlIHJlZ2V4cFxuICBvcmRlcmVkQ29kZXMoY29kZXM6IGFueSwgYzJwOiBhbnksIHBhcmVudDogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICAgIGNvZGVzID0gbmV3IFNldChjb2RlcylcbiAgICBpZiAoIXRoaXMuc2FuaXR5Q2hlY2tzKSByZXR1cm4gY29kZXNcbiAgICBsZXQgb3JkZXJlZCA9IGMycFtcIl9wYXR0ZXJuX1wiXS5tYXRjaChuZXcgUmVnRXhwKFwiLy4qPy9cIiwgXCJnXCIpKVxuICAgIG9yZGVyZWQgPSBvcmRlcmVkLm1hcCgoeDogc3RyaW5nKSA9PiB4LnJlcGxhY2UobmV3IFJlZ0V4cChcIi8oLiopL1wiKSwgXCIkMVwiKSlcbiAgICBpZiAocGFyZW50ICE9IG51bGwpIG9yZGVyZWQgPSBvcmRlcmVkLm1hcCgoeDogc3RyaW5nKSA9PiBgJHtwYXJlbnR9LSR7eH1gKVxuICAgIG9yZGVyZWQgPSBuZXcgU2V0KG9yZGVyZWQpXG4gICAgYXNzZXJ0KGVxU2V0KG9yZGVyZWQsIGNvZGVzKSwgYCR7Wy4uLm9yZGVyZWRdfSAhPSAke1suLi5jb2Rlc119YClcbiAgICByZXR1cm4gb3JkZXJlZFxuICB9XG5cbiAgdmFsaWRhdGVDaHJvbm9sb2d5KGFjdGVzTGVnaXNsYXRpZnM6IGFueSwgYzJwOiBhbnksIHBhcmVudDogc3RyaW5nKTogdm9pZCB7XG4gICAgY29uc3QgcGF0dGVybiA9IGMycFtcIl9wYXR0ZXJuX1wiXVxuICAgIGNvbnN0IHNlcXVlbmNlID0gYWN0ZXNMZWdpc2xhdGlmc1xuICAgICAgLm1hcCgoeDogYW55KSA9PiBgLyR7eC5jb2RlQWN0ZX0vYC5yZXBsYWNlKGAvJHtwYXJlbnR9LWAsIFwiL1wiKSlcbiAgICAgIC5qb2luKFwiXCIpXG4gICAgYXNzZXJ0KFxuICAgICAgc2VxdWVuY2UubWF0Y2gobmV3IFJlZ0V4cChwYXR0ZXJuKSksXG4gICAgICBgJHtwYXR0ZXJufSBkb2VzIG5vdCBtYXRjaCAke3NlcXVlbmNlfWAsXG4gICAgKVxuICAgIGMycC5fbWF0Y2hfY291bnRfKytcbiAgfVxuXG4gIG1lcmdlQWN0ZShhY3RlczogYW55LCBhY3RlOiBhbnksIGMycDogYW55LCBwYXJlbnQ6IHN0cmluZyk6IHZvaWQge1xuICAgIGxldCBjb2RlOiBzdHJpbmcgPSBhY3RlLmNvZGVBY3RlXG4gICAgbGV0IHNob3J0Q29kZTogc3RyaW5nID0gY29kZS5yZXBsYWNlKG5ldyBSZWdFeHAoYF4ke3BhcmVudH0tYCksIFwiXCIpXG4gICAgc2hvcnRDb2RlID0gc2hvcnRDb2RlLnJlcGxhY2UoLy0oQU58U04pJC8sIFwiXCIpXG4gICAgdGhpcy5jb2Rlc1tzaG9ydENvZGVdID0gbnVsbFxuICAgIGxldCBuYW1lOiBzdHJpbmcgPSBhY3RlLmxpYmVsbGVBY3RlLm5vbUNhbm9uaXF1ZVxuICAgIGlmICghKGNvZGUgaW4gYWN0ZXMpKSB7XG4gICAgICBhY3Rlc1tjb2RlXSA9IHtcbiAgICAgICAgdHlwZTogYWN0ZS54c2lUeXBlLFxuICAgICAgICBuYW1lOiBuZXcgU2V0KFtuYW1lXSksXG4gICAgICAgIHNob3J0Q29kZTogc2hvcnRDb2RlLFxuICAgICAgICBhY3Rlczoge30sXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGFjdGVzW2NvZGVdLm5hbWUuYWRkKG5hbWUpXG4gICAgfVxuICAgIGlmIChcImFjdGVzTGVnaXNsYXRpZnNcIiBpbiBhY3RlKVxuICAgICAgdGhpcy5tZXJnZShhY3Rlc1tjb2RlXS5hY3RlcywgYWN0ZS5hY3Rlc0xlZ2lzbGF0aWZzLCBjMnBbY29kZV0sIGNvZGUpXG4gIH1cblxuICBtZXJnZShhY3RlczogYW55LCBhY3Rlc0xlZ2lzbGF0aWZzOiBhbnksIGMycDogYW55LCBwYXJlbnQ6IGFueSk6IHZvaWQge1xuICAgIGNvbnN0IGwgPSB0aGlzLnJlbWFwQWN0ZXMoYWN0ZXNMZWdpc2xhdGlmcylcbiAgICB0aGlzLnZhbGlkYXRlQ2hyb25vbG9neShsLCBjMnAsIHBhcmVudClcbiAgICBmb3IgKGNvbnN0IGFjdGUgb2YgbCkgdGhpcy5tZXJnZUFjdGUoYWN0ZXMsIGFjdGUsIGMycCwgcGFyZW50KVxuICB9XG5cbiAgY29sbGVjdChhY3Rlc0xlZ2lzbGF0aWZzOiBhbnkpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGFjdGUgb2YgdGhpcy5jb2xsZWN0QWN0ZXMoYWN0ZXNMZWdpc2xhdGlmcykpXG4gICAgICBpZiAoXCJhY3Rlc0xlZ2lzbGF0aWZzXCIgaW4gYWN0ZSkgdGhpcy5jb2xsZWN0KGFjdGUuYWN0ZXNMZWdpc2xhdGlmcylcbiAgfVxuXG4gIHZhbGlkYXRlTGV2ZWwoYzJwOiBhbnksIHBhdGg6IGFueSkge1xuICAgIGFzc2VydChjMnAuX21hdGNoX2NvdW50XyA+IDAsIGAke3BhdGh9IGlzIG5ldmVyIHVzZWRgKVxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGMycCkgYXMgW3N0cmluZywgYW55XVtdKSB7XG4gICAgICBpZiAodmFsdWUgIT0gbnVsbCAmJiB2YWx1ZS5jb25zdHJ1Y3Rvci5uYW1lID09IFwiQ29kZTJQYXR0ZXJuXCIpXG4gICAgICAgIHRoaXMudmFsaWRhdGVMZXZlbCh2YWx1ZSwgcGF0aC5jb25jYXQoW2tleV0pKVxuICAgIH1cbiAgfVxuXG4gIHZhbGlkYXRlKCkge1xuICAgIHRoaXMudmFsaWRhdGVMZXZlbCh0aGlzLmNvZGUycGF0dGVybiwgW10pXG4gIH1cblxuICBwcmludEVudHJ5KHNlY3Rpb25zOiBzdHJpbmcsIGVudHJ5OiBzdHJpbmcsIGNvZGVzOiBzdHJpbmcpIHtcbiAgICBjb25zdCB0aXRsZSA9IGBcXGAke2VudHJ5fVxcYF9fYFxuICAgIGNvbnNvbGUubG9nKHRpdGxlKVxuICAgIGNvbnN0IHVuZGVybGluZSA9IG5ldyBBcnJheSh0aXRsZS5sZW5ndGggKyAxKS5qb2luKHNlY3Rpb25zWzBdKVxuICAgIGNvbnNvbGUubG9nKHVuZGVybGluZSlcbiAgICBjb25zb2xlLmxvZyhjb2RlcylcbiAgfVxuXG4gIGFkZEFuY2hvcnMoa2V5OiBzdHJpbmcpIHtcbiAgICBpZiAoa2V5IGluIHRoaXMuYW5jaG9yc1ByaW50ZWQpIHJldHVyblxuICAgIGlmICh0aGlzLmxlY3R1cmVNYXBwZXIuaGFzKGtleSkpXG4gICAgICB0aGlzLmxlY3R1cmVNYXBwZXIubWVyZ2VDb2Rlcyh0aGlzLmFuY2hvcnMsIGtleSlcbiAgICBlbHNlIHRoaXMuYW5jaG9ycy5hZGQoa2V5KVxuICB9XG5cbiAgcHJpbnRBbmNob3JzKGtleTogc3RyaW5nKSB7XG4gICAgaWYgKGtleSBpbiB0aGlzLmFuY2hvcnNQcmludGVkKSByZXR1cm5cbiAgICB0aGlzLmFuY2hvcnNQcmludGVkW2tleV0gPSBudWxsXG4gICAgaWYgKHRoaXMubGVjdHVyZU1hcHBlci5oYXMoa2V5KSkgdGhpcy5sZWN0dXJlTWFwcGVyLnByaW50QW5jaG9ycyhrZXkpXG4gICAgZWxzZSBjb25zb2xlLmxvZyhgLi4gXyR7a2V5fTpgKVxuICB9XG5cbiAgZ2V0Q29kZXMoa2V5OiBzdHJpbmcsIHNob3J0Q29kZTogc3RyaW5nKSB7XG4gICAgaWYgKGtleSBpbiB0aGlzLmFuY2hvcnNQcmludGVkKSByZXR1cm4gYGNmIFxcXFwqJHtzaG9ydENvZGV9XFxcXCpgXG4gICAgaWYgKHRoaXMubGVjdHVyZU1hcHBlci5oYXMoa2V5KSkgcmV0dXJuIHRoaXMubGVjdHVyZU1hcHBlci5nZXRDb2RlcyhrZXkpXG4gICAgZWxzZSByZXR1cm4ga2V5XG4gIH1cblxuICByZW5hbWVDTVAoa2V5OiBzdHJpbmcsIG5hbWU6IHN0cmluZykge1xuICAgIGlmIChrZXkuc3RhcnRzV2l0aChcIkNNUFwiKSkge1xuICAgICAgaWYgKGtleS5lbmRzV2l0aChcIi1TTlwiKSkgcmV0dXJuIGAke25hbWV9IChTw6luYXQpYFxuICAgICAgZWxzZSBpZiAoa2V5LmVuZHNXaXRoKFwiLUFOXCIpKSByZXR1cm4gYCR7bmFtZX0gKEFzc2VtYmzDqWUgTmF0aW9uYWxlKWBcbiAgICAgIGVsc2UgcmV0dXJuIG5hbWVcbiAgICB9IGVsc2UgcmV0dXJuIG5hbWVcbiAgfVxuXG4gIHByaW50TGV2ZWwoYWN0ZXM6IGFueSwgc2VjdGlvbnM6IHN0cmluZywgYzJwOiBhbnksIHBhcmVudDogYW55KSB7XG4gICAgY29uc3Qga2V5czogU2V0PHN0cmluZz4gPSB0aGlzLm9yZGVyZWRDb2RlcyhPYmplY3Qua2V5cyhhY3RlcyksIGMycCwgcGFyZW50KVxuICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXMpIHtcbiAgICAgIGNvbnN0IHZhbHVlID0gYWN0ZXNba2V5XVxuICAgICAgbGV0IG5hbWUgPSBBcnJheS5mcm9tKHZhbHVlLm5hbWUpLmpvaW4oXCIsIFwiKVxuICAgICAgbmFtZSA9IHRoaXMucmVuYW1lQ01QKGtleSwgbmFtZSlcbiAgICAgIGNvbnN0IGNvZGVzID0gdGhpcy5nZXRDb2RlcyhrZXksIHZhbHVlLnNob3J0Q29kZSlcbiAgICAgIHRoaXMuYWRkQW5jaG9ycyhrZXkpXG4gICAgICB0aGlzLnByaW50QW5jaG9ycyhrZXkpXG4gICAgICBjb25zb2xlLmxvZyhcIlwiKVxuICAgICAgdGhpcy5wcmludEVudHJ5KHNlY3Rpb25zLCBgJHtuYW1lfSA8JHt2YWx1ZS5zaG9ydENvZGV9VE9DXz5gLCBjb2RlcylcbiAgICAgIGNvbnNvbGUubG9nKFwiXCIpXG4gICAgICBpZiAoT2JqZWN0LmtleXModmFsdWUuYWN0ZXMpLmxlbmd0aCA+IDApXG4gICAgICAgIHRoaXMucHJpbnRMZXZlbCh2YWx1ZS5hY3Rlcywgc2VjdGlvbnMuc3Vic3RyaW5nKDEpLCBjMnBba2V5XSwga2V5KVxuICAgIH1cbiAgfVxuXG4gIHByaW50Q29kZXMoKSB7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgT2JqZWN0LmtleXModGhpcy5jb2RlcykpXG4gICAgICBjb25zb2xlLmxvZyhgLi4gXyR7a2V5fVRPQzogaHR0cDovL2ApXG4gIH1cblxuICBwcmludEFuY2hvcnNJbmRleCgpIHtcbiAgICBmb3IgKGNvbnN0IGNvZGUgb2YgQXJyYXkuZnJvbSh0aGlzLmFuY2hvcnMpKVxuICAgICAgY29uc29sZS5sb2coYCogOnJlZjpcXGAke2NvZGV9IDwke2NvZGV9PlxcYGApXG4gIH1cblxuICBnZXRBZ2dyZWdhdGVkKHByb2NlZHVyZTogc3RyaW5nKSB7XG4gICAgaWYgKHByb2NlZHVyZSA9PSBcIlByb2PDqWR1cmUgbMOpZ2lzbGF0aXZlXCIpIHtcbiAgICAgIGNvbnN0IHJlbWFwcGVkID0gT2JqZWN0LmtleXModGhpcy5yZW1hcHBlZFByb2NlZHVyZXMpLmpvaW4oXCIsIFwiKVxuICAgICAgcmV0dXJuIGAgKGFncsOpZ2F0aW9uIGRlICR7cmVtYXBwZWR9KWBcbiAgICB9IGVsc2UgcmV0dXJuIFwiXCJcbiAgfVxuXG4gIHByaW50KCk6IHZvaWQge1xuICAgIHRoaXMuYW5jaG9yc1ByaW50ZWQgPSB7fVxuICAgIGZvciAoY29uc3QgW2tleSwgYWN0ZXNdIG9mIE9iamVjdC5lbnRyaWVzKHRoaXMucHJvY2VkdXJlcykgYXMgW1xuICAgICAgc3RyaW5nLFxuICAgICAgYW55LFxuICAgIF1bXSkge1xuICAgICAgY29uc3QgY29kZSA9IGtleS5yZXBsYWNlKC8gKy9nLCBcIl9cIilcbiAgICAgIHRoaXMuY29kZXNbY29kZV0gPSBudWxsXG4gICAgICBjb25zdCBhZ2dyZWdhdGVkID0gdGhpcy5nZXRBZ2dyZWdhdGVkKGtleSlcbiAgICAgIGNvbnN0IHRpdGxlID0gYFxcYCR7a2V5fSA8JHtjb2RlfVRPQ18+XFxgX18ke2FnZ3JlZ2F0ZWR9YFxuICAgICAgY29uc29sZS5sb2codGl0bGUpXG4gICAgICBjb25zdCB1bmRlcmxpbmUgPSBuZXcgQXJyYXkodGl0bGUubGVuZ3RoICsgMSkuam9pbihcIj1cIilcbiAgICAgIGNvbnNvbGUubG9nKHVuZGVybGluZSlcbiAgICAgIHRoaXMucHJpbnRMZXZlbChhY3RlcywgXCItfi4nXCIsIHRoaXMuY29kZTJwYXR0ZXJuW2tleV0sIG51bGwpXG4gICAgfVxuICAgIHRoaXMucHJpbnRDb2RlcygpXG4gICAgdGhpcy5wcmludEFuY2hvcnNJbmRleCgpXG4gIH1cbn1cblxuZnVuY3Rpb24gbWFpbihhcmd2OiBhbnkpOiBudW1iZXIge1xuICBjb25zdCBvcHRpb25zID0gcGFyc2VBcmdzKGFyZ3YpXG4gIGlmIChvcHRpb25zID09PSBudWxsKSByZXR1cm4gMVxuICBsZXQgZG9jID0gbmV3IEFjdGVzRG9jdW1lbnRhdGlvbihcbiAgICAhb3B0aW9uc1tcIm5vLXNhbml0eS1jaGVja3NcIl0sXG4gICAgb3B0aW9ucy52ZXJib3NlLFxuICApXG4gIGRvYy5jb2xsZWN0RmlsZXMob3B0aW9ucy5kYXRhKVxuICBkb2MucHJvY2Vzc0ZpbGVzKG9wdGlvbnMuZGF0YSlcbiAgZG9jLnByaW50KClcbiAgcmV0dXJuIDBcbn1cblxuLyogaXN0YW5idWwgaWdub3JlIGlmICovXG5pZiAocHJvY2Vzcy5hcmd2WzFdLmVuZHNXaXRoKFwiZG9jdW1lbnRfZG9zc2llcnNfbGVnaXNsYXRpZnMudHNcIikpXG4gIHByb2Nlc3MuZXhpdChtYWluKHByb2Nlc3MuYXJndikpXG4iXSwibWFwcGluZ3MiOiI7Ozs7QUFBQSxPQUFPQSxlQUFlLE1BQU0sbUJBQW1CO0FBQy9DLE9BQU9DLGdCQUFnQixNQUFNLG9CQUFvQjtBQUNqRCxPQUFPQyxNQUFNLE1BQU0sUUFBUTtBQUFBLFNBQ2xCQyxJQUFJLEVBQUVDLFFBQVE7QUFFdkIsU0FBU0MsU0FBU0EsQ0FBQ0MsSUFBYyxFQUFPO0VBQ3RDLE1BQU1DLGtCQUFrQixHQUFHLENBQ3pCO0lBQ0VDLFdBQVcsRUFBRSx5REFBeUQ7SUFDdEVDLGFBQWEsRUFBRSxJQUFJO0lBQ25CQyxRQUFRLEVBQUUsSUFBSTtJQUNkQyxJQUFJLEVBQUUsTUFBTTtJQUNaQyxJQUFJLEVBQUVDO0VBQ1IsQ0FBQyxFQUNEO0lBQ0VGLElBQUksRUFBRSxrQkFBa0I7SUFDeEJDLElBQUksRUFBRUUsT0FBTztJQUNiTixXQUFXLEVBQUU7RUFDZixDQUFDLEVBQ0Q7SUFDRUcsSUFBSSxFQUFFLFNBQVM7SUFDZkMsSUFBSSxFQUFFRSxPQUFPO0lBQ2JOLFdBQVcsRUFBRTtFQUNmLENBQUMsRUFDRDtJQUNFRyxJQUFJLEVBQUUsTUFBTTtJQUNaSCxXQUFXLEVBQUU7RUFDZixDQUFDLENBQ0Y7RUFDRCxNQUFNTyxRQUFRLEdBQUcsQ0FDZjtJQUNFQyxNQUFNLEVBQUUsK0NBQStDO0lBQ3ZEQyxPQUFPLEVBQUU7RUFDWCxDQUFDLEVBQ0Q7SUFDRUQsTUFBTSxFQUFFLFNBQVM7SUFDakJFLFVBQVUsRUFBRVg7RUFDZCxDQUFDLENBQ0Y7RUFDRCxNQUFNWSxPQUFPLEdBQUduQixlQUFlLENBQUNPLGtCQUFrQixFQUFFO0lBQ2xERCxJQUFJLEVBQUVBO0VBQ1IsQ0FBQyxDQUFDO0VBQ0YsSUFBSSxFQUFFLE1BQU0sSUFBSWEsT0FBTyxDQUFDLElBQUksRUFBRSxNQUFNLElBQUlBLE9BQU8sQ0FBQyxFQUFFO0lBQ2hEQyxPQUFPLENBQUNDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQztJQUNwQ0YsT0FBTyxDQUFDRyxJQUFJLEdBQUcsSUFBSTtFQUNyQjtFQUNBLElBQUksTUFBTSxJQUFJSCxPQUFPLEVBQUU7SUFDckIsTUFBTUksS0FBSyxHQUFHdEIsZ0JBQWdCLENBQUNjLFFBQVEsQ0FBQztJQUN4Q0ssT0FBTyxDQUFDSSxJQUFJLENBQUNELEtBQUssQ0FBQztJQUNuQixPQUFPLElBQUk7RUFDYjtFQUNBLE9BQU9KLE9BQU87QUFDaEI7QUFFQSxTQUFTTSxLQUFLQSxDQUFDQyxFQUFlLEVBQUVDLEVBQWUsRUFBVztFQUN4RCxJQUFJRCxFQUFFLENBQUNFLElBQUksS0FBS0QsRUFBRSxDQUFDQyxJQUFJLEVBQUUsT0FBTyxLQUFLO0VBQ3JDLEtBQUssSUFBSUMsQ0FBQyxJQUFJSCxFQUFFLEVBQUUsSUFBSSxDQUFDQyxFQUFFLENBQUNHLEdBQUcsQ0FBQ0QsQ0FBQyxDQUFDLEVBQUUsT0FBTyxLQUFLO0VBQzlDLE9BQU8sSUFBSTtBQUNiO0FBRUEsTUFBTUUsWUFBWSxDQUFDO0VBR2pCQyxXQUFXQSxDQUFDQyxPQUFZLEVBQUVDLFFBQWEsRUFBRTtJQUFBQyxlQUFBO0lBQUFBLGVBQUE7SUFDdkMsSUFBSSxDQUFDQyxTQUFTLEdBQUdILE9BQU87SUFDeEIsSUFBSSxDQUFDSSxhQUFhLEdBQUcsQ0FBQztJQUN0QkMsTUFBTSxDQUFDQyxNQUFNLENBQUMsSUFBSSxFQUFFTCxRQUFRLENBQUM7RUFDL0I7QUFDRjtBQUVBLE1BQU1NLG1CQUFtQixTQUFTVCxZQUFZLENBQUM7RUFDN0NDLFdBQVdBLENBQUEsRUFBRztJQUNaLEtBQUssQ0FBQyw4Q0FBOEMsRUFBRSxDQUFDLENBQUMsQ0FBQztFQUMzRDtBQUNGO0FBRUEsTUFBTVMsY0FBYyxDQUFDO0VBQUFULFlBQUE7SUFBQUcsZUFBQSxrQkFDSixDQUFDLENBQUM7SUFBQUEsZUFBQSxnQkFDSixJQUFJTyxHQUFHLENBQUMsQ0FBQztFQUFBO0VBZ0J0QixPQUFPQyxTQUFTQSxDQUFDQyxJQUFTLEVBQUU7SUFDMUIsT0FBT0EsSUFBSSxDQUFDQyxRQUFRLENBQUNDLEtBQUssQ0FBQ0wsY0FBYyxDQUFDTSxvQkFBb0IsQ0FBQztFQUNqRTtFQUVBLE9BQU9DLE9BQU9BLENBQUNKLElBQVMsRUFBRTtJQUN4QixJQUFJQSxJQUFJLENBQUNDLFFBQVEsQ0FBQ0MsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLE9BQU8sSUFBSSxNQUN0QyxJQUFJRixJQUFJLENBQUNDLFFBQVEsQ0FBQ0MsS0FBSyxDQUFDLEtBQUssQ0FBQyxFQUFFLE9BQU8sSUFBSSxNQUMzQyxNQUFNRyxLQUFLLENBQUMsR0FBR0wsSUFBSSxDQUFDQyxRQUFRLCtCQUErQixDQUFDO0VBQ25FO0VBRUEsT0FBT0ssR0FBR0EsQ0FBQ0wsUUFBYSxFQUFFO0lBQ3hCLE9BQU9BLFFBQVEsQ0FBQ00sT0FBTyxDQUFDVixjQUFjLENBQUNNLG9CQUFvQixFQUFFLFdBQVcsQ0FBQztFQUMzRTtFQUVBLE9BQU9LLFdBQVdBLENBQUNSLElBQVMsRUFBRTtJQUM1QixJQUFJLENBQUNILGNBQWMsQ0FBQ0UsU0FBUyxDQUFDQyxJQUFJLENBQUMsRUFBRTtJQUVyQyxPQUFPSCxjQUFjLENBQUNTLEdBQUcsQ0FBQ04sSUFBSSxDQUFDQyxRQUFRLENBQUM7RUFDMUM7RUFFQVEsR0FBR0EsQ0FBQ1QsSUFBUyxFQUFFO0lBQ2IsSUFBSSxDQUFDVSxLQUFLLENBQUNELEdBQUcsQ0FBQ1QsSUFBSSxDQUFDQyxRQUFRLENBQUM7SUFFN0IsTUFBTWpDLElBQUksR0FBRzZCLGNBQWMsQ0FBQ08sT0FBTyxDQUFDSixJQUFJLENBQUM7SUFFekMsSUFBSSxFQUFFQSxJQUFJLENBQUNXLFdBQVcsQ0FBQ0MsWUFBWSxJQUFJLElBQUksQ0FBQ0MsT0FBTyxDQUFDLEVBQ2xELElBQUksQ0FBQ0EsT0FBTyxDQUFDYixJQUFJLENBQUNXLFdBQVcsQ0FBQ0MsWUFBWSxDQUFDLEdBQUcsSUFBSWQsR0FBRyxDQUFDLENBQUM7SUFDekQsSUFBSSxDQUFDZSxPQUFPLENBQUNiLElBQUksQ0FBQ1csV0FBVyxDQUFDQyxZQUFZLENBQUMsQ0FBQ0gsR0FBRyxDQUFDekMsSUFBSSxDQUFDO0VBQ3ZEO0VBRUE4QyxLQUFLQSxDQUFDZCxJQUFTLEVBQUVDLFFBQWdCLEVBQUU7SUFDakNELElBQUksQ0FBQ0MsUUFBUSxHQUFHQSxRQUFRO0lBRXhCLElBQUljLEtBQUssR0FBRyxJQUFJLENBQUNGLE9BQU8sQ0FBQ2IsSUFBSSxDQUFDVyxXQUFXLENBQUNDLFlBQVksQ0FBQztJQUN2RCxJQUFJLEVBQUVHLEtBQUssQ0FBQzdCLEdBQUcsQ0FBQyxJQUFJLENBQUMsSUFBSTZCLEtBQUssQ0FBQzdCLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQyxFQUFFO01BQ3pDLElBQUk2QixLQUFLLENBQUM3QixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUVjLElBQUksQ0FBQ1csV0FBVyxDQUFDQyxZQUFZLElBQUksVUFBVSxNQUMzRCxJQUFJRyxLQUFLLENBQUM3QixHQUFHLENBQUMsSUFBSSxDQUFDLEVBQ3RCYyxJQUFJLENBQUNXLFdBQVcsQ0FBQ0MsWUFBWSxJQUFJLHdCQUF3QjtJQUM3RDtFQUNGO0VBRUFJLFVBQVVBLENBQUNOLEtBQVUsRUFBRTtJQUNyQixLQUFLLE1BQU1PLENBQUMsSUFBSUMsS0FBSyxDQUFDQyxJQUFJLENBQUMsSUFBSSxDQUFDVCxLQUFLLENBQUMsRUFBRUEsS0FBSyxDQUFDRCxHQUFHLENBQUNRLENBQUMsQ0FBQztFQUN0RDtFQUVBRyxZQUFZQSxDQUFBLEVBQUc7SUFDYixLQUFLLE1BQU1DLElBQUksSUFBSUgsS0FBSyxDQUFDQyxJQUFJLENBQUMsSUFBSSxDQUFDVCxLQUFLLENBQUMsRUFBRWxDLE9BQU8sQ0FBQzhDLEdBQUcsQ0FBQyxPQUFPRCxJQUFJLEdBQUcsQ0FBQztFQUN4RTtFQUVBRSxRQUFRQSxDQUFBLEVBQUc7SUFDVCxPQUFPTCxLQUFLLENBQUNDLElBQUksQ0FBQyxJQUFJLENBQUNULEtBQUssQ0FBQyxDQUFDYyxJQUFJLENBQUMsR0FBRyxDQUFDO0VBQ3pDO0FBQ0Y7QUFBQ0MsZUFBQSxHQXRFSzVCLGNBQWM7QUFBQU4sZUFBQSxDQUFkTSxjQUFjLG1CQUllLENBQy9CLEtBQUssRUFDTCxLQUFLLEVBQ0wsUUFBUSxFQUNSLFFBQVEsRUFDUixRQUFRLEVBQ1IsS0FBSyxFQUNMLEtBQUssRUFDTCxLQUFLLENBQ047QUFBQU4sZUFBQSxDQWJHTSxjQUFjLDBCQWNpQixJQUFJNkIsTUFBTSxDQUMzQyxNQUFNLEdBQUc3QixlQUFjLENBQUM4QixhQUFhLENBQUNILElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxVQUNwRCxDQUFDO0FBd0RILE1BQU1JLGFBQWEsQ0FBQztFQUFBeEMsWUFBQTtJQUFBRyxlQUFBLGtCQUNILENBQUMsQ0FBQztFQUFBO0VBRWpCTCxHQUFHQSxDQUFDZSxRQUFnQixFQUFFO0lBQ3BCLE9BQU9BLFFBQVEsSUFBSSxJQUFJLENBQUM0QixPQUFPO0VBQ2pDO0VBRUFDLE9BQU9BLENBQUM5QixJQUFTLEVBQUU7SUFDakIsTUFBTUMsUUFBUSxHQUFHSixjQUFjLENBQUNXLFdBQVcsQ0FBQ1IsSUFBSSxDQUFDO0lBQ2pELElBQUlDLFFBQVEsSUFBSThCLFNBQVMsRUFBRTtNQUN6QixJQUFJQyxRQUFRLEdBQUcsSUFBSSxDQUFDSCxPQUFPO01BQzNCLElBQUksRUFBRTVCLFFBQVEsSUFBSStCLFFBQVEsQ0FBQyxFQUFFQSxRQUFRLENBQUMvQixRQUFRLENBQUMsR0FBRyxJQUFJSixjQUFjLENBQUMsQ0FBQztNQUN0RW1DLFFBQVEsQ0FBQy9CLFFBQVEsQ0FBQyxDQUFDUSxHQUFHLENBQUNULElBQUksQ0FBQztJQUM5QjtFQUNGO0VBRUFjLEtBQUtBLENBQUNkLElBQVMsRUFBRTtJQUNmLE1BQU1DLFFBQVEsR0FBR0osY0FBYyxDQUFDVyxXQUFXLENBQUNSLElBQUksQ0FBQztJQUNqRCxJQUFJQyxRQUFRLElBQUk4QixTQUFTLEVBQUUsSUFBSSxDQUFDRixPQUFPLENBQUM1QixRQUFRLENBQUMsQ0FBQ2EsS0FBSyxDQUFDZCxJQUFJLEVBQUVDLFFBQVEsQ0FBQztFQUN6RTtFQUVBZSxVQUFVQSxDQUFDTixLQUFVLEVBQUVULFFBQWdCLEVBQUU7SUFDdkMsSUFBSSxDQUFDNEIsT0FBTyxDQUFDNUIsUUFBUSxDQUFDLENBQUNlLFVBQVUsQ0FBQ04sS0FBSyxDQUFDO0VBQzFDO0VBRUFVLFlBQVlBLENBQUNuQixRQUF