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

311 lines 41.8 kB
import { createReadStream, createWriteStream, existsSync, rmSync } from "fs"; import fetch from "node-fetch"; import { join } from "path"; import sax from "sax"; import { pipeline } from "stream/promises"; import { insertFounders } from "../db/founders"; import { insertSchools } from "../db/schools"; import { MunicipalityType, SchoolType, SyncPart, } from "../db/types"; import { prepareOptions, } from "../utils/helpers"; import { runSyncPart } from "./common"; const downloadXml = async (options) => { if (existsSync(getXmlFilePath(options))) { return; } console.log("Downloading a large XML file with school data..."); const response = await fetch(options.schoolsXmlUrl); if (response.status !== 200) { throw new Error(`The XML file could not be downloaded. HTTP Code: ${response.status}`); } await pipeline(response.body, createWriteStream(getXmlFilePath(options))); console.log("Finished downloading."); }; var XMLState; (function (XMLState) { XMLState[XMLState["None"] = 0] = "None"; XMLState[XMLState["RedIzo"] = 1] = "RedIzo"; XMLState[XMLState["SchoolName"] = 2] = "SchoolName"; XMLState[XMLState["Izo"] = 3] = "Izo"; XMLState[XMLState["Ico"] = 4] = "Ico"; XMLState[XMLState["SchoolType"] = 5] = "SchoolType"; XMLState[XMLState["Capacity"] = 6] = "Capacity"; XMLState[XMLState["RuianCode"] = 7] = "RuianCode"; XMLState[XMLState["Address"] = 8] = "Address"; XMLState[XMLState["FounderName"] = 9] = "FounderName"; XMLState[XMLState["FounderType"] = 10] = "FounderType"; XMLState[XMLState["FounderIco"] = 11] = "FounderIco"; })(XMLState || (XMLState = {})); const SCHOOL_TYPE_KINDERGARTEN = "A00"; const SCHOOL_TYPE_ELEMENTARY = "B00"; const getCorrectFounderType = (founderType) => { return founderType === "" ? "101" : founderType; }; const getMunicipalityType = (founderType) => { return founderType === "261" ? MunicipalityType.City : founderType === "263" ? MunicipalityType.District : MunicipalityType.Other; }; const processSchoolRegisterXml = async (options) => { let currentSchools; let currentRedizo; let currentName; let currentIzo; let currentIco; let currentType = null; let currentCapacity; let currentLocations = []; let state = XMLState.None; let currentFounders = []; let currentFounderIco; let currentFounderName; let currentFounderType; let isRuianCodeSet = false; let isRuianCodeMissing = false; let currentAddress = []; const founders = new Map(); const schools = []; const schoolsWithoutRuian = []; const streamPromise = new Promise((resolve, reject) => { const saxStream = sax .createStream(true) .on("opentag", (tag) => { switch (tag.name) { case "PravniSubjekt": currentSchools = []; currentRedizo = ""; currentName = ""; currentIzo = ""; currentCapacity = 0; isRuianCodeMissing = false; break; case "RedIzo": state = XMLState.RedIzo; break; case "RedPlnyNazev": state = XMLState.SchoolName; break; case "IZO": state = XMLState.Izo; break; case "ICO": state = XMLState.Ico; break; case "SkolaDruhTyp": state = XMLState.SchoolType; break; case "SkolaKapacita": state = XMLState.Capacity; break; case "MistoRUAINKod": isRuianCodeSet = false; currentAddress = []; state = XMLState.RuianCode; break; case "ZrizNazev": state = XMLState.FounderName; break; case "ZrizPravniForma": state = XMLState.FounderType; break; case "MistoAdresa1": case "MistoAdresa2": case "MistoAdresa3": state = XMLState.Address; break; case "ZrizDatumNarozeni": case "ZrizICO": state = XMLState.FounderIco; break; } }) .on("closetag", (tagName) => { switch (tagName) { case "PravniSubjekt": if (currentSchools.length > 0) { schools.push(...currentSchools); currentFounders.forEach((founder) => { const key = founder.name + founder.ico; if (founders.has(key)) { founders.get(key).schools.push(...currentSchools); } else { founders.set(key, { name: founder.name, ico: founder.ico, originalType: founder.type, municipalityType: getMunicipalityType(founder.type), schools: [...currentSchools], }); } }); } currentIco = ""; currentFounders = []; break; case "Zrizovatel": if (currentFounderIco === "" || currentFounderName === "") { currentFounders.push({ ico: currentIco, name: currentName, type: "224", // s.r.o (not all are those, but we don't need to differentiate here) }); } else { currentFounders.push({ ico: currentFounderIco, name: currentFounderName, type: getCorrectFounderType(currentFounderType), }); } currentFounderIco = ""; currentFounderName = ""; currentFounderType = ""; break; case "SkolaZarizeni": if (currentType !== null) { currentSchools.push({ izo: currentIzo, name: currentName, redizo: currentRedizo, capacity: currentCapacity, type: currentType, locations: currentLocations, }); } currentLocations = []; currentType = null; break; case "SkolaMistoVykonuCinnosti": if (isRuianCodeMissing) { schoolsWithoutRuian.push({ izo: currentIzo, address: currentAddress, type: currentType, }); } break; case "MistoRUAINKod": isRuianCodeMissing = !isRuianCodeSet; case "RedPlnyNazev": case "RedIzo": case "ICO": case "IZO": case "SkolaDruhTyp": case "SkolaKapacita": case "ZrizNazev": case "ZrizICO": case "ZrizDatumNarozeni": case "ZrizPravniForma": case "MistoAdresa1": case "MistoAdresa2": case "MistoAdresa3": state = XMLState.None; break; } }) .on("text", (text) => { switch (state) { case XMLState.RedIzo: currentRedizo = text; case XMLState.SchoolName: currentName = text; break; case XMLState.Izo: currentIzo = text; break; case XMLState.Ico: currentIco = text; break; case XMLState.SchoolType: if (text === SCHOOL_TYPE_KINDERGARTEN) { currentType = SchoolType.Kindergarten; } else if (text === SCHOOL_TYPE_ELEMENTARY) { currentType = SchoolType.Elementary; } break; case XMLState.RuianCode: isRuianCodeSet = true; currentLocations.push({ addressPointId: parseInt(text), }); break; case XMLState.Address: currentAddress.push(text); break; case XMLState.FounderName: currentFounderName = text; break; case XMLState.FounderIco: currentFounderIco = text; break; case XMLState.FounderType: currentFounderType = text; break; case XMLState.Capacity: currentCapacity = parseInt(text); break; } }) .on("error", reject) .on("end", resolve); // wanted to use 'await pipeline(createReadStream(getXmlFilePath(options)), saxStream)' // but the program would quit spontaneously after finishing stream - using Promise instead. createReadStream(getXmlFilePath(options)).pipe(saxStream); }); await streamPromise; return { schools, founders, schoolsWithoutRuian }; }; const importDataToDb = async (options, saveFoundersToCsv = false, saveSchoolsWithoutRuianToCsv = false) => { const { schools, founders, schoolsWithoutRuian } = await processSchoolRegisterXml(options); if (saveFoundersToCsv) { const csvFile = "founders.csv"; if (existsSync(csvFile)) { rmSync(csvFile); } var csv = createWriteStream(csvFile, { flags: "a", }); csv.write("IČO;Zřizovatel;Právní forma;Počet škol;Školy\n"); founders.forEach((founder) => { csv.write(`#${founder.ico};${founder.name};${founder.originalType};${founder.schools.length};${founder.schools.map((school) => school.name).join("---")}\n`); }); csv.end(); } if (saveSchoolsWithoutRuianToCsv) { const csvFile = "schoolsWithoutRuian.csv"; if (existsSync(csvFile)) { rmSync(csvFile); } var csv = createWriteStream(csvFile, { flags: "a", }); csv.write("IZO;Je mateřská;Je základní;adresa1;adresa2;adresa3\n"); schoolsWithoutRuian.forEach((schoolAddress) => { csv.write(`#${schoolAddress.izo};${schoolAddress.type === SchoolType.Kindergarten ? "TRUE" : "FALSE"};${schoolAddress.type === SchoolType.Elementary ? "TRUE" : "FALSE"};${schoolAddress.address.join(";")}\n`); }); csv.end(); } await insertSchools(schools); await insertFounders(Array.from(founders.values())); }; const getXmlFilePath = (options) => { return join(options.tmpDir, options.schoolsXmlFileName); }; export const downloadAndImportSchools = async (options = {}, saveFoundersToCsv = false, saveSchoolsWithoutRuianToCsv = false) => { await runSyncPart(SyncPart.Schools, [SyncPart.AddressPoints], async () => { const runOptions = prepareOptions(options); await downloadXml(runOptions); await importDataToDb(runOptions, saveFoundersToCsv, saveSchoolsWithoutRuianToCsv); deleteSchoolsXmlFile(runOptions); }); }; export const deleteSchoolsXmlFile = (options = {}) => { const runOptions = prepareOptions(options); if (existsSync(getXmlFilePath(runOptions))) { rmSync(getXmlFilePath(runOptions)); } }; //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic2Nob29scy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9vcGVuLWRhdGEtc3luYy9zY2hvb2xzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxpQkFBaUIsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sSUFBSSxDQUFDO0FBQzdFLE9BQU8sS0FBSyxNQUFNLFlBQVksQ0FBQztBQUMvQixPQUFPLEVBQUUsSUFBSSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzVCLE9BQU8sR0FBWSxNQUFNLEtBQUssQ0FBQztBQUUvQixPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDM0MsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ2hELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDOUMsT0FBTyxFQUVMLGdCQUFnQixFQUdoQixVQUFVLEVBQ1YsUUFBUSxHQUNULE1BQU0sYUFBYSxDQUFDO0FBQ3JCLE9BQU8sRUFHTCxjQUFjLEdBQ2YsTUFBTSxrQkFBa0IsQ0FBQztBQUMxQixPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRXZDLE1BQU0sV0FBVyxHQUFHLEtBQUssRUFBRSxPQUE0QixFQUFpQixFQUFFO0lBQ3hFLElBQUksVUFBVSxDQUFDLGNBQWMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxFQUFFO1FBQ3ZDLE9BQU87S0FDUjtJQUVELE9BQU8sQ0FBQyxHQUFHLENBQUMsa0RBQWtELENBQUMsQ0FBQztJQUNoRSxNQUFNLFFBQVEsR0FBRyxNQUFNLEtBQUssQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDcEQsSUFBSSxRQUFRLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRTtRQUMzQixNQUFNLElBQUksS0FBSyxDQUNiLG9EQUFvRCxRQUFRLENBQUMsTUFBTSxFQUFFLENBQ3RFLENBQUM7S0FD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bEMsVUFBc0MsRUFBRSxFQUN4QyxFQUFFO0lBQ0YsTUFBTSxVQUFVLEdBQUcsY0FBYyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBRTNDLElBQUksVUFBVSxDQUFDLGNBQWMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFO1FBQzFDLE1BQU0sQ0FBQyxjQUFjLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQztLQUNwQztBQUNILENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGNyZWF0ZVJlYWRTdHJlYW0sIGNyZWF0ZVdyaXRlU3RyZWFtLCBleGlzdHNTeW5jLCBybVN5bmMgfSBmcm9tIFwiZnNcIjtcclxuaW1wb3J0IGZldGNoIGZyb20gXCJub2RlLWZldGNoXCI7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tIFwicGF0aFwiO1xyXG5pbXBvcnQgc2F4LCB7IFRhZyB9IGZyb20gXCJzYXhcIjtcclxuXHJcbmltcG9ydCB7IHBpcGVsaW5lIH0gZnJvbSBcInN0cmVhbS9wcm9taXNlc1wiO1xyXG5pbXBvcnQgeyBpbnNlcnRGb3VuZGVycyB9IGZyb20gXCIuLi9kYi9mb3VuZGVyc1wiO1xyXG5pbXBvcnQgeyBpbnNlcnRTY2hvb2xzIH0gZnJvbSBcIi4uL2RiL3NjaG9vbHNcIjtcclxuaW1wb3J0IHtcclxuICBGb3VuZGVyLFxyXG4gIE11bmljaXBhbGl0eVR5cGUsXHJcbiAgU2Nob29sLFxyXG4gIFNjaG9vbExvY2F0aW9uLFxyXG4gIFNjaG9vbFR5cGUsXHJcbiAgU3luY1BhcnQsXHJcbn0gZnJvbSBcIi4uL2RiL3R5cGVzXCI7XHJcbmltcG9ydCB7XHJcbiAgT3BlbkRhdGFTeW5jT3B0aW9ucyxcclxuICBPcGVuRGF0YVN5bmNPcHRpb25zUGFydGlhbCxcclxuICBwcmVwYXJlT3B0aW9ucyxcclxufSBmcm9tIFwiLi4vdXRpbHMvaGVscGVyc1wiO1xyXG5pbXBvcnQgeyBydW5TeW5jUGFydCB9IGZyb20gXCIuL2NvbW1vblwiO1xyXG5cclxuY29uc3QgZG93bmxvYWRYbWwgPSBhc3luYyAob3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9ucyk6IFByb21pc2U8dm9pZD4gPT4ge1xyXG4gIGlmIChleGlzdHNTeW5jKGdldFhtbEZpbGVQYXRoKG9wdGlvbnMpKSkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgY29uc29sZS5sb2coXCJEb3dubG9hZGluZyBhIGxhcmdlIFhNTCBmaWxlIHdpdGggc2Nob29sIGRhdGEuLi5cIik7XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChvcHRpb25zLnNjaG9vbHNYbWxVcmwpO1xyXG4gIGlmIChyZXNwb25zZS5zdGF0dXMgIT09IDIwMCkge1xyXG4gICAgdGhyb3cgbmV3IEVycm9yKFxyXG4gICAgICBgVGhlIFhNTCBmaWxlIGNvdWxkIG5vdCBiZSBkb3dubG9hZGVkLiBIVFRQIENvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzfWBcclxuICAgICk7XHJcbiAgfVxyXG4gIGF3YWl0IHBpcGVsaW5lKHJlc3BvbnNlLmJvZHksIGNyZWF0ZVdyaXRlU3RyZWFtKGdldFhtbEZpbGVQYXRoKG9wdGlvbnMpKSk7XHJcbiAgY29uc29sZS5sb2coXCJGaW5pc2hlZCBkb3dubG9hZGluZy5cIik7XHJcbn07XHJcblxyXG5lbnVtIFhNTFN0YXRlIHtcclxuICBOb25lLFxyXG4gIFJlZEl6byxcclxuICBTY2hvb2xOYW1lLFxyXG4gIEl6byxcclxuICBJY28sXHJcbiAgU2Nob29sVHlwZSxcclxuICBDYXBhY2l0eSxcclxuICBSdWlhbkNvZGUsXHJcbiAgQWRkcmVzcyxcclxuICBGb3VuZGVyTmFtZSxcclxuICBGb3VuZGVyVHlwZSxcclxuICBGb3VuZGVySWNvLFxyXG59XHJcblxyXG5jb25zdCBTQ0hPT0xfVFlQRV9LSU5ERVJHQVJURU4gPSBcIkEwMFwiO1xyXG5jb25zdCBTQ0hPT0xfVFlQRV9FTEVNRU5UQVJZID0gXCJCMDBcIjtcclxuXHJcbmNvbnN0IGdldENvcnJlY3RGb3VuZGVyVHlwZSA9IChmb3VuZGVyVHlwZTogc3RyaW5nKTogc3RyaW5nID0+IHtcclxuICByZXR1cm4gZm91bmRlclR5cGUgPT09IFwiXCIgPyBcIjEwMVwiIDogZm91bmRlclR5cGU7XHJcbn07XHJcblxyXG5jb25zdCBnZXRNdW5pY2lwYWxpdHlUeXBlID0gKGZvdW5kZXJUeXBlOiBzdHJpbmcpOiBNdW5pY2lwYWxpdHlUeXBlID0+IHtcclxuICByZXR1cm4gZm91bmRlclR5cGUgPT09IFwiMjYxXCJcclxuICAgID8gTXVuaWNpcGFsaXR5VHlwZS5DaXR5XHJcbiAgICA6IGZvdW5kZXJUeXBlID09PSBcIjI2M1wiXHJcbiAgICA/IE11bmljaXBhbGl0eVR5cGUuRGlzdHJpY3RcclxuICAgIDogTXVuaWNpcGFsaXR5VHlwZS5PdGhlcjtcclxufTtcclxuXHJcbnR5cGUgU2Nob29sQWRkcmVzcyA9IHtcclxuICBpem86IHN0cmluZztcclxuICBhZGRyZXNzOiBzdHJpbmdbXTtcclxuICB0eXBlOiBTY2hvb2xUeXBlO1xyXG59O1xyXG5cclxuY29uc3QgcHJvY2Vzc1NjaG9vbFJlZ2lzdGVyWG1sID0gYXN5bmMgKFxyXG4gIG9wdGlvbnM6IE9wZW5EYXRhU3luY09wdGlvbnNcclxuKTogUHJvbWlzZTx7XHJcbiAgc2Nob29sczogU2Nob29sW107XHJcbiAgZm91bmRlcnM6IE1hcDxzdHJpbmcsIEZvdW5kZXI+O1xyXG4gIHNjaG9vbHNXaXRob3V0UnVpYW46IFNjaG9vbEFkZHJlc3NbXTtcclxufT4gPT4ge1xyXG4gIGxldCBjdXJyZW50U2Nob29sczogU2Nob29sW107XHJcbiAgbGV0IGN1cnJlbnRSZWRpem86IHN0cmluZztcclxuICBsZXQgY3VycmVudE5hbWU6IHN0cmluZztcclxuICBsZXQgY3VycmVudEl6bzogc3RyaW5nO1xyXG4gIGxldCBjdXJyZW50SWNvOiBzdHJpbmc7XHJcbiAgbGV0IGN1cnJlbnRUeXBlOiBTY2hvb2xUeXBlIHwgbnVsbCA9IG51bGw7XHJcbiAgbGV0IGN1cnJlbnRDYXBhY2l0eTogbnVtYmVyO1xyXG4gIGxldCBjdXJyZW50TG9jYXRpb25zOiBTY2hvb2xMb2NhdGlvbltdID0gW107XHJcbiAgbGV0IHN0YXRlOiBYTUxTdGF0ZSA9IFhNTFN0YXRlLk5vbmU7XHJcbiAgbGV0IGN1cnJlbnRGb3VuZGVycyA9IFtdO1xyXG4gIGxldCBjdXJyZW50Rm91bmRlckljbzogc3RyaW5nO1xyXG4gIGxldCBjdXJyZW50Rm91bmRlck5hbWU6IHN0cmluZztcclxuICBsZXQgY3VycmVudEZvdW5kZXJUeXBlOiBzdHJpbmc7XHJcbiAgbGV0IGlzUnVpYW5Db2RlU2V0ID0gZmFsc2U7XHJcbiAgbGV0IGlzUnVpYW5Db2RlTWlzc2luZyA9IGZhbHNlO1xyXG4gIGxldCBjdXJyZW50QWRkcmVzcyA9IFtdO1xyXG4gIGNvbnN0IGZvdW5kZXJzID0gbmV3IE1hcDxzdHJpbmcsIEZvdW5kZXI+KCk7XHJcbiAgY29uc3Qgc2Nob29sczogU2Nob29sW10gPSBbXTtcclxuICBjb25zdCBzY2hvb2xzV2l0aG91dFJ1aWFuOiBTY2hvb2xBZGRyZXNzW10gPSBbXTtcclxuXHJcbiAgY29uc3Qgc3RyZWFtUHJvbWlzZSA9IG5ldyBQcm9taXNlPHZvaWQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHNheFN0cmVhbSA9IHNheFxyXG4gICAgICAuY3JlYXRlU3RyZWFtKHRydWUpXHJcbiAgICAgIC5vbihcIm9wZW50YWdcIiwgKHRhZzogVGFnKSA9PiB7XHJcbiAgICAgICAgc3dpdGNoICh0YWcubmFtZSkge1xyXG4gICAgICAgICAgY2FzZSBcIlByYXZuaVN1Ympla3RcIjpcclxuICAgICAgICAgICAgY3VycmVudFNjaG9vbHMgPSBbXTtcclxuICAgICAgICAgICAgY3VycmVudFJlZGl6byA9IFwiXCI7XHJcbiAgICAgICAgICAgIGN1cnJlbnROYW1lID0gXCJcIjtcclxuICAgICAgICAgICAgY3VycmVudEl6byA9IFwiXCI7XHJcbiAgICAgICAgICAgIGN1cnJlbnRDYXBhY2l0eSA9IDA7XHJcbiAgICAgICAgICAgIGlzUnVpYW5Db2RlTWlzc2luZyA9IGZhbHNlO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgXCJSZWRJem9cIjpcclxuICAgICAgICAgICAgc3RhdGUgPSBYTUxTdGF0ZS5SZWRJem87XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBcIlJlZFBsbnlOYXpldlwiOlxyXG4gICAgICAgICAgICBzdGF0ZSA9IFhNTFN0YXRlLlNjaG9vbE5hbWU7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBcIklaT1wiOlxyXG4gICAgICAgICAgICBzdGF0ZSA9IFhNTFN0YXRlLkl6bztcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFwiSUNPXCI6XHJcbiAgICAgICAgICAgIHN0YXRlID0gWE1MU3RhdGUuSWNvO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgXCJTa29sYURydWhUeXBcIjpcclxuICAgICAgICAgICAgc3RhdGUgPSBYTUxTdGF0ZS5TY2hvb2xUeXBlO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgXCJTa29sYUthcGFjaXRhXCI6XHJcbiAgICAgICAgICAgIHN0YXRlID0gWE1MU3RhdGUuQ2FwYWNpdHk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBcIk1pc3RvUlVBSU5Lb2RcIjpcclxuICAgICAgICAgICAgaXNSdWlhbkNvZGVTZXQgPSBmYWxzZTtcclxuICAgICAgICAgICAgY3VycmVudEFkZHJlc3MgPSBbXTtcclxuICAgICAgICAgICAgc3RhdGUgPSBYTUxTdGF0ZS5SdWlhbkNvZGU7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBcIlpyaXpOYXpldlwiOlxyXG4gICAgICAgICAgICBzdGF0ZSA9IFhNTFN0YXRlLkZvdW5kZXJOYW1lO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgXCJacml6UHJhdm5pRm9ybWFcIjpcclxuICAgICAgICAgICAgc3RhdGUgPSBYTUxTdGF0ZS5Gb3VuZGVyVHlwZTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2ExXCI6XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2EyXCI6XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2EzXCI6XHJcbiAgICAgICAgICAgIHN0YXRlID0gWE1MU3RhdGUuQWRkcmVzcztcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFwiWnJpekRhdHVtTmFyb3plbmlcIjpcclxuICAgICAgICAgIGNhc2UgXCJacml6SUNPXCI6XHJcbiAgICAgICAgICAgIHN0YXRlID0gWE1MU3RhdGUuRm91bmRlckljbztcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgICAub24oXCJjbG9zZXRhZ1wiLCAodGFnTmFtZTogc3RyaW5nKSA9PiB7XHJcbiAgICAgICAgc3dpdGNoICh0YWdOYW1lKSB7XHJcbiAgICAgICAgICBjYXNlIFwiUHJhdm5pU3ViamVrdFwiOlxyXG4gICAgICAgICAgICBpZiAoY3VycmVudFNjaG9vbHMubGVuZ3RoID4gMCkge1xyXG4gICAgICAgICAgICAgIHNjaG9vbHMucHVzaCguLi5jdXJyZW50U2Nob29scyk7XHJcbiAgICAgICAgICAgICAgY3VycmVudEZvdW5kZXJzLmZvckVhY2goKGZvdW5kZXIpID0+IHtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGtleSA9IGZvdW5kZXIubmFtZSArIGZvdW5kZXIuaWNvO1xyXG4gICAgICAgICAgICAgICAgaWYgKGZvdW5kZXJzLmhhcyhrZXkpKSB7XHJcbiAgICAgICAgICAgICAgICAgIGZvdW5kZXJzLmdldChrZXkpLnNjaG9vbHMucHVzaCguLi5jdXJyZW50U2Nob29scyk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICBmb3VuZGVycy5zZXQoa2V5LCB7XHJcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogZm91bmRlci5uYW1lLFxyXG4gICAgICAgICAgICAgICAgICAgIGljbzogZm91bmRlci5pY28sXHJcbiAgICAgICAgICAgICAgICAgICAgb3JpZ2luYWxUeXBlOiBmb3VuZGVyLnR5cGUsXHJcbiAgICAgICAgICAgICAgICAgICAgbXVuaWNpcGFsaXR5VHlwZTogZ2V0TXVuaWNpcGFsaXR5VHlwZShmb3VuZGVyLnR5cGUpLFxyXG4gICAgICAgICAgICAgICAgICAgIHNjaG9vbHM6IFsuLi5jdXJyZW50U2Nob29sc10sXHJcbiAgICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGN1cnJlbnRJY28gPSBcIlwiO1xyXG4gICAgICAgICAgICBjdXJyZW50Rm91bmRlcnMgPSBbXTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcblxyXG4gICAgICAgICAgY2FzZSBcIlpyaXpvdmF0ZWxcIjpcclxuICAgICAgICAgICAgaWYgKGN1cnJlbnRGb3VuZGVySWNvID09PSBcIlwiIHx8IGN1cnJlbnRGb3VuZGVyTmFtZSA9PT0gXCJcIikge1xyXG4gICAgICAgICAgICAgIGN1cnJlbnRGb3VuZGVycy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIGljbzogY3VycmVudEljbyxcclxuICAgICAgICAgICAgICAgIG5hbWU6IGN1cnJlbnROYW1lLFxyXG4gICAgICAgICAgICAgICAgdHlwZTogXCIyMjRcIiwgLy8gcy5yLm8gKG5vdCBhbGwgYXJlIHRob3NlLCBidXQgd2UgZG9uJ3QgbmVlZCB0byBkaWZmZXJlbnRpYXRlIGhlcmUpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgY3VycmVudEZvdW5kZXJzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgaWNvOiBjdXJyZW50Rm91bmRlckljbyxcclxuICAgICAgICAgICAgICAgIG5hbWU6IGN1cnJlbnRGb3VuZGVyTmFtZSxcclxuICAgICAgICAgICAgICAgIHR5cGU6IGdldENvcnJlY3RGb3VuZGVyVHlwZShjdXJyZW50Rm91bmRlclR5cGUpLFxyXG4gICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGN1cnJlbnRGb3VuZGVySWNvID0gXCJcIjtcclxuICAgICAgICAgICAgY3VycmVudEZvdW5kZXJOYW1lID0gXCJcIjtcclxuICAgICAgICAgICAgY3VycmVudEZvdW5kZXJUeXBlID0gXCJcIjtcclxuXHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBcIlNrb2xhWmFyaXplbmlcIjpcclxuICAgICAgICAgICAgaWYgKGN1cnJlbnRUeXBlICE9PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgY3VycmVudFNjaG9vbHMucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBpem86IGN1cnJlbnRJem8sXHJcbiAgICAgICAgICAgICAgICBuYW1lOiBjdXJyZW50TmFtZSxcclxuICAgICAgICAgICAgICAgIHJlZGl6bzogY3VycmVudFJlZGl6byxcclxuICAgICAgICAgICAgICAgIGNhcGFjaXR5OiBjdXJyZW50Q2FwYWNpdHksXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBjdXJyZW50VHlwZSxcclxuICAgICAgICAgICAgICAgIGxvY2F0aW9uczogY3VycmVudExvY2F0aW9ucyxcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBjdXJyZW50TG9jYXRpb25zID0gW107XHJcbiAgICAgICAgICAgIGN1cnJlbnRUeXBlID0gbnVsbDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFwiU2tvbGFNaXN0b1Z5a29udUNpbm5vc3RpXCI6XHJcbiAgICAgICAgICAgIGlmIChpc1J1aWFuQ29kZU1pc3NpbmcpIHtcclxuICAgICAgICAgICAgICBzY2hvb2xzV2l0aG91dFJ1aWFuLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgaXpvOiBjdXJyZW50SXpvLFxyXG4gICAgICAgICAgICAgICAgYWRkcmVzczogY3VycmVudEFkZHJlc3MsXHJcbiAgICAgICAgICAgICAgICB0eXBlOiBjdXJyZW50VHlwZSxcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgXCJNaXN0b1JVQUlOS29kXCI6XHJcbiAgICAgICAgICAgIGlzUnVpYW5Db2RlTWlzc2luZyA9ICFpc1J1aWFuQ29kZVNldDtcclxuICAgICAgICAgIGNhc2UgXCJSZWRQbG55TmF6ZXZcIjpcclxuICAgICAgICAgIGNhc2UgXCJSZWRJem9cIjpcclxuICAgICAgICAgIGNhc2UgXCJJQ09cIjpcclxuICAgICAgICAgIGNhc2UgXCJJWk9cIjpcclxuICAgICAgICAgIGNhc2UgXCJTa29sYURydWhUeXBcIjpcclxuICAgICAgICAgIGNhc2UgXCJTa29sYUthcGFjaXRhXCI6XHJcbiAgICAgICAgICBjYXNlIFwiWnJpek5hemV2XCI6XHJcbiAgICAgICAgICBjYXNlIFwiWnJpeklDT1wiOlxyXG4gICAgICAgICAgY2FzZSBcIlpyaXpEYXR1bU5hcm96ZW5pXCI6XHJcbiAgICAgICAgICBjYXNlIFwiWnJpelByYXZuaUZvcm1hXCI6XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2ExXCI6XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2EyXCI6XHJcbiAgICAgICAgICBjYXNlIFwiTWlzdG9BZHJlc2EzXCI6XHJcbiAgICAgICAgICAgIHN0YXRlID0gWE1MU3RhdGUuTm9uZTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KVxyXG4gICAgICAub24oXCJ0ZXh0XCIsICh0ZXh0OiBzdHJpbmcpID0+IHtcclxuICAgICAgICBzd2l0Y2ggKHN0YXRlKSB7XHJcbiAgICAgICAgICBjYXNlIFhNTFN0YXRlLlJlZEl6bzpcclxuICAgICAgICAgICAgY3VycmVudFJlZGl6byA9IHRleHQ7XHJcbiAgICAgICAgICBjYXNlIFhNTFN0YXRlLlNjaG9vbE5hbWU6XHJcbiAgICAgICAgICAgIGN1cnJlbnROYW1lID0gdGV4dDtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFhNTFN0YXRlLkl6bzpcclxuICAgICAgICAgICAgY3VycmVudEl6byA9IHRleHQ7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBYTUxTdGF0ZS5JY286XHJcbiAgICAgICAgICAgIGN1cnJlbnRJY28gPSB0ZXh0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgWE1MU3RhdGUuU2Nob29sVHlwZTpcclxuICAgICAgICAgICAgaWYgKHRleHQgPT09IFNDSE9PTF9UWVBFX0tJTkRFUkdBUlRFTikge1xyXG4gICAgICAgICAgICAgIGN1cnJlbnRUeXBlID0gU2Nob29sVHlwZS5LaW5kZXJnYXJ0ZW47XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodGV4dCA9PT0gU0NIT09MX1RZUEVfRUxFTUVOVEFSWSkge1xyXG4gICAgICAgICAgICAgIGN1cnJlbnRUeXBlID0gU2Nob29sVHlwZS5FbGVtZW50YXJ5O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBYTUxTdGF0ZS5SdWlhbkNvZGU6XHJcbiAgICAgICAgICAgIGlzUnVpYW5Db2RlU2V0ID0gdHJ1ZTtcclxuICAgICAgICAgICAgY3VycmVudExvY2F0aW9ucy5wdXNoKHtcclxuICAgICAgICAgICAgICBhZGRyZXNzUG9pbnRJZDogcGFyc2VJbnQodGV4dCksXHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgWE1MU3RhdGUuQWRkcmVzczpcclxuICAgICAgICAgICAgY3VycmVudEFkZHJlc3MucHVzaCh0ZXh0KTtcclxuICAgICAgICAgICAgYnJlYWs7XHJcbiAgICAgICAgICBjYXNlIFhNTFN0YXRlLkZvdW5kZXJOYW1lOlxyXG4gICAgICAgICAgICBjdXJyZW50Rm91bmRlck5hbWUgPSB0ZXh0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgWE1MU3RhdGUuRm91bmRlckljbzpcclxuICAgICAgICAgICAgY3VycmVudEZvdW5kZXJJY28gPSB0ZXh0O1xyXG4gICAgICAgICAgICBicmVhaztcclxuICAgICAgICAgIGNhc2UgWE1MU3RhdGUuRm91bmRlclR5cGU6XHJcbiAgICAgICAgICAgIGN1cnJlbnRGb3VuZGVyVHlwZSA9IHRleHQ7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgICAgY2FzZSBYTUxTdGF0ZS5DYXBhY2l0eTpcclxuICAgICAgICAgICAgY3VycmVudENhcGFjaXR5ID0gcGFyc2VJbnQodGV4dCk7XHJcbiAgICAgICAgICAgIGJyZWFrO1xyXG4gICAgICAgIH1cclxuICAgICAgfSlcclxuICAgICAgLm9uKFwiZXJyb3JcIiwgcmVqZWN0KVxyXG4gICAgICAub24oXCJlbmRcIiwgcmVzb2x2ZSk7XHJcblxyXG4gICAgLy8gd2FudGVkIHRvIHVzZSAnYXdhaXQgcGlwZWxpbmUoY3JlYXRlUmVhZFN0cmVhbShnZXRYbWxGaWxlUGF0aChvcHRpb25zKSksIHNheFN0cmVhbSknXHJcbiAgICAvLyBidXQgdGhlIHByb2dyYW0gd291bGQgcXVpdCBzcG9udGFuZW91c2x5IGFmdGVyIGZpbmlzaGluZyBzdHJlYW0gLSB1c2luZyBQcm9taXNlIGluc3RlYWQuXHJcbiAgICBjcmVhdGVSZWFkU3RyZWFtKGdldFhtbEZpbGVQYXRoKG9wdGlvbnMpKS5waXBlKHNheFN0cmVhbSk7XHJcbiAgfSk7XHJcblxyXG4gIGF3YWl0IHN0cmVhbVByb21pc2U7XHJcblxyXG4gIHJldHVybiB7IHNjaG9vbHMsIGZvdW5kZXJzLCBzY2hvb2xzV2l0aG91dFJ1aWFuIH07XHJcbn07XHJcblxyXG5jb25zdCBpbXBvcnREYXRhVG9EYiA9IGFzeW5jIChcclxuICBvcHRpb25zOiBPcGVuRGF0YVN5bmNPcHRpb25zLFxyXG4gIHNhdmVGb3VuZGVyc1RvQ3N2OiBib29sZWFuID0gZmFsc2UsXHJcbiAgc2F2ZVNjaG9vbHNXaXRob3V0UnVpYW5Ub0NzdjogYm9vbGVhbiA9IGZhbHNlXHJcbikgPT4ge1xyXG4gIGNvbnN0IHsgc2Nob29scywgZm91bmRlcnMsIHNjaG9vbHNXaXRob3V0UnVpYW4gfSA9XHJcbiAgICBhd2FpdCBwcm9jZXNzU2Nob29sUmVnaXN0ZXJYbWwob3B0aW9ucyk7XHJcblxyXG4gIGlmIChzYXZlRm91bmRlcnNUb0Nzdikge1xyXG4gICAgY29uc3QgY3N2RmlsZSA9IFwiZm91bmRlcnMuY3N2XCI7XHJcblxyXG4gICAgaWYgKGV4aXN0c1N5bmMoY3N2RmlsZSkpIHtcclxuICAgICAgcm1TeW5jKGNzdkZpbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHZhciBjc3YgPSBjcmVhdGVXcml0ZVN0cmVhbShjc3ZGaWxlLCB7XHJcbiAgICAgIGZsYWdzOiBcImFcIixcclxuICAgIH0pO1xyXG4gICAgY3N2LndyaXRlKFwiScSMTztaxZlpem92YXRlbDtQcsOhdm7DrSBmb3JtYTtQb8SNZXQgxaFrb2w7xaBrb2x5XFxuXCIpO1xyXG4gICAgZm91bmRlcnMuZm9yRWFjaCgoZm91bmRlcikgPT4ge1xyXG4gICAgICBjc3Yud3JpdGUoXHJcbiAgICAgICAgYCMke2ZvdW5kZXIuaWNvfTske2ZvdW5kZXIubmFtZX07JHtmb3VuZGVyLm9yaWdpbmFsVHlwZX07JHtcclxuICAgICAgICAgIGZvdW5kZXIuc2Nob29scy5sZW5ndGhcclxuICAgICAgICB9OyR7Zm91bmRlci5zY2hvb2xzLm1hcCgoc2Nob29sKSA9PiBzY2hvb2wubmFtZSkuam9pbihcIi0tLVwiKX1cXG5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuICAgIGNzdi5lbmQoKTtcclxuICB9XHJcblxyXG4gIGlmIChzYXZlU2Nob29sc1dpdGhvdXRSdWlhblRvQ3N2KSB7XHJcbiAgICBjb25zdCBjc3ZGaWxlID0gXCJzY2hvb2xzV2l0aG91dFJ1aWFuLmNzdlwiO1xyXG5cclxuICAgIGlmIChleGlzdHNTeW5jKGNzdkZpbGUpKSB7XHJcbiAgICAgIHJtU3luYyhjc3ZGaWxlKTtcclxuICAgIH1cclxuXHJcbiAgICB2YXIgY3N2ID0gY3JlYXRlV3JpdGVTdHJlYW0oY3N2RmlsZSwge1xyXG4gICAgICBmbGFnczogXCJhXCIsXHJcbiAgICB9KTtcclxuICAgIGNzdi53cml0ZShcIklaTztKZSBtYXRlxZlza8OhO0plIHrDoWtsYWRuw607YWRyZXNhMTthZHJlc2EyO2FkcmVzYTNcXG5cIik7XHJcbiAgICBzY2hvb2xzV2l0aG91dFJ1aWFuLmZvckVhY2goKHNjaG9vbEFkZHJlc3MpID0+IHtcclxuICAgICAgY3N2LndyaXRlKFxyXG4gICAgICAgIGAjJHtzY2hvb2xBZGRyZXNzLml6b307JHtcclxuICAgICAgICAgIHNjaG9vbEFkZHJlc3MudHlwZSA9PT0gU2Nob29sVHlwZS5LaW5kZXJnYXJ0ZW4gPyBcIlRSVUVcIiA6IFwiRkFMU0VcIlxyXG4gICAgICAgIH07JHtcclxuICAgICAgICAgIHNjaG9vbEFkZHJlc3MudHlwZSA9PT0gU2Nob29sVHlwZS5FbGVtZW50YXJ5ID8gXCJUUlVFXCIgOiBcIkZBTFNFXCJcclxuICAgICAgICB9OyR7c2Nob29sQWRkcmVzcy5hZGRyZXNzLmpvaW4oXCI7XCIpfVxcbmBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG4gICAgY3N2LmVuZCgpO1xyXG4gIH1cclxuXHJcbiAgYXdhaXQgaW5zZXJ0U2Nob29scyhzY2hvb2xzKTtcclxuXHJcbiAgYXdhaXQgaW5zZXJ0Rm91bmRlcnMoQXJyYXkuZnJvbShmb3VuZGVycy52YWx1ZXMoKSkpO1xyXG59O1xyXG5cclxuY29uc3QgZ2V0WG1sRmlsZVBhdGggPSAob3B0aW9uczogT3BlbkRhdGFTeW5jT3B0aW9uc1BhcnRpYWwpOiBzdHJpbmcgPT4ge1xyXG4gIHJldHVybiBqb2luKG9wdGlvbnMudG1wRGlyLCBvcHRpb25zLnNjaG9vbHNYbWxGaWxlTmFtZSk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZG93bmxvYWRBbmRJbXBvcnRTY2hvb2xzID0gYXN5bmMgKFxyXG4gIG9wdGlvbnM6IE9wZW5EYXRhU3luY09wdGlvbnNQYXJ0aWFsID0ge30sXHJcbiAgc2F2ZUZvdW5kZXJzVG9Dc3Y6IGJvb2xlYW4gPSBmYWxzZSxcclxuICBzYXZlU2Nob29sc1dpdGhvdXRSdWlhblRvQ3N2OiBib29sZWFuID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgYXdhaXQgcnVuU3luY1BhcnQoU3luY1BhcnQuU2Nob29scywgW1N5bmNQYXJ0LkFkZHJlc3NQb2ludHNdLCBhc3luYyAoKSA9PiB7XHJcbiAgICBjb25zdCBydW5PcHRpb25zID0gcHJlcGFyZU9wdGlvbnMob3B0aW9ucyk7XHJcblxyXG4gICAgYXdhaXQgZG93bmxvYWRYbWwocnVuT3B0aW9ucyk7XHJcbiAgICBhd2FpdCBpbXBvcnREYXRhVG9EYihcclxuICAgICAgcnVuT3B0aW9ucyxcclxuICAgICAgc2F2ZUZvdW5kZXJzVG9Dc3YsXHJcbiAgICAgIHNhdmVTY2hvb2xzV2l0aG91dFJ1aWFuVG9Dc3ZcclxuICAgICk7XHJcbiAgICBkZWxldGVTY2hvb2xzWG1sRmlsZShydW5PcHRpb25zKTtcclxuICB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBkZWxldGVTY2hvb2xzWG1sRmlsZSA9IChcclxuICBvcHRpb25zOiBPcGVuRGF0YVN5bmNPcHRpb25zUGFydGlhbCA9IHt9XHJcbikgPT4ge1xyXG4gIGNvbnN0IHJ1bk9wdGlvbnMgPSBwcmVwYXJlT3B0aW9ucyhvcHRpb25zKTtcclxuXHJcbiAgaWYgKGV4aXN0c1N5bmMoZ2V0WG1sRmlsZVBhdGgocnVuT3B0aW9ucykpKSB7XHJcbiAgICBybVN5bmMoZ2V0WG1sRmlsZVBhdGgocnVuT3B0aW9ucykpO1xyXG4gIH1cclxufTtcclxuIl19