UNPKG

@tricoteuses/assemblee

Version:

Retrieve, clean up & handle French Assemblée nationale's open data

184 lines (183 loc) 25.3 kB
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; } function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; } function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } import Ajv from "ajv"; import commandLineArgs from "command-line-args"; import commandLineUsage from "command-line-usage"; import { load, getFiles } from "../file_systems.mjs"; import * as git from "../git.mjs"; import temp from "temp"; import fs from "fs-extra"; import path from "path"; import { validDataset, getDatasets, getSchemas, datasetDirectorySchema } from "../../src/datasets.mjs"; // Automatically track and cleanup files at exit temp.track(); function parseArgs(argv) { const optionsDefinitions = [{ description: "pathname to the directory containing the dataset", defaultOption: true, name: "data", type: String }, { description: "URL or path to the tricoteuses-assemblee git repository", defaultValue: "https://git.en-root.org/tricoteuses/tricoteuses-assemblee.git", name: "repository", type: String }, { description: `dataset (possible values must include exactly one of ${getDatasets()})`, name: "dataset", type: String }, { description: `schema (possible values are ${getSchemas()})`, name: "schema", type: String }, { description: "ignore schemaVersion from JSON files and use the current directory instead of the --repository", name: "dev", type: Boolean }, { description: "increase verbosity", name: "verbose", type: Boolean }, { name: "help", description: "Print this usage guide." }]; const sections = [{ header: "Validate JSON files", content: "Validate JSON files" }, { header: "Options", optionList: optionsDefinitions }]; const options = commandLineArgs(optionsDefinitions, { argv: argv }); if (options.dataset) { if (!validDataset(options.dataset)) { console.error(`--dataset ${options.dataset}`); options.help = true; } } if (options.schema) { if (!getSchemas().includes(options.schema)) { console.error(`--schema ${options.schema}`); options.help = true; } } if ("help" in options) { const usage = commandLineUsage(sections); console.warn(usage); return null; } return options; } class Validate { constructor(options) { _defineProperty(this, "options", void 0); _defineProperty(this, "version2schema", void 0); _defineProperty(this, "tmpDir", void 0); this.options = options; this.version2schema = {}; this.tmpDir = temp.mkdirSync("validation"); } getSchemaDir(tag) { if (this.options.dev == true) { if (this.options.verbose) console.log("--dev: use src/schemas"); return "src/schemas"; } const repositoryDir = path.join(this.tmpDir, "tricoteuses-assemblee"); const tagDir = path.join(this.tmpDir, tag); if (!fs.existsSync(tagDir)) { if (!fs.existsSync(repositoryDir)) { git.run(this.tmpDir, `clone --quiet ${this.options.repository} ${repositoryDir}`); } git.run(repositoryDir, `checkout tags/${tag} -- src/schemas > /dev/null 2>&1`); fs.renameSync(path.join(repositoryDir, "src/schemas"), tagDir); } return tagDir; } getValidator(version) { if (!(version in this.version2schema)) { const ajv = new Ajv(); const dir = this.getSchemaDir(`schema-${version}`); let references = []; for (const reference of getFiles([`${dir}/${this.options.schema}/*.json`])) references.push(reference); for (const file of getFiles(references)) { if (this.options.verbose) console.log(`reference: ${file}`); ajv.addSchema(load(file)); } const schema = this.options.schema; const Schema = schema.charAt(0).toUpperCase() + schema.slice(1); const s = `${dir}/${schema}/${Schema}.json`; if (this.options.verbose) console.log(`schema ${s}`); this.version2schema[version] = ajv.compile(load(s)); } return this.version2schema[version]; } getVersion(content) { if (content.schemaVersion != undefined) return content.schemaVersion; return `${this.options.schema}-1.0`; } getSchemaURL(version) { if (this.options.dev == true) return "src/schemas";else { if (fs.existsSync(this.options.repository)) { return `${this.options.repository}/src/schemas at tag schema-${version}`; } else { const repository = this.options.repository.replace(/\.git$/, ""); return `${repository}/tree/schema-${version}/src/schemas`; } } } validate(content, filename) { const tag = this.getVersion(content); const validator = this.getValidator(tag); const valid = validator(content); const schemaURL = this.getSchemaURL(tag); if (!valid) { console.error(`${schemaURL} finds ${filename} is invalid`); console.error(validator.errors); return 1; } else { if (this.options.verbose) console.log(`${schemaURL} finds ${filename} is valid`); return 0; } } async process() { let status = 0; for (const file of getFiles([this.options.data])) { const content = load(file); status |= this.validate(content, file); } return status; } } async function main(argv) { const options = parseArgs(argv); if (options === null) return 1; let directorySchema = []; if (options.schema) { directorySchema = [[options.data, options.schema]]; } else if (options.dataset) { directorySchema = datasetDirectorySchema(options.dataset); } else { console.error("either --schema or --dataset is required"); return 1; } for (const d of directorySchema) { options.schema = d[1]; options.data = d[0]; if (options.verbose) console.log(`working on files ${options.data} with schema ${options.schema}`); const validate = new Validate(options); const status = await validate.process(); if (status != 0) return status; } return 0; } /* istanbul ignore if */ if (process.argv[1].endsWith("validate_json.ts")) main(process.argv).then(exitCode => { process.exit(exitCode); }).catch(error => { console.error(error); process.exit(1); }); //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJBanYiLCJjb21tYW5kTGluZUFyZ3MiLCJjb21tYW5kTGluZVVzYWdlIiwibG9hZCIsImdldEZpbGVzIiwiZ2l0IiwidGVtcCIsImZzIiwicGF0aCIsInZhbGlkRGF0YXNldCIsImdldERhdGFzZXRzIiwiZ2V0U2NoZW1hcyIsImRhdGFzZXREaXJlY3RvcnlTY2hlbWEiLCJ0cmFjayIsInBhcnNlQXJncyIsImFyZ3YiLCJvcHRpb25zRGVmaW5pdGlvbnMiLCJkZXNjcmlwdGlvbiIsImRlZmF1bHRPcHRpb24iLCJuYW1lIiwidHlwZSIsIlN0cmluZyIsImRlZmF1bHRWYWx1ZSIsIkJvb2xlYW4iLCJzZWN0aW9ucyIsImhlYWRlciIsImNvbnRlbnQiLCJvcHRpb25MaXN0Iiwib3B0aW9ucyIsImRhdGFzZXQiLCJjb25zb2xlIiwiZXJyb3IiLCJoZWxwIiwic2NoZW1hIiwiaW5jbHVkZXMiLCJ1c2FnZSIsIndhcm4iLCJWYWxpZGF0ZSIsImNvbnN0cnVjdG9yIiwiX2RlZmluZVByb3BlcnR5IiwidmVyc2lvbjJzY2hlbWEiLCJ0bXBEaXIiLCJta2RpclN5bmMiLCJnZXRTY2hlbWFEaXIiLCJ0YWciLCJkZXYiLCJ2ZXJib3NlIiwibG9nIiwicmVwb3NpdG9yeURpciIsImpvaW4iLCJ0YWdEaXIiLCJleGlzdHNTeW5jIiwicnVuIiwicmVwb3NpdG9yeSIsInJlbmFtZVN5bmMiLCJnZXRWYWxpZGF0b3IiLCJ2ZXJzaW9uIiwiYWp2IiwiZGlyIiwicmVmZXJlbmNlcyIsInJlZmVyZW5jZSIsInB1c2giLCJmaWxlIiwiYWRkU2NoZW1hIiwiU2NoZW1hIiwiY2hhckF0IiwidG9VcHBlckNhc2UiLCJzbGljZSIsInMiLCJjb21waWxlIiwiZ2V0VmVyc2lvbiIsInNjaGVtYVZlcnNpb24iLCJ1bmRlZmluZWQiLCJnZXRTY2hlbWFVUkwiLCJyZXBsYWNlIiwidmFsaWRhdGUiLCJmaWxlbmFtZSIsInZhbGlkYXRvciIsInZhbGlkIiwic2NoZW1hVVJMIiwiZXJyb3JzIiwicHJvY2VzcyIsInN0YXR1cyIsImRhdGEiLCJtYWluIiwiZGlyZWN0b3J5U2NoZW1hIiwiZCIsImVuZHNXaXRoIiwidGhlbiIsImV4aXRDb2RlIiwiZXhpdCIsImNhdGNoIl0sInNvdXJjZXMiOlsiLi4vLi4vc3JjL3NjcmlwdHMvdmFsaWRhdGVfanNvbi50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQWp2IGZyb20gXCJhanZcIlxuaW1wb3J0IGNvbW1hbmRMaW5lQXJncyBmcm9tIFwiY29tbWFuZC1saW5lLWFyZ3NcIlxuaW1wb3J0IGNvbW1hbmRMaW5lVXNhZ2UgZnJvbSBcImNvbW1hbmQtbGluZS11c2FnZVwiXG5pbXBvcnQgeyBsb2FkLCBnZXRGaWxlcyB9IGZyb20gXCIuLi9maWxlX3N5c3RlbXNcIlxuaW1wb3J0ICogYXMgZ2l0IGZyb20gXCIuLi9naXRcIlxuaW1wb3J0IHRlbXAgZnJvbSBcInRlbXBcIlxuaW1wb3J0IGZzIGZyb20gXCJmcy1leHRyYVwiXG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiXG5pbXBvcnQge1xuICB2YWxpZERhdGFzZXQsXG4gIGdldERhdGFzZXRzLFxuICBnZXRTY2hlbWFzLFxuICBkYXRhc2V0RGlyZWN0b3J5U2NoZW1hLFxufSBmcm9tIFwiLi4vLi4vc3JjL2RhdGFzZXRzXCJcblxuLy8gQXV0b21hdGljYWxseSB0cmFjayBhbmQgY2xlYW51cCBmaWxlcyBhdCBleGl0XG50ZW1wLnRyYWNrKClcblxuZnVuY3Rpb24gcGFyc2VBcmdzKGFyZ3Y6IHN0cmluZ1tdKTogYW55IHtcbiAgY29uc3Qgb3B0aW9uc0RlZmluaXRpb25zID0gW1xuICAgIHtcbiAgICAgIGRlc2NyaXB0aW9uOiBcInBhdGhuYW1lIHRvIHRoZSBkaXJlY3RvcnkgY29udGFpbmluZyB0aGUgZGF0YXNldFwiLFxuICAgICAgZGVmYXVsdE9wdGlvbjogdHJ1ZSxcbiAgICAgIG5hbWU6IFwiZGF0YVwiLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0sXG4gICAge1xuICAgICAgZGVzY3JpcHRpb246IFwiVVJMIG9yIHBhdGggdG8gdGhlIHRyaWNvdGV1c2VzLWFzc2VtYmxlZSBnaXQgcmVwb3NpdG9yeVwiLFxuICAgICAgZGVmYXVsdFZhbHVlOlxuICAgICAgICBcImh0dHBzOi8vZ2l0LmVuLXJvb3Qub3JnL3RyaWNvdGV1c2VzL3RyaWNvdGV1c2VzLWFzc2VtYmxlZS5naXRcIixcbiAgICAgIG5hbWU6IFwicmVwb3NpdG9yeVwiLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0sXG4gICAge1xuICAgICAgZGVzY3JpcHRpb246IGBkYXRhc2V0IChwb3NzaWJsZSB2YWx1ZXMgbXVzdCBpbmNsdWRlIGV4YWN0bHkgb25lIG9mICR7Z2V0RGF0YXNldHMoKX0pYCxcbiAgICAgIG5hbWU6IFwiZGF0YXNldFwiLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0sXG4gICAge1xuICAgICAgZGVzY3JpcHRpb246IGBzY2hlbWEgKHBvc3NpYmxlIHZhbHVlcyBhcmUgJHtnZXRTY2hlbWFzKCl9KWAsXG4gICAgICBuYW1lOiBcInNjaGVtYVwiLFxuICAgICAgdHlwZTogU3RyaW5nLFxuICAgIH0sXG4gICAge1xuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgIFwiaWdub3JlIHNjaGVtYVZlcnNpb24gZnJvbSBKU09OIGZpbGVzIGFuZCB1c2UgdGhlIGN1cnJlbnQgZGlyZWN0b3J5IGluc3RlYWQgb2YgdGhlIC0tcmVwb3NpdG9yeVwiLFxuICAgICAgbmFtZTogXCJkZXZcIixcbiAgICAgIHR5cGU6IEJvb2xlYW4sXG4gICAgfSxcbiAgICB7XG4gICAgICBkZXNjcmlwdGlvbjogXCJpbmNyZWFzZSB2ZXJib3NpdHlcIixcbiAgICAgIG5hbWU6IFwidmVyYm9zZVwiLFxuICAgICAgdHlwZTogQm9vbGVhbixcbiAgICB9LFxuICAgIHtcbiAgICAgIG5hbWU6IFwiaGVscFwiLFxuICAgICAgZGVzY3JpcHRpb246IFwiUHJpbnQgdGhpcyB1c2FnZSBndWlkZS5cIixcbiAgICB9LFxuICBdXG4gIGNvbnN0IHNlY3Rpb25zID0gW1xuICAgIHtcbiAgICAgIGhlYWRlcjogXCJWYWxpZGF0ZSBKU09OIGZpbGVzXCIsXG4gICAgICBjb250ZW50OiBcIlZhbGlkYXRlIEpTT04gZmlsZXNcIixcbiAgICB9LFxuICAgIHtcbiAgICAgIGhlYWRlcjogXCJPcHRpb25zXCIsXG4gICAgICBvcHRpb25MaXN0OiBvcHRpb25zRGVmaW5pdGlvbnMsXG4gICAgfSxcbiAgXVxuICBjb25zdCBvcHRpb25zID0gY29tbWFuZExpbmVBcmdzKG9wdGlvbnNEZWZpbml0aW9ucywge1xuICAgIGFyZ3Y6IGFyZ3YsXG4gIH0pXG5cbiAgaWYgKG9wdGlvbnMuZGF0YXNldCkge1xuICAgIGlmICghdmFsaWREYXRhc2V0KG9wdGlvbnMuZGF0YXNldCkpIHtcbiAgICAgIGNvbnNvbGUuZXJyb3IoYC0tZGF0YXNldCAke29wdGlvbnMuZGF0YXNldH1gKVxuICAgICAgb3B0aW9ucy5oZWxwID0gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIGlmIChvcHRpb25zLnNjaGVtYSkge1xuICAgIGlmICghZ2V0U2NoZW1hcygpLmluY2x1ZGVzKG9wdGlvbnMuc2NoZW1hKSkge1xuICAgICAgY29uc29sZS5lcnJvcihgLS1zY2hlbWEgJHtvcHRpb25zLnNjaGVtYX1gKVxuICAgICAgb3B0aW9ucy5oZWxwID0gdHJ1ZVxuICAgIH1cbiAgfVxuXG4gIGlmIChcImhlbHBcIiBpbiBvcHRpb25zKSB7XG4gICAgY29uc3QgdXNhZ2UgPSBjb21tYW5kTGluZVVzYWdlKHNlY3Rpb25zKVxuICAgIGNvbnNvbGUud2Fybih1c2FnZSlcbiAgICByZXR1cm4gbnVsbFxuICB9XG4gIHJldHVybiBvcHRpb25zXG59XG5cbmNsYXNzIFZhbGlkYXRlIHtcbiAgb3B0aW9uczogYW55XG4gIHZlcnNpb24yc2NoZW1hOiBhbnlcbiAgdG1wRGlyOiBzdHJpbmdcblxuICBjb25zdHJ1Y3RvcihvcHRpb25zOiBhbnkpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zXG4gICAgdGhpcy52ZXJzaW9uMnNjaGVtYSA9IHt9XG4gICAgdGhpcy50bXBEaXIgPSB0ZW1wLm1rZGlyU3luYyhcInZhbGlkYXRpb25cIilcbiAgfVxuXG4gIGdldFNjaGVtYURpcih0YWc6IHN0cmluZykge1xuICAgIGlmICh0aGlzLm9wdGlvbnMuZGV2ID09IHRydWUpIHtcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudmVyYm9zZSkgY29uc29sZS5sb2coXCItLWRldjogdXNlIHNyYy9zY2hlbWFzXCIpXG4gICAgICByZXR1cm4gXCJzcmMvc2NoZW1hc1wiXG4gICAgfVxuICAgIGNvbnN0IHJlcG9zaXRvcnlEaXIgPSBwYXRoLmpvaW4odGhpcy50bXBEaXIsIFwidHJpY290ZXVzZXMtYXNzZW1ibGVlXCIpXG4gICAgY29uc3QgdGFnRGlyID0gcGF0aC5qb2luKHRoaXMudG1wRGlyLCB0YWcpXG4gICAgaWYgKCFmcy5leGlzdHNTeW5jKHRhZ0RpcikpIHtcbiAgICAgIGlmICghZnMuZXhpc3RzU3luYyhyZXBvc2l0b3J5RGlyKSkge1xuICAgICAgICBnaXQucnVuKFxuICAgICAgICAgIHRoaXMudG1wRGlyLFxuICAgICAgICAgIGBjbG9uZSAtLXF1aWV0ICR7dGhpcy5vcHRpb25zLnJlcG9zaXRvcnl9ICR7cmVwb3NpdG9yeURpcn1gLFxuICAgICAgICApXG4gICAgICB9XG4gICAgICBnaXQucnVuKFxuICAgICAgICByZXBvc2l0b3J5RGlyLFxuICAgICAgICBgY2hlY2tvdXQgdGFncy8ke3RhZ30gLS0gc3JjL3NjaGVtYXMgPiAvZGV2L251bGwgMj4mMWAsXG4gICAgICApXG4gICAgICBmcy5yZW5hbWVTeW5jKHBhdGguam9pbihyZXBvc2l0b3J5RGlyLCBcInNyYy9zY2hlbWFzXCIpLCB0YWdEaXIpXG4gICAgfVxuICAgIHJldHVybiB0YWdEaXJcbiAgfVxuXG4gIGdldFZhbGlkYXRvcih2ZXJzaW9uOiBzdHJpbmcpOiBhbnkge1xuICAgIGlmICghKHZlcnNpb24gaW4gdGhpcy52ZXJzaW9uMnNjaGVtYSkpIHtcbiAgICAgIGNvbnN0IGFqdiA9IG5ldyBBanYoKVxuICAgICAgY29uc3QgZGlyID0gdGhpcy5nZXRTY2hlbWFEaXIoYHNjaGVtYS0ke3ZlcnNpb259YClcbiAgICAgIGxldCByZWZlcmVuY2VzID0gW11cbiAgICAgIGZvciAoY29uc3QgcmVmZXJlbmNlIG9mIGdldEZpbGVzKFtcbiAgICAgICAgYCR7ZGlyfS8ke3RoaXMub3B0aW9ucy5zY2hlbWF9LyouanNvbmAsXG4gICAgICBdKSlcbiAgICAgICAgcmVmZXJlbmNlcy5wdXNoKHJlZmVyZW5jZSlcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiBnZXRGaWxlcyhyZWZlcmVuY2VzKSkge1xuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnZlcmJvc2UpIGNvbnNvbGUubG9nKGByZWZlcmVuY2U6ICR7ZmlsZX1gKVxuICAgICAgICBhanYuYWRkU2NoZW1hKGxvYWQoZmlsZSkpXG4gICAgICB9XG4gICAgICBjb25zdCBzY2hlbWEgPSB0aGlzLm9wdGlvbnMuc2NoZW1hXG4gICAgICBjb25zdCBTY2hlbWEgPSBzY2hlbWEuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyBzY2hlbWEuc2xpY2UoMSlcbiAgICAgIGNvbnN0IHMgPSBgJHtkaXJ9LyR7c2NoZW1hfS8ke1NjaGVtYX0uanNvbmBcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudmVyYm9zZSkgY29uc29sZS5sb2coYHNjaGVtYSAke3N9YClcbiAgICAgIHRoaXMudmVyc2lvbjJzY2hlbWFbdmVyc2lvbl0gPSBhanYuY29tcGlsZShsb2FkKHMpKVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy52ZXJzaW9uMnNjaGVtYVt2ZXJzaW9uXVxuICB9XG5cbiAgZ2V0VmVyc2lvbihjb250ZW50OiBhbnkpOiBzdHJpbmcge1xuICAgIGlmIChjb250ZW50LnNjaGVtYVZlcnNpb24gIT0gdW5kZWZpbmVkKSByZXR1cm4gY29udGVudC5zY2hlbWFWZXJzaW9uXG4gICAgcmV0dXJuIGAke3RoaXMub3B0aW9ucy5zY2hlbWF9LTEuMGBcbiAgfVxuXG4gIGdldFNjaGVtYVVSTCh2ZXJzaW9uOiBzdHJpbmcpOiBhbnkge1xuICAgIGlmICh0aGlzLm9wdGlvbnMuZGV2ID09IHRydWUpIHJldHVybiBcInNyYy9zY2hlbWFzXCJcbiAgICBlbHNlIHtcbiAgICAgIGlmIChmcy5leGlzdHNTeW5jKHRoaXMub3B0aW9ucy5yZXBvc2l0b3J5KSkge1xuICAgICAgICByZXR1cm4gYCR7dGhpcy5vcHRpb25zLnJlcG9zaXRvcnl9L3NyYy9zY2hlbWFzIGF0IHRhZyBzY2hlbWEtJHt2ZXJzaW9ufWBcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnN0IHJlcG9zaXRvcnkgPSB0aGlzLm9wdGlvbnMucmVwb3NpdG9yeS5yZXBsYWNlKC9cXC5naXQkLywgXCJcIilcbiAgICAgICAgcmV0dXJuIGAke3JlcG9zaXRvcnl9L3RyZWUvc2NoZW1hLSR7dmVyc2lvbn0vc3JjL3NjaGVtYXNgXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgdmFsaWRhdGUoY29udGVudDogYW55LCBmaWxlbmFtZTogc3RyaW5nKTogbnVtYmVyIHtcbiAgICBjb25zdCB0YWcgPSB0aGlzLmdldFZlcnNpb24oY29udGVudClcbiAgICBjb25zdCB2YWxpZGF0b3IgPSB0aGlzLmdldFZhbGlkYXRvcih0YWcpXG4gICAgY29uc3QgdmFsaWQgPSB2YWxpZGF0b3IoY29udGVudClcbiAgICBjb25zdCBzY2hlbWFVUkwgPSB0aGlzLmdldFNjaGVtYVVSTCh0YWcpXG4gICAgaWYgKCF2YWxpZCkge1xuICAgICAgY29uc29sZS5lcnJvcihgJHtzY2hlbWFVUkx9IGZpbmRzICR7ZmlsZW5hbWV9IGlzIGludmFsaWRgKVxuICAgICAgY29uc29sZS5lcnJvcih2YWxpZGF0b3IuZXJyb3JzKVxuICAgICAgcmV0dXJuIDFcbiAgICB9IGVsc2Uge1xuICAgICAgaWYgKHRoaXMub3B0aW9ucy52ZXJib3NlKVxuICAgICAgICBjb25zb2xlLmxvZyhgJHtzY2hlbWFVUkx9IGZpbmRzICR7ZmlsZW5hbWV9IGlzIHZhbGlkYClcbiAgICAgIHJldHVybiAwXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgcHJvY2VzcygpOiBQcm9taXNlPG51bWJlcj4ge1xuICAgIGxldCBzdGF0dXMgPSAwXG4gICAgZm9yIChjb25zdCBmaWxlIG9mIGdldEZpbGVzKFt0aGlzLm9wdGlvbnMuZGF0YV0pKSB7XG4gICAgICBjb25zdCBjb250ZW50ID0gbG9hZChmaWxlKVxuICAgICAgc3RhdHVzIHw9IHRoaXMudmFsaWRhdGUoY29udGVudCwgZmlsZSlcbiAgICB9XG4gICAgcmV0dXJuIHN0YXR1c1xuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIG1haW4oYXJndjogYW55KTogUHJvbWlzZTxudW1iZXI+IHtcbiAgY29uc3Qgb3B0aW9ucyA9IHBhcnNlQXJncyhhcmd2KVxuICBpZiAob3B0aW9ucyA9PT0gbnVsbCkgcmV0dXJuIDFcbiAgbGV0IGRpcmVjdG9yeVNjaGVtYSA9IFtdXG4gIGlmIChvcHRpb25zLnNjaGVtYSkge1xuICAgIGRpcmVjdG9yeVNjaGVtYSA9IFtbb3B0aW9ucy5kYXRhLCBvcHRpb25zLnNjaGVtYV1dXG4gIH0gZWxzZSBpZiAob3B0aW9ucy5kYXRhc2V0KSB7XG4gICAgZGlyZWN0b3J5U2NoZW1hID0gZGF0YXNldERpcmVjdG9yeVNjaGVtYShvcHRpb25zLmRhdGFzZXQpXG4gIH0gZWxzZSB7XG4gICAgY29uc29sZS5lcnJvcihcImVpdGhlciAtLXNjaGVtYSBvciAtLWRhdGFzZXQgaXMgcmVxdWlyZWRcIilcbiAgICByZXR1cm4gMVxuICB9XG4gIGZvciAoY29uc3QgZCBvZiBkaXJlY3RvcnlTY2hlbWEpIHtcbiAgICBvcHRpb25zLnNjaGVtYSA9IGRbMV1cbiAgICBvcHRpb25zLmRhdGEgPSBkWzBdXG4gICAgaWYgKG9wdGlvbnMudmVyYm9zZSlcbiAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICBgd29ya2luZyBvbiBmaWxlcyAke29wdGlvbnMuZGF0YX0gd2l0aCBzY2hlbWEgJHtvcHRpb25zLnNjaGVtYX1gLFxuICAgICAgKVxuICAgIGNvbnN0IHZhbGlkYXRlID0gbmV3IFZhbGlkYXRlKG9wdGlvbnMpXG4gICAgY29uc3Qgc3RhdHVzID0gYXdhaXQgdmFsaWRhdGUucHJvY2VzcygpXG4gICAgaWYgKHN0YXR1cyAhPSAwKSByZXR1cm4gc3RhdHVzXG4gIH1cbiAgcmV0dXJuIDBcbn1cblxuLyogaXN0YW5idWwgaWdub3JlIGlmICovXG5pZiAocHJvY2Vzcy5hcmd2WzFdLmVuZHNXaXRoKFwidmFsaWRhdGVfanNvbi50c1wiKSlcbiAgbWFpbihwcm9jZXNzLmFyZ3YpXG4gICAgLnRoZW4oKGV4aXRDb2RlKSA9PiB7XG4gICAgICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpXG4gICAgfSlcbiAgICAuY2F0Y2goKGVycm9yKSA9PiB7XG4gICAgICBjb25zb2xlLmVycm9yKGVycm9yKVxuICAgICAgcHJvY2Vzcy5leGl0KDEpXG4gICAgfSlcbiJdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsT0FBT0EsR0FBRyxNQUFNLEtBQUs7QUFDckIsT0FBT0MsZUFBZSxNQUFNLG1CQUFtQjtBQUMvQyxPQUFPQyxnQkFBZ0IsTUFBTSxvQkFBb0I7QUFBQSxTQUN4Q0MsSUFBSSxFQUFFQyxRQUFRO0FBQUEsT0FDaEIsS0FBS0MsR0FBRztBQUNmLE9BQU9DLElBQUksTUFBTSxNQUFNO0FBQ3ZCLE9BQU9DLEVBQUUsTUFBTSxVQUFVO0FBQ3pCLE9BQU9DLElBQUksTUFBTSxNQUFNO0FBQUEsU0FFckJDLFlBQVksRUFDWkMsV0FBVyxFQUNYQyxVQUFVLEVBQ1ZDLHNCQUFzQixrQ0FHeEI7QUFDQU4sSUFBSSxDQUFDTyxLQUFLLENBQUMsQ0FBQztBQUVaLFNBQVNDLFNBQVNBLENBQUNDLElBQWMsRUFBTztFQUN0QyxNQUFNQyxrQkFBa0IsR0FBRyxDQUN6QjtJQUNFQyxXQUFXLEVBQUUsa0RBQWtEO0lBQy9EQyxhQUFhLEVBQUUsSUFBSTtJQUNuQkMsSUFBSSxFQUFFLE1BQU07SUFDWkMsSUFBSSxFQUFFQztFQUNSLENB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