obsidian-dev-utils
Version:
This is the collection of useful functions that you can use for your Obsidian plugin development
251 lines (248 loc) • 36.2 kB
JavaScript
/*
THIS IS A GENERATED/BUNDLED FILE BY ESBUILD
if you want to view the source, please visit the github repository of this plugin
*/
(function initEsm(){if(globalThis.process){return}const browserProcess={browser:true,cwd(){return"/"},env:{},platform:"android"};globalThis.process=browserProcess})();
import { abortSignalAny } from "../AbortController.mjs";
import { requestAnimationFrameAsync } from "../Async.mjs";
import {
ensureLfEndings,
getLfNormalizedOffsetToOriginalOffsetMapper,
hasSingleOccurrence,
indent,
unindent
} from "../String.mjs";
import { resolveValue } from "../ValueProvider.mjs";
import {
invokeWithFileSystemLock,
process,
saveNote
} from "./Vault.mjs";
async function getCodeBlockMarkdownInfo(options) {
const { app, ctx, el, source } = options;
const sourceFile = app.vault.getFileByPath(ctx.sourcePath);
if (!sourceFile) {
throw new Error(`Source file ${ctx.sourcePath} not found.`);
}
await requestAnimationFrameAsync();
await saveNote(app, sourceFile);
let markdownInfo = null;
await invokeWithFileSystemLock(app, sourceFile, (noteContent) => {
const noteContentLf = ensureLfEndings(noteContent);
const approximateSectionInfo = {
lineEnd: noteContentLf.split("\n").length - 1,
lineStart: 0,
text: noteContentLf
};
approximateSectionInfo.text = ensureLfEndings(approximateSectionInfo.text);
const sourceLf = ensureLfEndings(source);
if (!hasSingleOccurrence(noteContentLf, approximateSectionInfo.text)) {
return;
}
const sectionOffset = noteContentLf.indexOf(approximateSectionInfo.text);
const linesBeforeSectionCount = noteContentLf.slice(0, sectionOffset).split("\n").length - 1;
const isInCallout = !!el.parentElement?.classList.contains("callout-content");
const language = getLanguageFromElement(el);
const sourceLines = sourceLf.split("\n");
const textLines = approximateSectionInfo.text.split("\n");
const textLineOffsets = /* @__PURE__ */ new Map();
textLineOffsets.set(linesBeforeSectionCount, sectionOffset);
let lastTextLineOffset = sectionOffset;
for (let i = 0; i < textLines.length; i++) {
const textLine = textLines[i] ?? "";
const lineOffset = lastTextLineOffset + textLine.length + 1;
textLineOffsets.set(linesBeforeSectionCount + i + 1, lineOffset);
lastTextLineOffset = lineOffset;
}
const potentialCodeBlockTextLines = textLines.map(
(line, index) => approximateSectionInfo.lineStart <= index && index <= approximateSectionInfo.lineEnd ? line : ""
);
const potentialCodeBlockText = potentialCodeBlockTextLines.join("\n");
const REG_EXP = /(?<=^|\n)(?<LinePrefix> {0,3}(?:> {1,3})*)(?<CodeBlockStartDelimiter>(?<CodeBlockStartDelimiterChar>[`~])(?:\k<CodeBlockStartDelimiterChar>{2,}))(?<CodeBlockLanguage>\S*)(?:[ \t](?<CodeBlockArgs>.*?))?(?:\n(?<CodeBlockContent>(?:\n?\k<LinePrefix>.*)+?))?\n\k<LinePrefix>(?<CodeBlockEndDelimiter>\k<CodeBlockStartDelimiter>\k<CodeBlockStartDelimiterChar>*)[ \t]*(?=\n|$)/g;
for (const match of potentialCodeBlockText.matchAll(REG_EXP)) {
if (!isSuitableCodeBlock(match, language, sourceLf, isInCallout)) {
continue;
}
if (markdownInfo) {
return;
}
markdownInfo = createMarkdownInfoFromMatch({
approximateSectionInfo,
linesBeforeSectionCount,
match,
noteContent,
potentialCodeBlockText,
sourceLinesCount: sourceLines.length,
textLineOffsets
});
}
if (!markdownInfo) {
return;
}
if (noteContentLf === noteContent) {
return;
}
const lfOffsetMapper = getLfNormalizedOffsetToOriginalOffsetMapper(noteContent);
markdownInfo.positionInNote.start.offset = lfOffsetMapper(markdownInfo.positionInNote.start.offset);
markdownInfo.positionInNote.end.offset = lfOffsetMapper(markdownInfo.positionInNote.end.offset);
});
return markdownInfo;
}
async function insertAfterCodeBlock(options) {
const { app, ctx, lineOffset = 0, text } = options;
await process(app, ctx.sourcePath, async (_abortSignal, content) => {
const markdownInfo = await getCodeBlockMarkdownInfo(options);
if (!markdownInfo) {
throw new Error("Could not uniquely identify the code block.");
}
if (content !== markdownInfo.noteContent) {
return null;
}
const insertLineIndex = markdownInfo.positionInNote.end.line + lineOffset + 1;
return insertText(content, insertLineIndex, text, options.shouldPreserveLinePrefix);
});
}
async function insertBeforeCodeBlock(options) {
const { app, ctx, lineOffset = 0, text } = options;
await process(app, ctx.sourcePath, async (_abortSignal, content) => {
const markdownInfo = await getCodeBlockMarkdownInfo(options);
if (!markdownInfo) {
throw new Error("Could not uniquely identify the code block.");
}
if (content !== markdownInfo.noteContent) {
return null;
}
const insertLineIndex = markdownInfo.positionInNote.start.line - lineOffset;
return insertText(content, insertLineIndex, text, options.shouldPreserveLinePrefix);
});
}
async function removeCodeBlock(options) {
await replaceCodeBlock({
...options,
codeBlockProvider: "",
shouldKeepGapWhenEmpty: options.shouldKeepGap ?? false
});
}
async function replaceCodeBlock(options) {
const { app, codeBlockProvider, ctx } = options;
options.abortSignal?.throwIfAborted();
await process(app, ctx.sourcePath, async (abortSignal, content) => {
abortSignal = abortSignalAny(abortSignal, options.abortSignal);
abortSignal.throwIfAborted();
const markdownInfo = await getCodeBlockMarkdownInfo(options);
if (!markdownInfo) {
throw new Error("Could not uniquely identify the code block.");
}
if (content !== markdownInfo.noteContent) {
return null;
}
let oldCodeBlock = content.slice(markdownInfo.positionInNote.start.offset, markdownInfo.positionInNote.end.offset);
if (options.shouldPreserveLinePrefix) {
oldCodeBlock = unindent(oldCodeBlock, markdownInfo.linePrefix);
}
let newCodeBlock = await resolveValue(codeBlockProvider, abortSignal, oldCodeBlock);
abortSignal.throwIfAborted();
if ((newCodeBlock || options.shouldKeepGapWhenEmpty) && options.shouldPreserveLinePrefix) {
newCodeBlock = indent(newCodeBlock, markdownInfo.linePrefix);
}
const textBeforeCodeBlock = content.slice(0, markdownInfo.positionInNote.start.offset);
const textAfterCodeBlock = content.slice(markdownInfo.positionInNote.end.offset);
if (newCodeBlock || options.shouldKeepGapWhenEmpty) {
return `${textBeforeCodeBlock}${newCodeBlock}${textAfterCodeBlock}`;
}
if (!textBeforeCodeBlock && !textAfterCodeBlock) {
return "";
}
if (textBeforeCodeBlock) {
return `${textBeforeCodeBlock.slice(0, -1)}${textAfterCodeBlock}`;
}
return `${textBeforeCodeBlock}${textAfterCodeBlock.slice(1)}`;
});
}
function createMarkdownInfoFromMatch(options) {
const {
approximateSectionInfo,
linesBeforeSectionCount,
match,
noteContent,
potentialCodeBlockText,
sourceLinesCount,
textLineOffsets
} = options;
const linePrefix = match.groups?.["LinePrefix"] ?? "";
const codeBlockStartDelimiter = match.groups?.["CodeBlockStartDelimiter"] ?? "";
const codeBlockEndDelimiter = match.groups?.["CodeBlockEndDelimiter"] ?? "";
const codeBlockArgsStr = match.groups?.["CodeBlockArgs"] ?? "";
const language = match.groups?.["CodeBlockLanguage"] ?? "";
const previousText = potentialCodeBlockText.slice(0, match.index);
const previousTextLinesCount = previousText.split("\n").length - 1;
const startLine = linesBeforeSectionCount + previousTextLinesCount;
const endLine = startLine + sourceLinesCount + 1;
return {
args: codeBlockArgsStr.split(/\s+/).filter(Boolean),
endDelimiter: codeBlockEndDelimiter,
language,
linePrefix,
noteContent,
positionInNote: {
end: {
col: (textLineOffsets.get(endLine + 1) ?? 0) - (textLineOffsets.get(endLine) ?? 0) - 1,
line: endLine,
offset: (textLineOffsets.get(endLine + 1) ?? 0) - 1
},
start: {
col: 0,
line: startLine,
offset: textLineOffsets.get(startLine) ?? 0
}
},
rawArgsStr: codeBlockArgsStr,
sectionInfo: {
lineEnd: previousTextLinesCount + sourceLinesCount + 1,
lineStart: previousTextLinesCount,
text: approximateSectionInfo.text
},
startDelimiter: codeBlockStartDelimiter
};
}
function getLanguageFromElement(el) {
const BLOCK_LANGUAGE_PREFIX = "block-language-";
return Array.from(el.classList).find((cls) => cls.startsWith(BLOCK_LANGUAGE_PREFIX))?.slice(BLOCK_LANGUAGE_PREFIX.length) ?? "";
}
function insertText(content, insertLineIndex, text, shouldPreserveLinePrefix) {
const lines = content.split("\n");
const newLines = lines.slice();
const textLines = text.split("\n");
if (insertLineIndex < 0) {
insertLineIndex = 0;
}
if (insertLineIndex > lines.length) {
insertLineIndex = lines.length;
}
const PREFIX_LINE_REG_EXP = /^ {0,3}(?:> {1,3})*/g;
const match = (lines[insertLineIndex] ?? "").match(PREFIX_LINE_REG_EXP);
const linePrefix = match?.[0] ?? "";
newLines.splice(insertLineIndex, 0, ...shouldPreserveLinePrefix ? textLines.map((line) => indent(line, linePrefix)) : textLines);
return newLines.join("\n");
}
function isSuitableCodeBlock(match, language, sourceLf, isInCallout) {
const codeBlockLanguage = match.groups?.["CodeBlockLanguage"] ?? "";
if (codeBlockLanguage !== language) {
return false;
}
const linePrefix = match.groups?.["LinePrefix"] ?? "";
if (isInCallout && !linePrefix.includes("> ")) {
return false;
}
const codeBlockContent = match.groups?.["CodeBlockContent"] ?? "";
const cleanCodeBlockContent = codeBlockContent.split("\n").map((line) => line.slice(linePrefix.length)).join("\n");
return cleanCodeBlockContent === sourceLf;
}
export {
getCodeBlockMarkdownInfo,
insertAfterCodeBlock,
insertBeforeCodeBlock,
removeCodeBlock,
replaceCodeBlock
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL01hcmtkb3duQ29kZUJsb2NrUHJvY2Vzc29yLnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBwYWNrYWdlRG9jdW1lbnRhdGlvblxuICpcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBwcm9jZXNzaW5nIGNvZGUgYmxvY2tzIGluIE9ic2lkaWFuLlxuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgQXBwLFxuICBNYXJrZG93blBvc3RQcm9jZXNzb3JDb250ZXh0LFxuICBNYXJrZG93blNlY3Rpb25JbmZvcm1hdGlvblxufSBmcm9tICdvYnNpZGlhbic7XG5cbmltcG9ydCB0eXBlIHsgVmFsdWVQcm92aWRlciB9IGZyb20gJy4uL1ZhbHVlUHJvdmlkZXIudHMnO1xuaW1wb3J0IHR5cGUgeyBDb2RlQmxvY2tNYXJrZG93bkluZm9ybWF0aW9uIH0gZnJvbSAnLi9Db2RlQmxvY2tNYXJrZG93bkluZm9ybWF0aW9uLnRzJztcblxuaW1wb3J0IHsgYWJvcnRTaWduYWxBbnkgfSBmcm9tICcuLi9BYm9ydENvbnRyb2xsZXIudHMnO1xuaW1wb3J0IHsgcmVxdWVzdEFuaW1hdGlvbkZyYW1lQXN5bmMgfSBmcm9tICcuLi9Bc3luYy50cyc7XG5pbXBvcnQge1xuICBlbnN1cmVMZkVuZGluZ3MsXG4gIGdldExmTm9ybWFsaXplZE9mZnNldFRvT3JpZ2luYWxPZmZzZXRNYXBwZXIsXG4gIGhhc1NpbmdsZU9jY3VycmVuY2UsXG4gIGluZGVudCxcbiAgdW5pbmRlbnRcbn0gZnJvbSAnLi4vU3RyaW5nLnRzJztcbmltcG9ydCB7IHJlc29sdmVWYWx1ZSB9IGZyb20gJy4uL1ZhbHVlUHJvdmlkZXIudHMnO1xuaW1wb3J0IHtcbiAgaW52b2tlV2l0aEZpbGVTeXN0ZW1Mb2NrLFxuICBwcm9jZXNzLFxuICBzYXZlTm90ZVxufSBmcm9tICcuL1ZhdWx0LnRzJztcblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmsgZ2V0Q29kZUJsb2NrTWFya2Rvd25JbmZvfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBHZXRDb2RlQmxvY2tNYXJrZG93bkluZm9PcHRpb25zIHtcbiAgLyoqXG4gICAqIEFuIE9ic2lkaWFuIGFwcCBpbnN0YW5jZS5cbiAgICovXG4gIGFwcDogQXBwO1xuXG4gIC8qKlxuICAgKiBBIHtAbGluayBNYXJrZG93blBvc3RQcm9jZXNzb3JDb250ZXh0fSBvYmplY3QuXG4gICAqL1xuICBjdHg6IE1hcmtkb3duUG9zdFByb2Nlc3NvckNvbnRleHQ7XG5cbiAgLyoqXG4gICAqIEEge0BsaW5rIEhUTUxFbGVtZW50fSByZXByZXNlbnRpbmcgdGhlIGNvZGUgYmxvY2suXG4gICAqL1xuICBlbDogSFRNTEVsZW1lbnQ7XG5cbiAgLyoqXG4gICAqIEEgc291cmNlIG9mIHRoZSBjb2RlIGJsb2NrLlxuICAgKi9cbiAgc291cmNlOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3Ige0BsaW5rIGluc2VydEFmdGVyQ29kZUJsb2NrfSAvIHtAbGluayBpbnNlcnRCZWZvcmVDb2RlQmxvY2t9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEluc2VydENvZGVCbG9ja09wdGlvbnMgZXh0ZW5kcyBHZXRDb2RlQmxvY2tNYXJrZG93bkluZm9PcHRpb25zIHtcbiAgLyoqXG4gICAqIEEgbnVtYmVyIG9mIGxpbmVzIHRvIG9mZnNldCB0aGUgaW5zZXJ0aW9uIGJ5LiBEZWZhdWx0IGlzIGAwYC5cbiAgICovXG4gIGxpbmVPZmZzZXQ/OiBudW1iZXI7XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gcHJlc2VydmUgdGhlIGxpbmUgcHJlZml4IG9mIHRoZSBjb2RlIGJsb2NrLiBEZWZhdWx0IGlzIGBmYWxzZWAuXG4gICAqL1xuICBzaG91bGRQcmVzZXJ2ZUxpbmVQcmVmaXg/OiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBBIHRleHQgdG8gaW5zZXJ0IGFmdGVyIHRoZSBjb2RlIGJsb2NrLlxuICAgKi9cbiAgdGV4dDogc3RyaW5nO1xufVxuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayByZW1vdmVDb2RlQmxvY2t9LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFJlbW92ZUNvZGVCbG9ja09wdGlvbnMgZXh0ZW5kcyBHZXRDb2RlQmxvY2tNYXJrZG93bkluZm9PcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8ga2VlcCB0aGUgZ2FwIGFmdGVyIHJlbW92aW5nIHRoZSBjb2RlIGJsb2NrLiBEZWZhdWx0IGlzIGBmYWxzZWAuXG4gICAqL1xuICBzaG91bGRLZWVwR2FwPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBPcHRpb25zIGZvciB7QGxpbmsgcmVwbGFjZUNvZGVCbG9ja30uXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVwbGFjZUNvZGVCbG9ja09wdGlvbnMgZXh0ZW5kcyBHZXRDb2RlQmxvY2tNYXJrZG93bkluZm9PcHRpb25zIHtcbiAgLyoqXG4gICAqIEFuIGFib3J0IHNpZ25hbCB0byBjb250cm9sIHRoZSBleGVjdXRpb24gb2YgdGhlIGZ1bmN0aW9uLlxuICAgKi9cbiAgYWJvcnRTaWduYWw/OiBBYm9ydFNpZ25hbDtcblxuICAvKipcbiAgICogUHJvdmlkZXMgYSBuZXcgY29kZSBibG9jay5cbiAgICovXG4gIGNvZGVCbG9ja1Byb3ZpZGVyOiBWYWx1ZVByb3ZpZGVyPHN0cmluZywgW3N0cmluZ10+O1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGtlZXAgdGhlIGdhcCB3aGVuIHRoZSBuZXcgY29kZSBibG9jayBpcyBlbXB0eS4gRGVmYXVsdCBpcyBgZmFsc2VgLlxuICAgKi9cbiAgc2hvdWxkS2VlcEdhcFdoZW5FbXB0eT86IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gcHJlc2VydmUgdGhlIGxpbmUgcHJlZml4IG9mIHRoZSBjb2RlIGJsb2NrLiBEZWZhdWx0IGlzIGBmYWxzZWAuXG4gICAqL1xuICBzaG91bGRQcmVzZXJ2ZUxpbmVQcmVmaXg/OiBib29sZWFuO1xufVxuXG5pbnRlcmZhY2UgQ3JlYXRlTWFya2Rvd25JbmZvRnJvbU1hdGNoT3B0aW9ucyB7XG4gIGFwcHJveGltYXRlU2VjdGlvbkluZm86IE1hcmtkb3duU2VjdGlvbkluZm9ybWF0aW9uO1xuICBsaW5lc0JlZm9yZVNlY3Rpb25Db3VudDogbnVtYmVyO1xuICBtYXRjaDogUmVnRXhwTWF0Y2hBcnJheTtcbiAgbm90ZUNvbnRlbnQ6IHN0cmluZztcbiAgcG90ZW50aWFsQ29kZUJsb2NrVGV4dDogc3RyaW5nO1xuICBzb3VyY2VMaW5lc0NvdW50OiBudW1iZXI7XG4gIHRleHRMaW5lT2Zmc2V0czogTWFwPG51bWJlciwgbnVtYmVyPjtcbn1cblxuLyoqXG4gKiBHZXRzIHRoZSBpbmZvcm1hdGlvbiBhYm91dCBhIGNvZGUgYmxvY2sgaW4gYSBNYXJrZG93biBzZWN0aW9uLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBmdW5jdGlvbi5cbiAqIEByZXR1cm5zIFRoZSBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY29kZSBibG9jayBpbiB0aGUgTWFya2Rvd24gc2VjdGlvbi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldENvZGVCbG9ja01hcmtkb3duSW5mbyhvcHRpb25zOiBHZXRDb2RlQmxvY2tNYXJrZG93bkluZm9PcHRpb25zKTogUHJvbWlzZTxDb2RlQmxvY2tNYXJrZG93bkluZm9ybWF0aW9uIHwgbnVsbD4ge1xuICBjb25zdCB7IGFwcCwgY3R4LCBlbCwgc291cmNlIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IHNvdXJjZUZpbGUgPSBhcHAudmF1bHQuZ2V0RmlsZUJ5UGF0aChjdHguc291cmNlUGF0aCk7XG4gIGlmICghc291cmNlRmlsZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgU291cmNlIGZpbGUgJHtjdHguc291cmNlUGF0aH0gbm90IGZvdW5kLmApO1xuICB9XG5cbiAgYXdhaXQgcmVxdWVzdEFuaW1hdGlvbkZyYW1lQXN5bmMoKTtcbiAgYXdhaXQgc2F2ZU5vdGUoYXBwLCBzb3VyY2VGaWxlKTtcblxuICBsZXQgbWFya2Rvd25JbmZvOiBDb2RlQmxvY2tNYXJrZG93bkluZm9ybWF0aW9uIHwgbnVsbCA9IG51bGw7XG5cbiAgYXdhaXQgaW52b2tlV2l0aEZpbGVTeXN0ZW1Mb2NrKGFwcCwgc291cmNlRmlsZSwgKG5vdGVDb250ZW50KSA9PiB7XG4gICAgY29uc3Qgbm90ZUNvbnRlbnRMZiA9IGVuc3VyZUxmRW5kaW5ncyhub3RlQ29udGVudCk7XG5cbiAgICBjb25zdCBhcHByb3hpbWF0ZVNlY3Rpb25JbmZvOiBNYXJrZG93blNlY3Rpb25JbmZvcm1hdGlvbiA9IHtcbiAgICAgIGxpbmVFbmQ6IG5vdGVDb250ZW50TGYuc3BsaXQoJ1xcbicpLmxlbmd0aCAtIDEsXG4gICAgICBsaW5lU3RhcnQ6IDAsXG4gICAgICB0ZXh0OiBub3RlQ29udGVudExmXG4gICAgfTtcblxuICAgIGFwcHJveGltYXRlU2VjdGlvbkluZm8udGV4dCA9IGVuc3VyZUxmRW5kaW5ncyhhcHByb3hpbWF0ZVNlY3Rpb25JbmZvLnRleHQpO1xuICAgIGNvbnN0IHNvdXJjZUxmID0gZW5zdXJlTGZFbmRpbmdzKHNvdXJjZSk7XG5cbiAgICBpZiAoIWhhc1NpbmdsZU9jY3VycmVuY2Uobm90ZUNvbnRlbnRMZiwgYXBwcm94aW1hdGVTZWN0aW9uSW5mby50ZXh0KSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnN0IHNlY3Rpb25PZmZzZXQgPSBub3RlQ29udGVudExmLmluZGV4T2YoYXBwcm94aW1hdGVTZWN0aW9uSW5mby50ZXh0KTtcbiAgICBjb25zdCBsaW5lc0JlZm9yZVNlY3Rpb25Db3VudCA9IG5vdGVDb250ZW50TGYuc2xpY2UoMCwgc2VjdGlvbk9mZnNldCkuc3BsaXQoJ1xcbicpLmxlbmd0aCAtIDE7XG5cbiAgICBjb25zdCBpc0luQ2FsbG91dCA9ICEhZWwucGFyZW50RWxlbWVudD8uY2xhc3NMaXN0LmNvbnRhaW5zKCdjYWxsb3V0LWNvbnRlbnQnKTtcblxuICAgIGNvbnN0IGxhbmd1YWdlID0gZ2V0TGFuZ3VhZ2VGcm9tRWxlbWVudChlbCk7XG4gICAgY29uc3Qgc291cmNlTGluZXMgPSBzb3VyY2VMZi5zcGxpdCgnXFxuJyk7XG5cbiAgICBjb25zdCB0ZXh0TGluZXMgPSBhcHByb3hpbWF0ZVNlY3Rpb25JbmZvLnRleHQuc3BsaXQoJ1xcbicpO1xuICAgIGNvbnN0IHRleHRMaW5lT2Zmc2V0cyA9IG5ldyBNYXA8bnVtYmVyLCBudW1iZXI+KCk7XG4gICAgdGV4dExpbmVPZmZzZXRzLnNldChsaW5lc0JlZm9yZVNlY3Rpb25Db3VudCwgc2VjdGlvbk9mZnNldCk7XG5cbiAgICBsZXQgbGFzdFRleHRMaW5lT2Zmc2V0ID0gc2VjdGlvbk9mZnNldDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHRleHRMaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgY29uc3QgdGV4dExpbmUgPSB0ZXh0TGluZXNbaV0gPz8gJyc7XG4gICAgICBjb25zdCBsaW5lT2Zmc2V0ID0gbGFzdFRleHRMaW5lT2Zmc2V0ICsgdGV4dExpbmUubGVuZ3RoICsgMTtcbiAgICAgIHRleHRMaW5lT2Zmc2V0cy5zZXQobGluZXNCZWZvcmVTZWN0aW9uQ291bnQgKyBpICsgMSwgbGluZU9mZnNldCk7XG4gICAgICBsYXN0VGV4dExpbmVPZmZzZXQgPSBsaW5lT2Zmc2V0O1xuICAgIH1cblxuICAgIGNvbnN0IHBvdGVudGlhbENvZGVCbG9ja1RleHRMaW5lcyA9IHRleHRMaW5lcy5tYXAoKGxpbmUsIGluZGV4KSA9PlxuICAgICAgYXBwcm94aW1hdGVTZWN0aW9uSW5mby5saW5lU3RhcnQgPD0gaW5kZXggJiYgaW5kZXggPD0gYXBwcm94aW1hdGVTZWN0aW9uSW5mby5saW5lRW5kID8gbGluZSA6ICcnXG4gICAgKTtcbiAgICBjb25zdCBwb3RlbnRpYWxDb2RlQmxvY2tUZXh0ID0gcG90ZW50aWFsQ29kZUJsb2NrVGV4dExpbmVzLmpvaW4oJ1xcbicpO1xuXG4gICAgY29uc3QgUkVHX0VYUCA9XG4gICAgICAvKD88PV58XFxuKSg/PExpbmVQcmVmaXg+IHswLDN9KD86PiB7MSwzfSkqKSg/PENvZGVCbG9ja1N0YXJ0RGVsaW1pdGVyPig/PENvZGVCbG9ja1N0YXJ0RGVsaW1pdGVyQ2hhcj5bYH5dKSg/OlxcazxDb2RlQmxvY2tTdGFydERlbGltaXRlckNoYXI+ezIsfSkpKD88Q29kZUJsb2NrTGFuZ3VhZ2U+XFxTKikoPzpbIFxcdF0oPzxDb2RlQmxvY2tBcmdzPi4qPykpPyg/Olxcbig/PENvZGVCbG9ja0NvbnRlbnQ+KD86XFxuP1xcazxMaW5lUHJlZml4Pi4qKSs/KSk/XFxuXFxrPExpbmVQcmVmaXg+KD88Q29kZUJsb2NrRW5kRGVsaW1pdGVyPlxcazxDb2RlQmxvY2tTdGFydERlbGltaXRlcj5cXGs8Q29kZUJsb2NrU3RhcnREZWxpbWl0ZXJDaGFyPiopWyBcXHRdKig/PVxcbnwkKS9nO1xuXG4gICAgZm9yIChjb25zdCBtYXRjaCBvZiBwb3RlbnRpYWxDb2RlQmxvY2tUZXh0Lm1hdGNoQWxsKFJFR19FWFApKSB7XG4gICAgICBpZiAoIWlzU3VpdGFibGVDb2RlQmxvY2sobWF0Y2gsIGxhbmd1YWdlLCBzb3VyY2VMZiwgaXNJbkNhbGxvdXQpKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAobWFya2Rvd25JbmZvKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgbWFya2Rvd25JbmZvID0gY3JlYXRlTWFya2Rvd25JbmZvRnJvbU1hdGNoKHtcbiAgICAgICAgYXBwcm94aW1hdGVTZWN0aW9uSW5mbyxcbiAgICAgICAgbGluZXNCZWZvcmVTZWN0aW9uQ291bnQsXG4gICAgICAgIG1hdGNoLFxuICAgICAgICBub3RlQ29udGVudCxcbiAgICAgICAgcG90ZW50aWFsQ29kZUJsb2NrVGV4dCxcbiAgICAgICAgc291cmNlTGluZXNDb3VudDogc291cmNlTGluZXMubGVuZ3RoLFxuICAgICAgICB0ZXh0TGluZU9mZnNldHNcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmICghbWFya2Rvd25JbmZvKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKG5vdGVDb250ZW50TGYgPT09IG5vdGVDb250ZW50KSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgbGZPZmZzZXRNYXBwZXIgPSBnZXRMZk5vcm1hbGl6ZWRPZmZzZXRUb09yaWdpbmFsT2Zmc2V0TWFwcGVyKG5vdGVDb250ZW50KTtcbiAgICBtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuc3RhcnQub2Zmc2V0ID0gbGZPZmZzZXRNYXBwZXIobWFya2Rvd25JbmZvLnBvc2l0aW9uSW5Ob3RlLnN0YXJ0Lm9mZnNldCk7XG4gICAgbWFya2Rvd25JbmZvLnBvc2l0aW9uSW5Ob3RlLmVuZC5vZmZzZXQgPSBsZk9mZnNldE1hcHBlcihtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuZW5kLm9mZnNldCk7XG4gIH0pO1xuXG4gIHJldHVybiBtYXJrZG93bkluZm87XG59XG5cbi8qKlxuICogSW5zZXJ0cyB0ZXh0IGFmdGVyIHRoZSBjb2RlIGJsb2NrLlxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluc2VydEFmdGVyQ29kZUJsb2NrKG9wdGlvbnM6IEluc2VydENvZGVCbG9ja09wdGlvbnMpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgeyBhcHAsIGN0eCwgbGluZU9mZnNldCA9IDAsIHRleHQgfSA9IG9wdGlvbnM7XG5cbiAgYXdhaXQgcHJvY2VzcyhhcHAsIGN0eC5zb3VyY2VQYXRoLCBhc3luYyAoX2Fib3J0U2lnbmFsLCBjb250ZW50KSA9PiB7XG4gICAgY29uc3QgbWFya2Rvd25JbmZvID0gYXdhaXQgZ2V0Q29kZUJsb2NrTWFya2Rvd25JbmZvKG9wdGlvbnMpO1xuICAgIGlmICghbWFya2Rvd25JbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCB1bmlxdWVseSBpZGVudGlmeSB0aGUgY29kZSBibG9jay4nKTtcbiAgICB9XG5cbiAgICBpZiAoY29udGVudCAhPT0gbWFya2Rvd25JbmZvLm5vdGVDb250ZW50KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBjb25zdCBpbnNlcnRMaW5lSW5kZXggPSBtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuZW5kLmxpbmUgKyBsaW5lT2Zmc2V0ICsgMTtcbiAgICByZXR1cm4gaW5zZXJ0VGV4dChjb250ZW50LCBpbnNlcnRMaW5lSW5kZXgsIHRleHQsIG9wdGlvbnMuc2hvdWxkUHJlc2VydmVMaW5lUHJlZml4KTtcbiAgfSk7XG59XG5cbi8qKlxuICogSW5zZXJ0cyB0ZXh0IGJlZm9yZSB0aGUgY29kZSBibG9jay5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnNlcnRCZWZvcmVDb2RlQmxvY2sob3B0aW9uczogSW5zZXJ0Q29kZUJsb2NrT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IGFwcCwgY3R4LCBsaW5lT2Zmc2V0ID0gMCwgdGV4dCB9ID0gb3B0aW9ucztcblxuICBhd2FpdCBwcm9jZXNzKGFwcCwgY3R4LnNvdXJjZVBhdGgsIGFzeW5jIChfYWJvcnRTaWduYWwsIGNvbnRlbnQpID0+IHtcbiAgICBjb25zdCBtYXJrZG93bkluZm8gPSBhd2FpdCBnZXRDb2RlQmxvY2tNYXJrZG93bkluZm8ob3B0aW9ucyk7XG4gICAgaWYgKCFtYXJrZG93bkluZm8pIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ291bGQgbm90IHVuaXF1ZWx5IGlkZW50aWZ5IHRoZSBjb2RlIGJsb2NrLicpO1xuICAgIH1cblxuICAgIGlmIChjb250ZW50ICE9PSBtYXJrZG93bkluZm8ubm90ZUNvbnRlbnQpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cblxuICAgIGNvbnN0IGluc2VydExpbmVJbmRleCA9IG1hcmtkb3duSW5mby5wb3NpdGlvbkluTm90ZS5zdGFydC5saW5lIC0gbGluZU9mZnNldDtcbiAgICByZXR1cm4gaW5zZXJ0VGV4dChjb250ZW50LCBpbnNlcnRMaW5lSW5kZXgsIHRleHQsIG9wdGlvbnMuc2hvdWxkUHJlc2VydmVMaW5lUHJlZml4KTtcbiAgfSk7XG59XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgY29kZSBibG9jay5cbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZW1vdmVDb2RlQmxvY2sob3B0aW9uczogUmVtb3ZlQ29kZUJsb2NrT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCByZXBsYWNlQ29kZUJsb2NrKHtcbiAgICAuLi5vcHRpb25zLFxuICAgIGNvZGVCbG9ja1Byb3ZpZGVyOiAnJyxcbiAgICBzaG91bGRLZWVwR2FwV2hlbkVtcHR5OiBvcHRpb25zLnNob3VsZEtlZXBHYXAgPz8gZmFsc2VcbiAgfSk7XG59XG5cbi8qKlxuICogUmVwbGFjZXMgdGhlIGNvZGUgYmxvY2suXG4gKlxuICogQHBhcmFtIG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBmb3IgdGhlIGZ1bmN0aW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVwbGFjZUNvZGVCbG9jayhvcHRpb25zOiBSZXBsYWNlQ29kZUJsb2NrT3B0aW9ucyk6IFByb21pc2U8dm9pZD4ge1xuICBjb25zdCB7IGFwcCwgY29kZUJsb2NrUHJvdmlkZXIsIGN0eCB9ID0gb3B0aW9ucztcbiAgb3B0aW9ucy5hYm9ydFNpZ25hbD8udGhyb3dJZkFib3J0ZWQoKTtcblxuICBhd2FpdCBwcm9jZXNzKGFwcCwgY3R4LnNvdXJjZVBhdGgsIGFzeW5jIChhYm9ydFNpZ25hbCwgY29udGVudCkgPT4ge1xuICAgIGFib3J0U2lnbmFsID0gYWJvcnRTaWduYWxBbnkoYWJvcnRTaWduYWwsIG9wdGlvbnMuYWJvcnRTaWduYWwpO1xuICAgIGFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG4gICAgY29uc3QgbWFya2Rvd25JbmZvID0gYXdhaXQgZ2V0Q29kZUJsb2NrTWFya2Rvd25JbmZvKG9wdGlvbnMpO1xuICAgIGlmICghbWFya2Rvd25JbmZvKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NvdWxkIG5vdCB1bmlxdWVseSBpZGVudGlmeSB0aGUgY29kZSBibG9jay4nKTtcbiAgICB9XG5cbiAgICBpZiAoY29udGVudCAhPT0gbWFya2Rvd25JbmZvLm5vdGVDb250ZW50KSB7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBsZXQgb2xkQ29kZUJsb2NrID0gY29udGVudC5zbGljZShtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuc3RhcnQub2Zmc2V0LCBtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuZW5kLm9mZnNldCk7XG4gICAgaWYgKG9wdGlvbnMuc2hvdWxkUHJlc2VydmVMaW5lUHJlZml4KSB7XG4gICAgICBvbGRDb2RlQmxvY2sgPSB1bmluZGVudChvbGRDb2RlQmxvY2ssIG1hcmtkb3duSW5mby5saW5lUHJlZml4KTtcbiAgICB9XG5cbiAgICBsZXQgbmV3Q29kZUJsb2NrID0gYXdhaXQgcmVzb2x2ZVZhbHVlKGNvZGVCbG9ja1Byb3ZpZGVyLCBhYm9ydFNpZ25hbCwgb2xkQ29kZUJsb2NrKTtcbiAgICBhYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuICAgIGlmICgobmV3Q29kZUJsb2NrIHx8IG9wdGlvbnMuc2hvdWxkS2VlcEdhcFdoZW5FbXB0eSkgJiYgb3B0aW9ucy5zaG91bGRQcmVzZXJ2ZUxpbmVQcmVmaXgpIHtcbiAgICAgIG5ld0NvZGVCbG9jayA9IGluZGVudChuZXdDb2RlQmxvY2ssIG1hcmtkb3duSW5mby5saW5lUHJlZml4KTtcbiAgICB9XG5cbiAgICBjb25zdCB0ZXh0QmVmb3JlQ29kZUJsb2NrID0gY29udGVudC5zbGljZSgwLCBtYXJrZG93bkluZm8ucG9zaXRpb25Jbk5vdGUuc3RhcnQub2Zmc2V0KTtcbiAgICBjb25zdCB0ZXh0QWZ0ZXJDb2RlQmxvY2sgPSBjb250ZW50LnNsaWNlKG1hcmtkb3duSW5mby5wb3NpdGlvbkluTm90ZS5lbmQub2Zmc2V0KTtcblxuICAgIGlmIChuZXdDb2RlQmxvY2sgfHwgb3B0aW9ucy5zaG91bGRLZWVwR2FwV2hlbkVtcHR5KSB7XG4gICAgICByZXR1cm4gYCR7dGV4dEJlZm9yZUNvZGVCbG9ja30ke25ld0NvZGVCbG9ja30ke3RleHRBZnRlckNvZGVCbG9ja31gO1xuICAgIH1cblxuICAgIGlmICghdGV4dEJlZm9yZUNvZGVCbG9jayAmJiAhdGV4dEFmdGVyQ29kZUJsb2NrKSB7XG4gICAgICByZXR1cm4gJyc7XG4gICAgfVxuXG4gICAgaWYgKHRleHRCZWZvcmVDb2RlQmxvY2spIHtcbiAgICAgIHJldHVybiBgJHt0ZXh0QmVmb3JlQ29kZUJsb2NrLnNsaWNlKDAsIC0xKX0ke3RleHRBZnRlckNvZGVCbG9ja31gO1xuICAgIH1cblxuICAgIHJldHVybiBgJHt0ZXh0QmVmb3JlQ29kZUJsb2NrfSR7dGV4dEFmdGVyQ29kZUJsb2NrLnNsaWNlKDEpfWA7XG4gIH0pO1xufVxuXG5mdW5jdGlvbiBjcmVhdGVNYXJrZG93bkluZm9Gcm9tTWF0Y2gob3B0aW9uczogQ3JlYXRlTWFya2Rvd25JbmZvRnJvbU1hdGNoT3B0aW9ucyk6IENvZGVCbG9ja01hcmtkb3duSW5mb3JtYXRpb24ge1xuICBjb25zdCB7XG4gICAgYXBwcm94aW1hdGVTZWN0aW9uSW5mbyxcbiAgICBsaW5lc0JlZm9yZVNlY3Rpb25Db3VudCxcbiAgICBtYXRjaCxcbiAgICBub3RlQ29udGVudCxcbiAgICBwb3RlbnRpYWxDb2RlQmxvY2tUZXh0LFxuICAgIHNvdXJjZUxpbmVzQ291bnQsXG4gICAgdGV4dExpbmVPZmZzZXRzXG4gIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IGxpbmVQcmVmaXggPSBtYXRjaC5ncm91cHM/LlsnTGluZVByZWZpeCddID8/ICcnO1xuICBjb25zdCBjb2RlQmxvY2tTdGFydERlbGltaXRlciA9IG1hdGNoLmdyb3Vwcz8uWydDb2RlQmxvY2tTdGFydERlbGltaXRlciddID8/ICcnO1xuICBjb25zdCBjb2RlQmxvY2tFbmREZWxpbWl0ZXIgPSBtYXRjaC5ncm91cHM/LlsnQ29kZUJsb2NrRW5kRGVsaW1pdGVyJ10gPz8gJyc7XG4gIGNvbnN0IGNvZGVCbG9ja0FyZ3NTdHIgPSBtYXRjaC5ncm91cHM/LlsnQ29kZUJsb2NrQXJncyddID8/ICcnO1xuICBjb25zdCBsYW5ndWFnZSA9IG1hdGNoLmdyb3Vwcz8uWydDb2RlQmxvY2tMYW5ndWFnZSddID8/ICcnO1xuXG4gIGNvbnN0IHByZXZpb3VzVGV4dCA9IHBvdGVudGlhbENvZGVCbG9ja1RleHQuc2xpY2UoMCwgbWF0Y2guaW5kZXgpO1xuICBjb25zdCBwcmV2aW91c1RleHRMaW5lc0NvdW50ID0gcHJldmlvdXNUZXh0LnNwbGl0KCdcXG4nKS5sZW5ndGggLSAxO1xuXG4gIGNvbnN0IHN0YXJ0TGluZSA9IGxpbmVzQmVmb3JlU2VjdGlvbkNvdW50ICsgcHJldmlvdXNUZXh0TGluZXNDb3VudDtcbiAgY29uc3QgZW5kTGluZSA9IHN0YXJ0TGluZSArIHNvdXJjZUxpbmVzQ291bnQgKyAxO1xuXG4gIHJldHVybiB7XG4gICAgYXJnczogY29kZUJsb2NrQXJnc1N0ci5zcGxpdCgvXFxzKy8pLmZpbHRlcihCb29sZWFuKSxcbiAgICBlbmREZWxpbWl0ZXI6IGNvZGVCbG9ja0VuZERlbGltaXRlcixcbiAgICBsYW5ndWFnZSxcbiAgICBsaW5lUHJlZml4LFxuICAgIG5vdGVDb250ZW50LFxuICAgIHBvc2l0aW9uSW5Ob3RlOiB7XG4gICAgICBlbmQ6IHtcbiAgICAgICAgY29sOiAodGV4dExpbmVPZmZzZXRzLmdldChlbmRMaW5lICsgMSkgPz8gMCkgLSAodGV4dExpbmVPZmZzZXRzLmdldChlbmRMaW5lKSA/PyAwKSAtIDEsXG4gICAgICAgIGxpbmU6IGVuZExpbmUsXG4gICAgICAgIG9mZnNldDogKHRleHRMaW5lT2Zmc2V0cy5nZXQoZW5kTGluZSArIDEpID8/IDApIC0gMVxuICAgICAgfSxcbiAgICAgIHN0YXJ0OiB7XG4gICAgICAgIGNvbDogMCxcbiAgICAgICAgbGluZTogc3RhcnRMaW5lLFxuICAgICAgICBvZmZzZXQ6IHRleHRMaW5lT2Zmc2V0cy5nZXQoc3RhcnRMaW5lKSA/PyAwXG4gICAgICB9XG4gICAgfSxcbiAgICByYXdBcmdzU3RyOiBjb2RlQmxvY2tBcmdzU3RyLFxuICAgIHNlY3Rpb25JbmZvOiB7XG4gICAgICBsaW5lRW5kOiBwcmV2aW91c1RleHRMaW5lc0NvdW50ICsgc291cmNlTGluZXNDb3VudCArIDEsXG4gICAgICBsaW5lU3RhcnQ6IHByZXZpb3VzVGV4dExpbmVzQ291bnQsXG4gICAgICB0ZXh0OiBhcHByb3hpbWF0ZVNlY3Rpb25JbmZvLnRleHRcbiAgICB9LFxuICAgIHN0YXJ0RGVsaW1pdGVyOiBjb2RlQmxvY2tTdGFydERlbGltaXRlclxuICB9O1xufVxuXG5mdW5jdGlvbiBnZXRMYW5ndWFnZUZyb21FbGVtZW50KGVsOiBIVE1MRWxlbWVudCk6IHN0cmluZyB7XG4gIGNvbnN0IEJMT0NLX0xBTkdVQUdFX1BSRUZJWCA9ICdibG9jay1sYW5ndWFnZS0nO1xuICByZXR1cm4gQXJyYXkuZnJvbShlbC5jbGFzc0xpc3QpLmZpbmQoKGNscykgPT4gY2xzLnN0YXJ0c1dpdGgoQkxPQ0tfTEFOR1VBR0VfUFJFRklYKSk/LnNsaWNlKEJMT0NLX0xBTkdVQUdFX1BSRUZJWC5sZW5ndGgpID8/ICcnO1xufVxuXG5mdW5jdGlvbiBpbnNlcnRUZXh0KGNvbnRlbnQ6IHN0cmluZywgaW5zZXJ0TGluZUluZGV4OiBudW1iZXIsIHRleHQ6IHN0cmluZywgc2hvdWxkUHJlc2VydmVMaW5lUHJlZml4PzogYm9vbGVhbik6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzID0gY29udGVudC5zcGxpdCgnXFxuJyk7XG4gIGNvbnN0IG5ld0xpbmVzID0gbGluZXMuc2xpY2UoKTtcbiAgY29uc3QgdGV4dExpbmVzID0gdGV4dC5zcGxpdCgnXFxuJyk7XG5cbiAgaWYgKGluc2VydExpbmVJbmRleCA8IDApIHtcbiAgICBpbnNlcnRMaW5lSW5kZXggPSAwO1xuICB9XG4gIGlmIChpbnNlcnRMaW5lSW5kZXggPiBsaW5lcy5sZW5ndGgpIHtcbiAgICBpbnNlcnRMaW5lSW5kZXggPSBsaW5lcy5sZW5ndGg7XG4gIH1cblxuICBjb25zdCBQUkVGSVhfTElORV9SRUdfRVhQID0gL14gezAsM30oPzo+IHsxLDN9KSovZztcbiAgY29uc3QgbWF0Y2ggPSAobGluZXNbaW5zZXJ0TGluZUluZGV4XSA/PyAnJykubWF0Y2goUFJFRklYX0xJTkVfUkVHX0VYUCk7XG4gIGNvbnN0IGxpbmVQcmVmaXggPSBtYXRjaD8uWzBdID8/ICcnO1xuICBuZXdMaW5lcy5zcGxpY2UoaW5zZXJ0TGluZUluZGV4LCAwLCAuLi4oc2hvdWxkUHJlc2VydmVMaW5lUHJlZml4ID8gdGV4dExpbmVzLm1hcCgobGluZSkgPT4gaW5kZW50KGxpbmUsIGxpbmVQcmVmaXgpKSA6IHRleHRMaW5lcykpO1xuICByZXR1cm4gbmV3TGluZXMuam9pbignXFxuJyk7XG59XG5cbmZ1bmN0aW9uIGlzU3VpdGFibGVDb2RlQmxvY2soXG4gIG1hdGNoOiBSZWdFeHBNYXRjaEFycmF5LFxuICBsYW5ndWFnZTogc3RyaW5nLFxuICBzb3VyY2VMZjogc3RyaW5nLFxuICBpc0luQ2FsbG91dDogYm9vbGVhblxuKTogYm9vbGVhbiB7XG4gIGNvbnN0IGNvZGVCbG9ja0xhbmd1YWdlID0gbWF0Y2guZ3JvdXBzPy5bJ0NvZGVCbG9ja0xhbmd1YWdlJ10gPz8gJyc7XG4gIGlmIChjb2RlQmxvY2tMYW5ndWFnZSAhPT0gbGFuZ3VhZ2UpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBsaW5lUHJlZml4ID0gbWF0Y2guZ3JvdXBzPy5bJ0xpbmVQcmVmaXgnXSA/PyAnJztcblxuICBpZiAoaXNJbkNhbGxvdXQgJiYgIWxpbmVQcmVmaXguaW5jbHVkZXMoJz4gJykpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICBjb25zdCBjb2RlQmxvY2tDb250ZW50ID0gbWF0Y2guZ3JvdXBzPy5bJ0NvZGVCbG9ja0NvbnRlbnQnXSA/PyAnJztcbiAgY29uc3QgY2xlYW5Db2RlQmxvY2tDb250ZW50ID0gY29kZUJsb2NrQ29udGVudC5zcGxpdCgnXFxuJykubWFwKChsaW5lKSA9PiBsaW5lLnNsaWNlKGxpbmVQcmVmaXgubGVuZ3RoKSkuam9pbignXFxuJyk7XG5cbiAgcmV0dXJuIGNsZWFuQ29kZUJsb2NrQ29udGVudCA9PT0gc291cmNlTGY7XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7O0FBZUEsU0FBUyxzQkFBc0I7QUFDL0IsU0FBUyxrQ0FBa0M7QUFDM0M7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUCxTQUFTLG9CQUFvQjtBQUM3QjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFrR1AsZUFBc0IseUJBQXlCLFNBQXdGO0FBQ3JJLFFBQU0sRUFBRSxLQUFLLEtBQUssSUFBSSxPQUFPLElBQUk7QUFFakMsUUFBTSxhQUFhLElBQUksTUFBTSxjQUFjLElBQUksVUFBVTtBQUN6RCxNQUFJLENBQUMsWUFBWTtBQUNmLFVBQU0sSUFBSSxNQUFNLGVBQWUsSUFBSSxVQUFVLGFBQWE7QUFBQSxFQUM1RDtBQUVBLFFBQU0sMkJBQTJCO0FBQ2pDLFFBQU0sU0FBUyxLQUFLLFVBQVU7QUFFOUIsTUFBSSxlQUFvRDtBQUV4RCxRQUFNLHlCQUF5QixLQUFLLFlBQVksQ0FBQyxnQkFBZ0I7QUFDL0QsVUFBTSxnQkFBZ0IsZ0JBQWdCLFdBQVc7QUFFakQsVUFBTSx5QkFBcUQ7QUFBQSxNQUN6RCxTQUFTLGNBQWMsTUFBTSxJQUFJ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