obsidian-dev-utils 83.2.0 → 84.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +32 -0
- package/dist/dev/main.js +2463 -1744
- package/dist/lib/cjs/generated-during-build.cjs +2 -2
- package/dist/lib/cjs/obsidian/components/plugin-notice-component.cjs +139 -8
- package/dist/lib/cjs/obsidian/components/plugin-notice-component.d.cts +94 -0
- package/dist/lib/cjs/obsidian/components/rename-delete-handler-component.cjs +10 -10
- package/dist/lib/cjs/obsidian/components/rename-delete-handler-component.d.cts +3 -3
- package/dist/lib/cjs/obsidian/css-class.cjs +2 -1
- package/dist/lib/cjs/obsidian/css-class.d.cts +5 -0
- package/dist/lib/cjs/obsidian/editor.cjs +1 -1
- package/dist/lib/cjs/obsidian/editor.d.cts +2 -2
- package/dist/lib/cjs/obsidian/file-manager.cjs +9 -9
- package/dist/lib/cjs/obsidian/file-manager.d.cts +9 -9
- package/dist/lib/cjs/obsidian/i18n/locales/en.cjs +8 -8
- package/dist/lib/cjs/obsidian/i18n/locales/en.d.cts +7 -7
- package/dist/lib/cjs/obsidian/i18n/locales/translations-map.d.cts +7 -7
- package/dist/lib/cjs/obsidian/index.cjs +7 -4
- package/dist/lib/cjs/obsidian/index.d.cts +2 -1
- package/dist/lib/cjs/obsidian/markdown-code-block-processor.cjs +7 -7
- package/dist/lib/cjs/obsidian/markdown-code-block-processor.d.cts +9 -9
- package/dist/lib/cjs/obsidian/plugin/plugin.cjs +21 -21
- package/dist/lib/cjs/obsidian/plugin/plugin.d.cts +15 -15
- package/dist/lib/cjs/obsidian/resource-lock.cjs +899 -0
- package/dist/lib/cjs/obsidian/resource-lock.d.cts +227 -0
- package/dist/lib/cjs/obsidian/vault-transaction.cjs +371 -0
- package/dist/lib/cjs/obsidian/vault-transaction.d.cts +146 -0
- package/dist/lib/cjs/obsidian/vault.cjs +4 -4
- package/dist/lib/cjs/obsidian/vault.d.cts +3 -3
- package/dist/lib/esm/generated-during-build.mjs +2 -2
- package/dist/lib/esm/obsidian/components/plugin-notice-component.d.mts +94 -0
- package/dist/lib/esm/obsidian/components/plugin-notice-component.mjs +143 -9
- package/dist/lib/esm/obsidian/components/rename-delete-handler-component.d.mts +3 -3
- package/dist/lib/esm/obsidian/components/rename-delete-handler-component.mjs +10 -10
- package/dist/lib/esm/obsidian/css-class.d.mts +5 -0
- package/dist/lib/esm/obsidian/css-class.mjs +2 -1
- package/dist/lib/esm/obsidian/editor.d.mts +2 -2
- package/dist/lib/esm/obsidian/editor.mjs +1 -1
- package/dist/lib/esm/obsidian/file-manager.d.mts +9 -9
- package/dist/lib/esm/obsidian/file-manager.mjs +9 -9
- package/dist/lib/esm/obsidian/i18n/locales/en.d.mts +7 -7
- package/dist/lib/esm/obsidian/i18n/locales/en.mjs +8 -8
- package/dist/lib/esm/obsidian/i18n/locales/translations-map.d.mts +7 -7
- package/dist/lib/esm/obsidian/index.d.mts +2 -1
- package/dist/lib/esm/obsidian/index.mjs +5 -3
- package/dist/lib/esm/obsidian/markdown-code-block-processor.d.mts +9 -9
- package/dist/lib/esm/obsidian/markdown-code-block-processor.mjs +7 -7
- package/dist/lib/esm/obsidian/plugin/plugin.d.mts +15 -15
- package/dist/lib/esm/obsidian/plugin/plugin.mjs +21 -21
- package/dist/lib/esm/obsidian/resource-lock.d.mts +227 -0
- package/dist/lib/esm/obsidian/resource-lock.mjs +799 -0
- package/dist/lib/esm/obsidian/vault-transaction.d.mts +146 -0
- package/dist/lib/esm/obsidian/vault-transaction.mjs +271 -0
- package/dist/lib/esm/obsidian/vault.d.mts +3 -3
- package/dist/lib/esm/obsidian/vault.mjs +4 -4
- package/dist/styles.css +8 -1
- package/obsidian/resource-lock/package.json +6 -0
- package/obsidian/vault-transaction/package.json +6 -0
- package/package.json +2 -2
- package/dist/lib/cjs/obsidian/editor-lock.cjs +0 -545
- package/dist/lib/cjs/obsidian/editor-lock.d.cts +0 -142
- package/dist/lib/esm/obsidian/editor-lock.d.mts +0 -142
- package/dist/lib/esm/obsidian/editor-lock.mjs +0 -442
- package/obsidian/editor-lock/package.json +0 -6
|
@@ -1,442 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
|
|
3
|
-
if you want to view the source, please visit the github repository of this plugin
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
(function initEsm() {
|
|
7
|
-
// eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
|
|
8
|
-
if (globalThis.process) {
|
|
9
|
-
return;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
const browserProcess = {
|
|
13
|
-
browser: true,
|
|
14
|
-
cwd() {
|
|
15
|
-
return '/';
|
|
16
|
-
},
|
|
17
|
-
env: {},
|
|
18
|
-
platform: 'android'
|
|
19
|
-
};
|
|
20
|
-
// eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
|
|
21
|
-
globalThis.process = browserProcess;
|
|
22
|
-
})();
|
|
23
|
-
|
|
24
|
-
import { ViewType } from "@obsidian-typings/obsidian-public-latest/implementations";
|
|
25
|
-
import {
|
|
26
|
-
MarkdownView,
|
|
27
|
-
Menu,
|
|
28
|
-
setIcon,
|
|
29
|
-
setTooltip,
|
|
30
|
-
TFile
|
|
31
|
-
} from "obsidian";
|
|
32
|
-
import { convertAsyncToSync } from "../async.mjs";
|
|
33
|
-
import {
|
|
34
|
-
CallbackDisposable,
|
|
35
|
-
MultipleDisposeBehavior
|
|
36
|
-
} from "../disposable.mjs";
|
|
37
|
-
import { noop } from "../function.mjs";
|
|
38
|
-
import { getObsidianDevUtilsState } from "../obsidian-dev-utils-state.mjs";
|
|
39
|
-
import { assertNonNullable } from "../type-guards.mjs";
|
|
40
|
-
import { ComponentEx } from "./components/component-ex.mjs";
|
|
41
|
-
import { toggleEditorReadOnly } from "./editor.mjs";
|
|
42
|
-
import { getPath } from "./file-system.mjs";
|
|
43
|
-
import { appendCodeBlock } from "./html-element.mjs";
|
|
44
|
-
import { t } from "./i18n/i18n.mjs";
|
|
45
|
-
import { confirm } from "./modals/confirm.mjs";
|
|
46
|
-
const BEEP_DURATION_SECONDS = 0.08;
|
|
47
|
-
const BEEP_FREQUENCY_HZ = 660;
|
|
48
|
-
const BEEP_GAIN = 0.05;
|
|
49
|
-
const BEEP_THROTTLE_MILLISECONDS = 200;
|
|
50
|
-
const EDITOR_LOCK_STATE_KEY = "editorLock";
|
|
51
|
-
const LOCK_ICON_ID = "lock";
|
|
52
|
-
const LOCK_INDICATOR_CSS_CLASS = "obsidian-dev-utils-lock-indicator";
|
|
53
|
-
const LOCK_INDICATOR_FLASH_CSS_CLASS = "obsidian-dev-utils-lock-indicator-flash";
|
|
54
|
-
const STATUS_BAR_ITEM_CSS_CLASS = "status-bar-item";
|
|
55
|
-
const STATUS_BAR_CSS_SELECTOR = ".status-bar";
|
|
56
|
-
const UNLOCK_ICON_ID = "unlock";
|
|
57
|
-
class EditorLockEventsComponent extends ComponentEx {
|
|
58
|
-
app;
|
|
59
|
-
onChange;
|
|
60
|
-
onFileMenu;
|
|
61
|
-
constructor(params) {
|
|
62
|
-
super();
|
|
63
|
-
this.app = params.app;
|
|
64
|
-
this.onChange = params.onChange;
|
|
65
|
-
this.onFileMenu = params.onFileMenu;
|
|
66
|
-
}
|
|
67
|
-
onload() {
|
|
68
|
-
super.onload();
|
|
69
|
-
this.registerEvent(this.app.workspace.on("active-leaf-change", this.onChange));
|
|
70
|
-
this.registerEvent(this.app.workspace.on("layout-change", this.onChange));
|
|
71
|
-
this.registerEvent(this.app.workspace.on("file-open", this.onChange));
|
|
72
|
-
this.registerEvent(this.app.workspace.on("file-menu", this.onFileMenu));
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
class EditorPathLockManager {
|
|
76
|
-
abortControllersByPath = /* @__PURE__ */ new Map();
|
|
77
|
-
audioContext = null;
|
|
78
|
-
eventsComponent;
|
|
79
|
-
indicatorsByView = /* @__PURE__ */ new Map();
|
|
80
|
-
lastBeepMilliseconds = 0;
|
|
81
|
-
lockCountByPluginIdByPath = /* @__PURE__ */ new Map();
|
|
82
|
-
statusBarItemEl = null;
|
|
83
|
-
isLocked(app, pathOrFile) {
|
|
84
|
-
return this.isPathLocked(getPath(app, pathOrFile));
|
|
85
|
-
}
|
|
86
|
-
lock(app, pathOrFile, pluginId, abortController) {
|
|
87
|
-
const path = getPath(app, pathOrFile);
|
|
88
|
-
let lockCountByPluginId = this.lockCountByPluginIdByPath.get(path);
|
|
89
|
-
if (!lockCountByPluginId) {
|
|
90
|
-
lockCountByPluginId = /* @__PURE__ */ new Map();
|
|
91
|
-
this.lockCountByPluginIdByPath.set(path, lockCountByPluginId);
|
|
92
|
-
}
|
|
93
|
-
lockCountByPluginId.set(pluginId, (lockCountByPluginId.get(pluginId) ?? 0) + 1);
|
|
94
|
-
if (abortController) {
|
|
95
|
-
let abortControllers = this.abortControllersByPath.get(path);
|
|
96
|
-
if (!abortControllers) {
|
|
97
|
-
abortControllers = /* @__PURE__ */ new Set();
|
|
98
|
-
this.abortControllersByPath.set(path, abortControllers);
|
|
99
|
-
}
|
|
100
|
-
abortControllers.add(abortController);
|
|
101
|
-
}
|
|
102
|
-
this.ensureSubscribed(app);
|
|
103
|
-
this.reconcile(app);
|
|
104
|
-
return new CallbackDisposable({
|
|
105
|
-
callback: () => {
|
|
106
|
-
if (abortController) {
|
|
107
|
-
const abortControllers = this.abortControllersByPath.get(path);
|
|
108
|
-
assertNonNullable(abortControllers);
|
|
109
|
-
abortControllers.delete(abortController);
|
|
110
|
-
if (abortControllers.size === 0) {
|
|
111
|
-
this.abortControllersByPath.delete(path);
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
this.unlockPath(app, path, pluginId);
|
|
115
|
-
},
|
|
116
|
-
multipleDisposeBehavior: MultipleDisposeBehavior.Ignore
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
/**
|
|
120
|
-
* Aborts every {@link AbortController} currently registered for the note at the given path, which
|
|
121
|
-
* cancels the operations holding the lock. Each operation releases its own lock in its `finally`
|
|
122
|
-
* when it observes the abort, so this does not unlock the path directly. A no-op when no controller
|
|
123
|
-
* is registered for the path.
|
|
124
|
-
*
|
|
125
|
-
* @param app - The Obsidian app instance.
|
|
126
|
-
* @param pathOrFile - The path or file of the note to request an unlock for.
|
|
127
|
-
*/
|
|
128
|
-
requestUnlock(app, pathOrFile) {
|
|
129
|
-
const abortControllers = this.abortControllersByPath.get(getPath(app, pathOrFile));
|
|
130
|
-
if (!abortControllers) {
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
for (const controller of abortControllers) {
|
|
134
|
-
controller.abort();
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
unlock(app, pathOrFile, pluginId) {
|
|
138
|
-
this.unlockPath(app, getPath(app, pathOrFile), pluginId);
|
|
139
|
-
}
|
|
140
|
-
unlockAllForPlugin(app, pluginId) {
|
|
141
|
-
for (const [path, lockCountByPluginId] of this.lockCountByPluginIdByPath) {
|
|
142
|
-
if (lockCountByPluginId.delete(pluginId) && lockCountByPluginId.size === 0) {
|
|
143
|
-
this.lockCountByPluginIdByPath.delete(path);
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
this.reconcileAndCleanup(app);
|
|
147
|
-
}
|
|
148
|
-
addUnlockMenuItem(app, menu, path) {
|
|
149
|
-
menu.addItem((item) => {
|
|
150
|
-
item.setTitle(t(($) => $.obsidianDevUtils.editorLock.unlockMenuItem)).setIcon(UNLOCK_ICON_ID).onClick(convertAsyncToSync(async () => {
|
|
151
|
-
const isConfirmed = await confirm({
|
|
152
|
-
app,
|
|
153
|
-
message: this.unlockConfirmMessage(app, path),
|
|
154
|
-
title: t(($) => $.obsidianDevUtils.editorLock.unlockConfirmTitle)
|
|
155
|
-
});
|
|
156
|
-
if (isConfirmed) {
|
|
157
|
-
this.requestUnlock(app, path);
|
|
158
|
-
}
|
|
159
|
-
}));
|
|
160
|
-
});
|
|
161
|
-
}
|
|
162
|
-
beep() {
|
|
163
|
-
const nowMilliseconds = Date.now();
|
|
164
|
-
if (nowMilliseconds - this.lastBeepMilliseconds < BEEP_THROTTLE_MILLISECONDS) {
|
|
165
|
-
return;
|
|
166
|
-
}
|
|
167
|
-
this.lastBeepMilliseconds = nowMilliseconds;
|
|
168
|
-
const AudioContextClass = window.AudioContext;
|
|
169
|
-
if (!AudioContextClass) {
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
this.audioContext ??= new AudioContextClass();
|
|
173
|
-
const audioContext = this.audioContext;
|
|
174
|
-
const oscillator = audioContext.createOscillator();
|
|
175
|
-
const gainNode = audioContext.createGain();
|
|
176
|
-
oscillator.type = "sine";
|
|
177
|
-
oscillator.frequency.value = BEEP_FREQUENCY_HZ;
|
|
178
|
-
gainNode.gain.value = BEEP_GAIN;
|
|
179
|
-
oscillator.connect(gainNode);
|
|
180
|
-
gainNode.connect(audioContext.destination);
|
|
181
|
-
oscillator.start();
|
|
182
|
-
oscillator.stop(audioContext.currentTime + BEEP_DURATION_SECONDS);
|
|
183
|
-
}
|
|
184
|
-
createIndicators(app, view, path, tooltip) {
|
|
185
|
-
const actionIconEl = view.addAction(LOCK_ICON_ID, tooltip, noop);
|
|
186
|
-
this.registerUnlockMenu(app, actionIconEl, () => path);
|
|
187
|
-
let tabIconEl = null;
|
|
188
|
-
const tabStatusContainerEl = view.leaf.tabHeaderStatusContainerEl;
|
|
189
|
-
if (tabStatusContainerEl) {
|
|
190
|
-
tabIconEl = tabStatusContainerEl.createSpan({ cls: LOCK_INDICATOR_CSS_CLASS });
|
|
191
|
-
setIcon(tabIconEl, LOCK_ICON_ID);
|
|
192
|
-
setTooltip(tabIconEl, tooltip);
|
|
193
|
-
this.registerUnlockMenu(app, tabIconEl, () => path);
|
|
194
|
-
}
|
|
195
|
-
const onTypeAttempt = () => {
|
|
196
|
-
this.flashIndicators(view);
|
|
197
|
-
this.beep();
|
|
198
|
-
};
|
|
199
|
-
view.contentEl.addEventListener("beforeinput", onTypeAttempt);
|
|
200
|
-
return {
|
|
201
|
-
actionIconEl,
|
|
202
|
-
disposeTypeListener: () => {
|
|
203
|
-
view.contentEl.removeEventListener("beforeinput", onTypeAttempt);
|
|
204
|
-
},
|
|
205
|
-
tabIconEl
|
|
206
|
-
};
|
|
207
|
-
}
|
|
208
|
-
ensureSubscribed(app) {
|
|
209
|
-
if (this.eventsComponent) {
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
this.eventsComponent = new EditorLockEventsComponent({
|
|
213
|
-
app,
|
|
214
|
-
onChange: () => {
|
|
215
|
-
this.reconcile(app);
|
|
216
|
-
},
|
|
217
|
-
onFileMenu: (menu, file) => {
|
|
218
|
-
this.handleFileMenu(app, menu, file);
|
|
219
|
-
}
|
|
220
|
-
});
|
|
221
|
-
this.eventsComponent.load();
|
|
222
|
-
}
|
|
223
|
-
flashElement(el) {
|
|
224
|
-
el.removeClass(LOCK_INDICATOR_FLASH_CSS_CLASS);
|
|
225
|
-
el.getBoundingClientRect();
|
|
226
|
-
el.addClass(LOCK_INDICATOR_FLASH_CSS_CLASS);
|
|
227
|
-
}
|
|
228
|
-
flashIndicators(view) {
|
|
229
|
-
const indicators = this.indicatorsByView.get(view);
|
|
230
|
-
for (const el of [indicators?.actionIconEl, indicators?.tabIconEl, this.statusBarItemEl]) {
|
|
231
|
-
if (el) {
|
|
232
|
-
this.flashElement(el);
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
handleFileMenu(app, menu, file) {
|
|
237
|
-
if (!(file instanceof TFile)) {
|
|
238
|
-
return;
|
|
239
|
-
}
|
|
240
|
-
if (!this.isPathLocked(file.path)) {
|
|
241
|
-
return;
|
|
242
|
-
}
|
|
243
|
-
this.addUnlockMenuItem(app, menu, file.path);
|
|
244
|
-
}
|
|
245
|
-
isPathLocked(path) {
|
|
246
|
-
return (this.lockCountByPluginIdByPath.get(path)?.size ?? 0) > 0;
|
|
247
|
-
}
|
|
248
|
-
lockingPluginNames(app, path) {
|
|
249
|
-
const lockCountByPluginId = this.lockCountByPluginIdByPath.get(path);
|
|
250
|
-
assertNonNullable(lockCountByPluginId);
|
|
251
|
-
return Array.from(lockCountByPluginId.keys()).map((pluginId) => app.plugins.manifests[pluginId]?.name ?? pluginId);
|
|
252
|
-
}
|
|
253
|
-
lockTooltip(app, path) {
|
|
254
|
-
const header = t(($) => $.obsidianDevUtils.editorLock.lockedByTooltip);
|
|
255
|
-
return [header, ...this.lockingPluginNames(app, path)].join("\n");
|
|
256
|
-
}
|
|
257
|
-
reconcile(app) {
|
|
258
|
-
const viewsToLock = /* @__PURE__ */ new Set();
|
|
259
|
-
for (const leaf of app.workspace.getLeavesOfType(ViewType.Markdown)) {
|
|
260
|
-
const view = leaf.view;
|
|
261
|
-
if (!(view instanceof MarkdownView)) {
|
|
262
|
-
continue;
|
|
263
|
-
}
|
|
264
|
-
const path = view.file?.path;
|
|
265
|
-
if (path === void 0) {
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
if (this.isPathLocked(path)) {
|
|
269
|
-
viewsToLock.add(view);
|
|
270
|
-
const tooltip = this.lockTooltip(app, path);
|
|
271
|
-
toggleEditorReadOnly(view.editor, true);
|
|
272
|
-
const indicators = this.indicatorsByView.get(view);
|
|
273
|
-
if (indicators) {
|
|
274
|
-
this.updateIndicatorTooltips(indicators, tooltip);
|
|
275
|
-
} else {
|
|
276
|
-
this.indicatorsByView.set(view, this.createIndicators(app, view, path, tooltip));
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
}
|
|
280
|
-
for (const [view, indicators] of this.indicatorsByView) {
|
|
281
|
-
if (!viewsToLock.has(view)) {
|
|
282
|
-
toggleEditorReadOnly(view.editor, false);
|
|
283
|
-
indicators.disposeTypeListener();
|
|
284
|
-
indicators.actionIconEl.remove();
|
|
285
|
-
indicators.tabIconEl?.remove();
|
|
286
|
-
this.indicatorsByView.delete(view);
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
this.updateStatusBar(app);
|
|
290
|
-
}
|
|
291
|
-
reconcileAndCleanup(app) {
|
|
292
|
-
this.reconcile(app);
|
|
293
|
-
if (this.lockCountByPluginIdByPath.size === 0) {
|
|
294
|
-
this.eventsComponent?.unload();
|
|
295
|
-
this.eventsComponent = void 0;
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
registerUnlockMenu(app, el, getContextPath) {
|
|
299
|
-
el.addEventListener("contextmenu", (evt) => {
|
|
300
|
-
evt.preventDefault();
|
|
301
|
-
const path = getContextPath();
|
|
302
|
-
if (path === void 0) {
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
const menu = new Menu();
|
|
306
|
-
this.addUnlockMenuItem(app, menu, path);
|
|
307
|
-
menu.showAtMouseEvent(evt);
|
|
308
|
-
});
|
|
309
|
-
}
|
|
310
|
-
unlockConfirmMessage(app, path) {
|
|
311
|
-
const fragment = createFragment();
|
|
312
|
-
fragment.appendText(t(($) => $.obsidianDevUtils.editorLock.unlockConfirmMessage));
|
|
313
|
-
for (const name of this.lockingPluginNames(app, path)) {
|
|
314
|
-
fragment.createEl("br");
|
|
315
|
-
appendCodeBlock(fragment, name);
|
|
316
|
-
}
|
|
317
|
-
return fragment;
|
|
318
|
-
}
|
|
319
|
-
unlockPath(app, path, pluginId) {
|
|
320
|
-
const lockCountByPluginId = this.lockCountByPluginIdByPath.get(path);
|
|
321
|
-
if (!lockCountByPluginId) {
|
|
322
|
-
return;
|
|
323
|
-
}
|
|
324
|
-
const count = lockCountByPluginId.get(pluginId) ?? 0;
|
|
325
|
-
if (count <= 0) {
|
|
326
|
-
return;
|
|
327
|
-
}
|
|
328
|
-
if (count === 1) {
|
|
329
|
-
lockCountByPluginId.delete(pluginId);
|
|
330
|
-
} else {
|
|
331
|
-
lockCountByPluginId.set(pluginId, count - 1);
|
|
332
|
-
}
|
|
333
|
-
if (lockCountByPluginId.size === 0) {
|
|
334
|
-
this.lockCountByPluginIdByPath.delete(path);
|
|
335
|
-
}
|
|
336
|
-
this.reconcileAndCleanup(app);
|
|
337
|
-
}
|
|
338
|
-
updateIndicatorTooltips(indicators, tooltip) {
|
|
339
|
-
setTooltip(indicators.actionIconEl, tooltip);
|
|
340
|
-
if (indicators.tabIconEl) {
|
|
341
|
-
setTooltip(indicators.tabIconEl, tooltip);
|
|
342
|
-
}
|
|
343
|
-
}
|
|
344
|
-
updateStatusBar(app) {
|
|
345
|
-
const activeView = app.workspace.getActiveViewOfType(MarkdownView);
|
|
346
|
-
const activePath = activeView?.file?.path;
|
|
347
|
-
const isActiveLocked = activePath !== void 0 && this.isPathLocked(activePath);
|
|
348
|
-
if (!isActiveLocked || !activeView) {
|
|
349
|
-
this.statusBarItemEl?.remove();
|
|
350
|
-
this.statusBarItemEl = null;
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
if (!this.statusBarItemEl) {
|
|
354
|
-
const statusBarEl = activeView.containerEl.ownerDocument.body.querySelector(STATUS_BAR_CSS_SELECTOR);
|
|
355
|
-
if (!statusBarEl) {
|
|
356
|
-
return;
|
|
357
|
-
}
|
|
358
|
-
this.statusBarItemEl = statusBarEl.createDiv({ cls: [STATUS_BAR_ITEM_CSS_CLASS, LOCK_INDICATOR_CSS_CLASS] });
|
|
359
|
-
setIcon(this.statusBarItemEl, LOCK_ICON_ID);
|
|
360
|
-
this.registerUnlockMenu(app, this.statusBarItemEl, () => app.workspace.getActiveViewOfType(MarkdownView)?.file?.path);
|
|
361
|
-
}
|
|
362
|
-
setTooltip(this.statusBarItemEl, this.lockTooltip(app, activePath));
|
|
363
|
-
}
|
|
364
|
-
}
|
|
365
|
-
class EditorLockComponent extends ComponentEx {
|
|
366
|
-
app;
|
|
367
|
-
pluginId;
|
|
368
|
-
/**
|
|
369
|
-
* Creates an editor-lock handle owned by a plugin.
|
|
370
|
-
*
|
|
371
|
-
* @param app - The Obsidian app instance.
|
|
372
|
-
* @param pluginId - The id of the owning plugin (e.g. its `manifest.id`). Locks are attributed to
|
|
373
|
-
* it for reference-counting and the indicators' "locked by" tooltip.
|
|
374
|
-
*/
|
|
375
|
-
constructor(app, pluginId) {
|
|
376
|
-
super();
|
|
377
|
-
this.app = app;
|
|
378
|
-
this.pluginId = pluginId;
|
|
379
|
-
}
|
|
380
|
-
/**
|
|
381
|
-
* Checks whether the note at the given path is currently locked by any plugin.
|
|
382
|
-
*
|
|
383
|
-
* @param pathOrFile - The path or file of the note to check.
|
|
384
|
-
* @returns `true` if the note has at least one active lock, `false` otherwise.
|
|
385
|
-
*/
|
|
386
|
-
isLockedForPath(pathOrFile) {
|
|
387
|
-
return getManager().isLocked(this.app, pathOrFile);
|
|
388
|
-
}
|
|
389
|
-
/**
|
|
390
|
-
* Locks the note at the given path on behalf of this plugin, making it read-only in every current
|
|
391
|
-
* and future {@link MarkdownView} until the lock is released. Reference-counted: balance each call
|
|
392
|
-
* with a dispose of the returned {@link Disposable} (ideally via `using`) or {@link unlockForPath}.
|
|
393
|
-
*
|
|
394
|
-
* @param pathOrFile - The path or file of the note to lock.
|
|
395
|
-
* @param options - Optional locking options. Pass an
|
|
396
|
-
* {@link EditorLockComponentLockForPathOptions.abortController} to make the lock cancelable via the
|
|
397
|
-
* indicator's right-click "unlock" menu or {@link requestEditorUnlockForPath}.
|
|
398
|
-
* @returns A {@link Disposable} that releases this lock when disposed. Disposing more than once is a no-op.
|
|
399
|
-
*/
|
|
400
|
-
lockForPath(pathOrFile, options) {
|
|
401
|
-
return getManager().lock(this.app, pathOrFile, this.pluginId, options?.abortController);
|
|
402
|
-
}
|
|
403
|
-
/**
|
|
404
|
-
* Releases every lock still held by this plugin when the component (and thus the plugin) unloads,
|
|
405
|
-
* so no note is left stuck read-only by an operation that never completed.
|
|
406
|
-
*/
|
|
407
|
-
onunload() {
|
|
408
|
-
getManager().unlockAllForPlugin(this.app, this.pluginId);
|
|
409
|
-
super.onunload();
|
|
410
|
-
}
|
|
411
|
-
/**
|
|
412
|
-
* Releases one lock previously acquired for the note at the given path via {@link lockForPath}.
|
|
413
|
-
*
|
|
414
|
-
* @param pathOrFile - The path or file of the note to unlock.
|
|
415
|
-
*/
|
|
416
|
-
unlockForPath(pathOrFile) {
|
|
417
|
-
getManager().unlock(this.app, pathOrFile, this.pluginId);
|
|
418
|
-
}
|
|
419
|
-
}
|
|
420
|
-
function isEditorLockedForPath(app, pathOrFile) {
|
|
421
|
-
return getManager().isLocked(app, pathOrFile);
|
|
422
|
-
}
|
|
423
|
-
function lockEditorForPath(app, pathOrFile, pluginId) {
|
|
424
|
-
return getManager().lock(app, pathOrFile, pluginId);
|
|
425
|
-
}
|
|
426
|
-
function requestEditorUnlockForPath(app, pathOrFile) {
|
|
427
|
-
getManager().requestUnlock(app, pathOrFile);
|
|
428
|
-
}
|
|
429
|
-
function unlockEditorForPath(app, pathOrFile, pluginId) {
|
|
430
|
-
getManager().unlock(app, pathOrFile, pluginId);
|
|
431
|
-
}
|
|
432
|
-
function getManager() {
|
|
433
|
-
return getObsidianDevUtilsState(EDITOR_LOCK_STATE_KEY, new EditorPathLockManager()).value;
|
|
434
|
-
}
|
|
435
|
-
export {
|
|
436
|
-
EditorLockComponent,
|
|
437
|
-
isEditorLockedForPath,
|
|
438
|
-
lockEditorForPath,
|
|
439
|
-
requestEditorUnlockForPath,
|
|
440
|
-
unlockEditorForPath
|
|
441
|
-
};
|
|
442
|
-
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL2VkaXRvci1sb2NrLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogTm90ZS1zY29wZWQsIHJlZmVyZW5jZS1jb3VudGVkIGVkaXRvciBsb2NraW5nLlxuICpcbiAqIFdoZXJlIHtAbGluayB0b2dnbGVFZGl0b3JSZWFkT25seX0gZnJvbSBgLi9lZGl0b3IudHNgIHRvZ2dsZXMgdGhlIHJlYWQtb25seSBzdGF0ZSBvZiBhIHNpbmdsZVxuICoge0BsaW5rIEVkaXRvcn0gaW5zdGFuY2UsIHRoZSBoZWxwZXJzIGhlcmUgbG9jayBhIG5vdGUgYnkgaXRzICoqcGF0aCoqOiB3aGlsZSBhIHBhdGggaXNcbiAqIGxvY2tlZCwgZXZlcnkgY3VycmVudCBhbmQgZnV0dXJlIHtAbGluayBNYXJrZG93blZpZXd9IG9mIHRoYXQgbm90ZSAoaW4gYW55IHdpbmRvdywgaW5jbHVkaW5nXG4gKiBwb3BvdXRzKSBpcyBtYWRlIHJlYWQtb25seSBhbmQgc2hvd3MgYSBsb2NrIGluZGljYXRvciBpbiBpdHMgdGFiIGhlYWRlciwgaXRzIHZpZXcgYWN0aW9uIGJhciwgYW5kXG4gKiB0aGUgc3RhdHVzIGJhciAod2hpbGUgdGhlIG5vdGUgaXMgYWN0aXZlKS4gTG9ja3MgYXJlIHJlZmVyZW5jZS1jb3VudGVkIHBlciBsb2NraW5nIHBsdWdpbiwgc29cbiAqIG5lc3RlZCBvciBjb25jdXJyZW50IG9wZXJhdGlvbnMgb24gdGhlIHNhbWUgbm90ZSBhcmUgc2FmZSBcdTIwMTQgdGhlIG5vdGUgaXMgdW5sb2NrZWQgb25seSB3aGVuIHRoZVxuICogbGFzdCBsb2NrIGlzIHJlbGVhc2VkIFx1MjAxNCBhbmQgdGhlIGluZGljYXRvcnMnIHRvb2x0aXAgbGlzdHMgd2hpY2ggcGx1Z2lucyBjdXJyZW50bHkgaG9sZCBhIGxvY2suXG4gKlxuICogVGhlIGFjcXVpcmVycyByZXR1cm4gYSB7QGxpbmsgRGlzcG9zYWJsZX0sIHNvIHRoZSBwcmVmZXJyZWQgY2FsbCBzdHlsZSBpcyBhIGB1c2luZ2AgZGVjbGFyYXRpb25cbiAqIHRoYXQgcmVsZWFzZXMgYXV0b21hdGljYWxseSBhdCBzY29wZSBleGl0IChpbmNsdWRpbmcgb24gdGhyb3cpOlxuICpcbiAqIGBgYHRzXG4gKiB1c2luZyBfbG9jayA9IGxvY2tFZGl0b3JGb3JQYXRoKGFwcCwgcGF0aCwgdGhpcy5tYW5pZmVzdC5pZCk7XG4gKiAvLyAuLi4gbG9uZy1ydW5uaW5nIHdvcmsgKHByb2Nlc3MsIHByb2Nlc3NGcm9udE1hdHRlciwgbWVyZ2Uvc3BsaXQpIC4uLlxuICogLy8gYXV0by11bmxvY2tlZCBhdCBzY29wZSBleGl0XG4gKiBgYGBcbiAqXG4gKiBUaGUgZXhwbGljaXQge0BsaW5rIHVubG9ja0VkaXRvckZvclBhdGh9IHBhaXIgcmVtYWlucyBhdmFpbGFibGUgZm9yIG5vbi1gdXNpbmdgIGNhbGwgc2l0ZXMuXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBBcHAsXG4gIFRBYnN0cmFjdEZpbGVcbn0gZnJvbSAnb2JzaWRpYW4nO1xuXG5pbXBvcnQgeyBWaWV3VHlwZSB9IGZyb20gJ0BvYnNpZGlhbi10eXBpbmdzL29ic2lkaWFuLXB1YmxpYy1sYXRlc3QvaW1wbGVtZW50YXRpb25zJztcbmltcG9ydCB7XG4gIE1hcmtkb3duVmlldyxcbiAgTWVudSxcbiAgc2V0SWNvbixcbiAgc2V0VG9vbHRpcCxcbiAgVEZpbGVcbn0gZnJvbSAnb2JzaWRpYW4nO1xuXG5pbXBvcnQgdHlwZSB7IFBhdGhPckZpbGUgfSBmcm9tICcuL2ZpbGUtc3lzdGVtLnRzJztcblxuaW1wb3J0IHsgY29udmVydEFzeW5jVG9TeW5jIH0gZnJvbSAnLi4vYXN5bmMudHMnO1xuaW1wb3J0IHtcbiAgQ2FsbGJhY2tEaXNwb3NhYmxlLFxuICBNdWx0aXBsZURpc3Bvc2VCZWhhdmlvclxufSBmcm9tICcuLi9kaXNwb3NhYmxlLnRzJztcbmltcG9ydCB7IG5vb3AgfSBmcm9tICcuLi9mdW5jdGlvbi50cyc7XG5pbXBvcnQgeyBnZXRPYnNpZGlhbkRldlV0aWxzU3RhdGUgfSBmcm9tICcuLi9vYnNpZGlhbi1kZXYtdXRpbHMtc3RhdGUudHMnO1xuaW1wb3J0IHsgYXNzZXJ0Tm9uTnVsbGFibGUgfSBmcm9tICcuLi90eXBlLWd1YXJkcy50cyc7XG5pbXBvcnQgeyBDb21wb25lbnRFeCB9IGZyb20gJy4vY29tcG9uZW50cy9jb21wb25lbnQtZXgudHMnO1xuaW1wb3J0IHsgdG9nZ2xlRWRpdG9yUmVhZE9ubHkgfSBmcm9tICcuL2VkaXRvci50cyc7XG5pbXBvcnQgeyBnZXRQYXRoIH0gZnJvbSAnLi9maWxlLXN5c3RlbS50cyc7XG5pbXBvcnQgeyBhcHBlbmRDb2RlQmxvY2sgfSBmcm9tICcuL2h0bWwtZWxlbWVudC50cyc7XG5pbXBvcnQgeyB0IH0gZnJvbSAnLi9pMThuL2kxOG4udHMnO1xuaW1wb3J0IHsgY29uZmlybSB9IGZyb20gJy4vbW9kYWxzL2NvbmZpcm0udHMnO1xuXG5jb25zdCBCRUVQX0RVUkFUSU9OX1NFQ09ORFMgPSAwLjA4O1xuY29uc3QgQkVFUF9GUkVRVUVOQ1lfSFogPSA2NjA7XG5jb25zdCBCRUVQX0dBSU4gPSAwLjA1O1xuY29uc3QgQkVFUF9USFJPVFRMRV9NSUxMSVNFQ09ORFMgPSAyMDA7XG5jb25zdCBFRElUT1JfTE9DS19TVEFURV9LRVkgPSAnZWRpdG9yTG9jayc7XG5jb25zdCBMT0NLX0lDT05fSUQgPSAnbG9jayc7XG5jb25zdCBMT0NLX0lORElDQVRPUl9DU1NfQ0xBU1MgPSAnb2JzaWRpYW4tZGV2LXV0aWxzLWxvY2staW5kaWNhdG9yJztcbmNvbnN0IExPQ0tfSU5ESUNBVE9SX0ZMQVNIX0NTU19DTEFTUyA9ICdvYnNpZGlhbi1kZXYtdXRpbHMtbG9jay1pbmRpY2F0b3ItZmxhc2gnO1xuY29uc3QgU1RBVFVTX0JBUl9JVEVNX0NTU19DTEFTUyA9ICdzdGF0dXMtYmFyLWl0ZW0nO1xuY29uc3QgU1RBVFVTX0JBUl9DU1NfU0VMRUNUT1IgPSAnLnN0YXR1cy1iYXInO1xuY29uc3QgVU5MT0NLX0lDT05fSUQgPSAndW5sb2NrJztcblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmsgRWRpdG9yTG9ja0NvbXBvbmVudC5sb2NrRm9yUGF0aH0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgRWRpdG9yTG9ja0NvbXBvbmVudExvY2tGb3JQYXRoT3B0aW9ucyB7XG4gIC8qKlxuICAgKiBBbiBvcHRpb25hbCB7QGxpbmsgQWJvcnRDb250cm9sbGVyfSBhc3NvY2lhdGVkIHdpdGggdGhlIGxvY2suIFdoZW4gdGhlIGxvY2sgaW5kaWNhdG9yIGlzXG4gICAqIHJpZ2h0LWNsaWNrZWQgYW5kIHRoZSB1c2VyIGNvbmZpcm1zIGFuIHVubG9jayAob3Ige0BsaW5rIHJlcXVlc3RFZGl0b3JVbmxvY2tGb3JQYXRofSBpcyBjYWxsZWQgZm9yXG4gICAqIHRoZSBwYXRoKSwgdGhpcyBjb250cm9sbGVyIGlzIGFib3J0ZWQgc28gdGhlIG9wZXJhdGlvbiBob2xkaW5nIHRoZSBsb2NrIGNhbiBjYW5jZWwgaXRzZWxmIGFuZFxuICAgKiByZWxlYXNlIHRoZSBsb2NrIGluIGl0cyBvd24gY2xlYW51cC5cbiAgICovXG4gIHJlYWRvbmx5IGFib3J0Q29udHJvbGxlcj86IEFib3J0Q29udHJvbGxlcjtcbn1cblxuLyoqXG4gKiBDb25zdHJ1Y3RvciBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgRWRpdG9yTG9ja0V2ZW50c0NvbXBvbmVudH0uXG4gKi9cbmludGVyZmFjZSBFZGl0b3JMb2NrRXZlbnRzQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMge1xuICByZWFkb25seSBhcHA6IEFwcDtcbiAgb25DaGFuZ2UodGhpczogdm9pZCk6IHZvaWQ7XG4gIG9uRmlsZU1lbnUodGhpczogdm9pZCwgbWVudTogTWVudSwgZmlsZTogVEFic3RyYWN0RmlsZSk6IHZvaWQ7XG59XG5cbmludGVyZmFjZSBMb2NrSW5kaWNhdG9ycyB7XG4gIHJlYWRvbmx5IGFjdGlvbkljb25FbDogSFRNTEVsZW1lbnQ7XG4gIGRpc3Bvc2VUeXBlTGlzdGVuZXIoKTogdm9pZDtcbiAgcmVhZG9ubHkgdGFiSWNvbkVsOiBIVE1MRWxlbWVudCB8IG51bGw7XG59XG5cbi8qKlxuICogU3Vic2NyaWJlcyB0byB0aGUgd29ya3NwYWNlIGV2ZW50cyB0aGF0IHNob3VsZCB0cmlnZ2VyIGEgbG9jayByZWNvbmNpbGUgKGFuZCB0aGUgZmlsZSBjb250ZXh0LW1lbnVcbiAqIGV2ZW50IHRoYXQgb2ZmZXJzIGFuIFwiVW5sb2NrXCIgaXRlbSkuIEltcGxlbWVudGVkIGFzIGEge0BsaW5rIENvbXBvbmVudEV4fSBzbyB0aGUgc3Vic2NyaXB0aW9ucyBhcmVcbiAqIHJlZ2lzdGVyZWQgb24gYGxvYWQoKWAgYW5kIGF1dG9tYXRpY2FsbHkgcmVtb3ZlZCBvbiBgdW5sb2FkKClgLCBpbnN0ZWFkIG9mIGJlaW5nIHRyYWNrZWQgYnkgaGFuZC5cbiAqL1xuY2xhc3MgRWRpdG9yTG9ja0V2ZW50c0NvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudEV4IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhcHA6IEFwcDtcbiAgcHJpdmF0ZSByZWFkb25seSBvbkNoYW5nZTogKCkgPT4gdm9pZDtcbiAgcHJpdmF0ZSByZWFkb25seSBvbkZpbGVNZW51OiAobWVudTogTWVudSwgZmlsZTogVEFic3RyYWN0RmlsZSkgPT4gdm9pZDtcblxuICBwdWJsaWMgY29uc3RydWN0b3IocGFyYW1zOiBFZGl0b3JMb2NrRXZlbnRzQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuYXBwID0gcGFyYW1zLmFwcDtcbiAgICB0aGlzLm9uQ2hhbmdlID0gcGFyYW1zLm9uQ2hhbmdlO1xuICAgIHRoaXMub25GaWxlTWVudSA9IHBhcmFtcy5vbkZpbGVNZW51O1xuICB9XG5cbiAgcHVibGljIG92ZXJyaWRlIG9ubG9hZCgpOiB2b2lkIHtcbiAgICBzdXBlci5vbmxvYWQoKTtcbiAgICB0aGlzLnJlZ2lzdGVyRXZlbnQodGhpcy5hcHAud29ya3NwYWNlLm9uKCdhY3RpdmUtbGVhZi1jaGFuZ2UnLCB0aGlzLm9uQ2hhbmdlKSk7XG4gICAgdGhpcy5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLndvcmtzcGFjZS5vbignbGF5b3V0LWNoYW5nZScsIHRoaXMub25DaGFuZ2UpKTtcbiAgICAvLyBTYW1lLWxlYWYgbmF2aWdhdGlvbiB0byBhbm90aGVyIG5vdGUgZmlyZXMgbm8gbGVhZi9sYXlvdXQgY2hhbmdlOyB3aXRob3V0IHRoaXMgaXQgc3RheXMgcmVhZC1vbmx5LlxuICAgIHRoaXMucmVnaXN0ZXJFdmVudCh0aGlzLmFwcC53b3Jrc3BhY2Uub24oJ2ZpbGUtb3BlbicsIHRoaXMub25DaGFuZ2UpKTtcbiAgICAvLyBBZGRzIGFuIFwiVW5sb2NrXCIgaXRlbSB0byBhIGxvY2tlZCBub3RlJ3MgdGFiL2ZpbGUgY29udGV4dCBtZW51IChhbG9uZ3NpZGUgdGhlIGluZGljYXRvciBtZW51cykuXG4gICAgdGhpcy5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLndvcmtzcGFjZS5vbignZmlsZS1tZW51JywgdGhpcy5vbkZpbGVNZW51KSk7XG4gIH1cbn1cblxuLyoqXG4gKiBUcmFja3MgcmVmZXJlbmNlLWNvdW50ZWQsIHBhdGgtc2NvcGVkIGVkaXRvciBsb2NrcyBhbmQga2VlcHMgZXZlcnkgb3BlbiB7QGxpbmsgTWFya2Rvd25WaWV3fSBpblxuICogc3luYyB3aXRoIHRoZSBsb2NrZWQtcGF0aCBzZXQuIEEgc2luZ2xlIGluc3RhbmNlIGxpdmVzIG9uIHRoZSBzaGFyZWQgYG9ic2lkaWFuLWRldi11dGlsc2Agc3RhdGUuXG4gKiBGb3IgZWFjaCBsb2NrZWQgcGF0aCB0aGUgbG9jayBjb3VudCBpcyB0cmFja2VkIHBlciBsb2NraW5nIHBsdWdpbiwgc28gdGhlIGluZGljYXRvcnMgY2FuIHJlcG9ydFxuICogd2hpY2ggcGx1Z2lucyBjdXJyZW50bHkgaG9sZCBhIGxvY2suXG4gKi9cbmNsYXNzIEVkaXRvclBhdGhMb2NrTWFuYWdlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYWJvcnRDb250cm9sbGVyc0J5UGF0aCA9IG5ldyBNYXA8c3RyaW5nLCBTZXQ8QWJvcnRDb250cm9sbGVyPj4oKTtcbiAgcHJpdmF0ZSBhdWRpb0NvbnRleHQ6IEF1ZGlvQ29udGV4dCB8IG51bGwgPSBudWxsO1xuICBwcml2YXRlIGV2ZW50c0NvbXBvbmVudDogRWRpdG9yTG9ja0V2ZW50c0NvbXBvbmVudCB8IHVuZGVmaW5lZDtcbiAgcHJpdmF0ZSByZWFkb25seSBpbmRpY2F0b3JzQnlWaWV3ID0gbmV3IE1hcDxNYXJrZG93blZpZXcsIExvY2tJbmRpY2F0b3JzPigpO1xuICBwcml2YXRlIGxhc3RCZWVwTWlsbGlzZWNvbmRzID0gMDtcbiAgcHJpdmF0ZSByZWFkb25seSBsb2NrQ291bnRCeVBsdWdpbklkQnlQYXRoID0gbmV3IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIG51bWJlcj4+KCk7XG4gIHByaXZhdGUgc3RhdHVzQmFySXRlbUVsOiBIVE1MRWxlbWVudCB8IG51bGwgPSBudWxsO1xuXG4gIHB1YmxpYyBpc0xvY2tlZChhcHA6IEFwcCwgcGF0aE9yRmlsZTogUGF0aE9yRmlsZSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB0aGlzLmlzUGF0aExvY2tlZChnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSkpO1xuICB9XG5cbiAgcHVibGljIGxvY2soYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUsIHBsdWdpbklkOiBzdHJpbmcsIGFib3J0Q29udHJvbGxlcj86IEFib3J0Q29udHJvbGxlcik6IERpc3Bvc2FibGUge1xuICAgIGNvbnN0IHBhdGggPSBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSk7XG4gICAgbGV0IGxvY2tDb3VudEJ5UGx1Z2luSWQgPSB0aGlzLmxvY2tDb3VudEJ5UGx1Z2luSWRCeVBhdGguZ2V0KHBhdGgpO1xuICAgIGlmICghbG9ja0NvdW50QnlQbHVnaW5JZCkge1xuICAgICAgbG9ja0NvdW50QnlQbHVnaW5JZCA9IG5ldyBNYXA8c3RyaW5nLCBudW1iZXI+KCk7XG4gICAgICB0aGlzLmxvY2tDb3VudEJ5UGx1Z2luSWRCeVBhdGguc2V0KHBhdGgsIGxvY2tDb3VudEJ5UGx1Z2luSWQpO1xuICAgIH1cbiAgICBsb2NrQ291bnRCeVBsdWdpbklkLnNldChwbHVnaW5JZCwgKGxvY2tDb3VudEJ5UGx1Z2luSWQuZ2V0KHBsdWdpbklkKSA/PyAwKSArIDEpO1xuICAgIGlmIChhYm9ydENvbnRyb2xsZXIpIHtcbiAgICAgIGxldCBhYm9ydENvbnRyb2xsZXJzID0gdGhpcy5hYm9ydENvbnRyb2xsZXJzQnlQYXRoLmdldChwYXRoKTtcbiAgICAgIGlmICghYWJvcnRDb250cm9sbGVycykge1xuICAgICAgICBhYm9ydENvbnRyb2xsZXJzID0gbmV3IFNldDxBYm9ydENvbnRyb2xsZXI+KCk7XG4gICAgICAgIHRoaXMuYWJvcnRDb250cm9sbGVyc0J5UGF0aC5zZXQocGF0aCwgYWJvcnRDb250cm9sbGVycyk7XG4gICAgICB9XG4gICAgICBhYm9ydENvbnRyb2xsZXJzLmFkZChhYm9ydENvbnRyb2xsZXIpO1xuICAgIH1cbiAgICB0aGlzLmVuc3VyZVN1YnNjcmliZWQoYXBwKTtcbiAgICB0aGlzLnJlY29uY2lsZShhcHApO1xuXG4gICAgcmV0dXJuIG5ldyBDYWxsYmFja0Rpc3Bvc2FibGUoe1xuICAgICAgY2FsbGJhY2s6ICgpOiB2b2lkID0+IHtcbiAgICAgICAgaWYgKGFib3J0Q29udHJvbGxlcikge1xuICAgICAgICAgIGNvbnN0IGFib3J0Q29udHJvbGxlcnMgPSB0aGlzLmFib3J0Q29udHJvbGxlcnNCeVBhdGguZ2V0KHBhdGgpO1xuICAgICAgICAgIC8vIFRoZSBzZXQgd2FzIGNyZWF0ZWQgd2hlbiB0aGlzIGxvY2sgYWRkZWQgaXRzIGNvbnRyb2xsZXIgYW5kIGlzIG9ubHkgcmVtb3ZlZCBoZXJlLlxuICAgICAgICAgIC8vIEl0IGlzIHRoZXJlZm9yZSBhbHdheXMgcHJlc2VudCB3aGlsZSB0aGlzIChzaW5nbGUtcnVuKSBkaXNwb3NhYmxlIGNhbGxiYWNrIGV4ZWN1dGVzLlxuICAgICAgICAgIGFzc2VydE5vbk51bGxhYmxlKGFib3J0Q29udHJvbGxlcnMpO1xuICAgICAgICAgIGFib3J0Q29udHJvbGxlcnMuZGVsZXRlKGFib3J0Q29udHJvbGxlcik7XG4gICAgICAgICAgaWYgKGFib3J0Q29udHJvbGxlcnMuc2l6ZSA9PT0gMCkge1xuICAgICAgICAgICAgdGhpcy5hYm9ydENvbnRyb2xsZXJzQnlQYXRoLmRlbGV0ZShwYXRoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy51bmxvY2tQYXRoKGFwcCwgcGF0aCwgcGx1Z2luSWQpO1xuICAgICAgfSxcbiAgICAgIG11bHRpcGxlRGlzcG9zZUJlaGF2aW9yOiBNdWx0aXBsZURpc3Bvc2VCZWhhdmlvci5JZ25vcmVcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBYm9ydHMgZXZlcnkge0BsaW5rIEFib3J0Q29udHJvbGxlcn0gY3VycmVudGx5IHJlZ2lzdGVyZWQgZm9yIHRoZSBub3RlIGF0IHRoZSBnaXZlbiBwYXRoLCB3aGljaFxuICAgKiBjYW5jZWxzIHRoZSBvcGVyYXRpb25zIGhvbGRpbmcgdGhlIGxvY2suIEVhY2ggb3BlcmF0aW9uIHJlbGVhc2VzIGl0cyBvd24gbG9jayBpbiBpdHMgYGZpbmFsbHlgXG4gICAqIHdoZW4gaXQgb2JzZXJ2ZXMgdGhlIGFib3J0LCBzbyB0aGlzIGRvZXMgbm90IHVubG9jayB0aGUgcGF0aCBkaXJlY3RseS4gQSBuby1vcCB3aGVuIG5vIGNvbnRyb2xsZXJcbiAgICogaXMgcmVnaXN0ZXJlZCBmb3IgdGhlIHBhdGguXG4gICAqXG4gICAqIEBwYXJhbSBhcHAgLSBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICAgKiBAcGFyYW0gcGF0aE9yRmlsZSAtIFRoZSBwYXRoIG9yIGZpbGUgb2YgdGhlIG5vdGUgdG8gcmVxdWVzdCBhbiB1bmxvY2sgZm9yLlxuICAgKi9cbiAgcHVibGljIHJlcXVlc3RVbmxvY2soYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUpOiB2b2lkIHtcbiAgICBjb25zdCBhYm9ydENvbnRyb2xsZXJzID0gdGhpcy5hYm9ydENvbnRyb2xsZXJzQnlQYXRoLmdldChnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSkpO1xuICAgIGlmICghYWJvcnRDb250cm9sbGVycykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBmb3IgKGNvbnN0IGNvbnRyb2xsZXIgb2YgYWJvcnRDb250cm9sbGVycykge1xuICAgICAgY29udHJvbGxlci5hYm9ydCgpO1xuICAgIH1cbiAgfVxuXG4gIHB1YmxpYyB1bmxvY2soYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUsIHBsdWdpbklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICB0aGlzLnVubG9ja1BhdGgoYXBwLCBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSksIHBsdWdpbklkKTtcbiAgfVxuXG4gIHB1YmxpYyB1bmxvY2tBbGxGb3JQbHVnaW4oYXBwOiBBcHAsIHBsdWdpbklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IFtwYXRoLCBsb2NrQ291bnRCeVBsdWdpbklkXSBvZiB0aGlzLmxvY2tDb3VudEJ5UGx1Z2luSWRCeVBhdGgpIHtcbiAgICAgIGlmIChsb2NrQ291bnRCeVBsdWdpbklkLmRlbGV0ZShwbHVnaW5JZCkgJiYgbG9ja0NvdW50QnlQbHVnaW5JZC5zaXplID09PSAwKSB7XG4gICAgICAgIHRoaXMubG9ja0NvdW50QnlQbHVnaW5JZEJ5UGF0aC5kZWxldGUocGF0aCk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucmVjb25jaWxlQW5kQ2xlYW51cChhcHApO1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRVbmxvY2tNZW51SXRlbShhcHA6IEFwcCwgbWVudTogTWVudSwgcGF0aDogc3RyaW5nKTogdm9pZCB7XG4gICAgbWVudS5hZGRJdGVtKChpdGVtKSA9PiB7XG4gICAgICBpdGVtXG4gICAgICAgIC5zZXRUaXRsZSh0KCgkKSA9PiAkLm9ic2lkaWFuRGV2VXRpbHMuZWRpdG9yTG9jay51bmxvY2tNZW51SXRlbSkpXG4gICAgICAgIC5zZXRJY29uKFVOTE9DS19JQ09OX0lEKVxuICAgICAgICAub25DbGljayhjb252ZXJ0QXN5bmNUb1N5bmMoYXN5bmMgKCkgPT4ge1xuICAgICAgICAgIGNvbnN0IGlzQ29uZmlybWVkID0gYXdhaXQgY29uZmlybSh7XG4gICAgICAgICAgICBhcHAsXG4gICAgICAgICAgICBtZXNzYWdlOiB0aGlzLnVubG9ja0NvbmZpcm1NZXNzYWdlKGFwcCwgcGF0aCksXG4gICAgICAgICAgICB0aXRsZTogdCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLmVkaXRvckxvY2sudW5sb2NrQ29uZmlybVRpdGxlKVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIGlmIChpc0NvbmZpcm1lZCkge1xuICAgICAgICAgICAgdGhpcy5yZXF1ZXN0VW5sb2NrKGFwcCwgcGF0aCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGJlZXAoKTogdm9pZCB7XG4gICAgLy8gVGhyb3R0bGUgc28gYSBidXJzdCBvZiBrZXlzdHJva2VzIGRvZXMgbm90IHN0YWNrIG92ZXJsYXBwaW5nIHRvbmVzIGludG8gYSBidXp6LlxuICAgIGNvbnN0IG5vd01pbGxpc2Vjb25kcyA9IERhdGUubm93KCk7XG4gICAgaWYgKG5vd01pbGxpc2Vjb25kcyAtIHRoaXMubGFzdEJlZXBNaWxsaXNlY29uZHMgPCBCRUVQX1RIUk9UVExFX01JTExJU0VDT05EUykge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmxhc3RCZWVwTWlsbGlzZWNvbmRzID0gbm93TWlsbGlzZWNvbmRzO1xuXG4gICAgLy8gYGxpYi5kb21gIHR5cGVzIGBBdWRpb0NvbnRleHRgIGFzIGFsd2F5cyBwcmVzZW50LCBidXQgaXQgaXMgYWJzZW50IGluIHNvbWUgcnVudGltZXNcbiAgICAvLyAoZS5nLiB0aGUganNkb20gdGVzdCBlbnZpcm9ubWVudCksIHNvIHRoaXMgZ3VhcmQgaXMgcmVhbCwgbm90IHJlZHVuZGFudC5cbiAgICBjb25zdCBBdWRpb0NvbnRleHRDbGFzcyA9IHdpbmRvdy5BdWRpb0NvbnRleHQ7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb24gLS0gc2VlIHRoZSBjb21tZW50IGFib3ZlLlxuICAgIGlmICghQXVkaW9Db250ZXh0Q2xhc3MpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hdWRpb0NvbnRleHQgPz89IG5ldyBBdWRpb0NvbnRleHRDbGFzcygpO1xuICAgIGNvbnN0IGF1ZGlvQ29udGV4dCA9IHRoaXMuYXVkaW9Db250ZXh0O1xuICAgIGNvbnN0IG9zY2lsbGF0b3IgPSBhdWRpb0NvbnRleHQuY3JlYXRlT3NjaWxsYXRvcigpO1xuICAgIGNvbnN0IGdhaW5Ob2RlID0gYXVkaW9Db250ZXh0LmNyZWF0ZUdhaW4oKTtcbiAgICBvc2NpbGxhdG9yLnR5cGUgPSAnc2luZSc7XG4gICAgb3NjaWxsYXRvci5mcmVxdWVuY3kudmFsdWUgPSBCRUVQX0ZSRVFVRU5DWV9IWjtcbiAgICBnYWluTm9kZS5nYWluLnZhbHVlID0gQkVFUF9HQUlOO1xuICAgIG9zY2lsbGF0b3IuY29ubmVjdChnYWluTm9kZSk7XG4gICAgZ2Fpbk5vZGUuY29ubmVjdChhdWRpb0NvbnRleHQuZGVzdGluYXRpb24pO1xuICAgIG9zY2lsbGF0b3Iuc3RhcnQoKTtcbiAgICBvc2NpbGxhdG9yLnN0b3AoYXVkaW9Db250ZXh0LmN1cnJlbnRUaW1lICsgQkVFUF9EVVJBVElPTl9TRUNPTkRTKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlSW5kaWNhdG9ycyhhcHA6IEFwcCwgdmlldzogTWFya2Rvd25WaWV3LCBwYXRoOiBzdHJpbmcsIHRvb2x0aXA6IHN0cmluZyk6IExvY2tJbmRpY2F0b3JzIHtcbiAgICBjb25zdCBhY3Rpb25JY29uRWwgPSB2aWV3LmFkZEFjdGlvbihMT0NLX0lDT05fSUQsIHRvb2x0aXAsIG5vb3ApO1xuICAgIHRoaXMucmVnaXN0ZXJVbmxvY2tNZW51KGFwcCwgYWN0aW9uSWNvbkVsLCAoKSA9PiBwYXRoKTtcblxuICAgIGxldCB0YWJJY29uRWw6IEhUTUxFbGVtZW50IHwgbnVsbCA9IG51bGw7XG4gICAgY29uc3QgdGFiU3RhdHVzQ29udGFpbmVyRWwgPSB2aWV3LmxlYWYudGFiSGVhZGVyU3RhdHVzQ29udGFpbmVyRWw7XG4gICAgaWYgKHRhYlN0YXR1c0NvbnRhaW5lckVsKSB7XG4gICAgICB0YWJJY29uRWwgPSB0YWJTdGF0dXNDb250YWluZXJFbC5jcmVhdGVTcGFuKHsgY2xzOiBMT0NLX0lORElDQVRPUl9DU1NfQ0xBU1MgfSk7XG4gICAgICBzZXRJY29uKHRhYkljb25FbCwgTE9DS19JQ09OX0lEKTtcbiAgICAgIHNldFRvb2x0aXAodGFiSWNvbkVsLCB0b29sdGlwKTtcbiAgICAgIHRoaXMucmVnaXN0ZXJVbmxvY2tNZW51KGFwcCwgdGFiSWNvbkVsLCAoKSA9PiBwYXRoKTtcbiAgICB9XG5cbiAgICAvLyBBIGxvY2tlZCB2aWV3IGlzIHJlYWQtb25seSBidXQgc3RpbGwgZWRpdGFibGUtZm9jdXNhYmxlLCBzbyBhIGtleXN0cm9rZSBmaXJlcyBgYmVmb3JlaW5wdXRgLlxuICAgIC8vIE9uIHRoYXQgcmVqZWN0ZWQgYXR0ZW1wdCwgZmxhc2ggdGhlIGluZGljYXRvcnMgYW5kIGJlZXAgc28gaXQncyBjbGVhciB0aGUgbm90ZSBpcyBsb2NrZWQuXG4gICAgLy8gVGhlIGxpc3RlbmVyIGlzIHJlbW92ZWQgb24gdW5sb2NrLlxuICAgIGNvbnN0IG9uVHlwZUF0dGVtcHQgPSAoKTogdm9pZCA9PiB7XG4gICAgICB0aGlzLmZsYXNoSW5kaWNhdG9ycyh2aWV3KTtcbiAgICAgIHRoaXMuYmVlcCgpO1xuICAgIH07XG4gICAgdmlldy5jb250ZW50RWwuYWRkRXZlbnRMaXN0ZW5lcignYmVmb3JlaW5wdXQnLCBvblR5cGVBdHRlbXB0KTtcblxuICAgIHJldHVybiB7XG4gICAgICBhY3Rpb25JY29uRWwsXG4gICAgICBkaXNwb3NlVHlwZUxpc3RlbmVyOiAoKTogdm9pZCA9PiB7XG4gICAgICAgIHZpZXcuY29udGVudEVsLnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2JlZm9yZWlucHV0Jywgb25UeXBlQXR0ZW1wdCk7XG4gICAgICB9LFxuICAgICAgdGFiSWNvbkVsXG4gICAgfTtcbiAgfVxuXG4gIHByaXZhdGUgZW5zdXJlU3Vic2NyaWJlZChhcHA6IEFwcCk6IHZvaWQge1xuICAgIGlmICh0aGlzLmV2ZW50c0NvbXBvbmVudCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmV2ZW50c0NvbXBvbmVudCA9IG5ldyBFZGl0b3JMb2NrRXZlbnRzQ29tcG9uZW50KHtcbiAgICAgIGFwcCxcbiAgICAgIG9uQ2hhbmdlOiAoKTogdm9pZCA9PiB7XG4gICAgICAgIHRoaXMucmVjb25jaWxlKGFwcCk7XG4gICAgICB9LFxuICAgICAgb25GaWxlTWVudTogKG1lbnUsIGZpbGUpOiB2b2lkID0+IHtcbiAgICAgICAgdGhpcy5oYW5kbGVGaWxlTWVudShhcHAsIG1lbnUsIGZpbGUpO1xuICAgICAgfVxuICAgIH0pO1xuICAgIHRoaXMuZXZlbnRzQ29tcG9uZW50LmxvYWQoKTtcbiAgfVxuXG4gIHByaXZhdGUgZmxhc2hFbGVtZW50KGVsOiBIVE1MRWxlbWVudCk6IHZvaWQge1xuICAgIGVsLnJlbW92ZUNsYXNzKExPQ0tfSU5ESUNBVE9SX0ZMQVNIX0NTU19DTEFTUyk7XG4gICAgLy8gUmVhZCBsYXlvdXQgdG8gZm9yY2UgYSByZWZsb3cgc28gdGhlIGZsYXNoIGFuaW1hdGlvbiByZXN0YXJ0cyBvbiBldmVyeSByZWplY3RlZCBrZXlzdHJva2UuXG4gICAgZWwuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgZWwuYWRkQ2xhc3MoTE9DS19JTkRJQ0FUT1JfRkxBU0hfQ1NTX0NMQVNTKTtcbiAgfVxuXG4gIHByaXZhdGUgZmxhc2hJbmRpY2F0b3JzKHZpZXc6IE1hcmtkb3duVmlldyk6IHZvaWQge1xuICAgIGNvbnN0IGluZGljYXRvcnMgPSB0aGlzLmluZGljYXRvcnNCeVZpZXcuZ2V0KHZpZXcpO1xuICAgIGZvciAoY29uc3QgZWwgb2YgW2luZGljYXRvcnM/LmFjdGlvbkljb25FbCwgaW5kaWNhdG9ycz8udGFiSWNvbkVsLCB0aGlzLnN0YXR1c0Jhckl0ZW1FbF0pIHtcbiAgICAgIGlmIChlbCkge1xuICAgICAgICB0aGlzLmZsYXNoRWxlbWVudChlbCk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBoYW5kbGVGaWxlTWVudShhcHA6IEFwcCwgbWVudTogTWVudSwgZmlsZTogVEFic3RyYWN0RmlsZSk6IHZvaWQge1xuICAgIGlmICghKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKCF0aGlzLmlzUGF0aExvY2tlZChmaWxlLnBhdGgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIHRoaXMuYWRkVW5sb2NrTWVudUl0ZW0oYXBwLCBtZW51LCBmaWxlLnBhdGgpO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1BhdGhMb2NrZWQocGF0aDogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuICh0aGlzLmxvY2tDb3VudEJ5UGx1Z2luSWRCeVBhdGguZ2V0KHBhdGgpPy5zaXplID8/IDApID4gMDtcbiAgfVxuXG4gIHByaXZhdGUgbG9ja2luZ1BsdWdpbk5hbWVzKGFwcDogQXBwLCBwYXRoOiBzdHJpbmcpOiBzdHJpbmdbXSB7XG4gICAgY29uc3QgbG9ja0NvdW50QnlQbHVnaW5JZCA9IHRoaXMubG9ja0NvdW50QnlQbHVnaW5JZEJ5UGF0aC5nZXQocGF0aCk7XG4gICAgLy8gYGxvY2tpbmdQbHVnaW5OYW1lc2AgaXMgb25seSBldmVyIGNhbGxlZCBmb3IgYSBsb2NrZWQgcGF0aCwgc28gdGhlIHBlci1wbHVnaW4gbWFwIGlzIGFsd2F5cyBwcmVzZW50LlxuICAgIGFzc2VydE5vbk51bGxhYmxlKGxvY2tDb3VudEJ5UGx1Z2luSWQpO1xuICAgIHJldHVybiBBcnJheS5mcm9tKGxvY2tDb3VudEJ5UGx1Z2luSWQua2V5cygpKS5tYXAoKHBsdWdpbklkKSA9PiBhcHAucGx1Z2lucy5tYW5pZmVzdHNbcGx1Z2luSWRdPy5uYW1lID8/IHBsdWdpbklkKTtcbiAgfVxuXG4gIHByaXZhdGUgbG9ja1Rvb2x0aXAoYXBwOiBBcHAsIHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gICAgY29uc3QgaGVhZGVyID0gdCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLmVkaXRvckxvY2subG9ja2VkQnlUb29sdGlwKTtcbiAgICAvLyBBIHJ1bnRpbWUtbGVuZ3RoIGxpc3Qgb2YgcGx1Z2luIG5hbWVzLCBvbmUgcGVyIGxpbmUgdW5kZXIgdGhlIGhlYWRlci5cbiAgICByZXR1cm4gW2hlYWRlciwgLi4udGhpcy5sb2NraW5nUGx1Z2luTmFtZXMoYXBwLCBwYXRoKV0uam9pbignXFxuJyk7XG4gIH1cblxuICBwcml2YXRlIHJlY29uY2lsZShhcHA6IEFwcCk6IHZvaWQge1xuICAgIGNvbnN0IHZpZXdzVG9Mb2NrID0gbmV3IFNldDxNYXJrZG93blZpZXc+KCk7XG4gICAgZm9yIChjb25zdCBsZWFmIG9mIGFwcC53b3Jrc3BhY2UuZ2V0TGVhdmVzT2ZUeXBlKFZpZXdUeXBlLk1hcmtkb3duKSkge1xuICAgICAgY29uc3QgdmlldyA9IGxlYWYudmlldztcbiAgICAgIGlmICghKHZpZXcgaW5zdGFuY2VvZiBNYXJrZG93blZpZXcpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBjb25zdCBwYXRoID0gdmlldy5maWxlPy5wYXRoO1xuICAgICAgaWYgKHBhdGggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgaWYgKHRoaXMuaXNQYXRoTG9ja2VkKHBhdGgpKSB7XG4gICAgICAgIHZpZXdzVG9Mb2NrLmFkZCh2aWV3KTtcbiAgICAgICAgY29uc3QgdG9vbHRpcCA9IHRoaXMubG9ja1Rvb2x0aXAoYXBwLCBwYXRoKTtcbiAgICAgICAgLy8gUmUtYXBwbHkgdGhlIHJlYWQtb25seSB0b2dnbGUgb24gZXZlcnkgcmVjb25jaWxlLCBub3Qgb25seSB0aGUgZmlyc3QgdGltZSBhIHZpZXcgaXMgdHJhY2tlZC5cbiAgICAgICAgLy8gVGhlIHRvZ2dsZSBpcyBpZGVtcG90ZW50LCBzbyByZS1hcHBseWluZyB0byBhbiBhbHJlYWR5LWxvY2tlZCB2aWV3IGlzIGNoZWFwLlxuICAgICAgICAvLyBBIHZpZXcgb3BlbmVkIGFmdGVyIHRoZSBsb2NrIGlzIHJlY29uY2lsZWQgc3luY2hyb25vdXNseSwgYmVmb3JlIGl0cyBDb2RlTWlycm9yIGlzIHJlYWR5LlxuICAgICAgICAvLyBJdHMgZmlyc3QgdG9nZ2xlIGlzIHRoZXJlZm9yZSBhIG5vLW9wOyByZS1hcHBseWluZyBtYWtlcyB0aGUgbG9jayB0YWtlIGhvbGQgb25jZSBpdCBzZXR0bGVzLlxuICAgICAgICB0b2dnbGVFZGl0b3JSZWFkT25seSh2aWV3LmVkaXRvciwgdHJ1ZSk7XG4gICAgICAgIGNvbnN0IGluZGljYXRvcnMgPSB0aGlzLmluZGljYXRvcnNCeVZpZXcuZ2V0KHZpZXcpO1xuICAgICAgICBpZiAoaW5kaWNhdG9ycykge1xuICAgICAgICAgIHRoaXMudXBkYXRlSW5kaWNhdG9yVG9vbHRpcHMoaW5kaWNhdG9ycywgdG9vbHRpcCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhpcy5pbmRpY2F0b3JzQnlWaWV3LnNldCh2aWV3LCB0aGlzLmNyZWF0ZUluZGljYXRvcnMoYXBwLCB2aWV3LCBwYXRoLCB0b29sdGlwKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IFt2aWV3LCBpbmRpY2F0b3JzXSBvZiB0aGlzLmluZGljYXRvcnNCeVZpZXcpIHtcbiAgICAgIGlmICghdmlld3NUb0xvY2suaGFzKHZpZXcpKSB7XG4gICAgICAgIHRvZ2dsZUVkaXRvclJlYWRPbmx5KHZpZXcuZWRpdG9yLCBmYWxzZSk7XG4gICAgICAgIGluZGljYXRvcnMuZGlzcG9zZVR5cGVMaXN0ZW5lcigpO1xuICAgICAgICBpbmRpY2F0b3JzLmFjdGlvbkljb25FbC5yZW1vdmUoKTtcbiAgICAgICAgaW5kaWNhdG9ycy50YWJJY29uRWw/LnJlbW92ZSgpO1xuICAgICAgICB0aGlzLmluZGljYXRvcnNCeVZpZXcuZGVsZXRlKHZpZXcpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHRoaXMudXBkYXRlU3RhdHVzQmFyKGFwcCk7XG4gIH1cblxuICBwcml2YXRlIHJlY29uY2lsZUFuZENsZWFudXAoYXBwOiBBcHApOiB2b2lkIHtcbiAgICB0aGlzLnJlY29uY2lsZShhcHApO1xuICAgIGlmICh0aGlzLmxvY2tDb3VudEJ5UGx1Z2luSWRCeVBhdGguc2l6ZSA9PT0gMCkge1xuICAgICAgdGhpcy5ldmVudHNDb21wb25lbnQ/LnVubG9hZCgpO1xuICAgICAgdGhpcy5ldmVudHNDb21wb25lbnQgPSB1bmRlZmluZWQ7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSByZWdpc3RlclVubG9ja01lbnUoYXBwOiBBcHAsIGVsOiBIVE1MRWxlbWVudCwgZ2V0Q29udGV4dFBhdGg6ICgpID0+IHN0cmluZyB8IHVuZGVmaW5lZCk6IHZvaWQge1xuICAgIC8vIEEgcGxhaW4gbGlzdGVuZXIgZGllcyB3aXRoIHRoZSBlbGVtZW50IHdoZW4gaXQgaXMgYC5yZW1vdmUoKWBkIG9uIHVubG9jaywgc28gaXQgbmV2ZXIgbGVha3MuXG4gICAgZWwuYWRkRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCAoZXZ0KSA9PiB7XG4gICAgICBldnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGNvbnN0IHBhdGggPSBnZXRDb250ZXh0UGF0aCgpO1xuICAgICAgaWYgKHBhdGggPT09IHVuZGVmaW5lZCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBjb25zdCBtZW51ID0gbmV3IE1lbnUoKTtcbiAgICAgIHRoaXMuYWRkVW5sb2NrTWVudUl0ZW0oYXBwLCBtZW51LCBwYXRoKTtcbiAgICAgIG1lbnUuc2hvd0F0TW91c2VFdmVudChldnQpO1xuICAgIH0pO1xuICB9XG5cbiAgcHJpdmF0ZSB1bmxvY2tDb25maXJtTWVzc2FnZShhcHA6IEFwcCwgcGF0aDogc3RyaW5nKTogRG9jdW1lbnRGcmFnbWVudCB7XG4gICAgY29uc3QgZnJhZ21lbnQgPSBjcmVhdGVGcmFnbWVudCgpO1xuICAgIGZyYWdtZW50LmFwcGVuZFRleHQodCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLmVkaXRvckxvY2sudW5sb2NrQ29uZmlybU1lc3NhZ2UpKTtcbiAgICAvLyBBIHJ1bnRpbWUtbGVuZ3RoIGxpc3Qgb2YgdGhlIHBsdWdpbnMgY3VycmVudGx5IGhvbGRpbmcgYSBsb2NrLCBlYWNoIGFzIGEgY29kZSBibG9jayBvbiBpdHMgb3duIGxpbmUuXG4gICAgZm9yIChjb25zdCBuYW1lIG9mIHRoaXMubG9ja2luZ1BsdWdpbk5hbWVzKGFwcCwgcGF0aCkpIHtcbiAgICAgIGZyYWdtZW50LmNyZWF0ZUVsKCdicicpO1xuICAgICAgYXBwZW5kQ29kZUJsb2NrKGZyYWdtZW50LCBuYW1lKTtcbiAgICB9XG4gICAgcmV0dXJuIGZyYWdtZW50O1xuICB9XG5cbiAgcHJpdmF0ZSB1bmxvY2tQYXRoKGFwcDogQXBwLCBwYXRoOiBzdHJpbmcsIHBsdWdpbklkOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBsb2NrQ291bnRCeVBsdWdpbklkID0gdGhpcy5sb2NrQ291bnRCeVBsdWdpbklkQnlQYXRoLmdldChwYXRoKTtcbiAgICBpZiAoIWxvY2tDb3VudEJ5UGx1Z2luSWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zdCBjb3VudCA9IGxvY2tDb3VudEJ5UGx1Z2luSWQuZ2V0KHBsdWdpbklkKSA/PyAwO1xuICAgIGlmIChjb3VudCA8PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGNvdW50ID09PSAxKSB7XG4gICAgICBsb2NrQ291bnRCeVBsdWdpbklkLmRlbGV0ZShwbHVnaW5JZCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvY2tDb3VudEJ5UGx1Z2luSWQuc2V0KHBsdWdpbklkLCBjb3VudCAtIDEpO1xuICAgIH1cblxuICAgIGlmIChsb2NrQ291bnRCeVBsdWdpbklkLnNpemUgPT09IDApIHtcbiAgICAgIHRoaXMubG9ja0NvdW50QnlQbHVnaW5JZEJ5UGF0aC5kZWxldGUocGF0aCk7XG4gICAgfVxuXG4gICAgdGhpcy5yZWNvbmNpbGVBbmRDbGVhbnVwKGFwcCk7XG4gIH1cblxuICBwcml2YXRlIHVwZGF0ZUluZGljYXRvclRvb2x0aXBzKGluZGljYXRvcnM6IExvY2tJbmRpY2F0b3JzLCB0b29sdGlwOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBzZXRUb29sdGlwKGluZGljYXRvcnMuYWN0aW9uSWNvbkVsLCB0b29sdGlwKTtcbiAgICBpZiAoaW5kaWNhdG9ycy50YWJJY29uRWwpIHtcbiAgICAgIHNldFRvb2x0aXAoaW5kaWNhdG9ycy50YWJJY29uRWwsIHRvb2x0aXApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgdXBkYXRlU3RhdHVzQmFyKGFwcDogQXBwKTogdm9pZCB7XG4gICAgY29uc3QgYWN0aXZlVmlldyA9IGFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShNYXJrZG93blZpZXcpO1xuICAgIGNvbnN0IGFjdGl2ZVBhdGggPSBhY3RpdmVWaWV3Py5maWxlPy5wYXRoO1xuICAgIGNvbnN0IGlzQWN0aXZlTG9ja2VkID0gYWN0aXZlUGF0aCAhPT0gdW5kZWZpbmVkICYmIHRoaXMuaXNQYXRoTG9ja2VkKGFjdGl2ZVBhdGgpO1xuXG4gICAgaWYgKCFpc0FjdGl2ZUxvY2tlZCB8fCAhYWN0aXZlVmlldykge1xuICAgICAgdGhpcy5zdGF0dXNCYXJJdGVtRWw/LnJlbW92ZSgpO1xuICAgICAgdGhpcy5zdGF0dXNCYXJJdGVtRWwgPSBudWxsO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5zdGF0dXNCYXJJdGVtRWwpIHtcbiAgICAgIGNvbnN0IHN0YXR1c0JhckVsID0gYWN0aXZlVmlldy5jb250YWluZXJFbC5vd25lckRvY3VtZW50LmJvZHkucXVlcnlTZWxlY3RvcjxIVE1MRWxlbWVudD4oU1RBVFVTX0JBUl9DU1NfU0VMRUNUT1IpO1xuICAgICAgaWYgKCFzdGF0dXNCYXJFbCkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICB0aGlzLnN0YXR1c0Jhckl0ZW1FbCA9IHN0YXR1c0JhckVsLmNyZWF0ZURpdih7IGNsczogW1NUQVRVU19CQVJfSVRFTV9DU1NfQ0xBU1MsIExPQ0tfSU5ESUNBVE9SX0NTU19DTEFTU10gfSk7XG4gICAgICBzZXRJY29uKHRoaXMuc3RhdHVzQmFySXRlbUVsLCBMT0NLX0lDT05fSUQpO1xuICAgICAgLy8gVGhlIHNpbmdsZSBzdGF0dXMtYmFyIGl0ZW0gaXMgcmV1c2VkIGFjcm9zcyBhY3RpdmUtbm90ZSBzd2l0Y2hlcy5cbiAgICAgIC8vIEl0IG11c3QgcmVzb2x2ZSB0aGUgY3VycmVudGx5IGFjdGl2ZSBub3RlJ3MgcGF0aCBhdCBjbGljayB0aW1lIHJhdGhlciB0aGFuIGNhcHR1cmluZyBvbmUgcGF0aC5cbiAgICAgIHRoaXMucmVnaXN0ZXJVbmxvY2tNZW51KGFwcCwgdGhpcy5zdGF0dXNCYXJJdGVtRWwsICgpID0+IGFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShNYXJrZG93blZpZXcpPy5maWxlPy5wYXRoKTtcbiAgICB9XG5cbiAgICBzZXRUb29sdGlwKHRoaXMuc3RhdHVzQmFySXRlbUVsLCB0aGlzLmxvY2tUb29sdGlwKGFwcCwgYWN0aXZlUGF0aCkpO1xuICB9XG59XG5cbi8qKlxuICogQSBwZXItcGx1Z2luIGhhbmRsZSBmb3Igbm90ZS1zY29wZWQgZWRpdG9yIGxvY2tpbmcuIEFkZCBpdCBhcyBhIGNoaWxkIG9mIHlvdXIgcGx1Z2luXG4gKiAoYHRoaXMuYWRkQ2hpbGQobmV3IEVkaXRvckxvY2tDb21wb25lbnQodGhpcy5hcHApKWApIHNvIHRoYXQgYW55IGxvY2tzIGl0IHN0aWxsIGhvbGRzIGFyZSByZWxlYXNlZFxuICogYXV0b21hdGljYWxseSB3aGVuIHRoZSBwbHVnaW4gdW5sb2FkcyBcdTIwMTQgYSBub3RlIGNhbiBuZXZlciBiZSBsZWZ0IHN0dWNrIHJlYWQtb25seSBiZWNhdXNlIHRoZVxuICogcGx1Z2luIHRoYXQgbG9ja2VkIGl0IHdhcyBkaXNhYmxlZCBvciByZWxvYWRlZCBtaWQtb3BlcmF0aW9uLlxuICpcbiAqIExvY2tzIGFyZSByZWZlcmVuY2UtY291bnRlZCBhbmQgYXR0cmlidXRlZCB0byB0aGlzIHBsdWdpbiwgc28gdGhlIGxvY2sgaW5kaWNhdG9ycycgdG9vbHRpcCBuYW1lc1xuICogaXQgYW1vbmcgdGhlIHBsdWdpbnMgY3VycmVudGx5IGhvbGRpbmcgYSBsb2NrLlxuICovXG5leHBvcnQgY2xhc3MgRWRpdG9yTG9ja0NvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudEV4IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhcHA6IEFwcDtcbiAgcHJpdmF0ZSByZWFkb25seSBwbHVnaW5JZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGVkaXRvci1sb2NrIGhhbmRsZSBvd25lZCBieSBhIHBsdWdpbi5cbiAgICpcbiAgICogQHBhcmFtIGFwcCAtIFRoZSBPYnNpZGlhbiBhcHAgaW5zdGFuY2UuXG4gICAqIEBwYXJhbSBwbHVnaW5JZCAtIFRoZSBpZCBvZiB0aGUgb3duaW5nIHBsdWdpbiAoZS5nLiBpdHMgYG1hbmlmZXN0LmlkYCkuIExvY2tzIGFyZSBhdHRyaWJ1dGVkIHRvXG4gICAqIGl0IGZvciByZWZlcmVuY2UtY291bnRpbmcgYW5kIHRoZSBpbmRpY2F0b3JzJyBcImxvY2tlZCBieVwiIHRvb2x0aXAuXG4gICAqL1xuICBwdWJsaWMgY29uc3RydWN0b3IoYXBwOiBBcHAsIHBsdWdpbklkOiBzdHJpbmcpIHtcbiAgICBzdXBlcigpO1xuICAgIHRoaXMuYXBwID0gYXBwO1xuICAgIHRoaXMucGx1Z2luSWQgPSBwbHVnaW5JZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDaGVja3Mgd2hldGhlciB0aGUgbm90ZSBhdCB0aGUgZ2l2ZW4gcGF0aCBpcyBjdXJyZW50bHkgbG9ja2VkIGJ5IGFueSBwbHVnaW4uXG4gICAqXG4gICAqIEBwYXJhbSBwYXRoT3JGaWxlIC0gVGhlIHBhdGggb3IgZmlsZSBvZiB0aGUgbm90ZSB0byBjaGVjay5cbiAgICogQHJldHVybnMgYHRydWVgIGlmIHRoZSBub3RlIGhhcyBhdCBsZWFzdCBvbmUgYWN0aXZlIGxvY2ssIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICAgKi9cbiAgcHVibGljIGlzTG9ja2VkRm9yUGF0aChwYXRoT3JGaWxlOiBQYXRoT3JGaWxlKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIGdldE1hbmFnZXIoKS5pc0xvY2tlZCh0aGlzLmFwcCwgcGF0aE9yRmlsZSk7XG4gIH1cblxuICAvKipcbiAgICogTG9ja3MgdGhlIG5vdGUgYXQgdGhlIGdpdmVuIHBhdGggb24gYmVoYWxmIG9mIHRoaXMgcGx1Z2luLCBtYWtpbmcgaXQgcmVhZC1vbmx5IGluIGV2ZXJ5IGN1cnJlbnRcbiAgICogYW5kIGZ1dHVyZSB7QGxpbmsgTWFya2Rvd25WaWV3fSB1bnRpbCB0aGUgbG9jayBpcyByZWxlYXNlZC4gUmVmZXJlbmNlLWNvdW50ZWQ6IGJhbGFuY2UgZWFjaCBjYWxsXG4gICAqIHdpdGggYSBkaXNwb3NlIG9mIHRoZSByZXR1cm5lZCB7QGxpbmsgRGlzcG9zYWJsZX0gKGlkZWFsbHkgdmlhIGB1c2luZ2ApIG9yIHtAbGluayB1bmxvY2tGb3JQYXRofS5cbiAgICpcbiAgICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgcGF0aCBvciBmaWxlIG9mIHRoZSBub3RlIHRvIGxvY2suXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3B0aW9uYWwgbG9ja2luZyBvcHRpb25zLiBQYXNzIGFuXG4gICAqIHtAbGluayBFZGl0b3JMb2NrQ29tcG9uZW50TG9ja0ZvclBhdGhPcHRpb25zLmFib3J0Q29udHJvbGxlcn0gdG8gbWFrZSB0aGUgbG9jayBjYW5jZWxhYmxlIHZpYSB0aGVcbiAgICogaW5kaWNhdG9yJ3MgcmlnaHQtY2xpY2sgXCJ1bmxvY2tcIiBtZW51IG9yIHtAbGluayByZXF1ZXN0RWRpdG9yVW5sb2NrRm9yUGF0aH0uXG4gICAqIEByZXR1cm5zIEEge0BsaW5rIERpc3Bvc2FibGV9IHRoYXQgcmVsZWFzZXMgdGhpcyBsb2NrIHdoZW4gZGlzcG9zZWQuIERpc3Bvc2luZyBtb3JlIHRoYW4gb25jZSBpcyBhIG5vLW9wLlxuICAgKi9cbiAgcHVibGljIGxvY2tGb3JQYXRoKHBhdGhPckZpbGU6IFBhdGhPckZpbGUsIG9wdGlvbnM/OiBFZGl0b3JMb2NrQ29tcG9uZW50TG9ja0ZvclBhdGhPcHRpb25zKTogRGlzcG9zYWJsZSB7XG4gICAgcmV0dXJuIGdldE1hbmFnZXIoKS5sb2NrKHRoaXMuYXBwLCBwYXRoT3JGaWxlLCB0aGlzLnBsdWdpbklkLCBvcHRpb25zPy5hYm9ydENvbnRyb2xsZXIpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbGVhc2VzIGV2ZXJ5IGxvY2sgc3RpbGwgaGVsZCBieSB0aGlzIHBsdWdpbiB3aGVuIHRoZSBjb21wb25lbnQgKGFuZCB0aHVzIHRoZSBwbHVnaW4pIHVubG9hZHMsXG4gICAqIHNvIG5vIG5vdGUgaXMgbGVmdCBzdHVjayByZWFkLW9ubHkgYnkgYW4gb3BlcmF0aW9uIHRoYXQgbmV2ZXIgY29tcGxldGVkLlxuICAgKi9cbiAgcHVibGljIG92ZXJyaWRlIG9udW5sb2FkKCk6IHZvaWQge1xuICAgIGdldE1hbmFnZXIoKS51bmxvY2tBbGxGb3JQbHVnaW4odGhpcy5hcHAsIHRoaXMucGx1Z2luSWQpO1xuICAgIHN1cGVyLm9udW5sb2FkKCk7XG4gIH1cblxuICAvKipcbiAgICogUmVsZWFzZXMgb25lIGxvY2sgcHJldmlvdXNseSBhY3F1aXJlZCBmb3IgdGhlIG5vdGUgYXQgdGhlIGdpdmVuIHBhdGggdmlhIHtAbGluayBsb2NrRm9yUGF0aH0uXG4gICAqXG4gICAqIEBwYXJhbSBwYXRoT3JGaWxlIC0gVGhlIHBhdGggb3IgZmlsZSBvZiB0aGUgbm90ZSB0byB1bmxvY2suXG4gICAqL1xuICBwdWJsaWMgdW5sb2NrRm9yUGF0aChwYXRoT3JGaWxlOiBQYXRoT3JGaWxlKTogdm9pZCB7XG4gICAgZ2V0TWFuYWdlcigpLnVubG9jayh0aGlzLmFwcCwgcGF0aE9yRmlsZSwgdGhpcy5wbHVnaW5JZCk7XG4gIH1cbn1cblxuLyoqXG4gKiBDaGVja3Mgd2hldGhlciB0aGUgbm90ZSBhdCB0aGUgZ2l2ZW4gcGF0aCBpcyBjdXJyZW50bHkgbG9ja2VkLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgcGF0aCBvciBmaWxlIG9mIHRoZSBub3RlIHRvIGNoZWNrLlxuICogQHJldHVybnMgYHRydWVgIGlmIHRoZSBub3RlIGhhcyBhdCBsZWFzdCBvbmUgYWN0aXZlIGxvY2ssIGBmYWxzZWAgb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNFZGl0b3JMb2NrZWRGb3JQYXRoKGFwcDogQXBwLCBwYXRoT3JGaWxlOiBQYXRoT3JGaWxlKTogYm9vbGVhbiB7XG4gIHJldHVybiBnZXRNYW5hZ2VyKCkuaXNMb2NrZWQoYXBwLCBwYXRoT3JGaWxlKTtcbn1cblxuLyoqXG4gKiBMb2NrcyB0aGUgbm90ZSBhdCB0aGUgZ2l2ZW4gcGF0aCwgbWFraW5nIGl0IHJlYWQtb25seSBpbiBldmVyeSBjdXJyZW50IGFuZCBmdXR1cmVcbiAqIHtAbGluayBNYXJrZG93blZpZXd9IHVudGlsIHRoZSBsb2NrIGlzIHJlbGVhc2VkLCBhbmQgc2hvd2luZyBhIGxvY2sgaW5kaWNhdG9yIGluIHRoZSB0YWIgaGVhZGVyLFxuICogdmlldyBhY3Rpb24gYmFyLCBhbmQgKHdoaWxlIGFjdGl2ZSkgdGhlIHN0YXR1cyBiYXIuIFRoZSBpbmRpY2F0b3JzJyB0b29sdGlwIGxpc3RzIHRoZSBwbHVnaW5zXG4gKiB0aGF0IGN1cnJlbnRseSBob2xkIGEgbG9jayBvbiB0aGUgbm90ZS5cbiAqXG4gKiBUaGUgbG9jayBpcyByZWZlcmVuY2UtY291bnRlZCBwZXIgY2FsbGluZyBwbHVnaW46IGVhY2ggY2FsbCBtdXN0IGJlIGJhbGFuY2VkIGJ5IGV4YWN0bHkgb25lXG4gKiByZWxlYXNlIChlaXRoZXIgZGlzcG9zaW5nIHRoZSByZXR1cm5lZCB7QGxpbmsgRGlzcG9zYWJsZX0gXHUyMDE0IGlkZWFsbHkgdmlhIGEgYHVzaW5nYCBkZWNsYXJhdGlvbiBcdTIwMTQgb3JcbiAqIGEgbWF0Y2hpbmcge0BsaW5rIHVubG9ja0VkaXRvckZvclBhdGh9IGNhbGwpLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgcGF0aCBvciBmaWxlIG9mIHRoZSBub3RlIHRvIGxvY2suXG4gKiBAcGFyYW0gcGx1Z2luSWQgLSBUaGUgaWQgb2YgdGhlIGxvY2tpbmcgcGx1Z2luIChlLmcuIGl0cyBgbWFuaWZlc3QuaWRgKS4gVGhlIGxvY2sgaXMgYXR0cmlidXRlZCB0b1xuICogaXQgZm9yIHJlZmVyZW5jZS1jb3VudGluZyBhbmQgdGhlIGluZGljYXRvcnMnIFwibG9ja2VkIGJ5XCIgdG9vbHRpcC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIERpc3Bvc2FibGV9IHRoYXQgcmVsZWFzZXMgdGhpcyBsb2NrIHdoZW4gZGlzcG9zZWQuIERpc3Bvc2luZyBtb3JlIHRoYW4gb25jZSBpcyBhIG5vLW9wLlxuICovXG5leHBvcnQgZnVuY3Rpb24gbG9ja0VkaXRvckZvclBhdGgoYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUsIHBsdWdpbklkOiBzdHJpbmcpOiBEaXNwb3NhYmxlIHtcbiAgcmV0dXJuIGdldE1hbmFnZXIoKS5sb2NrKGFwcCwgcGF0aE9yRmlsZSwgcGx1Z2luSWQpO1xufVxuXG4vKipcbiAqIFJlcXVlc3RzIGFuIHVubG9jayBvZiB0aGUgbm90ZSBhdCB0aGUgZ2l2ZW4gcGF0aCBieSBhYm9ydGluZyBldmVyeSB7QGxpbmsgQWJvcnRDb250cm9sbGVyfSB0aGF0IHdhc1xuICogYXNzb2NpYXRlZCB3aXRoIGEgbG9jayBvbiBpdCAodmlhIHtAbGluayBFZGl0b3JMb2NrQ29tcG9uZW50LmxvY2tGb3JQYXRofSdzXG4gKiB7QGxpbmsgRWRpdG9yTG9ja0NvbXBvbmVudExvY2tGb3JQYXRoT3B0aW9ucy5hYm9ydENvbnRyb2xsZXJ9KS4gVGhlIG9wZXJhdGlvbnMgaG9sZGluZyB0aGUgbG9ja1xuICogb2JzZXJ2ZSB0aGUgYWJvcnQgYW5kIHJlbGVhc2UgdGhlaXIgb3duIGxvY2tzLiBBIG5vLW9wIHdoZW4gbm8gYWJvcnRhYmxlIGxvY2sgaXMgcmVnaXN0ZXJlZCBmb3IgdGhlXG4gKiBwYXRoLlxuICpcbiAqIFRoaXMgbGV0cyBhIGNvbnN1bWluZyBwbHVnaW4gd2lyZSBpdHMgb3duIFwidW5sb2NrIGFjdGl2ZSBub3RlXCIgY29tbWFuZCB3aXRob3V0IHJlYWNoaW5nIGludG8gdGhlXG4gKiBsb2NrIG1hbmFnZXIgZGlyZWN0bHkuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBPYnNpZGlhbiBhcHAgaW5zdGFuY2UuXG4gKiBAcGFyYW0gcGF0aE9yRmlsZSAtIFRoZSBwYXRoIG9yIGZpbGUgb2YgdGhlIG5vdGUgdG8gcmVxdWVzdCBhbiB1bmxvY2sgZm9yLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVxdWVzdEVkaXRvclVubG9ja0ZvclBhdGgoYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUpOiB2b2lkIHtcbiAgZ2V0TWFuYWdlcigpLnJlcXVlc3RVbmxvY2soYXBwLCBwYXRoT3JGaWxlKTtcbn1cblxuLyoqXG4gKiBSZWxlYXNlcyBvbmUgbG9jayBwcmV2aW91c2x5IGFjcXVpcmVkIGZvciB0aGUgbm90ZSBhdCB0aGUgZ2l2ZW4gcGF0aCB2aWEge0BsaW5rIGxvY2tFZGl0b3JGb3JQYXRofS5cbiAqXG4gKiBXaGVuIHRoZSBsYXN0IGxvY2sgaXMgcmVsZWFzZWQgdGhlIG5vdGUgYmVjb21lcyBmdWxseSBlZGl0YWJsZSBhZ2FpbiBhbmQgaXRzIGxvY2sgaW5kaWNhdG9ycyBhcmVcbiAqIHJlbW92ZWQuIENhbGxpbmcgdGhpcyB3aGVuIHRoZSBub3RlIGlzIG5vdCBsb2NrZWQgaXMgYSBuby1vcC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIE9ic2lkaWFuIGFwcCBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoT3JGaWxlIC0gVGhlIHBhdGggb3IgZmlsZSBvZiB0aGUgbm90ZSB0byB1bmxvY2suXG4gKiBAcGFyYW0gcGx1Z2luSWQgLSBUaGUgaWQgb2YgdGhlIHBsdWdpbiB0aGF0IGhvbGRzIHRoZSBsb2NrIChlLmcuIGl0cyBgbWFuaWZlc3QuaWRgKTsgb25lIG9mIGl0c1xuICogbG9ja3Mgb24gdGhlIG5vdGUgaXMgcmVsZWFzZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1bmxvY2tFZGl0b3JGb3JQYXRoKGFwcDogQXBwLCBwYXRoT3JGaWxlOiBQYXRoT3JGaWxlLCBwbHVnaW5JZDogc3RyaW5nKTogdm9pZCB7XG4gIGdldE1hbmFnZXIoKS51bmxvY2soYXBwLCBwYXRoT3JGaWxlLCBwbHVnaW5JZCk7XG59XG5cbmZ1bmN0aW9uIGdldE1hbmFnZXIoKTogRWRpdG9yUGF0aExvY2tNYW5hZ2VyIHtcbiAgcmV0dXJuIGdldE9ic2lkaWFuRGV2VXRpbHNTdGF0ZTxFZGl0b3JQYXRoTG9ja01hbmFnZXI+KEVESVRPUl9MT0NLX1NUQVRFX0tFWSwgbmV3IEVkaXRvclBhdGhMb2NrTWFuYWdlcigpKS52YWx1ZTtcbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBOEJBLFNBQVMsZ0JBQWdCO0FBQ3pCO0FBQUEsRUFDRTtB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
|