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

95 lines 18 kB
import { wholeLineError } from "../street-markdown/smd"; import { findClosestString } from "../utils/helpers"; import { getKnexDb, insertMultipleRows } from "./db"; const BATCH_SIZE = 500; export const insertSchools = async (schools) => { const knex = getKnexDb(); const uniqueSchools = filterOutDuplicates(schools); // Fetch all existing schools with their current location in one query const existing = await knex("school") .leftJoin("school_location", "school.izo", "school_location.school_izo") .select("school.izo", "school.name", "school.capacity", "school_location.address_point_id"); const existingMap = new Map(existing.map((r) => [r.izo, r])); const toInsert = uniqueSchools.filter((s) => !existingMap.has(s.izo)); const toUpdate = uniqueSchools.filter((s) => existingMap.has(s.izo)); // --- Insert new schools --- const insertedSchools = await insertMultipleRows(toInsert.map((school) => [ school.izo, school.redizo, school.name, school.capacity.toString(), school.type.toString(), ]), "school", ["izo", "redizo", "name", "capacity", "type"]); // --- Update existing schools (name + capacity) in batches --- const toUpdateFields = toUpdate.filter((s) => { const row = existingMap.get(s.izo); return row.name !== s.name || Number(row.capacity) !== s.capacity; }); for (let i = 0; i < toUpdateFields.length; i += BATCH_SIZE) { const batch = toUpdateFields.slice(i, i + BATCH_SIZE); await Promise.all(batch.map((s) => knex("school").where("izo", s.izo).update({ name: s.name, capacity: s.capacity }))); } // --- Handle locations --- // New schools and existing schools without any location need an insert const toInsertLocation = [ ...toInsert, ...toUpdate.filter((s) => existingMap.get(s.izo).address_point_id === null), ].filter((s) => s.locations.length > 0); // Existing schools whose first location changed need a delete + insert // Guard against reordering: only update if the old RUIAN is gone entirely from the new locations const toUpdateLocation = toUpdate.filter((s) => { const row = existingMap.get(s.izo); const newRuians = s.locations.map((l) => l.addressPointId); return (row.address_point_id !== null && newRuians.length > 0 && !newRuians.includes(row.address_point_id)); }); // Delete outdated locations in batches for (let i = 0; i < toUpdateLocation.length; i += BATCH_SIZE) { const batch = toUpdateLocation.slice(i, i + BATCH_SIZE); await knex("school_location") .whereIn("school_izo", batch.map((s) => s.izo)) .delete(); } let insertedLocations = 0; for (const school of [...toInsertLocation, ...toUpdateLocation]) { try { insertedLocations += await insertMultipleRows([[school.izo, school.locations[0].addressPointId.toString()]], "school_location", ["school_izo", "address_point_id"], true); } catch (error) { console.log(`Cannot add location with RUIAN code ${school.locations[0].addressPointId} (school IZO = ${school.izo}): code does not exist.`); } } return insertedSchools + insertedLocations; }; export const findSchool = (name, schools, maxDistance) => { if (schools.length === 0) { return { school: null, errors: [wholeLineError("Aktuální zřizovatel nemá žádné školy.", name)], }; } const errors = []; const exactSchool = schools.find((school) => school.name === name); if (exactSchool) { return { school: exactSchool, errors }; } const namesList = schools.map((school) => school.name); const bestMatch = findClosestString(name, namesList, maxDistance); if (bestMatch === null) { errors.push(wholeLineError(`Škola s názvem '${name}' neexistuje.`, name)); return { school: null, errors }; } const closestSchool = schools.find((school) => bestMatch === school.name); errors.push(wholeLineError(`Škola s názvem '${name}' neexistuje, mysleli jste '${bestMatch}'?`, name)); return { school: closestSchool, errors }; }; const filterOutDuplicates = (schools) => { const izoSet = new Set(); return schools.filter((school) => { const duplicate = izoSet.has(school.izo); izoSet.add(school.izo); return !duplicate; }); }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nob29scy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9kYi9zY2hvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUV4RCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNyRCxPQUFPLEVBQUUsU0FBUyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sTUFBTSxDQUFDO0FBR3JELE1BQU0sVUFBVSxHQUFHLEdBQUcsQ0FBQztBQUV2QixNQUFNLENBQUMsTUFBTSxhQUFhLEdBQUcsS0FBSyxFQUFFLE9BQWlCLEVBQW1CLEVBQUU7SUFDeEUsTUFBTSxJQUFJLEdBQUcsU0FBUyxFQUFFLENBQUM7SUFFekIsTUFBTSxhQUFhLEdBQUcsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFbkQsc0VBQXNFO0lBQ3RFLE1BQU0sUUFBUSxHQUNaLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQztTQUNqQixRQUFRLENBQUMsaUJBQWlCLEVBQUUsWUFBWSxFQUFFLDRCQUE0QixDQUFDO1NBQ3ZFLE1BQU0sQ0FBQyxZQUFZLEVBQUUsYUFBYSxFQUFFLGlCQUFpQixFQUFFLGtDQUFrQyxDQUFDLENBQUM7SUFFaEcsTUFBTSxXQUFXLEdBQUcsSUFBSSxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUU3RCxNQUFNLFFBQVEsR0FBRyxhQUFhLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDdEUsTUFBTSxRQUFRLEdBQUcsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztJQUVyRSw2QkFBNkI7SUFDN0IsTUFBTSxlQUFlLEdBQUcsTUFBTSxrQkFBa0IsQ0FDOUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFLENBQUM7UUFDdkIsTUFBTSxDQUFDLEdBQUc7UUFDVixNQUFNLENBQUMsTUFBTTtRQUNiLE1BQU0sQ0FBQyxJQUFJO1FBQ1gsTUFBTSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUU7UUFDMUIsTUFBTSxDQUFDLElBQUksQ0FBQyxRQUFRLEVBQUU7S0FDdkIsQ0FBQyxFQUNGLFFBQVEsRUFDUixDQUFDLEtBQUssRUFBRSxRQUFRLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FDOUMsQ0FBQztJQUVGLCtEQUErRDtJQUMvRCxNQUFNLGNBQWMsR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUU7UUFDM0MsTUFBTSxHQUFHLEdBQUcsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDbkMsT0FBTyxHQUFHLENBQUMsSUFBSSxLQUFLLENBQUMsQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsS0FBSyxDQUFDLENBQUMsUUFBUSxDQUFDO0lBQ3BFLENBQUMsQ0FBQyxDQUFDO0lBRUgsS0FBSyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLGNBQWMsQ0FBQyxNQUFNLEVBQUUsQ0FBQyxJQUFJLFVBQVUsRUFBRTtRQUMxRCxNQUFNLEtBQUssR0FBRyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFDdEQsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUNmLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUNkLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQ2xGLENBQ0YsQ0FBQztLQUNIO0lBRUQsMkJBQTJCO0lBQzNCLHVFQUF1RTtJQUN2RSxNQUFNLGdCQUFnQixHQUFHO1FBQ3ZCLEdBQUcsUUFBUTtRQUNYLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsZ0JBQWdCLEtBQUssSUFBSSxDQUFDO0tBQzVFLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztJQUV4Qyx1RUFBdUU7SUFDdkUsaUdBQWlHO0lBQ2pHLE1BQU0sZ0JBQWdCLEdBQUcsUUFBUSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFO1FBQzdDLE1BQU0sR0FBRyxHQUFHLFdBQVcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ25DLE1BQU0sU0FBUyxHQUFHLENBQUMsQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDM0QsT0FBTyxDQUNMLEdBQUcsQ0FBQyxnQkFBZ0IsS0FBSyxJQUFJO1lBQzdCLFNBQVMsQ0FBQyxNQUFNLEdBQUcsQ0FBQztZQUNwQixDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLGdCQUFnQixDQUFDLENBQzFDLENBQUM7SUFDSixDQUFDLENBQUMsQ0FBQztJQUVILHVDQUF1QztJQUN2QyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsZ0JBQWdCLENBQUMsTUFBTSxFQUFFLENBQUMsSUFBSSxVQUFVLEVBQUU7UUFDNUQsTUFBTSxLQUFLLEdBQUcsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLEdBQUcsVUFBVSxDQUFDLENBQUM7UUFDeEQsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUM7YUFDMUIsT0FBTyxDQUNOLFlBQVksRUFDWixLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQ3hCO2FBQ0EsTUFBTSxFQUFFLENBQUM7S0FDYjtJQUVELElBQUksaUJBQWlCLEdBQUcsQ0FBQyxDQUFDO0lBRTFCLEtBQUssTUFBTSxNQUFNLElBQUksQ0FBQyxHQUFHLGdCQUFnQixFQUFFLEdBQUcsZ0JBQWdCLENBQUMsRUFBRTtRQUMvRCxJQUFJO1lBQ0YsaUJBQWlCLElBQUksTUFBTSxrQkFBa0IsQ0FDM0MsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxFQUM3RCxpQkFBaUIsRUFDakIsQ0FBQyxZQUFZLEVBQUUsa0JBQWtCLENBQUMsRUFDbEMsSUFBSSxDQUNMLENBQUM7U0FDSDtRQUFDLE9BQU8sS0FBSyxFQUFFO1lBQ2QsT0FBTyxDQUFDLEdBQUcsQ0FDVCx1Q0FBdUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxjQUFjLGtCQUFrQixNQUFNLENBQUMsR0FBRyx5QkFBeUIsQ0FDL0gsQ0FBQztTQUNIO0tBQ0Y7SUFFRCxPQUFPLGVBQWUsR0FBRyxpQkFBaUIsQ0FBQztBQUM3QyxDQUFDLENBQUM7QUFFRixNQUFNLENBQUMsTUFBTSxVQUFVLEdBQUcsQ0FDeEIsSUFBWSxFQUNaLE9BQWlCLEVBQ2pCLFdBQW9CLEVBQzJCLEVBQUU7SUFDakQsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtRQUN4QixPQUFPO1lBQ0wsTUFBTSxFQUFFLElBQUk7WUFDWixNQUFNLEVBQUUsQ0FBQyxjQUFjLENBQUMsdUNBQXVDLEVBQUUsSUFBSSxDQUFDLENBQUM7U0FDeEUsQ0FBQztLQUNIO0lBRUQsTUFBTSxNQUFNLEdBQWUsRUFBRSxDQUFDO0lBRTlCLE1BQU0sV0FBVyxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssSUFBSSxDQUFDLENBQUM7SUFDbkUsSUFBSSxXQUFXLEVBQUU7UUFDZixPQUFPLEVBQUUsTUFBTSxFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQztLQUN4QztJQUVELE1BQU0sU0FBUyxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN2RCxNQUFNLFNBQVMsR0FBRyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsU0FBUyxFQUFFLFdBQVcsQ0FBQyxDQUFDO0lBQ2xFLElBQUksU0FBUyxLQUFLLElBQUksRUFBRTtRQUN0QixNQUFNLENBQUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxtQkFBbUIsSUFBSSxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQztRQUMxRSxPQUFPLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsQ0FBQztLQUNqQztJQUNELE1BQU0sYUFBYSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsRUFBRSxDQUFDLFNBQVMsS0FBSyxNQUFNLENBQUMsSUFBSSxDQUFDLENBQUM7SUFFMUUsTUFBTSxDQUFDLElBQUksQ0FDVCxjQUFjLENBQ1osbUJBQW1CLElBQUksK0JBQStCLFNBQVMsSUFBSSxFQUNuRSxJQUFJLENBQ0wsQ0FDRixDQUFDO0lBRUYsT0FBTyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsTUFBTSxFQUFFLENBQUM7QUFDM0MsQ0FBQyxDQUFDO0FBRUYsTUFBTSxtQkFBbUIsR0FBRyxDQUFDLE9BQWlCLEVBQVksRUFBRTtJQUMxRCxNQUFNLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBRSxDQUFDO0lBQ3pCLE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLE1BQU0sRUFBRSxFQUFFO1FBQy9CLE1BQU0sU0FBUyxHQUFHLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3pDLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZCLE9BQU8sQ0FBQyxTQUFTLENBQUM7SUFDcEIsQ0FBQyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyB3aG9sZUxpbmVFcnJvciB9IGZyb20gXCIuLi9zdHJlZXQtbWFya2Rvd24vc21kXCI7XHJcbmltcG9ydCB7IFNtZEVycm9yIH0gZnJvbSBcIi4uL3N0cmVldC1tYXJrZG93bi90eXBlc1wiO1xyXG5pbXBvcnQgeyBmaW5kQ2xvc2VzdFN0cmluZyB9IGZyb20gXCIuLi91dGlscy9oZWxwZXJzXCI7XHJcbmltcG9ydCB7IGdldEtuZXhEYiwgaW5zZXJ0TXVsdGlwbGVSb3dzIH0gZnJvbSBcIi4vZGJcIjtcclxuaW1wb3J0IHsgU2Nob29sIH0gZnJvbSBcIi4vdHlwZXNcIjtcclxuXHJcbmNvbnN0IEJBVENIX1NJWkUgPSA1MDA7XHJcblxyXG5leHBvcnQgY29uc3QgaW5zZXJ0U2Nob29scyA9IGFzeW5jIChzY2hvb2xzOiBTY2hvb2xbXSk6IFByb21pc2U8bnVtYmVyPiA9PiB7XHJcbiAgY29uc3Qga25leCA9IGdldEtuZXhEYigpO1xyXG5cclxuICBjb25zdCB1bmlxdWVTY2hvb2xzID0gZmlsdGVyT3V0RHVwbGljYXRlcyhzY2hvb2xzKTtcclxuXHJcbiAgLy8gRmV0Y2ggYWxsIGV4aXN0aW5nIHNjaG9vbHMgd2l0aCB0aGVpciBjdXJyZW50IGxvY2F0aW9uIGluIG9uZSBxdWVyeVxyXG4gIGNvbnN0IGV4aXN0aW5nOiB7IGl6bzogc3RyaW5nOyBuYW1lOiBzdHJpbmc7IGNhcGFjaXR5OiBudW1iZXI7IGFkZHJlc3NfcG9pbnRfaWQ6IG51bWJlciB8IG51bGwgfVtdID1cclxuICAgIGF3YWl0IGtuZXgoXCJzY2hvb2xcIilcclxuICAgICAgLmxlZnRKb2luKFwic2Nob29sX2xvY2F0aW9uXCIsIFwic2Nob29sLml6b1wiLCBcInNjaG9vbF9sb2NhdGlvbi5zY2hvb2xfaXpvXCIpXHJcbiAgICAgIC5zZWxlY3QoXCJzY2hvb2wuaXpvXCIsIFwic2Nob29sLm5hbWVcIiwgXCJzY2hvb2wuY2FwYWNpdHlcIiwgXCJzY2hvb2xfbG9jYXRpb24uYWRkcmVzc19wb2ludF9pZFwiKTtcclxuXHJcbiAgY29uc3QgZXhpc3RpbmdNYXAgPSBuZXcgTWFwKGV4aXN0aW5nLm1hcCgocikgPT4gW3IuaXpvLCByXSkpO1xyXG5cclxuICBjb25zdCB0b0luc2VydCA9IHVuaXF1ZVNjaG9vbHMuZmlsdGVyKChzKSA9PiAhZXhpc3RpbmdNYXAuaGFzKHMuaXpvKSk7XHJcbiAgY29uc3QgdG9VcGRhdGUgPSB1bmlxdWVTY2hvb2xzLmZpbHRlcigocykgPT4gZXhpc3RpbmdNYXAuaGFzKHMuaXpvKSk7XHJcblxyXG4gIC8vIC0tLSBJbnNlcnQgbmV3IHNjaG9vbHMgLS0tXHJcbiAgY29uc3QgaW5zZXJ0ZWRTY2hvb2xzID0gYXdhaXQgaW5zZXJ0TXVsdGlwbGVSb3dzKFxyXG4gICAgdG9JbnNlcnQubWFwKChzY2hvb2wpID0+IFtcclxuICAgICAgc2Nob29sLml6byxcclxuICAgICAgc2Nob29sLnJlZGl6byxcclxuICAgICAgc2Nob29sLm5hbWUsXHJcbiAgICAgIHNjaG9vbC5jYXBhY2l0eS50b1N0cmluZygpLFxyXG4gICAgICBzY2hvb2wudHlwZS50b1N0cmluZygpLFxyXG4gICAgXSksXHJcbiAgICBcInNjaG9vbFwiLFxyXG4gICAgW1wiaXpvXCIsIFwicmVkaXpvXCIsIFwibmFtZVwiLCBcImNhcGFjaXR5XCIsIFwidHlwZVwiXVxyXG4gICk7XHJcblxyXG4gIC8vIC0tLSBVcGRhdGUgZXhpc3Rpbmcgc2Nob29scyAobmFtZSArIGNhcGFjaXR5KSBpbiBiYXRjaGVzIC0tLVxyXG4gIGNvbnN0IHRvVXBkYXRlRmllbGRzID0gdG9VcGRhdGUuZmlsdGVyKChzKSA9PiB7XHJcbiAgICBjb25zdCByb3cgPSBleGlzdGluZ01hcC5nZXQocy5pem8pO1xyXG4gICAgcmV0dXJuIHJvdy5uYW1lICE9PSBzLm5hbWUgfHwgTnVtYmVyKHJvdy5jYXBhY2l0eSkgIT09IHMuY2FwYWNpdHk7XHJcbiAgfSk7XHJcblxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdG9VcGRhdGVGaWVsZHMubGVuZ3RoOyBpICs9IEJBVENIX1NJWkUpIHtcclxuICAgIGNvbnN0IGJhdGNoID0gdG9VcGRhdGVGaWVsZHMuc2xpY2UoaSwgaSArIEJBVENIX1NJWkUpO1xyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoXHJcbiAgICAgIGJhdGNoLm1hcCgocykgPT5cclxuICAgICAgICBrbmV4KFwic2Nob29sXCIpLndoZXJlKFwiaXpvXCIsIHMuaXpvKS51cGRhdGUoeyBuYW1lOiBzLm5hbWUsIGNhcGFjaXR5OiBzLmNhcGFjaXR5IH0pXHJcbiAgICAgIClcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyAtLS0gSGFuZGxlIGxvY2F0aW9ucyAtLS1cclxuICAvLyBOZXcgc2Nob29scyBhbmQgZXhpc3Rpbmcgc2Nob29scyB3aXRob3V0IGFueSBsb2NhdGlvbiBuZWVkIGFuIGluc2VydFxyXG4gIGNvbnN0IHRvSW5zZXJ0TG9jYXRpb24gPSBbXHJcbiAgICAuLi50b0luc2VydCxcclxuICAgIC4uLnRvVXBkYXRlLmZpbHRlcigocykgPT4gZXhpc3RpbmdNYXAuZ2V0KHMuaXpvKS5hZGRyZXNzX3BvaW50X2lkID09PSBudWxsKSxcclxuICBdLmZpbHRlcigocykgPT4gcy5sb2NhdGlvbnMubGVuZ3RoID4gMCk7XHJcblxyXG4gIC8vIEV4aXN0aW5nIHNjaG9vbHMgd2hvc2UgZmlyc3QgbG9jYXRpb24gY2hhbmdlZCBuZWVkIGEgZGVsZXRlICsgaW5zZXJ0XHJcbiAgLy8gR3VhcmQgYWdhaW5zdCByZW9yZGVyaW5nOiBvbmx5IHVwZGF0ZSBpZiB0aGUgb2xkIFJVSUFOIGlzIGdvbmUgZW50aXJlbHkgZnJvbSB0aGUgbmV3IGxvY2F0aW9uc1xyXG4gIGNvbnN0IHRvVXBkYXRlTG9jYXRpb24gPSB0b1VwZGF0ZS5maWx0ZXIoKHMpID0+IHtcclxuICAgIGNvbnN0IHJvdyA9IGV4aXN0aW5nTWFwLmdldChzLml6byk7XHJcbiAgICBjb25zdCBuZXdSdWlhbnMgPSBzLmxvY2F0aW9ucy5tYXAoKGwpID0+IGwuYWRkcmVzc1BvaW50SWQpO1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgcm93LmFkZHJlc3NfcG9pbnRfaWQgIT09IG51bGwgJiZcclxuICAgICAgbmV3UnVpYW5zLmxlbmd0aCA+IDAgJiZcclxuICAgICAgIW5ld1J1aWFucy5pbmNsdWRlcyhyb3cuYWRkcmVzc19wb2ludF9pZClcclxuICAgICk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIERlbGV0ZSBvdXRkYXRlZCBsb2NhdGlvbnMgaW4gYmF0Y2hlc1xyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgdG9VcGRhdGVMb2NhdGlvbi5sZW5ndGg7IGkgKz0gQkFUQ0hfU0laRSkge1xyXG4gICAgY29uc3QgYmF0Y2ggPSB0b1VwZGF0ZUxvY2F0aW9uLnNsaWNlKGksIGkgKyBCQVRDSF9TSVpFKTtcclxuICAgIGF3YWl0IGtuZXgoXCJzY2hvb2xfbG9jYXRpb25cIilcclxuICAgICAgLndoZXJlSW4oXHJcbiAgICAgICAgXCJzY2hvb2xfaXpvXCIsXHJcbiAgICAgICAgYmF0Y2gubWFwKChzKSA9PiBzLml6bylcclxuICAgICAgKVxyXG4gICAgICAuZGVsZXRlKCk7XHJcbiAgfVxyXG5cclxuICBsZXQgaW5zZXJ0ZWRMb2NhdGlvbnMgPSAwO1xyXG5cclxuICBmb3IgKGNvbnN0IHNjaG9vbCBvZiBbLi4udG9JbnNlcnRMb2NhdGlvbiwgLi4udG9VcGRhdGVMb2NhdGlvbl0pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGluc2VydGVkTG9jYXRpb25zICs9IGF3YWl0IGluc2VydE11bHRpcGxlUm93cyhcclxuICAgICAgICBbW3NjaG9vbC5pem8sIHNjaG9vbC5sb2NhdGlvbnNbMF0uYWRkcmVzc1BvaW50SWQudG9TdHJpbmcoKV1dLFxyXG4gICAgICAgIFwic2Nob29sX2xvY2F0aW9uXCIsXHJcbiAgICAgICAgW1wic2Nob29sX2l6b1wiLCBcImFkZHJlc3NfcG9pbnRfaWRcIl0sXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgYENhbm5vdCBhZGQgbG9jYXRpb24gd2l0aCBSVUlBTiBjb2RlICR7c2Nob29sLmxvY2F0aW9uc1swXS5hZGRyZXNzUG9pbnRJZH0gKHNjaG9vbCBJWk8gPSAke3NjaG9vbC5pem99KTogY29kZSBkb2VzIG5vdCBleGlzdC5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gaW5zZXJ0ZWRTY2hvb2xzICsgaW5zZXJ0ZWRMb2NhdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZmluZFNjaG9vbCA9IChcclxuICBuYW1lOiBzdHJpbmcsXHJcbiAgc2Nob29sczogU2Nob29sW10sXHJcbiAgbWF4RGlzdGFuY2U/OiBudW1iZXJcclxuKTogeyBzY2hvb2w6IFNjaG9vbCB8IG51bGw7IGVycm9yczogU21kRXJyb3JbXSB9ID0+IHtcclxuICBpZiAoc2Nob29scy5sZW5ndGggPT09IDApIHtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHNjaG9vbDogbnVsbCxcclxuICAgICAgZXJyb3JzOiBbd2hvbGVMaW5lRXJyb3IoXCJBa3R1w6FsbsOtIHrFmWl6b3ZhdGVsIG5lbcOhIMW+w6FkbsOpIMWha29seS5cIiwgbmFtZSldLFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIGNvbnN0IGVycm9yczogU21kRXJyb3JbXSA9IFtdO1xyXG5cclxuICBjb25zdCBleGFjdFNjaG9vbCA9IHNjaG9vbHMuZmluZCgoc2Nob29sKSA9PiBzY2hvb2wubmFtZSA9PT0gbmFtZSk7XHJcbiAgaWYgKGV4YWN0U2Nob29sKSB7XHJcbiAgICByZXR1cm4geyBzY2hvb2w6IGV4YWN0U2Nob29sLCBlcnJvcnMgfTtcclxuICB9XHJcblxyXG4gIGNvbnN0IG5hbWVzTGlzdCA9IHNjaG9vbHMubWFwKChzY2hvb2wpID0+IHNjaG9vbC5uYW1lKTtcclxuICBjb25zdCBiZXN0TWF0Y2ggPSBmaW5kQ2xvc2VzdFN0cmluZyhuYW1lLCBuYW1lc0xpc3QsIG1heERpc3RhbmNlKTtcclxuICBpZiAoYmVzdE1hdGNoID09PSBudWxsKSB7XHJcbiAgICBlcnJvcnMucHVzaCh3aG9sZUxpbmVFcnJvcihgxaBrb2xhIHMgbsOhenZlbSAnJHtuYW1lfScgbmVleGlzdHVqZS5gLCBuYW1lKSk7XHJcbiAgICByZXR1cm4geyBzY2hvb2w6IG51bGwsIGVycm9ycyB9O1xyXG4gIH1cclxuICBjb25zdCBjbG9zZXN0U2Nob29sID0gc2Nob29scy5maW5kKChzY2hvb2wpID0+IGJlc3RNYXRjaCA9PT0gc2Nob29sLm5hbWUpO1xyXG5cclxuICBlcnJvcnMucHVzaChcclxuICAgIHdob2xlTGluZUVycm9yKFxyXG4gICAgICBgxaBrb2xhIHMgbsOhenZlbSAnJHtuYW1lfScgbmVleGlzdHVqZSwgbXlzbGVsaSBqc3RlICcke2Jlc3RNYXRjaH0nP2AsXHJcbiAgICAgIG5hbWVcclxuICAgIClcclxuICApO1xyXG5cclxuICByZXR1cm4geyBzY2hvb2w6IGNsb3Nlc3RTY2hvb2wsIGVycm9ycyB9O1xyXG59O1xyXG5cclxuY29uc3QgZmlsdGVyT3V0RHVwbGljYXRlcyA9IChzY2hvb2xzOiBTY2hvb2xbXSk6IFNjaG9vbFtdID0+IHtcclxuICBjb25zdCBpem9TZXQgPSBuZXcgU2V0KCk7XHJcbiAgcmV0dXJuIHNjaG9vbHMuZmlsdGVyKChzY2hvb2wpID0+IHtcclxuICAgIGNvbnN0IGR1cGxpY2F0ZSA9IGl6b1NldC5oYXMoc2Nob29sLml6byk7XHJcbiAgICBpem9TZXQuYWRkKHNjaG9vbC5pem8pO1xyXG4gICAgcmV0dXJuICFkdXBsaWNhdGU7XHJcbiAgfSk7XHJcbn07XHJcbiJdfQ==