UNPKG

obsidian-dev-utils

Version:

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

362 lines (354 loc) 46.3 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 { getLibDebugger } from "../Debug.mjs"; import { throwExpression } from "../Error.mjs"; import { ObsidianPluginRepoPaths } from "../obsidian/Plugin/ObsidianPluginRepoPaths.mjs"; import { join } from "../Path.mjs"; import { replaceAll } from "../String.mjs"; import { readdirPosix } from "./Fs.mjs"; import { editJson } from "./JSON.mjs"; import { cp, createInterface, existsSync, readFile, rm, writeFile } from "./NodeModules.mjs"; import { editNpmShrinkWrapJson, editPackageJson, editPackageLockJson, readPackageJson } from "./Npm.mjs"; import { npmRun } from "./NpmRun.mjs"; import { ObsidianDevUtilsRepoPaths } from "./ObsidianDevUtilsRepoPaths.mjs"; import { execFromRoot, resolvePathFromRootSafe } from "./Root.mjs"; var VersionUpdateType = /* @__PURE__ */ ((VersionUpdateType2) => { VersionUpdateType2["Beta"] = "beta"; VersionUpdateType2["Invalid"] = "invalid"; VersionUpdateType2["Major"] = "major"; VersionUpdateType2["Manual"] = "manual"; VersionUpdateType2["Minor"] = "minor"; VersionUpdateType2["Patch"] = "patch"; return VersionUpdateType2; })(VersionUpdateType || {}); async function addGitTag(newVersion) { await execFromRoot(`git tag -a ${newVersion} -m ${newVersion} --force`, { isQuiet: true }); } async function addUpdatedFilesToGit(newVersion) { await execFromRoot(["git", "add", "--all"], { isQuiet: true }); await execFromRoot(`git commit -m ${newVersion} --allow-empty`, { isQuiet: true }); } async function checkGitHubCliInstalled() { try { await execFromRoot("gh --version", { isQuiet: true }); } catch { throw new Error("GitHub CLI is not installed. Please install it from https://cli.github.com/"); } } async function checkGitInstalled() { try { await execFromRoot("git --version", { isQuiet: true }); } catch { throw new Error("Git is not installed. Please install it from https://git-scm.com/"); } } async function checkGitRepoClean() { try { const stdout = await execFromRoot("git status --porcelain --untracked-files=all", { isQuiet: true }); if (stdout) { throw new Error(); } } catch { throw new Error("Git repository is not clean. Please commit or stash your changes before releasing a new version."); } } async function copyUpdatedManifest() { await cp( resolvePathFromRootSafe(ObsidianPluginRepoPaths.ManifestJson), resolvePathFromRootSafe(join(ObsidianPluginRepoPaths.DistBuild, ObsidianPluginRepoPaths.ManifestJson)), { force: true } ); } async function getNewVersion(versionUpdateType) { const versionType = getVersionUpdateType(versionUpdateType); if (versionType === "manual" /* Manual */) { return versionUpdateType; } const packageJson = await readPackageJson(); const currentVersion = packageJson.version ?? ""; const match = /^(?<Major>\d+)\.(?<Minor>\d+)\.(?<Patch>\d+)(?:-beta\.(?<Beta>\d+))?$/.exec(currentVersion); if (!match) { throw new Error(`Invalid current version format: ${currentVersion}`); } let major = Number(match.groups?.["Major"] ?? ""); let minor = Number(match.groups?.["Minor"] ?? ""); let patch = Number(match.groups?.["Patch"] ?? ""); let beta = Number(match.groups?.["Beta"] ?? ""); switch (versionType) { case "beta" /* Beta */: if (beta === 0) { patch++; } beta++; break; case "major" /* Major */: major++; minor = 0; patch = 0; beta = 0; break; case "minor" /* Minor */: minor++; patch = 0; beta = 0; break; case "patch" /* Patch */: if (beta === 0) { patch++; } else { beta = 0; } break; default: throw new Error(`Invalid version update type: ${versionType}`); } return `${String(major)}.${String(minor)}.${String(patch)}${beta > 0 ? `-beta.${String(beta)}` : ""}`; } async function getReleaseNotes(newVersion) { const changelogPath = resolvePathFromRootSafe(ObsidianPluginRepoPaths.ChangelogMd); const content = await readFile(changelogPath, "utf-8"); const newVersionEscaped = replaceAll(newVersion, ".", "\\."); const match = new RegExp(` ## ${newVersionEscaped} ((.| )+?) ##`).exec(content); let releaseNotes = match?.[1] ? `${match[1]} ` : ""; const tags = (await execFromRoot("git tag --sort=-creatordate", { isQuiet: true })).split(/\r?\n/); const previousVersion = tags[1]; let changesUrl; const repoUrl = await execFromRoot("gh repo view --json url -q .url", { isQuiet: true }); if (previousVersion) { changesUrl = `${repoUrl}/compare/${previousVersion}...${newVersion}`; } else { changesUrl = `${repoUrl}/commits/${newVersion}`; } releaseNotes += `**Full Changelog**: ${changesUrl}`; return releaseNotes; } function getVersionUpdateType(versionUpdateType) { const versionUpdateTypeEnum = versionUpdateType; switch (versionUpdateTypeEnum) { case "beta" /* Beta */: case "major" /* Major */: case "minor" /* Minor */: case "patch" /* Patch */: return versionUpdateTypeEnum; default: if (/^\d+\.\d+\.\d+(?:-[\w\d.-]+)?$/.test(versionUpdateType)) { return "manual" /* Manual */; } return "invalid" /* Invalid */; } } async function gitPush() { await execFromRoot("git push --follow-tags --force", { isQuiet: true }); } async function publishGitHubRelease(newVersion, isObsidianPlugin) { let filePaths; if (isObsidianPlugin) { const buildFolder = resolvePathFromRootSafe(ObsidianPluginRepoPaths.DistBuild); const fileNames = await readdirPosix(buildFolder); filePaths = fileNames.map((fileName) => join(buildFolder, fileName)); } else { const resultJson = await execFromRoot(["npm", "pack", "--pack-destination", ObsidianDevUtilsRepoPaths.Dist, "--json"], { isQuiet: true }); const result = JSON.parse(resultJson); filePaths = [ join(ObsidianDevUtilsRepoPaths.Dist, result[0].filename), join(ObsidianDevUtilsRepoPaths.Dist, ObsidianDevUtilsRepoPaths.StylesCss) ]; } filePaths = filePaths.filter((filePath) => existsSync(resolvePathFromRootSafe(filePath))); await execFromRoot([ "gh", "release", "create", newVersion, ...filePaths, "--title", `v${newVersion}`, ...isBeta(newVersion) ? ["--prerelease"] : [], "--notes-file", "-" ], { isQuiet: true, stdin: await getReleaseNotes(newVersion) }); } async function updateChangelog(newVersion) { const HEADER_LINES_COUNT = 2; const changelogPath = resolvePathFromRootSafe(ObsidianPluginRepoPaths.ChangelogMd); let previousChangelogLines; if (existsSync(changelogPath)) { const content = await readFile(changelogPath, "utf-8"); previousChangelogLines = content.split("\n").slice(HEADER_LINES_COUNT); if (previousChangelogLines.at(-1) === "") { previousChangelogLines.pop(); } } else { previousChangelogLines = []; } const lastTag = replaceAll(previousChangelogLines[0] ?? "", "## ", ""); const commitRange = lastTag ? `${lastTag}..HEAD` : "HEAD"; const commitMessagesStr = await execFromRoot(`git log ${commitRange} --format=%B --first-parent -z`, { isQuiet: true }); const commitMessages = commitMessagesStr.split("\0").filter(Boolean).map(toSingleLine); let newChangeLog = `# CHANGELOG ## ${newVersion} `; for (const message of commitMessages) { newChangeLog += `- ${message} `; } if (previousChangelogLines.length > 0) { newChangeLog += "\n"; for (const line of previousChangelogLines) { newChangeLog += `${line} `; } } await writeFile(changelogPath, newChangeLog, "utf-8"); const codeVersion = await execFromRoot("code --version", { isQuiet: true, shouldIgnoreExitCode: true }); const versionDebugger = getLibDebugger("Version"); if (codeVersion) { versionDebugger(`Please update the ${ObsidianPluginRepoPaths.ChangelogMd} file. Close Visual Studio Code when you are done...`); await execFromRoot(["code", "-w", changelogPath], { isQuiet: true, shouldIgnoreExitCode: true }); } else { versionDebugger("Could not find Visual Studio Code in your PATH. Using console mode instead."); await createInterface(process.stdin, process.stdout).question( `Please update the ${ObsidianPluginRepoPaths.ChangelogMd} file. Press Enter when you are done...` ); } } async function updateVersion(versionUpdateType, prepareGitHubRelease) { if (!versionUpdateType) { const npmOldVersion = process.env["npm_old_version"]; const npmNewVersion = process.env["npm_new_version"]; if (npmOldVersion && npmNewVersion) { await updateVersionInFiles(npmOldVersion); await updateVersion(npmNewVersion, prepareGitHubRelease); return; } throw new Error("No version update type provided"); } const isObsidianPlugin = existsSync(resolvePathFromRootSafe(ObsidianPluginRepoPaths.ManifestJson)); validate(versionUpdateType); await checkGitInstalled(); await checkGitRepoClean(); await checkGitHubCliInstalled(); await npmRun("format:check"); await npmRun("spellcheck"); await npmRun("build"); await npmRun("lint"); const newVersion = await getNewVersion(versionUpdateType); await updateVersionInFiles(newVersion); if (isObsidianPlugin) { await updateVersionInFilesForPlugin(newVersion); } await updateChangelog(newVersion); await addUpdatedFilesToGit(newVersion); await addGitTag(newVersion); await gitPush(); await prepareGitHubRelease?.(newVersion); await publishGitHubRelease(newVersion, isObsidianPlugin); } async function updateVersionInFiles(newVersion) { await editPackageJson((packageJson) => { packageJson.version = newVersion; }); await editPackageLockJson(update, { shouldSkipIfMissing: true }); await editNpmShrinkWrapJson(update, { shouldSkipIfMissing: true }); function update(packageLockJson) { packageLockJson.version = newVersion; const defaultPackage = packageLockJson.packages?.[""]; if (defaultPackage) { defaultPackage.version = newVersion; } } } function validate(versionUpdateType) { if (getVersionUpdateType(versionUpdateType) === "invalid" /* Invalid */) { throw new Error("Invalid version update type. Please use 'major', 'minor', 'patch', or 'x.y.z[-suffix]' format."); } } async function getLatestObsidianVersion() { const response = await fetch("https://api.github.com/repos/obsidianmd/obsidian-releases/releases/latest"); const obsidianReleasesJson = await response.json(); return obsidianReleasesJson.name ?? throwExpression(new Error("Could not find the name of the latest Obsidian release")); } function isBeta(version) { return version.includes("beta" /* Beta */); } function toSingleLine(str) { const lines = str.split(/\r?\n/).filter(Boolean); return lines.join(" "); } async function updateVersionInFilesForPlugin(newVersion) { const manifestBetaJsonPath = resolvePathFromRootSafe(ObsidianPluginRepoPaths.ManifestBetaJson); if (isBeta(newVersion)) { await cp( resolvePathFromRootSafe(ObsidianPluginRepoPaths.ManifestJson), manifestBetaJsonPath, { force: true } ); await editJson(ObsidianPluginRepoPaths.ManifestBetaJson, (manifest) => { manifest.version = newVersion; }); } else { const latestObsidianVersion = await getLatestObsidianVersion(); await editJson(ObsidianPluginRepoPaths.ManifestJson, (manifest) => { manifest.minAppVersion = latestObsidianVersion; manifest.version = newVersion; }); await editJson(ObsidianPluginRepoPaths.VersionsJson, (versions) => { versions[newVersion] = latestObsidianVersion; }); if (existsSync(manifestBetaJsonPath)) { await rm(manifestBetaJsonPath); } } await copyUpdatedManifest(); } export { VersionUpdateType, addGitTag, addUpdatedFilesToGit, checkGitHubCliInstalled, checkGitInstalled, checkGitRepoClean, copyUpdatedManifest, getNewVersion, getReleaseNotes, getVersionUpdateType, gitPush, publishGitHubRelease, updateChangelog, updateVersion, updateVersionInFiles, validate }; //# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsiLi4vLi4vLi4vLi4vc3JjL1NjcmlwdFV0aWxzL3ZlcnNpb24udHMiXSwKICAic291cmNlc0NvbnRlbnQiOiBbIi8qKlxuICogQHBhY2thZ2VEb2N1bWVudGF0aW9uXG4gKlxuICogVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyB2ZXJzaW9uIHVwZGF0ZXMgaW4gYSBwcm9qZWN0LlxuICogSXQgaW5jbHVkZXMgdGFza3Mgc3VjaCBhcyB2YWxpZGF0aW5nIHZlcnNpb24gdXBkYXRlIHR5cGVzLCBjaGVja2luZyB0aGUgc3RhdGVcbiAqIG9mIEdpdCBhbmQgR2l0SHViIENMSSwgdXBkYXRpbmcgdmVyc2lvbiBudW1iZXJzIGluIGZpbGVzLCBhbmQgcGVyZm9ybWluZ1xuICogR2l0IG9wZXJhdGlvbnMgc3VjaCBhcyB0YWdnaW5nIGFuZCBwdXNoaW5nLlxuICovXG5cbmltcG9ydCB0eXBlIHsgUGFja2FnZUxvY2tKc29uIH0gZnJvbSAnLi9OcG0udHMnO1xuXG5pbXBvcnQgeyBnZXRMaWJEZWJ1Z2dlciB9IGZyb20gJy4uL0RlYnVnLnRzJztcbmltcG9ydCB7IHRocm93RXhwcmVzc2lvbiB9IGZyb20gJy4uL0Vycm9yLnRzJztcbmltcG9ydCB7IE9ic2lkaWFuUGx1Z2luUmVwb1BhdGhzIH0gZnJvbSAnLi4vb2JzaWRpYW4vUGx1Z2luL09ic2lkaWFuUGx1Z2luUmVwb1BhdGhzLnRzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICcuLi9QYXRoLnRzJztcbmltcG9ydCB7IHJlcGxhY2VBbGwgfSBmcm9tICcuLi9TdHJpbmcudHMnO1xuaW1wb3J0IHsgcmVhZGRpclBvc2l4IH0gZnJvbSAnLi9Gcy50cyc7XG5pbXBvcnQgeyBlZGl0SnNvbiB9IGZyb20gJy4vSlNPTi50cyc7XG5pbXBvcnQge1xuICBjcCxcbiAgY3JlYXRlSW50ZXJmYWNlLFxuICBleGlzdHNTeW5jLFxuICByZWFkRmlsZSxcbiAgcm0sXG4gIHdyaXRlRmlsZVxufSBmcm9tICcuL05vZGVNb2R1bGVzLnRzJztcbmltcG9ydCB7XG4gIGVkaXROcG1TaHJpbmtXcmFwSnNvbixcbiAgZWRpdFBhY2thZ2VKc29uLFxuICBlZGl0UGFja2FnZUxvY2tKc29uLFxuICByZWFkUGFja2FnZUpzb25cbn0gZnJvbSAnLi9OcG0udHMnO1xuaW1wb3J0IHsgbnBtUnVuIH0gZnJvbSAnLi9OcG1SdW4udHMnO1xuaW1wb3J0IHsgT2JzaWRpYW5EZXZVdGlsc1JlcG9QYXRocyB9IGZyb20gJy4vT2JzaWRpYW5EZXZVdGlsc1JlcG9QYXRocy50cyc7XG5pbXBvcnQge1xuICBleGVjRnJvbVJvb3QsXG4gIHJlc29sdmVQYXRoRnJvbVJvb3RTYWZlXG59IGZyb20gJy4vUm9vdC50cyc7XG5cbi8qKlxuICogRW51bSByZXByZXNlbnRpbmcgZGlmZmVyZW50IHR5cGVzIG9mIHZlcnNpb24gdXBkYXRlcy5cbiAqL1xuZXhwb3J0IGVudW0gVmVyc2lvblVwZGF0ZVR5cGUge1xuICBCZXRhID0gJ2JldGEnLFxuICBJbnZhbGlkID0gJ2ludmFsaWQnLFxuICBNYWpvciA9ICdtYWpvcicsXG4gIE1hbnVhbCA9ICdtYW51YWwnLFxuICBNaW5vciA9ICdtaW5vcicsXG4gIFBhdGNoID0gJ3BhdGNoJ1xufVxuXG4vKipcbiAqIFR5cGUgcmVwcmVzZW50aW5nIHRoZSBtYW5pZmVzdCBmaWxlIGZvcm1hdCBmb3IgT2JzaWRpYW4gcGx1Z2lucy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBNYW5pZmVzdCB7XG4gIC8qKlxuICAgKiBBIG1pbmltdW0gT2JzaWRpYW4gdmVyc2lvbiByZXF1aXJlZCBmb3IgdGhlIHBsdWdpbi5cbiAgICovXG4gIG1pbkFwcFZlcnNpb246IHN0cmluZztcblxuICAvKipcbiAgICogQSB2ZXJzaW9uIG9mIHRoZSBwbHVnaW4uXG4gICAqL1xuICB2ZXJzaW9uOiBzdHJpbmc7XG59XG5cbi8qKlxuICogVHlwZSByZXByZXNlbnRpbmcgdGhlIHN0cnVjdHVyZSBvZiBPYnNpZGlhbiByZWxlYXNlcyBKU09OLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIE9ic2lkaWFuUmVsZWFzZXNKc29uIHtcbiAgLyoqXG4gICAqIEEgbmFtZSBvZiB0aGUgT2JzaWRpYW4gcmVsZWFzZS5cbiAgICovXG4gIG5hbWU6IHN0cmluZztcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgR2l0IHRhZyBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxuICpcbiAqIEBwYXJhbSBuZXdWZXJzaW9uIC0gVGhlIG5ldyB2ZXJzaW9uIG51bWJlciB0byB1c2UgZm9yIHRoZSB0YWcuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHRhZyBoYXMgYmVlbiBjcmVhdGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkR2l0VGFnKG5ld1ZlcnNpb246IHN0cmluZyk6IFByb21pc2U8dm9pZD4ge1xuICBhd2FpdCBleGVjRnJvbVJvb3QoYGdpdCB0YWcgLWEgJHtuZXdWZXJzaW9ufSAtbSAke25ld1ZlcnNpb259IC0tZm9yY2VgLCB7IGlzUXVpZXQ6IHRydWUgfSk7XG59XG5cbi8qKlxuICogQWRkcyB1cGRhdGVkIGZpbGVzIHRvIHRoZSBHaXQgc3RhZ2luZyBhcmVhIGFuZCBjb21taXRzIHRoZW0gd2l0aCB0aGUgbmV3IHZlcnNpb24gbWVzc2FnZS5cbiAqXG4gKiBAcGFyYW0gbmV3VmVyc2lvbiAtIFRoZSBuZXcgdmVyc2lvbiBudW1iZXIgdXNlZCBhcyB0aGUgY29tbWl0IG1lc3NhZ2UuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGZpbGVzIGhhdmUgYmVlbiBhZGRlZCBhbmQgY29tbWl0dGVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkVXBkYXRlZEZpbGVzVG9HaXQobmV3VmVyc2lvbjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGV4ZWNGcm9tUm9vdChbJ2dpdCcsICdhZGQnLCAnLS1hbGwnXSwgeyBpc1F1aWV0OiB0cnVlIH0pO1xuICBhd2FpdCBleGVjRnJvbVJvb3QoYGdpdCBjb21taXQgLW0gJHtuZXdWZXJzaW9ufSAtLWFsbG93LWVtcHR5YCwgeyBpc1F1aWV0OiB0cnVlIH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgR2l0SHViIENMSSBpcyBpbnN0YWxsZWQgb24gdGhlIHN5c3RlbS5cbiAqXG4gKiBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIEdpdEh1YiBDTEkgaXMgbm90IGluc3RhbGxlZC5cbiAqXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBHaXRIdWIgQ0xJIGlzIG5vdCBpbnN0YWxsZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0dpdEh1YkNsaUluc3RhbGxlZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBleGVjRnJvbVJvb3QoJ2doIC0tdmVyc2lvbicsIHsgaXNRdWlldDogdHJ1ZSB9KTtcbiAgfSBjYXRjaCB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdHaXRIdWIgQ0xJIGlzIG5vdCBpbnN0YWxsZWQuIFBsZWFzZSBpbnN0YWxsIGl0IGZyb20gaHR0cHM6Ly9jbGkuZ2l0aHViLmNvbS8nKTtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiBHaXQgaXMgaW5zdGFsbGVkIG9uIHRoZSBzeXN0ZW0uXG4gKlxuICogVGhyb3dzIGFuIGVycm9yIGlmIEdpdCBpcyBub3QgaW5zdGFsbGVkLlxuICpcbiAqIEB0aHJvd3MgRXJyb3IgaWYgR2l0IGlzIG5vdCBpbnN0YWxsZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjaGVja0dpdEluc3RhbGxlZCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgdHJ5IHtcbiAgICBhd2FpdCBleGVjRnJvbVJvb3QoJ2dpdCAtLXZlcnNpb24nLCB7IGlzUXVpZXQ6IHRydWUgfSk7XG4gIH0gY2F0Y2gge1xuICAgIHRocm93IG5ldyBFcnJvcignR2l0IGlzIG5vdCBpbnN0YWxsZWQuIFBsZWFzZSBpbnN0YWxsIGl0IGZyb20gaHR0cHM6Ly9naXQtc2NtLmNvbS8nKTtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgR2l0IHJlcG9zaXRvcnkgaXMgY2xlYW4sIG1lYW5pbmcgdGhlcmUgYXJlIG5vIHVuY29tbWl0dGVkIGNoYW5nZXMuXG4gKlxuICogVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBHaXQgcmVwb3NpdG9yeSBpcyBub3QgY2xlYW4uXG4gKlxuICogQHRocm93cyBFcnJvciBpZiB0aGUgR2l0IHJlcG9zaXRvcnkgaXMgbm90IGNsZWFuLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tHaXRSZXBvQ2xlYW4oKTogUHJvbWlzZTx2b2lkPiB7XG4gIHRyeSB7XG4gICAgY29uc3Qgc3Rkb3V0ID0gYXdhaXQgZXhlY0Zyb21Sb290KCdnaXQgc3RhdHVzIC0tcG9yY2VsYWluIC0tdW50cmFja2VkLWZpbGVzPWFsbCcsIHsgaXNRdWlldDogdHJ1ZSB9KTtcbiAgICBpZiAoc3Rkb3V0KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIHRocm93IG5ldyBFcnJvcignR2l0IHJlcG9zaXRvcnkgaXMgbm90IGNsZWFuLiBQbGVhc2UgY29tbWl0IG9yIHN0YXNoIHlvdXIgY2hhbmdlcyBiZWZvcmUgcmVsZWFzaW5nIGEgbmV3IHZlcnNpb24uJyk7XG4gIH1cbn1cblxuLyoqXG4gKiBDb3BpZXMgdGhlIHVwZGF0ZWQgbWFuaWZlc3QgZmlsZSB0byB0aGUgZGlzdHJpYnV0aW9uIGJ1aWxkIGZvbGRlci5cbiAqXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIGNvcHkgb3BlcmF0aW9uIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29weVVwZGF0ZWRNYW5pZmVzdCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgY3AoXG4gICAgcmVzb2x2ZVBhdGhGcm9tUm9vdFNhZmUoT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTWFuaWZlc3RKc29uKSxcbiAgICByZXNvbHZlUGF0aEZyb21Sb290U2FmZShqb2luKE9ic2lkaWFuUGx1Z2luUmVwb1BhdGhzLkRpc3RCdWlsZCwgT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTWFuaWZlc3RKc29uKSksXG4gICAgeyBmb3JjZTogdHJ1ZSB9XG4gICk7XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIGEgbmV3IHZlcnNpb24gc3RyaW5nIGJhc2VkIG9uIHRoZSBjdXJyZW50IHZlcnNpb24gYW5kIHRoZSBzcGVjaWZpZWQgdXBkYXRlIHR5cGUuXG4gKlxuICogQHBhcmFtIHZlcnNpb25VcGRhdGVUeXBlIC0gVGhlIHR5cGUgb2YgdmVyc2lvbiB1cGRhdGUgKG1ham9yLCBtaW5vciwgcGF0Y2gsIGJldGEsIG9yIG1hbnVhbCkuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHRvIHRoZSBuZXcgdmVyc2lvbiBzdHJpbmcuXG4gKiBAdGhyb3dzIEVycm9yIGlmIHRoZSBjdXJyZW50IHZlcnNpb24gZm9ybWF0IGlzIGludmFsaWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBnZXROZXdWZXJzaW9uKHZlcnNpb25VcGRhdGVUeXBlOiBzdHJpbmcpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCB2ZXJzaW9uVHlwZSA9IGdldFZlcnNpb25VcGRhdGVUeXBlKHZlcnNpb25VcGRhdGVUeXBlKTtcbiAgaWYgKHZlcnNpb25UeXBlID09PSBWZXJzaW9uVXBkYXRlVHlwZS5NYW51YWwpIHtcbiAgICByZXR1cm4gdmVyc2lvblVwZGF0ZVR5cGU7XG4gIH1cblxuICBjb25zdCBwYWNrYWdlSnNvbiA9IGF3YWl0IHJlYWRQYWNrYWdlSnNvbigpO1xuICBjb25zdCBjdXJyZW50VmVyc2lvbiA9IHBhY2thZ2VKc29uLnZlcnNpb24gPz8gJyc7XG5cbiAgY29uc3QgbWF0Y2ggPSAvXig/PE1ham9yPlxcZCspXFwuKD88TWlub3I+XFxkKylcXC4oPzxQYXRjaD5cXGQrKSg/Oi1iZXRhXFwuKD88QmV0YT5cXGQrKSk/JC8uZXhlYyhjdXJyZW50VmVyc2lvbik7XG4gIGlmICghbWF0Y2gpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY3VycmVudCB2ZXJzaW9uIGZvcm1hdDogJHtjdXJyZW50VmVyc2lvbn1gKTtcbiAgfVxuXG4gIGxldCBtYWpvciA9IE51bWJlcihtYXRjaC5ncm91cHM/LlsnTWFqb3InXSA/PyAnJyk7XG4gIGxldCBtaW5vciA9IE51bWJlcihtYXRjaC5ncm91cHM/LlsnTWlub3InXSA/PyAnJyk7XG4gIGxldCBwYXRjaCA9IE51bWJlcihtYXRjaC5ncm91cHM/LlsnUGF0Y2gnXSA/PyAnJyk7XG4gIGxldCBiZXRhID0gTnVtYmVyKG1hdGNoLmdyb3Vwcz8uWydCZXRhJ10gPz8gJycpO1xuXG4gIHN3aXRjaCAodmVyc2lvblR5cGUpIHtcbiAgICBjYXNlIFZlcnNpb25VcGRhdGVUeXBlLkJldGE6XG4gICAgICBpZiAoYmV0YSA9PT0gMCkge1xuICAgICAgICBwYXRjaCsrO1xuICAgICAgfVxuICAgICAgYmV0YSsrO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBWZXJzaW9uVXBkYXRlVHlwZS5NYWpvcjpcbiAgICAgIG1ham9yKys7XG4gICAgICBtaW5vciA9IDA7XG4gICAgICBwYXRjaCA9IDA7XG4gICAgICBiZXRhID0gMDtcbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgVmVyc2lvblVwZGF0ZVR5cGUuTWlub3I6XG4gICAgICBtaW5vcisrO1xuICAgICAgcGF0Y2ggPSAwO1xuICAgICAgYmV0YSA9IDA7XG4gICAgICBicmVhaztcbiAgICBjYXNlIFZlcnNpb25VcGRhdGVUeXBlLlBhdGNoOlxuICAgICAgaWYgKGJldGEgPT09IDApIHtcbiAgICAgICAgcGF0Y2grKztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGJldGEgPSAwO1xuICAgICAgfVxuICAgICAgYnJlYWs7XG4gICAgZGVmYXVsdDpcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCB2ZXJzaW9uIHVwZGF0ZSB0eXBlOiAke3ZlcnNpb25UeXBlfWApO1xuICB9XG5cbiAgcmV0dXJuIGAke1N0cmluZyhtYWpvcil9LiR7U3RyaW5nKG1pbm9yKX0uJHtTdHJpbmcocGF0Y2gpfSR7YmV0YSA+IDAgPyBgLWJldGEuJHtTdHJpbmcoYmV0YSl9YCA6ICcnfWA7XG59XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSByZWxlYXNlIG5vdGVzIGZvciBhIHNwZWNpZmljIHZlcnNpb24gZnJvbSB0aGUgY2hhbmdlbG9nLlxuICpcbiAqIEBwYXJhbSBuZXdWZXJzaW9uIC0gVGhlIG5ldyB2ZXJzaW9uIG51bWJlciBmb3Igd2hpY2ggdG8gZ2V0IHRoZSByZWxlYXNlIG5vdGVzLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byB0aGUgcmVsZWFzZSBub3RlcyBmb3IgdGhlIHNwZWNpZmllZCB2ZXJzaW9uLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0UmVsZWFzZU5vdGVzKG5ld1ZlcnNpb246IHN0cmluZyk6IFByb21pc2U8c3RyaW5nPiB7XG4gIGNvbnN0IGNoYW5nZWxvZ1BhdGggPSByZXNvbHZlUGF0aEZyb21Sb290U2FmZShPYnNpZGlhblBsdWdpblJlcG9QYXRocy5DaGFuZ2Vsb2dNZCk7XG4gIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCByZWFkRmlsZShjaGFuZ2Vsb2dQYXRoLCAndXRmLTgnKTtcbiAgY29uc3QgbmV3VmVyc2lvbkVzY2FwZWQgPSByZXBsYWNlQWxsKG5ld1ZlcnNpb24sICcuJywgJ1xcXFwuJyk7XG4gIGNvbnN0IG1hdGNoID0gbmV3IFJlZ0V4cChgXFxuIyMgJHtuZXdWZXJzaW9uRXNjYXBlZH1cXG5cXG4oKC58XFxuKSs/KVxcblxcbiMjYCkuZXhlYyhjb250ZW50KTtcbiAgbGV0IHJlbGVhc2VOb3RlcyA9IG1hdGNoPy5bMV0gPyBgJHttYXRjaFsxXX1cXG5cXG5gIDogJyc7XG5cbiAgY29uc3QgdGFncyA9IChhd2FpdCBleGVjRnJvbVJvb3QoJ2dpdCB0YWcgLS1zb3J0PS1jcmVhdG9yZGF0ZScsIHsgaXNRdWlldDogdHJ1ZSB9KSkuc3BsaXQoL1xccj9cXG4vKTtcbiAgY29uc3QgcHJldmlvdXNWZXJzaW9uID0gdGFnc1sxXTtcbiAgbGV0IGNoYW5nZXNVcmw6IHN0cmluZztcblxuICBjb25zdCByZXBvVXJsID0gYXdhaXQgZXhlY0Zyb21Sb290KCdnaCByZXBvIHZpZXcgLS1qc29uIHVybCAtcSAudXJsJywgeyBpc1F1aWV0OiB0cnVlIH0pO1xuXG4gIGlmIChwcmV2aW91c1ZlcnNpb24pIHtcbiAgICBjaGFuZ2VzVXJsID0gYCR7cmVwb1VybH0vY29tcGFyZS8ke3ByZXZpb3VzVmVyc2lvbn0uLi4ke25ld1ZlcnNpb259YDtcbiAgfSBlbHNlIHtcbiAgICBjaGFuZ2VzVXJsID0gYCR7cmVwb1VybH0vY29tbWl0cy8ke25ld1ZlcnNpb259YDtcbiAgfVxuXG4gIHJlbGVhc2VOb3RlcyArPSBgKipGdWxsIENoYW5nZWxvZyoqOiAke2NoYW5nZXNVcmx9YDtcbiAgcmV0dXJuIHJlbGVhc2VOb3Rlcztcbn1cblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSB0eXBlIG9mIHZlcnNpb24gdXBkYXRlIGJhc2VkIG9uIHRoZSBpbnB1dCBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHZlcnNpb25VcGRhdGVUeXBlIC0gVGhlIGlucHV0IHN0cmluZyByZXByZXNlbnRpbmcgdGhlIHZlcnNpb24gdXBkYXRlIHR5cGUuXG4gKiBAcmV0dXJucyBUaGUgY29ycmVzcG9uZGluZyBgVmVyc2lvblVwZGF0ZVR5cGVgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0VmVyc2lvblVwZGF0ZVR5cGUodmVyc2lvblVwZGF0ZVR5cGU6IHN0cmluZyk6IFZlcnNpb25VcGRhdGVUeXBlIHtcbiAgY29uc3QgdmVyc2lvblVwZGF0ZVR5cGVFbnVtID0gdmVyc2lvblVwZGF0ZVR5cGUgYXMgVmVyc2lvblVwZGF0ZVR5cGU7XG4gIHN3aXRjaCAodmVyc2lvblVwZGF0ZVR5cGVFbnVtKSB7XG4gICAgY2FzZSBWZXJzaW9uVXBkYXRlVHlwZS5CZXRhOlxuICAgIGNhc2UgVmVyc2lvblVwZGF0ZVR5cGUuTWFqb3I6XG4gICAgY2FzZSBWZXJzaW9uVXBkYXRlVHlwZS5NaW5vcjpcbiAgICBjYXNlIFZlcnNpb25VcGRhdGVUeXBlLlBhdGNoOlxuICAgICAgcmV0dXJuIHZlcnNpb25VcGRhdGVUeXBlRW51bTtcblxuICAgIGRlZmF1bHQ6XG4gICAgICBpZiAoL15cXGQrXFwuXFxkK1xcLlxcZCsoPzotW1xcd1xcZC4tXSspPyQvLnRlc3QodmVyc2lvblVwZGF0ZVR5cGUpKSB7XG4gICAgICAgIHJldHVybiBWZXJzaW9uVXBkYXRlVHlwZS5NYW51YWw7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBWZXJzaW9uVXBkYXRlVHlwZS5JbnZhbGlkO1xuICB9XG59XG5cbi8qKlxuICogUHVzaGVzIGNvbW1pdHMgYW5kIHRhZ3MgdG8gdGhlIHJlbW90ZSBHaXQgcmVwb3NpdG9yeS5cbiAqXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHB1c2ggb3BlcmF0aW9uIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2l0UHVzaCgpOiBQcm9taXNlPHZvaWQ+IHtcbiAgYXdhaXQgZXhlY0Zyb21Sb290KCdnaXQgcHVzaCAtLWZvbGxvdy10YWdzIC0tZm9yY2UnLCB7IGlzUXVpZXQ6IHRydWUgfSk7XG59XG5cbi8qKlxuICogUHVibGlzaGVzIGEgR2l0SHViIHJlbGVhc2UgZm9yIHRoZSBuZXcgdmVyc2lvbi5cbiAqXG4gKiBIYW5kbGVzIHRoZSBjcmVhdGlvbiBvZiBhIHJlbGVhc2UgYW5kIHVwbG9hZGluZyBmaWxlcyBmb3IgZWl0aGVyIGFuIE9ic2lkaWFuIHBsdWdpbiBvciBhbm90aGVyIHByb2plY3QuXG4gKlxuICogQHBhcmFtIG5ld1ZlcnNpb24gLSBUaGUgbmV3IHZlcnNpb24gbnVtYmVyIGZvciB0aGUgcmVsZWFzZS5cbiAqIEBwYXJhbSBpc09ic2lkaWFuUGx1Z2luIC0gQSBib29sZWFuIGluZGljYXRpbmcgaWYgdGhlIHByb2plY3QgaXMgYW4gT2JzaWRpYW4gcGx1Z2luLlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB3aGVuIHRoZSByZWxlYXNlIGhhcyBiZWVuIHB1Ymxpc2hlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1Ymxpc2hHaXRIdWJSZWxlYXNlKG5ld1ZlcnNpb246IHN0cmluZywgaXNPYnNpZGlhblBsdWdpbjogYm9vbGVhbik6IFByb21pc2U8dm9pZD4ge1xuICBsZXQgZmlsZVBhdGhzOiBzdHJpbmdbXTtcblxuICBpZiAoaXNPYnNpZGlhblBsdWdpbikge1xuICAgIGNvbnN0IGJ1aWxkRm9sZGVyID0gcmVzb2x2ZVBhdGhGcm9tUm9vdFNhZmUoT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuRGlzdEJ1aWxkKTtcbiAgICBjb25zdCBmaWxlTmFtZXMgPSBhd2FpdCByZWFkZGlyUG9zaXgoYnVpbGRGb2xkZXIpO1xuICAgIGZpbGVQYXRocyA9IGZpbGVOYW1lcy5tYXAoKGZpbGVOYW1lKSA9PiBqb2luKGJ1aWxkRm9sZGVyLCBmaWxlTmFtZSkpO1xuICB9IGVsc2Uge1xuICAgIGNvbnN0IHJlc3VsdEpzb24gPSBhd2FpdCBleGVjRnJvbVJvb3QoWyducG0nLCAncGFjaycsICctLXBhY2stZGVzdGluYXRpb24nLCBPYnNpZGlhbkRldlV0aWxzUmVwb1BhdGhzLkRpc3QsICctLWpzb24nXSwgeyBpc1F1aWV0OiB0cnVlIH0pO1xuICAgIGNvbnN0IHJlc3VsdCA9IEpTT04ucGFyc2UocmVzdWx0SnNvbikgYXMgW3sgZmlsZW5hbWU6IHN0cmluZyB9XTtcbiAgICBmaWxlUGF0aHMgPSBbXG4gICAgICBqb2luKE9ic2lkaWFuRGV2VXRpbHNSZXBvUGF0aHMuRGlzdCwgcmVzdWx0WzBdLmZpbGVuYW1lKSxcbiAgICAgIGpvaW4oT2JzaWRpYW5EZXZVdGlsc1JlcG9QYXRocy5EaXN0LCBPYnNpZGlhbkRldlV0aWxzUmVwb1BhdGhzLlN0eWxlc0NzcylcbiAgICBdO1xuICB9XG5cbiAgZmlsZVBhdGhzID0gZmlsZVBhdGhzLmZpbHRlcigoZmlsZVBhdGgpID0+IGV4aXN0c1N5bmMocmVzb2x2ZVBhdGhGcm9tUm9vdFNhZmUoZmlsZVBhdGgpKSk7XG5cbiAgYXdhaXQgZXhlY0Zyb21Sb290KFtcbiAgICAnZ2gnLFxuICAgICdyZWxlYXNlJyxcbiAgICAnY3JlYXRlJyxcbiAgICBuZXdWZXJzaW9uLFxuICAgIC4uLmZpbGVQYXRocyxcbiAgICAnLS10aXRsZScsXG4gICAgYHYke25ld1ZlcnNpb259YCxcbiAgICAuLi4oaXNCZXRhKG5ld1ZlcnNpb24pID8gWyctLXByZXJlbGVhc2UnXSA6IFtdKSxcbiAgICAnLS1ub3Rlcy1maWxlJyxcbiAgICAnLSdcbiAgXSwge1xuICAgIGlzUXVpZXQ6IHRydWUsXG4gICAgc3RkaW46IGF3YWl0IGdldFJlbGVhc2VOb3RlcyhuZXdWZXJzaW9uKVxuICB9KTtcbn1cblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBjaGFuZ2Vsb2cgZmlsZSB3aXRoIG5ldyB2ZXJzaW9uIGluZm9ybWF0aW9uIGFuZCBjb21taXQgbWVzc2FnZXMuXG4gKlxuICogVGhpcyBmdW5jdGlvbiByZWFkcyB0aGUgY3VycmVudCBjaGFuZ2Vsb2csIGFwcGVuZHMgbmV3IGVudHJpZXMgZm9yIHRoZSBsYXRlc3QgdmVyc2lvbixcbiAqIGFuZCBwcm9tcHRzIHRoZSB1c2VyIHRvIHJldmlldyB0aGUgY2hhbmdlcy5cbiAqXG4gKiBAcGFyYW0gbmV3VmVyc2lvbiAtIFRoZSBuZXcgdmVyc2lvbiBudW1iZXIgdG8gYmUgYWRkZWQgdG8gdGhlIGNoYW5nZWxvZy5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgY2hhbmdlbG9nIHVwZGF0ZSBpcyBjb21wbGV0ZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHVwZGF0ZUNoYW5nZWxvZyhuZXdWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgSEVBREVSX0xJTkVTX0NPVU5UID0gMjtcbiAgY29uc3QgY2hhbmdlbG9nUGF0aCA9IHJlc29sdmVQYXRoRnJvbVJvb3RTYWZlKE9ic2lkaWFuUGx1Z2luUmVwb1BhdGhzLkNoYW5nZWxvZ01kKTtcbiAgbGV0IHByZXZpb3VzQ2hhbmdlbG9nTGluZXM6IHN0cmluZ1tdO1xuICBpZiAoZXhpc3RzU3luYyhjaGFuZ2Vsb2dQYXRoKSkge1xuICAgIGNvbnN0IGNvbnRlbnQgPSBhd2FpdCByZWFkRmlsZShjaGFuZ2Vsb2dQYXRoLCAndXRmLTgnKTtcbiAgICBwcmV2aW91c0NoYW5nZWxvZ0xpbmVzID0gY29udGVudC5zcGxpdCgnXFxuJykuc2xpY2UoSEVBREVSX0xJTkVTX0NPVU5UKTtcbiAgICBpZiAocHJldmlvdXNDaGFuZ2Vsb2dMaW5lcy5hdCgtMSkgPT09ICcnKSB7XG4gICAgICBwcmV2aW91c0NoYW5nZWxvZ0xpbmVzLnBvcCgpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBwcmV2aW91c0NoYW5nZWxvZ0xpbmVzID0gW107XG4gIH1cblxuICBjb25zdCBsYXN0VGFnID0gcmVwbGFjZUFsbChwcmV2aW91c0NoYW5nZWxvZ0xpbmVzWzBdID8/ICcnLCAnIyMgJywgJycpO1xuICBjb25zdCBjb21taXRSYW5nZSA9IGxhc3RUYWcgPyBgJHtsYXN0VGFnfS4uSEVBRGAgOiAnSEVBRCc7XG4gIGNvbnN0IGNvbW1pdE1lc3NhZ2VzU3RyID0gYXdhaXQgZXhlY0Zyb21Sb290KGBnaXQgbG9nICR7Y29tbWl0UmFuZ2V9IC0tZm9ybWF0PSVCIC0tZmlyc3QtcGFyZW50IC16YCwgeyBpc1F1aWV0OiB0cnVlIH0pO1xuICBjb25zdCBjb21taXRNZXNzYWdlcyA9IGNvbW1pdE1lc3NhZ2VzU3RyLnNwbGl0KCdcXDAnKS5maWx0ZXIoQm9vbGVhbikubWFwKHRvU2luZ2xlTGluZSk7XG5cbiAgbGV0IG5ld0NoYW5nZUxvZyA9IGAjIENIQU5HRUxPR1xcblxcbiMjICR7bmV3VmVyc2lvbn1cXG5cXG5gO1xuXG4gIGZvciAoY29uc3QgbWVzc2FnZSBvZiBjb21taXRNZXNzYWdlcykge1xuICAgIG5ld0NoYW5nZUxvZyArPSBgLSAke21lc3NhZ2V9XFxuYDtcbiAgfVxuXG4gIGlmIChwcmV2aW91c0NoYW5nZWxvZ0xpbmVzLmxlbmd0aCA+IDApIHtcbiAgICBuZXdDaGFuZ2VMb2cgKz0gJ1xcbic7XG4gICAgZm9yIChjb25zdCBsaW5lIG9mIHByZXZpb3VzQ2hhbmdlbG9nTGluZXMpIHtcbiAgICAgIG5ld0NoYW5nZUxvZyArPSBgJHtsaW5lfVxcbmA7XG4gICAgfVxuICB9XG5cbiAgYXdhaXQgd3JpdGVGaWxlKGNoYW5nZWxvZ1BhdGgsIG5ld0NoYW5nZUxvZywgJ3V0Zi04Jyk7XG5cbiAgY29uc3QgY29kZVZlcnNpb24gPSBhd2FpdCBleGVjRnJvbVJvb3QoJ2NvZGUgLS12ZXJzaW9uJywge1xuICAgIGlzUXVpZXQ6IHRydWUsXG4gICAgc2hvdWxkSWdub3JlRXhpdENvZGU6IHRydWVcbiAgfSk7XG4gIGNvbnN0IHZlcnNpb25EZWJ1Z2dlciA9IGdldExpYkRlYnVnZ2VyKCdWZXJzaW9uJyk7XG4gIGlmIChjb2RlVmVyc2lvbikge1xuICAgIHZlcnNpb25EZWJ1Z2dlcihgUGxlYXNlIHVwZGF0ZSB0aGUgJHtPYnNpZGlhblBsdWdpblJlcG9QYXRocy5DaGFuZ2Vsb2dNZH0gZmlsZS4gQ2xvc2UgVmlzdWFsIFN0dWRpbyBDb2RlIHdoZW4geW91IGFyZSBkb25lLi4uYCk7XG4gICAgYXdhaXQgZXhlY0Zyb21Sb290KFsnY29kZScsICctdycsIGNoYW5nZWxvZ1BhdGhdLCB7XG4gICAgICBpc1F1aWV0OiB0cnVlLFxuICAgICAgc2hvdWxkSWdub3JlRXhpdENvZGU6IHRydWVcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICB2ZXJzaW9uRGVidWdnZXIoJ0NvdWxkIG5vdCBmaW5kIFZpc3VhbCBTdHVkaW8gQ29kZSBpbiB5b3VyIFBBVEguIFVzaW5nIGNvbnNvbGUgbW9kZSBpbnN0ZWFkLicpO1xuICAgIGF3YWl0IGNyZWF0ZUludGVyZmFjZShwcm9jZXNzLnN0ZGluLCBwcm9jZXNzLnN0ZG91dCkucXVlc3Rpb24oXG4gICAgICBgUGxlYXNlIHVwZGF0ZSB0aGUgJHtPYnNpZGlhblBsdWdpblJlcG9QYXRocy5DaGFuZ2Vsb2dNZH0gZmlsZS4gUHJlc3MgRW50ZXIgd2hlbiB5b3UgYXJlIGRvbmUuLi5gXG4gICAgKTtcbiAgfVxufVxuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIHZlcnNpb24gb2YgdGhlIHByb2plY3QgYmFzZWQgb24gdGhlIHNwZWNpZmllZCB1cGRhdGUgdHlwZS5cbiAqXG4gKiBUaGlzIGZ1bmN0aW9uIHBlcmZvcm1zIGEgc2VyaWVzIG9mIHRhc2tzIHRvIGhhbmRsZSB2ZXJzaW9uIHVwZGF0ZXM6XG4gKiAxLiBWYWxpZGF0ZXMgdGhlIHZlcnNpb24gdXBkYXRlIHR5cGUuXG4gKiAyLiBDaGVja3MgaWYgR2l0IGFuZCBHaXRIdWIgQ0xJIGFyZSBpbnN0YWxsZWQuXG4gKiAzLiBWZXJpZmllcyB0aGF0IHRoZSBHaXQgcmVwb3NpdG9yeSBpcyBjbGVhbi5cbiAqIDQuIFJ1bnMgc3BlbGxjaGVjayBhbmQgbGludGluZy5cbiAqIDUuIEJ1aWxkcyB0aGUgcHJvamVjdC5cbiAqIDYuIFVwZGF0ZXMgdmVyc2lvbiBpbiBmaWxlcyBhbmQgY2hhbmdlbG9nLlxuICogNy4gQWRkcyB1cGRhdGVkIGZpbGVzIHRvIEdpdCwgdGFncyB0aGUgY29tbWl0LCBhbmQgcHVzaGVzIHRvIHRoZSByZXBvc2l0b3J5LlxuICogOC4gSWYgYW4gT2JzaWRpYW4gcGx1Z2luLCBjb3BpZXMgdGhlIHVwZGF0ZWQgbWFuaWZlc3QgYW5kIHB1Ymxpc2hlcyBhIEdpdEh1YiByZWxlYXNlLlxuICpcbiAqIEBwYXJhbSB2ZXJzaW9uVXBkYXRlVHlwZSAtIFRoZSB0eXBlIG9mIHZlcnNpb24gdXBkYXRlIHRvIHBlcmZvcm0gKG1ham9yLCBtaW5vciwgcGF0Y2gsIGJldGEsIG9yIHgueS56Wy1iZXRhOnVdKS5cbiAqIEBwYXJhbSBwcmVwYXJlR2l0SHViUmVsZWFzZSAtIEEgY2FsbGJhY2sgZnVuY3Rpb24gdG8gcHJlcGFyZSB0aGUgR2l0SHViIHJlbGVhc2UuXG4gKiBAcmV0dXJucyBBIHtAbGluayBQcm9taXNlfSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHZlcnNpb24gdXBkYXRlIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlVmVyc2lvbih2ZXJzaW9uVXBkYXRlVHlwZT86IHN0cmluZywgcHJlcGFyZUdpdEh1YlJlbGVhc2U/OiAobmV3VmVyc2lvbjogc3RyaW5nKSA9PiBQcm9taXNlPHZvaWQ+KTogUHJvbWlzZTx2b2lkPiB7XG4gIGlmICghdmVyc2lvblVwZGF0ZVR5cGUpIHtcbiAgICBjb25zdCBucG1PbGRWZXJzaW9uID0gcHJvY2Vzcy5lbnZbJ25wbV9vbGRfdmVyc2lvbiddO1xuICAgIGNvbnN0IG5wbU5ld1ZlcnNpb24gPSBwcm9jZXNzLmVudlsnbnBtX25ld192ZXJzaW9uJ107XG5cbiAgICBpZiAobnBtT2xkVmVyc2lvbiAmJiBucG1OZXdWZXJzaW9uKSB7XG4gICAgICBhd2FpdCB1cGRhdGVWZXJzaW9uSW5GaWxlcyhucG1PbGRWZXJzaW9uKTtcbiAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obnBtTmV3VmVyc2lvbiwgcHJlcGFyZUdpdEh1YlJlbGVhc2UpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFcnJvcignTm8gdmVyc2lvbiB1cGRhdGUgdHlwZSBwcm92aWRlZCcpO1xuICB9XG5cbiAgY29uc3QgaXNPYnNpZGlhblBsdWdpbiA9IGV4aXN0c1N5bmMocmVzb2x2ZVBhdGhGcm9tUm9vdFNhZmUoT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTWFuaWZlc3RKc29uKSk7XG5cbiAgdmFsaWRhdGUodmVyc2lvblVwZGF0ZVR5cGUpO1xuICBhd2FpdCBjaGVja0dpdEluc3RhbGxlZCgpO1xuICBhd2FpdCBjaGVja0dpdFJlcG9DbGVhbigpO1xuICBhd2FpdCBjaGVja0dpdEh1YkNsaUluc3RhbGxlZCgpO1xuICBhd2FpdCBucG1SdW4oJ2Zvcm1hdDpjaGVjaycpO1xuICBhd2FpdCBucG1SdW4oJ3NwZWxsY2hlY2snKTtcbiAgYXdhaXQgbnBtUnVuKCdidWlsZCcpO1xuICBhd2FpdCBucG1SdW4oJ2xpbnQnKTtcblxuICBjb25zdCBuZXdWZXJzaW9uID0gYXdhaXQgZ2V0TmV3VmVyc2lvbih2ZXJzaW9uVXBkYXRlVHlwZSk7XG4gIGF3YWl0IHVwZGF0ZVZlcnNpb25JbkZpbGVzKG5ld1ZlcnNpb24pO1xuICBpZiAoaXNPYnNpZGlhblBsdWdpbikge1xuICAgIGF3YWl0IHVwZGF0ZVZlcnNpb25JbkZpbGVzRm9yUGx1Z2luKG5ld1ZlcnNpb24pO1xuICB9XG5cbiAgYXdhaXQgdXBkYXRlQ2hhbmdlbG9nKG5ld1ZlcnNpb24pO1xuICBhd2FpdCBhZGRVcGRhdGVkRmlsZXNUb0dpdChuZXdWZXJzaW9uKTtcbiAgYXdhaXQgYWRkR2l0VGFnKG5ld1ZlcnNpb24pO1xuICBhd2FpdCBnaXRQdXNoKCk7XG4gIGF3YWl0IHByZXBhcmVHaXRIdWJSZWxlYXNlPy4obmV3VmVyc2lvbik7XG4gIGF3YWl0IHB1Ymxpc2hHaXRIdWJSZWxlYXNlKG5ld1ZlcnNpb24sIGlzT2JzaWRpYW5QbHVnaW4pO1xufVxuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIHZlcnNpb24gaW4gdmFyaW91cyBmaWxlcywgaW5jbHVkaW5nIGBwYWNrYWdlLmpzb25gLCBgcGFja2FnZS1sb2NrLmpzb25gLFxuICogYW5kIE9ic2lkaWFuIHBsdWdpbiBtYW5pZmVzdHMgaWYgYXBwbGljYWJsZS5cbiAqXG4gKiBAcGFyYW0gbmV3VmVyc2lvbiAtIFRoZSBuZXcgdmVyc2lvbiBzdHJpbmcgdG8gdXBkYXRlIGluIHRoZSBmaWxlcy5cbiAqIEByZXR1cm5zIEEge0BsaW5rIFByb21pc2V9IHRoYXQgcmVzb2x2ZXMgd2hlbiB0aGUgdXBkYXRlIGlzIGNvbXBsZXRlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlVmVyc2lvbkluRmlsZXMobmV3VmVyc2lvbjogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gIGF3YWl0IGVkaXRQYWNrYWdlSnNvbigocGFja2FnZUpzb24pID0+IHtcbiAgICBwYWNrYWdlSnNvbi52ZXJzaW9uID0gbmV3VmVyc2lvbjtcbiAgfSk7XG5cbiAgYXdhaXQgZWRpdFBhY2thZ2VMb2NrSnNvbih1cGRhdGUsIHsgc2hvdWxkU2tpcElmTWlzc2luZzogdHJ1ZSB9KTtcbiAgYXdhaXQgZWRpdE5wbVNocmlua1dyYXBKc29uKHVwZGF0ZSwgeyBzaG91bGRTa2lwSWZNaXNzaW5nOiB0cnVlIH0pO1xuXG4gIGZ1bmN0aW9uIHVwZGF0ZShwYWNrYWdlTG9ja0pzb246IFBhY2thZ2VMb2NrSnNvbik6IHZvaWQge1xuICAgIHBhY2thZ2VMb2NrSnNvbi52ZXJzaW9uID0gbmV3VmVyc2lvbjtcbiAgICBjb25zdCBkZWZhdWx0UGFja2FnZSA9IHBhY2thZ2VMb2NrSnNvbi5wYWNrYWdlcz8uWycnXTtcbiAgICBpZiAoZGVmYXVsdFBhY2thZ2UpIHtcbiAgICAgIGRlZmF1bHRQYWNrYWdlLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIFZhbGlkYXRlcyB0aGUgdmVyc2lvbiB1cGRhdGUgdHlwZSB0byBlbnN1cmUgaXQgaXMgZWl0aGVyIGEgcmVjb2duaXplZCB0eXBlXG4gKiBvciBhIHZhbGlkIG1hbnVhbCB2ZXJzaW9uIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gdmVyc2lvblVwZGF0ZVR5cGUgLSBUaGUgdmVyc2lvbiB1cGRhdGUgdHlwZSB0byB2YWxpZGF0ZS5cbiAqIEB0aHJvd3MgRXJyb3IgaWYgdGhlIHZlcnNpb24gdXBkYXRlIHR5cGUgaXMgaW52YWxpZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlKHZlcnNpb25VcGRhdGVUeXBlOiBzdHJpbmcpOiB2b2lkIHtcbiAgaWYgKGdldFZlcnNpb25VcGRhdGVUeXBlKHZlcnNpb25VcGRhdGVUeXBlKSA9PT0gVmVyc2lvblVwZGF0ZVR5cGUuSW52YWxpZCkge1xuICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCB2ZXJzaW9uIHVwZGF0ZSB0eXBlLiBQbGVhc2UgdXNlIFxcJ21ham9yXFwnLCBcXCdtaW5vclxcJywgXFwncGF0Y2hcXCcsIG9yIFxcJ3gueS56Wy1zdWZmaXhdXFwnIGZvcm1hdC4nKTtcbiAgfVxufVxuXG4vKipcbiAqIEZldGNoZXMgdGhlIGxhdGVzdCB2ZXJzaW9uIG9mIE9ic2lkaWFuIGZyb20gdGhlIEdpdEh1YiByZWxlYXNlcyBBUEkuXG4gKlxuICogQHJldHVybnMgQSB7QGxpbmsgUHJvbWlzZX0gdGhhdCByZXNvbHZlcyB0byB0aGUgbGF0ZXN0IHZlcnNpb24gb2YgT2JzaWRpYW4uXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGdldExhdGVzdE9ic2lkaWFuVmVyc2lvbigpOiBQcm9taXNlPHN0cmluZz4ge1xuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKCdodHRwczovL2FwaS5naXRodWIuY29tL3JlcG9zL29ic2lkaWFubWQvb2JzaWRpYW4tcmVsZWFzZXMvcmVsZWFzZXMvbGF0ZXN0Jyk7XG4gIGNvbnN0IG9ic2lkaWFuUmVsZWFzZXNKc29uID0gYXdhaXQgcmVzcG9uc2UuanNvbigpIGFzIFBhcnRpYWw8T2JzaWRpYW5SZWxlYXNlc0pzb24+O1xuICByZXR1cm4gb2JzaWRpYW5SZWxlYXNlc0pzb24ubmFtZSA/PyB0aHJvd0V4cHJlc3Npb24obmV3IEVycm9yKCdDb3VsZCBub3QgZmluZCB0aGUgbmFtZSBvZiB0aGUgbGF0ZXN0IE9ic2lkaWFuIHJlbGVhc2UnKSk7XG59XG5cbmZ1bmN0aW9uIGlzQmV0YSh2ZXJzaW9uOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgcmV0dXJuIHZlcnNpb24uaW5jbHVkZXMoVmVyc2lvblVwZGF0ZVR5cGUuQmV0YSk7XG59XG5cbmZ1bmN0aW9uIHRvU2luZ2xlTGluZShzdHI6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGxpbmVzID0gc3RyLnNwbGl0KC9cXHI/XFxuLykuZmlsdGVyKEJvb2xlYW4pO1xuICByZXR1cm4gbGluZXMuam9pbignICcpO1xufVxuXG5hc3luYyBmdW5jdGlvbiB1cGRhdGVWZXJzaW9uSW5GaWxlc0ZvclBsdWdpbihuZXdWZXJzaW9uOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHtcbiAgY29uc3QgbWFuaWZlc3RCZXRhSnNvblBhdGggPSByZXNvbHZlUGF0aEZyb21Sb290U2FmZShPYnNpZGlhblBsdWdpblJlcG9QYXRocy5NYW5pZmVzdEJldGFKc29uKTtcbiAgaWYgKGlzQmV0YShuZXdWZXJzaW9uKSkge1xuICAgIGF3YWl0IGNwKFxuICAgICAgcmVzb2x2ZVBhdGhGcm9tUm9vdFNhZmUoT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTWFuaWZlc3RKc29uKSxcbiAgICAgIG1hbmlmZXN0QmV0YUpzb25QYXRoLFxuICAgICAgeyBmb3JjZTogdHJ1ZSB9XG4gICAgKTtcbiAgICBhd2FpdCBlZGl0SnNvbjxNYW5pZmVzdD4oT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuTWFuaWZlc3RCZXRhSnNvbiwgKG1hbmlmZXN0KSA9PiB7XG4gICAgICBtYW5pZmVzdC52ZXJzaW9uID0gbmV3VmVyc2lvbjtcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBjb25zdCBsYXRlc3RPYnNpZGlhblZlcnNpb24gPSBhd2FpdCBnZXRMYXRlc3RPYnNpZGlhblZlcnNpb24oKTtcblxuICAgIGF3YWl0IGVkaXRKc29uPE1hbmlmZXN0PihPYnNpZGlhblBsdWdpblJlcG9QYXRocy5NYW5pZmVzdEpzb24sIChtYW5pZmVzdCkgPT4ge1xuICAgICAgbWFuaWZlc3QubWluQXBwVmVyc2lvbiA9IGxhdGVzdE9ic2lkaWFuVmVyc2lvbjtcbiAgICAgIG1hbmlmZXN0LnZlcnNpb24gPSBuZXdWZXJzaW9uO1xuICAgIH0pO1xuXG4gICAgYXdhaXQgZWRpdEpzb248UmVjb3JkPHN0cmluZywgc3RyaW5nPj4oT2JzaWRpYW5QbHVnaW5SZXBvUGF0aHMuVmVyc2lvbnNKc29uLCAodmVyc2lvbnMpID0+IHtcbiAgICAgIHZlcnNpb25zW25ld1ZlcnNpb25dID0gbGF0ZXN0T2JzaWRpYW5WZXJzaW9uO1xuICAgIH0pO1xuXG4gICAgaWYgKGV4aXN0c1N5bmMobWFuaWZlc3RCZXRhSnNvblBhdGgpKSB7XG4gICAgICBhd2FpdCBybShtYW5pZmVzdEJldGFKc29uUGF0aCk7XG4gICAgfVxuICB9XG5cbiAgYXdhaXQgY29weVVwZGF0ZWRNYW5pZmVzdCgpO1xufVxuIl0sCiAgIm1hcHBpbmdzIjogIjs7Ozs7OztBQVdBLFNBQVMsc0JBQXNCO0FBQy9CLFNBQVMsdUJBQXVCO0FBQ2hDLFNBQVMsK0JBQStCO0FBQ3hDLFNBQVMsWUFBWTtBQUNyQixTQUFTLGtCQUFrQjtBQUMzQixTQUFTLG9CQUFvQjtBQUM3QixTQUFTLGdCQUFnQjtBQUN6QjtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLE9BQ0s7QUFDUDtBQUFBLEVBQ0U7QUFBQSxFQUNBO0FBQUEsRUFDQTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBQ1AsU0FBUyxjQUFjO0FBQ3ZCLFNBQVMsaUNBQWlDO0FBQzFDO0FBQUEsRUFDRTtBQUFBLEVBQ0E7QUFBQSxPQUNLO0FBS0EsSUFBSyxvQkFBTCxrQkFBS0EsdUJBQUw7QUFDTCxFQUFBQSxtQkFBQSxVQUFPO0FBQ1AsRUFBQUEsbUJBQUEsYUFBVTtBQUNWLEVBQUFBLG1CQUFBLFdBQVE7QUFDUixFQUFBQSxtQkFBQSxZQUFTO0FBQ1QsRUFBQUEsbUJBQUEsV0FBUTtBQUNSLEVBQUFBLG1CQUFBLFdBQVE7QUFORSxTQUFBQTtBQUFBLEdBQUE7QUF3Q1osZUFBc0IsVUFBVSxZQUFt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Z0IsVUFBVTtBQUMxQixVQUFNLGlCQUFpQixnQkFBZ0IsV0FBVyxFQUFFO0FBQ3BELFFBQUksZ0JBQWdCO0FBQ2xCLHFCQUFlLFVBQVU7QUFBQSxJQUMzQjtBQUFBLEVBQ0Y7QUFDRjtBQVNPLFNBQVMsU0FBUyxtQkFBaUM7QUFDeEQsTUFBSSxxQkFBcUIsaUJBQWlCLE1BQU0seUJBQTJCO0FBQ3pFLFVBQU0sSUFBSSxNQUFNLGdHQUF3RztBQUFBLEVBQzFIO0FBQ0Y7QUFPQSxlQUFlLDJCQUE0QztBQUN6RCxRQUFNLFdBQVcsTUFBTSxNQUFNLDJFQUEyRTtBQUN4RyxRQUFNLHVCQUF1QixNQUFNLFNBQVMsS0FBSztBQUNqRCxTQUFPLHFCQUFxQixRQUFRLGdCQUFnQixJQUFJLE1BQU0sd0RBQXdELENBQUM7QUFDekg7QUFFQSxTQUFTLE9BQU8sU0FBMEI7QUFDeEMsU0FBTyxRQUFRLFNBQVMsaUJBQXNCO0FBQ2hEO0FBRUEsU0FBUyxhQUFhLEtBQXFCO0FBQ3pDLFFBQU0sUUFBUSxJQUFJLE1BQU0sT0FBTyxFQUFFLE9BQU8sT0FBTztBQUMvQyxTQUFPLE1BQU0sS0FBSyxHQUFHO0FBQ3ZCO0FBRUEsZUFBZSw4QkFBOEIsWUFBbUM7QUFDOUUsUUFBTSx1QkFBdUIsd0JBQXdCLHdCQUF3QixnQkFBZ0I7QUFDN0YsTUFBSSxPQUFPLFVBQVUsR0FBRztBQUN0QixVQUFNO0FBQUEsTUFDSix3QkFBd0Isd0JBQXdCLFlBQVk7QUFBQSxNQUM1RDtBQUFBLE1BQ0EsRUFBRSxPQUFPLEtBQUs7QUFBQSxJQUNoQjtBQUNBLFVBQU0sU0FBbUIsd0JBQXdCLGtCQUFrQixDQUFDLGFBQWE7QUFDL0UsZUFBUyxVQUFVO0FBQUEsSUFDckIsQ0FBQztBQUFBLEVBQ0gsT0FBTztBQUNMLFVBQU0sd0JBQXdCLE1BQU0seUJBQXlCO0FBRTdELFVBQU0sU0FBbUIsd0JBQXdCLGNBQWMsQ0FBQyxhQUFhO0FBQzNFLGVBQVMsZ0JBQWdCO0FBQ3pCLGVBQVMsVUFBVTtBQUFBLElBQ3JCLENBQUM7QUFFRCxVQUFNLFNBQWlDLHdCQUF3QixjQUFjLENBQUMsYUFBYTtBQUN6RixlQUFTLFVBQVUsSUFBSTtBQUFBLElBQ3pCLENBQUM7QUFFRCxRQUFJLFdBQVcsb0JBQW9CLEdBQUc7QUFDcEMsWUFBTSxHQUFHLG9CQUFvQjtBQUFBLElBQy9CO0FBQUEsRUFDRjtBQUVBLFFBQU0sb0JBQW9CO0FBQzVCOyIsCiAgIm5hbWVzIjogWyJWZXJzaW9uVXBkYXRlVHlwZSJdCn0K