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
JavaScript
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