UNPKG

obsidian-dev-utils

Version:

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

473 lines (460 loc) 52.8 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) { // eslint-disable-next-line no-global-assign, no-implicit-globals -- We need to patch the `require()` function. require = Object.assign( (id) => requirePatched(id), originalRequire, { __isPatched: true } ); } const newFuncs = { __extractDefault() { return extractDefault; }, process() { const browserProcess = { browser: true, cwd() { return '/'; }, env: {}, platform: 'android' }; return browserProcess; } }; for (const key of Object.keys(newFuncs)) { globalThisRecord[key] ??= newFuncs[key]?.(); } function name(obj) { return obj; } function extractDefault(module) { return module && module.__esModule && 'default' in module ? module.default : module; } const OBSIDIAN_BUILT_IN_MODULE_NAMES = [ 'obsidian', '@codemirror/autocomplete', '@codemirror/collab', '@codemirror/commands', '@codemirror/language', '@codemirror/lint', '@codemirror/search', '@codemirror/state', '@codemirror/text', '@codemirror/view', '@lezer/common', '@lezer/lr', '@lezer/highlight']; const DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES = [ '@codemirror/closebrackets', '@codemirror/comment', '@codemirror/fold', '@codemirror/gutter', '@codemirror/highlight', '@codemirror/history', '@codemirror/matchbrackets', '@codemirror/panel', '@codemirror/rangeset', '@codemirror/rectangular-selection', '@codemirror/stream-parser', '@codemirror/tooltip']; function requirePatched(id) { if (OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id) || DEPRECATED_OBSIDIAN_BUILT_IN_MODULE_NAMES.includes(id)) { return originalRequire?.(id); } // eslint-disable-next-line @typescript-eslint/no-deprecated, @typescript-eslint/no-unnecessary-condition -- We need access to app here which might not be available yet. if (globalThis?.app?.isMobile) { if (id === 'process' || id === 'node:process') { console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Fake process object is returned instead.`); return globalThis.process; } } else { const module = originalRequire?.(id); if (module) { return extractDefault(module); } } console.debug(`The most likely you can safely ignore this error. Module not found: ${id}. Empty object is returned instead.`); return {}; } })(); "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 FileChange_exports = {}; __export(FileChange_exports, { applyContentChanges: () => applyContentChanges, applyFileChanges: () => applyFileChanges, isCanvasChange: () => isCanvasChange, isCanvasFileNodeChange: () => isCanvasFileNodeChange, isCanvasTextNodeChange: () => isCanvasTextNodeChange, isContentChange: () => isContentChange, isFrontmatterChange: () => isFrontmatterChange, isFrontmatterChangeWithOffsets: () => isFrontmatterChangeWithOffsets, toFrontmatterChangeWithOffsets: () => toFrontmatterChangeWithOffsets }); module.exports = __toCommonJS(FileChange_exports); var import_implementations = require('obsidian-typings/implementations'); var import_Debug = require('../Debug.cjs'); var import_Error = require('../Error.cjs'); var import_ObjectUtils = require('../ObjectUtils.cjs'); var import_ValueProvider = require('../ValueProvider.cjs'); var import_FileSystem = require('./FileSystem.cjs'); var import_Frontmatter = require('./Frontmatter.cjs'); var import_FrontmatterLinkCacheWithOffsets = require('./FrontmatterLinkCacheWithOffsets.cjs'); var import_Reference = require('./Reference.cjs'); var import_Vault = require('./Vault.cjs'); async function applyContentChanges(abortSignal, content, path, changesProvider, shouldRetryOnInvalidChanges = true) { abortSignal.throwIfAborted(); let changes = await (0, import_ValueProvider.resolveValue)(changesProvider, abortSignal, content); abortSignal.throwIfAborted(); if (changes === null) { return null; } const { frontmatter, hasFrontmatterError } = parseFrontmatterSafely(content, path); if (!validateChanges(changes, content, frontmatter, path)) { return shouldRetryOnInvalidChanges ? null : content; } changes = sortAndFilterChanges(changes); const { frontmatterChanged, newContent } = applyContentChangesToText(changes, content, hasFrontmatterError, path); await applyFrontmatterChangesWithOffsets(abortSignal, frontmatter, frontmatterChanged, path); abortSignal.throwIfAborted(); return buildFinalContent(newContent, frontmatter, frontmatterChanged); } async function applyFileChanges(app, pathOrFile, changesProvider, processOptions = {}, shouldRetryOnInvalidChanges = true) { await (0, import_Vault.process)(app, pathOrFile, async (abortSignal, content) => { if ((0, import_FileSystem.isCanvasFile)(app, pathOrFile)) { return await applyCanvasChanges(abortSignal, content, (0, import_FileSystem.getPath)(app, pathOrFile), changesProvider, shouldRetryOnInvalidChanges); } return await applyContentChanges(abortSignal, content, (0, import_FileSystem.getPath)(app, pathOrFile), changesProvider, shouldRetryOnInvalidChanges); }, processOptions); } function isCanvasChange(change) { return (0, import_Reference.isCanvasReference)(change.reference); } function isCanvasFileNodeChange(change) { return isCanvasChange(change) && change.reference.type === "file"; } function isCanvasTextNodeChange(change) { return isCanvasChange(change) && change.reference.type === "text"; } function isContentChange(fileChange) { return (0, import_implementations.isReferenceCache)(fileChange.reference); } function isFrontmatterChange(fileChange) { return (0, import_implementations.isFrontmatterLinkCache)(fileChange.reference); } function isFrontmatterChangeWithOffsets(fileChange) { return (0, import_FrontmatterLinkCacheWithOffsets.isFrontmatterLinkCacheWithOffsets)(fileChange.reference); } function toFrontmatterChangeWithOffsets(fileChange) { if (isFrontmatterChangeWithOffsets(fileChange)) { return fileChange; } return { ...fileChange, reference: (0, import_FrontmatterLinkCacheWithOffsets.toFrontmatterLinkCacheWithOffsets)(fileChange.reference) }; } async function applyCanvasChanges(abortSignal, content, path, changesProvider, shouldRetryOnInvalidChanges = true) { const changes = await (0, import_ValueProvider.resolveValue)(changesProvider, abortSignal, content); abortSignal.throwIfAborted(); if (changes === null) { return null; } const canvasData = parseJsonSafe(content); const canvasTextChanges = /* @__PURE__ */ new Map(); for (const change of changes) { if (!isCanvasChange(change)) { const message = "Only canvas changes are supported for canvas files"; console.error(message, { change, path }); continue; } const node = canvasData.nodes[change.reference.nodeIndex]; if (!node) { const message = "Node not found"; console.error(message, { nodeIndex: change.reference.nodeIndex, path }); return null; } if (isCanvasFileNodeChange(change)) { if (node.file !== change.oldContent) { (0, import_Debug.getLibDebugger)("FileChange:applyCanvasChanges")("Content mismatch", { actualContent: node.file, expectedContent: change.oldContent, nodeIndex: change.reference.nodeIndex, path, type: "file" }); return null; } node.file = change.newContent; } else if (isCanvasTextNodeChange(change)) { let canvasTextChangesForNode = canvasTextChanges.get(change.reference.nodeIndex); if (!canvasTextChangesForNode) { canvasTextChangesForNode = []; canvasTextChanges.set(change.reference.nodeIndex, canvasTextChangesForNode); } canvasTextChangesForNode.push(change); } } for (const [nodeIndex, canvasTextChangesForNode] of canvasTextChanges.entries()) { const node = canvasData.nodes[nodeIndex]; if (!node) { const message = "Node not found"; console.error(message, { nodeIndex, path }); return null; } if (typeof node.text !== "string") { const message = "Node text is not a string"; console.error(message, { nodeIndex, path }); return null; } const contentChanges = canvasTextChangesForNode.map((change) => (0, import_Reference.referenceToFileChange)(change.reference.originalReference, change.newContent)); node.text = await applyContentChanges( abortSignal, node.text, `${path}.node${String(nodeIndex)}.VIRTUAL_FILE.md`, contentChanges, shouldRetryOnInvalidChanges ); } return JSON.stringify(canvasData, null, " "); } function applyContentChangesToText(changes, content, hasFrontmatterError, path) { let newContent = ""; let lastIndex = 0; let lastContentChange = { newContent: "", oldContent: "", reference: { link: "", original: "", position: { end: { col: 0, line: 0, offset: 0 }, start: { col: 0, line: 0, offset: 0 } } } }; const frontmatterChangesWithOffsetMap = /* @__PURE__ */ new Map(); for (const change of changes) { if (isContentChange(change)) { if (lastIndex <= change.reference.position.start.offset) { newContent += content.slice(lastIndex, change.reference.position.start.offset); newContent += change.newContent; lastIndex = change.reference.position.end.offset; lastContentChange = change; } else { const overlappingStartOffset = change.reference.position.start.offset - lastContentChange.reference.position.start.offset; const overlappingEndOffset = change.reference.position.end.offset - lastContentChange.reference.position.start.offset; const overlappingContent = lastContentChange.newContent.slice(overlappingStartOffset, overlappingEndOffset); if (overlappingContent !== change.oldContent) { const message = "Overlapping changes"; console.error(message, { change, lastContentChange }); throw new Error(message); } newContent = newContent.slice(0, newContent.length - lastContentChange.newContent.length) + lastContentChange.newContent.slice(0, overlappingStartOffset) + change.newContent + lastContentChange.newContent.slice(overlappingEndOffset); } } else if (isFrontmatterChange(change)) { if (hasFrontmatterError) { console.error(`Cannot apply frontmatter change in ${path}, because frontmatter parsing failed`, { change }); } else { let frontmatterChangesWithOffsets = frontmatterChangesWithOffsetMap.get(change.reference.key); if (!frontmatterChangesWithOffsets) { frontmatterChangesWithOffsets = []; frontmatterChangesWithOffsetMap.set(change.reference.key, frontmatterChangesWithOffsets); } frontmatterChangesWithOffsets.push(toFrontmatterChangeWithOffsets(change)); } } } newContent += content.slice(lastIndex); return { frontmatterChanged: frontmatterChangesWithOffsetMap, newContent }; } async function applyFrontmatterChangesWithOffsets(abortSignal, frontmatter, frontmatterChangesWithOffsetMap, path) { for (const [key, frontmatterChangesWithOffsets] of frontmatterChangesWithOffsetMap.entries()) { const propertyValue = (0, import_ObjectUtils.getNestedPropertyValue)(frontmatter, key); if (typeof propertyValue !== "string") { return; } const contentChanges = frontmatterChangesWithOffsets.map((change) => ({ newContent: change.newContent, oldContent: change.oldContent, reference: { link: "", original: "", position: { end: { col: change.reference.endOffset, line: 0, offset: change.reference.endOffset }, start: { col: change.reference.startOffset, line: 0, offset: change.reference.startOffset } } } })); const newPropertyValue = await applyContentChanges(abortSignal, propertyValue, `${path}.frontmatter.${key}.VIRTUAL_FILE.md`, contentChanges); if (newPropertyValue === null) { return; } (0, import_ObjectUtils.setNestedPropertyValue)(frontmatter, key, newPropertyValue); } } function buildFinalContent(newContent, frontmatter, frontmatterChanged) { if (frontmatterChanged.size > 0) { return (0, import_Frontmatter.setFrontmatter)(newContent, frontmatter); } return newContent; } function parseFrontmatterSafely(content, path) { let frontmatter = {}; let hasFrontmatterError = false; try { frontmatter = (0, import_Frontmatter.parseFrontmatter)(content); } catch (error) { (0, import_Error.printError)(new Error(`Frontmatter parsing failed in ${path}`, { cause: error })); hasFrontmatterError = true; } return { frontmatter, hasFrontmatterError }; } function parseJsonSafe(content) { let parsed; try { parsed = JSON.parse(content); } catch { parsed = null; } if (parsed === null || typeof parsed !== "object") { parsed = {}; } return parsed; } function sortAndFilterChanges(changes) { changes.sort((a, b) => { if (isContentChange(a) && isContentChange(b)) { return a.reference.position.start.offset - b.reference.position.start.offset; } if (isFrontmatterChangeWithOffsets(a) && isFrontmatterChangeWithOffsets(b)) { return a.reference.key.localeCompare(b.reference.key) || a.reference.startOffset - b.reference.startOffset; } if (isFrontmatterChange(a) && isFrontmatterChange(b)) { return a.reference.key.localeCompare(b.reference.key); } return isContentChange(a) ? -1 : 1; }); return changes.filter((change, index) => { if (change.oldContent === change.newContent) { return false; } if (index === 0) { return true; } return !(0, import_ObjectUtils.deepEqual)(change, changes[index - 1]); }); } function validateChanges(changes, content, frontmatter, path) { const validateChangesDebugger = (0, import_Debug.getLibDebugger)("FileChange:validateChanges"); for (const change of changes) { if (isContentChange(change)) { const startOffset = change.reference.position.start.offset; const endOffset = change.reference.position.end.offset; const actualContent = content.slice(startOffset, endOffset); if (actualContent !== change.oldContent) { validateChangesDebugger("Content mismatch", { actualContent, endOffset, expectedContent: change.oldContent, path, startOffset }); return false; } } else if (isFrontmatterChangeWithOffsets(change)) { const propertyValue = (0, import_ObjectUtils.getNestedPropertyValue)(frontmatter, change.reference.key); if (typeof propertyValue !== "string") { validateChangesDebugger("Property value is not a string", { frontmatterKey: change.reference.key, path, propertyValue }); return false; } const actualContent = propertyValue.slice(change.reference.startOffset, change.reference.endOffset); if (actualContent !== change.oldContent) { validateChangesDebugger("Content mismatch", { actualContent, expectedContent: change.oldContent, frontmatterKey: change.reference.key, path, startOffset: change.reference.startOffset }); return false; } } else if (isFrontmatterChange(change)) { const actualContent = (0, import_ObjectUtils.getNestedPropertyValue)(frontmatter, change.reference.key); if (actualContent !== change.oldContent) { validateChangesDebugger("Content mismatch", { actualContent, expectedContent: change.oldContent, frontmatterKey: change.reference.key, path }); return false; } } } return true; } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { applyContentChanges, applyFileChanges, isCanvasChange, isCanvasFileNodeChange, isCanvasTextNodeChange, isContentChange, isFrontmatterChange, isFrontmatterChangeWithOffsets, toFrontmatterChangeWithOffsets }); //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL0ZpbGVDaGFuZ2UudHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKlxuICogQ29udGFpbnMgdXRpbGl0eSB0eXBlcyBhbmQgZnVuY3Rpb25zIGZvciBoYW5kbGluZyBmaWxlIGNoYW5nZXMgaW4gT2JzaWRpYW4uXG4gKi9cblxuaW1wb3J0IHR5cGUge1xuICBBcHAsXG4gIEZyb250bWF0dGVyTGlua0NhY2hlLFxuICBSZWZlcmVuY2UsXG4gIFJlZmVyZW5jZUNhY2hlXG59IGZyb20gJ29ic2lkaWFuJztcbmltcG9ydCB0eXBlIHsgQ2FudmFzRGF0YSB9IGZyb20gJ29ic2lkaWFuL0NhbnZhcy5kLnRzJztcblxuaW1wb3J0IHtcbiAgaXNGcm9udG1hdHRlckxpbmtDYWNoZSxcbiAgaXNSZWZlcmVuY2VDYWNoZVxufSBmcm9tICdvYnNpZGlhbi10eXBpbmdzL2ltcGxlbWVudGF0aW9ucyc7XG5cbmltcG9ydCB0eXBlIHsgR2VuZXJpY09iamVjdCB9IGZyb20gJy4uL09iamVjdFV0aWxzLnRzJztcbmltcG9ydCB0eXBlIHsgVmFsdWVQcm92aWRlciB9IGZyb20gJy4uL1ZhbHVlUHJvdmlkZXIudHMnO1xuaW1wb3J0IHR5cGUgeyBQYXRoT3JGaWxlIH0gZnJvbSAnLi9GaWxlU3lzdGVtLnRzJztcbmltcG9ydCB0eXBlIHsgQ29tYmluZWRGcm9udG1hdHRlciB9IGZyb20gJy4vRnJvbnRtYXR0ZXIudHMnO1xuaW1wb3J0IHR5cGUgeyBGcm9udG1hdHRlckxpbmtDYWNoZVdpdGhPZmZzZXRzIH0gZnJvbSAnLi9Gcm9udG1hdHRlckxpbmtDYWNoZVdpdGhPZmZzZXRzLnRzJztcbmltcG9ydCB0eXBlIHtcbiAgQ2FudmFzRmlsZU5vZGVSZWZlcmVuY2UsXG4gIENhbnZhc1JlZmVyZW5jZSxcbiAgQ2FudmFzVGV4dE5vZGVSZWZlcmVuY2Vcbn0gZnJvbSAnLi9SZWZlcmVuY2UudHMnO1xuaW1wb3J0IHR5cGUgeyBQcm9jZXNzT3B0aW9ucyB9IGZyb20gJy4vVmF1bHQudHMnO1xuXG5pbXBvcnQgeyBnZXRMaWJEZWJ1Z2dlciB9IGZyb20gJy4uL0RlYnVnLnRzJztcbmltcG9ydCB7IHByaW50RXJyb3IgfSBmcm9tICcuLi9FcnJvci50cyc7XG5pbXBvcnQge1xuICBkZWVwRXF1YWwsXG4gIGdldE5lc3RlZFByb3BlcnR5VmFsdWUsXG4gIHNldE5lc3RlZFByb3BlcnR5VmFsdWVcbn0gZnJvbSAnLi4vT2JqZWN0VXRpbHMudHMnO1xuaW1wb3J0IHsgcmVzb2x2ZVZhbHVlIH0gZnJvbSAnLi4vVmFsdWVQcm92aWRlci50cyc7XG5pbXBvcnQge1xuICBnZXRQYXRoLFxuICBpc0NhbnZhc0ZpbGVcbn0gZnJvbSAnLi9GaWxlU3lzdGVtLnRzJztcbmltcG9ydCB7XG4gIHBhcnNlRnJvbnRtYXR0ZXIsXG4gIHNldEZyb250bWF0dGVyXG59IGZyb20gJy4vRnJvbnRtYXR0ZXIudHMnO1xuaW1wb3J0IHtcbiAgaXNGcm9udG1hdHRlckxpbmtDYWNoZVdpdGhPZmZzZXRzLFxuICB0b0Zyb250bWF0dGVyTGlua0NhY2hlV2l0aE9mZnNldHNcbn0gZnJvbSAnLi9Gcm9udG1hdHRlckxpbmtDYWNoZVdpdGhPZmZzZXRzLnRzJztcbmltcG9ydCB7XG4gIGlzQ2FudmFzUmVmZXJlbmNlLFxuICByZWZlcmVuY2VUb0ZpbGVDaGFuZ2Vcbn0gZnJvbSAnLi9SZWZlcmVuY2UudHMnO1xuaW1wb3J0IHsgcHJvY2VzcyB9IGZyb20gJy4vVmF1bHQudHMnO1xuXG4vKipcbiAqIEEgZmlsZSBjaGFuZ2UgaW4gdGhlIHZhdWx0LlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEZpbGVDaGFuZ2Uge1xuICAvKipcbiAgICogQSBuZXcgY29udGVudCB0byByZXBsYWNlIHRoZSBvbGQgY29udGVudC5cbiAgICovXG4gIG5ld0NvbnRlbnQ6IHN0cmluZztcblxuICAvKipcbiAgICogQW4gb2xkIGNvbnRlbnQgdGhhdCB3aWxsIGJlIHJlcGxhY2VkLlxuICAgKi9cbiAgb2xkQ29udGVudDogc3RyaW5nO1xuXG4gIC8qKlxuICAgKiBBIHJlZmVyZW5jZSB0aGF0IGNhdXNlZCB0aGUgY2hhbmdlLlxuICAgKi9cbiAgcmVmZXJlbmNlOiBSZWZlcmVuY2U7XG59XG50eXBlIENhbnZhc0NoYW5nZSA9IHsgcmVmZXJlbmNlOiBDYW52YXNSZWZlcmVuY2UgfSAmIEZpbGVDaGFuZ2U7XG50eXBlIENhbnZhc0ZpbGVOb2RlQ2hhbmdlID0geyByZWZlcmVuY2U6IENhbnZhc0ZpbGVOb2RlUmVmZXJlbmNlIH0gJiBGaWxlQ2hhbmdlO1xudHlwZSBDYW52YXNUZXh0Tm9kZUNoYW5nZSA9IHsgcmVmZXJlbmNlOiBDYW52YXNUZXh0Tm9kZVJlZmVyZW5jZSB9ICYgRmlsZUNoYW5nZTtcbnR5cGUgQ29udGVudENoYW5nZSA9IHsgcmVmZXJlbmNlOiBSZWZlcmVuY2VDYWNoZSB9ICYgRmlsZUNoYW5nZTtcbnR5cGUgRnJvbnRtYXR0ZXJDaGFuZ2UgPSB7IHJlZmVyZW5jZTogRnJvbnRtYXR0ZXJMaW5rQ2FjaGUgfSAmIEZpbGVDaGFuZ2U7XG50eXBlIEZyb250bWF0dGVyQ2hhbmdlV2l0aE9mZnNldHMgPSB7IHJlZmVyZW5jZTogRnJvbnRtYXR0ZXJMaW5rQ2FjaGVXaXRoT2Zmc2V0cyB9ICYgRmlsZUNoYW5nZTtcblxuLyoqXG4gKiBBcHBsaWVzIGEgc2VyaWVzIG9mIGNvbnRlbnQgY2hhbmdlcyB0byB0aGUgc3BlY2lmaWVkIGNvbnRlbnQuXG4gKlxuICogQHBhcmFtIGFib3J0U2lnbmFsIC0gVGhlIGFib3J0IHNpZ25hbCB0byBjb250cm9sIHRoZSBleGVjdXRpb24gb2YgdGhlIGZ1bmN0aW9uLlxuICogQHBhcmFtIGNvbnRlbnQgLSBUaGUgY29udGVudCB0byB3aGljaCB0aGUgY2hhbmdlcyBzaG91bGQgYmUgYXBwbGllZC5cbiAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIGNoYW5nZXMgc2hvdWxkIGJlIGFwcGxpZWQuXG4gKiBAcGFyYW0gY2hhbmdlc1Byb3ZpZGVyIC0gQSBwcm92aWRlciB0aGF0IHJldHVybnMgYW4gYXJyYXkgb2YgY29udGVudCBjaGFuZ2VzIHRvIGFwcGx5LlxuICogQHBhcmFtIHNob3VsZFJldHJ5T25JbnZhbGlkQ2hhbmdlcyAtIFdoZXRoZXIgdG8gcmV0cnkgdGhlIG9wZXJhdGlvbiBpZiB0aGUgY2hhbmdlcyBhcmUgaW52YWxpZC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHVwZGF0ZWQgY29udGVudCBvciB0byBgbnVsbGAgaWYgdXBkYXRlIGRpZG4ndCBzdWNjZWVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYXBwbHlDb250ZW50Q2hhbmdlcyhcbiAgYWJvcnRTaWduYWw6IEFib3J0U2lnbmFsLFxuICBjb250ZW50OiBzdHJpbmcsXG4gIHBhdGg6IHN0cmluZyxcbiAgY2hhbmdlc1Byb3ZpZGVyOiBWYWx1ZVByb3ZpZGVyPEZpbGVDaGFuZ2VbXSB8IG51bGwsIFtjb250ZW50OiBzdHJpbmddPixcbiAgc2hvdWxkUmV0cnlPbkludmFsaWRDaGFuZ2VzID0gdHJ1ZVxuKTogUHJvbWlzZTxudWxsIHwgc3RyaW5nPiB7XG4gIGFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG4gIGxldCBjaGFuZ2VzID0gYXdhaXQgcmVzb2x2ZVZhbHVlKGNoYW5nZXNQcm92aWRlciwgYWJvcnRTaWduYWwsIGNvbnRlbnQpO1xuICBhYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuICBpZiAoY2hhbmdlcyA9PT0gbnVsbCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgY29uc3QgeyBmcm9udG1hdHRlciwgaGFzRnJvbnRtYXR0ZXJFcnJvciB9ID0gcGFyc2VGcm9udG1hdHRlclNhZmVseShjb250ZW50LCBwYXRoKTtcblxuICBpZiAoIXZhbGlkYXRlQ2hhbmdlcyhjaGFuZ2VzLCBjb250ZW50LCBmcm9udG1hdHRlciwgcGF0aCkpIHtcbiAgICByZXR1cm4gc2hvdWxkUmV0cnlPbkludmFsaWRDaGFuZ2VzID8gbnVsbCA6IGNvbnRlbnQ7XG4gIH1cblxuICBjaGFuZ2VzID0gc29ydEFuZEZpbHRlckNoYW5nZXMoY2hhbmdlcyk7XG5cbiAgY29uc3QgeyBmcm9udG1hdHRlckNoYW5nZWQsIG5ld0NvbnRlbnQgfSA9IGFwcGx5Q29udGVudENoYW5nZXNUb1RleHQoY2hhbmdlcywgY29udGVudCwgaGFzRnJvbnRtYXR0ZXJFcnJvciwgcGF0aCk7XG5cbiAgYXdhaXQgYXBwbHlGcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0cyhhYm9ydFNpZ25hbCwgZnJvbnRtYXR0ZXIsIGZyb250bWF0dGVyQ2hhbmdlZCwgcGF0aCk7XG4gIGFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG5cbiAgcmV0dXJuIGJ1aWxkRmluYWxDb250ZW50KG5ld0NvbnRlbnQsIGZyb250bWF0dGVyLCBmcm9udG1hdHRlckNoYW5nZWQpO1xufVxuXG4vKipcbiAqIEFwcGxpZXMgYSBzZXJpZXMgb2YgZmlsZSBjaGFuZ2VzIHRvIHRoZSBzcGVjaWZpZWQgZmlsZSBvciBwYXRoIHdpdGhpbiB0aGUgYXBwbGljYXRpb24uXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZSB3aGVyZSB0aGUgZmlsZSBjaGFuZ2VzIHdpbGwgYmUgYXBwbGllZC5cbiAqIEBwYXJhbSBwYXRoT3JGaWxlIC0gVGhlIHBhdGggb3IgZmlsZSB0byB3aGljaCB0aGUgY2hhbmdlcyBzaG91bGQgYmUgYXBwbGllZC5cbiAqIEBwYXJhbSBjaGFuZ2VzUHJvdmlkZXIgLSBBIHByb3ZpZGVyIHRoYXQgcmV0dXJucyBhbiBhcnJheSBvZiBmaWxlIGNoYW5nZXMgdG8gYXBwbHkuXG4gKiBAcGFyYW0gcHJvY2Vzc09wdGlvbnMgLSBPcHRpb25hbCBvcHRpb25zIGZvciBwcm9jZXNzaW5nL3JldHJ5aW5nIHRoZSBvcGVyYXRpb24uXG4gKiBAcGFyYW0gc2hvdWxkUmV0cnlPbkludmFsaWRDaGFuZ2VzIC0gV2hldGhlciB0byByZXRyeSB0aGUgb3BlcmF0aW9uIGlmIHRoZSBjaGFuZ2VzIGFyZSBpbnZhbGlkLlxuICpcbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgZmlsZSBjaGFuZ2VzIGhhdmUgYmVlbiBzdWNjZXNzZnVsbHkgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFwcGx5RmlsZUNoYW5nZXMoXG4gIGFwcDogQXBwLFxuICBwYXRoT3JGaWxlOiBQYXRoT3JGaWxlLFxuICBjaGFuZ2VzUHJvdmlkZXI6IFZhbHVlUHJvdmlkZXI8RmlsZUNoYW5nZVtdIHwgbnVsbCwgW2NvbnRlbnQ6IHN0cmluZ10+LFxuICBwcm9jZXNzT3B0aW9uczogUHJvY2Vzc09wdGlvbnMgPSB7fSxcbiAgc2hvdWxkUmV0cnlPbkludmFsaWRDaGFuZ2VzID0gdHJ1ZVxuKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IHByb2Nlc3MoYXBwLCBwYXRoT3JGaWxlLCBhc3luYyAoYWJvcnRTaWduYWwsIGNvbnRlbnQpID0+IHtcbiAgICBpZiAoaXNDYW52YXNGaWxlKGFwcCwgcGF0aE9yRmlsZSkpIHtcbiAgICAgIHJldHVybiBhd2FpdCBhcHBseUNhbnZhc0NoYW5nZXMoYWJvcnRTaWduYWwsIGNvbnRlbnQsIGdldFBhdGgoYXBwLCBwYXRoT3JGaWxlKSwgY2hhbmdlc1Byb3ZpZGVyLCBzaG91bGRSZXRyeU9uSW52YWxpZENoYW5nZXMpO1xuICAgIH1cblxuICAgIHJldHVybiBhd2FpdCBhcHBseUNvbnRlbnRDaGFuZ2VzKGFib3J0U2lnbmFsLCBjb250ZW50LCBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSksIGNoYW5nZXNQcm92aWRlciwgc2hvdWxkUmV0cnlPbkludmFsaWRDaGFuZ2VzKTtcbiAgfSwgcHJvY2Vzc09wdGlvbnMpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIGZpbGUgY2hhbmdlIGlzIGEgY2FudmFzIGNoYW5nZS5cbiAqXG4gKiBAcGFyYW0gY2hhbmdlIC0gVGhlIGZpbGUgY2hhbmdlIHRvIGNoZWNrLlxuICogQHJldHVybnMgV2hldGhlciB0aGUgZmlsZSBjaGFuZ2UgaXMgYSBjYW52YXMgY2hhbmdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDYW52YXNDaGFuZ2UoY2hhbmdlOiBGaWxlQ2hhbmdlKTogY2hhbmdlIGlzIENhbnZhc0NoYW5nZSB7XG4gIHJldHVybiBpc0NhbnZhc1JlZmVyZW5jZShjaGFuZ2UucmVmZXJlbmNlKTtcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBmaWxlIGNoYW5nZSBpcyBhIGNhbnZhcyBmaWxlIG5vZGUgY2hhbmdlLlxuICpcbiAqIEBwYXJhbSBjaGFuZ2UgLSBUaGUgZmlsZSBjaGFuZ2UgdG8gY2hlY2suXG4gKiBAcmV0dXJucyBXaGV0aGVyIHRoZSBmaWxlIGNoYW5nZSBpcyBhIGNhbnZhcyBmaWxlIG5vZGUgY2hhbmdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDYW52YXNGaWxlTm9kZUNoYW5nZShjaGFuZ2U6IEZpbGVDaGFuZ2UpOiBjaGFuZ2UgaXMgQ2FudmFzRmlsZU5vZGVDaGFuZ2Uge1xuICByZXR1cm4gaXNDYW52YXNDaGFuZ2UoY2hhbmdlKSAmJiBjaGFuZ2UucmVmZXJlbmNlLnR5cGUgPT09ICdmaWxlJztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBmaWxlIGNoYW5nZSBpcyBhIGNhbnZhcyB0ZXh0IG5vZGUgY2hhbmdlLlxuICpcbiAqIEBwYXJhbSBjaGFuZ2UgLSBUaGUgZmlsZSBjaGFuZ2UgdG8gY2hlY2suXG4gKiBAcmV0dXJucyBXaGV0aGVyIHRoZSBmaWxlIGNoYW5nZSBpcyBhIGNhbnZhcyB0ZXh0IG5vZGUgY2hhbmdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDYW52YXNUZXh0Tm9kZUNoYW5nZShjaGFuZ2U6IEZpbGVDaGFuZ2UpOiBjaGFuZ2UgaXMgQ2FudmFzVGV4dE5vZGVDaGFuZ2Uge1xuICByZXR1cm4gaXNDYW52YXNDaGFuZ2UoY2hhbmdlKSAmJiBjaGFuZ2UucmVmZXJlbmNlLnR5cGUgPT09ICd0ZXh0Jztcbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgYSBmaWxlIGNoYW5nZSBpcyBhIGNvbnRlbnQgY2hhbmdlLlxuICpcbiAqIEBwYXJhbSBmaWxlQ2hhbmdlIC0gVGhlIGZpbGUgY2hhbmdlIHRvIGNoZWNrLlxuICogQHJldHVybnMgQSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgZmlsZSBjaGFuZ2UgaXMgYSBjb250ZW50IGNoYW5nZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQ29udGVudENoYW5nZShmaWxlQ2hhbmdlOiBGaWxlQ2hhbmdlKTogZmlsZUNoYW5nZSBpcyBDb250ZW50Q2hhbmdlIHtcbiAgcmV0dXJuIGlzUmVmZXJlbmNlQ2FjaGUoZmlsZUNoYW5nZS5yZWZlcmVuY2UpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIGZpbGUgY2hhbmdlIGlzIGEgZnJvbnRtYXR0ZXIgY2hhbmdlLlxuICpcbiAqIEBwYXJhbSBmaWxlQ2hhbmdlIC0gVGhlIGZpbGUgY2hhbmdlIHRvIGNoZWNrLlxuICogQHJldHVybnMgQSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgZmlsZSBjaGFuZ2UgaXMgYSBmcm9udG1hdHRlciBjaGFuZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0Zyb250bWF0dGVyQ2hhbmdlKGZpbGVDaGFuZ2U6IEZpbGVDaGFuZ2UpOiBmaWxlQ2hhbmdlIGlzIEZyb250bWF0dGVyQ2hhbmdlIHtcbiAgcmV0dXJuIGlzRnJvbnRtYXR0ZXJMaW5rQ2FjaGUoZmlsZUNoYW5nZS5yZWZlcmVuY2UpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIGZpbGUgY2hhbmdlIGlzIGEgZnJvbnRtYXR0ZXIgY2hhbmdlIHdpdGggb2Zmc2V0cy5cbiAqXG4gKiBAcGFyYW0gZmlsZUNoYW5nZSAtIFRoZSBmaWxlIGNoYW5nZSB0byBjaGVjay5cbiAqIEByZXR1cm5zIEEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGZpbGUgY2hhbmdlIGlzIGEgZnJvbnRtYXR0ZXIgY2hhbmdlIHdpdGggb2Zmc2V0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0cyhmaWxlQ2hhbmdlOiBGaWxlQ2hhbmdlKTogZmlsZUNoYW5nZSBpcyBGcm9udG1hdHRlckNoYW5nZVdpdGhPZmZzZXRzIHtcbiAgcmV0dXJuIGlzRnJvbnRtYXR0ZXJMaW5rQ2FjaGVXaXRoT2Zmc2V0cyhmaWxlQ2hhbmdlLnJlZmVyZW5jZSk7XG59XG5cbi8qKlxuICogQ29udmVydHMgYSBmcm9udG1hdHRlciBjaGFuZ2UgdG8gYSBmcm9udG1hdHRlciBjaGFuZ2Ugd2l0aCBvZmZzZXRzLlxuICpcbiAqIEBwYXJhbSBmaWxlQ2hhbmdlIC0gVGhlIGZpbGUgY2hhbmdlIHRvIGNvbnZlcnQuXG4gKiBAcmV0dXJucyBUaGUgY29udmVydGVkIGZpbGUgY2hhbmdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gdG9Gcm9udG1hdHRlckNoYW5nZVdpdGhPZmZzZXRzKGZpbGVDaGFuZ2U6IEZyb250bWF0dGVyQ2hhbmdlKTogRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0cyB7XG4gIGlmIChpc0Zyb250bWF0dGVyQ2hhbmdlV2l0aE9mZnNldHMoZmlsZUNoYW5nZSkpIHtcbiAgICByZXR1cm4gZmlsZUNoYW5nZTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgLi4uZmlsZUNoYW5nZSxcbiAgICByZWZlcmVuY2U6IHRvRnJvbnRtYXR0ZXJMaW5rQ2FjaGVXaXRoT2Zmc2V0cyhmaWxlQ2hhbmdlLnJlZmVyZW5jZSlcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXBwbHlDYW52YXNDaGFuZ2VzKFxuICBhYm9ydFNpZ25hbDogQWJvcnRTaWduYWwsXG4gIGNvbnRlbnQ6IHN0cmluZyxcbiAgcGF0aDogc3RyaW5nLFxuICBjaGFuZ2VzUHJvdmlkZXI6IFZhbHVlUHJvdmlkZXI8RmlsZUNoYW5nZVtdIHwgbnVsbCwgW2NvbnRlbnQ6IHN0cmluZ10+LFxuICBzaG91bGRSZXRyeU9uSW52YWxpZENoYW5nZXMgPSB0cnVlXG4pOiBQcm9taXNlPG51bGwgfCBzdHJpbmc+IHtcbiAgY29uc3QgY2hhbmdlcyA9IGF3YWl0IHJlc29sdmVWYWx1ZShjaGFuZ2VzUHJvdmlkZXIsIGFib3J0U2lnbmFsLCBjb250ZW50KTtcbiAgYWJvcnRTaWduYWwudGhyb3dJZkFib3J0ZWQoKTtcbiAgaWYgKGNoYW5nZXMgPT09IG51bGwpIHtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGNvbnN0IGNhbnZhc0RhdGEgPSBwYXJzZUpzb25TYWZlKGNvbnRlbnQpIGFzIENhbnZhc0RhdGE7XG5cbiAgY29uc3QgY2FudmFzVGV4dENoYW5nZXMgPSBuZXcgTWFwPG51bWJlciwgQ2FudmFzVGV4dE5vZGVDaGFuZ2VbXT4oKTtcblxuICBmb3IgKGNvbnN0IGNoYW5nZSBvZiBjaGFuZ2VzKSB7XG4gICAgaWYgKCFpc0NhbnZhc0NoYW5nZShjaGFuZ2UpKSB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gJ09ubHkgY2FudmFzIGNoYW5nZXMgYXJlIHN1cHBvcnRlZCBmb3IgY2FudmFzIGZpbGVzJztcbiAgICAgIGNvbnNvbGUuZXJyb3IobWVzc2FnZSwge1xuICAgICAgICBjaGFuZ2UsXG4gICAgICAgIHBhdGhcbiAgICAgIH0pO1xuICAgICAgY29udGludWU7XG4gICAgfVxuXG4gICAgY29uc3Qgbm9kZSA9IGNhbnZhc0RhdGEubm9kZXNbY2hhbmdlLnJlZmVyZW5jZS5ub2RlSW5kZXhdO1xuICAgIGlmICghbm9kZSkge1xuICAgICAgY29uc3QgbWVzc2FnZSA9ICdOb2RlIG5vdCBmb3VuZCc7XG4gICAgICBjb25zb2xlLmVycm9yKG1lc3NhZ2UsIHtcbiAgICAgICAgbm9kZUluZGV4OiBjaGFuZ2UucmVmZXJlbmNlLm5vZGVJbmRleCxcbiAgICAgICAgcGF0aFxuICAgICAgfSk7XG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAoaXNDYW52YXNGaWxlTm9kZUNoYW5nZShjaGFuZ2UpKSB7XG4gICAgICBpZiAobm9kZS5maWxlICE9PSBjaGFuZ2Uub2xkQ29udGVudCkge1xuICAgICAgICBnZXRMaWJEZWJ1Z2dlcignRmlsZUNoYW5nZTphcHBseUNhbnZhc0NoYW5nZXMnKSgnQ29udGVudCBtaXNtYXRjaCcsIHtcbiAgICAgICAgICBhY3R1YWxDb250ZW50OiBub2RlLmZpbGUgYXMgc3RyaW5nIHwgdW5kZWZpbmVkLFxuICAgICAgICAgIGV4cGVjdGVkQ29udGVudDogY2hhbmdlLm9sZENvbnRlbnQsXG4gICAgICAgICAgbm9kZUluZGV4OiBjaGFuZ2UucmVmZXJlbmNlLm5vZGVJbmRleCxcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIHR5cGU6ICdmaWxlJ1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgIH1cbiAgICAgIG5vZGUuZmlsZSA9IGNoYW5nZS5uZXdDb250ZW50O1xuICAgIH0gZWxzZSBpZiAoaXNDYW52YXNUZXh0Tm9kZUNoYW5nZShjaGFuZ2UpKSB7XG4gICAgICBsZXQgY2FudmFzVGV4dENoYW5nZXNGb3JOb2RlID0gY2FudmFzVGV4dENoYW5nZXMuZ2V0KGNoYW5nZS5yZWZlcmVuY2Uubm9kZUluZGV4KTtcbiAgICAgIGlmICghY2FudmFzVGV4dENoYW5nZXNGb3JOb2RlKSB7XG4gICAgICAgIGNhbnZhc1RleHRDaGFuZ2VzRm9yTm9kZSA9IFtdO1xuICAgICAgICBjYW52YXNUZXh0Q2hhbmdlcy5zZXQoY2hhbmdlLnJlZmVyZW5jZS5ub2RlSW5kZXgsIGNhbnZhc1RleHRDaGFuZ2VzRm9yTm9kZSk7XG4gICAgICB9XG5cbiAgICAgIGNhbnZhc1RleHRDaGFuZ2VzRm9yTm9kZS5wdXNoKGNoYW5nZSk7XG4gICAgfVxuICB9XG5cbiAgZm9yIChjb25zdCBbbm9kZUluZGV4LCBjYW52YXNUZXh0Q2hhbmdlc0Zvck5vZGVdIG9mIGNhbnZhc1RleHRDaGFuZ2VzLmVudHJpZXMoKSkge1xuICAgIGNvbnN0IG5vZGUgPSBjYW52YXNEYXRhLm5vZGVzW25vZGVJbmRleF07XG4gICAgaWYgKCFub2RlKSB7XG4gICAgICBjb25zdCBtZXNzYWdlID0gJ05vZGUgbm90IGZvdW5kJztcbiAgICAgIGNvbnNvbGUuZXJyb3IobWVzc2FnZSwge1xuICAgICAgICBub2RlSW5kZXgsXG4gICAgICAgIHBhdGhcbiAgICAgIH0pO1xuXG4gICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG5cbiAgICBpZiAodHlwZW9mIG5vZGUudGV4dCAhPT0gJ3N0cmluZycpIHtcbiAgICAgIGNvbnN0IG1lc3NhZ2UgPSAnTm9kZSB0ZXh0IGlzIG5vdCBhIHN0cmluZyc7XG4gICAgICBjb25zb2xlLmVycm9yKG1lc3NhZ2UsIHtcbiAgICAgICAgbm9kZUluZGV4LFxuICAgICAgICBwYXRoXG4gICAgICB9KTtcblxuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgY29uc3QgY29udGVudENoYW5nZXMgPSBjYW52YXNUZXh0Q2hhbmdlc0Zvck5vZGUubWFwKChjaGFuZ2UpID0+IHJlZmVyZW5jZVRvRmlsZUNoYW5nZShjaGFuZ2UucmVmZXJlbmNlLm9yaWdpbmFsUmVmZXJlbmNlLCBjaGFuZ2UubmV3Q29udGVudCkpO1xuICAgIG5vZGUudGV4dCA9IGF3YWl0IGFwcGx5Q29udGVudENoYW5nZXMoXG4gICAgICBhYm9ydFNpZ25hbCxcbiAgICAgIG5vZGUudGV4dCxcbiAgICAgIGAke3BhdGh9Lm5vZGUke1N0cmluZyhub2RlSW5kZXgpfS5WSVJUVUFMX0ZJTEUubWRgLFxuICAgICAgY29udGVudENoYW5nZXMsXG4gICAgICBzaG91bGRSZXRyeU9uSW52YWxpZENoYW5nZXNcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KGNhbnZhc0RhdGEsIG51bGwsICdcXHQnKTtcbn1cblxuZnVuY3Rpb24gYXBwbHlDb250ZW50Q2hhbmdlc1RvVGV4dChcbiAgY2hhbmdlczogRmlsZUNoYW5nZVtdLFxuICBjb250ZW50OiBzdHJpbmcsXG4gIGhhc0Zyb250bWF0dGVyRXJyb3I6IGJvb2xlYW4sXG4gIHBhdGg6IHN0cmluZ1xuKTogeyBmcm9udG1hdHRlckNoYW5nZWQ6IE1hcDxzdHJpbmcsIEZyb250bWF0dGVyQ2hhbmdlV2l0aE9mZnNldHNbXT47IG5ld0NvbnRlbnQ6IHN0cmluZyB9IHtcbiAgbGV0IG5ld0NvbnRlbnQgPSAnJztcbiAgbGV0IGxhc3RJbmRleCA9IDA7XG4gIGxldCBsYXN0Q29udGVudENoYW5nZTogQ29udGVudENoYW5nZSA9IHtcbiAgICBuZXdDb250ZW50OiAnJyxcbiAgICBvbGRDb250ZW50OiAnJyxcbiAgICByZWZlcmVuY2U6IHtcbiAgICAgIGxpbms6ICcnLFxuICAgICAgb3JpZ2luYWw6ICcnLFxuICAgICAgcG9zaXRpb246IHtcbiAgICAgICAgZW5kOiB7IGNvbDogMCwgbGluZTogMCwgb2Zmc2V0OiAwIH0sXG4gICAgICAgIHN0YXJ0OiB7IGNvbDogMCwgbGluZTogMCwgb2Zmc2V0OiAwIH1cbiAgICAgIH1cbiAgICB9XG4gIH07XG4gIGNvbnN0IGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRNYXAgPSBuZXcgTWFwPHN0cmluZywgRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0c1tdPigpO1xuXG4gIGZvciAoY29uc3QgY2hhbmdlIG9mIGNoYW5nZXMpIHtcbiAgICBpZiAoaXNDb250ZW50Q2hhbmdlKGNoYW5nZSkpIHtcbiAgICAgIGlmIChsYXN0SW5kZXggPD0gY2hhbmdlLnJlZmVyZW5jZS5wb3NpdGlvbi5zdGFydC5vZmZzZXQpIHtcbiAgICAgICAgbmV3Q29udGVudCArPSBjb250ZW50LnNsaWNlKGxhc3RJbmRleCwgY2hhbmdlLnJlZmVyZW5jZS5wb3NpdGlvbi5zdGFydC5vZmZzZXQpO1xuICAgICAgICBuZXdDb250ZW50ICs9IGNoYW5nZS5uZXdDb250ZW50O1xuICAgICAgICBsYXN0SW5kZXggPSBjaGFuZ2UucmVmZXJlbmNlLnBvc2l0aW9uLmVuZC5vZmZzZXQ7XG4gICAgICAgIGxhc3RDb250ZW50Q2hhbmdlID0gY2hhbmdlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3Qgb3ZlcmxhcHBpbmdTdGFydE9mZnNldCA9IGNoYW5nZS5yZWZlcmVuY2UucG9zaXRpb24uc3RhcnQub2Zmc2V0IC0gbGFzdENvbnRlbnRDaGFuZ2UucmVmZXJlbmNlLnBvc2l0aW9uLnN0YXJ0Lm9mZnNldDtcbiAgICAgICAgY29uc3Qgb3ZlcmxhcHBpbmdFbmRPZmZzZXQgPSBjaGFuZ2UucmVmZXJlbmNlLnBvc2l0aW9uLmVuZC5vZmZzZXQgLSBsYXN0Q29udGVudENoYW5nZS5yZWZlcmVuY2UucG9zaXRpb24uc3RhcnQub2Zmc2V0O1xuICAgICAgICBjb25zdCBvdmVybGFwcGluZ0NvbnRlbnQgPSBsYXN0Q29udGVudENoYW5nZS5uZXdDb250ZW50LnNsaWNlKG92ZXJsYXBwaW5nU3RhcnRPZmZzZXQsIG92ZXJsYXBwaW5nRW5kT2Zmc2V0KTtcbiAgICAgICAgaWYgKG92ZXJsYXBwaW5nQ29udGVudCAhPT0gY2hhbmdlLm9sZENvbnRlbnQpIHtcbiAgICAgICAgICBjb25zdCBtZXNzYWdlID0gJ092ZXJsYXBwaW5nIGNoYW5nZXMnO1xuICAgICAgICAgIGNvbnNvbGUuZXJyb3IobWVzc2FnZSwgeyBjaGFuZ2UsIGxhc3RDb250ZW50Q2hhbmdlIH0pO1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcihtZXNzYWdlKTtcbiAgICAgICAgfVxuICAgICAgICBuZXdDb250ZW50ID0gbmV3Q29udGVudC5zbGljZSgwLCBuZXdDb250ZW50Lmxlbmd0aCAtIGxhc3RDb250ZW50Q2hhbmdlLm5ld0NvbnRlbnQubGVuZ3RoKVxuICAgICAgICAgICsgbGFzdENvbnRlbnRDaGFuZ2UubmV3Q29udGVudC5zbGljZSgwLCBvdmVybGFwcGluZ1N0YXJ0T2Zmc2V0KVxuICAgICAgICAgICsgY2hhbmdlLm5ld0NvbnRlbnRcbiAgICAgICAgICArIGxhc3RDb250ZW50Q2hhbmdlLm5ld0NvbnRlbnQuc2xpY2Uob3ZlcmxhcHBpbmdFbmRPZmZzZXQpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNGcm9udG1hdHRlckNoYW5nZShjaGFuZ2UpKSB7XG4gICAgICBpZiAoaGFzRnJvbnRtYXR0ZXJFcnJvcikge1xuICAgICAgICBjb25zb2xlLmVycm9yKGBDYW5ub3QgYXBwbHkgZnJvbnRtYXR0ZXIgY2hhbmdlIGluICR7cGF0aH0sIGJlY2F1c2UgZnJvbnRtYXR0ZXIgcGFyc2luZyBmYWlsZWRgLCB7IGNoYW5nZSB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBmcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0cyA9IGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRNYXAuZ2V0KGNoYW5nZS5yZWZlcmVuY2Uua2V5KTtcbiAgICAgICAgaWYgKCFmcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0cykge1xuICAgICAgICAgIGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRzID0gW107XG4gICAgICAgICAgZnJvbnRtYXR0ZXJDaGFuZ2VzV2l0aE9mZnNldE1hcC5zZXQoY2hhbmdlLnJlZmVyZW5jZS5rZXksIGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRzKTtcbiAgICAgICAgfVxuICAgICAgICBmcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0cy5wdXNoKHRvRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0cyhjaGFuZ2UpKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBuZXdDb250ZW50ICs9IGNvbnRlbnQuc2xpY2UobGFzdEluZGV4KTtcblxuICByZXR1cm4geyBmcm9udG1hdHRlckNoYW5nZWQ6IGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRNYXAsIG5ld0NvbnRlbnQgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gYXBwbHlGcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0cyhcbiAgYWJvcnRTaWduYWw6IEFib3J0U2lnbmFsLFxuICBmcm9udG1hdHRlcjogQ29tYmluZWRGcm9udG1hdHRlcjx1bmtub3duPixcbiAgZnJvbnRtYXR0ZXJDaGFuZ2VzV2l0aE9mZnNldE1hcDogTWFwPHN0cmluZywgRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0c1tdPixcbiAgcGF0aDogc3RyaW5nXG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgZm9yIChjb25zdCBba2V5LCBmcm9udG1hdHRlckNoYW5nZXNXaXRoT2Zmc2V0c10gb2YgZnJvbnRtYXR0ZXJDaGFuZ2VzV2l0aE9mZnNldE1hcC5lbnRyaWVzKCkpIHtcbiAgICBjb25zdCBwcm9wZXJ0eVZhbHVlID0gZ2V0TmVzdGVkUHJvcGVydHlWYWx1ZShmcm9udG1hdHRlciwga2V5KTtcbiAgICBpZiAodHlwZW9mIHByb3BlcnR5VmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgY29udGVudENoYW5nZXM6IENvbnRlbnRDaGFuZ2VbXSA9IGZyb250bWF0dGVyQ2hhbmdlc1dpdGhPZmZzZXRzLm1hcCgoY2hhbmdlKSA9PiAoe1xuICAgICAgbmV3Q29udGVudDogY2hhbmdlLm5ld0NvbnRlbnQsXG4gICAgICBvbGRDb250ZW50OiBjaGFuZ2Uub2xkQ29udGVudCxcbiAgICAgIHJlZmVyZW5jZToge1xuICAgICAgICBsaW5rOiAnJyxcbiAgICAgICAgb3JpZ2luYWw6ICcnLFxuICAgICAgICBwb3NpdGlvbjoge1xuICAgICAgICAgIGVuZDoge1xuICAgICAgICAgICAgY29sOiBjaGFuZ2UucmVmZXJlbmNlLmVuZE9mZnNldCxcbiAgICAgICAgICAgIGxpbmU6IDAsXG4gICAgICAgICAgICBvZmZzZXQ6IGNoYW5nZS5yZWZlcmVuY2UuZW5kT2Zmc2V0XG4gICAgICAgICAgfSxcbiAgICAgICAgICBzdGFydDoge1xuICAgICAgICAgICAgY29sOiBjaGFuZ2UucmVmZXJlbmNlLnN0YXJ0T2Zmc2V0LFxuICAgICAgICAgICAgbGluZTogMCxcbiAgICAgICAgICAgIG9mZnNldDogY2hhbmdlLnJlZmVyZW5jZS5zdGFydE9mZnNldFxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gYXMgQ29udGVudENoYW5nZSkpO1xuXG4gICAgY29uc3QgbmV3UHJvcGVydHlWYWx1ZSA9IGF3YWl0IGFwcGx5Q29udGVudENoYW5nZXMoYWJvcnRTaWduYWwsIHByb3BlcnR5VmFsdWUsIGAke3BhdGh9LmZyb250bWF0dGVyLiR7a2V5fS5WSVJUVUFMX0ZJTEUubWRgLCBjb250ZW50Q2hhbmdlcyk7XG4gICAgaWYgKG5ld1Byb3BlcnR5VmFsdWUgPT09IG51bGwpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBzZXROZXN0ZWRQcm9wZXJ0eVZhbHVlKGZyb250bWF0dGVyLCBrZXksIG5ld1Byb3BlcnR5VmFsdWUpO1xuICB9XG59XG5cbmZ1bmN0aW9uIGJ1aWxkRmluYWxDb250ZW50KFxuICBuZXdDb250ZW50OiBzdHJpbmcsXG4gIGZyb250bWF0dGVyOiBDb21iaW5lZEZyb250bWF0dGVyPHVua25vd24+LFxuICBmcm9udG1hdHRlckNoYW5nZWQ6IE1hcDxzdHJpbmcsIEZyb250bWF0dGVyQ2hhbmdlV2l0aE9mZnNldHNbXT5cbik6IHN0cmluZyB7XG4gIGlmIChmcm9udG1hdHRlckNoYW5nZWQuc2l6ZSA+IDApIHtcbiAgICByZXR1cm4gc2V0RnJvbnRtYXR0ZXIobmV3Q29udGVudCwgZnJvbnRtYXR0ZXIpO1xuICB9XG4gIHJldHVybiBuZXdDb250ZW50O1xufVxuXG5mdW5jdGlvbiBwYXJzZUZyb250bWF0dGVyU2FmZWx5KGNvbnRlbnQ6IHN0cmluZywgcGF0aDogc3RyaW5nKTogeyBmcm9udG1hdHRlcjogQ29tYmluZWRGcm9udG1hdHRlcjx1bmtub3duPjsgaGFzRnJvbnRtYXR0ZXJFcnJvcjogYm9vbGVhbiB9IHtcbiAgbGV0IGZyb250bWF0dGVyOiBDb21iaW5lZEZyb250bWF0dGVyPHVua25vd24+ID0ge307XG4gIGxldCBoYXNGcm9udG1hdHRlckVycm9yID0gZmFsc2U7XG5cbiAgdHJ5IHtcbiAgICBmcm9udG1hdHRlciA9IHBhcnNlRnJvbnRtYXR0ZXIoY29udGVudCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcHJpbnRFcnJvcihuZXcgRXJyb3IoYEZyb250bWF0dGVyIHBhcnNpbmcgZmFpbGVkIGluICR7cGF0aH1gLCB7IGNhdXNlOiBlcnJvciB9KSk7XG4gICAgaGFzRnJvbnRtYXR0ZXJFcnJvciA9IHRydWU7XG4gIH1cblxuICByZXR1cm4geyBmcm9udG1hdHRlciwgaGFzRnJvbnRtYXR0ZXJFcnJvciB9O1xufVxuXG5mdW5jdGlvbiBwYXJzZUpzb25TYWZlKGNvbnRlbnQ6IHN0cmluZyk6IEdlbmVyaWNPYmplY3Qge1xuICBsZXQgcGFyc2VkOiB1bmtub3duO1xuICB0cnkge1xuICAgIHBhcnNlZCA9IEpTT04ucGFyc2UoY29udGVudCk7XG4gIH0gY2F0Y2gge1xuICAgIHBhcnNlZCA9IG51bGw7XG4gIH1cblxuICBpZiAocGFyc2VkID09PSBudWxsIHx8IHR5cGVvZiBwYXJzZWQgIT09ICdvYmplY3QnKSB7XG4gICAgcGFyc2VkID0ge307XG4gIH1cblxuICByZXR1cm4gcGFyc2VkIGFzIEdlbmVyaWNPYmplY3Q7XG59XG5cbmZ1bmN0aW9uIHNvcnRBbmRGaWx0ZXJDaGFuZ2VzKGNoYW5nZXM6IEZpbGVDaGFuZ2VbXSk6IEZpbGVDaGFuZ2VbXSB7XG4gIC8vIFNvcnQgY2hhbmdlcyBieSB0eXBlIGFuZCBwb3NpdGlvblxuICBjaGFuZ2VzLnNvcnQoKGEsIGIpID0+IHtcbiAgICBpZiAoaXNDb250ZW50Q2hhbmdlKGEpICYmIGlzQ29udGVudENoYW5nZShiKSkge1xuICAgICAgcmV0dXJuIGEucmVmZXJlbmNlLnBvc2l0aW9uLnN0YXJ0Lm9mZnNldCAtIGIucmVmZXJlbmNlLnBvc2l0aW9uLnN0YXJ0Lm9mZnNldDtcbiAgICB9XG5cbiAgICBpZiAoaXNGcm9udG1hdHRlckNoYW5nZVdpdGhPZmZzZXRzKGEpICYmIGlzRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0cyhiKSkge1xuICAgICAgcmV0dXJuIGEucmVmZXJlbmNlLmtleS5sb2NhbGVDb21wYXJlKGIucmVmZXJlbmNlLmtleSkgfHwgYS5yZWZlcmVuY2Uuc3RhcnRPZmZzZXQgLSBiLnJlZmVyZW5jZS5zdGFydE9mZnNldDtcbiAgICB9XG5cbiAgICBpZiAoaXNGcm9udG1hdHRlckNoYW5nZShhKSAmJiBpc0Zyb250bWF0dGVyQ2hhbmdlKGIpKSB7XG4gICAgICByZXR1cm4gYS5yZWZlcmVuY2Uua2V5LmxvY2FsZUNvbXBhcmUoYi5yZWZlcmVuY2Uua2V5KTtcbiAgICB9XG5cbiAgICByZXR1cm4gaXNDb250ZW50Q2hhbmdlKGEpID8gLTEgOiAxO1xuICB9KTtcblxuICAvLyBGaWx0ZXIgb3V0IGR1cGxpY2F0ZSBhbmQgbm8tb3AgY2hhbmdlc1xuICByZXR1cm4gY2hhbmdlcy5maWx0ZXIoKGNoYW5nZSwgaW5kZXgpID0+IHtcbiAgICBpZiAoY2hhbmdlLm9sZENvbnRlbnQgPT09IGNoYW5nZS5uZXdDb250ZW50KSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChpbmRleCA9PT0gMCkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiAhZGVlcEVxdWFsKGNoYW5nZSwgY2hhbmdlc1tpbmRleCAtIDFdKTtcbiAgfSk7XG59XG5cbmZ1bmN0aW9uIHZhbGlkYXRlQ2hhbmdlcyhjaGFuZ2VzOiBGaWxlQ2hhbmdlW10sIGNvbnRlbnQ6IHN0cmluZywgZnJvbnRtYXR0ZXI6IENvbWJpbmVkRnJvbnRtYXR0ZXI8dW5rbm93bj4sIHBhdGg6IHN0cmluZyk6IGJvb2xlYW4ge1xuICBjb25zdCB2YWxpZGF0ZUNoYW5nZXNEZWJ1Z2dlciA9IGdldExpYkRlYnVnZ2VyKCdGaWxlQ2hhbmdlOnZhbGlkYXRlQ2hhbmdlcycpO1xuICBmb3IgKGNvbnN0IGNoYW5nZSBvZiBjaGFuZ2VzKSB7XG4gICAgaWYgKGlzQ29udGVudENoYW5nZShjaGFuZ2UpKSB7XG4gICAgICBjb25zdCBzdGFydE9mZnNldCA9IGNoYW5nZS5yZWZlcmVuY2UucG9zaXRpb24uc3RhcnQub2Zmc2V0O1xuICAgICAgY29uc3QgZW5kT2Zmc2V0ID0gY2hhbmdlLnJlZmVyZW5jZS5wb3NpdGlvbi5lbmQub2Zmc2V0O1xuICAgICAgY29uc3QgYWN0dWFsQ29udGVudCA9IGNvbnRlbnQuc2xpY2Uoc3RhcnRPZmZzZXQsIGVuZE9mZnNldCk7XG4gICAgICBpZiAoYWN0dWFsQ29udGVudCAhPT0gY2hhbmdlLm9sZENvbnRlbnQpIHtcbiAgICAgICAgdmFsaWRhdGVDaGFuZ2VzRGVidWdnZXIoJ0NvbnRlbnQgbWlzbWF0Y2gnLCB7XG4gICAgICAgICAgYWN0dWFsQ29udGVudCxcbiAgICAgICAgICBlbmRPZmZzZXQsXG4gICAgICAgICAgZXhwZWN0ZWRDb250ZW50OiBjaGFuZ2Uub2xkQ29udGVudCxcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIHN0YXJ0T2Zmc2V0XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKGlzRnJvbnRtYXR0ZXJDaGFuZ2VXaXRoT2Zmc2V0cyhjaGFuZ2UpKSB7XG4gICAgICBjb25zdCBwcm9wZXJ0eVZhbHVlID0gZ2V0TmVzdGVkUHJvcGVydHlWYWx1ZShmcm9udG1hdHRlciwgY2hhbmdlLnJlZmVyZW5jZS5rZXkpO1xuICAgICAgaWYgKHR5cGVvZiBwcm9wZXJ0eVZhbHVlICE9PSAnc3RyaW5nJykge1xuICAgICAgICB2YWxpZGF0ZUNoYW5nZXNEZWJ1Z2dlcignUHJvcGVydHkgdmFsdWUgaXMgbm90IGEgc3RyaW5nJywge1xuICAgICAgICAgIGZyb250bWF0dGVyS2V5OiBjaGFuZ2UucmVmZXJlbmNlLmtleSxcbiAgICAgICAgICBwYXRoLFxuICAgICAgICAgIHByb3BlcnR5VmFsdWVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cblxuICAgICAgY29uc3QgYWN0dWFsQ29udGVudCA9IHByb3BlcnR5VmFsdWUuc2xpY2UoY2hhbmdlLnJlZmVyZW5jZS5zdGFydE9mZnNldCwgY2hhbmdlLnJlZmVyZW5jZS5lbmRPZmZzZXQpO1xuICAgICAgaWYgKGFjdHVhbENvbnRlbnQgIT09IGNoYW5nZS5vbGRDb250ZW50KSB7XG4gICAgICAgIHZhbGlkYXRlQ2hhbmdlc0RlYnVnZ2VyKCdDb250ZW50IG1pc21hdGNoJywge1xuICAgICAgICAgIGFjdHVhbENvbnRlbnQsXG4gICAgICAgICAgZXhwZWN0ZWRDb250ZW50OiBjaGFuZ2Uub2xkQ29udGVudCxcbiAgICAgICAgICBmcm9udG1hdHRlcktleTogY2hhbmdlLnJlZmVyZW5jZS5rZXksXG4gICAgICAgICAgcGF0aCxcbiAgICAgICAgICBzdGFydE9mZnNldDogY2hhbmdlLnJlZmVyZW5jZS5zdGFydE9mZnNldFxuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChpc0Zyb250bWF0dGVyQ2hhbmdlKGNoYW5nZSkpIHtcbiAgICAgIGNvbnN0IGFjdHVhbENvbnRlbnQgPSBnZXROZXN0ZWRQcm9wZXJ0eVZhbHVlKGZyb250bWF0dGVyLCBjaGFuZ2UucmVmZXJlbmNlLmtleSk7XG4gICAgICBpZiAoYWN0dWFsQ29udGVudCAhPT0gY2hhbmdlLm9sZENvbnRlbnQpIHtcbiAgICAgICAgdmFsaWRhdGVDaGFuZ2VzRGVidWdnZXIoJ0NvbnRlbnQgbWlzbWF0Y2gnLCB7XG4gICAgICAgICAgYWN0dWFsQ29udGVudCxcbiAgICAgICAgICBleHBlY3RlZENvbnRlbnQ6IGNoYW5nZS5vbGRDb250ZW50LFxuICAgICAgICAgIGZyb250bWF0dGVyS2V5OiBjaGFuZ2UucmVmZXJlbmNlLmtleSxcbiAgICAgICAgICBwYXRoXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9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