obsidian-dev-utils 101.6.0 → 101.7.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.
Files changed (64) hide show
  1. package/CHANGELOG.md +5 -0
  2. package/dist/integration-test-plugin/main.js +4410 -3705
  3. package/dist/lib/cjs/__merged.cjs +26 -1
  4. package/dist/lib/cjs/__merged.d.cts +4 -1
  5. package/dist/lib/cjs/generated-during-build.cjs +1 -1
  6. package/dist/lib/cjs/obsidian/components/component-ex.cjs +14 -1
  7. package/dist/lib/cjs/obsidian/components/component-ex.d.cts +11 -0
  8. package/dist/lib/cjs/obsidian/components/index.cjs +4 -1
  9. package/dist/lib/cjs/obsidian/components/index.d.cts +1 -0
  10. package/dist/lib/cjs/obsidian/components/plugin-gate-component.cjs +520 -0
  11. package/dist/lib/cjs/obsidian/components/plugin-gate-component.d.cts +299 -0
  12. package/dist/lib/cjs/obsidian/components/plugin-suggestion-component.cjs +17 -38
  13. package/dist/lib/cjs/obsidian/components/plugin-suggestion-component.d.cts +25 -18
  14. package/dist/lib/cjs/obsidian/components/rename-delete-handler-component.cjs +7 -2
  15. package/dist/lib/cjs/obsidian/css-class.cjs +3 -1
  16. package/dist/lib/cjs/obsidian/css-class.d.cts +9 -0
  17. package/dist/lib/cjs/obsidian/html-element.cjs +27 -3
  18. package/dist/lib/cjs/obsidian/html-element.d.cts +36 -0
  19. package/dist/lib/cjs/obsidian/i18n/locales/en.cjs +15 -1
  20. package/dist/lib/cjs/obsidian/i18n/locales/en.d.cts +14 -0
  21. package/dist/lib/cjs/obsidian/i18n/locales/translations-map.d.cts +14 -0
  22. package/dist/lib/cjs/obsidian/plugin/index.cjs +7 -1
  23. package/dist/lib/cjs/obsidian/plugin/index.d.cts +2 -0
  24. package/dist/lib/cjs/obsidian/plugin/plugin-api.cjs +2 -2
  25. package/dist/lib/cjs/obsidian/plugin/plugin-api.d.cts +34 -15
  26. package/dist/lib/cjs/obsidian/plugin/plugin-install-state.cjs +208 -0
  27. package/dist/lib/cjs/obsidian/plugin/plugin-install-state.d.cts +113 -0
  28. package/dist/lib/cjs/obsidian/plugin/plugin-lifecycle-events.cjs +161 -0
  29. package/dist/lib/cjs/obsidian/plugin/plugin-lifecycle-events.d.cts +119 -0
  30. package/dist/lib/cjs/obsidian/plugin/plugin.cjs +241 -21
  31. package/dist/lib/cjs/obsidian/plugin/plugin.d.cts +133 -4
  32. package/dist/lib/esm/__merged.d.mts +4 -1
  33. package/dist/lib/esm/__merged.mjs +30 -2
  34. package/dist/lib/esm/generated-during-build.mjs +1 -1
  35. package/dist/lib/esm/obsidian/components/component-ex.d.mts +11 -0
  36. package/dist/lib/esm/obsidian/components/component-ex.mjs +14 -1
  37. package/dist/lib/esm/obsidian/components/index.d.mts +1 -0
  38. package/dist/lib/esm/obsidian/components/index.mjs +3 -1
  39. package/dist/lib/esm/obsidian/components/plugin-gate-component.d.mts +299 -0
  40. package/dist/lib/esm/obsidian/components/plugin-gate-component.mjs +428 -0
  41. package/dist/lib/esm/obsidian/components/plugin-suggestion-component.d.mts +25 -18
  42. package/dist/lib/esm/obsidian/components/plugin-suggestion-component.mjs +21 -41
  43. package/dist/lib/esm/obsidian/components/rename-delete-handler-component.mjs +7 -2
  44. package/dist/lib/esm/obsidian/css-class.d.mts +9 -0
  45. package/dist/lib/esm/obsidian/css-class.mjs +3 -1
  46. package/dist/lib/esm/obsidian/html-element.d.mts +36 -0
  47. package/dist/lib/esm/obsidian/html-element.mjs +24 -2
  48. package/dist/lib/esm/obsidian/i18n/locales/en.d.mts +14 -0
  49. package/dist/lib/esm/obsidian/i18n/locales/en.mjs +15 -1
  50. package/dist/lib/esm/obsidian/i18n/locales/translations-map.d.mts +14 -0
  51. package/dist/lib/esm/obsidian/plugin/index.d.mts +2 -0
  52. package/dist/lib/esm/obsidian/plugin/index.mjs +5 -1
  53. package/dist/lib/esm/obsidian/plugin/plugin-api.d.mts +34 -15
  54. package/dist/lib/esm/obsidian/plugin/plugin-api.mjs +2 -2
  55. package/dist/lib/esm/obsidian/plugin/plugin-install-state.d.mts +113 -0
  56. package/dist/lib/esm/obsidian/plugin/plugin-install-state.mjs +106 -0
  57. package/dist/lib/esm/obsidian/plugin/plugin-lifecycle-events.d.mts +119 -0
  58. package/dist/lib/esm/obsidian/plugin/plugin-lifecycle-events.mjs +54 -0
  59. package/dist/lib/esm/obsidian/plugin/plugin.d.mts +133 -4
  60. package/dist/lib/esm/obsidian/plugin/plugin.mjs +245 -21
  61. package/obsidian/components/plugin-gate-component/package.json +6 -0
  62. package/obsidian/plugin/plugin-install-state/package.json +6 -0
  63. package/obsidian/plugin/plugin-lifecycle-events/package.json +6 -0
  64. package/package.json +1 -1
