text-to-map
Version:
Text To Map usiluje o lepší, strojově zpracovatelné využití částí vyhlášek s výčtem ulic a dalších lokací. Jde o rozšiřitelnou sadu konceptů a nástrojů, které zajistí hladký převod výčtu ulic a jejich rozsahů v lidsky srozumitelném jazyce do strojově zpra
176 lines • 24 kB
JavaScript
import { existsSync, mkdirSync } from "fs";
import { tmpdir } from "os";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
import { MunicipalityType } from "../db/types";
const appName = "text-to-map";
export const getAppDataDirPath = () => join(process.env.APPDATA ||
(process.platform == "darwin"
? process.env.HOME + "/Library/Preferences"
: process.env.HOME + "/.local/share"), appName);
export const prepareOptions = (options) => {
const dataDir = options.dataDir ?? getAppDataDirPath();
if (!existsSync(dataDir)) {
mkdirSync(dataDir);
}
const tmpAppDir = join(tmpdir(), appName);
if (!existsSync(tmpAppDir)) {
mkdirSync(tmpAppDir);
}
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const defaults = {
tmpDir: tmpAppDir,
dataDir: dataDir,
dbFilePath: join(dataDir, "address_points.db"),
dbInitFilePath: join(__dirname, "..", "address_points_init.db"),
addressPointsAtomUrl: "https://atom.cuzk.cz/RUIAN-CSV-ADR-ST/RUIAN-CSV-ADR-ST.xml",
addressPointsZipFileName: "ruian_csv.zip",
addressPointsCsvFolderName: "CSV",
streetsAtomUrl: "https://atom.cuzk.cz/RUIAN-OBCE-SHP/RUIAN-OBCE-SHP.xml",
streetZipFolderName: "streets",
streetDbfFileName: "UL_L.dbf",
polygonShpFileName: "OBEC_P.shp",
districtPolygonShpFileName: "MOMC_P.shp",
districtPolygonDbfFileName: "MOMC_P.dbf",
schoolsXmlUrl: "https://rejstriky.msmt.cz/opendata/vrejcelk.xml",
schoolsXmlFileName: "school-register.xml",
regionsCsvUrl: "https://www.czso.cz/documents/10180/23208674/struktura_uzemi_cr.csv",
regionsSchemaUrl: "https://www.czso.cz/documents/10180/23208674/struktura_uzemi_cr-metadata.json",
regionsCsvFileName: "struktura_uzemi_cr.csv",
};
return {
...defaults,
...options,
};
};
const cityPatterns = [
/^[sS]tatutární město +(.*)$/,
/^[oO]bec +(.*)$/,
/^[mM]ěsto +(.*)$/,
/^[mM]ěstys +(.*)$/,
];
const districtPatterns = [
/^[mM]ěstská část +(.*)$/,
/^[mM]ěstský obvod +(.*)$/,
/^[sS]tatutární město +.*, [mM]ěstská část +(.*)$/,
/^[sS]tatutární město +.*, [mM]ěstský obvod +(.*)$/,
];
export const extractMunicipalityName = (founder) => {
const patterns = founder.municipalityType === MunicipalityType.City
? cityPatterns
: districtPatterns;
const correctPattern = patterns.filter((pattern) => pattern.test(founder.name));
if (correctPattern.length > 0) {
const result = correctPattern[0].exec(founder.name);
if (typeof result[1] !== "undefined") {
return result[1]
.replace(" - ", "-")
.replace(/\s{2,}/g, " ")
.trim();
}
}
return founder.name;
};
export const sanitizeMunicipalityName = (name) => {
return name
.replace(" - ", "-")
.replace(/\s{2,}/g, " ")
.trim();
};
export const findClosestString = (str, arr, maxDistance) => {
let closestStr = "";
let closestDistance = Number.MAX_SAFE_INTEGER;
for (let i = 0; i < arr.length; i++) {
const currentStr = arr[i];
const distance = interpunctionDistance(str, currentStr);
if (distance < closestDistance) {
closestStr = currentStr;
closestDistance = distance;
}
// exact match found, exit loop
if (closestDistance === 0) {
break;
}
}
if (maxDistance !== undefined && closestDistance > maxDistance) {
return "";
}
return closestStr;
};
const interpunctionDistance = (str1, str2) => {
let distance = levenshteinDistance(str1, str2);
const interpunctionMistakes = {
a: ["á"],
á: ["a"],
e: ["é", "ě"],
é: ["e", "ě"],
ě: ["e", "é"],
i: ["í"],
í: ["i"],
y: ["ý"],
ý: ["y"],
o: ["ó"],
ó: ["o"],
u: ["ú", "ů"],
ů: ["u", "ú"],
ú: ["u", "ů"],
c: ["č"],
č: ["c"],
d: ["ď"],
ď: ["d"],
n: ["ň"],
ň: ["n"],
r: ["ř"],
ř: ["r"],
s: ["š"],
š: ["s"],
t: ["ť"],
ť: ["t"],
z: ["ž"],
ž: ["z"],
};
const str1Chars = str1.split("");
const str2Chars = str2.split("");
for (let i = 0; i < str1Chars.length; i++) {
const char1 = str1Chars[i];
const char2 = str2Chars[i];
if (interpunctionMistakes[char1] &&
interpunctionMistakes[char1].includes(char2)) {
// Subtract a penalty from the distance for interpunction mistakes
distance -= 0.5;
}
}
return distance;
};
const levenshteinDistance = (str1, str2) => {
const matrix = Array(str2.length + 1)
.fill(null)
.map(() => Array(str1.length + 1).fill(null));
for (let i = 0; i <= str1.length; i++) {
matrix[0][i] = i;
}
for (let j = 0; j <= str2.length; j++) {
matrix[j][0] = j;
}
for (let j = 1; j <= str2.length; j++) {
for (let i = 1; i <= str1.length; i++) {
if (str1[i - 1] === str2[j - 1]) {
matrix[j][i] = matrix[j - 1][i - 1];
}
else {
matrix[j][i] =
Math.min(matrix[j][i - 1], // deletion
matrix[j - 1][i], // insertion
matrix[j - 1][i - 1] // substitution
) + 1;
}
}
}
return matrix[str2.length][str1.length];
};
export function roundToNDecimalPlaces(toRound, decimalPlaces) {
return (Math.round(toRound * Math.pow(10, decimalPlaces)) /
Math.pow(10, decimalPlaces));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDNUIsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDckMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwQyxPQUFPLEVBQVcsZ0JBQWdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFeEQsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDO0FBeUI5QixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxHQUFXLEVBQUUsQ0FDNUMsSUFBSSxDQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTztJQUNqQixDQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksUUFBUTtRQUMzQixDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsc0JBQXNCO1FBQzNDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxlQUFlLENBQUMsRUFDekMsT0FBTyxDQUNSLENBQUM7QUFFSixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FDNUIsT0FBbUMsRUFDZCxFQUFFO0lBQ3ZCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElBQUksaUJBQWlCLEVBQUUsQ0FBQztJQUN2RCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQ3hCLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztLQUNwQjtJQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMs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QUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztRQUNiLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7UUFDYixDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO1FBQ2IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0tBQ1QsQ0FBQztJQUVGLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDakMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUVqQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUN6QyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDM0IsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTNCLElBQ0UscUJBQXFCLENBQUMsS0FBSyxDQUFDO1lBQzVCLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFDNUM7WUFDQSxrRUFBa0U7WUFDbEUsUUFBUSxJQUFJLEdBQUcsQ0FBQztTQUNqQjtLQUNGO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLElBQVksRUFBRSxJQUFZLEVBQVUsRUFBRTtJQUNqRSxNQUFNLE1BQU0sR0FBZSxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDOUMsSUFBSSxDQUFDLElBQUksQ0FBQztTQUNWLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUVoRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNyQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0tBQ2xCO0lBRUQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDckMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztLQUNsQjtJQUVELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3JDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3JDLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFO2dCQUMvQixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDckM7aUJBQU07Z0JBQ0wsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDVixJQUFJLENBQUMsR0FBRyxDQUNOLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsV0FBVztvQkFDN0IsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZO29CQUM5QixNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxlQUFlO3FCQUNyQyxHQUFHLENBQUMsQ0FBQzthQUNUO1NBQ0Y7S0FDRjtJQUVELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDMUMsQ0FBQyxDQUFDO0FBRUYsTUFBTSxVQUFVLHFCQUFxQixDQUNuQyxPQUFlLEVBQ2YsYUFBcUI7SUFFckIsT0FBTyxDQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLGFBQWEsQ0FBQyxDQUM1QixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gXCJmc1wiO1xyXG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwib3NcIjtcclxuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gXCJwYXRoXCI7XHJcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tIFwidXJsXCI7XHJcbmltcG9ydCB7IEZvdW5kZXIsIE11bmljaXBhbGl0eVR5cGUgfSBmcm9tIFwiLi4vZGIvdHlwZXNcIjtcclxuXHJcbmNvbnN0IGFwcE5hbWUgPSBcInRleHQtdG8tbWFwXCI7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIE9wZW5EYXRhU3luY09wdGlvbnMge1xyXG4gIHRtcERpcjogc3RyaW5nO1xyXG4gIGRhdGFEaXI6IHN0cmluZztcclxuICBkYkZpbGVQYXRoOiBzdHJpbmc7XHJcbiAgZGJJbml0RmlsZVBhdGg6IHN0cmluZztcclxuICBhZGRyZXNzUG9pbnRzQXRvbVVybDogc3RyaW5nO1xyXG4gIGFkZHJlc3NQb2ludHNaaXBGaWxlTmFtZTogc3RyaW5nO1xyXG4gIGFkZHJlc3NQb2ludHNDc3ZGb2xkZXJOYW1lOiBzdHJpbmc7XHJcbiAgc3RyZWV0c0F0b21Vcmw6IHN0cmluZztcclxuICBzdHJlZXRaaXBGb2xkZXJOYW1lOiBzdHJpbmc7XHJcbiAgc3RyZWV0RGJmRmlsZU5hbWU6IHN0cmluZztcclxuICBwb2x5Z29uU2hwRmlsZU5hbWU6IHN0cmluZztcclxuICBkaXN0cmljdFBvbHlnb25TaHBGaWxlTmFtZTogc3RyaW5nO1xyXG4gIGRpc3RyaWN0UG9seWdvbkRiZkZpbGVOYW1lOiBzdHJpbmc7XHJcbiAgc2Nob29sc1htbFVybDogc3RyaW5nO1xyXG4gIHNjaG9vbHNYbWxGaWxlTmFtZTogc3RyaW5nO1xyXG4gIHJlZ2lvbnNDc3ZVcmw6IHN0cmluZztcclxuICByZWdpb25zU2NoZW1hVXJsOiBzdHJpbmc7XHJcbiAgcmVnaW9uc0NzdkZpbGVOYW1lOiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCB0eXBlIE9wZW5EYXRhU3luY09wdGlvbnNQYXJ0aWFsID0gUGFydGlhbDxPcGVuRGF0YVN5bmNPcHRpb25zPjtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRBcHBEYXRhRGlyUGF0aCA9ICgpOiBzdHJpbmcgPT5cclxuICBqb2luKFxyXG4gICAgcHJvY2Vzcy5lbnYuQVBQREFUQSB8fFxyXG4gICAgICAocHJvY2Vzcy5wbGF0Zm9ybSA9PSBcImRhcndpblwiXHJcbiAgICAgICAgPyBwcm9jZXNzLmVudi5IT01FICsgXCIvTGlicmFyeS9QcmVmZXJlbmNlc1wiXHJcbiAgICAgICAgOiBwcm9jZXNzLmVudi5IT01FICsgXCIvLmxvY2FsL3NoYXJlXCIpLFxyXG4gICAgYXBwTmFtZVxyXG4gICk7XHJcblxyXG5leHBvcnQgY29uc3QgcHJlcGFyZU9wdGlvbnMgPSAoXHJcbiAgb3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1BhcnRpYWxcclxuKTogT3BlbkRhdGFTeW5jT3B0aW9ucyA9PiB7XHJcbiAgY29uc3QgZGF0YURpciA9IG9wdGlvbnMuZGF0YURpciA/PyBnZXRBcHBEYXRhRGlyUGF0aCgpO1xyXG4gIGlmICghZXhpc3RzU3luYyhkYXRhRGlyKSkge1xyXG4gICAgbWtkaXJTeW5jKGRhdGFEaXIpO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgdG1wQXBwRGlyID0gam9pbih0bXBkaXIoKSwgYXBwTmFtZSk7XHJcbiAgaWYgKCFleGlzdHNTeW5jKHRtcEFwcERpcikpIHtcclxuICAgIG1rZGlyU3luYyh0bXBBcHBEaXIpO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcclxuICBjb25zdCBfX2Rpcm5hbWUgPSBkaXJuYW1lKF9fZmlsZW5hbWUpO1xyXG5cclxuICBjb25zdCBkZWZhdWx0czogT3BlbkRhdGFTeW5jT3B0aW9ucyA9IHtcclxuICAgIHRtcERpcjogdG1wQXBwRGlyLFxyXG4gICAgZGF0YURpcjogZGF0YURpcixcclxuICAgIGRiRmlsZVBhdGg6IGpvaW4oZGF0YURpciwgXCJhZGRyZXNzX3BvaW50cy5kYlwiKSxcclxuICAgIGRiSW5pdEZpbGVQYXRoOiBqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcImFkZHJlc3NfcG9pbnRzX2luaXQuZGJcIiksXHJcbiAgICBhZGRyZXNzUG9pbnRzQXRvbVVybDpcclxuICAgICAgXCJodHRwczovL2F0b20uY3V6ay5jei9SVUlBTi1DU1YtQURSLVNUL1JVSUFOLUNTVi1BRFItU1QueG1sXCIsXHJcbiAgICBhZGRyZXNzUG9pbnRzWmlwRmlsZU5hbWU6IFwicnVpYW5fY3N2LnppcFwiLFxyXG4gICAgYWRkcmVzc1BvaW50c0NzdkZvbGRlck5hbWU6IFwiQ1NWXCIsXHJcbiAgICBzdHJlZXRzQXRvbVVybDogXCJodHRwczovL2F0b20uY3V6ay5jei9SVUlBTi1PQkNFLVNIUC9SVUlBTi1PQkNFLVNIUC54bWxcIixcclxuICAgIHN0cmVldFppcEZvbGRlck5hbWU6IFwic3RyZWV0c1wiLFxyXG4gICAgc3RyZWV0RGJmRmlsZU5hbWU6IFwiVUxfTC5kYmZcIixcclxuICAgIHBvbHlnb25TaHBGaWxlTmFtZTogXCJPQkVDX1Auc2hwXCIsXHJcbiAgICBkaXN0cmljdFBvbHlnb25TaHBGaWxlTmFtZTogXCJNT01DX1Auc2hwXCIsXHJcbiAgICBkaXN0cmljdFBvbHlnb25EYmZGaWxlTmFtZTogXCJNT01DX1AuZGJmXCIsXHJcbiAgICBzY2hvb2xzWG1sVXJsOiBcImh0dHBzOi8vcmVqc3RyaWt5Lm1zbXQuY3ovb3BlbmRhdGEvdnJlamNlbGsueG1sXCIsXHJcbiAgICBzY2hvb2xzWG1sRmlsZU5hbWU6IFwic2Nob29sLXJlZ2lzdGVyLnhtbFwiLFxyXG4gICAgcmVnaW9uc0NzdlVybDpcclxuICAgICAgXCJodHRwczovL3d3dy5jenNvLmN6L2RvY3VtZW50cy8xMDE4MC8yMzIwODY3NC9zdHJ1a3R1cmFfdXplbWlfY3IuY3N2XCIsXHJcbiAgICByZWdpb25zU2NoZW1hVXJsOlxyXG4gICAgICBcImh0dHBzOi8vd3d3LmN6c28uY3ovZG9jdW1lbnRzLzEwMTgwLzIzMjA4Njc0L3N0cnVrdHVyYV91emVtaV9jci1tZXRhZGF0YS5qc29uXCIsXHJcbiAgICByZWdpb25zQ3N2RmlsZU5hbWU6IFwic3RydWt0dXJhX3V6ZW1pX2NyLmNzdlwiLFxyXG4gIH07XHJcblxyXG4gIHJldHVybiB7XHJcbiAgICAuLi5kZWZhdWx0cyxcclxuICAgIC4uLm9wdGlvbnMsXHJcbiAgfTtcclxufTtcclxuXHJcbmNvbnN0IGNpdHlQYXR0ZXJucyA9IFtcclxuICAvXltzU110YXR1dMOhcm7DrSBtxJtzdG8gKyguKikkLyxcclxuICAvXltvT11iZWMgKyguKikkLyxcclxuICAvXlttTV3Em3N0byArKC4qKSQvLFxyXG4gIC9eW21NXcSbc3R5cyArKC4qKSQvLFxyXG5dO1xyXG5cclxuY29uc3QgZGlzdHJpY3RQYXR0ZXJucyA9IFtcclxuICAvXlttTV3Em3N0c2vDoSDEjcOhc3QgKyguKikkLyxcclxuICAvXlttTV3Em3N0c2vDvSBvYnZvZCArKC4qKSQvLFxyXG4gIC9eW3NTXXRhdHV0w6FybsOtIG3Em3N0byArLiosIFttTV3Em3N0c2vDoSDEjcOhc3QgKyguKikkLyxcclxuICAvXltzU110YXR1dMOhcm7DrSBtxJtzdG8gKy4qLCBbbU1dxJtzdHNrw70gb2J2b2QgKyguKikkLyxcclxuXTtcclxuXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0TXVuaWNpcGFsaXR5TmFtZSA9IChmb3VuZGVyOiBGb3VuZGVyKTogc3RyaW5nID0+IHtcclxuICBjb25zdCBwYXR0ZXJucyA9XHJcbiAgICBmb3VuZGVyLm11bmljaXBhbGl0eVR5cGUgPT09IE11bmljaXBhbGl0eVR5cGUuQ2l0eVxyXG4gICAgICA/IGNpdHlQYXR0ZXJuc1xyXG4gICAgICA6IGRpc3RyaWN0UGF0dGVybnM7XHJcbiAgY29uc3QgY29ycmVjdFBhdHRlcm4gPSBwYXR0ZXJucy5maWx0ZXIoKHBhdHRlcm4pID0+XHJcbiAgICBwYXR0ZXJuLnRlc3QoZm91bmRlci5uYW1lKVxyXG4gICk7XHJcbiAgaWYgKGNvcnJlY3RQYXR0ZXJuLmxlbmd0aCA+IDApIHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGNvcnJlY3RQYXR0ZXJuWzBdLmV4ZWMoZm91bmRlci5uYW1lKTtcclxuICAgIGlmICh0eXBlb2YgcmVzdWx0WzFdICE9PSBcInVuZGVmaW5lZFwiKSB7XHJcbiAgICAgIHJldHVybiByZXN1bHRbMV1cclxuICAgICAgICAucmVwbGFjZShcIiAtIFwiLCBcIi1cIilcclxuICAgICAgICAucmVwbGFjZSgvXFxzezIsfS9nLCBcIiBcIilcclxuICAgICAgICAudHJpbSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGZvdW5kZXIubmFtZTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBzYW5pdGl6ZU11bmljaXBhbGl0eU5hbWUgPSAobmFtZTogc3RyaW5nKTogc3RyaW5nID0+IHtcclxuICByZXR1cm4gbmFtZVxyXG4gICAgLnJlcGxhY2UoXCIgLSBcIiwgXCItXCIpXHJcbiAgICAucmVwbGFjZSgvXFxzezIsfS9nLCBcIiBcIilcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZmluZENsb3Nlc3RTdHJpbmcgPSAoXHJcbiAgc3RyOiBzdHJpbmcsXHJcbiAgYXJyOiBzdHJpbmdbXSxcclxuICBtYXhEaXN0YW5jZT86IG51bWJlclxyXG4pOiBzdHJpbmcgfCBudWxsID0+IHtcclxuICBsZXQgY2xvc2VzdFN0ciA9IFwiXCI7XHJcbiAgbGV0IGNsb3Nlc3REaXN0YW5jZSA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG5cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3QgY3VycmVudFN0ciA9IGFycltpXTtcclxuICAgIGNvbnN0IGRpc3RhbmNlID0gaW50ZXJwdW5jdGlvbkRpc3RhbmNlKHN0ciwgY3VycmVudFN0cik7XHJcblxyXG4gICAgaWYgKGRpc3RhbmNlIDwgY2xvc2VzdERpc3RhbmNlKSB7XHJcbiAgICAgIGNsb3Nlc3RTdHIgPSBjdXJyZW50U3RyO1xyXG4gICAgICBjbG9zZXN0RGlzdGFuY2UgPSBkaXN0YW5jZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBleGFjdCBtYXRjaCBmb3VuZCwgZXhpdCBsb29wXHJcbiAgICBpZiAoY2xvc2VzdERpc3RhbmNlID09PSAwKSB7XHJcbiAgICAgIGJyZWFrO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgaWYgKG1heERpc3RhbmNlICE9PSB1bmRlZmluZWQgJiYgY2xvc2VzdERpc3RhbmNlID4gbWF4RGlzdGFuY2UpIHtcclxuICAgIHJldHVybiBcIlwiO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNsb3Nlc3RTdHI7XHJcbn07XHJcblxyXG5jb25zdCBpbnRlcnB1bmN0aW9uRGlzdGFuY2UgPSAoc3RyMTogc3RyaW5nLCBzdHIyOiBzdHJpbmcpOiBudW1iZXIgPT4ge1xyXG4gIGxldCBkaXN0YW5jZSA9IGxldmVuc2h0ZWluRGlzdGFuY2Uoc3RyMSwgc3RyMik7XHJcblxyXG4gIGNvbnN0IGludGVycHVuY3Rpb25NaXN0YWtlcyA9IHtcclxuICAgIGE6IFtcIsOhXCJdLFxyXG4gICAgw6E6IFtcImFcIl0sXHJcbiAgICBlOiBbXCLDqVwiLCBcIsSbXCJdLFxyXG4gICAgw6k6IFtcImVcIiwgXCLEm1wiXSxcclxuICAgIMSbOiBbXCJlXCIsIFwiw6lcIl0sXHJcbiAgICBpOiBbXCLDrVwiXSxcclxuICAgIMOtOiBbXCJpXCJdLFxyXG4gICAgeTogW1wiw71cIl0sXHJcbiAgICDDvTogW1wieVwiXSxcclxuICAgIG86IFtcIsOzXCJdLFxyXG4gICAgw7M6IFtcIm9cIl0sXHJcbiAgICB1OiBbXCLDulwiLCBcIsWvXCJdLFxyXG4gICAgxa86IFtcInVcIiwgXCLDulwiXSxcclxuICAgIMO6OiBbXCJ1XCIsIFwixa9cIl0sXHJcbiAgICBjOiBbXCLEjVwiXSxcclxuICAgIMSNOiBbXCJjXCJdLFxyXG4gICAgZDogW1wixI9cIl0sXHJcbiAgICDEjzogW1wiZFwiXSxcclxuICAgIG46IFtcIsWIXCJdLFxyXG4gICAgxYg6IFtcIm5cIl0sXHJcbiAgICByOiBbXCLFmVwiXSxcclxuICAgIMWZOiBbXCJyXCJdLFxyXG4gICAgczogW1wixaFcIl0sXHJcbiAgICDFoTogW1wic1wiXSxcclxuICAgIHQ6IFtcIsWlXCJdLFxyXG4gICAgxaU6IFtcInRcIl0sXHJcbiAgICB6OiBbXCLFvlwiXSxcclxuICAgIMW+OiBbXCJ6XCJdLFxyXG4gIH07XHJcblxyXG4gIGNvbnN0IHN0cjFDaGFycyA9IHN0cjEuc3BsaXQoXCJcIik7XHJcbiAgY29uc3Qgc3RyMkNoYXJzID0gc3RyMi5zcGxpdChcIlwiKTtcclxuXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdHIxQ2hhcnMubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IGNoYXIxID0gc3RyMUNoYXJzW2ldO1xyXG4gICAgY29uc3QgY2hhcjIgPSBzdHIyQ2hhcnNbaV07XHJcblxyXG4gICAgaWYgKFxyXG4gICAgICBpbnRlcnB1bmN0aW9uTWlzdGFrZXNbY2hhcjFdICYmXHJcbiAgICAgIGludGVycHVuY3Rpb25NaXN0YWtlc1tjaGFyMV0uaW5jbHVkZXMoY2hhcjIpXHJcbiAgICApIHtcclxuICAgICAgLy8gU3VidHJhY3QgYSBwZW5hbHR5IGZyb20gdGhlIGRpc3RhbmNlIGZvciBpbnRlcnB1bmN0aW9uIG1pc3Rha2VzXHJcbiAgICAgIGRpc3RhbmNlIC09IDAuNTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBkaXN0YW5jZTtcclxufTtcclxuXHJcbmNvbnN0IGxldmVuc2h0ZWluRGlzdGFuY2UgPSAoc3RyMTogc3RyaW5nLCBzdHIyOiBzdHJpbmcpOiBudW1iZXIgPT4ge1xyXG4gIGNvbnN0IG1hdHJpeDogbnVtYmVyW11bXSA9IEFycmF5KHN0cjIubGVuZ3RoICsgMSlcclxuICAgIC5maWxsKG51bGwpXHJcbiAgICAubWFwKCgpID0+IEFycmF5KHN0cjEubGVuZ3RoICsgMSkuZmlsbChudWxsKSk7XHJcblxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDw9IHN0cjEubGVuZ3RoOyBpKyspIHtcclxuICAgIG1hdHJpeFswXVtpXSA9IGk7XHJcbiAgfVxyXG5cclxuICBmb3IgKGxldCBqID0gMDsgaiA8PSBzdHIyLmxlbmd0aDsgaisrKSB7XHJcbiAgICBtYXRyaXhbal1bMF0gPSBqO1xyXG4gIH1cclxuXHJcbiAgZm9yIChsZXQgaiA9IDE7IGogPD0gc3RyMi5sZW5ndGg7IGorKykge1xyXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gc3RyMS5sZW5ndGg7IGkrKykge1xyXG4gICAgICBpZiAoc3RyMVtpIC0gMV0gPT09IHN0cjJbaiAtIDFdKSB7XHJcbiAgICAgICAgbWF0cml4W2pdW2ldID0gbWF0cml4W2ogLSAxXVtpIC0gMV07XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbWF0cml4W2pdW2ldID1cclxuICAgICAgICAgIE1hdGgubWluKFxyXG4gICAgICAgICAgICBtYXRyaXhbal1baSAtIDFdLCAvLyBkZWxldGlvblxyXG4gICAgICAgICAgICBtYXRyaXhbaiAtIDFdW2ldLCAvLyBpbnNlcnRpb25cclxuICAgICAgICAgICAgbWF0cml4W2ogLSAxXVtpIC0gMV0gLy8gc3Vic3RpdHV0aW9uXHJcbiAgICAgICAgICApICsgMTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1hdHJpeFtzdHIyLmxlbmd0aF1bc3RyMS5sZW5ndGhdO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kVG9ORGVjaW1hbFBsYWNlcyhcclxuICB0b1JvdW5kOiBudW1iZXIsXHJcbiAgZGVjaW1hbFBsYWNlczogbnVtYmVyXHJcbik6IG51bWJlciB7XHJcbiAgcmV0dXJuIChcclxuICAgIE1hdGgucm91bmQodG9Sb3VuZCAqIE1hdGgucG93KDEwLCBkZWNpbWFsUGxhY2VzKSkgL1xyXG4gICAgTWF0aC5wb3coMTAsIGRlY2ltYWxQbGFjZXMpXHJcbiAgKTtcclxufVxyXG4iXX0=