UNPKG

obsidian-dev-utils

Version:

This is the collection of useful functions that you can use for your Obsidian plugin development

518 lines (516 loc) 70.2 kB
/* THIS IS A GENERATED/BUNDLED FILE BY ESBUILD if you want to view the source, please visit the github repository of this plugin */ (function initCjs(){const globalThisRecord=globalThis;globalThisRecord["__name"]??=name;const originalRequire=require;if(originalRequire&&!originalRequire.__isPatched){require=Object.assign(id=>requirePatched(id),originalRequire,{__isPatched:true})}const newFuncs={__extractDefault:__name(()=>extractDefault,"__extractDefault"),process:__name(()=>{const browserProcess={browser:true,cwd:__name(()=>"/","cwd"),env:{},platform:"android"};return browserProcess},"process")};for(const key of Object.keys(newFuncs)){globalThisRecord[key]??=newFuncs[key]?.()}function name(obj){return obj}__name(name,"name");function extractDefault(module){return module&&module.__esModule&&"default"in module?module.default:module}__name(extractDefault,"extractDefault");function requirePatched(id){const module=originalRequire?.(id);if(module){return extractDefault(module)}if(id==="process"||id==="node:process"){console.error(`Module not found: ${id}. Fake process object is returned instead.`);return globalThis.process}console.error(`Module not found: ${id}. Empty object is returned instead.`);return{}}__name(requirePatched,"requirePatched")})(); "use strict"; 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); var RenameDeleteHandler_exports = {}; __export(RenameDeleteHandler_exports, { EmptyAttachmentFolderBehavior: () => EmptyAttachmentFolderBehavior, registerRenameDeleteHandlers: () => registerRenameDeleteHandlers }); module.exports = __toCommonJS(RenameDeleteHandler_exports); var import_obsidian = require('obsidian'); var import_implementations = require('obsidian-typings/implementations'); var import_Array = require('../Array.cjs'); var import_Debug = require('../Debug.cjs'); var import_ObjectUtils = require('../ObjectUtils.cjs'); var import_Path = require('../Path.cjs'); var import_String = require('../String.cjs'); var import_App = require('./App.cjs'); var import_AttachmentPath = require('./AttachmentPath.cjs'); var import_FileSystem = require('./FileSystem.cjs'); var import_Link = require('./Link.cjs'); var import_MetadataCache = require('./MetadataCache.cjs'); var import_MonkeyAround = require('./MonkeyAround.cjs'); var import_Queue = require('./Queue.cjs'); var import_Vault = require('./Vault.cjs'); var import_VaultEx = require('./VaultEx.cjs'); const deletedMetadataCacheMap = /* @__PURE__ */ new Map(); const handledRenames = /* @__PURE__ */ new Set(); const interruptedRenamesMap = /* @__PURE__ */ new Map(); var EmptyAttachmentFolderBehavior = /* @__PURE__ */ ((EmptyAttachmentFolderBehavior2) => { EmptyAttachmentFolderBehavior2["Delete"] = "Delete"; EmptyAttachmentFolderBehavior2["DeleteWithEmptyParents"] = "DeleteWithEmptyParents"; EmptyAttachmentFolderBehavior2["Keep"] = "Keep"; return EmptyAttachmentFolderBehavior2; })(EmptyAttachmentFolderBehavior || {}); function registerRenameDeleteHandlers(plugin, settingsBuilder) { const renameDeleteHandlersMap = getRenameDeleteHandlersMap(plugin.app); const pluginId = plugin.manifest.id; renameDeleteHandlersMap.set(pluginId, settingsBuilder); logRegisteredHandlers(plugin.app); plugin.register(() => { renameDeleteHandlersMap.delete(pluginId); logRegisteredHandlers(plugin.app); }); const app = plugin.app; plugin.registerEvent( app.vault.on("delete", (file) => { handleDeleteIfEnabled(plugin, file); }) ); plugin.registerEvent( app.vault.on("rename", (file, oldPath) => { handleRenameIfEnabled(plugin, file, oldPath); }) ); plugin.registerEvent( app.metadataCache.on("deleted", (file, prevCache) => { handleMetadataDeletedIfEnabled(plugin, file, prevCache); }) ); (0, import_MonkeyAround.registerPatch)(plugin, app.fileManager, { runAsyncLinkUpdate: (next) => { return (linkUpdatesHandler) => runAsyncLinkUpdate(app, next, linkUpdatesHandler); } }); } async function cleanupParentFolders(app, parentFolderPaths, notePath) { const settings = getSettings(app); if (settings.emptyAttachmentFolderBehavior === "Keep" /* Keep */) { return; } for (const parentFolderPath of parentFolderPaths) { switch (settings.emptyAttachmentFolderBehavior) { case "Delete" /* Delete */: await (0, import_VaultEx.deleteSafe)(app, parentFolderPath, notePath, void 0, true); break; case "DeleteWithEmptyParents" /* DeleteWithEmptyParents */: await (0, import_VaultEx.deleteEmptyFolderHierarchy)(app, parentFolderPath); break; default: break; } } } async function continueInterruptedRenames(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks) { const interruptedRenames = interruptedRenamesMap.get(oldPath); if (interruptedRenames) { interruptedRenamesMap.delete(oldPath); for (const interruptedRename of interruptedRenames) { await handleRenameAsync(app, interruptedRename.oldPath, newPath, oldPathBacklinksMap, oldPathLinks, interruptedRename.combinedBacklinksMap); } } } async function fillRenameMap(app, oldPath, newPath, renameMap, oldPathLinks) { renameMap.set(oldPath, newPath); if (!isNoteEx(app, oldPath)) { return; } const settings = getSettings(app); const oldAttachmentFolderPath = await (0, import_AttachmentPath.getAttachmentFolderPath)(app, oldPath); const newAttachmentFolderPath = settings.shouldRenameAttachmentFolder ? await (0, import_AttachmentPath.getAttachmentFolderPath)(app, newPath) : oldAttachmentFolderPath; const isOldAttachmentFolderAtRoot = oldAttachmentFolderPath === "/"; const oldAttachmentFolder = (0, import_FileSystem.getFolderOrNull)(app, oldAttachmentFolderPath); if (!oldAttachmentFolder) { return; } if (oldAttachmentFolderPath === newAttachmentFolderPath && !settings.shouldRenameAttachmentFiles) { return; } const oldAttachmentFiles = []; if (await (0, import_AttachmentPath.hasOwnAttachmentFolder)(app, oldPath)) { import_obsidian.Vault.recurseChildren(oldAttachmentFolder, (oldAttachmentFile) => { if ((0, import_FileSystem.isFile)(oldAttachmentFile)) { oldAttachmentFiles.push(oldAttachmentFile); } }); } else { for (const oldPathLink of oldPathLinks) { const oldAttachmentFile = (0, import_Link.extractLinkFile)(app, oldPathLink, oldPath); if (!oldAttachmentFile) { continue; } if (isOldAttachmentFolderAtRoot || oldAttachmentFile.path.startsWith(oldAttachmentFolderPath)) { const oldAttachmentBacklinks = await (0, import_MetadataCache.getBacklinksForFileSafe)(app, oldAttachmentFile); if (oldAttachmentBacklinks.keys().length === 1) { oldAttachmentFiles.push(oldAttachmentFile); } } } } const oldBasename = (0, import_Path.basename)(oldPath, (0, import_Path.extname)(oldPath)); const newBasename = (0, import_Path.basename)(newPath, (0, import_Path.extname)(newPath)); for (const oldAttachmentFile of oldAttachmentFiles) { if (isNoteEx(app, oldAttachmentFile.path)) { continue; } const relativePath = isOldAttachmentFolderAtRoot ? oldAttachmentFile.path : (0, import_Path.relative)(oldAttachmentFolderPath, oldAttachmentFile.path); const newFolder = (0, import_Path.join)(newAttachmentFolderPath, (0, import_Path.dirname)(relativePath)); const newChildBasename = settings.shouldRenameAttachmentFiles ? (0, import_String.replaceAll)(oldAttachmentFile.basename, oldBasename, newBasename) : oldAttachmentFile.basename; let newChildPath = (0, import_Path.join)(newFolder, (0, import_Path.makeFileName)(newChildBasename, oldAttachmentFile.extension)); if (oldAttachmentFile.path === newChildPath) { continue; } if (settings.shouldDeleteConflictingAttachments) { const newChildFile = (0, import_FileSystem.getFileOrNull)(app, newChildPath); if (newChildFile) { console.warn(`Removing conflicting attachment ${newChildFile.path}.`); await app.fileManager.trashFile(newChildFile); } } else { newChildPath = app.vault.getAvailablePath((0, import_Path.join)(newFolder, newChildBasename), oldAttachmentFile.extension); } renameMap.set(oldAttachmentFile.path, newChildPath); } } function getRenameDeleteHandlersMap(app) { return (0, import_App.getObsidianDevUtilsState)(app, "renameDeleteHandlersMap", /* @__PURE__ */ new Map()).value; } function getSettings(app) { const renameDeleteHandlersMap = getRenameDeleteHandlersMap(app); const settingsBuilders = Array.from(renameDeleteHandlersMap.values()).reverse(); const settings = {}; settings.isNote = (path) => (0, import_FileSystem.isNote)(app, path); settings.isPathIgnored = () => false; for (const settingsBuilder of settingsBuilders) { const newSettings = settingsBuilder(); settings.shouldDeleteConflictingAttachments ||= newSettings.shouldDeleteConflictingAttachments ?? false; if (newSettings.emptyAttachmentFolderBehavior) { settings.emptyAttachmentFolderBehavior ??= newSettings.emptyAttachmentFolderBehavior; } settings.shouldHandleDeletions ||= newSettings.shouldHandleDeletions ?? false; settings.shouldHandleRenames ||= newSettings.shouldHandleRenames ?? false; settings.shouldRenameAttachmentFiles ||= newSettings.shouldRenameAttachmentFiles ?? false; settings.shouldRenameAttachmentFolder ||= newSettings.shouldRenameAttachmentFolder ?? false; settings.shouldUpdateFileNameAliases ||= newSettings.shouldUpdateFileNameAliases ?? false; const isPathIgnored = settings.isPathIgnored; settings.isPathIgnored = (path) => isPathIgnored(path) || (newSettings.isPathIgnored?.(path) ?? false); const currentIsNote = settings.isNote; settings.isNote = (path) => currentIsNote(path) && (newSettings.isNote?.(path) ?? true); } settings.emptyAttachmentFolderBehavior ??= "Keep" /* Keep */; return settings; } async function handleCaseCollision(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks) { if (!app.vault.adapter.insensitive || oldPath.toLowerCase() !== newPath.toLowerCase()) { return false; } const tempPath = (0, import_Path.join)((0, import_Path.dirname)(newPath), `__temp__${(0, import_Path.basename)(newPath)}`); await renameHandled(app, newPath, tempPath); await handleRenameAsync(app, oldPath, tempPath, oldPathBacklinksMap, oldPathLinks); await app.vault.rename((0, import_FileSystem.getFile)(app, tempPath), newPath); return true; } async function handleDelete(app, path) { (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleDelete")(`Handle Delete ${path}`); if (!isNoteEx(app, path)) { return; } const settings = getSettings(app); if (!settings.shouldHandleDeletions) { return; } if (settings.isPathIgnored?.(path)) { console.warn(`Skipping delete handler of ${path} as the path is ignored.`); return; } const cache = deletedMetadataCacheMap.get(path); deletedMetadataCacheMap.delete(path); const parentFolderPaths = /* @__PURE__ */ new Set(); if (cache) { const links = (0, import_MetadataCache.getAllLinks)(cache); for (const link of links) { const attachmentFile = (0, import_Link.extractLinkFile)(app, link, path); if (!attachmentFile) { continue; } if (isNoteEx(app, attachmentFile.path)) { continue; } parentFolderPaths.add(attachmentFile.parent?.path ?? ""); await (0, import_VaultEx.deleteSafe)(app, attachmentFile, path, false, settings.emptyAttachmentFolderBehavior !== "Keep" /* Keep */); } } await cleanupParentFolders(app, Array.from(parentFolderPaths), path); const attachmentFolderPath = await (0, import_AttachmentPath.getAttachmentFolderPath)(app, path); const attachmentFolder = (0, import_FileSystem.getFolderOrNull)(app, attachmentFolderPath); if (!attachmentFolder) { return; } if (!await (0, import_AttachmentPath.hasOwnAttachmentFolder)(app, path)) { return; } await (0, import_VaultEx.deleteSafe)(app, attachmentFolder, path, false, settings.emptyAttachmentFolderBehavior !== "Keep" /* Keep */); } function handleDeleteIfEnabled(plugin, file) { const app = plugin.app; if (!shouldInvokeHandler(plugin)) { return; } const path = file.path; (0, import_Queue.addToQueue)(app, () => handleDelete(app, path)); } function handleMetadataDeleted(app, file, prevCache) { const settings = getSettings(app); if (settings.isPathIgnored?.(file.path)) { console.warn(`Skipping metadata delete handler of ${file.path} as the path is ignored.`); return; } if (!settings.shouldHandleDeletions) { return; } if ((0, import_FileSystem.isMarkdownFile)(app, file) && prevCache) { deletedMetadataCacheMap.set(file.path, prevCache); } } function handleMetadataDeletedIfEnabled(plugin, file, prevCache) { if (!shouldInvokeHandler(plugin)) { return; } handleMetadataDeleted(plugin.app, file, prevCache); } function handleRename(app, oldPath, newPath) { const key = makeKey(oldPath, newPath); (0, import_Debug.getLibDebugger)("RenameDeleteHandler:handleRename")(`Handle Rename ${key}`); if (handledRenames.has(key)) { handledRenames.delete(key); return; } const settings = getSettings(app); if (!settings.shouldHandleRenames) { return; } if (settings.isPathIgnored?.(oldPath)) { console.warn(`Skipping rename handler of old path ${oldPath} as the path is ignored.`); return; } if (settings.isPathIgnored?.(newPath)) { console.warn(`Skipping rename handler of new path ${newPath} as the path is ignored.`); return; } const cache = app.metadataCache.getCache(oldPath) ?? app.metadataCache.getCache(newPath); const oldPathLinks = cache ? (0, import_MetadataCache.getAllLinks)(cache) : []; const oldPathBacklinksMap = (0, import_MetadataCache.getBacklinksForFileOrPath)(app, oldPath).data; (0, import_Queue.addToQueue)(app, () => handleRenameAsync(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks)); } async function handleRenameAsync(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks, interruptedCombinedBacklinksMap) { await continueInterruptedRenames(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks); await refreshLinks(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks); if (await handleCaseCollision(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks)) { return; } try { const renameMap = /* @__PURE__ */ new Map(); await fillRenameMap(app, oldPath, newPath, renameMap, oldPathLinks); const combinedBacklinksMap = /* @__PURE__ */ new Map(); initBacklinksMap(oldPathBacklinksMap, renameMap, combinedBacklinksMap, oldPath); for (const attachmentOldPath of renameMap.keys()) { if (attachmentOldPath === oldPath) { continue; } const attachmentOldPathBacklinksMap = (await (0, import_MetadataCache.getBacklinksForFileSafe)(app, attachmentOldPath)).data; initBacklinksMap(attachmentOldPathBacklinksMap, renameMap, combinedBacklinksMap, attachmentOldPath); } const parentFolderPaths = /* @__PURE__ */ new Set(); for (const [oldAttachmentPath, newAttachmentPath] of renameMap.entries()) { if (oldAttachmentPath === oldPath) { continue; } const fixedNewAttachmentPath = await renameHandled(app, oldAttachmentPath, newAttachmentPath); renameMap.set(oldAttachmentPath, fixedNewAttachmentPath); parentFolderPaths.add((0, import_Path.dirname)(oldAttachmentPath)); } await cleanupParentFolders(app, Array.from(parentFolderPaths), oldPath); const settings = getSettings(app); for (const [newBacklinkPath, linkJsonToPathMap] of Array.from(combinedBacklinksMap.entries()).concat( Array.from(interruptedCombinedBacklinksMap?.entries() ?? []) )) { await (0, import_Link.editLinks)(app, newBacklinkPath, (link) => { const oldAttachmentPath = linkJsonToPathMap.get((0, import_ObjectUtils.toJson)(link)); if (!oldAttachmentPath) { return; } const newAttachmentPath = renameMap.get(oldAttachmentPath); if (!newAttachmentPath) { return; } return (0, import_Link.updateLink)((0, import_ObjectUtils.normalizeOptionalProperties)({ app, link, newSourcePathOrFile: newBacklinkPath, newTargetPathOrFile: newAttachmentPath, oldTargetPathOrFile: oldAttachmentPath, shouldUpdateFileNameAlias: settings.shouldUpdateFileNameAliases })); }, { shouldFailOnMissingFile: false }); } if (isNoteEx(app, newPath)) { await (0, import_Link.updateLinksInFile)((0, import_ObjectUtils.normalizeOptionalProperties)({ app, newSourcePathOrFile: newPath, oldSourcePathOrFile: oldPath, shouldFailOnMissingFile: false, shouldUpdateFileNameAlias: settings.shouldUpdateFileNameAliases })); } if (!(0, import_FileSystem.getFileOrNull)(app, newPath)) { let interruptedRenames = interruptedRenamesMap.get(newPath); if (!interruptedRenames) { interruptedRenames = []; interruptedRenamesMap.set(newPath, interruptedRenames); } interruptedRenames.push({ combinedBacklinksMap, oldPath }); } } finally { const orphanKeys = Array.from(handledRenames); (0, import_Queue.addToQueue)(app, () => { for (const key of orphanKeys) { handledRenames.delete(key); } }); } } function handleRenameIfEnabled(plugin, file, oldPath) { if (!shouldInvokeHandler(plugin)) { return; } if (!(0, import_FileSystem.isFile)(file)) { return; } const newPath = file.path; handleRename(plugin.app, oldPath, newPath); } function initBacklinksMap(singleBacklinksMap, renameMap, combinedBacklinksMap, path) { for (const [backlinkPath, links] of singleBacklinksMap.entries()) { const newBacklinkPath = renameMap.get(backlinkPath) ?? backlinkPath; const linkJsonToPathMap = combinedBacklinksMap.get(newBacklinkPath) ?? /* @__PURE__ */ new Map(); combinedBacklinksMap.set(newBacklinkPath, linkJsonToPathMap); for (const link of links) { linkJsonToPathMap.set((0, import_ObjectUtils.toJson)(link), path); } } } function isNoteEx(app, path) { const settings = getSettings(app); return settings.isNote?.(path) ?? false; } function logRegisteredHandlers(app) { const renameDeleteHandlersMap = getRenameDeleteHandlersMap(app); (0, import_Debug.getLibDebugger)("RenameDeleteHandler:logRegisteredHandlers")( `Plugins with registered rename/delete handlers: ${JSON.stringify(Array.from(renameDeleteHandlersMap.keys()))}` ); } function makeKey(oldPath, newPath) { return `${oldPath} -> ${newPath}`; } async function refreshLinks(app, oldPath, newPath, oldPathBacklinksMap, oldPathLinks) { const cache = app.metadataCache.getCache(oldPath) ?? app.metadataCache.getCache(newPath); const oldPathLinksRefreshed = cache ? (0, import_MetadataCache.getAllLinks)(cache) : []; const fakeOldFile = (0, import_FileSystem.getFile)(app, oldPath, true); let oldPathBacklinksMapRefreshed = /* @__PURE__ */ new Map(); await (0, import_MetadataCache.tempRegisterFilesAndRun)(app, [fakeOldFile], async () => { oldPathBacklinksMapRefreshed = (await (0, import_MetadataCache.getBacklinksForFileSafe)(app, fakeOldFile)).data; }); for (const link of oldPathLinksRefreshed) { if (oldPathLinks.includes(link)) { continue; } oldPathLinks.push(link); } for (const [backlinkPath, refreshedLinks] of oldPathBacklinksMapRefreshed.entries()) { let oldLinks = oldPathBacklinksMap.get(backlinkPath); if (!oldLinks) { oldLinks = []; oldPathBacklinksMap.set(backlinkPath, oldLinks); } for (const link of refreshedLinks) { if (oldLinks.includes(link)) { continue; } oldLinks.push(link); } } } async function renameHandled(app, oldPath, newPath) { newPath = (0, import_Vault.getSafeRenamePath)(app, oldPath, newPath); if (oldPath === newPath) { return newPath; } const key = makeKey(oldPath, newPath); handledRenames.add(key); newPath = await (0, import_Vault.renameSafe)(app, oldPath, newPath); return newPath; } async function runAsyncLinkUpdate(app, next, linkUpdatesHandler) { await next.call(app.fileManager, wrappedHandler); async function wrappedHandler(linkUpdates) { let isRenameCalled = false; const eventRef = app.vault.on("rename", () => { isRenameCalled = true; }); try { await linkUpdatesHandler(linkUpdates); } finally { app.vault.offref(eventRef); } const settings = getSettings(app); if (isRenameCalled && settings.shouldHandleRenames) { (0, import_Array.filterInPlace)( linkUpdates, (linkUpdate) => { if (settings.isPathIgnored?.(linkUpdate.sourceFile.path)) { console.warn(`Roll back to default link update of source file ${linkUpdate.sourceFile.path} as the path is ignored.`); return true; } if (settings.isPathIgnored?.(linkUpdate.resolvedFile.path)) { console.warn(`Roll back to default link update of resolved file ${linkUpdate.resolvedFile.path} as the path is ignored.`); return true; } if (!app.internalPlugins.getEnabledPluginById(import_implementations.InternalPluginName.Canvas)) { return false; } if (app.plugins.getPlugin("backlink-cache")) { return false; } if (linkUpdate.sourceFile.extension === "canvas") { return true; } if (linkUpdate.resolvedFile.extension === "canvas") { return true; } return false; } ); } } } function shouldInvokeHandler(plugin) { const app = plugin.app; const pluginId = plugin.manifest.id; const renameDeleteHandlerPluginIds = getRenameDeleteHandlersMap(app); const mainPluginId = Array.from(renameDeleteHandlerPluginIds.keys())[0]; if (mainPluginId !== pluginId) { return false; } return true; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { EmptyAttachmentFolderBehavior, registerRenameDeleteHandlers }); //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL1JlbmFtZURlbGV0ZUhhbmRsZXIudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKlxuICogQ29udGFpbnMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIGhhbmRsaW5nIHJlbmFtZSBhbmQgZGVsZXRlIGV2ZW50cyBpbiBPYnNpZGlhbi5cbiAqL1xuXG5pbXBvcnQgdHlwZSB7XG4gIEFwcCxcbiAgQ2FjaGVkTWV0YWRhdGEsXG4gIEZpbGVNYW5hZ2VyLFxuICBQbHVnaW4sXG4gIFJlZmVyZW5jZSxcbiAgVEFic3RyYWN0RmlsZSxcbiAgVEZpbGVcbn0gZnJvbSAnb2JzaWRpYW4nO1xuaW1wb3J0IHR5cGUge1xuICBMaW5rVXBkYXRlLFxuICBMaW5rVXBkYXRlc0hhbmRsZXJcbn0gZnJvbSAnb2JzaWRpYW4tdHlwaW5ncyc7XG5cbmltcG9ydCB7IFZhdWx0IH0gZnJvbSAnb2JzaWRpYW4nO1xuaW1wb3J0IHsgSW50ZXJuYWxQbHVnaW5OYW1lIH0gZnJvbSAnb2JzaWRpYW4tdHlwaW5ncy9pbXBsZW1lbnRhdGlvbnMnO1xuXG5pbXBvcnQgdHlwZSB7XG4gIFVwZGF0ZUxpbmtPcHRpb25zLFxuICBVcGRhdGVMaW5rc0luRmlsZU9wdGlvbnNcbn0gZnJvbSAnLi9MaW5rLnRzJztcblxuaW1wb3J0IHsgZmlsdGVySW5QbGFjZSB9IGZyb20gJy4uL0FycmF5LnRzJztcbmltcG9ydCB7IGdldExpYkRlYnVnZ2VyIH0gZnJvbSAnLi4vRGVidWcudHMnO1xuaW1wb3J0IHtcbiAgbm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzLFxuICB0b0pzb25cbn0gZnJvbSAnLi4vT2JqZWN0VXRpbHMudHMnO1xuaW1wb3J0IHtcbiAgYmFzZW5hbWUsXG4gIGRpcm5hbWUsXG4gIGV4dG5hbWUsXG4gIGpvaW4sXG4gIG1ha2VGaWxlTmFtZSxcbiAgcmVsYXRpdmVcbn0gZnJvbSAnLi4vUGF0aC50cyc7XG5pbXBvcnQgeyByZXBsYWNlQWxsIH0gZnJvbSAnLi4vU3RyaW5nLnRzJztcbmltcG9ydCB7IGdldE9ic2lkaWFuRGV2VXRpbHNTdGF0ZSB9IGZyb20gJy4vQXBwLnRzJztcbmltcG9ydCB7XG4gIGdldEF0dGFjaG1lbnRGb2xkZXJQYXRoLFxuICBoYXNPd25BdHRhY2htZW50Rm9sZGVyXG59IGZyb20gJy4vQXR0YWNobWVudFBhdGgudHMnO1xuaW1wb3J0IHtcbiAgZ2V0RmlsZSxcbiAgZ2V0RmlsZU9yTnVsbCxcbiAgZ2V0Rm9sZGVyT3JOdWxsLFxuICBpc0ZpbGUsXG4gIGlzTWFya2Rvd25GaWxlLFxuICBpc05vdGVcbn0gZnJvbSAnLi9GaWxlU3lzdGVtLnRzJztcbmltcG9ydCB7XG4gIGVkaXRMaW5rcyxcbiAgZXh0cmFjdExpbmtGaWxlLFxuICB1cGRhdGVMaW5rLFxuICB1cGRhdGVMaW5rc0luRmlsZVxufSBmcm9tICcuL0xpbmsudHMnO1xuaW1wb3J0IHtcbiAgZ2V0QWxsTGlua3MsXG4gIGdldEJhY2tsaW5rc0ZvckZpbGVPclBhdGgsXG4gIGdldEJhY2tsaW5rc0ZvckZpbGVTYWZlLFxuICB0ZW1wUmVnaXN0ZXJGaWxlc0FuZFJ1blxufSBmcm9tICcuL01ldGFkYXRhQ2FjaGUudHMnO1xuaW1wb3J0IHsgcmVnaXN0ZXJQYXRjaCB9IGZyb20gJy4vTW9ua2V5QXJvdW5kLnRzJztcbmltcG9ydCB7IGFkZFRvUXVldWUgfSBmcm9tICcuL1F1ZXVlLnRzJztcbmltcG9ydCB7XG4gIGdldFNhZmVSZW5hbWVQYXRoLFxuICByZW5hbWVTYWZlXG59IGZyb20gJy4vVmF1bHQudHMnO1xuaW1wb3J0IHtcbiAgZGVsZXRlRW1wdHlGb2xkZXJIaWVyYXJjaHksXG4gIGRlbGV0ZVNhZmVcbn0gZnJvbSAnLi9WYXVsdEV4LnRzJztcblxuY29uc3QgZGVsZXRlZE1ldGFkYXRhQ2FjaGVNYXAgPSBuZXcgTWFwPHN0cmluZywgQ2FjaGVkTWV0YWRhdGE+KCk7XG5jb25zdCBoYW5kbGVkUmVuYW1lcyA9IG5ldyBTZXQ8c3RyaW5nPigpO1xuY29uc3QgaW50ZXJydXB0ZWRSZW5hbWVzTWFwID0gbmV3IE1hcDxzdHJpbmcsIEludGVycnVwdGVkUmVuYW1lW10+KCk7XG5cbi8qKlxuICogVGhlIGJlaGF2aW9yIG9mIHRoZSByZW5hbWUvZGVsZXRlIGhhbmRsZXIgd2hlbiBkZWxldGluZyBlbXB0eSBhdHRhY2htZW50IGZvbGRlcnMuXG4gKi9cbmV4cG9ydCBlbnVtIEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yIHtcbiAgLyoqXG4gICAqIERlbGV0ZSB0aGUgZW1wdHkgYXR0YWNobWVudCBmb2xkZXIuXG4gICAqL1xuICBEZWxldGUgPSAnRGVsZXRlJyxcblxuICAvKipcbiAgICogRGVsZXRlIHRoZSBlbXB0eSBhdHRhY2htZW50IGZvbGRlciBhbmQgYWxsIGl0cyBlbXB0eSBwYXJlbnRzLlxuICAgKi9cbiAgRGVsZXRlV2l0aEVtcHR5UGFyZW50cyA9ICdEZWxldGVXaXRoRW1wdHlQYXJlbnRzJyxcblxuICAvKipcbiAgICogS2VlcCB0aGUgZW1wdHkgYXR0YWNobWVudCBmb2xkZXIuXG4gICAqL1xuICBLZWVwID0gJ0tlZXAnXG59XG5cbi8qKlxuICogU2V0dGluZ3MgZm9yIHRoZSByZW5hbWUvZGVsZXRlIGhhbmRsZXIuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgUmVuYW1lRGVsZXRlSGFuZGxlclNldHRpbmdzIHtcbiAgLyoqXG4gICAqIFRoZSBiZWhhdmlvciBvZiB0aGUgcmVuYW1lL2RlbGV0ZSBoYW5kbGVyIHdoZW4gZGVsZXRpbmcgZW1wdHkgYXR0YWNobWVudCBmb2xkZXJzLlxuICAgKi9cbiAgZW1wdHlBdHRhY2htZW50Rm9sZGVyQmVoYXZpb3I6IEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRoZSBwYXRoIGlzIGEgbm90ZS5cbiAgICovXG4gIGlzTm90ZShwYXRoOiBzdHJpbmcpOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGlnbm9yZSB0aGUgcGF0aC5cbiAgICovXG4gIGlzUGF0aElnbm9yZWQocGF0aDogc3RyaW5nKTogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBkZWxldGUgY29uZmxpY3RpbmcgYXR0YWNobWVudHMuXG4gICAqL1xuICBzaG91bGREZWxldGVDb25mbGljdGluZ0F0dGFjaG1lbnRzOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGhhbmRsZSBkZWxldGlvbnMuXG4gICAqL1xuICBzaG91bGRIYW5kbGVEZWxldGlvbnM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gaGFuZGxlIHJlbmFtZXMuXG4gICAqL1xuICBzaG91bGRIYW5kbGVSZW5hbWVzOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHJlbmFtZSBhdHRhY2htZW50IGZpbGVzIHdoZW4gYSBub3RlIGlzIHJlbmFtZWQuXG4gICAqL1xuICBzaG91bGRSZW5hbWVBdHRhY2htZW50RmlsZXM6IGJvb2xlYW47XG5cbiAgLyoqXG4gICAqIFdoZXRoZXIgdG8gcmVuYW1lIGF0dGFjaG1lbnQgZm9sZGVyIHdoZW4gYSBub3RlIGlzIHJlbmFtZWQuXG4gICAqL1xuICBzaG91bGRSZW5hbWVBdHRhY2htZW50Rm9sZGVyOiBib29sZWFuO1xuXG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIHVwZGF0ZSBmaWxlIG5hbWUgYWxpYXNlcyB3aGVuIGEgbm90ZSBpcyByZW5hbWVkLlxuICAgKi9cbiAgc2hvdWxkVXBkYXRlRmlsZU5hbWVBbGlhc2VzOiBib29sZWFuO1xufVxuXG5pbnRlcmZhY2UgSW50ZXJydXB0ZWRSZW5hbWUge1xuICBjb21iaW5lZEJhY2tsaW5rc01hcDogTWFwPHN0cmluZywgTWFwPHN0cmluZywgc3RyaW5nPj47XG4gIG9sZFBhdGg6IHN0cmluZztcbn1cblxudHlwZSBSdW5Bc3luY0xpbmtVcGRhdGVGbiA9IEZpbGVNYW5hZ2VyWydydW5Bc3luY0xpbmtVcGRhdGUnXTtcblxuLyoqXG4gKiBSZWdpc3RlcnMgdGhlIHJlbmFtZS9kZWxldGUgaGFuZGxlcnMuXG4gKlxuICogQHBhcmFtIHBsdWdpbiAtIFRoZSBwbHVnaW4gaW5zdGFuY2UuXG4gKiBAcGFyYW0gc2V0dGluZ3NCdWlsZGVyIC0gQSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIHNldHRpbmdzIGZvciB0aGUgcmVuYW1lIGRlbGV0ZSBoYW5kbGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gcmVnaXN0ZXJSZW5hbWVEZWxldGVIYW5kbGVycyhwbHVnaW46IFBsdWdpbiwgc2V0dGluZ3NCdWlsZGVyOiAoKSA9PiBQYXJ0aWFsPFJlbmFtZURlbGV0ZUhhbmRsZXJTZXR0aW5ncz4pOiB2b2lkIHtcbiAgY29uc3QgcmVuYW1lRGVsZXRlSGFuZGxlcnNNYXAgPSBnZXRSZW5hbWVEZWxldGVIYW5kbGVyc01hcChwbHVnaW4uYXBwKTtcbiAgY29uc3QgcGx1Z2luSWQgPSBwbHVnaW4ubWFuaWZlc3QuaWQ7XG5cbiAgcmVuYW1lRGVsZXRlSGFuZGxlcnNNYXAuc2V0KHBsdWdpbklkLCBzZXR0aW5nc0J1aWxkZXIpO1xuICBsb2dSZWdpc3RlcmVkSGFuZGxlcnMocGx1Z2luLmFwcCk7XG5cbiAgcGx1Z2luLnJlZ2lzdGVyKCgpID0+IHtcbiAgICByZW5hbWVEZWxldGVIYW5kbGVyc01hcC5kZWxldGUocGx1Z2luSWQpO1xuICAgIGxvZ1JlZ2lzdGVyZWRIYW5kbGVycyhwbHVnaW4uYXBwKTtcbiAgfSk7XG5cbiAgY29uc3QgYXBwID0gcGx1Z2luLmFwcDtcbiAgcGx1Z2luLnJlZ2lzdGVyRXZlbnQoXG4gICAgYXBwLnZhdWx0Lm9uKCdkZWxldGUnLCAoZmlsZSkgPT4ge1xuICAgICAgaGFuZGxlRGVsZXRlSWZFbmFibGVkKHBsdWdpbiwgZmlsZSk7XG4gICAgfSlcbiAgKTtcblxuICBwbHVnaW4ucmVnaXN0ZXJFdmVudChcbiAgICBhcHAudmF1bHQub24oJ3JlbmFtZScsIChmaWxlLCBvbGRQYXRoKSA9PiB7XG4gICAgICBoYW5kbGVSZW5hbWVJZkVuYWJsZWQocGx1Z2luLCBmaWxlLCBvbGRQYXRoKTtcbiAgICB9KVxuICApO1xuXG4gIHBsdWdpbi5yZWdpc3RlckV2ZW50KFxuICAgIGFwcC5tZXRhZGF0YUNhY2hlLm9uKCdkZWxldGVkJywgKGZpbGUsIHByZXZDYWNoZSkgPT4ge1xuICAgICAgaGFuZGxlTWV0YWRhdGFEZWxldGVkSWZFbmFibGVkKHBsdWdpbiwgZmlsZSwgcHJldkNhY2hlKTtcbiAgICB9KVxuICApO1xuXG4gIHJlZ2lzdGVyUGF0Y2gocGx1Z2luLCBhcHAuZmlsZU1hbmFnZXIsIHtcbiAgICBydW5Bc3luY0xpbmtVcGRhdGU6IChuZXh0OiBSdW5Bc3luY0xpbmtVcGRhdGVGbik6IFJ1bkFzeW5jTGlua1VwZGF0ZUZuID0+IHtcbiAgICAgIHJldHVybiAobGlua1VwZGF0ZXNIYW5kbGVyKSA9PiBydW5Bc3luY0xpbmtVcGRhdGUoYXBwLCBuZXh0LCBsaW5rVXBkYXRlc0hhbmRsZXIpO1xuICAgIH1cbiAgfSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNsZWFudXBQYXJlbnRGb2xkZXJzKGFwcDogQXBwLCBwYXJlbnRGb2xkZXJQYXRoczogc3RyaW5nW10sIG5vdGVQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3Qgc2V0dGluZ3MgPSBnZXRTZXR0aW5ncyhhcHApO1xuICBpZiAoc2V0dGluZ3MuZW1wdHlBdHRhY2htZW50Rm9sZGVyQmVoYXZpb3IgPT09IEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yLktlZXApIHtcbiAgICByZXR1cm47XG4gIH1cbiAgZm9yIChjb25zdCBwYXJlbnRGb2xkZXJQYXRoIG9mIHBhcmVudEZvbGRlclBhdGhzKSB7XG4gICAgc3dpdGNoIChzZXR0aW5ncy5lbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvcikge1xuICAgICAgY2FzZSBFbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvci5EZWxldGU6XG4gICAgICAgIGF3YWl0IGRlbGV0ZVNhZmUoYXBwLCBwYXJlbnRGb2xkZXJQYXRoLCBub3RlUGF0aCwgdW5kZWZpbmVkLCB0cnVlKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yLkRlbGV0ZVdpdGhFbXB0eVBhcmVudHM6XG4gICAgICAgIGF3YWl0IGRlbGV0ZUVtcHR5Rm9sZGVySGllcmFyY2h5KGFwcCwgcGFyZW50Rm9sZGVyUGF0aCk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgZGVmYXVsdDpcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGNvbnRpbnVlSW50ZXJydXB0ZWRSZW5hbWVzKFxuICBhcHA6IEFwcCxcbiAgb2xkUGF0aDogc3RyaW5nLFxuICBuZXdQYXRoOiBzdHJpbmcsXG4gIG9sZFBhdGhCYWNrbGlua3NNYXA6IE1hcDxzdHJpbmcsIFJlZmVyZW5jZVtdPixcbiAgb2xkUGF0aExpbmtzOiBSZWZlcmVuY2VbXVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGludGVycnVwdGVkUmVuYW1lcyA9IGludGVycnVwdGVkUmVuYW1lc01hcC5nZXQob2xkUGF0aCk7XG4gIGlmIChpbnRlcnJ1cHRlZFJlbmFtZXMpIHtcbiAgICBpbnRlcnJ1cHRlZFJlbmFtZXNNYXAuZGVsZXRlKG9sZFBhdGgpO1xuICAgIGZvciAoY29uc3QgaW50ZXJydXB0ZWRSZW5hbWUgb2YgaW50ZXJydXB0ZWRSZW5hbWVzKSB7XG4gICAgICBhd2FpdCBoYW5kbGVSZW5hbWVBc3luYyhhcHAsIGludGVycnVwdGVkUmVuYW1lLm9sZFBhdGgsIG5ld1BhdGgsIG9sZFBhdGhCYWNrbGlua3NNYXAsIG9sZFBhdGhMaW5rcywgaW50ZXJydXB0ZWRSZW5hbWUuY29tYmluZWRCYWNrbGlua3NNYXApO1xuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBmaWxsUmVuYW1lTWFwKGFwcDogQXBwLCBvbGRQYXRoOiBzdHJpbmcsIG5ld1BhdGg6IHN0cmluZywgcmVuYW1lTWFwOiBNYXA8c3RyaW5nLCBzdHJpbmc+LCBvbGRQYXRoTGlua3M6IFJlZmVyZW5jZVtdKTogUHJvbWlzZTx2b2lkPiB7XG4gIHJlbmFtZU1hcC5zZXQob2xkUGF0aCwgbmV3UGF0aCk7XG5cbiAgaWYgKCFpc05vdGVFeChhcHAsIG9sZFBhdGgpKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qgc2V0dGluZ3MgPSBnZXRTZXR0aW5ncyhhcHApO1xuXG4gIGNvbnN0IG9sZEF0dGFjaG1lbnRGb2xkZXJQYXRoID0gYXdhaXQgZ2V0QXR0YWNobWVudEZvbGRlclBhdGgoYXBwLCBvbGRQYXRoKTtcbiAgY29uc3QgbmV3QXR0YWNobWVudEZvbGRlclBhdGggPSBzZXR0aW5ncy5zaG91bGRSZW5hbWVBdHRhY2htZW50Rm9sZGVyXG4gICAgPyBhd2FpdCBnZXRBdHRhY2htZW50Rm9sZGVyUGF0aChhcHAsIG5ld1BhdGgpXG4gICAgOiBvbGRBdHRhY2htZW50Rm9sZGVyUGF0aDtcblxuICBjb25zdCBpc09sZEF0dGFjaG1lbnRGb2xkZXJBdFJvb3QgPSBvbGRBdHRhY2htZW50Rm9sZGVyUGF0aCA9PT0gJy8nO1xuXG4gIGNvbnN0IG9sZEF0dGFjaG1lbnRGb2xkZXIgPSBnZXRGb2xkZXJPck51bGwoYXBwLCBvbGRBdHRhY2htZW50Rm9sZGVyUGF0aCk7XG5cbiAgaWYgKCFvbGRBdHRhY2htZW50Rm9sZGVyKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKG9sZEF0dGFjaG1lbnRGb2xkZXJQYXRoID09PSBuZXdBdHRhY2htZW50Rm9sZGVyUGF0aCAmJiAhc2V0dGluZ3Muc2hvdWxkUmVuYW1lQXR0YWNobWVudEZpbGVzKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qgb2xkQXR0YWNobWVudEZpbGVzOiBURmlsZVtdID0gW107XG5cbiAgaWYgKGF3YWl0IGhhc093bkF0dGFjaG1lbnRGb2xkZXIoYXBwLCBvbGRQYXRoKSkge1xuICAgIFZhdWx0LnJlY3Vyc2VDaGlsZHJlbihvbGRBdHRhY2htZW50Rm9sZGVyLCAob2xkQXR0YWNobWVudEZpbGUpID0+IHtcbiAgICAgIGlmIChpc0ZpbGUob2xkQXR0YWNobWVudEZpbGUpKSB7XG4gICAgICAgIG9sZEF0dGFjaG1lbnRGaWxlcy5wdXNoKG9sZEF0dGFjaG1lbnRGaWxlKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBmb3IgKGNvbnN0IG9sZFBhdGhMaW5rIG9mIG9sZFBhdGhMaW5rcykge1xuICAgICAgY29uc3Qgb2xkQXR0YWNobWVudEZpbGUgPSBleHRyYWN0TGlua0ZpbGUoYXBwLCBvbGRQYXRoTGluaywgb2xkUGF0aCk7XG4gICAgICBpZiAoIW9sZEF0dGFjaG1lbnRGaWxlKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNPbGRBdHRhY2htZW50Rm9sZGVyQXRSb290IHx8IG9sZEF0dGFjaG1lbnRGaWxlLnBhdGguc3RhcnRzV2l0aChvbGRBdHRhY2htZW50Rm9sZGVyUGF0aCkpIHtcbiAgICAgICAgY29uc3Qgb2xkQXR0YWNobWVudEJhY2tsaW5rcyA9IGF3YWl0IGdldEJhY2tsaW5rc0ZvckZpbGVTYWZlKGFwcCwgb2xkQXR0YWNobWVudEZpbGUpO1xuICAgICAgICBpZiAob2xkQXR0YWNobWVudEJhY2tsaW5rcy5rZXlzKCkubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgb2xkQXR0YWNobWVudEZpbGVzLnB1c2gob2xkQXR0YWNobWVudEZpbGUpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3Qgb2xkQmFzZW5hbWUgPSBiYXNlbmFtZShvbGRQYXRoLCBleHRuYW1lKG9sZFBhdGgpKTtcbiAgY29uc3QgbmV3QmFzZW5hbWUgPSBiYXNlbmFtZShuZXdQYXRoLCBleHRuYW1lKG5ld1BhdGgpKTtcblxuICBmb3IgKGNvbnN0IG9sZEF0dGFjaG1lbnRGaWxlIG9mIG9sZEF0dGFjaG1lbnRGaWxlcykge1xuICAgIGlmIChpc05vdGVFeChhcHAsIG9sZEF0dGFjaG1lbnRGaWxlLnBhdGgpKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG4gICAgY29uc3QgcmVsYXRpdmVQYXRoID0gaXNPbGRBdHRhY2htZW50Rm9sZGVyQXRSb290ID8gb2xkQXR0YWNobWVudEZpbGUucGF0aCA6IHJlbGF0aXZlKG9sZEF0dGFjaG1lbnRGb2xkZXJQYXRoLCBvbGRBdHRhY2htZW50RmlsZS5wYXRoKTtcbiAgICBjb25zdCBuZXdGb2xkZXIgPSBqb2luKG5ld0F0dGFjaG1lbnRGb2xkZXJQYXRoLCBkaXJuYW1lKHJlbGF0aXZlUGF0aCkpO1xuICAgIGNvbnN0IG5ld0NoaWxkQmFzZW5hbWUgPSBzZXR0aW5ncy5zaG91bGRSZW5hbWVBdHRhY2htZW50RmlsZXNcbiAgICAgID8gcmVwbGFjZUFsbChvbGRBdHRhY2htZW50RmlsZS5iYXNlbmFtZSwgb2xkQmFzZW5hbWUsIG5ld0Jhc2VuYW1lKVxuICAgICAgOiBvbGRBdHRhY2htZW50RmlsZS5iYXNlbmFtZTtcbiAgICBsZXQgbmV3Q2hpbGRQYXRoID0gam9pbihuZXdGb2xkZXIsIG1ha2VGaWxlTmFtZShuZXdDaGlsZEJhc2VuYW1lLCBvbGRBdHRhY2htZW50RmlsZS5leHRlbnNpb24pKTtcblxuICAgIGlmIChvbGRBdHRhY2htZW50RmlsZS5wYXRoID09PSBuZXdDaGlsZFBhdGgpIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIGlmIChzZXR0aW5ncy5zaG91bGREZWxldGVDb25mbGljdGluZ0F0dGFjaG1lbnRzKSB7XG4gICAgICBjb25zdCBuZXdDaGlsZEZpbGUgPSBnZXRGaWxlT3JOdWxsKGFwcCwgbmV3Q2hpbGRQYXRoKTtcbiAgICAgIGlmIChuZXdDaGlsZEZpbGUpIHtcbiAgICAgICAgY29uc29sZS53YXJuKGBSZW1vdmluZyBjb25mbGljdGluZyBhdHRhY2htZW50ICR7bmV3Q2hpbGRGaWxlLnBhdGh9LmApO1xuICAgICAgICBhd2FpdCBhcHAuZmlsZU1hbmFnZXIudHJhc2hGaWxlKG5ld0NoaWxkRmlsZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG5ld0NoaWxkUGF0aCA9IGFwcC52YXVsdC5nZXRBdmFpbGFibGVQYXRoKGpvaW4obmV3Rm9sZGVyLCBuZXdDaGlsZEJhc2VuYW1lKSwgb2xkQXR0YWNobWVudEZpbGUuZXh0ZW5zaW9uKTtcbiAgICB9XG4gICAgcmVuYW1lTWFwLnNldChvbGRBdHRhY2htZW50RmlsZS5wYXRoLCBuZXdDaGlsZFBhdGgpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGdldFJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwKGFwcDogQXBwKTogTWFwPHN0cmluZywgKCkgPT4gUGFydGlhbDxSZW5hbWVEZWxldGVIYW5kbGVyU2V0dGluZ3M+PiB7XG4gIHJldHVybiBnZXRPYnNpZGlhbkRldlV0aWxzU3RhdGUoYXBwLCAncmVuYW1lRGVsZXRlSGFuZGxlcnNNYXAnLCBuZXcgTWFwPHN0cmluZywgKCkgPT4gUGFydGlhbDxSZW5hbWVEZWxldGVIYW5kbGVyU2V0dGluZ3M+PigpKS52YWx1ZTtcbn1cblxuZnVuY3Rpb24gZ2V0U2V0dGluZ3MoYXBwOiBBcHApOiBQYXJ0aWFsPFJlbmFtZURlbGV0ZUhhbmRsZXJTZXR0aW5ncz4ge1xuICBjb25zdCByZW5hbWVEZWxldGVIYW5kbGVyc01hcCA9IGdldFJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwKGFwcCk7XG4gIGNvbnN0IHNldHRpbmdzQnVpbGRlcnMgPSBBcnJheS5mcm9tKHJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwLnZhbHVlcygpKS5yZXZlcnNlKCk7XG5cbiAgY29uc3Qgc2V0dGluZ3M6IFBhcnRpYWw8UmVuYW1lRGVsZXRlSGFuZGxlclNldHRpbmdzPiA9IHt9O1xuICBzZXR0aW5ncy5pc05vdGUgPSAocGF0aDogc3RyaW5nKTogYm9vbGVhbiA9PiBpc05vdGUoYXBwLCBwYXRoKTtcbiAgc2V0dGluZ3MuaXNQYXRoSWdub3JlZCA9ICgpOiBib29sZWFuID0+IGZhbHNlO1xuXG4gIGZvciAoY29uc3Qgc2V0dGluZ3NCdWlsZGVyIG9mIHNldHRpbmdzQnVpbGRlcnMpIHtcbiAgICBjb25zdCBuZXdTZXR0aW5ncyA9IHNldHRpbmdzQnVpbGRlcigpO1xuICAgIHNldHRpbmdzLnNob3VsZERlbGV0ZUNvbmZsaWN0aW5nQXR0YWNobWVudHMgfHw9IG5ld1NldHRpbmdzLnNob3VsZERlbGV0ZUNvbmZsaWN0aW5nQXR0YWNobWVudHMgPz8gZmFsc2U7XG4gICAgaWYgKG5ld1NldHRpbmdzLmVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yKSB7XG4gICAgICBzZXR0aW5ncy5lbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvciA/Pz0gbmV3U2V0dGluZ3MuZW1wdHlBdHRhY2htZW50Rm9sZGVyQmVoYXZpb3I7XG4gICAgfVxuICAgIHNldHRpbmdzLnNob3VsZEhhbmRsZURlbGV0aW9ucyB8fD0gbmV3U2V0dGluZ3Muc2hvdWxkSGFuZGxlRGVsZXRpb25zID8/IGZhbHNlO1xuICAgIHNldHRpbmdzLnNob3VsZEhhbmRsZVJlbmFtZXMgfHw9IG5ld1NldHRpbmdzLnNob3VsZEhhbmRsZVJlbmFtZXMgPz8gZmFsc2U7XG4gICAgc2V0dGluZ3Muc2hvdWxkUmVuYW1lQXR0YWNobWVudEZpbGVzIHx8PSBuZXdTZXR0aW5ncy5zaG91bGRSZW5hbWVBdHRhY2htZW50RmlsZXMgPz8gZmFsc2U7XG4gICAgc2V0dGluZ3Muc2hvdWxkUmVuYW1lQXR0YWNobWVudEZvbGRlciB8fD0gbmV3U2V0dGluZ3Muc2hvdWxkUmVuYW1lQXR0YWNobWVudEZvbGRlciA/PyBmYWxzZTtcbiAgICBzZXR0aW5ncy5zaG91bGRVcGRhdGVGaWxlTmFtZUFsaWFzZXMgfHw9IG5ld1NldHRpbmdzLnNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXNlcyA/PyBmYWxzZTtcbiAgICBjb25zdCBpc1BhdGhJZ25vcmVkID0gc2V0dGluZ3MuaXNQYXRoSWdub3JlZDtcbiAgICBzZXR0aW5ncy5pc1BhdGhJZ25vcmVkID0gKHBhdGg6IHN0cmluZyk6IGJvb2xlYW4gPT4gaXNQYXRoSWdub3JlZChwYXRoKSB8fCAobmV3U2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKHBhdGgpID8/IGZhbHNlKTtcbiAgICBjb25zdCBjdXJyZW50SXNOb3RlID0gc2V0dGluZ3MuaXNOb3RlO1xuICAgIHNldHRpbmdzLmlzTm90ZSA9IChwYXRoOiBzdHJpbmcpOiBib29sZWFuID0+IGN1cnJlbnRJc05vdGUocGF0aCkgJiYgKG5ld1NldHRpbmdzLmlzTm90ZT8uKHBhdGgpID8/IHRydWUpO1xuICB9XG5cbiAgc2V0dGluZ3MuZW1wdHlBdHRhY2htZW50Rm9sZGVyQmVoYXZpb3IgPz89IEVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yLktlZXA7XG4gIHJldHVybiBzZXR0aW5ncztcbn1cblxuYXN5bmMgZnVuY3Rpb24gaGFuZGxlQ2FzZUNvbGxpc2lvbihcbiAgYXBwOiBBcHAsXG4gIG9sZFBhdGg6IHN0cmluZyxcbiAgbmV3UGF0aDogc3RyaW5nLFxuICBvbGRQYXRoQmFja2xpbmtzTWFwOiBNYXA8c3RyaW5nLCBSZWZlcmVuY2VbXT4sXG4gIG9sZFBhdGhMaW5rczogUmVmZXJlbmNlW11cbik6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAoIWFwcC52YXVsdC5hZGFwdGVyLmluc2Vuc2l0aXZlIHx8IG9sZFBhdGgudG9Mb3dlckNhc2UoKSAhPT0gbmV3UGF0aC50b0xvd2VyQ2FzZSgpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgY29uc3QgdGVtcFBhdGggPSBqb2luKGRpcm5hbWUobmV3UGF0aCksIGBfX3RlbXBfXyR7YmFzZW5hbWUobmV3UGF0aCl9YCk7XG4gIGF3YWl0IHJlbmFtZUhhbmRsZWQoYXBwLCBuZXdQYXRoLCB0ZW1wUGF0aCk7XG4gIGF3YWl0IGhhbmRsZVJlbmFtZUFzeW5jKGFwcCwgb2xkUGF0aCwgdGVtcFBhdGgsIG9sZFBhdGhCYWNrbGlua3NNYXAsIG9sZFBhdGhMaW5rcyk7XG4gIGF3YWl0IGFwcC52YXVsdC5yZW5hbWUoZ2V0RmlsZShhcHAsIHRlbXBQYXRoKSwgbmV3UGF0aCk7XG4gIHJldHVybiB0cnVlO1xufVxuXG5hc3luYyBmdW5jdGlvbiBoYW5kbGVEZWxldGUoYXBwOiBBcHAsIHBhdGg6IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBnZXRMaWJEZWJ1Z2dlcignUmVuYW1lRGVsZXRlSGFuZGxlcjpoYW5kbGVEZWxldGUnKShgSGFuZGxlIERlbGV0ZSAke3BhdGh9YCk7XG4gIGlmICghaXNOb3RlRXgoYXBwLCBwYXRoKSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoYXBwKTtcbiAgaWYgKCFzZXR0aW5ncy5zaG91bGRIYW5kbGVEZWxldGlvbnMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKHBhdGgpKSB7XG4gICAgY29uc29sZS53YXJuKGBTa2lwcGluZyBkZWxldGUgaGFuZGxlciBvZiAke3BhdGh9IGFzIHRoZSBwYXRoIGlzIGlnbm9yZWQuYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3QgY2FjaGUgPSBkZWxldGVkTWV0YWRhdGFDYWNoZU1hcC5nZXQocGF0aCk7XG4gIGRlbGV0ZWRNZXRhZGF0YUNhY2hlTWFwLmRlbGV0ZShwYXRoKTtcbiAgY29uc3QgcGFyZW50Rm9sZGVyUGF0aHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgaWYgKGNhY2hlKSB7XG4gICAgY29uc3QgbGlua3MgPSBnZXRBbGxMaW5rcyhjYWNoZSk7XG5cbiAgICBmb3IgKGNvbnN0IGxpbmsgb2YgbGlua3MpIHtcbiAgICAgIGNvbnN0IGF0dGFjaG1lbnRGaWxlID0gZXh0cmFjdExpbmtGaWxlKGFwcCwgbGluaywgcGF0aCk7XG4gICAgICBpZiAoIWF0dGFjaG1lbnRGaWxlKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuXG4gICAgICBpZiAoaXNOb3RlRXgoYXBwLCBhdHRhY2htZW50RmlsZS5wYXRoKSkge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cblxuICAgICAgcGFyZW50Rm9sZGVyUGF0aHMuYWRkKGF0dGFjaG1lbnRGaWxlLnBhcmVudD8ucGF0aCA/PyAnJyk7XG4gICAgICBhd2FpdCBkZWxldGVTYWZlKGFwcCwgYXR0YWNobWVudEZpbGUsIHBhdGgsIGZhbHNlLCBzZXR0aW5ncy5lbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvciAhPT0gRW1wdHlBdHRhY2htZW50Rm9sZGVyQmVoYXZpb3IuS2VlcCk7XG4gICAgfVxuICB9XG5cbiAgYXdhaXQgY2xlYW51cFBhcmVudEZvbGRlcnMoYXBwLCBBcnJheS5mcm9tKHBhcmVudEZvbGRlclBhdGhzKSwgcGF0aCk7XG5cbiAgY29uc3QgYXR0YWNobWVudEZvbGRlclBhdGggPSBhd2FpdCBnZXRBdHRhY2htZW50Rm9sZGVyUGF0aChhcHAsIHBhdGgpO1xuICBjb25zdCBhdHRhY2htZW50Rm9sZGVyID0gZ2V0Rm9sZGVyT3JOdWxsKGFwcCwgYXR0YWNobWVudEZvbGRlclBhdGgpO1xuXG4gIGlmICghYXR0YWNobWVudEZvbGRlcikge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICghKGF3YWl0IGhhc093bkF0dGFjaG1lbnRGb2xkZXIoYXBwLCBwYXRoKSkpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBhd2FpdCBkZWxldGVTYWZlKGFwcCwgYXR0YWNobWVudEZvbGRlciwgcGF0aCwgZmFsc2UsIHNldHRpbmdzLmVtcHR5QXR0YWNobWVudEZvbGRlckJlaGF2aW9yICE9PSBFbXB0eUF0dGFjaG1lbnRGb2xkZXJCZWhhdmlvci5LZWVwKTtcbn1cblxuZnVuY3Rpb24gaGFuZGxlRGVsZXRlSWZFbmFibGVkKHBsdWdpbjogUGx1Z2luLCBmaWxlOiBUQWJzdHJhY3RGaWxlKTogdm9pZCB7XG4gIGNvbnN0IGFwcCA9IHBsdWdpbi5hcHA7XG4gIGlmICghc2hvdWxkSW52b2tlSGFuZGxlcihwbHVnaW4pKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IHBhdGggPSBmaWxlLnBhdGg7XG4gIGFkZFRvUXVldWUoYXBwLCAoKSA9PiBoYW5kbGVEZWxldGUoYXBwLCBwYXRoKSk7XG59XG5cbmZ1bmN0aW9uIGhhbmRsZU1ldGFkYXRhRGVsZXRlZChhcHA6IEFwcCwgZmlsZTogVEFic3RyYWN0RmlsZSwgcHJldkNhY2hlOiBDYWNoZWRNZXRhZGF0YSB8IG51bGwpOiB2b2lkIHtcbiAgY29uc3Qgc2V0dGluZ3MgPSBnZXRTZXR0aW5ncyhhcHApO1xuICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKGZpbGUucGF0aCkpIHtcbiAgICBjb25zb2xlLndhcm4oYFNraXBwaW5nIG1ldGFkYXRhIGRlbGV0ZSBoYW5kbGVyIG9mICR7ZmlsZS5wYXRofSBhcyB0aGUgcGF0aCBpcyBpZ25vcmVkLmApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGlmICghc2V0dGluZ3Muc2hvdWxkSGFuZGxlRGVsZXRpb25zKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmIChpc01hcmtkb3duRmlsZShhcHAsIGZpbGUpICYmIHByZXZDYWNoZSkge1xuICAgIGRlbGV0ZWRNZXRhZGF0YUNhY2hlTWFwLnNldChmaWxlLnBhdGgsIHByZXZDYWNoZSk7XG4gIH1cbn1cblxuZnVuY3Rpb24gaGFuZGxlTWV0YWRhdGFEZWxldGVkSWZFbmFibGVkKHBsdWdpbjogUGx1Z2luLCBmaWxlOiBUQWJzdHJhY3RGaWxlLCBwcmV2Q2FjaGU6IENhY2hlZE1ldGFkYXRhIHwgbnVsbCk6IHZvaWQge1xuICBpZiAoIXNob3VsZEludm9rZUhhbmRsZXIocGx1Z2luKSkge1xuICAgIHJldHVybjtcbiAgfVxuICBoYW5kbGVNZXRhZGF0YURlbGV0ZWQocGx1Z2luLmFwcCwgZmlsZSwgcHJldkNhY2hlKTtcbn1cblxuZnVuY3Rpb24gaGFuZGxlUmVuYW1lKGFwcDogQXBwLCBvbGRQYXRoOiBzdHJpbmcsIG5ld1BhdGg6IHN0cmluZyk6IHZvaWQge1xuICBjb25zdCBrZXkgPSBtYWtlS2V5KG9sZFBhdGgsIG5ld1BhdGgpO1xuICBnZXRMaWJEZWJ1Z2dlcignUmVuYW1lRGVsZXRlSGFuZGxlcjpoYW5kbGVSZW5hbWUnKShgSGFuZGxlIFJlbmFtZSAke2tleX1gKTtcbiAgaWYgKGhhbmRsZWRSZW5hbWVzLmhhcyhrZXkpKSB7XG4gICAgaGFuZGxlZFJlbmFtZXMuZGVsZXRlKGtleSk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgY29uc3Qgc2V0dGluZ3MgPSBnZXRTZXR0aW5ncyhhcHApO1xuICBpZiAoIXNldHRpbmdzLnNob3VsZEhhbmRsZVJlbmFtZXMpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICBpZiAoc2V0dGluZ3MuaXNQYXRoSWdub3JlZD8uKG9sZFBhdGgpKSB7XG4gICAgY29uc29sZS53YXJuKGBTa2lwcGluZyByZW5hbWUgaGFuZGxlciBvZiBvbGQgcGF0aCAke29sZFBhdGh9IGFzIHRoZSBwYXRoIGlzIGlnbm9yZWQuYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaWYgKHNldHRpbmdzLmlzUGF0aElnbm9yZWQ/LihuZXdQYXRoKSkge1xuICAgIGNvbnNvbGUud2FybihgU2tpcHBpbmcgcmVuYW1lIGhhbmRsZXIgb2YgbmV3IHBhdGggJHtuZXdQYXRofSBhcyB0aGUgcGF0aCBpcyBpZ25vcmVkLmApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IGNhY2hlID0gYXBwLm1ldGFkYXRhQ2FjaGUuZ2V0Q2FjaGUob2xkUGF0aCkgPz8gYXBwLm1ldGFkYXRhQ2FjaGUuZ2V0Q2FjaGUobmV3UGF0aCk7XG4gIGNvbnN0IG9sZFBhdGhMaW5rcyA9IGNhY2hlID8gZ2V0QWxsTGlua3MoY2FjaGUpIDogW107XG4gIGNvbnN0IG9sZFBhdGhCYWNrbGlua3NNYXAgPSBnZXRCYWNrbGlua3NGb3JGaWxlT3JQYXRoKGFwcCwgb2xkUGF0aCkuZGF0YTtcbiAgYWRkVG9RdWV1ZShhcHAsICgpID0+IGhhbmRsZVJlbmFtZUFzeW5jKGFwcCwgb2xkUGF0aCwgbmV3UGF0aCwgb2xkUGF0aEJhY2tsaW5rc01hcCwgb2xkUGF0aExpbmtzKSk7XG59XG5cbmFzeW5jIGZ1bmN0aW9uIGhhbmRsZVJlbmFtZUFzeW5jKFxuICBhcHA6IEFwcCxcbiAgb2xkUGF0aDogc3RyaW5nLFxuICBuZXdQYXRoOiBzdHJpbmcsXG4gIG9sZFBhdGhCYWNrbGlua3NNYXA6IE1hcDxzdHJpbmcsIFJlZmVyZW5jZVtdPixcbiAgb2xkUGF0aExpbmtzOiBSZWZlcmVuY2VbXSxcbiAgaW50ZXJydXB0ZWRDb21iaW5lZEJhY2tsaW5rc01hcD86IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIHN0cmluZz4+XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgY29udGludWVJbnRlcnJ1cHRlZFJlbmFtZXMoYXBwLCBvbGRQYXRoLCBuZXdQYXRoLCBvbGRQYXRoQmFja2xpbmtzTWFwLCBvbGRQYXRoTGlua3MpO1xuICBhd2FpdCByZWZyZXNoTGlua3MoYXBwLCBvbGRQYXRoLCBuZXdQYXRoLCBvbGRQYXRoQmFja2xpbmtzTWFwLCBvbGRQYXRoTGlua3MpO1xuICBpZiAoYXdhaXQgaGFuZGxlQ2FzZUNvbGxpc2lvbihhcHAsIG9sZFBhdGgsIG5ld1BhdGgsIG9sZFBhdGhCYWNrbGlua3NNYXAsIG9sZFBhdGhMaW5rcykpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB0cnkge1xuICAgIGNvbnN0IHJlbmFtZU1hcCA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgYXdhaXQgZmlsbFJlbmFtZU1hcChhcHAsIG9sZFBhdGgsIG5ld1BhdGgsIHJlbmFtZU1hcCwgb2xkUGF0aExpbmtzKTtcblxuICAgIGNvbnN0IGNvbWJpbmVkQmFja2xpbmtzTWFwID0gbmV3IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIHN0cmluZz4+KCk7XG4gICAgaW5pdEJhY2tsaW5rc01hcChvbGRQYXRoQmFja2xpbmtzTWFwLCByZW5hbWVNYXAsIGNvbWJpbmVkQmFja2xpbmtzTWFwLCBvbGRQYXRoKTtcblxuICAgIGZvciAoY29uc3QgYXR0YWNobWVudE9sZFBhdGggb2YgcmVuYW1lTWFwLmtleXMoKSkge1xuICAgICAgaWYgKGF0dGFjaG1lbnRPbGRQYXRoID09PSBvbGRQYXRoKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgYXR0YWNobWVudE9sZFBhdGhCYWNrbGlua3NNYXAgPSAoYXdhaXQgZ2V0QmFja2xpbmtzRm9yRmlsZVNhZmUoYXBwLCBhdHRhY2htZW50T2xkUGF0aCkpLmRhdGE7XG4gICAgICBpbml0QmFja2xpbmtzTWFwKGF0dGFjaG1lbnRPbGRQYXRoQmFja2xpbmtzTWFwLCByZW5hbWVNYXAsIGNvbWJpbmVkQmFja2xpbmtzTWFwLCBhdHRhY2htZW50T2xkUGF0aCk7XG4gICAgfVxuXG4gICAgY29uc3QgcGFyZW50Rm9sZGVyUGF0aHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcblxuICAgIGZvciAoY29uc3QgW29sZEF0dGFjaG1lbnRQYXRoLCBuZXdBdHRhY2htZW50UGF0aF0gb2YgcmVuYW1lTWFwLmVudHJpZXMoKSkge1xuICAgICAgaWYgKG9sZEF0dGFjaG1lbnRQYXRoID09PSBvbGRQYXRoKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgZml4ZWROZXdBdHRhY2htZW50UGF0aCA9IGF3YWl0IHJlbmFtZUhhbmRsZWQoYXBwLCBvbGRBdHRhY2htZW50UGF0aCwgbmV3QXR0YWNobWVudFBhdGgpO1xuICAgICAgcmVuYW1lTWFwLnNldChvbGRBdHRhY2htZW50UGF0aCwgZml4ZWROZXdBdHRhY2htZW50UGF0aCk7XG4gICAgICBwYXJlbnRGb2xkZXJQYXRocy5hZGQoZGlybmFtZShvbGRBdHRhY2htZW50UGF0aCkpO1xuICAgIH1cblxuICAgIGF3YWl0IGNsZWFudXBQYXJlbnRGb2xkZXJzKGFwcCwgQXJyYXkuZnJvbShwYXJlbnRGb2xkZXJQYXRocyksIG9sZFBhdGgpO1xuICAgIGNvbnN0IHNldHRpbmdzID0gZ2V0U2V0dGluZ3MoYXBwKTtcblxuICAgIGZvciAoXG4gICAgICBjb25zdCBbbmV3QmFja2xpbmtQYXRoLCBsaW5rSnNvblRvUGF0aE1hcF0gb2YgQXJyYXkuZnJvbShjb21iaW5lZEJhY2tsaW5rc01hcC5lbnRyaWVzKCkpLmNvbmNhdChcbiAgICAgICAgQXJyYXkuZnJvbShpbnRlcnJ1cHRlZENvbWJpbmVkQmFja2xpbmtzTWFwPy5lbnRyaWVzKCkgPz8gW10pXG4gICAgICApXG4gICAgKSB7XG4gICAgICBhd2FpdCBlZGl0TGlua3MoYXBwLCBuZXdCYWNrbGlua1BhdGgsIChsaW5rKSA9PiB7XG4gICAgICAgIGNvbnN0IG9sZEF0dGFjaG1lbnRQYXRoID0gbGlua0pzb25Ub1BhdGhNYXAuZ2V0KHRvSnNvbihsaW5rKSk7XG4gICAgICAgIGlmICghb2xkQXR0YWNobWVudFBhdGgpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXdBdHRhY2htZW50UGF0aCA9IHJlbmFtZU1hcC5nZXQob2xkQXR0YWNobWVudFBhdGgpO1xuICAgICAgICBpZiAoIW5ld0F0dGFjaG1lbnRQYXRoKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVwZGF0ZUxpbmsobm9ybWFsaXplT3B0aW9uYWxQcm9wZXJ0aWVzPFVwZGF0ZUxpbmtPcHRpb25zPih7XG4gICAgICAgICAgYXBwLFxuICAgICAgICAgIGxpbmssXG4gICAgICAgICAgbmV3U291cmNlUGF0aE9yRmlsZTogbmV3QmFja2xpbmtQYXRoLFxuICAgICAgICAgIG5ld1RhcmdldFBhdGhPckZpbGU6IG5ld0F0dGFjaG1lbnRQYXRoLFxuICAgICAgICAgIG9sZFRhcmdldFBhdGhPckZpbGU6IG9sZEF0dGFjaG1lbnRQYXRoLFxuICAgICAgICAgIHNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXM6IHNldHRpbmdzLnNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXNlc1xuICAgICAgICB9KSk7XG4gICAgICB9LCB7XG4gICAgICAgIHNob3VsZEZhaWxPbk1pc3NpbmdGaWxlOiBmYWxzZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGlzTm90ZUV4KGFwcCwgbmV3UGF0aCkpIHtcbiAgICAgIGF3YWl0IHVwZGF0ZUxpbmtzSW5GaWxlKG5vcm1hbGl6ZU9wdGlvbmFsUHJvcGVydGllczxVcGRhdGVMaW5rc0luRmlsZU9wdGlvbnM+KHtcbiAgICAgICAgYXBwLFxuICAgICAgICBuZXdTb3VyY2VQYXRoT3JGaWxlOiBuZXdQYXRoLFxuICAgICAgICBvbGRTb3VyY2VQYXRoT3JGaWxlOiBvbGRQYXRoLFxuICAgICAgICBzaG91bGRGYWlsT25NaXNzaW5nRmlsZTogZmFsc2UsXG4gICAgICAgIHNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXM6IHNldHRpbmdzLnNob3VsZFVwZGF0ZUZpbGVOYW1lQWxpYXNlc1xuICAgICAgfSkpO1xuICAgIH1cblxuICAgIGlmICghZ2V0RmlsZU9yTnVsbChhcHAsIG5ld1BhdGgpKSB7XG4gICAgICBsZXQgaW50ZXJydXB0ZWRSZW5hbWVzID0gaW50ZXJydXB0ZWRSZW5hbWVzTWFwLmdldChuZXdQYXRoKTtcbiAgICAgIGlmICghaW50ZXJydXB0ZWRSZW5hbWVzKSB7XG4gICAgICAgIGludGVycnVwdGVkUmVuYW1lcyA9IFtdO1xuICAgICAgICBpbnRlcnJ1cHRlZFJlbmFtZXNNYXAuc2V0KG5ld1BhdGgsIGludGVycnVwdGVkUmVuYW1lcyk7XG4gICAgICB9XG4gICAgICBpbnRlcnJ1cHRlZFJlbmFtZXMucHVzaCh7XG4gICAgICAgIGNvbWJpbmVkQmFja2xpbmtzTWFwLFxuICAgICAgICBvbGRQYXRoXG4gICAgICB9KTtcbiAgICB9XG4gIH0gZmluYWxseSB7XG4gICAgY29uc3Qgb3JwaGFuS2V5cyA9IEFycmF5LmZyb20oaGFuZGxlZFJlbmFtZXMpO1xuICAgIGFkZFRvUXVldWUoYXBwLCAoKSA9PiB7XG4gICAgICBmb3IgKGNvbnN0IGtleSBvZiBvcnBoYW5LZXlzKSB7XG4gICAgICAgIGhhbmRsZWRSZW5hbWVzLmRlbGV0ZShrZXkpO1xuICAgICAgfVxuICAgIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIGhhbmRsZVJlbmFtZUlmRW5hYmxlZChwbHVnaW46IFBsdWdpbiwgZmlsZTogVEFic3RyYWN0RmlsZSwgb2xkUGF0aDogc3RyaW5nKTogdm9pZCB7XG4gIGlmICghc2hvdWxkSW52b2tlSGFuZGxlcihwbHVnaW4pKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGlmICghaXNGaWxlKGZpbGUpKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIGNvbnN0IG5ld1BhdGggPSBmaWxlLnBhdGg7XG4gIGhhbmRsZVJlbmFtZShwbHVnaW4uYXBwLCBvbGRQYXRoLCBuZXdQYXRoKTtcbn1cblxuZnVuY3Rpb24gaW5pdEJhY2tsaW5rc01hcChcbiAgc2luZ2xlQmFja2xpbmtzTWFwOiBNYXA8c3RyaW5nLCBSZWZlcmVuY2VbXT4sXG4gIHJlbmFtZU1hcDogTWFwPHN0cmluZywgc3RyaW5nPixcbiAgY29tYmluZWRCYWNrbGlua3NNYXA6IE1hcDxzdHJpbmcsIE1hcDxzdHJpbmcsIHN0cmluZz4+LFxuICBwYXRoOiBzdHJpbmdcbik6IHZvaWQge1xuICBmb3IgKGNvbnN0IFtiYWNrbGlua1BhdGgsIGxpbmtzXSBvZiBzaW5nbGVCYWNrbGlua3NNYXAuZW50cmllcygpKSB7XG4gICAgY29uc3QgbmV3QmFja2xpbmtQYXRoID0gcmVuYW1lTWFwLmdldChiYWNrbGlua1BhdGgpID8/IGJhY2tsaW5rUGF0aDtcbiAgICBjb25zdCBsaW5rSnNvblRvUGF0aE1hcCA9IGNvbWJpbmVkQmFja2xpbmtzTWFwLmdldChuZXdCYWNrbGlua1BhdGgpID8/IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG4gICAgY29tYmluZWRCYWNrbGlua3NNYXAuc2V0KG5ld0JhY2tsaW5rUGF0aCwgbGlua0pzb25Ub1BhdGhNYXApO1xuICAgIGZvciAoY29uc3QgbGluayBvZiBsaW5rcykge1xuICAgICAgbGlua0pzb25Ub1BhdGhNYXAuc2V0KHRvSnNvbihsaW5rKSwgcGF0aCk7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGlzTm90ZUV4KGFwcDogQXBwLCBwYXRoOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgY29uc3Qgc2V0dGluZ3MgPSBnZXRTZXR0aW5ncyhhcHApO1xuICByZXR1cm4gc2V0dGluZ3MuaXNOb3RlPy4ocGF0aCkgPz8gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIGxvZ1JlZ2lzdGVyZWRIYW5kbGVycyhhcHA6IEFwcCk6IHZvaWQge1xuICBjb25zdCByZW5hbWVEZWxldGVIYW5kbGVyc01hcCA9IGdldFJlbmFtZURlbGV0ZUhhbmRsZXJzTWFwKGFwcCk7XG4gIGdldExpYkRlYnVnZ2VyKCdSZW5hbWVEZWxldGVIYW5kbGVyOmxvZ1JlZ2lzdGVyZWRIYW5kbGVycycpKF