@dpkit/table
Version:
Data Package implementation in TypeScript.
157 lines • 21.8 kB
JavaScript
import { col, lit } from "nodejs-polars";
import { matchField } from "../field/index.js";
import { validateField } from "../field/index.js";
import { validateRows } from "../row/index.js";
import { getPolarsSchema } from "../schema/index.js";
import { normalizeFields } from "./normalize.js";
export async function validateTable(table, options) {
const { schema, sampleRows = 100, invalidRowsLimit = 100 } = options ?? {};
const errors = [];
if (schema) {
const sample = await table.head(sampleRows).collect();
const polarsSchema = getPolarsSchema(sample.schema);
const matchErrors = validateFieldsMatch({ schema, polarsSchema });
errors.push(...matchErrors);
const fieldErrors = await validateFields(table, schema, polarsSchema, invalidRowsLimit);
errors.push(...fieldErrors);
}
return { errors, valid: !errors.length };
}
function validateFieldsMatch(props) {
const { schema, polarsSchema } = props;
const errors = [];
const fieldsMatch = schema.fieldsMatch ?? "exact";
const fields = schema.fields;
const polarsFields = polarsSchema.fields;
const names = fields.map(field => field.name);
const polarsNames = polarsFields.map(field => field.name);
const requiredNames = fields
.filter(field => field.constraints?.required)
.map(field => field.name);
const extraFields = polarsFields.length - fields.length;
const missingFields = fields.length - polarsFields.length;
const extraNames = arrayDiff(polarsNames, names);
const missingNames = arrayDiff(names, polarsNames);
const missingRequiredNames = arrayDiff(requiredNames, polarsNames);
if (fieldsMatch === "exact") {
if (extraFields > 0) {
errors.push({
type: "fields/extra",
fieldNames: extraNames,
});
}
if (missingFields > 0) {
errors.push({
type: "fields/missing",
fieldNames: missingNames,
});
}
}
if (fieldsMatch === "equal") {
if (extraNames.length > 0) {
errors.push({
type: "fields/extra",
fieldNames: extraNames,
});
}
if (missingRequiredNames.length > 0) {
errors.push({
type: "fields/missing",
fieldNames: missingRequiredNames,
});
}
}
if (fieldsMatch === "subset") {
if (missingRequiredNames.length > 0) {
errors.push({
type: "fields/missing",
fieldNames: missingRequiredNames,
});
}
}
if (fieldsMatch === "superset") {
if (extraNames.length > 0) {
errors.push({
type: "fields/extra",
fieldNames: extraNames,
});
}
}
if (fieldsMatch === "partial") {
if (missingNames.length === fields.length) {
errors.push({
type: "fields/missing",
fieldNames: missingNames,
});
}
}
return errors;
}
async function validateFields(table, schema, polarsSchema, invalidRowsLimit) {
const errors = [];
const targetNames = [];
const sources = Object.entries(normalizeFields(schema, polarsSchema, { dontParse: true })).map(([name, expr]) => {
return expr.alias(`source:${name}`);
});
const targets = Object.entries(normalizeFields(schema, polarsSchema, { dontParse: false })).map(([name, expr]) => {
const targetName = `target:${name}`;
targetNames.push(targetName);
return expr.alias(targetName);
});
let errorTable = table
.withRowCount()
.select(col("row_nr").add(1), lit(false).alias("error"), ...sources, ...targets);
for (const [index, field] of schema.fields.entries()) {
const polarsField = matchField(index, field, schema, polarsSchema);
if (polarsField) {
const fieldResult = validateField(field, { errorTable, polarsField });
errorTable = fieldResult.errorTable;
errors.push(...fieldResult.errors);
}
}
const rowsResult = validateRows(schema, errorTable);
errorTable = rowsResult.errorTable;
errors.push(...rowsResult.errors);
const errorFrame = await errorTable
.filter(col("error").eq(true))
.head(invalidRowsLimit)
.drop(targetNames)
.collect();
for (const record of errorFrame.toRecords()) {
const typeErrorInFields = [];
for (const [key, value] of Object.entries(record)) {
const [kind, type, name] = key.split(":");
if (kind === "error" && value === true && type && name) {
const rowNumber = record.row_nr;
// Cell-level errors
if (type.startsWith("cell/")) {
if (!typeErrorInFields.includes(name)) {
errors.push({
rowNumber,
type: type,
fieldName: name,
cell: (record[`source:${name}`] ?? "").toString(),
});
}
// Type error is a terminating error for a cell
if (type === "cell/type") {
typeErrorInFields.push(name);
}
}
// Row-level errors
if (type.startsWith("row/")) {
errors.push({
rowNumber,
type: type,
fieldNames: name.split(","),
});
}
}
}
}
return errors;
}
function arrayDiff(a, b) {
return a.filter(x => !b.includes(x));
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi90YWJsZS92YWxpZGF0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsR0FBRyxFQUFFLEdBQUcsRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUV4QyxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sbUJBQW1CLENBQUE7QUFDOUMsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFBO0FBQ2pELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUM5QyxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sb0JBQW9CLENBQUE7QUFHcEQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLGdCQUFnQixDQUFBO0FBRWhELE1BQU0sQ0FBQyxLQUFLLFVBQVUsYUFBYSxDQUNqQyxLQUFZLEVBQ1osT0FJQztJQUVELE1BQU0sRUFBRSxNQUFNLEVBQUUsVUFBVSxHQUFHLEdBQUcsRUFBRSxnQkFBZ0IsR0FBRyxHQUFHLEVBQUUsR0FBRyxPQUFPLElBQUksRUFBRSxDQUFBO0lBQzFFLE1BQU0sTUFBTSxHQUFpQixFQUFFLENBQUE7SUFFL0IsSUFBSSxNQUFNLEVBQUUsQ0FBQztRQUNYLE1BQU0sTUFBTSxHQUFHLE1BQU0sS0FBSyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQTtRQUNyRCxNQUFNLFlBQVksR0FBRyxlQUFlLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxDQUFBO1FBRW5ELE1BQU0sV0FBVyxHQUFHLG1CQUFtQixDQUFDLEVBQUUsTUFBTSxFQUFFLFlBQVksRUFBRSxDQUFDLENBQUE7UUFDakUsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLFdBQVcsQ0FBQyxDQUFBO1FBRTNCLE1BQU0sV0FBVyxHQUFHLE1BQU0sY0FBYyxDQUN0QyxLQUFLLEVBQ0wsTUFBTSxFQUNOLFlBQVksRUFDWixnQkFBZ0IsQ0FD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Q0osQ0FBQztvQkFFRCwrQ0FBK0M7b0JBQy9DLElBQUksSUFBSSxLQUFLLFdBQVcsRUFBRSxDQUFDO3dCQUN6QixpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUE7b0JBQzlCLENBQUM7Z0JBQ0gsQ0FBQztnQkFFRCxtQkFBbUI7Z0JBQ25CLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxNQUFNLENBQUMsRUFBRSxDQUFDO29CQUM1QixNQUFNLENBQUMsSUFBSSxDQUFDO3dCQUNWLFNBQVM7d0JBQ1QsSUFBSSxFQUFFLElBQVc7d0JBQ2pCLFVBQVUsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQztxQkFDNUIsQ0FBQyxDQUFBO2dCQUNKLENBQUM7WUFDSCxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFFRCxPQUFPLE1BQU0sQ0FBQTtBQUNmLENBQUM7QUFFRCxTQUFTLFNBQVMsQ0FBQyxDQUFXLEVBQUUsQ0FBVztJQUN6QyxPQUFPLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtBQUN0QyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHR5cGUgeyBTY2hlbWEgfSBmcm9tIFwiQGRwa2l0L2NvcmVcIlxuaW1wb3J0IHsgY29sLCBsaXQgfSBmcm9tIFwibm9kZWpzLXBvbGFyc1wiXG5pbXBvcnQgdHlwZSB7IFRhYmxlRXJyb3IgfSBmcm9tIFwiLi4vZXJyb3IvaW5kZXgudHNcIlxuaW1wb3J0IHsgbWF0Y2hGaWVsZCB9IGZyb20gXCIuLi9maWVsZC9pbmRleC50c1wiXG5pbXBvcnQgeyB2YWxpZGF0ZUZpZWxkIH0gZnJvbSBcIi4uL2ZpZWxkL2luZGV4LnRzXCJcbmltcG9ydCB7IHZhbGlkYXRlUm93cyB9IGZyb20gXCIuLi9yb3cvaW5kZXgudHNcIlxuaW1wb3J0IHsgZ2V0UG9sYXJzU2NoZW1hIH0gZnJvbSBcIi4uL3NjaGVtYS9pbmRleC50c1wiXG5pbXBvcnQgdHlwZSB7IFBvbGFyc1NjaGVtYSB9IGZyb20gXCIuLi9zY2hlbWEvaW5kZXgudHNcIlxuaW1wb3J0IHR5cGUgeyBUYWJsZSB9IGZyb20gXCIuL1RhYmxlLnRzXCJcbmltcG9ydCB7IG5vcm1hbGl6ZUZpZWxkcyB9IGZyb20gXCIuL25vcm1hbGl6ZS50c1wiXG5cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB2YWxpZGF0ZVRhYmxlKFxuICB0YWJsZTogVGFibGUsXG4gIG9wdGlvbnM/OiB7XG4gICAgc2NoZW1hPzogU2NoZW1hXG4gICAgc2FtcGxlUm93cz86IG51bWJlclxuICAgIGludmFsaWRSb3dzTGltaXQ/OiBudW1iZXJcbiAgfSxcbikge1xuICBjb25zdCB7IHNjaGVtYSwgc2FtcGxlUm93cyA9IDEwMCwgaW52YWxpZFJvd3NMaW1pdCA9IDEwMCB9ID0gb3B0aW9ucyA/PyB7fVxuICBjb25zdCBlcnJvcnM6IFRhYmxlRXJyb3JbXSA9IFtdXG5cbiAgaWYgKHNjaGVtYSkge1xuICAgIGNvbnN0IHNhbXBsZSA9IGF3YWl0IHRhYmxlLmhlYWQoc2FtcGxlUm93cykuY29sbGVjdCgpXG4gICAgY29uc3QgcG9sYXJzU2NoZW1hID0gZ2V0UG9sYXJzU2NoZW1hKHNhbXBsZS5zY2hlbWEpXG5cbiAgICBjb25zdCBtYXRjaEVycm9ycyA9IHZhbGlkYXRlRmllbGRzTWF0Y2goeyBzY2hlbWEsIHBvbGFyc1NjaGVtYSB9KVxuICAgIGVycm9ycy5wdXNoKC4uLm1hdGNoRXJyb3JzKVxuXG4gICAgY29uc3QgZmllbGRFcnJvcnMgPSBhd2FpdCB2YWxpZGF0ZUZpZWxkcyhcbiAgICAgIHRhYmxlLFxuICAgICAgc2NoZW1hLFxuICAgICAgcG9sYXJzU2NoZW1hLFxuICAgICAgaW52YWxpZFJvd3NMaW1pdCxcbiAgICApXG4gICAgZXJyb3JzLnB1c2goLi4uZmllbGRFcnJvcnMpXG4gIH1cblxuICByZXR1cm4geyBlcnJvcnMsIHZhbGlkOiAhZXJyb3JzLmxlbmd0aCB9XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlRmllbGRzTWF0Y2gocHJvcHM6IHtcbiAgc2NoZW1hOiBTY2hlbWFcbiAgcG9sYXJzU2NoZW1hOiBQb2xhcnNTY2hlbWFcbn0pIHtcbiAgY29uc3QgeyBzY2hlbWEsIHBvbGFyc1NjaGVtYSB9ID0gcHJvcHNcblxuICBjb25zdCBlcnJvcnM6IFRhYmxlRXJyb3JbXSA9IFtdXG4gIGNvbnN0IGZpZWxkc01hdGNoID0gc2NoZW1hLmZpZWxkc01hdGNoID8/IFwiZXhhY3RcIlxuXG4gIGNvbnN0IGZpZWxkcyA9IHNjaGVtYS5maWVsZHNcbiAgY29uc3QgcG9sYXJzRmllbGRzID0gcG9sYXJzU2NoZW1hLmZpZWxkc1xuXG4gIGNvbnN0IG5hbWVzID0gZmllbGRzLm1hcChmaWVsZCA9PiBmaWVsZC5uYW1lKVxuICBjb25zdCBwb2xhcnNOYW1lcyA9IHBvbGFyc0ZpZWxkcy5tYXAoZmllbGQgPT4gZmllbGQubmFtZSlcblxuICBjb25zdCByZXF1aXJlZE5hbWVzID0gZmllbGRzXG4gICAgLmZpbHRlcihmaWVsZCA9PiBmaWVsZC5jb25zdHJhaW50cz8ucmVxdWlyZWQpXG4gICAgLm1hcChmaWVsZCA9PiBmaWVsZC5uYW1lKVxuXG4gIGNvbnN0IGV4dHJhRmllbGRzID0gcG9sYXJzRmllbGRzLmxlbmd0aCAtIGZpZWxkcy5sZW5ndGhcbiAgY29uc3QgbWlzc2luZ0ZpZWxkcyA9IGZpZWxkcy5sZW5ndGggLSBwb2xhcnNGaWVsZHMubGVuZ3RoXG5cbiAgY29uc3QgZXh0cmFOYW1lcyA9IGFycmF5RGlmZihwb2xhcnNOYW1lcywgbmFtZXMpXG4gIGNvbnN0IG1pc3NpbmdOYW1lcyA9IGFycmF5RGlmZihuYW1lcywgcG9sYXJzTmFtZXMpXG4gIGNvbnN0IG1pc3NpbmdSZXF1aXJlZE5hbWVzID0gYXJyYXlEaWZmKHJlcXVpcmVkTmFtZXMsIHBvbGFyc05hbWVzKVxuXG4gIGlmIChmaWVsZHNNYXRjaCA9PT0gXCJleGFjdFwiKSB7XG4gICAgaWYgKGV4dHJhRmllbGRzID4gMCkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICB0eXBlOiBcImZpZWxkcy9leHRyYVwiLFxuICAgICAgICBmaWVsZE5hbWVzOiBleHRyYU5hbWVzLFxuICAgICAgfSlcbiAgICB9XG5cbiAgICBpZiAobWlzc2luZ0ZpZWxkcyA+IDApIHtcbiAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgdHlwZTogXCJmaWVsZHMvbWlzc2luZ1wiLFxuICAgICAgICBmaWVsZE5hbWVzOiBtaXNzaW5nTmFtZXMsXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG4gIGlmIChmaWVsZHNNYXRjaCA9PT0gXCJlcXVhbFwiKSB7XG4gICAgaWYgKGV4dHJhTmFtZXMubGVuZ3RoID4gMCkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICB0eXBlOiBcImZpZWxkcy9leHRyYVwiLFxuICAgICAgICBmaWVsZE5hbWVzOiBleHRyYU5hbWVzLFxuICAgICAgfSlcbiAgICB9XG5cbiAgICBpZiAobWlzc2luZ1JlcXVpcmVkTmFtZXMubGVuZ3RoID4gMCkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICB0eXBlOiBcImZpZWxkcy9taXNzaW5nXCIsXG4gICAgICAgIGZpZWxkTmFtZXM6IG1pc3NpbmdSZXF1aXJlZE5hbWVzLFxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBpZiAoZmllbGRzTWF0Y2ggPT09IFwic3Vic2V0XCIpIHtcbiAgICBpZiAobWlzc2luZ1JlcXVpcmVkTmFtZXMubGVuZ3RoID4gMCkge1xuICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICB0eXBlOiBcImZpZWxkcy9taXNzaW5nXCIsXG4gICAgICAgIGZpZWxkTmFtZXM6IG1pc3NpbmdSZXF1aXJlZE5hbWVzLFxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBpZiAoZmllbGRzTWF0Y2ggPT09IFwic3VwZXJzZXRcIikge1xuICAgIGlmIChleHRyYU5hbWVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGVycm9ycy5wdXNoKHtcbiAgICAgICAgdHlwZTogXCJmaWVsZHMvZXh0cmFcIixcbiAgICAgICAgZmllbGROYW1lczogZXh0cmFOYW1lcyxcbiAgICAgIH0pXG4gICAgfVxuICB9XG5cbiAgaWYgKGZpZWxkc01hdGNoID09PSBcInBhcnRpYWxcIikge1xuICAgIGlmIChtaXNzaW5nTmFtZXMubGVuZ3RoID09PSBmaWVsZHMubGVuZ3RoKSB7XG4gICAgICBlcnJvcnMucHVzaCh7XG4gICAgICAgIHR5cGU6IFwiZmllbGRzL21pc3NpbmdcIixcbiAgICAgICAgZmllbGROYW1lczogbWlzc2luZ05hbWVzLFxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICByZXR1cm4gZXJyb3JzXG59XG5cbmFzeW5jIGZ1bmN0aW9uIHZhbGlkYXRlRmllbGRzKFxuICB0YWJsZTogVGFibGUsXG4gIHNjaGVtYTogU2NoZW1hLFxuICBwb2xhcnNTY2hlbWE6IFBvbGFyc1NjaGVtYSxcbiAgaW52YWxpZFJvd3NMaW1pdDogbnVtYmVyLFxuKSB7XG4gIGNvbnN0IGVycm9yczogVGFibGVFcnJvcltdID0gW11cbiAgY29uc3QgdGFyZ2V0TmFtZXM6IHN0cmluZ1tdID0gW11cblxuICBjb25zdCBzb3VyY2VzID0gT2JqZWN0LmVudHJpZXMoXG4gICAgbm9ybWFsaXplRmllbGRzKHNjaGVtYSwgcG9sYXJzU2NoZW1hLCB7IGRvbnRQYXJzZTogdHJ1ZSB9KSxcbiAgKS5tYXAoKFtuYW1lLCBleHByXSkgPT4ge1xuICAgIHJldHVybiBleHByLmFsaWFzKGBzb3VyY2U6JHtuYW1lfWApXG4gIH0pXG5cbiAgY29uc3QgdGFyZ2V0cyA9IE9iamVjdC5lbnRyaWVzKFxuICAgIG5vcm1hbGl6ZUZpZWxkcyhzY2hlbWEsIHBvbGFyc1NjaGVtYSwgeyBkb250UGFyc2U6IGZhbHNlIH0pLFxuICApLm1hcCgoW25hbWUsIGV4cHJdKSA9PiB7XG4gICAgY29uc3QgdGFyZ2V0TmFtZSA9IGB0YXJnZXQ6JHtuYW1lfWBcbiAgICB0YXJnZXROYW1lcy5wdXNoKHRhcmdldE5hbWUpXG4gICAgcmV0dXJuIGV4cHIuYWxpYXModGFyZ2V0TmFtZSlcbiAgfSlcblxuICBsZXQgZXJyb3JUYWJsZSA9IHRhYmxlXG4gICAgLndpdGhSb3dDb3VudCgpXG4gICAgLnNlbGVjdChcbiAgICAgIGNvbChcInJvd19uclwiKS5hZGQoMSksXG4gICAgICBsaXQoZmFsc2UpLmFsaWFzKFwiZXJyb3JcIiksXG4gICAgICAuLi5zb3VyY2VzLFxuICAgICAgLi4udGFyZ2V0cyxcbiAgICApXG5cbiAgZm9yIChjb25zdCBbaW5kZXgsIGZpZWxkXSBvZiBzY2hlbWEuZmllbGRzLmVudHJpZXMoKSkge1xuICAgIGNvbnN0IHBvbGFyc0ZpZWxkID0gbWF0Y2hGaWVsZChpbmRleCwgZmllbGQsIHNjaGVtYSwgcG9sYXJzU2NoZW1hKVxuICAgIGlmIChwb2xhcnNGaWVsZCkge1xuICAgICAgY29uc3QgZmllbGRSZXN1bHQgPSB2YWxpZGF0ZUZpZWxkKGZpZWxkLCB7IGVycm9yVGFibGUsIHBvbGFyc0ZpZWxkIH0pXG4gICAgICBlcnJvclRhYmxlID0gZmllbGRSZXN1bHQuZXJyb3JUYWJsZVxuICAgICAgZXJyb3JzLnB1c2goLi4uZmllbGRSZXN1bHQuZXJyb3JzKVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IHJvd3NSZXN1bHQgPSB2YWxpZGF0ZVJvd3Moc2NoZW1hLCBlcnJvclRhYmxlKVxuICBlcnJvclRhYmxlID0gcm93c1Jlc3VsdC5lcnJvclRhYmxlXG4gIGVycm9ycy5wdXNoKC4uLnJvd3NSZXN1bHQuZXJyb3JzKVxuXG4gIGNvbnN0IGVycm9yRnJhbWUgPSBhd2FpdCBlcnJvclRhYmxlXG4gICAgLmZpbHRlcihjb2woXCJlcnJvclwiKS5lcSh0cnVlKSlcbiAgICAuaGVhZChpbnZhbGlkUm93c0xpbWl0KVxuICAgIC5kcm9wKHRhcmdldE5hbWVzKVxuICAgIC5jb2xsZWN0KClcblxuICBmb3IgKGNvbnN0IHJlY29yZCBvZiBlcnJvckZyYW1lLnRvUmVjb3JkcygpIGFzIGFueVtdKSB7XG4gICAgY29uc3QgdHlwZUVycm9ySW5GaWVsZHM6IHN0cmluZ1tdID0gW11cbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhyZWNvcmQpKSB7XG4gICAgICBjb25zdCBba2luZCwgdHlwZSwgbmFtZV0gPSBrZXkuc3BsaXQoXCI6XCIpXG4gICAgICBpZiAoa2luZCA9PT0gXCJlcnJvclwiICYmIHZhbHVlID09PSB0cnVlICYmIHR5cGUgJiYgbmFtZSkge1xuICAgICAgICBjb25zdCByb3dOdW1iZXIgPSByZWNvcmQucm93X25yXG5cbiAgICAgICAgLy8gQ2VsbC1sZXZlbCBlcnJvcnNcbiAgICAgICAgaWYgKHR5cGUuc3RhcnRzV2l0aChcImNlbGwvXCIpKSB7XG4gICAgICAgICAgaWYgKCF0eXBlRXJyb3JJbkZpZWxkcy5pbmNsdWRlcyhuYW1lKSkge1xuICAgICAgICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICAgICAgICByb3dOdW1iZXIsXG4gICAgICAgICAgICAgIHR5cGU6IHR5cGUgYXMgYW55LFxuICAgICAgICAgICAgICBmaWVsZE5hbWU6IG5hbWUgYXMgYW55LFxuICAgICAgICAgICAgICBjZWxsOiAocmVjb3JkW2Bzb3VyY2U6JHtuYW1lfWBdID8/IFwiXCIpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFR5cGUgZXJyb3IgaXMgYSB0ZXJtaW5hdGluZyBlcnJvciBmb3IgYSBjZWxsXG4gICAgICAgICAgaWYgKHR5cGUgPT09IFwiY2VsbC90eXBlXCIpIHtcbiAgICAgICAgICAgIHR5cGVFcnJvckluRmllbGRzLnB1c2gobmFtZSlcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBSb3ctbGV2ZWwgZXJyb3JzXG4gICAgICAgIGlmICh0eXBlLnN0YXJ0c1dpdGgoXCJyb3cvXCIpKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goe1xuICAgICAgICAgICAgcm93TnVtYmVyLFxuICAgICAgICAgICAgdHlwZTogdHlwZSBhcyBhbnksXG4gICAgICAgICAgICBmaWVsZE5hbWVzOiBuYW1lLnNwbGl0KFwiLFwiKSxcbiAgICAgICAgICB9KVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGVycm9yc1xufVxuXG5mdW5jdGlvbiBhcnJheURpZmYoYTogc3RyaW5nW10sIGI6IHN0cmluZ1tdKSB7XG4gIHJldHVybiBhLmZpbHRlcih4ID0+ICFiLmluY2x1ZGVzKHgpKVxufVxuIl19