@mnaoumov/obsidian-lib 10.5.1 → 10.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.
- package/codemirror/inline-token-widgets/package.json +6 -0
- package/codemirror/settings-facet/package.json +6 -0
- package/command-handlers/open-discussion-command-handler/package.json +6 -0
- package/command-handlers/open-feature-request-command-handler/package.json +6 -0
- package/command-handlers/open-git-hub-command-handler/package.json +6 -0
- package/components/settings-facet-component/package.json +6 -0
- package/components/style-sheet-component/package.json +6 -0
- package/dist/lib/cjs/__merged.cjs +137 -1
- package/dist/lib/cjs/__merged.d.cts +26 -0
- package/dist/lib/cjs/anchored-suggest.cjs +232 -0
- package/dist/lib/cjs/anchored-suggest.d.cts +116 -0
- package/dist/lib/cjs/broken-link-candidates.cjs +366 -0
- package/dist/lib/cjs/broken-link-candidates.d.cts +181 -0
- package/dist/lib/cjs/bug-report.cjs +4 -2
- package/dist/lib/cjs/bug-report.d.cts +1 -1
- package/dist/lib/cjs/code-block-render-handoff.cjs +272 -0
- package/dist/lib/cjs/code-block-render-handoff.d.cts +131 -0
- package/dist/lib/cjs/codemirror/index.cjs +7 -1
- package/dist/lib/cjs/codemirror/index.d.cts +2 -0
- package/dist/lib/cjs/codemirror/inline-token-widgets.cjs +250 -0
- package/dist/lib/cjs/codemirror/inline-token-widgets.d.cts +109 -0
- package/dist/lib/cjs/codemirror/settings-facet.cjs +132 -0
- package/dist/lib/cjs/codemirror/settings-facet.d.cts +19 -0
- package/dist/lib/cjs/command-handlers/index.cjs +10 -1
- package/dist/lib/cjs/command-handlers/index.d.cts +3 -0
- package/dist/lib/cjs/command-handlers/open-bug-report-command-handler.cjs +9 -12
- package/dist/lib/cjs/command-handlers/open-bug-report-command-handler.d.cts +6 -8
- package/dist/lib/cjs/command-handlers/open-discussion-command-handler.cjs +127 -0
- package/dist/lib/cjs/command-handlers/open-discussion-command-handler.d.cts +45 -0
- package/dist/lib/cjs/command-handlers/open-feature-request-command-handler.cjs +119 -0
- package/dist/lib/cjs/command-handlers/open-feature-request-command-handler.d.cts +33 -0
- package/dist/lib/cjs/command-handlers/open-git-hub-command-handler.cjs +121 -0
- package/dist/lib/cjs/command-handlers/open-git-hub-command-handler.d.cts +43 -0
- package/dist/lib/cjs/components/index.cjs +7 -1
- package/dist/lib/cjs/components/index.d.cts +2 -0
- package/dist/lib/cjs/components/settings-facet-component.cjs +136 -0
- package/dist/lib/cjs/components/settings-facet-component.d.cts +68 -0
- package/dist/lib/cjs/components/style-sheet-component.cjs +198 -0
- package/dist/lib/cjs/components/style-sheet-component.d.cts +79 -0
- package/dist/lib/cjs/css-class.cjs +8 -1
- package/dist/lib/cjs/css-class.d.cts +28 -0
- package/dist/lib/cjs/data-stores/data-store-transport.cjs +7 -4
- package/dist/lib/cjs/data-stores/data-store-transport.d.cts +1 -1
- package/dist/lib/cjs/data-stores/shared-data-store.cjs +1 -1
- package/dist/lib/cjs/data-stores/shared-data-store.d.cts +1 -1
- package/dist/lib/cjs/desktop-git-runner.cjs +117 -0
- package/dist/lib/cjs/desktop-git-runner.d.cts +17 -0
- package/dist/lib/cjs/desktop-request-url-stream.cjs +258 -0
- package/dist/lib/cjs/desktop-request-url-stream.d.cts +22 -0
- package/dist/lib/cjs/editor-suggest-registrar.cjs +8 -2
- package/dist/lib/cjs/editor-suggest-registrar.d.cts +14 -2
- package/dist/lib/cjs/editor-suggest.cjs +197 -0
- package/dist/lib/cjs/editor-suggest.d.cts +103 -0
- package/dist/lib/cjs/feature-request.cjs +115 -0
- package/dist/lib/cjs/feature-request.d.cts +54 -0
- package/dist/lib/cjs/generated-during-build.cjs +2 -2
- package/dist/lib/cjs/git-hub-discussion.cjs +101 -0
- package/dist/lib/cjs/git-hub-discussion.d.cts +28 -0
- package/dist/lib/cjs/git-rename-history.cjs +148 -0
- package/dist/lib/cjs/git-rename-history.d.cts +43 -0
- package/dist/lib/cjs/hotkey.cjs +185 -0
- package/dist/lib/cjs/hotkey.d.cts +59 -0
- package/dist/lib/cjs/i18n/locales/en.cjs +13 -1
- package/dist/lib/cjs/i18n/locales/en.d.cts +12 -0
- package/dist/lib/cjs/i18n/locales/translations-map.d.cts +12 -0
- package/dist/lib/cjs/index.cjs +46 -1
- package/dist/lib/cjs/index.d.cts +15 -0
- package/dist/lib/cjs/inline-token-renderer.cjs +145 -0
- package/dist/lib/cjs/inline-token-renderer.d.cts +88 -0
- package/dist/lib/cjs/link-and-tag-input-suggest.cjs +325 -0
- package/dist/lib/cjs/link-and-tag-input-suggest.d.cts +229 -0
- package/dist/lib/cjs/markdown-code-block-processor.cjs +13 -1
- package/dist/lib/cjs/markdown-code-block-processor.d.cts +18 -0
- package/dist/lib/cjs/markdown.cjs +6 -1
- package/dist/lib/cjs/markdown.d.cts +10 -1
- package/dist/lib/cjs/rendered-markdown.cjs +306 -0
- package/dist/lib/cjs/rendered-markdown.d.cts +77 -0
- package/dist/lib/cjs/request-url.cjs +523 -0
- package/dist/lib/cjs/request-url.d.cts +233 -0
- package/dist/lib/cjs/setting-components/folder-list-component.cjs +216 -0
- package/dist/lib/cjs/setting-components/folder-list-component.d.cts +73 -0
- package/dist/lib/cjs/setting-components/hotkey-component.cjs +260 -0
- package/dist/lib/cjs/setting-components/hotkey-component.d.cts +85 -0
- package/dist/lib/cjs/setting-components/index.cjs +13 -1
- package/dist/lib/cjs/setting-components/index.d.cts +4 -0
- package/dist/lib/cjs/setting-components/list-component.cjs +291 -0
- package/dist/lib/cjs/setting-components/list-component.d.cts +106 -0
- package/dist/lib/cjs/setting-components/tag-list-component.cjs +220 -0
- package/dist/lib/cjs/setting-components/tag-list-component.d.cts +82 -0
- package/dist/lib/cjs/setting-ex.cjs +51 -1
- package/dist/lib/cjs/setting-ex.d.cts +35 -1
- package/dist/lib/cjs/settings-tabs.cjs +258 -0
- package/dist/lib/cjs/settings-tabs.d.cts +101 -0
- package/dist/lib/cjs/vault.cjs +2 -2
- package/dist/lib/cjs/vault.d.cts +3 -1
- package/dist/lib/esm/__merged.d.mts +26 -0
- package/dist/lib/esm/__merged.mjs +139 -1
- package/dist/lib/esm/anchored-suggest.d.mts +116 -0
- package/dist/lib/esm/anchored-suggest.mjs +144 -0
- package/dist/lib/esm/broken-link-candidates.d.mts +181 -0
- package/dist/lib/esm/broken-link-candidates.mjs +275 -0
- package/dist/lib/esm/bug-report.d.mts +1 -1
- package/dist/lib/esm/bug-report.mjs +4 -2
- package/dist/lib/esm/code-block-render-handoff.d.mts +131 -0
- package/dist/lib/esm/code-block-render-handoff.mjs +183 -0
- package/dist/lib/esm/codemirror/index.d.mts +2 -0
- package/dist/lib/esm/codemirror/index.mjs +5 -1
- package/dist/lib/esm/codemirror/inline-token-widgets.d.mts +109 -0
- package/dist/lib/esm/codemirror/inline-token-widgets.mjs +167 -0
- package/dist/lib/esm/codemirror/settings-facet.d.mts +19 -0
- package/dist/lib/esm/codemirror/settings-facet.mjs +44 -0
- package/dist/lib/esm/command-handlers/index.d.mts +3 -0
- package/dist/lib/esm/command-handlers/index.mjs +7 -1
- package/dist/lib/esm/command-handlers/open-bug-report-command-handler.d.mts +6 -8
- package/dist/lib/esm/command-handlers/open-bug-report-command-handler.mjs +9 -12
- package/dist/lib/esm/command-handlers/open-discussion-command-handler.d.mts +45 -0
- package/dist/lib/esm/command-handlers/open-discussion-command-handler.mjs +39 -0
- package/dist/lib/esm/command-handlers/open-feature-request-command-handler.d.mts +33 -0
- package/dist/lib/esm/command-handlers/open-feature-request-command-handler.mjs +31 -0
- package/dist/lib/esm/command-handlers/open-git-hub-command-handler.d.mts +43 -0
- package/dist/lib/esm/command-handlers/open-git-hub-command-handler.mjs +33 -0
- package/dist/lib/esm/components/index.d.mts +2 -0
- package/dist/lib/esm/components/index.mjs +5 -1
- package/dist/lib/esm/components/settings-facet-component.d.mts +68 -0
- package/dist/lib/esm/components/settings-facet-component.mjs +48 -0
- package/dist/lib/esm/components/style-sheet-component.d.mts +79 -0
- package/dist/lib/esm/components/style-sheet-component.mjs +109 -0
- package/dist/lib/esm/css-class.d.mts +28 -0
- package/dist/lib/esm/css-class.mjs +8 -1
- package/dist/lib/esm/data-stores/data-store-transport.d.mts +1 -1
- package/dist/lib/esm/data-stores/data-store-transport.mjs +7 -4
- package/dist/lib/esm/data-stores/shared-data-store.d.mts +1 -1
- package/dist/lib/esm/data-stores/shared-data-store.mjs +1 -1
- package/dist/lib/esm/desktop-git-runner.d.mts +17 -0
- package/dist/lib/esm/desktop-git-runner.mjs +19 -0
- package/dist/lib/esm/desktop-request-url-stream.d.mts +22 -0
- package/dist/lib/esm/desktop-request-url-stream.mjs +170 -0
- package/dist/lib/esm/editor-suggest-registrar.d.mts +14 -2
- package/dist/lib/esm/editor-suggest-registrar.mjs +8 -2
- package/dist/lib/esm/editor-suggest.d.mts +103 -0
- package/dist/lib/esm/editor-suggest.mjs +108 -0
- package/dist/lib/esm/feature-request.d.mts +54 -0
- package/dist/lib/esm/feature-request.mjs +25 -0
- package/dist/lib/esm/generated-during-build.mjs +2 -2
- package/dist/lib/esm/git-hub-discussion.d.mts +28 -0
- package/dist/lib/esm/git-hub-discussion.mjs +13 -0
- package/dist/lib/esm/git-rename-history.d.mts +43 -0
- package/dist/lib/esm/git-rename-history.mjs +59 -0
- package/dist/lib/esm/hotkey.d.mts +59 -0
- package/dist/lib/esm/hotkey.mjs +95 -0
- package/dist/lib/esm/i18n/locales/en.d.mts +12 -0
- package/dist/lib/esm/i18n/locales/en.mjs +13 -1
- package/dist/lib/esm/i18n/locales/translations-map.d.mts +12 -0
- package/dist/lib/esm/index.d.mts +15 -0
- package/dist/lib/esm/index.mjs +31 -1
- package/dist/lib/esm/inline-token-renderer.d.mts +88 -0
- package/dist/lib/esm/inline-token-renderer.mjs +59 -0
- package/dist/lib/esm/link-and-tag-input-suggest.d.mts +229 -0
- package/dist/lib/esm/link-and-tag-input-suggest.mjs +239 -0
- package/dist/lib/esm/markdown-code-block-processor.d.mts +18 -0
- package/dist/lib/esm/markdown-code-block-processor.mjs +16 -1
- package/dist/lib/esm/markdown.d.mts +10 -1
- package/dist/lib/esm/markdown.mjs +9 -1
- package/dist/lib/esm/rendered-markdown.d.mts +77 -0
- package/dist/lib/esm/rendered-markdown.mjs +219 -0
- package/dist/lib/esm/request-url.d.mts +233 -0
- package/dist/lib/esm/request-url.mjs +428 -0
- package/dist/lib/esm/setting-components/folder-list-component.d.mts +73 -0
- package/dist/lib/esm/setting-components/folder-list-component.mjs +131 -0
- package/dist/lib/esm/setting-components/hotkey-component.d.mts +85 -0
- package/dist/lib/esm/setting-components/hotkey-component.mjs +178 -0
- package/dist/lib/esm/setting-components/index.d.mts +4 -0
- package/dist/lib/esm/setting-components/index.mjs +9 -1
- package/dist/lib/esm/setting-components/list-component.d.mts +106 -0
- package/dist/lib/esm/setting-components/list-component.mjs +206 -0
- package/dist/lib/esm/setting-components/tag-list-component.d.mts +82 -0
- package/dist/lib/esm/setting-components/tag-list-component.mjs +131 -0
- package/dist/lib/esm/setting-ex.d.mts +35 -1
- package/dist/lib/esm/setting-ex.mjs +51 -1
- package/dist/lib/esm/settings-tabs.d.mts +101 -0
- package/dist/lib/esm/settings-tabs.mjs +170 -0
- package/dist/lib/esm/vault.d.mts +3 -1
- package/dist/lib/esm/vault.mjs +2 -2
- package/dist/styles.css +83 -1
- package/package.json +2 -2
- package/setting-components/folder-list-component/package.json +6 -0
- package/setting-components/hotkey-component/package.json +6 -0
- package/setting-components/list-component/package.json +6 -0
- package/setting-components/tag-list-component/package.json +6 -0
|
@@ -0,0 +1,366 @@
|
|
|
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
|
+
(function () {
|
|
6
|
+
function ensureBrowserProcess() {
|
|
7
|
+
const browserProcess = {
|
|
8
|
+
browser: true,
|
|
9
|
+
cwd() {
|
|
10
|
+
return "/";
|
|
11
|
+
},
|
|
12
|
+
env: {},
|
|
13
|
+
platform: "android"
|
|
14
|
+
};
|
|
15
|
+
const existingProcess = globalThis.process;
|
|
16
|
+
if (!existingProcess) {
|
|
17
|
+
globalThis.process = browserProcess;
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (existingProcess.versions?.node) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
const existingProcessRecord = existingProcess;
|
|
24
|
+
for (const [key, value] of Object.entries(browserProcess)) {
|
|
25
|
+
existingProcessRecord[key] ??= value;
|
|
26
|
+
}
|
|
27
|
+
existingProcessRecord["browser"] = true;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
ensureBrowserProcess();
|
|
31
|
+
})();
|
|
32
|
+
(function patchObsidianRequire() {
|
|
33
|
+
const originalRequire = require;
|
|
34
|
+
if (!originalRequire || originalRequire.__isPatched) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
require = Object.assign(
|
|
38
|
+
(id) => requirePatched(id),
|
|
39
|
+
originalRequire,
|
|
40
|
+
{
|
|
41
|
+
__isPatched: true
|
|
42
|
+
}
|
|
43
|
+
);
|
|
44
|
+
function extractDefault($module) {
|
|
45
|
+
return $module && $module.__esModule && "default" in $module ? $module.default : $module;
|
|
46
|
+
}
|
|
47
|
+
const OBSIDIAN_BUILT_IN_MODULE_NAMES = /* @__PURE__ */ new Set([
|
|
48
|
+
"@codemirror/autocomplete",
|
|
49
|
+
"@codemirror/collab",
|
|
50
|
+
"@codemirror/commands",
|
|
51
|
+
"@codemirror/language",
|
|
52
|
+
"@codemirror/lint",
|
|
53
|
+
"@codemirror/search",
|
|
54
|
+
"@codemirror/state",
|
|
55
|
+
"@codemirror/text",
|
|
56
|
+
"@codemirror/view",
|
|
57
|
+
"@lezer/common",
|
|
58
|
+
"@lezer/highlight",
|
|
59
|
+
"@lezer/lr",
|
|
60
|
+
"obsidian"
|
|
61
|
+
]);
|
|
62
|
+
const DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES = /* @__PURE__ */ new Set([
|
|
63
|
+
"@codemirror/closebrackets",
|
|
64
|
+
"@codemirror/comment",
|
|
65
|
+
"@codemirror/fold",
|
|
66
|
+
"@codemirror/gutter",
|
|
67
|
+
"@codemirror/highlight",
|
|
68
|
+
"@codemirror/history",
|
|
69
|
+
"@codemirror/matchbrackets",
|
|
70
|
+
"@codemirror/panel",
|
|
71
|
+
"@codemirror/rangeset",
|
|
72
|
+
"@codemirror/rectangular-selection",
|
|
73
|
+
"@codemirror/stream-parser",
|
|
74
|
+
"@codemirror/tooltip"
|
|
75
|
+
]);
|
|
76
|
+
function requirePatched(id) {
|
|
77
|
+
if (OBSIDIAN_BUILT_IN_MODULE_NAMES.has(id) || DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES.has(id)) {
|
|
78
|
+
return originalRequire?.(id);
|
|
79
|
+
}
|
|
80
|
+
const app = globalThis.app;
|
|
81
|
+
if (app?.isMobile) {
|
|
82
|
+
if (id === "process" || id === "node:process") {
|
|
83
|
+
console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Fake process object is returned instead.`);
|
|
84
|
+
return process;
|
|
85
|
+
}
|
|
86
|
+
} else {
|
|
87
|
+
const $module = originalRequire?.(id);
|
|
88
|
+
if ($module) {
|
|
89
|
+
return extractDefault($module);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Empty object is returned instead.`);
|
|
93
|
+
return {};
|
|
94
|
+
}
|
|
95
|
+
})();
|
|
96
|
+
|
|
97
|
+
"use strict";
|
|
98
|
+
var __defProp = Object.defineProperty;
|
|
99
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
100
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
101
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
102
|
+
var __export = (target, all) => {
|
|
103
|
+
for (var name in all)
|
|
104
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
105
|
+
};
|
|
106
|
+
var __copyProps = (to, from, except, desc) => {
|
|
107
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
108
|
+
for (let key of __getOwnPropNames(from))
|
|
109
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
110
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
111
|
+
}
|
|
112
|
+
return to;
|
|
113
|
+
};
|
|
114
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
115
|
+
var broken_link_candidates_exports = {};
|
|
116
|
+
__export(broken_link_candidates_exports, {
|
|
117
|
+
BrokenLinkCandidateFinder: () => BrokenLinkCandidateFinder,
|
|
118
|
+
BrokenLinkEvidenceKind: () => BrokenLinkEvidenceKind,
|
|
119
|
+
getParentPath: () => getParentPath,
|
|
120
|
+
getPathMapping: () => getPathMapping
|
|
121
|
+
});
|
|
122
|
+
module.exports = __toCommonJS(broken_link_candidates_exports);
|
|
123
|
+
var import_type_guards = require('@mnaoumov/typescript-lib/type-guards');
|
|
124
|
+
var BrokenLinkEvidenceKind = /* @__PURE__ */ ((BrokenLinkEvidenceKind2) => {
|
|
125
|
+
BrokenLinkEvidenceKind2["Alias"] = "Alias";
|
|
126
|
+
BrokenLinkEvidenceKind2["CaseChange"] = "CaseChange";
|
|
127
|
+
BrokenLinkEvidenceKind2["GitRename"] = "GitRename";
|
|
128
|
+
BrokenLinkEvidenceKind2["RenamedFolder"] = "RenamedFolder";
|
|
129
|
+
BrokenLinkEvidenceKind2["SameName"] = "SameName";
|
|
130
|
+
BrokenLinkEvidenceKind2["Title"] = "Title";
|
|
131
|
+
return BrokenLinkEvidenceKind2;
|
|
132
|
+
})(BrokenLinkEvidenceKind || {});
|
|
133
|
+
const FOLDER_NOTE_MIN_SUFFIX_LENGTH = 2;
|
|
134
|
+
const EVIDENCE_KIND_ORDER = [
|
|
135
|
+
"GitRename" /* GitRename */,
|
|
136
|
+
"CaseChange" /* CaseChange */,
|
|
137
|
+
"Alias" /* Alias */,
|
|
138
|
+
"Title" /* Title */,
|
|
139
|
+
"RenamedFolder" /* RenamedFolder */,
|
|
140
|
+
"SameName" /* SameName */
|
|
141
|
+
];
|
|
142
|
+
class BrokenLinkCandidateFinder {
|
|
143
|
+
aliasesByPath;
|
|
144
|
+
childFoldersByFolder = /* @__PURE__ */ new Map();
|
|
145
|
+
filePathSet;
|
|
146
|
+
filesByLowerCasePath = /* @__PURE__ */ new Map();
|
|
147
|
+
filesByName = /* @__PURE__ */ new Map();
|
|
148
|
+
folderNoteFileNames;
|
|
149
|
+
folderPaths = /* @__PURE__ */ new Set([""]);
|
|
150
|
+
gitRenames;
|
|
151
|
+
titlesByPath;
|
|
152
|
+
/**
|
|
153
|
+
* Indexes the vault snapshot.
|
|
154
|
+
*
|
|
155
|
+
* @param params - The snapshot.
|
|
156
|
+
*/
|
|
157
|
+
constructor(params) {
|
|
158
|
+
this.aliasesByPath = params.aliasesByPath;
|
|
159
|
+
this.filePathSet = new Set(params.filePaths);
|
|
160
|
+
this.folderNoteFileNames = new Set(params.folderNoteFileNames);
|
|
161
|
+
this.gitRenames = params.gitRenames;
|
|
162
|
+
this.titlesByPath = params.titlesByPath;
|
|
163
|
+
for (const filePath of params.filePaths) {
|
|
164
|
+
addToMultiMap(this.filesByName, getName(filePath), filePath);
|
|
165
|
+
addToMultiMap(this.filesByLowerCasePath, filePath.toLowerCase(), filePath);
|
|
166
|
+
let folder = getParentPath(filePath);
|
|
167
|
+
while (!this.folderPaths.has(folder)) {
|
|
168
|
+
this.folderPaths.add(folder);
|
|
169
|
+
addToMultiMap(this.childFoldersByFolder, getParentPath(folder), folder);
|
|
170
|
+
folder = getParentPath(folder);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Finds the candidates for every missing path at once.
|
|
176
|
+
*
|
|
177
|
+
* All at once because one kind of evidence is collective: a renamed folder is recognized by every missing
|
|
178
|
+
* target that was under it turning up together under one sibling folder.
|
|
179
|
+
*
|
|
180
|
+
* @param missingPaths - The vault paths that links lead to and no file holds.
|
|
181
|
+
* @returns The candidates for each missing path, strongest first; an empty list when nothing is known.
|
|
182
|
+
*/
|
|
183
|
+
findAll(missingPaths) {
|
|
184
|
+
const uniqueMissingPaths = new Set(missingPaths);
|
|
185
|
+
const missingSubtrees = this.getMissingSubtrees(uniqueMissingPaths);
|
|
186
|
+
const result = /* @__PURE__ */ new Map();
|
|
187
|
+
for (const missingPath of uniqueMissingPaths) {
|
|
188
|
+
let add2 = function(path, kind, description) {
|
|
189
|
+
addToMultiMap(evidenceByPath, path, { description, kind });
|
|
190
|
+
};
|
|
191
|
+
var add = add2;
|
|
192
|
+
const evidenceByPath = /* @__PURE__ */ new Map();
|
|
193
|
+
this.addGitRenameCandidate(missingPath, add2);
|
|
194
|
+
this.addCaseChangeCandidates(missingPath, add2);
|
|
195
|
+
this.addAliasAndTitleCandidates(missingPath, add2);
|
|
196
|
+
this.addRenamedFolderCandidates(missingPath, missingSubtrees, add2);
|
|
197
|
+
this.addSameNameCandidates(missingPath, add2);
|
|
198
|
+
result.set(missingPath, sortCandidates(evidenceByPath));
|
|
199
|
+
}
|
|
200
|
+
return result;
|
|
201
|
+
}
|
|
202
|
+
addAliasAndTitleCandidates(missingPath, add) {
|
|
203
|
+
const name = getName(missingPath);
|
|
204
|
+
const isFolderNote = this.folderNoteFileNames.has(name);
|
|
205
|
+
let oldName;
|
|
206
|
+
if (isFolderNote) {
|
|
207
|
+
oldName = getName(getParentPath(missingPath));
|
|
208
|
+
if (!oldName) {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
} else if (name.toLowerCase().endsWith(".md")) {
|
|
212
|
+
oldName = name.slice(0, -".md".length);
|
|
213
|
+
} else {
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
const lowerCaseOldName = oldName.toLowerCase();
|
|
217
|
+
const isEligible = (path) => this.filePathSet.has(path) && (!isFolderNote || getName(path) === name);
|
|
218
|
+
for (const [path, aliases] of this.aliasesByPath) {
|
|
219
|
+
if (isEligible(path) && aliases.some((alias) => alias.toLowerCase() === lowerCaseOldName)) {
|
|
220
|
+
add(path, "Alias" /* Alias */, `Its aliases hold the old name "${oldName}".`);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
for (const [path, title] of this.titlesByPath) {
|
|
224
|
+
if (isEligible(path) && title.toLowerCase() === lowerCaseOldName) {
|
|
225
|
+
add(path, "Title" /* Title */, `Its title is the old name "${oldName}".`);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
addCaseChangeCandidates(missingPath, add) {
|
|
230
|
+
for (const path of this.filesByLowerCasePath.get(missingPath.toLowerCase()) ?? []) {
|
|
231
|
+
add(path, "CaseChange" /* CaseChange */, "Only the letter case of its path differs.");
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
addGitRenameCandidate(missingPath, add) {
|
|
235
|
+
const gitRename = this.gitRenames.get(missingPath);
|
|
236
|
+
if (gitRename && this.filePathSet.has(gitRename.newPath)) {
|
|
237
|
+
add(gitRename.newPath, "GitRename" /* GitRename */, `Git history records the rename, in commit ${gitRename.commit}.`);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
addRenamedFolderCandidates(missingPath, missingSubtrees, add) {
|
|
241
|
+
const missingSubtree = missingSubtrees.get(missingPath);
|
|
242
|
+
if (!missingSubtree) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
const parentPath = getParentPath(missingSubtree.root);
|
|
246
|
+
const remainder = getRelativePath(missingSubtree.root, missingPath);
|
|
247
|
+
for (const siblingFolder of this.childFoldersByFolder.get(parentPath) ?? []) {
|
|
248
|
+
const isSubtreeIntact = [...missingSubtree.remainders].every((path) => this.filePathSet.has(joinPath(siblingFolder, path)));
|
|
249
|
+
if (!isSubtreeIntact) {
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
const fileCount = missingSubtree.remainders.size;
|
|
253
|
+
add(
|
|
254
|
+
joinPath(siblingFolder, remainder),
|
|
255
|
+
"RenamedFolder" /* RenamedFolder */,
|
|
256
|
+
`The folder "${missingSubtree.root}" is gone, and its sibling "${siblingFolder}" holds ${fileCount === 1 ? "the missing file that was" : `all ${String(fileCount)} missing files that were`} under it.`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
addSameNameCandidates(missingPath, add) {
|
|
261
|
+
const name = getName(missingPath);
|
|
262
|
+
const minSuffixLength = this.folderNoteFileNames.has(name) ? FOLDER_NOTE_MIN_SUFFIX_LENGTH : 1;
|
|
263
|
+
const missingSegments = missingPath.split("/");
|
|
264
|
+
let bestSuffixLength = minSuffixLength;
|
|
265
|
+
let bestPaths = [];
|
|
266
|
+
for (const path of this.filesByName.get(name) ?? []) {
|
|
267
|
+
const suffixLength = getCommonSuffixLength(missingSegments, path.split("/"));
|
|
268
|
+
if (suffixLength > bestSuffixLength) {
|
|
269
|
+
bestSuffixLength = suffixLength;
|
|
270
|
+
bestPaths = [path];
|
|
271
|
+
} else if (suffixLength === bestSuffixLength) {
|
|
272
|
+
bestPaths.push(path);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
const suffix = missingSegments.slice(-bestSuffixLength).join("/");
|
|
276
|
+
for (const path of bestPaths) {
|
|
277
|
+
add(path, "SameName" /* SameName */, `It has the same name, "${suffix}", in another folder.`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Groups the missing paths by the highest missing folder above each, the root of a subtree that may have been
|
|
282
|
+
* renamed as a whole.
|
|
283
|
+
*
|
|
284
|
+
* @param missingPaths - The missing paths.
|
|
285
|
+
* @returns Each missing path's subtree; a path whose own folder exists has none.
|
|
286
|
+
*/
|
|
287
|
+
getMissingSubtrees(missingPaths) {
|
|
288
|
+
const subtreesByRoot = /* @__PURE__ */ new Map();
|
|
289
|
+
const result = /* @__PURE__ */ new Map();
|
|
290
|
+
for (const missingPath of missingPaths) {
|
|
291
|
+
let root = getParentPath(missingPath);
|
|
292
|
+
if (this.folderPaths.has(root)) {
|
|
293
|
+
continue;
|
|
294
|
+
}
|
|
295
|
+
while (!this.folderPaths.has(getParentPath(root))) {
|
|
296
|
+
root = getParentPath(root);
|
|
297
|
+
}
|
|
298
|
+
let missingSubtree = subtreesByRoot.get(root);
|
|
299
|
+
if (!missingSubtree) {
|
|
300
|
+
missingSubtree = { remainders: /* @__PURE__ */ new Set(), root };
|
|
301
|
+
subtreesByRoot.set(root, missingSubtree);
|
|
302
|
+
}
|
|
303
|
+
missingSubtree.remainders.add(getRelativePath(root, missingPath));
|
|
304
|
+
result.set(missingPath, missingSubtree);
|
|
305
|
+
}
|
|
306
|
+
return result;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
function getParentPath(path) {
|
|
310
|
+
const index = path.lastIndexOf("/");
|
|
311
|
+
return index === -1 ? "" : path.slice(0, index);
|
|
312
|
+
}
|
|
313
|
+
function getPathMapping(oldPath, newPath) {
|
|
314
|
+
const oldSegments = oldPath.split("/");
|
|
315
|
+
const newSegments = newPath.split("/");
|
|
316
|
+
const suffixLength = getCommonSuffixLength(oldSegments, newSegments);
|
|
317
|
+
return {
|
|
318
|
+
newPrefix: newSegments.slice(0, newSegments.length - suffixLength).join("/"),
|
|
319
|
+
oldPrefix: oldSegments.slice(0, oldSegments.length - suffixLength).join("/")
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function addToMultiMap(map, key, value) {
|
|
323
|
+
let values = map.get(key);
|
|
324
|
+
if (!values) {
|
|
325
|
+
values = [];
|
|
326
|
+
map.set(key, values);
|
|
327
|
+
}
|
|
328
|
+
values.push(value);
|
|
329
|
+
}
|
|
330
|
+
function getCommonSuffixLength(segments1, segments2) {
|
|
331
|
+
let length = 0;
|
|
332
|
+
while (length < segments1.length && length < segments2.length && segments1.at(-length - 1) === segments2.at(-length - 1)) {
|
|
333
|
+
length++;
|
|
334
|
+
}
|
|
335
|
+
return length;
|
|
336
|
+
}
|
|
337
|
+
function getEvidenceRank(evidence) {
|
|
338
|
+
return EVIDENCE_KIND_ORDER.indexOf(evidence.kind);
|
|
339
|
+
}
|
|
340
|
+
function getName(path) {
|
|
341
|
+
return path.slice(path.lastIndexOf("/") + 1);
|
|
342
|
+
}
|
|
343
|
+
function getRelativePath(folder, path) {
|
|
344
|
+
return path.slice(folder.length + 1);
|
|
345
|
+
}
|
|
346
|
+
function joinPath(folder, path) {
|
|
347
|
+
return `${folder}/${path}`;
|
|
348
|
+
}
|
|
349
|
+
function sortCandidates(evidenceByPath) {
|
|
350
|
+
const candidates = [...evidenceByPath].map(([path, evidence]) => ({
|
|
351
|
+
evidence: evidence.sort((evidence1, evidence2) => getEvidenceRank(evidence1) - getEvidenceRank(evidence2)),
|
|
352
|
+
path
|
|
353
|
+
}));
|
|
354
|
+
return candidates.sort((candidate1, candidate2) => {
|
|
355
|
+
const rankDifference = getEvidenceRank((0, import_type_guards.ensureNonNullable)(candidate1.evidence[0])) - getEvidenceRank((0, import_type_guards.ensureNonNullable)(candidate2.evidence[0]));
|
|
356
|
+
return rankDifference || candidate1.path.localeCompare(candidate2.path);
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
360
|
+
0 && (module.exports = {
|
|
361
|
+
BrokenLinkCandidateFinder,
|
|
362
|
+
BrokenLinkEvidenceKind,
|
|
363
|
+
getParentPath,
|
|
364
|
+
getPathMapping
|
|
365
|
+
});
|
|
366
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9icm9rZW4tbGluay1jYW5kaWRhdGVzLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogQGZpbGVcbiAqXG4gKiBXaGVyZSBkaWQgYSBtaXNzaW5nIGxpbmsgdGFyZ2V0IGdvPyBQdXJlLCBubyBgQXBwYDogZXZlcnkgcXVlc3Rpb24gYWJvdXQgd2hpY2ggZmlsZSBhIGJyb2tlbiBsaW5rIG1vc3QgbGlrZWx5XG4gKiBtZWFudCBpcyBhbnN3ZXJhYmxlIGZyb20gYSBsaXN0IG9mIHBhdGhzLCB0aGUgbm90ZXMnIGFsaWFzZXMgYW5kIHRpdGxlcywgYW5kIHRoZSB2YXVsdCdzIGdpdCByZW5hbWVzLlxuICpcbiAqIEEgcmVuYW1lIGlzIG5vdCByZWNvdmVyYWJsZSBmcm9tIHRoZSBsaW5rIGFsb25lOiBhIGxpbmsgdG8gYGFscGhhL2JyYXZvL2NoYXJsaWUvIS5tZGAgc2F5cyBub3RoaW5nIGFib3V0XG4gKiBgY2hhcmxpZWAgaGF2aW5nIGJlY29tZSBgZGVsdGFgLiBTbyBldmVyeSBjYW5kaWRhdGUgY2FycmllcyB0aGUgZXZpZGVuY2UgdGhhdCBwcm9kdWNlZCBpdCwgZnJvbSBvdXRzaWRlIHRoZVxuICogbGluaywgYW5kIHRoZSBmaW5kZXIgbmV2ZXIgcGlja3Mgb25lIG9mIHNldmVyYWw6IGEgY2FsbGVyIG9mZmVycyBhIG9uZS1jbGljayBmaXggb25seSB3aGVuIGV4YWN0bHkgb25lXG4gKiBjYW5kaWRhdGUgZXhpc3RzLlxuICovXG5cbmltcG9ydCB7IGVuc3VyZU5vbk51bGxhYmxlIH0gZnJvbSAnQG1uYW91bW92L3R5cGVzY3JpcHQtbGliL3R5cGUtZ3VhcmRzJztcblxuLyoqXG4gKiBUaGUga2luZCBvZiBldmlkZW5jZSB0aGF0IG1ha2VzIGEgZmlsZSBhIGNhbmRpZGF0ZSBmb3IgYSBtaXNzaW5nIGxpbmsgdGFyZ2V0LlxuICpcbiAqIENhbmRpZGF0ZXMgbGlzdCBldmlkZW5jZSBzdHJvbmdlc3QgZmlyc3QsIGluIEVWSURFTkNFX0tJTkRfT1JERVIgYmVsb3cuXG4gKi9cbmV4cG9ydCBlbnVtIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQge1xuICAvKipcbiAgICogVGhlIGNhbmRpZGF0ZSdzIGBhbGlhc2VzYCBob2xkIHRoZSBtaXNzaW5nIHRhcmdldCdzIG9sZCBuYW1lLlxuICAgKi9cbiAgQWxpYXMgPSAnQWxpYXMnLFxuXG4gIC8qKlxuICAgKiBUaGUgY2FuZGlkYXRlJ3MgcGF0aCBkaWZmZXJzIGZyb20gdGhlIG1pc3Npbmcgb25lIG9ubHkgaW4gbGV0dGVyIGNhc2UuXG4gICAqL1xuICBDYXNlQ2hhbmdlID0gJ0Nhc2VDaGFuZ2UnLFxuXG4gIC8qKlxuICAgKiBUaGUgdmF1bHQncyBnaXQgaGlzdG9yeSByZWNvcmRzIHRoZSBtaXNzaW5nIHBhdGggYmVpbmcgcmVuYW1lZCB0byB0aGUgY2FuZGlkYXRlLlxuICAgKi9cbiAgR2l0UmVuYW1lID0gJ0dpdFJlbmFtZScsXG5cbiAgLyoqXG4gICAqIFRoZSBtaXNzaW5nIHRhcmdldCdzIGZvbGRlciBpcyBnb25lLCBhbmQgYSBzaWJsaW5nIGZvbGRlciBob2xkcyBldmVyeSBtaXNzaW5nIHRhcmdldCB0aGF0IHdhcyB1bmRlciBpdC5cbiAgICovXG4gIFJlbmFtZWRGb2xkZXIgPSAnUmVuYW1lZEZvbGRlcicsXG5cbiAgLyoqXG4gICAqIEEgZmlsZSB3aXRoIHRoZSBzYW1lIG5hbWUsIGFuZCB0aGUgbG9uZ2VzdCBydW4gb2YgdGhlIHNhbWUgcGFyZW50IGZvbGRlcnMsIHNpdHMgZWxzZXdoZXJlLlxuICAgKi9cbiAgU2FtZU5hbWUgPSAnU2FtZU5hbWUnLFxuXG4gIC8qKlxuICAgKiBUaGUgY2FuZGlkYXRlJ3MgYHRpdGxlYCBpcyB0aGUgbWlzc2luZyB0YXJnZXQncyBvbGQgbmFtZS5cbiAgICovXG4gIFRpdGxlID0gJ1RpdGxlJ1xufVxuXG4vKipcbiAqIEEgZm9sZGVyIG5vdGUncyBvd24gbmFtZSBpZGVudGlmaWVzIG5vdGhpbmcsIHNvIGEgc2FtZS1uYW1lIGNhbmRpZGF0ZSBtdXN0IHNoYXJlIGl0cyBmb2xkZXIncyBuYW1lIHRvby5cbiAqL1xuY29uc3QgRk9MREVSX05PVEVfTUlOX1NVRkZJWF9MRU5HVEggPSAyO1xuXG5jb25zdCBFVklERU5DRV9LSU5EX09SREVSOiByZWFkb25seSBCcm9rZW5MaW5rRXZpZGVuY2VLaW5kW10gPSBbXG4gIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQuR2l0UmVuYW1lLFxuICBCcm9rZW5MaW5rRXZpZGVuY2VLaW5kLkNhc2VDaGFuZ2UsXG4gIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQuQWxpYXMsXG4gIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQuVGl0bGUsXG4gIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQuUmVuYW1lZEZvbGRlcixcbiAgQnJva2VuTGlua0V2aWRlbmNlS2luZC5TYW1lTmFtZVxuXTtcblxuLyoqXG4gKiBPbmUgZmlsZSB0aGF0IGEgbWlzc2luZyBsaW5rIHRhcmdldCBtYXkgaGF2ZSBiZWNvbWUsIGFuZCB3aHkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJva2VuTGlua0NhbmRpZGF0ZSB7XG4gIC8qKlxuICAgKiBFdmVyeSByZWFzb24gdGhpcyBmaWxlIGlzIGEgY2FuZGlkYXRlLCBzdHJvbmdlc3QgZmlyc3QuXG4gICAqL1xuICByZWFkb25seSBldmlkZW5jZTogcmVhZG9ubHkgQnJva2VuTGlua0V2aWRlbmNlW107XG5cbiAgLyoqXG4gICAqIFRoZSBjYW5kaWRhdGUncyB2YXVsdCBwYXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgcGF0aDogc3RyaW5nO1xufVxuXG4vKipcbiAqIFRoZSBwYXJhbWV0ZXJzIGZvciB7QGxpbmsgQnJva2VuTGlua0NhbmRpZGF0ZUZpbmRlcn0uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgQnJva2VuTGlua0NhbmRpZGF0ZUZpbmRlckNvbnN0cnVjdG9yUGFyYW1zIHtcbiAgLyoqXG4gICAqIEVhY2ggbm90ZSdzIGBhbGlhc2VzYCwgYnkgbm90ZSBwYXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgYWxpYXNlc0J5UGF0aDogUmVhZG9ubHlNYXA8c3RyaW5nLCByZWFkb25seSBzdHJpbmdbXT47XG5cbiAgLyoqXG4gICAqIEV2ZXJ5IGZpbGUgaW4gdGhlIHZhdWx0LlxuICAgKi9cbiAgcmVhZG9ubHkgZmlsZVBhdGhzOiByZWFkb25seSBzdHJpbmdbXTtcblxuICAvKipcbiAgICogVGhlIGZpbGUgbmFtZXMgYSBmb2xkZXIgbm90ZSBpcyBzdG9yZWQgdW5kZXIsIHN1Y2ggYXMgYGluZGV4Lm1kYC4gU3VjaCBhIG5hbWUgc2F5cyBub3RoaW5nIGFib3V0IHdoaWNoXG4gICAqIG5vdGUgaXQgaXMsIHNvIGEgc2FtZS1uYW1lIGNhbmRpZGF0ZSBtdXN0IHNoYXJlIGl0cyBmb2xkZXIncyBuYW1lIHRvbywgYW5kIHRoZSBvbGQgbmFtZSBhbiBhbGlhcyBpc1xuICAgKiBtYXRjaGVkIGFnYWluc3QgaXMgdGhlIGZvbGRlcidzLlxuICAgKi9cbiAgcmVhZG9ubHkgZm9sZGVyTm90ZUZpbGVOYW1lczogcmVhZG9ubHkgc3RyaW5nW107XG5cbiAgLyoqXG4gICAqIFRoZSB2YXVsdCdzIGdpdCByZW5hbWVzOiBlYWNoIG9sZCB2YXVsdCBwYXRoIHRvIHRoZSBwYXRoIGl0IHdhcyByZW5hbWVkIHRvLCBjaGFpbnMgYWxyZWFkeSBmb2xsb3dlZC5cbiAgICovXG4gIHJlYWRvbmx5IGdpdFJlbmFtZXM6IFJlYWRvbmx5TWFwPHN0cmluZywgR2l0UmVuYW1lPjtcblxuICAvKipcbiAgICogRWFjaCBub3RlJ3MgYHRpdGxlYCwgYnkgbm90ZSBwYXRoLlxuICAgKi9cbiAgcmVhZG9ubHkgdGl0bGVzQnlQYXRoOiBSZWFkb25seU1hcDxzdHJpbmcsIHN0cmluZz47XG59XG5cbi8qKlxuICogT25lIHJlYXNvbiBhIGZpbGUgaXMgYSBjYW5kaWRhdGUgZm9yIGEgbWlzc2luZyBsaW5rIHRhcmdldC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBCcm9rZW5MaW5rRXZpZGVuY2Uge1xuICAvKipcbiAgICogQSBzZW50ZW5jZSBuYW1pbmcgdGhlIGV2aWRlbmNlLCBmb3IgdGhlIHVzZXIgdG8ganVkZ2UgaXQgYnkuXG4gICAqL1xuICByZWFkb25seSBkZXNjcmlwdGlvbjogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBUaGUga2luZCBvZiBldmlkZW5jZS5cbiAgICovXG4gIHJlYWRvbmx5IGtpbmQ6IEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQ7XG59XG5cbi8qKlxuICogQSByZW5hbWUgcmVjb3JkZWQgaW4gdGhlIHZhdWx0J3MgZ2l0IGhpc3RvcnkuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgR2l0UmVuYW1lIHtcbiAgLyoqXG4gICAqIFRoZSBhYmJyZXZpYXRlZCBoYXNoIG9mIHRoZSBjb21taXQgdGhhdCBtYWRlIHRoZSBsYXN0IHJlbmFtZSBvZiB0aGUgY2hhaW4uXG4gICAqL1xuICByZWFkb25seSBjb21taXQ6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIHZhdWx0IHBhdGggdGhlIGZpbGUgd2FzIGxhc3QgcmVuYW1lZCB0by5cbiAgICovXG4gIHJlYWRvbmx5IG5ld1BhdGg6IHN0cmluZztcbn1cblxuLyoqXG4gKiBUaGUgcGFydCBvZiBhIG1pc3NpbmcgcGF0aCB0aGF0IGEgY2FuZGlkYXRlIHJlcGxhY2VkOiB3aGF0IGEgXCJmaXggYWxsIGxpa2UgdGhpc1wiIGFwcGxpZXMgdG8gZXZlcnkgb3RoZXIgbGluay5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQYXRoTWFwcGluZyB7XG4gIC8qKlxuICAgKiBUaGUgcGFydCBvZiB0aGUgY2FuZGlkYXRlIHBhdGggdGhhdCByZXBsYWNlZCB7QGxpbmsgb2xkUHJlZml4fTsgYCcnYCBmb3IgdGhlIHZhdWx0IHJvb3QuXG4gICAqL1xuICByZWFkb25seSBuZXdQcmVmaXg6IHN0cmluZztcblxuICAvKipcbiAgICogVGhlIGxlYWRpbmcgcGFydCBvZiB0aGUgbWlzc2luZyBwYXRoIHRoYXQgbm8gbG9uZ2VyIGV4aXN0czsgYCcnYCBmb3IgdGhlIHZhdWx0IHJvb3QuXG4gICAqL1xuICByZWFkb25seSBvbGRQcmVmaXg6IHN0cmluZztcbn1cblxudHlwZSBFdmlkZW5jZUFkZGVyID0gKHBhdGg6IHN0cmluZywga2luZDogQnJva2VuTGlua0V2aWRlbmNlS2luZCwgZGVzY3JpcHRpb246IHN0cmluZykgPT4gdm9pZDtcblxuaW50ZXJmYWNlIE1pc3NpbmdTdWJ0cmVlIHtcbiAgLyoqXG4gICAqIEVhY2ggbWlzc2luZyBwYXRoIHVuZGVyIHRoZSBzdWJ0cmVlJ3Mgcm9vdCwgcmVsYXRpdmUgdG8gaXQuXG4gICAqL1xuICByZWFkb25seSByZW1haW5kZXJzOiBTZXQ8c3RyaW5nPjtcblxuICByZWFkb25seSByb290OiBzdHJpbmc7XG59XG5cbi8qKlxuICogRmluZHMgdGhlIGNhbmRpZGF0ZXMgZm9yIG1pc3NpbmcgbGluayB0YXJnZXRzLCBmcm9tIG9uZSBzbmFwc2hvdCBvZiB0aGUgdmF1bHQuXG4gKi9cbmV4cG9ydCBjbGFzcyBCcm9rZW5MaW5rQ2FuZGlkYXRlRmluZGVyIHtcbiAgcHJpdmF0ZSByZWFkb25seSBhbGlhc2VzQnlQYXRoOiBSZWFkb25seU1hcDxzdHJpbmcsIHJlYWRvbmx5IHN0cmluZ1tdPjtcbiAgcHJpdmF0ZSByZWFkb25seSBjaGlsZEZvbGRlcnNCeUZvbGRlciA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlUGF0aFNldDogUmVhZG9ubHlTZXQ8c3RyaW5nPjtcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlc0J5TG93ZXJDYXNlUGF0aCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBmaWxlc0J5TmFtZSA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmdbXT4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBmb2xkZXJOb3RlRmlsZU5hbWVzOiBSZWFkb25seVNldDxzdHJpbmc+O1xuICBwcml2YXRlIHJlYWRvbmx5IGZvbGRlclBhdGhzID0gbmV3IFNldDxzdHJpbmc+KFsnJ10pO1xuICBwcml2YXRlIHJlYWRvbmx5IGdpdFJlbmFtZXM6IFJlYWRvbmx5TWFwPHN0cmluZywgR2l0UmVuYW1lPjtcbiAgcHJpdmF0ZSByZWFkb25seSB0aXRsZXNCeVBhdGg6IFJlYWRvbmx5TWFwPHN0cmluZywgc3RyaW5nPjtcblxuICAvKipcbiAgICogSW5kZXhlcyB0aGUgdmF1bHQgc25hcHNob3QuXG4gICAqXG4gICAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgc25hcHNob3QuXG4gICAqL1xuICBwdWJsaWMgY29uc3RydWN0b3IocGFyYW1zOiBCcm9rZW5MaW5rQ2FuZGlkYXRlRmluZGVyQ29uc3RydWN0b3JQYXJhbXMpIHtcbiAgICB0aGlzLmFsaWFzZXNCeVBhdGggPSBwYXJhbXMuYWxpYXNlc0J5UGF0aDtcbiAgICB0aGlzLmZpbGVQYXRoU2V0ID0gbmV3IFNldChwYXJhbXMuZmlsZVBhdGhzKTtcbiAgICB0aGlzLmZvbGRlck5vdGVGaWxlTmFtZXMgPSBuZXcgU2V0KHBhcmFtcy5mb2xkZXJOb3RlRmlsZU5hbWVzKTtcbiAgICB0aGlzLmdpdFJlbmFtZXMgPSBwYXJhbXMuZ2l0UmVuYW1lcztcbiAgICB0aGlzLnRpdGxlc0J5UGF0aCA9IHBhcmFtcy50aXRsZXNCeVBhdGg7XG5cbiAgICBmb3IgKGNvbnN0IGZpbGVQYXRoIG9mIHBhcmFtcy5maWxlUGF0aHMpIHtcbiAgICAgIGFkZFRvTXVsdGlNYXAodGhpcy5maWxlc0J5TmFtZSwgZ2V0TmFtZShmaWxlUGF0aCksIGZpbGVQYXRoKTtcbiAgICAgIGFkZFRvTXVsdGlNYXAodGhpcy5maWxlc0J5TG93ZXJDYXNlUGF0aCwgZmlsZVBhdGgudG9Mb3dlckNhc2UoKSwgZmlsZVBhdGgpO1xuXG4gICAgICBsZXQgZm9sZGVyID0gZ2V0UGFyZW50UGF0aChmaWxlUGF0aCk7XG4gICAgICB3aGlsZSAoIXRoaXMuZm9sZGVyUGF0aHMuaGFzKGZvbGRlcikpIHtcbiAgICAgICAgdGhpcy5mb2xkZXJQYXRocy5hZGQoZm9sZGVyKTtcbiAgICAgICAgYWRkVG9NdWx0aU1hcCh0aGlzLmNoaWxkRm9sZGVyc0J5Rm9sZGVyLCBnZXRQYXJlbnRQYXRoKGZvbGRlciksIGZvbGRlcik7XG4gICAgICAgIGZvbGRlciA9IGdldFBhcmVudFBhdGgoZm9sZGVyKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogRmluZHMgdGhlIGNhbmRpZGF0ZXMgZm9yIGV2ZXJ5IG1pc3NpbmcgcGF0aCBhdCBvbmNlLlxuICAgKlxuICAgKiBBbGwgYXQgb25jZSBiZWNhdXNlIG9uZSBraW5kIG9mIGV2aWRlbmNlIGlzIGNvbGxlY3RpdmU6IGEgcmVuYW1lZCBmb2xkZXIgaXMgcmVjb2duaXplZCBieSBldmVyeSBtaXNzaW5nXG4gICAqIHRhcmdldCB0aGF0IHdhcyB1bmRlciBpdCB0dXJuaW5nIHVwIHRvZ2V0aGVyIHVuZGVyIG9uZSBzaWJsaW5nIGZvbGRlci5cbiAgICpcbiAgICogQHBhcmFtIG1pc3NpbmdQYXRocyAtIFRoZSB2YXVsdCBwYXRocyB0aGF0IGxpbmtzIGxlYWQgdG8gYW5kIG5vIGZpbGUgaG9sZHMuXG4gICAqIEByZXR1cm5zIFRoZSBjYW5kaWRhdGVzIGZvciBlYWNoIG1pc3NpbmcgcGF0aCwgc3Ryb25nZXN0IGZpcnN0OyBhbiBlbXB0eSBsaXN0IHdoZW4gbm90aGluZyBpcyBrbm93bi5cbiAgICovXG4gIHB1YmxpYyBmaW5kQWxsKG1pc3NpbmdQYXRoczogSXRlcmFibGU8c3RyaW5nPik6IE1hcDxzdHJpbmcsIEJyb2tlbkxpbmtDYW5kaWRhdGVbXT4ge1xuICAgIGNvbnN0IHVuaXF1ZU1pc3NpbmdQYXRocyA9IG5ldyBTZXQobWlzc2luZ1BhdGhzKTtcbiAgICBjb25zdCBtaXNzaW5nU3VidHJlZXMgPSB0aGlzLmdldE1pc3NpbmdTdWJ0cmVlcyh1bmlxdWVNaXNzaW5nUGF0aHMpO1xuICAgIGNvbnN0IHJlc3VsdCA9IG5ldyBNYXA8c3RyaW5nLCBCcm9rZW5MaW5rQ2FuZGlkYXRlW10+KCk7XG5cbiAgICBmb3IgKGNvbnN0IG1pc3NpbmdQYXRoIG9mIHVuaXF1ZU1pc3NpbmdQYXRocykge1xuICAgICAgY29uc3QgZXZpZGVuY2VCeVBhdGggPSBuZXcgTWFwPHN0cmluZywgQnJva2VuTGlua0V2aWRlbmNlW10+KCk7XG4gICAgICBmdW5jdGlvbiBhZGQocGF0aDogc3RyaW5nLCBraW5kOiBCcm9rZW5MaW5rRXZpZGVuY2VLaW5kLCBkZXNjcmlwdGlvbjogc3RyaW5nKTogdm9pZCB7XG4gICAgICAgIGFkZFRvTXVsdGlNYXAoZXZpZGVuY2VCeVBhdGgsIHBhdGgsIHsgZGVzY3JpcHRpb24sIGtpbmQgfSk7XG4gICAgICB9XG5cbiAgICAgIHRoaXMuYWRkR2l0UmVuYW1lQ2FuZGlkYXRlKG1pc3NpbmdQYXRoLCBhZGQpO1xuICAgICAgdGhpcy5hZGRDYXNlQ2hhbmdlQ2FuZGlkYXRlcyhtaXNzaW5nUGF0aCwgYWRkKTtcbiAgICAgIHRoaXMuYWRkQWxpYXNBbmRUaXRsZUNhbmRpZGF0ZXMobWlzc2luZ1BhdGgsIGFkZCk7XG4gICAgICB0aGlzLmFkZFJlbmFtZWRGb2xkZXJDYW5kaWRhdGVzKG1pc3NpbmdQYXRoLCBtaXNzaW5nU3VidHJlZXMsIGFkZCk7XG4gICAgICB0aGlzLmFkZFNhbWVOYW1lQ2FuZGlkYXRlcyhtaXNzaW5nUGF0aCwgYWRkKTtcblxuICAgICAgcmVzdWx0LnNldChtaXNzaW5nUGF0aCwgc29ydENhbmRpZGF0ZXMoZXZpZGVuY2VCeVBhdGgpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9XG5cbiAgcHJpdmF0ZSBhZGRBbGlhc0FuZFRpdGxlQ2FuZGlkYXRlcyhtaXNzaW5nUGF0aDogc3RyaW5nLCBhZGQ6IEV2aWRlbmNlQWRkZXIpOiB2b2lkIHtcbiAgICBjb25zdCBuYW1lID0gZ2V0TmFtZShtaXNzaW5nUGF0aCk7XG4gICAgY29uc3QgaXNGb2xkZXJOb3RlID0gdGhpcy5mb2xkZXJOb3RlRmlsZU5hbWVzLmhhcyhuYW1lKTtcbiAgICBsZXQgb2xkTmFtZTogc3RyaW5nO1xuXG4gICAgaWYgKGlzRm9sZGVyTm90ZSkge1xuICAgICAgb2xkTmFtZSA9IGdldE5hbWUoZ2V0UGFyZW50UGF0aChtaXNzaW5nUGF0aCkpO1xuICAgICAgaWYgKCFvbGROYW1lKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKG5hbWUudG9Mb3dlckNhc2UoKS5lbmRzV2l0aCgnLm1kJykpIHtcbiAgICAgIG9sZE5hbWUgPSBuYW1lLnNsaWNlKDAsIC0nLm1kJy5sZW5ndGgpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgbG93ZXJDYXNlT2xkTmFtZSA9IG9sZE5hbWUudG9Mb3dlckNhc2UoKTtcbiAgICBjb25zdCBpc0VsaWdpYmxlID0gKHBhdGg6IHN0cmluZyk6IGJvb2xlYW4gPT4gdGhpcy5maWxlUGF0aFNldC5oYXMocGF0aCkgJiYgKCFpc0ZvbGRlck5vdGUgfHwgZ2V0TmFtZShwYXRoKSA9PT0gbmFtZSk7XG5cbiAgICBmb3IgKGNvbnN0IFtwYXRoLCBhbGlhc2VzXSBvZiB0aGlzLmFsaWFzZXNCeVBhdGgpIHtcbiAgICAgIGlmIChpc0VsaWdpYmxlKHBhdGgpICYmIGFsaWFzZXMuc29tZSgoYWxpYXMpID0+IGFsaWFzLnRvTG93ZXJDYXNlKCkgPT09IGxvd2VyQ2FzZU9sZE5hbWUpKSB7XG4gICAgICAgIGFkZChwYXRoLCBCcm9rZW5MaW5rRXZpZGVuY2VLaW5kLkFsaWFzLCBgSXRzIGFsaWFzZXMgaG9sZCB0aGUgb2xkIG5hbWUgXCIke29sZE5hbWV9XCIuYCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBbcGF0aCwgdGl0bGVdIG9mIHRoaXMudGl0bGVzQnlQYXRoKSB7XG4gICAgICBpZiAoaXNFbGlnaWJsZShwYXRoKSAmJiB0aXRsZS50b0xvd2VyQ2FzZSgpID09PSBsb3dlckNhc2VPbGROYW1lKSB7XG4gICAgICAgIGFkZChwYXRoLCBCcm9rZW5MaW5rRXZpZGVuY2VLaW5kLlRpdGxlLCBgSXRzIHRpdGxlIGlzIHRoZSBvbGQgbmFtZSBcIiR7b2xkTmFtZX1cIi5gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZENhc2VDaGFuZ2VDYW5kaWRhdGVzKG1pc3NpbmdQYXRoOiBzdHJpbmcsIGFkZDogRXZpZGVuY2VBZGRlcik6IHZvaWQge1xuICAgIGZvciAoY29uc3QgcGF0aCBvZiB0aGlzLmZpbGVzQnlMb3dlckNhc2VQYXRoLmdldChtaXNzaW5nUGF0aC50b0xvd2VyQ2FzZSgpKSA/PyBbXSkge1xuICAgICAgYWRkKHBhdGgsIEJyb2tlbkxpbmtFdmlkZW5jZUtpbmQuQ2FzZUNoYW5nZSwgJ09ubHkgdGhlIGxldHRlciBjYXNlIG9mIGl0cyBwYXRoIGRpZmZlcnMuJyk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBhZGRHaXRSZW5hbWVDYW5kaWRhdGUobWlzc2luZ1BhdGg6IHN0cmluZywgYWRkOiBFdmlkZW5jZUFkZGVyKTogdm9pZCB7XG4gICAgY29uc3QgZ2l0UmVuYW1lID0gdGhpcy5naXRSZW5hbWVzLmdldChtaXNzaW5nUGF0aCk7XG4gICAgaWYgKGdpdFJlbmFtZSAmJiB0aGlzLmZpbGVQYXRoU2V0LmhhcyhnaXRSZW5hbWUubmV3UGF0aCkpIHtcbiAgICAgIGFkZChnaXRSZW5hbWUubmV3UGF0aCwgQnJva2VuTGlua0V2aWRlbmNlS2luZC5HaXRSZW5hbWUsIGBHaXQgaGlzdG9yeSByZWNvcmRzIHRoZSByZW5hbWUsIGluIGNvbW1pdCAke2dpdFJlbmFtZS5jb21taXR9LmApO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYWRkUmVuYW1lZEZvbGRlckNhbmRpZGF0ZXMobWlzc2luZ1BhdGg6IHN0cmluZywgbWlzc2luZ1N1YnRyZWVzOiBSZWFkb25seU1hcDxzdHJpbmcsIE1pc3NpbmdTdWJ0cmVlPiwgYWRkOiBFdmlkZW5jZUFkZGVyKTogdm9pZCB7XG4gICAgY29uc3QgbWlzc2luZ1N1YnRyZWUgPSBtaXNzaW5nU3VidHJlZXMuZ2V0KG1pc3NpbmdQYXRoKTtcbiAgICBpZiAoIW1pc3NpbmdTdWJ0cmVlKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcGFyZW50UGF0aCA9IGdldFBhcmVudFBhdGgobWlzc2luZ1N1YnRyZWUucm9vdCk7XG4gICAgY29uc3QgcmVtYWluZGVyID0gZ2V0UmVsYXRpdmVQYXRoKG1pc3NpbmdTdWJ0cmVlLnJvb3QsIG1pc3NpbmdQYXRoKTtcblxuICAgIGZvciAoY29uc3Qgc2libGluZ0ZvbGRlciBvZiB0aGlzLmNoaWxkRm9sZGVyc0J5Rm9sZGVyLmdldChwYXJlbnRQYXRoKSA/PyBbXSkge1xuICAgICAgY29uc3QgaXNTdWJ0cmVlSW50YWN0ID0gWy4uLm1pc3NpbmdTdWJ0cmVlLnJlbWFpbmRlcnNdLmV2ZXJ5KChwYXRoKSA9PiB0aGlzLmZpbGVQYXRoU2V0Lmhhcyhqb2luUGF0aChzaWJsaW5nRm9sZGVyLCBwYXRoKSkpO1xuICAgICAgaWYgKCFpc1N1YnRyZWVJbnRhY3QpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG5cbiAgICAgIGNvbnN0IGZpbGVDb3VudCA9IG1pc3NpbmdTdWJ0cmVlLnJlbWFpbmRlcnMuc2l6ZTtcbiAgICAgIGFkZChcbiAgICAgICAgam9pblBhdGgoc2libGluZ0ZvbGRlciwgcmVtYWluZGVyKSxcbiAgICAgICAgQnJva2VuTGlua0V2aWRlbmNlS2luZC5SZW5hbWVkRm9sZGVyLFxuICAgICAgICBgVGhlIGZvbGRlciBcIiR7bWlzc2luZ1N1YnRyZWUucm9vdH1cIiBpcyBnb25lLCBhbmQgaXRzIHNpYmxpbmcgXCIke3NpYmxpbmdGb2xkZXJ9XCIgaG9sZHMgJHtmaWxlQ291bnQgPT09IDEgPyAndGhlIG1pc3NpbmcgZmlsZSB0aGF0IHdhcycgOiBgYWxsICR7U3RyaW5nKGZpbGVDb3VudCl9IG1pc3NpbmcgZmlsZXMgdGhhdCB3ZXJlYH0gdW5kZXIgaXQuYFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIGFkZFNhbWVOYW1lQ2FuZGlkYXRlcyhtaXNzaW5nUGF0aDogc3RyaW5nLCBhZGQ6IEV2aWRlbmNlQWRkZXIpOiB2b2lkIHtcbiAgICBjb25zdCBuYW1lID0gZ2V0TmFtZShtaXNzaW5nUGF0aCk7XG4gICAgY29uc3QgbWluU3VmZml4TGVuZ3RoID0gdGhpcy5mb2xkZXJOb3RlRmlsZU5hbWVzLmhhcyhuYW1lKSA/IEZPTERFUl9OT1RFX01JTl9TVUZGSVhfTEVOR1RIIDogMTtcbiAgICBjb25zdCBtaXNzaW5nU2VnbWVudHMgPSBtaXNzaW5nUGF0aC5zcGxpdCgnLycpO1xuICAgIGxldCBiZXN0U3VmZml4TGVuZ3RoID0gbWluU3VmZml4TGVuZ3RoO1xuICAgIGxldCBiZXN0UGF0aHM6IHN0cmluZ1tdID0gW107XG5cbiAgICBmb3IgKGNvbnN0IHBhdGggb2YgdGhpcy5maWxlc0J5TmFtZS5nZXQobmFtZSkgPz8gW10pIHtcbiAgICAgIGNvbnN0IHN1ZmZpeExlbmd0aCA9IGdldENvbW1vblN1ZmZpeExlbmd0aChtaXNzaW5nU2VnbWVudHMsIHBhdGguc3BsaXQoJy8nKSk7XG4gICAgICBpZiAoc3VmZml4TGVuZ3RoID4gYmVzdFN1ZmZpeExlbmd0aCkge1xuICAgICAgICBiZXN0U3VmZml4TGVuZ3RoID0gc3VmZml4TGVuZ3RoO1xuICAgICAgICBiZXN0UGF0aHMgPSBbcGF0aF07XG4gICAgICB9IGVsc2UgaWYgKHN1ZmZpeExlbmd0aCA9PT0gYmVzdFN1ZmZpeExlbmd0aCkge1xuICAgICAgICBiZXN0UGF0aHMucHVzaChwYXRoKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBjb25zdCBzdWZmaXggPSBtaXNzaW5nU2VnbWVudHMuc2xpY2UoLWJlc3RTdWZmaXhMZW5ndGgpLmpvaW4oJy8nKTtcbiAgICBmb3IgKGNvbnN0IHBhdGggb2YgYmVzdFBhdGhzKSB7XG4gICAgICBhZGQocGF0aCwgQnJva2VuTGlua0V2aWRlbmNlS2luZC5TYW1lTmFtZSwgYEl0IGhhcyB0aGUgc2FtZSBuYW1lLCBcIiR7c3VmZml4fVwiLCBpbiBhbm90aGVyIGZvbGRlci5gKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR3JvdXBzIHRoZSBtaXNzaW5nIHBhdGhzIGJ5IHRoZSBoaWdoZXN0IG1pc3NpbmcgZm9sZGVyIGFib3ZlIGVhY2gsIHRoZSByb290IG9mIGEgc3VidHJlZSB0aGF0IG1heSBoYXZlIGJlZW5cbiAgICogcmVuYW1lZCBhcyBhIHdob2xlLlxuICAgKlxuICAgKiBAcGFyYW0gbWlzc2luZ1BhdGhzIC0gVGhlIG1pc3NpbmcgcGF0aHMuXG4gICAqIEByZXR1cm5zIEVhY2ggbWlzc2luZyBwYXRoJ3Mgc3VidHJlZTsgYSBwYXRoIHdob3NlIG93biBmb2xkZXIgZXhpc3RzIGhhcyBub25lLlxuICAgKi9cbiAgcHJpdmF0ZSBnZXRNaXNzaW5nU3VidHJlZXMobWlzc2luZ1BhdGhzOiBSZWFkb25seVNldDxzdHJpbmc+KTogTWFwPHN0cmluZywgTWlzc2luZ1N1YnRyZWU+IHtcbiAgICBjb25zdCBzdWJ0cmVlc0J5Um9vdCA9IG5ldyBNYXA8c3RyaW5nLCBNaXNzaW5nU3VidHJlZT4oKTtcbiAgICBjb25zdCByZXN1bHQgPSBuZXcgTWFwPHN0cmluZywgTWlzc2luZ1N1YnRyZWU+KCk7XG5cbiAgICBmb3IgKGNvbnN0IG1pc3NpbmdQYXRoIG9mIG1pc3NpbmdQYXRocykge1xuICAgICAgbGV0IHJvb3QgPSBnZXRQYXJlbnRQYXRoKG1pc3NpbmdQYXRoKTtcbiAgICAgIGlmICh0aGlzLmZvbGRlclBhdGhzLmhhcyhyb290KSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgd2hpbGUgKCF0aGlzLmZvbGRlclBhdGhzLmhhcyhnZXRQYXJlbnRQYXRoKHJvb3QpKSkge1xuICAgICAgICByb290ID0gZ2V0UGFyZW50UGF0aChyb290KTtcbiAgICAgIH1cblxuICAgICAgbGV0IG1pc3NpbmdTdWJ0cmVlID0gc3VidHJlZXNCeVJvb3QuZ2V0KHJvb3QpO1xuICAgICAgaWYgKCFtaXNzaW5nU3VidHJlZSkge1xuICAgICAgICBtaXNzaW5nU3VidHJlZSA9IHsgcmVtYWluZGVyczogbmV3IFNldCgpLCByb290IH07XG4gICAgICAgIHN1YnRyZWVzQnlSb290LnNldChyb290LCBtaXNzaW5nU3VidHJlZSk7XG4gICAgICB9XG5cbiAgICAgIG1pc3NpbmdTdWJ0cmVlLnJlbWFpbmRlcnMuYWRkKGdldFJlbGF0aXZlUGF0aChyb290LCBtaXNzaW5nUGF0aCkpO1xuICAgICAgcmVzdWx0LnNldChtaXNzaW5nUGF0aCwgbWlzc2luZ1N1YnRyZWUpO1xuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn1cblxuLyoqXG4gKiBUaGUgcGFyZW50IGZvbGRlciBvZiBhIHZhdWx0IHBhdGguXG4gKlxuICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aC5cbiAqIEByZXR1cm5zIFRoZSBwYXJlbnQgZm9sZGVyOyBgJydgIGZvciB0aGUgdmF1bHQgcm9vdC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBhcmVudFBhdGgocGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgaW5kZXggPSBwYXRoLmxhc3RJbmRleE9mKCcvJyk7XG4gIHJldHVybiBpbmRleCA9PT0gLTEgPyAnJyA6IHBhdGguc2xpY2UoMCwgaW5kZXgpO1xufVxuXG4vKipcbiAqIFRoZSBwYXJ0IG9mIGEgbWlzc2luZyBwYXRoIHRoYXQgYSBjYW5kaWRhdGUgcGF0aCByZXBsYWNlZCwgZm91bmQgYnkgZHJvcHBpbmcgdGhlIHBhdGggc2VnbWVudHMgdGhleSBlbmQgd2l0aFxuICogaW4gY29tbW9uLlxuICpcbiAqIEBwYXJhbSBvbGRQYXRoIC0gVGhlIG1pc3NpbmcgcGF0aC5cbiAqIEBwYXJhbSBuZXdQYXRoIC0gVGhlIGNhbmRpZGF0ZSBwYXRoLlxuICogQHJldHVybnMgVGhlIHByZWZpeGVzIHRoYXQgZGlmZmVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UGF0aE1hcHBpbmcob2xkUGF0aDogc3RyaW5nLCBuZXdQYXRoOiBzdHJpbmcpOiBQYXRoTWFwcGluZyB7XG4gIGNvbnN0IG9sZFNlZ21lbnRzID0gb2xkUGF0aC5zcGxpdCgnLycpO1xuICBjb25zdCBuZXdTZWdtZW50cyA9IG5ld1BhdGguc3BsaXQoJy8nKTtcbiAgY29uc3Qgc3VmZml4TGVuZ3RoID0gZ2V0Q29tbW9uU3VmZml4TGVuZ3RoKG9sZFNlZ21lbnRzLCBuZXdTZWdtZW50cyk7XG4gIHJldHVybiB7XG4gICAgbmV3UHJlZml4OiBuZXdTZWdtZW50cy5zbGljZSgwLCBuZXdTZWdtZW50cy5sZW5ndGggLSBzdWZmaXhMZW5ndGgpLmpvaW4oJy8nKSxcbiAgICBvbGRQcmVmaXg6IG9sZFNlZ21lbnRzLnNsaWNlKDAsIG9sZFNlZ21lbnRzLmxlbmd0aCAtIHN1ZmZpeExlbmd0aCkuam9pbignLycpXG4gIH07XG59XG5cbmZ1bmN0aW9uIGFkZFRvTXVsdGlNYXA8S2V5LCBWYWx1ZT4obWFwOiBNYXA8S2V5LCBWYWx1ZVtdPiwga2V5OiBLZXksIHZhbHVlOiBWYWx1ZSk6IHZvaWQge1xuICBsZXQgdmFsdWVzID0gbWFwLmdldChrZXkpO1xuICBpZiAoIXZhbHVlcykge1xuICAgIHZhbHVlcyA9IFtdO1xuICAgIG1hcC5zZXQoa2V5LCB2YWx1ZXMpO1xuICB9XG4gIHZhbHVlcy5wdXNoKHZhbHVlKTtcbn1cblxuZnVuY3Rpb24gZ2V0Q29tbW9uU3VmZml4TGVuZ3RoKHNlZ21lbnRzMTogcmVhZG9ubHkgc3RyaW5nW10sIHNlZ21lbnRzMjogcmVhZG9ubHkgc3RyaW5nW10pOiBudW1iZXIge1xuICBsZXQgbGVuZ3RoID0gMDtcbiAgd2hpbGUgKGxlbmd0aCA8IHNlZ21lbnRzMS5sZW5ndGggJiYgbGVuZ3RoIDwgc2VnbWVudHMyLmxlbmd0aCAmJiBzZWdtZW50czEuYXQoLWxlbmd0aCAtIDEpID09PSBzZWdtZW50czIuYXQoLWxlbmd0aCAtIDEpKSB7XG4gICAgbGVuZ3RoKys7XG4gIH1cbiAgcmV0dXJuIGxlbmd0aDtcbn1cblxuZnVuY3Rpb24gZ2V0RXZpZGVuY2VSYW5rKGV2aWRlbmNlOiBCcm9rZW5MaW5rRXZpZGVuY2UpOiBudW1iZXIge1xuICByZXR1cm4gRVZJREVOQ0VfS0lORF9PUkRFUi5pbmRleE9mKGV2aWRlbmNlLmtpbmQpO1xufVxuXG5mdW5jdGlvbiBnZXROYW1lKHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoLnNsaWNlKHBhdGgubGFzdEluZGV4T2YoJy8nKSArIDEpO1xufVxuXG4vLyBUaGUgZm9sZGVyIGlzIG5ldmVyIHRoZSB2YXVsdCByb290IGhlcmU6IGEgbWlzc2luZyBzdWJ0cmVlJ3Mgcm9vdCBpcyBhIG1pc3NpbmcgZm9sZGVyLCBhbmQgaXRzIHNpYmxpbmdzIGFyZVxuLy8gZm9sZGVycyB0b28uXG5mdW5jdGlvbiBnZXRSZWxhdGl2ZVBhdGgoZm9sZGVyOiBzdHJpbmcsIHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBwYXRoLnNsaWNlKGZvbGRlci5sZW5ndGggKyAxKTtcbn1cblxuZnVuY3Rpb24gam9pblBhdGgoZm9sZGVyOiBzdHJpbmcsIHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBgJHtmb2xkZXJ9LyR7cGF0aH1gO1xufVxuXG5mdW5jdGlvbiBzb3J0Q2FuZGlkYXRlcyhldmlkZW5jZUJ5UGF0aDogUmVhZG9ubHlNYXA8c3RyaW5nLCBCcm9rZW5MaW5rRXZpZGVuY2VbXT4pOiBCcm9rZW5MaW5rQ2FuZGlkYXRlW10ge1xuICBjb25zdCBjYW5kaWRhdGVzID0gWy4uLmV2aWRlbmNlQnlQYXRoXS5tYXAoKFtwYXRoLCBldmlkZW5jZV0pID0+ICh7XG4gICAgZXZpZGVuY2U6IGV2aWRlbmNlLnNvcnQoKGV2aWRlbmNlMSwgZXZpZGVuY2UyKSA9PiBnZXRFdmlkZW5jZVJhbmsoZXZpZGVuY2UxKSAtIGdldEV2aWRlbmNlUmFuayhldmlkZW5jZTIpKSxcbiAgICBwYXRoXG4gIH0pKTtcblxuICByZXR1cm4gY2FuZGlkYXRlcy5zb3J0KChjYW5kaWRhdGUxLCBjYW5kaWRhdGUyKSA9PiB7XG4gICAgY29uc3QgcmFua0RpZmZlcmVuY2UgPSBnZXRFdmlkZW5jZVJhbmsoZW5zdXJlTm9uTnVsbGFibGUoY2FuZGlkYXRlMS5ldmlkZW5jZVswXSkpIC0gZ2V0RXZpZGVuY2VSYW5rKGVuc3VyZU5vbk51bGxhYmxlKGNhbmRpZGF0ZTIuZXZpZGVuY2VbMF0pKTtcbiAgICByZXR1cm4gcmFua0RpZmZlcmVuY2UgfHwgY2FuZGlkYXRlMS5wYXRoLmxvY2FsZUNvbXBhcmUoY2FuZGlkYXRlMi5wYXRoKTtcbiAgfSk7XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFZQSx5QkFBa0M7QUFPM0IsSUFBSyx5QkFBTCxrQkFBS0EsNEJBQUw7QUFJTCxFQUFBQSx3QkFBQSxXQUFRO0FBS1IsRUFBQUEsd0JBQUEsZ0JBQWE7QUFLYixFQUFBQSx3QkFBQSxlQUFZO0FBS1osRUFBQUEsd0JBQUEsbUJBQWdCO0FBS2hCLEVBQUFBLHdCQUFBLGNBQVc7QUFLWCxFQUFBQSx3QkFBQSxXQUFRO0FBN0JFLFNBQUFBO0FBQUEsR0FBQTtBQW1DWixNQUFNLGdDQUFnQztBQUV0QyxNQUFNLHNCQUF5RDtBQUFBLEVBQzdEO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFDRjtBQTRHTyxNQUFNLDBCQUEwQjtBQUFBLEVBQ3BCO0FBQUEsRUFDQSx1QkFBdUIsb0JBQUksSUFBc0I7QUFBQSxFQUNqRDtBQUFBLEVBQ0EsdUJBQXVCLG9CQUFJLElBQXNCO0FBQUEsRUFDakQsY0FBYyxvQkFBSSxJQUFzQjtBQUFBLEVBQ3hDO0FBQUEsRUFDQSxjQUFjLG9CQUFJLElBQVksQ0FBQyxFQUFFLENBQUM7QUFBQSxFQUNsQztBQUFBLEVBQ0E7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUEsRUFPVixZQUFZLFFBQW9EO0FBQ3JFLFNBQUssZ0JBQWdCLE9BQU87QUFDNUIsU0FBSyxjQUFjLElBQUksSUFBSSxPQUFPLFNBQVM7QUFDM0MsU0FBSyxzQkFBc0IsSUFBSSxJQUFJLE9BQU8sbUJBQW1CO0FBQzdELFNBQUssYUFBYSxPQUFPO0FBQ3pCLFNBQUssZUFBZSxPQUFPO0FBRTNCLGVBQVcsWUFBWSxPQUFPLFdBQVc7QUFDdkMsb0JBQWMsS0FBSyxhQUFhLFFBQVEsUUFBUSxHQUFHLFFBQVE7QUFDM0Qsb0JBQWMsS0FBSyxzQkFBc0IsU0FBUyxZQUFZLEdBQUcsUUFBUTtBQUV6RSxVQUFJLFNBQVMsY0FBYyxRQUFRO0FBQ25DLGFBQU8sQ0FBQyxLQUFLLFlBQVksSUFBSSxNQUFNLEdBQUc7QUFDcEMsYUFBSyxZQUFZLElBQUksTUFBTTtBQUMzQixzQkFBYyxLQUFLLHNCQUFzQixjQUFjLE1BQU0sR0FBRyxNQUFNO0FBQ3RFLGlCQUFTLGNBQWMsTUFBTTtBQUFBLE1BQy9CO0FBQUEsSUFDRjtBQUFBLEVBQ0Y7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQSxFQVdPLFFBQVEsY0FBb0U7QUFDakYsVUFBTSxxQkFBcUIsSUFBSSxJQUFJLFlBQVk7QUFDL0MsVUFBTSxrQkFBa0IsS0FBSyxtQkFBbUIsa0JBQWtCO0FBQ2xFLFVBQU0sU0FBUyxvQkFBSSxJQUFtQztBQUV0RCxlQUFXLGVBQWUsb0JBQW9CO0FBRTVDLFVBQVNDLE9BQVQsU0FBYSxNQUFjLE1BQThCLGFBQTJCO0FBQ2xGLHNCQUFjLGdCQUFnQixNQUFNLEVBQUUsYUFBYSxLQUFLLENBQUM7QUFBQSxNQUMzRDtBQUZTLGdCQUFBQTtBQURULFlBQU0saUJBQWlCLG9CQUFJLElBQWtDO0FBSzdELFdBQUssc0JBQXNCLGFBQWFBLElBQUc7QUFDM0MsV0FBSyx3QkFBd0IsYUFBYUEsSUFBRztBQUM3QyxXQUFLLDJCQUEyQixhQUFhQSxJQUFHO0FBQ2hELFdBQUssMkJBQTJCLGFBQWEsaUJBQWlCQSxJQUFHO0FBQ2pFLFdBQUssc0JBQXNCLGFBQWFBLElBQUc7QUFFM0MsYUFBTyxJQUFJLGFBQWEsZUFBZSxjQUFjLENBQUM7QUFBQSxJQUN4RDtBQUVBLFdBQU87QUFBQSxFQUNUO0FBQUEsRUFFUSwyQkFBMkIsYUFBcUIsS0FBMEI7QUFDaEYsVUFBTSxPQUFPLFFBQVEsV0FBVztBQUNoQyxVQUFNLGVBQWUsS0FBSyxvQkFBb0IsSUFBSSxJQUFJO0FBQ3RELFFBQUk7QUFFSixRQUFJLGNBQWM7QUFDaEIsZ0JBQVUsUUFBUSxjQUFjLFdBQVcsQ0FBQztBQUM1QyxVQUFJLENBQUMsU0FBUztBQUNaO0FBQUEsTUFDRjtBQUFBLElBQ0YsV0FBVyxLQUFLLFlBQVksRUFBRSxTQUFTLEtBQUssR0FBRztBQUM3QyxnQkFBVSxLQUFLLE1BQU0sR0FBRyxDQUFDLE1BQU0sTUFBTTtBQUFBLElBQ3ZDLE9BQU87QUFDTDtBQUFBLElBQ0Y7QUFFQSxVQUFNLG1CQUFtQixRQUFRLFlBQVk7QUFDN0MsVUFBTSxhQUFhLENBQUMsU0FBMEIsS0FBSyxZQUFZLElBQUksSUFBSSxNQUFNLENBQUMsZ0JBQWdCLFFBQVEsSUFBSSxNQUFNO0FBRWhILGVBQVcsQ0FBQyxNQUFNLE9BQU8sS0FBSyxLQUFLLGVBQWU7QUFDaEQsVUFBSSxXQUFXLElBQUksS0FBSyxRQUFRLEtBQUssQ0FBQyxVQUFVLE1BQU0sWUFBWSxNQUFNLGdCQUFnQixHQUFHO0FBQ3pGLFlBQUksTUFBTSxxQkFBOEIsa0NBQWtDLE9BQU8sSUFBSTtBQUFBLE1BQ3ZGO0FBQUEsSUFDRjtBQUVBLGVBQVcsQ0FBQyxNQUFNLEtBQUssS0FBSyxLQUFLLGNBQWM7QUFDN0MsVUFBSSxXQUFXLElBQUksS0FBSyxNQUFNLFlBQVksTUFBTSxrQkFBa0I7QUFDaEUsWUFBSSxNQUFNLHFCQUE4Qiw4QkFBOEIsT0FBTyxJQUFJO0FBQUEsTUFDbkY7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUFBLEVBRVEsd0JBQXdCLGFBQXFCLEtBQTBCO0FBQzdFLGVBQVcsUUFBUSxLQUFLLHFCQUFxQixJQUFJLFlBQVksWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHO0FBQ2pGLFVBQUksTUFBTSwrQkFBbUMsMkNBQTJDO0FBQUEsSUFDMUY7QUFBQSxFQUNGO0FBQUEsRUFFUSxzQkFBc0IsYUFBcUIsS0FBMEI7QUFDM0UsVUFBTSxZQUFZLEtBQUssV0FBVyxJQUFJLFdBQVc7QUFDakQsUUFBSSxhQUFhLEtBQUssWUFBWSxJQUFJLFVBQVUsT0FBTyxHQUFHO0FBQ3hELFVBQUksVUFBVSxTQUFTLDZCQUFrQyw2Q0FBNkMsVUFBVSxNQUFNLEdBQUc7QUFBQSxJQUMzSDtBQUFBLEVBQ0Y7QUFBQSxFQUVRLDJCQUEyQixhQUFxQixpQkFBc0QsS0FBMEI7QUFDdEksVUFBTSxpQkFBaUIsZ0JBQWdCLElBQUksV0FBVztBQUN0RCxRQUFJLENBQUMsZ0JBQWdCO0FBQ25CO0FBQUEsSUFDRjtBQUVBLFVBQU0sYUFBYSxjQUFjLGVBQWUsSUFBSTtBQUNwRCxVQUFNLFlBQVksZ0JBQWdCLGVBQWUsTUFBTSxXQUFXO0FBRWxFLGVBQVcsaUJBQWlCLEtBQUsscUJBQXFCLElBQUksVUFBVSxLQUFLLENBQUMsR0FBRztBQUMzRSxZQUFNLGtCQUFrQixDQUFDLEdBQUcsZUFBZSxVQUFVLEVBQUUsTUFBTSxDQUFDLFNBQVMsS0FBSyxZQUFZLElBQUksU0FBUyxlQUFlLElBQUksQ0FBQyxDQUFDO0FBQzFILFVBQUksQ0FBQyxpQkFBaUI7QUFDcEI7QUFBQSxNQUNGO0FBRUEsWUFBTSxZQUFZLGVBQWUsV0FBVztBQUM1QztBQUFBLFFBQ0UsU0FBUyxlQUFlLFNBQVM7QUFBQSxRQUNqQztBQUFBLFFBQ0EsZUFBZSxlQUFlLElBQUksK0JBQStCLGFBQWEsV0FBVyxjQUFjLElBQUksOEJBQThCLE9BQU8sT0FBTyxTQUFTLENBQUMsMEJBQTBCO0FBQUEsTUFDN0w7QUFBQSxJQUNGO0FBQUEsRUFDRjtBQUFBLEVBRVEsc0JBQXNCLGFBQXFCLEtBQTBCO0FBQzNFLFVBQU0sT0FBTyxRQUFRLFdBQVc7QUFDaEMsVUFBTSxrQkFBa0IsS0FBSyxvQkFBb0IsSUFBSSxJQUFJLElBQUksZ0NBQWdDO0FBQzdGLFVBQU0sa0JBQWtCLFlBQVksTUFBTSxHQUFHO0FBQzdDLFFBQUksbUJBQW1CO0FBQ3ZCLFFBQUksWUFBc0IsQ0FBQztBQUUzQixlQUFXLFFBQVEsS0FBSyxZQUFZLElBQUksSUFBSSxLQUFLLENBQUMsR0FBRztBQUNuRCxZQUFNLGVBQWUsc0JBQXNCLGlCQUFpQixLQUFLLE1BQU0sR0FBRyxDQUFDO0FBQzNFLFVBQUksZUFBZSxrQkFBa0I7QUFDbkMsMkJBQW1CO0FBQ25CLG9CQUFZLENBQUMsSUFBSTtBQUFBLE1BQ25CLFdBQVcsaUJBQWlCLGtCQUFrQjtBQUM1QyxrQkFBVSxLQUFLLElBQUk7QUFBQSxNQUNyQjtBQUFBLElBQ0Y7QUFFQSxVQUFNLFNBQVMsZ0JBQWdCLE1BQU0sQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLEdBQUc7QUFDaEUsZUFBVyxRQUFRLFdBQVc7QUFDNUIsVUFBSSxNQUFNLDJCQUFpQywwQkFBMEIsTUFBTSx1QkFBdUI7QUFBQSxJQUNwRztBQUFBLEVBQ0Y7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBU1EsbUJBQW1CLGNBQWdFO0FBQ3pGLFVBQU0saUJBQWlCLG9CQUFJLElBQTRCO0FBQ3ZELFVBQU0sU0FBUyxvQkFBSSxJQUE0QjtBQUUvQyxlQUFXLGVBQWUsY0FBYztBQUN0QyxVQUFJLE9BQU8sY0FBYyxXQUFXO0FBQ3BDLFVBQUksS0FBSyxZQUFZLElBQUksSUFBSSxHQUFHO0FBQzlCO0FBQUEsTUFDRjtBQUVBLGFBQU8sQ0FBQyxLQUFLLFlBQVksSUFBSSxjQUFjLElBQUksQ0FBQyxHQUFHO0FBQ2pELGVBQU8sY0FBYyxJQUFJO0FBQUEsTUFDM0I7QUFFQSxVQUFJLGlCQUFpQixlQUFlLElBQUksSUFBSTtBQUM1QyxVQUFJLENBQUMsZ0JBQWdCO0FBQ25CLHlCQUFpQixFQUFFLFlBQVksb0JBQUksSUFBSSxHQUFHLEtBQUs7QUFDL0MsdUJBQWUsSUFBSSxNQUFNLGNBQWM7QUFBQSxNQUN6QztBQUVBLHFCQUFlLFdBQVcsSUFBSSxnQkFBZ0IsTUFBTSxXQUFXLENBQUM7QUFDaEUsYUFBTyxJQUFJLGFBQWEsY0FBYztBQUFBLElBQ3hDO0FBRUEsV0FBTztBQUFBLEVBQ1Q7QUFDRjtBQVFPLFNBQVMsY0FBYyxNQUFzQjtBQUNsRCxRQUFNLFFBQVEsS0FBSyxZQUFZLEdBQUc7QUFDbEMsU0FBTyxVQUFVLEtBQUssS0FBSyxLQUFLLE1BQU0sR0FBRyxLQUFLO0FBQ2hEO0FBVU8sU0FBUyxlQUFlLFNBQWlCLFNBQThCO0FBQzVFLFFBQU0sY0FBYyxRQUFRLE1BQU0sR0FBRztBQUNyQyxRQUFNLGNBQWMsUUFBUSxNQUFNLEdBQUc7QUFDckMsUUFBTSxlQUFlLHNCQUFzQixhQUFhLFdBQVc7QUFDbkUsU0FBTztBQUFBLElBQ0wsV0FBVyxZQUFZLE1BQU0sR0FBRyxZQUFZLFNBQVMsWUFBWSxFQUFFLEtBQUssR0FBRztBQUFBLElBQzNFLFdBQVcsWUFBWSxNQUFNLEdBQUcsWUFBWSxTQUFTLFlBQVksRUFBRSxLQUFLLEdBQUc7QUFBQSxFQUM3RTtBQUNGO0FBRUEsU0FBUyxjQUEwQixLQUF3QixLQUFVLE9BQW9CO0FBQ3ZGLE1BQUksU0FBUyxJQUFJLElBQUksR0FBRztBQUN4QixNQUFJLENBQUMsUUFBUTtBQUNYLGFBQVMsQ0FBQztBQUNWLFFBQUksSUFBSSxLQUFLLE1BQU07QUFBQSxFQUNyQjtBQUNBLFNBQU8sS0FBSyxLQUFLO0FBQ25CO0FBRUEsU0FBUyxzQkFBc0IsV0FBOEIsV0FBc0M7QUFDakcsTUFBSSxTQUFTO0FBQ2IsU0FBTyxTQUFTLFVBQVUsVUFBVSxTQUFTLFVBQVUsVUFBVSxVQUFVLEdBQUcsQ0FBQyxTQUFTLENBQUMsTUFBTSxVQUFVLEdBQUcsQ0FBQyxTQUFTLENBQUMsR0FBRztBQUN4SDtBQUFBLEVBQ0Y7QUFDQSxTQUFPO0FBQ1Q7QUFFQSxTQUFTLGdCQUFnQixVQUFzQztBQUM3RCxTQUFPLG9CQUFvQixRQUFRLFNBQVMsSUFBSTtBQUNsRDtBQUVBLFNBQVMsUUFBUSxNQUFzQjtBQUNyQyxTQUFPLEtBQUssTUFBTSxLQUFLLFlBQVksR0FBRyxJQUFJLENBQUM7QUFDN0M7QUFJQSxTQUFTLGdCQUFnQixRQUFnQixNQUFzQjtBQUM3RCxTQUFPLEtBQUssTUFBTSxPQUFPLFNBQVMsQ0FBQztBQUNyQztBQUVBLFNBQVMsU0FBUyxRQUFnQixNQUFzQjtBQUN0RCxTQUFPLEdBQUcsTUFBTSxJQUFJLElBQUk7QUFDMUI7QUFFQSxTQUFTLGVBQWUsZ0JBQWtGO0FBQ3hHLFFBQU0sYUFBYSxDQUFDLEdBQUcsY0FBYyxFQUFFLElBQUksQ0FBQyxDQUFDLE1BQU0sUUFBUSxPQUFPO0FBQUEsSUFDaEUsVUFBVSxTQUFTLEtBQUssQ0FBQyxXQUFXLGNBQWMsZ0JBQWdCLFNBQVMsSUFBSSxnQkFBZ0IsU0FBUyxDQUFDO0FBQUEsSUFDekc7QUFBQSxFQUNGLEVBQUU7QUFFRixTQUFPLFdBQVcsS0FBSyxDQUFDLFlBQVksZUFBZTtBQUNqRCxVQUFNLGlCQUFpQixvQkFBZ0Isc0NBQWtCLFdBQVcsU0FBUyxDQUFDLENBQUMsQ0FBQyxJQUFJLG9CQUFnQixzQ0FBa0IsV0FBVyxTQUFTLENBQUMsQ0FBQyxDQUFDO0FBQzdJLFdBQU8sa0JBQWtCLFdBQVcsS0FBSyxjQUFjLFdBQVcsSUFBSTtBQUFBLEVBQ3hFLENBQUM7QUFDSDsiLCJuYW1lcyI6WyJCcm9rZW5MaW5rRXZpZGVuY2VLaW5kIiwiYWRkIl19
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/// <reference path="./library-references.d.cts" />
|
|
2
|
+
/**
|
|
3
|
+
* @file
|
|
4
|
+
*
|
|
5
|
+
* Where did a missing link target go? Pure, no `App`: every question about which file a broken link most likely
|
|
6
|
+
* meant is answerable from a list of paths, the notes' aliases and titles, and the vault's git renames.
|
|
7
|
+
*
|
|
8
|
+
* A rename is not recoverable from the link alone: a link to `alpha/bravo/charlie/!.md` says nothing about
|
|
9
|
+
* `charlie` having become `delta`. So every candidate carries the evidence that produced it, from outside the
|
|
10
|
+
* link, and the finder never picks one of several: a caller offers a one-click fix only when exactly one
|
|
11
|
+
* candidate exists.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* The kind of evidence that makes a file a candidate for a missing link target.
|
|
15
|
+
*
|
|
16
|
+
* Candidates list evidence strongest first, in EVIDENCE_KIND_ORDER below.
|
|
17
|
+
*/
|
|
18
|
+
export declare enum BrokenLinkEvidenceKind {
|
|
19
|
+
/**
|
|
20
|
+
* The candidate's `aliases` hold the missing target's old name.
|
|
21
|
+
*/
|
|
22
|
+
Alias = "Alias",
|
|
23
|
+
/**
|
|
24
|
+
* The candidate's path differs from the missing one only in letter case.
|
|
25
|
+
*/
|
|
26
|
+
CaseChange = "CaseChange",
|
|
27
|
+
/**
|
|
28
|
+
* The vault's git history records the missing path being renamed to the candidate.
|
|
29
|
+
*/
|
|
30
|
+
GitRename = "GitRename",
|
|
31
|
+
/**
|
|
32
|
+
* The missing target's folder is gone, and a sibling folder holds every missing target that was under it.
|
|
33
|
+
*/
|
|
34
|
+
RenamedFolder = "RenamedFolder",
|
|
35
|
+
/**
|
|
36
|
+
* A file with the same name, and the longest run of the same parent folders, sits elsewhere.
|
|
37
|
+
*/
|
|
38
|
+
SameName = "SameName",
|
|
39
|
+
/**
|
|
40
|
+
* The candidate's `title` is the missing target's old name.
|
|
41
|
+
*/
|
|
42
|
+
Title = "Title"
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* One file that a missing link target may have become, and why.
|
|
46
|
+
*/
|
|
47
|
+
export interface BrokenLinkCandidate {
|
|
48
|
+
/**
|
|
49
|
+
* Every reason this file is a candidate, strongest first.
|
|
50
|
+
*/
|
|
51
|
+
readonly evidence: readonly BrokenLinkEvidence[];
|
|
52
|
+
/**
|
|
53
|
+
* The candidate's vault path.
|
|
54
|
+
*/
|
|
55
|
+
readonly path: string;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* The parameters for {@link BrokenLinkCandidateFinder}.
|
|
59
|
+
*/
|
|
60
|
+
export interface BrokenLinkCandidateFinderConstructorParams {
|
|
61
|
+
/**
|
|
62
|
+
* Each note's `aliases`, by note path.
|
|
63
|
+
*/
|
|
64
|
+
readonly aliasesByPath: ReadonlyMap<string, readonly string[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Every file in the vault.
|
|
67
|
+
*/
|
|
68
|
+
readonly filePaths: readonly string[];
|
|
69
|
+
/**
|
|
70
|
+
* The file names a folder note is stored under, such as `index.md`. Such a name says nothing about which
|
|
71
|
+
* note it is, so a same-name candidate must share its folder's name too, and the old name an alias is
|
|
72
|
+
* matched against is the folder's.
|
|
73
|
+
*/
|
|
74
|
+
readonly folderNoteFileNames: readonly string[];
|
|
75
|
+
/**
|
|
76
|
+
* The vault's git renames: each old vault path to the path it was renamed to, chains already followed.
|
|
77
|
+
*/
|
|
78
|
+
readonly gitRenames: ReadonlyMap<string, GitRename>;
|
|
79
|
+
/**
|
|
80
|
+
* Each note's `title`, by note path.
|
|
81
|
+
*/
|
|
82
|
+
readonly titlesByPath: ReadonlyMap<string, string>;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* One reason a file is a candidate for a missing link target.
|
|
86
|
+
*/
|
|
87
|
+
export interface BrokenLinkEvidence {
|
|
88
|
+
/**
|
|
89
|
+
* A sentence naming the evidence, for the user to judge it by.
|
|
90
|
+
*/
|
|
91
|
+
readonly description: string;
|
|
92
|
+
/**
|
|
93
|
+
* The kind of evidence.
|
|
94
|
+
*/
|
|
95
|
+
readonly kind: BrokenLinkEvidenceKind;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* A rename recorded in the vault's git history.
|
|
99
|
+
*/
|
|
100
|
+
export interface GitRename {
|
|
101
|
+
/**
|
|
102
|
+
* The abbreviated hash of the commit that made the last rename of the chain.
|
|
103
|
+
*/
|
|
104
|
+
readonly commit: string;
|
|
105
|
+
/**
|
|
106
|
+
* The vault path the file was last renamed to.
|
|
107
|
+
*/
|
|
108
|
+
readonly newPath: string;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* The part of a missing path that a candidate replaced: what a "fix all like this" applies to every other link.
|
|
112
|
+
*/
|
|
113
|
+
export interface PathMapping {
|
|
114
|
+
/**
|
|
115
|
+
* The part of the candidate path that replaced {@link oldPrefix}; `''` for the vault root.
|
|
116
|
+
*/
|
|
117
|
+
readonly newPrefix: string;
|
|
118
|
+
/**
|
|
119
|
+
* The leading part of the missing path that no longer exists; `''` for the vault root.
|
|
120
|
+
*/
|
|
121
|
+
readonly oldPrefix: string;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Finds the candidates for missing link targets, from one snapshot of the vault.
|
|
125
|
+
*/
|
|
126
|
+
export declare class BrokenLinkCandidateFinder {
|
|
127
|
+
private readonly aliasesByPath;
|
|
128
|
+
private readonly childFoldersByFolder;
|
|
129
|
+
private readonly filePathSet;
|
|
130
|
+
private readonly filesByLowerCasePath;
|
|
131
|
+
private readonly filesByName;
|
|
132
|
+
private readonly folderNoteFileNames;
|
|
133
|
+
private readonly folderPaths;
|
|
134
|
+
private readonly gitRenames;
|
|
135
|
+
private readonly titlesByPath;
|
|
136
|
+
/**
|
|
137
|
+
* Indexes the vault snapshot.
|
|
138
|
+
*
|
|
139
|
+
* @param params - The snapshot.
|
|
140
|
+
*/
|
|
141
|
+
constructor(params: BrokenLinkCandidateFinderConstructorParams);
|
|
142
|
+
/**
|
|
143
|
+
* Finds the candidates for every missing path at once.
|
|
144
|
+
*
|
|
145
|
+
* All at once because one kind of evidence is collective: a renamed folder is recognized by every missing
|
|
146
|
+
* target that was under it turning up together under one sibling folder.
|
|
147
|
+
*
|
|
148
|
+
* @param missingPaths - The vault paths that links lead to and no file holds.
|
|
149
|
+
* @returns The candidates for each missing path, strongest first; an empty list when nothing is known.
|
|
150
|
+
*/
|
|
151
|
+
findAll(missingPaths: Iterable<string>): Map<string, BrokenLinkCandidate[]>;
|
|
152
|
+
private addAliasAndTitleCandidates;
|
|
153
|
+
private addCaseChangeCandidates;
|
|
154
|
+
private addGitRenameCandidate;
|
|
155
|
+
private addRenamedFolderCandidates;
|
|
156
|
+
private addSameNameCandidates;
|
|
157
|
+
/**
|
|
158
|
+
* Groups the missing paths by the highest missing folder above each, the root of a subtree that may have been
|
|
159
|
+
* renamed as a whole.
|
|
160
|
+
*
|
|
161
|
+
* @param missingPaths - The missing paths.
|
|
162
|
+
* @returns Each missing path's subtree; a path whose own folder exists has none.
|
|
163
|
+
*/
|
|
164
|
+
private getMissingSubtrees;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* The parent folder of a vault path.
|
|
168
|
+
*
|
|
169
|
+
* @param path - The path.
|
|
170
|
+
* @returns The parent folder; `''` for the vault root.
|
|
171
|
+
*/
|
|
172
|
+
export declare function getParentPath(path: string): string;
|
|
173
|
+
/**
|
|
174
|
+
* The part of a missing path that a candidate path replaced, found by dropping the path segments they end with
|
|
175
|
+
* in common.
|
|
176
|
+
*
|
|
177
|
+
* @param oldPath - The missing path.
|
|
178
|
+
* @param newPath - The candidate path.
|
|
179
|
+
* @returns The prefixes that differ.
|
|
180
|
+
*/
|
|
181
|
+
export declare function getPathMapping(oldPath: string, newPath: string): PathMapping;
|