@@ -0,0 +1,428 @@
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 () {
7
+ function ensureBrowserProcess() {
8
+ const browserProcess = {
9
+ browser: true,
10
+ cwd() {
11
+ return '/';
12
+ },
13
+ env: {},
14
+ platform: 'android'
15
+ };
16
+
17
+ // eslint-disable-next-line obsidianmd/no-global-this, unicorn/no-unnecessary-global-this -- Must stay `globalThis`-qualified: in the emitted banner a bare `process` is a free identifier, so reading it where the host has none throws a ReferenceError instead of yielding `undefined`. That is the very case this function exists to handle.
18
+ const existingProcess = globalThis.process;
19
+
20
+ if (!existingProcess) {
21
+ // eslint-disable-next-line obsidianmd/no-global-this -- Actively use globalThis.
22
+ globalThis.process = browserProcess;
23
+ return;
24
+ }
25
+
26
+ if (existingProcess.versions?.node) {
27
+ return;
28
+ }
29
+
30
+ const existingProcessRecord = existingProcess;
31
+
32
+ for (const [key, value] of Object.entries(browserProcess)) {
33
+ existingProcessRecord[key] ??= value;
34
+ }
35
+
36
+ existingProcessRecord['browser'] = true;
37
+ }
38
+
39
+ (function initEsm() {
40
+ ensureBrowserProcess();
41
+ })();
42
+ })();
43
+
44
+ import { satisfies as satisfiesVersion } from "compare-versions";
45
+ import {
46
+ ButtonComponent,
47
+ PluginSettingTab
48
+ } from "obsidian";
49
+ import { convertAsyncToSync } from "../../async.mjs";
50
+ import { disableCommunityPlugin } from "../community-plugins.mjs";
51
+ import { CssClass } from "../css-class.mjs";
52
+ import {
53
+ asCodeBlock,
54
+ createFragmentWithCodeBlocks
55
+ } from "../html-element.mjs";
56
+ import { t } from "../i18n/i18n.mjs";
57
+ import { watchPluginApi } from "../plugin/plugin-api.mjs";
58
+ import {
59
+ getInstalledPluginState,
60
+ getInstalledPluginVersion,
61
+ installAndEnablePlugin,
62
+ InstalledPluginState
63
+ } from "../plugin/plugin-install-state.mjs";
64
+ import {
65
+ PLUGIN_LOADED_EVENT_NAME,
66
+ PLUGIN_UNLOADED_EVENT_NAME
67
+ } from "../plugin/plugin-lifecycle-events.mjs";
68
+ import { registerAsyncEvent } from "./async-events-component.mjs";
69
+ import { ComponentEx } from "./component-ex.mjs";
70
+ import { CallbackLayoutReadyComponent } from "./layout-ready-component.mjs";
71
+ var PluginConflictSeverity = /* @__PURE__ */ ((PluginConflictSeverity2) => {
72
+ PluginConflictSeverity2["Block"] = "block";
73
+ PluginConflictSeverity2["Warn"] = "warn";
74
+ return PluginConflictSeverity2;
75
+ })(PluginConflictSeverity || {});
76
+ class BlockedPluginSettingTab extends PluginSettingTab {
77
+ renderBanner;
78
+ /**
79
+ * Creates an instance of {@link BlockedPluginSettingTab}.
80
+ *
81
+ * @param params - The constructor parameters.
82
+ */
83
+ constructor(params) {
84
+ super(params.plugin.app, params.plugin);
85
+ this.renderBanner = params.renderBanner;
86
+ }
87
+ /**
88
+ * Renders the tab.
89
+ */
90
+ display() {
91
+ this.containerEl.empty();
92
+ this.renderBanner(this.containerEl);
93
+ }
94
+ }
95
+ class PluginGateComponent extends ComponentEx {
96
+ announcedWarningPluginIds = /* @__PURE__ */ new Set();
97
+ apiRefs = /* @__PURE__ */ new Map();
98
+ blockedSettingTab = null;
99
+ conflicts;
100
+ dependencies;
101
+ hasAnnouncedBlocked = false;
102
+ isFeatureSurfaceLoaded = false;
103
+ isLayoutReady = false;
104
+ loadFeatureSurface;
105
+ plugin;
106
+ pluginNoticeComponent;
107
+ unloadFeatureSurface;
108
+ get app() {
109
+ return this.plugin.app;
110
+ }
111
+ /**
112
+ * Creates an instance of {@link PluginGateComponent}.
113
+ *
114
+ * @param params - The constructor parameters.
115
+ */
116
+ constructor(params) {
117
+ super();
118
+ this.conflicts = params.conflicts;
119
+ this.dependencies = params.dependencies;
120
+ this.loadFeatureSurface = params.loadFeatureSurface;
121
+ this.plugin = params.plugin;
122
+ this.pluginNoticeComponent = params.pluginNoticeComponent;
123
+ this.unloadFeatureSurface = params.unloadFeatureSurface;
124
+ }
125
+ /**
126
+ * Starts watching every declared dependency and conflict.
127
+ */
128
+ onload() {
129
+ for (const dependency of this.dependencies) {
130
+ const apiRef = watchPluginApi({
131
+ apiVersionRange: dependency.apiVersionRange,
132
+ app: this.app,
133
+ component: this,
134
+ pluginId: dependency.pluginId
135
+ });
136
+ registerAsyncEvent(
137
+ this,
138
+ apiRef.on("change", async () => {
139
+ await this.refresh();
140
+ })
141
+ );
142
+ this.apiRefs.set(dependency.pluginId, apiRef);
143
+ }
144
+ const lifecycleEventNames = [PLUGIN_LOADED_EVENT_NAME, PLUGIN_UNLOADED_EVENT_NAME];
145
+ for (const eventName of lifecycleEventNames) {
146
+ this.registerEvent(this.app.workspace.on(
147
+ eventName,
148
+ convertAsyncToSync(async (payload) => {
149
+ if (payload.pluginId === this.plugin.manifest.id) {
150
+ return;
151
+ }
152
+ await this.refresh();
153
+ })
154
+ ));
155
+ }
156
+ this.addChild(
157
+ new CallbackLayoutReadyComponent(this.app, () => {
158
+ this.isLayoutReady = true;
159
+ this.presentUnsatisfied(this.getUnsatisfiedDependencies(), this.getActiveConflicts("block" /* Block */));
160
+ this.announceWarnings();
161
+ })
162
+ );
163
+ this.register(() => {
164
+ this.hideBlockedSettingTab();
165
+ });
166
+ }
167
+ /**
168
+ * Evaluates the gate once the watches are in place, loading the feature surface if it is already open.
169
+ *
170
+ * @returns A {@link Promise} that resolves once the first evaluation is complete.
171
+ */
172
+ async onloadAsync() {
173
+ await this.refresh();
174
+ }
175
+ /**
176
+ * Renders a banner for every conflict the host is running alongside, so a plugin can put the overlap in
177
+ * its own settings tab.
178
+ *
179
+ * Consumer-invoked, exactly like `PluginSuggestionComponent.renderBanner`: the library registers the
180
+ * settings tab a BLOCKED plugin needs, because that plugin never got to register one of its own, but it
181
+ * has no hook into the tab a running plugin builds. Renders nothing when no warning conflict holds.
182
+ *
183
+ * @param containerEl - The element to render into.
184
+ */
185
+ renderConflictWarningBanner(containerEl) {
186
+ for (const conflict of this.getActiveConflicts("warn" /* Warn */)) {
187
+ this.renderConflictEntry(containerEl, conflict, this.createConflictWarningMessage(conflict));
188
+ }
189
+ }
190
+ announceWarnings() {
191
+ if (!this.isLayoutReady || !this.isFeatureSurfaceLoaded) {
192
+ return;
193
+ }
194
+ for (const conflict of this.getActiveConflicts("warn" /* Warn */)) {
195
+ if (this.announcedWarningPluginIds.has(conflict.pluginId)) {
196
+ continue;
197
+ }
198
+ this.announcedWarningPluginIds.add(conflict.pluginId);
199
+ this.pluginNoticeComponent.showNotice(this.createConflictWarningMessage(conflict));
200
+ }
201
+ }
202
+ createBlockedMessage(dependency) {
203
+ return createFragmentWithCodeBlocks(t(($) => $.obsidianDevUtils.pluginDependency.blockedNotice, {
204
+ dependencyPluginName: asCodeBlock(dependency.pluginName),
205
+ pluginName: asCodeBlock(this.plugin.manifest.name)
206
+ }));
207
+ }
208
+ createConflictAppearedMessage(conflict) {
209
+ return createFragmentWithCodeBlocks(t(($) => $.obsidianDevUtils.pluginConflict.conflictAppearedNotice, {
210
+ conflictingPluginName: asCodeBlock(conflict.pluginName),
211
+ pluginName: asCodeBlock(this.plugin.manifest.name)
212
+ }));
213
+ }
214
+ createConflictBlockedMessage(conflict) {
215
+ return createFragmentWithCodeBlocks(t(($) => $.obsidianDevUtils.pluginConflict.blockedNotice, {
216
+ conflictingPluginName: asCodeBlock(conflict.pluginName),
217
+ pluginName: asCodeBlock(this.plugin.manifest.name)
218
+ }));
219
+ }
220
+ createConflictWarningMessage(conflict) {
221
+ return createFragmentWithCodeBlocks(t(($) => $.obsidianDevUtils.pluginConflict.warningNotice, {
222
+ conflictingPluginName: asCodeBlock(conflict.pluginName),
223
+ pluginName: asCodeBlock(this.plugin.manifest.name)
224
+ }));
225
+ }
226
+ createDependencyLostMessage(dependency) {
227
+ return createFragmentWithCodeBlocks(t(($) => $.obsidianDevUtils.pluginDependency.dependencyLostNotice, {
228
+ dependencyPluginName: asCodeBlock(dependency.pluginName),
229
+ pluginName: asCodeBlock(this.plugin.manifest.name)
230
+ }));
231
+ }
232
+ /**
233
+ * Finds the declared conflicts of one severity that are currently in force.
234
+ *
235
+ * @param severity - The severity to select.
236
+ * @returns The conflicts holding right now, in the order they were declared.
237
+ */
238
+ getActiveConflicts(severity) {
239
+ return this.conflicts.filter((conflict) => conflict.severity === severity && this.isConflictActive(conflict));
240
+ }
241
+ getUnsatisfiedDependencies() {
242
+ return this.dependencies.filter((dependency) => !this.apiRefs.get(dependency.pluginId)?.value);
243
+ }
244
+ hideBlockedSettingTab() {
245
+ if (!this.blockedSettingTab) {
246
+ return;
247
+ }
248
+ this.app.setting.removeSettingTab(this.blockedSettingTab);
249
+ this.blockedSettingTab = null;
250
+ }
251
+ /**
252
+ * Decides whether one declared conflict is in force right now.
253
+ *
254
+ * Only an ENABLED plugin counts. One that is installed but switched off registers nothing, so it cannot
255
+ * collide, and acting on it would be an alarm the user can only answer by uninstalling something they
256
+ * have already turned off.
257
+ *
258
+ * @param conflict - The declared conflict.
259
+ * @returns Whether the conflicting plugin is enabled at a conflicting version.
260
+ */
261
+ isConflictActive(conflict) {
262
+ const installedVersion = getInstalledPluginVersion({
263
+ app: this.app,
264
+ pluginId: conflict.pluginId
265
+ });
266
+ if (installedVersion === null) {
267
+ return false;
268
+ }
269
+ try {
270
+ return satisfiesVersion(installedVersion, conflict.conflictingVersionRange);
271
+ } catch {
272
+ return true;
273
+ }
274
+ }
275
+ /**
276
+ * Says what is in the way, and puts the same explanation where the user will look for the plugin's
277
+ * settings.
278
+ *
279
+ * @param unsatisfiedDependencies - The dependencies that are not currently satisfied.
280
+ * @param blockingConflicts - The conflicts currently refusing the plugin the right to run.
281
+ */
282
+ presentUnsatisfied(unsatisfiedDependencies, blockingConflicts) {
283
+ if (!this.isLayoutReady || unsatisfiedDependencies.length === 0 && blockingConflicts.length === 0) {
284
+ return;
285
+ }
286
+ this.showBlockedSettingTab(unsatisfiedDependencies, blockingConflicts);
287
+ if (this.hasAnnouncedBlocked) {
288
+ return;
289
+ }
290
+ this.hasAnnouncedBlocked = true;
291
+ for (const dependency of unsatisfiedDependencies) {
292
+ this.pluginNoticeComponent.showNotice(this.createBlockedMessage(dependency));
293
+ }
294
+ for (const conflict of blockingConflicts) {
295
+ this.pluginNoticeComponent.showNotice(this.createConflictBlockedMessage(conflict));
296
+ }
297
+ }
298
+ /**
299
+ * Re-evaluates the gate and moves the feature surface to match.
300
+ *
301
+ * @returns A {@link Promise} that resolves once the surface matches the gate.
302
+ */
303
+ async refresh() {
304
+ const unsatisfiedDependencies = this.getUnsatisfiedDependencies();
305
+ const blockingConflicts = this.getActiveConflicts("block" /* Block */);
306
+ if (unsatisfiedDependencies.length === 0 && blockingConflicts.length === 0) {
307
+ this.hideBlockedSettingTab();
308
+ this.hasAnnouncedBlocked = false;
309
+ if (!this.isFeatureSurfaceLoaded) {
310
+ this.isFeatureSurfaceLoaded = true;
311
+ await this.loadFeatureSurface();
312
+ }
313
+ this.announceWarnings();
314
+ return;
315
+ }
316
+ if (this.isFeatureSurfaceLoaded) {
317
+ this.isFeatureSurfaceLoaded = false;
318
+ this.unloadFeatureSurface();
319
+ for (const dependency of unsatisfiedDependencies) {
320
+ this.pluginNoticeComponent.showNotice(this.createDependencyLostMessage(dependency));
321
+ }
322
+ for (const conflict of blockingConflicts) {
323
+ this.pluginNoticeComponent.showNotice(this.createConflictAppearedMessage(conflict));
324
+ }
325
+ this.hasAnnouncedBlocked = true;
326
+ this.showBlockedSettingTab(unsatisfiedDependencies, blockingConflicts);
327
+ return;
328
+ }
329
+ this.presentUnsatisfied(unsatisfiedDependencies, blockingConflicts);
330
+ }
331
+ /**
332
+ * Renders the blocked explanation into a settings-tab container: what is missing or in the way, why it
333
+ * matters, and the button that fixes it.
334
+ *
335
+ * @param containerEl - The element to render into.
336
+ * @param unsatisfiedDependencies - The dependencies that are not currently satisfied.
337
+ * @param blockingConflicts - The conflicts currently refusing the plugin the right to run.
338
+ */
339
+ renderBlockedBanner(containerEl, unsatisfiedDependencies, blockingConflicts) {
340
+ if (unsatisfiedDependencies.length > 0) {
341
+ containerEl.createEl("h2", { text: t(($) => $.obsidianDevUtils.pluginDependency.settingsHeading) });
342
+ }
343
+ for (const dependency of unsatisfiedDependencies) {
344
+ const bannerEl = containerEl.createDiv({
345
+ cls: [CssClass.LibraryName, CssClass.PluginDependencyBanner]
346
+ });
347
+ bannerEl.append(this.createBlockedMessage(dependency));
348
+ bannerEl.createDiv({ text: dependency.reason });
349
+ const state = getInstalledPluginState({
350
+ app: this.app,
351
+ pluginId: dependency.pluginId
352
+ });
353
+ new ButtonComponent(bannerEl).setButtonText(t(
354
+ ($) => state === InstalledPluginState.InstalledButDisabled ? $.obsidianDevUtils.pluginSuggestion.enable : $.obsidianDevUtils.pluginSuggestion.install
355
+ )).setCta().onClick(convertAsyncToSync(async () => {
356
+ await installAndEnablePlugin({
357
+ app: this.app,
358
+ pluginId: dependency.pluginId,
359
+ pluginName: dependency.pluginName,
360
+ pluginNoticeComponent: this.pluginNoticeComponent
361
+ });
362
+ }));
363
+ if (state !== InstalledPluginState.Enabled) {
364
+ continue;
365
+ }
366
+ this.renderOpenSettingsButton(bannerEl, dependency.pluginId, dependency.pluginName);
367
+ }
368
+ if (blockingConflicts.length === 0) {
369
+ return;
370
+ }
371
+ containerEl.createEl("h2", { text: t(($) => $.obsidianDevUtils.pluginConflict.settingsHeading) });
372
+ for (const conflict of blockingConflicts) {
373
+ this.renderConflictEntry(containerEl, conflict, this.createConflictBlockedMessage(conflict));
374
+ }
375
+ }
376
+ /**
377
+ * Renders one conflict: what it is, why it matters, and the two ways out of it.
378
+ *
379
+ * The repair is offered on the OTHER plugin — disabling it is the one thing this plugin can do in a
380
+ * click, since it cannot update someone else's plugin — and it is the persisted `disablePluginAndSave`
381
+ * rather than the transient disable, because the user asked for it by clicking.
382
+ *
383
+ * @param containerEl - The element to render into.
384
+ * @param conflict - The conflict to render.
385
+ * @param messageFragment - The sentence explaining the conflict.
386
+ */
387
+ renderConflictEntry(containerEl, conflict, messageFragment) {
388
+ const bannerEl = containerEl.createDiv({
389
+ cls: [CssClass.LibraryName, CssClass.PluginConflictBanner]
390
+ });
391
+ bannerEl.append(messageFragment);
392
+ bannerEl.createDiv({ text: conflict.reason });
393
+ new ButtonComponent(bannerEl).setButtonText(t(($) => $.obsidianDevUtils.pluginConflict.disable, { conflictingPluginName: conflict.pluginName })).setCta().onClick(convertAsyncToSync(async () => {
394
+ await disableCommunityPlugin({
395
+ app: this.app,
396
+ pluginId: conflict.pluginId
397
+ });
398
+ await this.refresh();
399
+ }));
400
+ this.renderOpenSettingsButton(bannerEl, conflict.pluginId, conflict.pluginName);
401
+ }
402
+ renderOpenSettingsButton(bannerEl, pluginId, pluginName) {
403
+ new ButtonComponent(bannerEl).setButtonText(t(($) => $.obsidianDevUtils.pluginDependency.openDependencySettings, {
404
+ dependencyPluginName: pluginName
405
+ })).onClick(() => {
406
+ this.app.setting.open();
407
+ this.app.setting.openTabById(pluginId);
408
+ });
409
+ }
410
+ showBlockedSettingTab(unsatisfiedDependencies, blockingConflicts) {
411
+ if (this.blockedSettingTab) {
412
+ return;
413
+ }
414
+ const blockedSettingTab = new BlockedPluginSettingTab({
415
+ plugin: this.plugin,
416
+ renderBanner: (containerEl) => {
417
+ this.renderBlockedBanner(containerEl, unsatisfiedDependencies, blockingConflicts);
418
+ }
419
+ });
420
+ this.app.setting.addSettingTab(blockedSettingTab);
421
+ this.blockedSettingTab = blockedSettingTab;
422
+ }
423
+ }
424
+ export {
425
+ PluginConflictSeverity,
426
+ PluginGateComponent
427
+ };
428
+ //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL2NvbXBvbmVudHMvcGx1Z2luLWdhdGUtY29tcG9uZW50LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBmaWxlXG4gKlxuICogVGhlIGdhdGUgb24gYSBwbHVnaW4ncyBmZWF0dXJlIHN1cmZhY2U6IHdoYXQgbXVzdCBiZSBQUkVTRU5UIGZvciBpdCB0byBydW4sIGFuZCB3aGF0IG11c3QgTk9UIGJlLlxuICpcbiAqIEJvdGggaGFsdmVzIGFuc3dlciB0aGUgc2FtZSBxdWVzdGlvbiBcdTIwMTQgbWF5IHRoaXMgcGx1Z2luJ3MgYG9ubG9hZEltcGxgIHJ1biByaWdodCBub3c/IFx1MjAxNCBzbyB0aGV5IGFyZSBvbmVcbiAqIGNvbXBvbmVudCByYXRoZXIgdGhhbiB0d28uIEEgc2Vjb25kLCBpbmRlcGVuZGVudCBnYXRlIHdvdWxkIGRvdWJsZS1sb2FkIHRoZSBzdXJmYWNlIGFuZCBzdGFjayBhIHNlY29uZFxuICogXCJibG9ja2VkXCIgc2V0dGluZ3MgdGFiIG9udG8gdGhlIHNhbWUgcGx1Z2luLCBhbmQgbmVpdGhlciBjb3VsZCBzZWUgdGhlIG90aGVyJ3MgcmVhc29uIGZvciByZWZ1c2luZy5cbiAqXG4gKiAjIyBEZXBlbmRlbmNpZXM6IGEgcGx1Z2luIGRlY2xhcmluZyB3aGF0IGl0IGNhbm5vdCB3b3JrIHdpdGhvdXRcbiAqXG4gKiBUaGlzIGlzIHRoZSBzdHJpY3Qgc2libGluZyBvZiBgUGx1Z2luU3VnZ2VzdGlvbkNvbXBvbmVudGAsIGFuZCB0aGUgZGlmZmVyZW5jZSBpcyB0aGUgd2hvbGUgcG9pbnQuIEFcbiAqIFNVR0dFU1RJT04gaXMgYW4gb2ZmZXIgXHUyMDE0IHRoZSBob3N0IGtlZXBzIHdvcmtpbmcgd2l0aG91dCBpdCBhbmQgc2ltcGx5IGNhbm5vdCBkbyBvbmUgdGhpbmcuIEEgREVQRU5ERU5DWVxuICogaXMgYSByZXF1aXJlbWVudDogYG9ubG9hZEltcGxgIG5ldmVyIHJ1bnMsIG5vIGNvbW1hbmQgaXMgcmVnaXN0ZXJlZCwgbm8gaGFuZGxlciBpcyBpbnN0YWxsZWQsIG5vdGhpbmcgaXNcbiAqIHBhdGNoZWQuIFJlYWNoIGZvciBhIHN1Z2dlc3Rpb24gd2hlbiB0aGUgb3RoZXIgcGx1Z2luIGFkZHMgc29tZXRoaW5nOyByZWFjaCBmb3IgYSBkZXBlbmRlbmN5IHdoZW4gdGhlXG4gKiBob3N0J3MgYWR2ZXJ0aXNlZCBiZWhhdmlvciBpcyBub3QgdGhlcmUgd2l0aG91dCBpdC5cbiAqXG4gKiBPYnNpZGlhbiBoYXMgbm8gZGVwZW5kZW5jeSBmaWVsZCBpbiBhIG1hbmlmZXN0LCB3aGljaCBpcyBleGFjdGx5IHRoZSBwcm9ibGVtIHRoaXMgY2xvc2VzLiBXaXRob3V0IG9uZSxcbiAqIGEgdXNlciBtZWV0aW5nIGFuIHVuZmFtaWxpYXIgcGx1Z2luIGluIHRoZWlyIGxpc3QgbW9udGhzIGxhdGVyIGhhcyBub3RoaW5nIHRlbGxpbmcgdGhlbSBpdCBpc1xuICogbG9hZC1iZWFyaW5nIFx1MjAxNCB0aGV5IHJlbW92ZSBpdCwgYW5kIHRoZSBicmVha2FnZSBzdXJmYWNlcyB3ZWVrcyBhZnRlciB0aGF0IGFzIGRhbWFnZSB0aGV5IGNhbm5vdCBjb25uZWN0XG4gKiB0byBhbnl0aGluZyB0aGV5IGRpZC4gU28gdGhlIHJlbGF0aW9uc2hpcCBpcyBtYWRlIHZpc2libGUgZnJvbSBib3RoIGVuZHMgYW5kIGVuZm9yY2VkIHdoaWxlIGl0IGhvbGRzOlxuICogdGhlIGRlcGVuZGVudCBleHBsYWlucyBpdHNlbGYgd2hlcmUgdGhlIHVzZXIgaXMgbG9va2luZywgcmVwYWlycyBpdHNlbGYgaW4gb25lIGNsaWNrLCBhbmQgcmVhY3RzIHRoZVxuICogSU5TVEFOVCB0aGUgZGVwZW5kZW5jeSBnb2VzIGF3YXkgcmF0aGVyIHRoYW4gZGVncmFkaW5nIHF1aWV0bHkuXG4gKlxuICogVGhyZWUgY2hvaWNlcyBhcmUgZGVsaWJlcmF0ZSBhbmQgd29ydGggc3RhdGluZywgYmVjYXVzZSBlYWNoIGhhcyBhbiBvYnZpb3VzLWxvb2tpbmcgYWx0ZXJuYXRpdmU6XG4gKlxuICogLSAqKkJsb2NrZWQgbWVhbnMgZW5hYmxlZC1idXQtaW5lcnQsIG5ldmVyIHNlbGYtZGlzYWJsZWQuKiogQ2FsbGluZyBgZGlzYWJsZVBsdWdpbkFuZFNhdmVgIG9uIGl0c2VsZlxuICogICB3b3VsZCBiZSB0aGUgbGl0ZXJhbCByZWFkaW5nIG9mIFwicmVmdXNlcyB0byBsb2FkXCIsIGFuZCBpdCByZXdyaXRlcyBhIGNvbmZpZyB0aGF0IGJlbG9uZ3MgdG8gdGhlIHVzZXIgXHUyMDE0XG4gKiAgIHdobyB3b3VsZCB0aGVuIGhhdmUgdG8gcmVtZW1iZXIgdG8gcmUtZW5hYmxlIGl0IGFmdGVyIGZpeGluZyB0aGUgZGVwZW5kZW5jeS4gU3RheWluZyBlbmFibGVkIGFuZCBpbmVydFxuICogICBzYXlzIHRoZSBzYW1lIHRoaW5nIHRvIHRoZSB1c2VyLCBjaGFuZ2VzIG5vdGhpbmcgdGhleSBvd24sIGFuZCBjYW4gdW5kbyBpdHNlbGYuXG4gKiAtICoqQmxvY2tlZCBpcyBub3QgYW4gZXJyb3IuKiogVGhyb3dpbmcgZnJvbSBgb25sb2FkYCBtYXJrcyB0aGUgcGx1Z2luIGZhaWxlZCBpbiBPYnNpZGlhbiBhbmQgaGFuZHMgdGhlXG4gKiAgIHVzZXIgYSBzdGFjayB0cmFjZSBpbnN0ZWFkIG9mIGEgc2VudGVuY2UgYW5kIGEgYnV0dG9uLlxuICogLSAqKkEgZGVwZW5kZW5jeSBtdXN0IHB1Ymxpc2ggYW4gQVBJLioqIFRoYXQgaXMgd2hhdCBtYWtlcyBwcmVzZW5jZSwgYWJzZW5jZSwgdmVyc2lvbiBhbmQgZGVwYXJ0dXJlIGFsbFxuICogICBvYnNlcnZhYmxlIHRocm91Z2ggb25lIG1lY2hhbmlzbSBcdTIwMTQgYHdhdGNoUGx1Z2luQXBpYCdzIHJlZmVyZW5jZSBpcyBsaXZlLCBpcyByZXZva2VkIHdoZW4gdGhlIHByb3ZpZGVyXG4gKiAgIHVubG9hZHMsIGFuZCBhbHJlYWR5IGNsYXNzaWZpZXMgbm90LWluc3RhbGxlZCBhZ2FpbnN0IG5vdC1lbmFibGVkIGFnYWluc3QgdG9vLW9sZC4gQSBwcm92aWRlciB3aXRoXG4gKiAgIG5vdGhpbmcgdG8gZXhwb3NlIGNhbiBwdWJsaXNoIGFuIGVtcHR5IEFQSSBwdXJlbHkgc28gaXQgY2FuIGJlIGRlcGVuZGVkIHVwb247IHRoZSBhbHRlcm5hdGl2ZSB3b3VsZCBiZVxuICogICBhIHNlY29uZCwgd2Vha2VyIGRldGVjdGlvbiBwYXRoIHRvIG1haW50YWluIGJlc2lkZSBpdC5cbiAqXG4gKiAjIyBDb25mbGljdHM6IGEgcGx1Z2luIGRlY2xhcmluZyB3aGF0IGl0IHJlZnVzZXMgdG8gcnVuIGJlc2lkZVxuICpcbiAqIFRoZSBpbnZlcnNlIHJlbGF0aW9uc2hpcCwgYW5kIGl0IG5lZWRzIGl0cyBvd24gZGV0ZWN0aW9uIHBhdGggYmVjYXVzZSB0aGUgZGVwZW5kZW5jeSBvbmUgZG9lcyBub3QgZml0LlxuICogQSBjb25mbGljdGluZyBwbHVnaW4gaXMgdHlwaWNhbGx5IGFuIE9MRCB2ZXJzaW9uIG9mIHNvbWUgb3RoZXIgcGx1Z2luIHRoYXQgc3RpbGwgb3ducyBiZWhhdmlvciB0aGlzIG9uZVxuICogaGFzIHRha2VuIG92ZXIgXHUyMDE0IGl0IHB1Ymxpc2hlcyBubyBBUEkgYXQgYWxsLCBzbyB0aGVyZSBpcyBubyBgYXBpVmVyc2lvblJhbmdlYCB0byBjb21wYXJlIGFnYWluc3QuXG4gKlxuICogVGhlIGFyZ3VtZW50IGZvciByZWZ1c2luZyByYXRoZXIgdGhhbiBjb21wZXRpbmcgY29tZXMgZnJvbSB0aGUgY2FzZSB0aGlzIGdlbmVyYWxpemVzOiB0d28gcmVuYW1lL2RlbGV0ZVxuICogaGFuZGxlcnMgYWN0aW5nIG9uIG9uZSByZW5hbWUgY29ycnVwdCBsaW5rcyBhbmQgbW92ZSBhdHRhY2htZW50cyB0d2ljZSwgYW5kIHRoZXJlIGlzIG5vIHJlbGlhYmxlIHdheSB0b1xuICogd2luIHRoYXQgcmFjZSBcdTIwMTQgYSBoYW5kbGVyIGlzIGVsZWN0ZWQgYnkgcmVnaXN0cnkgb3JkZXIsIGJ1dCB0aGUgcGF0Y2hlcyB0aGF0IGRvIHRoZSB3b3JrIHNpdCBvdXRzaWRlXG4gKiB0aGF0IGVsZWN0aW9uLCBzbyB3aGljaGV2ZXIgcGx1Z2luIGxvYWRlZCBmaXJzdCBrZWVwcyBhIGhhbmQgb24gdGhlIHdoZWVsLiBFdmVyeSBzY2hlbWUgZm9yIHNlaXppbmdcbiAqIGNvbnRyb2wgZnJvbSBpbnNpZGUgaXMgbG9hZC1vcmRlciBkZXBlbmRlbnQuIFJlZnVzaW5nIGlzIGRldGVybWluaXN0aWMgd2hlcmUgY29tcGV0aW5nIGlzIG5vdCwgYW5kIGFcbiAqIHZhdWx0IHRoYXQgYnJpZWZseSBoYXMgbm8gaGFuZGxlciBpcyBhIGZhciBiZXR0ZXIgb3V0Y29tZSB0aGFuIG9uZSB3aXRoIHR3by5cbiAqXG4gKiBUd28gZGV0YWlscyBvZiB0aGF0IGRldGVjdGlvbiBjYXJyeSBvdmVyIHZlcmJhdGltLCBiZWNhdXNlIGJvdGggYXJlIGxvYWQtYmVhcmluZzpcbiAqXG4gKiAtICoqVmVyc2lvbnMgYXJlIHJlYWQsIG5ldmVyIHRoZSByZWdpc3RyeS4qKiBBIHBsdWdpbiB0aGF0IGhhcyBub3QgbG9hZGVkIHlldCBoYXMgcmVnaXN0ZXJlZCBub3RoaW5nLCBzb1xuICogICBhc2tpbmcgdGhlIHJlZ2lzdHJ5IGdpdmVzIGEgZGlmZmVyZW50IGFuc3dlciBkZXBlbmRpbmcgb24gd2hlbiBpdCBpcyBhc2tlZC4gYGFwcC5wbHVnaW5zLm1hbmlmZXN0c2AgaXNcbiAqICAgcG9wdWxhdGVkIGZvciBldmVyeSBpbnN0YWxsZWQgcGx1Z2luIGF0IHN0YXJ0dXAsIHdoYXRldmVyIHRoZSBsb2FkIG9yZGVyIHR1cm5zIG91dCB0byBiZS5cbiAqIC0gKipBbiB1bnBhcnNlYWJsZSB2ZXJzaW9uIGNvdW50cyBhcyBjb25mbGljdGluZy4qKiBGYWlsaW5nIGNsb3NlZCBpcyB0aGUgc2FmZSBkaXJlY3Rpb246IGEgZmFsc2UgYWxhcm1cbiAqICAgY29zdHMgYSBub3RpY2UsIGEgZmFsc2UgYWxsLWNsZWFyIGNvc3RzIGEgdmF1bHQuXG4gKlxuICogTm90IGV2ZXJ5IG92ZXJsYXAgaXMgdGhhdCBzZXZlcmUsIHdoaWNoIGlzIHdoeSBhIGNvbmZsaWN0IGRlY2xhcmVzIGEge0BsaW5rIFBsdWdpbkNvbmZsaWN0U2V2ZXJpdHl9LlxuICogVHdvIHBsdWdpbnMgc2hpcHBpbmcgdGhlIHNhbWUgY29tbWFuZCBkdXBsaWNhdGUgYSBwYWxldHRlIGVudHJ5IGFuZCBkbyB0aGUgd29yayB0d2ljZSBcdTIwMTQgYW5ub3lpbmcsIG5vdFxuICogY29ycnVwdGluZyBcdTIwMTQgYW5kIHJlZnVzaW5nIHRvIGxvYWQgb3ZlciB0aGF0IHdvdWxkIGJlIGEgd29yc2Ugb3V0Y29tZSB0aGFuIHRoZSBvdmVybGFwLiBUaG9zZSBkZWNsYXJlXG4gKiB7QGxpbmsgUGx1Z2luQ29uZmxpY3RTZXZlcml0eS5XYXJufSBhbmQgYm90aCBrZWVwIHJ1bm5pbmcuXG4gKlxuICogIyMgV2hhdCB0aGlzIGNhbiBhbmQgY2Fubm90IHNlZVxuICpcbiAqIE9ic2lkaWFuIHJhaXNlcyBubyBldmVudCB3aGVuIEFOT1RIRVIgcGx1Z2luIGlzIGVuYWJsZWQgb3IgZGlzYWJsZWQgKHNlZSBgcGx1Z2luLWxpZmVjeWNsZS1ldmVudHMudHNgKSxcbiAqIHNvIGxpdmUgY29uZmxpY3QgZGV0ZWN0aW9uIGhhcyBhIHJlYWwgY2VpbGluZyBhbmQgaXQgaXMgc3RhdGVkIGhlcmUgcmF0aGVyIHRoYW4gaW1wbGllZCBhd2F5LiBBXG4gKiBjb25mbGljdGluZyBwbHVnaW4gYnVpbHQgb24gdGhpcyBsaWJyYXJ5IGFubm91bmNlcyBpdHNlbGYgdGhyb3VnaCB0aGUgbGlmZWN5Y2xlIGJyb2FkY2FzdCwgYW5kIGlzXG4gKiB0aGVyZWZvcmUgY2F1Z2h0IHRoZSBtb21lbnQgaXQgaXMgZW5hYmxlZCBvciBkaXNhYmxlZC4gT25lIHRoYXQgaXMgbm90IFx1MjAxNCBhbiBvbGQgcmVsZWFzZSBwcmVkYXRpbmcgdGhlXG4gKiBicm9hZGNhc3QsIG9yIGEgcGx1Z2luIGJ5IGFub3RoZXIgYXV0aG9yIGVudGlyZWx5IFx1MjAxNCBpcyBjYXVnaHQgYXQgdGhlIG5leHQgbG9hZCwgd2hpY2ggaXMgd2hlbiBpdHNcbiAqIG1hbmlmZXN0IGlzIHJlYWQuXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBBcHAsXG4gIFBsdWdpblxufSBmcm9tICdvYnNpZGlhbic7XG5cbmltcG9ydCB7IHNhdGlzZmllcyBhcyBzYXRpc2ZpZXNWZXJzaW9uIH0gZnJvbSAnY29tcGFyZS12ZXJzaW9ucyc7XG5pbXBvcnQge1xuICBCdXR0b25Db21wb25lbnQsXG4gIFBsdWdpblNldHRpbmdUYWJcbn0gZnJvbSAnb2JzaWRpYW4nO1xuXG5pbXBvcnQgdHlwZSB7IFBsdWdpbkFwaVJlZiB9IGZyb20gJy4uL3BsdWdpbi9wbHVnaW4tYXBpLnRzJztcbmltcG9ydCB0eXBlIHtcbiAgUGx1Z2luTGlmZWN5Y2xlRXZlbnROYW1lLFxuICBQbHVnaW5MaWZlY3ljbGVFdmVudFBheWxvYWRcbn0gZnJvbSAnLi4vcGx1Z2luL3BsdWdpbi1saWZlY3ljbGUtZXZlbnRzLnRzJztcbmltcG9ydCB0eXBlIHsgUGx1Z2luTm90aWNlQ29tcG9uZW50IH0gZnJvbSAnLi9wbHVnaW4tbm90aWNlLWNvbXBvbmVudC50cyc7XG5cbmltcG9ydCB7IGNvbnZlcnRBc3luY1RvU3luYyB9IGZyb20gJy4uLy4uL2FzeW5jLnRzJztcbmltcG9ydCB7IGRpc2FibGVDb21tdW5pdHlQbHVnaW4gfSBmcm9tICcuLi9jb21tdW5pdHktcGx1Z2lucy50cyc7XG5pbXBvcnQgeyBDc3NDbGFzcyB9IGZyb20gJy4uL2Nzcy1jbGFzcy50cyc7XG5pbXBvcnQge1xuICBhc0NvZGVCbG9jayxcbiAgY3JlYXRlRnJhZ21lbnRXaXRoQ29kZUJsb2Nrc1xufSBmcm9tICcuLi9odG1sLWVsZW1lbnQudHMnO1xuaW1wb3J0IHsgdCB9IGZyb20gJy4uL2kxOG4vaTE4bi50cyc7XG5pbXBvcnQgeyB3YXRjaFBsdWdpbkFwaSB9IGZyb20gJy4uL3BsdWdpbi9wbHVnaW4tYXBpLnRzJztcbmltcG9ydCB7XG4gIGdldEluc3RhbGxlZFBsdWdpblN0YXRlLFxuICBnZXRJbnN0YWxsZWRQbHVnaW5WZXJzaW9uLFxuICBpbnN0YWxsQW5kRW5hYmxlUGx1Z2luLFxuICBJbnN0YWxsZWRQbHVnaW5TdGF0ZVxufSBmcm9tICcuLi9wbHVnaW4vcGx1Z2luLWluc3RhbGwtc3RhdGUudHMnO1xuaW1wb3J0IHtcbiAgUExVR0lOX0xPQURFRF9FVkVOVF9OQU1FLFxuICBQTFVHSU5fVU5MT0FERURfRVZFTlRfTkFNRVxufSBmcm9tICcuLi9wbHVnaW4vcGx1Z2luLWxpZmVjeWNsZS1ldmVudHMudHMnO1xuaW1wb3J0IHsgcmVnaXN0ZXJBc3luY0V2ZW50IH0gZnJvbSAnLi9hc3luYy1ldmVudHMtY29tcG9uZW50LnRzJztcbmltcG9ydCB7IENvbXBvbmVudEV4IH0gZnJvbSAnLi9jb21wb25lbnQtZXgudHMnO1xuaW1wb3J0IHsgQ2FsbGJhY2tMYXlvdXRSZWFkeUNvbXBvbmVudCB9IGZyb20gJy4vbGF5b3V0LXJlYWR5LWNvbXBvbmVudC50cyc7XG5cbi8qKlxuICogSG93IGJhZGx5IHR3byBwbHVnaW5zIHJ1bm5pbmcgc2lkZSBieSBzaWRlIGdvZXMgd3JvbmcsIGFuZCB0aGVyZWZvcmUgd2hhdCB0aGlzIG9uZSBkb2VzIGFib3V0IGl0LlxuICovXG5leHBvcnQgZW51bSBQbHVnaW5Db25mbGljdFNldmVyaXR5IHtcbiAgLyoqXG4gICAqIFRoZSBob3N0IHJlZnVzZXMgdG8gcnVuIGF0IGFsbCB3aGlsZSB0aGUgY29uZmxpY3QgaG9sZHM6IGBvbmxvYWRJbXBsYCBuZXZlciBydW5zLCBub3RoaW5nIGlzXG4gICAqIHJlZ2lzdGVyZWQsIGFuZCB0aGUgcGx1Z2luIGV4cGxhaW5zIGl0c2VsZiB0aGUgd2F5IGEgbWlzc2luZyBkZXBlbmRlbmN5IGRvZXMuXG4gICAqXG4gICAqIEZvciBhbiBvdmVybGFwIHdoZXJlIGJvdGggcGx1Z2lucyBhY3Rpbmcgb24gdGhlIHNhbWUgb3BlcmF0aW9uIGRhbWFnZXMgdGhlIHZhdWx0LlxuICAgKi9cbiAgQmxvY2sgPSAnYmxvY2snLFxuXG4gIC8qKlxuICAgKiBUaGUgaG9zdCBydW5zIGFueXdheSBhbmQgc2F5cyB0aGUgb3ZlcmxhcCBpcyB0aGVyZS5cbiAgICpcbiAgICogRm9yIGFuIG92ZXJsYXAgdGhhdCBpcyBhbm5veWluZyByYXRoZXIgdGhhbiBkZXN0cnVjdGl2ZSBcdTIwMTQgZHVwbGljYXRlIGNvbW1hbmRzLCB3b3JrIGRvbmUgdHdpY2UgXHUyMDE0IHdoZXJlXG4gICAqIHJlZnVzaW5nIHRvIGxvYWQgd291bGQgY29zdCB0aGUgdXNlciBtb3JlIHRoYW4gdGhlIG92ZXJsYXAgZG9lcy5cbiAgICovXG4gIFdhcm4gPSAnd2Fybidcbn1cblxuLyoqXG4gKiBBIHBsdWdpbiBhbm90aGVyIHBsdWdpbiByZWZ1c2VzIHRvIHJ1biBiZXNpZGUsIG9yIHdhcm5zIGFib3V0IHJ1bm5pbmcgYmVzaWRlLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFBsdWdpbkNvbmZsaWN0IHtcbiAgLyoqXG4gICAqIFRoZSBzZW12ZXIgcmFuZ2Ugb2YgdGhlIE9USEVSIHBsdWdpbidzIHZlcnNpb25zIHRoYXQgY29uZmxpY3QsIGUuZy4gYCc8MTIuMC4wJ2AgZm9yIFwiZXZlcnkgdmVyc2lvblxuICAgKiBiZWZvcmUgdGhlIG9uZSB0aGF0IGdhdmUgdGhpcyBiZWhhdmlvciB1cFwiLlxuICAgKlxuICAgKiBBIHJhbmdlIHJhdGhlciB0aGFuIGEgbWluaW11bSwgc28gYW4gb3ZlcmxhcCBjb25maW5lZCB0byBvbmUgbWFqb3IgKGAnPj0zIDw0J2ApIGlzIGV4cHJlc3NpYmxlLCBhbmQgc29cbiAgICogaXMgYSBwbHVnaW4gdGhhdCBjb25mbGljdHMgYXQgZXZlcnkgdmVyc2lvbiBcdTIwMTQgc3BlbGwgdGhhdCBgJz49MC4wLjAnYCwgc2luY2UgYGNvbXBhcmUtdmVyc2lvbnNgIHJlamVjdHNcbiAgICogYSBiYXJlIGAqYC4gRXZhbHVhdGVkIGFnYWluc3QgYG1hbmlmZXN0LnZlcnNpb25gOyBhIHZlcnNpb24gdGhhdCBjYW5ub3QgYmUgcGFyc2VkIGNvdW50cyBhc1xuICAgKiBjb25mbGljdGluZy5cbiAgICovXG4gIHJlYWRvbmx5IGNvbmZsaWN0aW5nVmVyc2lvblJhbmdlOiBzdHJpbmc7XG5cbiAgLyoqXG4gICAqIFRoZSBgbWFuaWZlc3QuaWRgIG9mIHRoZSBjb25mbGljdGluZyBwbHVnaW4sIGFzIGxpc3RlZCBpbiBPYnNpZGlhbidzIGNvbW11bml0eSBwbHVnaW4gcmVnaXN0cnkuXG4gICAqL1xuICByZWFkb25seSBwbHVnaW5JZDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgZGlzcGxheSBuYW1lIG9mIHRoZSBjb25mbGljdGluZyBwbHVnaW4sIHNob3duIHRvIHRoZSB1c2VyLlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luTmFtZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIGxvY2FsaXplZCBzZW50ZW5jZSBzYXlpbmcgd2hhdCBnb2VzIHdyb25nIHdoZW4gYm90aCBydW4sIHNob3duIGluIHRoZSBiYW5uZXIuXG4gICAqXG4gICAqIFRoZSBkZWNsYXJpbmcgcGx1Z2luIG93bnMgdGhpcyBzdHJpbmcgYmVjYXVzZSBvbmx5IGl0IGtub3dzIHdoYXQgdGhlIHR3byBvZiB0aGVtIGNvbGxpZGUgb3ZlciwgYW5kIGFcbiAgICogdXNlciBiZWluZyBhc2tlZCB0byBkaXNhYmxlIHNvbWV0aGluZyBkZXNlcnZlcyB0byBiZSB0b2xkIHdoeS5cbiAgICovXG4gIHJlYWRvbmx5IHJlYXNvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBXaGF0IHRoaXMgcGx1Z2luIGRvZXMgYWJvdXQgdGhlIGNvbmZsaWN0LlxuICAgKi9cbiAgcmVhZG9ubHkgc2V2ZXJpdHk6IFBsdWdpbkNvbmZsaWN0U2V2ZXJpdHk7XG59XG5cbi8qKlxuICogQSBwbHVnaW4gYW5vdGhlciBwbHVnaW4gY2Fubm90IHdvcmsgd2l0aG91dC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQbHVnaW5EZXBlbmRlbmN5IHtcbiAgLyoqXG4gICAqIFRoZSBzZW12ZXIgcmFuZ2Ugb2YgQVBJIGNvbnRyYWN0IHZlcnNpb25zIHRoZSBkZXBlbmRlbnQgY29tcGlsZWQgYWdhaW5zdCwgZS5nLiBgJ14yJ2AuXG4gICAqXG4gICAqIEEgZGVwZW5kZW5jeSB3aG9zZSBwdWJsaXNoZWQgQVBJIGZhbGxzIG91dHNpZGUgdGhlIHJhbmdlIGNvdW50cyBhcyBVTlNBVElTRklFRCwgd2hpY2ggaXMgd2hhdCB0dXJucyBhXG4gICAqIHNpbGVudCBiZWhhdmlvcmFsIG1pc21hdGNoIGJldHdlZW4gdHdvIGluZGVwZW5kZW50bHkgcmVsZWFzZWQgcGx1Z2lucyBpbnRvIGEgdmlzaWJsZSBcInVwZGF0ZSB0aGlzXG4gICAqIG9uZVwiIG1lc3NhZ2UuIFNwZWxsIFwiYW55IHZlcnNpb25cIiBhcyBgJz49MC4wLjAnYCBcdTIwMTQgYGNvbXBhcmUtdmVyc2lvbnNgIHJlamVjdHMgYSBiYXJlIGAqYC5cbiAgICovXG4gIHJlYWRvbmx5IGFwaVZlcnNpb25SYW5nZTogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUgYG1hbmlmZXN0LmlkYCBvZiB0aGUgcmVxdWlyZWQgcGx1Z2luLCBhcyBsaXN0ZWQgaW4gT2JzaWRpYW4ncyBjb21tdW5pdHkgcGx1Z2luIHJlZ2lzdHJ5LlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luSWQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGRpc3BsYXkgbmFtZSBvZiB0aGUgcmVxdWlyZWQgcGx1Z2luLCBzaG93biB0byB0aGUgdXNlci5cbiAgICovXG4gIHJlYWRvbmx5IHBsdWdpbk5hbWU6IHN0cmluZztcblxuICAvKipcbiAgICogQSBsb2NhbGl6ZWQgc2VudGVuY2Ugc2F5aW5nIHdoYXQgdGhlIGRlcGVuZGVudCBkb2VzIHdpdGggdGhpcyBwbHVnaW4sIHNob3duIGluIHRoZSBzZXR0aW5ncyBiYW5uZXIuXG4gICAqXG4gICAqIFRoZSBkZXBlbmRlbnQgb3ducyB0aGlzIHN0cmluZyBiZWNhdXNlIG9ubHkgaXQga25vd3Mgd2hhdCBpdCB1c2VzIHRoZSBvdGhlciBwbHVnaW4gZm9yLCBhbmQgYSB1c2VyXG4gICAqIGJlaW5nIGFza2VkIHRvIGluc3RhbGwgc29tZXRoaW5nIGRlc2VydmVzIHRvIGJlIHRvbGQgd2h5LlxuICAgKi9cbiAgcmVhZG9ubHkgcmVhc29uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogUGFyYW1ldGVycyBmb3IgdGhlIHtAbGluayBQbHVnaW5HYXRlQ29tcG9uZW50fSBjb25zdHJ1Y3Rvci5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQbHVnaW5HYXRlQ29tcG9uZW50Q29uc3RydWN0b3JQYXJhbXMge1xuICAvKipcbiAgICogVGhlIGNvbmZsaWN0cyB0byBlbmZvcmNlLiBBbiBlbXB0eSBsaXN0IG1lYW5zIHRoZSBwbHVnaW4gcmVmdXNlcyB0byBydW4gYmVzaWRlIG5vdGhpbmcuXG4gICAqL1xuICByZWFkb25seSBjb25mbGljdHM6IHJlYWRvbmx5IFBsdWdpbkNvbmZsaWN0W107XG5cbiAgLyoqXG4gICAqIFRoZSBkZXBlbmRlbmNpZXMgdG8gZW5mb3JjZS4gQW4gZW1wdHkgbGlzdCBtZWFucyB0aGUgcGx1Z2luIGRlcGVuZHMgb24gbm90aGluZywgYW5kIGl0cyBmZWF0dXJlXG4gICAqIHN1cmZhY2UgbG9hZHMgaW1tZWRpYXRlbHkuXG4gICAqL1xuICByZWFkb25seSBkZXBlbmRlbmNpZXM6IHJlYWRvbmx5IFBsdWdpbkRlcGVuZGVuY3lbXTtcblxuICAvKipcbiAgICogTG9hZHMgdGhlIGhvc3QgcGx1Z2luJ3MgZmVhdHVyZSBzdXJmYWNlLiBDYWxsZWQgb25jZSBldmVyeSBkZXBlbmRlbmN5IGlzIHNhdGlzZmllZCBhbmQgbm8gYmxvY2tpbmdcbiAgICogY29uZmxpY3QgaG9sZHMsIGFuZCBhZ2FpbiBhZnRlciBhIGdhdGUgdGhhdCBoYWQgY2xvc2VkIG9wZW5zIGJhY2sgdXAuXG4gICAqXG4gICAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc3VyZmFjZSBpcyBsb2FkZWQuXG4gICAqL1xuICBsb2FkRmVhdHVyZVN1cmZhY2UodGhpczogdm9pZCk6IFByb21pc2U8dm9pZD47XG5cbiAgLyoqXG4gICAqIFRoZSBob3N0IHBsdWdpbiBcdTIwMTQgdGhlIG9uZSBkZWNsYXJpbmcgdGhlIGRlcGVuZGVuY2llcyBhbmQgY29uZmxpY3RzLlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luOiBQbHVnaW47XG5cbiAgLyoqXG4gICAqIFRoZSBob3N0IHBsdWdpbidzIG5vdGljZSBjb21wb25lbnQsIHVzZWQgdG8gc2F5IHdoYXQgaXMgbWlzc2luZywgd2hhdCBpcyBpbiB0aGUgd2F5LCBhbmQgd2hhdCBjaGFuZ2VkLlxuICAgKi9cbiAgcmVhZG9ubHkgcGx1Z2luTm90aWNlQ29tcG9uZW50OiBQbHVnaW5Ob3RpY2VDb21wb25lbnQ7XG5cbiAgLyoqXG4gICAqIFVubG9hZHMgdGhlIGhvc3QgcGx1Z2luJ3MgZmVhdHVyZSBzdXJmYWNlLiBDYWxsZWQgd2hlbiBhIGdhdGUgdGhhdCBoYWQgYmVlbiBvcGVuIGNsb3Nlcy5cbiAgICovXG4gIHVubG9hZEZlYXR1cmVTdXJmYWNlKHRoaXM6IHZvaWQpOiB2b2lkO1xufVxuXG4vKipcbiAqIFBhcmFtZXRlcnMgZm9yIHRoZSB7QGxpbmsgQmxvY2tlZFBsdWdpblNldHRpbmdUYWJ9IGNvbnN0cnVjdG9yLlxuICovXG5pbnRlcmZhY2UgQmxvY2tlZFBsdWdpblNldHRpbmdUYWJDb25zdHJ1Y3RvclBhcmFtcyB7XG4gIC8qKlxuICAgKiBUaGUgYmxvY2tlZCBwbHVnaW4uXG4gICAqL1xuICByZWFkb25seSBwbHVnaW46IFBsdWdpbjtcblxuICAvKipcbiAgICogUmVuZGVycyB0aGUgYmxvY2tlZCBleHBsYW5hdGlvbiBpbnRvIHRoZSB0YWIncyBjb250YWluZXIuXG4gICAqXG4gICAqIEBwYXJhbSBjb250YWluZXJFbCAtIFRoZSB0YWIncyBjb250YWluZXIgZWxlbWVudC5cbiAgICovXG4gIHJlbmRlckJhbm5lcih0aGlzOiB2b2lkLCBjb250YWluZXJFbDogSFRNTEVsZW1lbnQpOiB2b2lkO1xufVxuXG4vKipcbiAqIFRoZSBzZXR0aW5ncyB0YWIgYSBibG9ja2VkIHBsdWdpbiBzaG93cyBpbiBwbGFjZSBvZiB0aGUgb25lIGl0IG5ldmVyIGdvdCB0byByZWdpc3Rlci5cbiAqXG4gKiBBIGJsb2NrZWQgcGx1Z2luJ3MgYG9ubG9hZEltcGxgIG5ldmVyIHJhbiwgc28gaXRzIHJlYWwgc2V0dGluZ3MgdGFiIGRvZXMgbm90IGV4aXN0IFx1MjAxNCBhbmQgYSB1c2VyIHdobyBnb2VzXG4gKiBsb29raW5nIGZvciB0aGUgcGx1Z2luJ3Mgc2V0dGluZ3MgaXMgcHJlY2lzZWx5IHRoZSB1c2VyIGFza2luZyBcIndoeSBpc24ndCB0aGlzIGRvaW5nIGFueXRoaW5nP1wiLiBBblxuICogZW1wdHkgc3BhY2UgaXMgdGhlIHdvcnN0IHBvc3NpYmxlIGFuc3dlciB0byB0aGF0IHF1ZXN0aW9uLlxuICovXG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgb2JzaWRpYW5tZC9zZXR0aW5ncy10YWIvcHJlZmVyLXNldHRpbmctZGVmaW5pdGlvbnMgLS0gVGhpcyB0YWIgaGFzIG5vIHNldHRpbmdzIHRvIGRlY2xhcmUuIEl0IHN0YW5kcyBpbiBmb3IgYSBzZXR0aW5ncyB0YWIgdGhhdCBkb2VzIG5vdCBleGlzdCB5ZXQsIGNhcnJ5aW5nIGFuIGV4cGxhbmF0aW9uIGFuZCBhIHJlcGFpciBidXR0b24sIGFuZCB0aGUgcGx1Z2luJ3MgcmVhbCBzZXR0aW5ncyBhcHBlYXIgdGhlIG1vbWVudCB0aGUgZ2F0ZSBvcGVucy5cbmNsYXNzIEJsb2NrZWRQbHVnaW5TZXR0aW5nVGFiIGV4dGVuZHMgUGx1Z2luU2V0dGluZ1RhYiB7XG4gIHByaXZhdGUgcmVhZG9ubHkgcmVuZGVyQmFubmVyOiAoY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KSA9PiB2b2lkO1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHtAbGluayBCbG9ja2VkUGx1Z2luU2V0dGluZ1RhYn0uXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgY29uc3RydWN0b3IgcGFyYW1ldGVycy5cbiAgICovXG4gIHB1YmxpYyBjb25zdHJ1Y3RvcihwYXJhbXM6IEJsb2NrZWRQbHVnaW5TZXR0aW5nVGFiQ29uc3RydWN0b3JQYXJhbXMpIHtcbiAgICBzdXBlcihwYXJhbXMucGx1Z2luLmFwcCwgcGFyYW1zLnBsdWdpbik7XG4gICAgdGhpcy5yZW5kZXJCYW5uZXIgPSBwYXJhbXMucmVuZGVyQmFubmVyO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbmRlcnMgdGhlIHRhYi5cbiAgICovXG4gIHB1YmxpYyBvdmVycmlkZSBkaXNwbGF5KCk6IHZvaWQge1xuICAgIHRoaXMuY29udGFpbmVyRWwuZW1wdHkoKTtcbiAgICB0aGlzLnJlbmRlckJhbm5lcih0aGlzLmNvbnRhaW5lckVsKTtcbiAgfVxufVxuXG4vKipcbiAqIEVuZm9yY2VzIGEgcGx1Z2luJ3MgbWFuZGF0b3J5IGRlcGVuZGVuY2llcyBhbmQgZGVjbGFyZWQgY29uZmxpY3RzLCBnYXRpbmcgaXRzIGZlYXR1cmUgc3VyZmFjZSBvbiBib3RoLlxuICovXG5leHBvcnQgY2xhc3MgUGx1Z2luR2F0ZUNvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudEV4IHtcbiAgcHJpdmF0ZSByZWFkb25seSBhbm5vdW5jZWRXYXJuaW5nUGx1Z2luSWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gIHByaXZhdGUgcmVhZG9ubHkgYXBpUmVmcyA9IG5ldyBNYXA8c3RyaW5nLCBQbHVnaW5BcGlSZWY8b2JqZWN0Pj4oKTtcbiAgcHJpdmF0ZSBibG9ja2VkU2V0dGluZ1RhYjogbnVsbCB8IFBsdWdpblNldHRpbmdUYWIgPSBudWxsO1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbmZsaWN0czogcmVhZG9ubHkgUGx1Z2luQ29uZmxpY3RbXTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZXBlbmRlbmNpZXM6IHJlYWRvbmx5IFBsdWdpbkRlcGVuZGVuY3lbXTtcbiAgcHJpdmF0ZSBoYXNBbm5vdW5jZWRCbG9ja2VkID0gZmFsc2U7XG4gIHByaXZhdGUgaXNGZWF0dXJlU3VyZmFjZUxvYWRlZCA9IGZhbHNlO1xuICBwcml2YXRlIGlzTGF5b3V0UmVhZHkgPSBmYWxzZTtcbiAgcHJpdmF0ZSByZWFkb25seSBsb2FkRmVhdHVyZVN1cmZhY2U6ICgpID0+IFByb21pc2U8dm9pZD47XG4gIHByaXZhdGUgcmVhZG9ubHkgcGx1Z2luOiBQbHVnaW47XG4gIHByaXZhdGUgcmVhZG9ubHkgcGx1Z2luTm90aWNlQ29tcG9uZW50OiBQbHVnaW5Ob3RpY2VDb21wb25lbnQ7XG4gIHByaXZhdGUgcmVhZG9ubHkgdW5sb2FkRmVhdHVyZVN1cmZhY2U6ICgpID0+IHZvaWQ7XG5cbiAgcHJpdmF0ZSBnZXQgYXBwKCk6IEFwcCB7XG4gICAgcmV0dXJuIHRoaXMucGx1Z2luLmFwcDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHtAbGluayBQbHVnaW5HYXRlQ29tcG9uZW50fS5cbiAgICpcbiAgICogQHBhcmFtIHBhcmFtcyAtIFRoZSBjb25zdHJ1Y3RvciBwYXJhbWV0ZXJzLlxuICAgKi9cbiAgcHVibGljIGNvbnN0cnVjdG9yKHBhcmFtczogUGx1Z2luR2F0ZUNvbXBvbmVudENvbnN0cnVjdG9yUGFyYW1zKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLmNvbmZsaWN0cyA9IHBhcmFtcy5jb25mbGljdHM7XG4gICAgdGhpcy5kZXBlbmRlbmNpZXMgPSBwYXJhbXMuZGVwZW5kZW5jaWVzO1xuICAgIHRoaXMubG9hZEZlYXR1cmVTdXJmYWNlID0gcGFyYW1zLmxvYWRGZWF0dXJlU3VyZmFjZTtcbiAgICB0aGlzLnBsdWdpbiA9IHBhcmFtcy5wbHVnaW47XG4gICAgdGhpcy5wbHVnaW5Ob3RpY2VDb21wb25lbnQgPSBwYXJhbXMucGx1Z2luTm90aWNlQ29tcG9uZW50O1xuICAgIHRoaXMudW5sb2FkRmVhdHVyZVN1cmZhY2UgPSBwYXJhbXMudW5sb2FkRmVhdHVyZVN1cmZhY2U7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnRzIHdhdGNoaW5nIGV2ZXJ5IGRlY2xhcmVkIGRlcGVuZGVuY3kgYW5kIGNvbmZsaWN0LlxuICAgKi9cbiAgcHVibGljIG92ZXJyaWRlIG9ubG9hZCgpOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGRlcGVuZGVuY3kgb2YgdGhpcy5kZXBlbmRlbmNpZXMpIHtcbiAgICAgIGNvbnN0IGFwaVJlZiA9IHdhdGNoUGx1Z2luQXBpPG9iamVjdD4oe1xuICAgICAgICBhcGlWZXJzaW9uUmFuZ2U6IGRlcGVuZGVuY3kuYXBpVmVyc2lvblJhbmdlLFxuICAgICAgICBhcHA6IHRoaXMuYXBwLFxuICAgICAgICBjb21wb25lbnQ6IHRoaXMsXG4gICAgICAgIHBsdWdpbklkOiBkZXBlbmRlbmN5LnBsdWdpbklkXG4gICAgICB9KTtcbiAgICAgIHJlZ2lzdGVyQXN5bmNFdmVudChcbiAgICAgICAgdGhpcyxcbiAgICAgICAgYXBpUmVmLm9uKCdjaGFuZ2UnLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgYXdhaXQgdGhpcy5yZWZyZXNoKCk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgICAgdGhpcy5hcGlSZWZzLnNldChkZXBlbmRlbmN5LnBsdWdpbklkLCBhcGlSZWYpO1xuICAgIH1cblxuICAgIC8vIEEgY29uZmxpY3QgaGFzIG5vIEFQSSB0byB3YXRjaCBcdTIwMTQgaXQgaXMgcmVhZCBvdXQgb2YgdGhlIG1hbmlmZXN0cyBcdTIwMTQgc28gdGhlIHRyaWdnZXIgdG8gcmUtcmVhZCBpcyB0aGVcbiAgICAvLyBMaWJyYXJ5J3Mgb3duIGxpZmVjeWNsZSBicm9hZGNhc3QuIEl0IGNvdmVycyBldmVyeSBjb25mbGljdGluZyBwbHVnaW4gYnVpbHQgb24gdGhpcyBsaWJyYXJ5OyBvbmVcbiAgICAvLyBUaGF0IGlzIG5vdCBpcyBjYXVnaHQgYXQgdGhlIG5leHQgbG9hZCwgYXMgdGhlIGZpbGUgaGVhZGVyIHNheXMuXG4gICAgY29uc3QgbGlmZWN5Y2xlRXZlbnROYW1lczogUGx1Z2luTGlmZWN5Y2xlRXZlbnROYW1lW10gPSBbUExVR0lOX0xPQURFRF9FVkVOVF9OQU1FLCBQTFVHSU5fVU5MT0FERURfRVZFTlRfTkFNRV07XG4gICAgZm9yIChjb25zdCBldmVudE5hbWUgb2YgbGlmZWN5Y2xlRXZlbnROYW1lcykge1xuICAgICAgdGhpcy5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLndvcmtzcGFjZS5vbihcbiAgICAgICAgZXZlbnROYW1lLFxuICAgICAgICBjb252ZXJ0QXN5bmNUb1N5bmMoYXN5bmMgKHBheWxvYWQ6IFBsdWdpbkxpZmVjeWNsZUV2ZW50UGF5bG9hZCkgPT4ge1xuICAgICAgICAgIGlmIChwYXlsb2FkLnBsdWdpbklkID09PSB0aGlzLnBsdWdpbi5tYW5pZmVzdC5pZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIGF3YWl0IHRoaXMucmVmcmVzaCgpO1xuICAgICAgICB9KVxuICAgICAgKSk7XG4gICAgfVxuXG4gICAgLy8gTm90aGluZyBpcyBTQUlEIGFib3V0IGEgbWlzc2luZyBkZXBlbmRlbmN5IHVudGlsIHRoZSBsYXlvdXQgaXMgcmVhZHkuIFBsdWdpbnMgbG9hZCBpbiBhbiB1bnNwZWNpZmllZFxuICAgIC8vIE9yZGVyLCBzbyBhIGRlcGVuZGVuY3kgdGhhdCBzaW1wbHkgaGFzIG5vdCBsb2FkZWQgeWV0IGlzIGluZGlzdGluZ3Vpc2hhYmxlIGF0IHRoaXMgcG9pbnQgZnJvbSBvbmVcbiAgICAvLyBUaGF0IGlzIG5vdCBpbnN0YWxsZWQgXHUyMDE0IGFubm91bmNpbmcgaGVyZSB3b3VsZCBwdXQgYSBcIm1pc3NpbmcgcGx1Z2luXCIgbm90aWNlIG9uIHNjcmVlbiBhdCBldmVyeVxuICAgIC8vIFN0YXJ0dXAgYW5kIHRha2UgaXQgYXdheSBhIG1vbWVudCBsYXRlci4gVGhlIGdhdGUgaXRzZWxmIGRvZXMgbm90IHdhaXQ6IHRoZSBzdXJmYWNlIGxvYWRzIHRoZVxuICAgIC8vIEluc3RhbnQgdGhlIGRlcGVuZGVuY3kgaXMgdGhlcmUsIHdoZW5ldmVyIHRoYXQgaXMuXG4gICAgdGhpcy5hZGRDaGlsZChcbiAgICAgIG5ldyBDYWxsYmFja0xheW91dFJlYWR5Q29tcG9uZW50KHRoaXMuYXBwLCAoKSA9PiB7XG4gICAgICAgIHRoaXMuaXNMYXlvdXRSZWFkeSA9IHRydWU7XG4gICAgICAgIHRoaXMucHJlc2VudFVuc2F0aXNmaWVkKHRoaXMuZ2V0VW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMoKSwgdGhpcy5nZXRBY3RpdmVDb25mbGljdHMoUGx1Z2luQ29uZmxpY3RTZXZlcml0eS5CbG9jaykpO1xuICAgICAgICB0aGlzLmFubm91bmNlV2FybmluZ3MoKTtcbiAgICAgIH0pXG4gICAgKTtcblxuICAgIHRoaXMucmVnaXN0ZXIoKCkgPT4ge1xuICAgICAgdGhpcy5oaWRlQmxvY2tlZFNldHRpbmdUYWIoKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZXMgdGhlIGdhdGUgb25jZSB0aGUgd2F0Y2hlcyBhcmUgaW4gcGxhY2UsIGxvYWRpbmcgdGhlIGZlYXR1cmUgc3VyZmFjZSBpZiBpdCBpcyBhbHJlYWR5IG9wZW4uXG4gICAqXG4gICAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZmlyc3QgZXZhbHVhdGlvbiBpcyBjb21wbGV0ZS5cbiAgICovXG4gIHB1YmxpYyBvdmVycmlkZSBhc3luYyBvbmxvYWRBc3luYygpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBhd2FpdCB0aGlzLnJlZnJlc2goKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIGEgYmFubmVyIGZvciBldmVyeSBjb25mbGljdCB0aGUgaG9zdCBpcyBydW5uaW5nIGFsb25nc2lkZSwgc28gYSBwbHVnaW4gY2FuIHB1dCB0aGUgb3ZlcmxhcCBpblxuICAgKiBpdHMgb3duIHNldHRpbmdzIHRhYi5cbiAgICpcbiAgICogQ29uc3VtZXItaW52b2tlZCwgZXhhY3RseSBsaWtlIGBQbHVnaW5TdWdnZXN0aW9uQ29tcG9uZW50LnJlbmRlckJhbm5lcmA6IHRoZSBsaWJyYXJ5IHJlZ2lzdGVycyB0aGVcbiAgICogc2V0dGluZ3MgdGFiIGEgQkxPQ0tFRCBwbHVnaW4gbmVlZHMsIGJlY2F1c2UgdGhhdCBwbHVnaW4gbmV2ZXIgZ290IHRvIHJlZ2lzdGVyIG9uZSBvZiBpdHMgb3duLCBidXQgaXRcbiAgICogaGFzIG5vIGhvb2sgaW50byB0aGUgdGFiIGEgcnVubmluZyBwbHVnaW4gYnVpbGRzLiBSZW5kZXJzIG5vdGhpbmcgd2hlbiBubyB3YXJuaW5nIGNvbmZsaWN0IGhvbGRzLlxuICAgKlxuICAgKiBAcGFyYW0gY29udGFpbmVyRWwgLSBUaGUgZWxlbWVudCB0byByZW5kZXIgaW50by5cbiAgICovXG4gIHB1YmxpYyByZW5kZXJDb25mbGljdFdhcm5pbmdCYW5uZXIoY29udGFpbmVyRWw6IEhUTUxFbGVtZW50KTogdm9pZCB7XG4gICAgZm9yIChjb25zdCBjb25mbGljdCBvZiB0aGlzLmdldEFjdGl2ZUNvbmZsaWN0cyhQbHVnaW5Db25mbGljdFNldmVyaXR5Lldhcm4pKSB7XG4gICAgICB0aGlzLnJlbmRlckNvbmZsaWN0RW50cnkoY29udGFpbmVyRWwsIGNvbmZsaWN0LCB0aGlzLmNyZWF0ZUNvbmZsaWN0V2FybmluZ01lc3NhZ2UoY29uZmxpY3QpKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFubm91bmNlV2FybmluZ3MoKTogdm9pZCB7XG4gICAgLy8gQSB3YXJuaW5nIGRlc2NyaWJlcyB0d28gcGx1Z2lucyB0aGF0IGFyZSBib3RoIFJVTk5JTkcsIHNvIGl0IGlzIHBvaW50bGVzcyB3aGlsZSB0aGlzIG9uZSBpcyBibG9ja2VkXG4gICAgLy8gXHUyMDE0IGFuZCBpdCB3YWl0cyBmb3IgbGF5b3V0LXJlYWR5IGZvciB0aGUgc2FtZSByZWFzb24gdGhlIGJsb2NrZWQgbm90aWNlIGRvZXMuXG4gICAgaWYgKCF0aGlzLmlzTGF5b3V0UmVhZHkgfHwgIXRoaXMuaXNGZWF0dXJlU3VyZmFjZUxvYWRlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgY29uZmxpY3Qgb2YgdGhpcy5nZXRBY3RpdmVDb25mbGljdHMoUGx1Z2luQ29uZmxpY3RTZXZlcml0eS5XYXJuKSkge1xuICAgICAgaWYgKHRoaXMuYW5ub3VuY2VkV2FybmluZ1BsdWdpbklkcy5oYXMoY29uZmxpY3QucGx1Z2luSWQpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLmFubm91bmNlZFdhcm5pbmdQbHVnaW5JZHMuYWRkKGNvbmZsaWN0LnBsdWdpbklkKTtcbiAgICAgIHRoaXMucGx1Z2luTm90aWNlQ29tcG9uZW50LnNob3dOb3RpY2UodGhpcy5jcmVhdGVDb25mbGljdFdhcm5pbmdNZXNzYWdlKGNvbmZsaWN0KSk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVCbG9ja2VkTWVzc2FnZShkZXBlbmRlbmN5OiBQbHVnaW5EZXBlbmRlbmN5KTogRG9jdW1lbnRGcmFnbWVudCB7XG4gICAgcmV0dXJuIGNyZWF0ZUZyYWdtZW50V2l0aENvZGVCbG9ja3ModCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpbkRlcGVuZGVuY3kuYmxvY2tlZE5vdGljZSwge1xuICAgICAgZGVwZW5kZW5jeVBsdWdpbk5hbWU6IGFzQ29kZUJsb2NrKGRlcGVuZGVuY3kucGx1Z2luTmFtZSksXG4gICAgICBwbHVnaW5OYW1lOiBhc0NvZGVCbG9jayh0aGlzLnBsdWdpbi5tYW5pZmVzdC5uYW1lKVxuICAgIH0pKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQ29uZmxpY3RBcHBlYXJlZE1lc3NhZ2UoY29uZmxpY3Q6IFBsdWdpbkNvbmZsaWN0KTogRG9jdW1lbnRGcmFnbWVudCB7XG4gICAgcmV0dXJuIGNyZWF0ZUZyYWdtZW50V2l0aENvZGVCbG9ja3ModCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpbkNvbmZsaWN0LmNvbmZsaWN0QXBwZWFyZWROb3RpY2UsIHtcbiAgICAgIGNvbmZsaWN0aW5nUGx1Z2luTmFtZTogYXNDb2RlQmxvY2soY29uZmxpY3QucGx1Z2luTmFtZSksXG4gICAgICBwbHVnaW5OYW1lOiBhc0NvZGVCbG9jayh0aGlzLnBsdWdpbi5tYW5pZmVzdC5uYW1lKVxuICAgIH0pKTtcbiAgfVxuXG4gIHByaXZhdGUgY3JlYXRlQ29uZmxpY3RCbG9ja2VkTWVzc2FnZShjb25mbGljdDogUGx1Z2luQ29uZmxpY3QpOiBEb2N1bWVudEZyYWdtZW50IHtcbiAgICByZXR1cm4gY3JlYXRlRnJhZ21lbnRXaXRoQ29kZUJsb2Nrcyh0KCgkKSA9PiAkLm9ic2lkaWFuRGV2VXRpbHMucGx1Z2luQ29uZmxpY3QuYmxvY2tlZE5vdGljZSwge1xuICAgICAgY29uZmxpY3RpbmdQbHVnaW5OYW1lOiBhc0NvZGVCbG9jayhjb25mbGljdC5wbHVnaW5OYW1lKSxcbiAgICAgIHBsdWdpbk5hbWU6IGFzQ29kZUJsb2NrKHRoaXMucGx1Z2luLm1hbmlmZXN0Lm5hbWUpXG4gICAgfSkpO1xuICB9XG5cbiAgcHJpdmF0ZSBjcmVhdGVDb25mbGljdFdhcm5pbmdNZXNzYWdlKGNvbmZsaWN0OiBQbHVnaW5Db25mbGljdCk6IERvY3VtZW50RnJhZ21lbnQge1xuICAgIHJldHVybiBjcmVhdGVGcmFnbWVudFdpdGhDb2RlQmxvY2tzKHQoKCQpID0+ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5Db25mbGljdC53YXJuaW5nTm90aWNlLCB7XG4gICAgICBjb25mbGljdGluZ1BsdWdpbk5hbWU6IGFzQ29kZUJsb2NrKGNvbmZsaWN0LnBsdWdpbk5hbWUpLFxuICAgICAgcGx1Z2luTmFtZTogYXNDb2RlQmxvY2sodGhpcy5wbHVnaW4ubWFuaWZlc3QubmFtZSlcbiAgICB9KSk7XG4gIH1cblxuICBwcml2YXRlIGNyZWF0ZURlcGVuZGVuY3lMb3N0TWVzc2FnZShkZXBlbmRlbmN5OiBQbHVnaW5EZXBlbmRlbmN5KTogRG9jdW1lbnRGcmFnbWVudCB7XG4gICAgcmV0dXJuIGNyZWF0ZUZyYWdtZW50V2l0aENvZGVCbG9ja3ModCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpbkRlcGVuZGVuY3kuZGVwZW5kZW5jeUxvc3ROb3RpY2UsIHtcbiAgICAgIGRlcGVuZGVuY3lQbHVnaW5OYW1lOiBhc0NvZGVCbG9jayhkZXBlbmRlbmN5LnBsdWdpbk5hbWUpLFxuICAgICAgcGx1Z2luTmFtZTogYXNDb2RlQmxvY2sodGhpcy5wbHVnaW4ubWFuaWZlc3QubmFtZSlcbiAgICB9KSk7XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgdGhlIGRlY2xhcmVkIGNvbmZsaWN0cyBvZiBvbmUgc2V2ZXJpdHkgdGhhdCBhcmUgY3VycmVudGx5IGluIGZvcmNlLlxuICAgKlxuICAgKiBAcGFyYW0gc2V2ZXJpdHkgLSBUaGUgc2V2ZXJpdHkgdG8gc2VsZWN0LlxuICAgKiBAcmV0dXJucyBUaGUgY29uZmxpY3RzIGhvbGRpbmcgcmlnaHQgbm93LCBpbiB0aGUgb3JkZXIgdGhleSB3ZXJlIGRlY2xhcmVkLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRBY3RpdmVDb25mbGljdHMoc2V2ZXJpdHk6IFBsdWdpbkNvbmZsaWN0U2V2ZXJpdHkpOiBQbHVnaW5Db25mbGljdFtdIHtcbiAgICByZXR1cm4gdGhpcy5jb25mbGljdHMuZmlsdGVyKChjb25mbGljdCkgPT4gY29uZmxpY3Quc2V2ZXJpdHkgPT09IHNldmVyaXR5ICYmIHRoaXMuaXNDb25mbGljdEFjdGl2ZShjb25mbGljdCkpO1xuICB9XG5cbiAgcHJpdmF0ZSBnZXRVbnNhdGlzZmllZERlcGVuZGVuY2llcygpOiBQbHVnaW5EZXBlbmRlbmN5W10ge1xuICAgIHJldHVybiB0aGlzLmRlcGVuZGVuY2llcy5maWx0ZXIoKGRlcGVuZGVuY3kpID0+ICF0aGlzLmFwaVJlZnMuZ2V0KGRlcGVuZGVuY3kucGx1Z2luSWQpPy52YWx1ZSk7XG4gIH1cblxuICBwcml2YXRlIGhpZGVCbG9ja2VkU2V0dGluZ1RhYigpOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuYmxvY2tlZFNldHRpbmdUYWIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLmFwcC5zZXR0aW5nLnJlbW92ZVNldHRpbmdUYWIodGhpcy5ibG9ja2VkU2V0dGluZ1RhYik7XG4gICAgdGhpcy5ibG9ja2VkU2V0dGluZ1RhYiA9IG51bGw7XG4gIH1cblxuICAvKipcbiAgICogRGVjaWRlcyB3aGV0aGVyIG9uZSBkZWNsYXJlZCBjb25mbGljdCBpcyBpbiBmb3JjZSByaWdodCBub3cuXG4gICAqXG4gICAqIE9ubHkgYW4gRU5BQkxFRCBwbHVnaW4gY291bnRzLiBPbmUgdGhhdCBpcyBpbnN0YWxsZWQgYnV0IHN3aXRjaGVkIG9mZiByZWdpc3RlcnMgbm90aGluZywgc28gaXQgY2Fubm90XG4gICAqIGNvbGxpZGUsIGFuZCBhY3Rpbmcgb24gaXQgd291bGQgYmUgYW4gYWxhcm0gdGhlIHVzZXIgY2FuIG9ubHkgYW5zd2VyIGJ5IHVuaW5zdGFsbGluZyBzb21ldGhpbmcgdGhleVxuICAgKiBoYXZlIGFscmVhZHkgdHVybmVkIG9mZi5cbiAgICpcbiAgICogQHBhcmFtIGNvbmZsaWN0IC0gVGhlIGRlY2xhcmVkIGNvbmZsaWN0LlxuICAgKiBAcmV0dXJucyBXaGV0aGVyIHRoZSBjb25mbGljdGluZyBwbHVnaW4gaXMgZW5hYmxlZCBhdCBhIGNvbmZsaWN0aW5nIHZlcnNpb24uXG4gICAqL1xuICBwcml2YXRlIGlzQ29uZmxpY3RBY3RpdmUoY29uZmxpY3Q6IFBsdWdpbkNvbmZsaWN0KTogYm9vbGVhbiB7XG4gICAgY29uc3QgaW5zdGFsbGVkVmVyc2lvbiA9IGdldEluc3RhbGxlZFBsdWdpblZlcnNpb24oe1xuICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgIHBsdWdpbklkOiBjb25mbGljdC5wbHVnaW5JZFxuICAgIH0pO1xuXG4gICAgaWYgKGluc3RhbGxlZFZlcnNpb24gPT09IG51bGwpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHNhdGlzZmllc1ZlcnNpb24oaW5zdGFsbGVkVmVyc2lvbiwgY29uZmxpY3QuY29uZmxpY3RpbmdWZXJzaW9uUmFuZ2UpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFNheXMgd2hhdCBpcyBpbiB0aGUgd2F5LCBhbmQgcHV0cyB0aGUgc2FtZSBleHBsYW5hdGlvbiB3aGVyZSB0aGUgdXNlciB3aWxsIGxvb2sgZm9yIHRoZSBwbHVnaW4nc1xuICAgKiBzZXR0aW5ncy5cbiAgICpcbiAgICogQHBhcmFtIHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzIC0gVGhlIGRlcGVuZGVuY2llcyB0aGF0IGFyZSBub3QgY3VycmVudGx5IHNhdGlzZmllZC5cbiAgICogQHBhcmFtIGJsb2NraW5nQ29uZmxpY3RzIC0gVGhlIGNvbmZsaWN0cyBjdXJyZW50bHkgcmVmdXNpbmcgdGhlIHBsdWdpbiB0aGUgcmlnaHQgdG8gcnVuLlxuICAgKi9cbiAgcHJpdmF0ZSBwcmVzZW50VW5zYXRpc2ZpZWQoXG4gICAgdW5zYXRpc2ZpZWREZXBlbmRlbmNpZXM6IHJlYWRvbmx5IFBsdWdpbkRlcGVuZGVuY3lbXSxcbiAgICBibG9ja2luZ0NvbmZsaWN0czogcmVhZG9ubHkgUGx1Z2luQ29uZmxpY3RbXVxuICApOiB2b2lkIHtcbiAgICBpZiAoIXRoaXMuaXNMYXlvdXRSZWFkeSB8fCAodW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMubGVuZ3RoID09PSAwICYmIGJsb2NraW5nQ29uZmxpY3RzLmxlbmd0aCA9PT0gMCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLnNob3dCbG9ja2VkU2V0dGluZ1RhYih1bnNhdGlzZmllZERlcGVuZGVuY2llcywgYmxvY2tpbmdDb25mbGljdHMpO1xuXG4gICAgaWYgKHRoaXMuaGFzQW5ub3VuY2VkQmxvY2tlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRoaXMuaGFzQW5ub3VuY2VkQmxvY2tlZCA9IHRydWU7XG4gICAgZm9yIChjb25zdCBkZXBlbmRlbmN5IG9mIHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzKSB7XG4gICAgICB0aGlzLnBsdWdpbk5vdGljZUNvbXBvbmVudC5zaG93Tm90aWNlKHRoaXMuY3JlYXRlQmxvY2tlZE1lc3NhZ2UoZGVwZW5kZW5jeSkpO1xuICAgIH1cblxuICAgIGZvciAoY29uc3QgY29uZmxpY3Qgb2YgYmxvY2tpbmdDb25mbGljdHMpIHtcbiAgICAgIHRoaXMucGx1Z2luTm90aWNlQ29tcG9uZW50LnNob3dOb3RpY2UodGhpcy5jcmVhdGVDb25mbGljdEJsb2NrZWRNZXNzYWdlKGNvbmZsaWN0KSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlLWV2YWx1YXRlcyB0aGUgZ2F0ZSBhbmQgbW92ZXMgdGhlIGZlYXR1cmUgc3VyZmFjZSB0byBtYXRjaC5cbiAgICpcbiAgICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzdXJmYWNlIG1hdGNoZXMgdGhlIGdhdGUuXG4gICAqL1xuICBwcml2YXRlIGFzeW5jIHJlZnJlc2goKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgdW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMgPSB0aGlzLmdldFVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzKCk7XG4gICAgY29uc3QgYmxvY2tpbmdDb25mbGljdHMgPSB0aGlzLmdldEFjdGl2ZUNvbmZsaWN0cyhQbHVnaW5Db25mbGljdFNldmVyaXR5LkJsb2NrKTtcblxuICAgIGlmICh1bnNhdGlzZmllZERlcGVuZGVuY2llcy5sZW5ndGggPT09IDAgJiYgYmxvY2tpbmdDb25mbGljdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICB0aGlzLmhpZGVCbG9ja2VkU2V0dGluZ1RhYigpO1xuICAgICAgdGhpcy5oYXNBbm5vdW5jZWRCbG9ja2VkID0gZmFsc2U7XG5cbiAgICAgIGlmICghdGhpcy5pc0ZlYXR1cmVTdXJmYWNlTG9hZGVkKSB7XG4gICAgICAgIHRoaXMuaXNGZWF0dXJlU3VyZmFjZUxvYWRlZCA9IHRydWU7XG4gICAgICAgIGF3YWl0IHRoaXMubG9hZEZlYXR1cmVTdXJmYWNlKCk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYW5ub3VuY2VXYXJuaW5ncygpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLmlzRmVhdHVyZVN1cmZhY2VMb2FkZWQpIHtcbiAgICAgIHRoaXMuaXNGZWF0dXJlU3VyZmFjZUxvYWRlZCA9IGZhbHNlO1xuICAgICAgdGhpcy51bmxvYWRGZWF0dXJlU3VyZmFjZSgpO1xuXG4gICAgICAvLyBBIGdhdGUgdGhhdCBjbG9zZXMgd2hpbGUgdGhlIHBsdWdpbiBpcyBSVU5OSU5HIGlzIHRoZSBjYXNlIHdvcnRoIGJlaW5nIGxvdWQgYWJvdXQ6IHRoZSB1c2VyIGp1c3RcbiAgICAgIC8vIERpZCBzb21ldGhpbmcsIGFuZCB0aGUgY29uc2VxdWVuY2UgaXMgaW1tZWRpYXRlIGFuZCBpbnZpc2libGUgd2l0aG91dCB0aGlzLiBBbm5vdW5jZWQgcmVnYXJkbGVzc1xuICAgICAgLy8gT2YgbGF5b3V0IHJlYWRpbmVzcywgYmVjYXVzZSBhIHJ1bm5pbmcgcGx1Z2luIG1lYW5zIHRoZSBsYXlvdXQgaXMgbG9uZyBzaW5jZSByZWFkeS5cbiAgICAgIGZvciAoY29uc3QgZGVwZW5kZW5jeSBvZiB1bnNhdGlzZmllZERlcGVuZGVuY2llcykge1xuICAgICAgICB0aGlzLnBsdWdpbk5vdGljZUNvbXBvbmVudC5zaG93Tm90aWNlKHRoaXMuY3JlYXRlRGVwZW5kZW5jeUxvc3RNZXNzYWdlKGRlcGVuZGVuY3kpKTtcbiAgICAgIH1cblxuICAgICAgZm9yIChjb25zdCBjb25mbGljdCBvZiBibG9ja2luZ0NvbmZsaWN0cykge1xuICAgICAgICB0aGlzLnBsdWdpbk5vdGljZUNvbXBvbmVudC5zaG93Tm90aWNlKHRoaXMuY3JlYXRlQ29uZmxpY3RBcHBlYXJlZE1lc3NhZ2UoY29uZmxpY3QpKTtcbiAgICAgIH1cblxuICAgICAgdGhpcy5oYXNBbm5vdW5jZWRCbG9ja2VkID0gdHJ1ZTtcbiAgICAgIHRoaXMuc2hvd0Jsb2NrZWRTZXR0aW5nVGFiKHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzLCBibG9ja2luZ0NvbmZsaWN0cyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdGhpcy5wcmVzZW50VW5zYXRpc2ZpZWQodW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMsIGJsb2NraW5nQ29uZmxpY3RzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIHRoZSBibG9ja2VkIGV4cGxhbmF0aW9uIGludG8gYSBzZXR0aW5ncy10YWIgY29udGFpbmVyOiB3aGF0IGlzIG1pc3Npbmcgb3IgaW4gdGhlIHdheSwgd2h5IGl0XG4gICAqIG1hdHRlcnMsIGFuZCB0aGUgYnV0dG9uIHRoYXQgZml4ZXMgaXQuXG4gICAqXG4gICAqIEBwYXJhbSBjb250YWluZXJFbCAtIFRoZSBlbGVtZW50IHRvIHJlbmRlciBpbnRvLlxuICAgKiBAcGFyYW0gdW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMgLSBUaGUgZGVwZW5kZW5jaWVzIHRoYXQgYXJlIG5vdCBjdXJyZW50bHkgc2F0aXNmaWVkLlxuICAgKiBAcGFyYW0gYmxvY2tpbmdDb25mbGljdHMgLSBUaGUgY29uZmxpY3RzIGN1cnJlbnRseSByZWZ1c2luZyB0aGUgcGx1Z2luIHRoZSByaWdodCB0byBydW4uXG4gICAqL1xuICBwcml2YXRlIHJlbmRlckJsb2NrZWRCYW5uZXIoXG4gICAgY29udGFpbmVyRWw6IEhUTUxFbGVtZW50LFxuICAgIHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzOiByZWFkb25seSBQbHVnaW5EZXBlbmRlbmN5W10sXG4gICAgYmxvY2tpbmdDb25mbGljdHM6IHJlYWRvbmx5IFBsdWdpbkNvbmZsaWN0W11cbiAgKTogdm9pZCB7XG4gICAgaWYgKHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzLmxlbmd0aCA+IDApIHtcbiAgICAgIGNvbnRhaW5lckVsLmNyZWF0ZUVsKCdoMicsIHsgdGV4dDogdCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpbkRlcGVuZGVuY3kuc2V0dGluZ3NIZWFkaW5nKSB9KTtcbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGRlcGVuZGVuY3kgb2YgdW5zYXRpc2ZpZWREZXBlbmRlbmNpZXMpIHtcbiAgICAgIGNvbnN0IGJhbm5lckVsID0gY29udGFpbmVyRWwuY3JlYXRlRGl2KHtcbiAgICAgICAgY2xzOiBbQ3NzQ2xhc3MuTGlicmFyeU5hbWUsIENzc0NsYXNzLlBsdWdpbkRlcGVuZGVuY3lCYW5uZXJdXG4gICAgICB9KTtcbiAgICAgIGJhbm5lckVsLmFwcGVuZCh0aGlzLmNyZWF0ZUJsb2NrZWRNZXNzYWdlKGRlcGVuZGVuY3kpKTtcbiAgICAgIGJhbm5lckVsLmNyZWF0ZURpdih7IHRleHQ6IGRlcGVuZGVuY3kucmVhc29uIH0pO1xuXG4gICAgICBjb25zdCBzdGF0ZSA9IGdldEluc3RhbGxlZFBsdWdpblN0YXRlKHtcbiAgICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgICAgcGx1Z2luSWQ6IGRlcGVuZGVuY3kucGx1Z2luSWRcbiAgICAgIH0pO1xuXG4gICAgICBuZXcgQnV0dG9uQ29tcG9uZW50KGJhbm5lckVsKVxuICAgICAgICAuc2V0QnV0dG9uVGV4dCh0KCgkKSA9PlxuICAgICAgICAgIHN0YXRlID09PSBJbnN0YWxsZWRQbHVnaW5TdGF0ZS5JbnN0YWxsZWRCdXREaXNhYmxlZFxuICAgICAgICAgICAgPyAkLm9ic2lkaWFuRGV2VXRpbHMucGx1Z2luU3VnZ2VzdGlvbi5lbmFibGVcbiAgICAgICAgICAgIDogJC5vYnNpZGlhbkRldlV0aWxzLnBsdWdpblN1Z2dlc3Rpb24uaW5zdGFsbFxuICAgICAgICApKVxuICAgICAgICAuc2V0Q3RhKClcbiAgICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgICBhd2FpdCBpbnN0YWxsQW5kRW5hYmxlUGx1Z2luKHtcbiAgICAgICAgICAgIGFwcDogdGhpcy5hcHAsXG4gICAgICAgICAgICBwbHVnaW5JZDogZGVwZW5kZW5jeS5wbHVnaW5JZCxcbiAgICAgICAgICAgIHBsdWdpbk5hbWU6IGRlcGVuZGVuY3kucGx1Z2luTmFtZSxcbiAgICAgICAgICAgIHBsdWdpbk5vdGljZUNvbXBvbmVudDogdGhpcy5wbHVnaW5Ob3RpY2VDb21wb25lbnRcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSkpO1xuXG4gICAgICAvLyBUaGUgbGluayBPVVQgdG8gdGhlIGRlcGVuZGVuY3kncyBvd24gc2V0dGluZ3MsIHNob3duIG9ubHkgb25jZSBpdCBpcyBpbnN0YWxsZWQgYW5kIGVuYWJsZWQgXHUyMDE0IHRoZVxuICAgICAgLy8gT3RoZXIgaGFsZiBvZiB0aGUgcmVsYXRpb25zaGlwIGJlaW5nIHZpc2libGUgZnJvbSBib3RoIGVuZHMuIEl0IGlzIHdoYXQgc3RvcHMgXCJjb25maWd1cmUgb25lXG4gICAgICAvLyBPcGVyYXRpb24gYWNyb3NzIHR3byBwbHVnaW5zXCIgZnJvbSBtZWFuaW5nIFwiZ28gYW5kIGZpbmQgdGhlIG90aGVyIHBsdWdpbiB5b3Vyc2VsZlwiLlxuICAgICAgaWYgKHN0YXRlICE9PSBJbnN0YWxsZWRQbHVnaW5TdGF0ZS5FbmFibGVkKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICB0aGlzLnJlbmRlck9wZW5TZXR0aW5nc0J1dHRvbihiYW5uZXJFbCwgZGVwZW5kZW5jeS5wbHVnaW5JZCwgZGVwZW5kZW5jeS5wbHVnaW5OYW1lKTtcbiAgICB9XG5cbiAgICBpZiAoYmxvY2tpbmdDb25mbGljdHMubGVuZ3RoID09PSAwKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29udGFpbmVyRWwuY3JlYXRlRWwoJ2gyJywgeyB0ZXh0OiB0KCgkKSA9PiAkLm9ic2lkaWFuRGV2VXRpbHMucGx1Z2luQ29uZmxpY3Quc2V0dGluZ3NIZWFkaW5nKSB9KTtcblxuICAgIGZvciAoY29uc3QgY29uZmxpY3Qgb2YgYmxvY2tpbmdDb25mbGljdHMpIHtcbiAgICAgIHRoaXMucmVuZGVyQ29uZmxpY3RFbnRyeShjb250YWluZXJFbCwgY29uZmxpY3QsIHRoaXMuY3JlYXRlQ29uZmxpY3RCbG9ja2VkTWVzc2FnZShjb25mbGljdCkpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZW5kZXJzIG9uZSBjb25mbGljdDogd2hhdCBpdCBpcywgd2h5IGl0IG1hdHRlcnMsIGFuZCB0aGUgdHdvIHdheXMgb3V0IG9mIGl0LlxuICAgKlxuICAgKiBUaGUgcmVwYWlyIGlzIG9mZmVyZWQgb24gdGhlIE9USEVSIHBsdWdpbiBcdTIwMTQgZGlzYWJsaW5nIGl0IGlzIHRoZSBvbmUgdGhpbmcgdGhpcyBwbHVnaW4gY2FuIGRvIGluIGFcbiAgICogY2xpY2ssIHNpbmNlIGl0IGNhbm5vdCB1cGRhdGUgc29tZW9uZSBlbHNlJ3MgcGx1Z2luIFx1MjAxNCBhbmQgaXQgaXMgdGhlIHBlcnNpc3RlZCBgZGlzYWJsZVBsdWdpbkFuZFNhdmVgXG4gICAqIHJhdGhlciB0aGFuIHRoZSB0cmFuc2llbnQgZGlzYWJsZSwgYmVjYXVzZSB0aGUgdXNlciBhc2tlZCBmb3IgaXQgYnkgY2xpY2tpbmcuXG4gICAqXG4gICAqIEBwYXJhbSBjb250YWluZXJFbCAtIFRoZSBlbGVtZW50IHRvIHJlbmRlciBpbnRvLlxuICAgKiBAcGFyYW0gY29uZmxpY3QgLSBUaGUgY29uZmxpY3QgdG8gcmVuZGVyLlxuICAgKiBAcGFyYW0gbWVzc2FnZUZyYWdtZW50IC0gVGhlIHNlbnRlbmNlIGV4cGxhaW5pbmcgdGhlIGNvbmZsaWN0LlxuICAgKi9cbiAgcHJpdmF0ZSByZW5kZXJDb25mbGljdEVudHJ5KGNvbnRhaW5lckVsOiBIVE1MRWxlbWVudCwgY29uZmxpY3Q6IFBsdWdpbkNvbmZsaWN0LCBtZXNzYWdlRnJhZ21lbnQ6IERvY3VtZW50RnJhZ21lbnQpOiB2b2lkIHtcbiAgICBjb25zdCBiYW5uZXJFbCA9IGNvbnRhaW5lckVsLmNyZWF0ZURpdih7XG4gICAgICBjbHM6IFtDc3NDbGFzcy5MaWJyYXJ5TmFtZSwgQ3NzQ2xhc3MuUGx1Z2luQ29uZmxpY3RCYW5uZXJdXG4gICAgfSk7XG4gICAgYmFubmVyRWwuYXBwZW5kKG1lc3NhZ2VGcmFnbWVudCk7XG4gICAgYmFubmVyRWwuY3JlYXRlRGl2KHsgdGV4dDogY29uZmxpY3QucmVhc29uIH0pO1xuXG4gICAgbmV3IEJ1dHRvbkNvbXBvbmVudChiYW5uZXJFbClcbiAgICAgIC5zZXRCdXR0b25UZXh0KHQoKCQpID0+ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5Db25mbGljdC5kaXNhYmxlLCB7IGNvbmZsaWN0aW5nUGx1Z2luTmFtZTogY29uZmxpY3QucGx1Z2luTmFtZSB9KSlcbiAgICAgIC5zZXRDdGEoKVxuICAgICAgLm9uQ2xpY2soY29udmVydEFzeW5jVG9TeW5jKGFzeW5jICgpID0+IHtcbiAgICAgICAgYXdhaXQgZGlzYWJsZUNvbW11bml0eVBsdWdpbih7XG4gICAgICAgICAgYXBwOiB0aGlzLmFwcCxcbiAgICAgICAgICBwbHVnaW5JZDogY29uZmxpY3QucGx1Z2luSWRcbiAgICAgICAgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMucmVmcmVzaCgpO1xuICAgICAgfSkpO1xuXG4gICAgdGhpcy5yZW5kZXJPcGVuU2V0dGluZ3NCdXR0b24oYmFubmVyRWwsIGNvbmZsaWN0LnBsdWdpbklkLCBjb25mbGljdC5wbHVnaW5OYW1lKTtcbiAgfVxuXG4gIHByaXZhdGUgcmVuZGVyT3BlblNldHRpbmdzQnV0dG9uKGJhbm5lckVsOiBIVE1MRWxlbWVudCwgcGx1Z2luSWQ6IHN0cmluZywgcGx1Z2luTmFtZTogc3RyaW5nKTogdm9pZCB7XG4gICAgbmV3IEJ1dHRvbkNvbXBvbmVudChiYW5uZXJFbClcbiAgICAgIC5zZXRCdXR0b25UZXh0KHQoKCQpID0+ICQub2JzaWRpYW5EZXZVdGlscy5wbHVnaW5EZXBlbmRlbmN5Lm9wZW5EZXBlbmRlbmN5U2V0dGluZ3MsIHtcbiAgICAgICAgZGVwZW5kZW5jeVBsdWdpbk5hbWU6IHBsdWdpbk5hbWVcbiAgICAgIH0pKVxuICAgICAgLm9uQ2xpY2soKCkgPT4ge1xuICAgICAgICB0aGlzLmFwcC5zZXR0aW5nLm9wZW4oKTtcbiAgICAgICAgdGhpcy5hcHAuc2V0dGluZy5vcGVuVGFiQnlJZChwbHVnaW5JZCk7XG4gICAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgc2hvd0Jsb2NrZWRTZXR0aW5nVGFiKFxuICAgIHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzOiByZWFkb25seSBQbHVnaW5EZXBlbmRlbmN5W10sXG4gICAgYmxvY2tpbmdDb25mbGljdHM6IHJlYWRvbmx5IFBsdWdpbkNvbmZsaWN0W11cbiAgKTogdm9pZCB7XG4gICAgaWYgKHRoaXMuYmxvY2tlZFNldHRpbmdUYWIpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBBZGRlZCB0aHJvdWdoIGBhcHAuc2V0dGluZ2AgcmF0aGVyIHRoYW4gYHBsdWdpbi5hZGRTZXR0aW5nVGFiYCwgYmVjYXVzZSB0aGlzIHRhYiBoYXMgdG8gY29tZSBiYWNrXG4gICAgLy8gT0ZGIGFnYWluIHRoZSBtb21lbnQgdGhlIGdhdGUgb3BlbnMgXHUyMDE0IG90aGVyd2lzZSB0aGUgcGx1Z2luJ3Mgb3duIHNldHRpbmdzIHRhYiwgcmVnaXN0ZXJlZCBieVxuICAgIC8vIGBvbmxvYWRJbXBsYCwgd291bGQgYXBwZWFyIGJlc2lkZSBhIHN0YWxlIFwicmVxdWlyZWQgcGx1Z2luIG1pc3NpbmdcIiBvbmUuIGBwbHVnaW4uYWRkU2V0dGluZ1RhYmBcbiAgICAvLyBPbmx5IGV2ZXIgcmVtb3ZlcyBhdCBwbHVnaW4gdW5sb2FkLlxuICAgIGNvbnN0IGJsb2NrZWRTZXR0aW5nVGFiID0gbmV3IEJsb2NrZWRQbHVnaW5TZXR0aW5nVGFiKHtcbiAgICAgIHBsdWdpbjogdGhpcy5wbHVnaW4sXG4gICAgICByZW5kZXJCYW5uZXI6IChjb250YWluZXJFbCk6IHZvaWQgPT4ge1xuICAgICAgICB0aGlzLnJlbmRlckJsb2NrZWRCYW5uZXIoY29udGFpbmVyRWwsIHVuc2F0aXNmaWVkRGVwZW5kZW5jaWVzLCBibG9ja2luZ0NvbmZsaWN0cyk7XG4gICAgICB9XG4gICAgfSk7XG4gICAgdGhpcy5hcHAuc2V0dGluZy5hZGRTZXR0aW5nVGFiKGJsb2NrZWRTZXR0aW5nVGFiKTtcbiAgICB0aGlzLmJsb2NrZWRTZXR0aW5nVGFiID0gYmxvY2tlZFNldHRpbmdUYWI7XG4gIH1cbn1cbiJdLAogICJtYXBwaW5ncyI6ICI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUErRUEsU0FBUyxhQUFhLHdCQUF3QjtBQUM5QztBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQVNQLFNBQVMsMEJBQTBCO0FBQ25DLFNBQVMsOEJBQThCO0FBQ3ZDLFNBQVMsZ0JBQWdCO0FBQ3pCO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxTQUFTO0FBQ2xCLFNBQVMsc0JBQXNCO0FBQy9CO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUDtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsT0FDSztBQUNQLFNBQVMsMEJBQTBCO0FBQ25DLFNBQVMsbUJBQW1CO0FBQzVCLFNBQVMsb0NBQW9DO0FBS3RDLElBQUsseUJBQUwsa0JBQUtBLDRCQUFMO0FBT0wsRUFBQUEsd0JBQUEsV0FBUTtBQVFSLEVBQUFBLHdCQUFBLFVBQU87QUFmRyxTQUFBQTtBQUFBLEdBQUE7QUF5SlosTUFBTSxnQ0FBZ0MsaUJBQWlCO0FBQUEsRUFDcEM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFPVixZQUFZLFFBQWtEO0FBQ25FLFVBQU0sT0FBTyxPQUFPLEtBQUssT0FBTyxNQUFNO0FBQ3RDLFNBQUssZUFBZSxPQUFPO0FBQUEsRUFDN0I7QUFBQTtBQUFBO0FBQUE7QUFB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QUFFLE1BQU0sRUFBRSxDQUFDLE1BQU0sRUFBRSxpQkFBaUIsZUFBZSxlQUFlLEVBQUUsQ0FBQztBQUVoRyxlQUFXLFlBQVksbUJBQW1CO0FBQ3hDLFdBQUssb0JBQW9CLGFBQWEsVUFBVSxLQUFLLDZCQUE2QixRQUFRLENBQUM7QUFBQSxJQUM3RjtBQUFBLEVBQ0Y7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFhUSxvQkFBb0IsYUFBMEIsVUFBMEIsaUJBQXlDO0FBQ3ZILFVBQU0sV0FBVyxZQUFZLFVBQVU7QUFBQSxNQUNyQyxLQUFLLENBQUMsU0FBUyxhQUFhLFNBQVMsb0JBQW9CO0FBQUEsSUFDM0QsQ0FBQztBQUNELGFBQVMsT0FBTyxlQUFlO0FBQy9CLGFBQVMsVUFBVSxFQUFFLE1BQU0sU0FBUyxPQUFPLENBQUM7QUFFNUMsUUFBSSxnQkFBZ0IsUUFBUSxFQUN6QixjQUFjLEVBQUUsQ0FBQyxNQUFNLEVBQUUsaUJBQWlCLGVBQWUsU0FBUyxFQUFFLHVCQUF1QixTQUFTLFdBQVcsQ0FBQyxDQUFDLEVBQ2pILE9BQU8sRUFDUCxRQUFRLG1CQUFtQixZQUFZO0FBQ3RDLFlBQU0sdUJBQXVCO0FBQUEsUUFDM0IsS0FBSyxLQUFLO0FBQUEsUUFDVixVQUFVLFNBQVM7QUFBQSxNQUNyQixDQUFDO0FBQ0QsWUFBTSxLQUFLLFFBQVE7QUFBQSxJQUNyQixDQUFDLENBQUM7QUFFSixTQUFLLHlCQUF5QixVQUFVLFNBQVMsVUFBVSxTQUFTLFVBQVU7QUFBQSxFQUNoRjtBQUFBLEVBRVEseUJBQXlCLFVBQXVCLFVBQWtCLFlBQTBCO0FBQ2xHLFFBQUksZ0JBQWdCLFFBQVEsRUFDekIsY0FBYyxFQUFFLENBQUMsTUFBTSxFQUFFLGlCQUFpQixpQkFBaUIsd0JBQXdCO0FBQUEsTUFDbEYsc0JBQXNCO0FBQUEsSUFDeEIsQ0FBQyxDQUFDLEVBQ0QsUUFBUSxNQUFNO0FBQ2IsV0FBSyxJQUFJLFFBQVEsS0FBSztBQUN0QixXQUFLLElBQUksUUFBUSxZQUFZLFFBQVE7QUFBQSxJQUN2QyxDQUFDO0FBQUEsRUFDTDtBQUFBLEVBRVEsc0JBQ04seUJBQ0EsbUJBQ007QUFDTixRQUFJLEtBQUssbUJBQW1CO0FBQzFCO0FBQUEsSUFDRjtBQU1BLFVBQU0sb0JBQW9CLElBQUksd0JBQXdCO0FBQUEsTUFDcEQsUUFBUSxLQUFLO0FBQUEsTUFDYixjQUFjLENBQUMsZ0JBQXNCO0FBQ25DLGFBQUssb0JBQW9CLGFBQWEseUJBQXlCLGlCQUFpQjtBQUFBLE1BQ2xGO0FBQUEsSUFDRixDQUFDO0FBQ0QsU0FBSyxJQUFJLFFBQVEsY0FBYyxpQkFBaUI7QUFDaEQsU0FBSyxvQkFBb0I7QUFBQSxFQUMzQjtBQUNGOyIsCiAgIm5hbWVzIjogWyJQbHVnaW5Db25mbGljdFNldmVyaXR5Il0KfQo=
@@ -5,10 +5,21 @@
5
5
  * Component that suggests installing another community plugin the host plugin needs in order to offer
