UNPKG

@tricoteuses/assemblee

Version:

Retrieve, clean up & handle French Assemblée nationale's open data

517 lines (515 loc) 104 kB
import assert from "assert"; import commandLineArgs from "command-line-args"; import fs from "fs-extra"; import path from "path"; import { datasets, DatasetStructure, EnabledDatasets, getEnabledDatasets, filterByLegislature } from "../datasets.mjs"; import { existingDateToJson, patchedDateToJson } from "../dates.mjs"; import * as git from "../git.mjs"; import { walkDir } from "../file_systems.mjs"; import { pathFromCompteRenduUid, pathFromDocumentUid, pathFromDossierParlementaireUid, pathFromQuestionUid, pathFromReunionUid, pathFromScrutinUid } from "../loaders.mjs"; import { Convert as ActeursEtOrganesRawConvert } from "../raw_types/acteurs_et_organes.mjs"; import { Convert as AgendasRawConvert } from "../raw_types/agendas.mjs"; import { Convert as AmendementsRawConvert } from "../raw_types/amendements.mjs"; import { Convert as DossiersLegislatifsRawConvert } from "../raw_types/dossiers_legislatifs.mjs"; import { Convert as ScrutinsRawConvert } from "../raw_types/scrutins.mjs"; import { Convert as QuestionsRawConvert } from "../raw_types/questions.mjs"; import { Convert as ComptesRendusRawConvert } from "../raw_types/debats.mjs"; import { cloneOption, commitOption, categoriesOption, legislatureOption, remoteOption, silentOption, verboseOption, dataDirDefaultOption, pullOption, fetchDocumentsOption, parseDocumentsOption, documentFormatOption } from "./shared/cli_helpers.mjs"; function parseArgs(argv) { const optionsDefinitions = [cloneOption, commitOption, categoriesOption, legislatureOption, remoteOption, silentOption, verboseOption, dataDirDefaultOption, fetchDocumentsOption, parseDocumentsOption, documentFormatOption, pullOption, { alias: "V", help: "don't validate raw data", name: "no-validate-raw", type: Boolean }]; const options = commandLineArgs(optionsDefinitions, { argv: argv }); return options; } function clearDirectory(dirPath) { fs.ensureDirSync(dirPath); for (const filename of fs.readdirSync(dirPath)) { if (!filename.startsWith(".")) { fs.removeSync(path.join(dirPath, filename)); } } } function cloneGit(gitGroupUrl, datasetName, dataDir) { git.clone(gitGroupUrl, datasetName, dataDir); } function reorganizeData(options) { const dataDir = options.dataDir; Date.prototype.toJSON = patchedDateToJson; let exitCode = options.commit ? 10 : 0; const gitGroupUrl = options.clone?.trim().replace(/\/+$/, ""); const validateRawData = !options["no-validate-raw"]; const enabledDatasets = getEnabledDatasets(options.categories); let chosenDatasets = filterByLegislature(datasets, options.legislature); function commitGit(datasetReorganizedDir, options) { if (options.commit) { const errorCode = git.commitAndPush(datasetReorganizedDir, "Nouvelle moisson", options.remote); if (exitCode === 10 && errorCode !== 10 || exitCode === 0 && errorCode !== 0 && errorCode !== 10) { exitCode = errorCode; } } } if (enabledDatasets & EnabledDatasets.ActeursEtOrganes) { for (const dataset of chosenDatasets.acteursEtOrganes) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); if (options.pull) { git.resetAndPull(datasetReorganizedDir); } clearDirectory(datasetReorganizedDir); const acteursReorganizedDir = path.join(datasetReorganizedDir, "acteurs"); fs.mkdirSync(acteursReorganizedDir); const organesReorganizedDir = path.join(datasetReorganizedDir, "organes"); fs.mkdirSync(organesReorganizedDir); switch (dataset.structure) { case DatasetStructure.SingleFile: { const originalJson = fs.readFileSync(originalJsonDirectoryOrFilePath, { encoding: "utf8" }); const originalData = validateRawData ? ActeursEtOrganesRawConvert.toActeursEtOrganes(originalJson) : JSON.parse(originalJson); for (const acteur of originalData.export.acteurs.acteur) { const reorganizedJsonFilePath = path.join(acteursReorganizedDir, acteur.uid["#text"] + ".json"); fs.writeFileSync(reorganizedJsonFilePath, JSON.stringify(acteur, null, 2), { encoding: "utf8" }); } for (const organe of originalData.export.organes.organe) { const reorganizedJsonFilePath = path.join(organesReorganizedDir, organe.uid + ".json"); fs.writeFileSync(reorganizedJsonFilePath, JSON.stringify(organe, null, 2), { encoding: "utf8" }); } } break; case DatasetStructure.SegmentedFiles: { const deportsByActeurUid = {}; if (fs.existsSync(path.join(originalJsonDirectoryOrFilePath, "deport"))) { for (const deportSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["deport"])) { const deportFilename = deportSplitPath[deportSplitPath.length - 1]; if (!deportFilename.endsWith(".json")) { continue; } const deportOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...deportSplitPath); if (options.verbose) { console.log(` Loading "deport" file: ${deportOriginalFilePath}…`); } const deportOriginalJson = fs.readFileSync(deportOriginalFilePath, { encoding: "utf8" }); const deportOriginal = validateRawData ? ActeursEtOrganesRawConvert.toDeport(deportOriginalJson) : JSON.parse(deportOriginalJson); const deport = deportOriginal.deport; let deports = deportsByActeurUid[deport.acteurRef]; if (deports === undefined) { deports = deportsByActeurUid[deport.acteurRef] = []; } deports.push(deport); } for (const deports of Object.values(deportsByActeurUid)) { deports.sort((a, b) => a.uid.length === b.uid.length ? a.uid.localeCompare(b.uid) : a.uid.length - b.uid.length); } } const mandatsByActeurUid = {}; if (fs.existsSync(path.join(originalJsonDirectoryOrFilePath, "mandat"))) { for (const mandatSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["mandat"])) { const mandatFilename = mandatSplitPath[mandatSplitPath.length - 1]; if (!mandatFilename.endsWith(".json")) { continue; } const mandatOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...mandatSplitPath); if (options.verbose) { console.log(` Loading "mandat" file: ${mandatOriginalFilePath}…`); } const mandatOriginalJson = fs.readFileSync(mandatOriginalFilePath, { encoding: "utf8" }); const mandatOriginal = validateRawData ? ActeursEtOrganesRawConvert.toMandatWrapper(mandatOriginalJson) : JSON.parse(mandatOriginalJson); const mandat = mandatOriginal.mandat; let mandats = mandatsByActeurUid[mandat.acteurRef]; if (mandats === undefined) { mandats = mandatsByActeurUid[mandat.acteurRef] = []; } mandats.push(mandat); } for (const mandats of Object.values(mandatsByActeurUid)) { mandats.sort((a, b) => a.uid.length === b.uid.length ? a.uid.localeCompare(b.uid) : a.uid.length - b.uid.length); } } for (const acteurSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["acteur"])) { const acteurFilename = acteurSplitPath[acteurSplitPath.length - 1]; if (!acteurFilename.endsWith(".json")) { continue; } const acteurOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...acteurSplitPath); if (options.verbose) { console.log(` Reorganizing "acteur" file: ${acteurOriginalFilePath}…`); } const acteurOriginalJson = fs.readFileSync(acteurOriginalFilePath, { encoding: "utf8" }); const acteurOriginal = validateRawData ? ActeursEtOrganesRawConvert.toActeur(acteurOriginalJson) : JSON.parse(acteurOriginalJson); const acteur = acteurOriginal.acteur; const acteurUid = acteur.uid["#text"]; const deports = deportsByActeurUid[acteurUid]; if (deports !== undefined) { assert.strictEqual(acteur.deports, undefined); acteur.deports = { deport: deports }; } const mandats = mandatsByActeurUid[acteurUid]; if (mandats !== undefined) { assert.strictEqual(acteur.mandats, undefined); acteur.mandats = { mandat: mandats }; } const acteurReorganizedJsonFilePath = path.join(acteursReorganizedDir, acteurUid + ".json"); fs.writeFileSync(acteurReorganizedJsonFilePath, JSON.stringify(acteur, null, 2), { encoding: "utf8" }); } for (const organeSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["organe"])) { const organeFilename = organeSplitPath[organeSplitPath.length - 1]; if (!organeFilename.endsWith(".json")) { continue; } const organeOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...organeSplitPath); if (options.verbose) { console.log(` Reorganizing "organe" file: ${organeOriginalFilePath}…`); } const organeOriginalJson = fs.readFileSync(organeOriginalFilePath, { encoding: "utf8" }); const organeOriginal = validateRawData ? ActeursEtOrganesRawConvert.toOrgane(organeOriginalJson) : JSON.parse(organeOriginalJson); const organe = organeOriginal.organe; const organeReorganizedJsonFilePath = path.join(organesReorganizedDir, organe.uid + ".json"); fs.writeFileSync(organeReorganizedJsonFilePath, JSON.stringify(organe, null, 2), { encoding: "utf8" }); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.Agendas) { for (const dataset of chosenDatasets.agendas) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); switch (dataset.structure) { case DatasetStructure.SingleFile: { const originalJson = fs.readFileSync(originalJsonDirectoryOrFilePath, { encoding: "utf8" }); const originalData = validateRawData ? AgendasRawConvert.toAgendas(originalJson) : JSON.parse(originalJson); for (const reunion of originalData.reunions.reunion) { writeReorganizedJson(datasetReorganizedDir, reunion, pathFromReunionUid); } } break; case DatasetStructure.SegmentedFiles: { for (const reunionSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["reunion"])) { const reunionFilename = reunionSplitPath[reunionSplitPath.length - 1]; if (!reunionFilename.endsWith(".json")) { continue; } const reunionOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...reunionSplitPath); if (options.verbose) { console.log(` Reorganizing "reunion" file: ${reunionOriginalFilePath}…`); } const reunionOriginalJson = fs.readFileSync(reunionOriginalFilePath, { encoding: "utf8" }); const reunionOriginal = validateRawData ? AgendasRawConvert.toReunion(reunionOriginalJson) : JSON.parse(reunionOriginalJson); const reunion = reunionOriginal.reunion; writeReorganizedJson(datasetReorganizedDir, reunion, pathFromReunionUid); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.Amendements) { for (const dataset of chosenDatasets.amendements) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); switch (dataset.structure) { case DatasetStructure.SingleFile: { const originalJson = fs.readFileSync(originalJsonDirectoryOrFilePath, { encoding: "utf8" }); const originalData = validateRawData ? AmendementsRawConvert.toAmendements(originalJson) : JSON.parse(originalJson); for (const texteLegislatif of originalData.textesEtAmendements.texteleg) { for (const amendement of texteLegislatif.amendements) { writeAmendementReorganizedJson(datasetReorganizedDir, amendement); } } } break; case DatasetStructure.SegmentedFiles: { for (const amendementSplitPath of walkDir(originalJsonDirectoryOrFilePath)) { const amendementFilename = amendementSplitPath[amendementSplitPath.length - 1]; if (!amendementFilename.endsWith(".json")) { continue; } const amendementOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...amendementSplitPath); if (options.verbose) { console.log(` Reorganizing "amendement" file: ${amendementOriginalFilePath}…`); } const amendementOriginalJson = fs.readFileSync(amendementOriginalFilePath, { encoding: "utf8" }); const amendementOriginal = validateRawData ? AmendementsRawConvert.toAmendementWrapper(amendementOriginalJson) : JSON.parse(amendementOriginalJson); const amendement = amendementOriginal.amendement; writeAmendementReorganizedJson(datasetReorganizedDir, amendement); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.DossiersLegislatifs) { for (const dataset of chosenDatasets.dossiersLegislatifs) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); const documentsDir = path.join(datasetReorganizedDir, "documents"); fs.mkdirSync(documentsDir); const dossiersDir = path.join(datasetReorganizedDir, "dossiers"); fs.mkdirSync(dossiersDir); switch (dataset.structure) { case DatasetStructure.SingleFile: { const originalJson = fs.readFileSync(originalJsonDirectoryOrFilePath, { encoding: "utf8" }); const originalData = validateRawData ? DossiersLegislatifsRawConvert.toDossiersLegislatifs(originalJson) : JSON.parse(originalJson); for (const document of originalData.export.textesLegislatifs.document) { writeReorganizedJson(documentsDir, document, pathFromDocumentUid); } for (const { dossierParlementaire } of originalData.export.dossiersLegislatifs.dossier) { writeReorganizedJson(dossiersDir, dossierParlementaire, pathFromDossierParlementaireUid); } } break; case DatasetStructure.SegmentedFiles: { for (const documentSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["document"])) { const documentFilename = documentSplitPath[documentSplitPath.length - 1]; if (!documentFilename.endsWith(".json")) { continue; } const documentOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...documentSplitPath); if (options.verbose) { console.log(` Reorganizing "document" file: ${documentOriginalFilePath}…`); } const documentOriginalJson = fs.readFileSync(documentOriginalFilePath, { encoding: "utf8" }); const documentOriginal = validateRawData ? DossiersLegislatifsRawConvert.toDocument(documentOriginalJson) : JSON.parse(documentOriginalJson); const document = documentOriginal.document; writeReorganizedJson(documentsDir, document, pathFromDocumentUid); } for (const dossierParlementaireSplitPath of walkDir(originalJsonDirectoryOrFilePath, ["dossierParlementaire"])) { const dossierParlementaireFilename = dossierParlementaireSplitPath[dossierParlementaireSplitPath.length - 1]; if (!dossierParlementaireFilename.endsWith(".json")) { continue; } const dossierParlementaireOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...dossierParlementaireSplitPath); if (options.verbose) { console.log(` Reorganizing "dossierParlementaire" file: ${dossierParlementaireOriginalFilePath}…`); } const dossierParlementaireOriginalJson = fs.readFileSync(dossierParlementaireOriginalFilePath, { encoding: "utf8" }); const dossierParlementaireOriginal = validateRawData ? DossiersLegislatifsRawConvert.toDossierParlementaire(dossierParlementaireOriginalJson) : JSON.parse(dossierParlementaireOriginalJson); const dossierParlementaire = dossierParlementaireOriginal.dossierParlementaire; writeReorganizedJson(dossiersDir, dossierParlementaire, pathFromDossierParlementaireUid); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.Scrutins) { for (let dataset of chosenDatasets.scrutins) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); switch (dataset.structure) { case DatasetStructure.SingleFile: { const originalJson = fs.readFileSync(originalJsonDirectoryOrFilePath, { encoding: "utf8" }); const originalData = validateRawData ? ScrutinsRawConvert.toScrutins(originalJson) : JSON.parse(originalJson); for (const scrutin of originalData.scrutins.scrutin) { writeReorganizedJson(datasetReorganizedDir, scrutin, pathFromScrutinUid); } } break; case DatasetStructure.SegmentedFiles: { for (const scrutinSplitPath of walkDir(originalJsonDirectoryOrFilePath)) { const scrutinFilename = scrutinSplitPath[scrutinSplitPath.length - 1]; if (!scrutinFilename.endsWith(".json")) { continue; } const scrutinOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...scrutinSplitPath); if (options.verbose) { console.log(` Reorganizing "scrutin" file: ${scrutinOriginalFilePath}…`); } const scrutinOriginalJson = fs.readFileSync(scrutinOriginalFilePath, { encoding: "utf8" }); const scrutinOriginal = validateRawData ? ScrutinsRawConvert.toScrutinWrapper(scrutinOriginalJson) : JSON.parse(scrutinOriginalJson); const scrutin = scrutinOriginal.scrutin; writeReorganizedJson(datasetReorganizedDir, scrutin, pathFromScrutinUid); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.Questions) { for (const dataset of datasets.questions) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".json"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); switch (dataset.structure) { case DatasetStructure.SegmentedFiles: { for (const questionSplitPath of walkDir(originalJsonDirectoryOrFilePath)) { const questionFilename = questionSplitPath[questionSplitPath.length - 1]; if (!questionFilename.endsWith(".json")) { continue; } const questionOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...questionSplitPath); if (options.verbose) { console.log(` Reorganizing "question" file: ${questionOriginalFilePath}…`); } const questionOriginalJson = fs.readFileSync(questionOriginalFilePath, { encoding: "utf8" }); const questionOriginal = validateRawData ? QuestionsRawConvert.toQuestionWrapper(questionOriginalJson) : JSON.parse(questionOriginalJson); const question = questionOriginal.question; writeReorganizedJson(datasetReorganizedDir, question, pathFromQuestionUid); } } break; } commitGit(datasetReorganizedDir, options); } } if (enabledDatasets & EnabledDatasets.ComptesRendusSeances) { for (const dataset of datasets.comptesRendusSeances) { const originalJsonDirectoryOrFilePath = path.join(dataDir, dataset.filename); if (!options.silent) { console.log(`Reorganizing ${originalJsonDirectoryOrFilePath}`); } const datasetName = path.basename(originalJsonDirectoryOrFilePath, ".xml"); cloneGit(gitGroupUrl, datasetName, dataDir); const datasetReorganizedDir = path.join(dataDir, datasetName); clearDirectory(datasetReorganizedDir); switch (dataset.structure) { case DatasetStructure.SegmentedFiles: { for (const compteRenduSeanceSplitPath of walkDir(originalJsonDirectoryOrFilePath)) { const compteRenduSeanceFilename = compteRenduSeanceSplitPath[compteRenduSeanceSplitPath.length - 1]; if (!compteRenduSeanceFilename.endsWith(".json")) { continue; } const compteRenduSeanceOriginalFilePath = path.join(originalJsonDirectoryOrFilePath, ...compteRenduSeanceSplitPath); if (options.verbose) { console.log(` Reorganizing "compteRenduSeance" file: ${compteRenduSeanceOriginalFilePath}…`); } const compteRenduSeanceOriginalJson = fs.readFileSync(compteRenduSeanceOriginalFilePath, { encoding: "utf8" }); const compteRenduSeanceOriginal = validateRawData ? ComptesRendusRawConvert.toCompteRenduWrapper(compteRenduSeanceOriginalJson) : JSON.parse(compteRenduSeanceOriginalJson); const compteRenduSeance = compteRenduSeanceOriginal.compteRendu; writeReorganizedJson(datasetReorganizedDir, compteRenduSeance, pathFromCompteRenduUid); } } break; } commitGit(datasetReorganizedDir, options); } } // Restore standard conversion of dates to JSON. Date.prototype.toJSON = existingDateToJson; return exitCode; } function writeAmendementReorganizedJson(datasetReorganizedDir, amendement) { const uidTexteLegislatif = amendement.texteLegislatifRef; assert.notStrictEqual(uidTexteLegislatif, undefined); const texteLegislatifDir = path.join(datasetReorganizedDir, uidTexteLegislatif); fs.ensureDirSync(texteLegislatifDir); const reorganizedJsonFilePath = path.join(texteLegislatifDir, amendement.uid + ".json"); fs.writeFileSync(reorganizedJsonFilePath, JSON.stringify(amendement, null, 2), { encoding: "utf8" }); } function writeReorganizedJson(dir, obj, pathFromUid) { const basename = pathFromUid(dir, obj.uid); fs.writeFileSync(`${basename}.json`, JSON.stringify(obj, null, 2), { encoding: "utf8" }); } function main(argv) { const options = parseArgs(argv); return reorganizeData(options); } /* istanbul ignore if */ if (process.argv[1].endsWith("reorganize_data.ts")) process.exit(main(process.argv)); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJhc3NlcnQiLCJjb21tYW5kTGluZUFyZ3MiLCJmcyIsInBhdGgiLCJkYXRhc2V0cyIsIkRhdGFzZXRTdHJ1Y3R1cmUiLCJFbmFibGVkRGF0YXNldHMiLCJnZXRFbmFibGVkRGF0YXNldHMiLCJmaWx0ZXJCeUxlZ2lzbGF0dXJlIiwiZXhpc3RpbmdEYXRlVG9Kc29uIiwicGF0Y2hlZERhdGVUb0pzb24iLCJnaXQiLCJ3YWxrRGlyIiwicGF0aEZyb21Db21wdGVSZW5kdVVpZCIsInBhdGhGcm9tRG9jdW1lbnRVaWQiLCJwYXRoRnJvbURvc3NpZXJQYXJsZW1lbnRhaXJlVWlkIiwicGF0aEZyb21RdWVzdGlvblVpZCIsInBhdGhGcm9tUmV1bmlvblVpZCIsInBhdGhGcm9tU2NydXRpblVpZCIsIkNvbnZlcnQiLCJBY3RldXJzRXRPcmdhbmVzUmF3Q29udmVydCIsIkFnZW5kYXNSYXdDb252ZXJ0IiwiQW1lbmRlbWVudHNSYXdDb252ZXJ0IiwiRG9zc2llcnNMZWdpc2xhdGlmc1Jhd0NvbnZlcnQiLCJTY3J1dGluc1Jhd0NvbnZlcnQiLCJRdWVzdGlvbnNSYXdDb252ZXJ0IiwiQ29tcHRlc1JlbmR1c1Jhd0NvbnZlcnQiLCJjbG9uZU9wdGlvbiIsImNvbW1pdE9wdGlvbiIsImNhdGVnb3JpZXNPcHRpb24iLCJsZWdpc2xhdHVyZU9wdGlvbiIsInJlbW90ZU9wdGlvbiIsInNpbGVudE9wdGlvbiIsInZlcmJvc2VPcHRpb24iLCJkYXRhRGlyRGVmYXVsdE9wdGlvbiIsInB1bGxPcHRpb24iLCJmZXRjaERvY3VtZW50c09wdGlvbiIsInBhcnNlRG9jdW1lbnRzT3B0aW9uIiwiZG9jdW1lbnRGb3JtYXRPcHRpb24iLCJwYXJzZUFyZ3MiLCJhcmd2Iiwib3B0aW9uc0RlZmluaXRpb25zIiwiYWxpYXMiLCJoZWxwIiwibmFtZSIsInR5cGUiLCJCb29sZWFuIiwib3B0aW9ucyIsImNsZWFyRGlyZWN0b3J5IiwiZGlyUGF0aCIsImVuc3VyZURpclN5bmMiLCJmaWxlbmFtZSIsInJlYWRkaXJTeW5jIiwic3RhcnRzV2l0aCIsInJlbW92ZVN5bmMiLCJqb2luIiwiY2xvbmVHaXQiLCJnaXRHcm91cFVybCIsImRhdGFzZXROYW1lIiwiZGF0YURpciIsImNsb25lIiwicmVvcmdhbml6ZURhdGEiLCJEYXRlIiwicHJvdG90eXBlIiwidG9KU09OIiwiZXhpdENvZGUiLCJjb21taXQiLCJ0cmltIiwicmVwbGFjZSIsInZhbGlkYXRlUmF3RGF0YSIsImVuYWJsZWREYXRhc2V0cyIsImNhdGVnb3JpZXMiLCJjaG9zZW5EYXRhc2V0cyIsImxlZ2lzbGF0dXJlIiwiY29tbWl0R2l0IiwiZGF0YXNldFJlb3JnYW5pemVkRGlyIiwiZXJyb3JDb2RlIiwiY29tbWl0QW5kUHVzaCIsInJlbW90ZSIsIkFjdGV1cnNFdE9yZ2FuZXMiLCJkYXRhc2V0IiwiYWN0ZXVyc0V0T3JnYW5lcyIsIm9yaWdpbmFsSnNvbkRpcmVjdG9yeU9yRmlsZVBhdGgiLCJzaWxlbnQiLCJjb25zb2xlIiwibG9nIiwiYmFzZW5hbWUiLCJwdWxsIiwicmVzZXRBbmRQdWxsIiwiYWN0ZXVyc1Jlb3JnYW5pemVkRGlyIiwibWtkaXJTeW5jIiwib3JnYW5lc1Jlb3JnYW5pemVkRGlyIiwic3RydWN0dXJlIiwiU2luZ2xlRmlsZSIsIm9yaWdpbmFsSnNvbiIsInJlYWRGaWxlU3luYyIsImVuY29kaW5nIiwib3JpZ2luYWxEYXRhIiwidG9BY3RldXJzRXRPcmdhbmVzIiwiSlNPTiIsInBhcnNlIiwiYWN0ZXVyIiwiZXhwb3J0IiwiYWN0ZXVycyIsInJlb3JnYW5pemVkSnNvbkZpbGVQYXRoIiwidWlkIiwid3JpdGVGaWxlU3luYyIsInN0cmluZ2lmeSIsIm9yZ2FuZSIsIm9yZ2FuZXMiLCJTZWdtZW50ZWRGaWxlcyIsImRlcG9ydHNCeUFjdGV1clVpZCIsImV4aXN0c1N5bmMiLCJkZXBvcnRTcGxpdFBhdGgiLCJkZXBvcnRGaWxlbmFtZSIsImxlbmd0aCIsImVuZHNXaXRoIiwiZGVwb3J0T3JpZ2luYWxGaWxlUGF0aCIsInZlcmJvc2UiLCJkZXBvcnRPcmlnaW5hbEpzb24iLCJkZXBvcnRPcmlnaW5hbCIsInRvRGVwb3J0IiwiZGVwb3J0IiwiZGVwb3J0cyIsImFjdGV1clJlZiIsInVuZGVmaW5lZCIsInB1c2giLCJPYmplY3QiLCJ2YWx1ZXMiLCJzb3J0IiwiYSIsImIiLCJsb2NhbGVDb21wYXJlIiwibWFuZGF0c0J5QWN0ZXVyVWlkIiwibWFuZGF0U3BsaXRQYXRoIiwibWFuZGF0RmlsZW5hbWUiLCJtYW5kYXRPcmlnaW5hbEZpbGVQYXRoIiwibWFuZGF0T3JpZ2luYWxKc29uIiwibWFuZGF0T3JpZ2luYWwiLCJ0b01hbmRhdFdyYXBwZXIiLCJtYW5kYXQiLCJtYW5kYXRzIiwiYWN0ZXVyU3BsaXRQYXRoIiwiYWN0ZXVyRmlsZW5hbWUiLCJhY3RldXJPcmlnaW5hbEZpbGVQYXRoIiwiYWN0ZXVyT3JpZ2luYWxKc29uIiwiYWN0ZXVyT3JpZ2luYWwiLCJ0b0FjdGV1ciIsImFjdGV1clVpZCIsInN0cmljdEVxdWFsIiwiYWN0ZXVyUmVvcmdhbml6ZWRKc29uRmlsZVBhdGgiLCJvcmdhbmVTcGxpdFBhdGgiLCJvcmdhbmVGaWxlbmFtZSIsIm9yZ2FuZU9yaWdpbmFsRmlsZVBhdGgiLCJvcmdhbmVPcmlnaW5hbEpzb24iLCJvcmdhbmVPcmlnaW5hbCIsInRvT3JnYW5lIiwib3JnYW5lUmVvcmdhbml6ZWRKc29uRmlsZVBhdGgiLCJBZ2VuZGFzIiwiYWdlbmRhcyIsInRvQWdlbmRhcyIsInJldW5pb24iLCJyZXVuaW9ucyIsIndyaXRlUmVvcmdhbml6ZWRKc29uIiwicmV1bmlvblNwbGl0UGF0aCIsInJldW5pb25GaWxlbmFtZSIsInJldW5pb25PcmlnaW5hbEZpbGVQYXRoIiwicmV1bmlvbk9yaWdpbmFsSnNvbiIsInJldW5pb25PcmlnaW5hbCIsInRvUmV1bmlvbiIsIkFtZW5kZW1lbnRzIiwiYW1lbmRlbWVudHMiLCJ0b0FtZW5kZW1lbnRzIiwidGV4dGVMZWdpc2xhdGlmIiwidGV4dGVzRXRBbWVuZGVtZW50cyIsInRleHRlbGVnIiwiYW1lbmRlbWVudCIsIndyaXRlQW1lbmRlbWVudFJlb3JnYW5pemVkSnNvbiIsImFtZW5kZW1lbnRTcGxpdFBhdGgiLCJhbWVuZGVtZW50RmlsZW5hbWUiLCJhbWVuZGVtZW50T3JpZ2luYWxGaWxlUGF0aCIsImFtZW5kZW1lbnRPcmlnaW5hbEpzb24iLCJhbWVuZGVtZW50T3JpZ2luYWwiLCJ0b0FtZW5kZW1lbnRXcmFwcGVyIiwiRG9zc2llcnNMZWdpc2xhdGlmcyIsImRvc3NpZXJzTGVnaXNsYXRpZnMiLCJkb2N1bWVudHNEaXIiLCJkb3NzaWVyc0RpciIsInRvRG9zc2llcnNMZWdpc2xhdGlmcyIsImRvY3VtZW50IiwidGV4dGVzTGVnaXNsYXRpZnMiLCJkb3NzaWVyUGFybGVtZW50YWlyZSIsImRvc3NpZXIiLCJkb2N1bWVudFNwbGl0UGF0aCIsImRvY3VtZW50RmlsZW5hbWUiLCJkb2N1bWVudE9yaWdpbmFsRmlsZVBhdGgiLCJkb2N1bWVudE9yaWdpbmFsSnNvbiIsImRvY3VtZW50T3JpZ2luYWwiLCJ0b0RvY3VtZW50IiwiZG9zc2llclBhcmxlbWVudGFpcmVTcGxpdFBhdGgiLCJkb3NzaWVyUGFybGVtZW50YWlyZUZpbGVuYW1lIiwiZG9zc2llclBhcmxlbWVudGFpcmVPcmlnaW5hbEZpbGVQYXRoIiwiZG9zc2llclBhcmxlbWVudGFpcmVPcmlnaW5hbEpzb24iLCJkb3NzaWVyUGFybGVtZW50YWlyZU9yaWdpbmFsIiwidG9Eb3NzaWVyUGFybGVtZW50YWlyZSIsIlNjcnV0aW5zIiwic2NydXRpbnMiLCJ0b1NjcnV0aW5zIiwic2NydXRpbiIsInNjcnV0aW5TcGxpdFBhdGgiLCJzY3J1dGluRmlsZW5hbWUiLCJzY3J1dGluT3JpZ2luYWxGaWxlUGF0aCIsInNjcnV0aW5PcmlnaW5hbEpzb24iLCJzY3J1dGluT3JpZ2luYWwiLCJ0b1NjcnV0aW5XcmFwcGVyIiwiUXVlc3Rpb25zIiwicXVlc3Rpb25zIiwicXVlc3Rpb25TcGxpdFBhdGgiLCJxdWVzdGlvbkZpbGVuYW1lIiwicXVlc3Rpb25PcmlnaW5hbEZpbGVQYXRoIiwicXVlc3Rpb25PcmlnaW5hbEpzb24iLCJxdWVzdGlvbk9yaWdpbmFsIiwidG9RdWVzdGlvbldyYXBwZXIiLCJxdWVzdGlvbiIsIkNvbXB0ZXNSZW5kdXNTZWFuY2VzIiwiY29tcHRlc1JlbmR1c1NlYW5jZXMiLCJjb21wdGVSZW5kdVNlYW5jZVNwbGl0UGF0aCIsImNvbXB0ZVJlbmR1U2VhbmNlRmlsZW5hbWUiLCJjb21wdGVSZW5kdVNlYW5jZU9yaWdpbmFsRmlsZVBhdGgiLCJjb21wdGVSZW5kdVNlYW5jZU9yaWdpbmFsSnNvbiIsImNvbXB0ZVJlbmR1U2VhbmNlT3JpZ2luYWwiLCJ0b0NvbXB0ZVJlbmR1V3JhcHBlciIsImNvbXB0ZVJlbmR1U2VhbmNlIiwiY29tcHRlUmVuZHUiLCJ1aWRUZXh0ZUxlZ2lzbGF0aWYiLCJ0ZXh0ZUxlZ2lzbGF0aWZSZWYiLCJub3RTdHJpY3RFcXVhbCIsInRleHRlTGVnaXNsYXRpZkRpciIsImRpciIsIm9iaiIsInBhdGhGcm9tVWlkIiwibWFpbiIsInByb2Nlc3MiLCJleGl0Il0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmlwdHMvcmVvcmdhbml6ZV9kYXRhLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBhc3NlcnQgZnJvbSBcImFzc2VydFwiXG5pbXBvcnQgY29tbWFuZExpbmVBcmdzIGZyb20gXCJjb21tYW5kLWxpbmUtYXJnc1wiXG5pbXBvcnQgZnMgZnJvbSBcImZzLWV4dHJhXCJcbmltcG9ydCBwYXRoIGZyb20gXCJwYXRoXCJcbmltcG9ydCB7XG4gIGRhdGFzZXRzLFxuICBEYXRhc2V0U3RydWN0dXJlLFxuICBFbmFibGVkRGF0YXNldHMsXG4gIGdldEVuYWJsZWREYXRhc2V0cyxcbiAgZmlsdGVyQnlMZWdpc2xhdHVyZSxcbn0gZnJvbSBcIi4uL2RhdGFzZXRzXCJcbmltcG9ydCB7IGV4aXN0aW5nRGF0ZVRvSnNvbiwgcGF0Y2hlZERhdGVUb0pzb24gfSBmcm9tIFwiLi4vZGF0ZXNcIlxuaW1wb3J0ICogYXMgZ2l0IGZyb20gXCIuLi9naXRcIlxuaW1wb3J0IHsgd2Fsa0RpciB9IGZyb20gXCIuLi9maWxlX3N5c3RlbXNcIlxuaW1wb3J0IHtcbiAgcGF0aEZyb21Db21wdGVSZW5kdVVpZCxcbiAgcGF0aEZyb21Eb2N1bWVudFVpZCxcbiAgcGF0aEZyb21Eb3NzaWVyUGFybGVtZW50YWlyZVVpZCxcbiAgcGF0aEZyb21RdWVzdGlvblVpZCxcbiAgcGF0aEZyb21SZXVuaW9uVWlkLFxuICBwYXRoRnJvbVNjcnV0aW5VaWQsXG59IGZyb20gXCIuLi9sb2FkZXJzXCJcbmltcG9ydCB7IENvbnZlcnQgYXMgQWN0ZXVyc0V0T3JnYW5lc1Jhd0NvbnZlcnQgfSBmcm9tIFwiLi4vcmF3X3R5cGVzL2FjdGV1cnNfZXRfb3JnYW5lc1wiXG5pbXBvcnQgeyBDb252ZXJ0IGFzIEFnZW5kYXNSYXdDb252ZXJ0IH0gZnJvbSBcIi4uL3Jhd190eXBlcy9hZ2VuZGFzXCJcbmltcG9ydCB7IENvbnZlcnQgYXMgQW1lbmRlbWVudHNSYXdDb252ZXJ0IH0gZnJvbSBcIi4uL3Jhd190eXBlcy9hbWVuZGVtZW50c1wiXG5pbXBvcnQgeyBDb252ZXJ0IGFzIERvc3NpZXJzTGVnaXNsYXRpZnNSYXdDb252ZXJ0IH0gZnJvbSBcIi4uL3Jhd190eXBlcy9kb3NzaWVyc19sZWdpc2xhdGlmc1wiXG5pbXBvcnQgeyBDb252ZXJ0IGFzIFNjcnV0aW5zUmF3Q29udmVydCB9IGZyb20gXCIuLi9yYXdfdHlwZXMvc2NydXRpbnNcIlxuaW1wb3J0IHsgQ29udmVydCBhcyBRdWVzdGlvbnNSYXdDb252ZXJ0IH0gZnJvbSBcIi4uL3Jhd190eXBlcy9xdWVzdGlvbnNcIlxuaW1wb3J0IHsgQ29udmVydCBhcyBDb21wdGVzUmVuZHVzUmF3Q29udmVydCB9IGZyb20gXCIuLi9yYXdfdHlwZXMvZGViYXRzXCJcbmltcG9ydCB7XG4gIGNsb25lT3B0aW9uLFxuICBjb21taXRPcHRpb24sXG4gIGNhdGVnb3JpZXNPcHRpb24sXG4gIGxlZ2lzbGF0dXJlT3B0aW9uLFxuICByZW1vdGVPcHRpb24sXG4gIHNpbGVudE9wdGlvbixcbiAgdmVyYm9zZU9wdGlvbixcbiAgZGF0YURpckRlZmF1bHRPcHRpb24sXG4gIHB1bGxPcHRpb24sXG4gIGZldGNoRG9jdW1lbnRzT3B0aW9uLFxuICBwYXJzZURvY3VtZW50c09wdGlvbixcbiAgZG9jdW1lbnRGb3JtYXRPcHRpb24sXG59IGZyb20gXCIuL3NoYXJlZC9jbGlfaGVscGVyc1wiXG5cbmZ1bmN0aW9uIHBhcnNlQXJncyhhcmd2OiBzdHJpbmdbXSk6IGFueSB7XG4gIGNvbnN0IG9wdGlvbnNEZWZpbml0aW9ucyA9IFtcbiAgICBjbG9uZU9wdGlvbixcbiAgICBjb21taXRPcHRpb24sXG4gICAgY2F0ZWdvcmllc09wdGlvbixcbiAgICBsZWdpc2xhdHVyZU9wdGlvbixcbiAgICByZW1vdGVPcHRpb24sXG4gICAgc2lsZW50T3B0aW9uLFxuICAgIHZlcmJvc2VPcHRpb24sXG4gICAgZGF0YURpckRlZmF1bHRPcHRpb24sXG4gICAgZmV0Y2hEb2N1bWVudHNPcHRpb24sXG4gICAgcGFyc2VEb2N1bWVudHNPcHRpb24sXG4gICAgZG9jdW1lbnRGb3JtYXRPcHRpb24sXG4gICAgcHVsbE9wdGlvbixcbiAgICB7XG4gICAgICBhbGlhczogXCJWXCIsXG4gICAgICBoZWxwOiBcImRvbid0IHZhbGlkYXRlIHJhdyBkYXRhXCIsXG4gICAgICBuYW1lOiBcIm5vLXZhbGlkYXRlLXJhd1wiLFxuICAgICAgdHlwZTogQm9vbGVhbixcbiAgICB9LFxuICBdXG4gIGNvbnN0IG9wdGlvbnMgPSBjb21tYW5kTGluZUFyZ3Mob3B0aW9uc0RlZmluaXRpb25zLCB7XG4gICAgYXJndjogYXJndixcbiAgfSlcbiAgcmV0dXJuIG9wdGlvbnNcbn1cblxuZnVuY3Rpb24gY2xlYXJEaXJlY3RvcnkoZGlyUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIGZzLmVuc3VyZURpclN5bmMoZGlyUGF0aClcbiAgZm9yIChjb25zdCBmaWxlbmFtZSBvZiBmcy5yZWFkZGlyU3luYyhkaXJQYXRoKSkge1xuICAgIGlmICghZmlsZW5hbWUuc3RhcnRzV2l0aChcIi5cIikpIHtcbiAgICAgIGZzLnJlbW92ZVN5bmMocGF0aC5qb2luKGRpclBhdGgsIGZpbGVuYW1lKSlcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gY2xvbmVHaXQoXG4gIGdpdEdyb3VwVXJsOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4gIGRhdGFzZXROYW1lOiBzdHJpbmcsXG4gIGRhdGFEaXI6IHN0cmluZyxcbik6IHZvaWQge1xuICBnaXQuY2xvbmUoZ2l0R3JvdXBVcmwsIGRhdGFzZXROYW1lLCBkYXRhRGlyKVxufVxuXG5mdW5jdGlvbiByZW9yZ2FuaXplRGF0YShvcHRpb25zOiBhbnkpOiBudW1iZXIge1xuICBjb25zdCBkYXRhRGlyID0gb3B0aW9ucy5kYXRhRGlyXG4gIERhdGUucHJvdG90eXBlLnRvSlNPTiA9IHBhdGNoZWREYXRlVG9Kc29uXG4gIGxldCBleGl0Q29kZSA9IG9wdGlvbnMuY29tbWl0ID8gMTAgOiAwXG4gIGNvbnN0IGdpdEdyb3VwVXJsID0gb3B0aW9ucy5jbG9uZT8udHJpbSgpLnJlcGxhY2UoL1xcLyskLywgXCJcIilcbiAgY29uc3QgdmFsaWRhdGVSYXdEYXRhID0gIW9wdGlvbnNbXCJuby12YWxpZGF0ZS1yYXdcIl1cbiAgY29uc3QgZW5hYmxlZERhdGFzZXRzID0gZ2V0RW5hYmxlZERhdGFzZXRzKG9wdGlvbnMuY2F0ZWdvcmllcylcbiAgbGV0IGNob3NlbkRhdGFzZXRzID0gZmlsdGVyQnlMZWdpc2xhdHVyZShkYXRhc2V0cywgb3B0aW9ucy5sZWdpc2xhdHVyZSlcblxuICBmdW5jdGlvbiBjb21taXRHaXQoZGF0YXNldFJlb3JnYW5pemVkRGlyOiBzdHJpbmcsIG9wdGlvbnM6IGFueSk6IHZvaWQge1xuICAgIGlmIChvcHRpb25zLmNvbW1pdCkge1xuICAgICAgY29uc3QgZXJyb3JDb2RlID0gZ2l0LmNvbW1pdEFuZFB1c2goXG4gICAgICAgIGRhdGFzZXRSZW9yZ2FuaXplZERpcixcbiAgICAgICAgXCJOb3V2ZWxsZSBtb2lzc29uXCIsXG4gICAgICAgIG9wdGlvbnMucmVtb3RlLFxuICAgICAgKVxuICAgICAgaWYgKFxuICAgICAgICAoZXhpdENvZGUgPT09IDEwICYmIGVycm9yQ29kZSAhPT0gMTApIHx8XG4gICAgICAgIChleGl0Q29kZSA9PT0gMCAmJiBlcnJvckNvZGUgIT09IDAgJiYgZXJyb3JDb2RlICE9PSAxMClcbiAgICAgICkge1xuICAgICAgICBleGl0Q29kZSA9IGVycm9yQ29kZVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGlmIChlbmFibGVkRGF0YXNldHMgJiBFbmFibGVkRGF0YXNldHMuQWN0ZXVyc0V0T3JnYW5lcykge1xuICAgIGZvciAoY29uc3QgZGF0YXNldCBvZiBjaG9zZW5EYXRhc2V0cy5hY3RldXJzRXRPcmdhbmVzKSB7XG4gICAgICBjb25zdCBvcmlnaW5hbEpzb25EaXJlY3RvcnlPckZpbGVQYXRoOiBzdHJpbmcgPSBwYXRoLmpvaW4oXG4gICAgICAgIGRhdGFEaXIsXG4gICAgICAgIGRhdGFzZXQuZmlsZW5hbWUsXG4gICAgICApXG4gICAgICBpZiAoIW9wdGlvbnMuc2lsZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBSZW9yZ2FuaXppbmcgJHtvcmlnaW5hbEpzb25EaXJlY3RvcnlPckZpbGVQYXRofWApXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGRhdGFzZXROYW1lID0gcGF0aC5iYXNlbmFtZShcbiAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgXCIuanNvblwiLFxuICAgICAgKVxuICAgICAgY2xvbmVHaXQoZ2l0R3JvdXBVcmwsIGRhdGFzZXROYW1lLCBkYXRhRGlyKVxuXG4gICAgICBjb25zdCBkYXRhc2V0UmVvcmdhbml6ZWREaXIgPSBwYXRoLmpvaW4oZGF0YURpciwgZGF0YXNldE5hbWUpXG4gICAgICBpZiAob3B0aW9ucy5wdWxsKSB7XG4gICAgICAgIGdpdC5yZXNldEFuZFB1bGwoZGF0YXNldFJlb3JnYW5pemVkRGlyKVxuICAgICAgfVxuICAgICAgY2xlYXJEaXJlY3RvcnkoZGF0YXNldFJlb3JnYW5pemVkRGlyKVxuXG4gICAgICBjb25zdCBhY3RldXJzUmVvcmdhbml6ZWREaXIgPSBwYXRoLmpvaW4oZGF0YXNldFJlb3JnYW5pemVkRGlyLCBcImFjdGV1cnNcIilcbiAgICAgIGZzLm1rZGlyU3luYyhhY3RldXJzUmVvcmdhbml6ZWREaXIpXG4gICAgICBjb25zdCBvcmdhbmVzUmVvcmdhbml6ZWREaXIgPSBwYXRoLmpvaW4oZGF0YXNldFJlb3JnYW5pemVkRGlyLCBcIm9yZ2FuZXNcIilcbiAgICAgIGZzLm1rZGlyU3luYyhvcmdhbmVzUmVvcmdhbml6ZWREaXIpXG5cbiAgICAgIHN3aXRjaCAoZGF0YXNldC5zdHJ1Y3R1cmUpIHtcbiAgICAgICAgY2FzZSBEYXRhc2V0U3RydWN0dXJlLlNpbmdsZUZpbGU6XG4gICAgICAgICAge1xuICAgICAgICAgICAgY29uc3Qgb3JpZ2luYWxKc29uOiBzdHJpbmcgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgICAgICAgIG9yaWdpbmFsSnNvbkRpcmVjdG9yeU9yRmlsZVBhdGgsXG4gICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICApXG4gICAgICAgICAgICBjb25zdCBvcmlnaW5hbERhdGE6IGFueSA9IHZhbGlkYXRlUmF3RGF0YVxuICAgICAgICAgICAgICA/IEFjdGV1cnNFdE9yZ2FuZXNSYXdDb252ZXJ0LnRvQWN0ZXVyc0V0T3JnYW5lcyhvcmlnaW5hbEpzb24pXG4gICAgICAgICAgICAgIDogSlNPTi5wYXJzZShvcmlnaW5hbEpzb24pXG5cbiAgICAgICAgICAgIGZvciAoY29uc3QgYWN0ZXVyIG9mIG9yaWdpbmFsRGF0YS5leHBvcnQuYWN0ZXVycy5hY3RldXIpIHtcbiAgICAgICAgICAgICAgY29uc3QgcmVvcmdhbml6ZWRKc29uRmlsZVBhdGg6IHN0cmluZyA9IHBhdGguam9pbihcbiAgICAgICAgICAgICAgICBhY3RldXJzUmVvcmdhbml6ZWREaXIsXG4gICAgICAgICAgICAgICAgYWN0ZXVyLnVpZFtcIiN0ZXh0XCJdICsgXCIuanNvblwiLFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIGZzLndyaXRlRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgcmVvcmdhbml6ZWRKc29uRmlsZVBhdGgsXG4gICAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoYWN0ZXVyLCBudWxsLCAyKSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IG9yZ2FuZSBvZiBvcmlnaW5hbERhdGEuZXhwb3J0Lm9yZ2FuZXMub3JnYW5lKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHJlb3JnYW5pemVkSnNvbkZpbGVQYXRoOiBzdHJpbmcgPSBwYXRoLmpvaW4oXG4gICAgICAgICAgICAgICAgb3JnYW5lc1Jlb3JnYW5pemVkRGlyLFxuICAgICAgICAgICAgICAgIG9yZ2FuZS51aWQgKyBcIi5qc29uXCIsXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgICByZW9yZ2FuaXplZEpzb25GaWxlUGF0aCxcbiAgICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShvcmdhbmUsIG51bGwsIDIpLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIGVuY29kaW5nOiBcInV0ZjhcIixcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIGNhc2UgRGF0YXNldFN0cnVjdHVyZS5TZWdtZW50ZWRGaWxlczpcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjb25zdCBkZXBvcnRzQnlBY3RldXJVaWQ6IHtcbiAgICAgICAgICAgICAgW2FjdGV1clVpZDogc3RyaW5nXTogeyB1aWQ6IHN0cmluZyB9W11cbiAgICAgICAgICAgIH0gPSB7fVxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICBmcy5leGlzdHNTeW5jKFxuICAgICAgICAgICAgICAgIHBhdGguam9pbihvcmlnaW5hbEpzb25EaXJlY3RvcnlPckZpbGVQYXRoLCBcImRlcG9ydFwiKSxcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgZGVwb3J0U3BsaXRQYXRoIG9mIHdhbGtEaXIoXG4gICAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgICBbXCJkZXBvcnRcIl0sXG4gICAgICAgICAgICAgICkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBkZXBvcnRGaWxlbmFtZSA9XG4gICAgICAgICAgICAgICAgICBkZXBvcnRTcGxpdFBhdGhbZGVwb3J0U3BsaXRQYXRoLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgaWYgKCFkZXBvcnRGaWxlbmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBkZXBvcnRPcmlnaW5hbEZpbGVQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgICAgIC4uLmRlcG9ydFNwbGl0UGF0aCxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgIGAgIExvYWRpbmcgXCJkZXBvcnRcIiBmaWxlOiAke2RlcG9ydE9yaWdpbmFsRmlsZVBhdGh94oCmYCxcbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgZGVwb3J0T3JpZ2luYWxKc29uOiBzdHJpbmcgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgICBkZXBvcnRPcmlnaW5hbEZpbGVQYXRoLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBjb25zdCBkZXBvcnRPcmlnaW5hbDogYW55ID0gdmFsaWRhdGVSYXdEYXRhXG4gICAgICAgICAgICAgICAgICA/IEFjdGV1cnNFdE9yZ2FuZXNSYXdDb252ZXJ0LnRvRGVwb3J0KGRlcG9ydE9yaWdpbmFsSnNvbilcbiAgICAgICAgICAgICAgICAgIDogSlNPTi5wYXJzZShkZXBvcnRPcmlnaW5hbEpzb24pXG4gICAgICAgICAgICAgICAgY29uc3QgZGVwb3J0ID0gZGVwb3J0T3JpZ2luYWwuZGVwb3J0XG4gICAgICAgICAgICAgICAgbGV0IGRlcG9ydHMgPSBkZXBvcnRzQnlBY3RldXJVaWRbZGVwb3J0LmFjdGV1clJlZl1cbiAgICAgICAgICAgICAgICBpZiAoZGVwb3J0cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICBkZXBvcnRzID0gZGVwb3J0c0J5QWN0ZXVyVWlkW2RlcG9ydC5hY3RldXJSZWZdID0gW11cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGVwb3J0cy5wdXNoKGRlcG9ydClcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGZvciAoY29uc3QgZGVwb3J0cyBvZiBPYmplY3QudmFsdWVzKGRlcG9ydHNCeUFjdGV1clVpZCkpIHtcbiAgICAgICAgICAgICAgICBkZXBvcnRzLnNvcnQoKGEsIGIpID0+XG4gICAgICAgICAgICAgICAgICBhLnVpZC5sZW5ndGggPT09IGIudWlkLmxlbmd0aFxuICAgICAgICAgICAgICAgICAgICA/IGEudWlkLmxvY2FsZUNvbXBhcmUoYi51aWQpXG4gICAgICAgICAgICAgICAgICAgIDogYS51aWQubGVuZ3RoIC0gYi51aWQubGVuZ3RoLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjb25zdCBtYW5kYXRzQnlBY3RldXJVaWQ6IHtcbiAgICAgICAgICAgICAgW2FjdGV1clVpZDogc3RyaW5nXTogeyB1aWQ6IHN0cmluZyB9W11cbiAgICAgICAgICAgIH0gPSB7fVxuICAgICAgICAgICAgaWYgKFxuICAgICAgICAgICAgICBmcy5leGlzdHNTeW5jKFxuICAgICAgICAgICAgICAgIHBhdGguam9pbihvcmlnaW5hbEpzb25EaXJlY3RvcnlPckZpbGVQYXRoLCBcIm1hbmRhdFwiKSxcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIGZvciAoY29uc3QgbWFuZGF0U3BsaXRQYXRoIG9mIHdhbGtEaXIoXG4gICAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgICBbXCJtYW5kYXRcIl0sXG4gICAgICAgICAgICAgICkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBtYW5kYXRGaWxlbmFtZSA9XG4gICAgICAgICAgICAgICAgICBtYW5kYXRTcGxpdFBhdGhbbWFuZGF0U3BsaXRQYXRoLmxlbmd0aCAtIDFdXG4gICAgICAgICAgICAgICAgaWYgKCFtYW5kYXRGaWxlbmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBtYW5kYXRPcmlnaW5hbEZpbGVQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgICAgIC4uLm1hbmRhdFNwbGl0UGF0aCxcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgICAgICAgICAgIGAgIExvYWRpbmcgXCJtYW5kYXRcIiBmaWxlOiAke21hbmRhdE9yaWdpbmFsRmlsZVBhdGh94oCmYCxcbiAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgbWFuZGF0T3JpZ2luYWxKc29uOiBzdHJpbmcgPSBmcy5yZWFkRmlsZVN5bmMoXG4gICAgICAgICAgICAgICAgICBtYW5kYXRPcmlnaW5hbEZpbGVQYXRoLFxuICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbmNvZGluZzogXCJ1dGY4XCIsXG4gICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBjb25zdCBtYW5kYXRPcmlnaW5hbDogYW55ID0gdmFsaWRhdGVSYXdEYXRhXG4gICAgICAgICAgICAgICAgICA/IEFjdGV1cnNFdE9yZ2FuZXNSYXdDb252ZXJ0LnRvTWFuZGF0V3JhcHBlcihcbiAgICAgICAgICAgICAgICAgICAgICBtYW5kYXRPcmlnaW5hbEpzb24sXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgIDogSlNPTi5wYXJzZShtYW5kYXRPcmlnaW5hbEpzb24pXG4gICAgICAgICAgICAgICAgY29uc3QgbWFuZGF0ID0gbWFuZGF0T3JpZ2luYWwubWFuZGF0XG4gICAgICAgICAgICAgICAgbGV0IG1hbmRhdHMgPSBtYW5kYXRzQnlBY3RldXJVaWRbbWFuZGF0LmFjdGV1clJlZl1cbiAgICAgICAgICAgICAgICBpZiAobWFuZGF0cyA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICBtYW5kYXRzID0gbWFuZGF0c0J5QWN0ZXVyVWlkW21hbmRhdC5hY3RldXJSZWZdID0gW11cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbWFuZGF0cy5wdXNoKG1hbmRhdClcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGZvciAoY29uc3QgbWFuZGF0cyBvZiBPYmplY3QudmFsdWVzKG1hbmRhdHNCeUFjdGV1clVpZCkpIHtcbiAgICAgICAgICAgICAgICBtYW5kYXRzLnNvcnQoKGEsIGIpID0+XG4gICAgICAgICAgICAgICAgICBhLnVpZC5sZW5ndGggPT09IGIudWlkLmxlbmd0aFxuICAgICAgICAgICAgICAgICAgICA/IGEudWlkLmxvY2FsZUNvbXBhcmUoYi51aWQpXG4gICAgICAgICAgICAgICAgICAgIDogYS51aWQubGVuZ3RoIC0gYi51aWQubGVuZ3RoLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKGNvbnN0IGFjdGV1clNwbGl0UGF0aCBvZiB3YWxrRGlyKFxuICAgICAgICAgICAgICBvcmlnaW5hbEpzb25EaXJlY3RvcnlPckZpbGVQYXRoLFxuICAgICAgICAgICAgICBbXCJhY3RldXJcIl0sXG4gICAgICAgICAgICApKSB7XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGV1ckZpbGVuYW1lID0gYWN0ZXVyU3BsaXRQYXRoW2FjdGV1clNwbGl0UGF0aC5sZW5ndGggLSAxXVxuICAgICAgICAgICAgICBpZiAoIWFjdGV1ckZpbGVuYW1lLmVuZHNXaXRoKFwiLmpzb25cIikpIHtcbiAgICAgICAgICAgICAgICBjb250aW51ZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGV1ck9yaWdpbmFsRmlsZVBhdGggPSBwYXRoLmpvaW4oXG4gICAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgICAuLi5hY3RldXJTcGxpdFBhdGgsXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgaWYgKG9wdGlvbnMudmVyYm9zZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgYCAgUmVvcmdhbml6aW5nIFwiYWN0ZXVyXCIgZmlsZTogJHthY3RldXJPcmlnaW5hbEZpbGVQYXRofeKApmAsXG4gICAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGV1ck9yaWdpbmFsSnNvbjogc3RyaW5nID0gZnMucmVhZEZpbGVTeW5jKFxuICAgICAgICAgICAgICAgIGFjdGV1ck9yaWdpbmFsRmlsZVBhdGgsXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgZW5jb2Rpbmc6IFwidXRmOFwiLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgY29uc3QgYWN0ZXVyT3JpZ2luYWw6IGFueSA9IHZhbGlkYXRlUmF3RGF0YVxuICAgICAgICAgICAgICAgID8gQWN0ZXVyc0V0T3JnYW5lc1Jhd0NvbnZlcnQudG9BY3RldXIoYWN0ZXVyT3JpZ2luYWxKc29uKVxuICAgICAgICAgICAgICAgIDogSlNPTi5wYXJzZShhY3RldXJPcmlnaW5hbEpzb24pXG4gICAgICAgICAgICAgIGNvbnN0IGFjdGV1ciA9IGFjdGV1ck9yaWdpbmFsLmFjdGV1clxuICAgICAgICAgICAgICBjb25zdCBhY3RldXJVaWQgPSBhY3RldXIudWlkW1wiI3RleHRcIl1cbiAgICAgICAgICAgICAgY29uc3QgZGVwb3J0cyA9IGRlcG9ydHNCeUFjdGV1clVpZFthY3RldXJVaWRdXG4gICAgICAgICAgICAgIGlmIChkZXBvcnRzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBhc3NlcnQuc3RyaWN0RXF1YWwoYWN0ZXVyLmRlcG9ydHMsIHVuZGVmaW5lZClcbiAgICAgICAgICAgICAgICBhY3RldXIuZGVwb3J0cyA9IHsgZGVwb3J0OiBkZXBvcnRzIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBtYW5kYXRzID0gbWFuZGF0c0J5QWN0ZXVyVWlkW2FjdGV1clVpZF1cbiAgICAgICAgICAgICAgaWYgKG1hbmRhdHMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGFzc2VydC5zdHJpY3RFcXVhbChhY3RldXIubWFuZGF0cywgdW5kZWZpbmVkKVxuICAgICAgICAgICAgICAgIGFjdGV1ci5tYW5kYXRzID0geyBtYW5kYXQ6IG1hbmRhdHMgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGFjdGV1clJlb3JnYW5pemVkSnNvbkZpbGVQYXRoOiBzdHJpbmcgPSBwYXRoLmpvaW4oXG4gICAgICAgICAgICAgICAgYWN0ZXVyc1Jlb3JnYW5pemVkRGlyLFxuICAgICAgICAgICAgICAgIGFjdGV1clVpZCArIFwiLmpzb25cIixcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKFxuICAgICAgICAgICAgICAgIGFjdGV1clJlb3JnYW5pemVkSnNvbkZpbGVQYXRoLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGFjdGV1ciwgbnVsbCwgMiksXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgZW5jb2Rpbmc6IFwidXRmOFwiLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9yIChjb25zdCBvcmdhbmVTcGxpdFBhdGggb2Ygd2Fsa0RpcihcbiAgICAgICAgICAgICAgb3JpZ2luYWxKc29uRGlyZWN0b3J5T3JGaWxlUGF0aCxcbiAgICAgICAgICAgICAgW1wib3JnYW5lXCJdLFxuICAgICAgICAgICAgKSkge1xuICAgICAgICAgICAgICBjb25zdCBvcmdhbmVGaWxlbmFtZSA9IG9yZ2FuZVNwbGl0UGF0aFtvcmdhbmVTcGxpdFBhdGgubGVuZ3RoIC0gMV1cbiAgICAgICAgICAgICAgaWYgKCFvcmdhbmVGaWxlbmFtZS5lbmRzV2l0aChcIi5qc29uXCIpKSB7XG4gICAgICAgICAgICAgICAgY29udGludWVcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBvcmdhbmVPcmlnaW5hbEZpbGVQYXRoID0gcGF0aC5qb2luKFxuICAgICAgICAgICAgICAgIG9yaWdpbmFsSnNvbkRpcmVjdG9yeU9yRmlsZVBhdGgsXG4gICAgICAgICAgICAgICAgLi4ub3JnYW5lU3BsaXRQYXRoLFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIGlmIChvcHRpb25zLnZlcmJvc2UpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgIGAgIFJlb3JnYW5pemluZyBcIm9yZ2FuZVwiIGZpbGU6ICR7b3JnYW5lT3JpZ2luYWxGaWxlUGF0aH3igKZgLFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBjb25zdCBvcmdhbmVPcmlnaW5hbEpzb246IHN0cmluZyA9IGZzLnJlYWRGaWxlU3luYyhcbiAgICAgICAgICAgICAgICBvcmdhbmVPcmlnaW5hbEZpbGVQYXRoLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgIGVuY29kaW5nOiBcInV0ZjhcIixcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgIGNvbnN0IG9yZ2FuZU9yaWdpbmFsOiBhbnkgPSB2YWxpZGF0ZVJhd0RhdGFcbiAgICAgICAgICAgICAgICA/IEFjdGV1cnNFdE9yZ2FuZXNSYXdDb252ZXJ0LnRvT3JnYW5lKG9yZ2FuZU9yaWdpbmFsSnNvbilcbiAgICAgICAgICAgICAgICA6IEpTT04ucGFyc2Uob3JnYW5lT3JpZ2luYWxKc29uKVxuICAgICAgICAgICAgICBjb25zdCBvcmdhbmUgPSBvcmdhbmVPcmlnaW5hbC5vcmdhbmVcbiAgICAgICAgICAgICAgY29uc3Qgb3JnYW5lUmVvcmdhbml6ZWRKc29uRmlsZVBhdGg6IHN0cmluZyA9IHBhdGguam9pbihcbiAgICAgICAgICAgICAgICBvcmdhbmVzUmVvcmdhbml6ZWREaXIsXG4gICAgICAgICAgICAgICAgb3JnYW5lLnVpZCArIFwiLmpzb25cIixcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgICBmcy53cml0ZUZpbGVTeW5jKFxuICAgICAgICAgICAgICAgIG9yZ2FuZVJlb3JnYW5pemVkSnNvbkZpbGVQYXRoLFxuICAgICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KG9yZ2FuZSwgbnVsbCwgMiksXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgZW5jb2Rpbmc6IFwidXRmOFwiLFxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICA