UNPKG

mobx-bonsai-yjs

Version:

Y.js two-way binding for mobx-bonsai

317 lines (316 loc) 40.8 kB
import { isObservableObject, when, runInAction, remove, set, isObservableArray, action } from "mobx"; import { _isPrimitive, _isArray, _isPlainObject, getNodeTypeAndKey, onDeepChange, _buildNodeFullPath, node, _runDetachingDuplicatedNodes, resolvePath, assertIsNode, walkTree, WalkTreeMode, _disposeOnce, getParentToChildPath } from "mobx-bonsai"; import * as Y from "yjs"; 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.Map || target instanceof Y.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.Array) { target = target.get(+pathSegment); } else if (target instanceof Y.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 (_isPrimitive(v)) { return v; } if (_isArray(v)) { const arr = new Y.Array(); applyPlainArrayToYArray(arr, v); return arr; } if (_isPlainObject(v) || isObservableObject(v)) { const frozenData = !!((_a = getNodeTypeAndKey(v).type) == null ? void 0 : _a.isFrozen); if (frozenData) { return v; } const map = new Y.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: node2, yjsDoc, yjsObject, yjsOriginGetter, yjsOriginCache, yjsReplicatingRef }) { let pendingMobxChanges = []; let mobxDeepChangesNestingLevel = 0; const disposeOnDeepChange = onDeepChange(node2, (change) => { if (yjsReplicatingRef.current > 0) { return; } mobxDeepChangesNestingLevel++; const path = _buildNodeFullPath(change.object); pendingMobxChanges.push({ change, path }); 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.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.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.Map || yjsObject instanceof Y.Array) { return node(yjsObject.toJSON(), { skipInit: true }); } else { throw failure("only Y.js Map and Array instances can be bound to nodes"); } } function yjsToPlainValue(v) { if (_isPrimitive(v)) { return v; } if (v instanceof Y.Map || v instanceof Y.Array) { return v.toJSON(); } throw failure(`unsupported Y.js value type: ${v}`); } function setupYjsToNodeReplication({ node: node2, yjsObject, yjsOriginCache, yjsReplicatingRef }) { const yjsObserverCallback = (events, transaction) => { if (events.length === 0) { return; } if (yjsOriginCache.has(transaction.origin)) { return; } yjsReplicatingRef.current++; try { runInAction(() => { _runDetachingDuplicatedNodes(() => { events.forEach((event) => { const resolutionResult = resolvePath(node2, event.path); if (!resolutionResult.resolved) { throw failure( `failed to resolve node path for yjs event: ${JSON.stringify(event.path)}` ); } const mobxTarget = resolutionResult.value; assertIsNode(mobxTarget, "mobxTarget"); if (event instanceof Y.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) { set(mobxObject, key, yjsValue); } } break; case "delete": if (mobxObject[key] !== void 0) { remove(mobxObject, key); } break; default: throw failure(`unsupported Yjs map event action: ${change.action}`); } }); } else if (event instanceof Y.YArrayEvent) { if (!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 = action( ({ yjsDoc, yjsObject, yjsOrigin }) => { yjsOrigin = yjsOrigin != null ? yjsOrigin : Symbol("mobx-bonsai-yjs-origin"); const yjsOriginGetter = typeof yjsOrigin === "function" ? yjsOrigin : () => yjsOrigin; const node2 = createNodeFromYjsObject(yjsObject); const yjsReplicatingRef = { current: 0 }; const yjsOriginCache = /* @__PURE__ */ new WeakSet(); const yjsToNodeReplicationAdmin = setupYjsToNodeReplication({ node: node2, yjsObject, yjsOriginCache, yjsReplicatingRef }); const nodeToYjsReplicationAdmin = setupNodeToYjsReplication({ node: node2, yjsDoc, yjsObject, yjsOriginGetter, yjsOriginCache, yjsReplicatingRef }); walkTree( node2, (n) => { const { type } = getNodeTypeAndKey(n); type == null ? void 0 : type._initNode(n); }, WalkTreeMode.ChildrenFirst ); const ret = { node: node2, getYjsValueForNode: (target) => { if (target === node2) { return yjsObject; } const path = getParentToChildPath(node2, target); if (!path) { throw new Error("node not found in the bound tree"); } return resolveYjsStructurePath(yjsObject, path); }, dispose: _disposeOnce(() => { nodeToYjsReplicationAdmin.dispose(); yjsToNodeReplicationAdmin.dispose(); }), [Symbol.dispose]: () => { ret.dispose(); } }; return ret; } ); export { MobxBonsaiYjsError, applyPlainArrayToYArray, applyPlainObjectToYMap, bindYjsToNode, convertPlainToYjsValue }; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ieC1ib25zYWkteWpzLmVzbS5tanMiLCJzb3VyY2VzIjpbIi4uL3NyYy9lcnJvci9Nb2J4Qm9uc2FpWWpzRXJyb3IudHMiLCIuLi9zcmMvZXJyb3IvZmFpbHVyZS50cyIsIi4uL3NyYy95anNCaW5kaW5nL3lqc1R5cGVzL2NoZWNrcy50cyIsIi4uL3NyYy95anNCaW5kaW5nL25vZGVUb1lqcy9yZXNvbHZlWWpzU3RydWN0dXJlUGF0aC50cyIsIi4uL3NyYy95anNCaW5kaW5nL25vZGVUb1lqcy9jb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlLnRzIiwiLi4vc3JjL3lqc0JpbmRpbmcvbm9kZVRvWWpzL3NldHVwTm9kZVRvWWpzUmVwbGljYXRpb24udHMiLCIuLi9zcmMveWpzQmluZGluZy95anNUb05vZGUvY3JlYXRlTm9kZUZyb21ZanNPYmplY3QudHMiLCIuLi9zcmMveWpzQmluZGluZy95anNUb05vZGUvc2V0dXBZanNUb05vZGVSZXBsaWNhdGlvbi50cyIsIi4uL3NyYy95anNCaW5kaW5nL2JpbmRZanNUb05vZGUudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBIG1vYngtYm9uc2FpLXlqcyBlcnJvci5cbiAqL1xuZXhwb3J0IGNsYXNzIE1vYnhCb25zYWlZanNFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobXNnOiBzdHJpbmcpIHtcbiAgICBzdXBlcihtc2cpXG5cbiAgICAvLyBTZXQgdGhlIHByb3RvdHlwZSBleHBsaWNpdGx5LlxuICAgIE9iamVjdC5zZXRQcm90b3R5cGVPZih0aGlzLCBNb2J4Qm9uc2FpWWpzRXJyb3IucHJvdG90eXBlKVxuICB9XG59XG4iLCJpbXBvcnQgeyBNb2J4Qm9uc2FpWWpzRXJyb3IgfSBmcm9tIFwiLi9Nb2J4Qm9uc2FpWWpzRXJyb3JcIlxuXG5leHBvcnQgZnVuY3Rpb24gZmFpbHVyZShtc2c6IHN0cmluZykge1xuICByZXR1cm4gbmV3IE1vYnhCb25zYWlZanNFcnJvcihtc2cpXG59XG4iLCJpbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuLi8uLi9lcnJvci9mYWlsdXJlXCJcbmltcG9ydCB7IFlqc1N0cnVjdHVyZSB9IGZyb20gXCIuL3R5cGVzXCJcblxuZXhwb3J0IGZ1bmN0aW9uIGlzWWpzU3RydWN0dXJlKHRhcmdldDogdW5rbm93bik6IHRhcmdldCBpcyBZanNTdHJ1Y3R1cmUge1xuICByZXR1cm4gdGFyZ2V0IGluc3RhbmNlb2YgWS5NYXAgfHwgdGFyZ2V0IGluc3RhbmNlb2YgWS5BcnJheVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYXNzZXJ0SXNZanNTdHJ1Y3R1cmUodGFyZ2V0OiB1bmtub3duKTogYXNzZXJ0cyB0YXJnZXQgaXMgWWpzU3RydWN0dXJlIHtcbiAgY29uc3QgdmFsaWQgPSBpc1lqc1N0cnVjdHVyZSh0YXJnZXQpXG4gIGlmICghdmFsaWQpIHtcbiAgICB0aHJvdyBmYWlsdXJlKFwidGFyZ2V0IGlzIG5vdCBhIGJpbmRhYmxlIHkuanMgb2JqZWN0XCIpXG4gIH1cbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uLy4uL2Vycm9yL2ZhaWx1cmVcIlxuaW1wb3J0IHsgYXNzZXJ0SXNZanNTdHJ1Y3R1cmUgfSBmcm9tIFwiLi4veWpzVHlwZXMvY2hlY2tzXCJcbmltcG9ydCB7IFlqc1N0cnVjdHVyZSB9IGZyb20gXCIuLi95anNUeXBlcy90eXBlc1wiXG5cbmV4cG9ydCBmdW5jdGlvbiByZXNvbHZlWWpzU3RydWN0dXJlUGF0aChcbiAgeWpzT2JqZWN0OiBZanNTdHJ1Y3R1cmUsXG4gIHBhdGg6IHJlYWRvbmx5IChzdHJpbmcgfCBudW1iZXIpW11cbik6IHVua25vd24ge1xuICBsZXQgdGFyZ2V0ID0geWpzT2JqZWN0XG4gIGFzc2VydElzWWpzU3RydWN0dXJlKHRhcmdldClcblxuICBwYXRoLmZvckVhY2goKHBhdGhTZWdtZW50LCBpKSA9PiB7XG4gICAgaWYgKHRhcmdldCBpbnN0YW5jZW9mIFkuQXJyYXkpIHtcbiAgICAgIHRhcmdldCA9IHRhcmdldC5nZXQoK3BhdGhTZWdtZW50KVxuICAgIH0gZWxzZSBpZiAodGFyZ2V0IGluc3RhbmNlb2YgWS5NYXApIHtcbiAgICAgIHRhcmdldCA9IHRhcmdldC5nZXQoU3RyaW5nKHBhdGhTZWdtZW50KSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgZmFpbHVyZShcbiAgICAgICAgYFkuTWFwIG9yIFkuQXJyYXkgd2FzIGV4cGVjdGVkIGF0IHBhdGggJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICBwYXRoLnNsaWNlKDAsIGkpXG4gICAgICAgICl9IGluIG9yZGVyIHRvIHJlc29sdmUgcGF0aCAke0pTT04uc3RyaW5naWZ5KHBhdGgpfSwgYnV0IGdvdCAke3RhcmdldH0gaW5zdGVhZGBcbiAgICAgIClcbiAgICB9XG4gIH0pXG5cbiAgcmV0dXJuIHRhcmdldFxufVxuIiwiaW1wb3J0IHsgaXNPYnNlcnZhYmxlT2JqZWN0IH0gZnJvbSBcIm1vYnhcIlxuaW1wb3J0IHsgX2lzQXJyYXksIF9pc1BsYWluT2JqZWN0LCBfaXNQcmltaXRpdmUsIF9QcmltaXRpdmUsIGdldE5vZGVUeXBlQW5kS2V5IH0gZnJvbSBcIm1vYngtYm9uc2FpXCJcbmltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uLy4uL2Vycm9yL2ZhaWx1cmVcIlxuaW1wb3J0IHsgWWpzVmFsdWUgfSBmcm9tIFwiLi4veWpzVHlwZXMvdHlwZXNcIlxuXG4vKipcbiAqIENvbnZlcnRzIGEgcGxhaW4gdmFsdWUgdG8gYSBZLmpzIHZhbHVlLlxuICogT2JqZWN0cyBhcmUgY29udmVydGVkIHRvIFkuTWFwcywgYXJyYXlzIHRvIFkuQXJyYXlzLCBwcmltaXRpdmVzIGFyZSB1bnRvdWNoZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlPFQgZXh0ZW5kcyBfUHJpbWl0aXZlPih2OiBUKTogVFxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUodjogcmVhZG9ubHkgYW55W10pOiBZLkFycmF5PFlqc1ZhbHVlPlxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUodjogUmVhZG9ubHk8UmVjb3JkPHN0cmluZywgYW55Pj4pOiBZLk1hcDxZanNWYWx1ZT5cblxuZXhwb3J0IGZ1bmN0aW9uIGNvbnZlcnRQbGFpblRvWWpzVmFsdWUodjogYW55KTogWWpzVmFsdWUge1xuICBpZiAoX2lzUHJpbWl0aXZlKHYpKSB7XG4gICAgcmV0dXJuIHZcbiAgfVxuXG4gIGlmIChfaXNBcnJheSh2KSkge1xuICAgIGNvbnN0IGFyciA9IG5ldyBZLkFycmF5PFlqc1ZhbHVlPigpXG4gICAgYXBwbHlQbGFpbkFycmF5VG9ZQXJyYXkoYXJyLCB2KVxuICAgIHJldHVybiBhcnIgYXMgWWpzVmFsdWVcbiAgfVxuXG4gIGlmIChfaXNQbGFpbk9iamVjdCh2KSB8fCBpc09ic2VydmFibGVPYmplY3QodikpIHtcbiAgICBjb25zdCBmcm96ZW5EYXRhID0gISFnZXROb2RlVHlwZUFuZEtleSh2KS50eXBlPy5pc0Zyb3plblxuICAgIGlmIChmcm96ZW5EYXRhKSB7XG4gICAgICByZXR1cm4gdiAvLyBzdG9yZSBhcyBpc1xuICAgIH1cblxuICAgIGNvbnN0IG1hcCA9IG5ldyBZLk1hcDxZanNWYWx1ZT4oKVxuICAgIGFwcGx5UGxhaW5PYmplY3RUb1lNYXAobWFwLCB2KVxuICAgIHJldHVybiBtYXAgYXMgWWpzVmFsdWVcbiAgfVxuXG4gIHRocm93IGZhaWx1cmUoYHVuc3VwcG9ydGVkIHZhbHVlIHR5cGU6ICR7dn1gKVxufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBwbGFpbiBhcnJheSB0byBhIFkuQXJyYXksIHVzaW5nIHRoZSBjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlIHRvIGNvbnZlcnQgdGhlIHZhbHVlcy5cbiAqXG4gKiBAcGFyYW0gZGVzdCAtIFRoZSBZLmpzIEFycmF5IHRoYXQgd2lsbCByZWNlaXZlIHRoZSBjb252ZXJ0ZWQgdmFsdWVzLlxuICogQHBhcmFtIHNvdXJjZSAtIFRoZSBwbGFpbiBKYXZhU2NyaXB0IGFycmF5IHdob3NlIHZhbHVlcyB3aWxsIGJlIGNvbnZlcnRlZCBhbmQgcHVzaGVkIHRvIHRoZSBkZXN0aW5hdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IGFwcGx5UGxhaW5BcnJheVRvWUFycmF5ID0gKGRlc3Q6IFkuQXJyYXk8YW55Piwgc291cmNlOiByZWFkb25seSBhbnlbXSkgPT4ge1xuICBjb25zdCB5anNWYWxzID0gc291cmNlLm1hcChjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlKVxuICBkZXN0LnB1c2goeWpzVmFscylcbn1cblxuLyoqXG4gKiBBcHBsaWVzIGEgcGxhaW4gb2JqZWN0IHRvIGEgWS5NYXAsIHVzaW5nIHRoZSBjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlIHRvIGNvbnZlcnQgdGhlIHZhbHVlcy5cbiAqXG4gKiBAcGFyYW0gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBZLk1hcCB3aGVyZSB0aGUgcHJvcGVydGllcyB3aWxsIGJlIHNldFxuICogQHBhcmFtIHNvdXJjZSAtIFRoZSBwbGFpbiBKYXZhU2NyaXB0IG9iamVjdCB3aG9zZSBwcm9wZXJ0aWVzIHdpbGwgYmUgYXBwbGllZCB0byB0aGUgWS5NYXBcbiAqL1xuZXhwb3J0IGNvbnN0IGFwcGx5UGxhaW5PYmplY3RUb1lNYXAgPSAoZGVzdDogWS5NYXA8YW55Piwgc291cmNlOiBSZWFkb25seTxSZWNvcmQ8c3RyaW5nLCBhbnk+PikgPT4ge1xuICBPYmplY3QuZW50cmllcyhzb3VyY2UpLmZvckVhY2goKFtrLCB2XSkgPT4ge1xuICAgIGNvbnN0IHlqc1ZhbCA9IGNvbnZlcnRQbGFpblRvWWpzVmFsdWUodilcbiAgICBkZXN0LnNldChrLCB5anNWYWwpXG4gIH0pXG59XG4iLCJpbXBvcnQgeyB3aGVuIH0gZnJvbSBcIm1vYnhcIlxuaW1wb3J0IHsgX2J1aWxkTm9kZUZ1bGxQYXRoLCBOb2RlQ2hhbmdlLCBvbkRlZXBDaGFuZ2UgfSBmcm9tIFwibW9ieC1ib25zYWlcIlxuaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi4vLi4vZXJyb3IvZmFpbHVyZVwiXG5pbXBvcnQgeyBZanNTdHJ1Y3R1cmUgfSBmcm9tIFwiLi4veWpzVHlwZXMvdHlwZXNcIlxuaW1wb3J0IHsgY29udmVydFBsYWluVG9ZanNWYWx1ZSB9IGZyb20gXCIuL2NvbnZlcnRQbGFpblRvWWpzVmFsdWVcIlxuaW1wb3J0IHsgcmVzb2x2ZVlqc1N0cnVjdHVyZVBhdGggfSBmcm9tIFwiLi9yZXNvbHZlWWpzU3RydWN0dXJlUGF0aFwiXG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cE5vZGVUb1lqc1JlcGxpY2F0aW9uKHtcbiAgbm9kZSxcbiAgeWpzRG9jLFxuICB5anNPYmplY3QsXG4gIHlqc09yaWdpbkdldHRlcixcbiAgeWpzT3JpZ2luQ2FjaGUsXG4gIHlqc1JlcGxpY2F0aW5nUmVmLFxufToge1xuICBub2RlOiBvYmplY3RcbiAgeWpzRG9jOiBZLkRvY1xuICB5anNPYmplY3Q6IFlqc1N0cnVjdHVyZVxuICB5anNPcmlnaW5HZXR0ZXI6ICgpID0+IHN5bWJvbFxuICB5anNPcmlnaW5DYWNoZTogV2Vha1NldDxzeW1ib2w+XG4gIHlqc1JlcGxpY2F0aW5nUmVmOiB7IGN1cnJlbnQ6IG51bWJlciB9XG59KSB7XG4gIGxldCBwZW5kaW5nTW9ieENoYW5nZXM6IHtcbiAgICBjaGFuZ2U6IE5vZGVDaGFuZ2VcbiAgICBwYXRoOiBzdHJpbmdbXVxuICB9W10gPSBbXVxuICBsZXQgbW9ieERlZXBDaGFuZ2VzTmVzdGluZ0xldmVsID0gMFxuXG4gIGNvbnN0IGRpc3Bvc2VPbkRlZXBDaGFuZ2UgPSBvbkRlZXBDaGFuZ2Uobm9kZSwgKGNoYW5nZSkgPT4ge1xuICAgIC8vIGlmIHRoaXMgY29tZXMgZnJvbSBhIHlqcyBjaGFuZ2UsIGlnbm9yZSBpdFxuICAgIGlmICh5anNSZXBsaWNhdGluZ1JlZi5jdXJyZW50ID4gMCkge1xuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgbW9ieERlZXBDaGFuZ2VzTmVzdGluZ0xldmVsKytcbiAgICBjb25zdCBwYXRoID0gX2J1aWxkTm9kZUZ1bGxQYXRoKGNoYW5nZS5vYmplY3QpXG4gICAgcGVuZGluZ01vYnhDaGFuZ2VzLnB1c2goeyBjaGFuZ2UsIHBhdGggfSlcblxuICAgIC8vIGhhY2sgdG8gYXBwbHkgcGVuZGluZyBtb2J4IGNoYW5nZXMgb25jZSBhbGwgYWN0aW9ucyBhbmQgcmVhY3Rpb25zIGFyZSBmaW5pc2hlZFxuICAgIHdoZW4oXG4gICAgICAoKSA9PiB0cnVlLFxuICAgICAgKCkgPT4ge1xuICAgICAgICBtb2J4RGVlcENoYW5nZXNOZXN0aW5nTGV2ZWwtLVxuICAgICAgICBpZiAobW9ieERlZXBDaGFuZ2VzTmVzdGluZ0xldmVsID09PSAwKSB7XG4gICAgICAgICAgY29uc3QgeWpzT3JpZ2luID0geWpzT3JpZ2luR2V0dGVyKClcbiAgICAgICAgICB5anNPcmlnaW5DYWNoZS5hZGQoeWpzT3JpZ2luKVxuXG4gICAgICAgICAgeWpzRG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG1vYnhDaGFuZ2VzVG9BcHBseSA9IHBlbmRpbmdNb2J4Q2hhbmdlc1xuICAgICAgICAgICAgcGVuZGluZ01vYnhDaGFuZ2VzID0gW11cbiAgICAgICAgICAgIG1vYnhDaGFuZ2VzVG9BcHBseS5mb3JFYWNoKCh7IGNoYW5nZSwgcGF0aCB9KSA9PiB7XG4gICAgICAgICAgICAgIGNvbnN0IHlqc1RhcmdldCA9IHJlc29sdmVZanNTdHJ1Y3R1cmVQYXRoKHlqc09iamVjdCwgcGF0aClcblxuICAgICAgICAgICAgICAvLyBub3cgeS5qcyBhbmQgbW9ieCBzaG91bGQgYmUgaW4gdGhlIHNhbWUgdGFyZ2V0XG5cbiAgICAgICAgICAgICAgLy8gSW4gTW9iWCA1LCBvYnNlcnZhYmxlS2luZCBkb2Vzbid0IGV4aXN0LCBidXQgd2UgY2FuIGNoZWNrIGZvciB0aGUgcHJlc2VuY2Ugb2YgJ25hbWUnIHZzICdpbmRleCdcbiAgICAgICAgICAgICAgLy8gdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiBvYmplY3QgYW5kIGFycmF5IGNoYW5nZXNcbiAgICAgICAgICAgICAgY29uc3QgaXNPYmplY3RDaGFuZ2UgPSBcIm5hbWVcIiBpbiBjaGFuZ2VcblxuICAgICAgICAgICAgICBpZiAoaXNPYmplY3RDaGFuZ2UpIHtcbiAgICAgICAgICAgICAgICBpZiAoISh5anNUYXJnZXQgaW5zdGFuY2VvZiBZLk1hcCkpIHtcbiAgICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoXCJ5anMgdGFyZ2V0IHdhcyBleHBlY3RlZCB0byBiZSBhIG1hcFwiKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCB5anNNYXAgPSB5anNUYXJnZXRcblxuICAgICAgICAgICAgICAgIHN3aXRjaCAoY2hhbmdlLnR5cGUpIHtcbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJhZGRcIjpcbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJ1cGRhdGVcIjpcbiAgICAgICAgICAgICAgICAgICAgeWpzTWFwLnNldChTdHJpbmcoY2hhbmdlLm5hbWUpLCBjb252ZXJ0UGxhaW5Ub1lqc1ZhbHVlKGNoYW5nZS5uZXdWYWx1ZSkpXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJyZW1vdmVcIjpcbiAgICAgICAgICAgICAgICAgICAgeWpzTWFwLmRlbGV0ZShTdHJpbmcoY2hhbmdlLm5hbWUpKVxuICAgICAgICAgICAgICAgICAgICBicmVha1xuXG4gICAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBmYWlsdXJlKGB1bnN1cHBvcnRlZCBtb2J4IG9iamVjdCBjaGFuZ2UgdHlwZWApXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIEFycmF5IGNoYW5nZVxuICAgICAgICAgICAgICAgIGlmICghKHlqc1RhcmdldCBpbnN0YW5jZW9mIFkuQXJyYXkpKSB7XG4gICAgICAgICAgICAgICAgICB0aHJvdyBmYWlsdXJlKFwieWpzIHRhcmdldCB3YXMgZXhwZWN0ZWQgdG8gYmUgYW4gYXJyYXlcIilcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgeWpzQXJyYXkgPSB5anNUYXJnZXRcblxuICAgICAgICAgICAgICAgIHN3aXRjaCAoY2hhbmdlLnR5cGUpIHtcbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJ1cGRhdGVcIjoge1xuICAgICAgICAgICAgICAgICAgICB5anNBcnJheS5kZWxldGUoY2hhbmdlLmluZGV4LCAxKVxuICAgICAgICAgICAgICAgICAgICB5anNBcnJheS5pbnNlcnQoY2hhbmdlLmluZGV4LCBbY29udmVydFBsYWluVG9ZanNWYWx1ZShjaGFuZ2UubmV3VmFsdWUpXSlcbiAgICAgICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgY2FzZSBcInNwbGljZVwiOiB7XG4gICAgICAgICAgICAgICAgICAgIHlqc0FycmF5LmRlbGV0ZShjaGFuZ2UuaW5kZXgsIGNoYW5nZS5yZW1vdmVkQ291bnQpXG4gICAgICAgICAgICAgICAgICAgIHlqc0FycmF5Lmluc2VydChjaGFuZ2UuaW5kZXgsIGNoYW5nZS5hZGRlZC5tYXAoY29udmVydFBsYWluVG9ZanNWYWx1ZSkpXG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoYHVuc3VwcG9ydGVkIG1vYnggYXJyYXkgY2hhbmdlIHR5cGVgKVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICB9LCB5anNPcmlnaW4pXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICApXG4gIH0pXG5cbiAgcmV0dXJuIHtcbiAgICBkaXNwb3NlOiAoKSA9PiB7XG4gICAgICBkaXNwb3NlT25EZWVwQ2hhbmdlKClcbiAgICB9LFxuICB9XG59XG4iLCJpbXBvcnQgeyBub2RlIH0gZnJvbSBcIm1vYngtYm9uc2FpXCJcclxuaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcclxuaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuLi8uLi9lcnJvci9mYWlsdXJlXCJcclxuaW1wb3J0IHsgWWpzU3RydWN0dXJlIH0gZnJvbSBcIi4uL3lqc1R5cGVzL3R5cGVzXCJcclxuXHJcbmV4cG9ydCBmdW5jdGlvbiBjcmVhdGVOb2RlRnJvbVlqc09iamVjdDxUIGV4dGVuZHMgb2JqZWN0Pih5anNPYmplY3Q6IFlqc1N0cnVjdHVyZSk6IFQge1xyXG4gIGlmICh5anNPYmplY3QgaW5zdGFuY2VvZiBZLk1hcCB8fCB5anNPYmplY3QgaW5zdGFuY2VvZiBZLkFycmF5KSB7XHJcbiAgICByZXR1cm4gbm9kZSh5anNPYmplY3QudG9KU09OKCksIHsgc2tpcEluaXQ6IHRydWUgfSkgYXMgdW5rbm93biBhcyBUXHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IGZhaWx1cmUoXCJvbmx5IFkuanMgTWFwIGFuZCBBcnJheSBpbnN0YW5jZXMgY2FuIGJlIGJvdW5kIHRvIG5vZGVzXCIpXHJcbiAgfVxyXG59XHJcbiIsImltcG9ydCB7IGlzT2JzZXJ2YWJsZUFycmF5LCByZW1vdmUsIHJ1bkluQWN0aW9uLCBzZXQgfSBmcm9tIFwibW9ieFwiXG5pbXBvcnQge1xuICBfaXNQcmltaXRpdmUsXG4gIF9QcmltaXRpdmUsXG4gIF9ydW5EZXRhY2hpbmdEdXBsaWNhdGVkTm9kZXMsXG4gIGFzc2VydElzTm9kZSxcbiAgcmVzb2x2ZVBhdGgsXG59IGZyb20gXCJtb2J4LWJvbnNhaVwiXG5pbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgZmFpbHVyZSB9IGZyb20gXCIuLi8uLi9lcnJvci9mYWlsdXJlXCJcbmltcG9ydCB7IFlqc1N0cnVjdHVyZSwgWWpzVmFsdWUgfSBmcm9tIFwiLi4veWpzVHlwZXMvdHlwZXNcIlxuXG5mdW5jdGlvbiB5anNUb1BsYWluVmFsdWU8VCBleHRlbmRzIF9QcmltaXRpdmU+KHY6IFQpOiBUXG5mdW5jdGlvbiB5anNUb1BsYWluVmFsdWUodjogWS5NYXA8YW55Pik6IFJlY29yZDxzdHJpbmcsIGFueT5cbmZ1bmN0aW9uIHlqc1RvUGxhaW5WYWx1ZSh2OiBZLkFycmF5PGFueT4pOiBhbnlbXVxuXG5mdW5jdGlvbiB5anNUb1BsYWluVmFsdWUodjogWWpzVmFsdWUpOiB1bmtub3duIHtcbiAgaWYgKF9pc1ByaW1pdGl2ZSh2KSkge1xuICAgIHJldHVybiB2XG4gIH1cblxuICBpZiAodiBpbnN0YW5jZW9mIFkuTWFwIHx8IHYgaW5zdGFuY2VvZiBZLkFycmF5KSB7XG4gICAgcmV0dXJuIHYudG9KU09OKClcbiAgfVxuXG4gIHRocm93IGZhaWx1cmUoYHVuc3VwcG9ydGVkIFkuanMgdmFsdWUgdHlwZTogJHt2fWApXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cFlqc1RvTm9kZVJlcGxpY2F0aW9uKHtcbiAgbm9kZSxcbiAgeWpzT2JqZWN0LFxuICB5anNPcmlnaW5DYWNoZSxcbiAgeWpzUmVwbGljYXRpbmdSZWYsXG59OiB7XG4gIG5vZGU6IG9iamVjdFxuICB5anNPYmplY3Q6IFlqc1N0cnVjdHVyZVxuICB5anNPcmlnaW5DYWNoZTogV2Vha1NldDxzeW1ib2w+XG4gIHlqc1JlcGxpY2F0aW5nUmVmOiB7IGN1cnJlbnQ6IG51bWJlciB9XG59KSB7XG4gIGNvbnN0IHlqc09ic2VydmVyQ2FsbGJhY2sgPSAoZXZlbnRzOiBZLllFdmVudDxhbnk+W10sIHRyYW5zYWN0aW9uOiBZLlRyYW5zYWN0aW9uKSA9PiB7XG4gICAgaWYgKGV2ZW50cy5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIGlmIGl0IGNvbWVzIGZyb20gYSBtb2J4LWJvbnNhaS15anMgY2hhbmdlLCBpZ25vcmUgaXRcbiAgICBpZiAoeWpzT3JpZ2luQ2FjaGUuaGFzKHRyYW5zYWN0aW9uLm9yaWdpbikpIHtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIC8vIGxvY2sgdG8gZW5zdXJlIG1vYnggY2hhbmdlcyBkb24ndCB0cmlnZ2VyIHlqcyBjaGFuZ2VzIGFnYWluXG4gICAgeWpzUmVwbGljYXRpbmdSZWYuY3VycmVudCsrXG5cbiAgICB0cnkge1xuICAgICAgcnVuSW5BY3Rpb24oKCkgPT4ge1xuICAgICAgICBfcnVuRGV0YWNoaW5nRHVwbGljYXRlZE5vZGVzKCgpID0+IHtcbiAgICAgICAgICBldmVudHMuZm9yRWFjaCgoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHJlc29sdXRpb25SZXN1bHQgPSByZXNvbHZlUGF0aChub2RlLCBldmVudC5wYXRoKVxuICAgICAgICAgICAgaWYgKCFyZXNvbHV0aW9uUmVzdWx0LnJlc29sdmVkKSB7XG4gICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoXG4gICAgICAgICAgICAgICAgYGZhaWxlZCB0byByZXNvbHZlIG5vZGUgcGF0aCBmb3IgeWpzIGV2ZW50OiAke0pTT04uc3RyaW5naWZ5KGV2ZW50LnBhdGgpfWBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgbW9ieFRhcmdldCA9IHJlc29sdXRpb25SZXN1bHQudmFsdWVcbiAgICAgICAgICAgIGFzc2VydElzTm9kZShtb2J4VGFyZ2V0LCBcIm1vYnhUYXJnZXRcIilcblxuICAgICAgICAgICAgLy8gbm93IHkuanMgYW5kIG1vYnggc2hvdWxkIGJlIGluIHRoZSBzYW1lIHRhcmdldFxuXG4gICAgICAgICAgICBpZiAoZXZlbnQgaW5zdGFuY2VvZiBZLllNYXBFdmVudCkge1xuICAgICAgICAgICAgICAvLyBEaXJlY3RseSBjaGVjayBpZiBpdCdzIGFuIGFycmF5IChhcnJheXMgYXJlIG9iamVjdHMgdG9vKVxuICAgICAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShtb2J4VGFyZ2V0KSkge1xuICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoXCJtb2J4IHRhcmdldCB3YXMgZXhwZWN0ZWQgdG8gYmUgYW4gb2JqZWN0XCIpXG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICBjb25zdCBtb2J4T2JqZWN0ID0gbW9ieFRhcmdldFxuICAgICAgICAgICAgICBjb25zdCB5anNNYXAgPSBldmVudC50YXJnZXRcblxuICAgICAgICAgICAgICBldmVudC5jaGFuZ2VzLmtleXMuZm9yRWFjaCgoY2hhbmdlLCBrZXkpID0+IHtcbiAgICAgICAgICAgICAgICBzd2l0Y2ggKGNoYW5nZS5hY3Rpb24pIHtcbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJhZGRcIjpcbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJ1cGRhdGVcIjpcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgIC8vIHdlIGhhdmUgdG8gY2hlY2sgYmVjYXVzZSBzb21ldGltZXMgeWpzIHNlbmRzXG4gICAgICAgICAgICAgICAgICAgICAgLy8gYW4gdXBkYXRlIGV2ZW50IGZvciBzb21ldGhpbmcgYWxyZWFkeSB0aGVyZVxuICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHlqc1ZhbHVlID0geWpzVG9QbGFpblZhbHVlKHlqc01hcC5nZXQoa2V5KSlcbiAgICAgICAgICAgICAgICAgICAgICBpZiAoKG1vYnhPYmplY3QgYXMgYW55KVtrZXldICE9PSB5anNWYWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2V0KG1vYnhPYmplY3QsIGtleSwgeWpzVmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICAgICAgICAgICAgICAgIGNhc2UgXCJkZWxldGVcIjpcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgaGF2ZSB0byBjaGVjayBiZWNhdXNlIHNvbWV0aW1lcyB5anMgc2VuZHNcbiAgICAgICAgICAgICAgICAgICAgLy8gYW4gdXBkYXRlIGV2ZW50IGZvciBzb21ldGhpbmcgYWxyZWFkeSB0aGVyZVxuICAgICAgICAgICAgICAgICAgICBpZiAoKG1vYnhPYmplY3QgYXMgYW55KVtrZXldICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICByZW1vdmUobW9ieE9iamVjdCwga2V5KVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG5cbiAgICAgICAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoYHVuc3VwcG9ydGVkIFlqcyBtYXAgZXZlbnQgYWN0aW9uOiAke2NoYW5nZS5hY3Rpb259YClcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGV2ZW50IGluc3RhbmNlb2YgWS5ZQXJyYXlFdmVudCkge1xuICAgICAgICAgICAgICBpZiAoIWlzT2JzZXJ2YWJsZUFycmF5KG1vYnhUYXJnZXQpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcIm1vYnggdGFyZ2V0IHdhcyBleHBlY3RlZCB0byBiZSBhbiBhcnJheVwiKVxuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgY29uc3QgbW9ieEFycmF5ID0gbW9ieFRhcmdldFxuICAgICAgICAgICAgICBsZXQgcmV0YWluID0gMFxuXG4gICAgICAgICAgICAgIGV2ZW50LmNoYW5nZXMuZGVsdGEuZm9yRWFjaCgoY2hhbmdlKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGNoYW5nZS5yZXRhaW4pIHtcbiAgICAgICAgICAgICAgICAgIHJldGFpbiArPSBjaGFuZ2UucmV0YWluXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGNoYW5nZS5kZWxldGUpIHtcbiAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBYIGl0ZW1zIGF0IHJldGFpbiBwb3NpdGlvblxuICAgICAgICAgICAgICAgICAgbW9ieEFycmF5LnNwbGljZShyZXRhaW4sIGNoYW5nZS5kZWxldGUpXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGNoYW5nZS5pbnNlcnQpIHtcbiAgICAgICAgICAgICAgICAgIGNvbnN0IG5ld1ZhbHVlcyA9IEFycmF5LmlzQXJyYXkoY2hhbmdlLmluc2VydCkgPyBjaGFuZ2UuaW5zZXJ0IDogW2NoYW5nZS5pbnNlcnRdXG4gICAgICAgICAgICAgICAgICBtb2J4QXJyYXkuc3BsaWNlKHJldGFpbiwgMCwgLi4ubmV3VmFsdWVzLm1hcCgodikgPT4geWpzVG9QbGFpblZhbHVlKHYpKSlcbiAgICAgICAgICAgICAgICAgIHJldGFpbiArPSBuZXdWYWx1ZXMubGVuZ3RoXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcInVuc3VwcG9ydGVkIFkuanMgZXZlbnQgdHlwZVwiKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0pXG4gICAgICAgIH0pXG4gICAgICB9KVxuICAgIH0gZmluYWxseSB7XG4gICAgICB5anNSZXBsaWNhdGluZ1JlZi5jdXJyZW50LS1cbiAgICB9XG4gIH1cblxuICB5anNPYmplY3Qub2JzZXJ2ZURlZXAoeWpzT2JzZXJ2ZXJDYWxsYmFjaylcblxuICByZXR1cm4ge1xuICAgIGRpc3Bvc2U6ICgpID0+IHtcbiAgICAgIHlqc09iamVjdC51bm9ic2VydmVEZWVwKHlqc09ic2VydmVyQ2FsbGJhY2spXG4gICAgfSxcbiAgfVxufVxuIiwiaW1wb3J0IHsgYWN0aW9uIH0gZnJvbSBcIm1vYnhcIlxuaW1wb3J0IHtcbiAgX0Rpc3Bvc2UsXG4gIF9kaXNwb3NlT25jZSxcbiAgZ2V0Tm9kZVR5cGVBbmRLZXksXG4gIGdldFBhcmVudFRvQ2hpbGRQYXRoLFxuICBOb2RlV2l0aEFueVR5cGUsXG4gIFdhbGtUcmVlTW9kZSxcbiAgd2Fsa1RyZWUsXG59IGZyb20gXCJtb2J4LWJvbnNhaVwiXG5pbXBvcnQgdHlwZSAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyByZXNvbHZlWWpzU3RydWN0dXJlUGF0aCB9IGZyb20gXCIuL25vZGVUb1lqcy9yZXNvbHZlWWpzU3RydWN0dXJlUGF0aFwiXG5pbXBvcnQgeyBzZXR1cE5vZGVUb1lqc1JlcGxpY2F0aW9uIH0gZnJvbSBcIi4vbm9kZVRvWWpzL3NldHVwTm9kZVRvWWpzUmVwbGljYXRpb25cIlxuaW1wb3J0IHsgY3JlYXRlTm9kZUZyb21ZanNPYmplY3QgfSBmcm9tIFwiLi95anNUb05vZGUvY3JlYXRlTm9kZUZyb21ZanNPYmplY3RcIlxuaW1wb3J0IHsgc2V0dXBZanNUb05vZGVSZXBsaWNhdGlvbiB9IGZyb20gXCIuL3lqc1RvTm9kZS9zZXR1cFlqc1RvTm9kZVJlcGxpY2F0aW9uXCJcbmltcG9ydCB7IFlqc1N0cnVjdHVyZSB9IGZyb20gXCIuL3lqc1R5cGVzL3R5cGVzXCJcblxuLyoqXG4gKiBDcmVhdGVzIGEgbm9kZSB0aGF0IGlzIGJvdW5kIHRvIGEgWS5qcyBkYXRhIHN0cnVjdHVyZS5cbiAqIFkuanMgTWFwIGFuZCBBcnJheSBpbnN0YW5jZXMgYXJlIGJvdW5kIHRvIE1vYlggb2JqZWN0cyBhbmQgYXJyYXlzLCByZXNwZWN0aXZlbHkuXG4gKi9cbmV4cG9ydCBjb25zdCBiaW5kWWpzVG9Ob2RlID0gYWN0aW9uKFxuICA8VCBleHRlbmRzIG9iamVjdD4oe1xuICAgIHlqc0RvYyxcbiAgICB5anNPYmplY3QsXG4gICAgeWpzT3JpZ2luLFxuICB9OiB7XG4gICAgLyoqXG4gICAgICogVGhlIFkuanMgZG9jdW1lbnQuXG4gICAgICovXG4gICAgeWpzRG9jOiBZLkRvY1xuXG4gICAgLyoqXG4gICAgICogVGhlIFkuanMgZGF0YSBzdHJ1Y3R1cmUgdG8gYmluZC5cbiAgICAgKi9cbiAgICB5anNPYmplY3Q6IFlqc1N0cnVjdHVyZVxuXG4gICAgLyoqXG4gICAgICogVGhlIFkuanMgb3JpZ2luIHN5bWJvbCB1c2VkIGZvciBiaW5kaW5nIHRyYW5zYWN0aW9ucywgb3IgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIHN5bWJvbC5cbiAgICAgKiBPbmUgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGdlbmVyYXRlZCBpZiBub3QgcHJvdmlkZWQuXG4gICAgICovXG4gICAgeWpzT3JpZ2luPzogc3ltYm9sIHwgKCgpID0+IHN5bWJvbClcbiAgfSk6IHtcbiAgICAvKipcbiAgICAgKiBUaGUgYm91bmQgbm9kZS5cbiAgICAgKi9cbiAgICBub2RlOiBUXG5cbiAgICAvKipcbiAgICAgKiBSZXNvbHZlcyB0aGUgY29ycmVzcG9uZGluZyBZLmpzIHZhbHVlIGZvciBhIGdpdmVuIHRhcmdldCBub2RlLlxuICAgICAqXG4gICAgICogQHBhcmFtIG5vZGUgLSBUaGUgbm9kZSB0byByZXNvbHZlIGluIHRoZSBib3VuZCBZanMgc3RydWN0dXJlLlxuICAgICAqIEByZXR1cm5zIFRoZSByZXNvbHZlZCBZLmpzIHZhbHVlLlxuICAgICAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIHRhcmdldCBub2RlIGlzIG5vdCBmb3VuZCBpbiB0aGUgYm91bmQgdHJlZS5cbiAgICAgKi9cbiAgICBnZXRZanNWYWx1ZUZvck5vZGU6IChub2RlOiBvYmplY3QpID0+IHVua25vd25cblxuICAgIC8qKlxuICAgICAqIERpc3Bvc2VzIHRoZSBiaW5kaW5nLlxuICAgICAqL1xuICAgIGRpc3Bvc2U6IF9EaXNwb3NlXG5cbiAgICAvKipcbiAgICAgKiBEaXNwb3NlcyB0aGUgYmluZGluZy5cbiAgICAgKi9cbiAgICBbU3ltYm9sLmRpc3Bvc2VdKCk6IHZvaWRcbiAgfSA9PiB7XG4gICAgeWpzT3JpZ2luID0geWpzT3JpZ2luID8/IFN5bWJvbChcIm1vYngtYm9uc2FpLXlqcy1vcmlnaW5cIilcblxuICAgIC8vIENvbnZlcnQgeWpzT3JpZ2luIHRvIGEgZ2V0dGVyIGZ1bmN0aW9uIGlmIGl0J3MgYSBwbGFpbiBzeW1ib2xcbiAgICBjb25zdCB5anNPcmlnaW5HZXR0ZXIgPSB0eXBlb2YgeWpzT3JpZ2luID09PSBcImZ1bmN0aW9uXCIgPyB5anNPcmlnaW4gOiAoKSA9PiB5anNPcmlnaW5cblxuICAgIGNvbnN0IG5vZGUgPSBjcmVhdGVOb2RlRnJvbVlqc09iamVjdDxUPih5anNPYmplY3QpXG5cbiAgICBjb25zdCB5anNSZXBsaWNhdGluZ1JlZiA9IHsgY3VycmVudDogMCB9XG5cbiAgICBjb25zdCB5anNPcmlnaW5DYWNoZSA9IG5ldyBXZWFrU2V0PHN5bWJvbD4oKVxuXG4gICAgY29uc3QgeWpzVG9Ob2RlUmVwbGljYXRpb25BZG1pbiA9IHNldHVwWWpzVG9Ob2RlUmVwbGljYXRpb24oe1xuICAgICAgbm9kZTogbm9kZSxcbiAgICAgIHlqc09iamVjdCxcbiAgICAgIHlqc09yaWdpbkNhY2hlLFxuICAgICAgeWpzUmVwbGljYXRpbmdSZWYsXG4gICAgfSlcblxuICAgIGNvbnN0IG5vZGVUb1lqc1JlcGxpY2F0aW9uQWRtaW4gPSBzZXR1cE5vZGVUb1lqc1JlcGxpY2F0aW9uKHtcbiAgICAgIG5vZGU6IG5vZGUsXG4gICAgICB5anNEb2MsXG4gICAgICB5anNPYmplY3QsXG4gICAgICB5anNPcmlnaW5HZXR0ZXIsXG4gICAgICB5anNPcmlnaW5DYWNoZSxcbiAgICAgIHlqc1JlcGxpY2F0aW5nUmVmLFxuICAgIH0pXG5cbiAgICAvLyBydW4gbm9kZSBpbml0aWFsaXphdGlvbiBjYWxsYmFja3MgaGVyZSwgbGF0ZXIsIHRvIHN5bmMgY2hhbmdlc1xuICAgIHdhbGtUcmVlKFxuICAgICAgbm9kZSxcbiAgICAgIChuKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgdHlwZSB9ID0gZ2V0Tm9kZVR5cGVBbmRLZXkobilcbiAgICAgICAgdHlwZT8uX2luaXROb2RlKG4gYXMgTm9kZVdpdGhBbnlUeXBlKVxuICAgICAgfSxcbiAgICAgIFdhbGtUcmVlTW9kZS5DaGlsZHJlbkZpcnN0XG4gICAgKVxuXG4gICAgY29uc3QgcmV0ID0ge1xuICAgICAgbm9kZSxcblxuICAgICAgZ2V0WWpzVmFsdWVGb3JOb2RlOiAodGFyZ2V0OiBvYmplY3QpID0+IHtcbiAgICAgICAgaWYgKHRhcmdldCA9PT0gbm9kZSkge1xuICAgICAgICAgIHJldHVybiB5anNPYmplY3RcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwYXRoID0gZ2V0UGFyZW50VG9DaGlsZFBhdGgobm9kZSwgdGFyZ2V0KVxuICAgICAgICBpZiAoIXBhdGgpIHtcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJub2RlIG5vdCBmb3VuZCBpbiB0aGUgYm91bmQgdHJlZVwiKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXNvbHZlWWpzU3RydWN0dXJlUGF0aCh5anNPYmplY3QsIHBhdGgpXG4gICAgICB9LFxuXG4gICAgICBkaXNwb3NlOiBfZGlzcG9zZU9uY2UoKCkgPT4ge1xuICAgICAgICBub2RlVG9ZanNSZXBsaWNhdGlvbkFkbWluLmRpc3Bvc2UoKVxuICAgICAgICB5anNUb05vZGVSZXBsaWNhdGlvbkFkbWluLmRpc3Bvc2UoKVxuICAgICAgfSksXG5cbiAgICAgIFtTeW1ib2wuZGlzcG9zZV06ICgpID0+IHtcbiAgICAgICAgcmV0LmRpc3Bvc2UoKVxuICAgICAgfSxcbiAgICB9XG5cbiAgICByZXR1cm4gcmV0XG4gIH1cbilcbiJdLCJuYW1lcyI6WyJub2RlIiwiY2hhbmdlIiwicGF0aCJdLCJtYXBwaW5ncyI6Ijs7O0FBR08sTUFBTSwyQkFBMkIsTUFBTTtBQUFBLEVBQzVDLFlBQVksS0FBYTtBQUN2QixVQUFNLEdBQUc7QUFHVCxXQUFPLGVBQWUsTUFBTSxtQkFBbUIsU0FBUztBQUFBLEVBQzFEO0FBQ0Y7QUNSTyxTQUFTLFFBQVEsS0FBYTtB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