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

440 lines 65.7 kB
import { checkStreetExists, findAddressPoints, getAddressPointById, } from "../db/address-points"; import { disconnectKnex } from "../db/db"; import { findFounder, getFounderById, getFounderCityCode, } from "../db/founders"; import { findSchool } from "../db/schools"; import { MunicipalityType, founderToMunicipality, } from "../db/types"; import { getMunicipalityPartResult, getRestOfMunicipalityPart, getSwitchMunicipality, getWholeMunicipality, isMunicipalitySwitch, isRestOfMunicipalityLine, isRestOfMunicipalityPartLine, isRestWithNoStreetNameLine, isWholeMunicipality, } from "./municipality"; import { parseLine } from "./smd-line-parser"; export const parseOrdinanceToAddressPoints = async ({ lines, initialState = {}, onError = () => { }, onWarning = () => { }, onProcessedLine = () => { }, includeUnmappedAddressPoints = false, schoolType, }) => { try { const state = { currentMunicipality: null, currentFilterMunicipality: null, currentArea: null, schoolsCompleted: false, areaCount: 0, rests: { noStreetNameArea: { areaIndex: null, lineNumber: null, }, municipalityParts: [], wholeMunicipalityArea: { areaIndex: null, lineNumber: null, }, includeUnmappedAddressPoints, }, municipalities: [], ...initialState, }; let lineNumber = 1; for (const rawLine of lines) { const line = cleanLine(rawLine); await processOneLine({ line, rawLine: rawLine.trim(), state, lineNumber, onError, onWarning, schoolType, }); onProcessedLine({ lineNumber, line }); lineNumber++; } if (state.currentArea != null) { if (state.currentMunicipality == null) { return []; } state.currentMunicipality.areas.push(mapAreaForExport(state.currentArea)); } await completeCurrentMunicipality(state); return state.municipalities; } catch (error) { console.error(error); } finally { await disconnectKnex(); } return []; }; export const convertMunicipality = (municipality) => { return { municipalityName: municipality.municipalityName, areas: municipality.areas.map((area) => ({ index: area.index, schools: area.schools, addresses: Array.from(area.addressMap.values()).filter((point) => point.lat !== 0 && point.lng !== 0), })), code: municipality.founder.municipalityCode, municipalityType: municipality.founder.municipalityType === MunicipalityType.City ? "city" : "district", cityCodes: [...new Set(municipality.cityCodes)], districtCodes: [...new Set(municipality.districtCodes)], unmappedPoints: municipality.unmappedPoints.filter((point) => point.lat !== 0 && point.lng !== 0), }; }; const processOneLine = async (params) => { const { line, lineNumber, state } = params; if (line[0] === "#") { await processMunicipalityLine(params); return; } if (line === "") { // end of school processEmptyLine(params); return; } if (line[0] === "!") { return; } if (state.currentArea === null) { await processFirstSchoolLine(params); return; } if (state.schoolsCompleted === false) { const foundNextSchool = await processNextSchoolLine(params); if (foundNextSchool) { return; } else { state.schoolsCompleted = true; } } if (isMunicipalitySwitch(line)) { await processMunicipalitySwitchLine(params); } else if (isWholeMunicipality(line)) { await processWholeMunicipalityLine(params); } else if (isRestWithNoStreetNameLine(line)) { state.rests.noStreetNameArea = { areaIndex: state.currentArea.index, lineNumber, }; } else if (isRestOfMunicipalityLine(line)) { state.rests.wholeMunicipalityArea = { areaIndex: state.currentArea.index, lineNumber, }; } else if (isRestOfMunicipalityPartLine(line)) { const { municipalityPartCode, errors } = await getRestOfMunicipalityPart(line, state.currentMunicipality.founder); if (errors.length > 0) { params.onError({ lineNumber: lineNumber, line, errors }); } else { state.rests.municipalityParts.push({ municipalityPartCode, areaIndex: state.currentArea.index, lineNumber: lineNumber, }); } } else { await processAddressPointLine(params); } }; const processMunicipalityLine = async ({ line, lineNumber, state, schoolType, onError, }) => { if (state.currentArea !== null) { state.currentMunicipality.areas.push(state.currentArea); } await completeCurrentMunicipality(state); const { municipality, errors } = await getNewMunicipalityByName(line, schoolType); if (errors.length > 0) { onError({ lineNumber, line, errors }); } state.currentMunicipality = municipality; state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder); state.currentArea = null; }; const completeCurrentMunicipality = async (state) => { if (state.currentMunicipality !== null) { await addRests(state); state.municipalities.push(convertMunicipality(state.currentMunicipality)); } }; const processEmptyLine = ({ state }) => { if (state.currentArea !== null) { state.currentMunicipality.areas.push(state.currentArea); state.currentArea = null; } }; const processFirstSchoolLine = async ({ rawLine, lineNumber, state, onError, }) => { if (state.currentMunicipality === null) { onError({ lineNumber, line: rawLine, errors: [ wholeLineError("Definici školy musí předcházet definice zřizovatele (uvozená '#', např. '# Strakonice').", rawLine), ], }); return; } state.currentArea = { index: state.areaCount++, schools: [ await getNewSchool({ name: rawLine, founder: state.currentMunicipality.founder, lineNumber, required: true, onError, }), ], addresses: [], addressMap: new Map(), allSchoolsAdded: false, }; state.schoolsCompleted = false; state.currentFilterMunicipality = founderToMunicipality(state.currentMunicipality.founder); }; const processNextSchoolLine = async ({ line, lineNumber, state, }) => { const school = await getNewSchool({ name: line, founder: state.currentMunicipality.founder, lineNumber, required: false, onError: () => { }, }); if (school === null) { return false; } state.currentArea.schools.push(school); return true; }; const processMunicipalitySwitchLine = async ({ line, state, lineNumber, onError, }) => { const { municipality, errors } = await getSwitchMunicipality(line, state.currentMunicipality.founder); if (errors.length > 0) { onError({ lineNumber, line, errors }); } else { state.currentFilterMunicipality = municipality; } }; const processWholeMunicipalityLine = async ({ line, state, lineNumber, onError, }) => { const { municipality, errors } = await getWholeMunicipality(line, state.currentMunicipality.founder); if (errors.length > 0) { onError({ lineNumber, line, errors }); } else { if (municipality.type === MunicipalityType.City) { state.currentMunicipality.cityCodes.push(municipality.code); } else { state.currentMunicipality.districtCodes.push(municipality.code); } const addressPoints = await findAddressPoints({ type: "wholeMunicipality", municipality, }); addAddressPointsToArea(state.currentArea, addressPoints, lineNumber); } }; const addAddressPointsToArea = (area, addressPoints, lineNumber, municipalityCode) => { for (const point of addressPoints) { if (area.addressMap.has(point.id)) { area.addressMap.get(point.id).lineNumbers.push(lineNumber - 1); } else { area.addressMap.set(point.id, mapAddressPointForExport(point, lineNumber, municipalityCode)); } } }; const processAddressPointLine = async ({ line, state, lineNumber, onError, onWarning, }) => { const { smdLines, errors } = parseLine(line); if (errors.length > 0) { onError({ lineNumber, line, errors }); } else { for (const smdLine of smdLines) { if (smdLine.type === "street") { const { exists, errors } = await checkStreetExists(smdLine.street, state.currentMunicipality.founder); if (errors.length > 0) { onWarning({ lineNumber, line, errors }); } if (exists) { const addressPoints = await findAddressPoints({ type: "smdLine", smdLine, municipality: state.currentFilterMunicipality, }); addAddressPointsToArea(state.currentArea, addressPoints, lineNumber, state.currentMunicipality.code !== state.currentFilterMunicipality.code ? state.currentFilterMunicipality.code : undefined); } } else if (smdLine.type === "municipalityPart") { const { municipalityPartCode, errors } = await getMunicipalityPartResult(smdLine.municipalityPart, line, await getFounderCityCode(state.currentFilterMunicipality.type, state.currentFilterMunicipality.code)); if (errors.length > 0) { onWarning({ lineNumber, line, errors }); } else { const addressPoints = await findAddressPoints({ type: "smdLine", smdLine, municipality: state.currentFilterMunicipality, municipalityPartCode, }); addAddressPointsToArea(state.currentArea, addressPoints, lineNumber); } } } } }; const addRestToArea = (restPoints, areaIndex, lineNumber, state) => { const addressPointsIds = getAllAddressPointsIds(state.currentMunicipality); // filter out address points already present const remainingPoints = restPoints.filter((point) => !addressPointsIds.has(point.id)); addAddressPointsToArea(state.currentMunicipality.areas.find((area) => area.index === areaIndex), remainingPoints, lineNumber); }; const addRests = async (state) => { if (state.rests.noStreetNameArea.areaIndex !== null) { await addRestWithNoStreetNameToSchool(state.rests.noStreetNameArea.lineNumber, state); } if (state.rests.wholeMunicipalityArea.areaIndex !== null) { await addRestOfMunicipality(state.rests.wholeMunicipalityArea.lineNumber, state); } for (const rest of state.rests.municipalityParts) { await addRestOfMunicipalityPart(state, rest.municipalityPartCode, rest.areaIndex, rest.lineNumber); } if (state.rests.includeUnmappedAddressPoints) { await addRestOfMunicipalityToUnmappedPoints(state); } state.rests.noStreetNameArea.areaIndex = null; state.rests.wholeMunicipalityArea.areaIndex = null; state.rests.municipalityParts = []; }; const addRestWithNoStreetNameToSchool = async (lineNumber, state) => { // get all address points without street name for current municipality const pointsNoStreetName = await findAddressPoints({ type: "wholeMunicipalityNoStreetName", municipality: { code: state.currentMunicipality.founder.municipalityCode, type: state.currentMunicipality.founder.municipalityType, }, }); addRestToArea(pointsNoStreetName, state.rests.noStreetNameArea.areaIndex, lineNumber, state); }; const addRestOfMunicipality = async (lineNumber, state) => { addRestToArea(await getRestOfMunicipality(state), state.rests.wholeMunicipalityArea.areaIndex, lineNumber, state); }; const addRestOfMunicipalityToUnmappedPoints = async (state) => { state.currentMunicipality.unmappedPoints = (await getRestOfMunicipality(state)).map((point) => mapAddressPointForExport(point)); }; const getRestOfMunicipality = async (state) => { // get all address points for current municipality const allPoints = await findAddressPoints({ type: "wholeMunicipality", municipality: { code: state.currentMunicipality.founder.municipalityCode, type: state.currentMunicipality.founder.municipalityType, }, }); // filter out address points already present const addressPointsIds = getAllAddressPointsIds(state.currentMunicipality); return allPoints.filter((point) => !addressPointsIds.has(point.id)); }; const addRestOfMunicipalityPart = async (state, municipalityPartCode, areaIndex, lineNumber) => { const allPoints = await findAddressPoints({ type: "wholeMunicipalityPart", municipalityPartCode, }); addRestToArea(allPoints, areaIndex, lineNumber, state); }; export const getNewMunicipalityByName = async (name, schoolType) => { const { founder, errors } = await findFounder(name, schoolType); return getNewMunicipality(founder, errors); }; export const getNewMunicipalityByFounderId = async (founderId, schoolType) => { const { founder, errors } = await getFounderById(founderId, schoolType); return getNewMunicipality(founder, errors); }; const getNewMunicipality = (founder, errors) => ({ municipality: { municipalityName: founder ? founder.name : "Neznámá obec", founder, areas: [], code: founder ? founder.municipalityCode : 0, municipalityType: founder.municipalityType === MunicipalityType.City ? "city" : "district", cityCodes: founder.municipalityType === MunicipalityType.City ? [founder.municipalityCode] : [], districtCodes: founder.municipalityType === MunicipalityType.District ? [founder.municipalityCode] : [], unmappedPoints: [], }, errors, }); export const getNewSchool = async ({ name, founder, lineNumber, required, onError, }) => { let exportSchool = { name, izo: "", }; if (founder !== null) { const { school, errors } = findSchool(name, founder.schools, required ? undefined : 4); if (errors.length > 0) { onError({ lineNumber, line: name, errors }); } if (school) { exportSchool.name = school.name; exportSchool.izo = school.izo || ""; if (school.locations.length > 0) { const position = await getAddressPointById(school.locations[0].addressPointId); if (position !== null) { exportSchool.position = mapAddressPointForExport(position); } } } else { return null; } } return { ...exportSchool, addressMap: new Map() }; }; const getAllAddressPointsIds = (municipality) => { const addressPointsIds = new Set(); for (const area of municipality.areas) { for (const id of area.addressMap.keys()) { addressPointsIds.add(id); } } return addressPointsIds; }; const mapAddressPointForExport = (addressPoint, lineNumber, municipalityCode) => { return { address: addressPoint.address, lat: roundToNDecimalPlaces(addressPoint.lat, 6), lng: roundToNDecimalPlaces(addressPoint.lng, 6), ...(lineNumber !== undefined ? { lineNumbers: [lineNumber - 1] } : {}), ...(municipalityCode !== undefined ? { municipalityCode } : {}), }; }; const mapAreaForExport = (area) => ({ ...area, schools: area.schools.map((school) => ({ ...school, position: school.position ? mapAddressPointForExport(school.position) : null, })), }); const cleanLine = (line) => { return line.trim().replace(/–/g, "-"); }; export const wholeLineError = (message, line) => ({ message, startOffset: 0, endOffset: line.length + 1, }); const roundToNDecimalPlaces = (toRound, decimalPlaces) => { return (Math.round(toRound * Math.pow(10, decimalPlaces)) / Math.pow(10, decimalPlaces)); }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic21kLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3N0cmVldC1tYXJrZG93bi9zbWQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUNMLGlCQUFpQixFQUNqQixpQkFBaUIsRUFDakIsbUJBQW1CLEdBQ3BCLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQyxPQUFPLEVBQ0wsV0FBVyxFQUNYLGNBQWMsRUFDZCxrQkFBa0IsR0FDbkIsTUFBTSxnQkFBZ0IsQ0FBQztBQUN4QixPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQzNDLE9BQU8sRUFFTCxnQkFBZ0IsRUFFaEIscUJBQXFCLEdBQ3RCLE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFDTCx5QkFBeUIsRUFDekIseUJBQXlCLEVBQ3pCLHFCQUFxQixFQUNyQixvQkFBb0IsRUFDcEIsb0JBQW9CLEVBQ3BCLHdCQUF3QixFQUN4Qiw0QkFBNEIsRUFDNUIsMEJBQTBCLEVBQzFCLG1CQUFtQixHQUNwQixNQUFNLGdCQUFnQixDQUFDO0FBQ3hCLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQTJCOUMsTUFBTSxDQUFDLE1BQU0sNkJBQTZCLEdBQUcsS0FBSyxFQUFFLEVBQ2xELEtBQUssRUFDTCxZQUFZLEdBQUcsRUFBRSxFQUNqQixPQUFPLEdBQUcsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUNsQixTQUFTLEdBQUcsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUNwQixlQUFlLEdBQUcsR0FBRyxFQUFFLEdBQUUsQ0FBQyxFQUMxQiw0QkFBNEIsR0FBRyxLQUFLLEVBQ3BDLFVBQVUsR0FDVSxFQUEyQixFQUFFO0lBQ2pELElBQUk7UUFDRixNQUFNLEtBQUssR0FBYTtZQUN0QixtQkFBbUIsRUFBRSxJQUFJO1lBQ3pCLHlCQUF5QixFQUFFLElBQUk7WUFDL0Is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QUFDLElBQUk7S0FDVCxDQUFDLENBQUM7Q0FDSixDQUFDLENBQUM7QUFFSCxNQUFNLFNBQVMsR0FBRyxDQUFDLElBQVksRUFBRSxFQUFFO0lBQ2pDLE9BQU8sSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLEVBQUUsR0FBRyxDQUFDLENBQUM7QUFDeEMsQ0FBQyxDQUFDO0FBRUYsTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsT0FBZSxFQUFFLElBQVksRUFBWSxFQUFFLENBQUMsQ0FBQztJQUMxRSxPQUFPO0lBQ1AsV0FBVyxFQUFFLENBQUM7SUFDZCxTQUFTLEVBQUUsSUFBSSxDQUFDLE1BQU0sR0FBRyxDQUFDO0NBQzNCLENBQUMsQ0FBQztBQUVILE1BQU0scUJBQXFCLEdBQUcsQ0FDNUIsT0FBZSxFQUNmLGFBQXFCLEVBQ2IsRUFBRTtJQUNWLE9BQU8sQ0FDTCxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUNqRCxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxhQUFhLENBQUMsQ0FDNUIsQ0FBQztBQUNKLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XHJcbiAgY2hlY2tTdHJlZXRFeGlzdHMsXHJcbiAgZmluZEFkZHJlc3NQb2ludHMsXHJcbiAgZ2V0QWRkcmVzc1BvaW50QnlJZCxcclxufSBmcm9tIFwiLi4vZGIvYWRkcmVzcy1wb2ludHNcIjtcclxuaW1wb3J0IHsgZGlzY29ubmVjdEtuZXggfSBmcm9tIFwiLi4vZGIvZGJcIjtcclxuaW1wb3J0IHtcclxuICBmaW5kRm91bmRlcixcclxuICBnZXRGb3VuZGVyQnlJZCxcclxuICBnZXRGb3VuZGVyQ2l0eUNvZGUsXHJcbn0gZnJvbSBcIi4uL2RiL2ZvdW5kZXJzXCI7XHJcbmltcG9ydCB7IGZpbmRTY2hvb2wgfSBmcm9tIFwiLi4vZGIvc2Nob29sc1wiO1xyXG5pbXBvcnQge1xyXG4gIEZvdW5kZXIsXHJcbiAgTXVuaWNpcGFsaXR5VHlwZSxcclxuICBTY2hvb2xUeXBlLFxyXG4gIGZvdW5kZXJUb011bmljaXBhbGl0eSxcclxufSBmcm9tIFwiLi4vZGIvdHlwZXNcIjtcclxuaW1wb3J0IHtcclxuICBnZXRNdW5pY2lwYWxpdHlQYXJ0UmVzdWx0LFxyXG4gIGdldFJlc3RPZk11bmljaXBhbGl0eVBhcnQsXHJcbiAgZ2V0U3dpdGNoTXVuaWNpcGFsaXR5LFxyXG4gIGdldFdob2xlTXVuaWNpcGFsaXR5LFxyXG4gIGlzTXVuaWNpcGFsaXR5U3dpdGNoLFxyXG4gIGlzUmVzdE9mTXVuaWNpcGFsaXR5TGluZSxcclxuICBpc1Jlc3RPZk11bmljaXBhbGl0eVBhcnRMaW5lLFxyXG4gIGlzUmVzdFdpdGhOb1N0cmVldE5hbWVMaW5lLFxyXG4gIGlzV2hvbGVNdW5pY2lwYWxpdHksXHJcbn0gZnJvbSBcIi4vbXVuaWNpcGFsaXR5XCI7XHJcbmltcG9ydCB7IHBhcnNlTGluZSB9IGZyb20gXCIuL3NtZC1saW5lLXBhcnNlclwiO1xyXG5pbXBvcnQge1xyXG4gIEFkZHJlc3NQb2ludCxcclxuICBFcnJvckNhbGxiYWNrUGFyYW1zLFxyXG4gIEV4cG9ydEFkZHJlc3NQb2ludCxcclxuICBJbnRlcm1lZGlhdGVBcmVhLFxyXG4gIEludGVybWVkaWF0ZU11bmljaXBhbGl0eSxcclxuICBJbnRlcm1lZGlhdGVNdW5pY2lwYWxpdHlSZXN1bHQsXHJcbiAgSW50ZXJtZWRpYXRlU2Nob29sLFxyXG4gIE11bmljaXBhbGl0eSxcclxuICBQcm9jZXNzTGluZUNhbGxiYWNrUGFyYW1zLFxyXG4gIFByb2Nlc3NMaW5lUGFyYW1zLFxyXG4gIFNjaG9vbCxcclxuICBTbWRFcnJvcixcclxuICBTbWRTdGF0ZSxcclxufSBmcm9tIFwiLi90eXBlc1wiO1xyXG5cclxuaW50ZXJmYWNlIFBhcnNlT3JkaW5hbmNlUHJvcHMge1xyXG4gIGxpbmVzOiBzdHJpbmdbXTtcclxuICBpbml0aWFsU3RhdGU/OiBQYXJ0aWFsPFNtZFN0YXRlPjtcclxuICBvbkVycm9yPzogKHBhcmFtczogRXJyb3JDYWxsYmFja1BhcmFtcykgPT4gdm9pZDtcclxuICBvbldhcm5pbmc/OiAocGFyYW1zOiBFcnJvckNhbGxiYWNrUGFyYW1zKSA9PiB2b2lkO1xyXG4gIG9uUHJvY2Vzc2VkTGluZT86IChwYXJhbXM6IFByb2Nlc3NMaW5lQ2FsbGJhY2tQYXJhbXMpID0+IHZvaWQ7XHJcbiAgaW5jbHVkZVVubWFwcGVkQWRkcmVzc1BvaW50czogYm9vbGVhbjtcclxuICBzY2hvb2xUeXBlOiBTY2hvb2xUeXBlO1xyXG59XHJcblxyXG5leHBvcnQgY29uc3QgcGFyc2VPcmRpbmFuY2VUb0FkZHJlc3NQb2ludHMgPSBhc3luYyAoe1xyXG4gIGxpbmVzLFxyXG4gIGluaXRpYWxTdGF0ZSA9IHt9LFxyXG4gIG9uRXJyb3IgPSAoKSA9PiB7fSxcclxuICBvbldhcm5pbmcgPSAoKSA9PiB7fSxcclxuICBvblByb2Nlc3NlZExpbmUgPSAoKSA9PiB7fSxcclxuICBpbmNsdWRlVW5tYXBwZWRBZGRyZXNzUG9pbnRzID0gZmFsc2UsXHJcbiAgc2Nob29sVHlwZSxcclxufTogUGFyc2VPcmRpbmFuY2VQcm9wcyk6IFByb21pc2U8TXVuaWNpcGFsaXR5W10+ID0+IHtcclxuICB0cnkge1xyXG4gICAgY29uc3Qgc3RhdGU6IFNtZFN0YXRlID0ge1xyXG4gICAgICBjdXJyZW50TXVuaWNpcGFsaXR5OiBudWxsLFxyXG4gICAgICBjdXJyZW50RmlsdGVyTXVuaWNpcGFsaXR5OiBudWxsLFxyXG4gICAgICBjdXJyZW50QXJlYTogbnVsbCxcclxuICAgICAgc2Nob29sc0NvbXBsZXRlZDogZmFsc2UsXHJcbiAgICAgIGFyZWFDb3VudDogMCxcclxuICAgICAgcmVzdHM6IHtcclxuICAgICAgICBub1N0cmVldE5hbWVBcmVhOiB7XHJcbiAgICAgICAgICBhcmVhSW5kZXg6IG51bGwsXHJcbiAgICAgICAgICBsaW5lTnVtYmVyOiBudWxsLFxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgbXVuaWNpcGFsaXR5UGFydHM6IFtdLFxyXG4gICAgICAgIHdob2xlTXVuaWNpcGFsaXR5QXJlYToge1xyXG4gICAgICAgICAgYXJlYUluZGV4OiBudWxsLFxyXG4gICAgICAgICAgbGluZU51bWJlcjogbnVsbCxcclxuICAgICAgICB9LFxyXG4gICAgICAgIGluY2x1ZGVVbm1hcHBlZEFkZHJlc3NQb2ludHMsXHJcbiAgICAgIH0sXHJcbiAgICAgIG11bmljaXBhbGl0aWVzOiBbXSxcclxuICAgICAgLi4uaW5pdGlhbFN0YXRlLFxyXG4gICAgfTtcclxuXHJcbiAgICBsZXQgbGluZU51bWJlciA9IDE7XHJcblxyXG4gICAgZm9yIChjb25zdCByYXdMaW5lIG9mIGxpbmVzKSB7XHJcbiAgICAgIGNvbnN0IGxpbmUgPSBjbGVhbkxpbmUocmF3TGluZSk7XHJcbiAgICAgIGF3YWl0IHByb2Nlc3NPbmVMaW5lKHtcclxuICAgICAgICBsaW5lLFxyXG4gICAgICAgIHJhd0xpbmU6IHJhd0xpbmUudHJpbSgpLFxyXG4gICAgICAgIHN0YXRlLFxyXG4gICAgICAgIGxpbmVOdW1iZXIsXHJcbiAgICAgICAgb25FcnJvcixcclxuICAgICAgICBvbldhcm5pbmcsXHJcbiAgICAgICAgc2Nob29sVHlwZSxcclxuICAgICAgfSk7XHJcbiAgICAgIG9uUHJvY2Vzc2VkTGluZSh7IGxpbmVOdW1iZXIsIGxpbmUgfSk7XHJcbiAgICAgIGxpbmVOdW1iZXIrKztcclxuICAgIH1cclxuXHJcbiAgICBpZiAoc3RhdGUuY3VycmVudEFyZWEgIT0gbnVsbCkge1xyXG4gICAgICBpZiAoc3RhdGUuY3VycmVudE11bmljaXBhbGl0eSA9PSBudWxsKSB7XHJcbiAgICAgICAgcmV0dXJuIFtdO1xyXG4gICAgICB9XHJcbiAgICAgIHN0YXRlLmN1cnJlbnRNdW5pY2lwYWxpdHkuYXJlYXMucHVzaChtYXBBcmVhRm9yRXhwb3J0KHN0YXRlLmN1cnJlbnRBcmVhKSk7XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgY29tcGxldGVDdXJyZW50TXVuaWNpcGFsaXR5KHN0YXRlKTtcclxuXHJcbiAgICByZXR1cm4gc3RhdGUubXVuaWNpcGFsaXRpZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGNvbnNvbGUuZXJyb3IoZXJyb3IpO1xyXG4gIH0gZmluYWxseSB7XHJcbiAgICBhd2FpdCBkaXNjb25uZWN0S25leCgpO1xyXG4gIH1cclxuICByZXR1cm4gW107XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgY29udmVydE11bmljaXBhbGl0eSA9IChcclxuICBtdW5pY2lwYWxpdHk6IEludGVybWVkaWF0ZU11bmljaXBhbGl0eVxyXG4pOiBNdW5pY2lwYWxpdHkgPT4ge1xyXG4gIHJldHVybiB7XHJcbiAgICBtdW5pY2lwYWxpdHlOYW1lOiBtdW5pY2lwYWxpdHkubXVuaWNpcGFsaXR5TmFtZSxcclxuICAgIGFyZWFzOiBtdW5pY2lwYWxpdHkuYXJlYXMubWFwKChhcmVhKSA9PiAoe1xyXG4gICAgICBpbmRleDogYXJlYS5pbmRleCxcclxuICAgICAgc2Nob29sczogYXJlYS5zY2hvb2xzLFxyXG4gICAgICBhZGRyZXNzZXM6IEFycmF5LmZyb20oYXJlYS5hZGRyZXNzTWFwLnZhbHVlcygpKS5maWx0ZXIoXHJcbiAgICAgICAgKHBvaW50KSA9PiBwb2ludC5sYXQgIT09IDAgJiYgcG9pbnQubG5nICE9PSAwXHJcbiAgICAgICksXHJcbiAgICB9KSksXHJcbiAgICBjb2RlOiBtdW5pY2lwYWxpdHkuZm91bmRlci5tdW5pY2lwYWxpdHlDb2RlLFxyXG4gICAgbXVuaWNpcGFsaXR5VHlwZTpcclxuICAgICAgbXVuaWNpcGFsaXR5LmZvdW5kZXIubXVuaWNpcGFsaXR5VHlwZSA9PT0gTXVuaWNpcGFsaXR5VHlwZS5DaXR5XHJcbiAgICAgICAgPyBcImNpdHlcIlxyXG4gICAgICAgIDogXCJkaXN0cmljdFwiLFxyXG4gICAgY2l0eUNvZGVzOiBbLi4ubmV3IFNldChtdW5pY2lwYWxpdHkuY2l0eUNvZGVzKV0sXHJcbiAgICBkaXN0cmljdENvZGVzOiBbLi4ubmV3IFNldChtdW5pY2lwYWxpdHkuZGlzdHJpY3RDb2RlcyldLFxyXG4gICAgdW5tYXBwZWRQb2ludHM6IG11bmljaXBhbGl0eS51bm1hcHBlZFBvaW50cy5maWx0ZXIoXHJcbiAgICAgIChwb2ludCkgPT4gcG9pbnQubGF0ICE9PSAwICYmIHBvaW50LmxuZyAhPT0gMFxyXG4gICAgKSxcclxuICB9O1xyXG59O1xyXG5cclxuY29uc3QgcHJvY2Vzc09uZUxpbmUgPSBhc3luYyAocGFyYW1zOiBQcm9jZXNzTGluZVBhcmFtcykgPT4ge1xyXG4gIGNvbnN0IHsgbGluZSwgbGluZU51bWJlciwgc3RhdGUgfSA9IHBhcmFtcztcclxuXHJcbiAgaWYgKGxpbmVbMF0gPT09IFwiI1wiKSB7XHJcbiAgICBhd2FpdCBwcm9jZXNzTXVuaWNpcGFsaXR5TGluZShwYXJhbXMpO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgaWYgKGxpbmUgPT09IFwiXCIpIHtcclxuICAgIC8vIGVuZCBvZiBzY2hvb2xcclxuICAgIHByb2Nlc3NFbXB0eUxpbmUocGFyYW1zKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIGlmIChsaW5lWzBdID09PSBcIiFcIikge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgaWYgKHN0YXRlLmN1cnJlbnRBcmVhID09PSBudWxsKSB7XHJcbiAgICBhd2FpdCBwcm9jZXNzRmlyc3RTY2hvb2xMaW5lKHBhcmFtcyk7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICBpZiAoc3RhdGUuc2Nob29sc0NvbXBsZXRlZCA9PT0gZmFsc2UpIHtcclxuICAgIGNvbnN0IGZvdW5kTmV4dFNjaG9vbCA9IGF3YWl0IHByb2Nlc3NOZXh0U2Nob29sTGluZShwYXJhbXMpO1xyXG4gICAgaWYgKGZvdW5kTmV4dFNjaG9vbCkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBzdGF0ZS5zY2hvb2xzQ29tcGxldGVkID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIGlmIChpc011bmljaXBhbGl0eVN3aXRjaChsaW5lKSkge1xyXG4gICAgYXdhaXQgcHJvY2Vzc011bmljaXBhbGl0eVN3aXRjaExpbmUocGFyYW1zKTtcclxuICB9IGVsc2UgaWYgKGlzV2hvbGVNdW5pY2lwYWxpdHkobGluZSkpIHtcclxuICAgIGF3YWl0IHByb2Nlc3NXaG9sZU11bmljaXBhbGl0eUxpbmUocGFyYW1zKTtcclxuICB9IGVsc2UgaWYgKGlzUmVzdFdpdGhOb1N0cmVldE5hbWVMaW5lKGxpbmUpKSB7XHJcbiAgICBzdGF0ZS5yZXN0cy5ub1N0cmVldE5hbWVBcmVhID0ge1xyXG4gICAgICBhcmVhSW5kZXg6IHN0YXRlLmN1cnJlbnRBcmVhLmluZGV4LFxyXG4gICAgICBsaW5lTnVtYmVyLFxyXG4gICAgfTtcclxuICB9IGVsc2UgaWYgKGlzUmVzdE9mTXVuaWNpcGFsaXR5TGluZShsaW5lKSkge1xyXG4gICAgc3RhdGUucmVzdHMud2hvbGVNdW5pY2lwYWxpdHlBcmVhID0ge1xyXG4gICAgICBhcmVhSW5kZXg6IHN0YXRlLmN1cnJlbnRBcmVhLmluZGV4LFxyXG4gICAgICBsaW5lTnVtYmVyLFxyXG4gICAgfTtcclxuICB9IGVsc2UgaWYgKGlzUmVzdE9mTXVuaWNpcGFsaXR5UGFydExpbmUobGluZSkpIHtcclxuICAgIGNvbnN0IHsgbXVuaWNpcGFsaXR5UGFydENvZGUsIGVycm9ycyB9ID0gYXdhaXQgZ2V0UmVzdE9mTXVuaWNpcGFsaXR5UGFydChcclxuICAgICAgbGluZSxcclxuICAgICAgc3RhdGUuY3VycmVudE11bmljaXBhbGl0eS5mb3VuZGVyXHJcbiAgICApO1xyXG4gICAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XHJcbiAgICAgIHBhcmFtcy5vbkVycm9yKHsgbGluZU51bWJlcjogbGluZU51bWJlciwgbGluZSwgZXJyb3JzIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgc3RhdGUucmVzdHMubXVuaWNpcGFsaXR5UGFydHMucHVzaCh7XHJcbiAgICAgICAgbXVuaWNpcGFsaXR5UGFydENvZGUsXHJcbiAgICAgICAgYXJlYUluZGV4OiBzdGF0ZS5jdXJyZW50QXJlYS5pbmRleCxcclxuICAgICAgICBsaW5lTnVtYmVyOiBsaW5lTnVtYmVyLFxyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgYXdhaXQgcHJvY2Vzc0FkZHJlc3NQb2ludExpbmUocGFyYW1zKTtcclxuICB9XHJcbn07XHJcblxyXG5jb25zdCBwcm9jZXNzTXVuaWNpcGFsaXR5TGluZSA9IGFzeW5jICh7XHJcbiAgbGluZSxcclxuICBsaW5lTnVtYmVyLFxyXG4gIHN0YXRlLFxyXG4gIHNjaG9vbFR5cGUsXHJcbiAgb25FcnJvcixcclxufTogUHJvY2Vzc0xpbmVQYXJhbXMpID0+IHtcclxuICBpZiAoc3RhdGUuY3VycmVudEFyZWEgIT09IG51bGwpIHtcclxuICAgIHN0YXRlLmN1cnJlbnRNdW5pY2lwYWxpdHkuYXJlYXMucHVzaChzdGF0ZS5jdXJyZW50QXJlYSk7XHJcbiAgfVxyXG5cclxuICBhd2FpdCBjb21wbGV0ZUN1cnJlbnRNdW5pY2lwYWxpdHkoc3RhdGUpO1xyXG5cclxuICBjb25zdCB7IG11bmljaXBhbGl0eSwgZXJyb3JzIH0gPSBhd2FpdCBnZXROZXdNdW5pY2lwYWxpdHlCeU5hbWUoXHJcbiAgICBsaW5lLFxyXG4gICAgc2Nob29sVHlwZVxyXG4gICk7XHJcbiAgaWYgKGVycm9ycy5sZW5ndGggPiAwKSB7XHJcbiAgICBvbkVycm9yKHsgbGluZU51bWJlciwgbGluZSwgZXJyb3JzIH0pO1xyXG4gIH1cclxuICBzdGF0ZS5jdXJyZW50TXVuaWNpcGFsaXR5ID0gbXVuaWNpcGFsaXR5O1xyXG4gIHN0YXRlLmN1cnJlbnRGaWx0ZXJNdW5pY2lwYWxpdHkgPSBmb3VuZGVyVG9NdW5pY2lwYWxpdHkoXHJcbiAgICBzdGF0ZS5jdXJyZW50TXVuaWNpcGFsaXR5LmZvdW5kZXJcclxuICApO1xyXG5cclxuICBzdGF0ZS5jdXJyZW50QXJlYSA9IG51bGw7XHJcbn07XHJcblxyXG5jb25zdCBjb21wbGV0ZUN1cnJlbnRNdW5pY2lwYWxpdHkgPSBhc3luYyAoc3RhdGU6IFNtZFN0YXRlKSA9PiB7XHJcbiAgaWYgKHN0YXRlLmN1cnJlbnRNdW5pY2lwYWxpdHkgIT09IG51bGwpIHtcclxuICAgIGF3YWl0IGFkZFJlc3RzKHN0YXRlKTtcclxuICAgIHN0YXRlLm11bmljaXBhbGl0aWVzLnB1c2goY29udmVydE11bmljaXBhbGl0eShzdGF0ZS5jdXJyZW50TXVuaWNpcGFsaXR5KSk7XHJcbiAgfVxyXG59O1xyXG5cclxuY29uc3QgcHJvY2Vzc0VtcHR5TGluZSA9ICh7IHN0YXRlIH06IFByb2Nlc3NMaW5lUGFyYW1zKSA9PiB7XHJcbiAgaWYgKHN0YXRlLmN1cnJlbnRBcmVhICE9PSBudWxsKSB7XHJcbiAgICBzdGF0ZS5jdXJyZW50TXVuaWNpcGFsaXR5LmFyZWFzLnB1c2goc3RhdGUuY3VycmVudEFyZWEpO1xyXG4gICAgc3RhdGUuY3VycmVudEFyZWEgPSBudWxsO1xyXG4gIH1cclxufTtcclxuXHJcbmNvbnN0IHByb2Nlc3NGaXJzdFNjaG9vbExpbmUgPSBhc3luYyAoe1xyXG4gIHJhd0xpbmUsXHJcbiAgbGluZU51bWJlcixcclxuICBzdGF0ZSxcclxuICBvbkVycm9yLFxyXG59OiBQcm9jZXNzTGluZVBhcmFtcykgPT4ge1xyXG4gIGlmIChzdGF0ZS5jdXJyZW50TXVuaWNpcGFsaXR5ID09PSBudWxsKSB7XHJcbiAgICBvbkVycm9yKHtcclxuICAgICAgbGluZU51bWJlcixcclxuICAgICAgbGluZTogcmF3TGluZSxcclxuICAgICAgZXJyb3JzOiBbXHJcbiAgICAgICAgd2hvbGVMaW5lRXJyb3IoXHJcbiAgICAgICAgICBcIkRlZmluaWNpIMWha29seSBtdXPDrSBwxZllZGNow6F6ZXQgZGVmaW5pY2UgesWZaXpvdmF0ZWxlICh1dm96ZW7DoSAnIycsIG5hcMWZLiAnIyBTdHJha29uaWNlJykuXCIsXHJcbiAgICAgICAgICByYXdMaW5lXHJcbiAgICAgICAgKSxcclxuICAgICAgXSxcclxuICAgIH0pO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuICBzdGF0ZS5jdXJyZW50QXJlYSA9IHtcclxuICAgIGluZGV4OiBzdGF0ZS5hcmVhQ291bnQrKyxcclxuICAgIHNjaG9vbHM6IFtcclxuICAgICAgYXdhaXQgZ2V0TmV3U2Nob29sKHtcclxuICAgICAgICBuYW1lOiByYXdMaW5lLFxyXG4gICAgICAgIGZvdW5kZXI6IHN0YXRlLmN1cnJlbnRNdW5pY2lwYWxpdHkuZm91bmRlcixcclxuICAgICAgICBsaW5lTnVtYmVyLFxyXG4gICAgICAgIHJlcXVpcmVkOiB0cnVlLFxyXG4gICAgICAgIG9uRXJyb3IsXHJcbiAgICAgIH0pLFxyXG4gICAgXSxcclxuICAgIGFkZHJlc3NlczogW10sXHJcbiAgICBhZGRyZXNzTWFwOiBuZXcgTWFwPG51bWJlciwgRXhwb3J0QWRkcmVzc1BvaW50PigpLFxyXG4gICAgYWxsU2Nob29sc0FkZGVkOiBmYWxzZSxcclxuICB9O1xyXG4gIHN0YXRlLnNjaG9vbHNDb21wbGV0ZWQgPSBmYWxzZTtcclxuICBzdGF0ZS5jdXJyZW50RmlsdGVyTXVuaWNpcGFsaXR5ID0gZm91bmRlclRvTXVuaWNpcGFsaXR5KFxyXG4gICAgc3RhdGUuY3VycmVudE11bmljaXBhbGl0eS5mb3VuZGVyXHJcbiAgKTtcclxufTtcclxuXHJcbmNvbnN0IHByb2Nlc3NOZXh0U2Nob29sTGluZSA9IGFzeW5jICh7XHJcbiAgbGluZSxcclxuICBsaW5lTnVtYmVyLFxyXG4gIHN0YXRlLFxyXG59OiBQcm9jZXNzTGluZVBhcmFtcyk6IFByb21pc2U8Ym9vbGVhbj4gPT4ge1xyXG4gIGNvbnN0IHNjaG9vbCA9IGF3YWl0IGdldE5ld1NjaG9vbCh7XHJcbiAgICBuYW1lOiBsaW5lLFxyXG4gICAgZm91bmRlcjogc3RhdGUuY3VycmVudE11bmljaXBhbGl0eS5mb3VuZGVyLFxyXG4gICAg