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
68 lines • 12.7 kB
JavaScript
import AdmZip from "adm-zip";
import { parse } from "csv-parse";
import { createReadStream, createWriteStream, readdirSync, rmSync } from "fs";
import iconv from "iconv-lite";
import fetch from "node-fetch";
import { join } from "path";
import { pipeline } from "stream/promises";
import chunk from "lodash/chunk";
import { commitAddressPoints, removeDeprecatedAddressPoints, } from "../db/address-points";
import { SyncPart } from "../db/types";
import { getLatestUrlFromAtomFeed } from "../utils/atom";
import { prepareOptions, } from "../utils/helpers";
import { runSyncPart } from "./common";
const maxBufferSize = 1000;
const downloadAndUnzip = async (url, options) => {
const zipFilePath = join(options.tmpDir, options.addressPointsZipFileName);
console.log("Downloading a large ZIP file with RUIAN data (~65 MB)...");
const response = await fetch(url);
if (response.status !== 200) {
throw new Error(`The ZIP file could not be downloaded. HTTP Code: ${response.status}`);
}
await pipeline(response.body, createWriteStream(zipFilePath));
console.log("Finished downloading.");
const zip = new AdmZip(zipFilePath);
console.log(`Starting to unzip CSV files to '${options.tmpDir}'`);
zip.extractAllTo(options.tmpDir, true);
console.log("Unzip completed.");
rmSync(zipFilePath);
console.log("Removed the ZIP file.");
};
const importDataToDb = async (options) => {
const extractionFolder = getExtractionFolder(options);
const files = readdirSync(extractionFolder);
let total = 0;
let next = 0;
console.log("Initiating import of RUIAN data to search DB (~3 million rows to be imported).");
const allIds = new Set();
for (const [i, file] of files.entries()) {
const rows = [];
const parseStream = parse({ delimiter: ";", fromLine: 2 }).on("data", async (data) => {
rows.push(data);
allIds.add(parseInt(data[0]));
});
await pipeline(createReadStream(join(extractionFolder, file)), iconv.decodeStream("win1250"), parseStream);
const chunks = chunk(rows, maxBufferSize);
await Promise.all(chunks.map(async (chunk) => {
total += await commitAddressPoints(chunk);
if (total - next >= 100000) {
next += 100000;
console.log(`Total imported rows: ${next}`);
}
}));
console.log(`${i + 1}/${files.length} files imported.`);
}
await removeDeprecatedAddressPoints(allIds);
console.log(`Import completed. Total imported rows: ${total}`);
};
const getExtractionFolder = (options) => join(options.tmpDir, options.addressPointsCsvFolderName);
export const downloadAndImportAddressPoints = async (options = {}) => {
await runSyncPart(SyncPart.AddressPoints, [], async () => {
const completeOptions = prepareOptions(options);
const datasetFeedLink = await getLatestUrlFromAtomFeed(completeOptions.addressPointsAtomUrl);
const zipUrl = await getLatestUrlFromAtomFeed(datasetFeedLink);
await downloadAndUnzip(zipUrl, completeOptions);
await importDataToDb(completeOptions);
});
};
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYWRkcmVzcy1wb2ludHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvb3Blbi1kYXRhLXN5bmMvYWRkcmVzcy1wb2ludHMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxNQUFNLE1BQU0sU0FBUyxDQUFDO0FBQzdCLE9BQU8sRUFBRSxLQUFLLEVBQUUsTUFBTSxXQUFXLENBQUM7QUFDbEMsT0FBTyxFQUFFLGdCQUFnQixFQUFFLGlCQUFpQixFQUFFLFdBQVcsRUFBRSxNQUFNLEVBQUUsTUFBTSxJQUFJLENBQUM7QUFDOUUsT0FBTyxLQUFLLE1BQU0sWUFBWSxDQUFDO0FBQy9CLE9BQU8sS0FBSyxNQUFNLFlBQVksQ0FBQztBQUMvQixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVCLE9BQU8sRUFBRSxRQUFRLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMzQyxPQUFPLEtBQUssTUFBTSxjQUFjLENBQUM7QUFDakMsT0FBTyxFQUNMLG1CQUFtQixFQUNuQiw2QkFBNkIsR0FDOUIsTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSx3QkFBd0IsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RCxPQUFPLEVBR0wsY0FBYyxHQUNmLE1BQU0sa0JBQWtCLENBQUM7QUFDMUIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUV2QyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUM7QUFFM0IsTUFBTSxnQkFBZ0IsR0FBRyxLQUFLLEVBQzVCLEdBQVcsRUFDWCxPQUE0QixFQUNiLEVBQUU7SUFDakIsTUFBTSxXQUFXLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFFM0UsT0FBTyxDQUFDLEdBQUcsQ0FBQywwREFBMEQsQ0FBQyxDQUFDO0lBQ3hFLE1BQU0sUUFBUSxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQ2xDLElBQUksUUFBUSxDQUFDLE1BQU0sS0FBSyxHQUFHLEVBQUU7UUFDM0IsTUFBTSxJQUFJLEtBQUssQ0FDYixvREFBb0QsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUN0RSxDQUFDO0tBQ0g7SUFDRCxNQUFNLFFBQVEsQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLGlCQUFpQixDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUM7SUFFOUQsT0FBTyxDQUFDLEdBQUcsQ0FBQyx1QkFBdUIsQ0FBQyxDQUFDO0lBQ3JDLE1BQU0sR0FBRyxHQUFHLElBQUksTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBRXBDLE9BQU8sQ0FBQyxHQUFHLENBQUMsbUNBQW1DLE9BQU8sQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDO0lBQ2xFLEdBQUcsQ0FBQyxZQUFZLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUMsQ0FBQztJQUN2QyxPQUFPLENBQUMsR0FBRyxDQUFDLGtCQUFrQixDQUFDLENBQUM7SUFFaEMsTUFBTSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3BCLE9BQU8sQ0FBQyxHQUFHLENBQUMsdUJBQXVCLENBQUMsQ0FBQztBQUN2QyxDQUFDLENBQUM7QUFFRixNQUFNLGNBQWMsR0FBRyxLQUFLLEVBQUUsT0FBNEIsRUFBRSxFQUFFO0lBQzVELE1BQU0sZ0JBQWdCLEdBQUcsbUJBQW1CLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFdEQsTUFBTSxLQUFLLEdBQUcsV0FBVyxDQUFDLGdCQUFnQixDQUFDLENBQUM7SUFFNUMsSUFBSSxLQUFLLEdBQUcsQ0FBQyxDQUFDO0lBQ2QsSUFBSSxJQUFJLEdBQUcsQ0FBQyxDQUFDO0lBRWIsT0FBTyxDQUFDLEdBQUcsQ0FDVCxnRkFBZ0YsQ0FDakYsQ0FBQztJQUVGLE1BQU0sTUFBTSxHQUFHLElBQUksR0FBRyxFQUFVLENBQUM7SUFFakMsS0FBSyxNQUFNLENBQUMsQ0FBQyxFQUFFLElBQUksQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsRUFBRTtRQUN2QyxNQUFNLElBQUksR0FBZSxFQUFFLENBQUM7UUFDNUIsTUFBTSxXQUFXLEdBQUcsS0FBSyxDQUFDLEVBQUUsU0FBUyxFQUFFLEdBQUcsRUFBRSxRQUFRLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQyxFQUFFLENBQzNELE1BQU0sRUFDTixLQUFLLEVBQUUsSUFBSSxFQUFFLEVBQUU7WUFDYixJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7UUFDaEMsQ0FBQyxDQUNGLENBQUM7UUFFRixNQUFNLFFBQVEsQ0FDWixnQkFBZ0IsQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsSUFBSSxDQUFDLENBQUMsRUFDOUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxTQUFTLENBQUMsRUFDN0IsV0FBVyxDQUNaLENBQUM7UUFFRixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsSUFBSSxFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBRTFDLE1BQU0sT0FBTyxDQUFDLEdBQUcsQ0FDZixNQUFNLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxLQUFLLEVBQUUsRUFBRTtZQUN6QixLQUFLLElBQUksTUFBTSxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztZQUUxQyxJQUFJLEtBQUssR0FBRyxJQUFJLElBQUksTUFBTSxFQUFFO2dCQUMxQixJQUFJLElBQUksTUFBTSxDQUFDO2dCQUNmLE9BQU8sQ0FBQyxHQUFHLENBQUMsd0JBQXdCLElBQUksRUFBRSxDQUFDLENBQUM7YUFDN0M7UUFDSCxDQUFDLENBQUMsQ0FDSCxDQUFDO1FBRUYsT0FBTyxDQUFDLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sa0JBQWtCLENBQUMsQ0FBQztLQUN6RDtJQUVELE1BQU0sNkJBQTZCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFFNUMsT0FBTyxDQUFDLEdBQUcsQ0FBQywwQ0FBMEMsS0FBSyxFQUFFLENBQUMsQ0FBQztBQUNqRSxDQUFDLENBQUM7QUFFRixNQUFNLG1CQUFtQixHQUFHLENBQUMsT0FBNEIsRUFBRSxFQUFFLENBQzNELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLE9BQU8sQ0FBQywwQkFBMEIsQ0FBQyxDQUFDO0FBRTNELE1BQU0sQ0FBQyxNQUFNLDhCQUE4QixHQUFHLEtBQUssRUFDakQsVUFBc0MsRUFBRSxFQUN6QixFQUFFO0lBQ2pCLE1BQU0sV0FBVyxDQUFDLFFBQVEsQ0FBQyxhQUFhLEVBQUUsRUFBRSxFQUFFLEtBQUssSUFBSSxFQUFFO1FBQ3ZELE1BQU0sZUFBZSxHQUFHLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNoRCxNQUFNLGVBQWUsR0FBRyxNQUFNLHdCQUF3QixDQUNwRCxlQUFlLENBQUMsb0JBQW9CLENBQ3JDLENBQUM7UUFDRixNQUFNLE1BQU0sR0FBRyxNQUFNLHdCQUF3QixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQy9ELE1BQU0sZ0JBQWdCLENBQUMsTUFBTSxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBQ2hELE1BQU0sY0FBYyxDQUFDLGVBQWUsQ0FBQyxDQUFDO0lBQ3hDLENBQUMsQ0FBQyxDQUFDO0FBQ0wsQ0FBQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEFkbVppcCBmcm9tIFwiYWRtLXppcFwiO1xyXG5pbXBvcnQgeyBwYXJzZSB9IGZyb20gXCJjc3YtcGFyc2VcIjtcclxuaW1wb3J0IHsgY3JlYXRlUmVhZFN0cmVhbSwgY3JlYXRlV3JpdGVTdHJlYW0sIHJlYWRkaXJTeW5jLCBybVN5bmMgfSBmcm9tIFwiZnNcIjtcclxuaW1wb3J0IGljb252IGZyb20gXCJpY29udi1saXRlXCI7XHJcbmltcG9ydCBmZXRjaCBmcm9tIFwibm9kZS1mZXRjaFwiO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSBcInBhdGhcIjtcclxuaW1wb3J0IHsgcGlwZWxpbmUgfSBmcm9tIFwic3RyZWFtL3Byb21pc2VzXCI7XHJcbmltcG9ydCBjaHVuayBmcm9tIFwibG9kYXNoL2NodW5rXCI7XHJcbmltcG9ydCB7XHJcbiAgY29tbWl0QWRkcmVzc1BvaW50cyxcclxuICByZW1vdmVEZXByZWNhdGVkQWRkcmVzc1BvaW50cyxcclxufSBmcm9tIFwiLi4vZGIvYWRkcmVzcy1wb2ludHNcIjtcclxuaW1wb3J0IHsgU3luY1BhcnQgfSBmcm9tIFwiLi4vZGIvdHlwZXNcIjtcclxuaW1wb3J0IHsgZ2V0TGF0ZXN0VXJsRnJvbUF0b21GZWVkIH0gZnJvbSBcIi4uL3V0aWxzL2F0b21cIjtcclxuaW1wb3J0IHtcclxuICBPcGVuRGF0YVN5bmNPcHRpb25zLFxyXG4gIE9wZW5EYXRhU3luY09wdGlvbnNQYXJ0aWFsLFxyXG4gIHByZXBhcmVPcHRpb25zLFxyXG59IGZyb20gXCIuLi91dGlscy9oZWxwZXJzXCI7XHJcbmltcG9ydCB7IHJ1blN5bmNQYXJ0IH0gZnJvbSBcIi4vY29tbW9uXCI7XHJcblxyXG5jb25zdCBtYXhCdWZmZXJTaXplID0gMTAwMDtcclxuXHJcbmNvbnN0IGRvd25sb2FkQW5kVW56aXAgPSBhc3luYyAoXHJcbiAgdXJsOiBzdHJpbmcsXHJcbiAgb3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1xyXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcclxuICBjb25zdCB6aXBGaWxlUGF0aCA9IGpvaW4ob3B0aW9ucy50bXBEaXIsIG9wdGlvbnMuYWRkcmVzc1BvaW50c1ppcEZpbGVOYW1lKTtcclxuXHJcbiAgY29uc29sZS5sb2coXCJEb3dubG9hZGluZyBhIGxhcmdlIFpJUCBmaWxlIHdpdGggUlVJQU4gZGF0YSAofjY1IE1CKS4uLlwiKTtcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKHVybCk7XHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1cyAhPT0gMjAwKSB7XHJcbiAgICB0aHJvdyBuZXcgRXJyb3IoXHJcbiAgICAgIGBUaGUgWklQIGZpbGUgY291bGQgbm90IGJlIGRvd25sb2FkZWQuIEhUVFAgQ29kZTogJHtyZXNwb25zZS5zdGF0dXN9YFxyXG4gICAgKTtcclxuICB9XHJcbiAgYXdhaXQgcGlwZWxpbmUocmVzcG9uc2UuYm9keSwgY3JlYXRlV3JpdGVTdHJlYW0oemlwRmlsZVBhdGgpKTtcclxuXHJcbiAgY29uc29sZS5sb2coXCJGaW5pc2hlZCBkb3dubG9hZGluZy5cIik7XHJcbiAgY29uc3QgemlwID0gbmV3IEFkbVppcCh6aXBGaWxlUGF0aCk7XHJcblxyXG4gIGNvbnNvbGUubG9nKGBTdGFydGluZyB0byB1bnppcCBDU1YgZmlsZXMgdG8gJyR7b3B0aW9ucy50bXBEaXJ9J2ApO1xyXG4gIHppcC5leHRyYWN0QWxsVG8ob3B0aW9ucy50bXBEaXIsIHRydWUpO1xyXG4gIGNvbnNvbGUubG9nKFwiVW56aXAgY29tcGxldGVkLlwiKTtcclxuXHJcbiAgcm1TeW5jKHppcEZpbGVQYXRoKTtcclxuICBjb25zb2xlLmxvZyhcIlJlbW92ZWQgdGhlIFpJUCBmaWxlLlwiKTtcclxufTtcclxuXHJcbmNvbnN0IGltcG9ydERhdGFUb0RiID0gYXN5bmMgKG9wdGlvbnM6IE9wZW5EYXRhU3luY09wdGlvbnMpID0+IHtcclxuICBjb25zdCBleHRyYWN0aW9uRm9sZGVyID0gZ2V0RXh0cmFjdGlvbkZvbGRlcihvcHRpb25zKTtcclxuXHJcbiAgY29uc3QgZmlsZXMgPSByZWFkZGlyU3luYyhleHRyYWN0aW9uRm9sZGVyKTtcclxuXHJcbiAgbGV0IHRvdGFsID0gMDtcclxuICBsZXQgbmV4dCA9IDA7XHJcblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgXCJJbml0aWF0aW5nIGltcG9ydCBvZiBSVUlBTiBkYXRhIHRvIHNlYXJjaCBEQiAofjMgbWlsbGlvbiByb3dzIHRvIGJlIGltcG9ydGVkKS5cIlxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGFsbElkcyA9IG5ldyBTZXQ8bnVtYmVyPigpO1xyXG5cclxuICBmb3IgKGNvbnN0IFtpLCBmaWxlXSBvZiBmaWxlcy5lbnRyaWVzKCkpIHtcclxuICAgIGNvbnN0IHJvd3M6IHN0cmluZ1tdW10gPSBbXTtcclxuICAgIGNvbnN0IHBhcnNlU3RyZWFtID0gcGFyc2UoeyBkZWxpbWl0ZXI6IFwiO1wiLCBmcm9tTGluZTogMiB9KS5vbihcclxuICAgICAgXCJkYXRhXCIsXHJcbiAgICAgIGFzeW5jIChkYXRhKSA9PiB7XHJcbiAgICAgICAgcm93cy5wdXNoKGRhdGEpO1xyXG4gICAgICAgIGFsbElkcy5hZGQocGFyc2VJbnQoZGF0YVswXSkpO1xyXG4gICAgICB9XHJcbiAgICApO1xyXG5cclxuICAgIGF3YWl0IHBpcGVsaW5lKFxyXG4gICAgICBjcmVhdGVSZWFkU3RyZWFtKGpvaW4oZXh0cmFjdGlvbkZvbGRlciwgZmlsZSkpLFxyXG4gICAgICBpY29udi5kZWNvZGVTdHJlYW0oXCJ3aW4xMjUwXCIpLFxyXG4gICAgICBwYXJzZVN0cmVhbVxyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCBjaHVua3MgPSBjaHVuayhyb3dzLCBtYXhCdWZmZXJTaXplKTtcclxuXHJcbiAgICBhd2FpdCBQcm9taXNlLmFsbChcclxuICAgICAgY2h1bmtzLm1hcChhc3luYyAoY2h1bmspID0+IHtcclxuICAgICAgICB0b3RhbCArPSBhd2FpdCBjb21taXRBZGRyZXNzUG9pbnRzKGNodW5rKTtcclxuXHJcbiAgICAgICAgaWYgKHRvdGFsIC0gbmV4dCA+PSAxMDAwMDApIHtcclxuICAgICAgICAgIG5leHQgKz0gMTAwMDAwO1xyXG4gICAgICAgICAgY29uc29sZS5sb2coYFRvdGFsIGltcG9ydGVkIHJvd3M6ICR7bmV4dH1gKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnNvbGUubG9nKGAke2kgKyAxfS8ke2ZpbGVzLmxlbmd0aH0gZmlsZXMgaW1wb3J0ZWQuYCk7XHJcbiAgfVxyXG5cclxuICBhd2FpdCByZW1vdmVEZXByZWNhdGVkQWRkcmVzc1BvaW50cyhhbGxJZHMpO1xyXG5cclxuICBjb25zb2xlLmxvZyhgSW1wb3J0IGNvbXBsZXRlZC4gVG90YWwgaW1wb3J0ZWQgcm93czogJHt0b3RhbH1gKTtcclxufTtcclxuXHJcbmNvbnN0IGdldEV4dHJhY3Rpb25Gb2xkZXIgPSAob3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9ucykgPT5cclxuICBqb2luKG9wdGlvbnMudG1wRGlyLCBvcHRpb25zLmFkZHJlc3NQb2ludHNDc3ZGb2xkZXJOYW1lKTtcclxuXHJcbmV4cG9ydCBjb25zdCBkb3dubG9hZEFuZEltcG9ydEFkZHJlc3NQb2ludHMgPSBhc3luYyAoXHJcbiAgb3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1BhcnRpYWwgPSB7fVxyXG4pOiBQcm9taXNlPHZvaWQ+ID0+IHtcclxuICBhd2FpdCBydW5TeW5jUGFydChTeW5jUGFydC5BZGRyZXNzUG9pbnRzLCBbXSwgYXN5bmMgKCkgPT4ge1xyXG4gICAgY29uc3QgY29tcGxldGVPcHRpb25zID0gcHJlcGFyZU9wdGlvbnMob3B0aW9ucyk7XHJcbiAgICBjb25zdCBkYXRhc2V0RmVlZExpbmsgPSBhd2FpdCBnZXRMYXRlc3RVcmxGcm9tQXRvbUZlZWQoXHJcbiAgICAgIGNvbXBsZXRlT3B0aW9ucy5hZGRyZXNzUG9pbnRzQXRvbVVybFxyXG4gICAgKTtcclxuICAgIGNvbnN0IHppcFVybCA9IGF3YWl0IGdldExhdGVzdFVybEZyb21BdG9tRmVlZChkYXRhc2V0RmVlZExpbmspO1xyXG4gICAgYXdhaXQgZG93bmxvYWRBbmRVbnppcCh6aXBVcmwsIGNvbXBsZXRlT3B0aW9ucyk7XHJcbiAgICBhd2FpdCBpbXBvcnREYXRhVG9EYihjb21wbGV0ZU9wdGlvbnMpO1xyXG4gIH0pO1xyXG59O1xyXG4iXX0=