mobx-keystone-yjs
Version:
Yjs bindings for mobx-keystone
759 lines (758 loc) • 103 kB
JavaScript
(function(global, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("mobx"), require("mobx-keystone"), require("yjs")) : typeof define === "function" && define.amd ? define(["exports", "mobx", "mobx-keystone", "yjs"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global["mobx-keystone-yjs"] = {}, global.mobx, global["mobx-keystone"], global.yjs));
})(this, (function(exports2, mobx, mobxKeystone, Y) {
"use strict";var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
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 MobxKeystoneYjsError extends Error {
constructor(msg) {
super(msg);
Object.setPrototypeOf(this, MobxKeystoneYjsError.prototype);
}
}
function failure(msg) {
return new MobxKeystoneYjsError(msg);
}
const yjsCollectionAtoms = /* @__PURE__ */ new WeakMap();
const getYjsCollectionAtom = (yjsCollection) => {
return yjsCollectionAtoms.get(yjsCollection);
};
const getOrCreateYjsCollectionAtom = (yjsCollection) => {
let atom = yjsCollectionAtoms.get(yjsCollection);
if (!atom) {
atom = mobx.createAtom(`yjsCollectionAtom`);
yjsCollectionAtoms.set(yjsCollection, atom);
}
return atom;
};
function isYjsValueDeleted(yjsValue) {
var _a, _b;
if (yjsValue instanceof Y__namespace.AbstractType) {
return !!((_a = yjsValue._item) == null ? void 0 : _a.deleted) || !!((_b = yjsValue.doc) == null ? void 0 : _b.isDestroyed);
}
return false;
}
function resolveYjsPath(yjsObject, path) {
let currentYjsObject = yjsObject;
let i = -1;
for (const pathPart of path) {
i++;
if (currentYjsObject instanceof Y__namespace.Text) {
return currentYjsObject;
}
if (currentYjsObject instanceof Y__namespace.Map) {
getOrCreateYjsCollectionAtom(currentYjsObject).reportObserved();
const key = String(pathPart);
currentYjsObject = currentYjsObject.get(key);
} else if (currentYjsObject instanceof Y__namespace.Array) {
getOrCreateYjsCollectionAtom(currentYjsObject).reportObserved();
const key = Number(pathPart);
currentYjsObject = currentYjsObject.get(key);
} 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 ${currentYjsObject} instead`
);
}
}
return currentYjsObject;
}
const yjsBindingContext = mobxKeystone.createContext(void 0);
var __defProp2 = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __decorateClass = (decorators, target, key, kind) => {
var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
for (var i = decorators.length - 1, decorator; i >= 0; i--)
if (decorator = decorators[i])
result = (kind ? decorator(target, key, result) : decorator(result)) || result;
if (kind && result) __defProp2(target, key, result);
return result;
};
const deltaListType = mobxKeystone.types.array(mobxKeystone.types.frozen(mobxKeystone.types.unchecked()));
const yjsTextModelId = "mobx-keystone-yjs/YjsTextModel";
exports2.YjsTextModel = class YjsTextModel extends mobxKeystone.Model({
deltaList: mobxKeystone.tProp(deltaListType, () => [])
}) {
constructor() {
super(...arguments);
/**
* Atom that gets changed when the associated Y.js text changes.
*/
__publicField(this, "yjsTextChangedAtom", mobx.createAtom("yjsTextChangedAtom"));
}
/**
* Helper function to create a YjsTextModel instance with a simple text.
*/
static withText(text) {
return new DecoratedYjsTextModel({
deltaList: [
mobxKeystone.frozen([
{
insert: text
}
])
]
});
}
get _yjsObjectPath() {
const ctx = yjsBindingContext.get(this);
if ((ctx == null ? void 0 : ctx.boundObject) == null) {
throw failure(
"the YjsTextModel instance must be part of a bound object before it can be accessed"
);
}
const path = mobxKeystone.getParentToChildPath(ctx.boundObject, this);
if (!path) {
throw failure("a path from the bound object to the YjsTextModel instance is not available");
}
return path;
}
get _yjsObjectAtPath() {
const path = this._yjsObjectPath;
const ctx = yjsBindingContext.get(this);
return resolveYjsPath(ctx.yjsObject, path);
}
get yjsText() {
const yjsObject = this._yjsObjectAtPath;
if (!(yjsObject instanceof Y__namespace.Text)) {
throw failure(`Y.Text was expected at path ${JSON.stringify(this._yjsObjectPath)}`);
}
return yjsObject;
}
get text() {
this.yjsTextChangedAtom.reportObserved();
const ctx = yjsBindingContext.get(this);
if ((ctx == null ? void 0 : ctx.boundObject) != null) {
try {
const yjsTextString = this.yjsText.toString();
if (yjsTextString !== "" || this.deltaList.length === 0) {
return yjsTextString;
}
} catch {
}
}
return this.deltaListToText();
}
deltaListToText() {
const doc = new Y__namespace.Doc();
const text = doc.getText();
this.deltaList.forEach((d) => {
text.applyDelta(d.data);
});
return text.toString();
}
onInit() {
const shouldReplicateToYjs = (ctx) => {
return !!ctx && !!ctx.boundObject && !ctx.isApplyingYjsChangesToMobxKeystone;
};
let reapplyDeltasToYjsText = false;
const newDeltas = [];
let disposeObserveDeltaList;
const disposeReactionToDeltaListRefChange = mobx.reaction(
() => this.$.deltaList,
(deltaList) => {
disposeObserveDeltaList == null ? void 0 : disposeObserveDeltaList();
disposeObserveDeltaList = void 0;
disposeObserveDeltaList = mobx.observe(deltaList, (change) => {
if (reapplyDeltasToYjsText) {
return;
}
if (!shouldReplicateToYjs(yjsBindingContext.get(this))) {
return;
}
if (change.type === "splice" && change.removedCount === 0 && change.addedCount > 0 && change.index === this.deltaList.length) {
newDeltas.push(...change.added);
} else {
reapplyDeltasToYjsText = true;
}
});
},
{ fireImmediately: true }
);
const disposeOnSnapshot = mobxKeystone.onSnapshot(this, () => {
try {
if (reapplyDeltasToYjsText) {
const ctx = yjsBindingContext.get(this);
if (shouldReplicateToYjs(ctx)) {
const { yjsText } = this;
if (isYjsValueDeleted(yjsText)) {
throw failure("cannot reapply deltas to deleted Yjs.Text");
}
ctx.yjsDoc.transact(() => {
if (yjsText.length > 0) {
yjsText.delete(0, yjsText.length);
}
this.deltaList.forEach((frozenDeltas) => {
yjsText.applyDelta(frozenDeltas.data);
});
}, ctx.yjsOrigin);
}
} else if (newDeltas.length > 0) {
const ctx = yjsBindingContext.get(this);
if (shouldReplicateToYjs(ctx)) {
const { yjsText } = this;
if (isYjsValueDeleted(yjsText)) {
throw failure("cannot reapply deltas to deleted Yjs.Text");
}
ctx.yjsDoc.transact(() => {
newDeltas.forEach((frozenDeltas) => {
yjsText.applyDelta(frozenDeltas.data);
});
}, ctx.yjsOrigin);
}
}
} finally {
reapplyDeltasToYjsText = false;
newDeltas.length = 0;
}
});
const diposeYjsTextChangedAtom = hookYjsTextChangedAtom(
() => this.yjsText,
this.yjsTextChangedAtom
);
return () => {
disposeOnSnapshot();
disposeReactionToDeltaListRefChange();
disposeObserveDeltaList == null ? void 0 : disposeObserveDeltaList();
disposeObserveDeltaList = void 0;
diposeYjsTextChangedAtom();
};
}
};
__decorateClass([
mobx.computed
], exports2.YjsTextModel.prototype, "_yjsObjectPath", 1);
__decorateClass([
mobx.computed
], exports2.YjsTextModel.prototype, "_yjsObjectAtPath", 1);
__decorateClass([
mobx.computed
], exports2.YjsTextModel.prototype, "yjsText", 1);
__decorateClass([
mobx.computed
], exports2.YjsTextModel.prototype, "text", 1);
exports2.YjsTextModel = __decorateClass([
mobxKeystone.model(yjsTextModelId)
], exports2.YjsTextModel);
const DecoratedYjsTextModel = exports2.YjsTextModel;
function hookYjsTextChangedAtom(getYjsText, textChangedAtom) {
let disposeObserveYjsText;
const observeFn = () => {
textChangedAtom.reportChanged();
};
const disposeReactionToYTextChange = mobx.reaction(
() => {
try {
const yjsText = getYjsText();
return isYjsValueDeleted(yjsText) ? void 0 : yjsText;
} catch {
return void 0;
}
},
(yjsText) => {
disposeObserveYjsText == null ? void 0 : disposeObserveYjsText();
disposeObserveYjsText = void 0;
if (yjsText) {
yjsText.observe(observeFn);
disposeObserveYjsText = () => {
yjsText.unobserve(observeFn);
};
}
textChangedAtom.reportChanged();
},
{
fireImmediately: true
}
);
return () => {
disposeReactionToYTextChange();
disposeObserveYjsText == null ? void 0 : disposeObserveYjsText();
disposeObserveYjsText = void 0;
};
}
const yjsContainerToSnapshot = /* @__PURE__ */ new WeakMap();
function setYjsContainerSnapshot(container, snapshot) {
yjsContainerToSnapshot.set(container, snapshot);
}
function isYjsContainerUpToDate(container, snapshot) {
return yjsContainerToSnapshot.get(container) === snapshot;
}
function isPlainPrimitive(v) {
const t = typeof v;
return t === "string" || t === "number" || t === "boolean" || v === null || v === void 0;
}
function isPlainArray(v) {
return Array.isArray(v);
}
function isPlainObject(v) {
return typeof v === "object" && v !== null && !Array.isArray(v);
}
function convertJsonToYjsData(v) {
if (isPlainPrimitive(v)) {
return v;
}
if (isPlainArray(v)) {
const arr = new Y__namespace.Array();
applyJsonArrayToYArray(arr, v);
return arr;
}
if (isPlainObject(v)) {
if (v[mobxKeystone.frozenKey] === true) {
return v;
}
if (v[mobxKeystone.modelTypeKey] === yjsTextModelId) {
const text = new Y__namespace.Text();
const yjsTextModel = v;
yjsTextModel.deltaList.forEach((frozenDeltas) => {
text.applyDelta(frozenDeltas.data);
});
return text;
}
const map = new Y__namespace.Map();
applyJsonObjectToYMap(map, v);
return map;
}
throw new Error(`unsupported value type: ${v}`);
}
const applyJsonArrayToYArray = (dest, source, options = {}) => {
const { mode = "add" } = options;
if (mode === "merge" && isYjsContainerUpToDate(dest, source)) {
return;
}
const srcLen = source.length;
if (mode === "add") {
for (let i = 0; i < srcLen; i++) {
dest.push([convertJsonToYjsData(source[i])]);
}
return;
}
const destLen = dest.length;
if (destLen > srcLen) {
dest.delete(srcLen, destLen - srcLen);
}
const minLen = Math.min(destLen, srcLen);
for (let i = 0; i < minLen; i++) {
const srcItem = source[i];
const destItem = dest.get(i);
if (isPlainObject(srcItem) && destItem instanceof Y__namespace.Map) {
applyJsonObjectToYMap(destItem, srcItem, options);
continue;
}
if (isPlainArray(srcItem) && destItem instanceof Y__namespace.Array) {
applyJsonArrayToYArray(destItem, srcItem, options);
continue;
}
if (isPlainPrimitive(srcItem) && destItem === srcItem) {
continue;
}
dest.delete(i, 1);
dest.insert(i, [convertJsonToYjsData(srcItem)]);
}
for (let i = destLen; i < srcLen; i++) {
dest.push([convertJsonToYjsData(source[i])]);
}
setYjsContainerSnapshot(dest, source);
};
const applyJsonObjectToYMap = (dest, source, options = {}) => {
const { mode = "add" } = options;
if (mode === "merge" && isYjsContainerUpToDate(dest, source)) {
return;
}
if (mode === "add") {
for (const k of Object.keys(source)) {
const v = source[k];
if (v !== void 0) {
dest.set(k, convertJsonToYjsData(v));
}
}
return;
}
const sourceKeysWithValues = new Set(Object.keys(source).filter((k) => source[k] !== void 0));
for (const key of dest.keys()) {
if (!sourceKeysWithValues.has(key)) {
dest.delete(key);
}
}
for (const k of Object.keys(source)) {
const v = source[k];
if (v === void 0) {
continue;
}
const existing = dest.get(k);
if (isPlainObject(v) && existing instanceof Y__namespace.Map) {
applyJsonObjectToYMap(existing, v, options);
continue;
}
if (isPlainArray(v) && existing instanceof Y__namespace.Array) {
applyJsonArrayToYArray(existing, v, options);
continue;
}
if (isPlainPrimitive(v) && existing === v) {
continue;
}
dest.set(k, convertJsonToYjsData(v));
}
setYjsContainerSnapshot(dest, source);
};
function convertValue(v) {
if (v === null || v === void 0 || typeof v !== "object") {
return v;
}
if (Array.isArray(v) && v.length === 0) {
return new Y__namespace.Array();
}
return convertJsonToYjsData(v);
}
function applyMobxChangeToYjsObject(change, yjsObject) {
if (isYjsValueDeleted(yjsObject)) {
throw failure("cannot apply patch to deleted Yjs value");
}
const yjsContainer = resolveYjsPath(yjsObject, change.path);
if (!yjsContainer) {
return;
}
if (yjsContainer instanceof Y__namespace.Array) {
if (change.type === mobxKeystone.DeepChangeType.ArraySplice) {
yjsContainer.delete(change.index, change.removedValues.length);
if (change.addedValues.length > 0) {
const valuesToInsert = change.addedValues.map(convertValue);
yjsContainer.insert(change.index, valuesToInsert);
}
} else if (change.type === mobxKeystone.DeepChangeType.ArrayUpdate) {
yjsContainer.delete(change.index, 1);
yjsContainer.insert(change.index, [convertValue(change.newValue)]);
} else {
throw failure(`unsupported array change type: ${change.type}`);
}
} else if (yjsContainer instanceof Y__namespace.Map) {
if (change.type === mobxKeystone.DeepChangeType.ObjectAdd || change.type === mobxKeystone.DeepChangeType.ObjectUpdate) {
const key = change.key;
if (change.newValue === void 0) {
yjsContainer.delete(key);
} else {
yjsContainer.set(key, convertValue(change.newValue));
}
} else if (change.type === mobxKeystone.DeepChangeType.ObjectRemove) {
const key = change.key;
yjsContainer.delete(key);
} else {
throw failure(`unsupported object change type: ${change.type}`);
}
} else if (yjsContainer instanceof Y__namespace.Text) {
return;
} else {
throw failure(`unsupported Yjs container type: ${yjsContainer}`);
}
}
const convertYjsDataToJson = mobx.action((yjsData) => {
if (yjsData instanceof Y__namespace.Array) {
return yjsData.map((v) => convertYjsDataToJson(v));
}
if (yjsData instanceof Y__namespace.Map) {
const obj = {};
yjsData.forEach((v, k) => {
obj[k] = convertYjsDataToJson(v);
});
return obj;
}
if (yjsData instanceof Y__namespace.Text) {
const deltas = yjsData.toDelta();
return mobxKeystone.modelSnapshotOutWithMetadata(exports2.YjsTextModel, {
deltaList: deltas.length > 0 ? [{ $frozen: true, data: deltas }] : []
});
}
return yjsData;
});
function applyYjsEventToMobx(event, boundObject, reconciliationMap) {
const path = event.path;
const { value: target } = mobxKeystone.resolvePath(boundObject, path);
if (!target) {
throw failure(`cannot resolve path ${JSON.stringify(path)}`);
}
mobxKeystone.runUnprotected(() => {
if (event instanceof Y__namespace.YMapEvent) {
applyYMapEventToMobx(event, target, reconciliationMap);
} else if (event instanceof Y__namespace.YArrayEvent) {
applyYArrayEventToMobx(event, target, reconciliationMap);
} else if (event instanceof Y__namespace.YTextEvent) {
applyYTextEventToMobx(event, target);
}
});
}
function processDeletedValue(val, reconciliationMap) {
if (val && typeof val === "object" && mobxKeystone.isModel(val)) {
const sn = mobxKeystone.getSnapshot(val);
const id = mobxKeystone.getSnapshotModelId(sn);
if (id) {
reconciliationMap.set(id, val);
}
}
}
function reviveValue(jsonValue, reconciliationMap) {
if (jsonValue === null || typeof jsonValue !== "object") {
return jsonValue;
}
if (mobxKeystone.isFrozenSnapshot(jsonValue)) {
return mobxKeystone.frozen(jsonValue.data);
}
if (reconciliationMap && jsonValue && typeof jsonValue === "object") {
const modelId = mobxKeystone.getSnapshotModelId(jsonValue);
if (modelId) {
const existing = reconciliationMap.get(modelId);
if (existing) {
reconciliationMap.delete(modelId);
return existing;
}
}
}
return mobxKeystone.fromSnapshot(jsonValue);
}
function applyYMapEventToMobx(event, target, reconciliationMap) {
const source = event.target;
event.changes.keys.forEach((change, key) => {
switch (change.action) {
case "add":
case "update": {
const yjsValue = source.get(key);
const jsonValue = convertYjsDataToJson(yjsValue);
if (change.action === "update") {
processDeletedValue(target[key], reconciliationMap);
}
target[key] = reviveValue(jsonValue, reconciliationMap);
break;
}
case "delete": {
processDeletedValue(target[key], reconciliationMap);
if (mobxKeystone.isModel(target)) {
mobx.remove(target.$, key);
} else {
mobx.remove(target, key);
}
break;
}
default:
throw failure(`unsupported Yjs map event action: ${change.action}`);
}
});
}
function applyYArrayEventToMobx(event, target, reconciliationMap) {
let currentIndex = 0;
for (const change of event.changes.delta) {
if (change.retain) {
currentIndex += change.retain;
}
if (change.delete) {
const deletedItems = target.slice(currentIndex, currentIndex + change.delete);
deletedItems.forEach((item) => {
processDeletedValue(item, reconciliationMap);
});
target.splice(currentIndex, change.delete);
}
if (change.insert) {
const insertedItems = Array.isArray(change.insert) ? change.insert : [change.insert];
const values = insertedItems.map((yjsValue) => {
const jsonValue = convertYjsDataToJson(yjsValue);
return reviveValue(jsonValue, reconciliationMap);
});
target.splice(currentIndex, 0, ...values);
currentIndex += values.length;
}
}
}
function applyYTextEventToMobx(event, target) {
if (target == null ? void 0 : target.deltaList) {
target.deltaList.push(mobxKeystone.frozen(event.delta));
}
}
function captureChangeSnapshots(change) {
if (change.type === mobxKeystone.DeepChangeType.ArraySplice && change.addedValues.length > 0) {
const snapshots = change.addedValues.map((v) => mobxKeystone.isTreeNode(v) ? mobxKeystone.getSnapshot(v) : v);
return { ...change, addedValues: snapshots };
} else if (change.type === mobxKeystone.DeepChangeType.ArrayUpdate) {
const snapshot = mobxKeystone.isTreeNode(change.newValue) ? mobxKeystone.getSnapshot(change.newValue) : change.newValue;
return { ...change, newValue: snapshot };
} else if (change.type === mobxKeystone.DeepChangeType.ObjectAdd || change.type === mobxKeystone.DeepChangeType.ObjectUpdate) {
const snapshot = mobxKeystone.isTreeNode(change.newValue) ? mobxKeystone.getSnapshot(change.newValue) : change.newValue;
return { ...change, newValue: snapshot };
}
return change;
}
function bindYjsToMobxKeystone({
yjsDoc,
yjsObject,
mobxKeystoneType
}) {
const yjsOrigin = /* @__PURE__ */ Symbol("bindYjsToMobxKeystoneTransactionOrigin");
let applyingYjsChangesToMobxKeystone = 0;
const bindingContext = {
yjsDoc,
yjsObject,
mobxKeystoneType,
yjsOrigin,
boundObject: void 0,
// not yet created
get isApplyingYjsChangesToMobxKeystone() {
return applyingYjsChangesToMobxKeystone > 0;
}
};
if (isYjsValueDeleted(yjsObject)) {
throw failure("cannot apply patch to deleted Yjs value");
}
const yjsJson = convertYjsDataToJson(yjsObject);
let boundObject;
let hasInitChanges = false;
const createBoundObject = () => {
const disposeGlobalListener = mobxKeystone.onGlobalDeepChange((_target, change) => {
if (change.isInit) {
hasInitChanges = true;
}
});
try {
const result = yjsBindingContext.apply(
() => mobxKeystone.fromSnapshot(mobxKeystoneType, yjsJson),
bindingContext
);
yjsBindingContext.set(result, { ...bindingContext, boundObject: result });
return result;
} finally {
disposeGlobalListener();
}
};
boundObject = createBoundObject();
const observeDeepCb = mobx.action((events) => {
const eventsToApply = [];
events.forEach((event) => {
var _a;
if (event.transaction.origin !== yjsOrigin) {
eventsToApply.push(event);
}
if (event.target instanceof Y__namespace.Map || event.target instanceof Y__namespace.Array) {
(_a = getYjsCollectionAtom(event.target)) == null ? void 0 : _a.reportChanged();
}
});
if (eventsToApply.length > 0) {
applyingYjsChangesToMobxKeystone++;
try {
const reconciliationMap = /* @__PURE__ */ new Map();
const initChanges = [];
const disposeGlobalListener = mobxKeystone.onGlobalDeepChange((target, change) => {
if (change.isInit) {
initChanges.push({ target, change: captureChangeSnapshots(change) });
}
});
try {
eventsToApply.forEach((event) => {
applyYjsEventToMobx(event, boundObject, reconciliationMap);
});
} finally {
disposeGlobalListener();
}
if (initChanges.length > 0 && !isYjsValueDeleted(yjsObject)) {
yjsDoc.transact(() => {
for (const { target, change } of initChanges) {
const pathToTarget = mobxKeystone.getParentToChildPath(boundObject, target);
if (pathToTarget !== void 0) {
const changeWithCorrectPath = {
...change,
path: [...pathToTarget, ...change.path]
};
applyMobxChangeToYjsObject(changeWithCorrectPath, yjsObject);
}
}
}, yjsOrigin);
}
if (yjsObject instanceof Y__namespace.Map || yjsObject instanceof Y__namespace.Array) {
setYjsContainerSnapshot(yjsObject, mobxKeystone.getSnapshot(boundObject));
}
} finally {
applyingYjsChangesToMobxKeystone--;
}
}
});
yjsObject.observeDeep(observeDeepCb);
let pendingChanges = [];
const disposeOnDeepChange = mobxKeystone.onDeepChange(boundObject, (change) => {
if (applyingYjsChangesToMobxKeystone > 0) {
return;
}
if (change.isInit) {
return;
}
pendingChanges.push(captureChangeSnapshots(change));
});
const disposeOnSnapshot = mobxKeystone.onSnapshot(boundObject, (boundObjectSnapshot) => {
if (pendingChanges.length === 0) {
return;
}
const changesToApply = pendingChanges;
pendingChanges = [];
if (isYjsValueDeleted(yjsObject)) {
return;
}
yjsDoc.transact(() => {
changesToApply.forEach((change) => {
applyMobxChangeToYjsObject(change, yjsObject);
});
}, yjsOrigin);
if (yjsObject instanceof Y__namespace.Map || yjsObject instanceof Y__namespace.Array) {
setYjsContainerSnapshot(yjsObject, boundObjectSnapshot);
}
});
const finalSnapshot = mobxKeystone.getSnapshot(boundObject);
if (hasInitChanges) {
yjsDoc.transact(() => {
if (yjsObject instanceof Y__namespace.Map) {
applyJsonObjectToYMap(yjsObject, finalSnapshot, {
mode: "merge"
});
} else if (yjsObject instanceof Y__namespace.Array) {
applyJsonArrayToYArray(yjsObject, finalSnapshot, {
mode: "merge"
});
}
}, yjsOrigin);
}
if (yjsObject instanceof Y__namespace.Map || yjsObject instanceof Y__namespace.Array) {
setYjsContainerSnapshot(yjsObject, finalSnapshot);
}
const dispose = () => {
yjsDoc.off("destroy", dispose);
disposeOnDeepChange();
disposeOnSnapshot();
yjsObject.unobserveDeep(observeDeepCb);
};
yjsDoc.on("destroy", dispose);
return {
boundObject,
dispose,
yjsOrigin
};
}
exports2.MobxKeystoneYjsError = MobxKeystoneYjsError;
exports2.applyJsonArrayToYArray = applyJsonArrayToYArray;
exports2.applyJsonObjectToYMap = applyJsonObjectToYMap;
exports2.bindYjsToMobxKeystone = bindYjsToMobxKeystone;
exports2.convertJsonToYjsData = convertJsonToYjsData;
exports2.yjsBindingContext = yjsBindingContext;
exports2.yjsTextModelId = yjsTextModelId;
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" });
}));
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibW9ieC1rZXlzdG9uZS15anMudW1kLmpzIiwic291cmNlcyI6WyIuLi9zcmMvdXRpbHMvZXJyb3IudHMiLCIuLi9zcmMvdXRpbHMvZ2V0T3JDcmVhdGVZanNDb2xsZWN0aW9uQXRvbS50cyIsIi4uL3NyYy91dGlscy9pc1lqc1ZhbHVlRGVsZXRlZC50cyIsIi4uL3NyYy9iaW5kaW5nL3Jlc29sdmVZanNQYXRoLnRzIiwiLi4vc3JjL2JpbmRpbmcveWpzQmluZGluZ0NvbnRleHQudHMiLCIuLi9zcmMvYmluZGluZy9ZanNUZXh0TW9kZWwudHMiLCIuLi9zcmMvYmluZGluZy95anNTbmFwc2hvdFRyYWNraW5nLnRzIiwiLi4vc3JjL2JpbmRpbmcvY29udmVydEpzb25Ub1lqc0RhdGEudHMiLCIuLi9zcmMvYmluZGluZy9hcHBseU1vYnhDaGFuZ2VUb1lqc09iamVjdC50cyIsIi4uL3NyYy9iaW5kaW5nL2NvbnZlcnRZanNEYXRhVG9Kc29uLnRzIiwiLi4vc3JjL2JpbmRpbmcvYXBwbHlZanNFdmVudFRvTW9ieC50cyIsIi4uL3NyYy9iaW5kaW5nL2JpbmRZanNUb01vYnhLZXlzdG9uZS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcclxuICogQSBtb2J4LWtleXN0b25lLXlqcyBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjbGFzcyBNb2J4S2V5c3RvbmVZanNFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICBjb25zdHJ1Y3Rvcihtc2c6IHN0cmluZykge1xyXG4gICAgc3VwZXIobXNnKVxyXG5cclxuICAgIC8vIFNldCB0aGUgcHJvdG90eXBlIGV4cGxpY2l0bHkuXHJcbiAgICBPYmplY3Quc2V0UHJvdG90eXBlT2YodGhpcywgTW9ieEtleXN0b25lWWpzRXJyb3IucHJvdG90eXBlKVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEBpbnRlcm5hbFxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZhaWx1cmUobXNnOiBzdHJpbmcpIHtcclxuICByZXR1cm4gbmV3IE1vYnhLZXlzdG9uZVlqc0Vycm9yKG1zZylcclxufVxyXG4iLCJpbXBvcnQgeyBjcmVhdGVBdG9tLCBJQXRvbSB9IGZyb20gXCJtb2J4XCJcbmltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5cbmNvbnN0IHlqc0NvbGxlY3Rpb25BdG9tcyA9IG5ldyBXZWFrTWFwPFkuTWFwPHVua25vd24+IHwgWS5BcnJheTx1bmtub3duPiwgSUF0b20+KClcblxuLyoqXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGNvbnN0IGdldFlqc0NvbGxlY3Rpb25BdG9tID0gKFxuICB5anNDb2xsZWN0aW9uOiBZLk1hcDx1bmtub3duPiB8IFkuQXJyYXk8dW5rbm93bj5cbik6IElBdG9tIHwgdW5kZWZpbmVkID0+IHtcbiAgcmV0dXJuIHlqc0NvbGxlY3Rpb25BdG9tcy5nZXQoeWpzQ29sbGVjdGlvbilcbn1cblxuLyoqXG4gKiBAaW50ZXJuYWxcbiAqL1xuZXhwb3J0IGNvbnN0IGdldE9yQ3JlYXRlWWpzQ29sbGVjdGlvbkF0b20gPSAoXG4gIHlqc0NvbGxlY3Rpb246IFkuTWFwPHVua25vd24+IHwgWS5BcnJheTx1bmtub3duPlxuKTogSUF0b20gPT4ge1xuICBsZXQgYXRvbSA9IHlqc0NvbGxlY3Rpb25BdG9tcy5nZXQoeWpzQ29sbGVjdGlvbilcbiAgaWYgKCFhdG9tKSB7XG4gICAgYXRvbSA9IGNyZWF0ZUF0b20oYHlqc0NvbGxlY3Rpb25BdG9tYClcbiAgICB5anNDb2xsZWN0aW9uQXRvbXMuc2V0KHlqc0NvbGxlY3Rpb24sIGF0b20pXG4gIH1cbiAgcmV0dXJuIGF0b21cbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgWS5qcyB2YWx1ZSBoYXMgYmVlbiBkZWxldGVkIG9yIGl0cyBkb2N1bWVudCBkZXN0cm95ZWQuXG4gKlxuICogQHBhcmFtIHlqc1ZhbHVlIFRoZSBZLmpzIHZhbHVlIHRvIGNoZWNrLlxuICogQHJldHVybnMgYHRydWVgIGlmIHRoZSB2YWx1ZSBpcyBkZWxldGVkIG9yIGRlc3Ryb3llZCwgYGZhbHNlYCBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1lqc1ZhbHVlRGVsZXRlZCh5anNWYWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICBpZiAoeWpzVmFsdWUgaW5zdGFuY2VvZiBZLkFic3RyYWN0VHlwZSkge1xuICAgIHJldHVybiAhISh5anNWYWx1ZSBhcyBhbnkpLl9pdGVtPy5kZWxldGVkIHx8ICEheWpzVmFsdWUuZG9jPy5pc0Rlc3Ryb3llZFxuICB9XG4gIHJldHVybiBmYWxzZVxufVxuIiwiaW1wb3J0ICogYXMgWSBmcm9tIFwieWpzXCJcbmltcG9ydCB7IGZhaWx1cmUgfSBmcm9tIFwiLi4vdXRpbHMvZXJyb3JcIlxuaW1wb3J0IHsgZ2V0T3JDcmVhdGVZanNDb2xsZWN0aW9uQXRvbSB9IGZyb20gXCIuLi91dGlscy9nZXRPckNyZWF0ZVlqc0NvbGxlY3Rpb25BdG9tXCJcblxuLyoqXG4gKiBSZXNvbHZlcyBhIHBhdGggd2l0aGluIGEgWWpzIG9iamVjdCBzdHJ1Y3R1cmUuXG4gKiBSZXR1cm5zIHRoZSBZanMgY29udGFpbmVyIGF0IHRoZSBzcGVjaWZpZWQgcGF0aC5cbiAqXG4gKiBXaGVuIGEgWS5UZXh0IGlzIGVuY291bnRlcmVkIGR1cmluZyBwYXRoIHJlc29sdXRpb24gKGVpdGhlciBhdCB0aGUgc3RhcnRcbiAqIG9yIG1pZC1wYXRoKSwgaXQgaXMgcmV0dXJuZWQgaW1tZWRpYXRlbHkgc2luY2UgWS5UZXh0IGRvZXNuJ3Qgc3VwcG9ydFxuICogbmVzdGVkIHBhdGggdHJhdmVyc2FsLlxuICpcbiAqIEBwYXJhbSB5anNPYmplY3QgVGhlIHJvb3QgWWpzIG9iamVjdFxuICogQHBhcmFtIHBhdGggQXJyYXkgb2Yga2V5cy9pbmRpY2VzIHRvIHRyYXZlcnNlXG4gKiBAcmV0dXJucyBUaGUgWWpzIGNvbnRhaW5lciBhdCB0aGUgcGF0aCwgb3IgWS5UZXh0IGlmIGVuY291bnRlcmVkIGR1cmluZyB0cmF2ZXJzYWxcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc29sdmVZanNQYXRoKFxuICB5anNPYmplY3Q6IFkuTWFwPHVua25vd24+IHwgWS5BcnJheTx1bmtub3duPiB8IFkuVGV4dCxcbiAgcGF0aDogcmVhZG9ubHkgKHN0cmluZyB8IG51bWJlcilbXVxuKTogdW5rbm93biB7XG4gIGxldCBjdXJyZW50WWpzT2JqZWN0OiB1bmtub3duID0geWpzT2JqZWN0XG5cbiAgbGV0IGkgPSAtMVxuICBmb3IgKGNvbnN0IHBhdGhQYXJ0IG9mIHBhdGgpIHtcbiAgICBpKytcbiAgICAvLyBJZiB3ZSBlbmNvdW50ZXIgYSBZLlRleHQgZHVyaW5nIHBhdGggcmVzb2x1dGlvbiwgcmV0dXJuIGl0IGltbWVkaWF0ZWx5LlxuICAgIC8vIFkuVGV4dCBvYmplY3RzIGRvbid0IHN1cHBvcnQgbmVzdGVkIHBhdGggdHJhdmVyc2FsLCBhbmQgdGhlaXIgdXBkYXRlc1xuICAgIC8vIGFyZSBoYW5kbGVkIHNlcGFyYXRlbHkgYnkgWWpzVGV4dE1vZGVsJ3Mgb3duIHN5bmNocm9uaXphdGlvbiBtZWNoYW5pc20uXG4gICAgaWYgKGN1cnJlbnRZanNPYmplY3QgaW5zdGFuY2VvZiBZLlRleHQpIHtcbiAgICAgIHJldHVybiBjdXJyZW50WWpzT2JqZWN0XG4gICAgfVxuXG4gICAgaWYgKGN1cnJlbnRZanNPYmplY3QgaW5zdGFuY2VvZiBZLk1hcCkge1xuICAgICAgZ2V0T3JDcmVhdGVZanNDb2xsZWN0aW9uQXRvbShjdXJyZW50WWpzT2JqZWN0KS5yZXBvcnRPYnNlcnZlZCgpXG4gICAgICBjb25zdCBrZXkgPSBTdHJpbmcocGF0aFBhcnQpXG4gICAgICBjdXJyZW50WWpzT2JqZWN0ID0gY3VycmVudFlqc09iamVjdC5nZXQoa2V5KVxuICAgIH0gZWxzZSBpZiAoY3VycmVudFlqc09iamVjdCBpbnN0YW5jZW9mIFkuQXJyYXkpIHtcbiAgICAgIGdldE9yQ3JlYXRlWWpzQ29sbGVjdGlvbkF0b20oY3VycmVudFlqc09iamVjdCkucmVwb3J0T2JzZXJ2ZWQoKVxuICAgICAgY29uc3Qga2V5ID0gTnVtYmVyKHBhdGhQYXJ0KVxuICAgICAgY3VycmVudFlqc09iamVjdCA9IGN1cnJlbnRZanNPYmplY3QuZ2V0KGtleSlcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgZmFpbHVyZShcbiAgICAgICAgYFkuTWFwIG9yIFkuQXJyYXkgd2FzIGV4cGVjdGVkIGF0IHBhdGggJHtKU09OLnN0cmluZ2lmeShcbiAgICAgICAgICBwYXRoLnNsaWNlKDAsIGkpXG4gICAgICAgICl9IGluIG9yZGVyIHRvIHJlc29sdmUgcGF0aCAke0pTT04uc3RyaW5naWZ5KHBhdGgpfSwgYnV0IGdvdCAke2N1cnJlbnRZanNPYmplY3R9IGluc3RlYWRgXG4gICAgICApXG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGN1cnJlbnRZanNPYmplY3Rcbn1cbiIsImltcG9ydCB7IEFueVR5cGUsIGNyZWF0ZUNvbnRleHQgfSBmcm9tIFwibW9ieC1rZXlzdG9uZVwiXG5pbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuXG4vKipcbiAqIENvbnRleHQgd2l0aCBpbmZvIG9uIGhvdyBhIG1vYngta2V5c3RvbmUgbW9kZWwgaXMgYm91bmQgdG8gYSBZLmpzIGRhdGEgc3RydWN0dXJlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFlqc0JpbmRpbmdDb250ZXh0IHtcbiAgLyoqXG4gICAqIFRoZSBZLmpzIGRvY3VtZW50LlxuICAgKi9cbiAgeWpzRG9jOiBZLkRvY1xuXG4gIC8qKlxuICAgKiBUaGUgYm91bmQgWS5qcyBkYXRhIHN0cnVjdHVyZS5cbiAgICovXG4gIHlqc09iamVjdDogWS5NYXA8dW5rbm93bj4gfCBZLkFycmF5PHVua25vd24+IHwgWS5UZXh0XG5cbiAgLyoqXG4gICAqIFRoZSBtb2J4LWtleXN0b25lIG1vZGVsIHR5cGUuXG4gICAqL1xuICBtb2J4S2V5c3RvbmVUeXBlOiBBbnlUeXBlXG5cbiAgLyoqXG4gICAqIFRoZSBvcmlnaW4gc3ltYm9sIHVzZWQgZm9yIHRyYW5zYWN0aW9ucy5cbiAgICovXG4gIHlqc09yaWdpbjogc3ltYm9sXG5cbiAgLyoqXG4gICAqIFRoZSBib3VuZCBtb2J4LWtleXN0b25lIGluc3RhbmNlLlxuICAgKi9cbiAgYm91bmRPYmplY3Q6IHVua25vd25cblxuICAvKipcbiAgICogV2hldGhlciB3ZSBhcmUgY3VycmVudGx5IGFwcGx5aW5nIFkuanMgY2hhbmdlcyB0byB0aGUgbW9ieC1rZXlzdG9uZSBtb2RlbC5cbiAgICovXG4gIGlzQXBwbHlpbmdZanNDaGFuZ2VzVG9Nb2J4S2V5c3RvbmU6IGJvb2xlYW5cbn1cblxuLyoqXG4gKiBDb250ZXh0IHdpdGggaW5mbyBvbiBob3cgYSBtb2J4LWtleXN0b25lIG1vZGVsIGlzIGJvdW5kIHRvIGEgWS5qcyBkYXRhIHN0cnVjdHVyZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHlqc0JpbmRpbmdDb250ZXh0ID0gY3JlYXRlQ29udGV4dDxZanNCaW5kaW5nQ29udGV4dCB8IHVuZGVmaW5lZD4odW5kZWZpbmVkKVxuIiwiaW1wb3J0IHsgY29tcHV0ZWQsIGNyZWF0ZUF0b20sIElBdG9tLCBvYnNlcnZlLCByZWFjdGlvbiB9IGZyb20gXCJtb2J4XCJcbmltcG9ydCB7XG4gIEZyb3plbixcbiAgZnJvemVuLFxuICBnZXRQYXJlbnRUb0NoaWxkUGF0aCxcbiAgTW9kZWwsXG4gIG1vZGVsLFxuICBvblNuYXBzaG90LFxuICB0UHJvcCxcbiAgdHlwZXMsXG59IGZyb20gXCJtb2J4LWtleXN0b25lXCJcbmltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5pbXBvcnQgeyBmYWlsdXJlIH0gZnJvbSBcIi4uL3V0aWxzL2Vycm9yXCJcbmltcG9ydCB7IGlzWWpzVmFsdWVEZWxldGVkIH0gZnJvbSBcIi4uL3V0aWxzL2lzWWpzVmFsdWVEZWxldGVkXCJcbmltcG9ydCB7IHJlc29sdmVZanNQYXRoIH0gZnJvbSBcIi4vcmVzb2x2ZVlqc1BhdGhcIlxuaW1wb3J0IHsgWWpzQmluZGluZ0NvbnRleHQsIHlqc0JpbmRpbmdDb250ZXh0IH0gZnJvbSBcIi4veWpzQmluZGluZ0NvbnRleHRcIlxuXG4vLyBEZWx0YVtdW10sIHNpbmNlIGVhY2ggc2luZ2xlIGNoYW5nZSBpcyBhIERlbHRhW11cbi8vIHdlIHVzZSBmcm96ZW4gc28gdGhhdCB3ZSBjYW4gcmV1c2UgZWFjaCBkZWx0YSBjaGFuZ2VcbmNvbnN0IGRlbHRhTGlzdFR5cGUgPSB0eXBlcy5hcnJheSh0eXBlcy5mcm96ZW4odHlwZXMudW5jaGVja2VkPHVua25vd25bXT4oKSkpXG5cbmV4cG9ydCBjb25zdCB5anNUZXh0TW9kZWxJZCA9IFwibW9ieC1rZXlzdG9uZS15anMvWWpzVGV4dE1vZGVsXCJcblxuLyoqXG4gKiBBIG1vYngta2V5c3RvbmUgbW9kZWwgdGhhdCByZXByZXNlbnRzIGEgWWpzLlRleHQgb2JqZWN0LlxuICovXG5AbW9kZWwoeWpzVGV4dE1vZGVsSWQpXG5leHBvcnQgY2xhc3MgWWpzVGV4dE1vZGVsIGV4dGVuZHMgTW9kZWwoe1xuICBkZWx0YUxpc3Q6IHRQcm9wKGRlbHRhTGlzdFR5cGUsICgpID0+IFtdKSxcbn0pIHtcbiAgLyoqXG4gICAqIEhlbHBlciBmdW5jdGlvbiB0byBjcmVhdGUgYSBZanNUZXh0TW9kZWwgaW5zdGFuY2Ugd2l0aCBhIHNpbXBsZSB0ZXh0LlxuICAgKi9cbiAgc3RhdGljIHdpdGhUZXh0KHRleHQ6IHN0cmluZyk6IFlqc1RleHRNb2RlbCB7XG4gICAgcmV0dXJuIG5ldyBEZWNvcmF0ZWRZanNUZXh0TW9kZWwoe1xuICAgICAgZGVsdGFMaXN0OiBbXG4gICAgICAgIGZyb3plbihbXG4gICAgICAgICAge1xuICAgICAgICAgICAgaW5zZXJ0OiB0ZXh0LFxuICAgICAgICAgIH0sXG4gICAgICAgIF0pLFxuICAgICAgXSxcbiAgICB9KVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBZLmpzIHBhdGggZnJvbSB0aGUgYm91bmQgb2JqZWN0IHRvIHRoZSBZanNUZXh0TW9kZWwgaW5zdGFuY2UuXG4gICAqL1xuICBAY29tcHV0ZWRcbiAgcHJpdmF0ZSBnZXQgX3lqc09iamVjdFBhdGgoKSB7XG4gICAgY29uc3QgY3R4ID0geWpzQmluZGluZ0NvbnRleHQuZ2V0KHRoaXMpXG4gICAgaWYgKGN0eD8uYm91bmRPYmplY3QgPT0gbnVsbCkge1xuICAgICAgdGhyb3cgZmFpbHVyZShcbiAgICAgICAgXCJ0aGUgWWpzVGV4dE1vZGVsIGluc3RhbmNlIG11c3QgYmUgcGFydCBvZiBhIGJvdW5kIG9iamVjdCBiZWZvcmUgaXQgY2FuIGJlIGFjY2Vzc2VkXCJcbiAgICAgIClcbiAgICB9XG5cbiAgICBjb25zdCBwYXRoID0gZ2V0UGFyZW50VG9DaGlsZFBhdGgoY3R4LmJvdW5kT2JqZWN0LCB0aGlzKVxuICAgIGlmICghcGF0aCkge1xuICAgICAgdGhyb3cgZmFpbHVyZShcImEgcGF0aCBmcm9tIHRoZSBib3VuZCBvYmplY3QgdG8gdGhlIFlqc1RleHRNb2RlbCBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlXCIpXG4gICAgfVxuXG4gICAgcmV0dXJuIHBhdGhcbiAgfVxuXG4gIC8qKlxuICAgKiBUaGUgWWpzLlRleHQgb2JqZWN0IHByZXNlbnQgYXQgdGhpcyBtb2J4LWtleXN0b25lIG5vZGUncyBwYXRoLlxuICAgKi9cbiAgQGNvbXB1dGVkXG4gIHByaXZhdGUgZ2V0IF95anNPYmplY3RBdFBhdGgoKTogdW5rbm93biB7XG4gICAgY29uc3QgcGF0aCA9IHRoaXMuX3lqc09iamVjdFBhdGhcblxuICAgIGNvbnN0IGN0eCA9IHlqc0JpbmRpbmdDb250ZXh0LmdldCh0aGlzKSFcblxuICAgIHJldHVybiByZXNvbHZlWWpzUGF0aChjdHgueWpzT2JqZWN0LCBwYXRoKVxuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBZanMuVGV4dCBvYmplY3QgcmVwcmVzZW50ZWQgYnkgdGhpcyBtb2J4LWtleXN0b25lIG5vZGUuXG4gICAqL1xuICBAY29tcHV0ZWRcbiAgZ2V0IHlqc1RleHQoKTogWS5UZXh0IHtcbiAgICBjb25zdCB5anNPYmplY3QgPSB0aGlzLl95anNPYmplY3RBdFBhdGhcblxuICAgIGlmICghKHlqc09iamVjdCBpbnN0YW5jZW9mIFkuVGV4dCkpIHtcbiAgICAgIHRocm93IGZhaWx1cmUoYFkuVGV4dCB3YXMgZXhwZWN0ZWQgYXQgcGF0aCAke0pTT04uc3RyaW5naWZ5KHRoaXMuX3lqc09iamVjdFBhdGgpfWApXG4gICAgfVxuXG4gICAgcmV0dXJuIHlqc09iamVjdFxuICB9XG5cbiAgLyoqXG4gICAqIEF0b20gdGhhdCBnZXRzIGNoYW5nZWQgd2hlbiB0aGUgYXNzb2NpYXRlZCBZLmpzIHRleHQgY2hhbmdlcy5cbiAgICovXG4gIHlqc1RleHRDaGFuZ2VkQXRvbSA9IGNyZWF0ZUF0b20oXCJ5anNUZXh0Q2hhbmdlZEF0b21cIilcblxuICAvKipcbiAgICogVGhlIHRleHQgdmFsdWUgb2YgdGhlIFlqcy5UZXh0IG9iamVjdC5cbiAgICogU2hvcnRjdXQgZm9yIGB5anNUZXh0LnRvU3RyaW5nKClgLCBidXQgY29tcHV0ZWQuXG4gICAqL1xuICBAY29tcHV0ZWRcbiAgZ2V0IHRleHQoKTogc3RyaW5nIHtcbiAgICB0aGlzLnlqc1RleHRDaGFuZ2VkQXRvbS5yZXBvcnRPYnNlcnZlZCgpXG5cbiAgICBjb25zdCBjdHggPSB5anNCaW5kaW5nQ29udGV4dC5nZXQodGhpcylcbiAgICBpZiAoY3R4Py5ib3VuZE9iamVjdCAhPSBudWxsKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB5anNUZXh0U3RyaW5nID0gdGhpcy55anNUZXh0LnRvU3RyaW5nKClcbiAgICAgICAgLy8gaWYgdGhlIHlqc1RleHQgaXMgZGV0YWNoZWQsIHRvU3RyaW5nKCkgcmV0dXJucyBhbiBlbXB0eSBzdHJpbmdcbiAgICAgICAgLy8gaW4gdGhhdCBjYXNlIHdlIHNob3VsZCB1c2UgdGhlIGRlbHRhTGlzdCBhcyBhIGZhbGxiYWNrXG4gICAgICAgIGlmICh5anNUZXh0U3RyaW5nICE9PSBcIlwiIHx8IHRoaXMuZGVsdGFMaXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgIHJldHVybiB5anNUZXh0U3RyaW5nXG4gICAgICAgIH1cbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICAvLyBmYWxsIGJhY2tcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBmYWxsIGJhY2sgdG8gZGVsdGFMaXN0XG4gICAgcmV0dXJuIHRoaXMuZGVsdGFMaXN0VG9UZXh0KClcbiAgfVxuXG4gIHByaXZhdGUgZGVsdGFMaXN0VG9UZXh0KCk6IHN0cmluZyB7XG4gICAgY29uc3QgZG9jID0gbmV3IFkuRG9jKClcbiAgICBjb25zdCB0ZXh0ID0gZG9jLmdldFRleHQoKVxuICAgIHRoaXMuZGVsdGFMaXN0LmZvckVhY2goKGQpID0+IHtcbiAgICAgIHRleHQuYXBwbHlEZWx0YShkLmRhdGEpXG4gICAgfSlcbiAgICByZXR1cm4gdGV4dC50b1N0cmluZygpXG4gIH1cblxuICBwcm90ZWN0ZWQgb25Jbml0KCkge1xuICAgIGNvbnN0IHNob3VsZFJlcGxpY2F0ZVRvWWpzID0gKGN0eDogWWpzQmluZGluZ0NvbnRleHQgfCB1bmRlZmluZWQpOiBjdHggaXMgWWpzQmluZGluZ0NvbnRleHQgPT4ge1xuICAgICAgcmV0dXJuICEhY3R4ICYmICEhY3R4LmJvdW5kT2JqZWN0ICYmICFjdHguaXNBcHBseWluZ1lqc0NoYW5nZXNUb01vYnhLZXlzdG9uZVxuICAgIH1cblxuICAgIGxldCByZWFwcGx5RGVsdGFzVG9ZanNUZXh0ID0gZmFsc2VcbiAgICBjb25zdCBuZXdEZWx0YXM6IEZyb3plbjx1bmtub3duW10+W10gPSBbXVxuXG4gICAgbGV0IGRpc3Bvc2VPYnNlcnZlRGVsdGFMaXN0OiAoKCkgPT4gdm9pZCkgfCB1bmRlZmluZWRcblxuICAgIGNvbnN0IGRpc3Bvc2VSZWFjdGlvblRvRGVsdGFMaXN0UmVmQ2hhbmdlID0gcmVhY3Rpb24oXG4gICAgICAoKSA9PiB0aGlzLiQuZGVsdGFMaXN0LFxuICAgICAgKGRlbHRhTGlzdCkgPT4ge1xuICAgICAgICBkaXNwb3NlT2JzZXJ2ZURlbHRhTGlzdD8uKClcbiAgICAgICAgZGlzcG9zZU9ic2VydmVEZWx0YUxpc3QgPSB1bmRlZmluZWRcblxuICAgICAgICBkaXNwb3NlT2JzZXJ2ZURlbHRhTGlzdCA9IG9ic2VydmUoZGVsdGFMaXN0LCAoY2hhbmdlKSA9PiB7XG4gICAgICAgICAgaWYgKHJlYXBwbHlEZWx0YXNUb1lqc1RleHQpIHtcbiAgICAgICAgICAgIC8vIGFscmVhZHkgZ29ubmEgcmVwbGFjZSB0aGVtIGFsbFxuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgfVxuICAgICAgICAgIGlmICghc2hvdWxkUmVwbGljYXRlVG9ZanMoeWpzQmluZGluZ0NvbnRleHQuZ2V0KHRoaXMpKSkge1xuICAgICAgICAgICAgLy8geWpzIHRleHQgaXMgYWxyZWFkeSB1cCB0byBkYXRlIHdpdGggdGhlc2UgY2hhbmdlc1xuICAgICAgICAgICAgcmV0dXJuXG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKFxuICAgICAgICAgICAgY2hhbmdlLnR5cGUgPT09IFwic3BsaWNlXCIgJiZcbiAgICAgICAgICAgIGNoYW5nZS5yZW1vdmVkQ291bnQgPT09IDAgJiZcbiAgICAgICAgICAgIGNoYW5nZS5hZGRlZENvdW50ID4gMCAmJlxuICAgICAgICAgICAgY2hhbmdlLmluZGV4ID09PSB0aGlzLmRlbHRhTGlzdC5sZW5ndGhcbiAgICAgICAgICApIHtcbiAgICAgICAgICAgIC8vIG9wdGltaXphdGlvbiwganVzdCBhZGRpbmcgbmV3IG9uZXMgdG8gdGhlIGVuZFxuICAgICAgICAgICAgbmV3RGVsdGFzLnB1c2goLi4uY2hhbmdlLmFkZGVkKVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBhbnkgb3RoZXIgY2hhbmdlLCB3ZSBuZWVkIHRvIHJlYXBwbHkgYWxsIGRlbHRhc1xuICAgICAgICAgICAgcmVhcHBseURlbHRhc1RvWWpzVGV4dCA9IHRydWVcbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICB9LFxuICAgICAgeyBmaXJlSW1tZWRpYXRlbHk6IHRydWUgfVxuICAgIClcblxuICAgIGNvbnN0IGRpc3Bvc2VPblNuYXBzaG90ID0gb25TbmFwc2hvdCh0aGlzLCAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBpZiAocmVhcHBseURlbHRhc1RvWWpzVGV4dCkge1xuICAgICAgICAgIGNvbnN0IGN0eCA9IHlqc0JpbmRpbmdDb250ZXh0LmdldCh0aGlzKVxuXG4gICAgICAgICAgaWYgKHNob3VsZFJlcGxpY2F0ZVRvWWpzKGN0eCkpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgeWpzVGV4dCB9ID0gdGhpc1xuICAgICAgICAgICAgaWYgKGlzWWpzVmFsdWVEZWxldGVkKHlqc1RleHQpKSB7XG4gICAgICAgICAgICAgIHRocm93IGZhaWx1cmUoXCJjYW5ub3QgcmVhcHBseSBkZWx0YXMgdG8gZGVsZXRlZCBZanMuVGV4dFwiKVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjdHgueWpzRG9jLnRyYW5zYWN0KCgpID0+IHtcbiAgICAgICAgICAgICAgLy8gZGlkbid0IGZpbmQgYSBiZXR0ZXIgd2F5IHRoYW4gdGhpcyB0byByZWFwcGx5IGFsbCBkZWx0YXNcbiAgICAgICAgICAgICAgLy8gd2l0aG91dCBoYXZpbmcgdG8gcmUtY3JlYXRlIHRoZSBZLlRleHQgb2JqZWN0XG4gICAgICAgICAgICAgIGlmICh5anNUZXh0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB5anNUZXh0LmRlbGV0ZSgwLCB5anNUZXh0Lmxlbmd0aClcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIHRoaXMuZGVsdGFMaXN0LmZvckVhY2goKGZyb3plbkRlbHRhcykgPT4ge1xuICAgICAgICAgICAgICAgIHlqc1RleHQuYXBwbHlEZWx0YShmcm96ZW5EZWx0YXMuZGF0YSlcbiAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgIH0sIGN0eC55anNPcmlnaW4pXG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKG5ld0RlbHRhcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc3QgY3R4ID0geWpzQmluZGluZ0NvbnRleHQuZ2V0KHRoaXMpXG5cbiAgICAgICAgICBpZiAoc2hvdWxkUmVwbGljYXRlVG9ZanMoY3R4KSkge1xuICAgICAgICAgICAgY29uc3QgeyB5anNUZXh0IH0gPSB0aGlzXG4gICAgICAgICAgICBpZiAoaXNZanNWYWx1ZURlbGV0ZWQoeWpzVGV4dCkpIHtcbiAgICAgICAgICAgICAgdGhyb3cgZmFpbHVyZShcImNhbm5vdCByZWFwcGx5IGRlbHRhcyB0byBkZWxldGVkIFlqcy5UZXh0XCIpXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGN0eC55anNEb2MudHJhbnNhY3QoKCkgPT4ge1xuICAgICAgICAgICAgICBuZXdEZWx0YXMuZm9yRWFjaCgoZnJvemVuRGVsdGFzKSA9PiB7XG4gICAgICAgICAgICAgICAgeWpzVGV4dC5hcHBseURlbHRhKGZyb3plbkRlbHRhcy5kYXRhKVxuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgfSwgY3R4Lnlqc09yaWdpbilcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIHJlYXBwbHlEZWx0YXNUb1lqc1RleHQgPSBmYWxzZVxuICAgICAgICBuZXdEZWx0YXMubGVuZ3RoID0gMFxuICAgICAgfVxuICAgIH0pXG5cbiAgICBjb25zdCBkaXBvc2VZanNUZXh0Q2hhbmdlZEF0b20gPSBob29rWWpzVGV4dENoYW5nZWRBdG9tKFxuICAgICAgKCkgPT4gdGhpcy55anNUZXh0LFxuICAgICAgdGhpcy55anNUZXh0Q2hhbmdlZEF0b21cbiAgICApXG5cbiAgICByZXR1cm4gKCkgPT4ge1xuICAgICAgZGlzcG9zZU9uU25hcHNob3QoKVxuICAgICAgZGlzcG9zZVJlYWN0aW9uVG9EZWx0YUxpc3RSZWZDaGFuZ2UoKVxuICAgICAgZGlzcG9zZU9ic2VydmVEZWx0YUxpc3Q/LigpXG4gICAgICBkaXNwb3NlT2JzZXJ2ZURlbHRhTGlzdCA9IHVuZGVmaW5lZFxuXG4gICAgICBkaXBvc2VZanNUZXh0Q2hhbmdlZEF0b20oKVxuICAgIH1cbiAgfVxufVxuXG4vLyB3ZSB1c2UgdGhpcyB0cmljayBqdXN0IHRvIGF2b2lkIGEgYmFiZWwgYnVnIHRoYXQgY2F1c2VzIGNsYXNzZXMgdXNlZCBpbnNpZGUgY2xhc3NlcyBub3QgdG8gYmUgb3ZlcnJpZGVuXG4vLyBieSB0aGUgZGVjb3JhdG9yXG5jb25zdCBEZWNvcmF0ZWRZanNUZXh0TW9kZWwgPSBZanNUZXh0TW9kZWxcblxuZnVuY3Rpb24gaG9va1lqc1RleHRDaGFuZ2VkQXRvbShnZXRZanNUZXh0OiAoKSA9PiBZLlRleHQsIHRleHRDaGFuZ2VkQXRvbTogSUF0b20pIHtcbiAgbGV0IGRpc3Bvc2VPYnNlcnZlWWpzVGV4dDogKCgpID0+IHZvaWQpIHwgdW5kZWZpbmVkXG5cbiAgY29uc3Qgb2JzZXJ2ZUZuID0gKCkgPT4ge1xuICAgIHRleHRDaGFuZ2VkQXRvbS5yZXBvcnRDaGFuZ2VkKClcbiAgfVxuXG4gIGNvbnN0IGRpc3Bvc2VSZWFjdGlvblRvWVRleHRDaGFuZ2UgPSByZWFjdGlvbihcbiAgICAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB5anNUZXh0ID0gZ2V0WWpzVGV4dCgpXG4gICAgICAgIHJldHVybiBpc1lqc1ZhbHVlRGVsZXRlZCh5anNUZXh0KSA/IHVuZGVmaW5lZCA6IHlqc1RleHRcbiAgICAgIH0gY2F0Y2gge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkXG4gICAgICB9XG4gICAgfSxcbiAgICAoeWpzVGV4dCkgPT4ge1xuICAgICAgZGlzcG9zZU9ic2VydmVZanNUZXh0Py4oKVxuICAgICAgZGlzcG9zZU9ic2VydmVZanNUZXh0ID0gdW5kZWZpbmVkXG5cbiAgICAgIGlmICh5anNUZXh0KSB7XG4gICAgICAgIHlqc1RleHQub2JzZXJ2ZShvYnNlcnZlRm4pXG5cbiAgICAgICAgZGlzcG9zZU9ic2VydmVZanNUZXh0ID0gKCkgPT4ge1xuICAgICAgICAgIHlqc1RleHQudW5vYnNlcnZlKG9ic2VydmVGbilcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICB0ZXh0Q2hhbmdlZEF0b20ucmVwb3J0Q2hhbmdlZCgpXG4gICAgfSxcbiAgICB7XG4gICAgICBmaXJlSW1tZWRpYXRlbHk6IHRydWUsXG4gICAgfVxuICApXG5cbiAgcmV0dXJuICgpID0+IHtcbiAgICBkaXNwb3NlUmVhY3Rpb25Ub1lUZXh0Q2hhbmdlKClcbiAgICBkaXNwb3NlT2JzZXJ2ZVlqc1RleHQ/LigpXG4gICAgZGlzcG9zZU9ic2VydmVZanNUZXh0ID0gdW5kZWZpbmVkXG4gIH1cbn1cbiIsImltcG9ydCAqIGFzIFkgZnJvbSBcInlqc1wiXG5cbi8qKlxuICogV2Vha01hcCB0aGF0IHRyYWNrcyB3aGljaCBzbmFwc2hvdCBlYWNoIFkuanMgY29udGFpbmVyIHdhcyBsYXN0IHN5bmNlZCBmcm9tLlxuICogVGhpcyBpcyB1c2VkIGR1cmluZyByZWNvbmNpbGlhdGlvbiB0byBza2lwIGNvbnRhaW5lcnMgdGhhdCBhcmUgYWxyZWFkeSB1cC10by1kYXRlLlxuICpcbiAqIFRoZSBrZXkgaXMgdGhlIFkuanMgY29udGFpbmVyIChZLk1hcCBvciBZLkFycmF5KS5cbiAqIFRoZSB2YWx1ZSBpcyB0aGUgc25hcHNob3QgKHBsYWluIG9iamVjdCBvciBhcnJheSkgdGhhdCB3YXMgbGFzdCBzeW5jZWQgdG8gaXQuXG4gKi9cbmV4cG9ydCBjb25zdCB5anNDb250YWluZXJUb1NuYXBzaG90ID0gbmV3IFdlYWtNYXA8WS5NYXA8YW55PiB8IFkuQXJyYXk8YW55PiwgdW5rbm93bj4oKVxuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIHNuYXBzaG90IHRyYWNraW5nIGZvciBhIFkuanMgY29udGFpbmVyLlxuICogQ2FsbCB0aGlzIGFmdGVyIHN5bmNpbmcgYSBzbmFwc2hvdCB0byBhIFkuanMgY29udGFpbmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0WWpzQ29udGFpbmVyU25hcHNob3QoXG4gIGNvbnRhaW5lcjogWS5NYXA8YW55PiB8IFkuQXJyYXk8YW55PixcbiAgc25hcHNob3Q6IHVua25vd25cbik6IHZvaWQge1xuICB5anNDb250YWluZXJUb1NuYXBzaG90LnNldChjb250YWluZXIsIHNuYXBzaG90KVxufVxuXG4vKipcbiAqIEdldHMgdGhlIGxhc3Qgc3luY2VkIHNuYXBzaG90IGZvciBhIFkuanMgY29udGFpbmVyLlxuICogUmV0dXJucyB1bmRlZmluZWQgaWYgdGhlIGNvbnRhaW5lciBoYXMgbmV2ZXIgYmVlbiBzeW5jZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRZanNDb250YWluZXJTbmFwc2hvdChjb250YWluZXI6IFkuTWFwPGFueT4gfCBZLkFycmF5PGFueT4pOiB1bmtub3duIHtcbiAgcmV0dXJuIHlqc0NvbnRhaW5lclRvU25hcHNob3QuZ2V0KGNvbnRhaW5lcilcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBZLmpzIGNvbnRhaW5lciBpcyB1cC10by1kYXRlIHdpdGggdGhlIGdpdmVuIHNuYXBzaG90LlxuICogVXNlcyByZWZlcmVuY2UgZXF1YWxpdHkgdG8gY2hlY2sgaWYgdGhlIHNuYXBzaG90IGlzIHRoZSBzYW1lLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNZanNDb250YWluZXJVcFRvRGF0ZShcbiAgY29udGFpbmVyOiBZLk1hcDxhbnk+IHwgWS5BcnJheTxhbnk+LFxuICBzbmFwc2hvdDogdW5rbm93blxuKTogYm9vbGVhbiB7XG4gIHJldHVybiB5anNDb250YWluZXJUb1NuYXBzaG90LmdldChjb250YWluZXIpID09PSBzbmFwc2hvdFxufVxuIiwiaW1wb3J0IHsgZnJvemVuS2V5LCBtb2RlbFR5cGVLZXksIFNuYXBzaG90T3V0T2YgfSBmcm9tIFwibW9ieC1rZXlzdG9uZVwiXG5pbXBvcnQgKiBhcyBZIGZyb20gXCJ5anNcIlxuaW1wb3J0IHsgUGxhaW5BcnJheSwgUGxhaW5PYmplY3QsIFBsYWluUHJpbWl0aXZlLCBQbGFpblZhbHVlIH0gZnJvbSBcIi4uL3BsYWluVHlwZXNcIlxuaW1wb3J0IHsgWWpzRGF0YSB9IGZyb20gXCIuL2NvbnZlcnRZanNEYXRhVG9Kc29uXCJcbmltcG9ydCB7IFlqc1RleHRNb2RlbCwgeWpzVGV4dE1vZGVsSWQgfSBmcm9tIFwiLi9ZanNUZXh0TW9kZWxcIlxuaW1wb3J0IHsgaXNZanNDb250YWluZXJVcFRvRGF0ZSwgc2V0WWpzQ29udGFpbmVyU25hcHNob3QgfSBmcm9tIFwiLi95anNTbmFwc2hvdFRyYWNraW5nXCJcblxuLyoqXG4gKiBPcHRpb25zIGZvciBhcHBseWluZyBKU09OIGRhdGEgdG8gWS5qcyBkYXRhIHN0cnVjdHVyZXMuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQXBwbHlKc29uVG9ZanNPcHRpb25zIHtcbiAgLyoqXG4gICAqIFRoZSBtb2RlIHRvIHVzZSB3aGVuIGFwcGx5aW5nIEpTT04gZGF0YSB0byBZLmpzIGRhdGEgc3RydWN0dXJlcy5cbiAgICogLSBgYWRkYDogQ3JlYXRlcyBuZXcgWS5qcyBjb250YWluZXJzIGZvciBvYmplY3RzL2FycmF5cyAoZGVmYXVsdCwgYmFja3dhcmRzIGNvbXBhdGlibGUpXG4gICAqIC0gYG1lcmdlYDogUmVjdXJzaXZlbHkgbWVyZ2VzIHZhbHVlcywgcHJlc2VydmluZyBleGlzdGluZyBjb250YWluZXIgcmVmZXJlbmNlcyB3aGVyZSBwb3NzaWJsZVxuICAgKi9cbiAgbW9kZT86IFwiYWRkXCIgfCBcIm1lcmdlXCJcbn1cblxuZnVuY3Rpb24gaXNQbGFpblByaW1pdGl2ZSh2OiBQbGFpblZhbHVlKTogdiBpcyBQbGFpblByaW1pdGl2ZSB7XG4gIGNvbnN0IHQgPSB0eXBlb2YgdlxuICByZXR1cm4gdCA9PT0gXCJzdHJpbmdcIiB8fCB0ID09PSBcIm51bWJlclwiIHx8IHQgPT09IFwiYm9vbGVhblwiIHx8IHYgPT09IG51bGwgfHwgdiA9PT0gdW5kZWZpbmVkXG59XG5cbmZ1bmN0aW9uIGlzUGxhaW5BcnJheSh2OiBQbGFpblZhbHVlKTogdiBpcyBQbGFpbkFycmF5IHtcbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkodilcbn1cblxuZnVuY3Rpb24gaXNQbGFpbk9iamVjdCh2OiBQbGFpblZhbHVlKTogdiBpcyBQbGFpbk9iamVjdCB7XG4gIHJldHVybiB0eXBlb2YgdiA9PT0gXCJvYmplY3RcIiAmJiB2ICE9PSBudWxsICYmICFBcnJheS5pc0FycmF5KHYpXG59XG5cbi8qKlxuICogQ29udmVydHMgYSBwbGFpbiB2YWx1ZSB0byBhIFkuanMgZGF0YSBzdHJ1Y3R1cmUuXG4gKiBPYmplY3RzIGFyZSBjb252ZXJ0ZWQgdG8gWS5NYXBzLCBhcnJheXMgdG8gWS5BcnJheXMsIHByaW1pdGl2ZXMgYXJlIHVudG91Y2hlZC5cbiAqIEZyb3plbiB2YWx1ZXMgYXJlIGEgc3BlY2lhbCBjYXNlIGFuZCB0aGV5IGFyZSBrZXB0IGFzIGltbXV0YWJsZSBwbGFpbiB2YWx1ZXMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBjb252ZXJ0SnNvblRvWWpzRGF0YSh2OiBQbGFpblZhbHVlKTogWWpzRGF0YSB7XG4gIGlmIChpc1BsYWluUHJpbWl0aXZlKHYpKSB7XG4gICAgcmV0dXJuIHZcbiAgfVxuXG4gIGlmIChpc1BsYWluQXJyYXkodikpIHtcbiAgICBjb25zdCBhcnIgPSBuZXcgWS5BcnJheSgpXG4gICAgYXBwbHlKc29uQXJyYXlUb1lBcnJheShhcnIsIHYpXG4gICAgcmV0dXJuIGFyclxuICB9XG5cbiAgaWYgKGlzUGxhaW5PYmplY3QodikpIHtcbiAgICBpZiAodltmcm96ZW5LZXldID09PSB0cnVlKSB7XG4gICAgICAvLyBmcm96ZW4gdmFsdWUsIHNhdmUgYXMgaW1tdXRhYmxlIG9iamVjdFxuICAgICAgcmV0dXJuIHZcbiAgICB9XG5cbiAgICBpZiAodlttb2RlbFR5cGVLZXldID09PSB5anNUZXh0TW9kZWxJZCkge1xuICAgICAgY29uc3QgdGV4dCA9IG5ldyBZLlRleHQoKVxuICAgICAgY29uc3QgeWpzVGV4dE1vZGVsID0gdiBhcyB1bmtub3duIGFzIFNuYXBzaG90T3V0T2Y8WWpzVGV4dE1vZGVsPlxuICAgICAgeWpzVGV4dE1vZGVsLmRlbHRhTGlzdC5mb3JFYWNoKChmcm96ZW5EZWx0YXMpID0+IHtcbiAgICAgICAgdGV4dC5hcHBseURlbHRhKGZyb3plbkRlbHRhcy5kYXRhKVxuICAgICAgfSlcbiAgICAgIHJldHVybiB0ZXh0XG4gICAgfVxuXG4gICAgY29uc3QgbWFwID0gbmV3IFkuTWFwKClcbiAgICBhcHBseUpzb25PYmplY3RUb1lNYXAobWFwLCB2KVxuICAgIHJldHVybiBtYXBcbiAgfVxuXG4gIHRocm93IG5ldyBFcnJvcihgdW5zdXBwb3J0ZWQgdmFsdWUgdHlwZTogJHt2fWApXG59XG5cbi8qKlxuICogQXBwbGllcyBhIEpTT04gYXJyYXkgdG8gYSBZLkFycmF5LCB1c2luZyB0aGUgY29udmVydEpzb25Ub1lqc0RhdGEgdG8gY29udmVydCB0aGUgdmFsdWVzLlxuICpcbiAqIEBwYXJhbSBkZXN0IFRoZSBkZXN0aW5hdGlvbiBZLkFycmF5LlxuICogQHBhcmFtIHNvdXJjZSBUaGUgc291cmNlIEpTT04gYXJyYXkuXG4gKiBAcGFyYW0gb3B0aW9ucyBPcHRpb25zIGZvciBhcHBseWluZyB0aGUgSlNPTiBkYXRhLlxuICovXG5leHBvcnQgY29uc3QgYXBwbHlKc29uQXJyYXlUb1lBcnJheSA