mobx-bonsai-yjs
Version:
Y.js two-way binding for mobx-bonsai
335 lines (334 loc) • 43.4 kB
JavaScript
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("mobx"), require("mobx-bonsai"), require("yjs")) : typeof define === "function" && define.amd ? define(["exports", "mobx", "mobx-bonsai", "yjs"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["mobx-bonsai-yjs"] = {}, global.mobx, global["mobx-bonsai"], global.yjs));
})(this, (function(exports2, mobx, mobxBonsai, Y) {
"use strict";
function _interopNamespaceDefault(e) {
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
if (e) {
for (const k in e) {
if (k !== "default") {
const d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: () => e[k]
});
}
}
}
n.default = e;
return Object.freeze(n);
}
const Y__namespace = /* @__PURE__ */ _interopNamespaceDefault(Y);
class MobxBonsaiYjsError extends Error {
constructor(msg) {
super(msg);
Object.setPrototypeOf(this, MobxBonsaiYjsError.prototype);
}
}
function failure(msg) {
return new MobxBonsaiYjsError(msg);
}
function isYjsStructure(target) {
return target instanceof Y__namespace.Map || target instanceof Y__namespace.Array;
}
function assertIsYjsStructure(target) {
const valid = isYjsStructure(target);
if (!valid) {
throw failure("target is not a bindable y.js object");
}
}
function resolveYjsStructurePath(yjsObject, path) {
let target = yjsObject;
assertIsYjsStructure(target);
path.forEach((pathSegment, i) => {
if (target instanceof Y__namespace.Array) {
target = target.get(+pathSegment);
} else if (target instanceof Y__namespace.Map) {
target = target.get(String(pathSegment));
} else {
throw failure(
`Y.Map or Y.Array was expected at path ${JSON.stringify(
path.slice(0, i)
)} in order to resolve path ${JSON.stringify(path)}, but got ${target} instead`
);
}
});
return target;
}
function convertPlainToYjsValue(v) {
var _a;
if (mobxBonsai._isPrimitive(v)) {
return v;
}
if (mobxBonsai._isArray(v)) {
const arr = new Y__namespace.Array();
applyPlainArrayToYArray(arr, v);
return arr;
}
if (mobxBonsai._isPlainObject(v) || mobx.isObservableObject(v)) {
const frozenData = !!((_a = mobxBonsai.getNodeTypeAndKey(v).type) == null ? void 0 : _a.isFrozen);
if (frozenData) {
return v;
}
const map = new Y__namespace.Map();
applyPlainObjectToYMap(map, v);
return map;
}
throw failure(`unsupported value type: ${v}`);
}
const applyPlainArrayToYArray = (dest, source) => {
const yjsVals = source.map(convertPlainToYjsValue);
dest.push(yjsVals);
};
const applyPlainObjectToYMap = (dest, source) => {
Object.entries(source).forEach(([k, v]) => {
const yjsVal = convertPlainToYjsValue(v);
dest.set(k, yjsVal);
});
};
function setupNodeToYjsReplication({
node,
yjsDoc,
yjsObject,
yjsOriginGetter,
yjsOriginCache,
yjsReplicatingRef
}) {
let pendingMobxChanges = [];
let mobxDeepChangesNestingLevel = 0;
const disposeOnDeepChange = mobxBonsai.onDeepChange(node, (change) => {
if (yjsReplicatingRef.current > 0) {
return;
}
mobxDeepChangesNestingLevel++;
const path = mobxBonsai._buildNodeFullPath(change.object);
pendingMobxChanges.push({ change, path });
mobx.when(
() => true,
() => {
mobxDeepChangesNestingLevel--;
if (mobxDeepChangesNestingLevel === 0) {
const yjsOrigin = yjsOriginGetter();
yjsOriginCache.add(yjsOrigin);
yjsDoc.transact(() => {
const mobxChangesToApply = pendingMobxChanges;
pendingMobxChanges = [];
mobxChangesToApply.forEach(({ change: change2, path: path2 }) => {
const yjsTarget = resolveYjsStructurePath(yjsObject, path2);
const isObjectChange = "name" in change2;
if (isObjectChange) {
if (!(yjsTarget instanceof Y__namespace.Map)) {
throw failure("yjs target was expected to be a map");
}
const yjsMap = yjsTarget;
switch (change2.type) {
case "add":
case "update":
yjsMap.set(String(change2.name), convertPlainToYjsValue(change2.newValue));
break;
case "remove":
yjsMap.delete(String(change2.name));
break;
default:
throw failure(`unsupported mobx object change type`);
}
} else {
if (!(yjsTarget instanceof Y__namespace.Array)) {
throw failure("yjs target was expected to be an array");
}
const yjsArray = yjsTarget;
switch (change2.type) {
case "update": {
yjsArray.delete(change2.index, 1);
yjsArray.insert(change2.index, [convertPlainToYjsValue(change2.newValue)]);
break;
}
case "splice": {
yjsArray.delete(change2.index, change2.removedCount);
yjsArray.insert(change2.index, change2.added.map(convertPlainToYjsValue));
break;
}
default:
throw failure(`unsupported mobx array change type`);
}
}
});
}, yjsOrigin);
}
}
);
});
return {
dispose: () => {
disposeOnDeepChange();
}
};
}
function createNodeFromYjsObject(yjsObject) {
if (yjsObject instanceof Y__namespace.Map || yjsObject instanceof Y__namespace.Array) {
return mobxBonsai.node(yjsObject.toJSON(), { skipInit: true });
} else {
throw failure("only Y.js Map and Array instances can be bound to nodes");
}
}
function yjsToPlainValue(v) {
if (mobxBonsai._isPrimitive(v)) {
return v;
}
if (v instanceof Y__namespace.Map || v instanceof Y__namespace.Array) {
return v.toJSON();
}
throw failure(`unsupported Y.js value type: ${v}`);
}
function setupYjsToNodeReplication({
node,
yjsObject,
yjsOriginCache,
yjsReplicatingRef
}) {
const yjsObserverCallback = (events, transaction) => {
if (events.length === 0) {
return;
}
if (yjsOriginCache.has(transaction.origin)) {
return;
}
yjsReplicatingRef.current++;
try {
mobx.runInAction(() => {
mobxBonsai._runDetachingDuplicatedNodes(() => {
events.forEach((event) => {
const resolutionResult = mobxBonsai.resolvePath(node, event.path);
if (!resolutionResult.resolved) {
throw failure(
`failed to resolve node path for yjs event: ${JSON.stringify(event.path)}`
);
}
const mobxTarget = resolutionResult.value;
mobxBonsai.assertIsNode(mobxTarget, "mobxTarget");
if (event instanceof Y__namespace.YMapEvent) {
if (Array.isArray(mobxTarget)) {
throw failure("mobx target was expected to be an object");
}
const mobxObject = mobxTarget;
const yjsMap = event.target;
event.changes.keys.forEach((change, key) => {
switch (change.action) {
case "add":
case "update":
{
const yjsValue = yjsToPlainValue(yjsMap.get(key));
if (mobxObject[key] !== yjsValue) {
mobx.set(mobxObject, key, yjsValue);
}
}
break;
case "delete":
if (mobxObject[key] !== void 0) {
mobx.remove(mobxObject, key);
}
break;
default:
throw failure(`unsupported Yjs map event action: ${change.action}`);
}
});
} else if (event instanceof Y__namespace.YArrayEvent) {
if (!mobx.isObservableArray(mobxTarget)) {
throw failure("mobx target was expected to be an array");
}
const mobxArray = mobxTarget;
let retain = 0;
event.changes.delta.forEach((change) => {
if (change.retain) {
retain += change.retain;
}
if (change.delete) {
mobxArray.splice(retain, change.delete);
}
if (change.insert) {
const newValues = Array.isArray(change.insert) ? change.insert : [change.insert];
mobxArray.splice(retain, 0, ...newValues.map((v) => yjsToPlainValue(v)));
retain += newValues.length;
}
});
} else {
throw failure("unsupported Y.js event type");
}
});
});
});
} finally {
yjsReplicatingRef.current--;
}
};
yjsObject.observeDeep(yjsObserverCallback);
return {
dispose: () => {
yjsObject.unobserveDeep(yjsObserverCallback);
}
};
}
const bindYjsToNode = mobx.action(
({
yjsDoc,
yjsObject,
yjsOrigin
}) => {
yjsOrigin = yjsOrigin != null ? yjsOrigin : Symbol("mobx-bonsai-yjs-origin");
const yjsOriginGetter = typeof yjsOrigin === "function" ? yjsOrigin : () => yjsOrigin;
const node = createNodeFromYjsObject(yjsObject);
const yjsReplicatingRef = { current: 0 };
const yjsOriginCache = /* @__PURE__ */ new WeakSet();
const yjsToNodeReplicationAdmin = setupYjsToNodeReplication({
node,
yjsObject,
yjsOriginCache,
yjsReplicatingRef
});
const nodeToYjsReplicationAdmin = setupNodeToYjsReplication({
node,
yjsDoc,
yjsObject,
yjsOriginGetter,
yjsOriginCache,
yjsReplicatingRef
});
mobxBonsai.walkTree(
node,
(n) => {
const { type } = mobxBonsai.getNodeTypeAndKey(n);
type == null ? void 0 : type._initNode(n);
},
mobxBonsai.WalkTreeMode.ChildrenFirst
);
const ret = {
node,
getYjsValueForNode: (target) => {
if (target === node) {
return yjsObject;
}
const path = mobxBonsai.getParentToChildPath(node, target);
if (!path) {
throw new Error("node not found in the bound tree");
}
return resolveYjsStructurePath(yjsObject, path);
},
dispose: mobxBonsai._disposeOnce(() => {
nodeToYjsReplicationAdmin.dispose();
yjsToNodeReplicationAdmin.dispose();
}),
[Symbol.dispose]: () => {
ret.dispose();
}
};
return ret;
}
);
exports2.MobxBonsaiYjsError = MobxBonsaiYjsError;
exports2.applyPlainArrayToYArray = applyPlainArrayToYArray;
exports2.applyPlainObjectToYMap = applyPlainObjectToYMap;
exports2.bindYjsToNode = bindYjsToNode;
exports2.convertPlainToYjsValue = convertPlainToYjsValue;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
}));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ieC1ib25zYWkteWpzLnVtZC5qcyIsInNvdXJjZXMiOlsiLi4vc3JjL2Vycm9yL01vYnhCb25zYWlZanNFcnJvci50cyIsIi4uL3NyYy9lcnJvci9mYWlsdXJlLnRzIiwiLi4vc3JjL3lqc0JpbmRpbmcveWpzVHlwZXMvY2hlY2tzLnRzIiwiLi4vc3JjL3lqc0JpbmRpbmcvbm9kZVRvWWpzL3Jlc29sdmVZanNTdHJ1Y3R1cmVQYXRoLnRzIiwiLi4vc3JjL3lqc0JpbmRpbmcvbm9kZVRvWWpzL2NvbnZlcnRQbGFpblRvWWpzVmFsdWUudHMiLCIuLi9zcmMveWpzQmluZGluZy9ub2RlVG9ZanMvc2V0dXBOb2RlVG9ZanNSZXBsaWNhdGlvbi50cyIsIi4uL3NyYy95anNCaW5kaW5nL3lqc1RvTm9kZS9jcmVhdGVOb2RlRnJvbVlqc09iamVjdC50cyIsIi4uL3NyYy95anNCaW5kaW5nL3lqc1RvTm9kZS9zZXR1cFlqc1RvTm9kZVJlcGxpY2F0aW9uLnRzIiwiLi4vc3JjL3lqc0JpbmRpbmcvYmluZFlqc1RvTm9kZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEEgbW9ieC1ib25zYWkteWpzIGVycm9yLlxuICovXG5leHBvcnQgY2xhc3MgTW9ieEJvbnNhaVlqc0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZykge1xuICAgIHN1cGVyKG1zZylcblxuICAgIC8vIFNldCB0aGUgcHJvdG90eXBlIGV4cGxpY2l0bHkuXG4gICAgT2JqZWN0LnNldFByb3RvdHlwZU9mKHRoaXMsIE1vYnhCb25zYWlZanNFcnJvci5wcm90b3R5cGUpXG4gIH1cbn1cbiIsImltcG9ydCB7IE1vYnhCb25zYWlZanNFcnJvciB9IGZyb20gXCIuL01vYnhCb25zYWlZanNFcnJvclwiXG5cbmV4cG9ydCBmdW5jdGlvbiBmYWlsdXJlKG1zZzogc3RyaW5nKSB7XG4gIHJldHVybiBuZXcgTW9ieEJvbnNhaVlqc0Vycm9yKG1zZylcbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uLy4uL2Vycm9yL2ZhaWx1cmVcIlxuaW1wb3J0IHsgWWpzU3RydWN0dXJlIH0gZnJvbSBcIi4vdHlwZXNcIlxuXG5leHBvcnQgZnVuY3Rpb24gaXNZanNTdHJ1Y3R1cmUodGFyZ2V0OiB1bmtub3duKTogdGFyZ2V0IGlzIFlqc1N0cnVjdHVyZSB7XG4gIHJldHVybiB0YXJnZXQgaW5zdGFuY2VvZiBZLk1hcCB8fCB0YXJnZXQgaW5zdGFuY2VvZiBZLkFycmF5XG59XG5cbmV4cG9ydCBmdW5jdGlvbiBhc3NlcnRJc1lqc1N0cnVjdHVyZSh0YXJnZXQ6IHVua25vd24pOiBhc3NlcnRzIHRhcmdldCBpcyBZanNTdHJ1Y3R1cmUge1xuICBjb25zdCB2YWxpZCA9IGlzWWpzU3RydWN0dXJlKHRhcmdldClcbiAgaWYgKCF2YWxpZCkge1xuICAgIHRocm93IGZhaWx1cmUoXCJ0YXJnZXQgaXMgbm90IGEgYmluZGFibGUgeS5qcyBvYmplY3RcIilcbiAgfVxufVxuIiwiaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi4vLi4vZXJyb3IvZmFpbHVyZVwiXG5pbXBvcnQgeyBhc3NlcnRJc1lqc1N0cnVjdHVyZSB9IGZyb20gXCIuLi95anNUeXBlcy9jaGVja3NcIlxuaW1wb3J0IHsgWWpzU3RydWN0dXJlIH0gZnJvbSBcIi4uL3lqc1R5cGVzL3R5cGVzXCJcblxuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVZanNTdHJ1Y3R1cmVQYXRoKFxuICB5anNPYmplY3Q6IFlqc1N0cnVjdHVyZSxcbiAgcGF0aDogcmVhZG9ubHkgKHN0cmluZyB8IG51bWJlcilbXVxuKTogdW5rbm93biB7XG4gIGxldCB0YXJnZXQgPSB5anNPYmplY3RcbiAgYXNzZXJ0SXNZanNTdHJ1Y3R1cmUodGFyZ2V0KVxuXG4gIHBhdGguZm9yRWFjaCgocGF0aFNlZ21lbnQsIGkpID0+IHtcbiAgICBpZiAodGFyZ2V0IGluc3RhbmNlb2YgWS5BcnJheSkge1xuICAgICAgdGFyZ2V0ID0gdGFyZ2V0LmdldCgrcGF0aFNlZ21lbnQpXG4gICAgfSBlbHNlIGlmICh0YXJnZXQgaW5zdGFuY2VvZiBZLk1hcCkge1xuICAgICAgdGFyZ2V0ID0gdGFyZ2V0LmdldChTdHJpbmcocGF0aFNlZ21lbnQpKVxuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBmYWlsdXJlKFxuICAgICAgICBgWS5NYXAgb3IgWS5BcnJheSB3YXMgZXhwZWN0ZWQgYXQgcGF0aCAke0pTT04uc3RyaW5naWZ5KFxuICAgICAgICAgIHBhdGguc2xpY2UoMCwgaSlcbiAgICAgICAgKX0gaW4gb3JkZXIgdG8gcmVzb2x2ZSBwYXRoICR7SlNPTi5zdHJpbmdpZnkocGF0aCl9LCBidXQgZ290ICR7dGFyZ2V0fSBpbnN0ZWFkYFxuICAgICAgKVxuICAgIH1cbiAgfSlcblxuICByZXR1cm4gdGFyZ2V0XG59XG4iLCJpbXBvcnQgeyBpc09ic2VydmFibGVPYmplY3QgfSBmcm9tIFwibW9ieFwiXG5pbXBvcnQgeyBfaXNBcnJheSwgX2lzUGxhaW5PYmplY3QsIF9pc1ByaW1pdGl2ZSwgX1ByaW1pdGl2ZSwgZ2V0Tm9kZVR5cGVBbmRLZXkgfSBmcm9tIFwibW9ieC1ib25zYWlcIlxuaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi4vLi4vZXJyb3IvZmFpbHVyZVwiXG5pbXBvcnQgeyBZanNWYWx1ZSB9IGZyb20gXCIuLi95anNUeXBlcy90eXBlc1wiXG5cbi8qKlxuICogQ29udmVydHMgYSBwbGFpbiB2YWx1ZSB0byBhIFkuanMgdmFsdWUuXG4gKiBPYmplY3RzIGFyZSBjb252ZXJ0ZWQgdG8gWS5NYXBzLCBhcnJheXMgdG8gWS5BcnJheXMsIHByaW1pdGl2ZXMgYXJlIHVudG91Y2hlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRQbGFpblRvWWpzVmFsdWU8VCBleHRlbmRzIF9QcmltaXRpdmU+KHY6IFQpOiBUXG5leHBvcnQgZnVuY3Rpb24gY29udmVydFBsYWluVG9ZanNWYWx1ZSh2OiByZWFkb25seSBhbnlbXSk6IFkuQXJyYXk8WWpzVmFsdWU+XG5leHBvcnQgZnVuY3Rpb24gY29udmVydFBsYWluVG9ZanNWYWx1ZSh2OiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBhbnk+Pik6IFkuTWFwPFlqc1ZhbHVlPlxuXG5leHBvcnQgZnVuY3Rpb24gY29udmVydFBsYWluVG9ZanNWYWx1ZSh2OiBhbnkpOiBZanNWYWx1ZSB7XG4gIGlmIChfaXNQcmltaXRpdmUodikpIHtcbiAgICByZXR1cm4gdlxuICB9XG5cbiAgaWYgKF9pc0FycmF5KHYpKSB7XG4gICAgY29uc3QgYXJyID0gbmV3IFkuQXJyYXk8WWpzVmFsdWU+KClcbiAgICBhcHBseVBsYWluQXJyYXlUb1lBcnJheShhcnIsIHYpXG4gICAgcmV0dXJuIGFyciBhcyBZanNWYWx1ZVxuICB9XG5cbiAgaWYgKF9pc1BsYWluT2JqZWN0KHYpIHx8IGlzT2JzZXJ2YWJsZU9iamVjdCh2KSkge1xuICAgIGNvbnN0IGZyb3plbkRhdGEgPSAhIWdldE5vZGVUeXBlQW5kS2V5KHYpLnR5cGU/LmlzRnJvemVuXG4gICAgaWYgKGZyb3plbkRhdGEpIHtcbiAgICAgIHJldHVybiB2IC8vIHN0b3JlIGFzIGlzXG4gICAgfVxuXG4gICAgY29uc3QgbWFwID0gbmV3IFkuTWFwPFlqc1ZhbHVlPigpXG4gICAgYXBwbHlQbGFpbk9iamVjdFRvWU1hcChtYXAsIHYpXG4gICAgcmV0dXJuIG1hcCBhcyBZanNWYWx1ZVxuICB9XG5cbiAgdGhyb3cgZmFpbHVyZShgdW5zdXBwb3J0ZWQgdmFsdWUgdHlwZTogJHt2fWApXG59XG5cbi8qKlxuICogQXBwbGllcyBhIHBsYWluIGFycmF5IHRvIGEgWS5BcnJheSwgdXNpbmcgdGhlIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUgdG8gY29udmVydCB0aGUgdmFsdWVzLlxuICpcbiAqIEBwYXJhbSBkZXN0IC0gVGhlIFkuanMgQXJyYXkgdGhhdCB3aWxsIHJlY2VpdmUgdGhlIGNvbnZlcnRlZCB2YWx1ZXMuXG4gKiBAcGFyYW0gc291cmNlIC0gVGhlIHBsYWluIEphdmFTY3JpcHQgYXJyYXkgd2hvc2UgdmFsdWVzIHdpbGwgYmUgY29udmVydGVkIGFuZCBwdXNoZWQgdG8gdGhlIGRlc3RpbmF0aW9uLlxuICovXG5leHBvcnQgY29uc3QgYXBwbHlQbGFpbkFycmF5VG9ZQXJyYXkgPSAoZGVzdDogWS5BcnJheTxhbnk+LCBzb3VyY2U6IHJlYWRvbmx5IGFueVtdKSA9PiB7XG4gIGNvbnN0IHlqc1ZhbHMgPSBzb3VyY2UubWFwKGNvbnZlcnRQbGFpblRvWWpzVmFsdWUpXG4gIGRlc3QucHVzaCh5anNWYWxzKVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBwbGFpbiBvYmplY3QgdG8gYSBZLk1hcCwgdXNpbmcgdGhlIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUgdG8gY29udmVydCB0aGUgdmFsdWVzLlxuICpcbiAqIEBwYXJhbSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIFkuTWFwIHdoZXJlIHRoZSBwcm9wZXJ0aWVzIHdpbGwgYmUgc2V0XG4gKiBAcGFyYW0gc291cmNlIC0gVGhlIHBsYWluIEphdmFTY3JpcHQgb2JqZWN0IHdob3NlIHByb3BlcnRpZXMgd2lsbCBiZSBhcHBsaWVkIHRvIHRoZSBZLk1hcFxuICovXG5leHBvcnQgY29uc3QgYXBwbHlQbGFpbk9iamVjdFRvWU1hcCA9IChkZXN0OiBZLk1hcDxhbnk+LCBzb3VyY2U6IFJlYWRvbmx5PFJlY29yZDxzdHJpbmcsIGFueT4+KSA9PiB7XG4gIE9iamVjdC5lbnRyaWVzKHNvdXJjZSkuZm9yRWFjaCgoW2ssIHZdKSA9PiB7XG4gICAgY29uc3QgeWpzVmFsID0gY29udmVydFBsYWluVG9ZanNWYWx1ZSh2KVxuICAgIGRlc3Quc2V0KGssIHlqc1ZhbClcbiAgfSlcbn1cbiIsImltcG9ydCB7IHdoZW4gfSBmcm9tIFwibW9ieFwiXG5pbXBvcnQgeyBfYnVpbGROb2RlRnVsbFBhdGgsIE5vZGVDaGFuZ2UsIG9uRGVlcENoYW5nZSB9IGZyb20gXCJtb2J4LWJvbnNhaVwiXG5pbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuLi8uLi9lcnJvci9mYWlsdXJlXCJcbmltcG9ydCB7IFlqc1N0cnVjdHVyZSB9IGZyb20gXCIuLi95anNUeXBlcy90eXBlc1wiXG5pbXBvcnQgeyBjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlIH0gZnJvbSBcIi4vY29udmVydFBsYWluVG9ZanNWYWx1ZVwiXG5pbXBvcnQgeyByZXNvbHZlWWpzU3RydWN0dXJlUGF0aCB9IGZyb20gXCIuL3Jlc29sdmVZanNTdHJ1Y3R1cmVQYXRoXCJcblxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwTm9kZVRvWWpzUmVwbGljYXRpb24oe1xuICBub2RlLFxuICB5anNEb2MsXG4gIHlqc09iamVjdCxcbiAgeWpzT3JpZ2luR2V0dGVyLFxuICB5anNPcmlnaW5DYWNoZSxcbiAgeWpzUmVwbGljYXRpbmdSZWYsXG59OiB7XG4gIG5vZGU6IG9iamVjdFxuICB5anNEb2M6IFkuRG9jXG4gIHlqc09iamVjdDogWWpzU3RydWN0dXJlXG4gIHlqc09yaWdpbkdldHRlcjogKCkgPT4gc3ltYm9sXG4gIHlqc09yaWdpbkNhY2hlOiBXZWFrU2V0PHN5bWJvbD5cbiAgeWpzUmVwbGljYXRpbmdSZWY6IHsgY3VycmVudDogbnVtYmVyIH1cbn0pIHtcbiAgbGV0IHBlbmRpbmdNb2J4Q2hhbmdlczoge1xuICAgIGNoYW5nZTogTm9kZUNoYW5nZVxuICAgIHBhdGg6IHN0cmluZ1tdXG4gIH1bXSA9IFtdXG4gIGxldCBtb2J4RGVlcENoYW5nZXNOZXN0aW5nTGV2ZWwgPSAwXG5cbiAgY29uc3QgZGlzcG9zZU9uRGVlcENoYW5nZSA9IG9uRGVlcENoYW5nZShub2RlLCAoY2hhbmdlKSA9PiB7XG4gICAgLy8gaWYgdGhpcyBjb21lcyBmcm9tIGEgeWpzIGNoYW5nZSwgaWdub3JlIGl0XG4gICAgaWYgKHlqc1JlcGxpY2F0aW5nUmVmLmN1cnJlbnQgPiAwKSB7XG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICBtb2J4RGVlcENoYW5nZXNOZXN0aW5nTGV2ZWwrK1xuICAgIGNvbnN0IHBhdGggPSBfYnVpbGROb2RlRnVsbFBhdGgoY2hhbmdlLm9iamVjdClcbiAgICBwZW5kaW5nTW9ieENoYW5nZXMucHVzaCh7IGNoYW5nZSwgcGF0aCB9KVxuXG4gICAgLy8gaGFjayB0byBhcHBseSBwZW5kaW5nIG1vYnggY2hhbmdlcyBvbmNlIGFsbCBhY3Rpb25zIGFuZCByZWFjdGlvbnMgYXJlIGZpbmlzaGVkXG4gICAgd2hlbihcbiAgICAgICgpID0+IHRydWUsXG4gICAgICAoKSA9PiB7XG4gICAgICAgIG1vYnhEZWVwQ2hhbmdlc05lc3RpbmdMZXZlbC0tXG4gICAgICAgIGlmIChtb2J4RGVlcENoYW5nZXNOZXN0aW5nTGV2ZWwgPT09IDApIHtcbiAgICAgICAgICBjb25zdCB5anNPcmlnaW4gPSB5anNPcmlnaW5HZXR0ZXIoKVxuICAgICAgICAgIHlqc09yaWdpbkNhY2hlLmFkZCh5anNPcmlnaW4pXG5cbiAgICAgICAgICB5anNEb2MudHJhbnNhY3QoKCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgbW9ieENoYW5nZXNUb0FwcGx5ID0gcGVuZGluZ01vYnhDaGFuZ2VzXG4gICAgICAgICAgICBwZW5kaW5nTW9ieENoYW5nZXMgPSBbXVxuICAgICAgICAgICAgbW9ieENoYW5nZXNUb0FwcGx5LmZvckVhY2goKHsgY2hhbmdlLCBwYXRoIH0pID0+IHtcbiAgICAgICAgICAgICAgY29uc3QgeWpzVGFyZ2V0ID0gcmVzb2x2ZVlqc1N0cnVjdHVyZVBhdGgoeWpzT2JqZWN0LCBwYXRoKVxuXG4gICAgICAgICAgICAgIC8vIG5vdyB5LmpzIGFuZCBtb2J4IHNob3VsZCBiZSBpbiB0aGUgc2FtZSB0YXJnZXRcblxuICAgICAgICAgICAgICAvLyBJbiBNb2JYIDUsIG9ic2VydmFibGVLaW5kIGRvZXNuJ3QgZXhpc3QsIGJ1dCB3ZSBjYW4gY2hlY2sgZm9yIHRoZSBwcmVzZW5jZSBvZiAnbmFtZScgdnMgJ2luZGV4J1xuICAgICAgICAgICAgICAvLyB0byBkaXN0aW5ndWlzaCBiZXR3ZWVuIG9iamVjdCBhbmQgYXJyYXkgY2hhbmdlc1xuICAgICAgICAgICAgICBjb25zdCBpc09iamVjdENoYW5nZSA9IFwibmFtZVwiIGluIGNoYW5nZVxuXG4gICAgICAgICAgICAgIGlmIChpc09iamVjdENoYW5nZSkge1xuICAgICAgICAgICAgICAgIGlmICghKHlqc1RhcmdldCBpbnN0YW5jZW9mIFkuTWFwKSkge1xuICAgICAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcInlqcyB0YXJnZXQgd2FzIGV4cGVjdGVkIHRvIGJlIGEgbWFwXCIpXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNvbnN0IHlqc01hcCA9IHlqc1RhcmdldFxuXG4gICAgICAgICAgICAgICAgc3dpdGNoIChjaGFuZ2UudHlwZSkge1xuICAgICAgICAgICAgICAgICAgY2FzZSBcImFkZFwiOlxuICAgICAgICAgICAgICAgICAgY2FzZSBcInVwZGF0ZVwiOlxuICAgICAgICAgICAgICAgICAgICB5anNNYXAuc2V0KFN0cmluZyhjaGFuZ2UubmFtZSksIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUoY2hhbmdlLm5ld1ZhbHVlKSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWtcblxuICAgICAgICAgICAgICAgICAgY2FzZSBcInJlbW92ZVwiOlxuICAgICAgICAgICAgICAgICAgICB5anNNYXAuZGVsZXRlKFN0cmluZyhjaGFuZ2UubmFtZSkpXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoYHVuc3VwcG9ydGVkIG1vYnggb2JqZWN0IGNoYW5nZSB0eXBlYClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gQXJyYXkgY2hhbmdlXG4gICAgICAgICAgICAgICAgaWYgKCEoeWpzVGFyZ2V0IGluc3RhbmNlb2YgWS5BcnJheSkpIHtcbiAgICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoXCJ5anMgdGFyZ2V0IHdhcyBleHBlY3RlZCB0byBiZSBhbiBhcnJheVwiKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCB5anNBcnJheSA9IHlqc1RhcmdldFxuXG4gICAgICAgICAgICAgICAgc3dpdGNoIChjaGFuZ2UudHlwZSkge1xuICAgICAgICAgICAgICAgICAgY2FzZSBcInVwZGF0ZVwiOiB7XG4gICAgICAgICAgICAgICAgICAgIHlqc0FycmF5LmRlbGV0ZShjaGFuZ2UuaW5kZXgsIDEpXG4gICAgICAgICAgICAgICAgICAgIHlqc0FycmF5Lmluc2VydChjaGFuZ2UuaW5kZXgsIFtjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlKGNoYW5nZS5uZXdWYWx1ZSldKVxuICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICBjYXNlIFwic3BsaWNlXCI6IHtcbiAgICAgICAgICAgICAgICAgICAgeWpzQXJyYXkuZGVsZXRlKGNoYW5nZS5pbmRleCwgY2hhbmdlLnJlbW92ZWRDb3VudClcbiAgICAgICAgICAgICAgICAgICAgeWpzQXJyYXkuaW5zZXJ0KGNoYW5nZS5pbmRleCwgY2hhbmdlLmFkZGVkLm1hcChjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlKSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShgdW5zdXBwb3J0ZWQgbW9ieCBhcnJheSBjaGFuZ2UgdHlwZWApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KVxuICAgICAgICAgIH0sIHlqc09yaWdpbilcbiAgICAgICAgfVxuICAgICAgfVxuICAgIClcbiAgfSlcblxuICByZXR1cm4ge1xuICAgIGRpc3Bvc2U6ICgpID0+IHtcbiAgICAgIGRpc3Bvc2VPbkRlZXBDaGFuZ2UoKVxuICAgIH0sXG4gIH1cbn1cbiIsImltcG9ydCB7IG5vZGUgfSBmcm9tIFwibW9ieC1ib25zYWlcIlxyXG5pbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxyXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uLy4uL2Vycm9yL2ZhaWx1cmVcIlxyXG5pbXBvcnQgeyBZanNTdHJ1Y3R1cmUgfSBmcm9tIFwiLi4veWpzVHlwZXMvdHlwZXNcIlxyXG5cclxuZXhwb3J0IGZ1bmN0aW9uIGNyZWF0ZU5vZGVGcm9tWWpzT2JqZWN0PFQgZXh0ZW5kcyBvYmplY3Q+KHlqc09iamVjdDogWWpzU3RydWN0dXJlKTogVCB7XHJcbiAgaWYgKHlqc09iamVjdCBpbnN0YW5jZW9mIFkuTWFwIHx8IHlqc09iamVjdCBpbnN0YW5jZW9mIFkuQXJyYXkpIHtcclxuICAgIHJldHVybiBub2RlKHlqc09iamVjdC50b0pTT04oKSwgeyBza2lwSW5pdDogdHJ1ZSB9KSBhcyB1bmtub3duIGFzIFRcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgZmFpbHVyZShcIm9ubHkgWS5qcyBNYXAgYW5kIEFycmF5IGluc3RhbmNlcyBjYW4gYmUgYm91bmQgdG8gbm9kZXNcIilcclxuICB9XHJcbn1cclxuIiwiaW1wb3J0IHsgaXNPYnNlcnZhYmxlQXJyYXksIHJlbW92ZSwgcnVuSW5BY3Rpb24sIHNldCB9IGZyb20gXCJtb2J4XCJcbmltcG9ydCB7XG4gIF9pc1ByaW1pdGl2ZSxcbiAgX1ByaW1pdGl2ZSxcbiAgX3J1bkRldGFjaGluZ0R1cGxpY2F0ZWROb2RlcyxcbiAgYXNzZXJ0SXNOb2RlLFxuICByZXNvbHZlUGF0aCxcbn0gZnJvbSBcIm1vYngtYm9uc2FpXCJcbmltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uLy4uL2Vycm9yL2ZhaWx1cmVcIlxuaW1wb3J0IHsgWWpzU3RydWN0dXJlLCBZanNWYWx1ZSB9IGZyb20gXCIuLi95anNUeXBlcy90eXBlc1wiXG5cbmZ1bmN0aW9uIHlqc1RvUGxhaW5WYWx1ZTxUIGV4dGVuZHMgX1ByaW1pdGl2ZT4odjogVCk6IFRcbmZ1bmN0aW9uIHlqc1RvUGxhaW5WYWx1ZSh2OiBZLk1hcDxhbnk+KTogUmVjb3JkPHN0cmluZywgYW55PlxuZnVuY3Rpb24geWpzVG9QbGFpblZhbHVlKHY6IFkuQXJyYXk8YW55Pik6IGFueVtdXG5cbmZ1bmN0aW9uIHlqc1RvUGxhaW5WYWx1ZSh2OiBZanNWYWx1ZSk6IHVua25vd24ge1xuICBpZiAoX2lzUHJpbWl0aXZlKHYpKSB7XG4gICAgcmV0dXJuIHZcbiAgfVxuXG4gIGlmICh2IGluc3RhbmNlb2YgWS5NYXAgfHwgdiBpbnN0YW5jZW9mIFkuQXJyYXkpIHtcbiAgICByZXR1cm4gdi50b0pTT04oKVxuICB9XG5cbiAgdGhyb3cgZmFpbHVyZShgdW5zdXBwb3J0ZWQgWS5qcyB2YWx1ZSB0eXBlOiAke3Z9YClcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwWWpzVG9Ob2RlUmVwbGljYXRpb24oe1xuICBub2RlLFxuICB5anNPYmplY3QsXG4gIHlqc09yaWdpbkNhY2hlLFxuICB5anNSZXBsaWNhdGluZ1JlZixcbn06IHtcbiAgbm9kZTogb2JqZWN0XG4gIHlqc09iamVjdDogWWpzU3RydWN0dXJlXG4gIHlqc09yaWdpbkNhY2hlOiBXZWFrU2V0PHN5bWJvbD5cbiAgeWpzUmVwbGljYXRpbmdSZWY6IHsgY3VycmVudDogbnVtYmVyIH1cbn0pIHtcbiAgY29uc3QgeWpzT2JzZXJ2ZXJDYWxsYmFjayA9IChldmVudHM6IFkuWUV2ZW50PGFueT5bXSwgdHJhbnNhY3Rpb246IFkuVHJhbnNhY3Rpb24pID0+IHtcbiAgICBpZiAoZXZlbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gaWYgaXQgY29tZXMgZnJvbSBhIG1vYngtYm9uc2FpLXlqcyBjaGFuZ2UsIGlnbm9yZSBpdFxuICAgIGlmICh5anNPcmlnaW5DYWNoZS5oYXModHJhbnNhY3Rpb24ub3JpZ2luKSkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgLy8gbG9jayB0byBlbnN1cmUgbW9ieCBjaGFuZ2VzIGRvbid0IHRyaWdnZXIgeWpzIGNoYW5nZXMgYWdhaW5cbiAgICB5anNSZXBsaWNhdGluZ1JlZi5jdXJyZW50KytcblxuICAgIHRyeSB7XG4gICAgICBydW5JbkFjdGlvbigoKSA9PiB7XG4gICAgICAgIF9ydW5EZXRhY2hpbmdEdXBsaWNhdGVkTm9kZXMoKCkgPT4ge1xuICAgICAgICAgIGV2ZW50cy5mb3JFYWNoKChldmVudCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgcmVzb2x1dGlvblJlc3VsdCA9IHJlc29sdmVQYXRoKG5vZGUsIGV2ZW50LnBhdGgpXG4gICAgICAgICAgICBpZiAoIXJlc29sdXRpb25SZXN1bHQucmVzb2x2ZWQpIHtcbiAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcbiAgICAgICAgICAgICAgICBgZmFpbGVkIHRvIHJlc29sdmUgbm9kZSBwYXRoIGZvciB5anMgZXZlbnQ6ICR7SlNPTi5zdHJpbmdpZnkoZXZlbnQucGF0aCl9YFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBtb2J4VGFyZ2V0ID0gcmVzb2x1dGlvblJlc3VsdC52YWx1ZVxuICAgICAgICAgICAgYXNzZXJ0SXNOb2RlKG1vYnhUYXJnZXQsIFwibW9ieFRhcmdldFwiKVxuXG4gICAgICAgICAgICAvLyBub3cgeS5qcyBhbmQgbW9ieCBzaG91bGQgYmUgaW4gdGhlIHNhbWUgdGFyZ2V0XG5cbiAgICAgICAgICAgIGlmIChldmVudCBpbnN0YW5jZW9mIFkuWU1hcEV2ZW50KSB7XG4gICAgICAgICAgICAgIC8vIERpcmVjdGx5IGNoZWNrIGlmIGl0J3MgYW4gYXJyYXkgKGFycmF5cyBhcmUgb2JqZWN0cyB0b28pXG4gICAgICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KG1vYnhUYXJnZXQpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcIm1vYnggdGFyZ2V0IHdhcyBleHBlY3RlZCB0byBiZSBhbiBvYmplY3RcIilcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIGNvbnN0IG1vYnhPYmplY3QgPSBtb2J4VGFyZ2V0XG4gICAgICAgICAgICAgIGNvbnN0IHlqc01hcCA9IGV2ZW50LnRhcmdldFxuXG4gICAgICAgICAgICAgIGV2ZW50LmNoYW5nZXMua2V5cy5mb3JFYWNoKChjaGFuZ2UsIGtleSkgPT4ge1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoY2hhbmdlLmFjdGlvbikge1xuICAgICAgICAgICAgICAgICAgY2FzZSBcImFkZFwiOlxuICAgICAgICAgICAgICAgICAgY2FzZSBcInVwZGF0ZVwiOlxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgLy8gd2UgaGF2ZSB0byBjaGVjayBiZWNhdXNlIHNvbWV0aW1lcyB5anMgc2VuZHNcbiAgICAgICAgICAgICAgICAgICAgICAvLyBhbiB1cGRhdGUgZXZlbnQgZm9yIHNvbWV0aGluZyBhbHJlYWR5IHRoZXJlXG4gICAgICAgICAgICAgICAgICAgICAgY29uc3QgeWpzVmFsdWUgPSB5anNUb1BsYWluVmFsdWUoeWpzTWFwLmdldChrZXkpKVxuICAgICAgICAgICAgICAgICAgICAgIGlmICgobW9ieE9iamVjdCBhcyBhbnkpW2tleV0gIT09IHlqc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXQobW9ieE9iamVjdCwga2V5LCB5anNWYWx1ZSlcbiAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWtcblxuICAgICAgICAgICAgICAgICAgY2FzZSBcImRlbGV0ZVwiOlxuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBoYXZlIHRvIGNoZWNrIGJlY2F1c2Ugc29tZXRpbWVzIHlqcyBzZW5kc1xuICAgICAgICAgICAgICAgICAgICAvLyBhbiB1cGRhdGUgZXZlbnQgZm9yIHNvbWV0aGluZyBhbHJlYWR5IHRoZXJlXG4gICAgICAgICAgICAgICAgICAgIGlmICgobW9ieE9iamVjdCBhcyBhbnkpW2tleV0gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgICAgICAgIHJlbW92ZShtb2J4T2JqZWN0LCBrZXkpXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWtcblxuICAgICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShgdW5zdXBwb3J0ZWQgWWpzIG1hcCBldmVudCBhY3Rpb246ICR7Y2hhbmdlLmFjdGlvbn1gKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZXZlbnQgaW5zdGFuY2VvZiBZLllBcnJheUV2ZW50KSB7XG4gICAgICAgICAgICAgIGlmICghaXNPYnNlcnZhYmxlQXJyYXkobW9ieFRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBmYWlsdXJlKFwibW9ieCB0YXJnZXQgd2FzIGV4cGVjdGVkIHRvIGJlIGFuIGFycmF5XCIpXG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBjb25zdCBtb2J4QXJyYXkgPSBtb2J4VGFyZ2V0XG4gICAgICAgICAgICAgIGxldCByZXRhaW4gPSAwXG5cbiAgICAgICAgICAgICAgZXZlbnQuY2hhbmdlcy5kZWx0YS5mb3JFYWNoKChjaGFuZ2UpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlLnJldGFpbikge1xuICAgICAgICAgICAgICAgICAgcmV0YWluICs9IGNoYW5nZS5yZXRhaW5cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlLmRlbGV0ZSkge1xuICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIFggaXRlbXMgYXQgcmV0YWluIHBvc2l0aW9uXG4gICAgICAgICAgICAgICAgICBtb2J4QXJyYXkuc3BsaWNlKHJldGFpbiwgY2hhbmdlLmRlbGV0ZSlcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoY2hhbmdlLmluc2VydCkge1xuICAgICAgICAgICAgICAgICAgY29uc3QgbmV3VmFsdWVzID0gQXJyYXkuaXNBcnJheShjaGFuZ2UuaW5zZXJ0KSA/IGNoYW5nZS5pbnNlcnQgOiBbY2hhbmdlLmluc2VydF1cbiAgICAgICAgICAgICAgICAgIG1vYnhBcnJheS5zcGxpY2UocmV0YWluLCAwLCAuLi5uZXdWYWx1ZXMubWFwKCh2KSA9PiB5anNUb1BsYWluVmFsdWUodikpKVxuICAgICAgICAgICAgICAgICAgcmV0YWluICs9IG5ld1ZhbHVlcy5sZW5ndGhcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBmYWlsdXJlKFwidW5zdXBwb3J0ZWQgWS5qcyBldmVudCB0eXBlXCIpXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSlcbiAgICAgICAgfSlcbiAgICAgIH0pXG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHlqc1JlcGxpY2F0aW5nUmVmLmN1cnJlbnQtLVxuICAgIH1cbiAgfVxuXG4gIHlqc09iamVjdC5vYnNlcnZlRGVlcCh5anNPYnNlcnZlckNhbGxiYWNrKVxuXG4gIHJldHVybiB7XG4gICAgZGlzcG9zZTogKCkgPT4ge1xuICAgICAgeWpzT2JqZWN0LnVub2JzZXJ2ZURlZXAoeWpzT2JzZXJ2ZXJDYWxsYmFjaylcbiAgICB9LFxuICB9XG59XG4iLCJpbXBvcnQgeyBhY3Rpb24gfSBmcm9tIFwibW9ieFwiXG5pbXBvcnQge1xuICBfRGlzcG9zZSxcbiAgX2Rpc3Bvc2VPbmNlLFxuICBnZXROb2RlVHlwZUFuZEtleSxcbiAgZ2V0UGFyZW50VG9DaGlsZFBhdGgsXG4gIE5vZGVXaXRoQW55VHlwZSxcbiAgV2Fsa1RyZWVNb2RlLFxuICB3YWxrVHJlZSxcbn0gZnJvbSBcIm1vYngtYm9uc2FpXCJcbmltcG9ydCB0eXBlICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IHJlc29sdmVZanNTdHJ1Y3R1cmVQYXRoIH0gZnJvbSBcIi4vbm9kZVRvWWpzL3Jlc29sdmVZanNTdHJ1Y3R1cmVQYXRoXCJcbmltcG9ydCB7IHNldHVwTm9kZVRvWWpzUmVwbGljYXRpb24gfSBmcm9tIFwiLi9ub2RlVG9ZanMvc2V0dXBOb2RlVG9ZanNSZXBsaWNhdGlvblwiXG5pbXBvcnQgeyBjcmVhdGVOb2RlRnJvbVlqc09iamVjdCB9IGZyb20gXCIuL3lqc1RvTm9kZS9jcmVhdGVOb2RlRnJvbVlqc09iamVjdFwiXG5pbXBvcnQgeyBzZXR1cFlqc1RvTm9kZVJlcGxpY2F0aW9uIH0gZnJvbSBcIi4veWpzVG9Ob2RlL3NldHVwWWpzVG9Ob2RlUmVwbGljYXRpb25cIlxuaW1wb3J0IHsgWWpzU3RydWN0dXJlIH0gZnJvbSBcIi4veWpzVHlwZXMvdHlwZXNcIlxuXG4vKipcbiAqIENyZWF0ZXMgYSBub2RlIHRoYXQgaXMgYm91bmQgdG8gYSBZLmpzIGRhdGEgc3RydWN0dXJlLlxuICogWS5qcyBNYXAgYW5kIEFycmF5IGluc3RhbmNlcyBhcmUgYm91bmQgdG8gTW9iWCBvYmplY3RzIGFuZCBhcnJheXMsIHJlc3BlY3RpdmVseS5cbiAqL1xuZXhwb3J0IGNvbnN0IGJpbmRZanNUb05vZGUgPSBhY3Rpb24oXG4gIDxUIGV4dGVuZHMgb2JqZWN0Pih7XG4gICAgeWpzRG9jLFxuICAgIHlqc09iamVjdCxcbiAgICB5anNPcmlnaW4sXG4gIH06IHtcbiAgICAvKipcbiAgICAgKiBUaGUgWS5qcyBkb2N1bWVudC5cbiAgICAgKi9cbiAgICB5anNEb2M6IFkuRG9jXG5cbiAgICAvKipcbiAgICAgKiBUaGUgWS5qcyBkYXRhIHN0cnVjdHVyZSB0byBiaW5kLlxuICAgICAqL1xuICAgIHlqc09iamVjdDogWWpzU3RydWN0dXJlXG5cbiAgICAvKipcbiAgICAgKiBUaGUgWS5qcyBvcmlnaW4gc3ltYm9sIHVzZWQgZm9yIGJpbmRpbmcgdHJhbnNhY3Rpb25zLCBvciBhIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyB0aGUgc3ltYm9sLlxuICAgICAqIE9uZSB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgZ2VuZXJhdGVkIGlmIG5vdCBwcm92aWRlZC5cbiAgICAgKi9cbiAgICB5anNPcmlnaW4/OiBzeW1ib2wgfCAoKCkgPT4gc3ltYm9sKVxuICB9KToge1xuICAgIC8qKlxuICAgICAqIFRoZSBib3VuZCBub2RlLlxuICAgICAqL1xuICAgIG5vZGU6IFRcblxuICAgIC8qKlxuICAgICAqIFJlc29sdmVzIHRoZSBjb3JyZXNwb25kaW5nIFkuanMgdmFsdWUgZm9yIGEgZ2l2ZW4gdGFyZ2V0IG5vZGUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gbm9kZSAtIFRoZSBub2RlIHRvIHJlc29sdmUgaW4gdGhlIGJvdW5kIFlqcyBzdHJ1Y3R1cmUuXG4gICAgICogQHJldHVybnMgVGhlIHJlc29sdmVkIFkuanMgdmFsdWUuXG4gICAgICogQHRocm93cyBFcnJvciBpZiB0aGUgdGFyZ2V0IG5vZGUgaXMgbm90IGZvdW5kIGluIHRoZSBib3VuZCB0cmVlLlxuICAgICAqL1xuICAgIGdldFlqc1ZhbHVlRm9yTm9kZTogKG5vZGU6IG9iamVjdCkgPT4gdW5rbm93blxuXG4gICAgLyoqXG4gICAgICogRGlzcG9zZXMgdGhlIGJpbmRpbmcuXG4gICAgICovXG4gICAgZGlzcG9zZTogX0Rpc3Bvc2VcblxuICAgIC8qKlxuICAgICAqIERpc3Bvc2VzIHRoZSBiaW5kaW5nLlxuICAgICAqL1xuICAgIFtTeW1ib2wuZGlzcG9zZV0oKTogdm9pZFxuICB9ID0+IHtcbiAgICB5anNPcmlnaW4gPSB5anNPcmlnaW4gPz8gU3ltYm9sKFwibW9ieC1ib25zYWkteWpzLW9yaWdpblwiKVxuXG4gICAgLy8gQ29udmVydCB5anNPcmlnaW4gdG8gYSBnZXR0ZXIgZnVuY3Rpb24gaWYgaXQncyBhIHBsYWluIHN5bWJvbFxuICAgIGNvbnN0IHlqc09yaWdpbkdldHRlciA9IHR5cGVvZiB5anNPcmlnaW4gPT09IFwiZnVuY3Rpb25cIiA/IHlqc09yaWdpbiA6ICgpID0+IHlqc09yaWdpblxuXG4gICAgY29uc3Qgbm9kZSA9IGNyZWF0ZU5vZGVGcm9tWWpzT2JqZWN0PFQ+KHlqc09iamVjdClcblxuICAgIGNvbnN0IHlqc1JlcGxpY2F0aW5nUmVmID0geyBjdXJyZW50OiAwIH1cblxuICAgIGNvbnN0IHlqc09yaWdpbkNhY2hlID0gbmV3IFdlYWtTZXQ8c3ltYm9sPigpXG5cbiAgICBjb25zdCB5anNUb05vZGVSZXBsaWNhdGlvbkFkbWluID0gc2V0dXBZanNUb05vZGVSZXBsaWNhdGlvbih7XG4gICAgICBub2RlOiBub2RlLFxuICAgICAgeWpzT2JqZWN0LFxuICAgICAgeWpzT3JpZ2luQ2FjaGUsXG4gICAgICB5anNSZXBsaWNhdGluZ1JlZixcbiAgICB9KVxuXG4gICAgY29uc3Qgbm9kZVRvWWpzUmVwbGljYXRpb25BZG1pbiA9IHNldHVwTm9kZVRvWWpzUmVwbGljYXRpb24oe1xuICAgICAgbm9kZTogbm9kZSxcbiAgICAgIHlqc0RvYyxcbiAgICAgIHlqc09iamVjdCxcbiAgICAgIHlqc09yaWdpbkdldHRlcixcbiAgICAgIHlqc09yaWdpbkNhY2hlLFxuICAgICAgeWpzUmVwbGljYXRpbmdSZWYsXG4gICAgfSlcblxuICAgIC8vIHJ1biBub2RlIGluaXRpYWxpemF0aW9uIGNhbGxiYWNrcyBoZXJlLCBsYXRlciwgdG8gc3luYyBjaGFuZ2VzXG4gICAgd2Fsa1RyZWUoXG4gICAgICBub2RlLFxuICAgICAgKG4pID0+IHtcbiAgICAgICAgY29uc3QgeyB0eXBlIH0gPSBnZXROb2RlVHlwZUFuZEtleShuKVxuICAgICAgICB0eXBlPy5faW5pdE5vZGUobiBhcyBOb2RlV2l0aEFueVR5cGUpXG4gICAgICB9LFxuICAgICAgV2Fsa1RyZWVNb2RlLkNoaWxkcmVuRmlyc3RcbiAgICApXG5cbiAgICBjb25zdCByZXQgPSB7XG4gICAgICBub2RlLFxuXG4gICAgICBnZXRZanNWYWx1ZUZvck5vZGU6ICh0YXJnZXQ6IG9iamVjdCkgPT4ge1xuICAgICAgICBpZiAodGFyZ2V0ID09PSBub2RlKSB7XG4gICAgICAgICAgcmV0dXJuIHlqc09iamVjdFxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBhdGggPSBnZXRQYXJlbnRUb0NoaWxkUGF0aChub2RlLCB0YXJnZXQpXG4gICAgICAgIGlmICghcGF0aCkge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIm5vZGUgbm90IGZvdW5kIGluIHRoZSBib3VuZCB0cmVlXCIpXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJlc29sdmVZanNTdHJ1Y3R1cmVQYXRoKHlqc09iamVjdCwgcGF0aClcbiAgICAgIH0sXG5cbiAgICAgIGRpc3Bvc2U6IF9kaXNwb3NlT25jZSgoKSA9PiB7XG4gICAgICAgIG5vZGVUb1lqc1JlcGxpY2F0aW9uQWRtaW4uZGlzcG9zZSgpXG4gICAgICAgIHlqc1RvTm9kZVJlcGxpY2F0aW9uQWRtaW4uZGlzcG9zZSgpXG4gICAgICB9KSxcblxuICAgICAgW1N5bWJvbC5kaXNwb3NlXTogKCkgPT4ge1xuICAgICAgICByZXQuZGlzcG9zZSgpXG4gICAgICB9LFxuICAgIH1cblxuICAgIHJldHVybiByZXRcbiAgfVxuKVxuIl0sIm5hbWVzIjpbIlkiLCJfaXNQcmltaXRpdmUiLCJfaXNBcnJheSIsIl9pc1BsYWluT2JqZWN0IiwiaXNPYnNlcnZhYmxlT2JqZWN0IiwiZ2V0Tm9kZVR5cGVBbmRLZXkiLCJvbkRlZXBDaGFuZ2UiLCJfYnVpbGROb2RlRnVsbFBhdGgiLCJ3aGVuIiwiY2hhbmdlIiwicGF0aCIsIm5vZGUiLCJydW5JbkFjdGlvbiIsIl9ydW5EZXRhY2hpbmdEdXBsaWNhdGVkTm9kZXMiLCJyZXNvbHZlUGF0aCIsImFzc2VydElzTm9kZSIsInNldCIsInJlbW92ZSIsImlzT2JzZXJ2YWJsZUFycmF5IiwiYWN0aW9uIiwid2Fsa1RyZWUiLCJXYWxrVHJlZU1vZGUiLCJnZXRQYXJlbnRUb0NoaWxkUGF0aCIsIl9kaXNwb3NlT25jZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBR08sTUFBTSwyQkFBMkIsTUFBTTtBQUFBLElBQzVDLFlBQVksS0FBYTtBQUN2QixZQUFNLEdBQUc7QUFHVCxhQUFPLGVBQWUsTUFBTSxtQkFBbUIsU0FBUztBQUFBLElBQzFEO0FBQUEsRUFDRjtBQ1JPLFdBQVMsUUFBUSxLQUFhO0FBQ25DLFdBQU8sSUFBSSxtQkFBbUIsR0FBRztBQUFBLEVBQ25DO0FDQU8sV0FBUyxlQUFlLFFBQXlDO0FBQ3RFLFdBQU8sa0JBQWtCQSxhQUFFLE9BQU8sa0JBQWtCQSxhQUFFO0FBQUEsRUFDeEQ7QUFFTyxXQUFTLHFCQUFxQixRQUFpRDtBQUNwRixVQUFNLFFBQVEsZUFBZSxNQUFNO0FBQ25DLFFBQUksQ0FBQyxPQUFPO0FBQ1YsWUFBTSxRQUFRLHNDQUFzQztBQUFBLElBQ3REO0FBQUEsRUFDRjtBQ1JPLFdBQVMsd0JBQ2QsV0FDQSxNQUNTO0FBQ1QsUUFBSSxTQUFTO0FBQ2IseUJBQXFCLE1BQU07QUFFM0IsU0FBSyxRQUFRLENBQUMsYUFBYSxNQUFNO0FBQy9CLFVBQUksa0JBQWtCQSxhQUFFLE9BQU87QUFDN0IsaUJBQVMsT0FBTyxJQUFJLENBQUMsV0FBVztBQUFBLE1BQ2xDLFdBQVcsa0JBQWtCQSxhQUFFLEtBQUs7QUFDbEMsaUJBQVMsT0FBTyxJQUFJLE9BQU8sV0FBVyxDQUFDO0FBQUEsTUFDekMsT0FBTztBQUNMLGNBQU07QUFBQSxVQUNKLHlDQUF5QyxLQUFLO0FBQUEsWUFDNUMsS0FBSyxNQUFNLEdBQUcsQ0FBQztBQUFBLFVBQUEsQ0FDaEIsNkJBQTZCLEtBQUssVUFBVSxJQUFJLENB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