@valueflows/vf-graphql-holochain
Version:
GraphQL schema bindings for the Holochain implementation of ValueFlows
478 lines • 54.1 kB
JavaScript
import { decode } from '@msgpack/msgpack';
import { decodeHashFromBase64, encodeHashToBase64 } from '@holochain/client';
import { getEntryFromStore, addEntryToStore, updateLatestRevision } from './store.js';
export function extractIds(obj) {
// extract the ids from the object
let id = obj.id;
let revisionId = obj.revisionId;
let output = { id, revisionId, entry: {} };
let args = { ...obj };
delete args.id;
delete args.revisionId;
output.entry = args;
return output;
}
export async function getPaginatedCollection(cell, linkFunc, entryFunc, paginated) {
const collection = await getCollection(cell, linkFunc, null, paginated);
const paginatedCollection = paginateCollection(collection, paginated);
return paginatedCollection;
}
export function paginateCollection(collection, args) {
const paginated = collection.map((item) => {
return {
__typename: 'AgentEdge',
cursor: item.id,
node: {
...item,
__typename: item.agentType
}
};
});
return {
pageInfo: {
endCursor: null,
hasNextPage: false,
hasPreviousPage: false,
pageLimit: null,
startCursor: null,
totalCount: null,
},
edges: paginated
};
}
export async function getCollectionLinks(cell, linkFunc, payload, paginated) {
const result = await cell.callZome({
zome_name: 'hrea',
fn_name: linkFunc,
payload,
});
const dedupedLinks = Array.from(result.reduce((map, link) => {
const encodedTarget = encodeHashToBase64(link.tag);
if (!map.has(encodedTarget) || (map.get(encodedTarget)?.timestamp ?? 0) < link.timestamp) {
map.set(encodedTarget, link);
}
return map;
}, new Map()).values());
return dedupedLinks;
}
export async function getCollection(cell, linkFunc, payload, paginated) {
const dedupedLinks = await getCollectionLinks(cell, linkFunc, payload, paginated);
// handle pagination
if (paginated) {
const allLinkTags = dedupedLinks.map((link) => encodeHashToBase64(link.tag));
let sliceBegins = 0;
let sliceEnds = dedupedLinks.length;
if (paginated?.first) {
sliceBegins = Math.max(paginated?.first - 1, sliceBegins);
}
else if (paginated?.after) {
sliceBegins = Math.max((allLinkTags.indexOf(paginated?.after || "") + 1), sliceBegins);
}
if (paginated?.last) {
sliceEnds = Math.min(paginated?.last, sliceEnds);
}
else if (paginated?.before) {
sliceEnds = Math.min(allLinkTags.indexOf(paginated?.before || ""), sliceEnds);
}
const paginatedLinks = dedupedLinks.slice(sliceBegins, sliceEnds);
const entries = await getEntries(cell, paginatedLinks);
return entries;
}
else {
const entries = await getEntries(cell, dedupedLinks);
return entries;
}
}
export async function getEntries(cell, list) {
// for each entry in the list, check the store, and if not found, fetch it
let entries = [];
let toFetch = [];
list.forEach((link) => {
const revisionId = encodeHashToBase64(link.target);
let entry = getEntryFromStore(revisionId);
if (entry) {
entries.push(entry);
// console.log("======================got entry from store=======================", entry)
}
else {
toFetch.push(revisionId);
// console.log("--------------------------fetching entry from zome---------------------", revisionId)
}
});
if (toFetch.length > 0) {
let entriesRes = await cell.callZome({
zome_name: 'hrea',
fn_name: 'get_generic_entries',
payload: toFetch,
});
entriesRes.forEach((res) => {
if (res?.entry?.Present) {
const decoded = decode(res.entry.Present.entry);
const camelCased = snakeToCamel(decoded);
const withIds = {
...camelCased,
// @ts-ignore
id: decoded?.id ? encodeHashToBase64(decoded.id) : encodeHashToBase64(res.signed_action.hashed.hash),
revisionId: encodeHashToBase64(res.signed_action.hashed.hash),
meta: {
retrievedRevision: {
id: encodeHashToBase64(res.signed_action.hashed.hash),
time: res.signed_action.hashed.content.timestamp,
}
}
};
const withFormattedDates = formatDates(withIds);
addEntryToStore(withIds.revisionId, withFormattedDates);
updateLatestRevision(withFormattedDates.id, withFormattedDates);
entries.push(withFormattedDates);
}
else {
console.log(`No entry for items (${list})`, res);
}
});
}
return entries;
}
export function formatResItem(resItem, id) {
if (!resItem?.entry?.Present?.entry) {
return null;
}
let decoded = decode(resItem.entry.Present.entry);
let camel = snakeToCamel(decoded);
let withId = {
...camel,
id: id,
revisionId: encodeHashToBase64(resItem.signed_action.hashed.hash),
meta: {
retrievedRevision: {
id: encodeHashToBase64(resItem.signed_action.hashed.hash),
time: resItem.signed_action.hashed.content.timestamp,
}
}
};
let encoded = formatDates(withId);
return encoded;
}
export function snakeToCamelString(str) {
// convert a snake_case string to camelCase
return str.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
}
export function snakeToCamel(lib) {
// Recursively convert all keys from snake_case to camelCase
// Do not convert if it's a hash (object with only numeric keys)
if (Array.isArray(lib)) {
return lib.map(snakeToCamel);
}
else if (lib !== null && typeof lib === 'object') {
// Check if all keys are numeric (hash object)
const keys = Object.keys(lib);
const allNumeric = keys.length > 0 && keys.every(k => /^\d+$/.test(k));
if (allNumeric) {
return lib;
}
let camel = {};
for (let key in lib) {
let camelKey = key.replace(/_([a-z])/g, function (g) { return g[1].toUpperCase(); });
// convert rea_action
if (camelKey === "reaAction") {
camelKey = "action";
}
const value = lib[key];
camel[camelKey] = (typeof value === 'object' && value !== null)
? snakeToCamel(value)
: value;
}
return camel;
}
return lib;
}
export function camelToSnake(lib) {
// Recursively convert all keys from camelCase to snake_case
if (Array.isArray(lib)) {
return lib.map(camelToSnake);
}
else if (lib !== null && typeof lib === 'object') {
let snake = {};
for (let key in lib) {
let snakeKey = key.replace(/([A-Z])/g, "_$1").toLowerCase();
// convert action
if (snakeKey === "action") {
snakeKey = "rea_action";
}
// turn null values into undefined
let value = lib[key] === null ? undefined : lib[key];
// recursively convert objects and arrays
if (typeof value === 'object' && value !== null) {
value = camelToSnake(value);
}
snake[snakeKey] = value;
}
return snake;
}
return lib;
}
export function detectQuantityValueField(field) {
if (field.has_numerical_value !== undefined && field.has_unit !== undefined) {
return true;
}
return false;
}
export function decodePotentialQuantityValueField(field) {
if (field.hasNumericalValue !== undefined && field.hasUnit !== undefined) {
return {
has_numerical_value: field.hasNumericalValue,
has_unit: field.hasUnit?.id ? field.hasUnit.id : (field.hasUnit ? field.hasUnit : null)
};
}
return field;
}
export function findAndDecodeQuantityValueFields(obj) {
for (let key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
if (obj[key].hasNumericalValue !== undefined && obj[key].hasUnit !== undefined) {
obj[key] = decodePotentialQuantityValueField(obj[key]);
}
}
}
return obj;
}
// const dateFields = ['due', 'hasBeginning', 'hasEnd', 'hasPointInTime']
// export function formatDates(obj: any) {
// dateFields.forEach(field => {
// if (obj[field]) {
// obj[field] = new Date(obj[field] / 1000)
// }
// })
// return obj
// }
// export function reverseFormatDates(obj: any) {
// dateFields.forEach(field => {
// if (obj[field]) {
// obj[field] = new Date(obj[field]).getTime() * 1000
// }
// })
// return obj
// }
const dateFields = ['due', 'hasBeginning', 'hasEnd', 'hasPointInTime'];
export function formatDates(obj) {
dateFields.forEach(field => {
if (obj[field]) {
// Only convert if not already a Date
if (!(obj[field] instanceof Date)) {
// if it is a number, assume it's a timestamp
if (typeof obj[field] === 'number') {
obj[field] = new Date(obj[field] / 1000);
}
else if (typeof obj[field] === 'string') {
// if it's a string, try to parse it as a date
const parsedDate = new Date(obj[field]);
if (!isNaN(parsedDate.getTime())) {
obj[field] = parsedDate;
}
}
}
}
});
return obj;
}
export function reverseFormatDates(obj) {
dateFields.forEach(field => {
if (obj[field]) {
// Only convert if not already a number (timestamp)
if (obj[field] instanceof Date) {
obj[field] = obj[field].getTime() * 1000;
}
else if (typeof obj[field] === 'string') {
// if it's a string, try to parse it as a date
const parsedDate = new Date(obj[field]);
if (!isNaN(parsedDate.getTime())) {
obj[field] = parsedDate.getTime() * 1000;
}
}
}
});
return obj;
}
export function pluralize(str) {
if (str === 'person') {
return 'people';
}
else if (str.endsWith('s')) {
return str + 'es';
}
else if (str.endsWith('y')) {
return str.slice(0, -1) + 'ies';
}
else if (str.endsWith('o')) {
return str + 'es';
}
else if (str.endsWith('ch')) {
return str + 'es';
}
else if (str.endsWith('sh')) {
return str + 'es';
}
else {
return str + 's';
}
}
export function decodeHashFields(obj, hashFields) {
hashFields.forEach(field => {
if (obj[field]) {
const decodedField = decodeHashFromBase64(obj[field]);
obj[field] = decodedField;
obj[`${field}Id`] = decodedField;
}
});
return obj;
}
const actions = {
"dropoff": {
id: "dropoff",
label: "dropoff",
resourceEffect: "decrement",
onhandEffect: "decrement",
inputOutput: "output",
pairsWith: "pickup"
},
"pickup": {
id: "pickup",
label: "pickup",
resourceEffect: "increment",
onhandEffect: "increment",
inputOutput: "input",
pairsWith: "dropoff"
},
"consume": {
id: "consume",
label: "consume",
resourceEffect: "decrement",
onhandEffect: "decrement",
inputOutput: "input",
pairsWith: "notApplicable"
},
"use": {
id: "use",
label: "use",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "input",
pairsWith: "notApplicable"
},
"work": {
id: "work",
label: "work",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "input",
pairsWith: "notApplicable"
},
"cite": {
id: "cite",
label: "cite",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "input",
pairsWith: "notApplicable"
},
"produce": {
id: "produce",
label: "produce",
resourceEffect: "increment",
onhandEffect: "increment",
inputOutput: "output",
pairsWith: "notApplicable"
},
"accept": {
id: "accept",
label: "accept",
resourceEffect: "noEffect",
onhandEffect: "decrement",
inputOutput: "input",
pairsWith: "modify"
},
"modify": {
id: "modify",
label: "modify",
resourceEffect: "noEffect",
onhandEffect: "increment",
inputOutput: "output",
pairsWith: "accept"
},
"pass": {
id: "pass",
label: "pass",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "output",
pairsWith: "accept"
},
"fail": {
id: "fail",
label: "fail",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "output",
pairsWith: "accept"
},
"deliver-service": {
id: "deliver-service",
label: "deliver-service",
resourceEffect: "noEffect",
onhandEffect: "noEffect",
inputOutput: "output",
pairsWith: "notApplicable"
},
"transfer-all-rights": {
id: "transfer-all-rights",
label: "transfer-all-rights",
resourceEffect: "decrementIncrement",
onhandEffect: "noEffect",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
},
"transfer-custody": {
id: "transfer-custody",
label: "transfer-custody",
resourceEffect: "noEffect",
onhandEffect: "decrementIncrement",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
},
"transfer": {
id: "transfer",
label: "transfer",
resourceEffect: "decrementIncrement",
onhandEffect: "decrementIncrement",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
},
"move": {
id: "move",
label: "move",
resourceEffect: "decrementIncrement",
onhandEffect: "decrementIncrement",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
},
"raise": {
id: "raise",
label: "raise",
resourceEffect: "increment",
onhandEffect: "increment",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
},
"lower": {
id: "lower",
label: "lower",
resourceEffect: "decrement",
onhandEffect: "decrement",
inputOutput: "notApplicable",
pairsWith: "notApplicable"
}
};
export function getAction(id) {
return actions[id];
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlsLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxNQUFNLEVBQVUsTUFBTSxrQkFBa0IsQ0FBQztBQUNsRCxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsa0JBQWtCLEVBQThCLE1BQU0sbUJBQW1CLENBQUE7QUFFeEcsT0FBTyxFQUFFLGlCQUFpQixFQUFFLGVBQWUsRUFBRSxvQkFBb0IsRUFBRSxNQUFNLFlBQVksQ0FBQztBQWN0RixNQUFNLFVBQVUsVUFBVSxDQUFDLEdBQW9CO0lBQzdDLGtDQUFrQztJQUNsQyxJQUFJLEVBQUUsR0FBRyxHQUFHLENBQUMsRUFBRSxDQUFBO0lBQ2YsSUFBSSxVQUFVLEdBQUcsR0FBRyxDQUFDLFVBQVUsQ0FBQTtJQUMvQixJQUFJLE1BQU0sR0FBRyxFQUFDLEVBQUUsRUFBRSxVQUFVLEVBQUUsS0FBSyxFQUFFLEVBQUUsRUFBQyxDQUFBO0lBQ3hDLElBQUksSUFBSSxHQUFHLEVBQUUsR0FBRyxHQUFHLEVBQXlCLENBQUE7SUFDNUMsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFBO0lBQ2QsT0FBTyxJQUFJLENBQUMsVUFBVSxDQUFBO0lBQ3RCLE1BQU0sQ0FBQyxLQUFLLEdBQUcsSUFBSSxDQUFBO0lBQ25CLE9BQU8sTUFBTSxDQUFBO0FBQ2YsQ0FBQztBQUVELE1BQU0sQ0FBQyxLQUFLLFVBQVUsc0JBQXNCLENBQUMsSUFBUyxFQUFFLFFBQWdCLEVBQUUsU0FBaUIsRUFBRSxTQUF1QjtJQUNsSCxNQUFNLFVBQVUsR0FBRyxNQUFNLGFBQWEsQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxTQUFTLENBQUMsQ0FBQztJQUN4RSxNQUFNLG1CQUFtQixHQUFHLGtCQUFrQixDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUN0RSxPQUFPLG1CQUFtQixDQUFBO0FBQzVCLENBQUM7QUFFRCxNQUFNLFVB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Y0FBYyxFQUFFLFdBQVc7UUFDM0IsWUFBWSxFQUFFLFdBQVc7UUFDekIsV0FBVyxFQUFFLGVBQWU7UUFDNUIsU0FBUyxFQUFFLGVBQWU7S0FDM0I7SUFDRCxPQUFPLEVBQUU7UUFDUCxFQUFFLEVBQUUsT0FBTztRQUNYLEtBQUssRUFBRSxPQUFPO1FBQ2QsY0FBYyxFQUFFLFdBQVc7UUFDM0IsWUFBWSxFQUFFLFdBQVc7UUFDekIsV0FBVyxFQUFFLGVBQWU7UUFDNUIsU0FBUyxFQUFFLGVBQWU7S0FDM0I7Q0FDRixDQUFBO0FBRUQsTUFBTSxVQUFVLFNBQVMsQ0FBQyxFQUFVO0lBQ2xDLE9BQU8sT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFBO0FBQ3BCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBkZWNvZGUsIGVuY29kZSB9IGZyb20gJ0Btc2dwYWNrL21zZ3BhY2snO1xuaW1wb3J0IHsgZGVjb2RlSGFzaEZyb21CYXNlNjQsIGVuY29kZUhhc2hUb0Jhc2U2NCwgdHlwZSBBY3Rpb25IYXNoLCB0eXBlIExpbmsgfSBmcm9tICdAaG9sb2NoYWluL2NsaWVudCdcbmltcG9ydCB7IFBhZ2luZ1BhcmFtcyB9IGZyb20gJy4vdHlwZXMuanMnXG5pbXBvcnQgeyBnZXRFbnRyeUZyb21TdG9yZSwgYWRkRW50cnlUb1N0b3JlLCB1cGRhdGVMYXRlc3RSZXZpc2lvbiB9IGZyb20gJy4vc3RvcmUuanMnO1xuXG50eXBlIEV4dHJhY3RJZHNPdXRwdXQgPSB7XG4gIGlkOiBzdHJpbmc7XG4gIHJldmlzaW9uSWQ6IHN0cmluZztcbiAgZW50cnk6IGFueTtcbn1cblxudHlwZSBFeHRyYWN0SWRzSW5wdXQgPSB7XG4gIGlkOiBzdHJpbmc7XG4gIHJldmlzaW9uSWQ6IHN0cmluZztcbiAgW2tleTogc3RyaW5nXTogYW55O1xufVxuXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdElkcyhvYmo6IEV4dHJhY3RJZHNJbnB1dCk6IEV4dHJhY3RJZHNPdXRwdXQge1xuICAvLyBleHRyYWN0IHRoZSBpZHMgZnJvbSB0aGUgb2JqZWN0XG4gIGxldCBpZCA9IG9iai5pZFxuICBsZXQgcmV2aXNpb25JZCA9IG9iai5yZXZpc2lvbklkXG4gIGxldCBvdXRwdXQgPSB7aWQsIHJldmlzaW9uSWQsIGVudHJ5OiB7fX1cbiAgbGV0IGFyZ3MgPSB7IC4uLm9iaiB9IGFzIFBhcnRpYWw8dHlwZW9mIG9iaj5cbiAgZGVsZXRlIGFyZ3MuaWRcbiAgZGVsZXRlIGFyZ3MucmV2aXNpb25JZFxuICBvdXRwdXQuZW50cnkgPSBhcmdzXG4gIHJldHVybiBvdXRwdXRcbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldFBhZ2luYXRlZENvbGxlY3Rpb24oY2VsbDogYW55LCBsaW5rRnVuYzogc3RyaW5nLCBlbnRyeUZ1bmM6IHN0cmluZywgcGFnaW5hdGVkOiBQYWdpbmdQYXJhbXMpIHtcbiAgY29uc3QgY29sbGVjdGlvbiA9IGF3YWl0IGdldENvbGxlY3Rpb24oY2VsbCwgbGlua0Z1bmMsIG51bGwsIHBhZ2luYXRlZCk7XG4gIGNvbnN0IHBhZ2luYXRlZENvbGxlY3Rpb24gPSBwYWdpbmF0ZUNvbGxlY3Rpb24oY29sbGVjdGlvbiwgcGFnaW5hdGVkKTtcbiAgcmV0dXJuIHBhZ2luYXRlZENvbGxlY3Rpb25cbn1cbiAgXG5leHBvcnQgZnVuY3Rpb24gcGFnaW5hdGVDb2xsZWN0aW9uKGNvbGxlY3Rpb246IGFueSwgYXJnczogUGFnaW5nUGFyYW1zKSB7XG4gIGNvbnN0IHBhZ2luYXRlZCA9IGNvbGxlY3Rpb24ubWFwKChpdGVtOiBhbnkpID0+IHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgICAgX190eXBlbmFtZTogJ0FnZW50RWRnZScsXG4gICAgICAgICAgY3Vyc29yOiBpdGVtLmlkLFxuICAgICAgICAgIG5vZGU6IHtcbiAgICAgICAgICAgICAgLi4uaXRlbSxcbiAgICAgICAgICAgICAgX190eXBlbmFtZTogaXRlbS5hZ2VudFR5cGVcbiAgICAgICAgICB9XG4gICAgICB9XG4gIH0pXG4gIHJldHVybiB7XG4gICAgICBwYWdlSW5mbzoge1xuICAgICAgICAgIGVuZEN1cnNvcjogbnVsbCxcbiAgICAgICAgICBoYXNOZXh0UGFnZTogZmFsc2UsXG4gICAgICAgICAgaGFzUHJldmlvdXNQYWdlOiBmYWxzZSxcbiAgICAgICAgICBwYWdlTGltaXQ6IG51bGwsXG4gICAgICAgICAgc3RhcnRDdXJzb3I6IG51bGwsXG4gICAgICAgICAgdG90YWxDb3VudDogbnVsbCxcbiAgICAgIH0sXG4gICAgICBlZGdlczogcGFnaW5hdGVkXG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldENvbGxlY3Rpb25MaW5rcyhcbiAgY2VsbDogYW55LCBcbiAgbGlua0Z1bmM6IHN0cmluZywgXG4gIHBheWxvYWQ6IGFueSwgXG4gIHBhZ2luYXRlZD86IFBhZ2luZ1BhcmFtc1xuKSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgY2VsbC5jYWxsWm9tZSh7XG4gICAgICAgIHpvbWVfbmFtZTogJ2hyZWEnLFxuICAgICAgICBmbl9uYW1lOiBsaW5rRnVuYyxcbiAgICAgICAgcGF5bG9hZCxcbiAgICB9KVxuICAgIGNvbnN0IGRlZHVwZWRMaW5rczogQXJyYXk8TGluaz4gPSBBcnJheS5mcm9tKFxuICAgICAgICByZXN1bHQucmVkdWNlKChtYXA6IE1hcDxzdHJpbmcsIExpbms+LCBsaW5rOiBMaW5rKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBlbmNvZGVkVGFyZ2V0ID0gZW5jb2RlSGFzaFRvQmFzZTY0KGxpbmsudGFnKTtcbiAgICAgICAgICAgIGlmICghbWFwLmhhcyhlbmNvZGVkVGFyZ2V0KSB8fCAobWFwLmdldChlbmNvZGVkVGFyZ2V0KT8udGltZXN0YW1wID8/IDApIDwgbGluay50aW1lc3RhbXApIHtcbiAgICAgICAgICAgICAgICBtYXAuc2V0KGVuY29kZWRUYXJnZXQsIGxpbmspO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG1hcDtcbiAgICAgICAgfSwgbmV3IE1hcCgpKS52YWx1ZXMoKVxuICAgICk7XG4gICAgcmV0dXJuIGRlZHVwZWRMaW5rc1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0Q29sbGVjdGlvbihcbiAgY2VsbDogYW55LCBcbiAgbGlua0Z1bmM6IHN0cmluZywgXG4gIHBheWxvYWQ6IGFueSwgXG4gIHBhZ2luYXRlZD86IFBhZ2luZ1BhcmFtc1xuKSB7XG4gICAgY29uc3QgZGVkdXBlZExpbmtzID0gYXdhaXQgZ2V0Q29sbGVjdGlvbkxpbmtzKGNlbGwsIGxpbmtGdW5jLCBwYXlsb2FkLCBwYWdpbmF0ZWQpO1xuXG4gICAgLy8gaGFuZGxlIHBhZ2luYXRpb25cbiAgICBpZiAocGFnaW5hdGVkKSB7XG4gICAgICBjb25zdCBhbGxMaW5rVGFncyA9IGRlZHVwZWRMaW5rcy5tYXAoKGxpbms6IExpbmspID0+IGVuY29kZUhhc2hUb0Jhc2U2NChsaW5rLnRhZykpXG4gICAgICBsZXQgc2xpY2VCZWdpbnMgPSAwXG4gICAgICBsZXQgc2xpY2VFbmRzID0gZGVkdXBlZExpbmtzLmxlbmd0aFxuICAgICAgaWYgKHBhZ2luYXRlZD8uZmlyc3QpIHtcbiAgICAgICAgc2xpY2VCZWdpbnMgPSBNYXRoLm1heChwYWdpbmF0ZWQ/LmZpcnN0IC0gMSwgc2xpY2VCZWdpbnMpXG4gICAgICB9IGVsc2UgaWYgKHBhZ2luYXRlZD8uYWZ0ZXIpIHtcbiAgICAgICAgc2xpY2VCZWdpbnMgPSBNYXRoLm1heCgoYWxsTGlua1RhZ3MuaW5kZXhPZihwYWdpbmF0ZWQ/LmFmdGVyIHx8IFwiXCIpICsgMSksIHNsaWNlQmVnaW5zKVxuICAgICAgfVxuICAgICAgaWYgKHBhZ2luYXRlZD8ubGFzdCkge1xuICAgICAgICBzbGljZUVuZHMgPSBNYXRoLm1pbihwYWdpbmF0ZWQ/Lmxhc3QsIHNsaWNlRW5kcylcbiAgICAgIH0gZWxzZSBpZiAocGFnaW5hdGVkPy5iZWZvcmUpIHtcbiAgICAgICAgc2xpY2VFbmRzID0gTWF0aC5taW4oYWxsTGlua1RhZ3MuaW5kZXhPZihwYWdpbmF0ZWQ/LmJlZm9yZSB8fCBcIlwiKSwgc2xpY2VFbmRzKVxuICAgICAgfVxuICAgICAgXG4gICAgICBjb25zdCBwYWdpbmF0ZWRMaW5rcyA9IGRlZHVwZWRMaW5rcy5zbGljZShzbGljZUJlZ2lucywgc2xpY2VFbmRzKVxuICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IGdldEVudHJpZXMoY2VsbCwgcGFnaW5hdGVkTGlua3MpO1xuICAgICAgcmV0dXJuIGVudHJpZXNcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgZW50cmllcyA9IGF3YWl0IGdldEVudHJpZXMoY2VsbCwgZGVkdXBlZExpbmtzKTtcbiAgICAgIHJldHVybiBlbnRyaWVzXG4gICAgfVxufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0RW50cmllcyhjZWxsOiBhbnksIGxpc3Q6IExpbmtbXSkge1xuICAvLyBmb3IgZWFjaCBlbnRyeSBpbiB0aGUgbGlzdCwgY2hlY2sgdGhlIHN0b3JlLCBhbmQgaWYgbm90IGZvdW5kLCBmZXRjaCBpdFxuICBsZXQgZW50cmllczogYW55W10gPSBbXVxuICBsZXQgdG9GZXRjaDogc3RyaW5nW10gPSBbXVxuXG4gIGxpc3QuZm9yRWFjaCgobGluaykgPT4ge1xuICAgIGNvbnN0IHJldmlzaW9uSWQgPSBlbmNvZGVIYXNoVG9CYXNlNjQobGluay50YXJnZXQpXG4gICAgbGV0IGVudHJ5ID0gZ2V0RW50cnlGcm9tU3RvcmUocmV2aXNpb25JZClcbiAgICBpZiAoZW50cnkpIHtcbiAgICAgIGVudHJpZXMucHVzaChlbnRyeSlcbiAgICAgIC8vIGNvbnNvbGUubG9nKFwiPT09PT09PT09PT09PT09PT09PT09PWdvdCBlbnRyeSBmcm9tIHN0b3JlPT09PT09PT09PT09PT09PT09PT09PT1cIiwgZW50cnkpXG4gICAgfSBlbHNlIHtcbiAgICAgIHRvRmV0Y2gucHVzaChyZXZpc2lvbklkKVxuICAgICAgLy8gY29uc29sZS5sb2coXCItLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLWZldGNoaW5nIGVudHJ5IGZyb20gem9tZS0tLS0tLS0tLS0tLS0tLS0tLS0tLVwiLCByZXZpc2lvbklkKVxuICAgIH1cbiAgfSlcblxuICBpZiAodG9GZXRjaC5sZW5ndGggPiAwKSB7XG4gICAgbGV0IGVudHJpZXNSZXMgPSBhd2FpdCBjZWxsLmNhbGxab21lKHtcbiAgICAgIHpvbWVfbmFtZTogJ2hyZWEnLFxuICAgICAgZm5fbmFtZTogJ2dldF9nZW5lcmljX2VudHJpZXMnLFxuICAgICAgcGF5bG9hZDogdG9GZXRjaCxcbiAgICB9KVxuXG4gICAgZW50cmllc1Jlcy5mb3JFYWNoKChyZXM6IGFueSkgPT4ge1xuICAgICAgaWYgKHJlcz8uZW50cnk/LlByZXNlbnQpIHtcbiAgICAgICAgY29uc3QgZGVjb2RlZCA9IGRlY29kZShyZXMuZW50cnkuUHJlc2VudC5lbnRyeSlcbiAgICAgICAgY29uc3QgY2FtZWxDYXNlZCA9IHNuYWtlVG9DYW1lbChkZWNvZGVkKVxuICAgICAgICBjb25zdCB3aXRoSWRzID0ge1xuICAgICAgICAgIC4uLmNhbWVsQ2FzZWQsIFxuICAgICAgICAgIC8vIEB0cy1pZ25vcmVcbiAgICAgICAgICBpZDogZGVjb2RlZD8uaWQgPyBlbmNvZGVIYXNoVG9CYXNlNjQoZGVjb2RlZC5pZCkgOiBlbmNvZGVIYXNoVG9CYXNlNjQocmVzLnNpZ25lZF9hY3Rpb24uaGFzaGVkLmhhc2gpLCBcbiAgICAgICAgICByZXZpc2lvbklkOiBlbmNvZGVIYXNoVG9CYXNlNjQocmVzLnNpZ25lZF9hY3Rpb24uaGFzaGVkLmhhc2gpLFxuICAgICAgICAgIG1ldGE6IHtcbiAgICAgICAgICAgIHJldHJpZXZlZFJldmlzaW9uOiB7XG4gICAgICAgICAgICAgIGlkOiBlbmNvZGVIYXNoVG9CYXNlNjQocmVzLnNpZ25lZF9hY3Rpb24uaGFzaGVkLmhhc2gpLFxuICAgICAgICAgICAgICB0aW1lOiByZXMuc2lnbmVkX2FjdGlvbi5oYXNoZWQuY29udGVudC50aW1lc3RhbXAsXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHdpdGhGb3JtYXR0ZWREYXRlcyA9IGZvcm1hdERhdGVzKHdpdGhJZHMpXG4gICAgICAgIGFkZEVudHJ5VG9TdG9yZSh3aXRoSWRzLnJldmlzaW9uSWQsIHdpdGhGb3JtYXR0ZWREYXRlcylcbiAgICAgICAgdXBkYXRlTGF0ZXN0UmV2aXNpb24oXG4gICAgICAgICAgd2l0aEZvcm1hdHRlZERhdGVzLmlkLFxuICAgICAgICAgIHdpdGhGb3JtYXR0ZWREYXRlc1xuICAgICAgICApXG4gICAgICAgIGVudHJpZXMucHVzaCh3aXRoRm9ybWF0dGVkRGF0ZXMpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZyhgTm8gZW50cnkgZm9yIGl0ZW1zICgke2xpc3R9KWAsIHJlcylcbiAgICAgIH1cbiAgICB9KVxuICB9XG4gIHJldHVybiBlbnRyaWVzXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBmb3JtYXRSZXNJdGVtKHJlc0l0ZW06IGFueSwgaWQ6IHN0cmluZykge1xuICBpZiAoIXJlc0l0ZW0/LmVudHJ5Py5QcmVzZW50Py5lbnRyeSkgeyByZXR1cm4gbnVsbCB9XG4gIGxldCBkZWNvZGVkID0gZGVjb2RlKHJlc0l0ZW0uZW50cnkuUHJlc2VudC5lbnRyeSlcbiAgbGV0IGNhbWVsID0gc25ha2VUb0NhbWVsKGRlY29kZWQpXG4gIGxldCB3aXRoSWQgPSB7XG4gICAgLi4uY2FtZWwsIFxuICAgIGlkOiAgaWQsXG4gICAgcmV2aXNpb25JZDogZW5jb2RlSGFzaFRvQmFzZTY0KHJlc0l0ZW0uc2lnbmVkX2FjdGlvbi5oYXNoZWQuaGFzaCksXG4gICAgbWV0YToge1xuICAgICAgcmV0cmlldmVkUmV2aXNpb246IHtcbiAgICAgICAgaWQ6IGVuY29kZUhhc2hUb0Jhc2U2NChyZXNJdGVtLnNpZ25lZF9hY3Rpb24uaGFzaGVkLmhhc2gpLFxuICAgICAgICB0aW1lOiByZXNJdGVtLnNpZ25lZF9hY3Rpb24uaGFzaGVkLmNvbnRlbnQudGltZXN0YW1wLFxuICAgICAgfVxuICAgIH1cbiAgfVxuICBsZXQgZW5jb2RlZCA9IGZvcm1hdERhdGVzKHdpdGhJZClcbiAgcmV0dXJuIGVuY29kZWRcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNuYWtlVG9DYW1lbFN0cmluZyhzdHI6IHN0cmluZykge1xuICAvLyBjb252ZXJ0IGEgc25ha2VfY2FzZSBzdHJpbmcgdG8gY2FtZWxDYXNlXG4gIHJldHVybiBzdHIucmVwbGFjZSgvXyhbYS16XSkvZywgZnVuY3Rpb24gKGcpIHsgcmV0dXJuIGdbMV0udG9VcHBlckNhc2UoKTsgfSk7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzbmFrZVRvQ2FtZWwobGliOiBhbnkpOiBhbnkge1xuICAvLyBSZWN1cnNpdmVseSBjb252ZXJ0IGFsbCBrZXlzIGZyb20gc25ha2VfY2FzZSB0byBjYW1lbENhc2VcbiAgLy8gRG8gbm90IGNvbnZlcnQgaWYgaXQncyBhIGhhc2ggKG9iamVjdCB3aXRoIG9ubHkgbnVtZXJpYyBrZXlzKVxuICBpZiAoQXJyYXkuaXNBcnJheShsaWIpKSB7XG4gICAgcmV0dXJuIGxpYi5tYXAoc25ha2VUb0NhbWVsKTtcbiAgfSBlbHNlIGlmIChsaWIgIT09IG51bGwgJiYgdHlwZW9mIGxpYiA9PT0gJ29iamVjdCcpIHtcbiAgICAvLyBDaGVjayBpZiBhbGwga2V5cyBhcmUgbnVtZXJpYyAoaGFzaCBvYmplY3QpXG4gICAgY29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKGxpYik7XG4gICAgY29uc3QgYWxsTnVtZXJpYyA9IGtleXMubGVuZ3RoID4gMCAmJiBrZXlzLmV2ZXJ5KGsgPT4gL15cXGQrJC8udGVzdChrKSk7XG4gICAgaWYgKGFsbE51bWVyaWMpIHtcbiAgICAgIHJldHVybiBsaWI7XG4gICAgfVxuICAgIGxldCBjYW1lbDogYW55ID0ge307XG4gICAgZm9yIChsZXQga2V5IGluIGxpYikge1xuICAgICAgbGV0IGNhbWVsS2V5ID0ga2V5LnJlcGxhY2UoL18oW2Etel0pL2csIGZ1bmN0aW9uIChnKSB7IHJldHVybiBnWzFdLnRvVXBwZXJDYXNlKCk7IH0pO1xuICAgICAgLy8gY29udmVydCByZWFfYWN0aW9uXG4gICAgICBpZiAoY2FtZWxLZXkgPT09IFwicmVhQWN0aW9uXCIpIHtcbiAgICAgICAgY2FtZWxLZXkgPSBcImFjdGlvblwiO1xuICAgICAgfVxuICAgICAgY29uc3QgdmFsdWUgPSBsaWJba2V5XTtcbiAgICAgIGNhbWVsW2NhbWVsS2V5XSA9ICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsKVxuICAgICAgICA/IHNuYWtlVG9DYW1lbCh2YWx1ZSlcbiAgICAgICAgOiB2YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGNhbWVsO1xuICB9XG4gIHJldHVybiBsaWI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBjYW1lbFRvU25ha2UobGliOiBhbnkpOiBhbnkge1xuICAvLyBSZWN1cnNpdmVseSBjb252ZXJ0IGFsbCBrZXlzIGZyb20gY2FtZWxDYXNlIHRvIHNuYWtlX2Nhc2VcbiAgaWYgKEFycmF5LmlzQXJyYXkobGliKSkge1xuICAgIHJldHVybiBsaWIubWFwKGNhbWVsVG9TbmFrZSk7XG4gIH0gZWxzZSBpZiAobGliICE9PSBudWxsICYmIHR5cGVvZiBsaWIgPT09ICdvYmplY3QnKSB7XG4gICAgbGV0IHNuYWtlOiBhbnkgPSB7fTtcbiAgICBmb3IgKGxldCBrZXkgaW4gbGliKSB7XG4gICAgICBsZXQgc25ha2VLZXkgPSBrZXkucmVwbGFjZSgvKFtBLVpdKS9nLCBcIl8kMVwiKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgLy8gY29udmVydCBhY3Rpb25cbiAgICAgIGlmIChzbmFrZUtleSA9PT0gXCJhY3Rpb25cIikge1xuICAgICAgICBzbmFrZUtleSA9IFwicmVhX2FjdGlvblwiO1xuICAgICAgfVxuICAgICAgLy8gdHVybiBudWxsIHZhbHVlcyBpbnRvIHVuZGVmaW5lZFxuICAgICAgbGV0IHZhbHVlID0gbGliW2tleV0gPT09IG51bGwgPyB1bmRlZmluZWQgOiBsaWJba2V5XTtcbiAgICAgIC8vIHJlY3Vyc2l2ZWx5IGNvbnZlcnQgb2JqZWN0cyBhbmQgYXJyYXlzXG4gICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICB2YWx1ZSA9IGNhbWVsVG9TbmFrZSh2YWx1ZSk7XG4gICAgICB9XG4gICAgICBzbmFrZVtzbmFrZUtleV0gPSB2YWx1ZTtcbiAgICB9XG4gICAgcmV0dXJuIHNuYWtlO1xuICB9XG4gIHJldHVybiBsaWI7XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBkZXRlY3RRdWFudGl0eVZhbHVlRmllbGQoZmllbGQ6IGFueSkge1xuICBpZiAoZmllbGQuaGFzX251bWVyaWNhbF92YWx1ZSAhPT0gdW5kZWZpbmVkICYmIGZpZWxkLmhhc191bml0ICE9PSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gdHJ1ZVxuICB9XG4gIHJldHVybiBmYWxzZVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVjb2RlUG90ZW50aWFsUXVhbnRpdHlWYWx1ZUZpZWxkKGZpZWxkOiBhbnkpIHtcbiAgaWYgKGZpZWxkLmhhc051bWVyaWNhbFZhbHVlICE9PSB1bmRlZmluZWQgJiYgZmllbGQuaGFzVW5pdCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGhhc19udW1lcmljYWxfdmFsdWU6IGZpZWxkLmhhc051bWVyaWNhbFZhbHVlLFxuICAgICAgaGFzX3VuaXQ6IGZpZWxkLmhhc1VuaXQ/LmlkID8gZmllbGQuaGFzVW5pdC5pZCA6IChmaWVsZC5oYXNVbml0ID8gZmllbGQuaGFzVW5pdCA6IG51bGwpXG4gICAgfVxuICB9XG4gIHJldHVybiBmaWVsZFxufVxuXG5leHBvcnQgZnVuY3Rpb24gZmluZEFuZERlY29kZVF1YW50aXR5VmFsdWVGaWVsZHMob2JqOiBhbnkpIHtcbiAgZm9yIChsZXQga2V5IGluIG9iaikge1xuICAgIGlmICh0eXBlb2Ygb2JqW2tleV0gPT09ICdvYmplY3QnICYmIG9ialtrZXldICE9PSBudWxsKSB7XG4gICAgICBpZiAob2JqW2tleV0uaGFzTnVtZXJpY2FsVmFsdWUgIT09IHVuZGVmaW5lZCAmJiBvYmpba2V5XS5oYXNVbml0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgb2JqW2tleV0gPSBkZWNvZGVQb3RlbnRpYWxRdWFudGl0eVZhbHVlRmllbGQob2JqW2tleV0pXG4gICAgICB9XG4gICAgfVxuICB9XG4gIHJldHVybiBvYmpcbn1cblxuLy8gY29uc3QgZGF0ZUZpZWxkcyA9IFsnZHVlJywgJ2hhc0JlZ2lubmluZycsICdoYXNFbmQnLCAnaGFzUG9pbnRJblRpbWUnXVxuLy8gZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdERhdGVzKG9iajogYW55KSB7XG4vLyAgIGRhdGVGaWVsZHMuZm9yRWFjaChmaWVsZCA9PiB7XG4vLyAgICAgaWYgKG9ialtmaWVsZF0pIHtcbi8vICAgICAgIG9ialtmaWVsZF0gPSBuZXcgRGF0ZShvYmpbZmllbGRdIC8gMTAwMClcbi8vICAgICB9XG4vLyAgIH0pXG4vLyAgIHJldHVybiBvYmpcbi8vIH1cblxuLy8gZXhwb3J0IGZ1bmN0aW9uIHJldmVyc2VGb3JtYXREYXRlcyhvYmo6IGFueSkge1xuLy8gICBkYXRlRmllbGRzLmZvckVhY2goZmllbGQgPT4ge1xuLy8gICAgIGlmIChvYmpbZmllbGRdKSB7XG4vLyAgICAgICBvYmpbZmllbGRdID0gbmV3IERhdGUob2JqW2ZpZWxkXSkuZ2V0VGltZSgpICogMTAwMFxuLy8gICAgIH1cbi8vICAgfSlcbi8vICAgcmV0dXJuIG9ialxuLy8gfVxuY29uc3QgZGF0ZUZpZWxkcyA9IFsnZHVlJywgJ2hhc0JlZ2lubmluZycsICdoYXNFbmQnLCAnaGFzUG9pbnRJblRpbWUnXVxuZXhwb3J0IGZ1bmN0aW9uIGZvcm1hdERhdGVzKG9iajogYW55KSB7XG4gIGRhdGVGaWVsZHMuZm9yRWFjaChmaWVsZCA9PiB7XG4gICAgaWYgKG9ialtmaWVsZF0pIHtcbiAgICAgIC8vIE9ubHkgY29udmVydCBpZiBub3QgYWxyZWFkeSBhIERhdGVcbiAgICAgIGlmICghKG9ialtmaWVsZF0gaW5zdGFuY2VvZiBEYXRlKSkge1xuICAgICAgICAvLyBpZiBpdCBpcyBhIG51bWJlciwgYXNzdW1lIGl0J3MgYSB0aW1lc3RhbXBcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbZmllbGRdID09PSAnbnVtYmVyJykge1xuICAgICAgICAgIG9ialtmaWVsZF0gPSBuZXcgRGF0ZShvYmpbZmllbGRdIC8gMTAwMClcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqW2ZpZWxkXSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAvLyBpZiBpdCdzIGEgc3RyaW5nLCB0cnkgdG8gcGFyc2UgaXQgYXMgYSBkYXRlXG4gICAgICAgICAgY29uc3QgcGFyc2VkRGF0ZSA9IG5ldyBEYXRlKG9ialtmaWVsZF0pXG4gICAgICAgICAgaWYgKCFpc05hTihwYXJzZWREYXRlLmdldFRpbWUoKSkpIHtcbiAgICAgICAgICAgIG9ialtmaWVsZF0gPSBwYXJzZWREYXRlXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9KVxuICByZXR1cm4gb2JqXG59XG5cbmV4cG9ydCBmdW5jdGlvbiByZXZlcnNlRm9ybWF0RGF0ZXMob2JqOiBhbnkpIHtcbiAgZGF0ZUZpZWxkcy5mb3JFYWNoKGZpZWxkID0+IHtcbiAgICBpZiAob2JqW2ZpZWxkXSkge1xuICAgICAgLy8gT25seSBjb252ZXJ0IGlmIG5vdCBhbHJlYWR5IGEgbnVtYmVyICh0aW1lc3RhbXApXG4gICAgICBpZiAob2JqW2ZpZWxkXSBpbnN0YW5jZW9mIERhdGUpIHtcbiAgICAgICAgb2JqW2ZpZWxkXSA9IG9ialtmaWVsZF0uZ2V0VGltZSgpICogMTAwMFxuICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2JqW2ZpZWxkXSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgLy8gaWYgaXQncyBhIHN0cmluZywgdHJ5IHRvIHBhcnNlIGl0IGFzIGEgZGF0ZVxuICAgICAgICBjb25zdCBwYXJzZWREYXRlID0gbmV3IERhdGUob2JqW2ZpZWxkXSlcbiAgICAgICAgaWYgKCFpc05hTihwYXJzZWREYXRlLmdldFRpbWUoKSkpIHtcbiAgICAgICAgICBvYmpbZmllbGRdID0gcGFyc2VkRGF0ZS5nZXRUaW1lKCkgKiAxMDAwXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pXG4gIHJldHVybiBvYmpcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHBsdXJhbGl6ZShzdHI6IHN0cmluZykge1xuICBpZiAoc3RyID09PSAncGVyc29uJykge1xuICAgIHJldHVybiAncGVvcGxlJ1xuICB9IGVsc2UgaWYgKHN0ci5lbmRzV2l0aCgncycpKSB7XG4gICAgcmV0dXJuIHN0ciArICdlcydcbiAgfSBlbHNlIGlmIChzdHIuZW5kc1dpdGgoJ3knKSkge1xuICAgIHJldHVybiBzdHIuc2xpY2UoMCwgLTEpICsgJ2llcydcbiAgfSBlbHNlIGlmIChzdHIuZW5kc1dpdGgoJ28nKSkge1xuICAgIHJldHVybiBzdHIgKyAnZXMnXG4gIH0gZWxzZSBpZiAoc3RyLmVuZHNXaXRoKCdjaCcpKSB7XG4gICAgcmV0dXJuIHN0ciArICdlcydcbiAgfSBlbHNlIGlmIChzdHIuZW5kc1dpdGgoJ3NoJykpIHtcbiAgICByZXR1cm4gc3RyICsgJ2VzJ1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBzdHIgKyAncydcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gZGVjb2RlSGFzaEZpZWxkcyhvYmo6IGFueSwgaGFzaEZpZWxkczogc3RyaW5nW10pIHtcbiAgaGFzaEZpZWxkcy5mb3JFYWNoKGZpZWxkID0+IHtcbiAgICBpZiAob2JqW2ZpZWxkXSkge1xuICAgICAgY29uc3QgZGVjb2RlZEZpZWxkID0gZGVjb2RlSGFzaEZyb21CYXNlNjQob2JqW2ZpZWxkXSlcbiAgICAgIG9ialtmaWVsZF0gPSBkZWNvZGVkRmllbGRcbiAgICAgIG9ialtgJHtmaWVsZH1JZGBdID0gZGVjb2RlZEZpZWxkXG4gICAgfVxuICB9KVxuICByZXR1cm4gb2JqXG59XG5cbmNvbnN0IGFjdGlvbnMgPSB7XG4gIFwiZHJvcG9mZlwiOiB7XG4gICAgaWQ6IFwiZHJvcG9mZlwiLFxuICAgIGxhYmVsOiBcImRyb3BvZmZcIixcbiAgICByZXNvdXJjZUVmZmVjdDogXCJkZWNyZW1lbnRcIixcbiAgICBvbmhhbmRFZmZlY3Q6IFwiZGVjcmVtZW50XCIsXG4gICAgaW5wdXRPdXRwdXQ6IFwib3V0cHV0XCIsXG4gICAgcGFpcnNXaXRoOiBcInBpY2t1cFwiXG4gIH0sXG4gIFwicGlja3VwXCI6IHtcbiAgICBpZDogXCJwaWNrdXBcIixcbiAgICBsYWJlbDogXCJwaWNrdXBcIixcbiAgICByZXNvdXJjZUVmZmVjdDogXCJpbmNyZW1lbnRcIixcbiAgICBvbmhhbmRFZmZlY3Q6IFwiaW5jcmVtZW50XCIsXG4gICAgaW5wdXRPdXRwdXQ6IFwiaW5wdXRcIixcbiAgICBwYWlyc1dpdGg6IFwiZHJvcG9mZlwiXG4gIH0sXG4gIFwiY29uc3VtZVwiOiB7XG4gICAgaWQ6IFwiY29uc3VtZVwiLFxuICAgIGxhYmVsOiBcImNvbnN1bWVcIixcbiAgICByZXNvdXJjZUVmZmVjdDogXCJkZWNyZW1lbnRcIixcbiAgICBvbmhhbmRFZmZlY3Q6IFwiZGVjcmVtZW50XCIsXG4gICAgaW5wdXRPdXRwdXQ6IFwiaW5wdXRcIixcbiAgICBwYWlyc1dpdGg6IFwibm90QXBwbGljYWJsZVwiXG4gIH0sXG4gIFwidXNlXCI6IHtcbiAgICBpZDogXCJ1c2VcIixcbiAgICBsYWJlbDogXCJ1c2VcIixcbiAgICByZXNvdXJjZUVmZmVjdDogXCJub0VmZmVjdFwiLFxuICAgIG9uaGFuZEVmZmV