UNPKG

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
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,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9oZWxwZXJzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsU0FBUyxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzNDLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDNUIsT0FBTyxFQUFFLE9BQU8sRUFBRSxJQUFJLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDckMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLEtBQUssQ0FBQztBQUNwQyxPQUFPLEVBQVcsZ0JBQWdCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFFeEQsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDO0FBeUI5QixNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxHQUFXLEVBQUUsQ0FDNUMsSUFBSSxDQUNGLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTztJQUNqQixDQUFDLE9BQU8sQ0FBQyxRQUFRLElBQUksUUFBUTtRQUMzQixDQUFDLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEdBQUcsc0JBQXNCO1FBQzNDLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksR0FBRyxlQUFlLENBQUMsRUFDekMsT0FBTyxDQUNSLENBQUM7QUFFSixNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsQ0FDNUIsT0FBbUMsRUFDZCxFQUFFO0lBQ3ZCLE1BQU0sT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLElBQUksaUJBQWlCLEVBQUUsQ0FBQztJQUN2RCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFO1FBQ3hCLFNBQVMsQ0FBQyxPQUFPLENBQUMsQ0FBQztLQUNwQjtJQUVELE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxNQUFNLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztJQUMxQyxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsQ0FBQyxFQUFFO1FBQzFCLFNBQVMsQ0FBQyxTQUFTLENBQUMsQ0FBQztLQUN0QjtJQUVELE1BQU0sVUFBVSxHQUFHLGFBQWEsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xELE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztJQUV0QyxNQUFNLFFBQVEsR0FBd0I7UUFDcEMsTUFBTSxFQUFFLFNBQVM7UUFDakIsT0FBTyxFQUFFLE9BQU87UUFDaEIsVUFBVSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsbUJBQW1CLENBQUM7UUFDOUMsY0FBYyxFQUFFLElBQUksQ0FBQyxTQUFTLEVBQUUsSUFBSSxFQUFFLHdCQUF3QixDQUFDO1FBQy9ELG9CQUFvQixFQUNsQiw0REFBNEQ7UUFDOUQsd0JBQXdCLEVBQUUsZUFBZTtRQUN6QywwQkFBMEIsRUFBRSxLQUFLO1FBQ2pDLGNBQWMsRUFBRSx3REFBd0Q7UUFDeEUsbUJBQW1CLEVBQUUsU0FBUztRQUM5QixpQkFBaUIsRUFBRSxVQUFVO1FBQzdCLGtCQUFrQixFQUFFLFlBQVk7UUFDaEMsMEJBQTBCLEVBQUUsWUFBWTtRQUN4QywwQkFBMEIsRUFBRSxZQUFZO1FBQ3hDLGFBQWEsRUFBRSxpREFBaUQ7UUFDaEUsa0JBQWtCLEVBQUUscUJBQXFCO1FBQ3pDLGFBQWEsRUFDWCxxRUFBcUU7UUFDdkUsZ0JBQWdCLEVBQ2QsK0VBQStFO1FBQ2pGLGtCQUFrQixFQUFFLHdCQUF3QjtLQUM3QyxDQUFDO0lBRUYsT0FBTztRQUNMLEdBQUcsUUFBUTtRQUNYLEdBQUcsT0FBTztLQUNYLENBQUM7QUFDSixDQUFDLENBQUM7QUFFRixNQUFNLFlBQVksR0FBRztJQUNuQiw2QkFBNkI7SUFDN0IsaUJBQWlCO0lBQ2pCLGtCQUFrQjtJQUNsQixtQkFBbUI7Q0FDcEIsQ0FBQztBQUVGLE1BQU0sZ0JBQWdCLEdBQUc7SUFDdkIseUJBQXlCO0lBQ3pCLDBCQUEwQjtJQUMxQixrREFBa0Q7SUFDbEQsbURBQW1EO0NBQ3BELENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSx1QkFBdUIsR0FBRyxDQUFDLE9BQWdCLEVBQVUsRUFBRTtJQUNsRSxNQUFNLFFBQVEsR0FDWixPQUFPLENBQUMsZ0JBQWdCLEtBQUssZ0JBQWdCLENBQUMsSUFBSTtRQUNoRCxDQUFDLENBQUMsWUFBWTtRQUNkLENBQUMsQ0FBQyxnQkFBZ0IsQ0FBQztJQUN2QixNQUFNLGNBQWMsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FDakQsT0FBTyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQzNCLENBQUM7SUFDRixJQUFJLGNBQWMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFO1FBQzdCLE1BQU0sTUFBTSxHQUFHLGNBQWMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3BELElBQUksT0FBTyxNQUFNLENBQUMsQ0FBQyxDQUFDLEtBQUssV0FBVyxFQUFFO1lBQ3BDLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQztpQkFDYixPQUFPLENBQUMsS0FBSyxFQUFFLEdBQUcsQ0FBQztpQkFDbkIsT0FBTyxDQUFDLFNBQVMsRUFBRSxHQUFHLENBQUM7aUJBQ3ZCLElBQUksRUFBRSxDQUFDO1NBQ1g7S0FDRjtJQUVELE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQztBQUN0QixDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLElBQVksRUFBVSxFQUFFO0lBQy9ELE9BQU8sSUFBSTtTQUNSLE9BQU8sQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDO1NBQ25CLE9BQU8sQ0FBQyxTQUFTLEVBQUUsR0FBRyxDQUFDO1NBQ3ZCLElBQUksRUFBRSxDQUFDO0FBQ1osQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0saUJBQWlCLEdBQUcsQ0FDL0IsR0FBVyxFQUNYLEdBQWEsRUFDYixXQUFvQixFQUNMLEVBQUU7SUFDakIsSUFBSSxVQUFVLEdBQUcsRUFBRSxDQUFDO0lBQ3BCLElBQUksZUFBZSxHQUFHLE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBQztJQUU5QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNuQyxNQUFNLFVBQVUsR0FBRyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDMUIsTUFBTSxRQUFRLEdBQUcscUJBQXFCLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO1FBRXhELElBQUksUUFBUSxHQUFHLGVBQWUsRUFBRTtZQUM5QixVQUFVLEdBQUcsVUFBVSxDQUFDO1lBQ3hCLGVBQWUsR0FBRyxRQUFRLENBQUM7U0FDNUI7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxlQUFlLEtBQUssQ0FBQyxFQUFFO1lBQ3pCLE1BQU07U0FDUDtLQUNGO0lBRUQsSUFBSSxXQUFXLEtBQUssU0FBUyxJQUFJLGVBQWUsR0FBRyxXQUFXLEVBQUU7UUFDOUQsT0FBTyxFQUFFLENBQUM7S0FDWDtJQUVELE9BQU8sVUFBVSxDQUFDO0FBQ3BCLENBQUMsQ0FBQztBQUVGLE1BQU0scUJBQXFCLEdBQUcsQ0FBQyxJQUFZLEVBQUUsSUFBWSxFQUFVLEVBQUU7SUFDbkUsSUFBSSxRQUFRLEdBQUcsbUJBQW1CLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBRS9DLE1BQU0scUJBQXFCLEdBQUc7UUFDNUIsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztRQUNiLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7UUFDYixDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO1FBQ2IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQztRQUNiLENBQUMsRUFBRSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUM7UUFDYixDQUFDLEVBQUUsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDO1FBQ2IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO1FBQ1IsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDO0tBQ1QsQ0FBQztJQUVGLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLENBQUM7SUFDakMsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUVqQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUN6QyxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDM0IsTUFBTSxLQUFLLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRTNCLElBQ0UscUJBQXFCLENBQUMsS0FBSyxDQUFDO1lBQzVCLHFCQUFxQixDQUFDLEtBQUssQ0FBQyxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsRUFDNUM7WUFDQSxrRUFBa0U7WUFDbEUsUUFBUSxJQUFJLEdBQUcsQ0FBQztTQUNqQjtLQUNGO0lBRUQsT0FBTyxRQUFRLENBQUM7QUFDbEIsQ0FBQyxDQUFDO0FBRUYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLElBQVksRUFBRSxJQUFZLEVBQVUsRUFBRTtJQUNqRSxNQUFNLE1BQU0sR0FBZSxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUM7U0FDOUMsSUFBSSxDQUFDLElBQUksQ0FBQztTQUNWLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUVoRCxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLElBQUksSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsRUFBRTtRQUNyQyxNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0tBQ2xCO0lBRUQsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUU7UUFDckMsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQztLQUNsQjtJQUVELEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1FBQ3JDLEtBQUssSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFO1lBQ3JDLElBQUksSUFBSSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFO2dCQUMvQixNQUFNLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7YUFDckM7aUJBQU07Z0JBQ0wsTUFBTSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDVixJQUFJLENBQUMsR0FBRyxDQUNOLE1BQU0sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsV0FBVztvQkFDN0IsTUFBTSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxZQUFZO29CQUM5QixNQUFNLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxlQUFlO3FCQUNyQyxHQUFHLENBQUMsQ0FBQzthQUNUO1NBQ0Y7S0FDRjtJQUVELE9BQU8sTUFBTSxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7QUFDMUMsQ0FBQyxDQUFDO0FBRUYsTUFBTSxVQUFVLHFCQUFxQixDQUNuQyxPQUFlLEVBQ2YsYUFBcUI7SUFFckIsT0FBTyxDQUNMLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ2pELElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxFQUFFLGFBQWEsQ0FBQyxDQUM1QixDQUFDO0FBQ0osQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gXCJmc1wiO1xyXG5pbXBvcnQgeyB0bXBkaXIgfSBmcm9tIFwib3NcIjtcclxuaW1wb3J0IHsgZGlybmFtZSwgam9pbiB9IGZyb20gXCJwYXRoXCI7XHJcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tIFwidXJsXCI7XHJcbmltcG9ydCB7IEZvdW5kZXIsIE11bmljaXBhbGl0eVR5cGUgfSBmcm9tIFwiLi4vZGIvdHlwZXNcIjtcclxuXHJcbmNvbnN0IGFwcE5hbWUgPSBcInRleHQtdG8tbWFwXCI7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIE9wZW5EYXRhU3luY09wdGlvbnMge1xyXG4gIHRtcERpcjogc3RyaW5nO1xyXG4gIGRhdGFEaXI6IHN0cmluZztcclxuICBkYkZpbGVQYXRoOiBzdHJpbmc7XHJcbiAgZGJJbml0RmlsZVBhdGg6IHN0cmluZztcclxuICBhZGRyZXNzUG9pbnRzQXRvbVVybDogc3RyaW5nO1xyXG4gIGFkZHJlc3NQb2ludHNaaXBGaWxlTmFtZTogc3RyaW5nO1xyXG4gIGFkZHJlc3NQb2ludHNDc3ZGb2xkZXJOYW1lOiBzdHJpbmc7XHJcbiAgc3RyZWV0c0F0b21Vcmw6IHN0cmluZztcclxuICBzdHJlZXRaaXBGb2xkZXJOYW1lOiBzdHJpbmc7XHJcbiAgc3RyZWV0RGJmRmlsZU5hbWU6IHN0cmluZztcclxuICBwb2x5Z29uU2hwRmlsZU5hbWU6IHN0cmluZztcclxuICBkaXN0cmljdFBvbHlnb25TaHBGaWxlTmFtZTogc3RyaW5nO1xyXG4gIGRpc3RyaWN0UG9seWdvbkRiZkZpbGVOYW1lOiBzdHJpbmc7XHJcbiAgc2Nob29sc1htbFVybDogc3RyaW5nO1xyXG4gIHNjaG9vbHNYbWxGaWxlTmFtZTogc3RyaW5nO1xyXG4gIHJlZ2lvbnNDc3ZVcmw6IHN0cmluZztcclxuICByZWdpb25zU2NoZW1hVXJsOiBzdHJpbmc7XHJcbiAgcmVnaW9uc0NzdkZpbGVOYW1lOiBzdHJpbmc7XHJcbn1cclxuXHJcbmV4cG9ydCB0eXBlIE9wZW5EYXRhU3luY09wdGlvbnNQYXJ0aWFsID0gUGFydGlhbDxPcGVuRGF0YVN5bmNPcHRpb25zPjtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRBcHBEYXRhRGlyUGF0aCA9ICgpOiBzdHJpbmcgPT5cclxuICBqb2luKFxyXG4gICAgcHJvY2Vzcy5lbnYuQVBQREFUQSB8fFxyXG4gICAgICAocHJvY2Vzcy5wbGF0Zm9ybSA9PSBcImRhcndpblwiXHJcbiAgICAgICAgPyBwcm9jZXNzLmVudi5IT01FICsgXCIvTGlicmFyeS9QcmVmZXJlbmNlc1wiXHJcbiAgICAgICAgOiBwcm9jZXNzLmVudi5IT01FICsgXCIvLmxvY2FsL3NoYXJlXCIpLFxyXG4gICAgYXBwTmFtZVxyXG4gICk7XHJcblxyXG5leHBvcnQgY29uc3QgcHJlcGFyZU9wdGlvbnMgPSAoXHJcbiAgb3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1BhcnRpYWxcclxuKTogT3BlbkRhdGFTeW5jT3B0aW9ucyA9PiB7XHJcbiAgY29uc3QgZGF0YURpciA9IG9wdGlvbnMuZGF0YURpciA/PyBnZXRBcHBEYXRhRGlyUGF0aCgpO1xyXG4gIGlmICghZXhpc3RzU3luYyhkYXRhRGlyKSkge1xyXG4gICAgbWtkaXJTeW5jKGRhdGFEaXIpO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgdG1wQXBwRGlyID0gam9pbih0bXBkaXIoKSwgYXBwTmFtZSk7XHJcbiAgaWYgKCFleGlzdHNTeW5jKHRtcEFwcERpcikpIHtcclxuICAgIG1rZGlyU3luYyh0bXBBcHBEaXIpO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgX19maWxlbmFtZSA9IGZpbGVVUkxUb1BhdGgoaW1wb3J0Lm1ldGEudXJsKTtcclxuICBjb25zdCBfX2Rpcm5hbWUgPSBkaXJuYW1lKF9fZmlsZW5hbWUpO1xyXG5cclxuICBjb25zdCBkZWZhdWx0czogT3BlbkRhdGFTeW5jT3B0aW9ucyA9IHtcclxuICAgIHRtcERpcjogdG1wQXBwRGlyLFxyXG4gICAgZGF0YURpcjogZGF0YURpcixcclxuICAgIGRiRmlsZVBhdGg6IGpvaW4oZGF0YURpciwgXCJhZGRyZXNzX3BvaW50cy5kYlwiKSxcclxuICAgIGRiSW5pdEZpbGVQYXRoOiBqb2luKF9fZGlybmFtZSwgXCIuLlwiLCBcImFkZHJlc3NfcG9pbnRzX2luaXQuZGJcIiksXHJcbiAgICBhZGRyZXNzUG9pbnRzQXRvbVVybDpcclxuICAgICAgXCJodHRwczovL2F0b20uY3V6ay5jei9SVUlBTi1DU1YtQURSLVNUL1JVSUFOLUNTVi1BRFItU1QueG1sXCIsXHJcbiAgICBhZGRyZXNzUG9pbnRzWmlwRmlsZU5hbWU6IFwicnVpYW5fY3N2LnppcFwiLFxyXG4gICAgYWRkcmVzc1BvaW50c0NzdkZvbGRlck5hbWU6IFwiQ1NWXCIsXHJcbiAgICBzdHJlZXRzQXRvbVVybDogXCJodHRwczovL2F0b20uY3V6ay5jei9SVUlBTi1PQkNFLVNIUC9SVUlBTi1PQkNFLVNIUC54bWxcIixcclxuICAgIHN0cmVldFppcEZvbGRlck5hbWU6IFwic3RyZWV0c1wiLFxyXG4gICAgc3RyZWV0RGJmRmlsZU5hbWU6IFwiVUxfTC5kYmZcIixcclxuICAgIHBvbHlnb25TaHBGaWxlTmFtZTogXCJPQkVDX1Auc2hwXCIsXHJcbiAgICBkaXN0cmljdFBvbHlnb25TaHBGaWxlTmFtZTogXCJNT01DX1Auc2hwXCIsXHJcbiAgICBkaXN0cmljdFBvbHlnb25EYmZGaWxlTmFtZTogXCJNT01DX1AuZGJmXCIsXHJcbiAgICBzY2hvb2xzWG1sVXJsOiBcImh0dHBzOi8vcmVqc3RyaWt5Lm1zbXQuY3ovb3BlbmRhdGEvdnJlamNlbGsueG1sXCIsXHJcbiAgICBzY2hvb2xzWG1sRmlsZU5hbWU6IFwic2Nob29sLXJlZ2lzdGVyLnhtbFwiLFxyXG4gICAgcmVnaW9uc0NzdlVybDpcclxuICAgICAgXCJodHRwczovL3d3dy5jenNvLmN6L2RvY3VtZW50cy8xMDE4MC8yMzIwODY3NC9zdHJ1a3R1cmFfdXplbWlfY3IuY3N2XCIsXHJcbiAgICByZWdpb25zU2NoZW1hVXJsOlxyXG4gICAgICBcImh0dHBzOi8vd3d3LmN6c28uY3ovZG9jdW1lbnRzLzEwMTgwLzIzMjA4Njc0L3N0cnVrdHVyYV91emVtaV9jci1tZXRhZGF0YS5qc29uXCIsXHJcbiAgICByZWdpb25zQ3N2RmlsZU5hbWU6IFwic3RydWt0dXJhX3V6ZW1pX2NyLmNzdlwiLFxyXG4gIH07XHJcblxyXG4gIHJldHVybiB7XHJcbiAgICAuLi5kZWZhdWx0cyxcclxuICAgIC4uLm9wdGlvbnMsXHJcbiAgfTtcclxufTtcclxuXHJcbmNvbnN0IGNpdHlQYXR0ZXJucyA9IFtcclxuICAvXltzU110YXR1dMOhcm7DrSBtxJtzdG8gKyguKikkLyxcclxuICAvXltvT11iZWMgKyguKikkLyxcclxuICAvXlttTV3Em3N0byArKC4qKSQvLFxyXG4gIC9eW21NXcSbc3R5cyArKC4qKSQvLFxyXG5dO1xyXG5cclxuY29uc3QgZGlzdHJpY3RQYXR0ZXJucyA9IFtcclxuICAvXlttTV3Em3N0c2vDoSDEjcOhc3QgKyguKikkLyxcclxuICAvXlttTV3Em3N0c2vDvSBvYnZvZCArKC4qKSQvLFxyXG4gIC9eW3NTXXRhdHV0w6FybsOtIG3Em3N0byArLiosIFttTV3Em3N0c2vDoSDEjcOhc3QgKyguKikkLyxcclxuICAvXltzU110YXR1dMOhcm7DrSBtxJtzdG8gKy4qLCBbbU1dxJtzdHNrw70gb2J2b2QgKyguKikkLyxcclxuXTtcclxuXHJcbmV4cG9ydCBjb25zdCBleHRyYWN0TXVuaWNpcGFsaXR5TmFtZSA9IChmb3VuZGVyOiBGb3VuZGVyKTogc3RyaW5nID0+IHtcclxuICBjb25zdCBwYXR0ZXJucyA9XHJcbiAgICBmb3VuZGVyLm11bmljaXBhbGl0eVR5cGUgPT09IE11bmljaXBhbGl0eVR5cGUuQ2l0eVxyXG4gICAgICA/IGNpdHlQYXR0ZXJuc1xyXG4gICAgICA6IGRpc3RyaWN0UGF0dGVybnM7XHJcbiAgY29uc3QgY29ycmVjdFBhdHRlcm4gPSBwYXR0ZXJucy5maWx0ZXIoKHBhdHRlcm4pID0+XHJcbiAgICBwYXR0ZXJuLnRlc3QoZm91bmRlci5uYW1lKVxyXG4gICk7XHJcbiAgaWYgKGNvcnJlY3RQYXR0ZXJuLmxlbmd0aCA+IDApIHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGNvcnJlY3RQYXR0ZXJuWzBdLmV4ZWMoZm91bmRlci5uYW1lKTtcclxuICAgIGlmICh0eXBlb2YgcmVzdWx0WzFdICE9PSBcInVuZGVmaW5lZFwiKSB7XHJcbiAgICAgIHJldHVybiByZXN1bHRbMV1cclxuICAgICAgICAucmVwbGFjZShcIiAtIFwiLCBcIi1cIilcclxuICAgICAgICAucmVwbGFjZSgvXFxzezIsfS9nLCBcIiBcIilcclxuICAgICAgICAudHJpbSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGZvdW5kZXIubmFtZTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBzYW5pdGl6ZU11bmljaXBhbGl0eU5hbWUgPSAobmFtZTogc3RyaW5nKTogc3RyaW5nID0+IHtcclxuICByZXR1cm4gbmFtZVxyXG4gICAgLnJlcGxhY2UoXCIgLSBcIiwgXCItXCIpXHJcbiAgICAucmVwbGFjZSgvXFxzezIsfS9nLCBcIiBcIilcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZmluZENsb3Nlc3RTdHJpbmcgPSAoXHJcbiAgc3RyOiBzdHJpbmcsXHJcbiAgYXJyOiBzdHJpbmdbXSxcclxuICBtYXhEaXN0YW5jZT86IG51bWJlclxyXG4pOiBzdHJpbmcgfCBudWxsID0+IHtcclxuICBsZXQgY2xvc2VzdFN0ciA9IFwiXCI7XHJcbiAgbGV0IGNsb3Nlc3REaXN0YW5jZSA9IE51bWJlci5NQVhfU0FGRV9JTlRFR0VSO1xyXG5cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyci5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3QgY3VycmVudFN0ciA9IGFycltpXTtcclxuICAgIGNvbnN0IGRpc3RhbmNlID0gaW50ZXJwdW5jdGlvbkRpc3RhbmNlKHN0ciwgY3VycmVudFN0cik7XHJcblxyXG4gICAgaWYgKGRpc3RhbmNlIDwgY2xvc2VzdERpc3RhbmNlKSB7XHJcbiAgICAgIGNsb3Nlc3RTdHIgPSBjdXJyZW50U3RyO1xyXG4gICAgICBjbG9zZXN0RGlzdGFuY2UgPSBkaXN0YW5jZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBleGFjdCBtYXRjaCBmb3VuZCwgZXhpdCBsb29wXHJcbiAgICBpZiAoY2xvc2VzdERpc3RhbmNlID09PSAwKSB7XHJcbiAgICAgIGJyZWFrO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgaWYgKG1heERpc3RhbmNlICE9PSB1bmRlZmluZWQgJiYgY2xvc2VzdERpc3RhbmNlID4gbWF4RGlzdGFuY2UpIHtcclxuICAgIHJldHVybiBcIlwiO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNsb3Nlc3RTdHI7XHJcbn07XHJcblxyXG5jb25zdCBpbnRlcnB1bmN0aW9uRGlzdGFuY2UgPSAoc3RyMTogc3RyaW5nLCBzdHIyOiBzdHJpbmcpOiBudW1iZXIgPT4ge1xyXG4gIGxldCBkaXN0YW5jZSA9IGxldmVuc2h0ZWluRGlzdGFuY2Uoc3RyMSwgc3RyMik7XHJcblxyXG4gIGNvbnN0IGludGVycHVuY3Rpb25NaXN0YWtlcyA9IHtcclxuICAgIGE6IFtcIsOhXCJdLFxyXG4gICAgw6E6IFtcImFcIl0sXHJcbiAgICBlOiBbXCLDqVwiLCBcIsSbXCJdLFxyXG4gICAgw6k6IFtcImVcIiwgXCLEm1wiXSxcclxuICAgIMSbOiBbXCJlXCIsIFwiw6lcIl0sXHJcbiAgICBpOiBbXCLDrVwiXSxcclxuICAgIMOtOiBbXCJpXCJdLFxyXG4gICAgeTogW1wiw71cIl0sXHJcbiAgICDDvTogW1wieVwiXSxcclxuICAgIG86IFtcIsOzXCJdLFxyXG4gICAgw7M6IFtcIm9cIl0sXHJcbiAgICB1OiBbXCLDulwiLCBcIsWvXCJdLFxyXG4gICAgxa86IFtcInVcIiwgXCLDulwiXSxcclxuICAgIMO6OiBbXCJ1XCIsIFwixa9cIl0sXHJcbiAgICBjOiBbXCLEjVwiXSxcclxuICAgIMSNOiBbXCJjXCJdLFxyXG4gICAgZDogW1wixI9cIl0sXHJcbiAgICDEjzogW1wiZFwiXSxcclxuICAgIG46IFtcIsWIXCJdLFxyXG4gICAgxYg6IFtcIm5cIl0sXHJcbiAgICByOiBbXCLFmVwiXSxcclxuICAgIMWZOiBbXCJyXCJdLFxyXG4gICAgczogW1wixaFcIl0sXHJcbiAgICDFoTogW1wic1wiXSxcclxuICAgIHQ6IFtcIsWlXCJdLFxyXG4gICAgxaU6IFtcInRcIl0sXHJcbiAgICB6OiBbXCLFvlwiXSxcclxuICAgIMW+OiBbXCJ6XCJdLFxyXG4gIH07XHJcblxyXG4gIGNvbnN0IHN0cjFDaGFycyA9IHN0cjEuc3BsaXQoXCJcIik7XHJcbiAgY29uc3Qgc3RyMkNoYXJzID0gc3RyMi5zcGxpdChcIlwiKTtcclxuXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBzdHIxQ2hhcnMubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IGNoYXIxID0gc3RyMUNoYXJzW2ldO1xyXG4gICAgY29uc3QgY2hhcjIgPSBzdHIyQ2hhcnNbaV07XHJcblxyXG4gICAgaWYgKFxyXG4gICAgICBpbnRlcnB1bmN0aW9uTWlzdGFrZXNbY2hhcjFdICYmXHJcbiAgICAgIGludGVycHVuY3Rpb25NaXN0YWtlc1tjaGFyMV0uaW5jbHVkZXMoY2hhcjIpXHJcbiAgICApIHtcclxuICAgICAgLy8gU3VidHJhY3QgYSBwZW5hbHR5IGZyb20gdGhlIGRpc3RhbmNlIGZvciBpbnRlcnB1bmN0aW9uIG1pc3Rha2VzXHJcbiAgICAgIGRpc3RhbmNlIC09IDAuNTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHJldHVybiBkaXN0YW5jZTtcclxufTtcclxuXHJcbmNvbnN0IGxldmVuc2h0ZWluRGlzdGFuY2UgPSAoc3RyMTogc3RyaW5nLCBzdHIyOiBzdHJpbmcpOiBudW1iZXIgPT4ge1xyXG4gIGNvbnN0IG1hdHJpeDogbnVtYmVyW11bXSA9IEFycmF5KHN0cjIubGVuZ3RoICsgMSlcclxuICAgIC5maWxsKG51bGwpXHJcbiAgICAubWFwKCgpID0+IEFycmF5KHN0cjEubGVuZ3RoICsgMSkuZmlsbChudWxsKSk7XHJcblxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDw9IHN0cjEubGVuZ3RoOyBpKyspIHtcclxuICAgIG1hdHJpeFswXVtpXSA9IGk7XHJcbiAgfVxyXG5cclxuICBmb3IgKGxldCBqID0gMDsgaiA8PSBzdHIyLmxlbmd0aDsgaisrKSB7XHJcbiAgICBtYXRyaXhbal1bMF0gPSBqO1xyXG4gIH1cclxuXHJcbiAgZm9yIChsZXQgaiA9IDE7IGogPD0gc3RyMi5sZW5ndGg7IGorKykge1xyXG4gICAgZm9yIChsZXQgaSA9IDE7IGkgPD0gc3RyMS5sZW5ndGg7IGkrKykge1xyXG4gICAgICBpZiAoc3RyMVtpIC0gMV0gPT09IHN0cjJbaiAtIDFdKSB7XHJcbiAgICAgICAgbWF0cml4W2pdW2ldID0gbWF0cml4W2ogLSAxXVtpIC0gMV07XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbWF0cml4W2pdW2ldID1cclxuICAgICAgICAgIE1hdGgubWluKFxyXG4gICAgICAgICAgICBtYXRyaXhbal1baSAtIDFdLCAvLyBkZWxldGlvblxyXG4gICAgICAgICAgICBtYXRyaXhbaiAtIDFdW2ldLCAvLyBpbnNlcnRpb25cclxuICAgICAgICAgICAgbWF0cml4W2ogLSAxXVtpIC0gMV0gLy8gc3Vic3RpdHV0aW9uXHJcbiAgICAgICAgICApICsgMTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1hdHJpeFtzdHIyLmxlbmd0aF1bc3RyMS5sZW5ndGhdO1xyXG59O1xyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIHJvdW5kVG9ORGVjaW1hbFBsYWNlcyhcclxuICB0b1JvdW5kOiBudW1iZXIsXHJcbiAgZGVjaW1hbFBsYWNlczogbnVtYmVyXHJcbik6IG51bWJlciB7XHJcbiAgcmV0dXJuIChcclxuICAgIE1hdGgucm91bmQodG9Sb3VuZCAqIE1hdGgucG93KDEwLCBkZWNpbWFsUGxhY2VzKSkgL1xyXG4gICAgTWF0aC5wb3coMTAsIGRlY2ltYWxQbGFjZXMpXHJcbiAgKTtcclxufVxyXG4iXX0=