6
6
  * some of its behavior.
7
7
  *
8
- * A suggestion is not a dependency. Obsidian has no mechanism for one community plugin to require
9
- * another, and inventing one by refusing to load would punish the user for something they never agreed
10
- * to. So the host plugin keeps working without the suggested plugin it simply cannot offer whatever
11
- * that plugin owns — and this component asks, once, whether the user would like it installed.
8
+ * A suggestion is not a dependency but a dependency is now a thing this library HAS, so the choice
9
+ * between them is a real one. Use a suggestion when the other plugin ADDS something: the host keeps
10
+ * working without it, simply unable to offer whatever that plugin owns, and this component asks once
11
+ * whether the user would like it installed. Use `PluginGateComponent` when the host's advertised
12
+ * behavior is not there at all without the other plugin.
13
+ *
14
+ * This file used to argue the stronger position — that requiring another plugin should not exist, because
15
+ * "inventing one by refusing to load would punish the user for something they never agreed to". That was
16
+ * wrong about which option punishes the user, and the counter-case is worth keeping rather than quietly
17
+ * deleting. A load-bearing plugin the user cannot identify is not a neutral outcome: months later they
18
+ * meet it in their plugin list, nothing in Obsidian's manifest format says anything depends on it, they
19
+ * remove it, and the damage surfaces weeks after that with no way to connect the two. Beside that, a
20
+ * mandatory dependency that stays enabled-but-inert, names what it is waiting for, installs it in one
21
+ * click and resumes without a restart is not a punishment — it is the same information, delivered while
22
+ * the user can still act on it.
12
23
  *
