@tricoteuses/assemblee
Version:
Retrieve, clean up & handle French Assemblée nationale's open data
184 lines (183 loc) • 25.3 kB
JavaScript
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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