From 0f02f07359d34a604500a9ac7dbf3c876bcce59e Mon Sep 17 00:00:00 2001 From: moremeyou Date: Thu, 12 Oct 2023 21:02:26 +0200 Subject: [PATCH] 0.5.0 --- manifest.json | 2 +- src/main.js | 1790 +++++++++++++++++++++++++++++++++++++++++++++ src/package.json | 2 +- src/versions.json | 5 + versions.json | 4 - 5 files changed, 1797 insertions(+), 6 deletions(-) create mode 100644 src/main.js create mode 100644 src/versions.json delete mode 100644 versions.json diff --git a/manifest.json b/manifest.json index 7622b88..e0bccca 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "tag-buddy", "name": "Tag Buddy", - "version": "0.3.0", + "version": "0.5.0", "minAppVersion": "1.0.0", "description": "Add, edit and remove tags and copy, move or edit tagged blocks all without leaving reading-mode.", "author": "David Fasullo", diff --git a/src/main.js b/src/main.js new file mode 100644 index 0000000..4cccfee --- /dev/null +++ b/src/main.js @@ -0,0 +1,1790 @@ +/* +THIS IS A GENERATED/BUNDLED FILE BY ESBUILD +if you want to view the source, please visit the github repository of this plugin +*/ + +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); + +// main.ts +var main_exports = {}; +__export(main_exports, { + default: () => TagBuddy +}); +module.exports = __toCommonJS(main_exports); + +// settings.ts +var import_obsidian = require("obsidian"); +var TBSettingsTab = class extends import_obsidian.PluginSettingTab { + constructor(app2, plugin) { + super(app2, plugin); + this.plugin = plugin; + } + display() { + let { containerEl } = this; + containerEl.empty(); + containerEl.createEl("h1", { text: "Tag Buddy" }); + new import_obsidian.Setting(containerEl).setName("Override native tag search on click").setDesc("Toggle OFF to use CTRL/CMD+CLICK to remove tag.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.removeOnClick).onChange(async (value) => { + this.plugin.settings.removeOnClick = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("Convert to tag text (removes #)").setDesc("Toggle OFF to use OPT/ALT+CLICK to perform native tag search.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.optToConvert).onChange(async (value) => { + this.plugin.settings.optToConvert = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("Remove nested tags first").setDesc("Toggle OFF to use SHIFT+CLICK to remove nested tags first.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.removeChildTagsFirst).onChange(async (value) => { + this.plugin.settings.removeChildTagsFirst = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("Mobile tag search").setDesc("Toggle ON to restore mobile native tag search on tap. Tag removal will then use LONG PRESS.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.mobileTagSearch).onChange(async (value) => { + this.plugin.settings.mobileTagSearch = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("Show mobile notices").setDesc("Toggle OFF to hide notices when editing or removing a tag.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.mobileNotices).onChange(async (value) => { + this.plugin.settings.mobileNotices = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("BETA: Show tag summary paragraph buttons").setDesc("Show buttons below each tagged paragraph that let you copy, remove, and move the paragraph.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.tagSummaryBlockButtons).onChange(async (value) => { + this.plugin.settings.tagSummaryBlockButtons = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("BETA: Show tag summary buttons").setDesc("Show buttons below each summary that let you copy or make a note from the summary.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.showSummaryButtons).onChange(async (value) => { + this.plugin.settings.showSummaryButtons = value; + await this.plugin.saveSettings(); + }) + ); + new import_obsidian.Setting(containerEl).setName("Copy to section prefix").setDesc("When moving a tagged paragraph from tag summaries below note header sections use this prefix:\nExample: '- ', '> ', '- [ ]'").addText((text) => { + text.setPlaceholder(this.plugin.settings.taggedParagraphCopyPrefix).setValue(this.plugin.settings.taggedParagraphCopyPrefix).onChange(async (value) => { + this.plugin.settings.taggedParagraphCopyPrefix = value; + await this.plugin.saveSettings(); + }); + }); + function isValidTag(tag) { + const tagPattern = /^#[\w]+$/; + return tagPattern.test(tag); + } + function filterAndJoinTags(tagsString) { + const tagsArray = tagsString.split(", "); + const validTags = tagsArray.filter(isValidTag); + return validTags.join(", "); + } + new import_obsidian.Setting(containerEl).setName("Recent tags").setDesc("The most recent tags added via Tag Buddy are stored here. These will show up first in the list when adding.").addText((text) => { + text.setPlaceholder(this.plugin.settings.recentlyAddedTags).setValue(this.plugin.settings.recentlyAddedTags).onChange(async (value) => { + this.plugin.settings.recentlyAddedTags = filterAndJoinTags(value); + await this.plugin.saveSettings(); + }); + }); + new import_obsidian.Setting(containerEl).setName("Lock recent tags").setDesc("Toggle ON to lock the recent tags list. Recent tags will not be updated. Instead, the tags above will act like a favorites list.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.lockRecentTags).onChange(async (value) => { + this.plugin.settings.lockRecentTags = value; + await this.plugin.saveSettings(); + }) + ); + containerEl.createEl("hr"); + containerEl.createEl("h1", { text: "Support a buddy" }); + const donateButton = containerEl.createEl("a"); + donateButton.setAttribute("href", "https://www.buymeacoffee.com/moremeyou"); + donateButton.innerHTML = `Buy Me A Coffee`; + containerEl.createEl("br"); + containerEl.createEl("br"); + containerEl.createEl("br"); + new import_obsidian.Setting(containerEl).setName("Debug mode").setDesc("Output to console.").addToggle( + (toggle) => toggle.setValue(this.plugin.settings.debugMode).onChange(async (value) => { + this.plugin.settings.debugMode = value; + await this.plugin.saveSettings(); + }) + ); + } +}; + +// main.ts +var import_obsidian2 = require("obsidian"); +var DEFAULT_SETTINGS = { + removeOnClick: true, + // when true, cmd is needed when clicking to remove the tag + removeChildTagsFirst: true, + // use shift when false + optToConvert: true, + // when false, clicking tag will do nothing + mobileTagSearch: false, + // toggle on use double tap for search. press+hold will then remove. + mobileNotices: true, + tagSummaryBlockButtons: false, + taggedParagraphCopyPrefix: "", + recentlyAddedTags: "", + lockRecentTags: false, + showSummaryButtons: false, + debugMode: false +}; +var TagBuddy = class extends import_obsidian2.Plugin { + onunload() { + } + async onload() { + await this.loadSettings(); + this.addSettingTab(new TBSettingsTab(this.app, this)); + console.log("Tag Buddy Plugin loaded on " + (this.app.isMobile ? "mobile at " : "desktop at ") + new Date().toUTCString().substring(17)); + this.injectStyles(); + const debouncedProcessTags = this.debounce(this.processTags.bind(this), 500); + this.app.workspace.onLayoutReady(async () => { + setTimeout(async () => { + this.processTags(); + }, 500); + this.registerEvent(this.app.workspace.on("active-leaf-change", async () => { + })); + this.registerDomEvent(document, "contextmenu", async (event) => { + const view = await this.app.workspace.getActiveViewOfType(import_obsidian2.MarkdownView); + if (view && this.ctrlCmdKey(event) && view.getMode() == "preview") { + event.preventDefault(); + const file = await this.app.workspace.getActiveFile(); + this.showTagSelector(event.pageX, event.pageY, file); + } + }); + this.registerEvent(this.app.on("layout-change", (event) => { + debouncedProcessTags(); + })); + this.registerEvent(this.app.on("file-open", async (event) => { + debouncedProcessTags(); + })); + if (!this.app.isMobile) { + this.registerDomEvent(document, "click", this.onClickEvent.bind(this), true); + } else { + this.registerDomEvent(document, "click", (e) => { + const isTag = e.target.classList.contains("tag"); + if (isTag && !this.settings.mobileTagSearch) { + e.stopPropagation(); + } + }, true); + new PressAndHoldHandler(this, document, this.onClickEvent.bind(this)); + new DoubleTapHandler(this, document, this.onClickEvent.bind(this)); + } + }); + this.registerMarkdownCodeBlockProcessor("tag-summary", this.summaryCodeBlockProcessor.bind(this)); + } + async onClickEvent(event) { + const target = event.target; + const view = await this.app.workspace.getActiveViewOfType(import_obsidian2.MarkdownView); + if (!view && target.matches(".tag")) { + new import_obsidian2.Notice("Tag Buddy: Can't edit tag. Unsupported view type. Try again within that note."); + return; + } + if (view) { + if (view.getMode() != "preview") + return; + } else { + } + if (!this.app.isMobile) { + if (this.settings.removeOnClick && this.ctrlCmdKey(event) || !this.settings.removeOnClick && !this.ctrlCmdKey(event)) { + return; + } else if (event.altKey && !this.settings.optToConvert) { + return; + } + } else { + if (this.settings.mobileTagSearch && event.type == "touchend") { + return; + } + } + if (target && target.matches(".tag")) { + if (this.settings.removeOnClick || !this.settings.removeOnClick && this.ctrlCmdKey(event)) { + event.stopPropagation(); + event.preventDefault(); + } + const clickedTag = target.closest(".tag"); + const tag = clickedTag.innerText; + let tagIndex = clickedTag.getAttribute("md-index"); + let tagFile = clickedTag.getAttribute("file-source"); + if (tagFile) { + this.editTag(target, event); + } else { + setTimeout(async () => { + tagIndex = clickedTag.getAttribute("md-index"); + tagFile = clickedTag.getAttribute("file-source"); + this.editTag(target, event); + }, 300); + } + } else if (!view && target.matches(".tag")) { + new import_obsidian2.Notice("Tag Buddy: Can't edit tag. Might be in an unsupported view type."); + } + } + async editTag(tagEl, event, pragraphEl) { + const index = tagEl.getAttribute("md-index"); + const filePath = tagEl.getAttribute("file-source"); + if (this.settings.debugMode) + console.log("Tag Buddy edit tag: " + tagEl.innerText + "\nIn file: " + filePath); + if (filePath) { + const file = await this.validateFilePath(filePath); + let fileContent; + let fileContentBackup; + const tag = tagEl.innerText.trim(); + try { + fileContent = await this.app.vault.read(file); + fileContentBackup = fileContent; + } catch (error) { + new import_obsidian2.Notice("Tag Buddy file read error:\n" + error.message); + return; + } + let safeToEmptyFile = false; + const tagRegex = /^\s*#(\w+)\s*$/; + if (tagRegex.test(fileContent.trim())) { + safeToEmptyFile = true; + } + let beforeTag = fileContent.substring(0, index); + let afterTag = fileContent.substring(Number(index) + Number(tag.length)); + let afterTagChr; + let beforeTagChr; + if (afterTag.startsWith(" ")) { + afterTagChr = " "; + } else if (afterTag.startsWith("\n")) { + afterTagChr = "\n"; + } + if (fileContent[index] === "\n") { + beforeTag += "\n"; + } + let newContent = ""; + if (!event) { + newContent = beforeTag + afterTagChr + afterTag; + } else if (event.altKey || event.type == "touchstart" && !this.settings.mobileTagSearch) { + const noHash = tag.substring(1); + newContent = beforeTag + noHash + afterTagChr + afterTag; + if (this.app.isMobile && this.settings.mobileNotices) { + new import_obsidian2.Notice("Tag Buddy: " + tag + " converted to text."); + } + } else if (event.type == "touchend" || this.settings.mobileTagSearch || this.ctrlCmdKey(event) && !this.settings.removeOnClick || !this.ctrlCmdKey(event) && this.settings.removeOnClick) { + let parentTag = ""; + if (tag.includes("/") && (this.settings.removeChildTagsFirst || event.shiftKey && !this.settings.removeChildTagsFirst)) { + let parts = tag.split("/"); + const removedChild = parts.pop(); + parentTag = parts.join("/"); + newContent = beforeTag + (!beforeTag.endsWith(" ") ? " " : "") + parentTag + afterTagChr + afterTag; + if (this.app.isMobile && this.settings.mobileNotices) { + new import_obsidian2.Notice("Tag Buddy: '" + removedChild + "' removed from parent tag."); + } + } else { + newContent = beforeTag + afterTag; + if (this.app.isMobile && this.settings.mobileNotices) { + new import_obsidian2.Notice("Tag Buddy: " + tag + " removed."); + } + } + } + try { + if (tagEl.getAttribute("type") == "plugin-summary") { + const summaryEl = tagEl.closest(".tag-summary-paragraph"); + const mdSource = summaryEl.getAttribute("md-source").trim(); + const escapedText = this.escapeRegExp(mdSource); + const regex = new RegExp(escapedText, "g"); + const matches = fileContent.match(regex); + if (matches && matches.length > 1) { + new import_obsidian2.Notice("\u26A0\uFE0F Can't safely remove/edit tag:\nSurrounding text repeated in source note."); + return; + } else if (matches && matches.length === 0 || !matches) { + new import_obsidian2.Notice("\u26A0\uFE0F Can't find tag in source note.\n"); + return; + } + if (newContent == "" && !safeToEmptyFile || this.contentChangedTooMuch(fileContentBackup, newContent, tag, 2)) { + new import_obsidian2.Notice("Tag Buddy: File change error."); + newContent = fileContentBackup; + } else if (newContent == "" && safeToEmptyFile) { + new import_obsidian2.Notice("Tag Buddy: Tag removed. The note is empty."); + } + setTimeout(async () => { + const tagParagraphEl = tagEl.closest(".tag-summary-paragraph"); + const tagSummaryBlock = tagEl.closest(".tag-summary-block"); + const tagsToCheck = this.getTagsToCheckFromEl(tagSummaryBlock); + const tagsInContent = this.tagsInString(tagParagraphEl.innerText); + if (tagsToCheck.includes(tag)) { + const tagCount = this.countOccurrences(tagsToCheck, tagsInContent); + if (tagCount >= 2) { + this.updateSummary(tagSummaryBlock); + setTimeout(async () => { + this.processTags(); + }, 200); + } else { + const notice = new import_obsidian2.Notice(tag + " removed from paragraph.\n\u{1F517} Open source note.", 5e3); + this.removeElementWithAnimation(tagParagraphEl, () => { + setTimeout(async () => { + this.updateSummary(tagSummaryBlock); + tagParagraphEl.remove(); + }, 500); + setTimeout(async () => { + this.processTags(); + }, 800); + }); + this.registerDomEvent(notice.noticeEl, "click", (e) => { + this.app.workspace.openLinkText(filePath, ""); + }); + } + } else { + this.updateSummary(tagSummaryBlock); + setTimeout(async () => { + this.processTags(); + }, 200); + } + }, 200); + } else { + setTimeout(async () => { + this.processTags(); + }, 50); + } + await this.app.vault.modify(file, newContent); + } catch (error) { + try { + const backupFileName = String(file.name.substring(0, file.name.indexOf(".md")) + " BACKUP.md"); + this.app.vault.create(backupFileName, fileContentBackup); + new import_obsidian2.Notice("\u26A0\uFE0F Tag/note editing error: " + error.message + "\n" + backupFileName + " saved to vault root."); + } catch (error2) { + navigator.clipboard.writeText(fileContentBackup); + new import_obsidian2.Notice("\u26A0\uFE0F Tag/note editing error: " + error2.message + "\nNote content copied to clipboard."); + } + } + } else { + this.processTags(); + new import_obsidian2.Notice("\u26A0\uFE0F Can't identify tag location. Please try again."); + } + } + getTagsToCheckFromEl(tagSummaryEl) { + const tagsStr = tagSummaryEl.getAttribute("codeblock-tags"); + const tags = tagsStr ? tagsStr.split(",") : []; + const tagsIncludeStr = tagSummaryEl.getAttribute("codeblock-tags-include"); + const tagsInclude = tagsIncludeStr ? tagsIncludeStr.split(",") : []; + return tags.concat(tagsInclude); + } + updateSummary(summaryEl) { + const summaryContainer = summaryEl; + const tagsStr = summaryContainer.getAttribute("codeblock-tags"); + const tags = tagsStr ? tagsStr.split(",") : []; + const tagsIncludeStr = summaryContainer.getAttribute("codeblock-tags-include"); + const tagsInclude = tagsIncludeStr ? tagsIncludeStr.split(",") : []; + const tagsExcludeStr = summaryContainer.getAttribute("codeblock-tags-exclude"); + const tagsExclude = tagsExcludeStr ? tagsExcludeStr.split(",") : []; + const sectionsStr = summaryContainer.getAttribute("codeblock-sections"); + const sections = sectionsStr ? sectionsStr.split(",") : []; + const max = Number(summaryContainer.getAttribute("codeblock-max")); + const mdSource = summaryContainer.getAttribute("codeblock-code"); + this.createSummary(summaryContainer, tags, tagsInclude, tagsExclude, sections, max, "", mdSource); + } + /*async updateSummariess () { + //const activeFile = await this.app.workspace.getActiveFile(); + //const fileContent = await app.vault.read(activeFile); + const activeNoteContainer = await this.app.workspace.activeLeaf.containerEl; + const embeds = await activeNoteContainer.querySelectorAll('.tag-summary-block'); + //let embededTagFiles = []; + + embeds.forEach(async (embed) => { + if (embed.classList.contains('tag-summary-block')) { + this.updateSummary (embed); + } + }); + }*/ + async processTags() { + if (this.settings.debugMode) + console.log("Tag Buddy: Processing tags."); + const view = await this.app.workspace.getActiveViewOfType(import_obsidian2.MarkdownView); + if (view) { + const activeNoteContainer = await this.app.workspace.activeLeaf.containerEl; + const activeNoteReadingView = activeNoteContainer.querySelector(".markdown-reading-view"); + const activeNoteEditView = activeNoteContainer.querySelector(".markdown-source-view"); + const activeFile = await this.app.workspace.getActiveFile(); + const fileContent = await app.vault.read(activeFile); + const activeFileTagElements = await activeNoteContainer.querySelectorAll(".mod-active .tag:not(.markdown-embed .tag):not(.tag-summary-block .tag)"); + const activeFileTags = await this.getMarkdownTags(activeFile, fileContent); + if (activeFileTags.length > 0) + this.assignMarkdownTags(activeFileTags, activeFileTagElements, 0, "active"); + this.processEmbeds(activeNoteReadingView); + } + } + async getMarkdownTags(file, fileContent) { + const tagPositions = []; + let match; + const regex = /(?<=^|\s)(#[^\s#.,;!?:]+)(?=[.,;!?:\s]|$)|```/g; + let insideCodeBlock = false; + while ((match = regex.exec(fileContent)) !== null) { + if (match[0].trim() === "```") { + insideCodeBlock = !insideCodeBlock; + continue; + } + if (insideCodeBlock) + continue; + const tag = match[0].trim(); + if (fileContent.slice(match.index, match.index + tag.length + 2).endsWith("]]")) { + continue; + } + tagPositions.push({ tag, index: match.index, source: file.name }); + } + return tagPositions; + } + assignMarkdownTags(tagPositions, tagElements, startIndex, type) { + let tagEl; + const tagElArray = Array.from(tagElements); + let tagElIndex = 0; + tagPositions.forEach((tagPos, i) => { + if (tagPositions[i].index >= startIndex) { + tagEl = tagElArray[tagElIndex]; + if (tagEl) { + tagEl.setAttribute("md-index", tagPositions[i].index); + tagEl.setAttribute("file-source", tagPositions[i].source); + tagEl.setAttribute("type", type); + } + tagElIndex++; + } + }); + return tagElArray; + } + async processEmbeds(element, ids = ["tag-summary-block", "markdown-embed"]) { + const embeds = await element.querySelectorAll(".tag-summary-block, .markdown-embed"); + embeds.forEach(async (embed) => { + if (embed.classList.contains("tag-summary-block")) { + this.processTagSummary(embed); + } else if (embed.classList.contains("markdown-embed")) { + this.processNativeEmbed(embed); + if (Array.from(embed.querySelectorAll(".tag-summary-block")).length > 0) { + this.processTagSummary(embed); + } + } else { + } + }); + } + async processNativeEmbed(embed) { + const linkElement = embed.getAttribute("src"); + let filePath = embed.getAttribute("src"); + const linkArray = filePath.split("#"); + filePath = linkArray[0].trim() + ".md"; + const file = await this.validateFilePath(filePath); + if (file) { + const fileContent = await app.vault.read(file); + const embededTagFile = await this.getMarkdownTags(file, fileContent); + const tempComponent = new TempComponent(); + const tempContainerHTML = createEl("div"); + await import_obsidian2.MarkdownRenderer.renderMarkdown(fileContent, tempContainerHTML, file.path, tempComponent); + const innerText = embed.querySelector(".markdown-embed-content").innerText; + const startIndex = tempContainerHTML.innerText.indexOf(innerText); + this.assignMarkdownTags(embededTagFile, embed.querySelectorAll(".tag"), startIndex, "native-embed"); + } + } + async processTagSummary(embed) { + let summaryBlocks = embed.querySelectorAll("blockquote"); + summaryBlocks.forEach(async (block, index) => { + var _a, _b; + const filePath = block.getAttribute("file-source"); + const file = this.app.vault.getAbstractFileByPath(filePath); + const tempComponent = new TempComponent(); + if (file) { + let fileContent = await app.vault.read(file); + const embededTagFile = await this.getMarkdownTags(file, fileContent); + const tempBlock = block.cloneNode(true); + (_a = tempBlock.querySelector(".tagsummary-item-title")) == null ? void 0 : _a.remove(); + (_b = tempBlock.querySelector(".tagsummary-buttons")) == null ? void 0 : _b.remove(); + const markdownBlock = block.getAttribute("md-source").trim(); + const startIndex = fileContent.indexOf(markdownBlock); + this.assignMarkdownTags(embededTagFile, block.querySelectorAll(".tag"), startIndex, "plugin-summary"); + } + }); + } + async summaryCodeBlockProcessor(source, el, ctx) { + let tags = Array(); + let include = Array(); + let exclude = Array(); + let sections = Array(); + let max = 50; + const maxPattern = /^\s*max:\s*(\d+)\s*$/; + let match; + const rows = source.split("\n").filter((row) => row.length > 0); + rows.forEach((line) => { + if (line.match(/^\s*tags:[\p{L}0-9_\-/# ]+$/gu)) { + const content = line.replace(/^\s*tags:/, "").trim(); + let list = content.split(/\s+/).map((tag) => tag.trim()); + list = list.filter((tag) => { + if (tag.match(/^#[\p{L}]+[^#]*$/u)) { + return true; + } else { + return false; + } + }); + tags = list; + } + if (line.match(/^\s*include:[\p{L}0-9_\-/# ]+$/gu)) { + const content = line.replace(/^\s*include:/, "").trim(); + let list = content.split(/\s+/).map((tag) => tag.trim()); + list = list.filter((tag) => { + if (tag.match(/^#[\p{L}]+[^#]*$/u)) { + return true; + } else { + return false; + } + }); + include = list; + } + if (line.match(/^\s*exclude:[\p{L}0-9_\-/# ]+$/gu)) { + const content = line.replace(/^\s*exclude:/, "").trim(); + let list = content.split(/\s+/).map((tag) => tag.trim()); + list = list.filter((tag) => { + if (tag.match(/^#[\p{L}]+[^#]*$/u)) { + return true; + } else { + return false; + } + }); + exclude = list; + } + if (line.match(/^\s*sections:[\p{L}0-9_\-/#, ]+$/gu)) { + const content = line.replace(/^\s*sections:/, "").trim(); + let list = content.split(",").map((sec) => sec.trim()); + sections = list; + } + match = line.match(maxPattern); + if (match) { + max = Math.min(50, Number(match[1])); + } + }); + const codeBlock = "```tag-summary\n" + source.trim() + "\n```"; + if (tags.length > 0 || include.length > 0) { + await this.createSummary(el, tags, include, exclude, sections, max, ctx.sourcePath, codeBlock); + } else { + this.createEmptySummary(el, tags ? tags : [], include ? include : [], exclude ? exclude : [], sections ? sections : [], max ? max : [], ctx.sourcePath ? ctx.sourcePath : "", codeBlock); + } + } + createEmptySummary(element, tags, include, exclude, sections, max, fileCtx, mdSource) { + const container = createEl("div"); + const textDiv = createEl("blockquote"); + textDiv.innerHTML = "There are no files with tagged paragraphs that match the tags:
" + (tags.length > 0 ? tags.join(", ") : "No tags specified.") + "
"; + container.appendChild(textDiv); + container.setAttribute("codeblock-tags", tags.length > 0 ? tags.join(",") : ""); + container.setAttribute("codeblock-tags-include", include ? include.join(",") : ""); + container.setAttribute("codeblock-tags-exclude", exclude ? exclude.join(",") : ""); + container.setAttribute("codeblock-sections", sections ? sections.join(",") : ""); + container.setAttribute("codeblock-max", max); + container.setAttribute("codeblock-code", mdSource); + container.appendChild(this.makeSummaryRefreshButton(container)); + ; + element.replaceWith(container); + } + async createSummary(element, tags, include, exclude, sections, max, fileCtx, mdSource) { + const activeFile = await this.app.workspace.getActiveFile(); + const validTags = tags.concat(include); + const tempComponent = new TempComponent(); + const summaryContainer = createEl("div"); + summaryContainer.setAttribute("class", "tag-summary-block"); + let listFiles = this.app.vault.getMarkdownFiles(); + listFiles = listFiles.filter((file) => { + const cache = app.metadataCache.getFileCache(file); + const tagsInFile = (0, import_obsidian2.getAllTags)(cache); + if (validTags.some((value) => tagsInFile.includes(value))) { + return true; + } + return false; + }); + listFiles = listFiles.sort((file1, file2) => { + if (file1.path < file2.path) { + return -1; + } else if (file1.path > file2.path) { + return 1; + } else { + return 0; + } + }); + let listContents = await this.readFiles(listFiles); + let count = 0; + let summary = ""; + listContents.forEach((item) => { + const fileName = item[0].name.replace(/.md$/g, ""); + const filePath = item[0].path; + if (activeFile) { + if (activeFile.name == item[0].name) + return; + } + let listParagraphs = Array(); + const blocks = item[1].split(/\n\s*\n/).filter((row) => row.trim().length > 0); + blocks.forEach((paragraph) => { + let valid = false; + let listTags = paragraph.match(/#[\p{L}0-9_\-/#]+/gu); + if (listTags != null && listTags.length > 0) { + if (!paragraph.contains("```")) { + valid = this.isValidText(listTags, tags, include, exclude); + } + } + if (valid) { + let listItems = Array(); + let itemText = ""; + paragraph.split("\ns*\n").forEach((line) => { + if (count >= max) + return; + let isList = false; + isList = line.search(/(\s*[\-\+\*]){1}|([0-9]\.){1}\s+/) != -1; + if (!isList) { + listParagraphs.push(line); + itemText = ""; + } else { + line.split("\n").forEach((itemLine) => { + let level = 0; + const endIndex = itemLine.search(/[\-\+\*]{1}|([0-9]\.){1}\s+/); + const tabText = itemLine.slice(0, endIndex); + const tabs = tabText.match(/\t/g); + if (tabs) { + level = tabs.length; + } + if (level == 0) { + if (itemText != "") { + listItems.push(itemText); + itemText = ""; + } + itemText = "" + itemText.concat(itemLine + "\n"); + } else if (level > 0 && itemText != "") { + itemText = itemText.concat(itemLine + "\n"); + } + }); + } + count++; + }); + if (itemText != "") { + listItems.push(itemText); + itemText = ""; + } + listItems.forEach((line) => { + listTags = line.match(/#[\p{L}0-9_\-/#]+/gu); + if (listTags != null && listTags.length > 0) { + if (this.isValidText(listTags, tags, include, exclude)) { + listParagraphs.push(line); + } + } + }); + } + }); + listParagraphs.forEach(async (paragraph) => { + paragraph += "\n"; + var regex = new RegExp(); + var tagText = new String(); + var tagSection = null; + tags.forEach((tag) => { + tagText = tag.replace("#", "\\#"); + regex = new RegExp(`${tagText}(\\W|$)`, "g"); + if (paragraph.match(regex) != null) { + tagSection = tag; + } + }); + const buttonContainer = createEl("div"); + buttonContainer.setAttribute("class", "tagsummary-buttons"); + const paragraphEl = createEl("blockquote"); + paragraphEl.setAttribute("file-source", filePath); + paragraphEl.setAttribute("class", "tag-summary-paragraph"); + const blockLink = paragraph.match(/\^[\p{L}0-9_\-/^]+/gu); + let link; + if (blockLink) { + link = "[[" + filePath + "#" + blockLink + "|" + fileName + "]]"; + let count2 = 0; + sections.forEach((sec) => { + if (count2++ > 3) + return; + buttonContainer.appendChild(this.makeCopyToButton(paragraph, sec, paragraphEl, tags, filePath + "#" + blockLink, paragraphEl, summaryContainer)); + }); + if (this.settings.tagSummaryBlockButtons) { + buttonContainer.appendChild(this.makeCopyButton(paragraph.trim())); + buttonContainer.appendChild(this.makeRemoveTagButton(paragraphEl, tagSection, filePath + "#" + blockLink)); + } + } else { + link = "[[" + filePath + "|" + fileName + "]]"; + let count2 = 0; + sections.forEach((sec) => { + if (count2++ > 3) + return; + if (this.settings.tagSummaryBlockButtons) + buttonContainer.appendChild(this.makeCopyToButton(paragraph, sec, paragraphEl, tags, filePath, paragraphEl, summaryContainer)); + }); + if (this.settings.tagSummaryBlockButtons) { + buttonContainer.appendChild(this.makeCopyButton(paragraph.trim())); + buttonContainer.appendChild(this.makeRemoveTagButton(paragraphEl, tagSection, filePath)); + } + } + const mdParagraph = paragraph; + paragraph = "**" + link + "**\n" + paragraph; + summary += paragraph + "\n"; + await import_obsidian2.MarkdownRenderer.renderMarkdown(paragraph, paragraphEl, "", tempComponent); + const titleEl = createEl("span"); + titleEl.setAttribute("class", "tagsummary-item-title"); + titleEl.appendChild(paragraphEl.querySelector("strong").cloneNode(true)); + if (this.settings.tagSummaryBlockButtons) + paragraphEl.appendChild(buttonContainer); + paragraphEl.querySelector("strong").replaceWith(titleEl); + paragraphEl.setAttribute("md-source", mdParagraph); + summaryContainer.appendChild(paragraphEl); + }); + }); + if (summary != "") { + setTimeout(async () => { + if (this.settings.showSummaryButtons) { + summaryContainer.appendChild(this.makeSummaryRefreshButton(summaryContainer)); + summaryContainer.appendChild(this.makeCopySummaryButton(summary)); + summaryContainer.appendChild(this.makeSummaryNoteButton(summary, tags)); + summaryContainer.appendChild(this.makeBakeButton(summary, summaryContainer, activeFile.path)); + summaryContainer.appendChild(createEl("br")); + } + summaryContainer.appendChild(createEl("hr")); + }, 0); + summaryContainer.setAttribute("codeblock-tags", tags.join(",")); + summaryContainer.setAttribute("codeblock-tags-include", include.length > 0 ? include.join(",") : ""); + summaryContainer.setAttribute("codeblock-tags-exclude", exclude.length > 0 ? exclude.join(",") : ""); + summaryContainer.setAttribute("codeblock-sections", sections.length > 0 ? sections.join(",") : ""); + summaryContainer.setAttribute("codeblock-max", max); + summaryContainer.setAttribute("codeblock-code", mdSource); + element.replaceWith(summaryContainer); + } else { + this.createEmptySummary(element, tags ? tags : [], include ? include : [], exclude ? exclude : [], sections ? sections : [], max ? max : [], "", mdSource); + } + } + /*makeSwitchToEditingButton (view){ + const button = this.makeButton ('Edit code block in edit-mode', async(e) => { + e.stopPropagation(); + const view = await this.app.workspace.getActiveViewOfType(MarkdownView); + if (view.getMode() == 'preview') { + let curState = view.getState(); + curState.mode = 'source'; + view.setState(curState); + } + }); + button.title = 'Switch to edit mode'; + return button; + }*/ + makeCopySummaryButton(summaryMd) { + const button = this.makeButton(" \u274F ", (e) => { + e.stopPropagation(); + navigator.clipboard.writeText(summaryMd); + new import_obsidian2.Notice("Summary copied to clipboard."); + }); + button.title = "Copy summary"; + return button; + } + makeSummaryNoteButton(summaryMd, tags) { + const button = this.makeButton("Note", (e) => { + e.stopPropagation(); + const newNoteObj = this.fileObjFromTags(tags); + let fileContent = "## " + newNoteObj.title + "\n\n" + summaryMd; + const fileName = this.getActiveFileFolder() + newNoteObj.fileName; + const file = this.app.vault.getAbstractFileByPath(fileName); + let notice; + tags.forEach((tag) => { + fileContent = this.replaceTextInString(tag, fileContent, tag.substring(1), true); + }); + if (file instanceof import_obsidian2.TFile) { + notice = new import_obsidian2.Notice("\u26A0\uFE0F Note already exists.\nClick here to overwrite.", 5e3); + this.registerDomEvent(notice.noticeEl, "click", (e2) => { + this.app.vault.modify(file, fileContent); + notice = new import_obsidian2.Notice("Note updated.\n\u{1F517} Open note.", 5e3); + this.registerDomEvent(notice.noticeEl, "click", (e3) => { + this.app.workspace.openLinkText(fileName, ""); + }); + }); + } else if (!file) { + this.app.vault.create(fileName, fileContent); + const notice2 = new import_obsidian2.Notice("Tag Buddy: Summary note created. \u{1F4DC}\n\u{1F517} Open note."); + this.registerDomEvent(notice2.noticeEl, "click", (e2) => { + this.app.workspace.openLinkText(newNoteObj.fileName, ""); + }); + } + }); + button.title = "Create note from summary"; + return button; + } + fileObjFromTags(tags) { + let tagsArray = tags.map((tag) => tag.replace(/#/g, "").toLowerCase()); + tagsArray = tagsArray.filter((tag, index, self) => self.indexOf(tag) === index); + const tagsPart = tagsArray.join("+"); + const currentDate = new Date(); + const datePart = currentDate.getDate().toString().padStart(2, "0") + "-" + (currentDate.getMonth() + 1).toString().padStart(2, "0") + "-" + currentDate.getFullYear().toString().slice(-2); + const fileName = `Tag Summary (${tagsPart}) (${datePart}).md`; + const titleTagsPart = tagsArray.map((tag) => tag.charAt(0).toUpperCase() + tag.slice(1)).join(" + "); + const title = `${titleTagsPart} Tag Summary`; + return { + fileName, + title + }; + } + getActiveFileFolder() { + const activeFile = app.workspace.activeLeaf.view.file; + if (!activeFile) + return null; + const pathSeparator = activeFile.path.includes("\\") ? "\\" : "/"; + const pathParts = activeFile.path.split(pathSeparator); + pathParts.pop(); + let folderPath = pathParts.join(pathSeparator); + if (!folderPath.endsWith(pathSeparator)) { + folderPath += pathSeparator; + } + return folderPath; + } + makeSummaryRefreshButton(summaryEl) { + const button = this.makeButton(" \u21BA ", (e) => { + e.stopPropagation(); + this.updateSummary(summaryEl); + new import_obsidian2.Notice("Tag Summary updated"); + setTimeout(async () => { + this.processTags(); + }, 10); + }); + button.title = "Refresh Tag Summary"; + return button; + } + makeCopyToButton(content, section, paragraph, tags, filePath, paragraphEl, summaryEl) { + const buttonLabel = " \u274F " + this.truncateStringAtWord(section, 16); + const button = this.makeButton(buttonLabel, async (e) => { + e.stopPropagation(); + let newContent = content; + const prefix = this.settings.taggedParagraphCopyPrefix; + if (this.ctrlCmdKey(e)) { + tags.forEach((tag, i) => { + newContent = this.removeTagFromString(newContent, tag).trim(); + }); + } + const copySuccess = this.copyTextToSection(prefix + newContent, section, filePath); + if (copySuccess) { + if (this.ctrlCmdKey(e) && e.shiftKey) { + const file = this.app.vault.getAbstractFileByPath(filePath); + let fileContent = await this.app.vault.read(file); + fileContent = fileContent.trim(); + const newFileContent = this.replaceTextInString(content.trim(), fileContent, newContent).trim(); + if (fileContent != newFileContent) { + this.app.vault.modify(file, newFileContent); + const notice = new import_obsidian2.Notice("Paragraph moved to " + section + ".\n\u{1F517} Open source note.", 5e3); + this.removeElementWithAnimation(paragraphEl, () => { + setTimeout(async () => { + this.updateSummary(summaryEl); + paragraphEl.remove(); + }, 500); + setTimeout(async () => { + this.processTags(); + }, 800); + }); + this.registerDomEvent(notice.noticeEl, "click", (e2) => { + this.app.workspace.openLinkText(filePath, ""); + }); + } else { + new import_obsidian2.Notice("Tag Buddy: Paragraph copied to " + section + ".\nBut can't update source file."); + } + } else { + new import_obsidian2.Notice("Tag Buddy: Paragraph copied to " + section + "."); + } + } else { + } + }); + button.title = "Copy paragraph to " + section + ".\n" + this.ctrlCmdStr() + "+CLICK to remove tag(s) then copy.\n"; + button.title += "SHIFT+" + this.ctrlCmdStr() + "+CLICK to remove tags from source note paragraph."; + return button; + } + makeBakeButton(summaryMd, summaryEl, filePath) { + const button = this.makeButton("Bake", async (e) => { + e.stopPropagation(); + const mdSource = summaryEl.getAttribute("codeblock-code"); + if (mdSource) { + const file = this.app.vault.getAbstractFileByPath(filePath); + const fileContent = await this.app.vault.read(file); + const newFileContent = this.replaceTextInString(mdSource, fileContent, summaryMd); + this.app.vault.modify(file, newFileContent); + const notice = new import_obsidian2.Notice("Tag summary flattened to active note."); + } else { + new import_obsidian2.Notice("\u26A0\uFE0F Tag Buddy: Can find code block source. This is a BUG."); + } + }); + button.title = "Flatten summary (replaces code block)."; + return button; + } + makeCopyButton(content) { + const button = this.makeButton(" \u274F ", (e) => { + e.stopPropagation(); + navigator.clipboard.writeText(content); + const notice = new import_obsidian2.Notice("Tag Buddy: Copied to clipboard."); + }); + button.title = "Copy paragraph"; + return button; + } + ctrlCmdStr() { + const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0; + if (isMac) + return "CMD"; + else + return "CTRL"; + } + /*tagsInString (string:string, tag:string=''):Array { + const regex = new RegExp(tag.replace(/\//g, '\\/') + "(?![\\w\\/\\#])", "g"); + const matches = string.match(regex); + console.log(matches) + return matches || []; //matches ? matches.length : 0; + }*/ + tagsInString(string, tag) { + let regex; + if (tag) { + regex = new RegExp(tag.replace(/\//g, "\\/") + "(?![\\w\\/\\#])", "g"); + } else { + regex = /#(\w+)(?![\w\/#])/g; + } + const matches = string.match(regex); + return matches || []; + } + countOccurrences(summaryTags, contentTags) { + let count = 0; + for (let tag of summaryTags) { + count += contentTags.filter((item) => item === tag).length; + } + return count; + } + makeRemoveTagButton(paragraphEl, tag, filePath) { + const button = this.makeButton(" \u2317\u02E3 ", (e) => { + e.stopPropagation(); + const tagEl = this.getTagElement(paragraphEl, tag); + this.editTag(tagEl); + }); + button.title = "Remove " + tag + " from paragraph (and from this summary)."; + return button; + } + removeElementWithAnimation(el, callback) { + const height = el.offsetHeight; + el.style.height = `${height}px`; + setTimeout(() => { + el.style.height = "0px"; + el.style.opacity = "0"; + el.style.margin = "0"; + el.style.padding = "0"; + }, 0); + el.addEventListener("transitionend", function onEnd() { + el.removeEventListener("transitionend", onEnd); + callback(); + }); + } + makeButton(lable, clickFn, classId = "tagsummary-button") { + const button = document.createElement("button"); + button.innerText = lable; + button.className = classId; + this.registerDomEvent(button, "click", clickFn.bind(this)); + return button; + } + getMarkdownHeadings(bodyLines) { + const headers = []; + let accumulatedIndex = 0; + bodyLines.forEach((line, index) => { + const match = line.match(/^(#+)[\s]?(.*)$/); + if (match) { + headers.push({ + fullText: match[0], + level: match[1].length, + text: match[2], + line: index, + startIndex: accumulatedIndex, + endIndex: accumulatedIndex + match[0].length - 1 + }); + } + accumulatedIndex += line.length + 1; + }); + return headers; + } + getLinesInString(input) { + const lines = []; + let tempString = input; + while (tempString.includes("\n")) { + const lineEndIndex = tempString.indexOf("\n"); + lines.push(tempString.slice(0, lineEndIndex)); + tempString = tempString.slice(lineEndIndex + 1); + } + lines.push(tempString); + return lines; + } + insertTextAfterLine(text, body, line, filePath) { + const splitContent = body.split("\n"); + const pre = splitContent.slice(0, line + 1).join("\n"); + const post = splitContent.slice(line + 1).join("\n"); + return `${pre} +${text} +${post}`; + } + async copyTextToSection(text, section, filePath) { + const file = await this.app.workspace.getActiveFile(); + const fileContent = await this.app.vault.read(file); + const fileContentLines = this.getLinesInString(fileContent); + const mdHeadings = this.getMarkdownHeadings(fileContentLines); + if (mdHeadings.length > 0) { + const headingObj = mdHeadings.find((heading) => heading.text.trim() === section); + if (headingObj) { + const textWithLink = text + ` [[${filePath}|\u{1F517}]]`; + let newContent = this.insertTextAfterLine(textWithLink, fileContent, headingObj.line); + await this.app.vault.modify(file, newContent); + return true; + } else { + new import_obsidian2.Notice(`Tag Buddy: ${section} not found.`); + return false; + } + } else { + new import_obsidian2.Notice("Tag Buddy: There are no header sections in this note."); + return false; + } + } + removeTagFromString(inputText, hashtagToRemove, all = true) { + const regex = new RegExp("\\s?" + hashtagToRemove.replace(/#/g, "\\#") + "(?!\\w|\\/)", all ? "gi" : "i"); + return inputText.replace(regex, "").trim(); + } + /*getSectionTitleWithHashes(sectionTitle) { + const activeView = this.app.workspace.getActiveViewOfType(MarkdownView); + if (!activeView) { + console.log('No active markdown view found.'); + return null; + } + + const contentEl = activeView.contentEl; + + // Get all heading elements + // This doesn't work with super long notes. + const headings = contentEl.querySelectorAll('h1, h2, h3, h4, h5, h6'); + //const headings = await contentEl.getElementsByClassName('h1, h2, h3, h4, h5, h6'); + + //console.log(headings) + for (const heading of headings) { + if (heading.textContent.trim() === sectionTitle.trim()) { + // Determine the number of hashes based on the heading level + const level = parseInt(heading.tagName.substr(1), 10); // e.g., "H2" -> 2 + const hashes = '#'.repeat(level); + //console.log(heading); + return {md:`${hashes} ${sectionTitle}`, el:heading}; + } + } + + console.log(`Section "${sectionTitle}" not found.`); + return null; + }*/ + truncateStringAtWord(str, maxChars) { + if (str.length <= maxChars) + return str; + let truncated = str.substr(0, maxChars); + const lastSpace = truncated.lastIndexOf(" "); + if (lastSpace > 0) + truncated = truncated.substr(0, lastSpace); + return truncated; + } + async readFiles(listFiles) { + let list = []; + for (let t = 0; t < listFiles.length; t += 1) { + const file = listFiles[t]; + let content = await this.app.vault.cachedRead(file); + list.push([file, content]); + } + return list; + } + isValidText(listTags, tags, include, exclude) { + let valid = true; + if (tags.length > 0) { + valid = valid && tags.some((value) => listTags.includes(value)); + } + if (include.length > 0) { + valid = valid && include.every((value) => listTags.includes(value)); + } + if (valid && exclude.length > 0) { + valid = !exclude.some((value) => listTags.includes(value)); + } + return valid; + } + async validateFilePath(filePath) { + const matchingFiles = await app.vault.getFiles().filter((file) => file.name === filePath); + if (matchingFiles.length === 1) { + const filePath2 = matchingFiles[0].path; + const file = await this.app.vault.getAbstractFileByPath(filePath2); + return file; + } else if (matchingFiles.length > 1) { + new import_obsidian2.Notice("Tag Buddy: Multiple files found with the same name. Can't safely edit tag."); + return null; + } else { + new import_obsidian2.Notice("Tag Buddy: No file found. Try again, or this tag might be in an unsupported embed type."); + return null; + } + } + contentChangedTooMuch(original, modified, tag, buffer = 5) { + const expectedChange = tag.length; + const threshold = expectedChange + buffer; + const actualChange = Math.abs(original.length - modified.length); + return actualChange > threshold; + } + async loadSettings() { + this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); + } + async saveSettings() { + await this.saveData(this.settings); + } + isTagValid(tag) { + const tagPattern = /^#[\w]+$/; + return tagPattern.test(tag); + } + saveRecentTag(tag) { + if (this.isTagValid(tag)) { + const recentTagsString = this.settings.recentlyAddedTags; + let recentTags; + if (recentTagsString == "") { + recentTags = []; + } else if (recentTagsString.indexOf(", ")) { + recentTags = this.settings.recentlyAddedTags.split(", "); + } else { + recentTags = [this.settings.recentlyAddedTags]; + } + if (recentTags.includes(tag)) { + recentTags.splice(recentTags.indexOf(tag), 1); + } + recentTags.unshift(tag.trim()); + recentTags = recentTags.slice(0, 3); + this.settings.recentlyAddedTags = recentTags.join(", "); + this.saveSettings(); + } + } + getRecentTags() { + const recentTags = this.settings.recentlyAddedTags == "" ? [] : this.settings.recentlyAddedTags.split(", "); + return recentTags; + } + // fuck.this.function + /*cleanString(input) { + let cleanedStr; + + // Check if input is a DOM element + if (input instanceof Element) { + //console.log('input is: Element'); + cleanedStr = input.outerHTML.trim(); + } else { + //console.log('input is: String'); + cleanedStr = input.trim(); + } + + // Whitespace normalization + //cleanedStr = cleanedStr.replace(/\s+/g, ' '); + + // Remove
elements + //cleanedStr = cleanedStr.replace(/
/g, ' '); + + // Remove blockquote tags but keep their content + //cleanedStr = cleanedStr.replace(/<\/?blockquote>/g, ''); + + // Remove blockquote tags but keep their content + //cleanedStr = cleanedStr.replace(/<\/?div>/g, ''); + + // Remove spaces between tags + //cleanedStr = cleanedStr.replace(/>\s+<'); + + // Whitespace normalization + cleanedStr = cleanedStr.replace(/\s+/g, ' '); + + // HTML entity decoding + const textArea = document.createElement('textarea'); + textArea.innerHTML = cleanedStr; + cleanedStr = textArea.value.trim(); + + // Optional: convert to lowercase + // cleanedStr = cleanedStr.toLowerCase(); + + return cleanedStr; + }*/ + /*async refreshView (){ + //console.log('Refresh view.'); + new Notice ('Refresh view.'); + // if using rerender, + //const scrollState = this.app.workspace.getActiveViewOfType(MarkdownView)?.currentMode?.getScroll(); + //await view.previewMode.rerender(true); + + await app.workspace.activeLeaf.rebuildView(); + // only needed if we use rerender above. do this on a timeout + //this.app.workspace.getActiveViewOfType(MarkdownView).previewMode.applyScroll(scrollState); + }*/ + injectStyles() { + const styles = ` + .tagsummary-notags { + color: var(--link-color) !important; + font-weight: 500 !important; + border: 1px solid var(--link-color) !important; + border-radius: 5px !important; + padding: 10px 10px; + } + + .tagsummary-button { + + color: var(--text-primary) !important; + /*border: .5px solid var(--text-quote) !important;*/ + border-radius: 6px !important; + padding: 2.5px 5px !important; + font-size: 65% !important; + transition: background-color 0.3s !important; + margin: 0px 3px 0px 0px !important; + min-width: 40px !important; + + color: var(--link-color) !important; + border: 1px solid var(--link-color) !important; + background-color: var(--background-primary) !important; + + } + + .tagsummary-button:hover { + background-color: var(--link-color) !important; + color: var(--background-secondary) !important; + } + + .tagsummary-item-title { + margin: 5px 0px + } + + .tagsummary-buttons { + /*float: right;*/ + text-align: right !important; + } + + blockquote.tag-summary-paragraph { + transition: height 0.3s, opacity 0.3s; + /*transition: height 0.3s ease, margin 0.3s ease, padding 0.3s ease, opacity 0.3s ease;*/ + overflow: hidden; + } + + .removing { + height: 0 !important; + opacity: 0; + margin: 0; + padding: 0; + } + + @media only screen and (max-device-width: 480px), + only screen and (max-width: 480px) and (orientation: landscape), + only screen and (max-device-width: 1024px), + only screen and (min-width: 481px) and (max-width: 1024px) and (orientation: landscape) { + .tagsummary-button { + display: inline-block !important; + font-size: 12px !important; + padding: 5px 5px; + box-shadow: none; /* remove shadows if they look off */ + border-radius: 4px; + color: var(--link-color) !important; + border: 1px solid var(--link-color); + width: auto !important; /* auto adjusts width based on content */ + /*max-width: 60px !important; */ + max-height: 30px !important; + min-width: 40px !important; + white-space: nowrap; + /*text-align: left !important;*/ + overflow: hidden; + background-color: var(--background-primary) !important; + } + } + + .addtag-menu { + position: absolute !important; + background-color: var(--background-primary) !important; + /*color: white !important;*/ + border: 2px solid var(--divider-color) !important; + z-index: 10000 !important; + overflow-y: auto !important; + /*max-height: 150px !important;*/ + width: 150px !important; + box-shadow: 5px 5px 20px rgba(0, 0, 0, 0.5) !important; + border-radius: 8px !important; + font-family: Arial, sans-serif; + font-size: 12px !important; + overflow: hidden !important; // Hide overflow + padding-right: 10px !important; // Adjust padding to make space for scrollbar + box-sizing: border-box !important; + + border-radius: 10px !important; + + } + + .tag-list { + overflow-y: auto !important; + overflow-x: hidden !important; + /*padding-right: 8px !important; // Adjust padding to give space for scrollbar + /*margin-right: -8px !important; // Adjust margin to move scrollbar into the padding*/ + box-sizing: border-box !important; + } + + .tag-item { + padding: 5px 10px 5px 10px !important; + cursor: pointer !important; + /* border-bottom: 1px solid var(--divider-color) !important; // Separator line*/ + font-size: 14px !important; + /*width: 130px !important;*/ + width: 100% !important; + /*height: 20px !important;*/ + text-overflow: ellipsis !important; + white-space: nowrap !important; + box-sizing: border-box !important; + + + transition: background-color 0.2s ease !important; + border-radius: 5px !important; + } + + .tag-item:hover { + background-color: var(--background-modifier-hover) !important; // Added ,1 for opacity + /*color: white !important;*/ + } + .tag-item.active { + background-color: var(--background-modifier-hover) !important; + /*background-color: var(--interactive-accent) !important;*/ + /*color: white !important;*/ + } + + #addtag-menu .disable-hover .tag-item:hover { + background-color: inherit !important; + color: inherit !important; + } + + .tag-search { + width: 100% !important; + padding: 2.5px 5px !important; + border: none !important; + font-family: Arial, sans-serif; + font-size: 14px !important; + } + + .tag-search:focus { + outline: none !important; + border: none !important; + border-bottom: 0px !important; + box-shadow: none !important; + outline-style: none !important; + outline-width: 0px !important; + + + } + + `; + const styleSheet = createEl("style"); + styleSheet.type = "text/css"; + styleSheet.innerText = styles; + styleSheet.id = "tag-buddy-styles"; + document.head.appendChild(styleSheet); + } + async getEmbedFile(el) { + let filePath = el.getAttribute("src"); + const linkArray = filePath.split("#"); + filePath = linkArray[0].trim() + ".md"; + const file = await this.validateFilePath(filePath); + return file; + } + async getSummaryFile(el) { + const filePath = el.getAttribute("file-source"); + const file = await this.app.vault.getAbstractFileByPath(filePath); + return file; + } + showTagSelector(x, y) { + const maxTagContainerHeight = 170; + const tagItemHeight = 30; + const existingMenu = document.getElementById("addtag-menu"); + if (existingMenu) + existingMenu.remove(); + const menuEl = createEl("div"); + menuEl.setAttribute("id", "addtag-menu"); + menuEl.classList.add("addtag-menu"); + menuEl.style.left = `${x}px`; + menuEl.style.top = `${y}px`; + const searchEl = createEl("input"); + searchEl.setAttribute("type", "text"); + searchEl.setAttribute("id", "tag-search"); + searchEl.classList.add("tag-search"); + searchEl.setAttribute("placeholder", "Search tags..."); + menuEl.appendChild(searchEl); + const tagContainer = createEl("div"); + tagContainer.classList.add("tag-list"); + tagContainer.style.setProperty("max-height", `${maxTagContainerHeight}px`, "important"); + menuEl.appendChild(tagContainer); + const renderTags = (searchQuery) => { + tagContainer.innerHTML = ""; + const filteredTags = this.getTagsFromApp().filter((tag) => tag.toLowerCase().includes(searchQuery.toLowerCase())); + const dynamicHeight = Math.min(filteredTags.length * tagItemHeight, maxTagContainerHeight); + filteredTags.forEach((tag, index) => { + const itemEl = createEl("div"); + itemEl.innerText = `${tag}`; + itemEl.classList.add("tag-item"); + itemEl.title = `#${tag}`; + if (index === 0) { + itemEl.classList.add("active"); + } + itemEl.style.setProperty("max-height", `${dynamicHeight}px`, "important"); + this.registerDomEvent(itemEl, "click", (e) => { + this.addTag("#" + tag, x, y); + menuEl.remove(); + }, true); + tagContainer.appendChild(itemEl); + }); + if (filteredTags.length * tagItemHeight > maxTagContainerHeight) { + tagContainer.style.overflowY = "auto !important"; + } else { + tagContainer.style.overflowY = "hidden !important"; + } + }; + this.registerDomEvent(searchEl, "keyup", (e) => { + const searchQuery = e.target.value.trim(); + const pattern = /^[^\s\p{P}]+$/u; + if (e.key === "Enter") { + const activeTag = tagContainer.querySelector(".active"); + if (activeTag) { + this.addTag("#" + activeTag.innerText, x, y); + } else if (pattern.test(searchQuery)) { + this.addTag("#" + searchQuery, x, y); + } + menuEl.remove(); + } + }); + renderTags(""); + searchEl.addEventListener("input", (e) => { + renderTags(e.target.value); + }); + document.body.appendChild(menuEl); + searchEl.focus(); + const closeMenu = (e) => { + if (e instanceof MouseEvent && (e.button === 0 || e.button === 2)) { + if (!menuEl.contains(e.target)) { + menuEl.remove(); + document.body.removeEventListener("click", closeMenu); + document.body.removeEventListener("contextmenu", closeMenu); + document.body.removeEventListener("keyup", closeMenu); + } + } else if (e instanceof KeyboardEvent && e.key === "Escape") { + menuEl.remove(); + document.body.removeEventListener("click", closeMenu); + document.body.removeEventListener("contextmenu", closeMenu); + document.body.removeEventListener("keyup", closeMenu); + } + }; + setTimeout(() => { + this.registerDomEvent(document.body, "click", closeMenu); + this.registerDomEvent(document.body, "contextmenu", closeMenu); + this.registerDomEvent(document.body, "keyup", closeMenu); + }, 0); + this.registerDomEvent(tagContainer, "mousemove", () => { + tagContainer.classList.remove("disable-hover"); + const activeTag = tagContainer.querySelector(".tag-item.active"); + if (activeTag) { + activeTag.classList.remove("active"); + } + }); + this.registerDomEvent(searchEl, "blur", () => { + tagContainer.classList.remove("disable-hover"); + }); + this.registerDomEvent(searchEl, "keydown", (e) => { + const activeTag = tagContainer.querySelector(".active"); + let nextActiveTag; + if (["ArrowUp", "ArrowDown"].includes(e.key) || e.key.length === 1) { + tagContainer.classList.add("disable-hover"); + } + if (e.key === "ArrowDown") { + if (activeTag && activeTag.nextElementSibling) { + nextActiveTag = activeTag.nextElementSibling; + } else { + nextActiveTag = tagContainer.firstChild; + } + } else if (e.key === "ArrowUp") { + if (activeTag && activeTag.previousElementSibling) { + nextActiveTag = activeTag.previousElementSibling; + } else { + nextActiveTag = tagContainer.lastChild; + } + } else if (e.key === "Enter") { + } + if (nextActiveTag) { + if (activeTag) { + activeTag.classList.remove("active"); + } + nextActiveTag.classList.add("active"); + nextActiveTag.scrollIntoView({ block: "nearest" }); + searchEl.value = nextActiveTag.innerText; + } + }); + } + async addTag(tag, x, y) { + if (this.settings.debugMode) { + console.log("Tag Buddy add"); + console.log(x, y, tag); + } + let fileContent; + let file; + const clickedTextObj = this.getClickedTextObjFromDoc(x, y); + const clickedText = clickedTextObj == null ? void 0 : clickedTextObj.text; + const clickedTextIndex = clickedTextObj == null ? void 0 : clickedTextObj.index; + const clickedTextEl = clickedTextObj == null ? void 0 : clickedTextObj.el; + let contentSourceType = null; + let summaryEl; + let embedEl; + if (clickedTextObj) { + summaryEl = clickedTextEl.closest(".tag-summary-paragraph"); + embedEl = clickedTextEl.closest(".markdown-embed"); + if (summaryEl) { + file = await this.getSummaryFile(summaryEl); + fileContent = await this.app.vault.read(file); + contentSourceType = "plugin-summary"; + } else if (embedEl) { + file = await this.getEmbedFile(embedEl); + fileContent = await this.app.vault.read(file); + contentSourceType = "native-embed"; + } else { + file = await this.app.workspace.getActiveFile(); + fileContent = await this.app.vault.read(file); + contentSourceType = "active"; + } + } else { + new import_obsidian2.Notice("\u26A0\uFE0F Can't find text position or area too busy.\nTry a another text area."); + return; + } + if (clickedText) { + } else { + new import_obsidian2.Notice("\u26A0\uFE0F Can't add tag.\nTry a different text area."); + return; + } + const escapedClickedText = this.escapeRegExp(clickedText); + const regex = new RegExp(escapedClickedText, "g"); + const matches = fileContent.match(regex); + if (matches && matches.length > 1) { + new import_obsidian2.Notice("\u26A0\uFE0F Can't add tag: Clicked text repeated in note. Try a another text block."); + return; + } else if (matches && matches.length === 0 || !matches) { + new import_obsidian2.Notice("\u26A0\uFE0F Can't find text position or area too busy.\nTry a another text area."); + return; + } + if (!this.settings.lockRecentTags) + this.saveRecentTag(tag); + const startIndex = regex.exec(fileContent).index; + const endIndex = startIndex + clickedText.length - 1; + const clickedWordObj = this.getWordObjFromString(clickedText, clickedTextIndex); + const clickedWord = clickedWordObj.text; + const clickedWordIndex = clickedWordObj.index; + const newContent = this.insertTextInString(tag, fileContent, startIndex + clickedWordIndex); + await this.app.vault.modify(file, newContent); + if (contentSourceType == "plugin-summary") { + const summaryContainer = summaryEl.closest(".tag-summary-block"); + this.updateSummary(summaryContainer); + } + setTimeout(async () => { + this.processTags(); + }, 200); + } + replaceTextInString(replaceText, sourceText, newText, all = false) { + const regex = new RegExp(this.escapeRegExp(replaceText), all ? "gi" : "i"); + return sourceText.replace(regex, newText).trim(); + } + // I removed .trim() from the before and after to fix the add bug. + insertTextInString(newText, sourceText, charPos) { + return sourceText.substring(0, charPos) + " " + newText + " " + sourceText.substring(charPos); + } + removeTextFromString(removeText, sourceText, all = false) { + const regex = new RegExp(this.escapeRegExp(removeText), all ? "gi" : "i"); + return sourceText.replace(regex, "").trim(); + } + getWordObjFromString(sourceText, offset) { + let wordRegex = /[^\s]+(?=[.,:!?]?(\s|$))/g; + let match; + let index; + let word = null; + while ((match = wordRegex.exec(sourceText)) !== null) { + if (match.index <= offset && offset <= match.index + match[0].length) { + word = match[0]; + index = match.index; + break; + } + } + return { text: word, index }; + } + getClickedTextObjFromDoc(x, y, minNodeLength = 10) { + let range, nodeText, offset; + if (document.caretRangeFromPoint) { + range = document.caretRangeFromPoint(x, y); + if (range.startContainer.nodeType === Node.TEXT_NODE) { + nodeText = range.startContainer.nodeValue.trim(); + } else { + return null; + } + offset = range.startOffset; + } + if (nodeText.length < minNodeLength) { + return null; + } + return { text: nodeText, index: offset, el: range.startContainer.parentNode }; + } + /*async getClickedWord(e) { + //Get the click position + let x = e.clientX, y = e.clientY; + + // Get the word under the click position + let range, textNode, offset; + + // This method is better supported and gives us a range object + if (document.caretRangeFromPoint) { + range = document.caretRangeFromPoint(x, y); + textNode = range.startContainer; + offset = range.startOffset; + } + //console.log(textNode) + + // LATER, double check different notes types and around the interface + + // Check if we have a valid text node + if (textNode && textNode.nodeType === Node.TEXT_NODE) { + // Get the whole text of the clicked node + let fullText = textNode.textContent; + + // LATER: if the word end in valid punctuation, add a space between word and punctuation it when adding the hash. + // LATER, have predefined tags we can insert with different key modifiers on click + // like, #todo or #inbox #later + + let wordRegex = /[^\s]+(?=[.,:!?]?(\s|$))/g; + let match; + let clickedWord = null; + while ((match = wordRegex.exec(fullText)) !== null) { + if (match.index <= offset && offset <= match.index + match[0].length) { + // This is our word + if (!/^[^\p{L}\p{N}]/u.test(match[0]) && // Not starting with any non-alphanumeric + !/[^\p{L}\p{N}\s.,:!?]/u.test(match[0]) && // Not containing other than allowed chars + !/[.,:!?](?=[^\s$])/u.test(match[0])) { // If ends with punctuation, following character must be whitespace or end of string + clickedWord = match[0]; + break; + } + } + } + + + let activeView = await this.app.workspace.getActiveViewOfType(MarkdownView); + + + let editor = activeView.sourceMode.cmEditor; // Get the CodeMirror instance + let fullNote = editor.getValue(); + + const globalStartPosition = fullNote.indexOf(textNode.textContent); + + if (globalStartPosition !== -1) { + // Assuming the click was right at the end of the word + let wordEndPosition = globalStartPosition + offset; + + // Traverse backward until a space or start + while (wordEndPosition > 0 && fullNote[wordEndPosition] !== ' ' && fullNote[wordEndPosition] !== '\n') { + wordEndPosition--; + } + + wordEndPosition++; + + // Insert hash at wordEndPosition + const updatedNote = [fullNote.slice(0, wordEndPosition), '#', fullNote.slice(wordEndPosition)].join(''); + console.log(updatedNote); + } + + + } + + // LATER, to make this work in embeds and summaries + // and avoid adding when in the summary empty block. or other code blocks. maybe this check is earlier. + }*/ + escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); + } + getTagsFromApp() { + const tagsObject = this.app.metadataCache.getTags(); + const tagsArray = Object.entries(tagsObject); + tagsArray.sort((a, b) => b[1] - a[1]); + const recentTags = this.getRecentTags(); + if (recentTags.length > 0) { + const recentTagsAsTuples = recentTags.map((tag) => [tag, 0]); + const recentAndAllTags = recentTagsAsTuples.concat(tagsArray); + return recentAndAllTags.map(([tag, _]) => tag.replace(/^#/, "")); + } else { + return tagsArray.map(([tag, _]) => tag.replace(/^#/, "")); + } + } + getTagElement(paragraphEl, tagText) { + const els = paragraphEl.querySelectorAll(".tag"); + let tagElText = ""; + let tagElHasSub; + for (let el of els) { + tagElText = el.innerText.trim(); + if (tagElText === tagText) { + return el; + } + } + console.warn(`Element with text "${tagText}" not found`); + return null; + } + ctrlCmdKey(event) { + const isMac = navigator.platform.toUpperCase().indexOf("MAC") >= 0; + if (isMac) + return event.metaKey; + else + return event.ctrlKey; + } + debounce(func, wait) { + let timeout; + return function(...args) { + const context = this; + clearTimeout(timeout); + timeout = setTimeout(() => { + func.apply(context, args); + }, wait); + }; + } +}; +var TempComponent = class extends import_obsidian2.Component { + onload() { + } + onunload() { + } +}; +var DoubleTapHandler = class { + constructor(plugin, element, callback) { + this.plugin = plugin; + this.element = element; + this.callback = callback; + this.lastTap = 0; + this.plugin.registerDomEvent(this.element, "touchend", this.handleTouchEnd.bind(this), true); + } + handleTouchEnd(event) { + const currentTime = new Date().getTime(); + const tapLength = currentTime - this.lastTap; + clearTimeout(this.timeout); + if (tapLength < 500 && tapLength > 0) { + this.callback(event); + } else { + this.timeout = setTimeout(() => { + clearTimeout(this.timeout); + }, 500); + } + this.lastTap = currentTime; + } +}; +var PressAndHoldHandler = class { + constructor(plugin, element, callback, duration = 600) { + this.plugin = plugin; + this.element = element; + this.callback = callback; + this.duration = duration; + this.timeout = null; + this.plugin.registerDomEvent(this.element, "touchstart", this.handleTouchStart.bind(this), true); + this.plugin.registerDomEvent(this.element, "touchend", this.handleTouchEnd.bind(this), true); + } + handleTouchStart(event) { + this.timeout = setTimeout(() => { + this.callback(event); + this.timeout = null; + }, this.duration); + } + handleTouchEnd(event) { + if (this.timeout) { + clearTimeout(this.timeout); + this.timeout = null; + } + } +}; +//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsibWFpbi50cyIsICJzZXR0aW5ncy50cyJdLAogICJzb3VyY2VzQ29udGVudCI6IFsiaW1wb3J0IHsgVEJTZXR0aW5nc1RhYiB9IGZyb20gXCIuL3NldHRpbmdzXCI7XG5pbXBvcnQgeyBBcHAsIGRlYm91bmNlLCBFZGl0b3IsIE1hcmtkb3duUmVuZGVyZXIsIENvbXBvbmVudCwgVEZpbGUsIGdldEFsbFRhZ3MsIE1hcmtkb3duVmlldywgTW9kYWwsIE5vdGljZSwgUGx1Z2luLCBQbHVnaW5TZXR0aW5nVGFiLCBTZXR0aW5nIH0gZnJvbSAnb2JzaWRpYW4nO1xuXG5pbXBvcnQgeyBnZXRUYWdzRnJvbUFwcCB9IGZyb20gJy4vdXRpbHMnO1xuLy9pbXBvcnQgeyBzaG93VGFnU2VsZWN0b3IgfSBmcm9tICcuL3VpJzsgLy8gbmVlZCB0byBnaXZlIHRoZXNlIGZpbGVzIHJlZmVyZW5jZSB0byB0aGUgcGx1Z2luXG5pbnRlcmZhY2UgVEJTZXR0aW5ncyB7XG5cdHJlbW92ZU9uQ2xpY2s6IGJvb2xlYW47IC8vIGN0cmxcblx0cmVtb3ZlQ2hpbGRUYWdzRmlyc3Q7IC8vIFxuXHRvcHRUb0NvbnZlcnQ6IGJvb2xlYW47IC8vYWx0XG5cdG1vYmlsZVRhZ1NlYXJjaDogYm9vbGVhbjsgXG5cdG1vYmlsZU5vdGljZXM6IGJvb2xlYW47IFxuXHR0YWdTdW1tYXJ5QmxvY2tCdXR0b25zOiBib29sZWFuOyBcblx0dGFnZ2VkUGFyYWdyYXBoQ29weVByZWZpeDogc3RyaW5nO1xuXHRyZWNlbnRseUFkZGVkVGFnczogc3RyaW5nO1xuXHRsb2NrUmVjZW50VGFnczogYm9vbGVhbjtcblx0c2hvd1N1bW1hcnlCdXR0b25zOmJvb2xlYW47XG5cdGRlYnVnTW9kZTogYm9vbGVhbjtcbn1cblxuY29uc3QgREVGQVVMVF9TRVRUSU5HUzogUGFydGlhbDxUQlNldHRpbmdzPiA9IHtcblx0cmVtb3ZlT25DbGljazogdHJ1ZSwgLy8gd2hlbiB0cnVlLCBjbWQgaXMgbmVlZGVkIHdoZW4gY2xpY2tpbmcgdG8gcmVtb3ZlIHRoZSB0YWdcblx0cmVtb3ZlQ2hpbGRUYWdzRmlyc3Q6IHRydWUsIC8vIHVzZSBzaGlmdCB3aGVuIGZhbHNlXG5cdG9wdFRvQ29udmVydDogdHJ1ZSwgLy8gd2hlbiBmYWxzZSwgY2xpY2tpbmcgdGFnIHdpbGwgZG8gbm90aGluZ1xuXHRtb2JpbGVUYWdTZWFyY2g6IGZhbHNlLCAvLyB0b2dnbGUgb24gdXNlIGRvdWJsZSB0YXAgZm9yIHNlYXJjaC4gcHJlc3MraG9sZCB3aWxsIHRoZW4gcmVtb3ZlLlxuXHRtb2JpbGVOb3RpY2VzOiB0cnVlLFxuXHR0YWdTdW1tYXJ5QmxvY2tCdXR0b25zOiBmYWxzZSxcblx0dGFnZ2VkUGFyYWdyYXBoQ29weVByZWZpeDogJycsXG5cdHJlY2VudGx5QWRkZWRUYWdzOiAnJyxcblx0bG9ja1JlY2VudFRhZ3M6IGZhbHNlLFxuXHRzaG93U3VtbWFyeUJ1dHRvbnM6ZmFsc2UsXG5cdGRlYnVnTW9kZTogZmFsc2UsXG59OyBcblxuZXhwb3J0IGRlZmF1bHQgY2xhc3MgVGFnQnVkZHkgZXh0ZW5kcyBQbHVnaW4geyAgXG5cdHNldHRpbmdzOiBUQlNldHRpbmdzO1xuXG5cdG9udW5sb2FkKCkgeyAvLyBJIHRoaW5rIGFsbCB0aGUgY2xlYW51cCBpcyBkb25lIGF1dG9tYXRpY2FsbHkgdGhlIHdheSBJIHJlZ2lzdGVyIGV2ZXJ0aGluZy4gXG5cdH0gXG5cblx0YXN5bmMgb25sb2FkKCkge1xuXHRcdGF3YWl0IHRoaXMubG9hZFNldHRpbmdzKCk7XG5cdFx0dGhpcy5hZGRTZXR0aW5nVGFiKG5ldyBUQlNldHRpbmdzVGFiKHRoaXMuYXBwLCB0aGlzKSk7XHRcblx0XHRcblx0XHRjb25zb2xlLmxvZygnVGFnIEJ1ZGR5IFBsdWdpbiBsb2FkZWQgb24gJyArICh0aGlzLmFwcC5pc01vYmlsZT8nbW9iaWxlIGF0ICc6J2Rlc2t0b3AgYXQgJykgKyBuZXcgRGF0ZSgpLnRvVVRDU3RyaW5nKCkuc3Vic3RyaW5nKDE3KSk7XG5cdFx0XG5cdFx0dGhpcy5pbmplY3RTdHlsZXMoKTtcblxuXHRcdGNvbnN0IGRlYm91bmNlZFByb2Nlc3NUYWdzID0gdGhpcy5kZWJvdW5jZSh0aGlzLnByb2Nlc3NUYWdzLmJpbmQodGhpcyksIDUwMCk7XG5cblx0XHR0aGlzLmFwcC53b3Jrc3BhY2Uub25MYXlvdXRSZWFkeShhc3luYyAoKSA9PiB7XG5cblx0XHRcdC8vIE5lZWQgdG8gZmlndXJlIG91dCBob3cgdG8gZ2V0IHRoZSBjdXJyZW50IG1vdXNlIHBvc2l0aW9uXG5cdFx0XHQvKnRoaXMuYWRkQ29tbWFuZCh7XG5cdFx0XHQgICAgaWQ6ICdvcGVuLXRhZy1zZWxlY3RvcicsXG5cdFx0XHQgICAgbmFtZTogJ1RhZyBCdWRkeTogQWRkIHRhZyBhdCBtb3VzZSBwb3NpdGlvbicsXG5cdFx0XHQgICAgY2FsbGJhY2s6IChldmVudCkgPT4ge1xuXHRcdFx0ICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG5cdFx0XHQgICAgICAgICAgICBjb25zdCB4ID0gZXZlbnQuY2xpZW50WDtcblx0XHRcdCAgICAgICAgICAgIGNvbnN0IHkgPSBldmVudC5jbGllbnRZO1xuXHRcdFx0ICAgICAgICAgICAgdGhpcy5zaG93VGFnU2VsZWN0b3IoeCwgeSk7XG5cdFx0XHQgICAgICAgIH0sIDUwKTtcblx0XHRcdCAgICB9XG5cdFx0XHR9KTsqLyBcblxuXHRcdFx0Ly8gdGhpcy5yZWxvYWQoKTsgLy8gbm8gbmVlZCBmb3IgdGhpcyBhdG0uXG5cdFx0XHRzZXRUaW1lb3V0KGFzeW5jICgpID0+IHsgdGhpcy5wcm9jZXNzVGFncygpOyB9LCA1MDApXG5cdFx0XHRcblxuXHRcdCAgICB0aGlzLnJlZ2lzdGVyRXZlbnQoIHRoaXMuYXBwLndvcmtzcGFjZS5vbignYWN0aXZlLWxlYWYtY2hhbmdlJywgYXN5bmMgKCkgPT4geyBcblx0XHQgICAgXHQvL2NvbnNvbGUubG9nKCdhY3RpdmUgbGVhZiBjaGFuZ2UnKTsgXG5cdCAgICBcdFx0XG5cdCAgICBcdFx0Lyp0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoZG9jdW1lbnQsICdjb250ZXh0bWVudScsIGFzeW5jIChldmVudDogTW91c2VFdmVudCkgPT4ge1xuXHQgICAgXHRcdFx0Y29uc3QgdmlldyA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVWaWV3T2ZUeXBlKE1hcmtkb3duVmlldyk7XG5cdFx0XHQgICAgICAgIGlmICh2aWV3ICYmIHRoaXMuY3RybENtZEtleSAoZXZlbnQpICYmICh2aWV3LmdldE1vZGUoKSA9PSAncHJldmlldycpKSB7XG5cdFx0XHQgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0ICAgICAgICAgICAgY29uc29sZS5sb2coJ3JpZ2h0IGNsaWNrJylcblx0XHRcdCAgICAgICAgICAgIGNvbnN0IGZpbGUgPSBhd2FpdCB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xuXG5cdFx0XHQgICAgICAgICAgICB0aGlzLnNob3dUYWdTZWxlY3RvcihldmVudC5wYWdlWCwgZXZlbnQucGFnZVksIGZpbGUpO1xuXHRcdFx0ICAgICAgICB9XG5cdFx0XHQgICAgfSk7Ki9cblx0XHQgICAgfSkpO1xuXG5cblx0XHQgICAgdGhpcy5yZWdpc3RlckRvbUV2ZW50KGRvY3VtZW50LCAnY29udGV4dG1lbnUnLCBhc3luYyAoZXZlbnQ6IE1vdXNlRXZlbnQpID0+IHtcbiAgICBcdFx0XHRjb25zdCB2aWV3ID0gYXdhaXQgdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KTtcblx0XHQgICAgICAgIGlmICh2aWV3ICYmIHRoaXMuY3RybENtZEtleSAoZXZlbnQpICYmICh2aWV3LmdldE1vZGUoKSA9PSAncHJldmlldycpKSB7XG5cdFx0ICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHQgICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdyaWdodCBjbGljaycpXG5cdFx0ICAgICAgICAgICAgY29uc3QgZmlsZSA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk7XG5cdFx0ICAgICAgICAgICAgLy9jb25zb2xlLmxvZyh2aWV3KVxuXHRcdCAgICAgICAgICAgIHRoaXMuc2hvd1RhZ1NlbGVjdG9yKGV2ZW50LnBhZ2VYLCBldmVudC5wYWdlWSwgZmlsZSk7XG5cdFx0ICAgICAgICB9XG5cdFx0ICAgIH0pO1xuXG5cdFx0XHQvLyBEb24ndCBuZWVkIHRoaXMgZXZlbnQgYmVjYXVzZSB3ZSdsbCBhbHdheXMgbmVlZCB0byBzd2l0Y2ggYmV0d2VlbiB2aWV3cyB0byBlZGl0IG5vdGUgYW5kIGFmZmVjdCB0aGUgdGFnIGluZGljZXMuXG5cdFx0XHQvLyB0aGlzLnJlZ2lzdGVyRXZlbnQodGhpcy5hcHAud29ya3NwYWNlLm9uKCdlZGl0b3ItY2hhbmdlJywgZGVib3VuY2UoYXN5bmMgKCkgPT4geyBjb25zb2xlLmxvZygnZWRpdG9yIGNoYW5nZScpOyB0aGlzLnByb2Nlc3NUYWdzKCk7IH0sIDMwMDAsIHRydWUpKSk7XG5cdFx0XHQvLyBUaGlzIGV2ZW50IGlzIGJlc3QgYmVjYXVzZSB3ZSBhbHdheXMgbmVlZCB0byBzd2l0Y2ggbW9kZXMgdG8gZWRpdCBub3RlIG9yIGludGVyYWN0IHdpdGggdGFnIChyZWFkaW5nIG1vZGUpLlxuXHRcdFx0Ly8gdGhpcy5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLndvcmtzcGFjZS5vbihcImVkaXRvci1tZW51XCIsIHRoaXMub25FZGl0b3JNZW51LCB0aGlzKSk7XG5cdFx0XHQvLyB0aGlzLnJlZ2lzdGVyRXZlbnQoIHRoaXMuYXBwLndvcmtzcGFjZS5vbignZWRpdG9yLW1lbnUnLCBkZWJvdW5jZShhc3luYyAoKSA9PiB7IGNvbnNvbGUubG9nKCdhY3RpdmUgbGVhZiBjaGFuZ2UnKTsgdGhpcy5wcm9jZXNzVGFncygpOyB9LCAzMDAsIHRydWUpKSApO1xuXG5cdFx0XHR0aGlzLnJlZ2lzdGVyRXZlbnQoIHRoaXMuYXBwLm9uKCdsYXlvdXQtY2hhbmdlJywgKGV2ZW50OiBFZGl0b3JFdmVudCkgPT4geyAgXG5cdFx0XHRcdC8vc2V0VGltZW91dChhc3luYyAoKSA9PiB7IFxuXHRcdFx0XHQgLy9jb25zb2xlLmxvZygnbGF5b3V0IGNoYW5nZScpOyBcblx0XHRcdFx0XHQvL3RoaXMucHJvY2Vzc1RhZ3MoKTsgXG5cdFx0XHRcdFx0ZGVib3VuY2VkUHJvY2Vzc1RhZ3MoKTtcblx0XHRcdFx0Ly99LCAzMDApOyBcblx0XHRcdH0pKTtcblx0XHRcdFxuXHRcdFx0Ly8gVGhlcmUgaXMgYSBsaXR0bGUgcmVkdW5kYW5jeSBoZXJlIGJlY2F1c2Ugd2UgYWxzbyBnZXQgbGF5b3V0IGV2ZW50cyB3aGVuIHN3aXRjaGluZyBmaWxlc1xuXHRcdFx0dGhpcy5yZWdpc3RlckV2ZW50KHRoaXMuYXBwLm9uKCdmaWxlLW9wZW4nLCBhc3luYyAoZXZlbnQ6IEVkaXRvckV2ZW50KSA9PiB7IFxuXHRcdFx0XHQvL3NldFRpbWVvdXQoYXN5bmMgKCkgPT4geyBcblx0XHRcdFx0IC8vY29uc29sZS5sb2coJ2ZpbGUgb3BlbicpOyBcblx0XHRcdFx0XHQvL3RoaXMucHJvY2Vzc1RhZ3MoKTsgXG5cdFx0XHRcdFx0ZGVib3VuY2VkUHJvY2Vzc1RhZ3MoKTtcblx0XHRcdFx0Ly99LCAxMDAwKTsgXG5cdFx0XHR9KSk7XG5cblx0XHRcdFxuXG5cdFx0XHRpZiAoIXRoaXMuYXBwLmlzTW9iaWxlKSB7XG5cblx0XHRcdFx0Ly8gVGhpcyBldmVudCBoYW5kbGVzIGFsbCB0aGUgaW50ZXJhY3Rpb25zIG9uIGRlc2t0b3Bcblx0XHRcdFx0dGhpcy5yZWdpc3RlckRvbUV2ZW50KGRvY3VtZW50LCAnY2xpY2snLCB0aGlzLm9uQ2xpY2tFdmVudC5iaW5kKHRoaXMpLCB0cnVlKTtcblxuXHRcdFx0fSBlbHNlIHsgLy8gTW9iaWxlIGludGVyYWN0aW9uXG5cblx0XHRcdFx0Ly8gVGhpcyBldmVudCBjYXRjaGVzIGFsbCB0YXBzIG9uIG1vYmlsZSBiZWNhdXNlIHdlIGhhdmUgY3VzdG9tIGRvdWJsZS10YXAgYW5kIHByZXNzLWhvbGQgZXZlbnRzLlxuXHRcdFx0XHQvLyBCdXQgd2Ugb25seSBzdG9wIGFsbCBvdGhlciBzeXN0ZW0gZXZlbnRzIGlmIHRoaXMgY2xpY2sgd2FzIG9uIGEgdGFnLiBUaGVuIHdlIHRha2VvdmVyLiBcblx0XHRcdFx0dGhpcy5yZWdpc3RlckRvbUV2ZW50KGRvY3VtZW50LCAnY2xpY2snLCAoZSkgPT4geyBcblx0XHRcdFx0XHRjb25zdCBpc1RhZyA9IGUudGFyZ2V0LmNsYXNzTGlzdC5jb250YWlucygndGFnJyk7XG5cdFx0XHRcdFx0aWYgKGlzVGFnICYmICF0aGlzLnNldHRpbmdzLm1vYmlsZVRhZ1NlYXJjaCkge1xuXHRcdFx0XHRcdFx0Ly9uZXcgTm90aWNlICgnc3RvcCBwcm9wJylcblx0XHRcdFx0XHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LCB0cnVlKTtcblxuXHRcdFx0XHRuZXcgUHJlc3NBbmRIb2xkSGFuZGxlcih0aGlzLCBkb2N1bWVudCwgdGhpcy5vbkNsaWNrRXZlbnQuYmluZCh0aGlzKSk7XG5cdFx0XHRcdG5ldyBEb3VibGVUYXBIYW5kbGVyKHRoaXMsIGRvY3VtZW50LCB0aGlzLm9uQ2xpY2tFdmVudC5iaW5kKHRoaXMpKTtcblx0XHRcdH1cdFxuXHRcdFx0XG5cdFx0fSk7XG5cblx0XHQvLyBUYWcgc3VtbWFyeSBjb2RlIGJsb2NrXG5cdFx0dGhpcy5yZWdpc3Rlck1hcmtkb3duQ29kZUJsb2NrUHJvY2Vzc29yKFwidGFnLXN1bW1hcnlcIiwgdGhpcy5zdW1tYXJ5Q29kZUJsb2NrUHJvY2Vzc29yLmJpbmQodGhpcykpO1xuXHR9XG5cblx0YXN5bmMgb25DbGlja0V2ZW50IChldmVudCkge1xuXHRcdFxuXHRcdC8vIFN1cHBvcnQgZm9yIGRpZmZlcmVudCB2aWV3cz8gXG5cdFx0Ly8gSWYgdGFnIGhhcyBubyBjb250ZXh0IHByb3BlcnRpZXMsIHRoZW4gdHJ5IHRvIGZpZ3VyZSBvdXQgd2hlcmUgaXQgaXM/XG5cdFx0Ly8gT3IgbWF5YmUgdGhlcmUncyBhIHdheSB0byBoYXZlIG9ic2lkaWFuIGFkZCB0aGUgcHJvcGVydGllcyBnbG9iYWxseS5cblx0XHQvL25ldyBOb3RpY2UgKCdUYWcgQnVkZHkgZXZlbnQgdHlwZTogJyArIGV2ZW50LnR5cGUpO1xuXG5cdFx0Ly9jb25zb2xlLmxvZygobmF2aWdhdG9yLnBsYXRmb3JtLnRvVXBwZXJDYXNlKCkuaW5kZXhPZignTUFDJykgPj0gMCk/J1RoaXMgaXMgYSBNYWMnOidUaGlzIGlzIG5vdCBhIE1hYycpXG5cblx0XHRjb25zdCB0YXJnZXQgPSBldmVudC50YXJnZXQgYXMgSFRNTEVsZW1lbnQ7XG5cdFx0Y29uc3QgdmlldyA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVWaWV3T2ZUeXBlKE1hcmtkb3duVmlldyk7XG5cblx0XHQvLyBUaGlzIGNvbmRpdGlvbiBpdCBpbiBjYXNlIHdlIGNsaWNrIG9uIGEgdGFnIGluIGFub3RoZXIgcGx1Z2luIGxpa2UgcmVwZWF0IG9yIGNoZWNrbGlzdFxuXHRcdC8vIGNhbid0IGVkaXQgdGFncyBpbiB0aGVzZSBjYXNlcy4gRm9yIG5vdy5cblx0XHRpZiAoIXZpZXcgJiYgdGFyZ2V0Lm1hdGNoZXMoJy50YWcnKSkgeyBcblx0XHRcdG5ldyBOb3RpY2UoJ1RhZyBCdWRkeTogQ2FuXFwndCBlZGl0IHRhZy4gVW5zdXBwb3J0ZWQgdmlldyB0eXBlLiBUcnkgYWdhaW4gd2l0aGluIHRoYXQgbm90ZS4nKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAodmlldykgeyBcblx0XHRcdGlmICh2aWV3LmdldE1vZGUoKSAhPSAncHJldmlldycpIHJldHVybjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly9pZiAoZG9jdW1lbnQuY29udGFpbnMoJ3JlcGVhdC1lbWJlZGRlZF9ub3RlJykpXG5cdFx0fVxuXHRcdFxuXHRcdGlmICghdGhpcy5hcHAuaXNNb2JpbGUpIHtcblx0XHRcdC8vbmV3IE5vdGljZSAoJ1RhZyBCdWRkeSBldmVudCB0eXBlOiAnICsgZXZlbnQudHlwZSk7XG5cblx0XHRpZiAoKHRoaXMuc2V0dGluZ3MucmVtb3ZlT25DbGljayAmJiB0aGlzLmN0cmxDbWRLZXkoZXZlbnQpKSB8fCAoIXRoaXMuc2V0dGluZ3MucmVtb3ZlT25DbGljayAmJiAhdGhpcy5jdHJsQ21kS2V5KGV2ZW50KSkpIHsgXG5cdFx0XHRyZXR1cm47IFxuXHRcdH0gZWxzZSBpZiAoZXZlbnQuYWx0S2V5ICYmICF0aGlzLnNldHRpbmdzLm9wdFRvQ29udmVydCkgeyAgXG5cdFx0XHRyZXR1cm47IFxuXHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRcblx0XHRcdGlmICh0aGlzLnNldHRpbmdzLm1vYmlsZVRhZ1NlYXJjaCAmJiBldmVudC50eXBlID09ICd0b3VjaGVuZCcpIHtcblx0XHRcdFx0Ly8gaWYgd2UgZ2V0IHRoaXMgZmFyLCB0aGlzIGlzIGEgZG91YmxlIHRhcFxuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0fVxuXG5cblx0XHRcblx0XHQvL2lmICh2aWV3ICYmIHRhcmdldCAmJiB0YXJnZXQubWF0Y2hlcygnLnRhZycpKSB7XHRcblx0XHRpZiAodGFyZ2V0ICYmIHRhcmdldC5tYXRjaGVzKCcudGFnJykpIHtcdFxuXHRcdFx0Ly8gY29uc3Qgc2Nyb2xsU3RhdGUgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShNYXJrZG93blZpZXcpPy5jdXJyZW50TW9kZT8uZ2V0U2Nyb2xsKCk7XG5cblx0XHRcdGlmICh0aGlzLnNldHRpbmdzLnJlbW92ZU9uQ2xpY2sgfHwgKCF0aGlzLnNldHRpbmdzLnJlbW92ZU9uQ2xpY2sgJiYgdGhpcy5jdHJsQ21kS2V5KGV2ZW50KSkpIHtcblx0XHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGNsaWNrZWRUYWcgPSB0YXJnZXQuY2xvc2VzdCgnLnRhZycpOyAvL2V2ZW50LnRhcmdldCBhcyBIVE1MRWxlbWVudDtcblx0XHRcdGNvbnN0IHRhZyA9IGNsaWNrZWRUYWcuaW5uZXJUZXh0O1xuXG5cdFx0XHRsZXQgdGFnSW5kZXggPSBjbGlja2VkVGFnLmdldEF0dHJpYnV0ZSgnbWQtaW5kZXgnKTtcblx0XHRcdGxldCB0YWdGaWxlID0gY2xpY2tlZFRhZy5nZXRBdHRyaWJ1dGUoJ2ZpbGUtc291cmNlJyk7XG5cblx0XHRcdGlmICh0YWdGaWxlKSB7XG5cdFx0XHRcdC8vIFRyeVxuXHRcdFx0XHQvL3RoaXMuZWRpdFRhZyAoZXZlbnQsIHRhZ0luZGV4LCB0YWdGaWxlKTtcblx0XHRcdFx0dGhpcy5lZGl0VGFnICh0YXJnZXQsIGV2ZW50KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIFRyeSBhZ2FpblxuXHRcdFx0XHRzZXRUaW1lb3V0KGFzeW5jICgpID0+IHtcblx0XHRcdFx0XHR0YWdJbmRleCA9IGNsaWNrZWRUYWcuZ2V0QXR0cmlidXRlKCdtZC1pbmRleCcpO1xuXHRcdFx0XHRcdHRhZ0ZpbGUgPSBjbGlja2VkVGFnLmdldEF0dHJpYnV0ZSgnZmlsZS1zb3VyY2UnKTtcblx0XHRcdFx0XHQvL3RoaXMuZWRpdFRhZyAoZXZlbnQsIHRhZ0luZGV4LCB0YWdGaWxlKTtcblx0XHRcdFx0XHR0aGlzLmVkaXRUYWcgKHRhcmdldCwgZXZlbnQpO1xuXHRcdFx0XHR9LCAzMDApO1xuXHRcdFx0fVxuXHRcdFx0Ly9jb25zb2xlLmxvZyhjbGlja2VkVGFnLmdldEF0dHJpYnV0ZSgndHlwZScpKVxuXG5cdFx0XHRcblx0XHQvL30gZWxzZSBpZiAodmlldyA9PSBudWxsICYmIHRhcmdldCAmJiB0YXJnZXQubWF0Y2hlcygnLnRhZycpKSB7XG5cdFx0fSBlbHNlIGlmICghdmlldyAmJiB0YXJnZXQubWF0Y2hlcygnLnRhZycpKSB7XG5cdFx0XHRuZXcgTm90aWNlKCdUYWcgQnVkZHk6IENhblxcJ3QgZWRpdCB0YWcuIE1pZ2h0IGJlIGluIGFuIHVuc3VwcG9ydGVkIHZpZXcgdHlwZS4nKTtcblx0XHR9XG5cdH1cblxuXHRhc3luYyBlZGl0VGFnICh0YWdFbCwgZXZlbnQsIHByYWdyYXBoRWwpIHtcblx0XHQvL2NvbnNvbGUubG9nKHRhZ0VsKVxuXG5cdFx0Y29uc3QgaW5kZXggPSB0YWdFbC5nZXRBdHRyaWJ1dGUoJ21kLWluZGV4Jyk7XG5cdFx0Y29uc3QgZmlsZVBhdGggPSB0YWdFbC5nZXRBdHRyaWJ1dGUoJ2ZpbGUtc291cmNlJyk7XG5cblx0XHQvL2lmICh0aGlzLnNldHRpbmdzLmRlYnVnTW9kZSkgY29uc29sZS5sb2coJ1RhZyBCdWRkeSBlZGl0IHRhZzogJyArIGV2ZW50LnRhcmdldC5pbm5lclRleHQgKyAnXFxuSW4gZmlsZTogJyArIGZpbGVQYXRoKTtcblx0XHRpZiAodGhpcy5zZXR0aW5ncy5kZWJ1Z01vZGUpIGNvbnNvbGUubG9nKCdUYWcgQnVkZHkgZWRpdCB0YWc6ICcgKyB0YWdFbC5pbm5lclRleHQgKyAnXFxuSW4gZmlsZTogJyArIGZpbGVQYXRoKTtcblxuXHRcdGlmIChmaWxlUGF0aCkge1xuXG5cdFx0XHRjb25zdCBmaWxlOiBURmlsZSA9IGF3YWl0IHRoaXMudmFsaWRhdGVGaWxlUGF0aChmaWxlUGF0aCk7IC8vYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChmaWxlUGF0aCk7XG5cdFx0XHRsZXQgZmlsZUNvbnRlbnQ6IFN0cmluZztcblx0XHRcdGxldCBmaWxlQ29udGVudEJhY2t1cDogU3RyaW5nO1xuXHRcdFx0Ly9jb25zdCB0YWc6IFN0cmluZyA9IGV2ZW50LnRhcmdldC5pbm5lclRleHQudHJpbSgpO1xuXHRcdFx0Y29uc3QgdGFnOiBTdHJpbmcgPSB0YWdFbC5pbm5lclRleHQudHJpbSgpO1xuXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRcblx0XHRcdFx0ZmlsZUNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdFx0XHRmaWxlQ29udGVudEJhY2t1cCA9IGZpbGVDb250ZW50O1xuXG5cdFx0XHR9IGNhdGNoIChlcnJvcikge1xuXG5cdFx0XHRcdG5ldyBOb3RpY2UoJ1RhZyBCdWRkeSBmaWxlIHJlYWQgZXJyb3I6XFxuJyArIGVycm9yLm1lc3NhZ2UpO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9jb25zb2xlLmxvZyh0aGlzLmdldENsaWNrZWRUZXh0T2JqRnJvbURvYyhldmVudC5wYWdlWCwgZXZlbnQucGFnZVksIDApKVxuXG5cdFx0XHQvLyBjaGVjayBpZiB0aGUgZmlsZSBoYXMgb25seSBvbmUgdGFnIGxlZnQgKGFuZCB0aGF0J3MgYWxsIHRoYXRzIGxlZnQgaW4gdGhlIGZpbGUpXG5cdFx0XHRsZXQgc2FmZVRvRW1wdHlGaWxlID0gZmFsc2U7XG5cdFx0XHRjb25zdCB0YWdSZWdleCA9IC9eXFxzKiMoXFx3KylcXHMqJC87XG5cdFx0XHRpZiAodGFnUmVnZXgudGVzdChmaWxlQ29udGVudC50cmltKCkpKSB7XG5cdFx0ICAgIFx0c2FmZVRvRW1wdHlGaWxlID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdFxuXHRcdFx0bGV0IGJlZm9yZVRhZyA9IGZpbGVDb250ZW50LnN1YnN0cmluZygwLCBpbmRleCk7XG5cdFx0XHQvL2xldCBhZnRlclRhZyA9IGZpbGVDb250ZW50LnN1YnN0cmluZygoTnVtYmVyKGluZGV4KStOdW1iZXIodGFnLmxlbmd0aCkrMSkpO1xuXHRcdFx0bGV0IGFmdGVyVGFnID0gZmlsZUNvbnRlbnQuc3Vic3RyaW5nKChOdW1iZXIoaW5kZXgpK051bWJlcih0YWcubGVuZ3RoKSkpO1xuXG5cdFx0XHRsZXQgYWZ0ZXJUYWdDaHI7XG5cdFx0XHRsZXQgYmVmb3JlVGFnQ2hyXG4vL2NvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KGJlZm9yZVRhZykpXG5cdFx0XHRcbi8vY29uc29sZS5sb2cgKCdiZWZvcmUgdGFnIGVuZHMgd2l0aCBzcGFjZT8gJyArIGJlZm9yZS5zdGFydHNXaXRoKCcgJykpXG4vL2NvbnNvbGUubG9nICgnYmVmb3JlIHRhZyBlbmRzIHdpdGggbGluZWJyZWFrPyAnICsgYmVmb3JlLnN0YXJ0c1dpdGgoJ1xcbicpKVxuXHRcdFx0aWYgKGFmdGVyVGFnLnN0YXJ0c1dpdGgoJyAnKSkge1xuXHRcdFx0XHRhZnRlclRhZ0NociA9ICcgJztcblx0XHRcdH0gZWxzZSBpZiAoYWZ0ZXJUYWcuc3RhcnRzV2l0aCgnXFxuJykpIHtcblx0XHRcdFx0YWZ0ZXJUYWdDaHIgPSAnXFxuJztcblx0XHRcdH1cblxuXHRcdFx0Ly8gY2FuJ3QgcmVtZW1iZXIgd2h5IEkgaGF2ZSB0aGlzLi4uXG5cdFx0XHQvLyBuZWVkIHRvIHJlZmFjdG9yIGFsbCB0aGlzIGxpbmUgYnJlYWsgc3BhY2Ugc3R1ZmZcblx0XHRcdGlmIChmaWxlQ29udGVudFtpbmRleF0gPT09ICdcXG4nKSB7XG4gICAgXHRcdFx0YmVmb3JlVGFnICs9ICdcXG4nOyAvLyBhcHBlbmRpbmcgdGhlIG5ld2xpbmUgY2hhcmFjdGVyIHRvIGJlZm9yZVRhZ1xuXHRcdFx0fVxuXHRcdFx0XG5cdFx0XHQvL2NvbnNvbGUubG9nKCdGaWxlIGNvbnRlbnQ6ICcsIEpTT04uc3RyaW5naWZ5KGZpbGVDb250ZW50KSk7XG5cdFx0XHQvL2NvbnNvbGUubG9nICgnLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJyk7XG5cdFx0XHQvL2NvbnNvbGUubG9nKCdCZWZvcmUgVGFnOiAnLCBKU09OLnN0cmluZ2lmeShiZWZvcmVUYWcpKTtcblx0XHRcdC8vY29uc29sZS5sb2cgKCctLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nKTtcblx0XHRcdC8vY29uc29sZS5sb2coJ1RoZSBUYWc6ICcsIEpTT04uc3RyaW5naWZ5KHRhZykpO1xuXHRcdFx0Ly9jb25zb2xlLmxvZyAoJy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScpO1xuXHRcdFx0Ly9jb25zb2xlLmxvZygnQWZ0ZXIgVGFnOiAnLCBKU09OLnN0cmluZ2lmeShhZnRlclRhZykpO1xuXHRcblx0XHRcdGxldCBuZXdDb250ZW50ID0gJyc7XG5cblx0XHRcdC8vaWYgKHRoaXMuc2V0dGluZ3MuZGVidWdNb2RlKSB7XG5cblx0XHRcdFx0Ly8gbmV3Q29udGVudCA9IGJlZm9yZVRhZyArICcgXHUyNkEwXHVGRTBGLS0tXHVEODNFXHVERUY4JyArIHRhZyArICdcdUQ4M0VcdURFRjctLS1cdTI2QTBcdUZFMEYgJyArIGFmdGVyVGFnO1xuXHRcdFx0XHQvL25ld0NvbnRlbnQgPSBiZWZvcmVUYWcgKyAnIFx1MjZBMFx1RkUwRi0tLVx1MjdBMVx1RkUwRicgKyB0YWcgKyBhZnRlclRhZztcblxuXHRcdFx0Ly99IGVsc2VcblxuXHRcdFx0Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXHRcdFx0Ly8gU1VQRVIgTUVTU1kuIE5FRUQgVE8gUkVGQUNUT1Jcblx0XHRcdC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuXG5cdFx0XHRpZiAoIWV2ZW50KSB7IC8vIHRoZW4gd2UncmUgY2FsbGluZyB0aGlzIG1ldGhvZCBmcm9tIGEgYnV0dG9uLiBuZWVkIHRvIHJldGhpbmsgaG93IHRoaXMgaXMgb3JnYW5pemVkLlxuXHRcdFx0XHRcblx0XHRcdFx0Ly9hZnRlclRhZ0NociA9IGFmdGVyVGFnLmVuZHNXaXRoKCcgJyk/JyAnOicnXG5cdFx0XHRcdG5ld0NvbnRlbnQgPSBiZWZvcmVUYWcgKyBhZnRlclRhZ0NociArIGFmdGVyVGFnIC8vKyBhZnRlclRhZ0NocjtcblxuXHRcdFx0fSBlbHNlIGlmIChldmVudC5hbHRLZXkgfHwgKChldmVudC50eXBlID09ICd0b3VjaHN0YXJ0JykgJiYgIXRoaXMuc2V0dGluZ3MubW9iaWxlVGFnU2VhcmNoKSkgeyBcblxuXHRcdFx0XHQvLyBSZW1vdmUgdGhlIGhhc2ggb25seVxuXG5cdFx0XHRcdGNvbnN0IG5vSGFzaCA9IHRhZy5zdWJzdHJpbmcoMSk7XG5cdFx0XHRcdC8vbmV3Q29udGVudCA9IGJlZm9yZVRhZyArICghYmVmb3JlVGFnLmVuZHNXaXRoKCcgJyk/JyAnOicnKSArIG5vSGFzaCArIGFmdGVyVGFnO1xuXHRcdFx0XHRuZXdDb250ZW50ID0gYmVmb3JlVGFnICsgbm9IYXNoICsgYWZ0ZXJUYWdDaHIgKyBhZnRlclRhZztcblx0XHRcdFx0XG5cdFx0XHRcdGlmICh0aGlzLmFwcC5pc01vYmlsZSAmJiB0aGlzLnNldHRpbmdzLm1vYmlsZU5vdGljZXMpIHsgbmV3IE5vdGljZSAoJ1RhZyBCdWRkeTogJyArIHRhZyArICcgY29udmVydGVkIHRvIHRleHQuJyk7IH1cblx0XHRcdFx0Ly8gU2V0dGluZzogbWFrZSB0aGlzIGEgc2V0dGluZyB0byBzaG93IG5vdGljZXMgb24gbW9iaWxlXG5cdFx0XHRcblx0XHRcdH0gZWxzZSBpZiAoKChldmVudC50eXBlID09ICd0b3VjaGVuZCcpIHx8IHRoaXMuc2V0dGluZ3MubW9iaWxlVGFnU2VhcmNoKSB8fCAodGhpcy5jdHJsQ21kS2V5KGV2ZW50KSAmJiAhdGhpcy5zZXR0aW5ncy5yZW1vdmVPbkNsaWNrKSB8fCAoIXRoaXMuY3RybENtZEtleShldmVudCkgJiYgdGhpcy5zZXR0aW5ncy5yZW1vdmVPbkNsaWNrKSkge1xuXG5cdFx0XHRcdC8vIFJlbW92ZSB0YWcgKG9yIGNoaWxkIGZpcnN0LCBpZiBleGlzdHMpXG5cblx0XHRcdFx0bGV0IHBhcmVudFRhZyA9ICcnO1xuXG5cdFx0XHRcdGlmICh0YWcuaW5jbHVkZXMoJy8nKSAmJiAodGhpcy5zZXR0aW5ncy5yZW1vdmVDaGlsZFRhZ3NGaXJzdCB8fCAoZXZlbnQuc2hpZnRLZXkgJiYgIXRoaXMuc2V0dGluZ3MucmVtb3ZlQ2hpbGRUYWdzRmlyc3QpKSkge1xuXHRcdFx0XHRcdFxuXHRcdFx0XHRcdGxldCBwYXJ0cyA9IHRhZy5zcGxpdCgnLycpO1xuXHRcdFx0XHRcdGNvbnN0IHJlbW92ZWRDaGlsZCA9IHBhcnRzLnBvcCgpO1xuXHRcdFx0XHRcdHBhcmVudFRhZyA9IHBhcnRzLmpvaW4oJy8nKTtcblx0XHRcdFx0XHQvL25ld0NvbnRlbnQgPSBiZWZvcmVUYWcgKyAoIWJlZm9yZVRhZy5lbmRzV2l0aCgnICcpPycgJzonJykgKyBwYXJlbnRUYWcgKyAoIWFmdGVyVGFnLnN0YXJ0c1dpdGgoJyAnKT8nICc6JycpICsgYWZ0ZXJUYWc7XG5cdFx0XHRcdFx0bmV3Q29udGVudCA9IGJlZm9yZVRhZyArICghYmVmb3JlVGFnLmVuZHNXaXRoKCcgJyk/JyAnOicnKSArIHBhcmVudFRhZyArIGFmdGVyVGFnQ2hyICsgYWZ0ZXJUYWc7XG5cblxuXHRcdFx0XHRcdGlmICh0aGlzLmFwcC5pc01vYmlsZSAmJiB0aGlzLnNldHRpbmdzLm1vYmlsZU5vdGljZXMpIHsgbmV3IE5vdGljZSAoJ1RhZyBCdWRkeTogXFwnJyArIHJlbW92ZWRDaGlsZCArICdcXCcgcmVtb3ZlZCBmcm9tIHBhcmVudCB0YWcuJyk7IH1cblx0XHRcdFx0XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0bmV3Q29udGVudCA9IGJlZm9yZVRhZyArIGFmdGVyVGFnO1xuXHRcdFx0XHRcdGlmICh0aGlzLmFwcC5pc01vYmlsZSAmJiB0aGlzLnNldHRpbmdzLm1vYmlsZU5vdGljZXMpIHsgbmV3IE5vdGljZSAoJ1RhZyBCdWRkeTogJyArIHRhZyArICcgcmVtb3ZlZC4nKTsgfVxuXHRcdFx0XHR9XG5cdFx0XHR9IFxuXHRcdFx0XG5cblx0XHRcdHRyeSB7XG5cdFx0XHRcblx0XHRcdFx0Ly9hd2FpdCB0aGlzLmFwcC52YXVsdC5tb2RpZnkoZmlsZSwgbmV3Q29udGVudCk7XG5cblxuXHRcdFx0XHRpZiAodGFnRWwuZ2V0QXR0cmlidXRlKCd0eXBlJykgPT0gJ3BsdWdpbi1zdW1tYXJ5Jykge1xuXG5cblx0XHRcdFx0XHRjb25zdCBzdW1tYXJ5RWwgPSB0YWdFbC5jbG9zZXN0KCcudGFnLXN1bW1hcnktcGFyYWdyYXBoJyk7XG5cdFx0XHRcdFx0Y29uc3QgbWRTb3VyY2UgPSBzdW1tYXJ5RWwuZ2V0QXR0cmlidXRlKCdtZC1zb3VyY2UnKS50cmltKCk7XG5cdFx0XHRcdFx0XG5cdFx0XHRcdFx0Y29uc3QgZXNjYXBlZFRleHQgPSB0aGlzLmVzY2FwZVJlZ0V4cChtZFNvdXJjZSk7XG5cdFx0XHRcdFx0Y29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKGVzY2FwZWRUZXh0LCBcImdcIik7ICAvLyBUaGUgXCJnXCIgZmxhZyBtZWFucyBcImdsb2JhbFwiLCBzbyBpdCB3aWxsIGZpbmQgYWxsIG9jY3VycmVuY2VzXG5cdFx0XHRcdFx0Y29uc3QgbWF0Y2hlcyA9IGZpbGVDb250ZW50Lm1hdGNoKHJlZ2V4KTtcblx0XHRcdFx0XHRcblx0XHRcdFx0XHRpZiAobWF0Y2hlcyAmJiBtYXRjaGVzLmxlbmd0aCA+IDEpIHtcblx0XHRcdFx0XHQgICAgLy9jb25zb2xlLmxvZyhgRm91bmQgJHttYXRjaGVzLmxlbmd0aH0gb2NjdXJyZW5jZXMgb2YgXCIke3BhdHRlcm59XCIgaW4gXCIke3N1YmplY3R9XCIuYCk7XG5cdFx0XHRcdFx0ICAgIG5ldyBOb3RpY2UgKCdcdTI2QTBcdUZFMEYgQ2FuXFwndCBzYWZlbHkgcmVtb3ZlL2VkaXQgdGFnOlxcblN1cnJvdW5kaW5nIHRleHQgcmVwZWF0ZWQgaW4gc291cmNlIG5vdGUuJyk7XG5cdFx0XHRcdFx0ICAgIHJldHVybjtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKChtYXRjaGVzICYmIG1hdGNoZXMubGVuZ3RoID09PSAwKSB8fCAhbWF0Y2hlcykge1xuXHRcdFx0XHRcdFx0bmV3IE5vdGljZSAoJ1x1MjZBMFx1RkUwRiBDYW5cXCd0IGZpbmQgdGFnIGluIHNvdXJjZSBub3RlLlxcbicpO1xuXHRcdFx0XHRcdCAgICByZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cblx0XHRcdFx0XHQvLyBGaWxlIHNhZmV0eSBjaGVja3Ncblx0XHRcdFx0XHRpZiAoKG5ld0NvbnRlbnQgPT0gJycgJiYgIXNhZmVUb0VtcHR5RmlsZSkgfHwgdGhpcy5jb250ZW50Q2hhbmdlZFRvb011Y2goZmlsZUNvbnRlbnRCYWNrdXAsIG5ld0NvbnRlbnQsIHRhZywgMikpIHtcblx0XHRcdFx0XHRcdC8vIENoZWNrIGlmIHRoZXJlIHdhcyBvbmx5IG9uZSB0YWcgaW4gdGhlIGZpbGUsIGlmIHNvLCBkb24ndCByZXN0b3JlIGJhY2t1cDtcblx0XHRcdFx0XHRcdG5ldyBOb3RpY2UoJ1RhZyBCdWRkeTogRmlsZSBjaGFuZ2UgZXJyb3IuJyk7XG5cdFx0XHRcdFx0XHRuZXdDb250ZW50ID0gZmlsZUNvbnRlbnRCYWNrdXA7XG5cdFx0XHRcdFx0fSBlbHNlIGlmIChuZXdDb250ZW50ID09ICcnICYmIHNhZmVUb0VtcHR5RmlsZSkge1xuXHRcdFx0XHRcdFx0bmV3IE5vdGljZSgnVGFnIEJ1ZGR5OiBUYWcgcmVtb3ZlZC4gVGhlIG5vdGUgaXMgZW1wdHkuJyk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0c2V0VGltZW91dChhc3luYyAoKSA9PiB7XG5cdFx0XHRcdFx0XHRcblx0XHRcdFx0XHRcdGNvbnN0IHRhZ1BhcmFncmFwaEVsID0gdGFnRWwuY2xvc2VzdCgnLnRhZy1zdW1tYXJ5LXBhcmFncmFwaCcpO1xuXHRcdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygndGhpcyBpcyB0aGUgZXJyb3InKVxuXHRcdFx0XHRcdFx0Y29uc3QgdGFnU3VtbWFyeUJsb2NrID0gdGFnRWwuY2xvc2VzdCgnLnRhZy1zdW1tYXJ5LWJsb2NrJyk7XG5cdFx0XHRcdFx0XHRcblx0XHRcdFx0XHRcdC8vY29uc3QgdGFnc1N0ciA9IHRhZ1N1bW1hcnlCbG9jay5nZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay10YWdzJyk7XG5cdFx0XHRcdFx0XHQvL2NvbnN0IHRhZ3MgPSB0YWdzU3RyID8gdGFnc1N0ci5zcGxpdCgnLCcpIDogW107XG5cdFx0XHRcdFx0XHQvL2NvbnN0IHRhZ3NJbmNsdWRlU3RyID0gdGFnU3VtbWFyeUJsb2NrLmdldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MtaW5jbHVkZScpO1xuXHRcdFx0XHRcdFx0Ly9jb25zdCB0YWdzSW5jbHVkZSA9IHRhZ3NJbmNsdWRlU3RyID8gdGFnc0luY2x1ZGVTdHIuc3BsaXQoJywnKSA6IFtdO1xuXHRcdFx0XHRcdFx0Ly9jb25zdCB0YWdzVG9DaGVjayA9IHRhZ3MuY29uY2F0KHRhZ3NJbmNsdWRlKTtcblx0XHRcdFx0XHRcdGNvbnN0IHRhZ3NUb0NoZWNrID0gdGhpcy5nZXRUYWdzVG9DaGVja0Zyb21FbCh0YWdTdW1tYXJ5QmxvY2spO1xuXG5cdFx0XHRcdFx0XHRjb25zdCB0YWdzSW5Db250ZW50ID0gdGhpcy50YWdzSW5TdHJpbmcodGFnUGFyYWdyYXBoRWwuaW5uZXJUZXh0KTtcblx0XHRcdFx0XHRcdC8vY29uc3QgdGFnQ291bnQgPSB0YWdzSW5Db250ZW50Py5sZW5ndGg7XG5cdFx0XHRcdFx0XHQvL2NvbnN0IHRhZ0NvdW50ID0gdGhpcy5jb3VudE9jY3VycmVuY2VzKHRhZ3NUb0NoZWNrLCB0YWdzSW5Db250ZW50KVxuXG5cdFx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKCd0YWdzIHRvIGNoZWNrOiAnICsgdGFnc1RvQ2hlY2spXG5cdFx0XHRcdFx0XHRcblxuXHRcdFx0XHRcdFx0aWYgKHRhZ3NUb0NoZWNrLmluY2x1ZGVzKHRhZykpIHtcblx0XHRcdFx0XHRcdFx0Ly9sZXQgdGFnQ291bnQgPSB0aGlzLnRhZ3NJblN0cmluZyh0YWdQYXJhZ3JhcGhFbC5pbm5lclRleHQsIHRhZykubGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRjb25zdCB0YWdDb3VudCA9IHRoaXMuY291bnRPY2N1cnJlbmNlcyh0YWdzVG9DaGVjaywgdGFnc0luQ29udGVudClcblx0XHRcdFx0XHRcdFx0XG5cdFx0XHRcdFx0XHRcdC8vIGNvdW50IGFsbCBvZiB0aGUgb2NjdXJyZW5jZXMgb2YgdGFncyB0byBjaGVjayBhZ2FpbnN0IHRhZ3MgaW4gdGhpcyBwYXJhZ3JhcGhcblx0XHRcdFx0XHRcdFx0Ly8gbm90IGp1c3QgdGhlIG9uZSB0YWdcblxuXHRcdFx0XHRcdFx0XHRpZiAodGFnQ291bnQgPj0gMikge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMudXBkYXRlU3VtbWFyeSh0YWdTdW1tYXJ5QmxvY2spOyBcblx0XHRcdFx0XHRcdFx0XHQvL3RoaXMudXBkYXRlU3VtbWFyaWVzKCk7IC8vIGNhdXNlcyBzY3JlZW4gZmxpY2tlclxuXHRcdFx0XHRcdFx0XHQgICAgc2V0VGltZW91dChhc3luYyAoKSA9PiB7IHRoaXMucHJvY2Vzc1RhZ3MoKTsgfSwgMjAwKTtcblx0XHRcdFx0XHRcdFx0XHQvLyB0aGlzLnJlZnJlc2hWaWV3KCk7IC8vIG5vIG5lZWQgZm9yIHRoaXMgYXRtXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnbGFzdCBvbmUsIHdpbGwgcmVtb3ZlIHBhcmFncmFwaCcpXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3Qgbm90aWNlID0gbmV3IE5vdGljZSAodGFnICsgJyByZW1vdmVkIGZyb20gcGFyYWdyYXBoLlxcblx1RDgzRFx1REQxNyBPcGVuIHNvdXJjZSBub3RlLicsIDUwMDApO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMucmVtb3ZlRWxlbWVudFdpdGhBbmltYXRpb24odGFnUGFyYWdyYXBoRWwsICgpID0+IHtcblx0XHRcdFx0ICAgIFx0XHRcdFx0c2V0VGltZW91dChhc3luYyAoKSA9PiB7IHRoaXMudXBkYXRlU3VtbWFyeSh0YWdTdW1tYXJ5QmxvY2spOyB0YWdQYXJhZ3JhcGhFbC5yZW1vdmUoKTsgfSwgNTAwKTtcblx0XHRcdFx0XHRcdFx0XHRcdC8vdGhpcy51cGRhdGVTdW1tYXJpZXMoKTsgLy8gY2F1c2VzIHNjcmVlbiBmbGlja2VyXG5cdFx0XHRcdFx0XHRcdCAgICBcdHNldFRpbWVvdXQoYXN5bmMgKCkgPT4geyB0aGlzLnByb2Nlc3NUYWdzKCk7IH0sIDgwMCk7XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyB0aGlzLnJlZnJlc2hWaWV3KCk7IC8vIG5vIG5lZWQgZm9yIHRoaXMgYXRtXG5cdFx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHRcdFx0dGhpcy5yZWdpc3RlckRvbUV2ZW50KG5vdGljZS5ub3RpY2VFbCwgJ2NsaWNrJywgKGUpID0+IHtcblx0XHRcdFx0XHRcdFx0IFx0IFx0dGhpcy5hcHAud29ya3NwYWNlLm9wZW5MaW5rVGV4dChmaWxlUGF0aCwgJycpO1xuXHRcdFx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR0aGlzLnVwZGF0ZVN1bW1hcnkodGFnU3VtbWFyeUJsb2NrKTsgXG5cdFx0XHRcdFx0XHRcdC8vdGhpcy51cGRhdGVTdW1tYXJpZXMoKTsgLy8gY2F1c2VzIHNjcmVlbiBmbGlja2VyXG5cdFx0XHRcdFx0XHQgICAgc2V0VGltZW91dChhc3luYyAoKSA9PiB7IHRoaXMucHJvY2Vzc1RhZ3MoKTsgfSwgMjAwKTtcblx0XHRcdFx0XHRcdFx0Ly8gdGhpcy5yZWZyZXNoVmlldygpOyAvLyBubyBuZWVkIGZvciB0aGlzIGF0bVxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSwgMjAwKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRzZXRUaW1lb3V0KGFzeW5jICgpID0+IHsgdGhpcy5wcm9jZXNzVGFncygpOyB9LCA1MClcblx0XHRcdFx0fVxuXG5cblx0XHRcdFx0YXdhaXQgdGhpcy5hcHAudmF1bHQubW9kaWZ5KGZpbGUsIG5ld0NvbnRlbnQpO1xuXG5cblx0XHRcdH0gY2F0Y2ggKGVycm9yKSB7XG5cblx0XHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRcdGNvbnN0IGJhY2t1cEZpbGVOYW1lID0gU3RyaW5nKGZpbGUubmFtZS5zdWJzdHJpbmcoMCwgZmlsZS5uYW1lLmluZGV4T2YoJy5tZCcpKSArICcgQkFDS1VQLm1kJyk7XG5cdFx0XHRcdFx0dGhpcy5hcHAudmF1bHQuY3JlYXRlKGJhY2t1cEZpbGVOYW1lLCBmaWxlQ29udGVudEJhY2t1cCk7XG5cblx0XHRcdFx0XHRuZXcgTm90aWNlKCdcdTI2QTBcdUZFMEYgVGFnL25vdGUgZWRpdGluZyBlcnJvcjogJyArIGVycm9yLm1lc3NhZ2UgKyAnXFxuJyArIGJhY2t1cEZpbGVOYW1lICsgJyBzYXZlZCB0byB2YXVsdCByb290LicpO1xuXHRcdFx0XHRcblx0XHRcdFx0fSBjYXRjaCAoZXJyb3IpIHtcblxuXHRcdFx0XHRcdG5hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KGZpbGVDb250ZW50QmFja3VwKTtcblx0XHRcdFx0XHRuZXcgTm90aWNlKCdcdTI2QTBcdUZFMEYgVGFnL25vdGUgZWRpdGluZyBlcnJvcjogJyArIGVycm9yLm1lc3NhZ2UgKyAnXFxuTm90ZSBjb250ZW50IGNvcGllZCB0byBjbGlwYm9hcmQuJyk7XG5cblx0XHRcdFx0fVxuXHRcdFx0fSBcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5wcm9jZXNzVGFncygpO1xuXHRcdFx0bmV3IE5vdGljZSgnXHUyNkEwXHVGRTBGIENhblxcJ3QgaWRlbnRpZnkgdGFnIGxvY2F0aW9uLiBQbGVhc2UgdHJ5IGFnYWluLicpO1xuXHRcdH1cblx0fVxuXG5cdGdldFRhZ3NUb0NoZWNrRnJvbUVsICh0YWdTdW1tYXJ5RWwpOkFycmF5IHtcblx0XHRjb25zdCB0YWdzU3RyID0gdGFnU3VtbWFyeUVsLmdldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MnKTtcblx0XHRjb25zdCB0YWdzID0gdGFnc1N0ciA/IHRhZ3NTdHIuc3BsaXQoJywnKSA6IFtdO1xuXHRcdGNvbnN0IHRhZ3NJbmNsdWRlU3RyID0gdGFnU3VtbWFyeUVsLmdldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MtaW5jbHVkZScpO1xuXHRcdGNvbnN0IHRhZ3NJbmNsdWRlID0gdGFnc0luY2x1ZGVTdHIgPyB0YWdzSW5jbHVkZVN0ci5zcGxpdCgnLCcpIDogW107XG5cdFx0cmV0dXJuIHRhZ3MuY29uY2F0KHRhZ3NJbmNsdWRlKTtcblx0fVxuXG5cdHVwZGF0ZVN1bW1hcnkgKHN1bW1hcnlFbCkge1xuXHRcdC8vY29uc29sZS5sb2coJ1VwZGF0ZSBzdW1tYXJ5Jylcblx0XHRjb25zdCBzdW1tYXJ5Q29udGFpbmVyID0gc3VtbWFyeUVsOyAvL3RhZ0VsLmNsb3Nlc3QoJy50YWctc3VtbWFyeS1ibG9jaycpO1xuXHRcdGNvbnN0IHRhZ3NTdHIgPSBzdW1tYXJ5Q29udGFpbmVyLmdldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MnKTtcblx0XHRjb25zdCB0YWdzID0gdGFnc1N0ciA/IHRhZ3NTdHIuc3BsaXQoJywnKSA6IFtdO1xuXG5cdFx0Y29uc3QgdGFnc0luY2x1ZGVTdHIgPSBzdW1tYXJ5Q29udGFpbmVyLmdldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MtaW5jbHVkZScpO1xuXHRcdGNvbnN0IHRhZ3NJbmNsdWRlID0gdGFnc0luY2x1ZGVTdHIgPyB0YWdzSW5jbHVkZVN0ci5zcGxpdCgnLCcpIDogW107XG5cblx0XHRjb25zdCB0YWdzRXhjbHVkZVN0ciA9IHN1bW1hcnlDb250YWluZXIuZ2V0QXR0cmlidXRlKCdjb2RlYmxvY2stdGFncy1leGNsdWRlJyk7XG5cdFx0Y29uc3QgdGFnc0V4Y2x1ZGUgPSB0YWdzRXhjbHVkZVN0ciA/IHRhZ3NFeGNsdWRlU3RyLnNwbGl0KCcsJykgOiBbXTtcblxuXHRcdGNvbnN0IHNlY3Rpb25zU3RyID0gc3VtbWFyeUNvbnRhaW5lci5nZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay1zZWN0aW9ucycpO1xuXHRcdGNvbnN0IHNlY3Rpb25zID0gc2VjdGlvbnNTdHIgPyBzZWN0aW9uc1N0ci5zcGxpdCgnLCcpIDogW107XG5cblx0XHRjb25zdCBtYXggPSBOdW1iZXIoc3VtbWFyeUNvbnRhaW5lci5nZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay1tYXgnKSk7XG5cblx0XHRjb25zdCBtZFNvdXJjZSA9IHN1bW1hcnlDb250YWluZXIuZ2V0QXR0cmlidXRlKCdjb2RlYmxvY2stY29kZScpO1xuXG5cdFx0Ly8gUmVjcmVhdGUgc3VtbWFyeSBhZnRlciB3ZSd2ZSBlZGl0ZWQgdGhlIGZpbGVcblx0XHR0aGlzLmNyZWF0ZVN1bW1hcnkoc3VtbWFyeUNvbnRhaW5lciwgdGFncywgdGFnc0luY2x1ZGUsIHRhZ3NFeGNsdWRlLCBzZWN0aW9ucywgbWF4LCAnJywgbWRTb3VyY2UpO1xuXG5cdFx0Ly9zZXRUaW1lb3V0KGFzeW5jICgpID0+IHsgdGhpcy5wcm9jZXNzVGFncygpOyB9LCAyMDApO1xuXHR9XG5cblx0Lyphc3luYyB1cGRhdGVTdW1tYXJpZXNzICgpIHtcblx0XHQvL2NvbnN0IGFjdGl2ZUZpbGUgPSBhd2FpdCB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xuXHRcdC8vY29uc3QgZmlsZUNvbnRlbnQgPSBhd2FpdCBhcHAudmF1bHQucmVhZChhY3RpdmVGaWxlKTtcblx0XHRjb25zdCBhY3RpdmVOb3RlQ29udGFpbmVyID0gYXdhaXQgdGhpcy5hcHAud29ya3NwYWNlLmFjdGl2ZUxlYWYuY29udGFpbmVyRWw7XG5cdFx0Y29uc3QgZW1iZWRzID0gYXdhaXQgYWN0aXZlTm90ZUNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCcudGFnLXN1bW1hcnktYmxvY2snKTtcblx0XHQvL2xldCBlbWJlZGVkVGFnRmlsZXMgPSBbXTtcblxuXHRcdGVtYmVkcy5mb3JFYWNoKGFzeW5jIChlbWJlZCkgPT4ge1xuXHRcdFx0aWYgKGVtYmVkLmNsYXNzTGlzdC5jb250YWlucygndGFnLXN1bW1hcnktYmxvY2snKSkge1xuXHRcdFx0XHR0aGlzLnVwZGF0ZVN1bW1hcnkgKGVtYmVkKTtcblx0XHRcdH1cblx0XHR9KTtcblx0fSovXG5cblx0YXN5bmMgcHJvY2Vzc1RhZ3MgKCkge1xuXG5cdFx0aWYgKHRoaXMuc2V0dGluZ3MuZGVidWdNb2RlKSBjb25zb2xlLmxvZygnVGFnIEJ1ZGR5OiBQcm9jZXNzaW5nIHRhZ3MuJyk7XG5cdFx0Y29uc3QgdmlldyA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVWaWV3T2ZUeXBlKE1hcmtkb3duVmlldyk7XG5cdFx0aWYgKHZpZXcpIHtcblx0XHRcdC8vc2V0VGltZW91dChhc3luYyAoKSA9PiB7IFxuXHRcdFx0Y29uc3QgYWN0aXZlTm90ZUNvbnRhaW5lciA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5hY3RpdmVMZWFmLmNvbnRhaW5lckVsO1xuXHRcdFx0Ly9jb25zb2xlLmxvZyhhY3RpdmVOb3RlQ29udGFpbmVyKVxuXHRcdFx0Y29uc3QgYWN0aXZlTm90ZVJlYWRpbmdWaWV3ID0gYWN0aXZlTm90ZUNvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcubWFya2Rvd24tcmVhZGluZy12aWV3Jyk7XG5cdFx0XHRjb25zdCBhY3RpdmVOb3RlRWRpdFZpZXcgPSBhY3RpdmVOb3RlQ29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJy5tYXJrZG93bi1zb3VyY2UtdmlldycpO1xuXHRcdFx0XG5cdFx0XHQvL2NvbnNvbGUubG9nKGFjdGl2ZU5vdGVDb250YWluZXIpXG5cdFx0XHQvL2NvbnN0IGFjdGl2ZU5vdGVDb250YWluZXIgPSBhd2FpdCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCcudmlldy1jb250ZW50Jyk7XG5cdFx0XHQvL30sIDIwMClcblx0XHRcdC8vc2V0VGltZW91dChhc3luYyAoKSA9PiB7IC8vIEFsbCB0aGVzZSB0aW1lb3V0cyB3ZXJlIGZvciB0ZXN0aW5nLiBJc3N1ZXMgc2VlbXMgdG8gYmUgcmVzb2x2ZWQgbm93LlxuXHRcdFx0Y29uc3QgYWN0aXZlRmlsZSA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk7XG5cdFx0XHRjb25zdCBmaWxlQ29udGVudCA9IGF3YWl0IGFwcC52YXVsdC5yZWFkKGFjdGl2ZUZpbGUpO1xuXHRcdFx0Y29uc3QgYWN0aXZlRmlsZVRhZ0VsZW1lbnRzID0gYXdhaXQgYWN0aXZlTm90ZUNvbnRhaW5lci5xdWVyeVNlbGVjdG9yQWxsKCcubW9kLWFjdGl2ZSAudGFnOm5vdCgubWFya2Rvd24tZW1iZWQgLnRhZyk6bm90KC50YWctc3VtbWFyeS1ibG9jayAudGFnKScpO1xuXG5cdFx0XHQvL3NldFRpbWVvdXQoYXN5bmMgKCkgPT4geyBjb25zb2xlLmxvZyhhY3RpdmVGaWxlVGFnRWxlbWVudHMpfSwgMTAwMClcblx0XHRcdGNvbnN0IGFjdGl2ZUZpbGVUYWdzID0gYXdhaXQgdGhpcy5nZXRNYXJrZG93blRhZ3MoYWN0aXZlRmlsZSwgZmlsZUNvbnRlbnQpO1xuXHRcdFx0aWYgKGFjdGl2ZUZpbGVUYWdzLmxlbmd0aCA+IDApIHRoaXMuYXNzaWduTWFya2Rvd25UYWdzKGFjdGl2ZUZpbGVUYWdzLCBhY3RpdmVGaWxlVGFnRWxlbWVudHMsIDAsICdhY3RpdmUnKTtcblx0XHRcdC8vdGhpcy5wcm9jZXNzRW1iZWRzKGFjdGl2ZU5vdGVDb250YWluZXIpO1xuXHRcdFx0dGhpcy5wcm9jZXNzRW1iZWRzKGFjdGl2ZU5vdGVSZWFkaW5nVmlldyk7XG5cdFx0XHQvL30sIDUwMClcblx0XHR9XG5cdH1cblxuXHRhc3luYyBnZXRNYXJrZG93blRhZ3MgKGZpbGUsIGZpbGVDb250ZW50KSB7XG5cdFx0Ly9jb25zb2xlLmxvZygnZ2V0TWFya2Rvd25UYWdzJylcblx0XHRjb25zdCB0YWdQb3NpdGlvbnMgPSBbXTtcblx0XHRsZXQgbWF0Y2g7XG5cdFx0Ly9jb25zdCByZWdleCA9IC8oPzpefFxccykjW15cXHMjXSt8YGBgL2c7IC8vIEJVRzogd3JvbmcgbWF0Y2guaW5kZXguIG1hdGNoZXMgdGhlIHNwYWNlIGJlZm9yZSB0aGUgdGFnLlxuXHRcdC8vY29uc3QgcmVnZXggPSAvKD88PV58XFxzKSNbXlxccyNdK3xgYGAvZyAvLyBGSVguIEJ1dCBzdGlsbCBtYXRjaGluZyBwdW5jdHVhdGlvbiBhZnRlclxuXHRcdGNvbnN0IHJlZ2V4ID0gLyg/PD1efFxccykoI1teXFxzIy4sOyE/Ol0rKSg/PVsuLDshPzpcXHNdfCQpfGBgYC9nICAvLyBtYXRjaGVzIHB1bmN0dWF0aW9uIGFmdGVyLCBidXQgbm90IGluY2x1ZGVkIGluIHRoZSBtYXRjaFxuXG5cdFx0bGV0IGluc2lkZUNvZGVCbG9jayA9IGZhbHNlO1xuXG5cdFx0d2hpbGUgKChtYXRjaCA9IHJlZ2V4LmV4ZWMoZmlsZUNvbnRlbnQpKSAhPT0gbnVsbCkge1xuXHRcdCAgICBpZiAobWF0Y2hbMF0udHJpbSgpID09PSBcImBgYFwiKSB7XG5cdFx0ICAgICAgICBpbnNpZGVDb2RlQmxvY2sgPSAhaW5zaWRlQ29kZUJsb2NrOyBcblx0XHQgICAgICAgIGNvbnRpbnVlO1xuXHRcdCAgICB9XG5cdFx0ICAgIFxuXHRcdCAgICBpZiAoaW5zaWRlQ29kZUJsb2NrKSBjb250aW51ZTtcblxuXHRcdCAgICBjb25zdCB0YWcgPSBtYXRjaFswXS50cmltKCk7XG5cdFx0ICAgIC8vIExvb2sgYWhlYWQgZnJvbSB0aGUgY3VycmVudCBtYXRjaCBhbmQgc2VlIGlmIGl0J3MgZm9sbG93ZWQgYnkgXV1cblx0XHQgICAgaWYgKGZpbGVDb250ZW50LnNsaWNlKG1hdGNoLmluZGV4LCBtYXRjaC5pbmRleCArIHRhZy5sZW5ndGggKyAyKS5lbmRzV2l0aChcIl1dXCIpKSB7XG5cdFx0ICAgICAgICBjb250aW51ZTsgLy8gU2tpcCB0aGlzIG1hdGNoIGFzIGl0J3MgcGFydCBvZiBhIHdpa2lsaW5rXG5cdFx0ICAgIH1cblx0XHQgICAgdGFnUG9zaXRpb25zLnB1c2goe3RhZzp0YWcsIGluZGV4Om1hdGNoLmluZGV4LCBzb3VyY2U6ZmlsZS5uYW1lfSk7IFxuXHRcdCAgICAvL2NvbnNvbGUubG9nKHRhZ1Bvc2l0aW9uc1t0YWdQb3NpdGlvbnMubGVuZ3RoLTFdKVxuXHRcdH1cblx0XHQvL2NvbnNvbGUubG9nKCdtYXJrZG93biB0YWcgY291bnQ6ICcgKyB0YWdQb3NpdGlvbnMubGVuZ3RoKVxuXHRcdC8vY29uc29sZS5sb2codGFnUG9zaXRpb25zKVxuXHRcdHJldHVybiB0YWdQb3NpdGlvbnM7XG5cdH1cblxuXHRhc3NpZ25NYXJrZG93blRhZ3MgKHRhZ1Bvc2l0aW9uczpBcnJheSwgdGFnRWxlbWVudHMsIHN0YXJ0SW5kZXgsIHR5cGUpIHtcblx0XHQvL2NvbnNvbGUubG9nKCctLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nKVxuXHRcdC8vY29uc29sZS5sb2coc3RhcnRJbmRleClcblx0XHQvL2NvbnNvbGUubG9nKHRhZ1Bvc2l0aW9ucylcblx0XHRsZXQgdGFnRWw7XG5cdFx0Y29uc3QgdGFnRWxBcnJheSA9IEFycmF5LmZyb20odGFnRWxlbWVudHMpO1xuXHRcdGxldCB0YWdFbEluZGV4ID0gMDtcblx0XHQvL3RhZ1Bvc2l0aW9ucy5mb3JFYWNoKGl0ZW0gPT4gY29uc29sZS5sb2coaXRlbS5pbmRleCwgaXRlbS50YWcpKTtcblx0XHR0YWdQb3NpdGlvbnMuZm9yRWFjaCgodGFnUG9zLCBpKSA9PiB7XG5cdFx0XHRpZiAodGFnUG9zaXRpb25zW2ldLmluZGV4ID49IHN0YXJ0SW5kZXgpIHtcblx0XHRcdFx0dGFnRWwgPSB0YWdFbEFycmF5W3RhZ0VsSW5kZXhdIGFzIEhUTUxFbGVtZW50O1xuXHRcdFx0XHRpZiAodGFnRWwpIHtcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKHRhZ0VsLCB0YWdQb3NpdGlvbnNbaV0udGFnLCB0YWdQb3NpdGlvbnNbaV0uaW5kZXgpO1xuICAgICAgICBcdFx0XHR0YWdFbC5zZXRBdHRyaWJ1dGUoJ21kLWluZGV4JywgdGFnUG9zaXRpb25zW2ldLmluZGV4KTtcbiAgICAgICAgXHRcdFx0dGFnRWwuc2V0QXR0cmlidXRlKCdmaWxlLXNvdXJjZScsIHRhZ1Bvc2l0aW9uc1tpXS5zb3VyY2UpO1xuICAgICAgICBcdFx0XHR0YWdFbC5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCB0eXBlKTtcbiAgICAgICAgXHRcdFx0Ly90YWdFbEluZGV4Kys7XG4gICAgICAgIFx0XHR9IFxuICAgICAgICBcdFx0dGFnRWxJbmRleCsrO1xuICAgIFx0XHR9IFxuXHRcdH0pOyBcblx0XHRyZXR1cm4gdGFnRWxBcnJheTsgLy9BcnJheS5mcm9tKHRhZ0VsZW1lbnRzKTsgXG5cdH1cblxuXHRhc3luYyBwcm9jZXNzRW1iZWRzIChlbGVtZW50LCBpZHM9Wyd0YWctc3VtbWFyeS1ibG9jaycsICdtYXJrZG93bi1lbWJlZCddKSB7XG4gXHRcdC8vY29uc3QgZW1iZWRzID0gYXdhaXQgZWxlbWVudC5xdWVyeVNlbGVjdG9yQWxsKCcubW9kLWFjdGl2ZSAudGFnOm5vdCgubWFya2Rvd24tZW1iZWQgLnRhZyk6bm90KC50YWctc3VtbWFyeS1ibG9jayAudGFnKScpO1xuXHRcdC8vY29uc29sZS5sb2coJ3Byb2Nlc3NFbWJlZHMnKVxuXHRcdGNvbnN0IGVtYmVkcyA9IGF3YWl0IGVsZW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLnRhZy1zdW1tYXJ5LWJsb2NrLCAubWFya2Rvd24tZW1iZWQnKTtcblx0XHQvL2xldCBlbWJlZGVkVGFnRmlsZXMgPSBbXTtcblx0XHQvL2NvbnNvbGUubG9nKGVtYmVkcylcblx0XHRlbWJlZHMuZm9yRWFjaChhc3luYyAoZW1iZWQpID0+IHtcblx0XHRcdC8vY29uc29sZS5sb2coZW1iZWQpXG5cdFx0XHQvL2lmIChlbWJlZC5jbGFzc0xpc3QuY29udGFpbnMoJ3RhZy1zdW1tYXJ5LWJsb2NrJykgJiYgaWRzLmluY2x1ZGVzKCd0YWctc3VtbWFyeS1ibG9jaycpKSB7XG5cdFx0XHRpZiAoZW1iZWQuY2xhc3NMaXN0LmNvbnRhaW5zKCd0YWctc3VtbWFyeS1ibG9jaycpKSB7XG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ3Byb2Nlc3Mgc3VtbWFyeScpXG5cdFx0XHRcdHRoaXMucHJvY2Vzc1RhZ1N1bW1hcnkoZW1iZWQpO1x0XG5cblx0XHRcdC8vfSBlbHNlIGlmIChlbWJlZC5jbGFzc0xpc3QuY29udGFpbnMoJ21hcmtkb3duLWVtYmVkJykgJiYgaWRzLmluY2x1ZGVzKCdtYXJrZG93bi1lbWJlZCcpKSB7XG5cdFx0XHR9IGVsc2UgaWYgKGVtYmVkLmNsYXNzTGlzdC5jb250YWlucygnbWFya2Rvd24tZW1iZWQnKSkge1xuXG5cdFx0XHRcdHRoaXMucHJvY2Vzc05hdGl2ZUVtYmVkKGVtYmVkKTtcblx0XHRcdFx0XG5cdFx0XHRcdGlmIChBcnJheS5mcm9tKGVtYmVkLnF1ZXJ5U2VsZWN0b3JBbGwoJy50YWctc3VtbWFyeS1ibG9jaycpKS5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdFx0dGhpcy5wcm9jZXNzVGFnU3VtbWFyeShlbWJlZCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQvL25ldyBOb3RpY2UoJ1RhZyBCdWRkeTogVGFnIGVtYmVkIGluIHVuc3VwcG9ydGVkIGVsZW1lbnQuJyk7XG5cdFx0XHRcdC8vIEhhbmRsZSB0aGlzIGlzc3VlIG9uIGNsaWNrLlxuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdC8vcmV0dXJuIGVtYmVkZWRUYWdGaWxlcztcblx0fVxuXG5cdGFzeW5jIHByb2Nlc3NOYXRpdmVFbWJlZCAoZW1iZWQpIHtcblx0XHRjb25zdCBsaW5rRWxlbWVudCA9IGVtYmVkLmdldEF0dHJpYnV0ZSgnc3JjJyk7IC8vdGhpcy5maW5kQW5jZXN0b3IoY2xpY2tlZFRhZywgJ3NwYW4nKVxuXHRcdGxldCBmaWxlUGF0aCA9IGVtYmVkLmdldEF0dHJpYnV0ZSgnc3JjJyk7XG5cdFx0Y29uc3QgbGlua0FycmF5ID0gZmlsZVBhdGguc3BsaXQoJyMnKTtcblx0XHRmaWxlUGF0aCA9IGxpbmtBcnJheVswXS50cmltKCkgKyAnLm1kJztcblx0XHRjb25zdCBmaWxlID0gYXdhaXQgdGhpcy52YWxpZGF0ZUZpbGVQYXRoKGZpbGVQYXRoKVxuXHRcdGlmIChmaWxlKSB7XG5cdFx0XHRjb25zdCBmaWxlQ29udGVudCA9IGF3YWl0IGFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdFx0Y29uc3QgZW1iZWRlZFRhZ0ZpbGUgPSBhd2FpdCB0aGlzLmdldE1hcmtkb3duVGFncyhmaWxlLCBmaWxlQ29udGVudClcblx0XHRcdC8vZW1iZWRlZFRhZ0ZpbGVzLnB1c2goZW1iZWRlZFRhZ0ZpbGUpO1xuXHRcdFx0XG5cdFx0XHRjb25zdCB0ZW1wQ29tcG9uZW50ID0gbmV3IFRlbXBDb21wb25lbnQoKTtcblx0XHRcdGNvbnN0IHRlbXBDb250YWluZXJIVE1MID0gY3JlYXRlRWwoXCJkaXZcIik7XG5cdFx0XHRcblx0XHRcdGF3YWl0IE1hcmtkb3duUmVuZGVyZXIucmVuZGVyTWFya2Rvd24oZmlsZUNvbnRlbnQsIHRlbXBDb250YWluZXJIVE1MLCBmaWxlLnBhdGgsIHRlbXBDb21wb25lbnQpO1xuXHRcdFx0XG5cdFx0XHQvL2NvbnN0IGlubmVyVGV4dCA9IHRoaXMuY2xlYW5TdHJpbmcoZW1iZWQucXVlcnlTZWxlY3RvcignLm1hcmtkb3duLWVtYmVkLWNvbnRlbnQnKS5pbm5lclRleHQpO1xuXHRcdFx0Ly9jb25zdCBzdGFydEluZGV4ID0gdGhpcy5jbGVhblN0cmluZyh0ZW1wQ29udGFpbmVySFRNTC5pbm5lclRleHQpLmluZGV4T2YoaW5uZXJUZXh0KTtcblx0XHRcdGNvbnN0IGlubmVyVGV4dCA9IGVtYmVkLnF1ZXJ5U2VsZWN0b3IoJy5tYXJrZG93bi1lbWJlZC1jb250ZW50JykuaW5uZXJUZXh0O1xuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHRlbXBDb250YWluZXJIVE1MLmlubmVyVGV4dC5pbmRleE9mKGlubmVyVGV4dCk7XG5cdFx0XHRcblx0XHRcdHRoaXMuYXNzaWduTWFya2Rvd25UYWdzKGVtYmVkZWRUYWdGaWxlLCBlbWJlZC5xdWVyeVNlbGVjdG9yQWxsKCcudGFnJyksIHN0YXJ0SW5kZXgsICduYXRpdmUtZW1iZWQnKTtcblx0XHR9XG5cdH1cblxuXHRhc3luYyBwcm9jZXNzVGFnU3VtbWFyeSAoZW1iZWQpIHtcblx0XHRsZXQgc3VtbWFyeUJsb2NrcyA9IGVtYmVkLnF1ZXJ5U2VsZWN0b3JBbGwoJ2Jsb2NrcXVvdGUnKTsgXG5cdFx0c3VtbWFyeUJsb2Nrcy5mb3JFYWNoKGFzeW5jIChibG9jaywgaW5kZXgpID0+IHtcblxuXHRcdFx0Y29uc3QgZmlsZVBhdGggPSBibG9jay5nZXRBdHRyaWJ1dGUoJ2ZpbGUtc291cmNlJyk7IC8vIGxpbmtFbGVtZW50LmdldEF0dHJpYnV0ZSgnZGF0YS1ocmVmJylcblx0XHRcdGNvbnN0IGZpbGUgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoZmlsZVBhdGgpO1xuXHRcdFx0Y29uc3QgdGVtcENvbXBvbmVudCA9IG5ldyBUZW1wQ29tcG9uZW50KCk7XG5cblx0XHRcdGlmIChmaWxlKSB7XG5cdFx0XHRcdGxldCBmaWxlQ29udGVudCA9IGF3YWl0IGFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdFx0XHRjb25zdCBlbWJlZGVkVGFnRmlsZSA9IGF3YWl0IHRoaXMuZ2V0TWFya2Rvd25UYWdzKGZpbGUsIGZpbGVDb250ZW50KTtcblx0XHRcdFx0XG5cdFx0XHRcdC8vIENyZWF0ZSBhIHRlbXBvcnR5IGVsZW1lbnQgYmxvY2sgc28gd2UgY2FuIG1hdGNoIG1hdGNoIHRleHQgb25seSBjb250ZW50IG9mIHRoaXMgZWxlbWVudCB3aXRoIGl0J3Mgc291cmNlIG5vdGVcblx0XHRcdFx0Y29uc3QgdGVtcEJsb2NrID0gYmxvY2suY2xvbmVOb2RlKHRydWUpO1xuXHRcdFx0XHQvL3RlbXBCbG9jay5xdWVyeVNlbGVjdG9yKCdicicpPy5yZW1vdmUoKTtcblx0XHRcdFx0Ly90ZW1wQmxvY2sucXVlcnlTZWxlY3Rvcignc3Ryb25nJyk/LnJlbW92ZSgpOyBcblx0XHRcdFx0dGVtcEJsb2NrLnF1ZXJ5U2VsZWN0b3IoJy50YWdzdW1tYXJ5LWl0ZW0tdGl0bGUnKT8ucmVtb3ZlKCk7IFxuXHRcdFx0XHR0ZW1wQmxvY2sucXVlcnlTZWxlY3RvcignLnRhZ3N1bW1hcnktYnV0dG9ucycpPy5yZW1vdmUoKTsgXG5cdFx0XHRcdC8vY29uc3QgYmxvY2tUZXh0ID0gdGhpcy5jbGVhblN0cmluZyh0ZW1wQmxvY2suaW5uZXJUZXh0KTsgLy8gZnVjayB0aGlzIGJ1ZyFcblx0XHRcdFx0Ly9jb25zdCBzdGFydEluZGV4ID0gdGhpcy5jbGVhblN0cmluZyhmaWxlQ29udGVudCkuaW5kZXhPZihibG9ja1RleHQpXG5cdFx0XHRcdFxuXHRcdFx0XHQvLy8vL1xuXHRcdFx0XHQvLyBvbGQgd2F5IGJlZm9yZSB3ZSBzdG9yZWQgdGhlIE1EIHBhcmFncmFwaCBpbiB0aGUgaHRtbCBlbGVtZW50XG5cdFx0XHRcdC8vY29uc3QgbWFya2Rvd25CbG9jayA9IGh0bWxUb01hcmtkb3duKHRlbXBCbG9jaykudHJpbSgpO1xuXHRcdFx0XHQvLy8vL1xuXHRcdFx0XHQvLyBORVcgV0FZXG5cdFx0XHRcdGNvbnN0IG1hcmtkb3duQmxvY2sgPSBibG9jay5nZXRBdHRyaWJ1dGUoJ21kLXNvdXJjZScpLnRyaW0oKTtcblxuXG5cdFx0XHRcdC8vZmlsZUNvbnRlbnQgPSBmaWxlQ29udGVudC5yZXBsYWNlKC9cXHMrL2csICcgJyk7IC8vIHdoaXRlc3BhY2Ugbm9ybWFsaXphdGlvbiBiZWNhdXNlIHRoZSB0YWcgc3VtbWFyeSB3aWxsIGhhdmUgZG9uZSB0aGlzIHRvIHRoZSBibG9ja1xuXHRcdFx0XHQvLyBub3BlLCBjYW4ndCBkbyB0aGF0IGJlY2F1c2UgdGhlbiB0aGUgaW5kZXhlcyB3aWxsIGJlIG9mZi5cblx0XHRcdFx0XG5cblx0XHRcdFx0Ly9jb25zdCBibG9ja1RleHQgPSBtYXJrZG93bkJsb2NrOyAvL3RlbXBCbG9jay5pbm5lclRleHQudHJpbSgpO1xuXHRcdFx0XHRjb25zdCBzdGFydEluZGV4ID0gZmlsZUNvbnRlbnQuaW5kZXhPZihtYXJrZG93bkJsb2NrKTtcblx0XHRcdFx0Ly9jb25zdCB0ZW1wRG9tID0gY3JlYXRlRWwoJ2RpdicpOyBcblx0XHRcdFx0Ly9hd2FpdCBNYXJrZG93blJlbmRlcmVyLnJlbmRlck1hcmtkb3duKGZpbGVDb250ZW50LCB0ZW1wRG9tLCAnJywgdGVtcENvbXBvbmVudCk7XG5cdFx0XHRcdC8vY29uc3QgdGVtcENvbnRlbnQgPSB0ZW1wRG9tLmlubmVyVGV4dFxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCctLS0tLT4gJyArIGZpbGVDb250ZW50LmluZGV4T2YoJyN0b29sczInKSlcblx0XHRcdFx0Lypjb25zb2xlLmxvZyhmaWxlQ29udGVudClcblx0XHRcdFx0Y29uc29sZS5sb2coJy0tLS0tLS0tLS0tLS0tLS0nKVxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKEpTT04uc3RyaW5naWZ5KG1hcmtkb3duQmxvY2spKSAvL2NvbnNvbGUubG9nKGJsb2NrVGV4dClcblx0XHRcdFx0Y29uc29sZS5sb2cobWFya2Rvd25CbG9jaylcblx0XHRcdFx0Y29uc29sZS5sb2coJy0tLS0tLS0tLS0tLS0tLS0nKVxuXHRcdFx0XHRjb25zb2xlLmxvZyhmaWxlQ29udGVudC5pbmRleE9mKG1hcmtkb3duQmxvY2spKSovXG5cdFx0XHRcdC8vIGh0bWxUb01hcmtkb3duKHN1bW1hcnlDb250YWluZXIuaW5uZXJIVE1MKVxuXG5cdFx0XHRcdC8vY29uc29sZS5sb2coc3RhcnRJbmRleClcblx0XHRcdFx0dGhpcy5hc3NpZ25NYXJrZG93blRhZ3MoZW1iZWRlZFRhZ0ZpbGUsIGJsb2NrLnF1ZXJ5U2VsZWN0b3JBbGwoJy50YWcnKSwgc3RhcnRJbmRleCwgJ3BsdWdpbi1zdW1tYXJ5Jyk7XG5cdFx0XHR9XG5cdFx0fSk7XHRcdFxuXHR9XG5cblx0YXN5bmMgc3VtbWFyeUNvZGVCbG9ja1Byb2Nlc3NvciAoc291cmNlLCBlbCwgY3R4KSB7XG5cdFx0Ly8gSW5pdGlhbGl6ZSB0YWcgbGlzdFxuXHRcdGxldCB0YWdzOiBzdHJpbmdbXSA9IEFycmF5KCk7XG5cdFx0bGV0IGluY2x1ZGU6IHN0cmluZ1tdID0gQXJyYXkoKTtcblx0XHRsZXQgZXhjbHVkZTogc3RyaW5nW10gPSBBcnJheSgpO1xuXHRcdGxldCBzZWN0aW9uczogc3RyaW5nW10gPSBBcnJheSgpO1xuXHRcdGxldCBtYXg6IG51bWJlciA9IDUwO1xuXHRcdGNvbnN0IG1heFBhdHRlcm4gPSAvXlxccyptYXg6XFxzKihcXGQrKVxccyokLztcblx0XHRsZXQgbWF0Y2g7XG5cblx0XHQvLyBQcm9jZXNzIHJvd3MgaW5zaWRlIGNvZGVibG9ja1xuXHRcdGNvbnN0IHJvd3MgPSBzb3VyY2Uuc3BsaXQoXCJcXG5cIikuZmlsdGVyKChyb3cpID0+IHJvdy5sZW5ndGggPiAwKTtcblx0XHRyb3dzLmZvckVhY2goKGxpbmUpID0+IHtcblx0XHRcdC8vIENoZWNrIGlmIHRoZSBsaW5lIHNwZWNpZmllcyB0aGUgdGFncyAoT1IpXG5cdFx0XHRpZiAobGluZS5tYXRjaCgvXlxccyp0YWdzOltcXHB7TH0wLTlfXFwtLyMgXSskL2d1KSkge1xuXHRcdFx0XHRjb25zdCBjb250ZW50ID0gbGluZS5yZXBsYWNlKC9eXFxzKnRhZ3M6LywgXCJcIikudHJpbSgpO1xuXG5cdFx0XHRcdC8vIEdldCB0aGUgbGlzdCBvZiB2YWxpZCB0YWdzIGFuZCBhc3NpZ24gdGhlbSB0byB0aGUgdGFncyB2YXJpYWJsZVxuXHRcdFx0XHRsZXQgbGlzdCA9IGNvbnRlbnQuc3BsaXQoL1xccysvKS5tYXAoKHRhZykgPT4gdGFnLnRyaW0oKSk7XG5cdFx0XHRcdGxpc3QgPSBsaXN0LmZpbHRlcigodGFnKSA9PiB7XG5cdFx0XHRcdFx0aWYgKHRhZy5tYXRjaCgvXiNbXFxwe0x9XStbXiNdKiQvdSkpIHtcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblx0XHRcdFx0dGFncyA9IGxpc3Q7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIHRoZSBsaW5lIHNwZWNpZmllcyB0aGUgdGFncyB0byBpbmNsdWRlIChBTkQpXG5cdFx0XHRpZiAobGluZS5tYXRjaCgvXlxccyppbmNsdWRlOltcXHB7TH0wLTlfXFwtLyMgXSskL2d1KSkge1xuXHRcdFx0XHRjb25zdCBjb250ZW50ID0gbGluZS5yZXBsYWNlKC9eXFxzKmluY2x1ZGU6LywgXCJcIikudHJpbSgpO1xuXG5cdFx0XHRcdC8vIEdldCB0aGUgbGlzdCBvZiB2YWxpZCB0YWdzIGFuZCBhc3NpZ24gdGhlbSB0byB0aGUgaW5jbHVkZSB2YXJpYWJsZVxuXHRcdFx0XHRsZXQgbGlzdCA9IGNvbnRlbnQuc3BsaXQoL1xccysvKS5tYXAoKHRhZykgPT4gdGFnLnRyaW0oKSk7XG5cdFx0XHRcdGxpc3QgPSBsaXN0LmZpbHRlcigodGFnKSA9PiB7XG5cdFx0XHRcdFx0aWYgKHRhZy5tYXRjaCgvXiNbXFxwe0x9XStbXiNdKiQvdSkpIHtcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblx0XHRcdFx0aW5jbHVkZSA9IGxpc3Q7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIHRoZSBsaW5lIHNwZWNpZmllcyB0aGUgdGFncyB0byBleGNsdWRlIChOT1QpXG5cdFx0XHRpZiAobGluZS5tYXRjaCgvXlxccypleGNsdWRlOltcXHB7TH0wLTlfXFwtLyMgXSskL2d1KSkge1xuXHRcdFx0XHRjb25zdCBjb250ZW50ID0gbGluZS5yZXBsYWNlKC9eXFxzKmV4Y2x1ZGU6LywgXCJcIikudHJpbSgpO1xuXG5cdFx0XHRcdC8vIEdldCB0aGUgbGlzdCBvZiB2YWxpZCB0YWdzIGFuZCBhc3NpZ24gdGhlbSB0byB0aGUgZXhjbHVkZSB2YXJpYWJsZVxuXHRcdFx0XHRsZXQgbGlzdCA9IGNvbnRlbnQuc3BsaXQoL1xccysvKS5tYXAoKHRhZykgPT4gdGFnLnRyaW0oKSk7XG5cdFx0XHRcdGxpc3QgPSBsaXN0LmZpbHRlcigodGFnKSA9PiB7XG5cdFx0XHRcdFx0aWYgKHRhZy5tYXRjaCgvXiNbXFxwe0x9XStbXiNdKiQvdSkpIHtcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9KTtcblx0XHRcdFx0ZXhjbHVkZSA9IGxpc3Q7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGlmIHRoZSBsaW5lIHNwZWNpZmllcyBzZWN0aW9ucyBvZiBhIG5vdGVcblx0XHRcdGlmIChsaW5lLm1hdGNoKC9eXFxzKnNlY3Rpb25zOltcXHB7TH0wLTlfXFwtLyMsIF0rJC9ndSkpIHtcblx0XHRcdFx0Y29uc3QgY29udGVudCA9IGxpbmUucmVwbGFjZSgvXlxccypzZWN0aW9uczovLCBcIlwiKS50cmltKCk7XG5cdFx0XHRcdC8vIEdldCB0aGUgbGlzdCBvZiBzZWN0aW9ucyBhbmQgYXNzaWduIHRoZW0gdG8gdGhlIHNlY3Rpb25zIHZhcmlhYmxlXG5cdFx0XHRcdGxldCBsaXN0ID0gY29udGVudC5zcGxpdCgnLCcpLm1hcCgoc2VjKSA9PiBzZWMudHJpbSgpKTtcblx0XHRcdFx0c2VjdGlvbnMgPSBsaXN0O1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDaGVjayBpZiB0aGUgbGluZSBzcGVjaWZpZXMgbWF4IG51bWJlciBvZiBibG9ja3MgdG8gZGlzcGxheVxuXHRcdFx0bWF0Y2ggPSBsaW5lLm1hdGNoKG1heFBhdHRlcm4pO1xuXHRcdFx0aWYgKG1hdGNoKSB7XG4gICAgXHRcdFx0bWF4ID0gTWF0aC5taW4oNTAsIE51bWJlcihtYXRjaFsxXSkpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdGNvbnN0IGNvZGVCbG9jayA9ICdgYGB0YWctc3VtbWFyeVxcbicrc291cmNlLnRyaW0oKSsnXFxuYGBgJ1xuXHRcdC8vIENyZWF0ZSBzdW1tYXJ5IG9ubHkgaWYgdGhlIHVzZXIgc3BlY2lmaWVkIHNvbWUgdGFnc1xuXHRcdGlmICh0YWdzLmxlbmd0aCA+IDAgfHwgaW5jbHVkZS5sZW5ndGggPiAwKSB7XG5cdFx0XHRhd2FpdCB0aGlzLmNyZWF0ZVN1bW1hcnkoZWwsIHRhZ3MsIGluY2x1ZGUsIGV4Y2x1ZGUsIHNlY3Rpb25zLCBtYXgsIGN0eC5zb3VyY2VQYXRoLCBjb2RlQmxvY2spO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmNyZWF0ZUVtcHR5U3VtbWFyeShlbCwgdGFncz90YWdzOltdLCBpbmNsdWRlP2luY2x1ZGU6W10sIGV4Y2x1ZGU/ZXhjbHVkZTpbXSwgc2VjdGlvbnM/c2VjdGlvbnM6W10sIG1heD9tYXg6W10sIGN0eC5zb3VyY2VQYXRoP2N0eC5zb3VyY2VQYXRoOicnLCBjb2RlQmxvY2spO1xuXHRcdH0gXG5cdH07IFxuXG5cdGNyZWF0ZUVtcHR5U3VtbWFyeShlbGVtZW50OiBIVE1MRWxlbWVudCwgdGFnczogU3RyaW5nW10sIGluY2x1ZGU6IHN0cmluZ1tdLCBleGNsdWRlOiBzdHJpbmdbXSwgc2VjdGlvbnM6IHN0cmluZ1tdLCBtYXg6IG51bWJlciwgZmlsZUN0eDogc3RyaW5nLCBtZFNvdXJjZTpzdHJpbmcpIHtcblx0XHRjb25zdCBjb250YWluZXIgPSBjcmVhdGVFbCgnZGl2Jyk7XG5cdFx0Ly9jb25zdCBidXR0b25Db250YWluZXIgPSBjcmVhdGVFbCgnZGl2Jyk7XG5cdFx0Ly9idXR0b25Db250YWluZXIuc2V0QXR0cmlidXRlKCdjbGFzcycsICd0YWdzdW1tYXJ5LWJ1dHRvbnMnKTtcblx0XHRjb25zdCB0ZXh0RGl2ID0gY3JlYXRlRWwoXCJibG9ja3F1b3RlXCIpO1xuXHRcdC8vY29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAndGFnc3VtbWFyeS1ub3RhZ3MnKTtcblx0XHR0ZXh0RGl2LmlubmVySFRNTCA9IFwiVGhlcmUgYXJlIG5vIGZpbGVzIHdpdGggdGFnZ2VkIHBhcmFncmFwaHMgdGhhdCBtYXRjaCB0aGUgdGFnczo8YnI+XCIgKyAodGFncy5sZW5ndGg+MD90YWdzLmpvaW4oJywgJyk6XCJObyB0YWdzIHNwZWNpZmllZC5cIikgKyBcIjxicj5cIjtcblx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQodGV4dERpdik7XG5cdFx0Ly9jb25zdCB2aWV3ID0gdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KTtcblx0XHQvL2NvbnN0IHN3aXRjaE1vZGVCdXR0b24gPSB0aGlzLm1ha2VTd2l0Y2hUb0VkaXRpbmdCdXR0b24gKHZpZXcpO1xuXHRcdC8vY29udGFpbmVyLmFwcGVuZENoaWxkKHN3aXRjaE1vZGVCdXR0b24pO1xuXHRcdC8vY29uc29sZS5sb2coaW5jbHVkZS5sZW5ndGgpXG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MnLCAoKHRhZ3MubGVuZ3RoPjApP3RhZ3Muam9pbignLCcpOicnKSk7XG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MtaW5jbHVkZScsIChpbmNsdWRlP2luY2x1ZGUuam9pbignLCcpOicnKSk7XG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXRhZ3MtZXhjbHVkZScsIChleGNsdWRlP2V4Y2x1ZGUuam9pbignLCcpOicnKSk7XG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXNlY3Rpb25zJywgKHNlY3Rpb25zP3NlY3Rpb25zLmpvaW4oJywnKTonJykpO1xuXHRcdGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay1tYXgnLCBtYXgpO1xuXHRcdGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay1jb2RlJywgbWRTb3VyY2UpO1xuXHRcdC8vaWYgKHRoaXMuc2V0dGluZ3MuZGVidWdNb2RlKSBcblx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5tYWtlU3VtbWFyeVJlZnJlc2hCdXR0b24oY29udGFpbmVyKSk7O1xuXG5cdFx0ZWxlbWVudC5yZXBsYWNlV2l0aChjb250YWluZXIpO1xuXHR9XG5cblx0YXN5bmMgY3JlYXRlU3VtbWFyeShcblx0XHRlbGVtZW50OiBIVE1MRWxlbWVudCwgXG5cdFx0dGFnczogc3RyaW5nW10sIFxuXHRcdGluY2x1ZGU6IHN0cmluZ1tdLCBcblx0XHRleGNsdWRlOiBzdHJpbmdbXSwgXG5cdFx0c2VjdGlvbnM6IHN0cmluZ1tdLFxuXHRcdG1heDogbnVtYmVyLCBcblx0XHRmaWxlQ3R4OiBzdHJpbmcsXG5cdFx0bWRTb3VyY2U6c3RyaW5nKSB7XG5cdFx0XG5cdFx0Y29uc3QgYWN0aXZlRmlsZSA9IGF3YWl0IHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk7XG5cdFx0Y29uc3QgdmFsaWRUYWdzID0gdGFncy5jb25jYXQoaW5jbHVkZSk7IC8vIEFsbCB0aGUgdGFncyBzZWxlY3RlZCBieSB0aGUgdXNlclxuXHRcdGNvbnN0IHRlbXBDb21wb25lbnQgPSBuZXcgVGVtcENvbXBvbmVudCgpO1xuXHRcdGNvbnN0IHN1bW1hcnlDb250YWluZXIgPSBjcmVhdGVFbCgnZGl2Jyk7XG5cdFx0XG5cdFx0c3VtbWFyeUNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgJ3RhZy1zdW1tYXJ5LWJsb2NrJyk7XG5cdFx0XG5cdFx0Ly8gR2V0IGZpbGVzXG5cdFx0bGV0IGxpc3RGaWxlcyA9IHRoaXMuYXBwLnZhdWx0LmdldE1hcmtkb3duRmlsZXMoKTtcblxuXHRcdC8vIEZpbHRlciBmaWxlc1xuXHRcdGxpc3RGaWxlcyA9IGxpc3RGaWxlcy5maWx0ZXIoKGZpbGUpID0+IHtcblx0XHRcdC8vIFJlbW92ZSBmaWxlcyB0aGF0IGRvIG5vdCBjb250YWluIHRoZSB0YWdzIHNlbGVjdGVkIGJ5IHRoZSB1c2VyXG5cdFx0XHRjb25zdCBjYWNoZSA9IGFwcC5tZXRhZGF0YUNhY2hlLmdldEZpbGVDYWNoZShmaWxlKTtcblx0XHRcdGNvbnN0IHRhZ3NJbkZpbGUgPSBnZXRBbGxUYWdzKGNhY2hlKTtcblxuXHRcdFx0aWYgKHZhbGlkVGFncy5zb21lKCh2YWx1ZSkgPT4gdGFnc0luRmlsZS5pbmNsdWRlcyh2YWx1ZSkpKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuICAgICAgICB9KTtcblxuXHRcdC8vIFNvcnQgZmlsZXMgYWxwaGFiZXRpY2FsbHlcblx0XHQvLyBjaGFuZ2UgdG8gc29ydCBieSBsYXN0IG1vZGlmaWVkP1xuXHRcdGxpc3RGaWxlcyA9IGxpc3RGaWxlcy5zb3J0KChmaWxlMSwgZmlsZTIpID0+IHtcblx0XHRcdGlmIChmaWxlMS5wYXRoIDwgZmlsZTIucGF0aCkge1xuXHRcdFx0XHRyZXR1cm4gLTE7XG5cdFx0XHR9IGVsc2UgaWYgKGZpbGUxLnBhdGggPiBmaWxlMi5wYXRoKSB7XG5cdFx0XHRcdHJldHVybiAxO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuIDA7XG5cdFx0XHR9XG5cdFx0fSk7XG5cblx0XHQvLyBHZXQgZmlsZXMgY29udGVudFxuXHRcdGxldCBsaXN0Q29udGVudHM6IFtURmlsZSwgc3RyaW5nXVtdID0gYXdhaXQgdGhpcy5yZWFkRmlsZXMobGlzdEZpbGVzKTtcblx0XHRsZXQgY291bnQgPSAwO1xuXG5cdFx0Ly8gQ3JlYXRlIHN1bW1hcnlcblx0XHRsZXQgc3VtbWFyeTogc3RyaW5nID0gXCJcIjtcblx0XHRsaXN0Q29udGVudHMuZm9yRWFjaCgoaXRlbSkgPT4ge1xuXHRcdFx0Ly9pZiAoY291bnQgPj0gbWF4KSByZXR1cm47XG5cblx0XHRcdC8vIEdldCBmaWxlcyBuYW1lXG5cdFx0XHRjb25zdCBmaWxlTmFtZSA9IGl0ZW1bMF0ubmFtZS5yZXBsYWNlKC8ubWQkL2csIFwiXCIpO1xuXHRcdFx0Y29uc3QgZmlsZVBhdGggPSBpdGVtWzBdLnBhdGg7XG5cdFx0XHQvL2NvbnNvbGUubG9nKGFjdGl2ZUZpbGUpXG5cdFx0XHQvLyBEbyBub3QgYWRkIHRoaXMgaXRlbSBpZiBpdCdzIGluIHRoZSBzYW1lIGZpbGUgd2UncmUgY3JlYXRpbmcgdGhlIHN1bW1hcnlcblx0XHRcdC8vIHNob3VsZCBmaWx0ZXIgdGhpcyBmaWxlIG91dCBlYXJsaWVyXG5cdFx0XHRpZiAoYWN0aXZlRmlsZSkge1xuXHRcdFx0XHRpZiAoYWN0aXZlRmlsZS5uYW1lID09IGl0ZW1bMF0ubmFtZSkgcmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBHZXQgcGFyYWdyYXBoc1xuXHRcdFx0bGV0IGxpc3RQYXJhZ3JhcGhzOiBzdHJpbmdbXSA9IEFycmF5KCk7XG5cdFx0XHRjb25zdCBibG9ja3MgPSBpdGVtWzFdLnNwbGl0KC9cXG5cXHMqXFxuLykuZmlsdGVyKChyb3cpID0+IHJvdy50cmltKCkubGVuZ3RoID4gMCk7XG5cblx0XHRcdC8vIEdldCBsaXN0IGl0ZW1zXG5cdFx0XHRibG9ja3MuZm9yRWFjaCgocGFyYWdyYXBoKSA9PiB7XG5cdFx0XHRcdFxuXHRcdFx0XHQvLyBDaGVjayBpZiB0aGUgcGFyYWdyYXBoIGlzIGFub3RoZXIgcGx1Z2luXG5cdFx0XHRcdGxldCB2YWxpZCA9IGZhbHNlO1xuXHRcdFx0XHRsZXQgbGlzdFRhZ3MgPSBwYXJhZ3JhcGgubWF0Y2goLyNbXFxwe0x9MC05X1xcLS8jXSsvZ3UpO1xuXHRcdFx0XHRcblx0XHRcdFx0aWYgKGxpc3RUYWdzICE9IG51bGwgJiYgbGlzdFRhZ3MubGVuZ3RoID4gMCkge1xuXHRcdFx0XHRcdC8vY29uc29sZS5sb2coJ3BhcmFncmFwaC5jb250YWlucyhcImBgYFwiKSA6ICcgKyBwYXJhZ3JhcGguY29udGFpbnMoXCJgYGBcIikpXG5cdFx0XHRcdFx0aWYgKCFwYXJhZ3JhcGguY29udGFpbnMoXCJgYGBcIikpIHtcblx0XHRcdFx0XHRcdC8vY29uc29sZS5sb2coaW5jbHVkZSlcblx0XHRcdFx0XHRcdHZhbGlkID0gdGhpcy5pc1ZhbGlkVGV4dChsaXN0VGFncywgdGFncywgaW5jbHVkZSwgZXhjbHVkZSk7XG5cdFx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKHZhbGlkKVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh2YWxpZCkge1xuXHRcdFx0XHRcdC8vIEFkZCBwYXJhZ3JhcGhzIGFuZCB0aGUgaXRlbXMgb2YgYSBsaXN0XG5cdFx0XHRcdFx0bGV0IGxpc3RJdGVtczogc3RyaW5nW10gPSBBcnJheSgpO1xuXHRcdFx0XHRcdGxldCBpdGVtVGV4dCA9IFwiXCI7XG5cblx0XHRcdFx0XHRwYXJhZ3JhcGguc3BsaXQoJ1xcblxccypcXG4nKS5mb3JFYWNoKChsaW5lKSA9PiB7XG5cdFx0XHRcdFx0XHRpZiAoY291bnQgPj0gbWF4KSByZXR1cm47XG5cdFx0XHRcdFx0XHRsZXQgaXNMaXN0ID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRpc0xpc3QgPSBsaW5lLnNlYXJjaCgvKFxccypbXFwtXFwrXFwqXSl7MX18KFswLTldXFwuKXsxfVxccysvKSAhPSAtMVxuXG5cdFx0XHRcdFx0XHRpZiAoIWlzTGlzdCkge1xuXHRcdFx0XHRcdFx0XHQvLyBBZGQgbm9ybWFsIHBhcmFncmFwaHNcblx0XHRcdFx0XHRcdFx0bGlzdFBhcmFncmFwaHMucHVzaChsaW5lKTtcblx0XHRcdFx0XHRcdFx0aXRlbVRleHQgPSBcIlwiO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0bGluZS5zcGxpdCgnXFxuJykuZm9yRWFjaCgoaXRlbUxpbmUpID0+IHtcblx0XHRcdFx0XHRcdFx0XHQvLyBHZXQgdGhlIGl0ZW0ncyBsZXZlbFxuXHRcdFx0XHRcdFx0XHRcdGxldCBsZXZlbCA9IDA7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZW5kSW5kZXggPSBpdGVtTGluZS5zZWFyY2goL1tcXC1cXCtcXCpdezF9fChbMC05XVxcLil7MX1cXHMrLyk7XG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgdGFiVGV4dCA9IGl0ZW1MaW5lLnNsaWNlKDAsIGVuZEluZGV4KTtcblx0XHRcdFx0XHRcdFx0XHRjb25zdCB0YWJzID0gdGFiVGV4dC5tYXRjaCgvXFx0L2cpO1xuXHRcdFx0XHRcdFx0XHRcdGlmICh0YWJzKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRsZXZlbCA9IHRhYnMubGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHQvLyBHZXQgaXRlbXMgdHJlZVxuXHRcdFx0XHRcdFx0XHRcdGlmIChsZXZlbCA9PSAwKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoaXRlbVRleHQgIT0gXCJcIikge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRsaXN0SXRlbXMucHVzaChpdGVtVGV4dCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGl0ZW1UZXh0ID0gXCJcIjtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdGl0ZW1UZXh0ID0gXCJcIiArIGl0ZW1UZXh0LmNvbmNhdChpdGVtTGluZSArIFwiXFxuXCIpO1xuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gUmVtb3ZlZCBpbmNsdWRlIGNoaWxkcmVuIHNldHRpbmdcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2UgaWYgKGxldmVsID4gMCAmJiBpdGVtVGV4dCAhPSBcIlwiKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRpdGVtVGV4dCA9IGl0ZW1UZXh0LmNvbmNhdChpdGVtTGluZSArIFwiXFxuXCIpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRjb3VudCsrXG5cdFx0XHRcdFx0fSk7XG5cblx0XHRcdFx0XHRpZiAoaXRlbVRleHQgIT0gXCJcIikge1xuXHRcdFx0XHRcdFx0bGlzdEl0ZW1zLnB1c2goaXRlbVRleHQpO1xuXHRcdFx0XHRcdFx0aXRlbVRleHQgPSBcIlwiO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIENoZWNrIHRhZ3Mgb24gdGhlIGl0ZW1zXG5cdFx0XHRcdFx0bGlzdEl0ZW1zLmZvckVhY2goKGxpbmUpID0+IHtcblx0XHRcdFx0XHRcdGxpc3RUYWdzID0gbGluZS5tYXRjaCgvI1tcXHB7TH0wLTlfXFwtLyNdKy9ndSk7XG5cdFx0XHRcdFx0XHRpZiAobGlzdFRhZ3MgIT0gbnVsbCAmJiBsaXN0VGFncy5sZW5ndGggPiAwKSB7XG5cdFx0XHRcdFx0XHRcdGlmICh0aGlzLmlzVmFsaWRUZXh0KGxpc3RUYWdzLCB0YWdzLCBpbmNsdWRlLCBleGNsdWRlKSkge1xuXHRcdFx0XHRcdFx0XHRcdGxpc3RQYXJhZ3JhcGhzLnB1c2gobGluZSk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0fVxuXHRcdFx0XHRcblx0XHRcdFx0XG5cdFx0XHR9KVxuXG5cdFx0XHQvLyBQcm9jZXNzIGVhY2ggYmxvY2sgb2YgdGV4dFxuXHRcdFx0bGlzdFBhcmFncmFwaHMuZm9yRWFjaChhc3luYyhwYXJhZ3JhcGgpID0+IHtcblx0XHRcdFx0Ly8gUmVzdG9yZSBuZXdsaW5lIGF0IHRoZSBlbmRcblx0XHRcdFx0cGFyYWdyYXBoICs9IFwiXFxuXCI7XG5cdFx0XHRcdHZhciByZWdleCA9IG5ldyBSZWdFeHA7XG5cblx0XHRcdFx0Ly8gQ2hlY2sgd2hpY2ggdGFnIG1hdGNoZXMgaW4gdGhpcyBwYXJhZ3JhcGguXG5cdFx0XHRcdHZhciB0YWdUZXh0ID0gbmV3IFN0cmluZztcblx0XHRcdFx0dmFyIHRhZ1NlY3Rpb24gPSBudWxsO1xuXHRcdFx0XHR0YWdzLmZvckVhY2goKHRhZykgPT4ge1xuXHRcdFx0XHRcdHRhZ1RleHQgPSB0YWcucmVwbGFjZSgnIycsICdcXFxcIycpO1xuXHRcdFx0XHRcdHJlZ2V4ID0gbmV3IFJlZ0V4cChgJHt0YWdUZXh0fShcXFxcV3wkKWAsICdnJyk7XG4gICAgICAgICAgICAgIFx0XHRpZiAocGFyYWdyYXBoLm1hdGNoKHJlZ2V4KSAhPSBudWxsKSB7IFxuICAgICAgICAgICAgICBcdFx0XHR0YWdTZWN0aW9uID0gdGFnXG4gICAgICAgICAgICAgIFx0XHR9IFxuICAgICAgICAgICAgXHR9KTtcbiAgICAgICAgICBcdFx0XG4gICAgICAgICAgXHRcdGNvbnN0IGJ1dHRvbkNvbnRhaW5lciA9IGNyZWF0ZUVsKCdkaXYnKTtcbiAgICAgICAgICBcdFx0YnV0dG9uQ29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAndGFnc3VtbWFyeS1idXR0b25zJylcbiAgICAgICAgICBcdFx0Y29uc3QgcGFyYWdyYXBoRWwgPSBjcmVhdGVFbChcImJsb2NrcXVvdGVcIik7XG5cdFx0XHRcdHBhcmFncmFwaEVsLnNldEF0dHJpYnV0ZSgnZmlsZS1zb3VyY2UnLCBmaWxlUGF0aCk7XG5cdFx0XHRcdHBhcmFncmFwaEVsLnNldEF0dHJpYnV0ZSgnY2xhc3MnLCAndGFnLXN1bW1hcnktcGFyYWdyYXBoJyk7XG5cblx0XHRcdFx0Ly8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vL1xuXHRcdFx0XHQvLyAgTUVTU1khIExvdHMgb2YgcmVmYWN0b3JpbmcgdG8gYmUgZG9uZSBpbiB0aGlzIGZ1bmN0aW9uXG5cdFx0XHRcdC8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy8vLy9cblxuXHRcdFx0XHQvLyBBZGQgbGluayB0byBvcmlnaW5hbCBub3RlLiBUYWcgQnVkZHkgYWRkZWQgZGVlcCBsaW5raW5nLlxuXHRcdFx0XHRjb25zdCBibG9ja0xpbmsgPSBwYXJhZ3JhcGgubWF0Y2goL1xcXltcXHB7TH0wLTlfXFwtL15dKy9ndSk7IFxuXHRcdFx0XHRsZXQgbGluaztcblx0XHRcdFx0Ly9jb25zb2xlLmxvZyhmaWxlUGF0aCwgZmlsZU5hbWUpXG4gICAgICAgIFx0XHRpZiAoYmxvY2tMaW5rKSB7IFxuICAgICAgICBcdFx0XHQvL3BhcmFncmFwaCA9IFwiKipbW1wiICsgZmlsZVBhdGggKyBcIiNcIiArIGJsb2NrTGluayArIFwifFwiICsgZmlsZU5hbWUgKyBcIl1dKipcIiArIHBhcmFncmFwaDsgXG4gICAgICAgIFx0XHRcdGxpbmsgPSAnW1snICsgZmlsZVBhdGggKyAnIycgKyBibG9ja0xpbmsgKyAnfCcgKyBmaWxlTmFtZSArICddXSc7XG5cbiAgICAgICAgXHRcdFx0Ly9pZiAodGhpcy5hcHAucGx1Z2lucy5nZXRQbHVnaW4oJ3F1aWNrYWRkJykpIHtcblx0XHRcdFx0XHRcdGxldCBjb3VudCA9IDA7XG5cdFx0XHRcdFx0XHRzZWN0aW9ucy5mb3JFYWNoKChzZWMpID0+IHtcblx0XHRcdFx0XHRcdFx0aWYgKGNvdW50KysgPiAzKSByZXR1cm47IC8vIGxpbWl0IHRvIDQgc2VjdGlvbiBidXR0b25zIGZvciBub3csIGZvciBzcGFjZS5cblx0XHRcdFx0XHRcdFx0Ly9idXR0b25Db250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5tYWtlQ29weVRvQnV0dG9uIChwYXJhZ3JhcGgsIHNlYywgcGFyYWdyYXBoRWwsIHRhZ1NlY3Rpb24sIChmaWxlUGF0aCArICcjJyArIGJsb2NrTGluaykpKTtcblx0XHRcdFx0XHRcdFx0YnV0dG9uQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubWFrZUNvcHlUb0J1dHRvbiAocGFyYWdyYXBoLCBzZWMsIHBhcmFncmFwaEVsLCB0YWdzLCAoZmlsZVBhdGggKyAnIycgKyBibG9ja0xpbmspLCBwYXJhZ3JhcGhFbCwgc3VtbWFyeUNvbnRhaW5lcikpO1xuXHRcdFx0XHRcdFx0fSk7XG5cdFx0XHRcdFx0Ly99XG5cdFx0XHRcdFx0aWYgKHRoaXMuc2V0dGluZ3MudGFnU3VtbWFyeUJsb2NrQnV0dG9ucykge1xuXHRcdFx0XHRcdFx0YnV0dG9uQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubWFrZUNvcHlCdXR0b24ocGFyYWdyYXBoLnRyaW0oKSkpO1xuICAgICAgICBcdFx0XHRcdGJ1dHRvbkNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm1ha2VSZW1vdmVUYWdCdXR0b24ocGFyYWdyYXBoRWwsIHRhZ1NlY3Rpb24sIChmaWxlUGF0aCArICcjJyArIGJsb2NrTGluaykpKTtcbiAgICAgICAgXHRcdFx0fVxuXG4gICAgICAgIFx0XHR9IGVsc2UgeyBcbiAgICAgICAgXHRcdFx0Ly9wYXJhZ3JhcGggPSBcIioqW1tcIiArIGZpbGVQYXRoICsgXCJ8XCIgKyBmaWxlTmFtZSArIFwiXV0qKlwiICsgcGFyYWdyYXBoOyBcbiAgICAgICAgXHRcdFx0bGluayA9ICdbWycgKyBmaWxlUGF0aCArICd8JyArIGZpbGVOYW1lICsgJ11dJztcblxuICAgICAgICBcdFx0XHQvL2lmICh0aGlzLmFwcC5wbHVnaW5zLmdldFBsdWdpbigncXVpY2thZGQnKSkge1xuXHRcdFx0XHRcdFx0bGV0IGNvdW50ID0gMDtcblx0XHRcdFx0XHRcdHNlY3Rpb25zLmZvckVhY2goKHNlYykgPT4ge1xuXHRcdFx0XHRcdFx0XHRpZiAoY291bnQrKyA+IDMpIHJldHVybjsgLy8gbGltaXQgdG8gNCBzZWN0aW9uIGJ1dHRvbnMgZm9yIG5vdywgZm9yIHNwYWNlLlxuXHRcdFx0XHRcdFx0XHQvL2lmICh0aGlzLnNldHRpbmdzLnRhZ1N1bW1hcnlCbG9ja0J1dHRvbnMpIGJ1dHRvbkNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm1ha2VDb3B5VG9CdXR0b24gKHBhcmFncmFwaCwgc2VjLCBwYXJhZ3JhcGhFbCwgdGFnU2VjdGlvbiwgZmlsZVBhdGgpKTtcblx0XHRcdFx0XHRcdFx0aWYgKHRoaXMuc2V0dGluZ3MudGFnU3VtbWFyeUJsb2NrQnV0dG9ucykgYnV0dG9uQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubWFrZUNvcHlUb0J1dHRvbiAocGFyYWdyYXBoLCBzZWMsIHBhcmFncmFwaEVsLCB0YWdzLCBmaWxlUGF0aCwgcGFyYWdyYXBoRWwsIHN1bW1hcnlDb250YWluZXIpKTtcblx0XHRcdFx0XHRcdH0pO1xuXHRcdFx0XHRcdC8vfVxuXHRcdFx0XHRcdGlmICh0aGlzLnNldHRpbmdzLnRhZ1N1bW1hcnlCbG9ja0J1dHRvbnMpIHtcblx0XHRcdFx0XHRcdGJ1dHRvbkNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm1ha2VDb3B5QnV0dG9uKHBhcmFncmFwaC50cmltKCkpKTtcbiAgICAgICAgXHRcdFx0XHRidXR0b25Db250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5tYWtlUmVtb3ZlVGFnQnV0dG9uKHBhcmFncmFwaEVsLCB0YWdTZWN0aW9uLCBmaWxlUGF0aCkpO1xuICAgICAgICBcdFx0XHR9XG4gICAgICAgIFx0XHR9XG4gICAgICAgIFx0XHQvL2NvbnNvbGUubG9nKCdNRCBwYXJhZ3JhcGg6XFxuJyArIHBhcmFncmFwaClcbiAgICAgICAgXHRcdGNvbnN0IG1kUGFyYWdyYXBoID0gcGFyYWdyYXBoO1xuICAgICAgICBcdFx0cGFyYWdyYXBoID0gJyoqJyArIGxpbmsgKyAnKipcXG4nICsgcGFyYWdyYXBoO1xuICAgICAgICAgICAgXHQvL3BhcmFncmFwaCArPSBcIlxcblwiO1xuICAgICAgICAgIFx0XHRzdW1tYXJ5ICs9IHBhcmFncmFwaCArICdcXG4nOyBcblxuICAgICAgICAgIFx0XHQvL2NvbnN0IHRlbXBFbCA9IGF3YWl0IGNyZWF0ZUVsKCdkaXYnKTtcbiAgICAgICAgICBcdFx0Ly9hd2FpdCBNYXJrZG93blJlbmRlcmVyLnJlbmRlck1hcmtkb3duKHBhcmFncmFwaCwgdGVtcEVsLCcnLCB0ZW1wQ29tcG9uZW50KTtcbiAgICAgICAgICBcdFx0Ly9hd2FpdCBNYXJrZG93blJlbmRlcmVyLnJlbmRlck1hcmtkb3duKHBhcmFncmFwaCwgcGFyYWdyYXBoRWwsIHRoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVGaWxlKCk/LnBhdGgsIHRlbXBDb21wb25lbnQpO1xuICAgICAgICAgIFx0XHQvL2F3YWl0IE1hcmtkb3duUmVuZGVyZXIucmVuZGVyTWFya2Rvd24ocGFyYWdyYXBoLCBwYXJhZ3JhcGhFbCwgJycsIHRlbXBDb21wb25lbnQpO1xuICAgICAgICAgIFx0XHRhd2FpdCBNYXJrZG93blJlbmRlcmVyLnJlbmRlck1hcmtkb3duKHBhcmFncmFwaCwgcGFyYWdyYXBoRWwsICcnLCB0ZW1wQ29tcG9uZW50KTtcbiAgICAgICAgICBcdFx0Ly9jb25zb2xlLmxvZyhwYXJhZ3JhcGgpO1xuICAgICAgICAgIFx0XHQvL2NvbnNvbGUubG9nKCctLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJylcbiAgICAgICAgICBcdFx0Ly9jb25zb2xlLmxvZyhwYXJhZ3JhcGhFbC5pbm5lckhUTUwpXG5cbiAgICAgICAgICBcdFx0Y29uc3QgdGl0bGVFbCA9IGNyZWF0ZUVsKCdzcGFuJyk7XG4gICAgICAgICAgXHRcdHRpdGxlRWwuc2V0QXR0cmlidXRlKCdjbGFzcycsICd0YWdzdW1tYXJ5LWl0ZW0tdGl0bGUnKTtcbiAgICAgICAgICBcdFx0dGl0bGVFbC5hcHBlbmRDaGlsZChwYXJhZ3JhcGhFbC5xdWVyeVNlbGVjdG9yKCdzdHJvbmcnKS5jbG9uZU5vZGUodHJ1ZSkpXG4gICAgICAgICAgXHRcdGlmICh0aGlzLnNldHRpbmdzLnRhZ1N1bW1hcnlCbG9ja0J1dHRvbnMpIHBhcmFncmFwaEVsLmFwcGVuZENoaWxkKGJ1dHRvbkNvbnRhaW5lcik7XG4gICAgICAgICAgXHRcdHBhcmFncmFwaEVsLnF1ZXJ5U2VsZWN0b3IoJ3N0cm9uZycpLnJlcGxhY2VXaXRoKHRpdGxlRWwpXG4gICAgICAgICAgXHRcdHBhcmFncmFwaEVsLnNldEF0dHJpYnV0ZSgnbWQtc291cmNlJywgbWRQYXJhZ3JhcGgpXG5cbiAgICAgICAgICBcdFx0c3VtbWFyeUNvbnRhaW5lci5hcHBlbmRDaGlsZChwYXJhZ3JhcGhFbCk7XG5cdFx0XHR9KTtcblx0XHRcdC8vY291bnQrK1xuXHRcdH0pO1xuXHRcblx0XHRcblx0XHQvLyBBZGQgU3VtbWFyeVxuXHRcdGlmIChzdW1tYXJ5ICE9IFwiXCIpIHtcblx0XHRcdHNldFRpbWVvdXQoYXN5bmMgKCkgPT4geyBcblx0XHRcdFx0aWYgKHRoaXMuc2V0dGluZ3Muc2hvd1N1bW1hcnlCdXR0b25zKSB7XG5cdFx0XHRcdFx0c3VtbWFyeUNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm1ha2VTdW1tYXJ5UmVmcmVzaEJ1dHRvbihzdW1tYXJ5Q29udGFpbmVyKSk7XG5cdCAgICAgICAgXHRcdHN1bW1hcnlDb250YWluZXIuYXBwZW5kQ2hpbGQodGhpcy5tYWtlQ29weVN1bW1hcnlCdXR0b24oc3VtbWFyeSkpO1xuXHQgICAgICAgIFx0XHRzdW1tYXJ5Q29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMubWFrZVN1bW1hcnlOb3RlQnV0dG9uKHN1bW1hcnksIHRhZ3MpKTtcblx0ICAgICAgICBcdFx0c3VtbWFyeUNvbnRhaW5lci5hcHBlbmRDaGlsZCh0aGlzLm1ha2VCYWtlQnV0dG9uKHN1bW1hcnksIHN1bW1hcnlDb250YWluZXIsIGFjdGl2ZUZpbGUucGF0aCkpO1xuXHQgICAgICAgIFx0XHQvLyBXaGVuIHJlZmFjdG9yaW5nLCB3ZSBzaG91bGQgaGF2ZSBhIHN1bW1hcnkgb2JqZWN0IHRoYXQgc3RvcmVzIGV2ZXJ5dGhpbmcgYWJvdXQgaXQuIFxuXHQgICAgICAgIFx0XHQvLyBUaGF0IHdpbGwgaGVscCB3aXRoIG1ha2luZyB1bmRvXG5cdCAgICAgICAgXHRcdC8vIFdoYXQgYWJvdXQgZm9yIG5hdGl2ZSBlbWJlZHNcblx0ICAgICAgICBcdFx0c3VtbWFyeUNvbnRhaW5lci5hcHBlbmRDaGlsZChjcmVhdGVFbCgnYnInKSk7IFxuXHRcdFx0XHR9IFxuXHRcdFx0XHRzdW1tYXJ5Q29udGFpbmVyLmFwcGVuZENoaWxkKGNyZWF0ZUVsKCdocicpKTsgXG5cdFx0XHR9LCAwKTtcblx0XHRcdHN1bW1hcnlDb250YWluZXIuc2V0QXR0cmlidXRlKCdjb2RlYmxvY2stdGFncycsIHRhZ3Muam9pbignLCcpKTtcblx0XHRcdHN1bW1hcnlDb250YWluZXIuc2V0QXR0cmlidXRlKCdjb2RlYmxvY2stdGFncy1pbmNsdWRlJywgKChpbmNsdWRlLmxlbmd0aD4wKT9pbmNsdWRlLmpvaW4oJywnKTonJykpO1xuXHRcdFx0c3VtbWFyeUNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2NvZGVibG9jay10YWdzLWV4Y2x1ZGUnLCAoKGV4Y2x1ZGUubGVuZ3RoPjApP2V4Y2x1ZGUuam9pbignLCcpOicnKSk7XG5cdFx0XHRzdW1tYXJ5Q29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLXNlY3Rpb25zJywgKChzZWN0aW9ucy5sZW5ndGg+MCk/c2VjdGlvbnMuam9pbignLCcpOicnKSk7XG5cdFx0XHRzdW1tYXJ5Q29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLW1heCcsIG1heCk7XG5cdFx0XHRzdW1tYXJ5Q29udGFpbmVyLnNldEF0dHJpYnV0ZSgnY29kZWJsb2NrLWNvZGUnLCBtZFNvdXJjZSk7XG5cblx0XHRcdC8vIGF3YWl0IE1hcmtkb3duUmVuZGVyZXIucmVuZGVyTWFya2Rvd24oaHRtbFRvTWFya2Rvd24oc3VtbWFyeUNvbnRhaW5lci5pbm5lckhUTUwpLCBzdW1tYXJ5Q29udGFpbmVyLCAnJywgdGVtcENvbXBvbmVudCk7XG5cdFx0XHRlbGVtZW50LnJlcGxhY2VXaXRoKHN1bW1hcnlDb250YWluZXIpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvL3RoaXMuY3JlYXRlRW1wdHlTdW1tYXJ5KGVsZW1lbnQsIHRhZ3MsIGluY2x1ZGUsIGV4Y2x1ZGUpO1xuXHRcdFx0dGhpcy5jcmVhdGVFbXB0eVN1bW1hcnkoZWxlbWVudCwgdGFncz90YWdzOltdLCBpbmNsdWRlP2luY2x1ZGU6W10sIGV4Y2x1ZGU/ZXhjbHVkZTpbXSwgc2VjdGlvbnM/c2VjdGlvbnM6W10sIG1heD9tYXg6W10sICcnLCBtZFNvdXJjZSk7XG5cdFx0fVxuXHR9XG5cblx0LyptYWtlU3dpdGNoVG9FZGl0aW5nQnV0dG9uICh2aWV3KXtcblx0XHRjb25zdCBidXR0b24gPSB0aGlzLm1ha2VCdXR0b24gKCdFZGl0IGNvZGUgYmxvY2sgaW4gZWRpdC1tb2RlJywgYXN5bmMoZSkgPT4geyBcblx0XHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRjb25zdCB2aWV3ID0gYXdhaXQgdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KTtcblx0XHRcdGlmICh2aWV3LmdldE1vZGUoKSA9PSAncHJldmlldycpIHtcbiAgICAgIFx0XHRcdGxldCBjdXJTdGF0ZSA9IHZpZXcuZ2V0U3RhdGUoKTtcbiAgICAgIFx0XHRcdGN1clN0YXRlLm1vZGUgPSAnc291cmNlJztcbiAgICAgIFx0XHRcdHZpZXcuc2V0U3RhdGUoY3VyU3RhdGUpO1xuICAgIFx0XHR9XG5cdFx0fSk7XG5cdFx0YnV0dG9uLnRpdGxlID0gJ1N3aXRjaCB0byBlZGl0IG1vZGUnO1xuXHRcdHJldHVybiBidXR0b247XG5cdH0qL1xuXG5cdG1ha2VDb3B5U3VtbWFyeUJ1dHRvbiAoc3VtbWFyeU1kOnN0cmluZykge1xuXHRcdGNvbnN0IGJ1dHRvbiA9IHRoaXMubWFrZUJ1dHRvbiAoJyBcdTI3NEYgICcsIChlKSA9PiB7IFxuXHRcdFx0ZS5zdG9wUHJvcGFnYXRpb24oKTtcblx0XHRcdG5hdmlnYXRvci5jbGlwYm9hcmQud3JpdGVUZXh0KHN1bW1hcnlNZCk7XG5cdFx0XHRuZXcgTm90aWNlICgnU3VtbWFyeSBjb3BpZWQgdG8gY2xpcGJvYXJkLicpO1xuXHRcdH0pO1xuXHRcdGJ1dHRvbi50aXRsZSA9ICdDb3B5IHN1bW1hcnknO1xuXHRcdHJldHVybiBidXR0b247XG5cdH1cblxuXHRtYWtlU3VtbWFyeU5vdGVCdXR0b24gKHN1bW1hcnlNZDpzdHJpbmcsIHRhZ3M6QXJyYXkpIHtcblx0XHRjb25zdCBidXR0b24gPSB0aGlzLm1ha2VCdXR0b24gKCdOb3RlJywgKGUpID0+IHsgXG5cdFx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdFx0Y29uc3QgbmV3Tm90ZU9iaiA9IHRoaXMuZmlsZU9iakZyb21UYWdzKHRhZ3MpO1xuXHRcdFx0bGV0IGZpbGVDb250ZW50ID0gJyMjICcgKyBuZXdOb3RlT2JqLnRpdGxlICsgJ1xcblxcbicgKyBzdW1tYXJ5TWQ7XG5cdFx0XHRjb25zdCBmaWxlTmFtZSA9IHRoaXMuZ2V0QWN0aXZlRmlsZUZvbGRlcigpK25ld05vdGVPYmouZmlsZU5hbWU7XG5cdFx0XHRjb25zdCBmaWxlID0gdGhpcy5hcHAudmF1bHQuZ2V0QWJzdHJhY3RGaWxlQnlQYXRoKGZpbGVOYW1lKTtcblx0XHRcdGxldCBub3RpY2U7XG5cblx0XHRcdHRhZ3MuZm9yRWFjaCAoKHRhZykgPT4ge1xuXHRcdFx0XHQvL2ZpbGVDb250ZW50ID0gdGhpcy5yZW1vdmVUYWdGcm9tU3RyaW5nKGZpbGVDb250ZW50LCB0YWcpO1xuXHRcdFx0XHRmaWxlQ29udGVudCA9IHRoaXMucmVwbGFjZVRleHRJblN0cmluZyAodGFnLCBmaWxlQ29udGVudCwgdGFnLnN1YnN0cmluZygxKSwgdHJ1ZSlcblx0XHRcdFx0Ly9yZXBsYWNlVGV4dEluU3RyaW5nIChyZXBsYWNlVGV4dCwgc291cmNlVGV4dCwgbmV3VGV4dCwgYWxsOmJvb2xlYW49ZmFsc2UpIFxuXHRcdFx0fSk7XG5cdFx0XHQvL2NvbnNvbGUubG9nKGZpbGVDb250ZW50KVxuXHRcdFx0aWYgKGZpbGUgaW5zdGFuY2VvZiBURmlsZSkge1xuXHRcdFx0XHQvL2F3YWl0IGxlYWYub3BlbkZpbGUoZmlsZSwge2FjdGl2ZTogbmV3Rm9sZGVyLmZvY3VzZWR9KTtcblx0XHRcdFx0bm90aWNlID0gbmV3IE5vdGljZSAoJ1x1MjZBMFx1RkUwRiBOb3RlIGFscmVhZHkgZXhpc3RzLlxcbkNsaWNrIGhlcmUgdG8gb3ZlcndyaXRlLicsIDUwMDApO1xuXHRcdFx0XHR0aGlzLnJlZ2lzdGVyRG9tRXZlbnQobm90aWNlLm5vdGljZUVsLCAnY2xpY2snLCAoZSkgPT4ge1xuXHRcdFx0XHRcdHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCBmaWxlQ29udGVudCk7XG5cdFx0XHRcdFx0bm90aWNlID0gbmV3IE5vdGljZSAoJ05vdGUgdXBkYXRlZC5cXG5cdUQ4M0RcdUREMTcgT3BlbiBub3RlLicsIDUwMDApO1xuXHRcdFx0XHRcdHRoaXMucmVnaXN0ZXJEb21FdmVudChub3RpY2Uubm90aWNlRWwsICdjbGljaycsIChlKSA9PiB7XG5cdFx0XHRcdFx0XHR0aGlzLmFwcC53b3Jrc3BhY2Uub3BlbkxpbmtUZXh0KGZpbGVOYW1lLCAnJyk7XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSBlbHNlIGlmICghZmlsZSkge1xuXHRcdFx0XHR0aGlzLmFwcC52YXVsdC5jcmVhdGUoZmlsZU5hbWUsIGZpbGVDb250ZW50KTtcblx0XHRcdFx0Y29uc3Qgbm90aWNlID0gbmV3IE5vdGljZSAoJ1RhZyBCdWRkeTogU3VtbWFyeSBub3RlIGNyZWF0ZWQuIFx1RDgzRFx1RENEQ1xcblx1RDgzRFx1REQxNyBPcGVuIG5vdGUuJyk7XG5cdFx0XHRcdHRoaXMucmVnaXN0ZXJEb21FdmVudChub3RpY2Uubm90aWNlRWwsICdjbGljaycsIChlKSA9PiB7XG5cdFx0XHRcdFx0dGhpcy5hcHAud29ya3NwYWNlLm9wZW5MaW5rVGV4dChuZXdOb3RlT2JqLmZpbGVOYW1lLCAnJyk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH0pO1xuXHRcdGJ1dHRvbi50aXRsZSA9ICdDcmVhdGUgbm90ZSBmcm9tIHN1bW1hcnknO1xuXHRcdHJldHVybiBidXR0b247XG5cdH1cblxuXHRmaWxlT2JqRnJvbVRhZ3ModGFnczpBcnJheSk6T2JqZWN0IHtcblx0ICAgIC8vIFJlbW92ZSBoYXNoZXMgYW5kIHNwbGl0IHRhZ3MgaW50byBhbiBhcnJheVxuXHQgICAgbGV0IHRhZ3NBcnJheSA9IHRhZ3MubWFwKHRhZyA9PiB0YWcucmVwbGFjZSgvIy9nLCAnJykudG9Mb3dlckNhc2UoKSk7XG5cblx0ICAgIC8vIEZpbHRlciBvdXQgZHVwbGljYXRlc1xuXHQgICAgdGFnc0FycmF5ID0gdGFnc0FycmF5LmZpbHRlcigodGFnLCBpbmRleCwgc2VsZikgPT4gc2VsZi5pbmRleE9mKHRhZykgPT09IGluZGV4KTtcblxuXHQgICAgLy8gQ29uc3RydWN0IHRoZSBmaWxlIG5hbWVcblx0ICAgIGNvbnN0IHRhZ3NQYXJ0ID0gdGFnc0FycmF5LmpvaW4oJysnKTtcblx0ICAgIGNvbnN0IGN1cnJlbnREYXRlID0gbmV3IERhdGUoKTtcblx0ICAgIGNvbnN0IGRhdGVQYXJ0ID0gY3VycmVudERhdGUuZ2V0RGF0ZSgpLnRvU3RyaW5nKCkucGFkU3RhcnQoMiwgJzAnKSArICctJyArXG5cdCAgICAgICAgICAgICAgICAgICAgIChjdXJyZW50RGF0ZS5nZXRNb250aCgpICsgMSkudG9TdHJpbmcoKS5wYWRTdGFydCgyLCAnMCcpICsgJy0nICtcblx0ICAgICAgICAgICAgICAgICAgICAgY3VycmVudERhdGUuZ2V0RnVsbFllYXIoKS50b1N0cmluZygpLnNsaWNlKC0yKTtcblx0ICAgIGNvbnN0IGZpbGVOYW1lID0gYFRhZyBTdW1tYXJ5ICgke3RhZ3NQYXJ0fSkgKCR7ZGF0ZVBhcnR9KS5tZGA7XG5cblx0ICAgIC8vIENvbnN0cnVjdCB0aGUgdGl0bGVcblx0ICAgIGNvbnN0IHRpdGxlVGFnc1BhcnQgPSB0YWdzQXJyYXkubWFwKHRhZyA9PiB0YWcuY2hhckF0KDApLnRvVXBwZXJDYXNlKCkgKyB0YWcuc2xpY2UoMSkpLmpvaW4oJyArICcpO1xuXHQgICAgY29uc3QgdGl0bGUgPSBgJHt0aXRsZVRhZ3NQYXJ0fSBUYWcgU3VtbWFyeWA7XG5cblx0ICAgIC8vIFJldHVybiB0aGUgb2JqZWN0IHdpdGggZmlsZU5hbWUgYW5kIHRpdGxlIHByb3BlcnRpZXNcblx0ICAgIHJldHVybiB7XG5cdCAgICAgICAgZmlsZU5hbWU6IGZpbGVOYW1lLFxuXHQgICAgICAgIHRpdGxlOiB0aXRsZVxuXHQgICAgfTtcblx0fVxuXG5cdGdldEFjdGl2ZUZpbGVGb2xkZXIoKSB7XG5cdFx0Y29uc3QgYWN0aXZlRmlsZSA9IGFwcC53b3Jrc3BhY2UuYWN0aXZlTGVhZi52aWV3LmZpbGU7XG5cdCAgICBpZiAoIWFjdGl2ZUZpbGUpIHJldHVybiBudWxsO1xuXG5cdCAgICAvLyBEZXRlcm1pbmUgdGhlIGNvcnJlY3QgcGF0aCBzZXBhcmF0b3Jcblx0ICAgIGNvbnN0IHBhdGhTZXBhcmF0b3IgPSBhY3RpdmVGaWxlLnBhdGguaW5jbHVkZXMoJ1xcXFwnKSA/ICdcXFxcJyA6ICcvJztcblxuXHQgICAgY29uc3QgcGF0aFBhcnRzID0gYWN0aXZlRmlsZS5wYXRoLnNwbGl0KHBhdGhTZXBhcmF0b3IpO1xuXHQgICAgcGF0aFBhcnRzLnBvcCgpOyAgLy8gUmVtb3ZlIHRoZSBmaWxlIG5hbWUgcGFydFxuXHQgICAgbGV0IGZvbGRlclBhdGggPSBwYXRoUGFydHMuam9pbihwYXRoU2VwYXJhdG9yKTtcblxuXHQgICAgLy8gRW5zdXJlIHRoZSBmb2xkZXIgcGF0aCBlbmRzIHdpdGggdGhlIGNvcnJlY3QgcGF0aCBzZXBhcmF0b3Jcblx0ICAgIGlmICghZm9sZGVyUGF0aC5lbmRzV2l0aChwYXRoU2VwYXJhdG9yKSkge1xuXHQgICAgICAgIGZvbGRlclBhdGggKz0gcGF0aFNlcGFyYXRvcjtcblx0ICAgIH1cblxuXHQgICAgcmV0dXJuIGZvbGRlclBhdGg7XG5cdH1cblxuXHRtYWtlU3VtbWFyeVJlZnJlc2hCdXR0b24gKHN1bW1hcnlFbCkge1x0XG5cdFx0Y29uc3QgYnV0dG9uID0gdGhpcy5tYWtlQnV0dG9uICgnIFx1MjFCQSAgJywgKGUpID0+IHsgXG5cdFx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdFx0dGhpcy51cGRhdGVTdW1tYXJ5KHN1bW1hcnlFbCk7XG5cdFx0XHRuZXcgTm90aWNlICgnVGFnIFN1bW1hcnkgdXBkYXRlZCcpO1xuXHRcdFx0c2V0VGltZW91dChhc3luYyAoKSA9PiB7IHRoaXMucHJvY2Vzc1RhZ3MoKTsgfSwgMTApO1xuXHRcdH0pO1xuXHRcdGJ1dHRvbi50aXRsZSA9ICdSZWZyZXNoIFRhZyBTdW1tYXJ5Jztcblx0XHRyZXR1cm4gYnV0dG9uO1xuXHR9XG5cblx0bWFrZUNvcHlUb0J1dHRvbiAoY29udGVudCwgc2VjdGlvbiwgcGFyYWdyYXBoLCB0YWdzOkFycmF5LCBmaWxlUGF0aCwgcGFyYWdyYXBoRWwsIHN1bW1hcnlFbCkge1xuXHRcdC8vY29uc3QgcXVpY2tBZGRQbHVnaW4gPSB0aGlzLmFwcC5wbHVnaW5zLnBsdWdpbnMucXVpY2thZGQuYXBpOyAvLyBuZWVkIHRvIGNoZWNrIGlmIHRoaXMgcGx1Z2luIGlzIGluc3RhbGxlZC4gYW5kIHNldHRpbmdzLlxuXHRcdGNvbnN0IGJ1dHRvbkxhYmVsID0gKCcgXHUyNzRGICAgJyArIHRoaXMudHJ1bmNhdGVTdHJpbmdBdFdvcmQoc2VjdGlvbiwgMTYpKTtcblx0XHRjb25zdCBidXR0b24gPSB0aGlzLm1ha2VCdXR0b24gKGJ1dHRvbkxhYmVsLCBhc3luYyhlKSA9PiB7IFxuXHRcdFx0ZS5zdG9wUHJvcGFnYXRpb24oKTtcblxuXHRcdFx0bGV0IG5ld0NvbnRlbnQgPSBjb250ZW50O1xuXHRcdFx0Y29uc3QgcHJlZml4ID0gdGhpcy5zZXR0aW5ncy50YWdnZWRQYXJhZ3JhcGhDb3B5UHJlZml4O1xuXG5cdFx0XHRpZiAodGhpcy5jdHJsQ21kS2V5KGUpKSB7XG5cdFx0XHRcdHRhZ3MuZm9yRWFjaCgodGFnLCBpKSA9PiB7XG5cdFx0XHRcdFx0bmV3Q29udGVudCA9IHRoaXMucmVtb3ZlVGFnRnJvbVN0cmluZyhuZXdDb250ZW50LCB0YWcpLnRyaW0oKTtcblx0XHRcdFx0fSk7XG5cdFx0XHR9IFxuXG5cdFx0XHQvL2NvbnN0IG5ld0NvbnRlbnQgPSBwcmVmaXggKyAodGhpcy5jdHJsQ21kS2V5KGUpID8gdGhpcy5yZW1vdmVUYWdGcm9tU3RyaW5nKGNvbnRlbnQsIHRhZykgOiBjb250ZW50KS50cmltKCk7XG5cdFx0XHRjb25zdCBjb3B5U3VjY2VzcyA9IHRoaXMuY29weVRleHRUb1NlY3Rpb24ocHJlZml4ICsgbmV3Q29udGVudCwgc2VjdGlvbiwgZmlsZVBhdGgpO1xuXHRcdFx0Ly9xdWlja0FkZFBsdWdpbi5leGVjdXRlQ2hvaWNlKCdDb3B5IFRvIFNlY3Rpb24nLCB7c2VjdGlvbjpzZWN0aW9uRWxPYmoubWQsIGNvbnRlbnQ6KHRoaXMucmVtb3ZlVGFnRnJvbVN0cmluZyhjb250ZW50QXNMaXN0LCB0YWcpKydcXG4nKX0pO1xuXG5cdFx0XHRpZiAoY29weVN1Y2Nlc3MpIHtcblx0XHRcdFx0aWYgKHRoaXMuY3RybENtZEtleShlKSAmJiBlLnNoaWZ0S2V5KSB7XG5cdFx0XHRcdFx0XG5cdFx0XHRcdFx0Y29uc3QgZmlsZSA9IHRoaXMuYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChmaWxlUGF0aCk7XG5cdFx0XHRcdFx0bGV0IGZpbGVDb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcblx0XHRcdFx0XHRmaWxlQ29udGVudCA9IGZpbGVDb250ZW50LnRyaW0oKTtcblx0XHRcdFx0XHRcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKGZpbGVDb250ZW50KTtcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKCctLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0nKVxuXHRcdFx0XHRcdGNvbnN0IG5ld0ZpbGVDb250ZW50ID0gdGhpcy5yZXBsYWNlVGV4dEluU3RyaW5nIChjb250ZW50LnRyaW0oKSwgZmlsZUNvbnRlbnQsIG5ld0NvbnRlbnQpLnRyaW0oKTtcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKGZpbGVDb250ZW50LmluZGV4T2YoY29udGVudC50cmltKCkpKTtcblx0XHRcdFx0XHQvL2NvbnNvbGUubG9nKG5ld0ZpbGVDb250ZW50KVxuXHRcdFx0XHRcdC8vXG5cdFx0XHRcdFx0aWYgKGZpbGVDb250ZW50ICE9IG5ld0ZpbGVDb250ZW50KSB7XG5cdFx0XHRcdFx0XHRcblx0XHRcdFx0XHRcdHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCBuZXdGaWxlQ29udGVudCk7XG5cblx0XHRcdFx0XHRcdGNvbnN0IG5vdGljZSA9IG5ldyBOb3RpY2UgKCdQYXJhZ3JhcGggbW92ZWQgdG8gJyArIHNlY3Rpb24gKycuXFxuXHVEODNEXHVERDE3IE9wZW4gc291cmNlIG5vdGUuJywgNTAwMCk7XG5cblx0XHRcdFx0XHRcdHRoaXMucmVtb3ZlRWxlbWVudFdpdGhBbmltYXRpb24ocGFyYWdyYXBoRWwsICgpID0+IHtcblx0XHQgICAgXHRcdFx0XHRzZXRUaW1lb3V0KGFzeW5jICgpID0+IHsgdGhpcy51cGRhdGVTdW1tYXJ5KHN1bW1hcnlFbCk7IHBhcmFncmFwaEVsLnJlbW92ZSgpOyB9LCA1MDApO1x0XHRcdFx0XHRcdFxuXHRcdFx0XHRcdCAgICBcdHNldFRpbWVvdXQoYXN5bmMgKCkgPT4geyB0aGlzLnByb2Nlc3NUYWdzKCk7IH0sIDgwMCk7XG5cdFx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRcdHRoaXMucmVnaXN0ZXJEb21FdmVudChub3RpY2Uubm90aWNlRWwsICdjbGljaycsIChlKSA9PiB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuYXBwLndvcmtzcGFjZS5vcGVuTGlua1RleHQoZmlsZVBhdGgsICcnKTtcblx0XHQgXHRcdFx0XHR9KTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0bmV3IE5vdGljZSAoJ1RhZyBCdWRkeTogUGFyYWdyYXBoIGNvcGllZCB0byAnICsgc2VjdGlvbiArICcuXFxuQnV0IGNhblxcJ3QgdXBkYXRlIHNvdXJjZSBmaWxlLicpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRuZXcgTm90aWNlICgnVGFnIEJ1ZGR5OiBQYXJhZ3JhcGggY29waWVkIHRvICcgKyBzZWN0aW9uICsgJy4nKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly8gZXJyb3JzIGN1cnJlbnRseSBmcm9tIGZyb20gdGhlIGNvcHkgdG8uIFdpbGwgcmVmYWN0b3IuXG5cdFx0XHR9XG5cblx0XHR9KTtcblxuXHRcdGJ1dHRvbi50aXRsZSA9ICdDb3B5IHBhcmFncmFwaCB0byAnICsgc2VjdGlvbiArICcuXFxuJysgdGhpcy5jdHJsQ21kU3RyKCkgKyAnK0NMSUNLIHRvIHJlbW92ZSB0YWcocykgdGhlbiBjb3B5Llxcbic7XG5cdFx0YnV0dG9uLnRpdGxlICs9ICdTSElGVCsnICsgdGhpcy5jdHJsQ21kU3RyKCkgKyAnK0NMSUNLIHRvIHJlbW92ZSB0YWdzIGZyb20gc291cmNlIG5vdGUgcGFyYWdyYXBoLidcblx0XHRyZXR1cm4gYnV0dG9uO1xuXHR9XG5cblx0bWFrZUJha2VCdXR0b24gKHN1bW1hcnlNZCwgc3VtbWFyeUVsLCBmaWxlUGF0aCkge1x0XG5cdFx0Y29uc3QgYnV0dG9uID0gdGhpcy5tYWtlQnV0dG9uICgnQmFrZScsIGFzeW5jKGUpID0+IHsgXG5cdFx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdFx0Y29uc3QgbWRTb3VyY2UgPSBzdW1tYXJ5RWwuZ2V0QXR0cmlidXRlKCdjb2RlYmxvY2stY29kZScpO1xuXHRcdFx0aWYgKG1kU291cmNlKSB7XG5cdFx0XHRcdC8vY29uc29sZS5sb2cobWRTb3VyY2UpXG5cdFx0XHRcdC8vIGFjdGl2ZSBmaWxlXG5cdFx0XHRcdGNvbnN0IGZpbGUgPSB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoZmlsZVBhdGgpO1xuXHRcdFx0XHRjb25zdCBmaWxlQ29udGVudCA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LnJlYWQoZmlsZSk7XG5cdFx0XHRcdC8vIHJlcGxhY2UgdGhpcyBtZFNvdXJjZSBpbiBhY3RpdmUgZmlsZVxuXHRcdFx0XHRjb25zdCBuZXdGaWxlQ29udGVudCA9IHRoaXMucmVwbGFjZVRleHRJblN0cmluZyAobWRTb3VyY2UsIGZpbGVDb250ZW50LCBzdW1tYXJ5TWQpXG5cdFx0XHRcdC8vY29uc29sZS5sb2cobmV3RmlsZUNvbnRlbnQpXG5cdFx0XHRcdC8vIHNhdmUgdGhlIGFjdGl2ZSBub3RlXG5cdFx0XHRcdHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCBuZXdGaWxlQ29udGVudCk7XG5cblx0XHRcdFx0Y29uc3Qgbm90aWNlID0gbmV3IE5vdGljZSAoJ1RhZyBzdW1tYXJ5IGZsYXR0ZW5lZCB0byBhY3RpdmUgbm90ZS4nKTtcblx0XHRcdFx0Ly9ub3RpY2Uubm90aWNlRWwuc3R5bGUudG9wID0gJzUwMHB4Jztcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG5ldyBOb3RpY2UgKCdcdTI2QTBcdUZFMEYgVGFnIEJ1ZGR5OiBDYW5cXHQgZmluZCBjb2RlIGJsb2NrIHNvdXJjZS4gVGhpcyBpcyBhIEJVRy4nKTtcblx0XHRcdH1cblx0XHR9KTtcblx0XHRidXR0b24udGl0bGUgPSAnRmxhdHRlbiBzdW1tYXJ5IChyZXBsYWNlcyBjb2RlIGJsb2NrKS4nO1xuXHRcdHJldHVybiBidXR0b247XG5cdH1cblxuXHRtYWtlQ29weUJ1dHRvbiAoY29udGVudCkge1x0XG5cdFx0Y29uc3QgYnV0dG9uID0gdGhpcy5tYWtlQnV0dG9uICgnIFx1Mjc0RiAnLCAoZSkgPT4geyBcblx0XHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0XHRuYXZpZ2F0b3IuY2xpcGJvYXJkLndyaXRlVGV4dChjb250ZW50KTtcblx0XHRcdGNvbnN0IG5vdGljZSA9IG5ldyBOb3RpY2UgKCdUYWcgQnVkZHk6IENvcGllZCB0byBjbGlwYm9hcmQuJyk7XG5cdFx0XHQvL25vdGljZS5ub3RpY2VFbC5zdHlsZS50b3AgPSAnNTAwcHgnO1xuXHRcdH0pO1xuXHRcdGJ1dHRvbi50aXRsZSA9ICdDb3B5IHBhcmFncmFwaCc7XG5cdFx0cmV0dXJuIGJ1dHRvbjtcblx0fVxuXG5cdGN0cmxDbWRTdHIgKCkge1xuXHRcdGNvbnN0IGlzTWFjID0gKG5hdmlnYXRvci5wbGF0Zm9ybS50b1VwcGVyQ2FzZSgpLmluZGV4T2YoJ01BQycpID49IDApO1xuXHRcdGlmIChpc01hYykgcmV0dXJuICdDTUQnO1xuXHRcdGVsc2UgcmV0dXJuICdDVFJMJztcblx0fVxuXG5cdC8qdGFnc0luU3RyaW5nIChzdHJpbmc6c3RyaW5nLCB0YWc6c3RyaW5nPScnKTpBcnJheSB7XG5cdFx0Y29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKHRhZy5yZXBsYWNlKC9cXC8vZywgJ1xcXFwvJykgKyBcIig/IVtcXFxcd1xcXFwvXFxcXCNdKVwiLCBcImdcIik7XG5cdFx0Y29uc3QgbWF0Y2hlcyA9IHN0cmluZy5tYXRjaChyZWdleCk7XG5cdFx0Y29uc29sZS5sb2cobWF0Y2hlcylcblx0XHRyZXR1cm4gbWF0Y2hlcyB8fCBbXTsgLy9tYXRjaGVzID8gbWF0Y2hlcy5sZW5ndGggOiAwO1xuXHR9Ki9cblx0dGFnc0luU3RyaW5nKHN0cmluZzogc3RyaW5nLCB0YWc/OiBzdHJpbmcpOiBzdHJpbmdbXSB7XG5cdCAgICBsZXQgcmVnZXg7XG5cblx0ICAgIGlmICh0YWcpIHtcblx0ICAgICAgICByZWdleCA9IG5ldyBSZWdFeHAodGFnLnJlcGxhY2UoL1xcLy9nLCAnXFxcXC8nKSArIFwiKD8hW1xcXFx3XFxcXC9cXFxcI10pXCIsIFwiZ1wiKTtcblx0ICAgIH0gZWxzZSB7XG5cdCAgICAgICAgLy8gTWF0Y2ggYW55IHRhZy1saWtlIHBhdHRlcm4gc3RhcnRpbmcgd2l0aCAnIydcblx0ICAgICAgICByZWdleCA9IC8jKFxcdyspKD8hW1xcd1xcLyNdKS9nO1xuXHQgICAgfVxuXG5cdCAgICBjb25zdCBtYXRjaGVzID0gc3RyaW5nLm1hdGNoKHJlZ2V4KTtcblx0ICAgIHJldHVybiBtYXRjaGVzIHx8IFtdO1xuXHR9XG5cblx0Y291bnRPY2N1cnJlbmNlcyhzdW1tYXJ5VGFncywgY29udGVudFRhZ3MpIHtcblx0ICAgIGxldCBjb3VudCA9IDA7XG5cdCAgICAvL2NvbnNvbGUubG9nIChzdW1tYXJ5VGFncywgY29udGVudFRhZ3MpO1xuXHQgICAgZm9yIChsZXQgdGFnIG9mIHN1bW1hcnlUYWdzKSB7XG5cdCAgICAgICAgY291bnQgKz0gY29udGVudFRhZ3MuZmlsdGVyKGl0ZW0gPT4gaXRlbSA9PT0gdGFnKS5sZW5ndGg7XG5cdCAgICB9XG5cblx0ICAgIHJldHVybiBjb3VudDtcblx0fVxuXG5cdG1ha2VSZW1vdmVUYWdCdXR0b24gKHBhcmFncmFwaEVsLCB0YWcsIGZpbGVQYXRoKSB7XG5cdFx0Y29uc3QgYnV0dG9uID0gdGhpcy5tYWtlQnV0dG9uICgnIFx1MjMxN1x1MDJFMyAnLCAoZSkgPT4geyBcblx0XHRcdGUuc3RvcFByb3BhZ2F0aW9uKCk7XG5cblx0XHRcdC8vY29uc3QgdGFnc1RvQ2hlY2sgPSB0aGlzLmdldFRhZ3NUb0NoZWNrRnJvbUVsKHBhcmFncmFwaEVsLmNsb3Nlc3QoJy50YWctc3VtbWFyeS1ibG9jaycpKTtcblx0XHRcdC8vY29uc3QgdGFnc0luQ29udGVudCA9IHRoaXMudGFnc0luU3RyaW5nKHBhcmFncmFwaEVsLmlubmVyVGV4dCk7XG5cdFx0XHQvL2NvbnN0IHRhZ0NvdW50ID0gdGFnc0luQ29udGVudD8ubGVuZ3RoO1xuXHRcdFx0Ly9jb25zdCB0YWdDb3VudCA9IHRoaXMuY291bnRPY2N1cnJlbmNlcyh0YWdzVG9DaGVjaywgdGFnc0luQ29udGVudClcblxuXHRcdFx0Ly9jb25zb2xlLmxvZygnc3VtbWFyeSB0YWdzIGxlZnQ6ICcgKyB0YWdDb3VudClcblxuXHRcdFx0Y29uc3QgdGFnRWwgPSB0aGlzLmdldFRhZ0VsZW1lbnQocGFyYWdyYXBoRWwsIHRhZyk7XG5cdFx0XHR0aGlzLmVkaXRUYWcodGFnRWwpO1xuXHRcdFx0LyppZiAodGFnQ291bnQgPj0gMiApIHtcblx0XHRcdFx0Ly9jb25zb2xlLmxvZygnbW9yZSB0aGFuIG9uZSBsZWZ0JylcbiAgICBcdFx0XHR0aGlzLmVkaXRUYWcodGFnRWwpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Ly9jb25zb2xlLmxvZygnbGFzdCBvbmUsIHdpbGwgcmVtb3ZlIHBhcmFncmFwaCcpXG5cdFx0XHRcdGNvbnN0IG5vdGljZSA9IG5ldyBOb3RpY2UgKCdcdUQ4M0RcdUREMTYgJyArIHRhZyArICcgcmVtb3ZlZCBmcm9tIHBhcmFncmFwaC5cXG5cdUQ4M0RcdUREMTcgT3BlbiBzb3VyY2Ugbm90ZS4nLCA1MDAwKTtcblx0XHRcdFx0dGhpcy5yZW1vdmVFbGVtZW50V2l0aEFuaW1hdGlvbihwYXJhZ3JhcGhFbCwgKCkgPT4ge1xuICAgIFx0XHRcdFx0dGhpcy5lZGl0VGFnKHRhZ0VsKTtcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHRoaXMucmVnaXN0ZXJEb21FdmVudChub3RpY2Uubm90aWNlRWwsICdjbGljaycsIChlKSA9PiB7XG5cdFx0XHQgXHQgXHR0aGlzLmFwcC53b3Jrc3BhY2Uub3BlbkxpbmtUZXh0KGZpbGVQYXRoLCAnJyk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fSovXG5cdFx0fSk7XG5cdFx0YnV0dG9uLnRpdGxlID0gJ1JlbW92ZSAnICsgdGFnICsgJyBmcm9tIHBhcmFncmFwaCAoYW5kIGZyb20gdGhpcyBzdW1tYXJ5KS4nO1xuXHRcdHJldHVybiBidXR0b247XG5cdH1cblxuXHRyZW1vdmVFbGVtZW50V2l0aEFuaW1hdGlvbihlbCwgY2FsbGJhY2spIHtcblx0ICAvLyBHZXQgdGhlIGFjdHVhbCBoZWlnaHQgb2YgdGhlIGVsZW1lbnRcblx0ICBjb25zdCBoZWlnaHQgPSBlbC5vZmZzZXRIZWlnaHQ7XG5cblx0ICAvLyBTZXQgaGVpZ2h0IHRvIHRoZSBjdXJyZW50IHZhbHVlIGZvciBDU1MgdHJhbnNpdGlvblxuXHQgIGVsLnN0eWxlLmhlaWdodCA9IGAke2hlaWdodH1weGA7XG5cblx0ICAvLyBBbGxvdyB0aGUgYnJvd3NlciB0byB1cGRhdGUsIHRoZW4gc2V0IHRvIDAgdG8gdHJpZ2dlciB0aGUgdHJhbnNpdGlvblxuXHQgIC8vc2V0VGltZW91dCgoKSA9PiB7IGVsLnN0eWxlLmhlaWdodCA9ICcwcHgnOyB9LCAwKTtcblx0ICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgZWwuc3R5bGUuaGVpZ2h0ID0gJzBweCc7XG4gICAgICAgIGVsLnN0eWxlLm9wYWNpdHkgPSAnMCc7XG4gICAgICAgIGVsLnN0eWxlLm1hcmdpbiA9ICcwJztcbiAgICAgICAgZWwuc3R5bGUucGFkZGluZyA9ICcwJztcbiAgICBcdH0sIDApO1xuXHQgIFxuXHQgIGVsLmFkZEV2ZW50TGlzdGVuZXIoJ3RyYW5zaXRpb25lbmQnLCBmdW5jdGlvbiBvbkVuZCgpIHtcbiAgICBcdFx0ZWwucmVtb3ZlRXZlbnRMaXN0ZW5lcigndHJhbnNpdGlvbmVuZCcsIG9uRW5kKTtcbiAgICBcdFx0Y2FsbGJhY2soKTtcblx0ICAgIFx0Ly9zZXRUaW1lb3V0KCgpID0+IHsgZWwucmVtb3ZlKCk7IH0sIDEwKTsgLy8gcmVtb3ZlIGluIHRoZSBjYWxsYmFja1xuXHQgIH0pO1xuXHR9XG5cblx0bWFrZUJ1dHRvbiAobGFibGUsIGNsaWNrRm4sIGNsYXNzSWQ9J3RhZ3N1bW1hcnktYnV0dG9uJykge1xuXHRcdGNvbnN0IGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2J1dHRvbicpO1xuXHQgICAgYnV0dG9uLmlubmVyVGV4dCA9IGxhYmxlO1xuXHQgICAgYnV0dG9uLmNsYXNzTmFtZSA9IGNsYXNzSWQ7XG5cdCAgICB0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoYnV0dG9uLCAnY2xpY2snLCBjbGlja0ZuLmJpbmQodGhpcykpO1xuXHQgICAgcmV0dXJuIGJ1dHRvbjtcblx0fVxuXG5cdGdldE1hcmtkb3duSGVhZGluZ3MoYm9keUxpbmVzOiBzdHJpbmdbXSk6IEhlYWRpbmdbXSB7XG5cdFx0Y29uc3QgaGVhZGVyczogSGVhZGluZ1tdID0gW107XG5cdFx0bGV0IGFjY3VtdWxhdGVkSW5kZXggPSAwO1xuXG5cdFx0Ym9keUxpbmVzLmZvckVhY2goKGxpbmUsIGluZGV4KSA9PiB7XG5cdFx0XHRjb25zdCBtYXRjaCA9IGxpbmUubWF0Y2goL14oIyspW1xcc10/KC4qKSQvKTtcblxuXHRcdFx0aWYgKG1hdGNoKSB7XG5cdFx0XHRcdGhlYWRlcnMucHVzaCh7XG5cdFx0XHRcdFx0ZnVsbFRleHQ6IG1hdGNoWzBdLFxuXHRcdFx0XHRcdGxldmVsOiBtYXRjaFsxXS5sZW5ndGgsXG5cdFx0XHRcdFx0dGV4dDogbWF0Y2hbMl0sXG5cdFx0XHRcdFx0bGluZTogaW5kZXgsXG5cdFx0XHRcdFx0c3RhcnRJbmRleDogYWNjdW11bGF0ZWRJbmRleCxcblx0ICAgICAgICBcdFx0ZW5kSW5kZXg6IChhY2N1bXVsYXRlZEluZGV4ICsgbWF0Y2hbMF0ubGVuZ3RoIC0gMSlcblx0XHRcdFx0fSk7XG5cdFx0XHR9XG5cdFx0XHRhY2N1bXVsYXRlZEluZGV4ICs9IGxpbmUubGVuZ3RoICsgMTtcblx0XHR9KTtcblxuXHRcdHJldHVybiBoZWFkZXJzO1xuXHR9XG5cblx0Z2V0TGluZXNJblN0cmluZyhpbnB1dDogc3RyaW5nKSB7XG5cdFx0Y29uc3QgbGluZXM6IHN0cmluZ1tdID0gW107XG5cdFx0bGV0IHRlbXBTdHJpbmcgPSBpbnB1dDtcblxuXHRcdHdoaWxlICh0ZW1wU3RyaW5nLmluY2x1ZGVzKFwiXFxuXCIpKSB7XG5cdFx0XHRjb25zdCBsaW5lRW5kSW5kZXggPSB0ZW1wU3RyaW5nLmluZGV4T2YoXCJcXG5cIik7XG5cdFx0XHRsaW5lcy5wdXNoKHRlbXBTdHJpbmcuc2xpY2UoMCwgbGluZUVuZEluZGV4KSk7XG5cdFx0XHR0ZW1wU3RyaW5nID0gdGVtcFN0cmluZy5zbGljZShsaW5lRW5kSW5kZXggKyAxKTtcblx0XHR9XG5cdFx0bGluZXMucHVzaCh0ZW1wU3RyaW5nKTtcblxuXHRcdHJldHVybiBsaW5lcztcblx0fVxuXG5cdGluc2VydFRleHRBZnRlckxpbmUodGV4dDogc3RyaW5nLCBib2R5OiBzdHJpbmcsIGxpbmU6IG51bWJlciwgZmlsZVBhdGgpOiBzdHJpbmcge1xuXHRcdGNvbnN0IHNwbGl0Q29udGVudCA9IGJvZHkuc3BsaXQoXCJcXG5cIik7XG5cdFx0Y29uc3QgcHJlID0gc3BsaXRDb250ZW50LnNsaWNlKDAsIGxpbmUgKyAxKS5qb2luKFwiXFxuXCIpO1xuXHRcdGNvbnN0IHBvc3QgPSBzcGxpdENvbnRlbnQuc2xpY2UobGluZSArIDEpLmpvaW4oXCJcXG5cIik7XG5cblx0XHRyZXR1cm4gYCR7cHJlfVxcbiR7dGV4dH1cXG4ke3Bvc3R9YDtcblx0fVxuXG5cdGFzeW5jIGNvcHlUZXh0VG9TZWN0aW9uKHRleHQsIHNlY3Rpb24sIGZpbGVQYXRoKXtcblx0XHQvL2NvbnNvbGUubG9nKGZpbGVQYXRoKVxuXHRcdGNvbnN0IGZpbGUgPSBhd2FpdCB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlRmlsZSgpO1xuXHRcdGNvbnN0IGZpbGVDb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcblx0XHRjb25zdCBmaWxlQ29udGVudExpbmVzOiBzdHJpbmdbXSA9IHRoaXMuZ2V0TGluZXNJblN0cmluZyhmaWxlQ29udGVudCk7XG5cdFx0Y29uc3QgbWRIZWFkaW5ncyA9IHRoaXMuZ2V0TWFya2Rvd25IZWFkaW5ncyhmaWxlQ29udGVudExpbmVzKTtcblx0XHRpZiAobWRIZWFkaW5ncy5sZW5ndGggPiAwKSB7IC8vIGlmIHRoZXJlIGFyZSBhbnkgaGVhZGluZ3Ncblx0XHRcdGNvbnN0IGhlYWRpbmdPYmogPSBtZEhlYWRpbmdzLmZpbmQoaGVhZGluZyA9PiBoZWFkaW5nLnRleHQudHJpbSgpID09PSBzZWN0aW9uKTtcblx0XHRcdGlmIChoZWFkaW5nT2JqKSB7XG5cdFx0XHRcdGNvbnN0IHRleHRXaXRoTGluayA9IHRleHQgKyBgIFtbJHtmaWxlUGF0aH18XHVEODNEXHVERDE3XV1gXG5cdFx0XHRcdC8vbGV0IG5ld0NvbnRlbnQgPSB0aGlzLmluc2VydFRleHRBZnRlckxpbmUodGV4dCwgZmlsZUNvbnRlbnQsIGhlYWRpbmdPYmoubGluZSk7XG5cdFx0XHRcdGxldCBuZXdDb250ZW50ID0gdGhpcy5pbnNlcnRUZXh0QWZ0ZXJMaW5lKHRleHRXaXRoTGluaywgZmlsZUNvbnRlbnQsIGhlYWRpbmdPYmoubGluZSk7XG5cdFx0XHRcdGF3YWl0IHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCBuZXdDb250ZW50KTtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRuZXcgTm90aWNlIChgVGFnIEJ1ZGR5OiAke3NlY3Rpb259IG5vdCBmb3VuZC5gKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXcgTm90aWNlICgnVGFnIEJ1ZGR5OiBUaGVyZSBhcmUgbm8gaGVhZGVyIHNlY3Rpb25zIGluIHRoaXMgbm90ZS4nKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdH1cblxuXHRyZW1vdmVUYWdGcm9tU3RyaW5nKGlucHV0VGV4dCwgaGFzaHRhZ1RvUmVtb3ZlLCBhbGw6Ym9vbGVhbj10cnVlKTpzdHJpbmcge1xuXHQgICAgLy8gVXNlIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGdsb2JhbGx5IHJlcGxhY2UgdGhlIGhhc2h0YWcgd2l0aCBhbiBlbXB0eSBzdHJpbmdcblx0ICAgIC8vY29uc29sZS5sb2coJ1RhZyB0byByZW1vdmU6ICcgKyBoYXNodGFnVG9SZW1vdmUpXG5cdCAgICAvL2NvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cChcIlxcXFxzP1wiICsgaGFzaHRhZ1RvUmVtb3ZlICsgXCJcXFxcYlwiLCBhbGw/XCJnaVwiOlwiaVwiKTtcblx0ICAgIGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cChcIlxcXFxzP1wiICsgaGFzaHRhZ1RvUmVtb3ZlLnJlcGxhY2UoLyMvZywgJ1xcXFwjJykgKyBcIig/IVxcXFx3fFxcXFwvKVwiLCBhbGw/XCJnaVwiOlwiaVwiKTtcblx0ICAgIHJldHVybiBpbnB1dFRleHQucmVwbGFjZShyZWdleCwgJycpLnRyaW0oKTtcblx0fVxuXG5cdC8qZ2V0U2VjdGlvblRpdGxlV2l0aEhhc2hlcyhzZWN0aW9uVGl0bGUpIHtcblx0ICAgIGNvbnN0IGFjdGl2ZVZpZXcgPSB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShNYXJrZG93blZpZXcpO1xuXHQgICAgaWYgKCFhY3RpdmVWaWV3KSB7XG5cdCAgICAgICAgY29uc29sZS5sb2coJ05vIGFjdGl2ZSBtYXJrZG93biB2aWV3IGZvdW5kLicpO1xuXHQgICAgICAgIHJldHVybiBudWxsO1xuXHQgICAgfVxuXG5cdCAgICBjb25zdCBjb250ZW50RWwgPSBhY3RpdmVWaWV3LmNvbnRlbnRFbDtcblxuXHQgICAgLy8gR2V0IGFsbCBoZWFkaW5nIGVsZW1lbnRzXG5cdCAgICAvLyBUaGlzIGRvZXNuJ3Qgd29yayB3aXRoIHN1cGVyIGxvbmcgbm90ZXMuIFxuXHQgICAgY29uc3QgaGVhZGluZ3MgPSBjb250ZW50RWwucXVlcnlTZWxlY3RvckFsbCgnaDEsIGgyLCBoMywgaDQsIGg1LCBoNicpO1xuXHQgICAgLy9jb25zdCBoZWFkaW5ncyA9IGF3YWl0IGNvbnRlbnRFbC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdoMSwgaDIsIGgzLCBoNCwgaDUsIGg2Jyk7XG5cdCAgICBcblx0ICAgIC8vY29uc29sZS5sb2coaGVhZGluZ3MpXG5cdCAgICBmb3IgKGNvbnN0IGhlYWRpbmcgb2YgaGVhZGluZ3MpIHtcblx0ICAgICAgICBpZiAoaGVhZGluZy50ZXh0Q29udGVudC50cmltKCkgPT09IHNlY3Rpb25UaXRsZS50cmltKCkpIHtcblx0ICAgICAgICAgICAgLy8gRGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgaGFzaGVzIGJhc2VkIG9uIHRoZSBoZWFkaW5nIGxldmVsXG5cdCAgICAgICAgICAgIGNvbnN0IGxldmVsID0gcGFyc2VJbnQoaGVhZGluZy50YWdOYW1lLnN1YnN0cigxKSwgMTApOyAgLy8gZS5nLiwgXCJIMlwiIC0+IDJcblx0ICAgICAgICAgICAgY29uc3QgaGFzaGVzID0gJyMnLnJlcGVhdChsZXZlbCk7XG5cdCAgICAgICAgICAgIC8vY29uc29sZS5sb2coaGVhZGluZyk7XG5cdCAgICAgICAgICAgIHJldHVybiB7bWQ6YCR7aGFzaGVzfSAke3NlY3Rpb25UaXRsZX1gLCBlbDpoZWFkaW5nfTtcblx0ICAgICAgICB9XG5cdCAgICB9XG5cblx0ICAgIGNvbnNvbGUubG9nKGBTZWN0aW9uIFwiJHtzZWN0aW9uVGl0bGV9XCIgbm90IGZvdW5kLmApO1xuXHQgICAgcmV0dXJuIG51bGw7XG5cdH0qL1xuXG5cdHRydW5jYXRlU3RyaW5nQXRXb3JkKHN0ciwgbWF4Q2hhcnMpIHtcblx0ICAgIGlmIChzdHIubGVuZ3RoIDw9IG1heENoYXJzKSByZXR1cm4gc3RyO1xuXHQgICAgbGV0IHRydW5jYXRlZCA9IHN0ci5zdWJzdHIoMCwgbWF4Q2hhcnMpOyAgXG5cdCAgICBjb25zdCBsYXN0U3BhY2UgPSB0cnVuY2F0ZWQubGFzdEluZGV4T2YoJyAnKTsgXG5cdCAgICBpZiAobGFzdFNwYWNlID4gMCkgdHJ1bmNhdGVkID0gdHJ1bmNhdGVkLnN1YnN0cigwLCBsYXN0U3BhY2UpOyAvLyBUcnVuY2F0ZSBhdCB0aGUgbGFzdCBmdWxsIHdvcmRcblx0ICAgIHJldHVybiB0cnVuY2F0ZWRcblx0fVxuXG5cdGFzeW5jIHJlYWRGaWxlcyhsaXN0RmlsZXM6IFRGaWxlW10pOiBQcm9taXNlPFtURmlsZSwgc3RyaW5nXVtdPiB7XG5cdFx0bGV0IGxpc3Q6IFtURmlsZSwgc3RyaW5nXVtdID0gW107XG5cdFx0Zm9yIChsZXQgdCA9IDA7IHQgPCBsaXN0RmlsZXMubGVuZ3RoOyB0ICs9IDEpIHtcblx0XHRcdGNvbnN0IGZpbGUgPSBsaXN0RmlsZXNbdF07XG5cdFx0XHRsZXQgY29udGVudCA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LmNhY2hlZFJlYWQoZmlsZSk7XG5cdFx0XHRsaXN0LnB1c2goW2ZpbGUsIGNvbnRlbnRdKTtcblx0XHR9XG5cdFx0cmV0dXJuIGxpc3Q7XG5cdH1cblxuXHRpc1ZhbGlkVGV4dChsaXN0VGFnczogc3RyaW5nW10sIHRhZ3M6IHN0cmluZ1tdLCBpbmNsdWRlOiBzdHJpbmdbXSwgZXhjbHVkZTogc3RyaW5nW10pOiBib29sZWFuIHtcblx0XHRsZXQgdmFsaWQgPSB0cnVlO1xuXG5cdFx0Ly8gQ2hlY2sgT1IgKHRhZ3MpXG5cdFx0aWYgKHRhZ3MubGVuZ3RoID4gMCkge1xuXHRcdFx0dmFsaWQgPSB2YWxpZCAmJiB0YWdzLnNvbWUoKHZhbHVlKSA9PiBsaXN0VGFncy5pbmNsdWRlcyh2YWx1ZSkpO1xuXHRcdH1cblx0XHQvLyBDaGVjayBBTkQgKGluY2x1ZGUpXG5cdFx0aWYgKGluY2x1ZGUubGVuZ3RoID4gMCkge1xuXHRcdFx0dmFsaWQgPSB2YWxpZCAmJiBpbmNsdWRlLmV2ZXJ5KCh2YWx1ZSkgPT4gbGlzdFRhZ3MuaW5jbHVkZXModmFsdWUpKTtcblx0XHR9XG5cdFx0Ly8gQ2hlY2sgTk9UIChleGNsdWRlKVxuXHRcdGlmICh2YWxpZCAmJiBleGNsdWRlLmxlbmd0aCA+IDApIHtcblx0XHRcdHZhbGlkID0gIWV4Y2x1ZGUuc29tZSgodmFsdWUpID0+IGxpc3RUYWdzLmluY2x1ZGVzKHZhbHVlKSk7XG5cdFx0fVxuXHRcdHJldHVybiB2YWxpZDtcdFx0XG5cdH1cblxuXHRhc3luYyB2YWxpZGF0ZUZpbGVQYXRoIChmaWxlUGF0aCkge1xuXHRcdGNvbnN0IG1hdGNoaW5nRmlsZXMgPSBhd2FpdCBhcHAudmF1bHQuZ2V0RmlsZXMoKS5maWx0ZXIoZmlsZSA9PiBmaWxlLm5hbWUgPT09IGZpbGVQYXRoKTtcblx0XHRpZiAobWF0Y2hpbmdGaWxlcy5sZW5ndGggPT09IDEpIHtcblx0XHRcdGNvbnN0IGZpbGVQYXRoID0gbWF0Y2hpbmdGaWxlc1swXS5wYXRoO1xuXHRcdFx0Y29uc3QgZmlsZSA9IGF3YWl0IHRoaXMuYXBwLnZhdWx0LmdldEFic3RyYWN0RmlsZUJ5UGF0aChmaWxlUGF0aCk7XG5cdFx0XHQvL2NvbnNvbGUubG9nKCdWYWxpZGF0ZSBmaWxlOiAnICsgZW1iZWRGaWxlLm5hbWUpO1xuXHRcdFx0cmV0dXJuIGZpbGU7XG5cdFx0fSBlbHNlIGlmIChtYXRjaGluZ0ZpbGVzLmxlbmd0aCA+IDEpIHtcblx0XHRcdG5ldyBOb3RpY2UoJ1RhZyBCdWRkeTogTXVsdGlwbGUgZmlsZXMgZm91bmQgd2l0aCB0aGUgc2FtZSBuYW1lLiBDYW5cXCd0IHNhZmVseSBlZGl0IHRhZy4nKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXcgTm90aWNlKCdUYWcgQnVkZHk6IE5vIGZpbGUgZm91bmQuIFRyeSBhZ2Fpbiwgb3IgdGhpcyB0YWcgbWlnaHQgYmUgaW4gYW4gdW5zdXBwb3J0ZWQgZW1iZWQgdHlwZS4nKTtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblx0fVxuXG5cdGNvbnRlbnRDaGFuZ2VkVG9vTXVjaChvcmlnaW5hbCwgbW9kaWZpZWQsIHRhZywgYnVmZmVyID0gNSkge1xuXHQgIGNvbnN0IGV4cGVjdGVkQ2hhbmdlID0gdGFnLmxlbmd0aDsgLy8gaW5jbHVkaW5nIHRoZSAnIycgc3ltYm9sXG5cdCAgY29uc3QgdGhyZXNob2xkID0gZXhwZWN0ZWRDaGFuZ2UgKyBidWZmZXI7IC8vIGFsbG93IGZvciBzb21lIG1pbm9yIHVuaW50ZW5kZWQgbW9kaWZpY2F0aW9uc1xuXHQgIGNvbnN0IGFjdHVhbENoYW5nZSA9IE1hdGguYWJzKG9yaWdpbmFsLmxlbmd0aCAtIG1vZGlmaWVkLmxlbmd0aCk7XG5cblx0ICByZXR1cm4gYWN0dWFsQ2hhbmdlID4gdGhyZXNob2xkO1xuXHR9XG5cblx0YXN5bmMgbG9hZFNldHRpbmdzKCkge1xuXHRcdHRoaXMuc2V0dGluZ3MgPSBPYmplY3QuYXNzaWduKHt9LCBERUZBVUxUX1NFVFRJTkdTLCBhd2FpdCB0aGlzLmxvYWREYXRhKCkpO1xuXHR9XG5cblx0YXN5bmMgc2F2ZVNldHRpbmdzKCkge1xuXHRcdGF3YWl0IHRoaXMuc2F2ZURhdGEodGhpcy5zZXR0aW5ncyk7XG5cdH1cblxuXHRpc1RhZ1ZhbGlkICh0YWc6c3RyaW5nKTpib29sZWFuIHsgLy8gaW5jbHVkaW5nIHRoZSAjXG5cdFx0Y29uc3QgdGFnUGF0dGVybiA9IC9eI1tcXHddKyQvO1xuXHRcdHJldHVybiB0YWdQYXR0ZXJuLnRlc3QodGFnKTtcblx0fVxuXG5cdHNhdmVSZWNlbnRUYWcgKHRhZzpzdHJpbmcpIHtcblxuXHRcdGlmICh0aGlzLmlzVGFnVmFsaWQodGFnKSkge1xuXG5cdFx0XHRcblx0XHRcdGNvbnN0IHJlY2VudFRhZ3NTdHJpbmcgPSB0aGlzLnNldHRpbmdzLnJlY2VudGx5QWRkZWRUYWdzO1xuXHRcdFx0bGV0IHJlY2VudFRhZ3M6QXJyYXk7XG5cdFx0XHRpZiAocmVjZW50VGFnc1N0cmluZyA9PSAnJykge1xuXHRcdFx0XHRyZWNlbnRUYWdzID0gW107XG5cdFx0XHR9IGVsc2UgaWYgKHJlY2VudFRhZ3NTdHJpbmcuaW5kZXhPZignLCAnKSkge1xuXHRcdFx0XHRyZWNlbnRUYWdzID0gdGhpcy5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFncy5zcGxpdCgnLCAnKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHJlY2VudFRhZ3MgPSBbdGhpcy5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFnc11cblx0XHRcdH1cblxuXHRcdFx0aWYgKHJlY2VudFRhZ3MuaW5jbHVkZXModGFnKSkge1xuXHRcdFx0XHRyZWNlbnRUYWdzLnNwbGljZShyZWNlbnRUYWdzLmluZGV4T2YodGFnKSwgMSk7XG5cdFx0XHR9XG5cblx0XHRcdHJlY2VudFRhZ3MudW5zaGlmdCh0YWcudHJpbSgpKTtcblx0XHRcdHJlY2VudFRhZ3MgPSByZWNlbnRUYWdzLnNsaWNlKDAsIDMpO1xuXHRcdFx0dGhpcy5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFncyA9IHJlY2VudFRhZ3Muam9pbignLCAnKTtcblx0XHRcdHRoaXMuc2F2ZVNldHRpbmdzKCk7XG5cdFx0fVxuXHR9XG5cblx0Z2V0UmVjZW50VGFncyAoKTpBcnJheSB7XG5cdFx0Y29uc3QgcmVjZW50VGFncyA9IHRoaXMuc2V0dGluZ3MucmVjZW50bHlBZGRlZFRhZ3M9PScnP1tdOnRoaXMuc2V0dGluZ3MucmVjZW50bHlBZGRlZFRhZ3Muc3BsaXQoJywgJyk7XG5cdFx0cmV0dXJuIHJlY2VudFRhZ3M7XG5cdH1cblxuXHQvLyBmdWNrLnRoaXMuZnVuY3Rpb25cblx0LypjbGVhblN0cmluZyhpbnB1dCkge1xuXHRcdGxldCBjbGVhbmVkU3RyO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgaW5wdXQgaXMgYSBET00gZWxlbWVudFxuXHRcdGlmIChpbnB1dCBpbnN0YW5jZW9mIEVsZW1lbnQpIHtcblx0XHRcdC8vY29uc29sZS5sb2coJ2lucHV0IGlzOiBFbGVtZW50Jyk7XG5cdFx0XHRjbGVhbmVkU3RyID0gaW5wdXQub3V0ZXJIVE1MLnRyaW0oKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly9jb25zb2xlLmxvZygnaW5wdXQgaXM6IFN0cmluZycpO1xuXHRcdFx0Y2xlYW5lZFN0ciA9IGlucHV0LnRyaW0oKTtcblx0XHR9XG5cblx0XHQvLyBXaGl0ZXNwYWNlIG5vcm1hbGl6YXRpb25cblx0XHQvL2NsZWFuZWRTdHIgPSBjbGVhbmVkU3RyLnJlcGxhY2UoL1xccysvZywgJyAnKTtcblxuXHRcdC8vIFJlbW92ZSA8YnI+IGVsZW1lbnRzXG5cdFx0Ly9jbGVhbmVkU3RyID0gY2xlYW5lZFN0ci5yZXBsYWNlKC88YnI+L2csICcgJyk7XG5cblx0XHQvLyBSZW1vdmUgYmxvY2txdW90ZSB0YWdzIGJ1dCBrZWVwIHRoZWlyIGNvbnRlbnRcblx0XHQvL2NsZWFuZWRTdHIgPSBjbGVhbmVkU3RyLnJlcGxhY2UoLzxcXC8/YmxvY2txdW90ZT4vZywgJycpO1xuXG5cdFx0Ly8gUmVtb3ZlIGJsb2NrcXVvdGUgdGFncyBidXQga2VlcCB0aGVpciBjb250ZW50XG5cdFx0Ly9jbGVhbmVkU3RyID0gY2xlYW5lZFN0ci5yZXBsYWNlKC88XFwvP2Rpdj4vZywgJycpO1xuXG5cdFx0Ly8gUmVtb3ZlIHNwYWNlcyBiZXR3ZWVuIHRhZ3Ncblx0XHQvL2NsZWFuZWRTdHIgPSBjbGVhbmVkU3RyLnJlcGxhY2UoLz5cXHMrPC9nLCAnPjwnKTtcblxuXHRcdC8vIFdoaXRlc3BhY2Ugbm9ybWFsaXphdGlvblxuXHRcdGNsZWFuZWRTdHIgPSBjbGVhbmVkU3RyLnJlcGxhY2UoL1xccysvZywgJyAnKTtcblxuXHRcdC8vIEhUTUwgZW50aXR5IGRlY29kaW5nXG5cdFx0Y29uc3QgdGV4dEFyZWEgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZXh0YXJlYScpO1xuXHRcdHRleHRBcmVhLmlubmVySFRNTCA9IGNsZWFuZWRTdHI7XG5cdFx0Y2xlYW5lZFN0ciA9IHRleHRBcmVhLnZhbHVlLnRyaW0oKTtcblxuXHRcdC8vIE9wdGlvbmFsOiBjb252ZXJ0IHRvIGxvd2VyY2FzZVxuXHRcdC8vIGNsZWFuZWRTdHIgPSBjbGVhbmVkU3RyLnRvTG93ZXJDYXNlKCk7XG5cblx0XHRyZXR1cm4gY2xlYW5lZFN0cjtcblx0fSovXG5cblx0Lyphc3luYyByZWZyZXNoVmlldyAoKXtcblx0XHQvL2NvbnNvbGUubG9nKCdSZWZyZXNoIHZpZXcuJyk7XG5cdFx0bmV3IE5vdGljZSAoJ1JlZnJlc2ggdmlldy4nKTtcblx0XHQvLyBpZiB1c2luZyByZXJlbmRlcixcblx0XHQvL2NvbnN0IHNjcm9sbFN0YXRlID0gdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZVZpZXdPZlR5cGUoTWFya2Rvd25WaWV3KT8uY3VycmVudE1vZGU/LmdldFNjcm9sbCgpO1xuXHRcdC8vYXdhaXQgdmlldy5wcmV2aWV3TW9kZS5yZXJlbmRlcih0cnVlKTtcblxuXHRcdGF3YWl0IGFwcC53b3Jrc3BhY2UuYWN0aXZlTGVhZi5yZWJ1aWxkVmlldygpO1xuXHRcdC8vIG9ubHkgbmVlZGVkIGlmIHdlIHVzZSByZXJlbmRlciBhYm92ZS4gZG8gdGhpcyBvbiBhIHRpbWVvdXRcblx0XHQvL3RoaXMuYXBwLndvcmtzcGFjZS5nZXRBY3RpdmVWaWV3T2ZUeXBlKE1hcmtkb3duVmlldykucHJldmlld01vZGUuYXBwbHlTY3JvbGwoc2Nyb2xsU3RhdGUpO1xuXHR9Ki9cblxuICAgIGluamVjdFN0eWxlcygpIHtcbiAgICAvLyBDaGVjayBpZiB0aGUgc3R5bGVzIGhhdmUgYWxyZWFkeSBiZWVuIGluamVjdGVkIHRvIGF2b2lkIGR1cGxpY2F0aW9uXG4gICAgLy9pZiAoZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ215LXBsdWdpbi1zdHlsZXMnKSkgcmV0dXJuO1xuXG4gICAgXHRjb25zdCBzdHlsZXMgPSBgXG4gICAgICAgIC50YWdzdW1tYXJ5LW5vdGFncyB7XG4gICAgICAgIFx0Y29sb3I6IHZhcigtLWxpbmstY29sb3IpICFpbXBvcnRhbnQ7XG4gICAgICAgIFx0Zm9udC13ZWlnaHQ6IDUwMCAhaW1wb3J0YW50O1xuICAgICAgICBcdGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWxpbmstY29sb3IpICFpbXBvcnRhbnQ7IFxuICAgICAgICBcdGJvcmRlci1yYWRpdXM6IDVweCAhaW1wb3J0YW50O1xuICAgICAgICBcdHBhZGRpbmc6IDEwcHggMTBweDtcbiAgICAgICAgfVxuXG4gICAgICAgIC50YWdzdW1tYXJ5LWJ1dHRvbiB7XG5cbiAgICAgICAgICAgIGNvbG9yOiB2YXIoLS10ZXh0LXByaW1hcnkpICFpbXBvcnRhbnQ7XG4gICAgICAgICAgICAvKmJvcmRlcjogLjVweCBzb2xpZCB2YXIoLS10ZXh0LXF1b3RlKSAhaW1wb3J0YW50OyovXG4gICAgICAgICAgICBib3JkZXItcmFkaXVzOiA2cHggIWltcG9ydGFudDtcbiAgICAgICAgICAgIHBhZGRpbmc6IDIuNXB4IDVweCAhaW1wb3J0YW50O1xuICAgICAgICAgICAgZm9udC1zaXplOiA2NSUgIWltcG9ydGFudDtcbiAgICAgICAgICAgIHRyYW5zaXRpb246IGJhY2tncm91bmQtY29sb3IgMC4zcyAhaW1wb3J0YW50O1xuICAgICAgICAgICAgbWFyZ2luOiAwcHggM3B4IDBweCAwcHggIWltcG9ydGFudDtcbiAgICAgICAgICAgIG1pbi13aWR0aDogNDBweCAhaW1wb3J0YW50O1xuXG5cdCAgICAgICBjb2xvcjogdmFyKC0tbGluay1jb2xvcikgIWltcG9ydGFudDtcblx0ICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWxpbmstY29sb3IpICFpbXBvcnRhbnQ7IFxuXHRcdCAgIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWJhY2tncm91bmQtcHJpbWFyeSkgIWltcG9ydGFudDtcblxuICAgICAgICB9XG5cbiAgICAgICAgLnRhZ3N1bW1hcnktYnV0dG9uOmhvdmVyIHtcbiAgICAgICAgICAgIGJhY2tncm91bmQtY29sb3I6IHZhcigtLWxpbmstY29sb3IpICFpbXBvcnRhbnQ7XG4gICAgICAgICAgICBjb2xvcjogdmFyKC0tYmFja2dyb3VuZC1zZWNvbmRhcnkpICFpbXBvcnRhbnQ7XG4gICAgICAgIH1cblxuICAgICAgICAudGFnc3VtbWFyeS1pdGVtLXRpdGxlIHtcbiAgICAgICAgICAgIG1hcmdpbjogNXB4IDBweFxuICAgICAgICB9XG5cbiAgICAgICAgLnRhZ3N1bW1hcnktYnV0dG9ucyB7XG4gICAgICAgICAgICAvKmZsb2F0OiByaWdodDsqL1xuICAgICAgICAgICAgdGV4dC1hbGlnbjogcmlnaHQgIWltcG9ydGFudDtcbiAgICAgICAgfVxuXG5cdFx0YmxvY2txdW90ZS50YWctc3VtbWFyeS1wYXJhZ3JhcGgge1xuXHRcdCAgdHJhbnNpdGlvbjogaGVpZ2h0IDAuM3MsIG9wYWNpdHkgMC4zcztcblx0XHQgIC8qdHJhbnNpdGlvbjogaGVpZ2h0IDAuM3MgZWFzZSwgbWFyZ2luIDAuM3MgZWFzZSwgcGFkZGluZyAwLjNzIGVhc2UsIG9wYWNpdHkgMC4zcyBlYXNlOyovXG5cdFx0ICBvdmVyZmxvdzogaGlkZGVuO1xuXHRcdH1cblxuXHRcdC5yZW1vdmluZyB7XG5cdFx0ICBoZWlnaHQ6IDAgIWltcG9ydGFudDsgXG5cdFx0ICBvcGFjaXR5OiAwO1xuXHRcdCAgbWFyZ2luOiAwO1xuXHRcdCAgcGFkZGluZzogMDtcblx0XHR9XG5cblx0ICAgIEBtZWRpYSBvbmx5IHNjcmVlbiBhbmQgKG1heC1kZXZpY2Utd2lkdGg6IDQ4MHB4KSwgXG5cdCAgICAgICBvbmx5IHNjcmVlbiBhbmQgKG1heC13aWR0aDogNDgwcHgpIGFuZCAob3JpZW50YXRpb246IGxhbmRzY2FwZSksXG5cdCAgICAgICBvbmx5IHNjcmVlbiBhbmQgKG1heC1kZXZpY2Utd2lkdGg6IDEwMjRweCksIFxuXHQgICAgICAgb25seSBzY3JlZW4gYW5kIChtaW4td2lkdGg6IDQ4MXB4KSBhbmQgKG1heC13aWR0aDogMTAyNHB4KSBhbmQgKG9yaWVudGF0aW9uOiBsYW5kc2NhcGUpIHtcblx0XHQgICAudGFnc3VtbWFyeS1idXR0b24ge1xuXHRcdCAgICAgICBkaXNwbGF5OiBpbmxpbmUtYmxvY2sgIWltcG9ydGFudDtcblx0XHQgICAgICAgZm9udC1zaXplOiAxMnB4ICFpbXBvcnRhbnQ7XG5cdFx0ICAgICAgIHBhZGRpbmc6IDVweCA1cHg7XG5cdFx0ICAgICAgIGJveC1zaGFkb3c6IG5vbmU7ICAvKiByZW1vdmUgc2hhZG93cyBpZiB0aGV5IGxvb2sgb2ZmICovXG5cdFx0ICAgICAgIGJvcmRlci1yYWRpdXM6IDRweDtcblx0XHQgICAgICAgY29sb3I6IHZhcigtLWxpbmstY29sb3IpICFpbXBvcnRhbnQ7XG5cdFx0ICAgICAgIGJvcmRlcjogMXB4IHNvbGlkIHZhcigtLWxpbmstY29sb3IpOyBcblx0XHQgICAgICAgd2lkdGg6IGF1dG8gIWltcG9ydGFudDsgICAgICAgICAgICAvKiBhdXRvIGFkanVzdHMgd2lkdGggYmFzZWQgb24gY29udGVudCAqL1xuICAgIFx0XHQgICAvKm1heC13aWR0aDogNjBweCAhaW1wb3J0YW50OyAgKi8gIFxuICAgIFx0XHQgICBtYXgtaGVpZ2h0OiAzMHB4ICFpbXBvcnRhbnQ7XG4gICAgXHRcdCAgIG1pbi13aWR0aDogNDBweCAhaW1wb3J0YW50O1xuICAgIFx0XHQgICB3aGl0ZS1zcGFjZTogbm93cmFwO1xuICAgIFx0XHQgICAvKnRleHQtYWxpZ246IGxlZnQgIWltcG9ydGFudDsqL1xuICAgIFx0XHQgICBvdmVyZmxvdzogaGlkZGVuO1xuICAgIFx0XHQgICBiYWNrZ3JvdW5kLWNvbG9yOiB2YXIoLS1iYWNrZ3JvdW5kLXByaW1hcnkpICFpbXBvcnRhbnQ7XG5cdFx0ICAgfVxuXHRcdH1cblxuXHRcdC5hZGR0YWctbWVudSB7XG5cdFx0XHRwb3NpdGlvbjogYWJzb2x1dGUgIWltcG9ydGFudDtcblx0XHQgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tYmFja2dyb3VuZC1wcmltYXJ5KSAhaW1wb3J0YW50O1xuXHRcdCAgICAvKmNvbG9yOiB3aGl0ZSAhaW1wb3J0YW50OyovXG5cdFx0ICAgIGJvcmRlcjogMnB4IHNvbGlkIHZhcigtLWRpdmlkZXItY29sb3IpICFpbXBvcnRhbnQ7XG5cdFx0ICAgIHotaW5kZXg6IDEwMDAwICFpbXBvcnRhbnQ7XG5cdFx0ICAgIG92ZXJmbG93LXk6IGF1dG8gIWltcG9ydGFudDtcblx0XHQgICAgLyptYXgtaGVpZ2h0OiAxNTBweCAhaW1wb3J0YW50OyovXG5cdFx0ICAgIHdpZHRoOiAxNTBweCAhaW1wb3J0YW50O1xuXHRcdCAgICBib3gtc2hhZG93OiA1cHggNXB4IDIwcHggcmdiYSgwLCAwLCAwLCAwLjUpICFpbXBvcnRhbnQ7XG5cdCAgICAgICAgYm9yZGVyLXJhZGl1czogOHB4ICFpbXBvcnRhbnQ7ICBcblx0ICAgICAgICBmb250LWZhbWlseTogQXJpYWwsIHNhbnMtc2VyaWY7ICBcblx0ICAgICAgICBmb250LXNpemU6IDEycHggIWltcG9ydGFudDtcblx0ICAgICAgICBvdmVyZmxvdzogaGlkZGVuICFpbXBvcnRhbnQ7ICAvLyBIaWRlIG92ZXJmbG93XG5cdFx0XHRwYWRkaW5nLXJpZ2h0OiAxMHB4ICFpbXBvcnRhbnQ7ICAvLyBBZGp1c3QgcGFkZGluZyB0byBtYWtlIHNwYWNlIGZvciBzY3JvbGxiYXJcblx0XHRcdGJveC1zaXppbmc6IGJvcmRlci1ib3ggIWltcG9ydGFudDsgXG5cdFx0XHRcbiAgICBcdFx0Ym9yZGVyLXJhZGl1czogMTBweCAhaW1wb3J0YW50O1xuICAgIFx0XHRcblx0XHR9XG5cblx0XHQudGFnLWxpc3Qge1xuXHRcdFx0b3ZlcmZsb3cteTogYXV0byAhaW1wb3J0YW50O1xuXHRcdCAgICBvdmVyZmxvdy14OiBoaWRkZW4gIWltcG9ydGFudDsgXG5cdFx0ICAgIC8qcGFkZGluZy1yaWdodDogOHB4ICFpbXBvcnRhbnQ7ICAvLyBBZGp1c3QgcGFkZGluZyB0byBnaXZlIHNwYWNlIGZvciBzY3JvbGxiYXJcblx0XHQgICAgLyptYXJnaW4tcmlnaHQ6IC04cHggIWltcG9ydGFudDsgIC8vIEFkanVzdCBtYXJnaW4gdG8gbW92ZSBzY3JvbGxiYXIgaW50byB0aGUgcGFkZGluZyovXG5cdFx0ICAgIGJveC1zaXppbmc6IGJvcmRlci1ib3ggIWltcG9ydGFudDsgXG5cdFx0fVxuXG5cdFx0LnRhZy1pdGVtIHtcblx0XHRcdHBhZGRpbmc6IDVweCAxMHB4IDVweCAxMHB4ICFpbXBvcnRhbnQ7ICBcbiAgICAgICAgICAgIGN1cnNvcjogcG9pbnRlciAhaW1wb3J0YW50O1xuICAgICAgICAgICAvKiBib3JkZXItYm90dG9tOiAxcHggc29saWQgdmFyKC0tZGl2aWRlci1jb2xvcikgIWltcG9ydGFudDsgIC8vIFNlcGFyYXRvciBsaW5lKi9cbiAgICAgICAgICAgIGZvbnQtc2l6ZTogMTRweCAhaW1wb3J0YW50O1xuICAgICAgICAgICAgLyp3aWR0aDogMTMwcHggIWltcG9ydGFudDsqL1xuICAgICAgICAgICAgd2lkdGg6IDEwMCUgIWltcG9ydGFudDtcbiAgICAgICAgICAgIC8qaGVpZ2h0OiAyMHB4ICFpbXBvcnRhbnQ7Ki9cbiAgICAgICAgICAgIHRleHQtb3ZlcmZsb3c6IGVsbGlwc2lzICFpbXBvcnRhbnQ7IFxuXHRcdFx0d2hpdGUtc3BhY2U6IG5vd3JhcCAhaW1wb3J0YW50OyAgXG5cdFx0XHRib3gtc2l6aW5nOiBib3JkZXItYm94ICFpbXBvcnRhbnQ7IFxuXG5cdFx0XHRcblx0XHRcdHRyYW5zaXRpb246IGJhY2tncm91bmQtY29sb3IgMC4ycyBlYXNlICFpbXBvcnRhbnQ7IFxuXHRcdFx0Ym9yZGVyLXJhZGl1czogNXB4ICFpbXBvcnRhbnQ7IFxuXHRcdH1cblxuXHRcdC50YWctaXRlbTpob3ZlciB7XG5cdCAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tYmFja2dyb3VuZC1tb2RpZmllci1ob3ZlcikgIWltcG9ydGFudDsgLy8gQWRkZWQgLDEgZm9yIG9wYWNpdHlcblx0ICAgICAgICAvKmNvbG9yOiB3aGl0ZSAhaW1wb3J0YW50OyovXG5cdCAgICB9XG5cdFx0LnRhZy1pdGVtLmFjdGl2ZSB7XG5cdCAgICAgICAgYmFja2dyb3VuZC1jb2xvcjogdmFyKC0tYmFja2dyb3VuZC1tb2RpZmllci1ob3ZlcikgIWltcG9ydGFudDtcblx0ICAgICAgICAvKmJhY2tncm91bmQtY29sb3I6IHZhcigtLWludGVyYWN0aXZlLWFjY2VudCkgIWltcG9ydGFudDsqL1xuXHQgICAgICAgIC8qY29sb3I6IHdoaXRlICFpbXBvcnRhbnQ7Ki9cblx0ICAgIH1cblxuXHRcdCNhZGR0YWctbWVudSAuZGlzYWJsZS1ob3ZlciAudGFnLWl0ZW06aG92ZXIge1xuXHRcdCAgICBiYWNrZ3JvdW5kLWNvbG9yOiBpbmhlcml0ICFpbXBvcnRhbnQ7XG5cdFx0ICAgIGNvbG9yOiBpbmhlcml0ICFpbXBvcnRhbnQ7XG5cdFx0fVxuXG5cdCAgICAudGFnLXNlYXJjaCB7XG5cdCAgICAgXHR3aWR0aDogMTAwJSAhaW1wb3J0YW50O1xuXHQgICAgICAgIHBhZGRpbmc6IDIuNXB4IDVweCAhaW1wb3J0YW50O1xuXHQgICAgICAgIGJvcmRlcjogbm9uZSAhaW1wb3J0YW50O1xuXHQgICAgICAgIGZvbnQtZmFtaWx5OiBBcmlhbCwgc2Fucy1zZXJpZjtcblx0ICAgICAgICBmb250LXNpemU6IDE0cHggIWltcG9ydGFudDtcblx0ICAgIH1cblxuICAgICAgICAudGFnLXNlYXJjaDpmb2N1cyB7XG4gICAgICAgIFx0b3V0bGluZTogbm9uZSAhaW1wb3J0YW50O1xuICAgICAgICBcdGJvcmRlcjogbm9uZSAhaW1wb3J0YW50O1xuICAgICAgICBcdGJvcmRlci1ib3R0b206IDBweCAhaW1wb3J0YW50O1xuICAgICAgICBcdGJveC1zaGFkb3c6IG5vbmUgIWltcG9ydGFudDtcbiAgICAgICAgXHRvdXRsaW5lLXN0eWxlOiBub25lICFpbXBvcnRhbnQ7XG4gICAgXHRcdG91dGxpbmUtd2lkdGg6IDBweCAhaW1wb3J0YW50O1xuXG5cbiAgICAgICAgfSBcblxuICAgIGA7XG5cblx0ICAgIGNvbnN0IHN0eWxlU2hlZXQgPSBjcmVhdGVFbChcInN0eWxlXCIpO1xuXHQgICAgc3R5bGVTaGVldC50eXBlID0gXCJ0ZXh0L2Nzc1wiO1xuXHQgICAgc3R5bGVTaGVldC5pbm5lclRleHQgPSBzdHlsZXM7XG5cdCAgICBzdHlsZVNoZWV0LmlkID0gJ3RhZy1idWRkeS1zdHlsZXMnOyAvLyBJRCB0byBwcmV2ZW50IGluamVjdGluZyB0aGUgc3R5bGVzIG11bHRpcGxlIHRpbWVzXG5cdCAgICBkb2N1bWVudC5oZWFkLmFwcGVuZENoaWxkKHN0eWxlU2hlZXQpO1xuXHR9XG5cblx0YXN5bmMgZ2V0RW1iZWRGaWxlIChlbCk6VEZpbGUge1xuXHRcdGxldCBmaWxlUGF0aCA9IGVsLmdldEF0dHJpYnV0ZSgnc3JjJyk7XG5cdFx0Y29uc3QgbGlua0FycmF5ID0gZmlsZVBhdGguc3BsaXQoJyMnKTtcblx0XHRmaWxlUGF0aCA9IGxpbmtBcnJheVswXS50cmltKCkgKyAnLm1kJztcblx0XHRjb25zdCBmaWxlID0gYXdhaXQgdGhpcy52YWxpZGF0ZUZpbGVQYXRoKGZpbGVQYXRoKTtcblx0XHQvL2NvbnN0IGZpbGVDb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcblx0XHRyZXR1cm4gZmlsZTsgLy9Db250ZW50O1xuXHR9XG5cblx0YXN5bmMgZ2V0U3VtbWFyeUZpbGUgKGVsKTpURmlsZSB7XG5cdFx0Y29uc3QgZmlsZVBhdGggPSBlbC5nZXRBdHRyaWJ1dGUoJ2ZpbGUtc291cmNlJyk7IFxuXHRcdGNvbnN0IGZpbGUgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5nZXRBYnN0cmFjdEZpbGVCeVBhdGgoZmlsZVBhdGgpO1xuXHRcdC8vY29uc3QgZmlsZUNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdHJldHVybiBmaWxlO1xuXHR9XG5cblx0c2hvd1RhZ1NlbGVjdG9yKHg6IG51bWJlciwgeTogbnVtYmVyKSB7XG5cdFx0Ly9jb25zb2xlLmxvZygnc2hvdyB0YWcgaW5zcGVjdG9yJylcblx0XHQvLyBBZGp1c3RtZW50cyBmb3IgdGhlIHNjcm9sbGJhciBhbmQgZHluYW1pYyBoZWlnaHRcblx0XHRjb25zdCBtYXhUYWdDb250YWluZXJIZWlnaHQgPSAxNzA7IC8vIFRoaXMgaXMgYSBjaG9zZW4gbWF4IGhlaWdodCwgYWRqdXN0IGFzIGRlc2lyZWRcblx0XHRjb25zdCB0YWdJdGVtSGVpZ2h0ID0gMzA7IC8vIEFwcHJveGltYXRlIGhlaWdodCBvZiBvbmUgdGFnIGl0ZW0sIGFkanVzdCBiYXNlZCBvbiB5b3VyIHN0eWxlc1xuXHRcdC8vIDMwIHdvcmtzIHBlcmZlY3QgYmFzZWQgb24gb3RoZXIgcGFkZGluZyBhbmQgbWFyZ2luLiAyMCBicmVha3MgaXQgd2hlbiB0aGVyZSdzIG9uZSBsZWZ0LlxuXG5cdCAgICAvLyBSZW1vdmUgYW55IGV4aXN0aW5nIGNvbnRleHQgbWVudVxuICAgIFx0Y29uc3QgZXhpc3RpbmdNZW51ID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2FkZHRhZy1tZW51Jyk7XG4gICAgXHRpZiAoZXhpc3RpbmdNZW51KSBleGlzdGluZ01lbnUucmVtb3ZlKCk7XG5cblx0ICAgIGNvbnN0IG1lbnVFbCA9IGNyZWF0ZUVsKCdkaXYnKTtcblx0ICAgIG1lbnVFbC5zZXRBdHRyaWJ1dGUoJ2lkJywgJ2FkZHRhZy1tZW51Jyk7XG5cdCAgICBtZW51RWwuY2xhc3NMaXN0LmFkZCgnYWRkdGFnLW1lbnUnKTtcblx0ICAgIG1lbnVFbC5zdHlsZS5sZWZ0ID0gYCR7eH1weGA7XG5cdFx0bWVudUVsLnN0eWxlLnRvcCA9IGAke3l9cHhgO1xuXHRcdC8vbWVudUVsLnN0eWxlLm1heEhlaWdodCA9IGAke21heFRhZ0NvbnRhaW5lckhlaWdodH1weDtgO1xuXG5cdCAgICAvLyBDcmVhdGUgYW5kIHN0eWxlIHRoZSBzZWFyY2ggaW5wdXQgZmllbGRcblx0ICAgIGNvbnN0IHNlYXJjaEVsID0gY3JlYXRlRWwoJ2lucHV0Jyk7XG5cdCAgICBzZWFyY2hFbC5zZXRBdHRyaWJ1dGUoJ3R5cGUnLCAndGV4dCcpO1xuXHQgICAgc2VhcmNoRWwuc2V0QXR0cmlidXRlKCdpZCcsICd0YWctc2VhcmNoJyk7XG5cdCAgICBzZWFyY2hFbC5jbGFzc0xpc3QuYWRkKCd0YWctc2VhcmNoJyk7XG5cdCAgICBzZWFyY2hFbC5zZXRBdHRyaWJ1dGUoJ3BsYWNlaG9sZGVyJywgJ1NlYXJjaCB0YWdzLi4uJyk7XG5cdCAgICBcblx0ICAgIG1lbnVFbC5hcHBlbmRDaGlsZChzZWFyY2hFbCk7XG5cdCAgICAvLyBDb250YWluZXIgZm9yIHRoZSB0YWdzXG5cdCAgICBjb25zdCB0YWdDb250YWluZXIgPSBjcmVhdGVFbCgnZGl2Jyk7XG5cdCAgICAvL3RhZ0NvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2lkJywgJ3RhZy1saXN0Jyk7XG5cdCAgICB0YWdDb250YWluZXIuY2xhc3NMaXN0LmFkZCgndGFnLWxpc3QnKTtcblx0ICAgIC8vdGFnQ29udGFpbmVyLnN0eWxlLm1heEhlaWdodCA9IGAke21heFRhZ0NvbnRhaW5lckhlaWdodH1weDtgO1xuXHQgICAgLy90YWdDb250YWluZXIuc3R5bGUuc2V0UHJvcGVydHkoJ2hlaWdodCcsIGAke21heFRhZ0NvbnRhaW5lckhlaWdodH1weGAsICdpbXBvcnRhbnQnKTtcblx0ICAgIHRhZ0NvbnRhaW5lci5zdHlsZS5zZXRQcm9wZXJ0eSgnbWF4LWhlaWdodCcsIGAke21heFRhZ0NvbnRhaW5lckhlaWdodH1weGAsICdpbXBvcnRhbnQnKTtcblxuXHQgICAgbWVudUVsLmFwcGVuZENoaWxkKHRhZ0NvbnRhaW5lcik7XG5cblx0XHRjb25zdCByZW5kZXJUYWdzID0gKHNlYXJjaFF1ZXJ5OiBzdHJpbmcpID0+IHtcblx0ICAgIFx0dGFnQ29udGFpbmVyLmlubmVySFRNTCA9ICcnOyAgLy8gQ2xlYXIgZXhpc3RpbmcgdGFnc1xuXHQgICAgXHQvL2NvbnN0IGZpbHRlcmVkVGFncyA9IHRoaXMuZmV0Y2hBbGxUYWdzKCkuZmlsdGVyKHRhZyA9PiB0YWcuaW5jbHVkZXMoc2VhcmNoUXVlcnkpKTtcblx0ICAgIFx0Y29uc3QgZmlsdGVyZWRUYWdzID0gdGhpcy5nZXRUYWdzRnJvbUFwcCgpLmZpbHRlcih0YWcgPT4gdGFnLnRvTG93ZXJDYXNlKCkuaW5jbHVkZXMoc2VhcmNoUXVlcnkudG9Mb3dlckNhc2UoKSkpO1xuXHQgICAgXHQvLyBTZXQgdGhlIGR5bmFtaWMgaGVpZ2h0IGJhc2VkIG9uIHRoZSBudW1iZXIgb2YgcmVzdWx0c1xuXHQgICAgXHQvLyArMTAgbmVlZGVkIGZpeGVzIGFuIHVuc3F1YXNoYWJsZSBidWcgd2hlbiBvbmx5IG9uZSBpdGVtIHJlbWFpbnMgaW4gdGhlIHNlYXJjaFxuXHQgICAgXHRjb25zdCBkeW5hbWljSGVpZ2h0ID0gTWF0aC5taW4oZmlsdGVyZWRUYWdzLmxlbmd0aCAqIHRhZ0l0ZW1IZWlnaHQsIG1heFRhZ0NvbnRhaW5lckhlaWdodCkvLysxMDtcblx0ICAgIFx0XG5cdCAgICBcblx0XHQgICAgZmlsdGVyZWRUYWdzLmZvckVhY2goKHRhZywgaW5kZXgpID0+IHtcblx0XHQgICAgICAgIGNvbnN0IGl0ZW1FbCA9IGNyZWF0ZUVsKCdkaXYnKTtcblx0XHQgICAgICAgIGl0ZW1FbC5pbm5lclRleHQgPSBgJHt0YWd9YDtcblx0XHQgICAgICAgIGl0ZW1FbC5jbGFzc0xpc3QuYWRkKCd0YWctaXRlbScpO1xuXHRcdCAgICAgICAgaXRlbUVsLnRpdGxlID0gYCMke3RhZ31gO1xuXHQgICAgICAgICAgICBpZiAoaW5kZXggPT09IDApIHtcblx0ICAgICAgICAgICAgICAgIGl0ZW1FbC5jbGFzc0xpc3QuYWRkKCdhY3RpdmUnKTsgIC8vIEFkZCBhY3RpdmUgY2xhc3MgdG8gdGhlIGZpcnN0IHRhZ1xuXHQgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIGl0ZW1FbC5zdHlsZS5zZXRQcm9wZXJ0eSgnbWF4LWhlaWdodCcsIGAke2R5bmFtaWNIZWlnaHR9cHhgLCAnaW1wb3J0YW50Jyk7XG5cblx0XHQgICAgICAgIHRoaXMucmVnaXN0ZXJEb21FdmVudChpdGVtRWwsICdjbGljaycsIChlKSA9PiB7XG5cdFx0ICAgICAgICAvL2l0ZW1FbC5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsICgpID0+IHtcblx0XHRcdFx0ICAgIC8vY29uc29sZS5sb2coYC0tLS0tPiBTZWxlY3RlZCB0YWc6ICMke3RhZ31gKTtcblx0XHRcdFx0ICAgIC8vIEFkZCB5b3VyIGxvZ2ljIGhlcmUgdG8gaW5zZXJ0IHRoZSB0YWcgaW50byB0aGUgbm90ZVxuXHRcdCAgICAgICAgXHR0aGlzLmFkZFRhZygnIycrdGFnLCB4LCB5KVxuXHRcdFx0XHQgICAgLy8gQ2xvc2UgdGhlIG1lbnUgYWZ0ZXIgc2VsZWN0aW9uXG5cdFx0XHRcdCAgICBtZW51RWwucmVtb3ZlKCk7XG5cdFx0XHRcdH0sIHRydWUpO1xuXG5cdCAgICAgICAgXHR0YWdDb250YWluZXIuYXBwZW5kQ2hpbGQoaXRlbUVsKTtcbiAgICBcdFx0fSk7XG5cblxuXHRcdCAgICBpZiAoZmlsdGVyZWRUYWdzLmxlbmd0aCAqIHRhZ0l0ZW1IZWlnaHQgPiBtYXhUYWdDb250YWluZXJIZWlnaHQpIHtcblx0XHQgICAgICAgIHRhZ0NvbnRhaW5lci5zdHlsZS5vdmVyZmxvd1kgPSAnYXV0byAhaW1wb3J0YW50Jztcblx0XHQgICAgfSBlbHNlIHtcblx0XHQgICAgICAgIHRhZ0NvbnRhaW5lci5zdHlsZS5vdmVyZmxvd1kgPSAnaGlkZGVuICFpbXBvcnRhbnQnO1xuXHRcdCAgICB9XG5cdFx0fTtcblxuXHRcdC8vIEhhbmRsZSBFbnRlciBrZXkgcHJlc3Ncblx0XHR0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoc2VhcmNoRWwsICdrZXl1cCcsIChlOiBLZXlib2FyZEV2ZW50KSA9PiB7XG5cdFx0Ly9zZWFyY2hFbC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgKGU6IEtleWJvYXJkRXZlbnQpID0+IHtcblx0XHRcdGNvbnN0IHNlYXJjaFF1ZXJ5ID0gKGUudGFyZ2V0IGFzIEhUTUxJbnB1dEVsZW1lbnQpLnZhbHVlLnRyaW0oKTtcblx0XHRcdGNvbnN0IHBhdHRlcm4gPSAvXlteXFxzXFxwe1B9XSskL3U7IFxuXHRcdFx0Ly9jb25zdCBpc1ZhbGlkID0gcGF0dGVybi50ZXN0KFwiZXhhbXBsZVwiKTsgXG5cblxuXHRcdCAgICBpZiAoZS5rZXkgPT09ICdFbnRlcicpIHtcblx0XHQgICAgICAgIGNvbnN0IGFjdGl2ZVRhZyA9IHRhZ0NvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcuYWN0aXZlJyk7XG5cdFx0ICAgICAgICBpZiAoYWN0aXZlVGFnKSB7XG5cdFx0ICAgICAgICAgICAgLy9hY3RpdmVUYWcuY2xpY2soKTsgIC8vIFNpbXVsYXRlIGEgY2xpY2sgb24gdGhlIGFjdGl2ZSB0YWdcblx0XHQgICAgICAgICAgICB0aGlzLmFkZFRhZygnIycrYWN0aXZlVGFnLmlubmVyVGV4dCwgeCwgeSk7XG5cdFx0ICAgICAgICB9IGVsc2UgaWYgKHBhdHRlcm4udGVzdChzZWFyY2hRdWVyeSkpIHtcblx0XHQgICAgICAgIFx0dGhpcy5hZGRUYWcoJyMnK3NlYXJjaFF1ZXJ5LCB4LCB5KTtcblx0XHQgICAgICAgIH1cblx0XHQgICAgICAgIG1lbnVFbC5yZW1vdmUoKTtcblx0XHQgICAgfVxuXHRcdH0pO1xuXG5cdCAgICAvLyBJbml0aWFsIHJlbmRlclxuXHQgICAgcmVuZGVyVGFncygnJyk7XG5cblx0ICAgIC8vIEV2ZW50IGxpc3RlbmVyIGZvciBzZWFyY2ggaW5wdXRcblx0ICAgIHNlYXJjaEVsLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgKGUpID0+IHtcblx0ICAgICAgICByZW5kZXJUYWdzKChlLnRhcmdldCBhcyBIVE1MSW5wdXRFbGVtZW50KS52YWx1ZSk7XG5cdCAgICB9KTtcblxuXHRcdC8vIGNvbnN0IGRlYm91bmNlZFByb2Nlc3NUYWdzID0gdGhpcy5kZWJvdW5jZSh0aGlzLnByb2Nlc3NUYWdzLmJpbmQodGhpcyksIDUwMCk7XG5cblx0ICAgIC8vIEFkZCB0aGUgbWVudSB0byB0aGUgZG9jdW1lbnRcblx0ICAgIGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQobWVudUVsKTtcblxuXHQgICAgLy8gQXV0by1mb2N1cyBvbiB0aGUgc2VhcmNoIGlucHV0XG4gICAgXHRzZWFyY2hFbC5mb2N1cygpO1xuXG5cdFx0Y29uc3QgY2xvc2VNZW51ID0gKGU6IE1vdXNlRXZlbnQgfCBLZXlib2FyZEV2ZW50KSA9PiB7XG5cdFx0ICAgIGlmIChlIGluc3RhbmNlb2YgTW91c2VFdmVudCAmJiAoZS5idXR0b24gPT09IDAgfHwgZS5idXR0b24gPT09IDIpKSB7XG5cdFx0ICAgICAgICBpZiAoIW1lbnVFbC5jb250YWlucyhlLnRhcmdldCBhcyBOb2RlKSkgeyAgLy8gQ2hlY2sgaWYgdGhlIGNsaWNrIHdhcyBvdXRzaWRlIHRoZSBtZW51XG5cdFx0ICAgICAgICAgICAgbWVudUVsLnJlbW92ZSgpO1xuXHRcdCAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ0VudGVyIDEnKVxuXG5cdFx0ICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKCdjbGljaycsIGNsb3NlTWVudSk7XG5cdFx0ICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGNsb3NlTWVudSk7XG5cdFx0ICAgICAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXl1cCcsIGNsb3NlTWVudSk7XG5cdFx0ICAgICAgICB9XG5cdFx0ICAgIH0gZWxzZSBpZiAoZSBpbnN0YW5jZW9mIEtleWJvYXJkRXZlbnQgJiYgZS5rZXkgPT09ICdFc2NhcGUnKSB7XG5cdFx0ICAgICAgICBtZW51RWwucmVtb3ZlKCk7XG5cdFx0ICAgICAgICBkb2N1bWVudC5ib2R5LnJlbW92ZUV2ZW50TGlzdGVuZXIoJ2NsaWNrJywgY2xvc2VNZW51KTtcblx0XHQgICAgICAgIGRvY3VtZW50LmJvZHkucmVtb3ZlRXZlbnRMaXN0ZW5lcignY29udGV4dG1lbnUnLCBjbG9zZU1lbnUpO1xuXHRcdCAgICAgICAgZG9jdW1lbnQuYm9keS5yZW1vdmVFdmVudExpc3RlbmVyKCdrZXl1cCcsIGNsb3NlTWVudSk7XG5cdFx0ICAgIH1cblx0XHR9O1xuXG5cdFx0c2V0VGltZW91dCgoKSA9PiB7XG5cdFx0ICAgIC8vZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKCdjbGljaycsIGNsb3NlTWVudSk7XG5cdFx0ICAgIC8vZG9jdW1lbnQuYm9keS5hZGRFdmVudExpc3RlbmVyKCdjb250ZXh0bWVudScsIGNsb3NlTWVudSk7ICAvLyBMaXN0ZW4gZm9yIHJpZ2h0IGNsaWNrcyB0b29cblx0XHQgICAgLy9kb2N1bWVudC5ib2R5LmFkZEV2ZW50TGlzdGVuZXIoJ2tleWRvd24nLCBjbG9zZU1lbnUpO1xuXHRcdCAgICB0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoZG9jdW1lbnQuYm9keSwgJ2NsaWNrJywgY2xvc2VNZW51KTtcbiAgICAgICAgICAgIHRoaXMucmVnaXN0ZXJEb21FdmVudChkb2N1bWVudC5ib2R5LCAnY29udGV4dG1lbnUnLCBjbG9zZU1lbnUpO1xuICAgICAgICAgICAgdGhpcy5yZWdpc3RlckRvbUV2ZW50KGRvY3VtZW50LmJvZHksICdrZXl1cCcsIGNsb3NlTWVudSk7XG5cdFx0fSwgMCk7XG5cblx0XHQvL3RhZ0NvbnRhaW5lci5hZGRFdmVudExpc3RlbmVyKCdtb3VzZW1vdmUnLCAoKSA9PiB7XG5cdFx0dGhpcy5yZWdpc3RlckRvbUV2ZW50KHRhZ0NvbnRhaW5lciwgJ21vdXNlbW92ZScsICgpID0+IHtcblx0XHQgICAgLy8gUmVhY3RpdmF0ZSB0aGUgaG92ZXIgZWZmZWN0XG5cdFx0ICAgIHRhZ0NvbnRhaW5lci5jbGFzc0xpc3QucmVtb3ZlKCdkaXNhYmxlLWhvdmVyJyk7XG5cdFx0ICAgIFxuXHRcdCAgICAvLyBGaW5kIGFueSB0YWcgd2l0aCB0aGUgJ2FjdGl2ZScgY2xhc3MgYW5kIHJlbW92ZSB0aGF0IGNsYXNzXG5cdFx0ICAgIGNvbnN0IGFjdGl2ZVRhZyA9IHRhZ0NvbnRhaW5lci5xdWVyeVNlbGVjdG9yKCcudGFnLWl0ZW0uYWN0aXZlJyk7XG5cdFx0ICAgIGlmIChhY3RpdmVUYWcpIHtcblx0XHQgICAgICAgIGFjdGl2ZVRhZy5jbGFzc0xpc3QucmVtb3ZlKCdhY3RpdmUnKTtcblx0XHQgICAgfVxuXHRcdH0pO1xuXG5cdFx0Ly8gSGFuZGxlIEVudGVyIGtleSBwcmVzc1xuXHRcdC8vc2VhcmNoRWwuYWRkRXZlbnRMaXN0ZW5lcignYmx1cicsICgpID0+IHtcblx0XHR0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoc2VhcmNoRWwsICdibHVyJywgKCkgPT4ge1xuXHRcdCAgICB0YWdDb250YWluZXIuY2xhc3NMaXN0LnJlbW92ZSgnZGlzYWJsZS1ob3ZlcicpO1xuXHRcdH0pO1xuXHQgICAgLy9zZWFyY2hFbC5hZGRFdmVudExpc3RlbmVyKCdrZXlkb3duJywgKGU6IEtleWJvYXJkRXZlbnQpID0+IHtcblx0XHR0aGlzLnJlZ2lzdGVyRG9tRXZlbnQoc2VhcmNoRWwsICdrZXlkb3duJywgKGU6IEtleWJvYXJkRXZlbnQpID0+IHtcblx0XHQgICAgY29uc3QgYWN0aXZlVGFnID0gdGFnQ29udGFpbmVyLnF1ZXJ5U2VsZWN0b3IoJy5hY3RpdmUnKTtcblx0XHQgICAgbGV0IG5leHRBY3RpdmVUYWc7XG5cdFx0ICAgIGlmIChbJ0Fycm93VXAnLCAnQXJyb3dEb3duJ10uaW5jbHVkZXMoZS5rZXkpIHx8IGUua2V5Lmxlbmd0aCA9PT0gMSkgeyAvLyBDaGVjayBmb3IgYXJyb3cga2V5cyBvciBhbnkgc2luZ2xlIGNoYXJhY3RlciBrZXkgcHJlc3Ncblx0XHQgICAgICAgIHRhZ0NvbnRhaW5lci5jbGFzc0xpc3QuYWRkKCdkaXNhYmxlLWhvdmVyJyk7XG5cdFx0ICAgIH1cblx0XHQgICAgaWYgKGUua2V5ID09PSAnQXJyb3dEb3duJykge1xuXHRcdCAgICAgICAgaWYgKGFjdGl2ZVRhZyAmJiBhY3RpdmVUYWcubmV4dEVsZW1lbnRTaWJsaW5nKSB7XG5cdFx0ICAgICAgICAgICAgbmV4dEFjdGl2ZVRhZyA9IGFjdGl2ZVRhZy5uZXh0RWxlbWVudFNpYmxpbmc7XG5cdFx0ICAgICAgICB9IGVsc2Uge1xuXHRcdCAgICAgICAgICAgIG5leHRBY3RpdmVUYWcgPSB0YWdDb250YWluZXIuZmlyc3RDaGlsZDsgLy8gbG9vcCBiYWNrIHRvIHRoZSBmaXJzdCBpdGVtXG5cdFx0ICAgICAgICB9XG5cdFx0ICAgIH0gZWxzZSBpZiAoZS5rZXkgPT09ICdBcnJvd1VwJykge1xuXHRcdCAgICAgICAgaWYgKGFjdGl2ZVRhZyAmJiBhY3RpdmVUYWcucHJldmlvdXNFbGVtZW50U2libGluZykge1xuXHRcdCAgICAgICAgICAgIG5leHRBY3RpdmVUYWcgPSBhY3RpdmVUYWcucHJldmlvdXNFbGVtZW50U2libGluZztcblx0XHQgICAgICAgIH0gZWxzZSB7XG5cdFx0ICAgICAgICAgICAgbmV4dEFjdGl2ZVRhZyA9IHRhZ0NvbnRhaW5lci5sYXN0Q2hpbGQ7IC8vIGxvb3AgYmFjayB0byB0aGUgbGFzdCBpdGVtXG5cdFx0ICAgICAgICB9XG5cdFx0ICAgIH0gZWxzZSBpZiAoZS5rZXkgPT09ICdFbnRlcicpIHtcblx0XHQgICAgICAgIC8vaWYgKGFjdGl2ZVRhZykge1xuXHRcdCAgICAgICAgLy9cdGNvbnNvbGUubG9nKCdFbnRlciAyJykgLy8gdGhpcyBuZXZlciBoYXBwZW5zLlxuXHRcdCAgICAgICAgLy8gICAgYWN0aXZlVGFnLmNsaWNrKCk7XG5cdFx0ICAgICAgICAvLyAgICByZXR1cm47XG5cdFx0ICAgICAgIC8vIH1cblx0XHQgICAgfVxuXG5cdFx0ICAgIGlmIChuZXh0QWN0aXZlVGFnKSB7XG5cdFx0ICAgICAgICBpZiAoYWN0aXZlVGFnKSB7XG5cdFx0ICAgICAgICAgICAgYWN0aXZlVGFnLmNsYXNzTGlzdC5yZW1vdmUoJ2FjdGl2ZScpO1xuXHRcdCAgICAgICAgfVxuXHRcdCAgICAgICAgbmV4dEFjdGl2ZVRhZy5jbGFzc0xpc3QuYWRkKCdhY3RpdmUnKTtcblx0XHQgICAgICAgIC8vIEVuc3VyZSB0aGUgbmV3bHkgYWN0aXZlIHRhZyBpcyB2aXNpYmxlXG5cdFx0ICAgICAgICBuZXh0QWN0aXZlVGFnLnNjcm9sbEludG9WaWV3KHsgYmxvY2s6ICduZWFyZXN0JyB9KTtcblx0XHQgICAgICAgIHNlYXJjaEVsLnZhbHVlID0gbmV4dEFjdGl2ZVRhZy5pbm5lclRleHQ7XG5cdFx0ICAgIH1cblx0XHR9KTtcblx0fVxuXG5cdGFzeW5jIGFkZFRhZyAodGFnOnN0cmluZywgeDpudW1iZXIsIHk6bnVtYmVyKSB7XG5cblx0XHRpZiAodGhpcy5zZXR0aW5ncy5kZWJ1Z01vZGUpIHsgY29uc29sZS5sb2coJ1RhZyBCdWRkeSBhZGQnKTsgY29uc29sZS5sb2coeCwgeSwgdGFnKTsgfVxuXG5cdFx0bGV0IGZpbGVDb250ZW50OnN0cmluZztcblx0XHRsZXQgZmlsZTpURmlsZTtcblx0XHRjb25zdCBjbGlja2VkVGV4dE9iaiA9IHRoaXMuZ2V0Q2xpY2tlZFRleHRPYmpGcm9tRG9jICh4LCB5KTtcblx0XHRjb25zdCBjbGlja2VkVGV4dDpzdHJpbmcgPSBjbGlja2VkVGV4dE9iaj8udGV4dDtcblx0XHRjb25zdCBjbGlja2VkVGV4dEluZGV4Om51bWJlciA9IGNsaWNrZWRUZXh0T2JqPy5pbmRleDsgLy8gdGhpcyBpcyB0aGUgaW5kZXggaW4gZG9jdW1lbnQsIGZvciBuYXJyb3dpbmcgZG93biB0byB0aGUgd29yZCBjbGlja2VkLlxuXHRcdGNvbnN0IGNsaWNrZWRUZXh0RWw6SFRNTEVsZW1lbnQgPSBjbGlja2VkVGV4dE9iaj8uZWw7XG5cdFx0bGV0IGNvbnRlbnRTb3VyY2VUeXBlOnN0cmluZyA9IG51bGxcblx0XHRsZXQgc3VtbWFyeUVsOkhUTUxFbGVtZW50O1xuXHRcdGxldCBlbWJlZEVsOkhUTUxFbGVtZW50O1xuXG5cdFx0aWYgKGNsaWNrZWRUZXh0T2JqKSB7XG5cblx0XHRcdHN1bW1hcnlFbCA9IGNsaWNrZWRUZXh0RWwuY2xvc2VzdCgnLnRhZy1zdW1tYXJ5LXBhcmFncmFwaCcpO1xuXHRcdFx0ZW1iZWRFbCA9IGNsaWNrZWRUZXh0RWwuY2xvc2VzdCgnLm1hcmtkb3duLWVtYmVkJyk7XG5cblx0XHRcdGlmIChzdW1tYXJ5RWwpIHtcblx0XHRcdFx0XG5cdFx0XHRcdGZpbGUgPSBhd2FpdCB0aGlzLmdldFN1bW1hcnlGaWxlKHN1bW1hcnlFbCk7XG5cdFx0XHRcdGZpbGVDb250ZW50ID0gYXdhaXQgdGhpcy5hcHAudmF1bHQucmVhZChmaWxlKTtcblx0XHRcdFx0Y29udGVudFNvdXJjZVR5cGUgPSAncGx1Z2luLXN1bW1hcnknO1xuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdJbiBhIHN1bW1hcnknKVxuXG5cdFx0XHRcdC8vY29uc29sZS5sb2coZmlsZUNvbnRlbnQpXG5cdFx0XHRcdFxuXHRcdFx0fSBlbHNlIGlmIChlbWJlZEVsKSB7XG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ0luIGFuIGVtYmVkJyk7XG5cdFx0XHRcdGZpbGUgPSBhd2FpdCB0aGlzLmdldEVtYmVkRmlsZShlbWJlZEVsKTtcblx0XHRcdFx0ZmlsZUNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdFx0XHRjb250ZW50U291cmNlVHlwZSA9ICduYXRpdmUtZW1iZWQnO1xuXHRcdFx0XHQvL2NvbnNvbGUubG9nKGZpbGVDb250ZW50KVxuXG5cdFx0XHRcdC8vICEhISEhISB3ZSBjb3VsZCBiZSBpbiBzb21lIG90aGVyIGtpbmQgb2YgZW1iZWQvdmlldy9wbHVnaW4uIE5lZWQgdG8gYmUgc3VyZSBhYm91dCB0aGlzLlxuXHRcdFx0fSBlbHNlIHsgXG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ0luIGEgYWN0aXZlIGZpbGUnKVxuXHRcdFx0XHRmaWxlID0gYXdhaXQgdGhpcy5hcHAud29ya3NwYWNlLmdldEFjdGl2ZUZpbGUoKTtcblx0XHRcdFx0ZmlsZUNvbnRlbnQgPSBhd2FpdCB0aGlzLmFwcC52YXVsdC5yZWFkKGZpbGUpO1xuXHRcdFx0XHRjb250ZW50U291cmNlVHlwZSA9ICdhY3RpdmUnO1xuXHRcdFx0fSBcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXcgTm90aWNlICgnXHUyNkEwXHVGRTBGIENhblxcJ3QgZmluZCB0ZXh0IHBvc2l0aW9uIG9yIGFyZWEgdG9vIGJ1c3kuXFxuVHJ5IGEgYW5vdGhlciB0ZXh0IGFyZWEuJyk7XG5cdFx0ICAgIHJldHVybjtcblx0XHR9XG5cblxuXHRcdGlmIChjbGlja2VkVGV4dCkge1xuXHRcdFx0Ly9jb25zb2xlLmxvZyAoY2xpY2tlZFRleHQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXcgTm90aWNlICgnXHUyNkEwXHVGRTBGIENhblxcJ3QgYWRkIHRhZy5cXG5UcnkgYSBkaWZmZXJlbnQgdGV4dCBhcmVhLicpXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y29uc3QgZXNjYXBlZENsaWNrZWRUZXh0ID0gdGhpcy5lc2NhcGVSZWdFeHAoY2xpY2tlZFRleHQpO1xuXHRcdGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cChlc2NhcGVkQ2xpY2tlZFRleHQsIFwiZ1wiKTsgIC8vIFRoZSBcImdcIiBmbGFnIG1lYW5zIFwiZ2xvYmFsXCIsIHNvIGl0IHdpbGwgZmluZCBhbGwgb2NjdXJyZW5jZXNcblx0XHRjb25zdCBtYXRjaGVzID0gZmlsZUNvbnRlbnQubWF0Y2gocmVnZXgpO1xuXG5cdFx0aWYgKG1hdGNoZXMgJiYgbWF0Y2hlcy5sZW5ndGggPiAxKSB7XG5cdFx0ICAgIC8vY29uc29sZS5sb2coYEZvdW5kICR7bWF0Y2hlcy5sZW5ndGh9IG9jY3VycmVuY2VzIG9mIFwiJHtwYXR0ZXJufVwiIGluIFwiJHtzdWJqZWN0fVwiLmApO1xuXHRcdCAgICBuZXcgTm90aWNlICgnXHUyNkEwXHVGRTBGIENhblxcJ3QgYWRkIHRhZzogQ2xpY2tlZCB0ZXh0IHJlcGVhdGVkIGluIG5vdGUuIFRyeSBhIGFub3RoZXIgdGV4dCBibG9jay4nKTtcblx0XHQgICAgcmV0dXJuO1xuXHRcdH0gZWxzZSBpZiAoKG1hdGNoZXMgJiYgbWF0Y2hlcy5sZW5ndGggPT09IDApIHx8ICFtYXRjaGVzKSB7XG5cdFx0XHRuZXcgTm90aWNlICgnXHUyNkEwXHVGRTBGIENhblxcJ3QgZmluZCB0ZXh0IHBvc2l0aW9uIG9yIGFyZWEgdG9vIGJ1c3kuXFxuVHJ5IGEgYW5vdGhlciB0ZXh0IGFyZWEuJyk7XG5cdFx0ICAgIHJldHVybjtcblx0XHR9IFxuXG5cdFx0aWYgKCF0aGlzLnNldHRpbmdzLmxvY2tSZWNlbnRUYWdzKSB0aGlzLnNhdmVSZWNlbnRUYWcgKHRhZyk7IFxuXHRcdFxuXHRcdGNvbnN0IHN0YXJ0SW5kZXggPSByZWdleC5leGVjKGZpbGVDb250ZW50KS5pbmRleDsgLy8gdGhpcyBpcyB0aGUgaW5kZXggaW4gdGhlIG1kIHNvdXJjZVxuXHRcdGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIGNsaWNrZWRUZXh0Lmxlbmd0aC0xO1xuXG5cdFx0Y29uc3QgY2xpY2tlZFdvcmRPYmogPSB0aGlzLmdldFdvcmRPYmpGcm9tU3RyaW5nIChjbGlja2VkVGV4dCwgY2xpY2tlZFRleHRJbmRleCk7XG5cdFx0Y29uc3QgY2xpY2tlZFdvcmQgPSBjbGlja2VkV29yZE9iai50ZXh0O1xuXHRcdGNvbnN0IGNsaWNrZWRXb3JkSW5kZXggPSBjbGlja2VkV29yZE9iai5pbmRleDtcblx0XHRcblxuLy9jb25zb2xlLmxvZyhKU09OLnN0cmluZ2lmeSh0YWcpKVxuXHRcdFx0XG4vL2NvbnNvbGUubG9nICgnYmVmb3JlIHRhZyBlbmRzIHdpdGggc3BhY2U/ICcgKyBiZWZvcmUuc3RhcnRzV2l0aCgnICcpKVxuLy9jb25zb2xlLmxvZyAoJ2JlZm9yZSB0YWcgZW5kcyB3aXRoIGxpbmVicmVhaz8gJyArIGJlZm9yZS5zdGFydHNXaXRoKCdcXG4nKSlcblxuXG5cdFx0Y29uc3QgbmV3Q29udGVudCA9IHRoaXMuaW5zZXJ0VGV4dEluU3RyaW5nKHRhZywgZmlsZUNvbnRlbnQsIHN0YXJ0SW5kZXgrY2xpY2tlZFdvcmRJbmRleClcblx0XHRcblxuXHRcdC8vIG1vZGlmeSBmaWxlXG5cdFx0Ly9jb25zb2xlLmxvZyhuZXdDb250ZW50KVxuXHRcdGF3YWl0IHRoaXMuYXBwLnZhdWx0Lm1vZGlmeShmaWxlLCBuZXdDb250ZW50KTtcblxuXHRcdGlmIChjb250ZW50U291cmNlVHlwZSA9PSAncGx1Z2luLXN1bW1hcnknKSB7XG5cdFx0XHRjb25zdCBzdW1tYXJ5Q29udGFpbmVyID0gc3VtbWFyeUVsLmNsb3Nlc3QoJy50YWctc3VtbWFyeS1ibG9jaycpXG5cdFx0XHR0aGlzLnVwZGF0ZVN1bW1hcnkoc3VtbWFyeUNvbnRhaW5lcik7IFxuXHRcdH1cblxuXHRcdHNldFRpbWVvdXQoYXN5bmMgKCkgPT4geyB0aGlzLnByb2Nlc3NUYWdzKCk7IH0sIDIwMCk7XG5cdH1cblxuXHRyZXBsYWNlVGV4dEluU3RyaW5nIChyZXBsYWNlVGV4dCwgc291cmNlVGV4dCwgbmV3VGV4dCwgYWxsOmJvb2xlYW49ZmFsc2UpOnN0cmluZyB7XG5cblx0XHRjb25zdCByZWdleCA9IG5ldyBSZWdFeHAodGhpcy5lc2NhcGVSZWdFeHAocmVwbGFjZVRleHQpLCBhbGwgPyBcImdpXCIgOiBcImlcIik7XG4gICAgXHRyZXR1cm4gc291cmNlVGV4dC5yZXBsYWNlKHJlZ2V4LCBuZXdUZXh0KS50cmltKCk7XG5cdH1cblxuXHQvLyBJIHJlbW92ZWQgLnRyaW0oKSBmcm9tIHRoZSBiZWZvcmUgYW5kIGFmdGVyIHRvIGZpeCB0aGUgYWRkIGJ1Zy5cblx0aW5zZXJ0VGV4dEluU3RyaW5nIChuZXdUZXh0LCBzb3VyY2VUZXh0LCBjaGFyUG9zKTpzdHJpbmcgeyAvLyBwYXNzIDAgZm9yIHRoZSBzdGFydCBvciBzb3VyY2VUZXh0Lmxlbmd0aC0xIGZvciB0aGUgZW5kXG5cblx0XHQvLyBMQVRFUjogUHJvcGVyIHdoaXRlIHNwYWNlIG9yIGxpbmUgYnJlYWsgY2hlY2tpbmcgb2YgdGhlIGFyZWEgd2UncmUgYWRkaW5nXG5cdFx0Ly9yZXR1cm4gKHNvdXJjZVRleHQuc3Vic3RyaW5nKDAsIGNoYXJQb3MpLnRyaW0oKSArICcgJyArIG5ld1RleHQgKyAnICcgKyBzb3VyY2VUZXh0LnN1YnN0cmluZyhjaGFyUG9zKSkudHJpbSgpO1xuXHRcdHJldHVybiAoc291cmNlVGV4dC5zdWJzdHJpbmcoMCwgY2hhclBvcykgKyAnICcgKyBuZXdUZXh0ICsgJyAnICsgc291cmNlVGV4dC5zdWJzdHJpbmcoY2hhclBvcykpO1xuXHR9XG5cblx0cmVtb3ZlVGV4dEZyb21TdHJpbmcgKHJlbW92ZVRleHQsIHNvdXJjZVRleHQsIGFsbDpib29sZWFuPWZhbHNlKTpzdHJpbmcge1xuXG5cdFx0Y29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKHRoaXMuZXNjYXBlUmVnRXhwKHJlbW92ZVRleHQpLCBhbGwgPyBcImdpXCIgOiBcImlcIik7XG4gICAgXHRyZXR1cm4gc291cmNlVGV4dC5yZXBsYWNlKHJlZ2V4LCAnJykudHJpbSgpO1xuXHR9XG5cblx0Z2V0V29yZE9iakZyb21TdHJpbmcoc291cmNlVGV4dCwgb2Zmc2V0KTpPYmplY3Qge1xuXHRcdGxldCB3b3JkUmVnZXggPSAvW15cXHNdKyg/PVsuLDohP10/KFxcc3wkKSkvZztcblx0XHRsZXQgbWF0Y2g7XG5cdFx0bGV0IGluZGV4O1xuXHRcdGxldCB3b3JkID0gbnVsbDtcbiAgICAgICAgd2hpbGUgKChtYXRjaCA9IHdvcmRSZWdleC5leGVjKHNvdXJjZVRleHQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKG1hdGNoLmluZGV4IDw9IG9mZnNldCAmJiBvZmZzZXQgPD0gbWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIG91ciB3b3JkXG4gICAgICAgICAgICAgICAgLy9pZiAoIS9eW15cXHB7TH1cXHB7Tn1dL3UudGVzdChtYXRjaFswXSkgJiYgICAgICAgIC8vIE5vdCBzdGFydGluZyB3aXRoIGFueSBub24tYWxwaGFudW1lcmljXG4gICAgICAgICAgICAgICAgLy8gICAgIS9bXlxccHtMfVxccHtOfVxccy4sOiE/XS91LnRlc3QobWF0Y2hbMF0pICYmXHQvLyBOb3QgY29udGFpbmluZyBvdGhlciB0aGFuIGFsbG93ZWQgY2hhcnNcbiAgICAgICAgICAgICAgICAvLyAgICAhL1suLDohP10oPz1bXlxccyRdKS91LnRlc3QobWF0Y2hbMF0pKSB7ICAgICAvLyBJZiBlbmRzIHdpdGggcHVuY3R1YXRpb24sIGZvbGxvd2luZyBjaGFyYWN0ZXIgbXVzdCBiZSB3aGl0ZXNwYWNlIG9yIGVuZCBvZiBzdHJpbmdcbiAgICAgICAgICAgICAgICAgICAgd29yZCA9IG1hdGNoWzBdO1xuICAgICAgICAgICAgICAgICAgICBpbmRleCA9IG1hdGNoLmluZGV4O1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgLy8gfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7dGV4dDogd29yZCwgaW5kZXg6IGluZGV4fTtcblx0fVxuXG5cdGdldENsaWNrZWRUZXh0T2JqRnJvbURvYyh4LCB5LCBtaW5Ob2RlTGVuZ3RoOnN0cmluZz0xMCk6c3RyaW5nIHtcblx0XHQvL2NvbnN0IG1pbk5vZGVMZW5ndGg6bnVtYmVyID0gMTA7XG5cblx0ICAgIC8vIEdldCB0aGUgd29yZCB1bmRlciB0aGUgY2xpY2sgcG9zaXRpb25cblx0ICAgIGxldCByYW5nZSwgbm9kZVRleHQsIG9mZnNldDtcblxuXHQgICAgLy8gVGhpcyBtZXRob2QgaXMgYmV0dGVyIHN1cHBvcnRlZCBhbmQgZ2l2ZXMgdXMgYSByYW5nZSBvYmplY3Rcblx0ICAgIGlmIChkb2N1bWVudC5jYXJldFJhbmdlRnJvbVBvaW50KSB7XG5cdCAgICAgICAgcmFuZ2UgPSBkb2N1bWVudC5jYXJldFJhbmdlRnJvbVBvaW50KHgsIHkpO1xuXHQgICAgICAgIFxuXHQgICAgICAgIC8vY29uc3QgY29udGFpbmVyRWwgPSByYW5nZS5zdGFydENvbnRhaW5lci5wYXJlbnROb2RlIGFzIEhUTUxFbGVtZW50O1xuXHQgICAgICAgIC8vY29uc29sZS5sb2coY29udGFpbmVyRWwuY2xvc2VzdCgnLnRhZy1zdW1tYXJ5LWJsb2NrJykpXG5cdCAgICAgICAgXG5cdCAgICAgICAgLy9jb25zb2xlLmxvZyhyYW5nZS5zdGFydENvbnRhaW5lci5wYXJlbnROb2RlLnBhcmVudE5vZGUpXG5cdCAgICAgICAgXG5cblx0ICAgICAgICBpZiAocmFuZ2Uuc3RhcnRDb250YWluZXIubm9kZVR5cGUgPT09IE5vZGUuVEVYVF9OT0RFKSB7XG4gICAgICAgIFx0XHRub2RlVGV4dCA9IHJhbmdlLnN0YXJ0Q29udGFpbmVyLm5vZGVWYWx1ZS50cmltKCk7XG4gICAgXHRcdH0gZWxzZSB7XG4gICAgXHRcdFx0Ly9jb25zb2xlLmxvZyAoJ25vIHRleHQnKVxuICAgIFx0XHRcdHJldHVybiBudWxsO1xuICAgIFx0XHR9XG5cdCAgICAgICAgb2Zmc2V0ID0gcmFuZ2Uuc3RhcnRPZmZzZXQ7XG5cdCAgICB9XG5cblx0ICAgIGlmIChub2RlVGV4dC5sZW5ndGggPCBtaW5Ob2RlTGVuZ3RoKSB7XG5cdCAgICBcdC8vY29uc29sZS5sb2cgKCd0ZXh0IHRvbyBzaG9ydCcpXG5cdCAgICBcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHQgICAgcmV0dXJuIHt0ZXh0OiBub2RlVGV4dCwgaW5kZXg6IG9mZnNldCwgZWw6IHJhbmdlLnN0YXJ0Q29udGFpbmVyLnBhcmVudE5vZGV9O1xuXHR9XG5cblx0Lyphc3luYyBnZXRDbGlja2VkV29yZChlKSB7XG5cdFx0Ly9HZXQgdGhlIGNsaWNrIHBvc2l0aW9uXG5cdCAgICBsZXQgeCA9IGUuY2xpZW50WCwgeSA9IGUuY2xpZW50WTtcblxuXHQgICAgLy8gR2V0IHRoZSB3b3JkIHVuZGVyIHRoZSBjbGljayBwb3NpdGlvblxuXHQgICAgbGV0IHJhbmdlLCB0ZXh0Tm9kZSwgb2Zmc2V0O1xuXG5cdCAgICAvLyBUaGlzIG1ldGhvZCBpcyBiZXR0ZXIgc3VwcG9ydGVkIGFuZCBnaXZlcyB1cyBhIHJhbmdlIG9iamVjdFxuXHQgICAgaWYgKGRvY3VtZW50LmNhcmV0UmFuZ2VGcm9tUG9pbnQpIHtcblx0ICAgICAgICByYW5nZSA9IGRvY3VtZW50LmNhcmV0UmFuZ2VGcm9tUG9pbnQoeCwgeSk7XG5cdCAgICAgICAgdGV4dE5vZGUgPSByYW5nZS5zdGFydENvbnRhaW5lcjtcblx0ICAgICAgICBvZmZzZXQgPSByYW5nZS5zdGFydE9mZnNldDtcblx0ICAgIH1cblx0ICAgIC8vY29uc29sZS5sb2codGV4dE5vZGUpXG5cblx0ICAgIC8vIExBVEVSLCBkb3VibGUgY2hlY2sgZGlmZmVyZW50IG5vdGVzIHR5cGVzIGFuZCBhcm91bmQgdGhlIGludGVyZmFjZVxuXG5cdCAgICAvLyBDaGVjayBpZiB3ZSBoYXZlIGEgdmFsaWQgdGV4dCBub2RlXG5cdCAgICBpZiAodGV4dE5vZGUgJiYgdGV4dE5vZGUubm9kZVR5cGUgPT09IE5vZGUuVEVYVF9OT0RFKSB7XG5cdCAgICAgICAgLy8gR2V0IHRoZSB3aG9sZSB0ZXh0IG9mIHRoZSBjbGlja2VkIG5vZGVcblx0ICAgICAgICBsZXQgZnVsbFRleHQgPSB0ZXh0Tm9kZS50ZXh0Q29udGVudDtcblxuXHQgICAgICAgIC8vIExBVEVSOiBpZiB0aGUgd29yZCBlbmQgaW4gdmFsaWQgcHVuY3R1YXRpb24sIGFkZCBhIHNwYWNlIGJldHdlZW4gd29yZCBhbmQgcHVuY3R1YXRpb24gaXQgd2hlbiBhZGRpbmcgdGhlIGhhc2guXG5cdCAgICAgICAgLy8gTEFURVIsIGhhdmUgcHJlZGVmaW5lZCB0YWdzIHdlIGNhbiBpbnNlcnQgd2l0aCBkaWZmZXJlbnQga2V5IG1vZGlmaWVycyBvbiBjbGlja1xuXHQgICAgICAgIC8vIGxpa2UsICN0b2RvIG9yICNpbmJveCAjbGF0ZXJcblxuXHQgICAgICAgIGxldCB3b3JkUmVnZXggPSAvW15cXHNdKyg/PVsuLDohP10/KFxcc3wkKSkvZztcblx0XHRcdGxldCBtYXRjaDtcblx0XHRcdGxldCBjbGlja2VkV29yZCA9IG51bGw7XG5cdCAgICAgICAgd2hpbGUgKChtYXRjaCA9IHdvcmRSZWdleC5leGVjKGZ1bGxUZXh0KSkgIT09IG51bGwpIHtcblx0ICAgICAgICAgICAgaWYgKG1hdGNoLmluZGV4IDw9IG9mZnNldCAmJiBvZmZzZXQgPD0gbWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgpIHtcblx0ICAgICAgICAgICAgICAgIC8vIFRoaXMgaXMgb3VyIHdvcmRcblx0ICAgICAgICAgICAgICAgIGlmICghL15bXlxccHtMfVxccHtOfV0vdS50ZXN0KG1hdGNoWzBdKSAmJiAgICAgICAgLy8gTm90IHN0YXJ0aW5nIHdpdGggYW55IG5vbi1hbHBoYW51bWVyaWNcblx0ICAgICAgICAgICAgICAgICAgICAhL1teXFxwe0x9XFxwe059XFxzLiw6IT9dL3UudGVzdChtYXRjaFswXSkgJiZcdC8vIE5vdCBjb250YWluaW5nIG90aGVyIHRoYW4gYWxsb3dlZCBjaGFyc1xuXHQgICAgICAgICAgICAgICAgICAgICEvWy4sOiE/XSg/PVteXFxzJF0pL3UudGVzdChtYXRjaFswXSkpIHsgICAgIC8vIElmIGVuZHMgd2l0aCBwdW5jdHVhdGlvbiwgZm9sbG93aW5nIGNoYXJhY3RlciBtdXN0IGJlIHdoaXRlc3BhY2Ugb3IgZW5kIG9mIHN0cmluZ1xuXHQgICAgICAgICAgICAgICAgICAgIGNsaWNrZWRXb3JkID0gbWF0Y2hbMF07XG5cdCAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG5cdCAgICAgICAgICAgICAgICB9XG5cdCAgICAgICAgICAgIH1cblx0ICAgICAgICB9XG5cblxuXHRcdFx0bGV0IGFjdGl2ZVZpZXcgPSBhd2FpdCB0aGlzLmFwcC53b3Jrc3BhY2UuZ2V0QWN0aXZlVmlld09mVHlwZShNYXJrZG93blZpZXcpO1xuXG5cdFx0XHRcblx0XHQgICAgbGV0IGVkaXRvciA9IGFjdGl2ZVZpZXcuc291cmNlTW9kZS5jbUVkaXRvcjsgIC8vIEdldCB0aGUgQ29kZU1pcnJvciBpbnN0YW5jZVxuXHRcdCAgICBsZXQgZnVsbE5vdGUgPSBlZGl0b3IuZ2V0VmFsdWUoKTsgXG5cblx0XHRcdGNvbnN0IGdsb2JhbFN0YXJ0UG9zaXRpb24gPSBmdWxsTm90ZS5pbmRleE9mKHRleHROb2RlLnRleHRDb250ZW50KTtcblxuXHRcdFx0aWYgKGdsb2JhbFN0YXJ0UG9zaXRpb24gIT09IC0xKSB7XG5cdFx0XHQgICAgLy8gQXNzdW1pbmcgdGhlIGNsaWNrIHdhcyByaWdodCBhdCB0aGUgZW5kIG9mIHRoZSB3b3JkXG5cdFx0XHQgICAgbGV0IHdvcmRFbmRQb3NpdGlvbiA9IGdsb2JhbFN0YXJ0UG9zaXRpb24gKyBvZmZzZXQ7XG5cblx0XHRcdCAgICAvLyBUcmF2ZXJzZSBiYWNrd2FyZCB1bnRpbCBhIHNwYWNlIG9yIHN0YXJ0XG5cdFx0XHQgICAgd2hpbGUgKHdvcmRFbmRQb3NpdGlvbiA+IDAgJiYgZnVsbE5vdGVbd29yZEVuZFBvc2l0aW9uXSAhPT0gJyAnICYmIGZ1bGxOb3RlW3dvcmRFbmRQb3NpdGlvbl0gIT09ICdcXG4nKSB7XG5cdFx0XHQgICAgICAgIHdvcmRFbmRQb3NpdGlvbi0tO1xuXHRcdFx0ICAgIH1cblxuXHRcdFx0ICAgIHdvcmRFbmRQb3NpdGlvbisrO1xuXG5cdFx0XHQgICAgLy8gSW5zZXJ0IGhhc2ggYXQgd29yZEVuZFBvc2l0aW9uXG5cdFx0XHQgICAgY29uc3QgdXBkYXRlZE5vdGUgPSBbZnVsbE5vdGUuc2xpY2UoMCwgd29yZEVuZFBvc2l0aW9uKSwgJyMnLCBmdWxsTm90ZS5zbGljZSh3b3JkRW5kUG9zaXRpb24pXS5qb2luKCcnKTtcblx0XHRcdCAgICBjb25zb2xlLmxvZyh1cGRhdGVkTm90ZSk7XG5cdFx0XHR9XG5cblxuXHRcdH1cblxuXHRcdC8vIExBVEVSLCB0byBtYWtlIHRoaXMgd29yayBpbiBlbWJlZHMgYW5kIHN1bW1hcmllc1xuXHRcdC8vIGFuZCBhdm9pZCBhZGRpbmcgd2hlbiBpbiB0aGUgc3VtbWFyeSBlbXB0eSBibG9jay4gb3Igb3RoZXIgY29kZSBibG9ja3MuIG1heWJlIHRoaXMgY2hlY2sgaXMgZWFybGllci5cblx0fSovXG5cblx0ZXNjYXBlUmVnRXhwKHN0cmluZyk6c3RyaW5nIHtcbiAgICBcdHJldHVybiBzdHJpbmcucmVwbGFjZSgvWy4qKz9eJHt9KCl8W1xcXVxcXFxdL2csICdcXFxcJCYnKTsgLy8gJCYgbWVhbnMgdGhlIHdob2xlIG1hdGNoZWQgc3RyaW5nXG5cdH1cblxuXHRnZXRUYWdzRnJvbUFwcCgpOiBzdHJpbmdbXSB7XG5cdCAgICBjb25zdCB0YWdzT2JqZWN0ID0gdGhpcy5hcHAubWV0YWRhdGFDYWNoZS5nZXRUYWdzKCk7XG5cblx0ICAgIC8vIENvbnZlcnQgdGFnc09iamVjdCB0byBhbiBhcnJheSBvZiBbdGFnLCBjb3VudF0gdHVwbGVzXG5cdCAgICBjb25zdCB0YWdzQXJyYXkgPSBPYmplY3QuZW50cmllcyh0YWdzT2JqZWN0KTtcblxuXHQgICAgLy8gU29ydCBieSB1c2UgY291bnRcblx0ICAgIHRhZ3NBcnJheS5zb3J0KChhLCBiKSA9PiBiWzFdIC0gYVsxXSk7XG5cblx0ICAgIGNvbnN0IHJlY2VudFRhZ3MgPSB0aGlzLmdldFJlY2VudFRhZ3MoKTtcblx0ICAgLy8gY29uc29sZS5sb2coJ3JlY2VudCB0YWcgbGVuZ3RoOiAnICsgcmVjZW50VGFncy5sZW5ndGgpXG5cblx0ICAgIGlmIChyZWNlbnRUYWdzLmxlbmd0aD4wKSB7XG5cdCAgICBcdC8vY29uc29sZS5sb2cocmVjZW50VGFncylcblx0ICAgIFx0Ly8gY29udmVydCB0aGVtIHRvIFt0YWcsIGNvdW50XSB0dXBsZXMgZm9yIGNvbnNpc3RlbmN5XG5cdCAgIFx0XHRjb25zdCByZWNlbnRUYWdzQXNUdXBsZXMgPSByZWNlbnRUYWdzLm1hcCh0YWcgPT4gW3RhZywgMF0pO1xuXHQgICAgXHQvLyBDb25jYXRlbmF0ZSB0aGUgdHdvIGFycmF5c1xuXHQgICAgXHRjb25zdCByZWNlbnRBbmRBbGxUYWdzID0gcmVjZW50VGFnc0FzVHVwbGVzLmNvbmNhdCh0YWdzQXJyYXkpO1xuXHQgICAgXHQvLyBFeHRyYWN0IHRhZyBuYW1lcyBhZnRlciByZW1vdmluZyB0aGUgI1xuXHQgICAgXHRyZXR1cm4gcmVjZW50QW5kQWxsVGFncy5tYXAoKFt0YWcsIF9dKSA9PiB0YWcucmVwbGFjZSgvXiMvLCBcIlwiKSk7XG4gICAgICAgXHR9IGVsc2Uge1xuICAgICAgIFx0XHRyZXR1cm4gdGFnc0FycmF5Lm1hcCgoW3RhZywgX10pID0+IHRhZy5yZXBsYWNlKC9eIy8sIFwiXCIpKTtcbiAgICAgICBcdH1cblx0fVxuXG5cdGdldFRhZ0VsZW1lbnQocGFyYWdyYXBoRWwsIHRhZ1RleHQpIHtcblx0ICAgIC8vY29uc29sZS5sb2coJ0dldCB0YWcgZWxlbWVudCcpXG5cdCAgICBjb25zdCBlbHMgPSBwYXJhZ3JhcGhFbC5xdWVyeVNlbGVjdG9yQWxsKCcudGFnJyk7IFxuXHQgICAgLy9BcnJheS5mcm9tKGVscykubWFwKGVsID0+IGNvbnNvbGUubG9nKGVsLmlubmVyVGV4dCkpO1xuXHQgICAgbGV0IHRhZ0VsVGV4dCA9ICcnO1xuXHQgICAgbGV0IHRhZ0VsSGFzU3ViOmJvb2xlYW47XG5cdCAgICBmb3IgKGxldCBlbCBvZiBlbHMpIHtcblx0ICAgIFx0dGFnRWxUZXh0ID0gZWwuaW5uZXJUZXh0LnRyaW0oKTtcblx0ICAgIFx0Ly9jb25zb2xlLmxvZyh0YWdFbFRleHQgKyAnID09ICcgKyB0YWdUZXh0KVxuXHQgICAgXHRpZiAodGFnRWxUZXh0ID09PSB0YWdUZXh0KSB7XG5cdCAgICBcdFx0Ly9jb25zb2xlLmxvZyhlbC5pbm5lclRleHQpXG5cdCAgICBcdFx0Ly9jb25zb2xlLmxvZyhlbClcblx0ICAgIFx0XHRyZXR1cm4gZWxcblx0ICAgIFx0fVxuXHQgICAgXHQvL3RhZ0VsVGV4dCA9IGVsLmlubmVyVGV4dC50cmltKCk7XG5cdCAgICBcdC8vdGFnRWxIYXNTdWIgPSB0YWdFbFRleHQuaW5jbHVkZXMoJy8nKVxuXHQgICAgXHQvL2NvbnNvbGUubG9nKHRhZ0VsVGV4dCArICcgaGFzIHN1Yj8gJyArIHRhZ0VsSGFzU3ViKVxuXHQgICAgfVx0XG5cdCAgICAvKmZvciAobGV0IGVsIG9mIGVscykge1xuXHQgICAgXHRjb25zb2xlLmxvZyhlbC5pbm5lclRleHQpXG5cdCAgICBcdHRhZ0VsVGV4dCA9IGVsLmlubmVyVGV4dC50cmltKCk7XG5cdCAgICBcdHRhZ0VsSGFzU3ViID0gdGFnRWxUZXh0LmluY2x1ZGVzKCcvJylcblx0ICAgIFx0Ly9jb25zb2xlLmxvZyh0YWdFbFRleHQgKyAnIGhhcyBzdWI/ICcgKyB0YWdFbEhhc1N1Yilcblx0ICAgICAgICBpZiAodGFnRWxIYXNTdWIpIHtcblx0ICAgICAgICBcdC8vY29uc29sZS5sb2coZWwpO1xuXHQgICAgICAgIFx0Y29udGludWU7XG5cdCAgICAgICAgfSBlbHNlIGlmICh0YWdFbFRleHQgPT09IHRhZ1RleHQgJiYgKCF0YWdFbEhhc1N1YiB8fCAodGFnRWxIYXNTdWIgJiYgKHRhZ0VsVGV4dCA9PT0gdGFnVGV4dCkpKSkge1xuXHQgICAgICAgICAgICByZXR1cm4gZWw7XG5cdCAgICAgICAgfVxuXHQgICAgfSovXG5cblx0ICAgIGNvbnNvbGUud2FybihgRWxlbWVudCB3aXRoIHRleHQgXCIke3RhZ1RleHR9XCIgbm90IGZvdW5kYCk7XG5cdCAgICByZXR1cm4gbnVsbDtcblx0fVxuXG5cdGN0cmxDbWRLZXkgKGV2ZW50KSB7XG5cdFx0Y29uc3QgaXNNYWMgPSAobmF2aWdhdG9yLnBsYXRmb3JtLnRvVXBwZXJDYXNlKCkuaW5kZXhPZignTUFDJykgPj0gMCk7XG5cblx0XHRpZiAoaXNNYWMpIHJldHVybiBldmVudC5tZXRhS2V5O1xuXHRcdGVsc2UgcmV0dXJuIGV2ZW50LmN0cmxLZXk7XG5cdH1cblxuXHRkZWJvdW5jZShmdW5jLCB3YWl0KSB7XG4gICAgXHRsZXQgdGltZW91dDtcbiAgICBcdHJldHVybiBmdW5jdGlvbiguLi5hcmdzKSB7XG4gICAgICAgIFx0Y29uc3QgY29udGV4dCA9IHRoaXM7XG4gICAgICAgIFx0Y2xlYXJUaW1lb3V0KHRpbWVvdXQpO1xuICAgICAgICBcdHRpbWVvdXQgPSBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgIFx0ZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgXHR9LCB3YWl0KTtcbiAgICBcdH07XG5cdH1cbn1cblxuY2xhc3MgVGVtcENvbXBvbmVudCBleHRlbmRzIENvbXBvbmVudCB7XG5cdG9ubG9hZCgpIHt9XG5cdG9udW5sb2FkKCkge31cbn1cblxuY2xhc3MgRG91YmxlVGFwSGFuZGxlciB7XG4gIGNvbnN0cnVjdG9yKHBsdWdpbiwgZWxlbWVudCwgY2FsbGJhY2spIHtcbiAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbjsgLy8gU3RvcmUgdGhlIHBsdWdpbiBpbnN0YW5jZVxuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgIHRoaXMubGFzdFRhcCA9IDA7XG4gICAgLy9uZXcgTm90aWNlKCdkb3VibGUgdGFwIGNyZWF0ZWQnKVxuICAgIHRoaXMucGx1Z2luLnJlZ2lzdGVyRG9tRXZlbnQodGhpcy5lbGVtZW50LCAndG91Y2hlbmQnLCB0aGlzLmhhbmRsZVRvdWNoRW5kLmJpbmQodGhpcyksIHRydWUpO1xuICB9XG5cbiAgaGFuZGxlVG91Y2hFbmQoZXZlbnQpIHtcbiAgICBjb25zdCBjdXJyZW50VGltZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IHRhcExlbmd0aCA9IGN1cnJlbnRUaW1lIC0gdGhpcy5sYXN0VGFwO1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXQpO1xuICAgIFxuICAgIGlmICh0YXBMZW5ndGggPCA1MDAgJiYgdGFwTGVuZ3RoID4gMCkge1xuICAgICAgLy9ldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgLy9ldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgIC8vbmV3IE5vdGljZSgnZG91YmxlIHRhcCBmaXJlZCcpO1xuICAgICAgdGhpcy5jYWxsYmFjayhldmVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudGltZW91dCA9IHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICBjbGVhclRpbWVvdXQodGhpcy50aW1lb3V0KTtcbiAgICAgIH0sIDUwMCk7XG4gICAgfVxuICAgIHRoaXMubGFzdFRhcCA9IGN1cnJlbnRUaW1lO1xuICB9XG59XG5cbmNsYXNzIFByZXNzQW5kSG9sZEhhbmRsZXIge1xuICBjb25zdHJ1Y3RvcihwbHVnaW4sIGVsZW1lbnQsIGNhbGxiYWNrLCBkdXJhdGlvbiA9IDYwMCkge1xuICAgIHRoaXMucGx1Z2luID0gcGx1Z2luO1xuICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgdGhpcy5jYWxsYmFjayA9IGNhbGxiYWNrO1xuICAgIHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjsgLy8gZHVyYXRpb24gaW4gbWlsbGlzZWNvbmRzIHRvIGNvbnNpZGVyIGFzIFwiaG9sZFwiXG4gICAgdGhpcy50aW1lb3V0ID0gbnVsbDtcblxuICAgIC8vbmV3IE5vdGljZSAoJ3ByZXNzQW5kSG9sZCBjcmVhdGVkLicpXG5cbiAgICB0aGlzLnBsdWdpbi5yZWdpc3RlckRvbUV2ZW50KHRoaXMuZWxlbWVudCwgJ3RvdWNoc3RhcnQnLCB0aGlzLmhhbmRsZVRvdWNoU3RhcnQuYmluZCh0aGlzKSwgdHJ1ZSk7XG4gICAgdGhpcy5wbHVnaW4ucmVnaXN0ZXJEb21FdmVudCh0aGlzLmVsZW1lbnQsICd0b3VjaGVuZCcsIHRoaXMuaGFuZGxlVG91Y2hFbmQuYmluZCh0aGlzKSwgdHJ1ZSk7XG4gIH1cblxuICBoYW5kbGVUb3VjaFN0YXJ0KGV2ZW50KSB7XG4gICAgLy9ldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIC8vZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgdGhpcy50aW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgXHQvL25ldyBOb3RpY2UgKCdwcmVzc0FuZEhvbGQgZXZlbnQgZmlyZWQuJylcbiAgICAgIHRoaXMuY2FsbGJhY2soZXZlbnQpO1xuICAgICAgdGhpcy50aW1lb3V0ID0gbnVsbDtcbiAgICB9LCB0aGlzLmR1cmF0aW9uKTtcbiAgfVxuXG4gIGhhbmRsZVRvdWNoRW5kKGV2ZW50KSB7XG4gICAgaWYgKHRoaXMudGltZW91dCkge1xuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMudGltZW91dCk7XG4gICAgICB0aGlzLnRpbWVvdXQgPSBudWxsO1xuICAgIH1cbiAgfVxufVxuIiwgIlxuaW1wb3J0IFRhZ0J1ZGR5IGZyb20gXCJtYWluXCI7XG5pbXBvcnQgeyBBcHAsIFBsdWdpblNldHRpbmdUYWIsIFNldHRpbmcgfSBmcm9tIFwib2JzaWRpYW5cIjtcblxuZXhwb3J0IGNsYXNzIFRCU2V0dGluZ3NUYWIgZXh0ZW5kcyBQbHVnaW5TZXR0aW5nVGFiIHtcbiAgICBwbHVnaW46IFRhZ0J1ZGR5O1xuXG4gICAgY29uc3RydWN0b3IoYXBwOiBBcHAsIHBsdWdpbjogVGFnQnVkZHkpIHtcbiAgICAgICAgc3VwZXIoYXBwLCBwbHVnaW4pO1xuICAgICAgICB0aGlzLnBsdWdpbiA9IHBsdWdpbjtcbiAgICB9XG4gICAgZGlzcGxheSgpOiB2b2lkIHtcbiAgICAgICAgbGV0IHsgY29udGFpbmVyRWwgfSA9IHRoaXM7XG4gICAgICAgIGNvbnRhaW5lckVsLmVtcHR5KCk7XG5cbiAgICAgICAgY29udGFpbmVyRWwuY3JlYXRlRWwoXCJoMVwiLCB7IHRleHQ6IFwiVGFnIEJ1ZGR5XCIgfSk7XG5cbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAgIC5zZXROYW1lKFwiT3ZlcnJpZGUgbmF0aXZlIHRhZyBzZWFyY2ggb24gY2xpY2tcIilcbiAgICAgICAgLnNldERlc2MoXCJUb2dnbGUgT0ZGIHRvIHVzZSBDVFJML0NNRCtDTElDSyB0byByZW1vdmUgdGFnLlwiKVxuICAgICAgICAuYWRkVG9nZ2xlKCh0b2dnbGUpID0+XG4gICAgICAgICAgICB0b2dnbGVcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5yZW1vdmVPbkNsaWNrKVxuICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLnJlbW92ZU9uQ2xpY2sgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAgIC5zZXROYW1lKFwiQ29udmVydCB0byB0YWcgdGV4dCAocmVtb3ZlcyAjKVwiKVxuICAgICAgICAuc2V0RGVzYyhcIlRvZ2dsZSBPRkYgdG8gdXNlIE9QVC9BTFQrQ0xJQ0sgdG8gcGVyZm9ybSBuYXRpdmUgdGFnIHNlYXJjaC5cIilcbiAgICAgICAgLmFkZFRvZ2dsZSgodG9nZ2xlKSA9PlxuICAgICAgICAgICAgdG9nZ2xlXG4gICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3Mub3B0VG9Db252ZXJ0KVxuICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLm9wdFRvQ29udmVydCA9IHZhbHVlO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgICAgLnNldE5hbWUoXCJSZW1vdmUgbmVzdGVkIHRhZ3MgZmlyc3RcIilcbiAgICAgICAgLnNldERlc2MoXCJUb2dnbGUgT0ZGIHRvIHVzZSBTSElGVCtDTElDSyB0byByZW1vdmUgbmVzdGVkIHRhZ3MgZmlyc3QuXCIpXG4gICAgICAgIC5hZGRUb2dnbGUoKHRvZ2dsZSkgPT5cbiAgICAgICAgICAgIHRvZ2dsZVxuICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLnJlbW92ZUNoaWxkVGFnc0ZpcnN0KVxuICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLnJlbW92ZUNoaWxkVGFnc0ZpcnN0ID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgICAuc2V0TmFtZShcIk1vYmlsZSB0YWcgc2VhcmNoXCIpXG4gICAgICAgIC5zZXREZXNjKFwiVG9nZ2xlIE9OIHRvIHJlc3RvcmUgbW9iaWxlIG5hdGl2ZSB0YWcgc2VhcmNoIG9uIHRhcC4gVGFnIHJlbW92YWwgd2lsbCB0aGVuIHVzZSBMT05HIFBSRVNTLlwiKVxuICAgICAgICAuYWRkVG9nZ2xlKCh0b2dnbGUpID0+XG4gICAgICAgICAgICB0b2dnbGVcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5tb2JpbGVUYWdTZWFyY2gpXG4gICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MubW9iaWxlVGFnU2VhcmNoID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgICAuc2V0TmFtZShcIlNob3cgbW9iaWxlIG5vdGljZXNcIilcbiAgICAgICAgLnNldERlc2MoXCJUb2dnbGUgT0ZGIHRvIGhpZGUgbm90aWNlcyB3aGVuIGVkaXRpbmcgb3IgcmVtb3ZpbmcgYSB0YWcuXCIpXG4gICAgICAgIC5hZGRUb2dnbGUoKHRvZ2dsZSkgPT5cbiAgICAgICAgICAgIHRvZ2dsZVxuICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLm1vYmlsZU5vdGljZXMpXG4gICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MubW9iaWxlTm90aWNlcyA9IHZhbHVlO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMucGx1Z2luLnNhdmVTZXR0aW5ncygpO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcblxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgICAgLnNldE5hbWUoXCJCRVRBOiBTaG93IHRhZyBzdW1tYXJ5IHBhcmFncmFwaCBidXR0b25zXCIpXG4gICAgICAgIC5zZXREZXNjKFwiU2hvdyBidXR0b25zIGJlbG93IGVhY2ggdGFnZ2VkIHBhcmFncmFwaCB0aGF0IGxldCB5b3UgY29weSwgcmVtb3ZlLCBhbmQgbW92ZSB0aGUgcGFyYWdyYXBoLlwiKVxuICAgICAgICAuYWRkVG9nZ2xlKCh0b2dnbGUpID0+XG4gICAgICAgICAgICB0b2dnbGVcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy50YWdTdW1tYXJ5QmxvY2tCdXR0b25zKVxuICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLnRhZ1N1bW1hcnlCbG9ja0J1dHRvbnMgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgbmV3IFNldHRpbmcoY29udGFpbmVyRWwpXG4gICAgICAgIC5zZXROYW1lKFwiQkVUQTogU2hvdyB0YWcgc3VtbWFyeSBidXR0b25zXCIpXG4gICAgICAgIC5zZXREZXNjKFwiU2hvdyBidXR0b25zIGJlbG93IGVhY2ggc3VtbWFyeSB0aGF0IGxldCB5b3UgY29weSBvciBtYWtlIGEgbm90ZSBmcm9tIHRoZSBzdW1tYXJ5LlwiKVxuICAgICAgICAuYWRkVG9nZ2xlKCh0b2dnbGUpID0+XG4gICAgICAgICAgICB0b2dnbGVcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5zaG93U3VtbWFyeUJ1dHRvbnMpXG4gICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3Muc2hvd1N1bW1hcnlCdXR0b25zID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5wbHVnaW4uc2F2ZVNldHRpbmdzKCk7XG4gICAgICAgICAgICB9KVxuICAgICAgICApO1xuXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgICAuc2V0TmFtZShcIkNvcHkgdG8gc2VjdGlvbiBwcmVmaXhcIilcbiAgICAgICAgLnNldERlc2MoXCJXaGVuIG1vdmluZyBhIHRhZ2dlZCBwYXJhZ3JhcGggZnJvbSB0YWcgc3VtbWFyaWVzIGJlbG93IG5vdGUgaGVhZGVyIHNlY3Rpb25zIHVzZSB0aGlzIHByZWZpeDpcXG5FeGFtcGxlOiAnLSAnLCAnPiAnLCAnLSBbIF0nXCIpXG4gICAgICAgIC5hZGRUZXh0KCh0ZXh0KSA9PiB7XG4gICAgICAgICAgICB0ZXh0XG4gICAgICAgICAgICAuc2V0UGxhY2Vob2xkZXIodGhpcy5wbHVnaW4uc2V0dGluZ3MudGFnZ2VkUGFyYWdyYXBoQ29weVByZWZpeClcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy50YWdnZWRQYXJhZ3JhcGhDb3B5UHJlZml4KVxuICAgICAgICAgICAgLm9uQ2hhbmdlKGFzeW5jICh2YWx1ZSkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMucGx1Z2luLnNldHRpbmdzLnRhZ2dlZFBhcmFncmFwaENvcHlQcmVmaXggPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBmdW5jdGlvbiBpc1ZhbGlkVGFnKHRhZykge1xuICAgICAgICAgICAgY29uc3QgdGFnUGF0dGVybiA9IC9eI1tcXHddKyQvO1xuICAgICAgICAgICAgcmV0dXJuIHRhZ1BhdHRlcm4udGVzdCh0YWcpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gZmlsdGVyQW5kSm9pblRhZ3ModGFnc1N0cmluZykge1xuICAgICAgICAgICAgY29uc3QgdGFnc0FycmF5ID0gdGFnc1N0cmluZy5zcGxpdChcIiwgXCIpO1xuICAgICAgICAgICAgY29uc3QgdmFsaWRUYWdzID0gdGFnc0FycmF5LmZpbHRlcihpc1ZhbGlkVGFnKTtcbiAgICAgICAgICAgIHJldHVybiB2YWxpZFRhZ3Muam9pbihcIiwgXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQWRkaW5nIHdpbGwgYWx3YXlzIGxpbWl0IHRvIDMuIEJ1dCBpZiB0aGV5IGVkaXQgaXQgaGVyZSwgaXQgY2FuIGJlIGFueSBsZW5ndGguXG4gICAgICAgIG5ldyBTZXR0aW5nKGNvbnRhaW5lckVsKVxuICAgICAgICAuc2V0TmFtZShcIlJlY2VudCB0YWdzXCIpXG4gICAgICAgIC5zZXREZXNjKFwiVGhlIG1vc3QgcmVjZW50IHRhZ3MgYWRkZWQgdmlhIFRhZyBCdWRkeSBhcmUgc3RvcmVkIGhlcmUuIFRoZXNlIHdpbGwgc2hvdyB1cCBmaXJzdCBpbiB0aGUgbGlzdCB3aGVuIGFkZGluZy5cIilcbiAgICAgICAgLmFkZFRleHQoKHRleHQpID0+IHtcbiAgICAgICAgICAgIHRleHRcbiAgICAgICAgICAgIC5zZXRQbGFjZWhvbGRlcih0aGlzLnBsdWdpbi5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFncylcbiAgICAgICAgICAgIC5zZXRWYWx1ZSh0aGlzLnBsdWdpbi5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFncylcbiAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5yZWNlbnRseUFkZGVkVGFncyA9IGZpbHRlckFuZEpvaW5UYWdzKHZhbHVlKTsgLy92YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgICAgLnNldE5hbWUoXCJMb2NrIHJlY2VudCB0YWdzXCIpXG4gICAgICAgIC5zZXREZXNjKFwiVG9nZ2xlIE9OIHRvIGxvY2sgdGhlIHJlY2VudCB0YWdzIGxpc3QuIFJlY2VudCB0YWdzIHdpbGwgbm90IGJlIHVwZGF0ZWQuIEluc3RlYWQsIHRoZSB0YWdzIGFib3ZlIHdpbGwgYWN0IGxpa2UgYSBmYXZvcml0ZXMgbGlzdC5cIilcbiAgICAgICAgLmFkZFRvZ2dsZSgodG9nZ2xlKSA9PlxuICAgICAgICAgICAgdG9nZ2xlXG4gICAgICAgICAgICAuc2V0VmFsdWUodGhpcy5wbHVnaW4uc2V0dGluZ3MubG9ja1JlY2VudFRhZ3MpXG4gICAgICAgICAgICAub25DaGFuZ2UoYXN5bmMgKHZhbHVlKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wbHVnaW4uc2V0dGluZ3MubG9ja1JlY2VudFRhZ3MgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG5cbiAgICAgICAgY29udGFpbmVyRWwuY3JlYXRlRWwoJ2hyJyk7XG4gICAgICAgIGNvbnRhaW5lckVsLmNyZWF0ZUVsKFwiaDFcIiwgeyB0ZXh0OiBcIlN1cHBvcnQgYSBidWRkeVwiIH0pO1xuICAgICAgICBjb25zdCBkb25hdGVCdXR0b24gPSBjb250YWluZXJFbC5jcmVhdGVFbCgnYScpO1xuICAgICAgICBkb25hdGVCdXR0b24uc2V0QXR0cmlidXRlKCdocmVmJywgJ2h0dHBzOi8vd3d3LmJ1eW1lYWNvZmZlZS5jb20vbW9yZW1leW91Jyk7XG4gICAgICAgIGRvbmF0ZUJ1dHRvbi5pbm5lckhUTUwgPSBgPGltZyBzcmM9XCJodHRwczovL2Nkbi5idXltZWFjb2ZmZWUuY29tL2J1dHRvbnMvdjIvZGVmYXVsdC15ZWxsb3cucG5nXCIgYWx0PVwiQnV5IE1lIEEgQ29mZmVlXCIgc3R5bGU9XCJoZWlnaHQ6IDQwcHggIWltcG9ydGFudDt3aWR0aDogMTUwcHggIWltcG9ydGFudDtcIiA+PC9hPmA7XG5cbiAgICAgICAgY29udGFpbmVyRWwuY3JlYXRlRWwoJ2JyJyk7XG4gICAgICAgIGNvbnRhaW5lckVsLmNyZWF0ZUVsKCdicicpO1xuICAgICAgICBjb250YWluZXJFbC5jcmVhdGVFbCgnYnInKTtcblxuICAgICAgICBuZXcgU2V0dGluZyhjb250YWluZXJFbClcbiAgICAgICAgLnNldE5hbWUoXCJEZWJ1ZyBtb2RlXCIpXG4gICAgICAgIC5zZXREZXNjKFwiT3V0cHV0IHRvIGNvbnNvbGUuXCIpXG4gICAgICAgIC5hZGRUb2dnbGUoKHRvZ2dsZSkgPT5cbiAgICAgICAgICAgIHRvZ2dsZVxuICAgICAgICAgICAgLnNldFZhbHVlKHRoaXMucGx1Z2luLnNldHRpbmdzLmRlYnVnTW9kZSlcbiAgICAgICAgICAgIC5vbkNoYW5nZShhc3luYyAodmFsdWUpID0+IHtcbiAgICAgICAgICAgICAgICB0aGlzLnBsdWdpbi5zZXR0aW5ncy5kZWJ1Z01vZGUgPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsdWdpbi5zYXZlU2V0dGluZ3MoKTtcbiAgICAgICAgICAgIH0pXG4gICAgICAgICk7XG4gICAgfVxufVxuXG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBOzs7QUNFQSxzQkFBK0M7QUFFeEMsSUFBTSxnQkFBTixjQUE0QixpQ0FBaUI7QUFBQSxFQUdoRCxZQUFZQSxNQUFVLFFBQWtCO0FBQ3BDLFVBQU1BLE1BQUssTUFBTTtBQUNqQixTQUFLLFNBQVM7QUFBQSxFQUNsQjtBQUFBLEVBQ0EsVUFBZ0I7QUFDWixRQUFJLEVBQUUsWUFBWSxJQUFJO0FBQ3RCLGdCQUFZLE1BQU07QUFFbEIsZ0JBQVksU0FBUyxNQUFNLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFaEQsUUFBSSx3QkFBUSxXQUFXLEVBQ3RCLFFBQVEscUNBQXFDLEVBQzdDLFFBQVEsaURB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O0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEVBd0RHLGVBQWU7QUFJZCxVQUFNLFNBQVM7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUE4SmYsVUFBTSxhQUFhLFNB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QUEsRUFDeEIsWUFBWSxRQUFRLFNBQVMsVUFBVSxXQUFXLEtBQUs7QUFDckQsU0FBSyxTQUFTO0FBQ2QsU0FBSyxVQUFVO0FBQ2YsU0FBSyxXQUFXO0FBQ2hCLFNBQUssV0FBVztBQUNoQixTQUFLLFVBQVU7QUFJZixTQUFLLE9BQU8saUJBQWlCLEtBQUssU0FBUyxjQUFjLEtBQUssaUJBQWlCLEtBQUssSUFBSSxHQUFHLElBQUk7QUFDL0YsU0FBSyxPQUFPLGlCQUFpQixLQUFLLFNBQVMsWUFBWSxLQUFLLGVBQWUsS0FBSyxJQUFJLEdBQUcsSUFBSTtBQUFBLEVBQzdGO0FBQUEsRUFFQSxpQkFBaUIsT0FBTztBQUd0QixTQUFLLFVBQVUsV0FBVyxNQUFNO0FBRTlCLFdBQUssU0FBUyxLQUFLO0FBQ25CLFdBQUssVUFBVTtBQUFBLElBQ2pCLEdBQUcsS0FBSyxRQUFRO0FBQUEsRUFDbEI7QUFBQSxFQUVBLGVBQWUsT0FBTztBQUNwQixRQUFJLEtBQUssU0FBUztBQUNoQixtQkFBYSxLQUFLLE9BQU87QUFDekIsV0FBSyxVQUFVO0FBQUEsSUFDakI7QUFBQSxFQUNGO0FBQ0Y7IiwKICAibmFtZXMiOiBbImFwcCIsICJpbXBvcnRfb2JzaWRpYW4iLCAiZXJyb3IiLCAiY291bnQiLCAiZSIsICJub3RpY2UiLCAiZmlsZVBhdGgiXQp9Cg== diff --git a/src/package.json b/src/package.json index a0b202f..cd9bee4 100644 --- a/src/package.json +++ b/src/package.json @@ -1,6 +1,6 @@ { "name": "TagBuddy", - "version": "0.3.0", + "version": "0.7.1", "description": "Add, edit and remove tags and copy, move or edit tagged blocks all without leaving reading-mode.", "main": "main.js", "scripts": { diff --git a/src/versions.json b/src/versions.json new file mode 100644 index 0000000..7e61e08 --- /dev/null +++ b/src/versions.json @@ -0,0 +1,5 @@ +{ + "0.2.0": "1.0.0", + "0.3.0": "1.0.0", + "0.5.0": "1.0.0" +} \ No newline at end of file diff --git a/versions.json b/versions.json deleted file mode 100644 index 53be939..0000000 --- a/versions.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "0.2.0": "1.0.0", - "0.3.0": "1.0.0" -} \ No newline at end of file