13
24
  * The ask is surfaced twice, deliberately, because the two placements answer different questions:
14
25
  * a notice on load ("you are missing something you probably want") and a settings-tab banner ("the
@@ -19,24 +30,16 @@ import type { App } from 'obsidian';
19
30
  import type { Promisable } from 'type-fest';
20
31
  import type { PluginNoticeComponent } from './plugin-notice-component.mjs';
21
32
  import type { PluginSettingsComponentBase } from './plugin-settings-component.mjs';
33
+ import { InstalledPluginState } from '../plugin/plugin-install-state.mjs';
22
34
  import { ComponentEx } from './component-ex.mjs';
23
35
  /**
24
36
  * How the suggested plugin is currently present in the vault.
37
+ *
38
+ * The same three states a mandatory dependency is in, so this is {@link InstalledPluginState} under the
39
+ * name this component has always used — one enum, so a caller holding a state from either component can
40
+ * compare it against either name.
25
41
  */
26
- export declare enum SuggestedPluginState {
27
- /**
28
- * Installed and enabled — there is nothing to suggest.
29
- */
30
- Enabled = "enabled",
31
- /**
32
- * Installed but disabled. Only an enable is needed, so no download happens.
33
- */
34
- InstalledButDisabled = "installedButDisabled",
35
- /**
36
- * Not installed at all.
37
- */
38
- NotInstalled = "notInstalled"
39
- }
42
+ export declare const SuggestedPluginState: typeof InstalledPluginState;
40
43
  /**
41
44
  * Parameters for the {@link PluginSuggestionComponent} constructor.
42
45
  */
@@ -92,6 +95,10 @@ export interface PluginSuggestionComponentConstructorParams {
92
95
  */
93
96
  readonly suggestedPluginName: string;
94
97
  }
98
+ /**
99
+ * How the suggested plugin is currently present in the vault.
100
+ */
101
+ export type SuggestedPluginState = InstalledPluginState;
95
102
  /**
96
103
  * Suggests installing another community plugin, via a load-time notice and a settings-tab banner.
97
104
  */