UNPKG

obsidian-dev-utils

Version:

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

403 lines 50.5 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 initEsm() {
  if (globalThis.process) {
    return;
  }

  const browserProcess = {
    browser: true,
    cwd() {
      return '/';
    },
    env: {},
    platform: 'android'
  };
  globalThis.process = browserProcess;
})();

import {
  MarkdownView,
  TAbstractFile,
  TFile,
  TFolder
} from "obsidian";
import {
  parentFolderPath,
  ViewType
} from "obsidian-typings/implementations";
import { abortSignalAny } from "../AbortController.mjs";
import { getLibDebugger } from "../Debug.mjs";
import { noopAsync } from "../Function.mjs";
import {
  basename,
  dirname,
  extname,
  join
} from "../Path.mjs";
import { resolveValue } from "../ValueProvider.mjs";
import { retryWithTimeoutNotice } from "./AsyncWithNotice.mjs";
import {
  lockEditor,
  unlockEditor
} from "./Editor.mjs";
import {
  asFile,
  asFolder,
  FileSystemType,
  getAbstractFile,
  getAbstractFileOrNull,
  getFile,
  getFileOrNull,
  getFileSystemType,
  getFolder,
  getFolderOrNull,
  getPath,
  isFile,
  isMarkdownFile,
  isNote
} from "./FileSystem.mjs";
import { t } from "./i18n/i18n.mjs";
async function copySafe(app, oldPathOrFile, newPath) {
  const file = getFile(app, oldPathOrFile);
  if (file.path === newPath) {
    return newPath;
  }
  const newFolderPath = parentFolderPath(newPath);
  await createFolderSafe(app, newFolderPath);
  const newAvailablePath = getAvailablePath(app, newPath);
  try {
    await app.vault.copy(file, newAvailablePath);
  } catch (e) {
    if (!await app.vault.exists(newAvailablePath)) {
      throw e;
    }
  }
  return newAvailablePath;
}
async function createFolderSafe(app, path) {
  if (await app.vault.adapter.exists(path)) {
    return false;
  }
  try {
    await app.vault.createFolder(path);
    return true;
  } catch (e) {
    if (!await app.vault.exists(path)) {
      throw e;
    }
    return true;
  }
}
async function createTempFile(app, path) {
  let file = getFileOrNull(app, path);
  if (file) {
    return noopAsync;
  }
  const folderCleanup = await createTempFolder(app, parentFolderPath(path));
  try {
    await app.vault.create(path, "");
  } catch (e) {
    if (!await app.vault.exists(path)) {
      throw e;
    }
  }
  return async () => {
    file = getFile(app, path);
    if (!file.deleted) {
      await app.fileManager.trashFile(file);
    }
    await folderCleanup();
  };
}
async function createTempFolder(app, path) {
  let folder = getFolderOrNull(app, path);
  if (folder) {
    return noopAsync;
  }
  const folderPath = parentFolderPath(path);
  await createTempFolder(app, folderPath);
  const folderCleanup = await createTempFolder(app, parentFolderPath(path));
  await createFolderSafe(app, path);
  return async () => {
    folder = getFolder(app, path);
    if (!folder.deleted) {
      await app.fileManager.trashFile(folder);
    }
    await folderCleanup();
  };
}
function getAbstractFilePathSafe(app, path, type) {
  const abstractFile = getAbstractFileOrNull(app, path);
  if (abstractFile && getFileSystemType(abstractFile) === type) {
    return path;
  }
  return getAvailablePath(app, path);
}
function getAvailablePath(app, path) {
  const ext = extname(path);
  return app.vault.getAvailablePath(join(dirname(path), basename(path, ext)), ext.slice(1));
}
function getFilePathSafe(app, path) {
  return getAbstractFilePathSafe(app, path, FileSystemType.File);
}
function getFolderPathSafe(app, path) {
  return getAbstractFilePathSafe(app, path, FileSystemType.Folder);
}
function getMarkdownFilesSorted(app) {
  return app.vault.getMarkdownFiles().sort((a, b) => a.path.localeCompare(b.path));
}
function getNoteFilesSorted(app) {
  return app.vault.getAllLoadedFiles().filter((file) => isFile(file) && isNote(app, file)).sort((a, b) => a.path.localeCompare(b.path));
}
async function getOrCreateAbstractFileSafe(app, path, type) {
  path = getAbstractFilePathSafe(app, path, type);
  const abstractFile = getAbstractFileOrNull(app, path);
  if (abstractFile) {
    return abstractFile;
  }
  switch (type) {
    case FileSystemType.File:
      return await app.vault.create(path, "");
    case FileSystemType.Folder:
      return await app.vault.createFolder(path);
    default:
      throw new Error(`Invalid file system type: ${type}`);
  }
}
async function getOrCreateFileSafe(app, path) {
  return asFile(await getOrCreateAbstractFileSafe(app, path, FileSystemType.File));
}
async function getOrCreateFolderSafe(app, path) {
  return asFolder(await getOrCreateAbstractFileSafe(app, path, FileSystemType.Folder));
}
function getSafeRenamePath(app, oldPathOrAbstractFile, newPath) {
  const oldPath = getPath(app, oldPathOrAbstractFile);
  if (app.vault.adapter.insensitive) {
    let folderPath = dirname(newPath);
    let nonExistingPath = basename(newPath);
    let folder;
    while (true) {
      folder = getFolderOrNull(app, folderPath, true);
      if (folder) {
        break;
      }
      nonExistingPath = join(basename(folderPath), nonExistingPath);
      folderPath = dirname(folderPath);
    }
    newPath = join(folder.getParentPrefix(), nonExistingPath);
  }
  if (oldPath.toLowerCase() === newPath.toLowerCase()) {
    return newPath;
  }
  return getAvailablePath(app, newPath);
}
async function invokeWithFileSystemLock(app, pathOrFile, fn) {
  const file = getFile(app, pathOrFile);
  await app.vault.process(file, (content) => {
    fn(content);
    return content;
  });
}
function isChild(app, a, b) {
  const aPath = getPath(app, a);
  const bPath = getPath(app, b);
  if (aPath === bPath) {
    return false;
  }
  if (bPath === "/") {
    return true;
  }
  return aPath.startsWith(`${bPath}/`);
}
function isChildOrSelf(app, a, b) {
  const aPath = getPath(app, a);
  const bPath = getPath(app, b);
  return aPath === bPath || isChild(app, a, b);
}
async function isEmptyFolder(app, pathOrFolder) {
  const listedFiles = await listSafe(app, getPath(app, pathOrFolder));
  return listedFiles.files.length === 0 && listedFiles.folders.length === 0;
}
async function listSafe(app, pathOrFolder) {
  const path = getPath(app, pathOrFolder);
  const EMPTY = { files: [], folders: [] };
  if ((await app.vault.adapter.stat(path))?.type !== "folder") {
    return EMPTY;
  }
  try {
    return await app.vault.adapter.list(path);
  } catch (e) {
    if (await app.vault.exists(path)) {
      throw e;
    }
    return EMPTY;
  }
}
async function process(app, pathOrFile, newContentProvider, options = {}) {
  const DEFAULT_RETRY_OPTIONS = {
    shouldFailOnMissingFile: true,
    shouldLockEditorWhileProcessing: true,
    shouldShowTimeoutNotice: true,
    // eslint-disable-next-line no-magic-numbers -- Default value.
    timeoutInMilliseconds: 500
  };
  const fullOptions = { ...DEFAULT_RETRY_OPTIONS, ...options };
  const abortController = new AbortController();
  fullOptions.abortSignal = abortSignalAny(fullOptions.abortSignal, abortController.signal);
  const path = getPath(app, pathOrFile);
  let activeLeafChangeEventRef = null;
  if (fullOptions.shouldLockEditorWhileProcessing) {
    for (const leaf of app.workspace.getLeavesOfType(ViewType.Markdown)) {
      if (leaf.view instanceof MarkdownView && leaf.view.file?.path === path) {
        lockEditor(leaf.view.editor);
      }
    }
    activeLeafChangeEventRef = app.workspace.on("active-leaf-change", (leaf) => {
      if (leaf?.view instanceof MarkdownView && leaf.view.file?.path === path) {
        lockEditor(leaf.view.editor);
      }
    });
  }
  try {
    await retryWithTimeoutNotice({
      async operationFn(abortSignal) {
        abortSignal.throwIfAborted();
        const oldContent = await readSafe(app, pathOrFile);
        abortSignal.throwIfAborted();
        if (oldContent === null) {
          return handleMissingFile();
        }
        const newContent = await resolveValue(newContentProvider, abortSignal, oldContent);
        abortSignal.throwIfAborted();
        if (newContent === null) {
          return false;
        }
        let isSuccess = true;
        const doesFileExist = await invokeFileActionSafe(app, pathOrFile, async (file) => {
          abortSignal.throwIfAborted();
          await app.vault.process(file, (content) => {
            abortSignal.throwIfAborted();
            if (content !== oldContent) {
              getLibDebugger("Vault:process")("Content has changed since it was read. Retrying...", {
                actualContent: content,
                expectedContent: oldContent,
                path: file.path
              });
              isSuccess = false;
              return content;
            }
            return newContent;
          });
          abortSignal.throwIfAborted();
        });
        if (!doesFileExist) {
          return handleMissingFile();
        }
        return isSuccess;
        function handleMissingFile() {
          if (fullOptions.shouldFailOnMissingFile) {
            throw new Error(`File '${path}' not found`);
          }
          return true;
        }
      },
      operationName: t(($) => $.obsidianDevUtils.vault.processFile, { filePath: path }),
      retryOptions: fullOptions,
      shouldShowTimeoutNotice: fullOptions.shouldShowTimeoutNotice
    });
  } finally {
    activeLeafChangeEventRef?.e.offref(activeLeafChangeEventRef);
    for (const leaf of app.workspace.getLeavesOfType(ViewType.Markdown)) {
      if (leaf.view instanceof MarkdownView && leaf.view.file?.path === path) {
        unlockEditor(leaf.view.editor);
      }
    }
  }
}
async function readSafe(app, pathOrFile) {
  let content = null;
  await invokeFileActionSafe(app, pathOrFile, async (file) => {
    await saveNote(app, file);
    content = await app.vault.read(file);
  });
  return content;
}
async function renameSafe(app, oldPathOrAbstractFile, newPath) {
  const oldAbstractFile = getAbstractFile(app, oldPathOrAbstractFile);
  const newAvailablePath = getSafeRenamePath(app, oldPathOrAbstractFile, newPath);
  if (oldAbstractFile.path.toLowerCase() === newAvailablePath.toLowerCase()) {
    if (oldAbstractFile.path !== newPath) {
      await app.fileManager.renameFile(oldAbstractFile, newAvailablePath);
    }
    return newAvailablePath;
  }
  const newFolderPath = parentFolderPath(newAvailablePath);
  await createFolderSafe(app, newFolderPath);
  try {
    await app.fileManager.renameFile(oldAbstractFile, newAvailablePath);
  } catch (e) {
    if (!await app.vault.exists(newAvailablePath) || await app.vault.exists(oldAbstractFile.path)) {
      throw e;
    }
  }
  return newAvailablePath;
}
async function saveNote(app, pathOrFile) {
  if (!isMarkdownFile(app, pathOrFile)) {
    return;
  }
  const path = getPath(app, pathOrFile);
  for (const leaf of app.workspace.getLeavesOfType(ViewType.Markdown)) {
    if (leaf.view instanceof MarkdownView && leaf.view.file?.path === path && leaf.view.dirty) {
      await leaf.view.save();
    }
  }
}
async function invokeFileActionSafe(app, pathOrFile, fileAction) {
  const path = getPath(app, pathOrFile);
  let file = getFileOrNull(app, path);
  if (!file || file.deleted) {
    return false;
  }
  try {
    await fileAction(file);
    return true;
  } catch (e) {
    file = getFileOrNull(app, path);
    if (!file || file.deleted) {
      return false;
    }
    throw e;
  }
}
export {
  copySafe,
  createFolderSafe,
  createTempFile,
  createTempFolder,
  getAbstractFilePathSafe,
  getAvailablePath,
  getFilePathSafe,
  getFolderPathSafe,
  getMarkdownFilesSorted,
  getNoteFilesSorted,
  getOrCreateAbstractFileSafe,
  getOrCreateFileSafe,
  getOrCreateFolderSafe,
  getSafeRenamePath,
  invokeWithFileSystemLock,
  isChild,
  isChildOrSelf,
  isEmptyFolder,
  listSafe,
  process,
  readSafe,
  renameSafe,
  saveNote
};
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL29ic2lkaWFuL1ZhdWx0LnRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyIvKipcbiAqIEBwYWNrYWdlRG9jdW1lbnRhdGlvblxuICpcbiAqIFRoaXMgbW9kdWxlIHByb3ZpZGVzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciB3b3JraW5nIHdpdGggdGhlIE9ic2lkaWFuIFZhdWx0LlxuICovXG5cbmltcG9ydCB0eXBlIHtcbiAgQXBwLFxuICBFdmVudFJlZixcbiAgTGlzdGVkRmlsZXNcbn0gZnJvbSAnb2JzaWRpYW4nO1xuXG5pbXBvcnQge1xuICBNYXJrZG93blZpZXcsXG4gIFRBYnN0cmFjdEZpbGUsXG4gIFRGaWxlLFxuICBURm9sZGVyXG59IGZyb20gJ29ic2lkaWFuJztcbmltcG9ydCB7XG4gIHBhcmVudEZvbGRlclBhdGgsXG4gIFZpZXdUeXBlXG59IGZyb20gJ29ic2lkaWFuLXR5cGluZ3MvaW1wbGVtZW50YXRpb25zJztcblxuaW1wb3J0IHR5cGUgeyBSZXRyeU9wdGlvbnMgfSBmcm9tICcuLi9Bc3luYy50cyc7XG5pbXBvcnQgdHlwZSB7IFZhbHVlUHJvdmlkZXIgfSBmcm9tICcuLi9WYWx1ZVByb3ZpZGVyLnRzJztcbmltcG9ydCB0eXBlIHtcbiAgUGF0aE9yQWJzdHJhY3RGaWxlLFxuICBQYXRoT3JGaWxlLFxuICBQYXRoT3JGb2xkZXJcbn0gZnJvbSAnLi9GaWxlU3lzdGVtLnRzJztcblxuaW1wb3J0IHsgYWJvcnRTaWduYWxBbnkgfSBmcm9tICcuLi9BYm9ydENvbnRyb2xsZXIudHMnO1xuaW1wb3J0IHsgZ2V0TGliRGVidWdnZXIgfSBmcm9tICcuLi9EZWJ1Zy50cyc7XG5pbXBvcnQgeyBub29wQXN5bmMgfSBmcm9tICcuLi9GdW5jdGlvbi50cyc7XG5pbXBvcnQge1xuICBiYXNlbmFtZSxcbiAgZGlybmFtZSxcbiAgZXh0bmFtZSxcbiAgam9pblxufSBmcm9tICcuLi9QYXRoLnRzJztcbmltcG9ydCB7IHJlc29sdmVWYWx1ZSB9IGZyb20gJy4uL1ZhbHVlUHJvdmlkZXIudHMnO1xuaW1wb3J0IHsgcmV0cnlXaXRoVGltZW91dE5vdGljZSB9IGZyb20gJy4vQXN5bmNXaXRoTm90aWNlLnRzJztcbmltcG9ydCB7XG4gIGxvY2tFZGl0b3IsXG4gIHVubG9ja0VkaXRvclxufSBmcm9tICcuL0VkaXRvci50cyc7XG5pbXBvcnQge1xuICBhc0ZpbGUsXG4gIGFzRm9sZGVyLFxuICBGaWxlU3lzdGVtVHlwZSxcbiAgZ2V0QWJzdHJhY3RGaWxlLFxuICBnZXRBYnN0cmFjdEZpbGVPck51bGwsXG4gIGdldEZpbGUsXG4gIGdldEZpbGVPck51bGwsXG4gIGdldEZpbGVTeXN0ZW1UeXBlLFxuICBnZXRGb2xkZXIsXG4gIGdldEZvbGRlck9yTnVsbCxcbiAgZ2V0UGF0aCxcbiAgaXNGaWxlLFxuICBpc01hcmtkb3duRmlsZSxcbiAgaXNOb3RlXG59IGZyb20gJy4vRmlsZVN5c3RlbS50cyc7XG5pbXBvcnQgeyB0IH0gZnJvbSAnLi9pMThuL2kxOG4udHMnO1xuXG4vKipcbiAqIE9wdGlvbnMgZm9yIHtAbGluayBwcm9jZXNzfS5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBQcm9jZXNzT3B0aW9ucyBleHRlbmRzIFJldHJ5T3B0aW9ucyB7XG4gIC8qKlxuICAgKiBXaGV0aGVyIHRvIGZhaWwgaWYgdGhlIGZpbGUgaXMgbWlzc2luZyBvciBkZWxldGVkLiBEZWZhdWx0IGlzIGB0cnVlYC5cbiAgICovXG4gIHNob3VsZEZhaWxPbk1pc3NpbmdGaWxlPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBsb2NrIHRoZSBlZGl0b3Igd2hpbGUgcHJvY2Vzc2luZyB0aGUgZmlsZS4gQXBwbGljYWJsZSBvbmx5IGZvciBtYXJrZG93biBmaWxlcy4gRGVmYXVsdCBpcyBgdHJ1ZWAuXG4gICAqL1xuICBzaG91bGRMb2NrRWRpdG9yV2hpbGVQcm9jZXNzaW5nPzogYm9vbGVhbjtcblxuICAvKipcbiAgICogV2hldGhlciB0byBzaG93IGEgdGltZW91dCBub3RpY2UuIERlZmF1bHQgaXMgYHRydWVgLlxuICAgKi9cbiAgc2hvdWxkU2hvd1RpbWVvdXROb3RpY2U/OiBib29sZWFuO1xufVxuXG4vKipcbiAqIENvcGllcyBhIGZpbGUgc2FmZWx5IGluIHRoZSB2YXVsdC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIG9sZFBhdGhPckZpbGUgLSBUaGUgb2xkIHBhdGggb3IgZmlsZSB0byBjb3B5LlxuICogQHBhcmFtIG5ld1BhdGggLSBUaGUgbmV3IHBhdGggdG8gY29weSB0aGUgZmlsZSB0by5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG5ldyBwYXRoIG9mIHRoZSBjb3BpZWQgZmlsZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNvcHlTYWZlKGFwcDogQXBwLCBvbGRQYXRoT3JGaWxlOiBQYXRoT3JGaWxlLCBuZXdQYXRoOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCBmaWxlID0gZ2V0RmlsZShhcHAsIG9sZFBhdGhPckZpbGUpO1xuXG4gIGlmIChmaWxlLnBhdGggPT09IG5ld1BhdGgpIHtcbiAgICByZXR1cm4gbmV3UGF0aDtcbiAgfVxuXG4gIGNvbnN0IG5ld0ZvbGRlclBhdGggPSBwYXJlbnRGb2xkZXJQYXRoKG5ld1BhdGgpO1xuICBhd2FpdCBjcmVhdGVGb2xkZXJTYWZlKGFwcCwgbmV3Rm9sZGVyUGF0aCk7XG5cbiAgY29uc3QgbmV3QXZhaWxhYmxlUGF0aCA9IGdldEF2YWlsYWJsZVBhdGgoYXBwLCBuZXdQYXRoKTtcblxuICB0cnkge1xuICAgIGF3YWl0IGFwcC52YXVsdC5jb3B5KGZpbGUsIG5ld0F2YWlsYWJsZVBhdGgpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgaWYgKCFhd2FpdCBhcHAudmF1bHQuZXhpc3RzKG5ld0F2YWlsYWJsZVBhdGgpKSB7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuZXdBdmFpbGFibGVQYXRoO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBmb2xkZXIgc2FmZWx5IGluIHRoZSBzcGVjaWZpZWQgcGF0aC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aCBvZiB0aGUgZm9sZGVyIHRvIGNyZWF0ZS5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gYSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgZm9sZGVyIHdhcyBjcmVhdGVkLlxuICogQHRocm93cyBJZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgY3JlYXRpbmcgdGhlIGZvbGRlciBhbmQgaXQgc3RpbGwgZG9lc24ndCBleGlzdC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUZvbGRlclNhZmUoYXBwOiBBcHAsIHBhdGg6IHN0cmluZyk6IFByb21pc2U8Ym9vbGVhbj4ge1xuICBpZiAoYXdhaXQgYXBwLnZhdWx0LmFkYXB0ZXIuZXhpc3RzKHBhdGgpKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBhcHAudmF1bHQuY3JlYXRlRm9sZGVyKHBhdGgpO1xuICAgIHJldHVybiB0cnVlO1xuICB9IGNhdGNoIChlKSB7XG4gICAgaWYgKCFhd2FpdCBhcHAudmF1bHQuZXhpc3RzKHBhdGgpKSB7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSB0ZW1wb3JhcnkgZmlsZSBpbiB0aGUgdmF1bHQgd2l0aCBwYXJlbnQgZm9sZGVycyBpZiBuZWVkZWQuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggb2YgdGhlIGZpbGUgdG8gY3JlYXRlLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byBhIGZ1bmN0aW9uIHRoYXQgY2FuIGJlIGNhbGxlZCB0byBkZWxldGUgdGhlIHRlbXBvcmFyeSBmaWxlIGFuZCBhbGwgaXRzIGNyZWF0ZWQgcGFyZW50cy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVRlbXBGaWxlKGFwcDogQXBwLCBwYXRoOiBzdHJpbmcpOiBQcm9taXNlPCgpID0+IFByb21pc2U8dm9pZD4+IHtcbiAgbGV0IGZpbGUgPSBnZXRGaWxlT3JOdWxsKGFwcCwgcGF0aCk7XG4gIGlmIChmaWxlKSB7XG4gICAgcmV0dXJuIG5vb3BBc3luYztcbiAgfVxuXG4gIGNvbnN0IGZvbGRlckNsZWFudXAgPSBhd2FpdCBjcmVhdGVUZW1wRm9sZGVyKGFwcCwgcGFyZW50Rm9sZGVyUGF0aChwYXRoKSk7XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBhcHAudmF1bHQuY3JlYXRlKHBhdGgsICcnKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGlmICghYXdhaXQgYXBwLnZhdWx0LmV4aXN0cyhwYXRoKSkge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gYXN5bmMgKCkgPT4ge1xuICAgIGZpbGUgPSBnZXRGaWxlKGFwcCwgcGF0aCk7XG4gICAgaWYgKCFmaWxlLmRlbGV0ZWQpIHtcbiAgICAgIGF3YWl0IGFwcC5maWxlTWFuYWdlci50cmFzaEZpbGUoZmlsZSk7XG4gICAgfVxuICAgIGF3YWl0IGZvbGRlckNsZWFudXAoKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgdGVtcG9yYXJ5IGZvbGRlciBpbiB0aGUgdmF1bHQgd2l0aCBwYXJlbnQgZm9sZGVycyBpZiBuZWVkZWQuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggb2YgdGhlIGZvbGRlciB0byBjcmVhdGUuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIGEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgY2FsbGVkIHRvIGRlbGV0ZSB0aGUgdGVtcG9yYXJ5IGZvbGRlciBhbmQgYWxsIGl0cyBjcmVhdGVkIHBhcmVudHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVUZW1wRm9sZGVyKGFwcDogQXBwLCBwYXRoOiBzdHJpbmcpOiBQcm9taXNlPCgpID0+IFByb21pc2U8dm9pZD4+IHtcbiAgbGV0IGZvbGRlciA9IGdldEZvbGRlck9yTnVsbChhcHAsIHBhdGgpO1xuICBpZiAoZm9sZGVyKSB7XG4gICAgcmV0dXJuIG5vb3BBc3luYztcbiAgfVxuXG4gIGNvbnN0IGZvbGRlclBhdGggPSBwYXJlbnRGb2xkZXJQYXRoKHBhdGgpO1xuICBhd2FpdCBjcmVhdGVUZW1wRm9sZGVyKGFwcCwgZm9sZGVyUGF0aCk7XG5cbiAgY29uc3QgZm9sZGVyQ2xlYW51cCA9IGF3YWl0IGNyZWF0ZVRlbXBGb2xkZXIoYXBwLCBwYXJlbnRGb2xkZXJQYXRoKHBhdGgpKTtcblxuICBhd2FpdCBjcmVhdGVGb2xkZXJTYWZlKGFwcCwgcGF0aCk7XG5cbiAgcmV0dXJuIGFzeW5jICgpID0+IHtcbiAgICBmb2xkZXIgPSBnZXRGb2xkZXIoYXBwLCBwYXRoKTtcbiAgICBpZiAoIWZvbGRlci5kZWxldGVkKSB7XG4gICAgICBhd2FpdCBhcHAuZmlsZU1hbmFnZXIudHJhc2hGaWxlKGZvbGRlcik7XG4gICAgfVxuICAgIGF3YWl0IGZvbGRlckNsZWFudXAoKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBHZXRzIGEgc2FmZSBwYXRoIGZvciBhIGZpbGUgb3IgZm9sZGVyLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgYXBwbGljYXRpb24gaW5zdGFuY2UuXG4gKiBAcGFyYW0gcGF0aCAtIFRoZSBwYXRoIG9mIHRoZSBmaWxlIG9yIGZvbGRlciB0byBnZXQgYSBzYWZlIHBhdGggZm9yLlxuICogQHBhcmFtIHR5cGUgLSBUaGUgdHlwZSBvZiB0aGUgZmlsZSBzeXN0ZW0gb2JqZWN0LlxuICogQHJldHVybnMgVGhlIHNhZmUgcGF0aCBmb3IgdGhlIGZpbGUgb3IgZm9sZGVyLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzdHJhY3RGaWxlUGF0aFNhZmUoYXBwOiBBcHAsIHBhdGg6IHN0cmluZywgdHlwZTogRmlsZVN5c3RlbVR5cGUpOiBzdHJpbmcge1xuICBjb25zdCBhYnN0cmFjdEZpbGUgPSBnZXRBYnN0cmFjdEZpbGVPck51bGwoYXBwLCBwYXRoKTtcblxuICBpZiAoYWJzdHJhY3RGaWxlICYmIGdldEZpbGVTeXN0ZW1UeXBlKGFic3RyYWN0RmlsZSkgPT09IHR5cGUpIHtcbiAgICByZXR1cm4gcGF0aDtcbiAgfVxuXG4gIHJldHVybiBnZXRBdmFpbGFibGVQYXRoKGFwcCwgcGF0aCk7XG59XG5cbi8qKlxuICogR2V0cyBhbiBhdmFpbGFibGUgcGF0aCBmb3IgYSBmaWxlIGluIHRoZSB2YXVsdC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aCBvZiB0aGUgZmlsZSB0byBnZXQgYW4gYXZhaWxhYmxlIHBhdGggZm9yLlxuICogQHJldHVybnMgVGhlIGF2YWlsYWJsZSBwYXRoIGZvciB0aGUgZmlsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEF2YWlsYWJsZVBhdGgoYXBwOiBBcHAsIHBhdGg6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGV4dCA9IGV4dG5hbWUocGF0aCk7XG4gIHJldHVybiBhcHAudmF1bHQuZ2V0QXZhaWxhYmxlUGF0aChqb2luKGRpcm5hbWUocGF0aCksIGJhc2VuYW1lKHBhdGgsIGV4dCkpLCBleHQuc2xpY2UoMSkpO1xufVxuXG4vKipcbiAqIEdldHMgYSBzYWZlIGZpbGUgcGF0aCBmb3IgYSBmaWxlIG9yIGZvbGRlci5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aCBvZiB0aGUgZmlsZSBvciBmb2xkZXIgdG8gZ2V0IGEgc2FmZSBwYXRoIGZvci5cbiAqIEByZXR1cm5zIFRoZSBzYWZlIHBhdGggZm9yIHRoZSBmaWxlIG9yIGZvbGRlci5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldEZpbGVQYXRoU2FmZShhcHA6IEFwcCwgcGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldEFic3RyYWN0RmlsZVBhdGhTYWZlKGFwcCwgcGF0aCwgRmlsZVN5c3RlbVR5cGUuRmlsZSk7XG59XG5cbi8qKlxuICogR2V0cyBhIHNhZmUgZm9sZGVyIHBhdGggZm9yIGEgZmlsZSBvciBmb2xkZXIuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggb2YgdGhlIGZpbGUgb3IgZm9sZGVyIHRvIGdldCBhIHNhZmUgcGF0aCBmb3IuXG4gKiBAcmV0dXJucyBUaGUgc2FmZSBwYXRoIGZvciB0aGUgZmlsZSBvciBmb2xkZXIuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRGb2xkZXJQYXRoU2FmZShhcHA6IEFwcCwgcGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgcmV0dXJuIGdldEFic3RyYWN0RmlsZVBhdGhTYWZlKGFwcCwgcGF0aCwgRmlsZVN5c3RlbVR5cGUuRm9sZGVyKTtcbn1cblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW4gYXJyYXkgb2YgTWFya2Rvd24gZmlsZXMgZnJvbSB0aGUgYXBwJ3MgdmF1bHQgYW5kIHNvcnRzIHRoZW0gYWxwaGFiZXRpY2FsbHkgYnkgdGhlaXIgZmlsZSBwYXRoLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICogQHJldHVybnMgQW4gYXJyYXkgb2YgTWFya2Rvd24gZmlsZXMgc29ydGVkIGJ5IGZpbGUgcGF0aC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldE1hcmtkb3duRmlsZXNTb3J0ZWQoYXBwOiBBcHApOiBURmlsZVtdIHtcbiAgcmV0dXJuIGFwcC52YXVsdC5nZXRNYXJrZG93bkZpbGVzKCkuc29ydCgoYSwgYikgPT4gYS5wYXRoLmxvY2FsZUNvbXBhcmUoYi5wYXRoKSk7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIGFuIGFycmF5IG9mIGFsbCBub3RlIGZpbGVzIGZyb20gdGhlIGFwcCdzIHZhdWx0IGFuZCBzb3J0cyB0aGVtIGFscGhhYmV0aWNhbGx5IGJ5IHRoZWlyIGZpbGUgcGF0aC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIE9ic2lkaWFuIGFwcCBpbnN0YW5jZS5cbiAqIEByZXR1cm5zIEFuIGFycmF5IG9mIGFsbCBub3RlIGZpbGVzIGluIHRoZSB2YXVsdCBzb3J0ZWQgYnkgZmlsZSBwYXRoLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0Tm90ZUZpbGVzU29ydGVkKGFwcDogQXBwKTogVEZpbGVbXSB7XG4gIHJldHVybiBhcHAudmF1bHQuZ2V0QWxsTG9hZGVkRmlsZXMoKS5maWx0ZXIoKGZpbGUpID0+IGlzRmlsZShmaWxlKSAmJiBpc05vdGUoYXBwLCBmaWxlKSkuc29ydCgoYSwgYikgPT4gYS5wYXRoLmxvY2FsZUNvbXBhcmUoYi5wYXRoKSkgYXMgVEZpbGVbXTtcbn1cblxuLyoqXG4gKiBHZXRzIG9yIGNyZWF0ZXMgYW4gYWJzdHJhY3QgZmlsZSBzYWZlbHkgaW4gdGhlIHNwZWNpZmllZCBwYXRoLlxuICpcbiAqIElmIHRoZSBmaWxlIGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIHJldHVybmVkLlxuICogSWYgdGhlIGZpbGUgZG9lcyBub3QgZXhpc3QsIGl0IHdpbGwgYmUgY3JlYXRlZCBhbmQgcmV0dXJuZWQuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoIC0gVGhlIHBhdGggb2YgdGhlIGFic3RyYWN0IGZpbGUgdG8gZ2V0IG9yIGNyZWF0ZS5cbiAqIEBwYXJhbSB0eXBlIC0gVGhlIHR5cGUgb2YgdGhlIGFic3RyYWN0IGZpbGUgdG8gZ2V0IG9yIGNyZWF0ZS5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGFic3RyYWN0IGZpbGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRPckNyZWF0ZUFic3RyYWN0RmlsZVNhZmUoYXBwOiBBcHAsIHBhdGg6IHN0cmluZywgdHlwZTogRmlsZVN5c3RlbVR5cGUpOiBQcm9taXNlPFRBYnN0cmFjdEZpbGU+IHtcbiAgcGF0aCA9IGdldEFic3RyYWN0RmlsZVBhdGhTYWZlKGFwcCwgcGF0aCwgdHlwZSk7XG4gIGNvbnN0IGFic3RyYWN0RmlsZSA9IGdldEFic3RyYWN0RmlsZU9yTnVsbChhcHAsIHBhdGgpO1xuICBpZiAoYWJzdHJhY3RGaWxlKSB7XG4gICAgcmV0dXJuIGFic3RyYWN0RmlsZTtcbiAgfVxuXG4gIHN3aXRjaCAodHlwZSkge1xuICAgIGNhc2UgRmlsZVN5c3RlbVR5cGUuRmlsZTpcbiAgICAgIHJldHVybiBhd2FpdCBhcHAudmF1bHQuY3JlYXRlKHBhdGgsICcnKTtcbiAgICBjYXNlIEZpbGVTeXN0ZW1UeXBlLkZvbGRlcjpcbiAgICAgIHJldHVybiBhd2FpdCBhcHAudmF1bHQuY3JlYXRlRm9sZGVyKHBhdGgpO1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgZmlsZSBzeXN0ZW0gdHlwZTogJHt0eXBlIGFzIHN0cmluZ31gKTtcbiAgfVxufVxuXG4vKipcbiAqIEdldHMgb3IgY3JlYXRlcyBhIGZpbGUgc2FmZWx5IGluIHRoZSBzcGVjaWZpZWQgcGF0aC5cbiAqXG4gKiBJZiB0aGUgZmlsZSBhbHJlYWR5IGV4aXN0cywgaXQgd2lsbCBiZSByZXR1cm5lZC5cbiAqIElmIHRoZSBmaWxlIGRvZXMgbm90IGV4aXN0LCBpdCB3aWxsIGJlIGNyZWF0ZWQgYW5kIHJldHVybmVkLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgYXBwbGljYXRpb24gaW5zdGFuY2UuXG4gKiBAcGFyYW0gcGF0aCAtIFRoZSBwYXRoIG9mIHRoZSBmaWxlIHRvIGdldCBvciBjcmVhdGUuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIHRoZSBmaWxlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0T3JDcmVhdGVGaWxlU2FmZShhcHA6IEFwcCwgcGF0aDogc3RyaW5nKTogUHJvbWlzZTxURmlsZT4ge1xuICByZXR1cm4gYXNGaWxlKGF3YWl0IGdldE9yQ3JlYXRlQWJzdHJhY3RGaWxlU2FmZShhcHAsIHBhdGgsIEZpbGVTeXN0ZW1UeXBlLkZpbGUpKTtcbn1cblxuLyoqXG4gKiBHZXRzIG9yIGNyZWF0ZXMgYSBmb2xkZXIgc2FmZWx5IGluIHRoZSBzcGVjaWZpZWQgcGF0aC5cbiAqXG4gKiBJZiB0aGUgZm9sZGVyIGFscmVhZHkgZXhpc3RzLCBpdCB3aWxsIGJlIHJldHVybmVkLlxuICogSWYgdGhlIGZvbGRlciBkb2VzIG5vdCBleGlzdCwgaXQgd2lsbCBiZSBjcmVhdGVkIGFuZCByZXR1cm5lZC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGggLSBUaGUgcGF0aCBvZiB0aGUgZm9sZGVyIHRvIGdldCBvciBjcmVhdGUuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIHRoZSBmb2xkZXIuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXRPckNyZWF0ZUZvbGRlclNhZmUoYXBwOiBBcHAsIHBhdGg6IHN0cmluZyk6IFByb21pc2U8VEZvbGRlcj4ge1xuICByZXR1cm4gYXNGb2xkZXIoYXdhaXQgZ2V0T3JDcmVhdGVBYnN0cmFjdEZpbGVTYWZlKGFwcCwgcGF0aCwgRmlsZVN5c3RlbVR5cGUuRm9sZGVyKSk7XG59XG5cbi8qKlxuICogR2V0cyBhIHNhZmUgcmVuYW1lIHBhdGggZm9yIGEgZmlsZS5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIG9sZFBhdGhPckFic3RyYWN0RmlsZSAtIFRoZSBvbGQgcGF0aCBvciBhYnN0cmFjdCBmaWxlIHRvIHJlbmFtZS5cbiAqIEBwYXJhbSBuZXdQYXRoIC0gVGhlIG5ldyBwYXRoIHRvIHJlbmFtZSB0aGUgYWJzdHJhY3QgZmlsZSB0by5cbiAqIEByZXR1cm5zIFRoZSBzYWZlIHJlbmFtZSBwYXRoIGZvciB0aGUgYWJzdHJhY3QgZmlsZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFNhZmVSZW5hbWVQYXRoKGFwcDogQXBwLCBvbGRQYXRoT3JBYnN0cmFjdEZpbGU6IFBhdGhPckFic3RyYWN0RmlsZSwgbmV3UGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3Qgb2xkUGF0aCA9IGdldFBhdGgoYXBwLCBvbGRQYXRoT3JBYnN0cmFjdEZpbGUpO1xuXG4gIGlmIChhcHAudmF1bHQuYWRhcHRlci5pbnNlbnNpdGl2ZSkge1xuICAgIGxldCBmb2xkZXJQYXRoID0gZGlybmFtZShuZXdQYXRoKTtcbiAgICBsZXQgbm9uRXhpc3RpbmdQYXRoID0gYmFzZW5hbWUobmV3UGF0aCk7XG4gICAgbGV0IGZvbGRlcjogbnVsbCB8IFRGb2xkZXI7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby11bm5lY2Vzc2FyeS1jb25kaXRpb24gLS0gVGhlcmUgaXMgbm8gZWxlZ2FudCB3YXkgdG8gcGVyZm9ybSBpbmZpbml0ZSBsb29wcy5cbiAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgZm9sZGVyID0gZ2V0Rm9sZGVyT3JOdWxsKGFwcCwgZm9sZGVyUGF0aCwgdHJ1ZSk7XG4gICAgICBpZiAoZm9sZGVyKSB7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgbm9uRXhpc3RpbmdQYXRoID0gam9pbihiYXNlbmFtZShmb2xkZXJQYXRoKSwgbm9uRXhpc3RpbmdQYXRoKTtcbiAgICAgIGZvbGRlclBhdGggPSBkaXJuYW1lKGZvbGRlclBhdGgpO1xuICAgIH1cbiAgICBuZXdQYXRoID0gam9pbihmb2xkZXIuZ2V0UGFyZW50UHJlZml4KCksIG5vbkV4aXN0aW5nUGF0aCk7XG4gIH1cblxuICBpZiAob2xkUGF0aC50b0xvd2VyQ2FzZSgpID09PSBuZXdQYXRoLnRvTG93ZXJDYXNlKCkpIHtcbiAgICByZXR1cm4gbmV3UGF0aDtcbiAgfVxuXG4gIHJldHVybiBnZXRBdmFpbGFibGVQYXRoKGFwcCwgbmV3UGF0aCk7XG59XG5cbi8qKlxuICogSW52b2tlcyBhIGZ1bmN0aW9uIHdpdGggdGhlIGZpbGUgc3lzdGVtIGxvY2suXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoT3JGaWxlIC0gVGhlIHBhdGggb3IgZmlsZSB0byBleGVjdXRlIHRoZSBmdW5jdGlvbiB3aXRoIHRoZSBmaWxlIHN5c3RlbSBsb2NrIG9mLlxuICogQHBhcmFtIGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGV4ZWN1dGUuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBpbnZva2VXaXRoRmlsZVN5c3RlbUxvY2soYXBwOiBBcHAsIHBhdGhPckZpbGU6IFBhdGhPckZpbGUsIGZuOiAoY29udGVudDogc3RyaW5nKSA9PiB2b2lkKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGZpbGUgPSBnZXRGaWxlKGFwcCwgcGF0aE9yRmlsZSk7XG4gIGF3YWl0IGFwcC52YXVsdC5wcm9jZXNzKGZpbGUsIChjb250ZW50KSA9PiB7XG4gICAgZm4oY29udGVudCk7XG4gICAgcmV0dXJuIGNvbnRlbnQ7XG4gIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIHBhdGggb3IgZmlsZSBpcyBhIGNoaWxkIG9mIGFub3RoZXIgcGF0aCBvciBmaWxlLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgYXBwbGljYXRpb24gaW5zdGFuY2UuXG4gKiBAcGFyYW0gYSAtIFRoZSBmaXJzdCBwYXRoIG9yIGZpbGUuXG4gKiBAcGFyYW0gYiAtIFRoZSBzZWNvbmQgcGF0aCBvciBmaWxlLlxuICogQHJldHVybnMgQSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgZmlyc3QgcGF0aCBvciBmaWxlIGlzIGEgY2hpbGQgb2YgdGhlIHNlY29uZCBwYXRoIG9yIGZpbGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NoaWxkKGFwcDogQXBwLCBhOiBQYXRoT3JBYnN0cmFjdEZpbGUsIGI6IFBhdGhPckFic3RyYWN0RmlsZSk6IGJvb2xlYW4ge1xuICBjb25zdCBhUGF0aCA9IGdldFBhdGgoYXBwLCBhKTtcbiAgY29uc3QgYlBhdGggPSBnZXRQYXRoKGFwcCwgYik7XG5cbiAgaWYgKGFQYXRoID09PSBiUGF0aCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGlmIChiUGF0aCA9PT0gJy8nKSB7XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICByZXR1cm4gYVBhdGguc3RhcnRzV2l0aChgJHtiUGF0aH0vYCk7XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgcGF0aCBvciBmaWxlIGlzIGEgY2hpbGQgb3Igc2VsZiBvZiBhbm90aGVyIHBhdGggb3IgZmlsZS5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIGEgLSBUaGUgZmlyc3QgcGF0aCBvciBmaWxlLlxuICogQHBhcmFtIGIgLSBUaGUgc2Vjb25kIHBhdGggb3IgZmlsZS5cbiAqIEByZXR1cm5zIEEgYm9vbGVhbiBpbmRpY2F0aW5nIHdoZXRoZXIgdGhlIGZpcnN0IHBhdGggb3IgZmlsZSBpcyBhIGNoaWxkIG9yIHNlbGYgb2YgdGhlIHNlY29uZCBwYXRoIG9yIGZpbGUuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NoaWxkT3JTZWxmKGFwcDogQXBwLCBhOiBQYXRoT3JBYnN0cmFjdEZpbGUsIGI6IFBhdGhPckFic3RyYWN0RmlsZSk6IGJvb2xlYW4ge1xuICBjb25zdCBhUGF0aCA9IGdldFBhdGgoYXBwLCBhKTtcbiAgY29uc3QgYlBhdGggPSBnZXRQYXRoKGFwcCwgYik7XG4gIHJldHVybiBhUGF0aCA9PT0gYlBhdGggfHwgaXNDaGlsZChhcHAsIGEsIGIpO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiBhIGZvbGRlciBpcyBlbXB0eS5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGhPckZvbGRlciAtIFRoZSBwYXRoIG9yIGZvbGRlciB0byBjaGVjay5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gYSBib29sZWFuIGluZGljYXRpbmcgd2hldGhlciB0aGUgZm9sZGVyIGlzIGVtcHR5LlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaXNFbXB0eUZvbGRlcihhcHA6IEFwcCwgcGF0aE9yRm9sZGVyOiBQYXRoT3JGb2xkZXIpOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgY29uc3QgbGlzdGVkRmlsZXMgPSBhd2FpdCBsaXN0U2FmZShhcHAsIGdldFBhdGgoYXBwLCBwYXRoT3JGb2xkZXIpKTtcbiAgcmV0dXJuIGxpc3RlZEZpbGVzLmZpbGVzLmxlbmd0aCA9PT0gMCAmJiBsaXN0ZWRGaWxlcy5mb2xkZXJzLmxlbmd0aCA9PT0gMDtcbn1cblxuLyoqXG4gKiBTYWZlbHkgbGlzdHMgdGhlIGZpbGVzIGFuZCBmb2xkZXJzIGF0IHRoZSBzcGVjaWZpZWQgcGF0aCBpbiB0aGUgdmF1bHQuXG4gKlxuICogQHBhcmFtIGFwcCAtIFRoZSBPYnNpZGlhbiBhcHBsaWNhdGlvbiBpbnN0YW5jZS5cbiAqIEBwYXJhbSBwYXRoT3JGb2xkZXIgLSBUaGUgcGF0aCBvciBmb2xkZXIgdG8gbGlzdC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gYSB7QGxpbmsgTGlzdGVkRmlsZXN9IG9iamVjdCBjb250YWluaW5nIHRoZSBsaXN0ZWQgZmlsZXMgYW5kIGZvbGRlcnMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBsaXN0U2FmZShhcHA6IEFwcCwgcGF0aE9yRm9sZGVyOiBQYXRoT3JGb2xkZXIpOiBQcm9taXNlPExpc3RlZEZpbGVzPiB7XG4gIGNvbnN0IHBhdGggPSBnZXRQYXRoKGFwcCwgcGF0aE9yRm9sZGVyKTtcbiAgY29uc3QgRU1QVFkgPSB7IGZpbGVzOiBbXSwgZm9sZGVyczogW10gfTtcblxuICBpZiAoKGF3YWl0IGFwcC52YXVsdC5hZGFwdGVyLnN0YXQocGF0aCkpPy50eXBlICE9PSAnZm9sZGVyJykge1xuICAgIHJldHVybiBFTVBUWTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgcmV0dXJuIGF3YWl0IGFwcC52YXVsdC5hZGFwdGVyLmxpc3QocGF0aCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoYXdhaXQgYXBwLnZhdWx0LmV4aXN0cyhwYXRoKSkge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gICAgcmV0dXJuIEVNUFRZO1xuICB9XG59XG5cbi8qKlxuICogUHJvY2Vzc2VzIGEgZmlsZSB3aXRoIHJldHJ5IGxvZ2ljLCB1cGRhdGluZyBpdHMgY29udGVudCBiYXNlZCBvbiBhIHByb3ZpZGVkIHZhbHVlIG9yIGZ1bmN0aW9uLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgYXBwbGljYXRpb24gaW5zdGFuY2UsIHR5cGljYWxseSB1c2VkIGZvciBhY2Nlc3NpbmcgdGhlIHZhdWx0LlxuICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgcGF0aCBvciBmaWxlIHRvIGJlIHByb2Nlc3NlZC4gSXQgY2FuIGJlIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgcGF0aCBvciBhIGZpbGUgb2JqZWN0LlxuICogQHBhcmFtIG5ld0NvbnRlbnRQcm92aWRlciAtIEEgdmFsdWUgcHJvdmlkZXIgdGhhdCByZXR1cm5zIHRoZSBuZXcgY29udGVudCBiYXNlZCBvbiB0aGUgb2xkIGNvbnRlbnQgb2YgdGhlIGZpbGUuXG4gKiBJdCBjYW4gYmUgYSBzdHJpbmcgb3IgYSBmdW5jdGlvbiB0aGF0IHRha2VzIHRoZSBvbGQgY29udGVudCBhcyBhbiBhcmd1bWVudCBhbmQgcmV0dXJucyB0aGUgbmV3IGNvbnRlbnQuXG4gKiBJZiBmdW5jdGlvbiBpcyBwcm92aWRlZCwgaXQgc2hvdWxkIHJldHVybiBgbnVsbGAgaWYgdGhlIHByb2Nlc3Mgc2hvdWxkIGJlIHJldHJpZWQuXG4gKiBAcGFyYW0gb3B0aW9ucyAtIE9wdGlvbmFsIG9wdGlvbnMgZm9yIHByb2Nlc3NpbmcvcmV0cnlpbmcgdGhlIG9wZXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHByb2Nlc3MgaXMgY29tcGxldGUuXG4gKlxuICogQHRocm93cyBXaWxsIHRocm93IGFuIGVycm9yIGlmIHRoZSBwcm9jZXNzIGZhaWxzIGFmdGVyIHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIHJldHJpZXMgb3IgdGltZW91dC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHByb2Nlc3MoXG4gIGFwcDogQXBwLFxuICBwYXRoT3JGaWxlOiBQYXRoT3JGaWxlLFxuICBuZXdDb250ZW50UHJvdmlkZXI6IFZhbHVlUHJvdmlkZXI8bnVsbCB8IHN0cmluZywgW3N0cmluZ10+LFxuICBvcHRpb25zOiBQcm9jZXNzT3B0aW9ucyA9IHt9XG4pOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgREVGQVVMVF9SRVRSWV9PUFRJT05TID0ge1xuICAgIHNob3VsZEZhaWxPbk1pc3NpbmdGaWxlOiB0cnVlLFxuICAgIHNob3VsZExvY2tFZGl0b3JXaGlsZVByb2Nlc3Npbmc6IHRydWUsXG4gICAgc2hvdWxkU2hvd1RpbWVvdXROb3RpY2U6IHRydWUsXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLW1hZ2ljLW51bWJlcnMgLS0gRGVmYXVsdCB2YWx1ZS5cbiAgICB0aW1lb3V0SW5NaWxsaXNlY29uZHM6IDUwMFxuICB9O1xuICBjb25zdCBmdWxsT3B0aW9ucyA9IHsgLi4uREVGQVVMVF9SRVRSWV9PUFRJT05TLCAuLi5vcHRpb25zIH07XG4gIGNvbnN0IGFib3J0Q29udHJvbGxlciA9IG5ldyBBYm9ydENvbnRyb2xsZXIoKTtcbiAgZnVsbE9wdGlvbnMuYWJvcnRTaWduYWwgPSBhYm9ydFNpZ25hbEFueShmdWxsT3B0aW9ucy5hYm9ydFNpZ25hbCwgYWJvcnRDb250cm9sbGVyLnNpZ25hbCk7XG4gIGNvbnN0IHBhdGggPSBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSk7XG5cbiAgbGV0IGFjdGl2ZUxlYWZDaGFuZ2VFdmVudFJlZjogRXZlbnRSZWYgfCBudWxsID0gbnVsbDtcblxuICBpZiAoZnVsbE9wdGlvbnMuc2hvdWxkTG9ja0VkaXRvcldoaWxlUHJvY2Vzc2luZykge1xuICAgIGZvciAoY29uc3QgbGVhZiBvZiBhcHAud29ya3NwYWNlLmdldExlYXZlc09mVHlwZShWaWV3VHlwZS5NYXJrZG93bikpIHtcbiAgICAgIGlmIChsZWFmLnZpZXcgaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgJiYgbGVhZi52aWV3LmZpbGU/LnBhdGggPT09IHBhdGgpIHtcbiAgICAgICAgbG9ja0VkaXRvcihsZWFmLnZpZXcuZWRpdG9yKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBhY3RpdmVMZWFmQ2hhbmdlRXZlbnRSZWYgPSBhcHAud29ya3NwYWNlLm9uKCdhY3RpdmUtbGVhZi1jaGFuZ2UnLCAobGVhZikgPT4ge1xuICAgICAgaWYgKGxlYWY/LnZpZXcgaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgJiYgbGVhZi52aWV3LmZpbGU/LnBhdGggPT09IHBhdGgpIHtcbiAgICAgICAgbG9ja0VkaXRvcihsZWFmLnZpZXcuZWRpdG9yKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHRyeSB7XG4gICAgYXdhaXQgcmV0cnlXaXRoVGltZW91dE5vdGljZSh7XG4gICAgICBhc3luYyBvcGVyYXRpb25GbihhYm9ydFNpZ25hbCkge1xuICAgICAgICBhYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuXG4gICAgICAgIGNvbnN0IG9sZENvbnRlbnQgPSBhd2FpdCByZWFkU2FmZShhcHAsIHBhdGhPckZpbGUpO1xuICAgICAgICBhYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuXG4gICAgICAgIGlmIChvbGRDb250ZW50ID09PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuIGhhbmRsZU1pc3NpbmdGaWxlKCk7XG4gICAgICAgIH1cblxuICAgICAgICBjb25zdCBuZXdDb250ZW50ID0gYXdhaXQgcmVzb2x2ZVZhbHVlKG5ld0NvbnRlbnRQcm92aWRlciwgYWJvcnRTaWduYWwsIG9sZENvbnRlbnQpO1xuICAgICAgICBhYm9ydFNpZ25hbC50aHJvd0lmQWJvcnRlZCgpO1xuXG4gICAgICAgIGlmIChuZXdDb250ZW50ID09PSBudWxsKSB7XG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgbGV0IGlzU3VjY2VzcyA9IHRydWU7XG4gICAgICAgIGNvbnN0IGRvZXNGaWxlRXhpc3QgPSBhd2FpdCBpbnZva2VGaWxlQWN0aW9uU2FmZShhcHAsIHBhdGhPckZpbGUsIGFzeW5jIChmaWxlKSA9PiB7XG4gICAgICAgICAgYWJvcnRTaWduYWwudGhyb3dJZkFib3J0ZWQoKTtcbiAgICAgICAgICBhd2FpdCBhcHAudmF1bHQucHJvY2VzcyhmaWxlLCAoY29udGVudCkgPT4ge1xuICAgICAgICAgICAgYWJvcnRTaWduYWwudGhyb3dJZkFib3J0ZWQoKTtcbiAgICAgICAgICAgIGlmIChjb250ZW50ICE9PSBvbGRDb250ZW50KSB7XG4gICAgICAgICAgICAgIGdldExpYkRlYnVnZ2VyKCdWYXVsdDpwcm9jZXNzJykoJ0NvbnRlbnQgaGFzIGNoYW5nZWQgc2luY2UgaXQgd2FzIHJlYWQuIFJldHJ5aW5nLi4uJywge1xuICAgICAgICAgICAgICAgIGFjdHVhbENvbnRlbnQ6IGNvbnRlbnQsXG4gICAgICAgICAgICAgICAgZXhwZWN0ZWRDb250ZW50OiBvbGRDb250ZW50LFxuICAgICAgICAgICAgICAgIHBhdGg6IGZpbGUucGF0aFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgaXNTdWNjZXNzID0gZmFsc2U7XG4gICAgICAgICAgICAgIHJldHVybiBjb250ZW50O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbmV3Q29udGVudDtcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIGFib3J0U2lnbmFsLnRocm93SWZBYm9ydGVkKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghZG9lc0ZpbGVFeGlzdCkge1xuICAgICAgICAgIHJldHVybiBoYW5kbGVNaXNzaW5nRmlsZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGlzU3VjY2VzcztcblxuICAgICAgICBmdW5jdGlvbiBoYW5kbGVNaXNzaW5nRmlsZSgpOiBib29sZWFuIHtcbiAgICAgICAgICBpZiAoZnVsbE9wdGlvbnMuc2hvdWxkRmFpbE9uTWlzc2luZ0ZpbGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgRmlsZSAnJHtwYXRofScgbm90IGZvdW5kYCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgb3BlcmF0aW9uTmFtZTogdCgoJCkgPT4gJC5vYnNpZGlhbkRldlV0aWxzLnZhdWx0LnByb2Nlc3NGaWxlLCB7IGZpbGVQYXRoOiBwYXRoIH0pLFxuICAgICAgcmV0cnlPcHRpb25zOiBmdWxsT3B0aW9ucyxcbiAgICAgIHNob3VsZFNob3dUaW1lb3V0Tm90aWNlOiBmdWxsT3B0aW9ucy5zaG91bGRTaG93VGltZW91dE5vdGljZVxuICAgIH0pO1xuICB9IGZpbmFsbHkge1xuICAgIGFjdGl2ZUxlYWZDaGFuZ2VFdmVudFJlZj8uZS5vZmZyZWYoYWN0aXZlTGVhZkNoYW5nZUV2ZW50UmVmKTtcbiAgICBmb3IgKGNvbnN0IGxlYWYgb2YgYXBwLndvcmtzcGFjZS5nZXRMZWF2ZXNPZlR5cGUoVmlld1R5cGUuTWFya2Rvd24pKSB7XG4gICAgICBpZiAobGVhZi52aWV3IGluc3RhbmNlb2YgTWFya2Rvd25WaWV3ICYmIGxlYWYudmlldy5maWxlPy5wYXRoID09PSBwYXRoKSB7XG4gICAgICAgIHVubG9ja0VkaXRvcihsZWFmLnZpZXcuZWRpdG9yKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBSZWFkcyB0aGUgY29udGVudCBvZiBhIGZpbGUgc2FmZWx5IGZyb20gdGhlIHZhdWx0LlxuICpcbiAqIEl0IGNvdmVycyB0aGUgY2FzZSB3aGVuIHRoZSBmaWxlIHdhcyByZW1vdmVkIGR1cmluZyB0aGUgcmVhZGluZy5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgcGF0aCBvciBmaWxlIHRvIHJlYWQuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIHRoZSBjb250ZW50IG9mIHRoZSBmaWxlIG9yIGBudWxsYCBpZiB0aGUgZmlsZSBpcyBtaXNzaW5nIG9yIGRlbGV0ZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiByZWFkU2FmZShhcHA6IEFwcCwgcGF0aE9yRmlsZTogUGF0aE9yRmlsZSk6IFByb21pc2U8bnVsbCB8IHN0cmluZz4ge1xuICBsZXQgY29udGVudDogbnVsbCB8IHN0cmluZyA9IG51bGw7XG4gIGF3YWl0IGludm9rZUZpbGVBY3Rpb25TYWZlKGFwcCwgcGF0aE9yRmlsZSwgYXN5bmMgKGZpbGUpID0+IHtcbiAgICBhd2FpdCBzYXZlTm90ZShhcHAsIGZpbGUpO1xuICAgIGNvbnRlbnQgPSBhd2FpdCBhcHAudmF1bHQucmVhZChmaWxlKTtcbiAgfSk7XG4gIHJldHVybiBjb250ZW50O1xufVxuXG4vKipcbiAqIFJlbmFtZXMgYSBmaWxlIHNhZmVseSBpbiB0aGUgdmF1bHQuXG4gKiBJZiB0aGUgbmV3IHBhdGggYWxyZWFkeSBleGlzdHMsIHRoZSBmaWxlIHdpbGwgYmUgcmVuYW1lZCB0byBhbiBhdmFpbGFibGUgcGF0aC5cbiAqXG4gKiBAcGFyYW0gYXBwIC0gVGhlIGFwcGxpY2F0aW9uIGluc3RhbmNlLlxuICogQHBhcmFtIG9sZFBhdGhPckFic3RyYWN0RmlsZSAtIFRoZSBvbGQgcGF0aCBvciBmaWxlIHRvIHJlbmFtZS5cbiAqIEBwYXJhbSBuZXdQYXRoIC0gVGhlIG5ldyBwYXRoIHRvIHJlbmFtZSB0aGUgZmlsZSB0by5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgdG8gdGhlIG5ldyBwYXRoIG9mIHRoZSBmaWxlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVuYW1lU2FmZShhcHA6IEFwcCwgb2xkUGF0aE9yQWJzdHJhY3RGaWxlOiBQYXRoT3JBYnN0cmFjdEZpbGUsIG5ld1BhdGg6IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IG9sZEFic3RyYWN0RmlsZSA9IGdldEFic3RyYWN0RmlsZShhcHAsIG9sZFBhdGhPckFic3RyYWN0RmlsZSk7XG5cbiAgY29uc3QgbmV3QXZhaWxhYmxlUGF0aCA9IGdldFNhZmVSZW5hbWVQYXRoKGFwcCwgb2xkUGF0aE9yQWJzdHJhY3RGaWxlLCBuZXdQYXRoKTtcblxuICBpZiAob2xkQWJzdHJhY3RGaWxlLnBhdGgudG9Mb3dlckNhc2UoKSA9PT0gbmV3QXZhaWxhYmxlUGF0aC50b0xvd2VyQ2FzZSgpKSB7XG4gICAgaWYgKG9sZEFic3RyYWN0RmlsZS5wYXRoICE9PSBuZXdQYXRoKSB7XG4gICAgICBhd2FpdCBhcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShvbGRBYnN0cmFjdEZpbGUsIG5ld0F2YWlsYWJsZVBhdGgpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3QXZhaWxhYmxlUGF0aDtcbiAgfVxuXG4gIGNvbnN0IG5ld0ZvbGRlclBhdGggPSBwYXJlbnRGb2xkZXJQYXRoKG5ld0F2YWlsYWJsZVBhdGgpO1xuICBhd2FpdCBjcmVhdGVGb2xkZXJTYWZlKGFwcCwgbmV3Rm9sZGVyUGF0aCk7XG5cbiAgdHJ5IHtcbiAgICBhd2FpdCBhcHAuZmlsZU1hbmFnZXIucmVuYW1lRmlsZShvbGRBYnN0cmFjdEZpbGUsIG5ld0F2YWlsYWJsZVBhdGgpO1xuICB9IGNhdGNoIChlKSB7XG4gICAgaWYgKCFhd2FpdCBhcHAudmF1bHQuZXhpc3RzKG5ld0F2YWlsYWJsZVBhdGgpIHx8IGF3YWl0IGFwcC52YXVsdC5leGlzdHMob2xkQWJzdHJhY3RGaWxlLnBhdGgpKSB7XG4gICAgICB0aHJvdyBlO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBuZXdBdmFpbGFibGVQYXRoO1xufVxuXG4vKipcbiAqIFNhdmVzIHRoZSBzcGVjaWZpZWQgbm90ZSBpbiB0aGUgT2JzaWRpYW4gYXBwLlxuICpcbiAqIEBwYXJhbSBhcHAgLSBUaGUgT2JzaWRpYW4gYXBwIGluc3RhbmNlLlxuICogQHBhcmFtIHBhdGhPckZpbGUgLSBUaGUgbm90ZSB0byBiZSBzYXZlZC5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgbm90ZSBpcyBzYXZlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNhdmVOb3RlKGFwcDogQXBwLCBwYXRoT3JGaWxlOiBQYXRoT3JGaWxlKTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghaXNNYXJrZG93bkZpbGUoYXBwLCBwYXRoT3JGaWxlKSkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIGNvbnN0IHBhdGggPSBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSk7XG5cbiAgZm9yIChjb25zdCBsZWFmIG9mIGFwcC53b3Jrc3BhY2UuZ2V0TGVhdmVzT2ZUeXBlKFZpZXdUeXBlLk1hcmtkb3duKSkge1xuICAgIGlmIChsZWFmLnZpZXcgaW5zdGFuY2VvZiBNYXJrZG93blZpZXcgJiYgbGVhZi52aWV3LmZpbGU/LnBhdGggPT09IHBhdGggJiYgbGVhZi52aWV3LmRpcnR5KSB7XG4gICAgICBhd2FpdCBsZWFmLnZpZXcuc2F2ZSgpO1xuICAgIH1cbiAgfVxufVxuXG5hc3luYyBmdW5jdGlvbiBpbnZva2VGaWxlQWN0aW9uU2FmZShhcHA6IEFwcCwgcGF0aE9yRmlsZTogUGF0aE9yRmlsZSwgZmlsZUFjdGlvbjogKGZpbGU6IFRGaWxlKSA9PiBQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTxib29sZWFuPiB7XG4gIGNvbnN0IHBhdGggPSBnZXRQYXRoKGFwcCwgcGF0aE9yRmlsZSk7XG4gIGxldCBmaWxlID0gZ2V0RmlsZU9yTnVsbChhcHAsIHBhdGgpO1xuICBpZiAoIWZpbGUgfHwgZmlsZS5kZWxldGVkKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG4gIHRyeSB7XG4gICAgYXdhaXQgZmlsZUFjdGlvbihmaWxlKTtcbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIGZpbGUgPSBnZXRGaWxlT3JOdWxsKGFwcCwgcGF0aCk7XG4gICAgaWYgKCFmaWxlIHx8IGZpbGUuZGVsZXRlZCkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB0aHJvdyBlO1xuICB9XG59XG4iXSwKICAibWFwcGluZ3MiOiAiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFZQTtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1A7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFVUCxTQUFTLHNCQUFzQjtBQUMvQixTQUFTLHNCQUFzQjtBQUMvQixTQUFTLGlCQUFpQjtBQUMxQjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxvQkFBb0I7QUFDN0IsU0FBUyw4QkFBOEI7QUFDdkM7QUFBQSxFQUNFO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUDtBQUFBLEVBQ0U7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QixLQUFLLHFCQUFxQjtBQUVsRSxRQUFNLG1CQUFtQixrQkFBa0IsS0FBSyx1QkFBdUIsT0FBTztBQUU5RSxNQUFJLGdCQUFnQixLQUFLLFlBQVksTUFBTSxpQkFBaUIsWUFBWSxHQUFHO0FBQ3pFLFFBQUksZ0JBQWdCLFNBQVMsU0FBUztBQUNwQyxZQUFNLElBQUksWUFBWSxXQUFXLGlCQUFpQixnQkFBZ0I7QUFBQSxJQUNwRTtBQUNBLFdBQU87QUFBQSxFQUNUO0FBRUEsUUFBTSxnQkFBZ0IsaUJBQWlCLGdCQUFnQjtBQUN2RCxRQUFNLGlCQUFpQixLQUFLLGFBQWE7QUFFekMsTUFBSTtBQUNGLFVBQU0sSUFBSSxZQUFZLFdBQVcsaUJBQWlCLGdCQUFnQjtBQUFBLEVBQ3BFLFNBQVMsR0FBRztBQUNWLFFBQUksQ0FBQyxNQUFNLElBQUksTUFBTSxPQUFPLGdCQUFnQixLQUFLLE1BQU0sSUFBSSxNQUFNLE9BQU8sZ0JBQWdCLElBQUksR0FBRztBQUM3RixZQUFNO0FBQUEsSUFDUjtBQUFBLEVBQ0Y7QUFFQSxTQUFPO0FBQ1Q7QUFTQSxlQUFzQixTQUFTLEtBQVUsWUFBdUM7QUFDOUUsTUFBSSxDQUFDLGVBQWUsS0FBSyxVQUFVLEdBQUc7QUFDcEM7QUFBQSxFQUNGO0FBRUEsUUFBTSxPQUFPLFFBQVEsS0FBSyxVQUFVO0FBRXBDLGFBQVcsUUFBUSxJQUFJLFVBQVUsZ0JBQWdCLFNBQVMsUUFBUSxHQUFHO0FBQ25FLFFBQUksS0FBSyxnQkFBZ0IsZ0JBQWdCLEtBQUssS0FBSyxNQUFNLFNBQVMsUUFBUSxLQUFLLEtBQUssT0FBTztBQUN6RixZQUFNLEtBQUssS0FBSyxLQUFLO0FBQUEsSUFDdkI7QUFBQSxFQUNGO0FBQ0Y7QUFFQSxlQUFlLHFCQUFxQixLQUFVLFlBQXdCLFlBQThEO0FBQ2xJLFFBQU0sT0FBTyxRQUFRLEtBQUssVUFBVTtBQUNwQyxNQUFJLE9BQU8sY0FBYyxLQUFLLElBQUk7QUFDbEMsTUFBSSxDQUFDLFFBQVEsS0FBSyxTQUFTO0FBQ3pCLFdBQU87QUFBQSxFQUNUO0FBQ0EsTUFBSTtBQUNGLFVBQU0sV0FBVyxJQUFJO0FBQ3JCLFdBQU87QUFBQSxFQUNULFNBQVMsR0FBRztBQUNWLFdBQU8sY0FBYyxLQUFLLElBQUk7QUFDOUIsUUFBSSxDQUFDLFFBQVEsS0FBSyxTQUFTO0FBQ3pCLGFBQU87QUFBQSxJQUNUO0FBQ0EsVUFBTTtBQUFBLEVBQ1I7QUFDRjsiLAogICJuYW1lcyI6IFtdCn0K