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
132 lines • 23 kB
JavaScript
import AdmZip from "adm-zip";
import { createWriteStream, existsSync, mkdirSync, rmSync } from "fs";
import fetch from "node-fetch";
import parseDBF from "parsedbf";
import { join } from "path";
import ShpToGeoJson from "shp-to-geojson";
import { pipeline } from "stream/promises";
import { coordEach } from "@turf/meta";
import { setCityPolygonGeojson } from "../db/cities";
import { clearStreetSyncTable, deleteStreets, getAllSyncedStreets, insertStreetsFromDbf, setStreetAsSynced, } from "../db/street-sync";
import { SyncPart } from "../db/types";
import { getAllUrlsFromAtomFeed, getLatestUrlFromAtomFeed, } from "../utils/atom";
import { prepareOptions, } from "../utils/helpers";
import jtsk2wgs84 from "../utils/jtsk2wgs84";
import { runSyncPart } from "./common";
const prepareFolders = (options) => {
const tempFolder = getTempFolder(options);
if (!existsSync(tempFolder)) {
mkdirSync(tempFolder);
}
};
const getTempFolder = (options) => {
return join(options.tmpDir, options.streetZipFolderName);
};
const downloadZipAndParseFiles = async (url, index, options) => {
const response = await fetch(url);
if (response.status !== 200) {
throw new Error(`The ZIP file from '${url}' could not be downloaded. HTTP Code: ${response.status}`);
}
const zipFilePath = join(getTempFolder(options), `street${index}.zip`);
await pipeline(response.body, createWriteStream(zipFilePath));
const zip = new AdmZip(zipFilePath);
const folderName = zip.getEntries()[0].entryName;
const cityCode = folderName.substring(0, 6);
const dbfEntryName = `${folderName}${options.streetDbfFileName}`;
const streetData = parseDBF(zip.getEntry(dbfEntryName).getData(), "win1250");
const shpEntryName = `${folderName}${options.polygonShpFileName}`;
const polygonData = convertShpToGeoJson(zip.getEntry(shpEntryName).getData());
const districtShpEntryName = `${folderName}${options.districtPolygonShpFileName}`;
const districtShpEntry = zip.getEntry(districtShpEntryName);
let districtsPolygonData = undefined;
if (districtShpEntry !== null) {
const districtDbfEntryName = `${folderName}${options.districtPolygonDbfFileName}`;
districtsPolygonData = convertShpToGeoJson(districtShpEntry.getData(), zip.getEntry(districtDbfEntryName).getData());
}
rmSync(zipFilePath);
return { streetData, polygonData, districtsPolygonData, cityCode };
};
const convertShpToGeoJson = (shpBuffer, dbfBuffer) => {
const shp = new ShpToGeoJson({
arraybuffers: {
shpBuffer,
...(dbfBuffer ? { dbfBuffer } : {}),
},
});
const geoJson = shp.getGeoJson();
delete geoJson.bbox;
coordEach(geoJson, (currentCoord) => {
const [y, x] = currentCoord;
const { lat, lon } = jtsk2wgs84(-x, -y);
currentCoord[0] = lon;
currentCoord[1] = lat;
});
return geoJson;
};
const importDataToDb = async ({ streetData, cityCode, polygonData, districtsPolygonData, }) => {
if (streetData.length > 0) {
await insertStreetsFromDbf(streetData);
}
await setCityPolygonGeojson(cityCode, polygonData, districtsPolygonData);
};
const attempts = 5;
export const downloadAndImportStreets = async (options = {}, noCache = false) => {
await runSyncPart(SyncPart.Streets, [SyncPart.AddressPoints], async () => {
console.log("Starting to download and import streets. This takes up to 1 hour.");
const completeOptions = prepareOptions(options);
prepareFolders(completeOptions);
// Clear street sync table if no-cache flag is set
if (noCache) {
console.log("Clearing street sync cache...");
await clearStreetSyncTable();
}
const allDatasetFeedLinks = await getAllUrlsFromAtomFeed(completeOptions.streetsAtomUrl);
console.log(`Total of ${allDatasetFeedLinks.length} links to ZIP files.`);
const syncedStreetLinks = await getAllSyncedStreets();
const toDelete = [];
// remove all deprecated links (not in the new list)
syncedStreetLinks.forEach((link) => {
if (!allDatasetFeedLinks.includes(link)) {
toDelete.push(link);
delete syncedStreetLinks[link];
}
});
await deleteStreets(toDelete);
let done = syncedStreetLinks.size;
console.log(`Total of ${done} links to ZIP files already stored.`);
// get all links not yet stored
const newLinks = allDatasetFeedLinks.filter((link) => !syncedStreetLinks.has(link));
let delay = 0;
console.log(`Loading ${newLinks.length} new links to ZIP files.`);
for (const link of newLinks) {
for (let i = 0; i < attempts; i++) {
try {
const zipLink = await getLatestUrlFromAtomFeed(link);
const data = await downloadZipAndParseFiles(zipLink, done, completeOptions);
await importDataToDb(data);
await setStreetAsSynced(link);
done++;
console.log(`Loaded links: ${done}/${allDatasetFeedLinks.length}`);
await wait(delay);
break;
}
catch (error) {
if (i < attempts - 1) {
delay += 100; // if error occured, it is likely to repeat so we wait a bit longer
const waitTime = (i + 1) * 3;
console.error(`Error connecting to CUZK servers, retrying in ${waitTime} seconds...`);
console.log(error);
await wait(waitTime * 1000);
}
else {
throw error;
}
}
}
}
});
};
const wait = async (ms) => {
await new Promise((resolve) => setTimeout(resolve, ms));
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3RyZWV0cy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcGVuLWRhdGEtc3luYy9zdHJlZXRzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sTUFBTSxNQUFNLFNBQVMsQ0FBQztBQUU3QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsVUFBVSxFQUFFLFNBQVMsRUFBRSxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDdEUsT0FBTyxLQUFLLE1BQU0sWUFBWSxDQUFDO0FBQy9CLE9BQU8sUUFBUSxNQUFNLFVBQVUsQ0FBQztBQUNoQyxPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVCLE9BQU8sWUFBWSxNQUFNLGdCQUFnQixDQUFDO0FBQzFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUczQyxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0sWUFBWSxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxxQkFBcUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUNyRCxPQUFPLEVBQ0wsb0JBQW9CLEVBQ3BCLGFBQWEsRUFDYixtQkFBbUIsRUFDbkIsb0JBQW9CLEVBQ3BCLGlCQUFpQixHQUNsQixNQUFNLG1CQUFtQixDQUFDO0FBQzNCLE9BQU8sRUFBYSxRQUFRLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDbEQsT0FBTyxFQUNMLHNCQUFzQixFQUN0Qix3QkFBd0IsR0FDekIsTUFBTSxlQUFlLENBQUM7QUFDdkIsT0FBTyxFQUdMLGNBQWMsR0FDZixNQUFNLGtCQUFrQixDQUFDO0FBQzFCLE9BQU8sVUFBVSxNQUFNLHFCQUFxQixDQUFDO0FBQzdDLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxVQUFVLENBQUM7QUFFdkMsTUFBTSxjQUFjLEdBQUcsQ0FBQyxPQUE0QixFQUFFLEVBQUU7SUFDdEQsTUFBTSxVQUFVLEdBQUcsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQzFDLElBQUksQ0FB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QyxDQUFDLENBQUM7QUFDTCxDQUFDLENBQUM7QUFFRixNQUFNLElBQUksR0FBRyxLQUFLLEVBQUUsRUFBVSxFQUFpQixFQUFFO0lBQy9DLE1BQU0sSUFBSSxPQUFPLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztBQUMxRCxDQUFDLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQWRtWmlwIGZyb20gXCJhZG0temlwXCI7XHJcbmltcG9ydCB7IEJ1ZmZlciB9IGZyb20gXCJidWZmZXJcIjtcclxuaW1wb3J0IHsgY3JlYXRlV3JpdGVTdHJlYW0sIGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcm1TeW5jIH0gZnJvbSBcImZzXCI7XHJcbmltcG9ydCBmZXRjaCBmcm9tIFwibm9kZS1mZXRjaFwiO1xyXG5pbXBvcnQgcGFyc2VEQkYgZnJvbSBcInBhcnNlZGJmXCI7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xyXG5pbXBvcnQgU2hwVG9HZW9Kc29uIGZyb20gXCJzaHAtdG8tZ2VvanNvblwiO1xyXG5pbXBvcnQgeyBwaXBlbGluZSB9IGZyb20gXCJzdHJlYW0vcHJvbWlzZXNcIjtcclxuXHJcbmltcG9ydCB7IEZlYXR1cmVDb2xsZWN0aW9uIH0gZnJvbSBcIkB0dXJmL2hlbHBlcnNcIjtcclxuaW1wb3J0IHsgY29vcmRFYWNoIH0gZnJvbSBcIkB0dXJmL21ldGFcIjtcclxuaW1wb3J0IHsgc2V0Q2l0eVBvbHlnb25HZW9qc29uIH0gZnJvbSBcIi4uL2RiL2NpdGllc1wiO1xyXG5pbXBvcnQge1xyXG4gIGNsZWFyU3RyZWV0U3luY1RhYmxlLFxyXG4gIGRlbGV0ZVN0cmVldHMsXHJcbiAgZ2V0QWxsU3luY2VkU3RyZWV0cyxcclxuICBpbnNlcnRTdHJlZXRzRnJvbURiZixcclxuICBzZXRTdHJlZXRBc1N5bmNlZCxcclxufSBmcm9tIFwiLi4vZGIvc3RyZWV0LXN5bmNcIjtcclxuaW1wb3J0IHsgRGJmU3RyZWV0LCBTeW5jUGFydCB9IGZyb20gXCIuLi9kYi90eXBlc1wiO1xyXG5pbXBvcnQge1xyXG4gIGdldEFsbFVybHNGcm9tQXRvbUZlZWQsXHJcbiAgZ2V0TGF0ZXN0VXJsRnJvbUF0b21GZWVkLFxyXG59IGZyb20gXCIuLi91dGlscy9hdG9tXCI7XHJcbmltcG9ydCB7XHJcbiAgT3BlbkRhdGFTeW5jT3B0aW9ucyxcclxuICBPcGVuRGF0YVN5bmNPcHRpb25zUGFydGlhbCxcclxuICBwcmVwYXJlT3B0aW9ucyxcclxufSBmcm9tIFwiLi4vdXRpbHMvaGVscGVyc1wiO1xyXG5pbXBvcnQganRzazJ3Z3M4NCBmcm9tIFwiLi4vdXRpbHMvanRzazJ3Z3M4NFwiO1xyXG5pbXBvcnQgeyBydW5TeW5jUGFydCB9IGZyb20gXCIuL2NvbW1vblwiO1xyXG5cclxuY29uc3QgcHJlcGFyZUZvbGRlcnMgPSAob3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHRlbXBGb2xkZXIgPSBnZXRUZW1wRm9sZGVyKG9wdGlvbnMpO1xyXG4gIGlmICghZXhpc3RzU3luYyh0ZW1wRm9sZGVyKSkge1xyXG4gICAgbWtkaXJTeW5jKHRlbXBGb2xkZXIpO1xyXG4gIH1cclxufTtcclxuXHJcbmNvbnN0IGdldFRlbXBGb2xkZXIgPSAob3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9ucykgPT4ge1xyXG4gIHJldHVybiBqb2luKG9wdGlvbnMudG1wRGlyLCBvcHRpb25zLnN0cmVldFppcEZvbGRlck5hbWUpO1xyXG59O1xyXG5cclxuY29uc3QgZG93bmxvYWRaaXBBbmRQYXJzZUZpbGVzID0gYXN5bmMgKFxyXG4gIHVybDogc3RyaW5nLFxyXG4gIGluZGV4OiBudW1iZXIsXHJcbiAgb3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1xyXG4pOiBQcm9taXNlPHtcclxuICBzdHJlZXREYXRhOiBEYmZTdHJlZXRbXTtcclxuICBwb2x5Z29uRGF0YTogRmVhdHVyZUNvbGxlY3Rpb247XHJcbiAgZGlzdHJpY3RzUG9seWdvbkRhdGE/OiBGZWF0dXJlQ29sbGVjdGlvbjtcclxuICBjaXR5Q29kZTogc3RyaW5nO1xyXG59PiA9PiB7XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaCh1cmwpO1xyXG4gIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFxyXG4gICAgICBgVGhlIFpJUCBmaWxlIGZyb20gJyR7dXJsfScgY291bGQgbm90IGJlIGRvd25sb2FkZWQuIEhUVFAgQ29kZTogJHtyZXNwb25zZS5zdGF0dXN9YFxyXG4gICAgKTtcclxuICB9XHJcbiAgY29uc3QgemlwRmlsZVBhdGggPSBqb2luKGdldFRlbXBGb2xkZXIob3B0aW9ucyksIGBzdHJlZXQke2luZGV4fS56aXBgKTtcclxuICBhd2FpdCBwaXBlbGluZShyZXNwb25zZS5ib2R5LCBjcmVhdGVXcml0ZVN0cmVhbSh6aXBGaWxlUGF0aCkpO1xyXG5cclxuICBjb25zdCB6aXAgPSBuZXcgQWRtWmlwKHppcEZpbGVQYXRoKTtcclxuICBjb25zdCBmb2xkZXJOYW1lID0gemlwLmdldEVudHJpZXMoKVswXS5lbnRyeU5hbWU7XHJcbiAgY29uc3QgY2l0eUNvZGUgPSBmb2xkZXJOYW1lLnN1YnN0cmluZygwLCA2KTtcclxuICBjb25zdCBkYmZFbnRyeU5hbWUgPSBgJHtmb2xkZXJOYW1lfSR7b3B0aW9ucy5zdHJlZXREYmZGaWxlTmFtZX1gO1xyXG4gIGNvbnN0IHN0cmVldERhdGEgPSBwYXJzZURCRjxEYmZTdHJlZXQ+KFxyXG4gICAgemlwLmdldEVudHJ5KGRiZkVudHJ5TmFtZSkuZ2V0RGF0YSgpLFxyXG4gICAgXCJ3aW4xMjUwXCJcclxuICApO1xyXG5cclxuICBjb25zdCBzaHBFbnRyeU5hbWUgPSBgJHtmb2xkZXJOYW1lfSR7b3B0aW9ucy5wb2x5Z29uU2hwRmlsZU5hbWV9YDtcclxuICBjb25zdCBwb2x5Z29uRGF0YSA9IGNvbnZlcnRTaHBUb0dlb0pzb24oemlwLmdldEVudHJ5KHNocEVudHJ5TmFtZSkuZ2V0RGF0YSgpKTtcclxuXHJcbiAgY29uc3QgZGlzdHJpY3RTaHBFbnRyeU5hbWUgPSBgJHtmb2xkZXJOYW1lfSR7b3B0aW9ucy5kaXN0cmljdFBvbHlnb25TaHBGaWxlTmFtZX1gO1xyXG4gIGNvbnN0IGRpc3RyaWN0U2hwRW50cnkgPSB6aXAuZ2V0RW50cnkoZGlzdHJpY3RTaHBFbnRyeU5hbWUpO1xyXG5cclxuICBsZXQgZGlzdHJpY3RzUG9seWdvbkRhdGE6IEZlYXR1cmVDb2xsZWN0aW9uID0gdW5kZWZpbmVkO1xyXG4gIGlmIChkaXN0cmljdFNocEVudHJ5ICE9PSBudWxsKSB7XHJcbiAgICBjb25zdCBkaXN0cmljdERiZkVudHJ5TmFtZSA9IGAke2ZvbGRlck5hbWV9JHtvcHRpb25zLmRpc3RyaWN0UG9seWdvbkRiZkZpbGVOYW1lfWA7XHJcbiAgICBkaXN0cmljdHNQb2x5Z29uRGF0YSA9IGNvbnZlcnRTaHBUb0dlb0pzb24oXHJcbiAgICAgIGRpc3RyaWN0U2hwRW50cnkuZ2V0RGF0YSgpLFxyXG4gICAgICB6aXAuZ2V0RW50cnkoZGlzdHJpY3REYmZFbnRyeU5hbWUpLmdldERhdGEoKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJtU3luYyh6aXBGaWxlUGF0aCk7XHJcbiAgcmV0dXJuIHsgc3RyZWV0RGF0YSwgcG9seWdvbkRhdGEsIGRpc3RyaWN0c1BvbHlnb25EYXRhLCBjaXR5Q29kZSB9O1xyXG59O1xyXG5cclxuY29uc3QgY29udmVydFNocFRvR2VvSnNvbiA9IChcclxuICBzaHBCdWZmZXI6IEJ1ZmZlcixcclxuICBkYmZCdWZmZXI/OiBCdWZmZXJcclxuKTogRmVhdHVyZUNvbGxlY3Rpb24gPT4ge1xyXG4gIGNvbnN0IHNocCA9IG5ldyBTaHBUb0dlb0pzb24oe1xyXG4gICAgYXJyYXlidWZmZXJzOiB7XHJcbiAgICAgIHNocEJ1ZmZlcixcclxuICAgICAgLi4uKGRiZkJ1ZmZlciA/IHsgZGJmQnVmZmVyIH0gOiB7fSksXHJcbiAgICB9LFxyXG4gIH0pO1xyXG4gIGNvbnN0IGdlb0pzb24gPSBzaHAuZ2V0R2VvSnNvbigpO1xyXG4gIGRlbGV0ZSBnZW9Kc29uLmJib3g7XHJcblxyXG4gIGNvb3JkRWFjaChnZW9Kc29uIGFzIGFueSwgKGN1cnJlbnRDb29yZCkgPT4ge1xyXG4gICAgY29uc3QgW3ksIHhdID0gY3VycmVudENvb3JkO1xyXG4gICAgY29uc3QgeyBsYXQsIGxvbiB9ID0ganRzazJ3Z3M4NCgteCwgLXkpO1xyXG4gICAgY3VycmVudENvb3JkWzBdID0gbG9uO1xyXG4gICAgY3VycmVudENvb3JkWzFdID0gbGF0O1xyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gZ2VvSnNvbiBhcyBGZWF0dXJlQ29sbGVjdGlvbjtcclxufTtcclxuXHJcbmNvbnN0IGltcG9ydERhdGFUb0RiID0gYXN5bmMgKHtcclxuICBzdHJlZXREYXRhLFxyXG4gIGNpdHlDb2RlLFxyXG4gIHBvbHlnb25EYXRhLFxyXG4gIGRpc3RyaWN0c1BvbHlnb25EYXRhLFxyXG59OiB7XHJcbiAgc3RyZWV0RGF0YTogRGJmU3RyZWV0W107XHJcbiAgY2l0eUNvZGU6IHN0cmluZztcclxuICBwb2x5Z29uRGF0YTogRmVhdHVyZUNvbGxlY3Rpb247XHJcbiAgZGlzdHJpY3RzUG9seWdvbkRhdGE/OiBGZWF0dXJlQ29sbGVjdGlvbjtcclxufSkgPT4ge1xyXG4gIGlmIChzdHJlZXREYXRhLmxlbmd0aCA+IDApIHtcclxuICAgIGF3YWl0IGluc2VydFN0cmVldHNGcm9tRGJmKHN0cmVldERhdGEpO1xyXG4gIH1cclxuICBhd2FpdCBzZXRDaXR5UG9seWdvbkdlb2pzb24oY2l0eUNvZGUsIHBvbHlnb25EYXRhLCBkaXN0cmljdHNQb2x5Z29uRGF0YSk7XHJcbn07XHJcblxyXG5jb25zdCBhdHRlbXB0cyA9IDU7XHJcblxyXG5leHBvcnQgY29uc3QgZG93bmxvYWRBbmRJbXBvcnRTdHJlZXRzID0gYXN5bmMgKFxyXG4gIG9wdGlvbnM6IE9wZW5EYXRhU3luY09wdGlvbnNQYXJ0aWFsID0ge30sXHJcbiAgbm9DYWNoZTogYm9vbGVhbiA9IGZhbHNlXHJcbik6IFByb21pc2U8dm9pZD4gPT4ge1xyXG4gIGF3YWl0IHJ1blN5bmNQYXJ0KFN5bmNQYXJ0LlN0cmVldHMsIFtTeW5jUGFydC5BZGRyZXNzUG9pbnRzXSwgYXN5bmMgKCkgPT4ge1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIFwiU3RhcnRpbmcgdG8gZG93bmxvYWQgYW5kIGltcG9ydCBzdHJlZXRzLiBUaGlzIHRha2VzIHVwIHRvIDEgaG91ci5cIlxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCBjb21wbGV0ZU9wdGlvbnMgPSBwcmVwYXJlT3B0aW9ucyhvcHRpb25zKTtcclxuICAgIHByZXBhcmVGb2xkZXJzKGNvbXBsZXRlT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gQ2xlYXIgc3RyZWV0IHN5bmMgdGFibGUgaWYgbm8tY2FjaGUgZmxhZyBpcyBzZXRcclxuICAgIGlmIChub0NhY2hlKSB7XHJcbiAgICAgIGNvbnNvbGUubG9nKFwiQ2xlYXJpbmcgc3RyZWV0IHN5bmMgY2FjaGUuLi5cIik7XHJcbiAgICAgIGF3YWl0IGNsZWFyU3RyZWV0U3luY1RhYmxlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgY29uc3QgYWxsRGF0YXNldEZlZWRMaW5rcyA9IGF3YWl0IGdldEFsbFVybHNGcm9tQXRvbUZlZWQoXHJcbiAgICAgIGNvbXBsZXRlT3B0aW9ucy5zdHJlZXRzQXRvbVVybFxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zb2xlLmxvZyhgVG90YWwgb2YgJHthbGxEYXRhc2V0RmVlZExpbmtzLmxlbmd0aH0gbGlua3MgdG8gWklQIGZpbGVzLmApO1xyXG5cclxuICAgIGNvbnN0IHN5bmNlZFN0cmVldExpbmtzID0gYXdhaXQgZ2V0QWxsU3luY2VkU3RyZWV0cygpO1xyXG5cclxuICAgIGNvbnN0IHRvRGVsZXRlOiBzdHJpbmdbXSA9IFtdO1xyXG4gICAgLy8gcmVtb3ZlIGFsbCBkZXByZWNhdGVkIGxpbmtzIChub3QgaW4gdGhlIG5ldyBsaXN0KVxyXG4gICAgc3luY2VkU3RyZWV0TGlua3MuZm9yRWFjaCgobGluaykgPT4ge1xyXG4gICAgICBpZiAoIWFsbERhdGFzZXRGZWVkTGlua3MuaW5jbHVkZXMobGluaykpIHtcclxuICAgICAgICB0b0RlbGV0ZS5wdXNoKGxpbmspO1xyXG4gICAgICAgIGRlbGV0ZSBzeW5jZWRTdHJlZXRMaW5rc1tsaW5rXTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgYXdhaXQgZGVsZXRlU3RyZWV0cyh0b0RlbGV0ZSk7XHJcblxyXG4gICAgbGV0IGRvbmUgPSBzeW5jZWRTdHJlZXRMaW5rcy5zaXplO1xyXG4gICAgY29uc29sZS5sb2coYFRvdGFsIG9mICR7ZG9uZX0gbGlua3MgdG8gWklQIGZpbGVzIGFscmVhZHkgc3RvcmVkLmApO1xyXG5cclxuICAgIC8vIGdldCBhbGwgbGlua3Mgbm90IHlldCBzdG9yZWRcclxuICAgIGNvbnN0IG5ld0xpbmtzID0gYWxsRGF0YXNldEZlZWRMaW5rcy5maWx0ZXIoXHJcbiAgICAgIChsaW5rKSA9PiAhc3luY2VkU3RyZWV0TGlua3MuaGFzKGxpbmspXHJcbiAgICApO1xyXG5cclxuICAgIGxldCBkZWxheSA9IDA7XHJcbiAgICBjb25zb2xlLmxvZyhgTG9hZGluZyAke25ld0xpbmtzLmxlbmd0aH0gbmV3IGxpbmtzIHRvIFpJUCBmaWxlcy5gKTtcclxuICAgIGZvciAoY29uc3QgbGluayBvZiBuZXdMaW5rcykge1xyXG4gICAgICBmb3IgKGxldCBpID0gMDsgaSA8IGF0dGVtcHRzOyBpKyspIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgY29uc3QgemlwTGluayA9IGF3YWl0IGdldExhdGVzdFVybEZyb21BdG9tRmVlZChsaW5rKTtcclxuICAgICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCBkb3dubG9hZFppcEFuZFBhcnNlRmlsZXMoXHJcbiAgICAgICAgICAgIHppcExpbmssXHJcbiAgICAgICAgICAgIGRvbmUsXHJcbiAgICAgICAgICAgIGNvbXBsZXRlT3B0aW9uc1xyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIGF3YWl0IGltcG9ydERhdGFUb0RiKGRhdGEpO1xyXG4gICAgICAgICAgYXdhaXQgc2V0U3RyZWV0QXNTeW5jZWQobGluayk7XHJcblxyXG4gICAgICAgICAgZG9uZSsrO1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYExvYWRlZCBsaW5rczogJHtkb25lfS8ke2FsbERhdGFzZXRGZWVkTGlua3MubGVuZ3RofWApO1xyXG4gICAgICAgICAgYXdhaXQgd2FpdChkZWxheSk7XHJcbiAgICAgICAgICBicmVhaztcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgaWYgKGkgPCBhdHRlbXB0cyAtIDEpIHtcclxuICAgICAgICAgICAgZGVsYXkgKz0gMTAwOyAvLyBpZiBlcnJvciBvY2N1cmVkLCBpdCBpcyBsaWtlbHkgdG8gcmVwZWF0IHNvIHdlIHdhaXQgYSBiaXQgbG9uZ2VyXHJcbiAgICAgICAgICAgIGNvbnN0IHdhaXRUaW1lID0gKGkgKyAxKSAqIDM7XHJcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXHJcbiAgICAgICAgICAgICAgYEVycm9yIGNvbm5lY3RpbmcgdG8gQ1VaSyBzZXJ2ZXJzLCByZXRyeWluZyBpbiAke3dhaXRUaW1lfSBzZWNvbmRzLi4uYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XHJcbiAgICAgICAgICAgIGF3YWl0IHdhaXQod2FpdFRpbWUgKiAxMDAwKTtcclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59O1xyXG5cclxuY29uc3Qgd2FpdCA9IGFzeW5jIChtczogbnVtYmVyKTogUHJvbWlzZTx2b2lkPiA9PiB7XHJcbiAgYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHNldFRpbWVvdXQocmVzb2x2ZSwgbXMpKTtcclxufTtcclxuIl19