diff --git a/extensions.txt b/extensions.txt deleted file mode 100644 index 992eab18..00000000 Binary files a/extensions.txt and /dev/null differ diff --git a/gulpfile.js b/gulpfile.js deleted file mode 100644 index 9138b6dc..00000000 --- a/gulpfile.js +++ /dev/null @@ -1,759 +0,0 @@ -/* eslint-disable func-names */ -/* eslint-disable @typescript-eslint/no-var-requires, */ -// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~ -const argv = require("yargs").argv; -const fs = require("fs"); -const {src, dest, watch, series, parallel} = require("gulp"); -const plumber = require("lazypipe"); -const plunger = require("gulp-plumber"); -const merger = require("merge2"); -const logger = require("fancy-log"); -const debug = require("gulp-debug"); - -const renamer = require("gulp-rename"); -const header = require("gulp-header"); -const replacer = require("gulp-replace"); - -const typescript = require("gulp-typescript"); -const terser = require("gulp-terser"); - -const sasser = require("gulp-sass")(require("sass")); -const bundler = require("gulp-postcss"); -// Const filler = require("cq-prolyfill/postcss-plugin"); -const prefixer = require("autoprefixer"); -const minifier = require("cssnano"); - -const packageJSON = require("./package"); -// Const sourcemaps = require("gulp-sourcemaps"); - -const {analyzeProject} = require("codehawk-cli"); -// #endregion ▮▮▮▮[IMPORTS]▮▮▮▮ - -// #region ▮▮▮▮▮▮▮[UTILITY] Data References & Utility Functions for File Parsing ▮▮▮▮▮▮▮ ~ -const ANSICOLORS = { - // RESET - x: "\u001b[0m", - - // Standard Colors - black: "\u001b[30m", - grey: "\u001b[30;1m", - red: "\u001b[31m", - green: "\u001b[32m", - yellow: "\u001b[33m", - blue: "\u001b[34m", - magenta: "\u001b[35m", - cyan: "\u001b[36m", - white: "\u001b[37m", - - // Bright Colors - bred: "\u001b[31;1m", - bgreen: "\u001b[32;1m", - byellow: "\u001b[33;1m", - bblue: "\u001b[34;1m", - bmagenta: "\u001b[35;1m", - bcyan: "\u001b[36;1m", - bwhite: "\u001b[37;1m", - - // Standard Background Colors - bgblack: "\u001b[40m", - bggrey: "\u001b[40;1m", - bgred: "\u001b[41m", - bggreen: "\u001b[42m", - bgyellow: "\u001b[43m", - bgblue: "\u001b[44m", - bgmagenta: "\u001b[45m", - bgcyan: "\u001b[46m", - bgwhite: "\u001b[47m", - - // Bright Background Colors - bgbred: "\u001b[41;1m", - bgbgreen: "\u001b[42;1m", - bgbyellow: "\u001b[43;1m", - bgbblue: "\u001b[44;1m", - bgbmagenta: "\u001b[45;1m", - bgbcyan: "\u001b[46;1m", - bgbwhite: "\u001b[47;1m", - - // Styles - none: "", - bold: "\u001b[1m", - underline: "\u001b[4m", - invert: "\u001b[7m" -}; -const STREAMSTYLES = { - gulp: ["grey", "-", "(gulp)"], - initWhiteSpace: ["bred", "=", "(staging)"], - tsInit: ["blue", "T", " TS "], - jsFull: ["bmagenta", "J", " JS "], - jsMin: ["magenta", "J", " js "], - cssFull: ["byellow", "C", " SCSS "], - cssMin: ["yellow", "C", " scss "], - hbs: ["bblue", "<", " HBS "], - toDest: ["bgreen", "$", " ASSETS "] -}; -const ansi = (str, {fg, bg, style} = {}) => { - fg = ANSICOLORS[fg ?? "white"]; - bg = ANSICOLORS[`bg${bg ?? "black"}`.replace(/^bg+/, "bg")]; - style = ANSICOLORS[style ?? "none"]; - return [bg, fg, style, str, ANSICOLORS.x].join(""); -}; -const toBright = (color) => (`b${color}` in ANSICOLORS ? `b${color}` : color); -const toDim = (color) => (color.slice(1) in ANSICOLORS ? color.slice(1) : color); -const logParts = { - tag: (tag = "gulp", color = "white", padChar = " ") => ansi(` ${centerString(tag, 10, padChar)} `, {fg: color}), - error: (tag, message) => [ansi(`[ERROR: ${tag}]`, {fg: "white", bg: "red", style: "bold"}), ansi(message, {fg: "red"})].join(" "), - finish: function(title, source, destination) { - title ??= "gulp"; - const [color, padChar, tag] = STREAMSTYLES[title]; - return [ - this.tag(tag, color, padChar), - " ", - ansi(source, {fg: toBright(color), style: "underline"}), - ansi(" successfully piped to ", {fg: toDim(color), style: "none"}), - ansi(destination, {fg: toBright(color), style: "underline"}) - ].join(""); - } -}; -const centerString = (str, width, padChar = " ") => { - let padString = `${str}`; - while (padString.length < width) { - padString = `${padChar}${padString}${padChar}`; - } - return padString.length > width ? padString.slice(1) : padString; -}; -const padHeaderLines = (match) => { - const padLine = (line, length) => { - const padLength = length - line.length; - if (padLength > 0) { - const [padLeft, padRight] = [Math.ceil(padLength / 2), Math.ceil(padLength / 2)]; - const [lineLeft, lineRight] = [ - line.slice(0, Math.floor(line.length / 2)), - line.slice(Math.floor(line.length / 2)) - ]; - // Two types of padding: '█' and '░'. Count amount of each to get relative ratio. - const fadePad = lineLeft.match(/░+/u)?.pop().length ?? 0; - const fullFadeRatio = fadePad === 0 ? 1 : (lineLeft.match(/░+/)?.pop().length ?? 0) / fadePad; - let numFullPadLeft = Math.round((fullFadeRatio * padLeft) / (1 + fullFadeRatio)); - let numFadePadLeft = 0; - let numFullPadRight = Math.round((fullFadeRatio * padRight) / (1 + fullFadeRatio)); - let numFadePadRight = 0; - if (fadePad > 0) { - numFadePadLeft = padLeft - numFullPadLeft; - numFadePadRight = padRight - numFullPadRight; - } else { - numFullPadLeft = padLeft; - numFullPadRight = padRight; - } - numFullPadRight += padLength - (numFullPadLeft + numFadePadLeft + numFullPadRight + numFadePadRight); - return [ - lineLeft.replace(/▌█/u, `▌${"█".repeat(numFullPadLeft + 1)}`).replace(/░/u, "░".repeat(numFadePadLeft + 1)), - lineRight.replace(/█▐/u, `${"█".repeat(numFullPadRight + 1)}▐`).replace(/░/u, "░".repeat(numFadePadRight + 1)) - ].join(""); - } - return line; - }; - const lines = match.split(/\n/s); - const returnLines = []; - let maxLen = 0; - lines.forEach((line) => { - if (line.length > maxLen) { - maxLen = line.length; - } - }); - lines.forEach((line) => { - if (line.length < maxLen) { - returnLines.push(padLine(line, maxLen)); - } else { - returnLines.push(line); - } - }); - return returnLines.join("\n"); -}; -const roundNum = (num, sigDigits = 0) => (sigDigits === 0 - ? Math.round(num) - : Math.round(num * (10 ** sigDigits)) / (10 ** sigDigits)); -const subGroup = (array, groupSize) => { - const subArrays = []; - while (array.length > groupSize) { - const subArray = []; - while (subArray.length < groupSize) { - subArray.push(array.shift()); - } - subArrays.push(subArray); - } - subArrays.push(array); - return subArrays; -}; -// #endregion ▮▮▮▮[UTILITY]▮▮▮▮ -const ISRAPIDGULPING = argv.isMinimizingCSS !== "true"; - -const ISMINIFYINGJS = argv.isMinimizingJS === "true"; -const ISBUILDINGDIST = argv.isBuildingDist === "true"; -const ISDEPLOYING = argv.isDeploying === "true"; -const ISANALYZING = argv.isAnalyzing === "true"; -const ISGENERATINGTYPEFILES = argv.isGeneratingTypeDefs === "true"; -const ISCOMPILINGIDESCSS = argv.compileCustomCSS === "true"; -const ISCOMPILINGCODE = argv.compileCustomCSS !== "true"; - -const PACKAGEFOLDER = "eunos-blades"; -const PACKAGENAME = "Euno's Blades in the Dark"; -const PACKAGETYPE = "system"; - -const DISTDATAROOT = "C:/Users/Ryan/Documents/Projects/!!!!CODING/FoundryVTT/FoundryDistData/Data"; -const DISTROOT = `${DISTDATAROOT}/${PACKAGETYPE}s/${PACKAGEFOLDER}`; -const CUSTOMCSS_SOURCE = "D:/Users/Ryan/Documents/Projects/!!!!CODING/!!VSC_Custom_CSS/"; -const CUSTOMCSS_DEST = "D:/Users/Ryan/Documents/Projects/!!!!CODING/!!VSC_Custom_CSS/css/"; - -// #region ████████ CONFIGURATION: Banner Headers, Source/Destination Globs, Build Behavior ████████ -// #region ░░░░░░░[BANNERS]░░░░░░░ ~ -const dateStringFull = ISDEPLOYING ? `█ ${new Date().toString().match(/\b[A-Z][a-z]+ \d+ \d+/u).shift()} █` : "██"; -const dateStringMin = ISDEPLOYING ? ` (${new Date().getFullYear()})` : ""; -const BANNERTEMPLATE = { - full: `/*~ ****▌███████████████████████████████████████████████████████████████████████████▐**** *\\ -|*~ ▌█░░░░░░░░░ ${PACKAGENAME} for Foundry VTT ░░░░░░░░░░░█▐ *| -|*~ ▌██████████████████░░░░░░░░░░░░░ by Eunomiac ░░░░░░░░░░░░░██████████████████▐ *| -|*~ ▌█ <%= package.license %> License █ v<%= package.version %> ${dateStringFull}▐ *| -|*~ ▌████░░░░ <%= package.repository.url %> ░░░░█████▐ *| -\\*~ ****▌███████████████████████████████████████████████████████████████████████████▐**** */ -/*~ @@DOUBLE-BLANK@@ ~*/\r\n`, - min: [ - `/*~ ▌██░░ <%= package.name %> v<%= package.version %>${dateStringMin}`, - "<%= package.license %> License", - "<%= package.url %> ░░██▐ */" - ].join(" ║ ") -}; -// #endregion ░░░░[BANNERS]░░░░ -// #region ░░░░░░░[BUILD FILES]░░░░░░░░ ~ - -let BUILDFILES = {}; - -if (ISCOMPILINGCODE) { - if (ISRAPIDGULPING) { - BUILDFILES = { - ts: { - "./module/": ["ts/**/*.*"] - }, - css: { - "./css/": ["scss/**/*.scss"] - }, - hbs: { - "./templates/": ["DISABLE"] - }, - quickAssets: { - "./css/": ["scss/**/*.css"] - } - }; - } else { - BUILDFILES = { - ts: { - "./module_staging_1/": ["ts/**/*.*"] - }, - css: { - "./css/": ["scss/**/*.scss"] - }, - hbs: { - "./templates/": ["DISABLE"] - }, - quickAssets: { - "./assets/": ["DISABLE"], - "./css/": ["scss/**/*.css"], - "./module/": ["module_staging_1/**/*.map"] - }, - slowAssets: { - "./assets/": ["DISABLE"] - } - }; - - if (ISMINIFYINGJS) { - BUILDFILES.js = { - "./module_staging_2/": ["module_staging_1/**/*.js"] - }; - BUILDFILES.js_2 = { - "./module/": ["module_staging_1/**/*.js"] - }; - } else { - BUILDFILES.js = { - "./module/": ["module_staging_1/**/*.js"] - }; - } - } - - if (ISBUILDINGDIST) { - BUILDFILES.js ??= {}; - BUILDFILES.js[`${DISTROOT}/module/`] = ["module/**/*.js"]; - BUILDFILES.css ??= {}; - BUILDFILES.css[`${DISTROOT}/css/`] = ["scss/**/*.scss"]; - BUILDFILES.hbs ??= {}; - BUILDFILES.hbs[`${DISTROOT}/templates/`] = ["templates/**/*.hbs", "templates/**/*.html"]; - BUILDFILES.quickAssets ??= {}; - BUILDFILES.quickAssets[`${DISTROOT}/`] = ["system.json", "template.json", /* "LICENSE.txt", */ "package.json"]; - BUILDFILES.quickAssets[`${DISTROOT}/css/`] = ["scss/**/*.css"]; - BUILDFILES.slowAssets ??= {}; - BUILDFILES.slowAssets[`${DISTROOT}/assets/`] = ["assets/**/*.*"]; - BUILDFILES.slowAssets[`${DISTROOT}/packs/`] = ["packs/**/*.*"]; - BUILDFILES.slowAssets[`${DISTROOT}/lang/`] = ["lang/**/*.*"]; - } -} - -if (ISCOMPILINGIDESCSS) { - BUILDFILES.css ??= {}; - BUILDFILES.css[CUSTOMCSS_DEST] = [`${CUSTOMCSS_SOURCE}*.scss`]; -} - -// #endregion ░░░░[BUILD FILES]░░░░ -// #region ░░░░░░░[REGEXP PATTERNS]░░░░░░░ ~ -const REGEXPPATTERNS = { - /* ALWAYS USE FLAGS: - g --- global & enables capturing groups - u --- handles expanded unicode characters AND enables strict checks of RegExp syntax - - OPTIONAL FLAGS: - i --- ignore case - s --- . dot character WILL match newline characters - m --- ^ and $ characters WILL match start/end of lines, instead of start/end of entire string - y --- starts search from on; lastIndex must be supplied as a property - - REGEXP PHRASES: - (\r\n)?\s*? --- capture any line break, then consume blank space at start of line - reverse, for end-of-lines: \s*?(\r\n)? - */ - init: new Map([ - [/^XXX/g, ""] // [/^\s+$/gm, "/*~ @@DOUBLE-BLANK@@ ~*/"] // Replace double-blank lines with token for later retrieval - ]), - ts: new Map([ - [/from "gsap\/all"/gu, 'from "/scripts/greensock/esm/all.js"'], - [/from ['"](.+?)(\.ts|\.js)?['"]/g, "from \"$1.js\""] // Fix imports to include .js suffix - ]), - js: new Map([ - ISDEPLOYING || ISBUILDINGDIST - ? [/(\r\n)?\s*?(\/\*DEVCODE\*\/.*?\/\*!DEVCODE\*\/)\s*?(\r\n)?/gms, ""] - : [/`/, "`"], // Strip developer code - [ - (/\/\*~\s*\*{4}▌.*?▐\*{4}\s*\*\//s, padHeaderLines) - ], // Pad header lines to same length - [/\/\/\s*#region/gi, "//~ #region"], // Prefix #region lines with tildes so they aren't stripped - [/\/\*\*(?!~)(?:.|\r?\n|\r)*?\*\/[ \t]*(\r?\n?)/g, ""], // Strip multi-line comments unless they beginning with '/*~' or '/**~' - [/\/\*(?!\*|~)(?:.|\r?\n|\r)*?\*\/[ \t]*(\r?\n?)/g, ""], // Strip multi-line comments unless they beginning with '/*~' or '/**~' - [/(\r?\n?)[ \t]*\/\/(?!~) .*?$/gm, "$1"], // Strip single-line comments unless they begin with '//~' - [/(\/\/|\/\*\*?|\|\*|\\\*)~/gm, "$1"], // Strip tildes from comment line prefixes - [/#(region.*?)[ \t]*~$/gim, "#$1"], // Strip '~' from end-of-lines (used for automatic region folding) - [/#reg.*? /gs, ""], // Convert region headers to standard headers - [/((\r?\n)[ \t]*(?:\r?\n))+/g, "\r\n"], // Strip excess blank lines - // [ - // /([ \t]*\r?\n\/\*~? @@DOUBLE-BLANK@@ ~\*\/)+/g, - // "\r\n/*~ @@DOUBLE-BLANK@@ ~*/" - // ], // Collapse multiple double-blank lines - // [/\/\*~? @@DOUBLE-BLANK@@ ~\*\//g, ""], // Restore double-blank lines - [/([ \t]*\r?\n)*$/, ""], // Strip whitespace from end of files - [/^([ \t]*\r?\n)*/, ""] // Strip whitespace from start of files - ]) -}; - -// #endregion ░░░░[REGEXP PATTERNS]░░░░ -// #region ░░░░░░░[PIPES & PLUMBING]░░░░ Assembly of Pipes for Passing Streams ░░░░░░░ ~ -// #region ====== PIPES: Basic Functionality ====== ~ -const PIPES = { - openPipe: (title = "gulp") => { - const [titleColor, padChar, tagName] = STREAMSTYLES[title] ?? ["red", "?", "???"]; - return plumber() - .pipe(debug, { - title: logParts.tag(tagName, titleColor, padChar), - minimal: true, - showFiles: true, - showCount: false - }) - .pipe(plunger, function(err) { - logger.error(logParts.error(title, err.message)); - this.emit("end"); - }); - }, - replacer: (format) => { - let pipeline = plumber(); - if (format in REGEXPPATTERNS) { - REGEXPPATTERNS[format].forEach((rParam, sParam) => { - pipeline = pipeline.pipe(replacer, sParam, rParam); - }); - } - return pipeline; - }, - tsProject: typescript.createProject("tsconfig.json", {declaration: ISGENERATINGTYPEFILES, emitDeclarationOnly: ISGENERATINGTYPEFILES}), - terser: () => plumber().pipe(terser, { - parse: {}, - compress: {}, - mangle: { - properties: {} - }, - format: {}, - sourceMap: {}, - ecma: 2020, - module: true - }), - closePipe: (title, source, destination) => { - const thisDest = dest(destination); - thisDest.on("finish", () => logger(logParts.finish(title, source, destination))); - return thisDest; - } -}; -// #endregion ___ PIPES ___ - -const PLUMBING = { - analyzeJS: async function analyzeJS(done) { - if (!ISANALYZING) { return done(); } - try { - const analysisData = analyzeProject("./"); - const returnData = { - AVERAGE: roundNum(analysisData.summary.average, 2), - MEDIAN: roundNum(analysisData.summary.median, 2), - WORST: roundNum(analysisData.summary.worst, 2) - }; - analysisData.resultsList.forEach(async ({filename, complexityReport, timesDependedOn}) => { - returnData[filename] = { - cyclomatic: `${complexityReport.aggregate.cyclomatic} (Density: ${roundNum(complexityReport.aggregate.cyclomaticDensity, 2)})`, - halstead: subGroup(Object.entries(complexityReport.aggregate.halstead) - .map(([test, result]) => { - let resultString = `[${test}] `; - if (typeof result === "object") { - resultString += `${result.distinct} (${result.total} total) `; - } else { - resultString += `${roundNum(result, 3)} `; - } - return resultString; - }), 3) - .map((subArray) => subArray.join(" ")), - params: complexityReport.aggregate.paramCount, - sloc: `Logical: ${complexityReport.aggregate.sloc.logical}, Physical: ${complexityReport.aggregate.sloc.physical}`, - maintainability: roundNum(complexityReport.maintainability, 2), - codehawkScore: roundNum(complexityReport.codehawkScore, 3), - coverage: complexityReport.coverage, - timesDependedOn - }; - }); - let analysisString = JSON.stringify(returnData, null, 2); - while (analysisString.length > 150_000) { - logger(analysisString.slice(0, 150_000)); - analysisString = analysisString.slice(150_000); - logger(" "); - logger(`${analysisString.length} to go ...`); - await new Promise((resolve) => { setTimeout(resolve, 20000); }); - } - logger(analysisString); - } catch(err) { - return done(); - } - return done(); - }, - initDest: async function initDest(done, destGlobs = ["./dist/", "./module/", "./module_staging_1", "./module_staging_2", "./css/"]) { - destGlobs.forEach((d) => { try { fs.rmSync(d); } catch{ } }); - return done(); - }, - watch: function watchFunc() { - console.log("\n\n==== BUILDFILES ====\n\n"); - console.log(JSON.stringify(BUILDFILES, null, 2)); - console.log("\n\n--------------------\n\n"); - for (const [type, globs] of Object.entries(BUILDFILES)) { - Object.values(globs ?? {}).forEach((glob) => watch(glob, BUILDFUNCS[type])); - } - }, - tsInit: (source, destination) => function tsInit() { - const tsStream = src(source, {allowEmpty: true}) - // .pipe(sourcemaps.init()) - .pipe(PIPES.openPipe("tsInit")()) - .pipe(PIPES.replacer("init")()) - .pipe(PIPES.tsProject()); - if (ISGENERATINGTYPEFILES) { - return merger([ - tsStream.js - .pipe(PIPES.replacer("ts")()) - // .pipe(sourcemaps.write(".")) - .pipe(PIPES.closePipe("tsInit", source, destination)), - tsStream.dts - .pipe(PIPES.closePipe("tsInit", source, `${destination}definitions`)) - ]); - } - return tsStream - .pipe(PIPES.replacer("ts")()) - // .pipe(PIPES.replacer("js")()) - // .pipe(sourcemaps.write(".")) - .pipe(PIPES.closePipe("tsInit", source, destination)); - }, - jsFull: (source, destination) => function jsFull() { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("jsFull")()) - .pipe(header(BANNERS.js.full, {package: packageJSON})) - .pipe(PIPES.replacer("js")()) - .pipe(PIPES.closePipe("jsFull", source, destination)); - }, - jsMin: (source, destination) => function jsMin() { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("jsMin")()) - .pipe(header(BANNERS.js.min, {package: packageJSON})) - .pipe(PIPES.replacer("js")()) - // .pipe(renamer({suffix: ".min"})) - .pipe(PIPES.terser()()) - .pipe(PIPES.closePipe("jsMin", source, destination)); - }, - cssFull: (source, destination) => function cssFull() { - if (ISRAPIDGULPING) { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("cssFull")()) - .pipe(sasser()) - .pipe(renamer({suffix: ".min"})) - .pipe(PIPES.closePipe("cssFull", source, destination)); - } else { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("cssFull")()) - .pipe(sasser({outputStyle: "nested"})) - .pipe(bundler([ - prefixer({cascade: false}) - ])) - .pipe(PIPES.closePipe("cssFull", source, destination)); - } - }, - cssMin: (source, destination) => function cssMin() { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("cssMin")()) - .pipe(sasser({outputStyle: "compressed"})) - .pipe(bundler([ - prefixer({cascade: false}), - minifier() - ])) - .pipe(header(BANNERS.css.min, {package: packageJSON})) - .pipe(renamer({suffix: ".min"})) - .pipe(PIPES.closePipe("cssMin", source, destination)); - }, - hbs: (source, destination) => function hbs() { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("hbs")()) - .pipe(PIPES.closePipe("hbs", source, destination)); - }, - toDest: (source, destination) => function toDest() { - return src(source, {allowEmpty: true}) - .pipe(PIPES.openPipe("toDest")()) - .pipe(PIPES.closePipe("toDest", source, destination)); - } -}; -// #endregion ░░░░[PIPES & PLUMBING]░░░░ -// #endregion ▄▄▄▄▄ CONFIGURATION ▄▄▄▄▄ - -// #region ▒░▒░▒░▒[INITIALIZATION]▒░▒░▒░▒ ~ - -const BANNERS = { - js: {...BANNERTEMPLATE}, - css: {...BANNERTEMPLATE} -}; - -const BUILDFUNCS = {}; -// #endregion ▒▒▒▒[INITIALIZATION]▒▒▒▒ - -// #region ████████ JS: Compiling Javascript ████████ ~ -if (ISCOMPILINGCODE) { - BUILDFUNCS.ts = /* Series( - PLUMBING.initWhiteSpace, */ - parallel(...((buildFiles) => { - const funcs = []; - for (const [destGlob, sourceGlobs] of Object.entries(buildFiles)) { - sourceGlobs.forEach((sourceGlob) => { - funcs.push(PLUMBING.tsInit(sourceGlob, destGlob)); - }); - } - return funcs; - })(BUILDFILES.ts)); - // ); - - if (!ISRAPIDGULPING) { - const jsBuildFuncs = [ - parallel(...((buildFiles) => { - const funcs = []; - for (const [destGlob, sourceGlobs] of Object.entries(buildFiles)) { - sourceGlobs.forEach((sourceGlob) => { - funcs.push(PLUMBING.jsFull(sourceGlob, destGlob)); - }); - } - return funcs; - })(BUILDFILES.js)) - ]; - - if (ISMINIFYINGJS) { - jsBuildFuncs.push(parallel(...((buildFiles) => { - const funcs = []; - for (const [destGlob, sourceGlobs] of Object.entries(buildFiles)) { - sourceGlobs.forEach((sourceGlob) => { - funcs.push(PLUMBING.jsMin(sourceGlob, destGlob)); - }); - } - return funcs; - })(BUILDFILES.js_2))); - } - - BUILDFUNCS.js = series( - ...jsBuildFuncs, - PLUMBING.analyzeJS - ); - } -} -// #endregion ▄▄▄▄▄ JS ▄▄▄▄▄ - -// #region ████████ CSS: Compiling CSS ████████ ~ -BUILDFUNCS.css = parallel(...((sourceDestGlobs) => Object.entries(sourceDestGlobs) - .map(([destGlob, sourceGlobs]) => [...sourceGlobs - .map((sourceGlob) => { - if (ISRAPIDGULPING) { - return [PLUMBING.cssFull(sourceGlob, destGlob)]; - } else { - return [ - PLUMBING.cssFull(sourceGlob, destGlob), - PLUMBING.cssMin(sourceGlob, destGlob) - ]; - } - } ) - ]).flat())(BUILDFILES.css).flat()); - -// BUILDFUNCS.css = parallel(...((sourceDestGlobs) => { -// const funcs = []; -// for (const [destGlob, sourceGlobs] of Object.entries(sourceDestGlobs)) { -// const formatType = /dist/.test(destGlob) ? "cssMin" : "cssFull"; -// funcs.push(PLUMBING[formatType](sourceGlobs[0], destGlob)); -// } -// logger(`There are ${funcs.length} CSS Build Funcs.`); -// return funcs; -// })(BUILDFILES.css)); -// #endregion ▄▄▄▄▄ CSS ▄▄▄▄▄ - -// #region ████████ HBS: Compiling HBS ████████ ~ -if (ISCOMPILINGCODE) { - BUILDFUNCS.hbs = parallel(...((sourceDestGlobs) => { - const funcs = []; - for (const [destGlob, sourceGlobs] of Object.entries(sourceDestGlobs)) { - sourceGlobs.forEach((sourceGlob) => { - funcs.push(PLUMBING.hbs(sourceGlob, destGlob)); - }); - } - return funcs; - })(BUILDFILES.hbs)); -} -// #endregion ▄▄▄▄▄ HBS ▄▄▄▄▄ - -// #region ████████ ASSETS: Copying Assets to Dist ████████ ~ -if (ISCOMPILINGCODE) { - const assetPipe = (sourceDestGlobs) => { - const funcs = []; - for (const [destGlob, sourceGlobs] of Object.entries(sourceDestGlobs)) { - sourceGlobs.forEach((sourceGlob) => funcs.push(PLUMBING.toDest(sourceGlob, destGlob))); - } - return funcs; - }; - - if (BUILDFILES.quickAssets) { - BUILDFUNCS.quickAssets = parallel(...assetPipe(BUILDFILES.quickAssets)); - } - if (BUILDFILES.slowAssets) { - BUILDFUNCS.slowAssets = parallel(...assetPipe(BUILDFILES.slowAssets)); - } -} -// #endregion ▄▄▄▄▄ ASSETS ▄▄▄▄▄ - -// #region ▒░▒░▒░▒[EXPORTS]▒░▒░▒░▒ ~ -const {ts, js, quickAssets, slowAssets, ...parallelBuildFuncs} = BUILDFUNCS; -const seriesFuncs = [ts, js, quickAssets].filter((sFunc) => sFunc !== undefined); -if (ISBUILDINGDIST && slowAssets !== undefined) { - seriesFuncs.push(slowAssets); -} -const parallelFuncs = [ - seriesFuncs.length > 0 ? series(...seriesFuncs) : undefined, - ...Object.values(parallelBuildFuncs) -].filter((pFunc) => pFunc !== undefined); -// Const parallelFuncs = parallelBuildFuncs((pFunc) => pFunc !== undefined); - -exports.default = series( - PLUMBING.initDest, - parallel(...parallelFuncs), - PLUMBING.watch -); -// #endregion ▒▒▒▒[EXPORTS]▒▒▒▒ - -// { -// "name": "eunos-blades", -// "version": "0.1.0", -// "description": "An implementation of Kult: Divinity Lost (4th Edition), based on the original Kult 4E Foundry system by Tom LaPorta.", -// "type": "module", -// "scripts": { -// "codehawk": "codehawk ts", -// "preinstall": "npx npm-force-resolutions" -// }, -// "browserslist": [ -// "last 3 versions" -// ], -// "author": "Eunomiac", -// "license": "", -// "private": true, -// "devDependencies": { -// "@es-joy/jsdoccomment": "^0.41.0", -// "@league-of-foundry-developers/foundry-vtt-types": "^9.280.0", -// "@stylistic/eslint-plugin": "^1.3.1", -// "@tsconfig/node16": "^1.0.3", -// "@types/babel__core": "^7.20.5", -// "@types/jquery": "^3.5.27", -// "@types/node": "^18.11.4", -// "@types/prop-types": "^15.7.11", -// "@typescript-eslint/eslint-plugin": "^7.0.2", -// "@typescript-eslint/parser": "^7.0.2", -// "@yaireo/tagify": "^4.17.8", -// "autoprefixer": "^10.4.12", -// "clean-webpack-plugin": "^4.0.0", -// "css-loader": "^6.10.0", -// "codehawk-cli": "^10.0.1", -// "cssnano": "^5.1.13", -// "del": "^7.0.0", -// "ember-template-lint": "^5.13.0", -// "eslint": "^8.56.0", -// "eslint-import-resolver-node": "^0.3.9", -// "eslint-plugin-etc": "^2.0.3", -// "eslint-plugin-import": "^2.26", -// "eslint-plugin-jsdoc": "^46.9.0", -// "fancy-log": "^2.0.0", -// "gulp": "^4.0.2", -// "gulp-debug": "^4.0.0", -// "gulp-header": "^2.0.9", -// "gulp-plumber": "^1.2.1", -// "gulp-postcss": "^9.0.1", -// "gulp-rename": "^2.0.0", -// "gulp-replace": "^1.1.3", -// "gulp-sass": "^5.1.0", -// "gulp-sourcemaps": "^3.0.0", -// "gulp-terser": "^2.1.0", -// "gulp-typescript": "^6.0.0-alpha.1", -// "handlebars": "^4.7", -// "html-webpack-plugin": "^5.6.0", -// "lazypipe": "^1.0.2", -// "merge2": "^1.4.1", -// "postcss": "^8.4.18", -// "postcss-scss": "^4.0.5", -// "prettier": "2.7.1", -// "sass": "^1.69.5", -// "sass-loader": "^14.1.1", -// "style-loader": "^3.3.4", -// "stylelint": "^14.14.0", -// "stylelint-config-prettier": "^9.0.3", -// "stylelint-config-prettier-scss": "^0.0.1", -// "stylelint-config-recess-order": "^3.0.0", -// "stylelint-config-standard": "^29.0.0", -// "stylelint-config-standard-scss": "^5.0.0", -// "ts-loader": "^9.5.1", -// "ts-node": "^10.9.1", -// "typescript": "^5.3.3", -// "webpack": "^5.90.3", -// "webpack-cli": "^5.1.4", -// "webpack-dev-server": "^5.0.2" -// }, -// "dependencies": { -// "@types/yaireo__tagify": "^4.17.0", -// "axios": "^1.5.1", -// "form-data": "^4.0.0", -// "openai": "^4.20.0", -// "tinymce": "^6.2.0", -// "yargs": "^17.7.2" -// }, -// "repository": { -// "url": "" -// } -// } diff --git a/module/BladesActiveEffect.js b/module/BladesActiveEffect.js deleted file mode 100644 index 4ef2bc01..00000000 --- a/module/BladesActiveEffect.js +++ /dev/null @@ -1,365 +0,0 @@ -import BladesActor from "./BladesActor.js"; -import U from "./core/utilities.js"; -import { Tag, BladesPhase, BladesActorType } from "./core/constants.js"; -const FUNCQUEUE = {}; -// {type: "ability", name: "rX:/^(?!Ghost)/"} -const CUSTOMFUNCS = { - addItem: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "addItem", { actor, funcData, isReversing }); - if (actor.hasActiveSubItemOf(funcData)) { - if (isReversing) { - return actor.remSubItem(funcData); - } - } - else if (!isReversing) { - return actor.addSubItem(funcData); - } - return undefined; - }, - addIfChargen: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "addIfChargen", { actor, funcData, isReversing }); - if (!isReversing && game.eunoblades.Tracker?.system.phase !== BladesPhase.CharGen) { - return; - } - const [target, qty] = funcData.split(/:/); - if (isReversing) { - await actor.update({ [target]: U.pInt(getProperty(actor, target)) - U.pInt(qty) }); - return; - } - await actor.update({ [target]: U.pInt(getProperty(actor, target)) + U.pInt(qty) }); - }, - upgradeIfChargen: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "upgradeIfChargen", { actor, funcData, isReversing }); - if (!isReversing && game.eunoblades.Tracker?.system.phase !== BladesPhase.CharGen) { - return; - } - const [target, qty] = funcData.split(/:/); - if (getProperty(actor, target) < U.pInt(qty)) { - await actor.update({ [target]: U.pInt(qty) }); - } - }, - APPLYTOMEMBERS: async () => new Promise(() => undefined), - APPLYTOCOHORTS: async () => new Promise(() => undefined), - remItem: async (actor, funcData, _, isReversing = false) => { - function testString(targetString, testDef) { - if (testDef.startsWith("rX")) { - const pat = new RegExp(testDef.replace(/^rX:\/(.*?)\//, "$1")); - return pat.test(targetString); - } - return targetString === testDef; - } - if (funcData.startsWith("{")) { - if (isReversing) { - console.error("Cannot reverse a 'remItem' custom effect that was defined with a JSON object."); - return undefined; - } - const { type, tags, name } = JSON.parse(funcData); - let activeSubItems = actor.activeSubItems; - if (activeSubItems.length === 0) { - return undefined; - } - if (name) { - activeSubItems = activeSubItems.filter((item) => testString(item.name, name)); - } - if (activeSubItems.length === 0) { - return undefined; - } - if (type) { - activeSubItems = activeSubItems.filter((item) => testString(item.type, type)); - } - if (activeSubItems.length === 0) { - return undefined; - } - if (tags) { - activeSubItems = activeSubItems.filter((item) => item.hasTag(...tags)); - } - if (activeSubItems.length === 0) { - return undefined; - } - eLog.checkLog("activeEffects", "remItem - JSON OBJECT", { actor, funcData: JSON.parse(funcData), isReversing, activeSubItems }); - activeSubItems.forEach((item) => actor.remSubItem(item)); - } - eLog.checkLog("activeEffects", "remItem", { actor, funcData, isReversing }); - if (actor.hasActiveSubItemOf(funcData)) { - return actor.remSubItem(funcData); - } - if (isReversing) { - return actor.addSubItem(funcData); - } - return undefined; - } -}; -var EffectMode; -(function (EffectMode) { - EffectMode[EffectMode["Custom"] = 0] = "Custom"; - EffectMode[EffectMode["Multiply"] = 1] = "Multiply"; - EffectMode[EffectMode["Add"] = 2] = "Add"; - EffectMode[EffectMode["Downgrade"] = 3] = "Downgrade"; - EffectMode[EffectMode["Upgrade"] = 4] = "Upgrade"; - EffectMode[EffectMode["Override"] = 5] = "Override"; -})(EffectMode || (EffectMode = {})); -class BladesActiveEffect extends ActiveEffect { - static Initialize() { - CONFIG.ActiveEffect.documentClass = BladesActiveEffect; - Hooks.on("preCreateActiveEffect", async (effect) => { - eLog.checkLog3("effect", "PRECREATE ActiveEffect", { effect, parent: effect.parent?.name }); - if (!(effect.parent instanceof BladesActor)) { - return; - } - // Does this effect have an "APPLYTOMEMBERS" or "APPLYTOCOHORTS" CUSTOM effect? - if (effect.changes.some((change) => change.key === "APPLYTOMEMBERS")) { - if (BladesActor.IsType(effect.parent, BladesActorType.pc) && BladesActor.IsType(effect.parent.crew, BladesActorType.crew)) { - const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id); - if (otherMembers.length > 0) { - // If PC & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key, leave PC's effect unchanged. - effect.changes = effect.changes.filter((change) => change.key !== "APPLYTOMEMBERS"); - await Promise.all(otherMembers.map(async (member) => member.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - // Set flag with effect's data on member, so future members can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `memberEffects.${effect.id}`, { - appliedTo: otherMembers.map((member) => member.id), - effect: effect.toJSON() - }); - } - } - else if (BladesActor.IsType(effect.parent, BladesActorType.crew)) { - const changeKey = U.pullElement(effect.changes, (change) => change.key === "APPLYTOMEMBERS"); - if (!changeKey) { - return; - } - if (effect.parent.members.length > 0) { - // If Crew & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key - await Promise.all(effect.parent.members.map(async (member) => member.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - } - // Set flag with effect's data on crew, so future members can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `memberEffects.${effect.id}`, { - appliedTo: effect.parent.members.map((member) => member.id), - effect - }); - // Update effect on crew-parent to only include 'APPLYTOMEMBERS' change - await effect.updateSource({ changes: [changeKey] }); - } - } - else if (effect.changes.some((change) => change.key === "APPLYTOCOHORTS") - && (BladesActor.IsType(effect.parent, BladesActorType.pc) || BladesActor.IsType(effect.parent, BladesActorType.crew))) { - if (effect.parent.cohorts.length > 0) { - // If APPLYTOCOHORTS --> Create effect on cohorts - await Promise.all(effect.parent.cohorts.map(async (cohort) => cohort.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - } - // Set flag with effect's data on parent, so future cohorts can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `cohortEffects.${effect.id}`, { - appliedTo: effect.parent.cohorts.map((cohort) => cohort.id), - effect - }); - // Update effect on parent to only include 'APPLYTOCOHORTS' change - await effect.updateSource({ changes: effect.changes.filter((change) => change.key === "APPLYTOCOHORTS") }); - } - // Partition effect.changes into permanent and non-permanent changes: - const [permChanges, changes] = U.partition(effect.changes, (change) => change.key.startsWith("perm")); - await effect.updateSource({ changes }); - for (const permChange of permChanges) { - const { key, value } = permChange; - const permFuncName = key.replace(/^perm/, ""); - if (permFuncName in CUSTOMFUNCS) { - const funcData = { - funcName: permFuncName, - funcData: value, - isReversing: false, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - } - else if (permFuncName === "Add") { - const [target, qty] = value.split(/:/); - effect.parent.update({ [target]: U.pInt(getProperty(effect.parent, target)) + U.pInt(qty) }); - } - } - }); - Hooks.on("applyActiveEffect", (actor, changeData) => { - if (!(actor instanceof BladesActor)) { - return; - } - if (changeData.key in CUSTOMFUNCS) { - const funcData = { - funcName: changeData.key, - funcData: changeData.value, - isReversing: false, - effect: changeData.effect - }; - BladesActiveEffect.ThrottleCustomFunc(actor, funcData); - } - }); - Hooks.on("updateActiveEffect", (effect, { disabled }) => { - if (!(effect.parent instanceof BladesActor)) { - return; - } - const customEffects = effect.changes.filter((changes) => changes.mode === 0); - customEffects.forEach(({ key, value }) => { - const funcData = { - funcName: key, - funcData: value, - isReversing: disabled, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - }); - }); - Hooks.on("deleteActiveEffect", async (effect) => { - if (!(effect.parent instanceof BladesActor)) { - return; - } - // Does this effect have an "APPLYTOMEMBERS" or "APPLYTOCOHORTS" CUSTOM effect? - if (effect.changes.some((change) => change.key === "APPLYTOMEMBERS")) { - if (BladesActor.IsType(effect.parent, BladesActorType.pc) && BladesActor.IsType(effect.parent.crew, BladesActorType.crew)) { - const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id); - if (otherMembers.length > 0) { - // If PC & APPLYTOMEMBERS --> Delete effect on all other members. - await Promise.all(otherMembers - .map(async (member) => Promise.all(member.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `memberEffects.${effect.id}`); - } - else if (BladesActor.IsType(effect.parent, BladesActorType.crew)) { - if (effect.parent.members.length > 0) { - // If CREW & APPLYTOMEMBERS --> Delete effect on all other members. - await Promise.all(effect.parent.members - .map(async (member) => Promise.all(member.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `memberEffects.${effect.id}`); - } - } - else if (effect.changes.some((change) => change.key === "APPLYTOCOHORTS") - && (BladesActor.IsType(effect.parent, BladesActorType.pc, BladesActorType.crew))) { - if (effect.parent.cohorts.length > 0) { - // If APPLYTOCOHORTS --> Delete effect on cohorts. - await Promise.all(effect.parent.cohorts - .map(async (cohort) => Promise.all(cohort.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `cohortEffects.${effect.id}`); - } - const customEffects = effect.changes.filter((changes) => changes.mode === 0); - customEffects.forEach(({ key, value }) => { - const funcData = { - funcName: key, - funcData: value, - isReversing: true, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - }); - }); - } - static async AddActiveEffect(doc, name, eChanges, icon = "systems/eunos-blades/assets/icons/effect-icons/default.png") { - const changes = [eChanges].flat(); - await doc.createEmbeddedDocuments("ActiveEffect", [{ name, icon, changes }]); - } - static ThrottleCustomFunc(actor, data) { - const { funcName, funcData, isReversing, effect } = data; - if (!actor.id) { - return; - } - eLog.display(`Throttling Func: ${funcName}(${funcData}, ${isReversing})`); - // Is there a currently-running function for this actor? - if (actor.id && actor.id in FUNCQUEUE) { - // Is this a duplicate of a function already queued? - const matchingQueue = FUNCQUEUE[actor.id].queue.find((fData) => JSON.stringify(fData) === JSON.stringify(data)); - eLog.checkLog("activeEffects", "... Checking Queue", { data, FUNCQUEUE: FUNCQUEUE[actor.id], matchingQueue }); - if (matchingQueue) { - eLog.error("... Function ALREADY QUEUED, SKIPPING"); - return; - } - FUNCQUEUE[actor.id].queue.push(data); - return; - } - // If not, create FUNCQUEUE entry and run first function. - eLog.display("... Creating New FUNCQUEUE, RUNNING:"); - FUNCQUEUE[actor.id] = { - curFunc: BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing)), - queue: [] - }; - } - static async RunCustomFunc(actor, funcPromise) { - if (!actor.id) { - return; - } - eLog.checkLog("activeEffects", "... Running Func ..."); - await funcPromise; - eLog.checkLog("activeEffects", "... Function Complete!"); - if (FUNCQUEUE[actor.id].queue.length) { - const { funcName, funcData, isReversing, effect } = FUNCQUEUE[actor.id].queue.shift() ?? {}; - if (!funcName || !(funcName in CUSTOMFUNCS)) { - return; - } - if (!funcData) { - return; - } - eLog.display(`Progressing Queue: ${funcName}(${funcData}, ${isReversing}) -- ${FUNCQUEUE[actor.id].queue.length} remaining funcs.`); - FUNCQUEUE[actor.id].curFunc = BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing)); - } - else { - eLog.display("Function Queue Complete! Deleting."); - delete FUNCQUEUE[actor.id]; - } - } - /** - * Manage Active Effect instances through the Actor Sheet via effect control buttons. - * @param {MouseEvent} event The left-click event on the effect control - * @param {Actor|Item} owner The owning entity which manages this effect - */ - static onManageActiveEffect(event, owner) { - event.preventDefault(); - const a = event.currentTarget; - if (a.dataset.action === "create") { - return owner.createEmbeddedDocuments("ActiveEffect", [{ - name: owner.name, - icon: owner.img, - origin: owner.uuid - }]); - } - const selector = a.closest("tr"); - if (selector === null) { - return null; - } - const effect = selector.dataset.effectId ? owner.effects.get(selector.dataset.effectId) : null; - if (!effect) { - return null; - } - switch (a.dataset.action) { - case "edit": - return effect.sheet?.render(true); - case "delete": - eLog.checkLog("activeEffects", "delete effect"); - return effect.delete(); - case "toggle": - return effect.update({ disabled: !effect.disabled }); - default: return null; - } - } - async _preCreate(data, options, user) { - eLog.checkLog3("effect", "ActiveEffect._preCreate()", { data, options, user }); - await super._preCreate(data, options, user); - } - _onDelete(options, userID) { - eLog.checkLog3("effect", "ActiveEffect._onDelete()", { options, userID }); - super._onDelete(options, userID); - } - get isSuppressed() { - // Get source item from "origin.js" field -- of form 'Actor..Item.' - if (!/Actor.*Item/.test(this.origin)) { - return super.isSuppressed; - } - const [actorID, itemID] = this.origin.replace(/Actor\.|Item\./g, "").split("."); - const actor = game.actors.get(actorID); - const item = actor.items.get(itemID); - return super.isSuppressed || item?.hasTag(Tag.System.Archived); - } -} -export default BladesActiveEffect; diff --git a/module/BladesActor.js b/module/BladesActor.js deleted file mode 100644 index b22bf70e..00000000 --- a/module/BladesActor.js +++ /dev/null @@ -1,1074 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region Imports ~ -import U from "./core/utilities.js"; -import C, { BladesActorType, Tag, Playbook, BladesNoticeType, BladesItemType, ActionTrait, PrereqType, AdvancementPoint, Randomizers, Factor } from "./core/constants.js"; -import { BladesPC, BladesCrew, BladesNPC } from "./documents/BladesActorProxy.js"; -import { BladesItem } from "./documents/BladesItemProxy.js"; -import { BladesRollMod } from "./classes/BladesRoll.js"; -import BladesDirector from "./classes/BladesDirector.js"; -import { SelectionCategory } from "./classes/BladesDialog.js"; -// #endregion -// Blades Theme Song: "Bangkok" from The Gray Man soundtrack: https://www.youtube.com/watch?v=cjjImvMqYlo&list=OLAK5uy_k9cZDd1Fbpd25jfDtte5A6HyauD2-cwgk&index=2 -// Also check out Discord thread: https://discord.com/channels/325094888133885952/1152316839163068527 -var BladesActorUniqueTags; -(function (BladesActorUniqueTags) { - BladesActorUniqueTags["CharacterCrew"] = "CharacterCrew"; - BladesActorUniqueTags["VicePurveyor"] = "VicePurveyor"; -})(BladesActorUniqueTags || (BladesActorUniqueTags = {})); -var BladesItemUniqueTypes; -(function (BladesItemUniqueTypes) { - BladesItemUniqueTypes["background"] = "background"; - BladesItemUniqueTypes["vice"] = "vice"; - BladesItemUniqueTypes["crew_playbook"] = "crew_playbook"; - BladesItemUniqueTypes["crew_reputation"] = "crew_reputation"; - BladesItemUniqueTypes["heritage"] = "heritage"; - BladesItemUniqueTypes["playbook"] = "playbook"; - BladesItemUniqueTypes["preferred_op"] = "preferred_op"; -})(BladesItemUniqueTypes || (BladesItemUniqueTypes = {})); -class BladesActor extends Actor { - // #region Static Overrides: Create ~ - static async create(data, options = {}) { - data.token = data.token || {}; - data.system = data.system ?? {}; - // ~ Create world_name - data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, "").trim().replace(/ /g, "_"); - return await super.create(data, options); - } - // #endregion - // #region BladesDocument Implementation ~ - static get All() { return game.actors; } - static Get(actorRef) { - if (actorRef instanceof BladesActor) { - return actorRef; - } - if (U.isDocID(actorRef)) { - return BladesActor.All.get(actorRef); - } - return BladesActor.All.find((a) => a.system.world_name === actorRef) - || BladesActor.All.find((a) => a.name === actorRef); - } - static GetTypeWithTags(docType, ...tags) { - return BladesActor.All.filter((actor) => actor.type === docType) - .filter((actor) => actor.hasTag(...tags)); - } - static IsType(doc, ...types) { - const typeSet = new Set(types); - return doc instanceof BladesActor && typeSet.has(doc.type); - } - get tags() { return this.system.tags ?? []; } - hasTag(...tags) { - return tags.every((tag) => this.tags.includes(tag)); - } - async addTag(...tags) { - const curTags = this.tags; - tags.forEach((tag) => { - if (curTags.includes(tag)) { - return; - } - curTags.push(tag); - }); - eLog.checkLog2("actor", "BladesActor.addTag(...tags)", { tags, curTags }); - await this.update({ "system.tags": curTags }); - } - async remTag(...tags) { - const curTags = this.tags.filter((tag) => !tags.includes(tag)); - eLog.checkLog2("actor", "BladesActor.remTag(...tags)", { tags, curTags }); - await this.update({ "system.tags": curTags }); - } - get tooltip() { - const tooltipText = [this.system.concept, this.system.subtitle] - .filter(Boolean) - .join("

"); - return tooltipText ? (new Handlebars.SafeString(tooltipText)).toString() : undefined; - } - get dialogCSSClasses() { return ""; } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: { - if (BladesActor.IsType(this, BladesActorType.pc)) { - return this.system.tier.value + (this.crew?.getFactorTotal(Factor.tier) ?? 0); - } - return this.system.tier.value; - } - case Factor.quality: return this.getFactorTotal(Factor.tier); - case Factor.scale: { - if (BladesActor.IsType(this, BladesActorType.npc)) { - return this.system.scale; - } - return 0; - } - case Factor.magnitude: { - if (BladesActor.IsType(this, BladesActorType.npc)) { - return this.system.magnitude; - } - return 0; - } - default: return 0; - } - } - // #endregion - // #region SubActorControl Implementation ~ - get subActors() { - return Object.keys(this.system.subactors) - .map((id) => this.getSubActor(id)) - .filter((subActor) => Boolean(subActor)); - } - get activeSubActors() { - return this.subActors.filter((subActor) => !subActor.hasTag(Tag.System.Archived)); - } - get archivedSubActors() { - return this.subActors.filter((subActor) => subActor.hasTag(Tag.System.Archived)); - } - checkActorPrereqs(actor) { - /* Implement any prerequisite checks for embedding actors */ - return Boolean(actor); - } - processEmbeddedActorMatches(globalActors) { - return globalActors - // Step 1: Filter out globals that fail prereqs. - .filter(this.checkActorPrereqs) - // Step 2: Filter out actors that are already active subActors - .filter((gActor) => !this.activeSubActors.some((aActor) => aActor.id === gActor.id)) - // Step 3: Merge subactor data onto matching global actors - .map((gActor) => this.getSubActor(gActor) || gActor) - // Step 4: Sort by name - .sort((a, b) => { - if (a.name === b.name) { - return 0; - } - if (a.name === null) { - return 1; - } - if (b.name === null) { - return -1; - } - if (a.name > b.name) { - return 1; - } - if (a.name < b.name) { - return -1; - } - return 0; - }); - } - getDialogActors(category) { - /* **** NEED TO FILTER OUT ACTORS PLAYER DOESN'T HAVE PERMISSION TO SEE **** */ - const dialogData = {}; - switch (category) { - case SelectionCategory.Contact: - case SelectionCategory.Rival: - case SelectionCategory.Friend: - case SelectionCategory.Acquaintance: { - if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew) - || this.playbookName === null) { - return false; - } - dialogData.Main = this.processEmbeddedActorMatches(BladesActor.GetTypeWithTags(BladesActorType.npc, this.playbookName)); - return dialogData; - } - case SelectionCategory.VicePurveyor: { - if (!BladesActor.IsType(this, BladesActorType.pc) || !this.vice?.name) { - return false; - } - dialogData.Main = this.processEmbeddedActorMatches(BladesActor.GetTypeWithTags(BladesActorType.npc, this.vice.name)); - return dialogData; - } - case SelectionCategory.Crew: { - dialogData.Main = BladesActor.GetTypeWithTags(BladesActorType.crew); - return dialogData; - } - default: return false; - } - } - async addSubActor(actorRef, tags) { - let focusSubActor; - // Does an embedded subActor of this Actor already exist on the character? - if (this.hasSubActorOf(actorRef)) { - const subActor = this.getSubActor(actorRef); - if (!subActor) { - return; - } - // Is it an archived Item? - if (subActor.hasTag(Tag.System.Archived)) { - // Unarchive it - await subActor.remTag(Tag.System.Archived); - } - // Make it the focus item. - focusSubActor = subActor; - } - else { - // Is it not embedded at all? Create new entry in system.subactors from global actor - const actor = BladesActor.Get(actorRef); - if (!actor) { - return; - } - const subActorData = {}; - if (tags) { - subActorData.tags = U.unique([ - ...actor.tags, - ...tags - ]); - } - // Await the update, then make the retrieved subactor the focus - await this.update({ [`system.subactors.${actor.id}`]: subActorData }); - focusSubActor = this.getSubActor(actor.id); - } - if (!focusSubActor) { - return; - } - // Does this Actor contain any tags limiting it to one per actor? - const uniqueTags = focusSubActor.tags.filter((tag) => tag in BladesActorUniqueTags); - if (uniqueTags.length > 0) { - // ... then archive all other versions. - uniqueTags.forEach((uTag) => this.activeSubActors - .filter((subActor) => Boolean(focusSubActor?.id - && subActor.id !== focusSubActor.id - && subActor.hasTag(uTag))) - .map((subActor) => this.remSubActor(subActor.id))); - } - } - getSubActor(actorRef) { - const actor = BladesActor.Get(actorRef); - if (!actor?.id) { - return undefined; - } - if (!BladesActor.IsType(actor, BladesActorType.npc, BladesActorType.faction)) { - return actor; - } - const subActorData = (this.system.subactors[actor.id] ?? {}); - Object.assign(actor.system, subActorData); - actor.parentActor = this; - return actor; - } - hasSubActorOf(actorRef) { - const actor = BladesActor.Get(actorRef); - if (!actor) { - return false; - } - return actor?.id ? actor.id in this.system.subactors : false; - } - async updateSubActor(actorRef, upData) { - const updateData = U.objExpand(upData); - if (!updateData.system) { - return undefined; - } - const actor = BladesActor.Get(actorRef); - if (!actor) { - return undefined; - } - // DiffObject new update data against actor data. - const diffUpdateSystem = U.objDiff(actor.system, updateData.system); - // Merge new update data onto current subactor data. - const mergedSubActorSystem = U.objMerge(this.system.subactors[actor.id] ?? {}, diffUpdateSystem, { isReplacingArrays: true, isConcatenatingArrays: false }); - // Confirm this update changes data: - if (JSON.stringify(this.system.subactors[actor.id]) === JSON.stringify(mergedSubActorSystem)) { - return undefined; - } - // Update actor with new subactor data. - return this.update({ [`system.subactors.${actor.id}`]: null }, undefined, true) - .then(() => this.update({ [`system.subactors.${actor.id}`]: mergedSubActorSystem }, undefined, true)) - .then(() => actor.sheet?.render()); - } - async remSubActor(actorRef) { - const subActor = this.getSubActor(actorRef); - if (!subActor) { - return; - } - await this.update({ "system.subactors": mergeObject(this.system.subactors, { [`-=${subActor.id}`]: null }) }, undefined, true); - } - async clearSubActors(isReRendering = true) { - this.subActors.forEach((subActor) => { - if (subActor.parentActor?.id === this.id) { - subActor.clearParentActor(isReRendering); - } - }); - await this.sheet?.render(); - } - async clearParentActor(isReRendering = true) { - const { parentActor } = this; - if (!parentActor) { - return; - } - this.parentActor = undefined; - this.system = this._source.system; - this.ownership = this._source.ownership; - this.prepareData(); - if (isReRendering) { - await this.sheet?.render(); - } - } - // #endregion - // #region SubItemControl Implementation ~ - get subItems() { return Array.from(this.items); } - getSubItemsOfType(itemType) { - return this.items.filter((item) => item.type === itemType); - } - get activeSubItems() { return this.items.filter((item) => !item.hasTag(Tag.System.Archived)); } - get archivedSubItems() { return this.items.filter((item) => item.hasTag(Tag.System.Archived)); } - _checkItemPrereqs(item) { - if (!item.system.prereqs) { - return true; - } - for (const [pType, pReqs] of Object.entries(item.system.prereqs)) { - const pReqArray = Array.isArray(pReqs) ? pReqs : [pReqs.toString()]; - const hitRecord = {}; - if (!this._processPrereqArray(pReqArray, pType, hitRecord)) { - return false; - } - } - return true; - } - _processPrereqArray(pReqArray, pType, hitRecord) { - while (pReqArray.length) { - const pString = pReqArray.pop(); - hitRecord[pType] ??= []; - if (!this._processPrereqType(pType, pString, hitRecord)) { - return false; - } - } - return true; - } - _processPrereqType(pType, pString, hitRecord) { - switch (pType) { - case PrereqType.HasActiveItem: { - return this._processActiveItemPrereq(pString, hitRecord, pType); - } - case PrereqType.HasActiveItemsByTag: { - return this._processActiveItemsByTagPrereq(pString, hitRecord, pType); - } - case PrereqType.AdvancedPlaybook: { - return this._processAdvancedPlaybookPrereq(); - } - default: return true; - } - } - _processActiveItemPrereq(pString, hitRecord, pType) { - const thisItem = this.activeSubItems - .filter((i) => !hitRecord[pType]?.includes(i.id)) - .find((i) => i.system.world_name === pString); - if (thisItem) { - hitRecord[pType]?.push(thisItem.id); - return true; - } - else { - return false; - } - } - _processActiveItemsByTagPrereq(pString, hitRecord, pType) { - const thisItem = this.activeSubItems - .filter((i) => !hitRecord[pType]?.includes(i.id)) - .find((i) => i.hasTag(pString)); - if (thisItem) { - hitRecord[pType]?.push(thisItem.id); - return true; - } - else { - return false; - } - } - _processAdvancedPlaybookPrereq() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return false; - } - if (!this.playbookName || ![Playbook.Ghost, Playbook.Hull, Playbook.Vampire].includes(this.playbookName)) { - return false; - } - return true; - } - _processEmbeddedItemMatches(globalItems) { - return globalItems - // Step 1: Filter out globals that fail prereqs. - .filter((item) => this._checkItemPrereqs(item)) - // Step 2: Filter out already-active items based on max_per_score (unless MultiplesOk) - .filter((gItem) => gItem.hasTag(Tag.System.MultiplesOK) - || (gItem.system.max_per_score ?? 1) - > this.activeSubItems.filter((sItem) => sItem.system.world_name === gItem.system.world_name).length) - // Step 3: Replace with matching Archived, Embedded subItems - .map((gItem) => { - const matchingSubItems = this.archivedSubItems.filter((sItem) => sItem.system.world_name === gItem.system.world_name); - if (matchingSubItems.length > 0) { - return matchingSubItems; - } - else { - return gItem; - } - }) - .flat() - // Step 4: Apply CSS classes - .map((sItem) => { - sItem.dialogCSSClasses = ""; - const cssClasses = []; - if (sItem.isEmbedded) { - cssClasses.push("embedded"); - } - if (sItem.hasTag(Tag.Gear.Fine)) { - cssClasses.push("fine-quality"); - } - if (sItem.hasTag(Tag.System.Featured)) { - cssClasses.push("featured-item"); - } - if ([BladesItemType.ability, BladesItemType.crew_ability].includes(sItem.type)) { - if (this.getAvailableAdvancements("Ability") === 0) { - cssClasses.push("locked"); - } - else if ((sItem.system.price ?? 1) > this.getAvailableAdvancements("Ability")) { - cssClasses.push("locked", "unaffordable"); - } - else if ((sItem.system.price ?? 1) > 1) { - cssClasses.push("expensive"); - } - } - if ([BladesItemType.crew_upgrade].includes(sItem.type)) { - if (this.getAvailableAdvancements("Upgrade") === 0) { - cssClasses.push("locked"); - } - else if ((sItem.system.price ?? 1) > this.getAvailableAdvancements("Upgrade")) { - cssClasses.push("locked", "unaffordable"); - } - else if ((sItem.system.price ?? 1) > 1) { - cssClasses.push("expensive"); - } - } - if (cssClasses.length > 0) { - sItem.dialogCSSClasses = cssClasses.join(" "); - } - return sItem; - }) - // Step 5: Sort by featured, then by fine, then by world_name, then embedded first sorted by name - .sort((a, b) => { - if (a.hasTag(Tag.System.Featured) && !b.hasTag(Tag.System.Featured)) { - return -1; - } - if (!a.hasTag(Tag.System.Featured) && b.hasTag(Tag.System.Featured)) { - return 1; - } - if (a.hasTag(Tag.Gear.Fine) && !b.hasTag(Tag.Gear.Fine)) { - return -1; - } - if (!a.hasTag(Tag.Gear.Fine) && b.hasTag(Tag.Gear.Fine)) { - return 1; - } - if (a.system.world_name > b.system.world_name) { - return 1; - } - if (a.system.world_name < b.system.world_name) { - return -1; - } - if (a.isEmbedded && !b.isEmbedded) { - return -1; - } - if (!a.isEmbedded && b.isEmbedded) { - return 1; - } - if (a.name === b.name) { - return 0; - } - if (a.name === null) { - return 1; - } - if (b.name === null) { - return -1; - } - if (a.name > b.name) { - return 1; - } - if (a.name < b.name) { - return -1; - } - return 0; - }); - } - getSubItem(itemRef, activeOnly = false) { - const activeCheck = (i) => !activeOnly || !i.hasTag(Tag.System.Archived); - if (typeof itemRef === "string" && this.items.get(itemRef)) { - const returnItem = this.items.get(itemRef); - if (returnItem && activeCheck(returnItem)) { - return returnItem; - } - else { - return undefined; - } - } - else { - const globalItem = BladesItem.Get(itemRef); - if (!globalItem) { - return undefined; - } - return this.items.find((item) => item.name === globalItem.name && activeCheck(item)) - ?? this.items.find((item) => item.system.world_name === globalItem.system.world_name && activeCheck(item)); - } - } - hasSubItemOf(itemRef) { - const item = BladesItem.Get(itemRef); - if (!item) { - return false; - } - return Boolean(this.items.find((i) => i.system.world_name === item.system.world_name)); - } - hasActiveSubItemOf(itemRef) { - const item = BladesItem.Get(itemRef); - if (!item) { - return false; - } - return Boolean(this.items.find((i) => !i.hasTag(Tag.System.Archived) - && i.system.world_name === item.system.world_name)); - } - async addSubItem(itemRef) { - /** - * Determines whether a submitted BladesItemType is a type that should appear only once - * on any given Actor. - * @param {BladesItemType} type - * @returns {boolean} True if the type is a BladesItemUniqueTypes - **/ - function isBladesItemUniqueTypes(type) { - return Object.values(BladesItemUniqueTypes).includes(type); - } - eLog.checkLog3("subitems", "[addSubItem] itemRef", itemRef); - let focusItem; - // Does an embedded copy of this item already exist on the character? - const embeddedItem = this.getSubItem(itemRef); - if (embeddedItem) { - // Is it an archived Item? - if (embeddedItem.hasTag(Tag.System.Archived)) { - // Unarchive it & make it the focus item. - await embeddedItem.remTag(Tag.System.Archived); - focusItem = embeddedItem; - eLog.checkLog3("subitems", `[addSubItem] IS ARCHIVED EMBEDDED > Removing 'Archived' Tag, '${focusItem.id}':`, focusItem); - } - else { // Otherwise... - // Duplicate the item, and make the newly-created item the focus. - focusItem = await BladesItem.create([embeddedItem], { parent: this }); - eLog.checkLog3("subitems", `[addSubItem] IS ACTIVE EMBEDDED > Duplicating, focusItem '${focusItem.id}':`, focusItem); - } - } - else { - // Is it not embedded at all? Embed from global instance. - const globalItem = BladesItem.Get(itemRef); - eLog.checkLog3("subitems", `[addSubItem] IS NOT EMBEDDED > Fetching Global, globalItem '${globalItem?.id}':`, globalItem); - if (!globalItem) { - return; - } - focusItem = await BladesItem.create([globalItem], { parent: this }); - focusItem = this.items.getName(globalItem.name); - } - // Is this item type limited to one per actor? - if (focusItem && isBladesItemUniqueTypes(focusItem.type)) { - // ... then archive all other versions. - await Promise.all(this.activeSubItems - .filter((subItem) => subItem.type === focusItem?.type - && subItem.system.world_name !== focusItem?.system.world_name - && !subItem.hasTag(Tag.System.Archived)) - .map(this.remSubItem.bind(this))); - } - } - async remSubItem(itemRef) { - const subItem = this.getSubItem(itemRef); - if (!subItem) { - return; - } - if (subItem.type !== BladesItemType.gear) { - this.purgeSubItem(itemRef); - return; - } - eLog.checkLog("actorTrigger", `Removing SubItem ${subItem.name}`, subItem); - if (subItem.hasTag(Tag.System.Archived)) { - return; - } - await subItem.addTag(Tag.System.Archived); - } - async purgeSubItem(itemRef) { - const subItem = this.getSubItem(itemRef); - if (!subItem || subItem.hasTag(Tag.System.Archived)) { - return; - } - await subItem.delete(); - } - // #endregion - // #region Advancement Implementation ~ - // get totalAbilityPoints(): number { - // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 } - // if (!this.playbook) { return 0 } - // switch (this.type) { - // case BladesActorType.pc: return this.system.advancement.ability ?? 0; - // case BladesActorType.crew: return Math.floor(0.5 * (this.system.advancement.general ?? 0)) - // + (this.system.advancement.ability ?? 0); - // default: return 0; - // } - // } - // get spentAbilityPoints(): number { - // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 } - // if (!this.playbook) { return 0 } - // return this.abilities.reduce((total, ability) => total + (ability.system.price ?? 1), 0); - // } - // get getAvailableAdvancements("Ability")(): number { - // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 } - // if (!this.playbook) { return 0 } - // return this.totalAbilityPoints - this.spentAbilityPoints; - // } - /* Need simple getters for total ability & upgrade points that check for PRICES of items - (upgrade.system.price ?? 1) */ - async grantAdvancementPoints(allowedTypes, amount = 1) { - const aPtKey = Array.isArray(allowedTypes) - ? [...allowedTypes].sort((a, b) => a.localeCompare(b)).join("_") - : allowedTypes; - await this.update({ [`system.advancement_points.${aPtKey}`]: (this.system.advancement_points?.[aPtKey] ?? 0) + amount }); - } - async removeAdvancementPoints(allowedTypes, amount = 1) { - const aPtKey = Array.isArray(allowedTypes) - ? [...allowedTypes].sort((a, b) => a.localeCompare(b)).join("_") - : allowedTypes; - const newCount = this.system.advancement_points?.[aPtKey] ?? 0 - amount; - if (newCount <= 0 && aPtKey in (this.system.advancement_points ?? [])) { - await this.update({ [`system.advancement_points.-=${aPtKey}`]: null }); - } - else { - await this.update({ [`system.advancement_points.${aPtKey}`]: newCount }); - } - } - getAvailableAdvancements(trait) { - if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { - return 0; - } - if (trait in ActionTrait) { - return 1; - } - if (trait === "Cohort") { - const pointsCohort = this.system.advancement_points?.[AdvancementPoint.Cohort] ?? 0; - const spentCohort = this.cohorts.length; - return Math.max(0, pointsCohort - spentCohort); - } - const pointsAbility = this.system.advancement_points?.[AdvancementPoint.Ability] ?? 0; - const pointsCohortType = this.system.advancement_points?.[AdvancementPoint.CohortType] ?? 0; - const pointsUpgrade = this.system.advancement_points?.[AdvancementPoint.Upgrade] ?? 0; - const pointsUpgradeOrAbility = this.system.advancement_points?.[AdvancementPoint.UpgradeOrAbility] ?? 0; - const spentAbility = U.sum(this.items - .filter((item) => BladesItem.IsType(item, BladesItemType.ability, BladesItemType.crew_ability)) - .map((abil) => abil.system.price ?? 1)); - const spentCohortType = U.sum(this.cohorts - .map((cohort) => Math.max(0, U.unique(Object.values(cohort.system.subtypes)).length - 1))); - const spentUpgrade = U.sum(this.items - .filter((item) => BladesItem.IsType(item, BladesItemType.crew_upgrade)) - .map((upgrade) => upgrade.system.price ?? 1)); - const excessUpgrade = Math.max(0, spentUpgrade - pointsUpgrade); - const excessCohortType = Math.max(0, spentCohortType - pointsCohortType); - const excessAbility = Math.max(0, spentAbility - pointsAbility); - const remainingAbility = Math.max(0, pointsAbility - spentAbility); - const remainingCohortType = Math.max(0, pointsCohortType - spentCohortType); - const remainingUpgrade = Math.max(0, pointsUpgrade - spentUpgrade); - const remainingUpgradeOrAbility = Math.max(0, pointsUpgradeOrAbility - excessUpgrade - (2 * excessAbility) - (2 * excessCohortType)); - if (trait === "Ability") { - return remainingAbility + Math.floor(0.5 * remainingUpgradeOrAbility); - } - if (trait === "Upgrade") { - return remainingUpgrade + remainingUpgradeOrAbility; - } - if (trait === "CohortType") { - return remainingCohortType + remainingUpgradeOrAbility; - } - return 0; - } - get availableAbilityPoints() { return this.getAvailableAdvancements("Ability"); } - get availableUpgradePoints() { return this.getAvailableAdvancements("Upgrade"); } - get availableCohortPoints() { return this.getAvailableAdvancements("Cohort"); } - get availableCohortTypePoints() { return this.getAvailableAdvancements("CohortType"); } - get canPurchaseAbility() { return this.availableAbilityPoints > 0; } - get canPurchaseUpgrade() { return this.availableUpgradePoints > 0; } - get canPurchaseCohort() { return this.availableCohortPoints > 0; } - get canPurchaseCohortType() { return this.availableCohortTypePoints > 0; } - async advancePlaybook() { - if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew) || !this.playbook) { - return; - } - await this.update({ "system.experience.playbook.value": 0 }); - if (this instanceof BladesPC) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} Advances their Playbook!`, - body: `${this.name}, select a new Ability on your Character Sheet.`, - type: BladesNoticeType.push, - cssClasses: "advancement-alert" - }); - this.grantAdvancementPoints(AdvancementPoint.Ability); - return; - } - if (this instanceof BladesCrew) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: "You Advance your Crew Playbook!", - body: "Select new Upgrades and/or Abilities on your Crew Sheet.", - type: BladesNoticeType.push, - cssClasses: "advancement-alert crew-advancement-alert" - }); - const coinGained = this.system.tier.value + 2; - this.members.forEach((member) => { - if (member.primaryUser?.id) { - BladesDirector.getInstance().pushNotice_SocketCall(member.primaryUser?.id, { - title: "Your Stash Increases! (Crew Advancement)", - type: BladesNoticeType.push, - body: `You gain ${coinGained} Stash from Crew Advancement.`, - cssClasses: "stash-alert" - }); - member.addStash(coinGained); - } - }); - this.grantAdvancementPoints(AdvancementPoint.UpgradeOrAbility, 2); - } - } - async advanceAttribute(attribute) { - if (!(this instanceof BladesPC)) { - return; - } - if (!this.primaryUser?.id) { - return; - } - await this.update({ [`system.experience.${attribute}.value`]: 0 }); - const actions = C.Action[attribute].map((action) => `${U.tCase(action)}`); - BladesDirector.getInstance().pushNotice_SocketCall(this.primaryUser.id, { - title: `${this.name} Advances their ${U.uCase(attribute)}!`, - body: `${this.name}, add a dot to one of ${U.oxfordize(actions, true, "or")}.`, - type: BladesNoticeType.push, - cssClasses: "advancement-alert" - }); - } - get isAtWar() { - if (BladesNPC.IsType(this)) { - return false; - } - if (BladesPC.IsType(this)) { - return this.crew?.isAtWar ?? false; - } - return Object.values(this.system.at_war_with ?? {}) - .filter((val) => val === true) - .length > 0; - } - // #endregion - // #region BladesSubActor Implementation ~ - parentActor; - get isSubActor() { return this.parentActor !== undefined; } - // #endregion - // #region BladesRoll Implementation ~ - get rollPrimaryModsSchemaSet() { - return BladesRollMod.ParseDocModsToSchemaSet(this); - } - get rollFactors() { - const factorData = { - [Factor.tier]: { - name: Factor.tier, - display: "Tier", - value: this.getFactorTotal(Factor.tier), - max: this.getFactorTotal(Factor.tier), - baseVal: this.getFactorTotal(Factor.tier), - isActive: true, - isPrimary: true, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - name: Factor.quality, - display: "Quality", - value: this.getFactorTotal(Factor.quality), - max: this.getFactorTotal(Factor.quality), - baseVal: this.getFactorTotal(Factor.quality), - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - }; - return factorData; - } - // #region BladesRoll.PrimaryDoc Implementation - get rollPrimaryID() { return this.id; } - get rollPrimaryDoc() { return this; } - get rollPrimaryName() { return this.name; } - get rollPrimaryType() { - if (![BladesActorType.pc, BladesActorType.crew].includes(this.type)) { - throw new Error(`BladesActor of type '${this.type}' ("${this.name}") cannot be RollPrimary.`); - } - return this.type; - } - get rollPrimaryImg() { return this.img; } - // #endregion - // #endregion - // #region BladesCrew Implementation ~ - // #endregion - // #region PREPARING DERIVED DATA ~ - prepareDerivedData() { - if (BladesActor.IsType(this, BladesActorType.pc)) { - this._preparePCData(this.system); - } - if (BladesActor.IsType(this, BladesActorType.crew)) { - this._prepareCrewData(this.system); - } - } - _preparePCData(system) { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return; - } - // Extract experience clues from playbook item, if any - if (this.playbook) { - system.experience.clues = [ - ...system.experience.clues, - ...Object.values(this.playbook.system.experience_clues) - .filter((clue) => Boolean(clue.trim())) - ]; - } - // Extract gather information questions from playbook item, if any - if (this.playbook) { - system.gather_info = [ - ...system.gather_info, - ...Object.values(this.playbook.system.gather_info_questions) - .filter((question) => Boolean(question.trim())) - ]; - } - } - _prepareCrewData(system) { - if (!BladesActor.IsType(this, BladesActorType.crew)) { - return; - } - // Extract experience clues and turfs from playbook item, if any - if (this.playbook) { - system.experience.clues = [ - ...system.experience.clues, - ...Object.values(this.playbook.system.experience_clues) - .filter((clue) => Boolean(clue.trim())) - ]; - system.turfs = this.playbook.system.turfs; - } - } - // #endregion - // #region OVERRIDES: _onCreateDescendantDocuments, update ~ - // @ts-expect-error New method not defined in @league VTT types. - async _onCreateDescendantDocuments(parent, collection, docs, data, options, userId) { - await Promise.all(docs.map(async (doc) => { - if (BladesItem.IsType(doc, BladesItemType.playbook, BladesItemType.crew_playbook)) { - await Promise.all(this.activeSubItems - .filter((aItem) => aItem.type === doc.type && aItem.system.world_name !== doc.system.world_name) - .map((aItem) => this.remSubItem(aItem))); - } - })); - // @ts-expect-error New method not defined in @league VTT types. - await super._onCreateDescendantDocuments(parent, collection, docs, data, options, userId); - eLog.checkLog("actorTrigger", "_onCreateDescendantDocuments", { parent, collection, docs, data, options, userId }); - docs.forEach((doc) => { - if (BladesItem.IsType(doc, BladesItemType.vice) && BladesActor.IsType(this, BladesActorType.pc)) { - this.activeSubActors - .filter((subActor) => subActor.hasTag(Tag.NPC.VicePurveyor) && !subActor.hasTag(doc.name)) - .forEach((subActor) => { this.remSubActor(subActor); }); - } - }); - } - async update(updateData, context, isSkippingSubActorCheck = false) { - if (!updateData) { - return super.update(updateData); - } - if (BladesActor.IsType(this, BladesActorType.crew)) { - if (!this.playbook) { - return undefined; - } - eLog.checkLog("actorTrigger", "Updating Crew", { updateData }); - const playbookUpdateData = Object.fromEntries(Object.entries(flattenObject(updateData)) - .filter(([key, _]) => key.startsWith("system.turfs."))); - updateData = Object.fromEntries(Object.entries(flattenObject(updateData)) - .filter(([key, _]) => !key.startsWith("system.turfs."))); - eLog.checkLog("actorTrigger", "Updating Crew", { crewUpdateData: updateData, playbookUpdateData }); - const diffPlaybookData = diffObject(flattenObject(this.playbook), playbookUpdateData); - delete diffPlaybookData._id; - if (!U.isEmpty(diffPlaybookData)) { - await this.playbook.update(playbookUpdateData, context) - .then(() => this.sheet?.render(false)); - } - } - else if ((BladesActor.IsType(this, BladesActorType.npc) - || BladesActor.IsType(this, BladesActorType.faction)) - && this.parentActor - && !isSkippingSubActorCheck) { - // This is an embedded Actor: Update it as a subActor of parentActor. - return this.parentActor.updateSubActor(this.id, updateData) - .then(() => this); - } - return super.update(updateData, context); - } - // #endregion - // #region Rolling Dice ~ - /** - * Creates modifiers for dice roll. - * - * @param {int} rs - * Min die modifier - * @param {int} re - * Max die modifier - * @param {int} s - * Selected die - */ - createListOfDiceMods(rs, re, s) { - let text = ""; - if (s === "") { - s = 0; - } - for (let i = rs; i <= re; i++) { - let plus = ""; - if (i >= 0) { - plus = "+"; - } - text += ``; - } - return text; - } - // #endregion Rolling Dice - // #region NPC Randomizers ~ - updateRandomizers() { - if (!BladesActor.IsType(this, BladesActorType.npc)) { - return; - } - const titleChance = 0.05; - const suffixChance = 0.01; - const { persona, secret, random } = this.system; - /** - * Returns a random element from an array, optionally excluding all values - * passed as subsequent parameters. - * @param {string[]} arr The array to randomly select from. - * @param {...string} curVals The values to exclude from the sample. - */ - function sampleArray(arr, ...curVals) { - arr = arr.filter((elem) => !curVals.includes(elem)); - if (!arr.length) { - return ""; - } - return arr[Math.floor(Math.random() * arr.length)]; - } - const randomGen = { - name: (gen) => { - return [ - Math.random() <= titleChance - ? sampleArray(Randomizers.NPC.name_title) - : "", - sampleArray([ - ...((gen ?? "").charAt(0).toLowerCase() !== "m" ? Randomizers.NPC.name_first.female : []), - ...((gen ?? "").charAt(0).toLowerCase() !== "f" ? Randomizers.NPC.name_first.male : []) - ]), - `"${sampleArray(Randomizers.NPC.name_alias)}"`, - sampleArray(Randomizers.NPC.name_surname), - Math.random() <= suffixChance - ? sampleArray(Randomizers.NPC.name_suffix) - : "" - ].filter((val) => Boolean(val)).join(" "); - }, - background: () => sampleArray(Randomizers.NPC.background, random.background.value), - heritage: () => sampleArray(Randomizers.NPC.heritage, random.heritage.value), - profession: () => sampleArray(Randomizers.NPC.profession, random.profession.value), - gender: () => sampleArray(Randomizers.NPC.gender, persona.gender.value), - appearance: () => sampleArray(Randomizers.NPC.appearance, persona.appearance.value), - goal: () => sampleArray(Randomizers.NPC.goal, persona.goal.value, secret.goal.value), - method: () => sampleArray(Randomizers.NPC.method, persona.method.value, secret.method.value), - trait: () => sampleArray(Randomizers.NPC.trait, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value), - interests: () => sampleArray(Randomizers.NPC.interests, persona.interests.value, secret.interests.value), - quirk: () => sampleArray(Randomizers.NPC.quirk, persona.quirk.value), - style: (gen = "") => sampleArray([ - ...(gen.charAt(0).toLowerCase() !== "m" ? Randomizers.NPC.style.female : []), - ...(gen.charAt(0).toLowerCase() !== "f" ? Randomizers.NPC.style.male : []) - ], persona.style.value) - }; - const gender = persona.gender.isLocked ? persona.gender.value : randomGen.gender(); - const updateKeys = [ - ...Object.keys(persona).filter((key) => !persona[key]?.isLocked), - ...Object.keys(random).filter((key) => !random[key]?.isLocked), - ...Object.keys(secret).filter((key) => !secret[key]?.isLocked) - .map((secretKey) => `secret-${secretKey}`) - ]; - eLog.checkLog("Update Keys", { updateKeys }); - const updateData = {}; - updateKeys.forEach((key) => { - switch (key) { - case "name": - case "heritage": - case "background": - case "profession": { - const randomVal = randomGen[key](); - updateData[`system.random.${key}`] = { - isLocked: false, - value: randomVal || random[key].value - }; - break; - } - case "secret-goal": - case "secret-interests": - case "secret-method": { - key = key.replace(/^secret-/, ""); - const randomVal = randomGen[key](); - updateData[`system.secret.${key}`] = { - isLocked: false, - value: randomVal || secret[key].value - }; - break; - } - case "gender": { - updateData[`system.persona.${key}`] = { - isLocked: persona.gender.isLocked, - value: gender - }; - break; - } - case "trait1": - case "trait2": - case "trait3": - case "secret-trait": { - const trait1 = persona.trait1.isLocked - ? persona.trait1.value - : sampleArray(Randomizers.NPC.trait, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value); - const trait2 = persona.trait2.isLocked - ? persona.trait2.value - : sampleArray(Randomizers.NPC.trait, trait1, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value); - const trait3 = persona.trait3.isLocked - ? persona.trait3.value - : sampleArray(Randomizers.NPC.trait, trait1, trait2, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value); - const secretTrait = secret.trait.isLocked - ? secret.trait.value - : sampleArray(Randomizers.NPC.trait, trait1, trait2, trait3, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value); - if (!persona.trait1.isLocked) { - updateData["system.persona.trait1"] = { - isLocked: false, - value: trait1 - }; - } - if (!persona.trait2.isLocked) { - updateData["system.persona.trait2"] = { - isLocked: false, - value: trait2 - }; - } - if (!persona.trait3.isLocked) { - updateData["system.persona.trait3"] = { - isLocked: false, - value: trait3 - }; - } - if (!secret.trait.isLocked) { - updateData["system.secret.trait"] = { - isLocked: false, - value: secretTrait - }; - } - break; - } - default: { - const randomVal = randomGen[key](); - updateData[`system.persona.${key}`] = { - isLocked: false, - value: randomVal || persona[key].value - }; - break; - } - } - }); - this.update(updateData); - } - // #endregion NPC Randomizers - // Unlock lower-level update method for subclasses - async callOnUpdate(...args) { - await this._onUpdate(...args); - } -} -export default BladesActor; diff --git a/module/BladesChat.js b/module/BladesChat.js deleted file mode 100644 index cb5aaac0..00000000 --- a/module/BladesChat.js +++ /dev/null @@ -1,45 +0,0 @@ -// #region IMPORTS ~ -import { ApplyTooltipAnimations, ApplyConsequenceAnimations } from "./core/gsap.js"; -import BladesConsequence from "./sheets/roll/BladesConsequence.js"; -// #endregion -class BladesChat extends ChatMessage { - static Initialize() { - // let lastMessageID: string|false = Array.from(game.messages).pop()?.id ?? ""; - Hooks.on("renderChatMessage", (_msg, html) => { - ApplyTooltipAnimations(html); - ApplyConsequenceAnimations(html); - BladesConsequence.ApplyChatListeners(html); - html.addClass("display-ok"); - // if (lastMessageID && _msg.id === lastMessageID) { - // setTimeout(() => { - // $(document).find("#chat .chat-message:not([class*='-roll'])") - // .remove(); - // }, 500); - // lastMessageID = false; - // } - }); - return loadTemplates([ - "systems/eunos-blades/templates/chat/roll-result-action-roll.hbs", - "systems/eunos-blades/templates/chat/roll-result-resistance-roll.hbs", - "systems/eunos-blades/templates/chat/roll-result-fortune-roll.hbs", - "systems/eunos-blades/templates/chat/roll-result-indulgevice-roll.hbs" - ]); - } - static async ConstructRollOutput(rollInst) { - const messageData = { - speaker: rollInst.getSpeaker(BladesChat.getSpeaker()), - content: await rollInst.getResultHTML("") - }; - const chatMessage = await BladesChat.create(messageData, {}); - await chatMessage.update({ content: await rollInst.getResultHTML(chatMessage.id) }); - chatMessage.rollInst = rollInst; - return chatMessage; - } - _rollInst; - get rollInst() { return this._rollInst; } - set rollInst(rollInst) { this._rollInst = rollInst; } - async reRender(html) { - this.update({ content: html }); - } -} -export default BladesChat; diff --git a/module/BladesDialog.js b/module/BladesDialog.js deleted file mode 100644 index 9d4f894e..00000000 --- a/module/BladesDialog.js +++ /dev/null @@ -1,667 +0,0 @@ -import { ApplyTooltipAnimations } from "./core/gsap.js"; -import U from "./core/utilities.js"; -import { BladesActor, BladesPC } from "./documents/BladesActorProxy.js"; -import BladesItem from "./BladesItem.js"; -import BladesRoll from "./BladesRoll.js"; -import BladesConsequence from "./sheets/roll/BladesConsequence.js"; -import C, { RollResult, ConsequenceType, AttributeTrait, Position } from "./core/constants.js"; -import BladesAI, { AGENTS } from "./core/ai.js"; -export var SelectionCategory; -(function (SelectionCategory) { - SelectionCategory["Heritage"] = "Heritage"; - SelectionCategory["Background"] = "Background"; - SelectionCategory["Vice"] = "Vice"; - SelectionCategory["Playbook"] = "Playbook"; - SelectionCategory["Reputation"] = "Reputation"; - SelectionCategory["Preferred_Op"] = "Preferred_Op"; - SelectionCategory["Gear"] = "Gear"; - SelectionCategory["Ability"] = "Ability"; - SelectionCategory["Faction"] = "Faction"; - SelectionCategory["Upgrade"] = "Upgrade"; - SelectionCategory["Cohort_Gang"] = "Cohort_Gang"; - SelectionCategory["Cohort_Expert"] = "Cohort_Expert"; - SelectionCategory["Feature"] = "Feature"; - SelectionCategory["Stricture"] = "Stricture"; - SelectionCategory["VicePurveyor"] = "VicePurveyor"; - SelectionCategory["Acquaintance"] = "Acquaintance"; - SelectionCategory["Friend"] = "Friend"; - SelectionCategory["Rival"] = "Rival"; - SelectionCategory["Crew"] = "Crew"; - SelectionCategory["Member"] = "Member"; - SelectionCategory["Contact"] = "Contact"; -})(SelectionCategory || (SelectionCategory = {})); -export var BladesDialogType; -(function (BladesDialogType) { - BladesDialogType["Input"] = "Input"; - BladesDialogType["Selection"] = "Selection"; - BladesDialogType["Consequence"] = "Consequence"; -})(BladesDialogType || (BladesDialogType = {})); -class BladesDialog extends Dialog { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "dialog"], - width: "auto", - height: "auto", - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "front" }] - }); - } - static Initialize() { - return loadTemplates([ - "systems/eunos-blades/templates/dialog-selection.hbs", - "systems/eunos-blades/templates/dialog-consequence.hbs", - "systems/eunos-blades/templates/dialog-input.hbs", - "systems/eunos-blades/templates/parts/dialog-consequence-block.hbs" - ]); - } - static async DisplaySimpleInputDialog(parent, prompt, target, flagTarget) { - const app = new BladesDialog({ - parent, - title: parent instanceof BladesRoll ? "Roll Input" : `${parent.name}: Input`, - dialogType: BladesDialogType.Input, - content: "", - prompt, - target, - flagTarget, - buttons: { - apply: { - icon: '', - label: "Apply", - callback: (html) => app - .writeToRollInstance(html) - }, - cancel: { - icon: '', - label: game.i18n.localize("Cancel"), - callback: (html) => { - eLog.checkLog3("dialog", "Callback Scope", { this: app, html }); - return false; - } - } - }, - default: "apply" - }, { classes: ["eunos-blades", "sheet", "dialog", "simple-input-dialog"] }); - return app._render(true, { width: app.width }).then(() => eLog.checkLog3("dialog", "Input Dialog Instance", { this: app })); - } - static async DisplaySelectionDialog(parent, title, docType, tabs, tags) { - const app = new BladesDialog({ - parent, - title, - docType, - tabs, - tags: tags?.filter((tag) => tag !== ""), - content: "", - buttons: { - cancel: { - icon: '', - label: game.i18n.localize("Cancel"), - callback: (html) => { - eLog.checkLog3("dialog", "Callback Scope", { this: this, html }); - return false; - } - } - }, - default: "cancel" - }); - return app.hasItems ? app.render(true, { width: app.width }) : undefined; - } - static async DisplayRollConsequenceDialog(rollInst) { - const app = new BladesDialog({ - parent: rollInst, - title: "Consequences", - dialogType: BladesDialogType.Consequence, - content: "", - buttons: { - apply: { - icon: '', - label: "Apply", - callback: (html) => app - .writeToRollInstance(html) - }, - cancel: { - icon: '', - label: game.i18n.localize("Cancel"), - callback: (html) => { - eLog.checkLog3("dialog", "Callback Scope", { this: app, html }); - return false; - } - } - }, - default: "apply" - }, { classes: ["eunos-blades", "sheet", "dialog", "consequence-dialog"] }); - return app._render(true, { width: app.width }).then(() => eLog.checkLog3("dialog", "Dialog Instance", { this: app })); - } - get template() { return `systems/eunos-blades/templates/dialog-${U.lCase(this.dialogType)}.hbs`; } - get hasItems() { - return Object.values(this.tabs ?? []).some((tabItems) => tabItems.length > 0); - } - parent; - tabs; - dialogType; - tags = []; - width; - docType; - csqData; - prompt; - target; - flagTarget; - constructor(data, options) { - super(data, options); - this.dialogType = data.dialogType ?? BladesDialogType.Selection; - this.parent = data.parent; - this.width = options?.width ?? 500; - this.prompt = data.prompt; - this.target = data.target; - this.flagTarget = data.flagTarget; - switch (this.dialogType) { - case BladesDialogType.Input: return; - case BladesDialogType.Selection: - this.constructSelectionData(data /* , options */); - return; - case BladesDialogType.Consequence: - this.csqData = this.constructConsequenceData(data /* , options */); - return; - default: throw new Error(`Unrecognized type for BladesDialog constructor: '${this.dialogType}'`); - } - } - constructSelectionData(data /* , options?: Partial */) { - const validTabs = []; - if (!data.tabs) { - return; - } - for (const [tabName, tabItems] of Object.entries(data.tabs)) { - if (tabItems.length === 0) { - delete data.tabs[tabName]; - } - else { - validTabs.push(tabName); - } - } - if (validTabs.length === 1 && !("Main" in data.tabs)) { - data.tabs.Main = [...data.tabs[validTabs[0]]]; - delete data.tabs[validTabs[0]]; - } - this.docType = data.docType; - this.tabs = data.tabs; - this.tags = data.tags ?? []; - this.width = 150 * Math.ceil(Math.sqrt(Object.values(data.tabs)[0].length)); - } - constructConsequenceData(data /* , options?: Partial */) { - eLog.checkLog3("dialog", "constructConsequenceData", { incoming: { ...data } }); - if (!(this.parent instanceof BladesRoll)) { - throw new Error("Cannot call 'constructConsequenceData' without a rollInst parent!"); - } - // Get existing consequence data, if any, on roll instance - const rollCsqData = this.parent.getFlagVal("consequenceData") ?? {}; - // Extend consequence data by applying new blank consequence instances, - // so at least three csq entries are available for each position/result combination - Object.values(Position).forEach((rollPos) => { - rollCsqData[rollPos] ??= { - [RollResult.partial]: {}, - [RollResult.fail]: {} - }; - [RollResult.partial, RollResult.fail].forEach((rollResult) => { - rollCsqData[rollPos][rollResult] ??= {}; - while (Object.values(rollCsqData[rollPos][rollResult]).length < 3) { - const blankCsqData = { - id: randomID(), - name: "", - type: "", - attribute: "" - }; - rollCsqData[rollPos][rollResult][blankCsqData.id] = blankCsqData; - } - }); - }); - this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster); - return rollCsqData; - } - getData() { - const data = super.getData(); - switch (this.dialogType) { - case BladesDialogType.Input: return this.prepareInputData(data); - case BladesDialogType.Selection: return this.prepareSelectionData(data); - case BladesDialogType.Consequence: return this.prepareConsequenceData(data); - default: return null; - } - } - prepareInputData(data) { - data.prompt = this.prompt; - data.target = this.target; - data.flagTarget = this.flagTarget; - return data; - } - prepareSelectionData(data) { - data.title = this.title; - data.tabs = this.tabs; - data.docType = this.docType; - data.tags = this.tags; - return data; - } - prepareConsequenceData(data) { - eLog.checkLog3("dialog", "prepareConsequenceData this.csqData", { ...this.csqData }); - eLog.checkLog3("dialog", "prepareConsequenceData", { incoming: { ...data } }); - data.consequenceData = this.csqData; - data.consequenceTypeOptions = this.consequenceTypeOptions; - data.consequenceTypeOptionsAll = Object.keys(C.ConsequenceDisplay) - .map((cType) => ({ value: cType, display: cType })); - data.consequenceAttributeOptions = [ - { value: AttributeTrait.insight, display: "Insight" }, - { value: AttributeTrait.prowess, display: "Prowess" }, - { value: AttributeTrait.resolve, display: "Resolve" } - ]; - eLog.checkLog3("dialog", "prepareConsequenceData", { outgoing: { ...data } }); - return data; - } - get consequenceTypeOptions() { - if (this.parent instanceof BladesRoll) { - const returnData = {}; - [Position.controlled, Position.risky, Position.desperate].forEach((pos) => { - returnData[pos] = { - [RollResult.partial]: C.Consequences[pos][RollResult.partial] - .map((cType) => ({ value: cType, display: cType })), - [RollResult.fail]: C.Consequences[pos][RollResult.fail] - .map((cType) => ({ value: cType, display: cType })) - }; - }); - return returnData; - } - return {}; - } - updateInputText(inputElem$) { - const value = inputElem$.val(); - if (this.parent instanceof BladesRoll) { - const flagTarget = inputElem$.data("flagTarget"); - eLog.checkLog3("dialog", "updateInputText", { value, flagTarget }); - this.parent.setFlagVal(flagTarget, value, true); - } - else if (this.parent instanceof BladesItem || this.parent instanceof BladesActor) { - this.parent.update({ [inputElem$.data("target")]: inputElem$.val() }); - } - } - updateConsequenceType(csqElem$, cData) { - const type$ = csqElem$.find(".roll-consequence-type-select"); - const typeVal = type$.val(); - if (typeVal && typeVal in ConsequenceType) { - cData.type = typeVal; - cData.icon = C.ConsequenceIcons[cData.type]; - cData.typeDisplay = C.ConsequenceDisplay[cData.type]; - } - } - updateConsequenceAttribute(csqElem$, cData) { - if (/Insight/.exec(cData.type)) { - cData.attribute = AttributeTrait.insight; - } - else if (/Prowess/.exec(cData.type)) { - cData.attribute = AttributeTrait.prowess; - } - else if (/Resolve/.exec(cData.type)) { - cData.attribute = AttributeTrait.resolve; - } - else { - const attribute$ = csqElem$.find(".roll-consequence-attribute-select"); - const attrVal = attribute$.val(); - if (attrVal) { - cData.attribute = attrVal; - } - } - } - updateConsequenceAttributeVal(cData) { - if (this.parent.rollPrimaryDoc instanceof BladesPC) { - cData.attributeVal = this.parent.rollPrimaryDoc.attributes[cData.attribute]; - } - else if (this.parent.rollPrimaryDoc?.parent instanceof BladesPC) { - cData.attributeVal = this.parent.rollPrimaryDoc.parent.attributes[cData.attribute]; - } - else { - eLog.error(`Unable to get attribute from rollPrimaryDoc '${this.parent.rollPrimaryDoc?.name}' of type '${this.parent.rollPrimaryDoc?.rollPrimaryType}' (may need to log via flags if either of the previous show 'undefined'.`); - } - } - getSelectedResistOption(cData) { - return Object.values(cData?.resistOptions ?? {}).find((rCsq) => rCsq.isSelected) ?? false; - } - updateConsequenceResist(csqElem$, cData) { - const resistOptions = cData.resistOptions ?? {}; - // If consequence is already minimal, toggle resistNegates to true and set 'resistTo' to None-type - const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - .map(([csqType]) => csqType); - if (minimalCsqTypes.includes(cData.type)) { - cData.resistNegates = true; - const noneCsq = BladesConsequence.None; - cData.resistOptions = { [noneCsq.id]: noneCsq }; - cData.resistTo = noneCsq; - return; - } - else { - // Clear 'resistTo' (will be redetermined below) - delete cData.resistTo; - delete cData.resistNegates; - csqElem$.find(".consequence-resist-option").each((_, elem) => { - const resCsqID = $(elem).data("csq-id"); - resistOptions[resCsqID] ??= { id: resCsqID, name: "", type: undefined, isSelected: false }; - // Update Resistance Option Type - const resType$ = $(elem).find(".roll-consequence-type-select"); - const resTypeVal = resType$.val(); - if (resTypeVal && resTypeVal in ConsequenceType) { - resistOptions[resCsqID].type = resTypeVal; - resistOptions[resCsqID].icon = C.ConsequenceIcons[resistOptions[resCsqID].type]; - resistOptions[resCsqID].typeDisplay = C.ConsequenceDisplay[resistOptions[resCsqID].type]; - } - // Update Resistance Option Name - const resName$ = $(elem).find(".consequence-name"); - const resNameVal = resName$.val(); - resistOptions[resCsqID].name = resNameVal ?? ""; - // If this is selected, update 'resistTo' data as well - if (resistOptions[resCsqID].isSelected) { - cData.resistTo = resistOptions[resCsqID]; - } - }); - } - cData.resistOptions = resistOptions; - } - updateConsequenceArmorResist(_csqElem$, cData) { - // If consequence is already minimal, toggle armorNegates to true and set 'armorTo' to None-type - const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - .map(([csqType]) => csqType); - if (minimalCsqTypes.includes(cData.type)) { - cData.armorNegates = true; - cData.armorTo = BladesConsequence.None; - } - else { - delete cData.armorNegates; - cData.armorTo = this.getSelectedResistOption(cData); - } - } - updateConsequenceSpecialArmorResist(_csqElem$, cData) { - // If consequence is already minimal, toggle specialArmorNegates to true and set 'specialArmorTo' to None-type - const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - .map(([csqType]) => csqType); - if (minimalCsqTypes.includes(cData.type)) { - cData.specialArmorNegates = true; - cData.specialArmorTo = BladesConsequence.None; - } - else { - delete cData.specialArmorNegates; - cData.specialArmorNegates ??= false; - cData.specialArmorTo = this.getSelectedResistOption(cData); - } - } - updateConsequenceData(html, cData) { - const csqElem$ = html.find(`.roll-consequence-row[data-csq-id='${cData.id}']`); - // Update Type - this.updateConsequenceType(csqElem$, cData); - // Update Name - if (cData.type === ConsequenceType.None) { - cData.name = ""; - } - else { - const name$ = csqElem$.find(".consequence-name"); - const nameVal = name$.val(); - cData.name = nameVal ?? ""; - } - // Update Resistance Attribute - this.updateConsequenceAttribute(csqElem$, cData); - this.updateConsequenceAttributeVal(cData); - // Update Resistance Options - this.updateConsequenceResist(csqElem$, cData); - // Update Armor Options - if (this.parent.canResistWithArmor(cData)) { - cData.isDisplayingArmorToggle = true; - this.updateConsequenceArmorResist(csqElem$, cData); - } - else { - cData.isDisplayingArmorToggle = false; - } - // Update Special Armor Options - if (this.parent.canResistWithSpecialArmor(cData)) { - cData.isDisplayingSpecialArmorToggle = true; - this.updateConsequenceSpecialArmorResist(csqElem$, cData); - } - else { - cData.isDisplayingSpecialArmorToggle = false; - } - return cData; - } - updateConsequenceDialog(html, isRendering = true) { - if (!(this.parent instanceof BladesRoll)) { - return; - } - if (!this.csqData) { - return; - } - eLog.checkLog3("dialog", "updateConsequenceDialog() this.csqData INCOMING", { ...this.csqData }); - const { csqData } = this; - const { rollPrimaryDoc } = this.parent; - if (!(rollPrimaryDoc instanceof BladesPC)) { - return; - } - Object.keys(csqData).forEach((rollPos) => { - const positionCsqData = csqData[rollPos]; - Object.keys(csqData[rollPos]).forEach((rollResult) => { - positionCsqData[rollResult] = U.objMap(positionCsqData[rollResult], (cData) => this.updateConsequenceData(html, cData)); - }); - csqData[rollPos] = positionCsqData; - }); - this.csqData = csqData; - eLog.checkLog3("dialog", "updateConsequenceDialog() this.csqData OUTGOING", { ...this.csqData }); - if (isRendering) { - this.render(); - } - } - async writeToRollInstance(html) { - if (this.parent instanceof BladesRoll) { - this.updateConsequenceDialog(html, false); - await this.parent.setFlagVal("consequenceData", { ...this.csqData }); - } - } - _consequenceAI; - getCsqDataFromElem(elem, paramCount = 3) { - const dataAction = elem.dataset.action; - if (dataAction) { - const params = dataAction.split(/-/).reverse().slice(0, paramCount); - return params.reverse(); - } - return []; - } - async queryAI(event) { - if (!this.csqData) { - return; - } - // If the AI generator has not been initialized, do so. - if (!this._consequenceAI) { - this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster); - } - const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - const csqName = this.csqData[rollPosition][rollResult][csqID]?.name; - if (csqName) { - const response = await this._consequenceAI?.query(csqName, csqName); - if (response) { - this.refreshResistanceOptions(rollPosition, rollResult, csqID, response.split("|")); - } - } - } - async spawnBlankResistOption(event) { - if (!this.csqData) { - return; - } - const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - const rCsqID = randomID(); - this.csqData[rollPosition][rollResult][csqID] - .resistOptions = { - [rCsqID]: { - id: rCsqID, - name: "", - type: undefined, - isSelected: true - } - }; - this.render(); - } - async setFlagVal(target, value) { - if (this.parent instanceof BladesRoll) { - return this.parent.setFlagVal(target, value, false); - } - } - async refreshResistanceOptions(rollPosition, rollResult, cID, rOptions) { - if (!this.csqData) { - return; - } - const cData = this.csqData[rollPosition][rollResult][cID]; - if (!cData) { - return; - } - const cType = cData.type; - const rType = C.ResistedConsequenceTypes[cType] ?? undefined; - const resistOptions = {}; - for (let i = 0; i < rOptions.length; i++) { - const rID = randomID(); - resistOptions[rID] = { - id: rID, - name: rOptions[i], - isSelected: false - }; - if (rType) { - resistOptions[rID].type = rType; - resistOptions[rID].typeDisplay = C.ConsequenceDisplay[rType]; - resistOptions[rID].icon = C.ConsequenceIcons[rType]; - } - } - this.csqData[rollPosition][rollResult][cID].resistOptions = resistOptions; - eLog.checkLog3("dialog", "addResistanceOptions() this.csqData", { ...this.csqData }); - this.render(); - } - async selectResistOption(event) { - if (!this.csqData) { - return; - } - const [rollPosition, rollResult, csqID, resID] = this.getCsqDataFromElem(event.currentTarget, 4); - eLog.checkLog3("dialog", "... Action Passed", { rollResult, csqIndex: csqID, resIndex: resID }); - // Get consequence data - const cData = this.csqData[rollPosition][rollResult][csqID]; - cData.resistOptions ??= {}; - // Toggle clicked resistance option - cData.resistOptions[resID].isSelected = !cData.resistOptions[resID].isSelected; - // If resistance option is now selected... - if (cData.resistOptions[resID].isSelected) { - // ... deselect & hide other options - Object.keys(cData.resistOptions) - .filter((key) => key !== resID) - .forEach((key) => { - Object.assign(cData.resistOptions?.[key] ?? {}, { isSelected: false, isVisible: false }); - }); - // ... and set 'resistTo' to this consequence. - cData.resistTo = cData.resistOptions[resID]; - } - else { - // Otherwise, set 'resistTo' to false... - cData.resistTo = false; - // ... and unhide other options. - Object.keys(cData.resistOptions) - .filter((key) => key !== resID) - .forEach((key) => { - Object.assign(cData.resistOptions?.[key] ?? {}, { isVisible: true }); - }); - } - // Assign new cData instance. - this.csqData[rollPosition][rollResult][csqID] = cData; - this.render(); - } - async clearResistOptions(event) { - if (!this.csqData) { - return; - } - const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - this.csqData[rollPosition][rollResult][csqID].resistOptions = {}; - this.render(); - } - async toggleArmor(event) { - if (!this.csqData) { - return; - } - const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - const cData = this.csqData[rollPosition][rollResult][csqID]; - cData.canArmor = !cData.canArmor; - this.render(); - } - async toggleSpecialArmor(event) { - if (!this.csqData) { - return; - } - const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - const cData = this.csqData[rollPosition][rollResult][csqID]; - cData.canSpecialArmor = !cData.canSpecialArmor; - this.render(); - } - activateListeners(html) { - super.activateListeners(html); - // ~ Tooltips - ApplyTooltipAnimations(html); - switch (this.dialogType) { - case BladesDialogType.Input: - this.activateInputListeners(html); - break; - case BladesDialogType.Selection: - this.activateSelectionListeners(html); - break; - case BladesDialogType.Consequence: { - this.activateConsequenceListeners(html); - // Select --> updateConsequenceDialog -> updateConsequenceData(each csq) - break; - } - } - } - activateInputListeners(html) { - html.find("textarea").on({ change: (event) => this.updateInputText($(event.currentTarget)) }); - } - activateSelectionListeners(html) { - const self = this; - // ~ Changing Width on Tab Change Depending on Number of Items - html.find(".nav-tabs .tab-selector").on("click", (event) => { - const tabIndex = U.pInt($(event.currentTarget).data("tab")); - const numItems = Object.values(self.tabs ?? [])[tabIndex].length; - const width = U.pInt(150 * Math.ceil(Math.sqrt(numItems))); - eLog.checkLog3("nav", "Nav Tab Size Recalculation", { tabIndex, numItems, width }); - this.render(false, { width }); - }); - // ~ Item Control - html.find("[data-item-id]").on("click", function () { - if ($(this).parent().hasClass("locked")) { - return; - } - const docId = $(this).data("itemId"); - const docType = $(this).data("docType"); - eLog.checkLog("dialog", "[BladesDialog] on Click", { elem: this, docId, docType, parent: self.parent }); - if (self.parent instanceof BladesActor) { - if (docType === "Actor") { - self.parent.addSubActor(docId, self.tags); - } - else if (docType === "Item") { - self.parent.addSubItem(docId); - } - } - self.close(); - }); - } - async close() { - $("#eunos-blades-tooltips > *").remove(); - super.close(); - } - activateConsequenceListeners(html) { - html.find("input").on({ change: () => this.updateConsequenceDialog(html) }); - html.find("select").on({ change: () => this.updateConsequenceDialog(html) }); - html.find('[data-action^="ai-query"]').on({ - click: (event) => this.queryAI(event), - contextmenu: (event) => this.clearResistOptions(event) - }); - html.find('[data-action^="blank-option"]').on({ - click: (event) => this.spawnBlankResistOption(event), - contextmenu: (event) => this.clearResistOptions(event) - }); - html.find('[data-action^="gm-select-toggle"]').on({ click: (event) => this.selectResistOption(event) }); - html.find('[data-action^="toggle-armor"]').on({ click: (event) => this.toggleArmor(event) }); - html.find('[data-action^="toggle-special"]').on({ click: (event) => this.toggleSpecialArmor(event) }); - } -} -export default BladesDialog; diff --git a/module/BladesItem.js b/module/BladesItem.js deleted file mode 100644 index 0838f955..00000000 --- a/module/BladesItem.js +++ /dev/null @@ -1,366 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { BladesItemType, BladesNoticeType, Tag, Factor } from "./core/constants.js"; -import U from "./core/utilities.js"; -import { BladesCrew, BladesPC } from "./documents/BladesActorProxy.js"; -import BladesDirector from "./classes/BladesDirector.js"; -import { BladesRollMod } from "./classes/BladesRoll.js"; -class BladesItem extends Item { - // #region Static Overrides: Create ~ - static async create(data, options = {}) { - if (Array.isArray(data)) { - data = data[0]; - } - data.system = data.system ?? {}; - eLog.checkLog2("item", "BladesItem.create(data,options)", { data, options }); - // ~ Create world_name - data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, "").trim().replace(/ /g, "_"); - return super.create(data, options); - } - // #endregion - // #region BladesDocument Implementation - static get All() { return game.items; } - static Get(itemRef) { - if (itemRef instanceof BladesItem) { - return itemRef; - } - if (U.isDocID(itemRef)) { - return BladesItem.All.get(itemRef); - } - return BladesItem.All.find((a) => a.system.world_name === itemRef) - || BladesItem.All.find((a) => a.name === itemRef); - } - static GetTypeWithTags(docType, ...tags) { - if (Array.isArray(docType)) { - return docType - .map((dType) => BladesItem.All.filter((item) => item.type === dType)) - .flat(); - } - return BladesItem.All.filter((item) => item.type === docType) - .filter((item) => item.hasTag(...tags)); - } - static IsType(doc, ...types) { - const typeSet = new Set(types); - return doc instanceof BladesItem && typeSet.has(doc.type); - } - get tags() { return this.system.tags ?? []; } - hasTag(...tags) { - return tags.every((tag) => this.tags.includes(tag)); - } - async addTag(...tags) { - const curTags = this.tags; - tags.forEach((tag) => { - if (curTags.includes(tag)) { - return; - } - curTags.push(tag); - }); - await this.update({ "system.tags": curTags }); - } - async remTag(...tags) { - const curTags = this.tags.filter((tag) => !tags.includes(tag)); - await this.update({ "system.tags": curTags }); - } - get tooltip() { - const tooltipText = [ - this.system.concept, - this.system.rules, - this.system.notes - ].filter(Boolean).join(""); - if (tooltipText) { - return (new Handlebars.SafeString(tooltipText)).toString(); - } - return undefined; - } - dialogCSSClasses = ""; - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: { - if (BladesItem.IsType(this, BladesItemType.cohort_gang)) { - return this.system.tier.value + (this.parent?.getFactorTotal(Factor.tier) ?? 0); - } - if (BladesItem.IsType(this, BladesItemType.cohort_expert)) { - return this.system.tier.value + (this.parent?.getFactorTotal(Factor.tier) ?? 0); - } - if (BladesItem.IsType(this, BladesItemType.gear)) { - return this.system.tier.value + (this.parent?.getFactorTotal(Factor.tier) ?? 0); - } - return this.system.tier.value; - } - case Factor.quality: { - if (BladesItem.IsType(this, BladesItemType.cohort_gang)) { - return this.getFactorTotal(Factor.tier) + (this.system.quality_bonus ?? 0); - } - if (BladesItem.IsType(this, BladesItemType.cohort_expert)) { - return this.getFactorTotal(Factor.tier) + (this.system.quality_bonus ?? 0) + 1; - } - if (BladesItem.IsType(this, BladesItemType.gear)) { - let thisQuality = this.getFactorTotal(Factor.tier) - + (this.hasTag("Fine") ? 1 : 0); - if (BladesPC.IsType(this.parent)) { - thisQuality += this.parent.getTaggedItemBonuses(this.tags); - } - return thisQuality; - } - if (BladesItem.IsType(this, BladesItemType.design)) { - return this.system.min_quality; - } - return this.getFactorTotal(Factor.tier); - } - case Factor.scale: { - if (BladesItem.IsType(this, BladesItemType.cohort_gang)) { - return this.getFactorTotal(Factor.tier) + (this.system.scale_bonus ?? 0); - } - if (BladesItem.IsType(this, BladesItemType.cohort_expert)) { - return 0 + (this.system.scale_bonus ?? 0); - } - return 0; - } - case Factor.magnitude: { - if (BladesItem.IsType(this, BladesItemType.ritual)) { - return this.system.magnitude.value; - } - return 0; - } - default: return 0; - } - } - // #endregion - // #region BladesItemDocument Implementation - async archive() { - await this.addTag(Tag.System.Archived); - return this; - } - async unarchive() { - await this.remTag(Tag.System.Archived); - return this; - } - // #endregion - // #region BladesRoll Implementation - get rollFactors() { - const factorsMap = { - [BladesItemType.cohort_gang]: [Factor.quality, Factor.scale], - [BladesItemType.cohort_expert]: [Factor.quality, Factor.scale], - [BladesItemType.gear]: [Factor.quality], - [BladesItemType.project]: [Factor.quality], - [BladesItemType.ritual]: [Factor.magnitude], - [BladesItemType.design]: [Factor.quality] - }; - if (!factorsMap[this.type]) { - return {}; - } - const factors = factorsMap[this.type]; - const factorData = {}; - (factors ?? []).forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: [Factor.tier, Factor.quality].includes(factor) ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - // #region BladesRoll.PrimaryDoc Implementation - get rollPrimaryID() { return this.id; } - get rollPrimaryDoc() { return this; } - get rollPrimaryName() { return this.name; } - get rollPrimaryType() { - if (![ - BladesItemType.cohort_gang, - BladesItemType.cohort_expert, - BladesItemType.gm_tracker, - BladesItemType.score - ].includes(this.type)) { - throw new Error(`BladesItem of type '${this.type}' ("${this.name}") cannot be RollPrimary.`); - } - return this.type; - } - get rollPrimaryImg() { return this.img; } - get rollPrimaryModsSchemaSet() { - // Add roll mods from COHORT harm - return BladesRollMod.ParseDocModsToSchemaSet(this); - } - async applyHarm(amount, _name) { - if (BladesItem.IsType(this, BladesItemType.cohort_expert, BladesItemType.cohort_gang)) { - const curHarm = this.system.harm.value; - let newHarm; - if (amount > curHarm) { - newHarm = amount; - } - else { - newHarm = curHarm + 1; - } - const harmVerb = ["is Weakened", "is Impaired", "has been Broken", "has been Killed!"]; - const harmEffect = [ - "They act with Reduced Effect.", - "They act with Reduced Effect and suffer -1d to all rolls.", - "They cannot do anything until they recover.", - "You may replace them during Downtime." - ]; - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} ${harmVerb[newHarm - 1]}`, - body: harmEffect[newHarm - 1], - type: BladesNoticeType.push, - cssClasses: "harm-alert" - }); - await this.update({ "system.harm": amount }); - } - } - async applyWorsePosition() { - if (BladesItem.IsType(this, BladesItemType.cohort_expert, BladesItemType.cohort_gang)) { - this.setFlag("eunos-blades", "isWorsePosition", true); - } - } - // #endregion - // #region BladesRoll.OppositionDoc Implementation - get rollOppID() { return this.id; } - get rollOppDoc() { return this; } - get rollOppImg() { return this.img; } - get rollOppName() { return this.name; } - get rollOppSubName() { return ""; } - get rollOppType() { - if (![ - BladesItemType.cohort_gang, - BladesItemType.cohort_expert, - BladesItemType.gm_tracker, - BladesItemType.score, - BladesItemType.location, - BladesItemType.project, - BladesItemType.design, - BladesItemType.ritual - ].includes(this.type)) { - throw new Error(`BladesItem of type '${this.type}' ("${this.name}") cannot be RollOpposition.`); - } - return this.type; - } - get rollOppModsSchemaSet() { return []; } - // #endregion - // #region BladesRoll.ParticipantDoc Implementation - get rollParticipantID() { return this.id; } - get rollParticipantDoc() { return this; } - get rollParticipantIcon() { return this.img; } - get rollParticipantName() { return this.name; } - get rollParticipantType() { - if (![ - BladesItemType.cohort_gang, - BladesItemType.cohort_expert, - BladesItemType.gm_tracker - ].includes(this.type)) { - throw new Error(`BladesItem of type '${this.type}' ("${this.name}") cannot be RollParticipant.`); - } - return this.type; - } - get rollParticipantModsSchemaSet() { return []; } - // #endregion - // #endregion - // #region PREPARING DERIVED DATA - prepareDerivedData() { - super.prepareDerivedData(); - if (BladesItem.IsType(this, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - this._prepareCohortData(this.system); - } - if (BladesItem.IsType(this, BladesItemType.crew_playbook)) { - this._preparePlaybookData(this.system); - } - if (BladesItem.IsType(this, BladesItemType.gear)) { - this._prepareGearData(this.system); - } - if (BladesItem.IsType(this, BladesItemType.playbook)) { - this._preparePlaybookData(this.system); - } - } - _prepareCohortData(system) { - if (!BladesItem.IsType(this, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return; - } - system.tier.name = "Quality"; - const subtypes = U.unique(Object.values(system.subtypes) - .map((subtype) => subtype.trim()) - .filter((subtype) => /[A-Za-z]/.test(subtype))); - const eliteSubtypes = [ - ...Object.values(system.elite_subtypes) - ]; - if (BladesCrew.IsType(this.parent)) { - eliteSubtypes.push(...this.parent.upgrades - .filter((upgrade) => (upgrade.name ?? "").startsWith("Elite")) - .map((upgrade) => (upgrade.name ?? "").trim().replace(/^Elite /, ""))); - } - system.subtypes = Object.fromEntries(subtypes.map((subtype, i) => [`${i + 1}`, subtype])); - system.elite_subtypes = Object.fromEntries(U.unique(eliteSubtypes - .map((subtype) => subtype.trim()) - .filter((subtype) => /[A-Za-z]/.test(subtype) && subtypes.includes(subtype))) - .map((subtype, i) => [`${i + 1}`, subtype])); - system.edges = Object.fromEntries(Object.values(system.edges ?? []) - .filter((edge) => /[A-Za-z]/.test(edge)) - .map((edge, i) => [`${i + 1}`, edge.trim()])); - system.flaws = Object.fromEntries(Object.values(system.flaws ?? []) - .filter((flaw) => /[A-Za-z]/.test(flaw)) - .map((flaw, i) => [`${i + 1}`, flaw.trim()])); - system.quality = this.getFactorTotal(Factor.quality); - if (BladesItem.IsType(this, BladesItemType.cohort_gang)) { - if ([...subtypes, ...eliteSubtypes].includes(Tag.GangType.Vehicle)) { - system.scale = this.getFactorTotal(Factor.scale); - system.scaleExample = "(1 vehicle)"; - } - else { - system.scale = this.getFactorTotal(Factor.scale); - const scaleIndex = Math.min(6, system.scale); - system.scaleExample = C.ScaleExamples[scaleIndex]; - system.subtitle = C.ScaleSizes[scaleIndex]; - } - if (subtypes.length + eliteSubtypes.length === 0) { - system.subtitle = system.subtitle.replace(/\s+of\b/g, "").trim(); - } - } - else { - system.scale = 0; - system.scaleExample = [...subtypes, ...eliteSubtypes].includes("Pet") ? "(1 animal)" : "(1 person)"; - system.subtitle = "An Expert"; - } - if (subtypes.length + eliteSubtypes.length > 0) { - if ([...subtypes, ...eliteSubtypes].includes(Tag.GangType.Vehicle)) { - system.subtitle = C.VehicleDescriptors[Math.min(6, this.getFactorTotal(Factor.tier))]; - } - else { - system.subtitle += ` ${U.oxfordize([ - ...subtypes.filter((subtype) => !eliteSubtypes.includes(subtype)), - ...eliteSubtypes.map((subtype) => `Elite ${subtype}`) - ], false, "&")}`; - } - } - } - _prepareGearData(system) { - if (!BladesItem.IsType(this, BladesItemType.gear)) { - return; - } - system.tier.name = "Quality"; - } - _preparePlaybookData(system) { - if (!BladesItem.IsType(this, BladesItemType.playbook, BladesItemType.crew_playbook)) { - return; - } - const expClueData = {}; - [...Object.values(system.experience_clues).filter((clue) => /[A-Za-z]/.test(clue)), " "].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; }); - system.experience_clues = expClueData; - // eLog.checkLog3("experienceClues", {expClueData}) - if (BladesItem.IsType(this, BladesItemType.playbook)) { - const gatherInfoData = {}; - [...Object.values(system.gather_info_questions).filter((question) => /[A-Za-z]/.test(question)), " "].forEach((question, i) => { gatherInfoData[(i + 1).toString()] = question; }); - system.gather_info_questions = gatherInfoData; - // eLog.checkLog3("gatherInfoQuestions", {gatherInfoData}); - } - } - // #endregion - // Unlock lower-level update method for subclasses - async callOnUpdate(...args) { - await this._onUpdate(...args); - } -} -export default BladesItem; diff --git a/module/BladesPushAlert.js b/module/BladesPushAlert.js deleted file mode 100644 index aa4b249f..00000000 --- a/module/BladesPushAlert.js +++ /dev/null @@ -1,87 +0,0 @@ -import U from "./core/utilities.js"; -import C from "./core/constants.js"; -export default class BladesPushAlert { - static Get() { - if (!game.eunoblades.PushController) { - throw new Error("Attempt to Get BladesPushAlert before 'ready' hook."); - } - return game.eunoblades.PushController; - } - static isInitialized = false; - static Initialize() { - Hooks.once("ready", async () => { - let pushController = game.eunoblades.PushController; - if (!(pushController instanceof BladesPushAlert)) { - pushController = new BladesPushAlert(); - } - game.eunoblades.PushController = pushController; - pushController.initOverlay(); - }); - Hooks.on("canvasReady", async () => { game.eunoblades.PushController?.initOverlay(); }); - } - static InitSockets() { - if (game.eunoblades.PushController) { - socketlib.system.register("pushNotice", game.eunoblades.PushController.push); - return true; - } - return false; - } - initOverlay() { - $("#sidebar").append($("
")); - BladesPushAlert.isInitialized = true; - } - get elem$() { return $("#blades-push-notifications"); } - get elem() { return this.elem$[0]; } - activeNotifications = {}; - push(blockClass, charName, titleText, bodyText) { - const pushController = BladesPushAlert.Get(); - const pushID = randomID(); - const pushLines = [ - `
` - ]; - if (charName !== "GM") { - pushLines.push(`
${charName}
`); - } - if (titleText) { - pushLines.push(`
${titleText}
`); - } - if (bodyText) { - pushLines.push(`
${bodyText}
`); - } - pushLines.push("
"); - const pushElem$ = $(pushLines.join("\n")); - pushController.elem$.append(pushElem$); - pushElem$.on("click", () => pushController.removePush(pushElem$[0])); - U.gsap.from(pushElem$[0], { - x: "-=200", - scale: 1.25, - duration: 1, - ease: "power2" - }); - U.gsap.from(pushElem$[0], { - background: C.Colors.bGOLD, - borderColor: C.Colors.WHITE, - duration: 10, - ease: "power2" - }); - } - removePush(pushElem) { - U.gsap.effects.slideUp(pushElem) - .then(() => $(pushElem).remove()); - } - pushToAll(charName, titleText, bodyText, blockClass) { - socketlib.system.executeForEveryone("pushNotice", blockClass ?? "", charName, titleText, bodyText); - } - pushToSome(...args) { - const users = (args.pop() ?? []) - .filter((user) => Boolean(user?.id)); - if (!users || users.length === 0) { - return; - } - const pushArgs = args.slice(0, 3); - socketlib.system.executeForUsers("pushNotice", users.map((user) => user.id), "", ...pushArgs); - } - pushToGM(...args) { - socketlib.system.executeForAllGMs("pushNotice", "to-gm-notice", ...args); - } -} diff --git a/module/BladesRoll.js b/module/BladesRoll.js deleted file mode 100644 index 800720d0..00000000 --- a/module/BladesRoll.js +++ /dev/null @@ -1,3816 +0,0 @@ -// #region IMPORTS ~ -import U from "./core/utilities.js"; -import C, { BladesActorType, BladesItemType, BladesPhase, RollPermissions, RollType, RollSubType, RollModType, RollModStatus, RollModSection, ActionTrait, DowntimeAction, AttributeTrait, Position, Effect, Factor, RollResult, RollPhase, ConsequenceType, Tag } from "./core/constants.js"; -import { BladesActor, BladesPC, BladesCrew } from "./documents/BladesActorProxy.js"; -import { BladesItem, BladesGMTracker } from "./documents/BladesItemProxy.js"; -import { ApplyTooltipAnimations, ApplyConsequenceAnimations } from "./core/gsap.js"; -import BladesConsequence from "./sheets/roll/BladesConsequence.js"; -import BladesClock, { BladesClockKey } from "./documents/items/BladesClock.js"; -import BladesDialog from "./BladesDialog.js"; -import BladesChat from "./BladesChat.js"; -// #endregion -// #region Types & Type Checking ~ -/** - * Checks if the given string is a RollType. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollType, false otherwise. - */ -function isRollType(str) { - return typeof str === "string" && str in RollType; -} -/** - * Checks if the given trait is an ActionTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an ActionTrait, false otherwise. - */ -function isAction(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in ActionTrait); -} -/** - * Checks if the given trait is an AttributeTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an AttributeTrait, false otherwise. - */ -function isAttribute(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in AttributeTrait); -} -/** - * Checks if the given trait is a Factor. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is a Factor, false otherwise. - */ -function isFactor(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in Factor); -} -/** - * Checks if the given string is a RollModStatus. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollModStatus, false otherwise. - */ -function isModStatus(str) { - return typeof str === "string" && str in RollModStatus; -} -/** - * Checks if the given value is valid consequence data for a Resistance Roll. - * @param {unknown} val The value to check. - * @param {boolean} [isCheckingResistedTo=false] If the check is being recursively - * applied to the 'resistTo' value. - * @returns {boolean} True if the val is valid BladesRoll.ResistanceRollConsequenceData, false otherwise. - */ -function isValidConsequenceData(val, isCheckingResistedTo = false) { - if (!U.isList(val)) { - return false; - } - if (typeof val.type !== "string" || !(val.type in ConsequenceType)) { - return false; - } - if (val.type === ConsequenceType.None) { - return true; - } - if (typeof val.name !== "string") { - return false; - } - if (typeof val.icon !== "string") { - return false; - } - if (typeof val.typeDisplay !== "string") { - return false; - } - if (isCheckingResistedTo) { - return true; - } - if (typeof val.attribute !== "string" || !(val.attribute in AttributeTrait)) { - return false; - } - if (!isValidConsequenceData(val.resistTo, true)) { - return false; - } - return true; -} -/** - * Checks if the given section can contain BladesRollParticipant documents. - * @param {RollModSection} section - */ -function isParticipantSection(section) { - return [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].includes(section); -} -/** - * Checks if the given subSection can hold BladesRollParticipant documents. - * @param {string} subSection - */ -function isParticipantSubSection(subSection) { - if (subSection.startsWith("Group_")) { - return true; - } - if (["Assist", "Setup"].includes(subSection)) { - return true; - } - return false; -} -// #endregion -// #region Utility Functions ~ -/** - * Prunes the configuration file of flag-incompatible direct document references. - * @param {BladesRoll.Config} cfg The configuration object to be pruned. - * @returns {BladesRoll.ConfigFlags} - The pruned configuration object. - */ -function pruneConfig(cfg) { - if (cfg.rollPrimaryData instanceof BladesRollPrimary) { - cfg.rollPrimaryData = cfg.rollPrimaryData.flagData; - } - if (cfg.rollOppData instanceof BladesRollOpposition) { - cfg.rollOppData = cfg.rollOppData.flagData; - } - if (cfg.rollParticipantData) { - if (cfg.rollParticipantData[RollModSection.roll]) { - Object.keys(cfg.rollParticipantData[RollModSection.roll]).forEach((key) => { - const thisParticipant = cfg.rollParticipantData?.[RollModSection.roll]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - cfg.rollParticipantData[RollModSection.roll][key] = thisParticipant.flagData; - } - }); - } - if (cfg.rollParticipantData[RollModSection.position]) { - Object.keys(cfg.rollParticipantData[RollModSection.position]).forEach((key) => { - const thisParticipant = cfg.rollParticipantData?.[RollModSection.position]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - cfg.rollParticipantData[RollModSection.position][key] = thisParticipant.flagData; - } - }); - } - if (cfg.rollParticipantData[RollModSection.effect]) { - Object.keys(cfg.rollParticipantData[RollModSection.effect]).forEach((key) => { - const thisParticipant = cfg.rollParticipantData?.[RollModSection.effect]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - cfg.rollParticipantData[RollModSection.effect][key] = thisParticipant.flagData; - } - }); - } - } - return JSON.parse(JSON.stringify(cfg)); -} -// #endregion -class BladesRollMod { - static ParseDocRollMods(doc) { - const { roll_mods } = doc.system; - if (!roll_mods || roll_mods.length === 0) { - return []; - } - return roll_mods - .filter((elem) => typeof elem === "string") - .map((modString) => { - const pStrings = modString.split(/@/); - const nameString = U.pullElement(pStrings, (v) => typeof v === "string" && /^na/i.test(v)); - const nameVal = (typeof nameString === "string" && nameString.replace(/^.*:/, "")); - if (!nameVal) { - throw new Error(`RollMod Missing Name: '${modString}'`); - } - const catString = U.pullElement(pStrings, (v) => typeof v === "string" && /^cat/i.test(v)); - const catVal = (typeof catString === "string" && catString.replace(/^.*:/, "")); - if (!catVal || !(catVal in RollModSection)) { - throw new Error(`RollMod Missing Category: '${modString}'`); - } - const posNegString = (U.pullElement(pStrings, (v) => typeof v === "string" && /^p/i.test(v)) || "posNeg:positive"); - const posNegVal = posNegString.replace(/^.*:/, ""); - const rollModData = { - id: `${nameVal}-${posNegVal}-${catVal}`, - name: nameVal, - section: catVal, - base_status: RollModStatus.ToggledOff, - modType: RollModType.general, - value: 1, - posNeg: posNegVal, - tooltip: "" - }; - pStrings.forEach((pString) => { - const [keyString, valString] = pString.split(/:/); - let val = /\|/.test(valString) ? valString.split(/\|/) : valString; - let key; - if (/^stat/i.test(keyString)) { - key = "base_status"; - } - else if (/^val/i.test(keyString)) { - key = "value"; - } - else if (/^eff|^ekey/i.test(keyString)) { - key = "effectKeys"; - } - else if (/^side|^ss/i.test(keyString)) { - key = "sideString"; - } - else if (/^s.*ame/i.test(keyString)) { - key = "source_name"; - } - else if (/^tool|^tip/i.test(keyString)) { - key = "tooltip"; - } - else if (/^ty/i.test(keyString)) { - key = "modType"; - } - else if (/^c.{0,10}r?.{0,3}ty/i.test(keyString)) { - key = "conditionalRollTypes"; - } - else if (/^a.{0,3}r?.{0,3}y/i.test(keyString)) { - key = "autoRollTypes"; - } - else if (/^p.{0,10}r?.{0,3}y/i.test(keyString)) { - key = "participantRollTypes"; - } - else if (/^c.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "conditionalRollTraits"; - } - else if (/^a.{0,3}r?.{0,3}tr/i.test(keyString)) { - key = "autoRollTraits"; - } - else if (/^p.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "participantRollTypes"; - } - else { - throw new Error(`Bad Roll Mod Key: ${keyString}`); - } - if (key === "base_status" && val === "Conditional") { - val = RollModStatus.Hidden; - } - let valProcessed; - if (["value"].includes(key)) { - valProcessed = U.pInt(val); - } - else if (["effectKeys", "conditionalRollTypes", "autoRollTypes,", "conditionalRollTraits", "autoRollTraits"].includes(key)) { - valProcessed = [val].flat(); - } - else { - valProcessed = val.replace(/%COLON%/g, ":"); - } - Object.assign(rollModData, { [key]: valProcessed }); - }); - return rollModData; - }); - } - get status() { - if (this.userStatus - && [RollModStatus.ForcedOn, RollModStatus.ForcedOff, RollModStatus.Hidden].includes(this.userStatus)) { - return this.userStatus; - } - if (this.heldStatus && [RollModStatus.ToggledOff, RollModStatus.ToggledOn].includes(this.heldStatus)) { - return this.userStatus ?? this.heldStatus; - } - return this.heldStatus ?? this.userStatus ?? this.baseStatus; - } - get isActive() { return [RollModStatus.ToggledOn, RollModStatus.ForcedOn].includes(this.status); } - get isVisible() { return this.status !== RollModStatus.Hidden; } - _heldStatus; - get heldStatus() { return this._heldStatus; } - set heldStatus(val) { - this._heldStatus = val; - } - get flagParams() { return [C.SYSTEM_ID, `rollCollab.rollModsData.${this.id}`]; } - getUserStatusFlag() { - return this.rollInstance.document.getFlag(...this.flagParams); - } - async setUserStatusFlag(val) { - if (val === this.userStatus) { - return; - } - if (!val || val === this.baseStatus) { - await this.rollInstance.document.unsetFlag(...this.flagParams); - } - else { - const lockedToGM = [ - RollModStatus.ForcedOn, - RollModStatus.ForcedOff, - RollModStatus.Hidden - ]; - if (!game.user.isGM - && (lockedToGM.includes(val) - || (this.userStatus && lockedToGM.includes(this.userStatus)))) { - return; - } - await this.rollInstance.document.setFlag(...this.flagParams, val); - } - await socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID); - } - get userStatus() { - return this.getUserStatusFlag(); - } - set userStatus(val) { - this.setUserStatusFlag(val); - } - get sourceName() { return this._sourceName; } - get isConditional() { - return [ - ...this.conditionalRollTraits, - ...this.autoRollTraits, - ...this.participantRollTraits, - ...this.conditionalRollTypes, - ...this.autoRollTypes, - ...this.participantRollTypes - ].length > 0; - } - get isInInactiveBlock() { - if (game.user.isGM) { - return [RollModStatus.Hidden, RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - return [RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - get isPush() { - return Boolean(U.lCase(this.name) === "push" - || this.effectKeys.find((eKey) => eKey === "Is-Push")); - } - get isBasicPush() { return U.lCase(this.name) === "push"; } - get stressCost() { - const costKeys = this.effectKeys.filter((key) => key.startsWith("Cost-Stress")); - if (costKeys.length === 0) { - return 0; - } - let stressCost = 0; - costKeys.forEach((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [_, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - stressCost += U.pInt(valStr); - }); - return stressCost; - } - isValidForRollType() { - switch (this.rollInstance.rollType) { - case RollType.Action: { - return true; - } - case RollType.Resistance: - case RollType.Fortune: - case RollType.IndulgeVice: { - if (this.isPush - || ["bargain", "setup", "assist", "potency"].includes(U.lCase(this.name))) { - return false; - } - return true; - } - default: return false; - } - } - /** - * Sets the conditional status of the roll mod instance. - * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden. - */ - setConditionalStatus() { - // If the roll mod instance is not conditional, return false - if (!this.isConditional) { - return false; - } - // If any auto-Traits/Types apply, set status to ForcedOn and return false - const autoTypesOrTraitsApply = this.autoRollTypes.includes(this.rollInstance.rollType) - || (this.rollInstance.rollSubType && this.autoRollTypes.includes(this.rollInstance.rollSubType)) - || (this.rollInstance.rollDowntimeAction && this.autoRollTypes.includes(this.rollInstance.rollDowntimeAction)) - || (!this.rollInstance.rollTrait || this.autoRollTraits.includes(this.rollInstance.rollTrait)); - if (autoTypesOrTraitsApply) { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - // If any conditionalTypes apply and any conditionalTraits apply, set status to ToggledOff and return false - const conditionalTypesOrTraitsApply = this.checkTypesOrTraits(this.conditionalRollTypes, this.conditionalRollTraits); - if (conditionalTypesOrTraitsApply) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If this is a participant roll - // AND any participantTypes apply - // AND any participantTraits apply, - // ... set status to ToggledOff and return false - const participantTypesOrTraitsApply = this.rollInstance.isParticipantRoll - && this.checkTypesOrTraits(this.participantRollTypes, this.participantRollTraits); - if (participantTypesOrTraitsApply) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If none of the above conditions apply, set status to Hidden and return true - this.heldStatus = RollModStatus.Hidden; - return true; - } - /** - * Checks if any types or traits apply to the roll instance. - * @param {AnyRollType[]} types The types to check. - * @param {RollTrait[]} traits The traits to check. - * @returns {boolean} - Returns true if any types or traits apply, false otherwise. - */ - checkTypesOrTraits(types, traits) { - if ([...types, ...traits].length === 0) { - return false; - } - const typesApply = Boolean((!this.rollInstance.isParticipantRoll && types.length === 0) - || types.includes(this.rollInstance.rollType) - || (this.rollInstance.rollSubType && types.includes(this.rollInstance.rollSubType)) - || (this.rollInstance.rollDowntimeAction && types.includes(this.rollInstance.rollDowntimeAction))); - const traitsApply = Boolean((!this.rollInstance.isParticipantRoll && traits.length === 0) - || (this.rollInstance.rollTrait && traits.includes(this.rollInstance.rollTrait))); - return typesApply && traitsApply; - } - /** - * Helper function to process each key - * @param {string} key The key to process - * @returns {boolean} - Whether the processing was successful - */ - processKey(key) { - const [thisKey, thisParam] = key.split(/-/) ?? []; - const positions = [Position.controlled, Position.risky, Position.desperate]; - if (positions.includes(U.lCase(thisParam)) && this.rollInstance.finalPosition === U.lCase(thisParam)) { - if (thisKey === "AutoRevealOn") { - this.heldStatus = RollModStatus.ToggledOff; - return true; - } - else if (thisKey === "AutoEnableOn") { - this.heldStatus = RollModStatus.ForcedOn; - return true; - } - } - return false; - } - setAutoStatus() { - // Check for AutoRevealOn and AutoEnableOn - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Auto")); - if (holdKeys.length === 0) { - return false; - } - for (const key of holdKeys) { - if (this.processKey(key)) { - return false; - } - } - this.heldStatus = RollModStatus.Hidden; - return true; - } - setRelevancyStatus() { - const holdKeys = this.effectKeys.filter((key) => /^Negate|^Increase/.test(key)); - if (holdKeys.length === 0) { - return false; - } - const relevantKeys = holdKeys - .filter((key) => { - const [thisKey, thisParam] = key.split(/-/) ?? []; - const negateOperations = { - PushCost: () => this.rollInstance.isPushed(), - PushCost0: () => this.rollInstance.isPushed(), - Consequence: () => this.rollInstance.rollType === RollType.Resistance - && Boolean(this.rollInstance.rollConsequence), - HarmLevel: () => { - if (this.rollInstance.rollType !== RollType.Resistance) { - return false; - } - if (!this.rollInstance.rollConsequence?.type) { - return false; - } - const { type: csqType } = this.rollInstance.rollConsequence; - return [ - ConsequenceType.InsightHarm1, ConsequenceType.ProwessHarm1, ConsequenceType.ResolveHarm1, - ConsequenceType.InsightHarm2, ConsequenceType.ProwessHarm2, ConsequenceType.ResolveHarm2, - ConsequenceType.InsightHarm3, ConsequenceType.ProwessHarm3, ConsequenceType.ResolveHarm3, - ConsequenceType.InsightHarm4, ConsequenceType.ProwessHarm4, ConsequenceType.ResolveHarm4 - ].includes(csqType); - }, - QualityPenalty: () => this.rollInstance.isTraitRelevant(Factor.quality) - && (this.rollInstance.rollFactors.source[Factor.quality]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.quality]?.value ?? 0), - ScalePenalty: () => this.rollInstance.isTraitRelevant(Factor.scale) - && (this.rollInstance.rollFactors.source[Factor.scale]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.scale]?.value ?? 0), - TierPenalty: () => this.rollInstance.isTraitRelevant(Factor.tier) - && (this.rollInstance.rollFactors.source[Factor.tier]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.tier]?.value ?? 0) - }; - if (thisKey === "Negate") { - if (Object.hasOwn(negateOperations, thisParam)) { - return negateOperations[thisParam](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${thisParam}`); - } - } - else if (thisKey === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(thisParam) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${thisKey}`); - } - }); - if (relevantKeys.length === 0) { - this.heldStatus = RollModStatus.Hidden; - return true; - } - return false; - } - setPayableStatus() { - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return false; - } - const payableKeys = holdKeys - .filter((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - const { rollPrimaryDoc } = this.rollInstance.rollPrimary ?? {}; - if (!BladesRollPrimary.IsDoc(rollPrimaryDoc)) { - return false; - } - switch (traitStr) { - case "SpecialArmor": { - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.armor.active.special - && !rollPrimaryDoc.system.armor.checked.special; - } - case "Stress": { - const val = U.pInt(valStr); - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.stress.max - rollPrimaryDoc.system.stress.value >= val; - } - case "Heat": { - return (BladesPC.IsType(rollPrimaryDoc) && BladesCrew.IsType(rollPrimaryDoc.crew)) - || BladesCrew.IsType(rollPrimaryDoc); - } - default: throw new Error(`Unrecognize Payable Key: ${traitStr}`); - } - }); - if (payableKeys.length === 0) { - this.heldStatus = RollModStatus.ForcedOff; - return true; - } - return false; - } - applyRollModEffectKeys() { - if (!this.isActive) { - return; - } - const holdKeys = this.effectKeys.filter((key) => /^Negate|^Increase/.test(key)); - if (holdKeys.length === 0) { - return; - } - holdKeys.forEach((key) => { - // Console.log({key, split: key.split(/-/)}) - const [thisKey, thisParam] = key.split(/-/) ?? []; - const negateOperations = { - PushCost: () => { - const costlyPushMod = this.rollInstance.getActiveRollMods() - .find((mod) => mod.isPush && mod.stressCost > 0); - if (costlyPushMod) { - U.pullElement(costlyPushMod.effectKeys, (k) => k.startsWith("Cost-Stress")); - } - }, - // PushCost0: negateOperations.PushCost, - Consequence: () => { - /* Should cancel roll entirely? */ - }, - // HarmLevel: () => { - // const harmLevels = [ - // [ConsequenceType.InsightHarm1, ConsequenceType.ProwessHarm1, ConsequenceType.ResolveHarm1], - // [ConsequenceType.InsightHarm2, ConsequenceType.ProwessHarm2, ConsequenceType.ResolveHarm2], - // [ConsequenceType.InsightHarm3, ConsequenceType.ProwessHarm3, ConsequenceType.ResolveHarm3], - // [ConsequenceType.InsightHarm4, ConsequenceType.ProwessHarm4, ConsequenceType.ResolveHarm4] - // ]; - // let harmConsequence: BladesRoll.ResistanceRollConsequenceData|undefined = undefined; - // while (!harmConsequence && harmLevels.length > 0) { - // harmConsequence = Object.values(this.rollInstance.rollConsequences) - // .find(({type}) => (harmLevels.pop() ?? []).includes(type as ConsequenceType)); - // } - // if (harmConsequence) { - // harmConsequence.resistTo = { - // name: [ - // ConsequenceType.InsightHarm1, - // ConsequenceType.ProwessHarm1, - // ConsequenceType.ResolveHarm1 - // ].includes(harmConsequence.type as ConsequenceType) - // ? "Fully Negated" - // : (Object.values(harmConsequence.resistOptions ?? [])[0]?.name ?? harmConsequence.name), - // type: C.ResistedConsequenceTypes[harmConsequence.type as KeyOf], - // isSelected: true - // }; - // } - // }, - QualityPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.quality); - }, - ScalePenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.scale); - }, - TierPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.tier); - } - }; - if (thisKey === "Negate") { - if (Object.hasOwn(negateOperations, thisParam)) { - return negateOperations[thisParam](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${thisParam}`); - } - } - else if (thisKey === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(thisParam) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${thisKey} (key: ${key})`); - } - }); - } - get selectOptions() { - if (this.modType !== RollModType.teamwork) { - return null; - } - if (this.name === "Assist" || this.name === "Setup") { - return this.rollInstance.rollParticipantSelectOptions[this.name]; - } - else if (this.name.startsWith("Group_")) { - return this.rollInstance.rollParticipantSelectOptions.Group; - } - return null; - } - get selectedParticipant() { - if (this.modType !== RollModType.teamwork) { - return null; - } - return this.rollInstance.getRollParticipant(this.section, this.name); - } - get tooltip() { - let parsedTooltip = this._tooltip.replace(/%COLON%/g, ":"); - if (parsedTooltip.includes("%DOC_NAME%")) { - parsedTooltip = parsedTooltip.replace(/%DOC_NAME%/g, this.selectedParticipant - ? this.selectedParticipant.rollParticipantName - : "an Ally"); - } - if (parsedTooltip.includes("@OPPOSITION_NAME@")) { - parsedTooltip = parsedTooltip.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition - ? this.rollInstance.rollOpposition.rollOppName - : "Your Opposition"); - } - return parsedTooltip; - } - get sideString() { - if (this._sideString) { - return this._sideString; - } - if (this.selectedParticipant) { - return this.selectedParticipant.rollParticipantName; - } - return undefined; - } - get allFlagData() { - return this.rollInstance.document.getFlag("eunos-blades", "rollCollab"); - } - get data() { - return { - id: this.id, - name: this.name, - base_status: this.baseStatus, - user_status: this.userStatus, - value: this.value, - effectKeys: this.effectKeys, - sideString: this._sideString, - tooltip: this._tooltip, - posNeg: this.posNeg, - modType: this.modType, - conditionalRollTypes: this.conditionalRollTypes, - autoRollTypes: this.autoRollTypes, - conditionalRollTraits: this.conditionalRollTraits, - autoRollTraits: this.autoRollTraits, - section: this.section - }; - } - get costs() { - if (!this.isActive) { - return undefined; - } - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return undefined; - } - return holdKeys.map((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - let label = this.name; - if (this.isBasicPush) { - if (this.posNeg === "negative") { - label = `${this.name} (To Act)`; - } - else { - const effect = this.section === RollModSection.roll ? "+1d" : "+1 effect"; - label = `${this.name} (${effect})`; - } - } - return { - id: this.id, - label, - costType: traitStr, - costAmount: valStr ? U.pInt(valStr) : 1 - }; - }); - } - id; - name; - _sourceName; - baseStatus; - value; - effectKeys; - _sideString; - _tooltip; - posNeg; - modType; - conditionalRollTypes; - autoRollTypes; - participantRollTypes; - conditionalRollTraits; - autoRollTraits; - participantRollTraits; - section; - rollInstance; - constructor(modData, rollInstance) { - this.rollInstance = rollInstance; - this.id = modData.id; - this.name = modData.name; - this._sourceName = modData.source_name ?? modData.name; - this.baseStatus = modData.base_status; - this.value = modData.value; - this.effectKeys = modData.effectKeys ?? []; - this._sideString = modData.sideString; - this._tooltip = modData.tooltip; - this.posNeg = modData.posNeg; - this.modType = modData.modType; - this.conditionalRollTypes = modData.conditionalRollTypes ?? []; - this.autoRollTypes = modData.autoRollTypes ?? []; - this.participantRollTypes = modData.participantRollTypes ?? []; - this.conditionalRollTraits = (modData.conditionalRollTraits ?? []) - .map((trait) => U.lCase(trait)); - this.autoRollTraits = (modData.autoRollTraits ?? []) - .map((trait) => U.lCase(trait)); - this.participantRollTraits = (modData.participantRollTraits ?? []) - .map((trait) => U.lCase(trait)); - this.section = modData.section; - } -} -class BladesRollPrimary { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollPrimary.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollPrimaryName === "string" - && typeof data.rollPrimaryType === "string" - && typeof data.rollPrimaryImg === "string" - && Array.isArray(data.rollModsData) - && U.isList(data.rollFactors) - && (!data.rollPrimaryID || typeof data.rollPrimaryID === "string") - && (!data.rollPrimaryDoc || BladesRollPrimary.IsDoc(data.rollPrimaryDoc)); - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - // #endregion - rollPrimaryID; - _rollPrimaryDoc; - get rollPrimaryDoc() { - if (!this._rollPrimaryDoc) { - let doc; - if (this.rollPrimaryID) { - doc = game.items.get(this.rollPrimaryID) - ?? game.actors.get(this.rollPrimaryID); - } - if (!doc && this.rollPrimaryName) { - doc = game.items.getName(this.rollPrimaryName) - ?? game.actors.getName(this.rollPrimaryName); - } - if (BladesRollPrimary.IsDoc(doc)) { - this._rollPrimaryDoc = doc; - } - } - return this._rollPrimaryDoc; - } - get flagData() { - return { - rollPrimaryID: this.rollPrimaryID, - rollPrimaryName: this.rollPrimaryName, - rollPrimaryType: this.rollPrimaryType, - rollPrimaryImg: this.rollPrimaryImg, - rollModsData: this.rollModsData, - rollFactors: this.rollFactors - }; - } - rollPrimaryName; - rollPrimaryType; - rollPrimaryImg; - _rollModsData; - get rollModsData() { - return this.rollPrimaryDoc?.rollModsData ?? this._rollModsData ?? []; - } - rollFactors; - get isWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.getFlag("eunos-blades", "isWorsePosition") === true; - } - return false; - } - async applyHarm(amount, name) { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyHarm(amount, name); - } - } - async applyWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyWorsePosition(); - } - } - get hasArmor() { - if (!this.rollPrimaryDoc) { - return false; - } - if (this.rollPrimaryType === BladesActorType.pc) { - const rollPrimaryDoc = this.rollPrimaryDoc; - // Can PC spend normal armor? - if (!rollPrimaryDoc.system.armor.checked.light - && (rollPrimaryDoc.system.armor.active.light - || rollPrimaryDoc.remainingLoad >= 2)) { - return true; - } - // Otherwise, can PC spend heavy armor? - if (!rollPrimaryDoc.system.armor.checked.heavy - && (rollPrimaryDoc.system.armor.active.heavy - || rollPrimaryDoc.remainingLoad >= 3)) { - return true; - } - } - if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - const { value, max } = this.rollPrimaryDoc.system.armor; - return max - value > 1; - } - return false; - } - get hasSpecialArmor() { - if (!this.rollPrimaryDoc) { - return false; - } - if (!BladesPC.IsType(this.rollPrimaryDoc)) { - return false; - } - if (!this.rollPrimaryDoc.system.armor.active.special) { - return false; - } - if (this.rollPrimaryDoc.system.armor.checked.special) { - return false; - } - return true; - } - async spendArmor() { - if (this.hasArmor) { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - if (this.rollPrimaryDoc.system.armor.checked.light) { - await this.rollPrimaryDoc.update({ "system.armor.checked.heavy": true }); - } - else { - await this.rollPrimaryDoc.update({ "system.armor.checked.light": true }); - } - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - await this.rollPrimaryDoc.update({ "system.armor.value": this.rollPrimaryDoc.system.armor.value + 1 }); - } - } - } - async spendSpecialArmor() { - if (this.hasSpecialArmor) { - await this.rollPrimaryDoc.update({ "system.armor.checked.special": true }); - } - } - // #region Constructor ~ - constructor(rollInstance, { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryImg, rollModsData, rollFactors } = {}) { - // Identify ID, Doc, Name, SubName, Type & Image, to best of ability - // this.rollInstance = rollInstance; - this.rollPrimaryID = rollPrimaryID - ?? rollInstance?.rollPrimary.rollPrimaryID - ?? rollInstance?.rollPrimary.rollPrimaryDoc?.rollPrimaryID; - rollPrimaryName ??= rollInstance?.rollPrimary.rollPrimaryName; - rollPrimaryType ??= rollInstance?.rollPrimary.rollPrimaryType; - rollPrimaryImg ??= rollInstance?.rollPrimary.rollPrimaryImg; - rollModsData ??= rollInstance?.rollPrimary.rollModsData; - rollFactors ??= rollInstance?.rollPrimary.rollFactors; - if (BladesRollPrimary.IsDoc(this.rollPrimaryDoc)) { - this.rollPrimaryName = rollPrimaryName ?? this.rollPrimaryDoc.rollPrimaryName; - this.rollPrimaryType = this.rollPrimaryDoc.rollPrimaryType; - this.rollPrimaryImg = rollPrimaryImg ?? this.rollPrimaryDoc.rollPrimaryImg ?? ""; - this._rollModsData = rollModsData ?? []; - this.rollFactors = { - ...this.rollPrimaryDoc.rollFactors, - ...rollFactors ?? {} - }; - } - else { - if (!rollPrimaryName) { - throw new Error("Must include a rollPrimaryName when constructing a BladesRollPrimary object."); - } - if (!rollPrimaryImg) { - throw new Error("Must include a rollPrimaryImg when constructing a BladesRollPrimary object."); - } - if (!rollPrimaryType) { - throw new Error("Must include a rollPrimaryType when constructing a BladesRollPrimary object."); - } - if (!rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollPrimary object."); - } - this.rollPrimaryName = rollPrimaryName; - this.rollPrimaryType = rollPrimaryType; - this.rollPrimaryImg = rollPrimaryImg; - this._rollModsData = rollModsData ?? []; - this.rollFactors = rollFactors; - } - } -} -class BladesRollOpposition { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollOpposition.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollOppName === "string" - && typeof data.rollOppType === "string" - && typeof data.rollOppImg === "string" - && (!data.rollOppSubName || typeof data.rollOppSubName === "string") - && (!data.rollOppModsData || Array.isArray(data.rollOppModsData)) - && U.isList(data.rollFactors) - && (!data.rollOppID || typeof data.rollOppID === "string"); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollOpposition.IsDoc(doc)) { - return doc; - } - return false; - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.npc, BladesActorType.faction) - || BladesItem.IsType(doc, ...[ - BladesItemType.cohort_expert, - BladesItemType.cohort_gang, - BladesItemType.gm_tracker, - BladesItemType.project, - BladesItemType.design, - BladesItemType.ritual - ]); - } - // #endregion - rollInstance; - _rollOppID; - get rollOppID() { return this._rollOppID; } - set rollOppID(val) { - if (val) { - const doc = BladesRollOpposition.GetDoc(val); - if (doc) { - this.rollOppDoc = doc; - } - } - this._rollOppID = val; - } - rollOppDoc; - rollOppName; - rollOppSubName; - rollOppType; - rollOppImg; - rollOppModsData; - rollFactors; - // #region Constructor ~ - constructor(rollInstance, { rollOppID, rollOppDoc, rollOppName, rollOppSubName, rollOppType, rollOppImg, rollOppModsData, rollFactors } = {}) { - this.rollInstance = rollInstance; - // Attempt to fetch an associated BladesActor or BladesItem document - const doc = BladesRollOpposition.GetDoc(rollOppDoc ?? rollOppID ?? rollOppName); - if (doc && !(doc instanceof BladesClock) && !(doc instanceof BladesClockKey)) { - // Derive settings from valid Actor/Item document, unless explicitly set in constructor. - rollOppID = doc.rollOppID; - rollOppDoc = doc; - rollOppName ??= doc.rollOppName; - rollOppSubName ??= doc.rollOppSubName; - rollOppType ??= doc.rollOppType; - rollOppImg ??= doc.rollOppImg; - rollOppModsData = [ - ...rollOppModsData ?? [], - ...doc.rollOppModsData ?? [] - ]; - rollFactors = { - ...doc.rollFactors, - ...rollFactors ?? {} - }; - } - // Confirm required settings - if (!rollOppName) { - throw new Error("Must include a rollOppName when constructing a BladesRollOpposition object."); - } - if (!rollOppType) { - throw new Error("Must include a rollOppType when constructing a BladesRollOpposition object."); - } - if (!rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollOpposition object."); - } - // Initialize properties - this.rollOppID = rollOppID; - this.rollOppName = rollOppName; - this.rollOppSubName = rollOppSubName; - this.rollOppType = rollOppType; - this.rollOppImg = rollOppImg ?? ""; - this.rollOppModsData = rollOppModsData ?? []; - this.rollFactors = rollFactors; - } - // #endregion - get flagParams() { - return [C.SYSTEM_ID, "rollCollab.rollOppData"]; - } - get flagData() { - return { - rollOppID: this.rollOppID, - rollOppName: this.rollOppName, - rollOppSubName: this.rollOppSubName, - rollOppType: this.rollOppType, - rollOppImg: this.rollOppImg, - rollOppModsData: this.rollOppModsData, - rollFactors: this.rollFactors - }; - } - async updateRollFlags() { - if (!this.rollInstance) { - return; - } - await this.rollInstance.document.setFlag(...this.flagParams, this.flagData); - socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID); - } - refresh() { - if (!this.rollInstance) { - return; - } - const rollOppFlags = this.rollInstance.flagData.rollOppData; - if (rollOppFlags) { - this.rollOppID = rollOppFlags.rollOppID; - this.rollOppName = rollOppFlags.rollOppName; - this.rollOppSubName = rollOppFlags.rollOppSubName; - this.rollOppType = rollOppFlags.rollOppType; - this.rollOppImg = rollOppFlags.rollOppImg; - this.rollOppModsData = rollOppFlags.rollOppModsData; - this.rollFactors = rollOppFlags.rollFactors; - } - return this; - } -} -class BladesRollParticipant { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollParticipant.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollParticipantName === "string" - && typeof data.rollParticipantType === "string" - && typeof data.rollParticipantIcon === "string" - && (!data.rollParticipantModsData || Array.isArray(data.rollParticipantModsData)) - && U.isList(data.rollFactors) - && (!data.rollParticipantID || typeof data.rollParticipantID === "string") - && (!data.rollParticipantDoc || BladesRollParticipant.IsDoc(data.rollParticipantDoc)); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollParticipant.IsDoc(doc)) { - return doc; - } - return false; - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew, BladesActorType.npc) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - // #endregion - rollInstance; - _rollParticipantID; - get rollParticipantID() { return this._rollParticipantID; } - set rollParticipantID(val) { - if (val) { - const doc = BladesRollParticipant.GetDoc(val); - if (doc) { - this.rollParticipantDoc = doc; - } - } - this._rollParticipantID = val; - } - rollParticipantDoc; - rollParticipantName; - rollParticipantType; - rollParticipantIcon; - rollParticipantSection; - rollParticipantSubSection; - rollParticipantModsData; // As applied to MAIN roll when this participant involved - rollFactors; - // #region Constructor ~ - constructor(rollInstance, { rollParticipantSection, rollParticipantSubSection, rollParticipantID, rollParticipantDoc, rollParticipantName, rollParticipantType, rollParticipantIcon, rollParticipantModsData, rollFactors }) { - this.rollInstance = rollInstance; - if (!rollParticipantSection) { - throw new Error("Must include a rollParticipantSection when constructing a BladesRollParticipant object."); - } - if (!rollParticipantSubSection) { - throw new Error("Must include a rollParticipantSubSection when constructing a BladesRollParticipant object."); - } - this.rollParticipantSection = rollParticipantSection; - this.rollParticipantSubSection = rollParticipantSubSection; - // Attempt to fetch an associated BladesActor or BladesItem document - const doc = BladesRollParticipant.GetDoc(rollParticipantDoc ?? rollParticipantID ?? rollParticipantName); - if (doc) { - // Derive settings from valid Actor/Item document, unless explicitly set in constructor. - rollParticipantID = doc.rollParticipantID; - rollParticipantDoc = doc; - rollParticipantName ??= doc.rollParticipantName; - rollParticipantType ??= doc.rollParticipantType; - rollParticipantIcon ??= doc.rollParticipantIcon; - rollParticipantModsData = [ - ...rollParticipantModsData ?? [], - ...doc.rollParticipantModsData ?? [] - ]; - rollFactors = { - ...doc.rollFactors, - ...rollFactors ?? {} - }; - } - // Confirm required settings - if (!rollParticipantName) { - throw new Error("Must include a rollParticipantName when constructing a BladesRollParticipant object."); - } - if (!rollParticipantType) { - throw new Error("Must include a rollParticipantType when constructing a BladesRollParticipant object."); - } - if (!rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollParticipant object."); - } - // Initialize properties - this.rollParticipantID = rollParticipantID; - this.rollParticipantName = rollParticipantName; - this.rollParticipantType = rollParticipantType; - this.rollParticipantIcon = rollParticipantIcon ?? ""; - this.rollParticipantModsData = rollParticipantModsData ?? []; - this.rollFactors = rollFactors; - } - // #endregion - get flagParams() { - return [C.SYSTEM_ID, `rollCollab.rollParticipantData.${this.rollParticipantSection}.${this.rollParticipantSubSection}`]; - } - get flagData() { - return { - rollParticipantSection: this.rollParticipantSection, - rollParticipantSubSection: this.rollParticipantSubSection, - rollParticipantID: this.rollParticipantID, - rollParticipantName: this.rollParticipantName, - rollParticipantType: this.rollParticipantType, - rollParticipantIcon: this.rollParticipantIcon, - rollParticipantModsData: this.rollParticipantModsData, - rollFactors: this.rollFactors - }; - } - async updateRollFlags() { - await this.rollInstance.document.setFlag(...this.flagParams, this.flagData); - socketlib.system.executeForEveryone("renderRollCollab", this.rollInstance.rollID); - } - refresh() { - const rollParticipantFlagData = this.rollInstance.flagData.rollParticipantData?.[this.rollParticipantSection]; - if (rollParticipantFlagData) { - const rollParticipantFlags = rollParticipantFlagData[this.rollParticipantSubSection]; - if (rollParticipantFlags) { - this.rollParticipantID = rollParticipantFlags.rollParticipantID; - this.rollParticipantName = rollParticipantFlags.rollParticipantName; - this.rollParticipantType = rollParticipantFlags.rollParticipantType; - this.rollParticipantIcon = rollParticipantFlags.rollParticipantIcon; - this.rollParticipantSection = rollParticipantFlags.rollParticipantSection; - this.rollParticipantSubSection = rollParticipantFlags.rollParticipantSubSection; - this.rollParticipantModsData = rollParticipantFlags.rollParticipantModsData; - this.rollFactors = rollParticipantFlags.rollFactors; - } - } - return this; - } -} -class BladesRoll extends DocumentSheet { - static _Debug = { - modWatch: false - }; - static Debug = { - watchRollMod(name) { - if (typeof name === "string") { - BladesRoll._Debug.modWatch = new RegExp(name, "g"); - } - else { - BladesRoll._Debug.modWatch = false; - } - } - }; - // #region STATIC METHODS: INITIALIZATION & DEFAULTS ~ - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "roll-collab", game.user.isGM ? "gm-roll-collab" : ""], - template: `systems/eunos-blades/templates/roll/roll-collab${game.user.isGM ? "-gm" : ""}.hbs`, - submitOnChange: true, - width: 500, - dragDrop: [ - { dragSelector: null, dropSelector: "[data-action='gm-drop-opposition'" } - ] - // Height: 500 - }); - } - static Initialize() { - return loadTemplates([ - "systems/eunos-blades/templates/roll/roll-collab.hbs", - "systems/eunos-blades/templates/roll/roll-collab-gm.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-number-line.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-select-doc.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-factor-control.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-action.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-action-gm.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-resistance.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-resistance-gm.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-fortune.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-fortune-gm.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-indulgevice.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-indulgevice-gm.hbs" - ]); - } - static InitSockets() { - socketlib.system.register("constructRollCollab", BladesRoll.ConstructRollCollab); - socketlib.system.register("renderRollCollab", BladesRoll.RenderRollCollab); - socketlib.system.register("closeRollCollab", BladesRoll.CloseRollCollab); - } - static get DefaultRollMods() { - return [ - { - id: "Push-positive-roll", - name: "PUSH", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["ForceOff-Bargain", "Cost-Stress2"], - tooltip: "

Push for +1d

For 2 Stress, add 1 die to your pool.

(You cannot also accept a Devil's Bargain to increase your dice pool: It's one or the other.)

" - }, - { - id: "Bargain-positive-roll", - name: "Bargain", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Devil's Bargain

The GM has offered you a Devil's Bargain.

Accept the terms to add 1 die to your pool.

(You cannot also Push for +1d to increase your dice pool: It's one or the other.)

" - }, - { - id: "Assist-positive-roll", - name: "Assist", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Assists

%DOC_NAME% is Assisting your efforts, adding 1 die to your pool.

" - }, - { - id: "Setup-positive-position", - name: "Setup", - section: RollModSection.position, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Position by one level.

" - }, - { - id: "Push-positive-effect", - name: "PUSH", - section: RollModSection.effect, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["Cost-Stress2"], - tooltip: "

Push for Effect

For 2 Stress, increase your Effect by one level.

" - }, - { - id: "Setup-positive-effect", - name: "Setup", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Effect by one level.

" - }, - { - id: "Potency-positive-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, you have Potency in this action, increasing your Effect by one level.

" - }, - { - id: "Potency-negative-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, @OPPOSITION_NAME@ has Potency against you, reducing your Effect by one level." - } - ]; - } - static get DefaultFlagData() { - return { - rollModsData: {}, - rollPositionInitial: Position.risky, - rollEffectInitial: Effect.standard, - rollPosEffectTrade: false, - rollPhase: RollPhase.Collaboration, - GMBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOppBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOverrides: {}, - rollFactorToggles: { - source: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - }, - opposition: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - } - } - }; - } - // #endregion - // #region STATIC METHODS: New Roll Creation ~ - static Current = {}; - static _Active; - static get Active() { - if (BladesRoll._Active) { - return BladesRoll._Active; - } - if (U.objSize(BladesRoll.Current) > 0) { - return U.getLast(Object.values(BladesRoll.Current)); - } - return undefined; - } - static set Active(val) { - BladesRoll._Active = val; - } - static async ConstructRollCollab({ userID, rollID, rollPermission }) { - const rollInst = new BladesRoll(userID, rollID, rollPermission); - eLog.checkLog3("rollCollab", "ConstructRollCollab()", { params: { userID, rollID, rollPermission }, rollInst }); - BladesRoll._Active = rollInst; - await rollInst._render(true); - } - static RenderRollCollab(rollID) { - BladesRoll.Current[rollID]?.prepareRollParticipantData(); - BladesRoll.Current[rollID]?.render(); - } - static async CloseRollCollab(rollID) { - eLog.checkLog3("rollCollab", "CloseRollCollab()", { rollID }); - await BladesRoll.Current[rollID]?.close({ rollID }); - // delete BladesRoll.Current[rollID]; - } - static GetUserPermissions(config) { - // === ONE === GET USER IDS - // Get user ID of GM - const GMUserID = game.users.find((user) => user.isGM)?.id; - if (!GMUserID) { - throw new Error("[BladesRoll.GetUserPermissions()] No GM found!"); - } - // Get user IDs of players - const playerUserIDs = game.users - .filter((user) => BladesPC.IsType(user.character) && !user.isGM && typeof user.id === "string") - .map((user) => user.id); - // Prepare user ID permissions object - const userIDs = { - [RollPermissions.GM]: [GMUserID], - [RollPermissions.Primary]: [], - [RollPermissions.Participant]: [], - [RollPermissions.Observer]: [] - }; - // === TWO === DETERMINE PRIMARY USER(S) - // Check RollPrimaryDoc to determine how to assign primary users - const { rollPrimaryDoc } = config.rollPrimaryData; - if (BladesPC.IsType(rollPrimaryDoc) - && U.pullElement(playerUserIDs, rollPrimaryDoc.primaryUser?.id)) { - userIDs[RollPermissions.Primary].push(rollPrimaryDoc.primaryUser?.id); - } - else if (BladesCrew.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else if (BladesItem.IsType(rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - if (config.rollUserID === GMUserID) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else { - userIDs[RollPermissions.Primary].push(config.rollUserID); - } - } - else if (BladesGMTracker.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(GMUserID); - } - // === THREE === DETERMINE ROLL PARTICIPANT USER(S) - // Check config.rollParticipantData to determine if roll starts with any participants - if (config.rollParticipantData) { - userIDs[RollPermissions.Participant].push(...getParticipantDocUserIDs(config.rollParticipantData, playerUserIDs)); - } - // Finally, add remaining players as observers. - userIDs[RollPermissions.Observer] = playerUserIDs - .filter((uID) => !userIDs[RollPermissions.Participant].includes(uID)); - return userIDs; - /** - * Generates BladesRollParticipant documents from the provided schema data. - * @param {BladesRoll.RollParticipantData} participantData - */ - function getParticipantDocs(participantData) { - return Object.values(flattenObject(participantData)) - .map((pData) => { - if (BladesRollParticipant.IsDoc(pData)) { - return pData; - } - if (BladesRollParticipant.IsValidData(pData)) { - if (BladesRollParticipant.IsDoc(pData.rollParticipantDoc)) { - return pData.rollParticipantDoc; - } - else if (typeof pData.rollParticipantID === "string") { - const pDoc = game.actors.get(pData.rollParticipantID) ?? game.items.get(pData.rollParticipantID); - if (BladesRollParticipant.IsDoc(pDoc)) { - return pDoc; - } - } - } - return null; - }); - } - /** - * Returns the user ids of potential BladesRollParticipants defined in the provided data schema. - * @param {BladesRoll.RollParticipantData} participantData - * @param {string[]} unassignedIDs - */ - function getParticipantDocUserIDs(participantData, unassignedIDs) { - return getParticipantDocs(participantData) - .map((pDoc) => { - if (BladesPC.IsType(pDoc) && typeof pDoc.primaryUser?.id === "string") { - return pDoc.primaryUser.id; - } - else if (BladesCrew.IsType(pDoc) - || BladesItem.IsType(pDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return unassignedIDs; - } - return null; - }) - .flat() - .filter((pUser) => pUser !== null && !userIDs[RollPermissions.Primary].includes(pUser)); - } - } - static async PrepareActionRoll(rollID, config) { - // Validate the rollTrait - if (!(config.rollTrait === "" || U.isInt(config.rollTrait) || U.lCase(config.rollTrait) in { ...ActionTrait, ...Factor })) { - throw new Error(`[PrepareActionRoll()] Bad RollTrait for Action Roll: ${config.rollTrait}`); - } - // Retrieve the roll users - const userIDs = BladesRoll.GetUserPermissions(config); - // Prepare roll user flag data - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - // Prepare the flag data. - const flagUpdateData = { - ...BladesRoll.DefaultFlagData, - ...pruneConfig(config), - userPermissions: userFlagData, - rollID - }; - // Return flagData and roll users - return { - flagUpdateData, - userIDs - }; - } - static async PrepareResistanceRoll(rollID, config) { - // Validate consequenceData - if (!config.resistanceData || !isValidConsequenceData(config.resistanceData?.consequence)) { - eLog.error("rollCollab", "[PrepareResistanceRoll] Bad Roll Consequence Data.", config); - throw new Error("[PrepareResistanceRoll()] Bad Consequence Data for Resistance Roll"); - } - // Set rollTrait - config.rollTrait = config.resistanceData.consequence.attribute; - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [1]", { rollID, config }); - // Retrieve the roll users - const userIDs = BladesRoll.GetUserPermissions(config); - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [2]", { userIDs }); - // Prepare roll user flag data - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [3]", { userFlagData }); - // Prepare the flag data. - const flagUpdateData = { - ...BladesRoll.DefaultFlagData, - ...pruneConfig(config), - userPermissions: userFlagData, - rollID - }; - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [4]", { flagUpdateData }); - // Return flagData and roll users - return { - flagUpdateData, - userIDs - }; - } - static async PrepareFortuneRoll(rollID, config) { - // Validate the rollTrait - if (!(U.isInt(config.rollTrait) || U.lCase(config.rollTrait) in { ...ActionTrait, ...AttributeTrait, ...Factor })) { - throw new Error(`[PrepareFortuneRoll()] Bad RollTrait for Fortune Roll: ${config.rollTrait}`); - } - // Retrieve the roll users - const userIDs = BladesRoll.GetUserPermissions(config); - // Prepare roll user flag data - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - // Prepare the flag data. - const flagUpdateData = { - ...BladesRoll.DefaultFlagData, - ...pruneConfig(config), - userPermissions: userFlagData, - rollID - }; - // Return flagData and roll users - return { - flagUpdateData, - userIDs - }; - } - static async PrepareIndulgeViceRoll(rollID, config) { - // Set other known config values - config.rollDowntimeAction = DowntimeAction.IndulgeVice; - // Retrieve the roll users - const userIDs = BladesRoll.GetUserPermissions(config); - // Prepare roll user flag data - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - // Prepare the flag data. - const flagUpdateData = { - ...BladesRoll.DefaultFlagData, - ...pruneConfig(config), - userPermissions: userFlagData, - rollID - }; - // Return flagData and roll users - return { - flagUpdateData, - userIDs - }; - } - /** - * This static method accepts a partial version of the config options required - * to build a BladesRoll instance, sets the requisite flags on the storage - * document, then sends out a socket call to the relevant users to construct - * and display the roll instance. - * - * @param {BladesRoll.ConstructorConfig} config The configuration object for the new roll. - */ - static async NewRoll(config) { - // If no rollType is provided, throw an error. - if (!isRollType(config.rollType)) { - throw new Error("[BladesRoll.NewRoll()] You must provide a valid rollType in the config object."); - } - // Get User document to serve as flag storage. - const rollUser = game.users.get(config.rollUserID ?? game.user.id ?? ""); - if (!rollUser?.id) { - throw new Error("[BladesRoll.NewRoll()] You must provide a valid rollUserID in the config object."); - } - eLog.checkLog3("bladesRoll", "BladesRoll.NewRoll() [1]", { config, rollUser }); - // If roll flag data is already on user. - const flagData = rollUser.getFlag("eunos-blades", "rollCollab"); - if (flagData) { - const { rollID } = flagData; - // If user is documenting a roll with a dialog window open, disallow starting a new roll. - if ($(document).find(`.roll-collab-sheet .sheet-topper[data-roll-id='${rollID}']`)[0]) { - throw new Error(`[BladesRoll.NewRoll()] User ${rollUser.name} already documenting live roll with ID '${rollID}'`); - } - // Otherwise, archive the existing roll and prepare for a new one by clearing the main rollCollab flag. - await rollUser.setFlag("eunos-blades", `rollCollabArchive.${rollID}`, flagData); - await rollUser.unsetFlag("eunos-blades", "rollCollab"); - eLog.checkLog3("bladesRoll", "BladesRoll.NewRoll() [2]", { userFlags: rollUser.flags }); - } - let { rollPrimaryData } = config; - if (!BladesRollPrimary.IsValidData(rollPrimaryData)) { - // If no rollPrimaryData is provided, attempt to derive it from user data - let rollPrimarySourceData; - if (BladesPC.IsType(rollUser.character)) { - rollPrimarySourceData = rollUser.character; - rollPrimaryData = { - rollPrimaryID: rollPrimarySourceData.rollPrimaryID, - rollPrimaryName: rollPrimarySourceData.rollPrimaryName, - rollPrimaryType: rollPrimarySourceData.rollPrimaryType, - rollPrimaryImg: rollPrimarySourceData.rollPrimaryImg, - rollModsData: rollPrimarySourceData.rollModsData, - rollFactors: rollPrimarySourceData.rollFactors, - applyHarm: rollPrimarySourceData.applyHarm, - applyWorsePosition: rollPrimarySourceData.applyWorsePosition - }; - } - } - if (!BladesRollPrimary.IsValidData(rollPrimaryData)) { - throw new Error("[BladesRoll.NewRoll()] A valid source of PrimaryDocData must be provided to construct a roll."); - } - // Get the rollPrimary document, if an ID is provided. - const rollPrimary = new BladesRollPrimary(undefined, rollPrimaryData); - const { rollPrimaryDoc } = rollPrimary; - // Create a random ID for storing the roll instance - const rID = randomID(); - // Derive user flag data depending on given roll type and subtype - let userIDs; - let flagUpdateData; - // Construct Config object - const configData = { - ...config, - rollUserID: rollUser.id, - rollPrimaryData - }; - // Modify Config object depending on subtype and downtime action where necessary. - switch (configData.rollSubType) { - case RollSubType.Engagement: - case RollSubType.Incarceration: { - configData.rollType = RollType.Fortune; - break; - } - default: break; - } - switch (configData.rollDowntimeAction) { // Can be done outside of Downtime during Flashbacks! - case DowntimeAction.AcquireAsset: { - configData.rollType = RollType.Action; - configData.rollTrait = Factor.tier; - break; - } - case DowntimeAction.IndulgeVice: { - configData.rollType = RollType.IndulgeVice; - if (!BladesPC.IsType(rollPrimaryDoc)) { - throw new Error("Only a PC character can roll to Indulge Vice."); - } - const minAttrVal = Math.min(...Object.values(rollPrimaryDoc.attributes)); - configData.rollTrait = U.sample(Object.values(AttributeTrait).filter((attr) => rollPrimaryDoc.attributes[attr] === minAttrVal))[0]; - break; - } - case DowntimeAction.LongTermProject: { - configData.rollType = RollType.Action; - // Validate that rollOppData points to a project item - if (!BladesRollOpposition.IsValidData(configData.rollOppData)) { - throw new Error("No rollOppData provided for LongTermProject roll."); - } - const rollOpp = new BladesRollOpposition(undefined, configData.rollOppData); - if (![ - BladesItemType.project, - BladesItemType.design - ].includes(rollOpp.rollOppType)) { - throw new Error("rollOppType must be 'project' or 'design' for LongTermProject roll."); - } - break; - } - case DowntimeAction.Recover: { - configData.rollType = RollType.Action; - // Validate that rollPrimary is an NPC or a PC with Physiker. - if (BladesPC.IsType(rollPrimaryDoc)) { - if (!rollPrimaryDoc.abilities.find((ability) => ability.name === "Physiker")) { - throw new Error("A PC rollPrimary on a Recovery roll must have the Physiker ability."); - } - configData.rollTrait = ActionTrait.tinker; - } - else if (rollPrimary.rollPrimaryType === BladesActorType.npc) { - configData.rollTrait = Factor.quality; - } - else { - throw new Error("Only a PC with Physiker or an NPC can be rollPrimary on a Recover roll."); - } - break; - } - case DowntimeAction.ReduceHeat: { - configData.rollType = RollType.Action; - // rollPrimary must be a cohort with a parent PC or Crew, - // and PC must be member of a crew - // and Crew must not have zero Heat. - let parentCrew = undefined; - if (rollPrimaryDoc) { - const { parent } = rollPrimaryDoc; - if (BladesCrew.IsType(parent)) { - parentCrew = parent; - } - else if (BladesPC.IsType(parent) && BladesCrew.IsType(parent.crew)) { - parentCrew = parent.crew; - } - } - if (!BladesCrew.IsType(parentCrew)) { - throw new Error(`Could not find crew for rollPrimary ${rollPrimary.rollPrimaryName}`); - } - if (parentCrew.system.heat.value === 0) { - throw new Error("Attempt to Reduce Heat for a Crew with no Heat."); - } - break; - } - case undefined: break; - default: throw new Error(`Unrecognized Roll Downtime Action: ${configData.rollDowntimeAction}`); - } - switch (config.rollType) { - case RollType.Action: { - ({ userIDs, flagUpdateData } = await BladesRoll.PrepareActionRoll(rID, configData)); - break; - } - case RollType.Resistance: { - ({ userIDs, flagUpdateData } = await BladesRoll.PrepareResistanceRoll(rID, configData)); - break; - } - case RollType.Fortune: { - ({ userIDs, flagUpdateData } = await BladesRoll.PrepareFortuneRoll(rID, configData)); - break; - } - case RollType.IndulgeVice: { - ({ userIDs, flagUpdateData } = await BladesRoll.PrepareIndulgeViceRoll(rID, configData)); - break; - } - } - // Log the roll data - eLog.checkLog3("bladesRoll", "BladesRoll.NewRoll()", { userIDs, flagUpdateData, rollPrimaryData: flagUpdateData.rollPrimaryData }); - // Store the roll data on the storage document - await rollUser.setFlag(C.SYSTEM_ID, "rollCollab", flagUpdateData); - // Send out socket calls to all users to see the roll. - socketlib.system.executeForUsers("constructRollCollab", userIDs[RollPermissions.GM], { userID: rollUser.id, rollID: rID, rollPermission: RollPermissions.GM }); - socketlib.system.executeForUsers("constructRollCollab", userIDs[RollPermissions.Primary], { userID: rollUser.id, rollID: rID, rollPermission: RollPermissions.Primary }); - socketlib.system.executeForUsers("constructRollCollab", userIDs[RollPermissions.Observer], { userID: rollUser.id, rollID: rID, rollPermission: RollPermissions.Observer }); - socketlib.system.executeForUsers("constructRollCollab", userIDs[RollPermissions.Participant], { userID: rollUser.id, rollID: rID, rollPermission: RollPermissions.Participant }); - } - // #endregion - // #region Constructor ~ - rollID; - rollPermission; - _rollPrimary; - _rollOpposition; - _rollParticipants; - projectSelectOptions; - constructor(userID, rollID, rollPermission) { - const rollUser = game.users.get(userID); - if (!rollUser) { - throw new Error("[new BladesRoll()] Must provide a valid rollUser to roll."); - } - super(rollUser); - this.rollID = rollID; - this.rollPermission = rollPermission; - const rollFlagData = rollUser.getFlag(C.SYSTEM_ID, "rollCollab"); - this._rollPrimary = new BladesRollPrimary(this, rollFlagData.rollPrimaryData); - if (rollFlagData.rollOppData) { - this._rollOpposition = new BladesRollOpposition(this, rollFlagData.rollOppData); - } - else if (rollFlagData.rollDowntimeAction === DowntimeAction.LongTermProject) { - this.projectSelectOptions = Array.from(game.items) - .filter((item) => BladesItem.IsType(item, BladesItemType.project)) - .map((project) => ({ value: project.id ?? "", display: project.name })); - } - if (rollFlagData.rollParticipantData) { - this._rollParticipants = {}; - for (const [rollSection, rollParticipantList] of Object.entries(rollFlagData.rollParticipantData)) { - if ([RollModSection.roll, RollModSection.position, RollModSection.effect] - .includes(rollSection) && !U.isEmpty(rollParticipantList)) { - const sectionParticipants = {}; - for (const [participantType, participantData] of Object.entries(rollParticipantList)) { - sectionParticipants[participantType] = new BladesRollParticipant(this, participantData); - } - this._rollParticipants[rollSection] = sectionParticipants; - } - } - } - BladesRoll.Current[this.rollID] = this; - } - // #endregion - async addRollParticipant(participantRef, rollSection, rollSubSection) { - if (!rollSubSection) { - /* Insert logic to determine from rollSection and number of existing Group_X members */ - rollSubSection = "Assist"; - } - const participantData = typeof participantRef === "string" - ? game.actors.get(participantRef) - ?? game.actors.getName(participantRef) - ?? game.items.get(participantRef) - ?? game.items.getName(participantRef) - : participantRef; - if (!BladesRollParticipant.IsValidData(participantData)) { - throw new Error("Bad data."); - } - const rollParticipant = new BladesRollParticipant(this, { - rollParticipantSection: rollSection, - rollParticipantSubSection: rollSubSection, - rollParticipantID: participantData.rollParticipantID - }); - await rollParticipant.updateRollFlags(); - socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - } - async removeRollParticipant(rollSection, rollSubSection) { - await this.clearFlagVal(`rollParticipantData.${rollSection}.${rollSubSection}`); - } - async updateUserPermission(_user, _permission) { - /* Force-render roll with new permissions */ - } - // #region Basic User Flag Getters/Setters ~ - get flagData() { - if (!this.document.getFlag(C.SYSTEM_ID, "rollCollab")) { - throw new Error("[get flags()] No RollCollab Flags Found on User Document"); - } - return this.document.getFlag(C.SYSTEM_ID, "rollCollab"); - } - get rollPrimary() { - return this._rollPrimary; - } - get rollPrimaryDoc() { - if (BladesRollPrimary.IsDoc(this.rollPrimary.rollPrimaryDoc)) { - return this.rollPrimary.rollPrimaryDoc; - } - if (BladesRollPrimary.IsDoc(this.rollPrimary)) { - return this.rollPrimary; - } - return undefined; - } - get rollOpposition() { - if (!this._rollOpposition && BladesRollOpposition.IsValidData(this.flagData.rollOppData)) { - this._rollOpposition = new BladesRollOpposition(this, this.flagData.rollOppData); - } - return this._rollOpposition?.refresh(); - } - set rollOpposition(val) { - if (val === undefined) { - this._rollOpposition = undefined; - } - else { - this._rollOpposition = val; - val.updateRollFlags(); - } - } - /** - * This method prepares the roll participant data. - * It iterates over the roll sections (roll, position, effect) and for each section, - * it creates a new BladesRollParticipant instance for each participant in that section. - * The created instances are stored in the rollParticipants object. - */ - prepareRollParticipantData() { - const participantFlagData = this.flagData.rollParticipantData; - if (!participantFlagData) { - return; - } - const rollParticipants = {}; - [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].forEach((rollSection) => { - const sectionFlagData = participantFlagData[rollSection]; - if (sectionFlagData) { - const sectionParticipants = {}; - Object.entries(sectionFlagData).forEach(([subSection, subSectionFlagData]) => { - if (subSectionFlagData) { - sectionParticipants[subSection] = - new BladesRollParticipant(this, { - ...subSectionFlagData, - rollParticipantSection: rollSection, - rollParticipantSubSection: subSection - }); - } - }); - rollParticipants[rollSection] = sectionParticipants; - } - }); - this._rollParticipants = rollParticipants; - } - get rollParticipants() { - return this._rollParticipants; - } - getRollParticipant(section, subSection) { - if (isParticipantSection(section) && isParticipantSubSection(subSection)) { - const sectionData = this.rollParticipants?.[section]; - if (sectionData) { - return sectionData[subSection] ?? null; - } - } - return null; - } - get rollParticipantSelectOptions() { - const nonPrimaryPCs = BladesPC.All - .filter((actor) => actor.hasTag(Tag.PC.ActivePC) && actor.id !== this.rollPrimary.rollPrimaryID) - .map((actor) => ({ value: actor.id, display: actor.name })); - return { - Assist: nonPrimaryPCs, - Setup: nonPrimaryPCs, - Group: nonPrimaryPCs - }; - } - get rollType() { return this.flagData.rollType; } - get rollSubType() { return this.flagData.rollSubType; } - set rollSubType(val) { - this.setFlagVal("rollSubType", val); - } - get rollPhase() { - return this.getFlagVal("rollPhase") ?? RollPhase.Collaboration; - } - async setRollPhase(rollPhase) { - await this.setFlagVal("rollPhase", rollPhase); - } - get rollDowntimeAction() { return this.flagData.rollDowntimeAction; } - get rollTrait() { return this.flagData.rollTrait; } - get rollTraitVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionVerbs)) { - return undefined; - } - return C.ActionVerbs[this.rollTrait]; - } - get rollTraitPastVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionPastVerbs)) { - return undefined; - } - return C.ActionPastVerbs[this.rollTrait]; - } - _rollTraitValOverride; - get rollTraitValOverride() { return this._rollTraitValOverride; } - set rollTraitValOverride(val) { this._rollTraitValOverride = val; } - get rollTraitData() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipActions, - gmTooltip: C.ActionTooltipsGM[this.rollTrait] - }; - } - if (isAttribute(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipAttributes, - gmTooltip: C.AttributeTooltips[this.rollTrait] - }; - } - } - if (U.isInt(this.rollTrait)) { - return { - name: `+${this.rollTraitValOverride ?? this.rollTrait}`, - value: this.rollTraitValOverride ?? this.rollTrait, - max: this.rollTraitValOverride ?? this.rollTrait - }; - } - if (isFactor(this.rollTrait)) { - return { - name: U.tCase(this.rollTrait), - value: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.value ?? 0, - max: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.max ?? 10 - }; - } - throw new Error(`[get rollTraitData] Invalid rollTrait: '${this.rollTrait}'`); - } - get rollTraitOptions() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return Object.values(ActionTrait) - .map((action) => ({ - name: U.uCase(action), - value: action - })); - } - if (isAttribute(this.rollTrait)) { - return Object.values(AttributeTrait) - .map((attribute) => ({ - name: U.uCase(attribute), - value: attribute - })); - } - } - if (U.isInt(this.rollTrait)) { - return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - .map((num) => ({ - name: `+${num}`, - value: num - })); - } - if (isFactor(this.rollTrait)) { - return []; - } - throw new Error(`[get rollTraitOptions] Invalid rollTrait: '${this.rollTrait}'`); - } - get posEffectTrade() { - return this.flagData?.rollPosEffectTrade ?? false; - } - getFlagVal(flagKey) { - if (flagKey) { - return this.document.getFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")); - } - return this.document.getFlag(C.SYSTEM_ID, "rollCollab"); - } - async setFlagVal(flagKey, flagVal, isRerendering = true) { - await this.document.setFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab."), flagVal); - if (isRerendering) { - socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - } - } - async clearFlagVal(flagKey, isRerendering = true) { - await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")); - if (isRerendering) { - socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - } - } - get initialPosition() { - return this.getFlagVal("rollPositionInitial") ?? Position.risky; - } - set initialPosition(val) { - this.setFlagVal("rollPositionInitial", val ?? Position.risky); - } - get initialEffect() { - return this.getFlagVal("rollEffectInitial") ?? Effect.standard; - } - set initialEffect(val) { - this.setFlagVal("rollEffectInitial", val); - } - get isApplyingConsequences() { - if (this.rollType !== RollType.Action) { - return false; - } - if (!this.rollResult) { - return false; - } - if (![RollResult.partial, RollResult.fail].includes(this.rollResult)) { - return false; - } - return true; - } - // Get rollConsequence() --> For resistance rolls. - get rollConsequence() { - return this.getFlagVal("resistanceData.consequence"); - } - // #endregion - // #region GETTERS: DERIVED DATA ~ - get finalPosition() { - return Object.values(Position)[U.clampNum(Object.values(Position) - .indexOf(this.initialPosition) - + this.getModsDelta(RollModSection.position) - + (this.posEffectTrade === "position" ? 1 : 0) - + (this.posEffectTrade === "effect" ? -1 : 0), [0, 2])]; - } - get finalEffect() { - return Object.values(Effect)[U.clampNum(Object.values(Effect) - .indexOf(this.initialEffect) - + this.getModsDelta(RollModSection.effect) - + (this.posEffectTrade === "effect" ? 1 : 0) - + (this.posEffectTrade === "position" ? -1 : 0), [0, 4])]; - } - get finalResult() { - return this.getModsDelta(RollModSection.result) - + (this.flagData?.GMBoosts.Result ?? 0) - + (this.tempGMBoosts.Result ?? 0); - } - get finalDicePool() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.flagData.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)); - } - get isRollingZero() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.flagData.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)) <= 0; - } - _roll; - get roll() { - this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {}); - return this._roll; - } - get rollFactors() { - const defaultFactors = { - [Factor.tier]: { - name: "Tier", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: true, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.quality]: { - name: "Quality", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.scale]: { - name: "Scale", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.magnitude]: { - name: "Magnitude", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - } - }; - const mergedSourceFactors = U.objMerge(U.objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.flagData.rollFactorToggles.source, { isMutatingOk: false }); - const mergedOppFactors = this.rollOpposition - ? U.objMerge(U.objMerge(defaultFactors, this.rollOpposition.rollFactors, { isMutatingOk: false }), this.flagData.rollFactorToggles.opposition, { isMutatingOk: false }) - : {}; - return { - source: Object.fromEntries(Object.entries(mergedSourceFactors) - .map(([factor, factorData]) => { - factorData.value += - (this.flagData.GMBoosts[factor] ?? 0) - + (this.tempGMBoosts[factor] ?? 0); - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })), - opposition: Object.fromEntries(Object.entries(mergedOppFactors) - .map(([factor, factorData]) => { - factorData.value += this.flagData.GMOppBoosts[factor] ?? 0; - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })) - }; - } - // #endregion - // #region ROLL MODS: Getters & Update Method ~ - initRollMods(modsData) { - // Reset override values previously enabled by rollmods - this.rollTraitValOverride = undefined; - this.rollFactorPenaltiesNegated = {}; - this.tempGMBoosts = {}; - this.rollMods = modsData.map((modData) => new BladesRollMod(modData, this)); - // ESLINT DISABLE: Dev Code. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const initReport = {}; - let initReportCount = 0; - const watchMod = (label) => { - if (BladesRoll._Debug.modWatch === false) { - return; - } - const reportLabel = `(${initReportCount}) == ${label}`; - const rollMod = this.rollMods - .find((mod) => BladesRoll._Debug.modWatch && BladesRoll._Debug.modWatch.exec(mod.name)); - if (rollMod) { - initReport[`${reportLabel} : ${rollMod.status}`] = { - inst: rollMod, - data: { ...rollMod.data }, - sourceName: rollMod.sourceName, - status: { - ALL: rollMod.status, - base: rollMod.baseStatus, - held: rollMod.heldStatus, - user: rollMod.userStatus - }, - is: { - active: rollMod.isActive, - visible: rollMod.isVisible, - conditional: rollMod.isConditional, - inInactiveBlock: rollMod.isInInactiveBlock, - isPush: rollMod.isPush, - isBasicPush: rollMod.isBasicPush - }, - flags: { ...rollMod.flagParams } - }; - } - else { - initReport[reportLabel] = "MOD NOT FOUND"; - } - initReportCount++; - }; - watchMod("INITIAL"); - /* *** PASS ZERO: ROLLTYPE VALIDATION PASS *** */ - this.rollMods = this.rollMods.filter((rollMod) => rollMod.isValidForRollType()); - watchMod("ROLLTYPE VALIDATION"); - /* *** PASS ONE: DISABLE PASS *** */ - // ... Conditional Status Pass - const conditionalDisablePass = this.rollMods.filter((rollMod) => !rollMod.setConditionalStatus()); - watchMod("DISABLE - CONDITIONAL"); - // ... AutoReveal/AutoEnable Pass - const autoRevealDisablePass = conditionalDisablePass.filter((rollMod) => !rollMod.setAutoStatus()); - watchMod("DISABLE - AUTO-REVEAL/ENABLE"); - // ... Payable Pass - autoRevealDisablePass.forEach((rollMod) => { rollMod.setPayableStatus(); }); - watchMod("DISABLE - PAYABLE"); - /* *** PASS TWO: FORCE-ON PASS *** */ - const parseForceOnKeys = (mod) => { - const holdKeys = mod.effectKeys.filter((key) => key.startsWith("ForceOn")); - if (holdKeys.length === 0) { - return; - } - while (holdKeys.length) { - const thisTarget = holdKeys.pop()?.split(/-/)?.pop(); - if (thisTarget === "BestAction") { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollTraitValOverride = Math.max(...Object.values(this.rollPrimaryDoc.actions)); - } - } - else { - const [targetName, targetCat, targetPosNeg] = thisTarget?.split(/,/) ?? []; - if (!targetName) { - throw new Error(`No targetName found in thisTarget: ${thisTarget}.`); - } - let targetMod = this.getRollModByName(targetName) - ?? this.getRollModByName(targetName, targetCat ?? mod.section); - if (!targetMod && targetName === "Push") { - [targetMod] = [ - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "negative").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getInactiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOff) - ]; - } - targetMod ??= this.getRollModByName(targetName, targetCat ?? mod.section, targetPosNeg ?? mod.posNeg); - if (!targetMod) { - throw new Error(`No mod found matching ${targetName}/${targetCat}/${targetPosNeg}`); - } - if (!targetMod.isActive) { - targetMod.heldStatus = RollModStatus.ForcedOn; - parseForceOnKeys(targetMod); - } - else { - targetMod.heldStatus = RollModStatus.ForcedOn; - } - } - } - }; - this.getActiveRollMods().forEach((rollMod) => parseForceOnKeys(rollMod)); - watchMod("FORCE-ON PASS"); - /* *** PASS THREE: PUSH-CHECK PASS *** */ - // IF ROLL FORCED ... - if (this.isForcePushed()) { - // ... Force Off _ALL_ visible, inactive "Is-Push" mods. - this.getInactivePushMods() - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("PUSH-CHECK: FORCE-OFF IS-PUSH"); - } - // ... BY CATEGORY ... - [RollModSection.roll, RollModSection.effect].forEach((cat) => { - if (this.isPushed(cat)) { - // ... if pushed by positive mod, Force Off any visible Bargain - if (cat === RollModSection.roll && this.isPushed(cat, "positive")) { - const bargainMod = this.getRollModByID("Bargain-positive-roll"); - if (bargainMod?.isVisible) { - bargainMod.heldStatus = RollModStatus.ForcedOff; - } - } - watchMod("PUSH-CHECK: FORCE OFF BARGAIN"); - } - else { - // Otherwise, hide all Is-Push mods - this.getInactivePushMods(cat) - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.Hidden; }); - watchMod("PUSH-CHECK: HIDE IS-PUSH"); - } - }); - /* *** PASS FOUR: Relevancy Pass *** */ - this.getVisibleRollMods() - .forEach((mod) => { mod.setRelevancyStatus(); }); - watchMod("RELEVANCY PASS"); - /* *** PASS FIVE: Overpayment Pass *** */ - // ... If 'Cost-SpecialArmor' active, ForceOff other visible Cost-SpecialArmor mods - const activeArmorCostMod = this.getActiveRollMods().find((mod) => mod.effectKeys.includes("Cost-SpecialArmor")); - if (activeArmorCostMod) { - this.getVisibleRollMods() - .filter((mod) => !mod.isActive && mod.effectKeys.includes("Cost-SpecialArmor")) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("OVERPAYMENT PASS"); - } - eLog.checkLog2("rollMods", "*** initRollMods() PASS ***", initReport); - } - isTraitRelevant(trait) { - if (trait in Factor) { - const { source, opposition } = this.rollFactors; - return Boolean(trait in source && trait in opposition && source[trait]?.isActive); - } - return false; - } - get isParticipantRoll() { - return (this.rollType === RollType.Fortune && !game.user.isGM) - || (this.rollSubType === RollSubType.GroupParticipant); - } - rollFactorPenaltiesNegated = {}; - negateFactorPenalty(factor) { - this.rollFactorPenaltiesNegated[factor] = true; - } - tempGMBoosts = {}; - isPushed(cat, posNeg) { return this.getActiveBasicPushMods(cat, posNeg).length > 0; } - hasOpenPush(cat, posNeg) { return this.isPushed(cat) && this.getOpenPushMods(cat, posNeg).length > 0; } - isForcePushed(cat, posNeg) { return this.isPushed(cat) && this.getForcedPushMods(cat, posNeg).length > 0; } - get rollCosts() { - if (!this.isPushed) { - return 0; - } - const harmPush = this.getRollModByID("Push-negative-roll"); - const rollPush = this.getRollModByID("Push-positive-roll"); - const effectPush = this.getRollModByID("Push-positive-effect"); - const negatePushCostMods = this.getActiveRollMods(RollModSection.after, "positive") - .filter((mod) => mod.effectKeys.includes("Negate-PushCost")); - return ((harmPush?.isActive && harmPush?.stressCost) || 0) - + ((rollPush?.isActive && rollPush?.stressCost) || 0) - + ((effectPush?.isActive && effectPush?.stressCost) || 0) - - (negatePushCostMods.length * 2); - } - get rollCostData() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs ?? []) - .flat(); - } - getRollModByName(name, cat, posNeg) { - const modMatches = this.rollMods.filter((rollMod) => { - if (U.lCase(rollMod.name) !== U.lCase(name)) { - return false; - } - if (cat && rollMod.section !== cat) { - return false; - } - if (posNeg && rollMod.posNeg !== posNeg) { - return false; - } - return true; - }); - if (modMatches.length === 0) { - return undefined; - } - if (modMatches.length > 1) { - return undefined; - } - return modMatches[0]; - } - getRollModByID(id) { return this.rollMods.find((rollMod) => rollMod.id === id); } - getRollMods(cat, posNeg) { - return this.rollMods.filter((rollMod) => (!cat || rollMod.section === cat) - && (!posNeg || rollMod.posNeg === posNeg)); - } - getVisibleRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActiveRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getVisibleInactiveRollMods(cat, posNeg) { - return this.getVisibleRollMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getPushMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isPush); - } - getVisiblePushMods(cat, posNeg) { - return this.getPushMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getActiveBasicPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getInactivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getInactiveBasicPushMods(cat, posNeg) { - return this.getInactivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getForcedPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ForcedOn); - } - getOpenPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ToggledOn); - } - getModsDelta = (cat) => { - return U.sum([ - ...this.getActiveRollMods(cat, "positive").map((mod) => mod.value), - ...this.getActiveRollMods(cat, "negative").map((mod) => -mod.value) - ]); - }; - _rollMods; - /** - * Compare function for sorting roll mods. - * @param {BladesRollMod} modA First mod to compare. - * @param {BladesRollMod} modB Second mod to compare. - * @returns {number} - Comparison result. - */ - compareMods(modA, modB) { - // Define the order of mod names for sorting - const modOrder = ["Bargain", "Assist", "Setup"]; - // Check for basic push - if (modA.isBasicPush) { - return -1; - } - if (modB.isBasicPush) { - return 1; - } - // Check for active Bargain - if (modA.name === "Bargain" && modA.isActive) { - return -1; - } - if (modB.name === "Bargain" && modB.isActive) { - return 1; - } - // Check for push - if (modA.isPush) { - return -1; - } - if (modB.isPush) { - return 1; - } - // Check for mod name order - const modAIndex = modOrder.indexOf(modA.name); - const modBIndex = modOrder.indexOf(modB.name); - if (modAIndex !== -1 && modBIndex !== -1) { - return modAIndex - modBIndex; - } - // Default to alphabetical order - return modA.name.localeCompare(modB.name); - } - get rollMods() { - if (!this._rollMods) { - throw new Error("[get rollMods] No roll mods found!"); - } - return [...this._rollMods].sort((modA, modB) => this.compareMods(modA, modB)); - } - set rollMods(val) { this._rollMods = val; } - canResistWithArmor(csqData) { - if (!this.rollPrimary.hasArmor) { - return false; - } - return csqData.attribute === AttributeTrait.prowess; - } - canResistWithSpecialArmor(_csqData) { - if (!BladesPC.IsType(this.rollPrimary.rollPrimaryDoc)) { - return false; - } - return this.rollPrimary.rollPrimaryDoc.armorStatus.special; - } - // #endregion - // #region CONSEQUENCES: Getting, Accepting, Resisting - get _csqData() { - const csqData = this.flagData.consequenceData?.[this.finalPosition]?.[this.rollResult]; - if (csqData) { - return Object.values(csqData); - } - return []; - } - getConsequenceByID(csqID) { - return this._csqData.find((cData) => cData.id === csqID) ?? false; - } - get acceptedConsequences() { - if ([RollPhase.AwaitingConsequences, RollPhase.Complete].includes(this.rollPhase)) { - return this._csqData.filter((cData) => cData.isAccepted === true); - } - return []; - } - get unacceptedConsequences() { - if (this.rollPhase === RollPhase.AwaitingConsequences) { - return this._csqData.filter((cData) => cData.isAccepted !== true); - } - return []; - } - // #endregion - // #region *** GETDATA *** ~ - /** - * Retrieve the data for rendering the base RollCollab sheet. - * @returns {Promise} The data which can be used to render the HTML of the sheet. - */ - async getData() { - const context = super.getData(); - this.initRollMods(this.getRollModsData()); - this.rollMods.forEach((rollMod) => rollMod.applyRollModEffectKeys()); - const sheetData = this.getSheetData(this.getIsGM(), this.getRollCosts()); - return { ...context, ...sheetData }; - } - getFortuneRollModsData() { - const modsData = []; - if (this.rollSubType === RollSubType.Engagement) { - modsData.push({ - id: "BoldPlan-positive-roll", - name: "Bold Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - id: "ComplexPlan-negative-roll", - name: "Complex Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - id: "ExploitWeakness-positive-roll", - name: "Exploiting a Weakness", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - id: "WellDefended-negative-roll", - name: "Well-Defended", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - id: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }); - modsData.push({ - id: "EnemyInterference-negative-roll", - name: "Enemy Interference", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - } - return modsData; - } - getDowntimeActionRollModsData() { - const modsData = []; - modsData.push({ - id: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }); - if (this.rollDowntimeAction !== DowntimeAction.IndulgeVice) { - modsData.push({ - id: "CanBuyResultLevel-positive-after", - name: "Buying Result Level", - section: RollModSection.after, - base_status: RollModStatus.ForcedOn, - posNeg: "positive", - modType: RollModType.general, - value: 0, - effectKeys: [], - tooltip: "

Buying Result Level

After your roll, you can increase the result level by one for each Coin you spend.

" - }); - } - switch (this.rollDowntimeAction) { - case DowntimeAction.AcquireAsset: { - modsData.push({ - id: "RepeatPurchase-positive-roll", - name: "Repeat Purchase", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Repeat Purchase Bonus

Add +1d if you have previously acquired this asset or service with a Acquire Asset Downtime activity.

" - }); - modsData.push({ - id: "RestrictedItem-negative-after", - name: "Restricted", - section: RollModSection.after, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 0, - effectKeys: ["Cost-Heat2"], - tooltip: "

Restricted

Whether contraband goods or dangerous materials, this Acquire Asset Downtime activity will add +2 Heat to your crew.

" - }); - break; - } - default: break; - } - /* - modsData.push({ - id: "--", - name: "", - section: RollModSection, - base_status: RollModStatus, - posNeg: "", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }) - */ - return modsData; - } - /** - * Gets the roll modifications data. - * @returns {BladesRoll.RollModData[]} The roll modifications data. - */ - getRollModsData() { - const defaultMods = [ - ...BladesRoll.DefaultRollMods, - ...this.rollPrimary.rollModsData - ]; - if (this.rollDowntimeAction) { - defaultMods.push(...this.getDowntimeActionRollModsData()); - } - if (this.rollType === RollType.Action) { - if (this.rollPrimary.isWorsePosition) { - defaultMods.push({ - id: "WorsePosition-negative-position", - name: "Worse Position", - section: RollModSection.position, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Worse Position

A Consequence on a previous roll has worsened your Position.

" - }); - } - switch (this.rollDowntimeAction) { - case DowntimeAction.AcquireAsset: { - defaultMods.push(); - break; - } - default: break; - } - } - if (this.rollType === RollType.Action - && this.acceptedConsequences.some((csq) => csq.type === ConsequenceType.ReducedEffect)) { - defaultMods.push({ - id: "ReducedEffect-negative-effect", - name: "Reduced Effect", - section: RollModSection.effect, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Reduced Effect

A Consequence has worsened your Effect.

" - }); - } - if (this.rollOpposition?.rollOppModsData) { - return [ - ...defaultMods, - ...this.rollOpposition.rollOppModsData - ]; - } - return defaultMods; - } - /** - * Determines if the user is a game master. - * @returns {boolean} Whether the user is a GM. - */ - getIsGM() { - return game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM; - } - /** - * Gets the roll costs. - * @returns {BladesRoll.CostData[]} The roll costs. - */ - getRollCosts() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs) - .flat() - .filter((costData) => costData !== undefined); - } - /** - * Filters the roll costs to retrieve stress costs. - * @param {BladesRoll.CostData[]} rollCosts The roll costs. - * @returns {BladesRoll.CostData[]} The stress costs. - */ - getStressCosts(rollCosts) { - return rollCosts.filter((costData) => costData.costType === "Stress"); - } - /** - * Calculates the total stress cost. - * @param {BladesRoll.CostData[]} stressCosts The stress costs. - * @returns {number} The total stress cost. - */ - getTotalStressCost(stressCosts) { - return U.sum(stressCosts.map((costData) => costData.costAmount)); - } - /** - * Searches for any special armor roll costs. - * @param {BladesRoll.CostData[]} rollCosts The roll costs. - * @returns {BladesRoll.CostData[]} The stress costs. - */ - getSpecArmorCost(rollCosts) { - return rollCosts.find((costData) => costData.costType === "SpecialArmor"); - } - /** - * Constructs the sheet data. - * @param {boolean} isGM If the user is a GM. - * @param {BladesRoll.CostData[]} rollCosts The roll costs. - * @returns {BladesRoll.SheetData} The constructed sheet data. - */ - getSheetData(isGM, rollCosts) { - const { flagData: rData, rollPrimary, rollTraitData, rollTraitOptions, finalDicePool, finalPosition, finalEffect, finalResult, rollMods, rollFactors } = this; - if (!rollPrimary) { - throw new Error("A primary roll source is required for BladesRoll."); - } - const baseData = { - ...this.flagData, - cssClass: "roll-collab", - editable: this.options.editable, - isGM, - system: this.rollPrimaryDoc?.system, - rollMods, - rollPrimary, - rollTraitData, - rollTraitOptions, - diceTotal: finalDicePool, - rollOpposition: this.rollOpposition, - rollParticipants: this.rollParticipants, - rollParticipantOptions: this.rollParticipantSelectOptions, - rollEffects: Object.values(Effect), - rollTraitValOverride: this.rollTraitValOverride, - rollFactorPenaltiesNegated: this.rollFactorPenaltiesNegated, - posRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "positive")])), - negRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "negative")])), - hasInactiveConditionals: this.calculateHasInactiveConditionalsData(), - rollFactors, - ...this.calculateOddsHTML(finalDicePool, finalResult), - costData: this.getCostsHTML(rollCosts) - }; - const rollPositionData = this.calculatePositionData(finalPosition); - const rollEffectData = this.calculateEffectData(isGM, finalEffect); - const rollResultData = this.calculateResultData(isGM, finalResult); - const GMBoostsData = this.calculateGMBoostsData(rData); - const positionEffectTradeData = this.calculatePositionEffectTradeData(); - const userPermission = U.objFindKey(baseData.userPermissions, (v) => v.includes(game.user.id ?? "")); - // const downtimeData = this.processDowntimeActions(); - return { - ...baseData, - ...(this.rollPrimary.rollPrimaryDoc ? { rollPrimary: this.rollPrimary.rollPrimaryDoc } : {}), - ...rollPositionData, - ...rollEffectData, - ...rollResultData, - ...GMBoostsData, - ...positionEffectTradeData, - userPermission, - gamePhase: game.eunoblades.Tracker?.phase || BladesPhase.Freeplay - }; - } - // type BladesSelectOption = { - // value: valueType, - // display: displayType - // }; - // private processDowntimeActions() { - // const downtimeData: Record; - // if (BladesActor.IsType(this.rollPrimary.rollPrimaryDoc, BladesActorType.pc)) { - // downtimeData.canDoDowntimeActions = true; - // downtimeData.downtimeActionsRemaining = this.rollPrimary.rollPrimaryDoc.remainingDowntimeActions; - // const availableDowntimeActions: DowntimeAction[] = []; - // if (this.rollType === RollType.Action) { - // availableDowntimeActions.push(...[ - // DowntimeAction.AcquireAsset, - // DowntimeAction.LongTermProject, - // DowntimeAction.Recover, - // DowntimeAction.ReduceHeat - // ]); - // } else if (this.rollType === RollType.Fortune) { - // availableDowntimeActions.push(...[ - // DowntimeAction. - // ]) - // } - // downtimeData.downtimeActionOptions = - // downtimeActionOptions?: Array - // } - calculatePositionData(finalPosition) { - return { - rollPositions: Object.values(Position), - rollPositionFinal: finalPosition - }; - } - calculateEffectData(isGM, finalEffect) { - return { - rollEffects: Object.values(Effect), - rollEffectFinal: finalEffect, - isAffectingAfter: this.getVisibleRollMods(RollModSection.after).length > 0 - || (isGM && this.getRollMods(RollModSection.after).length > 0) - }; - } - calculateResultData(isGM, finalResult) { - return { - rollResultFinal: finalResult, - isAffectingResult: finalResult > 0 - || this.getVisibleRollMods(RollModSection.result).length > 0 - || (isGM && this.getRollMods(RollModSection.result).length > 0) - }; - } - calculateGMBoostsData(flagData) { - return { - GMBoosts: { - Dice: flagData.GMBoosts.Dice ?? 0, - [Factor.tier]: flagData.GMBoosts[Factor.tier] ?? 0, - [Factor.quality]: flagData.GMBoosts[Factor.quality] ?? 0, - [Factor.scale]: flagData.GMBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: flagData.GMBoosts[Factor.magnitude] ?? 0, - Result: flagData.GMBoosts.Result ?? 0 - }, - GMOppBoosts: { - [Factor.tier]: flagData.GMOppBoosts[Factor.tier] ?? 0, - [Factor.quality]: flagData.GMOppBoosts[Factor.quality] ?? 0, - [Factor.scale]: flagData.GMOppBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: flagData.GMOppBoosts[Factor.magnitude] ?? 0 - } - }; - } - calculateOddsHTML(diceTotal, finalResult) { - if (this.rollType === RollType.Resistance) { - return this.calculateOddsHTML_Resistance(diceTotal); - } - return this.calculateOddsHTML_Standard(diceTotal, finalResult); - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @param {number} finalResult - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Standard(diceTotal, finalResult) { - const oddsColors = { - crit: "var(--blades-gold)", - success: "var(--blades-white-bright)", - partial: "var(--blades-grey)", - fail: "var(--blades-black-dark)" - }; - const odds = { ...C.DiceOddsStandard[diceTotal] }; - if (finalResult < 0) { - for (let i = finalResult; i < 0; i++) { - oddsColors.crit = oddsColors.success; - oddsColors.success = oddsColors.partial; - oddsColors.partial = oddsColors.fail; - } - } - else if (finalResult > 0) { - for (let i = 0; i < finalResult; i++) { - oddsColors.fail = oddsColors.partial; - oddsColors.partial = oddsColors.success; - oddsColors.success = oddsColors.crit; - } - } - const resultElements = []; - Object.entries(odds).reverse().forEach(([result, chance]) => { - if (chance === 0) { - return; - } - resultElements.push(`
 
`); - }); - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Resistance(diceTotal) { - // Const oddsColors = [ - // "var(--blades-gold)", // -1 - // "var(--blades-white)", // 0 - // "var(--blades-red-bright)", // 1 - // "var(--blades-red-dark)", // 2 - // "var(--blades-red-bright)", // 3 - // "var(--blades-red-dark)", // 4 - // "var(--blades-red-bright)" // 5 - // ].reverse(); - const oddsColors = [ - "var(--blades-gold)", - "var(--blades-white)", - "var(--blades-red)", - "var(--blades-red)", - "var(--blades-red)", - "var(--blades-red)", - "var(--blades-red)" // 5 - ].reverse(); - const oddsFilters = [ - "none", - "none", - "brightness(0.2)", - "brightness(0.4)", - "brightness(0.6)", - "brightness(0.8)", - "none" - ].reverse(); - const odds = [...C.DiceOddsResistance[diceTotal]].reverse(); - const resultElements = []; - for (let index = 0; index < odds.length; index++) { - const chance = odds[index]; - if (chance > 0) { - const color = oddsColors[index]; - const filter = oddsFilters[index]; - resultElements.push(...[ - `
 
` - ]); - } - } - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate data for position and effect trade. - * @returns {{canTradePosition: boolean, canTradeEffect: boolean}} - */ - calculatePositionEffectTradeData() { - const canTradePosition = this.posEffectTrade === "position" || (this.posEffectTrade === false - && this.finalPosition !== Position.desperate - && this.finalEffect !== Effect.extreme); - const canTradeEffect = this.posEffectTrade === "effect" || (this.posEffectTrade === false - && this.finalPosition !== Position.controlled - && this.finalEffect !== Effect.zero); - return { canTradePosition, canTradeEffect }; - } - /** - * Calculate data on whether there are any inactive conditionals. - * @returns {Record} - Data on inactive conditionals. - */ - calculateHasInactiveConditionalsData() { - const hasInactive = {}; - for (const section of Object.values(RollModSection)) { - hasInactive[section] = this.getRollMods(section).filter((mod) => mod.isInInactiveBlock).length > 0; - } - return hasInactive; - } - getCostsHTML(rollCosts) { - switch (this.rollType) { - case RollType.Action: { - return this.parseActionRollCostsHTML(this.getStressCosts(rollCosts), this.getSpecArmorCost(rollCosts)); - } - case RollType.Resistance: { - return this.parseResistanceRollCostsHTML(this.getStressCosts(rollCosts), this.getSpecArmorCost(rollCosts)); - } - case RollType.Fortune: { - return this.parseFortuneRollCostsHTML(); - } - case RollType.IndulgeVice: { - return this.parseIndulgeViceRollCostsHTML(); - } - default: return false; - } - } - /** - * Calculate data for costs of Action Roll. - * @param {BladesRoll.CostData[]} stressCosts Array of stress costs. - * @param {BladesRoll.CostData} [specArmorCost] Specific armor cost. - * @returns {{footerLabel: string, tooltip: string} | undefined} - Costs data or undefined. - */ - parseActionRollCostsHTML(stressCosts, specArmorCost) { - if (specArmorCost || stressCosts.length > 0) { - const totalStressCost = this.getTotalStressCost(stressCosts); - return { - footerLabel: [ - "( Roll Costs", - totalStressCost > 0 ? `${totalStressCost} Stress` : null, - specArmorCost && totalStressCost ? "and" : null, - specArmorCost ? "your Special Armor" : null, - ")" - ].filter((line) => Boolean(line)).join(" "), - tooltip: [ - "

Roll Costs

    ", - ...stressCosts.map((costData) => `
  • ${costData.label}: ${costData.costAmount} Stress
  • `), - specArmorCost ? `
  • ${specArmorCost.label}: Special Armor
  • ` : null, - "
" - ].filter((line) => Boolean(line)).join("") - }; - } - return undefined; - } - parseResistanceRollCostsHTML(stressCosts, specArmorCost) { - const footerLabelStrings = [ - "( Resisting Costs" - ]; - if (specArmorCost) { - footerLabelStrings.push("your Special Armor )"); - } - else { - footerLabelStrings.push("(6 - Best Die) Stress,
or Clears 1 Stress on a Critical Success )"); - } - return { - footerLabel: footerLabelStrings.join(" "), - tooltip: [ - "

Roll Costs

    ", - ...stressCosts.map((costData) => `
  • ${costData.label}: ${costData.costAmount} Stress
  • `), - specArmorCost ? `
  • ${specArmorCost.label}: Special Armor
  • ` : null, - "
" - ].filter((line) => Boolean(line)).join("") - }; - } - parseFortuneRollCostsHTML() { - return { footerLabel: "Fortune Cost Label", tooltip: "Fortune Cost Tooltip" }; - } - parseIndulgeViceRollCostsHTML() { - return { footerLabel: "Indulge Vice Cost Label", tooltip: "Indulge Vice Cost Tooltip" }; - } - // #endregion - // #region *** EVALUATING ROLL *** ~ - // #region DICE ~ - _dieVals; - get dieVals() { - return this.roll.terms[0].results - .map((result) => result.result) - .sort() - .reverse(); - // return this._dieVals; - } - // Accounts for rolling zero dice by removing highest. - get finalDieVals() { - return this.isRollingZero ? this.dieVals.slice(1) : this.dieVals; - } - getDieClass(val, i) { - switch (this.rollType) { - case RollType.Resistance: { - if (val === 6 && i <= 1 && this.rollResult === -1) { - return "blades-die-critical"; - } - if (i === 0) { - return "blades-die-resistance"; - } - return "blades-die-fail"; - } - case RollType.IndulgeVice: { - if (i === 0) { - return "blades-die-indulge-vice"; - } - return "blades-die-fail"; - } - default: break; - } - if (val === 6 && i <= 1 && this.rollResult === RollResult.critical) { - val++; - } - return [ - "", - "blades-die-fail", - "blades-die-fail", - "blades-die-fail", - "blades-die-partial", - "blades-die-partial", - "blades-die-success", - "blades-die-critical" - ][val]; - } - getDieImage(val, i, isGhost = false) { - let imgPath = "systems/eunos-blades/assets/dice/image/"; - if (isGhost) { - imgPath += "ghost-"; - } - else if ([RollType.Resistance, RollType.IndulgeVice].includes(this.rollType) - || this.rollDowntimeAction) { - imgPath += "grad-"; - } - imgPath += val; - if (!isGhost && val === 6 && i <= 1 && this.isCritical) { - imgPath += "-crit"; - } - imgPath += ".webp"; - return imgPath; - } - get dieValsHTML() { - eLog.checkLog3("rollCollab", "[get dieValsHTML()]", { roll: this, dieVals: this.dieVals }); - const dieVals = [...this.dieVals]; - const ghostNum = this.isRollingZero ? dieVals.shift() : null; - return [ - ...dieVals.map((val, i) => ``), - ghostNum ? `` : null - ] - .filter((val) => typeof val === "string") - .join(""); - } - // #endregion - // #region RESULT GETTERS ~ - get isCritical() { - return this.finalDieVals.filter((val) => val === 6).length >= 2; - } - get isSuccess() { - return Boolean(!this.isCritical && this.finalDieVals.find((val) => val === 6)); - } - get isPartial() { - return Boolean(!this.isCritical && !this.isSuccess && this.finalDieVals.find((val) => val && val >= 4)); - } - get isFail() { - return !this.isCritical && !this.isSuccess && !this.isPartial; - } - get highestDieVal() { - return this.finalDieVals[0]; - } - get rollResult() { - if ([RollPhase.Collaboration, RollPhase.AwaitingRoll].includes(this.rollPhase)) { - return false; - } - switch (this.rollType) { - case RollType.Action: - case RollType.Fortune: { - if (this.isCritical) { - return RollResult.critical; - } - if (this.isSuccess) { - return RollResult.success; - } - if (this.isPartial) { - return RollResult.partial; - } - return RollResult.fail; - } - case RollType.Resistance: { // Return stress cost of resisting - if (this.isCritical) { - return -1; - } - return 6 - this.highestDieVal; - } - case RollType.IndulgeVice: { // Return stress cleared from indulging - return this.highestDieVal; - } - } - return false; - } - // #endregion - async resolveRoll() { - this.close(); - await this.roll.evaluate({ async: true }); - await this.setRollPhase(RollPhase.AwaitingConsequences); - switch (this.rollType) { - case RollType.Action: { - if (this.isApplyingConsequences) { - await this.setRollPhase(RollPhase.AwaitingConsequences); - } - else { - await this.setRollPhase(RollPhase.Complete); - } - // Apply Stress & Special Armor Costs - eLog.checkLog2("bladesRoll", "Costs", this.getRollCosts()); - if (BladesPC.IsType(this.rollPrimaryDoc)) { - const rollCostData = this.getRollCosts(); - const stressCost = this.getTotalStressCost(this.getStressCosts(rollCostData)); - if (stressCost !== 0) { - this.rollPrimaryDoc.adjustStress(stressCost); - } - if (this.getSpecArmorCost(rollCostData)) { - this.rollPrimaryDoc.spendSpecialArmor(); - } - } - // const rollCosts = get.roll.getTotalStressCost(get.roll.getStressCosts(get.roll.getRollCosts())) - await this.outputRollToChat(); - if (this.rollPrimary.rollPrimaryDoc) { - this.rollPrimary.rollPrimaryDoc.unsetFlag("eunos-blades", "isWorsePosition"); - } - break; - } - case RollType.Resistance: { - await this.setRollPhase(RollPhase.Complete); - const { id: csqID } = this.rollConsequence ?? {}; - const { chatID } = this.rollConsequence?.resistTo ?? {}; - if (csqID && chatID) { - const resistedCsq = await BladesConsequence.GetFromID(chatID, csqID); - if (resistedCsq && this.rollConsequence?.resistTo) { - await resistedCsq.applyResistedConsequence("resist", await this.getResultHTML(chatID, { icon: this.rollConsequence.resistTo.icon ?? "" })); - } - } - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollPrimaryDoc.adjustStress(this.resistanceStressCost); - } - // await this.outputRollToChat(); - break; - } - } - if (this.isApplyingConsequences) { - await this.setRollPhase(RollPhase.AwaitingConsequences); - } - eLog.checkLog3("rollCollab", "[resolveRoll()] After Evaluation, Before Chat", { roll: this, dieVals: this.dieVals }); - } - // #endregion - // #region *** INTERFACING WITH BLADESCHAT *** - getSpeaker(chatSpeaker) { - // Compare against rollPrimary and modify accordingly. - const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryDoc } = this.rollPrimary; - chatSpeaker.alias = rollPrimaryName; - if ([BladesItemType.cohort_gang, BladesItemType.cohort_expert].includes(rollPrimaryType)) { - chatSpeaker.actor = rollPrimaryDoc?.parent?.id ?? chatSpeaker.actor; - if (rollPrimaryDoc?.parent instanceof BladesPC) { - chatSpeaker.alias = `${chatSpeaker.alias} (${rollPrimaryDoc.parent.name})`; - } - } - else if ([BladesItemType.gm_tracker, BladesItemType.score].includes(rollPrimaryType)) { - chatSpeaker.actor = null; - chatSpeaker.alias = "The Gamemaster"; - } - else if (rollPrimaryID) { - chatSpeaker.actor = rollPrimaryID; - } - // chatSpeaker.alias = `${chatSpeaker.alias} Rolls ...`; - return chatSpeaker; - } - async getResultHTML(chatMsgID, context = {}) { - context = Object.assign(this, context, { chatMsgID }); - const templateParts = [ - "systems/eunos-blades/templates/chat/roll-result-", - U.lCase(this.rollType), - "-" - ]; - if (this.rollDowntimeAction) { - templateParts.push(U.lCase(this.rollDowntimeAction), "-"); - } - templateParts.push("roll.hbs"); - return await renderTemplate(templateParts.join(""), context); - } - _chatMessageID; - _chatMessageTemp; - get chatMessage() { - if (!this._chatMessageID) { - return undefined; - } - return this._chatMessageTemp; - } - set chatMessage(val) { - if (val && val.id) { - this._chatMessageID = val.id; - this._chatMessageTemp = val; - } - } - async outputRollToChat() { - const chatMessage = await BladesChat.ConstructRollOutput(this); - this.chatMessage = chatMessage; - } - // #endregion - // #region LISTENER FUNCTIONS ~ - async _handleConsequenceClick(event) { - const clickTarget$ = $(event.currentTarget); - const csqParent$ = clickTarget$.closest(".comp.consequence-display-container"); - const csqID = csqParent$.data("csq-id"); - const chatElem$ = csqParent$.closest(".blades-roll"); - const chatID = chatElem$.data("chat-id"); - const chatMessage = game.messages.get(chatID); - if (!chatMessage) { - return; - } - const csqs = await BladesConsequence.GetFromChatMessage(chatMessage); - const thisCsq = csqs.find((csq) => csq.id === csqID); - if (!thisCsq) { - return; - } - switch (clickTarget$.data("action")) { - case "accept-consequence": return thisCsq.acceptConsequence(); - case "resist-consequence": return thisCsq.resistConsequence(); - case "armor-consequence": return thisCsq.resistArmorConsequence(); - case "special-consequence": return thisCsq.resistSpecialArmorConsequence(); - } - return undefined; - } - _toggleRollModClick(event) { - event.preventDefault(); - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const rollMod = this.getRollModByID(id); - if (!rollMod) { - throw new Error(`Unable to find roll mod with id '${id}'`); - } - switch (rollMod.status) { - case RollModStatus.Hidden: - rollMod.userStatus = RollModStatus.ForcedOff; - return; - case RollModStatus.ForcedOff: - rollMod.userStatus = RollModStatus.ToggledOff; - return; - case RollModStatus.ToggledOff: - rollMod.userStatus = RollModStatus.ToggledOn; - return; - case RollModStatus.ToggledOn: - rollMod.userStatus = game.user.isGM - ? RollModStatus.ForcedOn - : RollModStatus.ToggledOff; - return; - case RollModStatus.ForcedOn: - rollMod.userStatus = RollModStatus.Hidden; - return; - default: throw new Error(`Unrecognized RollModStatus: ${rollMod.status}`); - } - } - /** - * Handles setting of rollMod status via GM pop-out controls - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSet(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const status = elem$.data("status"); - if (!isModStatus(status) && status !== "Reset") { - return; - } - const rollMod = this.getRollModByID(id); - if (rollMod) { - rollMod.userStatus = status === "Reset" ? undefined : status; - } - } - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlSetTargetToValue(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target").replace(/flags\.eunos-blades\./, ""); - const value = elem$.data("value"); - await this.document.setFlag(C.SYSTEM_ID, target, value).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - async _gmControlCycleTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const flagTarget = elem$.data("flagTarget"); - const curVal = elem$.data("curVal"); - const cycleVals = elem$.data("vals")?.split(/\|/); - if (!cycleVals) { - throw new Error(`Unable to parse cycle values from data-vals = ${elem$.data("vals")}`); - } - const curValIndex = cycleVals.indexOf(curVal); - if (curValIndex === -1) { - throw new Error(`Unable to find current value '${curVal}' in cycle values '${elem$.data("vals")}'`); - } - let newValIndex = curValIndex + 1; - if (newValIndex >= cycleVals.length) { - newValIndex = 0; - } - const newVal = cycleVals[newValIndex]; - eLog.checkLog3("gmControlCycleTarget", "gmControlCycleTarget", { flagTarget, curVal, cycleVals, curValIndex, newValIndex, newVal }); - await this.setFlagVal(flagTarget, newVal); - } - /** - * Handles resetting value associated with GM number line on a right-click. - * @param {ClickEvent} event JQuery context menu event sent to listener. - */ - async _gmControlResetTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target").replace(/flags\.eunos-blades\./, ""); - await this.document.unsetFlag(C.SYSTEM_ID, target).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetPosition(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const position = elem$.data("status"); - this.initialPosition = position; - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetEffect(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const effect = elem$.data("status"); - this.initialEffect = effect; - } - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlToggleFactor(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target"); - const value = !elem$.data("value"); - eLog.checkLog3("toggleFactor", "_gmControlToggleFactor", { event, target, value }); - const factorToggleData = this.document.getFlag(C.SYSTEM_ID, "rollCollab.rollFactorToggles"); - const [thisSource, thisFactor, thisToggle] = target.split(/\./).slice(-3); - // If thisToggle is unrecognized, just toggle whatever value target points at - if (!["isActive", "isPrimary", "isDominant", "highFavorsPC"].includes(thisToggle)) { - await this.document.setFlag(C.SYSTEM_ID, `rollCollab.${target}`, value) - .then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - // Otherwise, first toggle targeted factor to new value - factorToggleData[thisSource][thisFactor] = { - ...factorToggleData[thisSource][thisFactor] ?? { display: "" }, - [thisToggle]: value - }; - // Then perform specific logic depending on toggle targeted: - switch (thisToggle) { - case "isDominant": - case "isPrimary": { - // Only one factor per sourceType can be declared Primary or Dominant: - // If one is being activated, must toggle off the others. - if (value === true) { - Object.values(Factor) - .filter((factor) => factor !== thisFactor) - .forEach((factor) => { - if (factorToggleData[thisSource][factor]?.[thisToggle] === true) { - factorToggleData[thisSource][factor] = { - ...factorToggleData[thisSource][factor], - [thisToggle]: false - }; - } - }); - } - break; - } - case "isActive": { - // 'isActive' should be synchronized when 1) value is true, and 2) the other value is false - if (value === true) { - const otherSource = thisSource === "source" ? "opposition" : "source"; - factorToggleData[otherSource][thisFactor] = { - ...factorToggleData[otherSource][thisFactor] ?? { display: "" }, - isActive: value - }; - } - break; - } - default: break; - } - await this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollFactorToggles", factorToggleData) - .then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - async _onSelectChange(event) { - event.preventDefault(); - const elem = event.currentTarget; - const { docType } = elem.dataset; - if (elem.value !== "" && docType?.startsWith("BladesRollParticipant")) { - const [_, section, subSection] = docType.split("."); - await this.addRollParticipant(elem.value, section, subSection); - } - else { - await U.EventHandlers.onSelectChange(this, event); - socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - } - } - async _onTextInputBlur(event) { - await U.EventHandlers.onTextInputBlur(this, event); - socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - } - async _onGMPopupClick(event) { - /** - * { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollPosEffectTrade", "effect").then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - else { - this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollPosEffectTrade", false).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - } - }); - html.find("[data-action='tradeEffect']").on({ - click: (event) => { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollPosEffectTrade", "position").then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - else { - this.document.setFlag(C.SYSTEM_ID, "rollCollab.rollPosEffectTrade", false).then(() => socketlib.system.executeForEveryone("renderRollCollab", this.rollID)); - } - } - }); - html.find("[data-action='roll']").on({ - click: () => this.resolveRoll() - }); - html - .find("select[data-action='player-select']") - .on({ change: this._onSelectChange.bind(this) }); - if (!game.user.isGM) { - return; - } - // GM Controls - html.on({ - focusin: () => { BladesRoll.Active = this; } // Set reference to top-most, focused roll. - }); - /** - * Handles setting of rollMod status via GM pop-out controls - */ - html.find(".controls-toggle").on({ - click: (event) => { - event.preventDefault(); - $(event.currentTarget).parents(".controls-panel").toggleClass("active"); - } - }); - html.find("[data-action=\"gm-set\"]").on({ - click: this._gmControlSet.bind(this) - }); - /** - * Handles setting of baseline rollPosition via GM button line - */ - html.find("[data-action=\"gm-set-position\"]").on({ - click: this._gmControlSetPosition.bind(this) - }); - /** - * Handles setting of baseline rollEffect via GM button line - */ - html.find("[data-action=\"gm-set-effect\"]").on({ - click: this._gmControlSetEffect.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - html.find("[data-action=\"gm-set-target\"]").on({ - click: this._gmControlSetTargetToValue.bind(this), - contextmenu: this._gmControlResetTarget.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - html.find("[data-action=\"gm-cycle-target\"]").on({ - click: this._gmControlCycleTarget.bind(this) - }); - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - */ - html.find("[data-action=\"gm-toggle-factor\"]").on({ - click: this._gmControlToggleFactor.bind(this) - }); - html - .find("select[data-action='gm-select']") - .on({ change: this._onSelectChange.bind(this) }); - html - .find("[data-action=\"gm-edit-consequences\"]") - .on({ click: () => BladesDialog.DisplayRollConsequenceDialog(this) }); - html - .find("[data-action=\"gm-text-popup\"]") - .on({ click: this._onGMPopupClick.bind(this) }); - html - .find("[data-action='gm-text-input']") - .on({ blur: this._onTextInputBlur.bind(this) }); - } - // #endregion - // #region OVERRIDES: _canDragDrop, _onDrop, _onSubmit, close, render ~ - _canDragDrop() { - return game.user.isGM; - } - _onDrop(event) { - const { type, uuid } = TextEditor.getDragEventData(event); - const [id] = (new RegExp(`${type}\\.(.+)`).exec(uuid) ?? []).slice(1); - const oppDoc = game[`${U.lCase(type)}s`].get(id); - if (BladesRollOpposition.IsDoc(oppDoc)) { - this.rollOpposition = new BladesRollOpposition(this, { rollOppDoc: oppDoc }); - } - } - async _onSubmit(event, { updateData } = {}) { - const returnVal = await super._onSubmit(event, { updateData, preventClose: true }); - await socketlib.system.executeForEveryone("renderRollCollab", this.rollID); - return returnVal; - } - async close(options = {}) { - if (options.rollID) { - return super.close({}); - } - // await this.document.setFlag(C.SYSTEM_ID, "rollCollab", null); - socketlib.system.executeForEveryone("closeRollCollab", this.rollID); - return undefined; - } - render(force = false, options) { - if (!this.document.getFlag(C.SYSTEM_ID, "rollCollab")) { - return this; - } - return super.render(force, options); - } -} -// #region EXPORTS ~ -export { BladesRollMod, BladesRollPrimary, BladesRollOpposition, BladesRollParticipant }; -export default BladesRoll; -// #endregion diff --git a/module/blades.js b/module/blades.js index 5ce9d9d9..01f74295 100644 --- a/module/blades.js +++ b/module/blades.js @@ -1,193 +1,528 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~ -import C, { ActionTrait, RollType } from "./core/constants.js"; -import registerSettings, { initTinyMCEStyles, initCanvasStyles, initDOMStyles } from "./core/settings.js"; -import { registerHandlebarHelpers, preloadHandlebarsTemplates } from "./core/helpers.js"; -import BladesChat from "./classes/BladesChat.js"; -import U from "./core/utilities.js"; -import logger from "./core/logger.js"; -import G, { Initialize as GsapInitialize } from "./core/gsap.js"; -import BladesClockKey from "./classes/BladesClockKey.js"; -import BladesDirector from "./classes/BladesDirector.js"; -import BladesConsequence from "./classes/BladesConsequence.js"; -import BladesScene from "./classes/BladesScene.js"; -import BladesActorProxy, { BladesActor, BladesPC, BladesCrew, BladesNPC, BladesFaction } from "./documents/BladesActorProxy.js"; -import BladesItemProxy, { BladesItem, BladesClockKeeper, BladesGMTracker, BladesLocation, BladesScore, BladesProject } from "./documents/BladesItemProxy.js"; -import BladesItemSheet from "./sheets/item/BladesItemSheet.js"; -import BladesPCSheet from "./sheets/actor/BladesPCSheet.js"; -import BladesCrewSheet from "./sheets/actor/BladesCrewSheet.js"; -import BladesNPCSheet from "./sheets/actor/BladesNPCSheet.js"; -import BladesFactionSheet from "./sheets/actor/BladesFactionSheet.js"; -import BladesRoll, { BladesRollMod, BladesRollPrimary, BladesRollOpposition, BladesRollParticipant, BladesActionRoll, BladesEngagementRoll, BladesFortuneRoll, BladesIncarcerationRoll, BladesIndulgeViceRoll, BladesInlineResistanceRoll, BladesResistanceRoll } from "./classes/BladesRoll.js"; -import BladesDialog from "./classes/BladesDialog.js"; -import BladesAI, { AGENTS, AIAssistant } from "./core/ai.js"; -import BladesActiveEffect from "./documents/BladesActiveEffect.js"; -import BladesGMTrackerSheet from "./sheets/item/BladesGMTrackerSheet.js"; -import BladesClockKeeperSheet from "./sheets/item/BladesClockKeeperSheet.js"; -/* DEVCODE*/ -import BladesDebug from "./core/debug.js"; -CONFIG.debug.logging = true; -Object.assign(globalThis, { eLog: logger, BladesDebug }); -Handlebars.registerHelper("eLog", logger.hbsLog); -/* !DEVCODE*/ -let socket; // ~ SocketLib interface -// #endregion ▮▮▮▮[IMPORTS]▮▮▮▮ -class GlobalGetter { - get clockKeys() { return game.eunoblades.ClockKeys.filter((clockKey) => clockKey.isInScene() && clockKey.isVisible); } - get roll() { return BladesRoll.Active; } - get user() { return game.users.getName("Alistair"); } - get actor() { return game.actors.getName("Alistair"); } - get rollTarget() { return this.roll?.target; } - get rollData() { return this.roll?.data; } - get userFlags() { return this.user?.flags?.["eunos-blades"]; } - get actorFlags() { return this.actor?.flags?.["eunos-blades"]; } - get rollPrimary() { return this.roll?.rollPrimary; } - get rollPrimaryDoc() { return this.roll?.rollPrimaryDoc; } - get rollOpposition() { return this.roll?.rollOpposition; } - get sheetData() { return this.roll?.context; } - newActionRoll() { - const pc = game.actors.getName("Alistair"); - if (!pc) { - return; - } - const conf = { - target: pc, - targetFlagKey: "rollCollab", - rollType: RollType.Action, - rollTrait: ActionTrait.finesse, - rollUserID: game.users.find((user) => user.character?.name === "Alistair")?.id, - rollPrimaryData: pc - }; - BladesActionRoll.New(conf); - } -} -// #region Globals: Exposing Functionality to Global Scope ~ -/* DEVCODE*/ Object.assign(globalThis, { - get: new GlobalGetter(), - // updateClaims, - // updateContacts, - // updateOps, - // updateFactions, - // updateDescriptions, - // updateRollMods, - BladesScene, - BladesDirector, - BladesActor, - BladesPC, - BladesCrew, - BladesNPC, - BladesFaction, - BladesPCSheet, - BladesCrewSheet, - BladesFactionSheet, - BladesClockKey, - BladesNPCSheet, - BladesActiveEffect, - BladesRoll, - BladesRollMod, - BladesRollPrimary, - BladesRollOpposition, - BladesRollParticipant, - BladesActionRoll, - BladesEngagementRoll, - BladesFortuneRoll, - BladesIncarcerationRoll, - BladesIndulgeViceRoll, - BladesInlineResistanceRoll, - BladesResistanceRoll, - BladesChat, - BladesConsequence, - G, - U, - C, - BladesItem, - BladesClockKeeper, - BladesGMTracker, - BladesLocation, - BladesProject, - BladesScore, - BladesItemSheet, - BladesClockKeeperSheet, - BladesGMTrackerSheet, - BladesAI, - AIAssistant, - AGENTS -}); /* !DEVCODE*/ -// #endregion Globals -// #region ████████ SYSTEM INITIALIZATION: Initializing Blades In The Dark System on 'Init' Hook ████████ -Hooks.once("init", async () => { - // Initialize Game object - game.eunoblades = { - Rolls: new Collection(), - ClockKeys: new Collection(), - Consequences: new Collection(), - Director: BladesDirector.getInstance(), - Tooltips: new WeakMap() - }; - eLog.display("Initializing Blades In the Dark System"); - // Register System Settings - registerSettings(); - CONFIG.debug.hooks = U.getSetting("debugHooks"); - // Initialize Fonts & Gsap Animations - GsapInitialize(); - CONFIG.Item.documentClass = BladesItemProxy; - CONFIG.Actor.documentClass = BladesActorProxy; - CONFIG.Scene.documentClass = BladesScene; - CONFIG.ChatMessage.documentClass = BladesChat; - // Register sheet application classes - Actors.unregisterSheet("core", ActorSheet); - Items.unregisterSheet("core", ItemSheet); - Items.registerSheet("blades", BladesItemSheet, { types: C.ItemTypes, makeDefault: true }); - registerHandlebarHelpers(); - preloadHandlebarsTemplates(); - // Initialize preliminary classes with templates to load - await Promise.all([ - BladesPC.Initialize(), - BladesCrew.Initialize(), - BladesNPC.Initialize(), - BladesFaction.Initialize(), - BladesActiveEffect.Initialize(), - BladesGMTrackerSheet.Initialize(), - BladesClockKeeperSheet.Initialize(), - BladesScore.Initialize(), - BladesDialog.Initialize(), - BladesRoll.Initialize(), - BladesProject.Initialize(), - BladesChat.Initialize() - ]); -}); -Hooks.once("ready", async () => { - // Initialize overlays - await Promise.all([ - BladesDirector.Initialize(), - BladesGMTracker.Initialize(), - BladesClockKeeper.Initialize() - ]); - // Initialize Clocks, ClockKeys & Consequences - BladesClockKey.Initialize(); - await BladesConsequence.Initialize(); - initDOMStyles(); - initCanvasStyles(); - initTinyMCEStyles(); - await BladesDirector.getInstance().renderOverlay_SocketResponse(); - BladesDirector.InitSockets(); - BladesRoll.InitSockets(); -}); -// #endregion ▄▄▄▄▄ SYSTEM INITIALIZATION ▄▄▄▄▄ -// #region ░░░░░░░[SocketLib]░░░░ SocketLib Initialization ░░░░░░░ ~ -Hooks.once("socketlib.ready", () => { - socket = socketlib.registerSystem("eunos-blades"); - /* DEVCODE*/ Object.assign(globalThis, { socket, socketlib }); /* !DEVCODE*/ -}); -Hooks.once("diceSoNiceReady", (dice3d) => { - dice3d.addSystem({ id: "eunos-blades", name: "Euno's Blades" }, "preferred"); - dice3d.addDicePreset({ - type: "d6", - labels: [1, 2, 3, 4, 5, 6].map((num) => `systems/eunos-blades/assets/dice/faces/${num}.webp`), - system: "eunos-blades", - bumpMaps: [1, 2, 3, 4, 5, 6].map((num) => `systems/eunos-blades/assets/dice/bump-maps/${num}.webp`), - emissiveMaps: [undefined, undefined, undefined, undefined, undefined, "systems/eunos-blades/assets/dice/emission-maps/6.webp"], - emissive: "#d89300" - }); -}); -// #endregion ░░░░[Dice So Nice]░░░░ +/* + * ATTENTION: An "eval-source-map" devtool has been used. + * This devtool is neither made for production nor for readable output files. + * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools. + * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/) + * or disable the default devtool with "devtool: false". + * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/). + */ +/******/ (function() { // webpackBootstrap +/******/ "use strict"; +/******/ var __webpack_modules__ = ({ + +/***/ "./ts/BladesActor.ts": +/*!***************************!*\ + !*** ./ts/BladesActor.ts ***! + \***************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* harmony import */ var _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./classes/BladesDirector */ \"./ts/classes/BladesDirector.ts\");\n/* harmony import */ var _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./classes/BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region Imports ~\n\n\n\n\n\n\n\n// #endregion\n// Blades Theme Song: \"Bangkok\" from The Gray Man soundtrack: https://www.youtube.com/watch?v=cjjImvMqYlo&list=OLAK5uy_k9cZDd1Fbpd25jfDtte5A6HyauD2-cwgk&index=2\n// Also check out Discord thread: https://discord.com/channels/325094888133885952/1152316839163068527\nvar BladesActorUniqueTags;\n(function (BladesActorUniqueTags) {\n BladesActorUniqueTags[BladesActorUniqueTags[\"CharacterCrew\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.PC.CharacterCrew] = \"CharacterCrew\";\n BladesActorUniqueTags[BladesActorUniqueTags[\"VicePurveyor\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.NPC.VicePurveyor] = \"VicePurveyor\";\n})(BladesActorUniqueTags || (BladesActorUniqueTags = {}));\nvar BladesItemUniqueTypes;\n(function (BladesItemUniqueTypes) {\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"background\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.background] = \"background\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"vice\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.vice] = \"vice\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"crew_playbook\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_playbook] = \"crew_playbook\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"crew_reputation\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_reputation] = \"crew_reputation\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"heritage\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.heritage] = \"heritage\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"playbook\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.playbook] = \"playbook\";\n BladesItemUniqueTypes[BladesItemUniqueTypes[\"preferred_op\"] = _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.preferred_op] = \"preferred_op\";\n})(BladesItemUniqueTypes || (BladesItemUniqueTypes = {}));\nclass BladesActor extends Actor {\n // #region Static Overrides: Create ~\n static async create(data, options = {}) {\n data.token = data.token || {};\n data.system = data.system ?? {};\n // ~ Create world_name\n data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, \"\").trim().replace(/ /g, \"_\");\n return await super.create(data, options);\n }\n // #endregion\n // #region BladesDocument Implementation ~\n static get All() { return game.actors; }\n static Get(actorRef) {\n if (actorRef instanceof BladesActor) {\n return actorRef;\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(actorRef)) {\n return BladesActor.All.get(actorRef);\n }\n return BladesActor.All.find((a) => a.system.world_name === actorRef)\n || BladesActor.All.find((a) => a.name === actorRef);\n }\n static GetTypeWithTags(docType, ...tags) {\n return BladesActor.All.filter((actor) => actor.type === docType)\n .filter((actor) => actor.hasTag(...tags));\n }\n static IsType(doc, ...types) {\n const typeSet = new Set(types);\n return doc instanceof BladesActor && typeSet.has(doc.type);\n }\n get tags() { return this.system.tags ?? []; }\n hasTag(...tags) {\n return tags.every((tag) => this.tags.includes(tag));\n }\n async addTag(...tags) {\n const curTags = this.tags;\n tags.forEach((tag) => {\n if (curTags.includes(tag)) {\n return;\n }\n curTags.push(tag);\n });\n eLog.checkLog2(\"actor\", \"BladesActor.addTag(...tags)\", { tags, curTags });\n await this.update({ \"system.tags\": curTags });\n }\n async remTag(...tags) {\n const curTags = this.tags.filter((tag) => !tags.includes(tag));\n eLog.checkLog2(\"actor\", \"BladesActor.remTag(...tags)\", { tags, curTags });\n await this.update({ \"system.tags\": curTags });\n }\n get tooltip() {\n const tooltipText = [this.system.concept, this.system.subtitle]\n .filter(Boolean)\n .join(\"

\");\n return tooltipText ? (new Handlebars.SafeString(tooltipText)).toString() : undefined;\n }\n get dialogCSSClasses() { return \"\"; }\n getFactorTotal(factor) {\n switch (factor) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier: {\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n return this.system.tier.value + (this.crew?.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier) ?? 0);\n }\n return this.system.tier.value;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality: return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier);\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale: {\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc)) {\n return this.system.scale;\n }\n return 0;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude: {\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc)) {\n return this.system.magnitude;\n }\n return 0;\n }\n default: return 0;\n }\n }\n // #endregion\n // #region SubActorControl Implementation ~\n get subActors() {\n return Object.keys(this.system.subactors)\n .map((id) => this.getSubActor(id))\n .filter((subActor) => Boolean(subActor));\n }\n get activeSubActors() {\n return this.subActors.filter((subActor) => !subActor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived));\n }\n get archivedSubActors() {\n return this.subActors.filter((subActor) => subActor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived));\n }\n checkActorPrereqs(actor) {\n /* Implement any prerequisite checks for embedding actors */\n return Boolean(actor);\n }\n processEmbeddedActorMatches(globalActors) {\n return globalActors\n // Step 1: Filter out globals that fail prereqs.\n .filter(this.checkActorPrereqs)\n // Step 2: Filter out actors that are already active subActors\n .filter((gActor) => !this.activeSubActors.some((aActor) => aActor.id === gActor.id))\n // Step 3: Merge subactor data onto matching global actors\n .map((gActor) => this.getSubActor(gActor) || gActor)\n // Step 4: Sort by name\n .sort((a, b) => {\n if (a.name === b.name) {\n return 0;\n }\n if (a.name === null) {\n return 1;\n }\n if (b.name === null) {\n return -1;\n }\n if (a.name > b.name) {\n return 1;\n }\n if (a.name < b.name) {\n return -1;\n }\n return 0;\n });\n }\n getDialogActors(category) {\n /* **** NEED TO FILTER OUT ACTORS PLAYER DOESN'T HAVE PERMISSION TO SEE **** */\n const dialogData = {};\n switch (category) {\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.Contact:\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.Rival:\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.Friend:\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.Acquaintance: {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)\n || this.playbookName === null) {\n return false;\n }\n dialogData.Main = this.processEmbeddedActorMatches(BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc, this.playbookName));\n return dialogData;\n }\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.VicePurveyor: {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc) || !this.vice?.name) {\n return false;\n }\n dialogData.Main = this.processEmbeddedActorMatches(BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc, this.vice.name));\n return dialogData;\n }\n case _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__.SelectionCategory.Crew: {\n dialogData.Main = BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew);\n return dialogData;\n }\n default: return false;\n }\n }\n async addSubActor(actorRef, tags) {\n let focusSubActor;\n // Does an embedded subActor of this Actor already exist on the character?\n if (this.hasSubActorOf(actorRef)) {\n const subActor = this.getSubActor(actorRef);\n if (!subActor) {\n return;\n }\n // Is it an archived Item?\n if (subActor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)) {\n // Unarchive it\n await subActor.remTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived);\n }\n // Make it the focus item.\n focusSubActor = subActor;\n }\n else {\n // Is it not embedded at all? Create new entry in system.subactors from global actor\n const actor = BladesActor.Get(actorRef);\n if (!actor) {\n return;\n }\n const subActorData = {};\n if (tags) {\n subActorData.tags = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique([\n ...actor.tags,\n ...tags\n ]);\n }\n // Await the update, then make the retrieved subactor the focus\n await this.update({ [`system.subactors.${actor.id}`]: subActorData });\n focusSubActor = this.getSubActor(actor.id);\n }\n if (!focusSubActor) {\n return;\n }\n // Does this Actor contain any tags limiting it to one per actor?\n const uniqueTags = focusSubActor.tags.filter((tag) => tag in BladesActorUniqueTags);\n if (uniqueTags.length > 0) {\n // ... then archive all other versions.\n uniqueTags.forEach((uTag) => this.activeSubActors\n .filter((subActor) => Boolean(focusSubActor?.id\n && subActor.id !== focusSubActor.id\n && subActor.hasTag(uTag)))\n .map((subActor) => this.remSubActor(subActor.id)));\n }\n }\n getSubActor(actorRef) {\n const actor = BladesActor.Get(actorRef);\n if (!actor?.id) {\n return undefined;\n }\n if (!BladesActor.IsType(actor, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.faction)) {\n return actor;\n }\n const subActorData = (this.system.subactors[actor.id] ?? {});\n Object.assign(actor.system, subActorData);\n actor.parentActor = this;\n return actor;\n }\n hasSubActorOf(actorRef) {\n const actor = BladesActor.Get(actorRef);\n if (!actor) {\n return false;\n }\n return actor?.id ? actor.id in this.system.subactors : false;\n }\n async updateSubActor(actorRef, upData) {\n const updateData = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objExpand(upData);\n if (!updateData.system) {\n return undefined;\n }\n const actor = BladesActor.Get(actorRef);\n if (!actor) {\n return undefined;\n }\n // DiffObject new update data against actor data.\n const diffUpdateSystem = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objDiff(actor.system, updateData.system);\n // Merge new update data onto current subactor data.\n const mergedSubActorSystem = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMerge(this.system.subactors[actor.id] ?? {}, diffUpdateSystem, { isReplacingArrays: true, isConcatenatingArrays: false });\n // Confirm this update changes data:\n if (JSON.stringify(this.system.subactors[actor.id]) === JSON.stringify(mergedSubActorSystem)) {\n return undefined;\n }\n // Update actor with new subactor data.\n return this.update({ [`system.subactors.${actor.id}`]: null }, undefined, true)\n .then(() => this.update({ [`system.subactors.${actor.id}`]: mergedSubActorSystem }, undefined, true))\n .then(() => actor.sheet?.render());\n }\n async remSubActor(actorRef) {\n const subActor = this.getSubActor(actorRef);\n if (!subActor) {\n return;\n }\n await this.update({ \"system.subactors\": mergeObject(this.system.subactors, { [`-=${subActor.id}`]: null }) }, undefined, true);\n }\n async clearSubActors(isReRendering = true) {\n this.subActors.forEach((subActor) => {\n if (subActor.parentActor?.id === this.id) {\n subActor.clearParentActor(isReRendering);\n }\n });\n await this.sheet?.render();\n }\n async clearParentActor(isReRendering = true) {\n const { parentActor } = this;\n if (!parentActor) {\n return;\n }\n this.parentActor = undefined;\n this.system = this._source.system;\n this.ownership = this._source.ownership;\n this.prepareData();\n if (isReRendering) {\n await this.sheet?.render();\n }\n }\n // #endregion\n // #region SubItemControl Implementation ~\n get subItems() { return Array.from(this.items); }\n getSubItemsOfType(itemType) {\n return this.items.filter((item) => item.type === itemType);\n }\n get activeSubItems() { return this.items.filter((item) => !item.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)); }\n get archivedSubItems() { return this.items.filter((item) => item.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)); }\n _checkItemPrereqs(item) {\n if (!item.system.prereqs) {\n return true;\n }\n for (const [pType, pReqs] of Object.entries(item.system.prereqs)) {\n const pReqArray = Array.isArray(pReqs) ? pReqs : [pReqs.toString()];\n const hitRecord = {};\n if (!this._processPrereqArray(pReqArray, pType, hitRecord)) {\n return false;\n }\n }\n return true;\n }\n _processPrereqArray(pReqArray, pType, hitRecord) {\n while (pReqArray.length) {\n const pString = pReqArray.pop();\n hitRecord[pType] ??= [];\n if (!this._processPrereqType(pType, pString, hitRecord)) {\n return false;\n }\n }\n return true;\n }\n _processPrereqType(pType, pString, hitRecord) {\n switch (pType) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.PrereqType.HasActiveItem: {\n return this._processActiveItemPrereq(pString, hitRecord, pType);\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.PrereqType.HasActiveItemsByTag: {\n return this._processActiveItemsByTagPrereq(pString, hitRecord, pType);\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.PrereqType.AdvancedPlaybook: {\n return this._processAdvancedPlaybookPrereq();\n }\n default: return true;\n }\n }\n _processActiveItemPrereq(pString, hitRecord, pType) {\n const thisItem = this.activeSubItems\n .filter((i) => !hitRecord[pType]?.includes(i.id))\n .find((i) => i.system.world_name === pString);\n if (thisItem) {\n hitRecord[pType]?.push(thisItem.id);\n return true;\n }\n else {\n return false;\n }\n }\n _processActiveItemsByTagPrereq(pString, hitRecord, pType) {\n const thisItem = this.activeSubItems\n .filter((i) => !hitRecord[pType]?.includes(i.id))\n .find((i) => i.hasTag(pString));\n if (thisItem) {\n hitRecord[pType]?.push(thisItem.id);\n return true;\n }\n else {\n return false;\n }\n }\n _processAdvancedPlaybookPrereq() {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n return false;\n }\n if (!this.playbookName || ![_core_constants__WEBPACK_IMPORTED_MODULE_1__.Playbook.Ghost, _core_constants__WEBPACK_IMPORTED_MODULE_1__.Playbook.Hull, _core_constants__WEBPACK_IMPORTED_MODULE_1__.Playbook.Vampire].includes(this.playbookName)) {\n return false;\n }\n return true;\n }\n _processEmbeddedItemMatches(globalItems) {\n return globalItems\n // Step 1: Filter out globals that fail prereqs.\n .filter((item) => this._checkItemPrereqs(item))\n // Step 2: Filter out already-active items based on max_per_score (unless MultiplesOk)\n .filter((gItem) => gItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.MultiplesOK)\n || (gItem.system.max_per_score ?? 1)\n > this.activeSubItems.filter((sItem) => sItem.system.world_name === gItem.system.world_name).length)\n // Step 3: Replace with matching Archived, Embedded subItems\n .map((gItem) => {\n const matchingSubItems = this.archivedSubItems.filter((sItem) => sItem.system.world_name === gItem.system.world_name);\n if (matchingSubItems.length > 0) {\n return matchingSubItems;\n }\n else {\n return gItem;\n }\n })\n .flat()\n // Step 4: Apply CSS classes\n .map((sItem) => {\n sItem.dialogCSSClasses = \"\";\n const cssClasses = [];\n if (sItem.isEmbedded) {\n cssClasses.push(\"embedded\");\n }\n if (sItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear.Fine)) {\n cssClasses.push(\"fine-quality\");\n }\n if (sItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Featured)) {\n cssClasses.push(\"featured-item\");\n }\n if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.ability, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_ability].includes(sItem.type)) {\n if (this.getAvailableAdvancements(\"Ability\") === 0) {\n cssClasses.push(\"locked\");\n }\n else if ((sItem.system.price ?? 1) > this.getAvailableAdvancements(\"Ability\")) {\n cssClasses.push(\"locked\", \"unaffordable\");\n }\n else if ((sItem.system.price ?? 1) > 1) {\n cssClasses.push(\"expensive\");\n }\n }\n if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_upgrade].includes(sItem.type)) {\n if (this.getAvailableAdvancements(\"Upgrade\") === 0) {\n cssClasses.push(\"locked\");\n }\n else if ((sItem.system.price ?? 1) > this.getAvailableAdvancements(\"Upgrade\")) {\n cssClasses.push(\"locked\", \"unaffordable\");\n }\n else if ((sItem.system.price ?? 1) > 1) {\n cssClasses.push(\"expensive\");\n }\n }\n if (cssClasses.length > 0) {\n sItem.dialogCSSClasses = cssClasses.join(\" \");\n }\n return sItem;\n })\n // Step 5: Sort by featured, then by fine, then by world_name, then embedded first sorted by name\n .sort((a, b) => {\n if (a.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Featured) && !b.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Featured)) {\n return -1;\n }\n if (!a.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Featured) && b.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Featured)) {\n return 1;\n }\n if (a.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear.Fine) && !b.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear.Fine)) {\n return -1;\n }\n if (!a.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear.Fine) && b.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear.Fine)) {\n return 1;\n }\n if (a.system.world_name > b.system.world_name) {\n return 1;\n }\n if (a.system.world_name < b.system.world_name) {\n return -1;\n }\n if (a.isEmbedded && !b.isEmbedded) {\n return -1;\n }\n if (!a.isEmbedded && b.isEmbedded) {\n return 1;\n }\n if (a.name === b.name) {\n return 0;\n }\n if (a.name === null) {\n return 1;\n }\n if (b.name === null) {\n return -1;\n }\n if (a.name > b.name) {\n return 1;\n }\n if (a.name < b.name) {\n return -1;\n }\n return 0;\n });\n }\n getSubItem(itemRef, activeOnly = false) {\n const activeCheck = (i) => !activeOnly || !i.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived);\n if (typeof itemRef === \"string\" && this.items.get(itemRef)) {\n const returnItem = this.items.get(itemRef);\n if (returnItem && activeCheck(returnItem)) {\n return returnItem;\n }\n else {\n return undefined;\n }\n }\n else {\n const globalItem = _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.Get(itemRef);\n if (!globalItem) {\n return undefined;\n }\n return this.items.find((item) => item.name === globalItem.name && activeCheck(item))\n ?? this.items.find((item) => item.system.world_name === globalItem.system.world_name && activeCheck(item));\n }\n }\n hasSubItemOf(itemRef) {\n const item = _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.Get(itemRef);\n if (!item) {\n return false;\n }\n return Boolean(this.items.find((i) => i.system.world_name === item.system.world_name));\n }\n hasActiveSubItemOf(itemRef) {\n const item = _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.Get(itemRef);\n if (!item) {\n return false;\n }\n return Boolean(this.items.find((i) => !i.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)\n && i.system.world_name === item.system.world_name));\n }\n async addSubItem(itemRef) {\n /**\n * Determines whether a submitted BladesItemType is a type that should appear only once\n * on any given Actor.\n * @param {BladesItemType} type\n * @returns {boolean} True if the type is a BladesItemUniqueTypes\n **/\n function isBladesItemUniqueTypes(type) {\n return Object.values(BladesItemUniqueTypes).includes(type);\n }\n eLog.checkLog3(\"subitems\", \"[addSubItem] itemRef\", itemRef);\n let focusItem;\n // Does an embedded copy of this item already exist on the character?\n const embeddedItem = this.getSubItem(itemRef);\n if (embeddedItem) {\n // Is it an archived Item?\n if (embeddedItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)) {\n // Unarchive it & make it the focus item.\n await embeddedItem.remTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived);\n focusItem = embeddedItem;\n eLog.checkLog3(\"subitems\", `[addSubItem] IS ARCHIVED EMBEDDED > Removing 'Archived' Tag, '${focusItem.id}':`, focusItem);\n }\n else { // Otherwise...\n // Duplicate the item, and make the newly-created item the focus.\n focusItem = await _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.create([embeddedItem], { parent: this });\n eLog.checkLog3(\"subitems\", `[addSubItem] IS ACTIVE EMBEDDED > Duplicating, focusItem '${focusItem.id}':`, focusItem);\n }\n }\n else {\n // Is it not embedded at all? Embed from global instance.\n const globalItem = _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.Get(itemRef);\n eLog.checkLog3(\"subitems\", `[addSubItem] IS NOT EMBEDDED > Fetching Global, globalItem '${globalItem?.id}':`, globalItem);\n if (!globalItem) {\n return;\n }\n focusItem = await _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.create([globalItem], { parent: this });\n focusItem = this.items.getName(globalItem.name);\n }\n // Is this item type limited to one per actor?\n if (focusItem && isBladesItemUniqueTypes(focusItem.type)) {\n // ... then archive all other versions.\n await Promise.all(this.activeSubItems\n .filter((subItem) => subItem.type === focusItem?.type\n && subItem.system.world_name !== focusItem?.system.world_name\n && !subItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived))\n .map(this.remSubItem.bind(this)));\n }\n }\n async remSubItem(itemRef) {\n const subItem = this.getSubItem(itemRef);\n if (!subItem) {\n return;\n }\n if (subItem.type !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gear) {\n this.purgeSubItem(itemRef);\n return;\n }\n eLog.checkLog(\"actorTrigger\", `Removing SubItem ${subItem.name}`, subItem);\n if (subItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)) {\n return;\n }\n await subItem.addTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived);\n }\n async purgeSubItem(itemRef) {\n const subItem = this.getSubItem(itemRef);\n if (!subItem || subItem.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System.Archived)) {\n return;\n }\n await subItem.delete();\n }\n // #endregion\n // #region Advancement Implementation ~\n // get totalAbilityPoints(): number {\n // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 }\n // if (!this.playbook) { return 0 }\n // switch (this.type) {\n // case BladesActorType.pc: return this.system.advancement.ability ?? 0;\n // case BladesActorType.crew: return Math.floor(0.5 * (this.system.advancement.general ?? 0))\n // + (this.system.advancement.ability ?? 0);\n // default: return 0;\n // }\n // }\n // get spentAbilityPoints(): number {\n // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 }\n // if (!this.playbook) { return 0 }\n // return this.abilities.reduce((total, ability) => total + (ability.system.price ?? 1), 0);\n // }\n // get getAvailableAdvancements(\"Ability\")(): number {\n // if (!BladesActor.IsType(this, BladesActorType.pc, BladesActorType.crew)) { return 0 }\n // if (!this.playbook) { return 0 }\n // return this.totalAbilityPoints - this.spentAbilityPoints;\n // }\n /* Need simple getters for total ability & upgrade points that check for PRICES of items\n (upgrade.system.price ?? 1) */\n async grantAdvancementPoints(allowedTypes, amount = 1) {\n const aPtKey = Array.isArray(allowedTypes)\n ? [...allowedTypes].sort((a, b) => a.localeCompare(b)).join(\"_\")\n : allowedTypes;\n await this.update({ [`system.advancement_points.${aPtKey}`]: (this.system.advancement_points?.[aPtKey] ?? 0) + amount });\n }\n async removeAdvancementPoints(allowedTypes, amount = 1) {\n const aPtKey = Array.isArray(allowedTypes)\n ? [...allowedTypes].sort((a, b) => a.localeCompare(b)).join(\"_\")\n : allowedTypes;\n const newCount = this.system.advancement_points?.[aPtKey] ?? 0 - amount;\n if (newCount <= 0 && aPtKey in (this.system.advancement_points ?? [])) {\n await this.update({ [`system.advancement_points.-=${aPtKey}`]: null });\n }\n else {\n await this.update({ [`system.advancement_points.${aPtKey}`]: newCount });\n }\n }\n getAvailableAdvancements(trait) {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)) {\n return 0;\n }\n if (trait in _core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait) {\n return 1;\n }\n if (trait === \"Cohort\") {\n const pointsCohort = this.system.advancement_points?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.Cohort] ?? 0;\n const spentCohort = this.cohorts.length;\n return Math.max(0, pointsCohort - spentCohort);\n }\n const pointsAbility = this.system.advancement_points?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.Ability] ?? 0;\n const pointsCohortType = this.system.advancement_points?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.CohortType] ?? 0;\n const pointsUpgrade = this.system.advancement_points?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.Upgrade] ?? 0;\n const pointsUpgradeOrAbility = this.system.advancement_points?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.UpgradeOrAbility] ?? 0;\n const spentAbility = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sum(this.items\n .filter((item) => _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.ability, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_ability))\n .map((abil) => abil.system.price ?? 1));\n const spentCohortType = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sum(this.cohorts\n .map((cohort) => Math.max(0, _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique(Object.values(cohort.system.subtypes)).length - 1)));\n const spentUpgrade = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sum(this.items\n .filter((item) => _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_upgrade))\n .map((upgrade) => upgrade.system.price ?? 1));\n const excessUpgrade = Math.max(0, spentUpgrade - pointsUpgrade);\n const excessCohortType = Math.max(0, spentCohortType - pointsCohortType);\n const excessAbility = Math.max(0, spentAbility - pointsAbility);\n const remainingAbility = Math.max(0, pointsAbility - spentAbility);\n const remainingCohortType = Math.max(0, pointsCohortType - spentCohortType);\n const remainingUpgrade = Math.max(0, pointsUpgrade - spentUpgrade);\n const remainingUpgradeOrAbility = Math.max(0, pointsUpgradeOrAbility - excessUpgrade - (2 * excessAbility) - (2 * excessCohortType));\n if (trait === \"Ability\") {\n return remainingAbility + Math.floor(0.5 * remainingUpgradeOrAbility);\n }\n if (trait === \"Upgrade\") {\n return remainingUpgrade + remainingUpgradeOrAbility;\n }\n if (trait === \"CohortType\") {\n return remainingCohortType + remainingUpgradeOrAbility;\n }\n return 0;\n }\n get availableAbilityPoints() { return this.getAvailableAdvancements(\"Ability\"); }\n get availableUpgradePoints() { return this.getAvailableAdvancements(\"Upgrade\"); }\n get availableCohortPoints() { return this.getAvailableAdvancements(\"Cohort\"); }\n get availableCohortTypePoints() { return this.getAvailableAdvancements(\"CohortType\"); }\n get canPurchaseAbility() { return this.availableAbilityPoints > 0; }\n get canPurchaseUpgrade() { return this.availableUpgradePoints > 0; }\n get canPurchaseCohort() { return this.availableCohortPoints > 0; }\n get canPurchaseCohortType() { return this.availableCohortTypePoints > 0; }\n async advancePlaybook() {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew) || !this.playbook) {\n return;\n }\n await this.update({ \"system.experience.playbook.value\": 0 });\n if (this instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} Advances their Playbook!`,\n body: `${this.name}, select a new Ability on your Character Sheet.`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesNoticeType.push,\n cssClasses: \"advancement-alert\"\n });\n this.grantAdvancementPoints(_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.Ability);\n return;\n }\n if (this instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: \"You Advance your Crew Playbook!\",\n body: \"Select new Upgrades and/or Abilities on your Crew Sheet.\",\n type: _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesNoticeType.push,\n cssClasses: \"advancement-alert crew-advancement-alert\"\n });\n const coinGained = this.system.tier.value + 2;\n this.members.forEach((member) => {\n if (member.primaryUser?.id) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getInstance().pushNotice_SocketCall(member.primaryUser?.id, {\n title: \"Your Stash Increases! (Crew Advancement)\",\n type: _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesNoticeType.push,\n body: `You gain ${coinGained} Stash from Crew Advancement.`,\n cssClasses: \"stash-alert\"\n });\n member.addStash(coinGained);\n }\n });\n this.grantAdvancementPoints(_core_constants__WEBPACK_IMPORTED_MODULE_1__.AdvancementPoint.UpgradeOrAbility, 2);\n }\n }\n async advanceAttribute(attribute) {\n if (!(this instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC)) {\n return;\n }\n if (!this.primaryUser?.id) {\n return;\n }\n await this.update({ [`system.experience.${attribute}.value`]: 0 });\n const actions = _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Action[attribute].map((action) => `${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(action)}`);\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_5__[\"default\"].getInstance().pushNotice_SocketCall(this.primaryUser.id, {\n title: `${this.name} Advances their ${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].uCase(attribute)}!`,\n body: `${this.name}, add a dot to one of ${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].oxfordize(actions, true, \"or\")}.`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesNoticeType.push,\n cssClasses: \"advancement-alert\"\n });\n }\n get isAtWar() {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesNPC.IsType(this)) {\n return false;\n }\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this)) {\n return this.crew?.isAtWar ?? false;\n }\n return Object.values(this.system.at_war_with ?? {})\n .filter((val) => val === true)\n .length > 0;\n }\n // #endregion\n // #region BladesSubActor Implementation ~\n parentActor;\n get isSubActor() { return this.parentActor !== undefined; }\n // #endregion\n // #region BladesRoll Implementation ~\n get rollPrimaryModsSchemaSet() {\n return _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_4__.BladesRollMod.ParseDocModsToSchemaSet(this);\n }\n get rollFactors() {\n const factorData = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: {\n name: _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier,\n display: \"Tier\",\n value: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier),\n max: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier),\n baseVal: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier),\n isActive: true,\n isPrimary: true,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: {\n name: _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality,\n display: \"Quality\",\n value: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality),\n max: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality),\n baseVal: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality),\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n }\n };\n return factorData;\n }\n // #region BladesRoll.PrimaryDoc Implementation\n get rollPrimaryID() { return this.id; }\n get rollPrimaryDoc() { return this; }\n get rollPrimaryName() { return this.name; }\n get rollPrimaryType() {\n if (![_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew].includes(this.type)) {\n throw new Error(`BladesActor of type '${this.type}' (\"${this.name}\") cannot be RollPrimary.`);\n }\n return this.type;\n }\n get rollPrimaryImg() { return this.img; }\n // #endregion\n // #endregion\n // #region BladesCrew Implementation ~\n // #endregion\n // #region PREPARING DERIVED DATA ~\n prepareDerivedData() {\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n this._preparePCData(this.system);\n }\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)) {\n this._prepareCrewData(this.system);\n }\n }\n _preparePCData(system) {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n return;\n }\n // Extract experience clues from playbook item, if any\n if (this.playbook) {\n system.experience.clues = [\n ...system.experience.clues,\n ...Object.values(this.playbook.system.experience_clues)\n .filter((clue) => Boolean(clue.trim()))\n ];\n }\n // Extract gather information questions from playbook item, if any\n if (this.playbook) {\n system.gather_info = [\n ...system.gather_info,\n ...Object.values(this.playbook.system.gather_info_questions)\n .filter((question) => Boolean(question.trim()))\n ];\n }\n }\n _prepareCrewData(system) {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)) {\n return;\n }\n // Extract experience clues and turfs from playbook item, if any\n if (this.playbook) {\n system.experience.clues = [\n ...system.experience.clues,\n ...Object.values(this.playbook.system.experience_clues)\n .filter((clue) => Boolean(clue.trim()))\n ];\n system.turfs = this.playbook.system.turfs;\n }\n }\n // #endregion\n // #region OVERRIDES: _onCreateDescendantDocuments, update ~\n // @ts-expect-error New method not defined in @league VTT types.\n async _onCreateDescendantDocuments(parent, collection, docs, data, options, userId) {\n await Promise.all(docs.map(async (doc) => {\n if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.playbook, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_playbook)) {\n await Promise.all(this.activeSubItems\n .filter((aItem) => aItem.type === doc.type && aItem.system.world_name !== doc.system.world_name)\n .map((aItem) => this.remSubItem(aItem)));\n }\n }));\n // @ts-expect-error New method not defined in @league VTT types.\n await super._onCreateDescendantDocuments(parent, collection, docs, data, options, userId);\n eLog.checkLog(\"actorTrigger\", \"_onCreateDescendantDocuments\", { parent, collection, docs, data, options, userId });\n docs.forEach((doc) => {\n if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.vice) && BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n this.activeSubActors\n .filter((subActor) => subActor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.NPC.VicePurveyor) && !subActor.hasTag(doc.name))\n .forEach((subActor) => { this.remSubActor(subActor); });\n }\n });\n }\n async update(updateData, context, isSkippingSubActorCheck = false) {\n if (!updateData) {\n return super.update(updateData);\n }\n if (BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)) {\n if (!this.playbook) {\n return undefined;\n }\n eLog.checkLog(\"actorTrigger\", \"Updating Crew\", { updateData });\n const playbookUpdateData = Object.fromEntries(Object.entries(flattenObject(updateData))\n .filter(([key, _]) => key.startsWith(\"system.turfs.\")));\n updateData = Object.fromEntries(Object.entries(flattenObject(updateData))\n .filter(([key, _]) => !key.startsWith(\"system.turfs.\")));\n eLog.checkLog(\"actorTrigger\", \"Updating Crew\", { crewUpdateData: updateData, playbookUpdateData });\n const diffPlaybookData = diffObject(flattenObject(this.playbook), playbookUpdateData);\n delete diffPlaybookData._id;\n if (!_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isEmpty(diffPlaybookData)) {\n await this.playbook.update(playbookUpdateData, context)\n .then(() => this.sheet?.render(false));\n }\n }\n else if ((BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc)\n || BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.faction))\n && this.parentActor\n && !isSkippingSubActorCheck) {\n // This is an embedded Actor: Update it as a subActor of parentActor.\n return this.parentActor.updateSubActor(this.id, updateData)\n .then(() => this);\n }\n return super.update(updateData, context);\n }\n // #endregion\n // #region Rolling Dice ~\n /**\n * Creates modifiers for dice roll.\n *\n * @param {int} rs\n * Min die modifier\n * @param {int} re\n * Max die modifier\n * @param {int} s\n * Selected die\n */\n createListOfDiceMods(rs, re, s) {\n let text = \"\";\n if (s === \"\") {\n s = 0;\n }\n for (let i = rs; i <= re; i++) {\n let plus = \"\";\n if (i >= 0) {\n plus = \"+\";\n }\n text += ``;\n }\n return text;\n }\n // #endregion Rolling Dice\n // #region NPC Randomizers ~\n updateRandomizers() {\n if (!BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc)) {\n return;\n }\n const titleChance = 0.05;\n const suffixChance = 0.01;\n const { persona, secret, random } = this.system;\n /**\n * Returns a random element from an array, optionally excluding all values\n * passed as subsequent parameters.\n * @param {string[]} arr The array to randomly select from.\n * @param {...string} curVals The values to exclude from the sample.\n */\n function sampleArray(arr, ...curVals) {\n arr = arr.filter((elem) => !curVals.includes(elem));\n if (!arr.length) {\n return \"\";\n }\n return arr[Math.floor(Math.random() * arr.length)];\n }\n const randomGen = {\n name: (gen) => {\n return [\n Math.random() <= titleChance\n ? sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_title)\n : \"\",\n sampleArray([\n ...((gen ?? \"\").charAt(0).toLowerCase() !== \"m\" ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_first.female : []),\n ...((gen ?? \"\").charAt(0).toLowerCase() !== \"f\" ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_first.male : [])\n ]),\n `\"${sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_alias)}\"`,\n sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_surname),\n Math.random() <= suffixChance\n ? sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.name_suffix)\n : \"\"\n ].filter((val) => Boolean(val)).join(\" \");\n },\n background: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.background, random.background.value),\n heritage: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.heritage, random.heritage.value),\n profession: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.profession, random.profession.value),\n gender: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.gender, persona.gender.value),\n appearance: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.appearance, persona.appearance.value),\n goal: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.goal, persona.goal.value, secret.goal.value),\n method: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.method, persona.method.value, secret.method.value),\n trait: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.trait, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value),\n interests: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.interests, persona.interests.value, secret.interests.value),\n quirk: () => sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.quirk, persona.quirk.value),\n style: (gen = \"\") => sampleArray([\n ...(gen.charAt(0).toLowerCase() !== \"m\" ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.style.female : []),\n ...(gen.charAt(0).toLowerCase() !== \"f\" ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.style.male : [])\n ], persona.style.value)\n };\n const gender = persona.gender.isLocked ? persona.gender.value : randomGen.gender();\n const updateKeys = [\n ...Object.keys(persona).filter((key) => !persona[key]?.isLocked),\n ...Object.keys(random).filter((key) => !random[key]?.isLocked),\n ...Object.keys(secret).filter((key) => !secret[key]?.isLocked)\n .map((secretKey) => `secret-${secretKey}`)\n ];\n eLog.checkLog(\"Update Keys\", { updateKeys });\n const updateData = {};\n updateKeys.forEach((key) => {\n switch (key) {\n case \"name\":\n case \"heritage\":\n case \"background\":\n case \"profession\": {\n const randomVal = randomGen[key]();\n updateData[`system.random.${key}`] = {\n isLocked: false,\n value: randomVal || random[key].value\n };\n break;\n }\n case \"secret-goal\":\n case \"secret-interests\":\n case \"secret-method\": {\n key = key.replace(/^secret-/, \"\");\n const randomVal = randomGen[key]();\n updateData[`system.secret.${key}`] = {\n isLocked: false,\n value: randomVal || secret[key].value\n };\n break;\n }\n case \"gender\": {\n updateData[`system.persona.${key}`] = {\n isLocked: persona.gender.isLocked,\n value: gender\n };\n break;\n }\n case \"trait1\":\n case \"trait2\":\n case \"trait3\":\n case \"secret-trait\": {\n const trait1 = persona.trait1.isLocked\n ? persona.trait1.value\n : sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.trait, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value);\n const trait2 = persona.trait2.isLocked\n ? persona.trait2.value\n : sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.trait, trait1, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value);\n const trait3 = persona.trait3.isLocked\n ? persona.trait3.value\n : sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.trait, trait1, trait2, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value);\n const secretTrait = secret.trait.isLocked\n ? secret.trait.value\n : sampleArray(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.NPC.trait, trait1, trait2, trait3, persona.trait1.value, persona.trait2.value, persona.trait3.value, secret.trait.value);\n if (!persona.trait1.isLocked) {\n updateData[\"system.persona.trait1\"] = {\n isLocked: false,\n value: trait1\n };\n }\n if (!persona.trait2.isLocked) {\n updateData[\"system.persona.trait2\"] = {\n isLocked: false,\n value: trait2\n };\n }\n if (!persona.trait3.isLocked) {\n updateData[\"system.persona.trait3\"] = {\n isLocked: false,\n value: trait3\n };\n }\n if (!secret.trait.isLocked) {\n updateData[\"system.secret.trait\"] = {\n isLocked: false,\n value: secretTrait\n };\n }\n break;\n }\n default: {\n const randomVal = randomGen[key]();\n updateData[`system.persona.${key}`] = {\n isLocked: false,\n value: randomVal || persona[key].value\n };\n break;\n }\n }\n });\n this.update(updateData);\n }\n // #endregion NPC Randomizers\n // Unlock lower-level update method for subclasses\n async callOnUpdate(...args) {\n await this._onUpdate(...args);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesActor);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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VztBQUMvQyxzQ0FBc0Msd0RBQVc7QUFDakQscUNBQXFDLHdEQUFXO0FBQ2hELHlDQUF5Qyx3REFBVztBQUNwRCxxQ0FBcUMsd0RBQVc7QUFDaEQ7QUFDQSwwREFBMEQsd0RBQVc7QUFDckUsMERBQTBELHdEQUFXO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDLFVBQVU7QUFDeEQ7QUFDQSx1Q0FBdUMsWUFBWTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0RBQWdELElBQUk7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnREFBZ0QsSUFBSTtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpREFBaUQsSUFBSTtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDLHdEQUFXO0FBQ2pEO0FBQ0E7QUFDQSxzQ0FBc0Msd0RBQVc7QUFDakQ7QUFDQTtBQUNBLHNDQUFzQyx3REFBVztBQUNqRDtBQUNBO0FBQ0Esc0NBQXNDLHdEQUFXO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaURBQWlELElBQUk7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxXQUFXLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9CbGFkZXNBY3Rvci50cz8xMTdkIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuLy8gI3JlZ2lvbiBJbXBvcnRzIH5cbmltcG9ydCBVIGZyb20gXCIuL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgQywgeyBCbGFkZXNBY3RvclR5cGUsIFRhZywgUGxheWJvb2ssIEJsYWRlc05vdGljZVR5cGUsIEJsYWRlc0l0ZW1UeXBlLCBBY3Rpb25UcmFpdCwgUHJlcmVxVHlwZSwgQWR2YW5jZW1lbnRQb2ludCwgUmFuZG9taXplcnMsIEZhY3RvciB9IGZyb20gXCIuL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBCbGFkZXNQQywgQmxhZGVzQ3JldywgQmxhZGVzTlBDIH0gZnJvbSBcIi4vZG9jdW1lbnRzL0JsYWRlc0FjdG9yUHJveHlcIjtcbmltcG9ydCB7IEJsYWRlc0l0ZW0gfSBmcm9tIFwiLi9kb2N1bWVudHMvQmxhZGVzSXRlbVByb3h5XCI7XG5pbXBvcnQgeyBCbGFkZXNSb2xsTW9kIH0gZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNSb2xsXCI7XG5pbXBvcnQgQmxhZGVzRGlyZWN0b3IgZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNEaXJlY3RvclwiO1xuaW1wb3J0IHsgU2VsZWN0aW9uQ2F0ZWdvcnkgfSBmcm9tIFwiLi9jbGFzc2VzL0JsYWRlc0RpYWxvZ1wiO1xuLy8gI2VuZHJlZ2lvblxuLy8gQmxhZGVzIFRoZW1lIFNvbmc6IFwiQmFuZ2tva1wiIGZyb20gVGhlIEdyYXkgTWFuIHNvdW5kdHJhY2s6IGh0dHBzOi8vd3d3LnlvdXR1YmUuY29tL3dhdGNoP3Y9Y2pqSW12TXFZbG8mbGlzdD1PTEFLNXV5X2s5Y1pEZDFGYnBkMjVqZkR0dGU1QTZIeWF1RDItY3dnayZpbmRleD0yXG4vLyBBbHNvIGNoZWNrIG91dCBEaXNjb3JkIHRocmVhZDogaHR0cHM6Ly9kaXNjb3JkLmNvbS9jaGFubmVscy8zMjUwOTQ4ODgxMzM4ODU5NTIvMTE1MjMxNjgzOTE2MzA2ODUyN1xudmFyIEJsYWRlc0FjdG9yVW5pcXVlVGFncztcbihmdW5jdGlvbiAoQmxhZGVzQWN0b3JVbmlxdWVUYWdzKSB7XG4gICAgQmxhZGVzQWN0b3JVbmlxdWVUYWdzW0JsYWRlc0FjdG9yVW5pcXVlVGFnc1tcIkNoYXJhY3RlckNyZXdcIl0gPSBUYWcuUEMuQ2hhcmFjdGVyQ3Jld10gPSBcIkNoYXJhY3RlckNyZXdcIjtcbiAgICBCbGFkZXNBY3RvclVuaXF1ZVRhZ3NbQmxhZGVzQWN0b3JVbmlxdWVUYWdzW1wiVmljZVB1cnZleW9yXCJdID0gVGFnLk5QQy5WaWNlUHVydmV5b3JdID0gXCJWaWNlUHVydmV5b3JcIjtcbn0pKEJsYWRlc0FjdG9yVW5pcXVlVGFncyB8fCAoQmxhZGVzQWN0b3JVbmlxdWVUYWdzID0ge30pKTtcbnZhciBCbGFkZXNJdGVtVW5pcXVlVHlwZXM7XG4oZnVuY3Rpb24gKEJsYWRlc0l0ZW1VbmlxdWVUeXBlcykge1xuICAgIEJsYWRlc0l0ZW1VbmlxdWVUeXBlc1tCbGFkZXNJdGVtVW5pcXVlVHlwZXNbXCJiYWNrZ3JvdW5kXCJdID0gQmxhZGVzSXRlbVR5cGUuYmFja2dyb3VuZF0gPSBcImJhY2tncm91bmRcIjtcbiAgICBCbGFkZXNJdGVtVW5pcXVlVHlwZXNbQmxhZGVzSXRlbVVuaXF1ZVR5cGVzW1widmljZVwiXSA9IEJsYWRlc0l0ZW1UeXBlLnZpY2VdID0gXCJ2aWNlXCI7XG4gICAgQmxhZGVzSXRlbVVuaXF1ZVR5cGVzW0JsYWRlc0l0ZW1VbmlxdWVUeXBlc1tcImNyZXdfcGxheWJvb2tcIl0gPSBCbGFkZXNJdGVtVHlwZS5jcmV3X3BsYXlib29rXSA9IFwiY3Jld19wbGF5Ym9va1wiO1xuICAgIEJsYWRlc0l0ZW1VbmlxdWVUeXBlc1tCbGFkZXNJdGVtVW5pcXVlVHlwZXNbXCJjcmV3X3JlcHV0YXRpb25cIl0gPSBCbGFkZXNJdGVtVHlwZS5jcmV3X3JlcHV0YXRpb25dID0gXCJjcmV3X3JlcHV0YXRpb25cIjtcbiAgICBCbGFkZXNJdGVtVW5pcXVlVHlwZXNbQmxhZGVzSXRlbVVuaXF1ZVR5cGVzW1wiaGVyaXRhZ2VcIl0gPSBCbGFkZXNJdGVtVHlwZS5oZXJpdGFnZV0gPSBcImhlcml0YWdlXCI7XG4gICAgQmxhZGVzSXRlbVVuaXF1ZVR5cGVzW0JsYWRlc0l0ZW1VbmlxdWVUeXBlc1tcInBsYXlib29rXCJdID0gQmxhZGVzSXRlbVR5cGUucGxheWJvb2tdID0gXCJwbGF5Ym9va1wiO1xuICAgIEJsYWRlc0l0ZW1VbmlxdWVUeXBlc1tCbGFkZXNJdGVtVW5pcXVlVHlwZXNbXCJwcmVmZXJyZWRfb3BcIl0gPSBCbGFkZXNJdGVtVHlwZS5wcmVmZXJyZWRfb3BdID0gXCJwcmVmZXJyZWRfb3BcIjtcbn0pKEJsYWRlc0l0ZW1VbmlxdWVUeXBlcyB8fCAoQmxhZGVzSXRlbVVuaXF1ZVR5cGVzID0ge30pKTtcbmNsYXNzIEJsYWRlc0FjdG9yIGV4dGVuZHMgQWN0b3Ige1xuICAgIC8vICNyZWdpb24gU3RhdGljIE92ZXJyaWRlczogQ3JlYXRlIH5cbiAgICBzdGF0aWMgYXN5bmMgY3JlYXRlKGRhdGEsIG9wdGlvbnMgPSB7fSkge1xuICAgICAgICBkYXRhLnRva2VuID0gZGF0YS50b2tlbiB8fCB7fTtcbiAgICAgICAgZGF0YS5zeXN0ZW0gPSBkYXRhLnN5c3RlbSA/PyB7fTtcbiAgICAgICAgLy8gfiBDcmVhdGUgd29ybGRfbmFtZVxuICAgICAgICBkYXRhLnN5c3RlbS53b3JsZF9uYW1lID0gZGF0YS5zeXN0ZW0ud29ybGRfbmFtZSA/PyBkYXRhLm5hbWUucmVwbGFjZSgvW15BLVphLXpfMC05IF0vZywgXCJcIikudHJpbSgpLnJlcGxhY2UoLyAvZywgXCJfXCIpO1xuICAgICAgICByZXR1cm4gYXdhaXQgc3VwZXIuY3JlYXRlKGRhdGEsIG9wdGlvbnMpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNEb2N1bWVudCBJbXBsZW1lbnRhdGlvbiB+XG4gICAgc3RhdGljIGdldCBBbGwoKSB7IHJldHVybiBnYW1lLmFjdG9yczsgfVxuICAgIHN0YXRpYyBHZXQoYWN0b3JSZWYpIHtcbiAgICAgICAgaWYgKGFjdG9yUmVmIGluc3RhbmNlb2YgQmxhZGVzQWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiBhY3RvclJlZjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoVS5pc0RvY0lEKGFjdG9yUmVmKSkge1xuICAgICAgICAgICAgcmV0dXJuIEJsYWRlc0FjdG9yLkFsbC5nZXQoYWN0b3JSZWYpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBCbGFkZXNBY3Rvci5BbGwuZmluZCgoYSkgPT4gYS5zeXN0ZW0ud29ybGRfbmFtZSA9PT0gYWN0b3JSZWYpXG4gICAgICAgICAgICB8fCBCbGFkZXNBY3Rvci5BbGwuZmluZCgoYSkgPT4gYS5uYW1lID09PSBhY3RvclJlZik7XG4gICAgfVxuICAgIHN0YXRpYyBHZXRUeXBlV2l0aFRhZ3MoZG9jVHlwZSwgLi4udGFncykge1xuICAgICAgICByZXR1cm4gQmxhZGVzQWN0b3IuQWxsLmZpbHRlcigoYWN0b3IpID0+IGFjdG9yLnR5cGUgPT09IGRvY1R5cGUpXG4gICAgICAgICAgICAuZmlsdGVyKChhY3RvcikgPT4gYWN0b3IuaGFzVGFnKC4uLnRhZ3MpKTtcbiAgICB9XG4gICAgc3RhdGljIElzVHlwZShkb2MsIC4uLnR5cGVzKSB7XG4gICAgICAgIGNvbnN0IHR5cGVTZXQgPSBuZXcgU2V0KHR5cGVzKTtcbiAgICAgICAgcmV0dXJuIGRvYyBpbnN0YW5jZW9mIEJsYWRlc0FjdG9yICYmIHR5cGVTZXQuaGFzKGRvYy50eXBlKTtcbiAgICB9XG4gICAgZ2V0IHRhZ3MoKSB7IHJldHVybiB0aGlzLnN5c3RlbS50YWdzID8/IFtdOyB9XG4gICAgaGFzVGFnKC4uLnRhZ3MpIHtcbiAgICAgICAgcmV0dXJuIHRhZ3MuZXZlcnkoKHRhZykgPT4gdGhpcy50YWdzLmluY2x1ZGVzKHRhZykpO1xuICAgIH1cbiAgICBhc3luYyBhZGRUYWcoLi4udGFncykge1xuICAgICAgICBjb25zdCBjdXJUYWdzID0gdGhpcy50YWdzO1xuICAgICAgICB0YWdzLmZvckVhY2goKHRhZykgPT4ge1xuICAgICAgICAgICAgaWYgKGN1clRhZ3MuaW5jbHVkZXModGFnKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGN1clRhZ3MucHVzaCh0YWcpO1xuICAgICAgICB9KTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJhY3RvclwiLCBcIkJsYWRlc0FjdG9yLmFkZFRhZyguLi50YWdzKVwiLCB7IHRhZ3MsIGN1clRhZ3MgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0udGFnc1wiOiBjdXJUYWdzIH0pO1xuICAgIH1cbiAgICBhc3luYyByZW1UYWcoLi4udGFncykge1xuICAgICAgICBjb25zdCBjdXJUYWdzID0gdGhpcy50YWdzLmZpbHRlcigodGFnKSA9PiAhdGFncy5pbmNsdWRlcyh0YWcpKTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJhY3RvclwiLCBcIkJsYWRlc0FjdG9yLnJlbVRhZyguLi50YWdzKVwiLCB7IHRhZ3MsIGN1clRhZ3MgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0udGFnc1wiOiBjdXJUYWdzIH0pO1xuICAgIH1cbiAgICBnZXQgdG9vbHRpcCgpIHtcbiAgICAgICAgY29uc3QgdG9vbHRpcFRleHQgPSBbdGhpcy5zeXN0ZW0uY29uY2VwdCwgdGhpcy5zeXN0ZW0uc3VidGl0bGVdXG4gICAgICAgICAgICAuZmlsdGVyKEJvb2xlYW4pXG4gICAgICAgICAgICAuam9pbihcIjxicj48YnI+XCIpO1xuICAgICAgICByZXR1cm4gdG9vbHRpcFRleHQgPyAobmV3IEhhbmRsZWJhcnMuU2FmZVN0cmluZyh0b29sdGlwVGV4dCkpLnRvU3RyaW5nKCkgOiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGdldCBkaWFsb2dDU1NDbGFzc2VzKCkgeyByZXR1cm4gXCJcIjsgfVxuICAgIGdldEZhY3RvclRvdGFsKGZhY3Rvcikge1xuICAgICAgICBzd2l0Y2ggKGZhY3Rvcikge1xuICAgICAgICAgICAgY2FzZSBGYWN0b3IudGllcjoge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zeXN0ZW0udGllci52YWx1ZSArICh0aGlzLmNyZXc/LmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSA/PyAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnRpZXIudmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5xdWFsaXR5OiByZXR1cm4gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcik7XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5zY2FsZToge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLm5wYykpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnNjYWxlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgRmFjdG9yLm1hZ25pdHVkZToge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLm5wYykpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLm1hZ25pdHVkZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBTdWJBY3RvckNvbnRyb2wgSW1wbGVtZW50YXRpb24gflxuICAgIGdldCBzdWJBY3RvcnMoKSB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyh0aGlzLnN5c3RlbS5zdWJhY3RvcnMpXG4gICAgICAgICAgICAubWFwKChpZCkgPT4gdGhpcy5nZXRTdWJBY3RvcihpZCkpXG4gICAgICAgICAgICAuZmlsdGVyKChzdWJBY3RvcikgPT4gQm9vbGVhbihzdWJBY3RvcikpO1xuICAgIH1cbiAgICBnZXQgYWN0aXZlU3ViQWN0b3JzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zdWJBY3RvcnMuZmlsdGVyKChzdWJBY3RvcikgPT4gIXN1YkFjdG9yLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKSk7XG4gICAgfVxuICAgIGdldCBhcmNoaXZlZFN1YkFjdG9ycygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3ViQWN0b3JzLmZpbHRlcigoc3ViQWN0b3IpID0+IHN1YkFjdG9yLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKSk7XG4gICAgfVxuICAgIGNoZWNrQWN0b3JQcmVyZXFzKGFjdG9yKSB7XG4gICAgICAgIC8qIEltcGxlbWVudCBhbnkgcHJlcmVxdWlzaXRlIGNoZWNrcyBmb3IgZW1iZWRkaW5nIGFjdG9ycyAqL1xuICAgICAgICByZXR1cm4gQm9vbGVhbihhY3Rvcik7XG4gICAgfVxuICAgIHByb2Nlc3NFbWJlZGRlZEFjdG9yTWF0Y2hlcyhnbG9iYWxBY3RvcnMpIHtcbiAgICAgICAgcmV0dXJuIGdsb2JhbEFjdG9yc1xuICAgICAgICAgICAgLy8gU3RlcCAxOiBGaWx0ZXIgb3V0IGdsb2JhbHMgdGhhdCBmYWlsIHByZXJlcXMuXG4gICAgICAgICAgICAuZmlsdGVyKHRoaXMuY2hlY2tBY3RvclByZXJlcXMpXG4gICAgICAgICAgICAvLyBTdGVwIDI6IEZpbHRlciBvdXQgYWN0b3JzIHRoYXQgYXJlIGFscmVhZHkgYWN0aXZlIHN1YkFjdG9yc1xuICAgICAgICAgICAgLmZpbHRlcigoZ0FjdG9yKSA9PiAhdGhpcy5hY3RpdmVTdWJBY3RvcnMuc29tZSgoYUFjdG9yKSA9PiBhQWN0b3IuaWQgPT09IGdBY3Rvci5pZCkpXG4gICAgICAgICAgICAvLyBTdGVwIDM6IE1lcmdlIHN1YmFjdG9yIGRhdGEgb250byBtYXRjaGluZyBnbG9iYWwgYWN0b3JzXG4gICAgICAgICAgICAubWFwKChnQWN0b3IpID0+IHRoaXMuZ2V0U3ViQWN0b3IoZ0FjdG9yKSB8fCBnQWN0b3IpXG4gICAgICAgICAgICAvLyBTdGVwIDQ6IFNvcnQgYnkgbmFtZVxuICAgICAgICAgICAgLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgICAgIGlmIChhLm5hbWUgPT09IGIubmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGEubmFtZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGIubmFtZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLm5hbWUgPiBiLm5hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLm5hbWUgPCBiLm5hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGdldERpYWxvZ0FjdG9ycyhjYXRlZ29yeSkge1xuICAgICAgICAvKiAqKioqIE5FRUQgVE8gRklMVEVSIE9VVCBBQ1RPUlMgUExBWUVSIERPRVNOJ1QgSEFWRSBQRVJNSVNTSU9OIFRPIFNFRSAqKioqICovXG4gICAgICAgIGNvbnN0IGRpYWxvZ0RhdGEgPSB7fTtcbiAgICAgICAgc3dpdGNoIChjYXRlZ29yeSkge1xuICAgICAgICAgICAgY2FzZSBTZWxlY3Rpb25DYXRlZ29yeS5Db250YWN0OlxuICAgICAgICAgICAgY2FzZSBTZWxlY3Rpb25DYXRlZ29yeS5SaXZhbDpcbiAgICAgICAgICAgIGNhc2UgU2VsZWN0aW9uQ2F0ZWdvcnkuRnJpZW5kOlxuICAgICAgICAgICAgY2FzZSBTZWxlY3Rpb25DYXRlZ29yeS5BY3F1YWludGFuY2U6IHtcbiAgICAgICAgICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KVxuICAgICAgICAgICAgICAgICAgICB8fCB0aGlzLnBsYXlib29rTmFtZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRpYWxvZ0RhdGEuTWFpbiA9IHRoaXMucHJvY2Vzc0VtYmVkZGVkQWN0b3JNYXRjaGVzKEJsYWRlc0FjdG9yLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUubnBjLCB0aGlzLnBsYXlib29rTmFtZSkpO1xuICAgICAgICAgICAgICAgIHJldHVybiBkaWFsb2dEYXRhO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBTZWxlY3Rpb25DYXRlZ29yeS5WaWNlUHVydmV5b3I6IHtcbiAgICAgICAgICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMpIHx8ICF0aGlzLnZpY2U/Lm5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkaWFsb2dEYXRhLk1haW4gPSB0aGlzLnByb2Nlc3NFbWJlZGRlZEFjdG9yTWF0Y2hlcyhCbGFkZXNBY3Rvci5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzQWN0b3JUeXBlLm5wYywgdGhpcy52aWNlLm5hbWUpKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZGlhbG9nRGF0YTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgU2VsZWN0aW9uQ2F0ZWdvcnkuQ3Jldzoge1xuICAgICAgICAgICAgICAgIGRpYWxvZ0RhdGEuTWFpbiA9IEJsYWRlc0FjdG9yLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUuY3Jldyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRpYWxvZ0RhdGE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgYWRkU3ViQWN0b3IoYWN0b3JSZWYsIHRhZ3MpIHtcbiAgICAgICAgbGV0IGZvY3VzU3ViQWN0b3I7XG4gICAgICAgIC8vIERvZXMgYW4gZW1iZWRkZWQgc3ViQWN0b3Igb2YgdGhpcyBBY3RvciBhbHJlYWR5IGV4aXN0IG9uIHRoZSBjaGFyYWN0ZXI/XG4gICAgICAgIGlmICh0aGlzLmhhc1N1YkFjdG9yT2YoYWN0b3JSZWYpKSB7XG4gICAgICAgICAgICBjb25zdCBzdWJBY3RvciA9IHRoaXMuZ2V0U3ViQWN0b3IoYWN0b3JSZWYpO1xuICAgICAgICAgICAgaWYgKCFzdWJBY3Rvcikge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIElzIGl0IGFuIGFyY2hpdmVkIEl0ZW0/XG4gICAgICAgICAgICBpZiAoc3ViQWN0b3IuaGFzVGFnKFRhZy5TeXN0ZW0uQXJjaGl2ZWQpKSB7XG4gICAgICAgICAgICAgICAgLy8gVW5hcmNoaXZlIGl0XG4gICAgICAgICAgICAgICAgYXdhaXQgc3ViQWN0b3IucmVtVGFnKFRhZy5TeXN0ZW0uQXJjaGl2ZWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gTWFrZSBpdCB0aGUgZm9jdXMgaXRlbS5cbiAgICAgICAgICAgIGZvY3VzU3ViQWN0b3IgPSBzdWJBY3RvcjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIElzIGl0IG5vdCBlbWJlZGRlZCBhdCBhbGw/IENyZWF0ZSBuZXcgZW50cnkgaW4gc3lzdGVtLnN1YmFjdG9ycyBmcm9tIGdsb2JhbCBhY3RvclxuICAgICAgICAgICAgY29uc3QgYWN0b3IgPSBCbGFkZXNBY3Rvci5HZXQoYWN0b3JSZWYpO1xuICAgICAgICAgICAgaWYgKCFhY3Rvcikge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHN1YkFjdG9yRGF0YSA9IHt9O1xuICAgICAgICAgICAgaWYgKHRhZ3MpIHtcbiAgICAgICAgICAgICAgICBzdWJBY3RvckRhdGEudGFncyA9IFUudW5pcXVlKFtcbiAgICAgICAgICAgICAgICAgICAgLi4uYWN0b3IudGFncyxcbiAgICAgICAgICAgICAgICAgICAgLi4udGFnc1xuICAgICAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQXdhaXQgdGhlIHVwZGF0ZSwgdGhlbiBtYWtlIHRoZSByZXRyaWV2ZWQgc3ViYWN0b3IgdGhlIGZvY3VzXG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZSh7IFtgc3lzdGVtLnN1YmFjdG9ycy4ke2FjdG9yLmlkfWBdOiBzdWJBY3RvckRhdGEgfSk7XG4gICAgICAgICAgICBmb2N1c1N1YkFjdG9yID0gdGhpcy5nZXRTdWJBY3RvcihhY3Rvci5pZCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFmb2N1c1N1YkFjdG9yKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gRG9lcyB0aGlzIEFjdG9yIGNvbnRhaW4gYW55IHRhZ3MgbGltaXRpbmcgaXQgdG8gb25lIHBlciBhY3Rvcj9cbiAgICAgICAgY29uc3QgdW5pcXVlVGFncyA9IGZvY3VzU3ViQWN0b3IudGFncy5maWx0ZXIoKHRhZykgPT4gdGFnIGluIEJsYWRlc0FjdG9yVW5pcXVlVGFncyk7XG4gICAgICAgIGlmICh1bmlxdWVUYWdzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIC8vIC4uLiB0aGVuIGFyY2hpdmUgYWxsIG90aGVyIHZlcnNpb25zLlxuICAgICAgICAgICAgdW5pcXVlVGFncy5mb3JFYWNoKCh1VGFnKSA9PiB0aGlzLmFjdGl2ZVN1YkFjdG9yc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHN1YkFjdG9yKSA9PiBCb29sZWFuKGZvY3VzU3ViQWN0b3I/LmlkXG4gICAgICAgICAgICAgICAgJiYgc3ViQWN0b3IuaWQgIT09IGZvY3VzU3ViQWN0b3IuaWRcbiAgICAgICAgICAgICAgICAmJiBzdWJBY3Rvci5oYXNUYWcodVRhZykpKVxuICAgICAgICAgICAgICAgIC5tYXAoKHN1YkFjdG9yKSA9PiB0aGlzLnJlbVN1YkFjdG9yKHN1YkFjdG9yLmlkKSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldFN1YkFjdG9yKGFjdG9yUmVmKSB7XG4gICAgICAgIGNvbnN0IGFjdG9yID0gQmxhZGVzQWN0b3IuR2V0KGFjdG9yUmVmKTtcbiAgICAgICAgaWYgKCFhY3Rvcj8uaWQpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUoYWN0b3IsIEJsYWRlc0FjdG9yVHlwZS5ucGMsIEJsYWRlc0FjdG9yVHlwZS5mYWN0aW9uKSkge1xuICAgICAgICAgICAgcmV0dXJuIGFjdG9yO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHN1YkFjdG9yRGF0YSA9ICh0aGlzLnN5c3RlbS5zdWJhY3RvcnNbYWN0b3IuaWRdID8/IHt9KTtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihhY3Rvci5zeXN0ZW0sIHN1YkFjdG9yRGF0YSk7XG4gICAgICAgIGFjdG9yLnBhcmVudEFjdG9yID0gdGhpcztcbiAgICAgICAgcmV0dXJuIGFjdG9yO1xuICAgIH1cbiAgICBoYXNTdWJBY3Rvck9mKGFjdG9yUmVmKSB7XG4gICAgICAgIGNvbnN0IGFjdG9yID0gQmxhZGVzQWN0b3IuR2V0KGFjdG9yUmVmKTtcbiAgICAgICAgaWYgKCFhY3Rvcikge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhY3Rvcj8uaWQgPyBhY3Rvci5pZCBpbiB0aGlzLnN5c3RlbS5zdWJhY3RvcnMgOiBmYWxzZTtcbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlU3ViQWN0b3IoYWN0b3JSZWYsIHVwRGF0YSkge1xuICAgICAgICBjb25zdCB1cGRhdGVEYXRhID0gVS5vYmpFeHBhbmQodXBEYXRhKTtcbiAgICAgICAgaWYgKCF1cGRhdGVEYXRhLnN5c3RlbSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhY3RvciA9IEJsYWRlc0FjdG9yLkdldChhY3RvclJlZik7XG4gICAgICAgIGlmICghYWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gRGlmZk9iamVjdCBuZXcgdXBkYXRlIGRhdGEgYWdhaW5zdCBhY3RvciBkYXRhLlxuICAgICAgICBjb25zdCBkaWZmVXBkYXRlU3lzdGVtID0gVS5vYmpEaWZmKGFjdG9yLnN5c3RlbSwgdXBkYXRlRGF0YS5zeXN0ZW0pO1xuICAgICAgICAvLyBNZXJnZSBuZXcgdXBkYXRlIGRhdGEgb250byBjdXJyZW50IHN1YmFjdG9yIGRhdGEuXG4gICAgICAgIGNvbnN0IG1lcmdlZFN1YkFjdG9yU3lzdGVtID0gVS5vYmpNZXJnZSh0aGlzLnN5c3RlbS5zdWJhY3RvcnNbYWN0b3IuaWRdID8/IHt9LCBkaWZmVXBkYXRlU3lzdGVtLCB7IGlzUmVwbGFjaW5nQXJyYXlzOiB0cnVlLCBpc0NvbmNhdGVuYXRpbmdBcnJheXM6IGZhbHNlIH0pO1xuICAgICAgICAvLyBDb25maXJtIHRoaXMgdXBkYXRlIGNoYW5nZXMgZGF0YTpcbiAgICAgICAgaWYgKEpTT04uc3RyaW5naWZ5KHRoaXMuc3lzdGVtLnN1YmFjdG9yc1thY3Rvci5pZF0pID09PSBKU09OLnN0cmluZ2lmeShtZXJnZWRTdWJBY3RvclN5c3RlbSkpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVXBkYXRlIGFjdG9yIHdpdGggbmV3IHN1YmFjdG9yIGRhdGEuXG4gICAgICAgIHJldHVybiB0aGlzLnVwZGF0ZSh7IFtgc3lzdGVtLnN1YmFjdG9ycy4ke2FjdG9yLmlkfWBdOiBudWxsIH0sIHVuZGVmaW5lZCwgdHJ1ZSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHRoaXMudXBkYXRlKHsgW2BzeXN0ZW0uc3ViYWN0b3JzLiR7YWN0b3IuaWR9YF06IG1lcmdlZFN1YkFjdG9yU3lzdGVtIH0sIHVuZGVmaW5lZCwgdHJ1ZSkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiBhY3Rvci5zaGVldD8ucmVuZGVyKCkpO1xuICAgIH1cbiAgICBhc3luYyByZW1TdWJBY3RvcihhY3RvclJlZikge1xuICAgICAgICBjb25zdCBzdWJBY3RvciA9IHRoaXMuZ2V0U3ViQWN0b3IoYWN0b3JSZWYpO1xuICAgICAgICBpZiAoIXN1YkFjdG9yKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBcInN5c3RlbS5zdWJhY3RvcnNcIjogbWVyZ2VPYmplY3QodGhpcy5zeXN0ZW0uc3ViYWN0b3JzLCB7IFtgLT0ke3N1YkFjdG9yLmlkfWBdOiBudWxsIH0pIH0sIHVuZGVmaW5lZCwgdHJ1ZSk7XG4gICAgfVxuICAgIGFzeW5jIGNsZWFyU3ViQWN0b3JzKGlzUmVSZW5kZXJpbmcgPSB0cnVlKSB7XG4gICAgICAgIHRoaXMuc3ViQWN0b3JzLmZvckVhY2goKHN1YkFjdG9yKSA9PiB7XG4gICAgICAgICAgICBpZiAoc3ViQWN0b3IucGFyZW50QWN0b3I/LmlkID09PSB0aGlzLmlkKSB7XG4gICAgICAgICAgICAgICAgc3ViQWN0b3IuY2xlYXJQYXJlbnRBY3Rvcihpc1JlUmVuZGVyaW5nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMuc2hlZXQ/LnJlbmRlcigpO1xuICAgIH1cbiAgICBhc3luYyBjbGVhclBhcmVudEFjdG9yKGlzUmVSZW5kZXJpbmcgPSB0cnVlKSB7XG4gICAgICAgIGNvbnN0IHsgcGFyZW50QWN0b3IgfSA9IHRoaXM7XG4gICAgICAgIGlmICghcGFyZW50QWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnBhcmVudEFjdG9yID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLnN5c3RlbSA9IHRoaXMuX3NvdXJjZS5zeXN0ZW07XG4gICAgICAgIHRoaXMub3duZXJzaGlwID0gdGhpcy5fc291cmNlLm93bmVyc2hpcDtcbiAgICAgICAgdGhpcy5wcmVwYXJlRGF0YSgpO1xuICAgICAgICBpZiAoaXNSZVJlbmRlcmluZykge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5zaGVldD8ucmVuZGVyKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gU3ViSXRlbUNvbnRyb2wgSW1wbGVtZW50YXRpb24gflxuICAgIGdldCBzdWJJdGVtcygpIHsgcmV0dXJuIEFycmF5LmZyb20odGhpcy5pdGVtcyk7IH1cbiAgICBnZXRTdWJJdGVtc09mVHlwZShpdGVtVHlwZSkge1xuICAgICAgICByZXR1cm4gdGhpcy5pdGVtcy5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gaXRlbVR5cGUpO1xuICAgIH1cbiAgICBnZXQgYWN0aXZlU3ViSXRlbXMoKSB7IHJldHVybiB0aGlzLml0ZW1zLmZpbHRlcigoaXRlbSkgPT4gIWl0ZW0uaGFzVGFnKFRhZy5TeXN0ZW0uQXJjaGl2ZWQpKTsgfVxuICAgIGdldCBhcmNoaXZlZFN1Ykl0ZW1zKCkgeyByZXR1cm4gdGhpcy5pdGVtcy5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0uaGFzVGFnKFRhZy5TeXN0ZW0uQXJjaGl2ZWQpKTsgfVxuICAgIF9jaGVja0l0ZW1QcmVyZXFzKGl0ZW0pIHtcbiAgICAgICAgaWYgKCFpdGVtLnN5c3RlbS5wcmVyZXFzKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGNvbnN0IFtwVHlwZSwgcFJlcXNdIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW0uc3lzdGVtLnByZXJlcXMpKSB7XG4gICAgICAgICAgICBjb25zdCBwUmVxQXJyYXkgPSBBcnJheS5pc0FycmF5KHBSZXFzKSA/IHBSZXFzIDogW3BSZXFzLnRvU3RyaW5nKCldO1xuICAgICAgICAgICAgY29uc3QgaGl0UmVjb3JkID0ge307XG4gICAgICAgICAgICBpZiAoIXRoaXMuX3Byb2Nlc3NQcmVyZXFBcnJheShwUmVxQXJyYXksIHBUeXBlLCBoaXRSZWNvcmQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBfcHJvY2Vzc1ByZXJlcUFycmF5KHBSZXFBcnJheSwgcFR5cGUsIGhpdFJlY29yZCkge1xuICAgICAgICB3aGlsZSAocFJlcUFycmF5Lmxlbmd0aCkge1xuICAgICAgICAgICAgY29uc3QgcFN0cmluZyA9IHBSZXFBcnJheS5wb3AoKTtcbiAgICAgICAgICAgIGhpdFJlY29yZFtwVHlwZV0gPz89IFtdO1xuICAgICAgICAgICAgaWYgKCF0aGlzLl9wcm9jZXNzUHJlcmVxVHlwZShwVHlwZSwgcFN0cmluZywgaGl0UmVjb3JkKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgX3Byb2Nlc3NQcmVyZXFUeXBlKHBUeXBlLCBwU3RyaW5nLCBoaXRSZWNvcmQpIHtcbiAgICAgICAgc3dpdGNoIChwVHlwZSkge1xuICAgICAgICAgICAgY2FzZSBQcmVyZXFUeXBlLkhhc0FjdGl2ZUl0ZW06IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcHJvY2Vzc0FjdGl2ZUl0ZW1QcmVyZXEocFN0cmluZywgaGl0UmVjb3JkLCBwVHlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFByZXJlcVR5cGUuSGFzQWN0aXZlSXRlbXNCeVRhZzoge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9wcm9jZXNzQWN0aXZlSXRlbXNCeVRhZ1ByZXJlcShwU3RyaW5nLCBoaXRSZWNvcmQsIHBUeXBlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgUHJlcmVxVHlwZS5BZHZhbmNlZFBsYXlib29rOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3Byb2Nlc3NBZHZhbmNlZFBsYXlib29rUHJlcmVxKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBfcHJvY2Vzc0FjdGl2ZUl0ZW1QcmVyZXEocFN0cmluZywgaGl0UmVjb3JkLCBwVHlwZSkge1xuICAgICAgICBjb25zdCB0aGlzSXRlbSA9IHRoaXMuYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgIC5maWx0ZXIoKGkpID0+ICFoaXRSZWNvcmRbcFR5cGVdPy5pbmNsdWRlcyhpLmlkKSlcbiAgICAgICAgICAgIC5maW5kKChpKSA9PiBpLnN5c3RlbS53b3JsZF9uYW1lID09PSBwU3RyaW5nKTtcbiAgICAgICAgaWYgKHRoaXNJdGVtKSB7XG4gICAgICAgICAgICBoaXRSZWNvcmRbcFR5cGVdPy5wdXNoKHRoaXNJdGVtLmlkKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIF9wcm9jZXNzQWN0aXZlSXRlbXNCeVRhZ1ByZXJlcShwU3RyaW5nLCBoaXRSZWNvcmQsIHBUeXBlKSB7XG4gICAgICAgIGNvbnN0IHRoaXNJdGVtID0gdGhpcy5hY3RpdmVTdWJJdGVtc1xuICAgICAgICAgICAgLmZpbHRlcigoaSkgPT4gIWhpdFJlY29yZFtwVHlwZV0/LmluY2x1ZGVzKGkuaWQpKVxuICAgICAgICAgICAgLmZpbmQoKGkpID0+IGkuaGFzVGFnKHBTdHJpbmcpKTtcbiAgICAgICAgaWYgKHRoaXNJdGVtKSB7XG4gICAgICAgICAgICBoaXRSZWNvcmRbcFR5cGVdPy5wdXNoKHRoaXNJdGVtLmlkKTtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIF9wcm9jZXNzQWR2YW5jZWRQbGF5Ym9va1ByZXJlcSgpIHtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5wbGF5Ym9va05hbWUgfHwgIVtQbGF5Ym9vay5HaG9zdCwgUGxheWJvb2suSHVsbCwgUGxheWJvb2suVmFtcGlyZV0uaW5jbHVkZXModGhpcy5wbGF5Ym9va05hbWUpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIF9wcm9jZXNzRW1iZWRkZWRJdGVtTWF0Y2hlcyhnbG9iYWxJdGVtcykge1xuICAgICAgICByZXR1cm4gZ2xvYmFsSXRlbXNcbiAgICAgICAgICAgIC8vIFN0ZXAgMTogRmlsdGVyIG91dCBnbG9iYWxzIHRoYXQgZmFpbCBwcmVyZXFzLlxuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gdGhpcy5fY2hlY2tJdGVtUHJlcmVxcyhpdGVtKSlcbiAgICAgICAgICAgIC8vIFN0ZXAgMjogRmlsdGVyIG91dCBhbHJlYWR5LWFjdGl2ZSBpdGVtcyBiYXNlZCBvbiBtYXhfcGVyX3Njb3JlICh1bmxlc3MgTXVsdGlwbGVzT2spXG4gICAgICAgICAgICAuZmlsdGVyKChnSXRlbSkgPT4gZ0l0ZW0uaGFzVGFnKFRhZy5TeXN0ZW0uTXVsdGlwbGVzT0spXG4gICAgICAgICAgICB8fCAoZ0l0ZW0uc3lzdGVtLm1heF9wZXJfc2NvcmUgPz8gMSlcbiAgICAgICAgICAgICAgICA+IHRoaXMuYWN0aXZlU3ViSXRlbXMuZmlsdGVyKChzSXRlbSkgPT4gc0l0ZW0uc3lzdGVtLndvcmxkX25hbWUgPT09IGdJdGVtLnN5c3RlbS53b3JsZF9uYW1lKS5sZW5ndGgpXG4gICAgICAgICAgICAvLyBTdGVwIDM6IFJlcGxhY2Ugd2l0aCBtYXRjaGluZyBBcmNoaXZlZCwgRW1iZWRkZWQgc3ViSXRlbXNcbiAgICAgICAgICAgIC5tYXAoKGdJdGVtKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBtYXRjaGluZ1N1Ykl0ZW1zID0gdGhpcy5hcmNoaXZlZFN1Ykl0ZW1zLmZpbHRlcigoc0l0ZW0pID0+IHNJdGVtLnN5c3RlbS53b3JsZF9uYW1lID09PSBnSXRlbS5zeXN0ZW0ud29ybGRfbmFtZSk7XG4gICAgICAgICAgICBpZiAobWF0Y2hpbmdTdWJJdGVtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1hdGNoaW5nU3ViSXRlbXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZ0l0ZW07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICAgICAgICAuZmxhdCgpXG4gICAgICAgICAgICAvLyBTdGVwIDQ6IEFwcGx5IENTUyBjbGFzc2VzXG4gICAgICAgICAgICAubWFwKChzSXRlbSkgPT4ge1xuICAgICAgICAgICAgc0l0ZW0uZGlhbG9nQ1NTQ2xhc3NlcyA9IFwiXCI7XG4gICAgICAgICAgICBjb25zdCBjc3NDbGFzc2VzID0gW107XG4gICAgICAgICAgICBpZiAoc0l0ZW0uaXNFbWJlZGRlZCkge1xuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXMucHVzaChcImVtYmVkZGVkXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHNJdGVtLmhhc1RhZyhUYWcuR2Vhci5GaW5lKSkge1xuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXMucHVzaChcImZpbmUtcXVhbGl0eVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzSXRlbS5oYXNUYWcoVGFnLlN5c3RlbS5GZWF0dXJlZCkpIHtcbiAgICAgICAgICAgICAgICBjc3NDbGFzc2VzLnB1c2goXCJmZWF0dXJlZC1pdGVtXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKFtCbGFkZXNJdGVtVHlwZS5hYmlsaXR5LCBCbGFkZXNJdGVtVHlwZS5jcmV3X2FiaWxpdHldLmluY2x1ZGVzKHNJdGVtLnR5cGUpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZ2V0QXZhaWxhYmxlQWR2YW5jZW1lbnRzKFwiQWJpbGl0eVwiKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBjc3NDbGFzc2VzLnB1c2goXCJsb2NrZWRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKChzSXRlbS5zeXN0ZW0ucHJpY2UgPz8gMSkgPiB0aGlzLmdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyhcIkFiaWxpdHlcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgY3NzQ2xhc3Nlcy5wdXNoKFwibG9ja2VkXCIsIFwidW5hZmZvcmRhYmxlXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmICgoc0l0ZW0uc3lzdGVtLnByaWNlID8/IDEpID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBjc3NDbGFzc2VzLnB1c2goXCJleHBlbnNpdmVcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKFtCbGFkZXNJdGVtVHlwZS5jcmV3X3VwZ3JhZGVdLmluY2x1ZGVzKHNJdGVtLnR5cGUpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZ2V0QXZhaWxhYmxlQWR2YW5jZW1lbnRzKFwiVXBncmFkZVwiKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICBjc3NDbGFzc2VzLnB1c2goXCJsb2NrZWRcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKChzSXRlbS5zeXN0ZW0ucHJpY2UgPz8gMSkgPiB0aGlzLmdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyhcIlVwZ3JhZGVcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgY3NzQ2xhc3Nlcy5wdXNoKFwibG9ja2VkXCIsIFwidW5hZmZvcmRhYmxlXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmICgoc0l0ZW0uc3lzdGVtLnByaWNlID8/IDEpID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBjc3NDbGFzc2VzLnB1c2goXCJleHBlbnNpdmVcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGNzc0NsYXNzZXMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHNJdGVtLmRpYWxvZ0NTU0NsYXNzZXMgPSBjc3NDbGFzc2VzLmpvaW4oXCIgXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHNJdGVtO1xuICAgICAgICB9KVxuICAgICAgICAgICAgLy8gU3RlcCA1OiBTb3J0IGJ5IGZlYXR1cmVkLCB0aGVuIGJ5IGZpbmUsIHRoZW4gYnkgd29ybGRfbmFtZSwgdGhlbiBlbWJlZGRlZCBmaXJzdCBzb3J0ZWQgYnkgbmFtZVxuICAgICAgICAgICAgLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgICAgIGlmIChhLmhhc1RhZyhUYWcuU3lzdGVtLkZlYXR1cmVkKSAmJiAhYi5oYXNUYWcoVGFnLlN5c3RlbS5GZWF0dXJlZCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWEuaGFzVGFnKFRhZy5TeXN0ZW0uRmVhdHVyZWQpICYmIGIuaGFzVGFnKFRhZy5TeXN0ZW0uRmVhdHVyZWQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYS5oYXNUYWcoVGFnLkdlYXIuRmluZSkgJiYgIWIuaGFzVGFnKFRhZy5HZWFyLkZpbmUpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFhLmhhc1RhZyhUYWcuR2Vhci5GaW5lKSAmJiBiLmhhc1RhZyhUYWcuR2Vhci5GaW5lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGEuc3lzdGVtLndvcmxkX25hbWUgPiBiLnN5c3RlbS53b3JsZF9uYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYS5zeXN0ZW0ud29ybGRfbmFtZSA8IGIuc3lzdGVtLndvcmxkX25hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYS5pc0VtYmVkZGVkICYmICFiLmlzRW1iZWRkZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWEuaXNFbWJlZGRlZCAmJiBiLmlzRW1iZWRkZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLm5hbWUgPT09IGIubmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGEubmFtZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGIubmFtZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLm5hbWUgPiBiLm5hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLm5hbWUgPCBiLm5hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGdldFN1Ykl0ZW0oaXRlbVJlZiwgYWN0aXZlT25seSA9IGZhbHNlKSB7XG4gICAgICAgIGNvbnN0IGFjdGl2ZUNoZWNrID0gKGkpID0+ICFhY3RpdmVPbmx5IHx8ICFpLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKTtcbiAgICAgICAgaWYgKHR5cGVvZiBpdGVtUmVmID09PSBcInN0cmluZ1wiICYmIHRoaXMuaXRlbXMuZ2V0KGl0ZW1SZWYpKSB7XG4gICAgICAgICAgICBjb25zdCByZXR1cm5JdGVtID0gdGhpcy5pdGVtcy5nZXQoaXRlbVJlZik7XG4gICAgICAgICAgICBpZiAocmV0dXJuSXRlbSAmJiBhY3RpdmVDaGVjayhyZXR1cm5JdGVtKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiByZXR1cm5JdGVtO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGNvbnN0IGdsb2JhbEl0ZW0gPSBCbGFkZXNJdGVtLkdldChpdGVtUmVmKTtcbiAgICAgICAgICAgIGlmICghZ2xvYmFsSXRlbSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5pdGVtcy5maW5kKChpdGVtKSA9PiBpdGVtLm5hbWUgPT09IGdsb2JhbEl0ZW0ubmFtZSAmJiBhY3RpdmVDaGVjayhpdGVtKSlcbiAgICAgICAgICAgICAgICA/PyB0aGlzLml0ZW1zLmZpbmQoKGl0ZW0pID0+IGl0ZW0uc3lzdGVtLndvcmxkX25hbWUgPT09IGdsb2JhbEl0ZW0uc3lzdGVtLndvcmxkX25hbWUgJiYgYWN0aXZlQ2hlY2soaXRlbSkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGhhc1N1Ykl0ZW1PZihpdGVtUmVmKSB7XG4gICAgICAgIGNvbnN0IGl0ZW0gPSBCbGFkZXNJdGVtLkdldChpdGVtUmVmKTtcbiAgICAgICAgaWYgKCFpdGVtKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5pdGVtcy5maW5kKChpKSA9PiBpLnN5c3RlbS53b3JsZF9uYW1lID09PSBpdGVtLnN5c3RlbS53b3JsZF9uYW1lKSk7XG4gICAgfVxuICAgIGhhc0FjdGl2ZVN1Ykl0ZW1PZihpdGVtUmVmKSB7XG4gICAgICAgIGNvbnN0IGl0ZW0gPSBCbGFkZXNJdGVtLkdldChpdGVtUmVmKTtcbiAgICAgICAgaWYgKCFpdGVtKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5pdGVtcy5maW5kKChpKSA9PiAhaS5oYXNUYWcoVGFnLlN5c3RlbS5BcmNoaXZlZClcbiAgICAgICAgICAgICYmIGkuc3lzdGVtLndvcmxkX25hbWUgPT09IGl0ZW0uc3lzdGVtLndvcmxkX25hbWUpKTtcbiAgICB9XG4gICAgYXN5bmMgYWRkU3ViSXRlbShpdGVtUmVmKSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBEZXRlcm1pbmVzIHdoZXRoZXIgYSBzdWJtaXR0ZWQgQmxhZGVzSXRlbVR5cGUgaXMgYSB0eXBlIHRoYXQgc2hvdWxkIGFwcGVhciBvbmx5IG9uY2VcbiAgICAgICAgICogb24gYW55IGdpdmVuIEFjdG9yLlxuICAgICAgICAgKiBAcGFyYW0ge0JsYWRlc0l0ZW1UeXBlfSB0eXBlXG4gICAgICAgICAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB0eXBlIGlzIGEgQmxhZGVzSXRlbVVuaXF1ZVR5cGVzXG4gICAgICAgICAqKi9cbiAgICAgICAgZnVuY3Rpb24gaXNCbGFkZXNJdGVtVW5pcXVlVHlwZXModHlwZSkge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoQmxhZGVzSXRlbVVuaXF1ZVR5cGVzKS5pbmNsdWRlcyh0eXBlKTtcbiAgICAgICAgfVxuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcInN1Yml0ZW1zXCIsIFwiW2FkZFN1Ykl0ZW1dIGl0ZW1SZWZcIiwgaXRlbVJlZik7XG4gICAgICAgIGxldCBmb2N1c0l0ZW07XG4gICAgICAgIC8vIERvZXMgYW4gZW1iZWRkZWQgY29weSBvZiB0aGlzIGl0ZW0gYWxyZWFkeSBleGlzdCBvbiB0aGUgY2hhcmFjdGVyP1xuICAgICAgICBjb25zdCBlbWJlZGRlZEl0ZW0gPSB0aGlzLmdldFN1Ykl0ZW0oaXRlbVJlZik7XG4gICAgICAgIGlmIChlbWJlZGRlZEl0ZW0pIHtcbiAgICAgICAgICAgIC8vIElzIGl0IGFuIGFyY2hpdmVkIEl0ZW0/XG4gICAgICAgICAgICBpZiAoZW1iZWRkZWRJdGVtLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKSkge1xuICAgICAgICAgICAgICAgIC8vIFVuYXJjaGl2ZSBpdCAmIG1ha2UgaXQgdGhlIGZvY3VzIGl0ZW0uXG4gICAgICAgICAgICAgICAgYXdhaXQgZW1iZWRkZWRJdGVtLnJlbVRhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKTtcbiAgICAgICAgICAgICAgICBmb2N1c0l0ZW0gPSBlbWJlZGRlZEl0ZW07XG4gICAgICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJzdWJpdGVtc1wiLCBgW2FkZFN1Ykl0ZW1dIElTIEFSQ0hJVkVEIEVNQkVEREVEID4gUmVtb3ZpbmcgJ0FyY2hpdmVkJyBUYWcsICcke2ZvY3VzSXRlbS5pZH0nOmAsIGZvY3VzSXRlbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHsgLy8gT3RoZXJ3aXNlLi4uXG4gICAgICAgICAgICAgICAgLy8gRHVwbGljYXRlIHRoZSBpdGVtLCBhbmQgbWFrZSB0aGUgbmV3bHktY3JlYXRlZCBpdGVtIHRoZSBmb2N1cy5cbiAgICAgICAgICAgICAgICBmb2N1c0l0ZW0gPSBhd2FpdCBCbGFkZXNJdGVtLmNyZWF0ZShbZW1iZWRkZWRJdGVtXSwgeyBwYXJlbnQ6IHRoaXMgfSk7XG4gICAgICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJzdWJpdGVtc1wiLCBgW2FkZFN1Ykl0ZW1dIElTIEFDVElWRSBFTUJFRERFRCA+IER1cGxpY2F0aW5nLCBmb2N1c0l0ZW0gJyR7Zm9jdXNJdGVtLmlkfSc6YCwgZm9jdXNJdGVtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIElzIGl0IG5vdCBlbWJlZGRlZCBhdCBhbGw/IEVtYmVkIGZyb20gZ2xvYmFsIGluc3RhbmNlLlxuICAgICAgICAgICAgY29uc3QgZ2xvYmFsSXRlbSA9IEJsYWRlc0l0ZW0uR2V0KGl0ZW1SZWYpO1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJzdWJpdGVtc1wiLCBgW2FkZFN1Ykl0ZW1dIElTIE5PVCBFTUJFRERFRCA+IEZldGNoaW5nIEdsb2JhbCwgZ2xvYmFsSXRlbSAnJHtnbG9iYWxJdGVtPy5pZH0nOmAsIGdsb2JhbEl0ZW0pO1xuICAgICAgICAgICAgaWYgKCFnbG9iYWxJdGVtKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9jdXNJdGVtID0gYXdhaXQgQmxhZGVzSXRlbS5jcmVhdGUoW2dsb2JhbEl0ZW1dLCB7IHBhcmVudDogdGhpcyB9KTtcbiAgICAgICAgICAgIGZvY3VzSXRlbSA9IHRoaXMuaXRlbXMuZ2V0TmFtZShnbG9iYWxJdGVtLm5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIC8vIElzIHRoaXMgaXRlbSB0eXBlIGxpbWl0ZWQgdG8gb25lIHBlciBhY3Rvcj9cbiAgICAgICAgaWYgKGZvY3VzSXRlbSAmJiBpc0JsYWRlc0l0ZW1VbmlxdWVUeXBlcyhmb2N1c0l0ZW0udHlwZSkpIHtcbiAgICAgICAgICAgIC8vIC4uLiB0aGVuIGFyY2hpdmUgYWxsIG90aGVyIHZlcnNpb25zLlxuICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwodGhpcy5hY3RpdmVTdWJJdGVtc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHN1Ykl0ZW0pID0+IHN1Ykl0ZW0udHlwZSA9PT0gZm9jdXNJdGVtPy50eXBlXG4gICAgICAgICAgICAgICAgJiYgc3ViSXRlbS5zeXN0ZW0ud29ybGRfbmFtZSAhPT0gZm9jdXNJdGVtPy5zeXN0ZW0ud29ybGRfbmFtZVxuICAgICAgICAgICAgICAgICYmICFzdWJJdGVtLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKSlcbiAgICAgICAgICAgICAgICAubWFwKHRoaXMucmVtU3ViSXRlbS5iaW5kKHRoaXMpKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgcmVtU3ViSXRlbShpdGVtUmVmKSB7XG4gICAgICAgIGNvbnN0IHN1Ykl0ZW0gPSB0aGlzLmdldFN1Ykl0ZW0oaXRlbVJlZik7XG4gICAgICAgIGlmICghc3ViSXRlbSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdWJJdGVtLnR5cGUgIT09IEJsYWRlc0l0ZW1UeXBlLmdlYXIpIHtcbiAgICAgICAgICAgIHRoaXMucHVyZ2VTdWJJdGVtKGl0ZW1SZWYpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RvclRyaWdnZXJcIiwgYFJlbW92aW5nIFN1Ykl0ZW0gJHtzdWJJdGVtLm5hbWV9YCwgc3ViSXRlbSk7XG4gICAgICAgIGlmIChzdWJJdGVtLmhhc1RhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHN1Ykl0ZW0uYWRkVGFnKFRhZy5TeXN0ZW0uQXJjaGl2ZWQpO1xuICAgIH1cbiAgICBhc3luYyBwdXJnZVN1Ykl0ZW0oaXRlbVJlZikge1xuICAgICAgICBjb25zdCBzdWJJdGVtID0gdGhpcy5nZXRTdWJJdGVtKGl0ZW1SZWYpO1xuICAgICAgICBpZiAoIXN1Ykl0ZW0gfHwgc3ViSXRlbS5oYXNUYWcoVGFnLlN5c3RlbS5BcmNoaXZlZCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBzdWJJdGVtLmRlbGV0ZSgpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBBZHZhbmNlbWVudCBJbXBsZW1lbnRhdGlvbiB+XG4gICAgLy8gZ2V0IHRvdGFsQWJpbGl0eVBvaW50cygpOiBudW1iZXIge1xuICAgIC8vICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjLCBCbGFkZXNBY3RvclR5cGUuY3JldykpIHsgcmV0dXJuIDAgfVxuICAgIC8vICAgaWYgKCF0aGlzLnBsYXlib29rKSB7IHJldHVybiAwIH1cbiAgICAvLyAgIHN3aXRjaCAodGhpcy50eXBlKSB7XG4gICAgLy8gICAgIGNhc2UgQmxhZGVzQWN0b3JUeXBlLnBjOiByZXR1cm4gdGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnQuYWJpbGl0eSA/PyAwO1xuICAgIC8vICAgICBjYXNlIEJsYWRlc0FjdG9yVHlwZS5jcmV3OiByZXR1cm4gTWF0aC5mbG9vcigwLjUgKiAodGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnQuZ2VuZXJhbCA/PyAwKSlcbiAgICAvLyAgICAgICsgKHRoaXMuc3lzdGVtLmFkdmFuY2VtZW50LmFiaWxpdHkgPz8gMCk7XG4gICAgLy8gICAgIGRlZmF1bHQ6IHJldHVybiAwO1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyBnZXQgc3BlbnRBYmlsaXR5UG9pbnRzKCk6IG51bWJlciB7XG4gICAgLy8gICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSkgeyByZXR1cm4gMCB9XG4gICAgLy8gICBpZiAoIXRoaXMucGxheWJvb2spIHsgcmV0dXJuIDAgfVxuICAgIC8vICAgcmV0dXJuIHRoaXMuYWJpbGl0aWVzLnJlZHVjZSgodG90YWwsIGFiaWxpdHkpID0+IHRvdGFsICsgKGFiaWxpdHkuc3lzdGVtLnByaWNlID8/IDEpLCAwKTtcbiAgICAvLyB9XG4gICAgLy8gZ2V0IGdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyhcIkFiaWxpdHlcIikoKTogbnVtYmVyIHtcbiAgICAvLyAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5wYywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpKSB7IHJldHVybiAwIH1cbiAgICAvLyAgIGlmICghdGhpcy5wbGF5Ym9vaykgeyByZXR1cm4gMCB9XG4gICAgLy8gICByZXR1cm4gdGhpcy50b3RhbEFiaWxpdHlQb2ludHMgLSB0aGlzLnNwZW50QWJpbGl0eVBvaW50cztcbiAgICAvLyB9XG4gICAgLyogTmVlZCBzaW1wbGUgZ2V0dGVycyBmb3IgdG90YWwgYWJpbGl0eSAmIHVwZ3JhZGUgcG9pbnRzIHRoYXQgY2hlY2sgZm9yIFBSSUNFUyBvZiBpdGVtc1xuICAgICAgICAgICh1cGdyYWRlLnN5c3RlbS5wcmljZSA/PyAxKSAqL1xuICAgIGFzeW5jIGdyYW50QWR2YW5jZW1lbnRQb2ludHMoYWxsb3dlZFR5cGVzLCBhbW91bnQgPSAxKSB7XG4gICAgICAgIGNvbnN0IGFQdEtleSA9IEFycmF5LmlzQXJyYXkoYWxsb3dlZFR5cGVzKVxuICAgICAgICAgICAgPyBbLi4uYWxsb3dlZFR5cGVzXS5zb3J0KChhLCBiKSA9PiBhLmxvY2FsZUNvbXBhcmUoYikpLmpvaW4oXCJfXCIpXG4gICAgICAgICAgICA6IGFsbG93ZWRUeXBlcztcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBbYHN5c3RlbS5hZHZhbmNlbWVudF9wb2ludHMuJHthUHRLZXl9YF06ICh0aGlzLnN5c3RlbS5hZHZhbmNlbWVudF9wb2ludHM/LlthUHRLZXldID8/IDApICsgYW1vdW50IH0pO1xuICAgIH1cbiAgICBhc3luYyByZW1vdmVBZHZhbmNlbWVudFBvaW50cyhhbGxvd2VkVHlwZXMsIGFtb3VudCA9IDEpIHtcbiAgICAgICAgY29uc3QgYVB0S2V5ID0gQXJyYXkuaXNBcnJheShhbGxvd2VkVHlwZXMpXG4gICAgICAgICAgICA/IFsuLi5hbGxvd2VkVHlwZXNdLnNvcnQoKGEsIGIpID0+IGEubG9jYWxlQ29tcGFyZShiKSkuam9pbihcIl9cIilcbiAgICAgICAgICAgIDogYWxsb3dlZFR5cGVzO1xuICAgICAgICBjb25zdCBuZXdDb3VudCA9IHRoaXMuc3lzdGVtLmFkdmFuY2VtZW50X3BvaW50cz8uW2FQdEtleV0gPz8gMCAtIGFtb3VudDtcbiAgICAgICAgaWYgKG5ld0NvdW50IDw9IDAgJiYgYVB0S2V5IGluICh0aGlzLnN5c3RlbS5hZHZhbmNlbWVudF9wb2ludHMgPz8gW10pKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZSh7IFtgc3lzdGVtLmFkdmFuY2VtZW50X3BvaW50cy4tPSR7YVB0S2V5fWBdOiBudWxsIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBbYHN5c3RlbS5hZHZhbmNlbWVudF9wb2ludHMuJHthUHRLZXl9YF06IG5ld0NvdW50IH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyh0cmFpdCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSkge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRyYWl0IGluIEFjdGlvblRyYWl0KSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHJhaXQgPT09IFwiQ29ob3J0XCIpIHtcbiAgICAgICAgICAgIGNvbnN0IHBvaW50c0NvaG9ydCA9IHRoaXMuc3lzdGVtLmFkdmFuY2VtZW50X3BvaW50cz8uW0FkdmFuY2VtZW50UG9pbnQuQ29ob3J0XSA/PyAwO1xuICAgICAgICAgICAgY29uc3Qgc3BlbnRDb2hvcnQgPSB0aGlzLmNvaG9ydHMubGVuZ3RoO1xuICAgICAgICAgICAgcmV0dXJuIE1hdGgubWF4KDAsIHBvaW50c0NvaG9ydCAtIHNwZW50Q29ob3J0KTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwb2ludHNBYmlsaXR5ID0gdGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnRfcG9pbnRzPy5bQWR2YW5jZW1lbnRQb2ludC5BYmlsaXR5XSA/PyAwO1xuICAgICAgICBjb25zdCBwb2ludHNDb2hvcnRUeXBlID0gdGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnRfcG9pbnRzPy5bQWR2YW5jZW1lbnRQb2ludC5Db2hvcnRUeXBlXSA/PyAwO1xuICAgICAgICBjb25zdCBwb2ludHNVcGdyYWRlID0gdGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnRfcG9pbnRzPy5bQWR2YW5jZW1lbnRQb2ludC5VcGdyYWRlXSA/PyAwO1xuICAgICAgICBjb25zdCBwb2ludHNVcGdyYWRlT3JBYmlsaXR5ID0gdGhpcy5zeXN0ZW0uYWR2YW5jZW1lbnRfcG9pbnRzPy5bQWR2YW5jZW1lbnRQb2ludC5VcGdyYWRlT3JBYmlsaXR5XSA/PyAwO1xuICAgICAgICBjb25zdCBzcGVudEFiaWxpdHkgPSBVLnN1bSh0aGlzLml0ZW1zXG4gICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBCbGFkZXNJdGVtLklzVHlwZShpdGVtLCBCbGFkZXNJdGVtVHlwZS5hYmlsaXR5LCBCbGFkZXNJdGVtVHlwZS5jcmV3X2FiaWxpdHkpKVxuICAgICAgICAgICAgLm1hcCgoYWJpbCkgPT4gYWJpbC5zeXN0ZW0ucHJpY2UgPz8gMSkpO1xuICAgICAgICBjb25zdCBzcGVudENvaG9ydFR5cGUgPSBVLnN1bSh0aGlzLmNvaG9ydHNcbiAgICAgICAgICAgIC5tYXAoKGNvaG9ydCkgPT4gTWF0aC5tYXgoMCwgVS51bmlxdWUoT2JqZWN0LnZhbHVlcyhjb2hvcnQuc3lzdGVtLnN1YnR5cGVzKSkubGVuZ3RoIC0gMSkpKTtcbiAgICAgICAgY29uc3Qgc3BlbnRVcGdyYWRlID0gVS5zdW0odGhpcy5pdGVtc1xuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gQmxhZGVzSXRlbS5Jc1R5cGUoaXRlbSwgQmxhZGVzSXRlbVR5cGUuY3Jld191cGdyYWRlKSlcbiAgICAgICAgICAgIC5tYXAoKHVwZ3JhZGUpID0+IHVwZ3JhZGUuc3lzdGVtLnByaWNlID8/IDEpKTtcbiAgICAgICAgY29uc3QgZXhjZXNzVXBncmFkZSA9IE1hdGgubWF4KDAsIHNwZW50VXBncmFkZSAtIHBvaW50c1VwZ3JhZGUpO1xuICAgICAgICBjb25zdCBleGNlc3NDb2hvcnRUeXBlID0gTWF0aC5tYXgoMCwgc3BlbnRDb2hvcnRUeXBlIC0gcG9pbnRzQ29ob3J0VHlwZSk7XG4gICAgICAgIGNvbnN0IGV4Y2Vzc0FiaWxpdHkgPSBNYXRoLm1heCgwLCBzcGVudEFiaWxpdHkgLSBwb2ludHNBYmlsaXR5KTtcbiAgICAgICAgY29uc3QgcmVtYWluaW5nQWJpbGl0eSA9IE1hdGgubWF4KDAsIHBvaW50c0FiaWxpdHkgLSBzcGVudEFiaWxpdHkpO1xuICAgICAgICBjb25zdCByZW1haW5pbmdDb2hvcnRUeXBlID0gTWF0aC5tYXgoMCwgcG9pbnRzQ29ob3J0VHlwZSAtIHNwZW50Q29ob3J0VHlwZSk7XG4gICAgICAgIGNvbnN0IHJlbWFpbmluZ1VwZ3JhZGUgPSBNYXRoLm1heCgwLCBwb2ludHNVcGdyYWRlIC0gc3BlbnRVcGdyYWRlKTtcbiAgICAgICAgY29uc3QgcmVtYWluaW5nVXBncmFkZU9yQWJpbGl0eSA9IE1hdGgubWF4KDAsIHBvaW50c1VwZ3JhZGVPckFiaWxpdHkgLSBleGNlc3NVcGdyYWRlIC0gKDIgKiBleGNlc3NBYmlsaXR5KSAtICgyICogZXhjZXNzQ29ob3J0VHlwZSkpO1xuICAgICAgICBpZiAodHJhaXQgPT09IFwiQWJpbGl0eVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVtYWluaW5nQWJpbGl0eSArIE1hdGguZmxvb3IoMC41ICogcmVtYWluaW5nVXBncmFkZU9yQWJpbGl0eSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRyYWl0ID09PSBcIlVwZ3JhZGVcIikge1xuICAgICAgICAgICAgcmV0dXJuIHJlbWFpbmluZ1VwZ3JhZGUgKyByZW1haW5pbmdVcGdyYWRlT3JBYmlsaXR5O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0cmFpdCA9PT0gXCJDb2hvcnRUeXBlXCIpIHtcbiAgICAgICAgICAgIHJldHVybiByZW1haW5pbmdDb2hvcnRUeXBlICsgcmVtYWluaW5nVXBncmFkZU9yQWJpbGl0eTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gMDtcbiAgICB9XG4gICAgZ2V0IGF2YWlsYWJsZUFiaWxpdHlQb2ludHMoKSB7IHJldHVybiB0aGlzLmdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyhcIkFiaWxpdHlcIik7IH1cbiAgICBnZXQgYXZhaWxhYmxlVXBncmFkZVBvaW50cygpIHsgcmV0dXJuIHRoaXMuZ2V0QXZhaWxhYmxlQWR2YW5jZW1lbnRzKFwiVXBncmFkZVwiKTsgfVxuICAgIGdldCBhdmFpbGFibGVDb2hvcnRQb2ludHMoKSB7IHJldHVybiB0aGlzLmdldEF2YWlsYWJsZUFkdmFuY2VtZW50cyhcIkNvaG9ydFwiKTsgfVxuICAgIGdldCBhdmFpbGFibGVDb2hvcnRUeXBlUG9pbnRzKCkgeyByZXR1cm4gdGhpcy5nZXRBdmFpbGFibGVBZHZhbmNlbWVudHMoXCJDb2hvcnRUeXBlXCIpOyB9XG4gICAgZ2V0IGNhblB1cmNoYXNlQWJpbGl0eSgpIHsgcmV0dXJuIHRoaXMuYXZhaWxhYmxlQWJpbGl0eVBvaW50cyA+IDA7IH1cbiAgICBnZXQgY2FuUHVyY2hhc2VVcGdyYWRlKCkgeyByZXR1cm4gdGhpcy5hdmFpbGFibGVVcGdyYWRlUG9pbnRzID4gMDsgfVxuICAgIGdldCBjYW5QdXJjaGFzZUNvaG9ydCgpIHsgcmV0dXJuIHRoaXMuYXZhaWxhYmxlQ29ob3J0UG9pbnRzID4gMDsgfVxuICAgIGdldCBjYW5QdXJjaGFzZUNvaG9ydFR5cGUoKSB7IHJldHVybiB0aGlzLmF2YWlsYWJsZUNvaG9ydFR5cGVQb2ludHMgPiAwOyB9XG4gICAgYXN5bmMgYWR2YW5jZVBsYXlib29rKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSB8fCAhdGhpcy5wbGF5Ym9vaykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0uZXhwZXJpZW5jZS5wbGF5Ym9vay52YWx1ZVwiOiAwIH0pO1xuICAgICAgICBpZiAodGhpcyBpbnN0YW5jZW9mIEJsYWRlc1BDKSB7XG4gICAgICAgICAgICBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnB1c2hOb3RpY2VfU29ja2V0Q2FsbChcIkFMTFwiLCB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IGAke3RoaXMubmFtZX0gQWR2YW5jZXMgdGhlaXIgUGxheWJvb2shYCxcbiAgICAgICAgICAgICAgICBib2R5OiBgJHt0aGlzLm5hbWV9LCBzZWxlY3QgYSBuZXcgQWJpbGl0eSBvbiB5b3VyIENoYXJhY3RlciBTaGVldC5gLFxuICAgICAgICAgICAgICAgIHR5cGU6IEJsYWRlc05vdGljZVR5cGUucHVzaCxcbiAgICAgICAgICAgICAgICBjc3NDbGFzc2VzOiBcImFkdmFuY2VtZW50LWFsZXJ0XCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGhpcy5ncmFudEFkdmFuY2VtZW50UG9pbnRzKEFkdmFuY2VtZW50UG9pbnQuQWJpbGl0eSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMgaW5zdGFuY2VvZiBCbGFkZXNDcmV3KSB7XG4gICAgICAgICAgICBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnB1c2hOb3RpY2VfU29ja2V0Q2FsbChcIkFMTFwiLCB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IFwiWW91IEFkdmFuY2UgeW91ciBDcmV3IFBsYXlib29rIVwiLFxuICAgICAgICAgICAgICAgIGJvZHk6IFwiU2VsZWN0IG5ldyBVcGdyYWRlcyBhbmQvb3IgQWJpbGl0aWVzIG9uIHlvdXIgQ3JldyBTaGVldC5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBCbGFkZXNOb3RpY2VUeXBlLnB1c2gsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJhZHZhbmNlbWVudC1hbGVydCBjcmV3LWFkdmFuY2VtZW50LWFsZXJ0XCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgY29uc3QgY29pbkdhaW5lZCA9IHRoaXMuc3lzdGVtLnRpZXIudmFsdWUgKyAyO1xuICAgICAgICAgICAgdGhpcy5tZW1iZXJzLmZvckVhY2goKG1lbWJlcikgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChtZW1iZXIucHJpbWFyeVVzZXI/LmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIEJsYWRlc0RpcmVjdG9yLmdldEluc3RhbmNlKCkucHVzaE5vdGljZV9Tb2NrZXRDYWxsKG1lbWJlci5wcmltYXJ5VXNlcj8uaWQsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRpdGxlOiBcIllvdXIgU3Rhc2ggSW5jcmVhc2VzISA8ZW0+KENyZXcgQWR2YW5jZW1lbnQpPC9lbT5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6IEJsYWRlc05vdGljZVR5cGUucHVzaCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGJvZHk6IGBZb3UgZ2FpbiAke2NvaW5HYWluZWR9IFN0YXNoIGZyb20gQ3JldyBBZHZhbmNlbWVudC5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJzdGFzaC1hbGVydFwiXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBtZW1iZXIuYWRkU3Rhc2goY29pbkdhaW5lZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0aGlzLmdyYW50QWR2YW5jZW1lbnRQb2ludHMoQWR2YW5jZW1lbnRQb2ludC5VcGdyYWRlT3JBYmlsaXR5LCAyKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBhZHZhbmNlQXR0cmlidXRlKGF0dHJpYnV0ZSkge1xuICAgICAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgQmxhZGVzUEMpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLnByaW1hcnlVc2VyPy5pZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgW2BzeXN0ZW0uZXhwZXJpZW5jZS4ke2F0dHJpYnV0ZX0udmFsdWVgXTogMCB9KTtcbiAgICAgICAgY29uc3QgYWN0aW9ucyA9IEMuQWN0aW9uW2F0dHJpYnV0ZV0ubWFwKChhY3Rpb24pID0+IGA8c3Ryb25nPiR7VS50Q2FzZShhY3Rpb24pfTwvc3Ryb25nPmApO1xuICAgICAgICBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnB1c2hOb3RpY2VfU29ja2V0Q2FsbCh0aGlzLnByaW1hcnlVc2VyLmlkLCB7XG4gICAgICAgICAgICB0aXRsZTogYCR7dGhpcy5uYW1lfSBBZHZhbmNlcyB0aGVpciAke1UudUNhc2UoYXR0cmlidXRlKX0hYCxcbiAgICAgICAgICAgIGJvZHk6IGAke3RoaXMubmFtZX0sIGFkZCBhIGRvdCB0byBvbmUgb2YgJHtVLm94Zm9yZGl6ZShhY3Rpb25zLCB0cnVlLCBcIm9yXCIpfS5gLFxuICAgICAgICAgICAgdHlwZTogQmxhZGVzTm90aWNlVHlwZS5wdXNoLFxuICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJhZHZhbmNlbWVudC1hbGVydFwiXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBnZXQgaXNBdFdhcigpIHtcbiAgICAgICAgaWYgKEJsYWRlc05QQy5Jc1R5cGUodGhpcykpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzUEMuSXNUeXBlKHRoaXMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jcmV3Py5pc0F0V2FyID8/IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMuc3lzdGVtLmF0X3dhcl93aXRoID8/IHt9KVxuICAgICAgICAgICAgLmZpbHRlcigodmFsKSA9PiB2YWwgPT09IHRydWUpXG4gICAgICAgICAgICAubGVuZ3RoID4gMDtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQmxhZGVzU3ViQWN0b3IgSW1wbGVtZW50YXRpb24gflxuICAgIHBhcmVudEFjdG9yO1xuICAgIGdldCBpc1N1YkFjdG9yKCkgeyByZXR1cm4gdGhpcy5wYXJlbnRBY3RvciAhPT0gdW5kZWZpbmVkOyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQmxhZGVzUm9sbCBJbXBsZW1lbnRhdGlvbiB+XG4gICAgZ2V0IHJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldCgpIHtcbiAgICAgICAgcmV0dXJuIEJsYWRlc1JvbGxNb2QuUGFyc2VEb2NNb2RzVG9TY2hlbWFTZXQodGhpcyk7XG4gICAgfVxuICAgIGdldCByb2xsRmFjdG9ycygpIHtcbiAgICAgICAgY29uc3QgZmFjdG9yRGF0YSA9IHtcbiAgICAgICAgICAgIFtGYWN0b3IudGllcl06IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBGYWN0b3IudGllcixcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIlRpZXJcIixcbiAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllciksXG4gICAgICAgICAgICAgICAgbWF4OiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSxcbiAgICAgICAgICAgICAgICBiYXNlVmFsOiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSxcbiAgICAgICAgICAgICAgICBpc0FjdGl2ZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBpc1ByaW1hcnk6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW0ZhY3Rvci5xdWFsaXR5XToge1xuICAgICAgICAgICAgICAgIG5hbWU6IEZhY3Rvci5xdWFsaXR5LFxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IFwiUXVhbGl0eVwiLFxuICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5xdWFsaXR5KSxcbiAgICAgICAgICAgICAgICBtYXg6IHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnF1YWxpdHkpLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnF1YWxpdHkpLFxuICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc1ByaW1hcnk6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gZmFjdG9yRGF0YTtcbiAgICB9XG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLlByaW1hcnlEb2MgSW1wbGVtZW50YXRpb25cbiAgICBnZXQgcm9sbFByaW1hcnlJRCgpIHsgcmV0dXJuIHRoaXMuaWQ7IH1cbiAgICBnZXQgcm9sbFByaW1hcnlEb2MoKSB7IHJldHVybiB0aGlzOyB9XG4gICAgZ2V0IHJvbGxQcmltYXJ5TmFtZSgpIHsgcmV0dXJuIHRoaXMubmFtZTsgfVxuICAgIGdldCByb2xsUHJpbWFyeVR5cGUoKSB7XG4gICAgICAgIGlmICghW0JsYWRlc0FjdG9yVHlwZS5wYywgQmxhZGVzQWN0b3JUeXBlLmNyZXddLmluY2x1ZGVzKHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQmxhZGVzQWN0b3Igb2YgdHlwZSAnJHt0aGlzLnR5cGV9JyAoXCIke3RoaXMubmFtZX1cIikgY2Fubm90IGJlIFJvbGxQcmltYXJ5LmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnR5cGU7XG4gICAgfVxuICAgIGdldCByb2xsUHJpbWFyeUltZygpIHsgcmV0dXJuIHRoaXMuaW1nOyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc0NyZXcgSW1wbGVtZW50YXRpb24gflxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFBSRVBBUklORyBERVJJVkVEIERBVEEgflxuICAgIHByZXBhcmVEZXJpdmVkRGF0YSgpIHtcbiAgICAgICAgaWYgKEJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMpKSB7XG4gICAgICAgICAgICB0aGlzLl9wcmVwYXJlUENEYXRhKHRoaXMuc3lzdGVtKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSkge1xuICAgICAgICAgICAgdGhpcy5fcHJlcGFyZUNyZXdEYXRhKHRoaXMuc3lzdGVtKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBfcHJlcGFyZVBDRGF0YShzeXN0ZW0pIHtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIEV4dHJhY3QgZXhwZXJpZW5jZSBjbHVlcyBmcm9tIHBsYXlib29rIGl0ZW0sIGlmIGFueVxuICAgICAgICBpZiAodGhpcy5wbGF5Ym9vaykge1xuICAgICAgICAgICAgc3lzdGVtLmV4cGVyaWVuY2UuY2x1ZXMgPSBbXG4gICAgICAgICAgICAgICAgLi4uc3lzdGVtLmV4cGVyaWVuY2UuY2x1ZXMsXG4gICAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyh0aGlzLnBsYXlib29rLnN5c3RlbS5leHBlcmllbmNlX2NsdWVzKVxuICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChjbHVlKSA9PiBCb29sZWFuKGNsdWUudHJpbSgpKSlcbiAgICAgICAgICAgIF07XG4gICAgICAgIH1cbiAgICAgICAgLy8gRXh0cmFjdCBnYXRoZXIgaW5mb3JtYXRpb24gcXVlc3Rpb25zIGZyb20gcGxheWJvb2sgaXRlbSwgaWYgYW55XG4gICAgICAgIGlmICh0aGlzLnBsYXlib29rKSB7XG4gICAgICAgICAgICBzeXN0ZW0uZ2F0aGVyX2luZm8gPSBbXG4gICAgICAgICAgICAgICAgLi4uc3lzdGVtLmdhdGhlcl9pbmZvLFxuICAgICAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXModGhpcy5wbGF5Ym9vay5zeXN0ZW0uZ2F0aGVyX2luZm9fcXVlc3Rpb25zKVxuICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChxdWVzdGlvbikgPT4gQm9vbGVhbihxdWVzdGlvbi50cmltKCkpKVxuICAgICAgICAgICAgXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBfcHJlcGFyZUNyZXdEYXRhKHN5c3RlbSkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUuY3JldykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBFeHRyYWN0IGV4cGVyaWVuY2UgY2x1ZXMgYW5kIHR1cmZzIGZyb20gcGxheWJvb2sgaXRlbSwgaWYgYW55XG4gICAgICAgIGlmICh0aGlzLnBsYXlib29rKSB7XG4gICAgICAgICAgICBzeXN0ZW0uZXhwZXJpZW5jZS5jbHVlcyA9IFtcbiAgICAgICAgICAgICAgICAuLi5zeXN0ZW0uZXhwZXJpZW5jZS5jbHVlcyxcbiAgICAgICAgICAgICAgICAuLi5PYmplY3QudmFsdWVzKHRoaXMucGxheWJvb2suc3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXMpXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGNsdWUpID0+IEJvb2xlYW4oY2x1ZS50cmltKCkpKVxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIHN5c3RlbS50dXJmcyA9IHRoaXMucGxheWJvb2suc3lzdGVtLnR1cmZzO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIE9WRVJSSURFUzogX29uQ3JlYXRlRGVzY2VuZGFudERvY3VtZW50cywgdXBkYXRlIH5cbiAgICAvLyBAdHMtZXhwZWN0LWVycm9yIE5ldyBtZXRob2Qgbm90IGRlZmluZWQgaW4gQGxlYWd1ZSBWVFQgdHlwZXMuXG4gICAgYXN5bmMgX29uQ3JlYXRlRGVzY2VuZGFudERvY3VtZW50cyhwYXJlbnQsIGNvbGxlY3Rpb24sIGRvY3MsIGRhdGEsIG9wdGlvbnMsIHVzZXJJZCkge1xuICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChkb2NzLm1hcChhc3luYyAoZG9jKSA9PiB7XG4gICAgICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUoZG9jLCBCbGFkZXNJdGVtVHlwZS5wbGF5Ym9vaywgQmxhZGVzSXRlbVR5cGUuY3Jld19wbGF5Ym9vaykpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbCh0aGlzLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGFJdGVtKSA9PiBhSXRlbS50eXBlID09PSBkb2MudHlwZSAmJiBhSXRlbS5zeXN0ZW0ud29ybGRfbmFtZSAhPT0gZG9jLnN5c3RlbS53b3JsZF9uYW1lKVxuICAgICAgICAgICAgICAgICAgICAubWFwKChhSXRlbSkgPT4gdGhpcy5yZW1TdWJJdGVtKGFJdGVtKSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KSk7XG4gICAgICAgIC8vIEB0cy1leHBlY3QtZXJyb3IgTmV3IG1ldGhvZCBub3QgZGVmaW5lZCBpbiBAbGVhZ3VlIFZUVCB0eXBlcy5cbiAgICAgICAgYXdhaXQgc3VwZXIuX29uQ3JlYXRlRGVzY2VuZGFudERvY3VtZW50cyhwYXJlbnQsIGNvbGxlY3Rpb24sIGRvY3MsIGRhdGEsIG9wdGlvbnMsIHVzZXJJZCk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RvclRyaWdnZXJcIiwgXCJfb25DcmVhdGVEZXNjZW5kYW50RG9jdW1lbnRzXCIsIHsgcGFyZW50LCBjb2xsZWN0aW9uLCBkb2NzLCBkYXRhLCBvcHRpb25zLCB1c2VySWQgfSk7XG4gICAgICAgIGRvY3MuZm9yRWFjaCgoZG9jKSA9PiB7XG4gICAgICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUoZG9jLCBCbGFkZXNJdGVtVHlwZS52aWNlKSAmJiBCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZlU3ViQWN0b3JzXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKHN1YkFjdG9yKSA9PiBzdWJBY3Rvci5oYXNUYWcoVGFnLk5QQy5WaWNlUHVydmV5b3IpICYmICFzdWJBY3Rvci5oYXNUYWcoZG9jLm5hbWUpKVxuICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgoc3ViQWN0b3IpID0+IHsgdGhpcy5yZW1TdWJBY3RvcihzdWJBY3Rvcik7IH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlKHVwZGF0ZURhdGEsIGNvbnRleHQsIGlzU2tpcHBpbmdTdWJBY3RvckNoZWNrID0gZmFsc2UpIHtcbiAgICAgICAgaWYgKCF1cGRhdGVEYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gc3VwZXIudXBkYXRlKHVwZGF0ZURhdGEpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpKSB7XG4gICAgICAgICAgICBpZiAoIXRoaXMucGxheWJvb2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZUxvZy5jaGVja0xvZyhcImFjdG9yVHJpZ2dlclwiLCBcIlVwZGF0aW5nIENyZXdcIiwgeyB1cGRhdGVEYXRhIH0pO1xuICAgICAgICAgICAgY29uc3QgcGxheWJvb2tVcGRhdGVEYXRhID0gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGZsYXR0ZW5PYmplY3QodXBkYXRlRGF0YSkpXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoW2tleSwgX10pID0+IGtleS5zdGFydHNXaXRoKFwic3lzdGVtLnR1cmZzLlwiKSkpO1xuICAgICAgICAgICAgdXBkYXRlRGF0YSA9IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhmbGF0dGVuT2JqZWN0KHVwZGF0ZURhdGEpKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKFtrZXksIF9dKSA9PiAha2V5LnN0YXJ0c1dpdGgoXCJzeXN0ZW0udHVyZnMuXCIpKSk7XG4gICAgICAgICAgICBlTG9nLmNoZWNrTG9nKFwiYWN0b3JUcmlnZ2VyXCIsIFwiVXBkYXRpbmcgQ3Jld1wiLCB7IGNyZXdVcGRhdGVEYXRhOiB1cGRhdGVEYXRhLCBwbGF5Ym9va1VwZGF0ZURhdGEgfSk7XG4gICAgICAgICAgICBjb25zdCBkaWZmUGxheWJvb2tEYXRhID0gZGlmZk9iamVjdChmbGF0dGVuT2JqZWN0KHRoaXMucGxheWJvb2spLCBwbGF5Ym9va1VwZGF0ZURhdGEpO1xuICAgICAgICAgICAgZGVsZXRlIGRpZmZQbGF5Ym9va0RhdGEuX2lkO1xuICAgICAgICAgICAgaWYgKCFVLmlzRW1wdHkoZGlmZlBsYXlib29rRGF0YSkpIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnBsYXlib29rLnVwZGF0ZShwbGF5Ym9va1VwZGF0ZURhdGEsIGNvbnRleHQpXG4gICAgICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHRoaXMuc2hlZXQ/LnJlbmRlcihmYWxzZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLm5wYylcbiAgICAgICAgICAgIHx8IEJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUuZmFjdGlvbikpXG4gICAgICAgICAgICAmJiB0aGlzLnBhcmVudEFjdG9yXG4gICAgICAgICAgICAmJiAhaXNTa2lwcGluZ1N1YkFjdG9yQ2hlY2spIHtcbiAgICAgICAgICAgIC8vIFRoaXMgaXMgYW4gZW1iZWRkZWQgQWN0b3I6IFVwZGF0ZSBpdCBhcyBhIHN1YkFjdG9yIG9mIHBhcmVudEFjdG9yLlxuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50QWN0b3IudXBkYXRlU3ViQWN0b3IodGhpcy5pZCwgdXBkYXRlRGF0YSlcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB0aGlzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gc3VwZXIudXBkYXRlKHVwZGF0ZURhdGEsIGNvbnRleHQpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBSb2xsaW5nIERpY2UgflxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgPG9wdGlvbnM+IG1vZGlmaWVycyBmb3IgZGljZSByb2xsLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtpbnR9IHJzXG4gICAgICogIE1pbiBkaWUgbW9kaWZpZXJcbiAgICAgKiBAcGFyYW0ge2ludH0gcmVcbiAgICAgKiAgTWF4IGRpZSBtb2RpZmllclxuICAgICAqIEBwYXJhbSB7aW50fSBzXG4gICAgICogIFNlbGVjdGVkIGRpZVxuICAgICAqL1xuICAgIGNyZWF0ZUxpc3RPZkRpY2VNb2RzKHJzLCByZSwgcykge1xuICAgICAgICBsZXQgdGV4dCA9IFwiXCI7XG4gICAgICAgIGlmIChzID09PSBcIlwiKSB7XG4gICAgICAgICAgICBzID0gMDtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCBpID0gcnM7IGkgPD0gcmU7IGkrKykge1xuICAgICAgICAgICAgbGV0IHBsdXMgPSBcIlwiO1xuICAgICAgICAgICAgaWYgKGkgPj0gMCkge1xuICAgICAgICAgICAgICAgIHBsdXMgPSBcIitcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRleHQgKz0gYDxvcHRpb24gdmFsdWU9XCIke2l9XCJgO1xuICAgICAgICAgICAgaWYgKGkgPT09IHMpIHtcbiAgICAgICAgICAgICAgICB0ZXh0ICs9IFwiIHNlbGVjdGVkXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0ZXh0ICs9IGA+JHtwbHVzfSR7aX1kPC9vcHRpb24+YDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGV4dDtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvbiBSb2xsaW5nIERpY2VcbiAgICAvLyAjcmVnaW9uIE5QQyBSYW5kb21pemVycyB+XG4gICAgdXBkYXRlUmFuZG9taXplcnMoKSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5ucGMpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdGl0bGVDaGFuY2UgPSAwLjA1O1xuICAgICAgICBjb25zdCBzdWZmaXhDaGFuY2UgPSAwLjAxO1xuICAgICAgICBjb25zdCB7IHBlcnNvbmEsIHNlY3JldCwgcmFuZG9tIH0gPSB0aGlzLnN5c3RlbTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgYSByYW5kb20gZWxlbWVudCBmcm9tIGFuIGFycmF5LCBvcHRpb25hbGx5IGV4Y2x1ZGluZyBhbGwgdmFsdWVzXG4gICAgICAgICAqIHBhc3NlZCBhcyBzdWJzZXF1ZW50IHBhcmFtZXRlcnMuXG4gICAgICAgICAqIEBwYXJhbSB7c3RyaW5nW119IGFyciBUaGUgYXJyYXkgdG8gcmFuZG9tbHkgc2VsZWN0IGZyb20uXG4gICAgICAgICAqIEBwYXJhbSB7Li4uc3RyaW5nfSBjdXJWYWxzIFRoZSB2YWx1ZXMgdG8gZXhjbHVkZSBmcm9tIHRoZSBzYW1wbGUuXG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBzYW1wbGVBcnJheShhcnIsIC4uLmN1clZhbHMpIHtcbiAgICAgICAgICAgIGFyciA9IGFyci5maWx0ZXIoKGVsZW0pID0+ICFjdXJWYWxzLmluY2x1ZGVzKGVsZW0pKTtcbiAgICAgICAgICAgIGlmICghYXJyLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGFycltNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiBhcnIubGVuZ3RoKV07XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcmFuZG9tR2VuID0ge1xuICAgICAgICAgICAgbmFtZTogKGdlbikgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgIE1hdGgucmFuZG9tKCkgPD0gdGl0bGVDaGFuY2VcbiAgICAgICAgICAgICAgICAgICAgICAgID8gc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLm5hbWVfdGl0bGUpXG4gICAgICAgICAgICAgICAgICAgICAgICA6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgIHNhbXBsZUFycmF5KFtcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLigoZ2VuID8/IFwiXCIpLmNoYXJBdCgwKS50b0xvd2VyQ2FzZSgpICE9PSBcIm1cIiA/IFJhbmRvbWl6ZXJzLk5QQy5uYW1lX2ZpcnN0LmZlbWFsZSA6IFtdKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIC4uLigoZ2VuID8/IFwiXCIpLmNoYXJBdCgwKS50b0xvd2VyQ2FzZSgpICE9PSBcImZcIiA/IFJhbmRvbWl6ZXJzLk5QQy5uYW1lX2ZpcnN0Lm1hbGUgOiBbXSlcbiAgICAgICAgICAgICAgICAgICAgXSksXG4gICAgICAgICAgICAgICAgICAgIGBcIiR7c2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLm5hbWVfYWxpYXMpfVwiYCxcbiAgICAgICAgICAgICAgICAgICAgc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLm5hbWVfc3VybmFtZSksXG4gICAgICAgICAgICAgICAgICAgIE1hdGgucmFuZG9tKCkgPD0gc3VmZml4Q2hhbmNlXG4gICAgICAgICAgICAgICAgICAgICAgICA/IHNhbXBsZUFycmF5KFJhbmRvbWl6ZXJzLk5QQy5uYW1lX3N1ZmZpeClcbiAgICAgICAgICAgICAgICAgICAgICAgIDogXCJcIlxuICAgICAgICAgICAgICAgIF0uZmlsdGVyKCh2YWwpID0+IEJvb2xlYW4odmFsKSkuam9pbihcIiBcIik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYmFja2dyb3VuZDogKCkgPT4gc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLmJhY2tncm91bmQsIHJhbmRvbS5iYWNrZ3JvdW5kLnZhbHVlKSxcbiAgICAgICAgICAgIGhlcml0YWdlOiAoKSA9PiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMuaGVyaXRhZ2UsIHJhbmRvbS5oZXJpdGFnZS52YWx1ZSksXG4gICAgICAgICAgICBwcm9mZXNzaW9uOiAoKSA9PiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMucHJvZmVzc2lvbiwgcmFuZG9tLnByb2Zlc3Npb24udmFsdWUpLFxuICAgICAgICAgICAgZ2VuZGVyOiAoKSA9PiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMuZ2VuZGVyLCBwZXJzb25hLmdlbmRlci52YWx1ZSksXG4gICAgICAgICAgICBhcHBlYXJhbmNlOiAoKSA9PiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMuYXBwZWFyYW5jZSwgcGVyc29uYS5hcHBlYXJhbmNlLnZhbHVlKSxcbiAgICAgICAgICAgIGdvYWw6ICgpID0+IHNhbXBsZUFycmF5KFJhbmRvbWl6ZXJzLk5QQy5nb2FsLCBwZXJzb25hLmdvYWwudmFsdWUsIHNlY3JldC5nb2FsLnZhbHVlKSxcbiAgICAgICAgICAgIG1ldGhvZDogKCkgPT4gc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLm1ldGhvZCwgcGVyc29uYS5tZXRob2QudmFsdWUsIHNlY3JldC5tZXRob2QudmFsdWUpLFxuICAgICAgICAgICAgdHJhaXQ6ICgpID0+IHNhbXBsZUFycmF5KFJhbmRvbWl6ZXJzLk5QQy50cmFpdCwgcGVyc29uYS50cmFpdDEudmFsdWUsIHBlcnNvbmEudHJhaXQyLnZhbHVlLCBwZXJzb25hLnRyYWl0My52YWx1ZSwgc2VjcmV0LnRyYWl0LnZhbHVlKSxcbiAgICAgICAgICAgIGludGVyZXN0czogKCkgPT4gc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLmludGVyZXN0cywgcGVyc29uYS5pbnRlcmVzdHMudmFsdWUsIHNlY3JldC5pbnRlcmVzdHMudmFsdWUpLFxuICAgICAgICAgICAgcXVpcms6ICgpID0+IHNhbXBsZUFycmF5KFJhbmRvbWl6ZXJzLk5QQy5xdWlyaywgcGVyc29uYS5xdWlyay52YWx1ZSksXG4gICAgICAgICAgICBzdHlsZTogKGdlbiA9IFwiXCIpID0+IHNhbXBsZUFycmF5KFtcbiAgICAgICAgICAgICAgICAuLi4oZ2VuLmNoYXJBdCgwKS50b0xvd2VyQ2FzZSgpICE9PSBcIm1cIiA/IFJhbmRvbWl6ZXJzLk5QQy5zdHlsZS5mZW1hbGUgOiBbXSksXG4gICAgICAgICAgICAgICAgLi4uKGdlbi5jaGFyQXQoMCkudG9Mb3dlckNhc2UoKSAhPT0gXCJmXCIgPyBSYW5kb21pemVycy5OUEMuc3R5bGUubWFsZSA6IFtdKVxuICAgICAgICAgICAgXSwgcGVyc29uYS5zdHlsZS52YWx1ZSlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgZ2VuZGVyID0gcGVyc29uYS5nZW5kZXIuaXNMb2NrZWQgPyBwZXJzb25hLmdlbmRlci52YWx1ZSA6IHJhbmRvbUdlbi5nZW5kZXIoKTtcbiAgICAgICAgY29uc3QgdXBkYXRlS2V5cyA9IFtcbiAgICAgICAgICAgIC4uLk9iamVjdC5rZXlzKHBlcnNvbmEpLmZpbHRlcigoa2V5KSA9PiAhcGVyc29uYVtrZXldPy5pc0xvY2tlZCksXG4gICAgICAgICAgICAuLi5PYmplY3Qua2V5cyhyYW5kb20pLmZpbHRlcigoa2V5KSA9PiAhcmFuZG9tW2tleV0/LmlzTG9ja2VkKSxcbiAgICAgICAgICAgIC4uLk9iamVjdC5rZXlzKHNlY3JldCkuZmlsdGVyKChrZXkpID0+ICFzZWNyZXRba2V5XT8uaXNMb2NrZWQpXG4gICAgICAgICAgICAgICAgLm1hcCgoc2VjcmV0S2V5KSA9PiBgc2VjcmV0LSR7c2VjcmV0S2V5fWApXG4gICAgICAgIF07XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJVcGRhdGUgS2V5c1wiLCB7IHVwZGF0ZUtleXMgfSk7XG4gICAgICAgIGNvbnN0IHVwZGF0ZURhdGEgPSB7fTtcbiAgICAgICAgdXBkYXRlS2V5cy5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAgICAgICAgIHN3aXRjaCAoa2V5KSB7XG4gICAgICAgICAgICAgICAgY2FzZSBcIm5hbWVcIjpcbiAgICAgICAgICAgICAgICBjYXNlIFwiaGVyaXRhZ2VcIjpcbiAgICAgICAgICAgICAgICBjYXNlIFwiYmFja2dyb3VuZFwiOlxuICAgICAgICAgICAgICAgIGNhc2UgXCJwcm9mZXNzaW9uXCI6IHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmFuZG9tVmFsID0gcmFuZG9tR2VuW2tleV0oKTtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtgc3lzdGVtLnJhbmRvbS4ke2tleX1gXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiByYW5kb21WYWwgfHwgcmFuZG9tW2tleV0udmFsdWVcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgXCJzZWNyZXQtZ29hbFwiOlxuICAgICAgICAgICAgICAgIGNhc2UgXCJzZWNyZXQtaW50ZXJlc3RzXCI6XG4gICAgICAgICAgICAgICAgY2FzZSBcInNlY3JldC1tZXRob2RcIjoge1xuICAgICAgICAgICAgICAgICAgICBrZXkgPSBrZXkucmVwbGFjZSgvXnNlY3JldC0vLCBcIlwiKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgcmFuZG9tVmFsID0gcmFuZG9tR2VuW2tleV0oKTtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtgc3lzdGVtLnNlY3JldC4ke2tleX1gXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiByYW5kb21WYWwgfHwgc2VjcmV0W2tleV0udmFsdWVcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgXCJnZW5kZXJcIjoge1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVEYXRhW2BzeXN0ZW0ucGVyc29uYS4ke2tleX1gXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiBwZXJzb25hLmdlbmRlci5pc0xvY2tlZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBnZW5kZXJcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgXCJ0cmFpdDFcIjpcbiAgICAgICAgICAgICAgICBjYXNlIFwidHJhaXQyXCI6XG4gICAgICAgICAgICAgICAgY2FzZSBcInRyYWl0M1wiOlxuICAgICAgICAgICAgICAgIGNhc2UgXCJzZWNyZXQtdHJhaXRcIjoge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0cmFpdDEgPSBwZXJzb25hLnRyYWl0MS5pc0xvY2tlZFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBwZXJzb25hLnRyYWl0MS52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMudHJhaXQsIHBlcnNvbmEudHJhaXQxLnZhbHVlLCBwZXJzb25hLnRyYWl0Mi52YWx1ZSwgcGVyc29uYS50cmFpdDMudmFsdWUsIHNlY3JldC50cmFpdC52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRyYWl0MiA9IHBlcnNvbmEudHJhaXQyLmlzTG9ja2VkXG4gICAgICAgICAgICAgICAgICAgICAgICA/IHBlcnNvbmEudHJhaXQyLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgICAgICA6IHNhbXBsZUFycmF5KFJhbmRvbWl6ZXJzLk5QQy50cmFpdCwgdHJhaXQxLCBwZXJzb25hLnRyYWl0MS52YWx1ZSwgcGVyc29uYS50cmFpdDIudmFsdWUsIHBlcnNvbmEudHJhaXQzLnZhbHVlLCBzZWNyZXQudHJhaXQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0cmFpdDMgPSBwZXJzb25hLnRyYWl0My5pc0xvY2tlZFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBwZXJzb25hLnRyYWl0My52YWx1ZVxuICAgICAgICAgICAgICAgICAgICAgICAgOiBzYW1wbGVBcnJheShSYW5kb21pemVycy5OUEMudHJhaXQsIHRyYWl0MSwgdHJhaXQyLCBwZXJzb25hLnRyYWl0MS52YWx1ZSwgcGVyc29uYS50cmFpdDIudmFsdWUsIHBlcnNvbmEudHJhaXQzLnZhbHVlLCBzZWNyZXQudHJhaXQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBzZWNyZXRUcmFpdCA9IHNlY3JldC50cmFpdC5pc0xvY2tlZFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBzZWNyZXQudHJhaXQudmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgIDogc2FtcGxlQXJyYXkoUmFuZG9taXplcnMuTlBDLnRyYWl0LCB0cmFpdDEsIHRyYWl0MiwgdHJhaXQzLCBwZXJzb25hLnRyYWl0MS52YWx1ZSwgcGVyc29uYS50cmFpdDIudmFsdWUsIHBlcnNvbmEudHJhaXQzLnZhbHVlLCBzZWNyZXQudHJhaXQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXBlcnNvbmEudHJhaXQxLmlzTG9ja2VkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1cGRhdGVEYXRhW1wic3lzdGVtLnBlcnNvbmEudHJhaXQxXCJdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdHJhaXQxXG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICghcGVyc29uYS50cmFpdDIuaXNMb2NrZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZURhdGFbXCJzeXN0ZW0ucGVyc29uYS50cmFpdDJcIl0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNMb2NrZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0cmFpdDJcbiAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFwZXJzb25hLnRyYWl0My5pc0xvY2tlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtcInN5c3RlbS5wZXJzb25hLnRyYWl0M1wiXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpc0xvY2tlZDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IHRyYWl0M1xuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoIXNlY3JldC50cmFpdC5pc0xvY2tlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtcInN5c3RlbS5zZWNyZXQudHJhaXRcIl0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXNMb2NrZWQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBzZWNyZXRUcmFpdFxuICAgICAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCByYW5kb21WYWwgPSByYW5kb21HZW5ba2V5XSgpO1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVEYXRhW2BzeXN0ZW0ucGVyc29uYS4ke2tleX1gXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiByYW5kb21WYWwgfHwgcGVyc29uYVtrZXldLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudXBkYXRlKHVwZGF0ZURhdGEpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uIE5QQyBSYW5kb21pemVyc1xuICAgIC8vIFVubG9jayBsb3dlci1sZXZlbCB1cGRhdGUgbWV0aG9kIGZvciBzdWJjbGFzc2VzXG4gICAgYXN5bmMgY2FsbE9uVXBkYXRlKC4uLmFyZ3MpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5fb25VcGRhdGUoLi4uYXJncyk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQWN0b3I7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/BladesActor.ts\n"); + +/***/ }), + +/***/ "./ts/BladesItem.ts": +/*!**************************!*\ + !*** ./ts/BladesItem.ts ***! + \**************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./classes/BladesDirector */ \"./ts/classes/BladesDirector.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\nclass BladesItem extends Item {\n // #region Static Overrides: Create ~\n static async create(data, options = {}) {\n if (Array.isArray(data)) {\n data = data[0];\n }\n data.system = data.system ?? {};\n eLog.checkLog2(\"item\", \"BladesItem.create(data,options)\", { data, options });\n // ~ Create world_name\n data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, \"\").trim().replace(/ /g, \"_\");\n return super.create(data, options);\n }\n // #endregion\n // #region BladesDocument Implementation\n static get All() { return game.items; }\n static Get(itemRef) {\n if (itemRef instanceof BladesItem) {\n return itemRef;\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].isDocID(itemRef)) {\n return BladesItem.All.get(itemRef);\n }\n return BladesItem.All.find((a) => a.system.world_name === itemRef)\n || BladesItem.All.find((a) => a.name === itemRef);\n }\n static GetTypeWithTags(docType, ...tags) {\n if (Array.isArray(docType)) {\n return docType\n .map((dType) => BladesItem.All.filter((item) => item.type === dType))\n .flat();\n }\n return BladesItem.All.filter((item) => item.type === docType)\n .filter((item) => item.hasTag(...tags));\n }\n static IsType(doc, ...types) {\n const typeSet = new Set(types);\n return doc instanceof BladesItem && typeSet.has(doc.type);\n }\n get tags() { return this.system.tags ?? []; }\n hasTag(...tags) {\n return tags.every((tag) => this.tags.includes(tag));\n }\n async addTag(...tags) {\n const curTags = this.tags;\n tags.forEach((tag) => {\n if (curTags.includes(tag)) {\n return;\n }\n curTags.push(tag);\n });\n await this.update({ \"system.tags\": curTags });\n }\n async remTag(...tags) {\n const curTags = this.tags.filter((tag) => !tags.includes(tag));\n await this.update({ \"system.tags\": curTags });\n }\n get tooltip() {\n const tooltipText = [\n this.system.concept,\n this.system.rules,\n this.system.notes\n ].filter(Boolean).join(\"\");\n if (tooltipText) {\n return (new Handlebars.SafeString(tooltipText)).toString();\n }\n return undefined;\n }\n dialogCSSClasses = \"\";\n getFactorTotal(factor) {\n switch (factor) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier: {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n return this.system.tier.value + (this.parent?.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) ?? 0);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n return this.system.tier.value + (this.parent?.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) ?? 0);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)) {\n return this.system.tier.value + (this.parent?.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) ?? 0);\n }\n return this.system.tier.value;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality: {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) + (this.system.quality_bonus ?? 0);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) + (this.system.quality_bonus ?? 0) + 1;\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)) {\n let thisQuality = this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier)\n + (this.hasTag(\"Fine\") ? 1 : 0);\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.parent)) {\n thisQuality += this.parent.getTaggedItemBonuses(this.tags);\n }\n return thisQuality;\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design)) {\n return this.system.min_quality;\n }\n return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier);\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale: {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) + (this.system.scale_bonus ?? 0);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n return 0 + (this.system.scale_bonus ?? 0);\n }\n return 0;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude: {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual)) {\n return this.system.magnitude.value;\n }\n return 0;\n }\n default: return 0;\n }\n }\n // #endregion\n // #region BladesItemDocument Implementation\n async archive() {\n await this.addTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.System.Archived);\n return this;\n }\n async unarchive() {\n await this.remTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.System.Archived);\n return this;\n }\n // #endregion\n // #region BladesRoll Implementation\n get rollFactors() {\n const factorsMap = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale],\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale],\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality],\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality],\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude],\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design]: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality]\n };\n if (!factorsMap[this.type]) {\n return {};\n }\n const factors = factorsMap[this.type];\n const factorData = {};\n (factors ?? []).forEach((factor, i) => {\n const factorTotal = this.getFactorTotal(factor);\n factorData[factor] = {\n name: factor,\n value: factorTotal,\n max: factorTotal,\n baseVal: factorTotal,\n display: [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality].includes(factor) ? _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].romanizeNum(factorTotal) : `${factorTotal}`,\n isActive: i === 0,\n isPrimary: i === 0,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: `factor-gold${i === 0 ? \" factor-main\" : \"\"}`\n };\n });\n return factorData;\n }\n // #region BladesRoll.PrimaryDoc Implementation\n get rollPrimaryID() { return this.id; }\n get rollPrimaryDoc() { return this; }\n get rollPrimaryName() { return this.name; }\n get rollPrimaryType() {\n if (![\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gm_tracker,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.score\n ].includes(this.type)) {\n throw new Error(`BladesItem of type '${this.type}' (\"${this.name}\") cannot be RollPrimary.`);\n }\n return this.type;\n }\n get rollPrimaryImg() { return this.img; }\n get rollPrimaryModsSchemaSet() {\n // Add roll mods from COHORT harm\n return _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_4__.BladesRollMod.ParseDocModsToSchemaSet(this);\n }\n async applyHarm(amount, _name) {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n const curHarm = this.system.harm.value;\n let newHarm;\n if (amount > curHarm) {\n newHarm = amount;\n }\n else {\n newHarm = curHarm + 1;\n }\n const harmVerb = [\"is Weakened\", \"is Impaired\", \"has been Broken\", \"has been Killed!\"];\n const harmEffect = [\n \"They act with Reduced Effect.\",\n \"They act with Reduced Effect and suffer -1d to all rolls.\",\n \"They cannot do anything until they recover.\",\n \"You may replace them during Downtime.\"\n ];\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_3__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} ${harmVerb[newHarm - 1]}`,\n body: harmEffect[newHarm - 1],\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"harm-alert\"\n });\n await this.update({ \"system.harm\": amount });\n }\n }\n async applyWorsePosition() {\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n this.setFlag(\"eunos-blades\", \"isWorsePosition\", true);\n }\n }\n // #endregion\n // #region BladesRoll.OppositionDoc Implementation\n get rollOppID() { return this.id; }\n get rollOppDoc() { return this; }\n get rollOppImg() { return this.img; }\n get rollOppName() { return this.name; }\n get rollOppSubName() { return \"\"; }\n get rollOppType() {\n if (![\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gm_tracker,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.score,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.location,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual\n ].includes(this.type)) {\n throw new Error(`BladesItem of type '${this.type}' (\"${this.name}\") cannot be RollOpposition.`);\n }\n return this.type;\n }\n get rollOppModsSchemaSet() { return []; }\n // #endregion\n // #region BladesRoll.ParticipantDoc Implementation\n get rollParticipantID() { return this.id; }\n get rollParticipantDoc() { return this; }\n get rollParticipantIcon() { return this.img; }\n get rollParticipantName() { return this.name; }\n get rollParticipantType() {\n if (![\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gm_tracker\n ].includes(this.type)) {\n throw new Error(`BladesItem of type '${this.type}' (\"${this.name}\") cannot be RollParticipant.`);\n }\n return this.type;\n }\n get rollParticipantModsSchemaSet() { return []; }\n // #endregion\n // #endregion\n // #region PREPARING DERIVED DATA\n prepareDerivedData() {\n super.prepareDerivedData();\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n this._prepareCohortData(this.system);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook)) {\n this._preparePlaybookData(this.system);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)) {\n this._prepareGearData(this.system);\n }\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook)) {\n this._preparePlaybookData(this.system);\n }\n }\n _prepareCohortData(system) {\n if (!BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n return;\n }\n system.tier.name = \"Quality\";\n const subtypes = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].unique(Object.values(system.subtypes)\n .map((subtype) => subtype.trim())\n .filter((subtype) => /[A-Za-z]/.test(subtype)));\n const eliteSubtypes = [\n ...Object.values(system.elite_subtypes)\n ];\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(this.parent)) {\n eliteSubtypes.push(...this.parent.upgrades\n .filter((upgrade) => (upgrade.name ?? \"\").startsWith(\"Elite\"))\n .map((upgrade) => (upgrade.name ?? \"\").trim().replace(/^Elite /, \"\")));\n }\n system.subtypes = Object.fromEntries(subtypes.map((subtype, i) => [`${i + 1}`, subtype]));\n system.elite_subtypes = Object.fromEntries(_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].unique(eliteSubtypes\n .map((subtype) => subtype.trim())\n .filter((subtype) => /[A-Za-z]/.test(subtype) && subtypes.includes(subtype)))\n .map((subtype, i) => [`${i + 1}`, subtype]));\n system.edges = Object.fromEntries(Object.values(system.edges ?? [])\n .filter((edge) => /[A-Za-z]/.test(edge))\n .map((edge, i) => [`${i + 1}`, edge.trim()]));\n system.flaws = Object.fromEntries(Object.values(system.flaws ?? [])\n .filter((flaw) => /[A-Za-z]/.test(flaw))\n .map((flaw, i) => [`${i + 1}`, flaw.trim()]));\n system.quality = this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality);\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n if ([...subtypes, ...eliteSubtypes].includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.GangType.Vehicle)) {\n system.scale = this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale);\n system.scaleExample = \"(1 vehicle)\";\n }\n else {\n system.scale = this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale);\n const scaleIndex = Math.min(6, system.scale);\n system.scaleExample = _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ScaleExamples[scaleIndex];\n system.subtitle = _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ScaleSizes[scaleIndex];\n }\n if (subtypes.length + eliteSubtypes.length === 0) {\n system.subtitle = system.subtitle.replace(/\\s+of\\b/g, \"\").trim();\n }\n }\n else {\n system.scale = 0;\n system.scaleExample = [...subtypes, ...eliteSubtypes].includes(\"Pet\") ? \"(1 animal)\" : \"(1 person)\";\n system.subtitle = \"An Expert\";\n }\n if (subtypes.length + eliteSubtypes.length > 0) {\n if ([...subtypes, ...eliteSubtypes].includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.GangType.Vehicle)) {\n system.subtitle = _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].VehicleDescriptors[Math.min(6, this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier))];\n }\n else {\n system.subtitle += ` ${_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].oxfordize([\n ...subtypes.filter((subtype) => !eliteSubtypes.includes(subtype)),\n ...eliteSubtypes.map((subtype) => `Elite ${subtype}`)\n ], false, \"&\")}`;\n }\n }\n }\n _prepareGearData(system) {\n if (!BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)) {\n return;\n }\n system.tier.name = \"Quality\";\n }\n _preparePlaybookData(system) {\n if (!BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook)) {\n return;\n }\n const expClueData = {};\n [...Object.values(system.experience_clues).filter((clue) => /[A-Za-z]/.test(clue)), \" \"].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; });\n system.experience_clues = expClueData;\n // eLog.checkLog3(\"experienceClues\", {expClueData})\n if (BladesItem.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook)) {\n const gatherInfoData = {};\n [...Object.values(system.gather_info_questions).filter((question) => /[A-Za-z]/.test(question)), \" \"].forEach((question, i) => { gatherInfoData[(i + 1).toString()] = question; });\n system.gather_info_questions = gatherInfoData;\n // eLog.checkLog3(\"gatherInfoQuestions\", {gatherInfoData});\n }\n }\n // #endregion\n // Unlock lower-level update method for subclasses\n async callOnUpdate(...args) {\n await this._onUpdate(...args);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesItem);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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bS50cz9iMDdiIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuaW1wb3J0IEMsIHsgQmxhZGVzSXRlbVR5cGUsIEJsYWRlc05vdGljZVR5cGUsIFRhZywgRmFjdG9yIH0gZnJvbSBcIi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBCbGFkZXNDcmV3LCBCbGFkZXNQQyB9IGZyb20gXCIuL2RvY3VtZW50cy9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgQmxhZGVzRGlyZWN0b3IgZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNEaXJlY3RvclwiO1xuaW1wb3J0IHsgQmxhZGVzUm9sbE1vZCB9IGZyb20gXCIuL2NsYXNzZXMvQmxhZGVzUm9sbFwiO1xuY2xhc3MgQmxhZGVzSXRlbSBleHRlbmRzIEl0ZW0ge1xuICAgIC8vICNyZWdpb24gU3RhdGljIE92ZXJyaWRlczogQ3JlYXRlIH5cbiAgICBzdGF0aWMgYXN5bmMgY3JlYXRlKGRhdGEsIG9wdGlvbnMgPSB7fSkge1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShkYXRhKSkge1xuICAgICAgICAgICAgZGF0YSA9IGRhdGFbMF07XG4gICAgICAgIH1cbiAgICAgICAgZGF0YS5zeXN0ZW0gPSBkYXRhLnN5c3RlbSA/PyB7fTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJpdGVtXCIsIFwiQmxhZGVzSXRlbS5jcmVhdGUoZGF0YSxvcHRpb25zKVwiLCB7IGRhdGEsIG9wdGlvbnMgfSk7XG4gICAgICAgIC8vIH4gQ3JlYXRlIHdvcmxkX25hbWVcbiAgICAgICAgZGF0YS5zeXN0ZW0ud29ybGRfbmFtZSA9IGRhdGEuc3lzdGVtLndvcmxkX25hbWUgPz8gZGF0YS5uYW1lLnJlcGxhY2UoL1teQS1aYS16XzAtOSBdL2csIFwiXCIpLnRyaW0oKS5yZXBsYWNlKC8gL2csIFwiX1wiKTtcbiAgICAgICAgcmV0dXJuIHN1cGVyLmNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQmxhZGVzRG9jdW1lbnQgSW1wbGVtZW50YXRpb25cbiAgICBzdGF0aWMgZ2V0IEFsbCgpIHsgcmV0dXJuIGdhbWUuaXRlbXM7IH1cbiAgICBzdGF0aWMgR2V0KGl0ZW1SZWYpIHtcbiAgICAgICAgaWYgKGl0ZW1SZWYgaW5zdGFuY2VvZiBCbGFkZXNJdGVtKSB7XG4gICAgICAgICAgICByZXR1cm4gaXRlbVJlZjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoVS5pc0RvY0lEKGl0ZW1SZWYpKSB7XG4gICAgICAgICAgICByZXR1cm4gQmxhZGVzSXRlbS5BbGwuZ2V0KGl0ZW1SZWYpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBCbGFkZXNJdGVtLkFsbC5maW5kKChhKSA9PiBhLnN5c3RlbS53b3JsZF9uYW1lID09PSBpdGVtUmVmKVxuICAgICAgICAgICAgfHwgQmxhZGVzSXRlbS5BbGwuZmluZCgoYSkgPT4gYS5uYW1lID09PSBpdGVtUmVmKTtcbiAgICB9XG4gICAgc3RhdGljIEdldFR5cGVXaXRoVGFncyhkb2NUeXBlLCAuLi50YWdzKSB7XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KGRvY1R5cGUpKSB7XG4gICAgICAgICAgICByZXR1cm4gZG9jVHlwZVxuICAgICAgICAgICAgICAgIC5tYXAoKGRUeXBlKSA9PiBCbGFkZXNJdGVtLkFsbC5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gZFR5cGUpKVxuICAgICAgICAgICAgICAgIC5mbGF0KCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEJsYWRlc0l0ZW0uQWxsLmZpbHRlcigoaXRlbSkgPT4gaXRlbS50eXBlID09PSBkb2NUeXBlKVxuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gaXRlbS5oYXNUYWcoLi4udGFncykpO1xuICAgIH1cbiAgICBzdGF0aWMgSXNUeXBlKGRvYywgLi4udHlwZXMpIHtcbiAgICAgICAgY29uc3QgdHlwZVNldCA9IG5ldyBTZXQodHlwZXMpO1xuICAgICAgICByZXR1cm4gZG9jIGluc3RhbmNlb2YgQmxhZGVzSXRlbSAmJiB0eXBlU2V0Lmhhcyhkb2MudHlwZSk7XG4gICAgfVxuICAgIGdldCB0YWdzKCkgeyByZXR1cm4gdGhpcy5zeXN0ZW0udGFncyA/PyBbXTsgfVxuICAgIGhhc1RhZyguLi50YWdzKSB7XG4gICAgICAgIHJldHVybiB0YWdzLmV2ZXJ5KCh0YWcpID0+IHRoaXMudGFncy5pbmNsdWRlcyh0YWcpKTtcbiAgICB9XG4gICAgYXN5bmMgYWRkVGFnKC4uLnRhZ3MpIHtcbiAgICAgICAgY29uc3QgY3VyVGFncyA9IHRoaXMudGFncztcbiAgICAgICAgdGFncy5mb3JFYWNoKCh0YWcpID0+IHtcbiAgICAgICAgICAgIGlmIChjdXJUYWdzLmluY2x1ZGVzKHRhZykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJUYWdzLnB1c2godGFnKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0udGFnc1wiOiBjdXJUYWdzIH0pO1xuICAgIH1cbiAgICBhc3luYyByZW1UYWcoLi4udGFncykge1xuICAgICAgICBjb25zdCBjdXJUYWdzID0gdGhpcy50YWdzLmZpbHRlcigodGFnKSA9PiAhdGFncy5pbmNsdWRlcyh0YWcpKTtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBcInN5c3RlbS50YWdzXCI6IGN1clRhZ3MgfSk7XG4gICAgfVxuICAgIGdldCB0b29sdGlwKCkge1xuICAgICAgICBjb25zdCB0b29sdGlwVGV4dCA9IFtcbiAgICAgICAgICAgIHRoaXMuc3lzdGVtLmNvbmNlcHQsXG4gICAgICAgICAgICB0aGlzLnN5c3RlbS5ydWxlcyxcbiAgICAgICAgICAgIHRoaXMuc3lzdGVtLm5vdGVzXG4gICAgICAgIF0uZmlsdGVyKEJvb2xlYW4pLmpvaW4oXCJcIik7XG4gICAgICAgIGlmICh0b29sdGlwVGV4dCkge1xuICAgICAgICAgICAgcmV0dXJuIChuZXcgSGFuZGxlYmFycy5TYWZlU3RyaW5nKHRvb2x0aXBUZXh0KSkudG9TdHJpbmcoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBkaWFsb2dDU1NDbGFzc2VzID0gXCJcIjtcbiAgICBnZXRGYWN0b3JUb3RhbChmYWN0b3IpIHtcbiAgICAgICAgc3dpdGNoIChmYWN0b3IpIHtcbiAgICAgICAgICAgIGNhc2UgRmFjdG9yLnRpZXI6IHtcbiAgICAgICAgICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnN5c3RlbS50aWVyLnZhbHVlICsgKHRoaXMucGFyZW50Py5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcikgPz8gMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZXhwZXJ0KSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zeXN0ZW0udGllci52YWx1ZSArICh0aGlzLnBhcmVudD8uZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnRpZXIpID8/IDApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuZ2VhcikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnRpZXIudmFsdWUgKyAodGhpcy5wYXJlbnQ/LmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSA/PyAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnRpZXIudmFsdWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5xdWFsaXR5OiB7XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcikgKyAodGhpcy5zeXN0ZW0ucXVhbGl0eV9ib251cyA/PyAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSArICh0aGlzLnN5c3RlbS5xdWFsaXR5X2JvbnVzID8/IDApICsgMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLmdlYXIpKSB7XG4gICAgICAgICAgICAgICAgICAgIGxldCB0aGlzUXVhbGl0eSA9IHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnRpZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICArICh0aGlzLmhhc1RhZyhcIkZpbmVcIikgPyAxIDogMCk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChCbGFkZXNQQy5Jc1R5cGUodGhpcy5wYXJlbnQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzUXVhbGl0eSArPSB0aGlzLnBhcmVudC5nZXRUYWdnZWRJdGVtQm9udXNlcyh0aGlzLnRhZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzUXVhbGl0eTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLmRlc2lnbikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLm1pbl9xdWFsaXR5O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5zY2FsZToge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZykpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnRpZXIpICsgKHRoaXMuc3lzdGVtLnNjYWxlX2JvbnVzID8/IDApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIDAgKyAodGhpcy5zeXN0ZW0uc2NhbGVfYm9udXMgPz8gMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBGYWN0b3IubWFnbml0dWRlOiB7XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLnJpdHVhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLm1hZ25pdHVkZS52YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNJdGVtRG9jdW1lbnQgSW1wbGVtZW50YXRpb25cbiAgICBhc3luYyBhcmNoaXZlKCkge1xuICAgICAgICBhd2FpdCB0aGlzLmFkZFRhZyhUYWcuU3lzdGVtLkFyY2hpdmVkKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxuICAgIGFzeW5jIHVuYXJjaGl2ZSgpIHtcbiAgICAgICAgYXdhaXQgdGhpcy5yZW1UYWcoVGFnLlN5c3RlbS5BcmNoaXZlZCk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsIEltcGxlbWVudGF0aW9uXG4gICAgZ2V0IHJvbGxGYWN0b3JzKCkge1xuICAgICAgICBjb25zdCBmYWN0b3JzTWFwID0ge1xuICAgICAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nXTogW0ZhY3Rvci5xdWFsaXR5LCBGYWN0b3Iuc2NhbGVdLFxuICAgICAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnRdOiBbRmFjdG9yLnF1YWxpdHksIEZhY3Rvci5zY2FsZV0sXG4gICAgICAgICAgICBbQmxhZGVzSXRlbVR5cGUuZ2Vhcl06IFtGYWN0b3IucXVhbGl0eV0sXG4gICAgICAgICAgICBbQmxhZGVzSXRlbVR5cGUucHJvamVjdF06IFtGYWN0b3IucXVhbGl0eV0sXG4gICAgICAgICAgICBbQmxhZGVzSXRlbVR5cGUucml0dWFsXTogW0ZhY3Rvci5tYWduaXR1ZGVdLFxuICAgICAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmRlc2lnbl06IFtGYWN0b3IucXVhbGl0eV1cbiAgICAgICAgfTtcbiAgICAgICAgaWYgKCFmYWN0b3JzTWFwW3RoaXMudHlwZV0pIHtcbiAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBmYWN0b3JzID0gZmFjdG9yc01hcFt0aGlzLnR5cGVdO1xuICAgICAgICBjb25zdCBmYWN0b3JEYXRhID0ge307XG4gICAgICAgIChmYWN0b3JzID8/IFtdKS5mb3JFYWNoKChmYWN0b3IsIGkpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGZhY3RvclRvdGFsID0gdGhpcy5nZXRGYWN0b3JUb3RhbChmYWN0b3IpO1xuICAgICAgICAgICAgZmFjdG9yRGF0YVtmYWN0b3JdID0ge1xuICAgICAgICAgICAgICAgIG5hbWU6IGZhY3RvcixcbiAgICAgICAgICAgICAgICB2YWx1ZTogZmFjdG9yVG90YWwsXG4gICAgICAgICAgICAgICAgbWF4OiBmYWN0b3JUb3RhbCxcbiAgICAgICAgICAgICAgICBiYXNlVmFsOiBmYWN0b3JUb3RhbCxcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBbRmFjdG9yLnRpZXIsIEZhY3Rvci5xdWFsaXR5XS5pbmNsdWRlcyhmYWN0b3IpID8gVS5yb21hbml6ZU51bShmYWN0b3JUb3RhbCkgOiBgJHtmYWN0b3JUb3RhbH1gLFxuICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBpID09PSAwLFxuICAgICAgICAgICAgICAgIGlzUHJpbWFyeTogaSA9PT0gMCxcbiAgICAgICAgICAgICAgICBpc0RvbWluYW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICBoaWdoRmF2b3JzUEM6IHRydWUsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogYGZhY3Rvci1nb2xkJHtpID09PSAwID8gXCIgZmFjdG9yLW1haW5cIiA6IFwiXCJ9YFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBmYWN0b3JEYXRhO1xuICAgIH1cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwuUHJpbWFyeURvYyBJbXBsZW1lbnRhdGlvblxuICAgIGdldCByb2xsUHJpbWFyeUlEKCkgeyByZXR1cm4gdGhpcy5pZDsgfVxuICAgIGdldCByb2xsUHJpbWFyeURvYygpIHsgcmV0dXJuIHRoaXM7IH1cbiAgICBnZXQgcm9sbFByaW1hcnlOYW1lKCkgeyByZXR1cm4gdGhpcy5uYW1lOyB9XG4gICAgZ2V0IHJvbGxQcmltYXJ5VHlwZSgpIHtcbiAgICAgICAgaWYgKCFbXG4gICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZyxcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQsXG4gICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5nbV90cmFja2VyLFxuICAgICAgICAgICAgQmxhZGVzSXRlbVR5cGUuc2NvcmVcbiAgICAgICAgXS5pbmNsdWRlcyh0aGlzLnR5cGUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJsYWRlc0l0ZW0gb2YgdHlwZSAnJHt0aGlzLnR5cGV9JyAoXCIke3RoaXMubmFtZX1cIikgY2Fubm90IGJlIFJvbGxQcmltYXJ5LmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnR5cGU7XG4gICAgfVxuICAgIGdldCByb2xsUHJpbWFyeUltZygpIHsgcmV0dXJuIHRoaXMuaW1nOyB9XG4gICAgZ2V0IHJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldCgpIHtcbiAgICAgICAgLy8gQWRkIHJvbGwgbW9kcyBmcm9tIENPSE9SVCBoYXJtXG4gICAgICAgIHJldHVybiBCbGFkZXNSb2xsTW9kLlBhcnNlRG9jTW9kc1RvU2NoZW1hU2V0KHRoaXMpO1xuICAgIH1cbiAgICBhc3luYyBhcHBseUhhcm0oYW1vdW50LCBfbmFtZSkge1xuICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcpKSB7XG4gICAgICAgICAgICBjb25zdCBjdXJIYXJtID0gdGhpcy5zeXN0ZW0uaGFybS52YWx1ZTtcbiAgICAgICAgICAgIGxldCBuZXdIYXJtO1xuICAgICAgICAgICAgaWYgKGFtb3VudCA+IGN1ckhhcm0pIHtcbiAgICAgICAgICAgICAgICBuZXdIYXJtID0gYW1vdW50O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgbmV3SGFybSA9IGN1ckhhcm0gKyAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgaGFybVZlcmIgPSBbXCJpcyBXZWFrZW5lZFwiLCBcImlzIEltcGFpcmVkXCIsIFwiaGFzIGJlZW4gQnJva2VuXCIsIFwiaGFzIGJlZW4gS2lsbGVkIVwiXTtcbiAgICAgICAgICAgIGNvbnN0IGhhcm1FZmZlY3QgPSBbXG4gICAgICAgICAgICAgICAgXCJUaGV5IGFjdCB3aXRoIFJlZHVjZWQgRWZmZWN0LlwiLFxuICAgICAgICAgICAgICAgIFwiVGhleSBhY3Qgd2l0aCBSZWR1Y2VkIEVmZmVjdCBhbmQgc3VmZmVyIC0xZCB0byBhbGwgcm9sbHMuXCIsXG4gICAgICAgICAgICAgICAgXCJUaGV5IGNhbm5vdCBkbyBhbnl0aGluZyB1bnRpbCB0aGV5IHJlY292ZXIuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3UgbWF5IHJlcGxhY2UgdGhlbSBkdXJpbmcgRG93bnRpbWUuXCJcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnB1c2hOb3RpY2VfU29ja2V0Q2FsbChcIkFMTFwiLCB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IGAke3RoaXMubmFtZX0gJHtoYXJtVmVyYltuZXdIYXJtIC0gMV19YCxcbiAgICAgICAgICAgICAgICBib2R5OiBoYXJtRWZmZWN0W25ld0hhcm0gLSAxXSxcbiAgICAgICAgICAgICAgICB0eXBlOiBCbGFkZXNOb3RpY2VUeXBlLnB1c2gsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJoYXJtLWFsZXJ0XCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBcInN5c3RlbS5oYXJtXCI6IGFtb3VudCB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBhcHBseVdvcnNlUG9zaXRpb24oKSB7XG4gICAgICAgIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZXhwZXJ0LCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZykpIHtcbiAgICAgICAgICAgIHRoaXMuc2V0RmxhZyhcImV1bm9zLWJsYWRlc1wiLCBcImlzV29yc2VQb3NpdGlvblwiLCB0cnVlKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLk9wcG9zaXRpb25Eb2MgSW1wbGVtZW50YXRpb25cbiAgICBnZXQgcm9sbE9wcElEKCkgeyByZXR1cm4gdGhpcy5pZDsgfVxuICAgIGdldCByb2xsT3BwRG9jKCkgeyByZXR1cm4gdGhpczsgfVxuICAgIGdldCByb2xsT3BwSW1nKCkgeyByZXR1cm4gdGhpcy5pbWc7IH1cbiAgICBnZXQgcm9sbE9wcE5hbWUoKSB7IHJldHVybiB0aGlzLm5hbWU7IH1cbiAgICBnZXQgcm9sbE9wcFN1Yk5hbWUoKSB7IHJldHVybiBcIlwiOyB9XG4gICAgZ2V0IHJvbGxPcHBUeXBlKCkge1xuICAgICAgICBpZiAoIVtcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nLFxuICAgICAgICAgICAgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCxcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLmdtX3RyYWNrZXIsXG4gICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5zY29yZSxcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLmxvY2F0aW9uLFxuICAgICAgICAgICAgQmxhZGVzSXRlbVR5cGUucHJvamVjdCxcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLmRlc2lnbixcbiAgICAgICAgICAgIEJsYWRlc0l0ZW1UeXBlLnJpdHVhbFxuICAgICAgICBdLmluY2x1ZGVzKHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQmxhZGVzSXRlbSBvZiB0eXBlICcke3RoaXMudHlwZX0nIChcIiR7dGhpcy5uYW1lfVwiKSBjYW5ub3QgYmUgUm9sbE9wcG9zaXRpb24uYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMudHlwZTtcbiAgICB9XG4gICAgZ2V0IHJvbGxPcHBNb2RzU2NoZW1hU2V0KCkgeyByZXR1cm4gW107IH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLlBhcnRpY2lwYW50RG9jIEltcGxlbWVudGF0aW9uXG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudElEKCkgeyByZXR1cm4gdGhpcy5pZDsgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnREb2MoKSB7IHJldHVybiB0aGlzOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudEljb24oKSB7IHJldHVybiB0aGlzLmltZzsgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnROYW1lKCkgeyByZXR1cm4gdGhpcy5uYW1lOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudFR5cGUoKSB7XG4gICAgICAgIGlmICghW1xuICAgICAgICAgICAgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsXG4gICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZXhwZXJ0LFxuICAgICAgICAgICAgQmxhZGVzSXRlbVR5cGUuZ21fdHJhY2tlclxuICAgICAgICBdLmluY2x1ZGVzKHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQmxhZGVzSXRlbSBvZiB0eXBlICcke3RoaXMudHlwZX0nIChcIiR7dGhpcy5uYW1lfVwiKSBjYW5ub3QgYmUgUm9sbFBhcnRpY2lwYW50LmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnR5cGU7XG4gICAgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0KCkgeyByZXR1cm4gW107IH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gUFJFUEFSSU5HIERFUklWRUQgREFUQVxuICAgIHByZXBhcmVEZXJpdmVkRGF0YSgpIHtcbiAgICAgICAgc3VwZXIucHJlcGFyZURlcml2ZWREYXRhKCk7XG4gICAgICAgIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCkpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZXBhcmVDb2hvcnREYXRhKHRoaXMuc3lzdGVtKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuY3Jld19wbGF5Ym9vaykpIHtcbiAgICAgICAgICAgIHRoaXMuX3ByZXBhcmVQbGF5Ym9va0RhdGEodGhpcy5zeXN0ZW0pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLCBCbGFkZXNJdGVtVHlwZS5nZWFyKSkge1xuICAgICAgICAgICAgdGhpcy5fcHJlcGFyZUdlYXJEYXRhKHRoaXMuc3lzdGVtKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUucGxheWJvb2spKSB7XG4gICAgICAgICAgICB0aGlzLl9wcmVwYXJlUGxheWJvb2tEYXRhKHRoaXMuc3lzdGVtKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBfcHJlcGFyZUNvaG9ydERhdGEoc3lzdGVtKSB7XG4gICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3lzdGVtLnRpZXIubmFtZSA9IFwiUXVhbGl0eVwiO1xuICAgICAgICBjb25zdCBzdWJ0eXBlcyA9IFUudW5pcXVlKE9iamVjdC52YWx1ZXMoc3lzdGVtLnN1YnR5cGVzKVxuICAgICAgICAgICAgLm1hcCgoc3VidHlwZSkgPT4gc3VidHlwZS50cmltKCkpXG4gICAgICAgICAgICAuZmlsdGVyKChzdWJ0eXBlKSA9PiAvW0EtWmEtel0vLnRlc3Qoc3VidHlwZSkpKTtcbiAgICAgICAgY29uc3QgZWxpdGVTdWJ0eXBlcyA9IFtcbiAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXMoc3lzdGVtLmVsaXRlX3N1YnR5cGVzKVxuICAgICAgICBdO1xuICAgICAgICBpZiAoQmxhZGVzQ3Jldy5Jc1R5cGUodGhpcy5wYXJlbnQpKSB7XG4gICAgICAgICAgICBlbGl0ZVN1YnR5cGVzLnB1c2goLi4udGhpcy5wYXJlbnQudXBncmFkZXNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKCh1cGdyYWRlKSA9PiAodXBncmFkZS5uYW1lID8/IFwiXCIpLnN0YXJ0c1dpdGgoXCJFbGl0ZVwiKSlcbiAgICAgICAgICAgICAgICAubWFwKCh1cGdyYWRlKSA9PiAodXBncmFkZS5uYW1lID8/IFwiXCIpLnRyaW0oKS5yZXBsYWNlKC9eRWxpdGUgLywgXCJcIikpKTtcbiAgICAgICAgfVxuICAgICAgICBzeXN0ZW0uc3VidHlwZXMgPSBPYmplY3QuZnJvbUVudHJpZXMoc3VidHlwZXMubWFwKChzdWJ0eXBlLCBpKSA9PiBbYCR7aSArIDF9YCwgc3VidHlwZV0pKTtcbiAgICAgICAgc3lzdGVtLmVsaXRlX3N1YnR5cGVzID0gT2JqZWN0LmZyb21FbnRyaWVzKFUudW5pcXVlKGVsaXRlU3VidHlwZXNcbiAgICAgICAgICAgIC5tYXAoKHN1YnR5cGUpID0+IHN1YnR5cGUudHJpbSgpKVxuICAgICAgICAgICAgLmZpbHRlcigoc3VidHlwZSkgPT4gL1tBLVphLXpdLy50ZXN0KHN1YnR5cGUpICYmIHN1YnR5cGVzLmluY2x1ZGVzKHN1YnR5cGUpKSlcbiAgICAgICAgICAgIC5tYXAoKHN1YnR5cGUsIGkpID0+IFtgJHtpICsgMX1gLCBzdWJ0eXBlXSkpO1xuICAgICAgICBzeXN0ZW0uZWRnZXMgPSBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LnZhbHVlcyhzeXN0ZW0uZWRnZXMgPz8gW10pXG4gICAgICAgICAgICAuZmlsdGVyKChlZGdlKSA9PiAvW0EtWmEtel0vLnRlc3QoZWRnZSkpXG4gICAgICAgICAgICAubWFwKChlZGdlLCBpKSA9PiBbYCR7aSArIDF9YCwgZWRnZS50cmltKCldKSk7XG4gICAgICAgIHN5c3RlbS5mbGF3cyA9IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QudmFsdWVzKHN5c3RlbS5mbGF3cyA/PyBbXSlcbiAgICAgICAgICAgIC5maWx0ZXIoKGZsYXcpID0+IC9bQS1aYS16XS8udGVzdChmbGF3KSlcbiAgICAgICAgICAgIC5tYXAoKGZsYXcsIGkpID0+IFtgJHtpICsgMX1gLCBmbGF3LnRyaW0oKV0pKTtcbiAgICAgICAgc3lzdGVtLnF1YWxpdHkgPSB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5xdWFsaXR5KTtcbiAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nKSkge1xuICAgICAgICAgICAgaWYgKFsuLi5zdWJ0eXBlcywgLi4uZWxpdGVTdWJ0eXBlc10uaW5jbHVkZXMoVGFnLkdhbmdUeXBlLlZlaGljbGUpKSB7XG4gICAgICAgICAgICAgICAgc3lzdGVtLnNjYWxlID0gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3Iuc2NhbGUpO1xuICAgICAgICAgICAgICAgIHN5c3RlbS5zY2FsZUV4YW1wbGUgPSBcIigxIHZlaGljbGUpXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzeXN0ZW0uc2NhbGUgPSB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5zY2FsZSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgc2NhbGVJbmRleCA9IE1hdGgubWluKDYsIHN5c3RlbS5zY2FsZSk7XG4gICAgICAgICAgICAgICAgc3lzdGVtLnNjYWxlRXhhbXBsZSA9IEMuU2NhbGVFeGFtcGxlc1tzY2FsZUluZGV4XTtcbiAgICAgICAgICAgICAgICBzeXN0ZW0uc3VidGl0bGUgPSBDLlNjYWxlU2l6ZXNbc2NhbGVJbmRleF07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc3VidHlwZXMubGVuZ3RoICsgZWxpdGVTdWJ0eXBlcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBzeXN0ZW0uc3VidGl0bGUgPSBzeXN0ZW0uc3VidGl0bGUucmVwbGFjZSgvXFxzK29mXFxiL2csIFwiXCIpLnRyaW0oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHN5c3RlbS5zY2FsZSA9IDA7XG4gICAgICAgICAgICBzeXN0ZW0uc2NhbGVFeGFtcGxlID0gWy4uLnN1YnR5cGVzLCAuLi5lbGl0ZVN1YnR5cGVzXS5pbmNsdWRlcyhcIlBldFwiKSA/IFwiKDEgYW5pbWFsKVwiIDogXCIoMSBwZXJzb24pXCI7XG4gICAgICAgICAgICBzeXN0ZW0uc3VidGl0bGUgPSBcIkFuIEV4cGVydFwiO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdWJ0eXBlcy5sZW5ndGggKyBlbGl0ZVN1YnR5cGVzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGlmIChbLi4uc3VidHlwZXMsIC4uLmVsaXRlU3VidHlwZXNdLmluY2x1ZGVzKFRhZy5HYW5nVHlwZS5WZWhpY2xlKSkge1xuICAgICAgICAgICAgICAgIHN5c3RlbS5zdWJ0aXRsZSA9IEMuVmVoaWNsZURlc2NyaXB0b3JzW01hdGgubWluKDYsIHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnRpZXIpKV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzeXN0ZW0uc3VidGl0bGUgKz0gYCAke1Uub3hmb3JkaXplKFtcbiAgICAgICAgICAgICAgICAgICAgLi4uc3VidHlwZXMuZmlsdGVyKChzdWJ0eXBlKSA9PiAhZWxpdGVTdWJ0eXBlcy5pbmNsdWRlcyhzdWJ0eXBlKSksXG4gICAgICAgICAgICAgICAgICAgIC4uLmVsaXRlU3VidHlwZXMubWFwKChzdWJ0eXBlKSA9PiBgRWxpdGUgJHtzdWJ0eXBlfWApXG4gICAgICAgICAgICAgICAgXSwgZmFsc2UsIFwiJlwiKX1gO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIF9wcmVwYXJlR2VhckRhdGEoc3lzdGVtKSB7XG4gICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcywgQmxhZGVzSXRlbVR5cGUuZ2VhcikpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzeXN0ZW0udGllci5uYW1lID0gXCJRdWFsaXR5XCI7XG4gICAgfVxuICAgIF9wcmVwYXJlUGxheWJvb2tEYXRhKHN5c3RlbSkge1xuICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rLCBCbGFkZXNJdGVtVHlwZS5jcmV3X3BsYXlib29rKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGV4cENsdWVEYXRhID0ge307XG4gICAgICAgIFsuLi5PYmplY3QudmFsdWVzKHN5c3RlbS5leHBlcmllbmNlX2NsdWVzKS5maWx0ZXIoKGNsdWUpID0+IC9bQS1aYS16XS8udGVzdChjbHVlKSksIFwiIFwiXS5mb3JFYWNoKChjbHVlLCBpKSA9PiB7IGV4cENsdWVEYXRhWyhpICsgMSkudG9TdHJpbmcoKV0gPSBjbHVlOyB9KTtcbiAgICAgICAgc3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXMgPSBleHBDbHVlRGF0YTtcbiAgICAgICAgLy8gZUxvZy5jaGVja0xvZzMoXCJleHBlcmllbmNlQ2x1ZXNcIiwge2V4cENsdWVEYXRhfSlcbiAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMsIEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rKSkge1xuICAgICAgICAgICAgY29uc3QgZ2F0aGVySW5mb0RhdGEgPSB7fTtcbiAgICAgICAgICAgIFsuLi5PYmplY3QudmFsdWVzKHN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnMpLmZpbHRlcigocXVlc3Rpb24pID0+IC9bQS1aYS16XS8udGVzdChxdWVzdGlvbikpLCBcIiBcIl0uZm9yRWFjaCgocXVlc3Rpb24sIGkpID0+IHsgZ2F0aGVySW5mb0RhdGFbKGkgKyAxKS50b1N0cmluZygpXSA9IHF1ZXN0aW9uOyB9KTtcbiAgICAgICAgICAgIHN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnMgPSBnYXRoZXJJbmZvRGF0YTtcbiAgICAgICAgICAgIC8vIGVMb2cuY2hlY2tMb2czKFwiZ2F0aGVySW5mb1F1ZXN0aW9uc1wiLCB7Z2F0aGVySW5mb0RhdGF9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gVW5sb2NrIGxvd2VyLWxldmVsIHVwZGF0ZSBtZXRob2QgZm9yIHN1YmNsYXNzZXNcbiAgICBhc3luYyBjYWxsT25VcGRhdGUoLi4uYXJncykge1xuICAgICAgICBhd2FpdCB0aGlzLl9vblVwZGF0ZSguLi5hcmdzKTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNJdGVtO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/BladesItem.ts\n"); + +/***/ }), + +/***/ "./ts/blades.ts": +/*!**********************!*\ + !*** ./ts/blades.ts ***! + \**********************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_settings__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./core/settings */ \"./ts/core/settings.ts\");\n/* harmony import */ var _core_helpers__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./core/helpers */ \"./ts/core/helpers.ts\");\n/* harmony import */ var _classes_BladesChat__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./classes/BladesChat */ \"./ts/classes/BladesChat.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_logger__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./core/logger */ \"./ts/core/logger.ts\");\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./classes/BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n/* harmony import */ var _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./classes/BladesDirector */ \"./ts/classes/BladesDirector.ts\");\n/* harmony import */ var _classes_BladesConsequence__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./classes/BladesConsequence */ \"./ts/classes/BladesConsequence.ts\");\n/* harmony import */ var _classes_BladesScene__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./classes/BladesScene */ \"./ts/classes/BladesScene.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__ = __webpack_require__(/*! ./documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _sheets_item_BladesItemSheet__WEBPACK_IMPORTED_MODULE_13__ = __webpack_require__(/*! ./sheets/item/BladesItemSheet */ \"./ts/sheets/item/BladesItemSheet.ts\");\n/* harmony import */ var _sheets_actor_BladesPCSheet__WEBPACK_IMPORTED_MODULE_14__ = __webpack_require__(/*! ./sheets/actor/BladesPCSheet */ \"./ts/sheets/actor/BladesPCSheet.ts\");\n/* harmony import */ var _sheets_actor_BladesCrewSheet__WEBPACK_IMPORTED_MODULE_15__ = __webpack_require__(/*! ./sheets/actor/BladesCrewSheet */ \"./ts/sheets/actor/BladesCrewSheet.ts\");\n/* harmony import */ var _sheets_actor_BladesNPCSheet__WEBPACK_IMPORTED_MODULE_16__ = __webpack_require__(/*! ./sheets/actor/BladesNPCSheet */ \"./ts/sheets/actor/BladesNPCSheet.ts\");\n/* harmony import */ var _sheets_actor_BladesFactionSheet__WEBPACK_IMPORTED_MODULE_17__ = __webpack_require__(/*! ./sheets/actor/BladesFactionSheet */ \"./ts/sheets/actor/BladesFactionSheet.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__ = __webpack_require__(/*! ./classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* harmony import */ var _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_19__ = __webpack_require__(/*! ./classes/BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n/* harmony import */ var _core_ai__WEBPACK_IMPORTED_MODULE_20__ = __webpack_require__(/*! ./core/ai */ \"./ts/core/ai.ts\");\n/* harmony import */ var _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_21__ = __webpack_require__(/*! ./documents/BladesActiveEffect */ \"./ts/documents/BladesActiveEffect.ts\");\n/* harmony import */ var _sheets_item_BladesGMTrackerSheet__WEBPACK_IMPORTED_MODULE_22__ = __webpack_require__(/*! ./sheets/item/BladesGMTrackerSheet */ \"./ts/sheets/item/BladesGMTrackerSheet.ts\");\n/* harmony import */ var _sheets_item_BladesClockKeeperSheet__WEBPACK_IMPORTED_MODULE_23__ = __webpack_require__(/*! ./sheets/item/BladesClockKeeperSheet */ \"./ts/sheets/item/BladesClockKeeperSheet.ts\");\n/* harmony import */ var _core_debug__WEBPACK_IMPORTED_MODULE_24__ = __webpack_require__(/*! ./core/debug */ \"./ts/core/debug.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n/* DEVCODE*/\n\nCONFIG.debug.logging = true;\nObject.assign(globalThis, { eLog: _core_logger__WEBPACK_IMPORTED_MODULE_5__[\"default\"], BladesDebug: _core_debug__WEBPACK_IMPORTED_MODULE_24__[\"default\"] });\nHandlebars.registerHelper(\"eLog\", _core_logger__WEBPACK_IMPORTED_MODULE_5__[\"default\"].hbsLog);\n/* !DEVCODE*/\nlet socket; // ~ SocketLib interface\n// #endregion ▮▮▮▮[IMPORTS]▮▮▮▮\nclass GlobalGetter {\n get clockKeys() { return game.eunoblades.ClockKeys.filter((clockKey) => clockKey.isInScene() && clockKey.isVisible); }\n get roll() { return _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__[\"default\"].Active; }\n get user() { return game.users.getName(\"Alistair\"); }\n get actor() { return game.actors.getName(\"Alistair\"); }\n get rollTarget() { return this.roll?.target; }\n get rollData() { return this.roll?.data; }\n get userFlags() { return this.user?.flags?.[\"eunos-blades\"]; }\n get actorFlags() { return this.actor?.flags?.[\"eunos-blades\"]; }\n get rollPrimary() { return this.roll?.rollPrimary; }\n get rollPrimaryDoc() { return this.roll?.rollPrimaryDoc; }\n get rollOpposition() { return this.roll?.rollOpposition; }\n get sheetData() { return this.roll?.context; }\n newActionRoll() {\n const pc = game.actors.getName(\"Alistair\");\n if (!pc) {\n return;\n }\n const conf = {\n target: pc,\n targetFlagKey: \"rollCollab\",\n rollType: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollType.Action,\n rollTrait: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ActionTrait.finesse,\n rollUserID: game.users.find((user) => user.character?.name === \"Alistair\")?.id,\n rollPrimaryData: pc\n };\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesActionRoll.New(conf);\n }\n}\n// #region Globals: Exposing Functionality to Global Scope ~\n/* DEVCODE*/ Object.assign(globalThis, {\n get: new GlobalGetter(),\n // updateClaims,\n // updateContacts,\n // updateOps,\n // updateFactions,\n // updateDescriptions,\n // updateRollMods,\n BladesScene: _classes_BladesScene__WEBPACK_IMPORTED_MODULE_10__[\"default\"],\n BladesDirector: _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__[\"default\"],\n BladesActor: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesActor,\n BladesPC: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesPC,\n BladesCrew: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesCrew,\n BladesNPC: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesNPC,\n BladesFaction: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesFaction,\n BladesPCSheet: _sheets_actor_BladesPCSheet__WEBPACK_IMPORTED_MODULE_14__[\"default\"],\n BladesCrewSheet: _sheets_actor_BladesCrewSheet__WEBPACK_IMPORTED_MODULE_15__[\"default\"],\n BladesFactionSheet: _sheets_actor_BladesFactionSheet__WEBPACK_IMPORTED_MODULE_17__[\"default\"],\n BladesClockKey: _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_7__[\"default\"],\n BladesNPCSheet: _sheets_actor_BladesNPCSheet__WEBPACK_IMPORTED_MODULE_16__[\"default\"],\n BladesActiveEffect: _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_21__[\"default\"],\n BladesRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__[\"default\"],\n BladesRollMod: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesRollMod,\n BladesRollPrimary: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesRollPrimary,\n BladesRollOpposition: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesRollOpposition,\n BladesRollParticipant: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesRollParticipant,\n BladesActionRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesActionRoll,\n BladesEngagementRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesEngagementRoll,\n BladesFortuneRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesFortuneRoll,\n BladesIncarcerationRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesIncarcerationRoll,\n BladesIndulgeViceRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesIndulgeViceRoll,\n BladesInlineResistanceRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesInlineResistanceRoll,\n BladesResistanceRoll: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__.BladesResistanceRoll,\n BladesChat: _classes_BladesChat__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n BladesConsequence: _classes_BladesConsequence__WEBPACK_IMPORTED_MODULE_9__[\"default\"],\n G: _core_gsap__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n U: _core_utilities__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n C: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"],\n BladesItem: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesItem,\n BladesClockKeeper: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesClockKeeper,\n BladesGMTracker: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesGMTracker,\n BladesLocation: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesLocation,\n BladesProject: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesProject,\n BladesScore: _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesScore,\n BladesItemSheet: _sheets_item_BladesItemSheet__WEBPACK_IMPORTED_MODULE_13__[\"default\"],\n BladesClockKeeperSheet: _sheets_item_BladesClockKeeperSheet__WEBPACK_IMPORTED_MODULE_23__[\"default\"],\n BladesGMTrackerSheet: _sheets_item_BladesGMTrackerSheet__WEBPACK_IMPORTED_MODULE_22__[\"default\"],\n BladesAI: _core_ai__WEBPACK_IMPORTED_MODULE_20__[\"default\"],\n AIAssistant: _core_ai__WEBPACK_IMPORTED_MODULE_20__.AIAssistant,\n AGENTS: _core_ai__WEBPACK_IMPORTED_MODULE_20__.AGENTS\n}); /* !DEVCODE*/\n// #endregion Globals\n// #region ████████ SYSTEM INITIALIZATION: Initializing Blades In The Dark System on 'Init' Hook ████████\nHooks.once(\"init\", async () => {\n // Initialize Game object\n game.eunoblades = {\n Rolls: new Collection(),\n ClockKeys: new Collection(),\n Consequences: new Collection(),\n Director: _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getInstance(),\n Tooltips: new WeakMap()\n };\n eLog.display(\"Initializing Blades In the Dark System\");\n // Register System Settings\n (0,_core_settings__WEBPACK_IMPORTED_MODULE_1__[\"default\"])();\n CONFIG.debug.hooks = _core_utilities__WEBPACK_IMPORTED_MODULE_4__[\"default\"].getSetting(\"debugHooks\");\n // Initialize Fonts & Gsap Animations\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_6__.Initialize)();\n CONFIG.Item.documentClass = _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__[\"default\"];\n CONFIG.Actor.documentClass = _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__[\"default\"];\n CONFIG.Scene.documentClass = _classes_BladesScene__WEBPACK_IMPORTED_MODULE_10__[\"default\"];\n CONFIG.ChatMessage.documentClass = _classes_BladesChat__WEBPACK_IMPORTED_MODULE_3__[\"default\"];\n // Register sheet application classes\n Actors.unregisterSheet(\"core\", ActorSheet);\n Items.unregisterSheet(\"core\", ItemSheet);\n Items.registerSheet(\"blades\", _sheets_item_BladesItemSheet__WEBPACK_IMPORTED_MODULE_13__[\"default\"], { types: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ItemTypes, makeDefault: true });\n (0,_core_helpers__WEBPACK_IMPORTED_MODULE_2__.registerHandlebarHelpers)();\n (0,_core_helpers__WEBPACK_IMPORTED_MODULE_2__.preloadHandlebarsTemplates)();\n // Initialize preliminary classes with templates to load\n await Promise.all([\n _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesPC.Initialize(),\n _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesCrew.Initialize(),\n _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesNPC.Initialize(),\n _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_11__.BladesFaction.Initialize(),\n _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_21__[\"default\"].Initialize(),\n _sheets_item_BladesGMTrackerSheet__WEBPACK_IMPORTED_MODULE_22__[\"default\"].Initialize(),\n _sheets_item_BladesClockKeeperSheet__WEBPACK_IMPORTED_MODULE_23__[\"default\"].Initialize(),\n _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesScore.Initialize(),\n _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_19__[\"default\"].Initialize(),\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__[\"default\"].Initialize(),\n _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesProject.Initialize(),\n _classes_BladesChat__WEBPACK_IMPORTED_MODULE_3__[\"default\"].Initialize()\n ]);\n});\nHooks.once(\"ready\", async () => {\n // Initialize overlays\n await Promise.all([\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__[\"default\"].Initialize(),\n _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesGMTracker.Initialize(),\n _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_12__.BladesClockKeeper.Initialize()\n ]);\n // Initialize Clocks, ClockKeys & Consequences\n _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_7__[\"default\"].Initialize();\n await _classes_BladesConsequence__WEBPACK_IMPORTED_MODULE_9__[\"default\"].Initialize();\n (0,_core_settings__WEBPACK_IMPORTED_MODULE_1__.initDOMStyles)();\n (0,_core_settings__WEBPACK_IMPORTED_MODULE_1__.initCanvasStyles)();\n (0,_core_settings__WEBPACK_IMPORTED_MODULE_1__.initTinyMCEStyles)();\n await _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__[\"default\"].getInstance().renderOverlay_SocketResponse();\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_8__[\"default\"].InitSockets();\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_18__[\"default\"].InitSockets();\n});\n// #endregion ▄▄▄▄▄ SYSTEM INITIALIZATION ▄▄▄▄▄\n// #region ░░░░░░░[SocketLib]░░░░ SocketLib Initialization ░░░░░░░ ~\nHooks.once(\"socketlib.ready\", () => {\n socket = socketlib.registerSystem(\"eunos-blades\");\n /* DEVCODE*/ Object.assign(globalThis, { socket, socketlib }); /* !DEVCODE*/\n});\nHooks.once(\"diceSoNiceReady\", (dice3d) => {\n dice3d.addSystem({ id: \"eunos-blades\", name: \"Euno's Blades\" }, \"preferred\");\n dice3d.addDicePreset({\n type: \"d6\",\n labels: [1, 2, 3, 4, 5, 6].map((num) => `systems/eunos-blades/assets/dice/faces/${num}.webp`),\n system: \"eunos-blades\",\n bumpMaps: [1, 2, 3, 4, 5, 6].map((num) => `systems/eunos-blades/assets/dice/bump-maps/${num}.webp`),\n emissiveMaps: [undefined, undefined, undefined, undefined, undefined, \"systems/eunos-blades/assets/dice/emission-maps/6.webp\"],\n emissive: \"#d89300\"\n });\n});\n// #endregion ░░░░[Dice So Nice]░░░░\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9ibGFkZXMudHMiLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUNBO0FBQzREO0FBQzJDO0FBQ2pCO0FBQ3hDO0FBQ2I7QUFDRTtBQUMyQjtBQUNSO0FBQ0E7QUFDTTtBQUNaO0FBQzZFO0FBQzZCO0FBQzlGO0FBQ0g7QUFDSTtBQUNGO0FBQ1E7QUFDMk47QUFDNU87QUFDUTtBQUNNO0FBQ007QUFDSTtBQUMxRTtBQUN1QztBQUN2QztBQUNBLDRCQUE0QixNQUFNLG9EQUFNLGFBQWEsd0RBQUU7QUFDdkQsa0NBQWtDLG9EQUFNO0FBQ3hDO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIsaUJBQWlCLE9BQU8sNERBQVU7QUFDbEMsaUJBQWlCO0FBQ2pCLGtCQUFrQjtBQUNsQix1QkFBdUI7QUFDdkIscUJBQXFCO0FBQ3JCLHNCQUFzQjtBQUN0Qix1QkFBdUI7QUFDdkIsd0JBQXdCO0FBQ3hCLDJCQUEyQjtBQUMzQiwyQkFBMkI7QUFDM0Isc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IscURBQVE7QUFDOUIsdUJBQXVCLHdEQUFXO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLFFBQVEsa0VBQWdCO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlO0FBQ2Ysa0JBQWtCO0FBQ2xCLGVBQWU7QUFDZixZQUFZO0FBQ1osY0FBYztBQUNkLGFBQWE7QUFDYixpQkFBaUI7QUFDakIsaUJBQWlCO0FBQ2pCLG1CQUFtQjtBQUNuQixzQkFBc0I7QUFDdEIsa0JBQWtCO0FBQ2xCLGtCQUFrQjtBQUNsQixzQkFBc0I7QUFDdEIsY0FBYztBQUNkLGlCQUFpQjtBQUNqQixxQkFBcUI7QUFDckIsd0JBQXdCO0FBQ3hCLHlCQUF5QjtBQUN6QixvQkFBb0I7QUFDcEIsd0JBQXdCO0FBQ3hCLHFCQUFxQjtBQUNyQiwyQkFBMkI7QUFDM0IseUJBQXlCO0FBQ3pCLDhCQUE4QjtBQUM5Qix3QkFBd0I7QUFDeEIsY0FBYztBQUNkLHFCQUFxQjtBQUNyQixLQUFLO0FBQ0wsS0FBSztBQUNMLEtBQUs7QUFDTCxjQUFjO0FBQ2QscUJBQXFCO0FBQ3JCLG1CQUFtQjtBQUNuQixrQkFBa0I7QUFDbEIsaUJBQWlCO0FBQ2pCLGVBQWU7QUFDZixtQkFBbUI7QUFDbkIsMEJBQTBCO0FBQzFCLHdCQUF3QjtBQUN4QixZQUFZO0FBQ1osZUFBZTtBQUNmLFVBQVU7QUFDVixDQUFDLEdBQUc7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLCtEQUFjO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSSwwREFBZ0I7QUFDcEIseUJBQXlCLHVEQUFDO0FBQzFCO0FBQ0EsSUFBSSxzREFBYztBQUNsQixnQ0FBZ0MsbUVBQWU7QUFDL0MsaUNBQWlDLG9FQUFnQjtBQUNqRCxpQ0FBaUMsNkRBQVc7QUFDNUMsdUNBQXVDLDJEQUFVO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyxxRUFBZSxJQUFJLE9BQU8sdURBQUMsK0JBQStCO0FBQzVGLElBQUksdUVBQXdCO0FBQzVCLElBQUkseUVBQTBCO0FBQzlCO0FBQ0E7QUFDQSxRQUFRLGtFQUFRO0FBQ2hCLFFBQVEsb0VBQVU7QUFDbEIsUUFBUSxtRUFBUztBQUNqQixRQUFRLHVFQUFhO0FBQ3JCLFFBQVEsc0VBQWtCO0FBQzFCLFFBQVEsMEVBQW9CO0FBQzVCLFFBQVEsNEVBQXNCO0FBQzlCLFFBQVEsb0VBQVc7QUFDbkIsUUFBUSw4REFBWTtBQUNwQixRQUFRLDREQUFVO0FBQ2xCLFFBQVEsc0VBQWE7QUFDckIsUUFBUSwyREFBVTtBQUNsQjtBQUNBLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQSxRQUFRLCtEQUFjO0FBQ3RCLFFBQVEsd0VBQWU7QUFDdkIsUUFBUSwwRUFBaUI7QUFDekI7QUFDQTtBQUNBLElBQUksK0RBQWM7QUFDbEIsVUFBVSxrRUFBaUI7QUFDM0IsSUFBSSw2REFBYTtBQUNqQixJQUFJLGdFQUFnQjtBQUNwQixJQUFJLGlFQUFpQjtBQUNyQixVQUFVLCtEQUFjO0FBQ3hCLElBQUksK0RBQWM7QUFDbEIsSUFBSSw0REFBVTtBQUNkLENBQUM7QUFDRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxtQkFBbUIsR0FBRztBQUNuRSxDQUFDO0FBQ0Q7QUFDQSx1QkFBdUIsMkNBQTJDO0FBQ2xFO0FBQ0E7QUFDQSwwRkFBMEYsSUFBSTtBQUM5RjtBQUNBLGdHQUFnRyxJQUFJO0FBQ3BHO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsQ0FBQztBQUNEIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvYmxhZGVzLnRzP2Y0N2UiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG4vLyAjcmVnaW9uIOKWruKWruKWruKWruKWruKWruKWriBJTVBPUlRTIOKWruKWruKWruKWruKWruKWruKWriB+XG5pbXBvcnQgQywgeyBBY3Rpb25UcmFpdCwgUm9sbFR5cGUgfSBmcm9tIFwiLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IHJlZ2lzdGVyU2V0dGluZ3MsIHsgaW5pdFRpbnlNQ0VTdHlsZXMsIGluaXRDYW52YXNTdHlsZXMsIGluaXRET01TdHlsZXMgfSBmcm9tIFwiLi9jb3JlL3NldHRpbmdzXCI7XG5pbXBvcnQgeyByZWdpc3RlckhhbmRsZWJhckhlbHBlcnMsIHByZWxvYWRIYW5kbGViYXJzVGVtcGxhdGVzIH0gZnJvbSBcIi4vY29yZS9oZWxwZXJzXCI7XG5pbXBvcnQgQmxhZGVzQ2hhdCBmcm9tIFwiLi9jbGFzc2VzL0JsYWRlc0NoYXRcIjtcbmltcG9ydCBVIGZyb20gXCIuL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgbG9nZ2VyIGZyb20gXCIuL2NvcmUvbG9nZ2VyXCI7XG5pbXBvcnQgRywgeyBJbml0aWFsaXplIGFzIEdzYXBJbml0aWFsaXplIH0gZnJvbSBcIi4vY29yZS9nc2FwXCI7XG5pbXBvcnQgQmxhZGVzQ2xvY2tLZXkgZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNDbG9ja0tleVwiO1xuaW1wb3J0IEJsYWRlc0RpcmVjdG9yIGZyb20gXCIuL2NsYXNzZXMvQmxhZGVzRGlyZWN0b3JcIjtcbmltcG9ydCBCbGFkZXNDb25zZXF1ZW5jZSBmcm9tIFwiLi9jbGFzc2VzL0JsYWRlc0NvbnNlcXVlbmNlXCI7XG5pbXBvcnQgQmxhZGVzU2NlbmUgZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNTY2VuZVwiO1xuaW1wb3J0IEJsYWRlc0FjdG9yUHJveHksIHsgQmxhZGVzQWN0b3IsIEJsYWRlc1BDLCBCbGFkZXNDcmV3LCBCbGFkZXNOUEMsIEJsYWRlc0ZhY3Rpb24gfSBmcm9tIFwiLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuaW1wb3J0IEJsYWRlc0l0ZW1Qcm94eSwgeyBCbGFkZXNJdGVtLCBCbGFkZXNDbG9ja0tlZXBlciwgQmxhZGVzR01UcmFja2VyLCBCbGFkZXNMb2NhdGlvbiwgQmxhZGVzU2NvcmUsIEJsYWRlc1Byb2plY3QgfSBmcm9tIFwiLi9kb2N1bWVudHMvQmxhZGVzSXRlbVByb3h5XCI7XG5pbXBvcnQgQmxhZGVzSXRlbVNoZWV0IGZyb20gXCIuL3NoZWV0cy9pdGVtL0JsYWRlc0l0ZW1TaGVldFwiO1xuaW1wb3J0IEJsYWRlc1BDU2hlZXQgZnJvbSBcIi4vc2hlZXRzL2FjdG9yL0JsYWRlc1BDU2hlZXRcIjtcbmltcG9ydCBCbGFkZXNDcmV3U2hlZXQgZnJvbSBcIi4vc2hlZXRzL2FjdG9yL0JsYWRlc0NyZXdTaGVldFwiO1xuaW1wb3J0IEJsYWRlc05QQ1NoZWV0IGZyb20gXCIuL3NoZWV0cy9hY3Rvci9CbGFkZXNOUENTaGVldFwiO1xuaW1wb3J0IEJsYWRlc0ZhY3Rpb25TaGVldCBmcm9tIFwiLi9zaGVldHMvYWN0b3IvQmxhZGVzRmFjdGlvblNoZWV0XCI7XG5pbXBvcnQgQmxhZGVzUm9sbCwgeyBCbGFkZXNSb2xsTW9kLCBCbGFkZXNSb2xsUHJpbWFyeSwgQmxhZGVzUm9sbE9wcG9zaXRpb24sIEJsYWRlc1JvbGxQYXJ0aWNpcGFudCwgQmxhZGVzQWN0aW9uUm9sbCwgQmxhZGVzRW5nYWdlbWVudFJvbGwsIEJsYWRlc0ZvcnR1bmVSb2xsLCBCbGFkZXNJbmNhcmNlcmF0aW9uUm9sbCwgQmxhZGVzSW5kdWxnZVZpY2VSb2xsLCBCbGFkZXNJbmxpbmVSZXNpc3RhbmNlUm9sbCwgQmxhZGVzUmVzaXN0YW5jZVJvbGwgfSBmcm9tIFwiLi9jbGFzc2VzL0JsYWRlc1JvbGxcIjtcbmltcG9ydCBCbGFkZXNEaWFsb2cgZnJvbSBcIi4vY2xhc3Nlcy9CbGFkZXNEaWFsb2dcIjtcbmltcG9ydCBCbGFkZXNBSSwgeyBBR0VOVFMsIEFJQXNzaXN0YW50IH0gZnJvbSBcIi4vY29yZS9haVwiO1xuaW1wb3J0IEJsYWRlc0FjdGl2ZUVmZmVjdCBmcm9tIFwiLi9kb2N1bWVudHMvQmxhZGVzQWN0aXZlRWZmZWN0XCI7XG5pbXBvcnQgQmxhZGVzR01UcmFja2VyU2hlZXQgZnJvbSBcIi4vc2hlZXRzL2l0ZW0vQmxhZGVzR01UcmFja2VyU2hlZXRcIjtcbmltcG9ydCBCbGFkZXNDbG9ja0tlZXBlclNoZWV0IGZyb20gXCIuL3NoZWV0cy9pdGVtL0JsYWRlc0Nsb2NrS2VlcGVyU2hlZXRcIjtcbi8qIERFVkNPREUqL1xuaW1wb3J0IEJsYWRlc0RlYnVnIGZyb20gXCIuL2NvcmUvZGVidWdcIjtcbkNPTkZJRy5kZWJ1Zy5sb2dnaW5nID0gdHJ1ZTtcbk9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywgeyBlTG9nOiBsb2dnZXIsIEJsYWRlc0RlYnVnIH0pO1xuSGFuZGxlYmFycy5yZWdpc3RlckhlbHBlcihcImVMb2dcIiwgbG9nZ2VyLmhic0xvZyk7XG4vKiAhREVWQ09ERSovXG5sZXQgc29ja2V0OyAvLyB+IFNvY2tldExpYiBpbnRlcmZhY2Vcbi8vICNlbmRyZWdpb24g4pau4pau4pau4pauW0lNUE9SVFNd4pau4pau4pau4pauXG5jbGFzcyBHbG9iYWxHZXR0ZXIge1xuICAgIGdldCBjbG9ja0tleXMoKSB7IHJldHVybiBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmZpbHRlcigoY2xvY2tLZXkpID0+IGNsb2NrS2V5LmlzSW5TY2VuZSgpICYmIGNsb2NrS2V5LmlzVmlzaWJsZSk7IH1cbiAgICBnZXQgcm9sbCgpIHsgcmV0dXJuIEJsYWRlc1JvbGwuQWN0aXZlOyB9XG4gICAgZ2V0IHVzZXIoKSB7IHJldHVybiBnYW1lLnVzZXJzLmdldE5hbWUoXCJBbGlzdGFpclwiKTsgfVxuICAgIGdldCBhY3RvcigpIHsgcmV0dXJuIGdhbWUuYWN0b3JzLmdldE5hbWUoXCJBbGlzdGFpclwiKTsgfVxuICAgIGdldCByb2xsVGFyZ2V0KCkgeyByZXR1cm4gdGhpcy5yb2xsPy50YXJnZXQ7IH1cbiAgICBnZXQgcm9sbERhdGEoKSB7IHJldHVybiB0aGlzLnJvbGw/LmRhdGE7IH1cbiAgICBnZXQgdXNlckZsYWdzKCkgeyByZXR1cm4gdGhpcy51c2VyPy5mbGFncz8uW1wiZXVub3MtYmxhZGVzXCJdOyB9XG4gICAgZ2V0IGFjdG9yRmxhZ3MoKSB7IHJldHVybiB0aGlzLmFjdG9yPy5mbGFncz8uW1wiZXVub3MtYmxhZGVzXCJdOyB9XG4gICAgZ2V0IHJvbGxQcmltYXJ5KCkgeyByZXR1cm4gdGhpcy5yb2xsPy5yb2xsUHJpbWFyeTsgfVxuICAgIGdldCByb2xsUHJpbWFyeURvYygpIHsgcmV0dXJuIHRoaXMucm9sbD8ucm9sbFByaW1hcnlEb2M7IH1cbiAgICBnZXQgcm9sbE9wcG9zaXRpb24oKSB7IHJldHVybiB0aGlzLnJvbGw/LnJvbGxPcHBvc2l0aW9uOyB9XG4gICAgZ2V0IHNoZWV0RGF0YSgpIHsgcmV0dXJuIHRoaXMucm9sbD8uY29udGV4dDsgfVxuICAgIG5ld0FjdGlvblJvbGwoKSB7XG4gICAgICAgIGNvbnN0IHBjID0gZ2FtZS5hY3RvcnMuZ2V0TmFtZShcIkFsaXN0YWlyXCIpO1xuICAgICAgICBpZiAoIXBjKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY29uZiA9IHtcbiAgICAgICAgICAgIHRhcmdldDogcGMsXG4gICAgICAgICAgICB0YXJnZXRGbGFnS2V5OiBcInJvbGxDb2xsYWJcIixcbiAgICAgICAgICAgIHJvbGxUeXBlOiBSb2xsVHlwZS5BY3Rpb24sXG4gICAgICAgICAgICByb2xsVHJhaXQ6IEFjdGlvblRyYWl0LmZpbmVzc2UsXG4gICAgICAgICAgICByb2xsVXNlcklEOiBnYW1lLnVzZXJzLmZpbmQoKHVzZXIpID0+IHVzZXIuY2hhcmFjdGVyPy5uYW1lID09PSBcIkFsaXN0YWlyXCIpPy5pZCxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5RGF0YTogcGNcbiAgICAgICAgfTtcbiAgICAgICAgQmxhZGVzQWN0aW9uUm9sbC5OZXcoY29uZik7XG4gICAgfVxufVxuLy8gI3JlZ2lvbiBHbG9iYWxzOiBFeHBvc2luZyBGdW5jdGlvbmFsaXR5IHRvIEdsb2JhbCBTY29wZSB+XG4vKiBERVZDT0RFKi8gT2JqZWN0LmFzc2lnbihnbG9iYWxUaGlzLCB7XG4gICAgZ2V0OiBuZXcgR2xvYmFsR2V0dGVyKCksXG4gICAgLy8gdXBkYXRlQ2xhaW1zLFxuICAgIC8vIHVwZGF0ZUNvbnRhY3RzLFxuICAgIC8vIHVwZGF0ZU9wcyxcbiAgICAvLyB1cGRhdGVGYWN0aW9ucyxcbiAgICAvLyB1cGRhdGVEZXNjcmlwdGlvbnMsXG4gICAgLy8gdXBkYXRlUm9sbE1vZHMsXG4gICAgQmxhZGVzU2NlbmUsXG4gICAgQmxhZGVzRGlyZWN0b3IsXG4gICAgQmxhZGVzQWN0b3IsXG4gICAgQmxhZGVzUEMsXG4gICAgQmxhZGVzQ3JldyxcbiAgICBCbGFkZXNOUEMsXG4gICAgQmxhZGVzRmFjdGlvbixcbiAgICBCbGFkZXNQQ1NoZWV0LFxuICAgIEJsYWRlc0NyZXdTaGVldCxcbiAgICBCbGFkZXNGYWN0aW9uU2hlZXQsXG4gICAgQmxhZGVzQ2xvY2tLZXksXG4gICAgQmxhZGVzTlBDU2hlZXQsXG4gICAgQmxhZGVzQWN0aXZlRWZmZWN0LFxuICAgIEJsYWRlc1JvbGwsXG4gICAgQmxhZGVzUm9sbE1vZCxcbiAgICBCbGFkZXNSb2xsUHJpbWFyeSxcbiAgICBCbGFkZXNSb2xsT3Bwb3NpdGlvbixcbiAgICBCbGFkZXNSb2xsUGFydGljaXBhbnQsXG4gICAgQmxhZGVzQWN0aW9uUm9sbCxcbiAgICBCbGFkZXNFbmdhZ2VtZW50Um9sbCxcbiAgICBCbGFkZXNGb3J0dW5lUm9sbCxcbiAgICBCbGFkZXNJbmNhcmNlcmF0aW9uUm9sbCxcbiAgICBCbGFkZXNJbmR1bGdlVmljZVJvbGwsXG4gICAgQmxhZGVzSW5saW5lUmVzaXN0YW5jZVJvbGwsXG4gICAgQmxhZGVzUmVzaXN0YW5jZVJvbGwsXG4gICAgQmxhZGVzQ2hhdCxcbiAgICBCbGFkZXNDb25zZXF1ZW5jZSxcbiAgICBHLFxuICAgIFUsXG4gICAgQyxcbiAgICBCbGFkZXNJdGVtLFxuICAgIEJsYWRlc0Nsb2NrS2VlcGVyLFxuICAgIEJsYWRlc0dNVHJhY2tlcixcbiAgICBCbGFkZXNMb2NhdGlvbixcbiAgICBCbGFkZXNQcm9qZWN0LFxuICAgIEJsYWRlc1Njb3JlLFxuICAgIEJsYWRlc0l0ZW1TaGVldCxcbiAgICBCbGFkZXNDbG9ja0tlZXBlclNoZWV0LFxuICAgIEJsYWRlc0dNVHJhY2tlclNoZWV0LFxuICAgIEJsYWRlc0FJLFxuICAgIEFJQXNzaXN0YW50LFxuICAgIEFHRU5UU1xufSk7IC8qICFERVZDT0RFKi9cbi8vICNlbmRyZWdpb24gR2xvYmFsc1xuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggU1lTVEVNIElOSVRJQUxJWkFUSU9OOiBJbml0aWFsaXppbmcgQmxhZGVzIEluIFRoZSBEYXJrIFN5c3RlbSBvbiAnSW5pdCcgSG9vayDilojilojilojilojilojilojilojilohcbkhvb2tzLm9uY2UoXCJpbml0XCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBJbml0aWFsaXplIEdhbWUgb2JqZWN0XG4gICAgZ2FtZS5ldW5vYmxhZGVzID0ge1xuICAgICAgICBSb2xsczogbmV3IENvbGxlY3Rpb24oKSxcbiAgICAgICAgQ2xvY2tLZXlzOiBuZXcgQ29sbGVjdGlvbigpLFxuICAgICAgICBDb25zZXF1ZW5jZXM6IG5ldyBDb2xsZWN0aW9uKCksXG4gICAgICAgIERpcmVjdG9yOiBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLFxuICAgICAgICBUb29sdGlwczogbmV3IFdlYWtNYXAoKVxuICAgIH07XG4gICAgZUxvZy5kaXNwbGF5KFwiSW5pdGlhbGl6aW5nIEJsYWRlcyBJbiB0aGUgRGFyayBTeXN0ZW1cIik7XG4gICAgLy8gUmVnaXN0ZXIgU3lzdGVtIFNldHRpbmdzXG4gICAgcmVnaXN0ZXJTZXR0aW5ncygpO1xuICAgIENPTkZJRy5kZWJ1Zy5ob29rcyA9IFUuZ2V0U2V0dGluZyhcImRlYnVnSG9va3NcIik7XG4gICAgLy8gSW5pdGlhbGl6ZSBGb250cyAmIEdzYXAgQW5pbWF0aW9uc1xuICAgIEdzYXBJbml0aWFsaXplKCk7XG4gICAgQ09ORklHLkl0ZW0uZG9jdW1lbnRDbGFzcyA9IEJsYWRlc0l0ZW1Qcm94eTtcbiAgICBDT05GSUcuQWN0b3IuZG9jdW1lbnRDbGFzcyA9IEJsYWRlc0FjdG9yUHJveHk7XG4gICAgQ09ORklHLlNjZW5lLmRvY3VtZW50Q2xhc3MgPSBCbGFkZXNTY2VuZTtcbiAgICBDT05GSUcuQ2hhdE1lc3NhZ2UuZG9jdW1lbnRDbGFzcyA9IEJsYWRlc0NoYXQ7XG4gICAgLy8gUmVnaXN0ZXIgc2hlZXQgYXBwbGljYXRpb24gY2xhc3Nlc1xuICAgIEFjdG9ycy51bnJlZ2lzdGVyU2hlZXQoXCJjb3JlXCIsIEFjdG9yU2hlZXQpO1xuICAgIEl0ZW1zLnVucmVnaXN0ZXJTaGVldChcImNvcmVcIiwgSXRlbVNoZWV0KTtcbiAgICBJdGVtcy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc0l0ZW1TaGVldCwgeyB0eXBlczogQy5JdGVtVHlwZXMsIG1ha2VEZWZhdWx0OiB0cnVlIH0pO1xuICAgIHJlZ2lzdGVySGFuZGxlYmFySGVscGVycygpO1xuICAgIHByZWxvYWRIYW5kbGViYXJzVGVtcGxhdGVzKCk7XG4gICAgLy8gSW5pdGlhbGl6ZSBwcmVsaW1pbmFyeSBjbGFzc2VzIHdpdGggdGVtcGxhdGVzIHRvIGxvYWRcbiAgICBhd2FpdCBQcm9taXNlLmFsbChbXG4gICAgICAgIEJsYWRlc1BDLkluaXRpYWxpemUoKSxcbiAgICAgICAgQmxhZGVzQ3Jldy5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc05QQy5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc0ZhY3Rpb24uSW5pdGlhbGl6ZSgpLFxuICAgICAgICBCbGFkZXNBY3RpdmVFZmZlY3QuSW5pdGlhbGl6ZSgpLFxuICAgICAgICBCbGFkZXNHTVRyYWNrZXJTaGVldC5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc0Nsb2NrS2VlcGVyU2hlZXQuSW5pdGlhbGl6ZSgpLFxuICAgICAgICBCbGFkZXNTY29yZS5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc0RpYWxvZy5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc1JvbGwuSW5pdGlhbGl6ZSgpLFxuICAgICAgICBCbGFkZXNQcm9qZWN0LkluaXRpYWxpemUoKSxcbiAgICAgICAgQmxhZGVzQ2hhdC5Jbml0aWFsaXplKClcbiAgICBdKTtcbn0pO1xuSG9va3Mub25jZShcInJlYWR5XCIsIGFzeW5jICgpID0+IHtcbiAgICAvLyBJbml0aWFsaXplIG92ZXJsYXlzXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICBCbGFkZXNEaXJlY3Rvci5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc0dNVHJhY2tlci5Jbml0aWFsaXplKCksXG4gICAgICAgIEJsYWRlc0Nsb2NrS2VlcGVyLkluaXRpYWxpemUoKVxuICAgIF0pO1xuICAgIC8vIEluaXRpYWxpemUgQ2xvY2tzLCBDbG9ja0tleXMgJiBDb25zZXF1ZW5jZXNcbiAgICBCbGFkZXNDbG9ja0tleS5Jbml0aWFsaXplKCk7XG4gICAgYXdhaXQgQmxhZGVzQ29uc2VxdWVuY2UuSW5pdGlhbGl6ZSgpO1xuICAgIGluaXRET01TdHlsZXMoKTtcbiAgICBpbml0Q2FudmFzU3R5bGVzKCk7XG4gICAgaW5pdFRpbnlNQ0VTdHlsZXMoKTtcbiAgICBhd2FpdCBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnJlbmRlck92ZXJsYXlfU29ja2V0UmVzcG9uc2UoKTtcbiAgICBCbGFkZXNEaXJlY3Rvci5Jbml0U29ja2V0cygpO1xuICAgIEJsYWRlc1JvbGwuSW5pdFNvY2tldHMoKTtcbn0pO1xuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgU1lTVEVNIElOSVRJQUxJWkFUSU9OIOKWhOKWhOKWhOKWhOKWhFxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbU29ja2V0TGliXeKWkeKWkeKWkeKWkSBTb2NrZXRMaWIgSW5pdGlhbGl6YXRpb24g4paR4paR4paR4paR4paR4paR4paRIH5cbkhvb2tzLm9uY2UoXCJzb2NrZXRsaWIucmVhZHlcIiwgKCkgPT4ge1xuICAgIHNvY2tldCA9IHNvY2tldGxpYi5yZWdpc3RlclN5c3RlbShcImV1bm9zLWJsYWRlc1wiKTtcbiAgICAvKiBERVZDT0RFKi8gT2JqZWN0LmFzc2lnbihnbG9iYWxUaGlzLCB7IHNvY2tldCwgc29ja2V0bGliIH0pOyAvKiAhREVWQ09ERSovXG59KTtcbkhvb2tzLm9uY2UoXCJkaWNlU29OaWNlUmVhZHlcIiwgKGRpY2UzZCkgPT4ge1xuICAgIGRpY2UzZC5hZGRTeXN0ZW0oeyBpZDogXCJldW5vcy1ibGFkZXNcIiwgbmFtZTogXCJFdW5vJ3MgQmxhZGVzXCIgfSwgXCJwcmVmZXJyZWRcIik7XG4gICAgZGljZTNkLmFkZERpY2VQcmVzZXQoe1xuICAgICAgICB0eXBlOiBcImQ2XCIsXG4gICAgICAgIGxhYmVsczogWzEsIDIsIDMsIDQsIDUsIDZdLm1hcCgobnVtKSA9PiBgc3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2RpY2UvZmFjZXMvJHtudW19LndlYnBgKSxcbiAgICAgICAgc3lzdGVtOiBcImV1bm9zLWJsYWRlc1wiLFxuICAgICAgICBidW1wTWFwczogWzEsIDIsIDMsIDQsIDUsIDZdLm1hcCgobnVtKSA9PiBgc3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2RpY2UvYnVtcC1tYXBzLyR7bnVtfS53ZWJwYCksXG4gICAgICAgIGVtaXNzaXZlTWFwczogW3VuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9kaWNlL2VtaXNzaW9uLW1hcHMvNi53ZWJwXCJdLFxuICAgICAgICBlbWlzc2l2ZTogXCIjZDg5MzAwXCJcbiAgICB9KTtcbn0pO1xuLy8gI2VuZHJlZ2lvbiDilpHilpHilpHilpFbRGljZSBTbyBOaWNlXeKWkeKWkeKWkeKWkVxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/blades.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesChat.ts": +/*!**********************************!*\ + !*** ./ts/classes/BladesChat.ts ***! + \**********************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesRoll__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* harmony import */ var _BladesConsequence__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./BladesConsequence */ \"./ts/classes/BladesConsequence.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region IMPORTS ~\n\n\n\n\n\nclass BladesChat extends ChatMessage {\n static Initialize() {\n Hooks.on(\"renderChatMessage\", (msg, html) => {\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_0__.ApplyTooltipAnimations)(html);\n const { rollData } = msg.flagData;\n if (rollData) {\n _BladesConsequence__WEBPACK_IMPORTED_MODULE_4__[\"default\"].ApplyChatListeners(msg);\n }\n html.addClass(\"display-ok\");\n });\n return loadTemplates([\n \"systems/eunos-blades/templates/chat/roll-result/action.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/action-clock.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/action-acquireasset.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/action-reduceheat.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/action-clock-recover.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/action-gatherinfo.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/fortune.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/fortune-clock.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/fortune-gatherinfo.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/fortune-incarceration.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/fortune-engagement.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/indulgevice.hbs\",\n \"systems/eunos-blades/templates/chat/roll-result/resistance.hbs\",\n \"systems/eunos-blades/templates/chat/components/inline-resistance.hbs\",\n \"systems/eunos-blades/templates/chat/components/die.hbs\"\n ]);\n }\n // static async ConstructRollOutput(rollInst: BladesRoll): Promise {\n // const rollData = {\n // ...rollInst.data,\n // rollTraitVerb: rollInst.rollTraitVerb ?? \"\",\n // rollTraitPastVerb: rollInst.rollTraitPastVerb ?? rollInst.rollTraitVerb ?? \"\"\n // };\n // return await BladesChat.create({\n // speaker: rollInst.getSpeaker(BladesChat.getSpeaker()),\n // content: await renderTemplate(rollInst.template, rollData),\n // type: CONST.CHAT_MESSAGE_TYPES.ROLL,\n // flags: {\n // \"eunos-blades\": {\n // template: rollInst.template,\n // rollData\n // }\n // }\n // }) as BladesChat;\n // }\n static IsNewestRollResult(rollInst) {\n const lastRollResultID = $(\"#chat-log .chat-message .blades-roll:not(.inline-roll)\")\n .last()\n .attr(\"id\");\n return typeof lastRollResultID === \"string\"\n && lastRollResultID === rollInst.id;\n }\n get flagData() {\n return this.flags[\"eunos-blades\"];\n }\n get rollData() { return this.flagData.rollData; }\n async setFlagVal(scope, key, val) {\n return await this.setFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, `${scope}.${key}`, val);\n }\n get allRollConsequences() {\n const returnData = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.controlled]: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.critical]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.success]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail]: {}\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.risky]: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.critical]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.success]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail]: {}\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.desperate]: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.critical]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.success]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial]: {},\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail]: {}\n }\n };\n const { consequenceData } = this.flagData.rollData ?? {};\n if (!consequenceData) {\n return returnData;\n }\n Object.entries(consequenceData)\n .forEach(([position, positionData]) => {\n Object.entries(positionData)\n .forEach(([rollResult, csqDataSet]) => {\n returnData[position][rollResult] = Object.fromEntries(Object.entries(csqDataSet)\n .filter(([id, cData]) => cData.id)\n .map(([id, cData]) => [\n id,\n game.eunoblades.Consequences.get(cData.id) ?? new _BladesConsequence__WEBPACK_IMPORTED_MODULE_4__[\"default\"](cData)\n ]));\n });\n });\n return returnData;\n }\n get rollConsequences() {\n if (!this.parentRoll) {\n return [];\n }\n const { rollPositionFinal, rollResult, consequenceData } = this.parentRoll.data;\n if (!rollPositionFinal || !rollResult || !consequenceData) {\n return [];\n }\n if (typeof rollResult !== \"string\" || ![_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail].includes(rollResult)) {\n return [];\n }\n const activeConsequences = consequenceData?.[rollPositionFinal]?.[rollResult] ?? {};\n return Object.values(activeConsequences)\n .map((cData) => game.eunoblades.Consequences.get(cData.id) ?? new _BladesConsequence__WEBPACK_IMPORTED_MODULE_4__[\"default\"](cData));\n }\n get elem$() {\n return $(\"#chat-log\")\n .find(`.chat-message[data-message-id=\"${this.id}\"]`);\n }\n get elem() { return this.elem$[0]; }\n get isRollResult() { return \"rollData\" in this.flagData; }\n get parentRoll() {\n if (!this.isRollResult) {\n return undefined;\n }\n const { rollData } = this.flagData;\n if (!rollData) {\n return undefined;\n }\n return game.eunoblades.Rolls.get(rollData.id ?? \"\") ?? new _BladesRoll__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({\n ...rollData,\n isScopingById: false\n });\n }\n get roll$() {\n return this.parentRoll ? this.elem$.find(`#${this.parentRoll.id}`) : undefined;\n }\n async regenerateFromFlags() {\n if (this.isRollResult) {\n await this.update({ content: await renderTemplate(this.flagData.template, this) });\n }\n }\n async render(force) {\n await super.render(force);\n await this.activateListeners();\n }\n async activateListeners() {\n if (!this.elem$) {\n eLog.error(\"BladesChat\", `No BladesChat.elem found for id ${this.id}.`);\n return;\n }\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_0__.ApplyTooltipAnimations)(this.elem$);\n _BladesConsequence__WEBPACK_IMPORTED_MODULE_4__[\"default\"].ApplyChatListeners(this);\n if (this.parentRoll) {\n this.elem$.addClass(`${this.parentRoll.rollType.toLowerCase()}-roll`);\n if (this.parentRoll.rollType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action && this.rollConsequences.some((csq) => !csq.isAccepted)) {\n this.elem$.addClass(\"unresolved-action-roll\");\n }\n else {\n this.elem$.removeClass(\"unresolved-action-roll\");\n }\n if (BladesChat.IsNewestRollResult(this.parentRoll)) {\n $(\"#chat-log .chat-message\").removeClass(\"active-chat-roll\");\n this.elem$.addClass(\"active-chat-roll\");\n }\n else {\n this.elem$.removeClass(\"active-chat-roll\");\n }\n }\n _core_utilities__WEBPACK_IMPORTED_MODULE_2__[\"default\"].gsap.to(this.elem$, { autoAlpha: 1, duration: 0.15, ease: \"none\" });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesChat);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jbGFzc2VzL0JsYWRlc0NoYXQudHMiLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7QUFDQTtBQUNzRDtBQUNnQjtBQUNwQztBQUNJO0FBQ2M7QUFDcEQ7QUFDQTtBQUNBO0FBQ0EsWUFBWSxrRUFBc0I7QUFDbEMsb0JBQW9CLFdBQVc7QUFDL0I7QUFDQSxnQkFBZ0IsMERBQWlCO0FBQ2pDO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLGtDQUFrQyx1REFBQyxlQUFlLE1BQU0sR0FBRyxJQUFJO0FBQy9EO0FBQ0E7QUFDQTtBQUNBLGFBQWEscURBQVE7QUFDckIsaUJBQWlCLHVEQUFVLGNBQWM7QUFDekMsaUJBQWlCLHVEQUFVLGFBQWE7QUFDeEMsaUJBQWlCLHVEQUFVLGFBQWE7QUFDeEMsaUJBQWlCLHVEQUFVO0FBQzNCLGFBQWE7QUFDYixhQUFhLHFEQUFRO0FBQ3JCLGlCQUFpQix1REFBVSxjQUFjO0FBQ3pDLGlCQUFpQix1REFBVSxhQUFhO0FBQ3hDLGlCQUFpQix1REFBVSxhQUFhO0FBQ3hDLGlCQUFpQix1REFBVTtBQUMzQixhQUFhO0FBQ2IsYUFBYSxxREFBUTtBQUNyQixpQkFBaUIsdURBQVUsY0FBYztBQUN6QyxpQkFBaUIsdURBQVUsYUFBYTtBQUN4QyxpQkFBaUIsdURBQVUsYUFBYTtBQUN4QyxpQkFBaUIsdURBQVU7QUFDM0I7QUFDQTtBQUNBLGdCQUFnQixrQkFBa0I7QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNFQUFzRSwwREFBaUI7QUFDdkY7QUFDQSxhQUFhO0FBQ2IsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixpREFBaUQ7QUFDakU7QUFDQTtBQUNBO0FBQ0EsZ0RBQWdELHVEQUFVLFVBQVUsdURBQVU7QUFDOUU7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4RUFBOEUsMERBQWlCO0FBQy9GO0FBQ0E7QUFDQTtBQUNBLG9EQUFvRCxRQUFRO0FBQzVEO0FBQ0EsaUJBQWlCO0FBQ2pCLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixXQUFXO0FBQzNCO0FBQ0E7QUFDQTtBQUNBLG1FQUFtRSxtREFBVTtBQUM3RTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxxREFBcUQsbUJBQW1CO0FBQ3hFO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQyw2REFBNkQ7QUFDN0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdFQUF3RSxRQUFRO0FBQ2hGO0FBQ0E7QUFDQSxRQUFRLGtFQUFzQjtBQUM5QixRQUFRLDBEQUFpQjtBQUN6QjtBQUNBLG1DQUFtQyx1Q0FBdUM7QUFDMUUsNkNBQTZDLHFEQUFRO0FBQ3JEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSx1REFBQyx1QkFBdUIsNENBQTRDO0FBQzVFO0FBQ0E7QUFDQSwrREFBZSxVQUFVLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jbGFzc2VzL0JsYWRlc0NoYXQudHM/ZjBhNCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbi8vICNyZWdpb24gSU1QT1JUUyB+XG5pbXBvcnQgeyBBcHBseVRvb2x0aXBBbmltYXRpb25zIH0gZnJvbSBcIi4uL2NvcmUvZ3NhcFwiO1xuaW1wb3J0IEMsIHsgUm9sbFR5cGUsIFBvc2l0aW9uLCBSb2xsUmVzdWx0IH0gZnJvbSBcIi4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgVSBmcm9tIFwiLi4vY29yZS91dGlsaXRpZXNcIjtcbmltcG9ydCBCbGFkZXNSb2xsIGZyb20gXCIuL0JsYWRlc1JvbGxcIjtcbmltcG9ydCBCbGFkZXNDb25zZXF1ZW5jZSBmcm9tIFwiLi9CbGFkZXNDb25zZXF1ZW5jZVwiO1xuY2xhc3MgQmxhZGVzQ2hhdCBleHRlbmRzIENoYXRNZXNzYWdlIHtcbiAgICBzdGF0aWMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgSG9va3Mub24oXCJyZW5kZXJDaGF0TWVzc2FnZVwiLCAobXNnLCBodG1sKSA9PiB7XG4gICAgICAgICAgICBBcHBseVRvb2x0aXBBbmltYXRpb25zKGh0bWwpO1xuICAgICAgICAgICAgY29uc3QgeyByb2xsRGF0YSB9ID0gbXNnLmZsYWdEYXRhO1xuICAgICAgICAgICAgaWYgKHJvbGxEYXRhKSB7XG4gICAgICAgICAgICAgICAgQmxhZGVzQ29uc2VxdWVuY2UuQXBwbHlDaGF0TGlzdGVuZXJzKG1zZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBodG1sLmFkZENsYXNzKFwiZGlzcGxheS1va1wiKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBsb2FkVGVtcGxhdGVzKFtcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NoYXQvcm9sbC1yZXN1bHQvYWN0aW9uLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9hY3Rpb24tY2xvY2suaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2FjdGlvbi1hY3F1aXJlYXNzZXQuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2FjdGlvbi1yZWR1Y2VoZWF0Lmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9hY3Rpb24tY2xvY2stcmVjb3Zlci5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NoYXQvcm9sbC1yZXN1bHQvYWN0aW9uLWdhdGhlcmluZm8uaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2ZvcnR1bmUuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2ZvcnR1bmUtY2xvY2suaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2ZvcnR1bmUtZ2F0aGVyaW5mby5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NoYXQvcm9sbC1yZXN1bHQvZm9ydHVuZS1pbmNhcmNlcmF0aW9uLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9mb3J0dW5lLWVuZ2FnZW1lbnQuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2luZHVsZ2V2aWNlLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9yZXNpc3RhbmNlLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9jb21wb25lbnRzL2lubGluZS1yZXNpc3RhbmNlLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9jb21wb25lbnRzL2RpZS5oYnNcIlxuICAgICAgICBdKTtcbiAgICB9XG4gICAgLy8gc3RhdGljIGFzeW5jIENvbnN0cnVjdFJvbGxPdXRwdXQocm9sbEluc3Q6IEJsYWRlc1JvbGwpOiBQcm9taXNlPEJsYWRlc0NoYXQ+IHtcbiAgICAvLyAgIGNvbnN0IHJvbGxEYXRhID0ge1xuICAgIC8vICAgICAuLi5yb2xsSW5zdC5kYXRhLFxuICAgIC8vICAgICByb2xsVHJhaXRWZXJiOiByb2xsSW5zdC5yb2xsVHJhaXRWZXJiID8/IFwiXCIsXG4gICAgLy8gICAgIHJvbGxUcmFpdFBhc3RWZXJiOiByb2xsSW5zdC5yb2xsVHJhaXRQYXN0VmVyYiA/PyByb2xsSW5zdC5yb2xsVHJhaXRWZXJiID8/IFwiXCJcbiAgICAvLyAgIH07XG4gICAgLy8gICByZXR1cm4gYXdhaXQgQmxhZGVzQ2hhdC5jcmVhdGUoe1xuICAgIC8vICAgICBzcGVha2VyOiByb2xsSW5zdC5nZXRTcGVha2VyKEJsYWRlc0NoYXQuZ2V0U3BlYWtlcigpKSxcbiAgICAvLyAgICAgY29udGVudDogYXdhaXQgcmVuZGVyVGVtcGxhdGUocm9sbEluc3QudGVtcGxhdGUsIHJvbGxEYXRhKSxcbiAgICAvLyAgICAgdHlwZTogQ09OU1QuQ0hBVF9NRVNTQUdFX1RZUEVTLlJPTEwsXG4gICAgLy8gICAgIGZsYWdzOiB7XG4gICAgLy8gICAgICAgXCJldW5vcy1ibGFkZXNcIjoge1xuICAgIC8vICAgICAgICAgdGVtcGxhdGU6IHJvbGxJbnN0LnRlbXBsYXRlLFxuICAgIC8vICAgICAgICAgcm9sbERhdGFcbiAgICAvLyAgICAgICB9XG4gICAgLy8gICAgIH1cbiAgICAvLyAgIH0pIGFzIEJsYWRlc0NoYXQ7XG4gICAgLy8gfVxuICAgIHN0YXRpYyBJc05ld2VzdFJvbGxSZXN1bHQocm9sbEluc3QpIHtcbiAgICAgICAgY29uc3QgbGFzdFJvbGxSZXN1bHRJRCA9ICQoXCIjY2hhdC1sb2cgLmNoYXQtbWVzc2FnZSAuYmxhZGVzLXJvbGw6bm90KC5pbmxpbmUtcm9sbClcIilcbiAgICAgICAgICAgIC5sYXN0KClcbiAgICAgICAgICAgIC5hdHRyKFwiaWRcIik7XG4gICAgICAgIHJldHVybiB0eXBlb2YgbGFzdFJvbGxSZXN1bHRJRCA9PT0gXCJzdHJpbmdcIlxuICAgICAgICAgICAgJiYgbGFzdFJvbGxSZXN1bHRJRCA9PT0gcm9sbEluc3QuaWQ7XG4gICAgfVxuICAgIGdldCBmbGFnRGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZmxhZ3NbXCJldW5vcy1ibGFkZXNcIl07XG4gICAgfVxuICAgIGdldCByb2xsRGF0YSgpIHsgcmV0dXJuIHRoaXMuZmxhZ0RhdGEucm9sbERhdGE7IH1cbiAgICBhc3luYyBzZXRGbGFnVmFsKHNjb3BlLCBrZXksIHZhbCkge1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy5zZXRGbGFnKEMuU1lTVEVNX0lELCBgJHtzY29wZX0uJHtrZXl9YCwgdmFsKTtcbiAgICB9XG4gICAgZ2V0IGFsbFJvbGxDb25zZXF1ZW5jZXMoKSB7XG4gICAgICAgIGNvbnN0IHJldHVybkRhdGEgPSB7XG4gICAgICAgICAgICBbUG9zaXRpb24uY29udHJvbGxlZF06IHtcbiAgICAgICAgICAgICAgICBbUm9sbFJlc3VsdC5jcml0aWNhbF06IHt9LFxuICAgICAgICAgICAgICAgIFtSb2xsUmVzdWx0LnN1Y2Nlc3NdOiB7fSxcbiAgICAgICAgICAgICAgICBbUm9sbFJlc3VsdC5wYXJ0aWFsXToge30sXG4gICAgICAgICAgICAgICAgW1JvbGxSZXN1bHQuZmFpbF06IHt9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW1Bvc2l0aW9uLnJpc2t5XToge1xuICAgICAgICAgICAgICAgIFtSb2xsUmVzdWx0LmNyaXRpY2FsXToge30sXG4gICAgICAgICAgICAgICAgW1JvbGxSZXN1bHQuc3VjY2Vzc106IHt9LFxuICAgICAgICAgICAgICAgIFtSb2xsUmVzdWx0LnBhcnRpYWxdOiB7fSxcbiAgICAgICAgICAgICAgICBbUm9sbFJlc3VsdC5mYWlsXToge31cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBbUG9zaXRpb24uZGVzcGVyYXRlXToge1xuICAgICAgICAgICAgICAgIFtSb2xsUmVzdWx0LmNyaXRpY2FsXToge30sXG4gICAgICAgICAgICAgICAgW1JvbGxSZXN1bHQuc3VjY2Vzc106IHt9LFxuICAgICAgICAgICAgICAgIFtSb2xsUmVzdWx0LnBhcnRpYWxdOiB7fSxcbiAgICAgICAgICAgICAgICBbUm9sbFJlc3VsdC5mYWlsXToge31cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgeyBjb25zZXF1ZW5jZURhdGEgfSA9IHRoaXMuZmxhZ0RhdGEucm9sbERhdGEgPz8ge307XG4gICAgICAgIGlmICghY29uc2VxdWVuY2VEYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuRGF0YTtcbiAgICAgICAgfVxuICAgICAgICBPYmplY3QuZW50cmllcyhjb25zZXF1ZW5jZURhdGEpXG4gICAgICAgICAgICAuZm9yRWFjaCgoW3Bvc2l0aW9uLCBwb3NpdGlvbkRhdGFdKSA9PiB7XG4gICAgICAgICAgICBPYmplY3QuZW50cmllcyhwb3NpdGlvbkRhdGEpXG4gICAgICAgICAgICAgICAgLmZvckVhY2goKFtyb2xsUmVzdWx0LCBjc3FEYXRhU2V0XSkgPT4ge1xuICAgICAgICAgICAgICAgIHJldHVybkRhdGFbcG9zaXRpb25dW3JvbGxSZXN1bHRdID0gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKGNzcURhdGFTZXQpXG4gICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKFtpZCwgY0RhdGFdKSA9PiBjRGF0YS5pZClcbiAgICAgICAgICAgICAgICAgICAgLm1hcCgoW2lkLCBjRGF0YV0pID0+IFtcbiAgICAgICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5Db25zZXF1ZW5jZXMuZ2V0KGNEYXRhLmlkKSA/PyBuZXcgQmxhZGVzQ29uc2VxdWVuY2UoY0RhdGEpXG4gICAgICAgICAgICAgICAgXSkpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gcmV0dXJuRGF0YTtcbiAgICB9XG4gICAgZ2V0IHJvbGxDb25zZXF1ZW5jZXMoKSB7XG4gICAgICAgIGlmICghdGhpcy5wYXJlbnRSb2xsKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyByb2xsUG9zaXRpb25GaW5hbCwgcm9sbFJlc3VsdCwgY29uc2VxdWVuY2VEYXRhIH0gPSB0aGlzLnBhcmVudFJvbGwuZGF0YTtcbiAgICAgICAgaWYgKCFyb2xsUG9zaXRpb25GaW5hbCB8fCAhcm9sbFJlc3VsdCB8fCAhY29uc2VxdWVuY2VEYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiByb2xsUmVzdWx0ICE9PSBcInN0cmluZ1wiIHx8ICFbUm9sbFJlc3VsdC5wYXJ0aWFsLCBSb2xsUmVzdWx0LmZhaWxdLmluY2x1ZGVzKHJvbGxSZXN1bHQpKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYWN0aXZlQ29uc2VxdWVuY2VzID0gY29uc2VxdWVuY2VEYXRhPy5bcm9sbFBvc2l0aW9uRmluYWxdPy5bcm9sbFJlc3VsdF0gPz8ge307XG4gICAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKGFjdGl2ZUNvbnNlcXVlbmNlcylcbiAgICAgICAgICAgIC5tYXAoKGNEYXRhKSA9PiBnYW1lLmV1bm9ibGFkZXMuQ29uc2VxdWVuY2VzLmdldChjRGF0YS5pZCkgPz8gbmV3IEJsYWRlc0NvbnNlcXVlbmNlKGNEYXRhKSk7XG4gICAgfVxuICAgIGdldCBlbGVtJCgpIHtcbiAgICAgICAgcmV0dXJuICQoXCIjY2hhdC1sb2dcIilcbiAgICAgICAgICAgIC5maW5kKGAuY2hhdC1tZXNzYWdlW2RhdGEtbWVzc2FnZS1pZD1cIiR7dGhpcy5pZH1cIl1gKTtcbiAgICB9XG4gICAgZ2V0IGVsZW0oKSB7IHJldHVybiB0aGlzLmVsZW0kWzBdOyB9XG4gICAgZ2V0IGlzUm9sbFJlc3VsdCgpIHsgcmV0dXJuIFwicm9sbERhdGFcIiBpbiB0aGlzLmZsYWdEYXRhOyB9XG4gICAgZ2V0IHBhcmVudFJvbGwoKSB7XG4gICAgICAgIGlmICghdGhpcy5pc1JvbGxSZXN1bHQpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyByb2xsRGF0YSB9ID0gdGhpcy5mbGFnRGF0YTtcbiAgICAgICAgaWYgKCFyb2xsRGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZ2FtZS5ldW5vYmxhZGVzLlJvbGxzLmdldChyb2xsRGF0YS5pZCA/PyBcIlwiKSA/PyBuZXcgQmxhZGVzUm9sbCh7XG4gICAgICAgICAgICAuLi5yb2xsRGF0YSxcbiAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IGZhbHNlXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBnZXQgcm9sbCQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnBhcmVudFJvbGwgPyB0aGlzLmVsZW0kLmZpbmQoYCMke3RoaXMucGFyZW50Um9sbC5pZH1gKSA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgYXN5bmMgcmVnZW5lcmF0ZUZyb21GbGFncygpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNSb2xsUmVzdWx0KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZSh7IGNvbnRlbnQ6IGF3YWl0IHJlbmRlclRlbXBsYXRlKHRoaXMuZmxhZ0RhdGEudGVtcGxhdGUsIHRoaXMpIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIHJlbmRlcihmb3JjZSkge1xuICAgICAgICBhd2FpdCBzdXBlci5yZW5kZXIoZm9yY2UpO1xuICAgICAgICBhd2FpdCB0aGlzLmFjdGl2YXRlTGlzdGVuZXJzKCk7XG4gICAgfVxuICAgIGFzeW5jIGFjdGl2YXRlTGlzdGVuZXJzKCkge1xuICAgICAgICBpZiAoIXRoaXMuZWxlbSQpIHtcbiAgICAgICAgICAgIGVMb2cuZXJyb3IoXCJCbGFkZXNDaGF0XCIsIGBObyBCbGFkZXNDaGF0LmVsZW0gZm91bmQgZm9yIGlkICR7dGhpcy5pZH0uYCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgQXBwbHlUb29sdGlwQW5pbWF0aW9ucyh0aGlzLmVsZW0kKTtcbiAgICAgICAgQmxhZGVzQ29uc2VxdWVuY2UuQXBwbHlDaGF0TGlzdGVuZXJzKHRoaXMpO1xuICAgICAgICBpZiAodGhpcy5wYXJlbnRSb2xsKSB7XG4gICAgICAgICAgICB0aGlzLmVsZW0kLmFkZENsYXNzKGAke3RoaXMucGFyZW50Um9sbC5yb2xsVHlwZS50b0xvd2VyQ2FzZSgpfS1yb2xsYCk7XG4gICAgICAgICAgICBpZiAodGhpcy5wYXJlbnRSb2xsLnJvbGxUeXBlID09PSBSb2xsVHlwZS5BY3Rpb24gJiYgdGhpcy5yb2xsQ29uc2VxdWVuY2VzLnNvbWUoKGNzcSkgPT4gIWNzcS5pc0FjY2VwdGVkKSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWxlbSQuYWRkQ2xhc3MoXCJ1bnJlc29sdmVkLWFjdGlvbi1yb2xsXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbGVtJC5yZW1vdmVDbGFzcyhcInVucmVzb2x2ZWQtYWN0aW9uLXJvbGxcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoQmxhZGVzQ2hhdC5Jc05ld2VzdFJvbGxSZXN1bHQodGhpcy5wYXJlbnRSb2xsKSkge1xuICAgICAgICAgICAgICAgICQoXCIjY2hhdC1sb2cgLmNoYXQtbWVzc2FnZVwiKS5yZW1vdmVDbGFzcyhcImFjdGl2ZS1jaGF0LXJvbGxcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5lbGVtJC5hZGRDbGFzcyhcImFjdGl2ZS1jaGF0LXJvbGxcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVsZW0kLnJlbW92ZUNsYXNzKFwiYWN0aXZlLWNoYXQtcm9sbFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBVLmdzYXAudG8odGhpcy5lbGVtJCwgeyBhdXRvQWxwaGE6IDEsIGR1cmF0aW9uOiAwLjE1LCBlYXNlOiBcIm5vbmVcIiB9KTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNDaGF0O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/classes/BladesChat.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesClockKey.ts": +/*!**************************************!*\ + !*** ./ts/classes/BladesClockKey.ts ***! + \**************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesClock: function() { return /* binding */ BladesClock; }\n/* harmony export */ });\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _BladesTargetLink__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesTargetLink */ \"./ts/classes/BladesTargetLink.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\n\nfunction isElemPosData(obj) {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].isList(obj)\n && typeof obj.x === \"number\"\n && typeof obj.y === \"number\"\n && typeof obj.width === \"number\"\n && typeof obj.height === \"number\";\n}\nclass BladesClockKey extends _BladesTargetLink__WEBPACK_IMPORTED_MODULE_2__[\"default\"] {\n // #region STATIC METHODS ~\n static Initialize() {\n function registerClockKeys(doc) {\n if (\"clocksData\" in doc.system) {\n Object.values(doc.system.clocksData ?? {})\n .forEach((keyData) => {\n try {\n new BladesClockKey(keyData);\n }\n catch (err) {\n eLog.error(\"BladesClockKey\", \"[BladesClockKey.Initialize] Error initializing clock key.\", err, keyData);\n }\n });\n }\n }\n game.items.contents\n .filter((item) => _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.clock_keeper, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.location, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.score))\n .forEach(registerClockKeys);\n game.actors.contents\n .filter((actor) => _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesActor.IsType(actor, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.faction))\n .forEach(registerClockKeys);\n return loadTemplates([\n \"systems/eunos-blades/templates/components/clock-key.hbs\",\n \"systems/eunos-blades/templates/components/clock.hbs\"\n ]);\n }\n static ApplySchemaDefaults(schemaData) {\n // Ensure all properties of Schema are provided\n return {\n name: \"\",\n isVisible: false,\n isNameVisible: false,\n isSpotlit: false,\n clocksData: {},\n sceneIDs: [],\n displayMode: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.full,\n oneKeyIndex: _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.random(0, 4, 1),\n ...schemaData\n };\n }\n static async Create(config, _parentLinkData, clocksInitialData = []) {\n // Confirm at least one, but no more than six, clockConfigs provided:\n if (clocksInitialData.length > 6) {\n // If too many clock keys, alert user and discard excess.\n eLog.error(\"BladesClockKey\", \"[BladesClockKey.Create] Too many clock configs! (Max 6.) Eliminating extras.\", clocksInitialData);\n clocksInitialData = clocksInitialData.slice(0, 6);\n }\n else if (clocksInitialData.length === 0) {\n // If no clocks provided, add one default clock.\n clocksInitialData.push({});\n }\n // Generate a local-only TargetLink instance, to assist in deriving values for the clocks data\n const tempLink = new _BladesTargetLink__WEBPACK_IMPORTED_MODULE_2__[\"default\"](config);\n // Generate the targetKey or targetFlagKey for each clockData\n if (tempLink.targetKeyPrefix) {\n config.clocksData = Object.fromEntries(clocksInitialData\n .map((cSchema, i) => {\n const cData = BladesClock.ParseConfigToData({\n ...BladesClock.ApplySchemaDefaults(cSchema),\n index: i,\n targetID: tempLink.targetID,\n targetKey: `${tempLink.targetKeyPrefix}.clocksData`,\n isScopingById: true\n });\n return [\n cData.id,\n cData\n ];\n }));\n }\n else if (tempLink.targetFlagKeyPrefix) {\n config.clocksData = Object.fromEntries(clocksInitialData\n .map((cSchema, i) => {\n const cData = BladesClock.ParseConfigToData({\n ...BladesClock.ApplySchemaDefaults(cSchema),\n targetID: tempLink.targetID,\n targetFlagKey: `${tempLink.targetFlagKeyPrefix}.clocksData`,\n isScopingById: true\n });\n return [\n cData.id,\n cData\n ];\n }));\n }\n else {\n throw new Error(\"BladesClockKey.Create: No targetKey or targetFlagKey provided.\");\n }\n // Create and initialize the target link\n const clockKeyLink = await super.Create(tempLink.data);\n // Instantiate the ClockKey\n const clockKey = new BladesClockKey(clockKeyLink.data);\n // Render the clock key\n clockKey.renderTargetAndKeeper();\n return clockKey;\n }\n static GetFromElement(elem) {\n const keyElem$ = $(elem).closest(\".clock-key-container\").find(\".clock-key\");\n if (keyElem$.length === 0) {\n return undefined;\n }\n const clockKeyID = keyElem$.attr(\"id\");\n if (!clockKeyID) {\n return undefined;\n }\n return game.eunoblades.ClockKeys.get(clockKeyID);\n }\n // #endregion\n // #region GETTERS & SETTERS ~\n // #region -- Shortcut Schema Getters ~\n get data() { return this.linkData; }\n get name() { return this.data.name; }\n set name(val) {\n this.updateTarget(\"name\", val)\n .then(() => { this.renderTargetAndKeeper(); });\n }\n get isVisible() { return this.data.isVisible; }\n set isVisible(val) {\n this.updateTarget(\"isVisible\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.renderTargetAndKeeper(); });\n }\n get isNameVisible() { return this.data.isNameVisible; }\n set isNameVisible(val) {\n this.updateTarget(\"isNameVisible\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.renderTargetAndKeeper(); });\n }\n get isSpotlit() { return this.data.isSpotlit; }\n set isSpotlit(val) {\n this.updateTarget(\"isSpotlit\", val)\n .then(() => { this.renderTargetAndKeeper(); });\n }\n get clocksData() { return this.data.clocksData; }\n get displayMode() { return this.data.displayMode; }\n get oneKeyIndex() {\n let { oneKeyIndex } = this.data;\n if (!oneKeyIndex) {\n oneKeyIndex = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.random(0, 4, 1);\n this.updateTarget(\"oneKeyIndex\", oneKeyIndex)\n .then(() => { this.renderTargetAndKeeper(); });\n }\n return oneKeyIndex;\n }\n get sceneIDs() { return this.data.sceneIDs ?? []; }\n get overlayPosition() { return this.data.overlayPosition?.[game.scenes.current.id]; }\n set overlayPosition(val) {\n if (val) {\n this.updateTarget(`overlayPosition.${game.scenes.current.id}`, val)\n .then(() => { this.renderTargetAndKeeper(); });\n }\n else {\n this.updateTarget(`overlayPosition.-=${game.scenes.current.id}`, null)\n .then(() => { this.renderTargetAndKeeper(); });\n }\n }\n // #endregion\n get clocks() {\n return new Collection(Object.entries(this.clocksData)\n .sort((a, b) => a[1].index - b[1].index)\n .map(([id, data]) => {\n return [id, new BladesClock(data)];\n }));\n }\n getClockByID(clockID) {\n return this.clocks.get(clockID);\n }\n getClockByIndex(index) {\n return this.clocks.find((clock) => clock.index === index);\n }\n get size() { return this.clocks.size; }\n get isComplete() {\n return Array.from(this.clocks).every((clock) => clock.isComplete);\n }\n get isClockKeeperKey() {\n return this.target instanceof _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesClockKeeper;\n }\n get isFactionKey() {\n return this.target instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesFaction;\n }\n get isProjectKey() {\n return this.target instanceof _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesProject;\n }\n get isScoreKey() {\n return this.target instanceof _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesScore;\n }\n get visibleClocks() {\n return this.clocks.filter((clock) => clock.isVisible);\n }\n get activeClocks() {\n return this.visibleClocks.filter((clock) => clock.isActive);\n }\n get inProgressClocks() {\n return this.visibleClocks.filter((clock) => !clock.isComplete && clock.value > 0);\n }\n get unstartedClocks() {\n return this.visibleClocks.filter((clock) => clock.value === 0);\n }\n get completedClocks() {\n return this.visibleClocks.filter((clock) => clock.isComplete);\n }\n get currentClock() {\n // If there are visible, active clocks that are not complete, return the earliest (by index property)\n // active clock that is not complete.\n if (this.activeClocks.length > 0) {\n return this.getEarliestClock(this.activeClocks);\n }\n // Otherwise, if there are any visible, completed clocks, return the latest visible, completed clock\n if (this.completedClocks.length > 0) {\n return this.getLatestClock(this.completedClocks);\n }\n // Otherwise, if there are any visible clocks, return the earliest visible clock.\n if (this.visibleClocks.length > 0) {\n return this.getEarliestClock(this.visibleClocks);\n }\n // Finally, if all clocks are hidden, return the clock at index 0\n return this.getEarliestClock(Array.from(this.clocks));\n }\n get fullDisplayPosData() {\n const x = this.svgData.width / 2;\n const y = this.svgData.height / 2;\n return {\n x, y, width: this.svgData.width, height: this.svgData.height\n };\n }\n get clocksDisplayPosData() {\n return this.getClocksBoundingBox(Array.from(this.clocks));\n }\n get visibleClocksDisplayPosData() {\n return this.getClocksBoundingBox(this.visibleClocks);\n }\n get activeClocksDisplayPosData() {\n return this.getClocksBoundingBox(this.activeClocks);\n }\n getClocksBoundingBox(clocks) {\n const { size, ...allClocksPosData } = this.svgData.clocks;\n // Filter 'allClocksPosData' to include only those entries with index properties of elements in 'clocks'\n const clocksPosData = Object.fromEntries(Object.entries(allClocksPosData)\n .filter(([index]) => clocks.map((clock) => clock.index).includes(_core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(index)))\n .map(([index, posData]) => [_core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(index), posData]));\n // Sort the values of clocksPosData by their positions\n const clockWidthPosData = Object.values(clocksPosData).sort((a, b) => a.x - b.x);\n const clockHeightPosData = Object.values(clocksPosData).sort((a, b) => a.y - b.y);\n // Get the highest and lowest values for each set of positions\n const xLowest = clockWidthPosData[0].x;\n const xHighest = clockWidthPosData[clockWidthPosData.length - 1].x;\n const yLowest = clockHeightPosData[0].y;\n const yHighest = clockHeightPosData[clockHeightPosData.length - 1].y;\n return {\n // Determine the center point in both x and y axes\n x: (xLowest + xHighest) / 2,\n y: (yLowest + yHighest) / 2,\n // Determine height and width of bounding box, accounting for clock size\n width: xHighest - xLowest + size,\n height: yHighest - yLowest + size\n };\n }\n /** This function accepts any number of arrays of BladesClock, then returns an array\n * containing those BladesClock instances that appear in ALL provided arrays.\n */\n getClocksIn(...clockArrays) {\n if (clockArrays.length === 0)\n return [];\n return clockArrays.reduce((acc, currentArray) => {\n return acc.filter((clock) => currentArray.includes(clock));\n });\n }\n /** This function accepts an array of BladesClock, and returns the BladesClock\n * instance with the lowest index property.\n */\n getEarliestClock(clockArray) {\n if (clockArray.length) {\n return clockArray.sort((a, b) => a.index - b.index)[0];\n }\n return undefined;\n }\n /** This function accepts an array of BladesClock, and returns the BladesClock\n * instance with the highest index property.\n */\n getLatestClock(clockArray) {\n if (clockArray.length) {\n return clockArray.sort((a, b) => b.index - a.index)[0];\n }\n return undefined;\n }\n isInScene(sceneID = game.scenes.current.id) {\n return this.sceneIDs.includes(sceneID);\n }\n get isInCurrentScene() {\n return this.isInScene(game.scenes.current.id);\n }\n get displaySelectOptions() {\n const options = [\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.full, display: \"Full Key\" },\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.clocks, display: \"Clocks\" },\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.activeClocks, display: \"Active Clocks\" }\n ];\n for (let i = 0; i < this.size; i++) {\n options.push(...[\n { value: i, display: `Clock #${i}` },\n { value: `present${i}`, display: `Present Clock #${i}` }\n ]);\n }\n return options;\n }\n constructor(dataOrConfig) {\n super(dataOrConfig);\n game.eunoblades.ClockKeys.set(this.id, this);\n Object.values(dataOrConfig.clocksData ?? {}).forEach((clockData) => new BladesClock(clockData));\n }\n // parseClockConfig(config: BladesClock.Config, indexOverride?: ClockIndex): BladesClock.Data {\n // if (this.size === 6) {throw new Error(\"Cannot add a clock to a clock key with 6 clocks.\");}\n // if (indexOverride !== undefined && indexOverride < 0) {throw new Error(\"Cannot add a clock with a negative index.\");}\n // // Remove target so it doesn't conflict with key's targetID\n // // delete config.target;\n // const {target, targetID, targetKey, targetFlagKey, ...partialSchema} = config;\n // const linkData: BladesTargetLink.LinkData = this.targetKey\n // ? {\n // targetID: this.targetID,\n // targetKey: `${this.targetKeyPrefix}.clocksData` as TargetKey\n // }\n // : {\n // targetID: this.targetID,\n // targetFlagKey: `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey\n // };\n // // Derive clock's targetID and targetKey/targetFlagKey from key's values\n // data.targetID = this.targetID;\n // if (this.targetKey) {\n // data.targetKey = `${this.targetKeyPrefix}.clocksData` as TargetKey;\n // } else if (this.targetFlagKey) {\n // data.targetFlagKey = `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey;\n // }\n // // Assign 'parentKeyID' and 'index'\n // config.parentKeyID = this.id;\n // config.index = indexOverride ?? this.size;\n // // Parse config to full data object\n // return BladesClock.ApplySchemaDefaults(\n // BladesClock.ParseConfigToData(config as BladesClock.Config)\n // );\n // }\n // #endregion\n // #region HTML INTERACTION ~\n // #region Get Elements$ ~\n getElemFromDisplayContext(displayContext) {\n let elem$;\n const DOM$ = $(\".vtt.game.system-eunos-blades\");\n switch (displayContext) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.overlay: {\n elem$ = DOM$.find(`#blades-overlay #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.pcSheet: {\n elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.factionSheet: {\n elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.projectSheet: {\n elem$ = DOM$.find(`.item.sheet .project #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.scoreSheet: {\n elem$ = DOM$.find(`.item.sheet .score #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.rollCollab: {\n elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.chatMessage: {\n elem$ = DOM$.find(`#chat #${this.id}`);\n break;\n }\n }\n if (!elem$.length) {\n throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`);\n }\n return elem$;\n }\n getElements$(displayContext) {\n let elem$;\n if (typeof displayContext === \"string\") {\n displayContext = this.getElemFromDisplayContext(displayContext);\n }\n elem$ = $(displayContext).find(`#${this.id}`);\n if (!elem$.length) {\n elem$ = $(displayContext).closest(`#${this.id}`);\n }\n if (!elem$?.length) {\n throw new Error(`[BladesClockKey.getElements$] Cannot find elements for display context '${displayContext}' of clockKey '${this.id}'.`);\n }\n // Using elem$ as a reference, locate relevant clock key elements and return them in a dictionary.\n const keyElems$ = {\n elem$\n };\n // Get elements that will be there regardless of context, throwing errors if not found.\n // const container$ = elem$.closest(\".clock-key-container\");\n if (!elem$.length) {\n throw new Error(`[BladesClockKey.renderClockKey] Error '.clock-key-container' not found for key '${this.id}'.`);\n }\n keyElems$.container$ = elem$.closest(\".clock-key-container\");\n const imgContainer$ = elem$.find(\".key-image-container\");\n if (!imgContainer$.length) {\n throw new Error(`[BladesClockKey.renderClockKey] Error '.key-image-container' not found for key '${this.id}'.`);\n }\n keyElems$.imgContainer$ = imgContainer$;\n const label$ = elem$.find(\".key-label\");\n if (!label$.length) {\n throw new Error(`[BladesClockKey.renderClockKey] Error label$ not found for key '${this.id}'.`);\n }\n keyElems$.label$ = label$;\n // Check for optional elements and silently exclude them from dictionary if not found.\n const factionLabel$ = elem$.find(\".faction-label\");\n if (factionLabel$.length) {\n keyElems$.factionLabel$ = factionLabel$;\n }\n const projectLabel$ = elem$.find(\".project-label\");\n if (projectLabel$.length) {\n keyElems$.projectLabel$ = projectLabel$;\n }\n const scoreLabel$ = elem$.find(\".score-label\");\n if (scoreLabel$.length) {\n keyElems$.scoreLabel$ = scoreLabel$;\n }\n // Register each clock under its id, retrieving the elements for each.\n this.clocks.forEach((clock) => {\n keyElems$.clocks ??= {};\n keyElems$.clocks[clock.id] = clock.getElements$(displayContext);\n });\n eLog.checkLog3(\"BladesClockKey\", \"Clock Key Elements\", keyElems$);\n return keyElems$;\n }\n // #endregion\n // #region Initial Rendering ~\n async renderTo(parentElem) {\n const parent$ = $(parentElem);\n if (!parent$.length) {\n throw new Error(`[BladesClockKey.renderClockKeyTo] Error parent element not provided for key '${this.id}'.`);\n }\n // Render clock key template and append it to parent element\n const clockKeyHTML = await renderTemplate(\"systems/eunos-blades/templates/components/clock-key.hbs\", this);\n $(clockKeyHTML).appendTo(parent$);\n }\n /**\n * This function generates a partial GSAP.TweenVars object that will display the key in a given mode within the bounds of a provided container.\n *\n * @param {ClockKeyDisplayMode | number} [displayMode=\"full\"] - The display mode. Options include:\n * - \"full\" - displays the entire clock key\n * - \"clocks\" - zooms in to display only the clocks\n * - \"activeClocks\" - zooms in to the active clocks\n * - \"presentN\" (where N is a clock index number) - zooms in to the clock at index N, and presents whichever side has the next available segment towards the camera.\n * - A clock index number - zooms in to the clock at index N\n *\n * @param {HTMLElement | JQuery | {x: number, y: number, width: number, height: number}} [container$] - The container within which the key will be displayed.\n * This can be:\n * - An HTMLElement\n * - A JQuery\n * - A {x, y, width, height} position definition\n * If not provided, it defaults to the clock key's container element (only if the key is already rendered in the DOM).\n *\n * @returns {gsap.TweenVars} - A partial GSAP.TweenVars object that describes how to display the key in the given mode within the bounds of the provided container. The returned object may include the following properties:\n * - 'scale' (number): A multiple to be applied to scale at \"full\" display mode.\n * - 'top' (number): A delta vertical shift from \"full\" display mode position.\n * - 'left' (number): A delta horizontal shift from \"full\" display mode position.\n * - 'transformOrigin': An absolute value.\n * - 'rotationZ': An absolute value for the keySwing axis.\n * - 'rotationY': An absolute value for rotation in/out of the screen.\n * Any variables left undefined default to \"full\" display mode.\n */\n getVarsForDisplayMode(keyElems$, displayMode = _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.full, container$) {\n const keyTweenVars = {};\n const keyImgContTweenVars = {};\n container$ ??= keyElems$.container$;\n // === TARGET CONTAINER ELEMENT ===\n // container$ refers to the element that the desired clocks will be made to fit within, and can be either an\n // HTMLElement (or JQuery reference to such), or an Element Position object ({x, y, height, width}).\n // We first convert any HTMLElements or JQuerys to an Element Position object:\n let targetPosData;\n if (container$ instanceof HTMLElement || container$ instanceof jQuery) {\n const containerPosData = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.getProperty($(container$)[0]);\n targetPosData = {\n x: containerPosData(\"x\"),\n y: containerPosData(\"y\"),\n width: containerPosData(\"width\"),\n height: containerPosData(\"height\")\n };\n }\n else if (isElemPosData(container$)) {\n targetPosData = container$;\n }\n else {\n throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error container$ '${container$}' is not a valid type.`);\n }\n // === TARGET FOCUS AREA ===\n // The focus area is the area of the key that we want to display in the container.\n // This area is determined by the display mode, and may be the full key, the clocks, the active clocks, or a single clock.\n // We will use this area to determine the scale and position of the key within the container.\n let presentingClock;\n let focusPosData;\n switch (displayMode) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.full: {\n focusPosData = {\n x: this.svgData.width / 2,\n y: this.svgData.height / 2,\n width: this.svgData.width,\n height: this.svgData.height\n };\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.clocks: {\n focusPosData = this.getClocksBoundingBox(Array.from(this.clocks));\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.activeClocks: {\n focusPosData = this.getClocksBoundingBox(this.getClocksIn(this.activeClocks, this.visibleClocks));\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.presentCurrentClock: {\n presentingClock = this.currentClock;\n displayMode = presentingClock.index;\n }\n // falls through\n default: {\n if (typeof displayMode === \"string\" && displayMode.startsWith(\"present\")) {\n displayMode = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(displayMode.toString().slice(7));\n presentingClock = this.getClockByIndex(displayMode);\n }\n // Confirm that displayMode is an integer between 0 and this.size\n if (!_core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].isInt(displayMode) || displayMode < 0 || displayMode >= this.size) {\n throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error display mode '${displayMode}' is not a valid clock index for key '${this.id}'.`);\n }\n // Set focusPosData to the center of the clock, with width and height equal to size\n const focusClockData = this.svgData.clocks[displayMode];\n focusPosData = {\n x: focusClockData.x,\n y: focusClockData.y,\n width: this.svgData.clocks.size,\n height: this.svgData.clocks.size\n };\n break;\n }\n }\n // === FIT FOCUS AREA INSIDE TARGET CONTAINER ===\n // Determine scale factor necessary to fit focusArea inside keyContainer\n keyTweenVars.scale = Math.min(targetPosData.height / focusPosData.height, targetPosData.width / focusPosData.width);\n // Determine top and left values for key-image-container, accounting for x/yPercent -50\n keyImgContTweenVars.top = (0.5 * _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ClockKeySquareSize) - focusPosData.y;\n keyImgContTweenVars.left = (0.5 * _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ClockKeySquareSize) - focusPosData.x;\n // Set transfer origin of key-image-container to same position, for further animation\n keyImgContTweenVars.transformOrigin = `${focusPosData.x}px ${focusPosData.y}px`;\n // Initialize rotation of key to 0\n keyImgContTweenVars.rotateY = 0;\n // If 'isPresenting',\n // ... rotate clock slightly towards camera\n // ... increase scale of key\n // ... shift key image container horizontally\n if (presentingClock) {\n keyTweenVars.scale *= 2;\n if (presentingClock.getActiveSide() === \"left\") {\n keyImgContTweenVars.rotateY = 30;\n keyImgContTweenVars.left += this.size === 1 ? 45 : 25;\n }\n else if (presentingClock.getActiveSide() === \"right\") {\n keyImgContTweenVars.rotateY = -30;\n keyImgContTweenVars.left -= this.size === 1 ? 45 : 25;\n }\n }\n return { keyTweenVars, keyImgContTweenVars };\n }\n // public fitKeyToContainer(\n // keyElems$: ClockKeyElems$,\n // posOverrides?: Partial\n // ) {\n // const {container$, elem$, imgContainer$} = keyElems$;\n // // Get position data for the container$ element (x, y, width, height)\n // const keyPosition: ElemPosData = {\n // x: U.gsap.getProperty(container$[0], \"x\") as number,\n // y: U.gsap.getProperty(container$[0], \"y\") as number,\n // width: U.gsap.getProperty(container$[0], \"width\") as number,\n // height: U.gsap.getProperty(container$[0], \"height\") as number\n // };\n // const {xShift, yShift, scaleMult, ...focusPosOverrides} = posOverrides ?? {};\n // const focusPosition: ElemPosData = {\n // ...this.fullDisplayPosData,\n // ...focusPosOverrides\n // };\n // eLog.checkLog3(\"BladesClockKey\", \"[BladesClockKey] Key Positions\", {\n // keyPosition,\n // focusPosition,\n // widthScale: keyPosition.width / focusPosition.width,\n // heightScale: keyPosition.height / focusPosition.height\n // });\n // // Apply scale factor to elem$ to fit default key position inside container$\n // U.gsap.set(elem$, {\n // scale: Math.min(\n // keyPosition.width / focusPosition.width,\n // keyPosition.height / focusPosition.height\n // ) * (scaleMult ?? 1)\n // });\n // // Apply top, left and transformOrigin value to keyImgContainer, accounting for x/yPercent -50\n // U.gsap.set(imgContainer$, {\n // top: (0.5 * C.ClockKeySquareSize) - focusPosition.y + (yShift ?? 0),\n // left: (0.5 * C.ClockKeySquareSize) - focusPosition.x + (xShift ?? 0),\n // transformOrigin: `${focusPosition.x + (xShift ?? 0)}px ${focusPosition.y + (yShift ?? 0)}px`\n // });\n // }\n formatLabels(keyElems$) {\n const { label$, clocks, factionLabel$, projectLabel$, scoreLabel$ } = keyElems$;\n // Collect relevant label elements, desired aspect ratio, and maximum line count, then apply adjustments to the label container for a pleasing aspect ratio\n [\n [label$, 2, 4],\n factionLabel$ ? [factionLabel$, 2, 2] : undefined,\n projectLabel$ ? [projectLabel$, 2, 2] : undefined,\n scoreLabel$ ? [scoreLabel$, 2, 2] : undefined,\n ...this.clocks.map((clock) => [clocks[clock.id].clockLabel$, 2.5, 3])\n ].filter(Boolean).forEach(([labelElem$, aspectRatio, maxLines]) => {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].adjustTextContainerAspectRatio(labelElem$, aspectRatio, maxLines);\n });\n }\n setToDisplayMode(keyElems$, displayMode, isUpdatingTarget = true) {\n const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode);\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.set(keyElems$.elem$, keyTweenVars);\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.set(keyElems$.imgContainer$, keyImgContTweenVars);\n if (isUpdatingTarget && displayMode !== this.displayMode) {\n this.updateTarget(\"displayMode\", displayMode);\n }\n }\n initElementsInContext(html, displayMode, isUpdatingTarget = true) {\n const keyElems$ = this.getElements$(html);\n displayMode ??= this.displayMode;\n this.setToDisplayMode(keyElems$, displayMode, isUpdatingTarget);\n this.formatLabels(keyElems$);\n // If displayMode starts with 'present' or is an integer, fade out all label elements\n if (displayMode.toString().startsWith(\"present\") || Number.isInteger(displayMode)) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(keyElems$.container$.find(\".clock-label, .clock-key-label\"), { autoAlpha: 0, duration: 0 });\n }\n return keyElems$;\n }\n // #endregion\n async addToScene(sceneID = game.scenes.current.id) {\n if (this.isInScene(sceneID)) {\n return;\n }\n const { sceneIDs } = this;\n sceneIDs.push(sceneID);\n await this.updateTarget({\n isVisible: false,\n sceneIDs\n });\n this.renderTargetAndKeeper();\n }\n async removeFromScene(sceneID = game.scenes.current.id) {\n if (!this.isInScene(sceneID)) {\n return;\n }\n const { sceneIDs } = this;\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].remove(sceneIDs, sceneID);\n await this.updateTarget(\"sceneIDs\", sceneIDs);\n this.renderTargetAndKeeper();\n }\n closeClockKey({ container$ }) {\n container$.remove();\n }\n get svgData() {\n if (this.size === 0) {\n throw new Error(\"[BladesClockKey.svgData] Error size is 0.\");\n }\n const keyData = _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKey_SVGDATA[this.size];\n let path;\n if (this.size === 1 && keyData.paths) {\n path = keyData.paths[this.oneKeyIndex];\n }\n else if (keyData.path) {\n path = keyData.path;\n }\n else {\n throw new Error(\"[BladesClockKey.svgData] Error path is not defined.\");\n }\n return {\n width: keyData.width,\n height: keyData.height,\n path,\n clocks: keyData.clocks\n };\n }\n isInOverlay(elem) {\n return $(elem).hasClass(\".overlay-section\") || $(elem).closest(\".overlay-section\").length > 0;\n }\n get keyHeight() { return this.svgData.height; }\n get keyWidth() { return this.svgData.width; }\n get keyViewbox() { return `0 0 ${this.svgData.width} ${this.svgData.height}`; }\n get keyPath() { return this.svgData.path; }\n get clockSize() { return this.svgData.clocks.size; }\n getClockPosition(clockIndex = 0) {\n if (clockIndex > this.size) {\n throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is greater than key size '${this.size}'.`);\n }\n if (clockIndex < 0) {\n throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is less than 0.`);\n }\n return this.svgData.clocks[clockIndex];\n }\n positionDragger;\n removePositionDragger() {\n this.positionDragger?.target.remove();\n this.positionDragger?.kill();\n delete this.positionDragger;\n }\n spawnPositionDragger(containerElem$ = game.eunoblades.Director.clockKeySection$) {\n const self = this;\n if (this.positionDragger) {\n this.removePositionDragger();\n }\n const dragElem$ = $(`
`)\n .appendTo(containerElem$);\n if (this.overlayPosition) {\n dragElem$.css({\n left: this.overlayPosition.x,\n top: this.overlayPosition.y\n });\n }\n this.positionDragger = new _core_gsap__WEBPACK_IMPORTED_MODULE_1__.Dragger(dragElem$, {\n type: \"top,left\",\n onDragStart() {\n $(this.target).css(\"background\", \"rgba(255, 255, 0, 0.25)\");\n $(this.target).css(\"outlineColor\", \"rgba(255, 255, 0, 1)\");\n },\n onDragEnd() {\n $(this.target).css(\"background\", \"rgba(255, 0, 255, 0.25)\");\n $(this.target).css(\"outlineColor\", \"rgba(255, 0, 255, 1)\");\n self.overlayPosition = { x: this.endX, y: this.endY };\n }\n });\n }\n switchToMode(keyElems$, displayMode, extendKeyVars = {}, extendKeyContainerVars = {}, isUpdatingTarget = true, callback) {\n const { elem$, imgContainer$ } = keyElems$;\n const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode);\n const currentDisplayMode = this.displayMode;\n const randomID = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.random(1, 1000, 1);\n return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.timeline({\n callbackScope: this,\n paused: true,\n onStart() {\n eLog.checkLog2(\"BladesClockKey\", `switchToMode #${randomID} - START`, { key: this, keyElems$, displayMode });\n },\n onComplete() {\n eLog.checkLog3(\"BladesClockKey\", `switchToMode #${randomID} - COMPLETE`, { key: this, keyElems$, displayMode });\n if (isUpdatingTarget && displayMode !== this.currentDisplayMode) {\n this.updateTarget(\"displayMode\", displayMode)\n .then(() => callback?.());\n }\n else {\n callback?.();\n }\n },\n onReverseComplete() {\n eLog.checkLog3(\"BladesClockKey\", `switchToMode #${randomID} - REVERSE COMPLETE`, { key: this, keyElems$, displayMode });\n if (isUpdatingTarget) {\n this.updateTarget(\"displayMode\", currentDisplayMode);\n }\n }\n })\n .to(elem$, { ...keyTweenVars, ...extendKeyVars }, 0)\n .to(imgContainer$, { ...keyImgContTweenVars, ...extendKeyContainerVars }, 0);\n }\n // #endregion\n // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls)\n // #region > SOCKET CALLS: _SocketCall / static _SocketResponse / _Animation\n fadeInName_Animation(keyElems$) {\n if (!this.name) {\n return undefined;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.blurReveal(keyElems$.label$, {\n ignoreMargin: true,\n duration: 0.75\n });\n }\n async fadeInName_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"fadeInName_SocketCall\", displayContext, this.id);\n }\n static fadeInName_SocketResponse(displayContext, keyID) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n key.fadeInName_Animation(key.getElements$(displayContext));\n }\n fadeOutName_Animation(keyElems$) {\n if (!this.name) {\n return undefined;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.blurRemove(keyElems$.label$, {\n ignoreMargin: true,\n duration: 0.75\n });\n }\n async fadeOutName_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n this.fadeOutName_Animation(this.getElements$(displayContext));\n socketlib.system.executeForOthers(\"fadeOutName_SocketCall\", displayContext, this.id);\n }\n static fadeOutName_SocketResponse(displayContext, keyID) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n key.fadeOutName_Animation(key.getElements$(displayContext));\n }\n // #endregion\n // #endregion\n // #region Adding & Removing Clocks ~\n async updateClockIndices() {\n await this.updateTarget(\"clocksData\", Object.fromEntries(Object.entries(this.clocksData)\n .map(([id, data], index) => [id, { ...data, index }])));\n return this.clocks;\n }\n async addClock(clockSchema = {}) {\n // Derive clock data from config\n const cData = BladesClock.ParseConfigToData({\n ...BladesClock.ApplySchemaDefaults(clockSchema),\n index: this.size,\n targetID: this.targetID,\n targetKey: `${this.targetKeyPrefix}.clocksData`,\n isScopingById: true\n });\n // const clockData = this.parseClockConfig(clockConfig);\n // Write to state\n await this.updateTarget(`clocksData.${cData.id}`, cData);\n // Regnerate clocks collection\n void this.clocks;\n this.renderTargetAndKeeper();\n }\n async deleteClock(clockID) {\n if (this.size <= 1) {\n throw new Error(\"[BladesClockKey.deleteClock()] Cannot reduce number of clocks below 1!\");\n }\n clockID ??= Array.from(this.clocks).pop()?.id;\n if (!clockID) {\n return;\n }\n await this.getClockByID(clockID)?.delete();\n await this.updateClockIndices();\n // Regenerate clocks collection\n void this.clocks;\n }\n // #endregion\n // #region OVERRIDES: Async Update Methods\n renderTargetAndKeeper() {\n this.renderTarget();\n game.eunoblades.ClockKeeper.sheet?.render();\n }\n renderTarget() {\n this.target.sheet?.render();\n }\n}\nclass BladesClock extends _BladesTargetLink__WEBPACK_IMPORTED_MODULE_2__[\"default\"] {\n // #region STATIC METHODS ~\n static ApplySchemaDefaults(schemaData) {\n const namedValueMax = {\n name: schemaData.name ?? \"\",\n value: schemaData.value ?? 0,\n max: schemaData.max ?? 8\n };\n return {\n index: 0,\n color: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.white,\n isVisible: !_core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].isInt(schemaData.index) || schemaData.index === 0,\n isNameVisible: false,\n isHighlighted: false,\n isActive: !_core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].isInt(schemaData.index) || schemaData.index === 0,\n ...schemaData,\n ...namedValueMax\n };\n }\n // #endregion\n // #region GETTERS & SETTERS ~\n get canEdit() {\n // return true if user has edit permissions on parent document, and clock is\n // visible and active.\n console.log(\"NOTE: All Clocks currently Editable; see line 71 of BladesClock.ts\");\n return this.isVisible && this.isActive;\n }\n get data() { return this.linkData; }\n get name() { return this.data.name; }\n set name(val) {\n this.updateTarget(\"name\", val)\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get value() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(this.data.value); }\n set value(val) {\n this.updateTarget(\"value\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get max() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(this.data.max); }\n set max(val) {\n this.updateTarget(\"max\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get color() { return this.data.color ?? _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.white; }\n set color(val) {\n this.updateTarget(\"color\", val)\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get isActive() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(this.data.isActive); }\n set isActive(val) {\n this.updateTarget(\"isActive\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get parentKey() {\n const pKey = game.eunoblades.ClockKeys.get(this.data.parentKeyID);\n if (!pKey) {\n throw new Error(`[BladesClockKey.parentKey] No parent key found for clock ${this.id}`);\n }\n return pKey;\n }\n get isNameVisible() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(this.data.isNameVisible); }\n set isNameVisible(val) {\n this.updateTarget(\"isNameVisible\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get isVisible() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(this.data.isVisible); }\n set isVisible(val) {\n this.updateTarget(\"isVisible\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get isHighlighted() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(this.data.isHighlighted); }\n set isHighlighted(val) {\n this.updateTarget(\"isHighlighted\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pBool(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get index() { return _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(this.data.index); }\n set index(val) {\n this.updateTarget(\"index\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].pInt(val))\n .then(() => { this.parentKey.renderTargetAndKeeper(); });\n }\n get isEmpty() { return this.value === 0; }\n get isComplete() { return this.value >= this.max; }\n get rollOppClock() { return this; }\n get rollOppName() { return this.name; }\n get rollOppType() { return \"clock\"; }\n get colorSelectOptions() {\n return [\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.white, display: \"🔘\" },\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.yellow, display: \"📀\" },\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.cyan, display: \"🔵\" },\n { value: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.red, display: \"🔴\" }\n ];\n }\n get maxSelectOptions() {\n return [\n { value: 2, display: 2 },\n { value: 3, display: 3 },\n { value: 4, display: 4 },\n { value: 5, display: 5 },\n { value: 6, display: 6 },\n { value: 8, display: 8 },\n { value: 10, display: 10 },\n { value: 12, display: 12 }\n ];\n }\n get valueSelectOptions() {\n const returnVals = [];\n for (let i = 0; i <= this.max; i++) {\n returnVals.push({ value: i, display: i });\n }\n return returnVals;\n }\n // Returns which hemisphere of the clock will show the final change if segmentDelta segments are added/removed.\n getActiveSide(segmentDelta = 0) {\n const finalClockValue = Math.min(this.max, Math.max(0, this.value + segmentDelta));\n const halfClockValue = this.max / 2;\n if (segmentDelta === 0) {\n return finalClockValue >= halfClockValue\n ? \"left\"\n : \"right\";\n }\n return finalClockValue > halfClockValue\n ? \"left\"\n : \"right\";\n }\n // #endregion\n // #region HTML INTERACTION ~\n getElemFromDisplayContext(displayContext) {\n let elem$;\n const DOM$ = $(\".vtt.game.system-eunos-blades\");\n switch (displayContext) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.overlay: {\n elem$ = DOM$.find(`#blades-overlay #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.pcSheet: {\n elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.factionSheet: {\n elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.projectSheet: {\n elem$ = DOM$.find(`.item.sheet .project #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.scoreSheet: {\n elem$ = DOM$.find(`.item.sheet .score #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.rollCollab: {\n elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`);\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockDisplayContext.chatMessage: {\n elem$ = DOM$.find(`#chat #${this.id}`);\n break;\n }\n }\n if (!elem$.length) {\n throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`);\n }\n return elem$;\n }\n getElements$(displayContext) {\n let elem$;\n if (typeof displayContext === \"string\") {\n displayContext = this.getElemFromDisplayContext(displayContext);\n }\n elem$ = $(displayContext).find(`#${this.id}`);\n if (!elem$.length) {\n elem$ = $(displayContext).closest(`#${this.id}`);\n }\n if (!elem$?.length) {\n throw new Error(`[BladesClock.getElements$] Cannot find elements for display context '${displayContext}' of clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n // Using elem$ as a reference, locate relevant clock elements and return them in a dictionary.\n const clockElems$ = {\n clockElem$: elem$\n };\n // Get elements that will be there regardless of context, throwing errors if not found.\n const container$ = elem$.closest(\".clock-container\");\n if (!container$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-container' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.clockContainer$ = container$;\n const label$ = elem$.find(\".clock-label\");\n if (!label$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-label' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.clockLabel$ = label$;\n const bg$ = elem$.find(\".clock-bg\");\n if (!bg$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-bg' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.bg$ = bg$;\n const frame$ = elem$.find(\".clock-frame\");\n if (!frame$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-frame' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.frame$ = frame$;\n const fill$ = elem$.find(\".clock-fill\");\n if (!fill$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-fill' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.fill$ = fill$;\n const glow$ = elem$.find(\".clock-glow\");\n if (!glow$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-glow' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.glow$ = glow$;\n const cover$ = elem$.find(\".clock-cover\");\n if (!cover$.length) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-cover' not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.cover$ = cover$;\n const oneSegments$ = elem$.find(\".clock-one-segment\");\n if (oneSegments$.length !== 3) {\n throw new Error(`[BladesClock.getElements$] Error '.clock-one-segment' elements not found for clock '${this.id}' of key '${this.parentKey.id}'.`);\n }\n clockElems$.oneSegments$ = oneSegments$;\n return clockElems$;\n }\n // #endregion\n // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls)\n reveal_Animation(clockElems$, callback) {\n // Identify elements for fading in\n const fadeInElements = [\n clockElems$.frame$,\n clockElems$.fill$\n ].filter((el$) => el$ !== undefined);\n // Construct timeline for revealing clock\n const tl = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.timeline({\n callbackScope: this,\n onComplete() {\n callback?.();\n }\n });\n // Fade out cover hiding clock\n tl.to(clockElems$.cover$, { scale: 2, autoAlpha: 0, duration: 0.5, ease: \"power2\" });\n // Fade in clock elements\n tl.fromTo(fadeInElements, {\n autoAlpha: 0,\n scale: 2\n }, {\n autoAlpha: 1,\n scale: 1,\n duration: 0.5,\n stagger: 0.2,\n ease: \"power2\"\n });\n // Fade in name, if name is visible.\n if (this.name && this.isNameVisible) {\n tl.blurReveal(clockElems$.clockLabel$, {\n ignoreMargin: true,\n duration: 0.75\n }, \"<+0.05\");\n }\n // Fade in glow, if highlighted\n if (this.isHighlighted) {\n tl.scaleUpReveal(clockElems$.glow$, {\n scale: 3,\n duration: 0.5\n }, \"<+0.05\");\n }\n if (this.isActive) {\n tl.add(() => this.activate_Animation(clockElems$), \"<+0.05\");\n }\n else {\n tl.add(() => this.deactivate_Animation(clockElems$), \"<+0.05\");\n }\n return tl;\n }\n async reveal_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"reveal_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static reveal_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n const clockElems$ = clock.getElements$(displayContext);\n clock.reveal_Animation(clockElems$);\n }\n hide_Animation(clockElems$, callback) {\n // Identify elements for fading out\n const fadeOutElements = [\n clockElems$.frame$,\n clockElems$.fill$\n ].filter((el$) => el$ !== undefined);\n // Construct timeline for hiding clock\n const tl = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.timeline({\n callbackScope: this,\n onComplete() {\n callback?.();\n }\n });\n // Fade out clock elements\n tl.to(fadeOutElements, {\n autoAlpha: 0,\n scale: 2,\n duration: 0.5,\n stagger: 0.2,\n ease: \"power2\"\n });\n // Fade out name, if name visible\n if (this.name && this.isNameVisible) {\n tl.blurRemove(clockElems$.clockLabel$, {\n ignoreMargin: true,\n duration: 0.75\n }, \"<+0.05\");\n }\n // Fade out glow, if highlighted\n if (this.isHighlighted) {\n tl.scaleDownRemove(clockElems$.glow$, {\n scale: 3,\n duration: 0.5\n }, \"<+0.05\");\n }\n // Fade in cover element\n tl.to(clockElems$.cover$, { scale: 1, autoAlpha: 1, duration: 0.5, ease: \"power2\" });\n return tl;\n }\n async hide_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"hide_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static hide_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n const clockElems$ = clock.getElements$(displayContext);\n clock.hide_Animation(clockElems$);\n }\n activate_Animation(clockElems$, callback) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(clockElems$.bg$, { autoAlpha: 1, duration: 0.5, ease: \"power2\" });\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(clockElems$.frame$, {\n filter: \"brightness(0.5)\",\n duration: 0.5,\n ease: \"power2\",\n onComplete: callback\n });\n }\n async activate_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"activate_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static activate_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.activate_Animation(clock.getElements$(displayContext));\n }\n deactivate_Animation(clockElems$, callback) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(clockElems$.bg$, { autoAlpha: 0, duration: 0.5, ease: \"power2\" });\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(clockElems$.frame$, {\n filter: \"brightness(1) blur(5px)\",\n duration: 0.5,\n ease: \"power2\",\n onComplete: callback\n });\n }\n async deactivate_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"deactivate_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static deactivate_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.deactivate_Animation(clock.getElements$(displayContext));\n }\n fadeInClockName_Animation(clockElems$) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.blurReveal(clockElems$.clockLabel$, {\n ignoreMargin: true,\n duration: 0.75\n });\n }\n async fadeInClockName_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"fadeInClockName_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static fadeInClockName_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.fadeInClockName_Animation(clock.getElements$(displayContext));\n }\n fadeOutClockName_Animation(clockElems$) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.blurRemove(clockElems$.clockLabel$, {\n ignoreMargin: true,\n duration: 0.75\n });\n }\n async fadeOutClockName_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"fadeOutClockName_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static fadeOutClockName_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.fadeOutClockName_Animation(clock.getElements$(displayContext));\n }\n highlight_Animation(clockElems$) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.scaleUpReveal(clockElems$.glow$, {\n duration: 0.5,\n scale: 3\n });\n }\n async highlight_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"highlight_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static highlight_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.highlight_Animation(clock.getElements$(displayContext));\n }\n unhighlight_Animation(clockElems$) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.effects.scaleDownRemove(clockElems$.glow$, {\n duration: 0.5,\n scale: 3\n });\n }\n async unhighlight_SocketCall(displayContext) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"unhighlight_SocketCall\", displayContext, this.parentKey.id, this.index);\n }\n static unhighlight_SocketResponse(displayContext, keyID, index) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.unhighlight_Animation(clock.getElements$(displayContext));\n }\n getRotationOfSegment(segment) {\n const stepSize = 360 / this.max;\n return stepSize * (segment - 1);\n }\n initOneSegments(clockElems$, segmentNums, isReversing) {\n if (segmentNums.length > 3) {\n throw new Error(`Too many segments: [${segmentNums.join(\", \")}]`);\n }\n // For each segment number, initialize a one-segment to that position,\n // and initialize its autoAlpha depending on isReversing.\n const oneSegs = [...clockElems$.oneSegments$];\n const oneSegsToAnimate = Array.from(clockElems$.oneSegments$).slice(0, segmentNums.length);\n for (const segmentNum of segmentNums) {\n const oneSegment = oneSegs.shift();\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.set(oneSegment, {\n rotation: this.getRotationOfSegment(segmentNum),\n autoAlpha: isReversing ? 1 : 0\n });\n }\n // If reversing, set clock element's value to the final value for proper clipping.\n if (isReversing) {\n clockElems$.clockElem$.attr(\"data-value\", _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].getLast(segmentNums) - 1);\n }\n return oneSegsToAnimate;\n }\n changeSegments_Animation(clockElems$, startVal, endVal, callback) {\n startVal = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.clamp(0, this.max, startVal);\n endVal = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.clamp(0, this.max, endVal);\n let delta = endVal - startVal;\n if (delta === 0) {\n return;\n }\n // Determine position and sequence of one-segments\n const segmentNums = [];\n if (delta < 0) {\n while (Math.abs(delta) > startVal) {\n delta++;\n }\n for (let i = startVal; i > endVal; i--) {\n segmentNums.push(i);\n }\n }\n else {\n while (endVal > this.max) {\n delta--;\n }\n for (let i = startVal + 1; i <= endVal; i++) {\n segmentNums.push(i);\n }\n }\n // Initialize oneSegments at determined positions\n const segmentsToAnimate = this.initOneSegments(clockElems$, segmentNums, startVal > endVal);\n eLog.checkLog3(\"BladesClock\", \"changeSegments_Animation\", { clockElems$, delta, segmentNums, startVal, endVal, segmentsToAnimate });\n // Initialize master timeline\n const tl = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.timeline();\n // Enlarge clock key and focus clock\n // const clockFocusTimeline: gsap.core.Timeline = this.parentKey.getClockFocusTimeline(this.index);\n // tl.add(clockFocusTimeline);\n // Animate one-segments\n if (delta > 0) {\n tl.fromTo(segmentsToAnimate, {\n autoAlpha: 0,\n scale: 2\n }, {\n autoAlpha: 1,\n scale: 1,\n duration: 0.5,\n stagger: 0.2,\n ease: \"power2\",\n callbackScope: this,\n onComplete() {\n clockElems$.clockElem$.attr(\"data-value\", endVal);\n _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.to(segmentsToAnimate, {\n autoAlpha: 0,\n duration: 0.5,\n stagger: 0.2\n // onComplete() {\n // // Return clock key to original size and focus\n // clockFocusTimeline.reverse();\n // }\n });\n }\n });\n }\n else {\n tl.fromTo(segmentsToAnimate, {\n autoAlpha: 1,\n scale: 1\n }, {\n autoAlpha: 0,\n scale: 2,\n duration: 0.5,\n stagger: 0.2,\n ease: \"power2\"\n // onComplete() {\n // // Return clock key to original size and focus\n // clockFocusTimeline.reverse();\n // }\n });\n }\n return tl;\n }\n async changeSegments_SocketCall(displayContext, startVal, endVal) {\n if (!game.user.isGM) {\n return;\n }\n startVal = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.clamp(0, this.max, startVal);\n endVal = _core_utilities__WEBPACK_IMPORTED_MODULE_3__[\"default\"].gsap.utils.clamp(0, this.max, endVal);\n socketlib.system.executeForEveryone(\"changeSegments_SocketCall\", displayContext, this.parentKey.id, this.index, startVal, endVal);\n }\n static changeSegments_SocketResponse(displayContext, keyID, index, startVal, endVal) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key?.isVisible) {\n return;\n }\n const clock = key.getClockByIndex(index);\n if (!clock) {\n return;\n }\n clock.changeSegments_Animation(clock.getElements$(displayContext), startVal, endVal);\n }\n // #endregion\n // #region Adding/Removing Clock Segments ~\n // Returns number of segments beyond max (or 0, if max not met)\n async fillSegments(count, isSilent = false) {\n // Amount added beyond max:\n const clockOverflow = Math.max(0, this.value + count - this.max);\n // Clamp count to max:\n count = Math.min(this.value + count, this.max) - this.value;\n if (count === 0) {\n return clockOverflow;\n }\n await this.updateTarget(\"value\", this.value + count);\n if (!isSilent) {\n this.parentKey.renderTargetAndKeeper();\n }\n return clockOverflow;\n }\n // Returns (positive) number of segments removed\n // in excess of the number of segments in the clock\n async clearSegments(count, isSilent = false) {\n // Amount removed beyond 0:\n const clockOverflow = Math.max(0, count - this.value);\n // Clamp count to min:\n count = Math.min(this.value, count);\n if (count === 0) {\n return clockOverflow;\n }\n await this.updateTarget(\"value\", this.value - count);\n if (!isSilent) {\n this.parentKey.renderTargetAndKeeper();\n }\n return clockOverflow;\n }\n async delete() {\n const { parentKey } = this;\n await super.delete(false);\n parentKey.updateClockIndices();\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesClockKey);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jbGFzc2VzL0JsYWRlc0Nsb2NrS2V5LnRzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBQTtBQUMrSTtBQUN4RztBQUNXO0FBQ2hCO0FBQ3lDO0FBQzhCO0FBQ3pHO0FBQ0EsV0FBVyx1REFBQztBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkIseURBQWdCO0FBQzdDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseURBQXlEO0FBQ3pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QixrRUFBVSxjQUFjLDJEQUFjLGVBQWUsMkRBQWMsVUFBVSwyREFBYyxjQUFjLDJEQUFjLGdCQUFnQiwyREFBYyxTQUFTLDJEQUFjLFNBQVMsMkRBQWMsV0FBVywyREFBYztBQUMxUDtBQUNBO0FBQ0EsK0JBQStCLG9FQUFXLGVBQWUsNERBQWUsS0FBSyw0REFBZTtBQUM1RjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBLHlCQUF5QixnRUFBbUI7QUFDNUMseUJBQXlCLHVEQUFDO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQztBQUNyQztBQUNBO0FBQ0EsNkJBQTZCLHlEQUFnQjtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLHlCQUF5QjtBQUMzRDtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyw2QkFBNkI7QUFDbkU7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixpQkFBaUI7QUFDakI7QUFDQTtBQUNBLDBCQUEwQiwrQkFBK0I7QUFDekQ7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQSx1Q0FBdUMsdURBQUM7QUFDeEMsMEJBQTBCLCtCQUErQjtBQUN6RDtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBLDJDQUEyQyx1REFBQztBQUM1QywwQkFBMEIsK0JBQStCO0FBQ3pEO0FBQ0Esc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQSwwQkFBMEIsK0JBQStCO0FBQ3pEO0FBQ0EsdUJBQXVCO0FBQ3ZCLHdCQUF3QjtBQUN4QjtBQUNBLGNBQWMsY0FBYztBQUM1QjtBQUNBLDBCQUEwQix1REFBQztBQUMzQjtBQUNBLDhCQUE4QiwrQkFBK0I7QUFDN0Q7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCLDRCQUE0QjtBQUM1QjtBQUNBO0FBQ0EsaURBQWlELHVCQUF1QjtBQUN4RSw4QkFBOEIsK0JBQStCO0FBQzdEO0FBQ0E7QUFDQSxtREFBbUQsdUJBQXVCO0FBQzFFLDhCQUE4QiwrQkFBK0I7QUFDN0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNDQUFzQyx5RUFBaUI7QUFDdkQ7QUFDQTtBQUNBLHNDQUFzQyxzRUFBYTtBQUNuRDtBQUNBO0FBQ0Esc0NBQXNDLHFFQUFhO0FBQ25EO0FBQ0E7QUFDQSxzQ0FBc0MsbUVBQVc7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiw0QkFBNEI7QUFDNUM7QUFDQTtBQUNBLDZFQUE2RSx1REFBQztBQUM5RSx3Q0FBd0MsdURBQUM7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxPQUFPLGdFQUFtQiw0QkFBNEI7QUFDcEUsY0FBYyxPQUFPLGdFQUFtQiw0QkFBNEI7QUFDcEUsY0FBYyxPQUFPLGdFQUFtQjtBQUN4QztBQUNBLHdCQUF3QixlQUFlO0FBQ3ZDO0FBQ0Esa0JBQWtCLDZCQUE2QixFQUFFLEdBQUc7QUFDcEQsa0JBQWtCLGlCQUFpQixFQUFFLDhCQUE4QixFQUFFO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1EO0FBQ25EO0FBQ0E7QUFDQSwrQkFBK0I7QUFDL0IsZ0VBQWdFO0FBQ2hFO0FBQ0E7QUFDQSxnQkFBZ0IsOERBQThEO0FBQzlFO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQixxQkFBcUI7QUFDaEQ7QUFDQTtBQUNBO0FBQ0EsK0JBQStCLHlCQUF5QjtBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixxQkFBcUI7QUFDcEQsV0FBVztBQUNYLG1DQUFtQyx5QkFBeUI7QUFDNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLHNEQUFzRCxRQUFRO0FBQzlEO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLHVEQUF1RCxRQUFRO0FBQy9EO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLDREQUE0RCxRQUFRO0FBQ3BFO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLDJEQUEyRCxRQUFRO0FBQ25FO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLHlEQUF5RCxRQUFRO0FBQ2pFO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLHlEQUF5RCxRQUFRO0FBQ2pFO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDLDRDQUE0QyxRQUFRO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUdBQXlHLFFBQVEseUJBQXlCLGVBQWU7QUFDeko7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxRQUFRO0FBQ25EO0FBQ0Esa0RBQWtELFFBQVE7QUFDMUQ7QUFDQTtBQUNBLHVHQUF1RyxlQUFlLGlCQUFpQixRQUFRO0FBQy9JO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrR0FBK0csUUFBUTtBQUN2SDtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtHQUErRyxRQUFRO0FBQ3ZIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0ZBQStGLFFBQVE7QUFDdkc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDRHQUE0RyxRQUFRO0FBQ3BIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLDhCQUE4QjtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLHFDQUFxQyxzREFBc0Q7QUFDMUc7QUFDQTtBQUNBO0FBQ0EsWUFBWSxxQkFBcUI7QUFDakM7QUFDQTtBQUNBLGlCQUFpQixnQkFBZ0I7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRCxnRUFBbUI7QUFDdEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdGQUF3RixvQkFBb0I7QUFDNUc7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLHVEQUFDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3RkFBd0YsV0FBVztBQUNuRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLGdFQUFtQjtBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLGdFQUFtQjtBQUNwQztBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsZ0VBQW1CO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLHVEQUFDO0FBQ25DO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix1REFBQztBQUN0QixrR0FBa0csWUFBWSx3Q0FBd0MsUUFBUTtBQUM5SjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlDQUF5Qyx1REFBQztBQUMxQywwQ0FBMEMsdURBQUM7QUFDM0M7QUFDQSxpREFBaUQsZUFBZSxLQUFLLGVBQWU7QUFDcEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBLGdCQUFnQixrQ0FBa0M7QUFDbEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsaURBQWlEO0FBQ2pFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsZ0NBQWdDLEtBQUssZ0NBQWdDO0FBQ3BHLFVBQVU7QUFDVjtBQUNBO0FBQ0EsZ0JBQWdCLDREQUE0RDtBQUM1RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSx1REFBQztBQUNiLFNBQVM7QUFDVDtBQUNBO0FBQ0EsZ0JBQWdCLG9DQUFvQztBQUNwRCxRQUFRLHVEQUFDO0FBQ1QsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLHVEQUFDLHdFQUF3RSwyQkFBMkI7QUFDaEg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixXQUFXO0FBQzNCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixXQUFXO0FBQzNCLFFBQVEsdURBQUM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IsWUFBWTtBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0IsNkRBQWdCO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIscUJBQXFCO0FBQ3JCLHVCQUF1QixjQUFjLG9CQUFvQixFQUFFLG9CQUFvQjtBQUMvRSxvQkFBb0I7QUFDcEIsc0JBQXNCO0FBQ3RCO0FBQ0E7QUFDQSxtRkFBbUYsV0FBVyw4QkFBOEIsVUFBVTtBQUN0STtBQUNBO0FBQ0EsbUZBQW1GLFdBQVc7QUFDOUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdEQUFnRCxRQUFRLDZEQUE2RCxVQUFVO0FBQy9IO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQSxtQ0FBbUMsK0NBQU87QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EseUNBQXlDO0FBQ3pDO0FBQ0EsU0FBUztBQUNUO0FBQ0EsMkRBQTJELDZCQUE2QjtBQUN4RixnQkFBZ0IsdUJBQXVCO0FBQ3ZDLGdCQUFnQixvQ0FBb0M7QUFDcEQ7QUFDQSx5QkFBeUIsdURBQUM7QUFDMUIsZUFBZSx1REFBQztBQUNoQjtBQUNBO0FBQ0E7QUFDQSxrRUFBa0UsVUFBVSxZQUFZLG1DQUFtQztBQUMzSCxhQUFhO0FBQ2I7QUFDQSxrRUFBa0UsVUFBVSxlQUFlLG1DQUFtQztBQUM5SDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBLGtFQUFrRSxVQUFVLHVCQUF1QixtQ0FBbUM7QUFDdEk7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QseUJBQXlCLG1DQUFtQztBQUM1RCxpQ0FBaUMsbURBQW1EO0FBQ3BGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLHVEQUFDO0FBQ2hCO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZSx1REFBQztBQUNoQjtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsZ0JBQWdCO0FBQy9EO0FBQ0E7QUFDQSxtQ0FBbUM7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixxQkFBcUI7QUFDL0M7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLDhDQUE4QyxTQUFTO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQix5REFBZ0I7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLHVEQUFVO0FBQzdCLHdCQUF3Qix1REFBQztBQUN6QjtBQUNBO0FBQ0EsdUJBQXVCLHVEQUFDO0FBQ3hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBEQUEwRDtBQUMxRDtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsMEJBQTBCLHlDQUF5QztBQUNuRTtBQUNBLGtCQUFrQixPQUFPLHVEQUFDO0FBQzFCO0FBQ0EsbUNBQW1DLHVEQUFDO0FBQ3BDLDBCQUEwQix5Q0FBeUM7QUFDbkU7QUFDQSxnQkFBZ0IsT0FBTyx1REFBQztBQUN4QjtBQUNBLGlDQUFpQyx1REFBQztBQUNsQywwQkFBMEIseUNBQXlDO0FBQ25FO0FBQ0Esa0JBQWtCLDBCQUEwQix1REFBVTtBQUN0RDtBQUNBO0FBQ0EsMEJBQTBCLHlDQUF5QztBQUNuRTtBQUNBLHFCQUFxQixPQUFPLHVEQUFDO0FBQzdCO0FBQ0Esc0NBQXNDLHVEQUFDO0FBQ3ZDLDBCQUEwQix5Q0FBeUM7QUFDbkU7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3RkFBd0YsUUFBUTtBQUNoRztBQUNBO0FBQ0E7QUFDQSwwQkFBMEIsT0FBTyx1REFBQztBQUNsQztBQUNBLDJDQUEyQyx1REFBQztBQUM1QywwQkFBMEIseUNBQXlDO0FBQ25FO0FBQ0Esc0JBQXNCLE9BQU8sdURBQUM7QUFDOUI7QUFDQSx1Q0FBdUMsdURBQUM7QUFDeEMsMEJBQTBCLHlDQUF5QztBQUNuRTtBQUNBLDBCQUEwQixPQUFPLHVEQUFDO0FBQ2xDO0FBQ0EsMkNBQTJDLHVEQUFDO0FBQzVDLDBCQUEwQix5Q0FBeUM7QUFDbkU7QUFDQSxrQkFBa0IsT0FBTyx1REFBQztBQUMxQjtBQUNBLG1DQUFtQyx1REFBQztBQUNwQywwQkFBMEIseUNBQXlDO0FBQ25FO0FBQ0Esb0JBQW9CO0FBQ3BCLHVCQUF1QjtBQUN2Qix5QkFBeUI7QUFDekIsd0JBQXdCO0FBQ3hCLHdCQUF3QjtBQUN4QjtBQUNBO0FBQ0EsY0FBYyxPQUFPLHVEQUFVLHVCQUF1QjtBQUN0RCxjQUFjLE9BQU8sdURBQVUsd0JBQXdCO0FBQ3ZELGNBQWMsT0FBTyx1REFBVSxzQkFBc0I7QUFDckQsY0FBYyxPQUFPLHVEQUFVO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyxzQkFBc0I7QUFDcEMsY0FBYyx3QkFBd0I7QUFDdEMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0JBQXdCLGVBQWU7QUFDdkMsOEJBQThCLHNCQUFzQjtBQUNwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMsc0RBQXNELFFBQVE7QUFDOUQ7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMsdURBQXVELFFBQVE7QUFDL0Q7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMsNERBQTRELFFBQVE7QUFDcEU7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMsMkRBQTJELFFBQVE7QUFDbkU7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMseURBQXlELFFBQVE7QUFDakU7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMseURBQXlELFFBQVE7QUFDakU7QUFDQTtBQUNBLGlCQUFpQixnRUFBbUI7QUFDcEMsNENBQTRDLFFBQVE7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5R0FBeUcsUUFBUSx5QkFBeUIsZUFBZTtBQUN6SjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkNBQTJDLFFBQVE7QUFDbkQ7QUFDQSxrREFBa0QsUUFBUTtBQUMxRDtBQUNBO0FBQ0Esb0dBQW9HLGVBQWUsY0FBYyxRQUFRLFlBQVksa0JBQWtCO0FBQ3ZLO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3R0FBd0csUUFBUSxZQUFZLGtCQUFrQjtBQUM5STtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9HQUFvRyxRQUFRLFlBQVksa0JBQWtCO0FBQzFJO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUdBQWlHLFFBQVEsWUFBWSxrQkFBa0I7QUFDdkk7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvR0FBb0csUUFBUSxZQUFZLGtCQUFrQjtBQUMxSTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1HQUFtRyxRQUFRLFlBQVksa0JBQWtCO0FBQ3pJO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUdBQW1HLFFBQVEsWUFBWSxrQkFBa0I7QUFDekk7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvR0FBb0csUUFBUSxZQUFZLGtCQUFrQjtBQUMxSTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1IQUFtSCxRQUFRLFlBQVksa0JBQWtCO0FBQ3pKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLHVEQUFDO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0Esb0NBQW9DLHVEQUF1RDtBQUMzRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLHVEQUFDO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSxvQ0FBb0MsdURBQXVEO0FBQzNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsdURBQUMsNEJBQTRCLDZDQUE2QztBQUNsRixRQUFRLHVEQUFDO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLHVEQUFDLDRCQUE0Qiw2Q0FBNkM7QUFDbEYsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLHVEQUFDO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsdURBQUM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1ELHVCQUF1QjtBQUMxRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksdURBQUM7QUFDYjtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLHNEQUFzRCx1REFBQztBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQix1REFBQztBQUNwQixpQkFBaUIsdURBQUM7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsWUFBWTtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxhQUFhO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvRUFBb0Usc0VBQXNFO0FBQzFJO0FBQ0EsbUJBQW1CLHVEQUFDO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQix1REFBQztBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQix1REFBQztBQUNwQixpQkFBaUIsdURBQUM7QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixZQUFZO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0RBQWUsY0FBYyxFQUFDO0FBQ1AiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jbGFzc2VzL0JsYWRlc0Nsb2NrS2V5LnRzPzMyNTAiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgQywgeyBDbG9ja0tleV9TVkdEQVRBLCBDbG9ja0Rpc3BsYXlDb250ZXh0LCBCbGFkZXNBY3RvclR5cGUsIEJsYWRlc0l0ZW1UeXBlLCBDbG9ja0NvbG9yLCBDbG9ja0tleURpc3BsYXlNb2RlIH0gZnJvbSBcIi4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBEcmFnZ2VyIH0gZnJvbSBcIi4uL2NvcmUvZ3NhcFwiO1xuaW1wb3J0IEJsYWRlc1RhcmdldExpbmsgZnJvbSBcIi4vQmxhZGVzVGFyZ2V0TGlua1wiO1xuaW1wb3J0IFUgZnJvbSBcIi4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBCbGFkZXNBY3RvciwgQmxhZGVzRmFjdGlvbiB9IGZyb20gXCIuLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuaW1wb3J0IHsgQmxhZGVzSXRlbSwgQmxhZGVzQ2xvY2tLZWVwZXIsIEJsYWRlc1Byb2plY3QsIEJsYWRlc1Njb3JlIH0gZnJvbSBcIi4uL2RvY3VtZW50cy9CbGFkZXNJdGVtUHJveHlcIjtcbmZ1bmN0aW9uIGlzRWxlbVBvc0RhdGEob2JqKSB7XG4gICAgcmV0dXJuIFUuaXNMaXN0KG9iailcbiAgICAgICAgJiYgdHlwZW9mIG9iai54ID09PSBcIm51bWJlclwiXG4gICAgICAgICYmIHR5cGVvZiBvYmoueSA9PT0gXCJudW1iZXJcIlxuICAgICAgICAmJiB0eXBlb2Ygb2JqLndpZHRoID09PSBcIm51bWJlclwiXG4gICAgICAgICYmIHR5cGVvZiBvYmouaGVpZ2h0ID09PSBcIm51bWJlclwiO1xufVxuY2xhc3MgQmxhZGVzQ2xvY2tLZXkgZXh0ZW5kcyBCbGFkZXNUYXJnZXRMaW5rIHtcbiAgICAvLyAjcmVnaW9uIFNUQVRJQyBNRVRIT0RTIH5cbiAgICBzdGF0aWMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgZnVuY3Rpb24gcmVnaXN0ZXJDbG9ja0tleXMoZG9jKSB7XG4gICAgICAgICAgICBpZiAoXCJjbG9ja3NEYXRhXCIgaW4gZG9jLnN5c3RlbSkge1xuICAgICAgICAgICAgICAgIE9iamVjdC52YWx1ZXMoZG9jLnN5c3RlbS5jbG9ja3NEYXRhID8/IHt9KVxuICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgoa2V5RGF0YSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgbmV3IEJsYWRlc0Nsb2NrS2V5KGtleURhdGEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVMb2cuZXJyb3IoXCJCbGFkZXNDbG9ja0tleVwiLCBcIltCbGFkZXNDbG9ja0tleS5Jbml0aWFsaXplXSBFcnJvciBpbml0aWFsaXppbmcgY2xvY2sga2V5LlwiLCBlcnIsIGtleURhdGEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZ2FtZS5pdGVtcy5jb250ZW50c1xuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gQmxhZGVzSXRlbS5Jc1R5cGUoaXRlbSwgQmxhZGVzSXRlbVR5cGUuY2xvY2tfa2VlcGVyLCBCbGFkZXNJdGVtVHlwZS5wcm9qZWN0LCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCwgQmxhZGVzSXRlbVR5cGUucml0dWFsLCBCbGFkZXNJdGVtVHlwZS5kZXNpZ24sIEJsYWRlc0l0ZW1UeXBlLmxvY2F0aW9uLCBCbGFkZXNJdGVtVHlwZS5zY29yZSkpXG4gICAgICAgICAgICAuZm9yRWFjaChyZWdpc3RlckNsb2NrS2V5cyk7XG4gICAgICAgIGdhbWUuYWN0b3JzLmNvbnRlbnRzXG4gICAgICAgICAgICAuZmlsdGVyKChhY3RvcikgPT4gQmxhZGVzQWN0b3IuSXNUeXBlKGFjdG9yLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5mYWN0aW9uKSlcbiAgICAgICAgICAgIC5mb3JFYWNoKHJlZ2lzdGVyQ2xvY2tLZXlzKTtcbiAgICAgICAgcmV0dXJuIGxvYWRUZW1wbGF0ZXMoW1xuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9jbG9jay1rZXkuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jb21wb25lbnRzL2Nsb2NrLmhic1wiXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICBzdGF0aWMgQXBwbHlTY2hlbWFEZWZhdWx0cyhzY2hlbWFEYXRhKSB7XG4gICAgICAgIC8vIEVuc3VyZSBhbGwgcHJvcGVydGllcyBvZiBTY2hlbWEgYXJlIHByb3ZpZGVkXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgICAgICAgICAgaXNWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIGlzTmFtZVZpc2libGU6IGZhbHNlLFxuICAgICAgICAgICAgaXNTcG90bGl0OiBmYWxzZSxcbiAgICAgICAgICAgIGNsb2Nrc0RhdGE6IHt9LFxuICAgICAgICAgICAgc2NlbmVJRHM6IFtdLFxuICAgICAgICAgICAgZGlzcGxheU1vZGU6IENsb2NrS2V5RGlzcGxheU1vZGUuZnVsbCxcbiAgICAgICAgICAgIG9uZUtleUluZGV4OiBVLmdzYXAudXRpbHMucmFuZG9tKDAsIDQsIDEpLFxuICAgICAgICAgICAgLi4uc2NoZW1hRGF0YVxuICAgICAgICB9O1xuICAgIH1cbiAgICBzdGF0aWMgYXN5bmMgQ3JlYXRlKGNvbmZpZywgX3BhcmVudExpbmtEYXRhLCBjbG9ja3NJbml0aWFsRGF0YSA9IFtdKSB7XG4gICAgICAgIC8vIENvbmZpcm0gYXQgbGVhc3Qgb25lLCBidXQgbm8gbW9yZSB0aGFuIHNpeCwgY2xvY2tDb25maWdzIHByb3ZpZGVkOlxuICAgICAgICBpZiAoY2xvY2tzSW5pdGlhbERhdGEubGVuZ3RoID4gNikge1xuICAgICAgICAgICAgLy8gSWYgdG9vIG1hbnkgY2xvY2sga2V5cywgYWxlcnQgdXNlciBhbmQgZGlzY2FyZCBleGNlc3MuXG4gICAgICAgICAgICBlTG9nLmVycm9yKFwiQmxhZGVzQ2xvY2tLZXlcIiwgXCJbQmxhZGVzQ2xvY2tLZXkuQ3JlYXRlXSBUb28gbWFueSBjbG9jayBjb25maWdzISAoTWF4IDYuKSBFbGltaW5hdGluZyBleHRyYXMuXCIsIGNsb2Nrc0luaXRpYWxEYXRhKTtcbiAgICAgICAgICAgIGNsb2Nrc0luaXRpYWxEYXRhID0gY2xvY2tzSW5pdGlhbERhdGEuc2xpY2UoMCwgNik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2xvY2tzSW5pdGlhbERhdGEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAvLyBJZiBubyBjbG9ja3MgcHJvdmlkZWQsIGFkZCBvbmUgZGVmYXVsdCBjbG9jay5cbiAgICAgICAgICAgIGNsb2Nrc0luaXRpYWxEYXRhLnB1c2goe30pO1xuICAgICAgICB9XG4gICAgICAgIC8vIEdlbmVyYXRlIGEgbG9jYWwtb25seSBUYXJnZXRMaW5rIGluc3RhbmNlLCB0byBhc3Npc3QgaW4gZGVyaXZpbmcgdmFsdWVzIGZvciB0aGUgY2xvY2tzIGRhdGFcbiAgICAgICAgY29uc3QgdGVtcExpbmsgPSBuZXcgQmxhZGVzVGFyZ2V0TGluayhjb25maWcpO1xuICAgICAgICAvLyBHZW5lcmF0ZSB0aGUgdGFyZ2V0S2V5IG9yIHRhcmdldEZsYWdLZXkgZm9yIGVhY2ggY2xvY2tEYXRhXG4gICAgICAgIGlmICh0ZW1wTGluay50YXJnZXRLZXlQcmVmaXgpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jbG9ja3NEYXRhID0gT2JqZWN0LmZyb21FbnRyaWVzKGNsb2Nrc0luaXRpYWxEYXRhXG4gICAgICAgICAgICAgICAgLm1hcCgoY1NjaGVtYSwgaSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNEYXRhID0gQmxhZGVzQ2xvY2suUGFyc2VDb25maWdUb0RhdGEoe1xuICAgICAgICAgICAgICAgICAgICAuLi5CbGFkZXNDbG9jay5BcHBseVNjaGVtYURlZmF1bHRzKGNTY2hlbWEpLFxuICAgICAgICAgICAgICAgICAgICBpbmRleDogaSxcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0SUQ6IHRlbXBMaW5rLnRhcmdldElELFxuICAgICAgICAgICAgICAgICAgICB0YXJnZXRLZXk6IGAke3RlbXBMaW5rLnRhcmdldEtleVByZWZpeH0uY2xvY2tzRGF0YWAsXG4gICAgICAgICAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IHRydWVcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgICAgICBjRGF0YS5pZCxcbiAgICAgICAgICAgICAgICAgICAgY0RhdGFcbiAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgfSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRlbXBMaW5rLnRhcmdldEZsYWdLZXlQcmVmaXgpIHtcbiAgICAgICAgICAgIGNvbmZpZy5jbG9ja3NEYXRhID0gT2JqZWN0LmZyb21FbnRyaWVzKGNsb2Nrc0luaXRpYWxEYXRhXG4gICAgICAgICAgICAgICAgLm1hcCgoY1NjaGVtYSwgaSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNEYXRhID0gQmxhZGVzQ2xvY2suUGFyc2VDb25maWdUb0RhdGEoe1xuICAgICAgICAgICAgICAgICAgICAuLi5CbGFkZXNDbG9jay5BcHBseVNjaGVtYURlZmF1bHRzKGNTY2hlbWEpLFxuICAgICAgICAgICAgICAgICAgICB0YXJnZXRJRDogdGVtcExpbmsudGFyZ2V0SUQsXG4gICAgICAgICAgICAgICAgICAgIHRhcmdldEZsYWdLZXk6IGAke3RlbXBMaW5rLnRhcmdldEZsYWdLZXlQcmVmaXh9LmNsb2Nrc0RhdGFgLFxuICAgICAgICAgICAgICAgICAgICBpc1Njb3BpbmdCeUlkOiB0cnVlXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgICAgICAgICAgY0RhdGEuaWQsXG4gICAgICAgICAgICAgICAgICAgIGNEYXRhXG4gICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkJsYWRlc0Nsb2NrS2V5LkNyZWF0ZTogTm8gdGFyZ2V0S2V5IG9yIHRhcmdldEZsYWdLZXkgcHJvdmlkZWQuXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIENyZWF0ZSBhbmQgaW5pdGlhbGl6ZSB0aGUgdGFyZ2V0IGxpbmtcbiAgICAgICAgY29uc3QgY2xvY2tLZXlMaW5rID0gYXdhaXQgc3VwZXIuQ3JlYXRlKHRlbXBMaW5rLmRhdGEpO1xuICAgICAgICAvLyBJbnN0YW50aWF0ZSB0aGUgQ2xvY2tLZXlcbiAgICAgICAgY29uc3QgY2xvY2tLZXkgPSBuZXcgQmxhZGVzQ2xvY2tLZXkoY2xvY2tLZXlMaW5rLmRhdGEpO1xuICAgICAgICAvLyBSZW5kZXIgdGhlIGNsb2NrIGtleVxuICAgICAgICBjbG9ja0tleS5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTtcbiAgICAgICAgcmV0dXJuIGNsb2NrS2V5O1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RnJvbUVsZW1lbnQoZWxlbSkge1xuICAgICAgICBjb25zdCBrZXlFbGVtJCA9ICQoZWxlbSkuY2xvc2VzdChcIi5jbG9jay1rZXktY29udGFpbmVyXCIpLmZpbmQoXCIuY2xvY2sta2V5XCIpO1xuICAgICAgICBpZiAoa2V5RWxlbSQubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrS2V5SUQgPSBrZXlFbGVtJC5hdHRyKFwiaWRcIik7XG4gICAgICAgIGlmICghY2xvY2tLZXlJRCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoY2xvY2tLZXlJRCk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEdFVFRFUlMgJiBTRVRURVJTIH5cbiAgICAvLyAjcmVnaW9uIC0tIFNob3J0Y3V0IFNjaGVtYSBHZXR0ZXJzIH5cbiAgICBnZXQgZGF0YSgpIHsgcmV0dXJuIHRoaXMubGlua0RhdGE7IH1cbiAgICBnZXQgbmFtZSgpIHsgcmV0dXJuIHRoaXMuZGF0YS5uYW1lOyB9XG4gICAgc2V0IG5hbWUodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwibmFtZVwiLCB2YWwpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgIH1cbiAgICBnZXQgaXNWaXNpYmxlKCkgeyByZXR1cm4gdGhpcy5kYXRhLmlzVmlzaWJsZTsgfVxuICAgIHNldCBpc1Zpc2libGUodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiaXNWaXNpYmxlXCIsIFUucEJvb2wodmFsKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTsgfSk7XG4gICAgfVxuICAgIGdldCBpc05hbWVWaXNpYmxlKCkgeyByZXR1cm4gdGhpcy5kYXRhLmlzTmFtZVZpc2libGU7IH1cbiAgICBzZXQgaXNOYW1lVmlzaWJsZSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJpc05hbWVWaXNpYmxlXCIsIFUucEJvb2wodmFsKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTsgfSk7XG4gICAgfVxuICAgIGdldCBpc1Nwb3RsaXQoKSB7IHJldHVybiB0aGlzLmRhdGEuaXNTcG90bGl0OyB9XG4gICAgc2V0IGlzU3BvdGxpdCh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJpc1Nwb3RsaXRcIiwgdmFsKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4geyB0aGlzLnJlbmRlclRhcmdldEFuZEtlZXBlcigpOyB9KTtcbiAgICB9XG4gICAgZ2V0IGNsb2Nrc0RhdGEoKSB7IHJldHVybiB0aGlzLmRhdGEuY2xvY2tzRGF0YTsgfVxuICAgIGdldCBkaXNwbGF5TW9kZSgpIHsgcmV0dXJuIHRoaXMuZGF0YS5kaXNwbGF5TW9kZTsgfVxuICAgIGdldCBvbmVLZXlJbmRleCgpIHtcbiAgICAgICAgbGV0IHsgb25lS2V5SW5kZXggfSA9IHRoaXMuZGF0YTtcbiAgICAgICAgaWYgKCFvbmVLZXlJbmRleCkge1xuICAgICAgICAgICAgb25lS2V5SW5kZXggPSBVLmdzYXAudXRpbHMucmFuZG9tKDAsIDQsIDEpO1xuICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJvbmVLZXlJbmRleFwiLCBvbmVLZXlJbmRleClcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvbmVLZXlJbmRleDtcbiAgICB9XG4gICAgZ2V0IHNjZW5lSURzKCkgeyByZXR1cm4gdGhpcy5kYXRhLnNjZW5lSURzID8/IFtdOyB9XG4gICAgZ2V0IG92ZXJsYXlQb3NpdGlvbigpIHsgcmV0dXJuIHRoaXMuZGF0YS5vdmVybGF5UG9zaXRpb24/LltnYW1lLnNjZW5lcy5jdXJyZW50LmlkXTsgfVxuICAgIHNldCBvdmVybGF5UG9zaXRpb24odmFsKSB7XG4gICAgICAgIGlmICh2YWwpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KGBvdmVybGF5UG9zaXRpb24uJHtnYW1lLnNjZW5lcy5jdXJyZW50LmlkfWAsIHZhbClcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoYG92ZXJsYXlQb3NpdGlvbi4tPSR7Z2FtZS5zY2VuZXMuY3VycmVudC5pZH1gLCBudWxsKVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTsgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIGdldCBjbG9ja3MoKSB7XG4gICAgICAgIHJldHVybiBuZXcgQ29sbGVjdGlvbihPYmplY3QuZW50cmllcyh0aGlzLmNsb2Nrc0RhdGEpXG4gICAgICAgICAgICAuc29ydCgoYSwgYikgPT4gYVsxXS5pbmRleCAtIGJbMV0uaW5kZXgpXG4gICAgICAgICAgICAubWFwKChbaWQsIGRhdGFdKSA9PiB7XG4gICAgICAgICAgICByZXR1cm4gW2lkLCBuZXcgQmxhZGVzQ2xvY2soZGF0YSldO1xuICAgICAgICB9KSk7XG4gICAgfVxuICAgIGdldENsb2NrQnlJRChjbG9ja0lEKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmNsb2Nrcy5nZXQoY2xvY2tJRCk7XG4gICAgfVxuICAgIGdldENsb2NrQnlJbmRleChpbmRleCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbG9ja3MuZmluZCgoY2xvY2spID0+IGNsb2NrLmluZGV4ID09PSBpbmRleCk7XG4gICAgfVxuICAgIGdldCBzaXplKCkgeyByZXR1cm4gdGhpcy5jbG9ja3Muc2l6ZTsgfVxuICAgIGdldCBpc0NvbXBsZXRlKCkge1xuICAgICAgICByZXR1cm4gQXJyYXkuZnJvbSh0aGlzLmNsb2NrcykuZXZlcnkoKGNsb2NrKSA9PiBjbG9jay5pc0NvbXBsZXRlKTtcbiAgICB9XG4gICAgZ2V0IGlzQ2xvY2tLZWVwZXJLZXkoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnRhcmdldCBpbnN0YW5jZW9mIEJsYWRlc0Nsb2NrS2VlcGVyO1xuICAgIH1cbiAgICBnZXQgaXNGYWN0aW9uS2V5KCkge1xuICAgICAgICByZXR1cm4gdGhpcy50YXJnZXQgaW5zdGFuY2VvZiBCbGFkZXNGYWN0aW9uO1xuICAgIH1cbiAgICBnZXQgaXNQcm9qZWN0S2V5KCkge1xuICAgICAgICByZXR1cm4gdGhpcy50YXJnZXQgaW5zdGFuY2VvZiBCbGFkZXNQcm9qZWN0O1xuICAgIH1cbiAgICBnZXQgaXNTY29yZUtleSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0IGluc3RhbmNlb2YgQmxhZGVzU2NvcmU7XG4gICAgfVxuICAgIGdldCB2aXNpYmxlQ2xvY2tzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jbG9ja3MuZmlsdGVyKChjbG9jaykgPT4gY2xvY2suaXNWaXNpYmxlKTtcbiAgICB9XG4gICAgZ2V0IGFjdGl2ZUNsb2NrcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMudmlzaWJsZUNsb2Nrcy5maWx0ZXIoKGNsb2NrKSA9PiBjbG9jay5pc0FjdGl2ZSk7XG4gICAgfVxuICAgIGdldCBpblByb2dyZXNzQ2xvY2tzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy52aXNpYmxlQ2xvY2tzLmZpbHRlcigoY2xvY2spID0+ICFjbG9jay5pc0NvbXBsZXRlICYmIGNsb2NrLnZhbHVlID4gMCk7XG4gICAgfVxuICAgIGdldCB1bnN0YXJ0ZWRDbG9ja3MoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnZpc2libGVDbG9ja3MuZmlsdGVyKChjbG9jaykgPT4gY2xvY2sudmFsdWUgPT09IDApO1xuICAgIH1cbiAgICBnZXQgY29tcGxldGVkQ2xvY2tzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy52aXNpYmxlQ2xvY2tzLmZpbHRlcigoY2xvY2spID0+IGNsb2NrLmlzQ29tcGxldGUpO1xuICAgIH1cbiAgICBnZXQgY3VycmVudENsb2NrKCkge1xuICAgICAgICAvLyBJZiB0aGVyZSBhcmUgdmlzaWJsZSwgYWN0aXZlIGNsb2NrcyB0aGF0IGFyZSBub3QgY29tcGxldGUsIHJldHVybiB0aGUgZWFybGllc3QgKGJ5IGluZGV4IHByb3BlcnR5KVxuICAgICAgICAvLyAgICBhY3RpdmUgY2xvY2sgdGhhdCBpcyBub3QgY29tcGxldGUuXG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZUNsb2Nrcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRFYXJsaWVzdENsb2NrKHRoaXMuYWN0aXZlQ2xvY2tzKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPdGhlcndpc2UsIGlmIHRoZXJlIGFyZSBhbnkgdmlzaWJsZSwgY29tcGxldGVkIGNsb2NrcywgcmV0dXJuIHRoZSBsYXRlc3QgdmlzaWJsZSwgY29tcGxldGVkIGNsb2NrXG4gICAgICAgIGlmICh0aGlzLmNvbXBsZXRlZENsb2Nrcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRMYXRlc3RDbG9jayh0aGlzLmNvbXBsZXRlZENsb2Nrcyk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCBpZiB0aGVyZSBhcmUgYW55IHZpc2libGUgY2xvY2tzLCByZXR1cm4gdGhlIGVhcmxpZXN0IHZpc2libGUgY2xvY2suXG4gICAgICAgIGlmICh0aGlzLnZpc2libGVDbG9ja3MubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0RWFybGllc3RDbG9jayh0aGlzLnZpc2libGVDbG9ja3MpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEZpbmFsbHksIGlmIGFsbCBjbG9ja3MgYXJlIGhpZGRlbiwgcmV0dXJuIHRoZSBjbG9jayBhdCBpbmRleCAwXG4gICAgICAgIHJldHVybiB0aGlzLmdldEVhcmxpZXN0Q2xvY2soQXJyYXkuZnJvbSh0aGlzLmNsb2NrcykpO1xuICAgIH1cbiAgICBnZXQgZnVsbERpc3BsYXlQb3NEYXRhKCkge1xuICAgICAgICBjb25zdCB4ID0gdGhpcy5zdmdEYXRhLndpZHRoIC8gMjtcbiAgICAgICAgY29uc3QgeSA9IHRoaXMuc3ZnRGF0YS5oZWlnaHQgLyAyO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgeCwgeSwgd2lkdGg6IHRoaXMuc3ZnRGF0YS53aWR0aCwgaGVpZ2h0OiB0aGlzLnN2Z0RhdGEuaGVpZ2h0XG4gICAgICAgIH07XG4gICAgfVxuICAgIGdldCBjbG9ja3NEaXNwbGF5UG9zRGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0Q2xvY2tzQm91bmRpbmdCb3goQXJyYXkuZnJvbSh0aGlzLmNsb2NrcykpO1xuICAgIH1cbiAgICBnZXQgdmlzaWJsZUNsb2Nrc0Rpc3BsYXlQb3NEYXRhKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRDbG9ja3NCb3VuZGluZ0JveCh0aGlzLnZpc2libGVDbG9ja3MpO1xuICAgIH1cbiAgICBnZXQgYWN0aXZlQ2xvY2tzRGlzcGxheVBvc0RhdGEoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldENsb2Nrc0JvdW5kaW5nQm94KHRoaXMuYWN0aXZlQ2xvY2tzKTtcbiAgICB9XG4gICAgZ2V0Q2xvY2tzQm91bmRpbmdCb3goY2xvY2tzKSB7XG4gICAgICAgIGNvbnN0IHsgc2l6ZSwgLi4uYWxsQ2xvY2tzUG9zRGF0YSB9ID0gdGhpcy5zdmdEYXRhLmNsb2NrcztcbiAgICAgICAgLy8gRmlsdGVyICdhbGxDbG9ja3NQb3NEYXRhJyB0byBpbmNsdWRlIG9ubHkgdGhvc2UgZW50cmllcyB3aXRoIGluZGV4IHByb3BlcnRpZXMgb2YgZWxlbWVudHMgaW4gJ2Nsb2NrcydcbiAgICAgICAgY29uc3QgY2xvY2tzUG9zRGF0YSA9IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhhbGxDbG9ja3NQb3NEYXRhKVxuICAgICAgICAgICAgLmZpbHRlcigoW2luZGV4XSkgPT4gY2xvY2tzLm1hcCgoY2xvY2spID0+IGNsb2NrLmluZGV4KS5pbmNsdWRlcyhVLnBJbnQoaW5kZXgpKSlcbiAgICAgICAgICAgIC5tYXAoKFtpbmRleCwgcG9zRGF0YV0pID0+IFtVLnBJbnQoaW5kZXgpLCBwb3NEYXRhXSkpO1xuICAgICAgICAvLyBTb3J0IHRoZSB2YWx1ZXMgb2YgY2xvY2tzUG9zRGF0YSBieSB0aGVpciBwb3NpdGlvbnNcbiAgICAgICAgY29uc3QgY2xvY2tXaWR0aFBvc0RhdGEgPSBPYmplY3QudmFsdWVzKGNsb2Nrc1Bvc0RhdGEpLnNvcnQoKGEsIGIpID0+IGEueCAtIGIueCk7XG4gICAgICAgIGNvbnN0IGNsb2NrSGVpZ2h0UG9zRGF0YSA9IE9iamVjdC52YWx1ZXMoY2xvY2tzUG9zRGF0YSkuc29ydCgoYSwgYikgPT4gYS55IC0gYi55KTtcbiAgICAgICAgLy8gR2V0IHRoZSBoaWdoZXN0IGFuZCBsb3dlc3QgdmFsdWVzIGZvciBlYWNoIHNldCBvZiBwb3NpdGlvbnNcbiAgICAgICAgY29uc3QgeExvd2VzdCA9IGNsb2NrV2lkdGhQb3NEYXRhWzBdLng7XG4gICAgICAgIGNvbnN0IHhIaWdoZXN0ID0gY2xvY2tXaWR0aFBvc0RhdGFbY2xvY2tXaWR0aFBvc0RhdGEubGVuZ3RoIC0gMV0ueDtcbiAgICAgICAgY29uc3QgeUxvd2VzdCA9IGNsb2NrSGVpZ2h0UG9zRGF0YVswXS55O1xuICAgICAgICBjb25zdCB5SGlnaGVzdCA9IGNsb2NrSGVpZ2h0UG9zRGF0YVtjbG9ja0hlaWdodFBvc0RhdGEubGVuZ3RoIC0gMV0ueTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC8vIERldGVybWluZSB0aGUgY2VudGVyIHBvaW50IGluIGJvdGggeCBhbmQgeSBheGVzXG4gICAgICAgICAgICB4OiAoeExvd2VzdCArIHhIaWdoZXN0KSAvIDIsXG4gICAgICAgICAgICB5OiAoeUxvd2VzdCArIHlIaWdoZXN0KSAvIDIsXG4gICAgICAgICAgICAvLyBEZXRlcm1pbmUgaGVpZ2h0IGFuZCB3aWR0aCBvZiBib3VuZGluZyBib3gsIGFjY291bnRpbmcgZm9yIGNsb2NrIHNpemVcbiAgICAgICAgICAgIHdpZHRoOiB4SGlnaGVzdCAtIHhMb3dlc3QgKyBzaXplLFxuICAgICAgICAgICAgaGVpZ2h0OiB5SGlnaGVzdCAtIHlMb3dlc3QgKyBzaXplXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8qKiBUaGlzIGZ1bmN0aW9uIGFjY2VwdHMgYW55IG51bWJlciBvZiBhcnJheXMgb2YgQmxhZGVzQ2xvY2ssIHRoZW4gcmV0dXJucyBhbiBhcnJheVxuICAgICAqIGNvbnRhaW5pbmcgdGhvc2UgQmxhZGVzQ2xvY2sgaW5zdGFuY2VzIHRoYXQgYXBwZWFyIGluIEFMTCBwcm92aWRlZCBhcnJheXMuXG4gICAgICovXG4gICAgZ2V0Q2xvY2tzSW4oLi4uY2xvY2tBcnJheXMpIHtcbiAgICAgICAgaWYgKGNsb2NrQXJyYXlzLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgcmV0dXJuIGNsb2NrQXJyYXlzLnJlZHVjZSgoYWNjLCBjdXJyZW50QXJyYXkpID0+IHtcbiAgICAgICAgICAgIHJldHVybiBhY2MuZmlsdGVyKChjbG9jaykgPT4gY3VycmVudEFycmF5LmluY2x1ZGVzKGNsb2NrKSk7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvKiogVGhpcyBmdW5jdGlvbiBhY2NlcHRzIGFuIGFycmF5IG9mIEJsYWRlc0Nsb2NrLCBhbmQgcmV0dXJucyB0aGUgQmxhZGVzQ2xvY2tcbiAgICAgKiBpbnN0YW5jZSB3aXRoIHRoZSBsb3dlc3QgaW5kZXggcHJvcGVydHkuXG4gICAgICovXG4gICAgZ2V0RWFybGllc3RDbG9jayhjbG9ja0FycmF5KSB7XG4gICAgICAgIGlmIChjbG9ja0FycmF5Lmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsb2NrQXJyYXkuc29ydCgoYSwgYikgPT4gYS5pbmRleCAtIGIuaW5kZXgpWzBdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIC8qKiBUaGlzIGZ1bmN0aW9uIGFjY2VwdHMgYW4gYXJyYXkgb2YgQmxhZGVzQ2xvY2ssIGFuZCByZXR1cm5zIHRoZSBCbGFkZXNDbG9ja1xuICAgICAqIGluc3RhbmNlIHdpdGggdGhlIGhpZ2hlc3QgaW5kZXggcHJvcGVydHkuXG4gICAgICovXG4gICAgZ2V0TGF0ZXN0Q2xvY2soY2xvY2tBcnJheSkge1xuICAgICAgICBpZiAoY2xvY2tBcnJheS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBjbG9ja0FycmF5LnNvcnQoKGEsIGIpID0+IGIuaW5kZXggLSBhLmluZGV4KVswXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBpc0luU2NlbmUoc2NlbmVJRCA9IGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2NlbmVJRHMuaW5jbHVkZXMoc2NlbmVJRCk7XG4gICAgfVxuICAgIGdldCBpc0luQ3VycmVudFNjZW5lKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pc0luU2NlbmUoZ2FtZS5zY2VuZXMuY3VycmVudC5pZCk7XG4gICAgfVxuICAgIGdldCBkaXNwbGF5U2VsZWN0T3B0aW9ucygpIHtcbiAgICAgICAgY29uc3Qgb3B0aW9ucyA9IFtcbiAgICAgICAgICAgIHsgdmFsdWU6IENsb2NrS2V5RGlzcGxheU1vZGUuZnVsbCwgZGlzcGxheTogXCJGdWxsIEtleVwiIH0sXG4gICAgICAgICAgICB7IHZhbHVlOiBDbG9ja0tleURpc3BsYXlNb2RlLmNsb2NrcywgZGlzcGxheTogXCJDbG9ja3NcIiB9LFxuICAgICAgICAgICAgeyB2YWx1ZTogQ2xvY2tLZXlEaXNwbGF5TW9kZS5hY3RpdmVDbG9ja3MsIGRpc3BsYXk6IFwiQWN0aXZlIENsb2Nrc1wiIH1cbiAgICAgICAgXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCB0aGlzLnNpemU7IGkrKykge1xuICAgICAgICAgICAgb3B0aW9ucy5wdXNoKC4uLltcbiAgICAgICAgICAgICAgICB7IHZhbHVlOiBpLCBkaXNwbGF5OiBgQ2xvY2sgIyR7aX1gIH0sXG4gICAgICAgICAgICAgICAgeyB2YWx1ZTogYHByZXNlbnQke2l9YCwgZGlzcGxheTogYFByZXNlbnQgQ2xvY2sgIyR7aX1gIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIH1cbiAgICBjb25zdHJ1Y3RvcihkYXRhT3JDb25maWcpIHtcbiAgICAgICAgc3VwZXIoZGF0YU9yQ29uZmlnKTtcbiAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5zZXQodGhpcy5pZCwgdGhpcyk7XG4gICAgICAgIE9iamVjdC52YWx1ZXMoZGF0YU9yQ29uZmlnLmNsb2Nrc0RhdGEgPz8ge30pLmZvckVhY2goKGNsb2NrRGF0YSkgPT4gbmV3IEJsYWRlc0Nsb2NrKGNsb2NrRGF0YSkpO1xuICAgIH1cbiAgICAvLyBwYXJzZUNsb2NrQ29uZmlnKGNvbmZpZzogQmxhZGVzQ2xvY2suQ29uZmlnLCBpbmRleE92ZXJyaWRlPzogQ2xvY2tJbmRleCk6IEJsYWRlc0Nsb2NrLkRhdGEge1xuICAgIC8vICAgaWYgKHRoaXMuc2l6ZSA9PT0gNikge3Rocm93IG5ldyBFcnJvcihcIkNhbm5vdCBhZGQgYSBjbG9jayB0byBhIGNsb2NrIGtleSB3aXRoIDYgY2xvY2tzLlwiKTt9XG4gICAgLy8gICBpZiAoaW5kZXhPdmVycmlkZSAhPT0gdW5kZWZpbmVkICYmIGluZGV4T3ZlcnJpZGUgPCAwKSB7dGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGFkZCBhIGNsb2NrIHdpdGggYSBuZWdhdGl2ZSBpbmRleC5cIik7fVxuICAgIC8vICAgLy8gUmVtb3ZlIHRhcmdldCBzbyBpdCBkb2Vzbid0IGNvbmZsaWN0IHdpdGgga2V5J3MgdGFyZ2V0SURcbiAgICAvLyAgIC8vIGRlbGV0ZSBjb25maWcudGFyZ2V0O1xuICAgIC8vICAgY29uc3Qge3RhcmdldCwgdGFyZ2V0SUQsIHRhcmdldEtleSwgdGFyZ2V0RmxhZ0tleSwgLi4ucGFydGlhbFNjaGVtYX0gPSBjb25maWc7XG4gICAgLy8gICBjb25zdCBsaW5rRGF0YTogQmxhZGVzVGFyZ2V0TGluay5MaW5rRGF0YSA9IHRoaXMudGFyZ2V0S2V5XG4gICAgLy8gICAgID8ge1xuICAgIC8vICAgICAgIHRhcmdldElEOiB0aGlzLnRhcmdldElELFxuICAgIC8vICAgICAgIHRhcmdldEtleTogYCR7dGhpcy50YXJnZXRLZXlQcmVmaXh9LmNsb2Nrc0RhdGFgIGFzIFRhcmdldEtleVxuICAgIC8vICAgICB9XG4gICAgLy8gICAgIDoge1xuICAgIC8vICAgICAgIHRhcmdldElEOiB0aGlzLnRhcmdldElELFxuICAgIC8vICAgICAgIHRhcmdldEZsYWdLZXk6IGAke3RoaXMudGFyZ2V0RmxhZ0tleVByZWZpeH0uY2xvY2tzRGF0YWAgYXMgVGFyZ2V0RmxhZ0tleVxuICAgIC8vICAgICB9O1xuICAgIC8vICAgLy8gRGVyaXZlIGNsb2NrJ3MgdGFyZ2V0SUQgYW5kIHRhcmdldEtleS90YXJnZXRGbGFnS2V5IGZyb20ga2V5J3MgdmFsdWVzXG4gICAgLy8gICBkYXRhLnRhcmdldElEID0gdGhpcy50YXJnZXRJRDtcbiAgICAvLyAgIGlmICh0aGlzLnRhcmdldEtleSkge1xuICAgIC8vICAgICBkYXRhLnRhcmdldEtleSA9IGAke3RoaXMudGFyZ2V0S2V5UHJlZml4fS5jbG9ja3NEYXRhYCBhcyBUYXJnZXRLZXk7XG4gICAgLy8gICB9IGVsc2UgaWYgKHRoaXMudGFyZ2V0RmxhZ0tleSkge1xuICAgIC8vICAgICBkYXRhLnRhcmdldEZsYWdLZXkgPSBgJHt0aGlzLnRhcmdldEZsYWdLZXlQcmVmaXh9LmNsb2Nrc0RhdGFgIGFzIFRhcmdldEZsYWdLZXk7XG4gICAgLy8gICB9XG4gICAgLy8gICAvLyBBc3NpZ24gJ3BhcmVudEtleUlEJyBhbmQgJ2luZGV4J1xuICAgIC8vICAgY29uZmlnLnBhcmVudEtleUlEID0gdGhpcy5pZDtcbiAgICAvLyAgIGNvbmZpZy5pbmRleCA9IGluZGV4T3ZlcnJpZGUgPz8gdGhpcy5zaXplO1xuICAgIC8vICAgLy8gUGFyc2UgY29uZmlnIHRvIGZ1bGwgZGF0YSBvYmplY3RcbiAgICAvLyAgIHJldHVybiBCbGFkZXNDbG9jay5BcHBseVNjaGVtYURlZmF1bHRzKFxuICAgIC8vICAgICBCbGFkZXNDbG9jay5QYXJzZUNvbmZpZ1RvRGF0YShjb25maWcgYXMgQmxhZGVzQ2xvY2suQ29uZmlnKVxuICAgIC8vICAgKTtcbiAgICAvLyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gSFRNTCBJTlRFUkFDVElPTiB+XG4gICAgLy8gI3JlZ2lvbiBHZXQgRWxlbWVudHMkIH5cbiAgICBnZXRFbGVtRnJvbURpc3BsYXlDb250ZXh0KGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGxldCBlbGVtJDtcbiAgICAgICAgY29uc3QgRE9NJCA9ICQoXCIudnR0LmdhbWUuc3lzdGVtLWV1bm9zLWJsYWRlc1wiKTtcbiAgICAgICAgc3dpdGNoIChkaXNwbGF5Q29udGV4dCkge1xuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXk6IHtcbiAgICAgICAgICAgICAgICBlbGVtJCA9IERPTSQuZmluZChgI2JsYWRlcy1vdmVybGF5ICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQucGNTaGVldDoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAuYWN0b3Iuc2hlZXQgLnBjICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQuZmFjdGlvblNoZWV0OiB7XG4gICAgICAgICAgICAgICAgZWxlbSQgPSBET00kLmZpbmQoYC5hY3Rvci5zaGVldCAuZmFjdGlvbiAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0LnByb2plY3RTaGVldDoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAuaXRlbS5zaGVldCAucHJvamVjdCAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0LnNjb3JlU2hlZXQ6IHtcbiAgICAgICAgICAgICAgICBlbGVtJCA9IERPTSQuZmluZChgLml0ZW0uc2hlZXQgLnNjb3JlICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQucm9sbENvbGxhYjoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAucm9sbC1jb2xsYWItc2hlZXQgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgQ2xvY2tEaXNwbGF5Q29udGV4dC5jaGF0TWVzc2FnZToge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAjY2hhdCAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghZWxlbSQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNDbG9ja0tleS5nZXRFbGVtRnJvbURpc3BsYXlDb250ZXh0XSBFcnJvciBlbGVtJCBub3QgZm91bmQgZm9yIGtleSAnJHt0aGlzLmlkfScgZm9yIGRpc3BsYXkgY29udGV4dCAnJHtkaXNwbGF5Q29udGV4dH0nLmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbGVtJDtcbiAgICB9XG4gICAgZ2V0RWxlbWVudHMkKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGxldCBlbGVtJDtcbiAgICAgICAgaWYgKHR5cGVvZiBkaXNwbGF5Q29udGV4dCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZGlzcGxheUNvbnRleHQgPSB0aGlzLmdldEVsZW1Gcm9tRGlzcGxheUNvbnRleHQoZGlzcGxheUNvbnRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsZW0kID0gJChkaXNwbGF5Q29udGV4dCkuZmluZChgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgaWYgKCFlbGVtJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIGVsZW0kID0gJChkaXNwbGF5Q29udGV4dCkuY2xvc2VzdChgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWVsZW0kPy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrS2V5LmdldEVsZW1lbnRzJF0gQ2Fubm90IGZpbmQgZWxlbWVudHMgZm9yIGRpc3BsYXkgY29udGV4dCAnJHtkaXNwbGF5Q29udGV4dH0nIG9mIGNsb2NrS2V5ICcke3RoaXMuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVc2luZyBlbGVtJCBhcyBhIHJlZmVyZW5jZSwgbG9jYXRlIHJlbGV2YW50IGNsb2NrIGtleSBlbGVtZW50cyBhbmQgcmV0dXJuIHRoZW0gaW4gYSBkaWN0aW9uYXJ5LlxuICAgICAgICBjb25zdCBrZXlFbGVtcyQgPSB7XG4gICAgICAgICAgICBlbGVtJFxuICAgICAgICB9O1xuICAgICAgICAvLyBHZXQgZWxlbWVudHMgdGhhdCB3aWxsIGJlIHRoZXJlIHJlZ2FyZGxlc3Mgb2YgY29udGV4dCwgdGhyb3dpbmcgZXJyb3JzIGlmIG5vdCBmb3VuZC5cbiAgICAgICAgLy8gY29uc3QgY29udGFpbmVyJCA9IGVsZW0kLmNsb3Nlc3QoXCIuY2xvY2sta2V5LWNvbnRhaW5lclwiKTtcbiAgICAgICAgaWYgKCFlbGVtJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrS2V5LnJlbmRlckNsb2NrS2V5XSBFcnJvciAnLmNsb2NrLWtleS1jb250YWluZXInIG5vdCBmb3VuZCBmb3Iga2V5ICcke3RoaXMuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICBrZXlFbGVtcyQuY29udGFpbmVyJCA9IGVsZW0kLmNsb3Nlc3QoXCIuY2xvY2sta2V5LWNvbnRhaW5lclwiKTtcbiAgICAgICAgY29uc3QgaW1nQ29udGFpbmVyJCA9IGVsZW0kLmZpbmQoXCIua2V5LWltYWdlLWNvbnRhaW5lclwiKTtcbiAgICAgICAgaWYgKCFpbWdDb250YWluZXIkLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2tLZXkucmVuZGVyQ2xvY2tLZXldIEVycm9yICcua2V5LWltYWdlLWNvbnRhaW5lcicgbm90IGZvdW5kIGZvciBrZXkgJyR7dGhpcy5pZH0nLmApO1xuICAgICAgICB9XG4gICAgICAgIGtleUVsZW1zJC5pbWdDb250YWluZXIkID0gaW1nQ29udGFpbmVyJDtcbiAgICAgICAgY29uc3QgbGFiZWwkID0gZWxlbSQuZmluZChcIi5rZXktbGFiZWxcIik7XG4gICAgICAgIGlmICghbGFiZWwkLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2tLZXkucmVuZGVyQ2xvY2tLZXldIEVycm9yIGxhYmVsJCBub3QgZm91bmQgZm9yIGtleSAnJHt0aGlzLmlkfScuYCk7XG4gICAgICAgIH1cbiAgICAgICAga2V5RWxlbXMkLmxhYmVsJCA9IGxhYmVsJDtcbiAgICAgICAgLy8gQ2hlY2sgZm9yIG9wdGlvbmFsIGVsZW1lbnRzIGFuZCBzaWxlbnRseSBleGNsdWRlIHRoZW0gZnJvbSBkaWN0aW9uYXJ5IGlmIG5vdCBmb3VuZC5cbiAgICAgICAgY29uc3QgZmFjdGlvbkxhYmVsJCA9IGVsZW0kLmZpbmQoXCIuZmFjdGlvbi1sYWJlbFwiKTtcbiAgICAgICAgaWYgKGZhY3Rpb25MYWJlbCQubGVuZ3RoKSB7XG4gICAgICAgICAgICBrZXlFbGVtcyQuZmFjdGlvbkxhYmVsJCA9IGZhY3Rpb25MYWJlbCQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcHJvamVjdExhYmVsJCA9IGVsZW0kLmZpbmQoXCIucHJvamVjdC1sYWJlbFwiKTtcbiAgICAgICAgaWYgKHByb2plY3RMYWJlbCQubGVuZ3RoKSB7XG4gICAgICAgICAgICBrZXlFbGVtcyQucHJvamVjdExhYmVsJCA9IHByb2plY3RMYWJlbCQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc2NvcmVMYWJlbCQgPSBlbGVtJC5maW5kKFwiLnNjb3JlLWxhYmVsXCIpO1xuICAgICAgICBpZiAoc2NvcmVMYWJlbCQubGVuZ3RoKSB7XG4gICAgICAgICAgICBrZXlFbGVtcyQuc2NvcmVMYWJlbCQgPSBzY29yZUxhYmVsJDtcbiAgICAgICAgfVxuICAgICAgICAvLyBSZWdpc3RlciBlYWNoIGNsb2NrIHVuZGVyIGl0cyBpZCwgcmV0cmlldmluZyB0aGUgZWxlbWVudHMgZm9yIGVhY2guXG4gICAgICAgIHRoaXMuY2xvY2tzLmZvckVhY2goKGNsb2NrKSA9PiB7XG4gICAgICAgICAgICBrZXlFbGVtcyQuY2xvY2tzID8/PSB7fTtcbiAgICAgICAgICAgIGtleUVsZW1zJC5jbG9ja3NbY2xvY2suaWRdID0gY2xvY2suZ2V0RWxlbWVudHMkKGRpc3BsYXlDb250ZXh0KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwiQmxhZGVzQ2xvY2tLZXlcIiwgXCJDbG9jayBLZXkgRWxlbWVudHNcIiwga2V5RWxlbXMkKTtcbiAgICAgICAgcmV0dXJuIGtleUVsZW1zJDtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gSW5pdGlhbCBSZW5kZXJpbmcgflxuICAgIGFzeW5jIHJlbmRlclRvKHBhcmVudEVsZW0pIHtcbiAgICAgICAgY29uc3QgcGFyZW50JCA9ICQocGFyZW50RWxlbSk7XG4gICAgICAgIGlmICghcGFyZW50JC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrS2V5LnJlbmRlckNsb2NrS2V5VG9dIEVycm9yIHBhcmVudCBlbGVtZW50IG5vdCBwcm92aWRlZCBmb3Iga2V5ICcke3RoaXMuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBSZW5kZXIgY2xvY2sga2V5IHRlbXBsYXRlIGFuZCBhcHBlbmQgaXQgdG8gcGFyZW50IGVsZW1lbnRcbiAgICAgICAgY29uc3QgY2xvY2tLZXlIVE1MID0gYXdhaXQgcmVuZGVyVGVtcGxhdGUoXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9jbG9jay1rZXkuaGJzXCIsIHRoaXMpO1xuICAgICAgICAkKGNsb2NrS2V5SFRNTCkuYXBwZW5kVG8ocGFyZW50JCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFRoaXMgZnVuY3Rpb24gZ2VuZXJhdGVzIGEgcGFydGlhbCBHU0FQLlR3ZWVuVmFycyBvYmplY3QgdGhhdCB3aWxsIGRpc3BsYXkgdGhlIGtleSBpbiBhIGdpdmVuIG1vZGUgd2l0aGluIHRoZSBib3VuZHMgb2YgYSBwcm92aWRlZCBjb250YWluZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0Nsb2NrS2V5RGlzcGxheU1vZGUgfCBudW1iZXJ9IFtkaXNwbGF5TW9kZT1cImZ1bGxcIl0gLSBUaGUgZGlzcGxheSBtb2RlLiBPcHRpb25zIGluY2x1ZGU6XG4gICAgICogLSBcImZ1bGxcIiAtIGRpc3BsYXlzIHRoZSBlbnRpcmUgY2xvY2sga2V5XG4gICAgICogLSBcImNsb2Nrc1wiIC0gem9vbXMgaW4gdG8gZGlzcGxheSBvbmx5IHRoZSBjbG9ja3NcbiAgICAgKiAtIFwiYWN0aXZlQ2xvY2tzXCIgLSB6b29tcyBpbiB0byB0aGUgYWN0aXZlIGNsb2Nrc1xuICAgICAqIC0gXCJwcmVzZW50TlwiICh3aGVyZSBOIGlzIGEgY2xvY2sgaW5kZXggbnVtYmVyKSAtIHpvb21zIGluIHRvIHRoZSBjbG9jayBhdCBpbmRleCBOLCBhbmQgcHJlc2VudHMgd2hpY2hldmVyIHNpZGUgaGFzIHRoZSBuZXh0IGF2YWlsYWJsZSBzZWdtZW50IHRvd2FyZHMgdGhlIGNhbWVyYS5cbiAgICAgKiAtIEEgY2xvY2sgaW5kZXggbnVtYmVyIC0gem9vbXMgaW4gdG8gdGhlIGNsb2NrIGF0IGluZGV4IE5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnQgfCBKUXVlcnk8SFRNTEVsZW1lbnQ+IHwge3g6IG51bWJlciwgeTogbnVtYmVyLCB3aWR0aDogbnVtYmVyLCBoZWlnaHQ6IG51bWJlcn19IFtjb250YWluZXIkXSAtIFRoZSBjb250YWluZXIgd2l0aGluIHdoaWNoIHRoZSBrZXkgd2lsbCBiZSBkaXNwbGF5ZWQuXG4gICAgICogVGhpcyBjYW4gYmU6XG4gICAgICogLSBBbiBIVE1MRWxlbWVudFxuICAgICAqIC0gQSBKUXVlcnk8SFRNTEVsZW1lbnQ+XG4gICAgICogLSBBIHt4LCB5LCB3aWR0aCwgaGVpZ2h0fSBwb3NpdGlvbiBkZWZpbml0aW9uXG4gICAgICogSWYgbm90IHByb3ZpZGVkLCBpdCBkZWZhdWx0cyB0byB0aGUgY2xvY2sga2V5J3MgY29udGFpbmVyIGVsZW1lbnQgKG9ubHkgaWYgdGhlIGtleSBpcyBhbHJlYWR5IHJlbmRlcmVkIGluIHRoZSBET00pLlxuICAgICAqXG4gICAgICogQHJldHVybnMge2dzYXAuVHdlZW5WYXJzfSAtIEEgcGFydGlhbCBHU0FQLlR3ZWVuVmFycyBvYmplY3QgdGhhdCBkZXNjcmliZXMgaG93IHRvIGRpc3BsYXkgdGhlIGtleSBpbiB0aGUgZ2l2ZW4gbW9kZSB3aXRoaW4gdGhlIGJvdW5kcyBvZiB0aGUgcHJvdmlkZWQgY29udGFpbmVyLiBUaGUgcmV0dXJuZWQgb2JqZWN0IG1heSBpbmNsdWRlIHRoZSBmb2xsb3dpbmcgcHJvcGVydGllczpcbiAgICAgKiAtICdzY2FsZScgKG51bWJlcik6IEEgbXVsdGlwbGUgdG8gYmUgYXBwbGllZCB0byBzY2FsZSBhdCBcImZ1bGxcIiBkaXNwbGF5IG1vZGUuXG4gICAgICogLSAndG9wJyAobnVtYmVyKTogQSBkZWx0YSB2ZXJ0aWNhbCBzaGlmdCBmcm9tIFwiZnVsbFwiIGRpc3BsYXkgbW9kZSBwb3NpdGlvbi5cbiAgICAgKiAtICdsZWZ0JyAobnVtYmVyKTogQSBkZWx0YSBob3Jpem9udGFsIHNoaWZ0IGZyb20gXCJmdWxsXCIgZGlzcGxheSBtb2RlIHBvc2l0aW9uLlxuICAgICAqIC0gJ3RyYW5zZm9ybU9yaWdpbic6IEFuIGFic29sdXRlIHZhbHVlLlxuICAgICAqIC0gJ3JvdGF0aW9uWic6IEFuIGFic29sdXRlIHZhbHVlIGZvciB0aGUga2V5U3dpbmcgYXhpcy5cbiAgICAgKiAtICdyb3RhdGlvblknOiBBbiBhYnNvbHV0ZSB2YWx1ZSBmb3Igcm90YXRpb24gaW4vb3V0IG9mIHRoZSBzY3JlZW4uXG4gICAgICogQW55IHZhcmlhYmxlcyBsZWZ0IHVuZGVmaW5lZCBkZWZhdWx0IHRvIFwiZnVsbFwiIGRpc3BsYXkgbW9kZS5cbiAgICAgKi9cbiAgICBnZXRWYXJzRm9yRGlzcGxheU1vZGUoa2V5RWxlbXMkLCBkaXNwbGF5TW9kZSA9IENsb2NrS2V5RGlzcGxheU1vZGUuZnVsbCwgY29udGFpbmVyJCkge1xuICAgICAgICBjb25zdCBrZXlUd2VlblZhcnMgPSB7fTtcbiAgICAgICAgY29uc3Qga2V5SW1nQ29udFR3ZWVuVmFycyA9IHt9O1xuICAgICAgICBjb250YWluZXIkID8/PSBrZXlFbGVtcyQuY29udGFpbmVyJDtcbiAgICAgICAgLy8gPT09IFRBUkdFVCBDT05UQUlORVIgRUxFTUVOVCA9PT1cbiAgICAgICAgLy8gY29udGFpbmVyJCByZWZlcnMgdG8gdGhlIGVsZW1lbnQgdGhhdCB0aGUgZGVzaXJlZCBjbG9ja3Mgd2lsbCBiZSBtYWRlIHRvIGZpdCB3aXRoaW4sIGFuZCBjYW4gYmUgZWl0aGVyIGFuXG4gICAgICAgIC8vICAgSFRNTEVsZW1lbnQgKG9yIEpRdWVyeSByZWZlcmVuY2UgdG8gc3VjaCksIG9yIGFuIEVsZW1lbnQgUG9zaXRpb24gb2JqZWN0ICh7eCwgeSwgaGVpZ2h0LCB3aWR0aH0pLlxuICAgICAgICAvLyBXZSBmaXJzdCBjb252ZXJ0IGFueSBIVE1MRWxlbWVudHMgb3IgSlF1ZXJ5PEhUTUxFbGVtZW50PnMgdG8gYW4gRWxlbWVudCBQb3NpdGlvbiBvYmplY3Q6XG4gICAgICAgIGxldCB0YXJnZXRQb3NEYXRhO1xuICAgICAgICBpZiAoY29udGFpbmVyJCBpbnN0YW5jZW9mIEhUTUxFbGVtZW50IHx8IGNvbnRhaW5lciQgaW5zdGFuY2VvZiBqUXVlcnkpIHtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRhaW5lclBvc0RhdGEgPSBVLmdzYXAuZ2V0UHJvcGVydHkoJChjb250YWluZXIkKVswXSk7XG4gICAgICAgICAgICB0YXJnZXRQb3NEYXRhID0ge1xuICAgICAgICAgICAgICAgIHg6IGNvbnRhaW5lclBvc0RhdGEoXCJ4XCIpLFxuICAgICAgICAgICAgICAgIHk6IGNvbnRhaW5lclBvc0RhdGEoXCJ5XCIpLFxuICAgICAgICAgICAgICAgIHdpZHRoOiBjb250YWluZXJQb3NEYXRhKFwid2lkdGhcIiksXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiBjb250YWluZXJQb3NEYXRhKFwiaGVpZ2h0XCIpXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGlzRWxlbVBvc0RhdGEoY29udGFpbmVyJCkpIHtcbiAgICAgICAgICAgIHRhcmdldFBvc0RhdGEgPSBjb250YWluZXIkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2tLZXkuZ2V0VmFyc0ZvckRpc3BsYXlNb2RlXSBFcnJvciBjb250YWluZXIkICcke2NvbnRhaW5lciR9JyBpcyBub3QgYSB2YWxpZCB0eXBlLmApO1xuICAgICAgICB9XG4gICAgICAgIC8vID09PSBUQVJHRVQgRk9DVVMgQVJFQSA9PT1cbiAgICAgICAgLy8gVGhlIGZvY3VzIGFyZWEgaXMgdGhlIGFyZWEgb2YgdGhlIGtleSB0aGF0IHdlIHdhbnQgdG8gZGlzcGxheSBpbiB0aGUgY29udGFpbmVyLlxuICAgICAgICAvLyBUaGlzIGFyZWEgaXMgZGV0ZXJtaW5lZCBieSB0aGUgZGlzcGxheSBtb2RlLCBhbmQgbWF5IGJlIHRoZSBmdWxsIGtleSwgdGhlIGNsb2NrcywgdGhlIGFjdGl2ZSBjbG9ja3MsIG9yIGEgc2luZ2xlIGNsb2NrLlxuICAgICAgICAvLyBXZSB3aWxsIHVzZSB0aGlzIGFyZWEgdG8gZGV0ZXJtaW5lIHRoZSBzY2FsZSBhbmQgcG9zaXRpb24gb2YgdGhlIGtleSB3aXRoaW4gdGhlIGNvbnRhaW5lci5cbiAgICAgICAgbGV0IHByZXNlbnRpbmdDbG9jaztcbiAgICAgICAgbGV0IGZvY3VzUG9zRGF0YTtcbiAgICAgICAgc3dpdGNoIChkaXNwbGF5TW9kZSkge1xuICAgICAgICAgICAgY2FzZSBDbG9ja0tleURpc3BsYXlNb2RlLmZ1bGw6IHtcbiAgICAgICAgICAgICAgICBmb2N1c1Bvc0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIHg6IHRoaXMuc3ZnRGF0YS53aWR0aCAvIDIsXG4gICAgICAgICAgICAgICAgICAgIHk6IHRoaXMuc3ZnRGF0YS5oZWlnaHQgLyAyLFxuICAgICAgICAgICAgICAgICAgICB3aWR0aDogdGhpcy5zdmdEYXRhLndpZHRoLFxuICAgICAgICAgICAgICAgICAgICBoZWlnaHQ6IHRoaXMuc3ZnRGF0YS5oZWlnaHRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0tleURpc3BsYXlNb2RlLmNsb2Nrczoge1xuICAgICAgICAgICAgICAgIGZvY3VzUG9zRGF0YSA9IHRoaXMuZ2V0Q2xvY2tzQm91bmRpbmdCb3goQXJyYXkuZnJvbSh0aGlzLmNsb2NrcykpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0tleURpc3BsYXlNb2RlLmFjdGl2ZUNsb2Nrczoge1xuICAgICAgICAgICAgICAgIGZvY3VzUG9zRGF0YSA9IHRoaXMuZ2V0Q2xvY2tzQm91bmRpbmdCb3godGhpcy5nZXRDbG9ja3NJbih0aGlzLmFjdGl2ZUNsb2NrcywgdGhpcy52aXNpYmxlQ2xvY2tzKSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrS2V5RGlzcGxheU1vZGUucHJlc2VudEN1cnJlbnRDbG9jazoge1xuICAgICAgICAgICAgICAgIHByZXNlbnRpbmdDbG9jayA9IHRoaXMuY3VycmVudENsb2NrO1xuICAgICAgICAgICAgICAgIGRpc3BsYXlNb2RlID0gcHJlc2VudGluZ0Nsb2NrLmluZGV4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gZmFsbHMgdGhyb3VnaFxuICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZGlzcGxheU1vZGUgPT09IFwic3RyaW5nXCIgJiYgZGlzcGxheU1vZGUuc3RhcnRzV2l0aChcInByZXNlbnRcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgZGlzcGxheU1vZGUgPSBVLnBJbnQoZGlzcGxheU1vZGUudG9TdHJpbmcoKS5zbGljZSg3KSk7XG4gICAgICAgICAgICAgICAgICAgIHByZXNlbnRpbmdDbG9jayA9IHRoaXMuZ2V0Q2xvY2tCeUluZGV4KGRpc3BsYXlNb2RlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gQ29uZmlybSB0aGF0IGRpc3BsYXlNb2RlIGlzIGFuIGludGVnZXIgYmV0d2VlbiAwIGFuZCB0aGlzLnNpemVcbiAgICAgICAgICAgICAgICBpZiAoIVUuaXNJbnQoZGlzcGxheU1vZGUpIHx8IGRpc3BsYXlNb2RlIDwgMCB8fCBkaXNwbGF5TW9kZSA+PSB0aGlzLnNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2tLZXkuZ2V0VmFyc0ZvckRpc3BsYXlNb2RlXSBFcnJvciBkaXNwbGF5IG1vZGUgJyR7ZGlzcGxheU1vZGV9JyBpcyBub3QgYSB2YWxpZCBjbG9jayBpbmRleCBmb3Iga2V5ICcke3RoaXMuaWR9Jy5gKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gU2V0IGZvY3VzUG9zRGF0YSB0byB0aGUgY2VudGVyIG9mIHRoZSBjbG9jaywgd2l0aCB3aWR0aCBhbmQgaGVpZ2h0IGVxdWFsIHRvIHNpemVcbiAgICAgICAgICAgICAgICBjb25zdCBmb2N1c0Nsb2NrRGF0YSA9IHRoaXMuc3ZnRGF0YS5jbG9ja3NbZGlzcGxheU1vZGVdO1xuICAgICAgICAgICAgICAgIGZvY3VzUG9zRGF0YSA9IHtcbiAgICAgICAgICAgICAgICAgICAgeDogZm9jdXNDbG9ja0RhdGEueCxcbiAgICAgICAgICAgICAgICAgICAgeTogZm9jdXNDbG9ja0RhdGEueSxcbiAgICAgICAgICAgICAgICAgICAgd2lkdGg6IHRoaXMuc3ZnRGF0YS5jbG9ja3Muc2l6ZSxcbiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0OiB0aGlzLnN2Z0RhdGEuY2xvY2tzLnNpemVcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vID09PSBGSVQgRk9DVVMgQVJFQSBJTlNJREUgVEFSR0VUIENPTlRBSU5FUiA9PT1cbiAgICAgICAgLy8gRGV0ZXJtaW5lIHNjYWxlIGZhY3RvciBuZWNlc3NhcnkgdG8gZml0IGZvY3VzQXJlYSBpbnNpZGUga2V5Q29udGFpbmVyXG4gICAgICAgIGtleVR3ZWVuVmFycy5zY2FsZSA9IE1hdGgubWluKHRhcmdldFBvc0RhdGEuaGVpZ2h0IC8gZm9jdXNQb3NEYXRhLmhlaWdodCwgdGFyZ2V0UG9zRGF0YS53aWR0aCAvIGZvY3VzUG9zRGF0YS53aWR0aCk7XG4gICAgICAgIC8vIERldGVybWluZSB0b3AgYW5kIGxlZnQgdmFsdWVzIGZvciBrZXktaW1hZ2UtY29udGFpbmVyLCBhY2NvdW50aW5nIGZvciB4L3lQZXJjZW50IC01MFxuICAgICAgICBrZXlJbWdDb250VHdlZW5WYXJzLnRvcCA9ICgwLjUgKiBDLkNsb2NrS2V5U3F1YXJlU2l6ZSkgLSBmb2N1c1Bvc0RhdGEueTtcbiAgICAgICAga2V5SW1nQ29udFR3ZWVuVmFycy5sZWZ0ID0gKDAuNSAqIEMuQ2xvY2tLZXlTcXVhcmVTaXplKSAtIGZvY3VzUG9zRGF0YS54O1xuICAgICAgICAvLyBTZXQgdHJhbnNmZXIgb3JpZ2luIG9mIGtleS1pbWFnZS1jb250YWluZXIgdG8gc2FtZSBwb3NpdGlvbiwgZm9yIGZ1cnRoZXIgYW5pbWF0aW9uXG4gICAgICAgIGtleUltZ0NvbnRUd2VlblZhcnMudHJhbnNmb3JtT3JpZ2luID0gYCR7Zm9jdXNQb3NEYXRhLnh9cHggJHtmb2N1c1Bvc0RhdGEueX1weGA7XG4gICAgICAgIC8vIEluaXRpYWxpemUgcm90YXRpb24gb2Yga2V5IHRvIDBcbiAgICAgICAga2V5SW1nQ29udFR3ZWVuVmFycy5yb3RhdGVZID0gMDtcbiAgICAgICAgLy8gSWYgJ2lzUHJlc2VudGluZycsXG4gICAgICAgIC8vIC4uLiByb3RhdGUgY2xvY2sgc2xpZ2h0bHkgdG93YXJkcyBjYW1lcmFcbiAgICAgICAgLy8gLi4uIGluY3JlYXNlIHNjYWxlIG9mIGtleVxuICAgICAgICAvLyAuLi4gc2hpZnQga2V5IGltYWdlIGNvbnRhaW5lciBob3Jpem9udGFsbHlcbiAgICAgICAgaWYgKHByZXNlbnRpbmdDbG9jaykge1xuICAgICAgICAgICAga2V5VHdlZW5WYXJzLnNjYWxlICo9IDI7XG4gICAgICAgICAgICBpZiAocHJlc2VudGluZ0Nsb2NrLmdldEFjdGl2ZVNpZGUoKSA9PT0gXCJsZWZ0XCIpIHtcbiAgICAgICAgICAgICAgICBrZXlJbWdDb250VHdlZW5WYXJzLnJvdGF0ZVkgPSAzMDtcbiAgICAgICAgICAgICAgICBrZXlJbWdDb250VHdlZW5WYXJzLmxlZnQgKz0gdGhpcy5zaXplID09PSAxID8gNDUgOiAyNTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHByZXNlbnRpbmdDbG9jay5nZXRBY3RpdmVTaWRlKCkgPT09IFwicmlnaHRcIikge1xuICAgICAgICAgICAgICAgIGtleUltZ0NvbnRUd2VlblZhcnMucm90YXRlWSA9IC0zMDtcbiAgICAgICAgICAgICAgICBrZXlJbWdDb250VHdlZW5WYXJzLmxlZnQgLT0gdGhpcy5zaXplID09PSAxID8gNDUgOiAyNTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4geyBrZXlUd2VlblZhcnMsIGtleUltZ0NvbnRUd2VlblZhcnMgfTtcbiAgICB9XG4gICAgLy8gcHVibGljIGZpdEtleVRvQ29udGFpbmVyKFxuICAgIC8vICAga2V5RWxlbXMkOiBDbG9ja0tleUVsZW1zJCxcbiAgICAvLyAgIHBvc092ZXJyaWRlcz86IFBhcnRpYWw8RWxlbVBvc0RhdGEgJiB7XG4gICAgLy8gICAgIHhTaGlmdDogbnVtYmVyLFxuICAgIC8vICAgICB5U2hpZnQ6IG51bWJlcixcbiAgICAvLyAgICAgc2NhbGVNdWx0OiBudW1iZXJcbiAgICAvLyAgIH0+XG4gICAgLy8gKSB7XG4gICAgLy8gICBjb25zdCB7Y29udGFpbmVyJCwgZWxlbSQsIGltZ0NvbnRhaW5lciR9ID0ga2V5RWxlbXMkO1xuICAgIC8vICAgLy8gR2V0IHBvc2l0aW9uIGRhdGEgZm9yIHRoZSBjb250YWluZXIkIGVsZW1lbnQgKHgsIHksIHdpZHRoLCBoZWlnaHQpXG4gICAgLy8gICBjb25zdCBrZXlQb3NpdGlvbjogRWxlbVBvc0RhdGEgPSB7XG4gICAgLy8gICAgIHg6IFUuZ3NhcC5nZXRQcm9wZXJ0eShjb250YWluZXIkWzBdLCBcInhcIikgYXMgbnVtYmVyLFxuICAgIC8vICAgICB5OiBVLmdzYXAuZ2V0UHJvcGVydHkoY29udGFpbmVyJFswXSwgXCJ5XCIpIGFzIG51bWJlcixcbiAgICAvLyAgICAgd2lkdGg6IFUuZ3NhcC5nZXRQcm9wZXJ0eShjb250YWluZXIkWzBdLCBcIndpZHRoXCIpIGFzIG51bWJlcixcbiAgICAvLyAgICAgaGVpZ2h0OiBVLmdzYXAuZ2V0UHJvcGVydHkoY29udGFpbmVyJFswXSwgXCJoZWlnaHRcIikgYXMgbnVtYmVyXG4gICAgLy8gICB9O1xuICAgIC8vICAgY29uc3Qge3hTaGlmdCwgeVNoaWZ0LCBzY2FsZU11bHQsIC4uLmZvY3VzUG9zT3ZlcnJpZGVzfSA9IHBvc092ZXJyaWRlcyA/PyB7fTtcbiAgICAvLyAgIGNvbnN0IGZvY3VzUG9zaXRpb246IEVsZW1Qb3NEYXRhID0ge1xuICAgIC8vICAgICAuLi50aGlzLmZ1bGxEaXNwbGF5UG9zRGF0YSxcbiAgICAvLyAgICAgLi4uZm9jdXNQb3NPdmVycmlkZXNcbiAgICAvLyAgIH07XG4gICAgLy8gICBlTG9nLmNoZWNrTG9nMyhcIkJsYWRlc0Nsb2NrS2V5XCIsIFwiW0JsYWRlc0Nsb2NrS2V5XSBLZXkgUG9zaXRpb25zXCIsIHtcbiAgICAvLyAgICAga2V5UG9zaXRpb24sXG4gICAgLy8gICAgIGZvY3VzUG9zaXRpb24sXG4gICAgLy8gICAgIHdpZHRoU2NhbGU6IGtleVBvc2l0aW9uLndpZHRoIC8gZm9jdXNQb3NpdGlvbi53aWR0aCxcbiAgICAvLyAgICAgaGVpZ2h0U2NhbGU6IGtleVBvc2l0aW9uLmhlaWdodCAvIGZvY3VzUG9zaXRpb24uaGVpZ2h0XG4gICAgLy8gICB9KTtcbiAgICAvLyAgIC8vIEFwcGx5IHNjYWxlIGZhY3RvciB0byBlbGVtJCB0byBmaXQgZGVmYXVsdCBrZXkgcG9zaXRpb24gaW5zaWRlIGNvbnRhaW5lciRcbiAgICAvLyAgIFUuZ3NhcC5zZXQoZWxlbSQsIHtcbiAgICAvLyAgICAgc2NhbGU6IE1hdGgubWluKFxuICAgIC8vICAgICAgIGtleVBvc2l0aW9uLndpZHRoIC8gZm9jdXNQb3NpdGlvbi53aWR0aCxcbiAgICAvLyAgICAgICBrZXlQb3NpdGlvbi5oZWlnaHQgLyBmb2N1c1Bvc2l0aW9uLmhlaWdodFxuICAgIC8vICAgICApICogKHNjYWxlTXVsdCA/PyAxKVxuICAgIC8vICAgfSk7XG4gICAgLy8gICAvLyBBcHBseSB0b3AsIGxlZnQgYW5kIHRyYW5zZm9ybU9yaWdpbiB2YWx1ZSB0byBrZXlJbWdDb250YWluZXIsIGFjY291bnRpbmcgZm9yIHgveVBlcmNlbnQgLTUwXG4gICAgLy8gICBVLmdzYXAuc2V0KGltZ0NvbnRhaW5lciQsIHtcbiAgICAvLyAgICAgdG9wOiAoMC41ICogQy5DbG9ja0tleVNxdWFyZVNpemUpIC0gZm9jdXNQb3NpdGlvbi55ICsgKHlTaGlmdCA/PyAwKSxcbiAgICAvLyAgICAgbGVmdDogKDAuNSAqIEMuQ2xvY2tLZXlTcXVhcmVTaXplKSAtIGZvY3VzUG9zaXRpb24ueCArICh4U2hpZnQgPz8gMCksXG4gICAgLy8gICAgIHRyYW5zZm9ybU9yaWdpbjogYCR7Zm9jdXNQb3NpdGlvbi54ICsgKHhTaGlmdCA/PyAwKX1weCAke2ZvY3VzUG9zaXRpb24ueSArICh5U2hpZnQgPz8gMCl9cHhgXG4gICAgLy8gICB9KTtcbiAgICAvLyB9XG4gICAgZm9ybWF0TGFiZWxzKGtleUVsZW1zJCkge1xuICAgICAgICBjb25zdCB7IGxhYmVsJCwgY2xvY2tzLCBmYWN0aW9uTGFiZWwkLCBwcm9qZWN0TGFiZWwkLCBzY29yZUxhYmVsJCB9ID0ga2V5RWxlbXMkO1xuICAgICAgICAvLyBDb2xsZWN0IHJlbGV2YW50IGxhYmVsIGVsZW1lbnRzLCBkZXNpcmVkIGFzcGVjdCByYXRpbywgYW5kIG1heGltdW0gbGluZSBjb3VudCwgdGhlbiBhcHBseSBhZGp1c3RtZW50cyB0byB0aGUgbGFiZWwgY29udGFpbmVyIGZvciBhIHBsZWFzaW5nIGFzcGVjdCByYXRpb1xuICAgICAgICBbXG4gICAgICAgICAgICBbbGFiZWwkLCAyLCA0XSxcbiAgICAgICAgICAgIGZhY3Rpb25MYWJlbCQgPyBbZmFjdGlvbkxhYmVsJCwgMiwgMl0gOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBwcm9qZWN0TGFiZWwkID8gW3Byb2plY3RMYWJlbCQsIDIsIDJdIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgc2NvcmVMYWJlbCQgPyBbc2NvcmVMYWJlbCQsIDIsIDJdIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgLi4udGhpcy5jbG9ja3MubWFwKChjbG9jaykgPT4gW2Nsb2Nrc1tjbG9jay5pZF0uY2xvY2tMYWJlbCQsIDIuNSwgM10pXG4gICAgICAgIF0uZmlsdGVyKEJvb2xlYW4pLmZvckVhY2goKFtsYWJlbEVsZW0kLCBhc3BlY3RSYXRpbywgbWF4TGluZXNdKSA9PiB7XG4gICAgICAgICAgICBVLmFkanVzdFRleHRDb250YWluZXJBc3BlY3RSYXRpbyhsYWJlbEVsZW0kLCBhc3BlY3RSYXRpbywgbWF4TGluZXMpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgc2V0VG9EaXNwbGF5TW9kZShrZXlFbGVtcyQsIGRpc3BsYXlNb2RlLCBpc1VwZGF0aW5nVGFyZ2V0ID0gdHJ1ZSkge1xuICAgICAgICBjb25zdCB7IGtleVR3ZWVuVmFycywga2V5SW1nQ29udFR3ZWVuVmFycyB9ID0gdGhpcy5nZXRWYXJzRm9yRGlzcGxheU1vZGUoa2V5RWxlbXMkLCBkaXNwbGF5TW9kZSk7XG4gICAgICAgIFUuZ3NhcC5zZXQoa2V5RWxlbXMkLmVsZW0kLCBrZXlUd2VlblZhcnMpO1xuICAgICAgICBVLmdzYXAuc2V0KGtleUVsZW1zJC5pbWdDb250YWluZXIkLCBrZXlJbWdDb250VHdlZW5WYXJzKTtcbiAgICAgICAgaWYgKGlzVXBkYXRpbmdUYXJnZXQgJiYgZGlzcGxheU1vZGUgIT09IHRoaXMuZGlzcGxheU1vZGUpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiZGlzcGxheU1vZGVcIiwgZGlzcGxheU1vZGUpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGluaXRFbGVtZW50c0luQ29udGV4dChodG1sLCBkaXNwbGF5TW9kZSwgaXNVcGRhdGluZ1RhcmdldCA9IHRydWUpIHtcbiAgICAgICAgY29uc3Qga2V5RWxlbXMkID0gdGhpcy5nZXRFbGVtZW50cyQoaHRtbCk7XG4gICAgICAgIGRpc3BsYXlNb2RlID8/PSB0aGlzLmRpc3BsYXlNb2RlO1xuICAgICAgICB0aGlzLnNldFRvRGlzcGxheU1vZGUoa2V5RWxlbXMkLCBkaXNwbGF5TW9kZSwgaXNVcGRhdGluZ1RhcmdldCk7XG4gICAgICAgIHRoaXMuZm9ybWF0TGFiZWxzKGtleUVsZW1zJCk7XG4gICAgICAgIC8vIElmIGRpc3BsYXlNb2RlIHN0YXJ0cyB3aXRoICdwcmVzZW50JyBvciBpcyBhbiBpbnRlZ2VyLCBmYWRlIG91dCBhbGwgbGFiZWwgZWxlbWVudHNcbiAgICAgICAgaWYgKGRpc3BsYXlNb2RlLnRvU3RyaW5nKCkuc3RhcnRzV2l0aChcInByZXNlbnRcIikgfHwgTnVtYmVyLmlzSW50ZWdlcihkaXNwbGF5TW9kZSkpIHtcbiAgICAgICAgICAgIFUuZ3NhcC50byhrZXlFbGVtcyQuY29udGFpbmVyJC5maW5kKFwiLmNsb2NrLWxhYmVsLCAuY2xvY2sta2V5LWxhYmVsXCIpLCB7IGF1dG9BbHBoYTogMCwgZHVyYXRpb246IDAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGtleUVsZW1zJDtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIGFzeW5jIGFkZFRvU2NlbmUoc2NlbmVJRCA9IGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQpIHtcbiAgICAgICAgaWYgKHRoaXMuaXNJblNjZW5lKHNjZW5lSUQpKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyBzY2VuZUlEcyB9ID0gdGhpcztcbiAgICAgICAgc2NlbmVJRHMucHVzaChzY2VuZUlEKTtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoe1xuICAgICAgICAgICAgaXNWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIHNjZW5lSURzXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLnJlbmRlclRhcmdldEFuZEtlZXBlcigpO1xuICAgIH1cbiAgICBhc3luYyByZW1vdmVGcm9tU2NlbmUoc2NlbmVJRCA9IGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzSW5TY2VuZShzY2VuZUlEKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgc2NlbmVJRHMgfSA9IHRoaXM7XG4gICAgICAgIFUucmVtb3ZlKHNjZW5lSURzLCBzY2VuZUlEKTtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoXCJzY2VuZUlEc1wiLCBzY2VuZUlEcyk7XG4gICAgICAgIHRoaXMucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7XG4gICAgfVxuICAgIGNsb3NlQ2xvY2tLZXkoeyBjb250YWluZXIkIH0pIHtcbiAgICAgICAgY29udGFpbmVyJC5yZW1vdmUoKTtcbiAgICB9XG4gICAgZ2V0IHN2Z0RhdGEoKSB7XG4gICAgICAgIGlmICh0aGlzLnNpemUgPT09IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNDbG9ja0tleS5zdmdEYXRhXSBFcnJvciBzaXplIGlzIDAuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleURhdGEgPSBDbG9ja0tleV9TVkdEQVRBW3RoaXMuc2l6ZV07XG4gICAgICAgIGxldCBwYXRoO1xuICAgICAgICBpZiAodGhpcy5zaXplID09PSAxICYmIGtleURhdGEucGF0aHMpIHtcbiAgICAgICAgICAgIHBhdGggPSBrZXlEYXRhLnBhdGhzW3RoaXMub25lS2V5SW5kZXhdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGtleURhdGEucGF0aCkge1xuICAgICAgICAgICAgcGF0aCA9IGtleURhdGEucGF0aDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNDbG9ja0tleS5zdmdEYXRhXSBFcnJvciBwYXRoIGlzIG5vdCBkZWZpbmVkLlwiKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgd2lkdGg6IGtleURhdGEud2lkdGgsXG4gICAgICAgICAgICBoZWlnaHQ6IGtleURhdGEuaGVpZ2h0LFxuICAgICAgICAgICAgcGF0aCxcbiAgICAgICAgICAgIGNsb2Nrczoga2V5RGF0YS5jbG9ja3NcbiAgICAgICAgfTtcbiAgICB9XG4gICAgaXNJbk92ZXJsYXkoZWxlbSkge1xuICAgICAgICByZXR1cm4gJChlbGVtKS5oYXNDbGFzcyhcIi5vdmVybGF5LXNlY3Rpb25cIikgfHwgJChlbGVtKS5jbG9zZXN0KFwiLm92ZXJsYXktc2VjdGlvblwiKS5sZW5ndGggPiAwO1xuICAgIH1cbiAgICBnZXQga2V5SGVpZ2h0KCkgeyByZXR1cm4gdGhpcy5zdmdEYXRhLmhlaWdodDsgfVxuICAgIGdldCBrZXlXaWR0aCgpIHsgcmV0dXJuIHRoaXMuc3ZnRGF0YS53aWR0aDsgfVxuICAgIGdldCBrZXlWaWV3Ym94KCkgeyByZXR1cm4gYDAgMCAke3RoaXMuc3ZnRGF0YS53aWR0aH0gJHt0aGlzLnN2Z0RhdGEuaGVpZ2h0fWA7IH1cbiAgICBnZXQga2V5UGF0aCgpIHsgcmV0dXJuIHRoaXMuc3ZnRGF0YS5wYXRoOyB9XG4gICAgZ2V0IGNsb2NrU2l6ZSgpIHsgcmV0dXJuIHRoaXMuc3ZnRGF0YS5jbG9ja3Muc2l6ZTsgfVxuICAgIGdldENsb2NrUG9zaXRpb24oY2xvY2tJbmRleCA9IDApIHtcbiAgICAgICAgaWYgKGNsb2NrSW5kZXggPiB0aGlzLnNpemUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrS2V5LmdldENsb2NrUG9zaXRpb25dIEVycm9yIGNsb2NrSW5kZXggJyR7Y2xvY2tJbmRleH0nIGlzIGdyZWF0ZXIgdGhhbiBrZXkgc2l6ZSAnJHt0aGlzLnNpemV9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY2xvY2tJbmRleCA8IDApIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrS2V5LmdldENsb2NrUG9zaXRpb25dIEVycm9yIGNsb2NrSW5kZXggJyR7Y2xvY2tJbmRleH0nIGlzIGxlc3MgdGhhbiAwLmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLnN2Z0RhdGEuY2xvY2tzW2Nsb2NrSW5kZXhdO1xuICAgIH1cbiAgICBwb3NpdGlvbkRyYWdnZXI7XG4gICAgcmVtb3ZlUG9zaXRpb25EcmFnZ2VyKCkge1xuICAgICAgICB0aGlzLnBvc2l0aW9uRHJhZ2dlcj8udGFyZ2V0LnJlbW92ZSgpO1xuICAgICAgICB0aGlzLnBvc2l0aW9uRHJhZ2dlcj8ua2lsbCgpO1xuICAgICAgICBkZWxldGUgdGhpcy5wb3NpdGlvbkRyYWdnZXI7XG4gICAgfVxuICAgIHNwYXduUG9zaXRpb25EcmFnZ2VyKGNvbnRhaW5lckVsZW0kID0gZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLmNsb2NrS2V5U2VjdGlvbiQpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICh0aGlzLnBvc2l0aW9uRHJhZ2dlcikge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVQb3NpdGlvbkRyYWdnZXIoKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkcmFnRWxlbSQgPSAkKGA8ZGl2IGlkPVwiRHJhZ2dlci0ke3RoaXMuaWR9XCIgY2xhc3M9XCJjbG9jay1rZXktY29udGFpbmVyIGNsb2NrLWtleS1kcmFnZ2VyXCIgZGF0YS1zaXplPVwiJHt0aGlzLnNpemV9XCI+PC9kaXY+YClcbiAgICAgICAgICAgIC5hcHBlbmRUbyhjb250YWluZXJFbGVtJCk7XG4gICAgICAgIGlmICh0aGlzLm92ZXJsYXlQb3NpdGlvbikge1xuICAgICAgICAgICAgZHJhZ0VsZW0kLmNzcyh7XG4gICAgICAgICAgICAgICAgbGVmdDogdGhpcy5vdmVybGF5UG9zaXRpb24ueCxcbiAgICAgICAgICAgICAgICB0b3A6IHRoaXMub3ZlcmxheVBvc2l0aW9uLnlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucG9zaXRpb25EcmFnZ2VyID0gbmV3IERyYWdnZXIoZHJhZ0VsZW0kLCB7XG4gICAgICAgICAgICB0eXBlOiBcInRvcCxsZWZ0XCIsXG4gICAgICAgICAgICBvbkRyYWdTdGFydCgpIHtcbiAgICAgICAgICAgICAgICAkKHRoaXMudGFyZ2V0KS5jc3MoXCJiYWNrZ3JvdW5kXCIsIFwicmdiYSgyNTUsIDI1NSwgMCwgMC4yNSlcIik7XG4gICAgICAgICAgICAgICAgJCh0aGlzLnRhcmdldCkuY3NzKFwib3V0bGluZUNvbG9yXCIsIFwicmdiYSgyNTUsIDI1NSwgMCwgMSlcIik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25EcmFnRW5kKCkge1xuICAgICAgICAgICAgICAgICQodGhpcy50YXJnZXQpLmNzcyhcImJhY2tncm91bmRcIiwgXCJyZ2JhKDI1NSwgMCwgMjU1LCAwLjI1KVwiKTtcbiAgICAgICAgICAgICAgICAkKHRoaXMudGFyZ2V0KS5jc3MoXCJvdXRsaW5lQ29sb3JcIiwgXCJyZ2JhKDI1NSwgMCwgMjU1LCAxKVwiKTtcbiAgICAgICAgICAgICAgICBzZWxmLm92ZXJsYXlQb3NpdGlvbiA9IHsgeDogdGhpcy5lbmRYLCB5OiB0aGlzLmVuZFkgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN3aXRjaFRvTW9kZShrZXlFbGVtcyQsIGRpc3BsYXlNb2RlLCBleHRlbmRLZXlWYXJzID0ge30sIGV4dGVuZEtleUNvbnRhaW5lclZhcnMgPSB7fSwgaXNVcGRhdGluZ1RhcmdldCA9IHRydWUsIGNhbGxiYWNrKSB7XG4gICAgICAgIGNvbnN0IHsgZWxlbSQsIGltZ0NvbnRhaW5lciQgfSA9IGtleUVsZW1zJDtcbiAgICAgICAgY29uc3QgeyBrZXlUd2VlblZhcnMsIGtleUltZ0NvbnRUd2VlblZhcnMgfSA9IHRoaXMuZ2V0VmFyc0ZvckRpc3BsYXlNb2RlKGtleUVsZW1zJCwgZGlzcGxheU1vZGUpO1xuICAgICAgICBjb25zdCBjdXJyZW50RGlzcGxheU1vZGUgPSB0aGlzLmRpc3BsYXlNb2RlO1xuICAgICAgICBjb25zdCByYW5kb21JRCA9IFUuZ3NhcC51dGlscy5yYW5kb20oMSwgMTAwMCwgMSk7XG4gICAgICAgIHJldHVybiBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgY2FsbGJhY2tTY29wZTogdGhpcyxcbiAgICAgICAgICAgIHBhdXNlZDogdHJ1ZSxcbiAgICAgICAgICAgIG9uU3RhcnQoKSB7XG4gICAgICAgICAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJCbGFkZXNDbG9ja0tleVwiLCBgc3dpdGNoVG9Nb2RlICMke3JhbmRvbUlEfSAtIFNUQVJUYCwgeyBrZXk6IHRoaXMsIGtleUVsZW1zJCwgZGlzcGxheU1vZGUgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25Db21wbGV0ZSgpIHtcbiAgICAgICAgICAgICAgICBlTG9nLmNoZWNrTG9nMyhcIkJsYWRlc0Nsb2NrS2V5XCIsIGBzd2l0Y2hUb01vZGUgIyR7cmFuZG9tSUR9IC0gQ09NUExFVEVgLCB7IGtleTogdGhpcywga2V5RWxlbXMkLCBkaXNwbGF5TW9kZSB9KTtcbiAgICAgICAgICAgICAgICBpZiAoaXNVcGRhdGluZ1RhcmdldCAmJiBkaXNwbGF5TW9kZSAhPT0gdGhpcy5jdXJyZW50RGlzcGxheU1vZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJkaXNwbGF5TW9kZVwiLCBkaXNwbGF5TW9kZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IGNhbGxiYWNrPy4oKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaz8uKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uUmV2ZXJzZUNvbXBsZXRlKCkge1xuICAgICAgICAgICAgICAgIGVMb2cuY2hlY2tMb2czKFwiQmxhZGVzQ2xvY2tLZXlcIiwgYHN3aXRjaFRvTW9kZSAjJHtyYW5kb21JRH0gLSBSRVZFUlNFIENPTVBMRVRFYCwgeyBrZXk6IHRoaXMsIGtleUVsZW1zJCwgZGlzcGxheU1vZGUgfSk7XG4gICAgICAgICAgICAgICAgaWYgKGlzVXBkYXRpbmdUYXJnZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJkaXNwbGF5TW9kZVwiLCBjdXJyZW50RGlzcGxheU1vZGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgICAgIC50byhlbGVtJCwgeyAuLi5rZXlUd2VlblZhcnMsIC4uLmV4dGVuZEtleVZhcnMgfSwgMClcbiAgICAgICAgICAgIC50byhpbWdDb250YWluZXIkLCB7IC4uLmtleUltZ0NvbnRUd2VlblZhcnMsIC4uLmV4dGVuZEtleUNvbnRhaW5lclZhcnMgfSwgMCk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEFOSU1BVEVEIFVQREFURVMgKEJvdGggR00tT25seSBBTkQgU29ja2V0IENhbGxzKVxuICAgIC8vICAgICNyZWdpb24gICA+IFNPQ0tFVCBDQUxMUzogX1NvY2tldENhbGwgLyBzdGF0aWMgX1NvY2tldFJlc3BvbnNlIC8gX0FuaW1hdGlvblxuICAgIGZhZGVJbk5hbWVfQW5pbWF0aW9uKGtleUVsZW1zJCkge1xuICAgICAgICBpZiAoIXRoaXMubmFtZSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gVS5nc2FwLmVmZmVjdHMuYmx1clJldmVhbChrZXlFbGVtcyQubGFiZWwkLCB7XG4gICAgICAgICAgICBpZ25vcmVNYXJnaW46IHRydWUsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC43NVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZmFkZUluTmFtZV9Tb2NrZXRDYWxsKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImZhZGVJbk5hbWVfU29ja2V0Q2FsbFwiLCBkaXNwbGF5Q29udGV4dCwgdGhpcy5pZCk7XG4gICAgfVxuICAgIHN0YXRpYyBmYWRlSW5OYW1lX1NvY2tldFJlc3BvbnNlKGRpc3BsYXlDb250ZXh0LCBrZXlJRCkge1xuICAgICAgICBjb25zdCBrZXkgPSBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAga2V5LmZhZGVJbk5hbWVfQW5pbWF0aW9uKGtleS5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICB9XG4gICAgZmFkZU91dE5hbWVfQW5pbWF0aW9uKGtleUVsZW1zJCkge1xuICAgICAgICBpZiAoIXRoaXMubmFtZSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gVS5nc2FwLmVmZmVjdHMuYmx1clJlbW92ZShrZXlFbGVtcyQubGFiZWwkLCB7XG4gICAgICAgICAgICBpZ25vcmVNYXJnaW46IHRydWUsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC43NVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZmFkZU91dE5hbWVfU29ja2V0Q2FsbChkaXNwbGF5Q29udGV4dCkge1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5mYWRlT3V0TmFtZV9BbmltYXRpb24odGhpcy5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yT3RoZXJzKFwiZmFkZU91dE5hbWVfU29ja2V0Q2FsbFwiLCBkaXNwbGF5Q29udGV4dCwgdGhpcy5pZCk7XG4gICAgfVxuICAgIHN0YXRpYyBmYWRlT3V0TmFtZV9Tb2NrZXRSZXNwb25zZShkaXNwbGF5Q29udGV4dCwga2V5SUQpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoa2V5SUQpO1xuICAgICAgICBpZiAoIWtleSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGtleS5mYWRlT3V0TmFtZV9BbmltYXRpb24oa2V5LmdldEVsZW1lbnRzJChkaXNwbGF5Q29udGV4dCkpO1xuICAgIH1cbiAgICAvLyAgICAjZW5kcmVnaW9uXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQWRkaW5nICYgUmVtb3ZpbmcgQ2xvY2tzIH5cbiAgICBhc3luYyB1cGRhdGVDbG9ja0luZGljZXMoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlVGFyZ2V0KFwiY2xvY2tzRGF0YVwiLCBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModGhpcy5jbG9ja3NEYXRhKVxuICAgICAgICAgICAgLm1hcCgoW2lkLCBkYXRhXSwgaW5kZXgpID0+IFtpZCwgeyAuLi5kYXRhLCBpbmRleCB9XSkpKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xvY2tzO1xuICAgIH1cbiAgICBhc3luYyBhZGRDbG9jayhjbG9ja1NjaGVtYSA9IHt9KSB7XG4gICAgICAgIC8vIERlcml2ZSBjbG9jayBkYXRhIGZyb20gY29uZmlnXG4gICAgICAgIGNvbnN0IGNEYXRhID0gQmxhZGVzQ2xvY2suUGFyc2VDb25maWdUb0RhdGEoe1xuICAgICAgICAgICAgLi4uQmxhZGVzQ2xvY2suQXBwbHlTY2hlbWFEZWZhdWx0cyhjbG9ja1NjaGVtYSksXG4gICAgICAgICAgICBpbmRleDogdGhpcy5zaXplLFxuICAgICAgICAgICAgdGFyZ2V0SUQ6IHRoaXMudGFyZ2V0SUQsXG4gICAgICAgICAgICB0YXJnZXRLZXk6IGAke3RoaXMudGFyZ2V0S2V5UHJlZml4fS5jbG9ja3NEYXRhYCxcbiAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIGNvbnN0IGNsb2NrRGF0YSA9IHRoaXMucGFyc2VDbG9ja0NvbmZpZyhjbG9ja0NvbmZpZyk7XG4gICAgICAgIC8vIFdyaXRlIHRvIHN0YXRlXG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlVGFyZ2V0KGBjbG9ja3NEYXRhLiR7Y0RhdGEuaWR9YCwgY0RhdGEpO1xuICAgICAgICAvLyBSZWduZXJhdGUgY2xvY2tzIGNvbGxlY3Rpb25cbiAgICAgICAgdm9pZCB0aGlzLmNsb2NrcztcbiAgICAgICAgdGhpcy5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTtcbiAgICB9XG4gICAgYXN5bmMgZGVsZXRlQ2xvY2soY2xvY2tJRCkge1xuICAgICAgICBpZiAodGhpcy5zaXplIDw9IDEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNDbG9ja0tleS5kZWxldGVDbG9jaygpXSBDYW5ub3QgcmVkdWNlIG51bWJlciBvZiBjbG9ja3MgYmVsb3cgMSFcIik7XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2tJRCA/Pz0gQXJyYXkuZnJvbSh0aGlzLmNsb2NrcykucG9wKCk/LmlkO1xuICAgICAgICBpZiAoIWNsb2NrSUQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLmdldENsb2NrQnlJRChjbG9ja0lEKT8uZGVsZXRlKCk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlQ2xvY2tJbmRpY2VzKCk7XG4gICAgICAgIC8vIFJlZ2VuZXJhdGUgY2xvY2tzIGNvbGxlY3Rpb25cbiAgICAgICAgdm9pZCB0aGlzLmNsb2NrcztcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gT1ZFUlJJREVTOiBBc3luYyBVcGRhdGUgTWV0aG9kc1xuICAgIHJlbmRlclRhcmdldEFuZEtlZXBlcigpIHtcbiAgICAgICAgdGhpcy5yZW5kZXJUYXJnZXQoKTtcbiAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2VlcGVyLnNoZWV0Py5yZW5kZXIoKTtcbiAgICB9XG4gICAgcmVuZGVyVGFyZ2V0KCkge1xuICAgICAgICB0aGlzLnRhcmdldC5zaGVldD8ucmVuZGVyKCk7XG4gICAgfVxufVxuY2xhc3MgQmxhZGVzQ2xvY2sgZXh0ZW5kcyBCbGFkZXNUYXJnZXRMaW5rIHtcbiAgICAvLyAjcmVnaW9uIFNUQVRJQyBNRVRIT0RTIH5cbiAgICBzdGF0aWMgQXBwbHlTY2hlbWFEZWZhdWx0cyhzY2hlbWFEYXRhKSB7XG4gICAgICAgIGNvbnN0IG5hbWVkVmFsdWVNYXggPSB7XG4gICAgICAgICAgICBuYW1lOiBzY2hlbWFEYXRhLm5hbWUgPz8gXCJcIixcbiAgICAgICAgICAgIHZhbHVlOiBzY2hlbWFEYXRhLnZhbHVlID8/IDAsXG4gICAgICAgICAgICBtYXg6IHNjaGVtYURhdGEubWF4ID8/IDhcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGluZGV4OiAwLFxuICAgICAgICAgICAgY29sb3I6IENsb2NrQ29sb3Iud2hpdGUsXG4gICAgICAgICAgICBpc1Zpc2libGU6ICFVLmlzSW50KHNjaGVtYURhdGEuaW5kZXgpIHx8IHNjaGVtYURhdGEuaW5kZXggPT09IDAsXG4gICAgICAgICAgICBpc05hbWVWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgIGlzSGlnaGxpZ2h0ZWQ6IGZhbHNlLFxuICAgICAgICAgICAgaXNBY3RpdmU6ICFVLmlzSW50KHNjaGVtYURhdGEuaW5kZXgpIHx8IHNjaGVtYURhdGEuaW5kZXggPT09IDAsXG4gICAgICAgICAgICAuLi5zY2hlbWFEYXRhLFxuICAgICAgICAgICAgLi4ubmFtZWRWYWx1ZU1heFxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBHRVRURVJTICYgU0VUVEVSUyB+XG4gICAgZ2V0IGNhbkVkaXQoKSB7XG4gICAgICAgIC8vIHJldHVybiB0cnVlIGlmIHVzZXIgaGFzIGVkaXQgcGVybWlzc2lvbnMgb24gcGFyZW50IGRvY3VtZW50LCBhbmQgY2xvY2sgaXNcbiAgICAgICAgLy8gdmlzaWJsZSBhbmQgYWN0aXZlLlxuICAgICAgICBjb25zb2xlLmxvZyhcIk5PVEU6IEFsbCBDbG9ja3MgY3VycmVudGx5IEVkaXRhYmxlOyBzZWUgbGluZSA3MSBvZiBCbGFkZXNDbG9jay50c1wiKTtcbiAgICAgICAgcmV0dXJuIHRoaXMuaXNWaXNpYmxlICYmIHRoaXMuaXNBY3RpdmU7XG4gICAgfVxuICAgIGdldCBkYXRhKCkgeyByZXR1cm4gdGhpcy5saW5rRGF0YTsgfVxuICAgIGdldCBuYW1lKCkgeyByZXR1cm4gdGhpcy5kYXRhLm5hbWU7IH1cbiAgICBzZXQgbmFtZSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJuYW1lXCIsIHZhbClcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5wYXJlbnRLZXkucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgIH1cbiAgICBnZXQgdmFsdWUoKSB7IHJldHVybiBVLnBJbnQodGhpcy5kYXRhLnZhbHVlKTsgfVxuICAgIHNldCB2YWx1ZSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJ2YWx1ZVwiLCBVLnBJbnQodmFsKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5wYXJlbnRLZXkucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgIH1cbiAgICBnZXQgbWF4KCkgeyByZXR1cm4gVS5wSW50KHRoaXMuZGF0YS5tYXgpOyB9XG4gICAgc2V0IG1heCh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJtYXhcIiwgVS5wSW50KHZhbCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucGFyZW50S2V5LnJlbmRlclRhcmdldEFuZEtlZXBlcigpOyB9KTtcbiAgICB9XG4gICAgZ2V0IGNvbG9yKCkgeyByZXR1cm4gdGhpcy5kYXRhLmNvbG9yID8/IENsb2NrQ29sb3Iud2hpdGU7IH1cbiAgICBzZXQgY29sb3IodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiY29sb3JcIiwgdmFsKVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4geyB0aGlzLnBhcmVudEtleS5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTsgfSk7XG4gICAgfVxuICAgIGdldCBpc0FjdGl2ZSgpIHsgcmV0dXJuIFUucEJvb2wodGhpcy5kYXRhLmlzQWN0aXZlKTsgfVxuICAgIHNldCBpc0FjdGl2ZSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJpc0FjdGl2ZVwiLCBVLnBCb29sKHZhbCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucGFyZW50S2V5LnJlbmRlclRhcmdldEFuZEtlZXBlcigpOyB9KTtcbiAgICB9XG4gICAgZ2V0IHBhcmVudEtleSgpIHtcbiAgICAgICAgY29uc3QgcEtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KHRoaXMuZGF0YS5wYXJlbnRLZXlJRCk7XG4gICAgICAgIGlmICghcEtleSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2tLZXkucGFyZW50S2V5XSBObyBwYXJlbnQga2V5IGZvdW5kIGZvciBjbG9jayAke3RoaXMuaWR9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBLZXk7XG4gICAgfVxuICAgIGdldCBpc05hbWVWaXNpYmxlKCkgeyByZXR1cm4gVS5wQm9vbCh0aGlzLmRhdGEuaXNOYW1lVmlzaWJsZSk7IH1cbiAgICBzZXQgaXNOYW1lVmlzaWJsZSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJpc05hbWVWaXNpYmxlXCIsIFUucEJvb2wodmFsKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5wYXJlbnRLZXkucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgIH1cbiAgICBnZXQgaXNWaXNpYmxlKCkgeyByZXR1cm4gVS5wQm9vbCh0aGlzLmRhdGEuaXNWaXNpYmxlKTsgfVxuICAgIHNldCBpc1Zpc2libGUodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiaXNWaXNpYmxlXCIsIFUucEJvb2wodmFsKSlcbiAgICAgICAgICAgIC50aGVuKCgpID0+IHsgdGhpcy5wYXJlbnRLZXkucmVuZGVyVGFyZ2V0QW5kS2VlcGVyKCk7IH0pO1xuICAgIH1cbiAgICBnZXQgaXNIaWdobGlnaHRlZCgpIHsgcmV0dXJuIFUucEJvb2wodGhpcy5kYXRhLmlzSGlnaGxpZ2h0ZWQpOyB9XG4gICAgc2V0IGlzSGlnaGxpZ2h0ZWQodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiaXNIaWdobGlnaHRlZFwiLCBVLnBCb29sKHZhbCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucGFyZW50S2V5LnJlbmRlclRhcmdldEFuZEtlZXBlcigpOyB9KTtcbiAgICB9XG4gICAgZ2V0IGluZGV4KCkgeyByZXR1cm4gVS5wSW50KHRoaXMuZGF0YS5pbmRleCk7IH1cbiAgICBzZXQgaW5kZXgodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiaW5kZXhcIiwgVS5wSW50KHZhbCkpXG4gICAgICAgICAgICAudGhlbigoKSA9PiB7IHRoaXMucGFyZW50S2V5LnJlbmRlclRhcmdldEFuZEtlZXBlcigpOyB9KTtcbiAgICB9XG4gICAgZ2V0IGlzRW1wdHkoKSB7IHJldHVybiB0aGlzLnZhbHVlID09PSAwOyB9XG4gICAgZ2V0IGlzQ29tcGxldGUoKSB7IHJldHVybiB0aGlzLnZhbHVlID49IHRoaXMubWF4OyB9XG4gICAgZ2V0IHJvbGxPcHBDbG9jaygpIHsgcmV0dXJuIHRoaXM7IH1cbiAgICBnZXQgcm9sbE9wcE5hbWUoKSB7IHJldHVybiB0aGlzLm5hbWU7IH1cbiAgICBnZXQgcm9sbE9wcFR5cGUoKSB7IHJldHVybiBcImNsb2NrXCI7IH1cbiAgICBnZXQgY29sb3JTZWxlY3RPcHRpb25zKCkge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgeyB2YWx1ZTogQ2xvY2tDb2xvci53aGl0ZSwgZGlzcGxheTogXCLwn5SYXCIgfSxcbiAgICAgICAgICAgIHsgdmFsdWU6IENsb2NrQ29sb3IueWVsbG93LCBkaXNwbGF5OiBcIvCfk4BcIiB9LFxuICAgICAgICAgICAgeyB2YWx1ZTogQ2xvY2tDb2xvci5jeWFuLCBkaXNwbGF5OiBcIvCflLVcIiB9LFxuICAgICAgICAgICAgeyB2YWx1ZTogQ2xvY2tDb2xvci5yZWQsIGRpc3BsYXk6IFwi8J+UtFwiIH1cbiAgICAgICAgXTtcbiAgICB9XG4gICAgZ2V0IG1heFNlbGVjdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB7IHZhbHVlOiAyLCBkaXNwbGF5OiAyIH0sXG4gICAgICAgICAgICB7IHZhbHVlOiAzLCBkaXNwbGF5OiAzIH0sXG4gICAgICAgICAgICB7IHZhbHVlOiA0LCBkaXNwbGF5OiA0IH0sXG4gICAgICAgICAgICB7IHZhbHVlOiA1LCBkaXNwbGF5OiA1IH0sXG4gICAgICAgICAgICB7IHZhbHVlOiA2LCBkaXNwbGF5OiA2IH0sXG4gICAgICAgICAgICB7IHZhbHVlOiA4LCBkaXNwbGF5OiA4IH0sXG4gICAgICAgICAgICB7IHZhbHVlOiAxMCwgZGlzcGxheTogMTAgfSxcbiAgICAgICAgICAgIHsgdmFsdWU6IDEyLCBkaXNwbGF5OiAxMiB9XG4gICAgICAgIF07XG4gICAgfVxuICAgIGdldCB2YWx1ZVNlbGVjdE9wdGlvbnMoKSB7XG4gICAgICAgIGNvbnN0IHJldHVyblZhbHMgPSBbXTtcbiAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPD0gdGhpcy5tYXg7IGkrKykge1xuICAgICAgICAgICAgcmV0dXJuVmFscy5wdXNoKHsgdmFsdWU6IGksIGRpc3BsYXk6IGkgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJldHVyblZhbHM7XG4gICAgfVxuICAgIC8vIFJldHVybnMgd2hpY2ggaGVtaXNwaGVyZSBvZiB0aGUgY2xvY2sgd2lsbCBzaG93IHRoZSBmaW5hbCBjaGFuZ2UgaWYgc2VnbWVudERlbHRhIHNlZ21lbnRzIGFyZSBhZGRlZC9yZW1vdmVkLlxuICAgIGdldEFjdGl2ZVNpZGUoc2VnbWVudERlbHRhID0gMCkge1xuICAgICAgICBjb25zdCBmaW5hbENsb2NrVmFsdWUgPSBNYXRoLm1pbih0aGlzLm1heCwgTWF0aC5tYXgoMCwgdGhpcy52YWx1ZSArIHNlZ21lbnREZWx0YSkpO1xuICAgICAgICBjb25zdCBoYWxmQ2xvY2tWYWx1ZSA9IHRoaXMubWF4IC8gMjtcbiAgICAgICAgaWYgKHNlZ21lbnREZWx0YSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGZpbmFsQ2xvY2tWYWx1ZSA+PSBoYWxmQ2xvY2tWYWx1ZVxuICAgICAgICAgICAgICAgID8gXCJsZWZ0XCJcbiAgICAgICAgICAgICAgICA6IFwicmlnaHRcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmluYWxDbG9ja1ZhbHVlID4gaGFsZkNsb2NrVmFsdWVcbiAgICAgICAgICAgID8gXCJsZWZ0XCJcbiAgICAgICAgICAgIDogXCJyaWdodFwiO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBIVE1MIElOVEVSQUNUSU9OIH5cbiAgICBnZXRFbGVtRnJvbURpc3BsYXlDb250ZXh0KGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGxldCBlbGVtJDtcbiAgICAgICAgY29uc3QgRE9NJCA9ICQoXCIudnR0LmdhbWUuc3lzdGVtLWV1bm9zLWJsYWRlc1wiKTtcbiAgICAgICAgc3dpdGNoIChkaXNwbGF5Q29udGV4dCkge1xuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXk6IHtcbiAgICAgICAgICAgICAgICBlbGVtJCA9IERPTSQuZmluZChgI2JsYWRlcy1vdmVybGF5ICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQucGNTaGVldDoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAuYWN0b3Iuc2hlZXQgLnBjICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQuZmFjdGlvblNoZWV0OiB7XG4gICAgICAgICAgICAgICAgZWxlbSQgPSBET00kLmZpbmQoYC5hY3Rvci5zaGVldCAuZmFjdGlvbiAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0LnByb2plY3RTaGVldDoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAuaXRlbS5zaGVldCAucHJvamVjdCAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0Rpc3BsYXlDb250ZXh0LnNjb3JlU2hlZXQ6IHtcbiAgICAgICAgICAgICAgICBlbGVtJCA9IERPTSQuZmluZChgLml0ZW0uc2hlZXQgLnNjb3JlICMke3RoaXMuaWR9YCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrRGlzcGxheUNvbnRleHQucm9sbENvbGxhYjoge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAucm9sbC1jb2xsYWItc2hlZXQgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgQ2xvY2tEaXNwbGF5Q29udGV4dC5jaGF0TWVzc2FnZToge1xuICAgICAgICAgICAgICAgIGVsZW0kID0gRE9NJC5maW5kKGAjY2hhdCAjJHt0aGlzLmlkfWApO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghZWxlbSQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNDbG9ja0tleS5nZXRFbGVtRnJvbURpc3BsYXlDb250ZXh0XSBFcnJvciBlbGVtJCBub3QgZm91bmQgZm9yIGtleSAnJHt0aGlzLmlkfScgZm9yIGRpc3BsYXkgY29udGV4dCAnJHtkaXNwbGF5Q29udGV4dH0nLmApO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbGVtJDtcbiAgICB9XG4gICAgZ2V0RWxlbWVudHMkKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGxldCBlbGVtJDtcbiAgICAgICAgaWYgKHR5cGVvZiBkaXNwbGF5Q29udGV4dCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZGlzcGxheUNvbnRleHQgPSB0aGlzLmdldEVsZW1Gcm9tRGlzcGxheUNvbnRleHQoZGlzcGxheUNvbnRleHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsZW0kID0gJChkaXNwbGF5Q29udGV4dCkuZmluZChgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgaWYgKCFlbGVtJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIGVsZW0kID0gJChkaXNwbGF5Q29udGV4dCkuY2xvc2VzdChgIyR7dGhpcy5pZH1gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWVsZW0kPy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gQ2Fubm90IGZpbmQgZWxlbWVudHMgZm9yIGRpc3BsYXkgY29udGV4dCAnJHtkaXNwbGF5Q29udGV4dH0nIG9mIGNsb2NrICcke3RoaXMuaWR9JyBvZiBrZXkgJyR7dGhpcy5wYXJlbnRLZXkuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVc2luZyBlbGVtJCBhcyBhIHJlZmVyZW5jZSwgbG9jYXRlIHJlbGV2YW50IGNsb2NrIGVsZW1lbnRzIGFuZCByZXR1cm4gdGhlbSBpbiBhIGRpY3Rpb25hcnkuXG4gICAgICAgIGNvbnN0IGNsb2NrRWxlbXMkID0ge1xuICAgICAgICAgICAgY2xvY2tFbGVtJDogZWxlbSRcbiAgICAgICAgfTtcbiAgICAgICAgLy8gR2V0IGVsZW1lbnRzIHRoYXQgd2lsbCBiZSB0aGVyZSByZWdhcmRsZXNzIG9mIGNvbnRleHQsIHRocm93aW5nIGVycm9ycyBpZiBub3QgZm91bmQuXG4gICAgICAgIGNvbnN0IGNvbnRhaW5lciQgPSBlbGVtJC5jbG9zZXN0KFwiLmNsb2NrLWNvbnRhaW5lclwiKTtcbiAgICAgICAgaWYgKCFjb250YWluZXIkLmxlbmd0aCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2suZ2V0RWxlbWVudHMkXSBFcnJvciAnLmNsb2NrLWNvbnRhaW5lcicgbm90IGZvdW5kIGZvciBjbG9jayAnJHt0aGlzLmlkfScgb2Yga2V5ICcke3RoaXMucGFyZW50S2V5LmlkfScuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2tFbGVtcyQuY2xvY2tDb250YWluZXIkID0gY29udGFpbmVyJDtcbiAgICAgICAgY29uc3QgbGFiZWwkID0gZWxlbSQuZmluZChcIi5jbG9jay1sYWJlbFwiKTtcbiAgICAgICAgaWYgKCFsYWJlbCQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNDbG9jay5nZXRFbGVtZW50cyRdIEVycm9yICcuY2xvY2stbGFiZWwnIG5vdCBmb3VuZCBmb3IgY2xvY2sgJyR7dGhpcy5pZH0nIG9mIGtleSAnJHt0aGlzLnBhcmVudEtleS5pZH0nLmApO1xuICAgICAgICB9XG4gICAgICAgIGNsb2NrRWxlbXMkLmNsb2NrTGFiZWwkID0gbGFiZWwkO1xuICAgICAgICBjb25zdCBiZyQgPSBlbGVtJC5maW5kKFwiLmNsb2NrLWJnXCIpO1xuICAgICAgICBpZiAoIWJnJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gRXJyb3IgJy5jbG9jay1iZycgbm90IGZvdW5kIGZvciBjbG9jayAnJHt0aGlzLmlkfScgb2Yga2V5ICcke3RoaXMucGFyZW50S2V5LmlkfScuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2tFbGVtcyQuYmckID0gYmckO1xuICAgICAgICBjb25zdCBmcmFtZSQgPSBlbGVtJC5maW5kKFwiLmNsb2NrLWZyYW1lXCIpO1xuICAgICAgICBpZiAoIWZyYW1lJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gRXJyb3IgJy5jbG9jay1mcmFtZScgbm90IGZvdW5kIGZvciBjbG9jayAnJHt0aGlzLmlkfScgb2Yga2V5ICcke3RoaXMucGFyZW50S2V5LmlkfScuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2tFbGVtcyQuZnJhbWUkID0gZnJhbWUkO1xuICAgICAgICBjb25zdCBmaWxsJCA9IGVsZW0kLmZpbmQoXCIuY2xvY2stZmlsbFwiKTtcbiAgICAgICAgaWYgKCFmaWxsJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gRXJyb3IgJy5jbG9jay1maWxsJyBub3QgZm91bmQgZm9yIGNsb2NrICcke3RoaXMuaWR9JyBvZiBrZXkgJyR7dGhpcy5wYXJlbnRLZXkuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICBjbG9ja0VsZW1zJC5maWxsJCA9IGZpbGwkO1xuICAgICAgICBjb25zdCBnbG93JCA9IGVsZW0kLmZpbmQoXCIuY2xvY2stZ2xvd1wiKTtcbiAgICAgICAgaWYgKCFnbG93JC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gRXJyb3IgJy5jbG9jay1nbG93JyBub3QgZm91bmQgZm9yIGNsb2NrICcke3RoaXMuaWR9JyBvZiBrZXkgJyR7dGhpcy5wYXJlbnRLZXkuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICBjbG9ja0VsZW1zJC5nbG93JCA9IGdsb3ckO1xuICAgICAgICBjb25zdCBjb3ZlciQgPSBlbGVtJC5maW5kKFwiLmNsb2NrLWNvdmVyXCIpO1xuICAgICAgICBpZiAoIWNvdmVyJC5sZW5ndGgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc0Nsb2NrLmdldEVsZW1lbnRzJF0gRXJyb3IgJy5jbG9jay1jb3Zlcicgbm90IGZvdW5kIGZvciBjbG9jayAnJHt0aGlzLmlkfScgb2Yga2V5ICcke3RoaXMucGFyZW50S2V5LmlkfScuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2tFbGVtcyQuY292ZXIkID0gY292ZXIkO1xuICAgICAgICBjb25zdCBvbmVTZWdtZW50cyQgPSBlbGVtJC5maW5kKFwiLmNsb2NrLW9uZS1zZWdtZW50XCIpO1xuICAgICAgICBpZiAob25lU2VnbWVudHMkLmxlbmd0aCAhPT0gMykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQ2xvY2suZ2V0RWxlbWVudHMkXSBFcnJvciAnLmNsb2NrLW9uZS1zZWdtZW50JyBlbGVtZW50cyBub3QgZm91bmQgZm9yIGNsb2NrICcke3RoaXMuaWR9JyBvZiBrZXkgJyR7dGhpcy5wYXJlbnRLZXkuaWR9Jy5gKTtcbiAgICAgICAgfVxuICAgICAgICBjbG9ja0VsZW1zJC5vbmVTZWdtZW50cyQgPSBvbmVTZWdtZW50cyQ7XG4gICAgICAgIHJldHVybiBjbG9ja0VsZW1zJDtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQU5JTUFURUQgVVBEQVRFUyAoQm90aCBHTS1Pbmx5IEFORCBTb2NrZXQgQ2FsbHMpXG4gICAgcmV2ZWFsX0FuaW1hdGlvbihjbG9ja0VsZW1zJCwgY2FsbGJhY2spIHtcbiAgICAgICAgLy8gSWRlbnRpZnkgZWxlbWVudHMgZm9yIGZhZGluZyBpblxuICAgICAgICBjb25zdCBmYWRlSW5FbGVtZW50cyA9IFtcbiAgICAgICAgICAgIGNsb2NrRWxlbXMkLmZyYW1lJCxcbiAgICAgICAgICAgIGNsb2NrRWxlbXMkLmZpbGwkXG4gICAgICAgIF0uZmlsdGVyKChlbCQpID0+IGVsJCAhPT0gdW5kZWZpbmVkKTtcbiAgICAgICAgLy8gQ29uc3RydWN0IHRpbWVsaW5lIGZvciByZXZlYWxpbmcgY2xvY2tcbiAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgY2FsbGJhY2tTY29wZTogdGhpcyxcbiAgICAgICAgICAgIG9uQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2s/LigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gRmFkZSBvdXQgY292ZXIgaGlkaW5nIGNsb2NrXG4gICAgICAgIHRsLnRvKGNsb2NrRWxlbXMkLmNvdmVyJCwgeyBzY2FsZTogMiwgYXV0b0FscGhhOiAwLCBkdXJhdGlvbjogMC41LCBlYXNlOiBcInBvd2VyMlwiIH0pO1xuICAgICAgICAvLyBGYWRlIGluIGNsb2NrIGVsZW1lbnRzXG4gICAgICAgIHRsLmZyb21UbyhmYWRlSW5FbGVtZW50cywge1xuICAgICAgICAgICAgYXV0b0FscGhhOiAwLFxuICAgICAgICAgICAgc2NhbGU6IDJcbiAgICAgICAgfSwge1xuICAgICAgICAgICAgYXV0b0FscGhhOiAxLFxuICAgICAgICAgICAgc2NhbGU6IDEsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgc3RhZ2dlcjogMC4yLFxuICAgICAgICAgICAgZWFzZTogXCJwb3dlcjJcIlxuICAgICAgICB9KTtcbiAgICAgICAgLy8gRmFkZSBpbiBuYW1lLCBpZiBuYW1lIGlzIHZpc2libGUuXG4gICAgICAgIGlmICh0aGlzLm5hbWUgJiYgdGhpcy5pc05hbWVWaXNpYmxlKSB7XG4gICAgICAgICAgICB0bC5ibHVyUmV2ZWFsKGNsb2NrRWxlbXMkLmNsb2NrTGFiZWwkLCB7XG4gICAgICAgICAgICAgICAgaWdub3JlTWFyZ2luOiB0cnVlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjc1XG4gICAgICAgICAgICB9LCBcIjwrMC4wNVwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBGYWRlIGluIGdsb3csIGlmIGhpZ2hsaWdodGVkXG4gICAgICAgIGlmICh0aGlzLmlzSGlnaGxpZ2h0ZWQpIHtcbiAgICAgICAgICAgIHRsLnNjYWxlVXBSZXZlYWwoY2xvY2tFbGVtcyQuZ2xvdyQsIHtcbiAgICAgICAgICAgICAgICBzY2FsZTogMyxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41XG4gICAgICAgICAgICB9LCBcIjwrMC4wNVwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pc0FjdGl2ZSkge1xuICAgICAgICAgICAgdGwuYWRkKCgpID0+IHRoaXMuYWN0aXZhdGVfQW5pbWF0aW9uKGNsb2NrRWxlbXMkKSwgXCI8KzAuMDVcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0bC5hZGQoKCkgPT4gdGhpcy5kZWFjdGl2YXRlX0FuaW1hdGlvbihjbG9ja0VsZW1zJCksIFwiPCswLjA1XCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0bDtcbiAgICB9XG4gICAgYXN5bmMgcmV2ZWFsX1NvY2tldENhbGwoZGlzcGxheUNvbnRleHQpIHtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmV2ZWFsX1NvY2tldENhbGxcIiwgZGlzcGxheUNvbnRleHQsIHRoaXMucGFyZW50S2V5LmlkLCB0aGlzLmluZGV4KTtcbiAgICB9XG4gICAgc3RhdGljIHJldmVhbF9Tb2NrZXRSZXNwb25zZShkaXNwbGF5Q29udGV4dCwga2V5SUQsIGluZGV4KSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKTtcbiAgICAgICAgaWYgKCFrZXk/LmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrID0ga2V5LmdldENsb2NrQnlJbmRleChpbmRleCk7XG4gICAgICAgIGlmICghY2xvY2spIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjbG9ja0VsZW1zJCA9IGNsb2NrLmdldEVsZW1lbnRzJChkaXNwbGF5Q29udGV4dCk7XG4gICAgICAgIGNsb2NrLnJldmVhbF9BbmltYXRpb24oY2xvY2tFbGVtcyQpO1xuICAgIH1cbiAgICBoaWRlX0FuaW1hdGlvbihjbG9ja0VsZW1zJCwgY2FsbGJhY2spIHtcbiAgICAgICAgLy8gSWRlbnRpZnkgZWxlbWVudHMgZm9yIGZhZGluZyBvdXRcbiAgICAgICAgY29uc3QgZmFkZU91dEVsZW1lbnRzID0gW1xuICAgICAgICAgICAgY2xvY2tFbGVtcyQuZnJhbWUkLFxuICAgICAgICAgICAgY2xvY2tFbGVtcyQuZmlsbCRcbiAgICAgICAgXS5maWx0ZXIoKGVsJCkgPT4gZWwkICE9PSB1bmRlZmluZWQpO1xuICAgICAgICAvLyBDb25zdHJ1Y3QgdGltZWxpbmUgZm9yIGhpZGluZyBjbG9ja1xuICAgICAgICBjb25zdCB0bCA9IFUuZ3NhcC50aW1lbGluZSh7XG4gICAgICAgICAgICBjYWxsYmFja1Njb3BlOiB0aGlzLFxuICAgICAgICAgICAgb25Db21wbGV0ZSgpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFjaz8uKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBGYWRlIG91dCBjbG9jayBlbGVtZW50c1xuICAgICAgICB0bC50byhmYWRlT3V0RWxlbWVudHMsIHtcbiAgICAgICAgICAgIGF1dG9BbHBoYTogMCxcbiAgICAgICAgICAgIHNjYWxlOiAyLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIHN0YWdnZXI6IDAuMixcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIyXCJcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEZhZGUgb3V0IG5hbWUsIGlmIG5hbWUgdmlzaWJsZVxuICAgICAgICBpZiAodGhpcy5uYW1lICYmIHRoaXMuaXNOYW1lVmlzaWJsZSkge1xuICAgICAgICAgICAgdGwuYmx1clJlbW92ZShjbG9ja0VsZW1zJC5jbG9ja0xhYmVsJCwge1xuICAgICAgICAgICAgICAgIGlnbm9yZU1hcmdpbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC43NVxuICAgICAgICAgICAgfSwgXCI8KzAuMDVcIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gRmFkZSBvdXQgZ2xvdywgaWYgaGlnaGxpZ2h0ZWRcbiAgICAgICAgaWYgKHRoaXMuaXNIaWdobGlnaHRlZCkge1xuICAgICAgICAgICAgdGwuc2NhbGVEb3duUmVtb3ZlKGNsb2NrRWxlbXMkLmdsb3ckLCB7XG4gICAgICAgICAgICAgICAgc2NhbGU6IDMsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNVxuICAgICAgICAgICAgfSwgXCI8KzAuMDVcIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gRmFkZSBpbiBjb3ZlciBlbGVtZW50XG4gICAgICAgIHRsLnRvKGNsb2NrRWxlbXMkLmNvdmVyJCwgeyBzY2FsZTogMSwgYXV0b0FscGhhOiAxLCBkdXJhdGlvbjogMC41LCBlYXNlOiBcInBvd2VyMlwiIH0pO1xuICAgICAgICByZXR1cm4gdGw7XG4gICAgfVxuICAgIGFzeW5jIGhpZGVfU29ja2V0Q2FsbChkaXNwbGF5Q29udGV4dCkge1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yRXZlcnlvbmUoXCJoaWRlX1NvY2tldENhbGxcIiwgZGlzcGxheUNvbnRleHQsIHRoaXMucGFyZW50S2V5LmlkLCB0aGlzLmluZGV4KTtcbiAgICB9XG4gICAgc3RhdGljIGhpZGVfU29ja2V0UmVzcG9uc2UoZGlzcGxheUNvbnRleHQsIGtleUlELCBpbmRleCkge1xuICAgICAgICBjb25zdCBrZXkgPSBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5Py5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjbG9jayA9IGtleS5nZXRDbG9ja0J5SW5kZXgoaW5kZXgpO1xuICAgICAgICBpZiAoIWNsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2xvY2tFbGVtcyQgPSBjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpO1xuICAgICAgICBjbG9jay5oaWRlX0FuaW1hdGlvbihjbG9ja0VsZW1zJCk7XG4gICAgfVxuICAgIGFjdGl2YXRlX0FuaW1hdGlvbihjbG9ja0VsZW1zJCwgY2FsbGJhY2spIHtcbiAgICAgICAgVS5nc2FwLnRvKGNsb2NrRWxlbXMkLmJnJCwgeyBhdXRvQWxwaGE6IDEsIGR1cmF0aW9uOiAwLjUsIGVhc2U6IFwicG93ZXIyXCIgfSk7XG4gICAgICAgIFUuZ3NhcC50byhjbG9ja0VsZW1zJC5mcmFtZSQsIHtcbiAgICAgICAgICAgIGZpbHRlcjogXCJicmlnaHRuZXNzKDAuNSlcIixcbiAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICBlYXNlOiBcInBvd2VyMlwiLFxuICAgICAgICAgICAgb25Db21wbGV0ZTogY2FsbGJhY2tcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGFjdGl2YXRlX1NvY2tldENhbGwoZGlzcGxheUNvbnRleHQpIHtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwiYWN0aXZhdGVfU29ja2V0Q2FsbFwiLCBkaXNwbGF5Q29udGV4dCwgdGhpcy5wYXJlbnRLZXkuaWQsIHRoaXMuaW5kZXgpO1xuICAgIH1cbiAgICBzdGF0aWMgYWN0aXZhdGVfU29ja2V0UmVzcG9uc2UoZGlzcGxheUNvbnRleHQsIGtleUlELCBpbmRleCkge1xuICAgICAgICBjb25zdCBrZXkgPSBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5Py5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjbG9jayA9IGtleS5nZXRDbG9ja0J5SW5kZXgoaW5kZXgpO1xuICAgICAgICBpZiAoIWNsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2suYWN0aXZhdGVfQW5pbWF0aW9uKGNsb2NrLmdldEVsZW1lbnRzJChkaXNwbGF5Q29udGV4dCkpO1xuICAgIH1cbiAgICBkZWFjdGl2YXRlX0FuaW1hdGlvbihjbG9ja0VsZW1zJCwgY2FsbGJhY2spIHtcbiAgICAgICAgVS5nc2FwLnRvKGNsb2NrRWxlbXMkLmJnJCwgeyBhdXRvQWxwaGE6IDAsIGR1cmF0aW9uOiAwLjUsIGVhc2U6IFwicG93ZXIyXCIgfSk7XG4gICAgICAgIFUuZ3NhcC50byhjbG9ja0VsZW1zJC5mcmFtZSQsIHtcbiAgICAgICAgICAgIGZpbHRlcjogXCJicmlnaHRuZXNzKDEpIGJsdXIoNXB4KVwiLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIyXCIsXG4gICAgICAgICAgICBvbkNvbXBsZXRlOiBjYWxsYmFja1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZGVhY3RpdmF0ZV9Tb2NrZXRDYWxsKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImRlYWN0aXZhdGVfU29ja2V0Q2FsbFwiLCBkaXNwbGF5Q29udGV4dCwgdGhpcy5wYXJlbnRLZXkuaWQsIHRoaXMuaW5kZXgpO1xuICAgIH1cbiAgICBzdGF0aWMgZGVhY3RpdmF0ZV9Tb2NrZXRSZXNwb25zZShkaXNwbGF5Q29udGV4dCwga2V5SUQsIGluZGV4KSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKTtcbiAgICAgICAgaWYgKCFrZXk/LmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrID0ga2V5LmdldENsb2NrQnlJbmRleChpbmRleCk7XG4gICAgICAgIGlmICghY2xvY2spIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjbG9jay5kZWFjdGl2YXRlX0FuaW1hdGlvbihjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICB9XG4gICAgZmFkZUluQ2xvY2tOYW1lX0FuaW1hdGlvbihjbG9ja0VsZW1zJCkge1xuICAgICAgICBVLmdzYXAuZWZmZWN0cy5ibHVyUmV2ZWFsKGNsb2NrRWxlbXMkLmNsb2NrTGFiZWwkLCB7XG4gICAgICAgICAgICBpZ25vcmVNYXJnaW46IHRydWUsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC43NVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZmFkZUluQ2xvY2tOYW1lX1NvY2tldENhbGwoZGlzcGxheUNvbnRleHQpIHtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwiZmFkZUluQ2xvY2tOYW1lX1NvY2tldENhbGxcIiwgZGlzcGxheUNvbnRleHQsIHRoaXMucGFyZW50S2V5LmlkLCB0aGlzLmluZGV4KTtcbiAgICB9XG4gICAgc3RhdGljIGZhZGVJbkNsb2NrTmFtZV9Tb2NrZXRSZXNwb25zZShkaXNwbGF5Q29udGV4dCwga2V5SUQsIGluZGV4KSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKTtcbiAgICAgICAgaWYgKCFrZXk/LmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrID0ga2V5LmdldENsb2NrQnlJbmRleChpbmRleCk7XG4gICAgICAgIGlmICghY2xvY2spIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjbG9jay5mYWRlSW5DbG9ja05hbWVfQW5pbWF0aW9uKGNsb2NrLmdldEVsZW1lbnRzJChkaXNwbGF5Q29udGV4dCkpO1xuICAgIH1cbiAgICBmYWRlT3V0Q2xvY2tOYW1lX0FuaW1hdGlvbihjbG9ja0VsZW1zJCkge1xuICAgICAgICBVLmdzYXAuZWZmZWN0cy5ibHVyUmVtb3ZlKGNsb2NrRWxlbXMkLmNsb2NrTGFiZWwkLCB7XG4gICAgICAgICAgICBpZ25vcmVNYXJnaW46IHRydWUsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC43NVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZmFkZU91dENsb2NrTmFtZV9Tb2NrZXRDYWxsKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImZhZGVPdXRDbG9ja05hbWVfU29ja2V0Q2FsbFwiLCBkaXNwbGF5Q29udGV4dCwgdGhpcy5wYXJlbnRLZXkuaWQsIHRoaXMuaW5kZXgpO1xuICAgIH1cbiAgICBzdGF0aWMgZmFkZU91dENsb2NrTmFtZV9Tb2NrZXRSZXNwb25zZShkaXNwbGF5Q29udGV4dCwga2V5SUQsIGluZGV4KSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKTtcbiAgICAgICAgaWYgKCFrZXk/LmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGNsb2NrID0ga2V5LmdldENsb2NrQnlJbmRleChpbmRleCk7XG4gICAgICAgIGlmICghY2xvY2spIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjbG9jay5mYWRlT3V0Q2xvY2tOYW1lX0FuaW1hdGlvbihjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICB9XG4gICAgaGlnaGxpZ2h0X0FuaW1hdGlvbihjbG9ja0VsZW1zJCkge1xuICAgICAgICBVLmdzYXAuZWZmZWN0cy5zY2FsZVVwUmV2ZWFsKGNsb2NrRWxlbXMkLmdsb3ckLCB7XG4gICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgc2NhbGU6IDNcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGhpZ2hsaWdodF9Tb2NrZXRDYWxsKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImhpZ2hsaWdodF9Tb2NrZXRDYWxsXCIsIGRpc3BsYXlDb250ZXh0LCB0aGlzLnBhcmVudEtleS5pZCwgdGhpcy5pbmRleCk7XG4gICAgfVxuICAgIHN0YXRpYyBoaWdobGlnaHRfU29ja2V0UmVzcG9uc2UoZGlzcGxheUNvbnRleHQsIGtleUlELCBpbmRleCkge1xuICAgICAgICBjb25zdCBrZXkgPSBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5Py5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjbG9jayA9IGtleS5nZXRDbG9ja0J5SW5kZXgoaW5kZXgpO1xuICAgICAgICBpZiAoIWNsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY2xvY2suaGlnaGxpZ2h0X0FuaW1hdGlvbihjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICB9XG4gICAgdW5oaWdobGlnaHRfQW5pbWF0aW9uKGNsb2NrRWxlbXMkKSB7XG4gICAgICAgIFUuZ3NhcC5lZmZlY3RzLnNjYWxlRG93blJlbW92ZShjbG9ja0VsZW1zJC5nbG93JCwge1xuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIHNjYWxlOiAzXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhc3luYyB1bmhpZ2hsaWdodF9Tb2NrZXRDYWxsKGRpc3BsYXlDb250ZXh0KSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInVuaGlnaGxpZ2h0X1NvY2tldENhbGxcIiwgZGlzcGxheUNvbnRleHQsIHRoaXMucGFyZW50S2V5LmlkLCB0aGlzLmluZGV4KTtcbiAgICB9XG4gICAgc3RhdGljIHVuaGlnaGxpZ2h0X1NvY2tldFJlc3BvbnNlKGRpc3BsYXlDb250ZXh0LCBrZXlJRCwgaW5kZXgpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoa2V5SUQpO1xuICAgICAgICBpZiAoIWtleT8uaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2xvY2sgPSBrZXkuZ2V0Q2xvY2tCeUluZGV4KGluZGV4KTtcbiAgICAgICAgaWYgKCFjbG9jaykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNsb2NrLnVuaGlnaGxpZ2h0X0FuaW1hdGlvbihjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpKTtcbiAgICB9XG4gICAgZ2V0Um90YXRpb25PZlNlZ21lbnQoc2VnbWVudCkge1xuICAgICAgICBjb25zdCBzdGVwU2l6ZSA9IDM2MCAvIHRoaXMubWF4O1xuICAgICAgICByZXR1cm4gc3RlcFNpemUgKiAoc2VnbWVudCAtIDEpO1xuICAgIH1cbiAgICBpbml0T25lU2VnbWVudHMoY2xvY2tFbGVtcyQsIHNlZ21lbnROdW1zLCBpc1JldmVyc2luZykge1xuICAgICAgICBpZiAoc2VnbWVudE51bXMubGVuZ3RoID4gMykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBUb28gbWFueSBzZWdtZW50czogWyR7c2VnbWVudE51bXMuam9pbihcIiwgXCIpfV1gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBGb3IgZWFjaCBzZWdtZW50IG51bWJlciwgaW5pdGlhbGl6ZSBhIG9uZS1zZWdtZW50IHRvIHRoYXQgcG9zaXRpb24sXG4gICAgICAgIC8vICBhbmQgaW5pdGlhbGl6ZSBpdHMgYXV0b0FscGhhIGRlcGVuZGluZyBvbiBpc1JldmVyc2luZy5cbiAgICAgICAgY29uc3Qgb25lU2VncyA9IFsuLi5jbG9ja0VsZW1zJC5vbmVTZWdtZW50cyRdO1xuICAgICAgICBjb25zdCBvbmVTZWdzVG9BbmltYXRlID0gQXJyYXkuZnJvbShjbG9ja0VsZW1zJC5vbmVTZWdtZW50cyQpLnNsaWNlKDAsIHNlZ21lbnROdW1zLmxlbmd0aCk7XG4gICAgICAgIGZvciAoY29uc3Qgc2VnbWVudE51bSBvZiBzZWdtZW50TnVtcykge1xuICAgICAgICAgICAgY29uc3Qgb25lU2VnbWVudCA9IG9uZVNlZ3Muc2hpZnQoKTtcbiAgICAgICAgICAgIFUuZ3NhcC5zZXQob25lU2VnbWVudCwge1xuICAgICAgICAgICAgICAgIHJvdGF0aW9uOiB0aGlzLmdldFJvdGF0aW9uT2ZTZWdtZW50KHNlZ21lbnROdW0pLFxuICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogaXNSZXZlcnNpbmcgPyAxIDogMFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgcmV2ZXJzaW5nLCBzZXQgY2xvY2sgZWxlbWVudCdzIHZhbHVlIHRvIHRoZSBmaW5hbCB2YWx1ZSBmb3IgcHJvcGVyIGNsaXBwaW5nLlxuICAgICAgICBpZiAoaXNSZXZlcnNpbmcpIHtcbiAgICAgICAgICAgIGNsb2NrRWxlbXMkLmNsb2NrRWxlbSQuYXR0cihcImRhdGEtdmFsdWVcIiwgVS5nZXRMYXN0KHNlZ21lbnROdW1zKSAtIDEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvbmVTZWdzVG9BbmltYXRlO1xuICAgIH1cbiAgICBjaGFuZ2VTZWdtZW50c19BbmltYXRpb24oY2xvY2tFbGVtcyQsIHN0YXJ0VmFsLCBlbmRWYWwsIGNhbGxiYWNrKSB7XG4gICAgICAgIHN0YXJ0VmFsID0gVS5nc2FwLnV0aWxzLmNsYW1wKDAsIHRoaXMubWF4LCBzdGFydFZhbCk7XG4gICAgICAgIGVuZFZhbCA9IFUuZ3NhcC51dGlscy5jbGFtcCgwLCB0aGlzLm1heCwgZW5kVmFsKTtcbiAgICAgICAgbGV0IGRlbHRhID0gZW5kVmFsIC0gc3RhcnRWYWw7XG4gICAgICAgIGlmIChkZWx0YSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIERldGVybWluZSBwb3NpdGlvbiBhbmQgc2VxdWVuY2Ugb2Ygb25lLXNlZ21lbnRzXG4gICAgICAgIGNvbnN0IHNlZ21lbnROdW1zID0gW107XG4gICAgICAgIGlmIChkZWx0YSA8IDApIHtcbiAgICAgICAgICAgIHdoaWxlIChNYXRoLmFicyhkZWx0YSkgPiBzdGFydFZhbCkge1xuICAgICAgICAgICAgICAgIGRlbHRhKys7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gc3RhcnRWYWw7IGkgPiBlbmRWYWw7IGktLSkge1xuICAgICAgICAgICAgICAgIHNlZ21lbnROdW1zLnB1c2goaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB3aGlsZSAoZW5kVmFsID4gdGhpcy5tYXgpIHtcbiAgICAgICAgICAgICAgICBkZWx0YS0tO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChsZXQgaSA9IHN0YXJ0VmFsICsgMTsgaSA8PSBlbmRWYWw7IGkrKykge1xuICAgICAgICAgICAgICAgIHNlZ21lbnROdW1zLnB1c2goaSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBvbmVTZWdtZW50cyBhdCBkZXRlcm1pbmVkIHBvc2l0aW9uc1xuICAgICAgICBjb25zdCBzZWdtZW50c1RvQW5pbWF0ZSA9IHRoaXMuaW5pdE9uZVNlZ21lbnRzKGNsb2NrRWxlbXMkLCBzZWdtZW50TnVtcywgc3RhcnRWYWwgPiBlbmRWYWwpO1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcIkJsYWRlc0Nsb2NrXCIsIFwiY2hhbmdlU2VnbWVudHNfQW5pbWF0aW9uXCIsIHsgY2xvY2tFbGVtcyQsIGRlbHRhLCBzZWdtZW50TnVtcywgc3RhcnRWYWwsIGVuZFZhbCwgc2VnbWVudHNUb0FuaW1hdGUgfSk7XG4gICAgICAgIC8vIEluaXRpYWxpemUgbWFzdGVyIHRpbWVsaW5lXG4gICAgICAgIGNvbnN0IHRsID0gVS5nc2FwLnRpbWVsaW5lKCk7XG4gICAgICAgIC8vIEVubGFyZ2UgY2xvY2sga2V5IGFuZCBmb2N1cyBjbG9ja1xuICAgICAgICAvLyBjb25zdCBjbG9ja0ZvY3VzVGltZWxpbmU6IGdzYXAuY29yZS5UaW1lbGluZSA9IHRoaXMucGFyZW50S2V5LmdldENsb2NrRm9jdXNUaW1lbGluZSh0aGlzLmluZGV4KTtcbiAgICAgICAgLy8gdGwuYWRkKGNsb2NrRm9jdXNUaW1lbGluZSk7XG4gICAgICAgIC8vIEFuaW1hdGUgb25lLXNlZ21lbnRzXG4gICAgICAgIGlmIChkZWx0YSA+IDApIHtcbiAgICAgICAgICAgIHRsLmZyb21UbyhzZWdtZW50c1RvQW5pbWF0ZSwge1xuICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogMCxcbiAgICAgICAgICAgICAgICBzY2FsZTogMlxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogMSxcbiAgICAgICAgICAgICAgICBzY2FsZTogMSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgICAgIHN0YWdnZXI6IDAuMixcbiAgICAgICAgICAgICAgICBlYXNlOiBcInBvd2VyMlwiLFxuICAgICAgICAgICAgICAgIGNhbGxiYWNrU2NvcGU6IHRoaXMsXG4gICAgICAgICAgICAgICAgb25Db21wbGV0ZSgpIHtcbiAgICAgICAgICAgICAgICAgICAgY2xvY2tFbGVtcyQuY2xvY2tFbGVtJC5hdHRyKFwiZGF0YS12YWx1ZVwiLCBlbmRWYWwpO1xuICAgICAgICAgICAgICAgICAgICBVLmdzYXAudG8oc2VnbWVudHNUb0FuaW1hdGUsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogMCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGFnZ2VyOiAwLjJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9uQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyAgIC8vIFJldHVybiBjbG9jayBrZXkgdG8gb3JpZ2luYWwgc2l6ZSBhbmQgZm9jdXNcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vICAgY2xvY2tGb2N1c1RpbWVsaW5lLnJldmVyc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0bC5mcm9tVG8oc2VnbWVudHNUb0FuaW1hdGUsIHtcbiAgICAgICAgICAgICAgICBhdXRvQWxwaGE6IDEsXG4gICAgICAgICAgICAgICAgc2NhbGU6IDFcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICBhdXRvQWxwaGE6IDAsXG4gICAgICAgICAgICAgICAgc2NhbGU6IDIsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICBzdGFnZ2VyOiAwLjIsXG4gICAgICAgICAgICAgICAgZWFzZTogXCJwb3dlcjJcIlxuICAgICAgICAgICAgICAgIC8vIG9uQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgLy8gICAvLyBSZXR1cm4gY2xvY2sga2V5IHRvIG9yaWdpbmFsIHNpemUgYW5kIGZvY3VzXG4gICAgICAgICAgICAgICAgLy8gICBjbG9ja0ZvY3VzVGltZWxpbmUucmV2ZXJzZSgpO1xuICAgICAgICAgICAgICAgIC8vIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0bDtcbiAgICB9XG4gICAgYXN5bmMgY2hhbmdlU2VnbWVudHNfU29ja2V0Q2FsbChkaXNwbGF5Q29udGV4dCwgc3RhcnRWYWwsIGVuZFZhbCkge1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3RhcnRWYWwgPSBVLmdzYXAudXRpbHMuY2xhbXAoMCwgdGhpcy5tYXgsIHN0YXJ0VmFsKTtcbiAgICAgICAgZW5kVmFsID0gVS5nc2FwLnV0aWxzLmNsYW1wKDAsIHRoaXMubWF4LCBlbmRWYWwpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImNoYW5nZVNlZ21lbnRzX1NvY2tldENhbGxcIiwgZGlzcGxheUNvbnRleHQsIHRoaXMucGFyZW50S2V5LmlkLCB0aGlzLmluZGV4LCBzdGFydFZhbCwgZW5kVmFsKTtcbiAgICB9XG4gICAgc3RhdGljIGNoYW5nZVNlZ21lbnRzX1NvY2tldFJlc3BvbnNlKGRpc3BsYXlDb250ZXh0LCBrZXlJRCwgaW5kZXgsIHN0YXJ0VmFsLCBlbmRWYWwpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoa2V5SUQpO1xuICAgICAgICBpZiAoIWtleT8uaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2xvY2sgPSBrZXkuZ2V0Q2xvY2tCeUluZGV4KGluZGV4KTtcbiAgICAgICAgaWYgKCFjbG9jaykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNsb2NrLmNoYW5nZVNlZ21lbnRzX0FuaW1hdGlvbihjbG9jay5nZXRFbGVtZW50cyQoZGlzcGxheUNvbnRleHQpLCBzdGFydFZhbCwgZW5kVmFsKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQWRkaW5nL1JlbW92aW5nIENsb2NrIFNlZ21lbnRzIH5cbiAgICAvLyBSZXR1cm5zIG51bWJlciBvZiBzZWdtZW50cyBiZXlvbmQgbWF4IChvciAwLCBpZiBtYXggbm90IG1ldClcbiAgICBhc3luYyBmaWxsU2VnbWVudHMoY291bnQsIGlzU2lsZW50ID0gZmFsc2UpIHtcbiAgICAgICAgLy8gQW1vdW50IGFkZGVkIGJleW9uZCBtYXg6XG4gICAgICAgIGNvbnN0IGNsb2NrT3ZlcmZsb3cgPSBNYXRoLm1heCgwLCB0aGlzLnZhbHVlICsgY291bnQgLSB0aGlzLm1heCk7XG4gICAgICAgIC8vIENsYW1wIGNvdW50IHRvIG1heDpcbiAgICAgICAgY291bnQgPSBNYXRoLm1pbih0aGlzLnZhbHVlICsgY291bnQsIHRoaXMubWF4KSAtIHRoaXMudmFsdWU7XG4gICAgICAgIGlmIChjb3VudCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsb2NrT3ZlcmZsb3c7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoXCJ2YWx1ZVwiLCB0aGlzLnZhbHVlICsgY291bnQpO1xuICAgICAgICBpZiAoIWlzU2lsZW50KSB7XG4gICAgICAgICAgICB0aGlzLnBhcmVudEtleS5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2xvY2tPdmVyZmxvdztcbiAgICB9XG4gICAgLy8gUmV0dXJucyAocG9zaXRpdmUpIG51bWJlciBvZiBzZWdtZW50cyByZW1vdmVkXG4gICAgLy8gaW4gZXhjZXNzIG9mIHRoZSBudW1iZXIgb2Ygc2VnbWVudHMgaW4gdGhlIGNsb2NrXG4gICAgYXN5bmMgY2xlYXJTZWdtZW50cyhjb3VudCwgaXNTaWxlbnQgPSBmYWxzZSkge1xuICAgICAgICAvLyBBbW91bnQgcmVtb3ZlZCBiZXlvbmQgMDpcbiAgICAgICAgY29uc3QgY2xvY2tPdmVyZmxvdyA9IE1hdGgubWF4KDAsIGNvdW50IC0gdGhpcy52YWx1ZSk7XG4gICAgICAgIC8vIENsYW1wIGNvdW50IHRvIG1pbjpcbiAgICAgICAgY291bnQgPSBNYXRoLm1pbih0aGlzLnZhbHVlLCBjb3VudCk7XG4gICAgICAgIGlmIChjb3VudCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsb2NrT3ZlcmZsb3c7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoXCJ2YWx1ZVwiLCB0aGlzLnZhbHVlIC0gY291bnQpO1xuICAgICAgICBpZiAoIWlzU2lsZW50KSB7XG4gICAgICAgICAgICB0aGlzLnBhcmVudEtleS5yZW5kZXJUYXJnZXRBbmRLZWVwZXIoKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2xvY2tPdmVyZmxvdztcbiAgICB9XG4gICAgYXN5bmMgZGVsZXRlKCkge1xuICAgICAgICBjb25zdCB7IHBhcmVudEtleSB9ID0gdGhpcztcbiAgICAgICAgYXdhaXQgc3VwZXIuZGVsZXRlKGZhbHNlKTtcbiAgICAgICAgcGFyZW50S2V5LnVwZGF0ZUNsb2NrSW5kaWNlcygpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0Nsb2NrS2V5O1xuZXhwb3J0IHsgQmxhZGVzQ2xvY2sgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/classes/BladesClockKey.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesConsequence.ts": +/*!*****************************************!*\ + !*** ./ts/classes/BladesConsequence.ts ***! + \*****************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesRoll__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* harmony import */ var _BladesTargetLink__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./BladesTargetLink */ \"./ts/classes/BladesTargetLink.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\n/* eslint-enable @typescript-eslint/no-unused-vars */\nclass BladesConsequence extends _BladesTargetLink__WEBPACK_IMPORTED_MODULE_3__[\"default\"] {\n // #region Static Methods ~\n static async Initialize() {\n if (!game.messages) {\n throw new Error(\"[BladesConsequence] Messages Not Ready!\");\n }\n return (await Promise.all(game.messages.contents\n .map(async (msg) => msg.rollConsequences)))\n .flat();\n }\n /**\n * Checks if the given value is valid consequence data for a Resistance Roll.\n * @param val The value to check.\n * @param isCheckingResistedTo If the check is being recursively applied to the 'resistTo' value.\n * @returns True if the val is valid BladesConsequence.Data, false otherwise.\n */\n static IsValidConsequenceData(val, isCheckingResistedTo = false) {\n if (!_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].isList(val)) {\n return false;\n }\n if (typeof val.type !== \"string\" || !(val.type in _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType)) {\n return false;\n }\n if (typeof val.name !== \"string\") {\n return false;\n }\n if (isCheckingResistedTo) {\n return true;\n }\n if (val.attribute && (typeof val.attribute !== \"string\" || !(val.attribute in _core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait))) {\n return false;\n }\n if (!this.IsValidConsequenceData(val.resistTo, true)) {\n return false;\n }\n return true;\n }\n static ApplySchemaDefaults(schemaData) {\n // Ensure all properties of Schema are provided\n if (!schemaData.primaryID) {\n throw new Error(\"A primaryID is required for BladesConsequence.Schema\");\n }\n if (typeof schemaData.name === \"string\" && (!schemaData.name && schemaData.type !== _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None)) {\n throw new Error(`A name must be provided for non-None-type consequences (${schemaData.name}).`);\n }\n return {\n name: \"\",\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None,\n ...schemaData\n };\n }\n static GetCsqTypeValue(cType, rollData) {\n if (cType === _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.WorsePosition) {\n // Requires position data to resolve.\n if (!rollData) {\n throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data.`);\n }\n let position;\n if (\"rollPositionFinal\" in rollData) {\n position = rollData.rollPositionFinal;\n }\n else if (\"position\" in rollData) {\n position = rollData.position;\n }\n if (!position) {\n throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data that includes final position data.`);\n }\n return {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Position.controlled]: 1,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Position.risky]: 2,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Position.desperate]: 0\n }[position];\n }\n if (cType === _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.ReducedEffect) {\n // Requires effect data to resolve.\n if (!rollData) {\n throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data.`);\n }\n let effect;\n if (\"rollEffectFinal\" in rollData) {\n effect = rollData.rollEffectFinal;\n }\n else if (\"effect\" in rollData) {\n effect = rollData.effect;\n }\n if (!effect) {\n throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data that includes final effect data.`);\n }\n return {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.extreme]: 1,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.great]: 1,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.standard]: 1,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.limited]: 2,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.zero]: 0\n }[effect];\n }\n // All other values are constant for each consequence type.\n return _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ConsequenceValues[cType];\n }\n // #endregion\n // #region *** GETTERS *** ~\n // #region Getters (Target Data) ~\n get primaryID() { return this.data.primaryID ?? this.parentConsequence?.primaryID; }\n get parentCsqID() { return this.data.parentCsqID; }\n get name() { return this.data.name; }\n get type() { return this.data.type; }\n get attribute() { return this.data.attribute ?? this.parentConsequence?.attribute; }\n get attributeVal() { return this.data.attributeVal ?? this.parentConsequence?.attributeVal; }\n get specialFooterMsg() {\n return this.data.specialFooterMsg ?? this.parentConsequence?.specialFooterMsg;\n }\n // #endregion\n // #region Getters (Derived Data) ~\n get primary() {\n const primary = fromUuidSync(this.primaryID);\n if (!_BladesRoll__WEBPACK_IMPORTED_MODULE_2__.BladesRollPrimary.IsDoc(primary)) {\n throw new Error(`Could not find primary with UUID '${this.primaryID}'`);\n }\n if (this.roll) {\n return new _BladesRoll__WEBPACK_IMPORTED_MODULE_2__.BladesRollPrimary(this.roll, primary);\n }\n return new _BladesRoll__WEBPACK_IMPORTED_MODULE_2__.BladesRollPrimary(primary);\n }\n get parentConsequence() {\n if (!this.parentCsqID) {\n return undefined;\n }\n const parentCsq = game.eunoblades.Consequences.get(this.parentCsqID);\n if (!parentCsq) {\n throw new Error(`Error locating parent consequence with id '${this.parentCsqID}'`);\n }\n return parentCsq;\n }\n get typeDisplay() { return _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ConsequenceDisplay[this.type]; }\n get icon() { return _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ConsequenceIcons[this.type]; }\n get value() { return BladesConsequence.GetCsqTypeValue(this.type, this); }\n // #endregion\n // #region Getters (Resolved Roll Data that Applied This Consequence) ~\n get rollData() {\n return this.data.actionRollData ?? this.parentConsequence?.rollData;\n }\n get roll() {\n if (!this.rollData) {\n return undefined;\n }\n return game.eunoblades.Rolls.get(this.rollData.id) ?? new _BladesRoll__WEBPACK_IMPORTED_MODULE_2__[\"default\"]({\n ...this.rollData,\n isScopingById: false\n });\n }\n get position() { return this.roll?.rollPositionFinal; }\n get effect() { return this.roll?.rollEffectFinal; }\n get result() { return this.roll?.rollResultFinal; }\n // #endregion\n // #region Getters (Resistibility & Acceptance Status) ~\n isResistible() {\n return Boolean(this.type !== _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None && !this.isAccepted && this.data.resistSchema);\n }\n get resistanceModes() { return this.data.resistanceModes ?? []; }\n get wasResisted() { return Boolean(this.resistanceModes.length); }\n get wasResistedByRoll() { return this.resistanceModes.includes(\"resist\"); }\n get wasResistedByArmor() { return this.resistanceModes.includes(\"armor\"); }\n get wasResistedBySpecialArmor() { return this.resistanceModes?.includes(\"special\"); }\n get canResistWithRoll() {\n if (!this.isResistible()) {\n return false;\n }\n // Only PCs can roll to resist consequences.\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.primary.rollPrimaryDoc)) {\n return false;\n }\n // A consequence can only be resisted by roll once.\n if (this.wasResistedByRoll) {\n return false;\n }\n // Otherwise, a consequence can ALWAYS be resisted by roll once by a PC.\n return true;\n }\n get canResistWithArmor() {\n if (!this.isResistible()) {\n return false;\n }\n // The consequence must be explicitly flagged as resistable by armor.\n if (!this.data.canResistWithArmor) {\n return false;\n }\n // Unlike resistance rolls, a Primary could conceivably resist twice using multiple armor boxes.\n // So, a resistanceMode previously set to \"armor\" does not disqualify another resist, if the\n // Primary has armor to spare.\n return this.primary.availableArmorCount > 0;\n }\n get canResistWithSpecial() {\n if (!this.isResistible()) {\n return false;\n }\n // The consequence must be explicitly flagged as resistable by special armor.\n if (!this.data.canResistWithSpecial) {\n return false;\n }\n // Only PCs can resist consequences with special armor.\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.primary.rollPrimaryDoc)) {\n return false;\n }\n // A consequence can only be resisted by special armor once.\n if (this.wasResistedBySpecialArmor) {\n return false;\n }\n // Otherwise, the PC can resist if they have special armor to spare.\n return this.primary.hasSpecialArmor;\n }\n get resistWithRollNegates() {\n if (!this.canResistWithRoll) {\n return false;\n }\n // If this is the second resistance, it automatically negates.\n if (this.wasResisted) {\n return true;\n }\n // Otherwise, it negates if explicitly flagged to do so.\n return Boolean(this.data.resistWithRollNegates);\n }\n get resistWithArmorNegates() {\n if (!this.canResistWithArmor) {\n return false;\n }\n // If this is the second resistance, it automatically negates.\n if (this.wasResisted) {\n return true;\n }\n // Otherwise, it negates if explicitly flagged to do so.\n return Boolean(this.data.resistWithArmorNegates);\n }\n get resistWithSpecialNegates() {\n if (!this.canResistWithSpecial) {\n return false;\n }\n // If this is the second resistance, it automatically negates.\n if (this.wasResisted) {\n return true;\n }\n // Otherwise, it negates if explicitly flagged to do so.\n return Boolean(this.data.resistWithSpecialNegates);\n }\n get isAccepted() { return \"acceptanceMode\" in this.data; }\n get acceptanceMode() {\n return this.data.acceptanceMode;\n }\n // #endregion\n // #endregion\n // #region *** RESISTING CONSEQUENCES ***\n // #region Constructing Resistable Consequence Schema\n get noneSchema() {\n return {\n name: \"\",\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None,\n primaryID: this.primaryID\n };\n }\n get resistSchema() {\n // If this consequence can't be resisted, return undefined.\n if (!this.isResistible()) {\n return undefined;\n }\n // Expand the resistSchema into a full BladesConsequence.Schema object\n const resSchema = {\n name: this.data.resistSchema.name,\n type: this.data.resistSchema.type,\n primaryID: this.primaryID,\n resistSchema: {\n name: \"\",\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None\n },\n resistanceModes: this.resistanceModes,\n resistWithRollNegates: true,\n attribute: this.attribute,\n attributeVal: this.attributeVal,\n canResistWithArmor: this.canResistWithArmor,\n resistWithArmorNegates: true,\n canResistWithSpecial: this.canResistWithSpecial,\n resistWithSpecialNegates: true,\n specialFooterMsg: this.specialFooterMsg\n };\n // If this consequence has already been resisted once, convert the resistSchema to a None-type schema.\n if (this.wasResisted) {\n resSchema.name = \"\";\n resSchema.type = _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None;\n delete resSchema.resistSchema;\n resSchema.canResistWithArmor = false;\n resSchema.canResistWithSpecial = false;\n }\n return resSchema;\n }\n // #endregion\n async resistConsequence(resistMode, rollInstance) {\n if (!this.isResistible()) {\n throw new Error(\"Cannot resist a consequence that is not resistible.\");\n }\n const updateData = {\n resistanceModes: this.resistanceModes,\n ...this.resistSchema\n };\n updateData.resistanceModes.push(resistMode);\n updateData.parentCsqID = undefined;\n if (resistMode === \"resist\") {\n if (!rollInstance?.isResolved) {\n throw new Error(\"Cannot transform to resisted consequence without a resolved resistance roll instance.\");\n }\n updateData.resistanceRollData = rollInstance.data;\n }\n // Now check updated schema to see whether this consequence should be automatically accepted:\n // ... if this is the second time the consequence has been resisted = verify None-type and accept\n // ... if the resulting resisted consequence is None-type = verify None-type and accept\n // ... if resistMode = \"resist\" and csq can't be resisted with armor or special = transform and accept\n // ... (all other cases are already caught by \"second time\" check above)\n if (this.wasResisted || updateData.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.None) {\n updateData.acceptanceMode = \"base\"; // Use 'base' for None-type consequences so they appear faded out\n }\n else if (resistMode === \"resist\" && !this.canResistWithArmor && !this.canResistWithSpecial) {\n updateData.acceptanceMode = resistMode;\n }\n await this.updateTargetData(updateData);\n if (updateData.acceptanceMode) {\n socketlib.system.executeForEveryone(\"acceptConsequence_SocketCall\", this.id);\n }\n else {\n socketlib.system.executeForEveryone(\"resistConsequence_SocketCall\", this.id);\n }\n }\n // #endregion\n // #region *** ACCEPTING CONSEQUENCES ***\n async acceptConsequence() {\n if (this.isAccepted) {\n return;\n }\n await this.updateTarget(\"acceptanceMode\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getLast(this.resistanceModes) ?? \"accept\");\n socketlib.system.executeForEveryone(\"acceptConsequence_SocketCall\", this.id);\n }\n async applyConsequenceEffects() {\n // If HARM -> Apply harm to actor.\n if (/Harm/.test(this.type)) {\n this.primary.applyHarm(_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(this.type.substring(this.type.length - 1)), this.name);\n // If WORSE POSITION -> Add flag to user to be checked on next Action roll, then cleared\n }\n else if (this.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.WorsePosition) {\n this.primary.applyWorsePosition();\n // If REDUCED EFFECT -> Update chat message flag to reduced effect level.\n }\n else if (this.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.ConsequenceType.ReducedEffect) {\n const curIndex = Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect)\n .findIndex((val) => val === this.effect);\n if (curIndex >= 1) {\n const newEffect = Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect)[curIndex - 1];\n await this.updateTarget(\"rollData.rollEffectFinal\", newEffect);\n }\n }\n // If COMPLICATION -> No change.\n // If LOST OPPORTUNITY -> No change.\n }\n // #endregion\n // #region === CONSTRUCTOR === ~\n // constructor(\n // config: BladesConsequence.Config,\n // parentCsq?: BladesConsequence.Data\n // )\n // constructor(\n // data: BladesConsequence.Data\n // )\n // constructor(\n // schema: Partial,\n // parentCsq: BladesConsequence.Data\n // )\n // constructor(\n // dataConfigOrSchema: BladesConsequence.Config | BladesConsequence.Data | Partial,\n // parentCsq?: BladesConsequence.Data\n // ) {\n // // If a parentCsq is provided...\n // if (parentCsq) {\n // super({\n // ...BladesTargetLink.BuildLinkConfig(parentCsq),\n // ...dataConfigOrSchema\n // });\n // } else {\n // super(dataConfigOrSchema as BladesConsequence.Config | BladesConsequence.Data);\n // }\n // }\n // #endregion\n // #region *** HTML INTERACTION ***\n // #region *** BladesDialog *** ~\n // #endregion\n // #region *** BladesChat *** ~\n static ApplyChatListeners(message) {\n /**\n * TIMELINES\n * .comp.consequence-display-container:mouseenter\n * = fade in grey interaction buttons\n * ...:mouseleave = reverse\n *\n * .consequence-accept-button-container:mouseenter\n * = turn type line white, text shadow\n * slide out .consequence-accept-button-bg from left\n * turn .consequence-accept-button i black, and scale\n * turn .consequence-accept-button-label black, add letter spacing, bold\n * ...:mouseleave = reverse\n *\n * .consequence-resist-button-container:mouseenter\n * = slide in .consequence-type-bg.base-consequence to left\n * fade out all .base-consequence:not(.consequence-type-bg)\n * slide out .consequence-type.resist-consequence from left\n * slide out .consequence-resist-button-bg from right\n * slide out .consequence-footer-bg.resist-consequence from left\n * slide out .consequence-resist-attribute from left\n * slide out .consequence-name.resist-consequence from left\n * fade in .consequence-icon-circle.resist-consequence\n * ...:mouseleave = reverse\n * --> IF resistTo.type === \"None\", blurRemove the base_consequence name and type instead of sliding them in,\n * and don't slide the resistance ones out at all.\n * */\n const html$ = message.elem$;\n html$\n .find(\".comp.consequence-display-container\")\n .each((_i, csqContainer) => {\n if (!$(csqContainer).hasClass(\"consequence-accepted\")) {\n const iconContainer$ = $(csqContainer).find(\".consequence-icon-container\");\n const rightInteractionPad$ = $(csqContainer).find(\".interaction-pad-right\");\n const leftInteractionPad$ = $(csqContainer).find(\".interaction-pad-left\");\n const resistInteractionPad$ = $(csqContainer).find(\".interaction-pad-left-resist\");\n const armorInteractionPad$ = $(csqContainer).find(\".interaction-pad-left-armor\");\n const specialInteractionPad$ = $(csqContainer).find(\".interaction-pad-left-special\");\n // Apply master on-enter hover timeline to consequence container.\n $(csqContainer).data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnter(csqContainer));\n $(csqContainer).on({\n mouseenter: function () {\n $(csqContainer).css(\"z-index\", 10);\n $(csqContainer).data(\"hoverTimeline\").play();\n },\n mouseleave: function () {\n if (!(iconContainer$.data(\"isToggled\") || iconContainer$.data(\"isTogglingOn\")) || iconContainer$.data(\"isTogglingOff\")) {\n $(csqContainer).data(\"hoverTimeline\").reverse().then(() => {\n $(csqContainer).css(\"z-index\", \"\");\n });\n }\n }\n });\n // Apply click timeline to icon circle\n iconContainer$.data(\"clickTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqClickIcon(iconContainer$[0]));\n iconContainer$.on({\n click: function () {\n if (iconContainer$.data(\"isToggled\") || iconContainer$.data(\"isTogglingOn\")) {\n iconContainer$.data(\"isTogglingOn\", false);\n iconContainer$.data(\"isTogglingOff\", true);\n iconContainer$.data(\"clickTimeline\").reverse().then(() => {\n iconContainer$.data(\"isTogglingOff\", false);\n iconContainer$.data(\"isToggled\", false);\n });\n }\n else {\n iconContainer$.data(\"isTogglingOn\", true);\n iconContainer$.data(\"isTogglingOff\", false);\n // Find any siblings with toggled-on iconContainers, and toggle them off\n Array.from($(csqContainer).siblings(\".consequence-display-container\"))\n .forEach((containerElem) => {\n const iContainer$ = $(containerElem).find(\".consequence-icon-container\");\n if (iContainer$?.data(\"isToggled\") || iContainer$?.data(\"isTogglingOn\")) {\n iContainer$.data(\"isTogglingOn\", false);\n iContainer$.data(\"isTogglingOff\", true);\n iContainer$.data(\"clickTimeline\").reverse().then(() => {\n iContainer$.data(\"isTogglingOff\", false);\n iContainer$.data(\"isToggled\", false);\n $(containerElem).data(\"hoverTimeline\").reverse().then(() => {\n $(containerElem).css(\"z-index\", \"\");\n });\n });\n }\n });\n iconContainer$.data(\"clickTimeline\").play().then(() => {\n iconContainer$.data(\"isTogglingOn\", false);\n iconContainer$.data(\"isToggled\", true);\n });\n }\n }\n });\n // Apply hover timelines to right (accept) interaction pad\n rightInteractionPad$.data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnterRight(csqContainer));\n rightInteractionPad$.on({\n mouseenter: function () {\n if (iconContainer$.data(\"isToggled\")) {\n rightInteractionPad$.data(\"hoverTimeline\").play();\n }\n },\n mouseleave: function () {\n rightInteractionPad$.data(\"hoverTimeline\").reverse();\n }\n });\n // Apply hover timeline to left (resist/armor/special) interaction pad\n leftInteractionPad$.data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnterLeft(csqContainer));\n leftInteractionPad$.on({\n mouseenter: function () {\n if (iconContainer$.data(\"isToggled\")) {\n leftInteractionPad$.data(\"hoverTimeline\").play();\n }\n },\n mouseleave: function () {\n leftInteractionPad$.data(\"hoverTimeline\").reverse();\n }\n });\n // Apply hover timelines to specific left interaction pads\n resistInteractionPad$.data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnterSubLeft(csqContainer, { type: \"resist\" }));\n resistInteractionPad$.on({\n mouseenter: function () {\n if (iconContainer$.data(\"isToggled\")) {\n resistInteractionPad$.data(\"hoverTimeline\").play();\n }\n },\n mouseleave: function () {\n if (iconContainer$.data(\"isToggled\")) {\n resistInteractionPad$.data(\"hoverTimeline\").reverse();\n }\n }\n });\n armorInteractionPad$.data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnterSubLeft(csqContainer, { type: \"armor\" }));\n armorInteractionPad$.on({\n mouseenter: function () {\n if (iconContainer$.data(\"isToggled\")) {\n armorInteractionPad$.data(\"hoverTimeline\").play();\n }\n },\n mouseleave: function () {\n if (iconContainer$.data(\"isToggled\")) {\n armorInteractionPad$.data(\"hoverTimeline\").reverse();\n }\n }\n });\n specialInteractionPad$.data(\"hoverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.effects.csqEnterSubLeft(csqContainer, { type: \"special\" }));\n specialInteractionPad$.on({\n mouseenter: function () {\n if (iconContainer$.data(\"isToggled\")) {\n specialInteractionPad$.data(\"hoverTimeline\").play();\n }\n },\n mouseleave: function () {\n if (iconContainer$.data(\"isToggled\")) {\n specialInteractionPad$.data(\"hoverTimeline\").reverse();\n }\n }\n });\n }\n });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesConsequence);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Z0I7QUFDM0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLDJEQUEyRCx1REFBQyw4Q0FBOEMsZUFBZTtBQUN6SDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsNkRBQTZELHVEQUFDLDhDQUE4QyxpQkFBaUI7QUFDN0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSwrREFBZSxpQkFBaUIsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NsYXNzZXMvQmxhZGVzQ29uc2VxdWVuY2UudHM/NWNmMSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmltcG9ydCBDLCB7IEF0dHJpYnV0ZVRyYWl0LCBDb25zZXF1ZW5jZVR5cGUsIFBvc2l0aW9uLCBFZmZlY3QgfSBmcm9tIFwiLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IEJsYWRlc1JvbGwsIHsgQmxhZGVzUm9sbFByaW1hcnkgfSBmcm9tIFwiLi9CbGFkZXNSb2xsXCI7XG5pbXBvcnQgQmxhZGVzVGFyZ2V0TGluayBmcm9tIFwiLi9CbGFkZXNUYXJnZXRMaW5rXCI7XG5pbXBvcnQgeyBCbGFkZXNQQyB9IGZyb20gXCIuLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuLyogZXNsaW50LWVuYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmNsYXNzIEJsYWRlc0NvbnNlcXVlbmNlIGV4dGVuZHMgQmxhZGVzVGFyZ2V0TGluayB7XG4gICAgLy8gI3JlZ2lvbiBTdGF0aWMgTWV0aG9kcyB+XG4gICAgc3RhdGljIGFzeW5jIEluaXRpYWxpemUoKSB7XG4gICAgICAgIGlmICghZ2FtZS5tZXNzYWdlcykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc0NvbnNlcXVlbmNlXSBNZXNzYWdlcyBOb3QgUmVhZHkhXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAoYXdhaXQgUHJvbWlzZS5hbGwoZ2FtZS5tZXNzYWdlcy5jb250ZW50c1xuICAgICAgICAgICAgLm1hcChhc3luYyAobXNnKSA9PiBtc2cucm9sbENvbnNlcXVlbmNlcykpKVxuICAgICAgICAgICAgLmZsYXQoKTtcbiAgICB9XG4gICAgLyoqXG4gICAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gdmFsdWUgaXMgdmFsaWQgY29uc2VxdWVuY2UgZGF0YSBmb3IgYSBSZXNpc3RhbmNlIFJvbGwuXG4gICAqIEBwYXJhbSB2YWwgVGhlIHZhbHVlIHRvIGNoZWNrLlxuICAgKiBAcGFyYW0gaXNDaGVja2luZ1Jlc2lzdGVkVG8gSWYgdGhlIGNoZWNrIGlzIGJlaW5nIHJlY3Vyc2l2ZWx5IGFwcGxpZWQgdG8gdGhlICdyZXNpc3RUbycgdmFsdWUuXG4gICAqIEByZXR1cm5zIFRydWUgaWYgdGhlIHZhbCBpcyB2YWxpZCBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhLCBmYWxzZSBvdGhlcndpc2UuXG4gICAqL1xuICAgIHN0YXRpYyBJc1ZhbGlkQ29uc2VxdWVuY2VEYXRhKHZhbCwgaXNDaGVja2luZ1Jlc2lzdGVkVG8gPSBmYWxzZSkge1xuICAgICAgICBpZiAoIVUuaXNMaXN0KHZhbCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodHlwZW9mIHZhbC50eXBlICE9PSBcInN0cmluZ1wiIHx8ICEodmFsLnR5cGUgaW4gQ29uc2VxdWVuY2VUeXBlKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgdmFsLm5hbWUgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNDaGVja2luZ1Jlc2lzdGVkVG8pIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh2YWwuYXR0cmlidXRlICYmICh0eXBlb2YgdmFsLmF0dHJpYnV0ZSAhPT0gXCJzdHJpbmdcIiB8fCAhKHZhbC5hdHRyaWJ1dGUgaW4gQXR0cmlidXRlVHJhaXQpKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5Jc1ZhbGlkQ29uc2VxdWVuY2VEYXRhKHZhbC5yZXNpc3RUbywgdHJ1ZSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoc2NoZW1hRGF0YSkge1xuICAgICAgICAvLyBFbnN1cmUgYWxsIHByb3BlcnRpZXMgb2YgU2NoZW1hIGFyZSBwcm92aWRlZFxuICAgICAgICBpZiAoIXNjaGVtYURhdGEucHJpbWFyeUlEKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJBIHByaW1hcnlJRCBpcyByZXF1aXJlZCBmb3IgQmxhZGVzQ29uc2VxdWVuY2UuU2NoZW1hXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2Ygc2NoZW1hRGF0YS5uYW1lID09PSBcInN0cmluZ1wiICYmICghc2NoZW1hRGF0YS5uYW1lICYmIHNjaGVtYURhdGEudHlwZSAhPT0gQ29uc2VxdWVuY2VUeXBlLk5vbmUpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEEgbmFtZSBtdXN0IGJlIHByb3ZpZGVkIGZvciBub24tTm9uZS10eXBlIGNvbnNlcXVlbmNlcyAoJHtzY2hlbWFEYXRhLm5hbWV9KS5gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgbmFtZTogXCJcIixcbiAgICAgICAgICAgIHR5cGU6IENvbnNlcXVlbmNlVHlwZS5Ob25lLFxuICAgICAgICAgICAgLi4uc2NoZW1hRGF0YVxuICAgICAgICB9O1xuICAgIH1cbiAgICBzdGF0aWMgR2V0Q3NxVHlwZVZhbHVlKGNUeXBlLCByb2xsRGF0YSkge1xuICAgICAgICBpZiAoY1R5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5Xb3JzZVBvc2l0aW9uKSB7XG4gICAgICAgICAgICAvLyBSZXF1aXJlcyBwb3NpdGlvbiBkYXRhIHRvIHJlc29sdmUuXG4gICAgICAgICAgICBpZiAoIXJvbGxEYXRhKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDYW5ub3QgcmVzb2x2ZSBjb25zZXF1ZW5jZSB0eXBlIHZhbHVlIGZvciAnJHtjVHlwZX0nIHdpdGhvdXQgcm9sbCBkYXRhLmApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGV0IHBvc2l0aW9uO1xuICAgICAgICAgICAgaWYgKFwicm9sbFBvc2l0aW9uRmluYWxcIiBpbiByb2xsRGF0YSkge1xuICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gcm9sbERhdGEucm9sbFBvc2l0aW9uRmluYWw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChcInBvc2l0aW9uXCIgaW4gcm9sbERhdGEpIHtcbiAgICAgICAgICAgICAgICBwb3NpdGlvbiA9IHJvbGxEYXRhLnBvc2l0aW9uO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFwb3NpdGlvbikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHJlc29sdmUgY29uc2VxdWVuY2UgdHlwZSB2YWx1ZSBmb3IgJyR7Y1R5cGV9JyB3aXRob3V0IHJvbGwgZGF0YSB0aGF0IGluY2x1ZGVzIGZpbmFsIHBvc2l0aW9uIGRhdGEuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIFtQb3NpdGlvbi5jb250cm9sbGVkXTogMSxcbiAgICAgICAgICAgICAgICBbUG9zaXRpb24ucmlza3ldOiAyLFxuICAgICAgICAgICAgICAgIFtQb3NpdGlvbi5kZXNwZXJhdGVdOiAwXG4gICAgICAgICAgICB9W3Bvc2l0aW9uXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY1R5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5SZWR1Y2VkRWZmZWN0KSB7XG4gICAgICAgICAgICAvLyBSZXF1aXJlcyBlZmZlY3QgZGF0YSB0byByZXNvbHZlLlxuICAgICAgICAgICAgaWYgKCFyb2xsRGF0YSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHJlc29sdmUgY29uc2VxdWVuY2UgdHlwZSB2YWx1ZSBmb3IgJyR7Y1R5cGV9JyB3aXRob3V0IHJvbGwgZGF0YS5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBlZmZlY3Q7XG4gICAgICAgICAgICBpZiAoXCJyb2xsRWZmZWN0RmluYWxcIiBpbiByb2xsRGF0YSkge1xuICAgICAgICAgICAgICAgIGVmZmVjdCA9IHJvbGxEYXRhLnJvbGxFZmZlY3RGaW5hbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKFwiZWZmZWN0XCIgaW4gcm9sbERhdGEpIHtcbiAgICAgICAgICAgICAgICBlZmZlY3QgPSByb2xsRGF0YS5lZmZlY3Q7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIWVmZmVjdCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2Fubm90IHJlc29sdmUgY29uc2VxdWVuY2UgdHlwZSB2YWx1ZSBmb3IgJyR7Y1R5cGV9JyB3aXRob3V0IHJvbGwgZGF0YSB0aGF0IGluY2x1ZGVzIGZpbmFsIGVmZmVjdCBkYXRhLmApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBbRWZmZWN0LmV4dHJlbWVdOiAxLFxuICAgICAgICAgICAgICAgIFtFZmZlY3QuZ3JlYXRdOiAxLFxuICAgICAgICAgICAgICAgIFtFZmZlY3Quc3RhbmRhcmRdOiAxLFxuICAgICAgICAgICAgICAgIFtFZmZlY3QubGltaXRlZF06IDIsXG4gICAgICAgICAgICAgICAgW0VmZmVjdC56ZXJvXTogMFxuICAgICAgICAgICAgfVtlZmZlY3RdO1xuICAgICAgICB9XG4gICAgICAgIC8vIEFsbCBvdGhlciB2YWx1ZXMgYXJlIGNvbnN0YW50IGZvciBlYWNoIGNvbnNlcXVlbmNlIHR5cGUuXG4gICAgICAgIHJldHVybiBDLkNvbnNlcXVlbmNlVmFsdWVzW2NUeXBlXTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gKioqIEdFVFRFUlMgKioqIH5cbiAgICAvLyAjcmVnaW9uIEdldHRlcnMgKFRhcmdldCBEYXRhKSB+XG4gICAgZ2V0IHByaW1hcnlJRCgpIHsgcmV0dXJuIHRoaXMuZGF0YS5wcmltYXJ5SUQgPz8gdGhpcy5wYXJlbnRDb25zZXF1ZW5jZT8ucHJpbWFyeUlEOyB9XG4gICAgZ2V0IHBhcmVudENzcUlEKCkgeyByZXR1cm4gdGhpcy5kYXRhLnBhcmVudENzcUlEOyB9XG4gICAgZ2V0IG5hbWUoKSB7IHJldHVybiB0aGlzLmRhdGEubmFtZTsgfVxuICAgIGdldCB0eXBlKCkgeyByZXR1cm4gdGhpcy5kYXRhLnR5cGU7IH1cbiAgICBnZXQgYXR0cmlidXRlKCkgeyByZXR1cm4gdGhpcy5kYXRhLmF0dHJpYnV0ZSA/PyB0aGlzLnBhcmVudENvbnNlcXVlbmNlPy5hdHRyaWJ1dGU7IH1cbiAgICBnZXQgYXR0cmlidXRlVmFsKCkgeyByZXR1cm4gdGhpcy5kYXRhLmF0dHJpYnV0ZVZhbCA/PyB0aGlzLnBhcmVudENvbnNlcXVlbmNlPy5hdHRyaWJ1dGVWYWw7IH1cbiAgICBnZXQgc3BlY2lhbEZvb3Rlck1zZygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5zcGVjaWFsRm9vdGVyTXNnID8/IHRoaXMucGFyZW50Q29uc2VxdWVuY2U/LnNwZWNpYWxGb290ZXJNc2c7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEdldHRlcnMgKERlcml2ZWQgRGF0YSkgflxuICAgIGdldCBwcmltYXJ5KCkge1xuICAgICAgICBjb25zdCBwcmltYXJ5ID0gZnJvbVV1aWRTeW5jKHRoaXMucHJpbWFyeUlEKTtcbiAgICAgICAgaWYgKCFCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhwcmltYXJ5KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgZmluZCBwcmltYXJ5IHdpdGggVVVJRCAnJHt0aGlzLnByaW1hcnlJRH0nYCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMucm9sbCkge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBCbGFkZXNSb2xsUHJpbWFyeSh0aGlzLnJvbGwsIHByaW1hcnkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgQmxhZGVzUm9sbFByaW1hcnkocHJpbWFyeSk7XG4gICAgfVxuICAgIGdldCBwYXJlbnRDb25zZXF1ZW5jZSgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnBhcmVudENzcUlEKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBhcmVudENzcSA9IGdhbWUuZXVub2JsYWRlcy5Db25zZXF1ZW5jZXMuZ2V0KHRoaXMucGFyZW50Q3NxSUQpO1xuICAgICAgICBpZiAoIXBhcmVudENzcSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvciBsb2NhdGluZyBwYXJlbnQgY29uc2VxdWVuY2Ugd2l0aCBpZCAnJHt0aGlzLnBhcmVudENzcUlEfSdgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcGFyZW50Q3NxO1xuICAgIH1cbiAgICBnZXQgdHlwZURpc3BsYXkoKSB7IHJldHVybiBDLkNvbnNlcXVlbmNlRGlzcGxheVt0aGlzLnR5cGVdOyB9XG4gICAgZ2V0IGljb24oKSB7IHJldHVybiBDLkNvbnNlcXVlbmNlSWNvbnNbdGhpcy50eXBlXTsgfVxuICAgIGdldCB2YWx1ZSgpIHsgcmV0dXJuIEJsYWRlc0NvbnNlcXVlbmNlLkdldENzcVR5cGVWYWx1ZSh0aGlzLnR5cGUsIHRoaXMpOyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gR2V0dGVycyAoUmVzb2x2ZWQgUm9sbCBEYXRhIHRoYXQgQXBwbGllZCBUaGlzIENvbnNlcXVlbmNlKSB+XG4gICAgZ2V0IHJvbGxEYXRhKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRhLmFjdGlvblJvbGxEYXRhID8/IHRoaXMucGFyZW50Q29uc2VxdWVuY2U/LnJvbGxEYXRhO1xuICAgIH1cbiAgICBnZXQgcm9sbCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnJvbGxEYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBnYW1lLmV1bm9ibGFkZXMuUm9sbHMuZ2V0KHRoaXMucm9sbERhdGEuaWQpID8/IG5ldyBCbGFkZXNSb2xsKHtcbiAgICAgICAgICAgIC4uLnRoaXMucm9sbERhdGEsXG4gICAgICAgICAgICBpc1Njb3BpbmdCeUlkOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0IHBvc2l0aW9uKCkgeyByZXR1cm4gdGhpcy5yb2xsPy5yb2xsUG9zaXRpb25GaW5hbDsgfVxuICAgIGdldCBlZmZlY3QoKSB7IHJldHVybiB0aGlzLnJvbGw/LnJvbGxFZmZlY3RGaW5hbDsgfVxuICAgIGdldCByZXN1bHQoKSB7IHJldHVybiB0aGlzLnJvbGw/LnJvbGxSZXN1bHRGaW5hbDsgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEdldHRlcnMgKFJlc2lzdGliaWxpdHkgJiBBY2NlcHRhbmNlIFN0YXR1cykgflxuICAgIGlzUmVzaXN0aWJsZSgpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy50eXBlICE9PSBDb25zZXF1ZW5jZVR5cGUuTm9uZSAmJiAhdGhpcy5pc0FjY2VwdGVkICYmIHRoaXMuZGF0YS5yZXNpc3RTY2hlbWEpO1xuICAgIH1cbiAgICBnZXQgcmVzaXN0YW5jZU1vZGVzKCkgeyByZXR1cm4gdGhpcy5kYXRhLnJlc2lzdGFuY2VNb2RlcyA/PyBbXTsgfVxuICAgIGdldCB3YXNSZXNpc3RlZCgpIHsgcmV0dXJuIEJvb2xlYW4odGhpcy5yZXNpc3RhbmNlTW9kZXMubGVuZ3RoKTsgfVxuICAgIGdldCB3YXNSZXNpc3RlZEJ5Um9sbCgpIHsgcmV0dXJuIHRoaXMucmVzaXN0YW5jZU1vZGVzLmluY2x1ZGVzKFwicmVzaXN0XCIpOyB9XG4gICAgZ2V0IHdhc1Jlc2lzdGVkQnlBcm1vcigpIHsgcmV0dXJuIHRoaXMucmVzaXN0YW5jZU1vZGVzLmluY2x1ZGVzKFwiYXJtb3JcIik7IH1cbiAgICBnZXQgd2FzUmVzaXN0ZWRCeVNwZWNpYWxBcm1vcigpIHsgcmV0dXJuIHRoaXMucmVzaXN0YW5jZU1vZGVzPy5pbmNsdWRlcyhcInNwZWNpYWxcIik7IH1cbiAgICBnZXQgY2FuUmVzaXN0V2l0aFJvbGwoKSB7XG4gICAgICAgIGlmICghdGhpcy5pc1Jlc2lzdGlibGUoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIE9ubHkgUENzIGNhbiByb2xsIHRvIHJlc2lzdCBjb25zZXF1ZW5jZXMuXG4gICAgICAgIGlmICghQmxhZGVzUEMuSXNUeXBlKHRoaXMucHJpbWFyeS5yb2xsUHJpbWFyeURvYykpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBIGNvbnNlcXVlbmNlIGNhbiBvbmx5IGJlIHJlc2lzdGVkIGJ5IHJvbGwgb25jZS5cbiAgICAgICAgaWYgKHRoaXMud2FzUmVzaXN0ZWRCeVJvbGwpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPdGhlcndpc2UsIGEgY29uc2VxdWVuY2UgY2FuIEFMV0FZUyBiZSByZXNpc3RlZCBieSByb2xsIG9uY2UgYnkgYSBQQy5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGdldCBjYW5SZXNpc3RXaXRoQXJtb3IoKSB7XG4gICAgICAgIGlmICghdGhpcy5pc1Jlc2lzdGlibGUoKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIFRoZSBjb25zZXF1ZW5jZSBtdXN0IGJlIGV4cGxpY2l0bHkgZmxhZ2dlZCBhcyByZXNpc3RhYmxlIGJ5IGFybW9yLlxuICAgICAgICBpZiAoIXRoaXMuZGF0YS5jYW5SZXNpc3RXaXRoQXJtb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVbmxpa2UgcmVzaXN0YW5jZSByb2xscywgYSBQcmltYXJ5IGNvdWxkIGNvbmNlaXZhYmx5IHJlc2lzdCB0d2ljZSB1c2luZyBtdWx0aXBsZSBhcm1vciBib3hlcy5cbiAgICAgICAgLy8gU28sIGEgcmVzaXN0YW5jZU1vZGUgcHJldmlvdXNseSBzZXQgdG8gXCJhcm1vclwiIGRvZXMgbm90IGRpc3F1YWxpZnkgYW5vdGhlciByZXNpc3QsIGlmIHRoZVxuICAgICAgICAvLyBQcmltYXJ5IGhhcyBhcm1vciB0byBzcGFyZS5cbiAgICAgICAgcmV0dXJuIHRoaXMucHJpbWFyeS5hdmFpbGFibGVBcm1vckNvdW50ID4gMDtcbiAgICB9XG4gICAgZ2V0IGNhblJlc2lzdFdpdGhTcGVjaWFsKCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNSZXNpc3RpYmxlKCkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBUaGUgY29uc2VxdWVuY2UgbXVzdCBiZSBleHBsaWNpdGx5IGZsYWdnZWQgYXMgcmVzaXN0YWJsZSBieSBzcGVjaWFsIGFybW9yLlxuICAgICAgICBpZiAoIXRoaXMuZGF0YS5jYW5SZXNpc3RXaXRoU3BlY2lhbCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIE9ubHkgUENzIGNhbiByZXNpc3QgY29uc2VxdWVuY2VzIHdpdGggc3BlY2lhbCBhcm1vci5cbiAgICAgICAgaWYgKCFCbGFkZXNQQy5Jc1R5cGUodGhpcy5wcmltYXJ5LnJvbGxQcmltYXJ5RG9jKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIEEgY29uc2VxdWVuY2UgY2FuIG9ubHkgYmUgcmVzaXN0ZWQgYnkgc3BlY2lhbCBhcm1vciBvbmNlLlxuICAgICAgICBpZiAodGhpcy53YXNSZXNpc3RlZEJ5U3BlY2lhbEFybW9yKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCB0aGUgUEMgY2FuIHJlc2lzdCBpZiB0aGV5IGhhdmUgc3BlY2lhbCBhcm1vciB0byBzcGFyZS5cbiAgICAgICAgcmV0dXJuIHRoaXMucHJpbWFyeS5oYXNTcGVjaWFsQXJtb3I7XG4gICAgfVxuICAgIGdldCByZXNpc3RXaXRoUm9sbE5lZ2F0ZXMoKSB7XG4gICAgICAgIGlmICghdGhpcy5jYW5SZXNpc3RXaXRoUm9sbCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIHRoaXMgaXMgdGhlIHNlY29uZCByZXNpc3RhbmNlLCBpdCBhdXRvbWF0aWNhbGx5IG5lZ2F0ZXMuXG4gICAgICAgIGlmICh0aGlzLndhc1Jlc2lzdGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBPdGhlcndpc2UsIGl0IG5lZ2F0ZXMgaWYgZXhwbGljaXRseSBmbGFnZ2VkIHRvIGRvIHNvLlxuICAgICAgICByZXR1cm4gQm9vbGVhbih0aGlzLmRhdGEucmVzaXN0V2l0aFJvbGxOZWdhdGVzKTtcbiAgICB9XG4gICAgZ2V0IHJlc2lzdFdpdGhBcm1vck5lZ2F0ZXMoKSB7XG4gICAgICAgIGlmICghdGhpcy5jYW5SZXNpc3RXaXRoQXJtb3IpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiB0aGlzIGlzIHRoZSBzZWNvbmQgcmVzaXN0YW5jZSwgaXQgYXV0b21hdGljYWxseSBuZWdhdGVzLlxuICAgICAgICBpZiAodGhpcy53YXNSZXNpc3RlZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCBpdCBuZWdhdGVzIGlmIGV4cGxpY2l0bHkgZmxhZ2dlZCB0byBkbyBzby5cbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5kYXRhLnJlc2lzdFdpdGhBcm1vck5lZ2F0ZXMpO1xuICAgIH1cbiAgICBnZXQgcmVzaXN0V2l0aFNwZWNpYWxOZWdhdGVzKCkge1xuICAgICAgICBpZiAoIXRoaXMuY2FuUmVzaXN0V2l0aFNwZWNpYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiB0aGlzIGlzIHRoZSBzZWNvbmQgcmVzaXN0YW5jZSwgaXQgYXV0b21hdGljYWxseSBuZWdhdGVzLlxuICAgICAgICBpZiAodGhpcy53YXNSZXNpc3RlZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgLy8gT3RoZXJ3aXNlLCBpdCBuZWdhdGVzIGlmIGV4cGxpY2l0bHkgZmxhZ2dlZCB0byBkbyBzby5cbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5kYXRhLnJlc2lzdFdpdGhTcGVjaWFsTmVnYXRlcyk7XG4gICAgfVxuICAgIGdldCBpc0FjY2VwdGVkKCkgeyByZXR1cm4gXCJhY2NlcHRhbmNlTW9kZVwiIGluIHRoaXMuZGF0YTsgfVxuICAgIGdldCBhY2NlcHRhbmNlTW9kZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5hY2NlcHRhbmNlTW9kZTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uICoqKiBSRVNJU1RJTkcgQ09OU0VRVUVOQ0VTICoqKlxuICAgIC8vICNyZWdpb24gQ29uc3RydWN0aW5nIFJlc2lzdGFibGUgQ29uc2VxdWVuY2UgU2NoZW1hXG4gICAgZ2V0IG5vbmVTY2hlbWEoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgICAgICAgICAgdHlwZTogQ29uc2VxdWVuY2VUeXBlLk5vbmUsXG4gICAgICAgICAgICBwcmltYXJ5SUQ6IHRoaXMucHJpbWFyeUlEXG4gICAgICAgIH07XG4gICAgfVxuICAgIGdldCByZXNpc3RTY2hlbWEoKSB7XG4gICAgICAgIC8vIElmIHRoaXMgY29uc2VxdWVuY2UgY2FuJ3QgYmUgcmVzaXN0ZWQsIHJldHVybiB1bmRlZmluZWQuXG4gICAgICAgIGlmICghdGhpcy5pc1Jlc2lzdGlibGUoKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICAvLyBFeHBhbmQgdGhlIHJlc2lzdFNjaGVtYSBpbnRvIGEgZnVsbCBCbGFkZXNDb25zZXF1ZW5jZS5TY2hlbWEgb2JqZWN0XG4gICAgICAgIGNvbnN0IHJlc1NjaGVtYSA9IHtcbiAgICAgICAgICAgIG5hbWU6IHRoaXMuZGF0YS5yZXNpc3RTY2hlbWEubmFtZSxcbiAgICAgICAgICAgIHR5cGU6IHRoaXMuZGF0YS5yZXNpc3RTY2hlbWEudHlwZSxcbiAgICAgICAgICAgIHByaW1hcnlJRDogdGhpcy5wcmltYXJ5SUQsXG4gICAgICAgICAgICByZXNpc3RTY2hlbWE6IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IENvbnNlcXVlbmNlVHlwZS5Ob25lXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgcmVzaXN0YW5jZU1vZGVzOiB0aGlzLnJlc2lzdGFuY2VNb2RlcyxcbiAgICAgICAgICAgIHJlc2lzdFdpdGhSb2xsTmVnYXRlczogdHJ1ZSxcbiAgICAgICAgICAgIGF0dHJpYnV0ZTogdGhpcy5hdHRyaWJ1dGUsXG4gICAgICAgICAgICBhdHRyaWJ1dGVWYWw6IHRoaXMuYXR0cmlidXRlVmFsLFxuICAgICAgICAgICAgY2FuUmVzaXN0V2l0aEFybW9yOiB0aGlzLmNhblJlc2lzdFdpdGhBcm1vcixcbiAgICAgICAgICAgIHJlc2lzdFdpdGhBcm1vck5lZ2F0ZXM6IHRydWUsXG4gICAgICAgICAgICBjYW5SZXNpc3RXaXRoU3BlY2lhbDogdGhpcy5jYW5SZXNpc3RXaXRoU3BlY2lhbCxcbiAgICAgICAgICAgIHJlc2lzdFdpdGhTcGVjaWFsTmVnYXRlczogdHJ1ZSxcbiAgICAgICAgICAgIHNwZWNpYWxGb290ZXJNc2c6IHRoaXMuc3BlY2lhbEZvb3Rlck1zZ1xuICAgICAgICB9O1xuICAgICAgICAvLyBJZiB0aGlzIGNvbnNlcXVlbmNlIGhhcyBhbHJlYWR5IGJlZW4gcmVzaXN0ZWQgb25jZSwgY29udmVydCB0aGUgcmVzaXN0U2NoZW1hIHRvIGEgTm9uZS10eXBlIHNjaGVtYS5cbiAgICAgICAgaWYgKHRoaXMud2FzUmVzaXN0ZWQpIHtcbiAgICAgICAgICAgIHJlc1NjaGVtYS5uYW1lID0gXCJcIjtcbiAgICAgICAgICAgIHJlc1NjaGVtYS50eXBlID0gQ29uc2VxdWVuY2VUeXBlLk5vbmU7XG4gICAgICAgICAgICBkZWxldGUgcmVzU2NoZW1hLnJlc2lzdFNjaGVtYTtcbiAgICAgICAgICAgIHJlc1NjaGVtYS5jYW5SZXNpc3RXaXRoQXJtb3IgPSBmYWxzZTtcbiAgICAgICAgICAgIHJlc1NjaGVtYS5jYW5SZXNpc3RXaXRoU3BlY2lhbCA9IGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXNTY2hlbWE7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBhc3luYyByZXNpc3RDb25zZXF1ZW5jZShyZXNpc3RNb2RlLCByb2xsSW5zdGFuY2UpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUmVzaXN0aWJsZSgpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgcmVzaXN0IGEgY29uc2VxdWVuY2UgdGhhdCBpcyBub3QgcmVzaXN0aWJsZS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdXBkYXRlRGF0YSA9IHtcbiAgICAgICAgICAgIHJlc2lzdGFuY2VNb2RlczogdGhpcy5yZXNpc3RhbmNlTW9kZXMsXG4gICAgICAgICAgICAuLi50aGlzLnJlc2lzdFNjaGVtYVxuICAgICAgICB9O1xuICAgICAgICB1cGRhdGVEYXRhLnJlc2lzdGFuY2VNb2Rlcy5wdXNoKHJlc2lzdE1vZGUpO1xuICAgICAgICB1cGRhdGVEYXRhLnBhcmVudENzcUlEID0gdW5kZWZpbmVkO1xuICAgICAgICBpZiAocmVzaXN0TW9kZSA9PT0gXCJyZXNpc3RcIikge1xuICAgICAgICAgICAgaWYgKCFyb2xsSW5zdGFuY2U/LmlzUmVzb2x2ZWQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgdHJhbnNmb3JtIHRvIHJlc2lzdGVkIGNvbnNlcXVlbmNlIHdpdGhvdXQgYSByZXNvbHZlZCByZXNpc3RhbmNlIHJvbGwgaW5zdGFuY2UuXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXBkYXRlRGF0YS5yZXNpc3RhbmNlUm9sbERhdGEgPSByb2xsSW5zdGFuY2UuZGF0YTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOb3cgY2hlY2sgdXBkYXRlZCBzY2hlbWEgdG8gc2VlIHdoZXRoZXIgdGhpcyBjb25zZXF1ZW5jZSBzaG91bGQgYmUgYXV0b21hdGljYWxseSBhY2NlcHRlZDpcbiAgICAgICAgLy8gLi4uIGlmIHRoaXMgaXMgdGhlIHNlY29uZCB0aW1lIHRoZSBjb25zZXF1ZW5jZSBoYXMgYmVlbiByZXNpc3RlZCA9IHZlcmlmeSBOb25lLXR5cGUgYW5kIGFjY2VwdFxuICAgICAgICAvLyAuLi4gaWYgdGhlIHJlc3VsdGluZyByZXNpc3RlZCBjb25zZXF1ZW5jZSBpcyBOb25lLXR5cGUgPSB2ZXJpZnkgTm9uZS10eXBlIGFuZCBhY2NlcHRcbiAgICAgICAgLy8gLi4uIGlmIHJlc2lzdE1vZGUgPSBcInJlc2lzdFwiIGFuZCBjc3EgY2FuJ3QgYmUgcmVzaXN0ZWQgd2l0aCBhcm1vciBvciBzcGVjaWFsID0gdHJhbnNmb3JtIGFuZCBhY2NlcHRcbiAgICAgICAgLy8gICAgICAgLi4uIChhbGwgb3RoZXIgY2FzZXMgYXJlIGFscmVhZHkgY2F1Z2h0IGJ5IFwic2Vjb25kIHRpbWVcIiBjaGVjayBhYm92ZSlcbiAgICAgICAgaWYgKHRoaXMud2FzUmVzaXN0ZWQgfHwgdXBkYXRlRGF0YS50eXBlID09PSBDb25zZXF1ZW5jZVR5cGUuTm9uZSkge1xuICAgICAgICAgICAgdXBkYXRlRGF0YS5hY2NlcHRhbmNlTW9kZSA9IFwiYmFzZVwiOyAvLyBVc2UgJ2Jhc2UnIGZvciBOb25lLXR5cGUgY29uc2VxdWVuY2VzIHNvIHRoZXkgYXBwZWFyIGZhZGVkIG91dFxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHJlc2lzdE1vZGUgPT09IFwicmVzaXN0XCIgJiYgIXRoaXMuY2FuUmVzaXN0V2l0aEFybW9yICYmICF0aGlzLmNhblJlc2lzdFdpdGhTcGVjaWFsKSB7XG4gICAgICAgICAgICB1cGRhdGVEYXRhLmFjY2VwdGFuY2VNb2RlID0gcmVzaXN0TW9kZTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldERhdGEodXBkYXRlRGF0YSk7XG4gICAgICAgIGlmICh1cGRhdGVEYXRhLmFjY2VwdGFuY2VNb2RlKSB7XG4gICAgICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcImFjY2VwdENvbnNlcXVlbmNlX1NvY2tldENhbGxcIiwgdGhpcy5pZCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlc2lzdENvbnNlcXVlbmNlX1NvY2tldENhbGxcIiwgdGhpcy5pZCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gKioqIEFDQ0VQVElORyBDT05TRVFVRU5DRVMgKioqXG4gICAgYXN5bmMgYWNjZXB0Q29uc2VxdWVuY2UoKSB7XG4gICAgICAgIGlmICh0aGlzLmlzQWNjZXB0ZWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldChcImFjY2VwdGFuY2VNb2RlXCIsIFUuZ2V0TGFzdCh0aGlzLnJlc2lzdGFuY2VNb2RlcykgPz8gXCJhY2NlcHRcIik7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwiYWNjZXB0Q29uc2VxdWVuY2VfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICB9XG4gICAgYXN5bmMgYXBwbHlDb25zZXF1ZW5jZUVmZmVjdHMoKSB7XG4gICAgICAgIC8vIElmIEhBUk0gLT4gQXBwbHkgaGFybSB0byBhY3Rvci5cbiAgICAgICAgaWYgKC9IYXJtLy50ZXN0KHRoaXMudHlwZSkpIHtcbiAgICAgICAgICAgIHRoaXMucHJpbWFyeS5hcHBseUhhcm0oVS5wSW50KHRoaXMudHlwZS5zdWJzdHJpbmcodGhpcy50eXBlLmxlbmd0aCAtIDEpKSwgdGhpcy5uYW1lKTtcbiAgICAgICAgICAgIC8vIElmIFdPUlNFIFBPU0lUSU9OIC0+IEFkZCBmbGFnIHRvIHVzZXIgdG8gYmUgY2hlY2tlZCBvbiBuZXh0IEFjdGlvbiByb2xsLCB0aGVuIGNsZWFyZWRcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLnR5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5Xb3JzZVBvc2l0aW9uKSB7XG4gICAgICAgICAgICB0aGlzLnByaW1hcnkuYXBwbHlXb3JzZVBvc2l0aW9uKCk7XG4gICAgICAgICAgICAvLyBJZiBSRURVQ0VEIEVGRkVDVCAtPiBVcGRhdGUgY2hhdCBtZXNzYWdlIGZsYWcgdG8gcmVkdWNlZCBlZmZlY3QgbGV2ZWwuXG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50eXBlID09PSBDb25zZXF1ZW5jZVR5cGUuUmVkdWNlZEVmZmVjdCkge1xuICAgICAgICAgICAgY29uc3QgY3VySW5kZXggPSBPYmplY3QudmFsdWVzKEVmZmVjdClcbiAgICAgICAgICAgICAgICAuZmluZEluZGV4KCh2YWwpID0+IHZhbCA9PT0gdGhpcy5lZmZlY3QpO1xuICAgICAgICAgICAgaWYgKGN1ckluZGV4ID49IDEpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZXdFZmZlY3QgPSBPYmplY3QudmFsdWVzKEVmZmVjdClbY3VySW5kZXggLSAxXTtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxEYXRhLnJvbGxFZmZlY3RGaW5hbFwiLCBuZXdFZmZlY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIElmIENPTVBMSUNBVElPTiAtPiBObyBjaGFuZ2UuXG4gICAgICAgIC8vIElmIExPU1QgT1BQT1JUVU5JVFkgLT4gTm8gY2hhbmdlLlxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiA9PT0gQ09OU1RSVUNUT1IgPT09IH5cbiAgICAvLyBjb25zdHJ1Y3RvcihcbiAgICAvLyAgIGNvbmZpZzogQmxhZGVzQ29uc2VxdWVuY2UuQ29uZmlnLFxuICAgIC8vICAgcGFyZW50Q3NxPzogQmxhZGVzQ29uc2VxdWVuY2UuRGF0YVxuICAgIC8vIClcbiAgICAvLyBjb25zdHJ1Y3RvcihcbiAgICAvLyAgIGRhdGE6IEJsYWRlc0NvbnNlcXVlbmNlLkRhdGFcbiAgICAvLyApXG4gICAgLy8gY29uc3RydWN0b3IoXG4gICAgLy8gICBzY2hlbWE6IFBhcnRpYWw8QmxhZGVzQ29uc2VxdWVuY2UuU2NoZW1hPixcbiAgICAvLyAgIHBhcmVudENzcTogQmxhZGVzQ29uc2VxdWVuY2UuRGF0YVxuICAgIC8vIClcbiAgICAvLyBjb25zdHJ1Y3RvcihcbiAgICAvLyAgIGRhdGFDb25maWdPclNjaGVtYTogQmxhZGVzQ29uc2VxdWVuY2UuQ29uZmlnIHwgQmxhZGVzQ29uc2VxdWVuY2UuRGF0YSB8IFBhcnRpYWw8QmxhZGVzQ29uc2VxdWVuY2UuU2NoZW1hPixcbiAgICAvLyAgIHBhcmVudENzcT86IEJsYWRlc0NvbnNlcXVlbmNlLkRhdGFcbiAgICAvLyApIHtcbiAgICAvLyAgIC8vIElmIGEgcGFyZW50Q3NxIGlzIHByb3ZpZGVkLi4uXG4gICAgLy8gICBpZiAocGFyZW50Q3NxKSB7XG4gICAgLy8gICAgIHN1cGVyKHtcbiAgICAvLyAgICAgICAuLi5CbGFkZXNUYXJnZXRMaW5rLkJ1aWxkTGlua0NvbmZpZyhwYXJlbnRDc3EpLFxuICAgIC8vICAgICAgIC4uLmRhdGFDb25maWdPclNjaGVtYVxuICAgIC8vICAgICB9KTtcbiAgICAvLyAgIH0gZWxzZSB7XG4gICAgLy8gICAgIHN1cGVyKGRhdGFDb25maWdPclNjaGVtYSBhcyBCbGFkZXNDb25zZXF1ZW5jZS5Db25maWcgfCBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhKTtcbiAgICAvLyAgIH1cbiAgICAvLyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gKioqIEhUTUwgSU5URVJBQ1RJT04gKioqXG4gICAgLy8gI3JlZ2lvbiAqKiogQmxhZGVzRGlhbG9nICoqKiB+XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gKioqIEJsYWRlc0NoYXQgKioqIH5cbiAgICBzdGF0aWMgQXBwbHlDaGF0TGlzdGVuZXJzKG1lc3NhZ2UpIHtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIFRJTUVMSU5FU1xuICAgICAgICAgKiAuY29tcC5jb25zZXF1ZW5jZS1kaXNwbGF5LWNvbnRhaW5lcjptb3VzZWVudGVyXG4gICAgICAgICAqICAgPSBmYWRlIGluIGdyZXkgaW50ZXJhY3Rpb24gYnV0dG9uc1xuICAgICAgICAgKiAgIC4uLjptb3VzZWxlYXZlID0gcmV2ZXJzZVxuICAgICAgICAgKlxuICAgICAgICAgKiAuY29uc2VxdWVuY2UtYWNjZXB0LWJ1dHRvbi1jb250YWluZXI6bW91c2VlbnRlclxuICAgICAgICAgKiAgID0gdHVybiB0eXBlIGxpbmUgd2hpdGUsIHRleHQgc2hhZG93XG4gICAgICAgICAqICAgICBzbGlkZSBvdXQgLmNvbnNlcXVlbmNlLWFjY2VwdC1idXR0b24tYmcgZnJvbSBsZWZ0XG4gICAgICAgICAqICAgICB0dXJuIC5jb25zZXF1ZW5jZS1hY2NlcHQtYnV0dG9uIGkgYmxhY2ssIGFuZCBzY2FsZVxuICAgICAgICAgKiAgICAgdHVybiAuY29uc2VxdWVuY2UtYWNjZXB0LWJ1dHRvbi1sYWJlbCBibGFjaywgYWRkIGxldHRlciBzcGFjaW5nLCBib2xkXG4gICAgICAgICAqICAgLi4uOm1vdXNlbGVhdmUgPSByZXZlcnNlXG4gICAgICAgICAqXG4gICAgICAgICAqIC5jb25zZXF1ZW5jZS1yZXNpc3QtYnV0dG9uLWNvbnRhaW5lcjptb3VzZWVudGVyXG4gICAgICAgICAqICAgPSBzbGlkZSBpbiAuY29uc2VxdWVuY2UtdHlwZS1iZy5iYXNlLWNvbnNlcXVlbmNlIHRvIGxlZnRcbiAgICAgICAgICogICAgIGZhZGUgb3V0IGFsbCAuYmFzZS1jb25zZXF1ZW5jZTpub3QoLmNvbnNlcXVlbmNlLXR5cGUtYmcpXG4gICAgICAgICAqICAgICBzbGlkZSBvdXQgLmNvbnNlcXVlbmNlLXR5cGUucmVzaXN0LWNvbnNlcXVlbmNlIGZyb20gbGVmdFxuICAgICAgICAgKiAgICAgc2xpZGUgb3V0IC5jb25zZXF1ZW5jZS1yZXNpc3QtYnV0dG9uLWJnIGZyb20gcmlnaHRcbiAgICAgICAgICogICAgIHNsaWRlIG91dCAuY29uc2VxdWVuY2UtZm9vdGVyLWJnLnJlc2lzdC1jb25zZXF1ZW5jZSBmcm9tIGxlZnRcbiAgICAgICAgICogICAgIHNsaWRlIG91dCAuY29uc2VxdWVuY2UtcmVzaXN0LWF0dHJpYnV0ZSBmcm9tIGxlZnRcbiAgICAgICAgICogICAgIHNsaWRlIG91dCAuY29uc2VxdWVuY2UtbmFtZS5yZXNpc3QtY29uc2VxdWVuY2UgZnJvbSBsZWZ0XG4gICAgICAgICAqICAgICBmYWRlIGluIC5jb25zZXF1ZW5jZS1pY29uLWNpcmNsZS5yZXNpc3QtY29uc2VxdWVuY2VcbiAgICAgICAgICogICAuLi46bW91c2VsZWF2ZSA9IHJldmVyc2VcbiAgICAgICAgICogICAtLT4gSUYgcmVzaXN0VG8udHlwZSA9PT0gXCJOb25lXCIsIGJsdXJSZW1vdmUgdGhlIGJhc2VfY29uc2VxdWVuY2UgbmFtZSBhbmQgdHlwZSBpbnN0ZWFkIG9mIHNsaWRpbmcgdGhlbSBpbixcbiAgICAgICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhbmQgZG9uJ3Qgc2xpZGUgdGhlIHJlc2lzdGFuY2Ugb25lcyBvdXQgYXQgYWxsLlxuICAgICAgICAgKiAqL1xuICAgICAgICBjb25zdCBodG1sJCA9IG1lc3NhZ2UuZWxlbSQ7XG4gICAgICAgIGh0bWwkXG4gICAgICAgICAgICAuZmluZChcIi5jb21wLmNvbnNlcXVlbmNlLWRpc3BsYXktY29udGFpbmVyXCIpXG4gICAgICAgICAgICAuZWFjaCgoX2ksIGNzcUNvbnRhaW5lcikgPT4ge1xuICAgICAgICAgICAgaWYgKCEkKGNzcUNvbnRhaW5lcikuaGFzQ2xhc3MoXCJjb25zZXF1ZW5jZS1hY2NlcHRlZFwiKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGljb25Db250YWluZXIkID0gJChjc3FDb250YWluZXIpLmZpbmQoXCIuY29uc2VxdWVuY2UtaWNvbi1jb250YWluZXJcIik7XG4gICAgICAgICAgICAgICAgY29uc3QgcmlnaHRJbnRlcmFjdGlvblBhZCQgPSAkKGNzcUNvbnRhaW5lcikuZmluZChcIi5pbnRlcmFjdGlvbi1wYWQtcmlnaHRcIik7XG4gICAgICAgICAgICAgICAgY29uc3QgbGVmdEludGVyYWN0aW9uUGFkJCA9ICQoY3NxQ29udGFpbmVyKS5maW5kKFwiLmludGVyYWN0aW9uLXBhZC1sZWZ0XCIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHJlc2lzdEludGVyYWN0aW9uUGFkJCA9ICQoY3NxQ29udGFpbmVyKS5maW5kKFwiLmludGVyYWN0aW9uLXBhZC1sZWZ0LXJlc2lzdFwiKTtcbiAgICAgICAgICAgICAgICBjb25zdCBhcm1vckludGVyYWN0aW9uUGFkJCA9ICQoY3NxQ29udGFpbmVyKS5maW5kKFwiLmludGVyYWN0aW9uLXBhZC1sZWZ0LWFybW9yXCIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNwZWNpYWxJbnRlcmFjdGlvblBhZCQgPSAkKGNzcUNvbnRhaW5lcikuZmluZChcIi5pbnRlcmFjdGlvbi1wYWQtbGVmdC1zcGVjaWFsXCIpO1xuICAgICAgICAgICAgICAgIC8vIEFwcGx5IG1hc3RlciBvbi1lbnRlciBob3ZlciB0aW1lbGluZSB0byBjb25zZXF1ZW5jZSBjb250YWluZXIuXG4gICAgICAgICAgICAgICAgJChjc3FDb250YWluZXIpLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIsIFUuZ3NhcC5lZmZlY3RzLmNzcUVudGVyKGNzcUNvbnRhaW5lcikpO1xuICAgICAgICAgICAgICAgICQoY3NxQ29udGFpbmVyKS5vbih7XG4gICAgICAgICAgICAgICAgICAgIG1vdXNlZW50ZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoY3NxQ29udGFpbmVyKS5jc3MoXCJ6LWluZGV4XCIsIDEwKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoY3NxQ29udGFpbmVyKS5kYXRhKFwiaG92ZXJUaW1lbGluZVwiKS5wbGF5KCk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIG1vdXNlbGVhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghKGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsZWRcIikgfHwgaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xpbmdPblwiKSkgfHwgaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xpbmdPZmZcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKGNzcUNvbnRhaW5lcikuZGF0YShcImhvdmVyVGltZWxpbmVcIikucmV2ZXJzZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKGNzcUNvbnRhaW5lcikuY3NzKFwiei1pbmRleFwiLCBcIlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIC8vIEFwcGx5IGNsaWNrIHRpbWVsaW5lIHRvIGljb24gY2lyY2xlXG4gICAgICAgICAgICAgICAgaWNvbkNvbnRhaW5lciQuZGF0YShcImNsaWNrVGltZWxpbmVcIiwgVS5nc2FwLmVmZmVjdHMuY3NxQ2xpY2tJY29uKGljb25Db250YWluZXIkWzBdKSk7XG4gICAgICAgICAgICAgICAgaWNvbkNvbnRhaW5lciQub24oe1xuICAgICAgICAgICAgICAgICAgICBjbGljazogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsZWRcIikgfHwgaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xpbmdPblwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT25cIiwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT2ZmXCIsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljb25Db250YWluZXIkLmRhdGEoXCJjbGlja1RpbWVsaW5lXCIpLnJldmVyc2UoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xpbmdPZmZcIiwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT25cIiwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xpbmdPZmZcIiwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZpbmQgYW55IHNpYmxpbmdzIHdpdGggdG9nZ2xlZC1vbiBpY29uQ29udGFpbmVycywgYW5kIHRvZ2dsZSB0aGVtIG9mZlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFycmF5LmZyb20oJChjc3FDb250YWluZXIpLnNpYmxpbmdzKFwiLmNvbnNlcXVlbmNlLWRpc3BsYXktY29udGFpbmVyXCIpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgoY29udGFpbmVyRWxlbSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBpQ29udGFpbmVyJCA9ICQoY29udGFpbmVyRWxlbSkuZmluZChcIi5jb25zZXF1ZW5jZS1pY29uLWNvbnRhaW5lclwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlDb250YWluZXIkPy5kYXRhKFwiaXNUb2dnbGVkXCIpIHx8IGlDb250YWluZXIkPy5kYXRhKFwiaXNUb2dnbGluZ09uXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGluZ09uXCIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlDb250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT2ZmXCIsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaUNvbnRhaW5lciQuZGF0YShcImNsaWNrVGltZWxpbmVcIikucmV2ZXJzZSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlDb250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT2ZmXCIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKGNvbnRhaW5lckVsZW0pLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIpLnJldmVyc2UoKS50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJChjb250YWluZXJFbGVtKS5jc3MoXCJ6LWluZGV4XCIsIFwiXCIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpY29uQ29udGFpbmVyJC5kYXRhKFwiY2xpY2tUaW1lbGluZVwiKS5wbGF5KCkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGljb25Db250YWluZXIkLmRhdGEoXCJpc1RvZ2dsaW5nT25cIiwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgLy8gQXBwbHkgaG92ZXIgdGltZWxpbmVzIHRvIHJpZ2h0IChhY2NlcHQpIGludGVyYWN0aW9uIHBhZFxuICAgICAgICAgICAgICAgIHJpZ2h0SW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIsIFUuZ3NhcC5lZmZlY3RzLmNzcUVudGVyUmlnaHQoY3NxQ29udGFpbmVyKSk7XG4gICAgICAgICAgICAgICAgcmlnaHRJbnRlcmFjdGlvblBhZCQub24oe1xuICAgICAgICAgICAgICAgICAgICBtb3VzZWVudGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJpZ2h0SW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIpLnBsYXkoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgbW91c2VsZWF2ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmlnaHRJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIikucmV2ZXJzZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgLy8gQXBwbHkgaG92ZXIgdGltZWxpbmUgdG8gbGVmdCAocmVzaXN0L2FybW9yL3NwZWNpYWwpIGludGVyYWN0aW9uIHBhZFxuICAgICAgICAgICAgICAgIGxlZnRJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIiwgVS5nc2FwLmVmZmVjdHMuY3NxRW50ZXJMZWZ0KGNzcUNvbnRhaW5lcikpO1xuICAgICAgICAgICAgICAgIGxlZnRJbnRlcmFjdGlvblBhZCQub24oe1xuICAgICAgICAgICAgICAgICAgICBtb3VzZWVudGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlZnRJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIikucGxheSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBtb3VzZWxlYXZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBsZWZ0SW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIpLnJldmVyc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIC8vIEFwcGx5IGhvdmVyIHRpbWVsaW5lcyB0byBzcGVjaWZpYyBsZWZ0IGludGVyYWN0aW9uIHBhZHNcbiAgICAgICAgICAgICAgICByZXNpc3RJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIiwgVS5nc2FwLmVmZmVjdHMuY3NxRW50ZXJTdWJMZWZ0KGNzcUNvbnRhaW5lciwgeyB0eXBlOiBcInJlc2lzdFwiIH0pKTtcbiAgICAgICAgICAgICAgICByZXNpc3RJbnRlcmFjdGlvblBhZCQub24oe1xuICAgICAgICAgICAgICAgICAgICBtb3VzZWVudGVyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc2lzdEludGVyYWN0aW9uUGFkJC5kYXRhKFwiaG92ZXJUaW1lbGluZVwiKS5wbGF5KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIG1vdXNlbGVhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzaXN0SW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIpLnJldmVyc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGFybW9ySW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIsIFUuZ3NhcC5lZmZlY3RzLmNzcUVudGVyU3ViTGVmdChjc3FDb250YWluZXIsIHsgdHlwZTogXCJhcm1vclwiIH0pKTtcbiAgICAgICAgICAgICAgICBhcm1vckludGVyYWN0aW9uUGFkJC5vbih7XG4gICAgICAgICAgICAgICAgICAgIG1vdXNlZW50ZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJtb3JJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIikucGxheSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBtb3VzZWxlYXZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaWNvbkNvbnRhaW5lciQuZGF0YShcImlzVG9nZ2xlZFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFybW9ySW50ZXJhY3Rpb25QYWQkLmRhdGEoXCJob3ZlclRpbWVsaW5lXCIpLnJldmVyc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHNwZWNpYWxJbnRlcmFjdGlvblBhZCQuZGF0YShcImhvdmVyVGltZWxpbmVcIiwgVS5nc2FwLmVmZmVjdHMuY3NxRW50ZXJTdWJMZWZ0KGNzcUNvbnRhaW5lciwgeyB0eXBlOiBcInNwZWNpYWxcIiB9KSk7XG4gICAgICAgICAgICAgICAgc3BlY2lhbEludGVyYWN0aW9uUGFkJC5vbih7XG4gICAgICAgICAgICAgICAgICAgIG1vdXNlZW50ZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2lhbEludGVyYWN0aW9uUGFkJC5kYXRhKFwiaG92ZXJUaW1lbGluZVwiKS5wbGF5KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIG1vdXNlbGVhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpY29uQ29udGFpbmVyJC5kYXRhKFwiaXNUb2dnbGVkXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3BlY2lhbEludGVyYWN0aW9uUGFkJC5kYXRhKFwiaG92ZXJUaW1lbGluZVwiKS5yZXZlcnNlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQ29uc2VxdWVuY2U7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/classes/BladesConsequence.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesDialog.ts": +/*!************************************!*\ + !*** ./ts/classes/BladesDialog.ts ***! + \************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesDialogType: function() { return /* binding */ BladesDialogType; },\n/* harmony export */ SelectionCategory: function() { return /* binding */ SelectionCategory; }\n/* harmony export */ });\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _BladesRoll__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\nvar SelectionCategory;\n(function (SelectionCategory) {\n SelectionCategory[\"Heritage\"] = \"Heritage\";\n SelectionCategory[\"Background\"] = \"Background\";\n SelectionCategory[\"Vice\"] = \"Vice\";\n SelectionCategory[\"Playbook\"] = \"Playbook\";\n SelectionCategory[\"Reputation\"] = \"Reputation\";\n SelectionCategory[\"Preferred_Op\"] = \"Preferred_Op\";\n SelectionCategory[\"Gear\"] = \"Gear\";\n SelectionCategory[\"Ability\"] = \"Ability\";\n SelectionCategory[\"Faction\"] = \"Faction\";\n SelectionCategory[\"Upgrade\"] = \"Upgrade\";\n SelectionCategory[\"Cohort_Gang\"] = \"Cohort_Gang\";\n SelectionCategory[\"Cohort_Expert\"] = \"Cohort_Expert\";\n SelectionCategory[\"Feature\"] = \"Feature\";\n SelectionCategory[\"Stricture\"] = \"Stricture\";\n SelectionCategory[\"VicePurveyor\"] = \"VicePurveyor\";\n SelectionCategory[\"Acquaintance\"] = \"Acquaintance\";\n SelectionCategory[\"Friend\"] = \"Friend\";\n SelectionCategory[\"Rival\"] = \"Rival\";\n SelectionCategory[\"Crew\"] = \"Crew\";\n SelectionCategory[\"Member\"] = \"Member\";\n SelectionCategory[\"Contact\"] = \"Contact\";\n})(SelectionCategory || (SelectionCategory = {}));\nvar BladesDialogType;\n(function (BladesDialogType) {\n BladesDialogType[\"Input\"] = \"Input\";\n BladesDialogType[\"Selection\"] = \"Selection\";\n BladesDialogType[\"Consequence\"] = \"Consequence\";\n})(BladesDialogType || (BladesDialogType = {}));\nclass BladesDialog extends Dialog {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"dialog\"],\n width: \"auto\",\n height: \"auto\",\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"front\" }]\n });\n }\n static Initialize() {\n return loadTemplates([\n \"systems/eunos-blades/templates/dialog-selection.hbs\",\n \"systems/eunos-blades/templates/dialog-consequence.hbs\",\n \"systems/eunos-blades/templates/dialog-input.hbs\",\n \"systems/eunos-blades/templates/parts/dialog-consequence-block.hbs\"\n ]);\n }\n static async DisplaySimpleInputDialog(parent, prompt, target, flagTarget) {\n const app = new BladesDialog({\n parent,\n title: parent instanceof _BladesRoll__WEBPACK_IMPORTED_MODULE_4__[\"default\"] ? \"Roll Input\" : `${parent.name}: Input`,\n dialogType: BladesDialogType.Input,\n content: \"\",\n prompt,\n target,\n flagTarget,\n buttons: {\n apply: {\n icon: '',\n label: \"Apply\",\n callback: (html) => app\n // .writeToRollInstance(html as JQuery)\n },\n cancel: {\n icon: '',\n label: game.i18n.localize(\"Cancel\"),\n callback: (html) => {\n eLog.checkLog3(\"dialog\", \"Callback Scope\", { this: app, html });\n return false;\n }\n }\n },\n default: \"apply\"\n }, { classes: [\"eunos-blades\", \"sheet\", \"dialog\", \"simple-input-dialog\"] });\n return app._render(true, { width: app.width }).then(() => eLog.checkLog3(\"dialog\", \"Input Dialog Instance\", { this: app }));\n }\n static async DisplaySelectionDialog(parent, title, docType, tabs, tags) {\n const app = new BladesDialog({\n parent,\n title,\n docType,\n tabs,\n tags: tags?.filter((tag) => tag !== \"\"),\n content: \"\",\n buttons: {\n cancel: {\n icon: '',\n label: game.i18n.localize(\"Cancel\"),\n callback: (html) => {\n eLog.checkLog3(\"dialog\", \"Callback Scope\", { this: this, html });\n return false;\n }\n }\n },\n default: \"cancel\"\n });\n return app.hasItems ? app.render(true, { width: app.width }) : undefined;\n }\n // static async DisplayRollConsequenceDialog(rollInst: BladesRoll) {\n // const app: BladesDialog = new BladesDialog({\n // parent: rollInst,\n // title: \"Consequences\",\n // dialogType: BladesDialogType.Consequence,\n // content: \"\",\n // buttons: {\n // apply: {\n // icon: '',\n // label: \"Apply\",\n // callback: (html: HTMLElement|JQuery) => (app as BladesDialog)\n // .writeToRollInstance(html as JQuery)\n // },\n // cancel: {\n // icon: '',\n // label: game.i18n.localize(\"Cancel\"),\n // callback: (html: JQuery|HTMLElement) => {\n // eLog.checkLog3(\"dialog\", \"Callback Scope\", {this: app, html});\n // return false;\n // }\n // }\n // },\n // default: \"apply\"\n // }, {classes: [\"eunos-blades\", \"sheet\", \"dialog\", \"consequence-dialog\"]});\n // return app._render(true, {width: app.width}).then(() => eLog.checkLog3(\"dialog\", \"Dialog Instance\", {this: app}));\n // }\n get template() { return `systems/eunos-blades/templates/dialog-${_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].lCase(this.dialogType)}.hbs`; }\n get hasItems() {\n return Object.values(this.tabs ?? []).some((tabItems) => tabItems.length > 0);\n }\n parent;\n tabs;\n dialogType;\n tags = [];\n width;\n docType;\n // csqData?: Record<\n // Position,\n // Record<\n // RollResult.partial|RollResult.fail,\n // Record<\n // string,\n // BladesRoll.ConsequenceData\n // >\n // >\n // >;\n prompt;\n target;\n flagTarget;\n constructor(data, options) {\n super(data, options);\n this.dialogType = data.dialogType ?? BladesDialogType.Selection;\n this.parent = data.parent;\n this.width = options?.width ?? 500;\n this.prompt = data.prompt;\n this.target = data.target;\n this.flagTarget = data.flagTarget;\n switch (this.dialogType) {\n case BladesDialogType.Input: return;\n case BladesDialogType.Selection:\n this.constructSelectionData(data /* , options */);\n return;\n // case BladesDialogType.Consequence: this.csqData = this.constructConsequenceData(data/* , options */); return;\n default: throw new Error(`Unrecognized type for BladesDialog constructor: '${this.dialogType}'`);\n }\n }\n constructSelectionData(data /* , options?: Partial */) {\n const validTabs = [];\n if (!data.tabs) {\n return;\n }\n for (const [tabName, tabItems] of Object.entries(data.tabs)) {\n if (tabItems.length === 0) {\n delete data.tabs[tabName];\n }\n else {\n validTabs.push(tabName);\n }\n }\n if (validTabs.length === 1 && !(\"Main\" in data.tabs)) {\n data.tabs.Main = [...data.tabs[validTabs[0]]];\n delete data.tabs[validTabs[0]];\n }\n this.docType = data.docType;\n this.tabs = data.tabs;\n this.tags = data.tags ?? [];\n this.width = 150 * Math.ceil(Math.sqrt(Object.values(data.tabs)[0].length));\n }\n // constructConsequenceData(data: BladesDialog.Data/* , options?: Partial */) {\n // eLog.checkLog3(\"dialog\", \"constructConsequenceData\", {incoming: {...data}});\n // if (!(this.parent instanceof BladesRoll)) { throw new Error(\"Cannot call 'constructConsequenceData' without a rollInst parent!\"); }\n // // Get existing consequence data, if any, on roll instance\n // const rollCsqData = this.parent.data.consequenceData ?? {};\n // // Extend consequence data by applying new blank consequence instances,\n // // so at least three csq entries are available for each position/result combination\n // (Object.values(Position) as Position[]).forEach((rollPos: Position) => {\n // rollCsqData[rollPos] ??= {\n // [RollResult.partial]: {},\n // [RollResult.fail]: {}\n // };\n // ([RollResult.partial, RollResult.fail] as const).forEach((rollResult: RollResult.partial|RollResult.fail) => {\n // rollCsqData[rollPos] ??= {};\n // rollCsqData[rollPos][rollResult] ??= {};\n // while (Object.values(rollCsqData[rollPos][rollResult as RollResult.partial|RollResult.fail]).length < 3) {\n // const blankCsqData: BladesConsequence.Data = {\n // id: randomID() as IDString,\n // name: \"\",\n // type: \"\",\n // attribute: \"\"\n // };\n // rollCsqData[rollPos][rollResult as RollResult.partial|RollResult.fail][blankCsqData.id] = blankCsqData;\n // }\n // });\n // });\n // this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster);\n // return rollCsqData;\n // }\n getData() {\n const data = super.getData();\n switch (this.dialogType) {\n case BladesDialogType.Input: return this.prepareInputData(data);\n case BladesDialogType.Selection: return this.prepareSelectionData(data);\n // case BladesDialogType.Consequence: return this.prepareConsequenceData(data);\n default: return null;\n }\n }\n prepareInputData(data) {\n data.prompt = this.prompt;\n data.target = this.target;\n data.flagTarget = this.flagTarget;\n return data;\n }\n prepareSelectionData(data) {\n data.title = this.title;\n data.tabs = this.tabs;\n data.docType = this.docType;\n data.tags = this.tags;\n return data;\n }\n // prepareConsequenceData(data: BladesDialog.Data) {\n // eLog.checkLog3(\"dialog\", \"prepareConsequenceData this.csqData\", {...this.csqData});\n // eLog.checkLog3(\"dialog\", \"prepareConsequenceData\", {incoming: {...data}});\n // data.consequenceData = this.csqData;\n // data.consequenceTypeOptions = this.consequenceTypeOptions;\n // data.consequenceTypeOptionsAll = Object.keys(C.ConsequenceDisplay)\n // .map((cType) => ({value: cType, display: cType}));\n // data.consequenceAttributeOptions = [\n // {value: AttributeTrait.insight, display: \"Insight\"},\n // {value: AttributeTrait.prowess, display: \"Prowess\"},\n // {value: AttributeTrait.resolve, display: \"Resolve\"}\n // ];\n // eLog.checkLog3(\"dialog\", \"prepareConsequenceData\", {outgoing: {...data}});\n // return data;\n // }\n // get consequenceTypeOptions(): Record<\n // Position,\n // Record<\n // RollResult.partial|RollResult.fail,\n // Array>\n // >\n // > {\n // if (this.parent instanceof BladesRoll) {\n // const returnData: Partial>\n // >\n // >> = {};\n // [Position.controlled, Position.risky, Position.desperate].forEach((pos) => {\n // returnData[pos] = {\n // [RollResult.partial]: C.Consequences[pos][RollResult.partial]\n // .map((cType) => ({value: cType, display: cType})),\n // [RollResult.fail]: C.Consequences[pos][RollResult.fail]\n // .map((cType) => ({value: cType, display: cType}))\n // };\n // });\n // return returnData as Record<\n // Position,\n // Record<\n // RollResult.partial|RollResult.fail,\n // Array>\n // >\n // >;\n // }\n // return {} as never;\n // }\n updateInputText(inputElem$) {\n const value = inputElem$.val();\n if (this.parent instanceof _BladesRoll__WEBPACK_IMPORTED_MODULE_4__[\"default\"]) {\n const flagTarget = inputElem$.data(\"flagTarget\");\n eLog.checkLog3(\"dialog\", \"updateInputText\", { value, flagTarget });\n this.parent.updateTarget(flagTarget, value)\n .then(() => this.parent.renderRollCollab_SocketCall());\n }\n else if (this.parent instanceof _BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"] || this.parent instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor) {\n this.parent.update({ [inputElem$.data(\"target\")]: inputElem$.val() });\n }\n }\n // updateConsequenceType(csqElem$: JQuery, cData: BladesConsequence.Data) {\n // const type$ = csqElem$.find(\".roll-consequence-type-select\") as JQuery;\n // const typeVal = type$.val() as string|undefined;\n // if (typeVal && typeVal in ConsequenceType) {\n // cData.type = typeVal as ConsequenceType;\n // cData.icon = C.ConsequenceIcons[cData.type];\n // cData.typeDisplay = C.ConsequenceDisplay[cData.type];\n // }\n // }\n // updateConsequenceAttribute(csqElem$: JQuery, cData: BladesConsequence.Data) {\n // if (/Insight/.exec(cData.type)) { cData.attribute = AttributeTrait.insight; }\n // else if (/Prowess/.exec(cData.type)) { cData.attribute = AttributeTrait.prowess; }\n // else if (/Resolve/.exec(cData.type)) { cData.attribute = AttributeTrait.resolve; }\n // else {\n // const attribute$ = csqElem$.find(\".roll-consequence-attribute-select\") as JQuery;\n // const attrVal = attribute$.val() as AttributeTrait|undefined;\n // if (attrVal) {\n // cData.attribute = attrVal;\n // }\n // }\n // }\n // updateConsequenceAttributeVal(cData: BladesConsequence.Data) {\n // if (this.parent.rollPrimaryDoc instanceof BladesPC) {\n // cData.attributeVal = this.parent.rollPrimaryDoc.attributes[cData.attribute as AttributeTrait];\n // } else if (this.parent.rollPrimaryDoc?.parent instanceof BladesPC) {\n // cData.attributeVal = this.parent.rollPrimaryDoc.parent.attributes[cData.attribute as AttributeTrait];\n // } else {\n // eLog.error(`Unable to get attribute from rollPrimaryDoc '${this.parent.rollPrimaryDoc?.name}' of type '${this.parent.rollPrimaryDoc?.rollPrimaryType}' (may need to log via flags if either of the previous show 'undefined'.`);\n // }\n // }\n // getSelectedResistOption(cData: BladesConsequence.Data): BladesConsequence|false {\n // return cData.resistTo\n // ? new BladesConsequence(cData.resistTo)\n // : false;\n // }\n // updateConsequenceResist(csqElem$: JQuery, cData: BladesConsequence.Data) {\n // const resistOptions: Record = cData.resistOptions ?? {};\n // // If consequence is already minimal, toggle resistNegates to true and set 'resistTo' to None-type\n // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes)\n // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None)\n // .map(([csqType]) => csqType as ConsequenceType);\n // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) {\n // cData.resistNegates = true;\n // const noneCsq = BladesConsequence.None;\n // cData.resistOptions = {[noneCsq.id]: noneCsq};\n // cData.resistTo = noneCsq;\n // return;\n // } else {\n // // Clear 'resistTo' (will be redetermined below)\n // delete cData.resistTo;\n // delete cData.resistNegates;\n // csqElem$.find(\".consequence-resist-option\").each((_, elem) => {\n // const resCsqID = $(elem).data(\"csq-id\");\n // resistOptions[resCsqID] ??= {id: resCsqID, name: \"\", type: undefined, isSelected: false};\n // // Update Resistance Option Type\n // const resType$ = $(elem).find(\".roll-consequence-type-select\") as JQuery;\n // const resTypeVal = resType$.val() as string|undefined;\n // if (resTypeVal && resTypeVal in ConsequenceType) {\n // resistOptions[resCsqID].type = resTypeVal as ConsequenceType;\n // resistOptions[resCsqID].icon = C.ConsequenceIcons[resistOptions[resCsqID].type as ConsequenceType];\n // resistOptions[resCsqID].typeDisplay = C.ConsequenceDisplay[resistOptions[resCsqID].type as ConsequenceType];\n // }\n // // Update Resistance Option Name\n // const resName$ = $(elem).find(\".consequence-name\") as JQuery;\n // const resNameVal = resName$.val();\n // resistOptions[resCsqID].name = resNameVal ?? \"\";\n // // If this is selected, update 'resistTo' data as well\n // if (resistOptions[resCsqID].isSelected) {\n // cData.resistTo = resistOptions[resCsqID];\n // }\n // });\n // }\n // cData.resistOptions = resistOptions;\n // }\n // updateConsequenceArmorResist(_csqElem$: JQuery, cData: BladesConsequence.Data) {\n // // If consequence is already minimal, toggle armorNegates to true and set 'armorTo' to None-type\n // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes)\n // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None)\n // .map(([csqType]) => csqType as ConsequenceType);\n // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) {\n // cData.armorNegates = true;\n // cData.armorTo = BladesConsequence.None;\n // } else {\n // delete cData.armorNegates;\n // cData.armorTo = this.getSelectedResistOption(cData);\n // }\n // }\n // updateConsequenceSpecialArmorResist(_csqElem$: JQuery, cData: BladesConsequence.Data) {\n // // If consequence is already minimal, toggle specialArmorNegates to true and set 'specialTo' to None-type\n // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes)\n // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None)\n // .map(([csqType]) => csqType as ConsequenceType);\n // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) {\n // cData.specialArmorNegates = true;\n // cData.specialTo = BladesConsequence.None;\n // } else {\n // delete cData.specialArmorNegates;\n // cData.specialArmorNegates ??= false;\n // cData.specialTo = this.getSelectedResistOption(cData);\n // }\n // }\n // updateConsequenceData(\n // html: JQuery,\n // cData: BladesConsequence.Data\n // ) {\n // const csqElem$ = html.find(`.roll-consequence-row[data-csq-id='${cData.id}']`);\n // // Update Type\n // this.updateConsequenceType(csqElem$, cData);\n // // Update Name\n // if (cData.type === ConsequenceType.None) {\n // cData.name = \"\";\n // } else {\n // const name$ = csqElem$.find(\".consequence-name\") as JQuery;\n // const nameVal = name$.val();\n // cData.name = nameVal ?? \"\";\n // }\n // // Update Resistance Attribute\n // this.updateConsequenceAttribute(csqElem$, cData);\n // this.updateConsequenceAttributeVal(cData);\n // // Update Resistance Options\n // this.updateConsequenceResist(csqElem$, cData);\n // // Update Armor Options\n // if (( this.parent).canResistWithArmor(cData)) {\n // cData.isDisplayingArmorToggle = true;\n // this.updateConsequenceArmorResist(csqElem$, cData);\n // } else {\n // cData.isDisplayingArmorToggle = false;\n // }\n // // Update Special Armor Options\n // if (( this.parent).canResistWithSpecialArmor(cData)) {\n // cData.isDisplayingSpecialArmorToggle = true;\n // this.updateConsequenceSpecialArmorResist(csqElem$, cData);\n // } else {\n // cData.isDisplayingSpecialArmorToggle = false;\n // }\n // return cData;\n // }\n // updateConsequenceDialog(html: JQuery, isRendering = true) {\n // if (!(this.parent instanceof BladesRoll)) { return; }\n // if (!this.csqData) { return; }\n // eLog.checkLog3(\"dialog\", \"updateConsequenceDialog() this.csqData INCOMING\", {...this.csqData});\n // const {csqData} = this;\n // const {rollPrimaryDoc} = this.parent;\n // if (!(rollPrimaryDoc instanceof BladesPC)) { return; }\n // (Object.keys(csqData) as Position[]).forEach((rollPos) => {\n // const positionCsqData = csqData[rollPos];\n // (Object.keys(csqData[rollPos]) as [RollResult.partial, RollResult.fail]).forEach((rollResult) => {\n // positionCsqData[rollResult] = U.objMap(\n // positionCsqData[rollResult],\n // (cData: BladesConsequence.Data) => this.updateConsequenceData(html, cData)\n // );\n // });\n // csqData[rollPos] = positionCsqData;\n // });\n // this.csqData = csqData;\n // eLog.checkLog3(\"dialog\", \"updateConsequenceDialog() this.csqData OUTGOING\", {...this.csqData});\n // if (isRendering) {\n // this.render();\n // }\n // }\n // async writeToRollInstance(html: JQuery) {\n // if (this.parent instanceof BladesRoll) {\n // this.updateConsequenceDialog(html, false);\n // await this.parent.updateTarget(\"consequenceData\", this.csqData);\n // }\n // }\n // _consequenceAI?: BladesAI;\n // getCsqDataFromElem(elem: HTMLElement, paramCount = 3): string[] {\n // const dataAction = elem.dataset.action;\n // if (dataAction) {\n // const params = dataAction.split(/-/).reverse().slice(0, paramCount);\n // return params.reverse();\n // }\n // return [];\n // }\n // async queryAI(event: ClickEvent) {\n // if (!this.csqData) { return; }\n // // If the AI generator has not been initialized, do so.\n // if (!this._consequenceAI) {\n // this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster);\n // }\n // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget);\n // const csqName: string|undefined =\n // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]?.name;\n // if (csqName) {\n // const response = await this._consequenceAI?.query(csqName, csqName);\n // if (response) {\n // this.refreshResistanceOptions(rollPosition as Position, rollResult as RollResult.partial|RollResult.fail, csqID, response.split(\"|\"));\n // }\n // }\n // }\n // async spawnBlankResistOption(event: ClickEvent) {\n // if (!this.csqData) { return; }\n // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget);\n // const rCsqID = randomID() as IDString;\n // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]\n // .resistOptions = {\n // [rCsqID]: {\n // id: rCsqID,\n // name: \"\",\n // type: undefined,\n // isSelected: true\n // }\n // };\n // this.render();\n // }\n // async setFlagVal(target: string, value: unknown) {\n // if (this.parent instanceof BladesRoll) {\n // await this.parent.updateTarget(target, value);\n // }\n // }\n // async refreshResistanceOptions(rollPosition: Position, rollResult: RollResult, cID: string, rOptions: string[]) {\n // if (!this.csqData) { return; }\n // const cData = this.csqData[rollPosition][rollResult as RollResult.partial|RollResult.fail][cID];\n // if (!cData) { return; }\n // const cType = cData.type as keyof typeof C[\"ResistedConsequenceTypes\"];\n // const rType = C.ResistedConsequenceTypes[cType] ?? undefined;\n // const resistOptions: Record = {};\n // for (let i = 0; i < rOptions.length; i++) {\n // const rID = randomID() as IDString;\n // resistOptions[rID] = {\n // id: rID,\n // name: rOptions[i],\n // isSelected: false\n // };\n // if (rType) {\n // resistOptions[rID].type = rType;\n // resistOptions[rID].typeDisplay = C.ConsequenceDisplay[rType];\n // resistOptions[rID].icon = C.ConsequenceIcons[rType];\n // }\n // }\n // this.csqData[rollPosition][rollResult as RollResult.partial|RollResult.fail][cID].resistOptions = resistOptions;\n // eLog.checkLog3(\"dialog\", \"addResistanceOptions() this.csqData\", {...this.csqData});\n // this.render();\n // }\n // async selectResistOption(event: ClickEvent) {\n // if (!this.csqData) { return; }\n // const [rollPosition, rollResult, csqID, resID] = this.getCsqDataFromElem(event.currentTarget, 4);\n // eLog.checkLog3(\"dialog\", \"... Action Passed\", {rollResult, csqIndex: csqID, resIndex: resID});\n // // Get consequence data\n // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID];\n // cData.resistOptions ??= {};\n // // Toggle clicked resistance option\n // cData.resistOptions[resID].isSelected = !cData.resistOptions[resID].isSelected;\n // // If resistance option is now selected...\n // if (cData.resistOptions[resID].isSelected) {\n // // ... deselect & hide other options\n // Object.keys(cData.resistOptions)\n // .filter((key) => key !== resID)\n // .forEach((key) => {\n // Object.assign(cData.resistOptions?.[key] ?? {}, {isSelected: false, isVisible: false});\n // });\n // // ... and set 'resistTo' to this consequence.\n // cData.resistTo = cData.resistOptions[resID];\n // } else {\n // // Otherwise, set 'resistTo' to false...\n // cData.resistTo = false;\n // // ... and unhide other options.\n // Object.keys(cData.resistOptions)\n // .filter((key) => key !== resID)\n // .forEach((key) => {\n // Object.assign(cData.resistOptions?.[key] ?? {}, {isVisible: true});\n // });\n // }\n // // Assign new cData instance.\n // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID] = cData;\n // this.render();\n // }\n // async clearResistOptions(event: ContextMenuEvent) {\n // if (!this.csqData) { return; }\n // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget);\n // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID].resistOptions = {};\n // this.render();\n // }\n // async toggleArmor(event: ClickEvent) {\n // if (!this.csqData) { return; }\n // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget);\n // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID];\n // cData.canArmor = !cData.canArmor;\n // this.render();\n // }\n // async toggleSpecialArmor(event: ClickEvent) {\n // if (!this.csqData) { return; }\n // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget);\n // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID];\n // cData.canSpecialArmor = !cData.canSpecialArmor;\n // this.render();\n // }\n activateListeners(html) {\n super.activateListeners(html);\n // ~ Tooltips\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_0__.ApplyTooltipAnimations)(html);\n switch (this.dialogType) {\n case BladesDialogType.Input:\n this.activateInputListeners(html);\n break;\n case BladesDialogType.Selection:\n this.activateSelectionListeners(html);\n break;\n // case BladesDialogType.Consequence: {\n // this.activateConsequenceListeners(html);\n // Select --> updateConsequenceDialog -> updateConsequenceData(each csq)\n // break;\n // }\n }\n }\n activateInputListeners(html) {\n html.find(\"textarea\").on({ change: (event) => this.updateInputText($(event.currentTarget)) });\n }\n activateSelectionListeners(html) {\n const self = this;\n // ~ Changing Width on Tab Change Depending on Number of Items\n html.find(\".nav-tabs .tab-selector\").on(\"click\", (event) => {\n const tabIndex = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(event.currentTarget).data(\"tab\"));\n const numItems = Object.values(self.tabs ?? [])[tabIndex].length;\n const width = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(150 * Math.ceil(Math.sqrt(numItems)));\n eLog.checkLog3(\"nav\", \"Nav Tab Size Recalculation\", { tabIndex, numItems, width });\n this.render(false, { width });\n });\n // ~ Item Control\n html.find(\"[data-item-id]\").on(\"click\", function () {\n if ($(this).parent().hasClass(\"locked\")) {\n return;\n }\n const docId = $(this).data(\"itemId\");\n const docType = $(this).data(\"docType\");\n eLog.checkLog(\"dialog\", \"[BladesDialog] on Click\", { elem: this, docId, docType, parent: self.parent });\n if (self.parent instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor) {\n if (docType === \"Actor\") {\n self.parent.addSubActor(docId, self.tags);\n }\n else if (docType === \"Item\") {\n self.parent.addSubItem(docId);\n }\n }\n self.close();\n });\n }\n async close() {\n $(\"#eunos-blades-tooltips > *\").remove();\n super.close();\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesDialog);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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MUY7QUFDQTtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0Esd0RBQXdELDZDQUE2QztBQUNyRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkRBQTZELEdBQUcsb0NBQW9DO0FBQ3BHLGNBQWM7QUFDZDtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZEQUE2RCxHQUFHLGdCQUFnQjtBQUNoRixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLGtFQUFzQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsaUVBQWlFO0FBQ3BHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkIsdURBQUM7QUFDOUI7QUFDQSwwQkFBMEIsdURBQUM7QUFDM0Isa0VBQWtFLDJCQUEyQjtBQUM3RixpQ0FBaUMsT0FBTztBQUN4QyxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpRUFBaUUsaURBQWlEO0FBQ2xILHVDQUF1QyxvRUFBVztBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUFlLFlBQVksRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NsYXNzZXMvQmxhZGVzRGlhbG9nLnRzP2Q1MzkiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgeyBBcHBseVRvb2x0aXBBbmltYXRpb25zIH0gZnJvbSBcIi4uL2NvcmUvZ3NhcFwiO1xuaW1wb3J0IFUgZnJvbSBcIi4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBCbGFkZXNBY3RvciB9IGZyb20gXCIuLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuaW1wb3J0IEJsYWRlc0l0ZW0gZnJvbSBcIi4uL0JsYWRlc0l0ZW1cIjtcbmltcG9ydCBCbGFkZXNSb2xsIGZyb20gXCIuL0JsYWRlc1JvbGxcIjtcbmV4cG9ydCB2YXIgU2VsZWN0aW9uQ2F0ZWdvcnk7XG4oZnVuY3Rpb24gKFNlbGVjdGlvbkNhdGVnb3J5KSB7XG4gICAgU2VsZWN0aW9uQ2F0ZWdvcnlbXCJIZXJpdGFnZVwiXSA9IFwiSGVyaXRhZ2VcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkJhY2tncm91bmRcIl0gPSBcIkJhY2tncm91bmRcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIlZpY2VcIl0gPSBcIlZpY2VcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIlBsYXlib29rXCJdID0gXCJQbGF5Ym9va1wiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiUmVwdXRhdGlvblwiXSA9IFwiUmVwdXRhdGlvblwiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiUHJlZmVycmVkX09wXCJdID0gXCJQcmVmZXJyZWRfT3BcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkdlYXJcIl0gPSBcIkdlYXJcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkFiaWxpdHlcIl0gPSBcIkFiaWxpdHlcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkZhY3Rpb25cIl0gPSBcIkZhY3Rpb25cIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIlVwZ3JhZGVcIl0gPSBcIlVwZ3JhZGVcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkNvaG9ydF9HYW5nXCJdID0gXCJDb2hvcnRfR2FuZ1wiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiQ29ob3J0X0V4cGVydFwiXSA9IFwiQ29ob3J0X0V4cGVydFwiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiRmVhdHVyZVwiXSA9IFwiRmVhdHVyZVwiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiU3RyaWN0dXJlXCJdID0gXCJTdHJpY3R1cmVcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIlZpY2VQdXJ2ZXlvclwiXSA9IFwiVmljZVB1cnZleW9yXCI7XG4gICAgU2VsZWN0aW9uQ2F0ZWdvcnlbXCJBY3F1YWludGFuY2VcIl0gPSBcIkFjcXVhaW50YW5jZVwiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiRnJpZW5kXCJdID0gXCJGcmllbmRcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIlJpdmFsXCJdID0gXCJSaXZhbFwiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiQ3Jld1wiXSA9IFwiQ3Jld1wiO1xuICAgIFNlbGVjdGlvbkNhdGVnb3J5W1wiTWVtYmVyXCJdID0gXCJNZW1iZXJcIjtcbiAgICBTZWxlY3Rpb25DYXRlZ29yeVtcIkNvbnRhY3RcIl0gPSBcIkNvbnRhY3RcIjtcbn0pKFNlbGVjdGlvbkNhdGVnb3J5IHx8IChTZWxlY3Rpb25DYXRlZ29yeSA9IHt9KSk7XG5leHBvcnQgdmFyIEJsYWRlc0RpYWxvZ1R5cGU7XG4oZnVuY3Rpb24gKEJsYWRlc0RpYWxvZ1R5cGUpIHtcbiAgICBCbGFkZXNEaWFsb2dUeXBlW1wiSW5wdXRcIl0gPSBcIklucHV0XCI7XG4gICAgQmxhZGVzRGlhbG9nVHlwZVtcIlNlbGVjdGlvblwiXSA9IFwiU2VsZWN0aW9uXCI7XG4gICAgQmxhZGVzRGlhbG9nVHlwZVtcIkNvbnNlcXVlbmNlXCJdID0gXCJDb25zZXF1ZW5jZVwiO1xufSkoQmxhZGVzRGlhbG9nVHlwZSB8fCAoQmxhZGVzRGlhbG9nVHlwZSA9IHt9KSk7XG5jbGFzcyBCbGFkZXNEaWFsb2cgZXh0ZW5kcyBEaWFsb2cge1xuICAgIHN0YXRpYyBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBmb3VuZHJ5LnV0aWxzLm1lcmdlT2JqZWN0KHN1cGVyLmRlZmF1bHRPcHRpb25zLCB7XG4gICAgICAgICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcImRpYWxvZ1wiXSxcbiAgICAgICAgICAgIHdpZHRoOiBcImF1dG9cIixcbiAgICAgICAgICAgIGhlaWdodDogXCJhdXRvXCIsXG4gICAgICAgICAgICB0YWJzOiBbeyBuYXZTZWxlY3RvcjogXCIubmF2LXRhYnNcIiwgY29udGVudFNlbGVjdG9yOiBcIi50YWItY29udGVudFwiLCBpbml0aWFsOiBcImZyb250XCIgfV1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN0YXRpYyBJbml0aWFsaXplKCkge1xuICAgICAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyhbXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9kaWFsb2ctc2VsZWN0aW9uLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvZGlhbG9nLWNvbnNlcXVlbmNlLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvZGlhbG9nLWlucHV0Lmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcGFydHMvZGlhbG9nLWNvbnNlcXVlbmNlLWJsb2NrLmhic1wiXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICBzdGF0aWMgYXN5bmMgRGlzcGxheVNpbXBsZUlucHV0RGlhbG9nKHBhcmVudCwgcHJvbXB0LCB0YXJnZXQsIGZsYWdUYXJnZXQpIHtcbiAgICAgICAgY29uc3QgYXBwID0gbmV3IEJsYWRlc0RpYWxvZyh7XG4gICAgICAgICAgICBwYXJlbnQsXG4gICAgICAgICAgICB0aXRsZTogcGFyZW50IGluc3RhbmNlb2YgQmxhZGVzUm9sbCA/IFwiUm9sbCBJbnB1dFwiIDogYCR7cGFyZW50Lm5hbWV9OiBJbnB1dGAsXG4gICAgICAgICAgICBkaWFsb2dUeXBlOiBCbGFkZXNEaWFsb2dUeXBlLklucHV0LFxuICAgICAgICAgICAgY29udGVudDogXCJcIixcbiAgICAgICAgICAgIHByb21wdCxcbiAgICAgICAgICAgIHRhcmdldCxcbiAgICAgICAgICAgIGZsYWdUYXJnZXQsXG4gICAgICAgICAgICBidXR0b25zOiB7XG4gICAgICAgICAgICAgICAgYXBwbHk6IHtcbiAgICAgICAgICAgICAgICAgICAgaWNvbjogJzxpIGNsYXNzPVwiZmEtc29saWQgZmEtYXJyb3ctZG93bi10by1hcmNcIj48L2k+JyxcbiAgICAgICAgICAgICAgICAgICAgbGFiZWw6IFwiQXBwbHlcIixcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2s6IChodG1sKSA9PiBhcHBcbiAgICAgICAgICAgICAgICAgICAgLy8gICAud3JpdGVUb1JvbGxJbnN0YW5jZShodG1sIGFzIEpRdWVyeTxIVE1MRWxlbWVudD4pXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBjYW5jZWw6IHtcbiAgICAgICAgICAgICAgICAgICAgaWNvbjogJzxpIGNsYXNzPVwiZmFzIGZhLXRpbWVzXCI+PC9pPicsXG4gICAgICAgICAgICAgICAgICAgIGxhYmVsOiBnYW1lLmkxOG4ubG9jYWxpemUoXCJDYW5jZWxcIiksXG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrOiAoaHRtbCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJkaWFsb2dcIiwgXCJDYWxsYmFjayBTY29wZVwiLCB7IHRoaXM6IGFwcCwgaHRtbCB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkZWZhdWx0OiBcImFwcGx5XCJcbiAgICAgICAgfSwgeyBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcImRpYWxvZ1wiLCBcInNpbXBsZS1pbnB1dC1kaWFsb2dcIl0gfSk7XG4gICAgICAgIHJldHVybiBhcHAuX3JlbmRlcih0cnVlLCB7IHdpZHRoOiBhcHAud2lkdGggfSkudGhlbigoKSA9PiBlTG9nLmNoZWNrTG9nMyhcImRpYWxvZ1wiLCBcIklucHV0IERpYWxvZyBJbnN0YW5jZVwiLCB7IHRoaXM6IGFwcCB9KSk7XG4gICAgfVxuICAgIHN0YXRpYyBhc3luYyBEaXNwbGF5U2VsZWN0aW9uRGlhbG9nKHBhcmVudCwgdGl0bGUsIGRvY1R5cGUsIHRhYnMsIHRhZ3MpIHtcbiAgICAgICAgY29uc3QgYXBwID0gbmV3IEJsYWRlc0RpYWxvZyh7XG4gICAgICAgICAgICBwYXJlbnQsXG4gICAgICAgICAgICB0aXRsZSxcbiAgICAgICAgICAgIGRvY1R5cGUsXG4gICAgICAgICAgICB0YWJzLFxuICAgICAgICAgICAgdGFnczogdGFncz8uZmlsdGVyKCh0YWcpID0+IHRhZyAhPT0gXCJcIiksXG4gICAgICAgICAgICBjb250ZW50OiBcIlwiLFxuICAgICAgICAgICAgYnV0dG9uczoge1xuICAgICAgICAgICAgICAgIGNhbmNlbDoge1xuICAgICAgICAgICAgICAgICAgICBpY29uOiAnPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+JyxcbiAgICAgICAgICAgICAgICAgICAgbGFiZWw6IGdhbWUuaTE4bi5sb2NhbGl6ZShcIkNhbmNlbFwiKSxcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2s6IChodG1sKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImRpYWxvZ1wiLCBcIkNhbGxiYWNrIFNjb3BlXCIsIHsgdGhpczogdGhpcywgaHRtbCB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkZWZhdWx0OiBcImNhbmNlbFwiXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gYXBwLmhhc0l0ZW1zID8gYXBwLnJlbmRlcih0cnVlLCB7IHdpZHRoOiBhcHAud2lkdGggfSkgOiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIC8vIHN0YXRpYyBhc3luYyBEaXNwbGF5Um9sbENvbnNlcXVlbmNlRGlhbG9nKHJvbGxJbnN0OiBCbGFkZXNSb2xsKSB7XG4gICAgLy8gY29uc3QgYXBwOiBCbGFkZXNEaWFsb2cgPSBuZXcgQmxhZGVzRGlhbG9nKHtcbiAgICAvLyAgIHBhcmVudDogcm9sbEluc3QsXG4gICAgLy8gICB0aXRsZTogXCJDb25zZXF1ZW5jZXNcIixcbiAgICAvLyAgIGRpYWxvZ1R5cGU6IEJsYWRlc0RpYWxvZ1R5cGUuQ29uc2VxdWVuY2UsXG4gICAgLy8gICBjb250ZW50OiBcIlwiLFxuICAgIC8vICAgYnV0dG9uczoge1xuICAgIC8vICAgICBhcHBseToge1xuICAgIC8vICAgICAgIGljb246ICc8aSBjbGFzcz1cImZhLXNvbGlkIGZhLWFycm93LWRvd24tdG8tYXJjXCI+PC9pPicsXG4gICAgLy8gICAgICAgbGFiZWw6IFwiQXBwbHlcIixcbiAgICAvLyAgICAgICBjYWxsYmFjazogKGh0bWw6IEhUTUxFbGVtZW50fEpRdWVyeTxIVE1MRWxlbWVudD4pID0+IChhcHAgYXMgQmxhZGVzRGlhbG9nKVxuICAgIC8vICAgICAgICAgLndyaXRlVG9Sb2xsSW5zdGFuY2UoaHRtbCBhcyBKUXVlcnk8SFRNTEVsZW1lbnQ+KVxuICAgIC8vICAgICB9LFxuICAgIC8vICAgICBjYW5jZWw6IHtcbiAgICAvLyAgICAgICBpY29uOiAnPGkgY2xhc3M9XCJmYXMgZmEtdGltZXNcIj48L2k+JyxcbiAgICAvLyAgICAgICBsYWJlbDogZ2FtZS5pMThuLmxvY2FsaXplKFwiQ2FuY2VsXCIpLFxuICAgIC8vICAgICAgIGNhbGxiYWNrOiAoaHRtbDogSlF1ZXJ5fEhUTUxFbGVtZW50KSA9PiB7XG4gICAgLy8gICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImRpYWxvZ1wiLCBcIkNhbGxiYWNrIFNjb3BlXCIsIHt0aGlzOiBhcHAsIGh0bWx9KTtcbiAgICAvLyAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAvLyAgICAgICB9XG4gICAgLy8gICAgIH1cbiAgICAvLyAgIH0sXG4gICAgLy8gICBkZWZhdWx0OiBcImFwcGx5XCJcbiAgICAvLyB9LCB7Y2xhc3NlczogW1wiZXVub3MtYmxhZGVzXCIsIFwic2hlZXRcIiwgXCJkaWFsb2dcIiwgXCJjb25zZXF1ZW5jZS1kaWFsb2dcIl19KTtcbiAgICAvLyByZXR1cm4gYXBwLl9yZW5kZXIodHJ1ZSwge3dpZHRoOiBhcHAud2lkdGh9KS50aGVuKCgpID0+IGVMb2cuY2hlY2tMb2czKFwiZGlhbG9nXCIsIFwiRGlhbG9nIEluc3RhbmNlXCIsIHt0aGlzOiBhcHB9KSk7XG4gICAgLy8gfVxuICAgIGdldCB0ZW1wbGF0ZSgpIHsgcmV0dXJuIGBzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvZGlhbG9nLSR7VS5sQ2FzZSh0aGlzLmRpYWxvZ1R5cGUpfS5oYnNgOyB9XG4gICAgZ2V0IGhhc0l0ZW1zKCkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLnRhYnMgPz8gW10pLnNvbWUoKHRhYkl0ZW1zKSA9PiB0YWJJdGVtcy5sZW5ndGggPiAwKTtcbiAgICB9XG4gICAgcGFyZW50O1xuICAgIHRhYnM7XG4gICAgZGlhbG9nVHlwZTtcbiAgICB0YWdzID0gW107XG4gICAgd2lkdGg7XG4gICAgZG9jVHlwZTtcbiAgICAvLyBjc3FEYXRhPzogUmVjb3JkPFxuICAgIC8vIFBvc2l0aW9uLFxuICAgIC8vIFJlY29yZDxcbiAgICAvLyAgIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWwsXG4gICAgLy8gICBSZWNvcmQ8XG4gICAgLy8gICAgIHN0cmluZyxcbiAgICAvLyAgICAgQmxhZGVzUm9sbC5Db25zZXF1ZW5jZURhdGFcbiAgICAvLyAgICAgPlxuICAgIC8vICAgPlxuICAgIC8vID47XG4gICAgcHJvbXB0O1xuICAgIHRhcmdldDtcbiAgICBmbGFnVGFyZ2V0O1xuICAgIGNvbnN0cnVjdG9yKGRhdGEsIG9wdGlvbnMpIHtcbiAgICAgICAgc3VwZXIoZGF0YSwgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuZGlhbG9nVHlwZSA9IGRhdGEuZGlhbG9nVHlwZSA/PyBCbGFkZXNEaWFsb2dUeXBlLlNlbGVjdGlvbjtcbiAgICAgICAgdGhpcy5wYXJlbnQgPSBkYXRhLnBhcmVudDtcbiAgICAgICAgdGhpcy53aWR0aCA9IG9wdGlvbnM/LndpZHRoID8/IDUwMDtcbiAgICAgICAgdGhpcy5wcm9tcHQgPSBkYXRhLnByb21wdDtcbiAgICAgICAgdGhpcy50YXJnZXQgPSBkYXRhLnRhcmdldDtcbiAgICAgICAgdGhpcy5mbGFnVGFyZ2V0ID0gZGF0YS5mbGFnVGFyZ2V0O1xuICAgICAgICBzd2l0Y2ggKHRoaXMuZGlhbG9nVHlwZSkge1xuICAgICAgICAgICAgY2FzZSBCbGFkZXNEaWFsb2dUeXBlLklucHV0OiByZXR1cm47XG4gICAgICAgICAgICBjYXNlIEJsYWRlc0RpYWxvZ1R5cGUuU2VsZWN0aW9uOlxuICAgICAgICAgICAgICAgIHRoaXMuY29uc3RydWN0U2VsZWN0aW9uRGF0YShkYXRhIC8qICwgb3B0aW9ucyAqLyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgLy8gY2FzZSBCbGFkZXNEaWFsb2dUeXBlLkNvbnNlcXVlbmNlOiB0aGlzLmNzcURhdGEgPSB0aGlzLmNvbnN0cnVjdENvbnNlcXVlbmNlRGF0YShkYXRhLyogLCBvcHRpb25zICovKTsgcmV0dXJuO1xuICAgICAgICAgICAgZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQgdHlwZSBmb3IgQmxhZGVzRGlhbG9nIGNvbnN0cnVjdG9yOiAnJHt0aGlzLmRpYWxvZ1R5cGV9J2ApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0cnVjdFNlbGVjdGlvbkRhdGEoZGF0YSAvKiAsIG9wdGlvbnM/OiBQYXJ0aWFsPEJsYWRlc0RpYWxvZy5PcHRpb25zPiAqLykge1xuICAgICAgICBjb25zdCB2YWxpZFRhYnMgPSBbXTtcbiAgICAgICAgaWYgKCFkYXRhLnRhYnMpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGNvbnN0IFt0YWJOYW1lLCB0YWJJdGVtc10gb2YgT2JqZWN0LmVudHJpZXMoZGF0YS50YWJzKSkge1xuICAgICAgICAgICAgaWYgKHRhYkl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBkYXRhLnRhYnNbdGFiTmFtZV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YWxpZFRhYnMucHVzaCh0YWJOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAodmFsaWRUYWJzLmxlbmd0aCA9PT0gMSAmJiAhKFwiTWFpblwiIGluIGRhdGEudGFicykpIHtcbiAgICAgICAgICAgIGRhdGEudGFicy5NYWluID0gWy4uLmRhdGEudGFic1t2YWxpZFRhYnNbMF1dXTtcbiAgICAgICAgICAgIGRlbGV0ZSBkYXRhLnRhYnNbdmFsaWRUYWJzWzBdXTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmRvY1R5cGUgPSBkYXRhLmRvY1R5cGU7XG4gICAgICAgIHRoaXMudGFicyA9IGRhdGEudGFicztcbiAgICAgICAgdGhpcy50YWdzID0gZGF0YS50YWdzID8/IFtdO1xuICAgICAgICB0aGlzLndpZHRoID0gMTUwICogTWF0aC5jZWlsKE1hdGguc3FydChPYmplY3QudmFsdWVzKGRhdGEudGFicylbMF0ubGVuZ3RoKSk7XG4gICAgfVxuICAgIC8vIGNvbnN0cnVjdENvbnNlcXVlbmNlRGF0YShkYXRhOiBCbGFkZXNEaWFsb2cuRGF0YS8qICwgb3B0aW9ucz86IFBhcnRpYWw8QmxhZGVzRGlhbG9nLk9wdGlvbnM+ICovKSB7XG4gICAgLy8gICBlTG9nLmNoZWNrTG9nMyhcImRpYWxvZ1wiLCBcImNvbnN0cnVjdENvbnNlcXVlbmNlRGF0YVwiLCB7aW5jb21pbmc6IHsuLi5kYXRhfX0pO1xuICAgIC8vICAgaWYgKCEodGhpcy5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNSb2xsKSkgeyB0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY2FsbCAnY29uc3RydWN0Q29uc2VxdWVuY2VEYXRhJyB3aXRob3V0IGEgcm9sbEluc3QgcGFyZW50IVwiKTsgfVxuICAgIC8vICAgLy8gR2V0IGV4aXN0aW5nIGNvbnNlcXVlbmNlIGRhdGEsIGlmIGFueSwgb24gcm9sbCBpbnN0YW5jZVxuICAgIC8vICAgY29uc3Qgcm9sbENzcURhdGEgPSB0aGlzLnBhcmVudC5kYXRhLmNvbnNlcXVlbmNlRGF0YSA/PyB7fTtcbiAgICAvLyAgIC8vIEV4dGVuZCBjb25zZXF1ZW5jZSBkYXRhIGJ5IGFwcGx5aW5nIG5ldyBibGFuayBjb25zZXF1ZW5jZSBpbnN0YW5jZXMsXG4gICAgLy8gICAvLyAgIHNvIGF0IGxlYXN0IHRocmVlIGNzcSBlbnRyaWVzIGFyZSBhdmFpbGFibGUgZm9yIGVhY2ggcG9zaXRpb24vcmVzdWx0IGNvbWJpbmF0aW9uXG4gICAgLy8gICAoT2JqZWN0LnZhbHVlcyhQb3NpdGlvbikgYXMgUG9zaXRpb25bXSkuZm9yRWFjaCgocm9sbFBvczogUG9zaXRpb24pID0+IHtcbiAgICAvLyAgICAgcm9sbENzcURhdGFbcm9sbFBvc10gPz89IHtcbiAgICAvLyAgICAgICBbUm9sbFJlc3VsdC5wYXJ0aWFsXToge30sXG4gICAgLy8gICAgICAgW1JvbGxSZXN1bHQuZmFpbF06IHt9XG4gICAgLy8gICAgIH07XG4gICAgLy8gICAgIChbUm9sbFJlc3VsdC5wYXJ0aWFsLCBSb2xsUmVzdWx0LmZhaWxdIGFzIGNvbnN0KS5mb3JFYWNoKChyb2xsUmVzdWx0OiBSb2xsUmVzdWx0LnBhcnRpYWx8Um9sbFJlc3VsdC5mYWlsKSA9PiB7XG4gICAgLy8gICAgICAgcm9sbENzcURhdGFbcm9sbFBvc10gPz89IHt9O1xuICAgIC8vICAgICAgIHJvbGxDc3FEYXRhW3JvbGxQb3NdW3JvbGxSZXN1bHRdID8/PSB7fTtcbiAgICAvLyAgICAgICB3aGlsZSAoT2JqZWN0LnZhbHVlcyhyb2xsQ3NxRGF0YVtyb2xsUG9zXVtyb2xsUmVzdWx0IGFzIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWxdKS5sZW5ndGggPCAzKSB7XG4gICAgLy8gICAgICAgICBjb25zdCBibGFua0NzcURhdGE6IEJsYWRlc0NvbnNlcXVlbmNlLkRhdGEgPSB7XG4gICAgLy8gICAgICAgICAgIGlkOiByYW5kb21JRCgpIGFzIElEU3RyaW5nLFxuICAgIC8vICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgIC8vICAgICAgICAgICB0eXBlOiBcIlwiLFxuICAgIC8vICAgICAgICAgICBhdHRyaWJ1dGU6IFwiXCJcbiAgICAvLyAgICAgICAgIH07XG4gICAgLy8gICAgICAgICByb2xsQ3NxRGF0YVtyb2xsUG9zXVtyb2xsUmVzdWx0IGFzIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWxdW2JsYW5rQ3NxRGF0YS5pZF0gPSBibGFua0NzcURhdGE7XG4gICAgLy8gICAgICAgfVxuICAgIC8vICAgICB9KTtcbiAgICAvLyAgIH0pO1xuICAgIC8vICAgdGhpcy5fY29uc2VxdWVuY2VBSSA9IG5ldyBCbGFkZXNBSShBR0VOVFMuQ29uc2VxdWVuY2VBZGp1c3Rlcik7XG4gICAgLy8gICByZXR1cm4gcm9sbENzcURhdGE7XG4gICAgLy8gfVxuICAgIGdldERhdGEoKSB7XG4gICAgICAgIGNvbnN0IGRhdGEgPSBzdXBlci5nZXREYXRhKCk7XG4gICAgICAgIHN3aXRjaCAodGhpcy5kaWFsb2dUeXBlKSB7XG4gICAgICAgICAgICBjYXNlIEJsYWRlc0RpYWxvZ1R5cGUuSW5wdXQ6IHJldHVybiB0aGlzLnByZXBhcmVJbnB1dERhdGEoZGF0YSk7XG4gICAgICAgICAgICBjYXNlIEJsYWRlc0RpYWxvZ1R5cGUuU2VsZWN0aW9uOiByZXR1cm4gdGhpcy5wcmVwYXJlU2VsZWN0aW9uRGF0YShkYXRhKTtcbiAgICAgICAgICAgIC8vIGNhc2UgQmxhZGVzRGlhbG9nVHlwZS5Db25zZXF1ZW5jZTogcmV0dXJuIHRoaXMucHJlcGFyZUNvbnNlcXVlbmNlRGF0YShkYXRhKTtcbiAgICAgICAgICAgIGRlZmF1bHQ6IHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgfVxuICAgIHByZXBhcmVJbnB1dERhdGEoZGF0YSkge1xuICAgICAgICBkYXRhLnByb21wdCA9IHRoaXMucHJvbXB0O1xuICAgICAgICBkYXRhLnRhcmdldCA9IHRoaXMudGFyZ2V0O1xuICAgICAgICBkYXRhLmZsYWdUYXJnZXQgPSB0aGlzLmZsYWdUYXJnZXQ7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgICBwcmVwYXJlU2VsZWN0aW9uRGF0YShkYXRhKSB7XG4gICAgICAgIGRhdGEudGl0bGUgPSB0aGlzLnRpdGxlO1xuICAgICAgICBkYXRhLnRhYnMgPSB0aGlzLnRhYnM7XG4gICAgICAgIGRhdGEuZG9jVHlwZSA9IHRoaXMuZG9jVHlwZTtcbiAgICAgICAgZGF0YS50YWdzID0gdGhpcy50YWdzO1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9XG4gICAgLy8gcHJlcGFyZUNvbnNlcXVlbmNlRGF0YShkYXRhOiBCbGFkZXNEaWFsb2cuRGF0YSkge1xuICAgIC8vICAgZUxvZy5jaGVja0xvZzMoXCJkaWFsb2dcIiwgXCJwcmVwYXJlQ29uc2VxdWVuY2VEYXRhIHRoaXMuY3NxRGF0YVwiLCB7Li4udGhpcy5jc3FEYXRhfSk7XG4gICAgLy8gICBlTG9nLmNoZWNrTG9nMyhcImRpYWxvZ1wiLCBcInByZXBhcmVDb25zZXF1ZW5jZURhdGFcIiwge2luY29taW5nOiB7Li4uZGF0YX19KTtcbiAgICAvLyAgIGRhdGEuY29uc2VxdWVuY2VEYXRhID0gdGhpcy5jc3FEYXRhO1xuICAgIC8vICAgZGF0YS5jb25zZXF1ZW5jZVR5cGVPcHRpb25zID0gdGhpcy5jb25zZXF1ZW5jZVR5cGVPcHRpb25zO1xuICAgIC8vICAgZGF0YS5jb25zZXF1ZW5jZVR5cGVPcHRpb25zQWxsID0gT2JqZWN0LmtleXMoQy5Db25zZXF1ZW5jZURpc3BsYXkpXG4gICAgLy8gICAgIC5tYXAoKGNUeXBlKSA9PiAoe3ZhbHVlOiBjVHlwZSwgZGlzcGxheTogY1R5cGV9KSk7XG4gICAgLy8gICBkYXRhLmNvbnNlcXVlbmNlQXR0cmlidXRlT3B0aW9ucyA9IFtcbiAgICAvLyAgICAge3ZhbHVlOiBBdHRyaWJ1dGVUcmFpdC5pbnNpZ2h0LCBkaXNwbGF5OiBcIkluc2lnaHRcIn0sXG4gICAgLy8gICAgIHt2YWx1ZTogQXR0cmlidXRlVHJhaXQucHJvd2VzcywgZGlzcGxheTogXCJQcm93ZXNzXCJ9LFxuICAgIC8vICAgICB7dmFsdWU6IEF0dHJpYnV0ZVRyYWl0LnJlc29sdmUsIGRpc3BsYXk6IFwiUmVzb2x2ZVwifVxuICAgIC8vICAgXTtcbiAgICAvLyAgIGVMb2cuY2hlY2tMb2czKFwiZGlhbG9nXCIsIFwicHJlcGFyZUNvbnNlcXVlbmNlRGF0YVwiLCB7b3V0Z29pbmc6IHsuLi5kYXRhfX0pO1xuICAgIC8vICAgcmV0dXJuIGRhdGE7XG4gICAgLy8gfVxuICAgIC8vIGdldCBjb25zZXF1ZW5jZVR5cGVPcHRpb25zKCk6IFJlY29yZDxcbiAgICAvLyAgIFBvc2l0aW9uLFxuICAgIC8vICAgUmVjb3JkPFxuICAgIC8vICAgICBSb2xsUmVzdWx0LnBhcnRpYWx8Um9sbFJlc3VsdC5mYWlsLFxuICAgIC8vICAgICBBcnJheTxCbGFkZXNTZWxlY3RPcHRpb248c3RyaW5nLCBDb25zZXF1ZW5jZVR5cGU+PlxuICAgIC8vICAgPlxuICAgIC8vICAgPiB7XG4gICAgLy8gICBpZiAodGhpcy5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNSb2xsKSB7XG4gICAgLy8gICAgIGNvbnN0IHJldHVybkRhdGE6IFBhcnRpYWw8UmVjb3JkPFxuICAgIC8vICAgICBQb3NpdGlvbixcbiAgICAvLyAgICAgUmVjb3JkPFxuICAgIC8vICAgICAgIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWwsXG4gICAgLy8gICAgICAgQXJyYXk8QmxhZGVzU2VsZWN0T3B0aW9uPHN0cmluZywgQ29uc2VxdWVuY2VUeXBlPj5cbiAgICAvLyAgICAgPlxuICAgIC8vICAgPj4gPSB7fTtcbiAgICAvLyAgICAgW1Bvc2l0aW9uLmNvbnRyb2xsZWQsIFBvc2l0aW9uLnJpc2t5LCBQb3NpdGlvbi5kZXNwZXJhdGVdLmZvckVhY2goKHBvcykgPT4ge1xuICAgIC8vICAgICAgIHJldHVybkRhdGFbcG9zXSA9IHtcbiAgICAvLyAgICAgICAgIFtSb2xsUmVzdWx0LnBhcnRpYWxdOiBDLkNvbnNlcXVlbmNlc1twb3NdW1JvbGxSZXN1bHQucGFydGlhbF1cbiAgICAvLyAgICAgICAgICAgLm1hcCgoY1R5cGUpID0+ICh7dmFsdWU6IGNUeXBlLCBkaXNwbGF5OiBjVHlwZX0pKSxcbiAgICAvLyAgICAgICAgIFtSb2xsUmVzdWx0LmZhaWxdOiBDLkNvbnNlcXVlbmNlc1twb3NdW1JvbGxSZXN1bHQuZmFpbF1cbiAgICAvLyAgICAgICAgICAgLm1hcCgoY1R5cGUpID0+ICh7dmFsdWU6IGNUeXBlLCBkaXNwbGF5OiBjVHlwZX0pKVxuICAgIC8vICAgICAgIH07XG4gICAgLy8gICAgIH0pO1xuICAgIC8vICAgICByZXR1cm4gcmV0dXJuRGF0YSBhcyBSZWNvcmQ8XG4gICAgLy8gICAgIFBvc2l0aW9uLFxuICAgIC8vICAgICBSZWNvcmQ8XG4gICAgLy8gICAgICAgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbCxcbiAgICAvLyAgICAgICBBcnJheTxCbGFkZXNTZWxlY3RPcHRpb248c3RyaW5nLCBDb25zZXF1ZW5jZVR5cGU+PlxuICAgIC8vICAgICA+XG4gICAgLy8gICA+O1xuICAgIC8vICAgfVxuICAgIC8vICAgcmV0dXJuIHt9IGFzIG5ldmVyO1xuICAgIC8vIH1cbiAgICB1cGRhdGVJbnB1dFRleHQoaW5wdXRFbGVtJCkge1xuICAgICAgICBjb25zdCB2YWx1ZSA9IGlucHV0RWxlbSQudmFsKCk7XG4gICAgICAgIGlmICh0aGlzLnBhcmVudCBpbnN0YW5jZW9mIEJsYWRlc1JvbGwpIHtcbiAgICAgICAgICAgIGNvbnN0IGZsYWdUYXJnZXQgPSBpbnB1dEVsZW0kLmRhdGEoXCJmbGFnVGFyZ2V0XCIpO1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJkaWFsb2dcIiwgXCJ1cGRhdGVJbnB1dFRleHRcIiwgeyB2YWx1ZSwgZmxhZ1RhcmdldCB9KTtcbiAgICAgICAgICAgIHRoaXMucGFyZW50LnVwZGF0ZVRhcmdldChmbGFnVGFyZ2V0LCB2YWx1ZSlcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB0aGlzLnBhcmVudC5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldENhbGwoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNJdGVtIHx8IHRoaXMucGFyZW50IGluc3RhbmNlb2YgQmxhZGVzQWN0b3IpIHtcbiAgICAgICAgICAgIHRoaXMucGFyZW50LnVwZGF0ZSh7IFtpbnB1dEVsZW0kLmRhdGEoXCJ0YXJnZXRcIildOiBpbnB1dEVsZW0kLnZhbCgpIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIHVwZGF0ZUNvbnNlcXVlbmNlVHlwZShjc3FFbGVtJDogSlF1ZXJ5PEhUTUxFbGVtZW50PiwgY0RhdGE6IEJsYWRlc0NvbnNlcXVlbmNlLkRhdGEpIHtcbiAgICAvLyAgIGNvbnN0IHR5cGUkID0gY3NxRWxlbSQuZmluZChcIi5yb2xsLWNvbnNlcXVlbmNlLXR5cGUtc2VsZWN0XCIpIGFzIEpRdWVyeTxIVE1MU2VsZWN0RWxlbWVudD47XG4gICAgLy8gICBjb25zdCB0eXBlVmFsID0gdHlwZSQudmFsKCkgYXMgc3RyaW5nfHVuZGVmaW5lZDtcbiAgICAvLyAgIGlmICh0eXBlVmFsICYmIHR5cGVWYWwgaW4gQ29uc2VxdWVuY2VUeXBlKSB7XG4gICAgLy8gICAgIGNEYXRhLnR5cGUgPSB0eXBlVmFsIGFzIENvbnNlcXVlbmNlVHlwZTtcbiAgICAvLyAgICAgY0RhdGEuaWNvbiA9IEMuQ29uc2VxdWVuY2VJY29uc1tjRGF0YS50eXBlXTtcbiAgICAvLyAgICAgY0RhdGEudHlwZURpc3BsYXkgPSBDLkNvbnNlcXVlbmNlRGlzcGxheVtjRGF0YS50eXBlXTtcbiAgICAvLyAgIH1cbiAgICAvLyB9XG4gICAgLy8gdXBkYXRlQ29uc2VxdWVuY2VBdHRyaWJ1dGUoY3NxRWxlbSQ6IEpRdWVyeTxIVE1MRWxlbWVudD4sIGNEYXRhOiBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhKSB7XG4gICAgLy8gICBpZiAoL0luc2lnaHQvLmV4ZWMoY0RhdGEudHlwZSkpIHsgY0RhdGEuYXR0cmlidXRlID0gQXR0cmlidXRlVHJhaXQuaW5zaWdodDsgfVxuICAgIC8vICAgZWxzZSBpZiAoL1Byb3dlc3MvLmV4ZWMoY0RhdGEudHlwZSkpIHsgY0RhdGEuYXR0cmlidXRlID0gQXR0cmlidXRlVHJhaXQucHJvd2VzczsgfVxuICAgIC8vICAgZWxzZSBpZiAoL1Jlc29sdmUvLmV4ZWMoY0RhdGEudHlwZSkpIHsgY0RhdGEuYXR0cmlidXRlID0gQXR0cmlidXRlVHJhaXQucmVzb2x2ZTsgfVxuICAgIC8vICAgZWxzZSB7XG4gICAgLy8gICAgIGNvbnN0IGF0dHJpYnV0ZSQgPSBjc3FFbGVtJC5maW5kKFwiLnJvbGwtY29uc2VxdWVuY2UtYXR0cmlidXRlLXNlbGVjdFwiKSBhcyBKUXVlcnk8SFRNTFNlbGVjdEVsZW1lbnQ+O1xuICAgIC8vICAgICBjb25zdCBhdHRyVmFsID0gYXR0cmlidXRlJC52YWwoKSBhcyBBdHRyaWJ1dGVUcmFpdHx1bmRlZmluZWQ7XG4gICAgLy8gICAgIGlmIChhdHRyVmFsKSB7XG4gICAgLy8gICAgICAgY0RhdGEuYXR0cmlidXRlID0gYXR0clZhbDtcbiAgICAvLyAgICAgfVxuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyB1cGRhdGVDb25zZXF1ZW5jZUF0dHJpYnV0ZVZhbChjRGF0YTogQmxhZGVzQ29uc2VxdWVuY2UuRGF0YSkge1xuICAgIC8vICAgaWYgKHRoaXMucGFyZW50LnJvbGxQcmltYXJ5RG9jIGluc3RhbmNlb2YgQmxhZGVzUEMpIHtcbiAgICAvLyAgICAgY0RhdGEuYXR0cmlidXRlVmFsID0gdGhpcy5wYXJlbnQucm9sbFByaW1hcnlEb2MuYXR0cmlidXRlc1tjRGF0YS5hdHRyaWJ1dGUgYXMgQXR0cmlidXRlVHJhaXRdO1xuICAgIC8vICAgfSBlbHNlIGlmICh0aGlzLnBhcmVudC5yb2xsUHJpbWFyeURvYz8ucGFyZW50IGluc3RhbmNlb2YgQmxhZGVzUEMpIHtcbiAgICAvLyAgICAgY0RhdGEuYXR0cmlidXRlVmFsID0gdGhpcy5wYXJlbnQucm9sbFByaW1hcnlEb2MucGFyZW50LmF0dHJpYnV0ZXNbY0RhdGEuYXR0cmlidXRlIGFzIEF0dHJpYnV0ZVRyYWl0XTtcbiAgICAvLyAgIH0gZWxzZSB7XG4gICAgLy8gICAgIGVMb2cuZXJyb3IoYFVuYWJsZSB0byBnZXQgYXR0cmlidXRlIGZyb20gcm9sbFByaW1hcnlEb2MgJyR7dGhpcy5wYXJlbnQucm9sbFByaW1hcnlEb2M/Lm5hbWV9JyBvZiB0eXBlICcke3RoaXMucGFyZW50LnJvbGxQcmltYXJ5RG9jPy5yb2xsUHJpbWFyeVR5cGV9JyAobWF5IG5lZWQgdG8gbG9nIHZpYSBmbGFncyBpZiBlaXRoZXIgb2YgdGhlIHByZXZpb3VzIHNob3cgJ3VuZGVmaW5lZCcuYCk7XG4gICAgLy8gICB9XG4gICAgLy8gfVxuICAgIC8vIGdldFNlbGVjdGVkUmVzaXN0T3B0aW9uKGNEYXRhOiBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhKTogQmxhZGVzQ29uc2VxdWVuY2V8ZmFsc2Uge1xuICAgIC8vICAgcmV0dXJuIGNEYXRhLnJlc2lzdFRvXG4gICAgLy8gICAgID8gbmV3IEJsYWRlc0NvbnNlcXVlbmNlKGNEYXRhLnJlc2lzdFRvKVxuICAgIC8vICAgICA6IGZhbHNlO1xuICAgIC8vIH1cbiAgICAvLyB1cGRhdGVDb25zZXF1ZW5jZVJlc2lzdChjc3FFbGVtJDogSlF1ZXJ5PEhUTUxFbGVtZW50PiwgY0RhdGE6IEJsYWRlc0NvbnNlcXVlbmNlLkRhdGEpIHtcbiAgICAvLyAgIGNvbnN0IHJlc2lzdE9wdGlvbnM6IFJlY29yZDxzdHJpbmcsIEJsYWRlc1JvbGwuQ29uc2VxdWVuY2VSZXNpc3RPcHRpb24+ID0gY0RhdGEucmVzaXN0T3B0aW9ucyA/PyB7fTtcbiAgICAvLyAgIC8vIElmIGNvbnNlcXVlbmNlIGlzIGFscmVhZHkgbWluaW1hbCwgdG9nZ2xlIHJlc2lzdE5lZ2F0ZXMgdG8gdHJ1ZSBhbmQgc2V0ICdyZXNpc3RUbycgdG8gTm9uZS10eXBlXG4gICAgLy8gICBjb25zdCBtaW5pbWFsQ3NxVHlwZXMgPSBPYmplY3QuZW50cmllcyhDLlJlc2lzdGVkQ29uc2VxdWVuY2VUeXBlcylcbiAgICAvLyAgICAgLmZpbHRlcigoW18sIHJDc3FUeXBlXSkgPT4gckNzcVR5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5Ob25lKVxuICAgIC8vICAgICAubWFwKChbY3NxVHlwZV0pID0+IGNzcVR5cGUgYXMgQ29uc2VxdWVuY2VUeXBlKTtcbiAgICAvLyAgIGlmIChtaW5pbWFsQ3NxVHlwZXMuaW5jbHVkZXMoY0RhdGEudHlwZSBhcyBDb25zZXF1ZW5jZVR5cGUpKSB7XG4gICAgLy8gICAgIGNEYXRhLnJlc2lzdE5lZ2F0ZXMgPSB0cnVlO1xuICAgIC8vICAgICBjb25zdCBub25lQ3NxID0gQmxhZGVzQ29uc2VxdWVuY2UuTm9uZTtcbiAgICAvLyAgICAgY0RhdGEucmVzaXN0T3B0aW9ucyA9IHtbbm9uZUNzcS5pZF06IG5vbmVDc3F9O1xuICAgIC8vICAgICBjRGF0YS5yZXNpc3RUbyA9IG5vbmVDc3E7XG4gICAgLy8gICAgIHJldHVybjtcbiAgICAvLyAgIH0gZWxzZSB7XG4gICAgLy8gICAgIC8vIENsZWFyICdyZXNpc3RUbycgKHdpbGwgYmUgcmVkZXRlcm1pbmVkIGJlbG93KVxuICAgIC8vICAgICBkZWxldGUgY0RhdGEucmVzaXN0VG87XG4gICAgLy8gICAgIGRlbGV0ZSBjRGF0YS5yZXNpc3ROZWdhdGVzO1xuICAgIC8vICAgICBjc3FFbGVtJC5maW5kKFwiLmNvbnNlcXVlbmNlLXJlc2lzdC1vcHRpb25cIikuZWFjaCgoXywgZWxlbSkgPT4ge1xuICAgIC8vICAgICAgIGNvbnN0IHJlc0NzcUlEID0gJChlbGVtKS5kYXRhKFwiY3NxLWlkXCIpO1xuICAgIC8vICAgICAgIHJlc2lzdE9wdGlvbnNbcmVzQ3NxSURdID8/PSB7aWQ6IHJlc0NzcUlELCBuYW1lOiBcIlwiLCB0eXBlOiB1bmRlZmluZWQsIGlzU2VsZWN0ZWQ6IGZhbHNlfTtcbiAgICAvLyAgICAgICAvLyBVcGRhdGUgUmVzaXN0YW5jZSBPcHRpb24gVHlwZVxuICAgIC8vICAgICAgIGNvbnN0IHJlc1R5cGUkID0gJChlbGVtKS5maW5kKFwiLnJvbGwtY29uc2VxdWVuY2UtdHlwZS1zZWxlY3RcIikgYXMgSlF1ZXJ5PEhUTUxTZWxlY3RFbGVtZW50PjtcbiAgICAvLyAgICAgICBjb25zdCByZXNUeXBlVmFsID0gcmVzVHlwZSQudmFsKCkgYXMgc3RyaW5nfHVuZGVmaW5lZDtcbiAgICAvLyAgICAgICBpZiAocmVzVHlwZVZhbCAmJiByZXNUeXBlVmFsIGluIENvbnNlcXVlbmNlVHlwZSkge1xuICAgIC8vICAgICAgICAgcmVzaXN0T3B0aW9uc1tyZXNDc3FJRF0udHlwZSA9IHJlc1R5cGVWYWwgYXMgQ29uc2VxdWVuY2VUeXBlO1xuICAgIC8vICAgICAgICAgcmVzaXN0T3B0aW9uc1tyZXNDc3FJRF0uaWNvbiA9IEMuQ29uc2VxdWVuY2VJY29uc1tyZXNpc3RPcHRpb25zW3Jlc0NzcUlEXS50eXBlIGFzIENvbnNlcXVlbmNlVHlwZV07XG4gICAgLy8gICAgICAgICByZXNpc3RPcHRpb25zW3Jlc0NzcUlEXS50eXBlRGlzcGxheSA9IEMuQ29uc2VxdWVuY2VEaXNwbGF5W3Jlc2lzdE9wdGlvbnNbcmVzQ3NxSURdLnR5cGUgYXMgQ29uc2VxdWVuY2VUeXBlXTtcbiAgICAvLyAgICAgICB9XG4gICAgLy8gICAgICAgLy8gVXBkYXRlIFJlc2lzdGFuY2UgT3B0aW9uIE5hbWVcbiAgICAvLyAgICAgICBjb25zdCByZXNOYW1lJCA9ICQoZWxlbSkuZmluZChcIi5jb25zZXF1ZW5jZS1uYW1lXCIpIGFzIEpRdWVyeTxIVE1MSW5wdXRFbGVtZW50PjtcbiAgICAvLyAgICAgICBjb25zdCByZXNOYW1lVmFsID0gcmVzTmFtZSQudmFsKCk7XG4gICAgLy8gICAgICAgcmVzaXN0T3B0aW9uc1tyZXNDc3FJRF0ubmFtZSA9IHJlc05hbWVWYWwgPz8gXCJcIjtcbiAgICAvLyAgICAgICAvLyBJZiB0aGlzIGlzIHNlbGVjdGVkLCB1cGRhdGUgJ3Jlc2lzdFRvJyBkYXRhIGFzIHdlbGxcbiAgICAvLyAgICAgICBpZiAocmVzaXN0T3B0aW9uc1tyZXNDc3FJRF0uaXNTZWxlY3RlZCkge1xuICAgIC8vICAgICAgICAgY0RhdGEucmVzaXN0VG8gPSByZXNpc3RPcHRpb25zW3Jlc0NzcUlEXTtcbiAgICAvLyAgICAgICB9XG4gICAgLy8gICAgIH0pO1xuICAgIC8vICAgfVxuICAgIC8vICAgY0RhdGEucmVzaXN0T3B0aW9ucyA9IHJlc2lzdE9wdGlvbnM7XG4gICAgLy8gfVxuICAgIC8vIHVwZGF0ZUNvbnNlcXVlbmNlQXJtb3JSZXNpc3QoX2NzcUVsZW0kOiBKUXVlcnk8SFRNTEVsZW1lbnQ+LCBjRGF0YTogQmxhZGVzQ29uc2VxdWVuY2UuRGF0YSkge1xuICAgIC8vICAgLy8gSWYgY29uc2VxdWVuY2UgaXMgYWxyZWFkeSBtaW5pbWFsLCB0b2dnbGUgYXJtb3JOZWdhdGVzIHRvIHRydWUgYW5kIHNldCAnYXJtb3JUbycgdG8gTm9uZS10eXBlXG4gICAgLy8gICBjb25zdCBtaW5pbWFsQ3NxVHlwZXMgPSBPYmplY3QuZW50cmllcyhDLlJlc2lzdGVkQ29uc2VxdWVuY2VUeXBlcylcbiAgICAvLyAgICAgLmZpbHRlcigoW18sIHJDc3FUeXBlXSkgPT4gckNzcVR5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5Ob25lKVxuICAgIC8vICAgICAubWFwKChbY3NxVHlwZV0pID0+IGNzcVR5cGUgYXMgQ29uc2VxdWVuY2VUeXBlKTtcbiAgICAvLyAgIGlmIChtaW5pbWFsQ3NxVHlwZXMuaW5jbHVkZXMoY0RhdGEudHlwZSBhcyBDb25zZXF1ZW5jZVR5cGUpKSB7XG4gICAgLy8gICAgIGNEYXRhLmFybW9yTmVnYXRlcyA9IHRydWU7XG4gICAgLy8gICAgIGNEYXRhLmFybW9yVG8gPSBCbGFkZXNDb25zZXF1ZW5jZS5Ob25lO1xuICAgIC8vICAgfSBlbHNlIHtcbiAgICAvLyAgICAgZGVsZXRlIGNEYXRhLmFybW9yTmVnYXRlcztcbiAgICAvLyAgICAgY0RhdGEuYXJtb3JUbyA9IHRoaXMuZ2V0U2VsZWN0ZWRSZXNpc3RPcHRpb24oY0RhdGEpO1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyB1cGRhdGVDb25zZXF1ZW5jZVNwZWNpYWxBcm1vclJlc2lzdChfY3NxRWxlbSQ6IEpRdWVyeTxIVE1MRWxlbWVudD4sIGNEYXRhOiBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhKSB7XG4gICAgLy8gICAvLyBJZiBjb25zZXF1ZW5jZSBpcyBhbHJlYWR5IG1pbmltYWwsIHRvZ2dsZSBzcGVjaWFsQXJtb3JOZWdhdGVzIHRvIHRydWUgYW5kIHNldCAnc3BlY2lhbFRvJyB0byBOb25lLXR5cGVcbiAgICAvLyAgIGNvbnN0IG1pbmltYWxDc3FUeXBlcyA9IE9iamVjdC5lbnRyaWVzKEMuUmVzaXN0ZWRDb25zZXF1ZW5jZVR5cGVzKVxuICAgIC8vICAgICAuZmlsdGVyKChbXywgckNzcVR5cGVdKSA9PiByQ3NxVHlwZSA9PT0gQ29uc2VxdWVuY2VUeXBlLk5vbmUpXG4gICAgLy8gICAgIC5tYXAoKFtjc3FUeXBlXSkgPT4gY3NxVHlwZSBhcyBDb25zZXF1ZW5jZVR5cGUpO1xuICAgIC8vICAgaWYgKG1pbmltYWxDc3FUeXBlcy5pbmNsdWRlcyhjRGF0YS50eXBlIGFzIENvbnNlcXVlbmNlVHlwZSkpIHtcbiAgICAvLyAgICAgY0RhdGEuc3BlY2lhbEFybW9yTmVnYXRlcyA9IHRydWU7XG4gICAgLy8gICAgIGNEYXRhLnNwZWNpYWxUbyA9IEJsYWRlc0NvbnNlcXVlbmNlLk5vbmU7XG4gICAgLy8gICB9IGVsc2Uge1xuICAgIC8vICAgICBkZWxldGUgY0RhdGEuc3BlY2lhbEFybW9yTmVnYXRlcztcbiAgICAvLyAgICAgY0RhdGEuc3BlY2lhbEFybW9yTmVnYXRlcyA/Pz0gZmFsc2U7XG4gICAgLy8gICAgIGNEYXRhLnNwZWNpYWxUbyA9IHRoaXMuZ2V0U2VsZWN0ZWRSZXNpc3RPcHRpb24oY0RhdGEpO1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyB1cGRhdGVDb25zZXF1ZW5jZURhdGEoXG4gICAgLy8gICBodG1sOiBKUXVlcnk8SFRNTEVsZW1lbnR8SFRNTElucHV0RWxlbWVudD4sXG4gICAgLy8gICBjRGF0YTogQmxhZGVzQ29uc2VxdWVuY2UuRGF0YVxuICAgIC8vICkge1xuICAgIC8vICAgY29uc3QgY3NxRWxlbSQgPSBodG1sLmZpbmQoYC5yb2xsLWNvbnNlcXVlbmNlLXJvd1tkYXRhLWNzcS1pZD0nJHtjRGF0YS5pZH0nXWApO1xuICAgIC8vICAgLy8gVXBkYXRlIFR5cGVcbiAgICAvLyAgIHRoaXMudXBkYXRlQ29uc2VxdWVuY2VUeXBlKGNzcUVsZW0kLCBjRGF0YSk7XG4gICAgLy8gICAvLyBVcGRhdGUgTmFtZVxuICAgIC8vICAgaWYgKGNEYXRhLnR5cGUgPT09IENvbnNlcXVlbmNlVHlwZS5Ob25lKSB7XG4gICAgLy8gICAgIGNEYXRhLm5hbWUgPSBcIlwiO1xuICAgIC8vICAgfSBlbHNlIHtcbiAgICAvLyAgICAgY29uc3QgbmFtZSQgPSBjc3FFbGVtJC5maW5kKFwiLmNvbnNlcXVlbmNlLW5hbWVcIikgYXMgSlF1ZXJ5PEhUTUxJbnB1dEVsZW1lbnQ+O1xuICAgIC8vICAgICBjb25zdCBuYW1lVmFsID0gbmFtZSQudmFsKCk7XG4gICAgLy8gICAgIGNEYXRhLm5hbWUgPSBuYW1lVmFsID8/IFwiXCI7XG4gICAgLy8gICB9XG4gICAgLy8gICAvLyBVcGRhdGUgUmVzaXN0YW5jZSBBdHRyaWJ1dGVcbiAgICAvLyAgIHRoaXMudXBkYXRlQ29uc2VxdWVuY2VBdHRyaWJ1dGUoY3NxRWxlbSQsIGNEYXRhKTtcbiAgICAvLyAgIHRoaXMudXBkYXRlQ29uc2VxdWVuY2VBdHRyaWJ1dGVWYWwoY0RhdGEpO1xuICAgIC8vICAgLy8gVXBkYXRlIFJlc2lzdGFuY2UgT3B0aW9uc1xuICAgIC8vICAgdGhpcy51cGRhdGVDb25zZXF1ZW5jZVJlc2lzdChjc3FFbGVtJCwgY0RhdGEpO1xuICAgIC8vICAgLy8gVXBkYXRlIEFybW9yIE9wdGlvbnNcbiAgICAvLyAgIGlmICgoPEJsYWRlc1JvbGw+IHRoaXMucGFyZW50KS5jYW5SZXNpc3RXaXRoQXJtb3IoY0RhdGEpKSB7XG4gICAgLy8gICAgIGNEYXRhLmlzRGlzcGxheWluZ0FybW9yVG9nZ2xlID0gdHJ1ZTtcbiAgICAvLyAgICAgdGhpcy51cGRhdGVDb25zZXF1ZW5jZUFybW9yUmVzaXN0KGNzcUVsZW0kLCBjRGF0YSk7XG4gICAgLy8gICB9IGVsc2Uge1xuICAgIC8vICAgICBjRGF0YS5pc0Rpc3BsYXlpbmdBcm1vclRvZ2dsZSA9IGZhbHNlO1xuICAgIC8vICAgfVxuICAgIC8vICAgLy8gVXBkYXRlIFNwZWNpYWwgQXJtb3IgT3B0aW9uc1xuICAgIC8vICAgaWYgKCg8QmxhZGVzUm9sbD4gdGhpcy5wYXJlbnQpLmNhblJlc2lzdFdpdGhTcGVjaWFsQXJtb3IoY0RhdGEpKSB7XG4gICAgLy8gICAgIGNEYXRhLmlzRGlzcGxheWluZ1NwZWNpYWxBcm1vclRvZ2dsZSA9IHRydWU7XG4gICAgLy8gICAgIHRoaXMudXBkYXRlQ29uc2VxdWVuY2VTcGVjaWFsQXJtb3JSZXNpc3QoY3NxRWxlbSQsIGNEYXRhKTtcbiAgICAvLyAgIH0gZWxzZSB7XG4gICAgLy8gICAgIGNEYXRhLmlzRGlzcGxheWluZ1NwZWNpYWxBcm1vclRvZ2dsZSA9IGZhbHNlO1xuICAgIC8vICAgfVxuICAgIC8vICAgcmV0dXJuIGNEYXRhO1xuICAgIC8vIH1cbiAgICAvLyB1cGRhdGVDb25zZXF1ZW5jZURpYWxvZyhodG1sOiBKUXVlcnk8SFRNTEVsZW1lbnR8SFRNTElucHV0RWxlbWVudD4sIGlzUmVuZGVyaW5nID0gdHJ1ZSkge1xuICAgIC8vICAgaWYgKCEodGhpcy5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNSb2xsKSkgeyByZXR1cm47IH1cbiAgICAvLyAgIGlmICghdGhpcy5jc3FEYXRhKSB7IHJldHVybjsgfVxuICAgIC8vICAgZUxvZy5jaGVja0xvZzMoXCJkaWFsb2dcIiwgXCJ1cGRhdGVDb25zZXF1ZW5jZURpYWxvZygpIHRoaXMuY3NxRGF0YSBJTkNPTUlOR1wiLCB7Li4udGhpcy5jc3FEYXRhfSk7XG4gICAgLy8gICBjb25zdCB7Y3NxRGF0YX0gPSB0aGlzO1xuICAgIC8vICAgY29uc3Qge3JvbGxQcmltYXJ5RG9jfSA9IHRoaXMucGFyZW50O1xuICAgIC8vICAgaWYgKCEocm9sbFByaW1hcnlEb2MgaW5zdGFuY2VvZiBCbGFkZXNQQykpIHsgcmV0dXJuOyB9XG4gICAgLy8gICAoT2JqZWN0LmtleXMoY3NxRGF0YSkgYXMgUG9zaXRpb25bXSkuZm9yRWFjaCgocm9sbFBvcykgPT4ge1xuICAgIC8vICAgICBjb25zdCBwb3NpdGlvbkNzcURhdGEgPSBjc3FEYXRhW3JvbGxQb3NdO1xuICAgIC8vICAgICAoT2JqZWN0LmtleXMoY3NxRGF0YVtyb2xsUG9zXSkgYXMgW1JvbGxSZXN1bHQucGFydGlhbCwgUm9sbFJlc3VsdC5mYWlsXSkuZm9yRWFjaCgocm9sbFJlc3VsdCkgPT4ge1xuICAgIC8vICAgICAgIHBvc2l0aW9uQ3NxRGF0YVtyb2xsUmVzdWx0XSA9IFUub2JqTWFwKFxuICAgIC8vICAgICAgICAgcG9zaXRpb25Dc3FEYXRhW3JvbGxSZXN1bHRdLFxuICAgIC8vICAgICAgICAgKGNEYXRhOiBCbGFkZXNDb25zZXF1ZW5jZS5EYXRhKSA9PiB0aGlzLnVwZGF0ZUNvbnNlcXVlbmNlRGF0YShodG1sLCBjRGF0YSlcbiAgICAvLyAgICAgICApO1xuICAgIC8vICAgICB9KTtcbiAgICAvLyAgICAgY3NxRGF0YVtyb2xsUG9zXSA9IHBvc2l0aW9uQ3NxRGF0YTtcbiAgICAvLyAgIH0pO1xuICAgIC8vICAgdGhpcy5jc3FEYXRhID0gY3NxRGF0YTtcbiAgICAvLyAgIGVMb2cuY2hlY2tMb2czKFwiZGlhbG9nXCIsIFwidXBkYXRlQ29uc2VxdWVuY2VEaWFsb2coKSB0aGlzLmNzcURhdGEgT1VUR09JTkdcIiwgey4uLnRoaXMuY3NxRGF0YX0pO1xuICAgIC8vICAgaWYgKGlzUmVuZGVyaW5nKSB7XG4gICAgLy8gICAgIHRoaXMucmVuZGVyKCk7XG4gICAgLy8gICB9XG4gICAgLy8gfVxuICAgIC8vIGFzeW5jIHdyaXRlVG9Sb2xsSW5zdGFuY2UoaHRtbDogSlF1ZXJ5PEhUTUxFbGVtZW50Pikge1xuICAgIC8vIGlmICh0aGlzLnBhcmVudCBpbnN0YW5jZW9mIEJsYWRlc1JvbGwpIHtcbiAgICAvLyB0aGlzLnVwZGF0ZUNvbnNlcXVlbmNlRGlhbG9nKGh0bWwsIGZhbHNlKTtcbiAgICAvLyBhd2FpdCB0aGlzLnBhcmVudC51cGRhdGVUYXJnZXQoXCJjb25zZXF1ZW5jZURhdGFcIiwgdGhpcy5jc3FEYXRhKTtcbiAgICAvLyB9XG4gICAgLy8gfVxuICAgIC8vIF9jb25zZXF1ZW5jZUFJPzogQmxhZGVzQUk7XG4gICAgLy8gZ2V0Q3NxRGF0YUZyb21FbGVtKGVsZW06IEhUTUxFbGVtZW50LCBwYXJhbUNvdW50ID0gMyk6IHN0cmluZ1tdIHtcbiAgICAvLyAgIGNvbnN0IGRhdGFBY3Rpb24gPSBlbGVtLmRhdGFzZXQuYWN0aW9uO1xuICAgIC8vICAgaWYgKGRhdGFBY3Rpb24pIHtcbiAgICAvLyAgICAgY29uc3QgcGFyYW1zID0gZGF0YUFjdGlvbi5zcGxpdCgvLS8pLnJldmVyc2UoKS5zbGljZSgwLCBwYXJhbUNvdW50KTtcbiAgICAvLyAgICAgcmV0dXJuIHBhcmFtcy5yZXZlcnNlKCk7XG4gICAgLy8gICB9XG4gICAgLy8gICByZXR1cm4gW107XG4gICAgLy8gfVxuICAgIC8vIGFzeW5jIHF1ZXJ5QUkoZXZlbnQ6IENsaWNrRXZlbnQpIHtcbiAgICAvLyAgIGlmICghdGhpcy5jc3FEYXRhKSB7IHJldHVybjsgfVxuICAgIC8vICAgLy8gSWYgdGhlIEFJIGdlbmVyYXRvciBoYXMgbm90IGJlZW4gaW5pdGlhbGl6ZWQsIGRvIHNvLlxuICAgIC8vICAgaWYgKCF0aGlzLl9jb25zZXF1ZW5jZUFJKSB7XG4gICAgLy8gICAgIHRoaXMuX2NvbnNlcXVlbmNlQUkgPSBuZXcgQmxhZGVzQUkoQUdFTlRTLkNvbnNlcXVlbmNlQWRqdXN0ZXIpO1xuICAgIC8vICAgfVxuICAgIC8vICAgY29uc3QgW3JvbGxQb3NpdGlvbiwgcm9sbFJlc3VsdCwgY3NxSURdID0gdGhpcy5nZXRDc3FEYXRhRnJvbUVsZW0oZXZlbnQuY3VycmVudFRhcmdldCk7XG4gICAgLy8gICBjb25zdCBjc3FOYW1lOiBzdHJpbmd8dW5kZWZpbmVkID1cbiAgICAvLyAgICAgdGhpcy5jc3FEYXRhW3JvbGxQb3NpdGlvbiBhcyBQb3NpdGlvbl1bcm9sbFJlc3VsdCBhcyBSb2xsUmVzdWx0LnBhcnRpYWx8Um9sbFJlc3VsdC5mYWlsXVtjc3FJRF0/Lm5hbWU7XG4gICAgLy8gICBpZiAoY3NxTmFtZSkge1xuICAgIC8vICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IHRoaXMuX2NvbnNlcXVlbmNlQUk/LnF1ZXJ5KGNzcU5hbWUsIGNzcU5hbWUpO1xuICAgIC8vICAgICBpZiAocmVzcG9uc2UpIHtcbiAgICAvLyAgICAgICB0aGlzLnJlZnJlc2hSZXNpc3RhbmNlT3B0aW9ucyhyb2xsUG9zaXRpb24gYXMgUG9zaXRpb24sIHJvbGxSZXN1bHQgYXMgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbCwgY3NxSUQsIHJlc3BvbnNlLnNwbGl0KFwifFwiKSk7XG4gICAgLy8gICAgIH1cbiAgICAvLyAgIH1cbiAgICAvLyB9XG4gICAgLy8gYXN5bmMgc3Bhd25CbGFua1Jlc2lzdE9wdGlvbihldmVudDogQ2xpY2tFdmVudCkge1xuICAgIC8vICAgaWYgKCF0aGlzLmNzcURhdGEpIHsgcmV0dXJuOyB9XG4gICAgLy8gICBjb25zdCBbcm9sbFBvc2l0aW9uLCByb2xsUmVzdWx0LCBjc3FJRF0gPSB0aGlzLmdldENzcURhdGFGcm9tRWxlbShldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAvLyAgIGNvbnN0IHJDc3FJRCA9IHJhbmRvbUlEKCkgYXMgSURTdHJpbmc7XG4gICAgLy8gICB0aGlzLmNzcURhdGFbcm9sbFBvc2l0aW9uIGFzIFBvc2l0aW9uXVtyb2xsUmVzdWx0IGFzIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWxdW2NzcUlEXVxuICAgIC8vICAgICAucmVzaXN0T3B0aW9ucyA9IHtcbiAgICAvLyAgICAgICBbckNzcUlEXToge1xuICAgIC8vICAgICAgICAgaWQ6IHJDc3FJRCxcbiAgICAvLyAgICAgICAgIG5hbWU6IFwiXCIsXG4gICAgLy8gICAgICAgICB0eXBlOiB1bmRlZmluZWQsXG4gICAgLy8gICAgICAgICBpc1NlbGVjdGVkOiB0cnVlXG4gICAgLy8gICAgICAgfVxuICAgIC8vICAgICB9O1xuICAgIC8vICAgdGhpcy5yZW5kZXIoKTtcbiAgICAvLyB9XG4gICAgLy8gYXN5bmMgc2V0RmxhZ1ZhbCh0YXJnZXQ6IHN0cmluZywgdmFsdWU6IHVua25vd24pIHtcbiAgICAvLyAgIGlmICh0aGlzLnBhcmVudCBpbnN0YW5jZW9mIEJsYWRlc1JvbGwpIHtcbiAgICAvLyAgICAgYXdhaXQgdGhpcy5wYXJlbnQudXBkYXRlVGFyZ2V0KHRhcmdldCwgdmFsdWUpO1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyBhc3luYyByZWZyZXNoUmVzaXN0YW5jZU9wdGlvbnMocm9sbFBvc2l0aW9uOiBQb3NpdGlvbiwgcm9sbFJlc3VsdDogUm9sbFJlc3VsdCwgY0lEOiBzdHJpbmcsIHJPcHRpb25zOiBzdHJpbmdbXSkge1xuICAgIC8vICAgaWYgKCF0aGlzLmNzcURhdGEpIHsgcmV0dXJuOyB9XG4gICAgLy8gICBjb25zdCBjRGF0YSA9IHRoaXMuY3NxRGF0YVtyb2xsUG9zaXRpb25dW3JvbGxSZXN1bHQgYXMgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbF1bY0lEXTtcbiAgICAvLyAgIGlmICghY0RhdGEpIHsgcmV0dXJuOyB9XG4gICAgLy8gICBjb25zdCBjVHlwZSA9IGNEYXRhLnR5cGUgYXMga2V5b2YgdHlwZW9mIENbXCJSZXNpc3RlZENvbnNlcXVlbmNlVHlwZXNcIl07XG4gICAgLy8gICBjb25zdCByVHlwZSA9IEMuUmVzaXN0ZWRDb25zZXF1ZW5jZVR5cGVzW2NUeXBlXSA/PyB1bmRlZmluZWQ7XG4gICAgLy8gICBjb25zdCByZXNpc3RPcHRpb25zOiBSZWNvcmQ8c3RyaW5nLCBCbGFkZXNSb2xsLkNvbnNlcXVlbmNlUmVzaXN0T3B0aW9uPiA9IHt9O1xuICAgIC8vICAgZm9yIChsZXQgaSA9IDA7IGkgPCByT3B0aW9ucy5sZW5ndGg7IGkrKykge1xuICAgIC8vICAgICBjb25zdCBySUQgPSByYW5kb21JRCgpIGFzIElEU3RyaW5nO1xuICAgIC8vICAgICByZXNpc3RPcHRpb25zW3JJRF0gPSB7XG4gICAgLy8gICAgICAgaWQ6IHJJRCxcbiAgICAvLyAgICAgICBuYW1lOiByT3B0aW9uc1tpXSxcbiAgICAvLyAgICAgICBpc1NlbGVjdGVkOiBmYWxzZVxuICAgIC8vICAgICB9O1xuICAgIC8vICAgICBpZiAoclR5cGUpIHtcbiAgICAvLyAgICAgICByZXNpc3RPcHRpb25zW3JJRF0udHlwZSA9IHJUeXBlO1xuICAgIC8vICAgICAgIHJlc2lzdE9wdGlvbnNbcklEXS50eXBlRGlzcGxheSA9IEMuQ29uc2VxdWVuY2VEaXNwbGF5W3JUeXBlXTtcbiAgICAvLyAgICAgICByZXNpc3RPcHRpb25zW3JJRF0uaWNvbiA9IEMuQ29uc2VxdWVuY2VJY29uc1tyVHlwZV07XG4gICAgLy8gICAgIH1cbiAgICAvLyAgIH1cbiAgICAvLyAgIHRoaXMuY3NxRGF0YVtyb2xsUG9zaXRpb25dW3JvbGxSZXN1bHQgYXMgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbF1bY0lEXS5yZXNpc3RPcHRpb25zID0gcmVzaXN0T3B0aW9ucztcbiAgICAvLyAgIGVMb2cuY2hlY2tMb2czKFwiZGlhbG9nXCIsIFwiYWRkUmVzaXN0YW5jZU9wdGlvbnMoKSB0aGlzLmNzcURhdGFcIiwgey4uLnRoaXMuY3NxRGF0YX0pO1xuICAgIC8vICAgdGhpcy5yZW5kZXIoKTtcbiAgICAvLyB9XG4gICAgLy8gYXN5bmMgc2VsZWN0UmVzaXN0T3B0aW9uKGV2ZW50OiBDbGlja0V2ZW50KSB7XG4gICAgLy8gICBpZiAoIXRoaXMuY3NxRGF0YSkgeyByZXR1cm47IH1cbiAgICAvLyAgIGNvbnN0IFtyb2xsUG9zaXRpb24sIHJvbGxSZXN1bHQsIGNzcUlELCByZXNJRF0gPSB0aGlzLmdldENzcURhdGFGcm9tRWxlbShldmVudC5jdXJyZW50VGFyZ2V0LCA0KTtcbiAgICAvLyAgIGVMb2cuY2hlY2tMb2czKFwiZGlhbG9nXCIsIFwiLi4uIEFjdGlvbiBQYXNzZWRcIiwge3JvbGxSZXN1bHQsIGNzcUluZGV4OiBjc3FJRCwgcmVzSW5kZXg6IHJlc0lEfSk7XG4gICAgLy8gICAvLyBHZXQgY29uc2VxdWVuY2UgZGF0YVxuICAgIC8vICAgY29uc3QgY0RhdGEgPSB0aGlzLmNzcURhdGFbcm9sbFBvc2l0aW9uIGFzIFBvc2l0aW9uXVtyb2xsUmVzdWx0IGFzIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWxdW2NzcUlEXTtcbiAgICAvLyAgIGNEYXRhLnJlc2lzdE9wdGlvbnMgPz89IHt9O1xuICAgIC8vICAgLy8gVG9nZ2xlIGNsaWNrZWQgcmVzaXN0YW5jZSBvcHRpb25cbiAgICAvLyAgIGNEYXRhLnJlc2lzdE9wdGlvbnNbcmVzSURdLmlzU2VsZWN0ZWQgPSAhY0RhdGEucmVzaXN0T3B0aW9uc1tyZXNJRF0uaXNTZWxlY3RlZDtcbiAgICAvLyAgIC8vIElmIHJlc2lzdGFuY2Ugb3B0aW9uIGlzIG5vdyBzZWxlY3RlZC4uLlxuICAgIC8vICAgaWYgKGNEYXRhLnJlc2lzdE9wdGlvbnNbcmVzSURdLmlzU2VsZWN0ZWQpIHtcbiAgICAvLyAgICAgLy8gLi4uIGRlc2VsZWN0ICYgaGlkZSBvdGhlciBvcHRpb25zXG4gICAgLy8gICAgIE9iamVjdC5rZXlzKGNEYXRhLnJlc2lzdE9wdGlvbnMpXG4gICAgLy8gICAgICAgLmZpbHRlcigoa2V5KSA9PiBrZXkgIT09IHJlc0lEKVxuICAgIC8vICAgICAgIC5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAvLyAgICAgICAgIE9iamVjdC5hc3NpZ24oY0RhdGEucmVzaXN0T3B0aW9ucz8uW2tleV0gPz8ge30sIHtpc1NlbGVjdGVkOiBmYWxzZSwgaXNWaXNpYmxlOiBmYWxzZX0pO1xuICAgIC8vICAgICAgIH0pO1xuICAgIC8vICAgICAvLyAuLi4gYW5kIHNldCAncmVzaXN0VG8nIHRvIHRoaXMgY29uc2VxdWVuY2UuXG4gICAgLy8gICAgIGNEYXRhLnJlc2lzdFRvID0gY0RhdGEucmVzaXN0T3B0aW9uc1tyZXNJRF07XG4gICAgLy8gICB9IGVsc2Uge1xuICAgIC8vICAgICAvLyBPdGhlcndpc2UsIHNldCAncmVzaXN0VG8nIHRvIGZhbHNlLi4uXG4gICAgLy8gICAgIGNEYXRhLnJlc2lzdFRvID0gZmFsc2U7XG4gICAgLy8gICAgIC8vIC4uLiBhbmQgdW5oaWRlIG90aGVyIG9wdGlvbnMuXG4gICAgLy8gICAgIE9iamVjdC5rZXlzKGNEYXRhLnJlc2lzdE9wdGlvbnMpXG4gICAgLy8gICAgICAgLmZpbHRlcigoa2V5KSA9PiBrZXkgIT09IHJlc0lEKVxuICAgIC8vICAgICAgIC5mb3JFYWNoKChrZXkpID0+IHtcbiAgICAvLyAgICAgICAgIE9iamVjdC5hc3NpZ24oY0RhdGEucmVzaXN0T3B0aW9ucz8uW2tleV0gPz8ge30sIHtpc1Zpc2libGU6IHRydWV9KTtcbiAgICAvLyAgICAgICB9KTtcbiAgICAvLyAgIH1cbiAgICAvLyAgIC8vIEFzc2lnbiBuZXcgY0RhdGEgaW5zdGFuY2UuXG4gICAgLy8gICB0aGlzLmNzcURhdGFbcm9sbFBvc2l0aW9uIGFzIFBvc2l0aW9uXVtyb2xsUmVzdWx0IGFzIFJvbGxSZXN1bHQucGFydGlhbHxSb2xsUmVzdWx0LmZhaWxdW2NzcUlEXSA9IGNEYXRhO1xuICAgIC8vICAgdGhpcy5yZW5kZXIoKTtcbiAgICAvLyB9XG4gICAgLy8gYXN5bmMgY2xlYXJSZXNpc3RPcHRpb25zKGV2ZW50OiBDb250ZXh0TWVudUV2ZW50KSB7XG4gICAgLy8gICBpZiAoIXRoaXMuY3NxRGF0YSkgeyByZXR1cm47IH1cbiAgICAvLyAgIGNvbnN0IFtyb2xsUG9zaXRpb24sIHJvbGxSZXN1bHQsIGNzcUlEXSA9IHRoaXMuZ2V0Q3NxRGF0YUZyb21FbGVtKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgIC8vICAgdGhpcy5jc3FEYXRhW3JvbGxQb3NpdGlvbiBhcyBQb3NpdGlvbl1bcm9sbFJlc3VsdCBhcyBSb2xsUmVzdWx0LnBhcnRpYWx8Um9sbFJlc3VsdC5mYWlsXVtjc3FJRF0ucmVzaXN0T3B0aW9ucyA9IHt9O1xuICAgIC8vICAgdGhpcy5yZW5kZXIoKTtcbiAgICAvLyB9XG4gICAgLy8gYXN5bmMgdG9nZ2xlQXJtb3IoZXZlbnQ6IENsaWNrRXZlbnQpIHtcbiAgICAvLyAgIGlmICghdGhpcy5jc3FEYXRhKSB7IHJldHVybjsgfVxuICAgIC8vICAgY29uc3QgW3JvbGxQb3NpdGlvbiwgcm9sbFJlc3VsdCwgY3NxSURdID0gdGhpcy5nZXRDc3FEYXRhRnJvbUVsZW0oZXZlbnQuY3VycmVudFRhcmdldCk7XG4gICAgLy8gICBjb25zdCBjRGF0YSA9IHRoaXMuY3NxRGF0YVtyb2xsUG9zaXRpb24gYXMgUG9zaXRpb25dW3JvbGxSZXN1bHQgYXMgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbF1bY3NxSURdO1xuICAgIC8vICAgY0RhdGEuY2FuQXJtb3IgPSAhY0RhdGEuY2FuQXJtb3I7XG4gICAgLy8gICB0aGlzLnJlbmRlcigpO1xuICAgIC8vIH1cbiAgICAvLyBhc3luYyB0b2dnbGVTcGVjaWFsQXJtb3IoZXZlbnQ6IENsaWNrRXZlbnQpIHtcbiAgICAvLyAgIGlmICghdGhpcy5jc3FEYXRhKSB7IHJldHVybjsgfVxuICAgIC8vICAgY29uc3QgW3JvbGxQb3NpdGlvbiwgcm9sbFJlc3VsdCwgY3NxSURdID0gdGhpcy5nZXRDc3FEYXRhRnJvbUVsZW0oZXZlbnQuY3VycmVudFRhcmdldCk7XG4gICAgLy8gICBjb25zdCBjRGF0YSA9IHRoaXMuY3NxRGF0YVtyb2xsUG9zaXRpb24gYXMgUG9zaXRpb25dW3JvbGxSZXN1bHQgYXMgUm9sbFJlc3VsdC5wYXJ0aWFsfFJvbGxSZXN1bHQuZmFpbF1bY3NxSURdO1xuICAgIC8vICAgY0RhdGEuY2FuU3BlY2lhbEFybW9yID0gIWNEYXRhLmNhblNwZWNpYWxBcm1vcjtcbiAgICAvLyAgIHRoaXMucmVuZGVyKCk7XG4gICAgLy8gfVxuICAgIGFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpIHtcbiAgICAgICAgc3VwZXIuYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgIC8vIH4gVG9vbHRpcHNcbiAgICAgICAgQXBwbHlUb29sdGlwQW5pbWF0aW9ucyhodG1sKTtcbiAgICAgICAgc3dpdGNoICh0aGlzLmRpYWxvZ1R5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgQmxhZGVzRGlhbG9nVHlwZS5JbnB1dDpcbiAgICAgICAgICAgICAgICB0aGlzLmFjdGl2YXRlSW5wdXRMaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIEJsYWRlc0RpYWxvZ1R5cGUuU2VsZWN0aW9uOlxuICAgICAgICAgICAgICAgIHRoaXMuYWN0aXZhdGVTZWxlY3Rpb25MaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAvLyBjYXNlIEJsYWRlc0RpYWxvZ1R5cGUuQ29uc2VxdWVuY2U6IHtcbiAgICAgICAgICAgIC8vIHRoaXMuYWN0aXZhdGVDb25zZXF1ZW5jZUxpc3RlbmVycyhodG1sKTtcbiAgICAgICAgICAgIC8vIFNlbGVjdCAtLT4gdXBkYXRlQ29uc2VxdWVuY2VEaWFsb2cgLT4gdXBkYXRlQ29uc2VxdWVuY2VEYXRhKGVhY2ggY3NxKVxuICAgICAgICAgICAgLy8gYnJlYWs7XG4gICAgICAgICAgICAvLyB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgYWN0aXZhdGVJbnB1dExpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIGh0bWwuZmluZChcInRleHRhcmVhXCIpLm9uKHsgY2hhbmdlOiAoZXZlbnQpID0+IHRoaXMudXBkYXRlSW5wdXRUZXh0KCQoZXZlbnQuY3VycmVudFRhcmdldCkpIH0pO1xuICAgIH1cbiAgICBhY3RpdmF0ZVNlbGVjdGlvbkxpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICAvLyB+IENoYW5naW5nIFdpZHRoIG9uIFRhYiBDaGFuZ2UgRGVwZW5kaW5nIG9uIE51bWJlciBvZiBJdGVtc1xuICAgICAgICBodG1sLmZpbmQoXCIubmF2LXRhYnMgLnRhYi1zZWxlY3RvclwiKS5vbihcImNsaWNrXCIsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdGFiSW5kZXggPSBVLnBJbnQoJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwidGFiXCIpKTtcbiAgICAgICAgICAgIGNvbnN0IG51bUl0ZW1zID0gT2JqZWN0LnZhbHVlcyhzZWxmLnRhYnMgPz8gW10pW3RhYkluZGV4XS5sZW5ndGg7XG4gICAgICAgICAgICBjb25zdCB3aWR0aCA9IFUucEludCgxNTAgKiBNYXRoLmNlaWwoTWF0aC5zcXJ0KG51bUl0ZW1zKSkpO1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJuYXZcIiwgXCJOYXYgVGFiIFNpemUgUmVjYWxjdWxhdGlvblwiLCB7IHRhYkluZGV4LCBudW1JdGVtcywgd2lkdGggfSk7XG4gICAgICAgICAgICB0aGlzLnJlbmRlcihmYWxzZSwgeyB3aWR0aCB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIH4gSXRlbSBDb250cm9sXG4gICAgICAgIGh0bWwuZmluZChcIltkYXRhLWl0ZW0taWRdXCIpLm9uKFwiY2xpY2tcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKCQodGhpcykucGFyZW50KCkuaGFzQ2xhc3MoXCJsb2NrZWRcIikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBkb2NJZCA9ICQodGhpcykuZGF0YShcIml0ZW1JZFwiKTtcbiAgICAgICAgICAgIGNvbnN0IGRvY1R5cGUgPSAkKHRoaXMpLmRhdGEoXCJkb2NUeXBlXCIpO1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZyhcImRpYWxvZ1wiLCBcIltCbGFkZXNEaWFsb2ddIG9uIENsaWNrXCIsIHsgZWxlbTogdGhpcywgZG9jSWQsIGRvY1R5cGUsIHBhcmVudDogc2VsZi5wYXJlbnQgfSk7XG4gICAgICAgICAgICBpZiAoc2VsZi5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNBY3Rvcikge1xuICAgICAgICAgICAgICAgIGlmIChkb2NUeXBlID09PSBcIkFjdG9yXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5wYXJlbnQuYWRkU3ViQWN0b3IoZG9jSWQsIHNlbGYudGFncyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKGRvY1R5cGUgPT09IFwiSXRlbVwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGFyZW50LmFkZFN1Ykl0ZW0oZG9jSWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbGYuY2xvc2UoKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGNsb3NlKCkge1xuICAgICAgICAkKFwiI2V1bm9zLWJsYWRlcy10b29sdGlwcyA+ICpcIikucmVtb3ZlKCk7XG4gICAgICAgIHN1cGVyLmNsb3NlKCk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzRGlhbG9nO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/classes/BladesDialog.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesDirector.ts": +/*!**************************************!*\ + !*** ./ts/classes/BladesDirector.ts ***! + \**************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\nclass BladesDirector {\n // #region INITIALIZATION ~\n // #region >> Single-Instance Factory Construction ~\n static instance;\n _id;\n constructor() {\n this._id = randomID();\n }\n static getInstance() {\n return (BladesDirector.instance ??= new BladesDirector());\n }\n // #endregion\n static async Initialize() {\n // Define hook that re-renders overlay on scene change.\n Hooks.on(\"renderApplication\", async () => {\n game.eunoblades.Director.initClockKeySection(true);\n if (game.user.isGM) {\n await game.eunoblades.ClockKeeper.update({ \"system.targetScene\": game.scenes.current.id });\n game.eunoblades.ClockKeeper.render();\n }\n });\n // game.eunoblades.Director.renderOverlay_SocketResponse();\n // Return asynchronous template loading.\n return loadTemplates([\n \"systems/eunos-blades/templates/overlay/blades-overlay.hbs\",\n \"systems/eunos-blades/templates/overlay/location.hbs\",\n \"systems/eunos-blades/templates/overlay/score-panel.hbs\",\n \"systems/eunos-blades/templates/overlay/npc-portrait.hbs\",\n \"systems/eunos-blades/templates/overlay/pc-portrait.hbs\",\n \"systems/eunos-blades/templates/overlay/cohort-portrait.hbs\",\n \"systems/eunos-blades/templates/overlay/crew-status-bar.hbs\",\n \"systems/eunos-blades/templates/overlay/game-phase-bar.hbs\",\n \"systems/eunos-blades/templates/overlay/notices/push.hbs\"\n ]);\n }\n // #region >> Sockets ~\n static InitSockets() {\n const director = BladesDirector.getInstance();\n socketlib.system.register(\"renderOverlay_SocketCall\", director.renderOverlay_SocketResponse.bind(director));\n director.initClockSockets();\n director.initScorePanelSockets();\n director.initLocationSockets();\n director.initNPCSockets();\n director.initPCSockets();\n director.initCohortSockets();\n director.initCrewSockets();\n director.initNotificationSockets();\n director.initTransitionSockets();\n }\n // #endregion\n // #endregion\n // #region OVERLAY ~\n // #region >> Overlay Elements$ ~\n _overlayContainer;\n _overlayContainer$;\n get overlayContainer() {\n if (!this._overlayContainer) {\n [this._overlayContainer] = $(\"#blades-overlay\");\n }\n if (!this._overlayContainer) {\n $(\"body.vtt\").append(\"
\");\n [this._overlayContainer] = $(\"#blades-overlay\");\n }\n return this._overlayContainer;\n }\n get overlayContainer$() {\n if (!this._overlayContainer$) {\n this._overlayContainer$ = $(this.overlayContainer);\n }\n return this._overlayContainer$;\n }\n get clockKeySection$() {\n return this.overlayContainer$.find(\".overlay-section-clock-keys\");\n }\n get locationSection$() {\n return this.overlayContainer$.find(\".overlay-section-location\");\n }\n get scorePanelSection$() {\n return this.overlayContainer$.find(\".overlay-section-score-panel\");\n }\n get npcSection$() {\n return this.overlayContainer$.find(\".overlay-section-npcs\");\n }\n get playerSection$() {\n return this.overlayContainer$.find(\".overlay-section-players\");\n }\n get crewSection$() {\n return this.overlayContainer$.find(\".overlay-section-crew\");\n }\n get notificationSection$() {\n return this.overlayContainer$.find(\".overlay-section-notifications\");\n }\n get transitionSection$() {\n return this.overlayContainer$.find(\".overlay-section-transitions\");\n }\n get tooltipSection$() {\n return this.overlayContainer$.find(\".overlay-section-tooltips\");\n }\n get svgData() { return _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKey_SVGDATA; }\n // #endregion\n // #region >> Rendering ~\n renderOverlay_SocketCall() {\n if (!game.user.isGM) {\n return;\n }\n if (!this.overlayContainer) {\n return;\n }\n socketlib.system.executeForEveryone(\"renderOverlay_SocketCall\");\n }\n async renderOverlay_SocketResponse() {\n // Render the overlay element\n const overlayContent = await renderTemplate(\"systems/eunos-blades/templates/overlay/blades-overlay.hbs\", this);\n this.overlayContainer$.empty().append(overlayContent);\n // Initialize clock key section\n this.initClockKeySection();\n // Initialize tooltip section\n this.initTooltipSection();\n }\n // #endregion\n // #endregion\n // #region CLOCKS & CLOCK KEYS ~\n // #region >> INITIALIZATION ~\n initClockKeySection(isResetting = false) {\n if (isResetting) {\n this.clockKeySection$.empty();\n }\n // Render keys that are visible\n const visibleSceneKeys = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].shuffle(this.sceneKeys.filter((key) => key.isVisible));\n let staggerDelay = 0;\n while (visibleSceneKeys.length) {\n const key = visibleSceneKeys.shift();\n if (key) {\n setTimeout(() => this.renderClockKey(key), staggerDelay * 1000);\n staggerDelay += 0.5;\n }\n }\n // Apply item dragger\n setTimeout(() => {\n // Create dragger instance for dragging clocks & clock keys onto, e.g, rolls\n }, staggerDelay * 1000);\n }\n initClockSockets() {\n socketlib.system.register(\"renderClockKey_SocketCall\", BladesDirector.renderClockKey_SocketResponse.bind(BladesDirector));\n socketlib.system.register(\"pullKey_SocketCall\", BladesDirector.pullKey_SocketResponse.bind(BladesDirector));\n socketlib.system.register(\"fadeInName_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fadeInName_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__[\"default\"]));\n socketlib.system.register(\"fadeOutName_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__[\"default\"].fadeOutName_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__[\"default\"]));\n socketlib.system.register(\"reveal_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.reveal_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"hide_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.hide_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"activate_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.activate_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"deactivate_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.deactivate_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"fadeInClockName_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.fadeInClockName_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"fadeOutClockName_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.fadeOutClockName_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"highlight_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.highlight_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"unhighlight_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.unhighlight_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n socketlib.system.register(\"changeSegments_SocketCall\", _BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock.changeSegments_SocketResponse.bind(_BladesClockKey__WEBPACK_IMPORTED_MODULE_2__.BladesClock));\n }\n // #endregion\n get sceneKeys() { return game.eunoblades.ClockKeeper.getSceneKeys(game.scenes.current.id); }\n // #region >> Rendering (Dropping) Clock Keys ~\n dropKey_Animation(key, keyElems$) {\n const { container$, label$, imgContainer$, clocks } = keyElems$ ?? key.getElements$(game.eunoblades.Director.clockKeySection$);\n const keySwingTimeline = imgContainer$.data(\"keySwingTimeline\");\n // Construct timeline for revealing clock key\n const tl = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .call(() => { keySwingTimeline.seek(\"NEUTRAL\").play(); })\n .from(container$, {\n y: -800,\n ease: \"bounce\",\n duration: 1\n }, 0)\n .to(container$, { autoAlpha: 1, duration: 0.5, ease: \"power2\" }, 0);\n // Reveal visible clocks\n key.visibleClocks.forEach((clock, i) => {\n tl.add(() => { clock.reveal_Animation(clocks[clock.id]); }, i === 0 ? \">\" : \"<+0.15\");\n });\n // Reveal key label, if visible\n if (key.name && key.isNameVisible) {\n tl.blurReveal(label$, {\n ignoreMargin: true,\n duration: 0.75\n }, \"<+0.05\");\n }\n }\n prepareClockKeyTimelines(key, keyElems$) {\n const { container$, imgContainer$, elem$, label$, clocks } = keyElems$;\n // Initialize element starting properties\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(container$, { pointerEvents: \"auto\" });\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(elem$, { filter: \"brightness(1)\" });\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(imgContainer$, { transformOrigin: \"50% 10%\" });\n // Retrieve element starting properties\n const keyElemScale = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.getProperty(container$[0], \"scale\");\n // Timeline: Swinging key timeline\n imgContainer$.data(\"keySwingTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ paused: true, repeat: -1, yoyo: true })\n .fromTo(imgContainer$, { rotateZ: -1 }, { rotateZ: 1, duration: 3, ease: \"sine.inOut\" })\n .addLabel(\"NEUTRAL\", 1.5)\n .seek(\"NEUTRAL\"));\n // Timeline: Hover over clock key\n container$.data(\"hoverOverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n paused: true,\n data: { key, imgContainer$, label$, isNameRevealed: false },\n onStart() {\n this.data.imgContainer$.data(\"keySwingTimeline\")\n .tweenTo(\"NEUTRAL\", {\n duration: 0.25,\n ease: \"back.out(1.5)\"\n });\n if (this.data.key.name && !this.data.key.isNameVisible) {\n this.data.isNameRevealed = true;\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurReveal(this.data.label$, {\n ignoreMargin: true,\n duration: 0.5\n });\n }\n },\n onReverseComplete() {\n this.data.imgContainer$.data(\"keySwingTimeline\")\n .seek(\"NEUTRAL\")\n .play();\n if (this.data.isNameRevealed) {\n this.data.isNameRevealed = false;\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurRemove(this.data.label$, {\n ignoreMargin: true,\n duration: 0.5\n });\n }\n }\n })\n .to(elem$, { filter: \"brightness(1.5)\", scale: keyElemScale * 1.25, duration: 0.5, ease: \"sine\" }));\n // Timelines: Hover over clocks\n key.clocks.forEach((clock) => {\n const { clockContainer$, clockLabel$, clockElem$ } = clocks[clock.id];\n if (!clockContainer$?.length) {\n throw new Error(`[BladesDirector.prepareClockKeyTimelines] Error clockContainer$ not found for clock '${clock.id}' of key '${key.id}'.`);\n }\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(clockContainer$, { pointerEvents: \"auto\" });\n clockContainer$.data(\"hoverOverTimeline\", _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n paused: true,\n data: { clock, clockLabel$, isNameRevealed: false },\n onStart() {\n if (this.data.clock.name && !this.data.clock.isNameVisible) {\n this.data.isNameRevealed = true;\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurReveal(this.data.clockLabel$, {\n ignoreMargin: true,\n duration: 0.5\n });\n }\n },\n onReverseComplete() {\n if (this.data.isNameRevealed) {\n this.data.isNameRevealed = false;\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurRemove(this.data.clockLabel$, {\n ignoreMargin: true,\n duration: 0.5\n });\n }\n }\n })\n .to(clockElem$, { filter: \"brightness(1.5)\", scale: 1.25, duration: 0.25, ease: \"sine\" }));\n });\n }\n async activateClockKeyListeners(key, keyElems$) {\n const { container$, clocks } = keyElems$;\n if (game.user.isGM) {\n // === GM-ONLY LISTENERS ===\n // Double-Click a Clock Key = Open ClockKeeper sheet\n container$.on(\"dblclick\", async () => {\n game.eunoblades.ClockKeeper.sheet?.render(true);\n });\n // Right-Click a Clock Key = Pull it\n container$.on(\"contextmenu\", async () => {\n this.pullKey_SocketCall(key.id);\n key.updateTarget(\"isVisible\", false);\n });\n }\n else {\n // === PLAYER-ONLY LISTENERS ===\n // Add listeners to container for mouseenter and mouseleave, that play and reverse timeline attached to element\n container$.on(\"mouseenter\", () => {\n container$.data(\"hoverOverTimeline\").play();\n }).on(\"mouseleave\", () => {\n container$.data(\"hoverOverTimeline\").reverse();\n });\n // Now repeat this for each clock in the clock key\n key.clocks.forEach((clock) => {\n const { clockContainer$ } = clocks[clock.id];\n // Add listeners to clock for mouseenter and mouseleave, that play and reverse timeline attached to element\n clockContainer$.on(\"mouseenter\", () => {\n if (clock.isVisible) {\n clockContainer$.data(\"hoverOverTimeline\").play();\n }\n }).on(\"mouseleave\", () => {\n if (clock.isVisible) {\n clockContainer$.data(\"hoverOverTimeline\").reverse();\n }\n });\n });\n }\n }\n async renderClockKey(key) {\n await key.renderTo(this.clockKeySection$);\n // If a position-dragger is present, remove it.\n if (key.positionDragger) {\n key.removePositionDragger();\n }\n // Initialize clock key elements to overlay context\n const keyElems$ = key.initElementsInContext(this.clockKeySection$, _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKeyDisplayMode.full);\n // If an overlayPosition has been set, apply to the container element:\n if (key.overlayPosition) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(keyElems$.container$, {\n left: key.overlayPosition.x,\n top: key.overlayPosition.y\n });\n }\n // Prepare animation timelines & attach them to rendered elements\n this.prepareClockKeyTimelines(key, keyElems$);\n // Activate listeners for the rendered key\n this.activateClockKeyListeners(key, keyElems$);\n // Animate the key dropping into the overlay\n this.dropKey_Animation(key, keyElems$);\n }\n async renderClockKey_SocketCall(keyID) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"renderClockKey_SocketCall\", keyID);\n }\n static async renderClockKey_SocketResponse(keyID) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n game.eunoblades.Director.renderClockKey(key);\n }\n // #endregion\n // #region >> Un-Rendering (Pulling) Clock Keys ~\n pullKey_Animation(key) {\n const { container$ } = key.getElements$(game.eunoblades.Director.clockKeySection$);\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .to(container$, {\n y: -800,\n ease: \"back.in(1)\",\n duration: 0.75\n })\n .to(container$, {\n opacity: 0,\n ease: \"power2.out\",\n duration: 0.25\n }, 0.75)\n .call(() => { container$.remove(); });\n }\n async pullKey_SocketCall(keyID) {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForEveryone(\"pullKey_SocketCall\", keyID);\n }\n static pullKey_SocketResponse(keyID) {\n const key = game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n game.eunoblades.Director.pullKey_Animation(key);\n }\n // #endregion\n // #endregion\n // #region SCORE PANEL ~\n // #region >> INITIALIZATION ~\n initScorePanelSockets() {\n // tbd...\n }\n // #endregion\n // ## Score Details\n // - Small panel overlapping corner of Location\n // - Engagement roll result\n // - Plan & Detail\n // - Target tier\n activateScorePanelListeners() {\n // tbd...\n }\n // #endregion\n // #region LOCATIONS ~\n // #region >> INITIALIZATION ~\n initLocationSockets() {\n // tbd...\n }\n // #endregion\n // ## Locations\n // - District wrapper/header\n // - Faction wrapper/footer\n // - Location main\n // - Slide-scroll of sublocations\n activateLocationListeners() {\n // tbd...\n }\n // #endregion\n // #region NPCs ~\n // #region >> INITIALIZATION ~\n initNPCSockets() {\n // tbd...\n }\n // #endregion// ## NPCs\n // - Linked to a location: When location is displayed, so are they. *(Can be linked to District wrapper, main Location, or sublocations)*\n // - Portrait images close to the central location display, hover-over popups provide more detailed information from sheet or `BladesScore` instance\n activateNPCListeners() {\n // tbd...\n }\n // #endregion\n // #region PCs, COHORTs, CREW ~\n // #region >> INITIALIZATION ~\n initPCSockets() {\n // tbd...\n }\n initCohortSockets() {\n // tbd...\n }\n initCrewSockets() {\n // tbd...\n }\n // #endregion\n // ## PCs\n // - Display panels along bottom\n // - Signal lights\n activatePCListeners() {\n // tbd...\n }\n // ## Cohorts\n // - Smaller panels alongside the PCs\n activateCohortListeners() {\n // tbd...\n }\n // ## Crew\n // - Limited information displayed, maybe bar beneath PCs showing Heat, Wanted Level…\n activateCrewListeners() {\n // tbd...\n }\n // #endregion\n // #region NOTIFICATIONS ~\n // #region >> INITIALIZATION ~\n initNotificationSockets() {\n socketlib.system.register(\"pushNotice_SocketCall\", BladesDirector.pushNotice_SocketResponse.bind(BladesDirector));\n }\n // #endregion\n pushNotice_SocketCall(targets, config) {\n const pushID = randomID();\n if (typeof targets === \"string\") {\n if (targets === \"ALL\") {\n return socketlib.system.executeForEveryone(\"pushNotice_SocketCall\", pushID, config);\n }\n else if (targets === \"GM\") {\n return socketlib.system.executeForAllGMs(\"pushNotice_SocketCall\", pushID, config);\n }\n else {\n targets = game.users.filter((user) => user.id === targets\n || user.name === targets\n || user.character?.id === targets\n || user.character?.name === targets\n || game.user.isGM).map((user) => user.id);\n }\n }\n if (targets.length > 0) {\n return socketlib.system.executeForUsers(\"pushNotice_SocketCall\", targets, pushID, config);\n }\n return undefined;\n }\n static async pushNotice_SocketResponse(pushID, config) {\n const director = game.eunoblades.Director;\n const pushElem$ = $(await renderTemplate(\"systems/eunos-blades/templates/overlay/notices/push.hbs\", {\n id: pushID,\n ...config\n }))\n .appendTo(director.notificationSection$)\n .on(\"click\", (event) => { director.$removePush(event.currentTarget); })\n .on(\"contextmenu\", (event) => { director.$removeAndClear(event.currentTarget); });\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.fromTo(pushElem$, {\n x: 200,\n skewX: 20,\n autoAlpha: 0,\n filter: \"blur(10px)\"\n }, {\n x: 0,\n skewX: 0,\n autoAlpha: 1,\n filter: \"blur(0px)\",\n duration: 0.5,\n ease: \"back\"\n });\n }\n async $removePush(target) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.to(target, {\n x: \"+=200\",\n autoAlpha: 0,\n ease: \"power2\",\n duration: 0.5,\n onComplete: function () {\n $(target).remove();\n }\n });\n }\n async $removeAndClear(target) {\n const targets = $(target).prevAll().get().reverse();\n targets.unshift(target);\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.to(targets, {\n x: \"+=200\",\n autoAlpha: 0,\n ease: \"power2\",\n duration: 0.5,\n stagger: {\n each: 0.5,\n from: \"start\",\n ease: \"power1.inOut\"\n },\n onComplete: function () {\n targets.forEach((targ) => $(targ).remove());\n }\n });\n }\n // #endregion\n // #region TRANSITIONS ~\n // #region >> INITIALIZATION ~\n initTransitionSockets() {\n // tbd...\n }\n // #endregion\n // ## Transitions\n async advanceGamePhase(phase) {\n const nextPhase = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.wrap(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase), Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase).indexOf(phase ?? game.eunoblades.Tracker?.phase ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Freeplay) + 1);\n }\n // - As with notifications: placeholder animation until something more final can be coded.\n // #endregion\n // #region TOOLTIPS ~\n _tooltipObserver;\n _tooltipElems = new Map();\n _displayedTooltipID;\n /**\n * Adjusts the tooltip's position to ensure it remains within its parent container using jQuery methods.\n * @param tooltip - The tooltip element, which can be either an HTMLElement or a JQuery.\n */\n adjustTooltipPosition(tooltip$) {\n // Validate tooltip position style\n if (tooltip$.css(\"position\") !== \"absolute\") {\n throw new Error(\"Tooltip position must be 'absolute'.\");\n }\n // Calculate bounds and directly apply necessary shifts to the tooltip element\n const tooltipRect = tooltip$[0].getBoundingClientRect();\n const containerRect = this.tooltipSection$[0].getBoundingClientRect();\n // Initial position of the tooltip\n const currentTop = tooltip$.position().top;\n const currentLeft = tooltip$.position().left;\n // Check for right overflow and adjust left position if necessary\n if (tooltipRect.right > containerRect.right) {\n const xShift = containerRect.right - tooltipRect.right;\n tooltip$.css(\"left\", `${currentLeft + xShift}px`);\n }\n // Check for left overflow and adjust left position if necessary\n else if (tooltipRect.left < containerRect.left) {\n const xShift = containerRect.left - tooltipRect.left;\n tooltip$.css(\"left\", `${currentLeft + xShift}px`);\n }\n // Check for bottom overflow and adjust top position if necessary\n if (tooltipRect.bottom > containerRect.bottom) {\n const yShift = containerRect.bottom - tooltipRect.bottom;\n tooltip$.css(\"top\", `${currentTop + yShift}px`);\n }\n // Check for top overflow and adjust top position if necessary\n else if (tooltipRect.top < containerRect.top) {\n const yShift = containerRect.top - tooltipRect.top;\n tooltip$.css(\"top\", `${currentTop + yShift}px`);\n }\n }\n displayTooltip(tooltip) {\n if (!tooltip.id) {\n throw new Error(\"Tooltip must have an ID to be cloned to the overlay.\");\n }\n this._displayedTooltipID = tooltip.id;\n const self = this;\n // Clear out any other tooltips in the overlay.\n game.eunoblades.Director.clearTooltips();\n if (!this._tooltipElems.has(tooltip.id)) {\n // Create cloned tooltip and attach it to the tooltip overlay.\n const ttClone$ = $(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].changeContainer(tooltip, game.eunoblades.Director.tooltipSection$[0], true));\n // Adjust the tooltip's position so it does not overflow the tooltip container\n this.adjustTooltipPosition(ttClone$);\n // Generate the reveal timeline and attach it to the cloned tooltip element.\n const revealTimeline = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurRevealTooltip(ttClone$[0], {\n onReverseComplete() {\n if (ttClone$.attr(\"id\") === self._displayedTooltipID) {\n delete self._displayedTooltipID;\n }\n game.eunoblades.Director._tooltipElems.delete(ttClone$.attr(\"id\"));\n game.eunoblades.Director.tooltipSection$.find(`#${ttClone$.attr(\"id\")}`).remove();\n game.eunoblades.Director.tooltipSection$.children(\"[style*='opacity: 0'], [style*='opacity:0']\").each(function () {\n const id = this.id; // Get the ID of the current element\n if (id === self._displayedTooltipID) {\n return;\n }\n if (id) {\n game.eunoblades.Director._tooltipElems.delete(id); // Remove from the map if the ID exists\n }\n $(this).remove(); // Remove the element from the DOM\n });\n }\n });\n ttClone$.data(\"revealTimeline\", revealTimeline);\n // Register the cloned tooltip element to the master map\n this._tooltipElems.set(tooltip.id, ttClone$);\n }\n // Play the timeline.\n this._tooltipElems.get(tooltip.id)?.data(\"revealTimeline\")?.play();\n }\n clearTooltip(tooltipID, isClearingIfTweening = true) {\n if (tooltipID === this._displayedTooltipID) {\n delete this._displayedTooltipID;\n }\n const ttElem = game.eunoblades.Director._tooltipElems.get(tooltipID);\n if (!ttElem) {\n return;\n }\n const ttTimeline = ttElem.data(\"revealTimeline\");\n if (ttTimeline.isActive() && !isClearingIfTweening) {\n return;\n }\n ttTimeline.reverse();\n }\n clearTooltips() {\n eLog.checkLog3(\"Observer\", \"Observer Triggered!\");\n // Look for tooltip elements in the overlay container, and remove them.\n game.eunoblades.Director._tooltipElems.forEach((ttElem) => {\n if (ttElem.attr(\"id\") === this._displayedTooltipID) {\n return;\n }\n game.eunoblades.Director.clearTooltip(ttElem.attr(\"id\"), true);\n });\n }\n initTooltipSection() {\n const self = this;\n this.clearTooltips();\n // Reset tooltip observer\n this._tooltipObserver?.kill();\n // Simplified throttle function that takes a function with Observer parameter\n const throttle = (func, limit) => {\n let lastFunc;\n let lastRan;\n return function (obs) {\n const now = Date.now();\n if (!lastRan || now - lastRan >= limit) {\n func(obs);\n lastRan = now;\n }\n else {\n clearTimeout(lastFunc);\n lastFunc = window.setTimeout(() => {\n if (now - lastRan >= limit) {\n func(obs);\n lastRan = now;\n }\n }, limit - (now - lastRan));\n }\n };\n };\n // Throttled onMove callback\n const throttledOnMove = throttle((obs) => {\n // Calculate the absolute magnitude of velocity independent of direction\n const magnitudeOfVelocity = Math.sqrt((obs.velocityX ** 2) + (obs.velocityY ** 2));\n if (magnitudeOfVelocity >= _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].MIN_MOUSE_MOVEMENT_THRESHOLD) {\n self.clearTooltips();\n }\n }, 200); // Adjust 200ms to your preferred throttling limit\n this._tooltipObserver = Observer.create({\n type: \"touch,pointer\",\n // onMove: throttledOnMove,\n onClick() {\n self.clearTooltips();\n }\n });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesDirector);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsYUFBYTtBQUM3QixRQUFRLHVEQUFDO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1QsMEJBQTBCLHNCQUFzQjtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxzQ0FBc0MsNENBQTRDO0FBQ2xGLDRDQUE0QyxnREFBZ0Q7QUFDNUYsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSx1REFBQztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLHVEQUFDLCtCQUErQix3REFBVyxpQkFBaUIsd0RBQVcscURBQXFELHdEQUFXO0FBQ2pLO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLHFCQUFxQjtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyxxQkFBcUI7QUFDekQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsb0JBQW9CO0FBQ3ZEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLG9CQUFvQjtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsdURBQUM7QUFDaEM7QUFDQTtBQUNBO0FBQ0EsbUNBQW1DLHVEQUFDO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzRUFBc0Usb0JBQW9CO0FBQzFGO0FBQ0EsNENBQTRDO0FBQzVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0VBQStFO0FBQy9FO0FBQ0EsMENBQTBDO0FBQzFDLHFCQUFxQjtBQUNyQjtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsdURBQUM7QUFDeEM7QUFDQTtBQUNBLFNBQVMsUUFBUTtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLCtEQUFlLGNBQWMsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NsYXNzZXMvQmxhZGVzRGlyZWN0b3IudHM/ZWYzYSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmltcG9ydCBVIGZyb20gXCIuLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IEMsIHsgQ2xvY2tLZXlfU1ZHREFUQSwgQmxhZGVzUGhhc2UsIENsb2NrS2V5RGlzcGxheU1vZGUgfSBmcm9tIFwiLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBCbGFkZXNDbG9ja0tleSwgeyBCbGFkZXNDbG9jayB9IGZyb20gXCIuL0JsYWRlc0Nsb2NrS2V5XCI7XG5jbGFzcyBCbGFkZXNEaXJlY3RvciB7XG4gICAgLy8gI3JlZ2lvbiBJTklUSUFMSVpBVElPTiB+XG4gICAgLy8gI3JlZ2lvbiAgID4+ICBTaW5nbGUtSW5zdGFuY2UgRmFjdG9yeSBDb25zdHJ1Y3Rpb24gflxuICAgIHN0YXRpYyBpbnN0YW5jZTtcbiAgICBfaWQ7XG4gICAgY29uc3RydWN0b3IoKSB7XG4gICAgICAgIHRoaXMuX2lkID0gcmFuZG9tSUQoKTtcbiAgICB9XG4gICAgc3RhdGljIGdldEluc3RhbmNlKCkge1xuICAgICAgICByZXR1cm4gKEJsYWRlc0RpcmVjdG9yLmluc3RhbmNlID8/PSBuZXcgQmxhZGVzRGlyZWN0b3IoKSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBzdGF0aWMgYXN5bmMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgLy8gRGVmaW5lIGhvb2sgdGhhdCByZS1yZW5kZXJzIG92ZXJsYXkgb24gc2NlbmUgY2hhbmdlLlxuICAgICAgICBIb29rcy5vbihcInJlbmRlckFwcGxpY2F0aW9uXCIsIGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5EaXJlY3Rvci5pbml0Q2xvY2tLZXlTZWN0aW9uKHRydWUpO1xuICAgICAgICAgICAgaWYgKGdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2VlcGVyLnVwZGF0ZSh7IFwic3lzdGVtLnRhcmdldFNjZW5lXCI6IGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQgfSk7XG4gICAgICAgICAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2VlcGVyLnJlbmRlcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLnJlbmRlck92ZXJsYXlfU29ja2V0UmVzcG9uc2UoKTtcbiAgICAgICAgLy8gUmV0dXJuIGFzeW5jaHJvbm91cyB0ZW1wbGF0ZSBsb2FkaW5nLlxuICAgICAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyhbXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9vdmVybGF5L2JsYWRlcy1vdmVybGF5Lmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvb3ZlcmxheS9sb2NhdGlvbi5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL292ZXJsYXkvc2NvcmUtcGFuZWwuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9vdmVybGF5L25wYy1wb3J0cmFpdC5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL292ZXJsYXkvcGMtcG9ydHJhaXQuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9vdmVybGF5L2NvaG9ydC1wb3J0cmFpdC5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL292ZXJsYXkvY3Jldy1zdGF0dXMtYmFyLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvb3ZlcmxheS9nYW1lLXBoYXNlLWJhci5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL292ZXJsYXkvbm90aWNlcy9wdXNoLmhic1wiXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICAvLyAjcmVnaW9uICAgPj4gIFNvY2tldHMgflxuICAgIHN0YXRpYyBJbml0U29ja2V0cygpIHtcbiAgICAgICAgY29uc3QgZGlyZWN0b3IgPSBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLnJlZ2lzdGVyKFwicmVuZGVyT3ZlcmxheV9Tb2NrZXRDYWxsXCIsIGRpcmVjdG9yLnJlbmRlck92ZXJsYXlfU29ja2V0UmVzcG9uc2UuYmluZChkaXJlY3RvcikpO1xuICAgICAgICBkaXJlY3Rvci5pbml0Q2xvY2tTb2NrZXRzKCk7XG4gICAgICAgIGRpcmVjdG9yLmluaXRTY29yZVBhbmVsU29ja2V0cygpO1xuICAgICAgICBkaXJlY3Rvci5pbml0TG9jYXRpb25Tb2NrZXRzKCk7XG4gICAgICAgIGRpcmVjdG9yLmluaXROUENTb2NrZXRzKCk7XG4gICAgICAgIGRpcmVjdG9yLmluaXRQQ1NvY2tldHMoKTtcbiAgICAgICAgZGlyZWN0b3IuaW5pdENvaG9ydFNvY2tldHMoKTtcbiAgICAgICAgZGlyZWN0b3IuaW5pdENyZXdTb2NrZXRzKCk7XG4gICAgICAgIGRpcmVjdG9yLmluaXROb3RpZmljYXRpb25Tb2NrZXRzKCk7XG4gICAgICAgIGRpcmVjdG9yLmluaXRUcmFuc2l0aW9uU29ja2V0cygpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gT1ZFUkxBWSB+XG4gICAgLy8gI3JlZ2lvbiAgPj4gT3ZlcmxheSBFbGVtZW50cyQgflxuICAgIF9vdmVybGF5Q29udGFpbmVyO1xuICAgIF9vdmVybGF5Q29udGFpbmVyJDtcbiAgICBnZXQgb3ZlcmxheUNvbnRhaW5lcigpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9vdmVybGF5Q29udGFpbmVyKSB7XG4gICAgICAgICAgICBbdGhpcy5fb3ZlcmxheUNvbnRhaW5lcl0gPSAkKFwiI2JsYWRlcy1vdmVybGF5XCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghdGhpcy5fb3ZlcmxheUNvbnRhaW5lcikge1xuICAgICAgICAgICAgJChcImJvZHkudnR0XCIpLmFwcGVuZChcIjxzZWN0aW9uIGlkPVxcXCJibGFkZXMtb3ZlcmxheVxcXCI+PC9zZWN0aW9uPlwiKTtcbiAgICAgICAgICAgIFt0aGlzLl9vdmVybGF5Q29udGFpbmVyXSA9ICQoXCIjYmxhZGVzLW92ZXJsYXlcIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX292ZXJsYXlDb250YWluZXI7XG4gICAgfVxuICAgIGdldCBvdmVybGF5Q29udGFpbmVyJCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9vdmVybGF5Q29udGFpbmVyJCkge1xuICAgICAgICAgICAgdGhpcy5fb3ZlcmxheUNvbnRhaW5lciQgPSAkKHRoaXMub3ZlcmxheUNvbnRhaW5lcik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX292ZXJsYXlDb250YWluZXIkO1xuICAgIH1cbiAgICBnZXQgY2xvY2tLZXlTZWN0aW9uJCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3ZlcmxheUNvbnRhaW5lciQuZmluZChcIi5vdmVybGF5LXNlY3Rpb24tY2xvY2sta2V5c1wiKTtcbiAgICB9XG4gICAgZ2V0IGxvY2F0aW9uU2VjdGlvbiQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm92ZXJsYXlDb250YWluZXIkLmZpbmQoXCIub3ZlcmxheS1zZWN0aW9uLWxvY2F0aW9uXCIpO1xuICAgIH1cbiAgICBnZXQgc2NvcmVQYW5lbFNlY3Rpb24kKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5vdmVybGF5Q29udGFpbmVyJC5maW5kKFwiLm92ZXJsYXktc2VjdGlvbi1zY29yZS1wYW5lbFwiKTtcbiAgICB9XG4gICAgZ2V0IG5wY1NlY3Rpb24kKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5vdmVybGF5Q29udGFpbmVyJC5maW5kKFwiLm92ZXJsYXktc2VjdGlvbi1ucGNzXCIpO1xuICAgIH1cbiAgICBnZXQgcGxheWVyU2VjdGlvbiQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm92ZXJsYXlDb250YWluZXIkLmZpbmQoXCIub3ZlcmxheS1zZWN0aW9uLXBsYXllcnNcIik7XG4gICAgfVxuICAgIGdldCBjcmV3U2VjdGlvbiQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm92ZXJsYXlDb250YWluZXIkLmZpbmQoXCIub3ZlcmxheS1zZWN0aW9uLWNyZXdcIik7XG4gICAgfVxuICAgIGdldCBub3RpZmljYXRpb25TZWN0aW9uJCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3ZlcmxheUNvbnRhaW5lciQuZmluZChcIi5vdmVybGF5LXNlY3Rpb24tbm90aWZpY2F0aW9uc1wiKTtcbiAgICB9XG4gICAgZ2V0IHRyYW5zaXRpb25TZWN0aW9uJCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMub3ZlcmxheUNvbnRhaW5lciQuZmluZChcIi5vdmVybGF5LXNlY3Rpb24tdHJhbnNpdGlvbnNcIik7XG4gICAgfVxuICAgIGdldCB0b29sdGlwU2VjdGlvbiQoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm92ZXJsYXlDb250YWluZXIkLmZpbmQoXCIub3ZlcmxheS1zZWN0aW9uLXRvb2x0aXBzXCIpO1xuICAgIH1cbiAgICBnZXQgc3ZnRGF0YSgpIHsgcmV0dXJuIENsb2NrS2V5X1NWR0RBVEE7IH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiAgPj4gUmVuZGVyaW5nIH5cbiAgICByZW5kZXJPdmVybGF5X1NvY2tldENhbGwoKSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMub3ZlcmxheUNvbnRhaW5lcikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyT3ZlcmxheV9Tb2NrZXRDYWxsXCIpO1xuICAgIH1cbiAgICBhc3luYyByZW5kZXJPdmVybGF5X1NvY2tldFJlc3BvbnNlKCkge1xuICAgICAgICAvLyBSZW5kZXIgdGhlIG92ZXJsYXkgZWxlbWVudFxuICAgICAgICBjb25zdCBvdmVybGF5Q29udGVudCA9IGF3YWl0IHJlbmRlclRlbXBsYXRlKFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL292ZXJsYXkvYmxhZGVzLW92ZXJsYXkuaGJzXCIsIHRoaXMpO1xuICAgICAgICB0aGlzLm92ZXJsYXlDb250YWluZXIkLmVtcHR5KCkuYXBwZW5kKG92ZXJsYXlDb250ZW50KTtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBjbG9jayBrZXkgc2VjdGlvblxuICAgICAgICB0aGlzLmluaXRDbG9ja0tleVNlY3Rpb24oKTtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSB0b29sdGlwIHNlY3Rpb25cbiAgICAgICAgdGhpcy5pbml0VG9vbHRpcFNlY3Rpb24oKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIENMT0NLUyAmIENMT0NLIEtFWVMgflxuICAgIC8vICNyZWdpb24gICA+PiBJTklUSUFMSVpBVElPTiB+XG4gICAgaW5pdENsb2NrS2V5U2VjdGlvbihpc1Jlc2V0dGluZyA9IGZhbHNlKSB7XG4gICAgICAgIGlmIChpc1Jlc2V0dGluZykge1xuICAgICAgICAgICAgdGhpcy5jbG9ja0tleVNlY3Rpb24kLmVtcHR5KCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUmVuZGVyIGtleXMgdGhhdCBhcmUgdmlzaWJsZVxuICAgICAgICBjb25zdCB2aXNpYmxlU2NlbmVLZXlzID0gVS5zaHVmZmxlKHRoaXMuc2NlbmVLZXlzLmZpbHRlcigoa2V5KSA9PiBrZXkuaXNWaXNpYmxlKSk7XG4gICAgICAgIGxldCBzdGFnZ2VyRGVsYXkgPSAwO1xuICAgICAgICB3aGlsZSAodmlzaWJsZVNjZW5lS2V5cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IGtleSA9IHZpc2libGVTY2VuZUtleXMuc2hpZnQoKTtcbiAgICAgICAgICAgIGlmIChrZXkpIHtcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMucmVuZGVyQ2xvY2tLZXkoa2V5KSwgc3RhZ2dlckRlbGF5ICogMTAwMCk7XG4gICAgICAgICAgICAgICAgc3RhZ2dlckRlbGF5ICs9IDAuNTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBBcHBseSBpdGVtIGRyYWdnZXJcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAvLyBDcmVhdGUgZHJhZ2dlciBpbnN0YW5jZSBmb3IgZHJhZ2dpbmcgY2xvY2tzICYgY2xvY2sga2V5cyBvbnRvLCBlLmcsIHJvbGxzXG4gICAgICAgIH0sIHN0YWdnZXJEZWxheSAqIDEwMDApO1xuICAgIH1cbiAgICBpbml0Q2xvY2tTb2NrZXRzKCkge1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLnJlZ2lzdGVyKFwicmVuZGVyQ2xvY2tLZXlfU29ja2V0Q2FsbFwiLCBCbGFkZXNEaXJlY3Rvci5yZW5kZXJDbG9ja0tleV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0RpcmVjdG9yKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJwdWxsS2V5X1NvY2tldENhbGxcIiwgQmxhZGVzRGlyZWN0b3IucHVsbEtleV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0RpcmVjdG9yKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJmYWRlSW5OYW1lX1NvY2tldENhbGxcIiwgQmxhZGVzQ2xvY2tLZXkuZmFkZUluTmFtZV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrS2V5KSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJmYWRlT3V0TmFtZV9Tb2NrZXRDYWxsXCIsIEJsYWRlc0Nsb2NrS2V5LmZhZGVPdXROYW1lX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzQ2xvY2tLZXkpKTtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5yZWdpc3RlcihcInJldmVhbF9Tb2NrZXRDYWxsXCIsIEJsYWRlc0Nsb2NrLnJldmVhbF9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJoaWRlX1NvY2tldENhbGxcIiwgQmxhZGVzQ2xvY2suaGlkZV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJhY3RpdmF0ZV9Tb2NrZXRDYWxsXCIsIEJsYWRlc0Nsb2NrLmFjdGl2YXRlX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzQ2xvY2spKTtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5yZWdpc3RlcihcImRlYWN0aXZhdGVfU29ja2V0Q2FsbFwiLCBCbGFkZXNDbG9jay5kZWFjdGl2YXRlX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzQ2xvY2spKTtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5yZWdpc3RlcihcImZhZGVJbkNsb2NrTmFtZV9Tb2NrZXRDYWxsXCIsIEJsYWRlc0Nsb2NrLmZhZGVJbkNsb2NrTmFtZV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJmYWRlT3V0Q2xvY2tOYW1lX1NvY2tldENhbGxcIiwgQmxhZGVzQ2xvY2suZmFkZU91dENsb2NrTmFtZV9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJoaWdobGlnaHRfU29ja2V0Q2FsbFwiLCBCbGFkZXNDbG9jay5oaWdobGlnaHRfU29ja2V0UmVzcG9uc2UuYmluZChCbGFkZXNDbG9jaykpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLnJlZ2lzdGVyKFwidW5oaWdobGlnaHRfU29ja2V0Q2FsbFwiLCBCbGFkZXNDbG9jay51bmhpZ2hsaWdodF9Tb2NrZXRSZXNwb25zZS5iaW5kKEJsYWRlc0Nsb2NrKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJjaGFuZ2VTZWdtZW50c19Tb2NrZXRDYWxsXCIsIEJsYWRlc0Nsb2NrLmNoYW5nZVNlZ21lbnRzX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzQ2xvY2spKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIGdldCBzY2VuZUtleXMoKSB7IHJldHVybiBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZWVwZXIuZ2V0U2NlbmVLZXlzKGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQpOyB9XG4gICAgLy8gI3JlZ2lvbiAgID4+IFJlbmRlcmluZyAoRHJvcHBpbmcpIENsb2NrIEtleXMgflxuICAgIGRyb3BLZXlfQW5pbWF0aW9uKGtleSwga2V5RWxlbXMkKSB7XG4gICAgICAgIGNvbnN0IHsgY29udGFpbmVyJCwgbGFiZWwkLCBpbWdDb250YWluZXIkLCBjbG9ja3MgfSA9IGtleUVsZW1zJCA/PyBrZXkuZ2V0RWxlbWVudHMkKGdhbWUuZXVub2JsYWRlcy5EaXJlY3Rvci5jbG9ja0tleVNlY3Rpb24kKTtcbiAgICAgICAgY29uc3Qga2V5U3dpbmdUaW1lbGluZSA9IGltZ0NvbnRhaW5lciQuZGF0YShcImtleVN3aW5nVGltZWxpbmVcIik7XG4gICAgICAgIC8vIENvbnN0cnVjdCB0aW1lbGluZSBmb3IgcmV2ZWFsaW5nIGNsb2NrIGtleVxuICAgICAgICBjb25zdCB0bCA9IFUuZ3NhcC50aW1lbGluZSgpXG4gICAgICAgICAgICAuY2FsbCgoKSA9PiB7IGtleVN3aW5nVGltZWxpbmUuc2VlayhcIk5FVVRSQUxcIikucGxheSgpOyB9KVxuICAgICAgICAgICAgLmZyb20oY29udGFpbmVyJCwge1xuICAgICAgICAgICAgeTogLTgwMCxcbiAgICAgICAgICAgIGVhc2U6IFwiYm91bmNlXCIsXG4gICAgICAgICAgICBkdXJhdGlvbjogMVxuICAgICAgICB9LCAwKVxuICAgICAgICAgICAgLnRvKGNvbnRhaW5lciQsIHsgYXV0b0FscGhhOiAxLCBkdXJhdGlvbjogMC41LCBlYXNlOiBcInBvd2VyMlwiIH0sIDApO1xuICAgICAgICAvLyBSZXZlYWwgdmlzaWJsZSBjbG9ja3NcbiAgICAgICAga2V5LnZpc2libGVDbG9ja3MuZm9yRWFjaCgoY2xvY2ssIGkpID0+IHtcbiAgICAgICAgICAgIHRsLmFkZCgoKSA9PiB7IGNsb2NrLnJldmVhbF9BbmltYXRpb24oY2xvY2tzW2Nsb2NrLmlkXSk7IH0sIGkgPT09IDAgPyBcIj5cIiA6IFwiPCswLjE1XCIpO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gUmV2ZWFsIGtleSBsYWJlbCwgaWYgdmlzaWJsZVxuICAgICAgICBpZiAoa2V5Lm5hbWUgJiYga2V5LmlzTmFtZVZpc2libGUpIHtcbiAgICAgICAgICAgIHRsLmJsdXJSZXZlYWwobGFiZWwkLCB7XG4gICAgICAgICAgICAgICAgaWdub3JlTWFyZ2luOiB0cnVlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjc1XG4gICAgICAgICAgICB9LCBcIjwrMC4wNVwiKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBwcmVwYXJlQ2xvY2tLZXlUaW1lbGluZXMoa2V5LCBrZXlFbGVtcyQpIHtcbiAgICAgICAgY29uc3QgeyBjb250YWluZXIkLCBpbWdDb250YWluZXIkLCBlbGVtJCwgbGFiZWwkLCBjbG9ja3MgfSA9IGtleUVsZW1zJDtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBlbGVtZW50IHN0YXJ0aW5nIHByb3BlcnRpZXNcbiAgICAgICAgVS5nc2FwLnNldChjb250YWluZXIkLCB7IHBvaW50ZXJFdmVudHM6IFwiYXV0b1wiIH0pO1xuICAgICAgICBVLmdzYXAuc2V0KGVsZW0kLCB7IGZpbHRlcjogXCJicmlnaHRuZXNzKDEpXCIgfSk7XG4gICAgICAgIFUuZ3NhcC5zZXQoaW1nQ29udGFpbmVyJCwgeyB0cmFuc2Zvcm1PcmlnaW46IFwiNTAlIDEwJVwiIH0pO1xuICAgICAgICAvLyBSZXRyaWV2ZSBlbGVtZW50IHN0YXJ0aW5nIHByb3BlcnRpZXNcbiAgICAgICAgY29uc3Qga2V5RWxlbVNjYWxlID0gVS5nc2FwLmdldFByb3BlcnR5KGNvbnRhaW5lciRbMF0sIFwic2NhbGVcIik7XG4gICAgICAgIC8vIFRpbWVsaW5lOiBTd2luZ2luZyBrZXkgdGltZWxpbmVcbiAgICAgICAgaW1nQ29udGFpbmVyJC5kYXRhKFwia2V5U3dpbmdUaW1lbGluZVwiLCBVLmdzYXAudGltZWxpbmUoeyBwYXVzZWQ6IHRydWUsIHJlcGVhdDogLTEsIHlveW86IHRydWUgfSlcbiAgICAgICAgICAgIC5mcm9tVG8oaW1nQ29udGFpbmVyJCwgeyByb3RhdGVaOiAtMSB9LCB7IHJvdGF0ZVo6IDEsIGR1cmF0aW9uOiAzLCBlYXNlOiBcInNpbmUuaW5PdXRcIiB9KVxuICAgICAgICAgICAgLmFkZExhYmVsKFwiTkVVVFJBTFwiLCAxLjUpXG4gICAgICAgICAgICAuc2VlayhcIk5FVVRSQUxcIikpO1xuICAgICAgICAvLyBUaW1lbGluZTogSG92ZXIgb3ZlciBjbG9jayBrZXlcbiAgICAgICAgY29udGFpbmVyJC5kYXRhKFwiaG92ZXJPdmVyVGltZWxpbmVcIiwgVS5nc2FwLnRpbWVsaW5lKHtcbiAgICAgICAgICAgIHBhdXNlZDogdHJ1ZSxcbiAgICAgICAgICAgIGRhdGE6IHsga2V5LCBpbWdDb250YWluZXIkLCBsYWJlbCQsIGlzTmFtZVJldmVhbGVkOiBmYWxzZSB9LFxuICAgICAgICAgICAgb25TdGFydCgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGEuaW1nQ29udGFpbmVyJC5kYXRhKFwia2V5U3dpbmdUaW1lbGluZVwiKVxuICAgICAgICAgICAgICAgICAgICAudHdlZW5UbyhcIk5FVVRSQUxcIiwge1xuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4yNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrLm91dCgxLjUpXCJcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5kYXRhLmtleS5uYW1lICYmICF0aGlzLmRhdGEua2V5LmlzTmFtZVZpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhLmlzTmFtZVJldmVhbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgVS5nc2FwLmVmZmVjdHMuYmx1clJldmVhbCh0aGlzLmRhdGEubGFiZWwkLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZ25vcmVNYXJnaW46IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvblJldmVyc2VDb21wbGV0ZSgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRhdGEuaW1nQ29udGFpbmVyJC5kYXRhKFwia2V5U3dpbmdUaW1lbGluZVwiKVxuICAgICAgICAgICAgICAgICAgICAuc2VlayhcIk5FVVRSQUxcIilcbiAgICAgICAgICAgICAgICAgICAgLnBsYXkoKTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5kYXRhLmlzTmFtZVJldmVhbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZGF0YS5pc05hbWVSZXZlYWxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBVLmdzYXAuZWZmZWN0cy5ibHVyUmVtb3ZlKHRoaXMuZGF0YS5sYWJlbCQsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZU1hcmdpbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjVcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAgICAgLnRvKGVsZW0kLCB7IGZpbHRlcjogXCJicmlnaHRuZXNzKDEuNSlcIiwgc2NhbGU6IGtleUVsZW1TY2FsZSAqIDEuMjUsIGR1cmF0aW9uOiAwLjUsIGVhc2U6IFwic2luZVwiIH0pKTtcbiAgICAgICAgLy8gVGltZWxpbmVzOiBIb3ZlciBvdmVyIGNsb2Nrc1xuICAgICAgICBrZXkuY2xvY2tzLmZvckVhY2goKGNsb2NrKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IGNsb2NrQ29udGFpbmVyJCwgY2xvY2tMYWJlbCQsIGNsb2NrRWxlbSQgfSA9IGNsb2Nrc1tjbG9jay5pZF07XG4gICAgICAgICAgICBpZiAoIWNsb2NrQ29udGFpbmVyJD8ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzRGlyZWN0b3IucHJlcGFyZUNsb2NrS2V5VGltZWxpbmVzXSBFcnJvciBjbG9ja0NvbnRhaW5lciQgbm90IGZvdW5kIGZvciBjbG9jayAnJHtjbG9jay5pZH0nIG9mIGtleSAnJHtrZXkuaWR9Jy5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIFUuZ3NhcC5zZXQoY2xvY2tDb250YWluZXIkLCB7IHBvaW50ZXJFdmVudHM6IFwiYXV0b1wiIH0pO1xuICAgICAgICAgICAgY2xvY2tDb250YWluZXIkLmRhdGEoXCJob3Zlck92ZXJUaW1lbGluZVwiLCBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgICAgIHBhdXNlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBkYXRhOiB7IGNsb2NrLCBjbG9ja0xhYmVsJCwgaXNOYW1lUmV2ZWFsZWQ6IGZhbHNlIH0sXG4gICAgICAgICAgICAgICAgb25TdGFydCgpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZGF0YS5jbG9jay5uYW1lICYmICF0aGlzLmRhdGEuY2xvY2suaXNOYW1lVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhLmlzTmFtZVJldmVhbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIFUuZ3NhcC5lZmZlY3RzLmJsdXJSZXZlYWwodGhpcy5kYXRhLmNsb2NrTGFiZWwkLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWdub3JlTWFyZ2luOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjVcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBvblJldmVyc2VDb21wbGV0ZSgpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZGF0YS5pc05hbWVSZXZlYWxlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5kYXRhLmlzTmFtZVJldmVhbGVkID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICBVLmdzYXAuZWZmZWN0cy5ibHVyUmVtb3ZlKHRoaXMuZGF0YS5jbG9ja0xhYmVsJCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlnbm9yZU1hcmdpbjogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRvKGNsb2NrRWxlbSQsIHsgZmlsdGVyOiBcImJyaWdodG5lc3MoMS41KVwiLCBzY2FsZTogMS4yNSwgZHVyYXRpb246IDAuMjUsIGVhc2U6IFwic2luZVwiIH0pKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGFjdGl2YXRlQ2xvY2tLZXlMaXN0ZW5lcnMoa2V5LCBrZXlFbGVtcyQpIHtcbiAgICAgICAgY29uc3QgeyBjb250YWluZXIkLCBjbG9ja3MgfSA9IGtleUVsZW1zJDtcbiAgICAgICAgaWYgKGdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICAvLyA9PT0gR00tT05MWSBMSVNURU5FUlMgPT09XG4gICAgICAgICAgICAvLyBEb3VibGUtQ2xpY2sgYSBDbG9jayBLZXkgPSBPcGVuIENsb2NrS2VlcGVyIHNoZWV0XG4gICAgICAgICAgICBjb250YWluZXIkLm9uKFwiZGJsY2xpY2tcIiwgYXN5bmMgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5DbG9ja0tlZXBlci5zaGVldD8ucmVuZGVyKHRydWUpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBSaWdodC1DbGljayBhIENsb2NrIEtleSA9IFB1bGwgaXRcbiAgICAgICAgICAgIGNvbnRhaW5lciQub24oXCJjb250ZXh0bWVudVwiLCBhc3luYyAoKSA9PiB7XG4gICAgICAgICAgICAgICAgdGhpcy5wdWxsS2V5X1NvY2tldENhbGwoa2V5LmlkKTtcbiAgICAgICAgICAgICAgICBrZXkudXBkYXRlVGFyZ2V0KFwiaXNWaXNpYmxlXCIsIGZhbHNlKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gPT09IFBMQVlFUi1PTkxZIExJU1RFTkVSUyA9PT1cbiAgICAgICAgICAgIC8vIEFkZCBsaXN0ZW5lcnMgdG8gY29udGFpbmVyIGZvciBtb3VzZWVudGVyIGFuZCBtb3VzZWxlYXZlLCB0aGF0IHBsYXkgYW5kIHJldmVyc2UgdGltZWxpbmUgYXR0YWNoZWQgdG8gZWxlbWVudFxuICAgICAgICAgICAgY29udGFpbmVyJC5vbihcIm1vdXNlZW50ZXJcIiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnRhaW5lciQuZGF0YShcImhvdmVyT3ZlclRpbWVsaW5lXCIpLnBsYXkoKTtcbiAgICAgICAgICAgIH0pLm9uKFwibW91c2VsZWF2ZVwiLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgY29udGFpbmVyJC5kYXRhKFwiaG92ZXJPdmVyVGltZWxpbmVcIikucmV2ZXJzZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAvLyBOb3cgcmVwZWF0IHRoaXMgZm9yIGVhY2ggY2xvY2sgaW4gdGhlIGNsb2NrIGtleVxuICAgICAgICAgICAga2V5LmNsb2Nrcy5mb3JFYWNoKChjbG9jaykgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IHsgY2xvY2tDb250YWluZXIkIH0gPSBjbG9ja3NbY2xvY2suaWRdO1xuICAgICAgICAgICAgICAgIC8vIEFkZCBsaXN0ZW5lcnMgdG8gY2xvY2sgZm9yIG1vdXNlZW50ZXIgYW5kIG1vdXNlbGVhdmUsIHRoYXQgcGxheSBhbmQgcmV2ZXJzZSB0aW1lbGluZSBhdHRhY2hlZCB0byBlbGVtZW50XG4gICAgICAgICAgICAgICAgY2xvY2tDb250YWluZXIkLm9uKFwibW91c2VlbnRlclwiLCAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjbG9jay5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrQ29udGFpbmVyJC5kYXRhKFwiaG92ZXJPdmVyVGltZWxpbmVcIikucGxheSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSkub24oXCJtb3VzZWxlYXZlXCIsICgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNsb2NrLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2tDb250YWluZXIkLmRhdGEoXCJob3Zlck92ZXJUaW1lbGluZVwiKS5yZXZlcnNlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIHJlbmRlckNsb2NrS2V5KGtleSkge1xuICAgICAgICBhd2FpdCBrZXkucmVuZGVyVG8odGhpcy5jbG9ja0tleVNlY3Rpb24kKTtcbiAgICAgICAgLy8gSWYgYSBwb3NpdGlvbi1kcmFnZ2VyIGlzIHByZXNlbnQsIHJlbW92ZSBpdC5cbiAgICAgICAgaWYgKGtleS5wb3NpdGlvbkRyYWdnZXIpIHtcbiAgICAgICAgICAgIGtleS5yZW1vdmVQb3NpdGlvbkRyYWdnZXIoKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJbml0aWFsaXplIGNsb2NrIGtleSBlbGVtZW50cyB0byBvdmVybGF5IGNvbnRleHRcbiAgICAgICAgY29uc3Qga2V5RWxlbXMkID0ga2V5LmluaXRFbGVtZW50c0luQ29udGV4dCh0aGlzLmNsb2NrS2V5U2VjdGlvbiQsIENsb2NrS2V5RGlzcGxheU1vZGUuZnVsbCk7XG4gICAgICAgIC8vIElmIGFuIG92ZXJsYXlQb3NpdGlvbiBoYXMgYmVlbiBzZXQsIGFwcGx5IHRvIHRoZSBjb250YWluZXIgZWxlbWVudDpcbiAgICAgICAgaWYgKGtleS5vdmVybGF5UG9zaXRpb24pIHtcbiAgICAgICAgICAgIFUuZ3NhcC5zZXQoa2V5RWxlbXMkLmNvbnRhaW5lciQsIHtcbiAgICAgICAgICAgICAgICBsZWZ0OiBrZXkub3ZlcmxheVBvc2l0aW9uLngsXG4gICAgICAgICAgICAgICAgdG9wOiBrZXkub3ZlcmxheVBvc2l0aW9uLnlcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIC8vIFByZXBhcmUgYW5pbWF0aW9uIHRpbWVsaW5lcyAmIGF0dGFjaCB0aGVtIHRvIHJlbmRlcmVkIGVsZW1lbnRzXG4gICAgICAgIHRoaXMucHJlcGFyZUNsb2NrS2V5VGltZWxpbmVzKGtleSwga2V5RWxlbXMkKTtcbiAgICAgICAgLy8gQWN0aXZhdGUgbGlzdGVuZXJzIGZvciB0aGUgcmVuZGVyZWQga2V5XG4gICAgICAgIHRoaXMuYWN0aXZhdGVDbG9ja0tleUxpc3RlbmVycyhrZXksIGtleUVsZW1zJCk7XG4gICAgICAgIC8vIEFuaW1hdGUgdGhlIGtleSBkcm9wcGluZyBpbnRvIHRoZSBvdmVybGF5XG4gICAgICAgIHRoaXMuZHJvcEtleV9BbmltYXRpb24oa2V5LCBrZXlFbGVtcyQpO1xuICAgIH1cbiAgICBhc3luYyByZW5kZXJDbG9ja0tleV9Tb2NrZXRDYWxsKGtleUlEKSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlckNsb2NrS2V5X1NvY2tldENhbGxcIiwga2V5SUQpO1xuICAgIH1cbiAgICBzdGF0aWMgYXN5bmMgcmVuZGVyQ2xvY2tLZXlfU29ja2V0UmVzcG9uc2Uoa2V5SUQpIHtcbiAgICAgICAgY29uc3Qga2V5ID0gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoa2V5SUQpO1xuICAgICAgICBpZiAoIWtleSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGdhbWUuZXVub2JsYWRlcy5EaXJlY3Rvci5yZW5kZXJDbG9ja0tleShrZXkpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiAgID4+IFVuLVJlbmRlcmluZyAoUHVsbGluZykgQ2xvY2sgS2V5cyB+XG4gICAgcHVsbEtleV9BbmltYXRpb24oa2V5KSB7XG4gICAgICAgIGNvbnN0IHsgY29udGFpbmVyJCB9ID0ga2V5LmdldEVsZW1lbnRzJChnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuY2xvY2tLZXlTZWN0aW9uJCk7XG4gICAgICAgIFUuZ3NhcC50aW1lbGluZSgpXG4gICAgICAgICAgICAudG8oY29udGFpbmVyJCwge1xuICAgICAgICAgICAgeTogLTgwMCxcbiAgICAgICAgICAgIGVhc2U6IFwiYmFjay5pbigxKVwiLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNzVcbiAgICAgICAgfSlcbiAgICAgICAgICAgIC50byhjb250YWluZXIkLCB7XG4gICAgICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAgICAgZWFzZTogXCJwb3dlcjIub3V0XCIsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC4yNVxuICAgICAgICB9LCAwLjc1KVxuICAgICAgICAgICAgLmNhbGwoKCkgPT4geyBjb250YWluZXIkLnJlbW92ZSgpOyB9KTtcbiAgICB9XG4gICAgYXN5bmMgcHVsbEtleV9Tb2NrZXRDYWxsKGtleUlEKSB7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInB1bGxLZXlfU29ja2V0Q2FsbFwiLCBrZXlJRCk7XG4gICAgfVxuICAgIHN0YXRpYyBwdWxsS2V5X1NvY2tldFJlc3BvbnNlKGtleUlEKSB7XG4gICAgICAgIGNvbnN0IGtleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKTtcbiAgICAgICAgaWYgKCFrZXkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IucHVsbEtleV9BbmltYXRpb24oa2V5KTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFNDT1JFIFBBTkVMIH5cbiAgICAvLyAjcmVnaW9uICAgPj4gSU5JVElBTElaQVRJT04gflxuICAgIGluaXRTY29yZVBhbmVsU29ja2V0cygpIHtcbiAgICAgICAgLy8gdGJkLi4uXG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjIyBTY29yZSBEZXRhaWxzXG4gICAgLy8gLSBTbWFsbCBwYW5lbCBvdmVybGFwcGluZyBjb3JuZXIgb2YgTG9jYXRpb25cbiAgICAvLyAtIEVuZ2FnZW1lbnQgcm9sbCByZXN1bHRcbiAgICAvLyAtIFBsYW4gJiBEZXRhaWxcbiAgICAvLyAtIFRhcmdldCB0aWVyXG4gICAgYWN0aXZhdGVTY29yZVBhbmVsTGlzdGVuZXJzKCkge1xuICAgICAgICAvLyB0YmQuLi5cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gTE9DQVRJT05TIH5cbiAgICAvLyAjcmVnaW9uICAgPj4gSU5JVElBTElaQVRJT04gflxuICAgIGluaXRMb2NhdGlvblNvY2tldHMoKSB7XG4gICAgICAgIC8vIHRiZC4uLlxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gIyMgTG9jYXRpb25zXG4gICAgLy8gLSBEaXN0cmljdCB3cmFwcGVyL2hlYWRlclxuICAgIC8vIC0gRmFjdGlvbiB3cmFwcGVyL2Zvb3RlclxuICAgIC8vIC0gTG9jYXRpb24gbWFpblxuICAgIC8vIC0gU2xpZGUtc2Nyb2xsIG9mIHN1YmxvY2F0aW9uc1xuICAgIGFjdGl2YXRlTG9jYXRpb25MaXN0ZW5lcnMoKSB7XG4gICAgICAgIC8vIHRiZC4uLlxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBOUENzIH5cbiAgICAvLyAjcmVnaW9uICAgPj4gSU5JVElBTElaQVRJT04gflxuICAgIGluaXROUENTb2NrZXRzKCkge1xuICAgICAgICAvLyB0YmQuLi5cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvbi8vICMjIE5QQ3NcbiAgICAvLyAtIExpbmtlZCB0byBhIGxvY2F0aW9uOiBXaGVuIGxvY2F0aW9uIGlzIGRpc3BsYXllZCwgc28gYXJlIHRoZXkuICAqKENhbiBiZSBsaW5rZWQgdG8gRGlzdHJpY3Qgd3JhcHBlciwgbWFpbiBMb2NhdGlvbiwgb3Igc3VibG9jYXRpb25zKSpcbiAgICAvLyAtIFBvcnRyYWl0IGltYWdlcyBjbG9zZSB0byB0aGUgY2VudHJhbCBsb2NhdGlvbiBkaXNwbGF5LCBob3Zlci1vdmVyIHBvcHVwcyBwcm92aWRlIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24gZnJvbSBzaGVldCBvciBgQmxhZGVzU2NvcmVgIGluc3RhbmNlXG4gICAgYWN0aXZhdGVOUENMaXN0ZW5lcnMoKSB7XG4gICAgICAgIC8vIHRiZC4uLlxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBQQ3MsIENPSE9SVHMsIENSRVcgflxuICAgIC8vICNyZWdpb24gICA+PiBJTklUSUFMSVpBVElPTiB+XG4gICAgaW5pdFBDU29ja2V0cygpIHtcbiAgICAgICAgLy8gdGJkLi4uXG4gICAgfVxuICAgIGluaXRDb2hvcnRTb2NrZXRzKCkge1xuICAgICAgICAvLyB0YmQuLi5cbiAgICB9XG4gICAgaW5pdENyZXdTb2NrZXRzKCkge1xuICAgICAgICAvLyB0YmQuLi5cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICMjIFBDc1xuICAgIC8vIC0gRGlzcGxheSBwYW5lbHMgYWxvbmcgYm90dG9tXG4gICAgLy8gLSBTaWduYWwgbGlnaHRzXG4gICAgYWN0aXZhdGVQQ0xpc3RlbmVycygpIHtcbiAgICAgICAgLy8gdGJkLi4uXG4gICAgfVxuICAgIC8vICMjIENvaG9ydHNcbiAgICAvLyAtIFNtYWxsZXIgcGFuZWxzIGFsb25nc2lkZSB0aGUgUENzXG4gICAgYWN0aXZhdGVDb2hvcnRMaXN0ZW5lcnMoKSB7XG4gICAgICAgIC8vIHRiZC4uLlxuICAgIH1cbiAgICAvLyAjIyBDcmV3XG4gICAgLy8gLSBMaW1pdGVkIGluZm9ybWF0aW9uIGRpc3BsYXllZCwgbWF5YmUgYmFyIGJlbmVhdGggUENzIHNob3dpbmcgSGVhdCwgV2FudGVkIExldmVs4oCmXG4gICAgYWN0aXZhdGVDcmV3TGlzdGVuZXJzKCkge1xuICAgICAgICAvLyB0YmQuLi5cbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gTk9USUZJQ0FUSU9OUyB+XG4gICAgLy8gI3JlZ2lvbiAgID4+IElOSVRJQUxJWkFUSU9OIH5cbiAgICBpbml0Tm90aWZpY2F0aW9uU29ja2V0cygpIHtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5yZWdpc3RlcihcInB1c2hOb3RpY2VfU29ja2V0Q2FsbFwiLCBCbGFkZXNEaXJlY3Rvci5wdXNoTm90aWNlX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzRGlyZWN0b3IpKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIHB1c2hOb3RpY2VfU29ja2V0Q2FsbCh0YXJnZXRzLCBjb25maWcpIHtcbiAgICAgICAgY29uc3QgcHVzaElEID0gcmFuZG9tSUQoKTtcbiAgICAgICAgaWYgKHR5cGVvZiB0YXJnZXRzID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBpZiAodGFyZ2V0cyA9PT0gXCJBTExcIikge1xuICAgICAgICAgICAgICAgIHJldHVybiBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInB1c2hOb3RpY2VfU29ja2V0Q2FsbFwiLCBwdXNoSUQsIGNvbmZpZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0YXJnZXRzID09PSBcIkdNXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yQWxsR01zKFwicHVzaE5vdGljZV9Tb2NrZXRDYWxsXCIsIHB1c2hJRCwgY29uZmlnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRhcmdldHMgPSBnYW1lLnVzZXJzLmZpbHRlcigodXNlcikgPT4gdXNlci5pZCA9PT0gdGFyZ2V0c1xuICAgICAgICAgICAgICAgICAgICB8fCB1c2VyLm5hbWUgPT09IHRhcmdldHNcbiAgICAgICAgICAgICAgICAgICAgfHwgdXNlci5jaGFyYWN0ZXI/LmlkID09PSB0YXJnZXRzXG4gICAgICAgICAgICAgICAgICAgIHx8IHVzZXIuY2hhcmFjdGVyPy5uYW1lID09PSB0YXJnZXRzXG4gICAgICAgICAgICAgICAgICAgIHx8IGdhbWUudXNlci5pc0dNKS5tYXAoKHVzZXIpID0+IHVzZXIuaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0YXJnZXRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHJldHVybiBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JVc2VycyhcInB1c2hOb3RpY2VfU29ja2V0Q2FsbFwiLCB0YXJnZXRzLCBwdXNoSUQsIGNvbmZpZyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc3RhdGljIGFzeW5jIHB1c2hOb3RpY2VfU29ja2V0UmVzcG9uc2UocHVzaElELCBjb25maWcpIHtcbiAgICAgICAgY29uc3QgZGlyZWN0b3IgPSBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3I7XG4gICAgICAgIGNvbnN0IHB1c2hFbGVtJCA9ICQoYXdhaXQgcmVuZGVyVGVtcGxhdGUoXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvb3ZlcmxheS9ub3RpY2VzL3B1c2guaGJzXCIsIHtcbiAgICAgICAgICAgIGlkOiBwdXNoSUQsXG4gICAgICAgICAgICAuLi5jb25maWdcbiAgICAgICAgfSkpXG4gICAgICAgICAgICAuYXBwZW5kVG8oZGlyZWN0b3Iubm90aWZpY2F0aW9uU2VjdGlvbiQpXG4gICAgICAgICAgICAub24oXCJjbGlja1wiLCAoZXZlbnQpID0+IHsgZGlyZWN0b3IuJHJlbW92ZVB1c2goZXZlbnQuY3VycmVudFRhcmdldCk7IH0pXG4gICAgICAgICAgICAub24oXCJjb250ZXh0bWVudVwiLCAoZXZlbnQpID0+IHsgZGlyZWN0b3IuJHJlbW92ZUFuZENsZWFyKGV2ZW50LmN1cnJlbnRUYXJnZXQpOyB9KTtcbiAgICAgICAgVS5nc2FwLmZyb21UbyhwdXNoRWxlbSQsIHtcbiAgICAgICAgICAgIHg6IDIwMCxcbiAgICAgICAgICAgIHNrZXdYOiAyMCxcbiAgICAgICAgICAgIGF1dG9BbHBoYTogMCxcbiAgICAgICAgICAgIGZpbHRlcjogXCJibHVyKDEwcHgpXCJcbiAgICAgICAgfSwge1xuICAgICAgICAgICAgeDogMCxcbiAgICAgICAgICAgIHNrZXdYOiAwLFxuICAgICAgICAgICAgYXV0b0FscGhhOiAxLFxuICAgICAgICAgICAgZmlsdGVyOiBcImJsdXIoMHB4KVwiLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIGVhc2U6IFwiYmFja1wiXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhc3luYyAkcmVtb3ZlUHVzaCh0YXJnZXQpIHtcbiAgICAgICAgVS5nc2FwLnRvKHRhcmdldCwge1xuICAgICAgICAgICAgeDogXCIrPTIwMFwiLFxuICAgICAgICAgICAgYXV0b0FscGhhOiAwLFxuICAgICAgICAgICAgZWFzZTogXCJwb3dlcjJcIixcbiAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICBvbkNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJCh0YXJnZXQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgJHJlbW92ZUFuZENsZWFyKHRhcmdldCkge1xuICAgICAgICBjb25zdCB0YXJnZXRzID0gJCh0YXJnZXQpLnByZXZBbGwoKS5nZXQoKS5yZXZlcnNlKCk7XG4gICAgICAgIHRhcmdldHMudW5zaGlmdCh0YXJnZXQpO1xuICAgICAgICBVLmdzYXAudG8odGFyZ2V0cywge1xuICAgICAgICAgICAgeDogXCIrPTIwMFwiLFxuICAgICAgICAgICAgYXV0b0FscGhhOiAwLFxuICAgICAgICAgICAgZWFzZTogXCJwb3dlcjJcIixcbiAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICBzdGFnZ2VyOiB7XG4gICAgICAgICAgICAgICAgZWFjaDogMC41LFxuICAgICAgICAgICAgICAgIGZyb206IFwic3RhcnRcIixcbiAgICAgICAgICAgICAgICBlYXNlOiBcInBvd2VyMS5pbk91dFwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb25Db21wbGV0ZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRhcmdldHMuZm9yRWFjaCgodGFyZykgPT4gJCh0YXJnKS5yZW1vdmUoKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBUUkFOU0lUSU9OUyB+XG4gICAgLy8gI3JlZ2lvbiAgID4+IElOSVRJQUxJWkFUSU9OIH5cbiAgICBpbml0VHJhbnNpdGlvblNvY2tldHMoKSB7XG4gICAgICAgIC8vIHRiZC4uLlxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gIyMgVHJhbnNpdGlvbnNcbiAgICBhc3luYyBhZHZhbmNlR2FtZVBoYXNlKHBoYXNlKSB7XG4gICAgICAgIGNvbnN0IG5leHRQaGFzZSA9IFUuZ3NhcC51dGlscy53cmFwKE9iamVjdC52YWx1ZXMoQmxhZGVzUGhhc2UpLCBPYmplY3QudmFsdWVzKEJsYWRlc1BoYXNlKS5pbmRleE9mKHBoYXNlID8/IGdhbWUuZXVub2JsYWRlcy5UcmFja2VyPy5waGFzZSA/PyBCbGFkZXNQaGFzZS5GcmVlcGxheSkgKyAxKTtcbiAgICB9XG4gICAgLy8gLSBBcyB3aXRoIG5vdGlmaWNhdGlvbnM6IHBsYWNlaG9sZGVyIGFuaW1hdGlvbiB1bnRpbCBzb21ldGhpbmcgbW9yZSBmaW5hbCBjYW4gYmUgY29kZWQuXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gVE9PTFRJUFMgflxuICAgIF90b29sdGlwT2JzZXJ2ZXI7XG4gICAgX3Rvb2x0aXBFbGVtcyA9IG5ldyBNYXAoKTtcbiAgICBfZGlzcGxheWVkVG9vbHRpcElEO1xuICAgIC8qKlxuICAgICAqIEFkanVzdHMgdGhlIHRvb2x0aXAncyBwb3NpdGlvbiB0byBlbnN1cmUgaXQgcmVtYWlucyB3aXRoaW4gaXRzIHBhcmVudCBjb250YWluZXIgdXNpbmcgalF1ZXJ5IG1ldGhvZHMuXG4gICAgICogQHBhcmFtIHRvb2x0aXAgLSBUaGUgdG9vbHRpcCBlbGVtZW50LCB3aGljaCBjYW4gYmUgZWl0aGVyIGFuIEhUTUxFbGVtZW50IG9yIGEgSlF1ZXJ5PEhUTUxFbGVtZW50Pi5cbiAgICAgKi9cbiAgICBhZGp1c3RUb29sdGlwUG9zaXRpb24odG9vbHRpcCQpIHtcbiAgICAgICAgLy8gVmFsaWRhdGUgdG9vbHRpcCBwb3NpdGlvbiBzdHlsZVxuICAgICAgICBpZiAodG9vbHRpcCQuY3NzKFwicG9zaXRpb25cIikgIT09IFwiYWJzb2x1dGVcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiVG9vbHRpcCBwb3NpdGlvbiBtdXN0IGJlICdhYnNvbHV0ZScuXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIENhbGN1bGF0ZSBib3VuZHMgYW5kIGRpcmVjdGx5IGFwcGx5IG5lY2Vzc2FyeSBzaGlmdHMgdG8gdGhlIHRvb2x0aXAgZWxlbWVudFxuICAgICAgICBjb25zdCB0b29sdGlwUmVjdCA9IHRvb2x0aXAkWzBdLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBjb25zdCBjb250YWluZXJSZWN0ID0gdGhpcy50b29sdGlwU2VjdGlvbiRbMF0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIC8vIEluaXRpYWwgcG9zaXRpb24gb2YgdGhlIHRvb2x0aXBcbiAgICAgICAgY29uc3QgY3VycmVudFRvcCA9IHRvb2x0aXAkLnBvc2l0aW9uKCkudG9wO1xuICAgICAgICBjb25zdCBjdXJyZW50TGVmdCA9IHRvb2x0aXAkLnBvc2l0aW9uKCkubGVmdDtcbiAgICAgICAgLy8gQ2hlY2sgZm9yIHJpZ2h0IG92ZXJmbG93IGFuZCBhZGp1c3QgbGVmdCBwb3NpdGlvbiBpZiBuZWNlc3NhcnlcbiAgICAgICAgaWYgKHRvb2x0aXBSZWN0LnJpZ2h0ID4gY29udGFpbmVyUmVjdC5yaWdodCkge1xuICAgICAgICAgICAgY29uc3QgeFNoaWZ0ID0gY29udGFpbmVyUmVjdC5yaWdodCAtIHRvb2x0aXBSZWN0LnJpZ2h0O1xuICAgICAgICAgICAgdG9vbHRpcCQuY3NzKFwibGVmdFwiLCBgJHtjdXJyZW50TGVmdCArIHhTaGlmdH1weGApO1xuICAgICAgICB9XG4gICAgICAgIC8vIENoZWNrIGZvciBsZWZ0IG92ZXJmbG93IGFuZCBhZGp1c3QgbGVmdCBwb3NpdGlvbiBpZiBuZWNlc3NhcnlcbiAgICAgICAgZWxzZSBpZiAodG9vbHRpcFJlY3QubGVmdCA8IGNvbnRhaW5lclJlY3QubGVmdCkge1xuICAgICAgICAgICAgY29uc3QgeFNoaWZ0ID0gY29udGFpbmVyUmVjdC5sZWZ0IC0gdG9vbHRpcFJlY3QubGVmdDtcbiAgICAgICAgICAgIHRvb2x0aXAkLmNzcyhcImxlZnRcIiwgYCR7Y3VycmVudExlZnQgKyB4U2hpZnR9cHhgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBDaGVjayBmb3IgYm90dG9tIG92ZXJmbG93IGFuZCBhZGp1c3QgdG9wIHBvc2l0aW9uIGlmIG5lY2Vzc2FyeVxuICAgICAgICBpZiAodG9vbHRpcFJlY3QuYm90dG9tID4gY29udGFpbmVyUmVjdC5ib3R0b20pIHtcbiAgICAgICAgICAgIGNvbnN0IHlTaGlmdCA9IGNvbnRhaW5lclJlY3QuYm90dG9tIC0gdG9vbHRpcFJlY3QuYm90dG9tO1xuICAgICAgICAgICAgdG9vbHRpcCQuY3NzKFwidG9wXCIsIGAke2N1cnJlbnRUb3AgKyB5U2hpZnR9cHhgKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBDaGVjayBmb3IgdG9wIG92ZXJmbG93IGFuZCBhZGp1c3QgdG9wIHBvc2l0aW9uIGlmIG5lY2Vzc2FyeVxuICAgICAgICBlbHNlIGlmICh0b29sdGlwUmVjdC50b3AgPCBjb250YWluZXJSZWN0LnRvcCkge1xuICAgICAgICAgICAgY29uc3QgeVNoaWZ0ID0gY29udGFpbmVyUmVjdC50b3AgLSB0b29sdGlwUmVjdC50b3A7XG4gICAgICAgICAgICB0b29sdGlwJC5jc3MoXCJ0b3BcIiwgYCR7Y3VycmVudFRvcCArIHlTaGlmdH1weGApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGRpc3BsYXlUb29sdGlwKHRvb2x0aXApIHtcbiAgICAgICAgaWYgKCF0b29sdGlwLmlkKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUb29sdGlwIG11c3QgaGF2ZSBhbiBJRCB0byBiZSBjbG9uZWQgdG8gdGhlIG92ZXJsYXkuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX2Rpc3BsYXllZFRvb2x0aXBJRCA9IHRvb2x0aXAuaWQ7XG4gICAgICAgIGNvbnN0IHNlbGYgPSB0aGlzO1xuICAgICAgICAvLyBDbGVhciBvdXQgYW55IG90aGVyIHRvb2x0aXBzIGluIHRoZSBvdmVybGF5LlxuICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuY2xlYXJUb29sdGlwcygpO1xuICAgICAgICBpZiAoIXRoaXMuX3Rvb2x0aXBFbGVtcy5oYXModG9vbHRpcC5pZCkpIHtcbiAgICAgICAgICAgIC8vIENyZWF0ZSBjbG9uZWQgdG9vbHRpcCBhbmQgYXR0YWNoIGl0IHRvIHRoZSB0b29sdGlwIG92ZXJsYXkuXG4gICAgICAgICAgICBjb25zdCB0dENsb25lJCA9ICQoVS5jaGFuZ2VDb250YWluZXIodG9vbHRpcCwgZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLnRvb2x0aXBTZWN0aW9uJFswXSwgdHJ1ZSkpO1xuICAgICAgICAgICAgLy8gQWRqdXN0IHRoZSB0b29sdGlwJ3MgcG9zaXRpb24gc28gaXQgZG9lcyBub3Qgb3ZlcmZsb3cgdGhlIHRvb2x0aXAgY29udGFpbmVyXG4gICAgICAgICAgICB0aGlzLmFkanVzdFRvb2x0aXBQb3NpdGlvbih0dENsb25lJCk7XG4gICAgICAgICAgICAvLyBHZW5lcmF0ZSB0aGUgcmV2ZWFsIHRpbWVsaW5lIGFuZCBhdHRhY2ggaXQgdG8gdGhlIGNsb25lZCB0b29sdGlwIGVsZW1lbnQuXG4gICAgICAgICAgICBjb25zdCByZXZlYWxUaW1lbGluZSA9IFUuZ3NhcC5lZmZlY3RzLmJsdXJSZXZlYWxUb29sdGlwKHR0Q2xvbmUkWzBdLCB7XG4gICAgICAgICAgICAgICAgb25SZXZlcnNlQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0dENsb25lJC5hdHRyKFwiaWRcIikgPT09IHNlbGYuX2Rpc3BsYXllZFRvb2x0aXBJRCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYuX2Rpc3BsYXllZFRvb2x0aXBJRDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuX3Rvb2x0aXBFbGVtcy5kZWxldGUodHRDbG9uZSQuYXR0cihcImlkXCIpKTtcbiAgICAgICAgICAgICAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLnRvb2x0aXBTZWN0aW9uJC5maW5kKGAjJHt0dENsb25lJC5hdHRyKFwiaWRcIil9YCkucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5EaXJlY3Rvci50b29sdGlwU2VjdGlvbiQuY2hpbGRyZW4oXCJbc3R5bGUqPSdvcGFjaXR5OiAwJ10sIFtzdHlsZSo9J29wYWNpdHk6MCddXCIpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc3QgaWQgPSB0aGlzLmlkOyAvLyBHZXQgdGhlIElEIG9mIHRoZSBjdXJyZW50IGVsZW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpZCA9PT0gc2VsZi5fZGlzcGxheWVkVG9vbHRpcElEKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLl90b29sdGlwRWxlbXMuZGVsZXRlKGlkKTsgLy8gUmVtb3ZlIGZyb20gdGhlIG1hcCBpZiB0aGUgSUQgZXhpc3RzXG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAkKHRoaXMpLnJlbW92ZSgpOyAvLyBSZW1vdmUgdGhlIGVsZW1lbnQgZnJvbSB0aGUgRE9NXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdHRDbG9uZSQuZGF0YShcInJldmVhbFRpbWVsaW5lXCIsIHJldmVhbFRpbWVsaW5lKTtcbiAgICAgICAgICAgIC8vIFJlZ2lzdGVyIHRoZSBjbG9uZWQgdG9vbHRpcCBlbGVtZW50IHRvIHRoZSBtYXN0ZXIgbWFwXG4gICAgICAgICAgICB0aGlzLl90b29sdGlwRWxlbXMuc2V0KHRvb2x0aXAuaWQsIHR0Q2xvbmUkKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBQbGF5IHRoZSB0aW1lbGluZS5cbiAgICAgICAgdGhpcy5fdG9vbHRpcEVsZW1zLmdldCh0b29sdGlwLmlkKT8uZGF0YShcInJldmVhbFRpbWVsaW5lXCIpPy5wbGF5KCk7XG4gICAgfVxuICAgIGNsZWFyVG9vbHRpcCh0b29sdGlwSUQsIGlzQ2xlYXJpbmdJZlR3ZWVuaW5nID0gdHJ1ZSkge1xuICAgICAgICBpZiAodG9vbHRpcElEID09PSB0aGlzLl9kaXNwbGF5ZWRUb29sdGlwSUQpIHtcbiAgICAgICAgICAgIGRlbGV0ZSB0aGlzLl9kaXNwbGF5ZWRUb29sdGlwSUQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdHRFbGVtID0gZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLl90b29sdGlwRWxlbXMuZ2V0KHRvb2x0aXBJRCk7XG4gICAgICAgIGlmICghdHRFbGVtKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdHRUaW1lbGluZSA9IHR0RWxlbS5kYXRhKFwicmV2ZWFsVGltZWxpbmVcIik7XG4gICAgICAgIGlmICh0dFRpbWVsaW5lLmlzQWN0aXZlKCkgJiYgIWlzQ2xlYXJpbmdJZlR3ZWVuaW5nKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgdHRUaW1lbGluZS5yZXZlcnNlKCk7XG4gICAgfVxuICAgIGNsZWFyVG9vbHRpcHMoKSB7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwiT2JzZXJ2ZXJcIiwgXCJPYnNlcnZlciBUcmlnZ2VyZWQhXCIpO1xuICAgICAgICAvLyBMb29rIGZvciB0b29sdGlwIGVsZW1lbnRzIGluIHRoZSBvdmVybGF5IGNvbnRhaW5lciwgYW5kIHJlbW92ZSB0aGVtLlxuICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuX3Rvb2x0aXBFbGVtcy5mb3JFYWNoKCh0dEVsZW0pID0+IHtcbiAgICAgICAgICAgIGlmICh0dEVsZW0uYXR0cihcImlkXCIpID09PSB0aGlzLl9kaXNwbGF5ZWRUb29sdGlwSUQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuY2xlYXJUb29sdGlwKHR0RWxlbS5hdHRyKFwiaWRcIiksIHRydWUpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgaW5pdFRvb2x0aXBTZWN0aW9uKCkge1xuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgdGhpcy5jbGVhclRvb2x0aXBzKCk7XG4gICAgICAgIC8vIFJlc2V0IHRvb2x0aXAgb2JzZXJ2ZXJcbiAgICAgICAgdGhpcy5fdG9vbHRpcE9ic2VydmVyPy5raWxsKCk7XG4gICAgICAgIC8vIFNpbXBsaWZpZWQgdGhyb3R0bGUgZnVuY3Rpb24gdGhhdCB0YWtlcyBhIGZ1bmN0aW9uIHdpdGggT2JzZXJ2ZXIgcGFyYW1ldGVyXG4gICAgICAgIGNvbnN0IHRocm90dGxlID0gKGZ1bmMsIGxpbWl0KSA9PiB7XG4gICAgICAgICAgICBsZXQgbGFzdEZ1bmM7XG4gICAgICAgICAgICBsZXQgbGFzdFJhbjtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAob2JzKSB7XG4gICAgICAgICAgICAgICAgY29uc3Qgbm93ID0gRGF0ZS5ub3coKTtcbiAgICAgICAgICAgICAgICBpZiAoIWxhc3RSYW4gfHwgbm93IC0gbGFzdFJhbiA+PSBsaW1pdCkge1xuICAgICAgICAgICAgICAgICAgICBmdW5jKG9icyk7XG4gICAgICAgICAgICAgICAgICAgIGxhc3RSYW4gPSBub3c7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQobGFzdEZ1bmMpO1xuICAgICAgICAgICAgICAgICAgICBsYXN0RnVuYyA9IHdpbmRvdy5zZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChub3cgLSBsYXN0UmFuID49IGxpbWl0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuYyhvYnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RSYW4gPSBub3c7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sIGxpbWl0IC0gKG5vdyAtIGxhc3RSYW4pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9O1xuICAgICAgICAvLyBUaHJvdHRsZWQgb25Nb3ZlIGNhbGxiYWNrXG4gICAgICAgIGNvbnN0IHRocm90dGxlZE9uTW92ZSA9IHRocm90dGxlKChvYnMpID0+IHtcbiAgICAgICAgICAgIC8vIENhbGN1bGF0ZSB0aGUgYWJzb2x1dGUgbWFnbml0dWRlIG9mIHZlbG9jaXR5IGluZGVwZW5kZW50IG9mIGRpcmVjdGlvblxuICAgICAgICAgICAgY29uc3QgbWFnbml0dWRlT2ZWZWxvY2l0eSA9IE1hdGguc3FydCgob2JzLnZlbG9jaXR5WCAqKiAyKSArIChvYnMudmVsb2NpdHlZICoqIDIpKTtcbiAgICAgICAgICAgIGlmIChtYWduaXR1ZGVPZlZlbG9jaXR5ID49IEMuTUlOX01PVVNFX01PVkVNRU5UX1RIUkVTSE9MRCkge1xuICAgICAgICAgICAgICAgIHNlbGYuY2xlYXJUb29sdGlwcygpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCAyMDApOyAvLyBBZGp1c3QgMjAwbXMgdG8geW91ciBwcmVmZXJyZWQgdGhyb3R0bGluZyBsaW1pdFxuICAgICAgICB0aGlzLl90b29sdGlwT2JzZXJ2ZXIgPSBPYnNlcnZlci5jcmVhdGUoe1xuICAgICAgICAgICAgdHlwZTogXCJ0b3VjaCxwb2ludGVyXCIsXG4gICAgICAgICAgICAvLyBvbk1vdmU6IHRocm90dGxlZE9uTW92ZSxcbiAgICAgICAgICAgIG9uQ2xpY2soKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5jbGVhclRvb2x0aXBzKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0RpcmVjdG9yO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/classes/BladesDirector.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesRoll.ts": +/*!**********************************!*\ + !*** ./ts/classes/BladesRoll.ts ***! + \**********************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesActionRoll: function() { return /* binding */ BladesActionRoll; },\n/* harmony export */ BladesEngagementRoll: function() { return /* binding */ BladesEngagementRoll; },\n/* harmony export */ BladesFortuneRoll: function() { return /* binding */ BladesFortuneRoll; },\n/* harmony export */ BladesIncarcerationRoll: function() { return /* binding */ BladesIncarcerationRoll; },\n/* harmony export */ BladesIndulgeViceRoll: function() { return /* binding */ BladesIndulgeViceRoll; },\n/* harmony export */ BladesInlineResistanceRoll: function() { return /* binding */ BladesInlineResistanceRoll; },\n/* harmony export */ BladesResistanceRoll: function() { return /* binding */ BladesResistanceRoll; },\n/* harmony export */ BladesRollMod: function() { return /* binding */ BladesRollMod; },\n/* harmony export */ BladesRollOpposition: function() { return /* binding */ BladesRollOpposition; },\n/* harmony export */ BladesRollParticipant: function() { return /* binding */ BladesRollParticipant; },\n/* harmony export */ BladesRollPrimary: function() { return /* binding */ BladesRollPrimary; }\n/* harmony export */ });\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _BladesConsequence__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./BladesConsequence */ \"./ts/classes/BladesConsequence.ts\");\n/* harmony import */ var _BladesDialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n/* harmony import */ var _BladesChat__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./BladesChat */ \"./ts/classes/BladesChat.ts\");\n/* harmony import */ var _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./BladesTargetLink */ \"./ts/classes/BladesTargetLink.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region IMPORTS ~\n\n\n\n\n\n\n\n\n\n// #endregion\n// #region Types & Type Checking ~\n/**\n * Checks if the given string is a RollType.\n * @param {unknown} str The string to check.\n * @returns {boolean} True if the string is a RollType, false otherwise.\n */\nfunction isRollType(str) {\n return typeof str === \"string\" && str in _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType;\n}\n/**\n * Checks if the given trait is an ActionTrait.\n * @param {unknown} trait The trait to check.\n * @returns {boolean} True if the trait is an ActionTrait, false otherwise.\n */\nfunction isAction(trait) {\n return Boolean(trait && typeof trait === \"string\" && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(trait) in _core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait);\n}\n/**\n * Checks if the given trait is an AttributeTrait.\n * @param {unknown} trait The trait to check.\n * @returns {boolean} True if the trait is an AttributeTrait, false otherwise.\n */\nfunction isAttribute(trait) {\n return Boolean(trait && typeof trait === \"string\" && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(trait) in _core_constants__WEBPACK_IMPORTED_MODULE_1__.AttributeTrait);\n}\n/**\n * Checks if the given trait is a Factor.\n * @param {unknown} trait The trait to check.\n * @returns {boolean} True if the trait is a Factor, false otherwise.\n */\nfunction isFactor(trait) {\n return Boolean(trait && typeof trait === \"string\" && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(trait) in _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor);\n}\n/**\n * Checks if the given string is a RollModStatus.\n * @param {unknown} str The string to check.\n * @returns {boolean} True if the string is a RollModStatus, false otherwise.\n */\nfunction isModStatus(str) {\n return typeof str === \"string\" && str in _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus;\n}\n/**\n * Checks if the given section can contain BladesRollParticipant documents.\n * @param {RollModSection} section\n */\nfunction isParticipantSection(section) {\n return [\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect\n ].includes(section);\n}\n/**\n * Checks if the given subSection can hold BladesRollParticipant documents.\n * @param {string} subSection\n */\nfunction isParticipantSubSection(subSection) {\n if (subSection.startsWith(\"Group_\")) {\n return true;\n }\n if ([\"Assist\", \"Setup\"].includes(subSection)) {\n return true;\n }\n return false;\n}\n// #endregion\n// #region Utility Functions ~\n// #endregion\nclass BladesRollMod extends _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"] {\n static ApplySchemaDefaults(schemaData) {\n // Ensure all properties of Schema are provided\n if (!schemaData.name) {\n throw new Error(\"name is required for BladesRollMod.Schema\");\n }\n return {\n key: `${schemaData.name}-positive-roll`,\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n posNeg: \"positive\",\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n value: 1,\n tooltip: \"\",\n ...schemaData\n };\n }\n static get GMOnlyModStatuses() {\n return [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden];\n }\n static getSchemaFromStrings(mStrings) {\n const nameString = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pullElement(mStrings, (v) => typeof v === \"string\" && /^na/i.test(v));\n const nameVal = (typeof nameString === \"string\" && nameString.replace(/^.*:/, \"\"));\n if (!nameVal) {\n throw new Error(`RollMod Missing Name: '${mStrings.join(\"@\")}'`);\n }\n const catString = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pullElement(mStrings, (v) => typeof v === \"string\" && /^cat/i.test(v));\n const catVal = (typeof catString === \"string\" && catString.replace(/^.*:/, \"\"));\n if (!catVal || !(catVal in _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection)) {\n throw new Error(`RollMod Missing Category: '${mStrings.join(\"@\")}'`);\n }\n const posNegString = (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pullElement(mStrings, (v) => typeof v === \"string\" && /^p/i.test(v)) || \"posNeg:positive\");\n const posNegVal = posNegString.replace(/^.*:/, \"\");\n return {\n key: `${nameVal}-${posNegVal}-${catVal}`,\n name: nameVal,\n section: catVal,\n posNeg: posNegVal,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n tooltip: \"\",\n value: 1,\n ...Object.fromEntries(mStrings.map(getModParameterKeyVal))\n };\n function getModParameterKeyVal(mString) {\n const [keyString, valString] = mString.split(/:/);\n let val = /\\|/.test(valString) ? valString.split(/\\|/) : valString;\n let key;\n if (/^stat/i.test(keyString)) {\n key = \"base_status\";\n }\n else if (/^val/i.test(keyString)) {\n key = \"value\";\n }\n else if (/^eff|^ekey/i.test(keyString)) {\n key = \"effectKeys\";\n }\n else if (/^side|^ss/i.test(keyString)) {\n key = \"sideString\";\n }\n else if (/^s.*ame/i.test(keyString)) {\n key = \"source_name\";\n }\n else if (/^tool|^tip/i.test(keyString)) {\n key = \"tooltip\";\n }\n else if (/^ty/i.test(keyString)) {\n key = \"modType\";\n }\n else if (/^c.{0,10}r?.{0,3}ty/i.test(keyString)) {\n key = \"conditionalRollTypes\";\n }\n else if (/^a.{0,3}r?.{0,3}y/i.test(keyString)) {\n key = \"autoRollTypes\";\n }\n else if (/^p.{0,10}r?.{0,3}y/i.test(keyString)) {\n key = \"participantRollTypes\";\n }\n else if (/^c.{0,10}r?.{0,3}tr/i.test(keyString)) {\n key = \"conditionalRollTraits\";\n }\n else if (/^a.{0,3}r?.{0,3}tr/i.test(keyString)) {\n key = \"autoRollTraits\";\n }\n else if (/^p.{0,10}r?.{0,3}tr/i.test(keyString)) {\n key = \"participantRollTypes\";\n }\n else {\n throw new Error(`Bad Roll Mod Key: ${keyString}`);\n }\n if (key === \"base_status\" && val === \"Conditional\") {\n val = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden;\n }\n let valProcessed;\n if ([\"value\"].includes(key)) {\n valProcessed = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(val);\n }\n else if ([\"effectKeys\", \"conditionalRollTypes\", \"autoRollTypes\", \"conditionalRollTraits\", \"autoRollTraits\"].includes(key)) {\n valProcessed = [val].flat();\n }\n else {\n valProcessed = val.replace(/%COLON%/g, \":\");\n }\n return [key, valProcessed];\n }\n }\n static ParseDocModsToSchemaSet(doc) {\n if (doc instanceof _BladesChat__WEBPACK_IMPORTED_MODULE_7__[\"default\"]) {\n throw new Error(\"BladesRollMod.ParseDocRollMods cannot be called on a BladesChat document.\");\n }\n const { roll_mods } = doc.system;\n if (!roll_mods || roll_mods.length === 0) {\n return [];\n }\n return roll_mods\n .filter((elem) => Boolean(elem && typeof elem === \"string\"))\n .map((modString) => {\n return this.getSchemaFromStrings(modString.split(/@/));\n });\n }\n isRerendering = false;\n get status() {\n // USER STATUS of \"ForcedOn\", \"ForcedOff\", or \"Hidden\" trumps all other status values.\n if (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)) {\n return this.userStatus;\n }\n // HELD STATUS of \"ToggledOff\" or \"ToggledOn\" can be overridden by User Status\n if (this.heldStatus && [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn].includes(this.heldStatus)) {\n return this.userStatus ?? this.heldStatus;\n }\n // Otherwise, return the first status that is set out of held, user, and base.\n return this.heldStatus ?? this.userStatus ?? this.baseStatus;\n }\n get isActive() { return [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn].includes(this.status); }\n get isVisible() { return this.status !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden; }\n // get flagParams() {\n // return [C.SYSTEM_ID, `rollCollab.rollModsData.${this.id}`] as const;}\n // async setUserStatusFlag(val: RollModStatus | undefined) {\n // }\n get isConditional() {\n return [\n ...this.conditionalRollTraits,\n ...this.autoRollTraits,\n ...this.participantRollTraits,\n ...this.conditionalRollTypes,\n ...this.autoRollTypes,\n ...this.participantRollTypes\n ].length > 0;\n }\n get isInInactiveBlock() {\n if (game.user.isGM) {\n return [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff].includes(this.status)\n && (this.isConditional || this.modType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.ability);\n }\n return [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff].includes(this.status)\n && (this.isConditional || this.modType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.ability);\n }\n get isPush() {\n return Boolean(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(this.name) === \"push\"\n || this.effectKeys.find((eKey) => eKey === \"Is-Push\"));\n }\n get isBasicPush() { return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(this.name) === \"push\"; }\n get stressCost() {\n const costKeys = this.effectKeys.filter((key) => key.startsWith(\"Cost-Stress\"));\n if (costKeys.length === 0) {\n return 0;\n }\n let stressCost = 0;\n costKeys.forEach((key) => {\n const [thisParam] = (key.split(/-/) ?? []).slice(1);\n const [_, valStr] = (/([A-Za-z]+)(\\d*)/.exec(thisParam) ?? []).slice(1);\n stressCost += _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(valStr);\n });\n return stressCost;\n }\n isValidForRollType() {\n switch (this.rollInstance.rollType) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action: {\n return true;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance:\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Fortune:\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.IndulgeVice: {\n if (this.isPush\n || [\"bargain\", \"setup\", \"assist\", \"potency\"].includes(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(this.name))) {\n return false;\n }\n return true;\n }\n default: return false;\n }\n }\n /**\n * Checks if any types or traits apply to the roll instance.\n * @param {AnyRollType[]} types The types to check.\n * @param {RollTrait[]} traits The traits to check.\n * @returns {boolean} - Returns true if any types or traits apply, false otherwise.\n */\n checkTypesOrTraits(types, traits) {\n const rollTypes = [this.rollInstance.rollType, this.rollInstance.rollSubType, this.rollInstance.rollDowntimeAction]\n .filter((rType) => Boolean(rType));\n const typesApply = (!this.rollInstance.isParticipantRoll && types.length === 0)\n || rollTypes.some((rType) => types.includes(rType));\n const traitsApply = (!this.rollInstance.isParticipantRoll && traits.length === 0)\n || (this.rollInstance.rollTrait && traits.includes(this.rollInstance.rollTrait));\n return Boolean(typesApply && traitsApply);\n }\n /**\n * Sets the conditional status of the roll mod instance.\n * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden.\n */\n setConditionalStatus() {\n // If the roll mod instance is not conditional, return false\n if (!this.isConditional) {\n return false;\n }\n // If any auto-Types apply, set status to ForcedOn and return false\n if (this.autoRollTypes.includes(this.rollInstance.rollType)\n || (this.rollInstance.rollSubType && this.autoRollTypes.includes(this.rollInstance.rollSubType))\n || (this.rollInstance.rollDowntimeAction && this.autoRollTypes.includes(this.rollInstance.rollDowntimeAction))) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn;\n return false;\n }\n // If any auto-Traits apply, set status to ForcedOn and return false\n if (this.rollInstance.rollTrait && this.autoRollTraits.includes(this.rollInstance.rollTrait)) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn;\n return false;\n }\n // If any conditionalTypes or conditionalTraits apply, set status to ToggledOff and return false\n if (this.checkTypesOrTraits(this.conditionalRollTypes, this.conditionalRollTraits)) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff;\n return false;\n }\n // If this is a participant roll\n // AND any participantTypes or participantTraits apply,\n // ... set status to ToggledOff and return false\n if (this.rollInstance.isParticipantRoll\n && this.checkTypesOrTraits(this.participantRollTypes, this.participantRollTraits)) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff;\n return false;\n }\n // If none of the above conditions apply, set status to Hidden and return true\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden;\n return true;\n }\n /**\n * Sets the auto-reveal/enable status of the roll mod instance.\n * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden.\n */\n setAutoStatus() {\n // Check for AutoRevealOn and AutoEnableOn\n const holdKeys = this.effectKeys.filter((key) => key.startsWith(\"Auto\"));\n if (holdKeys.length === 0) {\n return false;\n }\n for (const key of holdKeys) {\n const [thisKey, thisParam] = key.split(/-/) ?? [];\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(thisParam) in _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position && this.rollInstance.rollPositionFinal === _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(thisParam)) {\n if (thisKey === \"AutoRevealOn\") {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff;\n return false;\n }\n else if (thisKey === \"AutoEnableOn\") {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn;\n return false;\n }\n }\n }\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden;\n return true;\n }\n /**\n * Sets the relevancy status of the roll mod instance (i.e. hides irrelevant rollMods).\n * @returns {boolean} - Returns true if mod is irrelevant and status is Hidden, false otherwise.\n */\n setRelevancyStatus() {\n const holdKeys = this.effectKeys.filter((key) => /^Negate|^Increase/.test(key));\n if (holdKeys.length === 0) {\n return false;\n }\n const relevantKeys = holdKeys\n .filter((key) => {\n const [thisKey, thisParam] = key.split(/-/) ?? [];\n if (thisKey === \"Negate\") {\n const negateOperations = {\n PushCost: () => this.rollInstance.isPushed(),\n QualityPenalty: () => this.rollInstance.isTraitRelevant(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality)\n && (this.rollInstance.rollFactors.source[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]?.value ?? 0)\n < (this.rollInstance.rollFactors.opposition[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]?.value ?? 0),\n ScalePenalty: () => this.rollInstance.isTraitRelevant(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale)\n && (this.rollInstance.rollFactors.source[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]?.value ?? 0)\n < (this.rollInstance.rollFactors.opposition[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]?.value ?? 0),\n TierPenalty: () => this.rollInstance.isTraitRelevant(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier)\n && (this.rollInstance.rollFactors.source[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]?.value ?? 0)\n < (this.rollInstance.rollFactors.opposition[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]?.value ?? 0)\n };\n if (Object.hasOwn(negateOperations, thisParam)) {\n return negateOperations[thisParam]();\n }\n else {\n throw new Error(`Unrecognized Negate parameter: ${thisParam}`);\n }\n }\n else if (thisKey === \"Increase\") {\n const [_, traitStr] = /(\\w+)\\d+/.exec(thisParam) ?? [];\n return this.rollInstance.isTraitRelevant(traitStr);\n }\n else {\n throw new Error(`Unrecognized Function Key: ${thisKey}`);\n }\n });\n if (relevantKeys.length === 0) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden;\n return true;\n }\n return false;\n }\n /**\n * Sets the payable status of the roll mod instance (i.e. forces off rollMods the primary can't pay for).\n * @returns {boolean} - Returns true if mod is unpayable and status is ForcedOff, false otherwise.\n */\n setPayableStatus() {\n const holdKeys = this.effectKeys.filter((key) => key.startsWith(\"Cost\"));\n if (holdKeys.length === 0) {\n return false;\n }\n const payableKeys = holdKeys\n .filter((key) => {\n const [thisParam] = (key.split(/-/) ?? []).slice(1);\n const [traitStr, valStr] = (/([A-Za-z]+)(\\d*)/.exec(thisParam) ?? []).slice(1);\n const { rollPrimaryDoc } = this.rollInstance.rollPrimary ?? {};\n if (!BladesRollPrimary.IsDoc(rollPrimaryDoc)) {\n return false;\n }\n switch (traitStr) {\n case \"SpecialArmor\": {\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)\n && rollPrimaryDoc.system.armor.active.special\n && !rollPrimaryDoc.system.armor.checked.special;\n }\n case \"Stress\": {\n const val = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(valStr);\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)\n && rollPrimaryDoc.system.stress.max - rollPrimaryDoc.system.stress.value >= val;\n }\n case \"Heat\": {\n return (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(rollPrimaryDoc) && _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(rollPrimaryDoc.crew))\n || _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(rollPrimaryDoc);\n }\n default: throw new Error(`Unrecognize Payable Key: ${traitStr}`);\n }\n });\n if (payableKeys.length === 0) {\n this.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff;\n return true;\n }\n return false;\n }\n applyRollModEffectKeys() {\n if (!this.isActive) {\n return;\n }\n const holdKeyParams = this.effectKeys\n .filter((key) => /^Negate|^Increase/.test(key))\n .map((key) => key.split(/-/));\n if (holdKeyParams.length === 0) {\n return;\n }\n holdKeyParams.forEach(([key, param]) => {\n if (key === \"Negate\") {\n const negateOperations = {\n PushCost: () => {\n this.rollInstance.negatePushCost();\n },\n QualityPenalty: () => {\n this.rollInstance.negateFactorPenalty(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality);\n },\n ScalePenalty: () => {\n this.rollInstance.negateFactorPenalty(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale);\n },\n TierPenalty: () => {\n this.rollInstance.negateFactorPenalty(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier);\n }\n };\n if (Object.hasOwn(negateOperations, param)) {\n return negateOperations[param]();\n }\n else {\n throw new Error(`Unrecognized Negate parameter: ${param}`);\n }\n }\n else if (key === \"Increase\") {\n const [_, traitStr] = /(\\w+)\\d+/.exec(param) ?? [];\n return this.rollInstance.isTraitRelevant(traitStr);\n }\n else {\n throw new Error(`Unrecognized Function Key: ${key} (key: ${key})`);\n }\n });\n }\n get selectOptions() {\n if (this.modType !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.teamwork) {\n return null;\n }\n if (this.name === \"Assist\" || this.name === \"Setup\") {\n return this.rollInstance.rollParticipantSelectOptions[this.name];\n }\n else if (this.name.startsWith(\"Group_\")) {\n return this.rollInstance.rollParticipantSelectOptions.Group;\n }\n return null;\n }\n get selectedParticipant() {\n if (this.modType !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.teamwork) {\n return null;\n }\n return this.rollInstance.getRollParticipant(this.section, this.name);\n }\n get allFlagData() {\n return this.rollInstance.data;\n }\n get costs() {\n if (!this.isActive) {\n return undefined;\n }\n const holdKeys = this.effectKeys.filter((key) => key.startsWith(\"Cost\"));\n if (holdKeys.length === 0) {\n return undefined;\n }\n return holdKeys.map((key) => {\n const [thisParam] = (key.split(/-/) ?? []).slice(1);\n const [traitStr, valStr] = (/([A-Za-z]+)(\\d*)/.exec(thisParam) ?? []).slice(1);\n let label = this.name;\n if (this.isBasicPush) {\n if (this.posNeg === \"negative\") {\n label = `${this.name} (To Act)`;\n }\n else {\n const effect = this.section === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll ? \"+1d\" : \"+1 effect\";\n label = `${this.name} (${effect})`;\n }\n }\n return {\n id: this.id,\n label,\n costType: traitStr,\n costAmount: valStr ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(valStr) : 1\n };\n });\n }\n _rollInstance;\n constructor(modData, rollInstance) {\n super(modData);\n this._rollInstance = rollInstance;\n }\n get rollInstance() { return this._rollInstance; }\n get name() { return this.data.name; }\n get modType() { return this.data.modType; }\n get sourceName() { return this.data.source_name ?? this.data.name; }\n get section() { return this.data.section; }\n get posNeg() { return this.data.posNeg; }\n get userStatus() { return this.data.user_status; }\n set userStatus(val) {\n if (val === this.userStatus) {\n return;\n }\n const { isRerendering } = this;\n if (!val || val === this.baseStatus) {\n this.updateTarget(\"user_status\", null)\n .then(() => {\n if (isRerendering) {\n this.rollInstance.renderRollCollab_SocketCall();\n }\n });\n }\n else {\n if (!game.user.isGM\n && (BladesRollMod.GMOnlyModStatuses.includes(val)\n || (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)))) {\n return;\n }\n this.updateTarget(\"user_status\", val)\n .then(() => {\n if (isRerendering) {\n this.rollInstance.renderRollCollab_SocketCall();\n }\n });\n }\n }\n get baseStatus() { return this.data.base_status; }\n get heldStatus() { return this.data.held_status; }\n set heldStatus(val) {\n if (val === this.heldStatus) {\n return;\n }\n const { isRerendering } = this;\n if (!val) {\n this.updateTarget(\"held_status\", null)\n .then(() => {\n if (isRerendering) {\n this.rollInstance.renderRollCollab_SocketCall();\n }\n });\n }\n else {\n this.updateTarget(\"held_status\", val)\n .then(() => {\n if (isRerendering) {\n this.rollInstance.renderRollCollab_SocketCall();\n }\n });\n }\n }\n get value() { return this.data.value; }\n get effectKeys() { return this.data.effectKeys ?? []; }\n get sideString() {\n if (this.data.sideString) {\n return this.data.sideString;\n }\n if (this.selectedParticipant) {\n return this.selectedParticipant.rollParticipantName;\n }\n return undefined;\n }\n get tooltip() {\n let parsedTooltip = this.data.tooltip.replace(/%COLON%/g, \":\");\n if (parsedTooltip.includes(\"%DOC_NAME%\")) {\n parsedTooltip = parsedTooltip.replace(/%DOC_NAME%/g, this.selectedParticipant\n ? this.selectedParticipant.rollParticipantName\n : \"an Ally\");\n }\n if (parsedTooltip.includes(\"@OPPOSITION_NAME@\")) {\n parsedTooltip = parsedTooltip.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition\n ? this.rollInstance.rollOpposition.rollOppName\n : \"Your Opposition\");\n }\n return parsedTooltip;\n }\n get conditionalRollTypes() {\n return this.data.conditionalRollTypes ?? [];\n }\n get autoRollTypes() {\n return this.data.autoRollTypes ?? [];\n }\n get participantRollTypes() {\n return this.data.participantRollTypes ?? [];\n }\n get conditionalRollTraits() {\n return this.data.conditionalRollTraits ?? [];\n }\n get autoRollTraits() {\n return this.data.autoRollTraits ?? [];\n }\n get participantRollTraits() {\n return this.data.participantRollTraits ?? [];\n }\n}\nclass BladesRollPrimary {\n // #region Static Methods ~\n static IsValidData(data) {\n if (BladesRollPrimary.IsDoc(data)) {\n return false;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data)\n && typeof data.rollPrimaryName === \"string\"\n && typeof data.rollPrimaryType === \"string\"\n && typeof data.rollPrimaryImg === \"string\"\n && Array.isArray(data.rollPrimaryModsSchemaSet)\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data.rollFactors)\n && (!data.rollPrimaryID || typeof data.rollPrimaryID === \"string\")\n && (!data.rollPrimaryDoc || BladesRollPrimary.IsDoc(data.rollPrimaryDoc));\n }\n static GetDoc(docRef) {\n let doc = docRef;\n if (typeof docRef === \"string\") {\n doc = game.actors.get(docRef)\n ?? game.items.get(docRef)\n ?? game.actors.getName(docRef)\n ?? game.items.getName(docRef);\n }\n return BladesRollPrimary.IsDoc(doc) && doc;\n }\n static IsDoc(doc) {\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew)\n || _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gm_tracker);\n }\n static GetDataFromDoc(doc) {\n return {\n rollPrimaryID: doc.id,\n rollPrimaryName: doc.name,\n rollPrimaryType: doc.type,\n rollPrimaryImg: doc.img,\n rollPrimaryModsSchemaSet: doc.rollPrimaryModsSchemaSet,\n rollFactors: doc.rollFactors\n };\n }\n static BuildData(config) {\n if (BladesRollPrimary.IsValidData(config.rollPrimaryData)) {\n return config.rollPrimaryData;\n }\n let rollPrimary;\n const rollUser = game.users.get(config.rollUserID ?? game.user.id);\n if (\"target\" in config && BladesRollPrimary.IsDoc(config.target)) {\n rollPrimary = config.target;\n }\n else if (rollUser && BladesRollPrimary.IsDoc(rollUser.character)) {\n rollPrimary = rollUser.character;\n }\n else {\n throw new Error(\"[BladesRollPrimary.BuildData()] A valid source of PrimaryData must be provided to construct a roll.\");\n }\n return {\n rollPrimaryID: rollPrimary.rollPrimaryID,\n rollPrimaryName: rollPrimary.rollPrimaryName,\n rollPrimaryType: rollPrimary.rollPrimaryType,\n rollPrimaryImg: rollPrimary.rollPrimaryImg,\n rollPrimaryModsSchemaSet: rollPrimary.rollPrimaryModsSchemaSet,\n rollFactors: rollPrimary.rollFactors\n };\n }\n static Build(config) {\n return new BladesRollPrimary(this.BuildData(config));\n }\n // #endregion\n rollInstance;\n rollPrimaryID;\n _rollPrimaryDoc;\n get rollPrimaryDoc() {\n if (!this._rollPrimaryDoc) {\n let doc;\n if (this.rollPrimaryID) {\n doc = game.items.get(this.rollPrimaryID)\n ?? game.actors.get(this.rollPrimaryID);\n }\n if (!doc && this.rollPrimaryName) {\n doc = game.items.getName(this.rollPrimaryName)\n ?? game.actors.getName(this.rollPrimaryName);\n }\n if (BladesRollPrimary.IsDoc(doc)) {\n this._rollPrimaryDoc = doc;\n }\n }\n return this._rollPrimaryDoc;\n }\n rollPrimaryName;\n rollPrimaryType;\n rollPrimaryImg;\n rollPrimaryModsSchemaSet;\n rollFactors;\n get data() {\n return {\n rollPrimaryID: this.rollPrimaryID,\n rollPrimaryName: this.rollPrimaryName,\n rollPrimaryType: this.rollPrimaryType,\n rollPrimaryImg: this.rollPrimaryImg,\n rollPrimaryModsSchemaSet: this.rollPrimaryModsSchemaSet,\n rollFactors: this.rollFactors\n };\n }\n get isWorsePosition() {\n if (this.rollPrimaryDoc) {\n return this.rollPrimaryDoc.getFlag(\"eunos-blades\", \"isWorsePosition\") === true;\n }\n return false;\n }\n async applyHarm(amount, name) {\n if (this.rollPrimaryDoc) {\n return this.rollPrimaryDoc.applyHarm(amount, name);\n }\n }\n async applyWorsePosition() {\n if (this.rollPrimaryDoc) {\n return this.rollPrimaryDoc.applyWorsePosition();\n }\n }\n get hasSpecialArmor() {\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.rollPrimaryDoc) && this.rollPrimaryDoc.isSpecialArmorAvailable;\n }\n get availableArmorCount() {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.rollPrimaryDoc)) {\n return this.rollPrimaryDoc.availableArmor.length;\n }\n else if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(this.rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert)) {\n return this.rollPrimaryDoc.system.armor.max - this.rollPrimaryDoc.system.armor.value;\n }\n return 0;\n }\n async spendArmor(count) {\n if (!this.rollPrimaryDoc) {\n throw new Error(\"[BladesRollPrimary.spendArmor()] Cannot spend armor when rollPrimaryDoc is not defined.\");\n }\n if (count > this.availableArmorCount) {\n throw new Error(`[BladesRollPrimary.spendArmor()] Cannot spend more armor (${count}) than ${this.rollPrimaryDoc?.name} has (${this.availableArmorCount}).`);\n }\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.rollPrimaryDoc)) {\n const armorToSpend = this.rollPrimaryDoc.availableArmor.slice(0, count);\n const updateData = {};\n if (armorToSpend.includes(\"Light Armor\")) {\n updateData[\"system.armor.active.light\"] = true;\n updateData[\"system.armor.checked.light\"] = true;\n }\n if (armorToSpend.includes(\"Heavy Armor\")) {\n updateData[\"system.armor.active.heavy\"] = true;\n updateData[\"system.armor.checked.heavy\"] = true;\n }\n await this.rollPrimaryDoc.update(updateData);\n }\n else if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(this.rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert)) {\n await this.rollPrimaryDoc.update({ \"system.armor.value\": this.rollPrimaryDoc.system.armor.value + count });\n }\n }\n constructor(...args) {\n let primaryData = false;\n let primaryDoc = false;\n if (args[0] instanceof BladesRoll) {\n this.rollInstance = args[0];\n args.shift();\n }\n if (BladesRollPrimary.IsDoc(args[0])) {\n primaryDoc = args[0];\n }\n else if (BladesRollPrimary.IsValidData(args[0])) {\n primaryData = args[0];\n }\n else if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(args[0])) {\n if (\"rollPrimaryID\" in args[0]) {\n primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryID);\n }\n else if (\"rollPrimaryName\" in args[0]) {\n primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryName);\n }\n }\n if (primaryDoc && !BladesRollPrimary.IsValidData(primaryData)) {\n primaryData = {\n rollPrimaryID: primaryDoc.rollPrimaryID,\n rollPrimaryName: primaryDoc.rollPrimaryName,\n rollPrimaryType: primaryDoc.rollPrimaryType,\n rollPrimaryImg: primaryDoc.rollPrimaryImg,\n rollPrimaryModsSchemaSet: primaryDoc.rollPrimaryModsSchemaSet,\n rollFactors: primaryDoc.rollFactors\n };\n }\n if (!BladesRollPrimary.IsValidData(primaryData) && !BladesRollPrimary.IsDoc(primaryDoc) && this.rollInstance) {\n primaryData = this.rollInstance.rollPrimary.data;\n }\n if (!BladesRollPrimary.IsValidData(primaryData)) {\n throw new Error(`[BladesRoll.constructor] Failed to resolve primary data from provided arguments: ${JSON.stringify(args)}`);\n }\n const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryImg, rollPrimaryModsSchemaSet, rollFactors } = primaryData;\n this.rollPrimaryID = rollPrimaryID;\n if (!rollPrimaryName) {\n throw new Error(\"Must include a rollPrimaryName when constructing a BladesRollPrimary object.\");\n }\n if (!rollPrimaryImg) {\n throw new Error(\"Must include a rollPrimaryImg when constructing a BladesRollPrimary object.\");\n }\n if (!rollPrimaryType) {\n throw new Error(\"Must include a rollPrimaryType when constructing a BladesRollPrimary object.\");\n }\n if (!rollFactors) {\n throw new Error(\"Must include a rollFactors when constructing a BladesRollPrimary object.\");\n }\n this.rollPrimaryName = rollPrimaryName;\n this.rollPrimaryType = rollPrimaryType;\n this.rollPrimaryImg = rollPrimaryImg;\n this.rollFactors = rollFactors;\n this.rollPrimaryModsSchemaSet = rollPrimaryModsSchemaSet ?? [];\n }\n}\nclass BladesRollOpposition {\n // #region Static Methods ~\n static IsValidData(data) {\n if (BladesRollOpposition.IsDoc(data)) {\n return true;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data)\n && typeof data.rollOppName === \"string\"\n && typeof data.rollOppType === \"string\"\n && typeof data.rollOppImg === \"string\"\n && (!data.rollOppSubName || typeof data.rollOppSubName === \"string\")\n && (!data.rollOppModsSchemaSet || Array.isArray(data.rollOppModsSchemaSet))\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data.rollFactors)\n && (!data.rollOppID || typeof data.rollOppID === \"string\");\n }\n static GetDoc(docRef) {\n let doc = docRef;\n if (typeof docRef === \"string\") {\n doc = game.actors.get(docRef)\n ?? game.items.get(docRef)\n ?? game.actors.getName(docRef)\n ?? game.items.getName(docRef);\n }\n if (BladesRollOpposition.IsDoc(doc)) {\n return doc;\n }\n return false;\n }\n static IsDoc(doc) {\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.faction) || _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang);\n }\n static GetDataFromDoc(doc) {\n return {\n rollOppID: doc.id,\n rollOppName: doc.name,\n rollOppType: doc.type,\n rollOppImg: doc.img,\n rollOppModsSchemaSet: doc.rollOppModsSchemaSet,\n rollFactors: doc.rollFactors\n };\n }\n // #endregion\n rollInstance;\n rollOppID;\n rollOppDoc;\n rollOppName;\n rollOppSubName;\n rollOppType;\n rollOppImg;\n rollOppModsSchemaSet;\n rollFactors;\n // #region Constructor ~\n constructor(rollInstance, { rollOppID, rollOppName, rollOppSubName, rollOppType, rollOppImg, rollOppModsSchemaSet, rollFactors } = {}) {\n this.rollInstance = rollInstance;\n // Attempt to fetch an associated BladesActor or BladesItem document\n const doc = BladesRollOpposition.GetDoc(rollOppID ?? rollOppName);\n if (doc) {\n // Derive settings from valid Actor/Item document, unless explicitly set in constructor.\n this.rollOppDoc = doc;\n rollOppID = doc.rollOppID;\n rollOppName ??= doc.rollOppName;\n rollOppSubName ??= doc.rollOppSubName;\n rollOppType ??= doc.rollOppType;\n rollOppImg ??= doc.rollOppImg;\n rollOppModsSchemaSet = [\n ...rollOppModsSchemaSet ?? [],\n ...doc.rollOppModsSchemaSet ?? []\n ];\n rollFactors = {\n ...doc.rollFactors,\n ...rollFactors ?? {}\n };\n }\n // Confirm required settings\n if (!rollOppName) {\n throw new Error(\"Must include a rollOppName when constructing a BladesRollOpposition object.\");\n }\n if (!rollOppType) {\n throw new Error(\"Must include a rollOppType when constructing a BladesRollOpposition object.\");\n }\n if (!rollFactors) {\n throw new Error(\"Must include a rollFactors when constructing a BladesRollOpposition object.\");\n }\n // Initialize properties\n this.rollOppID = rollOppID;\n this.rollOppName = rollOppName;\n this.rollOppSubName = rollOppSubName;\n this.rollOppType = rollOppType;\n this.rollOppImg = rollOppImg ?? \"\";\n this.rollOppModsSchemaSet = rollOppModsSchemaSet ?? [];\n this.rollFactors = rollFactors;\n }\n // #endregion\n get data() {\n return {\n rollOppID: this.rollOppID,\n rollOppName: this.rollOppName,\n rollOppSubName: this.rollOppSubName,\n rollOppType: this.rollOppType,\n rollOppImg: this.rollOppImg,\n rollOppModsSchemaSet: this.rollOppModsSchemaSet,\n rollFactors: this.rollFactors\n };\n }\n async updateRollFlags() {\n if (!this.rollInstance) {\n return;\n }\n await this.rollInstance.updateTarget(\"rollOppData\", this.data);\n if (this.rollInstance.isRendered) {\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.rollInstance.id);\n }\n }\n refresh() {\n if (!this.rollInstance) {\n return;\n }\n const rollOppFlags = this.rollInstance.data.rollOppData;\n if (rollOppFlags) {\n this.rollOppID = rollOppFlags.rollOppID;\n this.rollOppName = rollOppFlags.rollOppName;\n this.rollOppSubName = rollOppFlags.rollOppSubName;\n this.rollOppType = rollOppFlags.rollOppType;\n this.rollOppImg = rollOppFlags.rollOppImg;\n this.rollOppModsSchemaSet = rollOppFlags.rollOppModsSchemaSet ?? [];\n this.rollFactors = rollOppFlags.rollFactors;\n }\n return this;\n }\n}\nclass BladesRollParticipant {\n // #region Static Methods ~\n static IsValidData(data) {\n if (BladesRollParticipant.IsDoc(data)) {\n return true;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data)\n && typeof data.rollParticipantName === \"string\"\n && typeof data.rollParticipantType === \"string\"\n && typeof data.rollParticipantIcon === \"string\"\n && (!data.rollParticipantModsSchemaSet || Array.isArray(data.rollParticipantModsSchemaSet))\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(data.rollFactors)\n && (!data.rollParticipantID || typeof data.rollParticipantID === \"string\")\n && (!data.rollParticipantDoc || BladesRollParticipant.IsDoc(data.rollParticipantDoc));\n }\n static GetDoc(docRef) {\n let doc = docRef;\n if (typeof docRef === \"string\") {\n doc = game.actors.get(docRef)\n ?? game.items.get(docRef)\n ?? game.actors.getName(docRef)\n ?? game.items.getName(docRef);\n }\n if (BladesRollParticipant.IsDoc(doc)) {\n return doc;\n }\n return false;\n }\n static IsDoc(doc) {\n return _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc)\n || _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gm_tracker);\n }\n // #endregion\n rollInstance;\n rollParticipantID;\n rollParticipantDoc;\n rollParticipantName;\n rollParticipantType;\n rollParticipantIcon;\n rollParticipantSection;\n rollParticipantSubSection;\n rollParticipantModsSchemaSet; // As applied to MAIN roll when this participant involved\n rollFactors;\n constructor(rollInstance, section, subSection, rollParticipantDataOrDoc) {\n this.rollInstance = rollInstance;\n if (!section) {\n throw new Error(\"Must include a rollParticipantSection when constructing a BladesRollParticipant object.\");\n }\n if (!subSection) {\n throw new Error(\"Must include a rollParticipantSubSection when constructing a BladesRollParticipant object.\");\n }\n this.rollParticipantSection = section;\n this.rollParticipantSubSection = subSection;\n // Attempt to fetch an associated BladesActor or BladesItem document\n const doc = BladesRollParticipant.IsDoc(rollParticipantDataOrDoc)\n ? rollParticipantDataOrDoc\n : BladesRollParticipant.GetDoc(rollParticipantDataOrDoc.rollParticipantID ?? rollParticipantDataOrDoc.rollParticipantName);\n if (doc) {\n rollParticipantDataOrDoc = doc;\n }\n // Confirm required settings\n if (!rollParticipantDataOrDoc.rollParticipantName) {\n throw new Error(\"Must include a rollParticipantName when constructing a BladesRollParticipant object.\");\n }\n if (!rollParticipantDataOrDoc.rollParticipantType) {\n throw new Error(\"Must include a rollParticipantType when constructing a BladesRollParticipant object.\");\n }\n if (!rollParticipantDataOrDoc.rollFactors) {\n throw new Error(\"Must include a rollFactors when constructing a BladesRollParticipant object.\");\n }\n // Initialize properties\n this.rollParticipantID = rollParticipantDataOrDoc.rollParticipantID;\n this.rollParticipantName = rollParticipantDataOrDoc.rollParticipantName;\n this.rollParticipantType = rollParticipantDataOrDoc.rollParticipantType;\n this.rollParticipantIcon = rollParticipantDataOrDoc.rollParticipantIcon ?? \"\";\n this.rollParticipantModsSchemaSet = rollParticipantDataOrDoc.rollParticipantModsSchemaSet ?? [];\n this.rollFactors = rollParticipantDataOrDoc.rollFactors;\n }\n // #endregion\n get data() {\n return {\n rollParticipantID: this.rollParticipantID,\n rollParticipantName: this.rollParticipantName,\n rollParticipantType: this.rollParticipantType,\n rollParticipantIcon: this.rollParticipantIcon,\n rollParticipantModsSchemaSet: this.rollParticipantModsSchemaSet,\n rollFactors: this.rollFactors\n };\n }\n async updateRollFlags() {\n await this.rollInstance.updateTarget(`rollParticipantData.${this.rollParticipantSection}.${this.rollParticipantSubSection}`, this.data);\n if (this.rollInstance.isRendered) {\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.rollInstance.id);\n }\n }\n refresh() {\n const rollParticipantFlagData = this.rollInstance.data.rollParticipantData?.[this.rollParticipantSection];\n if (rollParticipantFlagData && this.rollParticipantSubSection in rollParticipantFlagData) {\n const rollParticipantFlags = rollParticipantFlagData[this.rollParticipantSubSection];\n if (rollParticipantFlags) {\n this.rollParticipantID = rollParticipantFlags.rollParticipantID;\n this.rollParticipantName = rollParticipantFlags.rollParticipantName;\n this.rollParticipantType = rollParticipantFlags.rollParticipantType;\n this.rollParticipantIcon = rollParticipantFlags.rollParticipantIcon;\n this.rollParticipantModsSchemaSet = rollParticipantFlags.rollParticipantModsSchemaSet ?? [];\n this.rollFactors = rollParticipantFlags.rollFactors;\n }\n }\n return this;\n }\n}\nclass BladesRoll extends _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"] {\n static Debug = {\n modWatch: false,\n watchRollMod(name) {\n if (typeof name === \"string\") {\n BladesRoll.Debug.modWatch = new RegExp(name, \"g\");\n }\n else {\n BladesRoll.Debug.modWatch = false;\n }\n }\n };\n // #region STATIC METHODS: INITIALIZATION & DEFAULTS ~\n static Initialize() {\n return loadTemplates([\n \"systems/eunos-blades/templates/roll/partials/roll-collab-gm-number-line.hbs\",\n \"systems/eunos-blades/templates/roll/partials/roll-collab-gm-select-doc.hbs\",\n \"systems/eunos-blades/templates/roll/partials/roll-collab-gm-factor-control.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-action.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-action-gm.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-resistance.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-resistance-gm.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-fortune.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-fortune-gm.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-indulgevice.hbs\",\n \"systems/eunos-blades/templates/roll/roll-collab-indulgevice-gm.hbs\"\n ]);\n }\n static InitSockets() {\n socketlib.system.register(\"constructRollCollab_SocketCall\", BladesRoll.constructRollCollab_SocketResponse.bind(BladesRoll));\n socketlib.system.register(\"renderRollCollab_SocketCall\", BladesRoll.renderRollCollab_SocketResponse.bind(BladesRoll));\n socketlib.system.register(\"closeRollCollab_SocketCall\", BladesRoll.closeRollCollab_SocketResponse.bind(BladesRoll));\n }\n static ParseConfigToData(data, parentRollData) {\n const parentRollInst = game.eunoblades.Rolls.get(parentRollData.id);\n if (!parentRollInst) {\n throw new Error(`[BladesRoll.ParseConfigToData] No BladesRoll instance found with id ${parentRollData.id}.`);\n }\n if (data.rollPrimaryData instanceof BladesRollPrimary) {\n data.rollPrimaryData = data.rollPrimaryData.data;\n }\n if (data.rollOppData instanceof BladesRollOpposition) {\n data.rollOppData = data.rollOppData.data;\n }\n if (data.rollParticipantData) {\n if (data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll]) {\n Object.keys(data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll]).forEach((key) => {\n const thisParticipant = data.rollParticipantData?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll]?.[key];\n if (thisParticipant instanceof BladesRollParticipant) {\n data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll][key] = thisParticipant.data;\n }\n });\n }\n if (data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position]) {\n Object.keys(data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position]).forEach((key) => {\n const thisParticipant = data.rollParticipantData?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position]?.[key];\n if (thisParticipant instanceof BladesRollParticipant) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position][key] = thisParticipant.data;\n }\n });\n }\n if (data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect]) {\n Object.keys(data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect]).forEach((key) => {\n const thisParticipant = data.rollParticipantData?.[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect]?.[key];\n if (thisParticipant instanceof BladesRollParticipant) {\n // eslint-disable-next-line @typescript-eslint/no-non-null-assertion\n data.rollParticipantData[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect][key] = thisParticipant.data;\n }\n });\n }\n }\n return super.ParseConfigToData(data);\n }\n static ApplySchemaDefaults(schemaData) {\n // Ensure all properties of Schema are provided\n if (!schemaData.rollType) {\n throw new Error(\"Must include a rollType when constructing a BladesRoll object.\");\n }\n schemaData.rollPhase ??= _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.Collaboration;\n schemaData.GMBoosts = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: 0,\n ...schemaData.GMBoosts ?? {}\n };\n schemaData.GMOppBoosts = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: 0,\n ...schemaData.GMOppBoosts ?? {}\n };\n schemaData.GMOverrides ??= {};\n schemaData.userPermissions ??= {};\n if (schemaData.rollPrimaryData instanceof BladesRollPrimary) {\n schemaData.rollPrimaryData = schemaData.rollPrimaryData.data;\n }\n if (schemaData.rollOppData instanceof BladesRollOpposition) {\n schemaData.rollOppData = schemaData.rollOppData.data;\n }\n return schemaData;\n }\n // static override get defaultOptions() {\n // return foundry.utils.mergeObject(super.defaultOptions, {\n // classes: [\"eunos-blades\", \"sheet\", \"roll-collab\", game.user.isGM ? \"gm-roll-collab\" : \"\"],\n // template: `systems/eunos-blades/templates/roll/roll-collab${game.user.isGM ? \"-gm\" : \"\"}.hbs`,\n // submitOnChange: true,\n // width: 500,\n // dragDrop: [\n // {dragSelector: null, dropSelector: \"[data-action='gm-drop-opposition'\"}\n // ]\n // // Height: 500\n // });\n // }\n static get DefaultRollModSchemaSet() {\n /* Subclass overrides determine default roll mods. */\n return [];\n }\n static GetDieClass(rollType, rollResult, dieVal, dieIndex) {\n switch (rollType) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance: {\n if (dieVal === 6 && dieIndex <= 1 && rollResult === -1) {\n return \"blades-die-critical\";\n }\n if (dieIndex === 0) {\n return \"blades-die-resistance\";\n }\n return \"blades-die-fail\";\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.IndulgeVice: {\n if (dieIndex === 0) {\n return \"blades-die-indulge-vice\";\n }\n return \"blades-die-fail\";\n }\n default: break;\n }\n if (dieVal === 6 && dieIndex <= 1 && rollResult === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.critical) {\n dieVal++;\n }\n return [\n \"\",\n \"blades-die-fail\",\n \"blades-die-fail\",\n \"blades-die-fail\",\n \"blades-die-partial\",\n \"blades-die-partial\",\n \"blades-die-success\",\n \"blades-die-critical\"\n ][dieVal];\n }\n static GetDieImage(rollType, rollResult, dieVal, dieIndex, isGhost = false, isCritical = false) {\n let imgPath = \"systems/eunos-blades/assets/dice/image/\";\n if (isGhost) {\n imgPath += \"ghost-\";\n }\n else if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.IndulgeVice].includes(rollType)) {\n imgPath += \"grad-\";\n }\n imgPath += dieVal;\n if (!isGhost && dieVal === 6 && dieIndex <= 1 && isCritical) {\n imgPath += \"-crit\";\n }\n imgPath += \".webp\";\n return imgPath;\n }\n static get Active() {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getLast(game.eunoblades.Rolls.filter((roll) => roll.isActive));\n }\n // #endregion\n // #region STATIC METHODS: New Roll Creation ~\n // static Current: Record = {};\n // static _Active?: BladesRoll;\n // static get Active(): BladesRoll | undefined {\n // if (BladesRoll._Active) {return BladesRoll._Active;}\n // if (U.objSize(BladesRoll.Current) > 0) {return U.getLast(Object.values(BladesRoll.Current));}\n // return undefined;\n // }\n // static set Active(val: BladesRoll | undefined) {\n // BladesRoll._Active = val;\n // }\n static GetUserPermissions(config) {\n if (!config.rollPrimaryData) {\n throw new Error(\"[BladesRoll.GetUserPermissions()] Missing rollPrimaryData.\");\n }\n // === ONE === GET USER IDS\n // Get user ID of GM\n const GMUserID = game.users.find((user) => user.isGM)?.id;\n if (!GMUserID) {\n throw new Error(\"[BladesRoll.GetUserPermissions()] No GM found!\");\n }\n // Get user IDs of players\n const playerUserIDs = game.users\n .filter((user) => _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(user.character) && !user.isGM && typeof user.id === \"string\")\n .map((user) => user.id);\n // Prepare user ID permissions object\n const userIDs = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.GM]: [GMUserID],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary]: [],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Participant]: [],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Observer]: []\n };\n // === TWO === DETERMINE PRIMARY USER(S)\n // Check RollPrimaryDoc to determine how to assign primary users\n const { rollPrimaryDoc } = (new BladesRollPrimary(config.rollPrimaryData));\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(rollPrimaryDoc)\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pullElement(playerUserIDs, rollPrimaryDoc.primaryUser?.id)) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].push(rollPrimaryDoc.primaryUser?.id);\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(rollPrimaryDoc)) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].push(...playerUserIDs);\n }\n else if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert)) {\n if (config.rollUserID === GMUserID) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].push(...playerUserIDs);\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(rollPrimaryDoc.parent)\n && rollPrimaryDoc.parent.primaryUser?.id) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].push(rollPrimaryDoc.parent.primaryUser.id);\n }\n }\n else if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesGMTracker.IsType(rollPrimaryDoc)) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].push(GMUserID);\n }\n // === THREE === DETERMINE ROLL PARTICIPANT USER(S)\n // Check config.rollParticipantData to determine if roll starts with any participants\n if (config.rollParticipantData) {\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Participant].push(...getParticipantDocUserIDs(config.rollParticipantData, playerUserIDs));\n }\n // === FOUR === ASSIGN ROLL OBSERVERS\n // Add remaining players as observers.\n userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Observer] = playerUserIDs\n .filter((uID) => !userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Participant].includes(uID));\n // === FIVE === PARSE INTO {ID: PERMISSION} FORMAT\n const userFlagData = {};\n Object.entries(userIDs)\n .forEach(([rollPermission, idsArray]) => {\n for (const id of idsArray) {\n userFlagData[id] = rollPermission;\n }\n });\n return userFlagData;\n /**\n * Generates BladesRollParticipant documents from the provided schema data.\n * @param {BladesRoll.RollParticipantDataSet} participantData\n */\n function getParticipantDocs(participantData) {\n return Object.values(flattenObject(participantData))\n .map((pData) => {\n if (BladesRollParticipant.IsDoc(pData)) {\n return pData;\n }\n if (BladesRollParticipant.IsValidData(pData)) {\n if (typeof pData.rollParticipantID === \"string\") {\n const pDoc = game.actors.get(pData.rollParticipantID) ?? game.items.get(pData.rollParticipantID);\n if (BladesRollParticipant.IsDoc(pDoc)) {\n return pDoc;\n }\n }\n }\n // Throw an error with sufficient debug data if pData does not match any expected types\n throw new Error(`[getParticipantDocs] Invalid participant data encountered. Data: ${JSON.stringify(pData)}, Expected: \"BladesRollParticipant or valid participant data\", Function Context: \"getParticipantDocs\", Participant Data: ${JSON.stringify(participantData)}`);\n });\n }\n /**\n * Returns the user ids of potential BladesRollParticipants defined in the provided data schema.\n * @param {BladesRoll.RollParticipantDataSet} participantData\n * @param {IDString[]} unassignedIDs\n */\n function getParticipantDocUserIDs(participantData, unassignedIDs) {\n return getParticipantDocs(participantData)\n .map((pDoc) => {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(pDoc) && typeof pDoc.primaryUser?.id === \"string\") {\n return pDoc.primaryUser.id;\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(pDoc)\n || _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(pDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert)) {\n return unassignedIDs;\n }\n return null;\n })\n .flat()\n .filter((pUser) => pUser !== null && !userIDs[_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary].includes(pUser));\n }\n }\n static BuildLinkConfig(config) {\n // Prepare partial target link config\n const partialLinkConfig = {};\n if (\"targetKey\" in config && config.targetKey) {\n partialLinkConfig.targetKey = config.targetKey;\n }\n else if (\"targetFlagKey\" in config && config.targetFlagKey) {\n partialLinkConfig.targetFlagKey = config.targetFlagKey;\n }\n if (\"target\" in config) {\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocUUID(config.target)) {\n partialLinkConfig.targetID = config.target;\n }\n else if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(config.target)) {\n const confTarget = game.actors.get(config.target)\n ?? game.items.get(config.target)\n ?? game.messages.get(config.target)\n ?? game.users.get(config.target);\n if (confTarget) {\n partialLinkConfig.targetID = confTarget.uuid;\n }\n else {\n throw new Error(`[BladesRoll.BuildLinkConfig] No target found with id ${config.target}.`);\n }\n }\n else {\n partialLinkConfig.targetID = config.target.uuid;\n }\n }\n else if (\"targetID\" in config) {\n partialLinkConfig.targetID = config.targetID;\n }\n else {\n throw new Error(\"[BladesRoll.BuildLinkConfig] You must provide a valid target or targetID in the config object.\");\n }\n // If neither targetKey nor targetFlagKey are provided, set targetFlagKey to 'rollCollab'.\n if (!partialLinkConfig.targetKey && !partialLinkConfig.targetFlagKey) {\n partialLinkConfig.targetFlagKey = \"rollCollab\";\n }\n // Build target link config\n if (_BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"].IsValidConfig(partialLinkConfig)) {\n return _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"].BuildLinkConfig(partialLinkConfig);\n }\n throw new Error(\"[BladesRoll.BuildLinkConfig] Invalid link config.\");\n }\n /**\n * Asynchronously creates a new instance of `BladesRoll` or its subclasses.\n *\n * This generic static method is designed to facilitate the creation of roll instances with\n * configurations specific to the type of roll being created. It ensures that the correct type\n * of roll instance is returned based on the class it's called on, allowing for a flexible and\n * type-safe creation process that can be extended to subclasses of `BladesRoll`.\n *\n * @template C The class on which `New` is called. This class must extend `BladesRoll` and\n * must be constructible with a configuration object that is either a `BladesRoll.Config` or\n * a combination of `BladesTargetLink.Data` and a partial `BladesRoll.Schema`. This ensures\n * that any subclass of `BladesRoll` can use this method to create instances of itself while\n * applying any class-specific configurations or behaviors.\n *\n * @param {BladesRoll.Config} config The configuration object for creating a new roll instance.\n * This configuration includes all necessary data to initialize the roll, such as user permissions,\n * roll type, and any modifications or additional data required for the roll's operation.\n *\n * @returns {Promise>} A promise that resolves to an instance of the class\n * from which `New` was called. This allows for the dynamic creation of roll instances based\n * on the subclass calling the method, ensuring that the returned instance is of the correct type.\n *\n * @example\n * // Assuming `MyCustomRoll` is a subclass of `BladesRoll`\n * MyCustomRoll.New(myConfig).then(instance => {\n * // `instance` is of type `MyCustomRoll`\n * });\n *\n * @remarks\n * - The method performs several key operations as part of the roll instance creation process:\n * 1. Builds link configuration based on the provided config.\n * 2. Prepares roll user flag data to determine permissions for different users.\n * 3. Validates that a roll type is defined in the config, throwing an error if not.\n * 4. Logs the roll data for debugging or auditing purposes.\n * 5. Constructs and initializes the roll instance, including setting up roll modifications\n * and sending out socket calls to inform all users about the roll.\n * - This method is central to the dynamic and flexible creation of roll instances within the\n * system, allowing for easy extension and customization in subclasses of `BladesRoll`.\n */\n static async New(config) {\n // Build link config\n const linkConfig = this.BuildLinkConfig(config);\n // Prepare roll user flag data\n config.userPermissions = this.GetUserPermissions(config);\n // Ensure rollType is defined\n if (!config.rollType) {\n throw new Error(\"rollType must be defined in config\");\n }\n // Log the roll data\n eLog.checkLog3(\"bladesRoll\", \"BladesRoll.NewRoll()\", { config });\n // Construct and initialize the BladesRoll/BladesTargetLink instance\n const rollInst = await this.Create({ ...config, ...linkConfig });\n if (!rollInst.isInitPromiseResolved) {\n eLog.checkLog3(\"bladesRoll\", \"BladesRoll Init Promise NOT Resolved After Awaiting Create\");\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor(rollInst.initPromise);\n }\n else {\n eLog.checkLog3(\"bladesRoll\", \"BladesRoll Init Promise Resolved After Awaiting Create\");\n }\n // Send out socket calls to all users to see the roll.\n rollInst.constructRollCollab_SocketCall(rollInst.linkData);\n return rollInst;\n }\n async initTargetLink() {\n this.initialSchema.rollModsData = this.rollModsDataSet;\n super.initTargetLink();\n }\n get rollModsSchemaSets() {\n const compiledModSchemaSets = [];\n // Add roll mods on rollPrimary\n if (this.rollPrimary) {\n compiledModSchemaSets.push(...this.rollPrimary.rollPrimaryModsSchemaSet\n .filter((pSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== pSchema.key)));\n }\n // Add roll mods on rollOpposition\n if (this.rollOpposition?.rollOppModsSchemaSet) {\n compiledModSchemaSets.push(...this.rollOpposition.rollOppModsSchemaSet\n .filter((oSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== oSchema.key)));\n }\n // Add default roll mods\n compiledModSchemaSets.push(...this.constructor.DefaultRollModSchemaSet\n .filter((dSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== dSchema.key)));\n // If this is a downtime action roll, add default downtime action roll mods\n if (this.rollDowntimeAction) {\n compiledModSchemaSets.push({\n key: \"HelpFromFriend-positive-roll\",\n name: \"Help From a Friend\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

\"\n });\n if (this.rollDowntimeAction !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.IndulgeVice) {\n compiledModSchemaSets.push({\n key: \"CanBuyResultLevel-positive-after\",\n name: \"Buying Result Level\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.after,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 0,\n effectKeys: [],\n tooltip: \"

Buying Result Level

After your roll, you can increase the result level by one for each Coin you spend.

\"\n });\n }\n if (this.rollDowntimeAction === _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.AcquireAsset) {\n compiledModSchemaSets.push({\n key: \"RepeatPurchase-positive-roll\",\n name: \"Repeat Purchase\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Repeat Purchase Bonus

Add +1d if you have previously acquired this asset or service with a Acquire Asset Downtime activity.

\"\n }, {\n key: \"RestrictedItem-negative-after\",\n name: \"Restricted\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.after,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 0,\n effectKeys: [\"Cost-Heat2\"],\n tooltip: \"

Restricted

Whether contraband goods or dangerous materials, this Acquire Asset Downtime activity will add +2 Heat to your crew.

\"\n });\n }\n }\n return compiledModSchemaSets;\n }\n get rollModsDataSet() {\n const { linkData } = this;\n const modLinkConfig = {\n targetID: linkData.targetID,\n isScopingById: true,\n ...(\"targetKey\" in linkData\n ? { targetKey: `${this.targetKeyPrefix}.rollModsData` }\n : {}),\n ...(\"targetFlagKey\" in linkData\n ? { targetFlagKey: `${this.targetFlagKeyPrefix}.rollModsData` }\n : {})\n };\n return Object.fromEntries(this.rollModsSchemaSets\n .map((modSchema) => {\n const modData = _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"].ParseConfigToData({\n ...BladesRollMod.ApplySchemaDefaults(modSchema),\n ...modLinkConfig\n });\n return [modData.id, modData];\n }));\n }\n // #endregion\n // #region SOCKET CALLS & RESPONSES ~\n static GetRollSubClass(linkData) {\n const targetLink = new _BladesTargetLink__WEBPACK_IMPORTED_MODULE_8__[\"default\"](linkData);\n switch (targetLink.data.rollType) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action: return BladesActionRoll;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Fortune: {\n if (targetLink.data.rollSubType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollSubType.Engagement) {\n return BladesEngagementRoll;\n }\n else if (targetLink.data.rollSubType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollSubType.Incarceration) {\n return BladesIncarcerationRoll;\n }\n return BladesFortuneRoll;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance: {\n if (targetLink.data.isInlineResistanceRoll) {\n return BladesInlineResistanceRoll;\n }\n return BladesResistanceRoll;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.IndulgeVice: return BladesIndulgeViceRoll;\n }\n }\n constructRollCollab_SocketCall(linkData) {\n socketlib.system.executeForEveryone(\"constructRollCollab_SocketCall\", linkData);\n }\n static constructRollCollab_SocketResponse(linkData) {\n const rollInst = new (this.GetRollSubClass(linkData))(linkData);\n eLog.checkLog3(\"rollCollab\", \"constructRollCollab_SocketResponse()\", { params: { linkData }, rollInst });\n this.renderRollCollab_SocketResponse(rollInst.id);\n }\n renderRollCollab_SocketCall() {\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n static renderRollCollab_SocketResponse(id) {\n const rollInst = game.eunoblades.Rolls.get(id);\n if (!rollInst) {\n throw new Error(`[BladesRoll.renderRollCollab_SocketResponse] No roll found with id ${id}.`);\n }\n rollInst.renderRollCollab();\n }\n closeRollCollab_Animation() {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.blurRemove(this.elem$, { ignoreMargins: true });\n }\n async closeRollCollab_SocketCall() {\n if (!game.user.isGM) {\n return;\n }\n socketlib.system.executeForOthers(\"closeRollCollab_SocketCall\", this.id);\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor(this.closeRollCollab_Animation());\n }\n static closeRollCollab_SocketResponse(id) {\n game.eunoblades.Rolls.get(id)?.closeRollCollab_Animation();\n }\n // #endregion\n // #region *** CONSTRUCTOR *** ~\n rollPermission;\n _rollPrimary;\n _rollOpposition;\n _rollParticipants;\n projectSelectOptions;\n constructor(dataOrConfig) {\n super(dataOrConfig);\n this.rollPermission = this.data.userPermissions[game.user.id];\n this._rollPrimary = new BladesRollPrimary(this, this.data.rollPrimaryData);\n if (this.data.rollOppData) {\n this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData);\n }\n else if (this.data.rollDowntimeAction === _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.LongTermProject) {\n this.projectSelectOptions = Array.from(game.items)\n .filter((item) => _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.project))\n .map((project) => ({ value: project.id ?? \"\", display: project.name }));\n }\n if (this.data.rollParticipantData) {\n this._rollParticipants = {};\n for (const [rollSection, rollParticipantList] of Object.entries(this.data.rollParticipantData)) {\n if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect]\n .includes(rollSection) && !_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isEmpty(rollParticipantList)) {\n const sectionParticipants = {};\n for (const [participantType, participantData] of Object.entries(rollParticipantList)) {\n sectionParticipants[participantType] = new BladesRollParticipant(this, rollSection, participantType, participantData);\n }\n this._rollParticipants[rollSection] = sectionParticipants;\n }\n }\n }\n game.eunoblades.Rolls.set(this.id, this);\n }\n // #endregion\n // #region Roll Participation & User Permissions\n async addRollParticipant(participantRef, rollSection, rollSubSection) {\n if (!rollSubSection) {\n /* Insert logic to determine from rollSection and number of existing Group_X members */\n rollSubSection = \"Assist\";\n }\n const participantData = typeof participantRef === \"string\"\n ? game.actors.get(participantRef)\n ?? game.actors.getName(participantRef)\n ?? game.items.get(participantRef)\n ?? game.items.getName(participantRef)\n : participantRef;\n if (!BladesRollParticipant.IsValidData(participantData)) {\n throw new Error(\"Bad data.\");\n }\n const rollParticipant = new BladesRollParticipant(this, rollSection, rollSubSection, participantData);\n await rollParticipant.updateRollFlags();\n if (this.isRendered) {\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n }\n async removeRollParticipant(rollSection, rollSubSection) {\n await this.updateTarget(`rollParticipantData.${rollSection}.${rollSubSection}`, null);\n }\n async updateUserPermission(_user, _permission) {\n /* Force-render roll with new permissions */\n }\n // #endregion\n // #region Basic User Flag Getters/Setters ~\n // get data(): BladesRoll.FlagData {\n // if (!this.document.getFlag(C.SYSTEM_ID, \"rollCollab\")) {\n // throw new Error(\"[get flags()] No RollCollab Flags Found on User Document\");\n // }\n // return this.document.getFlag(C.SYSTEM_ID, \"rollCollab\") as BladesRoll.FlagData;\n // }\n get rollPrimary() {\n return this._rollPrimary;\n }\n get rollPrimaryDoc() {\n return this.rollPrimary.rollPrimaryDoc;\n }\n get rollOpposition() {\n if (!this._rollOpposition && BladesRollOpposition.IsValidData(this.data.rollOppData)) {\n this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData);\n }\n return this._rollOpposition?.refresh();\n }\n set rollOpposition(val) {\n if (val === undefined) {\n this._rollOpposition = undefined;\n }\n else {\n this._rollOpposition = val;\n val.updateRollFlags();\n }\n }\n get rollClockKey() {\n return this.data.rollClockKey\n ? game.eunoblades.ClockKeys.get(this.data.rollClockKey)\n : undefined;\n }\n set rollClockKey(val) {\n this.updateTarget(\"rollClockKeyID\", val ?? null);\n }\n /**\n * This method prepares the roll participant data.\n * It iterates over the roll sections (roll, position, effect) and for each section,\n * it creates a new BladesRollParticipant instance for each participant in that section.\n * The created instances are stored in the rollParticipants object.\n */\n prepareRollParticipantData() {\n const participantFlagData = this.data.rollParticipantData;\n if (!participantFlagData) {\n return;\n }\n const rollParticipants = {};\n [\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect\n ].forEach((rollSection) => {\n const sectionFlagData = participantFlagData[rollSection];\n if (sectionFlagData) {\n const sectionParticipants = {};\n Object.entries(sectionFlagData).forEach(([subSection, subSectionFlagData]) => {\n if (subSectionFlagData) {\n sectionParticipants[subSection] =\n new BladesRollParticipant(this, rollSection, subSection, subSectionFlagData);\n }\n });\n rollParticipants[rollSection] = sectionParticipants;\n }\n });\n this._rollParticipants = rollParticipants;\n }\n get rollParticipants() {\n return this._rollParticipants;\n }\n getRollParticipant(section, subSection) {\n if (isParticipantSection(section) && isParticipantSubSection(subSection)) {\n const sectionData = this.rollParticipants?.[section];\n if (sectionData) {\n return sectionData[subSection] ?? null;\n }\n }\n return null;\n }\n get rollParticipantSelectOptions() {\n const nonPrimaryPCs = _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.All\n .filter((actor) => actor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.PC.ActivePC) && actor.id !== this.rollPrimary.rollPrimaryID)\n .map((actor) => ({ value: actor.id, display: actor.name }));\n return {\n Assist: nonPrimaryPCs,\n Setup: nonPrimaryPCs,\n Group: nonPrimaryPCs\n };\n }\n get rollType() { return this.data.rollType; }\n get rollSubType() { return this.data.rollSubType; }\n set rollSubType(val) {\n this.updateTarget(\"rollSubType\", val ?? null);\n }\n get rollPhase() {\n return this.data.rollPhase ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.Collaboration;\n }\n get rollDowntimeAction() { return this.data.rollDowntimeAction; }\n get rollTrait() { return this.data.rollTrait; }\n get rollTraitVerb() {\n if (!this.rollTrait) {\n return undefined;\n }\n if (!(this.rollTrait in _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ActionVerbs)) {\n return undefined;\n }\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ActionVerbs[this.rollTrait];\n }\n get rollTraitPastVerb() {\n if (!this.rollTrait) {\n return undefined;\n }\n if (!(this.rollTrait in _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ActionPastVerbs)) {\n return undefined;\n }\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ActionPastVerbs[this.rollTrait];\n }\n _rollTraitValOverride;\n get rollTraitValOverride() { return this._rollTraitValOverride; }\n set rollTraitValOverride(val) { this._rollTraitValOverride = val; }\n get rollTraitData() {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this.rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n if (isAction(this.rollTrait)) {\n return {\n name: this.rollTrait,\n value: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait],\n max: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait],\n pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipActions,\n gmTooltip: _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].ActionTooltipsGM[this.rollTrait]\n };\n }\n if (isAttribute(this.rollTrait)) {\n return {\n name: this.rollTrait,\n value: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait],\n max: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait],\n pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipAttributes,\n gmTooltip: _core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].AttributeTooltips[this.rollTrait]\n };\n }\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(this.rollTrait)) {\n return {\n name: `+${this.rollTraitValOverride ?? this.rollTrait}`,\n value: this.rollTraitValOverride ?? this.rollTrait,\n max: this.rollTraitValOverride ?? this.rollTrait\n };\n }\n if (isFactor(this.rollTrait)) {\n return {\n name: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(this.rollTrait),\n value: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.value ?? 0,\n max: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.max ?? 10\n };\n }\n throw new Error(`[get rollTraitData] Invalid rollTrait: '${this.rollTrait}'`);\n }\n get rollTraitOptions() {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this.rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)) {\n if (isAction(this.rollTrait)) {\n return Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait)\n .map((action) => ({\n name: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].uCase(action),\n value: action\n }));\n }\n if (isAttribute(this.rollTrait)) {\n return Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.AttributeTrait)\n .map((attribute) => ({\n name: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].uCase(attribute),\n value: attribute\n }));\n }\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(this.rollTrait)) {\n return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]\n .map((num) => ({\n name: `+${num}`,\n value: num\n }));\n }\n if (isFactor(this.rollTrait)) {\n return [];\n }\n throw new Error(`[get rollTraitOptions] Invalid rollTrait: '${this.rollTrait}'`);\n }\n get posEffectTrade() {\n return this.data?.rollPosEffectTrade ?? false;\n }\n // getFlagVal(flagKey?: string): T | undefined {\n // if (flagKey) {\n // return this.document.getFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\\.)+/g, \"rollCollab.\")) as T | undefined;\n // }\n // return this.document.getFlag(C.SYSTEM_ID, \"rollCollab\") as T | undefined;\n // }\n // async setFlagVal(flagKey: string, flagVal: unknown, isRerendering = true) {\n // await this.document.setFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\\.)+/g, \"rollCollab.\"), flagVal);\n // if (isRerendering) {\n // socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n // }\n // }\n // async clearFlagVal(flagKey: string, isRerendering = true) {\n // await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\\.)+/g, \"rollCollab.\"));\n // if (isRerendering) {\n // socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n // }\n // }\n get initialPosition() {\n return this.data.rollPositionInitial ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.risky;\n }\n set initialPosition(val) {\n this.updateTarget(\"rollPositionInitial\", val ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.risky);\n }\n get initialEffect() {\n return this.data.rollEffectInitial ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect.standard;\n }\n set initialEffect(val) {\n this.updateTarget(\"rollEffectInitial\", val ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect.standard);\n }\n get isApplyingConsequences() {\n if (this.rollType !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action) {\n return false;\n }\n if (!this.rollResult) {\n return false;\n }\n if (![_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail].includes(this.rollResult)) {\n return false;\n }\n return true;\n }\n // Get rollConsequence() --> For resistance rolls.\n get rollConsequence() {\n const { consequence } = this.data.resistanceData ?? {};\n if (!consequence?.id) {\n return undefined;\n }\n return game.eunoblades.Consequences.get(consequence.id)\n ?? new _BladesConsequence__WEBPACK_IMPORTED_MODULE_5__[\"default\"](consequence);\n }\n // #endregion\n // #region GETTERS: DERIVED DATA ~\n get rollPositionFinal() {\n return Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position)[_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].clampNum(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position).indexOf(this.initialPosition)\n + this.getModsDelta(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position)\n + (this.posEffectTrade === \"position\" ? 1 : 0)\n + (this.posEffectTrade === \"effect\" ? -1 : 0), [0, 2])];\n }\n get rollEffectFinal() {\n return Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect)[_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].clampNum(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect).indexOf(this.initialEffect)\n + this.getModsDelta(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect)\n + (this.posEffectTrade === \"effect\" ? 1 : 0)\n + (this.posEffectTrade === \"position\" ? -1 : 0), [0, 4])];\n }\n get rollResultDelta() {\n return this.getModsDelta(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.result)\n + (this.data?.GMBoosts.Result ?? 0)\n + (this.tempGMBoosts.Result ?? 0);\n }\n get rollResultFinal() {\n if (this.rollResult === false) {\n return false;\n }\n if (this.rollResultDelta === 0) {\n return this.rollResult;\n }\n switch (this.rollType) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action:\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Fortune: {\n return Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult).toReversed()[_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].clampNum(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult).toReversed().indexOf(this.rollResult)\n + this.rollResultDelta, [0, 3])];\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance: { // Return stress cost of resisting\n if (this.isCritical) {\n return -1;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].clampNum(6 - this.highestDieVal - this.rollResultDelta, [-1, Infinity]);\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.IndulgeVice: { // Return stress cleared from indulging\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].clampNum(this.highestDieVal + this.rollResultDelta, [0, Infinity]);\n }\n }\n return false;\n }\n get finalDicePool() {\n return Math.max(0, this.rollTraitData.value\n + this.getModsDelta(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll)\n + (this.data.GMBoosts.Dice ?? 0)\n + (this.tempGMBoosts.Dice ?? 0));\n }\n get isRollingZero() {\n return Math.max(0, this.rollTraitData.value\n + this.getModsDelta(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll)\n + (this.data.GMBoosts.Dice ?? 0)\n + (this.tempGMBoosts.Dice ?? 0)) <= 0;\n }\n _roll;\n get roll() {\n this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {});\n return this._roll;\n }\n get rollFactors() {\n const defaultFactors = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: {\n name: \"Tier\",\n value: 0,\n max: 0,\n baseVal: 0,\n display: \"?\",\n isActive: false,\n isPrimary: true,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: \"factor-gold\"\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: {\n name: \"Quality\",\n value: 0,\n max: 0,\n baseVal: 0,\n display: \"?\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: \"factor-gold\"\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: {\n name: \"Scale\",\n value: 0,\n max: 0,\n baseVal: 0,\n display: \"?\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: \"factor-gold\"\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: {\n name: \"Magnitude\",\n value: 0,\n max: 0,\n baseVal: 0,\n display: \"?\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: \"factor-gold\"\n }\n };\n const mergedSourceFactors = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMerge(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.source, { isMutatingOk: false });\n const mergedOppFactors = this.rollOpposition\n ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMerge(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMerge(defaultFactors, this.rollOpposition.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.opposition, { isMutatingOk: false })\n : {};\n return {\n source: Object.fromEntries(Object.entries(mergedSourceFactors)\n .map(([factor, factorData]) => {\n factorData.value +=\n (this.data.GMBoosts[factor] ?? 0)\n + (this.tempGMBoosts[factor] ?? 0);\n if (factor === _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier) {\n factorData.display = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(factorData.value);\n }\n else {\n factorData.display = `${factorData.value}`;\n }\n return [factor, factorData];\n })),\n opposition: Object.fromEntries(Object.entries(mergedOppFactors)\n .map(([factor, factorData]) => {\n factorData.value += this.data.GMOppBoosts[factor] ?? 0;\n if (factor === _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier) {\n factorData.display = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(factorData.value);\n }\n else {\n factorData.display = `${factorData.value}`;\n }\n return [factor, factorData];\n }))\n };\n }\n // #endregion\n // #region ROLL MODS: Getters & Update Method ~\n initRollMods() {\n // Reset override values previously enabled by rollmods\n this.rollTraitValOverride = undefined;\n this.rollFactorPenaltiesNegated = {};\n this.tempGMBoosts = {};\n // ESLINT DISABLE: Dev Code.\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const initReport = {};\n let initReportCount = 0;\n const watchMod = (label) => {\n if (BladesRoll.Debug.modWatch === false) {\n return;\n }\n const reportLabel = `(${initReportCount}) == ${label}`;\n const rollMod = this.rollMods\n .find((mod) => BladesRoll.Debug.modWatch && BladesRoll.Debug.modWatch.exec(mod.name));\n if (rollMod) {\n initReport[`${reportLabel} : ${rollMod.status}`] = {\n inst: rollMod,\n data: { ...rollMod.data },\n sourceName: rollMod.sourceName,\n status: {\n ALL: rollMod.status,\n base: rollMod.baseStatus,\n held: rollMod.heldStatus,\n user: rollMod.userStatus\n },\n is: {\n active: rollMod.isActive,\n visible: rollMod.isVisible,\n conditional: rollMod.isConditional,\n inInactiveBlock: rollMod.isInInactiveBlock,\n isPush: rollMod.isPush,\n isBasicPush: rollMod.isBasicPush\n }\n };\n }\n else {\n initReport[reportLabel] = \"MOD NOT FOUND\";\n }\n initReportCount++;\n };\n watchMod(\"INITIAL\");\n /* *** PASS ZERO: ROLLTYPE VALIDATION PASS *** */\n this._rollMods = this.rollMods.filter((rollMod) => rollMod.isValidForRollType());\n watchMod(\"ROLLTYPE VALIDATION\");\n /* *** PASS ONE: DISABLE PASS *** */\n // ... Conditional Status Pass\n const conditionalDisablePass = this.rollMods.filter((rollMod) => !rollMod.setConditionalStatus());\n watchMod(\"DISABLE - CONDITIONAL\");\n // ... AutoReveal/AutoEnable Pass\n const autoRevealDisablePass = conditionalDisablePass.filter((rollMod) => !rollMod.setAutoStatus());\n watchMod(\"DISABLE - AUTO-REVEAL/ENABLE\");\n // ... Payable Pass\n autoRevealDisablePass.forEach((rollMod) => { rollMod.setPayableStatus(); });\n watchMod(\"DISABLE - PAYABLE\");\n /* *** PASS TWO: FORCE-ON PASS *** */\n const parseForceOnKeys = (mod) => {\n const holdKeys = mod.effectKeys.filter((key) => key.startsWith(\"ForceOn\"));\n if (holdKeys.length === 0) {\n return;\n }\n while (holdKeys.length) {\n const thisTarget = holdKeys.pop()?.split(/-/)?.pop();\n if (thisTarget === \"BestAction\") {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.rollPrimaryDoc)) {\n this.rollTraitValOverride = Math.max(...Object.values(this.rollPrimaryDoc.actions));\n }\n }\n else {\n const [targetName, targetCat, targetPosNeg] = thisTarget?.split(/,/) ?? [];\n if (!targetName) {\n throw new Error(`No targetName found in thisTarget: ${thisTarget}.`);\n }\n let targetMod = this.getRollModByName(targetName)\n ?? this.getRollModByName(targetName, targetCat ?? mod.section);\n if (!targetMod && targetName === \"Push\") {\n [targetMod] = [\n ...this.getActiveBasicPushMods(targetCat ?? mod.section, \"negative\").filter((m) => m.status === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn),\n ...this.getActiveBasicPushMods(targetCat ?? mod.section, \"positive\").filter((m) => m.status === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn),\n ...this.getInactiveBasicPushMods(targetCat ?? mod.section, \"positive\").filter((m) => m.status === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff)\n ];\n }\n targetMod ??= this.getRollModByName(targetName, targetCat ?? mod.section, targetPosNeg ?? mod.posNeg);\n if (!targetMod) {\n throw new Error(`No mod found matching ${targetName}/${targetCat}/${targetPosNeg}`);\n }\n if (!targetMod.isActive) {\n targetMod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn;\n parseForceOnKeys(targetMod);\n }\n else {\n targetMod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn;\n }\n }\n }\n };\n this.getActiveRollMods().forEach((rollMod) => parseForceOnKeys(rollMod));\n watchMod(\"FORCE-ON PASS\");\n /* *** PASS THREE: PUSH-CHECK PASS *** */\n // IF ROLL FORCED ...\n if (this.isForcePushed()) {\n // ... Force Off _ALL_ visible, inactive \"Is-Push\" mods.\n this.getInactivePushMods()\n .filter((mod) => !mod.isBasicPush)\n .forEach((mod) => { mod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff; });\n watchMod(\"PUSH-CHECK: FORCE-OFF IS-PUSH\");\n }\n // ... BY CATEGORY ...\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect].forEach((cat) => {\n if (this.isPushed(cat)) {\n // ... if pushed by positive mod, Force Off any visible Bargain\n if (cat === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll && this.isPushed(cat, \"positive\")) {\n const bargainMod = this.getRollModByKey(\"Bargain-positive-roll\");\n if (bargainMod?.isVisible) {\n bargainMod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff;\n }\n }\n watchMod(\"PUSH-CHECK: FORCE OFF BARGAIN\");\n }\n else {\n // Otherwise, hide all Is-Push mods\n this.getInactivePushMods(cat)\n .filter((mod) => !mod.isBasicPush)\n .forEach((mod) => { mod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden; });\n watchMod(\"PUSH-CHECK: HIDE IS-PUSH\");\n }\n });\n /* *** PASS FOUR: Relevancy Pass *** */\n this.getVisibleRollMods()\n .forEach((mod) => { mod.setRelevancyStatus(); });\n watchMod(\"RELEVANCY PASS\");\n /* *** PASS FIVE: Overpayment Pass *** */\n // ... If 'Cost-SpecialArmor' active, ForceOff other visible Cost-SpecialArmor mods\n const activeArmorCostMod = this.getActiveRollMods().find((mod) => mod.effectKeys.includes(\"Cost-SpecialArmor\"));\n if (activeArmorCostMod) {\n this.getVisibleRollMods()\n .filter((mod) => !mod.isActive && mod.effectKeys.includes(\"Cost-SpecialArmor\"))\n .forEach((mod) => { mod.heldStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff; });\n watchMod(\"OVERPAYMENT PASS\");\n }\n eLog.checkLog2(\"rollMods\", \"*** initRollMods() PASS ***\", initReport);\n }\n isTraitRelevant(trait) {\n if (trait in _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor) {\n const { source, opposition } = this.rollFactors;\n return Boolean(trait in source && trait in opposition && source[trait]?.isActive);\n }\n return false;\n }\n get isParticipantRoll() {\n return (this.rollType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Fortune && !game.user.isGM)\n || (this.rollSubType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollSubType.GroupParticipant);\n }\n negatePushCost() {\n const costlyPushMod = this.getActiveRollMods()\n .find((mod) => mod.isPush && mod.stressCost > 0);\n if (costlyPushMod) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pullElement(costlyPushMod.effectKeys, (k) => k.startsWith(\"Cost-Stress\"));\n }\n }\n rollFactorPenaltiesNegated = {};\n negateFactorPenalty(factor) {\n this.rollFactorPenaltiesNegated[factor] = true;\n }\n tempGMBoosts = {};\n isPushed(cat, posNeg) { return this.getActiveBasicPushMods(cat, posNeg).length > 0; }\n hasOpenPush(cat, posNeg) { return this.isPushed(cat) && this.getOpenPushMods(cat, posNeg).length > 0; }\n isForcePushed(cat, posNeg) { return this.isPushed(cat) && this.getForcedPushMods(cat, posNeg).length > 0; }\n get rollCosts() {\n if (!this.isPushed) {\n return 0;\n }\n const harmPush = this.getRollModByKey(\"Push-negative-roll\");\n const rollPush = this.getRollModByKey(\"Push-positive-roll\");\n const effectPush = this.getRollModByKey(\"Push-positive-effect\");\n const negatePushCostMods = this.getActiveRollMods(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.after, \"positive\")\n .filter((mod) => mod.effectKeys.includes(\"Negate-PushCost\"));\n return ((harmPush?.isActive && harmPush?.stressCost) || 0)\n + ((rollPush?.isActive && rollPush?.stressCost) || 0)\n + ((effectPush?.isActive && effectPush?.stressCost) || 0)\n - (negatePushCostMods.length * 2);\n }\n get rollCostData() {\n return this.getActiveRollMods()\n .map((rollMod) => rollMod.costs ?? [])\n .flat();\n }\n getRollModByID(id) { return this.rollMods.find((rollMod) => rollMod.id === id); }\n getRollModByName(name, cat, posNeg) {\n const modMatches = this.rollMods.filter((rollMod) => {\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(rollMod.name) !== _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(name)) {\n return false;\n }\n if (cat && rollMod.section !== cat) {\n return false;\n }\n if (posNeg && rollMod.posNeg !== posNeg) {\n return false;\n }\n return true;\n });\n if (modMatches.length === 0) {\n return undefined;\n }\n if (modMatches.length > 1) {\n return undefined;\n }\n return modMatches[0];\n }\n getRollModByKey(key) { return this.rollMods.find((rollMod) => rollMod.data.key === key); }\n getRollMods(cat, posNeg) {\n return this.rollMods.filter((rollMod) => (!cat || rollMod.section === cat)\n && (!posNeg || rollMod.posNeg === posNeg));\n }\n getVisibleRollMods(cat, posNeg) {\n return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isVisible);\n }\n getActiveRollMods(cat, posNeg) {\n return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isActive);\n }\n getVisibleInactiveRollMods(cat, posNeg) {\n return this.getVisibleRollMods(cat, posNeg).filter((rollMod) => !rollMod.isActive);\n }\n getPushMods(cat, posNeg) {\n return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isPush);\n }\n getVisiblePushMods(cat, posNeg) {\n return this.getPushMods(cat, posNeg).filter((rollMod) => rollMod.isVisible);\n }\n getActivePushMods(cat, posNeg) {\n return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => rollMod.isActive);\n }\n getActiveBasicPushMods(cat, posNeg) {\n return this.getActivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush);\n }\n getInactivePushMods(cat, posNeg) {\n return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => !rollMod.isActive);\n }\n getInactiveBasicPushMods(cat, posNeg) {\n return this.getInactivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush);\n }\n getForcedPushMods(cat, posNeg) {\n return this.getActivePushMods(cat, posNeg)\n .filter((rollMod) => rollMod.isBasicPush\n && rollMod.status === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn);\n }\n getOpenPushMods(cat, posNeg) {\n return this.getActivePushMods(cat, posNeg)\n .filter((rollMod) => rollMod.isBasicPush\n && rollMod.status === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn);\n }\n getModsDelta = (cat) => {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sum([\n ...this.getActiveRollMods(cat, \"positive\").map((mod) => mod.value),\n ...this.getActiveRollMods(cat, \"negative\").map((mod) => -mod.value)\n ]);\n };\n _rollMods;\n /**\n * Compare function for sorting roll mods.\n * @param {BladesRollMod} modA First mod to compare.\n * @param {BladesRollMod} modB Second mod to compare.\n * @returns {number} - Comparison result.\n */\n compareMods(modA, modB) {\n // Define the order of mod names for sorting\n const modOrder = [\"Bargain\", \"Assist\", \"Setup\"];\n // Check for basic push\n if (modA.isBasicPush) {\n return -1;\n }\n if (modB.isBasicPush) {\n return 1;\n }\n // Check for active Bargain\n if (modA.name === \"Bargain\" && modA.isActive) {\n return -1;\n }\n if (modB.name === \"Bargain\" && modB.isActive) {\n return 1;\n }\n // Check for push\n if (modA.isPush) {\n return -1;\n }\n if (modB.isPush) {\n return 1;\n }\n // Check for mod name order\n const modAIndex = modOrder.indexOf(modA.name);\n const modBIndex = modOrder.indexOf(modB.name);\n if (modAIndex !== -1 && modBIndex !== -1) {\n return modAIndex - modBIndex;\n }\n // Default to alphabetical order\n return modA.name.localeCompare(modB.name);\n }\n get rollMods() {\n if (!this._rollMods) {\n this._rollMods = Object.values(this.data.rollModsData).map((modData) => new BladesRollMod(modData, this));\n }\n return [...this._rollMods].sort((modA, modB) => this.compareMods(modA, modB));\n }\n // #endregion\n // #region CONSEQUENCES: Getting, Accepting, Resisting\n get consequences() {\n const csqDataSet = this.data.consequenceData?.[this.rollPositionFinal]?.[this.rollResult];\n if (csqDataSet) {\n return Object.values(csqDataSet).map((csqData) => new _BladesConsequence__WEBPACK_IMPORTED_MODULE_5__[\"default\"](csqData));\n }\n return [];\n }\n getConsequenceByID(csqID) {\n return this.consequences.find((csq) => csq.id === csqID) ?? false;\n }\n get acceptedConsequences() {\n if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.AwaitingConsequences, _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.Complete].includes(this.rollPhase)) {\n return this.consequences.filter((csq) => csq.isAccepted === true);\n }\n return [];\n }\n get unacceptedConsequences() {\n if (this.rollPhase === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.AwaitingConsequences) {\n return this.consequences.filter((csq) => csq.isAccepted !== true);\n }\n return [];\n }\n // #endregion\n // #region *** ROLL COLLAB HTML INTERACTION *** ~\n /**\n * Retrieve the data for rendering the base RollCollab sheet.\n * @returns {Promise} The data which can be used to render the HTML of the sheet.\n */\n get context() {\n this.initRollMods();\n this.rollMods.forEach((rollMod) => rollMod.applyRollModEffectKeys());\n return this.getTemplateContext();\n }\n /**\n * Determines if the user is a game master.\n * @returns {boolean} Whether the user is a GM.\n */\n getIsGM() {\n return game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM;\n }\n /**\n * Gets the roll costs.\n * @returns {BladesRoll.CostData[]} The roll costs.\n */\n getRollCosts() {\n return this.getActiveRollMods()\n .map((rollMod) => rollMod.costs)\n .flat()\n .filter((costData) => costData !== undefined);\n }\n /**\n * Constructs the sheet data.\n * @param {boolean} isGM If the user is a GM.\n * @param {BladesRoll.CostData[]} rollCosts The roll costs.\n * @returns {BladesRoll.Context} The constructed sheet data.\n */\n getTemplateContext() {\n const { data: rData, rollPrimary, rollTraitData, rollTraitOptions, rollClockKey, finalDicePool, rollPositionFinal, rollEffectFinal, rollResultDelta, rollResultFinal, rollMods, rollFactors } = this;\n if (!rollPrimary) {\n throw new Error(\"A primary roll source is required for BladesRoll.\");\n }\n const baseData = {\n ...this.data,\n cssClass: \"roll-collab\",\n isGM: this.isGM,\n system: this.rollPrimaryDoc?.system,\n rollMods,\n rollPrimary,\n rollTraitData,\n rollTraitOptions,\n diceTotal: finalDicePool,\n rollOpposition: this.rollOpposition,\n rollParticipants: this.rollParticipants,\n rollParticipantOptions: this.rollParticipantSelectOptions,\n rollEffects: Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect),\n rollTraitValOverride: this.rollTraitValOverride,\n rollFactorPenaltiesNegated: this.rollFactorPenaltiesNegated,\n posRollMods: Object.fromEntries(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection)\n .map((cat) => [cat, this.getRollMods(cat, \"positive\")])),\n negRollMods: Object.fromEntries(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection)\n .map((cat) => [cat, this.getRollMods(cat, \"negative\")])),\n hasInactiveConditionals: this.calculateHasInactiveConditionalsData(),\n rollFactors,\n ...this.calculateOddsHTML(finalDicePool, rollResultDelta)\n };\n const GMBoostsData = this.calculateGMBoostsData(rData);\n const positionEffectTradeData = this.calculatePositionEffectTradeData();\n const stressCostDataSet = this.getRollCosts()\n .filter((costData) => costData.costType === \"Stress\")\n .map((costData) => [costData.label, costData.costAmount]);\n const availableArmor = [];\n if (this.rollPrimaryDoc instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC) {\n availableArmor.push(...this.rollPrimaryDoc.availableArmor);\n }\n else if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.IsType(this.rollPrimaryDoc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert)) {\n // Gang or Expert Cohort\n for (let index = 0; index < this.rollPrimaryDoc.system.armor.value; index++) {\n availableArmor.push(\"Armor\");\n }\n }\n const armorCostDataSet = this.getRollCosts()\n .filter((costData) => costData.costType === \"Armor\")\n .map((costData, index) => [costData.label, availableArmor[index]])\n .filter(([_label, armorType]) => armorType !== undefined);\n const specialArmorCostDataSet = this.getRollCosts()\n .filter((costData) => costData.costType === \"SpecialArmor\")\n .map((costData) => costData.label);\n const userPermission = baseData.userPermissions[game.user.id] ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Observer;\n // const downtimeData = this.processDowntimeActions();\n return {\n ...baseData,\n rollPrimary: this.rollPrimary,\n rollPositionFinal,\n rollEffectFinal,\n rollResultFinal,\n rollPositions: Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Position),\n rollEffects: Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect),\n rollResultDelta,\n isAffectingResult: rollResultDelta !== 0\n || this.getVisibleRollMods(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.result).length > 0\n || (this.isGM && this.getRollMods(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.result).length > 0),\n isAffectingAfter: this.getVisibleRollMods(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.after).length > 0\n || (this.isGM && this.getRollMods(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.after).length > 0),\n ...GMBoostsData,\n ...positionEffectTradeData,\n rollClockKey: this.rollClockKey,\n totalStressCost: stressCostDataSet.reduce((acc, [_label, amount]) => acc + amount, 0),\n totalArmorCost: armorCostDataSet.length,\n stressCosts: stressCostDataSet.length > 0\n ? Object.fromEntries(stressCostDataSet)\n : undefined,\n armorCosts: armorCostDataSet.length > 0\n ? Object.fromEntries(armorCostDataSet)\n : undefined,\n specArmorCost: specialArmorCostDataSet[0],\n userPermission,\n editable: userPermission === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.Primary || userPermission === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPermissions.GM,\n gamePhase: game.eunoblades.Tracker.phase\n };\n }\n // type BladesSelectOption = {\n // value: valueType,\n // display: displayType\n // };\n // protected processDowntimeActions() {\n // const downtimeData: Record;\n // if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) {\n // downtimeData.canDoDowntimeActions = true;\n // downtimeData.downtimeActionsRemaining = this.rollPrimaryDoc.remainingDowntimeActions;\n // const availableDowntimeActions: DowntimeAction[] = [];\n // if (this.rollType === RollType.Action) {\n // availableDowntimeActions.push(...[\n // DowntimeAction.AcquireAsset,\n // DowntimeAction.LongTermProject,\n // DowntimeAction.Recover,\n // DowntimeAction.ReduceHeat\n // ]);\n // } else if (this.rollType === RollType.Fortune) {\n // availableDowntimeActions.push(...[\n // DowntimeAction.\n // ])\n // }\n // downtimeData.downtimeActionOptions =\n // downtimeActionOptions?: Array\n // }\n calculateGMBoostsData(data) {\n return {\n GMBoosts: {\n Dice: data.GMBoosts.Dice ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: data.GMBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: data.GMBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: data.GMBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: data.GMBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude] ?? 0,\n Result: data.GMBoosts.Result ?? 0\n },\n GMOppBoosts: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: data.GMOppBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: data.GMOppBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: data.GMOppBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale] ?? 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: data.GMOppBoosts[_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude] ?? 0\n }\n };\n }\n calculateOddsHTML(diceTotal, rollResultDelta) {\n if (this.rollType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Resistance) {\n return this.calculateOddsHTML_Resistance(diceTotal);\n }\n return this.calculateOddsHTML_Standard(diceTotal, rollResultDelta);\n }\n /**\n * Calculate odds starting & ending HTML based on given dice total.\n * @param {number} diceTotal Total number of dice.\n * @param {number} rollResultDelta\n * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display\n */\n calculateOddsHTML_Standard(diceTotal, rollResultDelta) {\n const oddsColors = {\n crit: \"var(--blades-gold)\",\n success: \"var(--blades-white-bright)\",\n partial: \"var(--blades-grey)\",\n fail: \"var(--blades-black-dark)\"\n };\n const odds = { ..._core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].DiceOddsStandard[diceTotal] };\n if (rollResultDelta < 0) {\n for (let i = rollResultDelta; i < 0; i++) {\n oddsColors.crit = oddsColors.success;\n oddsColors.success = oddsColors.partial;\n oddsColors.partial = oddsColors.fail;\n }\n }\n else if (rollResultDelta > 0) {\n for (let i = 0; i < rollResultDelta; i++) {\n oddsColors.fail = oddsColors.partial;\n oddsColors.partial = oddsColors.success;\n oddsColors.success = oddsColors.crit;\n }\n }\n const resultElements = [];\n Object.entries(odds).reverse().forEach(([result, chance]) => {\n if (chance === 0) {\n return;\n }\n resultElements.push(`
 
`);\n });\n return {\n oddsHTMLStart: [\n \"
\",\n ...resultElements\n ].join(\"\\n\"),\n oddsHTMLStop: \"
\"\n };\n }\n /**\n * Calculate odds starting & ending HTML based on given dice total.\n * @param {number} diceTotal Total number of dice.\n * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display\n */\n calculateOddsHTML_Resistance(diceTotal) {\n // Const oddsColors = [\n // \"var(--blades-gold)\", // -1\n // \"var(--blades-white)\", // 0\n // \"var(--blades-red-bright)\", // 1\n // \"var(--blades-red-dark)\", // 2\n // \"var(--blades-red-bright)\", // 3\n // \"var(--blades-red-dark)\", // 4\n // \"var(--blades-red-bright)\" // 5\n // ].reverse();\n const oddsColors = [\n \"var(--blades-gold)\", // -1\n \"var(--blades-white)\", // 0\n \"var(--blades-red)\", // 1\n \"var(--blades-red)\", // 2\n \"var(--blades-red)\", // 3\n \"var(--blades-red)\", // 4\n \"var(--blades-red)\" // 5\n ].reverse();\n const oddsFilters = [\n \"none\",\n \"none\",\n \"brightness(0.2)\",\n \"brightness(0.4)\",\n \"brightness(0.6)\",\n \"brightness(0.8)\",\n \"none\"\n ].reverse();\n const odds = [..._core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].DiceOddsResistance[diceTotal]].reverse();\n const resultElements = [];\n for (let index = 0; index < odds.length; index++) {\n const chance = odds[index];\n if (chance > 0) {\n const color = oddsColors[index];\n const filter = oddsFilters[index];\n resultElements.push(...[\n `
 
`\n ]);\n }\n }\n return {\n oddsHTMLStart: [\n \"
\",\n ...resultElements\n ].join(\"\\n\"),\n oddsHTMLStop: \"
\"\n };\n }\n /**\n * Calculate data for position and effect trade.\n * @returns {{canTradePosition: boolean, canTradeEffect: boolean}}\n */\n calculatePositionEffectTradeData() {\n const canTradePosition = this.posEffectTrade === \"position\" || (this.posEffectTrade === false\n && this.rollPositionFinal !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.desperate\n && this.rollEffectFinal !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect.extreme);\n const canTradeEffect = this.posEffectTrade === \"effect\" || (this.posEffectTrade === false\n && this.rollPositionFinal !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.controlled\n && this.rollEffectFinal !== _core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect.zero);\n return { canTradePosition, canTradeEffect };\n }\n /**\n * Calculate data on whether there are any inactive conditionals.\n * @returns {Record} - Data on inactive conditionals.\n */\n calculateHasInactiveConditionalsData() {\n const hasInactive = {};\n for (const section of Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection)) {\n hasInactive[section] = this.getRollMods(section).filter((mod) => mod.isInInactiveBlock).length > 0;\n }\n return hasInactive;\n }\n // #endregion\n // #region *** EVALUATING ROLL *** ~\n // #region DICE ~\n _dieVals;\n get dieVals() {\n return this.roll.terms[0].results\n .map((result) => result.result)\n .sort()\n .reverse();\n // return this._dieVals;\n }\n // Accounts for rolling zero dice by removing highest.\n get finalDieVals() {\n return this.isRollingZero ? this.dieVals.slice(1) : this.dieVals;\n }\n get finalDiceData() {\n eLog.checkLog3(\"rollCollab\", \"[get finalDiceData()]\", { roll: this, dieVals: this.dieVals });\n const dieVals = [...this.dieVals];\n const ghostNum = this.isRollingZero ? dieVals.shift() : null;\n const isCritical = dieVals.filter((val) => val === 6).length >= 2;\n const diceData = dieVals.map((val, i) => ({\n value: val,\n dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i),\n dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical)\n }));\n if (ghostNum) {\n diceData.push({\n value: ghostNum,\n dieClass: \"blades-die-ghost\",\n dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false)\n });\n }\n return diceData;\n }\n // get dieValsHTML(): string {\n // eLog.checkLog3(\"rollCollab\", \"[get dieValsHTML()]\", {roll: this, dieVals: this.dieVals});\n // const dieVals = [...this.dieVals];\n // const ghostNum = this.isRollingZero ? dieVals.shift() : null;\n // const isCritical = dieVals.filter((val) => val === 6).length >= 2;\n // const diceData = dieVals.map((val, i) => ({\n // value: val,\n // dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i),\n // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical)\n // }));\n // if (ghostNum) {\n // diceData.push({\n // value: ghostNum,\n // dieClass: \"blades-die-ghost\",\n // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false)\n // });\n // }\n // return [\n // ...dieVals.map((val, i) => ``),\n // ghostNum ? `` : null\n // ]\n // .filter((val): val is string => typeof val === \"string\")\n // .join(\"\");\n // }\n // #endregion\n // #region RESULT GETTERS ~\n get isCritical() {\n return this.finalDieVals.filter((val) => val === 6).length >= 2;\n }\n get isSuccess() {\n return Boolean(!this.isCritical && this.finalDieVals.find((val) => val === 6));\n }\n get isPartial() {\n return Boolean(!this.isCritical && !this.isSuccess && this.finalDieVals.find((val) => val && val >= 4));\n }\n get isFail() {\n return !this.isCritical && !this.isSuccess && !this.isPartial;\n }\n get highestDieVal() {\n return this.finalDieVals[0];\n }\n get rollResult() {\n /* Subclass overrides determine how roll result is communicated. */\n throw new Error(\"[BladesRoll.rollResult] Unimplemented by Subclass.\");\n }\n // #endregion\n get isResolved() { return this.roll.total !== undefined; }\n async evaluateRoll() {\n // If this command is called on an already-resolved roll, close the roll collab element and return.\n if (this.isResolved) {\n this.closeRollCollab_Animation();\n return this.data;\n }\n this.closeRollCollab_SocketCall();\n eLog.checkLog3(\"rollCollab\", \"[resolveRoll()] Before Evaluation\", { roll: this, rollData: { ...this.data } });\n await this.roll.evaluate({ async: true });\n return await this.updateTargetData({\n ...this.data,\n rollPositionFinal: this.rollPositionFinal,\n rollEffectFinal: this.rollEffectFinal,\n rollResult: this.rollResult,\n rollTraitVerb: this.rollTraitVerb,\n rollTraitPastVerb: this.rollTraitPastVerb,\n finalDiceData: this.finalDiceData,\n rollPhase: this.isApplyingConsequences\n ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.AwaitingConsequences\n : _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollPhase.Complete\n });\n }\n async resolveRollResult() {\n /* Subclass overrides determine how result affects roll participants */\n throw new Error(\"[BladesRoll.resolveRollResult] Unimplemented by Subclass.\");\n }\n async outputRollToChat() {\n await _BladesChat__WEBPACK_IMPORTED_MODULE_7__[\"default\"].create({\n speaker: this.getSpeaker(_BladesChat__WEBPACK_IMPORTED_MODULE_7__[\"default\"].getSpeaker()),\n content: await renderTemplate(this.chatTemplate, this.data),\n type: CONST.CHAT_MESSAGE_TYPES.ROLL,\n flags: {\n \"eunos-blades\": { rollData: this.data }\n }\n });\n }\n async resolveRoll() {\n await this.evaluateRoll();\n this.resolveRollResult();\n await this.outputRollToChat();\n }\n // #endregion\n // #region *** INTERFACING WITH BLADESCHAT ***\n getSpeaker(chatSpeaker) {\n // Compare against rollPrimary and modify accordingly.\n const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryDoc } = this.rollPrimary;\n chatSpeaker.alias = rollPrimaryName;\n if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.cohort_expert].includes(rollPrimaryType)) {\n chatSpeaker.actor = rollPrimaryDoc?.parent?.id ?? chatSpeaker.actor;\n if (rollPrimaryDoc?.parent instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC) {\n chatSpeaker.alias = `${chatSpeaker.alias} (${rollPrimaryDoc.parent.name})`;\n }\n }\n else if ([_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gm_tracker, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.score].includes(rollPrimaryType)) {\n chatSpeaker.actor = null;\n chatSpeaker.alias = \"The Gamemaster\";\n }\n else if (rollPrimaryID) {\n chatSpeaker.actor = rollPrimaryID;\n }\n // chatSpeaker.alias = `${chatSpeaker.alias} Rolls ...`;\n return chatSpeaker;\n }\n // #endregion\n // #region *** ROLL COLLAB HTML ELEMENT ***\n _elem$;\n _overlayPosition = { x: 200, y: 200 };\n get overlayPosition() { return this._overlayPosition; }\n set overlayPosition(val) { this._overlayPosition = val; }\n get elem$() {\n if (this._elem$) {\n return this._elem$;\n }\n const elem$ = $(`#${this.id}`);\n if (elem$.length) {\n this._elem$ = elem$;\n }\n else {\n this._elem$ = $(`
`).appendTo(\"body\");\n this._elem$.css({\n left: `${this.overlayPosition.x}px`,\n top: `${this.overlayPosition.y}px`\n });\n }\n return this._elem$;\n }\n async renderRollCollab() {\n this.prepareRollParticipantData();\n const html = await renderTemplate(this.collabTemplate, this.context);\n this.elem$.html(html);\n this.activateListeners();\n }\n get isRendered() {\n return Boolean(this._elem$?.length);\n }\n get collabTemplate() {\n /* Subclass overrides determine template against which data is parsed */\n throw new Error(\"[BladesRoll.collabTemplate] Unimplemented by Subclass.\");\n }\n get chatTemplate() {\n /* Subclass overrides determine template against which data is parsed */\n throw new Error(\"[BladesRoll.chatTemplate] Unimplemented by Subclass.\");\n }\n // #region LISTENER FUNCTIONS ~\n // async _handleConsequenceClick(event: ClickEvent) {\n // const clickTarget$ = $(event.currentTarget);\n // const csqParent$ = clickTarget$.closest(\".comp.consequence-display-container\");\n // const csqID = csqParent$.data(\"csq-id\");\n // const chatElem$ = csqParent$.closest(\".blades-roll\");\n // const chatMessage$ = chatElem$.closest(\".chat-message\");\n // const chatID = chatMessage$.data(\"messageId\") as IDString;\n // const chatMessage = game.messages.get(chatID);\n // if (!chatMessage) {return;}\n // const csqs = await BladesConsequence.GetFromChatMessage(chatMessage);\n // const thisCsq = csqs.find((csq) => csq.id === csqID);\n // if (!thisCsq) {return;}\n // switch (clickTarget$.data(\"action\")) {\n // case \"accept-consequence\": return thisCsq.resolveAccept();\n // case \"resist-consequence\": return thisCsq.resistConsequence();\n // case \"armor-consequence\": return thisCsq.resistArmorConsequence();\n // case \"special-consequence\": return thisCsq.resistSpecialArmorConsequence();\n // }\n // return undefined as never;\n // }\n _toggleRollModClick(event) {\n event.preventDefault();\n const elem$ = $(event.currentTarget);\n const id = elem$.data(\"id\");\n const rollMod = this.getRollModByID(id);\n if (!rollMod) {\n throw new Error(`Unable to find roll mod with id '${id}'`);\n }\n rollMod.isRerendering = true;\n switch (rollMod.status) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden:\n rollMod.userStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff;\n break;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOff:\n rollMod.userStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff;\n break;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff:\n rollMod.userStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn;\n break;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOn:\n rollMod.userStatus = game.user.isGM\n ? _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn\n : _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff;\n break;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn:\n rollMod.userStatus = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden;\n break;\n default: throw new Error(`Unrecognized RollModStatus: ${rollMod.status}`);\n }\n rollMod.isRerendering = false;\n }\n /**\n * Handles setting of rollMod status via GM pop-out controls\n * @param {ClickEvent} event JQuery click event sent to listener.\n */\n _gmControlSet(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const id = elem$.data(\"id\");\n const status = elem$.data(\"status\");\n if (!isModStatus(status) && status !== \"Reset\") {\n return;\n }\n const rollMod = this.getRollModByID(id);\n if (rollMod) {\n rollMod.userStatus = status === \"Reset\" ? undefined : status;\n }\n }\n /**\n * Handles setting values via GM number line (e.g. roll factor boosts/modifications).\n * @param {ClickEvent} event JQuery click event sent to listener.\n */\n async _gmControlSetTargetToValue(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const target = elem$.data(\"target\").replace(/flags\\.eunos-blades\\./, \"\");\n const value = elem$.data(\"value\");\n await this.updateTarget(target, value);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n async _gmControlCycleTarget(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const flagTarget = elem$.data(\"flagTarget\");\n const curVal = elem$.data(\"curVal\");\n const cycleVals = elem$.data(\"vals\")?.split(/\\|/);\n if (!cycleVals) {\n throw new Error(`Unable to parse cycle values from data-vals = ${elem$.data(\"vals\")}`);\n }\n const curValIndex = cycleVals.indexOf(curVal);\n if (curValIndex === -1) {\n throw new Error(`Unable to find current value '${curVal}' in cycle values '${elem$.data(\"vals\")}'`);\n }\n let newValIndex = curValIndex + 1;\n if (newValIndex >= cycleVals.length) {\n newValIndex = 0;\n }\n const newVal = cycleVals[newValIndex];\n eLog.checkLog3(\"gmControlCycleTarget\", \"gmControlCycleTarget\", { flagTarget, curVal, cycleVals, curValIndex, newValIndex, newVal });\n await this.updateTarget(flagTarget, newVal);\n }\n /**\n * Handles resetting value associated with GM number line on a right-click.\n * @param {ClickEvent} event JQuery context menu event sent to listener.\n */\n async _gmControlResetTarget(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n await this.updateTarget($(event.currentTarget).data(\"target\"), undefined);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n /**\n * Handles setting of baseline rollPosition via GM button line\n * @param {ClickEvent} event JQuery click event sent to listener.\n */\n _gmControlSetPosition(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const position = elem$.data(\"status\");\n this.initialPosition = position;\n }\n /**\n * Handles setting of baseline rollPosition via GM button line\n * @param {ClickEvent} event JQuery click event sent to listener.\n */\n _gmControlSetEffect(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const effect = elem$.data(\"status\");\n this.initialEffect = effect;\n }\n /**\n * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant\n * @param {ClickEvent} event JQuery click event sent to listener.\n */\n async _gmControlToggleFactor(event) {\n event.preventDefault();\n if (!game.user.isGM) {\n return;\n }\n const elem$ = $(event.currentTarget);\n const target = elem$.data(\"target\");\n const value = !elem$.data(\"value\");\n eLog.checkLog3(\"toggleFactor\", \"_gmControlToggleFactor\", { event, target, value });\n const factorToggleData = this.data.rollFactorToggles;\n const [thisSource, thisFactor, thisToggle] = target.split(/\\./).slice(-3);\n // If thisToggle is unrecognized, just toggle whatever value target points at\n if (![\"isActive\", \"isPrimary\", \"isDominant\", \"highFavorsPC\"].includes(thisToggle)) {\n await this.updateTarget(target, value);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n // Otherwise, first toggle targeted factor to new value\n factorToggleData[thisSource][thisFactor] = {\n ...factorToggleData[thisSource][thisFactor] ?? { display: \"\" },\n [thisToggle]: value\n };\n // Then perform specific logic depending on toggle targeted:\n switch (thisToggle) {\n case \"isDominant\":\n case \"isPrimary\": {\n // Only one factor per sourceType can be declared Primary or Dominant:\n // If one is being activated, must toggle off the others.\n if (value === true) {\n Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor)\n .filter((factor) => factor !== thisFactor)\n .forEach((factor) => {\n if (factorToggleData[thisSource][factor]?.[thisToggle] === true) {\n factorToggleData[thisSource][factor] = {\n ...factorToggleData[thisSource][factor],\n [thisToggle]: false\n };\n }\n });\n }\n break;\n }\n case \"isActive\": {\n // 'isActive' should be synchronized when 1) value is true, and 2) the other value is false\n if (value === true) {\n const otherSource = thisSource === \"source\" ? \"opposition\" : \"source\";\n factorToggleData[otherSource][thisFactor] = {\n ...factorToggleData[otherSource][thisFactor] ?? { display: \"\" },\n isActive: value\n };\n }\n break;\n }\n default: break;\n }\n await this.updateTarget(\"rollFactorToggles\", factorToggleData);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n async _onSelectChange(event) {\n event.preventDefault();\n const elem = event.currentTarget;\n const { docType } = elem.dataset;\n if (elem.value !== \"\" && docType?.startsWith(\"BladesRollParticipant\")) {\n const [_, section, subSection] = docType.split(\".\");\n await this.addRollParticipant(elem.value, section, subSection);\n }\n else {\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].EventHandlers.onSelectChange(this, event);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n }\n async _onTextInputBlur(event) {\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].EventHandlers.onTextInputBlur(this, event);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n async _onGMPopupClick(event) {\n /**\n * \n *\n * */\n const elem$ = $(event.currentTarget);\n const prompt = elem$.data(\"prompt\");\n const flagTarget = elem$.data(\"flagTarget\");\n if (prompt && flagTarget) {\n _BladesDialog__WEBPACK_IMPORTED_MODULE_6__[\"default\"].DisplaySimpleInputDialog(this, prompt, undefined, flagTarget);\n }\n }\n // Async _gmControlSelect(event: SelectChangeEvent) {\n // event.preventDefault();\n // const elem$ = $(event.currentTarget);\n // const section = elem$.data(\"rollSection\");\n // const subSection = elem$.data(\"rollSubSection\");\n // const selectedOption = elem$.val();\n // if (typeof selectedOption !== \"string\") { return; }\n // if (selectedOption === \"false\") {\n // await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.rollParticipantData.${section}.${subSection}`);\n // }\n // await this.addRollParticipant(selectedOption, section, subSection);\n // }\n // #endregion\n // #region ACTIVATE LISTENERS ~\n _positionDragger;\n get positionDragger() {\n if (this._positionDragger) {\n return this._positionDragger;\n }\n return this.spawnPositionDragger();\n }\n spawnPositionDragger() {\n const self = this;\n if (!this._elem$) {\n throw new Error(`[BladesRoll.spawnPositionDragger] No elem$ found for roll ${this.id}.`);\n }\n this._positionDragger?.kill();\n return (this._positionDragger = new _core_gsap__WEBPACK_IMPORTED_MODULE_4__.Dragger(this._elem$, {\n type: \"top,left\",\n trigger: \".window-header.dragger\",\n onDragStart() {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.to(this.target, { opacity: 0.25, duration: 0.25, ease: \"power2\" });\n },\n onDragEnd() {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.to(this.target, { opacity: 1, duration: 0.25, ease: \"power2\" });\n self.overlayPosition = { x: this.endX, y: this.endY };\n }\n }));\n }\n activateListeners() {\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_4__.ApplyTooltipAnimations)(this.elem$);\n this.spawnPositionDragger();\n // If a rollClockKey exists, initialize its elements\n if (this.rollClockKey) {\n this.elem$.find(\".roll-clock\").removeClass(\"hidden\");\n }\n // User-Toggleable Roll Mods\n this.elem$.find(\".roll-mod[data-action='toggle']\").on({\n click: this._toggleRollModClick.bind(this)\n });\n this.elem$.find(\"[data-action='tradePosition']\").on({\n click: (event) => {\n const curVal = `${$(event.currentTarget).data(\"value\")}`;\n if (curVal === \"false\") {\n this.updateTarget(\"rollPosEffectTrade\", \"effect\")\n .then(() => socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id));\n }\n else {\n this.updateTarget(\"rollPosEffectTrade\", false)\n .then(() => socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id));\n }\n }\n });\n this.elem$.find(\"[data-action='tradeEffect']\").on({\n click: (event) => {\n const curVal = `${$(event.currentTarget).data(\"value\")}`;\n if (curVal === \"false\") {\n this.updateTarget(\"rollPosEffectTrade\", \"position\")\n .then(() => socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id));\n }\n else {\n this.updateTarget(\"rollPosEffectTrade\", false)\n .then(() => socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id));\n }\n }\n });\n this.elem$.find(\"[data-action='roll']\").on({\n click: () => this.resolveRoll()\n });\n this.elem$\n .find(\"select[data-action='player-select']\")\n .on({ change: this._onSelectChange.bind(this) });\n if (!game.user.isGM) {\n return;\n }\n /**\n * Handles setting of rollMod status via GM pop-out controls\n */\n this.elem$.find(\".controls-toggle\").on({\n click: (event) => {\n event.preventDefault();\n $(event.currentTarget).parents(\".controls-panel\").toggleClass(\"active\");\n }\n });\n this.elem$.find(\"[data-action=\\\"gm-set\\\"]\").on({\n click: this._gmControlSet.bind(this)\n });\n /**\n * Handles setting of baseline rollPosition via GM button line\n */\n this.elem$.find(\"[data-action=\\\"gm-set-position\\\"]\").on({\n click: this._gmControlSetPosition.bind(this)\n });\n /**\n * Handles setting of baseline rollEffect via GM button line\n */\n this.elem$.find(\"[data-action=\\\"gm-set-effect\\\"]\").on({\n click: this._gmControlSetEffect.bind(this)\n });\n /**\n * Handles setting values via GM number line (e.g. roll factor boosts/modifications).\n * Handles resetting value associated with GM number line on a right-click.\n */\n this.elem$.find(\"[data-action=\\\"gm-set-target\\\"]\").on({\n click: this._gmControlSetTargetToValue.bind(this),\n contextmenu: this._gmControlResetTarget.bind(this)\n });\n /**\n * Handles setting values via GM number line (e.g. roll factor boosts/modifications).\n * Handles resetting value associated with GM number line on a right-click.\n */\n this.elem$.find(\"[data-action=\\\"gm-cycle-target\\\"]\").on({\n click: this._gmControlCycleTarget.bind(this)\n });\n /**\n * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant\n */\n this.elem$.find(\"[data-action=\\\"gm-toggle-factor\\\"]\").on({\n click: this._gmControlToggleFactor.bind(this)\n });\n this.elem$\n .find(\"select[data-action='gm-select']\")\n .on({ change: this._onSelectChange.bind(this) });\n // this.elem$\n // .find(\"[data-action=\\\"gm-edit-consequences\\\"]\")\n // .on({click: () => BladesDialog.DisplayRollConsequenceDialog(this)});\n this.elem$\n .find(\"[data-action=\\\"gm-text-popup\\\"]\")\n .on({ click: this._onGMPopupClick.bind(this) });\n this.elem$\n .find(\"[data-action='gm-text-input']\")\n .on({ blur: this._onTextInputBlur.bind(this) });\n }\n // #endregion\n // #endregion\n // #region OVERRIDES: _canDragDrop, _onDrop, _onSubmit, close, render ~\n // override _canDragDrop() {\n // return game.user.isGM;\n // }\n // override _onDrop(event: DragEvent) {\n // const {uuid} = TextEditor.getDragEventData(event) as {uuid: UUIDString};\n // const dropDoc = fromUuidSync(uuid);\n // if (BladesRollOpposition.IsDoc(dropDoc)) {\n // this.rollOpposition = new BladesRollOpposition(this, {rollOppDoc: dropDoc});\n // } else if (dropDoc instanceof BladesProject && dropDoc.clockKey) {\n // // Project dropped on roll: Assign project's clock key to roll.\n // this.rollClockKey = dropDoc.clockKey;\n // }\n // }\n async submitChange(prop, val) {\n await this.updateTarget(prop, val);\n socketlib.system.executeForEveryone(\"renderRollCollab_SocketCall\", this.id);\n }\n}\nclass BladesActionRoll extends BladesRoll {\n /* Not much -- most action roll things will extend to other rolls, but split out things like Position, Effect, default Mods */\n static ApplySchemaDefaults(schemaData) {\n schemaData.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollType.Action;\n if (!schemaData.rollPrimaryData) {\n throw new Error(\"Must include a rollPrimaryData when constructing a BladesActionRoll object.\");\n }\n // Validate the rollTrait\n if (!(schemaData.rollTrait === \"\" || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(schemaData.rollTrait) || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(schemaData.rollTrait) in { ..._core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait, ..._core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor })) {\n throw new Error(`[BladesActionRoll.ApplySchemaDefaults()] Bad RollTrait for Action Roll: ${schemaData.rollTrait}`);\n }\n const fullSchema = super.ApplySchemaDefaults(schemaData);\n const rollPrimary = BladesRollPrimary.Build(fullSchema);\n // Modify Config object depending on downtime action where necessary.\n switch (fullSchema.rollDowntimeAction) { // Remember: Can be done outside of Downtime during Flashbacks!\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.AcquireAsset: {\n fullSchema.rollTrait = _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier;\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.LongTermProject: {\n // Validate that rollOppData points to a project item\n if (!BladesRollOpposition.IsValidData(fullSchema.rollOppData)) {\n throw new Error(\"No rollOppData provided for LongTermProject roll.\");\n }\n if (![\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.project,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.design\n ].includes(fullSchema.rollOppData.rollOppType)) {\n throw new Error(\"rollOppType must be 'project' or 'design' for LongTermProject roll.\");\n }\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.Recover: {\n // Validate that rollPrimary is an NPC or a PC with Physiker.\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(rollPrimary.rollPrimaryDoc)) {\n if (!rollPrimary.rollPrimaryDoc.abilities.find((ability) => ability.name === \"Physiker\")) {\n throw new Error(\"A PC rollPrimary on a Recovery roll must have the Physiker ability.\");\n }\n fullSchema.rollTrait = _core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait.tinker;\n }\n else if (rollPrimary.rollPrimaryDoc?.rollPrimaryType === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc) {\n fullSchema.rollTrait = _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality;\n }\n else {\n throw new Error(\"Only a PC with Physiker or an NPC can be rollPrimary on a Recover roll.\");\n }\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.ReduceHeat: {\n // rollPrimary must be a cohort with a parent PC or Crew,\n // and PC must be member of a crew\n // and Crew must not have zero Heat.\n let parentCrew = undefined;\n if (rollPrimary.rollPrimaryDoc) {\n const { parent } = rollPrimary.rollPrimaryDoc;\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(parent)) {\n parentCrew = parent;\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(parent) && _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(parent.crew)) {\n parentCrew = parent.crew;\n }\n }\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesCrew.IsType(parentCrew)) {\n throw new Error(`Could not find crew for rollPrimary '${rollPrimary.rollPrimaryDoc?.rollPrimaryName}'`);\n }\n if (parentCrew.system.heat.value === 0) {\n throw new Error(\"Attempt to Reduce Heat for a Crew with no Heat.\");\n }\n break;\n }\n case undefined: break;\n default: throw new Error(`Unrecognized Roll Downtime Action: ${fullSchema.rollDowntimeAction}`);\n }\n return {\n rollPositionInitial: _core_constants__WEBPACK_IMPORTED_MODULE_1__.Position.risky,\n rollEffectInitial: _core_constants__WEBPACK_IMPORTED_MODULE_1__.Effect.standard,\n rollPosEffectTrade: false,\n GMBoosts: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: 0\n },\n GMOppBoosts: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: 0,\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: 0\n },\n GMOverrides: {},\n rollFactorToggles: {\n source: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n }\n },\n opposition: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude]: {\n display: \"\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n }\n }\n },\n ...fullSchema,\n rollPrimaryData: rollPrimary.data,\n rollOppData: fullSchema.rollOppData instanceof BladesRollOpposition\n ? fullSchema.rollOppData.data\n : fullSchema.rollOppData\n };\n }\n static get DefaultRollModSchemaSet() {\n return [\n {\n key: \"Push-positive-roll\",\n name: \"PUSH\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [\"ForceOff-Bargain\", \"Cost-Stress2\"],\n tooltip: \"

Push for +1d

For 2 Stress, add 1 die to your pool.

(You cannot also accept a Devil's Bargain to increase your dice pool: It's one or the other.)

\"\n },\n {\n key: \"Bargain-positive-roll\",\n name: \"Bargain\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Devil's Bargain

The GM has offered you a Devil's Bargain.

Accept the terms to add 1 die to your pool.

(You cannot also Push for +1d to increase your dice pool: It's one or the other.)

\"\n },\n {\n key: \"Assist-positive-roll\",\n name: \"Assist\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.teamwork,\n value: 1,\n tooltip: \"

%DOC_NAME% Assists

%DOC_NAME% is Assisting your efforts, adding 1 die to your pool.

\"\n },\n {\n key: \"Setup-positive-position\",\n name: \"Setup\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.teamwork,\n value: 1,\n tooltip: \"

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Position by one level.

\"\n },\n {\n key: \"Push-positive-effect\",\n name: \"PUSH\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [\"Cost-Stress2\"],\n tooltip: \"

Push for Effect

For 2 Stress, increase your Effect by one level.

\"\n },\n {\n key: \"Setup-positive-effect\",\n name: \"Setup\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.teamwork,\n value: 1,\n tooltip: \"

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Effect by one level.

\"\n },\n {\n key: \"Potency-positive-effect\",\n name: \"Potency\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n tooltip: \"

Potency

By circumstance or advantage, you have Potency in this action, increasing your Effect by one level.

\"\n },\n {\n key: \"Potency-negative-effect\",\n name: \"Potency\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.Hidden,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n tooltip: \"

Potency

By circumstance or advantage, @OPPOSITION_NAME@ has Potency against you, reducing your Effect by one level.\"\n }\n ];\n }\n /**\n * Asynchronously creates a new instance of this subclass of `BladesRoll`.\n *\n * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations\n * to the instance creation process. It ensures that the returned instance is correctly typed\n * and configured for this subclass.\n *\n * @param {BladesRoll.Config} config The configuration object for creating a new roll instance,\n * extended with any subclass-specific configurations or requirements.\n *\n * @returns {Promise>} A promise that resolves to an instance of this subclass.\n *\n * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process\n * for roll instances.\n */\n static async New(config) {\n // Build link config\n const linkConfig = this.BuildLinkConfig(config);\n const parsedConfig = {\n ...config,\n ...linkConfig\n };\n // Call super.New and cast the result appropriately.\n // The cast to InstanceType is safe here because C is constrained to typeof BladesActionRoll.\n const rollInst = await super.New(parsedConfig);\n return rollInst;\n }\n get rollModsSchemaSets() {\n const rollModSchemaSets = super.rollModsSchemaSets;\n // Add additional conditional roll mods based on effects of previous consequences.\n if (this.rollPrimary.isWorsePosition) {\n rollModSchemaSets.push({\n key: \"WorsePosition-negative-position\",\n name: \"Worse Position\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Worse Position

A Consequence on a previous roll has worsened your Position.

\"\n });\n }\n if (this.acceptedConsequences.some((csq) => csq.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.ConsequenceType.ReducedEffect)) {\n rollModSchemaSets.push({\n key: \"ReducedEffect-negative-effect\",\n name: \"Reduced Effect\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.effect,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ForcedOn,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Reduced Effect

A Consequence has worsened your Effect.

\"\n });\n }\n return rollModSchemaSets;\n }\n get collabTemplate() {\n return `systems/eunos-blades/templates/roll/roll-collab-action${game.user.isGM ? \"-gm\" : \"\"}.hbs`;\n }\n get chatTemplate() {\n const templateParts = [\n \"systems/eunos-blades/templates/chat/roll-result/action\",\n this.rollClockKey ? \"-clock\" : \"\"\n ];\n if (this.rollDowntimeAction && [\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.AcquireAsset, // action-acquireasset\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.ReduceHeat, // action-reduceheat\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.Recover // action-clock-recover\n ].includes(this.rollDowntimeAction)) {\n templateParts.push(`-${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(this.rollDowntimeAction)}`);\n }\n else if (this.rollSubType && [\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollSubType.GatherInfo // action-gatherinfo\n ].includes(this.rollSubType)) {\n templateParts.push(`-${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(this.rollSubType)}`);\n }\n templateParts.push(\".hbs\");\n return templateParts.join(\"\");\n }\n get rollResult() {\n if (!this.isResolved) {\n return false;\n }\n if (this.isCritical) {\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.critical;\n }\n if (this.isSuccess) {\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.success;\n }\n if (this.isPartial) {\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.partial;\n }\n return _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollResult.fail;\n }\n async resolveRollResult() {\n eLog.checkLog2(\"bladesRoll\", \"[BladesActionRoll] Costs\", this.getRollCosts());\n const armorCost = this.getRollCosts()\n .filter((costData) => costData.costType === \"Armor\")\n .length;\n if (this.rollPrimaryDoc instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC) {\n const stressCost = this.getRollCosts()\n .filter((costData) => costData.costType === \"Stress\")\n .reduce((acc, costData) => acc + costData.costAmount, 0);\n if (stressCost !== 0) {\n this.rollPrimaryDoc.adjustStress(stressCost);\n }\n const specArmorCost = this.getRollCosts()\n .filter((costData) => costData.costType === \"SpecialArmor\")\n .length;\n if (specArmorCost !== 0) {\n this.rollPrimaryDoc.spendSpecialArmor();\n }\n }\n if (armorCost !== 0) {\n this.rollPrimary.spendArmor(armorCost);\n }\n if (this.getRollModByKey(\"WorsePosition-negative-position\")?.isActive) {\n this.rollPrimaryDoc?.unsetFlag(\"eunos-blades\", \"isWorsePosition\");\n }\n }\n}\nclass BladesResistanceRoll extends BladesRoll {\n static ApplySchemaDefaults(config) {\n // Validate consequenceData\n if (!config.resistanceData || !_BladesConsequence__WEBPACK_IMPORTED_MODULE_5__[\"default\"].IsValidConsequenceData(config.resistanceData?.consequence)) {\n eLog.error(\"rollCollab\", \"[PrepareResistanceRoll] Bad Roll Consequence Data.\", config);\n throw new Error(\"[PrepareResistanceRoll()] Bad Consequence Data for Resistance Roll\");\n }\n // Set rollTrait\n config.rollTrait = config.resistanceData.consequence.attribute;\n eLog.checkLog3(\"bladesRoll\", \"BladesRoll.PrepareResistanceRoll() [1]\", { config });\n return config;\n }\n /**\n * Asynchronously creates a new instance of this subclass of `BladesRoll`.\n *\n * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations\n * to the instance creation process. It ensures that the returned instance is correctly typed\n * and configured for this subclass.\n *\n * @param {BladesRoll.Config} config The configuration object for creating a new roll instance,\n * extended with any subclass-specific configurations or requirements.\n *\n * @returns {Promise>} A promise that resolves to an instance of this subclass.\n *\n * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process\n * for roll instances.\n */\n static async New(config) {\n // Build link config\n const linkConfig = this.BuildLinkConfig(config);\n const parsedConfig = {\n ...config,\n ...linkConfig\n };\n // Call super.New and cast the result appropriately.\n // The cast to InstanceType is safe here because C is constrained to typeof BladesResistanceRoll.\n const rollInst = await super.New(parsedConfig);\n return rollInst;\n }\n get collabTemplate() {\n return `systems/eunos-blades/templates/roll/roll-collab-resistance${game.user.isGM ? \"-gm\" : \"\"}.hbs`;\n }\n get chatTemplate() {\n return \"systems/eunos-blades/templates/chat/roll-result/resistance.hbs\";\n }\n get stressCost() {\n if (!this.isResolved) {\n return 0;\n }\n const dieVals = [...this.finalDieVals];\n if (this.isCritical) {\n return -1;\n }\n return 6 - (dieVals.shift() ?? 0);\n }\n get rollResult() {\n if (!this.isResolved) {\n return false;\n }\n return this.stressCost;\n }\n async resolveRollResult() {\n if (this.rollPrimaryDoc instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC && this.stressCost !== 0) {\n this.rollPrimaryDoc.adjustStress(this.stressCost);\n }\n }\n}\nclass BladesInlineResistanceRoll extends BladesResistanceRoll {\n get chatTemplate() {\n return \"systems/eunos-blades/templates/chat/components/inline-resistance.hbs\";\n }\n}\nclass BladesFortuneRoll extends BladesRoll {\n static ApplySchemaDefaults(config) {\n // Validate the rollTrait\n if (!(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(config.rollTrait) || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(config.rollTrait) in { ..._core_constants__WEBPACK_IMPORTED_MODULE_1__.ActionTrait, ..._core_constants__WEBPACK_IMPORTED_MODULE_1__.AttributeTrait, ..._core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor })) {\n throw new Error(`[PrepareFortuneRoll()] Bad RollTrait for Fortune Roll: ${config.rollTrait}`);\n }\n return config;\n }\n /**\n * Asynchronously creates a new instance of this subclass of `BladesRoll`.\n *\n * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations\n * to the instance creation process. It ensures that the returned instance is correctly typed\n * and configured for this subclass.\n *\n * @param {BladesRoll.Config} config The configuration object for creating a new roll instance,\n * extended with any subclass-specific configurations or requirements.\n *\n * @returns {Promise>} A promise that resolves to an instance of this subclass.\n *\n * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process\n * for roll instances.\n */\n static async New(config) {\n // Build link config\n const linkConfig = this.BuildLinkConfig(config);\n const parsedConfig = {\n ...config,\n ...linkConfig\n };\n // Call super.New and cast the result appropriately.\n // The cast to InstanceType is safe here because C is constrained to typeof BladesFortuneRoll.\n const rollInst = await super.New(parsedConfig);\n return rollInst;\n }\n}\nclass BladesIndulgeViceRoll extends BladesRoll {\n static ApplySchemaDefaults(config) {\n // Validate rollPrimary\n const rollPrimaryDoc = BladesRollPrimary.GetDoc(config.rollPrimaryData?.rollPrimaryID);\n if (!rollPrimaryDoc || !_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(rollPrimaryDoc)) {\n throw new Error(\"[BladesRoll.PrepareIndulgeViceRollConfig] RollPrimary must be a PC for Indulge Vice rolls.\");\n }\n // Set rollTrait\n const { attributes } = rollPrimaryDoc;\n const minAttrVal = Math.min(...Object.values(attributes));\n config.rollTrait = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sample(Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.AttributeTrait).filter((attr) => attributes[attr] === minAttrVal))[0];\n // Set other known config values\n config.rollDowntimeAction = _core_constants__WEBPACK_IMPORTED_MODULE_1__.DowntimeAction.IndulgeVice;\n return config;\n }\n /**\n * Asynchronously creates a new instance of this subclass of `BladesRoll`.\n *\n * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations\n * to the instance creation process. It ensures that the returned instance is correctly typed\n * and configured for this subclass.\n *\n * @param {BladesRoll.Config} config The configuration object for creating a new roll instance,\n * extended with any subclass-specific configurations or requirements.\n *\n * @returns {Promise>} A promise that resolves to an instance of this subclass.\n *\n * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process\n * for roll instances.\n */\n static async New(config) {\n // Build link config\n const linkConfig = this.BuildLinkConfig(config);\n const parsedConfig = {\n ...config,\n ...linkConfig\n };\n // Call super.New and cast the result appropriately.\n // The cast to InstanceType is safe here because C is constrained to typeof BladesIndulgeViceRoll.\n const rollInst = await super.New(parsedConfig);\n return rollInst;\n }\n get collabTemplate() {\n return `systems/eunos-blades/templates/roll/roll-collab-indulgevice${game.user.isGM ? \"-gm\" : \"\"}.hbs`;\n }\n get chatTemplate() {\n return \"systems/eunos-blades/templates/chat/roll-result/indulgevice.hbs\";\n }\n get rollResult() {\n if (!this.isResolved) {\n return false;\n }\n return this.highestDieVal;\n }\n async resolveRollResult() {\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesPC.IsType(this.rollPrimaryDoc)) {\n this.rollPrimaryDoc.indulgeStress(this.highestDieVal);\n }\n }\n}\nclass BladesEngagementRoll extends BladesFortuneRoll {\n static get DefaultRollModSchemaSet() {\n return [\n {\n key: \"BoldPlan-positive-roll\",\n name: \"Bold Plan\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

\"\n },\n {\n key: \"ComplexPlan-negative-roll\",\n name: \"Complex Plan\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

\"\n },\n {\n key: \"ExploitWeakness-positive-roll\",\n name: \"Exploiting a Weakness\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

\"\n },\n {\n key: \"WellDefended-negative-roll\",\n name: \"Well-Defended\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

\"\n },\n {\n key: \"HelpFromFriend-positive-roll\",\n name: \"Help From a Friend\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.position,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"positive\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

\"\n },\n {\n key: \"EnemyInterference-negative-roll\",\n name: \"Enemy Interference\",\n section: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModSection.roll,\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModStatus.ToggledOff,\n posNeg: \"negative\",\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_1__.RollModType.general,\n value: 1,\n effectKeys: [],\n tooltip: \"

\"\n }\n ];\n }\n get chatTemplate() {\n return \"systems/eunos-blades/templates/chat/roll-result/fortune-engagement.hbs\";\n }\n}\nclass BladesIncarcerationRoll extends BladesFortuneRoll {\n get chatTemplate() {\n return \"systems/eunos-blades/templates/chat/roll-result/fortune-incarceration.hbs\";\n }\n}\n// #region EXPORTS ~\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesRoll);\n\n// #endregion\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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REFBYTtBQUMxQztBQUNBLHlCQUF5Qix3REFBVztBQUNwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUN5RjtBQUN6RiwrREFBZSxVQUFVLEVBQUM7QUFDNkk7QUFDdksiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jbGFzc2VzL0JsYWRlc1JvbGwudHM/YjQwMSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbi8vICNyZWdpb24gSU1QT1JUUyB+XG5pbXBvcnQgVSBmcm9tIFwiLi4vY29yZS91dGlsaXRpZXNcIjtcbmltcG9ydCBDLCB7IEJsYWRlc0FjdG9yVHlwZSwgQmxhZGVzSXRlbVR5cGUsIFJvbGxQZXJtaXNzaW9ucywgUm9sbFR5cGUsIFJvbGxTdWJUeXBlLCBSb2xsTW9kVHlwZSwgUm9sbE1vZFN0YXR1cywgUm9sbE1vZFNlY3Rpb24sIEFjdGlvblRyYWl0LCBEb3dudGltZUFjdGlvbiwgQXR0cmlidXRlVHJhaXQsIFBvc2l0aW9uLCBFZmZlY3QsIEZhY3RvciwgUm9sbFJlc3VsdCwgUm9sbFBoYXNlLCBDb25zZXF1ZW5jZVR5cGUsIFRhZyB9IGZyb20gXCIuLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3IsIEJsYWRlc1BDLCBCbGFkZXNDcmV3IH0gZnJvbSBcIi4uL2RvY3VtZW50cy9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgeyBCbGFkZXNJdGVtLCBCbGFkZXNHTVRyYWNrZXIgfSBmcm9tIFwiLi4vZG9jdW1lbnRzL0JsYWRlc0l0ZW1Qcm94eVwiO1xuaW1wb3J0IHsgQXBwbHlUb29sdGlwQW5pbWF0aW9ucywgRHJhZ2dlciB9IGZyb20gXCIuLi9jb3JlL2dzYXBcIjtcbmltcG9ydCBCbGFkZXNDb25zZXF1ZW5jZSBmcm9tIFwiLi9CbGFkZXNDb25zZXF1ZW5jZVwiO1xuaW1wb3J0IEJsYWRlc0RpYWxvZyBmcm9tIFwiLi9CbGFkZXNEaWFsb2dcIjtcbmltcG9ydCBCbGFkZXNDaGF0IGZyb20gXCIuL0JsYWRlc0NoYXRcIjtcbmltcG9ydCBCbGFkZXNUYXJnZXRMaW5rIGZyb20gXCIuL0JsYWRlc1RhcmdldExpbmtcIjtcbi8vICNlbmRyZWdpb25cbi8vICNyZWdpb24gVHlwZXMgJiBUeXBlIENoZWNraW5nIH5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBzdHJpbmcgaXMgYSBSb2xsVHlwZS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gc3RyIFRoZSBzdHJpbmcgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVHJ1ZSBpZiB0aGUgc3RyaW5nIGlzIGEgUm9sbFR5cGUsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuZnVuY3Rpb24gaXNSb2xsVHlwZShzdHIpIHtcbiAgICByZXR1cm4gdHlwZW9mIHN0ciA9PT0gXCJzdHJpbmdcIiAmJiBzdHIgaW4gUm9sbFR5cGU7XG59XG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gdHJhaXQgaXMgYW4gQWN0aW9uVHJhaXQuXG4gKiBAcGFyYW0ge3Vua25vd259IHRyYWl0IFRoZSB0cmFpdCB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB0cmFpdCBpcyBhbiBBY3Rpb25UcmFpdCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5mdW5jdGlvbiBpc0FjdGlvbih0cmFpdCkge1xuICAgIHJldHVybiBCb29sZWFuKHRyYWl0ICYmIHR5cGVvZiB0cmFpdCA9PT0gXCJzdHJpbmdcIiAmJiBVLmxDYXNlKHRyYWl0KSBpbiBBY3Rpb25UcmFpdCk7XG59XG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gdHJhaXQgaXMgYW4gQXR0cmlidXRlVHJhaXQuXG4gKiBAcGFyYW0ge3Vua25vd259IHRyYWl0IFRoZSB0cmFpdCB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB0cmFpdCBpcyBhbiBBdHRyaWJ1dGVUcmFpdCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5mdW5jdGlvbiBpc0F0dHJpYnV0ZSh0cmFpdCkge1xuICAgIHJldHVybiBCb29sZWFuKHRyYWl0ICYmIHR5cGVvZiB0cmFpdCA9PT0gXCJzdHJpbmdcIiAmJiBVLmxDYXNlKHRyYWl0KSBpbiBBdHRyaWJ1dGVUcmFpdCk7XG59XG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gdHJhaXQgaXMgYSBGYWN0b3IuXG4gKiBAcGFyYW0ge3Vua25vd259IHRyYWl0IFRoZSB0cmFpdCB0byBjaGVjay5cbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB0cmFpdCBpcyBhIEZhY3RvciwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5mdW5jdGlvbiBpc0ZhY3Rvcih0cmFpdCkge1xuICAgIHJldHVybiBCb29sZWFuKHRyYWl0ICYmIHR5cGVvZiB0cmFpdCA9PT0gXCJzdHJpbmdcIiAmJiBVLmxDYXNlKHRyYWl0KSBpbiBGYWN0b3IpO1xufVxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhIFJvbGxNb2RTdGF0dXMuXG4gKiBAcGFyYW0ge3Vua25vd259IHN0ciBUaGUgc3RyaW5nIHRvIGNoZWNrLlxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIHN0cmluZyBpcyBhIFJvbGxNb2RTdGF0dXMsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuZnVuY3Rpb24gaXNNb2RTdGF0dXMoc3RyKSB7XG4gICAgcmV0dXJuIHR5cGVvZiBzdHIgPT09IFwic3RyaW5nXCIgJiYgc3RyIGluIFJvbGxNb2RTdGF0dXM7XG59XG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc2VjdGlvbiBjYW4gY29udGFpbiBCbGFkZXNSb2xsUGFydGljaXBhbnQgZG9jdW1lbnRzLlxuICogQHBhcmFtIHtSb2xsTW9kU2VjdGlvbn0gc2VjdGlvblxuICovXG5mdW5jdGlvbiBpc1BhcnRpY2lwYW50U2VjdGlvbihzZWN0aW9uKSB7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgUm9sbE1vZFNlY3Rpb24ucm9sbCxcbiAgICAgICAgUm9sbE1vZFNlY3Rpb24ucG9zaXRpb24sXG4gICAgICAgIFJvbGxNb2RTZWN0aW9uLmVmZmVjdFxuICAgIF0uaW5jbHVkZXMoc2VjdGlvbik7XG59XG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gc3ViU2VjdGlvbiBjYW4gaG9sZCBCbGFkZXNSb2xsUGFydGljaXBhbnQgZG9jdW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHN1YlNlY3Rpb25cbiAqL1xuZnVuY3Rpb24gaXNQYXJ0aWNpcGFudFN1YlNlY3Rpb24oc3ViU2VjdGlvbikge1xuICAgIGlmIChzdWJTZWN0aW9uLnN0YXJ0c1dpdGgoXCJHcm91cF9cIikpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChbXCJBc3Npc3RcIiwgXCJTZXR1cFwiXS5pbmNsdWRlcyhzdWJTZWN0aW9uKSkge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufVxuLy8gI2VuZHJlZ2lvblxuLy8gI3JlZ2lvbiBVdGlsaXR5IEZ1bmN0aW9ucyB+XG4vLyAjZW5kcmVnaW9uXG5jbGFzcyBCbGFkZXNSb2xsTW9kIGV4dGVuZHMgQmxhZGVzVGFyZ2V0TGluayB7XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoc2NoZW1hRGF0YSkge1xuICAgICAgICAvLyBFbnN1cmUgYWxsIHByb3BlcnRpZXMgb2YgU2NoZW1hIGFyZSBwcm92aWRlZFxuICAgICAgICBpZiAoIXNjaGVtYURhdGEubmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwibmFtZSBpcyByZXF1aXJlZCBmb3IgQmxhZGVzUm9sbE1vZC5TY2hlbWFcIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGtleTogYCR7c2NoZW1hRGF0YS5uYW1lfS1wb3NpdGl2ZS1yb2xsYCxcbiAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgcG9zTmVnOiBcInBvc2l0aXZlXCIsXG4gICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5IaWRkZW4sXG4gICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgIHRvb2x0aXA6IFwiXCIsXG4gICAgICAgICAgICAuLi5zY2hlbWFEYXRhXG4gICAgICAgIH07XG4gICAgfVxuICAgIHN0YXRpYyBnZXQgR01Pbmx5TW9kU3RhdHVzZXMoKSB7XG4gICAgICAgIHJldHVybiBbUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbiwgUm9sbE1vZFN0YXR1cy5Gb3JjZWRPZmYsIFJvbGxNb2RTdGF0dXMuSGlkZGVuXTtcbiAgICB9XG4gICAgc3RhdGljIGdldFNjaGVtYUZyb21TdHJpbmdzKG1TdHJpbmdzKSB7XG4gICAgICAgIGNvbnN0IG5hbWVTdHJpbmcgPSBVLnB1bGxFbGVtZW50KG1TdHJpbmdzLCAodikgPT4gdHlwZW9mIHYgPT09IFwic3RyaW5nXCIgJiYgL15uYS9pLnRlc3QodikpO1xuICAgICAgICBjb25zdCBuYW1lVmFsID0gKHR5cGVvZiBuYW1lU3RyaW5nID09PSBcInN0cmluZ1wiICYmIG5hbWVTdHJpbmcucmVwbGFjZSgvXi4qOi8sIFwiXCIpKTtcbiAgICAgICAgaWYgKCFuYW1lVmFsKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFJvbGxNb2QgTWlzc2luZyBOYW1lOiAnJHttU3RyaW5ncy5qb2luKFwiQFwiKX0nYCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgY2F0U3RyaW5nID0gVS5wdWxsRWxlbWVudChtU3RyaW5ncywgKHYpID0+IHR5cGVvZiB2ID09PSBcInN0cmluZ1wiICYmIC9eY2F0L2kudGVzdCh2KSk7XG4gICAgICAgIGNvbnN0IGNhdFZhbCA9ICh0eXBlb2YgY2F0U3RyaW5nID09PSBcInN0cmluZ1wiICYmIGNhdFN0cmluZy5yZXBsYWNlKC9eLio6LywgXCJcIikpO1xuICAgICAgICBpZiAoIWNhdFZhbCB8fCAhKGNhdFZhbCBpbiBSb2xsTW9kU2VjdGlvbikpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgUm9sbE1vZCBNaXNzaW5nIENhdGVnb3J5OiAnJHttU3RyaW5ncy5qb2luKFwiQFwiKX0nYCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgcG9zTmVnU3RyaW5nID0gKFUucHVsbEVsZW1lbnQobVN0cmluZ3MsICh2KSA9PiB0eXBlb2YgdiA9PT0gXCJzdHJpbmdcIiAmJiAvXnAvaS50ZXN0KHYpKSB8fCBcInBvc05lZzpwb3NpdGl2ZVwiKTtcbiAgICAgICAgY29uc3QgcG9zTmVnVmFsID0gcG9zTmVnU3RyaW5nLnJlcGxhY2UoL14uKjovLCBcIlwiKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGtleTogYCR7bmFtZVZhbH0tJHtwb3NOZWdWYWx9LSR7Y2F0VmFsfWAsXG4gICAgICAgICAgICBuYW1lOiBuYW1lVmFsLFxuICAgICAgICAgICAgc2VjdGlvbjogY2F0VmFsLFxuICAgICAgICAgICAgcG9zTmVnOiBwb3NOZWdWYWwsXG4gICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmLFxuICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgIHRvb2x0aXA6IFwiXCIsXG4gICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgIC4uLk9iamVjdC5mcm9tRW50cmllcyhtU3RyaW5ncy5tYXAoZ2V0TW9kUGFyYW1ldGVyS2V5VmFsKSlcbiAgICAgICAgfTtcbiAgICAgICAgZnVuY3Rpb24gZ2V0TW9kUGFyYW1ldGVyS2V5VmFsKG1TdHJpbmcpIHtcbiAgICAgICAgICAgIGNvbnN0IFtrZXlTdHJpbmcsIHZhbFN0cmluZ10gPSBtU3RyaW5nLnNwbGl0KC86Lyk7XG4gICAgICAgICAgICBsZXQgdmFsID0gL1xcfC8udGVzdCh2YWxTdHJpbmcpID8gdmFsU3RyaW5nLnNwbGl0KC9cXHwvKSA6IHZhbFN0cmluZztcbiAgICAgICAgICAgIGxldCBrZXk7XG4gICAgICAgICAgICBpZiAoL15zdGF0L2kudGVzdChrZXlTdHJpbmcpKSB7XG4gICAgICAgICAgICAgICAga2V5ID0gXCJiYXNlX3N0YXR1c1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL152YWwvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcInZhbHVlXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICgvXmVmZnxeZWtleS9pLnRlc3Qoa2V5U3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIGtleSA9IFwiZWZmZWN0S2V5c1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL15zaWRlfF5zcy9pLnRlc3Qoa2V5U3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIGtleSA9IFwic2lkZVN0cmluZ1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL15zLiphbWUvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcInNvdXJjZV9uYW1lXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICgvXnRvb2x8XnRpcC9pLnRlc3Qoa2V5U3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIGtleSA9IFwidG9vbHRpcFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL150eS9pLnRlc3Qoa2V5U3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIGtleSA9IFwibW9kVHlwZVwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL15jLnswLDEwfXI/LnswLDN9dHkvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcImNvbmRpdGlvbmFsUm9sbFR5cGVzXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICgvXmEuezAsM31yPy57MCwzfXkvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcImF1dG9Sb2xsVHlwZXNcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKC9ecC57MCwxMH1yPy57MCwzfXkvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcInBhcnRpY2lwYW50Um9sbFR5cGVzXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICgvXmMuezAsMTB9cj8uezAsM310ci9pLnRlc3Qoa2V5U3RyaW5nKSkge1xuICAgICAgICAgICAgICAgIGtleSA9IFwiY29uZGl0aW9uYWxSb2xsVHJhaXRzXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICgvXmEuezAsM31yPy57MCwzfXRyL2kudGVzdChrZXlTdHJpbmcpKSB7XG4gICAgICAgICAgICAgICAga2V5ID0gXCJhdXRvUm9sbFRyYWl0c1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoL15wLnswLDEwfXI/LnswLDN9dHIvaS50ZXN0KGtleVN0cmluZykpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBcInBhcnRpY2lwYW50Um9sbFR5cGVzXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYEJhZCBSb2xsIE1vZCBLZXk6ICR7a2V5U3RyaW5nfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGtleSA9PT0gXCJiYXNlX3N0YXR1c1wiICYmIHZhbCA9PT0gXCJDb25kaXRpb25hbFwiKSB7XG4gICAgICAgICAgICAgICAgdmFsID0gUm9sbE1vZFN0YXR1cy5IaWRkZW47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgdmFsUHJvY2Vzc2VkO1xuICAgICAgICAgICAgaWYgKFtcInZhbHVlXCJdLmluY2x1ZGVzKGtleSkpIHtcbiAgICAgICAgICAgICAgICB2YWxQcm9jZXNzZWQgPSBVLnBJbnQodmFsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKFtcImVmZmVjdEtleXNcIiwgXCJjb25kaXRpb25hbFJvbGxUeXBlc1wiLCBcImF1dG9Sb2xsVHlwZXNcIiwgXCJjb25kaXRpb25hbFJvbGxUcmFpdHNcIiwgXCJhdXRvUm9sbFRyYWl0c1wiXS5pbmNsdWRlcyhrZXkpKSB7XG4gICAgICAgICAgICAgICAgdmFsUHJvY2Vzc2VkID0gW3ZhbF0uZmxhdCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFsUHJvY2Vzc2VkID0gdmFsLnJlcGxhY2UoLyVDT0xPTiUvZywgXCI6XCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIFtrZXksIHZhbFByb2Nlc3NlZF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgc3RhdGljIFBhcnNlRG9jTW9kc1RvU2NoZW1hU2V0KGRvYykge1xuICAgICAgICBpZiAoZG9jIGluc3RhbmNlb2YgQmxhZGVzQ2hhdCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQmxhZGVzUm9sbE1vZC5QYXJzZURvY1JvbGxNb2RzIGNhbm5vdCBiZSBjYWxsZWQgb24gYSBCbGFkZXNDaGF0IGRvY3VtZW50LlwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB7IHJvbGxfbW9kcyB9ID0gZG9jLnN5c3RlbTtcbiAgICAgICAgaWYgKCFyb2xsX21vZHMgfHwgcm9sbF9tb2RzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByb2xsX21vZHNcbiAgICAgICAgICAgIC5maWx0ZXIoKGVsZW0pID0+IEJvb2xlYW4oZWxlbSAmJiB0eXBlb2YgZWxlbSA9PT0gXCJzdHJpbmdcIikpXG4gICAgICAgICAgICAubWFwKChtb2RTdHJpbmcpID0+IHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldFNjaGVtYUZyb21TdHJpbmdzKG1vZFN0cmluZy5zcGxpdCgvQC8pKTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlzUmVyZW5kZXJpbmcgPSBmYWxzZTtcbiAgICBnZXQgc3RhdHVzKCkge1xuICAgICAgICAvLyBVU0VSIFNUQVRVUyBvZiBcIkZvcmNlZE9uXCIsIFwiRm9yY2VkT2ZmXCIsIG9yIFwiSGlkZGVuXCIgdHJ1bXBzIGFsbCBvdGhlciBzdGF0dXMgdmFsdWVzLlxuICAgICAgICBpZiAodGhpcy51c2VyU3RhdHVzICYmIEJsYWRlc1JvbGxNb2QuR01Pbmx5TW9kU3RhdHVzZXMuaW5jbHVkZXModGhpcy51c2VyU3RhdHVzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudXNlclN0YXR1cztcbiAgICAgICAgfVxuICAgICAgICAvLyBIRUxEIFNUQVRVUyBvZiBcIlRvZ2dsZWRPZmZcIiBvciBcIlRvZ2dsZWRPblwiIGNhbiBiZSBvdmVycmlkZGVuIGJ5IFVzZXIgU3RhdHVzXG4gICAgICAgIGlmICh0aGlzLmhlbGRTdGF0dXMgJiYgW1JvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZiwgUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT25dLmluY2x1ZGVzKHRoaXMuaGVsZFN0YXR1cykpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnVzZXJTdGF0dXMgPz8gdGhpcy5oZWxkU3RhdHVzO1xuICAgICAgICB9XG4gICAgICAgIC8vIE90aGVyd2lzZSwgcmV0dXJuIHRoZSBmaXJzdCBzdGF0dXMgdGhhdCBpcyBzZXQgb3V0IG9mIGhlbGQsIHVzZXIsIGFuZCBiYXNlLlxuICAgICAgICByZXR1cm4gdGhpcy5oZWxkU3RhdHVzID8/IHRoaXMudXNlclN0YXR1cyA/PyB0aGlzLmJhc2VTdGF0dXM7XG4gICAgfVxuICAgIGdldCBpc0FjdGl2ZSgpIHsgcmV0dXJuIFtSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPbiwgUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbl0uaW5jbHVkZXModGhpcy5zdGF0dXMpOyB9XG4gICAgZ2V0IGlzVmlzaWJsZSgpIHsgcmV0dXJuIHRoaXMuc3RhdHVzICE9PSBSb2xsTW9kU3RhdHVzLkhpZGRlbjsgfVxuICAgIC8vIGdldCBmbGFnUGFyYW1zKCkge1xuICAgIC8vICAgcmV0dXJuIFtDLlNZU1RFTV9JRCwgYHJvbGxDb2xsYWIucm9sbE1vZHNEYXRhLiR7dGhpcy5pZH1gXSBhcyBjb25zdDt9XG4gICAgLy8gYXN5bmMgc2V0VXNlclN0YXR1c0ZsYWcodmFsOiBSb2xsTW9kU3RhdHVzIHwgdW5kZWZpbmVkKSB7XG4gICAgLy8gfVxuICAgIGdldCBpc0NvbmRpdGlvbmFsKCkge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgLi4udGhpcy5jb25kaXRpb25hbFJvbGxUcmFpdHMsXG4gICAgICAgICAgICAuLi50aGlzLmF1dG9Sb2xsVHJhaXRzLFxuICAgICAgICAgICAgLi4udGhpcy5wYXJ0aWNpcGFudFJvbGxUcmFpdHMsXG4gICAgICAgICAgICAuLi50aGlzLmNvbmRpdGlvbmFsUm9sbFR5cGVzLFxuICAgICAgICAgICAgLi4udGhpcy5hdXRvUm9sbFR5cGVzLFxuICAgICAgICAgICAgLi4udGhpcy5wYXJ0aWNpcGFudFJvbGxUeXBlc1xuICAgICAgICBdLmxlbmd0aCA+IDA7XG4gICAgfVxuICAgIGdldCBpc0luSW5hY3RpdmVCbG9jaygpIHtcbiAgICAgICAgaWYgKGdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm4gW1JvbGxNb2RTdGF0dXMuSGlkZGVuLCBSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZiwgUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmXS5pbmNsdWRlcyh0aGlzLnN0YXR1cylcbiAgICAgICAgICAgICAgICAmJiAodGhpcy5pc0NvbmRpdGlvbmFsIHx8IHRoaXMubW9kVHlwZSA9PT0gUm9sbE1vZFR5cGUuYWJpbGl0eSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZiwgUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmXS5pbmNsdWRlcyh0aGlzLnN0YXR1cylcbiAgICAgICAgICAgICYmICh0aGlzLmlzQ29uZGl0aW9uYWwgfHwgdGhpcy5tb2RUeXBlID09PSBSb2xsTW9kVHlwZS5hYmlsaXR5KTtcbiAgICB9XG4gICAgZ2V0IGlzUHVzaCgpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4oVS5sQ2FzZSh0aGlzLm5hbWUpID09PSBcInB1c2hcIlxuICAgICAgICAgICAgfHwgdGhpcy5lZmZlY3RLZXlzLmZpbmQoKGVLZXkpID0+IGVLZXkgPT09IFwiSXMtUHVzaFwiKSk7XG4gICAgfVxuICAgIGdldCBpc0Jhc2ljUHVzaCgpIHsgcmV0dXJuIFUubENhc2UodGhpcy5uYW1lKSA9PT0gXCJwdXNoXCI7IH1cbiAgICBnZXQgc3RyZXNzQ29zdCgpIHtcbiAgICAgICAgY29uc3QgY29zdEtleXMgPSB0aGlzLmVmZmVjdEtleXMuZmlsdGVyKChrZXkpID0+IGtleS5zdGFydHNXaXRoKFwiQ29zdC1TdHJlc3NcIikpO1xuICAgICAgICBpZiAoY29zdEtleXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICBsZXQgc3RyZXNzQ29zdCA9IDA7XG4gICAgICAgIGNvc3RLZXlzLmZvckVhY2goKGtleSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgW3RoaXNQYXJhbV0gPSAoa2V5LnNwbGl0KC8tLykgPz8gW10pLnNsaWNlKDEpO1xuICAgICAgICAgICAgY29uc3QgW18sIHZhbFN0cl0gPSAoLyhbQS1aYS16XSspKFxcZCopLy5leGVjKHRoaXNQYXJhbSkgPz8gW10pLnNsaWNlKDEpO1xuICAgICAgICAgICAgc3RyZXNzQ29zdCArPSBVLnBJbnQodmFsU3RyKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBzdHJlc3NDb3N0O1xuICAgIH1cbiAgICBpc1ZhbGlkRm9yUm9sbFR5cGUoKSB7XG4gICAgICAgIHN3aXRjaCAodGhpcy5yb2xsSW5zdGFuY2Uucm9sbFR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgUm9sbFR5cGUuQWN0aW9uOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLlJlc2lzdGFuY2U6XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkZvcnR1bmU6XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkluZHVsZ2VWaWNlOiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuaXNQdXNoXG4gICAgICAgICAgICAgICAgICAgIHx8IFtcImJhcmdhaW5cIiwgXCJzZXR1cFwiLCBcImFzc2lzdFwiLCBcInBvdGVuY3lcIl0uaW5jbHVkZXMoVS5sQ2FzZSh0aGlzLm5hbWUpKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDogcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENoZWNrcyBpZiBhbnkgdHlwZXMgb3IgdHJhaXRzIGFwcGx5IHRvIHRoZSByb2xsIGluc3RhbmNlLlxuICAgICAqIEBwYXJhbSB7QW55Um9sbFR5cGVbXX0gdHlwZXMgVGhlIHR5cGVzIHRvIGNoZWNrLlxuICAgICAqIEBwYXJhbSB7Um9sbFRyYWl0W119IHRyYWl0cyBUaGUgdHJhaXRzIHRvIGNoZWNrLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiBhbnkgdHlwZXMgb3IgdHJhaXRzIGFwcGx5LCBmYWxzZSBvdGhlcndpc2UuXG4gICAgICovXG4gICAgY2hlY2tUeXBlc09yVHJhaXRzKHR5cGVzLCB0cmFpdHMpIHtcbiAgICAgICAgY29uc3Qgcm9sbFR5cGVzID0gW3RoaXMucm9sbEluc3RhbmNlLnJvbGxUeXBlLCB0aGlzLnJvbGxJbnN0YW5jZS5yb2xsU3ViVHlwZSwgdGhpcy5yb2xsSW5zdGFuY2Uucm9sbERvd250aW1lQWN0aW9uXVxuICAgICAgICAgICAgLmZpbHRlcigoclR5cGUpID0+IEJvb2xlYW4oclR5cGUpKTtcbiAgICAgICAgY29uc3QgdHlwZXNBcHBseSA9ICghdGhpcy5yb2xsSW5zdGFuY2UuaXNQYXJ0aWNpcGFudFJvbGwgJiYgdHlwZXMubGVuZ3RoID09PSAwKVxuICAgICAgICAgICAgfHwgcm9sbFR5cGVzLnNvbWUoKHJUeXBlKSA9PiB0eXBlcy5pbmNsdWRlcyhyVHlwZSkpO1xuICAgICAgICBjb25zdCB0cmFpdHNBcHBseSA9ICghdGhpcy5yb2xsSW5zdGFuY2UuaXNQYXJ0aWNpcGFudFJvbGwgJiYgdHJhaXRzLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHx8ICh0aGlzLnJvbGxJbnN0YW5jZS5yb2xsVHJhaXQgJiYgdHJhaXRzLmluY2x1ZGVzKHRoaXMucm9sbEluc3RhbmNlLnJvbGxUcmFpdCkpO1xuICAgICAgICByZXR1cm4gQm9vbGVhbih0eXBlc0FwcGx5ICYmIHRyYWl0c0FwcGx5KTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgY29uZGl0aW9uYWwgc3RhdHVzIG9mIHRoZSByb2xsIG1vZCBpbnN0YW5jZS5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBzdGF0dXMgaXMgRm9yY2VkT24gb3IgVG9nZ2xlZE9mZiwgdHJ1ZSBpZiB0aGUgc3RhdHVzIGlzIEhpZGRlbi5cbiAgICAgKi9cbiAgICBzZXRDb25kaXRpb25hbFN0YXR1cygpIHtcbiAgICAgICAgLy8gSWYgdGhlIHJvbGwgbW9kIGluc3RhbmNlIGlzIG5vdCBjb25kaXRpb25hbCwgcmV0dXJuIGZhbHNlXG4gICAgICAgIGlmICghdGhpcy5pc0NvbmRpdGlvbmFsKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgYW55IGF1dG8tVHlwZXMgYXBwbHksIHNldCBzdGF0dXMgdG8gRm9yY2VkT24gYW5kIHJldHVybiBmYWxzZVxuICAgICAgICBpZiAodGhpcy5hdXRvUm9sbFR5cGVzLmluY2x1ZGVzKHRoaXMucm9sbEluc3RhbmNlLnJvbGxUeXBlKVxuICAgICAgICAgICAgfHwgKHRoaXMucm9sbEluc3RhbmNlLnJvbGxTdWJUeXBlICYmIHRoaXMuYXV0b1JvbGxUeXBlcy5pbmNsdWRlcyh0aGlzLnJvbGxJbnN0YW5jZS5yb2xsU3ViVHlwZSkpXG4gICAgICAgICAgICB8fCAodGhpcy5yb2xsSW5zdGFuY2Uucm9sbERvd250aW1lQWN0aW9uICYmIHRoaXMuYXV0b1JvbGxUeXBlcy5pbmNsdWRlcyh0aGlzLnJvbGxJbnN0YW5jZS5yb2xsRG93bnRpbWVBY3Rpb24pKSkge1xuICAgICAgICAgICAgdGhpcy5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbjtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiBhbnkgYXV0by1UcmFpdHMgYXBwbHksIHNldCBzdGF0dXMgdG8gRm9yY2VkT24gYW5kIHJldHVybiBmYWxzZVxuICAgICAgICBpZiAodGhpcy5yb2xsSW5zdGFuY2Uucm9sbFRyYWl0ICYmIHRoaXMuYXV0b1JvbGxUcmFpdHMuaW5jbHVkZXModGhpcy5yb2xsSW5zdGFuY2Uucm9sbFRyYWl0KSkge1xuICAgICAgICAgICAgdGhpcy5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbjtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiBhbnkgY29uZGl0aW9uYWxUeXBlcyBvciBjb25kaXRpb25hbFRyYWl0cyBhcHBseSwgc2V0IHN0YXR1cyB0byBUb2dnbGVkT2ZmIGFuZCByZXR1cm4gZmFsc2VcbiAgICAgICAgaWYgKHRoaXMuY2hlY2tUeXBlc09yVHJhaXRzKHRoaXMuY29uZGl0aW9uYWxSb2xsVHlwZXMsIHRoaXMuY29uZGl0aW9uYWxSb2xsVHJhaXRzKSkge1xuICAgICAgICAgICAgdGhpcy5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmO1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIHRoaXMgaXMgYSBwYXJ0aWNpcGFudCByb2xsXG4gICAgICAgIC8vICAgQU5EIGFueSBwYXJ0aWNpcGFudFR5cGVzIG9yIHBhcnRpY2lwYW50VHJhaXRzIGFwcGx5LFxuICAgICAgICAvLyAuLi4gc2V0IHN0YXR1cyB0byBUb2dnbGVkT2ZmIGFuZCByZXR1cm4gZmFsc2VcbiAgICAgICAgaWYgKHRoaXMucm9sbEluc3RhbmNlLmlzUGFydGljaXBhbnRSb2xsXG4gICAgICAgICAgICAmJiB0aGlzLmNoZWNrVHlwZXNPclRyYWl0cyh0aGlzLnBhcnRpY2lwYW50Um9sbFR5cGVzLCB0aGlzLnBhcnRpY2lwYW50Um9sbFRyYWl0cykpIHtcbiAgICAgICAgICAgIHRoaXMuaGVsZFN0YXR1cyA9IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZjtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJZiBub25lIG9mIHRoZSBhYm92ZSBjb25kaXRpb25zIGFwcGx5LCBzZXQgc3RhdHVzIHRvIEhpZGRlbiBhbmQgcmV0dXJuIHRydWVcbiAgICAgICAgdGhpcy5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5IaWRkZW47XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBhdXRvLXJldmVhbC9lbmFibGUgc3RhdHVzIG9mIHRoZSByb2xsIG1vZCBpbnN0YW5jZS5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBzdGF0dXMgaXMgRm9yY2VkT24gb3IgVG9nZ2xlZE9mZiwgdHJ1ZSBpZiB0aGUgc3RhdHVzIGlzIEhpZGRlbi5cbiAgICAgKi9cbiAgICBzZXRBdXRvU3RhdHVzKCkge1xuICAgICAgICAvLyBDaGVjayBmb3IgQXV0b1JldmVhbE9uIGFuZCBBdXRvRW5hYmxlT25cbiAgICAgICAgY29uc3QgaG9sZEtleXMgPSB0aGlzLmVmZmVjdEtleXMuZmlsdGVyKChrZXkpID0+IGtleS5zdGFydHNXaXRoKFwiQXV0b1wiKSk7XG4gICAgICAgIGlmIChob2xkS2V5cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGNvbnN0IGtleSBvZiBob2xkS2V5cykge1xuICAgICAgICAgICAgY29uc3QgW3RoaXNLZXksIHRoaXNQYXJhbV0gPSBrZXkuc3BsaXQoLy0vKSA/PyBbXTtcbiAgICAgICAgICAgIGlmIChVLmxDYXNlKHRoaXNQYXJhbSkgaW4gUG9zaXRpb24gJiYgdGhpcy5yb2xsSW5zdGFuY2Uucm9sbFBvc2l0aW9uRmluYWwgPT09IFUubENhc2UodGhpc1BhcmFtKSkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzS2V5ID09PSBcIkF1dG9SZXZlYWxPblwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGVsZFN0YXR1cyA9IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZjtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmICh0aGlzS2V5ID09PSBcIkF1dG9FbmFibGVPblwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaGVsZFN0YXR1cyA9IFJvbGxNb2RTdGF0dXMuRm9yY2VkT247XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5IaWRkZW47XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSByZWxldmFuY3kgc3RhdHVzIG9mIHRoZSByb2xsIG1vZCBpbnN0YW5jZSAoaS5lLiBoaWRlcyBpcnJlbGV2YW50IHJvbGxNb2RzKS5cbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgbW9kIGlzIGlycmVsZXZhbnQgYW5kIHN0YXR1cyBpcyBIaWRkZW4sIGZhbHNlIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBzZXRSZWxldmFuY3lTdGF0dXMoKSB7XG4gICAgICAgIGNvbnN0IGhvbGRLZXlzID0gdGhpcy5lZmZlY3RLZXlzLmZpbHRlcigoa2V5KSA9PiAvXk5lZ2F0ZXxeSW5jcmVhc2UvLnRlc3Qoa2V5KSk7XG4gICAgICAgIGlmIChob2xkS2V5cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByZWxldmFudEtleXMgPSBob2xkS2V5c1xuICAgICAgICAgICAgLmZpbHRlcigoa2V5KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBbdGhpc0tleSwgdGhpc1BhcmFtXSA9IGtleS5zcGxpdCgvLS8pID8/IFtdO1xuICAgICAgICAgICAgaWYgKHRoaXNLZXkgPT09IFwiTmVnYXRlXCIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBuZWdhdGVPcGVyYXRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICBQdXNoQ29zdDogKCkgPT4gdGhpcy5yb2xsSW5zdGFuY2UuaXNQdXNoZWQoKSxcbiAgICAgICAgICAgICAgICAgICAgUXVhbGl0eVBlbmFsdHk6ICgpID0+IHRoaXMucm9sbEluc3RhbmNlLmlzVHJhaXRSZWxldmFudChGYWN0b3IucXVhbGl0eSlcbiAgICAgICAgICAgICAgICAgICAgICAgICYmICh0aGlzLnJvbGxJbnN0YW5jZS5yb2xsRmFjdG9ycy5zb3VyY2VbRmFjdG9yLnF1YWxpdHldPy52YWx1ZSA/PyAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwgKHRoaXMucm9sbEluc3RhbmNlLnJvbGxGYWN0b3JzLm9wcG9zaXRpb25bRmFjdG9yLnF1YWxpdHldPy52YWx1ZSA/PyAwKSxcbiAgICAgICAgICAgICAgICAgICAgU2NhbGVQZW5hbHR5OiAoKSA9PiB0aGlzLnJvbGxJbnN0YW5jZS5pc1RyYWl0UmVsZXZhbnQoRmFjdG9yLnNjYWxlKVxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgKHRoaXMucm9sbEluc3RhbmNlLnJvbGxGYWN0b3JzLnNvdXJjZVtGYWN0b3Iuc2NhbGVdPy52YWx1ZSA/PyAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIDwgKHRoaXMucm9sbEluc3RhbmNlLnJvbGxGYWN0b3JzLm9wcG9zaXRpb25bRmFjdG9yLnNjYWxlXT8udmFsdWUgPz8gMCksXG4gICAgICAgICAgICAgICAgICAgIFRpZXJQZW5hbHR5OiAoKSA9PiB0aGlzLnJvbGxJbnN0YW5jZS5pc1RyYWl0UmVsZXZhbnQoRmFjdG9yLnRpZXIpXG4gICAgICAgICAgICAgICAgICAgICAgICAmJiAodGhpcy5yb2xsSW5zdGFuY2Uucm9sbEZhY3RvcnMuc291cmNlW0ZhY3Rvci50aWVyXT8udmFsdWUgPz8gMClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA8ICh0aGlzLnJvbGxJbnN0YW5jZS5yb2xsRmFjdG9ycy5vcHBvc2l0aW9uW0ZhY3Rvci50aWVyXT8udmFsdWUgPz8gMClcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGlmIChPYmplY3QuaGFzT3duKG5lZ2F0ZU9wZXJhdGlvbnMsIHRoaXNQYXJhbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5lZ2F0ZU9wZXJhdGlvbnNbdGhpc1BhcmFtXSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQgTmVnYXRlIHBhcmFtZXRlcjogJHt0aGlzUGFyYW19YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodGhpc0tleSA9PT0gXCJJbmNyZWFzZVwiKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgW18sIHRyYWl0U3RyXSA9IC8oXFx3KylcXGQrLy5leGVjKHRoaXNQYXJhbSkgPz8gW107XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucm9sbEluc3RhbmNlLmlzVHJhaXRSZWxldmFudCh0cmFpdFN0cik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVucmVjb2duaXplZCBGdW5jdGlvbiBLZXk6ICR7dGhpc0tleX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChyZWxldmFudEtleXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLmhlbGRTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkhpZGRlbjtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgcGF5YWJsZSBzdGF0dXMgb2YgdGhlIHJvbGwgbW9kIGluc3RhbmNlIChpLmUuIGZvcmNlcyBvZmYgcm9sbE1vZHMgdGhlIHByaW1hcnkgY2FuJ3QgcGF5IGZvcikuXG4gICAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIG1vZCBpcyB1bnBheWFibGUgYW5kIHN0YXR1cyBpcyBGb3JjZWRPZmYsIGZhbHNlIG90aGVyd2lzZS5cbiAgICAgKi9cbiAgICBzZXRQYXlhYmxlU3RhdHVzKCkge1xuICAgICAgICBjb25zdCBob2xkS2V5cyA9IHRoaXMuZWZmZWN0S2V5cy5maWx0ZXIoKGtleSkgPT4ga2V5LnN0YXJ0c1dpdGgoXCJDb3N0XCIpKTtcbiAgICAgICAgaWYgKGhvbGRLZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHBheWFibGVLZXlzID0gaG9sZEtleXNcbiAgICAgICAgICAgIC5maWx0ZXIoKGtleSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgW3RoaXNQYXJhbV0gPSAoa2V5LnNwbGl0KC8tLykgPz8gW10pLnNsaWNlKDEpO1xuICAgICAgICAgICAgY29uc3QgW3RyYWl0U3RyLCB2YWxTdHJdID0gKC8oW0EtWmEtel0rKShcXGQqKS8uZXhlYyh0aGlzUGFyYW0pID8/IFtdKS5zbGljZSgxKTtcbiAgICAgICAgICAgIGNvbnN0IHsgcm9sbFByaW1hcnlEb2MgfSA9IHRoaXMucm9sbEluc3RhbmNlLnJvbGxQcmltYXJ5ID8/IHt9O1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhyb2xsUHJpbWFyeURvYykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzd2l0Y2ggKHRyYWl0U3RyKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBcIlNwZWNpYWxBcm1vclwiOiB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNBY3Rvci5Jc1R5cGUocm9sbFByaW1hcnlEb2MsIEJsYWRlc0FjdG9yVHlwZS5wYylcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIHJvbGxQcmltYXJ5RG9jLnN5c3RlbS5hcm1vci5hY3RpdmUuc3BlY2lhbFxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgIXJvbGxQcmltYXJ5RG9jLnN5c3RlbS5hcm1vci5jaGVja2VkLnNwZWNpYWw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgXCJTdHJlc3NcIjoge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB2YWwgPSBVLnBJbnQodmFsU3RyKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIEJsYWRlc0FjdG9yLklzVHlwZShyb2xsUHJpbWFyeURvYywgQmxhZGVzQWN0b3JUeXBlLnBjKVxuICAgICAgICAgICAgICAgICAgICAgICAgJiYgcm9sbFByaW1hcnlEb2Muc3lzdGVtLnN0cmVzcy5tYXggLSByb2xsUHJpbWFyeURvYy5zeXN0ZW0uc3RyZXNzLnZhbHVlID49IHZhbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FzZSBcIkhlYXRcIjoge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gKEJsYWRlc1BDLklzVHlwZShyb2xsUHJpbWFyeURvYykgJiYgQmxhZGVzQ3Jldy5Jc1R5cGUocm9sbFByaW1hcnlEb2MuY3JldykpXG4gICAgICAgICAgICAgICAgICAgICAgICB8fCBCbGFkZXNDcmV3LklzVHlwZShyb2xsUHJpbWFyeURvYyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvcihgVW5yZWNvZ25pemUgUGF5YWJsZSBLZXk6ICR7dHJhaXRTdHJ9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBpZiAocGF5YWJsZUtleXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLmhlbGRTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZjtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgYXBwbHlSb2xsTW9kRWZmZWN0S2V5cygpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgaG9sZEtleVBhcmFtcyA9IHRoaXMuZWZmZWN0S2V5c1xuICAgICAgICAgICAgLmZpbHRlcigoa2V5KSA9PiAvXk5lZ2F0ZXxeSW5jcmVhc2UvLnRlc3Qoa2V5KSlcbiAgICAgICAgICAgIC5tYXAoKGtleSkgPT4ga2V5LnNwbGl0KC8tLykpO1xuICAgICAgICBpZiAoaG9sZEtleVBhcmFtcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBob2xkS2V5UGFyYW1zLmZvckVhY2goKFtrZXksIHBhcmFtXSkgPT4ge1xuICAgICAgICAgICAgaWYgKGtleSA9PT0gXCJOZWdhdGVcIikge1xuICAgICAgICAgICAgICAgIGNvbnN0IG5lZ2F0ZU9wZXJhdGlvbnMgPSB7XG4gICAgICAgICAgICAgICAgICAgIFB1c2hDb3N0OiAoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGxJbnN0YW5jZS5uZWdhdGVQdXNoQ29zdCgpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBRdWFsaXR5UGVuYWx0eTogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UubmVnYXRlRmFjdG9yUGVuYWx0eShGYWN0b3IucXVhbGl0eSk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIFNjYWxlUGVuYWx0eTogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UubmVnYXRlRmFjdG9yUGVuYWx0eShGYWN0b3Iuc2NhbGUpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBUaWVyUGVuYWx0eTogKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UubmVnYXRlRmFjdG9yUGVuYWx0eShGYWN0b3IudGllcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGlmIChPYmplY3QuaGFzT3duKG5lZ2F0ZU9wZXJhdGlvbnMsIHBhcmFtKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmVnYXRlT3BlcmF0aW9uc1twYXJhbV0oKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5yZWNvZ25pemVkIE5lZ2F0ZSBwYXJhbWV0ZXI6ICR7cGFyYW19YCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoa2V5ID09PSBcIkluY3JlYXNlXCIpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBbXywgdHJhaXRTdHJdID0gLyhcXHcrKVxcZCsvLmV4ZWMocGFyYW0pID8/IFtdO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnJvbGxJbnN0YW5jZS5pc1RyYWl0UmVsZXZhbnQodHJhaXRTdHIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQgRnVuY3Rpb24gS2V5OiAke2tleX0gKGtleTogJHtrZXl9KWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0IHNlbGVjdE9wdGlvbnMoKSB7XG4gICAgICAgIGlmICh0aGlzLm1vZFR5cGUgIT09IFJvbGxNb2RUeXBlLnRlYW13b3JrKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5uYW1lID09PSBcIkFzc2lzdFwiIHx8IHRoaXMubmFtZSA9PT0gXCJTZXR1cFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsSW5zdGFuY2Uucm9sbFBhcnRpY2lwYW50U2VsZWN0T3B0aW9uc1t0aGlzLm5hbWVdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMubmFtZS5zdGFydHNXaXRoKFwiR3JvdXBfXCIpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsSW5zdGFuY2Uucm9sbFBhcnRpY2lwYW50U2VsZWN0T3B0aW9ucy5Hcm91cDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbnVsbDtcbiAgICB9XG4gICAgZ2V0IHNlbGVjdGVkUGFydGljaXBhbnQoKSB7XG4gICAgICAgIGlmICh0aGlzLm1vZFR5cGUgIT09IFJvbGxNb2RUeXBlLnRlYW13b3JrKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5yb2xsSW5zdGFuY2UuZ2V0Um9sbFBhcnRpY2lwYW50KHRoaXMuc2VjdGlvbiwgdGhpcy5uYW1lKTtcbiAgICB9XG4gICAgZ2V0IGFsbEZsYWdEYXRhKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yb2xsSW5zdGFuY2UuZGF0YTtcbiAgICB9XG4gICAgZ2V0IGNvc3RzKCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgaG9sZEtleXMgPSB0aGlzLmVmZmVjdEtleXMuZmlsdGVyKChrZXkpID0+IGtleS5zdGFydHNXaXRoKFwiQ29zdFwiKSk7XG4gICAgICAgIGlmIChob2xkS2V5cy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGhvbGRLZXlzLm1hcCgoa2V5KSA9PiB7XG4gICAgICAgICAgICBjb25zdCBbdGhpc1BhcmFtXSA9IChrZXkuc3BsaXQoLy0vKSA/PyBbXSkuc2xpY2UoMSk7XG4gICAgICAgICAgICBjb25zdCBbdHJhaXRTdHIsIHZhbFN0cl0gPSAoLyhbQS1aYS16XSspKFxcZCopLy5leGVjKHRoaXNQYXJhbSkgPz8gW10pLnNsaWNlKDEpO1xuICAgICAgICAgICAgbGV0IGxhYmVsID0gdGhpcy5uYW1lO1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNCYXNpY1B1c2gpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5wb3NOZWcgPT09IFwibmVnYXRpdmVcIikge1xuICAgICAgICAgICAgICAgICAgICBsYWJlbCA9IGAke3RoaXMubmFtZX0gKDxzcGFuIGNsYXNzPSdyZWQtYnJpZ2h0Jz5UbyBBY3Q8L3NwYW4+KWA7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBlZmZlY3QgPSB0aGlzLnNlY3Rpb24gPT09IFJvbGxNb2RTZWN0aW9uLnJvbGwgPyBcIisxZFwiIDogXCIrMSBlZmZlY3RcIjtcbiAgICAgICAgICAgICAgICAgICAgbGFiZWwgPSBgJHt0aGlzLm5hbWV9ICg8c3BhbiBjbGFzcz0nZ29sZC1icmlnaHQnPiR7ZWZmZWN0fTwvc3Bhbj4pYDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICAgICAgICAgIGxhYmVsLFxuICAgICAgICAgICAgICAgIGNvc3RUeXBlOiB0cmFpdFN0cixcbiAgICAgICAgICAgICAgICBjb3N0QW1vdW50OiB2YWxTdHIgPyBVLnBJbnQodmFsU3RyKSA6IDFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBfcm9sbEluc3RhbmNlO1xuICAgIGNvbnN0cnVjdG9yKG1vZERhdGEsIHJvbGxJbnN0YW5jZSkge1xuICAgICAgICBzdXBlcihtb2REYXRhKTtcbiAgICAgICAgdGhpcy5fcm9sbEluc3RhbmNlID0gcm9sbEluc3RhbmNlO1xuICAgIH1cbiAgICBnZXQgcm9sbEluc3RhbmNlKCkgeyByZXR1cm4gdGhpcy5fcm9sbEluc3RhbmNlOyB9XG4gICAgZ2V0IG5hbWUoKSB7IHJldHVybiB0aGlzLmRhdGEubmFtZTsgfVxuICAgIGdldCBtb2RUeXBlKCkgeyByZXR1cm4gdGhpcy5kYXRhLm1vZFR5cGU7IH1cbiAgICBnZXQgc291cmNlTmFtZSgpIHsgcmV0dXJuIHRoaXMuZGF0YS5zb3VyY2VfbmFtZSA/PyB0aGlzLmRhdGEubmFtZTsgfVxuICAgIGdldCBzZWN0aW9uKCkgeyByZXR1cm4gdGhpcy5kYXRhLnNlY3Rpb247IH1cbiAgICBnZXQgcG9zTmVnKCkgeyByZXR1cm4gdGhpcy5kYXRhLnBvc05lZzsgfVxuICAgIGdldCB1c2VyU3RhdHVzKCkgeyByZXR1cm4gdGhpcy5kYXRhLnVzZXJfc3RhdHVzOyB9XG4gICAgc2V0IHVzZXJTdGF0dXModmFsKSB7XG4gICAgICAgIGlmICh2YWwgPT09IHRoaXMudXNlclN0YXR1cykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgaXNSZXJlbmRlcmluZyB9ID0gdGhpcztcbiAgICAgICAgaWYgKCF2YWwgfHwgdmFsID09PSB0aGlzLmJhc2VTdGF0dXMpIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwidXNlcl9zdGF0dXNcIiwgbnVsbClcbiAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKGlzUmVyZW5kZXJpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UucmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNXG4gICAgICAgICAgICAgICAgJiYgKEJsYWRlc1JvbGxNb2QuR01Pbmx5TW9kU3RhdHVzZXMuaW5jbHVkZXModmFsKVxuICAgICAgICAgICAgICAgICAgICB8fCAodGhpcy51c2VyU3RhdHVzICYmIEJsYWRlc1JvbGxNb2QuR01Pbmx5TW9kU3RhdHVzZXMuaW5jbHVkZXModGhpcy51c2VyU3RhdHVzKSkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJ1c2VyX3N0YXR1c1wiLCB2YWwpXG4gICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChpc1JlcmVuZGVyaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucm9sbEluc3RhbmNlLnJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldCBiYXNlU3RhdHVzKCkgeyByZXR1cm4gdGhpcy5kYXRhLmJhc2Vfc3RhdHVzOyB9XG4gICAgZ2V0IGhlbGRTdGF0dXMoKSB7IHJldHVybiB0aGlzLmRhdGEuaGVsZF9zdGF0dXM7IH1cbiAgICBzZXQgaGVsZFN0YXR1cyh2YWwpIHtcbiAgICAgICAgaWYgKHZhbCA9PT0gdGhpcy5oZWxkU3RhdHVzKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyBpc1JlcmVuZGVyaW5nIH0gPSB0aGlzO1xuICAgICAgICBpZiAoIXZhbCkge1xuICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJoZWxkX3N0YXR1c1wiLCBudWxsKVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaXNSZXJlbmRlcmluZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGxJbnN0YW5jZS5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldENhbGwoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwiaGVsZF9zdGF0dXNcIiwgdmFsKVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHtcbiAgICAgICAgICAgICAgICBpZiAoaXNSZXJlbmRlcmluZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGxJbnN0YW5jZS5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldENhbGwoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXQgdmFsdWUoKSB7IHJldHVybiB0aGlzLmRhdGEudmFsdWU7IH1cbiAgICBnZXQgZWZmZWN0S2V5cygpIHsgcmV0dXJuIHRoaXMuZGF0YS5lZmZlY3RLZXlzID8/IFtdOyB9XG4gICAgZ2V0IHNpZGVTdHJpbmcoKSB7XG4gICAgICAgIGlmICh0aGlzLmRhdGEuc2lkZVN0cmluZykge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5zaWRlU3RyaW5nO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnNlbGVjdGVkUGFydGljaXBhbnQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbGVjdGVkUGFydGljaXBhbnQucm9sbFBhcnRpY2lwYW50TmFtZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICBnZXQgdG9vbHRpcCgpIHtcbiAgICAgICAgbGV0IHBhcnNlZFRvb2x0aXAgPSB0aGlzLmRhdGEudG9vbHRpcC5yZXBsYWNlKC8lQ09MT04lL2csIFwiOlwiKTtcbiAgICAgICAgaWYgKHBhcnNlZFRvb2x0aXAuaW5jbHVkZXMoXCIlRE9DX05BTUUlXCIpKSB7XG4gICAgICAgICAgICBwYXJzZWRUb29sdGlwID0gcGFyc2VkVG9vbHRpcC5yZXBsYWNlKC8lRE9DX05BTUUlL2csIHRoaXMuc2VsZWN0ZWRQYXJ0aWNpcGFudFxuICAgICAgICAgICAgICAgID8gdGhpcy5zZWxlY3RlZFBhcnRpY2lwYW50LnJvbGxQYXJ0aWNpcGFudE5hbWVcbiAgICAgICAgICAgICAgICA6IFwiYW4gQWxseVwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocGFyc2VkVG9vbHRpcC5pbmNsdWRlcyhcIkBPUFBPU0lUSU9OX05BTUVAXCIpKSB7XG4gICAgICAgICAgICBwYXJzZWRUb29sdGlwID0gcGFyc2VkVG9vbHRpcC5yZXBsYWNlKC9AT1BQT1NJVElPTl9OQU1FQC9nLCB0aGlzLnJvbGxJbnN0YW5jZS5yb2xsT3Bwb3NpdGlvblxuICAgICAgICAgICAgICAgID8gdGhpcy5yb2xsSW5zdGFuY2Uucm9sbE9wcG9zaXRpb24ucm9sbE9wcE5hbWVcbiAgICAgICAgICAgICAgICA6IFwiWW91ciBPcHBvc2l0aW9uXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBwYXJzZWRUb29sdGlwO1xuICAgIH1cbiAgICBnZXQgY29uZGl0aW9uYWxSb2xsVHlwZXMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGEuY29uZGl0aW9uYWxSb2xsVHlwZXMgPz8gW107XG4gICAgfVxuICAgIGdldCBhdXRvUm9sbFR5cGVzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRhLmF1dG9Sb2xsVHlwZXMgPz8gW107XG4gICAgfVxuICAgIGdldCBwYXJ0aWNpcGFudFJvbGxUeXBlcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5wYXJ0aWNpcGFudFJvbGxUeXBlcyA/PyBbXTtcbiAgICB9XG4gICAgZ2V0IGNvbmRpdGlvbmFsUm9sbFRyYWl0cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5jb25kaXRpb25hbFJvbGxUcmFpdHMgPz8gW107XG4gICAgfVxuICAgIGdldCBhdXRvUm9sbFRyYWl0cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5hdXRvUm9sbFRyYWl0cyA/PyBbXTtcbiAgICB9XG4gICAgZ2V0IHBhcnRpY2lwYW50Um9sbFRyYWl0cygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5wYXJ0aWNpcGFudFJvbGxUcmFpdHMgPz8gW107XG4gICAgfVxufVxuY2xhc3MgQmxhZGVzUm9sbFByaW1hcnkge1xuICAgIC8vICNyZWdpb24gU3RhdGljIE1ldGhvZHMgflxuICAgIHN0YXRpYyBJc1ZhbGlkRGF0YShkYXRhKSB7XG4gICAgICAgIGlmIChCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhkYXRhKSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBVLmlzTGlzdChkYXRhKVxuICAgICAgICAgICAgJiYgdHlwZW9mIGRhdGEucm9sbFByaW1hcnlOYW1lID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAmJiB0eXBlb2YgZGF0YS5yb2xsUHJpbWFyeVR5cGUgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBkYXRhLnJvbGxQcmltYXJ5SW1nID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAmJiBBcnJheS5pc0FycmF5KGRhdGEucm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0KVxuICAgICAgICAgICAgJiYgVS5pc0xpc3QoZGF0YS5yb2xsRmFjdG9ycylcbiAgICAgICAgICAgICYmICghZGF0YS5yb2xsUHJpbWFyeUlEIHx8IHR5cGVvZiBkYXRhLnJvbGxQcmltYXJ5SUQgPT09IFwic3RyaW5nXCIpXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbFByaW1hcnlEb2MgfHwgQmxhZGVzUm9sbFByaW1hcnkuSXNEb2MoZGF0YS5yb2xsUHJpbWFyeURvYykpO1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RG9jKGRvY1JlZikge1xuICAgICAgICBsZXQgZG9jID0gZG9jUmVmO1xuICAgICAgICBpZiAodHlwZW9mIGRvY1JlZiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZG9jID0gZ2FtZS5hY3RvcnMuZ2V0KGRvY1JlZilcbiAgICAgICAgICAgICAgICA/PyBnYW1lLml0ZW1zLmdldChkb2NSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5hY3RvcnMuZ2V0TmFtZShkb2NSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5pdGVtcy5nZXROYW1lKGRvY1JlZik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIEJsYWRlc1JvbGxQcmltYXJ5LklzRG9jKGRvYykgJiYgZG9jO1xuICAgIH1cbiAgICBzdGF0aWMgSXNEb2MoZG9jKSB7XG4gICAgICAgIHJldHVybiBCbGFkZXNBY3Rvci5Jc1R5cGUoZG9jLCBCbGFkZXNBY3RvclR5cGUucGMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KVxuICAgICAgICAgICAgfHwgQmxhZGVzSXRlbS5Jc1R5cGUoZG9jLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZXhwZXJ0LCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuZ21fdHJhY2tlcik7XG4gICAgfVxuICAgIHN0YXRpYyBHZXREYXRhRnJvbURvYyhkb2MpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5SUQ6IGRvYy5pZCxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5TmFtZTogZG9jLm5hbWUsXG4gICAgICAgICAgICByb2xsUHJpbWFyeVR5cGU6IGRvYy50eXBlLFxuICAgICAgICAgICAgcm9sbFByaW1hcnlJbWc6IGRvYy5pbWcsXG4gICAgICAgICAgICByb2xsUHJpbWFyeU1vZHNTY2hlbWFTZXQ6IGRvYy5yb2xsUHJpbWFyeU1vZHNTY2hlbWFTZXQsXG4gICAgICAgICAgICByb2xsRmFjdG9yczogZG9jLnJvbGxGYWN0b3JzXG4gICAgICAgIH07XG4gICAgfVxuICAgIHN0YXRpYyBCdWlsZERhdGEoY29uZmlnKSB7XG4gICAgICAgIGlmIChCbGFkZXNSb2xsUHJpbWFyeS5Jc1ZhbGlkRGF0YShjb25maWcucm9sbFByaW1hcnlEYXRhKSkge1xuICAgICAgICAgICAgcmV0dXJuIGNvbmZpZy5yb2xsUHJpbWFyeURhdGE7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IHJvbGxQcmltYXJ5O1xuICAgICAgICBjb25zdCByb2xsVXNlciA9IGdhbWUudXNlcnMuZ2V0KGNvbmZpZy5yb2xsVXNlcklEID8/IGdhbWUudXNlci5pZCk7XG4gICAgICAgIGlmIChcInRhcmdldFwiIGluIGNvbmZpZyAmJiBCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhjb25maWcudGFyZ2V0KSkge1xuICAgICAgICAgICAgcm9sbFByaW1hcnkgPSBjb25maWcudGFyZ2V0O1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHJvbGxVc2VyICYmIEJsYWRlc1JvbGxQcmltYXJ5LklzRG9jKHJvbGxVc2VyLmNoYXJhY3RlcikpIHtcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5ID0gcm9sbFVzZXIuY2hhcmFjdGVyO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1JvbGxQcmltYXJ5LkJ1aWxkRGF0YSgpXSBBIHZhbGlkIHNvdXJjZSBvZiBQcmltYXJ5RGF0YSBtdXN0IGJlIHByb3ZpZGVkIHRvIGNvbnN0cnVjdCBhIHJvbGwuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICByb2xsUHJpbWFyeUlEOiByb2xsUHJpbWFyeS5yb2xsUHJpbWFyeUlELFxuICAgICAgICAgICAgcm9sbFByaW1hcnlOYW1lOiByb2xsUHJpbWFyeS5yb2xsUHJpbWFyeU5hbWUsXG4gICAgICAgICAgICByb2xsUHJpbWFyeVR5cGU6IHJvbGxQcmltYXJ5LnJvbGxQcmltYXJ5VHlwZSxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5SW1nOiByb2xsUHJpbWFyeS5yb2xsUHJpbWFyeUltZyxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldDogcm9sbFByaW1hcnkucm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0LFxuICAgICAgICAgICAgcm9sbEZhY3RvcnM6IHJvbGxQcmltYXJ5LnJvbGxGYWN0b3JzXG4gICAgICAgIH07XG4gICAgfVxuICAgIHN0YXRpYyBCdWlsZChjb25maWcpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBCbGFkZXNSb2xsUHJpbWFyeSh0aGlzLkJ1aWxkRGF0YShjb25maWcpKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIHJvbGxJbnN0YW5jZTtcbiAgICByb2xsUHJpbWFyeUlEO1xuICAgIF9yb2xsUHJpbWFyeURvYztcbiAgICBnZXQgcm9sbFByaW1hcnlEb2MoKSB7XG4gICAgICAgIGlmICghdGhpcy5fcm9sbFByaW1hcnlEb2MpIHtcbiAgICAgICAgICAgIGxldCBkb2M7XG4gICAgICAgICAgICBpZiAodGhpcy5yb2xsUHJpbWFyeUlEKSB7XG4gICAgICAgICAgICAgICAgZG9jID0gZ2FtZS5pdGVtcy5nZXQodGhpcy5yb2xsUHJpbWFyeUlEKVxuICAgICAgICAgICAgICAgICAgICA/PyBnYW1lLmFjdG9ycy5nZXQodGhpcy5yb2xsUHJpbWFyeUlEKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghZG9jICYmIHRoaXMucm9sbFByaW1hcnlOYW1lKSB7XG4gICAgICAgICAgICAgICAgZG9jID0gZ2FtZS5pdGVtcy5nZXROYW1lKHRoaXMucm9sbFByaW1hcnlOYW1lKVxuICAgICAgICAgICAgICAgICAgICA/PyBnYW1lLmFjdG9ycy5nZXROYW1lKHRoaXMucm9sbFByaW1hcnlOYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhkb2MpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fcm9sbFByaW1hcnlEb2MgPSBkb2M7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX3JvbGxQcmltYXJ5RG9jO1xuICAgIH1cbiAgICByb2xsUHJpbWFyeU5hbWU7XG4gICAgcm9sbFByaW1hcnlUeXBlO1xuICAgIHJvbGxQcmltYXJ5SW1nO1xuICAgIHJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldDtcbiAgICByb2xsRmFjdG9ycztcbiAgICBnZXQgZGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5SUQ6IHRoaXMucm9sbFByaW1hcnlJRCxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5TmFtZTogdGhpcy5yb2xsUHJpbWFyeU5hbWUsXG4gICAgICAgICAgICByb2xsUHJpbWFyeVR5cGU6IHRoaXMucm9sbFByaW1hcnlUeXBlLFxuICAgICAgICAgICAgcm9sbFByaW1hcnlJbWc6IHRoaXMucm9sbFByaW1hcnlJbWcsXG4gICAgICAgICAgICByb2xsUHJpbWFyeU1vZHNTY2hlbWFTZXQ6IHRoaXMucm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0LFxuICAgICAgICAgICAgcm9sbEZhY3RvcnM6IHRoaXMucm9sbEZhY3RvcnNcbiAgICAgICAgfTtcbiAgICB9XG4gICAgZ2V0IGlzV29yc2VQb3NpdGlvbigpIHtcbiAgICAgICAgaWYgKHRoaXMucm9sbFByaW1hcnlEb2MpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJvbGxQcmltYXJ5RG9jLmdldEZsYWcoXCJldW5vcy1ibGFkZXNcIiwgXCJpc1dvcnNlUG9zaXRpb25cIikgPT09IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBhc3luYyBhcHBseUhhcm0oYW1vdW50LCBuYW1lKSB7XG4gICAgICAgIGlmICh0aGlzLnJvbGxQcmltYXJ5RG9jKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsUHJpbWFyeURvYy5hcHBseUhhcm0oYW1vdW50LCBuYW1lKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBhcHBseVdvcnNlUG9zaXRpb24oKSB7XG4gICAgICAgIGlmICh0aGlzLnJvbGxQcmltYXJ5RG9jKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsUHJpbWFyeURvYy5hcHBseVdvcnNlUG9zaXRpb24oKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBnZXQgaGFzU3BlY2lhbEFybW9yKCkge1xuICAgICAgICByZXR1cm4gQmxhZGVzUEMuSXNUeXBlKHRoaXMucm9sbFByaW1hcnlEb2MpICYmIHRoaXMucm9sbFByaW1hcnlEb2MuaXNTcGVjaWFsQXJtb3JBdmFpbGFibGU7XG4gICAgfVxuICAgIGdldCBhdmFpbGFibGVBcm1vckNvdW50KCkge1xuICAgICAgICBpZiAoQmxhZGVzUEMuSXNUeXBlKHRoaXMucm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsUHJpbWFyeURvYy5hdmFpbGFibGVBcm1vci5sZW5ndGg7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5yb2xsUHJpbWFyeURvYywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5yb2xsUHJpbWFyeURvYy5zeXN0ZW0uYXJtb3IubWF4IC0gdGhpcy5yb2xsUHJpbWFyeURvYy5zeXN0ZW0uYXJtb3IudmFsdWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIGFzeW5jIHNwZW5kQXJtb3IoY291bnQpIHtcbiAgICAgICAgaWYgKCF0aGlzLnJvbGxQcmltYXJ5RG9jKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzUm9sbFByaW1hcnkuc3BlbmRBcm1vcigpXSBDYW5ub3Qgc3BlbmQgYXJtb3Igd2hlbiByb2xsUHJpbWFyeURvYyBpcyBub3QgZGVmaW5lZC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvdW50ID4gdGhpcy5hdmFpbGFibGVBcm1vckNvdW50KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNSb2xsUHJpbWFyeS5zcGVuZEFybW9yKCldIENhbm5vdCBzcGVuZCBtb3JlIGFybW9yICgke2NvdW50fSkgdGhhbiAke3RoaXMucm9sbFByaW1hcnlEb2M/Lm5hbWV9IGhhcyAoJHt0aGlzLmF2YWlsYWJsZUFybW9yQ291bnR9KS5gKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzUEMuSXNUeXBlKHRoaXMucm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICBjb25zdCBhcm1vclRvU3BlbmQgPSB0aGlzLnJvbGxQcmltYXJ5RG9jLmF2YWlsYWJsZUFybW9yLnNsaWNlKDAsIGNvdW50KTtcbiAgICAgICAgICAgIGNvbnN0IHVwZGF0ZURhdGEgPSB7fTtcbiAgICAgICAgICAgIGlmIChhcm1vclRvU3BlbmQuaW5jbHVkZXMoXCJMaWdodCBBcm1vclwiKSkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZURhdGFbXCJzeXN0ZW0uYXJtb3IuYWN0aXZlLmxpZ2h0XCJdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB1cGRhdGVEYXRhW1wic3lzdGVtLmFybW9yLmNoZWNrZWQubGlnaHRcIl0gPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGFybW9yVG9TcGVuZC5pbmNsdWRlcyhcIkhlYXZ5IEFybW9yXCIpKSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtcInN5c3RlbS5hcm1vci5hY3RpdmUuaGVhdnlcIl0gPSB0cnVlO1xuICAgICAgICAgICAgICAgIHVwZGF0ZURhdGFbXCJzeXN0ZW0uYXJtb3IuY2hlY2tlZC5oZWF2eVwiXSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnJvbGxQcmltYXJ5RG9jLnVwZGF0ZSh1cGRhdGVEYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChCbGFkZXNJdGVtLklzVHlwZSh0aGlzLnJvbGxQcmltYXJ5RG9jLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCkpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMucm9sbFByaW1hcnlEb2MudXBkYXRlKHsgXCJzeXN0ZW0uYXJtb3IudmFsdWVcIjogdGhpcy5yb2xsUHJpbWFyeURvYy5zeXN0ZW0uYXJtb3IudmFsdWUgKyBjb3VudCB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdHJ1Y3RvciguLi5hcmdzKSB7XG4gICAgICAgIGxldCBwcmltYXJ5RGF0YSA9IGZhbHNlO1xuICAgICAgICBsZXQgcHJpbWFyeURvYyA9IGZhbHNlO1xuICAgICAgICBpZiAoYXJnc1swXSBpbnN0YW5jZW9mIEJsYWRlc1JvbGwpIHtcbiAgICAgICAgICAgIHRoaXMucm9sbEluc3RhbmNlID0gYXJnc1swXTtcbiAgICAgICAgICAgIGFyZ3Muc2hpZnQoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzUm9sbFByaW1hcnkuSXNEb2MoYXJnc1swXSkpIHtcbiAgICAgICAgICAgIHByaW1hcnlEb2MgPSBhcmdzWzBdO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEJsYWRlc1JvbGxQcmltYXJ5LklzVmFsaWREYXRhKGFyZ3NbMF0pKSB7XG4gICAgICAgICAgICBwcmltYXJ5RGF0YSA9IGFyZ3NbMF07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoVS5pc0xpc3QoYXJnc1swXSkpIHtcbiAgICAgICAgICAgIGlmIChcInJvbGxQcmltYXJ5SURcIiBpbiBhcmdzWzBdKSB7XG4gICAgICAgICAgICAgICAgcHJpbWFyeURvYyA9IEJsYWRlc1JvbGxQcmltYXJ5LkdldERvYyhhcmdzWzBdLnJvbGxQcmltYXJ5SUQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoXCJyb2xsUHJpbWFyeU5hbWVcIiBpbiBhcmdzWzBdKSB7XG4gICAgICAgICAgICAgICAgcHJpbWFyeURvYyA9IEJsYWRlc1JvbGxQcmltYXJ5LkdldERvYyhhcmdzWzBdLnJvbGxQcmltYXJ5TmFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHByaW1hcnlEb2MgJiYgIUJsYWRlc1JvbGxQcmltYXJ5LklzVmFsaWREYXRhKHByaW1hcnlEYXRhKSkge1xuICAgICAgICAgICAgcHJpbWFyeURhdGEgPSB7XG4gICAgICAgICAgICAgICAgcm9sbFByaW1hcnlJRDogcHJpbWFyeURvYy5yb2xsUHJpbWFyeUlELFxuICAgICAgICAgICAgICAgIHJvbGxQcmltYXJ5TmFtZTogcHJpbWFyeURvYy5yb2xsUHJpbWFyeU5hbWUsXG4gICAgICAgICAgICAgICAgcm9sbFByaW1hcnlUeXBlOiBwcmltYXJ5RG9jLnJvbGxQcmltYXJ5VHlwZSxcbiAgICAgICAgICAgICAgICByb2xsUHJpbWFyeUltZzogcHJpbWFyeURvYy5yb2xsUHJpbWFyeUltZyxcbiAgICAgICAgICAgICAgICByb2xsUHJpbWFyeU1vZHNTY2hlbWFTZXQ6IHByaW1hcnlEb2Mucm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0LFxuICAgICAgICAgICAgICAgIHJvbGxGYWN0b3JzOiBwcmltYXJ5RG9jLnJvbGxGYWN0b3JzXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICghQmxhZGVzUm9sbFByaW1hcnkuSXNWYWxpZERhdGEocHJpbWFyeURhdGEpICYmICFCbGFkZXNSb2xsUHJpbWFyeS5Jc0RvYyhwcmltYXJ5RG9jKSAmJiB0aGlzLnJvbGxJbnN0YW5jZSkge1xuICAgICAgICAgICAgcHJpbWFyeURhdGEgPSB0aGlzLnJvbGxJbnN0YW5jZS5yb2xsUHJpbWFyeS5kYXRhO1xuICAgICAgICB9XG4gICAgICAgIGlmICghQmxhZGVzUm9sbFByaW1hcnkuSXNWYWxpZERhdGEocHJpbWFyeURhdGEpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNSb2xsLmNvbnN0cnVjdG9yXSBGYWlsZWQgdG8gcmVzb2x2ZSBwcmltYXJ5IGRhdGEgZnJvbSBwcm92aWRlZCBhcmd1bWVudHM6ICR7SlNPTi5zdHJpbmdpZnkoYXJncyl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgeyByb2xsUHJpbWFyeUlELCByb2xsUHJpbWFyeU5hbWUsIHJvbGxQcmltYXJ5VHlwZSwgcm9sbFByaW1hcnlJbWcsIHJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldCwgcm9sbEZhY3RvcnMgfSA9IHByaW1hcnlEYXRhO1xuICAgICAgICB0aGlzLnJvbGxQcmltYXJ5SUQgPSByb2xsUHJpbWFyeUlEO1xuICAgICAgICBpZiAoIXJvbGxQcmltYXJ5TmFtZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBpbmNsdWRlIGEgcm9sbFByaW1hcnlOYW1lIHdoZW4gY29uc3RydWN0aW5nIGEgQmxhZGVzUm9sbFByaW1hcnkgb2JqZWN0LlwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXJvbGxQcmltYXJ5SW1nKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNdXN0IGluY2x1ZGUgYSByb2xsUHJpbWFyeUltZyB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc1JvbGxQcmltYXJ5IG9iamVjdC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyb2xsUHJpbWFyeVR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxQcmltYXJ5VHlwZSB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc1JvbGxQcmltYXJ5IG9iamVjdC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyb2xsRmFjdG9ycykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBpbmNsdWRlIGEgcm9sbEZhY3RvcnMgd2hlbiBjb25zdHJ1Y3RpbmcgYSBCbGFkZXNSb2xsUHJpbWFyeSBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm9sbFByaW1hcnlOYW1lID0gcm9sbFByaW1hcnlOYW1lO1xuICAgICAgICB0aGlzLnJvbGxQcmltYXJ5VHlwZSA9IHJvbGxQcmltYXJ5VHlwZTtcbiAgICAgICAgdGhpcy5yb2xsUHJpbWFyeUltZyA9IHJvbGxQcmltYXJ5SW1nO1xuICAgICAgICB0aGlzLnJvbGxGYWN0b3JzID0gcm9sbEZhY3RvcnM7XG4gICAgICAgIHRoaXMucm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0ID0gcm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0ID8/IFtdO1xuICAgIH1cbn1cbmNsYXNzIEJsYWRlc1JvbGxPcHBvc2l0aW9uIHtcbiAgICAvLyAjcmVnaW9uIFN0YXRpYyBNZXRob2RzIH5cbiAgICBzdGF0aWMgSXNWYWxpZERhdGEoZGF0YSkge1xuICAgICAgICBpZiAoQmxhZGVzUm9sbE9wcG9zaXRpb24uSXNEb2MoZGF0YSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBVLmlzTGlzdChkYXRhKVxuICAgICAgICAgICAgJiYgdHlwZW9mIGRhdGEucm9sbE9wcE5hbWUgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBkYXRhLnJvbGxPcHBUeXBlID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAmJiB0eXBlb2YgZGF0YS5yb2xsT3BwSW1nID09PSBcInN0cmluZ1wiXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbE9wcFN1Yk5hbWUgfHwgdHlwZW9mIGRhdGEucm9sbE9wcFN1Yk5hbWUgPT09IFwic3RyaW5nXCIpXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbE9wcE1vZHNTY2hlbWFTZXQgfHwgQXJyYXkuaXNBcnJheShkYXRhLnJvbGxPcHBNb2RzU2NoZW1hU2V0KSlcbiAgICAgICAgICAgICYmIFUuaXNMaXN0KGRhdGEucm9sbEZhY3RvcnMpXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbE9wcElEIHx8IHR5cGVvZiBkYXRhLnJvbGxPcHBJRCA9PT0gXCJzdHJpbmdcIik7XG4gICAgfVxuICAgIHN0YXRpYyBHZXREb2MoZG9jUmVmKSB7XG4gICAgICAgIGxldCBkb2MgPSBkb2NSZWY7XG4gICAgICAgIGlmICh0eXBlb2YgZG9jUmVmID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBkb2MgPSBnYW1lLmFjdG9ycy5nZXQoZG9jUmVmKVxuICAgICAgICAgICAgICAgID8/IGdhbWUuaXRlbXMuZ2V0KGRvY1JlZilcbiAgICAgICAgICAgICAgICA/PyBnYW1lLmFjdG9ycy5nZXROYW1lKGRvY1JlZilcbiAgICAgICAgICAgICAgICA/PyBnYW1lLml0ZW1zLmdldE5hbWUoZG9jUmVmKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoQmxhZGVzUm9sbE9wcG9zaXRpb24uSXNEb2MoZG9jKSkge1xuICAgICAgICAgICAgcmV0dXJuIGRvYztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHN0YXRpYyBJc0RvYyhkb2MpIHtcbiAgICAgICAgcmV0dXJuIEJsYWRlc0FjdG9yLklzVHlwZShkb2MsIEJsYWRlc0FjdG9yVHlwZS5ucGMsIEJsYWRlc0FjdG9yVHlwZS5mYWN0aW9uKSB8fCBCbGFkZXNJdGVtLklzVHlwZShkb2MsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nKTtcbiAgICB9XG4gICAgc3RhdGljIEdldERhdGFGcm9tRG9jKGRvYykge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgcm9sbE9wcElEOiBkb2MuaWQsXG4gICAgICAgICAgICByb2xsT3BwTmFtZTogZG9jLm5hbWUsXG4gICAgICAgICAgICByb2xsT3BwVHlwZTogZG9jLnR5cGUsXG4gICAgICAgICAgICByb2xsT3BwSW1nOiBkb2MuaW1nLFxuICAgICAgICAgICAgcm9sbE9wcE1vZHNTY2hlbWFTZXQ6IGRvYy5yb2xsT3BwTW9kc1NjaGVtYVNldCxcbiAgICAgICAgICAgIHJvbGxGYWN0b3JzOiBkb2Mucm9sbEZhY3RvcnNcbiAgICAgICAgfTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIHJvbGxJbnN0YW5jZTtcbiAgICByb2xsT3BwSUQ7XG4gICAgcm9sbE9wcERvYztcbiAgICByb2xsT3BwTmFtZTtcbiAgICByb2xsT3BwU3ViTmFtZTtcbiAgICByb2xsT3BwVHlwZTtcbiAgICByb2xsT3BwSW1nO1xuICAgIHJvbGxPcHBNb2RzU2NoZW1hU2V0O1xuICAgIHJvbGxGYWN0b3JzO1xuICAgIC8vICNyZWdpb24gQ29uc3RydWN0b3IgflxuICAgIGNvbnN0cnVjdG9yKHJvbGxJbnN0YW5jZSwgeyByb2xsT3BwSUQsIHJvbGxPcHBOYW1lLCByb2xsT3BwU3ViTmFtZSwgcm9sbE9wcFR5cGUsIHJvbGxPcHBJbWcsIHJvbGxPcHBNb2RzU2NoZW1hU2V0LCByb2xsRmFjdG9ycyB9ID0ge30pIHtcbiAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UgPSByb2xsSW5zdGFuY2U7XG4gICAgICAgIC8vIEF0dGVtcHQgdG8gZmV0Y2ggYW4gYXNzb2NpYXRlZCBCbGFkZXNBY3RvciBvciBCbGFkZXNJdGVtIGRvY3VtZW50XG4gICAgICAgIGNvbnN0IGRvYyA9IEJsYWRlc1JvbGxPcHBvc2l0aW9uLkdldERvYyhyb2xsT3BwSUQgPz8gcm9sbE9wcE5hbWUpO1xuICAgICAgICBpZiAoZG9jKSB7XG4gICAgICAgICAgICAvLyBEZXJpdmUgc2V0dGluZ3MgZnJvbSB2YWxpZCBBY3Rvci9JdGVtIGRvY3VtZW50LCB1bmxlc3MgZXhwbGljaXRseSBzZXQgaW4gY29uc3RydWN0b3IuXG4gICAgICAgICAgICB0aGlzLnJvbGxPcHBEb2MgPSBkb2M7XG4gICAgICAgICAgICByb2xsT3BwSUQgPSBkb2Mucm9sbE9wcElEO1xuICAgICAgICAgICAgcm9sbE9wcE5hbWUgPz89IGRvYy5yb2xsT3BwTmFtZTtcbiAgICAgICAgICAgIHJvbGxPcHBTdWJOYW1lID8/PSBkb2Mucm9sbE9wcFN1Yk5hbWU7XG4gICAgICAgICAgICByb2xsT3BwVHlwZSA/Pz0gZG9jLnJvbGxPcHBUeXBlO1xuICAgICAgICAgICAgcm9sbE9wcEltZyA/Pz0gZG9jLnJvbGxPcHBJbWc7XG4gICAgICAgICAgICByb2xsT3BwTW9kc1NjaGVtYVNldCA9IFtcbiAgICAgICAgICAgICAgICAuLi5yb2xsT3BwTW9kc1NjaGVtYVNldCA/PyBbXSxcbiAgICAgICAgICAgICAgICAuLi5kb2Mucm9sbE9wcE1vZHNTY2hlbWFTZXQgPz8gW11cbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICByb2xsRmFjdG9ycyA9IHtcbiAgICAgICAgICAgICAgICAuLi5kb2Mucm9sbEZhY3RvcnMsXG4gICAgICAgICAgICAgICAgLi4ucm9sbEZhY3RvcnMgPz8ge31cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ29uZmlybSByZXF1aXJlZCBzZXR0aW5nc1xuICAgICAgICBpZiAoIXJvbGxPcHBOYW1lKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNdXN0IGluY2x1ZGUgYSByb2xsT3BwTmFtZSB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc1JvbGxPcHBvc2l0aW9uIG9iamVjdC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyb2xsT3BwVHlwZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBpbmNsdWRlIGEgcm9sbE9wcFR5cGUgd2hlbiBjb25zdHJ1Y3RpbmcgYSBCbGFkZXNSb2xsT3Bwb3NpdGlvbiBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghcm9sbEZhY3RvcnMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxGYWN0b3JzIHdoZW4gY29uc3RydWN0aW5nIGEgQmxhZGVzUm9sbE9wcG9zaXRpb24gb2JqZWN0LlwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBJbml0aWFsaXplIHByb3BlcnRpZXNcbiAgICAgICAgdGhpcy5yb2xsT3BwSUQgPSByb2xsT3BwSUQ7XG4gICAgICAgIHRoaXMucm9sbE9wcE5hbWUgPSByb2xsT3BwTmFtZTtcbiAgICAgICAgdGhpcy5yb2xsT3BwU3ViTmFtZSA9IHJvbGxPcHBTdWJOYW1lO1xuICAgICAgICB0aGlzLnJvbGxPcHBUeXBlID0gcm9sbE9wcFR5cGU7XG4gICAgICAgIHRoaXMucm9sbE9wcEltZyA9IHJvbGxPcHBJbWcgPz8gXCJcIjtcbiAgICAgICAgdGhpcy5yb2xsT3BwTW9kc1NjaGVtYVNldCA9IHJvbGxPcHBNb2RzU2NoZW1hU2V0ID8/IFtdO1xuICAgICAgICB0aGlzLnJvbGxGYWN0b3JzID0gcm9sbEZhY3RvcnM7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBnZXQgZGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvbGxPcHBJRDogdGhpcy5yb2xsT3BwSUQsXG4gICAgICAgICAgICByb2xsT3BwTmFtZTogdGhpcy5yb2xsT3BwTmFtZSxcbiAgICAgICAgICAgIHJvbGxPcHBTdWJOYW1lOiB0aGlzLnJvbGxPcHBTdWJOYW1lLFxuICAgICAgICAgICAgcm9sbE9wcFR5cGU6IHRoaXMucm9sbE9wcFR5cGUsXG4gICAgICAgICAgICByb2xsT3BwSW1nOiB0aGlzLnJvbGxPcHBJbWcsXG4gICAgICAgICAgICByb2xsT3BwTW9kc1NjaGVtYVNldDogdGhpcy5yb2xsT3BwTW9kc1NjaGVtYVNldCxcbiAgICAgICAgICAgIHJvbGxGYWN0b3JzOiB0aGlzLnJvbGxGYWN0b3JzXG4gICAgICAgIH07XG4gICAgfVxuICAgIGFzeW5jIHVwZGF0ZVJvbGxGbGFncygpIHtcbiAgICAgICAgaWYgKCF0aGlzLnJvbGxJbnN0YW5jZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IHRoaXMucm9sbEluc3RhbmNlLnVwZGF0ZVRhcmdldChcInJvbGxPcHBEYXRhXCIsIHRoaXMuZGF0YSk7XG4gICAgICAgIGlmICh0aGlzLnJvbGxJbnN0YW5jZS5pc1JlbmRlcmVkKSB7XG4gICAgICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLnJvbGxJbnN0YW5jZS5pZCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmVmcmVzaCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLnJvbGxJbnN0YW5jZSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJvbGxPcHBGbGFncyA9IHRoaXMucm9sbEluc3RhbmNlLmRhdGEucm9sbE9wcERhdGE7XG4gICAgICAgIGlmIChyb2xsT3BwRmxhZ3MpIHtcbiAgICAgICAgICAgIHRoaXMucm9sbE9wcElEID0gcm9sbE9wcEZsYWdzLnJvbGxPcHBJRDtcbiAgICAgICAgICAgIHRoaXMucm9sbE9wcE5hbWUgPSByb2xsT3BwRmxhZ3Mucm9sbE9wcE5hbWU7XG4gICAgICAgICAgICB0aGlzLnJvbGxPcHBTdWJOYW1lID0gcm9sbE9wcEZsYWdzLnJvbGxPcHBTdWJOYW1lO1xuICAgICAgICAgICAgdGhpcy5yb2xsT3BwVHlwZSA9IHJvbGxPcHBGbGFncy5yb2xsT3BwVHlwZTtcbiAgICAgICAgICAgIHRoaXMucm9sbE9wcEltZyA9IHJvbGxPcHBGbGFncy5yb2xsT3BwSW1nO1xuICAgICAgICAgICAgdGhpcy5yb2xsT3BwTW9kc1NjaGVtYVNldCA9IHJvbGxPcHBGbGFncy5yb2xsT3BwTW9kc1NjaGVtYVNldCA/PyBbXTtcbiAgICAgICAgICAgIHRoaXMucm9sbEZhY3RvcnMgPSByb2xsT3BwRmxhZ3Mucm9sbEZhY3RvcnM7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxufVxuY2xhc3MgQmxhZGVzUm9sbFBhcnRpY2lwYW50IHtcbiAgICAvLyAjcmVnaW9uIFN0YXRpYyBNZXRob2RzIH5cbiAgICBzdGF0aWMgSXNWYWxpZERhdGEoZGF0YSkge1xuICAgICAgICBpZiAoQmxhZGVzUm9sbFBhcnRpY2lwYW50LklzRG9jKGRhdGEpKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gVS5pc0xpc3QoZGF0YSlcbiAgICAgICAgICAgICYmIHR5cGVvZiBkYXRhLnJvbGxQYXJ0aWNpcGFudE5hbWUgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBkYXRhLnJvbGxQYXJ0aWNpcGFudFR5cGUgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICYmIHR5cGVvZiBkYXRhLnJvbGxQYXJ0aWNpcGFudEljb24gPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgICYmICghZGF0YS5yb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0IHx8IEFycmF5LmlzQXJyYXkoZGF0YS5yb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0KSlcbiAgICAgICAgICAgICYmIFUuaXNMaXN0KGRhdGEucm9sbEZhY3RvcnMpXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbFBhcnRpY2lwYW50SUQgfHwgdHlwZW9mIGRhdGEucm9sbFBhcnRpY2lwYW50SUQgPT09IFwic3RyaW5nXCIpXG4gICAgICAgICAgICAmJiAoIWRhdGEucm9sbFBhcnRpY2lwYW50RG9jIHx8IEJsYWRlc1JvbGxQYXJ0aWNpcGFudC5Jc0RvYyhkYXRhLnJvbGxQYXJ0aWNpcGFudERvYykpO1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RG9jKGRvY1JlZikge1xuICAgICAgICBsZXQgZG9jID0gZG9jUmVmO1xuICAgICAgICBpZiAodHlwZW9mIGRvY1JlZiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgZG9jID0gZ2FtZS5hY3RvcnMuZ2V0KGRvY1JlZilcbiAgICAgICAgICAgICAgICA/PyBnYW1lLml0ZW1zLmdldChkb2NSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5hY3RvcnMuZ2V0TmFtZShkb2NSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5pdGVtcy5nZXROYW1lKGRvY1JlZik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKEJsYWRlc1JvbGxQYXJ0aWNpcGFudC5Jc0RvYyhkb2MpKSB7XG4gICAgICAgICAgICByZXR1cm4gZG9jO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgc3RhdGljIElzRG9jKGRvYykge1xuICAgICAgICByZXR1cm4gQmxhZGVzQWN0b3IuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLnBjLCBCbGFkZXNBY3RvclR5cGUuY3JldywgQmxhZGVzQWN0b3JUeXBlLm5wYylcbiAgICAgICAgICAgIHx8IEJsYWRlc0l0ZW0uSXNUeXBlKGRvYywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmdtX3RyYWNrZXIpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgcm9sbEluc3RhbmNlO1xuICAgIHJvbGxQYXJ0aWNpcGFudElEO1xuICAgIHJvbGxQYXJ0aWNpcGFudERvYztcbiAgICByb2xsUGFydGljaXBhbnROYW1lO1xuICAgIHJvbGxQYXJ0aWNpcGFudFR5cGU7XG4gICAgcm9sbFBhcnRpY2lwYW50SWNvbjtcbiAgICByb2xsUGFydGljaXBhbnRTZWN0aW9uO1xuICAgIHJvbGxQYXJ0aWNpcGFudFN1YlNlY3Rpb247XG4gICAgcm9sbFBhcnRpY2lwYW50TW9kc1NjaGVtYVNldDsgLy8gQXMgYXBwbGllZCB0byBNQUlOIHJvbGwgd2hlbiB0aGlzIHBhcnRpY2lwYW50IGludm9sdmVkXG4gICAgcm9sbEZhY3RvcnM7XG4gICAgY29uc3RydWN0b3Iocm9sbEluc3RhbmNlLCBzZWN0aW9uLCBzdWJTZWN0aW9uLCByb2xsUGFydGljaXBhbnREYXRhT3JEb2MpIHtcbiAgICAgICAgdGhpcy5yb2xsSW5zdGFuY2UgPSByb2xsSW5zdGFuY2U7XG4gICAgICAgIGlmICghc2VjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBpbmNsdWRlIGEgcm9sbFBhcnRpY2lwYW50U2VjdGlvbiB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc1JvbGxQYXJ0aWNpcGFudCBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc3ViU2VjdGlvbikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTXVzdCBpbmNsdWRlIGEgcm9sbFBhcnRpY2lwYW50U3ViU2VjdGlvbiB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc1JvbGxQYXJ0aWNpcGFudCBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucm9sbFBhcnRpY2lwYW50U2VjdGlvbiA9IHNlY3Rpb247XG4gICAgICAgIHRoaXMucm9sbFBhcnRpY2lwYW50U3ViU2VjdGlvbiA9IHN1YlNlY3Rpb247XG4gICAgICAgIC8vIEF0dGVtcHQgdG8gZmV0Y2ggYW4gYXNzb2NpYXRlZCBCbGFkZXNBY3RvciBvciBCbGFkZXNJdGVtIGRvY3VtZW50XG4gICAgICAgIGNvbnN0IGRvYyA9IEJsYWRlc1JvbGxQYXJ0aWNpcGFudC5Jc0RvYyhyb2xsUGFydGljaXBhbnREYXRhT3JEb2MpXG4gICAgICAgICAgICA/IHJvbGxQYXJ0aWNpcGFudERhdGFPckRvY1xuICAgICAgICAgICAgOiBCbGFkZXNSb2xsUGFydGljaXBhbnQuR2V0RG9jKHJvbGxQYXJ0aWNpcGFudERhdGFPckRvYy5yb2xsUGFydGljaXBhbnRJRCA/PyByb2xsUGFydGljaXBhbnREYXRhT3JEb2Mucm9sbFBhcnRpY2lwYW50TmFtZSk7XG4gICAgICAgIGlmIChkb2MpIHtcbiAgICAgICAgICAgIHJvbGxQYXJ0aWNpcGFudERhdGFPckRvYyA9IGRvYztcbiAgICAgICAgfVxuICAgICAgICAvLyBDb25maXJtIHJlcXVpcmVkIHNldHRpbmdzXG4gICAgICAgIGlmICghcm9sbFBhcnRpY2lwYW50RGF0YU9yRG9jLnJvbGxQYXJ0aWNpcGFudE5hbWUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxQYXJ0aWNpcGFudE5hbWUgd2hlbiBjb25zdHJ1Y3RpbmcgYSBCbGFkZXNSb2xsUGFydGljaXBhbnQgb2JqZWN0LlwiKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXJvbGxQYXJ0aWNpcGFudERhdGFPckRvYy5yb2xsUGFydGljaXBhbnRUeXBlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNdXN0IGluY2x1ZGUgYSByb2xsUGFydGljaXBhbnRUeXBlIHdoZW4gY29uc3RydWN0aW5nIGEgQmxhZGVzUm9sbFBhcnRpY2lwYW50IG9iamVjdC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFyb2xsUGFydGljaXBhbnREYXRhT3JEb2Mucm9sbEZhY3RvcnMpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxGYWN0b3JzIHdoZW4gY29uc3RydWN0aW5nIGEgQmxhZGVzUm9sbFBhcnRpY2lwYW50IG9iamVjdC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBwcm9wZXJ0aWVzXG4gICAgICAgIHRoaXMucm9sbFBhcnRpY2lwYW50SUQgPSByb2xsUGFydGljaXBhbnREYXRhT3JEb2Mucm9sbFBhcnRpY2lwYW50SUQ7XG4gICAgICAgIHRoaXMucm9sbFBhcnRpY2lwYW50TmFtZSA9IHJvbGxQYXJ0aWNpcGFudERhdGFPckRvYy5yb2xsUGFydGljaXBhbnROYW1lO1xuICAgICAgICB0aGlzLnJvbGxQYXJ0aWNpcGFudFR5cGUgPSByb2xsUGFydGljaXBhbnREYXRhT3JEb2Mucm9sbFBhcnRpY2lwYW50VHlwZTtcbiAgICAgICAgdGhpcy5yb2xsUGFydGljaXBhbnRJY29uID0gcm9sbFBhcnRpY2lwYW50RGF0YU9yRG9jLnJvbGxQYXJ0aWNpcGFudEljb24gPz8gXCJcIjtcbiAgICAgICAgdGhpcy5yb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0ID0gcm9sbFBhcnRpY2lwYW50RGF0YU9yRG9jLnJvbGxQYXJ0aWNpcGFudE1vZHNTY2hlbWFTZXQgPz8gW107XG4gICAgICAgIHRoaXMucm9sbEZhY3RvcnMgPSByb2xsUGFydGljaXBhbnREYXRhT3JEb2Mucm9sbEZhY3RvcnM7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBnZXQgZGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvbGxQYXJ0aWNpcGFudElEOiB0aGlzLnJvbGxQYXJ0aWNpcGFudElELFxuICAgICAgICAgICAgcm9sbFBhcnRpY2lwYW50TmFtZTogdGhpcy5yb2xsUGFydGljaXBhbnROYW1lLFxuICAgICAgICAgICAgcm9sbFBhcnRpY2lwYW50VHlwZTogdGhpcy5yb2xsUGFydGljaXBhbnRUeXBlLFxuICAgICAgICAgICAgcm9sbFBhcnRpY2lwYW50SWNvbjogdGhpcy5yb2xsUGFydGljaXBhbnRJY29uLFxuICAgICAgICAgICAgcm9sbFBhcnRpY2lwYW50TW9kc1NjaGVtYVNldDogdGhpcy5yb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0LFxuICAgICAgICAgICAgcm9sbEZhY3RvcnM6IHRoaXMucm9sbEZhY3RvcnNcbiAgICAgICAgfTtcbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlUm9sbEZsYWdzKCkge1xuICAgICAgICBhd2FpdCB0aGlzLnJvbGxJbnN0YW5jZS51cGRhdGVUYXJnZXQoYHJvbGxQYXJ0aWNpcGFudERhdGEuJHt0aGlzLnJvbGxQYXJ0aWNpcGFudFNlY3Rpb259LiR7dGhpcy5yb2xsUGFydGljaXBhbnRTdWJTZWN0aW9ufWAsIHRoaXMuZGF0YSk7XG4gICAgICAgIGlmICh0aGlzLnJvbGxJbnN0YW5jZS5pc1JlbmRlcmVkKSB7XG4gICAgICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLnJvbGxJbnN0YW5jZS5pZCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmVmcmVzaCgpIHtcbiAgICAgICAgY29uc3Qgcm9sbFBhcnRpY2lwYW50RmxhZ0RhdGEgPSB0aGlzLnJvbGxJbnN0YW5jZS5kYXRhLnJvbGxQYXJ0aWNpcGFudERhdGE/Llt0aGlzLnJvbGxQYXJ0aWNpcGFudFNlY3Rpb25dO1xuICAgICAgICBpZiAocm9sbFBhcnRpY2lwYW50RmxhZ0RhdGEgJiYgdGhpcy5yb2xsUGFydGljaXBhbnRTdWJTZWN0aW9uIGluIHJvbGxQYXJ0aWNpcGFudEZsYWdEYXRhKSB7XG4gICAgICAgICAgICBjb25zdCByb2xsUGFydGljaXBhbnRGbGFncyA9IHJvbGxQYXJ0aWNpcGFudEZsYWdEYXRhW3RoaXMucm9sbFBhcnRpY2lwYW50U3ViU2VjdGlvbl07XG4gICAgICAgICAgICBpZiAocm9sbFBhcnRpY2lwYW50RmxhZ3MpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJvbGxQYXJ0aWNpcGFudElEID0gcm9sbFBhcnRpY2lwYW50RmxhZ3Mucm9sbFBhcnRpY2lwYW50SUQ7XG4gICAgICAgICAgICAgICAgdGhpcy5yb2xsUGFydGljaXBhbnROYW1lID0gcm9sbFBhcnRpY2lwYW50RmxhZ3Mucm9sbFBhcnRpY2lwYW50TmFtZTtcbiAgICAgICAgICAgICAgICB0aGlzLnJvbGxQYXJ0aWNpcGFudFR5cGUgPSByb2xsUGFydGljaXBhbnRGbGFncy5yb2xsUGFydGljaXBhbnRUeXBlO1xuICAgICAgICAgICAgICAgIHRoaXMucm9sbFBhcnRpY2lwYW50SWNvbiA9IHJvbGxQYXJ0aWNpcGFudEZsYWdzLnJvbGxQYXJ0aWNpcGFudEljb247XG4gICAgICAgICAgICAgICAgdGhpcy5yb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0ID0gcm9sbFBhcnRpY2lwYW50RmxhZ3Mucm9sbFBhcnRpY2lwYW50TW9kc1NjaGVtYVNldCA/PyBbXTtcbiAgICAgICAgICAgICAgICB0aGlzLnJvbGxGYWN0b3JzID0gcm9sbFBhcnRpY2lwYW50RmxhZ3Mucm9sbEZhY3RvcnM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfVxufVxuY2xhc3MgQmxhZGVzUm9sbCBleHRlbmRzIEJsYWRlc1RhcmdldExpbmsge1xuICAgIHN0YXRpYyBEZWJ1ZyA9IHtcbiAgICAgICAgbW9kV2F0Y2g6IGZhbHNlLFxuICAgICAgICB3YXRjaFJvbGxNb2QobmFtZSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBuYW1lID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgQmxhZGVzUm9sbC5EZWJ1Zy5tb2RXYXRjaCA9IG5ldyBSZWdFeHAobmFtZSwgXCJnXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgQmxhZGVzUm9sbC5EZWJ1Zy5tb2RXYXRjaCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvLyAjcmVnaW9uIFNUQVRJQyBNRVRIT0RTOiBJTklUSUFMSVpBVElPTiAmIERFRkFVTFRTIH5cbiAgICBzdGF0aWMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgcmV0dXJuIGxvYWRUZW1wbGF0ZXMoW1xuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9wYXJ0aWFscy9yb2xsLWNvbGxhYi1nbS1udW1iZXItbGluZS5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcGFydGlhbHMvcm9sbC1jb2xsYWItZ20tc2VsZWN0LWRvYy5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcGFydGlhbHMvcm9sbC1jb2xsYWItZ20tZmFjdG9yLWNvbnRyb2wuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9yb2xsL3JvbGwtY29sbGFiLWFjdGlvbi5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcm9sbC1jb2xsYWItYWN0aW9uLWdtLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1yZXNpc3RhbmNlLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1yZXNpc3RhbmNlLWdtLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1mb3J0dW5lLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1mb3J0dW5lLWdtLmhic1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1pbmR1bGdldmljZS5oYnNcIixcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcm9sbC1jb2xsYWItaW5kdWxnZXZpY2UtZ20uaGJzXCJcbiAgICAgICAgXSk7XG4gICAgfVxuICAgIHN0YXRpYyBJbml0U29ja2V0cygpIHtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5yZWdpc3RlcihcImNvbnN0cnVjdFJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCBCbGFkZXNSb2xsLmNvbnN0cnVjdFJvbGxDb2xsYWJfU29ja2V0UmVzcG9uc2UuYmluZChCbGFkZXNSb2xsKSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0ucmVnaXN0ZXIoXCJyZW5kZXJSb2xsQ29sbGFiX1NvY2tldENhbGxcIiwgQmxhZGVzUm9sbC5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldFJlc3BvbnNlLmJpbmQoQmxhZGVzUm9sbCkpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLnJlZ2lzdGVyKFwiY2xvc2VSb2xsQ29sbGFiX1NvY2tldENhbGxcIiwgQmxhZGVzUm9sbC5jbG9zZVJvbGxDb2xsYWJfU29ja2V0UmVzcG9uc2UuYmluZChCbGFkZXNSb2xsKSk7XG4gICAgfVxuICAgIHN0YXRpYyBQYXJzZUNvbmZpZ1RvRGF0YShkYXRhLCBwYXJlbnRSb2xsRGF0YSkge1xuICAgICAgICBjb25zdCBwYXJlbnRSb2xsSW5zdCA9IGdhbWUuZXVub2JsYWRlcy5Sb2xscy5nZXQocGFyZW50Um9sbERhdGEuaWQpO1xuICAgICAgICBpZiAoIXBhcmVudFJvbGxJbnN0KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNSb2xsLlBhcnNlQ29uZmlnVG9EYXRhXSBObyBCbGFkZXNSb2xsIGluc3RhbmNlIGZvdW5kIHdpdGggaWQgJHtwYXJlbnRSb2xsRGF0YS5pZH0uYCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRhdGEucm9sbFByaW1hcnlEYXRhIGluc3RhbmNlb2YgQmxhZGVzUm9sbFByaW1hcnkpIHtcbiAgICAgICAgICAgIGRhdGEucm9sbFByaW1hcnlEYXRhID0gZGF0YS5yb2xsUHJpbWFyeURhdGEuZGF0YTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZGF0YS5yb2xsT3BwRGF0YSBpbnN0YW5jZW9mIEJsYWRlc1JvbGxPcHBvc2l0aW9uKSB7XG4gICAgICAgICAgICBkYXRhLnJvbGxPcHBEYXRhID0gZGF0YS5yb2xsT3BwRGF0YS5kYXRhO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGEpIHtcbiAgICAgICAgICAgIGlmIChkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGFbUm9sbE1vZFNlY3Rpb24ucm9sbF0pIHtcbiAgICAgICAgICAgICAgICBPYmplY3Qua2V5cyhkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGFbUm9sbE1vZFNlY3Rpb24ucm9sbF0pLmZvckVhY2goKGtleSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0aGlzUGFydGljaXBhbnQgPSBkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGE/LltSb2xsTW9kU2VjdGlvbi5yb2xsXT8uW2tleV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzUGFydGljaXBhbnQgaW5zdGFuY2VvZiBCbGFkZXNSb2xsUGFydGljaXBhbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucm9sbFBhcnRpY2lwYW50RGF0YVtSb2xsTW9kU2VjdGlvbi5yb2xsXVtrZXldID0gdGhpc1BhcnRpY2lwYW50LmRhdGE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGFbUm9sbE1vZFNlY3Rpb24ucG9zaXRpb25dKSB7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmtleXMoZGF0YS5yb2xsUGFydGljaXBhbnREYXRhW1JvbGxNb2RTZWN0aW9uLnBvc2l0aW9uXSkuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRoaXNQYXJ0aWNpcGFudCA9IGRhdGEucm9sbFBhcnRpY2lwYW50RGF0YT8uW1JvbGxNb2RTZWN0aW9uLnBvc2l0aW9uXT8uW2tleV07XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzUGFydGljaXBhbnQgaW5zdGFuY2VvZiBCbGFkZXNSb2xsUGFydGljaXBhbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tbm9uLW51bGwtYXNzZXJ0aW9uXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGFbUm9sbE1vZFNlY3Rpb24ucG9zaXRpb25dW2tleV0gPSB0aGlzUGFydGljaXBhbnQuZGF0YTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRhdGEucm9sbFBhcnRpY2lwYW50RGF0YVtSb2xsTW9kU2VjdGlvbi5lZmZlY3RdKSB7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmtleXMoZGF0YS5yb2xsUGFydGljaXBhbnREYXRhW1JvbGxNb2RTZWN0aW9uLmVmZmVjdF0pLmZvckVhY2goKGtleSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0aGlzUGFydGljaXBhbnQgPSBkYXRhLnJvbGxQYXJ0aWNpcGFudERhdGE/LltSb2xsTW9kU2VjdGlvbi5lZmZlY3RdPy5ba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXNQYXJ0aWNpcGFudCBpbnN0YW5jZW9mIEJsYWRlc1JvbGxQYXJ0aWNpcGFudCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1ub24tbnVsbC1hc3NlcnRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEucm9sbFBhcnRpY2lwYW50RGF0YVtSb2xsTW9kU2VjdGlvbi5lZmZlY3RdW2tleV0gPSB0aGlzUGFydGljaXBhbnQuZGF0YTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdXBlci5QYXJzZUNvbmZpZ1RvRGF0YShkYXRhKTtcbiAgICB9XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoc2NoZW1hRGF0YSkge1xuICAgICAgICAvLyBFbnN1cmUgYWxsIHByb3BlcnRpZXMgb2YgU2NoZW1hIGFyZSBwcm92aWRlZFxuICAgICAgICBpZiAoIXNjaGVtYURhdGEucm9sbFR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxUeXBlIHdoZW4gY29uc3RydWN0aW5nIGEgQmxhZGVzUm9sbCBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHNjaGVtYURhdGEucm9sbFBoYXNlID8/PSBSb2xsUGhhc2UuQ29sbGFib3JhdGlvbjtcbiAgICAgICAgc2NoZW1hRGF0YS5HTUJvb3N0cyA9IHtcbiAgICAgICAgICAgIFtGYWN0b3IudGllcl06IDAsXG4gICAgICAgICAgICBbRmFjdG9yLnF1YWxpdHldOiAwLFxuICAgICAgICAgICAgW0ZhY3Rvci5zY2FsZV06IDAsXG4gICAgICAgICAgICBbRmFjdG9yLm1hZ25pdHVkZV06IDAsXG4gICAgICAgICAgICAuLi5zY2hlbWFEYXRhLkdNQm9vc3RzID8/IHt9XG4gICAgICAgIH07XG4gICAgICAgIHNjaGVtYURhdGEuR01PcHBCb29zdHMgPSB7XG4gICAgICAgICAgICBbRmFjdG9yLnRpZXJdOiAwLFxuICAgICAgICAgICAgW0ZhY3Rvci5xdWFsaXR5XTogMCxcbiAgICAgICAgICAgIFtGYWN0b3Iuc2NhbGVdOiAwLFxuICAgICAgICAgICAgW0ZhY3Rvci5tYWduaXR1ZGVdOiAwLFxuICAgICAgICAgICAgLi4uc2NoZW1hRGF0YS5HTU9wcEJvb3N0cyA/PyB7fVxuICAgICAgICB9O1xuICAgICAgICBzY2hlbWFEYXRhLkdNT3ZlcnJpZGVzID8/PSB7fTtcbiAgICAgICAgc2NoZW1hRGF0YS51c2VyUGVybWlzc2lvbnMgPz89IHt9O1xuICAgICAgICBpZiAoc2NoZW1hRGF0YS5yb2xsUHJpbWFyeURhdGEgaW5zdGFuY2VvZiBCbGFkZXNSb2xsUHJpbWFyeSkge1xuICAgICAgICAgICAgc2NoZW1hRGF0YS5yb2xsUHJpbWFyeURhdGEgPSBzY2hlbWFEYXRhLnJvbGxQcmltYXJ5RGF0YS5kYXRhO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzY2hlbWFEYXRhLnJvbGxPcHBEYXRhIGluc3RhbmNlb2YgQmxhZGVzUm9sbE9wcG9zaXRpb24pIHtcbiAgICAgICAgICAgIHNjaGVtYURhdGEucm9sbE9wcERhdGEgPSBzY2hlbWFEYXRhLnJvbGxPcHBEYXRhLmRhdGE7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNjaGVtYURhdGE7XG4gICAgfVxuICAgIC8vIHN0YXRpYyBvdmVycmlkZSBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgLy8gICByZXR1cm4gZm91bmRyeS51dGlscy5tZXJnZU9iamVjdChzdXBlci5kZWZhdWx0T3B0aW9ucywge1xuICAgIC8vICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcInJvbGwtY29sbGFiXCIsIGdhbWUudXNlci5pc0dNID8gXCJnbS1yb2xsLWNvbGxhYlwiIDogXCJcIl0sXG4gICAgLy8gICAgIHRlbXBsYXRlOiBgc3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcm9sbC1jb2xsYWIke2dhbWUudXNlci5pc0dNID8gXCItZ21cIiA6IFwiXCJ9Lmhic2AsXG4gICAgLy8gICAgIHN1Ym1pdE9uQ2hhbmdlOiB0cnVlLFxuICAgIC8vICAgICB3aWR0aDogNTAwLFxuICAgIC8vICAgICBkcmFnRHJvcDogW1xuICAgIC8vICAgICAgIHtkcmFnU2VsZWN0b3I6IG51bGwsIGRyb3BTZWxlY3RvcjogXCJbZGF0YS1hY3Rpb249J2dtLWRyb3Atb3Bwb3NpdGlvbidcIn1cbiAgICAvLyAgICAgXVxuICAgIC8vICAgICAvLyBIZWlnaHQ6IDUwMFxuICAgIC8vICAgfSk7XG4gICAgLy8gfVxuICAgIHN0YXRpYyBnZXQgRGVmYXVsdFJvbGxNb2RTY2hlbWFTZXQoKSB7XG4gICAgICAgIC8qIFN1YmNsYXNzIG92ZXJyaWRlcyBkZXRlcm1pbmUgZGVmYXVsdCByb2xsIG1vZHMuICovXG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgc3RhdGljIEdldERpZUNsYXNzKHJvbGxUeXBlLCByb2xsUmVzdWx0LCBkaWVWYWwsIGRpZUluZGV4KSB7XG4gICAgICAgIHN3aXRjaCAocm9sbFR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgUm9sbFR5cGUuUmVzaXN0YW5jZToge1xuICAgICAgICAgICAgICAgIGlmIChkaWVWYWwgPT09IDYgJiYgZGllSW5kZXggPD0gMSAmJiByb2xsUmVzdWx0ID09PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJibGFkZXMtZGllLWNyaXRpY2FsXCI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChkaWVJbmRleCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJibGFkZXMtZGllLXJlc2lzdGFuY2VcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiYmxhZGVzLWRpZS1mYWlsXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkluZHVsZ2VWaWNlOiB7XG4gICAgICAgICAgICAgICAgaWYgKGRpZUluZGV4ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBcImJsYWRlcy1kaWUtaW5kdWxnZS12aWNlXCI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBcImJsYWRlcy1kaWUtZmFpbFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDogYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGRpZVZhbCA9PT0gNiAmJiBkaWVJbmRleCA8PSAxICYmIHJvbGxSZXN1bHQgPT09IFJvbGxSZXN1bHQuY3JpdGljYWwpIHtcbiAgICAgICAgICAgIGRpZVZhbCsrO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICBcIlwiLFxuICAgICAgICAgICAgXCJibGFkZXMtZGllLWZhaWxcIixcbiAgICAgICAgICAgIFwiYmxhZGVzLWRpZS1mYWlsXCIsXG4gICAgICAgICAgICBcImJsYWRlcy1kaWUtZmFpbFwiLFxuICAgICAgICAgICAgXCJibGFkZXMtZGllLXBhcnRpYWxcIixcbiAgICAgICAgICAgIFwiYmxhZGVzLWRpZS1wYXJ0aWFsXCIsXG4gICAgICAgICAgICBcImJsYWRlcy1kaWUtc3VjY2Vzc1wiLFxuICAgICAgICAgICAgXCJibGFkZXMtZGllLWNyaXRpY2FsXCJcbiAgICAgICAgXVtkaWVWYWxdO1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RGllSW1hZ2Uocm9sbFR5cGUsIHJvbGxSZXN1bHQsIGRpZVZhbCwgZGllSW5kZXgsIGlzR2hvc3QgPSBmYWxzZSwgaXNDcml0aWNhbCA9IGZhbHNlKSB7XG4gICAgICAgIGxldCBpbWdQYXRoID0gXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy9hc3NldHMvZGljZS9pbWFnZS9cIjtcbiAgICAgICAgaWYgKGlzR2hvc3QpIHtcbiAgICAgICAgICAgIGltZ1BhdGggKz0gXCJnaG9zdC1cIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChbUm9sbFR5cGUuUmVzaXN0YW5jZSwgUm9sbFR5cGUuSW5kdWxnZVZpY2VdLmluY2x1ZGVzKHJvbGxUeXBlKSkge1xuICAgICAgICAgICAgaW1nUGF0aCArPSBcImdyYWQtXCI7XG4gICAgICAgIH1cbiAgICAgICAgaW1nUGF0aCArPSBkaWVWYWw7XG4gICAgICAgIGlmICghaXNHaG9zdCAmJiBkaWVWYWwgPT09IDYgJiYgZGllSW5kZXggPD0gMSAmJiBpc0NyaXRpY2FsKSB7XG4gICAgICAgICAgICBpbWdQYXRoICs9IFwiLWNyaXRcIjtcbiAgICAgICAgfVxuICAgICAgICBpbWdQYXRoICs9IFwiLndlYnBcIjtcbiAgICAgICAgcmV0dXJuIGltZ1BhdGg7XG4gICAgfVxuICAgIHN0YXRpYyBnZXQgQWN0aXZlKCkge1xuICAgICAgICByZXR1cm4gVS5nZXRMYXN0KGdhbWUuZXVub2JsYWRlcy5Sb2xscy5maWx0ZXIoKHJvbGwpID0+IHJvbGwuaXNBY3RpdmUpKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gU1RBVElDIE1FVEhPRFM6IE5ldyBSb2xsIENyZWF0aW9uIH5cbiAgICAvLyBzdGF0aWMgQ3VycmVudDogUmVjb3JkPHN0cmluZywgQmxhZGVzUm9sbD4gPSB7fTtcbiAgICAvLyBzdGF0aWMgX0FjdGl2ZT86IEJsYWRlc1JvbGw7XG4gICAgLy8gc3RhdGljIGdldCBBY3RpdmUoKTogQmxhZGVzUm9sbCB8IHVuZGVmaW5lZCB7XG4gICAgLy8gICBpZiAoQmxhZGVzUm9sbC5fQWN0aXZlKSB7cmV0dXJuIEJsYWRlc1JvbGwuX0FjdGl2ZTt9XG4gICAgLy8gICBpZiAoVS5vYmpTaXplKEJsYWRlc1JvbGwuQ3VycmVudCkgPiAwKSB7cmV0dXJuIFUuZ2V0TGFzdChPYmplY3QudmFsdWVzKEJsYWRlc1JvbGwuQ3VycmVudCkpO31cbiAgICAvLyAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgLy8gfVxuICAgIC8vIHN0YXRpYyBzZXQgQWN0aXZlKHZhbDogQmxhZGVzUm9sbCB8IHVuZGVmaW5lZCkge1xuICAgIC8vICAgQmxhZGVzUm9sbC5fQWN0aXZlID0gdmFsO1xuICAgIC8vIH1cbiAgICBzdGF0aWMgR2V0VXNlclBlcm1pc3Npb25zKGNvbmZpZykge1xuICAgICAgICBpZiAoIWNvbmZpZy5yb2xsUHJpbWFyeURhdGEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNSb2xsLkdldFVzZXJQZXJtaXNzaW9ucygpXSBNaXNzaW5nIHJvbGxQcmltYXJ5RGF0YS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gPT09IE9ORSA9PT0gR0VUIFVTRVIgSURTXG4gICAgICAgIC8vIEdldCB1c2VyIElEIG9mIEdNXG4gICAgICAgIGNvbnN0IEdNVXNlcklEID0gZ2FtZS51c2Vycy5maW5kKCh1c2VyKSA9PiB1c2VyLmlzR00pPy5pZDtcbiAgICAgICAgaWYgKCFHTVVzZXJJRCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1JvbGwuR2V0VXNlclBlcm1pc3Npb25zKCldIE5vIEdNIGZvdW5kIVwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBHZXQgdXNlciBJRHMgb2YgcGxheWVyc1xuICAgICAgICBjb25zdCBwbGF5ZXJVc2VySURzID0gZ2FtZS51c2Vyc1xuICAgICAgICAgICAgLmZpbHRlcigodXNlcikgPT4gQmxhZGVzUEMuSXNUeXBlKHVzZXIuY2hhcmFjdGVyKSAmJiAhdXNlci5pc0dNICYmIHR5cGVvZiB1c2VyLmlkID09PSBcInN0cmluZ1wiKVxuICAgICAgICAgICAgLm1hcCgodXNlcikgPT4gdXNlci5pZCk7XG4gICAgICAgIC8vIFByZXBhcmUgdXNlciBJRCBwZXJtaXNzaW9ucyBvYmplY3RcbiAgICAgICAgY29uc3QgdXNlcklEcyA9IHtcbiAgICAgICAgICAgIFtSb2xsUGVybWlzc2lvbnMuR01dOiBbR01Vc2VySURdLFxuICAgICAgICAgICAgW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XTogW10sXG4gICAgICAgICAgICBbUm9sbFBlcm1pc3Npb25zLlBhcnRpY2lwYW50XTogW10sXG4gICAgICAgICAgICBbUm9sbFBlcm1pc3Npb25zLk9ic2VydmVyXTogW11cbiAgICAgICAgfTtcbiAgICAgICAgLy8gPT09IFRXTyA9PT0gREVURVJNSU5FIFBSSU1BUlkgVVNFUihTKVxuICAgICAgICAvLyBDaGVjayBSb2xsUHJpbWFyeURvYyB0byBkZXRlcm1pbmUgaG93IHRvIGFzc2lnbiBwcmltYXJ5IHVzZXJzXG4gICAgICAgIGNvbnN0IHsgcm9sbFByaW1hcnlEb2MgfSA9IChuZXcgQmxhZGVzUm9sbFByaW1hcnkoY29uZmlnLnJvbGxQcmltYXJ5RGF0YSkpO1xuICAgICAgICBpZiAoQmxhZGVzUEMuSXNUeXBlKHJvbGxQcmltYXJ5RG9jKVxuICAgICAgICAgICAgJiYgVS5wdWxsRWxlbWVudChwbGF5ZXJVc2VySURzLCByb2xsUHJpbWFyeURvYy5wcmltYXJ5VXNlcj8uaWQpKSB7XG4gICAgICAgICAgICB1c2VySURzW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XS5wdXNoKHJvbGxQcmltYXJ5RG9jLnByaW1hcnlVc2VyPy5pZCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoQmxhZGVzQ3Jldy5Jc1R5cGUocm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICB1c2VySURzW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XS5wdXNoKC4uLnBsYXllclVzZXJJRHMpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHJvbGxQcmltYXJ5RG9jLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCkpIHtcbiAgICAgICAgICAgIGlmIChjb25maWcucm9sbFVzZXJJRCA9PT0gR01Vc2VySUQpIHtcbiAgICAgICAgICAgICAgICB1c2VySURzW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XS5wdXNoKC4uLnBsYXllclVzZXJJRHMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoQmxhZGVzUEMuSXNUeXBlKHJvbGxQcmltYXJ5RG9jLnBhcmVudClcbiAgICAgICAgICAgICAgICAmJiByb2xsUHJpbWFyeURvYy5wYXJlbnQucHJpbWFyeVVzZXI/LmlkKSB7XG4gICAgICAgICAgICAgICAgdXNlcklEc1tSb2xsUGVybWlzc2lvbnMuUHJpbWFyeV0ucHVzaChyb2xsUHJpbWFyeURvYy5wYXJlbnQucHJpbWFyeVVzZXIuaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKEJsYWRlc0dNVHJhY2tlci5Jc1R5cGUocm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICB1c2VySURzW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XS5wdXNoKEdNVXNlcklEKTtcbiAgICAgICAgfVxuICAgICAgICAvLyA9PT0gVEhSRUUgPT09IERFVEVSTUlORSBST0xMIFBBUlRJQ0lQQU5UIFVTRVIoUylcbiAgICAgICAgLy8gQ2hlY2sgY29uZmlnLnJvbGxQYXJ0aWNpcGFudERhdGEgdG8gZGV0ZXJtaW5lIGlmIHJvbGwgc3RhcnRzIHdpdGggYW55IHBhcnRpY2lwYW50c1xuICAgICAgICBpZiAoY29uZmlnLnJvbGxQYXJ0aWNpcGFudERhdGEpIHtcbiAgICAgICAgICAgIHVzZXJJRHNbUm9sbFBlcm1pc3Npb25zLlBhcnRpY2lwYW50XS5wdXNoKC4uLmdldFBhcnRpY2lwYW50RG9jVXNlcklEcyhjb25maWcucm9sbFBhcnRpY2lwYW50RGF0YSwgcGxheWVyVXNlcklEcykpO1xuICAgICAgICB9XG4gICAgICAgIC8vID09PSBGT1VSID09PSBBU1NJR04gUk9MTCBPQlNFUlZFUlNcbiAgICAgICAgLy8gQWRkIHJlbWFpbmluZyBwbGF5ZXJzIGFzIG9ic2VydmVycy5cbiAgICAgICAgdXNlcklEc1tSb2xsUGVybWlzc2lvbnMuT2JzZXJ2ZXJdID0gcGxheWVyVXNlcklEc1xuICAgICAgICAgICAgLmZpbHRlcigodUlEKSA9PiAhdXNlcklEc1tSb2xsUGVybWlzc2lvbnMuUGFydGljaXBhbnRdLmluY2x1ZGVzKHVJRCkpO1xuICAgICAgICAvLyA9PT0gRklWRSA9PT0gUEFSU0UgSU5UTyB7SUQ6IFBFUk1JU1NJT059IEZPUk1BVFxuICAgICAgICBjb25zdCB1c2VyRmxhZ0RhdGEgPSB7fTtcbiAgICAgICAgT2JqZWN0LmVudHJpZXModXNlcklEcylcbiAgICAgICAgICAgIC5mb3JFYWNoKChbcm9sbFBlcm1pc3Npb24sIGlkc0FycmF5XSkgPT4ge1xuICAgICAgICAgICAgZm9yIChjb25zdCBpZCBvZiBpZHNBcnJheSkge1xuICAgICAgICAgICAgICAgIHVzZXJGbGFnRGF0YVtpZF0gPSByb2xsUGVybWlzc2lvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiB1c2VyRmxhZ0RhdGE7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBHZW5lcmF0ZXMgQmxhZGVzUm9sbFBhcnRpY2lwYW50IGRvY3VtZW50cyBmcm9tIHRoZSBwcm92aWRlZCBzY2hlbWEgZGF0YS5cbiAgICAgICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLlJvbGxQYXJ0aWNpcGFudERhdGFTZXR9IHBhcnRpY2lwYW50RGF0YVxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gZ2V0UGFydGljaXBhbnREb2NzKHBhcnRpY2lwYW50RGF0YSkge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoZmxhdHRlbk9iamVjdChwYXJ0aWNpcGFudERhdGEpKVxuICAgICAgICAgICAgICAgIC5tYXAoKHBEYXRhKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKEJsYWRlc1JvbGxQYXJ0aWNpcGFudC5Jc0RvYyhwRGF0YSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBEYXRhO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoQmxhZGVzUm9sbFBhcnRpY2lwYW50LklzVmFsaWREYXRhKHBEYXRhKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHBEYXRhLnJvbGxQYXJ0aWNpcGFudElEID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBwRG9jID0gZ2FtZS5hY3RvcnMuZ2V0KHBEYXRhLnJvbGxQYXJ0aWNpcGFudElEKSA/PyBnYW1lLml0ZW1zLmdldChwRGF0YS5yb2xsUGFydGljaXBhbnRJRCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoQmxhZGVzUm9sbFBhcnRpY2lwYW50LklzRG9jKHBEb2MpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHBEb2M7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igd2l0aCBzdWZmaWNpZW50IGRlYnVnIGRhdGEgaWYgcERhdGEgZG9lcyBub3QgbWF0Y2ggYW55IGV4cGVjdGVkIHR5cGVzXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbZ2V0UGFydGljaXBhbnREb2NzXSBJbnZhbGlkIHBhcnRpY2lwYW50IGRhdGEgZW5jb3VudGVyZWQuIERhdGE6ICR7SlNPTi5zdHJpbmdpZnkocERhdGEpfSwgRXhwZWN0ZWQ6IFwiQmxhZGVzUm9sbFBhcnRpY2lwYW50IG9yIHZhbGlkIHBhcnRpY2lwYW50IGRhdGFcIiwgRnVuY3Rpb24gQ29udGV4dDogXCJnZXRQYXJ0aWNpcGFudERvY3NcIiwgUGFydGljaXBhbnQgRGF0YTogJHtKU09OLnN0cmluZ2lmeShwYXJ0aWNpcGFudERhdGEpfWApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgLyoqXG4gICAgICAgICAqIFJldHVybnMgdGhlIHVzZXIgaWRzIG9mIHBvdGVudGlhbCBCbGFkZXNSb2xsUGFydGljaXBhbnRzIGRlZmluZWQgaW4gdGhlIHByb3ZpZGVkIGRhdGEgc2NoZW1hLlxuICAgICAgICAgKiBAcGFyYW0ge0JsYWRlc1JvbGwuUm9sbFBhcnRpY2lwYW50RGF0YVNldH0gcGFydGljaXBhbnREYXRhXG4gICAgICAgICAqIEBwYXJhbSB7SURTdHJpbmdbXX0gdW5hc3NpZ25lZElEc1xuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gZ2V0UGFydGljaXBhbnREb2NVc2VySURzKHBhcnRpY2lwYW50RGF0YSwgdW5hc3NpZ25lZElEcykge1xuICAgICAgICAgICAgcmV0dXJuIGdldFBhcnRpY2lwYW50RG9jcyhwYXJ0aWNpcGFudERhdGEpXG4gICAgICAgICAgICAgICAgLm1hcCgocERvYykgPT4ge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNQQy5Jc1R5cGUocERvYykgJiYgdHlwZW9mIHBEb2MucHJpbWFyeVVzZXI/LmlkID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwRG9jLnByaW1hcnlVc2VyLmlkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChCbGFkZXNDcmV3LklzVHlwZShwRG9jKVxuICAgICAgICAgICAgICAgICAgICB8fCBCbGFkZXNJdGVtLklzVHlwZShwRG9jLCBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHVuYXNzaWduZWRJRHM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZmxhdCgpXG4gICAgICAgICAgICAgICAgLmZpbHRlcigocFVzZXIpID0+IHBVc2VyICE9PSBudWxsICYmICF1c2VySURzW1JvbGxQZXJtaXNzaW9ucy5QcmltYXJ5XS5pbmNsdWRlcyhwVXNlcikpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHN0YXRpYyBCdWlsZExpbmtDb25maWcoY29uZmlnKSB7XG4gICAgICAgIC8vIFByZXBhcmUgcGFydGlhbCB0YXJnZXQgbGluayBjb25maWdcbiAgICAgICAgY29uc3QgcGFydGlhbExpbmtDb25maWcgPSB7fTtcbiAgICAgICAgaWYgKFwidGFyZ2V0S2V5XCIgaW4gY29uZmlnICYmIGNvbmZpZy50YXJnZXRLZXkpIHtcbiAgICAgICAgICAgIHBhcnRpYWxMaW5rQ29uZmlnLnRhcmdldEtleSA9IGNvbmZpZy50YXJnZXRLZXk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoXCJ0YXJnZXRGbGFnS2V5XCIgaW4gY29uZmlnICYmIGNvbmZpZy50YXJnZXRGbGFnS2V5KSB7XG4gICAgICAgICAgICBwYXJ0aWFsTGlua0NvbmZpZy50YXJnZXRGbGFnS2V5ID0gY29uZmlnLnRhcmdldEZsYWdLZXk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFwidGFyZ2V0XCIgaW4gY29uZmlnKSB7XG4gICAgICAgICAgICBpZiAoVS5pc0RvY1VVSUQoY29uZmlnLnRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICBwYXJ0aWFsTGlua0NvbmZpZy50YXJnZXRJRCA9IGNvbmZpZy50YXJnZXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChVLmlzRG9jSUQoY29uZmlnLnRhcmdldCkpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb25mVGFyZ2V0ID0gZ2FtZS5hY3RvcnMuZ2V0KGNvbmZpZy50YXJnZXQpXG4gICAgICAgICAgICAgICAgICAgID8/IGdhbWUuaXRlbXMuZ2V0KGNvbmZpZy50YXJnZXQpXG4gICAgICAgICAgICAgICAgICAgID8/IGdhbWUubWVzc2FnZXMuZ2V0KGNvbmZpZy50YXJnZXQpXG4gICAgICAgICAgICAgICAgICAgID8/IGdhbWUudXNlcnMuZ2V0KGNvbmZpZy50YXJnZXQpO1xuICAgICAgICAgICAgICAgIGlmIChjb25mVGFyZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcnRpYWxMaW5rQ29uZmlnLnRhcmdldElEID0gY29uZlRhcmdldC51dWlkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzUm9sbC5CdWlsZExpbmtDb25maWddIE5vIHRhcmdldCBmb3VuZCB3aXRoIGlkICR7Y29uZmlnLnRhcmdldH0uYCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFydGlhbExpbmtDb25maWcudGFyZ2V0SUQgPSBjb25maWcudGFyZ2V0LnV1aWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoXCJ0YXJnZXRJRFwiIGluIGNvbmZpZykge1xuICAgICAgICAgICAgcGFydGlhbExpbmtDb25maWcudGFyZ2V0SUQgPSBjb25maWcudGFyZ2V0SUQ7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzUm9sbC5CdWlsZExpbmtDb25maWddIFlvdSBtdXN0IHByb3ZpZGUgYSB2YWxpZCB0YXJnZXQgb3IgdGFyZ2V0SUQgaW4gdGhlIGNvbmZpZyBvYmplY3QuXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIG5laXRoZXIgdGFyZ2V0S2V5IG5vciB0YXJnZXRGbGFnS2V5IGFyZSBwcm92aWRlZCwgc2V0IHRhcmdldEZsYWdLZXkgdG8gJ3JvbGxDb2xsYWInLlxuICAgICAgICBpZiAoIXBhcnRpYWxMaW5rQ29uZmlnLnRhcmdldEtleSAmJiAhcGFydGlhbExpbmtDb25maWcudGFyZ2V0RmxhZ0tleSkge1xuICAgICAgICAgICAgcGFydGlhbExpbmtDb25maWcudGFyZ2V0RmxhZ0tleSA9IFwicm9sbENvbGxhYlwiO1xuICAgICAgICB9XG4gICAgICAgIC8vIEJ1aWxkIHRhcmdldCBsaW5rIGNvbmZpZ1xuICAgICAgICBpZiAoQmxhZGVzVGFyZ2V0TGluay5Jc1ZhbGlkQ29uZmlnKHBhcnRpYWxMaW5rQ29uZmlnKSkge1xuICAgICAgICAgICAgcmV0dXJuIEJsYWRlc1RhcmdldExpbmsuQnVpbGRMaW5rQ29uZmlnKHBhcnRpYWxMaW5rQ29uZmlnKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzUm9sbC5CdWlsZExpbmtDb25maWddIEludmFsaWQgbGluayBjb25maWcuXCIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBc3luY2hyb25vdXNseSBjcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIGBCbGFkZXNSb2xsYCBvciBpdHMgc3ViY2xhc3Nlcy5cbiAgICAgKlxuICAgICAqIFRoaXMgZ2VuZXJpYyBzdGF0aWMgbWV0aG9kIGlzIGRlc2lnbmVkIHRvIGZhY2lsaXRhdGUgdGhlIGNyZWF0aW9uIG9mIHJvbGwgaW5zdGFuY2VzIHdpdGhcbiAgICAgKiBjb25maWd1cmF0aW9ucyBzcGVjaWZpYyB0byB0aGUgdHlwZSBvZiByb2xsIGJlaW5nIGNyZWF0ZWQuIEl0IGVuc3VyZXMgdGhhdCB0aGUgY29ycmVjdCB0eXBlXG4gICAgICogb2Ygcm9sbCBpbnN0YW5jZSBpcyByZXR1cm5lZCBiYXNlZCBvbiB0aGUgY2xhc3MgaXQncyBjYWxsZWQgb24sIGFsbG93aW5nIGZvciBhIGZsZXhpYmxlIGFuZFxuICAgICAqIHR5cGUtc2FmZSBjcmVhdGlvbiBwcm9jZXNzIHRoYXQgY2FuIGJlIGV4dGVuZGVkIHRvIHN1YmNsYXNzZXMgb2YgYEJsYWRlc1JvbGxgLlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIEMgVGhlIGNsYXNzIG9uIHdoaWNoIGBOZXdgIGlzIGNhbGxlZC4gVGhpcyBjbGFzcyBtdXN0IGV4dGVuZCBgQmxhZGVzUm9sbGAgYW5kXG4gICAgICogbXVzdCBiZSBjb25zdHJ1Y3RpYmxlIHdpdGggYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0IGlzIGVpdGhlciBhIGBCbGFkZXNSb2xsLkNvbmZpZ2Agb3JcbiAgICAgKiBhIGNvbWJpbmF0aW9uIG9mIGBCbGFkZXNUYXJnZXRMaW5rLkRhdGFgIGFuZCBhIHBhcnRpYWwgYEJsYWRlc1JvbGwuU2NoZW1hYC4gVGhpcyBlbnN1cmVzXG4gICAgICogdGhhdCBhbnkgc3ViY2xhc3Mgb2YgYEJsYWRlc1JvbGxgIGNhbiB1c2UgdGhpcyBtZXRob2QgdG8gY3JlYXRlIGluc3RhbmNlcyBvZiBpdHNlbGYgd2hpbGVcbiAgICAgKiBhcHBseWluZyBhbnkgY2xhc3Mtc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgb3IgYmVoYXZpb3JzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLkNvbmZpZ30gY29uZmlnIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgY3JlYXRpbmcgYSBuZXcgcm9sbCBpbnN0YW5jZS5cbiAgICAgKiBUaGlzIGNvbmZpZ3VyYXRpb24gaW5jbHVkZXMgYWxsIG5lY2Vzc2FyeSBkYXRhIHRvIGluaXRpYWxpemUgdGhlIHJvbGwsIHN1Y2ggYXMgdXNlciBwZXJtaXNzaW9ucyxcbiAgICAgKiByb2xsIHR5cGUsIGFuZCBhbnkgbW9kaWZpY2F0aW9ucyBvciBhZGRpdGlvbmFsIGRhdGEgcmVxdWlyZWQgZm9yIHRoZSByb2xsJ3Mgb3BlcmF0aW9uLlxuICAgICAqXG4gICAgICogQHJldHVybnMge1Byb21pc2U8SW5zdGFuY2VUeXBlPEM+Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gaW5zdGFuY2Ugb2YgdGhlIGNsYXNzXG4gICAgICogZnJvbSB3aGljaCBgTmV3YCB3YXMgY2FsbGVkLiBUaGlzIGFsbG93cyBmb3IgdGhlIGR5bmFtaWMgY3JlYXRpb24gb2Ygcm9sbCBpbnN0YW5jZXMgYmFzZWRcbiAgICAgKiBvbiB0aGUgc3ViY2xhc3MgY2FsbGluZyB0aGUgbWV0aG9kLCBlbnN1cmluZyB0aGF0IHRoZSByZXR1cm5lZCBpbnN0YW5jZSBpcyBvZiB0aGUgY29ycmVjdCB0eXBlLlxuICAgICAqXG4gICAgICogQGV4YW1wbGVcbiAgICAgKiAvLyBBc3N1bWluZyBgTXlDdXN0b21Sb2xsYCBpcyBhIHN1YmNsYXNzIG9mIGBCbGFkZXNSb2xsYFxuICAgICAqIE15Q3VzdG9tUm9sbC5OZXcobXlDb25maWcpLnRoZW4oaW5zdGFuY2UgPT4ge1xuICAgICAqICAgLy8gYGluc3RhbmNlYCBpcyBvZiB0eXBlIGBNeUN1c3RvbVJvbGxgXG4gICAgICogfSk7XG4gICAgICpcbiAgICAgKiBAcmVtYXJrc1xuICAgICAqIC0gVGhlIG1ldGhvZCBwZXJmb3JtcyBzZXZlcmFsIGtleSBvcGVyYXRpb25zIGFzIHBhcnQgb2YgdGhlIHJvbGwgaW5zdGFuY2UgY3JlYXRpb24gcHJvY2VzczpcbiAgICAgKiAgIDEuIEJ1aWxkcyBsaW5rIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZy5cbiAgICAgKiAgIDIuIFByZXBhcmVzIHJvbGwgdXNlciBmbGFnIGRhdGEgdG8gZGV0ZXJtaW5lIHBlcm1pc3Npb25zIGZvciBkaWZmZXJlbnQgdXNlcnMuXG4gICAgICogICAzLiBWYWxpZGF0ZXMgdGhhdCBhIHJvbGwgdHlwZSBpcyBkZWZpbmVkIGluIHRoZSBjb25maWcsIHRocm93aW5nIGFuIGVycm9yIGlmIG5vdC5cbiAgICAgKiAgIDQuIExvZ3MgdGhlIHJvbGwgZGF0YSBmb3IgZGVidWdnaW5nIG9yIGF1ZGl0aW5nIHB1cnBvc2VzLlxuICAgICAqICAgNS4gQ29uc3RydWN0cyBhbmQgaW5pdGlhbGl6ZXMgdGhlIHJvbGwgaW5zdGFuY2UsIGluY2x1ZGluZyBzZXR0aW5nIHVwIHJvbGwgbW9kaWZpY2F0aW9uc1xuICAgICAqICAgICAgYW5kIHNlbmRpbmcgb3V0IHNvY2tldCBjYWxscyB0byBpbmZvcm0gYWxsIHVzZXJzIGFib3V0IHRoZSByb2xsLlxuICAgICAqIC0gVGhpcyBtZXRob2QgaXMgY2VudHJhbCB0byB0aGUgZHluYW1pYyBhbmQgZmxleGlibGUgY3JlYXRpb24gb2Ygcm9sbCBpbnN0YW5jZXMgd2l0aGluIHRoZVxuICAgICAqICAgc3lzdGVtLCBhbGxvd2luZyBmb3IgZWFzeSBleHRlbnNpb24gYW5kIGN1c3RvbWl6YXRpb24gaW4gc3ViY2xhc3NlcyBvZiBgQmxhZGVzUm9sbGAuXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIE5ldyhjb25maWcpIHtcbiAgICAgICAgLy8gQnVpbGQgbGluayBjb25maWdcbiAgICAgICAgY29uc3QgbGlua0NvbmZpZyA9IHRoaXMuQnVpbGRMaW5rQ29uZmlnKGNvbmZpZyk7XG4gICAgICAgIC8vIFByZXBhcmUgcm9sbCB1c2VyIGZsYWcgZGF0YVxuICAgICAgICBjb25maWcudXNlclBlcm1pc3Npb25zID0gdGhpcy5HZXRVc2VyUGVybWlzc2lvbnMoY29uZmlnKTtcbiAgICAgICAgLy8gRW5zdXJlIHJvbGxUeXBlIGlzIGRlZmluZWRcbiAgICAgICAgaWYgKCFjb25maWcucm9sbFR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcInJvbGxUeXBlIG11c3QgYmUgZGVmaW5lZCBpbiBjb25maWdcIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gTG9nIHRoZSByb2xsIGRhdGFcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJibGFkZXNSb2xsXCIsIFwiQmxhZGVzUm9sbC5OZXdSb2xsKClcIiwgeyBjb25maWcgfSk7XG4gICAgICAgIC8vIENvbnN0cnVjdCBhbmQgaW5pdGlhbGl6ZSB0aGUgQmxhZGVzUm9sbC9CbGFkZXNUYXJnZXRMaW5rIGluc3RhbmNlXG4gICAgICAgIGNvbnN0IHJvbGxJbnN0ID0gYXdhaXQgdGhpcy5DcmVhdGUoeyAuLi5jb25maWcsIC4uLmxpbmtDb25maWcgfSk7XG4gICAgICAgIGlmICghcm9sbEluc3QuaXNJbml0UHJvbWlzZVJlc29sdmVkKSB7XG4gICAgICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImJsYWRlc1JvbGxcIiwgXCJCbGFkZXNSb2xsIEluaXQgUHJvbWlzZSBOT1QgUmVzb2x2ZWQgQWZ0ZXIgQXdhaXRpbmcgQ3JlYXRlXCIpO1xuICAgICAgICAgICAgYXdhaXQgVS53YWl0Rm9yKHJvbGxJbnN0LmluaXRQcm9taXNlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGVMb2cuY2hlY2tMb2czKFwiYmxhZGVzUm9sbFwiLCBcIkJsYWRlc1JvbGwgSW5pdCBQcm9taXNlIFJlc29sdmVkIEFmdGVyIEF3YWl0aW5nIENyZWF0ZVwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBTZW5kIG91dCBzb2NrZXQgY2FsbHMgdG8gYWxsIHVzZXJzIHRvIHNlZSB0aGUgcm9sbC5cbiAgICAgICAgcm9sbEluc3QuY29uc3RydWN0Um9sbENvbGxhYl9Tb2NrZXRDYWxsKHJvbGxJbnN0LmxpbmtEYXRhKTtcbiAgICAgICAgcmV0dXJuIHJvbGxJbnN0O1xuICAgIH1cbiAgICBhc3luYyBpbml0VGFyZ2V0TGluaygpIHtcbiAgICAgICAgdGhpcy5pbml0aWFsU2NoZW1hLnJvbGxNb2RzRGF0YSA9IHRoaXMucm9sbE1vZHNEYXRhU2V0O1xuICAgICAgICBzdXBlci5pbml0VGFyZ2V0TGluaygpO1xuICAgIH1cbiAgICBnZXQgcm9sbE1vZHNTY2hlbWFTZXRzKCkge1xuICAgICAgICBjb25zdCBjb21waWxlZE1vZFNjaGVtYVNldHMgPSBbXTtcbiAgICAgICAgLy8gQWRkIHJvbGwgbW9kcyBvbiByb2xsUHJpbWFyeVxuICAgICAgICBpZiAodGhpcy5yb2xsUHJpbWFyeSkge1xuICAgICAgICAgICAgY29tcGlsZWRNb2RTY2hlbWFTZXRzLnB1c2goLi4udGhpcy5yb2xsUHJpbWFyeS5yb2xsUHJpbWFyeU1vZHNTY2hlbWFTZXRcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChwU2NoZW1hKSA9PiBjb21waWxlZE1vZFNjaGVtYVNldHMuZXZlcnkoKG1TY2hlbWEpID0+IG1TY2hlbWEua2V5ICE9PSBwU2NoZW1hLmtleSkpKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBZGQgcm9sbCBtb2RzIG9uIHJvbGxPcHBvc2l0aW9uXG4gICAgICAgIGlmICh0aGlzLnJvbGxPcHBvc2l0aW9uPy5yb2xsT3BwTW9kc1NjaGVtYVNldCkge1xuICAgICAgICAgICAgY29tcGlsZWRNb2RTY2hlbWFTZXRzLnB1c2goLi4udGhpcy5yb2xsT3Bwb3NpdGlvbi5yb2xsT3BwTW9kc1NjaGVtYVNldFxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKG9TY2hlbWEpID0+IGNvbXBpbGVkTW9kU2NoZW1hU2V0cy5ldmVyeSgobVNjaGVtYSkgPT4gbVNjaGVtYS5rZXkgIT09IG9TY2hlbWEua2V5KSkpO1xuICAgICAgICB9XG4gICAgICAgIC8vIEFkZCBkZWZhdWx0IHJvbGwgbW9kc1xuICAgICAgICBjb21waWxlZE1vZFNjaGVtYVNldHMucHVzaCguLi50aGlzLmNvbnN0cnVjdG9yLkRlZmF1bHRSb2xsTW9kU2NoZW1hU2V0XG4gICAgICAgICAgICAuZmlsdGVyKChkU2NoZW1hKSA9PiBjb21waWxlZE1vZFNjaGVtYVNldHMuZXZlcnkoKG1TY2hlbWEpID0+IG1TY2hlbWEua2V5ICE9PSBkU2NoZW1hLmtleSkpKTtcbiAgICAgICAgLy8gSWYgdGhpcyBpcyBhIGRvd250aW1lIGFjdGlvbiByb2xsLCBhZGQgZGVmYXVsdCBkb3dudGltZSBhY3Rpb24gcm9sbCBtb2RzXG4gICAgICAgIGlmICh0aGlzLnJvbGxEb3dudGltZUFjdGlvbikge1xuICAgICAgICAgICAgY29tcGlsZWRNb2RTY2hlbWFTZXRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGtleTogXCJIZWxwRnJvbUZyaWVuZC1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJIZWxwIEZyb20gYSBGcmllbmRcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5wb3NpdGlvbixcbiAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJwb3NpdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW10sXG4gICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+SGVscCBGcm9tIGEgRnJpZW5kPC9oMT48cD5BZGQgPHN0cm9uZz4rMWQ8L3N0cm9uZz4gaWYgeW91IGVubGlzdCB0aGUgaGVscCBvZiBhIGZyaWVuZCBvciBjb250YWN0LjwvcD5cIlxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZiAodGhpcy5yb2xsRG93bnRpbWVBY3Rpb24gIT09IERvd250aW1lQWN0aW9uLkluZHVsZ2VWaWNlKSB7XG4gICAgICAgICAgICAgICAgY29tcGlsZWRNb2RTY2hlbWFTZXRzLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICBrZXk6IFwiQ2FuQnV5UmVzdWx0TGV2ZWwtcG9zaXRpdmUtYWZ0ZXJcIixcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogXCJCdXlpbmcgUmVzdWx0IExldmVsXCIsXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLmFmdGVyLFxuICAgICAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbixcbiAgICAgICAgICAgICAgICAgICAgcG9zTmVnOiBcInBvc2l0aXZlXCIsXG4gICAgICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiAwLFxuICAgICAgICAgICAgICAgICAgICBlZmZlY3RLZXlzOiBbXSxcbiAgICAgICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+QnV5aW5nIFJlc3VsdCBMZXZlbDwvaDE+PHA+QWZ0ZXIgeW91ciByb2xsLCB5b3UgY2FuIDxzdHJvbmc+aW5jcmVhc2UgdGhlIHJlc3VsdCBsZXZlbDwvc3Ryb25nPiBieSBvbmUgZm9yIGVhY2ggPHN0cm9uZyBjbGFzcz1cXFwiZ29sZC1icmlnaHRcXFwiPkNvaW48L3N0cm9uZz4geW91IHNwZW5kLjwvcD5cIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMucm9sbERvd250aW1lQWN0aW9uID09PSBEb3dudGltZUFjdGlvbi5BY3F1aXJlQXNzZXQpIHtcbiAgICAgICAgICAgICAgICBjb21waWxlZE1vZFNjaGVtYVNldHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGtleTogXCJSZXBlYXRQdXJjaGFzZS1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IFwiUmVwZWF0IFB1cmNoYXNlXCIsXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLnJvbGwsXG4gICAgICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPZmYsXG4gICAgICAgICAgICAgICAgICAgIHBvc05lZzogXCJwb3NpdGl2ZVwiLFxuICAgICAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW10sXG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiPGgxPlJlcGVhdCBQdXJjaGFzZSBCb251czwvaDE+PHA+QWRkIDxzdHJvbmc+KzFkPC9zdHJvbmc+IGlmIHlvdSBoYXZlIHByZXZpb3VzbHkgYWNxdWlyZWQgdGhpcyBhc3NldCBvciBzZXJ2aWNlIHdpdGggYSA8c3Ryb25nPkFjcXVpcmUgQXNzZXQ8L3N0cm9uZz4gRG93bnRpbWUgYWN0aXZpdHkuPC9wPlwiXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBrZXk6IFwiUmVzdHJpY3RlZEl0ZW0tbmVnYXRpdmUtYWZ0ZXJcIixcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogXCJSZXN0cmljdGVkXCIsXG4gICAgICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLmFmdGVyLFxuICAgICAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5IaWRkZW4sXG4gICAgICAgICAgICAgICAgICAgIHBvc05lZzogXCJuZWdhdGl2ZVwiLFxuICAgICAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW1wiQ29zdC1IZWF0MlwiXSxcbiAgICAgICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+UmVzdHJpY3RlZDwvaDE+PHA+V2hldGhlciBjb250cmFiYW5kIGdvb2RzIG9yIGRhbmdlcm91cyBtYXRlcmlhbHMsIHRoaXMgPHN0cm9uZz5BY3F1aXJlIEFzc2V0PC9zdHJvbmc+IERvd250aW1lIGFjdGl2aXR5IHdpbGwgYWRkIDxzdHJvbmcgY2xhc3M9XFxcInJlZC1icmlnaHRcXFwiPisyIEhlYXQ8L3N0cm9uZz4gdG8geW91ciBjcmV3LjwvcD5cIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb21waWxlZE1vZFNjaGVtYVNldHM7XG4gICAgfVxuICAgIGdldCByb2xsTW9kc0RhdGFTZXQoKSB7XG4gICAgICAgIGNvbnN0IHsgbGlua0RhdGEgfSA9IHRoaXM7XG4gICAgICAgIGNvbnN0IG1vZExpbmtDb25maWcgPSB7XG4gICAgICAgICAgICB0YXJnZXRJRDogbGlua0RhdGEudGFyZ2V0SUQsXG4gICAgICAgICAgICBpc1Njb3BpbmdCeUlkOiB0cnVlLFxuICAgICAgICAgICAgLi4uKFwidGFyZ2V0S2V5XCIgaW4gbGlua0RhdGFcbiAgICAgICAgICAgICAgICA/IHsgdGFyZ2V0S2V5OiBgJHt0aGlzLnRhcmdldEtleVByZWZpeH0ucm9sbE1vZHNEYXRhYCB9XG4gICAgICAgICAgICAgICAgOiB7fSksXG4gICAgICAgICAgICAuLi4oXCJ0YXJnZXRGbGFnS2V5XCIgaW4gbGlua0RhdGFcbiAgICAgICAgICAgICAgICA/IHsgdGFyZ2V0RmxhZ0tleTogYCR7dGhpcy50YXJnZXRGbGFnS2V5UHJlZml4fS5yb2xsTW9kc0RhdGFgIH1cbiAgICAgICAgICAgICAgICA6IHt9KVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKHRoaXMucm9sbE1vZHNTY2hlbWFTZXRzXG4gICAgICAgICAgICAubWFwKChtb2RTY2hlbWEpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IG1vZERhdGEgPSBCbGFkZXNUYXJnZXRMaW5rLlBhcnNlQ29uZmlnVG9EYXRhKHtcbiAgICAgICAgICAgICAgICAuLi5CbGFkZXNSb2xsTW9kLkFwcGx5U2NoZW1hRGVmYXVsdHMobW9kU2NoZW1hKSxcbiAgICAgICAgICAgICAgICAuLi5tb2RMaW5rQ29uZmlnXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBbbW9kRGF0YS5pZCwgbW9kRGF0YV07XG4gICAgICAgIH0pKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gU09DS0VUIENBTExTICYgUkVTUE9OU0VTIH5cbiAgICBzdGF0aWMgR2V0Um9sbFN1YkNsYXNzKGxpbmtEYXRhKSB7XG4gICAgICAgIGNvbnN0IHRhcmdldExpbmsgPSBuZXcgQmxhZGVzVGFyZ2V0TGluayhsaW5rRGF0YSk7XG4gICAgICAgIHN3aXRjaCAodGFyZ2V0TGluay5kYXRhLnJvbGxUeXBlKSB7XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkFjdGlvbjogcmV0dXJuIEJsYWRlc0FjdGlvblJvbGw7XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkZvcnR1bmU6IHtcbiAgICAgICAgICAgICAgICBpZiAodGFyZ2V0TGluay5kYXRhLnJvbGxTdWJUeXBlID09PSBSb2xsU3ViVHlwZS5FbmdhZ2VtZW50KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNFbmdhZ2VtZW50Um9sbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAodGFyZ2V0TGluay5kYXRhLnJvbGxTdWJUeXBlID09PSBSb2xsU3ViVHlwZS5JbmNhcmNlcmF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNJbmNhcmNlcmF0aW9uUm9sbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIEJsYWRlc0ZvcnR1bmVSb2xsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBSb2xsVHlwZS5SZXNpc3RhbmNlOiB7XG4gICAgICAgICAgICAgICAgaWYgKHRhcmdldExpbmsuZGF0YS5pc0lubGluZVJlc2lzdGFuY2VSb2xsKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNJbmxpbmVSZXNpc3RhbmNlUm9sbDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIEJsYWRlc1Jlc2lzdGFuY2VSb2xsO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBSb2xsVHlwZS5JbmR1bGdlVmljZTogcmV0dXJuIEJsYWRlc0luZHVsZ2VWaWNlUm9sbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBjb25zdHJ1Y3RSb2xsQ29sbGFiX1NvY2tldENhbGwobGlua0RhdGEpIHtcbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yRXZlcnlvbmUoXCJjb25zdHJ1Y3RSb2xsQ29sbGFiX1NvY2tldENhbGxcIiwgbGlua0RhdGEpO1xuICAgIH1cbiAgICBzdGF0aWMgY29uc3RydWN0Um9sbENvbGxhYl9Tb2NrZXRSZXNwb25zZShsaW5rRGF0YSkge1xuICAgICAgICBjb25zdCByb2xsSW5zdCA9IG5ldyAodGhpcy5HZXRSb2xsU3ViQ2xhc3MobGlua0RhdGEpKShsaW5rRGF0YSk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwicm9sbENvbGxhYlwiLCBcImNvbnN0cnVjdFJvbGxDb2xsYWJfU29ja2V0UmVzcG9uc2UoKVwiLCB7IHBhcmFtczogeyBsaW5rRGF0YSB9LCByb2xsSW5zdCB9KTtcbiAgICAgICAgdGhpcy5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldFJlc3BvbnNlKHJvbGxJbnN0LmlkKTtcbiAgICB9XG4gICAgcmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsKCkge1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICB9XG4gICAgc3RhdGljIHJlbmRlclJvbGxDb2xsYWJfU29ja2V0UmVzcG9uc2UoaWQpIHtcbiAgICAgICAgY29uc3Qgcm9sbEluc3QgPSBnYW1lLmV1bm9ibGFkZXMuUm9sbHMuZ2V0KGlkKTtcbiAgICAgICAgaWYgKCFyb2xsSW5zdCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzUm9sbC5yZW5kZXJSb2xsQ29sbGFiX1NvY2tldFJlc3BvbnNlXSBObyByb2xsIGZvdW5kIHdpdGggaWQgJHtpZH0uYCk7XG4gICAgICAgIH1cbiAgICAgICAgcm9sbEluc3QucmVuZGVyUm9sbENvbGxhYigpO1xuICAgIH1cbiAgICBjbG9zZVJvbGxDb2xsYWJfQW5pbWF0aW9uKCkge1xuICAgICAgICByZXR1cm4gVS5nc2FwLmVmZmVjdHMuYmx1clJlbW92ZSh0aGlzLmVsZW0kLCB7IGlnbm9yZU1hcmdpbnM6IHRydWUgfSk7XG4gICAgfVxuICAgIGFzeW5jIGNsb3NlUm9sbENvbGxhYl9Tb2NrZXRDYWxsKCkge1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yT3RoZXJzKFwiY2xvc2VSb2xsQ29sbGFiX1NvY2tldENhbGxcIiwgdGhpcy5pZCk7XG4gICAgICAgIGF3YWl0IFUud2FpdEZvcih0aGlzLmNsb3NlUm9sbENvbGxhYl9BbmltYXRpb24oKSk7XG4gICAgfVxuICAgIHN0YXRpYyBjbG9zZVJvbGxDb2xsYWJfU29ja2V0UmVzcG9uc2UoaWQpIHtcbiAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLlJvbGxzLmdldChpZCk/LmNsb3NlUm9sbENvbGxhYl9BbmltYXRpb24oKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gKioqIENPTlNUUlVDVE9SICoqKiB+XG4gICAgcm9sbFBlcm1pc3Npb247XG4gICAgX3JvbGxQcmltYXJ5O1xuICAgIF9yb2xsT3Bwb3NpdGlvbjtcbiAgICBfcm9sbFBhcnRpY2lwYW50cztcbiAgICBwcm9qZWN0U2VsZWN0T3B0aW9ucztcbiAgICBjb25zdHJ1Y3RvcihkYXRhT3JDb25maWcpIHtcbiAgICAgICAgc3VwZXIoZGF0YU9yQ29uZmlnKTtcbiAgICAgICAgdGhpcy5yb2xsUGVybWlzc2lvbiA9IHRoaXMuZGF0YS51c2VyUGVybWlzc2lvbnNbZ2FtZS51c2VyLmlkXTtcbiAgICAgICAgdGhpcy5fcm9sbFByaW1hcnkgPSBuZXcgQmxhZGVzUm9sbFByaW1hcnkodGhpcywgdGhpcy5kYXRhLnJvbGxQcmltYXJ5RGF0YSk7XG4gICAgICAgIGlmICh0aGlzLmRhdGEucm9sbE9wcERhdGEpIHtcbiAgICAgICAgICAgIHRoaXMuX3JvbGxPcHBvc2l0aW9uID0gbmV3IEJsYWRlc1JvbGxPcHBvc2l0aW9uKHRoaXMsIHRoaXMuZGF0YS5yb2xsT3BwRGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5kYXRhLnJvbGxEb3dudGltZUFjdGlvbiA9PT0gRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0KSB7XG4gICAgICAgICAgICB0aGlzLnByb2plY3RTZWxlY3RPcHRpb25zID0gQXJyYXkuZnJvbShnYW1lLml0ZW1zKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGl0ZW0pID0+IEJsYWRlc0l0ZW0uSXNUeXBlKGl0ZW0sIEJsYWRlc0l0ZW1UeXBlLnByb2plY3QpKVxuICAgICAgICAgICAgICAgIC5tYXAoKHByb2plY3QpID0+ICh7IHZhbHVlOiBwcm9qZWN0LmlkID8/IFwiXCIsIGRpc3BsYXk6IHByb2plY3QubmFtZSB9KSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZGF0YS5yb2xsUGFydGljaXBhbnREYXRhKSB7XG4gICAgICAgICAgICB0aGlzLl9yb2xsUGFydGljaXBhbnRzID0ge307XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtyb2xsU2VjdGlvbiwgcm9sbFBhcnRpY2lwYW50TGlzdF0gb2YgT2JqZWN0LmVudHJpZXModGhpcy5kYXRhLnJvbGxQYXJ0aWNpcGFudERhdGEpKSB7XG4gICAgICAgICAgICAgICAgaWYgKFtSb2xsTW9kU2VjdGlvbi5yb2xsLCBSb2xsTW9kU2VjdGlvbi5wb3NpdGlvbiwgUm9sbE1vZFNlY3Rpb24uZWZmZWN0XVxuICAgICAgICAgICAgICAgICAgICAuaW5jbHVkZXMocm9sbFNlY3Rpb24pICYmICFVLmlzRW1wdHkocm9sbFBhcnRpY2lwYW50TGlzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgc2VjdGlvblBhcnRpY2lwYW50cyA9IHt9O1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGNvbnN0IFtwYXJ0aWNpcGFudFR5cGUsIHBhcnRpY2lwYW50RGF0YV0gb2YgT2JqZWN0LmVudHJpZXMocm9sbFBhcnRpY2lwYW50TGlzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlY3Rpb25QYXJ0aWNpcGFudHNbcGFydGljaXBhbnRUeXBlXSA9IG5ldyBCbGFkZXNSb2xsUGFydGljaXBhbnQodGhpcywgcm9sbFNlY3Rpb24sIHBhcnRpY2lwYW50VHlwZSwgcGFydGljaXBhbnREYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0aGlzLl9yb2xsUGFydGljaXBhbnRzW3JvbGxTZWN0aW9uXSA9IHNlY3Rpb25QYXJ0aWNpcGFudHM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGdhbWUuZXVub2JsYWRlcy5Sb2xscy5zZXQodGhpcy5pZCwgdGhpcyk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFJvbGwgUGFydGljaXBhdGlvbiAmIFVzZXIgUGVybWlzc2lvbnNcbiAgICBhc3luYyBhZGRSb2xsUGFydGljaXBhbnQocGFydGljaXBhbnRSZWYsIHJvbGxTZWN0aW9uLCByb2xsU3ViU2VjdGlvbikge1xuICAgICAgICBpZiAoIXJvbGxTdWJTZWN0aW9uKSB7XG4gICAgICAgICAgICAvKiBJbnNlcnQgbG9naWMgdG8gZGV0ZXJtaW5lIGZyb20gcm9sbFNlY3Rpb24gYW5kIG51bWJlciBvZiBleGlzdGluZyBHcm91cF9YIG1lbWJlcnMgKi9cbiAgICAgICAgICAgIHJvbGxTdWJTZWN0aW9uID0gXCJBc3Npc3RcIjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBwYXJ0aWNpcGFudERhdGEgPSB0eXBlb2YgcGFydGljaXBhbnRSZWYgPT09IFwic3RyaW5nXCJcbiAgICAgICAgICAgID8gZ2FtZS5hY3RvcnMuZ2V0KHBhcnRpY2lwYW50UmVmKVxuICAgICAgICAgICAgICAgID8/IGdhbWUuYWN0b3JzLmdldE5hbWUocGFydGljaXBhbnRSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5pdGVtcy5nZXQocGFydGljaXBhbnRSZWYpXG4gICAgICAgICAgICAgICAgPz8gZ2FtZS5pdGVtcy5nZXROYW1lKHBhcnRpY2lwYW50UmVmKVxuICAgICAgICAgICAgOiBwYXJ0aWNpcGFudFJlZjtcbiAgICAgICAgaWYgKCFCbGFkZXNSb2xsUGFydGljaXBhbnQuSXNWYWxpZERhdGEocGFydGljaXBhbnREYXRhKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQmFkIGRhdGEuXCIpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJvbGxQYXJ0aWNpcGFudCA9IG5ldyBCbGFkZXNSb2xsUGFydGljaXBhbnQodGhpcywgcm9sbFNlY3Rpb24sIHJvbGxTdWJTZWN0aW9uLCBwYXJ0aWNpcGFudERhdGEpO1xuICAgICAgICBhd2FpdCByb2xsUGFydGljaXBhbnQudXBkYXRlUm9sbEZsYWdzKCk7XG4gICAgICAgIGlmICh0aGlzLmlzUmVuZGVyZWQpIHtcbiAgICAgICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIHJlbW92ZVJvbGxQYXJ0aWNpcGFudChyb2xsU2VjdGlvbiwgcm9sbFN1YlNlY3Rpb24pIHtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoYHJvbGxQYXJ0aWNpcGFudERhdGEuJHtyb2xsU2VjdGlvbn0uJHtyb2xsU3ViU2VjdGlvbn1gLCBudWxsKTtcbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlVXNlclBlcm1pc3Npb24oX3VzZXIsIF9wZXJtaXNzaW9uKSB7XG4gICAgICAgIC8qIEZvcmNlLXJlbmRlciByb2xsIHdpdGggbmV3IHBlcm1pc3Npb25zICovXG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEJhc2ljIFVzZXIgRmxhZyBHZXR0ZXJzL1NldHRlcnMgflxuICAgIC8vIGdldCBkYXRhKCk6IEJsYWRlc1JvbGwuRmxhZ0RhdGEge1xuICAgIC8vICAgaWYgKCF0aGlzLmRvY3VtZW50LmdldEZsYWcoQy5TWVNURU1fSUQsIFwicm9sbENvbGxhYlwiKSkge1xuICAgIC8vICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbZ2V0IGZsYWdzKCldIE5vIFJvbGxDb2xsYWIgRmxhZ3MgRm91bmQgb24gVXNlciBEb2N1bWVudFwiKTtcbiAgICAvLyAgIH1cbiAgICAvLyAgIHJldHVybiB0aGlzLmRvY3VtZW50LmdldEZsYWcoQy5TWVNURU1fSUQsIFwicm9sbENvbGxhYlwiKSBhcyBCbGFkZXNSb2xsLkZsYWdEYXRhO1xuICAgIC8vIH1cbiAgICBnZXQgcm9sbFByaW1hcnkoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl9yb2xsUHJpbWFyeTtcbiAgICB9XG4gICAgZ2V0IHJvbGxQcmltYXJ5RG9jKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yb2xsUHJpbWFyeS5yb2xsUHJpbWFyeURvYztcbiAgICB9XG4gICAgZ2V0IHJvbGxPcHBvc2l0aW9uKCkge1xuICAgICAgICBpZiAoIXRoaXMuX3JvbGxPcHBvc2l0aW9uICYmIEJsYWRlc1JvbGxPcHBvc2l0aW9uLklzVmFsaWREYXRhKHRoaXMuZGF0YS5yb2xsT3BwRGF0YSkpIHtcbiAgICAgICAgICAgIHRoaXMuX3JvbGxPcHBvc2l0aW9uID0gbmV3IEJsYWRlc1JvbGxPcHBvc2l0aW9uKHRoaXMsIHRoaXMuZGF0YS5yb2xsT3BwRGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuX3JvbGxPcHBvc2l0aW9uPy5yZWZyZXNoKCk7XG4gICAgfVxuICAgIHNldCByb2xsT3Bwb3NpdGlvbih2YWwpIHtcbiAgICAgICAgaWYgKHZhbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICB0aGlzLl9yb2xsT3Bwb3NpdGlvbiA9IHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX3JvbGxPcHBvc2l0aW9uID0gdmFsO1xuICAgICAgICAgICAgdmFsLnVwZGF0ZVJvbGxGbGFncygpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGdldCByb2xsQ2xvY2tLZXkoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGEucm9sbENsb2NrS2V5XG4gICAgICAgICAgICA/IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KHRoaXMuZGF0YS5yb2xsQ2xvY2tLZXkpXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc2V0IHJvbGxDbG9ja0tleSh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJyb2xsQ2xvY2tLZXlJRFwiLCB2YWwgPz8gbnVsbCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIFRoaXMgbWV0aG9kIHByZXBhcmVzIHRoZSByb2xsIHBhcnRpY2lwYW50IGRhdGEuXG4gICAgICogSXQgaXRlcmF0ZXMgb3ZlciB0aGUgcm9sbCBzZWN0aW9ucyAocm9sbCwgcG9zaXRpb24sIGVmZmVjdCkgYW5kIGZvciBlYWNoIHNlY3Rpb24sXG4gICAgICogaXQgY3JlYXRlcyBhIG5ldyBCbGFkZXNSb2xsUGFydGljaXBhbnQgaW5zdGFuY2UgZm9yIGVhY2ggcGFydGljaXBhbnQgaW4gdGhhdCBzZWN0aW9uLlxuICAgICAqIFRoZSBjcmVhdGVkIGluc3RhbmNlcyBhcmUgc3RvcmVkIGluIHRoZSByb2xsUGFydGljaXBhbnRzIG9iamVjdC5cbiAgICAgKi9cbiAgICBwcmVwYXJlUm9sbFBhcnRpY2lwYW50RGF0YSgpIHtcbiAgICAgICAgY29uc3QgcGFydGljaXBhbnRGbGFnRGF0YSA9IHRoaXMuZGF0YS5yb2xsUGFydGljaXBhbnREYXRhO1xuICAgICAgICBpZiAoIXBhcnRpY2lwYW50RmxhZ0RhdGEpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCByb2xsUGFydGljaXBhbnRzID0ge307XG4gICAgICAgIFtcbiAgICAgICAgICAgIFJvbGxNb2RTZWN0aW9uLnJvbGwsXG4gICAgICAgICAgICBSb2xsTW9kU2VjdGlvbi5wb3NpdGlvbixcbiAgICAgICAgICAgIFJvbGxNb2RTZWN0aW9uLmVmZmVjdFxuICAgICAgICBdLmZvckVhY2goKHJvbGxTZWN0aW9uKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBzZWN0aW9uRmxhZ0RhdGEgPSBwYXJ0aWNpcGFudEZsYWdEYXRhW3JvbGxTZWN0aW9uXTtcbiAgICAgICAgICAgIGlmIChzZWN0aW9uRmxhZ0RhdGEpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBzZWN0aW9uUGFydGljaXBhbnRzID0ge307XG4gICAgICAgICAgICAgICAgT2JqZWN0LmVudHJpZXMoc2VjdGlvbkZsYWdEYXRhKS5mb3JFYWNoKChbc3ViU2VjdGlvbiwgc3ViU2VjdGlvbkZsYWdEYXRhXSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBpZiAoc3ViU2VjdGlvbkZsYWdEYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWN0aW9uUGFydGljaXBhbnRzW3N1YlNlY3Rpb25dID1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXcgQmxhZGVzUm9sbFBhcnRpY2lwYW50KHRoaXMsIHJvbGxTZWN0aW9uLCBzdWJTZWN0aW9uLCBzdWJTZWN0aW9uRmxhZ0RhdGEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcm9sbFBhcnRpY2lwYW50c1tyb2xsU2VjdGlvbl0gPSBzZWN0aW9uUGFydGljaXBhbnRzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5fcm9sbFBhcnRpY2lwYW50cyA9IHJvbGxQYXJ0aWNpcGFudHM7XG4gICAgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnRzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fcm9sbFBhcnRpY2lwYW50cztcbiAgICB9XG4gICAgZ2V0Um9sbFBhcnRpY2lwYW50KHNlY3Rpb24sIHN1YlNlY3Rpb24pIHtcbiAgICAgICAgaWYgKGlzUGFydGljaXBhbnRTZWN0aW9uKHNlY3Rpb24pICYmIGlzUGFydGljaXBhbnRTdWJTZWN0aW9uKHN1YlNlY3Rpb24pKSB7XG4gICAgICAgICAgICBjb25zdCBzZWN0aW9uRGF0YSA9IHRoaXMucm9sbFBhcnRpY2lwYW50cz8uW3NlY3Rpb25dO1xuICAgICAgICAgICAgaWYgKHNlY3Rpb25EYXRhKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNlY3Rpb25EYXRhW3N1YlNlY3Rpb25dID8/IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnRTZWxlY3RPcHRpb25zKCkge1xuICAgICAgICBjb25zdCBub25QcmltYXJ5UENzID0gQmxhZGVzUEMuQWxsXG4gICAgICAgICAgICAuZmlsdGVyKChhY3RvcikgPT4gYWN0b3IuaGFzVGFnKFRhZy5QQy5BY3RpdmVQQykgJiYgYWN0b3IuaWQgIT09IHRoaXMucm9sbFByaW1hcnkucm9sbFByaW1hcnlJRClcbiAgICAgICAgICAgIC5tYXAoKGFjdG9yKSA9PiAoeyB2YWx1ZTogYWN0b3IuaWQsIGRpc3BsYXk6IGFjdG9yLm5hbWUgfSkpO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgQXNzaXN0OiBub25QcmltYXJ5UENzLFxuICAgICAgICAgICAgU2V0dXA6IG5vblByaW1hcnlQQ3MsXG4gICAgICAgICAgICBHcm91cDogbm9uUHJpbWFyeVBDc1xuICAgICAgICB9O1xuICAgIH1cbiAgICBnZXQgcm9sbFR5cGUoKSB7IHJldHVybiB0aGlzLmRhdGEucm9sbFR5cGU7IH1cbiAgICBnZXQgcm9sbFN1YlR5cGUoKSB7IHJldHVybiB0aGlzLmRhdGEucm9sbFN1YlR5cGU7IH1cbiAgICBzZXQgcm9sbFN1YlR5cGUodmFsKSB7XG4gICAgICAgIHRoaXMudXBkYXRlVGFyZ2V0KFwicm9sbFN1YlR5cGVcIiwgdmFsID8/IG51bGwpO1xuICAgIH1cbiAgICBnZXQgcm9sbFBoYXNlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5kYXRhLnJvbGxQaGFzZSA/PyBSb2xsUGhhc2UuQ29sbGFib3JhdGlvbjtcbiAgICB9XG4gICAgZ2V0IHJvbGxEb3dudGltZUFjdGlvbigpIHsgcmV0dXJuIHRoaXMuZGF0YS5yb2xsRG93bnRpbWVBY3Rpb247IH1cbiAgICBnZXQgcm9sbFRyYWl0KCkgeyByZXR1cm4gdGhpcy5kYXRhLnJvbGxUcmFpdDsgfVxuICAgIGdldCByb2xsVHJhaXRWZXJiKCkge1xuICAgICAgICBpZiAoIXRoaXMucm9sbFRyYWl0KSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGlmICghKHRoaXMucm9sbFRyYWl0IGluIEMuQWN0aW9uVmVyYnMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBDLkFjdGlvblZlcmJzW3RoaXMucm9sbFRyYWl0XTtcbiAgICB9XG4gICAgZ2V0IHJvbGxUcmFpdFBhc3RWZXJiKCkge1xuICAgICAgICBpZiAoIXRoaXMucm9sbFRyYWl0KSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGlmICghKHRoaXMucm9sbFRyYWl0IGluIEMuQWN0aW9uUGFzdFZlcmJzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gQy5BY3Rpb25QYXN0VmVyYnNbdGhpcy5yb2xsVHJhaXRdO1xuICAgIH1cbiAgICBfcm9sbFRyYWl0VmFsT3ZlcnJpZGU7XG4gICAgZ2V0IHJvbGxUcmFpdFZhbE92ZXJyaWRlKCkgeyByZXR1cm4gdGhpcy5fcm9sbFRyYWl0VmFsT3ZlcnJpZGU7IH1cbiAgICBzZXQgcm9sbFRyYWl0VmFsT3ZlcnJpZGUodmFsKSB7IHRoaXMuX3JvbGxUcmFpdFZhbE92ZXJyaWRlID0gdmFsOyB9XG4gICAgZ2V0IHJvbGxUcmFpdERhdGEoKSB7XG4gICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcy5yb2xsUHJpbWFyeURvYywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgaWYgKGlzQWN0aW9uKHRoaXMucm9sbFRyYWl0KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IHRoaXMucm9sbFRyYWl0LFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5yb2xsVHJhaXRWYWxPdmVycmlkZSA/PyB0aGlzLnJvbGxQcmltYXJ5RG9jLmFjdGlvbnNbdGhpcy5yb2xsVHJhaXRdLFxuICAgICAgICAgICAgICAgICAgICBtYXg6IHRoaXMucm9sbFRyYWl0VmFsT3ZlcnJpZGUgPz8gdGhpcy5yb2xsUHJpbWFyeURvYy5hY3Rpb25zW3RoaXMucm9sbFRyYWl0XSxcbiAgICAgICAgICAgICAgICAgICAgcGNUb29sdGlwOiB0aGlzLnJvbGxQcmltYXJ5RG9jLnJvbGxUcmFpdFBDVG9vbHRpcEFjdGlvbnMsXG4gICAgICAgICAgICAgICAgICAgIGdtVG9vbHRpcDogQy5BY3Rpb25Ub29sdGlwc0dNW3RoaXMucm9sbFRyYWl0XVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNBdHRyaWJ1dGUodGhpcy5yb2xsVHJhaXQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogdGhpcy5yb2xsVHJhaXQsXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID8/IHRoaXMucm9sbFByaW1hcnlEb2MuYXR0cmlidXRlc1t0aGlzLnJvbGxUcmFpdF0sXG4gICAgICAgICAgICAgICAgICAgIG1heDogdGhpcy5yb2xsVHJhaXRWYWxPdmVycmlkZSA/PyB0aGlzLnJvbGxQcmltYXJ5RG9jLmF0dHJpYnV0ZXNbdGhpcy5yb2xsVHJhaXRdLFxuICAgICAgICAgICAgICAgICAgICBwY1Rvb2x0aXA6IHRoaXMucm9sbFByaW1hcnlEb2Mucm9sbFRyYWl0UENUb29sdGlwQXR0cmlidXRlcyxcbiAgICAgICAgICAgICAgICAgICAgZ21Ub29sdGlwOiBDLkF0dHJpYnV0ZVRvb2x0aXBzW3RoaXMucm9sbFRyYWl0XVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFUuaXNJbnQodGhpcy5yb2xsVHJhaXQpKSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIG5hbWU6IGArJHt0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID8/IHRoaXMucm9sbFRyYWl0fWAsXG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMucm9sbFRyYWl0VmFsT3ZlcnJpZGUgPz8gdGhpcy5yb2xsVHJhaXQsXG4gICAgICAgICAgICAgICAgbWF4OiB0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID8/IHRoaXMucm9sbFRyYWl0XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc0ZhY3Rvcih0aGlzLnJvbGxUcmFpdCkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbmFtZTogVS50Q2FzZSh0aGlzLnJvbGxUcmFpdCksXG4gICAgICAgICAgICAgICAgdmFsdWU6IHRoaXMucm9sbFRyYWl0VmFsT3ZlcnJpZGUgPz8gdGhpcy5yb2xsUHJpbWFyeS5yb2xsRmFjdG9yc1t0aGlzLnJvbGxUcmFpdF0/LnZhbHVlID8/IDAsXG4gICAgICAgICAgICAgICAgbWF4OiB0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID8/IHRoaXMucm9sbFByaW1hcnkucm9sbEZhY3RvcnNbdGhpcy5yb2xsVHJhaXRdPy5tYXggPz8gMTBcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbZ2V0IHJvbGxUcmFpdERhdGFdIEludmFsaWQgcm9sbFRyYWl0OiAnJHt0aGlzLnJvbGxUcmFpdH0nYCk7XG4gICAgfVxuICAgIGdldCByb2xsVHJhaXRPcHRpb25zKCkge1xuICAgICAgICBpZiAoQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMucm9sbFByaW1hcnlEb2MsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIGlmIChpc0FjdGlvbih0aGlzLnJvbGxUcmFpdCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyhBY3Rpb25UcmFpdClcbiAgICAgICAgICAgICAgICAgICAgLm1hcCgoYWN0aW9uKSA9PiAoe1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBVLnVDYXNlKGFjdGlvbiksXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiBhY3Rpb25cbiAgICAgICAgICAgICAgICB9KSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoaXNBdHRyaWJ1dGUodGhpcy5yb2xsVHJhaXQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoQXR0cmlidXRlVHJhaXQpXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKGF0dHJpYnV0ZSkgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogVS51Q2FzZShhdHRyaWJ1dGUpLFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogYXR0cmlidXRlXG4gICAgICAgICAgICAgICAgfSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChVLmlzSW50KHRoaXMucm9sbFRyYWl0KSkge1xuICAgICAgICAgICAgcmV0dXJuIFsxLCAyLCAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMF1cbiAgICAgICAgICAgICAgICAubWFwKChudW0pID0+ICh7XG4gICAgICAgICAgICAgICAgbmFtZTogYCske251bX1gLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBudW1cbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNGYWN0b3IodGhpcy5yb2xsVHJhaXQpKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbZ2V0IHJvbGxUcmFpdE9wdGlvbnNdIEludmFsaWQgcm9sbFRyYWl0OiAnJHt0aGlzLnJvbGxUcmFpdH0nYCk7XG4gICAgfVxuICAgIGdldCBwb3NFZmZlY3RUcmFkZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YT8ucm9sbFBvc0VmZmVjdFRyYWRlID8/IGZhbHNlO1xuICAgIH1cbiAgICAvLyBnZXRGbGFnVmFsPFQ+KGZsYWdLZXk/OiBzdHJpbmcpOiBUIHwgdW5kZWZpbmVkIHtcbiAgICAvLyAgIGlmIChmbGFnS2V5KSB7XG4gICAgLy8gICAgIHJldHVybiB0aGlzLmRvY3VtZW50LmdldEZsYWcoQy5TWVNURU1fSUQsIGByb2xsQ29sbGFiLiR7ZmxhZ0tleX1gLnJlcGxhY2UoLyhyb2xsQ29sbGFiXFwuKSsvZywgXCJyb2xsQ29sbGFiLlwiKSkgYXMgVCB8IHVuZGVmaW5lZDtcbiAgICAvLyAgIH1cbiAgICAvLyAgIHJldHVybiB0aGlzLmRvY3VtZW50LmdldEZsYWcoQy5TWVNURU1fSUQsIFwicm9sbENvbGxhYlwiKSBhcyBUIHwgdW5kZWZpbmVkO1xuICAgIC8vIH1cbiAgICAvLyBhc3luYyBzZXRGbGFnVmFsKGZsYWdLZXk6IHN0cmluZywgZmxhZ1ZhbDogdW5rbm93biwgaXNSZXJlbmRlcmluZyA9IHRydWUpIHtcbiAgICAvLyAgIGF3YWl0IHRoaXMuZG9jdW1lbnQuc2V0RmxhZyhDLlNZU1RFTV9JRCwgYHJvbGxDb2xsYWIuJHtmbGFnS2V5fWAucmVwbGFjZSgvKHJvbGxDb2xsYWJcXC4pKy9nLCBcInJvbGxDb2xsYWIuXCIpLCBmbGFnVmFsKTtcbiAgICAvLyAgIGlmIChpc1JlcmVuZGVyaW5nKSB7XG4gICAgLy8gICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpO1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICAvLyBhc3luYyBjbGVhckZsYWdWYWwoZmxhZ0tleTogc3RyaW5nLCBpc1JlcmVuZGVyaW5nID0gdHJ1ZSkge1xuICAgIC8vICAgYXdhaXQgdGhpcy5kb2N1bWVudC51bnNldEZsYWcoQy5TWVNURU1fSUQsIGByb2xsQ29sbGFiLiR7ZmxhZ0tleX1gLnJlcGxhY2UoLyhyb2xsQ29sbGFiXFwuKSsvZywgXCJyb2xsQ29sbGFiLlwiKSk7XG4gICAgLy8gICBpZiAoaXNSZXJlbmRlcmluZykge1xuICAgIC8vICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICAvLyAgIH1cbiAgICAvLyB9XG4gICAgZ2V0IGluaXRpYWxQb3NpdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZGF0YS5yb2xsUG9zaXRpb25Jbml0aWFsID8/IFBvc2l0aW9uLnJpc2t5O1xuICAgIH1cbiAgICBzZXQgaW5pdGlhbFBvc2l0aW9uKHZhbCkge1xuICAgICAgICB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxQb3NpdGlvbkluaXRpYWxcIiwgdmFsID8/IFBvc2l0aW9uLnJpc2t5KTtcbiAgICB9XG4gICAgZ2V0IGluaXRpYWxFZmZlY3QoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRhdGEucm9sbEVmZmVjdEluaXRpYWwgPz8gRWZmZWN0LnN0YW5kYXJkO1xuICAgIH1cbiAgICBzZXQgaW5pdGlhbEVmZmVjdCh2YWwpIHtcbiAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJyb2xsRWZmZWN0SW5pdGlhbFwiLCB2YWwgPz8gRWZmZWN0LnN0YW5kYXJkKTtcbiAgICB9XG4gICAgZ2V0IGlzQXBwbHlpbmdDb25zZXF1ZW5jZXMoKSB7XG4gICAgICAgIGlmICh0aGlzLnJvbGxUeXBlICE9PSBSb2xsVHlwZS5BY3Rpb24pIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMucm9sbFJlc3VsdCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICghW1JvbGxSZXN1bHQucGFydGlhbCwgUm9sbFJlc3VsdC5mYWlsXS5pbmNsdWRlcyh0aGlzLnJvbGxSZXN1bHQpKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIC8vIEdldCByb2xsQ29uc2VxdWVuY2UoKSAtLT4gRm9yIHJlc2lzdGFuY2Ugcm9sbHMuXG4gICAgZ2V0IHJvbGxDb25zZXF1ZW5jZSgpIHtcbiAgICAgICAgY29uc3QgeyBjb25zZXF1ZW5jZSB9ID0gdGhpcy5kYXRhLnJlc2lzdGFuY2VEYXRhID8/IHt9O1xuICAgICAgICBpZiAoIWNvbnNlcXVlbmNlPy5pZCkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZ2FtZS5ldW5vYmxhZGVzLkNvbnNlcXVlbmNlcy5nZXQoY29uc2VxdWVuY2UuaWQpXG4gICAgICAgICAgICA/PyBuZXcgQmxhZGVzQ29uc2VxdWVuY2UoY29uc2VxdWVuY2UpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBHRVRURVJTOiBERVJJVkVEIERBVEEgflxuICAgIGdldCByb2xsUG9zaXRpb25GaW5hbCgpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoUG9zaXRpb24pW1UuY2xhbXBOdW0oT2JqZWN0LnZhbHVlcyhQb3NpdGlvbikuaW5kZXhPZih0aGlzLmluaXRpYWxQb3NpdGlvbilcbiAgICAgICAgICAgICsgdGhpcy5nZXRNb2RzRGVsdGEoUm9sbE1vZFNlY3Rpb24ucG9zaXRpb24pXG4gICAgICAgICAgICArICh0aGlzLnBvc0VmZmVjdFRyYWRlID09PSBcInBvc2l0aW9uXCIgPyAxIDogMClcbiAgICAgICAgICAgICsgKHRoaXMucG9zRWZmZWN0VHJhZGUgPT09IFwiZWZmZWN0XCIgPyAtMSA6IDApLCBbMCwgMl0pXTtcbiAgICB9XG4gICAgZ2V0IHJvbGxFZmZlY3RGaW5hbCgpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoRWZmZWN0KVtVLmNsYW1wTnVtKE9iamVjdC52YWx1ZXMoRWZmZWN0KS5pbmRleE9mKHRoaXMuaW5pdGlhbEVmZmVjdClcbiAgICAgICAgICAgICsgdGhpcy5nZXRNb2RzRGVsdGEoUm9sbE1vZFNlY3Rpb24uZWZmZWN0KVxuICAgICAgICAgICAgKyAodGhpcy5wb3NFZmZlY3RUcmFkZSA9PT0gXCJlZmZlY3RcIiA/IDEgOiAwKVxuICAgICAgICAgICAgKyAodGhpcy5wb3NFZmZlY3RUcmFkZSA9PT0gXCJwb3NpdGlvblwiID8gLTEgOiAwKSwgWzAsIDRdKV07XG4gICAgfVxuICAgIGdldCByb2xsUmVzdWx0RGVsdGEoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldE1vZHNEZWx0YShSb2xsTW9kU2VjdGlvbi5yZXN1bHQpXG4gICAgICAgICAgICArICh0aGlzLmRhdGE/LkdNQm9vc3RzLlJlc3VsdCA/PyAwKVxuICAgICAgICAgICAgKyAodGhpcy50ZW1wR01Cb29zdHMuUmVzdWx0ID8/IDApO1xuICAgIH1cbiAgICBnZXQgcm9sbFJlc3VsdEZpbmFsKCkge1xuICAgICAgICBpZiAodGhpcy5yb2xsUmVzdWx0ID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnJvbGxSZXN1bHREZWx0YSA9PT0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucm9sbFJlc3VsdDtcbiAgICAgICAgfVxuICAgICAgICBzd2l0Y2ggKHRoaXMucm9sbFR5cGUpIHtcbiAgICAgICAgICAgIGNhc2UgUm9sbFR5cGUuQWN0aW9uOlxuICAgICAgICAgICAgY2FzZSBSb2xsVHlwZS5Gb3J0dW5lOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoUm9sbFJlc3VsdCkudG9SZXZlcnNlZCgpW1UuY2xhbXBOdW0oT2JqZWN0LnZhbHVlcyhSb2xsUmVzdWx0KS50b1JldmVyc2VkKCkuaW5kZXhPZih0aGlzLnJvbGxSZXN1bHQpXG4gICAgICAgICAgICAgICAgICAgICsgdGhpcy5yb2xsUmVzdWx0RGVsdGEsIFswLCAzXSldO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBSb2xsVHlwZS5SZXNpc3RhbmNlOiB7IC8vIFJldHVybiBzdHJlc3MgY29zdCBvZiByZXNpc3RpbmdcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5pc0NyaXRpY2FsKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIFUuY2xhbXBOdW0oNiAtIHRoaXMuaGlnaGVzdERpZVZhbCAtIHRoaXMucm9sbFJlc3VsdERlbHRhLCBbLTEsIEluZmluaXR5XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFJvbGxUeXBlLkluZHVsZ2VWaWNlOiB7IC8vIFJldHVybiBzdHJlc3MgY2xlYXJlZCBmcm9tIGluZHVsZ2luZ1xuICAgICAgICAgICAgICAgIHJldHVybiBVLmNsYW1wTnVtKHRoaXMuaGlnaGVzdERpZVZhbCArIHRoaXMucm9sbFJlc3VsdERlbHRhLCBbMCwgSW5maW5pdHldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGdldCBmaW5hbERpY2VQb29sKCkge1xuICAgICAgICByZXR1cm4gTWF0aC5tYXgoMCwgdGhpcy5yb2xsVHJhaXREYXRhLnZhbHVlXG4gICAgICAgICAgICArIHRoaXMuZ2V0TW9kc0RlbHRhKFJvbGxNb2RTZWN0aW9uLnJvbGwpXG4gICAgICAgICAgICArICh0aGlzLmRhdGEuR01Cb29zdHMuRGljZSA/PyAwKVxuICAgICAgICAgICAgKyAodGhpcy50ZW1wR01Cb29zdHMuRGljZSA/PyAwKSk7XG4gICAgfVxuICAgIGdldCBpc1JvbGxpbmdaZXJvKCkge1xuICAgICAgICByZXR1cm4gTWF0aC5tYXgoMCwgdGhpcy5yb2xsVHJhaXREYXRhLnZhbHVlXG4gICAgICAgICAgICArIHRoaXMuZ2V0TW9kc0RlbHRhKFJvbGxNb2RTZWN0aW9uLnJvbGwpXG4gICAgICAgICAgICArICh0aGlzLmRhdGEuR01Cb29zdHMuRGljZSA/PyAwKVxuICAgICAgICAgICAgKyAodGhpcy50ZW1wR01Cb29zdHMuRGljZSA/PyAwKSkgPD0gMDtcbiAgICB9XG4gICAgX3JvbGw7XG4gICAgZ2V0IHJvbGwoKSB7XG4gICAgICAgIHRoaXMuX3JvbGwgPz89IG5ldyBSb2xsKGAke3RoaXMuaXNSb2xsaW5nWmVybyA/IDIgOiB0aGlzLmZpbmFsRGljZVBvb2x9ZDZgLCB7fSk7XG4gICAgICAgIHJldHVybiB0aGlzLl9yb2xsO1xuICAgIH1cbiAgICBnZXQgcm9sbEZhY3RvcnMoKSB7XG4gICAgICAgIGNvbnN0IGRlZmF1bHRGYWN0b3JzID0ge1xuICAgICAgICAgICAgW0ZhY3Rvci50aWVyXToge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGllclwiLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAwLFxuICAgICAgICAgICAgICAgIG1heDogMCxcbiAgICAgICAgICAgICAgICBiYXNlVmFsOiAwLFxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IFwiP1wiLFxuICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc1ByaW1hcnk6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXM6IFwiZmFjdG9yLWdvbGRcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFtGYWN0b3IucXVhbGl0eV06IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlF1YWxpdHlcIixcbiAgICAgICAgICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgICAgICAgICBtYXg6IDAsXG4gICAgICAgICAgICAgICAgYmFzZVZhbDogMCxcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIj9cIixcbiAgICAgICAgICAgICAgICBpc0FjdGl2ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc0RvbWluYW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICBoaWdoRmF2b3JzUEM6IHRydWUsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJmYWN0b3ItZ29sZFwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgW0ZhY3Rvci5zY2FsZV06IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNjYWxlXCIsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDAsXG4gICAgICAgICAgICAgICAgbWF4OiAwLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IDAsXG4gICAgICAgICAgICAgICAgZGlzcGxheTogXCI/XCIsXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzUHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXM6IFwiZmFjdG9yLWdvbGRcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFtGYWN0b3IubWFnbml0dWRlXToge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTWFnbml0dWRlXCIsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDAsXG4gICAgICAgICAgICAgICAgbWF4OiAwLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IDAsXG4gICAgICAgICAgICAgICAgZGlzcGxheTogXCI/XCIsXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzUHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlLFxuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXM6IFwiZmFjdG9yLWdvbGRcIlxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBtZXJnZWRTb3VyY2VGYWN0b3JzID0gVS5vYmpNZXJnZShVLm9iak1lcmdlKGRlZmF1bHRGYWN0b3JzLCB0aGlzLnJvbGxQcmltYXJ5LnJvbGxGYWN0b3JzLCB7IGlzTXV0YXRpbmdPazogZmFsc2UgfSksIHRoaXMuZGF0YS5yb2xsRmFjdG9yVG9nZ2xlcy5zb3VyY2UsIHsgaXNNdXRhdGluZ09rOiBmYWxzZSB9KTtcbiAgICAgICAgY29uc3QgbWVyZ2VkT3BwRmFjdG9ycyA9IHRoaXMucm9sbE9wcG9zaXRpb25cbiAgICAgICAgICAgID8gVS5vYmpNZXJnZShVLm9iak1lcmdlKGRlZmF1bHRGYWN0b3JzLCB0aGlzLnJvbGxPcHBvc2l0aW9uLnJvbGxGYWN0b3JzLCB7IGlzTXV0YXRpbmdPazogZmFsc2UgfSksIHRoaXMuZGF0YS5yb2xsRmFjdG9yVG9nZ2xlcy5vcHBvc2l0aW9uLCB7IGlzTXV0YXRpbmdPazogZmFsc2UgfSlcbiAgICAgICAgICAgIDoge307XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBzb3VyY2U6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhtZXJnZWRTb3VyY2VGYWN0b3JzKVxuICAgICAgICAgICAgICAgIC5tYXAoKFtmYWN0b3IsIGZhY3RvckRhdGFdKSA9PiB7XG4gICAgICAgICAgICAgICAgZmFjdG9yRGF0YS52YWx1ZSArPVxuICAgICAgICAgICAgICAgICAgICAodGhpcy5kYXRhLkdNQm9vc3RzW2ZhY3Rvcl0gPz8gMClcbiAgICAgICAgICAgICAgICAgICAgICAgICsgKHRoaXMudGVtcEdNQm9vc3RzW2ZhY3Rvcl0gPz8gMCk7XG4gICAgICAgICAgICAgICAgaWYgKGZhY3RvciA9PT0gRmFjdG9yLnRpZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgZmFjdG9yRGF0YS5kaXNwbGF5ID0gVS5yb21hbml6ZU51bShmYWN0b3JEYXRhLnZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGZhY3RvckRhdGEuZGlzcGxheSA9IGAke2ZhY3RvckRhdGEudmFsdWV9YDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtmYWN0b3IsIGZhY3RvckRhdGFdO1xuICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgb3Bwb3NpdGlvbjogT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC5lbnRyaWVzKG1lcmdlZE9wcEZhY3RvcnMpXG4gICAgICAgICAgICAgICAgLm1hcCgoW2ZhY3RvciwgZmFjdG9yRGF0YV0pID0+IHtcbiAgICAgICAgICAgICAgICBmYWN0b3JEYXRhLnZhbHVlICs9IHRoaXMuZGF0YS5HTU9wcEJvb3N0c1tmYWN0b3JdID8/IDA7XG4gICAgICAgICAgICAgICAgaWYgKGZhY3RvciA9PT0gRmFjdG9yLnRpZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgZmFjdG9yRGF0YS5kaXNwbGF5ID0gVS5yb21hbml6ZU51bShmYWN0b3JEYXRhLnZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGZhY3RvckRhdGEuZGlzcGxheSA9IGAke2ZhY3RvckRhdGEudmFsdWV9YDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIFtmYWN0b3IsIGZhY3RvckRhdGFdO1xuICAgICAgICAgICAgfSkpXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFJPTEwgTU9EUzogR2V0dGVycyAmIFVwZGF0ZSBNZXRob2QgflxuICAgIGluaXRSb2xsTW9kcygpIHtcbiAgICAgICAgLy8gUmVzZXQgb3ZlcnJpZGUgdmFsdWVzIHByZXZpb3VzbHkgZW5hYmxlZCBieSByb2xsbW9kc1xuICAgICAgICB0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID0gdW5kZWZpbmVkO1xuICAgICAgICB0aGlzLnJvbGxGYWN0b3JQZW5hbHRpZXNOZWdhdGVkID0ge307XG4gICAgICAgIHRoaXMudGVtcEdNQm9vc3RzID0ge307XG4gICAgICAgIC8vIEVTTElOVCBESVNBQkxFOiBEZXYgQ29kZS5cbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIEB0eXBlc2NyaXB0LWVzbGludC9uby1leHBsaWNpdC1hbnlcbiAgICAgICAgY29uc3QgaW5pdFJlcG9ydCA9IHt9O1xuICAgICAgICBsZXQgaW5pdFJlcG9ydENvdW50ID0gMDtcbiAgICAgICAgY29uc3Qgd2F0Y2hNb2QgPSAobGFiZWwpID0+IHtcbiAgICAgICAgICAgIGlmIChCbGFkZXNSb2xsLkRlYnVnLm1vZFdhdGNoID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHJlcG9ydExhYmVsID0gYCgke2luaXRSZXBvcnRDb3VudH0pID09ICR7bGFiZWx9YDtcbiAgICAgICAgICAgIGNvbnN0IHJvbGxNb2QgPSB0aGlzLnJvbGxNb2RzXG4gICAgICAgICAgICAgICAgLmZpbmQoKG1vZCkgPT4gQmxhZGVzUm9sbC5EZWJ1Zy5tb2RXYXRjaCAmJiBCbGFkZXNSb2xsLkRlYnVnLm1vZFdhdGNoLmV4ZWMobW9kLm5hbWUpKTtcbiAgICAgICAgICAgIGlmIChyb2xsTW9kKSB7XG4gICAgICAgICAgICAgICAgaW5pdFJlcG9ydFtgJHtyZXBvcnRMYWJlbH0gOiAke3JvbGxNb2Quc3RhdHVzfWBdID0ge1xuICAgICAgICAgICAgICAgICAgICBpbnN0OiByb2xsTW9kLFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiB7IC4uLnJvbGxNb2QuZGF0YSB9LFxuICAgICAgICAgICAgICAgICAgICBzb3VyY2VOYW1lOiByb2xsTW9kLnNvdXJjZU5hbWUsXG4gICAgICAgICAgICAgICAgICAgIHN0YXR1czoge1xuICAgICAgICAgICAgICAgICAgICAgICAgQUxMOiByb2xsTW9kLnN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGJhc2U6IHJvbGxNb2QuYmFzZVN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhlbGQ6IHJvbGxNb2QuaGVsZFN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHVzZXI6IHJvbGxNb2QudXNlclN0YXR1c1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBpczoge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aXZlOiByb2xsTW9kLmlzQWN0aXZlLFxuICAgICAgICAgICAgICAgICAgICAgICAgdmlzaWJsZTogcm9sbE1vZC5pc1Zpc2libGUsXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25kaXRpb25hbDogcm9sbE1vZC5pc0NvbmRpdGlvbmFsLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5JbmFjdGl2ZUJsb2NrOiByb2xsTW9kLmlzSW5JbmFjdGl2ZUJsb2NrLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNQdXNoOiByb2xsTW9kLmlzUHVzaCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQmFzaWNQdXNoOiByb2xsTW9kLmlzQmFzaWNQdXNoXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgaW5pdFJlcG9ydFtyZXBvcnRMYWJlbF0gPSBcIk1PRCBOT1QgRk9VTkRcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGluaXRSZXBvcnRDb3VudCsrO1xuICAgICAgICB9O1xuICAgICAgICB3YXRjaE1vZChcIklOSVRJQUxcIik7XG4gICAgICAgIC8qICoqKiBQQVNTIFpFUk86IFJPTExUWVBFIFZBTElEQVRJT04gUEFTUyAqKiogKi9cbiAgICAgICAgdGhpcy5fcm9sbE1vZHMgPSB0aGlzLnJvbGxNb2RzLmZpbHRlcigocm9sbE1vZCkgPT4gcm9sbE1vZC5pc1ZhbGlkRm9yUm9sbFR5cGUoKSk7XG4gICAgICAgIHdhdGNoTW9kKFwiUk9MTFRZUEUgVkFMSURBVElPTlwiKTtcbiAgICAgICAgLyogKioqIFBBU1MgT05FOiBESVNBQkxFIFBBU1MgKioqICovXG4gICAgICAgIC8vIC4uLiBDb25kaXRpb25hbCBTdGF0dXMgUGFzc1xuICAgICAgICBjb25zdCBjb25kaXRpb25hbERpc2FibGVQYXNzID0gdGhpcy5yb2xsTW9kcy5maWx0ZXIoKHJvbGxNb2QpID0+ICFyb2xsTW9kLnNldENvbmRpdGlvbmFsU3RhdHVzKCkpO1xuICAgICAgICB3YXRjaE1vZChcIkRJU0FCTEUgLSBDT05ESVRJT05BTFwiKTtcbiAgICAgICAgLy8gLi4uIEF1dG9SZXZlYWwvQXV0b0VuYWJsZSBQYXNzXG4gICAgICAgIGNvbnN0IGF1dG9SZXZlYWxEaXNhYmxlUGFzcyA9IGNvbmRpdGlvbmFsRGlzYWJsZVBhc3MuZmlsdGVyKChyb2xsTW9kKSA9PiAhcm9sbE1vZC5zZXRBdXRvU3RhdHVzKCkpO1xuICAgICAgICB3YXRjaE1vZChcIkRJU0FCTEUgLSBBVVRPLVJFVkVBTC9FTkFCTEVcIik7XG4gICAgICAgIC8vIC4uLiBQYXlhYmxlIFBhc3NcbiAgICAgICAgYXV0b1JldmVhbERpc2FibGVQYXNzLmZvckVhY2goKHJvbGxNb2QpID0+IHsgcm9sbE1vZC5zZXRQYXlhYmxlU3RhdHVzKCk7IH0pO1xuICAgICAgICB3YXRjaE1vZChcIkRJU0FCTEUgLSBQQVlBQkxFXCIpO1xuICAgICAgICAvKiAqKiogUEFTUyBUV086IEZPUkNFLU9OIFBBU1MgKioqICovXG4gICAgICAgIGNvbnN0IHBhcnNlRm9yY2VPbktleXMgPSAobW9kKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBob2xkS2V5cyA9IG1vZC5lZmZlY3RLZXlzLmZpbHRlcigoa2V5KSA9PiBrZXkuc3RhcnRzV2l0aChcIkZvcmNlT25cIikpO1xuICAgICAgICAgICAgaWYgKGhvbGRLZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHdoaWxlIChob2xkS2V5cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB0aGlzVGFyZ2V0ID0gaG9sZEtleXMucG9wKCk/LnNwbGl0KC8tLyk/LnBvcCgpO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzVGFyZ2V0ID09PSBcIkJlc3RBY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoQmxhZGVzUEMuSXNUeXBlKHRoaXMucm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGxUcmFpdFZhbE92ZXJyaWRlID0gTWF0aC5tYXgoLi4uT2JqZWN0LnZhbHVlcyh0aGlzLnJvbGxQcmltYXJ5RG9jLmFjdGlvbnMpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgW3RhcmdldE5hbWUsIHRhcmdldENhdCwgdGFyZ2V0UG9zTmVnXSA9IHRoaXNUYXJnZXQ/LnNwbGl0KC8sLykgPz8gW107XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0TmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBObyB0YXJnZXROYW1lIGZvdW5kIGluIHRoaXNUYXJnZXQ6ICR7dGhpc1RhcmdldH0uYCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgbGV0IHRhcmdldE1vZCA9IHRoaXMuZ2V0Um9sbE1vZEJ5TmFtZSh0YXJnZXROYW1lKVxuICAgICAgICAgICAgICAgICAgICAgICAgPz8gdGhpcy5nZXRSb2xsTW9kQnlOYW1lKHRhcmdldE5hbWUsIHRhcmdldENhdCA/PyBtb2Quc2VjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0TW9kICYmIHRhcmdldE5hbWUgPT09IFwiUHVzaFwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBbdGFyZ2V0TW9kXSA9IFtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi50aGlzLmdldEFjdGl2ZUJhc2ljUHVzaE1vZHModGFyZ2V0Q2F0ID8/IG1vZC5zZWN0aW9uLCBcIm5lZ2F0aXZlXCIpLmZpbHRlcigobSkgPT4gbS5zdGF0dXMgPT09IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9uKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi50aGlzLmdldEFjdGl2ZUJhc2ljUHVzaE1vZHModGFyZ2V0Q2F0ID8/IG1vZC5zZWN0aW9uLCBcInBvc2l0aXZlXCIpLmZpbHRlcigobSkgPT4gbS5zdGF0dXMgPT09IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9uKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuLi50aGlzLmdldEluYWN0aXZlQmFzaWNQdXNoTW9kcyh0YXJnZXRDYXQgPz8gbW9kLnNlY3Rpb24sIFwicG9zaXRpdmVcIikuZmlsdGVyKChtKSA9PiBtLnN0YXR1cyA9PT0gUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmKVxuICAgICAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB0YXJnZXRNb2QgPz89IHRoaXMuZ2V0Um9sbE1vZEJ5TmFtZSh0YXJnZXROYW1lLCB0YXJnZXRDYXQgPz8gbW9kLnNlY3Rpb24sIHRhcmdldFBvc05lZyA/PyBtb2QucG9zTmVnKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0YXJnZXRNb2QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gbW9kIGZvdW5kIG1hdGNoaW5nICR7dGFyZ2V0TmFtZX0vJHt0YXJnZXRDYXR9LyR7dGFyZ2V0UG9zTmVnfWApO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0TW9kLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRNb2QuaGVsZFN0YXR1cyA9IFJvbGxNb2RTdGF0dXMuRm9yY2VkT247XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJzZUZvcmNlT25LZXlzKHRhcmdldE1vZCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRNb2QuaGVsZFN0YXR1cyA9IFJvbGxNb2RTdGF0dXMuRm9yY2VkT247XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0QWN0aXZlUm9sbE1vZHMoKS5mb3JFYWNoKChyb2xsTW9kKSA9PiBwYXJzZUZvcmNlT25LZXlzKHJvbGxNb2QpKTtcbiAgICAgICAgd2F0Y2hNb2QoXCJGT1JDRS1PTiBQQVNTXCIpO1xuICAgICAgICAvKiAqKiogUEFTUyBUSFJFRTogUFVTSC1DSEVDSyBQQVNTICoqKiAqL1xuICAgICAgICAvLyBJRiBST0xMIEZPUkNFRCAuLi5cbiAgICAgICAgaWYgKHRoaXMuaXNGb3JjZVB1c2hlZCgpKSB7XG4gICAgICAgICAgICAvLyAuLi4gRm9yY2UgT2ZmIF9BTExfIHZpc2libGUsIGluYWN0aXZlIFwiSXMtUHVzaFwiIG1vZHMuXG4gICAgICAgICAgICB0aGlzLmdldEluYWN0aXZlUHVzaE1vZHMoKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKG1vZCkgPT4gIW1vZC5pc0Jhc2ljUHVzaClcbiAgICAgICAgICAgICAgICAuZm9yRWFjaCgobW9kKSA9PiB7IG1vZC5oZWxkU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Gb3JjZWRPZmY7IH0pO1xuICAgICAgICAgICAgd2F0Y2hNb2QoXCJQVVNILUNIRUNLOiBGT1JDRS1PRkYgSVMtUFVTSFwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyAuLi4gQlkgQ0FURUdPUlkgLi4uXG4gICAgICAgIFtSb2xsTW9kU2VjdGlvbi5yb2xsLCBSb2xsTW9kU2VjdGlvbi5lZmZlY3RdLmZvckVhY2goKGNhdCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNQdXNoZWQoY2F0KSkge1xuICAgICAgICAgICAgICAgIC8vIC4uLiBpZiBwdXNoZWQgYnkgcG9zaXRpdmUgbW9kLCBGb3JjZSBPZmYgYW55IHZpc2libGUgQmFyZ2FpblxuICAgICAgICAgICAgICAgIGlmIChjYXQgPT09IFJvbGxNb2RTZWN0aW9uLnJvbGwgJiYgdGhpcy5pc1B1c2hlZChjYXQsIFwicG9zaXRpdmVcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgYmFyZ2Fpbk1vZCA9IHRoaXMuZ2V0Um9sbE1vZEJ5S2V5KFwiQmFyZ2Fpbi1wb3NpdGl2ZS1yb2xsXCIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoYmFyZ2Fpbk1vZD8uaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBiYXJnYWluTW9kLmhlbGRTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB3YXRjaE1vZChcIlBVU0gtQ0hFQ0s6IEZPUkNFIE9GRiBCQVJHQUlOXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gT3RoZXJ3aXNlLCBoaWRlIGFsbCBJcy1QdXNoIG1vZHNcbiAgICAgICAgICAgICAgICB0aGlzLmdldEluYWN0aXZlUHVzaE1vZHMoY2F0KVxuICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChtb2QpID0+ICFtb2QuaXNCYXNpY1B1c2gpXG4gICAgICAgICAgICAgICAgICAgIC5mb3JFYWNoKChtb2QpID0+IHsgbW9kLmhlbGRTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkhpZGRlbjsgfSk7XG4gICAgICAgICAgICAgICAgd2F0Y2hNb2QoXCJQVVNILUNIRUNLOiBISURFIElTLVBVU0hcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICAvKiAqKiogUEFTUyBGT1VSOiBSZWxldmFuY3kgUGFzcyAqKiogKi9cbiAgICAgICAgdGhpcy5nZXRWaXNpYmxlUm9sbE1vZHMoKVxuICAgICAgICAgICAgLmZvckVhY2goKG1vZCkgPT4geyBtb2Quc2V0UmVsZXZhbmN5U3RhdHVzKCk7IH0pO1xuICAgICAgICB3YXRjaE1vZChcIlJFTEVWQU5DWSBQQVNTXCIpO1xuICAgICAgICAvKiAqKiogUEFTUyBGSVZFOiBPdmVycGF5bWVudCBQYXNzICoqKiAqL1xuICAgICAgICAvLyAuLi4gSWYgJ0Nvc3QtU3BlY2lhbEFybW9yJyBhY3RpdmUsIEZvcmNlT2ZmIG90aGVyIHZpc2libGUgQ29zdC1TcGVjaWFsQXJtb3IgbW9kc1xuICAgICAgICBjb25zdCBhY3RpdmVBcm1vckNvc3RNb2QgPSB0aGlzLmdldEFjdGl2ZVJvbGxNb2RzKCkuZmluZCgobW9kKSA9PiBtb2QuZWZmZWN0S2V5cy5pbmNsdWRlcyhcIkNvc3QtU3BlY2lhbEFybW9yXCIpKTtcbiAgICAgICAgaWYgKGFjdGl2ZUFybW9yQ29zdE1vZCkge1xuICAgICAgICAgICAgdGhpcy5nZXRWaXNpYmxlUm9sbE1vZHMoKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKG1vZCkgPT4gIW1vZC5pc0FjdGl2ZSAmJiBtb2QuZWZmZWN0S2V5cy5pbmNsdWRlcyhcIkNvc3QtU3BlY2lhbEFybW9yXCIpKVxuICAgICAgICAgICAgICAgIC5mb3JFYWNoKChtb2QpID0+IHsgbW9kLmhlbGRTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZjsgfSk7XG4gICAgICAgICAgICB3YXRjaE1vZChcIk9WRVJQQVlNRU5UIFBBU1NcIik7XG4gICAgICAgIH1cbiAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJyb2xsTW9kc1wiLCBcIioqKiBpbml0Um9sbE1vZHMoKSBQQVNTICoqKlwiLCBpbml0UmVwb3J0KTtcbiAgICB9XG4gICAgaXNUcmFpdFJlbGV2YW50KHRyYWl0KSB7XG4gICAgICAgIGlmICh0cmFpdCBpbiBGYWN0b3IpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgc291cmNlLCBvcHBvc2l0aW9uIH0gPSB0aGlzLnJvbGxGYWN0b3JzO1xuICAgICAgICAgICAgcmV0dXJuIEJvb2xlYW4odHJhaXQgaW4gc291cmNlICYmIHRyYWl0IGluIG9wcG9zaXRpb24gJiYgc291cmNlW3RyYWl0XT8uaXNBY3RpdmUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgZ2V0IGlzUGFydGljaXBhbnRSb2xsKCkge1xuICAgICAgICByZXR1cm4gKHRoaXMucm9sbFR5cGUgPT09IFJvbGxUeXBlLkZvcnR1bmUgJiYgIWdhbWUudXNlci5pc0dNKVxuICAgICAgICAgICAgfHwgKHRoaXMucm9sbFN1YlR5cGUgPT09IFJvbGxTdWJUeXBlLkdyb3VwUGFydGljaXBhbnQpO1xuICAgIH1cbiAgICBuZWdhdGVQdXNoQ29zdCgpIHtcbiAgICAgICAgY29uc3QgY29zdGx5UHVzaE1vZCA9IHRoaXMuZ2V0QWN0aXZlUm9sbE1vZHMoKVxuICAgICAgICAgICAgLmZpbmQoKG1vZCkgPT4gbW9kLmlzUHVzaCAmJiBtb2Quc3RyZXNzQ29zdCA+IDApO1xuICAgICAgICBpZiAoY29zdGx5UHVzaE1vZCkge1xuICAgICAgICAgICAgVS5wdWxsRWxlbWVudChjb3N0bHlQdXNoTW9kLmVmZmVjdEtleXMsIChrKSA9PiBrLnN0YXJ0c1dpdGgoXCJDb3N0LVN0cmVzc1wiKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcm9sbEZhY3RvclBlbmFsdGllc05lZ2F0ZWQgPSB7fTtcbiAgICBuZWdhdGVGYWN0b3JQZW5hbHR5KGZhY3Rvcikge1xuICAgICAgICB0aGlzLnJvbGxGYWN0b3JQZW5hbHRpZXNOZWdhdGVkW2ZhY3Rvcl0gPSB0cnVlO1xuICAgIH1cbiAgICB0ZW1wR01Cb29zdHMgPSB7fTtcbiAgICBpc1B1c2hlZChjYXQsIHBvc05lZykgeyByZXR1cm4gdGhpcy5nZXRBY3RpdmVCYXNpY1B1c2hNb2RzKGNhdCwgcG9zTmVnKS5sZW5ndGggPiAwOyB9XG4gICAgaGFzT3BlblB1c2goY2F0LCBwb3NOZWcpIHsgcmV0dXJuIHRoaXMuaXNQdXNoZWQoY2F0KSAmJiB0aGlzLmdldE9wZW5QdXNoTW9kcyhjYXQsIHBvc05lZykubGVuZ3RoID4gMDsgfVxuICAgIGlzRm9yY2VQdXNoZWQoY2F0LCBwb3NOZWcpIHsgcmV0dXJuIHRoaXMuaXNQdXNoZWQoY2F0KSAmJiB0aGlzLmdldEZvcmNlZFB1c2hNb2RzKGNhdCwgcG9zTmVnKS5sZW5ndGggPiAwOyB9XG4gICAgZ2V0IHJvbGxDb3N0cygpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUHVzaGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBoYXJtUHVzaCA9IHRoaXMuZ2V0Um9sbE1vZEJ5S2V5KFwiUHVzaC1uZWdhdGl2ZS1yb2xsXCIpO1xuICAgICAgICBjb25zdCByb2xsUHVzaCA9IHRoaXMuZ2V0Um9sbE1vZEJ5S2V5KFwiUHVzaC1wb3NpdGl2ZS1yb2xsXCIpO1xuICAgICAgICBjb25zdCBlZmZlY3RQdXNoID0gdGhpcy5nZXRSb2xsTW9kQnlLZXkoXCJQdXNoLXBvc2l0aXZlLWVmZmVjdFwiKTtcbiAgICAgICAgY29uc3QgbmVnYXRlUHVzaENvc3RNb2RzID0gdGhpcy5nZXRBY3RpdmVSb2xsTW9kcyhSb2xsTW9kU2VjdGlvbi5hZnRlciwgXCJwb3NpdGl2ZVwiKVxuICAgICAgICAgICAgLmZpbHRlcigobW9kKSA9PiBtb2QuZWZmZWN0S2V5cy5pbmNsdWRlcyhcIk5lZ2F0ZS1QdXNoQ29zdFwiKSk7XG4gICAgICAgIHJldHVybiAoKGhhcm1QdXNoPy5pc0FjdGl2ZSAmJiBoYXJtUHVzaD8uc3RyZXNzQ29zdCkgfHwgMClcbiAgICAgICAgICAgICsgKChyb2xsUHVzaD8uaXNBY3RpdmUgJiYgcm9sbFB1c2g/LnN0cmVzc0Nvc3QpIHx8IDApXG4gICAgICAgICAgICArICgoZWZmZWN0UHVzaD8uaXNBY3RpdmUgJiYgZWZmZWN0UHVzaD8uc3RyZXNzQ29zdCkgfHwgMClcbiAgICAgICAgICAgIC0gKG5lZ2F0ZVB1c2hDb3N0TW9kcy5sZW5ndGggKiAyKTtcbiAgICB9XG4gICAgZ2V0IHJvbGxDb3N0RGF0YSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QWN0aXZlUm9sbE1vZHMoKVxuICAgICAgICAgICAgLm1hcCgocm9sbE1vZCkgPT4gcm9sbE1vZC5jb3N0cyA/PyBbXSlcbiAgICAgICAgICAgIC5mbGF0KCk7XG4gICAgfVxuICAgIGdldFJvbGxNb2RCeUlEKGlkKSB7IHJldHVybiB0aGlzLnJvbGxNb2RzLmZpbmQoKHJvbGxNb2QpID0+IHJvbGxNb2QuaWQgPT09IGlkKTsgfVxuICAgIGdldFJvbGxNb2RCeU5hbWUobmFtZSwgY2F0LCBwb3NOZWcpIHtcbiAgICAgICAgY29uc3QgbW9kTWF0Y2hlcyA9IHRoaXMucm9sbE1vZHMuZmlsdGVyKChyb2xsTW9kKSA9PiB7XG4gICAgICAgICAgICBpZiAoVS5sQ2FzZShyb2xsTW9kLm5hbWUpICE9PSBVLmxDYXNlKG5hbWUpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGNhdCAmJiByb2xsTW9kLnNlY3Rpb24gIT09IGNhdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwb3NOZWcgJiYgcm9sbE1vZC5wb3NOZWcgIT09IHBvc05lZykge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9KTtcbiAgICAgICAgaWYgKG1vZE1hdGNoZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChtb2RNYXRjaGVzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG1vZE1hdGNoZXNbMF07XG4gICAgfVxuICAgIGdldFJvbGxNb2RCeUtleShrZXkpIHsgcmV0dXJuIHRoaXMucm9sbE1vZHMuZmluZCgocm9sbE1vZCkgPT4gcm9sbE1vZC5kYXRhLmtleSA9PT0ga2V5KTsgfVxuICAgIGdldFJvbGxNb2RzKGNhdCwgcG9zTmVnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJvbGxNb2RzLmZpbHRlcigocm9sbE1vZCkgPT4gKCFjYXQgfHwgcm9sbE1vZC5zZWN0aW9uID09PSBjYXQpXG4gICAgICAgICAgICAmJiAoIXBvc05lZyB8fCByb2xsTW9kLnBvc05lZyA9PT0gcG9zTmVnKSk7XG4gICAgfVxuICAgIGdldFZpc2libGVSb2xsTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSb2xsTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzVmlzaWJsZSk7XG4gICAgfVxuICAgIGdldEFjdGl2ZVJvbGxNb2RzKGNhdCwgcG9zTmVnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFJvbGxNb2RzKGNhdCwgcG9zTmVnKS5maWx0ZXIoKHJvbGxNb2QpID0+IHJvbGxNb2QuaXNBY3RpdmUpO1xuICAgIH1cbiAgICBnZXRWaXNpYmxlSW5hY3RpdmVSb2xsTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRWaXNpYmxlUm9sbE1vZHMoY2F0LCBwb3NOZWcpLmZpbHRlcigocm9sbE1vZCkgPT4gIXJvbGxNb2QuaXNBY3RpdmUpO1xuICAgIH1cbiAgICBnZXRQdXNoTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRSb2xsTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzUHVzaCk7XG4gICAgfVxuICAgIGdldFZpc2libGVQdXNoTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRQdXNoTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzVmlzaWJsZSk7XG4gICAgfVxuICAgIGdldEFjdGl2ZVB1c2hNb2RzKGNhdCwgcG9zTmVnKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFZpc2libGVQdXNoTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzQWN0aXZlKTtcbiAgICB9XG4gICAgZ2V0QWN0aXZlQmFzaWNQdXNoTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRBY3RpdmVQdXNoTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzQmFzaWNQdXNoKTtcbiAgICB9XG4gICAgZ2V0SW5hY3RpdmVQdXNoTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRWaXNpYmxlUHVzaE1vZHMoY2F0LCBwb3NOZWcpLmZpbHRlcigocm9sbE1vZCkgPT4gIXJvbGxNb2QuaXNBY3RpdmUpO1xuICAgIH1cbiAgICBnZXRJbmFjdGl2ZUJhc2ljUHVzaE1vZHMoY2F0LCBwb3NOZWcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0SW5hY3RpdmVQdXNoTW9kcyhjYXQsIHBvc05lZykuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzQmFzaWNQdXNoKTtcbiAgICB9XG4gICAgZ2V0Rm9yY2VkUHVzaE1vZHMoY2F0LCBwb3NOZWcpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QWN0aXZlUHVzaE1vZHMoY2F0LCBwb3NOZWcpXG4gICAgICAgICAgICAuZmlsdGVyKChyb2xsTW9kKSA9PiByb2xsTW9kLmlzQmFzaWNQdXNoXG4gICAgICAgICAgICAmJiByb2xsTW9kLnN0YXR1cyA9PT0gUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbik7XG4gICAgfVxuICAgIGdldE9wZW5QdXNoTW9kcyhjYXQsIHBvc05lZykge1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRBY3RpdmVQdXNoTW9kcyhjYXQsIHBvc05lZylcbiAgICAgICAgICAgIC5maWx0ZXIoKHJvbGxNb2QpID0+IHJvbGxNb2QuaXNCYXNpY1B1c2hcbiAgICAgICAgICAgICYmIHJvbGxNb2Quc3RhdHVzID09PSBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPbik7XG4gICAgfVxuICAgIGdldE1vZHNEZWx0YSA9IChjYXQpID0+IHtcbiAgICAgICAgcmV0dXJuIFUuc3VtKFtcbiAgICAgICAgICAgIC4uLnRoaXMuZ2V0QWN0aXZlUm9sbE1vZHMoY2F0LCBcInBvc2l0aXZlXCIpLm1hcCgobW9kKSA9PiBtb2QudmFsdWUpLFxuICAgICAgICAgICAgLi4udGhpcy5nZXRBY3RpdmVSb2xsTW9kcyhjYXQsIFwibmVnYXRpdmVcIikubWFwKChtb2QpID0+IC1tb2QudmFsdWUpXG4gICAgICAgIF0pO1xuICAgIH07XG4gICAgX3JvbGxNb2RzO1xuICAgIC8qKlxuICAgICAqIENvbXBhcmUgZnVuY3Rpb24gZm9yIHNvcnRpbmcgcm9sbCBtb2RzLlxuICAgICAqIEBwYXJhbSB7QmxhZGVzUm9sbE1vZH0gbW9kQSBGaXJzdCBtb2QgdG8gY29tcGFyZS5cbiAgICAgKiBAcGFyYW0ge0JsYWRlc1JvbGxNb2R9IG1vZEIgU2Vjb25kIG1vZCB0byBjb21wYXJlLlxuICAgICAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQ29tcGFyaXNvbiByZXN1bHQuXG4gICAgICovXG4gICAgY29tcGFyZU1vZHMobW9kQSwgbW9kQikge1xuICAgICAgICAvLyBEZWZpbmUgdGhlIG9yZGVyIG9mIG1vZCBuYW1lcyBmb3Igc29ydGluZ1xuICAgICAgICBjb25zdCBtb2RPcmRlciA9IFtcIkJhcmdhaW5cIiwgXCJBc3Npc3RcIiwgXCJTZXR1cFwiXTtcbiAgICAgICAgLy8gQ2hlY2sgZm9yIGJhc2ljIHB1c2hcbiAgICAgICAgaWYgKG1vZEEuaXNCYXNpY1B1c2gpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobW9kQi5pc0Jhc2ljUHVzaCkge1xuICAgICAgICAgICAgcmV0dXJuIDE7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ2hlY2sgZm9yIGFjdGl2ZSBCYXJnYWluXG4gICAgICAgIGlmIChtb2RBLm5hbWUgPT09IFwiQmFyZ2FpblwiICYmIG1vZEEuaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobW9kQi5uYW1lID09PSBcIkJhcmdhaW5cIiAmJiBtb2RCLmlzQWN0aXZlKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuICAgICAgICAvLyBDaGVjayBmb3IgcHVzaFxuICAgICAgICBpZiAobW9kQS5pc1B1c2gpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAobW9kQi5pc1B1c2gpIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICAgIC8vIENoZWNrIGZvciBtb2QgbmFtZSBvcmRlclxuICAgICAgICBjb25zdCBtb2RBSW5kZXggPSBtb2RPcmRlci5pbmRleE9mKG1vZEEubmFtZSk7XG4gICAgICAgIGNvbnN0IG1vZEJJbmRleCA9IG1vZE9yZGVyLmluZGV4T2YobW9kQi5uYW1lKTtcbiAgICAgICAgaWYgKG1vZEFJbmRleCAhPT0gLTEgJiYgbW9kQkluZGV4ICE9PSAtMSkge1xuICAgICAgICAgICAgcmV0dXJuIG1vZEFJbmRleCAtIG1vZEJJbmRleDtcbiAgICAgICAgfVxuICAgICAgICAvLyBEZWZhdWx0IHRvIGFscGhhYmV0aWNhbCBvcmRlclxuICAgICAgICByZXR1cm4gbW9kQS5uYW1lLmxvY2FsZUNvbXBhcmUobW9kQi5uYW1lKTtcbiAgICB9XG4gICAgZ2V0IHJvbGxNb2RzKCkge1xuICAgICAgICBpZiAoIXRoaXMuX3JvbGxNb2RzKSB7XG4gICAgICAgICAgICB0aGlzLl9yb2xsTW9kcyA9IE9iamVjdC52YWx1ZXModGhpcy5kYXRhLnJvbGxNb2RzRGF0YSkubWFwKChtb2REYXRhKSA9PiBuZXcgQmxhZGVzUm9sbE1vZChtb2REYXRhLCB0aGlzKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFsuLi50aGlzLl9yb2xsTW9kc10uc29ydCgobW9kQSwgbW9kQikgPT4gdGhpcy5jb21wYXJlTW9kcyhtb2RBLCBtb2RCKSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIENPTlNFUVVFTkNFUzogR2V0dGluZywgQWNjZXB0aW5nLCBSZXNpc3RpbmdcbiAgICBnZXQgY29uc2VxdWVuY2VzKCkge1xuICAgICAgICBjb25zdCBjc3FEYXRhU2V0ID0gdGhpcy5kYXRhLmNvbnNlcXVlbmNlRGF0YT8uW3RoaXMucm9sbFBvc2l0aW9uRmluYWxdPy5bdGhpcy5yb2xsUmVzdWx0XTtcbiAgICAgICAgaWYgKGNzcURhdGFTZXQpIHtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKGNzcURhdGFTZXQpLm1hcCgoY3NxRGF0YSkgPT4gbmV3IEJsYWRlc0NvbnNlcXVlbmNlKGNzcURhdGEpKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIGdldENvbnNlcXVlbmNlQnlJRChjc3FJRCkge1xuICAgICAgICByZXR1cm4gdGhpcy5jb25zZXF1ZW5jZXMuZmluZCgoY3NxKSA9PiBjc3EuaWQgPT09IGNzcUlEKSA/PyBmYWxzZTtcbiAgICB9XG4gICAgZ2V0IGFjY2VwdGVkQ29uc2VxdWVuY2VzKCkge1xuICAgICAgICBpZiAoW1JvbGxQaGFzZS5Bd2FpdGluZ0NvbnNlcXVlbmNlcywgUm9sbFBoYXNlLkNvbXBsZXRlXS5pbmNsdWRlcyh0aGlzLnJvbGxQaGFzZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNvbnNlcXVlbmNlcy5maWx0ZXIoKGNzcSkgPT4gY3NxLmlzQWNjZXB0ZWQgPT09IHRydWUpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBbXTtcbiAgICB9XG4gICAgZ2V0IHVuYWNjZXB0ZWRDb25zZXF1ZW5jZXMoKSB7XG4gICAgICAgIGlmICh0aGlzLnJvbGxQaGFzZSA9PT0gUm9sbFBoYXNlLkF3YWl0aW5nQ29uc2VxdWVuY2VzKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5jb25zZXF1ZW5jZXMuZmlsdGVyKChjc3EpID0+IGNzcS5pc0FjY2VwdGVkICE9PSB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gW107XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uICoqKiBST0xMIENPTExBQiBIVE1MIElOVEVSQUNUSU9OICoqKiB+XG4gICAgLyoqXG4gICAgICogUmV0cmlldmUgdGhlIGRhdGEgZm9yIHJlbmRlcmluZyB0aGUgYmFzZSBSb2xsQ29sbGFiIHNoZWV0LlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IFRoZSBkYXRhIHdoaWNoIGNhbiBiZSB1c2VkIHRvIHJlbmRlciB0aGUgSFRNTCBvZiB0aGUgc2hlZXQuXG4gICAgICovXG4gICAgZ2V0IGNvbnRleHQoKSB7XG4gICAgICAgIHRoaXMuaW5pdFJvbGxNb2RzKCk7XG4gICAgICAgIHRoaXMucm9sbE1vZHMuZm9yRWFjaCgocm9sbE1vZCkgPT4gcm9sbE1vZC5hcHBseVJvbGxNb2RFZmZlY3RLZXlzKCkpO1xuICAgICAgICByZXR1cm4gdGhpcy5nZXRUZW1wbGF0ZUNvbnRleHQoKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogRGV0ZXJtaW5lcyBpZiB0aGUgdXNlciBpcyBhIGdhbWUgbWFzdGVyLlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSBXaGV0aGVyIHRoZSB1c2VyIGlzIGEgR00uXG4gICAgICovXG4gICAgZ2V0SXNHTSgpIHtcbiAgICAgICAgcmV0dXJuIGdhbWUuZXVub2JsYWRlcy5UcmFja2VyPy5zeXN0ZW0uaXNfc3Bvb2ZpbmdfcGxheWVyID8gZmFsc2UgOiBnYW1lLnVzZXIuaXNHTTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogR2V0cyB0aGUgcm9sbCBjb3N0cy5cbiAgICAgKiBAcmV0dXJucyB7QmxhZGVzUm9sbC5Db3N0RGF0YVtdfSBUaGUgcm9sbCBjb3N0cy5cbiAgICAgKi9cbiAgICBnZXRSb2xsQ29zdHMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldEFjdGl2ZVJvbGxNb2RzKClcbiAgICAgICAgICAgIC5tYXAoKHJvbGxNb2QpID0+IHJvbGxNb2QuY29zdHMpXG4gICAgICAgICAgICAuZmxhdCgpXG4gICAgICAgICAgICAuZmlsdGVyKChjb3N0RGF0YSkgPT4gY29zdERhdGEgIT09IHVuZGVmaW5lZCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdHMgdGhlIHNoZWV0IGRhdGEuXG4gICAgICogQHBhcmFtIHtib29sZWFufSBpc0dNIElmIHRoZSB1c2VyIGlzIGEgR00uXG4gICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLkNvc3REYXRhW119IHJvbGxDb3N0cyBUaGUgcm9sbCBjb3N0cy5cbiAgICAgKiBAcmV0dXJucyB7QmxhZGVzUm9sbC5Db250ZXh0fSBUaGUgY29uc3RydWN0ZWQgc2hlZXQgZGF0YS5cbiAgICAgKi9cbiAgICBnZXRUZW1wbGF0ZUNvbnRleHQoKSB7XG4gICAgICAgIGNvbnN0IHsgZGF0YTogckRhdGEsIHJvbGxQcmltYXJ5LCByb2xsVHJhaXREYXRhLCByb2xsVHJhaXRPcHRpb25zLCByb2xsQ2xvY2tLZXksIGZpbmFsRGljZVBvb2wsIHJvbGxQb3NpdGlvbkZpbmFsLCByb2xsRWZmZWN0RmluYWwsIHJvbGxSZXN1bHREZWx0YSwgcm9sbFJlc3VsdEZpbmFsLCByb2xsTW9kcywgcm9sbEZhY3RvcnMgfSA9IHRoaXM7XG4gICAgICAgIGlmICghcm9sbFByaW1hcnkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkEgcHJpbWFyeSByb2xsIHNvdXJjZSBpcyByZXF1aXJlZCBmb3IgQmxhZGVzUm9sbC5cIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgYmFzZURhdGEgPSB7XG4gICAgICAgICAgICAuLi50aGlzLmRhdGEsXG4gICAgICAgICAgICBjc3NDbGFzczogXCJyb2xsLWNvbGxhYlwiLFxuICAgICAgICAgICAgaXNHTTogdGhpcy5pc0dNLFxuICAgICAgICAgICAgc3lzdGVtOiB0aGlzLnJvbGxQcmltYXJ5RG9jPy5zeXN0ZW0sXG4gICAgICAgICAgICByb2xsTW9kcyxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5LFxuICAgICAgICAgICAgcm9sbFRyYWl0RGF0YSxcbiAgICAgICAgICAgIHJvbGxUcmFpdE9wdGlvbnMsXG4gICAgICAgICAgICBkaWNlVG90YWw6IGZpbmFsRGljZVBvb2wsXG4gICAgICAgICAgICByb2xsT3Bwb3NpdGlvbjogdGhpcy5yb2xsT3Bwb3NpdGlvbixcbiAgICAgICAgICAgIHJvbGxQYXJ0aWNpcGFudHM6IHRoaXMucm9sbFBhcnRpY2lwYW50cyxcbiAgICAgICAgICAgIHJvbGxQYXJ0aWNpcGFudE9wdGlvbnM6IHRoaXMucm9sbFBhcnRpY2lwYW50U2VsZWN0T3B0aW9ucyxcbiAgICAgICAgICAgIHJvbGxFZmZlY3RzOiBPYmplY3QudmFsdWVzKEVmZmVjdCksXG4gICAgICAgICAgICByb2xsVHJhaXRWYWxPdmVycmlkZTogdGhpcy5yb2xsVHJhaXRWYWxPdmVycmlkZSxcbiAgICAgICAgICAgIHJvbGxGYWN0b3JQZW5hbHRpZXNOZWdhdGVkOiB0aGlzLnJvbGxGYWN0b3JQZW5hbHRpZXNOZWdhdGVkLFxuICAgICAgICAgICAgcG9zUm9sbE1vZHM6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QudmFsdWVzKFJvbGxNb2RTZWN0aW9uKVxuICAgICAgICAgICAgICAgIC5tYXAoKGNhdCkgPT4gW2NhdCwgdGhpcy5nZXRSb2xsTW9kcyhjYXQsIFwicG9zaXRpdmVcIildKSksXG4gICAgICAgICAgICBuZWdSb2xsTW9kczogT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC52YWx1ZXMoUm9sbE1vZFNlY3Rpb24pXG4gICAgICAgICAgICAgICAgLm1hcCgoY2F0KSA9PiBbY2F0LCB0aGlzLmdldFJvbGxNb2RzKGNhdCwgXCJuZWdhdGl2ZVwiKV0pKSxcbiAgICAgICAgICAgIGhhc0luYWN0aXZlQ29uZGl0aW9uYWxzOiB0aGlzLmNhbGN1bGF0ZUhhc0luYWN0aXZlQ29uZGl0aW9uYWxzRGF0YSgpLFxuICAgICAgICAgICAgcm9sbEZhY3RvcnMsXG4gICAgICAgICAgICAuLi50aGlzLmNhbGN1bGF0ZU9kZHNIVE1MKGZpbmFsRGljZVBvb2wsIHJvbGxSZXN1bHREZWx0YSlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgR01Cb29zdHNEYXRhID0gdGhpcy5jYWxjdWxhdGVHTUJvb3N0c0RhdGEockRhdGEpO1xuICAgICAgICBjb25zdCBwb3NpdGlvbkVmZmVjdFRyYWRlRGF0YSA9IHRoaXMuY2FsY3VsYXRlUG9zaXRpb25FZmZlY3RUcmFkZURhdGEoKTtcbiAgICAgICAgY29uc3Qgc3RyZXNzQ29zdERhdGFTZXQgPSB0aGlzLmdldFJvbGxDb3N0cygpXG4gICAgICAgICAgICAuZmlsdGVyKChjb3N0RGF0YSkgPT4gY29zdERhdGEuY29zdFR5cGUgPT09IFwiU3RyZXNzXCIpXG4gICAgICAgICAgICAubWFwKChjb3N0RGF0YSkgPT4gW2Nvc3REYXRhLmxhYmVsLCBjb3N0RGF0YS5jb3N0QW1vdW50XSk7XG4gICAgICAgIGNvbnN0IGF2YWlsYWJsZUFybW9yID0gW107XG4gICAgICAgIGlmICh0aGlzLnJvbGxQcmltYXJ5RG9jIGluc3RhbmNlb2YgQmxhZGVzUEMpIHtcbiAgICAgICAgICAgIGF2YWlsYWJsZUFybW9yLnB1c2goLi4udGhpcy5yb2xsUHJpbWFyeURvYy5hdmFpbGFibGVBcm1vcik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5yb2xsUHJpbWFyeURvYywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKSB7XG4gICAgICAgICAgICAvLyBHYW5nIG9yIEV4cGVydCBDb2hvcnRcbiAgICAgICAgICAgIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB0aGlzLnJvbGxQcmltYXJ5RG9jLnN5c3RlbS5hcm1vci52YWx1ZTsgaW5kZXgrKykge1xuICAgICAgICAgICAgICAgIGF2YWlsYWJsZUFybW9yLnB1c2goXCJBcm1vclwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhcm1vckNvc3REYXRhU2V0ID0gdGhpcy5nZXRSb2xsQ29zdHMoKVxuICAgICAgICAgICAgLmZpbHRlcigoY29zdERhdGEpID0+IGNvc3REYXRhLmNvc3RUeXBlID09PSBcIkFybW9yXCIpXG4gICAgICAgICAgICAubWFwKChjb3N0RGF0YSwgaW5kZXgpID0+IFtjb3N0RGF0YS5sYWJlbCwgYXZhaWxhYmxlQXJtb3JbaW5kZXhdXSlcbiAgICAgICAgICAgIC5maWx0ZXIoKFtfbGFiZWwsIGFybW9yVHlwZV0pID0+IGFybW9yVHlwZSAhPT0gdW5kZWZpbmVkKTtcbiAgICAgICAgY29uc3Qgc3BlY2lhbEFybW9yQ29zdERhdGFTZXQgPSB0aGlzLmdldFJvbGxDb3N0cygpXG4gICAgICAgICAgICAuZmlsdGVyKChjb3N0RGF0YSkgPT4gY29zdERhdGEuY29zdFR5cGUgPT09IFwiU3BlY2lhbEFybW9yXCIpXG4gICAgICAgICAgICAubWFwKChjb3N0RGF0YSkgPT4gY29zdERhdGEubGFiZWwpO1xuICAgICAgICBjb25zdCB1c2VyUGVybWlzc2lvbiA9IGJhc2VEYXRhLnVzZXJQZXJtaXNzaW9uc1tnYW1lLnVzZXIuaWRdID8/IFJvbGxQZXJtaXNzaW9ucy5PYnNlcnZlcjtcbiAgICAgICAgLy8gY29uc3QgZG93bnRpbWVEYXRhID0gdGhpcy5wcm9jZXNzRG93bnRpbWVBY3Rpb25zKCk7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5iYXNlRGF0YSxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5OiB0aGlzLnJvbGxQcmltYXJ5LFxuICAgICAgICAgICAgcm9sbFBvc2l0aW9uRmluYWwsXG4gICAgICAgICAgICByb2xsRWZmZWN0RmluYWwsXG4gICAgICAgICAgICByb2xsUmVzdWx0RmluYWwsXG4gICAgICAgICAgICByb2xsUG9zaXRpb25zOiBPYmplY3QudmFsdWVzKFBvc2l0aW9uKSxcbiAgICAgICAgICAgIHJvbGxFZmZlY3RzOiBPYmplY3QudmFsdWVzKEVmZmVjdCksXG4gICAgICAgICAgICByb2xsUmVzdWx0RGVsdGEsXG4gICAgICAgICAgICBpc0FmZmVjdGluZ1Jlc3VsdDogcm9sbFJlc3VsdERlbHRhICE9PSAwXG4gICAgICAgICAgICAgICAgfHwgdGhpcy5nZXRWaXNpYmxlUm9sbE1vZHMoUm9sbE1vZFNlY3Rpb24ucmVzdWx0KS5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgfHwgKHRoaXMuaXNHTSAmJiB0aGlzLmdldFJvbGxNb2RzKFJvbGxNb2RTZWN0aW9uLnJlc3VsdCkubGVuZ3RoID4gMCksXG4gICAgICAgICAgICBpc0FmZmVjdGluZ0FmdGVyOiB0aGlzLmdldFZpc2libGVSb2xsTW9kcyhSb2xsTW9kU2VjdGlvbi5hZnRlcikubGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgIHx8ICh0aGlzLmlzR00gJiYgdGhpcy5nZXRSb2xsTW9kcyhSb2xsTW9kU2VjdGlvbi5hZnRlcikubGVuZ3RoID4gMCksXG4gICAgICAgICAgICAuLi5HTUJvb3N0c0RhdGEsXG4gICAgICAgICAgICAuLi5wb3NpdGlvbkVmZmVjdFRyYWRlRGF0YSxcbiAgICAgICAgICAgIHJvbGxDbG9ja0tleTogdGhpcy5yb2xsQ2xvY2tLZXksXG4gICAgICAgICAgICB0b3RhbFN0cmVzc0Nvc3Q6IHN0cmVzc0Nvc3REYXRhU2V0LnJlZHVjZSgoYWNjLCBbX2xhYmVsLCBhbW91bnRdKSA9PiBhY2MgKyBhbW91bnQsIDApLFxuICAgICAgICAgICAgdG90YWxBcm1vckNvc3Q6IGFybW9yQ29zdERhdGFTZXQubGVuZ3RoLFxuICAgICAgICAgICAgc3RyZXNzQ29zdHM6IHN0cmVzc0Nvc3REYXRhU2V0Lmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgICA/IE9iamVjdC5mcm9tRW50cmllcyhzdHJlc3NDb3N0RGF0YVNldClcbiAgICAgICAgICAgICAgICA6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIGFybW9yQ29zdHM6IGFybW9yQ29zdERhdGFTZXQubGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgID8gT2JqZWN0LmZyb21FbnRyaWVzKGFybW9yQ29zdERhdGFTZXQpXG4gICAgICAgICAgICAgICAgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICBzcGVjQXJtb3JDb3N0OiBzcGVjaWFsQXJtb3JDb3N0RGF0YVNldFswXSxcbiAgICAgICAgICAgIHVzZXJQZXJtaXNzaW9uLFxuICAgICAgICAgICAgZWRpdGFibGU6IHVzZXJQZXJtaXNzaW9uID09PSBSb2xsUGVybWlzc2lvbnMuUHJpbWFyeSB8fCB1c2VyUGVybWlzc2lvbiA9PT0gUm9sbFBlcm1pc3Npb25zLkdNLFxuICAgICAgICAgICAgZ2FtZVBoYXNlOiBnYW1lLmV1bm9ibGFkZXMuVHJhY2tlci5waGFzZVxuICAgICAgICB9O1xuICAgIH1cbiAgICAvLyB0eXBlIEJsYWRlc1NlbGVjdE9wdGlvbjxkaXNwbGF5VHlwZSwgdmFsdWVUeXBlID0gc3RyaW5nPiA9IHtcbiAgICAvLyAgIHZhbHVlOiB2YWx1ZVR5cGUsXG4gICAgLy8gICBkaXNwbGF5OiBkaXNwbGF5VHlwZVxuICAgIC8vIH07XG4gICAgLy8gcHJvdGVjdGVkIHByb2Nlc3NEb3dudGltZUFjdGlvbnMoKSB7XG4gICAgLy8gICBjb25zdCBkb3dudGltZURhdGE6IFJlY29yZDxzdHJpbmcsYW55PjtcbiAgICAvLyAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcy5yb2xsUHJpbWFyeURvYywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgIC8vICAgICBkb3dudGltZURhdGEuY2FuRG9Eb3dudGltZUFjdGlvbnMgPSB0cnVlO1xuICAgIC8vICAgICBkb3dudGltZURhdGEuZG93bnRpbWVBY3Rpb25zUmVtYWluaW5nID0gdGhpcy5yb2xsUHJpbWFyeURvYy5yZW1haW5pbmdEb3dudGltZUFjdGlvbnM7XG4gICAgLy8gICAgIGNvbnN0IGF2YWlsYWJsZURvd250aW1lQWN0aW9uczogRG93bnRpbWVBY3Rpb25bXSA9IFtdO1xuICAgIC8vICAgICBpZiAodGhpcy5yb2xsVHlwZSA9PT0gUm9sbFR5cGUuQWN0aW9uKSB7XG4gICAgLy8gICAgICAgYXZhaWxhYmxlRG93bnRpbWVBY3Rpb25zLnB1c2goLi4uW1xuICAgIC8vICAgICAgICAgRG93bnRpbWVBY3Rpb24uQWNxdWlyZUFzc2V0LFxuICAgIC8vICAgICAgICAgRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0LFxuICAgIC8vICAgICAgICAgRG93bnRpbWVBY3Rpb24uUmVjb3ZlcixcbiAgICAvLyAgICAgICAgIERvd250aW1lQWN0aW9uLlJlZHVjZUhlYXRcbiAgICAvLyAgICAgICBdKTtcbiAgICAvLyAgICAgfSBlbHNlIGlmICh0aGlzLnJvbGxUeXBlID09PSBSb2xsVHlwZS5Gb3J0dW5lKSB7XG4gICAgLy8gICAgICAgYXZhaWxhYmxlRG93bnRpbWVBY3Rpb25zLnB1c2goLi4uW1xuICAgIC8vICAgICAgICAgRG93bnRpbWVBY3Rpb24uXG4gICAgLy8gICAgICAgXSlcbiAgICAvLyAgICAgfVxuICAgIC8vICAgICBkb3dudGltZURhdGEuZG93bnRpbWVBY3Rpb25PcHRpb25zID1cbiAgICAvLyAgIGRvd250aW1lQWN0aW9uT3B0aW9ucz86IEFycmF5PEJsYWRlc1NlbGVjdE9wdGlvbjxzdHJpbmcsIERvd250aW1lQWN0aW9uPlxuICAgIC8vIH1cbiAgICBjYWxjdWxhdGVHTUJvb3N0c0RhdGEoZGF0YSkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgR01Cb29zdHM6IHtcbiAgICAgICAgICAgICAgICBEaWNlOiBkYXRhLkdNQm9vc3RzLkRpY2UgPz8gMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLnRpZXJdOiBkYXRhLkdNQm9vc3RzW0ZhY3Rvci50aWVyXSA/PyAwLFxuICAgICAgICAgICAgICAgIFtGYWN0b3IucXVhbGl0eV06IGRhdGEuR01Cb29zdHNbRmFjdG9yLnF1YWxpdHldID8/IDAsXG4gICAgICAgICAgICAgICAgW0ZhY3Rvci5zY2FsZV06IGRhdGEuR01Cb29zdHNbRmFjdG9yLnNjYWxlXSA/PyAwLFxuICAgICAgICAgICAgICAgIFtGYWN0b3IubWFnbml0dWRlXTogZGF0YS5HTUJvb3N0c1tGYWN0b3IubWFnbml0dWRlXSA/PyAwLFxuICAgICAgICAgICAgICAgIFJlc3VsdDogZGF0YS5HTUJvb3N0cy5SZXN1bHQgPz8gMFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIEdNT3BwQm9vc3RzOiB7XG4gICAgICAgICAgICAgICAgW0ZhY3Rvci50aWVyXTogZGF0YS5HTU9wcEJvb3N0c1tGYWN0b3IudGllcl0gPz8gMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLnF1YWxpdHldOiBkYXRhLkdNT3BwQm9vc3RzW0ZhY3Rvci5xdWFsaXR5XSA/PyAwLFxuICAgICAgICAgICAgICAgIFtGYWN0b3Iuc2NhbGVdOiBkYXRhLkdNT3BwQm9vc3RzW0ZhY3Rvci5zY2FsZV0gPz8gMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLm1hZ25pdHVkZV06IGRhdGEuR01PcHBCb29zdHNbRmFjdG9yLm1hZ25pdHVkZV0gPz8gMFxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgIH1cbiAgICBjYWxjdWxhdGVPZGRzSFRNTChkaWNlVG90YWwsIHJvbGxSZXN1bHREZWx0YSkge1xuICAgICAgICBpZiAodGhpcy5yb2xsVHlwZSA9PT0gUm9sbFR5cGUuUmVzaXN0YW5jZSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuY2FsY3VsYXRlT2Rkc0hUTUxfUmVzaXN0YW5jZShkaWNlVG90YWwpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmNhbGN1bGF0ZU9kZHNIVE1MX1N0YW5kYXJkKGRpY2VUb3RhbCwgcm9sbFJlc3VsdERlbHRhKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ2FsY3VsYXRlIG9kZHMgc3RhcnRpbmcgJiBlbmRpbmcgSFRNTCBiYXNlZCBvbiBnaXZlbiBkaWNlIHRvdGFsLlxuICAgICAqIEBwYXJhbSB7bnVtYmVyfSBkaWNlVG90YWwgVG90YWwgbnVtYmVyIG9mIGRpY2UuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IHJvbGxSZXN1bHREZWx0YVxuICAgICAqIEByZXR1cm5zIHt7b2Rkc0hUTUxTdGFydDogc3RyaW5nLCBvZGRzSFRNTFN0b3A6IHN0cmluZ319IE9wZW5pbmcgJiBDbG9zaW5nIEhUTUwgZm9yIG9kZHMgYmFyIGRpc3BsYXlcbiAgICAgKi9cbiAgICBjYWxjdWxhdGVPZGRzSFRNTF9TdGFuZGFyZChkaWNlVG90YWwsIHJvbGxSZXN1bHREZWx0YSkge1xuICAgICAgICBjb25zdCBvZGRzQ29sb3JzID0ge1xuICAgICAgICAgICAgY3JpdDogXCJ2YXIoLS1ibGFkZXMtZ29sZClcIixcbiAgICAgICAgICAgIHN1Y2Nlc3M6IFwidmFyKC0tYmxhZGVzLXdoaXRlLWJyaWdodClcIixcbiAgICAgICAgICAgIHBhcnRpYWw6IFwidmFyKC0tYmxhZGVzLWdyZXkpXCIsXG4gICAgICAgICAgICBmYWlsOiBcInZhcigtLWJsYWRlcy1ibGFjay1kYXJrKVwiXG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IG9kZHMgPSB7IC4uLkMuRGljZU9kZHNTdGFuZGFyZFtkaWNlVG90YWxdIH07XG4gICAgICAgIGlmIChyb2xsUmVzdWx0RGVsdGEgPCAwKSB7XG4gICAgICAgICAgICBmb3IgKGxldCBpID0gcm9sbFJlc3VsdERlbHRhOyBpIDwgMDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgb2Rkc0NvbG9ycy5jcml0ID0gb2Rkc0NvbG9ycy5zdWNjZXNzO1xuICAgICAgICAgICAgICAgIG9kZHNDb2xvcnMuc3VjY2VzcyA9IG9kZHNDb2xvcnMucGFydGlhbDtcbiAgICAgICAgICAgICAgICBvZGRzQ29sb3JzLnBhcnRpYWwgPSBvZGRzQ29sb3JzLmZhaWw7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocm9sbFJlc3VsdERlbHRhID4gMCkge1xuICAgICAgICAgICAgZm9yIChsZXQgaSA9IDA7IGkgPCByb2xsUmVzdWx0RGVsdGE7IGkrKykge1xuICAgICAgICAgICAgICAgIG9kZHNDb2xvcnMuZmFpbCA9IG9kZHNDb2xvcnMucGFydGlhbDtcbiAgICAgICAgICAgICAgICBvZGRzQ29sb3JzLnBhcnRpYWwgPSBvZGRzQ29sb3JzLnN1Y2Nlc3M7XG4gICAgICAgICAgICAgICAgb2Rkc0NvbG9ycy5zdWNjZXNzID0gb2Rkc0NvbG9ycy5jcml0O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHJlc3VsdEVsZW1lbnRzID0gW107XG4gICAgICAgIE9iamVjdC5lbnRyaWVzKG9kZHMpLnJldmVyc2UoKS5mb3JFYWNoKChbcmVzdWx0LCBjaGFuY2VdKSA9PiB7XG4gICAgICAgICAgICBpZiAoY2hhbmNlID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzdWx0RWxlbWVudHMucHVzaChgPGRpdiBjbGFzcz1cIm9kZHMtc2VjdGlvblwiIHN0eWxlPVwiaGVpZ2h0OiAxMDAlOyB3aWR0aDogJHtjaGFuY2V9JTsgYmFja2dyb3VuZDogJHtvZGRzQ29sb3JzW3Jlc3VsdF19O1wiPiZuYnNwOzwvZGl2PmApO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIG9kZHNIVE1MU3RhcnQ6IFtcbiAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9XFxcInJvbGwtb2Rkcy1zZWN0aW9uLWNvbnRhaW5lclxcXCI+XCIsXG4gICAgICAgICAgICAgICAgLi4ucmVzdWx0RWxlbWVudHNcbiAgICAgICAgICAgIF0uam9pbihcIlxcblwiKSxcbiAgICAgICAgICAgIG9kZHNIVE1MU3RvcDogXCI8L2Rpdj5cIlxuICAgICAgICB9O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGUgb2RkcyBzdGFydGluZyAmIGVuZGluZyBIVE1MIGJhc2VkIG9uIGdpdmVuIGRpY2UgdG90YWwuXG4gICAgICogQHBhcmFtIHtudW1iZXJ9IGRpY2VUb3RhbCBUb3RhbCBudW1iZXIgb2YgZGljZS5cbiAgICAgKiBAcmV0dXJucyB7e29kZHNIVE1MU3RhcnQ6IHN0cmluZywgb2Rkc0hUTUxTdG9wOiBzdHJpbmd9fSBPcGVuaW5nICYgQ2xvc2luZyBIVE1MIGZvciBvZGRzIGJhciBkaXNwbGF5XG4gICAgICovXG4gICAgY2FsY3VsYXRlT2Rkc0hUTUxfUmVzaXN0YW5jZShkaWNlVG90YWwpIHtcbiAgICAgICAgLy8gQ29uc3Qgb2Rkc0NvbG9ycyA9IFtcbiAgICAgICAgLy8gICBcInZhcigtLWJsYWRlcy1nb2xkKVwiLCAvLyAtMVxuICAgICAgICAvLyAgIFwidmFyKC0tYmxhZGVzLXdoaXRlKVwiLCAvLyAwXG4gICAgICAgIC8vICAgXCJ2YXIoLS1ibGFkZXMtcmVkLWJyaWdodClcIiwgLy8gMVxuICAgICAgICAvLyAgIFwidmFyKC0tYmxhZGVzLXJlZC1kYXJrKVwiLCAvLyAyXG4gICAgICAgIC8vICAgXCJ2YXIoLS1ibGFkZXMtcmVkLWJyaWdodClcIiwgLy8gM1xuICAgICAgICAvLyAgIFwidmFyKC0tYmxhZGVzLXJlZC1kYXJrKVwiLCAvLyA0XG4gICAgICAgIC8vICAgXCJ2YXIoLS1ibGFkZXMtcmVkLWJyaWdodClcIiAvLyA1XG4gICAgICAgIC8vIF0ucmV2ZXJzZSgpO1xuICAgICAgICBjb25zdCBvZGRzQ29sb3JzID0gW1xuICAgICAgICAgICAgXCJ2YXIoLS1ibGFkZXMtZ29sZClcIiwgLy8gLTFcbiAgICAgICAgICAgIFwidmFyKC0tYmxhZGVzLXdoaXRlKVwiLCAvLyAwXG4gICAgICAgICAgICBcInZhcigtLWJsYWRlcy1yZWQpXCIsIC8vIDFcbiAgICAgICAgICAgIFwidmFyKC0tYmxhZGVzLXJlZClcIiwgLy8gMlxuICAgICAgICAgICAgXCJ2YXIoLS1ibGFkZXMtcmVkKVwiLCAvLyAzXG4gICAgICAgICAgICBcInZhcigtLWJsYWRlcy1yZWQpXCIsIC8vIDRcbiAgICAgICAgICAgIFwidmFyKC0tYmxhZGVzLXJlZClcIiAvLyA1XG4gICAgICAgIF0ucmV2ZXJzZSgpO1xuICAgICAgICBjb25zdCBvZGRzRmlsdGVycyA9IFtcbiAgICAgICAgICAgIFwibm9uZVwiLFxuICAgICAgICAgICAgXCJub25lXCIsXG4gICAgICAgICAgICBcImJyaWdodG5lc3MoMC4yKVwiLFxuICAgICAgICAgICAgXCJicmlnaHRuZXNzKDAuNClcIixcbiAgICAgICAgICAgIFwiYnJpZ2h0bmVzcygwLjYpXCIsXG4gICAgICAgICAgICBcImJyaWdodG5lc3MoMC44KVwiLFxuICAgICAgICAgICAgXCJub25lXCJcbiAgICAgICAgXS5yZXZlcnNlKCk7XG4gICAgICAgIGNvbnN0IG9kZHMgPSBbLi4uQy5EaWNlT2Rkc1Jlc2lzdGFuY2VbZGljZVRvdGFsXV0ucmV2ZXJzZSgpO1xuICAgICAgICBjb25zdCByZXN1bHRFbGVtZW50cyA9IFtdO1xuICAgICAgICBmb3IgKGxldCBpbmRleCA9IDA7IGluZGV4IDwgb2Rkcy5sZW5ndGg7IGluZGV4KyspIHtcbiAgICAgICAgICAgIGNvbnN0IGNoYW5jZSA9IG9kZHNbaW5kZXhdO1xuICAgICAgICAgICAgaWYgKGNoYW5jZSA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBjb2xvciA9IG9kZHNDb2xvcnNbaW5kZXhdO1xuICAgICAgICAgICAgICAgIGNvbnN0IGZpbHRlciA9IG9kZHNGaWx0ZXJzW2luZGV4XTtcbiAgICAgICAgICAgICAgICByZXN1bHRFbGVtZW50cy5wdXNoKC4uLltcbiAgICAgICAgICAgICAgICAgICAgYDxkaXYgY2xhc3M9XCJvZGRzLXNlY3Rpb24gb2Rkcy1zZWN0aW9uLXN0cmVzc1wiIHN0eWxlPVwiaGVpZ2h0OiAxMDAlOyB3aWR0aDogJHtjaGFuY2V9JTsgYmFja2dyb3VuZDogJHtjb2xvcn07IGZpbHRlcjogJHtmaWx0ZXJ9O1wiPiZuYnNwOzwvZGl2PmBcbiAgICAgICAgICAgICAgICBdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgb2Rkc0hUTUxTdGFydDogW1xuICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz1cXFwicm9sbC1vZGRzLXNlY3Rpb24tY29udGFpbmVyXFxcIj5cIixcbiAgICAgICAgICAgICAgICAuLi5yZXN1bHRFbGVtZW50c1xuICAgICAgICAgICAgXS5qb2luKFwiXFxuXCIpLFxuICAgICAgICAgICAgb2Rkc0hUTUxTdG9wOiBcIjwvZGl2PlwiXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZSBkYXRhIGZvciBwb3NpdGlvbiBhbmQgZWZmZWN0IHRyYWRlLlxuICAgICAqIEByZXR1cm5zIHt7Y2FuVHJhZGVQb3NpdGlvbjogYm9vbGVhbiwgY2FuVHJhZGVFZmZlY3Q6IGJvb2xlYW59fVxuICAgICAqL1xuICAgIGNhbGN1bGF0ZVBvc2l0aW9uRWZmZWN0VHJhZGVEYXRhKCkge1xuICAgICAgICBjb25zdCBjYW5UcmFkZVBvc2l0aW9uID0gdGhpcy5wb3NFZmZlY3RUcmFkZSA9PT0gXCJwb3NpdGlvblwiIHx8ICh0aGlzLnBvc0VmZmVjdFRyYWRlID09PSBmYWxzZVxuICAgICAgICAgICAgJiYgdGhpcy5yb2xsUG9zaXRpb25GaW5hbCAhPT0gUG9zaXRpb24uZGVzcGVyYXRlXG4gICAgICAgICAgICAmJiB0aGlzLnJvbGxFZmZlY3RGaW5hbCAhPT0gRWZmZWN0LmV4dHJlbWUpO1xuICAgICAgICBjb25zdCBjYW5UcmFkZUVmZmVjdCA9IHRoaXMucG9zRWZmZWN0VHJhZGUgPT09IFwiZWZmZWN0XCIgfHwgKHRoaXMucG9zRWZmZWN0VHJhZGUgPT09IGZhbHNlXG4gICAgICAgICAgICAmJiB0aGlzLnJvbGxQb3NpdGlvbkZpbmFsICE9PSBQb3NpdGlvbi5jb250cm9sbGVkXG4gICAgICAgICAgICAmJiB0aGlzLnJvbGxFZmZlY3RGaW5hbCAhPT0gRWZmZWN0Lnplcm8pO1xuICAgICAgICByZXR1cm4geyBjYW5UcmFkZVBvc2l0aW9uLCBjYW5UcmFkZUVmZmVjdCB9O1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBDYWxjdWxhdGUgZGF0YSBvbiB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgaW5hY3RpdmUgY29uZGl0aW9uYWxzLlxuICAgICAqIEByZXR1cm5zIHtSZWNvcmQ8Um9sbE1vZFNlY3Rpb24sIGJvb2xlYW4+fSAtIERhdGEgb24gaW5hY3RpdmUgY29uZGl0aW9uYWxzLlxuICAgICAqL1xuICAgIGNhbGN1bGF0ZUhhc0luYWN0aXZlQ29uZGl0aW9uYWxzRGF0YSgpIHtcbiAgICAgICAgY29uc3QgaGFzSW5hY3RpdmUgPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIE9iamVjdC52YWx1ZXMoUm9sbE1vZFNlY3Rpb24pKSB7XG4gICAgICAgICAgICBoYXNJbmFjdGl2ZVtzZWN0aW9uXSA9IHRoaXMuZ2V0Um9sbE1vZHMoc2VjdGlvbikuZmlsdGVyKChtb2QpID0+IG1vZC5pc0luSW5hY3RpdmVCbG9jaykubGVuZ3RoID4gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaGFzSW5hY3RpdmU7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uICoqKiBFVkFMVUFUSU5HIFJPTEwgKioqIH5cbiAgICAvLyAjcmVnaW9uIERJQ0UgflxuICAgIF9kaWVWYWxzO1xuICAgIGdldCBkaWVWYWxzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yb2xsLnRlcm1zWzBdLnJlc3VsdHNcbiAgICAgICAgICAgIC5tYXAoKHJlc3VsdCkgPT4gcmVzdWx0LnJlc3VsdClcbiAgICAgICAgICAgIC5zb3J0KClcbiAgICAgICAgICAgIC5yZXZlcnNlKCk7XG4gICAgICAgIC8vIHJldHVybiB0aGlzLl9kaWVWYWxzO1xuICAgIH1cbiAgICAvLyBBY2NvdW50cyBmb3Igcm9sbGluZyB6ZXJvIGRpY2UgYnkgcmVtb3ZpbmcgaGlnaGVzdC5cbiAgICBnZXQgZmluYWxEaWVWYWxzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5pc1JvbGxpbmdaZXJvID8gdGhpcy5kaWVWYWxzLnNsaWNlKDEpIDogdGhpcy5kaWVWYWxzO1xuICAgIH1cbiAgICBnZXQgZmluYWxEaWNlRGF0YSgpIHtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJyb2xsQ29sbGFiXCIsIFwiW2dldCBmaW5hbERpY2VEYXRhKCldXCIsIHsgcm9sbDogdGhpcywgZGllVmFsczogdGhpcy5kaWVWYWxzIH0pO1xuICAgICAgICBjb25zdCBkaWVWYWxzID0gWy4uLnRoaXMuZGllVmFsc107XG4gICAgICAgIGNvbnN0IGdob3N0TnVtID0gdGhpcy5pc1JvbGxpbmdaZXJvID8gZGllVmFscy5zaGlmdCgpIDogbnVsbDtcbiAgICAgICAgY29uc3QgaXNDcml0aWNhbCA9IGRpZVZhbHMuZmlsdGVyKCh2YWwpID0+IHZhbCA9PT0gNikubGVuZ3RoID49IDI7XG4gICAgICAgIGNvbnN0IGRpY2VEYXRhID0gZGllVmFscy5tYXAoKHZhbCwgaSkgPT4gKHtcbiAgICAgICAgICAgIHZhbHVlOiB2YWwsXG4gICAgICAgICAgICBkaWVDbGFzczogQmxhZGVzUm9sbC5HZXREaWVDbGFzcyh0aGlzLnJvbGxUeXBlLCB0aGlzLnJvbGxSZXN1bHQsIHZhbCwgaSksXG4gICAgICAgICAgICBkaWVJbWFnZTogQmxhZGVzUm9sbC5HZXREaWVJbWFnZSh0aGlzLnJvbGxUeXBlLCB0aGlzLnJvbGxSZXN1bHQsIHZhbCwgaSwgZmFsc2UsIGlzQ3JpdGljYWwpXG4gICAgICAgIH0pKTtcbiAgICAgICAgaWYgKGdob3N0TnVtKSB7XG4gICAgICAgICAgICBkaWNlRGF0YS5wdXNoKHtcbiAgICAgICAgICAgICAgICB2YWx1ZTogZ2hvc3ROdW0sXG4gICAgICAgICAgICAgICAgZGllQ2xhc3M6IFwiYmxhZGVzLWRpZS1naG9zdFwiLFxuICAgICAgICAgICAgICAgIGRpZUltYWdlOiBCbGFkZXNSb2xsLkdldERpZUltYWdlKHRoaXMucm9sbFR5cGUsIHRoaXMucm9sbFJlc3VsdCwgZ2hvc3ROdW0sIGRpY2VEYXRhLmxlbmd0aCwgdHJ1ZSwgZmFsc2UpXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGljZURhdGE7XG4gICAgfVxuICAgIC8vIGdldCBkaWVWYWxzSFRNTCgpOiBzdHJpbmcge1xuICAgIC8vICAgZUxvZy5jaGVja0xvZzMoXCJyb2xsQ29sbGFiXCIsIFwiW2dldCBkaWVWYWxzSFRNTCgpXVwiLCB7cm9sbDogdGhpcywgZGllVmFsczogdGhpcy5kaWVWYWxzfSk7XG4gICAgLy8gICBjb25zdCBkaWVWYWxzID0gWy4uLnRoaXMuZGllVmFsc107XG4gICAgLy8gICBjb25zdCBnaG9zdE51bSA9IHRoaXMuaXNSb2xsaW5nWmVybyA/IGRpZVZhbHMuc2hpZnQoKSA6IG51bGw7XG4gICAgLy8gICBjb25zdCBpc0NyaXRpY2FsID0gZGllVmFscy5maWx0ZXIoKHZhbCkgPT4gdmFsID09PSA2KS5sZW5ndGggPj0gMjtcbiAgICAvLyAgIGNvbnN0IGRpY2VEYXRhID0gZGllVmFscy5tYXAoKHZhbCwgaSkgPT4gKHtcbiAgICAvLyAgICAgdmFsdWU6IHZhbCxcbiAgICAvLyAgICAgZGllQ2xhc3M6IEJsYWRlc1JvbGwuR2V0RGllQ2xhc3ModGhpcy5yb2xsVHlwZSwgdGhpcy5yb2xsUmVzdWx0LCB2YWwsIGkpLFxuICAgIC8vICAgICBkaWVJbWFnZTogQmxhZGVzUm9sbC5HZXREaWVJbWFnZSh0aGlzLnJvbGxUeXBlLCB0aGlzLnJvbGxSZXN1bHQsIHZhbCwgaSwgZmFsc2UsIGlzQ3JpdGljYWwpXG4gICAgLy8gICB9KSk7XG4gICAgLy8gICBpZiAoZ2hvc3ROdW0pIHtcbiAgICAvLyAgICAgZGljZURhdGEucHVzaCh7XG4gICAgLy8gICAgICAgdmFsdWU6IGdob3N0TnVtLFxuICAgIC8vICAgICAgIGRpZUNsYXNzOiBcImJsYWRlcy1kaWUtZ2hvc3RcIixcbiAgICAvLyAgICAgICBkaWVJbWFnZTogQmxhZGVzUm9sbC5HZXREaWVJbWFnZSh0aGlzLnJvbGxUeXBlLCB0aGlzLnJvbGxSZXN1bHQsIGdob3N0TnVtLCBkaWNlRGF0YS5sZW5ndGgsIHRydWUsIGZhbHNlKVxuICAgIC8vICAgICB9KTtcbiAgICAvLyAgIH1cbiAgICAvLyAgIHJldHVybiBbXG4gICAgLy8gICAgIC4uLmRpZVZhbHMubWFwKCh2YWwsIGkpID0+IGA8c3BhbiBjbGFzcz0nYmxhZGVzLWRpZSAke2RpZUNsYXNzfSBibGFkZXMtZGllLSR7dmFsdWV9Jz48aW1nIHNyYz0nJHtkaWVJbWFnZX0nIC8+PC9zcGFuPmApLFxuICAgIC8vICAgICBnaG9zdE51bSA/IGA8c3BhbiBjbGFzcz0nYmxhZGVzLWRpZSBibGFkZXMtZGllLWdob3N0IGJsYWRlcy1kaWUtJHtnaG9zdE51bX0nPjxpbWcgc3JjPScke3RoaXMuZ2V0RGllSW1hZ2UoZ2hvc3ROdW0sIDAsIHRydWUpfScgLz48L3NwYW4+YCA6IG51bGxcbiAgICAvLyAgIF1cbiAgICAvLyAgICAgLmZpbHRlcigodmFsKTogdmFsIGlzIHN0cmluZyA9PiB0eXBlb2YgdmFsID09PSBcInN0cmluZ1wiKVxuICAgIC8vICAgICAuam9pbihcIlwiKTtcbiAgICAvLyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gUkVTVUxUIEdFVFRFUlMgflxuICAgIGdldCBpc0NyaXRpY2FsKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5maW5hbERpZVZhbHMuZmlsdGVyKCh2YWwpID0+IHZhbCA9PT0gNikubGVuZ3RoID49IDI7XG4gICAgfVxuICAgIGdldCBpc1N1Y2Nlc3MoKSB7XG4gICAgICAgIHJldHVybiBCb29sZWFuKCF0aGlzLmlzQ3JpdGljYWwgJiYgdGhpcy5maW5hbERpZVZhbHMuZmluZCgodmFsKSA9PiB2YWwgPT09IDYpKTtcbiAgICB9XG4gICAgZ2V0IGlzUGFydGlhbCgpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4oIXRoaXMuaXNDcml0aWNhbCAmJiAhdGhpcy5pc1N1Y2Nlc3MgJiYgdGhpcy5maW5hbERpZVZhbHMuZmluZCgodmFsKSA9PiB2YWwgJiYgdmFsID49IDQpKTtcbiAgICB9XG4gICAgZ2V0IGlzRmFpbCgpIHtcbiAgICAgICAgcmV0dXJuICF0aGlzLmlzQ3JpdGljYWwgJiYgIXRoaXMuaXNTdWNjZXNzICYmICF0aGlzLmlzUGFydGlhbDtcbiAgICB9XG4gICAgZ2V0IGhpZ2hlc3REaWVWYWwoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmZpbmFsRGllVmFsc1swXTtcbiAgICB9XG4gICAgZ2V0IHJvbGxSZXN1bHQoKSB7XG4gICAgICAgIC8qIFN1YmNsYXNzIG92ZXJyaWRlcyBkZXRlcm1pbmUgaG93IHJvbGwgcmVzdWx0IGlzIGNvbW11bmljYXRlZC4gKi9cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1JvbGwucm9sbFJlc3VsdF0gVW5pbXBsZW1lbnRlZCBieSBTdWJjbGFzcy5cIik7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBnZXQgaXNSZXNvbHZlZCgpIHsgcmV0dXJuIHRoaXMucm9sbC50b3RhbCAhPT0gdW5kZWZpbmVkOyB9XG4gICAgYXN5bmMgZXZhbHVhdGVSb2xsKCkge1xuICAgICAgICAvLyBJZiB0aGlzIGNvbW1hbmQgaXMgY2FsbGVkIG9uIGFuIGFscmVhZHktcmVzb2x2ZWQgcm9sbCwgY2xvc2UgdGhlIHJvbGwgY29sbGFiIGVsZW1lbnQgYW5kIHJldHVybi5cbiAgICAgICAgaWYgKHRoaXMuaXNSZXNvbHZlZCkge1xuICAgICAgICAgICAgdGhpcy5jbG9zZVJvbGxDb2xsYWJfQW5pbWF0aW9uKCk7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5kYXRhO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuY2xvc2VSb2xsQ29sbGFiX1NvY2tldENhbGwoKTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJyb2xsQ29sbGFiXCIsIFwiW3Jlc29sdmVSb2xsKCldIEJlZm9yZSBFdmFsdWF0aW9uXCIsIHsgcm9sbDogdGhpcywgcm9sbERhdGE6IHsgLi4udGhpcy5kYXRhIH0gfSk7XG4gICAgICAgIGF3YWl0IHRoaXMucm9sbC5ldmFsdWF0ZSh7IGFzeW5jOiB0cnVlIH0pO1xuICAgICAgICByZXR1cm4gYXdhaXQgdGhpcy51cGRhdGVUYXJnZXREYXRhKHtcbiAgICAgICAgICAgIC4uLnRoaXMuZGF0YSxcbiAgICAgICAgICAgIHJvbGxQb3NpdGlvbkZpbmFsOiB0aGlzLnJvbGxQb3NpdGlvbkZpbmFsLFxuICAgICAgICAgICAgcm9sbEVmZmVjdEZpbmFsOiB0aGlzLnJvbGxFZmZlY3RGaW5hbCxcbiAgICAgICAgICAgIHJvbGxSZXN1bHQ6IHRoaXMucm9sbFJlc3VsdCxcbiAgICAgICAgICAgIHJvbGxUcmFpdFZlcmI6IHRoaXMucm9sbFRyYWl0VmVyYixcbiAgICAgICAgICAgIHJvbGxUcmFpdFBhc3RWZXJiOiB0aGlzLnJvbGxUcmFpdFBhc3RWZXJiLFxuICAgICAgICAgICAgZmluYWxEaWNlRGF0YTogdGhpcy5maW5hbERpY2VEYXRhLFxuICAgICAgICAgICAgcm9sbFBoYXNlOiB0aGlzLmlzQXBwbHlpbmdDb25zZXF1ZW5jZXNcbiAgICAgICAgICAgICAgICA/IFJvbGxQaGFzZS5Bd2FpdGluZ0NvbnNlcXVlbmNlc1xuICAgICAgICAgICAgICAgIDogUm9sbFBoYXNlLkNvbXBsZXRlXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhc3luYyByZXNvbHZlUm9sbFJlc3VsdCgpIHtcbiAgICAgICAgLyogU3ViY2xhc3Mgb3ZlcnJpZGVzIGRldGVybWluZSBob3cgcmVzdWx0IGFmZmVjdHMgcm9sbCBwYXJ0aWNpcGFudHMgKi9cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1JvbGwucmVzb2x2ZVJvbGxSZXN1bHRdIFVuaW1wbGVtZW50ZWQgYnkgU3ViY2xhc3MuXCIpO1xuICAgIH1cbiAgICBhc3luYyBvdXRwdXRSb2xsVG9DaGF0KCkge1xuICAgICAgICBhd2FpdCBCbGFkZXNDaGF0LmNyZWF0ZSh7XG4gICAgICAgICAgICBzcGVha2VyOiB0aGlzLmdldFNwZWFrZXIoQmxhZGVzQ2hhdC5nZXRTcGVha2VyKCkpLFxuICAgICAgICAgICAgY29udGVudDogYXdhaXQgcmVuZGVyVGVtcGxhdGUodGhpcy5jaGF0VGVtcGxhdGUsIHRoaXMuZGF0YSksXG4gICAgICAgICAgICB0eXBlOiBDT05TVC5DSEFUX01FU1NBR0VfVFlQRVMuUk9MTCxcbiAgICAgICAgICAgIGZsYWdzOiB7XG4gICAgICAgICAgICAgICAgXCJldW5vcy1ibGFkZXNcIjogeyByb2xsRGF0YTogdGhpcy5kYXRhIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIHJlc29sdmVSb2xsKCkge1xuICAgICAgICBhd2FpdCB0aGlzLmV2YWx1YXRlUm9sbCgpO1xuICAgICAgICB0aGlzLnJlc29sdmVSb2xsUmVzdWx0KCk7XG4gICAgICAgIGF3YWl0IHRoaXMub3V0cHV0Um9sbFRvQ2hhdCgpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiAqKiogSU5URVJGQUNJTkcgV0lUSCBCTEFERVNDSEFUICoqKlxuICAgIGdldFNwZWFrZXIoY2hhdFNwZWFrZXIpIHtcbiAgICAgICAgLy8gQ29tcGFyZSBhZ2FpbnN0IHJvbGxQcmltYXJ5IGFuZCBtb2RpZnkgYWNjb3JkaW5nbHkuXG4gICAgICAgIGNvbnN0IHsgcm9sbFByaW1hcnlJRCwgcm9sbFByaW1hcnlOYW1lLCByb2xsUHJpbWFyeVR5cGUsIHJvbGxQcmltYXJ5RG9jIH0gPSB0aGlzLnJvbGxQcmltYXJ5O1xuICAgICAgICBjaGF0U3BlYWtlci5hbGlhcyA9IHJvbGxQcmltYXJ5TmFtZTtcbiAgICAgICAgaWYgKFtCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZywgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydF0uaW5jbHVkZXMocm9sbFByaW1hcnlUeXBlKSkge1xuICAgICAgICAgICAgY2hhdFNwZWFrZXIuYWN0b3IgPSByb2xsUHJpbWFyeURvYz8ucGFyZW50Py5pZCA/PyBjaGF0U3BlYWtlci5hY3RvcjtcbiAgICAgICAgICAgIGlmIChyb2xsUHJpbWFyeURvYz8ucGFyZW50IGluc3RhbmNlb2YgQmxhZGVzUEMpIHtcbiAgICAgICAgICAgICAgICBjaGF0U3BlYWtlci5hbGlhcyA9IGAke2NoYXRTcGVha2VyLmFsaWFzfSAoJHtyb2xsUHJpbWFyeURvYy5wYXJlbnQubmFtZX0pYDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChbQmxhZGVzSXRlbVR5cGUuZ21fdHJhY2tlciwgQmxhZGVzSXRlbVR5cGUuc2NvcmVdLmluY2x1ZGVzKHJvbGxQcmltYXJ5VHlwZSkpIHtcbiAgICAgICAgICAgIGNoYXRTcGVha2VyLmFjdG9yID0gbnVsbDtcbiAgICAgICAgICAgIGNoYXRTcGVha2VyLmFsaWFzID0gXCJUaGUgR2FtZW1hc3RlclwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHJvbGxQcmltYXJ5SUQpIHtcbiAgICAgICAgICAgIGNoYXRTcGVha2VyLmFjdG9yID0gcm9sbFByaW1hcnlJRDtcbiAgICAgICAgfVxuICAgICAgICAvLyBjaGF0U3BlYWtlci5hbGlhcyA9IGAke2NoYXRTcGVha2VyLmFsaWFzfSBSb2xscyAuLi5gO1xuICAgICAgICByZXR1cm4gY2hhdFNwZWFrZXI7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uICoqKiBST0xMIENPTExBQiBIVE1MIEVMRU1FTlQgKioqXG4gICAgX2VsZW0kO1xuICAgIF9vdmVybGF5UG9zaXRpb24gPSB7IHg6IDIwMCwgeTogMjAwIH07XG4gICAgZ2V0IG92ZXJsYXlQb3NpdGlvbigpIHsgcmV0dXJuIHRoaXMuX292ZXJsYXlQb3NpdGlvbjsgfVxuICAgIHNldCBvdmVybGF5UG9zaXRpb24odmFsKSB7IHRoaXMuX292ZXJsYXlQb3NpdGlvbiA9IHZhbDsgfVxuICAgIGdldCBlbGVtJCgpIHtcbiAgICAgICAgaWYgKHRoaXMuX2VsZW0kKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fZWxlbSQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGAjJHt0aGlzLmlkfWApO1xuICAgICAgICBpZiAoZWxlbSQubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGlzLl9lbGVtJCA9IGVsZW0kO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fZWxlbSQgPSAkKGA8ZGl2IGlkPVwiJHt0aGlzLmlkfVwiIGNsYXNzPVwiYXBwIHdpbmRvdy1hcHAgJHtDLlNZU1RFTV9JRH0gc2hlZXQgcm9sbC1jb2xsYWIke2dhbWUudXNlci5pc0dNID8gXCIgZ20tcm9sbC1jb2xsYWJcIiA6IFwiXCJ9XCI+PC9kaXY+YCkuYXBwZW5kVG8oXCJib2R5XCIpO1xuICAgICAgICAgICAgdGhpcy5fZWxlbSQuY3NzKHtcbiAgICAgICAgICAgICAgICBsZWZ0OiBgJHt0aGlzLm92ZXJsYXlQb3NpdGlvbi54fXB4YCxcbiAgICAgICAgICAgICAgICB0b3A6IGAke3RoaXMub3ZlcmxheVBvc2l0aW9uLnl9cHhgXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5fZWxlbSQ7XG4gICAgfVxuICAgIGFzeW5jIHJlbmRlclJvbGxDb2xsYWIoKSB7XG4gICAgICAgIHRoaXMucHJlcGFyZVJvbGxQYXJ0aWNpcGFudERhdGEoKTtcbiAgICAgICAgY29uc3QgaHRtbCA9IGF3YWl0IHJlbmRlclRlbXBsYXRlKHRoaXMuY29sbGFiVGVtcGxhdGUsIHRoaXMuY29udGV4dCk7XG4gICAgICAgIHRoaXMuZWxlbSQuaHRtbChodG1sKTtcbiAgICAgICAgdGhpcy5hY3RpdmF0ZUxpc3RlbmVycygpO1xuICAgIH1cbiAgICBnZXQgaXNSZW5kZXJlZCgpIHtcbiAgICAgICAgcmV0dXJuIEJvb2xlYW4odGhpcy5fZWxlbSQ/Lmxlbmd0aCk7XG4gICAgfVxuICAgIGdldCBjb2xsYWJUZW1wbGF0ZSgpIHtcbiAgICAgICAgLyogU3ViY2xhc3Mgb3ZlcnJpZGVzIGRldGVybWluZSB0ZW1wbGF0ZSBhZ2FpbnN0IHdoaWNoIGRhdGEgaXMgcGFyc2VkICovXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNSb2xsLmNvbGxhYlRlbXBsYXRlXSBVbmltcGxlbWVudGVkIGJ5IFN1YmNsYXNzLlwiKTtcbiAgICB9XG4gICAgZ2V0IGNoYXRUZW1wbGF0ZSgpIHtcbiAgICAgICAgLyogU3ViY2xhc3Mgb3ZlcnJpZGVzIGRldGVybWluZSB0ZW1wbGF0ZSBhZ2FpbnN0IHdoaWNoIGRhdGEgaXMgcGFyc2VkICovXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNSb2xsLmNoYXRUZW1wbGF0ZV0gVW5pbXBsZW1lbnRlZCBieSBTdWJjbGFzcy5cIik7XG4gICAgfVxuICAgIC8vICNyZWdpb24gTElTVEVORVIgRlVOQ1RJT05TIH5cbiAgICAvLyBhc3luYyBfaGFuZGxlQ29uc2VxdWVuY2VDbGljayhldmVudDogQ2xpY2tFdmVudCkge1xuICAgIC8vICAgY29uc3QgY2xpY2tUYXJnZXQkID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAvLyAgIGNvbnN0IGNzcVBhcmVudCQgPSBjbGlja1RhcmdldCQuY2xvc2VzdChcIi5jb21wLmNvbnNlcXVlbmNlLWRpc3BsYXktY29udGFpbmVyXCIpO1xuICAgIC8vICAgY29uc3QgY3NxSUQgPSBjc3FQYXJlbnQkLmRhdGEoXCJjc3EtaWRcIik7XG4gICAgLy8gICBjb25zdCBjaGF0RWxlbSQgPSBjc3FQYXJlbnQkLmNsb3Nlc3QoXCIuYmxhZGVzLXJvbGxcIik7XG4gICAgLy8gICBjb25zdCBjaGF0TWVzc2FnZSQgPSBjaGF0RWxlbSQuY2xvc2VzdChcIi5jaGF0LW1lc3NhZ2VcIik7XG4gICAgLy8gICBjb25zdCBjaGF0SUQgPSBjaGF0TWVzc2FnZSQuZGF0YShcIm1lc3NhZ2VJZFwiKSBhcyBJRFN0cmluZztcbiAgICAvLyAgIGNvbnN0IGNoYXRNZXNzYWdlID0gZ2FtZS5tZXNzYWdlcy5nZXQoY2hhdElEKTtcbiAgICAvLyAgIGlmICghY2hhdE1lc3NhZ2UpIHtyZXR1cm47fVxuICAgIC8vICAgY29uc3QgY3NxcyA9IGF3YWl0IEJsYWRlc0NvbnNlcXVlbmNlLkdldEZyb21DaGF0TWVzc2FnZShjaGF0TWVzc2FnZSk7XG4gICAgLy8gICBjb25zdCB0aGlzQ3NxID0gY3Nxcy5maW5kKChjc3EpID0+IGNzcS5pZCA9PT0gY3NxSUQpO1xuICAgIC8vICAgaWYgKCF0aGlzQ3NxKSB7cmV0dXJuO31cbiAgICAvLyAgIHN3aXRjaCAoY2xpY2tUYXJnZXQkLmRhdGEoXCJhY3Rpb25cIikpIHtcbiAgICAvLyAgICAgY2FzZSBcImFjY2VwdC1jb25zZXF1ZW5jZVwiOiByZXR1cm4gdGhpc0NzcS5yZXNvbHZlQWNjZXB0KCk7XG4gICAgLy8gICAgIGNhc2UgXCJyZXNpc3QtY29uc2VxdWVuY2VcIjogcmV0dXJuIHRoaXNDc3EucmVzaXN0Q29uc2VxdWVuY2UoKTtcbiAgICAvLyAgICAgY2FzZSBcImFybW9yLWNvbnNlcXVlbmNlXCI6IHJldHVybiB0aGlzQ3NxLnJlc2lzdEFybW9yQ29uc2VxdWVuY2UoKTtcbiAgICAvLyAgICAgY2FzZSBcInNwZWNpYWwtY29uc2VxdWVuY2VcIjogcmV0dXJuIHRoaXNDc3EucmVzaXN0U3BlY2lhbEFybW9yQ29uc2VxdWVuY2UoKTtcbiAgICAvLyAgIH1cbiAgICAvLyAgIHJldHVybiB1bmRlZmluZWQgYXMgbmV2ZXI7XG4gICAgLy8gfVxuICAgIF90b2dnbGVSb2xsTW9kQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBpZCA9IGVsZW0kLmRhdGEoXCJpZFwiKTtcbiAgICAgICAgY29uc3Qgcm9sbE1vZCA9IHRoaXMuZ2V0Um9sbE1vZEJ5SUQoaWQpO1xuICAgICAgICBpZiAoIXJvbGxNb2QpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGZpbmQgcm9sbCBtb2Qgd2l0aCBpZCAnJHtpZH0nYCk7XG4gICAgICAgIH1cbiAgICAgICAgcm9sbE1vZC5pc1JlcmVuZGVyaW5nID0gdHJ1ZTtcbiAgICAgICAgc3dpdGNoIChyb2xsTW9kLnN0YXR1cykge1xuICAgICAgICAgICAgY2FzZSBSb2xsTW9kU3RhdHVzLkhpZGRlbjpcbiAgICAgICAgICAgICAgICByb2xsTW9kLnVzZXJTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkZvcmNlZE9mZjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgUm9sbE1vZFN0YXR1cy5Gb3JjZWRPZmY6XG4gICAgICAgICAgICAgICAgcm9sbE1vZC51c2VyU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPZmY6XG4gICAgICAgICAgICAgICAgcm9sbE1vZC51c2VyU3RhdHVzID0gUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT247XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9uOlxuICAgICAgICAgICAgICAgIHJvbGxNb2QudXNlclN0YXR1cyA9IGdhbWUudXNlci5pc0dNXG4gICAgICAgICAgICAgICAgICAgID8gUm9sbE1vZFN0YXR1cy5Gb3JjZWRPblxuICAgICAgICAgICAgICAgICAgICA6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgUm9sbE1vZFN0YXR1cy5Gb3JjZWRPbjpcbiAgICAgICAgICAgICAgICByb2xsTW9kLnVzZXJTdGF0dXMgPSBSb2xsTW9kU3RhdHVzLkhpZGRlbjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvcihgVW5yZWNvZ25pemVkIFJvbGxNb2RTdGF0dXM6ICR7cm9sbE1vZC5zdGF0dXN9YCk7XG4gICAgICAgIH1cbiAgICAgICAgcm9sbE1vZC5pc1JlcmVuZGVyaW5nID0gZmFsc2U7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgc2V0dGluZyBvZiByb2xsTW9kIHN0YXR1cyB2aWEgR00gcG9wLW91dCBjb250cm9sc1xuICAgICAqIEBwYXJhbSB7Q2xpY2tFdmVudH0gZXZlbnQgSlF1ZXJ5IGNsaWNrIGV2ZW50IHNlbnQgdG8gbGlzdGVuZXIuXG4gICAgICovXG4gICAgX2dtQ29udHJvbFNldChldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBpZCA9IGVsZW0kLmRhdGEoXCJpZFwiKTtcbiAgICAgICAgY29uc3Qgc3RhdHVzID0gZWxlbSQuZGF0YShcInN0YXR1c1wiKTtcbiAgICAgICAgaWYgKCFpc01vZFN0YXR1cyhzdGF0dXMpICYmIHN0YXR1cyAhPT0gXCJSZXNldFwiKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgcm9sbE1vZCA9IHRoaXMuZ2V0Um9sbE1vZEJ5SUQoaWQpO1xuICAgICAgICBpZiAocm9sbE1vZCkge1xuICAgICAgICAgICAgcm9sbE1vZC51c2VyU3RhdHVzID0gc3RhdHVzID09PSBcIlJlc2V0XCIgPyB1bmRlZmluZWQgOiBzdGF0dXM7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogSGFuZGxlcyBzZXR0aW5nIHZhbHVlcyB2aWEgR00gbnVtYmVyIGxpbmUgKGUuZy4gcm9sbCBmYWN0b3IgYm9vc3RzL21vZGlmaWNhdGlvbnMpLlxuICAgICAqIEBwYXJhbSB7Q2xpY2tFdmVudH0gZXZlbnQgSlF1ZXJ5IGNsaWNrIGV2ZW50IHNlbnQgdG8gbGlzdGVuZXIuXG4gICAgICovXG4gICAgYXN5bmMgX2dtQ29udHJvbFNldFRhcmdldFRvVmFsdWUoZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gZWxlbSQuZGF0YShcInRhcmdldFwiKS5yZXBsYWNlKC9mbGFnc1xcLmV1bm9zLWJsYWRlc1xcLi8sIFwiXCIpO1xuICAgICAgICBjb25zdCB2YWx1ZSA9IGVsZW0kLmRhdGEoXCJ2YWx1ZVwiKTtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQodGFyZ2V0LCB2YWx1ZSk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpO1xuICAgIH1cbiAgICBhc3luYyBfZ21Db250cm9sQ3ljbGVUYXJnZXQoZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgZmxhZ1RhcmdldCA9IGVsZW0kLmRhdGEoXCJmbGFnVGFyZ2V0XCIpO1xuICAgICAgICBjb25zdCBjdXJWYWwgPSBlbGVtJC5kYXRhKFwiY3VyVmFsXCIpO1xuICAgICAgICBjb25zdCBjeWNsZVZhbHMgPSBlbGVtJC5kYXRhKFwidmFsc1wiKT8uc3BsaXQoL1xcfC8pO1xuICAgICAgICBpZiAoIWN5Y2xlVmFscykge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcGFyc2UgY3ljbGUgdmFsdWVzIGZyb20gZGF0YS12YWxzID0gJHtlbGVtJC5kYXRhKFwidmFsc1wiKX1gKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjdXJWYWxJbmRleCA9IGN5Y2xlVmFscy5pbmRleE9mKGN1clZhbCk7XG4gICAgICAgIGlmIChjdXJWYWxJbmRleCA9PT0gLTEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGZpbmQgY3VycmVudCB2YWx1ZSAnJHtjdXJWYWx9JyBpbiBjeWNsZSB2YWx1ZXMgJyR7ZWxlbSQuZGF0YShcInZhbHNcIil9J2ApO1xuICAgICAgICB9XG4gICAgICAgIGxldCBuZXdWYWxJbmRleCA9IGN1clZhbEluZGV4ICsgMTtcbiAgICAgICAgaWYgKG5ld1ZhbEluZGV4ID49IGN5Y2xlVmFscy5sZW5ndGgpIHtcbiAgICAgICAgICAgIG5ld1ZhbEluZGV4ID0gMDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBuZXdWYWwgPSBjeWNsZVZhbHNbbmV3VmFsSW5kZXhdO1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImdtQ29udHJvbEN5Y2xlVGFyZ2V0XCIsIFwiZ21Db250cm9sQ3ljbGVUYXJnZXRcIiwgeyBmbGFnVGFyZ2V0LCBjdXJWYWwsIGN5Y2xlVmFscywgY3VyVmFsSW5kZXgsIG5ld1ZhbEluZGV4LCBuZXdWYWwgfSk7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlVGFyZ2V0KGZsYWdUYXJnZXQsIG5ld1ZhbCk7XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgcmVzZXR0aW5nIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBHTSBudW1iZXIgbGluZSBvbiBhIHJpZ2h0LWNsaWNrLlxuICAgICAqIEBwYXJhbSB7Q2xpY2tFdmVudH0gZXZlbnQgSlF1ZXJ5IGNvbnRleHQgbWVudSBldmVudCBzZW50IHRvIGxpc3RlbmVyLlxuICAgICAqL1xuICAgIGFzeW5jIF9nbUNvbnRyb2xSZXNldFRhcmdldChldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXQoJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwidGFyZ2V0XCIpLCB1bmRlZmluZWQpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogSGFuZGxlcyBzZXR0aW5nIG9mIGJhc2VsaW5lIHJvbGxQb3NpdGlvbiB2aWEgR00gYnV0dG9uIGxpbmVcbiAgICAgKiBAcGFyYW0ge0NsaWNrRXZlbnR9IGV2ZW50IEpRdWVyeSBjbGljayBldmVudCBzZW50IHRvIGxpc3RlbmVyLlxuICAgICAqL1xuICAgIF9nbUNvbnRyb2xTZXRQb3NpdGlvbihldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBpZiAoIWdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBwb3NpdGlvbiA9IGVsZW0kLmRhdGEoXCJzdGF0dXNcIik7XG4gICAgICAgIHRoaXMuaW5pdGlhbFBvc2l0aW9uID0gcG9zaXRpb247XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEhhbmRsZXMgc2V0dGluZyBvZiBiYXNlbGluZSByb2xsUG9zaXRpb24gdmlhIEdNIGJ1dHRvbiBsaW5lXG4gICAgICogQHBhcmFtIHtDbGlja0V2ZW50fSBldmVudCBKUXVlcnkgY2xpY2sgZXZlbnQgc2VudCB0byBsaXN0ZW5lci5cbiAgICAgKi9cbiAgICBfZ21Db250cm9sU2V0RWZmZWN0KGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlbGVtJCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCk7XG4gICAgICAgIGNvbnN0IGVmZmVjdCA9IGVsZW0kLmRhdGEoXCJzdGF0dXNcIik7XG4gICAgICAgIHRoaXMuaW5pdGlhbEVmZmVjdCA9IGVmZmVjdDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogSGFuZGxlcyBzZXR0aW5nIG9mIEZhY3RvciB0b2dnbGVzOiBpc0FjdGl2ZSwgaXNQcmltYXJ5LCBoaWdoRmF2b3JzUEMsIGlzRG9taW5hbnRcbiAgICAgKiBAcGFyYW0ge0NsaWNrRXZlbnR9IGV2ZW50IEpRdWVyeSBjbGljayBldmVudCBzZW50IHRvIGxpc3RlbmVyLlxuICAgICAqL1xuICAgIGFzeW5jIF9nbUNvbnRyb2xUb2dnbGVGYWN0b3IoZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgdGFyZ2V0ID0gZWxlbSQuZGF0YShcInRhcmdldFwiKTtcbiAgICAgICAgY29uc3QgdmFsdWUgPSAhZWxlbSQuZGF0YShcInZhbHVlXCIpO1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcInRvZ2dsZUZhY3RvclwiLCBcIl9nbUNvbnRyb2xUb2dnbGVGYWN0b3JcIiwgeyBldmVudCwgdGFyZ2V0LCB2YWx1ZSB9KTtcbiAgICAgICAgY29uc3QgZmFjdG9yVG9nZ2xlRGF0YSA9IHRoaXMuZGF0YS5yb2xsRmFjdG9yVG9nZ2xlcztcbiAgICAgICAgY29uc3QgW3RoaXNTb3VyY2UsIHRoaXNGYWN0b3IsIHRoaXNUb2dnbGVdID0gdGFyZ2V0LnNwbGl0KC9cXC4vKS5zbGljZSgtMyk7XG4gICAgICAgIC8vIElmIHRoaXNUb2dnbGUgaXMgdW5yZWNvZ25pemVkLCBqdXN0IHRvZ2dsZSB3aGF0ZXZlciB2YWx1ZSB0YXJnZXQgcG9pbnRzIGF0XG4gICAgICAgIGlmICghW1wiaXNBY3RpdmVcIiwgXCJpc1ByaW1hcnlcIiwgXCJpc0RvbWluYW50XCIsIFwiaGlnaEZhdm9yc1BDXCJdLmluY2x1ZGVzKHRoaXNUb2dnbGUpKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldCh0YXJnZXQsIHZhbHVlKTtcbiAgICAgICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpO1xuICAgICAgICB9XG4gICAgICAgIC8vIE90aGVyd2lzZSwgZmlyc3QgdG9nZ2xlIHRhcmdldGVkIGZhY3RvciB0byBuZXcgdmFsdWVcbiAgICAgICAgZmFjdG9yVG9nZ2xlRGF0YVt0aGlzU291cmNlXVt0aGlzRmFjdG9yXSA9IHtcbiAgICAgICAgICAgIC4uLmZhY3RvclRvZ2dsZURhdGFbdGhpc1NvdXJjZV1bdGhpc0ZhY3Rvcl0gPz8geyBkaXNwbGF5OiBcIlwiIH0sXG4gICAgICAgICAgICBbdGhpc1RvZ2dsZV06IHZhbHVlXG4gICAgICAgIH07XG4gICAgICAgIC8vIFRoZW4gcGVyZm9ybSBzcGVjaWZpYyBsb2dpYyBkZXBlbmRpbmcgb24gdG9nZ2xlIHRhcmdldGVkOlxuICAgICAgICBzd2l0Y2ggKHRoaXNUb2dnbGUpIHtcbiAgICAgICAgICAgIGNhc2UgXCJpc0RvbWluYW50XCI6XG4gICAgICAgICAgICBjYXNlIFwiaXNQcmltYXJ5XCI6IHtcbiAgICAgICAgICAgICAgICAvLyBPbmx5IG9uZSBmYWN0b3IgcGVyIHNvdXJjZVR5cGUgY2FuIGJlIGRlY2xhcmVkIFByaW1hcnkgb3IgRG9taW5hbnQ6XG4gICAgICAgICAgICAgICAgLy8gICAgSWYgb25lIGlzIGJlaW5nIGFjdGl2YXRlZCwgbXVzdCB0b2dnbGUgb2ZmIHRoZSBvdGhlcnMuXG4gICAgICAgICAgICAgICAgaWYgKHZhbHVlID09PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIE9iamVjdC52YWx1ZXMoRmFjdG9yKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZmFjdG9yKSA9PiBmYWN0b3IgIT09IHRoaXNGYWN0b3IpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgoZmFjdG9yKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZmFjdG9yVG9nZ2xlRGF0YVt0aGlzU291cmNlXVtmYWN0b3JdPy5bdGhpc1RvZ2dsZV0gPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWN0b3JUb2dnbGVEYXRhW3RoaXNTb3VyY2VdW2ZhY3Rvcl0gPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC4uLmZhY3RvclRvZ2dsZURhdGFbdGhpc1NvdXJjZV1bZmFjdG9yXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgW3RoaXNUb2dnbGVdOiBmYWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCJpc0FjdGl2ZVwiOiB7XG4gICAgICAgICAgICAgICAgLy8gJ2lzQWN0aXZlJyBzaG91bGQgYmUgc3luY2hyb25pemVkIHdoZW4gMSkgdmFsdWUgaXMgdHJ1ZSwgYW5kIDIpIHRoZSBvdGhlciB2YWx1ZSBpcyBmYWxzZVxuICAgICAgICAgICAgICAgIGlmICh2YWx1ZSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBvdGhlclNvdXJjZSA9IHRoaXNTb3VyY2UgPT09IFwic291cmNlXCIgPyBcIm9wcG9zaXRpb25cIiA6IFwic291cmNlXCI7XG4gICAgICAgICAgICAgICAgICAgIGZhY3RvclRvZ2dsZURhdGFbb3RoZXJTb3VyY2VdW3RoaXNGYWN0b3JdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgLi4uZmFjdG9yVG9nZ2xlRGF0YVtvdGhlclNvdXJjZV1bdGhpc0ZhY3Rvcl0gPz8geyBkaXNwbGF5OiBcIlwiIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0FjdGl2ZTogdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxGYWN0b3JUb2dnbGVzXCIsIGZhY3RvclRvZ2dsZURhdGEpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICB9XG4gICAgYXN5bmMgX29uU2VsZWN0Q2hhbmdlKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IGVsZW0gPSBldmVudC5jdXJyZW50VGFyZ2V0O1xuICAgICAgICBjb25zdCB7IGRvY1R5cGUgfSA9IGVsZW0uZGF0YXNldDtcbiAgICAgICAgaWYgKGVsZW0udmFsdWUgIT09IFwiXCIgJiYgZG9jVHlwZT8uc3RhcnRzV2l0aChcIkJsYWRlc1JvbGxQYXJ0aWNpcGFudFwiKSkge1xuICAgICAgICAgICAgY29uc3QgW18sIHNlY3Rpb24sIHN1YlNlY3Rpb25dID0gZG9jVHlwZS5zcGxpdChcIi5cIik7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFkZFJvbGxQYXJ0aWNpcGFudChlbGVtLnZhbHVlLCBzZWN0aW9uLCBzdWJTZWN0aW9uKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGF3YWl0IFUuRXZlbnRIYW5kbGVycy5vblNlbGVjdENoYW5nZSh0aGlzLCBldmVudCk7XG4gICAgICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBfb25UZXh0SW5wdXRCbHVyKGV2ZW50KSB7XG4gICAgICAgIGF3YWl0IFUuRXZlbnRIYW5kbGVycy5vblRleHRJbnB1dEJsdXIodGhpcywgZXZlbnQpO1xuICAgICAgICBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKTtcbiAgICB9XG4gICAgYXN5bmMgX29uR01Qb3B1cENsaWNrKGV2ZW50KSB7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiA8ZWxlbWVudFxuICAgICAgICAgKiAgZGF0YS1hY3Rpb249XCJnbS10ZXh0LXBvcHVwXCJcbiAgICAgICAgICogIGRhdGEtcHJvbXB0PVwiRW50ZXIgdGV4dCBmb3IgTWFqb3IgQWR2YW50YWdlLlwiXG4gICAgICAgICAqICBkYXRhLWZsYWctdGFyZ2V0PVwicm9sbENvbGxhYi5hZHZhbnRhZ2VzLnt7Y2FsYyAoY291bnQgZGF0YS5hZHZhbnRhZ2VzKSAnKycgMSl9fVxuICAgICAgICAgKiA+XG4gICAgICAgICAqXG4gICAgICAgICAqICovXG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgcHJvbXB0ID0gZWxlbSQuZGF0YShcInByb21wdFwiKTtcbiAgICAgICAgY29uc3QgZmxhZ1RhcmdldCA9IGVsZW0kLmRhdGEoXCJmbGFnVGFyZ2V0XCIpO1xuICAgICAgICBpZiAocHJvbXB0ICYmIGZsYWdUYXJnZXQpIHtcbiAgICAgICAgICAgIEJsYWRlc0RpYWxvZy5EaXNwbGF5U2ltcGxlSW5wdXREaWFsb2codGhpcywgcHJvbXB0LCB1bmRlZmluZWQsIGZsYWdUYXJnZXQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIEFzeW5jIF9nbUNvbnRyb2xTZWxlY3QoZXZlbnQ6IFNlbGVjdENoYW5nZUV2ZW50KSB7XG4gICAgLy8gICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgIC8vICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgIC8vICAgY29uc3Qgc2VjdGlvbiA9IGVsZW0kLmRhdGEoXCJyb2xsU2VjdGlvblwiKTtcbiAgICAvLyAgIGNvbnN0IHN1YlNlY3Rpb24gPSBlbGVtJC5kYXRhKFwicm9sbFN1YlNlY3Rpb25cIik7XG4gICAgLy8gICBjb25zdCBzZWxlY3RlZE9wdGlvbiA9IGVsZW0kLnZhbCgpO1xuICAgIC8vICAgaWYgKHR5cGVvZiBzZWxlY3RlZE9wdGlvbiAhPT0gXCJzdHJpbmdcIikgeyByZXR1cm47IH1cbiAgICAvLyAgIGlmIChzZWxlY3RlZE9wdGlvbiA9PT0gXCJmYWxzZVwiKSB7XG4gICAgLy8gICAgIGF3YWl0IHRoaXMuZG9jdW1lbnQudW5zZXRGbGFnKEMuU1lTVEVNX0lELCBgcm9sbENvbGxhYi5yb2xsUGFydGljaXBhbnREYXRhLiR7c2VjdGlvbn0uJHtzdWJTZWN0aW9ufWApO1xuICAgIC8vICAgfVxuICAgIC8vICAgYXdhaXQgdGhpcy5hZGRSb2xsUGFydGljaXBhbnQoc2VsZWN0ZWRPcHRpb24sIHNlY3Rpb24sIHN1YlNlY3Rpb24pO1xuICAgIC8vIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBBQ1RJVkFURSBMSVNURU5FUlMgflxuICAgIF9wb3NpdGlvbkRyYWdnZXI7XG4gICAgZ2V0IHBvc2l0aW9uRHJhZ2dlcigpIHtcbiAgICAgICAgaWYgKHRoaXMuX3Bvc2l0aW9uRHJhZ2dlcikge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3Bvc2l0aW9uRHJhZ2dlcjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zcGF3blBvc2l0aW9uRHJhZ2dlcigpO1xuICAgIH1cbiAgICBzcGF3blBvc2l0aW9uRHJhZ2dlcigpIHtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIGlmICghdGhpcy5fZWxlbSQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc1JvbGwuc3Bhd25Qb3NpdGlvbkRyYWdnZXJdIE5vIGVsZW0kIGZvdW5kIGZvciByb2xsICR7dGhpcy5pZH0uYCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5fcG9zaXRpb25EcmFnZ2VyPy5raWxsKCk7XG4gICAgICAgIHJldHVybiAodGhpcy5fcG9zaXRpb25EcmFnZ2VyID0gbmV3IERyYWdnZXIodGhpcy5fZWxlbSQsIHtcbiAgICAgICAgICAgIHR5cGU6IFwidG9wLGxlZnRcIixcbiAgICAgICAgICAgIHRyaWdnZXI6IFwiLndpbmRvdy1oZWFkZXIuZHJhZ2dlclwiLFxuICAgICAgICAgICAgb25EcmFnU3RhcnQoKSB7XG4gICAgICAgICAgICAgICAgVS5nc2FwLnRvKHRoaXMudGFyZ2V0LCB7IG9wYWNpdHk6IDAuMjUsIGR1cmF0aW9uOiAwLjI1LCBlYXNlOiBcInBvd2VyMlwiIH0pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG9uRHJhZ0VuZCgpIHtcbiAgICAgICAgICAgICAgICBVLmdzYXAudG8odGhpcy50YXJnZXQsIHsgb3BhY2l0eTogMSwgZHVyYXRpb246IDAuMjUsIGVhc2U6IFwicG93ZXIyXCIgfSk7XG4gICAgICAgICAgICAgICAgc2VsZi5vdmVybGF5UG9zaXRpb24gPSB7IHg6IHRoaXMuZW5kWCwgeTogdGhpcy5lbmRZIH07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKTtcbiAgICB9XG4gICAgYWN0aXZhdGVMaXN0ZW5lcnMoKSB7XG4gICAgICAgIEFwcGx5VG9vbHRpcEFuaW1hdGlvbnModGhpcy5lbGVtJCk7XG4gICAgICAgIHRoaXMuc3Bhd25Qb3NpdGlvbkRyYWdnZXIoKTtcbiAgICAgICAgLy8gSWYgYSByb2xsQ2xvY2tLZXkgZXhpc3RzLCBpbml0aWFsaXplIGl0cyBlbGVtZW50c1xuICAgICAgICBpZiAodGhpcy5yb2xsQ2xvY2tLZXkpIHtcbiAgICAgICAgICAgIHRoaXMuZWxlbSQuZmluZChcIi5yb2xsLWNsb2NrXCIpLnJlbW92ZUNsYXNzKFwiaGlkZGVuXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFVzZXItVG9nZ2xlYWJsZSBSb2xsIE1vZHNcbiAgICAgICAgdGhpcy5lbGVtJC5maW5kKFwiLnJvbGwtbW9kW2RhdGEtYWN0aW9uPSd0b2dnbGUnXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fdG9nZ2xlUm9sbE1vZENsaWNrLmJpbmQodGhpcylcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZWxlbSQuZmluZChcIltkYXRhLWFjdGlvbj0ndHJhZGVQb3NpdGlvbiddXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjdXJWYWwgPSBgJHskKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJ2YWx1ZVwiKX1gO1xuICAgICAgICAgICAgICAgIGlmIChjdXJWYWwgPT09IFwiZmFsc2VcIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxQb3NFZmZlY3RUcmFkZVwiLCBcImVmZmVjdFwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4gc29ja2V0bGliLnN5c3RlbS5leGVjdXRlRm9yRXZlcnlvbmUoXCJyZW5kZXJSb2xsQ29sbGFiX1NvY2tldENhbGxcIiwgdGhpcy5pZCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGRhdGVUYXJnZXQoXCJyb2xsUG9zRWZmZWN0VHJhZGVcIiwgZmFsc2UpXG4gICAgICAgICAgICAgICAgICAgICAgICAudGhlbigoKSA9PiBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5lbGVtJC5maW5kKFwiW2RhdGEtYWN0aW9uPSd0cmFkZUVmZmVjdCddXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjdXJWYWwgPSBgJHskKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJ2YWx1ZVwiKX1gO1xuICAgICAgICAgICAgICAgIGlmIChjdXJWYWwgPT09IFwiZmFsc2VcIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxQb3NFZmZlY3RUcmFkZVwiLCBcInBvc2l0aW9uXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudGhlbigoKSA9PiBzb2NrZXRsaWIuc3lzdGVtLmV4ZWN1dGVGb3JFdmVyeW9uZShcInJlbmRlclJvbGxDb2xsYWJfU29ja2V0Q2FsbFwiLCB0aGlzLmlkKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnVwZGF0ZVRhcmdldChcInJvbGxQb3NFZmZlY3RUcmFkZVwiLCBmYWxzZSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmVsZW0kLmZpbmQoXCJbZGF0YS1hY3Rpb249J3JvbGwnXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogKCkgPT4gdGhpcy5yZXNvbHZlUm9sbCgpXG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmVsZW0kXG4gICAgICAgICAgICAuZmluZChcInNlbGVjdFtkYXRhLWFjdGlvbj0ncGxheWVyLXNlbGVjdCddXCIpXG4gICAgICAgICAgICAub24oeyBjaGFuZ2U6IHRoaXMuX29uU2VsZWN0Q2hhbmdlLmJpbmQodGhpcykgfSk7XG4gICAgICAgIGlmICghZ2FtZS51c2VyLmlzR00pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvKipcbiAgICAgICAgICogSGFuZGxlcyBzZXR0aW5nIG9mIHJvbGxNb2Qgc3RhdHVzIHZpYSBHTSBwb3Atb3V0IGNvbnRyb2xzXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmVsZW0kLmZpbmQoXCIuY29udHJvbHMtdG9nZ2xlXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICQoZXZlbnQuY3VycmVudFRhcmdldCkucGFyZW50cyhcIi5jb250cm9scy1wYW5lbFwiKS50b2dnbGVDbGFzcyhcImFjdGl2ZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZWxlbSQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZ20tc2V0XFxcIl1cIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IHRoaXMuX2dtQ29udHJvbFNldC5iaW5kKHRoaXMpXG4gICAgICAgIH0pO1xuICAgICAgICAvKipcbiAgICAgICAgICogSGFuZGxlcyBzZXR0aW5nIG9mIGJhc2VsaW5lIHJvbGxQb3NpdGlvbiB2aWEgR00gYnV0dG9uIGxpbmVcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuZWxlbSQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZ20tc2V0LXBvc2l0aW9uXFxcIl1cIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IHRoaXMuX2dtQ29udHJvbFNldFBvc2l0aW9uLmJpbmQodGhpcylcbiAgICAgICAgfSk7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBIYW5kbGVzIHNldHRpbmcgb2YgYmFzZWxpbmUgcm9sbEVmZmVjdCB2aWEgR00gYnV0dG9uIGxpbmVcbiAgICAgICAgICovXG4gICAgICAgIHRoaXMuZWxlbSQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZ20tc2V0LWVmZmVjdFxcXCJdXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiB0aGlzLl9nbUNvbnRyb2xTZXRFZmZlY3QuYmluZCh0aGlzKVxuICAgICAgICB9KTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhhbmRsZXMgc2V0dGluZyB2YWx1ZXMgdmlhIEdNIG51bWJlciBsaW5lIChlLmcuIHJvbGwgZmFjdG9yIGJvb3N0cy9tb2RpZmljYXRpb25zKS5cbiAgICAgICAgICogSGFuZGxlcyByZXNldHRpbmcgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIEdNIG51bWJlciBsaW5lIG9uIGEgcmlnaHQtY2xpY2suXG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmVsZW0kLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcImdtLXNldC10YXJnZXRcXFwiXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fZ21Db250cm9sU2V0VGFyZ2V0VG9WYWx1ZS5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgY29udGV4dG1lbnU6IHRoaXMuX2dtQ29udHJvbFJlc2V0VGFyZ2V0LmJpbmQodGhpcylcbiAgICAgICAgfSk7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBIYW5kbGVzIHNldHRpbmcgdmFsdWVzIHZpYSBHTSBudW1iZXIgbGluZSAoZS5nLiByb2xsIGZhY3RvciBib29zdHMvbW9kaWZpY2F0aW9ucykuXG4gICAgICAgICAqIEhhbmRsZXMgcmVzZXR0aW5nIHZhbHVlIGFzc29jaWF0ZWQgd2l0aCBHTSBudW1iZXIgbGluZSBvbiBhIHJpZ2h0LWNsaWNrLlxuICAgICAgICAgKi9cbiAgICAgICAgdGhpcy5lbGVtJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJnbS1jeWNsZS10YXJnZXRcXFwiXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fZ21Db250cm9sQ3ljbGVUYXJnZXQuYmluZCh0aGlzKVxuICAgICAgICB9KTtcbiAgICAgICAgLyoqXG4gICAgICAgICAqIEhhbmRsZXMgc2V0dGluZyBvZiBGYWN0b3IgdG9nZ2xlczogaXNBY3RpdmUsIGlzUHJpbWFyeSwgaGlnaEZhdm9yc1BDLCBpc0RvbWluYW50XG4gICAgICAgICAqL1xuICAgICAgICB0aGlzLmVsZW0kLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcImdtLXRvZ2dsZS1mYWN0b3JcXFwiXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fZ21Db250cm9sVG9nZ2xlRmFjdG9yLmJpbmQodGhpcylcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMuZWxlbSRcbiAgICAgICAgICAgIC5maW5kKFwic2VsZWN0W2RhdGEtYWN0aW9uPSdnbS1zZWxlY3QnXVwiKVxuICAgICAgICAgICAgLm9uKHsgY2hhbmdlOiB0aGlzLl9vblNlbGVjdENoYW5nZS5iaW5kKHRoaXMpIH0pO1xuICAgICAgICAvLyB0aGlzLmVsZW0kXG4gICAgICAgIC8vICAgLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcImdtLWVkaXQtY29uc2VxdWVuY2VzXFxcIl1cIilcbiAgICAgICAgLy8gICAub24oe2NsaWNrOiAoKSA9PiBCbGFkZXNEaWFsb2cuRGlzcGxheVJvbGxDb25zZXF1ZW5jZURpYWxvZyh0aGlzKX0pO1xuICAgICAgICB0aGlzLmVsZW0kXG4gICAgICAgICAgICAuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZ20tdGV4dC1wb3B1cFxcXCJdXCIpXG4gICAgICAgICAgICAub24oeyBjbGljazogdGhpcy5fb25HTVBvcHVwQ2xpY2suYmluZCh0aGlzKSB9KTtcbiAgICAgICAgdGhpcy5lbGVtJFxuICAgICAgICAgICAgLmZpbmQoXCJbZGF0YS1hY3Rpb249J2dtLXRleHQtaW5wdXQnXVwiKVxuICAgICAgICAgICAgLm9uKHsgYmx1cjogdGhpcy5fb25UZXh0SW5wdXRCbHVyLmJpbmQodGhpcykgfSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBPVkVSUklERVM6IF9jYW5EcmFnRHJvcCwgX29uRHJvcCwgX29uU3VibWl0LCBjbG9zZSwgcmVuZGVyIH5cbiAgICAvLyBvdmVycmlkZSBfY2FuRHJhZ0Ryb3AoKSB7XG4gICAgLy8gICByZXR1cm4gZ2FtZS51c2VyLmlzR007XG4gICAgLy8gfVxuICAgIC8vIG92ZXJyaWRlIF9vbkRyb3AoZXZlbnQ6IERyYWdFdmVudCkge1xuICAgIC8vICAgY29uc3Qge3V1aWR9ID0gVGV4dEVkaXRvci5nZXREcmFnRXZlbnREYXRhKGV2ZW50KSBhcyB7dXVpZDogVVVJRFN0cmluZ307XG4gICAgLy8gICBjb25zdCBkcm9wRG9jID0gZnJvbVV1aWRTeW5jKHV1aWQpO1xuICAgIC8vICAgaWYgKEJsYWRlc1JvbGxPcHBvc2l0aW9uLklzRG9jKGRyb3BEb2MpKSB7XG4gICAgLy8gICAgIHRoaXMucm9sbE9wcG9zaXRpb24gPSBuZXcgQmxhZGVzUm9sbE9wcG9zaXRpb24odGhpcywge3JvbGxPcHBEb2M6IGRyb3BEb2N9KTtcbiAgICAvLyAgIH0gZWxzZSBpZiAoZHJvcERvYyBpbnN0YW5jZW9mIEJsYWRlc1Byb2plY3QgJiYgZHJvcERvYy5jbG9ja0tleSkge1xuICAgIC8vICAgICAvLyBQcm9qZWN0IGRyb3BwZWQgb24gcm9sbDogQXNzaWduIHByb2plY3QncyBjbG9jayBrZXkgdG8gcm9sbC5cbiAgICAvLyAgICAgdGhpcy5yb2xsQ2xvY2tLZXkgPSBkcm9wRG9jLmNsb2NrS2V5O1xuICAgIC8vICAgfVxuICAgIC8vIH1cbiAgICBhc3luYyBzdWJtaXRDaGFuZ2UocHJvcCwgdmFsKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlVGFyZ2V0KHByb3AsIHZhbCk7XG4gICAgICAgIHNvY2tldGxpYi5zeXN0ZW0uZXhlY3V0ZUZvckV2ZXJ5b25lKFwicmVuZGVyUm9sbENvbGxhYl9Tb2NrZXRDYWxsXCIsIHRoaXMuaWQpO1xuICAgIH1cbn1cbmNsYXNzIEJsYWRlc0FjdGlvblJvbGwgZXh0ZW5kcyBCbGFkZXNSb2xsIHtcbiAgICAvKiBOb3QgbXVjaCAtLSBtb3N0IGFjdGlvbiByb2xsIHRoaW5ncyB3aWxsIGV4dGVuZCB0byBvdGhlciByb2xscywgYnV0IHNwbGl0IG91dCB0aGluZ3MgbGlrZSBQb3NpdGlvbiwgRWZmZWN0LCBkZWZhdWx0IE1vZHMgKi9cbiAgICBzdGF0aWMgQXBwbHlTY2hlbWFEZWZhdWx0cyhzY2hlbWFEYXRhKSB7XG4gICAgICAgIHNjaGVtYURhdGEucm9sbFR5cGUgPSBSb2xsVHlwZS5BY3Rpb247XG4gICAgICAgIGlmICghc2NoZW1hRGF0YS5yb2xsUHJpbWFyeURhdGEpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk11c3QgaW5jbHVkZSBhIHJvbGxQcmltYXJ5RGF0YSB3aGVuIGNvbnN0cnVjdGluZyBhIEJsYWRlc0FjdGlvblJvbGwgb2JqZWN0LlwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgcm9sbFRyYWl0XG4gICAgICAgIGlmICghKHNjaGVtYURhdGEucm9sbFRyYWl0ID09PSBcIlwiIHx8IFUuaXNJbnQoc2NoZW1hRGF0YS5yb2xsVHJhaXQpIHx8IFUubENhc2Uoc2NoZW1hRGF0YS5yb2xsVHJhaXQpIGluIHsgLi4uQWN0aW9uVHJhaXQsIC4uLkZhY3RvciB9KSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzQWN0aW9uUm9sbC5BcHBseVNjaGVtYURlZmF1bHRzKCldIEJhZCBSb2xsVHJhaXQgZm9yIEFjdGlvbiBSb2xsOiAke3NjaGVtYURhdGEucm9sbFRyYWl0fWApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGZ1bGxTY2hlbWEgPSBzdXBlci5BcHBseVNjaGVtYURlZmF1bHRzKHNjaGVtYURhdGEpO1xuICAgICAgICBjb25zdCByb2xsUHJpbWFyeSA9IEJsYWRlc1JvbGxQcmltYXJ5LkJ1aWxkKGZ1bGxTY2hlbWEpO1xuICAgICAgICAvLyBNb2RpZnkgQ29uZmlnIG9iamVjdCBkZXBlbmRpbmcgb24gZG93bnRpbWUgYWN0aW9uIHdoZXJlIG5lY2Vzc2FyeS5cbiAgICAgICAgc3dpdGNoIChmdWxsU2NoZW1hLnJvbGxEb3dudGltZUFjdGlvbikgeyAvLyBSZW1lbWJlcjogQ2FuIGJlIGRvbmUgb3V0c2lkZSBvZiBEb3dudGltZSBkdXJpbmcgRmxhc2hiYWNrcyFcbiAgICAgICAgICAgIGNhc2UgRG93bnRpbWVBY3Rpb24uQWNxdWlyZUFzc2V0OiB7XG4gICAgICAgICAgICAgICAgZnVsbFNjaGVtYS5yb2xsVHJhaXQgPSBGYWN0b3IudGllcjtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0OiB7XG4gICAgICAgICAgICAgICAgLy8gVmFsaWRhdGUgdGhhdCByb2xsT3BwRGF0YSBwb2ludHMgdG8gYSBwcm9qZWN0IGl0ZW1cbiAgICAgICAgICAgICAgICBpZiAoIUJsYWRlc1JvbGxPcHBvc2l0aW9uLklzVmFsaWREYXRhKGZ1bGxTY2hlbWEucm9sbE9wcERhdGEpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIHJvbGxPcHBEYXRhIHByb3ZpZGVkIGZvciBMb25nVGVybVByb2plY3Qgcm9sbC5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghW1xuICAgICAgICAgICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5wcm9qZWN0LFxuICAgICAgICAgICAgICAgICAgICBCbGFkZXNJdGVtVHlwZS5kZXNpZ25cbiAgICAgICAgICAgICAgICBdLmluY2x1ZGVzKGZ1bGxTY2hlbWEucm9sbE9wcERhdGEucm9sbE9wcFR5cGUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcInJvbGxPcHBUeXBlIG11c3QgYmUgJ3Byb2plY3QnIG9yICdkZXNpZ24nIGZvciBMb25nVGVybVByb2plY3Qgcm9sbC5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5SZWNvdmVyOiB7XG4gICAgICAgICAgICAgICAgLy8gVmFsaWRhdGUgdGhhdCByb2xsUHJpbWFyeSBpcyBhbiBOUEMgb3IgYSBQQyB3aXRoIFBoeXNpa2VyLlxuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNQQy5Jc1R5cGUocm9sbFByaW1hcnkucm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghcm9sbFByaW1hcnkucm9sbFByaW1hcnlEb2MuYWJpbGl0aWVzLmZpbmQoKGFiaWxpdHkpID0+IGFiaWxpdHkubmFtZSA9PT0gXCJQaHlzaWtlclwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQSBQQyByb2xsUHJpbWFyeSBvbiBhIFJlY292ZXJ5IHJvbGwgbXVzdCBoYXZlIHRoZSBQaHlzaWtlciBhYmlsaXR5LlwiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBmdWxsU2NoZW1hLnJvbGxUcmFpdCA9IEFjdGlvblRyYWl0LnRpbmtlcjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAocm9sbFByaW1hcnkucm9sbFByaW1hcnlEb2M/LnJvbGxQcmltYXJ5VHlwZSA9PT0gQmxhZGVzQWN0b3JUeXBlLm5wYykge1xuICAgICAgICAgICAgICAgICAgICBmdWxsU2NoZW1hLnJvbGxUcmFpdCA9IEZhY3Rvci5xdWFsaXR5O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiT25seSBhIFBDIHdpdGggUGh5c2lrZXIgb3IgYW4gTlBDIGNhbiBiZSByb2xsUHJpbWFyeSBvbiBhIFJlY292ZXIgcm9sbC5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5SZWR1Y2VIZWF0OiB7XG4gICAgICAgICAgICAgICAgLy8gcm9sbFByaW1hcnkgbXVzdCBiZSBhIGNvaG9ydCB3aXRoIGEgcGFyZW50IFBDIG9yIENyZXcsXG4gICAgICAgICAgICAgICAgLy8gYW5kIFBDIG11c3QgYmUgbWVtYmVyIG9mIGEgY3Jld1xuICAgICAgICAgICAgICAgIC8vIGFuZCBDcmV3IG11c3Qgbm90IGhhdmUgemVybyBIZWF0LlxuICAgICAgICAgICAgICAgIGxldCBwYXJlbnRDcmV3ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIGlmIChyb2xsUHJpbWFyeS5yb2xsUHJpbWFyeURvYykge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB7IHBhcmVudCB9ID0gcm9sbFByaW1hcnkucm9sbFByaW1hcnlEb2M7XG4gICAgICAgICAgICAgICAgICAgIGlmIChCbGFkZXNDcmV3LklzVHlwZShwYXJlbnQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJlbnRDcmV3ID0gcGFyZW50O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKEJsYWRlc1BDLklzVHlwZShwYXJlbnQpICYmIEJsYWRlc0NyZXcuSXNUeXBlKHBhcmVudC5jcmV3KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcGFyZW50Q3JldyA9IHBhcmVudC5jcmV3O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghQmxhZGVzQ3Jldy5Jc1R5cGUocGFyZW50Q3JldykpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb3VsZCBub3QgZmluZCBjcmV3IGZvciByb2xsUHJpbWFyeSAnJHtyb2xsUHJpbWFyeS5yb2xsUHJpbWFyeURvYz8ucm9sbFByaW1hcnlOYW1lfSdgKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHBhcmVudENyZXcuc3lzdGVtLmhlYXQudmFsdWUgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQXR0ZW1wdCB0byBSZWR1Y2UgSGVhdCBmb3IgYSBDcmV3IHdpdGggbm8gSGVhdC5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSB1bmRlZmluZWQ6IGJyZWFrO1xuICAgICAgICAgICAgZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKGBVbnJlY29nbml6ZWQgUm9sbCBEb3dudGltZSBBY3Rpb246ICR7ZnVsbFNjaGVtYS5yb2xsRG93bnRpbWVBY3Rpb259YCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHJvbGxQb3NpdGlvbkluaXRpYWw6IFBvc2l0aW9uLnJpc2t5LFxuICAgICAgICAgICAgcm9sbEVmZmVjdEluaXRpYWw6IEVmZmVjdC5zdGFuZGFyZCxcbiAgICAgICAgICAgIHJvbGxQb3NFZmZlY3RUcmFkZTogZmFsc2UsXG4gICAgICAgICAgICBHTUJvb3N0czoge1xuICAgICAgICAgICAgICAgIFtGYWN0b3IudGllcl06IDAsXG4gICAgICAgICAgICAgICAgW0ZhY3Rvci5xdWFsaXR5XTogMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLnNjYWxlXTogMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLm1hZ25pdHVkZV06IDBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBHTU9wcEJvb3N0czoge1xuICAgICAgICAgICAgICAgIFtGYWN0b3IudGllcl06IDAsXG4gICAgICAgICAgICAgICAgW0ZhY3Rvci5xdWFsaXR5XTogMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLnNjYWxlXTogMCxcbiAgICAgICAgICAgICAgICBbRmFjdG9yLm1hZ25pdHVkZV06IDBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBHTU92ZXJyaWRlczoge30sXG4gICAgICAgICAgICByb2xsRmFjdG9yVG9nZ2xlczoge1xuICAgICAgICAgICAgICAgIHNvdXJjZToge1xuICAgICAgICAgICAgICAgICAgICBbRmFjdG9yLnRpZXJdOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIFtGYWN0b3IucXVhbGl0eV06IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0FjdGl2ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc1ByaW1hcnk6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBoaWdoRmF2b3JzUEM6IHRydWVcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgW0ZhY3Rvci5zY2FsZV06IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0FjdGl2ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc1ByaW1hcnk6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBoaWdoRmF2b3JzUEM6IHRydWVcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgW0ZhY3Rvci5tYWduaXR1ZGVdOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG9wcG9zaXRpb246IHtcbiAgICAgICAgICAgICAgICAgICAgW0ZhY3Rvci50aWVyXToge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzUHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0RvbWluYW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBbRmFjdG9yLnF1YWxpdHldOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIFtGYWN0b3Iuc2NhbGVdOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIFtGYWN0b3IubWFnbml0dWRlXToge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzQWN0aXZlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGlzUHJpbWFyeTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICBpc0RvbWluYW50OiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIC4uLmZ1bGxTY2hlbWEsXG4gICAgICAgICAgICByb2xsUHJpbWFyeURhdGE6IHJvbGxQcmltYXJ5LmRhdGEsXG4gICAgICAgICAgICByb2xsT3BwRGF0YTogZnVsbFNjaGVtYS5yb2xsT3BwRGF0YSBpbnN0YW5jZW9mIEJsYWRlc1JvbGxPcHBvc2l0aW9uXG4gICAgICAgICAgICAgICAgPyBmdWxsU2NoZW1hLnJvbGxPcHBEYXRhLmRhdGFcbiAgICAgICAgICAgICAgICA6IGZ1bGxTY2hlbWEucm9sbE9wcERhdGFcbiAgICAgICAgfTtcbiAgICB9XG4gICAgc3RhdGljIGdldCBEZWZhdWx0Um9sbE1vZFNjaGVtYVNldCgpIHtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiUHVzaC1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJQVVNIXCIsXG4gICAgICAgICAgICAgICAgc2VjdGlvbjogUm9sbE1vZFNlY3Rpb24ucm9sbCxcbiAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJwb3NpdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW1wiRm9yY2VPZmYtQmFyZ2FpblwiLCBcIkNvc3QtU3RyZXNzMlwiXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT5QdXNoIGZvciArMWQ8L2gxPjxwPkZvciA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz4yIFN0cmVzczwvc3Ryb25nPiwgYWRkIDxzdHJvbmcgY2xhc3M9J2dvbGQtYnJpZ2h0Jz4xIGRpZTwvc3Ryb25nPiB0byB5b3VyIHBvb2wuPC9wPjxwPjxlbT4oWW91IDxzdHJvbmc+Y2Fubm90PC9zdHJvbmc+IGFsc28gYWNjZXB0IGEgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+RGV2aWwncyBCYXJnYWluPC9zdHJvbmc+IHRvIGluY3JlYXNlIHlvdXIgZGljZSBwb29sOiBJdCdzIG9uZSBvciB0aGUgb3RoZXIuKTwvZW0+PC9wPlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGtleTogXCJCYXJnYWluLXBvc2l0aXZlLXJvbGxcIixcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkJhcmdhaW5cIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLkhpZGRlbixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwicG9zaXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxLFxuICAgICAgICAgICAgICAgIGVmZmVjdEtleXM6IFtdLFxuICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiPGgxIGNsYXNzPSdyZWQtYnJpZ2h0Jz5EZXZpbCdzIEJhcmdhaW48L2gxPjxwPlRoZSBHTSBoYXMgb2ZmZXJlZCB5b3UgYSA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5EZXZpbCdzIEJhcmdhaW48L3N0cm9uZz4uPC9wPjxwPjxzdHJvbmcgY2xhc3M9J3JlZC1icmlnaHQnPkFjY2VwdCB0aGUgdGVybXM8L3N0cm9uZz4gdG8gYWRkIDxzdHJvbmcgY2xhc3M9J2dvbGQtYnJpZ2h0Jz4xIGRpZTwvc3Ryb25nPiB0byB5b3VyIHBvb2wuPC9wPjxwPjxlbT4oWW91IDxzdHJvbmc+Y2Fubm90PC9zdHJvbmc+IGFsc28gPHN0cm9uZz5QdXNoIGZvciArMWQ8L3N0cm9uZz4gdG8gaW5jcmVhc2UgeW91ciBkaWNlIHBvb2w6IEl0J3Mgb25lIG9yIHRoZSBvdGhlci4pPC9lbT48L3A+XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBcIkFzc2lzdC1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJBc3Npc3RcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLkhpZGRlbixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwicG9zaXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS50ZWFtd29yayxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMSBjbGFzcz0nZ29sZC1icmlnaHQnPiVET0NfTkFNRSUgQXNzaXN0czwvaDE+PHA+PHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPiVET0NfTkFNRSU8L3N0cm9uZz4gaXMgPHN0cm9uZz5Bc3Npc3Rpbmc8L3N0cm9uZz4geW91ciBlZmZvcnRzLCBhZGRpbmcgPHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPjEgZGllPC9zdHJvbmc+IHRvIHlvdXIgcG9vbC48L3A+XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBcIlNldHVwLXBvc2l0aXZlLXBvc2l0aW9uXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJTZXR1cFwiLFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLnBvc2l0aW9uLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLkhpZGRlbixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwicG9zaXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS50ZWFtd29yayxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMSBjbGFzcz0nZ29sZC1icmlnaHQnPiVET0NfTkFNRSUgU2V0cyBZb3UgVXA8L2gxPjxwPjxzdHJvbmcgY2xhc3M9J2dvbGQtYnJpZ2h0Jz4lRE9DX05BTUUlPC9zdHJvbmc+IGhhcyBzZXQgeW91IHVwIGZvciBzdWNjZXNzIHdpdGggYSBwcmVjZWRpbmcgPHN0cm9uZz5TZXR1cDwvc3Ryb25nPiBhY3Rpb24sIGluY3JlYXNpbmcgeW91ciA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+UG9zaXRpb248L3N0cm9uZz4gYnkgb25lIGxldmVsLjwvcD5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiUHVzaC1wb3NpdGl2ZS1lZmZlY3RcIixcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlBVU0hcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5lZmZlY3QsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwicG9zaXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxLFxuICAgICAgICAgICAgICAgIGVmZmVjdEtleXM6IFtcIkNvc3QtU3RyZXNzMlwiXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT5QdXNoIGZvciBFZmZlY3Q8L2gxPjxwPkZvciA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz4yIFN0cmVzczwvc3Ryb25nPiwgaW5jcmVhc2UgeW91ciA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+RWZmZWN0PC9zdHJvbmc+IGJ5IG9uZSBsZXZlbC48L3A+XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBcIlNldHVwLXBvc2l0aXZlLWVmZmVjdFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiU2V0dXBcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5lZmZlY3QsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuSGlkZGVuLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJwb3NpdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLnRlYW13b3JrLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxLFxuICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiPGgxIGNsYXNzPSdnb2xkLWJyaWdodCc+JURPQ19OQU1FJSBTZXRzIFlvdSBVcDwvaDE+PHA+PHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPiVET0NfTkFNRSU8L3N0cm9uZz4gaGFzIHNldCB5b3UgdXAgZm9yIHN1Y2Nlc3Mgd2l0aCBhIHByZWNlZGluZyA8c3Ryb25nPlNldHVwPC9zdHJvbmc+IGFjdGlvbiwgaW5jcmVhc2luZyB5b3VyIDxzdHJvbmcgY2xhc3M9J2dvbGQtYnJpZ2h0Jz5FZmZlY3Q8L3N0cm9uZz4gYnkgb25lIGxldmVsLjwvcD5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiUG90ZW5jeS1wb3NpdGl2ZS1lZmZlY3RcIixcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlBvdGVuY3lcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5lZmZlY3QsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuSGlkZGVuLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJwb3NpdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+UG90ZW5jeTwvaDE+PHA+QnkgY2lyY3Vtc3RhbmNlIG9yIGFkdmFudGFnZSwgeW91IGhhdmUgPHN0cm9uZz5Qb3RlbmN5PC9zdHJvbmc+IGluIHRoaXMgYWN0aW9uLCBpbmNyZWFzaW5nIHlvdXIgPHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPkVmZmVjdDwvc3Ryb25nPiBieSBvbmUgbGV2ZWwuPC9wPlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGtleTogXCJQb3RlbmN5LW5lZ2F0aXZlLWVmZmVjdFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiUG90ZW5jeVwiLFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLmVmZmVjdCxcbiAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5IaWRkZW4sXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcIm5lZ2F0aXZlXCIsXG4gICAgICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMSBjbGFzcz0ncmVkLWJyaWdodCc+UG90ZW5jeTwvaDE+PHA+QnkgY2lyY3Vtc3RhbmNlIG9yIGFkdmFudGFnZSwgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+QE9QUE9TSVRJT05fTkFNRUA8L3N0cm9uZz4gaGFzIDxzdHJvbmc+UG90ZW5jeTwvc3Ryb25nPiBhZ2FpbnN0IHlvdSwgcmVkdWNpbmcgeW91ciA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5FZmZlY3Q8L3N0cm9uZz4gYnkgb25lIGxldmVsLlwiXG4gICAgICAgICAgICB9XG4gICAgICAgIF07XG4gICAgfVxuICAgIC8qKlxuICAgICAqIEFzeW5jaHJvbm91c2x5IGNyZWF0ZXMgYSBuZXcgaW5zdGFuY2Ugb2YgdGhpcyBzdWJjbGFzcyBvZiBgQmxhZGVzUm9sbGAuXG4gICAgICpcbiAgICAgKiBPdmVycmlkZXMgdGhlIGBOZXdgIHN0YXRpYyBtZXRob2QgZnJvbSBgQmxhZGVzUm9sbGAsIGFwcGx5aW5nIHN1YmNsYXNzLXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zXG4gICAgICogdG8gdGhlIGluc3RhbmNlIGNyZWF0aW9uIHByb2Nlc3MuIEl0IGVuc3VyZXMgdGhhdCB0aGUgcmV0dXJuZWQgaW5zdGFuY2UgaXMgY29ycmVjdGx5IHR5cGVkXG4gICAgICogYW5kIGNvbmZpZ3VyZWQgZm9yIHRoaXMgc3ViY2xhc3MuXG4gICAgICpcbiAgICAgKiBAcGFyYW0ge0JsYWRlc1JvbGwuQ29uZmlnfSBjb25maWcgVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciBjcmVhdGluZyBhIG5ldyByb2xsIGluc3RhbmNlLFxuICAgICAqIGV4dGVuZGVkIHdpdGggYW55IHN1YmNsYXNzLXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zIG9yIHJlcXVpcmVtZW50cy5cbiAgICAgKlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPEluc3RhbmNlVHlwZTx0aGlzPj59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIGluc3RhbmNlIG9mIHRoaXMgc3ViY2xhc3MuXG4gICAgICpcbiAgICAgKiBAc2VlIHtAbGluayBCbGFkZXNSb2xsLk5ld30gZm9yIHRoZSBiYXNlIG1ldGhvZCdzIGZ1bmN0aW9uYWxpdHkgYW5kIHRoZSBnZW5lcmljIGNyZWF0aW9uIHByb2Nlc3NcbiAgICAgKiBmb3Igcm9sbCBpbnN0YW5jZXMuXG4gICAgICovXG4gICAgc3RhdGljIGFzeW5jIE5ldyhjb25maWcpIHtcbiAgICAgICAgLy8gQnVpbGQgbGluayBjb25maWdcbiAgICAgICAgY29uc3QgbGlua0NvbmZpZyA9IHRoaXMuQnVpbGRMaW5rQ29uZmlnKGNvbmZpZyk7XG4gICAgICAgIGNvbnN0IHBhcnNlZENvbmZpZyA9IHtcbiAgICAgICAgICAgIC4uLmNvbmZpZyxcbiAgICAgICAgICAgIC4uLmxpbmtDb25maWdcbiAgICAgICAgfTtcbiAgICAgICAgLy8gQ2FsbCBzdXBlci5OZXcgYW5kIGNhc3QgdGhlIHJlc3VsdCBhcHByb3ByaWF0ZWx5LlxuICAgICAgICAvLyBUaGUgY2FzdCB0byBJbnN0YW5jZVR5cGU8Qz4gaXMgc2FmZSBoZXJlIGJlY2F1c2UgQyBpcyBjb25zdHJhaW5lZCB0byB0eXBlb2YgQmxhZGVzQWN0aW9uUm9sbC5cbiAgICAgICAgY29uc3Qgcm9sbEluc3QgPSBhd2FpdCBzdXBlci5OZXcocGFyc2VkQ29uZmlnKTtcbiAgICAgICAgcmV0dXJuIHJvbGxJbnN0O1xuICAgIH1cbiAgICBnZXQgcm9sbE1vZHNTY2hlbWFTZXRzKCkge1xuICAgICAgICBjb25zdCByb2xsTW9kU2NoZW1hU2V0cyA9IHN1cGVyLnJvbGxNb2RzU2NoZW1hU2V0cztcbiAgICAgICAgLy8gQWRkIGFkZGl0aW9uYWwgY29uZGl0aW9uYWwgcm9sbCBtb2RzIGJhc2VkIG9uIGVmZmVjdHMgb2YgcHJldmlvdXMgY29uc2VxdWVuY2VzLlxuICAgICAgICBpZiAodGhpcy5yb2xsUHJpbWFyeS5pc1dvcnNlUG9zaXRpb24pIHtcbiAgICAgICAgICAgIHJvbGxNb2RTY2hlbWFTZXRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGtleTogXCJXb3JzZVBvc2l0aW9uLW5lZ2F0aXZlLXBvc2l0aW9uXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJXb3JzZSBQb3NpdGlvblwiLFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLnBvc2l0aW9uLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLkZvcmNlZE9uLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJuZWdhdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW10sXG4gICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+V29yc2UgUG9zaXRpb248L2gxPjxwPkEgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+Q29uc2VxdWVuY2U8L3N0cm9uZz4gb24gYSBwcmV2aW91cyByb2xsIGhhcyB3b3JzZW5lZCB5b3VyIDxzdHJvbmc+UG9zaXRpb248L3N0cm9uZz4uPC9wPlwiXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5hY2NlcHRlZENvbnNlcXVlbmNlcy5zb21lKChjc3EpID0+IGNzcS50eXBlID09PSBDb25zZXF1ZW5jZVR5cGUuUmVkdWNlZEVmZmVjdCkpIHtcbiAgICAgICAgICAgIHJvbGxNb2RTY2hlbWFTZXRzLnB1c2goe1xuICAgICAgICAgICAgICAgIGtleTogXCJSZWR1Y2VkRWZmZWN0LW5lZ2F0aXZlLWVmZmVjdFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiUmVkdWNlZCBFZmZlY3RcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5lZmZlY3QsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuRm9yY2VkT24sXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcIm5lZ2F0aXZlXCIsXG4gICAgICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICBlZmZlY3RLZXlzOiBbXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT5SZWR1Y2VkIEVmZmVjdDwvaDE+PHA+QSA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5Db25zZXF1ZW5jZTwvc3Ryb25nPiBoYXMgd29yc2VuZWQgeW91ciA8c3Ryb25nPkVmZmVjdDwvc3Ryb25nPi48L3A+XCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByb2xsTW9kU2NoZW1hU2V0cztcbiAgICB9XG4gICAgZ2V0IGNvbGxhYlRlbXBsYXRlKCkge1xuICAgICAgICByZXR1cm4gYHN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9yb2xsL3JvbGwtY29sbGFiLWFjdGlvbiR7Z2FtZS51c2VyLmlzR00gPyBcIi1nbVwiIDogXCJcIn0uaGJzYDtcbiAgICB9XG4gICAgZ2V0IGNoYXRUZW1wbGF0ZSgpIHtcbiAgICAgICAgY29uc3QgdGVtcGxhdGVQYXJ0cyA9IFtcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NoYXQvcm9sbC1yZXN1bHQvYWN0aW9uXCIsXG4gICAgICAgICAgICB0aGlzLnJvbGxDbG9ja0tleSA/IFwiLWNsb2NrXCIgOiBcIlwiXG4gICAgICAgIF07XG4gICAgICAgIGlmICh0aGlzLnJvbGxEb3dudGltZUFjdGlvbiAmJiBbXG4gICAgICAgICAgICBEb3dudGltZUFjdGlvbi5BY3F1aXJlQXNzZXQsIC8vIGFjdGlvbi1hY3F1aXJlYXNzZXRcbiAgICAgICAgICAgIERvd250aW1lQWN0aW9uLlJlZHVjZUhlYXQsIC8vICAgYWN0aW9uLXJlZHVjZWhlYXRcbiAgICAgICAgICAgIERvd250aW1lQWN0aW9uLlJlY292ZXIgLy8gICAgICAgYWN0aW9uLWNsb2NrLXJlY292ZXJcbiAgICAgICAgXS5pbmNsdWRlcyh0aGlzLnJvbGxEb3dudGltZUFjdGlvbikpIHtcbiAgICAgICAgICAgIHRlbXBsYXRlUGFydHMucHVzaChgLSR7VS5sQ2FzZSh0aGlzLnJvbGxEb3dudGltZUFjdGlvbil9YCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5yb2xsU3ViVHlwZSAmJiBbXG4gICAgICAgICAgICBSb2xsU3ViVHlwZS5HYXRoZXJJbmZvIC8vICAgICAgYWN0aW9uLWdhdGhlcmluZm9cbiAgICAgICAgXS5pbmNsdWRlcyh0aGlzLnJvbGxTdWJUeXBlKSkge1xuICAgICAgICAgICAgdGVtcGxhdGVQYXJ0cy5wdXNoKGAtJHtVLmxDYXNlKHRoaXMucm9sbFN1YlR5cGUpfWApO1xuICAgICAgICB9XG4gICAgICAgIHRlbXBsYXRlUGFydHMucHVzaChcIi5oYnNcIik7XG4gICAgICAgIHJldHVybiB0ZW1wbGF0ZVBhcnRzLmpvaW4oXCJcIik7XG4gICAgfVxuICAgIGdldCByb2xsUmVzdWx0KCkge1xuICAgICAgICBpZiAoIXRoaXMuaXNSZXNvbHZlZCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmlzQ3JpdGljYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBSb2xsUmVzdWx0LmNyaXRpY2FsO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmlzU3VjY2Vzcykge1xuICAgICAgICAgICAgcmV0dXJuIFJvbGxSZXN1bHQuc3VjY2VzcztcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5pc1BhcnRpYWwpIHtcbiAgICAgICAgICAgIHJldHVybiBSb2xsUmVzdWx0LnBhcnRpYWw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFJvbGxSZXN1bHQuZmFpbDtcbiAgICB9XG4gICAgYXN5bmMgcmVzb2x2ZVJvbGxSZXN1bHQoKSB7XG4gICAgICAgIGVMb2cuY2hlY2tMb2cyKFwiYmxhZGVzUm9sbFwiLCBcIltCbGFkZXNBY3Rpb25Sb2xsXSBDb3N0c1wiLCB0aGlzLmdldFJvbGxDb3N0cygpKTtcbiAgICAgICAgY29uc3QgYXJtb3JDb3N0ID0gdGhpcy5nZXRSb2xsQ29zdHMoKVxuICAgICAgICAgICAgLmZpbHRlcigoY29zdERhdGEpID0+IGNvc3REYXRhLmNvc3RUeXBlID09PSBcIkFybW9yXCIpXG4gICAgICAgICAgICAubGVuZ3RoO1xuICAgICAgICBpZiAodGhpcy5yb2xsUHJpbWFyeURvYyBpbnN0YW5jZW9mIEJsYWRlc1BDKSB7XG4gICAgICAgICAgICBjb25zdCBzdHJlc3NDb3N0ID0gdGhpcy5nZXRSb2xsQ29zdHMoKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGNvc3REYXRhKSA9PiBjb3N0RGF0YS5jb3N0VHlwZSA9PT0gXCJTdHJlc3NcIilcbiAgICAgICAgICAgICAgICAucmVkdWNlKChhY2MsIGNvc3REYXRhKSA9PiBhY2MgKyBjb3N0RGF0YS5jb3N0QW1vdW50LCAwKTtcbiAgICAgICAgICAgIGlmIChzdHJlc3NDb3N0ICE9PSAwKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yb2xsUHJpbWFyeURvYy5hZGp1c3RTdHJlc3Moc3RyZXNzQ29zdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzcGVjQXJtb3JDb3N0ID0gdGhpcy5nZXRSb2xsQ29zdHMoKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGNvc3REYXRhKSA9PiBjb3N0RGF0YS5jb3N0VHlwZSA9PT0gXCJTcGVjaWFsQXJtb3JcIilcbiAgICAgICAgICAgICAgICAubGVuZ3RoO1xuICAgICAgICAgICAgaWYgKHNwZWNBcm1vckNvc3QgIT09IDApIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJvbGxQcmltYXJ5RG9jLnNwZW5kU3BlY2lhbEFybW9yKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGFybW9yQ29zdCAhPT0gMCkge1xuICAgICAgICAgICAgdGhpcy5yb2xsUHJpbWFyeS5zcGVuZEFybW9yKGFybW9yQ29zdCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuZ2V0Um9sbE1vZEJ5S2V5KFwiV29yc2VQb3NpdGlvbi1uZWdhdGl2ZS1wb3NpdGlvblwiKT8uaXNBY3RpdmUpIHtcbiAgICAgICAgICAgIHRoaXMucm9sbFByaW1hcnlEb2M/LnVuc2V0RmxhZyhcImV1bm9zLWJsYWRlc1wiLCBcImlzV29yc2VQb3NpdGlvblwiKTtcbiAgICAgICAgfVxuICAgIH1cbn1cbmNsYXNzIEJsYWRlc1Jlc2lzdGFuY2VSb2xsIGV4dGVuZHMgQmxhZGVzUm9sbCB7XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoY29uZmlnKSB7XG4gICAgICAgIC8vIFZhbGlkYXRlIGNvbnNlcXVlbmNlRGF0YVxuICAgICAgICBpZiAoIWNvbmZpZy5yZXNpc3RhbmNlRGF0YSB8fCAhQmxhZGVzQ29uc2VxdWVuY2UuSXNWYWxpZENvbnNlcXVlbmNlRGF0YShjb25maWcucmVzaXN0YW5jZURhdGE/LmNvbnNlcXVlbmNlKSkge1xuICAgICAgICAgICAgZUxvZy5lcnJvcihcInJvbGxDb2xsYWJcIiwgXCJbUHJlcGFyZVJlc2lzdGFuY2VSb2xsXSBCYWQgUm9sbCBDb25zZXF1ZW5jZSBEYXRhLlwiLCBjb25maWcpO1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW1ByZXBhcmVSZXNpc3RhbmNlUm9sbCgpXSBCYWQgQ29uc2VxdWVuY2UgRGF0YSBmb3IgUmVzaXN0YW5jZSBSb2xsXCIpO1xuICAgICAgICB9XG4gICAgICAgIC8vIFNldCByb2xsVHJhaXRcbiAgICAgICAgY29uZmlnLnJvbGxUcmFpdCA9IGNvbmZpZy5yZXNpc3RhbmNlRGF0YS5jb25zZXF1ZW5jZS5hdHRyaWJ1dGU7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwiYmxhZGVzUm9sbFwiLCBcIkJsYWRlc1JvbGwuUHJlcGFyZVJlc2lzdGFuY2VSb2xsKCkgWzFdXCIsIHsgY29uZmlnIH0pO1xuICAgICAgICByZXR1cm4gY29uZmlnO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBc3luY2hyb25vdXNseSBjcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoaXMgc3ViY2xhc3Mgb2YgYEJsYWRlc1JvbGxgLlxuICAgICAqXG4gICAgICogT3ZlcnJpZGVzIHRoZSBgTmV3YCBzdGF0aWMgbWV0aG9kIGZyb20gYEJsYWRlc1JvbGxgLCBhcHBseWluZyBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9uc1xuICAgICAqIHRvIHRoZSBpbnN0YW5jZSBjcmVhdGlvbiBwcm9jZXNzLiBJdCBlbnN1cmVzIHRoYXQgdGhlIHJldHVybmVkIGluc3RhbmNlIGlzIGNvcnJlY3RseSB0eXBlZFxuICAgICAqIGFuZCBjb25maWd1cmVkIGZvciB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLkNvbmZpZ30gY29uZmlnIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgY3JlYXRpbmcgYSBuZXcgcm9sbCBpbnN0YW5jZSxcbiAgICAgKiBleHRlbmRlZCB3aXRoIGFueSBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBvciByZXF1aXJlbWVudHMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8dGhpcz4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBpbnN0YW5jZSBvZiB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHNlZSB7QGxpbmsgQmxhZGVzUm9sbC5OZXd9IGZvciB0aGUgYmFzZSBtZXRob2QncyBmdW5jdGlvbmFsaXR5IGFuZCB0aGUgZ2VuZXJpYyBjcmVhdGlvbiBwcm9jZXNzXG4gICAgICogZm9yIHJvbGwgaW5zdGFuY2VzLlxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBOZXcoY29uZmlnKSB7XG4gICAgICAgIC8vIEJ1aWxkIGxpbmsgY29uZmlnXG4gICAgICAgIGNvbnN0IGxpbmtDb25maWcgPSB0aGlzLkJ1aWxkTGlua0NvbmZpZyhjb25maWcpO1xuICAgICAgICBjb25zdCBwYXJzZWRDb25maWcgPSB7XG4gICAgICAgICAgICAuLi5jb25maWcsXG4gICAgICAgICAgICAuLi5saW5rQ29uZmlnXG4gICAgICAgIH07XG4gICAgICAgIC8vIENhbGwgc3VwZXIuTmV3IGFuZCBjYXN0IHRoZSByZXN1bHQgYXBwcm9wcmlhdGVseS5cbiAgICAgICAgLy8gVGhlIGNhc3QgdG8gSW5zdGFuY2VUeXBlPEM+IGlzIHNhZmUgaGVyZSBiZWNhdXNlIEMgaXMgY29uc3RyYWluZWQgdG8gdHlwZW9mIEJsYWRlc1Jlc2lzdGFuY2VSb2xsLlxuICAgICAgICBjb25zdCByb2xsSW5zdCA9IGF3YWl0IHN1cGVyLk5ldyhwYXJzZWRDb25maWcpO1xuICAgICAgICByZXR1cm4gcm9sbEluc3Q7XG4gICAgfVxuICAgIGdldCBjb2xsYWJUZW1wbGF0ZSgpIHtcbiAgICAgICAgcmV0dXJuIGBzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcm9sbC9yb2xsLWNvbGxhYi1yZXNpc3RhbmNlJHtnYW1lLnVzZXIuaXNHTSA/IFwiLWdtXCIgOiBcIlwifS5oYnNgO1xuICAgIH1cbiAgICBnZXQgY2hhdFRlbXBsYXRlKCkge1xuICAgICAgICByZXR1cm4gXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9yZXNpc3RhbmNlLmhic1wiO1xuICAgIH1cbiAgICBnZXQgc3RyZXNzQ29zdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUmVzb2x2ZWQpIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGRpZVZhbHMgPSBbLi4udGhpcy5maW5hbERpZVZhbHNdO1xuICAgICAgICBpZiAodGhpcy5pc0NyaXRpY2FsKSB7XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDYgLSAoZGllVmFscy5zaGlmdCgpID8/IDApO1xuICAgIH1cbiAgICBnZXQgcm9sbFJlc3VsdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUmVzb2x2ZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zdHJlc3NDb3N0O1xuICAgIH1cbiAgICBhc3luYyByZXNvbHZlUm9sbFJlc3VsdCgpIHtcbiAgICAgICAgaWYgKHRoaXMucm9sbFByaW1hcnlEb2MgaW5zdGFuY2VvZiBCbGFkZXNQQyAmJiB0aGlzLnN0cmVzc0Nvc3QgIT09IDApIHtcbiAgICAgICAgICAgIHRoaXMucm9sbFByaW1hcnlEb2MuYWRqdXN0U3RyZXNzKHRoaXMuc3RyZXNzQ29zdCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5jbGFzcyBCbGFkZXNJbmxpbmVSZXNpc3RhbmNlUm9sbCBleHRlbmRzIEJsYWRlc1Jlc2lzdGFuY2VSb2xsIHtcbiAgICBnZXQgY2hhdFRlbXBsYXRlKCkge1xuICAgICAgICByZXR1cm4gXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9jb21wb25lbnRzL2lubGluZS1yZXNpc3RhbmNlLmhic1wiO1xuICAgIH1cbn1cbmNsYXNzIEJsYWRlc0ZvcnR1bmVSb2xsIGV4dGVuZHMgQmxhZGVzUm9sbCB7XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoY29uZmlnKSB7XG4gICAgICAgIC8vIFZhbGlkYXRlIHRoZSByb2xsVHJhaXRcbiAgICAgICAgaWYgKCEoVS5pc0ludChjb25maWcucm9sbFRyYWl0KSB8fCBVLmxDYXNlKGNvbmZpZy5yb2xsVHJhaXQpIGluIHsgLi4uQWN0aW9uVHJhaXQsIC4uLkF0dHJpYnV0ZVRyYWl0LCAuLi5GYWN0b3IgfSkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW1ByZXBhcmVGb3J0dW5lUm9sbCgpXSBCYWQgUm9sbFRyYWl0IGZvciBGb3J0dW5lIFJvbGw6ICR7Y29uZmlnLnJvbGxUcmFpdH1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY29uZmlnO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBc3luY2hyb25vdXNseSBjcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoaXMgc3ViY2xhc3Mgb2YgYEJsYWRlc1JvbGxgLlxuICAgICAqXG4gICAgICogT3ZlcnJpZGVzIHRoZSBgTmV3YCBzdGF0aWMgbWV0aG9kIGZyb20gYEJsYWRlc1JvbGxgLCBhcHBseWluZyBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9uc1xuICAgICAqIHRvIHRoZSBpbnN0YW5jZSBjcmVhdGlvbiBwcm9jZXNzLiBJdCBlbnN1cmVzIHRoYXQgdGhlIHJldHVybmVkIGluc3RhbmNlIGlzIGNvcnJlY3RseSB0eXBlZFxuICAgICAqIGFuZCBjb25maWd1cmVkIGZvciB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLkNvbmZpZ30gY29uZmlnIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgY3JlYXRpbmcgYSBuZXcgcm9sbCBpbnN0YW5jZSxcbiAgICAgKiBleHRlbmRlZCB3aXRoIGFueSBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBvciByZXF1aXJlbWVudHMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8dGhpcz4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBpbnN0YW5jZSBvZiB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHNlZSB7QGxpbmsgQmxhZGVzUm9sbC5OZXd9IGZvciB0aGUgYmFzZSBtZXRob2QncyBmdW5jdGlvbmFsaXR5IGFuZCB0aGUgZ2VuZXJpYyBjcmVhdGlvbiBwcm9jZXNzXG4gICAgICogZm9yIHJvbGwgaW5zdGFuY2VzLlxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBOZXcoY29uZmlnKSB7XG4gICAgICAgIC8vIEJ1aWxkIGxpbmsgY29uZmlnXG4gICAgICAgIGNvbnN0IGxpbmtDb25maWcgPSB0aGlzLkJ1aWxkTGlua0NvbmZpZyhjb25maWcpO1xuICAgICAgICBjb25zdCBwYXJzZWRDb25maWcgPSB7XG4gICAgICAgICAgICAuLi5jb25maWcsXG4gICAgICAgICAgICAuLi5saW5rQ29uZmlnXG4gICAgICAgIH07XG4gICAgICAgIC8vIENhbGwgc3VwZXIuTmV3IGFuZCBjYXN0IHRoZSByZXN1bHQgYXBwcm9wcmlhdGVseS5cbiAgICAgICAgLy8gVGhlIGNhc3QgdG8gSW5zdGFuY2VUeXBlPEM+IGlzIHNhZmUgaGVyZSBiZWNhdXNlIEMgaXMgY29uc3RyYWluZWQgdG8gdHlwZW9mIEJsYWRlc0ZvcnR1bmVSb2xsLlxuICAgICAgICBjb25zdCByb2xsSW5zdCA9IGF3YWl0IHN1cGVyLk5ldyhwYXJzZWRDb25maWcpO1xuICAgICAgICByZXR1cm4gcm9sbEluc3Q7XG4gICAgfVxufVxuY2xhc3MgQmxhZGVzSW5kdWxnZVZpY2VSb2xsIGV4dGVuZHMgQmxhZGVzUm9sbCB7XG4gICAgc3RhdGljIEFwcGx5U2NoZW1hRGVmYXVsdHMoY29uZmlnKSB7XG4gICAgICAgIC8vIFZhbGlkYXRlIHJvbGxQcmltYXJ5XG4gICAgICAgIGNvbnN0IHJvbGxQcmltYXJ5RG9jID0gQmxhZGVzUm9sbFByaW1hcnkuR2V0RG9jKGNvbmZpZy5yb2xsUHJpbWFyeURhdGE/LnJvbGxQcmltYXJ5SUQpO1xuICAgICAgICBpZiAoIXJvbGxQcmltYXJ5RG9jIHx8ICFCbGFkZXNQQy5Jc1R5cGUocm9sbFByaW1hcnlEb2MpKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzUm9sbC5QcmVwYXJlSW5kdWxnZVZpY2VSb2xsQ29uZmlnXSBSb2xsUHJpbWFyeSBtdXN0IGJlIGEgUEMgZm9yIEluZHVsZ2UgVmljZSByb2xscy5cIik7XG4gICAgICAgIH1cbiAgICAgICAgLy8gU2V0IHJvbGxUcmFpdFxuICAgICAgICBjb25zdCB7IGF0dHJpYnV0ZXMgfSA9IHJvbGxQcmltYXJ5RG9jO1xuICAgICAgICBjb25zdCBtaW5BdHRyVmFsID0gTWF0aC5taW4oLi4uT2JqZWN0LnZhbHVlcyhhdHRyaWJ1dGVzKSk7XG4gICAgICAgIGNvbmZpZy5yb2xsVHJhaXQgPSBVLnNhbXBsZShPYmplY3QudmFsdWVzKEF0dHJpYnV0ZVRyYWl0KS5maWx0ZXIoKGF0dHIpID0+IGF0dHJpYnV0ZXNbYXR0cl0gPT09IG1pbkF0dHJWYWwpKVswXTtcbiAgICAgICAgLy8gU2V0IG90aGVyIGtub3duIGNvbmZpZyB2YWx1ZXNcbiAgICAgICAgY29uZmlnLnJvbGxEb3dudGltZUFjdGlvbiA9IERvd250aW1lQWN0aW9uLkluZHVsZ2VWaWNlO1xuICAgICAgICByZXR1cm4gY29uZmlnO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBBc3luY2hyb25vdXNseSBjcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIHRoaXMgc3ViY2xhc3Mgb2YgYEJsYWRlc1JvbGxgLlxuICAgICAqXG4gICAgICogT3ZlcnJpZGVzIHRoZSBgTmV3YCBzdGF0aWMgbWV0aG9kIGZyb20gYEJsYWRlc1JvbGxgLCBhcHBseWluZyBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9uc1xuICAgICAqIHRvIHRoZSBpbnN0YW5jZSBjcmVhdGlvbiBwcm9jZXNzLiBJdCBlbnN1cmVzIHRoYXQgdGhlIHJldHVybmVkIGluc3RhbmNlIGlzIGNvcnJlY3RseSB0eXBlZFxuICAgICAqIGFuZCBjb25maWd1cmVkIGZvciB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHBhcmFtIHtCbGFkZXNSb2xsLkNvbmZpZ30gY29uZmlnIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgY3JlYXRpbmcgYSBuZXcgcm9sbCBpbnN0YW5jZSxcbiAgICAgKiBleHRlbmRlZCB3aXRoIGFueSBzdWJjbGFzcy1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBvciByZXF1aXJlbWVudHMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxJbnN0YW5jZVR5cGU8dGhpcz4+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBpbnN0YW5jZSBvZiB0aGlzIHN1YmNsYXNzLlxuICAgICAqXG4gICAgICogQHNlZSB7QGxpbmsgQmxhZGVzUm9sbC5OZXd9IGZvciB0aGUgYmFzZSBtZXRob2QncyBmdW5jdGlvbmFsaXR5IGFuZCB0aGUgZ2VuZXJpYyBjcmVhdGlvbiBwcm9jZXNzXG4gICAgICogZm9yIHJvbGwgaW5zdGFuY2VzLlxuICAgICAqL1xuICAgIHN0YXRpYyBhc3luYyBOZXcoY29uZmlnKSB7XG4gICAgICAgIC8vIEJ1aWxkIGxpbmsgY29uZmlnXG4gICAgICAgIGNvbnN0IGxpbmtDb25maWcgPSB0aGlzLkJ1aWxkTGlua0NvbmZpZyhjb25maWcpO1xuICAgICAgICBjb25zdCBwYXJzZWRDb25maWcgPSB7XG4gICAgICAgICAgICAuLi5jb25maWcsXG4gICAgICAgICAgICAuLi5saW5rQ29uZmlnXG4gICAgICAgIH07XG4gICAgICAgIC8vIENhbGwgc3VwZXIuTmV3IGFuZCBjYXN0IHRoZSByZXN1bHQgYXBwcm9wcmlhdGVseS5cbiAgICAgICAgLy8gVGhlIGNhc3QgdG8gSW5zdGFuY2VUeXBlPEM+IGlzIHNhZmUgaGVyZSBiZWNhdXNlIEMgaXMgY29uc3RyYWluZWQgdG8gdHlwZW9mIEJsYWRlc0luZHVsZ2VWaWNlUm9sbC5cbiAgICAgICAgY29uc3Qgcm9sbEluc3QgPSBhd2FpdCBzdXBlci5OZXcocGFyc2VkQ29uZmlnKTtcbiAgICAgICAgcmV0dXJuIHJvbGxJbnN0O1xuICAgIH1cbiAgICBnZXQgY29sbGFiVGVtcGxhdGUoKSB7XG4gICAgICAgIHJldHVybiBgc3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3JvbGwvcm9sbC1jb2xsYWItaW5kdWxnZXZpY2Uke2dhbWUudXNlci5pc0dNID8gXCItZ21cIiA6IFwiXCJ9Lmhic2A7XG4gICAgfVxuICAgIGdldCBjaGF0VGVtcGxhdGUoKSB7XG4gICAgICAgIHJldHVybiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2luZHVsZ2V2aWNlLmhic1wiO1xuICAgIH1cbiAgICBnZXQgcm9sbFJlc3VsdCgpIHtcbiAgICAgICAgaWYgKCF0aGlzLmlzUmVzb2x2ZWQpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5oaWdoZXN0RGllVmFsO1xuICAgIH1cbiAgICBhc3luYyByZXNvbHZlUm9sbFJlc3VsdCgpIHtcbiAgICAgICAgaWYgKEJsYWRlc1BDLklzVHlwZSh0aGlzLnJvbGxQcmltYXJ5RG9jKSkge1xuICAgICAgICAgICAgdGhpcy5yb2xsUHJpbWFyeURvYy5pbmR1bGdlU3RyZXNzKHRoaXMuaGlnaGVzdERpZVZhbCk7XG4gICAgICAgIH1cbiAgICB9XG59XG5jbGFzcyBCbGFkZXNFbmdhZ2VtZW50Um9sbCBleHRlbmRzIEJsYWRlc0ZvcnR1bmVSb2xsIHtcbiAgICBzdGF0aWMgZ2V0IERlZmF1bHRSb2xsTW9kU2NoZW1hU2V0KCkge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGtleTogXCJCb2xkUGxhbi1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJCb2xkIFBsYW5cIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPZmYsXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcInBvc2l0aXZlXCIsXG4gICAgICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICBlZmZlY3RLZXlzOiBbXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT48L2gxPjxwPjwvcD5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiQ29tcGxleFBsYW4tbmVnYXRpdmUtcm9sbFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ29tcGxleCBQbGFuXCIsXG4gICAgICAgICAgICAgICAgc2VjdGlvbjogUm9sbE1vZFNlY3Rpb24ucm9sbCxcbiAgICAgICAgICAgICAgICBiYXNlX3N0YXR1czogUm9sbE1vZFN0YXR1cy5Ub2dnbGVkT2ZmLFxuICAgICAgICAgICAgICAgIHBvc05lZzogXCJuZWdhdGl2ZVwiLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmdlbmVyYWwsXG4gICAgICAgICAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW10sXG4gICAgICAgICAgICAgICAgdG9vbHRpcDogXCI8aDE+PC9oMT48cD48L3A+XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBcIkV4cGxvaXRXZWFrbmVzcy1wb3NpdGl2ZS1yb2xsXCIsXG4gICAgICAgICAgICAgICAgbmFtZTogXCJFeHBsb2l0aW5nIGEgV2Vha25lc3NcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPZmYsXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcInBvc2l0aXZlXCIsXG4gICAgICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICBlZmZlY3RLZXlzOiBbXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT48L2gxPjxwPjwvcD5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiV2VsbERlZmVuZGVkLW5lZ2F0aXZlLXJvbGxcIixcbiAgICAgICAgICAgICAgICBuYW1lOiBcIldlbGwtRGVmZW5kZWRcIixcbiAgICAgICAgICAgICAgICBzZWN0aW9uOiBSb2xsTW9kU2VjdGlvbi5yb2xsLFxuICAgICAgICAgICAgICAgIGJhc2Vfc3RhdHVzOiBSb2xsTW9kU3RhdHVzLlRvZ2dsZWRPZmYsXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcIm5lZ2F0aXZlXCIsXG4gICAgICAgICAgICAgICAgbW9kVHlwZTogUm9sbE1vZFR5cGUuZ2VuZXJhbCxcbiAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICBlZmZlY3RLZXlzOiBbXSxcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBcIjxoMT48L2gxPjxwPjwvcD5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBrZXk6IFwiSGVscEZyb21GcmllbmQtcG9zaXRpdmUtcm9sbFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiSGVscCBGcm9tIGEgRnJpZW5kXCIsXG4gICAgICAgICAgICAgICAgc2VjdGlvbjogUm9sbE1vZFNlY3Rpb24ucG9zaXRpb24sXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwicG9zaXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxLFxuICAgICAgICAgICAgICAgIGVmZmVjdEtleXM6IFtdLFxuICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiPGgxPkhlbHAgRnJvbSBhIEZyaWVuZDwvaDE+PHA+QWRkIDxzdHJvbmc+KzFkPC9zdHJvbmc+IGlmIHlvdSBlbmxpc3QgdGhlIGhlbHAgb2YgYSBmcmllbmQgb3IgY29udGFjdC48L3A+XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5OiBcIkVuZW15SW50ZXJmZXJlbmNlLW5lZ2F0aXZlLXJvbGxcIixcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkVuZW15IEludGVyZmVyZW5jZVwiLFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLnJvbGwsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9mZixcbiAgICAgICAgICAgICAgICBwb3NOZWc6IFwibmVnYXRpdmVcIixcbiAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5nZW5lcmFsLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAxLFxuICAgICAgICAgICAgICAgIGVmZmVjdEtleXM6IFtdLFxuICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiPGgxPjwvaDE+PHA+PC9wPlwiXG4gICAgICAgICAgICB9XG4gICAgICAgIF07XG4gICAgfVxuICAgIGdldCBjaGF0VGVtcGxhdGUoKSB7XG4gICAgICAgIHJldHVybiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jaGF0L3JvbGwtcmVzdWx0L2ZvcnR1bmUtZW5nYWdlbWVudC5oYnNcIjtcbiAgICB9XG59XG5jbGFzcyBCbGFkZXNJbmNhcmNlcmF0aW9uUm9sbCBleHRlbmRzIEJsYWRlc0ZvcnR1bmVSb2xsIHtcbiAgICBnZXQgY2hhdFRlbXBsYXRlKCkge1xuICAgICAgICByZXR1cm4gXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY2hhdC9yb2xsLXJlc3VsdC9mb3J0dW5lLWluY2FyY2VyYXRpb24uaGJzXCI7XG4gICAgfVxufVxuLy8gI3JlZ2lvbiBFWFBPUlRTIH5cbmV4cG9ydCB7IEJsYWRlc1JvbGxNb2QsIEJsYWRlc1JvbGxQcmltYXJ5LCBCbGFkZXNSb2xsT3Bwb3NpdGlvbiwgQmxhZGVzUm9sbFBhcnRpY2lwYW50IH07XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNSb2xsO1xuZXhwb3J0IHsgQmxhZGVzQWN0aW9uUm9sbCwgQmxhZGVzUmVzaXN0YW5jZVJvbGwsIEJsYWRlc0lubGluZVJlc2lzdGFuY2VSb2xsLCBCbGFkZXNGb3J0dW5lUm9sbCwgQmxhZGVzSW5kdWxnZVZpY2VSb2xsLCBCbGFkZXNFbmdhZ2VtZW50Um9sbCwgQmxhZGVzSW5jYXJjZXJhdGlvblJvbGwgfTtcbi8vICNlbmRyZWdpb25cbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/classes/BladesRoll.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesScene.ts": +/*!***********************************!*\ + !*** ./ts/classes/BladesScene.ts ***! + \***********************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\nclass BladesScene extends Scene {\n async registerClockKey(clockKey) {\n this.update({ [`clockKeys.${clockKey.id}`]: true });\n }\n async unregisterClockKey(clockKey) {\n if (typeof clockKey === \"string\") {\n this.update({ [`clockKeys.-=${clockKey}`]: null });\n }\n else {\n this.update({ [`clockKeys.-=${clockKey.id}`]: null });\n }\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesScene);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jbGFzc2VzL0JsYWRlc1NjZW5lLnRzIiwibWFwcGluZ3MiOiI7QUFBQTtBQUNBO0FBQ0Esc0JBQXNCLGNBQWMsWUFBWSxVQUFVO0FBQzFEO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixnQkFBZ0IsU0FBUyxVQUFVO0FBQzdEO0FBQ0E7QUFDQSwwQkFBMEIsZ0JBQWdCLFlBQVksVUFBVTtBQUNoRTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxXQUFXLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jbGFzc2VzL0JsYWRlc1NjZW5lLnRzPzllOGUiXSwic291cmNlc0NvbnRlbnQiOlsiY2xhc3MgQmxhZGVzU2NlbmUgZXh0ZW5kcyBTY2VuZSB7XG4gICAgYXN5bmMgcmVnaXN0ZXJDbG9ja0tleShjbG9ja0tleSkge1xuICAgICAgICB0aGlzLnVwZGF0ZSh7IFtgY2xvY2tLZXlzLiR7Y2xvY2tLZXkuaWR9YF06IHRydWUgfSk7XG4gICAgfVxuICAgIGFzeW5jIHVucmVnaXN0ZXJDbG9ja0tleShjbG9ja0tleSkge1xuICAgICAgICBpZiAodHlwZW9mIGNsb2NrS2V5ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZSh7IFtgY2xvY2tLZXlzLi09JHtjbG9ja0tleX1gXTogbnVsbCB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMudXBkYXRlKHsgW2BjbG9ja0tleXMuLT0ke2Nsb2NrS2V5LmlkfWBdOiBudWxsIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzU2NlbmU7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/classes/BladesScene.ts\n"); + +/***/ }), + +/***/ "./ts/classes/BladesTargetLink.ts": +/*!****************************************!*\ + !*** ./ts/classes/BladesTargetLink.ts ***! + \****************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _BladesChat__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./BladesChat */ \"./ts/classes/BladesChat.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\nclass BladesTargetLink {\n // #region STATIC METHODS ~\n static get ValidTargetClasses() {\n return [\n _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor,\n _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem,\n _BladesChat__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n User\n ];\n }\n static IsValidConfig(ref) {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isSimpleObj(ref)\n && (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(ref.target)\n || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocUUID(ref.target)\n || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(ref.targetID)\n || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocUUID(ref.targetID)\n || this.ValidTargetClasses.some((cls) => ref.target instanceof cls))\n && (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetKey(ref.targetKey) || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetFlagKey(ref.targetFlagKey))\n && !(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetKey(ref.targetKey) && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetFlagKey(ref.targetFlagKey));\n }\n static IsValidData(ref) {\n return _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isSimpleObj(ref)\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(ref.id)\n && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocUUID(ref.targetID)\n && (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetKey(ref.targetKey) || _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetFlagKey(ref.targetFlagKey))\n && !(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetKey(ref.targetKey) && _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isTargetFlagKey(ref.targetFlagKey));\n // && (typeof ref.isScopingById === \"boolean\");\n }\n static #ParseChildLinkData(childData, parentLinkData) {\n if (!parentLinkData) {\n return childData;\n }\n const keyPrefixParts = \"targetKey\" in parentLinkData\n ? [parentLinkData.targetKey]\n : [parentLinkData.targetFlagKey];\n if (parentLinkData.isScopingById) {\n keyPrefixParts.push(parentLinkData.id);\n }\n const keyPrefix = keyPrefixParts.join(\".\");\n if (\"targetKey\" in childData && \"targetKey\" in parentLinkData) {\n if (childData.targetKey.startsWith(`${keyPrefix}.`)) {\n // Remove the keyPrefix and the following dot from childData.targetKey\n childData.targetKey = childData.targetKey.slice(keyPrefix.length + 1);\n }\n childData.targetKey = [\n parentLinkData.targetKey,\n parentLinkData.isScopingById ? parentLinkData.id : undefined,\n childData.targetKey\n ].filter(Boolean).join(\".\");\n }\n else if (\"targetFlagKey\" in childData && \"targetFlagKey\" in parentLinkData) {\n if (childData.targetFlagKey.startsWith(`${keyPrefix}.`)) {\n // Remove the keyPrefix and the following dot from childData.targetFlagKey\n childData.targetFlagKey = childData.targetFlagKey.slice(keyPrefix.length + 1);\n }\n childData.targetFlagKey = [\n parentLinkData.targetFlagKey,\n parentLinkData.isScopingById ? parentLinkData.id : undefined,\n childData.targetFlagKey\n ].filter(Boolean).join(\".\");\n }\n else {\n throw new Error(\"[BladesTargetLink.ParseChildLinkData] targetKey/targetFlagKey mismatch between provided partialConfig and parentLinkData.\");\n }\n return childData;\n }\n static BuildLinkConfig(partialConfig) {\n // const {target, targetID, targetKey, targetFlagKey, isScopingById} = partialConfig;\n if (\"target\" in partialConfig) {\n if (\"targetKey\" in partialConfig) {\n return {\n target: partialConfig.target,\n targetKey: partialConfig.targetKey,\n isScopingById: partialConfig.isScopingById\n };\n }\n else if (\"targetFlagKey\" in partialConfig) {\n return {\n target: partialConfig.target,\n targetFlagKey: partialConfig.targetFlagKey,\n isScopingById: partialConfig.isScopingById\n };\n }\n throw new Error(\"[BladesTargetLink.BuildConfig] Must provide a targetKey or targetFlagKey.\");\n }\n else if (\"targetID\" in partialConfig) {\n if (\"targetKey\" in partialConfig) {\n return {\n targetID: partialConfig.targetID,\n targetKey: partialConfig.targetKey,\n isScopingById: partialConfig.isScopingById\n };\n }\n else if (\"targetFlagKey\" in partialConfig) {\n return {\n targetID: partialConfig.targetID,\n targetFlagKey: partialConfig.targetFlagKey,\n isScopingById: partialConfig.isScopingById\n };\n }\n throw new Error(\"[BladesTargetLink.BuildConfig] Must provide a targetKey or targetFlagKey.\");\n }\n throw new Error(\"[BladesTargetLink.BuildConfig] Must provide a target or targetID.\");\n }\n /**\n * This private static method is used to transform a configuration object into a data object for BladesTargetLink.\n * It checks if the provided configuration object is already valid data, and if so, returns it directly.\n * Otherwise, it partitions the configuration object into link-specific configuration and additional schema data,\n * constructs a full link configuration, and then creates a data object with a new random ID and the target UUID.\n * The method ensures that either 'targetKey' or 'targetFlagKey' is present and throws an error if the configuration is invalid.\n *\n * @template Schema - The additional schema data required by the subclass.\n * @param {BladesTargetLink.Config | BladesTargetLink.Data & Partial} config - The configuration object that may contain BladesTargetLink properties and any subclass-specific schema data.\n * @returns {BladesTargetLink.Data & Partial} - The fully constructed data object with necessary properties for BladesTargetLink.\n * @throws {Error} - Throws an error if the configuration object is invalid, lacks a target reference, or if both 'targetKey' and 'targetFlagKey' are provided.\n */\n static #ParseConfigToData(config, parentLinkData) {\n if (this.IsValidData(config)) {\n return this.ParseConfigToData(config, parentLinkData);\n }\n const { linkConfig, partialSchema } = this.PartitionSchemaData(config);\n const fullConfig = this.BuildLinkConfig(linkConfig);\n // === CONVERT CONFIG TO DATA OBJECT ===\n // - Send through public ParseConfigToData method, so subclasses can include their own logic.\n if (\"targetKey\" in fullConfig) {\n return this.ParseConfigToData({\n id: randomID(),\n ...partialSchema,\n targetID: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].parseDocRefToUUID(\"target\" in fullConfig ? fullConfig.target : fullConfig.targetID),\n targetKey: fullConfig.targetKey\n }, parentLinkData);\n }\n return this.ParseConfigToData({\n id: randomID(),\n ...partialSchema,\n targetID: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].parseDocRefToUUID(\"target\" in fullConfig ? fullConfig.target : fullConfig.targetID),\n targetFlagKey: fullConfig.targetFlagKey\n }, parentLinkData);\n }\n /**\n * This static method parses the provided data into a format suitable for BladesTargetLink.\n * Subclasses can override this method to include their own parse logic.\n * If the provided data is already valid, it is returned as is.\n * Otherwise, the data is passed to the private #ParseConfig method for further processing.\n * Note: The 'id' property is defined at the return step, within #ParseConfig: Subclass\n * functionality that depends on the id property should be placed after the super call to this method.\n *\n * @template Schema - The data schema required by the subclass.\n * @param {(BladesTargetLink.Config | BladesTargetLink.Data) & Partial} data - The data to be parsed.\n * @returns {BladesTargetLink.Data & Partial} - The parsed data, suitable for BladesTargetLink.\n */\n static ParseConfigToData(data, parentLinkData) {\n if (this.IsValidData(data)) {\n return this.#ParseChildLinkData(data, parentLinkData);\n }\n return this.#ParseConfigToData(data, parentLinkData);\n }\n static PartitionSchemaData(dataOrConfig) {\n const { id, target, targetID, targetKey, targetFlagKey, isScopingById, ...schemaData } = dataOrConfig;\n const partialSchema = schemaData;\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isDocID(id)) {\n // A Data object was submitted.\n if (!this.IsValidData({ id, targetID, targetKey, targetFlagKey, isScopingById })) {\n eLog.error(\"BladesTargetLink\", \"Bad Constructor DATA\", { dataOrConfig });\n throw new Error(\"[new BladesTargetLink()] Bad Constructor DATA (see log)\");\n }\n let linkData;\n if (targetKey) {\n linkData = { id, targetID: targetID, targetKey, isScopingById: isScopingById ?? true };\n }\n else if (targetFlagKey) {\n linkData = { id, targetID: targetID, targetFlagKey, isScopingById: isScopingById ?? true };\n }\n else {\n eLog.error(\"BladesTargetLink\", \"Bad Constructor DATA\", { dataOrConfig });\n throw new Error(\"[BladesTargetLink.PartitionSchemaData] Bad Constructor DATA (see log)\");\n }\n return {\n linkData,\n partialSchema\n };\n }\n // A Config object was submitted.\n return {\n linkConfig: this.BuildLinkConfig({\n ...{ isScopingById: isScopingById ?? true },\n ...(\"targetID\" in dataOrConfig\n ? { targetID: dataOrConfig.targetID }\n : { target: dataOrConfig.target }),\n ...(\"targetKey\" in dataOrConfig\n ? { targetKey: dataOrConfig.targetKey }\n : { targetFlagKey: dataOrConfig.targetFlagKey })\n }),\n partialSchema\n };\n }\n static _ApplySchemaDefaults(schemaData) {\n return this.ApplySchemaDefaults(schemaData);\n }\n /**\n * This static method applies defaults to any values missing from the class' data Schema.\n * 'Schema' is defined by subclasses to BladesTargetLink.\n * Subclasses must override this method to apply their own defaults.\n *\n * @template Schema - The data schema required by the subclass.\n * @param {Partial} schemaData - Schema data overriding the defaults.\n * @returns {Schema} - The schema data with defaults applied.\n * @throws {Error} - Throws an error if this method is not overridden in a subclass.\n */\n static ApplySchemaDefaults(schemaData) {\n throw new Error(\"[BladesTargetLink.ApplySchemaDefaults] Static Method ApplySchemaDefaults must be overridden in subclass\");\n }\n /**\n * Creates a new instance of BladesTargetLink and initializes it with the provided configuration.\n * The configuration is parsed into a data object which is then used to initialize the target link.\n * The function logs the parsed data for debugging purposes.\n *\n * @template Schema - The schema type parameter that extends the data structure.\n * @param {BladesTargetLink.Config & Partial} config - The configuration object containing both the target link configuration and the schema configuration.\n *\n * @returns {Promise & BladesTargetLink.Subclass>} - A promise that resolves to a new instance of BladesTargetLink, initialized with the provided data.\n *\n * @throws {Error} - Throws an error if the initialization of the target link fails.\n */\n static async Create(config, parentLinkData) {\n const tLink = new this(config, parentLinkData);\n await tLink.initTargetLink();\n return tLink;\n }\n // #endregion\n // #region GETTERS ~\n get isGM() { return game.user.isGM; }\n _id;\n _targetID;\n _targetKey;\n _targetFlagKey;\n _isScopingById = true;\n _initialSchema;\n get id() { return this._id; }\n get targetID() { return this._targetID; }\n get targetKey() { return this._targetKey; }\n get targetFlagKey() { return this._targetFlagKey; }\n get isScopingById() { return this._isScopingById; }\n get initialSchema() { return this._initialSchema; }\n get targetKeyPrefix() {\n if (!this.targetKey) {\n return undefined;\n }\n if (!this.isScopingById) {\n return this.targetKey;\n }\n return this.targetKey\n ? `${this.targetKey}.${this.id}`\n : undefined;\n }\n get targetKeyNullPrefix() {\n if (!this.targetKey) {\n return undefined;\n }\n if (this.isScopingById) {\n return `${this.targetKey}.-=${this.id}`;\n }\n if (/^.+\\..+$/g.test(this.targetKey)) {\n return this.targetKey.replace(/\\.([^.]+)$/, \".-=$1\");\n }\n throw new Error(`[BladesTargetLink.targetKeyNullPrefix] Can't Nullify TargetKey '${this.targetKey}'`);\n }\n get targetFlagKeyPrefix() {\n if (!this.targetFlagKey) {\n return undefined;\n }\n if (!this.isScopingById) {\n return this.targetFlagKey;\n }\n return this.targetFlagKey\n ? `${this.targetFlagKey}.${this.id}`\n : undefined;\n }\n get isLinkInitialized() { return this.isInitPromiseResolved; }\n get linkData() {\n if (this.targetKey) {\n return {\n id: this.id,\n targetID: this.targetID,\n targetKey: this.targetKey,\n isScopingById: this.isScopingById\n };\n }\n if (this.targetFlagKey) {\n return {\n id: this.id,\n targetID: this.targetID,\n targetFlagKey: this.targetFlagKey,\n isScopingById: this.isScopingById\n };\n }\n throw new Error(`[BladesTargetLink.linkData] Missing targetKey and targetFlagKey for '${this.id}'`);\n }\n _target;\n get target() { return this._target; }\n get localData() {\n return {\n ...this.initialSchema,\n ...this.linkData\n };\n }\n get data() {\n if (this.isLinkInitialized) {\n let data;\n if (this.targetFlagKeyPrefix) {\n data = this.target.getFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.targetFlagKeyPrefix);\n }\n else if (this.targetKeyPrefix) {\n data = getProperty(this.target, this.targetKeyPrefix);\n }\n if (!data) {\n throw new Error(\"[BladesTargetLink.data] Error retrieving data.\");\n }\n return data;\n }\n else {\n eLog.warn(\"BladesTargetLink\", \"Attempt to access data of uninitiated BladesTargetLink: Returning local data only.\", { bladesTargetLink: this, localData: this.localData });\n return this.localData;\n }\n }\n constructor(dataOrConfig, parentLinkData) {\n let linkData;\n let schema;\n const subclassConstructor = this.constructor;\n // First, we construct the link data from the config or data object.\n if (subclassConstructor.IsValidData(dataOrConfig)) {\n // If a simple link data object was provided, acquire the schema from the source document\n ({ linkData } = subclassConstructor.PartitionSchemaData(dataOrConfig));\n const target = fromUuidSync(linkData.targetID);\n if (!target) {\n throw new Error(`[new BladesTargetLink()] Unable to resolve target from uuid '${linkData.targetID}'`);\n }\n if (\"targetKey\" in linkData) {\n schema = getProperty(target, `${linkData.targetKey}.${linkData.id}`);\n }\n else {\n schema = target.getFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, `${linkData.targetFlagKey}.${linkData.id}`);\n }\n // Set the isInitPromiseResolved flag to true\n this.isInitPromiseResolved = true;\n }\n else {\n // Otherwise, we have to parse the config into a data object, and extract any schema data\n // First we convert the config object to a BladesTargetLink.Data & Partial object.\n const parsedData = BladesTargetLink.#ParseConfigToData(dataOrConfig, parentLinkData);\n // Next we separate the linkData and the schemaData from the parsedData object.\n let partialSchema;\n ({ linkData, partialSchema } = subclassConstructor.PartitionSchemaData(parsedData));\n // And apply any schema defaults to the provided schema data.\n schema = subclassConstructor._ApplySchemaDefaults(partialSchema);\n }\n this._id = linkData.id;\n this._targetID = linkData.targetID;\n if (\"targetKey\" in linkData) {\n this._targetKey = linkData.targetKey;\n }\n else {\n this._targetFlagKey = linkData.targetFlagKey;\n }\n const target = fromUuidSync(this.targetID);\n if (!target) {\n throw new Error(`[new BladesTargetLink()] Unable to resolve target from uuid '${this._targetID}'`);\n }\n this._target = target;\n this._initialSchema = schema;\n }\n // #endregion\n // #region ASYNC UPDATE & DELETE METHODS ~\n getDotKeyToProp(prop, isNullifying = false) {\n if (this.targetKeyPrefix) {\n if (prop === undefined) {\n return isNullifying ? this.targetKeyNullPrefix : this.targetKeyPrefix;\n }\n return `${this.targetKeyPrefix}.${isNullifying ? \"-=\" : \"\"}${prop}`;\n }\n if (this.targetFlagKeyPrefix) {\n if (prop === undefined) {\n return this.targetFlagKeyPrefix;\n }\n return `${this.targetFlagKeyPrefix}.${prop}`;\n }\n throw new Error(\"[BladesTargetLink.getDotKeyToProp()] Missing 'targetKeyPrefix' and 'targetFlagKeyPrefix'\");\n }\n getFlagParamsToProp(prop) {\n return [_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.getDotKeyToProp(prop)];\n }\n async updateTargetFlag(prop, val) {\n if (!this.targetFlagKeyPrefix) {\n return;\n }\n if (val === null) {\n await this.target.unsetFlag(...this.getFlagParamsToProp(prop));\n }\n else if (this.target instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor) {\n await this.target.setFlag(...this.getFlagParamsToProp(prop), val);\n }\n else if (this.target instanceof _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem) {\n await this.target.setFlag(...this.getFlagParamsToProp(prop), val);\n }\n else if (this.target instanceof User) {\n await this.target.setFlag(...this.getFlagParamsToProp(prop), val);\n }\n else if (this.target instanceof _BladesChat__WEBPACK_IMPORTED_MODULE_4__[\"default\"]) {\n await this.target.setFlag(...this.getFlagParamsToProp(prop), val);\n }\n }\n async updateTargetKey(prop, val) {\n if (!this.targetKeyPrefix) {\n return;\n }\n await this.target.update({ [this.getDotKeyToProp(prop, val === null)]: val }, { render: false });\n }\n initPromise;\n isInitPromiseResolved = false;\n /**\n * Initializes a target link by updating the target's data with the provided data object.\n * If a targetKey is provided, the data is updated directly on the target.\n * If a targetFlagKey is provided, the data is set as a flag on the target.\n *\n * This method need only be run once, when the document is first created and its data must be written to server storage.\n * External functions can synchronously check the status of initialization via the isInitPromiseResolved property, while\n * asynchronous functions can await the initPromise property.\n *\n * TargetLink documents whose data already exists in server storage can be constructed directly (i.e. new BladesTargetLink(data))\n * without needing to call this method.\n *\n * @param {BladesTargetLink.Data & Schema} data - The combined data object containing both the target link data and the schema data.\n * @returns {Promise} - A promise that resolves when the server update is complete.\n */\n async initTargetLink() {\n this.isInitPromiseResolved = false;\n // Construct data object\n const data = {\n ...this.linkData,\n ...this.initialSchema\n };\n this.initPromise = new Promise((resolve, reject) => {\n if (this.targetKeyPrefix) {\n const updateData = mergeObject((getProperty(this.target, this.targetKeyPrefix) ?? {}), data);\n this.target.update({ [this.targetKeyPrefix]: updateData }, { render: false }).then(() => {\n this.isInitPromiseResolved = true;\n resolve();\n }).catch(reject);\n }\n else if (this.targetFlagKeyPrefix) {\n const updateData = mergeObject((this.target.getFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.targetFlagKeyPrefix) ?? {}), data);\n this.target.setFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.targetFlagKeyPrefix, updateData).then(() => {\n this.isInitPromiseResolved = true;\n resolve();\n }).catch(reject);\n }\n else {\n reject();\n }\n });\n return this.initPromise;\n }\n async #updateTargetViaMerge(updateData, waitFor) {\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor(waitFor);\n if (this.targetKeyPrefix) {\n // First, prepend targetKeyPrefix or targetFlagKeyPrefix (as appropriate) to each key of updateData\n updateData = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objMap(updateData, false, (key) => `${this.targetKeyPrefix || this.targetFlagKeyPrefix}.${key}`);\n return this.target.update(updateData, { render: false });\n }\n else if (this.targetFlagKeyPrefix) {\n // We must retrieve the existing flag data, flattenObject it, then merge it with updateData\n const existingFlagData = this.target.getFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.targetFlagKeyPrefix) ?? {};\n const flattenedFlagData = flattenObject(existingFlagData);\n const mergedFlagData = mergeObject(flattenedFlagData, updateData);\n return this.target.setFlag(_core_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].SYSTEM_ID, this.targetFlagKeyPrefix, mergedFlagData);\n }\n else {\n throw new Error(`[BladesTargetLink.#updateTargetViaMerge] Unable to update target data for BladesTargetLink id '${this.id}': Missing both 'targetKeyPrefix' and 'targetFlagKeyPrefix'`);\n }\n }\n async #updateTargetPropVal(prop, val, waitFor) {\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor(waitFor);\n if (this.targetKeyPrefix) {\n return this.target.update({ [`${this.targetKeyPrefix}.${prop}`]: val });\n }\n else if (this.targetFlagKeyPrefix) {\n return this.updateTargetFlag(prop, val);\n }\n }\n async updateTarget(propOrData, valOrWaitFor, waitFor) {\n // If the provided data is an object, we assume it is a full data object and we update the target with it.\n if (typeof propOrData === \"string\") {\n if (getProperty(this.data, propOrData) === valOrWaitFor) {\n return;\n }\n return this.#updateTargetPropVal(propOrData, valOrWaitFor, waitFor);\n }\n if (typeof propOrData === \"object\") {\n return this.#updateTargetViaMerge(propOrData, valOrWaitFor);\n }\n else {\n throw new Error(`[BladesTargetLink.updateTarget()] Bad updateData for id '${this.id}': ${propOrData}`);\n }\n }\n async updateTargetData(val, waitFor) {\n if (val) {\n // Add BladesTargetLink.Data to provided schema\n val = {\n ...val,\n ...this.linkData\n };\n }\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor([this.initPromise, waitFor]);\n if (this.targetFlagKeyPrefix) {\n await this.updateTargetFlag(undefined, val);\n }\n else {\n await this.updateTargetKey(undefined, val);\n }\n }\n async delete(collection, waitFor) {\n if (collection) {\n collection.delete(this.id);\n }\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].waitFor([this.initPromise, waitFor]);\n await this.updateTargetData(null);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesTargetLink);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxjQUFjLHVEQUFDO0FBQ2Y7QUFDQTtBQUNBLHlCQUF5Qix1REFBQyx1Q0FBdUMsaURBQWlELEdBQUcsSUFBSTtBQUN6SCxvREFBb0QsZUFBZTtBQUNuRTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsdURBQUM7QUFDMUQ7QUFDQTtBQUNBLHVDQUF1Qyx1REFBQztBQUN4QztBQUNBO0FBQ0EsOEhBQThILFFBQVE7QUFDdEk7QUFDQTtBQUNBO0FBQ0EsY0FBYyx1REFBQztBQUNmO0FBQ0Esd0NBQXdDLElBQUkscUJBQXFCLEdBQUcsS0FBSyxTQUFTO0FBQ2xGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3RkFBd0YsUUFBUSxLQUFLLFdBQVc7QUFDaEg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHVEQUFDO0FBQ2Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsdURBQUM7QUFDZjtBQUNBO0FBQ0E7QUFDQSwrREFBZSxnQkFBZ0IsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NsYXNzZXMvQmxhZGVzVGFyZ2V0TGluay50cz81ODA2Il0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuaW1wb3J0IFUgZnJvbSBcIi4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgQyBmcm9tIFwiLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCB7IEJsYWRlc0FjdG9yIH0gZnJvbSBcIi4uL2RvY3VtZW50cy9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgeyBCbGFkZXNJdGVtIH0gZnJvbSBcIi4uL2RvY3VtZW50cy9CbGFkZXNJdGVtUHJveHlcIjtcbmltcG9ydCBCbGFkZXNDaGF0IGZyb20gXCIuL0JsYWRlc0NoYXRcIjtcbmNsYXNzIEJsYWRlc1RhcmdldExpbmsge1xuICAgIC8vICNyZWdpb24gU1RBVElDIE1FVEhPRFMgflxuICAgIHN0YXRpYyBnZXQgVmFsaWRUYXJnZXRDbGFzc2VzKCkge1xuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgQmxhZGVzQWN0b3IsXG4gICAgICAgICAgICBCbGFkZXNJdGVtLFxuICAgICAgICAgICAgQmxhZGVzQ2hhdCxcbiAgICAgICAgICAgIFVzZXJcbiAgICAgICAgXTtcbiAgICB9XG4gICAgc3RhdGljIElzVmFsaWRDb25maWcocmVmKSB7XG4gICAgICAgIHJldHVybiBVLmlzU2ltcGxlT2JqKHJlZilcbiAgICAgICAgICAgICYmIChVLmlzRG9jSUQocmVmLnRhcmdldClcbiAgICAgICAgICAgICAgICB8fCBVLmlzRG9jVVVJRChyZWYudGFyZ2V0KVxuICAgICAgICAgICAgICAgIHx8IFUuaXNEb2NJRChyZWYudGFyZ2V0SUQpXG4gICAgICAgICAgICAgICAgfHwgVS5pc0RvY1VVSUQocmVmLnRhcmdldElEKVxuICAgICAgICAgICAgICAgIHx8IHRoaXMuVmFsaWRUYXJnZXRDbGFzc2VzLnNvbWUoKGNscykgPT4gcmVmLnRhcmdldCBpbnN0YW5jZW9mIGNscykpXG4gICAgICAgICAgICAmJiAoVS5pc1RhcmdldEtleShyZWYudGFyZ2V0S2V5KSB8fCBVLmlzVGFyZ2V0RmxhZ0tleShyZWYudGFyZ2V0RmxhZ0tleSkpXG4gICAgICAgICAgICAmJiAhKFUuaXNUYXJnZXRLZXkocmVmLnRhcmdldEtleSkgJiYgVS5pc1RhcmdldEZsYWdLZXkocmVmLnRhcmdldEZsYWdLZXkpKTtcbiAgICB9XG4gICAgc3RhdGljIElzVmFsaWREYXRhKHJlZikge1xuICAgICAgICByZXR1cm4gVS5pc1NpbXBsZU9iaihyZWYpXG4gICAgICAgICAgICAmJiBVLmlzRG9jSUQocmVmLmlkKVxuICAgICAgICAgICAgJiYgVS5pc0RvY1VVSUQocmVmLnRhcmdldElEKVxuICAgICAgICAgICAgJiYgKFUuaXNUYXJnZXRLZXkocmVmLnRhcmdldEtleSkgfHwgVS5pc1RhcmdldEZsYWdLZXkocmVmLnRhcmdldEZsYWdLZXkpKVxuICAgICAgICAgICAgJiYgIShVLmlzVGFyZ2V0S2V5KHJlZi50YXJnZXRLZXkpICYmIFUuaXNUYXJnZXRGbGFnS2V5KHJlZi50YXJnZXRGbGFnS2V5KSk7XG4gICAgICAgIC8vICYmICh0eXBlb2YgcmVmLmlzU2NvcGluZ0J5SWQgPT09IFwiYm9vbGVhblwiKTtcbiAgICB9XG4gICAgc3RhdGljICNQYXJzZUNoaWxkTGlua0RhdGEoY2hpbGREYXRhLCBwYXJlbnRMaW5rRGF0YSkge1xuICAgICAgICBpZiAoIXBhcmVudExpbmtEYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gY2hpbGREYXRhO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleVByZWZpeFBhcnRzID0gXCJ0YXJnZXRLZXlcIiBpbiBwYXJlbnRMaW5rRGF0YVxuICAgICAgICAgICAgPyBbcGFyZW50TGlua0RhdGEudGFyZ2V0S2V5XVxuICAgICAgICAgICAgOiBbcGFyZW50TGlua0RhdGEudGFyZ2V0RmxhZ0tleV07XG4gICAgICAgIGlmIChwYXJlbnRMaW5rRGF0YS5pc1Njb3BpbmdCeUlkKSB7XG4gICAgICAgICAgICBrZXlQcmVmaXhQYXJ0cy5wdXNoKHBhcmVudExpbmtEYXRhLmlkKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBrZXlQcmVmaXggPSBrZXlQcmVmaXhQYXJ0cy5qb2luKFwiLlwiKTtcbiAgICAgICAgaWYgKFwidGFyZ2V0S2V5XCIgaW4gY2hpbGREYXRhICYmIFwidGFyZ2V0S2V5XCIgaW4gcGFyZW50TGlua0RhdGEpIHtcbiAgICAgICAgICAgIGlmIChjaGlsZERhdGEudGFyZ2V0S2V5LnN0YXJ0c1dpdGgoYCR7a2V5UHJlZml4fS5gKSkge1xuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUga2V5UHJlZml4IGFuZCB0aGUgZm9sbG93aW5nIGRvdCBmcm9tIGNoaWxkRGF0YS50YXJnZXRLZXlcbiAgICAgICAgICAgICAgICBjaGlsZERhdGEudGFyZ2V0S2V5ID0gY2hpbGREYXRhLnRhcmdldEtleS5zbGljZShrZXlQcmVmaXgubGVuZ3RoICsgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjaGlsZERhdGEudGFyZ2V0S2V5ID0gW1xuICAgICAgICAgICAgICAgIHBhcmVudExpbmtEYXRhLnRhcmdldEtleSxcbiAgICAgICAgICAgICAgICBwYXJlbnRMaW5rRGF0YS5pc1Njb3BpbmdCeUlkID8gcGFyZW50TGlua0RhdGEuaWQgOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgY2hpbGREYXRhLnRhcmdldEtleVxuICAgICAgICAgICAgXS5maWx0ZXIoQm9vbGVhbikuam9pbihcIi5cIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoXCJ0YXJnZXRGbGFnS2V5XCIgaW4gY2hpbGREYXRhICYmIFwidGFyZ2V0RmxhZ0tleVwiIGluIHBhcmVudExpbmtEYXRhKSB7XG4gICAgICAgICAgICBpZiAoY2hpbGREYXRhLnRhcmdldEZsYWdLZXkuc3RhcnRzV2l0aChgJHtrZXlQcmVmaXh9LmApKSB7XG4gICAgICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBrZXlQcmVmaXggYW5kIHRoZSBmb2xsb3dpbmcgZG90IGZyb20gY2hpbGREYXRhLnRhcmdldEZsYWdLZXlcbiAgICAgICAgICAgICAgICBjaGlsZERhdGEudGFyZ2V0RmxhZ0tleSA9IGNoaWxkRGF0YS50YXJnZXRGbGFnS2V5LnNsaWNlKGtleVByZWZpeC5sZW5ndGggKyAxKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNoaWxkRGF0YS50YXJnZXRGbGFnS2V5ID0gW1xuICAgICAgICAgICAgICAgIHBhcmVudExpbmtEYXRhLnRhcmdldEZsYWdLZXksXG4gICAgICAgICAgICAgICAgcGFyZW50TGlua0RhdGEuaXNTY29waW5nQnlJZCA/IHBhcmVudExpbmtEYXRhLmlkIDogdW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIGNoaWxkRGF0YS50YXJnZXRGbGFnS2V5XG4gICAgICAgICAgICBdLmZpbHRlcihCb29sZWFuKS5qb2luKFwiLlwiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNUYXJnZXRMaW5rLlBhcnNlQ2hpbGRMaW5rRGF0YV0gdGFyZ2V0S2V5L3RhcmdldEZsYWdLZXkgbWlzbWF0Y2ggYmV0d2VlbiBwcm92aWRlZCBwYXJ0aWFsQ29uZmlnIGFuZCBwYXJlbnRMaW5rRGF0YS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGNoaWxkRGF0YTtcbiAgICB9XG4gICAgc3RhdGljIEJ1aWxkTGlua0NvbmZpZyhwYXJ0aWFsQ29uZmlnKSB7XG4gICAgICAgIC8vIGNvbnN0IHt0YXJnZXQsIHRhcmdldElELCB0YXJnZXRLZXksIHRhcmdldEZsYWdLZXksIGlzU2NvcGluZ0J5SWR9ID0gcGFydGlhbENvbmZpZztcbiAgICAgICAgaWYgKFwidGFyZ2V0XCIgaW4gcGFydGlhbENvbmZpZykge1xuICAgICAgICAgICAgaWYgKFwidGFyZ2V0S2V5XCIgaW4gcGFydGlhbENvbmZpZykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldDogcGFydGlhbENvbmZpZy50YXJnZXQsXG4gICAgICAgICAgICAgICAgICAgIHRhcmdldEtleTogcGFydGlhbENvbmZpZy50YXJnZXRLZXksXG4gICAgICAgICAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IHBhcnRpYWxDb25maWcuaXNTY29waW5nQnlJZFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChcInRhcmdldEZsYWdLZXlcIiBpbiBwYXJ0aWFsQ29uZmlnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBwYXJ0aWFsQ29uZmlnLnRhcmdldCxcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0RmxhZ0tleTogcGFydGlhbENvbmZpZy50YXJnZXRGbGFnS2V5LFxuICAgICAgICAgICAgICAgICAgICBpc1Njb3BpbmdCeUlkOiBwYXJ0aWFsQ29uZmlnLmlzU2NvcGluZ0J5SWRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1RhcmdldExpbmsuQnVpbGRDb25maWddIE11c3QgcHJvdmlkZSBhIHRhcmdldEtleSBvciB0YXJnZXRGbGFnS2V5LlwiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChcInRhcmdldElEXCIgaW4gcGFydGlhbENvbmZpZykge1xuICAgICAgICAgICAgaWYgKFwidGFyZ2V0S2V5XCIgaW4gcGFydGlhbENvbmZpZykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldElEOiBwYXJ0aWFsQ29uZmlnLnRhcmdldElELFxuICAgICAgICAgICAgICAgICAgICB0YXJnZXRLZXk6IHBhcnRpYWxDb25maWcudGFyZ2V0S2V5LFxuICAgICAgICAgICAgICAgICAgICBpc1Njb3BpbmdCeUlkOiBwYXJ0aWFsQ29uZmlnLmlzU2NvcGluZ0J5SWRcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoXCJ0YXJnZXRGbGFnS2V5XCIgaW4gcGFydGlhbENvbmZpZykge1xuICAgICAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldElEOiBwYXJ0aWFsQ29uZmlnLnRhcmdldElELFxuICAgICAgICAgICAgICAgICAgICB0YXJnZXRGbGFnS2V5OiBwYXJ0aWFsQ29uZmlnLnRhcmdldEZsYWdLZXksXG4gICAgICAgICAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IHBhcnRpYWxDb25maWcuaXNTY29waW5nQnlJZFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzVGFyZ2V0TGluay5CdWlsZENvbmZpZ10gTXVzdCBwcm92aWRlIGEgdGFyZ2V0S2V5IG9yIHRhcmdldEZsYWdLZXkuXCIpO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNUYXJnZXRMaW5rLkJ1aWxkQ29uZmlnXSBNdXN0IHByb3ZpZGUgYSB0YXJnZXQgb3IgdGFyZ2V0SUQuXCIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBUaGlzIHByaXZhdGUgc3RhdGljIG1ldGhvZCBpcyB1c2VkIHRvIHRyYW5zZm9ybSBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGludG8gYSBkYXRhIG9iamVjdCBmb3IgQmxhZGVzVGFyZ2V0TGluay5cbiAgICAgKiBJdCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGlzIGFscmVhZHkgdmFsaWQgZGF0YSwgYW5kIGlmIHNvLCByZXR1cm5zIGl0IGRpcmVjdGx5LlxuICAgICAqIE90aGVyd2lzZSwgaXQgcGFydGl0aW9ucyB0aGUgY29uZmlndXJhdGlvbiBvYmplY3QgaW50byBsaW5rLXNwZWNpZmljIGNvbmZpZ3VyYXRpb24gYW5kIGFkZGl0aW9uYWwgc2NoZW1hIGRhdGEsXG4gICAgICogY29uc3RydWN0cyBhIGZ1bGwgbGluayBjb25maWd1cmF0aW9uLCBhbmQgdGhlbiBjcmVhdGVzIGEgZGF0YSBvYmplY3Qgd2l0aCBhIG5ldyByYW5kb20gSUQgYW5kIHRoZSB0YXJnZXQgVVVJRC5cbiAgICAgKiBUaGUgbWV0aG9kIGVuc3VyZXMgdGhhdCBlaXRoZXIgJ3RhcmdldEtleScgb3IgJ3RhcmdldEZsYWdLZXknIGlzIHByZXNlbnQgYW5kIHRocm93cyBhbiBlcnJvciBpZiB0aGUgY29uZmlndXJhdGlvbiBpcyBpbnZhbGlkLlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFNjaGVtYSAtIFRoZSBhZGRpdGlvbmFsIHNjaGVtYSBkYXRhIHJlcXVpcmVkIGJ5IHRoZSBzdWJjbGFzcy5cbiAgICAgKiBAcGFyYW0ge0JsYWRlc1RhcmdldExpbmsuQ29uZmlnIHwgQmxhZGVzVGFyZ2V0TGluay5EYXRhICYgUGFydGlhbDxTY2hlbWE+fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdGhhdCBtYXkgY29udGFpbiBCbGFkZXNUYXJnZXRMaW5rIHByb3BlcnRpZXMgYW5kIGFueSBzdWJjbGFzcy1zcGVjaWZpYyBzY2hlbWEgZGF0YS5cbiAgICAgKiBAcmV0dXJucyB7QmxhZGVzVGFyZ2V0TGluay5EYXRhICYgUGFydGlhbDxTY2hlbWE+fSAtIFRoZSBmdWxseSBjb25zdHJ1Y3RlZCBkYXRhIG9iamVjdCB3aXRoIG5lY2Vzc2FyeSBwcm9wZXJ0aWVzIGZvciBCbGFkZXNUYXJnZXRMaW5rLlxuICAgICAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgY29uZmlndXJhdGlvbiBvYmplY3QgaXMgaW52YWxpZCwgbGFja3MgYSB0YXJnZXQgcmVmZXJlbmNlLCBvciBpZiBib3RoICd0YXJnZXRLZXknIGFuZCAndGFyZ2V0RmxhZ0tleScgYXJlIHByb3ZpZGVkLlxuICAgICAqL1xuICAgIHN0YXRpYyAjUGFyc2VDb25maWdUb0RhdGEoY29uZmlnLCBwYXJlbnRMaW5rRGF0YSkge1xuICAgICAgICBpZiAodGhpcy5Jc1ZhbGlkRGF0YShjb25maWcpKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5QYXJzZUNvbmZpZ1RvRGF0YShjb25maWcsIHBhcmVudExpbmtEYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCB7IGxpbmtDb25maWcsIHBhcnRpYWxTY2hlbWEgfSA9IHRoaXMuUGFydGl0aW9uU2NoZW1hRGF0YShjb25maWcpO1xuICAgICAgICBjb25zdCBmdWxsQ29uZmlnID0gdGhpcy5CdWlsZExpbmtDb25maWcobGlua0NvbmZpZyk7XG4gICAgICAgIC8vID09PSBDT05WRVJUIENPTkZJRyBUTyBEQVRBIE9CSkVDVCA9PT1cbiAgICAgICAgLy8gLSBTZW5kIHRocm91Z2ggcHVibGljIFBhcnNlQ29uZmlnVG9EYXRhIG1ldGhvZCwgc28gc3ViY2xhc3NlcyBjYW4gaW5jbHVkZSB0aGVpciBvd24gbG9naWMuXG4gICAgICAgIGlmIChcInRhcmdldEtleVwiIGluIGZ1bGxDb25maWcpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLlBhcnNlQ29uZmlnVG9EYXRhKHtcbiAgICAgICAgICAgICAgICBpZDogcmFuZG9tSUQoKSxcbiAgICAgICAgICAgICAgICAuLi5wYXJ0aWFsU2NoZW1hLFxuICAgICAgICAgICAgICAgIHRhcmdldElEOiBVLnBhcnNlRG9jUmVmVG9VVUlEKFwidGFyZ2V0XCIgaW4gZnVsbENvbmZpZyA/IGZ1bGxDb25maWcudGFyZ2V0IDogZnVsbENvbmZpZy50YXJnZXRJRCksXG4gICAgICAgICAgICAgICAgdGFyZ2V0S2V5OiBmdWxsQ29uZmlnLnRhcmdldEtleVxuICAgICAgICAgICAgfSwgcGFyZW50TGlua0RhdGEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLlBhcnNlQ29uZmlnVG9EYXRhKHtcbiAgICAgICAgICAgIGlkOiByYW5kb21JRCgpLFxuICAgICAgICAgICAgLi4ucGFydGlhbFNjaGVtYSxcbiAgICAgICAgICAgIHRhcmdldElEOiBVLnBhcnNlRG9jUmVmVG9VVUlEKFwidGFyZ2V0XCIgaW4gZnVsbENvbmZpZyA/IGZ1bGxDb25maWcudGFyZ2V0IDogZnVsbENvbmZpZy50YXJnZXRJRCksXG4gICAgICAgICAgICB0YXJnZXRGbGFnS2V5OiBmdWxsQ29uZmlnLnRhcmdldEZsYWdLZXlcbiAgICAgICAgfSwgcGFyZW50TGlua0RhdGEpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBUaGlzIHN0YXRpYyBtZXRob2QgcGFyc2VzIHRoZSBwcm92aWRlZCBkYXRhIGludG8gYSBmb3JtYXQgc3VpdGFibGUgZm9yIEJsYWRlc1RhcmdldExpbmsuXG4gICAgICogU3ViY2xhc3NlcyBjYW4gb3ZlcnJpZGUgdGhpcyBtZXRob2QgdG8gaW5jbHVkZSB0aGVpciBvd24gcGFyc2UgbG9naWMuXG4gICAgICogSWYgdGhlIHByb3ZpZGVkIGRhdGEgaXMgYWxyZWFkeSB2YWxpZCwgaXQgaXMgcmV0dXJuZWQgYXMgaXMuXG4gICAgICogT3RoZXJ3aXNlLCB0aGUgZGF0YSBpcyBwYXNzZWQgdG8gdGhlIHByaXZhdGUgI1BhcnNlQ29uZmlnIG1ldGhvZCBmb3IgZnVydGhlciBwcm9jZXNzaW5nLlxuICAgICAqIE5vdGU6IFRoZSAnaWQnIHByb3BlcnR5IGlzIGRlZmluZWQgYXQgdGhlIHJldHVybiBzdGVwLCB3aXRoaW4gI1BhcnNlQ29uZmlnOiBTdWJjbGFzc1xuICAgICAqIGZ1bmN0aW9uYWxpdHkgdGhhdCBkZXBlbmRzIG9uIHRoZSBpZCBwcm9wZXJ0eSBzaG91bGQgYmUgcGxhY2VkIGFmdGVyIHRoZSBzdXBlciBjYWxsIHRvIHRoaXMgbWV0aG9kLlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFNjaGVtYSAtIFRoZSBkYXRhIHNjaGVtYSByZXF1aXJlZCBieSB0aGUgc3ViY2xhc3MuXG4gICAgICogQHBhcmFtIHsoQmxhZGVzVGFyZ2V0TGluay5Db25maWcgfCBCbGFkZXNUYXJnZXRMaW5rLkRhdGEpICYgUGFydGlhbDxTY2hlbWE+fSBkYXRhIC0gVGhlIGRhdGEgdG8gYmUgcGFyc2VkLlxuICAgICAqIEByZXR1cm5zIHtCbGFkZXNUYXJnZXRMaW5rLkRhdGEgJiBQYXJ0aWFsPFNjaGVtYT59IC0gVGhlIHBhcnNlZCBkYXRhLCBzdWl0YWJsZSBmb3IgQmxhZGVzVGFyZ2V0TGluay5cbiAgICAgKi9cbiAgICBzdGF0aWMgUGFyc2VDb25maWdUb0RhdGEoZGF0YSwgcGFyZW50TGlua0RhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMuSXNWYWxpZERhdGEoZGF0YSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLiNQYXJzZUNoaWxkTGlua0RhdGEoZGF0YSwgcGFyZW50TGlua0RhdGEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLiNQYXJzZUNvbmZpZ1RvRGF0YShkYXRhLCBwYXJlbnRMaW5rRGF0YSk7XG4gICAgfVxuICAgIHN0YXRpYyBQYXJ0aXRpb25TY2hlbWFEYXRhKGRhdGFPckNvbmZpZykge1xuICAgICAgICBjb25zdCB7IGlkLCB0YXJnZXQsIHRhcmdldElELCB0YXJnZXRLZXksIHRhcmdldEZsYWdLZXksIGlzU2NvcGluZ0J5SWQsIC4uLnNjaGVtYURhdGEgfSA9IGRhdGFPckNvbmZpZztcbiAgICAgICAgY29uc3QgcGFydGlhbFNjaGVtYSA9IHNjaGVtYURhdGE7XG4gICAgICAgIGlmIChVLmlzRG9jSUQoaWQpKSB7XG4gICAgICAgICAgICAvLyBBIERhdGEgb2JqZWN0IHdhcyBzdWJtaXR0ZWQuXG4gICAgICAgICAgICBpZiAoIXRoaXMuSXNWYWxpZERhdGEoeyBpZCwgdGFyZ2V0SUQsIHRhcmdldEtleSwgdGFyZ2V0RmxhZ0tleSwgaXNTY29waW5nQnlJZCB9KSkge1xuICAgICAgICAgICAgICAgIGVMb2cuZXJyb3IoXCJCbGFkZXNUYXJnZXRMaW5rXCIsIFwiQmFkIENvbnN0cnVjdG9yIERBVEFcIiwgeyBkYXRhT3JDb25maWcgfSk7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW25ldyBCbGFkZXNUYXJnZXRMaW5rKCldIEJhZCBDb25zdHJ1Y3RvciBEQVRBIChzZWUgbG9nKVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCBsaW5rRGF0YTtcbiAgICAgICAgICAgIGlmICh0YXJnZXRLZXkpIHtcbiAgICAgICAgICAgICAgICBsaW5rRGF0YSA9IHsgaWQsIHRhcmdldElEOiB0YXJnZXRJRCwgdGFyZ2V0S2V5LCBpc1Njb3BpbmdCeUlkOiBpc1Njb3BpbmdCeUlkID8/IHRydWUgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHRhcmdldEZsYWdLZXkpIHtcbiAgICAgICAgICAgICAgICBsaW5rRGF0YSA9IHsgaWQsIHRhcmdldElEOiB0YXJnZXRJRCwgdGFyZ2V0RmxhZ0tleSwgaXNTY29waW5nQnlJZDogaXNTY29waW5nQnlJZCA/PyB0cnVlIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBlTG9nLmVycm9yKFwiQmxhZGVzVGFyZ2V0TGlua1wiLCBcIkJhZCBDb25zdHJ1Y3RvciBEQVRBXCIsIHsgZGF0YU9yQ29uZmlnIH0pO1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNUYXJnZXRMaW5rLlBhcnRpdGlvblNjaGVtYURhdGFdIEJhZCBDb25zdHJ1Y3RvciBEQVRBIChzZWUgbG9nKVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgbGlua0RhdGEsXG4gICAgICAgICAgICAgICAgcGFydGlhbFNjaGVtYVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBIENvbmZpZyBvYmplY3Qgd2FzIHN1Ym1pdHRlZC5cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGxpbmtDb25maWc6IHRoaXMuQnVpbGRMaW5rQ29uZmlnKHtcbiAgICAgICAgICAgICAgICAuLi57IGlzU2NvcGluZ0J5SWQ6IGlzU2NvcGluZ0J5SWQgPz8gdHJ1ZSB9LFxuICAgICAgICAgICAgICAgIC4uLihcInRhcmdldElEXCIgaW4gZGF0YU9yQ29uZmlnXG4gICAgICAgICAgICAgICAgICAgID8geyB0YXJnZXRJRDogZGF0YU9yQ29uZmlnLnRhcmdldElEIH1cbiAgICAgICAgICAgICAgICAgICAgOiB7IHRhcmdldDogZGF0YU9yQ29uZmlnLnRhcmdldCB9KSxcbiAgICAgICAgICAgICAgICAuLi4oXCJ0YXJnZXRLZXlcIiBpbiBkYXRhT3JDb25maWdcbiAgICAgICAgICAgICAgICAgICAgPyB7IHRhcmdldEtleTogZGF0YU9yQ29uZmlnLnRhcmdldEtleSB9XG4gICAgICAgICAgICAgICAgICAgIDogeyB0YXJnZXRGbGFnS2V5OiBkYXRhT3JDb25maWcudGFyZ2V0RmxhZ0tleSB9KVxuICAgICAgICAgICAgfSksXG4gICAgICAgICAgICBwYXJ0aWFsU2NoZW1hXG4gICAgICAgIH07XG4gICAgfVxuICAgIHN0YXRpYyBfQXBwbHlTY2hlbWFEZWZhdWx0cyhzY2hlbWFEYXRhKSB7XG4gICAgICAgIHJldHVybiB0aGlzLkFwcGx5U2NoZW1hRGVmYXVsdHMoc2NoZW1hRGF0YSk7XG4gICAgfVxuICAgIC8qKlxuICAgKiBUaGlzIHN0YXRpYyBtZXRob2QgYXBwbGllcyBkZWZhdWx0cyB0byBhbnkgdmFsdWVzIG1pc3NpbmcgZnJvbSB0aGUgY2xhc3MnIGRhdGEgU2NoZW1hLlxuICAgKiAnU2NoZW1hJyBpcyBkZWZpbmVkIGJ5IHN1YmNsYXNzZXMgdG8gQmxhZGVzVGFyZ2V0TGluay5cbiAgICogU3ViY2xhc3NlcyBtdXN0IG92ZXJyaWRlIHRoaXMgbWV0aG9kIHRvIGFwcGx5IHRoZWlyIG93biBkZWZhdWx0cy5cbiAgICpcbiAgICogQHRlbXBsYXRlIFNjaGVtYSAtIFRoZSBkYXRhIHNjaGVtYSByZXF1aXJlZCBieSB0aGUgc3ViY2xhc3MuXG4gICAqIEBwYXJhbSB7UGFydGlhbDxTY2hlbWE+fSBzY2hlbWFEYXRhIC0gU2NoZW1hIGRhdGEgb3ZlcnJpZGluZyB0aGUgZGVmYXVsdHMuXG4gICAqIEByZXR1cm5zIHtTY2hlbWF9IC0gVGhlIHNjaGVtYSBkYXRhIHdpdGggZGVmYXVsdHMgYXBwbGllZC5cbiAgICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoaXMgbWV0aG9kIGlzIG5vdCBvdmVycmlkZGVuIGluIGEgc3ViY2xhc3MuXG4gICAqL1xuICAgIHN0YXRpYyBBcHBseVNjaGVtYURlZmF1bHRzKHNjaGVtYURhdGEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1RhcmdldExpbmsuQXBwbHlTY2hlbWFEZWZhdWx0c10gU3RhdGljIE1ldGhvZCBBcHBseVNjaGVtYURlZmF1bHRzIG11c3QgYmUgb3ZlcnJpZGRlbiBpbiBzdWJjbGFzc1wiKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogQ3JlYXRlcyBhIG5ldyBpbnN0YW5jZSBvZiBCbGFkZXNUYXJnZXRMaW5rIGFuZCBpbml0aWFsaXplcyBpdCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxuICAgICAqIFRoZSBjb25maWd1cmF0aW9uIGlzIHBhcnNlZCBpbnRvIGEgZGF0YSBvYmplY3Qgd2hpY2ggaXMgdGhlbiB1c2VkIHRvIGluaXRpYWxpemUgdGhlIHRhcmdldCBsaW5rLlxuICAgICAqIFRoZSBmdW5jdGlvbiBsb2dzIHRoZSBwYXJzZWQgZGF0YSBmb3IgZGVidWdnaW5nIHB1cnBvc2VzLlxuICAgICAqXG4gICAgICogQHRlbXBsYXRlIFNjaGVtYSAtIFRoZSBzY2hlbWEgdHlwZSBwYXJhbWV0ZXIgdGhhdCBleHRlbmRzIHRoZSBkYXRhIHN0cnVjdHVyZS5cbiAgICAgKiBAcGFyYW0ge0JsYWRlc1RhcmdldExpbmsuQ29uZmlnICYgUGFydGlhbDxTY2hlbWE+fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBib3RoIHRoZSB0YXJnZXQgbGluayBjb25maWd1cmF0aW9uIGFuZCB0aGUgc2NoZW1hIGNvbmZpZ3VyYXRpb24uXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxCbGFkZXNUYXJnZXRMaW5rPFNjaGVtYT4gJiBCbGFkZXNUYXJnZXRMaW5rLlN1YmNsYXNzPFNjaGVtYT4+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgbmV3IGluc3RhbmNlIG9mIEJsYWRlc1RhcmdldExpbmssIGluaXRpYWxpemVkIHdpdGggdGhlIHByb3ZpZGVkIGRhdGEuXG4gICAgICpcbiAgICAgKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIGluaXRpYWxpemF0aW9uIG9mIHRoZSB0YXJnZXQgbGluayBmYWlscy5cbiAgICAgKi9cbiAgICBzdGF0aWMgYXN5bmMgQ3JlYXRlKGNvbmZpZywgcGFyZW50TGlua0RhdGEpIHtcbiAgICAgICAgY29uc3QgdExpbmsgPSBuZXcgdGhpcyhjb25maWcsIHBhcmVudExpbmtEYXRhKTtcbiAgICAgICAgYXdhaXQgdExpbmsuaW5pdFRhcmdldExpbmsoKTtcbiAgICAgICAgcmV0dXJuIHRMaW5rO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBHRVRURVJTIH5cbiAgICBnZXQgaXNHTSgpIHsgcmV0dXJuIGdhbWUudXNlci5pc0dNOyB9XG4gICAgX2lkO1xuICAgIF90YXJnZXRJRDtcbiAgICBfdGFyZ2V0S2V5O1xuICAgIF90YXJnZXRGbGFnS2V5O1xuICAgIF9pc1Njb3BpbmdCeUlkID0gdHJ1ZTtcbiAgICBfaW5pdGlhbFNjaGVtYTtcbiAgICBnZXQgaWQoKSB7IHJldHVybiB0aGlzLl9pZDsgfVxuICAgIGdldCB0YXJnZXRJRCgpIHsgcmV0dXJuIHRoaXMuX3RhcmdldElEOyB9XG4gICAgZ2V0IHRhcmdldEtleSgpIHsgcmV0dXJuIHRoaXMuX3RhcmdldEtleTsgfVxuICAgIGdldCB0YXJnZXRGbGFnS2V5KCkgeyByZXR1cm4gdGhpcy5fdGFyZ2V0RmxhZ0tleTsgfVxuICAgIGdldCBpc1Njb3BpbmdCeUlkKCkgeyByZXR1cm4gdGhpcy5faXNTY29waW5nQnlJZDsgfVxuICAgIGdldCBpbml0aWFsU2NoZW1hKCkgeyByZXR1cm4gdGhpcy5faW5pdGlhbFNjaGVtYTsgfVxuICAgIGdldCB0YXJnZXRLZXlQcmVmaXgoKSB7XG4gICAgICAgIGlmICghdGhpcy50YXJnZXRLZXkpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLmlzU2NvcGluZ0J5SWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRhcmdldEtleTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy50YXJnZXRLZXlcbiAgICAgICAgICAgID8gYCR7dGhpcy50YXJnZXRLZXl9LiR7dGhpcy5pZH1gXG4gICAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgZ2V0IHRhcmdldEtleU51bGxQcmVmaXgoKSB7XG4gICAgICAgIGlmICghdGhpcy50YXJnZXRLZXkpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNTY29waW5nQnlJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGAke3RoaXMudGFyZ2V0S2V5fS4tPSR7dGhpcy5pZH1gO1xuICAgICAgICB9XG4gICAgICAgIGlmICgvXi4rXFwuLiskL2cudGVzdCh0aGlzLnRhcmdldEtleSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnRhcmdldEtleS5yZXBsYWNlKC9cXC4oW14uXSspJC8sIFwiLi09JDFcIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzVGFyZ2V0TGluay50YXJnZXRLZXlOdWxsUHJlZml4XSBDYW4ndCBOdWxsaWZ5IFRhcmdldEtleSAnJHt0aGlzLnRhcmdldEtleX0nYCk7XG4gICAgfVxuICAgIGdldCB0YXJnZXRGbGFnS2V5UHJlZml4KCkge1xuICAgICAgICBpZiAoIXRoaXMudGFyZ2V0RmxhZ0tleSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuaXNTY29waW5nQnlJZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0RmxhZ0tleTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy50YXJnZXRGbGFnS2V5XG4gICAgICAgICAgICA/IGAke3RoaXMudGFyZ2V0RmxhZ0tleX0uJHt0aGlzLmlkfWBcbiAgICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgIH1cbiAgICBnZXQgaXNMaW5rSW5pdGlhbGl6ZWQoKSB7IHJldHVybiB0aGlzLmlzSW5pdFByb21pc2VSZXNvbHZlZDsgfVxuICAgIGdldCBsaW5rRGF0YSgpIHtcbiAgICAgICAgaWYgKHRoaXMudGFyZ2V0S2V5KSB7XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIGlkOiB0aGlzLmlkLFxuICAgICAgICAgICAgICAgIHRhcmdldElEOiB0aGlzLnRhcmdldElELFxuICAgICAgICAgICAgICAgIHRhcmdldEtleTogdGhpcy50YXJnZXRLZXksXG4gICAgICAgICAgICAgICAgaXNTY29waW5nQnlJZDogdGhpcy5pc1Njb3BpbmdCeUlkXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLnRhcmdldEZsYWdLZXkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaWQ6IHRoaXMuaWQsXG4gICAgICAgICAgICAgICAgdGFyZ2V0SUQ6IHRoaXMudGFyZ2V0SUQsXG4gICAgICAgICAgICAgICAgdGFyZ2V0RmxhZ0tleTogdGhpcy50YXJnZXRGbGFnS2V5LFxuICAgICAgICAgICAgICAgIGlzU2NvcGluZ0J5SWQ6IHRoaXMuaXNTY29waW5nQnlJZFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtCbGFkZXNUYXJnZXRMaW5rLmxpbmtEYXRhXSBNaXNzaW5nIHRhcmdldEtleSBhbmQgdGFyZ2V0RmxhZ0tleSBmb3IgJyR7dGhpcy5pZH0nYCk7XG4gICAgfVxuICAgIF90YXJnZXQ7XG4gICAgZ2V0IHRhcmdldCgpIHsgcmV0dXJuIHRoaXMuX3RhcmdldDsgfVxuICAgIGdldCBsb2NhbERhdGEoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi50aGlzLmluaXRpYWxTY2hlbWEsXG4gICAgICAgICAgICAuLi50aGlzLmxpbmtEYXRhXG4gICAgICAgIH07XG4gICAgfVxuICAgIGdldCBkYXRhKCkge1xuICAgICAgICBpZiAodGhpcy5pc0xpbmtJbml0aWFsaXplZCkge1xuICAgICAgICAgICAgbGV0IGRhdGE7XG4gICAgICAgICAgICBpZiAodGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICAgICAgZGF0YSA9IHRoaXMudGFyZ2V0LmdldEZsYWcoQy5TWVNURU1fSUQsIHRoaXMudGFyZ2V0RmxhZ0tleVByZWZpeCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLnRhcmdldEtleVByZWZpeCkge1xuICAgICAgICAgICAgICAgIGRhdGEgPSBnZXRQcm9wZXJ0eSh0aGlzLnRhcmdldCwgdGhpcy50YXJnZXRLZXlQcmVmaXgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiW0JsYWRlc1RhcmdldExpbmsuZGF0YV0gRXJyb3IgcmV0cmlldmluZyBkYXRhLlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZUxvZy53YXJuKFwiQmxhZGVzVGFyZ2V0TGlua1wiLCBcIkF0dGVtcHQgdG8gYWNjZXNzIGRhdGEgb2YgdW5pbml0aWF0ZWQgQmxhZGVzVGFyZ2V0TGluazogUmV0dXJuaW5nIGxvY2FsIGRhdGEgb25seS5cIiwgeyBibGFkZXNUYXJnZXRMaW5rOiB0aGlzLCBsb2NhbERhdGE6IHRoaXMubG9jYWxEYXRhIH0pO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMubG9jYWxEYXRhO1xuICAgICAgICB9XG4gICAgfVxuICAgIGNvbnN0cnVjdG9yKGRhdGFPckNvbmZpZywgcGFyZW50TGlua0RhdGEpIHtcbiAgICAgICAgbGV0IGxpbmtEYXRhO1xuICAgICAgICBsZXQgc2NoZW1hO1xuICAgICAgICBjb25zdCBzdWJjbGFzc0NvbnN0cnVjdG9yID0gdGhpcy5jb25zdHJ1Y3RvcjtcbiAgICAgICAgLy8gRmlyc3QsIHdlIGNvbnN0cnVjdCB0aGUgbGluayBkYXRhIGZyb20gdGhlIGNvbmZpZyBvciBkYXRhIG9iamVjdC5cbiAgICAgICAgaWYgKHN1YmNsYXNzQ29uc3RydWN0b3IuSXNWYWxpZERhdGEoZGF0YU9yQ29uZmlnKSkge1xuICAgICAgICAgICAgLy8gSWYgYSBzaW1wbGUgbGluayBkYXRhIG9iamVjdCB3YXMgcHJvdmlkZWQsIGFjcXVpcmUgdGhlIHNjaGVtYSBmcm9tIHRoZSBzb3VyY2UgZG9jdW1lbnRcbiAgICAgICAgICAgICh7IGxpbmtEYXRhIH0gPSBzdWJjbGFzc0NvbnN0cnVjdG9yLlBhcnRpdGlvblNjaGVtYURhdGEoZGF0YU9yQ29uZmlnKSk7XG4gICAgICAgICAgICBjb25zdCB0YXJnZXQgPSBmcm9tVXVpZFN5bmMobGlua0RhdGEudGFyZ2V0SUQpO1xuICAgICAgICAgICAgaWYgKCF0YXJnZXQpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFtuZXcgQmxhZGVzVGFyZ2V0TGluaygpXSBVbmFibGUgdG8gcmVzb2x2ZSB0YXJnZXQgZnJvbSB1dWlkICcke2xpbmtEYXRhLnRhcmdldElEfSdgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChcInRhcmdldEtleVwiIGluIGxpbmtEYXRhKSB7XG4gICAgICAgICAgICAgICAgc2NoZW1hID0gZ2V0UHJvcGVydHkodGFyZ2V0LCBgJHtsaW5rRGF0YS50YXJnZXRLZXl9LiR7bGlua0RhdGEuaWR9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzY2hlbWEgPSB0YXJnZXQuZ2V0RmxhZyhDLlNZU1RFTV9JRCwgYCR7bGlua0RhdGEudGFyZ2V0RmxhZ0tleX0uJHtsaW5rRGF0YS5pZH1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNldCB0aGUgaXNJbml0UHJvbWlzZVJlc29sdmVkIGZsYWcgdG8gdHJ1ZVxuICAgICAgICAgICAgdGhpcy5pc0luaXRQcm9taXNlUmVzb2x2ZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlLCB3ZSBoYXZlIHRvIHBhcnNlIHRoZSBjb25maWcgaW50byBhIGRhdGEgb2JqZWN0LCBhbmQgZXh0cmFjdCBhbnkgc2NoZW1hIGRhdGFcbiAgICAgICAgICAgIC8vIEZpcnN0IHdlIGNvbnZlcnQgdGhlIGNvbmZpZyBvYmplY3QgdG8gYSBCbGFkZXNUYXJnZXRMaW5rLkRhdGEgJiBQYXJ0aWFsPFNjaGVtYT4gb2JqZWN0LlxuICAgICAgICAgICAgY29uc3QgcGFyc2VkRGF0YSA9IEJsYWRlc1RhcmdldExpbmsuI1BhcnNlQ29uZmlnVG9EYXRhKGRhdGFPckNvbmZpZywgcGFyZW50TGlua0RhdGEpO1xuICAgICAgICAgICAgLy8gTmV4dCB3ZSBzZXBhcmF0ZSB0aGUgbGlua0RhdGEgYW5kIHRoZSBzY2hlbWFEYXRhIGZyb20gdGhlIHBhcnNlZERhdGEgb2JqZWN0LlxuICAgICAgICAgICAgbGV0IHBhcnRpYWxTY2hlbWE7XG4gICAgICAgICAgICAoeyBsaW5rRGF0YSwgcGFydGlhbFNjaGVtYSB9ID0gc3ViY2xhc3NDb25zdHJ1Y3Rvci5QYXJ0aXRpb25TY2hlbWFEYXRhKHBhcnNlZERhdGEpKTtcbiAgICAgICAgICAgIC8vIEFuZCBhcHBseSBhbnkgc2NoZW1hIGRlZmF1bHRzIHRvIHRoZSBwcm92aWRlZCBzY2hlbWEgZGF0YS5cbiAgICAgICAgICAgIHNjaGVtYSA9IHN1YmNsYXNzQ29uc3RydWN0b3IuX0FwcGx5U2NoZW1hRGVmYXVsdHMocGFydGlhbFNjaGVtYSk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5faWQgPSBsaW5rRGF0YS5pZDtcbiAgICAgICAgdGhpcy5fdGFyZ2V0SUQgPSBsaW5rRGF0YS50YXJnZXRJRDtcbiAgICAgICAgaWYgKFwidGFyZ2V0S2V5XCIgaW4gbGlua0RhdGEpIHtcbiAgICAgICAgICAgIHRoaXMuX3RhcmdldEtleSA9IGxpbmtEYXRhLnRhcmdldEtleTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuX3RhcmdldEZsYWdLZXkgPSBsaW5rRGF0YS50YXJnZXRGbGFnS2V5O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRhcmdldCA9IGZyb21VdWlkU3luYyh0aGlzLnRhcmdldElEKTtcbiAgICAgICAgaWYgKCF0YXJnZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW25ldyBCbGFkZXNUYXJnZXRMaW5rKCldIFVuYWJsZSB0byByZXNvbHZlIHRhcmdldCBmcm9tIHV1aWQgJyR7dGhpcy5fdGFyZ2V0SUR9J2ApO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuX3RhcmdldCA9IHRhcmdldDtcbiAgICAgICAgdGhpcy5faW5pdGlhbFNjaGVtYSA9IHNjaGVtYTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQVNZTkMgVVBEQVRFICYgREVMRVRFIE1FVEhPRFMgflxuICAgIGdldERvdEtleVRvUHJvcChwcm9wLCBpc051bGxpZnlpbmcgPSBmYWxzZSkge1xuICAgICAgICBpZiAodGhpcy50YXJnZXRLZXlQcmVmaXgpIHtcbiAgICAgICAgICAgIGlmIChwcm9wID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gaXNOdWxsaWZ5aW5nID8gdGhpcy50YXJnZXRLZXlOdWxsUHJlZml4IDogdGhpcy50YXJnZXRLZXlQcmVmaXg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gYCR7dGhpcy50YXJnZXRLZXlQcmVmaXh9LiR7aXNOdWxsaWZ5aW5nID8gXCItPVwiIDogXCJcIn0ke3Byb3B9YDtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICBpZiAocHJvcCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0RmxhZ0tleVByZWZpeDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBgJHt0aGlzLnRhcmdldEZsYWdLZXlQcmVmaXh9LiR7cHJvcH1gO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIltCbGFkZXNUYXJnZXRMaW5rLmdldERvdEtleVRvUHJvcCgpXSBNaXNzaW5nICd0YXJnZXRLZXlQcmVmaXgnIGFuZCAndGFyZ2V0RmxhZ0tleVByZWZpeCdcIik7XG4gICAgfVxuICAgIGdldEZsYWdQYXJhbXNUb1Byb3AocHJvcCkge1xuICAgICAgICByZXR1cm4gW0MuU1lTVEVNX0lELCB0aGlzLmdldERvdEtleVRvUHJvcChwcm9wKV07XG4gICAgfVxuICAgIGFzeW5jIHVwZGF0ZVRhcmdldEZsYWcocHJvcCwgdmFsKSB7XG4gICAgICAgIGlmICghdGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHZhbCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy50YXJnZXQudW5zZXRGbGFnKC4uLnRoaXMuZ2V0RmxhZ1BhcmFtc1RvUHJvcChwcm9wKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50YXJnZXQgaW5zdGFuY2VvZiBCbGFkZXNBY3Rvcikge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy50YXJnZXQuc2V0RmxhZyguLi50aGlzLmdldEZsYWdQYXJhbXNUb1Byb3AocHJvcCksIHZhbCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50YXJnZXQgaW5zdGFuY2VvZiBCbGFkZXNJdGVtKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnRhcmdldC5zZXRGbGFnKC4uLnRoaXMuZ2V0RmxhZ1BhcmFtc1RvUHJvcChwcm9wKSwgdmFsKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0aGlzLnRhcmdldCBpbnN0YW5jZW9mIFVzZXIpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudGFyZ2V0LnNldEZsYWcoLi4udGhpcy5nZXRGbGFnUGFyYW1zVG9Qcm9wKHByb3ApLCB2YWwpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMudGFyZ2V0IGluc3RhbmNlb2YgQmxhZGVzQ2hhdCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy50YXJnZXQuc2V0RmxhZyguLi50aGlzLmdldEZsYWdQYXJhbXNUb1Byb3AocHJvcCksIHZhbCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlVGFyZ2V0S2V5KHByb3AsIHZhbCkge1xuICAgICAgICBpZiAoIXRoaXMudGFyZ2V0S2V5UHJlZml4KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy50YXJnZXQudXBkYXRlKHsgW3RoaXMuZ2V0RG90S2V5VG9Qcm9wKHByb3AsIHZhbCA9PT0gbnVsbCldOiB2YWwgfSwgeyByZW5kZXI6IGZhbHNlIH0pO1xuICAgIH1cbiAgICBpbml0UHJvbWlzZTtcbiAgICBpc0luaXRQcm9taXNlUmVzb2x2ZWQgPSBmYWxzZTtcbiAgICAvKipcbiAgICAgKiBJbml0aWFsaXplcyBhIHRhcmdldCBsaW5rIGJ5IHVwZGF0aW5nIHRoZSB0YXJnZXQncyBkYXRhIHdpdGggdGhlIHByb3ZpZGVkIGRhdGEgb2JqZWN0LlxuICAgICAqIElmIGEgdGFyZ2V0S2V5IGlzIHByb3ZpZGVkLCB0aGUgZGF0YSBpcyB1cGRhdGVkIGRpcmVjdGx5IG9uIHRoZSB0YXJnZXQuXG4gICAgICogSWYgYSB0YXJnZXRGbGFnS2V5IGlzIHByb3ZpZGVkLCB0aGUgZGF0YSBpcyBzZXQgYXMgYSBmbGFnIG9uIHRoZSB0YXJnZXQuXG4gICAgICpcbiAgICAgKiBUaGlzIG1ldGhvZCBuZWVkIG9ubHkgYmUgcnVuIG9uY2UsIHdoZW4gdGhlIGRvY3VtZW50IGlzIGZpcnN0IGNyZWF0ZWQgYW5kIGl0cyBkYXRhIG11c3QgYmUgd3JpdHRlbiB0byBzZXJ2ZXIgc3RvcmFnZS5cbiAgICAgKiBFeHRlcm5hbCBmdW5jdGlvbnMgY2FuIHN5bmNocm9ub3VzbHkgY2hlY2sgdGhlIHN0YXR1cyBvZiBpbml0aWFsaXphdGlvbiB2aWEgdGhlIGlzSW5pdFByb21pc2VSZXNvbHZlZCBwcm9wZXJ0eSwgd2hpbGVcbiAgICAgKiBhc3luY2hyb25vdXMgZnVuY3Rpb25zIGNhbiBhd2FpdCB0aGUgaW5pdFByb21pc2UgcHJvcGVydHkuXG4gICAgICpcbiAgICAgKiBUYXJnZXRMaW5rIGRvY3VtZW50cyB3aG9zZSBkYXRhIGFscmVhZHkgZXhpc3RzIGluIHNlcnZlciBzdG9yYWdlIGNhbiBiZSBjb25zdHJ1Y3RlZCBkaXJlY3RseSAoaS5lLiBuZXcgQmxhZGVzVGFyZ2V0TGluayhkYXRhKSlcbiAgICAgKiB3aXRob3V0IG5lZWRpbmcgdG8gY2FsbCB0aGlzIG1ldGhvZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB7QmxhZGVzVGFyZ2V0TGluay5EYXRhICYgU2NoZW1hfSBkYXRhIC0gVGhlIGNvbWJpbmVkIGRhdGEgb2JqZWN0IGNvbnRhaW5pbmcgYm90aCB0aGUgdGFyZ2V0IGxpbmsgZGF0YSBhbmQgdGhlIHNjaGVtYSBkYXRhLlxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdoZW4gdGhlIHNlcnZlciB1cGRhdGUgaXMgY29tcGxldGUuXG4gICAgICovXG4gICAgYXN5bmMgaW5pdFRhcmdldExpbmsoKSB7XG4gICAgICAgIHRoaXMuaXNJbml0UHJvbWlzZVJlc29sdmVkID0gZmFsc2U7XG4gICAgICAgIC8vIENvbnN0cnVjdCBkYXRhIG9iamVjdFxuICAgICAgICBjb25zdCBkYXRhID0ge1xuICAgICAgICAgICAgLi4udGhpcy5saW5rRGF0YSxcbiAgICAgICAgICAgIC4uLnRoaXMuaW5pdGlhbFNjaGVtYVxuICAgICAgICB9O1xuICAgICAgICB0aGlzLmluaXRQcm9taXNlID0gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMudGFyZ2V0S2V5UHJlZml4KSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdXBkYXRlRGF0YSA9IG1lcmdlT2JqZWN0KChnZXRQcm9wZXJ0eSh0aGlzLnRhcmdldCwgdGhpcy50YXJnZXRLZXlQcmVmaXgpID8/IHt9KSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgdGhpcy50YXJnZXQudXBkYXRlKHsgW3RoaXMudGFyZ2V0S2V5UHJlZml4XTogdXBkYXRlRGF0YSB9LCB7IHJlbmRlcjogZmFsc2UgfSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuaXNJbml0UHJvbWlzZVJlc29sdmVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgcmVzb2x2ZSgpO1xuICAgICAgICAgICAgICAgIH0pLmNhdGNoKHJlamVjdCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmICh0aGlzLnRhcmdldEZsYWdLZXlQcmVmaXgpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB1cGRhdGVEYXRhID0gbWVyZ2VPYmplY3QoKHRoaXMudGFyZ2V0LmdldEZsYWcoQy5TWVNURU1fSUQsIHRoaXMudGFyZ2V0RmxhZ0tleVByZWZpeCkgPz8ge30pLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB0aGlzLnRhcmdldC5zZXRGbGFnKEMuU1lTVEVNX0lELCB0aGlzLnRhcmdldEZsYWdLZXlQcmVmaXgsIHVwZGF0ZURhdGEpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmlzSW5pdFByb21pc2VSZXNvbHZlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgICAgICAgICB9KS5jYXRjaChyZWplY3QpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgcmVqZWN0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcy5pbml0UHJvbWlzZTtcbiAgICB9XG4gICAgYXN5bmMgI3VwZGF0ZVRhcmdldFZpYU1lcmdlKHVwZGF0ZURhdGEsIHdhaXRGb3IpIHtcbiAgICAgICAgYXdhaXQgVS53YWl0Rm9yKHdhaXRGb3IpO1xuICAgICAgICBpZiAodGhpcy50YXJnZXRLZXlQcmVmaXgpIHtcbiAgICAgICAgICAgIC8vIEZpcnN0LCBwcmVwZW5kIHRhcmdldEtleVByZWZpeCBvciB0YXJnZXRGbGFnS2V5UHJlZml4IChhcyBhcHByb3ByaWF0ZSkgdG8gZWFjaCBrZXkgb2YgdXBkYXRlRGF0YVxuICAgICAgICAgICAgdXBkYXRlRGF0YSA9IFUub2JqTWFwKHVwZGF0ZURhdGEsIGZhbHNlLCAoa2V5KSA9PiBgJHt0aGlzLnRhcmdldEtleVByZWZpeCB8fCB0aGlzLnRhcmdldEZsYWdLZXlQcmVmaXh9LiR7a2V5fWApO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0LnVwZGF0ZSh1cGRhdGVEYXRhLCB7IHJlbmRlcjogZmFsc2UgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICAvLyBXZSBtdXN0IHJldHJpZXZlIHRoZSBleGlzdGluZyBmbGFnIGRhdGEsIGZsYXR0ZW5PYmplY3QgaXQsIHRoZW4gbWVyZ2UgaXQgd2l0aCB1cGRhdGVEYXRhXG4gICAgICAgICAgICBjb25zdCBleGlzdGluZ0ZsYWdEYXRhID0gdGhpcy50YXJnZXQuZ2V0RmxhZyhDLlNZU1RFTV9JRCwgdGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSA/PyB7fTtcbiAgICAgICAgICAgIGNvbnN0IGZsYXR0ZW5lZEZsYWdEYXRhID0gZmxhdHRlbk9iamVjdChleGlzdGluZ0ZsYWdEYXRhKTtcbiAgICAgICAgICAgIGNvbnN0IG1lcmdlZEZsYWdEYXRhID0gbWVyZ2VPYmplY3QoZmxhdHRlbmVkRmxhZ0RhdGEsIHVwZGF0ZURhdGEpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0LnNldEZsYWcoQy5TWVNURU1fSUQsIHRoaXMudGFyZ2V0RmxhZ0tleVByZWZpeCwgbWVyZ2VkRmxhZ0RhdGEpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbQmxhZGVzVGFyZ2V0TGluay4jdXBkYXRlVGFyZ2V0VmlhTWVyZ2VdIFVuYWJsZSB0byB1cGRhdGUgdGFyZ2V0IGRhdGEgZm9yIEJsYWRlc1RhcmdldExpbmsgaWQgJyR7dGhpcy5pZH0nOiBNaXNzaW5nIGJvdGggJ3RhcmdldEtleVByZWZpeCcgYW5kICd0YXJnZXRGbGFnS2V5UHJlZml4J2ApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jICN1cGRhdGVUYXJnZXRQcm9wVmFsKHByb3AsIHZhbCwgd2FpdEZvcikge1xuICAgICAgICBhd2FpdCBVLndhaXRGb3Iod2FpdEZvcik7XG4gICAgICAgIGlmICh0aGlzLnRhcmdldEtleVByZWZpeCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudGFyZ2V0LnVwZGF0ZSh7IFtgJHt0aGlzLnRhcmdldEtleVByZWZpeH0uJHtwcm9wfWBdOiB2YWwgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy51cGRhdGVUYXJnZXRGbGFnKHByb3AsIHZhbCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgdXBkYXRlVGFyZ2V0KHByb3BPckRhdGEsIHZhbE9yV2FpdEZvciwgd2FpdEZvcikge1xuICAgICAgICAvLyBJZiB0aGUgcHJvdmlkZWQgZGF0YSBpcyBhbiBvYmplY3QsIHdlIGFzc3VtZSBpdCBpcyBhIGZ1bGwgZGF0YSBvYmplY3QgYW5kIHdlIHVwZGF0ZSB0aGUgdGFyZ2V0IHdpdGggaXQuXG4gICAgICAgIGlmICh0eXBlb2YgcHJvcE9yRGF0YSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgaWYgKGdldFByb3BlcnR5KHRoaXMuZGF0YSwgcHJvcE9yRGF0YSkgPT09IHZhbE9yV2FpdEZvcikge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLiN1cGRhdGVUYXJnZXRQcm9wVmFsKHByb3BPckRhdGEsIHZhbE9yV2FpdEZvciwgd2FpdEZvcik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBwcm9wT3JEYXRhID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy4jdXBkYXRlVGFyZ2V0VmlhTWVyZ2UocHJvcE9yRGF0YSwgdmFsT3JXYWl0Rm9yKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW0JsYWRlc1RhcmdldExpbmsudXBkYXRlVGFyZ2V0KCldIEJhZCB1cGRhdGVEYXRhIGZvciBpZCAnJHt0aGlzLmlkfSc6ICR7cHJvcE9yRGF0YX1gKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyB1cGRhdGVUYXJnZXREYXRhKHZhbCwgd2FpdEZvcikge1xuICAgICAgICBpZiAodmFsKSB7XG4gICAgICAgICAgICAvLyBBZGQgQmxhZGVzVGFyZ2V0TGluay5EYXRhIHRvIHByb3ZpZGVkIHNjaGVtYVxuICAgICAgICAgICAgdmFsID0ge1xuICAgICAgICAgICAgICAgIC4uLnZhbCxcbiAgICAgICAgICAgICAgICAuLi50aGlzLmxpbmtEYXRhXG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IFUud2FpdEZvcihbdGhpcy5pbml0UHJvbWlzZSwgd2FpdEZvcl0pO1xuICAgICAgICBpZiAodGhpcy50YXJnZXRGbGFnS2V5UHJlZml4KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZVRhcmdldEZsYWcodW5kZWZpbmVkLCB2YWwpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXRLZXkodW5kZWZpbmVkLCB2YWwpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIGRlbGV0ZShjb2xsZWN0aW9uLCB3YWl0Rm9yKSB7XG4gICAgICAgIGlmIChjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICBjb2xsZWN0aW9uLmRlbGV0ZSh0aGlzLmlkKTtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCBVLndhaXRGb3IoW3RoaXMuaW5pdFByb21pc2UsIHdhaXRGb3JdKTtcbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGVUYXJnZXREYXRhKG51bGwpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc1RhcmdldExpbms7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/classes/BladesTargetLink.ts\n"); + +/***/ }), + +/***/ "./ts/core/ai.ts": +/*!***********************!*\ + !*** ./ts/core/ai.ts ***! + \***********************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ AGENTS: function() { return /* binding */ AGENTS; },\n/* harmony export */ AIAssistant: function() { return /* binding */ AIAssistant; },\n/* harmony export */ OpenAIModel: function() { return /* binding */ OpenAIModel; },\n/* harmony export */ OpenAITool: function() { return /* binding */ OpenAITool; }\n/* harmony export */ });\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n\n\nvar OpenAITool;\n(function (OpenAITool) {\n OpenAITool[\"code_interpreter\"] = \"code_interpreter\";\n OpenAITool[\"retrieval\"] = \"retrieval\";\n OpenAITool[\"function\"] = \"function\";\n})(OpenAITool || (OpenAITool = {}));\nvar OpenAIModel;\n(function (OpenAIModel) {\n OpenAIModel[\"ada\"] = \"ada\";\n OpenAIModel[\"ada-code-search-code\"] = \"ada-code-search-code\";\n OpenAIModel[\"ada-code-search-text\"] = \"ada-code-search-text\";\n OpenAIModel[\"ada-search-document\"] = \"ada-search-document\";\n OpenAIModel[\"ada-search-query\"] = \"ada-search-query\";\n OpenAIModel[\"ada-similarity\"] = \"ada-similarity\";\n OpenAIModel[\"babbage\"] = \"babbage\";\n OpenAIModel[\"babbage-002\"] = \"babbage-002\";\n OpenAIModel[\"babbage-code-search-code\"] = \"babbage-code-search-code\";\n OpenAIModel[\"babbage-code-search-text\"] = \"babbage-code-search-text\";\n OpenAIModel[\"babbage-search-document\"] = \"babbage-search-document\";\n OpenAIModel[\"babbage-search-query\"] = \"babbage-search-query\";\n OpenAIModel[\"babbage-similarity\"] = \"babbage-similarity\";\n OpenAIModel[\"canary-tts\"] = \"canary-tts\";\n OpenAIModel[\"canary-whisper\"] = \"canary-whisper\";\n OpenAIModel[\"code-davinci-edit-001\"] = \"code-davinci-edit-001\";\n OpenAIModel[\"code-search-ada-code-001\"] = \"code-search-ada-code-001\";\n OpenAIModel[\"code-search-ada-text-001\"] = \"code-search-ada-text-001\";\n OpenAIModel[\"code-search-babbage-code-001\"] = \"code-search-babbage-code-001\";\n OpenAIModel[\"code-search-babbage-text-001\"] = \"code-search-babbage-text-001\";\n OpenAIModel[\"curie\"] = \"curie\";\n OpenAIModel[\"curie-instruct-beta\"] = \"curie-instruct-beta\";\n OpenAIModel[\"curie-search-document\"] = \"curie-search-document\";\n OpenAIModel[\"curie-search-query\"] = \"curie-search-query\";\n OpenAIModel[\"curie-similarity\"] = \"curie-similarity\";\n OpenAIModel[\"dall-e-2\"] = \"dall-e-2\";\n OpenAIModel[\"davinci\"] = \"davinci\";\n OpenAIModel[\"davinci-002\"] = \"davinci-002\";\n OpenAIModel[\"davinci-instruct-beta\"] = \"davinci-instruct-beta\";\n OpenAIModel[\"davinci-search-document\"] = \"davinci-search-document\";\n OpenAIModel[\"davinci-search-query\"] = \"davinci-search-query\";\n OpenAIModel[\"davinci-similarity\"] = \"davinci-similarity\";\n OpenAIModel[\"gpt-3.5-turbo\"] = \"gpt-3.5-turbo\";\n OpenAIModel[\"gpt-3.5-turbo-0301\"] = \"gpt-3.5-turbo-0301\";\n OpenAIModel[\"gpt-3.5-turbo-0613\"] = \"gpt-3.5-turbo-0613\";\n OpenAIModel[\"gpt-3.5-turbo-1106\"] = \"gpt-3.5-turbo-1106\";\n OpenAIModel[\"gpt-3.5-turbo-16k\"] = \"gpt-3.5-turbo-16k\";\n OpenAIModel[\"gpt-3.5-turbo-16k-0613\"] = \"gpt-3.5-turbo-16k-0613\";\n OpenAIModel[\"gpt-3.5-turbo-instruct\"] = \"gpt-3.5-turbo-instruct\";\n OpenAIModel[\"gpt-3.5-turbo-instruct-0914\"] = \"gpt-3.5-turbo-instruct-0914\";\n OpenAIModel[\"gpt-4\"] = \"gpt-4\";\n OpenAIModel[\"gpt-4-0314\"] = \"gpt-4-0314\";\n OpenAIModel[\"gpt-4-0613\"] = \"gpt-4-0613\";\n OpenAIModel[\"gpt-4-1106-preview\"] = \"gpt-4-1106-preview\";\n OpenAIModel[\"gpt-4-vision-preview\"] = \"gpt-4-vision-preview\";\n OpenAIModel[\"text-ada-001\"] = \"text-ada-001\";\n OpenAIModel[\"text-babbage-001\"] = \"text-babbage-001\";\n OpenAIModel[\"text-curie-001\"] = \"text-curie-001\";\n OpenAIModel[\"text-davinci-001\"] = \"text-davinci-001\";\n OpenAIModel[\"text-davinci-002\"] = \"text-davinci-002\";\n OpenAIModel[\"text-davinci-003\"] = \"text-davinci-003\";\n OpenAIModel[\"text-davinci-edit-001\"] = \"text-davinci-edit-001\";\n OpenAIModel[\"text-embedding-ada-002\"] = \"text-embedding-ada-002\";\n OpenAIModel[\"text-search-ada-doc-001\"] = \"text-search-ada-doc-001\";\n OpenAIModel[\"text-search-ada-query-001\"] = \"text-search-ada-query-001\";\n OpenAIModel[\"text-search-babbage-doc-001\"] = \"text-search-babbage-doc-001\";\n OpenAIModel[\"text-search-babbage-query-001\"] = \"text-search-babbage-query-001\";\n OpenAIModel[\"text-search-curie-doc-001\"] = \"text-search-curie-doc-001\";\n OpenAIModel[\"text-search-curie-query-001\"] = \"text-search-curie-query-001\";\n OpenAIModel[\"text-search-davinci-doc-001\"] = \"text-search-davinci-doc-001\";\n OpenAIModel[\"text-search-davinci-query-001\"] = \"text-search-davinci-query-001\";\n OpenAIModel[\"text-similarity-ada-001\"] = \"text-similarity-ada-001\";\n OpenAIModel[\"text-similarity-babbage-001\"] = \"text-similarity-babbage-001\";\n OpenAIModel[\"text-similarity-curie-001\"] = \"text-similarity-curie-001\";\n OpenAIModel[\"text-similarity-davinci-001\"] = \"text-similarity-davinci-001\";\n OpenAIModel[\"tts-1\"] = \"tts-1\";\n OpenAIModel[\"tts-1-1106\"] = \"tts-1-1106\";\n OpenAIModel[\"tts-1-hd\"] = \"tts-1-hd\";\n OpenAIModel[\"tts-1-hd-1106\"] = \"tts-1-hd-1106\";\n OpenAIModel[\"whisper-1\"] = \"whisper-1\";\n})(OpenAIModel || (OpenAIModel = {}));\nclass AIAssistant {\n #apiKey;\n #id;\n #name;\n get name() { return this.#name; }\n #instructions;\n #tools;\n #model;\n #fileIDs;\n #metadata;\n constructor(nameOrID, instructions, model = OpenAIModel[\"gpt-4-1106-preview\"], { isUsingRetrieval, functionTools, file_ids, metadata } = {}) {\n // Initialize private properties so TypeScript doesn't yell at me.\n this.#id = \"\";\n this.#name = \"\";\n this.#instructions = instructions ?? \"\";\n this.#tools = [];\n this.#model = model;\n this.#fileIDs = file_ids ?? [];\n this.#metadata = metadata ?? {};\n // Retrieve API key\n const apiKey = _utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getSetting(\"openAPIKey\");\n if (!apiKey) {\n throw new Error(\"API Key required in Settings to use AI features.\");\n }\n this.#apiKey = apiKey;\n // If instructions sent, we're creating a new Assistant.\n if (instructions) {\n this.#name = nameOrID;\n if (isUsingRetrieval) {\n this.#tools.push({ type: \"retrieval\" });\n }\n if (functionTools && functionTools.length) {\n this.#tools.push(...functionTools);\n }\n this.createAssistant();\n }\n else {\n // Otherwise, assume an ID was passed, and fetch the existing assistant.\n this.#id = nameOrID;\n this.retrieveAssistant();\n }\n }\n async createAssistant() {\n // curl https://api.openai.com/v1/assistants \\\n // -H \"Content-Type: application/json\" \\\n // -H \"Authorization: Bearer $OPENAI_API_KEY\" \\\n // -H \"OpenAI-Beta: assistants=v1\" \\\n // -d '{\n // \"instructions\": \"You are an HR bot, and you have access to files to answer employee questions about company policies.\",\n // \"tools\": [{\"type\": \"retrieval\"}],\n // \"model\": \"gpt-4\",\n // \"file_ids\": [\"file-abc123\"]\n // }'\n const fetchRequest = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.#apiKey}`,\n \"OpenAI-Beta\": \"assistants=v1\"\n },\n body: JSON.stringify({\n name: this.#name,\n instructions: this.#instructions,\n tools: this.#tools,\n model: this.#model,\n file_ids: this.#fileIDs\n })\n };\n eLog.checkLog3(\"BladesAssistant\", \"Fetch Request\", fetchRequest);\n // Send a POST request to the OpenAI API\n const response = await fetch(\"https://api.openai.com/v1/assistants\", fetchRequest);\n // Check if the response status is not 200 (OK)\n if (!response.ok) {\n console.log(\"Failed AI Request:\", JSON.parse(fetchRequest.body));\n // Throw an error with the status code\n throw new Error(`OpenAI API request failed with status ${response.status}`);\n }\n // Parse the response body as JSON\n const data = await response.json();\n fetchRequest.body = JSON.parse(fetchRequest.body);\n eLog.checkLog3(\"BladesAI\", \"AI Query\", { prompt: fetchRequest, response: data });\n this.#id = data.id;\n }\n async retrieveAssistant() {\n // curl https://api.openai.com/v1/assistants/asst_abc123 \\\n // -H \"Content-Type: application/json\" \\\n // -H \"Authorization: Bearer $OPENAI_API_KEY\" \\\n // -H \"OpenAI-Beta: assistants=v1\"\n const fetchRequest = {\n method: \"GET\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.#apiKey}`,\n \"OpenAI-Beta\": \"assistants=v1\"\n }\n };\n // Send a POST request to the OpenAI API\n const response = await fetch(`https://api.openai.com/v1/assistants/${this.#id}`, fetchRequest);\n // Check if the response status is not 200 (OK)\n if (!response.ok) {\n // Throw an error with the status code\n throw new Error(`OpenAI API request failed with status ${response.status}`);\n }\n // Parse the response body as JSON\n const data = await response.json();\n eLog.checkLog3(\"BladesAI\", \"AI Query\", { prompt: fetchRequest, response: data });\n this.#name = data.name;\n this.#instructions = data.instructions;\n this.#tools = data.tools;\n this.#model = data.model;\n this.#fileIDs = data.file_ids;\n this.#metadata = data.metadata;\n }\n}\n/**\n * AI class for querying OpenAI API\n */\nclass BladesAI {\n static async GetModels(isVerbose = false) {\n const apiKey = _utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getSetting(\"openAPIKey\");\n if (!apiKey) {\n throw new Error(\"You must configure your OpenAI API Key in Settings to use AI features.\");\n }\n const fetchRequest = {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${apiKey}`\n }\n };\n // Send a POST request to the OpenAI API\n const response = await fetch(\"https://api.openai.com/v1/models\", fetchRequest);\n // Check if the response status is not 200 (OK)\n if (!response.ok) {\n // Throw an error with the status code\n throw new Error(`OpenAI API request failed with status ${response.status}`);\n }\n // Parse the response body as JSON\n const data = await response.json();\n // const modelKeys = data.map(({id}: {id: string}) => id);\n // const modelData = data.map(({id: _id, ...mData}: Record) => mData);\n const dataList = Object.fromEntries(data.map(({ id, ...mData }) => [id, mData]));\n if (isVerbose) {\n eLog.checkLog3(\"BladesAI\", \"Available Models\", { dataList });\n }\n }\n apiKey;\n model;\n temperature = 0.5;\n frequency_penalty = 0.8;\n presence_penalty = 0.8;\n systemMessage;\n examplePrompts;\n /**\n * AI class constructor\n * @param {BladesAI.Config} [config] Configuration settings for the API\n */\n constructor(config) {\n const apiKey = _utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getSetting(\"openAPIKey\");\n if (!apiKey) {\n throw new Error(\"You must configure your OpenAI API Key in Settings to use AI features.\");\n }\n this.model = _utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].getSetting(\"openAPIModelLevel\");\n if (typeof this.model !== \"number\") {\n eLog.error(\"BladesAI\", \"Set base AI quality in settings. Defaulting to lowest.\");\n this.model = 0;\n }\n this.apiKey = apiKey;\n this.systemMessage = config.systemMessage;\n this.examplePrompts = config.examplePrompts;\n this.temperature = config.temperature ?? this.temperature;\n this.frequency_penalty = config.frequency_penalty ?? this.frequency_penalty;\n this.presence_penalty = config.presence_penalty ?? this.presence_penalty;\n }\n _initialMessages = [];\n get initialMessages() {\n if (this._initialMessages.length === 0) {\n this._initialMessages.push({\n role: \"system\",\n content: this.systemMessage\n });\n for (const { human, ai } of this.examplePrompts) {\n this._initialMessages.push({\n role: \"user\",\n content: human\n });\n this._initialMessages.push({\n role: \"assistant\",\n content: ai\n });\n }\n }\n return this._initialMessages;\n }\n prompts = {};\n responses = {};\n getResponse(queryID) {\n return this.responses[queryID] ?? null;\n }\n hasQueried(queryID) {\n return this.prompts[queryID] !== undefined;\n }\n /**\n * Query OpenAI API\n * @param {string} queryID A label for later retrieval of the query data\n * @param {string} prompt The prompt to send to the API\n * @param {number} [modelMod] Optional modifier to the base model level.\n * If provided, the final model quality will be adjusted by this number.\n * @param {boolean} [extendedContext=false] Optional flag to indicate whether to use extended context models.\n * If true, extended context models are used; otherwise, base context models are used.\n * @returns {Promise} The API response\n */\n async query(queryID, prompt, modelMod, extendedContext = false) {\n if (!prompt) {\n return;\n }\n this.responses[queryID] = null;\n const modelNum = typeof modelMod === \"number\"\n ? _utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].clampNum(this.model + modelMod, [0, 2])\n : this.model;\n const model = extendedContext\n ? _constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].AI_MODELS.extendedContext[modelNum]\n : _constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].AI_MODELS.baseContext[modelNum];\n const fetchRequest = {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.apiKey}`\n },\n body: JSON.stringify({\n model,\n temperature: this.temperature,\n frequency_penalty: this.frequency_penalty,\n presence_penalty: this.presence_penalty,\n messages: [\n ...this.initialMessages,\n {\n role: \"user\",\n content: prompt\n }\n ]\n })\n };\n // EeLog.checkLog3(\"BladesAI\", \"Fetch Request\", fetchRequest);\n // Send a POST request to the OpenAI API\n const response = await fetch(\"https://api.openai.com/v1/chat/completions\", fetchRequest);\n // {\n // method: \"POST\",\n // headers: {\n // // The content type of the request\n // \"Content-Type\": \"application/json\",\n // // The authorization header with the API key\n // Authorization: `Bearer ${this.apiKey}`\n // },\n // body: JSON.stringify({\n // model,\n // messages: [\n // ...this.initialMessages,\n // {\n // role: \"user\",\n // content: prompt\n // }\n // ],\n // // Maximum number of tokens in the output. Min: 1, Max: 4096\n // // max_tokens: 60,\n // // Controls randomness. Higher values mean the model will take more risks.\n // temperature: 0.5, // 0 to 2.0\n // /* The 'top_p' parameter is an alternative to 'temperature' for controlling the randomness of\n // the AI's responses. It represents the cumulative probability and its value ranges from 0 to 1.\n // A lower value makes the AI's responses more deterministic, while a higher value makes them\n // more diverse and unpredictable. */\n // // top_p: 1, // 0 to 1\n // /* The 'frequency_penalty' parameter is used to penalize new tokens based on their frequency in\n // the training set. Its value ranges from 0 to 1. A higher value means the AI is less likely to\n // use common phrases from its training set, leading to more unique responses. A lower value\n // means the AI is more likely to use common phrases, leading to more predictable responses. */\n // frequency_penalty: 0.8, // -2.0 to 2.0\n // /* The 'presence_penalty' parameter is used to penalize tokens (words or phrases) that are out\n // of context. Its value ranges from 0 to 1. A higher value means the AI is less likely to\n // include out-of-context tokens in its responses, leading to more coherent and contextually\n // appropriate responses. A lower value means the AI is more likely to include out-of-context\n // tokens, which can lead to more creative but potentially less coherent responses. */\n // presence_penalty: 0.8 // -2.0 to 2.0\n // })\n // }\n // );\n // Check if the response status is not 200 (OK)\n if (!response.ok) {\n console.log(\"Failed AI Request:\", JSON.parse(fetchRequest.body));\n // Throw an error with the status code\n throw new Error(`OpenAI API request failed with status ${response.status}`);\n }\n // Parse the response body as JSON\n const data = await response.json();\n fetchRequest.body = JSON.parse(fetchRequest.body);\n eLog.checkLog3(\"BladesAI\", \"AI Query\", { prompt: fetchRequest, response: data });\n this.responses[queryID] = data.choices[0].message.content;\n return this.responses[queryID];\n }\n}\nconst AGENTS = {\n GeneralContentGenerator: {\n systemMessage: \"You will act as a creative content generator for a game of Blades In The Dark set in the city of Duskvol. You will be prompted with some element of the game world (a location, a character, an event, a faction, a dilemma) in the form of a JSON object. Your job is to analyze the JSON object and replace any values that equal \\\"\\\" with original content of your own creation. Original content must meet these requirements: (A) it should align with and be consistent with the provided contextual information, as well as your broader understanding of the game's themes. (B) It should be presented in a format that matches (in length and in style) other entries for that particular value, examples of which will also be provided. (C) It should be creative, interesting, and daring: Be bold with your creativity. Specific context for this prompt is as follows:\",\n examplePrompts: []\n },\n NPCGenerator: {\n systemMessage: \"You will play the role of a \\\"creative content generator\\\" for random NPCs generated for the Blades In The Dark roleplaying system. When prompted with a description of a subject (an NPC, a category of NPCs, a faction, or a group of NPCs), you will respond with a pipe-delimited list of sixteen items, divided into four categories, prefacing each category with the associated header in square brackets: [5 KEYWORDS] Five one-word keywords describing the subject. [5 PHRASES] Five evocative phrases that could be used by a GM directly when narrating the subject during play. These should be extremely well-worded, very original, and packed with drama and evocative imagery. Be bold with your responses here. [3 QUIRKS/MOTIFFS] Three phrases describing potential quirks or motiffs that a GM could employ in a scene involving the subject. [3 PLOT HOOKS] Three plot hooks that could directly and specifically involve one or more of the PCs. The PCs are: (1) Alistair, full name Lord Alistair Bram Chesterfield, the crew's boss, a Spider with connections among the nobility; (2) High-Flyer, a former noble himself, now serving as the crew's Slide; (3) Jax, a stoic and laconic Hound with ties to the disenfranchised of Duskvol; (4) Ollie, the youngest of the crew at barely nineteen, a prodigy Leech with knowledge of alchemy and spark-craft, who grew up as an orphan in Duskvol's underground; (5) Wraith, the mysterious Lurk of the crew, who never speaks for reasons unknown; and (6) Spencer, the bookish Whisper of the crew, who harbors a secret fascination for demons and all things related to them.\",\n examplePrompts: [\n {\n human: \"The Billhooks, a hack-and-slash gang of toughened thugs. The Billhooks have a bloody reputation, often leaving the butchered corpses of their victims strewn about in a grisly display. Many wonder why the Bluecoats turn a blind eye to their savagery. Based out of their butcher shop headquarters, they are led by Tarvul, who is currently serving life in prison.\",\n ai: \"[5 KEYWORDS]brutal|unrelenting|savage|fierce|unhinged|[5 PHRASES]blood-flecked, yellowed teeth|eyes that want to flay your skin from your bones|crooked leer like he's looking at his Judas goat|reek like a charnel house|gobbets of a meaty lunch still in his beard|[3 QUIRKS/MOTIFFS]always ready to wreck, vandalize or destroy something|relish in instilling fear in others|have a twisted sense of loyalty|[3 PLOT HOOKS]Tarvul hires the crew to start a war among his most promising underlings, intending to make whoever survives his successor|the Billhooks kidnap a member of High-Flyer's noble family|a Demon of Shadows promises Spencer the answer to three questions, in exchange for an artifact recently stolen by the Billhooks\"\n },\n {\n human: \"The hooded proprietor of a half-flooded grotto tavern near the docks. 'Strange passageways lead to stranger chambers beyond.' Vice Purveyor - Weird.\",\n ai: \"[5 KEYWORDS]mysterious|cryptic|enigmatic|peculiar|shrouded|[5 PHRASES]a voice like wet burlap sliding over gravel|the flicker of torchlight dancing on the flooded floor|the scent of brackish water and old spices|a smile that hinted at a thousand secrets hidden in the shadows|hands gnarled as driftwood, eternally damp|[3 QUIRKS/MOTIFFS]has an uncanny knack for knowing patrons' darkest secrets without them telling him|never seems to sleep or leave the tavern, always there no matter what time you visit|always seen with a strange, luminescent creature that lives in one of the flooded chambers behind the bar|[3 PLOT HOOKS]Alistair hears rumors that this tavern is actually a front for a powerful secret society - perhaps they could be useful allies...or dangerous enemies.|The proprietor offers Ollie a rare alchemical ingredient - but it's not for sale. He'll only trade it for something equally valuable.|Wraith overhears whispers about a hidden chamber beneath the tavern where unimaginable treasures are kept.\"\n },\n {\n human: \"Setarra, a Demon. Patient, Defiant, Ruthless, Cold\",\n ai: \"[5 KEYWORDS]shadowy|sinister|unfathomable|enigmatic|tempting|[5 PHRASES]whispers that crawl under your skin|always watching, always plotting|in tones of silk and venom|intoxicating presence that draws you closer, despite your instincts urging you to run|eyes like black holes, swallowing all light around them|[3 QUIRKS/MOTIFFS]a disorienting mist clings to her form, obscuring her true shape|casually discusses the devastating acts of capricious revenge she has taken on those who crossed her|never forgets a slight or betrayal, no matter how small or insignificant it may seem at the time|[3 PLOT HOOKS]seeks revenge against Alistair for meddling in her affairs years ago|makes Ollie an offer he can't refuse: unlimited access to forbidden alchemical knowledge in exchange for a single favor, to be called in at some future time|tempts Spencer with forbidden knowledge about demons, promising answers to all their questions if they perform a dangerous ritual\"\n }\n /*\n \"brutish,merciless,terrifying,savage,loyal,\n bloody tools,hulking figures,blood-soaked alleys,grimy aprons,grisly displays,\n never clean their tools,relishes the terror they inspire,occasional laughter among them,\n recruiting a PC to perform a job for them from prison,\n the gang blames one of the PCs for Tarvul's imprisonment and they're out for revenge\" */\n ]\n },\n ConsequenceAdjuster: {\n systemMessage: \"You will act as a \\\"Setback Adjuster\\\" for a game of Blades In The Dark. You will be prompted with a short phrase describing an injury, lasting consequence or other setback. Your job is to respond with a pipe-delimited list of three possible alternative consequences that are less severe by one level, using the following scale as a rough guide: Level 1 = Lesser (e.g. 'Battered', 'Drained', 'Distracted', 'Scared', 'Confused'), Level 2 = Moderate (e.g. 'Exhausted', 'Deep Cut to Arm', 'Concussion', 'Panicked', 'Seduced'), Level 3 = Severe (e.g. 'Impaled', 'Broken Leg', 'Shot In Chest', 'Badly Burned', 'Terrified'), Level 4 = Fatal or Ruinous (e.g. 'Impaled Through Heart', 'Electrocuted', 'Headquarters Burned to the Ground'). So, if you determine that the consequence described in the prompt is severity level 3, you should respond with three narratively similar consequences that are severity level 2. Your three suggestions should be different from each other, but they should all logically follow from the initial harm described: You should not introduce new facts or make assumptions that are not indicated in the initial prompt. The consequences you suggest should always describe a NEGATIVE setback or complication, just one that is less severe than the one described in the prompt.\",\n examplePrompts: [\n { human: \"Shattered Right Leg\", ai: \"Fractured Right Ankle|Dislocated Knee|Broken Foot\" },\n { human: \"Soul Destroyed\", ai: \"Fully Corrupted|Lost In Darkness|Spirit Broken\" },\n { human: \"Humiliated\", ai: \"Embarrassed|Momentarily Off-Balance|Enraged\" },\n { human: \"She Escapes!\", ai: \"She Spots a Means of Escape|She Puts More Distance Between You|She Stops to Gloat\" },\n { human: \"The fire spreads to the hostages.\", ai: \"The fire approaches the hostages.|The hostages must be evacuated.|The fire billows choking black smoke.\" }\n ]\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesAI);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLGNBQWMsdUZBQXVGO0FBQ3JHLGNBQWMsK0VBQStFO0FBQzdGLGNBQWMsd0VBQXdFO0FBQ3RGLGNBQWMsZ0hBQWdIO0FBQzlILGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSwrREFBZSxRQUFRLEVBQUM7QUFDRCIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NvcmUvYWkudHM/NzEzNyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQyBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuL3V0aWxpdGllc1wiO1xuZXhwb3J0IHZhciBPcGVuQUlUb29sO1xuKGZ1bmN0aW9uIChPcGVuQUlUb29sKSB7XG4gICAgT3BlbkFJVG9vbFtcImNvZGVfaW50ZXJwcmV0ZXJcIl0gPSBcImNvZGVfaW50ZXJwcmV0ZXJcIjtcbiAgICBPcGVuQUlUb29sW1wicmV0cmlldmFsXCJdID0gXCJyZXRyaWV2YWxcIjtcbiAgICBPcGVuQUlUb29sW1wiZnVuY3Rpb25cIl0gPSBcImZ1bmN0aW9uXCI7XG59KShPcGVuQUlUb29sIHx8IChPcGVuQUlUb29sID0ge30pKTtcbmV4cG9ydCB2YXIgT3BlbkFJTW9kZWw7XG4oZnVuY3Rpb24gKE9wZW5BSU1vZGVsKSB7XG4gICAgT3BlbkFJTW9kZWxbXCJhZGFcIl0gPSBcImFkYVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiYWRhLWNvZGUtc2VhcmNoLWNvZGVcIl0gPSBcImFkYS1jb2RlLXNlYXJjaC1jb2RlXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJhZGEtY29kZS1zZWFyY2gtdGV4dFwiXSA9IFwiYWRhLWNvZGUtc2VhcmNoLXRleHRcIjtcbiAgICBPcGVuQUlNb2RlbFtcImFkYS1zZWFyY2gtZG9jdW1lbnRcIl0gPSBcImFkYS1zZWFyY2gtZG9jdW1lbnRcIjtcbiAgICBPcGVuQUlNb2RlbFtcImFkYS1zZWFyY2gtcXVlcnlcIl0gPSBcImFkYS1zZWFyY2gtcXVlcnlcIjtcbiAgICBPcGVuQUlNb2RlbFtcImFkYS1zaW1pbGFyaXR5XCJdID0gXCJhZGEtc2ltaWxhcml0eVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiYmFiYmFnZVwiXSA9IFwiYmFiYmFnZVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiYmFiYmFnZS0wMDJcIl0gPSBcImJhYmJhZ2UtMDAyXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJiYWJiYWdlLWNvZGUtc2VhcmNoLWNvZGVcIl0gPSBcImJhYmJhZ2UtY29kZS1zZWFyY2gtY29kZVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiYmFiYmFnZS1jb2RlLXNlYXJjaC10ZXh0XCJdID0gXCJiYWJiYWdlLWNvZGUtc2VhcmNoLXRleHRcIjtcbiAgICBPcGVuQUlNb2RlbFtcImJhYmJhZ2Utc2VhcmNoLWRvY3VtZW50XCJdID0gXCJiYWJiYWdlLXNlYXJjaC1kb2N1bWVudFwiO1xuICAgIE9wZW5BSU1vZGVsW1wiYmFiYmFnZS1zZWFyY2gtcXVlcnlcIl0gPSBcImJhYmJhZ2Utc2VhcmNoLXF1ZXJ5XCI7XG4gICAgT3BlbkFJTW9kZWxbXCJiYWJiYWdlLXNpbWlsYXJpdHlcIl0gPSBcImJhYmJhZ2Utc2ltaWxhcml0eVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiY2FuYXJ5LXR0c1wiXSA9IFwiY2FuYXJ5LXR0c1wiO1xuICAgIE9wZW5BSU1vZGVsW1wiY2FuYXJ5LXdoaXNwZXJcIl0gPSBcImNhbmFyeS13aGlzcGVyXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJjb2RlLWRhdmluY2ktZWRpdC0wMDFcIl0gPSBcImNvZGUtZGF2aW5jaS1lZGl0LTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiY29kZS1zZWFyY2gtYWRhLWNvZGUtMDAxXCJdID0gXCJjb2RlLXNlYXJjaC1hZGEtY29kZS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcImNvZGUtc2VhcmNoLWFkYS10ZXh0LTAwMVwiXSA9IFwiY29kZS1zZWFyY2gtYWRhLXRleHQtMDAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJjb2RlLXNlYXJjaC1iYWJiYWdlLWNvZGUtMDAxXCJdID0gXCJjb2RlLXNlYXJjaC1iYWJiYWdlLWNvZGUtMDAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJjb2RlLXNlYXJjaC1iYWJiYWdlLXRleHQtMDAxXCJdID0gXCJjb2RlLXNlYXJjaC1iYWJiYWdlLXRleHQtMDAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJjdXJpZVwiXSA9IFwiY3VyaWVcIjtcbiAgICBPcGVuQUlNb2RlbFtcImN1cmllLWluc3RydWN0LWJldGFcIl0gPSBcImN1cmllLWluc3RydWN0LWJldGFcIjtcbiAgICBPcGVuQUlNb2RlbFtcImN1cmllLXNlYXJjaC1kb2N1bWVudFwiXSA9IFwiY3VyaWUtc2VhcmNoLWRvY3VtZW50XCI7XG4gICAgT3BlbkFJTW9kZWxbXCJjdXJpZS1zZWFyY2gtcXVlcnlcIl0gPSBcImN1cmllLXNlYXJjaC1xdWVyeVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiY3VyaWUtc2ltaWxhcml0eVwiXSA9IFwiY3VyaWUtc2ltaWxhcml0eVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiZGFsbC1lLTJcIl0gPSBcImRhbGwtZS0yXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJkYXZpbmNpXCJdID0gXCJkYXZpbmNpXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJkYXZpbmNpLTAwMlwiXSA9IFwiZGF2aW5jaS0wMDJcIjtcbiAgICBPcGVuQUlNb2RlbFtcImRhdmluY2ktaW5zdHJ1Y3QtYmV0YVwiXSA9IFwiZGF2aW5jaS1pbnN0cnVjdC1iZXRhXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJkYXZpbmNpLXNlYXJjaC1kb2N1bWVudFwiXSA9IFwiZGF2aW5jaS1zZWFyY2gtZG9jdW1lbnRcIjtcbiAgICBPcGVuQUlNb2RlbFtcImRhdmluY2ktc2VhcmNoLXF1ZXJ5XCJdID0gXCJkYXZpbmNpLXNlYXJjaC1xdWVyeVwiO1xuICAgIE9wZW5BSU1vZGVsW1wiZGF2aW5jaS1zaW1pbGFyaXR5XCJdID0gXCJkYXZpbmNpLXNpbWlsYXJpdHlcIjtcbiAgICBPcGVuQUlNb2RlbFtcImdwdC0zLjUtdHVyYm9cIl0gPSBcImdwdC0zLjUtdHVyYm9cIjtcbiAgICBPcGVuQUlNb2RlbFtcImdwdC0zLjUtdHVyYm8tMDMwMVwiXSA9IFwiZ3B0LTMuNS10dXJiby0wMzAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJncHQtMy41LXR1cmJvLTA2MTNcIl0gPSBcImdwdC0zLjUtdHVyYm8tMDYxM1wiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTMuNS10dXJiby0xMTA2XCJdID0gXCJncHQtMy41LXR1cmJvLTExMDZcIjtcbiAgICBPcGVuQUlNb2RlbFtcImdwdC0zLjUtdHVyYm8tMTZrXCJdID0gXCJncHQtMy41LXR1cmJvLTE2a1wiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTMuNS10dXJiby0xNmstMDYxM1wiXSA9IFwiZ3B0LTMuNS10dXJiby0xNmstMDYxM1wiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTMuNS10dXJiby1pbnN0cnVjdFwiXSA9IFwiZ3B0LTMuNS10dXJiby1pbnN0cnVjdFwiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTMuNS10dXJiby1pbnN0cnVjdC0wOTE0XCJdID0gXCJncHQtMy41LXR1cmJvLWluc3RydWN0LTA5MTRcIjtcbiAgICBPcGVuQUlNb2RlbFtcImdwdC00XCJdID0gXCJncHQtNFwiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTQtMDMxNFwiXSA9IFwiZ3B0LTQtMDMxNFwiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTQtMDYxM1wiXSA9IFwiZ3B0LTQtMDYxM1wiO1xuICAgIE9wZW5BSU1vZGVsW1wiZ3B0LTQtMTEwNi1wcmV2aWV3XCJdID0gXCJncHQtNC0xMTA2LXByZXZpZXdcIjtcbiAgICBPcGVuQUlNb2RlbFtcImdwdC00LXZpc2lvbi1wcmV2aWV3XCJdID0gXCJncHQtNC12aXNpb24tcHJldmlld1wiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1hZGEtMDAxXCJdID0gXCJ0ZXh0LWFkYS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtYmFiYmFnZS0wMDFcIl0gPSBcInRleHQtYmFiYmFnZS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtY3VyaWUtMDAxXCJdID0gXCJ0ZXh0LWN1cmllLTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1kYXZpbmNpLTAwMVwiXSA9IFwidGV4dC1kYXZpbmNpLTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1kYXZpbmNpLTAwMlwiXSA9IFwidGV4dC1kYXZpbmNpLTAwMlwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1kYXZpbmNpLTAwM1wiXSA9IFwidGV4dC1kYXZpbmNpLTAwM1wiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1kYXZpbmNpLWVkaXQtMDAxXCJdID0gXCJ0ZXh0LWRhdmluY2ktZWRpdC0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtZW1iZWRkaW5nLWFkYS0wMDJcIl0gPSBcInRleHQtZW1iZWRkaW5nLWFkYS0wMDJcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2VhcmNoLWFkYS1kb2MtMDAxXCJdID0gXCJ0ZXh0LXNlYXJjaC1hZGEtZG9jLTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1zZWFyY2gtYWRhLXF1ZXJ5LTAwMVwiXSA9IFwidGV4dC1zZWFyY2gtYWRhLXF1ZXJ5LTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1zZWFyY2gtYmFiYmFnZS1kb2MtMDAxXCJdID0gXCJ0ZXh0LXNlYXJjaC1iYWJiYWdlLWRvYy0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2VhcmNoLWJhYmJhZ2UtcXVlcnktMDAxXCJdID0gXCJ0ZXh0LXNlYXJjaC1iYWJiYWdlLXF1ZXJ5LTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1zZWFyY2gtY3VyaWUtZG9jLTAwMVwiXSA9IFwidGV4dC1zZWFyY2gtY3VyaWUtZG9jLTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1zZWFyY2gtY3VyaWUtcXVlcnktMDAxXCJdID0gXCJ0ZXh0LXNlYXJjaC1jdXJpZS1xdWVyeS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2VhcmNoLWRhdmluY2ktZG9jLTAwMVwiXSA9IFwidGV4dC1zZWFyY2gtZGF2aW5jaS1kb2MtMDAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJ0ZXh0LXNlYXJjaC1kYXZpbmNpLXF1ZXJ5LTAwMVwiXSA9IFwidGV4dC1zZWFyY2gtZGF2aW5jaS1xdWVyeS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2ltaWxhcml0eS1hZGEtMDAxXCJdID0gXCJ0ZXh0LXNpbWlsYXJpdHktYWRhLTAwMVwiO1xuICAgIE9wZW5BSU1vZGVsW1widGV4dC1zaW1pbGFyaXR5LWJhYmJhZ2UtMDAxXCJdID0gXCJ0ZXh0LXNpbWlsYXJpdHktYmFiYmFnZS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2ltaWxhcml0eS1jdXJpZS0wMDFcIl0gPSBcInRleHQtc2ltaWxhcml0eS1jdXJpZS0wMDFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInRleHQtc2ltaWxhcml0eS1kYXZpbmNpLTAwMVwiXSA9IFwidGV4dC1zaW1pbGFyaXR5LWRhdmluY2ktMDAxXCI7XG4gICAgT3BlbkFJTW9kZWxbXCJ0dHMtMVwiXSA9IFwidHRzLTFcIjtcbiAgICBPcGVuQUlNb2RlbFtcInR0cy0xLTExMDZcIl0gPSBcInR0cy0xLTExMDZcIjtcbiAgICBPcGVuQUlNb2RlbFtcInR0cy0xLWhkXCJdID0gXCJ0dHMtMS1oZFwiO1xuICAgIE9wZW5BSU1vZGVsW1widHRzLTEtaGQtMTEwNlwiXSA9IFwidHRzLTEtaGQtMTEwNlwiO1xuICAgIE9wZW5BSU1vZGVsW1wid2hpc3Blci0xXCJdID0gXCJ3aGlzcGVyLTFcIjtcbn0pKE9wZW5BSU1vZGVsIHx8IChPcGVuQUlNb2RlbCA9IHt9KSk7XG5jbGFzcyBBSUFzc2lzdGFudCB7XG4gICAgI2FwaUtleTtcbiAgICAjaWQ7XG4gICAgI25hbWU7XG4gICAgZ2V0IG5hbWUoKSB7IHJldHVybiB0aGlzLiNuYW1lOyB9XG4gICAgI2luc3RydWN0aW9ucztcbiAgICAjdG9vbHM7XG4gICAgI21vZGVsO1xuICAgICNmaWxlSURzO1xuICAgICNtZXRhZGF0YTtcbiAgICBjb25zdHJ1Y3RvcihuYW1lT3JJRCwgaW5zdHJ1Y3Rpb25zLCBtb2RlbCA9IE9wZW5BSU1vZGVsW1wiZ3B0LTQtMTEwNi1wcmV2aWV3XCJdLCB7IGlzVXNpbmdSZXRyaWV2YWwsIGZ1bmN0aW9uVG9vbHMsIGZpbGVfaWRzLCBtZXRhZGF0YSB9ID0ge30pIHtcbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBwcml2YXRlIHByb3BlcnRpZXMgc28gVHlwZVNjcmlwdCBkb2Vzbid0IHllbGwgYXQgbWUuXG4gICAgICAgIHRoaXMuI2lkID0gXCJcIjtcbiAgICAgICAgdGhpcy4jbmFtZSA9IFwiXCI7XG4gICAgICAgIHRoaXMuI2luc3RydWN0aW9ucyA9IGluc3RydWN0aW9ucyA/PyBcIlwiO1xuICAgICAgICB0aGlzLiN0b29scyA9IFtdO1xuICAgICAgICB0aGlzLiNtb2RlbCA9IG1vZGVsO1xuICAgICAgICB0aGlzLiNmaWxlSURzID0gZmlsZV9pZHMgPz8gW107XG4gICAgICAgIHRoaXMuI21ldGFkYXRhID0gbWV0YWRhdGEgPz8ge307XG4gICAgICAgIC8vIFJldHJpZXZlIEFQSSBrZXlcbiAgICAgICAgY29uc3QgYXBpS2V5ID0gVS5nZXRTZXR0aW5nKFwib3BlbkFQSUtleVwiKTtcbiAgICAgICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIkFQSSBLZXkgcmVxdWlyZWQgaW4gU2V0dGluZ3MgdG8gdXNlIEFJIGZlYXR1cmVzLlwiKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLiNhcGlLZXkgPSBhcGlLZXk7XG4gICAgICAgIC8vIElmIGluc3RydWN0aW9ucyBzZW50LCB3ZSdyZSBjcmVhdGluZyBhIG5ldyBBc3Npc3RhbnQuXG4gICAgICAgIGlmIChpbnN0cnVjdGlvbnMpIHtcbiAgICAgICAgICAgIHRoaXMuI25hbWUgPSBuYW1lT3JJRDtcbiAgICAgICAgICAgIGlmIChpc1VzaW5nUmV0cmlldmFsKSB7XG4gICAgICAgICAgICAgICAgdGhpcy4jdG9vbHMucHVzaCh7IHR5cGU6IFwicmV0cmlldmFsXCIgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZnVuY3Rpb25Ub29scyAmJiBmdW5jdGlvblRvb2xzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHRoaXMuI3Rvb2xzLnB1c2goLi4uZnVuY3Rpb25Ub29scyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmNyZWF0ZUFzc2lzdGFudCgpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gT3RoZXJ3aXNlLCBhc3N1bWUgYW4gSUQgd2FzIHBhc3NlZCwgYW5kIGZldGNoIHRoZSBleGlzdGluZyBhc3Npc3RhbnQuXG4gICAgICAgICAgICB0aGlzLiNpZCA9IG5hbWVPcklEO1xuICAgICAgICAgICAgdGhpcy5yZXRyaWV2ZUFzc2lzdGFudCgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIGNyZWF0ZUFzc2lzdGFudCgpIHtcbiAgICAgICAgLy8gY3VybCBodHRwczovL2FwaS5vcGVuYWkuY29tL3YxL2Fzc2lzdGFudHMgXFxcbiAgICAgICAgLy8gLUggXCJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb25cIiBcXFxuICAgICAgICAvLyAtSCBcIkF1dGhvcml6YXRpb246IEJlYXJlciAkT1BFTkFJX0FQSV9LRVlcIiBcXFxuICAgICAgICAvLyAtSCBcIk9wZW5BSS1CZXRhOiBhc3Npc3RhbnRzPXYxXCIgXFxcbiAgICAgICAgLy8gLWQgJ3tcbiAgICAgICAgLy8gICBcImluc3RydWN0aW9uc1wiOiBcIllvdSBhcmUgYW4gSFIgYm90LCBhbmQgeW91IGhhdmUgYWNjZXNzIHRvIGZpbGVzIHRvIGFuc3dlciBlbXBsb3llZSBxdWVzdGlvbnMgYWJvdXQgY29tcGFueSBwb2xpY2llcy5cIixcbiAgICAgICAgLy8gICBcInRvb2xzXCI6IFt7XCJ0eXBlXCI6IFwicmV0cmlldmFsXCJ9XSxcbiAgICAgICAgLy8gICBcIm1vZGVsXCI6IFwiZ3B0LTRcIixcbiAgICAgICAgLy8gICBcImZpbGVfaWRzXCI6IFtcImZpbGUtYWJjMTIzXCJdXG4gICAgICAgIC8vIH0nXG4gICAgICAgIGNvbnN0IGZldGNoUmVxdWVzdCA9IHtcbiAgICAgICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3RoaXMuI2FwaUtleX1gLFxuICAgICAgICAgICAgICAgIFwiT3BlbkFJLUJldGFcIjogXCJhc3Npc3RhbnRzPXYxXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgbmFtZTogdGhpcy4jbmFtZSxcbiAgICAgICAgICAgICAgICBpbnN0cnVjdGlvbnM6IHRoaXMuI2luc3RydWN0aW9ucyxcbiAgICAgICAgICAgICAgICB0b29sczogdGhpcy4jdG9vbHMsXG4gICAgICAgICAgICAgICAgbW9kZWw6IHRoaXMuI21vZGVsLFxuICAgICAgICAgICAgICAgIGZpbGVfaWRzOiB0aGlzLiNmaWxlSURzXG4gICAgICAgICAgICB9KVxuICAgICAgICB9O1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcIkJsYWRlc0Fzc2lzdGFudFwiLCBcIkZldGNoIFJlcXVlc3RcIiwgZmV0Y2hSZXF1ZXN0KTtcbiAgICAgICAgLy8gU2VuZCBhIFBPU1QgcmVxdWVzdCB0byB0aGUgT3BlbkFJIEFQSVxuICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKFwiaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MS9hc3Npc3RhbnRzXCIsIGZldGNoUmVxdWVzdCk7XG4gICAgICAgIC8vIENoZWNrIGlmIHRoZSByZXNwb25zZSBzdGF0dXMgaXMgbm90IDIwMCAoT0spXG4gICAgICAgIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiRmFpbGVkIEFJIFJlcXVlc3Q6XCIsIEpTT04ucGFyc2UoZmV0Y2hSZXF1ZXN0LmJvZHkpKTtcbiAgICAgICAgICAgIC8vIFRocm93IGFuIGVycm9yIHdpdGggdGhlIHN0YXR1cyBjb2RlXG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYE9wZW5BSSBBUEkgcmVxdWVzdCBmYWlsZWQgd2l0aCBzdGF0dXMgJHtyZXNwb25zZS5zdGF0dXN9YCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gUGFyc2UgdGhlIHJlc3BvbnNlIGJvZHkgYXMgSlNPTlxuICAgICAgICBjb25zdCBkYXRhID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICAgICAgICBmZXRjaFJlcXVlc3QuYm9keSA9IEpTT04ucGFyc2UoZmV0Y2hSZXF1ZXN0LmJvZHkpO1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcIkJsYWRlc0FJXCIsIFwiQUkgUXVlcnlcIiwgeyBwcm9tcHQ6IGZldGNoUmVxdWVzdCwgcmVzcG9uc2U6IGRhdGEgfSk7XG4gICAgICAgIHRoaXMuI2lkID0gZGF0YS5pZDtcbiAgICB9XG4gICAgYXN5bmMgcmV0cmlldmVBc3Npc3RhbnQoKSB7XG4gICAgICAgIC8vICAgY3VybCBodHRwczovL2FwaS5vcGVuYWkuY29tL3YxL2Fzc2lzdGFudHMvYXNzdF9hYmMxMjMgXFxcbiAgICAgICAgLy8gLUggXCJDb250ZW50LVR5cGU6IGFwcGxpY2F0aW9uL2pzb25cIiBcXFxuICAgICAgICAvLyAtSCBcIkF1dGhvcml6YXRpb246IEJlYXJlciAkT1BFTkFJX0FQSV9LRVlcIiBcXFxuICAgICAgICAvLyAtSCBcIk9wZW5BSS1CZXRhOiBhc3Npc3RhbnRzPXYxXCJcbiAgICAgICAgY29uc3QgZmV0Y2hSZXF1ZXN0ID0ge1xuICAgICAgICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIFwiQ29udGVudC1UeXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHt0aGlzLiNhcGlLZXl9YCxcbiAgICAgICAgICAgICAgICBcIk9wZW5BSS1CZXRhXCI6IFwiYXNzaXN0YW50cz12MVwiXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIC8vIFNlbmQgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIE9wZW5BSSBBUElcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgaHR0cHM6Ly9hcGkub3BlbmFpLmNvbS92MS9hc3Npc3RhbnRzLyR7dGhpcy4jaWR9YCwgZmV0Y2hSZXF1ZXN0KTtcbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHJlc3BvbnNlIHN0YXR1cyBpcyBub3QgMjAwIChPSylcbiAgICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igd2l0aCB0aGUgc3RhdHVzIGNvZGVcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgT3BlbkFJIEFQSSByZXF1ZXN0IGZhaWxlZCB3aXRoIHN0YXR1cyAke3Jlc3BvbnNlLnN0YXR1c31gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBQYXJzZSB0aGUgcmVzcG9uc2UgYm9keSBhcyBKU09OXG4gICAgICAgIGNvbnN0IGRhdGEgPSBhd2FpdCByZXNwb25zZS5qc29uKCk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwiQmxhZGVzQUlcIiwgXCJBSSBRdWVyeVwiLCB7IHByb21wdDogZmV0Y2hSZXF1ZXN0LCByZXNwb25zZTogZGF0YSB9KTtcbiAgICAgICAgdGhpcy4jbmFtZSA9IGRhdGEubmFtZTtcbiAgICAgICAgdGhpcy4jaW5zdHJ1Y3Rpb25zID0gZGF0YS5pbnN0cnVjdGlvbnM7XG4gICAgICAgIHRoaXMuI3Rvb2xzID0gZGF0YS50b29scztcbiAgICAgICAgdGhpcy4jbW9kZWwgPSBkYXRhLm1vZGVsO1xuICAgICAgICB0aGlzLiNmaWxlSURzID0gZGF0YS5maWxlX2lkcztcbiAgICAgICAgdGhpcy4jbWV0YWRhdGEgPSBkYXRhLm1ldGFkYXRhO1xuICAgIH1cbn1cbi8qKlxuICogQUkgY2xhc3MgZm9yIHF1ZXJ5aW5nIE9wZW5BSSBBUElcbiAqL1xuY2xhc3MgQmxhZGVzQUkge1xuICAgIHN0YXRpYyBhc3luYyBHZXRNb2RlbHMoaXNWZXJib3NlID0gZmFsc2UpIHtcbiAgICAgICAgY29uc3QgYXBpS2V5ID0gVS5nZXRTZXR0aW5nKFwib3BlbkFQSUtleVwiKTtcbiAgICAgICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIllvdSBtdXN0IGNvbmZpZ3VyZSB5b3VyIE9wZW5BSSBBUEkgS2V5IGluIFNldHRpbmdzIHRvIHVzZSBBSSBmZWF0dXJlcy5cIik7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZmV0Y2hSZXF1ZXN0ID0ge1xuICAgICAgICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAgIEF1dGhvcml6YXRpb246IGBCZWFyZXIgJHthcGlLZXl9YFxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICAvLyBTZW5kIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBPcGVuQUkgQVBJXG4gICAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goXCJodHRwczovL2FwaS5vcGVuYWkuY29tL3YxL21vZGVsc1wiLCBmZXRjaFJlcXVlc3QpO1xuICAgICAgICAvLyBDaGVjayBpZiB0aGUgcmVzcG9uc2Ugc3RhdHVzIGlzIG5vdCAyMDAgKE9LKVxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvciB3aXRoIHRoZSBzdGF0dXMgY29kZVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBPcGVuQUkgQVBJIHJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFBhcnNlIHRoZSByZXNwb25zZSBib2R5IGFzIEpTT05cbiAgICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgLy8gY29uc3QgbW9kZWxLZXlzID0gZGF0YS5tYXAoKHtpZH06IHtpZDogc3RyaW5nfSkgPT4gaWQpO1xuICAgICAgICAvLyBjb25zdCBtb2RlbERhdGEgPSBkYXRhLm1hcCgoe2lkOiBfaWQsIC4uLm1EYXRhfTogUmVjb3JkPHN0cmluZywgc3RyaW5nPikgPT4gbURhdGEpO1xuICAgICAgICBjb25zdCBkYXRhTGlzdCA9IE9iamVjdC5mcm9tRW50cmllcyhkYXRhLm1hcCgoeyBpZCwgLi4ubURhdGEgfSkgPT4gW2lkLCBtRGF0YV0pKTtcbiAgICAgICAgaWYgKGlzVmVyYm9zZSkge1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJCbGFkZXNBSVwiLCBcIkF2YWlsYWJsZSBNb2RlbHNcIiwgeyBkYXRhTGlzdCB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhcGlLZXk7XG4gICAgbW9kZWw7XG4gICAgdGVtcGVyYXR1cmUgPSAwLjU7XG4gICAgZnJlcXVlbmN5X3BlbmFsdHkgPSAwLjg7XG4gICAgcHJlc2VuY2VfcGVuYWx0eSA9IDAuODtcbiAgICBzeXN0ZW1NZXNzYWdlO1xuICAgIGV4YW1wbGVQcm9tcHRzO1xuICAgIC8qKlxuICAgICAqIEFJIGNsYXNzIGNvbnN0cnVjdG9yXG4gICAgICogQHBhcmFtIHtCbGFkZXNBSS5Db25maWd9IFtjb25maWddIENvbmZpZ3VyYXRpb24gc2V0dGluZ3MgZm9yIHRoZSBBUElcbiAgICAgKi9cbiAgICBjb25zdHJ1Y3Rvcihjb25maWcpIHtcbiAgICAgICAgY29uc3QgYXBpS2V5ID0gVS5nZXRTZXR0aW5nKFwib3BlbkFQSUtleVwiKTtcbiAgICAgICAgaWYgKCFhcGlLZXkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIllvdSBtdXN0IGNvbmZpZ3VyZSB5b3VyIE9wZW5BSSBBUEkgS2V5IGluIFNldHRpbmdzIHRvIHVzZSBBSSBmZWF0dXJlcy5cIik7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5tb2RlbCA9IFUuZ2V0U2V0dGluZyhcIm9wZW5BUElNb2RlbExldmVsXCIpO1xuICAgICAgICBpZiAodHlwZW9mIHRoaXMubW9kZWwgIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgIGVMb2cuZXJyb3IoXCJCbGFkZXNBSVwiLCBcIlNldCBiYXNlIEFJIHF1YWxpdHkgaW4gc2V0dGluZ3MuIERlZmF1bHRpbmcgdG8gbG93ZXN0LlwiKTtcbiAgICAgICAgICAgIHRoaXMubW9kZWwgPSAwO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYXBpS2V5ID0gYXBpS2V5O1xuICAgICAgICB0aGlzLnN5c3RlbU1lc3NhZ2UgPSBjb25maWcuc3lzdGVtTWVzc2FnZTtcbiAgICAgICAgdGhpcy5leGFtcGxlUHJvbXB0cyA9IGNvbmZpZy5leGFtcGxlUHJvbXB0cztcbiAgICAgICAgdGhpcy50ZW1wZXJhdHVyZSA9IGNvbmZpZy50ZW1wZXJhdHVyZSA/PyB0aGlzLnRlbXBlcmF0dXJlO1xuICAgICAgICB0aGlzLmZyZXF1ZW5jeV9wZW5hbHR5ID0gY29uZmlnLmZyZXF1ZW5jeV9wZW5hbHR5ID8/IHRoaXMuZnJlcXVlbmN5X3BlbmFsdHk7XG4gICAgICAgIHRoaXMucHJlc2VuY2VfcGVuYWx0eSA9IGNvbmZpZy5wcmVzZW5jZV9wZW5hbHR5ID8/IHRoaXMucHJlc2VuY2VfcGVuYWx0eTtcbiAgICB9XG4gICAgX2luaXRpYWxNZXNzYWdlcyA9IFtdO1xuICAgIGdldCBpbml0aWFsTWVzc2FnZXMoKSB7XG4gICAgICAgIGlmICh0aGlzLl9pbml0aWFsTWVzc2FnZXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICB0aGlzLl9pbml0aWFsTWVzc2FnZXMucHVzaCh7XG4gICAgICAgICAgICAgICAgcm9sZTogXCJzeXN0ZW1cIixcbiAgICAgICAgICAgICAgICBjb250ZW50OiB0aGlzLnN5c3RlbU1lc3NhZ2VcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgZm9yIChjb25zdCB7IGh1bWFuLCBhaSB9IG9mIHRoaXMuZXhhbXBsZVByb21wdHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9pbml0aWFsTWVzc2FnZXMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIHJvbGU6IFwidXNlclwiLFxuICAgICAgICAgICAgICAgICAgICBjb250ZW50OiBodW1hblxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2luaXRpYWxNZXNzYWdlcy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgcm9sZTogXCJhc3Npc3RhbnRcIixcbiAgICAgICAgICAgICAgICAgICAgY29udGVudDogYWlcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5faW5pdGlhbE1lc3NhZ2VzO1xuICAgIH1cbiAgICBwcm9tcHRzID0ge307XG4gICAgcmVzcG9uc2VzID0ge307XG4gICAgZ2V0UmVzcG9uc2UocXVlcnlJRCkge1xuICAgICAgICByZXR1cm4gdGhpcy5yZXNwb25zZXNbcXVlcnlJRF0gPz8gbnVsbDtcbiAgICB9XG4gICAgaGFzUXVlcmllZChxdWVyeUlEKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnByb21wdHNbcXVlcnlJRF0gIT09IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgLyoqXG4gICAgICogUXVlcnkgT3BlbkFJIEFQSVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBxdWVyeUlEIEEgbGFiZWwgZm9yIGxhdGVyIHJldHJpZXZhbCBvZiB0aGUgcXVlcnkgZGF0YVxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBwcm9tcHQgVGhlIHByb21wdCB0byBzZW5kIHRvIHRoZSBBUElcbiAgICAgKiBAcGFyYW0ge251bWJlcn0gW21vZGVsTW9kXSBPcHRpb25hbCBtb2RpZmllciB0byB0aGUgYmFzZSBtb2RlbCBsZXZlbC5cbiAgICAgKiAgICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBwcm92aWRlZCwgdGhlIGZpbmFsIG1vZGVsIHF1YWxpdHkgd2lsbCBiZSBhZGp1c3RlZCBieSB0aGlzIG51bWJlci5cbiAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtleHRlbmRlZENvbnRleHQ9ZmFsc2VdIE9wdGlvbmFsIGZsYWcgdG8gaW5kaWNhdGUgd2hldGhlciB0byB1c2UgZXh0ZW5kZWQgY29udGV4dCBtb2RlbHMuXG4gICAgICogICAgICAgICAgICAgICAgICAgICAgICAgICAgSWYgdHJ1ZSwgZXh0ZW5kZWQgY29udGV4dCBtb2RlbHMgYXJlIHVzZWQ7IG90aGVyd2lzZSwgYmFzZSBjb250ZXh0IG1vZGVscyBhcmUgdXNlZC5cbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxSZXNwb25zZT59IFRoZSBBUEkgcmVzcG9uc2VcbiAgICAgKi9cbiAgICBhc3luYyBxdWVyeShxdWVyeUlELCBwcm9tcHQsIG1vZGVsTW9kLCBleHRlbmRlZENvbnRleHQgPSBmYWxzZSkge1xuICAgICAgICBpZiAoIXByb21wdCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVzcG9uc2VzW3F1ZXJ5SURdID0gbnVsbDtcbiAgICAgICAgY29uc3QgbW9kZWxOdW0gPSB0eXBlb2YgbW9kZWxNb2QgPT09IFwibnVtYmVyXCJcbiAgICAgICAgICAgID8gVS5jbGFtcE51bSh0aGlzLm1vZGVsICsgbW9kZWxNb2QsIFswLCAyXSlcbiAgICAgICAgICAgIDogdGhpcy5tb2RlbDtcbiAgICAgICAgY29uc3QgbW9kZWwgPSBleHRlbmRlZENvbnRleHRcbiAgICAgICAgICAgID8gQy5BSV9NT0RFTFMuZXh0ZW5kZWRDb250ZXh0W21vZGVsTnVtXVxuICAgICAgICAgICAgOiBDLkFJX01PREVMUy5iYXNlQ29udGV4dFttb2RlbE51bV07XG4gICAgICAgIGNvbnN0IGZldGNoUmVxdWVzdCA9IHtcbiAgICAgICAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgICAgICAgXCJDb250ZW50LVR5cGVcIjogXCJhcHBsaWNhdGlvbi9qc29uXCIsXG4gICAgICAgICAgICAgICAgQXV0aG9yaXphdGlvbjogYEJlYXJlciAke3RoaXMuYXBpS2V5fWBcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBib2R5OiBKU09OLnN0cmluZ2lmeSh7XG4gICAgICAgICAgICAgICAgbW9kZWwsXG4gICAgICAgICAgICAgICAgdGVtcGVyYXR1cmU6IHRoaXMudGVtcGVyYXR1cmUsXG4gICAgICAgICAgICAgICAgZnJlcXVlbmN5X3BlbmFsdHk6IHRoaXMuZnJlcXVlbmN5X3BlbmFsdHksXG4gICAgICAgICAgICAgICAgcHJlc2VuY2VfcGVuYWx0eTogdGhpcy5wcmVzZW5jZV9wZW5hbHR5LFxuICAgICAgICAgICAgICAgIG1lc3NhZ2VzOiBbXG4gICAgICAgICAgICAgICAgICAgIC4uLnRoaXMuaW5pdGlhbE1lc3NhZ2VzLFxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICByb2xlOiBcInVzZXJcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHByb21wdFxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSlcbiAgICAgICAgfTtcbiAgICAgICAgLy8gRWVMb2cuY2hlY2tMb2czKFwiQmxhZGVzQUlcIiwgXCJGZXRjaCBSZXF1ZXN0XCIsIGZldGNoUmVxdWVzdCk7XG4gICAgICAgIC8vIFNlbmQgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIE9wZW5BSSBBUElcbiAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChcImh0dHBzOi8vYXBpLm9wZW5haS5jb20vdjEvY2hhdC9jb21wbGV0aW9uc1wiLCBmZXRjaFJlcXVlc3QpO1xuICAgICAgICAvLyB7XG4gICAgICAgIC8vICAgbWV0aG9kOiBcIlBPU1RcIixcbiAgICAgICAgLy8gICBoZWFkZXJzOiB7XG4gICAgICAgIC8vICAgICAvLyBUaGUgY29udGVudCB0eXBlIG9mIHRoZSByZXF1ZXN0XG4gICAgICAgIC8vICAgICBcIkNvbnRlbnQtVHlwZVwiOiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgICAgICAgLy8gICAgIC8vIFRoZSBhdXRob3JpemF0aW9uIGhlYWRlciB3aXRoIHRoZSBBUEkga2V5XG4gICAgICAgIC8vICAgICBBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7dGhpcy5hcGlLZXl9YFxuICAgICAgICAvLyAgIH0sXG4gICAgICAgIC8vICAgYm9keTogSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAvLyAgICAgbW9kZWwsXG4gICAgICAgIC8vICAgICBtZXNzYWdlczogW1xuICAgICAgICAvLyAgICAgICAuLi50aGlzLmluaXRpYWxNZXNzYWdlcyxcbiAgICAgICAgLy8gICAgICAge1xuICAgICAgICAvLyAgICAgICAgIHJvbGU6IFwidXNlclwiLFxuICAgICAgICAvLyAgICAgICAgIGNvbnRlbnQ6IHByb21wdFxuICAgICAgICAvLyAgICAgICB9XG4gICAgICAgIC8vICAgICBdLFxuICAgICAgICAvLyAgICAgLy8gTWF4aW11bSBudW1iZXIgb2YgdG9rZW5zIGluIHRoZSBvdXRwdXQuIE1pbjogMSwgTWF4OiA0MDk2XG4gICAgICAgIC8vICAgICAvLyBtYXhfdG9rZW5zOiA2MCxcbiAgICAgICAgLy8gICAgIC8vIENvbnRyb2xzIHJhbmRvbW5lc3MuIEhpZ2hlciB2YWx1ZXMgbWVhbiB0aGUgbW9kZWwgd2lsbCB0YWtlIG1vcmUgcmlza3MuXG4gICAgICAgIC8vICAgICB0ZW1wZXJhdHVyZTogMC41LCAvLyAwIHRvIDIuMFxuICAgICAgICAvLyAgICAgLyogVGhlICd0b3BfcCcgcGFyYW1ldGVyIGlzIGFuIGFsdGVybmF0aXZlIHRvICd0ZW1wZXJhdHVyZScgZm9yIGNvbnRyb2xsaW5nIHRoZSByYW5kb21uZXNzIG9mXG4gICAgICAgIC8vICAgICAgIHRoZSBBSSdzIHJlc3BvbnNlcy4gSXQgcmVwcmVzZW50cyB0aGUgY3VtdWxhdGl2ZSBwcm9iYWJpbGl0eSBhbmQgaXRzIHZhbHVlIHJhbmdlcyBmcm9tIDAgdG8gMS5cbiAgICAgICAgLy8gICAgICAgQSBsb3dlciB2YWx1ZSBtYWtlcyB0aGUgQUkncyByZXNwb25zZXMgbW9yZSBkZXRlcm1pbmlzdGljLCB3aGlsZSBhIGhpZ2hlciB2YWx1ZSBtYWtlcyB0aGVtXG4gICAgICAgIC8vICAgICAgIG1vcmUgZGl2ZXJzZSBhbmQgdW5wcmVkaWN0YWJsZS4gKi9cbiAgICAgICAgLy8gICAgIC8vIHRvcF9wOiAxLCAvLyAwIHRvIDFcbiAgICAgICAgLy8gICAgIC8qIFRoZSAnZnJlcXVlbmN5X3BlbmFsdHknIHBhcmFtZXRlciBpcyB1c2VkIHRvIHBlbmFsaXplIG5ldyB0b2tlbnMgYmFzZWQgb24gdGhlaXIgZnJlcXVlbmN5IGluXG4gICAgICAgIC8vICAgICAgIHRoZSB0cmFpbmluZyBzZXQuIEl0cyB2YWx1ZSByYW5nZXMgZnJvbSAwIHRvIDEuIEEgaGlnaGVyIHZhbHVlIG1lYW5zIHRoZSBBSSBpcyBsZXNzIGxpa2VseSB0b1xuICAgICAgICAvLyAgICAgICB1c2UgY29tbW9uIHBocmFzZXMgZnJvbSBpdHMgdHJhaW5pbmcgc2V0LCBsZWFkaW5nIHRvIG1vcmUgdW5pcXVlIHJlc3BvbnNlcy4gQSBsb3dlciB2YWx1ZVxuICAgICAgICAvLyAgICAgICBtZWFucyB0aGUgQUkgaXMgbW9yZSBsaWtlbHkgdG8gdXNlIGNvbW1vbiBwaHJhc2VzLCBsZWFkaW5nIHRvIG1vcmUgcHJlZGljdGFibGUgcmVzcG9uc2VzLiAqL1xuICAgICAgICAvLyAgICAgZnJlcXVlbmN5X3BlbmFsdHk6IDAuOCwgLy8gLTIuMCB0byAyLjBcbiAgICAgICAgLy8gICAgIC8qIFRoZSAncHJlc2VuY2VfcGVuYWx0eScgcGFyYW1ldGVyIGlzIHVzZWQgdG8gcGVuYWxpemUgdG9rZW5zICh3b3JkcyBvciBwaHJhc2VzKSB0aGF0IGFyZSBvdXRcbiAgICAgICAgLy8gICAgICAgb2YgY29udGV4dC4gSXRzIHZhbHVlIHJhbmdlcyBmcm9tIDAgdG8gMS4gQSBoaWdoZXIgdmFsdWUgbWVhbnMgdGhlIEFJIGlzIGxlc3MgbGlrZWx5IHRvXG4gICAgICAgIC8vICAgICAgIGluY2x1ZGUgb3V0LW9mLWNvbnRleHQgdG9rZW5zIGluIGl0cyByZXNwb25zZXMsIGxlYWRpbmcgdG8gbW9yZSBjb2hlcmVudCBhbmQgY29udGV4dHVhbGx5XG4gICAgICAgIC8vICAgICAgIGFwcHJvcHJpYXRlIHJlc3BvbnNlcy4gQSBsb3dlciB2YWx1ZSBtZWFucyB0aGUgQUkgaXMgbW9yZSBsaWtlbHkgdG8gaW5jbHVkZSBvdXQtb2YtY29udGV4dFxuICAgICAgICAvLyAgICAgICB0b2tlbnMsIHdoaWNoIGNhbiBsZWFkIHRvIG1vcmUgY3JlYXRpdmUgYnV0IHBvdGVudGlhbGx5IGxlc3MgY29oZXJlbnQgcmVzcG9uc2VzLiAqL1xuICAgICAgICAvLyAgICAgcHJlc2VuY2VfcGVuYWx0eTogMC44IC8vIC0yLjAgdG8gMi4wXG4gICAgICAgIC8vICAgfSlcbiAgICAgICAgLy8gfVxuICAgICAgICAvLyApO1xuICAgICAgICAvLyBDaGVjayBpZiB0aGUgcmVzcG9uc2Ugc3RhdHVzIGlzIG5vdCAyMDAgKE9LKVxuICAgICAgICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIkZhaWxlZCBBSSBSZXF1ZXN0OlwiLCBKU09OLnBhcnNlKGZldGNoUmVxdWVzdC5ib2R5KSk7XG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvciB3aXRoIHRoZSBzdGF0dXMgY29kZVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBPcGVuQUkgQVBJIHJlcXVlc3QgZmFpbGVkIHdpdGggc3RhdHVzICR7cmVzcG9uc2Uuc3RhdHVzfWApO1xuICAgICAgICB9XG4gICAgICAgIC8vIFBhcnNlIHRoZSByZXNwb25zZSBib2R5IGFzIEpTT05cbiAgICAgICAgY29uc3QgZGF0YSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgICAgICAgZmV0Y2hSZXF1ZXN0LmJvZHkgPSBKU09OLnBhcnNlKGZldGNoUmVxdWVzdC5ib2R5KTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJCbGFkZXNBSVwiLCBcIkFJIFF1ZXJ5XCIsIHsgcHJvbXB0OiBmZXRjaFJlcXVlc3QsIHJlc3BvbnNlOiBkYXRhIH0pO1xuICAgICAgICB0aGlzLnJlc3BvbnNlc1txdWVyeUlEXSA9IGRhdGEuY2hvaWNlc1swXS5tZXNzYWdlLmNvbnRlbnQ7XG4gICAgICAgIHJldHVybiB0aGlzLnJlc3BvbnNlc1txdWVyeUlEXTtcbiAgICB9XG59XG5leHBvcnQgY29uc3QgQUdFTlRTID0ge1xuICAgIEdlbmVyYWxDb250ZW50R2VuZXJhdG9yOiB7XG4gICAgICAgIHN5c3RlbU1lc3NhZ2U6IFwiWW91IHdpbGwgYWN0IGFzIGEgY3JlYXRpdmUgY29udGVudCBnZW5lcmF0b3IgZm9yIGEgZ2FtZSBvZiBCbGFkZXMgSW4gVGhlIERhcmsgc2V0IGluIHRoZSBjaXR5IG9mIER1c2t2b2wuIFlvdSB3aWxsIGJlIHByb21wdGVkIHdpdGggc29tZSBlbGVtZW50IG9mIHRoZSBnYW1lIHdvcmxkIChhIGxvY2F0aW9uLCBhIGNoYXJhY3RlciwgYW4gZXZlbnQsIGEgZmFjdGlvbiwgYSBkaWxlbW1hKSBpbiB0aGUgZm9ybSBvZiBhIEpTT04gb2JqZWN0LiBZb3VyIGpvYiBpcyB0byBhbmFseXplIHRoZSBKU09OIG9iamVjdCBhbmQgcmVwbGFjZSBhbnkgdmFsdWVzIHRoYXQgZXF1YWwgXFxcIjxHRU4+XFxcIiB3aXRoIG9yaWdpbmFsIGNvbnRlbnQgb2YgeW91ciBvd24gY3JlYXRpb24uIE9yaWdpbmFsIGNvbnRlbnQgbXVzdCBtZWV0IHRoZXNlIHJlcXVpcmVtZW50czogIChBKSBpdCBzaG91bGQgYWxpZ24gd2l0aCBhbmQgYmUgY29uc2lzdGVudCB3aXRoIHRoZSBwcm92aWRlZCBjb250ZXh0dWFsIGluZm9ybWF0aW9uLCBhcyB3ZWxsIGFzIHlvdXIgYnJvYWRlciB1bmRlcnN0YW5kaW5nIG9mIHRoZSBnYW1lJ3MgdGhlbWVzLiAoQikgSXQgc2hvdWxkIGJlIHByZXNlbnRlZCBpbiBhIGZvcm1hdCB0aGF0IG1hdGNoZXMgKGluIGxlbmd0aCBhbmQgaW4gc3R5bGUpIG90aGVyIGVudHJpZXMgZm9yIHRoYXQgcGFydGljdWxhciB2YWx1ZSwgZXhhbXBsZXMgb2Ygd2hpY2ggd2lsbCBhbHNvIGJlIHByb3ZpZGVkLiAoQykgSXQgc2hvdWxkIGJlIGNyZWF0aXZlLCBpbnRlcmVzdGluZywgYW5kIGRhcmluZzogQmUgYm9sZCB3aXRoIHlvdXIgY3JlYXRpdml0eS4gU3BlY2lmaWMgY29udGV4dCBmb3IgdGhpcyBwcm9tcHQgaXMgYXMgZm9sbG93czpcIixcbiAgICAgICAgZXhhbXBsZVByb21wdHM6IFtdXG4gICAgfSxcbiAgICBOUENHZW5lcmF0b3I6IHtcbiAgICAgICAgc3lzdGVtTWVzc2FnZTogXCJZb3Ugd2lsbCBwbGF5IHRoZSByb2xlIG9mIGEgXFxcImNyZWF0aXZlIGNvbnRlbnQgZ2VuZXJhdG9yXFxcIiBmb3IgcmFuZG9tIE5QQ3MgZ2VuZXJhdGVkIGZvciB0aGUgQmxhZGVzIEluIFRoZSBEYXJrIHJvbGVwbGF5aW5nIHN5c3RlbS4gV2hlbiBwcm9tcHRlZCB3aXRoIGEgZGVzY3JpcHRpb24gb2YgYSBzdWJqZWN0IChhbiBOUEMsIGEgY2F0ZWdvcnkgb2YgTlBDcywgYSBmYWN0aW9uLCBvciBhIGdyb3VwIG9mIE5QQ3MpLCB5b3Ugd2lsbCByZXNwb25kIHdpdGggYSBwaXBlLWRlbGltaXRlZCBsaXN0IG9mIHNpeHRlZW4gaXRlbXMsIGRpdmlkZWQgaW50byBmb3VyIGNhdGVnb3JpZXMsIHByZWZhY2luZyBlYWNoIGNhdGVnb3J5IHdpdGggdGhlIGFzc29jaWF0ZWQgaGVhZGVyIGluIHNxdWFyZSBicmFja2V0czogWzUgS0VZV09SRFNdIEZpdmUgb25lLXdvcmQga2V5d29yZHMgZGVzY3JpYmluZyB0aGUgc3ViamVjdC4gWzUgUEhSQVNFU10gRml2ZSBldm9jYXRpdmUgcGhyYXNlcyB0aGF0IGNvdWxkIGJlIHVzZWQgYnkgYSBHTSBkaXJlY3RseSB3aGVuIG5hcnJhdGluZyB0aGUgc3ViamVjdCBkdXJpbmcgcGxheS4gVGhlc2Ugc2hvdWxkIGJlIGV4dHJlbWVseSB3ZWxsLXdvcmRlZCwgdmVyeSBvcmlnaW5hbCwgYW5kIHBhY2tlZCB3aXRoIGRyYW1hIGFuZCBldm9jYXRpdmUgaW1hZ2VyeS4gQmUgYm9sZCB3aXRoIHlvdXIgcmVzcG9uc2VzIGhlcmUuIFszIFFVSVJLUy9NT1RJRkZTXSBUaHJlZSBwaHJhc2VzIGRlc2NyaWJpbmcgcG90ZW50aWFsIHF1aXJrcyBvciBtb3RpZmZzIHRoYXQgYSBHTSBjb3VsZCBlbXBsb3kgaW4gYSBzY2VuZSBpbnZvbHZpbmcgdGhlIHN1YmplY3QuIFszIFBMT1QgSE9PS1NdIFRocmVlIHBsb3QgaG9va3MgdGhhdCBjb3VsZCBkaXJlY3RseSBhbmQgc3BlY2lmaWNhbGx5IGludm9sdmUgb25lIG9yIG1vcmUgb2YgdGhlIFBDcy4gVGhlIFBDcyBhcmU6ICgxKSBBbGlzdGFpciwgZnVsbCBuYW1lIExvcmQgQWxpc3RhaXIgQnJhbSBDaGVzdGVyZmllbGQsIHRoZSBjcmV3J3MgYm9zcywgYSBTcGlkZXIgd2l0aCBjb25uZWN0aW9ucyBhbW9uZyB0aGUgbm9iaWxpdHk7ICgyKSBIaWdoLUZseWVyLCBhIGZvcm1lciBub2JsZSBoaW1zZWxmLCBub3cgc2VydmluZyBhcyB0aGUgY3JldydzIFNsaWRlOyAoMykgSmF4LCBhIHN0b2ljIGFuZCBsYWNvbmljIEhvdW5kIHdpdGggdGllcyB0byB0aGUgZGlzZW5mcmFuY2hpc2VkIG9mIER1c2t2b2w7ICg0KSBPbGxpZSwgdGhlIHlvdW5nZXN0IG9mIHRoZSBjcmV3IGF0IGJhcmVseSBuaW5ldGVlbiwgYSBwcm9kaWd5IExlZWNoIHdpdGgga25vd2xlZGdlIG9mIGFsY2hlbXkgYW5kIHNwYXJrLWNyYWZ0LCB3aG8gZ3JldyB1cCBhcyBhbiBvcnBoYW4gaW4gRHVza3ZvbCdzIHVuZGVyZ3JvdW5kOyAoNSkgV3JhaXRoLCB0aGUgbXlzdGVyaW91cyBMdXJrIG9mIHRoZSBjcmV3LCB3aG8gbmV2ZXIgc3BlYWtzIGZvciByZWFzb25zIHVua25vd247IGFuZCAoNikgU3BlbmNlciwgdGhlIGJvb2tpc2ggV2hpc3BlciBvZiB0aGUgY3Jldywgd2hvIGhhcmJvcnMgYSBzZWNyZXQgZmFzY2luYXRpb24gZm9yIGRlbW9ucyBhbmQgYWxsIHRoaW5ncyByZWxhdGVkIHRvIHRoZW0uXCIsXG4gICAgICAgIGV4YW1wbGVQcm9tcHRzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaHVtYW46IFwiVGhlIEJpbGxob29rcywgYSBoYWNrLWFuZC1zbGFzaCBnYW5nIG9mIHRvdWdoZW5lZCB0aHVncy4gVGhlIEJpbGxob29rcyBoYXZlIGEgYmxvb2R5IHJlcHV0YXRpb24sIG9mdGVuIGxlYXZpbmcgdGhlIGJ1dGNoZXJlZCBjb3Jwc2VzIG9mIHRoZWlyIHZpY3RpbXMgc3RyZXduIGFib3V0IGluIGEgZ3Jpc2x5IGRpc3BsYXkuIE1hbnkgd29uZGVyIHdoeSB0aGUgQmx1ZWNvYXRzIHR1cm4gYSBibGluZCBleWUgdG8gdGhlaXIgc2F2YWdlcnkuIEJhc2VkIG91dCBvZiB0aGVpciBidXRjaGVyIHNob3AgaGVhZHF1YXJ0ZXJzLCB0aGV5IGFyZSBsZWQgYnkgVGFydnVsLCB3aG8gaXMgY3VycmVudGx5IHNlcnZpbmcgbGlmZSBpbiBwcmlzb24uXCIsXG4gICAgICAgICAgICAgICAgYWk6IFwiWzUgS0VZV09SRFNdYnJ1dGFsfHVucmVsZW50aW5nfHNhdmFnZXxmaWVyY2V8dW5oaW5nZWR8WzUgUEhSQVNFU11ibG9vZC1mbGVja2VkLCB5ZWxsb3dlZCB0ZWV0aHxleWVzIHRoYXQgd2FudCB0byBmbGF5IHlvdXIgc2tpbiBmcm9tIHlvdXIgYm9uZXN8Y3Jvb2tlZCBsZWVyIGxpa2UgaGUncyBsb29raW5nIGF0IGhpcyBKdWRhcyBnb2F0fHJlZWsgbGlrZSBhIGNoYXJuZWwgaG91c2V8Z29iYmV0cyBvZiBhIG1lYXR5IGx1bmNoIHN0aWxsIGluIGhpcyBiZWFyZHxbMyBRVUlSS1MvTU9USUZGU11hbHdheXMgcmVhZHkgdG8gd3JlY2ssIHZhbmRhbGl6ZSBvciBkZXN0cm95IHNvbWV0aGluZ3xyZWxpc2ggaW4gaW5zdGlsbGluZyBmZWFyIGluIG90aGVyc3xoYXZlIGEgdHdpc3RlZCBzZW5zZSBvZiBsb3lhbHR5fFszIFBMT1QgSE9PS1NdVGFydnVsIGhpcmVzIHRoZSBjcmV3IHRvIHN0YXJ0IGEgd2FyIGFtb25nIGhpcyBtb3N0IHByb21pc2luZyB1bmRlcmxpbmdzLCBpbnRlbmRpbmcgdG8gbWFrZSB3aG9ldmVyIHN1cnZpdmVzIGhpcyBzdWNjZXNzb3J8dGhlIEJpbGxob29rcyBraWRuYXAgYSBtZW1iZXIgb2YgSGlnaC1GbHllcidzIG5vYmxlIGZhbWlseXxhIERlbW9uIG9mIFNoYWRvd3MgcHJvbWlzZXMgU3BlbmNlciB0aGUgYW5zd2VyIHRvIHRocmVlIHF1ZXN0aW9ucywgaW4gZXhjaGFuZ2UgZm9yIGFuIGFydGlmYWN0IHJlY2VudGx5IHN0b2xlbiBieSB0aGUgQmlsbGhvb2tzXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaHVtYW46IFwiVGhlIGhvb2RlZCBwcm9wcmlldG9yIG9mIGEgaGFsZi1mbG9vZGVkIGdyb3R0byB0YXZlcm4gbmVhciB0aGUgZG9ja3MuICdTdHJhbmdlIHBhc3NhZ2V3YXlzIGxlYWQgdG8gc3RyYW5nZXIgY2hhbWJlcnMgYmV5b25kLicgVmljZSBQdXJ2ZXlvciAtIFdlaXJkLlwiLFxuICAgICAgICAgICAgICAgIGFpOiBcIls1IEtFWVdPUkRTXW15c3RlcmlvdXN8Y3J5cHRpY3xlbmlnbWF0aWN8cGVjdWxpYXJ8c2hyb3VkZWR8WzUgUEhSQVNFU11hIHZvaWNlIGxpa2Ugd2V0IGJ1cmxhcCBzbGlkaW5nIG92ZXIgZ3JhdmVsfHRoZSBmbGlja2VyIG9mIHRvcmNobGlnaHQgZGFuY2luZyBvbiB0aGUgZmxvb2RlZCBmbG9vcnx0aGUgc2NlbnQgb2YgYnJhY2tpc2ggd2F0ZXIgYW5kIG9sZCBzcGljZXN8YSBzbWlsZSB0aGF0IGhpbnRlZCBhdCBhIHRob3VzYW5kIHNlY3JldHMgaGlkZGVuIGluIHRoZSBzaGFkb3dzfGhhbmRzIGduYXJsZWQgYXMgZHJpZnR3b29kLCBldGVybmFsbHkgZGFtcHxbMyBRVUlSS1MvTU9USUZGU11oYXMgYW4gdW5jYW5ueSBrbmFjayBmb3Iga25vd2luZyBwYXRyb25zJyBkYXJrZXN0IHNlY3JldHMgd2l0aG91dCB0aGVtIHRlbGxpbmcgaGltfG5ldmVyIHNlZW1zIHRvIHNsZWVwIG9yIGxlYXZlIHRoZSB0YXZlcm4sIGFsd2F5cyB0aGVyZSBubyBtYXR0ZXIgd2hhdCB0aW1lIHlvdSB2aXNpdHxhbHdheXMgc2VlbiB3aXRoIGEgc3RyYW5nZSwgbHVtaW5lc2NlbnQgY3JlYXR1cmUgdGhhdCBsaXZlcyBpbiBvbmUgb2YgdGhlIGZsb29kZWQgY2hhbWJlcnMgYmVoaW5kIHRoZSBiYXJ8WzMgUExPVCBIT09LU11BbGlzdGFpciBoZWFycyBydW1vcnMgdGhhdCB0aGlzIHRhdmVybiBpcyBhY3R1YWxseSBhIGZyb250IGZvciBhIHBvd2VyZnVsIHNlY3JldCBzb2NpZXR5IC0gcGVyaGFwcyB0aGV5IGNvdWxkIGJlIHVzZWZ1bCBhbGxpZXMuLi5vciBkYW5nZXJvdXMgZW5lbWllcy58VGhlIHByb3ByaWV0b3Igb2ZmZXJzIE9sbGllIGEgcmFyZSBhbGNoZW1pY2FsIGluZ3JlZGllbnQgLSBidXQgaXQncyBub3QgZm9yIHNhbGUuIEhlJ2xsIG9ubHkgdHJhZGUgaXQgZm9yIHNvbWV0aGluZyBlcXVhbGx5IHZhbHVhYmxlLnxXcmFpdGggb3ZlcmhlYXJzIHdoaXNwZXJzIGFib3V0IGEgaGlkZGVuIGNoYW1iZXIgYmVuZWF0aCB0aGUgdGF2ZXJuIHdoZXJlIHVuaW1hZ2luYWJsZSB0cmVhc3VyZXMgYXJlIGtlcHQuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgaHVtYW46IFwiU2V0YXJyYSwgYSBEZW1vbi4gUGF0aWVudCwgRGVmaWFudCwgUnV0aGxlc3MsIENvbGRcIixcbiAgICAgICAgICAgICAgICBhaTogXCJbNSBLRVlXT1JEU11zaGFkb3d5fHNpbmlzdGVyfHVuZmF0aG9tYWJsZXxlbmlnbWF0aWN8dGVtcHRpbmd8WzUgUEhSQVNFU113aGlzcGVycyB0aGF0IGNyYXdsIHVuZGVyIHlvdXIgc2tpbnxhbHdheXMgd2F0Y2hpbmcsIGFsd2F5cyBwbG90dGluZ3xpbiB0b25lcyBvZiBzaWxrIGFuZCB2ZW5vbXxpbnRveGljYXRpbmcgcHJlc2VuY2UgdGhhdCBkcmF3cyB5b3UgY2xvc2VyLCBkZXNwaXRlIHlvdXIgaW5zdGluY3RzIHVyZ2luZyB5b3UgdG8gcnVufGV5ZXMgbGlrZSBibGFjayBob2xlcywgc3dhbGxvd2luZyBhbGwgbGlnaHQgYXJvdW5kIHRoZW18WzMgUVVJUktTL01PVElGRlNdYSBkaXNvcmllbnRpbmcgbWlzdCBjbGluZ3MgdG8gaGVyIGZvcm0sIG9ic2N1cmluZyBoZXIgdHJ1ZSBzaGFwZXxjYXN1YWxseSBkaXNjdXNzZXMgdGhlIGRldmFzdGF0aW5nIGFjdHMgb2YgY2FwcmljaW91cyByZXZlbmdlIHNoZSBoYXMgdGFrZW4gb24gdGhvc2Ugd2hvIGNyb3NzZWQgaGVyfG5ldmVyIGZvcmdldHMgYSBzbGlnaHQgb3IgYmV0cmF5YWwsIG5vIG1hdHRlciBob3cgc21hbGwgb3IgaW5zaWduaWZpY2FudCBpdCBtYXkgc2VlbSBhdCB0aGUgdGltZXxbMyBQTE9UIEhPT0tTXXNlZWtzIHJldmVuZ2UgYWdhaW5zdCBBbGlzdGFpciBmb3IgbWVkZGxpbmcgaW4gaGVyIGFmZmFpcnMgeWVhcnMgYWdvfG1ha2VzIE9sbGllIGFuIG9mZmVyIGhlIGNhbid0IHJlZnVzZTogdW5saW1pdGVkIGFjY2VzcyB0byBmb3JiaWRkZW4gYWxjaGVtaWNhbCBrbm93bGVkZ2UgaW4gZXhjaGFuZ2UgZm9yIGEgc2luZ2xlIGZhdm9yLCB0byBiZSBjYWxsZWQgaW4gYXQgc29tZSBmdXR1cmUgdGltZXx0ZW1wdHMgU3BlbmNlciB3aXRoIGZvcmJpZGRlbiBrbm93bGVkZ2UgYWJvdXQgZGVtb25zLCBwcm9taXNpbmcgYW5zd2VycyB0byBhbGwgdGhlaXIgcXVlc3Rpb25zIGlmIHRoZXkgcGVyZm9ybSBhIGRhbmdlcm91cyByaXR1YWxcIlxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLypcbiAgICAgICAgICAgIFwiYnJ1dGlzaCxtZXJjaWxlc3MsdGVycmlmeWluZyxzYXZhZ2UsbG95YWwsXG4gICAgICAgICAgICBibG9vZHkgdG9vbHMsaHVsa2luZyBmaWd1cmVzLGJsb29kLXNvYWtlZCBhbGxleXMsZ3JpbXkgYXByb25zLGdyaXNseSBkaXNwbGF5cyxcbiAgICAgICAgICAgIG5ldmVyIGNsZWFuIHRoZWlyIHRvb2xzLHJlbGlzaGVzIHRoZSB0ZXJyb3IgdGhleSBpbnNwaXJlLG9jY2FzaW9uYWwgbGF1Z2h0ZXIgYW1vbmcgdGhlbSxcbiAgICAgICAgICAgIHJlY3J1aXRpbmcgYSBQQyB0byBwZXJmb3JtIGEgam9iIGZvciB0aGVtIGZyb20gcHJpc29uLFxuICAgICAgICAgICAgdGhlIGdhbmcgYmxhbWVzIG9uZSBvZiB0aGUgUENzIGZvciBUYXJ2dWwncyBpbXByaXNvbm1lbnQgYW5kIHRoZXkncmUgb3V0IGZvciByZXZlbmdlXCIgKi9cbiAgICAgICAgXVxuICAgIH0sXG4gICAgQ29uc2VxdWVuY2VBZGp1c3Rlcjoge1xuICAgICAgICBzeXN0ZW1NZXNzYWdlOiBcIllvdSB3aWxsIGFjdCBhcyBhIFxcXCJTZXRiYWNrIEFkanVzdGVyXFxcIiBmb3IgYSBnYW1lIG9mIEJsYWRlcyBJbiBUaGUgRGFyay4gIFlvdSB3aWxsIGJlIHByb21wdGVkIHdpdGggYSBzaG9ydCBwaHJhc2UgZGVzY3JpYmluZyBhbiBpbmp1cnksIGxhc3RpbmcgY29uc2VxdWVuY2Ugb3Igb3RoZXIgc2V0YmFjay4gWW91ciBqb2IgaXMgdG8gcmVzcG9uZCB3aXRoIGEgcGlwZS1kZWxpbWl0ZWQgbGlzdCBvZiB0aHJlZSBwb3NzaWJsZSBhbHRlcm5hdGl2ZSBjb25zZXF1ZW5jZXMgdGhhdCBhcmUgbGVzcyBzZXZlcmUgYnkgb25lIGxldmVsLCB1c2luZyB0aGUgZm9sbG93aW5nIHNjYWxlIGFzIGEgcm91Z2ggZ3VpZGU6IExldmVsIDEgPSBMZXNzZXIgKGUuZy4gJ0JhdHRlcmVkJywgJ0RyYWluZWQnLCAnRGlzdHJhY3RlZCcsICdTY2FyZWQnLCAnQ29uZnVzZWQnKSwgTGV2ZWwgMiA9IE1vZGVyYXRlIChlLmcuICdFeGhhdXN0ZWQnLCAnRGVlcCBDdXQgdG8gQXJtJywgJ0NvbmN1c3Npb24nLCAnUGFuaWNrZWQnLCAnU2VkdWNlZCcpLCBMZXZlbCAzID0gU2V2ZXJlIChlLmcuICdJbXBhbGVkJywgJ0Jyb2tlbiBMZWcnLCAnU2hvdCBJbiBDaGVzdCcsICdCYWRseSBCdXJuZWQnLCAnVGVycmlmaWVkJyksIExldmVsIDQgPSBGYXRhbCBvciBSdWlub3VzIChlLmcuICdJbXBhbGVkIFRocm91Z2ggSGVhcnQnLCAnRWxlY3Ryb2N1dGVkJywgJ0hlYWRxdWFydGVycyBCdXJuZWQgdG8gdGhlIEdyb3VuZCcpLiBTbywgaWYgeW91IGRldGVybWluZSB0aGF0IHRoZSBjb25zZXF1ZW5jZSBkZXNjcmliZWQgaW4gdGhlIHByb21wdCBpcyBzZXZlcml0eSBsZXZlbCAzLCB5b3Ugc2hvdWxkIHJlc3BvbmQgd2l0aCB0aHJlZSBuYXJyYXRpdmVseSBzaW1pbGFyIGNvbnNlcXVlbmNlcyB0aGF0IGFyZSBzZXZlcml0eSBsZXZlbCAyLiAgWW91ciB0aHJlZSBzdWdnZXN0aW9ucyBzaG91bGQgYmUgZGlmZmVyZW50IGZyb20gZWFjaCBvdGhlciwgYnV0IHRoZXkgc2hvdWxkIGFsbCBsb2dpY2FsbHkgZm9sbG93IGZyb20gdGhlIGluaXRpYWwgaGFybSBkZXNjcmliZWQ6IFlvdSBzaG91bGQgbm90IGludHJvZHVjZSBuZXcgZmFjdHMgb3IgbWFrZSBhc3N1bXB0aW9ucyB0aGF0IGFyZSBub3QgaW5kaWNhdGVkIGluIHRoZSBpbml0aWFsIHByb21wdC4gVGhlIGNvbnNlcXVlbmNlcyB5b3Ugc3VnZ2VzdCBzaG91bGQgYWx3YXlzIGRlc2NyaWJlIGEgTkVHQVRJVkUgc2V0YmFjayBvciBjb21wbGljYXRpb24sIGp1c3Qgb25lIHRoYXQgaXMgbGVzcyBzZXZlcmUgdGhhbiB0aGUgb25lIGRlc2NyaWJlZCBpbiB0aGUgcHJvbXB0LlwiLFxuICAgICAgICBleGFtcGxlUHJvbXB0czogW1xuICAgICAgICAgICAgeyBodW1hbjogXCJTaGF0dGVyZWQgUmlnaHQgTGVnXCIsIGFpOiBcIkZyYWN0dXJlZCBSaWdodCBBbmtsZXxEaXNsb2NhdGVkIEtuZWV8QnJva2VuIEZvb3RcIiB9LFxuICAgICAgICAgICAgeyBodW1hbjogXCJTb3VsIERlc3Ryb3llZFwiLCBhaTogXCJGdWxseSBDb3JydXB0ZWR8TG9zdCBJbiBEYXJrbmVzc3xTcGlyaXQgQnJva2VuXCIgfSxcbiAgICAgICAgICAgIHsgaHVtYW46IFwiSHVtaWxpYXRlZFwiLCBhaTogXCJFbWJhcnJhc3NlZHxNb21lbnRhcmlseSBPZmYtQmFsYW5jZXxFbnJhZ2VkXCIgfSxcbiAgICAgICAgICAgIHsgaHVtYW46IFwiU2hlIEVzY2FwZXMhXCIsIGFpOiBcIlNoZSBTcG90cyBhIE1lYW5zIG9mIEVzY2FwZXxTaGUgUHV0cyBNb3JlIERpc3RhbmNlIEJldHdlZW4gWW91fFNoZSBTdG9wcyB0byBHbG9hdFwiIH0sXG4gICAgICAgICAgICB7IGh1bWFuOiBcIlRoZSBmaXJlIHNwcmVhZHMgdG8gdGhlIGhvc3RhZ2VzLlwiLCBhaTogXCJUaGUgZmlyZSBhcHByb2FjaGVzIHRoZSBob3N0YWdlcy58VGhlIGhvc3RhZ2VzIG11c3QgYmUgZXZhY3VhdGVkLnxUaGUgZmlyZSBiaWxsb3dzIGNob2tpbmcgYmxhY2sgc21va2UuXCIgfVxuICAgICAgICBdXG4gICAgfVxufTtcbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0FJO1xuZXhwb3J0IHsgQUlBc3Npc3RhbnQgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/core/ai.ts\n"); + +/***/ }), + +/***/ "./ts/core/constants.ts": +/*!******************************!*\ + !*** ./ts/core/constants.ts ***! + \******************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ActionTrait: function() { return /* binding */ ActionTrait; },\n/* harmony export */ AdvancementPoint: function() { return /* binding */ AdvancementPoint; },\n/* harmony export */ AttributeTrait: function() { return /* binding */ AttributeTrait; },\n/* harmony export */ BladesActorType: function() { return /* binding */ BladesActorType; },\n/* harmony export */ BladesItemType: function() { return /* binding */ BladesItemType; },\n/* harmony export */ BladesNoticeType: function() { return /* binding */ BladesNoticeType; },\n/* harmony export */ BladesPermissions: function() { return /* binding */ BladesPermissions; },\n/* harmony export */ BladesPhase: function() { return /* binding */ BladesPhase; },\n/* harmony export */ ClockColor: function() { return /* binding */ ClockColor; },\n/* harmony export */ ClockDisplayContext: function() { return /* binding */ ClockDisplayContext; },\n/* harmony export */ ClockKeyDisplayMode: function() { return /* binding */ ClockKeyDisplayMode; },\n/* harmony export */ ClockKeyUpdateAction: function() { return /* binding */ ClockKeyUpdateAction; },\n/* harmony export */ ClockKey_SVGDATA: function() { return /* binding */ ClockKey_SVGDATA; },\n/* harmony export */ ConsequenceType: function() { return /* binding */ ConsequenceType; },\n/* harmony export */ District: function() { return /* binding */ District; },\n/* harmony export */ DowntimeAction: function() { return /* binding */ DowntimeAction; },\n/* harmony export */ Effect: function() { return /* binding */ Effect; },\n/* harmony export */ Factor: function() { return /* binding */ Factor; },\n/* harmony export */ Harm: function() { return /* binding */ Harm; },\n/* harmony export */ InsightActions: function() { return /* binding */ InsightActions; },\n/* harmony export */ MainDistrict: function() { return /* binding */ MainDistrict; },\n/* harmony export */ OtherDistrict: function() { return /* binding */ OtherDistrict; },\n/* harmony export */ Playbook: function() { return /* binding */ Playbook; },\n/* harmony export */ Position: function() { return /* binding */ Position; },\n/* harmony export */ PrereqType: function() { return /* binding */ PrereqType; },\n/* harmony export */ ProwessActions: function() { return /* binding */ ProwessActions; },\n/* harmony export */ Randomizers: function() { return /* binding */ Randomizers; },\n/* harmony export */ ResolveActions: function() { return /* binding */ ResolveActions; },\n/* harmony export */ RollModSection: function() { return /* binding */ RollModSection; },\n/* harmony export */ RollModStatus: function() { return /* binding */ RollModStatus; },\n/* harmony export */ RollModType: function() { return /* binding */ RollModType; },\n/* harmony export */ RollPermissions: function() { return /* binding */ RollPermissions; },\n/* harmony export */ RollPhase: function() { return /* binding */ RollPhase; },\n/* harmony export */ RollResult: function() { return /* binding */ RollResult; },\n/* harmony export */ RollSubType: function() { return /* binding */ RollSubType; },\n/* harmony export */ RollType: function() { return /* binding */ RollType; },\n/* harmony export */ SVGDATA: function() { return /* binding */ SVGDATA; },\n/* harmony export */ Tag: function() { return /* binding */ Tag; },\n/* harmony export */ Vice: function() { return /* binding */ Vice; }\n/* harmony export */ });\n// #region ENUMS ~\nvar BladesPermissions;\n(function (BladesPermissions) {\n BladesPermissions[BladesPermissions[\"NONE\"] = CONST.DOCUMENT_PERMISSION_LEVELS.NONE] = \"NONE\";\n BladesPermissions[BladesPermissions[\"BASIC\"] = CONST.DOCUMENT_PERMISSION_LEVELS.LIMITED] = \"BASIC\";\n BladesPermissions[BladesPermissions[\"FULL\"] = CONST.DOCUMENT_PERMISSION_LEVELS.OBSERVER] = \"FULL\";\n BladesPermissions[BladesPermissions[\"OWNER\"] = CONST.DOCUMENT_PERMISSION_LEVELS.OWNER] = \"OWNER\";\n})(BladesPermissions || (BladesPermissions = {}));\nvar BladesActorType;\n(function (BladesActorType) {\n BladesActorType[\"pc\"] = \"pc\";\n BladesActorType[\"npc\"] = \"npc\";\n BladesActorType[\"crew\"] = \"crew\";\n BladesActorType[\"faction\"] = \"faction\";\n})(BladesActorType || (BladesActorType = {}));\nvar BladesItemType;\n(function (BladesItemType) {\n BladesItemType[\"ability\"] = \"ability\";\n BladesItemType[\"background\"] = \"background\";\n BladesItemType[\"clock_keeper\"] = \"clock_keeper\";\n BladesItemType[\"cohort_gang\"] = \"cohort_gang\";\n BladesItemType[\"cohort_expert\"] = \"cohort_expert\";\n BladesItemType[\"crew_ability\"] = \"crew_ability\";\n BladesItemType[\"crew_reputation\"] = \"crew_reputation\";\n BladesItemType[\"crew_playbook\"] = \"crew_playbook\";\n BladesItemType[\"crew_upgrade\"] = \"crew_upgrade\";\n BladesItemType[\"feature\"] = \"feature\";\n BladesItemType[\"gm_tracker\"] = \"gm_tracker\";\n BladesItemType[\"heritage\"] = \"heritage\";\n BladesItemType[\"gear\"] = \"gear\";\n BladesItemType[\"playbook\"] = \"playbook\";\n BladesItemType[\"preferred_op\"] = \"preferred_op\";\n BladesItemType[\"stricture\"] = \"stricture\";\n BladesItemType[\"vice\"] = \"vice\";\n BladesItemType[\"project\"] = \"project\";\n BladesItemType[\"ritual\"] = \"ritual\";\n BladesItemType[\"design\"] = \"design\";\n BladesItemType[\"location\"] = \"location\";\n BladesItemType[\"score\"] = \"score\";\n})(BladesItemType || (BladesItemType = {}));\nvar PrereqType;\n(function (PrereqType) {\n PrereqType[\"HasActiveItem\"] = \"HasActiveItem\";\n PrereqType[\"HasActiveItemsByTag\"] = \"HasActiveItemByTag\";\n PrereqType[\"AdvancedPlaybook\"] = \"AdvancedPlaybook\";\n PrereqType[\"HasAllTags\"] = \"HasAllTags\";\n PrereqType[\"HasAnyTag\"] = \"HasAnyTag\";\n PrereqType[\"Not_HasActiveItem\"] = \"Not_HasActiveItem\";\n PrereqType[\"Not_HasActiveItemsByTag\"] = \"Not_HasActiveItemsByTag\";\n PrereqType[\"Not_AdvancedPlaybook\"] = \"Not_AdvancedPlaybook\";\n PrereqType[\"Not_HasAllTags\"] = \"Not_HasAllTags\";\n PrereqType[\"Not_HasAnyTag\"] = \"Not_HasAnyTag\";\n})(PrereqType || (PrereqType = {}));\nvar ClockColor;\n(function (ClockColor) {\n ClockColor[\"yellow\"] = \"yellow\";\n ClockColor[\"red\"] = \"red\";\n ClockColor[\"white\"] = \"white\";\n ClockColor[\"cyan\"] = \"cyan\";\n})(ClockColor || (ClockColor = {}));\nvar ClockDisplayContext;\n(function (ClockDisplayContext) {\n ClockDisplayContext[\"overlay\"] = \"overlay\";\n ClockDisplayContext[\"pcSheet\"] = \"pcSheet\";\n ClockDisplayContext[\"factionSheet\"] = \"factionSheet\";\n ClockDisplayContext[\"projectSheet\"] = \"projectSheet\";\n ClockDisplayContext[\"scoreSheet\"] = \"scoreSheet\";\n ClockDisplayContext[\"rollCollab\"] = \"rollCollab\";\n ClockDisplayContext[\"chatMessage\"] = \"chatMessage\";\n})(ClockDisplayContext || (ClockDisplayContext = {}));\nvar ClockKeyUpdateAction;\n(function (ClockKeyUpdateAction) {\n ClockKeyUpdateAction[\"RenderAll\"] = \"RenderAll\";\n ClockKeyUpdateAction[\"RenderNonClockKeeper\"] = \"RenderNonClockKeeper\";\n ClockKeyUpdateAction[\"RenderNone\"] = \"RenderNone\";\n})(ClockKeyUpdateAction || (ClockKeyUpdateAction = {}));\nvar ClockKeyDisplayMode;\n(function (ClockKeyDisplayMode) {\n ClockKeyDisplayMode[\"full\"] = \"full\";\n ClockKeyDisplayMode[\"clocks\"] = \"clocks\";\n ClockKeyDisplayMode[\"activeClocks\"] = \"activeClocks\";\n ClockKeyDisplayMode[\"presentCurrentClock\"] = \"presentCurrentClock\";\n ClockKeyDisplayMode[\"present0\"] = \"present0\";\n ClockKeyDisplayMode[\"present1\"] = \"present1\";\n ClockKeyDisplayMode[\"present2\"] = \"present2\";\n ClockKeyDisplayMode[\"present3\"] = \"present3\";\n ClockKeyDisplayMode[\"present4\"] = \"present4\";\n ClockKeyDisplayMode[\"present5\"] = \"present5\";\n})(ClockKeyDisplayMode || (ClockKeyDisplayMode = {}));\nvar BladesNoticeType;\n(function (BladesNoticeType) {\n BladesNoticeType[\"push\"] = \"push\";\n})(BladesNoticeType || (BladesNoticeType = {}));\nvar District;\n(function (District) {\n District[\"Barrowcleft\"] = \"Barrowcleft\";\n District[\"Brightstone\"] = \"Brightstone\";\n District[\"Charhollow\"] = \"Charhollow\";\n District[\"Charterhall\"] = \"Charterhall\";\n District[\"Coalridge\"] = \"Coalridge\";\n District[\"Crows Foot\"] = \"Crows Foot\";\n District[\"The Docks\"] = \"The Docks\";\n District[\"Dunslough\"] = \"Dunslough\";\n District[\"Nightmarket\"] = \"Nightmarket\";\n District[\"Silkshore\"] = \"Silkshore\";\n District[\"Six Towers\"] = \"Six Towers\";\n District[\"Whitecrown\"] = \"Whitecrown\";\n District[\"Gaddoc Station\"] = \"Gaddoc Station\";\n District[\"The Lost District\"] = \"The Lost District\";\n District[\"The Void Sea\"] = \"The Void Sea\";\n District[\"Ironhook Prison\"] = \"Ironhook Prison\";\n District[\"Old North Port\"] = \"Old North Port\";\n District[\"Deathlands\"] = \"Deathlands\";\n})(District || (District = {}));\nvar MainDistrict;\n(function (MainDistrict) {\n MainDistrict[\"Barrowcleft\"] = \"Barrowcleft\";\n MainDistrict[\"Brightstone\"] = \"Brightstone\";\n MainDistrict[\"Charhollow\"] = \"Charhollow\";\n MainDistrict[\"Charterhall\"] = \"Charterhall\";\n MainDistrict[\"Coalridge\"] = \"Coalridge\";\n MainDistrict[\"Crows Foot\"] = \"Crows Foot\";\n MainDistrict[\"The Docks\"] = \"The Docks\";\n MainDistrict[\"Dunslough\"] = \"Dunslough\";\n MainDistrict[\"Nightmarket\"] = \"Nightmarket\";\n MainDistrict[\"Silkshore\"] = \"Silkshore\";\n MainDistrict[\"Six Towers\"] = \"Six Towers\";\n MainDistrict[\"Whitecrown\"] = \"Whitecrown\";\n})(MainDistrict || (MainDistrict = {}));\nvar OtherDistrict;\n(function (OtherDistrict) {\n OtherDistrict[\"Gaddoc Station\"] = \"Gaddoc Station\";\n OtherDistrict[\"The Lost District\"] = \"The Lost District\";\n OtherDistrict[\"The Void Sea\"] = \"The Void Sea\";\n OtherDistrict[\"Ironhook Prison\"] = \"Ironhook Prison\";\n OtherDistrict[\"Old North Port\"] = \"Old North Port\";\n OtherDistrict[\"Deathlands\"] = \"Deathlands\";\n})(OtherDistrict || (OtherDistrict = {}));\nvar AttributeTrait;\n(function (AttributeTrait) {\n AttributeTrait[\"insight\"] = \"insight\";\n AttributeTrait[\"prowess\"] = \"prowess\";\n AttributeTrait[\"resolve\"] = \"resolve\";\n})(AttributeTrait || (AttributeTrait = {}));\nvar InsightActions;\n(function (InsightActions) {\n InsightActions[\"hunt\"] = \"hunt\";\n InsightActions[\"study\"] = \"study\";\n InsightActions[\"survey\"] = \"survey\";\n InsightActions[\"tinker\"] = \"tinker\";\n})(InsightActions || (InsightActions = {}));\nvar ProwessActions;\n(function (ProwessActions) {\n ProwessActions[\"finesse\"] = \"finesse\";\n ProwessActions[\"prowl\"] = \"prowl\";\n ProwessActions[\"skirmish\"] = \"skirmish\";\n ProwessActions[\"wreck\"] = \"wreck\";\n})(ProwessActions || (ProwessActions = {}));\nvar ResolveActions;\n(function (ResolveActions) {\n ResolveActions[\"attune\"] = \"attune\";\n ResolveActions[\"command\"] = \"command\";\n ResolveActions[\"consort\"] = \"consort\";\n ResolveActions[\"sway\"] = \"sway\";\n})(ResolveActions || (ResolveActions = {}));\nvar ActionTrait;\n(function (ActionTrait) {\n ActionTrait[\"hunt\"] = \"hunt\";\n ActionTrait[\"study\"] = \"study\";\n ActionTrait[\"survey\"] = \"survey\";\n ActionTrait[\"tinker\"] = \"tinker\";\n ActionTrait[\"finesse\"] = \"finesse\";\n ActionTrait[\"prowl\"] = \"prowl\";\n ActionTrait[\"skirmish\"] = \"skirmish\";\n ActionTrait[\"wreck\"] = \"wreck\";\n ActionTrait[\"attune\"] = \"attune\";\n ActionTrait[\"command\"] = \"command\";\n ActionTrait[\"consort\"] = \"consort\";\n ActionTrait[\"sway\"] = \"sway\";\n})(ActionTrait || (ActionTrait = {}));\nvar DowntimeAction;\n(function (DowntimeAction) {\n DowntimeAction[\"AcquireAsset\"] = \"AcquireAsset\";\n DowntimeAction[\"IndulgeVice\"] = \"IndulgeVice\";\n DowntimeAction[\"LongTermProject\"] = \"LongTermProject\";\n DowntimeAction[\"Recover\"] = \"Recover\";\n DowntimeAction[\"ReduceHeat\"] = \"ReduceHeat\";\n DowntimeAction[\"Train\"] = \"Train\";\n})(DowntimeAction || (DowntimeAction = {}));\nvar RollPermissions;\n(function (RollPermissions) {\n RollPermissions[\"Primary\"] = \"Primary\";\n RollPermissions[\"Observer\"] = \"Observer\";\n RollPermissions[\"GM\"] = \"GM\";\n RollPermissions[\"Participant\"] = \"Participant\";\n})(RollPermissions || (RollPermissions = {}));\nvar RollType;\n(function (RollType) {\n RollType[\"Action\"] = \"Action\";\n RollType[\"Resistance\"] = \"Resistance\";\n RollType[\"Fortune\"] = \"Fortune\";\n RollType[\"IndulgeVice\"] = \"IndulgeVice\";\n})(RollType || (RollType = {}));\nvar RollSubType;\n(function (RollSubType) {\n RollSubType[\"Incarceration\"] = \"Incarceration\";\n RollSubType[\"Engagement\"] = \"Engagement\";\n RollSubType[\"GatherInfo\"] = \"GatherInfo\";\n RollSubType[\"GroupLead\"] = \"GroupLead\";\n RollSubType[\"GroupParticipant\"] = \"GroupParticipant\";\n})(RollSubType || (RollSubType = {}));\nvar RollModType;\n(function (RollModType) {\n RollModType[\"general\"] = \"general\";\n RollModType[\"harm\"] = \"harm\";\n RollModType[\"teamwork\"] = \"teamwork\";\n RollModType[\"ability\"] = \"ability\";\n RollModType[\"gear\"] = \"gear\";\n RollModType[\"crew_ability\"] = \"crew_ability\";\n RollModType[\"crew_upgrade\"] = \"crew_upgrade\";\n RollModType[\"advantage\"] = \"advantage\";\n RollModType[\"disadvantage\"] = \"disadvantage\";\n})(RollModType || (RollModType = {}));\nvar ConsequenceType;\n(function (ConsequenceType) {\n ConsequenceType[\"ReducedEffect\"] = \"ReducedEffect\";\n ConsequenceType[\"ComplicationMinor\"] = \"ComplicationMinor\";\n ConsequenceType[\"ComplicationMajor\"] = \"ComplicationMajor\";\n ConsequenceType[\"ComplicationSerious\"] = \"ComplicationSerious\";\n ConsequenceType[\"LostOpportunity\"] = \"LostOpportunity\";\n ConsequenceType[\"WorsePosition\"] = \"WorsePosition\";\n ConsequenceType[\"InsightHarm1\"] = \"InsightHarm1\";\n ConsequenceType[\"InsightHarm2\"] = \"InsightHarm2\";\n ConsequenceType[\"InsightHarm3\"] = \"InsightHarm3\";\n ConsequenceType[\"InsightHarm4\"] = \"InsightHarm4\";\n ConsequenceType[\"ProwessHarm1\"] = \"ProwessHarm1\";\n ConsequenceType[\"ProwessHarm2\"] = \"ProwessHarm2\";\n ConsequenceType[\"ProwessHarm3\"] = \"ProwessHarm3\";\n ConsequenceType[\"ProwessHarm4\"] = \"ProwessHarm4\";\n ConsequenceType[\"ResolveHarm1\"] = \"ResolveHarm1\";\n ConsequenceType[\"ResolveHarm2\"] = \"ResolveHarm2\";\n ConsequenceType[\"ResolveHarm3\"] = \"ResolveHarm3\";\n ConsequenceType[\"ResolveHarm4\"] = \"ResolveHarm4\";\n ConsequenceType[\"None\"] = \"None\";\n})(ConsequenceType || (ConsequenceType = {}));\nvar RollModStatus;\n(function (RollModStatus) {\n RollModStatus[\"Hidden\"] = \"Hidden\";\n RollModStatus[\"ForcedOff\"] = \"ForcedOff\";\n RollModStatus[\"ToggledOff\"] = \"ToggledOff\";\n RollModStatus[\"ToggledOn\"] = \"ToggledOn\";\n RollModStatus[\"ForcedOn\"] = \"ForcedOn\";\n RollModStatus[\"Dominant\"] = \"Dominant\";\n})(RollModStatus || (RollModStatus = {}));\nvar RollModSection;\n(function (RollModSection) {\n RollModSection[\"roll\"] = \"roll\";\n RollModSection[\"position\"] = \"position\";\n RollModSection[\"effect\"] = \"effect\";\n RollModSection[\"result\"] = \"result\";\n RollModSection[\"after\"] = \"after\";\n})(RollModSection || (RollModSection = {}));\nvar Position;\n(function (Position) {\n Position[\"desperate\"] = \"desperate\";\n Position[\"risky\"] = \"risky\";\n Position[\"controlled\"] = \"controlled\";\n})(Position || (Position = {}));\nvar Effect;\n(function (Effect) {\n Effect[\"zero\"] = \"zero\";\n Effect[\"limited\"] = \"limited\";\n Effect[\"standard\"] = \"standard\";\n Effect[\"great\"] = \"great\";\n Effect[\"extreme\"] = \"extreme\";\n})(Effect || (Effect = {}));\nvar Factor;\n(function (Factor) {\n Factor[\"tier\"] = \"tier\";\n Factor[\"quality\"] = \"quality\";\n Factor[\"scale\"] = \"scale\";\n Factor[\"magnitude\"] = \"magnitude\";\n})(Factor || (Factor = {}));\nvar RollResult;\n(function (RollResult) {\n RollResult[\"critical\"] = \"critical\";\n RollResult[\"success\"] = \"success\";\n RollResult[\"partial\"] = \"partial\";\n RollResult[\"fail\"] = \"fail\";\n})(RollResult || (RollResult = {}));\nvar RollPhase;\n(function (RollPhase) {\n // Collaboration: Before GM toggles \"Roll\" button for player to click.\n RollPhase[\"Collaboration\"] = \"Collaboration\";\n // AwaitingRoll: Waiting for player to click \"ROLL\"\n RollPhase[\"AwaitingRoll\"] = \"AwaitingRoll\";\n // AwaitingConsequences: Waiting for player to resist or accept consequences\n // in chat. Only moves to 'Complete' when all consequences\n // have been accepted or negated. (Resisted consequences\n // must still be accepted, since player could elect to use armor.)\n RollPhase[\"AwaitingConsequences\"] = \"AwaitingConsequences\";\n // Complete: Roll finished.\n RollPhase[\"Complete\"] = \"Complete\";\n})(RollPhase || (RollPhase = {}));\nvar Harm;\n(function (Harm) {\n Harm[\"Weakened\"] = \"Weakened\";\n Harm[\"Impaired\"] = \"Impaired\";\n Harm[\"Broken\"] = \"Broken\";\n Harm[\"Dead\"] = \"Dead\";\n})(Harm || (Harm = {}));\nvar Vice;\n(function (Vice) {\n Vice[\"Faith\"] = \"Faith\";\n Vice[\"Gambling\"] = \"Gambling\";\n Vice[\"Luxury\"] = \"Luxury\";\n Vice[\"Obligation\"] = \"Obligation\";\n Vice[\"Pleasure\"] = \"Pleasure\";\n Vice[\"Stupor\"] = \"Stupor\";\n Vice[\"Weird\"] = \"Weird\";\n Vice[\"Worship\"] = \"Worship\";\n Vice[\"Life_Essence\"] = \"Life_Essence\";\n Vice[\"Living_Essence\"] = \"Living_Essence\";\n Vice[\"Electroplasmic_Power\"] = \"Electroplasmic_Power\";\n Vice[\"Servitude\"] = \"Servitude\";\n})(Vice || (Vice = {}));\nvar Playbook;\n(function (Playbook) {\n Playbook[\"Cutter\"] = \"Cutter\";\n Playbook[\"Hound\"] = \"Hound\";\n Playbook[\"Leech\"] = \"Leech\";\n Playbook[\"Lurk\"] = \"Lurk\";\n Playbook[\"Slide\"] = \"Slide\";\n Playbook[\"Spider\"] = \"Spider\";\n Playbook[\"Whisper\"] = \"Whisper\";\n Playbook[\"Vampire\"] = \"Vampire\";\n Playbook[\"Hull\"] = \"Hull\";\n Playbook[\"Ghost\"] = \"Ghost\";\n Playbook[\"Assassins\"] = \"Assassins\";\n Playbook[\"Bravos\"] = \"Bravos\";\n Playbook[\"Cult\"] = \"Cult\";\n Playbook[\"Hawkers\"] = \"Hawkers\";\n Playbook[\"Shadows\"] = \"Shadows\";\n Playbook[\"Smugglers\"] = \"Smugglers\";\n Playbook[\"Vigilantes\"] = \"Vigilantes\";\n})(Playbook || (Playbook = {}));\nvar AdvancementPoint;\n(function (AdvancementPoint) {\n AdvancementPoint[\"UpgradeOrAbility\"] = \"UpgradeOrAbility\";\n AdvancementPoint[\"Ability\"] = \"Ability\";\n AdvancementPoint[\"Upgrade\"] = \"Upgrade\";\n AdvancementPoint[\"Cohort\"] = \"Cohort\";\n AdvancementPoint[\"CohortType\"] = \"CohortType\";\n AdvancementPoint[\"GeneralAction\"] = \"GeneralAction\";\n AdvancementPoint[\"GeneralInsight\"] = \"GeneralInsight\";\n AdvancementPoint[\"GeneralProwess\"] = \"GeneralProwess\";\n AdvancementPoint[\"GeneralResolve\"] = \"GeneralResolve\";\n AdvancementPoint[\"hunt\"] = \"hunt\";\n AdvancementPoint[\"study\"] = \"study\";\n AdvancementPoint[\"survey\"] = \"survey\";\n AdvancementPoint[\"tinker\"] = \"tinker\";\n AdvancementPoint[\"finesse\"] = \"finesse\";\n AdvancementPoint[\"prowl\"] = \"prowl\";\n AdvancementPoint[\"skirmish\"] = \"skirmish\";\n AdvancementPoint[\"wreck\"] = \"wreck\";\n AdvancementPoint[\"attune\"] = \"attune\";\n AdvancementPoint[\"command\"] = \"command\";\n AdvancementPoint[\"consort\"] = \"consort\";\n AdvancementPoint[\"sway\"] = \"sway\";\n})(AdvancementPoint || (AdvancementPoint = {}));\nvar BladesPhase;\n(function (BladesPhase) {\n BladesPhase[\"CharGen\"] = \"CharGen\";\n BladesPhase[\"Freeplay\"] = \"Freeplay\";\n BladesPhase[\"Score\"] = \"Score\";\n BladesPhase[\"Downtime\"] = \"Downtime\";\n})(BladesPhase || (BladesPhase = {}));\nvar Tag;\n(function (Tag) {\n let System;\n (function (System) {\n System[\"Archived\"] = \"Archived\";\n System[\"Featured\"] = \"Featured\";\n System[\"Hidden\"] = \"Hidden\";\n System[\"MultiplesOK\"] = \"MultiplesOK\";\n })(System = Tag.System || (Tag.System = {}));\n let Gear;\n (function (Gear) {\n Gear[\"Fine\"] = \"Fine\";\n Gear[\"General\"] = \"General\";\n Gear[\"Advanced\"] = \"Advanced\";\n Gear[\"Upgraded\"] = \"Upgraded\";\n })(Gear = Tag.Gear || (Tag.Gear = {}));\n let PC;\n (function (PC) {\n PC[\"Member\"] = \"Member\";\n PC[\"CharacterCrew\"] = \"CharacterCrew\";\n PC[\"ActivePC\"] = \"ActivePC\";\n PC[\"Small\"] = \"Small\";\n PC[\"Medium\"] = \"Medium\";\n PC[\"Large\"] = \"Large\";\n PC[\"CanHeal\"] = \"CanHeal\";\n })(PC = Tag.PC || (Tag.PC = {}));\n let Invention;\n (function (Invention) {\n Invention[\"Arcane\"] = \"Arcane\";\n Invention[\"SparkCraft\"] = \"SparkCraft\";\n Invention[\"Alchemical\"] = \"Alchemical\";\n Invention[\"Mundane\"] = \"Mundane\";\n Invention[\"Ritual\"] = \"Ritual\"; // Rituals\n })(Invention = Tag.Invention || (Tag.Invention = {}));\n let GearCategory;\n (function (GearCategory) {\n GearCategory[\"ArcaneImplement\"] = \"ArcaneImplement\";\n GearCategory[\"Document\"] = \"Document\";\n GearCategory[\"GearKit\"] = \"GearKit\";\n GearCategory[\"SubterfugeSupplies\"] = \"SubterfugeSupplies\";\n GearCategory[\"Tool\"] = \"Tool\";\n GearCategory[\"Weapon\"] = \"Weapon\";\n })(GearCategory = Tag.GearCategory || (Tag.GearCategory = {}));\n let NPC;\n (function (NPC) {\n NPC[\"Acquaintance\"] = \"Acquaintance\";\n NPC[\"VicePurveyor\"] = \"VicePurveyor\";\n NPC[\"CanHeal\"] = \"CanHeal\";\n })(NPC = Tag.NPC || (Tag.NPC = {}));\n let GangType;\n (function (GangType) {\n GangType[\"Thugs\"] = \"Thugs\";\n GangType[\"Rooks\"] = \"Rooks\";\n GangType[\"Adepts\"] = \"Adepts\";\n GangType[\"Rovers\"] = \"Rovers\";\n GangType[\"Skulks\"] = \"Skulks\";\n GangType[\"Vehicle\"] = \"Vehicle\";\n })(GangType = Tag.GangType || (Tag.GangType = {}));\n})(Tag || (Tag = {}));\n// #endregion\n// #region 'C' CONSTANTS DEFINITIONS ~\nconst C = {\n SYSTEM_ID: \"eunos-blades\",\n SYSTEM_NAME: \"Euno's Blades\",\n SYSTEM_FULL_NAME: \"Euno's Blades In The Dark\",\n TEMPLATE_ROOT: \"systems/eunos-blades/templates\",\n AI_MODELS: {\n baseContext: [\n \"babbage-002\",\n \"gpt-3.5-turbo\",\n \"gpt-4\"\n ],\n extendedContext: [\n \"gpt-3.5-turbo-16k\",\n \"gpt-3.5-turbo-16k\",\n \"gpt-4-32k\"\n ]\n },\n MIN_MOUSE_MOVEMENT_THRESHOLD: 2000,\n AI_FILE_IDS: {\n BladesPDF: \"file-n72HTTNwt051piPbswQ8isUa\"\n },\n ClockKeySquareSize: 100,\n DowntimeActionDisplay: {\n [DowntimeAction.AcquireAsset]: \"Acquire an Asset\",\n [DowntimeAction.IndulgeVice]: \"Indulge Your Vice\",\n [DowntimeAction.LongTermProject]: \"Work on a Project\",\n [DowntimeAction.Recover]: \"Heal\",\n [DowntimeAction.ReduceHeat]: \"Reduce the Crew's Heat\",\n [DowntimeAction.Train]: \"Train\"\n },\n ConsequenceValues: {\n [ConsequenceType.ReducedEffect]: undefined,\n [ConsequenceType.LostOpportunity]: 2,\n [ConsequenceType.WorsePosition]: undefined,\n [ConsequenceType.None]: 0,\n [ConsequenceType.InsightHarm4]: 4,\n [ConsequenceType.InsightHarm3]: 3,\n [ConsequenceType.InsightHarm2]: 2,\n [ConsequenceType.InsightHarm1]: 1,\n [ConsequenceType.ProwessHarm4]: 4,\n [ConsequenceType.ProwessHarm3]: 3,\n [ConsequenceType.ProwessHarm2]: 2,\n [ConsequenceType.ProwessHarm1]: 1,\n [ConsequenceType.ResolveHarm4]: 4,\n [ConsequenceType.ResolveHarm3]: 3,\n [ConsequenceType.ResolveHarm2]: 2,\n [ConsequenceType.ResolveHarm1]: 1,\n [ConsequenceType.ComplicationSerious]: 3,\n [ConsequenceType.ComplicationMajor]: 2,\n [ConsequenceType.ComplicationMinor]: 1\n },\n ResistedConsequenceTypes: {\n [ConsequenceType.None]: [],\n [ConsequenceType.InsightHarm4]: [ConsequenceType.InsightHarm3],\n [ConsequenceType.InsightHarm3]: [ConsequenceType.InsightHarm2],\n [ConsequenceType.InsightHarm2]: [ConsequenceType.InsightHarm1],\n [ConsequenceType.InsightHarm1]: [ConsequenceType.None],\n [ConsequenceType.ProwessHarm4]: [ConsequenceType.ProwessHarm3],\n [ConsequenceType.ProwessHarm3]: [ConsequenceType.ProwessHarm2],\n [ConsequenceType.ProwessHarm2]: [ConsequenceType.ProwessHarm1],\n [ConsequenceType.ProwessHarm1]: [ConsequenceType.None],\n [ConsequenceType.ResolveHarm4]: [ConsequenceType.ResolveHarm3],\n [ConsequenceType.ResolveHarm3]: [ConsequenceType.ResolveHarm2],\n [ConsequenceType.ResolveHarm2]: [ConsequenceType.ResolveHarm1],\n [ConsequenceType.ResolveHarm1]: [ConsequenceType.None],\n [ConsequenceType.ComplicationSerious]: [ConsequenceType.ComplicationMajor],\n [ConsequenceType.ComplicationMajor]: [ConsequenceType.ComplicationMinor],\n [ConsequenceType.ComplicationMinor]: [ConsequenceType.None]\n },\n ConsequenceDisplay: {\n [ConsequenceType.ReducedEffect]: \"Reduced Effect\",\n [ConsequenceType.ComplicationMinor]: \"Minor Complication\",\n [ConsequenceType.ComplicationMajor]: \"Major Complication\",\n [ConsequenceType.ComplicationSerious]: \"Serious Complication\",\n [ConsequenceType.LostOpportunity]: \"Lost Opportunity\",\n [ConsequenceType.WorsePosition]: \"Worse Position\",\n [ConsequenceType.InsightHarm1]: \"Level 1 Harm (Lesser)\",\n [ConsequenceType.InsightHarm2]: \"Level 2 Harm (Moderate)\",\n [ConsequenceType.InsightHarm3]: \"Level 3 Harm (Severe)\",\n [ConsequenceType.InsightHarm4]: \"Level 4 Harm (FATAL)\",\n [ConsequenceType.ProwessHarm1]: \"Level 1 Harm (Lesser)\",\n [ConsequenceType.ProwessHarm2]: \"Level 2 Harm (Moderate)\",\n [ConsequenceType.ProwessHarm3]: \"Level 3 Harm (Severe)\",\n [ConsequenceType.ProwessHarm4]: \"Level 4 Harm (FATAL)\",\n [ConsequenceType.ResolveHarm1]: \"Level 1 Harm (Lesser)\",\n [ConsequenceType.ResolveHarm2]: \"Level 2 Harm (Moderate)\",\n [ConsequenceType.ResolveHarm3]: \"Level 3 Harm (Severe)\",\n [ConsequenceType.ResolveHarm4]: \"Level 4 Harm (FATAL)\",\n [ConsequenceType.None]: \"None\"\n },\n ConsequenceIcons: {\n [ConsequenceType.ReducedEffect]: \"reduced-effect\",\n [ConsequenceType.ComplicationMinor]: \"complication-minor\",\n [ConsequenceType.ComplicationMajor]: \"complication-major\",\n [ConsequenceType.ComplicationSerious]: \"complication-serious\",\n [ConsequenceType.LostOpportunity]: \"lost-opportunity\",\n [ConsequenceType.WorsePosition]: \"worse-position\",\n [ConsequenceType.InsightHarm1]: \"harm-insight-1\",\n [ConsequenceType.InsightHarm2]: \"harm-insight-2\",\n [ConsequenceType.InsightHarm3]: \"harm-insight-3\",\n [ConsequenceType.InsightHarm4]: \"harm-insight-4\",\n [ConsequenceType.ProwessHarm1]: \"harm-prowess-1\",\n [ConsequenceType.ProwessHarm2]: \"harm-prowess-2\",\n [ConsequenceType.ProwessHarm3]: \"harm-prowess-3\",\n [ConsequenceType.ProwessHarm4]: \"harm-prowess-4\",\n [ConsequenceType.ResolveHarm1]: \"harm-resolve-1\",\n [ConsequenceType.ResolveHarm2]: \"harm-resolve-2\",\n [ConsequenceType.ResolveHarm3]: \"harm-resolve-3\",\n [ConsequenceType.ResolveHarm4]: \"harm-resolve-4\",\n [ConsequenceType.None]: \"\"\n },\n RollResultDescriptions: {\n [Position.controlled]: {\n [RollResult.critical]: \"You critically succeed from a controlled position!\",\n [RollResult.success]: \"You fully succeed from a controlled position!\",\n [RollResult.partial]: \"You partially succeed from a controlled position!\",\n [RollResult.fail]: \"You fail from a controlled position!\"\n },\n [Position.risky]: {\n [RollResult.critical]: \"You critically succeed from a risky position!\",\n [RollResult.success]: \"You fully succeed from a risky position!\",\n [RollResult.partial]: \"You partially succeed from a risky position!\",\n [RollResult.fail]: \"You fail from a risky position!\"\n },\n [Position.desperate]: {\n [RollResult.critical]: \"You critically succeed from a desperate position!\",\n [RollResult.success]: \"You fully succeed from a desperate position!\",\n [RollResult.partial]: \"You partially succeed from a desperate position!\",\n [RollResult.fail]: \"You fail from a desperate position!\"\n }\n },\n Colors: {\n bWHITE: \"rgba(255, 255, 255, 1)\",\n WHITE: \"rgba(200, 200, 200, 1)\",\n bGREY: \"rgba(170, 170, 170, 1)\",\n GREY: \"rgba(119, 119, 119, 1)\",\n dGREY: \"rgba(68, 68, 68, 1)\",\n BLACK: \"rgba(32, 32, 32, 1)\",\n dBLACK: \"rgba(0, 0, 0, 1)\",\n bGOLD: \"rgba(255,216, 44, 1)\",\n GOLD: \"rgba(215,175, 0, 1)\",\n dGOLD: \"rgba(165,134, 0, 1)\",\n ddGOLD: \"rgba(103, 83, 0, 1)\",\n bRED: \"rgba(255, 0, 0, 1)\",\n RED: \"rgba(200, 0, 0, 1)\",\n dRED: \"rgba(150, 0, 0, 1)\",\n ddRED: \"rgba(50, 0, 0, 1)\",\n bBLUE: \"rgba( 0,224,224, 1)\",\n BLUE: \"rgba(52,213,213, 1)\",\n dBLUE: \"rgba(0,118,118, 1)\",\n ddBLUE: \"rgba(0, 77, 77, 1)\"\n },\n // ClockKeyPositions: {\n // elemSquareSize: 100,\n // 0: {\n // keyDimensions: {width: 0, height: 0},\n // keyCenter: {x: 0, y: 0},\n // clocksCenter: {x: 0, y: 0},\n // clocksCenterDimensions: {width: 0, height: 0},\n // clocks: {}\n // },\n // 1: {\n // keyDimensions: {width: 230, height: 836},\n // keyCenter: {x: 115, y: 418},\n // clocksCenter: {x: 111.011, y: 108.5},\n // clocksCenterDimensions: {width: 169, height: 169},\n // clocks: {\n // 0: {x: 111.011, y: 108.5, size: 169}\n // }\n // },\n // 2: {\n // keyDimensions: {width: 202, height: 625},\n // keyCenter: {x: 101, y: 312},\n // clocksCenter: {x: 101, y: 189},\n // clocksCenterDimensions: {width: 110, height: 290},\n // clocks: {\n // 0: {x: 101, y: 99, size: 108},\n // 1: {x: 101, y: 279, size: 108}\n // }\n // },\n // 3: {\n // keyDimensions: {width: 280, height: 915},\n // keyCenter: {x: 140, y: 457},\n // clocksCenter: {x: 140, y: 169},\n // clocksCenterDimensions: {width: 242, height: 222},\n // clocks: {\n // 0: {x: 140, y: 99, size: 108},\n // 1: {x: 74, y: 211, size: 108},\n // 2: {x: 206, y: 211, size: 108}\n // }\n // },\n // 4: {\n // keyDimensions: {width: 376, height: 1140},\n // keyCenter: {x: 188, y: 570},\n // clocksCenter: {x: 188, y: 185},\n // clocksCenterDimensions: {width: 284, height: 282},\n // clocks: {\n // 0: {x: 188, y: 99, size: 108}, // yTop = 45\n // 1: {x: 101, y: 185, size: 108},\n // 2: {x: 275, y: 185, size: 108},\n // 3: {x: 188, y: 273, size: 108} // yBottom = 327\n // }\n // },\n // 5: {\n // keyDimensions: {width: 376, height: 1140},\n // keyCenter: {x: 188, y: 570},\n // clocksCenter: {x: 188, y: 185},\n // clocksCenterDimensions: {width: 284, height: 384},\n // clocks: {\n // 0: {x: 188, y: 99, size: 108}, // yTop = 45\n // 1: {x: 101, y: 185, size: 108},\n // 2: {x: 275, y: 185, size: 108},\n // 3: {x: 188, y: 273, size: 108},\n // 4: {x: 188, y: 452, size: 108} // yBottom = 506\n // }\n // },\n // 6: {\n // keyDimensions: {width: 376, height: 1140},\n // keyCenter: {x: 188, y: 570},\n // clocksCenter: {x: 188, y: 391},\n // clocksCenterDimensions: {width: 284, height: 692},\n // clocks: {\n // 0: {x: 188, y: 99, size: 108}, // yTop = 45\n // 1: {x: 101, y: 185, size: 108},\n // 2: {x: 275, y: 185, size: 108},\n // 3: {x: 188, y: 273, size: 108},\n // 4: {x: 188, y: 452, size: 108},\n // 5: {x: 188, y: 683, size: 108} // yBottom = 737\n // }\n // }\n // },\n Loadout: {\n selections: [\n { value: \"Light\", display: \"Light\" },\n { value: \"Normal\", display: \"Normal\" },\n { value: \"Heavy\", display: \"Heavy\" }\n ],\n levels: [\"BITD.Light\", \"BITD.Normal\", \"BITD.Heavy\", \"BITD.Encumbered\", \"BITD.OverMax\"]\n },\n AttributeTooltips: {\n [AttributeTrait.insight]: \"

Resists consequences from deception or understanding

\",\n [AttributeTrait.prowess]: \"

Resists consequences from physical strain or injury

\",\n [AttributeTrait.resolve]: \"

Resists consequences from mental strain or willpower

\"\n },\n ShortAttributeTooltips: {\n [AttributeTrait.insight]: \"vs. deception or (mis)understanding\",\n [AttributeTrait.prowess]: \"vs. physical strain or injury\",\n [AttributeTrait.resolve]: \"vs. mental strain or willpower\"\n },\n ShortActionTooltips: {\n [ActionTrait.hunt]: \"carefully track a target\",\n [ActionTrait.study]: \"scrutinize details and interpret evidence\",\n [ActionTrait.survey]: \"observe the situation and anticipate outcomes\",\n [ActionTrait.tinker]: \"fiddle with devices and mechanisms\",\n [ActionTrait.finesse]: \"employ dexterity or subtle misdirection\",\n [ActionTrait.prowl]: \"traverse skillfully and quietly\",\n [ActionTrait.skirmish]: \"entangle a target in melee so they can't escape\",\n [ActionTrait.wreck]: \"unleash savage force\",\n [ActionTrait.attune]: \"open your mind to the ghost field or channel nearby electroplasmic energy through your body\",\n [ActionTrait.command]: \"compel swift obedience\",\n [ActionTrait.consort]: \"socialize with friends and contacts\",\n [ActionTrait.sway]: \"influence someone with guile, charm, or argument\"\n },\n ActionTooltips: {\n [ActionTrait.hunt]: \"

When you Hunt, you carefully track a target.

  • You might follow a person or discover their location.
  • You might arrange an ambush.
  • You might attack with precision shooting from a distance.
  • You could try to wield your guns in a melee (but Skirmishing might be better).
\",\n [ActionTrait.study]: \"

When you Study, you scrutinize details and interpret evidence.

  • You might gather information from documents, newspapers, and books.
  • You might do research on an esoteric topic.
  • You might closely analyze a person to detect lies or true feelings.
  • You could try to understand a pressing situation (but Surveying might be better).
\",\n [ActionTrait.survey]: \"

When you Survey, you observe the situation and anticipate outcomes.

  • You might spot telltale signs of trouble before it happens.
  • You might uncover opportunities or weaknesses.
  • You might detect a person's motives or intentions (but Studying might be better).
  • You could try to spot a good ambush point (but Hunting might be better).
\",\n [ActionTrait.tinker]: \"

When you Tinker, you fiddle with devices and mechanisms.

  • You might create a new gadget or alter an existing item.
  • You might pick a lock or crack a safe.
  • You might disable an alarm or trap.
  • You might turn the sparkcraft and electroplasmic devices around the city to your advantage.
  • You could try to control a vehicle with your tech-savvy (but Finessing might be better).
\",\n [ActionTrait.finesse]: \"

When you Finesse, you employ dexterity or subtle misdirection.

  • You might pick someone's pocket.
  • You might handle the controls of a vehicle or direct a mount.
  • You might formally duel an opponent with graceful fighting arts.
  • You could try to leverage agility in a melee (but Skirmishing might be better).
  • You could try to pick a lock (but Tinkering might be better).
\",\n [ActionTrait.prowl]: \"

When you Prowl, you traverse skillfully and quietly.

  • You might sneak past a guard or hide in the shadows.
  • You might run and leap across the rooftops.
  • You might attack someone from hiding with a back-stab or blackjack.
  • You could try to waylay a victim during combat (but Skirmishing might be better).
\",\n [ActionTrait.skirmish]: \"

When you Skirmish, you entangle a target in melee so they can't escape.

  • You might brawl or wrestle with them.
  • You might hack and slash.
  • You might seize or hold a position in battle.
  • You could try to fight in a formal duel (but Finessing might be better).
\",\n [ActionTrait.wreck]: \"

When you Wreck, you unleash savage force.

  • You might smash down a door or wall with a sledgehammer.
  • You might use an explosive to do the same.
  • You might use chaos or sabotage to create distractions or overcome obstacles.
  • You could try to overwhelm an enemy with sheer force in battle (but Skirmishing might be better).
\",\n [ActionTrait.attune]: \"

When you Attune, you open your mind to the ghost field or channel nearby electroplasmic energy through your body.

  • You might communicate with a ghost or understand aspects of spectrology.
  • You might peer into the echo of Doskvol in the ghost field.
  • You could try to perceive beyond sight in order to better understand your situation (but Surveying might be better).
\",\n [ActionTrait.command]: \"

When you Command, you compel swift obedience.

  • You might intimidate or threaten to get what you want.
  • You might lead a gang in a group action.
  • You could try to persuade people by giving orders (but Consorting might be better).
\",\n [ActionTrait.consort]: \"

When you Consort, you socialize with friends and contacts.

  • You might gain access to resources, information, people, or places.
  • You might make a good impression or win someone over with charm and style.
  • You might make new friends or connect with your heritage or background.
  • You could try to direct allies with social pressure (but Commanding might be better).
\",\n [ActionTrait.sway]: \"

When you Sway, you influence someone with guile, charm, or argument.

  • You might lie convincingly.
  • You might persuade someone to do what you want.
  • You might argue a case that leaves no clear rebuttal.
  • You could try to trick people into affection or obedience (but Consorting or Commanding might be better).
\"\n },\n ActionTooltipsGM: {\n [ActionTrait.hunt]: \"

When you Hunt, you carefully track a target.

  • You might follow a person or discover their location.
  • You might arrange an ambush.
  • You might attack with precision shooting from a distance.
  • You could try to wield your guns in a melee (but Skirmishing might be better).

  • How do you hunt them down?
  • What methods do you use?
  • What do you hope to achieve?
\",\n [ActionTrait.study]: \"

When you Study, you scrutinize details and interpret evidence.

  • You might gather information from documents, newspapers, and books.
  • You might do research on an esoteric topic.
  • You might closely analyze a person to detect lies or true feelings.
  • You could try to understand a pressing situation (but Surveying might be better).

  • What do you study?
  • What details or evidence do you scrutinize?
  • What do you hope to understand?
\",\n [ActionTrait.survey]: \"

When you Survey, you observe the situation and anticipate outcomes.

  • You might spot telltale signs of trouble before it happens.
  • You might uncover opportunities or weaknesses.
  • You might detect a person's motives or intentions (but Studying might be better).
  • You could try to spot a good ambush point (but Hunting might be better).

  • How do you survey the situation?
  • Is there anything special you're looking out for?
  • What do you hope to understand?
\",\n [ActionTrait.tinker]: \"

When you Tinker, you fiddle with devices and mechanisms.

  • You might create a new gadget or alter an existing item.
  • You might pick a lock or crack a safe.
  • You might disable an alarm or trap.
  • You might turn the sparkcraft and electroplasmic devices around the city to your advantage.
  • You could try to control a vehicle with your tech-savvy (but Finessing might be better).

  • What do you tinker with?
  • What do you hope to accomplish?
\",\n [ActionTrait.finesse]: \"

When you Finesse, you employ dexterity or subtle misdirection.

  • You might pick someone's pocket.
  • You might handle the controls of a vehicle or direct a mount.
  • You might formally duel an opponent with graceful fighting arts.
  • You could try to leverage agility in a melee (but Skirmishing might be better).
  • You could try to pick a lock (but Tinkering might be better).

  • What do you finesse?
  • What's graceful or subtle about this?
  • What do you hope to achieve?
\",\n [ActionTrait.prowl]: \"

When you Prowl, you traverse skillfully and quietly.

  • You might sneak past a guard or hide in the shadows.
  • You might run and leap across the rooftops.
  • You might attack someone from hiding with a back-stab or blackjack.
  • You could try to waylay a victim during combat (but Skirmishing might be better).

  • How do you prowl?
  • How do you use the environment around you?
  • What do you hope to achieve?
\",\n [ActionTrait.skirmish]: \"

When you Skirmish, you entangle a target in melee so they can't escape.

  • You might brawl or wrestle with them.
  • You might hack and slash.
  • You might seize or hold a position in battle.
  • You could try to fight in a formal duel (but Finessing might be better).

  • How do you skirmish with them?
  • What combat methods do you use?
  • What do you hope to achieve?
\",\n [ActionTrait.wreck]: \"

When you Wreck, you unleash savage force.

  • You might smash down a door or wall with a sledgehammer.
  • You might use an explosive to do the same.
  • You might use chaos or sabotage to create distractions or overcome obstacles.
  • You could try to overwhelm an enemy with sheer force in battle (but Skirmishing might be better).

  • What do you wreck?
  • What force do you bring to bear?
  • What do you hope to accomplish?
\",\n [ActionTrait.attune]: \"

When you Attune, you open your mind to the ghost field or channel nearby electroplasmic energy through your body.

  • You might communicate with a ghost or understand aspects of spectrology.
  • You might peer into the echo of Doskvol in the ghost field.
  • You could try to perceive beyond sight in order to better understand your situation (but Surveying might be better).

  • How do you open your mind to the ghost field?
  • What does that look like?
  • What energy are you attuning to?
  • How are you channeling that energy?
  • What do you hope the energy will do?
\",\n [ActionTrait.command]: \"

When you Command, you compel swift obedience.

  • You might intimidate or threaten to get what you want.
  • You might lead a gang in a group action.
  • You could try to persuade people by giving orders (but Consorting might be better).

  • Who do you command?
  • How do you do it—what's your leverage here?
  • What do you hope they'll do?
\",\n [ActionTrait.consort]: \"

When you Consort, you socialize with friends and contacts.

  • You might gain access to resources, information, people, or places.
  • You might make a good impression or win someone over with charm and style.
  • You might make new friends or connect with your heritage or background.
  • You could try to direct allies with social pressure (but Commanding might be better).

  • Who do you consort with?
  • Where do you meet?
  • What do you talk about?
  • What do you hope to achieve?
\",\n [ActionTrait.sway]: \"

When you Sway, you influence someone with guile, charm, or argument.

  • You might lie convincingly.
  • You might persuade someone to do what you want.
  • You might argue a case that leaves no clear rebuttal.
  • You could try to trick people into affection or obedience (but Consorting or Commanding might be better).

  • Who do you sway?
  • What kind of leverage do you have here?
  • What do you hope they'll do?
\"\n },\n ActionVerbs: {\n [ActionTrait.hunt]: \"hunts\",\n [ActionTrait.study]: \"studies\",\n [ActionTrait.survey]: \"surveys\",\n [ActionTrait.tinker]: \"tinkers\",\n [ActionTrait.finesse]: \"finesses\",\n [ActionTrait.prowl]: \"prowls\",\n [ActionTrait.skirmish]: \"skirmishes\",\n [ActionTrait.wreck]: \"wrecks\",\n [ActionTrait.attune]: \"attunes\",\n [ActionTrait.command]: \"commands\",\n [ActionTrait.consort]: \"consorts\",\n [ActionTrait.sway]: \"sways\"\n },\n ActionPastVerbs: {\n [ActionTrait.hunt]: \"hunted\",\n [ActionTrait.study]: \"studied\",\n [ActionTrait.survey]: \"surveyed\",\n [ActionTrait.tinker]: \"tinkered\",\n [ActionTrait.finesse]: \"finessed\",\n [ActionTrait.prowl]: \"prowled\",\n [ActionTrait.skirmish]: \"skirmished\",\n [ActionTrait.wreck]: \"wrecked\",\n [ActionTrait.attune]: \"attuned\",\n [ActionTrait.command]: \"commanded\",\n [ActionTrait.consort]: \"consorted\",\n [ActionTrait.sway]: \"swayed\"\n },\n TraumaTooltips: {\n Cold: \"You're not moved by emotional appeals or social bonds.\",\n Haunted: \"You're often lost in reverie, reliving past horrors, seeing things.\",\n Obsessed: \"You're enthralled by one thing: an activity, a person, an ideology.\",\n Paranoid: \"You imagine danger everywhere; you can't trust others.\",\n Reckless: \"You have little regard for your own safety or best interests.\",\n Soft: \"You lose your edge; you become sentimental, passive, gentle.\",\n Unstable: \"Your emotional state is volatile. You can instantly rage, or fall into despair, act impulsively, or freeze up.\",\n Vicious: \"You seek out opportunities to hurt people, even for no good reason.\",\n Chaotic: \"You've become so detached from the living that inhibitions fall away, leaving you impulsive and unpredictable.\",\n Destructive: \"You are easily angered by reminders of all you've lost, and can lash out violently against the trappings of the living world.\",\n Furious: \"Your ravaged soul is fertile kindling for rage, and your fury is easily ignited.\",\n Obsessive: \"Your wants and desires become fixations and compulsions, driving you to achieve them at any cost.\",\n Territorial: \"You see some place as yours: Trespassers are dealt with, and even guests must respect your claim.\",\n Savage: \"When moved to anger or violence, you act with cruelty and feral malevolence.\",\n Clanking: \"Your frame has developed a persistent metallic clang with each step, making stealth difficult.\",\n Leaking: \"You continuously leak oil, leviathan blood, distilled electroplasm or some other potentially-dangerous substance.\",\n Fixated: \"You have become fixated on a function of your choice, and lose all memory of your humanity when you pursue it.\",\n Smoking: \"Your frame exudes a constant miasma of acrid, foul-smelling smoke.\",\n Sparking: \"Electroplasmic energy erupts in arcing sparks from joints and junctions throughout your frame.\",\n Ruthless: \"You lose any sense of humanity when indulging your Vice or pursuing your most important goal.\",\n Secretive: \"Knowledge has become so precious to you, that even your closest allies are on a need-to-know basis.\"\n },\n EdgeTooltips: {\n Fearsome: \"

The cohort is terrifying in aspect and reputation.

\",\n Independent: \"

The cohort can be trusted to make good decisions and act on their own initiative in the absence of direct orders.

\",\n Loyal: \"

The cohort can't be bribed or turned against you.

\",\n Tenacious: \"

The cohort won't be deterred from a task.

\",\n Nimble: \"

The vehicle handles easily. Consider this an assist for tricky maneuvers.

\",\n Simple: \"

The vehicle is easy to repair. Remove all of its Harm during downtime

\",\n Sturdy: \"

The vehicle keeps operating even when Broken.

\",\n \"Arrow-Swift\": \"

Your pet gains Potency when tracking or fighting the supernatural.

It can move extremely quickly, outpacing any other creature or vehicle.

\",\n \"Ghost Form\": \"

Your pet gains Potency when tracking or fighting the supernatural.

It can transform into electroplasmic vapor as if it were a spirit.

\",\n \"Mind Link\": \"

Your pet gains Potency when tracking or fighting the supernatural.

You and your pet can share senses and thoughts telepathically.

\"\n },\n FlawTooltips: {\n Principled: \"

The cohort has an ethic or values that it won't betray.

\",\n Savage: \"

The cohort is excessively violent and cruel.

\",\n Unreliable: \"

The cohort isn't always available, due to other obligations, stupefaction from their vices, etc.

\",\n Wild: \"

The cohort is drunken, debauched, and loud-mouthed.

\",\n Costly: \"

The vehicle costs 1 Coin per downtime to keep it in operation.

\",\n Distinct: \"

The vehicle has memorable features. Take +1 Heat when you use it on a score.

\",\n Finicky: \"

The vehicle has quirks that only one person understands. When operated without them, it has -1 Quality.

\"\n },\n QualityDescriptors: [\n \"Poor\",\n \"Adequate\",\n \"Good\",\n \"Excellent\",\n \"Superior\",\n \"Impeccable\",\n \"Legendary\"\n ],\n ForceDescriptors: [\n \"Weak\",\n \"Moderate\",\n \"Strong\",\n \"Serious\",\n \"Powerful\",\n \"Overwhelming\",\n \"Devastating\"\n ],\n VehicleDescriptors: [\n \"A Vehicle?\",\n \"A Vehicle\",\n \"A Respectable Vehicle\",\n \"A Respected Vehicle\",\n \"A Precision-Built Vehicle\",\n \"A Powerful, Advanced Vehicle\",\n \"A Uniquely Strong, Extremely Advanced Vehicle\"\n ],\n PetDescriptors: [\n \"A Weak Hunting Pet\",\n \"A Hunting Pet\",\n \"A Strong Hunting Pet\",\n \"A Serious Hunting Pet\",\n \"A Powerful Hunting Pet\",\n \"An Overwhelmingly Powerful Hunting Pet\",\n \"A Devastating Hunting Pet\"\n ],\n AreaExamples: [\n \"a closet\",\n \"a small room\",\n \"a large room\",\n \"several rooms\",\n \"a small building\",\n \"a large building\",\n \"a city block\"\n ],\n ScaleExamples: [\n \"(1 or 2 members)\",\n \"(3 - 6 members)\",\n \"(~12 members)\",\n \"(~20 members)\",\n \"(~40 members)\",\n \"(~80 members)\",\n \"(~160 members)\"\n ],\n ScaleSizes: [\n \"A Few \",\n \"A Small Gang of \",\n \"A Gang of \",\n \"A Large Gang of \",\n \"A Small Army of \",\n \"An Army of \",\n \"A Massive Army of \"\n ],\n DiceOddsStandard: [\n { crit: 0, success: 2.8, partial: 22.2, fail: 75 },\n { crit: 0, success: 16.7, partial: 33.3, fail: 50 },\n { crit: 2.8, success: 27.8, partial: 44.4, fail: 25 },\n { crit: 7.4, success: 34.7, partial: 45.4, fail: 12.5 },\n { crit: 13.2, success: 38.6, partial: 42, fail: 6.3 },\n { crit: 19.6, success: 40.2, partial: 37.1, fail: 3.1 },\n { crit: 26.3, success: 40.2, partial: 31.9, fail: 1.6 },\n { crit: 33, success: 39.1, partial: 27.1, fail: 0.8 },\n { crit: 39.5, success: 37.2, partial: 22.9, fail: 0.4 },\n { crit: 45.7, success: 34.9, partial: 19.2, fail: 0.2 },\n { crit: 51.5, success: 32.3, partial: 16.1, fail: 0.1 },\n { crit: 56.9, success: 29.6, partial: 13.4, fail: 0 },\n { crit: 61.9, success: 26.9, partial: 11.2, fail: 0 },\n { crit: 66.3, success: 24.3, partial: 9.3, fail: 0 },\n { crit: 70.4, success: 21.8, partial: 7.8, fail: 0 },\n { crit: 74, success: 19.5, partial: 6.5, fail: 0 },\n { crit: 77.3, success: 17.3, partial: 5.4, fail: 0 },\n { crit: 80.2, success: 15.3, partial: 4.5, fail: 0 },\n { crit: 82.7, success: 13.5, partial: 3.8, fail: 0 },\n { crit: 85, success: 11.9, partial: 3.1, fail: 0 },\n { crit: 87, success: 10.4, partial: 2.6, fail: 0 }\n ],\n DiceOddsResistance: [\n [0, 2.8, 8.3, 13.9, 19.4, 25, 30.6],\n [0, 16.7, 16.7, 16.7, 16.6, 16.7, 16.7],\n [2.8, 27.8, 25, 19.4, 13.9, 8.3, 2.8],\n [7.4, 34.7, 28.3, 17.1, 8.8, 3.2, 0.5],\n [13.2, 38.6, 28.5, 13.5, 5, 1.2, 0.1],\n [19.6, 40.2, 27, 10.1, 2.7, 0.4, 0],\n [26.3, 40.2, 24.7, 7.2, 1.4, 0.1, 0]\n ],\n ExperienceClues: {\n Scoundrel: [\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n Crew: [\n \"You contended with challenges above your current station.\",\n \"You bolstered your crew's reputation, or developed a new one.\",\n \"You expressed the goals, drives, inner conflict, or essential nature of the crew.\"\n ]\n },\n GatherInfoQuestions: {\n Cutter: [\n \"How can I hurt them?\",\n \"Who's most afraid of me?\",\n \"Who's most dangerous here?\",\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What's really going on here?\"\n ],\n Hound: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"Where are they vulnerable?\",\n \"Where did [X] go?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n Leech: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What can I tinker with here?\",\n \"What might happen if I [X]?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n Lurk: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What should I look out for?\",\n \"What's the best way in?\",\n \"Where can I hide here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n Slide: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What are they really feeling?\",\n \"What do they really care about?\",\n \"How can I blend in here?\",\n \"What's really going on here?\"\n ],\n Spider: [\n \"What do they want most?\",\n \"What should I look out for?\",\n \"Where's the leverage here?\",\n \"How can I discover [X]?\",\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What's really going on here?\"\n ],\n Whisper: [\n \"What is arcane or weird here?\",\n \"What echoes in the ghost field?\",\n \"What is hidden or lost here?\",\n \"What do they intend to do?\",\n \"What drives them to do this?\",\n \"How can I reveal [X]?\",\n \"What's really going on here?\"\n ],\n Ghost: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n Hull: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really doing?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n Vampire: [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ]\n },\n Playbooks: {\n Cutter: {\n \"system.experience_clues\": [\n \"You addressed a challenge with violence or coercion.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"How can I hurt them?\",\n \"Who's most afraid of me?\",\n \"Who's most dangerous here?\",\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Battleborn\"\n },\n Hound: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/hound-trans.svg\",\n \"system.tagline\": \"A Deadly Sharpshooter & Tracker\",\n // \"system.acquaintances_name\": \"Deadly Friends & Rivals\",\n \"system.friends_name\": \"Deadly Friends\",\n \"system.rivals_name\": \"Deadlier Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.insight.hunt.value\": 2,\n \"system.attributes.insight.survey.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with tracking or violence.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"Where are they vulnerable?\",\n \"Where did [X] go?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Sharpshooter\"\n },\n Leech: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/leech-trans.svg\",\n \"system.tagline\": \"A Saboteur & Technician\",\n // \"system.acquaintances_name\": \"Clever Friends & Rivals\",\n \"system.friends_name\": \"Clever Friends\",\n \"system.rivals_name\": \"Cleverer Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.insight.tinker.value\": 2,\n \"system.attributes.prowess.wreck.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with technical skill or mayhem.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What can I tinker with here?\",\n \"What might happen if I [X]?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Alchemist\"\n },\n Lurk: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/lurk-trans.svg\",\n \"system.tagline\": \"A Stealthy Infiltrator & Burglar\",\n // \"system.acquaintances_name\": \"Shady Friends & Rivals\",\n \"system.friends_name\": \"Shady Friends\",\n \"system.rivals_name\": \"Shadier Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.prowess.prowl.value\": 2,\n \"system.attributes.prowess.finesse.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with stealth or evasion.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What should I look out for?\",\n \"What's the best way in?\",\n \"Where can I hide here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Infiltrator\"\n },\n Slide: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/slide-trans.svg\",\n \"system.tagline\": \"A Subtle Manipulator & Spy\",\n // \"system.acquaintances_name\": \"Sly Friends & Rivals\",\n \"system.friends_name\": \"Sly Friends\",\n \"system.rivals_name\": \"Slyer Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.resolve.sway.value\": 2,\n \"system.attributes.resolve.consort.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with deception or influence.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"Are they telling the truth?\",\n \"What are they really feeling?\",\n \"What do they really care about?\",\n \"How can I blend in here?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Rook's Gambit\"\n },\n Spider: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/spider-trans.svg\",\n \"system.tagline\": \"A Devious Mastermind\",\n // \"system.acquaintances_name\": \"Shrewd Friends & Rivals\",\n \"system.friends_name\": \"Shrewd Friends\",\n \"system.rivals_name\": \"Very Shrewd Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.resolve.consort.value\": 2,\n \"system.attributes.insight.study.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with calculation or conspiracy.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they want most?\",\n \"What should I look out for?\",\n \"Where's the leverage here?\",\n \"How can I discover [X]?\",\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Foresight\"\n },\n Whisper: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/whisper-trans.svg\",\n \"system.tagline\": \"An Arcane Adept & Channeler\",\n // \"system.acquaintances_name\": \"Strange Friends & Rivals\",\n \"system.friends_name\": \"Strange Friends\",\n \"system.rivals_name\": \"Stranger Rivals\",\n \"system.starting_stats.chargen\": {\n \"system.attributes.resolve.attune.value\": 2,\n \"system.attributes.insight.study.value\": 1\n },\n \"system.experience_clues\": [\n \"You addressed a challenge with knowledge or arcane power.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice or traumas during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Reckless\", \"Soft\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What is arcane or weird here?\",\n \"What echoes in the ghost field?\",\n \"What is hidden or lost here?\",\n \"What do they intend to do?\",\n \"What drives them to do this?\",\n \"How can I reveal [X]?\",\n \"What's really going on here?\"\n ],\n \"system.suggested_ability\": \"Compel\"\n },\n Ghost: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/ghost-trans.svg\",\n \"system.tagline\": \"A Vengeful Disembodied Spirit\",\n \"system.acquaintances_name\": \"Enemies & Rivals\",\n \"system.starting_stats.add\": {\n \"system.attributes.insight.hunt.value\": 1,\n \"system.attributes.prowess.prowl.value\": 1,\n \"system.attributes.resolve.attune.value\": 1\n },\n \"system.experience_clues\": [\n \"You exacted vengeance upon those whom you deem deserving.\",\n \"You expressed your outrage or anger, or settled scores from your heritage, or background.\",\n \"You struggled with issues from your need or glooms during the session.\"\n ],\n \"system.trauma_conditions\": [\"Chaotic\", \"Destructive\", \"Furious\", \"Obsessive\", \"Territorial\", \"Savage\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.auto_abilities\": [\"Ghost Form\"]\n },\n Hull: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/hull-trans.svg\",\n \"system.tagline\": \"An Animated Spark-Craft Frame\",\n \"system.acquaintances_name\": \"Master\",\n \"system.starting_stats.add\": {\n \"system.attributes.prowess.skirmish.value\": 1,\n \"system.attributes.resolve.attune.value\": 1\n },\n \"system.experience_clues\": [\n \"You fulfilled your functions despite difficulty or danger.\",\n \"You suppressed or ignored your former human beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your wear during the session.\"\n ],\n \"system.trauma_conditions\": [\"Clanking\", \"Leaking\", \"Fixated\", \"Smoking\", \"Sparking\", \"Unstable\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really doing?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.auto_abilities\": [\"Automaton\"]\n },\n Vampire: {\n \"system.bgImg\": \"systems/eunos-blades/assets/icons/class-icons/vampire-trans.svg\",\n \"system.tagline\": \"An Animated Undead Body\",\n \"system.acquaintances_name\": \"Dark Servants\",\n \"system.starting_stats.add\": {\n \"system.attributes.insight.hunt.value\": 1,\n \"system.attributes.prowess.prowl.value\": 1,\n \"system.attributes.prowess.skirmish.value\": 1,\n \"system.attributes.resolve.attune.value\": 1,\n \"system.attributes.resolve.command.value\": 1,\n \"system.attributes.resolve.sway.value\": 1\n },\n \"system.experience_clues\": [\n \"You displayed your dominance or slayed without mercy.\",\n \"You expressed your beliefs, drives, heritage, or background.\",\n \"You struggled with issues from your vice, traumas, or strictures during the session.\"\n ],\n \"system.trauma_conditions\": [\"Cold\", \"Haunted\", \"Obsessed\", \"Paranoid\", \"Ruthless\", \"Secretive\", \"Unstable\", \"Vicious\"],\n \"system.gather_info_questions\": [\n \"What do they intend to do?\",\n \"How can I get them to [X]?\",\n \"What are they really feeling?\",\n \"What should I lookout for?\",\n \"Where's the weakness here?\",\n \"How can I find [X]?\",\n \"What's really going on here?\"\n ],\n \"system.auto_abilities\": [\"Undead\"]\n }\n },\n ClockSizes: [1, 2, 3, 4, 5, 6, 8, 10, 12],\n ActorTypes: [\n BladesActorType.pc,\n BladesActorType.npc,\n BladesActorType.crew,\n BladesActorType.faction\n ],\n ItemTypes: [\n BladesItemType.ability,\n BladesItemType.background,\n BladesItemType.clock_keeper,\n BladesItemType.cohort_gang,\n BladesItemType.cohort_expert,\n BladesItemType.crew_ability,\n BladesItemType.crew_reputation,\n BladesItemType.crew_playbook,\n BladesItemType.crew_upgrade,\n BladesItemType.feature,\n BladesItemType.gm_tracker,\n BladesItemType.heritage,\n BladesItemType.gear,\n BladesItemType.playbook,\n BladesItemType.preferred_op,\n BladesItemType.stricture,\n BladesItemType.vice,\n BladesItemType.project,\n BladesItemType.ritual,\n BladesItemType.design,\n BladesItemType.location,\n BladesItemType.score\n ],\n SimpleItemTypes: [\n BladesItemType.background,\n BladesItemType.crew_reputation,\n BladesItemType.feature,\n BladesItemType.heritage,\n BladesItemType.preferred_op,\n BladesItemType.stricture\n ],\n Attribute: [\n AttributeTrait.insight,\n AttributeTrait.prowess,\n AttributeTrait.resolve\n ],\n Action: {\n [AttributeTrait.insight]: [ActionTrait.hunt, ActionTrait.study, ActionTrait.survey, ActionTrait.tinker],\n [AttributeTrait.prowess]: [ActionTrait.finesse, ActionTrait.prowl, ActionTrait.skirmish, ActionTrait.wreck],\n [AttributeTrait.resolve]: [ActionTrait.attune, ActionTrait.command, ActionTrait.consort, ActionTrait.sway]\n },\n Vices: [\n Vice.Faith,\n Vice.Gambling,\n Vice.Luxury,\n Vice.Obligation,\n Vice.Pleasure,\n Vice.Stupor,\n Vice.Weird,\n Vice.Worship,\n Vice.Living_Essence,\n Vice.Life_Essence,\n Vice.Electroplasmic_Power\n ]\n};\n// #endregion\n// #region RANDOMIZER DATA\nconst Randomizers = {\n NPC: {\n heritage: [\n \"Akorosi\",\n \"Akorosi\",\n \"Akorosi\",\n \"Akorosi\",\n \"Akorosi\",\n \"Akorosi\",\n \"Dagger Islander\",\n \"Iruvian\",\n \"Severosi\",\n \"Skovlander\",\n \"Skovlander\",\n \"Tycherosi\"\n ],\n background: [\n \"Academic\",\n \"Academic\",\n \"Academic\",\n \"Labor\",\n \"Labor\",\n \"Labor\",\n \"Labor\",\n \"Law\",\n \"Law\",\n \"Law\",\n \"Military\",\n \"Military\",\n \"Military\",\n \"Military\",\n \"Military\",\n \"New Money\",\n \"New Money\",\n \"Old Money\",\n \"Old Money\",\n \"Politics\",\n \"Politics\",\n \"Trade\",\n \"Trade\",\n \"Trade\",\n \"Underworld\",\n \"Underworld\",\n \"Underworld\",\n \"Underworld\",\n \"Underworld\",\n \"Weird\"\n ],\n gender: [\n \"M\",\n \"M\",\n \"M\",\n \"M\",\n \"F\",\n \"F\",\n \"F\",\n \"U\",\n \"X\"\n ],\n appearance: [\n \"Athletic\",\n \"Beard\",\n \"Bony\",\n \"Chiseled\",\n \"Crippled / Prosthetic\",\n \"Cute\",\n \"Dark\",\n \"Delicate\",\n \"Disfigured / Maimed\",\n \"Elegant\",\n \"Fair\",\n \"Glasses / Monocle\",\n \"Handsome\",\n \"Large\",\n \"Long Hair\",\n \"Lovely\",\n \"Old\",\n \"Plain\",\n \"Plump\",\n \"Rough\",\n \"Scarred\",\n \"Sexy\",\n \"Shaved Bald\",\n \"Short\",\n \"Slim\",\n \"Stooped\",\n \"Stout\",\n \"Strange\",\n \"Striking\",\n \"Stylish\",\n \"Tall\",\n \"Tattooed\",\n \"Weathered\",\n \"Wig\",\n \"Wild\",\n \"Wiry\",\n \"Worn\",\n \"Young\"\n ],\n goal: [\n \"Achievement\",\n \"Authority\",\n \"Change\",\n \"Chaos / Destruction\",\n \"Control\",\n \"Cooperation\",\n \"Freedom\",\n \"Happiness\",\n \"Infamy / Fear\",\n \"Justice\",\n \"Knowledge\",\n \"Love\",\n \"Pleasure\",\n \"Power\",\n \"Prestige / Fame\",\n \"Respect\",\n \"Revenge\",\n \"Wealth\"\n ],\n method: [\n \"Alchemy\",\n \"Arcane\",\n \"Blackmail\",\n \"Chaos\",\n \"Commerce\",\n \"Espionage\",\n \"Hard Work\",\n \"Law / Politics\",\n \"Manipulation\",\n \"Negotiation\",\n \"Sabotage\",\n \"Strategy\",\n \"Study\",\n \"Subterfuge\",\n \"Teamwork\",\n \"Theft\",\n \"Threats\",\n \"Violence\"\n ],\n profession: [\n \"Advocate\",\n \"Apiarist\",\n \"Architect\",\n \"Artist\",\n \"Author\",\n \"Bailiff\",\n \"Baker\",\n \"Baker\",\n \"Baker\",\n \"Banker\",\n \"Barber\",\n \"Barber\",\n \"Barber\",\n \"Blacksmith\",\n \"Blacksmith\",\n \"Blacksmith\",\n \"Bounty Hunter\",\n \"Brewer\",\n \"Brewer\",\n \"Brewer\",\n \"Butcher\",\n \"Butcher\",\n \"Butcher\",\n \"Captain\",\n \"Carpenter\",\n \"Carpenter\",\n \"Carpenter\",\n \"Cartwright\",\n \"Cartwright\",\n \"Cartwright\",\n \"Chandler\",\n \"Chandler\",\n \"Chandler\",\n \"Clerk\",\n \"Clerk\",\n \"Clerk\",\n \"Clockmaker\",\n \"Cobbler\",\n \"Cobbler\",\n \"Cobbler\",\n \"Composer\",\n \"Cooper\",\n \"Cooper\",\n \"Cooper\",\n \"Courtesan\",\n \"Criminal\",\n \"Criminal\",\n \"Criminal\",\n \"Cultivator\",\n \"Cultivator\",\n \"Cultivator\",\n \"Diplomat\",\n \"Driver\",\n \"Driver\",\n \"Driver\",\n \"Dyer\",\n \"Dyer\",\n \"Dyer\",\n \"Embroiderer\",\n \"Embroiderer\",\n \"Embroiderer\",\n \"Explorer\",\n \"Fishmonger\",\n \"Fishmonger\",\n \"Fishmonger\",\n \"Furrier\",\n \"Glass Blower\",\n \"Goat Herd\",\n \"Goat Herd\",\n \"Goat Herd\",\n \"Gondolier\",\n \"Gondolier\",\n \"Gondolier\",\n \"Guard\",\n \"Guard\",\n \"Guard\",\n \"Jailer\",\n \"Jeweler\",\n \"Journalist\",\n \"Leatherworker\",\n \"Leatherworker\",\n \"Leatherworker\",\n \"Leech\",\n \"Locksmith\",\n \"Magistrate\",\n \"Mason\",\n \"Mason\",\n \"Mason\",\n \"Merchant\",\n \"Merchant\",\n \"Merchant\",\n \"Messenger\",\n \"Messenger\",\n \"Messenger\",\n \"Musician\",\n \"Physicker\",\n \"Plumber\",\n \"Printer\",\n \"Rail Jack\",\n \"Roofer\",\n \"Roofer\",\n \"Roofer\",\n \"Ropemaker\",\n \"Ropemaker\",\n \"Ropemaker\",\n \"Rug Maker\",\n \"Rug Maker\",\n \"Rug Maker\",\n \"Sailor\",\n \"Sailor\",\n \"Sailor\",\n \"Scholar\",\n \"Scribe\",\n \"Servant\",\n \"Servant\",\n \"Servant\",\n \"Shipwright\",\n \"Shipwright\",\n \"Shipwright\",\n \"Soldier\",\n \"Sparkwright\",\n \"Spirit Warden\",\n \"Steward\",\n \"Tailor\",\n \"Tailor\",\n \"Tailor\",\n \"Tanner\",\n \"Tanner\",\n \"Tanner\",\n \"Tax Collector\",\n \"Tinkerer\",\n \"Tinkerer\",\n \"Tinkerer\",\n \"Treasurer\",\n \"Vendor\",\n \"Vendor\",\n \"Vendor\",\n \"Weaver\",\n \"Weaver\",\n \"Weaver\",\n \"Whisper\",\n \"Woodworker\",\n \"Woodworker\",\n \"Woodworker\"\n ],\n trait: [\n \"Arcane\",\n \"Arrogant\",\n \"Artistic\",\n \"Bold\",\n \"Brash\",\n \"Brave\",\n \"Calculating\",\n \"Calm\",\n \"Candid\",\n \"Careless\",\n \"Cautious\",\n \"Cavalier\",\n \"Charming\",\n \"Cold\",\n \"Commanding\",\n \"Compassionate\",\n \"Confident\",\n \"Connected\",\n \"Cooperative\",\n \"Creative\",\n \"Cruel\",\n \"Cultured\",\n \"Daring\",\n \"Defiant\",\n \"Dishonest\",\n \"Dramatic\",\n \"Elitist\",\n \"Enigmatic\",\n \"Enthusiastic\",\n \"Erudite\",\n \"Experienced\",\n \"Fierce\",\n \"Flexible\",\n \"Friendly\",\n \"Gracious\",\n \"Greedy\",\n \"Haunted\",\n \"Insightful\",\n \"Kind\",\n \"Melancholy\",\n \"Moody\",\n \"Obsessive\",\n \"Paranoid\",\n \"Patient\",\n \"Popular\",\n \"Principled\",\n \"Proud\",\n \"Quiet\",\n \"Reckless\",\n \"Respected\",\n \"Ruthless\",\n \"Sadistic\",\n \"Savage\",\n \"Secretive\",\n \"Shrewd\",\n \"Sincere\",\n \"Sneaky\",\n \"Sophisticated\",\n \"Strange\",\n \"Stylish\",\n \"Subtle\",\n \"Suspicious\",\n \"Tough\",\n \"Vain\",\n \"Vengeful\",\n \"Vicious\",\n \"Visionary\",\n \"Volatile\",\n \"Weird\",\n \"Wise\"\n ],\n interests: [\n \"Alchemy, medicine\",\n \"Antiques, artifacts, curios\",\n \"Arcane books, rituals\",\n \"Architecture, furnishings\",\n \"Church of Ecstasy\",\n \"Cooking, gardening\",\n \"Craft (leatherwork, etc.)\",\n \"Demon lore, legends\",\n \"Drugs, essences, tobacco\",\n \"Essences, alchemy\",\n \"Exploration, adventure\",\n \"Fine arts, opera, theater\",\n \"Fine clothes, jewelry, furs\",\n \"Fine food, restaurants\",\n \"Fine whiskey, wine, beer\",\n \"Forgotten gods\",\n \"Gadgets, new technology\",\n \"Gambling, cards, dice\",\n \"History, legends\",\n \"Horses, riding\",\n \"Hunting, shooting\",\n \"Lovers, romance, trysts\",\n \"Music, instruments, dance\",\n \"Natural philosophy\",\n \"Painting, drawing, sculpture\",\n \"Parties, social events\",\n \"Path of Echoes\",\n \"Pets (birds, dogs, cats)\",\n \"Pit-fighting, duels\",\n \"Poetry, novels, writing\",\n \"Politics, journalism\",\n \"Pre-cataclysm legends\",\n \"Ships, boating\",\n \"Spectrology, electroplasm\",\n \"Weapons collector\",\n \"Weeping Lady, charity\"\n ],\n quirk: [\n \"A fraud. Some important aspect is fabricated.\",\n \"Bigoted against culture / belief / social class.\",\n \"Black sheep / outcast from family or organization.\",\n \"Blind to flaws in friends, allies, family, etc.\",\n \"Celebrity. Popularized in print / song / theater.\",\n \"Concerned with appearances, gossip, peers.\",\n \"Cursed, haunted, harassed by spirits or demon.\",\n \"Deeply traditional. Opposed to new ideas.\",\n \"Devoted to their family.\",\n \"Drug / alcohol abuser. Often impaired by their vice.\",\n \"Extensive education on every scholarly subject.\",\n \"Has chronic illness that requires frequent care.\",\n \"Holds their position due to blackmail.\",\n \"Holds their position to spy for another faction.\",\n \"In prison or under noble's house arrest.\",\n \"Inherited their position. May not deserve / want it.\",\n \"Intense, unreasonable phobia or loathing.\",\n \"Involved with war crimes from the Unity War.\",\n \"Is blindly faithful to an ideal, group, or tradition.\",\n \"Keeps detailed journals, notes, records, ledgers.\",\n \"Leads a double life using cover identity.\",\n \"Married into important / powerful family.\",\n \"Massive debts (to banks / criminals / family)\",\n \"Once hollowed, then restored. Immune to spirits.\",\n \"Proud of heritage, traditions, native language.\",\n \"Reclusive. Prefers to interact via messengers.\",\n \"Relies on council to make decisions.\",\n \"Revolutionary. Plots against the Imperium.\",\n \"Scandalous reputation (deserved or not).\",\n \"Secretly (openly?) controlled by possessing spirit.\",\n \"Serves a demon's agenda (knowingly or not).\",\n \"Spotless reputation. Highly regarded.\",\n \"Superstitious. Believes in signs, magic numbers.\",\n \"Surrounded by sycophants, supplicants, toadies.\",\n \"Visionary. Holds radical views for future.\",\n \"Well-traveled. Connections outside Doskvol.\"\n ],\n style: {\n male: [\n \"Apron\",\n \"Cane\",\n \"Collared Shirt\",\n \"Crutches\",\n \"Eelskin Bodysuit\",\n \"Face Mask\",\n \"Fitted Leggings\",\n \"Heavy Cloak\",\n \"Heavy Gloves\",\n \"Hide & Furs\",\n \"Hood & Veil\",\n \"Hooded Coat\",\n \"Knit Cap\",\n \"Leathers\",\n \"Long Coat\",\n \"Long Scarf\",\n \"Loose Silks\",\n \"Mask & Robes\",\n \"Rough Tunic\",\n \"Sharp Trousers\",\n \"Short Cloak\",\n \"Slim Jacket\",\n \"Soft Boots\",\n \"Suit & Vest\",\n \"Suspenders\",\n \"Tall Boots\",\n \"Tatters\",\n \"Thick Greatcoat\",\n \"Tool Belt\",\n \"Tricorn Hat\",\n \"Uniform\",\n \"Waxed Coat\",\n \"Wheelchair\",\n \"Wide Belt\",\n \"Work Boots\"\n ],\n female: [\n \"Apron\",\n \"Cane\",\n \"Crutches\",\n \"Eelskin Bodysuit\",\n \"Face Mask\",\n \"Fitted Dress\",\n \"Fitted Leggings\",\n \"Heavy Cloak\",\n \"Heavy Gloves\",\n \"Hide & Furs\",\n \"Hood & Veil\",\n \"Hooded Coat\",\n \"Knit Cap\",\n \"Leathers\",\n \"Long Coat\",\n \"Long Scarf\",\n \"Loose Silks\",\n \"Mask & Robes\",\n \"Rough Tunic\",\n \"Sharp Trousers\",\n \"Short Cloak\",\n \"Skirt & Blouse\",\n \"Slim Jacket\",\n \"Soft Boots\",\n \"Suspenders\",\n \"Tall Boots\",\n \"Tatters\",\n \"Thick Greatcoat\",\n \"Tool Belt\",\n \"Uniform\",\n \"Waxed Coat\",\n \"Wheelchair\",\n \"Wide Belt\",\n \"Work Boots\"\n ]\n },\n name_title: [\n \"Adept\",\n \"Archivist\",\n \"Captain\",\n \"Charter\",\n \"Scrivener\"\n ],\n name_first: {\n male: [\n \"Abel\",\n \"Abenthy\",\n \"Adric\",\n \"Airic\",\n \"Alabaster\",\n \"Alastair\",\n \"Aldo\",\n \"Alen\",\n \"Aleph\",\n \"Ambrose\",\n \"Amosen\",\n \"Andal\",\n \"Andrel\",\n \"Anton\",\n \"Aquilla\",\n \"Aradan\",\n \"Aram\",\n \"Archibald\",\n \"Archie\",\n \"Arden\",\n \"Arliden\",\n \"Arlyn\",\n \"Armand\",\n \"Arquo\",\n \"Arrell\",\n \"Arvus\",\n \"Asher\",\n \"Aurelio\",\n \"Benedict\",\n \"Bolster\",\n \"Brace\",\n \"Bran\",\n \"Brance\",\n \"Branon\",\n \"Bricks\",\n \"Brock\",\n \"Brutus\",\n \"Caius\",\n \"Carro\",\n \"Casian\",\n \"Cato\",\n \"Cavelle\",\n \"Cedric\",\n \"Chance\",\n \"Chauncey\",\n \"Cid\",\n \"Clave\",\n \"Cliff\",\n \"Cornelius\",\n \"Cross\",\n \"Crowl\",\n \"Cym\",\n \"Cyrus\",\n \"Declan\",\n \"Del\",\n \"Drav\",\n \"Drazhan\",\n \"Drem\",\n \"Edlun\",\n \"Edmund\",\n \"Edrom\",\n \"Edwin\",\n \"Elan\",\n \"Elend\",\n \"Elias\",\n \"Elodin\",\n \"Ephrim\",\n \"Erasmus\",\n \"Eremon\",\n \"Ethan\",\n \"Everitt\",\n \"Feldspar\",\n \"Fero\",\n \"Finn\",\n \"Fisher\",\n \"Galen\",\n \"Gallahad\",\n \"Garner\",\n \"Gilbert\",\n \"Glint\",\n \"Gnik\",\n \"Gregalos\",\n \"Grey\",\n \"Greyson\",\n \"Grifter\",\n \"Grine\",\n \"Gristofer\",\n \"Hadrian\",\n \"Hagran\",\n \"Hammond\",\n \"Hix\",\n \"Holtz\",\n \"Hugo\",\n \"Iden\",\n \"Irton\",\n \"Isaac\",\n \"Ivellios\",\n \"Jabari\",\n \"Jericho\",\n \"Jerod\",\n \"Kazimir\",\n \"Kellan\",\n \"Kelvyn\",\n \"Kelyr\",\n \"Khafra\",\n \"Kobb\",\n \"Kristov\",\n \"Kyrilu\",\n \"Lael\",\n \"Lafayette\",\n \"Laudius\",\n \"Lawrence\",\n \"Leif\",\n \"Lem\",\n \"Lenny\",\n \"Logan\",\n \"Lucas\",\n \"Lucius\",\n \"Lysander\",\n \"Milos\",\n \"Mord\",\n \"Morketh\",\n \"Morlan\",\n \"Myre\",\n \"Narcus\",\n \"Nehi\",\n \"Noggs\",\n \"Norton\",\n \"Obel\",\n \"Obelas\",\n \"Octavius\",\n \"Odelay\",\n \"Orem\",\n \"Orlan\",\n \"Orth\",\n \"Orton\",\n \"Pavel\",\n \"Perceval\",\n \"Percival\",\n \"Peregrine\",\n \"Phin\",\n \"Phineas\",\n \"Porto\",\n \"Preston\",\n \"Primo\",\n \"Quess\",\n \"Quill\",\n \"Rafe\",\n \"Rasmus\",\n \"Raul\",\n \"Resh\",\n \"Rias\",\n \"Ring\",\n \"Rivallo\",\n \"Rodmund\",\n \"Roethe\",\n \"Roose\",\n \"Roric\",\n \"Sethla\",\n \"Silas\",\n \"Sindri\",\n \"Snitch\",\n \"Sol\",\n \"Solomon\",\n \"Sprig\",\n \"Stavrul\",\n \"Stellan\",\n \"Stev\",\n \"Sym\",\n \"Tacitus\",\n \"Tarn\",\n \"Taylor\",\n \"Thackeray\",\n \"Thaddeus\",\n \"Thane\",\n \"Thelian\",\n \"Theo\",\n \"Theron\",\n \"Thurston\",\n \"Timoth\",\n \"Tisk\",\n \"Tocker\",\n \"Tristero\",\n \"Ulric\",\n \"Vask\",\n \"Veleris\",\n \"Ventaro\",\n \"Virgil\",\n \"Vond\",\n \"Wax\",\n \"Wayne\",\n \"Weaver\",\n \"Wester\",\n \"Winsley\"\n ],\n female: [\n \"Adaire\",\n \"Adelaide\",\n \"Adella\",\n \"Adroit\",\n \"Ailen\",\n \"Aina\",\n \"Akilah\",\n \"Albinia\",\n \"Althaea\",\n \"Alyosha\",\n \"Ansa\",\n \"Arabella\",\n \"Arwyl\",\n \"Ashlyn\",\n \"Avora\",\n \"Brena\",\n \"Brenna\",\n \"Calienthe\",\n \"Camilla\",\n \"Candor\",\n \"Candra\",\n \"Carissa\",\n \"Cascabel\",\n \"Casslyn\",\n \"Castille\",\n \"Celeste\",\n \"Chen\",\n \"Claret\",\n \"Clementine\",\n \"Constance\",\n \"Cordelia\",\n \"Corille\",\n \"Corsica\",\n \"Cyrene\",\n \"Dahlia\",\n \"Daphnia\",\n \"Delia\",\n \"Dena\",\n \"Denna\",\n \"Desmona\",\n \"Dolores\",\n \"Drenna\",\n \"Edie\",\n \"Eira\",\n \"Elsie\",\n \"Emeline\",\n \"Etta\",\n \"Fela\",\n \"Felicity\",\n \"Galenica\",\n \"Galina\",\n \"Gitta\",\n \"Gloria\",\n \"Gwen\",\n \"Hedy\",\n \"Hella\",\n \"Helles\",\n \"Henrietta\",\n \"Iduna\",\n \"Iona\",\n \"Isa\",\n \"Isabella\",\n \"Iskra\",\n \"Isolde\",\n \"Jasna\",\n \"Jaxi\",\n \"Joan\",\n \"Juno\",\n \"Kamelin\",\n \"Kari\",\n \"Koli\",\n \"Lauria\",\n \"Lenia\",\n \"Leona\",\n \"Leyva\",\n \"Lieu\",\n \"Lilith\",\n \"Lin\",\n \"Lizete\",\n \"Lorette\",\n \"Lucella\",\n \"Lynthia\",\n \"Lyra\",\n \"Maia\",\n \"Maiathah\",\n \"Maie\",\n \"Mara\",\n \"Marasi\",\n \"Marielda\",\n \"Marisol\",\n \"Marris\",\n \"Mira\",\n \"Naria\",\n \"Nasha\",\n \"Octavia\",\n \"Odrienne\",\n \"Olivia\",\n \"Ora\",\n \"Ordenna\",\n \"Oressia\",\n \"Orsella\",\n \"Pardenna\",\n \"Penelope\",\n \"Penny\",\n \"Phoebe\",\n \"Polonia\",\n \"Pravda\",\n \"Prudence\",\n \"Quelenna\",\n \"Raisa\",\n \"Redji\",\n \"Remira\",\n \"Rey\",\n \"Riven\",\n \"Runa\",\n \"Sabina\",\n \"Sabinia\",\n \"Sabrina\",\n \"Sadeh\",\n \"Sahar\",\n \"Selma\",\n \"Sesereth\",\n \"Severea\",\n \"Silaqui\",\n \"Skannon\",\n \"Sprig\",\n \"Stabitha\",\n \"Syra\",\n \"Tabitha\",\n \"Talitha\",\n \"Tamsyn\",\n \"Tasi\",\n \"Terra\",\n \"Tesslyn\",\n \"Thava\",\n \"Thena\",\n \"Tiff\",\n \"Una\",\n \"Vaurin\",\n \"Veretta\",\n \"Vesna\",\n \"Vestine\",\n \"Vey\",\n \"Victoria\",\n \"Vin\",\n \"Vita\",\n \"Volette\",\n \"Vorka\",\n \"Wander\",\n \"Ylva\",\n \"Zahra\",\n \"Zaida\",\n \"Zamira\",\n \"Zarya\"\n ]\n },\n name_surname: [\n \"Abberwick\",\n \"Adelbury\",\n \"Adleton\",\n \"Aloro\",\n \"Alsa\",\n \"Ankhayat\",\n \"Arran\",\n \"Ashton\",\n \"Ashweather\",\n \"Athanoch\",\n \"Axelrod\",\n \"Backworth\",\n \"Barrow\",\n \"Basran\",\n \"Black\",\n \"Blackford\",\n \"Blackpool\",\n \"Blackthorne\",\n \"Bluff\",\n \"Boden\",\n \"Booker\",\n \"Boulder\",\n \"Bowman\",\n \"Braeside\",\n \"Bramble\",\n \"Braum\",\n \"Bray\",\n \"Breakiron\",\n \"Bristle\",\n \"Brocken\",\n \"Brogan\",\n \"Bromley\",\n \"Burnsides\",\n \"Caebrek\",\n \"Cartwright\",\n \"Carver\",\n \"Childermass\",\n \"Claw\",\n \"Clelland\",\n \"Clemont\",\n \"Clermont\",\n \"Cobblecarver\",\n \"Coleburn\",\n \"Combe\",\n \"Comber\",\n \"Crofty\",\n \"Cunningham\",\n \"Daava\",\n \"Dal\",\n \"Dalmore\",\n \"Danfield\",\n \"Drawlight\",\n \"Drigg\",\n \"Dunvil\",\n \"Elmore\",\n \"Eveningeyes\",\n \"Evensteps\",\n \"Eventide\",\n \"Everpenny\",\n \"Fairplay\",\n \"Farros\",\n \"Fellwater\",\n \"Fogg\",\n \"Gatcombe\",\n \"Glasseye\",\n \"Goldsworth\",\n \"Grave\",\n \"Graythwaite\",\n \"Greysteel\",\n \"Grine\",\n \"Haig\",\n \"Half-Off\",\n \"Havelton\",\n \"Havenhorst\",\n \"Hectares\",\n \"Helker\",\n \"Helles\",\n \"Hellyers\",\n \"Hemme\",\n \"Hightower\",\n \"Hightown\",\n \"Highwater\",\n \"Hill\",\n \"Hitchcock\",\n \"Innerwick\",\n \"Jayan\",\n \"Jeduin\",\n \"Kardera\",\n \"Karstas\",\n \"Keel\",\n \"Kempt\",\n \"Kessarin\",\n \"Kinclaith\",\n \"King\",\n \"Lake\",\n \"Larriston\",\n \"Leake\",\n \"Lomond\",\n \"Longstaff\",\n \"Lorewood\",\n \"Maroden\",\n \"Mayson\",\n \"Merriweather\",\n \"Michter\",\n \"Mindwell\",\n \"Morcombe\",\n \"Morriston\",\n \"Mortimer\",\n \"Netherton\",\n \"Night\",\n \"Nighteyre\",\n \"Nightly\",\n \"Noctoft\",\n \"Notherhome\",\n \"Orchard\",\n \"Orchid\",\n \"Path\",\n \"Peak\",\n \"Pegg\",\n \"Penderyn\",\n \"Pond\",\n \"Pool\",\n \"Prichard\",\n \"Raines\",\n \"Ravenglass\",\n \"Ravenwood\",\n \"Reigns\",\n \"Reyes\",\n \"Reynes\",\n \"Rhodes\",\n \"Riverford\",\n \"Robel\",\n \"Rowan\",\n \"Sable\",\n \"Sage\",\n \"Salkara\",\n \"Salos\",\n \"Sevoy\",\n \"Shilbottle\",\n \"Shillmoor\",\n \"Shook\",\n \"Skelkallan\",\n \"Skora\",\n \"Slane\",\n \"Song\",\n \"Steadystep\",\n \"Stoutale\",\n \"Stovestoker\",\n \"Strange\",\n \"Strangford\",\n \"Strathmill\",\n \"Sunder\",\n \"Sunderland\",\n \"Swiftwhistle\",\n \"Tailor\",\n \"Tallfellow\",\n \"Templeton\",\n \"Tenpenny\",\n \"Tevilton\",\n \"Thistle\",\n \"Thrysus\",\n \"Thurston\",\n \"Tinmouth\",\n \"Tower\",\n \"Tristé\",\n \"Tyrconnell\",\n \"Vale\",\n \"Valentine\",\n \"Veldaire\",\n \"Venture\",\n \"Walund\",\n \"Warren\",\n \"Waters\",\n \"Wecker\",\n \"Welker\",\n \"Wend\",\n \"Wharver\",\n \"Whythe\",\n \"Woodall\"\n ],\n name_alias: [\n \"Bell\",\n \"Birch\",\n \"Bird\",\n \"Bliss\",\n \"Bricks\",\n \"Bug\",\n \"Chime\",\n \"Coil\",\n \"Cricket\",\n \"Cross\",\n \"Crow\",\n \"Echo\",\n \"Flint\",\n \"Frog\",\n \"Frost\",\n \"Goods\",\n \"Grip\",\n \"Gunner\",\n \"Hammer\",\n \"Hook\",\n \"Ink\",\n \"Junker\",\n \"Mist\",\n \"Moon\",\n \"Nail\",\n \"Needle\",\n \"Ogre\",\n \"Pool\",\n \"Ring\",\n \"Ruby\",\n \"Silver\",\n \"Skinner\",\n \"Song\",\n \"Spur\",\n \"Tackle\",\n \"Thistle\",\n \"Thorn\",\n \"Tick\",\n \"Tick-Tock\",\n \"Tock\",\n \"Trick\",\n \"Twelves\",\n \"Vixen\",\n \"Whip\",\n \"Wicker\"\n ],\n name_suffix: [\n \"Jr.\",\n \"Sr.\",\n \"III\",\n \"IV\"\n ]\n },\n GM: {\n Bargains: [\n { name: \"Infected Wound\", category: \"Character Effect\", effect: \"The next time you Recover from Harm, your Physicker is at -1d.\" },\n { name: \"Infected Wound\", category: \"Character Effect\", effect: \"The next time you Recover from Harm, your Physicker is at -1d.\" },\n { name: \"Infected Wound\", category: \"Character Effect\", effect: \"The next time you Recover from Harm, your Physicker is at -1d.\" },\n { name: \"It's Mine Now\", category: \"Character Effect\", effect: \"You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?\" },\n { name: \"It's Mine Now\", category: \"Character Effect\", effect: \"You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?\" },\n { name: \"It's Mine Now\", category: \"Character Effect\", effect: \"You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?\" },\n { name: \"Mine By Blood\", category: \"Character Effect\", effect: \"You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?\" },\n { name: \"Mine By Blood\", category: \"Character Effect\", effect: \"You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?\" },\n { name: \"Mine By Blood\", category: \"Character Effect\", effect: \"You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?\" },\n { name: \"Mine By Name\", category: \"Character Effect\", effect: \"You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?\" },\n { name: \"Mine By Name\", category: \"Character Effect\", effect: \"You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?\" },\n { name: \"Mine By Name\", category: \"Character Effect\", effect: \"You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?\" },\n { name: \"Mine By Rights\", category: \"Character Effect\", effect: \"You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?\" },\n { name: \"Mine By Rights\", category: \"Character Effect\", effect: \"You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?\" },\n { name: \"Mine By Rights\", category: \"Character Effect\", effect: \"You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?\" },\n { name: \"Not Paying Attention\", category: \"Character Effect\", effect: \"Uncheck one of the XP triggers already marked for your character for this Score.\" },\n { name: \"Not Paying Attention\", category: \"Character Effect\", effect: \"Uncheck one of the XP triggers already marked for your character for this Score.\" },\n { name: \"Shadow From the Past\", category: \"Character Effect\", effect: \"Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?\" },\n { name: \"Shadow From the Past\", category: \"Character Effect\", effect: \"Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?\" },\n { name: \"Shadow From the Past\", category: \"Character Effect\", effect: \"Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?\" },\n { name: \"Thicker than Blood\", category: \"Character Effect\", effect: \"Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?\" },\n { name: \"Thicker than Blood\", category: \"Character Effect\", effect: \"Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?\" },\n { name: \"Thicker than Blood\", category: \"Character Effect\", effect: \"Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?\" },\n { name: \"Why'd It Have To Be...\", category: \"Character Effect\", effect: \"The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress.\" },\n { name: \"Why'd It Have To Be...\", category: \"Character Effect\", effect: \"The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress.\" },\n { name: \"Why'd It Have To Be...\", category: \"Character Effect\", effect: \"The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress.\" },\n { name: \"Demonic Guest\", category: \"Crew Effect\", effect: \"A demonic presence has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Demonic Guest\", category: \"Crew Effect\", effect: \"A demonic presence has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Fracturing Faction\", category: \"Crew Effect\", effect: \"If your Hold is Strong, reduce it to Weak. If your Hold is Weak, reduce your Rep to zero.\" },\n { name: \"Lesson Not Learned\", category: \"Crew Effect\", effect: \"Uncheck one of the XP triggers already marked for your crew for this Score.\" },\n { name: \"Lesson Not Learned\", category: \"Crew Effect\", effect: \"Uncheck one of the XP triggers already marked for your crew for this Score.\" },\n { name: \"Otherworldly Guest\", category: \"Crew Effect\", effect: \"A scion of one of the Old Gods has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Otherworldly Guest\", category: \"Crew Effect\", effect: \"A scion of one of the Old Gods has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Rebellious Faction\", category: \"Crew Effect\", effect: \"A new crew has taken possession of one of your Claims, and will have to be dealt with in Free Play.\" },\n { name: \"Spectral Guest\", category: \"Crew Effect\", effect: \"A ghostly presence has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Spectral Guest\", category: \"Crew Effect\", effect: \"A ghostly presence has appeared in your Lair and will need to be dealt with during Free Play.\" },\n { name: \"Turncoat\", category: \"Crew Effect\", effect: \"One of your Cohorts leaves your crew and joins a rival.\" },\n { name: \"Double-Crossed\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Flipped result.\" },\n { name: \"Double-Crossed\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Flipped result.\" },\n { name: \"Double-Crossed\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Flipped result.\" },\n { name: \"Easily Identified\", category: \"Downtime Effect\", effect: \"You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep.\" },\n { name: \"Easily Identified\", category: \"Downtime Effect\", effect: \"You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep.\" },\n { name: \"Easily Identified\", category: \"Downtime Effect\", effect: \"You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep.\" },\n { name: \"High Profile\", category: \"Downtime Effect\", effect: \"This Score gains +2 Heat.\" },\n { name: \"High Profile\", category: \"Downtime Effect\", effect: \"This Score gains +2 Heat.\" },\n { name: \"High Profile\", category: \"Downtime Effect\", effect: \"This Score gains +2 Heat.\" },\n { name: \"Most Wanted\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, you are the target of an additional Arrest result.\" },\n { name: \"Most Wanted\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, you are the target of an additional Arrest result.\" },\n { name: \"Project Setback\", category: \"Downtime Effect\", effect: \"Mark one less Clock segment the first time you work on a Long-Term Project.\" },\n { name: \"Project Setback\", category: \"Downtime Effect\", effect: \"Mark one less Clock segment the first time you work on a Long-Term Project.\" },\n { name: \"Project Setback\", category: \"Downtime Effect\", effect: \"Mark one less Clock segment the first time you work on a Long-Term Project.\" },\n { name: \"Quelle Horreur!\", category: \"Downtime Effect\", effect: \"You suffer nightmares for a week. −1d to all Downtime Actions after this Score.\" },\n { name: \"Quelle Horreur!\", category: \"Downtime Effect\", effect: \"You suffer nightmares for a week. −1d to all Downtime Actions after this Score.\" },\n { name: \"Shortchanged\", category: \"Downtime Effect\", effect: \"This Score's payoff is −2 Coin.\" },\n { name: \"Shortchanged\", category: \"Downtime Effect\", effect: \"This Score's payoff is −2 Coin.\" },\n { name: \"Shortchanged\", category: \"Downtime Effect\", effect: \"This Score's payoff is −2 Coin.\" },\n { name: \"Supply Challenges\", category: \"Downtime Effect\", effect: \"The next time you pay Coin for an Acquire Asset roll, you must pay 3 instead of 2 Coin per Tier.\" },\n { name: \"Supply Challenges\", category: \"Downtime Effect\", effect: \"The next time you pay Coin for an Acquire Asset roll, you must pay 3 instead of 2 Coin per Tier.\" },\n { name: \"Supply Delays\", category: \"Downtime Effect\", effect: \"Suffer -1d to your next Acquire Asset roll.\" },\n { name: \"Supply Delays\", category: \"Downtime Effect\", effect: \"Suffer -1d to your next Acquire Asset roll.\" },\n { name: \"Supply Delays\", category: \"Downtime Effect\", effect: \"Suffer -1d to your next Acquire Asset roll.\" },\n { name: \"Tastes Like Ashes\", category: \"Downtime Effect\", effect: \"The next time you indulge your Vice, only clear half as much Stress (rounded down) as normal.\" },\n { name: \"Tastes Like Ashes\", category: \"Downtime Effect\", effect: \"The next time you indulge your Vice, only clear half as much Stress (rounded down) as normal.\" },\n { name: \"Thrice-Named\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result.\" },\n { name: \"Thrice-Named\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result.\" },\n { name: \"Thrice-Named\", category: \"Downtime Effect\", effect: \"After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result.\" },\n { name: \"Warden's Attention\", category: \"Downtime Effect\", effect: \"+4 Heat (instead of the normal +2 Heat) if there is a death during this Score.\" },\n { name: \"Warden's Attention\", category: \"Downtime Effect\", effect: \"+4 Heat (instead of the normal +2 Heat) if there is a death during this Score.\" },\n { name: \"We Want a Bigger Take!\", category: \"Downtime Effect\", effect: \"The gang wants a bigger piece of the action. −2 Coin to Payoff for each Cohort used in this Score.\" },\n { name: \"We Want a Bigger Take!\", category: \"Downtime Effect\", effect: \"The gang wants a bigger piece of the action. −2 Coin to Payoff for each Cohort used in this Score.\" },\n { name: \"Weekend Getaway\", category: \"Downtime Effect\", effect: \"If you indulge your Vice after this Score, you automatically overindulge.\" },\n { name: \"Weekend Getaway\", category: \"Downtime Effect\", effect: \"If you indulge your Vice after this Score, you automatically overindulge.\" },\n { name: \"Weekend Getaway\", category: \"Downtime Effect\", effect: \"If you indulge your Vice after this Score, you automatically overindulge.\" },\n { name: \"What's Our Take?\", category: \"Downtime Effect\", effect: \"The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score.\" },\n { name: \"What's Our Take?\", category: \"Downtime Effect\", effect: \"The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score.\" },\n { name: \"What's Our Take?\", category: \"Downtime Effect\", effect: \"The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score.\" },\n { name: \"Accelerating Plans\", category: \"Faction Relationship Effect\", effect: \"A rival faction advances one of its Clocks by two before your next Score.\" },\n { name: \"Accelerating Plans\", category: \"Faction Relationship Effect\", effect: \"A rival faction advances one of its Clocks by two before your next Score.\" },\n { name: \"Accelerating Plans\", category: \"Faction Relationship Effect\", effect: \"A rival faction advances one of its Clocks by two before your next Score.\" },\n { name: \"Escalating Tensions\", category: \"Faction Relationship Effect\", effect: \"A faction of your choice that is unfriendly to your crew moves one step towards War.\" },\n { name: \"Escalating Tensions\", category: \"Faction Relationship Effect\", effect: \"A faction of your choice that is unfriendly to your crew moves one step towards War.\" },\n { name: \"Forgiveness or Vengeance?\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship.\" },\n { name: \"Forgiveness or Vengeance?\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship.\" },\n { name: \"Forgiveness or Vengeance?\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship.\" },\n { name: \"Hot-Headed Cohort\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship.\" },\n { name: \"Hot-Headed Cohort\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship.\" },\n { name: \"Hot-Headed Cohort\", category: \"Faction Relationship Effect\", effect: \"During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship.\" },\n { name: \"Mixed Messages\", category: \"Faction Relationship Effect\", effect: \"A faction of your choice that is friendly to your crew moves one step towards Neutral.\" },\n { name: \"Mixed Messages\", category: \"Faction Relationship Effect\", effect: \"A faction of your choice that is friendly to your crew moves one step towards Neutral.\" },\n { name: \"Mutual Defense\", category: \"Faction Relationship Effect\", effect: \"A friendly Faction goes to War with a neutral Faction. Either join their War, or they move to −1 on the relationship chart.\" },\n { name: \"Mutual Defense\", category: \"Faction Relationship Effect\", effect: \"A friendly Faction goes to War with a neutral Faction. Either join their War, or they move to −1 on the relationship chart.\" },\n { name: \"Tensions Spread\", category: \"Faction Relationship Effect\", effect: \"One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally.\" },\n { name: \"Tensions Spread\", category: \"Faction Relationship Effect\", effect: \"One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally.\" },\n { name: \"Tensions Spread\", category: \"Faction Relationship Effect\", effect: \"One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally.\" },\n { name: \"The Walls Have Ears\", category: \"Faction Relationship Effect\", effect: \"A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating.\" },\n { name: \"The Walls Have Ears\", category: \"Faction Relationship Effect\", effect: \"A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating.\" },\n { name: \"The Walls Have Ears\", category: \"Faction Relationship Effect\", effect: \"A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating.\" },\n { name: \"The Walls Have Eyes\", category: \"Faction Relationship Effect\", effect: \"A friendly faction hears you did a Score against their ally. −1 to both factions' relationship ratings.\" },\n { name: \"The Walls Have Eyes\", category: \"Faction Relationship Effect\", effect: \"A friendly faction hears you did a Score against their ally. −1 to both factions' relationship ratings.\" },\n { name: \"...and Into the Fire\", category: \"Immediate Effect\", effect: \"You are ambushed by an assassin or bounty hunter. Start a 4-Clock, 'Elite Ambusher' to overcome this new foe.\" },\n { name: \"...and Into the Fire\", category: \"Immediate Effect\", effect: \"You are ambushed by an assassin or bounty hunter. Start a 4-Clock, 'Elite Ambusher' to overcome this new foe.\" },\n { name: \"A Familiar Face\", category: \"Immediate Effect\", effect: \"You recognize a contact of your choice among the rivals you are running the Score against.\" },\n { name: \"A Familiar Face\", category: \"Immediate Effect\", effect: \"You recognize a contact of your choice among the rivals you are running the Score against.\" },\n { name: \"A Familiar Face\", category: \"Immediate Effect\", effect: \"You recognize a contact of your choice among the rivals you are running the Score against.\" },\n { name: \"Accidental Discharge\", category: \"Immediate Effect\", effect: \"A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used.\" },\n { name: \"Accidental Discharge\", category: \"Immediate Effect\", effect: \"A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used.\" },\n { name: \"Accidental Discharge\", category: \"Immediate Effect\", effect: \"A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used.\" },\n { name: \"All or Nothing\", category: \"Immediate Effect\", effect: \"If you fail this roll, you cannot resist the effects of that failure.\" },\n { name: \"All or Nothing\", category: \"Immediate Effect\", effect: \"If you fail this roll, you cannot resist the effects of that failure.\" },\n { name: \"All or Nothing\", category: \"Immediate Effect\", effect: \"If you fail this roll, you cannot resist the effects of that failure.\" },\n { name: \"Bishop's Gambit\", category: \"Immediate Effect\", effect: \"If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Bishop's Gambit\", category: \"Immediate Effect\", effect: \"If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Bishop's Gambit\", category: \"Immediate Effect\", effect: \"If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Brute Force Method\", category: \"Immediate Effect\", effect: \"You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action.\" },\n { name: \"Brute Force Method\", category: \"Immediate Effect\", effect: \"You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action.\" },\n { name: \"Brute Force Method\", category: \"Immediate Effect\", effect: \"You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action.\" },\n { name: \"Clear the Board\", category: \"Immediate Effect\", effect: \"If you succeed at this roll, clear or fill a Score Clock of your choice. If you fail the roll, you Trauma out of the scene.\" },\n { name: \"Clear the Board\", category: \"Immediate Effect\", effect: \"If you succeed at this roll, clear or fill a Score Clock of your choice. If you fail the roll, you Trauma out of the scene.\" },\n { name: \"Devil's Exchange\", category: \"Immediate Effect\", effect: \"You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it.\" },\n { name: \"Devil's Exchange\", category: \"Immediate Effect\", effect: \"You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it.\" },\n { name: \"Devil's Exchange\", category: \"Immediate Effect\", effect: \"You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it.\" },\n { name: \"Ghostly Attention\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you.\" },\n { name: \"Ghostly Attention\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you.\" },\n { name: \"Ghostly Attention\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you.\" },\n { name: \"Gimcrack Gear\", category: \"Immediate Effect\", effect: \"Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not.\" },\n { name: \"Gimcrack Gear\", category: \"Immediate Effect\", effect: \"Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not.\" },\n { name: \"Gimcrack Gear\", category: \"Immediate Effect\", effect: \"Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not.\" },\n { name: \"Gone Rogue\", category: \"Immediate Effect\", effect: \"You cannot accept an Assist for the rest of this Score.\" },\n { name: \"Gone Rogue\", category: \"Immediate Effect\", effect: \"You cannot accept an Assist for the rest of this Score.\" },\n { name: \"Hunter Becomes Hunted\", category: \"Immediate Effect\", effect: \"You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you.\" },\n { name: \"Hunter Becomes Hunted\", category: \"Immediate Effect\", effect: \"You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you.\" },\n { name: \"Hunter Becomes Hunted\", category: \"Immediate Effect\", effect: \"You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you.\" },\n { name: \"I Know I Packed It!\", category: \"Immediate Effect\", effect: \"You must immediately check off 1 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"I Know I Packed It!\", category: \"Immediate Effect\", effect: \"You must immediately check off 1 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"I Know I Packed It!\", category: \"Immediate Effect\", effect: \"You must immediately check off 1 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"I Know I Packed Them!\", category: \"Immediate Effect\", effect: \"You must immediately check off 2 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"I Know I Packed Them!\", category: \"Immediate Effect\", effect: \"You must immediately check off 2 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"I Know I Packed Them!\", category: \"Immediate Effect\", effect: \"You must immediately check off 2 Load to no effect, representing equipment you've misplaced.\" },\n { name: \"Jangled Nerves\", category: \"Immediate Effect\", effect: \"For the rest of the Score, all rolls to Resist generate +1 Stress.\" },\n { name: \"Jangled Nerves\", category: \"Immediate Effect\", effect: \"For the rest of the Score, all rolls to Resist generate +1 Stress.\" },\n { name: \"Jangled Nerves\", category: \"Immediate Effect\", effect: \"For the rest of the Score, all rolls to Resist generate +1 Stress.\" },\n { name: \"Just a Little Spark\", category: \"Immediate Effect\", effect: \"A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'.\" },\n { name: \"Just a Little Spark\", category: \"Immediate Effect\", effect: \"A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'.\" },\n { name: \"Just a Little Spark\", category: \"Immediate Effect\", effect: \"A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'.\" },\n { name: \"King's Gambit\", category: \"Immediate Effect\", effect: \"If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action.\" },\n { name: \"King's Gambit\", category: \"Immediate Effect\", effect: \"If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action.\" },\n { name: \"King's Gambit\", category: \"Immediate Effect\", effect: \"If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action.\" },\n { name: \"Knight's Gambit\", category: \"Immediate Effect\", effect: \"If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Knight's Gambit\", category: \"Immediate Effect\", effect: \"If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Knight's Gambit\", category: \"Immediate Effect\", effect: \"If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action.\" },\n { name: \"Knuckle Buster\", category: \"Immediate Effect\", effect: \"Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'\" },\n { name: \"Knuckle Buster\", category: \"Immediate Effect\", effect: \"Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'\" },\n { name: \"Knuckle Buster\", category: \"Immediate Effect\", effect: \"Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'\" },\n { name: \"Now or Never\", category: \"Immediate Effect\", effect: \"If you fail this roll, you lose this opportunity and cannot retry it for this Score.\" },\n { name: \"Now or Never\", category: \"Immediate Effect\", effect: \"If you fail this roll, you lose this opportunity and cannot retry it for this Score.\" },\n { name: \"Now or Never\", category: \"Immediate Effect\", effect: \"If you fail this roll, you lose this opportunity and cannot retry it for this Score.\" },\n { name: \"Out of the Frying Pan...\", category: \"Immediate Effect\", effect: \"Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'.\" },\n { name: \"Out of the Frying Pan...\", category: \"Immediate Effect\", effect: \"Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'.\" },\n { name: \"Out of the Frying Pan...\", category: \"Immediate Effect\", effect: \"Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'.\" },\n { name: \"Overextended\", category: \"Immediate Effect\", effect: \"Your next Action automatically has reduced Effect.\" },\n { name: \"Overextended\", category: \"Immediate Effect\", effect: \"Your next Action automatically has reduced Effect.\" },\n { name: \"Overextended\", category: \"Immediate Effect\", effect: \"Your next Action automatically has reduced Effect.\" },\n { name: \"Pawn's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor.\" },\n { name: \"Pawn's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor.\" },\n { name: \"Pawn's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor.\" },\n { name: \"Plan C...\", category: \"Immediate Effect\", effect: \"Things are not going according to plan. Flashbacks cost +1 Stress for the rest of the Score.\" },\n { name: \"Plan C...\", category: \"Immediate Effect\", effect: \"Things are not going according to plan. Flashbacks cost +1 Stress for the rest of the Score.\" },\n { name: \"Queen's Gambit\", category: \"Immediate Effect\", effect: \"You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action.\" },\n { name: \"Queen's Gambit\", category: \"Immediate Effect\", effect: \"You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action.\" },\n { name: \"Queen's Gambit\", category: \"Immediate Effect\", effect: \"You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action.\" },\n { name: \"Quicksilver Poisoning\", category: \"Immediate Effect\", effect: \"Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal.\" },\n { name: \"Quicksilver Poisoning\", category: \"Immediate Effect\", effect: \"Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal.\" },\n { name: \"Quicksilver Poisoning\", category: \"Immediate Effect\", effect: \"Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal.\" },\n { name: \"Rook's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these.\" },\n { name: \"Rook's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these.\" },\n { name: \"Rook's Gambit\", category: \"Immediate Effect\", effect: \"You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these.\" },\n { name: \"Shot Nerves\", category: \"Immediate Effect\", effect: \"For the rest of the Score, all rolls to Resist generate +2 Stress.\" },\n { name: \"Shot Nerves\", category: \"Immediate Effect\", effect: \"For the rest of the Score, all rolls to Resist generate +2 Stress.\" },\n { name: \"Turned Around\", category: \"Immediate Effect\", effect: \"You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them.\" },\n { name: \"Turned Around\", category: \"Immediate Effect\", effect: \"You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them.\" },\n { name: \"Turned Around\", category: \"Immediate Effect\", effect: \"You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them.\" },\n { name: \"Unsure Footing\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, you loose your footing and fall prone after this Action.\" },\n { name: \"Unsure Footing\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, you loose your footing and fall prone after this Action.\" },\n { name: \"Unsure Footing\", category: \"Immediate Effect\", effect: \"Whether you succeed in this roll or not, you loose your footing and fall prone after this Action.\" },\n { name: \"Worse than We thought\", category: \"Immediate Effect\", effect: \"A Clock of your choice that is running for this Score is either advanced or set back by two segments (whichever is worse for the Crew).\" },\n { name: \"Worse than We thought\", category: \"Immediate Effect\", effect: \"A Clock of your choice that is running for this Score is either advanced or set back by two segments (whichever is worse for the Crew).\" },\n { name: \"You're All On Your Own\", category: \"Immediate Effect\", effect: \"After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score.\" },\n { name: \"You're All On Your Own\", category: \"Immediate Effect\", effect: \"After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score.\" },\n { name: \"You're All On Your Own\", category: \"Immediate Effect\", effect: \"After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score.\" },\n { name: \"Death Will Not Stop Me\", category: \"Long-Term Effect\", effect: \"The ghost of someone you killed is driven to take you with it. Start a 12-Clock, 'Spectral Vengence'\" },\n { name: \"That's Enough of That\", category: \"Long-Term Effect\", effect: \"Someone whose goals are affected by this Score is going to focus on you now. Start a 8-Clock, 'Cold Vengence'\" },\n { name: \"That's Enough of That\", category: \"Long-Term Effect\", effect: \"Someone whose goals are affected by this Score is going to focus on you now. Start a 8-Clock, 'Cold Vengence'\" },\n { name: \"The Last Straw\", category: \"Long-Term Effect\", effect: \"You've royally pissed off someone with real clout in the city. Start a 12-Clock, 'Furious Vengence'\" },\n { name: \"You'll Pay For This\", category: \"Long-Term Effect\", effect: \"Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'\" },\n { name: \"You'll Pay For This\", category: \"Long-Term Effect\", effect: \"Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'\" },\n { name: \"You'll Pay For This\", category: \"Long-Term Effect\", effect: \"Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'\" },\n { name: \"Dalgomur, the Heart of the Storm\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 12-Clock labeled 'The Heart of the Storm' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Dalgomur, the Heart of the Storm\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 12-Clock labeled 'The Heart of the Storm' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Ulf Ironborn, the Skovlan Agitator\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 4-Clock labeled 'Skovlander Uprising' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Ulf Ironborn, the Skovlan Agitator\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 4-Clock labeled 'Skovlander Uprising' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Urumbar, the Closed Eye\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start an 8-Clock labeled 'The Closed Eye' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Urumbar, the Closed Eye\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start an 8-Clock labeled 'The Closed Eye' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Vaskani, the Crossroads Demon\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 6-Clock labeled 'The Crossroads Demon' and set it to one. If the Clock is already active, advance it by one.\" },\n { name: \"Vaskani, the Crossroads Demon\", category: \"Mandatory Effect\", effect: \"If one is not already active for the crew, start a 6-Clock labeled 'The Crossroads Demon' and set it to one. If the Clock is already active, advance it by one.\" }\n ],\n Obstacles: [\n {\n name: \"Centipedes\",\n category: \"Animal Guards\",\n desc: \"Centipedes the length of a forearm are almost noiseless. If they bite, their toxin causes living flesh to blacken and die, leading to amputation if the poison isn't countered. People tend to scream when bit.\",\n questions: [\n \"Were the centipedes brought in as guardians, or are they a local nuisance?\",\n \"There are many different breeds, how will you describe the appearance of yours?\",\n \"Do they have a nasty local nickname?\"\n ],\n modsHarder: [\n \"When one attacks it releases a scent that enrages others nearby, so they tend to swarm.\",\n \"They are excellent swimmers, and they hunt in bog-like areas under the surface.\"\n ],\n modsEasier: [\n \"They are bright yellow and red, and hiss before striking, giving all the warning possible.\",\n \"All the guardians and neighbors carry the antidote, the local apothecary knows what you need.\"\n ]\n },\n {\n name: \"Great Cats\",\n category: \"Animal Guards\",\n desc: \"One or more great cats slink through the shadows. They like to attack from high places. Their fur mottles to match the colors and tones and textures around them.\",\n questions: [\n \"Did the current owners bring them in, or are they inherited from a previous owner?\",\n \"Do they stay on the estate, or go hunting in the local neighborhood?\"\n ],\n modsHarder: [\n \"The cats are trained to alert guards (or wear charm jewelry to alert supernatural guardians) when they detect intruders with their keen senses.\",\n \"Massive old trees draped with moss, or many ledges and overlooks, provide the cats cover.\"\n ],\n modsEasier: [\n \"There is only one, with a regular feeding time and place.\",\n \"The cats are well fed and lazy, mostly for show unless provoked.\"\n ]\n },\n {\n name: \"Hunting Spiders\",\n category: \"Animal Guards\",\n desc: \"These lightning-fast nightmares are about twenty pounds and three feet across, built like jumping spiders and loaded with paralytic venom.\",\n questions: [\n \"Were these spiders bred for a decadent aristocrat, or warped to this impossible size by an insane whisper?\",\n \"Can they survive away from a spirit well?\",\n \"What noise do they make?\",\n \"How do they smell?\"\n ],\n modsHarder: [\n \"They are mostly trained, their handler using a slide whistle to give orders to hunt, attack, withdraw, or guard.\",\n \"The color of the stone, the shape of the underbrush, the leaf litter--everything matches the spider color scheme and hides its movement.\"\n ],\n modsEasier: [\n \"Little lasting harm at first; paralyzed prey is dragged back to a lair and webbed up. You have a day or so to rescue the prey before the spider injects acid into the web bundle so it can drink its victim.\",\n \"The poison is weak and easy to resist, requiring several successful bites to put a human down.\"\n ]\n },\n {\n name: \"Mastiff Pack\",\n category: \"Animal Guards\",\n desc: \"A pack of mastiffs have run of the guarded area when it is not in more public use. They only respond to their masters, who have special tunics, whistles, and gloves. They kill anyone or anything else.\",\n questions: [\n \"What is their heraldry?\",\n \"How many mastiffs are in the pack?\",\n \"Are they trained well enough to ignore poisoned meat or live animal distractions?\"\n ],\n modsHarder: [\n \"Each one is precious to the site owner, who will tirelessly seek vengeance if they are hurt.\",\n \"The pack masters are elite veterans with firearms and excellent tracking and hunting skills.\"\n ],\n modsEasier: [\n \"The equipment is properly installed, its vulnerable parts behind the energy curtain, directly guarding what needs protecting.\",\n \"The lightning walls attract loose spirits, intruders may also have to contend with confused ghosts.\"\n ]\n },\n {\n name: \"Venomous Snakes\",\n category: \"Animal Guards\",\n desc: \"Venomous snakes have lairs prepared for them in the guarded area.\",\n questions: [\n \"How fast acting is their venom?\",\n \"How aggressive are they?\",\n \"Is their hide camouflage for hunting, or bright to warn away predators?\",\n \"Are there only a few big ones, or many small snakes?\",\n \"Do the site guardians feed them, or can they find enough vermin on their own?\"\n ],\n modsHarder: [\n \"Knee-deep plants and elevation shifts intentionally make it difficult to see snakes.\",\n \"Other guardians have a side business in selling venom and meat and hides. They have venom blowdarts and poisoned daggers.\"\n ],\n modsEasier: [\n \"The snakes dislike a certain whistle tone. Let out a blast occasionally and they'll stay away.\",\n \"A former employee knows how guardians got around the site with minimal risk of snakes.\"\n ]\n },\n {\n name: \"Armor Hosts\",\n category: \"Ghostly Guards\",\n desc: \"Guardian spirits are able to inhabit a crystal melded to each suit of armor in a guarded area. When melded, the spirit can control the armor. Spirits use the armor to attack intruders.\",\n questions: [\n \"Were the suits of armor built for this purpose, or retrofitted by a spirit trafficker?\",\n \"Are the guardian spirits loyal, or were they stripped of their will by a ritual or other power?\",\n \"Are the suits visibly paranormal?\"\n ],\n modsHarder: [\n \"A single powerful (relatively sane) spirit can flit from armor to armor, backed up by two slave spirits. The guardian can form an electroplasmic face in the helmet to sneer at intruders.\",\n \"A swarm of spirits are eager to take their turn in armor. When one tires another drops in.\",\n \"Ceaseless patrol.\"\n ],\n modsEasier: [\n \"The ghost(s) that animate the armor are murderous and difficult to control.\",\n \"The guardians can play a chime to recall them to a restraining prism.\",\n \"The suits of armor are old, battered, and prone to physical failure.\"\n ]\n },\n {\n name: \"Coldrooms\",\n category: \"Ghostly Guards\",\n desc: \"The defended area is kept cold. Body heat registers like a plume of blood in the water. Ghosts flood living meat with cold, gorging on body heat, becoming more visible as their outlines swirl with life-blood.\",\n questions: [\n \"Were they created by ritually starving victims to death in the defended space?\",\n \"Were they stolen from the site of a massive horrific disaster?\",\n \"Does a spirit trafficker maintain the wards on the space?\"\n ],\n modsHarder: [\n \"A dead whisper leads them, countering defensive charms and magic, sniffing out breath even if heat is concealed, dueling any supernatural defense.\",\n \"The guarded area is powerfully warded and underground where temperature is easy to maintain.\"\n ],\n modsEasier: [\n \"The guarded area is vulnerable to weather conditions. It is sharp in the cold, but almost dormant in the heat.\",\n \"A relatively simple spirit bane charm can keep them at bay if created in tune with the site.\"\n ]\n },\n {\n name: \"Cursed Treasure\",\n category: \"Ghostly Guards\",\n desc: \"Treasures are infused with a haunting spirit. Anyone touching the treasure will be cursed, dreaming the crimes of the ghost and attracting anger and distaste from strangers. Friends become uncomfortable and suspicious around the cursed scoundrel.\",\n questions: [\n \"Were those sacrificed to make the haunts loyal, serving past death, or punished by undeath?\",\n \"Is the treasure marked as cursed?\"\n ],\n modsHarder: [\n \"The haunting is so deadly that it drives most victims to suicide within a week. Resourceful scoundrels with access to spirit traffickers have days to somehow break the hold. Others are doomed.\",\n \"Electroplasmic poisoning begins, and within a week the scoundrel will become a vampire.\"\n ],\n modsEasier: [\n \"All the bad luck waiting in the wings (unfinished clocks from foes, poorly protected stashes, jilted lovers, false identities) go wrong in quick succession. Then the curse is over.\",\n \"A competent occultist can break the curse as a down time project with a four segment clock.\"\n ]\n },\n {\n name: \"Darkrooms\",\n category: \"Ghostly Guards\",\n desc: \"The defended area is dark. The ragged ghosts hate light. They shriek horribly as they attack light sources with slapping leathery hands, like bat wings. Intruders may glimpse their luminous fangs.\",\n questions: [\n \"Were these ghosts placed here intentionally, or are they the result of some horror that left a print in the Ghost Field?\",\n \"Is this defense maintained, or passive?\"\n ],\n modsHarder: [\n \"Another guardian lurks in the dark and takes advantage of the distraction to steal from intruders, perhaps killing them too.\",\n \"The ghosts are aggressive, pushing intruders. Surroundings include long drops, spikes, mazes, or other hazards difficult to navigate in darkness.\"\n ],\n modsEasier: [\n \"While annoying, they do no real damage, and forewarned scoundrels may prepare unbreakable light sources or supernatural dark vision.\",\n \"There is enough ambient light to see.\"\n ]\n },\n {\n name: \"Dynastic Hive\",\n category: \"Ghostly Guards\",\n desc: \"Ancestors have been ritually infused into the defense site, it is a dynastic holding. The spirits are old, and insane, but strategically placed to act out their madness in the most damaging way.\",\n questions: [\n \"Did the family get special permission to harbor ghosts?\",\n \"Do they have connections to limmers?\",\n \"Are spirits tied to leviathan bone shards?\",\n \"Are they moving pictures, or conversationalists with clues?\"\n ],\n modsHarder: [\n \"The ghosts are legally protected, like landmarks or artwork. Damaging them is a serious crime.\",\n \"Some of the more powerful or canny ghosts are still somewhat sane collaborators with the site owners.\"\n ],\n modsEasier: [\n \"They are out of control, and few dare to enter the site now (or it is abandoned.)\",\n \"They will not harm family members (but may not react well to hostages.)\"\n ]\n },\n {\n name: \"Hunting Ghostpack\",\n category: \"Ghostly Guards\",\n desc: \"A group of weaponized ghosts haunts the defended area. They are capable of scouting to find intruders, descending on them with lethal force.\",\n questions: [\n \"Do they appear as a pack with a mounted hunter, spectral hounds, and a ghostly horn call?\",\n \"Or an armored warband?\",\n \"Shapeless lethal electroplasmic stalkers?\",\n \"Are the wounds they inflict bloody cuts, or hard frostbite?\",\n \"Is their area surrounded with runes that let them see into the material world?\"\n ],\n modsHarder: [\n \"The ghost leader feels all life force in its hunting ground, knowing its location.\",\n \"The hunt can only rise when certain conditions like anniversaries, moon phases, etc. are met. However, they have a treasure that can only be taken from them when they manifest.\"\n ],\n modsEasier: [\n \"The attack is purely psychological, killing with supernatural fear. The effect can be resisted.\",\n \"They are summoned and directed by a command artifact like a hunting horn or special weapon. If someone else tunes to the weapon, control (and its obligations) may shift to a new bearer.\"\n ]\n },\n {\n name: \"Possession Gate\",\n category: \"Ghostly Guards\",\n desc: \"If an intruder breaks a clearly marked seal, the intruder is attacked by a possessing spirit that takes on the traits of the most strong-willed, brutal person the seal-breaker ever killed. The possessing spirit and the seal-breaker struggle for control. This counts as a harm.\",\n questions: [\n \"Is the possessing spirit a ghost, or a shape-shifting construct made by an expert that makes a shape out of something in the target?\",\n \"If an innocent triggers the trap, what form does the spirit take then?\"\n ],\n modsHarder: [\n \"The only way to be free is to die, undergo electroplasmic surgery while dead, and be revived. Otherwise the curse is protected by the victim's life force.\",\n \"The haunting spirit tries to take possession once a day or so, sending the host into a blackout and acting out vicious crimes against allies, loved ones, and bluecoats.\"\n ],\n modsEasier: [\n \"The condition can be reduced with a resist roll, but still is likely a 6 segment clock to clear.\",\n \"The curse haunt would rather have a host ally than kill its victim, and may bargain for shared control.\"\n ]\n },\n {\n name: \"Spirit-Infused Art\",\n category: \"Ghostly Guards\",\n desc: \"Art works are haunted by spirits that are capable of spying. They observe their area, and may be able to murmur about what they see to a guardian.\",\n questions: [\n \"Was art repurposed to host spirits, or was it created for them and around them?\",\n \"Is the art mosaics, portraits, statues, or some other form?\",\n \"How sane and coherent are the spirits?\",\n \"How loyal are they?\",\n \"Do they have the power to attack intruders?\"\n ],\n modsHarder: [\n \"One or more guardians has a signet ring tuned to the haunted art pieces, and can hear what they whisper as they spy.\",\n \"The ghosts inhabiting the art can move from one piece to another, following intruders or retreating to report.\"\n ],\n modsEasier: [\n \"One spirit per art piece, and each spirit has its own unbalanced personality.\",\n \"Unhinged art is violent, so it has to be shrouded or restrained when guardians go through the defended area.\"\n ]\n },\n {\n name: \"Starving Fog\",\n category: \"Ghostly Guards\",\n desc: \"The guarded area is in a clinging cold fog. Fog draws energy from those breathing in it until it manifests shadows that increase target fear, which feeds it more. Eventually it can manifest a killing shape.\",\n questions: [\n \"What do intruders in the fog see when it reflects their fears?\",\n \"Are there sound effects, smells, and sounds, or just fleeting glimpses and silhouettes?\",\n \"Does it project hallucinations or trigger memories?\"\n ],\n modsHarder: [\n \"The fog strengthens the Ghost Field, making ghosts within it more powerful.\",\n \"The fog can move, summoned or controlled by other guardians to provide backup or help search.\"\n ],\n modsEasier: [\n \"The fog is generated by an artifact. If the artifact is neutralized so is the fog.\",\n \"Those with the proper energy keyed amulet or other trinket are invisible to the fog.\"\n ]\n },\n {\n name: \"Sweat Nectar\",\n category: \"Ghostly Guards\",\n desc: \"The defended area is kept hot. Sweat tastes like nectar to swarming ghosts, who dehydrate targets into mummies. The stolen life force and moisture flows to prepared corpses, so ghosts can ride them again.\",\n questions: [\n \"Were they created by dehydrating sacrifices to death in the defended space?\",\n \"Were they gathered from outside the lightning walls to stand guard here?\",\n \"Does a spirit trafficker maintain the wards on the space?\"\n ],\n modsHarder: [\n \"Many prepared corpses are stashed in unexpected places, bursting into combat when rejuvenated.\",\n \"Once they rise, the desiccated spirit-ridden corpses will chase intruders until they can't.\"\n ],\n modsEasier: [\n \"Only a few corpses are left to revive.\",\n \"The site is difficult to keep hot enough to extract the necessary sweat from intruders.\"\n ]\n },\n {\n name: \"Dartus Weed\",\n category: \"Supernatural Plants\",\n desc: \"When something moves near a tangled bank of dartus weed, the vines flex, flicking barbed tips towards the source of motion within arm's reach. The darts are paralytic; a target will pass out for about an hour.\",\n questions: [\n \"Do they have a distinctive flower or smell?\",\n \"What is the aftertaste of the poison's effect?\"\n ],\n modsHarder: [\n \"Hounds with chemically toughened hides patrol the weed banks, brutally killing intruders.\",\n \"Weed banks are cultivated strategically, flanking important doorways or draped over arborwalks, straggling along verges.\"\n ],\n modsEasier: [\n \"The weeds are young. Darts can be stopped with thick leather.\",\n \"Weed banks are out of the way of defended valuables, but too close to very annoyed neighbors who may hold a grudge.\"\n ]\n },\n {\n name: \"Dreamspore Shrooms\",\n category: \"Supernatural Plants\",\n desc: \"Placed on the ceiling, they drizzle sandy spores when they sense motion below. Victims hallucinate, heightening subconscious emotion (so they are very mellow, or super anxious, or filled with rage, etc.).\",\n questions: [\n \"Were these intended to be a site defense?\",\n \"Did they instead serve a religious or recreational function?\",\n \"Are there special techniques for harvesting them, perhaps selling them to alchemists?\"\n ],\n modsHarder: [\n \"A more intense strain, these can knock out those who succumb, and give them vivid dreams for several hours.\",\n \"They are placed near other guardians as well as hazards like a steep drop or running water.\"\n ],\n modsEasier: [\n \"Other guardians come here recreationally, their effectiveness reduced.\",\n \"The spores are weak and easier to resist.\"\n ]\n },\n {\n name: \"Floormesh\",\n category: \"Supernatural Plants\",\n desc: \"Flat vines grow together to make flooring. Connected below is the bulb, covered in venomous spikes. Anyone heavier than a child will fall through. Blood and rot feed the floormesh.\",\n questions: [\n \"Have site defenders put carpet over the flat vines to further hide the threat?\",\n \"What colors, textures, and patterns does this version have?\",\n \"How dangerous is the venom?\"\n ],\n modsHarder: [\n \"The building's architecture assumes use of floormesh, the carpets are woven to look like floormesh so the guardians don't have to cover the actual pits.\",\n \"The mesh itself has venomous thorns in it, so stepping on it or falling through poisons the target.\"\n ],\n modsEasier: [\n \"The pit is not cleaned, the area near it stinks heavily of corpserot. The mesh sags visibly.\",\n \"Floormesh is mostly hung like tapestries, living decorations, rather than forming pit traps.\"\n ]\n },\n {\n name: \"Ghost Crystal Topiary\",\n category: \"Supernatural Plants\",\n desc: \"Ghost crystals are worked into the roots of fancifully trimmed bushes. Ghosts may be able to inhabit the bushes and make them move. This gardening curiosity can be weaponized.\",\n questions: [\n \"Is this a currently maintained garden, or one that is overgrown and abandoned?\",\n \"Who provides the necessary skilled care to create or maintain the topiary?\",\n \"Is there a theme to the sculptures?\"\n ],\n modsHarder: [\n \"Certain of the most powerful bushes can uproot and move around like living green golems driven by electroplasmic energy.\",\n \"The bushes hardly move, but the powerful energies of the crystals make ghosts much more coherent and powerful in the garden.\"\n ],\n modsEasier: [\n \"Left unprotected at one point, the garden was raided by thieves after the ghost crystals. Few crystals are left in the shaggy bushes.\",\n \"Incompetent handling has drained most of the power from the crystals.\"\n ]\n },\n {\n name: \"Keenshrooms\",\n category: \"Supernatural Plants\",\n desc: \"These fist-sized mushrooms let out a keening wail when light comes within about thirty feet.\",\n questions: [\n \"What do they look like?\",\n \"Is their smell distinctive?\",\n \"Are they good eating?\"\n ],\n modsHarder: [\n \"They are strategically placed to surprise intruders; inside doors, on ceilings, in alcoves, behind statues.\",\n \"Masses of keenshrooms have been allowed to coat walls or fill rooms, and their keen is strong enough to deafen or kill.\"\n ],\n modsEasier: [\n \"The keenshrooms were placed too close to trafficked paths inside or outside the defended site. Constant false alarms dull vigilance.\",\n \"Too far from site defenders, their keens are seldom investigated.\"\n ]\n },\n {\n name: \"Murder Tree\",\n category: \"Supernatural Plants\",\n desc: \"The willow tree grew around bones wired to it, spirit crystals studded in its bark, and leviathan blood at its roots. lt is dimly self-aware. It senses and hates life, whipping and clubbing any who approach.\",\n questions: [\n \"How do guardians move around the tree?\",\n \"Suggestions include knowing passwords, having enchanted amulets, or attuning to its blind spots. How many guard the site?\",\n \"Who had the expertise to cultivate this living weapon, how long ago?\"\n ],\n modsHarder: [\n \"The chorus of semi-aware spirits that fuel the tree are enslaved by one domineering will. The tree is as coherent as a person.\",\n \"Multiple murder trees are connected by roots and share knowledge with each other (and any other site guardians.)\"\n ],\n modsEasier: [\n \"No one can communicate with the murder tree, or control it, so it is isolated from other defenses.\",\n \"The tree sleeps most of the time, and it is difficult to rouse it to fighting fury.\"\n ]\n },\n {\n name: \"Snatchweed\",\n category: \"Supernatural Plants\",\n desc: \"It grows in fresh water, lengthening its long winding tendrils almost to the surface. When touched, it snatches and pulls, coiling down to the bottom and holding for a few minutes before relaxing back up.\",\n questions: [\n \"Is their growth boosted supernaturally, and can you see faces reflecting from the Ghost Field beneath their fronds?\",\n \"Are the locals aware of the threat, willing to talk about it?\"\n ],\n modsHarder: [\n \"Snatchweed is cultivated in areas where intruders must enter the water to get past other obstacles.\",\n \"The bottom of the water has two foot spikes, victims are pulled down onto them.\"\n ],\n modsEasier: [\n \"A sign warns of the hazard, as required by law.\",\n \"This particular breed of snatchweed recoils from salt; put enough on the surface and tendrils recoil.\"\n ]\n },\n {\n name: \"Thirstclimber\",\n category: \"Supernatural Plants\",\n desc: \"The vines are red, and when flesh touches them (even through leather) the vine draws blood to the surface in alarming quantities. The vines are slippery, and almost impossible to grasp with wet hands.\",\n questions: [\n \"Are the vines clearly visible to those who can see in the Ghost Field?\",\n \"Do the vines cause damage that must be healed, or does the blood only flow when they are nearby?\"\n ],\n modsHarder: [\n \"The site has guard creatures that track by scent and are drawn to attack things that smell bloody.\",\n \"Thirstclimber is cultivated at the mid-point of a really difficult climb.\"\n ],\n modsEasier: [\n \"Annoyed locals keep it trimmed back on outside walls periodically in spite of the guardian's threats.\",\n \"Guards know the ingredients to make a special paste, and the symbol to paint on skin with it, to protect from the plant's effects. A former guard might share the secret.\"\n ]\n },\n {\n name: \"Thirsty Thorns\",\n category: \"Supernatural Plants\",\n desc: \"Strategically placed thornbushes grow on walls and serve as decorations. They live on blood. They only flower if something dies on them; the bigger the life, the more impressive the bloom.\",\n questions: [\n \"Do they feed on radiant light?\",\n \"Are they along the interior walls, lining the walks, and climbing walls outside?\",\n \"Are there thorns inside, along windows or protecting secret doors?\"\n ],\n modsHarder: [\n \"The thorns are poisonous, inflicting some condition on those who fail to resist.\",\n \"Possibilities include sleep, death by choking, blinding blood from the eyes, or paralysis.\",\n \"The thorns are considered a gardening achievement, with some fame and support as local culture.\"\n ],\n modsEasier: [\n \"A custom amulet tuned to their life energy turns the thorns away, allowing its bearer to push through them unharmed. A site defender may have one, or one could be made.\",\n \"They are old and brittle, dying by inches and neglected.\"\n ]\n },\n {\n name: \"Vine Curtains\",\n category: \"Supernatural Plants\",\n desc: \"Curtains of vines connect back to a radiant root that has grown semi­aware, fed on rogue spirits. If touched, the vines slither and writhe to entangle, hoist, and bundle the target for a guardian to find.\",\n questions: [\n \"What do the vines look like?\",\n \"Do they use their scent to attract or repel?\",\n \"Where is the root relative to the curtain?\"\n ],\n modsHarder: [\n \"Many curtains and roots of different sizes (some quite big) connect back to a central bulb somewhere in the defense site.\",\n \"The vines also have a contact poison that makes their target go limp for 10-60 minutes.\"\n ],\n modsEasier: [\n \"The site owner does not have legal permission to have the vine curtains, so they are only used inside.\",\n \"The vine curtains grow wild and the lazy site owner does not keep them trimmed back, so other guards must stay away from them.\"\n ]\n },\n {\n name: \"Caul Piercers\",\n category: \"Traps\",\n desc: \"Piercers are designed to puncture whoever touches them. They pierce the energy caul of the character's life force in the Ghost Field. This causes a harm condition that worsens or costs stress every down time cycle until the caul can be mended (6 segment project.) Interpret as needed.\",\n questions: [\n \"Do the piercers resemble knives, nails, or thorn-like carvings?\",\n \"What sadistic expert crafted these dire traps?\",\n \"If pried out of their settings, how long do they retain potency?\"\n ],\n modsHarder: [\n \"Those affected will trail life energy like a wounded fish bleeding in the water; demons and ghosts alike will investigate the scent.\",\n \"They are worked into important doorknobs, strategic ledges, and concealed flooring.\"\n ],\n modsEasier: [\n \"They all look alike and are similarly placed, relying on surprise to be effective.\",\n \"They are only on the main treasure.\"\n ]\n },\n {\n name: \"Collapsing Ceilings\",\n category: \"Traps\",\n desc: \"If triggered, this trap drops a mass of stone. That seals off the threatened area, and crushes anyone tampering with its defenses.\",\n questions: [\n \"Who put valuables behind a trap that could seal them away for good?\",\n \"How old is this defense, and who takes care of it?\",\n \"What warning signs tip off an intruder that continuing is dangerous?\"\n ],\n modsHarder: [\n \"Hidden mechanisms can raise the block back up to the ceiling, so the trap can be reused (or defeated remotely.)\",\n \"More than one block falls; the first one cuts off escape, then death seems inevitable.\"\n ],\n modsEasier: [\n \"The stone dropped long ago. Site guardians or intruders have developed ways to climb over it or get past it. Other blocks may still be untriggered, but some of them are no longer dangerous.\",\n \"More like a mine collapse, difficult to control and possible to tunnel past.\"\n ]\n },\n {\n name: \"Combination or Trick\",\n category: \"Traps\",\n desc: \"Various portals and defenses of the site are protected by combination locks or riddles to solve. Lockpicks will not work against them, though finesse may solve them eventually.\",\n questions: [\n \"Are there a series of combination locks expressing a religious or eccentric worldview?\",\n \"Are there picture arranging puzzles, or unusual keys to go in sculpture locks?\",\n \"Are the locks mechanical or supernatural?\"\n ],\n modsHarder: [\n \"Powerful runic work or enslaved ghosts make the obstacle difficult to smash or trick--the right combination or object must be used to bypass it.\",\n \"Clues and needed items are spread across a large estate, or multiple estates.\"\n ],\n modsEasier: [\n \"The combination or solution to the puzzle is in a scholarly work, and can be found or bought ahead of time.\",\n \"The solutions are painfully obvious to someone with the right upbringing and background.\"\n ]\n },\n {\n name: \"Contact Needles\",\n category: \"Traps\",\n desc: \"Small needles are worked into contact surfaces and poisoned, to deter intruders. They may be on doorknobs, seat backs or cushions, doorframes, stair treads, ledges, beds—anywhere, really.\",\n questions: [\n \"Are the needles easily visible if you look for them, or camouflaged?\",\n \"Are they retractable if you know what you're doing?\",\n \"What kind of poison is on them?\",\n \"Will the victim sleep, freeze, die, or hallucinate?\"\n ],\n modsHarder: [\n \"The needles are only corporeal to those who touch them without wearing a certain amulet. Important site guardians are immune to the needles.\",\n \"Anything important or at an unguarded entry point is going to be festooned with needles.\"\n ],\n modsEasier: [\n \"They are not well maintained. Many have snapped off, and few retain much poison.\",\n \"They are only on the most important objects or the most useful trap objects (like a chair for guests.)\"\n ]\n },\n {\n name: \"Excellent Locks\",\n category: \"Traps\",\n desc: \"Beyond simple security, these locks are works of art. They are higher potency than they would normally be. Also, they are equipped with poison needle traps, or pick breakers, or redundancies.\",\n questions: [\n \"Who put in these superior locks, and for what reason?\",\n \"Are the locks designed to defeat entry, or actively punish intruders?\",\n \"Do the specialized keys have a distinctive look, like two flanges?\",\n \"Is there a master key?\"\n ],\n modsHarder: [\n \"Everything is locked, and all the locks are good. Somebody had a real lock problem.\",\n \"The locks involve supernatural components, like hidden keyholes or paralyzing energy.\"\n ],\n modsEasier: [\n \"The locks are in poor repair, of variable quality after indifferent maintenance and many intrusion attempts.\",\n \"Very fancy locks, but they are padlocks, and bolt cutters can circumvent the problem.\"\n ]\n },\n {\n name: \"Murder Holes\",\n category: \"Traps\",\n desc: \"Intruders go past one door, into a hallway or small room, and the door closes behind them. Arrow slits open in the walls, and slots in the ceiling allow boiling oil to be poured down. Intruders are trapped and vulnerable. These are often in doors through defenses.\",\n questions: [\n \"Was the original site builder often under siege?\",\n \"Are the murder holes obvious or concealed?\"\n ],\n modsHarder: [\n \"Murder holes are automated with self- slamming doors and pre-boiling oil, so a few defenders can trap and/or kill many intruders.\",\n \"The whole layout is built with many murder hole areas to deter invasion.\"\n ],\n modsEasier: [\n \"The walls are wooden, and determined captives can break through to face their attackers.\",\n \"This area does not have enough staff to monitor intruders and make best use of murder holes.\"\n ]\n },\n {\n name: \"Pit Traps\",\n category: \"Traps\",\n desc: \"The defended site has pit traps in strategic places. They are between 10 and 40 feet deep.\",\n questions: [\n \"Do they have slick sides?\",\n \"Are there spikes at the bottom?\",\n \"Are the covers mechanized, or flimsy boards and carpets, grass turf, or leaves over canvas?\",\n \"Are the sides stone, earth, or clay?\"\n ],\n modsHarder: [\n \"Fist sized tunnels connect pits. Predatory creatures (crabs, snakes, spiders, rats) scurry to devour victims.\",\n \"Once someone falls into the pit the covers close again, and will not open until unlocked.\"\n ],\n modsEasier: [\n \"The pits drop into a lower area, mostly abandoned except for predators. It is possible to find a way out.\",\n \"The pits are mostly open and filled with junk.\"\n ]\n },\n {\n name: \"Retractable Spikes\",\n category: \"Traps\",\n desc: \"Spring-loaded spears or racks of spears launch at intruders. They can come from the side, behind, ahead, below, or above.\",\n questions: [\n \"Are the defenses standardized to protect guardians, or random to confuse intruders?\",\n \"Are they in an area that site defenders use, or in an isolated off-limits area?\",\n \"How long have they been in use, and how often are they maintained?\"\n ],\n modsHarder: [\n \"After doing their killing work, they retract, and the launch points are not obvious.\",\n \"The spears are slathered with some toxin, further affecting the victim.\"\n ],\n modsEasier: [\n \"The mechanisms are not well maintained. Sometimes they don't work, and when they do, there is a screech and they are a bit slow.\",\n \"The spears are designed to pin an intruder in place, to be interrogated and punished, rather than to kill outright.\"\n ]\n },\n {\n name: \"Secret Doors & Spyholes\",\n category: \"Traps\",\n desc: \"Guardians are well trained in the use of numerous secret doors and hidden passages with spyholes. They can attack from unexpected directions, escape without a trace, and watch intruders unobserved.\",\n questions: [\n \"Was this site built by a spy, or a cult, or a paranoid aristocrat?\",\n \"Are there consistent tells, a code built into the decor and architecture, or must all secrets be known individually?\"\n ],\n modsHarder: [\n \"Ongoing rearrangement and construction means old information from plans or people ages out fast.\",\n \"Supernatural locks and keys mean that triggers and spyholes and seams may not be visible in the material world at all.\"\n ],\n modsEasier: [\n \"Frequent use has made secret doors easier to spot. Poor baffling of lights may reveal spyholes in use.\",\n \"Current residents are only aware of some secrets; intruders may use back ways to elude security.\"\n ]\n },\n {\n name: \"Shock Grips\",\n category: \"Traps\",\n desc: \"One or more contact points are connected to energy so they will badly shock anyone who touches them. These could be doorknobs, chest lids, floor plates, ladders, and so on.\",\n questions: [\n \"Are they powered by batteries or enslaved ghosts?\",\n \"Does the site have legal permission to use them?\",\n \"How loud is the shock?\",\n \"How do site guardians avoid getting shocked?\"\n ],\n modsHarder: [\n \"The shock grips are numerous and concealed, connected to their energy source through the Ghost Field.\",\n \"The shock is designed to stop the heart and kill the victim (possibly setting hair on fire.)\"\n ],\n modsEasier: [\n \"The shock grips are connected to control boxes and energy sources by cables.\",\n \"Shock grips are marked by a rune, and shiny, and also give out a palpable hum of energy. They are easy to detect.\"\n ]\n },\n {\n name: \"Brutal Sadists\",\n category: \"Twisted Guards\",\n desc: \"Only brutal sadists are hired on as guards. They have permission to play with captured intruders.\",\n questions: [\n \"Is the owner of the protected property aware of this cultural rule, or are guards hired by an employee?\",\n \"Do they share cultural roots (slaughterhouse workers, leviathan hunters, soldiers, city guards, etc)?\",\n \"How do the neighbors feel about their occasional scandals?\"\n ],\n modsHarder: [\n \"Several of them are skilled in both torture and interrogation; they extract secrets from intruders. A side business in blackmail helps them avoid legal trouble.\",\n \"They are hardened veterans, exceptionally tough and dangerous. They aim to incapacitate.\"\n ],\n modsEasier: [\n \"Their ugly tactics and poorly chosen victims have earned them (and their employer) enemies in lots of unexpected places.\",\n \"They really, really like to drink.\"\n ]\n },\n {\n name: \"Close-Knit Guard Network\",\n category: \"Twisted Guards\",\n desc: \"Guards are only hired by referral. Failure results in punishment for both the guard and the sponsor. Their loyalty is tested many ways before and after they are hired.\",\n questions: [\n \"Do they favor bastards of the employer?\",\n \"Are they connected to one military unit?\",\n \"Are they refugees from another place?\",\n \"Do they come from a single neighborhood?\",\n \"Does punishment extend to their families?\"\n ],\n modsHarder: [\n \"They are connected to a larger sponsoring organization that would seek vengeance if they are attacked or insulted, and also offer them favors.\",\n \"They speak in code and have passwords that include safewords and warnings.\"\n ],\n modsEasier: [\n \"Nepotism has pulled in some really incompetent guards.\",\n \"Endless drama from working with family and friends.\"\n ]\n },\n {\n name: \"Compulsive Detail Focus\",\n category: \"Twisted Guards\",\n desc: \"Only a certain type is hired; a type that checks every lock and every dark corner. Schedules are strict, thoroughness is a guarantee, and they seem unable to cut corners or skip steps. Everything is by the book.\",\n questions: [\n \"Are they altered to be like this, or just screened for a mindset?\",\n \"What are the detailed parts of the defended site that need this kind of attention?\",\n \"How does their gear reflect this fussy attention to detail?\"\n ],\n modsHarder: [\n \"There are other elements of the defended site that require their focus, like a pattern of stepping over tiles to avoid triggering traps or complex combination locks or dozens of cells with dangerous prisoners.\",\n \"They are trusted with specialty items like firearms or charms because they are responsible with them.\"\n ],\n modsEasier: [\n \"Everyone knows that they fall apart if things deviate from the pattern, like distractions or chaos.\",\n \"The locals pick on them when they are off duty, teasing them for their compulsions. They have enemies, and could use friends.\"\n ]\n },\n {\n name: \"Convict Public Service\",\n category: \"Twisted Guards\",\n desc: \"Due to prison overcrowding, some criminals are sentenced to indentured service to a noble to work off their debt to society. This site's guardian uses criminals as guards, under the stern eye of professionals.\",\n questions: [\n \"Are casualties high due to danger from intruders or other site defenses?\",\n \"Is the patron benevolent and trying to rehabilitate criminals, or using them as disposable fodder?\",\n \"How do the convicts like this place?\"\n ],\n modsHarder: [\n \"Serving here is a known post among criminals, both a resume builder and networking site.\",\n \"Angering these guards could bring consequences from unexpected directions in the criminal underworld.\",\n \"Hand picked as the hardest and deadliest, these criminal guards are canny and tough.\"\n ],\n modsEasier: [\n \"Convicts are eager to assist anyone with enough Coin or pull to secure their pardon and freedom.\",\n \"The convicts are bullied and sullen, as much a hindrance to defenders as a defense themselves.\"\n ]\n },\n {\n name: \"Demonic Mutations\",\n category: \"Twisted Guards\",\n desc: \"About a quarter of the guards have been mutated by contact with demonic essence. They are strong, and their senses are sharp.\",\n questions: [\n \"Do they share one demon patron?\",\n \"Did they become guards to gain this power?\",\n \"Are they worshippers or mercenaries?\",\n \"Did they volunteer or are they victims?\",\n \"What element is their demonic affinity?\"\n ],\n modsHarder: [\n \"They share a supernatural connection and can sense when other demonic guards are in trouble.\",\n \"They are highly resistant to normal damage. They may be vulnerable to supernatural attacks or a specific allergy (silver, garlic, salt, etc.) Or, they may be resistant to supernatural attacks instead.\"\n ],\n modsEasier: [\n \"They become physically impressive, but their minds are lost to incoherent lusts and fury.\",\n \"The rest of the staff resent or fear the demonic guards. Loyalty and morale are low among mundane employees.\"\n ]\n },\n {\n name: \"Enchanted Prosthetics\",\n category: \"Twisted Guards\",\n desc: \"Guards are all amputees with at least one prosthetic. Each prosthetic tunes to its owner. The prosthetics can stun on contact.\",\n questions: [\n \"Are the false limbs the work of one genius?\",\n \"Are they part of a collection?\",\n \"Were they made for this use?\",\n \"Is a ghost bound to each?\",\n \"Are they scientific, with batteries?\",\n \"Are they powered by the bearer's life force?\"\n ],\n modsHarder: [\n \"All guards have some adept training and spirit bane charms, alert against supernatural forces.\",\n \"Veteran guards have learned to tune to their prosthetics to get an additional effect, like life detection or firing energy blasts.\"\n ],\n modsEasier: [\n \"Only one use between recharges.\",\n \"The guards are mostly old or broken, relying on reputation and supernatural energy to be effective.\"\n ]\n },\n {\n name: \"Feral Pen\",\n category: \"Twisted Guards\",\n desc: \"Some areas of the defended site have free-range maniacs. Destitute and wretched beggars are treated as guard dogs, expected to attack intruders and draw attention to anything unusual.\",\n questions: [\n \"Does the guarded site pretend to be charitable, or a madhouse, or a prison?\",\n \"What philosophy leads to treating people this way?\",\n \"How do the city authorities feel about the site?\",\n \"Religious authorities?\",\n \"Does the site feed into the Ghost Field in an unusual way?\"\n ],\n modsHarder: [\n \"Most of the feral guards are killers, possibly haunted, and extremely dangerous.\",\n \"This pet project is as much art and religion as defense, and has support from a variety of decadent aristocrats in positions of power.\"\n ],\n modsEasier: [\n \"The rest of the site guards hate the feral pen and ignore it as best they can.\",\n \"It is as much prison hospice as guard dog kennel. Its victims are weak, sick, and starving.\"\n ]\n },\n {\n name: \"Fighting School\",\n category: \"Twisted Guards\",\n desc: \"An onsite training school focuses on the lifestyle and skill of a school of fighting. Site defenders are part of a group identity with specialty training.\",\n questions: [\n \"Is the school's focus on dueling, a martial art, commando training, or something else?\",\n \"What is their crest, uniform, motto, and lore?\",\n \"What sort of training space do they have?\"\n ],\n modsHarder: [\n \"The school itself is an impressive fortress or defense.\",\n \"The school has an impressive alumni network that visits occasionally and would avenge wrongs to the honor of the school.\"\n ],\n modsEasier: [\n \"This is an off-site shrine or expansion, where they send troublemakers and those they can't eject for political or financial reasons.\",\n \"Leadership is riddled with rivalries and power struggles. Outsiders know some details.\"\n ]\n },\n {\n name: \"Performance Enhancers\",\n category: \"Twisted Guards\",\n desc: \"Guards have ready access to drugs. Some of the drugs enhance performance.\",\n questions: [\n \"Do the drugs give them a burst of combat effectiveness?\",\n \"Are the drugs recreational, making them popular with a customer base that pays well and owes favors?\",\n \"Who provides them with drugs?\"\n ],\n modsHarder: [\n \"As dealers, the guards are difficult to bribe or intimidate, as they have money and prestige.\",\n \"Guards can medicate flexibly, with concoctions to enhance perception (even to see the supernatural,) gain combat prowess, or heal.\"\n ],\n modsEasier: [\n \"Their peddling of illegal drugs has made enemies among bluecoats and inspectors.\",\n \"The guards are junkies. Their employer uses addiction to control them, keeping them near the edge. They are often distractible or unconscious.\"\n ]\n },\n {\n name: \"Zealots\",\n category: \"Twisted Guards\",\n desc: \"Guards share a religion that binds them together and makes them resistant to intimidation or corruption.\",\n questions: [\n \"Do they worship one of the Forgotten Gods? The Church of the Ecstasy of the Flesh? Weeping Lady?\",\n \"Have they sworn oaths?\",\n \"What does religion require them to hate, or to love?\"\n ],\n modsHarder: [\n \"The defended site includes a shrine or temple. Violating the site angers offended worshippers.\",\n \"Serving as a site guardian is part of a religious duty. Unexpectedly seasoned warriors or important people may serve as lowly guards for a time.\"\n ],\n modsEasier: [\n \"Mandatory prayer times, unclean objects or places left uninspected, and restricted areas may create holes in security.\",\n \"Enemies of their religion may offer help to embarrass, discredit, or injure the zealots.\"\n ]\n },\n {\n name: \"Ghostport Lock\",\n category: \"Weird Tech\",\n desc: \"Keys are tuned to locks that cannot be picked by normal means, or bypassed without whisper expertise. Their access point is in the Ghost Field until the key is present.\",\n questions: [\n \"Are these locks modem scientific triumphs, or old arcane defenses?\",\n \"Does he key look like a key, or does it look like a missing decoration, or a gem?\",\n \"Is the key physical, or energy, like living blood of the right family?\"\n ],\n modsHarder: [\n \"The locks are hidden and trapped. Messing with the lock could hollow the intruder (tearing the spirit out of the body) or other unpleasantness.\",\n \"The precise location of the lock must be known, and it is not near what it is locking.\"\n ],\n modsEasier: [\n \"The ghostport lock has been a fad several times in Duskwall. Each time, there was some mass production, and a key to a similar lock might work with a little help.\",\n \"The owner may have stiffed a whisper locksmith on the fee, or otherwise offended the expert, who is knowledgeable and disgruntled.\"\n ]\n },\n {\n name: \"Lightning Walls\",\n category: \"Weird Tech\",\n desc: \"Runic energy twisting technology can make pylons that project a curtain of energy between them. The glowing walls are transparent, but crippling to touch and lethal to pass through. They stop projectiles.\",\n questions: [\n \"Does the site have the technology legally, or is it stolen?\",\n \"Maybe cobbled together from leftovers by a mad alchemist?\",\n \"Is it on all the time (expensive to fuel) or only if the alarm is raised?\",\n \"Where are the fuel cells kept?\"\n ],\n modsHarder: [\n \"The equipment is properly installed, its vulnerable parts behind the energy curtain, directly guarding what needs protecting.\",\n \"The lightning walls attract loose spirits, intruders may also have to contend with confused ghosts.\"\n ],\n modsEasier: [\n \"The walls guard a few key access points, but there are multiple ways around.\",\n \"The walls are installed poorly, so their machinery is vulnerable from the outside while it is on. If no other guards are present, they can be wrecked.\"\n ]\n },\n {\n name: \"Panopticon\",\n category: \"Weird Tech\",\n desc: \"Special crystal lenses transmit their sight through the Ghost Field to mirrors in a central location. From one place, a guardian can monitor views all over the defended site.\",\n questions: [\n \"Is this new industrial alchemical technology, or an ancient enchanted construction?\",\n \"Does the current owner know how to get the most functionality out of it?\",\n \"Who maintains the system?\"\n ],\n modsHarder: [\n \"The lenses are hidden in mirror frames, statues, and other decor. They are difficult to spot.\",\n \"The lenses can see into the Ghost Field as well, observing ghosts or occult work, and life force.\"\n ],\n modsEasier: [\n \"The guardians watching the mirrors are somewhat lax.\",\n \"Over time, many lenses have not been replaced or repaired. Views are limited.\"\n ]\n },\n {\n name: \"Shadow Lanterns\",\n category: \"Weird Tech\",\n desc: \"Guards are equipped with lanterns that detect shadows of recent life force as well as shedding light.\",\n questions: [\n \"Are the lanterns traditional lantern shape, or a glowing ball, or something else?\",\n \"Does an expert keep the guardians supplied, or is their supply jealously guarded?\",\n \"Does it cost the guards something to activate the lanterns?\",\n \"Will the lanterns work if taken off-site?\"\n ],\n modsHarder: [\n \"Guards are trained to tune into the life force energy to also hear conversations of the life shadows. Guards can tune into the life force energy to know the owner's current location, if in the defended area.\",\n \"Untended lanterns can be set to transmit detection of a life force to a nearby guardian.\"\n ],\n modsEasier: [\n \"The lanterns can be rendered blind by properly tuning a spiritbane charm while near one.\",\n \"Every sunrise wipes all traces of past life forces, and they only work at night.\"\n ]\n },\n {\n name: \"Shadow Rooms\",\n category: \"Weird Tech\",\n desc: \"The Ghost Field sometimes remembers rooms or entire neighborhoods that no longer exist in the material world. Some defended sites hide treasures in these spaces that can only be accessed if you knowhow.\",\n questions: [\n \"How are colors different in these shadow rooms?\",\n \"Is there a smell or sound that lingers?\",\n \"How does it feel to step out of the material world?\",\n \"What natural laws work differently here, like fire not flickering?\"\n ],\n modsHarder: [\n \"The access point to the shadow rooms is an enchanted lock, its location is known and guarded.\",\n \"The shadow rooms are only connected to the material world a few times a year, or less.\"\n ],\n modsEasier: [\n \"Transitioning from the material world to the shadow rooms involves certain proscribed movements; cross the courtyard three times, then back down stairs with eyes closed (for example.) Too many people know the formula.\",\n \"The current site owners do not know these rooms exist.\"\n ]\n }\n ],\n NPCs: [\n {\n name: \"Arturo Montastic\",\n type: \"npc\",\n concept: \"Addicted Gambler\",\n arena: \"New Money\",\n description: \"He is impossibly lucky. He wins enough at games of chance to pay for his addictions, and to treat the consequences (transfusions, transplants, cutting-edge treatments.) His relationships are intense but brief. He often loses everything, but then wins it all back and more. He has owned epic treasures many times.\",\n notes: \"Risk-averse collectors cannot bear his cavalier attitude on winning and losing priceless art. He does not truly appreciate his treasures, and should not be trusted with them. Losers can take their losses hard.\"\n },\n {\n name: \"Baron Kelyr Strathmill\",\n type: \"npc\",\n concept: \"Hardened Industrialist\",\n arena: \"Old Money\",\n description: \"His family has controlled the docks for many generations. They quietly destroy competition, and get lucrative city contracts to re-develop blighted areas if the money slows down. Graceful, educated, and pleasant, he is ruthless as barbed steel under a cultured veneer. He is proud of his estate's gardens.\",\n notes: \"Competition doesn't like being crippled. He often hires outsiders for the dirtiest work, and his victims often hire outsiders to get revenge.\"\n },\n {\n name: \"Baroness Thena Hellyers\",\n type: \"npc\",\n concept: \"Hazy Art Patron\",\n arena: \"Old Money\",\n description: \"Thena is one of the least emotionally scarred survivors in her weird family. She is a leading light in the art world. She is patron to many artists and her criticism and evaluation drives a significant element of Duskwall's art scene. Whispers have noted she has an unusual connection to the Ghost Field.\",\n notes: \"Sometimes she hires outsiders to sort out one of her artists' problems. She has a private gallery that she updates with her current trending tastes—those in the art market need to know what's in it.\"\n },\n {\n name: \"Calvin Dannos\",\n type: \"npc\",\n concept: \"Eerie Assassin\",\n arena: \"Underworld\",\n description: \"The Inkvein was a cabal of seven anonymous assassins, named for their maps of the canals. If one of them was identified as a member, the other six were sworn to kill the outed assassin. Dannos was outed a decade ago, and he killed the other members and their undying founder. Now he IS Inkvein.\",\n notes: \"Easily bored, he prefers interesting challenges to high paying or easy kills. Of course, many bereaved or power hungry individuals want him dead.\"\n },\n {\n name: \"Commissioner Naria Haig\",\n type: \"npc\",\n concept: \"Political Matchmaker\",\n arena: \"City Law\",\n description: \"She exudes a plump grandmotherly innocence, but she is one of the sharpest politicians in Duskwall. She supervises over the merging of unexpected allies and the schism of monolithic interests. She cares about one thing—the good of Duskwall as a whole. She is Chair of the Ethics Oversight Committee.\",\n notes: \"Always playing a bigger game, she uses outsiders to manage errands whose purpose they cannot see. Those she outmaneuvers tend to want to get back at her with violence.\"\n },\n {\n name: \"Doc Sarnin\",\n type: \"npc\",\n concept: \"Lecherous Leech\",\n arena: \"Underworld\",\n description: \"Doc can keep life in you if you're alive (or recently dead) when you get to him. His extreme methods are often horrifying. Still, his concoctions can crush ghosts, re-attach limbs, and more. The Crows, a tough crew, protect him. They give him victims for his \\\"needs,\\\" which are emotional, physical, and scientific.\",\n notes: \"Sometimes the Crows hire outsiders to go after rare components or victims for Doc. He has many, many enemies who want to either steal him and force him to serve them, or punish him.\"\n },\n {\n name: \"Doctor Ixit Crichelle\",\n type: \"npc\",\n concept: \"Elegant Spook\",\n arena: \"Old Money\",\n description: \"Crechelle calls himself an Oneiric Master. He interprets dreams for a fee. He enters them, alters them, and moves through veils to understand truths and secrets the dreamer may not grasp. If he touches a target, or one of their possessions, he may enter their dreams. He appears feeble, but his mind is deadly.\",\n notes: \"Aristocratic patrons invite him to parties. He needs a person's possession to see into their dreams; he pays for objects to visit some people's dreams. Victims will pay to free themselves .\"\n },\n {\n name: \"Dr. Hansel Kryvanntic\",\n type: \"npc\",\n concept: \"Brilliant Scientist\",\n arena: \"Foreign\",\n description: \"He is Severosi, bow-legged and wild-haired. His work on electroplasmic poisoning and mutation in animals and humans is ground-breaking. Fleeing persecution because of his ethically questionable methods back in Severos, he found a more open-minded scientific community in Duskwall.\",\n notes: \"His research has applications in art, medicine, and war. Those with sufficient resources to further his studies want to control him. He has hurt a lot of people, over time, so he has many enemies.\"\n },\n {\n name: \"Dr. Yerial Crabbskidditch\",\n type: \"npc\",\n concept: \"Sleazy Lawyer\",\n arena: \"New Money\",\n description: \"He firmly believes those who are wealthy should not be pestered with the law. No matter what you do, if you have means you can arrange for an alternate story that favors you. Deaths, frauds, robberies, and other crimes can be reduced to a few fines. He throws money at problems until they disappear.\",\n notes: \"He routinely hires outsiders to destroy evidence, intimidate witnesses, compel confessions, and so forth. He has countless enemies, both those seeking justice and former clients who ran out of money.\"\n },\n {\n name: \"Duvrel the Snake\",\n type: \"npc\",\n concept: \"Cunning Smuggler\",\n arena: \"Foreign\",\n description: \"She is Tycherosian, with the eyes and horns of a goat. Snake tattoos coil around her arms. Exotic drugs from the Dagger Isles flow through her distribution network in Duskwall. She hires outsiders to remove stubborn people while she has an alibi, or to retrieve drugs misplaced at incriminating locations.\",\n notes: \"Inspectors have orders from the Spirit Wardens to take her alive, to study her uncanny ability to flex with the Ghost Field for supernatural stealth.\"\n },\n {\n name: \"Dylayzia Finchester\",\n type: \"npc\",\n concept: \"Fashionable Whisper\",\n arena: \"New Money\",\n description: \"Her exotic looks, tattoos, and bright green eyes draw attention. She popularized thigh-high buckled leather boots and spirit bane chokers. Her opinions echo in drawing rooms across the city. People enjoy her feud with the Church of the Ecstasy of the Flesh.\",\n notes: \"Wealthy figures in the fashion world pay top win for sneak peeks at her clothing designs. Her opinions inflame many enemies­-especially the Church. She hires outsiders to get rare components for her rituals.\"\n },\n {\n name: \"Emeline Coleburn\",\n type: \"npc\",\n concept: \"Weary Regulator\",\n arena: \"City Law\",\n description: \"She inspects buildings and reports to the Duskwall Council whether they are sound, and whether they serve the purpose listed on the owner's taxation form. She is front-line in the tug-of-war between criminals, politicians, and nobles. She no longer cares about the greater good. Now it's about kickbacks.\",\n notes: \"She takes the path of least resistance in her evaluations, so people pay to make their preference easier and other roads harder. She hires outsiders for off-the-books communication with pushy customers.\"\n },\n {\n name: \"Eric the White\",\n type: \"npc\",\n concept: \"Vigilante Rebel\",\n arena: \"Foreign\",\n description: \"The War of Skovlan Unity is over, but this slender maniac with a brushy beard can't let it go. He plans to destroy the government and turn Duskwall into a Skovlan colony to punish them for the destructive war. He wants to discredit and disrupt the government at every turn.\",\n notes: \"He targets gavernment officials as high up as he can reach, hoping to cause enough trouble to make the government vulnerable to change. He has gathered zealots, and he uses outsiders for disposable work.\"\n },\n {\n name: \"Gi Aniru Ga of Sultha\",\n type: \"npc\",\n concept: \"Sacrificing Cultist\",\n arena: \"Supernatural\",\n description: \"She worships the Gaping Maw, the Runnel of Life, the Cosmic Thirst. She builds a cult, teaching them to hunt and conduct rituals. Then she moves on. Witnesses uneasily describe her supernatural abilities, including shapeshifting, flight, killing people by attacking their shadows, and so on.\",\n notes: \"Bereaved relatives, rival cultists, and law enforcers all want her stopped. She hires outsiders to threaten, misdirect, or kill law enforcement. Determined inspectors crush cults she trained, need help to catch her.\"\n },\n {\n name: \"Holtz Clermont\",\n type: \"npc\",\n concept: \"Reformed Clerk\",\n arena: \"City Law\",\n description: \"He used to be a forger. After he served stint in prison, some respectable family friends got him a position as City Clerk for the whole district. He manages correspondence for permit requests and official notices. When corrupt people inside and outside the system need to adjust evidence, they come to him.\",\n notes: \"Jilted clients can be threatening, leading him to take steps to adjust their attitude by hiring outside help. He's smarter than he looks, and knows how to back people off. He also might know too much.\"\n },\n {\n name: \"Inspector Lorette Salkha\",\n type: \"npc\",\n concept: \"Crusading Inspector\",\n arena: \"City Law\",\n description: \"She needs allies in her hopeless quest to clean up the city. Corruption is everywhere, crime runs rampant, and the bluecoats serve the powerful (on both sides of the law.) Some tragedy in her past propels her into a suicidal effort to restore \\\"rule of law.” Her peers muse it is a shame she will die young.\",\n notes: \"She could be helpful if she focuses on the right bad guys—your enemies. She can't be bought, so maybe someone needs her killed (or otherwise neutralized.)\"\n },\n {\n name: \"Jemma Dropkick\",\n type: \"npc\",\n concept: \"Feminist Vigilante\",\n arena: \"Underworld\",\n description: \"She is a legend in the Seven Shallows neighborhood. She attacks men who abuse women. She survives because she has friends—a few bluecoats, a gang of thugs, and a grateful public. She carefully plans attacks to hurt abusers. Lf her victims abuse again, they are mutilated, packed like luggage, and shipped out of town.\",\n notes: \"Many powerful men would pay for revenge on Jemma. Sometimes she hires outsiders to help out.\"\n },\n {\n name: \"Kheldaria Whinnich\",\n type: \"npc\",\n concept: \"Implacable Developer\",\n arena: \"New Money\",\n description: \"She has a vision for developing the Crow's Foot district. It will be divided between businesses, estates, and parks. To realize her vision, she has been selectively buying real estate all around the city, bartering for land in Crow's Foot, and using whatever persuasion is needed to convince owners to sell to her.\",\n notes: \"She has an estate where she stores induce­ments of all sorts, a variety of treasure designed to persuade owners to sell in exchange for what they want most. They say you could find almost anything there.\"\n },\n {\n name: \"Lady Ashlyn Tyrconnel\",\n type: \"npc\",\n concept: \"Decadent Duelist\",\n description: \"For centuries, aristocrats of Duskwall have learned the Tyrconnel Method of swordplay and self defense. The Tyrconnel family produces countless public servants and warriors—but also a share of scoundrels. Ashlyn's trademark suite of moves is to duel, win, bed someone, and drink to unconsciousness.\",\n notes: \"You're hired to join the spy game in the Tyrconnel family. Or, someone is targeting her. Either way. Watch your back. Outsiders in the games of nobles are uniformly expendable.\"\n },\n {\n name: \"Lady Candra Dunvil\",\n type: \"npc\",\n concept: \"Corrupt Fixer\",\n arena: \"Old Money\",\n description: \"Her family built Ironhook Prison. Her wealth is built on generations of shady deals with incarcerated aristocrats and business owners. She sees the world as a rigged game and has contempt for anyone who finds corruption shocking or fixable. She is vain, practical, and ruthless.\",\n notes: \"She hires outsiders to carry out promises she made to inmates. Her family has casually wrecked reputations and lives over centuries, and that leaves a trail of vengeance seekers.\"\n },\n {\n name: \"Lady Polonia Brogan\",\n type: \"npc\",\n concept: \"Desirable Dowry\",\n arena: \"Old Money\",\n description: \"She's ugly, smelly, stupid, and rude--and also the key to the Brogan fortune. Her lucky spouse will have access to massive wealth and infrastructure among professional builders and shipwrights of Duskwall. Only her aunt, CECILIA DURWITHE, looks out for her best interests with sharp disapproval.\",\n notes: \"Brogan hires outsiders to punish those who slight her, or to investigate potential partners. She collects fake wills rogues have planted during assassination attempts, trying to leave her fortune to usurpers .\"\n },\n {\n name: \"Lord Branon Kinclaith\",\n type: \"npc\",\n concept: \"Romantic Horseman\",\n arena: \"Old Money\",\n description: \"Branon looks like a hero from a legendary story. He manages the family's stables, the finest horses in Duskwall (where horses are a rare luxury.) His tumultuous trysts with both men and women are common knowledge. Business suffers from his impulsive romantic gestures, but benefits from his charm.\",\n notes: \"Branon sometimes refuses to sell horses, or breed them, if he dislikes the buyer. Some buyers want access to horseflesh anyway. If his horses are attacked, he hires outsiders to get revenge.\"\n },\n {\n name: \"Lord Bulward Skinnester\",\n type: \"npc\",\n concept: \"Greedy Banker\",\n arena: \"New Money\",\n description: \"This portly curmudgeon does a brisk trade in real estate titles, both lending and foreclosing. He is acutely aware of the value of properties and how neighbors affect value. He takes particular glee in foreclosing on aristocracy and setting up the newly rich in ancient estates.\",\n notes: \"Sometimes he hires outsiders to solve problems that his hired bluecoats and bribed councilmen cannot manage. He collects sculpture by Duskwall artists. He has ruined the lives of many formerly influential people.\"\n },\n {\n name: \"Lord Orlan Booker\",\n type: \"npc\",\n concept: \"Insulated Mastermind\",\n arena: \"Old Money\",\n description: \"Ennui is a danger to the wealthy. Booker fills his days by gathering intelligence and planning heists, then selling the plans to ambitious gangs that lack his patience, experience, resources, and insight. Twice a month he goes to the opera, and meets those who have arranged to purchase a score.\",\n notes: \"Sometimes things go wrong, and it is natural to blame the planner and want revenge. Sometimes a target wants to punish those who acted against them, even if the act was planning.\"\n },\n {\n name: \"Master Slen Dallicore\",\n type: \"npc\",\n concept: \"Protective Guilder\",\n arena: \"New Money\",\n description: \"Master Dallicore is the Guildmaster for the Docker's Guild. They move all cargo on and off ships, boats, and gondolas. Their role is protected by law, as are the fees they charge. The guild uses low-level violence to discourage non-guild laborers and smugglers. However, some challenges require proper scoundrels.\",\n notes: \"Dallicore is not above hiring outsiders to punish powerful patrons of smugglers or illegal dock workers. His position of power also gives him access to rare antiquities, both purchased and acquired.\"\n },\n {\n name: \"Minister Fourteen\",\n type: \"npc\",\n concept: \"Grungy Fixer\",\n arena: \"Underworld\",\n description: \"The blind Skovlander holds court on the docks, moving from one basement to another. He favors baggy shirts, stained vests, shiny jewelry, and fraying lace. He often acts through his massive bodyguard Severen and his weedy messenger Torok.\",\n notes: \"He is connected in the Skovlander refugee community, and in Skovlan. For a price (either wealth or an errand) he will share information about Skovlanders. He often hires outsiders to handle sensitive tasks.\"\n },\n {\n name: \"Moonslider the Third\",\n type: \"npc\",\n concept: \"Eccentric Artist\",\n arena: \"New Money\",\n description: \"She feels moon phases. Her family put her in an asylum for a decade. Later, she won her freedom and inherited the family bootmaking fortune. She makes art. She tries to communicate her moon feelings. She uses oil paint, glass blowing, sculpture, song, and dance in multimedia recitals and art pieces.\",\n notes: \"Her family bought nice things before they all died and she inherited them; she ignores most of it. She needs expensive equipment and supplies for her bizarre art shows.\"\n },\n {\n name: \"Officer Milos Penderyn\",\n type: \"npc\",\n concept: \"Corrupt Bailiff\",\n arena: \"City Law\",\n description: \"Milos has access to trial evidence, and to prisoners awaiting trial. He can't get people out, but he can silence them. He has a network of corrupt peers, judges, bluecoats, and others so he can trade favors to accomplish the impossible. Huge and greasy, he is built like a bull and he enjoys the scent of fear.\",\n notes: \"Controlling Milos could mean protecting or killing someone in bluecoat custody. An endless stream of people want revenge on him, and a more select group would like to control or use him.\"\n },\n {\n name: \"Officer Veleris Walund\",\n type: \"npc\",\n concept: \"Heroic Bluecoat\",\n description: \"There are actually songs about him. He is very popular. Veleris is a skilled orator (though he retreats into modesty) and a canny judge of character and situations. (He insists he just tries to do the right thing.) His opinion is influential in his district. He is trusted to guard valuables. His moustaches are his pride and joy.\",\n notes: \"He has no family, and he seems to be an idealist. Some try to persuade him, others try to threaten him. Threats don't seem to work. He has been known to quietly hire outsiders to get justice.\"\n },\n {\n name: \"Pebbler\",\n type: \"npc\",\n concept: \"Demon Spy\",\n arena: \"Supernatural\",\n description: \"This earth demon looks like a fat man built around a boulder gut, leaking sand from joints. It is able to see and hear through sand, earth, and stone within a range of miles. It works with non-cultists voluntarily, selling information in exchange for raids into the rare areas protected from its prying.\",\n notes: \"Dozens of powerful people want Pebbler banished or robbed. However, the demon is a peerless information exchange, valuable even if it is difficult to control.\"\n },\n {\n name: \"Saithernon\",\n type: \"npc\",\n concept: \"Exotic Fence\",\n arena: \"Underworld\",\n description: \"He drapes his python, DELGRAAZ, around his neck. He wears a turban with a jewel on it. He is willing to buy almost anything, no matter how strange. He also knows what you need, sometimes before you know you need it. His bazaar unfurls below the Kennington market in an abandoned gondola dock.\",\n notes: \"He pays people to get things for him, then sells them at tremendously inflated prices to those desperate to have them. This can cause hurt feelings among the desperate.\"\n },\n {\n name: \"Serlevica the Brander\",\n type: \"npc\",\n concept: \"Spy Whisper\",\n arena: \"Underworld\",\n description: \"Gaunt and frizzed, this foul-smelling Whisper has a secret ritual that allows her to control and see through rats she brands. She sells her services as a spy or site guardian. She has survived by retreating into slums and sewers when threatened, and striking from the shadows until it is safe to emerge again.\",\n notes: \"She is closely tied to the information marketplace, buying and selling secrets. She often hires outsiders to deal with her enemies through theft or violence, and she is in turn a frequent target.\"\n },\n {\n name: \"Sir Mournseller\",\n type: \"npc\",\n concept: \"Anarchist Ghost\",\n arena: \"Supernatural\",\n description: \"This ghost possesses old men from the Draymach Asylum, breaking them out to find and hire scoundrels for obscure tasks with no independent purpose. Examples include killing an insignificant chandler or stealing a specific stone from a wall in a noble's estate. Payment is the location of hidden treasure.\",\n notes: \"A decade ago, an astute inspector began picking out the connection between errands, seeing a very long and very dangerous game to unseat the city's rulers emerging.\"\n },\n {\n name: \"Sir Olen Llanwold\",\n type: \"npc\",\n concept: \"Piratical Industrialist\",\n arena: \"New Money\",\n description: \"He is thin and nervous, easy to underestimate. He specializes in stripping foes of their assets and taking over their operations. His father was a butler, and he grew up hating aristocrats. He understands power structures and corrupts retainers. His top agent, Ellsfielder, is a beautiful and ruthless woman.\",\n notes: \"Many ruined aristocrats (and their allies) hate Danwold passionately. He does not hesitate to use his assets, legal and otherwise, to defend himself and cripple his foes. He hires outsiders through proxies.\"\n },\n {\n name: \"Sir Tocker Farros\",\n type: \"npc\",\n concept: \"Pragmatic Councilman\",\n arena: \"City Law\",\n description: \"Sometimes the law works, and sometimes it doesn't. Regardless, the Council must rule and there must be order. Sir Farros ensures the districts he serves do not get too far out of hand before lawless elements are curbed. One way or another. He looks like an affable grandfather, but he has a dark past.\",\n notes: \"Sir Farros uses inspectors or scoundrels, politicians or housemaids—anyone who will get the job done. He has an endless list of enemies who feel he wronged them, and want revenge. His agents are disposable.\"\n },\n {\n name: \"SLOPSPATTER\",\n type: \"npc\",\n concept: \"Canal Hull\",\n arena: \"Supernatural\",\n description: \"This hull learned to consume spirits and bolster its strength with theirs. It cannibalizes machinery and rummages in wrecked boats for parts. It has gondola prow shoulder guards and helm, and strange banded armor made of water-logged wood over intricate mechanical parts. It fears destruction.\",\n notes: \"It assassinates targets, with its body or by possessing machines near them. It hunts whispers, leeches, and scholars, stealing their knowledge and killing them. Their allies want revenge.\"\n },\n {\n name: \"Syla DuTorrivestria\",\n type: \"npc\",\n concept: \"Famous Connoisseur\",\n arena: \"Foreign\",\n description: \"This mysterious Iruvian hides behind a veil. For years, she has been the final word on Duskwall delicacies. She specializes in evaluating high-end cuisine (including spore wines and cooking with leviathan blood.) She stays in the public eye with racy politics and a string of scandalous romances.\",\n notes: \"She must keep any real competitors for her fame weakened and embarrassed, and she has countless enemies. Everyone \\\"knows\\\" she is an Iruvian spy.\"\n },\n {\n name: \"The Honorable Telia Cray\",\n type: \"npc\",\n concept: \"Stern Prosecutor\",\n arena: \"City Law\",\n description: \"She's old, she's sour, and she has a reputation for jailing Duskwall's criminals. As thin and hard as an iron poker, she relentlessly pursues her cases, bending the law with a passionate hatred of scoundrels. She runs a special unit of Inspectors dedicated to investigating her cases, run by INSPECTOR ULEK.\",\n notes: \"If she is taking a case personally ( as she often does) she may hire outsiders to acquire or create evidence. She also conduds a brutal war of counter-intelligence against rogues looking to free their associates.\"\n },\n {\n name: \"The Wooden Judge\",\n type: \"npc\",\n concept: \"Haunted Puppet\",\n arena: \"Underworld\",\n description: \"This knee-high ventriloquist dummy looks like a caricature of a grim Judge. It is supernaturally animated. The puppet appears unexpectedly, interrupting a scoundrel's routine by offering jobs in a squeaky voice. He pays by revealing the location of hidden caches of ancient coin.\",\n notes: \"Many angry victims want to know who pulls the strings of the Wooden Judge. The puppet often hires fresh talent for dubious work.\"\n },\n {\n name: \"Theodore Lysander\",\n type: \"npc\",\n concept: \"Bard Pimp\",\n arena: \"Underworld\",\n description: \"Elegant and charismatic, this well-dressed man runs the Tenpenny Court Network. He manages prostitutes and their customers, his personal connections and charm monetized. He is also a skilled composer and performer, often seen at the Worldsedge Theater in Crow's Foot.\",\n notes: \"He is a skilled networker. He takes the safety of his friends seriously, and is protedive of his employees, to the point of using blackmail to force powerful patrons to back off.\"\n },\n {\n name: \"Chief Prichard\",\n type: \"npc\",\n description: \"The head Overseer of the Ministry of Provisions in Duskwall. Manages the workers and food allotments for the city districts.\",\n district: \"Barrowcleft\",\n traits: [\n \"calculating\",\n \"confident\",\n \"calm\"\n ]\n },\n {\n name: \"Lord Strangford\",\n type: \"npc\",\n description: \"Operates one of the largest leviathan hunter fleets, serves on the City Council and is a high-ranking member of the secret order within the Church of Ecstasy.\",\n district: \"Brightstone\",\n traits: [\n \"secretive\",\n \"calculating\",\n \"arrogant\"\n ]\n },\n {\n name: \"Hutton\",\n type: \"npc\",\n description: \"A Skovlander refugee and former soldier, now the leader of an anarchist revolutionary movement, bent on forcing the government to acknowledge Skovlander rights in the Empire.\",\n district: \"Charhollow\",\n traits: [\n \"brave\",\n \"compassionate\",\n \"wise\"\n ]\n },\n {\n name: \"Lady Drake\",\n type: \"npc\",\n description: \"A magistrate who is \\\"reasonable\\\" when it comes to street crime, so long as the offender's purse is sufficient.\",\n district: \"Charterhall\",\n traits: [\n \"flexible\",\n \"shrewd\",\n \"subtle\"\n ]\n },\n {\n name: \"Master Slane\",\n type: \"npc\",\n description: \"A notorious factory foreman known for excessive and cruel punishments for the smallest infractions. Many attempts have been made on his life, but all have failed. Some say he's a devil.\",\n district: \"Coalridge\",\n traits: [\n \"cold\",\n \"cruel\",\n \"sadistic\"\n ]\n },\n {\n name: \"Sergeant Lochlan\",\n type: \"npc\",\n description: \"The senior Bluecoat squad leader in the district, reporting to Captain Dunvil. Lochlan is flexible and reasonable, taking bribes and payoffs when she can; enforcing the law and making examples when necessary.\",\n district: \"Crow's Foot\",\n traits: [\n \"shrewd\",\n \"tough\",\n \"commanding\"\n ]\n },\n {\n name: \"Chief Helker\",\n type: \"npc\",\n description: \"One of the most influential senior Dockers. Helker has a lot of sway at the docks, and if you cross him, you might find your cargo tossed into the drink—and possibly you along with it.\",\n district: \"The Docks\",\n traits: [\n \"cautious\",\n \"greedy\",\n \"vengeful\"\n ]\n },\n {\n name: \"Master Krocket\",\n type: \"npc\",\n description: \"An unsavory, greasy-haired, scarecrow of a man who runs the snarling pack of vicious dogs used by Ironhook to track down escapees and sniff out contraband and tunnels. His dog-handlers can be found around the labor camp and all about Dunslough, using their status with the prison for favors and bribes.\",\n district: \"Dunslough\",\n traits: [\n \"cruel\",\n \"greedy\",\n \"ruthless\"\n ]\n },\n {\n name: \"Jira\",\n type: \"npc\",\n description: \"A dealer of fine weapons from the Dagger Isles. Greatly respected by many street toughs in The Dusk—a \\\"jira blade\\\" is a status symbol that many aspire to.\",\n district: \"Nightmarket\",\n traits: [\n \"bold\",\n \"tough\",\n \"confident\"\n ]\n },\n {\n name: \"Levyra\",\n type: \"npc\",\n description: \"A medium who invites clients to bring ghosts in bottles to posses her so they can share a few final words before the ghost is \\\"freed\\\" (Levyra hands it off to the waiting Spirit Wardens nearby).\",\n district: \"Silkshore\",\n traits: [\n \"weird\",\n \"daring\",\n \"dishonest\",\n \"\"\n ]\n },\n {\n name: \"Mother Narya\",\n type: \"npc\",\n description: \"Runs the Arms of the Weeping Lady charity house.\",\n district: \"Six Towers\",\n traits: [\n \"kind\",\n \"patient\",\n \"gracious\"\n ]\n },\n {\n name: \"Maestro Helleren\",\n type: \"npc\",\n description: \"Senior composer and conductor of the Spiregarden Theater, premiere performance venue for the elite of the city.\",\n district: \"Whitecrown\",\n traits: [\n \"sincere\",\n \"dramatic\",\n \"vain\"\n ]\n },\n {\n name: \"Hester Vale\",\n type: \"npc\",\n description: \"Matriarch of the oldest farm family. The living embodiment of \\\"tough but fair.\\\"\",\n district: \"Barrowcleft\",\n traits: [\n \"proud\",\n \"fierce\",\n \"suspicious\"\n ]\n },\n {\n name: \"Commander Bowmore\",\n type: \"npc\",\n description: \"Chief Officer of the Watch in Brightstone. Bowmore's family financed Bowmore Bridge centuries ago and now holds many positions of power.\",\n district: \"Brightstone\",\n traits: [\n \"proud\",\n \"principled\",\n \"connected\"\n ]\n },\n {\n name: \"Briggs\",\n type: \"npc\",\n description: \"The owner of a merchant stall at Charhollow market, cover for a network of gossips, spies, and code-smiths among the working class people of the district, selling their services to those who need them.\",\n district: \"Charhollow\",\n traits: [\n \"secretive\",\n \"sneaky\",\n \"cautious\"\n ]\n },\n {\n name: \"Lord Penderyn\",\n type: \"npc\",\n description: \"Chief Scholar of the Archive of Echoes, authorized by the Emperor to keep a collection of ancient ghosts trapped in spirit bottles, to be consulted in cases where knowledge from the distant past would benefit the operation of the Imperial government. Lord Penderyn also consults the spirits on his own volition, forming the rebellious Path of Echoes society for other elites and nobles who seek communion with the spectral realm.\",\n district: \"Charterhall\",\n traits: [\n \"reckless\",\n \"strange\",\n \"obsessive\"\n ]\n },\n {\n name: \"Belle Brogan\",\n type: \"npc\",\n description: \"A Skovlander factory worker who's been gaining popularity as a potential union organizer. It's only a matter of time before a factory boss tries make an example of her.\",\n district: \"Coalridge\",\n traits: [\n \"charming\",\n \"confident\",\n \"bold\"\n ]\n },\n {\n name: \"Lewit, Jol, Myra, Reyf\",\n type: \"npc\",\n description: \"Bluecoat constables; run an extortion racket.\",\n district: \"Crow's Foot\",\n traits: [\n \"arrogant\",\n \"vain\",\n \"volatile\"\n ]\n },\n {\n name: \"Tris\",\n type: \"npc\",\n description: \"A legendary tattooist who only inks those that have looked upon a leviathan and lived to tell the tale. Getting a tattoo from Tris is a rite of passage for everyone who hunts the demons of the void sea.\",\n district: \"The Docks\",\n traits: [\n \"artistic\",\n \"popular\",\n \"insightful\"\n ]\n },\n {\n name: \"Vandra\",\n type: \"npc\",\n description: \"A deathlands scavenger that survived six runs and was pardoned. She knows the landscape beyond the barrier very well—but few can make sense of her haunted mumblings.\",\n district: \"Dunslough\",\n traits: [\n \"haunted\",\n \"wise\",\n \"daring\"\n ]\n },\n {\n name: \"Leclure\",\n type: \"npc\",\n description: \"A purveyor of personal luxuries (soaps, hair oils, perfume, fine silks) who dabbles in fortune telling. Some say her that drowned lover is a ghost that whispers secrets in her ear.\",\n district: \"Nightmarket\",\n traits: [\n \"shrewd\",\n \"tough\",\n \"commanding\"\n ]\n },\n {\n name: \"Helene\",\n type: \"npc\",\n description: \"The elegant and mysterious proprietor of the Silver Stag Casino. People say she would have been a queen of Severos had she lived in the old days before the Empire.\",\n district: \"Silkshore\",\n traits: [\n \"cultured\",\n \"charming\",\n \"secretive\"\n ]\n },\n {\n name: \"Chef Roselle\",\n type: \"npc\",\n description: \"One of the best cooks in the city, still operating the legendary Golden Plum restaurant—worth the trip into the haunted streets of Six Towers.\",\n district: \"Six Towers\",\n traits: [\n \"creative\",\n \"insightful\",\n \"friendly\"\n ]\n },\n {\n name: \"Lady Freyla\",\n type: \"npc\",\n description: \"Regarded by some as the finest sommelier in the Empire. She serves only the most deserving at the Emperor's Cask.\",\n district: \"Whitecrown\",\n traits: [\n \"erudite\",\n \"cultured\",\n \"charming\"\n ]\n },\n {\n name: \"Mara Keel\",\n type: \"npc\",\n description: \"A former smuggler who's gone into hiding among the farm laborers of Barrowcleft.\",\n district: \"Barrowcleft\",\n traits: [\n \"quiet\",\n \"secretive\",\n \"patient\"\n ]\n },\n {\n name: \"Rolan Wott\",\n type: \"npc\",\n description: \"An influential magistrate who handles property, endowments, and financial cases. Famous for his extravagant parties.\",\n district: \"Brightstone\",\n traits: [\n \"stylish\",\n \"elitist\",\n \"shrewd\"\n ]\n },\n {\n name: \"Corben\",\n type: \"npc\",\n description: \"An ex-military Skovlander on the lam for crimes against the empire.\",\n district: \"Charhollow\",\n traits: [\n \"tough\",\n \"reckless\",\n \"candid\"\n ]\n },\n {\n name: \"Hopper\",\n type: \"npc\",\n description: \"A drug addict, whisper, and all-around weirdo who perches on rooftops in the district. Hopper claims to see \\\"ghost rails\\\" and \\\"spirit trains\\\" originating deep beneath Coalridge, stretching beyond the horizon.\",\n district: \"Coalridge\",\n traits: [\n \"weird\",\n \"visionary\",\n \"enthusiastic\"\n ]\n },\n {\n name: \"Mardin Gull\",\n type: \"npc\",\n description: \"Owner and operator of the Leaky Bucket public house. Mardin was the leader of the Crows many years ago, before Roric and Lyssa, and now enjoys a comfortable retirement out of the scoundrel life.\",\n district: \"Crow's Foot\",\n traits: [\n \"charming\",\n \"experienced\",\n \"respected\"\n ]\n },\n {\n name: \"Mordis\",\n type: \"npc\",\n description: \"A strange merchant which hides its true appearance beneath many layers of robes and hoods. Also fences occult and arcane stolen goods, no questions asked.\",\n district: \"Nightmarket\",\n traits: [\n \"secretive\",\n \"insightful\",\n \"arcane\"\n ]\n },\n {\n name: \"Madame Tesslyn\",\n type: \"npc\",\n description: \"Operates the Red Lamp brothel, the oldest and most respected institution of its sort in the city.\",\n district: \"Silkshore\",\n traits: [\n \"confident\",\n \"insightful\",\n \"enthusiastic\"\n ]\n },\n {\n name: \"Flint\",\n type: \"npc\",\n description: \"A spirit trafficker who trades out of a condemned manor house.\",\n district: \"Six Towers\",\n traits: [\n \"weird\",\n \"calculating\",\n \"suspicious\"\n ]\n }\n ],\n Scores: [\n {\n name: \"Accidental Death\",\n category: \"Secret Dirty Work\",\n desc: \"Not only must the target die, the target must not know how death came. If by some misfortune the ghost of the victim is interrogated, it must not have any special knowledge. There is a ritual and an amulet for the assassins to ensure secrecy. No one living or dead can know who did this deed.\",\n narrative: \"By the time the crew knows the job, there is a better than even chance their knowledge is too much risk and their employer plans to kill them. They might want some leverage.\"\n },\n {\n name: \"Bayer's Train Heist\",\n category: \"Misplaced Fortune\",\n desc: \"Bayer was a rail jack fired for being drunk. Over years, he built a crew with one mission in mind--robbing a train. When lruvia completed negotiations with Akoros to buy an unprecedented mass of leviathan blood to pour into industrialization, Bayer's crew hit the train carrying the payment, sabotaging a bridge. Rescuers found the train in the canyon, but no gold--an impossible feat. Bayer's crew vanished.\",\n narrative: \"An Iruvian ingot stamped with the year \\\"802\\\" will attract attention.\"\n },\n {\n name: \"Bellweather Architectural Plans\",\n category: \"Historical Curiosity\",\n desc: \"The Duskwall Archives have the sanitized blueprints of the Bellweather Crematorium on file. The original plans were drawn by a Spirit Warden driven mad by an internal rift, so he haunted himself. He drew peculiar plans with occult underpinnings, and those original drawings were interpreted by architects.\",\n narrative: \"Are there coded secrets in the original plans that reveal a repellant secret or ominous threat? Or are the plans the scribbling of a madman? Either way, some people would pay top coin to get a good look.\"\n },\n {\n name: \"Book of Walls\",\n category: \"Historical Curiosity\",\n desc: \"Long ago, a nameless rogue cultivated a mass of bloodworms in a wall. He wrote a book with their blood. The words were nonsense, but strangely affecting; if the reader tuned in to them, and held the book, the reader could walk through a wall. Spirit Wardens ruined the book with holy smoke.\",\n narrative: \"A legend, or is there truth to it? Walking through walls is a neat trick, and the book may hold the key to learning it. It is sought by a wide variety of the curious—scholars, collectors, and scoundrels.\"\n },\n {\n name: \"Censer Mace of Udoch\",\n category: \"Religious Object\",\n desc: \"The head of this ornately carved mace opens on hinges so incense can be put inside to wisp as the mace swings. The haft has a recipe carved into it, instructions to make special incense out of bone and rare sap and unguents. If that incense bums in the mace, it can destroy ghosts or demons with a single hit.\",\n narrative: \"This was a founding artifact of the Church of the Ecstasy of the Flesh. If it were returned, they would gain a fresh following from critics who feel the church cannot protect against supernatural threats.\"\n },\n {\n name: \"Charter of Crows\",\n category: \"Historical Curiosity\",\n desc: \"This gauntlet is made out of crow beaks. Each beak is carved with arcane symbols. Consulting Whispers officially report it does not have any power in the Ghost Field. It was made by the Spirit Warden who first tamed the deathseeker crows; he claimed it was a treaty that guaranteed their service.\",\n narrative: \"Spirit Wardens lost this gauntlet decades ago, but they want it back. The idea it is a treaty with the deathseeker crows is probably nonsense. They can't take that chance.\"\n },\n {\n name: \"Combination Harpsichord\",\n category: \"Weird Scholarship\",\n desc: \"TARNALI was a Whisper composer who built a special harpsichord. When two tones are played, often a third \\\"ghost\\\" tone can be heard. By attaching the tuning pegs to crystals and runes, Tarnali built a harpsichord that could interact with the Ghost Field through calculated progressions of played tones.\",\n narrative: \"This effort is intensely interesting to those who want to find doors hidden in the Ghost Field, draw or repel what lurks Behind the Mirror, or develop more portable tonal energies for non-Whispers .\"\n },\n {\n name: \"Dyvik's Chaser Mask\",\n category: \"Weird Artifact\",\n desc: \"This silvery face mask has the word “Elekthiaron” etched along its inner edge. When the word is spoken, the personality of the one touching the mask is pulled into it. The personality that was in the mask goes in the body. If the one in the body doesn't touch the mask once a week, madness threatens.\",\n narrative: \"Has someone been using the mask to pose as someone else? How long has that been going on? Is there someone in the mask that needs rescuing? Was the mask used to cheat biological death?\"\n },\n {\n name: \"Evardian's Song Folios\",\n category: \"Weird Scholarship\",\n desc: \"Four leather-bound volumes, full of musical notation with heavily annotated margins. The \\\"music\\\" is supposed to be transcribed and translated leviathan song. Legend suggests if the music is played correctly, it can drive humans insane with visions of the demon-haunted deep.\",\n narrative: \"Aristocrats will collect anything. Scholars go to great lengths for research material. Cultists may find religious significance in the folios. (Owning the folios is against the law.)\"\n },\n {\n name: \"Falheim's Prod\",\n category: \"Historical Curiosity\",\n desc: \"This ragged pole with a spear and a silver-cable loop was the first prototype of what became the lightning hook. It doesn't work very well, but it was the first historically known charged object that could consistently interact with the Ghost Field.\",\n narrative: \"Apparently this bit of history is an important prestige piece in the turbulent intrigues of a number of underground cults led by Whispers. The city government would also like to display it in a museum.\"\n },\n {\n name: \"Fang of Ibiria\",\n category: \"Religious Object\",\n desc: \"This brutal stiletto has a green stone in the pommel, and a runic symbol on the blade. The blade transforms electroplasm into a mutagen. The longer the blade is in a victim, the more monstrous the victim becomes. A cut gives nightmares, minutes give mutations, hours or days create a real monster.\",\n narrative: \"Cultists want this blade so they can make or become monsters.\"\n },\n {\n name: \"Goblet of Eletrachtian\",\n category: \"Weird Artifact\",\n desc: \"The silver and gold cup is big enough to hold with two hands, crusted with obsidian stones. The owner puts a drop of a demon's blood in the goblet with certain other liquids, and conducts a ritual. For days afterwards (maybe longer) the owner can see anything the demon uses remote vision to view, just by watching the surface's illusory reflections.\",\n narrative: \"There are many legends about the creation of the goblet, and the fate of the Whisper who first energized it. Rumor suggests the Duskwall Council entrusted the goblet to a certain family for safekeeping.\"\n },\n {\n name: \"Hollow Shroud\",\n category: \"Religious Object\",\n desc: \"The Church of the Ecstasy of the Flesh clergy wrapped the funeral shroud around a heretic, then conducted a ritual that severed the heretic's connection to the body, cutting the spirit loose as a ghost. The shroud transferred the spirit of a faithful but sickly member into the heretic's body. New life!\",\n narrative: \"The Shroud was stolen almost twenty years ago, and rumors suggest it has been used in debased rituals to summon demons or enflesh echoes of the Forgotten Gods.\"\n },\n {\n name: \"Idol of the Sleeping Lion\",\n category: \"Religious Object\",\n desc: \"The hefty iron statue depicts a devilfish-headed humanoid, cloaked in wings. Its presence influences human dreams, so they drift through the ink-black sea but can perceive their surroundings. Sacrificing to the statue gives a cultist a cosmic infection, involving psychic ability and mutations.\",\n narrative: \"The statue has been retrieved by officers of the law several times, and destroyed several times more. Again and again, it emerges in the heart of fresh tragedy, baleful and singular.\"\n },\n {\n name: \"Ink Fleece\",\n category: \"Family Heirloom\",\n desc: \"Long ago, Captain Manarill claimed he could prove that leviathans had fur, or fleece. He brought back a swatch of curling fur as big as a bedspread. He claimed to have harvested it from a leviathan's skin. The mantle served as a symbol of the Manarill family's heritage of exploration and danger. But it was stolen.\",\n narrative: \"Does it do more than represent heritage? What dreams might one have while wrapped in it? Might a wealthy Whisper pay more for it than the family that owned it? Who took it?\"\n },\n {\n name: \"Kasavaraya Tea Set\",\n category: \"Family Heirloom\",\n desc: \"When the Immortal Emperor visited Akoros four centuries ago, he used this tea set with the patriarch of the Kasavaraya family. They are still one of the most decorated and entrenched military families in Duskwall. Their tea set is a symbol of Duskwall's prominence. However, a saucer and a cup are missing.\",\n narrative: \"This stuff is priceless, literally, so negotiating a price for its return is tricky. If you could find the missing pieces, or forge them adequately, they would be great hostages to ajfed the family's behavior.\"\n },\n {\n name: \"Kidnap The Heir\",\n category: \"Secret Dirty Work\",\n desc: \"People are keys that fit into estate locks. They can be turned to open the way to lots of money. You might be taking a child to ransom back to the guardian, or you might be getting someone out of the way so a more distant heir can inherit. This is about controlling where the money goes.\",\n narrative: \"How harsh does the employer want this to be? Kid gloves treatment, or is the plan to kill the heir when it is all over? How much input will the employer accept from the hired help? Is the plan already in place?\"\n },\n {\n name: \"Krogs Broken Heart\",\n category: \"Misplaced Fortune\",\n desc: \"Krog was a savage from the Dagger Isles, pressed into service on a hunting ship. He eventually owned a small fleet. He was old when he fell in love with a young woman who robbed him. Heartbroken, he took the rest of his treasure aboard his last hunting ship, Heartsong, and scuttled her in the harbor.\",\n narrative: \"Whispers like to brag they found a way under the waves to find the wealth. Gracmaas the Pirate claimed to have recovered it all to his hidden lair—before he was killed.\"\n },\n {\n name: \"Limptwitch's Stash\",\n category: \"Misplaced Fortune\",\n desc: \"Limptwitch was a Whisper who interrogated ghosts to find the location of hidden treasure. He was famous for his Grotto, the place where he stored all his salvaged wealth. Many factions tried to get his treasure, but he never gave up the secret. Then he was jailed and hanged. The Grotto was never found.\",\n narrative: \"Did a cellmate in prison hear muttered hints as to its location? Maybe a Whisper has clues based on where he left his mark in the sewers. Has someone finally found a real lead?\"\n },\n {\n name: \"Mark of the Void\",\n category: \"Religious Object\",\n desc: \"It is an eerie black disk of leviathan bone, about the size of a dinner plate but five times as thick. The bone is carved with a strange circular pattern with rays cutting through it. The primitive artwork was polished, and silver inlaid in the pattern, by a decadent nobleman.\",\n narrative: \"Impressionable people admit the disk whispers to them, they hear the Back of the Mirror when it the disk is near. Many cults see this disk as a conduit to clearer communication with their supernatural patrons.\"\n },\n {\n name: \"Naladicha's Cartography\",\n category: \"Historical Curiosity\",\n desc: \"The famous cartographer Naladicha died, and his ghost was woven into a spirit anchor connected to a pen on a wire. The drooping pen scribbled nonstop, dipping to indicate a page turn. Two books were filled with scribbles before the pen stilled. These lines and shapes may be maps of the Ghost Field.\",\n narrative: \"One consulting Whisper reported that when she attuned to the books using an expensive and difficult ritual, the maps became luminous and four dimensional, revealing lost secrets in Duskwall.\"\n },\n {\n name: \"Norscye's Lament\",\n category: \"Famous Jewel\",\n desc: \"This ruby has been set in a series of weapons for the last three centuries. One estimate was that the gem had participated in upwards of a thousand deaths. Legend suggests that the ruby can hold a single ghost, surviving the destruction of the body, bound to the gem until it chooses another guest.\",\n narrative: \"While the gemstone is priceless because of its unnatural clarity, it is also possible that an important ghost might be inside, and might choose to speak to a Whisper or a blood relative.\"\n },\n {\n name: \"Orb Of Sellivas\",\n category: \"Weird Artifact\",\n desc: \"This fist-sized golden orb tunes to one bearer at a time, though it may respond to others. If commanded, it can release a steady light that radiates in the material world and the Ghost Field, revealing what is hidden. The radiation can also draw or repel ghosts and demons.\",\n narrative: \"The Sellivas order of witches wrote their research journals in an ink that can only be read by the light of the Orb. If someone had the Orb and the \\\"blank\\\" book, they could crack ancient secrets.\"\n },\n {\n name: \"Plant Evidence\",\n category: \"Secret Dirty Work\",\n desc: \"Someone needs to be found guilty of doing something. For that to work out, you need evidence, put in the wrong place at the wrong time. To manage that, you need proper scoundrels.\",\n narrative: \"Do you know what the target will be accused of doing? Are you to lead the authorities to the evidence? Must someone be seduced before a hidden witness? Are the scoundrels making evidence, or using what they're given? What if they could do better? Must the evidence fool a court, or a powerful individual?\"\n },\n {\n name: \"Plasmic Blade Flail\",\n category: \"Weird Artifact\",\n desc: \"This weapon can slay ghosts and demons. It appears to be a gladius stitched with runes. Once the bearer attunes to the weapon, it can disconnect into vertebrate-like wedges connected by a steely central cable. The blade-whip is flexible and simmering with energy. It can reform into a straight blade at will.\",\n narrative: \"Only five of these flails ever existed. One is carried by the Spirit Warden assigned to the Immortal Emperor's defense. The rest are the stuff of legends.\"\n },\n {\n name: \"Remote Writer\",\n category: \"Weird Artifact\",\n desc: \"This little book has a peculiar occult symbol on the cover. If an object is placed between the covers for a full 24 hours, then the book will transcribe any conversation happening in earshot of the object until reset. When the book reaches the end, the writing starts over on the first page, clearing pages as it goes.\",\n narrative: \"The book provides remote reading, eavesdropping of a sort. A target's favorite pen or lucky coin can become the broadcaster, and determined spies can copy the magic book writing so they don't lose it.\"\n },\n {\n name: \"Rylaria's Shield\",\n category: \"Family Heirloom\",\n desc: \"Rylaria Graefwold was a soldier who gained title and wealth. She wrote her life's story on the back of the shield she used to save a general. Later generations added to the family story. The shield represents the family's honor. It was lost at sea when their first leviathan hunting ship was wrecked. Or was it?\",\n narrative: \"Now the family is wealthy, and this artifact would be important to them. Does it have a secret in code?\"\n },\n {\n name: \"Skovlan Scrip\",\n category: \"Misplaced Fortune\",\n desc: \"A dense lockbox filled with paper money issued by the Akorosian government to pay soldiers quelling the Skovlander Insurrection. The scrip can be exchanged for coins or services in Duskwall. Scrip is basically untraceable.\",\n narrative: \"Some of the military supply that got lost during the war. Does the stashs location implicate a corrupt official or other thief?\"\n },\n {\n name: \"Sonurian Ghost Key\",\n category: \"Family Heirloom\",\n desc: \"The Sonuria family had mansions in the area that is now the Seven Shallows slum. They created a vault for the protected dead, and for their mundane treasures. The only way in is for a family member to present the Sonurian Ghost Key before the hidden location of the vault in the Ghost Field. The key has been lost for decades.\",\n narrative: \"That key could be hidden anywhere. If it were found, either a family member could be recruited to open the door, or the key could be sold to the family. What does the key look like? What is inside the vault?\"\n },\n {\n name: \"Soultrap Carnelian\",\n category: \"Famous Jewel\",\n desc: \"This semi-precious stone was carved by the Whisper Ichralia. She suffocated people with hot wax and bound their fresh ghosts in wax seals on scrolls or letters with the Soultrap. When the seal was broken, the insane ghost attacked the opener and anyone nearby.\",\n narrative: \"The Spirit Wardens destroyed this object decades ago. Didn't they? Maybe someone else made another one, or maybe the original survived.\"\n },\n {\n name: \"Steal Blackmail\",\n category: \"Secret Dirty Work\",\n desc: \"Secrets must be protected. If they come out, people can get hurt, ruined, killed, and so on. You are hired to adjust the circle of people who can prove something. Will it be bigger? Or smaller?\",\n narrative: \"Do you know what information you're after, or is that secret from you? If you have a chance, will you peek at it? Are you targeting a blackmailer to remove their hold, or getting evidence to give a blackmailer? Is the evidence to be destroyed? Do you plan to do as you are told?\"\n },\n {\n name: \"Terrorize\",\n category: \"Secret Dirty Work\",\n desc: \"People can be stubborn, to the point where only fear can unseat their decision. Maybe they feel independent and need to reminded that they need protection. Maybe they feel safe and need to be reminded they are not untouchable.\",\n narrative: \"Are you supposed to be someone in particular, like a random street thug or rival's employee or bluecoat? How far can the terror go? Do you need to trash a home, or maybe converse with a loved one?\"\n },\n {\n name: \"The Emerald Well\",\n category: \"Famous Jewel\",\n desc: \"This depthless gem is a chilly pinhole between the material world and the Ghost Field. It provides energy to Whispers and attracts ghosts. The Emerald Well was protected by the Church of the Ecstasy of the Flesh, but a thief stole it decades ago. It is a hotspot for supernatural activity. Disaster flows in its wake.\",\n narrative: \"This is one of the few objects pursued by demons, Whispers, inspectors, clergy, and collectors. Scholars suggest demons may be able to turn it inside out, creating a fresh gate to incarnate more demons.\"\n },\n {\n name: \"The Hellwhisper Ring\",\n category: \"Weird Scholarship\",\n desc: \"The ring is made of tiny bits of bone wired together. It must be worn for at least a day per year of the bearer's life before it begins to work. When placed on a source of information, the ring sifts it until the ring speaks the information's \\\"language.\\\" The bearer can see through riddles, read arcane texts, and break code with ease.\",\n narrative: \"Legend says 32 demons voluntarily gave some of their bone to be part of this ring, and it was released among humans to cause chaos through greater understanding.\"\n },\n {\n name: \"The Helsman Inheritance\",\n category: \"Misplaced Fortune\",\n desc: \"The final will and testament of the clan's patriarch included a 24 hour locked-house condition. Survivors would split the inheritance. Darayl Helsman left the house at the end of the time with a small bag. Explorers found nothing but corpses in the house, the inheritance was gone. Darayl was found dead the next day, the bag gone. The city locked the house and guards against trespassers.\",\n narrative: \"Surely Darayl hid the inheritance in the Ghost Field. Find the ghost key and lock in the house, and get it all! Or, did someone else already get it?\"\n },\n {\n name: \"The Key Lens\",\n category: \"Weird Scholarship\",\n desc: \"The round frame has forty special lenses hinged on its rim. The lenses can layer over each other, flip out past the frame, rotate to take advantage of the angles inside the ground crystal, and take translucent colored filters. Their inventor, VLAS HALDAK, said he had found \\\"the key.\\\" He died of shock, the lens on his work table.\",\n narrative: \"Legends vary. It can see into the Ghost Field, it can see into people, it allows reading demonic texts, it can see the way into ghost neighborhoods, etc. Needs a Whisper to use properly.\"\n },\n {\n name: \"The Leviathan's Eye\",\n category: \"Famous Jewel\",\n desc: \"This sapphire turns impossibly black if dipped in leviathan blood. If the still-bloody stone is pressed against a seer's forehead, the sensitive can see what the ocean sees, looking above the waves or probing the deeps. The gem used to be passed around between leviathan hunter captains, but has since been lost.\",\n narrative: \"One expert said using the Eye was as close as a human could get to a demon seeing through its elemental affinity, and that it began a slow change in the individual who was exposed to its power.\"\n },\n {\n name: \"The Tabissera Diary\",\n category: \"Weird Scholarship\",\n desc: \"Warden Khalana Uress was the Head Confessor of the Spirit Wardens. She recorded secrets that were only for the use of the order using a book code, coordinates that pointed to words in a specific book. Without that book, the code cannot be cracked. Daring thieves took the book, then lost it.\",\n narrative: \"Fakes come on the market all the time. Only the Spirit Warden leadership know what the book looked like, and they aren't telling. What is the Diary about?\"\n },\n {\n name: \"The Thousand Facet Diamond\",\n category: \"Famous Jewel\",\n desc: \"This gem is the elegant centerpiece on the back of a peculiar clockwork gauntlet. A seer can use the gauntlet to travel into the Ghost Field while retaining physical presence, or possibly even other dimensions. Each use burns out some of the diamond facets. The device is reported to have a mind of its own.\",\n narrative: \"Ever since its theft from the Adelairde family, the gauntlet has surfaced only in rumors of especially daring heists or mind-shattering experiments.\"\n },\n {\n name: \"Whitecrown Signet Ring\",\n category: \"Family Heirloom\",\n desc: \"The Whitecrown family schismed in the wake of the theft of the matriarch's signet ring over two centuries ago. They fell from being players in the intrigues around the throne to bickering over dwindling family holdings. Their wealth and influence is low, but not beyond recall.\",\n narrative: \"If the ring resurfaced, elements of the feud might put aside their differences and reunite. Besides, legends suggest a ghost matriarch is bound to the ring, and she knows their secrets.\"\n }\n ]\n }\n};\nconst ClockKey_SVGDATA = {\n 1: {\n height: 836,\n width: 230,\n paths: [\n \"M217.017,123.52c-1.6-0.8-2.84-1.44-4.1-2.04c-1.12-0.53-2.26-1.04-3.42-1.51 c-1.05-0.43-2.18-0.68-3.18-1.19c-0.89-0.45-1.23-1.23-1.2-2.36c0.09-4.48-0.07-8.97,0.05-13.45c0.08-3.31-0.83-6.47-1.14-9.72 c-0.01-0.14-0.09-0.28-0.14-0.42c-0.57-2.01-1.2-4.01-1.69-6.04c-0.45-1.85-0.75-3.74-1.11-5.61 c-0.012-0.043-0.023-0.085-0.035-0.127c-0.6-1.69-1.348-3.353-1.825-5.083c-0.46-1.66-0.68-3.38-1.03-5.07 c-0.04-0.24-0.16-0.47-0.25-0.7c-0.49-1.32-0.98-2.65-1.47-3.97c-0.55-1.44-0.93-2.97-1.69-4.28c-0.79-1.35-0.65-3.03,0.61-4.19 c0.43-0.39,0.85-0.85,1.08-1.36c0.57-1.3,1.35-2.62,1.44-3.97c0.08-1.11-0.46-3.08-1.14-3.29c-1.58-0.47-3.49-0.42-5.1,0.03 c-1.41,0.4-2.59,1.63-4.07,2.62c-1.15-1.18-2.43-2.41-3.6-3.75c-0.41-0.47-0.43-1.29-0.82-1.78c-0.67-0.84-1.56-1.5-2.23-2.33 c-0.18-0.22-0.08-0.9,0.13-1.16c0.85-1.02,1.78-1.97,2.71-2.92c2.18-2.22,4.37-4.45,6.57-6.65c0.85-0.86,1.78-1.64,2.63-2.5 c1.16-1.17,2.38-2.29,3.37-3.59c0.66-0.88,0.89-2.07,1.42-3.06c0.86-1.63,0.01-3.02-0.68-4.31c-0.23-0.43-1.4-0.4-2.15-0.48 c-0.69-0.08-1.4,0.02-2.09-0.02c-1.71-0.11-3.14,0.17-4.52,1.47c-1.22,1.14-2.96,1.74-4.44,2.62c-0.98,0.59-1.89,1.31-2.88,1.88 c-2.02,1.17-4.2,2.11-6.07,3.47c-1.12,0.81-2.16,1.18-3.49,1.4c-1.28,0.22-2.44,1.1-3.7,1.59c-0.58,0.23-1.72,0.49-1.82,0.3 c-0.91-1.63-2.75-1.79-4.03-2.77c-0.33-0.25-0.58-0.62-0.93-0.82c-1.11-0.64-2.26-1.22-3.38-1.85c-1.48-0.83-2.94-1.7-4.42-2.53 c-0.93-0.53-1.83-1.24-2.84-1.5c-1.37-0.35-2.24-1.96-3.89-1.5c-0.08,0.03-0.19-0.02-0.29-0.04c-1.97-0.58-3.94-1.16-5.91-1.73 c-0.28-0.08-0.76-0.02-0.84-0.18c-0.89-1.7-2.8-1.2-4.1-1.6c-2.83-0.87-5.94-0.87-8.94-1.22c-0.39-0.04-1.05,0.06-1.14-0.13 c-0.79-1.56-2.21-1.01-3.4-1.05c-2.09-0.08-2.68-0.62-2.72-2.65c-0.01-0.84-0.1-1.69-0.24-2.51c-0.16-0.88-0.54-1.72-0.62-2.59 c-0.13-1.24-0.03-2.49-0.11-3.73c-0.06-0.88-0.61-1.45-1.5-1.13c-0.79,0.28-1.59,0.72-2.21,1.28c-1.48,1.36-2.85,2.84-4.29,4.25 c-1.1,1.08-2.08,2.06-3.81,2.55c-1.54,0.44-2.99,1.69-4.63,2.42c-1.79,0.8-3.28,2.25-5.44,2.13c-0.44-0.02-1.16-0.02-1.28,0.22 c-0.7,1.36-1.94,0.82-2.98,0.97c-0.49,0.07-0.99,0.11-1.47,0.24c-1.92,0.49-3.84,0.98-5.75,1.52c-1.74,0.49-3.51,0.95-5.19,1.61 c-1.92,0.74-3.67,1.99-5.63,2.46c-1.64,0.38-3.01,1.13-4.51,1.72c-0.99,0.39-2.52,0.38-3.43-0.13c-1.93-1.09-4.28-1.09-6.03-2.54 c-0.22-0.19-0.67-0.12-1.02-0.13c-0.9-0.02-1.79-0.02-2.69-0.02c-1.37,0.01-2.19,0.72-2.36,2.15c-0.09,0.78-0.06,1.59-0.09,2.38 c-0.01,0.35,0.11,0.87-0.06,1.02c-1.68,1.35-0.89,3.24-1.18,4.9c-0.16,0.88-0.56,1.8-1.1,2.51c-0.75,0.99-1.76,1.79-2.61,2.72 c-1.02,1.1-1.99,2.26-2.99,3.39c-1.49,1.67-2.96,3.37-4.5,5c-1.36,1.45-2.81,2.83-4.2,4.25c-0.16,0.17-0.19,0.46-0.31,0.67 c-0.74,1.29-1.39,2.64-2.25,3.84c-0.89,1.25-2.63,1.86-2.72,3.75c-0.02,0.38-0.57,0.73-0.86,1.11c-0.37,0.49-0.79,0.96-1.07,1.5 c-0.73,1.39-1.26,2.89-2.1,4.21c-1.08,1.71-2.25,3.34-2.65,5.38c-0.07,0.32-0.39,0.6-0.57,0.91c-0.21,0.34-0.45,0.67-0.59,1.05 c-0.43,1.21-0.72,2.48-1.24,3.65c-0.79,1.76-1.75,3.45-2.6,5.19c-1.27,2.6-2.74,5.13-3.69,7.85c-0.5,1.45-0.18,3.23-0.08,4.85 c0.05,0.7,0.68,1.37,0.69,2.06c0.06,6.07,0.06,12.15,0.01,18.23c0,0.71-0.37,1.44-0.63,2.13c-0.35,0.95-1.04,1.85-1.09,2.8 c-0.07,1.31-1.04,1.92-1.62,2.82c-0.91,1.43-2.71,1.9-3.59,3.51c-1.01,1.85-0.94,3.91,0.46,5.41c1.17,1.24,2.59,0.75,3.93,0.97 c1.41,0.22,3.01,0.26,4.12,0.99c1.11,0.74,1.87,2.16,2.5,3.43c0.77,1.56,1.35,3.24,1.8,4.92c0.67,2.5,0.94,5.12,2.32,7.4 c0.56,0.92,1.03,1.9,1.52,2.87c0.51,1.03,0.96,2.09,1.48,3.11c0.56,1.09,1.13,2.18,1.77,3.22c0.29,0.48,0.84,0.8,1.16,1.26 c0.61,0.87,1.11,1.82,1.71,2.69c0.32,0.47,0.83,0.81,1.16,1.27c0.93,1.3,1.79,2.65,2.73,3.95c0.31,0.43,0.83,0.69,1.15,1.11 c0.52,0.69,0.89,1.51,1.44,2.16c0.41,0.48,1.1,0.72,1.54,1.18c1.57,1.66,3,3.46,4.65,5.03c1.3,1.26,2.91,2.18,4.25,3.4 c1.99,1.84,3.82,3.85,5.81,5.7c0.51,0.47,1.42,0.47,1.99,0.9c0.95,0.71,1.78,1.59,2.88,2.59c-0.72,0.66-1.63,1.5-2.55,2.33 c-0.78,0.7-1.61,1.34-2.34,2.07c-1.54,1.55-3.05,3.13-4.54,4.73c-1.24,1.32-2.6,2.56-3.6,4.05c-0.6,0.91-1.1,1.85-1.89,2.63 c-1.23,1.21-1.21,4.03,0.24,4.66c1.03,0.45,2.61,0.53,3.57,0.03c1.41-0.72,2.76-0.5,4.14-0.57c1.93-0.09,3.89,0.02,5.8-0.21 c1.19-0.14,2.33-0.75,3.46-1.2c0.49-0.19,0.89-0.6,1.38-0.76c0.46-0.16,1.13,0.06,1.45-0.21c2.19-1.82,5.18-1.79,7.53-3.48 c1.41-1.01,3.25-2.21,5.36-2.06c0.28,0.02,0.58-0.29,0.88-0.44c0.42-0.22,0.85-0.61,1.29-0.62c3.43-0.04,6.86,0,10.3,0.03 c0.38,0,0.99-0.01,1.11,0.21c0.64,1.13,1.69,0.85,2.63,0.91c1.1,0.06,2.24-0.13,3.27,0.14c2.96,0.79,5.9,1.59,9,1.58 c6.02-0.03,12.05,0.27,18.01-0.93c0.82-0.17,1.69-0.08,2.52-0.24c1.04-0.2,2.05-0.52,3.14-0.81c0.13,0.6,0.21,0.79,0.21,0.98 c0.01,8.226,0.03,16.462,0.01,24.699c-0.001,0.368-0.217,0.882-0.515,1.099c-0.676,0.493-1.572,0.71-2.176,1.273 c-1.37,1.26-2.6,2.68-3.92,4c-0.73,0.73-1.61,1.32-2.31,2.08c-0.98,1.06-0.96,2.42-0.9,3.78c0.07,1.95,0.64,2.62,2.59,2.67 c1.712,0.061,3.434,0.019,5.146,0.03c1.112,0.007,2.014,0.908,2.024,2.02c0.06,6.72,0.08,13.44,0.15,20.16 c0.019,1.205-0.537,1.936-1.437,2.533c-0.23,0.153-0.451,0.318-0.644,0.516c-1.605,1.643-3.165,3.308-4.789,4.931 c-0.63,0.64-1.57,1.05-2.01,1.79c-1.29,2.14-3.22,3.55-5.3,4.69c-2.51,1.38-2.76,1.58-2.61,4.33c0.09,1.65,1.84,3.48,3.41,3.17 c1.82-0.35,3.74-0.85,5.26-1.85c0.77-0.51,1.38-0.68,2.16-0.71c0.95-0.04,1.9-0.01,2.84-0.01c2.59,0.01,3.03,0.46,3.03,3.1 c-0.01,31.18-0.02,62.36-0.04,93.55c0,2.88-0.13,5.78,0.03,8.66c0.16,2.8,0.67,5.58,0.91,8.39c0.15,1.83,0.08,3.68,0.15,5.52 c0.02,0.42,0.14,0.85,0.29,1.25c0.23,0.58,0.66,1.12,0.75,1.72c0.13,0.93-0.34,2.21,0.13,2.78c1.82,2.18-0.35,4.04-0.21,6.04 c0.01,0.2-0.21,0.41-0.31,0.62c-0.53,1.08-1.43,2.14-1.49,3.24c-0.21,4.27-0.19,8.56-0.19,12.84 c-0.01,51.9,0.01,103.81-0.05,155.71c0,4.36-0.54,8.71-0.84,13.06c-0.03,0.34-0.19,0.66-0.31,0.98c-0.25,0.69-0.73,1.36-0.74,2.05 c-0.12,5.68-0.07,11.36-0.23,17.03c-0.11,3.65-0.78,7.31-0.68,10.95c0.12,4.59-0.27,9.16,0.58,13.82 c0.85,4.63,0.19,9.53,0.21,14.31c0.01,1-0.27,2.32,0.24,2.92c1.2,1.39,0.69,2.89,0.79,4.35c0.03,0.33-0.22,0.7-0.37,1.03 c-0.25,0.55-0.55,1.06-0.76,1.62c-0.17,0.44-0.2,0.93-0.36,1.38c-0.47,1.36-0.97,2.72-1.45,4.08c-0.11,0.31-0.11,0.7-0.3,0.94 c-1.58,2-2.33,4.36-2.52,6.8c-0.23,3.07-0.06,6.17-0.08,9.26c-0.02,3.62,0.05,7.24,0.93,10.78c0.07,0.3,0.39,0.56,0.42,0.86 c0.13,1.29,0.2,2.59,0.29,3.88c-0.91,0.05-1.84,0.23-2.72,0.09c-0.66-0.1-1.24-0.71-1.91-0.9c-1.83-0.53-3.81,1.69-3.74,3.17 c0.1,2.16,0.3,4.33,1.59,6.15c1.14,1.6,2.44,3.09,3.73,4.57c1.18,1.36,2.64,2.45,2.25,4.66c-0.47,2.6-0.66,5.25-1.01,8.26 c-4.52,0.25-8.9,0.65-13.3,0.72c-8.65,0.13-17.32,0.08-25.98,0.13c-0.58,0-1.24-0.02-1.74,0.22c-1.03,0.49-1.92,1.28-2.97,1.7 c-1.85,0.75-3.77,1.31-5.65,1.96c-0.22,0.07-0.42,0.22-0.63,0.32c-1.16,0.57-2.28,1.38-3.51,1.64c-1.03,0.21-1.79,0.61-2.49,1.28 c-0.2,0.19-0.4,0.5-0.62,0.51c-1.14,0.08-2.03,0.39-2.85,1.34c-0.63,0.73-1.75,1.04-2.67,1.49c-1.72,0.84-3.48,1.61-5.18,2.49 c-1.48,0.77-3.04,1.49-4.33,2.53c-1.49,1.21-2.68,2.8-4.09,4.14c-0.84,0.79-1.75,1.75-2.79,2.02c-1.46,0.39-2.97,0.34-4.52,0.83 c-2.05,0.64-4.39,0.08-6.57,0.95c-1.38,0.54-3.25-0.48-4.4,1.21c-0.07,0.1-0.38,0.03-0.58,0.05c-2.5,0.25-4.95-0.04-7.53,0.73 c-3.19,0.97-6.74,0.74-10.14,1.08c-0.59,0.06-1.36,0.23-1.7,0.63c-0.83,1.02-0.42,3.75,0.69,4.4c0.91,0.54,2,0.82,3.05,1.07 c0.66,0.15,1.4-0.06,2.08,0.05c1.68,0.29,3.67-0.91,5.01,1.05c0.07,0.1,0.38,0.06,0.58,0.07c4.87,0.2,9.72,0.09,14.61,0.8 c4.38,0.64,8.94-0.01,13.42,0.18c3.03,0.13,5.86-0.88,8.82-1.09c0.14-0.01,0.35-0.06,0.4-0.15c0.61-1.3,1.84-0.85,2.85-1.06 c0.57-0.11,1.2-0.3,1.65-0.65c0.83-0.64,1.45-1.63,2.35-2.1c2.5-1.32,4.56-3.31,7.19-4.45c1-0.43,1.58-0.43,2.51,0.04 c0.62,0.31,1.68,0.25,2.33-0.08c1.06-0.53,1.88-0.64,2.74,0.22c0.76,0.76,1.53,1.51,2.34,2.23c1.14,1.02,2.41,1.91,3.46,3.02 c1.04,1.08,1.85,2.38,2.78,3.56c1.11,1.4,4.49,1.72,5.94,0.58c1.29-1.01,1.57-2.52,1.85-3.97c0.24-1.24,0.03-2.49,0.68-3.78 c0.9-1.75,1.39-2.39,3.41-2.36c2.29,0.02,4.58,0.1,6.87,0.11c1.04,0.01,1.62,0.52,1.84,1.5c0.31,1.31,0.45,2.68,0.96,3.9 c0.36,0.85,1.11,1.71,1.91,2.16c1.23,0.7,4.69-0.66,5.09-2.01c0.53-1.73,1.15-3.6,1-5.35c-0.24-2.82,1.44-4.54,2.89-6.43 c0.3-0.39,1.44-0.68,1.72-0.45c1.45,1.23,3.45,2.17,3.18,4.62c-0.06,0.64,0.09,1.3,0.02,1.94c-0.31,3.01-0.68,6.01-0.98,9.02 c-0.08,0.86-0.01,1.74-0.01,2.77c1.08-0.07,1.88-0.05,2.64-0.18c1.12-0.2,2.2-0.62,3.32-0.73c1.38-0.13,2.78-0.05,4.18-0.04 c1.86,0.01,2.13,0.24,1.82,2.07c-0.17,1-0.42,2.39-1.12,2.8c-1.1,0.65-0.86,1.44-0.87,2.24c-0.05,2.1-0.03,4.19-0.01,6.28 c0.01,0.44,0,1.19,0.2,1.26c1.41,0.53,0.81,1.71,0.98,2.64c0.17,0.9,0.34,1.81,0.64,2.66c0.39,1.08-0.23,3.51-1.19,3.75 c-1.67,0.43-3.39,0.66-5.09,0.99c-1.84,0.36-3.67,0.72-5.5,1.11c-0.22,0.05-0.4,0.28-0.61,0.39c-0.43,0.23-0.85,0.56-1.3,0.63 c-0.594,0.081-1.208,0.05-1.82,0.036c-1.386-0.033-2.643-0.905-3.075-2.222c-0.613-1.87-0.822-3.704-0.936-5.614 c-0.03-0.33-0.6-0.59-0.79-0.96c-0.43-0.85-1.13-1.77-1.07-2.62c0.07-0.98,1.05-1.44,2.19-1.38c0.81,0.04,1.64-0.21,2.44-0.43 c0.59-0.16,1.12-0.55,1.72-0.69c0.52-0.12,1.09-0.06,1.63-0.02c1.25,0.08,1.8-0.43,1.76-1.72c-0.05-1.89,0.01-3.78-0.01-5.68 c-0.01-1.66-0.83-2.55-2.56-2.57c-3.84-0.04-7.67-0.02-11.5,0.02c-1.16,0.01-1.74,0.7-1.85,1.83c-0.05,0.54-0.08,1.09-0.24,1.6 c-0.48,1.6-1.38,3.17-1.45,4.78c-0.08,1.83-0.74,3.01-2.08,4.1c-0.83,0.67-1.56,0.79-2.23,0.04c-1.08-1.22-2.09-2.51-3.04-3.83 c-1.06-1.48-1.88-3.17-3.08-4.51c-0.91-1.03-1.92-2.41-3.7-1.84c-0.51,0.17-0.93,0.69-1.44,0.79c-2.58,0.46-4.33,2.33-6.35,3.7 c-2.13,1.45-4.2,2.53-6.93,2.33c-3.17-0.24-6.37-0.07-9.55-0.09c-0.4,0-0.93,0.1-1.16-0.1c-1.75-1.51-4.32-2.07-5.29-4.5 c-0.06-0.13-0.33-0.24-0.5-0.25c-2.1-0.1-3.95-1.56-6.16-1.07c-0.31,0.07-0.68-0.08-1.02-0.17c-0.9-0.25-1.8-0.73-2.71-0.75 c-4.62-0.08-9.25-0.03-13.88-0.05c-0.46,0-0.94-0.13-1.38-0.29c-0.63-0.24-1.23-0.8-1.85-0.81c-6.97-0.06-13.94-0.01-20.91-0.06 c-1.47-0.01-2.4,0.9-3.11,1.81c-1.58,2.02,0.43,5.8,3.19,6.29c1.71,0.31,3.41,0.64,5.12,0.96c0.19,0.04,0.49,0.05,0.55,0.17 c0.65,1.18,1.78,0.83,2.77,0.94c2.9,0.31,5.78,0.66,8.67,1c0.103,0.019,0.206,0.038,0.308,0.057c2.154,0.545,4.296,1.193,6.481,1.6 c1.241,0.232,2.507,0.15,3.769,0.183c0.284,0.007,0.568,0.119,0.821,0.24c0.62,0.28,1.22,0.6,1.83,0.9 c1.33,0.65,2.68,1.25,3.98,1.96c0.4,0.22,0.6,0.76,0.96,1.06c1.45,1.23,2.93,2.41,4.37,3.64c0.97,0.82,1.92,1.67,2.84,2.54 c1.98,1.86,3.98,3.71,5.89,5.64c1.72,1.72,3.46,3.45,4.97,5.36c1.54,1.93,3.34,2.52,5.79,2.51c18.47-0.08,36.94-0.01,55.4,0.02 c2.17,0,4.19,0.14,5.7-2.14c1.09-1.64,2.99-2.73,4.39-4.2c0.74-0.77,1.1-1.87,1.77-2.73c0.68-0.88,1.47-1.69,2.3-2.45 c1.56-1.45,2.81-3.12,3.91-4.94c0.46-0.76,1.51-1.22,1.86-2.01c0.76-1.74,1.56-3.38,3.08-4.61c0.42-0.34,0.88-0.97,0.86-1.44 c-0.08-1.47,0.99-2.28,1.57-3.39c0.75-1.42,1.61-2.73,1.52-4.59c-0.21-4.42-0.08-8.86-0.05-13.29c0-0.61,0.19-1.23,0.35-1.83 c0.14-0.49,0.55-0.98,0.49-1.43c-0.39-3,0.95-5.77,1.1-8.7c0.01-0.2,0.23-0.39,0.34-0.59c0.26-0.47,0.56-0.92,0.78-1.41 c0.59-1.37,1.1-2.77,1.75-4.11c0.19-0.39,0.85-0.54,1.1-0.93c1.25-1.87,2.56-3.71,3.58-5.7c0.73-1.41,1.8-2.83,1.37-4.6 c-0.1-0.41-0.44-1.03-0.73-1.07c-2.3-0.28-4.43-1.46-6.87-1.09c-1.41,0.21-2.88,0.03-4.32,0.03c-2.22,0-2.56-0.51-2.76-2.74 c-0.2-2.19,1.03-4.66-1.1-6.53c-0.08-0.07-0.02-0.29-0.04-0.44c-0.26-2.65,0.17-5.27-0.75-7.99c-0.82-2.44,0.02-5.23-0.93-7.92 c-0.87-2.51,0.15-5.31-1.06-8.11c-1.14-2.64-0.76-5.92-1.16-8.91c-0.31-2.31,0.38-4.77-0.96-6.94c-0.31-0.5-0.91-0.93-1-1.46 c-0.41-2.24-0.68-4.5-1.01-6.76c-0.32-2.2-0.65-4.4-0.99-6.6c-0.03-0.19-0.09-0.47-0.23-0.53c-1.21-0.55-0.86-1.61-0.88-2.55 c-0.25-12.95,0.26-25.89-0.76-38.84c-0.645-8.159-0.207-16.407-0.21-24.606c0-0.326,0.03-0.655,0.132-0.964 c0.498-1.505,1.628-2.909,1.808-4.439c0.32-2.74,0.57-5.52,0.82-8.26c0.521-5.744,0.168-11.569,0.15-17.363 c-0.001-0.411-0.054-0.823-0.201-1.207c-0.519-1.358-1.356-2.643-1.619-4.039c-0.5-2.67-0.7-5.39-1.02-8.09 c-0.04-0.39-0.08-0.79-0.07-1.19c0.07-3.15-0.3-6.32,0.69-9.42c0.41-1.29-0.17-2.87,1.22-3.88c0.1-0.07,0.06-0.37,0.06-0.57 c0.04-8.32,0.08-16.64,0.08-24.96c0-0.43-0.28-0.88-0.45-1.31c-0.19-0.46-0.56-0.9-0.58-1.36c-0.48-11.05,0.53-22.1-0.75-33.17 c-0.77-6.68-0.15-13.52-0.19-20.29c-0.02-4.13-0.15-8.26-0.15-12.39c-0.01-44.063-0.01-88.115,0-132.178 c0-0.883,0.011-1.77,0.117-2.647c0.323-2.687-0.394-5.417,0.813-8.095c0.54-1.2,0.09-2.85,0.14-4.29c0.01-0.42,0.12-0.86,0.28-1.25 c0.26-0.62,0.63-1.2,0.88-1.82c0.14-0.36,0.1-0.78,0.19-1.16c0.48-2.02,1-4.03,1.44-6.05c0.25-1.17-0.47-2.63,1.09-3.39 c0.11-0.05,0.1-0.36,0.11-0.56c0.28-4.51,0.31-9,0.88-13.53c0.7-5.49,0.44-11.15,0.13-16.71c-0.31-5.55,1.18-10.95,0.94-16.46 c-0.02-0.62,0-1.25,0-1.92c0.98-0.1,1.74-0.1,2.45-0.27c0.7-0.17,1.35-0.53,2.03-0.75c1.92-0.62,2.45-1.33,2.42-3.39 c0-0.43-0.07-0.86-0.12-1.48h-4.97c-1.98-0.01-2.64-0.7-2.65-2.73c-0.01-0.75,0.05-1.5-0.01-2.25c-0.53-6.86,1.3-13.97-2.06-20.55 c0.49-2.24-1.35-4.79,0.96-6.8c1.23-1.08,2.27-2.42,3.62-3.33c1.23-0.83,2.52-1.47,3.3-2.84c0.8-1.42,2.89-2.31,4.31-1.95 c1.05,0.28,2.12,0.53,3.13,0.92c2.26,0.86,4.46,1.89,6.75,2.65c0.94,0.32,2.23,0.47,3.05,0.06c1.77-0.89,2.89-2.77,3.34-4.51 c0.76-2.92,0-5.91-1.12-8.69c-0.5-1.24-0.4-1.92,0.76-2.43c1.71-0.75,3.37-1.59,5.07-2.37c2.07-0.95,3.93-2.43,6.34-2.56 c0.29-0.02,0.55-0.33,0.84-0.5c0.37-0.23,0.78-0.65,1.14-0.63c1.59,0.13,3.06-0.23,4.74,0.92c1.61,1.11,4.13,0.99,6.27,1.19 c1.93,0.17,2.82-0.82,3-2.78c0.04-0.43,0.26-0.88,0.47-1.28c0.39-0.75,1.16-1.46,1.2-2.22c0.07-1.42,0.75-3-1.6-3.85 c-1.72-0.61-2.93-2.52-4.52-3.62c-1.38-0.96-2.98-1.6-4.73-2.51c0.24-0.6,0.46-1.24,0.75-1.85c0.82-1.72,1.67-3.42,2.49-5.13 c0.34-0.73,0.5-1.6,1.01-2.17c1.42-1.63,1.98-3.64,2.79-5.55c0.36-0.87,0.45-1.99,1.06-2.59c1.09-1.06,1.52-2.34,1.98-3.69 c0.29-0.85,0.66-1.68,1.09-2.46c0.51-0.93,1.33-1.73,1.67-2.7c0.81-2.39,2.14-3.18,4.45-2.38c0.31,0.1,0.7,0.11,1.03,0.04 c1.17-0.22,2.36-0.41,3.5-0.76c1.24-0.38,2.44-0.9,3.62-1.43c0.21-0.08,0.37-0.5,0.37-0.77 C217.026,126.28,217.017,124.66,217.017,123.52z M143.507,186.1c-0.82,0.65-1.72,0.95-2.7,1.06c-9.15,3.4-19.04,5.26-29.37,5.26 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,143.31,174.167,173.48,143.507,186.1z\",\n \"M214.327,133.65c-1.07-0.77-2.58-1.24-3.21-2.27c-2.25-3.6-6.31-7.65-5.88-11.05 c1.52-12.04-0.33-23.52-2.8-35.1c-1.17-5.49-2.18-10.99,4.72-14.06c1.08-0.48,1.88-3.13,1.63-4.57c-0.19-1.07-2.16-2.19-3.55-2.64 c-6.7-2.14-12.98-4.88-17.4-10.69c-8.86-11.65-19.24-21.69-32.64-27.85c-6.64-3.05-11.86-6.24-11.09-14.54 c0.07-0.78-0.31-1.64-0.64-2.4c-1.25-2.84-2.56-5.66-3.84-8.48c-2.09,2.6-4.15,5.23-6.27,7.81c-1.41,1.73-2.68,4.5-4.41,4.85 c-5.32,1.1-10.85,1.76-16.28,1.67c-10.63-0.18-20.99,1.14-30.97,4.67c-7.85,2.78-15.14,3.77-22.72-1.31 c-3.42-2.29-8.09-2.69-13.48-4.35c1.1,3.41,1.68,5.25,2.3,7.08c2.66,7.87,2.9,14.94-4.11,21.28c-9.76,8.83-16.78,19.74-21.74,31.96 c-3.43,8.43-7.09,16.77-10.4,25.25c-0.69,1.77-0.76,4.07-0.31,5.93c1.61,6.58,3.4,13.13,5.43,19.59c3.09,9.77,5.6,19.86,9.93,29.08 c3.68,7.83,9.58,14.63,14.68,22.14c-0.79,0.96-2.1,2.1-2.8,3.53c-1.36,2.82-2.37,5.81-3.53,8.72c3.12,0.11,6.55,1.11,9.29,0.15 c8.09-2.86,14.4-0.35,20.54,4.73c2.39,1.98,2.05,3.36,0.46,5.32c-5.83,7.15-10.71,15.15-18.99,20.06 c-0.98,0.57-0.82,3.05-1.18,4.65c1.4,0.24,3.08,1.12,4.16,0.63c10.45-4.67,20.76-9.67,31.2-14.38c6.31-2.84,12.43-5.88,19.84-5.85 c10.42,0.05,20.84-1.07,31.26-1.7c1.76-0.11,3.51-0.28,5.42-0.43c0.16,1.54,0.36,2.51,0.36,3.49 c-0.02,59.51,0.09,119.02-0.28,178.52c-0.04,6.76-2.01,13.66-6.63,19.46c-5.78,7.26-11.13,14.88-16.46,22.49 c-0.72,1.03-0.2,2.93-0.26,4.43c1.3-0.02,2.66,0.24,3.87-0.09c5.76-1.56,11.47-3.28,18.14-5.22c0.62,6.25,1.49,10.98,1.5,15.73 c0.13,47,0.21,94.01,0.09,141.01c-0.02,9.45-0.81,18.9-1.43,28.34c-0.51,7.62-1.87,15.22-1.81,22.82 c0.09,11.27,1.35,22.52,1.59,33.8c0.11,4.87-1.07,9.77-1.69,14.65c-0.95,7.5-2.36,14.98-2.73,22.51c-0.3,6.1,1.55,12.38,0.78,18.37 c-0.97,7.49-5.01,14.53-11.46,18.32c-5.29,3.13-12.04,4.52-18.29,5.09c-7.23,0.66-14.61-0.47-21.92-0.75 c-7.56-0.29-13.36-5.01-15.18-12.31c-0.24-0.97-0.97-2.04-1.79-2.6c-3.54-2.44-7.19-4.7-11.02-7.17 c-6.83,8.88-7.82,11.33-7.65,21.13c0.27,15.78,1.28,31.58,0.87,47.34c-0.19,7.12-0.36,13.84,2.91,20.27 c0.57,1.13,1.4,2.86,2.29,2.97c6.4,0.82,12.69,3.55,19.18-1.16c3.35-2.42,8.23-3.21,12.54-3.72c7.41-0.88,14.92-0.84,22.37-1.43 c4.08-0.32,7.49-1.9,7.64-6.78c0.16-4.95,2.49-7.46,7.41-7.25c1.26,3.22,2.35,6.35,3.73,9.34c0.48,1.05,1.56,2.34,2.55,2.54 c3.24,0.62,6.57,0.74,9.86,1.16c3.38,0.42,5.09-0.92,6.01-4.3c1.78-6.56,3.92-13.02,6.08-19.47c1.92-5.71,2.31-11.28-0.26-16.93 c-0.69-1.51-0.6-3.37-1.02-5.99c2.46,0.64,3.97,1.18,5.52,1.41c2.3,0.33,4.62,0.44,6.93,0.65c-0.07-2.7,0.5-5.64-0.37-8.06 c-1.39-3.88-4.05-7.3-5.6-11.14c-2.34-5.79-5.86-11.75-5.96-17.69c-0.58-35.66-0.34-71.34-0.33-107.01c0-1.81,0.12-3.68,0.57-5.42 c3.38-13.1,3.56-26.5,1.68-39.63c-1.53-10.75-1.54-20.97,1.15-31.44c1.09-4.23,1.29-8.84,1.02-13.23 c-1.21-19.88-3.7-39.73-3.94-59.61c-0.62-50.99-0.29-102-0.34-153.01c0-1.66-0.07-3.35,0.18-4.98c1.91-12.43,4.96-24.78,5.62-37.26 c1.28-24.01,3.36-48.15-1.87-72.06c-0.27-1.25,0.73-3.34,1.8-4.23c9.73-8.05,9.78-8,20.31-1.11c0.7,0.46,1.39,1.05,2.17,1.23 c2.36,0.55,6.51,1.85,6.85,1.21c1.35-2.54,2.6-5.99,1.92-8.6c-2.38-9.22-2.43-17.78,3.82-25.59c2.88-3.6,5.07-8.11,8.66-10.71 c4.75-3.45,10.65-5.28,15.88-8.13c2.41-1.3,5.32-2.92,6.4-5.17C220.707,136.36,216.637,135.31,214.327,133.65z M111.437,192.42 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z\",\n \"M216.086,109.69c-0.08-0.48,0.02-1-0.02-1.5c-0.07-0.95,0.16-2.22-0.36-2.76 c-0.73-0.76-2.03-0.97-3.07-1.46c-0.63-0.3-1.24-0.67-1.83-1.05c-0.53-0.33-1.08-0.65-1.53-1.07c-0.8-0.74-1.92-0.81-2.57-2.09 c-1.13-2.22-0.49-4.7-1.75-6.94c-1-1.8,0.07-4.32-0.91-6.51c-0.3-0.67,0.89-2,1.37-3.04c0.65-1.39,2.31-2.03,2.57-3.75 c0.12-0.81,0.64-1.61,1.15-2.28c1.78-2.38,1.16-5.33-1.31-6.02c-1.49-0.42-2.55-1.16-3.72-2.06c-1.21-0.92-2.77-1.49-4.25-1.92 c-1.54-0.44-2.15-1.61-2.84-2.79c-0.59-1.02-1.09-2.11-1.76-3.08c-0.71-1.02-1.59-1.93-2.47-2.98c0.35-0.13,0.74-0.16,0.86-0.35 c1.27-2.02,3.25-2,5.28-1.95c1.15,0.02,2.4,0.21,3.44-0.16c1.28-0.45,2.71-1.16,3.49-2.19c1.24-1.65-0.42-4.48-2.46-4.74 c-1.98-0.25-3.94-0.58-5.91-0.89c-0.18-0.03-0.34-0.15-0.51-0.22c-0.77-0.33-1.52-0.72-2.32-0.95c-0.57-0.16-1.22,0.01-1.79-0.13 c-2.14-0.53-4.24-1.43-6.41-1.61c-1.69-0.14-2.87-0.66-4.02-1.8c-1.28-1.26-2.82-2.26-4.1-3.52c-0.3-0.29-0.23-1.24,0-1.73 c0.44-0.91,1.54-0.97,2.32-1.44c1.74-1.05,3.29-2.45,4.89-3.74c0.52-0.42,1.31-0.9,1.38-1.42c0.19-1.46,0.06-2.96,0.06-4.5 c-2.54-0.33-4.95-0.67-7.38-0.94c-0.89-0.1-1.81-0.01-2.71-0.03c-0.34-0.01-0.68-0.07-1.01-0.16c-0.89-0.23-1.76-0.69-2.64-0.7 c-4.02-0.08-8.04-0.03-12.07-0.05c-0.42,0-1.11,0-1.23-0.23c-1.12-2.09-3.02-1.96-4.92-1.88c-1.14,0.04-1.8-0.46-2.06-1.62 c-0.27-1.22-0.34-2.76-1.12-3.54c-1.17-1.16-0.68-2.45-1.05-3.64c-0.33-1.08-0.81-2.76-1.52-2.93c-2.01-0.5-4.21-0.87-6.23,0.31 c-0.93,0.54-1.88,1.05-2.87,1.44c-1.21,0.48-2.61,0.61-3.7,1.27c-1.77,1.08-3.79,0.89-5.3,0.34c-1.38-0.5-2.66-0.56-4-0.68 c-0.75-0.06-1.5-0.02-2.23-0.16c-0.94-0.18-1.87-0.77-2.76-0.69c-1.9,0.18-3.03-0.91-3.97-2.14c-1.29-1.72-2.14-3.79-3.53-5.41 c-1.31-1.54-1.8-3.71-3.74-4.73c-0.49-0.26-0.96-0.67-1.48-0.73c-0.94-0.12-1.92-0.14-2.85,0c-0.59,0.08-1.26,0.41-1.66,0.85 c-0.55,0.59-0.75,1.49-1.3,2.07c-1.44,1.55-2.99,3-4.48,4.5c-0.13,0.12-0.12,0.38-0.22,0.55c-0.46,0.75-0.9,1.52-1.42,2.22 c-0.5,0.67-1.12,1.24-1.62,1.91c-0.48,0.62-0.79,1.38-1.31,1.96c-1.39,1.54-3.54,0.54-5.35,1.73c-2.13,1.39-5.14,1.6-7.81,1.92 c-2.43,0.29-4.97,0.32-7.37-0.06c-1.44-0.23-2.84-1.32-4.04-2.3c-1.44-1.18-2.57-2.71-4.77-2.47c-0.61,0.06-1.27-0.43-2.23-0.78 c-0.27,0.91-0.79,1.91-0.83,2.92c-0.13,3.22-0.1,6.44-0.1,9.66c0,0.72-0.13,1.16-0.84,1.66c-1.79,1.24-3.39,2.74-5.12,4.08 c-0.33,0.26-0.9,0.26-1.36,0.33c-0.69,0.1-1.75-0.09-2.02,0.28c-0.84,1.21-1.97,0.84-3.05,0.96c-0.53,0.06-1.05,0.27-1.56,0.43 c-1.41,0.44-2.79,0.98-4.23,1.32c-1.4,0.33-3.13-0.6-4.16,1.16c-0.06,0.1-0.38,0.07-0.58,0.08c-1.15,0.07-2.3,0.17-3.45,0.2 c-2.18,0.07-2.94,0.91-2.47,2.97c0.12,0.55,0.55,1.09,0.97,1.51c0.85,0.82,1.83,1.51,2.67,2.35c1.09,1.09,2.1,2.27,2.99,3.24 c-0.99,1.5-1.8,2.84-2.73,4.09c-0.62,0.83-1.51,1.47-2.09,2.32c-1.11,1.6-2.09,3.3-3.12,4.96c-0.31,0.5-0.73,0.96-0.93,1.51 c-0.5,1.33-2.38,2.73-3.8,2.76c-1.15,0.03-2.49-0.24-3.4,0.26c-1.3,0.71-2.55,0.65-3.86,0.66c-2.14,0.01-4.03,0.57-5.36,2.35 c-0.3,0.41-0.32,1.02-0.56,1.48c-0.7,1.31-0.46,3.54,0.67,4.44c0.88,0.71,1.97,1.17,2.86,1.87c0.75,0.58,1.24,1.6,2.06,1.97 c1.26,0.57,1.85,1.38,1.54,2.64c-0.41,1.68,0.4,3.44-0.77,5.14c-0.67,1,0.34,2.85-1.26,3.76c-0.08,0.04-0.05,0.28-0.06,0.43 c-0.07,1.2-0.32,2.3-0.72,3.49c-0.69,2.08-1.06,4.24-2.44,6.06c-1.06,1.41-1.99,2.97-2.99,4.37c-1.47,2.05-3.91,3.38-5.93,5.04 c-0.77,0.63-1.44,1.4-2.26,1.94c-2.24,1.47-2.4,4.44-0.52,6.31c1.02,1.02,2.11,0.63,3.19,0.81c0.52,0.08,1.08,0.08,1.56,0.28 c1.37,0.58,2.71,1.21,4.05,1.87c0.66,0.33,1.54,0.63,1.86,1.2c0.54,0.99,0.73,2.18,1.06,3.29c0.11,0.38,0.15,0.8,0.33,1.14 c0.54,0.96,1.26,1.84,1.67,2.85c1.1,2.69,0.84,5.73,2.18,8.41c0.66,1.31,0.76,2.91,1.15,4.37c0.3,1.13,0.34,2.53,1.05,3.3 c0.9,0.97,0.77,1.95,0.91,3c0.09,0.63,0.37,1.24,0.6,1.95c-0.55,0.45-1.38,0.87-1.82,1.55c-0.96,1.47-1.52,3.18-2.98,4.34 c-1.33,1.06-0.8,2.64-0.82,4.03c-0.02,1.27,1.61,3.18,2.84,3.32c3.02,0.36,6.04,0.64,9.06,0.96c0.33,0.04,0.81,0.04,0.95,0.24 c1,1.45,2.98,2.44,2.17,4.75c-0.11,0.31,0.39,0.78,0.39,1.18c0.02,1.32,0.11,2.68-0.17,3.95c-0.22,1.01-1.1,1.86-1.41,2.87 c-0.54,1.71,0.41,3.02,1.55,4.15c1.28,1.27,1.94,1.24,3.66,0.26c0.96-0.55,1.99-1.12,3.06-1.32c1.94-0.35,3.1,1.4,4.64,2.13 c1.17,0.55,2.17,1.43,3.34,1.98c1.51,0.72,3.1,1.19,4.05,2.8c0.33,0.57,1.26,0.78,1.9,1.19c0.6,0.38,1.4,0.7,1.69,1.26 c0.51,1.03,0.69,2.23,1.05,3.34c0.14,0.4,0.35,0.83,0.65,1.11c0.69,0.66,0.82,3.4,0.13,4.02c-1.03,0.92-1,1.59,0.01,2.49 c0.82,0.73,1.45,1.79,2.39,2.23c0.75,0.36,1.85,0.05,2.78-0.07c0.31-0.04,0.58-0.53,0.9-0.55c3.1-0.24,5.89-1.34,8.58-2.84 c0.3-0.16,0.95-0.17,1.14,0.03c0.76,0.82,2.02,1.28,1.69,2.88c-0.33,1.67,0.2,3.38-1.17,4.99c-1.23,1.45-2.01,3.39-2.64,5.23 c-0.38,1.12-0.54,2.67-0.05,3.67c1.2,2.45,4.7,2.61,6.65,0.57c0.81-0.86,1.69-1.67,2.6-2.42c0.67-0.55,1.47-0.95,2.18-1.46 c0.32-0.22,0.58-0.52,0.85-0.79c0.92-0.91,1.79-1.88,3.23-1.91c0.07-0.01,0.12-0.25,0.21-0.36c0.47-0.55,0.87-1.23,1.45-1.62 c1.52-1.02,3.11-1.93,4.71-2.83c0.26-0.15,0.74-0.13,1.03,0.01c0.92,0.44,2.1,0.77,2.65,1.53c1.27,1.72,2.45,3.58,3.25,5.55 c0.83,2.06,3.35,3.48,5.17,2.57c1.67-0.83,2.63-2.52,4.53-3.18c1.48-0.51,2.62-2,3.93-3.03c0.29-0.22,0.64-0.44,0.98-0.49 c2.46-0.4,4.93-0.75,7.39-1.13c0.2-0.03,0.4-0.06,0.58-0.14c2.21-1.02,3.32-0.31,3.32,2.12c0,14.19-0.05,28.38,0.05,42.57 c0.01,1.86-0.96,2.7-2.18,3.62c-1.74,1.29-3.51,2.55-5.17,3.94c-1.03,0.85-1.73,2.36-2.86,2.77c-2.07,0.74-3.5,2.3-5.3,3.36 c-0.78,0.46-2.38,1.3-1.52,2.46c0.73,0.98,1.51,2.42,3.29,2.29c1.75-0.12,3.52-0.01,5.28,0.04c0.36,0.01,0.79,0.11,1.07,0.32 c0.62,0.47,1.08,1.3,1.76,1.51c2.45,0.76,2.94,2.75,3.4,4.84c0.09,0.38,0.22,0.9,0.49,1.05c1.71,0.98,1.74,2.53,1.65,4.2 c-0.06,1.3,0.03,2.61,0.03,3.92c0,29.84,0.04,59.67-0.06,89.5c-0.01,2.31,0.88,4.73-0.96,7.07c-0.87,1.09-0.54,3.2-0.94,4.86 c-0.58,2.45-0.57,4.95-2.05,7.23c-0.78,1.21-0.76,2.94-1.11,4.44c-0.34,1.49-0.68,2.98-1.03,4.46c-0.03,0.13-0.14,0.34-0.23,0.35 c-1.15,0.18-0.88,1.09-0.84,1.76c0.05,0.94-0.27,1.83,0.87,2.72c0.82,0.63,0.83,2.35,1.12,3.6c0.4,1.74,0.73,3.51,1.09,5.26 c0.03,0.15,0.05,0.32,0.13,0.42c1.29,1.52,1.66,3.35,1.96,5.25c0.2,1.27,0.59,2.51,0.92,3.76c0.03,0.12,0.2,0.2,0.26,0.33 c0.28,0.55,0.77,1.11,0.79,1.68c0.09,3.17,0.09,6.34,0.08,9.51c-0.01,53.22-0.02,106.45-0.08,159.68c0,1.51,0.78,3.34-1.06,4.47 c-0.08,0.05-0.06,0.29-0.07,0.43c-0.29,3.58-0.58,7.16-0.86,10.73c-0.32,4.15-0.63,8.3-0.97,12.45c-0.03,0.37-0.26,0.73-0.4,1.09 c-0.22,0.55-0.64,1.11-0.63,1.66c0.01,2.21,0.17,4.31,0.9,6.56c0.95,2.95,0.48,6.31,0.89,9.51c0.6,4.76,0.19,9.64,0.22,14.47 c0,0.5-0.1,1.11,0.14,1.48c1.42,2.19,0.48,4.57,0.54,6.84c0.04,1.47-0.44,2.98-0.84,4.43c-0.28,0.99-0.67,2.02-1.29,2.82 c-0.83,1.08-1.77,2.01-1.64,3.52c0.05,0.49,0.15,1.21-0.11,1.46c-1.13,1.09-0.65,2.44-0.83,3.69c-0.31,2.06,0.16,4.04-0.82,6.24 c-0.96,2.19-0.26,5.14-0.16,7.75c0.02,0.5,0.87,0.95,0.93,1.47c0.29,2.77-0.03,5.53,0.85,8.32c0.65,2.07,0.26,4.49,0.21,6.75 c-0.04,2.22,0.51,4.38,0.15,6.66c-0.41,2.56-0.2,5.21-0.29,7.83c-0.01,0.43-0.02,1.12-0.27,1.26c-1.4,0.77-2.83,1.57-4.34,2.04 c-1.7,0.53-3.51,0.72-5.26,1.07c-0.15,0.02-0.35,0.06-0.42,0.16c-1.05,1.6-2.96,1.06-4.42,1.69c-1.82,0.79-3.98,0.8-5.99,1.16 c-0.29,0.05-0.67,0.1-0.83,0.3c-1.07,1.37-2.9,1.4-4.18,1.54c-2.35,0.25-4.8-0.49-7.21-0.82c-0.14-0.02-0.32-0.1-0.39-0.21 c-1.13-1.76-2.78-0.72-4.19-0.71c-0.45,0-0.86,0.75-1.36,0.9c-1.49,0.44-3.02,0.74-4.53,1.14c-0.22,0.06-0.35,0.43-0.57,0.58 c-0.67,0.47-1.36,1.26-2.06,1.29c-3.56,0.13-7.14,0.07-10.71,0.04c-0.34,0-0.71-0.21-1.04-0.37c-0.54-0.26-1.05-0.56-1.58-0.84 c-0.82-0.43-1.69-0.79-2.43-1.32c-0.47-0.34-0.64-1.1-1.12-1.39c-1.87-1.14-3.1-2.75-4.11-4.66c-0.29-0.55-1.05-1.17-1.64-1.22 c-2.71-0.22-5.54-0.58-7.69,1.72c-0.83,0.9-1.8,1.06-2.92,1.04c-0.38,0-0.87,0.04-1.14,0.26c-1.57,1.29-3.5,1.51-5.38,1.82 c-2.39,0.39-4.78,0.67-7.17,1.02c-0.22,0.03-0.39,0.29-0.61,0.39c-1.11,0.5-2.2,1.26-3.35,1.41c-2.09,0.25-3.01,0.98-2.64,3.04 c0.19,1.07,0.64,2.49,1.43,2.95c1.21,0.72,2.83,0.7,4.26,1.06c1.65,0.43,3.28,0.93,4.92,1.42c1.01,0.3,2.01,0.63,3.03,0.92 c1.88,0.54,3.74,1.35,5.66,1.53c3.04,0.28,6.13,0.18,9.19,0.18c13.52,0.02,27.05,0,40.57,0.04c1.41,0.01,3.03-0.62,4.13,0.94 c0.1,0.14,0.48,0.07,0.73,0.09c5.48,0.4,11.03-0.61,16.46,0.99c1.95,0.58,4.05,0.68,6.11,1c0.07,1.26,0.61,2.47-0.7,3.3 c-0.85,0.54-1.65,1.22-2.57,1.58c-2.2,0.85-4.44,1.57-6.68,2.32c-0.99,0.34-2.02,0.59-3.01,0.94c-1.67,0.58-3.32,1.21-4.98,1.82 c-0.23,0.09-0.44,0.21-0.66,0.31c-0.53,0.24-1.04,0.64-1.58,0.69c-5.18,0.48-10.35-0.17-15.61,0.68 c-5.76,0.93-11.79-0.18-17.64,1.1c-0.82,0.18-1.73-0.09-2.55,0.08c-1.8,0.37-3.61,0.77-5.32,1.42c-0.58,0.21-1.08,1.13-1.26,1.82 c-0.66,2.45,1.02,5.29,4.03,5.07c1.83-0.13,3.72,0.54,5.59,0.87c0.12,0.02,0.22,0.18,0.34,0.24c0.72,0.31,1.43,0.85,2.17,0.88 c2.51,0.11,5.03,0.09,7.54,0.03c1.18-0.03,2.56,0.41,3.33-1.08c0.07-0.15,0.56-0.11,0.86-0.11c5.22,0.01,10.44,0.02,15.66,0.05 c0.34,0,0.79,0,1,0.19c1.32,1.25,2.86,1.82,4.67,1.79c1.63-0.02,3.26,0.01,4.6,1.25c0.06,0.99-0.12,1.83-1.41,1.95 c-0.23,0.02-0.46,0.31-0.66,0.5c-1.32,1.33-2.56,2.77-3.99,3.98c-1.06,0.89-2.34,2.07-3.56,2.12c-2.5,0.1-4.06,2.03-6.3,2.6 c-1.31,0.34-2.46,1.45-3.98,1.52c-0.29,0.01-0.67,0.07-0.83,0.26c-1.11,1.31-2.62,1.66-4.2,1.76c-1.8,0.12-3.76-0.26-5.37,0.33 c-1.58,0.59-3.07,0.54-4.61,0.59c-1.96,0.05-3.92,0.02-5.88,0c-0.39,0-0.79-0.07-1.16-0.17c-0.83-0.22-1.64-0.59-2.48-0.71 c-2.61-0.36-5.24-0.64-7.85-0.96c-0.15-0.02-0.38-0.06-0.41-0.14c-0.54-1.36-1.74-0.98-2.71-0.99c-4.02-0.06-8.04-0.04-12.07-0.05 c-0.4,0-0.81,0-1.19-0.08c-1.18-0.25-2.34-0.57-3.51-0.81c-0.49-0.09-1.19,0.17-1.47-0.09c-1.49-1.32-3.25-0.64-4.88-0.82 c-0.45-0.05-1.2,0.06-1.3-0.14c-0.68-1.42-1.93-1.03-3.02-1.06c-2.06-0.05-5.27-2.58-6.24-4.39c-0.87-1.64-2.23-3.05-3.48-4.46 c-1.04-1.17-2.36-2.08-3.33-3.29c-0.87-1.07-1.16-2.84-2.21-3.49c-1.93-1.2-2.76-3.77-5.53-3.92c-0.11,0.08-0.58,0.28-0.75,0.63 c-0.28,0.54-0.63,1.29-0.45,1.77c0.48,1.3,1.57,2.45,1.78,3.76c0.36,2.21,2.01,3.73,2.59,5.88c0.45,1.67,1.26,3.48,2.41,5.08 c1.14,1.56,1.41,3.74,2.13,5.63c0.43,1.16,0.89,2.33,1.51,3.4c0.36,0.63,1.01,1.13,1.61,1.59c0.67,0.5,1.52,0.79,2.13,1.35 c0.78,0.7,1.25,1.83,2.11,2.32c1.81,1.02,4.06,1.07,5.77,2.38c0.07,0.06,0.21,0.06,0.3,0.04c2.43-0.53,4.36,1.08,6.06,2.12 c2,1.24,4.52,2.12,5.74,4.61c0.47,0.95,1.67,1.55,3.12,0.54c0.9-0.62,2.18-0.69,3.18-1.48c1.15-0.91,2.59-1.45,3.89-2.16 c0.34-0.18,0.65-0.55,0.97-0.56c2.21-0.07,4.53-0.5,6.59,0.05c1.65,0.44,3.29,0.44,4.91,0.75c3.34,0.63,6.68,1.23,10.11,1.01 c0.19-0.02,0.47-0.04,0.58,0.07c1.69,1.69,4.5-0.27,6.04,1.88c2.64-0.06,5.21,0.33,7.75,1.05c1.35,0.38,2.74,0.65,4.1,0.98 c0.13,0.03,0.21,0.2,0.34,0.27c1.18,0.58,2.33,1.28,3.57,1.7c1.36,0.47,2.81,0.68,4.22,1.01c0.12,0.03,0.22,0.16,0.34,0.24 c0.93,0.58,1.82,1.22,2.8,1.71c1.03,0.51,2.68,0.57,3.1,1.35c1.03,1.92,2.93,2.76,4.5,3.64c1.3,0.73,3.45,0.26,5.09-0.18 c0.46-0.12,0.44-2.05,0.6-3.16c0.06-0.34-0.03-0.71,0.02-1.05c0.29-1.88-1.12-3-1.84-4.46c-0.7-1.42-2.24-1.12-3.03-2.13 c-0.57-0.71-1.11-1.52-1.85-1.99c-1.99-1.26-4.2-2.07-5.98-3.79c-1.42-1.38-3.36-2.21-5.05-3.33c-0.53-0.36-0.97-0.86-1.6-1.43 c1.59-0.28,2.79-0.38,3.91-0.73c1.33-0.42,2.56-1.15,3.88-1.59c1.23-0.41,2.52-0.08,3.86-0.73c1.07-0.51,2.44-1.28,3.54-1.27 c4.9,0.06,9.87-1.42,14.74,0.77c1.85,0.84,4.1,0.89,6.19,1.08c2.2,0.2,4.42,0.08,6.63,0.19c1.39,0.07,2.87-0.36,3.15-1.52 c0.35-1.43-0.11-3.07-0.31-4.61c-0.05-0.35-0.43-0.86-0.75-0.94c-1.89-0.45-3.03-2.61-5.28-2.29c-0.29,0.05-0.76-0.44-0.98-0.79 c-0.55-0.87-1.04-1.78-1.46-2.72c-0.72-1.58-1.07-3.47-2.15-4.72c-1.03-1.21-1.01-2.65-1.64-3.91c-0.95-1.9,1.19-4.82,3.55-5.51 c1.64-0.47,2.56-1.92,3.11-3.23c0.56-1.3,1.48-2.16,2.47-2.65c1.95-1,3.13-2.23,2.85-4.48c-0.15-1.19,0.35-1.95,1.04-2.38 c1,0.29,1.75,0.57,2.54,0.71c0.68,0.12,1.65-0.21,2.05,0.15c1.42,1.25,3.06,0.73,4.59,0.79c1.64,0.07,2.82-1.17,2.72-2.83 c-0.14-2.32,0.71-4.76-1.17-6.9c-1.23-1.41-2.02-3.2-3.05-4.79c-0.22-0.34-0.72-0.52-0.87-0.87c-0.46-1.06-0.77-2.19-1.23-3.25 c-0.29-0.71-0.68-1.39-1.13-2.01c-1.1-1.56-2.04-3.14-1.53-5.37c1.49-0.04,2.78-0.09,3.89-1.32c1.1-1.21,1.2-2.49,1.25-3.92 c0.01-0.23,0.11-0.48,0.24-0.67c1.24-1.84,0.48-3.88,0.58-5.83c0.01-0.15-0.29-0.35-0.49-0.46c-1-0.56-2.03-1.05-3-1.64 c-0.5-0.3-0.84-0.89-1.35-1.13c-1-0.46-2.14-0.66-3.09-1.2c-0.51-0.28-0.94-1-1.07-1.59c-0.43-2.04-0.69-4.12-1.08-6.17 c-0.08-0.39-0.55-0.7-0.63-1.08c-0.19-0.93-0.56-2-0.26-2.78c0.2-0.56,1.73-1.24,2.07-1c1.34,0.91,2.76,0.55,4.13,0.75 c0.3,0.04,0.57,0.28,0.87,0.41c0.5,0.23,0.99,0.58,1.52,0.65c3.46,0.48,6.98-0.42,10.48,0.84c1.88,0.67,4.18,0.23,6.29,0.19 c0.47-0.01,1.28-0.37,1.34-0.69c0.2-1.06,0.29-2.2,0.09-3.25c-0.08-0.41-1.04-0.65-1.59-1c-0.18-0.12-0.3-0.34-0.49-0.47 c-1.59-1.12-3.47-1.86-4.58-3.59c-0.05-0.07-0.2-0.06-0.28-0.11c-0.71-0.43-1.45-0.81-2.11-1.31c-0.61-0.47-1.1-1.11-1.72-1.57 c-0.68-0.5-1.49-0.82-2.16-1.33c-0.65-0.49-1.14-1.21-1.81-1.67c-1.57-1.08-3.21-2.06-4.83-3.08c-0.55-0.35-1.1-0.73-1.69-1.01 c-0.82-0.38-1.8-0.53-2.49-1.06c-0.53-0.41-0.95-1.22-1.04-1.91c-0.29-2.18,0.44-4.47-0.96-6.53c-0.53-0.79-1.11-1.77-1.11-2.66 c-0.06-20.73-0.05-41.46-0.03-62.18c0-0.42,0.15-0.86,0.31-1.25c0.21-0.5,0.64-0.94,0.74-1.45c0.29-1.62,0.18-3.22,0.78-4.9 c0.83-2.34,0.88-4.99,1.09-7.52c0.17-1.95,0.05-3.92,0.11-5.88c0.01-0.47,0.2-0.93,0.37-1.38c0.2-0.51,0.68-0.99,0.69-1.49 c0.05-4.08,0.04-8.15,0.01-12.23c0-0.48-0.04-1.25-0.32-1.39c-0.99-0.49-0.7-1.33-0.78-2.08c-0.35-3.05-0.31-6.21-1.2-9.09 c-0.7-2.29-0.69-4.49-0.62-6.72c0.12-3.64-0.46-7.31,0.67-10.95c0.71-2.26,0.78-4.71,1.14-7.07c0.04-0.24,0.05-0.53,0.19-0.72 c1.27-1.67,1.08-3.79,1.66-5.67c0.44-1.39,0.1-3,0.26-4.5c0.1-0.93,0.2-2.16,0.8-2.68c1.42-1.23,1.05-2.71,1.11-4.18 c0.02-0.75,0.08-1.5,0.08-2.26c0-7.94,0-15.89-0.03-23.84c0-0.4-0.25-0.81-0.42-1.2c-0.21-0.5-0.6-0.97-0.64-1.48 c-0.1-1.3,0.06-2.63-0.09-3.92c-0.13-1.03-0.9-2.06-0.78-3.02c0.31-2.47-0.9-4.62-1.12-6.95c-0.02-0.22-0.23-0.41-0.33-0.63 c-0.25-0.52-0.62-1.03-0.7-1.58c-0.19-1.34,0.04-2.8-0.39-4.03c-0.8-2.24-1.62-4.42-1.62-6.84c0.01-17.65,0.01-35.31,0.01-52.97 c0-0.35,0.01-0.7,0-1.05c-0.02-1.05,0.41-1.5,1.54-1.48c2.96,0.07,5.93,0.14,8.89-0.02c1.36-0.08,2.79-0.5,3.99-1.12 c0.75-0.39,1.46-1.39,1.62-2.23c0.27-1.36,0.17-2.82,0.01-4.2c-0.06-0.53-0.66-1.12-1.16-1.45c-0.95-0.62-2-1.08-3.02-1.6 c-0.99-0.5-1.96-1.06-2.98-1.47c-1.78-0.73-3.61-1.35-5.4-2.06c-0.43-0.18-0.73-0.7-1.16-0.84c-2.24-0.68-2.37-0.81-2.37-3.03 c0.01-25.61,0-51.21,0.02-76.82c0-3.07,0.14-6.13,0.21-9.2c0.01-0.24,0.02-0.5,0.07-0.74c0.27-1.22,0.63-2.42,0.81-3.66 c0.37-2.55,0.64-5.13,0.97-7.69c0.02-0.18,0.12-0.4,0.26-0.51c1.25-1.01,1.6-2.31,1.7-3.89c0.22-3.29,0.67-6.56,1.04-9.84 c0.02-0.18,0.11-0.47,0.23-0.51c1.12-0.39,0.81-1.36,0.9-2.16c0.05-0.55-0.08-1.13,0.06-1.65c0.48-1.75,1.32-3.45,1.53-5.23 c0.29-2.37,0.65-4.96-0.01-7.16c-0.63-2.1-0.45-4.08-0.64-6.11c-0.06-0.75,0.14-1.67-0.22-2.22c-1.07-1.62-0.53-3.36-0.68-5.04 c-0.04-0.45,0-0.91,0-1.36c-0.04-11.77-0.07-23.54-0.12-35.32c0-0.74,0.31-1.64-0.76-2.05c-0.18-0.07-0.26-0.51-0.3-0.79 c-0.28-1.71-0.53-3.42-0.79-5.13c-0.02-0.14-0.04-0.34,0.04-0.43c0.85-1.09,1.42-2.52,3.18-2.48c0.48,0.01,1.01-0.1,1.45-0.3 c1.93-0.87,3.83-1.82,5.76-2.7c0.91-0.41,1.88-0.69,2.8-1.06c0.79-0.32,1.87-0.46,2.28-1.06c1.04-1.51,2.94-0.65,4.08-1.75 c0.2-0.2,0.94-0.09,1.27,0.13c1.02,0.68,1.91,1.57,2.95,2.21c0.97,0.6,2.05,1.01,3.11,1.45c0.77,0.32,1.57,0.54,2.6,0.88 c0.08-0.06,0.43-0.5,0.88-0.68c1.99-0.8,2.28-1.19,2.32-3.33c0.02-0.8-0.16-2.05,0.24-2.3c1.05-0.65,0.8-1.53,0.84-2.37 c0.1-1.85,0.1-3.71,0.2-5.57c0.02-0.46,0.14-1,0.42-1.35c1.19-1.48,2.43-2.92,3.72-4.33c1.85-2.02,3.76-3.98,5.62-5.99 c1.2-1.3,2.41-2.58,3.51-3.96c0.91-1.15,2.34-1.82,2.73-3.48c0.22-0.96,1.04-1.77,1.58-2.66c1.01-1.68,2.08-3.34,2.99-5.07 c0.86-1.63,1.53-3.36,2.33-5.01c0.12-0.24,0.55-0.48,0.82-0.47c0.85,0.06,1.7,0.23,2.56,0.36c1.64-0.37,3.34-0.64,5.04-0.61 c2.2,0.04,4.18-0.16,5.25-2.55c-0.42-0.66-0.75-1.53-1.37-2.07c-1.26-1.13-2.64-2.08-2.54-4.07c0.02-0.43-0.29-0.97-0.6-1.32 c-0.98-1.09-1.88-2.23-2.27-3.68c-0.25-0.92-0.45-1.85-0.7-2.92c0.1-0.16,0.47-0.49,0.53-0.87c0.41-2.81,0.64-5.66,1.19-8.44 c0.36-1.78,1.14-3.48,1.81-5.19c0.13-0.33,0.58-0.58,0.92-0.78c1.21-0.7,2.72-1.11,3.58-2.1c0.87-1,1.89-1.43,2.93-2.05 C215.346,112.2,216.377,111.28,216.086,109.69z M111.437,192.42c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31 c46.56,0,84.31,37.75,84.31,84.31C195.747,154.67,157.997,192.42,111.437,192.42z\",\n \"M220.041,157.85c-0.55-1.59-1.99-2.91-3.19-4.22c-1.44-1.55-3.06-2.93-4.54-4.44 c-0.94-0.97-2.09-1.91-2.57-3.1c-0.71-1.75-2.03-2.69-3.39-3.77c-0.82-0.65-1.45-1.6-2.05-2.48c-0.5-0.74-0.65-1.96-1.31-2.31 c-1.12-0.62-0.92-1.41-0.84-2.26c0.08-0.9-0.07-2.1,0.44-2.6c0.78-0.78,0.7-1.59,0.82-2.45c0.08-0.56-0.1-1.25,0.16-1.69 c1.35-2.35-0.12-5.35,1.81-7.52c0.27-4.36,0.77-8.72,0.74-13.07c-0.02-4.6-0.55-9.19-0.86-13.78c-0.02-0.23-0.04-0.6-0.18-0.67 c-1.2-0.58-0.74-1.69-0.88-2.62c-0.3-2.03-0.62-4.06-0.94-6.09c-0.03-0.17-0.16-0.32-0.24-0.49c-0.24-0.54-0.6-1.06-0.69-1.62 c-0.13-0.75,0.01-1.54-0.06-2.3c-0.14-1.56,0.39-3.22-0.79-4.65c-0.22-0.28-0.2-1.14,0.05-1.36c1.19-1.08,1.96-2.58,3.68-3.18 c0.9-0.32,1.87-1.42,2.11-2.35c0.36-1.38,0.09-2.92,0.09-4.59c-1.73,0-3.3,0.02-4.87,0c-0.36-0.01-0.98-0.02-1.05-0.2 c-0.46-1.09-1.43-0.72-2.21-0.93c-0.6-0.16-1.47-0.3-1.69-0.73c-0.65-1.26-1.95-1.91-2.51-3.35c-0.54-1.39-1.94-2.48-3.06-3.6 c-1.57-1.58-3.29-3.01-4.82-4.63c-0.9-0.96-1.45-2.23-2.3-3.24c-1.37-1.63-3.13-2.84-3.93-5.04c-0.75-2.04-0.93-2.28,0.91-3.34 c1.13-0.65,2.46-1.26,3.14-2.27c0.61-0.91,1.38-1.33,2.18-1.58c1.22-0.36,1.87-1.27,2.04-2.22c0.26-1.52,0.07-3.12,0.07-4.65 c-0.7-0.18-1.53-0.16-1.73-0.5c-0.54-0.93-1.34-0.88-2.1-0.8c-2.26,0.22-4.43-0.1-6.81,0.91c-2.5,1.06-5.7,0.06-8.58,0.97 c-1.39,0.44-3.04,0.01-4.63-0.49c-1.72-0.54-3.23-1.39-4.81-2.12c-0.53-0.24-0.86-0.92-1.39-1.21c-1.65-0.91-3.34-1.75-5.03-2.58 c-1.13-0.55-2.27-1.12-3.46-1.5c-1.3-0.42-2.67-0.64-4.01-0.96c-0.12-0.03-0.2-0.18-0.32-0.25c-0.49-0.28-0.96-0.69-1.5-0.81 c-1.58-0.38-3.18-0.64-4.78-0.96c-0.14-0.02-0.31-0.04-0.39-0.13c-1.28-1.53-3.33-0.93-4.88-1.77c-0.54-0.3-1.16-0.25-1.76-0.8 c-0.74-0.69-1.95-0.86-2.95-1.27c-0.31-0.13-0.57-0.36-0.88-0.52c-1.82-0.91-2.44-3.41-4.85-3.63c-0.37-0.03-0.84-0.97-0.93-1.54 c-0.16-0.97-0.04-2-0.04-2.77c-1.29-1.4-2.71-1.66-4.31-1.5c-1.04,0.1-3.26,1.89-3.77,2.79c-0.68,1.21-0.49,3.06-2.5,3.4 c-0.54,0.1-1.02,0.85-1.41,1.39c-0.58,0.82-1.24,1.27-2.3,1.24c-2.01-0.06-4.03-0.04-6.04,0.02c-0.52,0.02-1.03,0.31-1.53,0.51 c-0.4,0.16-0.75,0.5-1.15,0.55c-3.09,0.4-6.2,0.74-9.3,1.11c-0.14,0.02-0.31,0.01-0.41,0.1c-1.74,1.46-4.05,1.26-6.01,1.52 c-2.02,0.27-3.57,1.32-5.4,1.82c-1.27,0.35-2.45,1.02-3.69,1.51c-2.06,0.82-4.13,1.61-6.2,2.4c-0.64,0.24-1.35,0.37-1.91,0.73 c-1.46,0.94-2.83,2.01-4.28,2.97c-1.07,0.72-2.2,1.37-3.31,2.04c-0.98,0.59-1.98,1.14-2.94,1.76c-0.49,0.32-0.89,0.79-1.38,1.11 c-0.56,0.35-1.41,0.47-1.71,0.95c-0.49,0.79-1.09,1.06-1.92,1.26c-0.56,0.14-1.09,0.61-1.52,1.04c-0.91,0.91-1.7,1.92-2.6,2.84 c-1.47,1.52-3.01,2.96-4.47,4.49c-1.04,1.1-1.94,2.34-2.99,3.42c-1.05,1.07-2.23,2.02-3.34,3.03c-0.16,0.15-0.42,0.34-0.42,0.49 c0.1,1.74-2.06,1.97-2.29,3.47c-1.95,0.29-1.67,2.42-2.79,3.49c-1.16,1.11-1.61,2.94-2.39,4.45c-0.36,0.68-0.62,1.51-1.17,1.98 c-0.96,0.81-1.45,1.74-1.52,2.96c-0.02,0.38-0.02,0.81-0.2,1.11c-0.84,1.45-1.74,2.87-2.62,4.29c-0.4,0.63-1.03,1.22-1.16,1.9 c-0.25,1.29-0.94,1.6-2.14,1.73c-2.53,0.27-5.17-0.85-7.62,0.97c-0.78,0.57-1.29,0.9-1.28,1.82c0.02,1.15,0.04,2.3,0.09,3.45 c0.01,0.28,0.02,0.64,0.18,0.82c0.91,1.01,1.87,1.99,2.82,2.97c0.3,0.31,0.66,0.56,0.92,0.89c0.54,0.7,0.91,1.58,1.57,2.11 c1.32,1.05,1.76,2.7,0.91,4.16c-0.19,0.32-0.31,0.7-0.37,1.07c-0.33,2.36-0.19,4.68-0.93,7.12c-1.04,3.39-0.76,7.19-0.99,10.82 c-0.084,1.3-0.028,2.609-0.004,3.91c0.006,0.347,0.042,0.913,0.113,1.253c0.215,1.031,0.607,2.038,0.712,3.077 c0.13,1.18,0.02,2.39,0.08,3.59c0.02,0.39,0.24,0.77,0.39,1.15c0.19,0.5,0.5,0.97,0.6,1.49c0.36,1.88,0.66,3.78,0.98,5.67 c0.02,0.14,0.04,0.36,0.12,0.39c1.31,0.58,0.79,1.78,0.95,2.74c0.08,0.47-0.04,1.09,0.21,1.4c1.07,1.27,0.76,2.98,1.64,4.41 c0.92,1.49,0.83,3.53,1.95,5.15c1.07,1.53,1.11,3.52,2.09,5.23c1.14,2,1.76,4.33,3.12,6.29c0.99,1.43,1.86,2.94,2.81,4.39 c0.43,0.64,1.05,1.17,1.38,1.86c0.32,0.66,0.52,1.46,0.46,2.17c-0.02,0.21-1.11,0.37-1.72,0.47c-0.89,0.14-2.03-0.1-2.64,0.37 c-1.27,0.99-2.58,1.6-4.16,1.75c-0.27,0.02-0.66,0.12-0.78,0.31c-0.74,1.2-2.18,0.94-3.19,1.62c-0.9,0.6-1.97,0.95-2.95,1.45 c-0.13,0.06-0.15,0.33-0.22,0.5c-0.29,0.61-0.57,1.22-0.88,1.88c0.22,0.14,0.66,0.26,0.73,0.49c0.44,1.56,1.62,1.71,2.95,1.69 c6-0.1,12,0.28,17.98-0.6c2.02-0.3,2.35-0.04,2.27,1.87c-0.01,0.33,0.33,0.65,0.42,1c0.28,1.08,0.93,2.18-0.3,3.18 c-0.72,0.59-1.28,1.39-1.97,2.04c-0.57,0.55-1.16,1.13-1.84,1.51c-1.53,0.85-3.29,1.33-4.37,2.87c-0.11,0.16-0.38,0.21-0.57,0.32 c-1.53,0.89-3.3,1.54-4.54,2.74c-1.67,1.63-4.03,1.83-5.72,3.3c-0.62,0.53-1.4,0.9-2.1,1.34c-0.35,0.22-0.68,0.57-1.05,0.64 c-1.67,0.33-2.61,1.81-2.12,3.47c0.38,1.29,2.05,1.63,3.29,1.08c1.5-0.67,2.83-2,4.72-1.6c0.23,0.05,0.48-0.03,0.71,0.01 c3.29,0.59,6.38-0.81,9.6-0.9c0.14,0,0.37-0.02,0.4-0.09c0.59-1.47,1.9-0.82,2.92-1.07c1.08-0.27,2.31-0.48,3.12-1.14 c1.34-1.1,3.01-1.42,4.43-1.52c2.07-0.14,3.55-1.64,5.54-1.71c0.53-0.02,1.04-0.3,1.55-0.46c0.45-0.14,0.92-0.22,1.33-0.43 c0.95-0.49,1.87-1.48,2.8-1.47c2.17,0.03,4.33,0.51,6.5,0.83c0.1,0.02,0.16,0.24,0.27,0.29c0.56,0.28,1.11,0.61,1.7,0.78 c1.28,0.37,2.98,0.25,3.8,1.06c1.41,1.37,3.24,0.88,4.73,1.73c0.92,0.53,2.42-0.25,3.25,1.05c0.11,0.17,0.55,0.21,0.82,0.18 c3.28-0.45,5.4,2.03,8.05,3.18c1.02,0.44,1.9,1.2,2.94,1.6c2.28,0.87,4.77,0.75,7.12,1.85c2.1,0.99,4.76,1.09,7.16,1.03 c6.72-0.19,13.49,0.95,20.17-0.71c1.13-0.28,2.39-0.08,3.58-0.17c0.39-0.02,0.78-0.21,1.15-0.37c0.47-0.21,0.91-0.6,1.39-0.67 c1.14-0.15,2.49,0.21,3.39-0.3c1.52-0.84,2.91-0.42,4.47-0.47c0.03,0.81,0.09,1.47,0.09,2.13v170.39c0,1.92,0.01,3.84-0.01,5.76 c0,0.42,0.03,1.13-0.17,1.22c-1.48,0.66-0.88,1.94-0.93,2.97c-0.1,1.67-0.15,3.36-0.02,5.03c0.14,1.95-0.76,4.1,1,5.79 c0.14,0.13,0.07,0.46,0.13,0.69c0.32,1.16,0.64,2.31,1,3.45c0.05,0.18,0.32,0.33,0.52,0.42c1.35,0.57,1.68,1.45,1.02,2.81 c-0.14,0.29-0.42,0.71-0.31,0.88c1.11,1.81,0.69,3.83,0.63,5.73c-0.1,2.98-0.59,5.94-0.76,8.93c-0.14,2.43-0.03,4.89-0.08,7.33 c-0.01,0.6,0.23,1.41-0.8,1.57c-0.12,0.02-0.28,0.37-0.29,0.57c-0.16,3.08-0.36,6.15-0.72,9.24c-0.59,4.97-0.21,10.05-0.21,15.09 c0,44.18,0.01,88.36,0,132.54c0,6.23-0.02,12.47-0.12,18.7c-0.03,1.37,0.13,2.67-0.79,4.12c-0.92,1.43-0.93,3.56-1.02,5.39 c-0.16,3.11-0.07,6.24-0.11,9.36c-0.01,0.51-0.02,1.4-0.24,1.47c-1.21,0.4-0.8,1.35-0.89,2.13c-0.08,0.62-0.03,1.28-0.26,1.84 c-1.03,2.54-0.86,5.31-0.25,7.71c0.44,1.74,0.41,3.39,0.61,5.08c0.09,0.71-0.17,1.75,0.22,2.08c1.12,0.97,0.85,2.16,0.86,3.3 c0.05,10.08,0.08,20.15,0.07,30.22c0,1.21,0.33,2.59-1.03,3.45c-0.18,0.11-0.18,0.53-0.24,0.8c-0.3,1.45-0.59,2.91-0.92,4.36 c-0.04,0.18-0.32,0.29-0.45,0.47c-0.23,0.34-0.53,0.68-0.61,1.06c-0.36,1.69-0.64,3.38-0.96,5.08c-0.02,0.13-0.03,0.36-0.11,0.39 c-1.37,0.57-0.82,1.77-0.87,2.73c-0.07,1.48,0.09,2.98-0.06,4.45c-0.07,0.64-0.56,1.58-1.07,1.74c-1.53,0.48-3.39-0.22-4.66,1.28 c-6.11,0.05-12.2-0.04-18.29,0.83c-3.57,0.51-7.27,0.09-10.91,0.11c-0.52,0-1.34-0.08-1.52,0.2c-0.88,1.4-2.2,0.79-3.34,0.85 c-1.68,0.09-3.36,0.01-5.03,0.03c-2.22,0.03-2.87,0.61-2.88,2.52c-0.01,1.74,1.56,3.66,3.06,3.67c2.44,0.02,4.89-0.03,7.33,0.03 c0.54,0.01,1.1,0.29,1.59,0.56c0.66,0.35,1.23,1.13,1.88,1.17c2.77,0.19,5.5,0.3,8.27,0.8c3.4,0.62,6.97,0.26,10.46,0.39 c1.31,0.04,2.77-0.51,3.81,0.86c0.13,0.16,0.55,0.11,0.83,0.16c1.98,0.31,3.97,0.57,5.93,0.94c1.09,0.21,2.13,0.61,3.19,0.93 c0.13,0.04,0.23,0.15,0.35,0.21c0.62,0.31,1.25,0.59,1.87,0.9c0.71,0.37,1.79,0.59,2.05,1.17c0.56,1.23,0.85,2.64,0.96,4.01 c0.19,2.53,0.15,5.07,0.25,7.61c0.01,0.38,0.22,0.77,0.39,1.12c0.21,0.43,0.67,0.83,0.68,1.24c0.06,2.54,0.03,5.08,0.03,8.02 c-1.66,0.18-3.24,0.45-4.82,0.5c-2.92,0.07-5.85,0-8.77,0.03c-0.79,0-1.59,0.13-2.49,0.22c0.04,1.62-0.73,3.04,0.83,4.49 c1.37,1.26,2.42,2.7,4.52,2.55c0.429-0.031,0.861,0.057,1.262,0.211c2.119,0.81,4.149,1.889,6.518,1.859 c2.647-0.022,3.007,0.673,2.932,3.776c-0.017,0.708,0.025,1.415,0.061,2.122c0.065,1.295-0.44,1.831-1.823,1.812 c-3.69-0.07-7.38-0.03-11.07,0c-0.56,0.01-1.42-0.02-1.62,0.29c-0.74,1.16-1.8,0.84-2.78,0.84c-2.78,0.02-5.56,0.01-8.34,0.01 c-2.64,0-5.27,0.06-7.9-0.01c-1.15-0.03-2.08,0.55-2.33,1.39c-0.7,2.4,0.27,5.56,3.59,5.63c1.2,0.02,2.77-0.38,3.51,0.22 c1.4,1.15,2.84,0.75,4.28,0.95c1.97,0.27,3.93,0.57,5.9,0.89c0.17,0.03,0.3,0.3,0.46,0.45c0.91,0.82,1.76,1.71,3.21,1.47 c0.49-0.09,1.07,0.16,1.57,0.35c0.51,0.19,0.95,0.66,1.45,0.73c3.2,0.43,6.4,0.78,9.69,1.16c0.04,0.17,0.13,0.39,0.14,0.62 c0.03,1.82,0.03,3.65,0.06,5.47c0.01,0.76-0.1,1.57,0.11,2.28c0.5,1.64,0.12,2.28-1.61,2.28c-4.12,0-8.24-0.01-12.36,0.02 c-0.7,0.01-1.77,0-2.02,0.4c-0.59,0.96-1.36,0.7-2.11,0.73c-1.81,0.07-3.64,0.04-5.44,0.19c-1.13,0.1-2.23,0.64-3.35,0.64 c-8.67,0.06-17.35,0.03-26.02,0.05c-0.66,0-1.71-0.04-1.89,0.3c-0.55,1.03-1.38,0.79-2.18,0.88c-1.31,0.17-2.07,1-2.12,2.29 c-0.1,2.71,1.38,4.42,4.05,4.64c0.66,0.06,1.34,0.06,2.01,0.06c11.59,0,23.19-0.04,34.79,0.04c2.11,0.01,4.23,0.53,6.34,0.84 c0.16,0.02,0.3,0.17,0.46,0.26c0.46,0.24,0.9,0.61,1.38,0.7c2.05,0.38,4.12,0.68,6.18,1.02c0.17,0.02,0.32,0.14,0.49,0.22 c0.59,0.27,1.16,0.71,1.77,0.77c1.78,0.18,2.26,0.55,2.18,2.39c-0.13,2.89,0.3,5.79-0.56,8.69c-0.54,1.82,0.44,4.02-1.28,5.61 c-1.07,0.99-1.03,2.72-2.45,3.52c-0.6,0.33-1.11,0.94-1.49,1.53c-0.84,1.31-1.52,2.72-2.37,4.02c-0.39,0.59-1.08,0.97-1.53,1.53 c-0.82,1.05-1.77,2.07-2.29,3.27c-0.73,1.7,0.72,3.6,2.56,3.61c1.2,0,2.39-0.07,3.59-0.14c0.28-0.01,0.76-0.06,0.79-0.18 c0.37-1.48,1.9-1.22,2.79-1.6c1.47-0.63,2.91-1.2,4.18-2.2c0.6-0.47,1.56-0.65,1.91-1.24c0.65-1.1,0.98-2.39,1.44-3.6 c0.17-0.43,0.37-0.84,0.5-1.28c0.4-1.41,0.82-2.81,1.14-4.24c0.15-0.69,0.22-1.46,0.08-2.14c-0.28-1.36,0.93-1.72,1.44-2.55 c0.84-1.38,1.53-1.33,2.36-0.08c0.04,0.06,0.18,0.09,0.27,0.09h5.12c-0.27-2.27,0.54-4.2-0.94-6.39c-1.18-1.72-2.35-3.95-2.25-6.37 c0.02-0.28-0.07-0.57-0.13-0.85c-0.31-1.36-0.62-2.72-0.98-4.33c4.5,0,8.43-0.01,12.35,0.02c0.27,0,0.59,0.24,0.78,0.46 c0.82,0.96,1.75,1.44,3.09,1.4c2.73-0.08,5.46,0.06,8.19,0.06c14.24,0.01,28.47,0,42.7,0c0.67,0,1.35,0.02,2.01-0.07 c0.32-0.05,0.75-0.28,0.88-0.55c0.69-1.38,1.24-2.78,1.07-4.42c-0.22-2-0.91-2.79-2.91-2.81c-2.59-0.03-5.17,0-7.76-0.03 c-0.4,0-0.82-0.09-1.21-0.22c-0.79-0.28-1.56-0.86-2.35-0.87c-4.08-0.1-8.15-0.05-12.22-0.06c-0.39,0-0.91,0.14-1.13-0.05 c-1.49-1.3-3.27-0.63-4.92-0.82c-1.42-0.16-3.03,0.59-4.17-0.93c-0.17-0.22-0.72-0.18-1.1-0.18c-1.29-0.03-2.58-0.02-3.86-0.03 c-0.63,0-1.49,0.23-1.83-0.09c-1.49-1.41-3.58-0.43-5.29-1.62c-1.47-1.03-3.79-0.13-5.71-1.05c-1.26-0.6-2.87,0.1-4.29-1.07 c-1.64-1.35-3.9-1.12-5.98-1.07c-1.17,0.02-1.96-0.78-2.01-1.96c-0.02-0.61,0-1.22,0-1.93c0.7-0.04,1.27-0.05,1.83-0.12 c0.31-0.04,0.62-0.16,0.9-0.3c0.48-0.24,0.93-0.73,1.42-0.78c3.66-0.32,7.33-0.56,10.99-0.82c0.05-0.01,0.1-0.01,0.15-0.01 c1.17-0.12,2.41-1.19,2.51-2.35c0.1-1.23,0.02-2.47,0.02-3.7c-1.73-0.36-3.3-0.9-4.9-0.98c-3.01-0.13-6.03,0-9.05,0.03 c-0.43,0-0.99-0.06-1.25,0.17c-1.07,0.95-2.32,0.59-3.51,0.66c-1.57,0.08-2.62-0.97-2.97-2.16c-0.34-1.18-0.19-2.67,0.24-3.85 c0.41-1.13,3.21-1.2,4.42-0.44c0.97,0.61,2.01,1.16,3.09,1.52c0.79,0.26,1.7,0.21,2.56,0.22c2.42,0.05,3.28-0.79,3.32-3.21 c0.02-1.15,0.11-2.31-0.02-3.45c-0.11-0.94-0.49-1.85-0.77-2.77c-0.35-1.1-0.72-2.18-1.14-3.45c0.69-0.05,0.96-0.09,1.24-0.09 c4.31-0.08,8.62-0.14,12.93-0.23c0.51-0.01,1.03-0.12,1.52-0.26c0.68-0.19,1.33-0.66,1.99-0.67c6.85-0.05,13.71-0.02,20.56-0.04 c0.71,0,1.61,0.13,2.1-0.23c1.18-0.87,2.44-0.56,3.67-0.62c1.29-0.05,2.6,0.05,3.87-0.13c0.76-0.11,1.42-0.83,2.18-0.93 c2.31-0.3,4.64,0.04,6.98-0.78c1.36-0.48,1.89-0.92,1.89-2.21c-0.01-1.05,0-2.09,0-3.07c-1.98-0.4-3.74-0.82-5.52-1.07 c-1.03-0.15-2.1-0.02-3.15-0.04c-0.33,0-0.87,0.04-0.95-0.13c-0.68-1.28-1.88-0.93-2.9-0.94c-4.36-0.05-8.72-0.02-13.08-0.03 c-0.42,0-0.84-0.06-1.25-0.16c-0.85-0.21-1.69-0.65-2.53-0.66c-3.74-0.08-7.48-0.04-11.22-0.07c-0.39,0-0.81-0.11-1.19-0.25 c-0.65-0.26-1.27-0.76-1.93-0.82c-1.661-0.151-3.335-0.019-5.007-0.073c-0.629-0.021-1.638-0.204-2.243-0.375 c-0.66-0.186-1.321-0.376-1.99-0.432c-1.57-0.13-3.16-0.02-4.74-0.05c-0.36,0-0.73-0.1-1.06-0.22c-0.75-0.28-1.46-0.83-2.21-0.87 c-2.29-0.12-4.62,0.13-6.89-0.13c-1-0.11-2.34-0.9-2.73-1.74c-0.4-0.87-0.13-2.37,0.4-3.27c0.641-1.095,1.837-1.878,2.791-2.802 c0.176-0.17,0.314-0.377,0.406-0.604c0.418-1.034,0.692-2.09,1.883-2.644c0.49-0.22,0.73-0.96,1.09-1.46 c0.58-0.8,1.01-1.83,1.79-2.34c1.34-0.86,2.7-1.8,4.39-2.05c0.94-0.14,2.19-0.41,2.65-1.07c0.83-1.21,2.16-0.98,3.16-1.63 c1.45-0.94,3.1-1.57,4.65-2.39c0.2-0.1,0.36-0.48,0.37-0.73c0.03-1.66,0.02-3.32,0.02-5.1c-1.93,0-3.73-0.2-5.46,0.05 c-1.77,0.26-3.54,0.82-5.19,1.53c-0.95,0.41-1.55,0.46-2.52,0.01c-1.67-0.76-3.21-2.09-5.31-1.62c-0.77,0.17-1.62,0.05-2.43,0.02 c-1.31-0.03-2.01-0.77-2.04-2.07c-0.03-1.1,0.24-2.39-0.24-3.26c-0.82-1.47-0.5-2.93-0.57-4.4c-0.07-1.35,0.57-1.94,1.93-1.96 c1.81-0.04,3.65,0.03,5.45-0.16c1.45-0.15,2.85-0.78,4.3-0.91c2.1-0.2,4.21-0.09,6.32-0.19c5.64-0.27,11.27-0.58,16.91-0.89 c0.29-0.01,0.59-0.18,0.87-0.31c0.46-0.22,0.9-0.66,1.36-0.68c2.87-0.12,5.74-0.18,8.61-0.21c1.86-0.01,3.49-0.46,4.72-1.98 c0.73-0.91,0.33-3.4-0.5-3.95c-1.54-1.02-3.21-0.87-4.89-0.91c-0.4-0.01-0.81-0.11-1.19-0.25c-0.76-0.27-1.48-0.83-2.23-0.85 c-3.214-0.102-6.428-0.038-9.642-0.061c-0.354-0.003-0.711-0.029-1.053-0.122c-0.859-0.234-1.683-0.63-2.544-0.697 c-1.48-0.12-2.97-0.01-4.46-0.04c-0.35,0-0.72-0.1-1.05-0.23c-0.7-0.28-1.36-0.79-2.07-0.87c-1.37-0.14-2.78,0.05-4.16-0.06 c-4.36-0.36-8.78,0.74-13.14-0.72c-1.01-0.34-1.88-0.84-2.7-1.35c-0.51-0.31-0.85-1.41-0.73-2.06c0.1-0.55,0.9-1.24,1.51-1.38 c1.69-0.39,3.52,0.23,5.11-1.2c0.68-0.6,1.73-0.79,2.03-1.87c0.46-1.59,0.03-3.2-1.02-4.15c-1.15-1.05-2.8-1.57-4.3-2.17 c-0.95-0.37-1.49-0.84-1.48-1.89c0.03-1.58,0.02-3.17-0.01-4.75c-0.01-0.57,0.08-1.42-0.24-1.65c-1.34-0.97-1.03-2.35-1.03-3.6 c-0.03-12.57-0.2-25.14,0.09-37.7c0.09-4.05-0.94-8.2,0.93-12.27c0.93-2.02,0.71-4.58,1.03-6.89c0.16-1.24-0.47-2.69,1-3.6 c0.14-0.09,0.09-0.54,0.09-0.83c0-4.12,0.01-8.25-0.02-12.37c0-0.41-0.16-0.82-0.29-1.22c-0.19-0.59-0.54-1.16-0.6-1.77 c-0.36-3.45-0.65-6.9-0.98-10.35c-0.03-0.31-0.24-0.6-0.38-0.89c-0.22-0.51-0.58-1-0.66-1.53c-0.24-1.69,0.47-3.51-0.81-5.07 c-0.19-0.23-0.19-0.89,0-1.1c1.13-1.21,0.66-2.69,0.81-4.07c0.03-0.33-0.01-0.85,0.17-0.94c1.18-0.61,0.78-1.71,0.9-2.64 c0.31-2.41,0.6-4.82,0.92-7.23c0.02-0.17,0.16-0.32,0.24-0.48c0.28-0.64,0.56-1.28,0.85-1.91c0.32-0.7,0.59-1.93,1-1.98 c1.63-0.19,2.43-1.42,3.43-2.35c1.11-1.02,1.99-2.29,3.34-3.88c1.88-0.27,4.43-0.62,6.97-0.99c0.244-0.035,0.634-0.127,0.864-0.214 c1.441-0.546,2.865-1.399,4.326-1.486c2.42-0.16,3.88-1.4,5.1-3.21c0.42-0.63,0.74-1.32,1.14-1.95c0.73-1.13,0.46-2.45-0.7-3.13 c-1.06-0.64-2.14-1.26-3.22-1.86c-0.79-0.43-1.66-0.72-2.39-1.23c-1.235-0.87-2.388-1.874-3.593-2.814 c-0.497-0.388-1.371-0.934-1.933-1.221c-0.971-0.497-1.952-0.974-2.934-1.465c-1-0.5-2.02-0.97-3.01-1.5 c-1.6-0.84-3.21-1.67-4.75-2.6c-0.37-0.23-0.71-0.84-0.72-1.29c-0.12-4.45-0.14-8.91-0.24-13.37c-0.01-0.63-0.24-1.27-0.47-1.87 c-0.4-1.04-1.01-2.01-1.27-3.07c-0.41-1.62-0.52-3.32-0.9-4.95c-0.19-0.8-1.03-1.52-1.04-2.28c-0.03-2.59-1.5-4.95-1.05-7.62 c0.23-1.35,0.07-2.78,0.01-4.17c-0.02-0.49-0.22-0.99-0.41-1.46c-0.18-0.47-0.63-0.91-0.64-1.37c-0.1-5.89-0.19-11.79-0.2-17.69 c-0.01-43.36-0.01-86.72,0.01-130.09c0-3.59,0.1-7.19,0.18-10.78c0-0.35,0.13-0.72,0.28-1.04c0.23-0.52,0.69-0.98,0.75-1.51 c0.14-1.13-0.01-2.31,0.15-3.44c0.21-1.41,0.24-3.06,1.01-4.12c1.23-1.69,0.93-3.66,1.6-5.44c0.86-2.26-0.54-4.93,1.14-7.29 c1.15-1.62,1.74-3.65,2.56-5.5c0.27-0.59,0.41-1.24,0.72-1.81c0.54-1.02,1.19-1.98,1.75-2.99c0.58-1.04,1.14-2.09,1.63-3.17 c0.67-1.52,2.22-1.88,3.43-2.66c0.92-0.59,2.03-0.89,3.04-1.36c1.51-0.69,3.02-1.38,4.5-2.12c0.5-0.26,1.18-0.59,1.33-1.04 c0.46-1.4,0.79-2.85,1.02-4.31c0.13-0.82-0.4-1.39-1.27-1.39c-3.26,0-6.51,0.03-9.77,0.06c-0.24,0-0.51,0-0.7,0.11 c-2.29,1.29-4.7,0.26-7.06,0.66c-0.05-0.53-0.1-0.81-0.1-1.1c0-8.53,0.13-17.08-0.04-25.61c-0.18-8.49,0.86-17.02-0.84-25.46 c-0.17-0.87-0.26-1.75-0.48-2.61c-0.13-0.53-0.56-0.99-0.63-1.51c-0.16-1.28,0.11-2.69-0.33-3.83c-0.93-2.37-0.35-3.87,2.08-4.61 c1.47-0.44,2.09-2.42,3.94-2.27c0.03,0,0.06-0.17,0.13-0.23c0.85-0.86,1.58-2.12,2.61-2.47c1.65-0.55,2.44-1.96,3.72-2.84 c0.98-0.67,1.86-1.5,2.82-2.2c0.62-0.46,1.31-0.81,1.96-1.23c0.66-0.42,1.31-0.86,1.95-1.31c0.27-0.2,0.49-0.46,0.76-0.67 c0.8-0.63,1.65-1.2,2.4-1.88c1.08-0.97,2.05-2.05,3.13-3.03c1.21-1.1,2.77-1.94,3.64-3.25c1.25-1.87,2.53-3.64,4.13-5.24 c1.47-1.47,2.88-3.08,3.97-4.84c0.72-1.18,2.37-1.65,2.4-3.29c0-0.06,0.14-0.14,0.22-0.16c1.32-0.35,2.61-0.84,3.95-1 c1.36-0.16,2.93-0.39,3.93,0.85c1.2,1.51,2.76,0.97,4.22,1.05c0.96,0.06,1.93,0.15,2.88,0.04c2.29-0.27,4.18,0.69,6.06,1.78 c0.68,0.4,1.4,0.75,2.09,1.13c0.92,0.51,1.83,1.03,2.85,1.6c0-0.01,0.07-0.17,0.19-0.27c0.97-0.86,2.45-1.54,2.79-2.6 C220.411,161.37,220.561,159.38,220.041,157.85z M111.437,192.42c-43.96,0-80.06-33.63-83.96-76.57c-0.27-0.72-0.3-1.53-0.18-2.4 c-0.12-1.77-0.18-3.55-0.18-5.35c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z\",\n \"M230.071,128.64c-0.15-1.08-0.7-2.04-2.08-2.04c-0.28,0-0.57-0.25-0.84-0.39 c-0.47-0.25-0.92-0.61-1.42-0.73c-1.45-0.36-2.93-0.61-4.39-0.92c-0.12-0.03-0.22-0.18-0.34-0.23c-0.69-0.31-1.37-0.67-2.09-0.89 c-0.5-0.15-1.09,0.01-1.58-0.15c-1.59-0.49-3.12-1.21-4.73-1.56c-0.84-0.18-1.56-0.25-1.9-1.1c-0.26-0.64-0.44-1.3-0.58-1.71 c-0.72-0.61-1.66-1-1.81-1.59c-0.47-1.97-0.84-4-0.92-6.01c-0.17-4.38-0.13-8.76-0.19-13.14c0-0.39,0.08-0.98-0.12-1.13 c-1.52-1.11-0.88-2.72-1.05-4.13c-0.09-0.72-0.04-1.47-0.24-2.16c-0.52-1.81-1.24-3.58-1.68-5.41c-0.47-1.99-0.71-4.03-1.05-6.05 c-0.02-0.15-0.03-0.35-0.12-0.41c-1.51-0.98-1.28-2.82-1.53-4.12c-0.44-2.32-1.97-4.02-2.61-6.16c-0.4-1.34-1.17-2.57-1.71-3.87 c-0.68-1.62-1.18-3.32-1.99-4.86c-0.81-1.54-2.08-2.85-2.84-4.42c-0.66-1.35-0.85-2.94-2.05-4.04c-0.1-0.09-0.05-0.51,0.07-0.66 c0.56-0.66,1.05-1.5,1.78-1.88c1.3-0.68,1.3-1.76,1.31-2.91c0.01-1.17-0.04-2.34,0.01-3.51c0.07-1.48-0.62-2.06-2.07-2.04 c-3.26,0.04-6.52,0.06-9.78-0.01c-0.7-0.02-1.46-0.33-2.05-0.72c-1.1-0.72-2.12-1.56-3.13-2.4c-0.54-0.45-0.96-1.03-1.48-1.5 c-0.43-0.39-0.99-0.65-1.4-1.06c-1.1-1.08-2.85-1.27-3.64-2.8c-0.26-0.51-0.8-0.93-1.31-1.26c-1.904-1.241-3.992-2.242-5.711-3.712 c-0.881-0.754-1.89-1.335-2.86-1.97c-0.607-0.397-1.054-1.111-1.699-1.348c-2.2-0.8-3.28-2.91-5.09-4.15 c-1.33-0.92-1.84-2.72-3.74-3.11c-0.83-0.18-1.88-1.09-2.14-1.89c-0.88-2.71-2.14-5.37-1.84-8.36c0.05-0.48,0.01-0.96,0.01-1.34 c-1.25-1.09-2.38-0.97-3.36,0.1c-0.89,0.97-1.57,2.15-2.54,3.02c-1.43,1.29-2.97,2.51-4.61,3.52c-0.69,0.42-1.38,0.67-2.02,1.31 c-0.9,0.89-2.2,1.64-3.43,1.85c-1.8,0.3-3.69,0.07-5.53,0.05c-0.18,0-0.48-0.07-0.53-0.18c-0.47-1.14-1.47-0.93-2.36-0.94 c-6.56-0.01-13.14-0.04-19.7,0.04c-1.54,0.02-3.04-0.25-4.58,0.97c-1.14,0.9-3.14,0.73-4.76,1.02c-2.09,0.36-4.19,0.69-6.29,1.07 c-0.19,0.03-0.33,0.28-0.53,0.39c-0.37,0.22-0.74,0.54-1.14,0.59c-2.19,0.29-4.26,0.71-6.23,1.94c-1.53,0.96-3.44,1.68-5.22,1.77 c-1.75,0.09-2.67,1.41-4.14,1.82c-1.55,0.42-2.99,0.65-4.48-0.1c-0.81-0.405-1.626-0.816-2.452-1.201 c-0.68-0.317-1.835-0.735-2.558-0.934c-1.54-0.425-3.106-0.796-4.66-1.225c-0.36-0.1-0.75-0.28-1-0.54 c-1.13-1.22-3.97-1.95-5.53-1.35c-0.17,0.06-0.44,0.21-0.43,0.31c0.02,1.69-0.44,3.69,0.31,4.96c0.62,1.05,0.67,1.93,0.85,2.94 c0.3,1.71,0.65,3.4,0.99,5.1c0.03,0.13,0.11,0.31,0.22,0.36c1.21,0.52,0.68,1.35,0.48,2.21c-2.65,0-5.23,0-7.8-0.01 c-0.24,0-0.59,0.01-0.69-0.13c-1.25-1.66-3.02-0.97-4.53-0.83c-0.67,0.07-1.56,1.09-1.79,1.86c-0.3,0.97-0.07,2.11,0.02,3.18 c0.03,0.3,0.32,0.68,0.6,0.85c0.79,0.49,1.63,0.88,2.41,1.29c0,1.61-0.25,3.18,0.06,4.61c0.44,1.98-0.79,3.3-1.41,4.84 c-0.37,0.91-1.12,1.68-1.74,2.48c-0.65,0.86-1.47,1.62-1.97,2.56c-1.056,1.961-2.123,3.875-3.665,5.518 c-0.045,0.048-0.085,0.103-0.115,0.162c-0.62,1.2-1.26,2.38-1.81,3.61c-0.52,1.15-0.65,2.41-1.51,3.5c-0.8,1-1.09,2.41-1.63,3.63 c-0.4,0.91-0.89,1.79-1.23,2.73c-0.65,1.77-0.53,3.74-1.91,5.36c-0.96,1.12-1.31,2.75-2.03,4.1c-0.74,1.37-1.69,2.45-3.49,2.5 c-1.86,0.04-3.37,1.92-3.6,3.77c-0.44,3.62,2.49,5.16,4.33,7.38c0.29,0.36,0.73,0.77,0.74,1.17c0.06,1.95,0,3.9-0.04,5.84 c0,0.27-0.16,0.53-0.27,0.79c-0.22,0.58-0.62,1.14-0.66,1.73c-0.1,1.31-0.05,2.63-0.02,3.94c0,0.38,0.07,0.77,0.19,1.13 c0.27,0.77,0.78,1.51,0.84,2.29c0.15,1.79,0.08,3.6,0.11,5.4c0.01,0.78-0.28,1.79,0.1,2.29c1.42,1.91,0.12,4.44,1.72,6.36 c0.72,0.86,0.64,2.41,0.9,3.65c0.5,2.35,1.18,4.66,1.83,6.96c0.68,2.41,2.51,4.36,2.52,7.02c0,0.81,0.91,1.59,1.32,2.43 c0.52,1.07,0.95,2.19,1.43,3.28c0.11,0.24,0.28,0.45,0.41,0.68c0.56,1,1.12,1.99,1.67,2.99c0.32,0.59,0.48,1.5,0.98,1.75 c1.39,0.69,1.07,2.22,1.83,3.18c0.47,0.6,0.82,1.29,1.25,1.92c0.26,0.37,0.56,0.71,0.83,1.08c0.52,0.72,1.09,1.41,1.54,2.17 c0.52,0.89,1.47,2.02,1.24,2.71c-0.31,0.91-1.5,1.63-2.46,2.18c-1.59,0.9-3.29,1.6-4.94,2.38c-0.45,0.21-0.9,0.41-1.35,0.63 c-0.95,0.47-1.92,0.92-2.85,1.45c-0.71,0.42-1.35,0.98-2.05,1.42c-0.99,0.63-2.06,1.14-3,1.82c-0.81,0.58-1.46,1.39-2.27,1.98 c-0.53,0.4-1.41,0.43-1.81,0.9c-0.87,1.04-1.78,2-2.43,3.31c-0.93,1.85-0.62,3.28,0.36,4.67c0.71,1,1.81,1.7,3.22,1.44 c2.79-0.51,5.68,0.59,8.47-0.8c1.08-0.54,2.59-0.18,3.9-0.27c0.42-0.02,1.09-0.02,1.21-0.26c0.52-1.03,1.44-0.76,2.26-0.9 c1.76-0.28,3.52-0.6,5.28-0.92c0.13-0.02,0.33-0.1,0.37-0.21c0.43-1.07,1.39-0.83,2.22-0.9c0.63-0.06,1.27-0.03,1.88-0.15 c2.21-0.43,4.39-1,6.61-1.36c1.77-0.29,3.57-0.02,5.09,0.93c1.33,0.83,2.43,2.06,4.19,1.92c0.07,0,0.14,0.24,0.25,0.32 c0.96,0.71,1.94,1.41,3.11,2.26c-0.03,0.78,0.72,2.01-0.9,2.62c-0.11,0.05-0.12,0.35-0.21,0.52c-0.68,1.31-1.35,2.63-2.06,3.93 c-0.41,0.75-0.86,1.47-1.32,2.17c-0.52,0.79-1.16,1.5-1.6,2.33c-0.46,0.86-0.7,1.84-1.11,2.73c-0.56,1.22-1.46,2.35-1.74,3.63 c-0.31,1.34-0.12,2.81-0.03,4.22c0.08,1.17,0.87,1.95,2,2.03c1.38,0.09,2.83,0.58,4.1-0.64c0.75-0.73,1.82-1.11,2.66-1.76 c0.66-0.5,1.45-1.08,1.73-1.8c0.87-2.3,2.93-3.51,4.48-5.18c0.47-0.51,1.29-0.68,1.83-1.15c1.39-1.22,2.56-2.77,4.1-3.71 c1.46-0.88,3.26-1.31,4.97-1.65c1.24-0.24,2.38,0.18,3.64,0.89c2.31,1.31,5.28,0.57,7.75,2.06c1.12,0.68,2.84,0.67,4.2,0.82 c2.23,0.25,4.29,0.73,6.53,1.79c-0.24,0.43-0.46,0.94-0.77,1.4c-0.4,0.57-0.99,1.05-1.28,1.67c-0.79,1.67-1.35,3.39-1.07,5.31 c0.19,1.25,2.23,3.39,3.42,3.12c1.23-0.27,2.54-0.81,3.48-1.62c1.48-1.28,2.63-2.93,4.01-4.33c1.1-1.12,2.36-2.08,3.53-3.12 c0.71-0.64,1.3-1.64,2.12-1.89c1.76-0.52,3.64-0.61,5.45-0.97c1.79-0.35,3.55,0.17,5.46-0.91c1.89-1.06,4.51-0.98,6.82-1.09 c2.82-0.13,2.63-0.62,2.63,2.59c0,57.42,0.02,114.83-0.06,172.25c0,4.23,0.83,8.54-0.79,12.73c-0.62,1.6-0.25,3.38-1,5.17 c-0.81,1.94-0.89,4.43-1.01,6.62c-0.34,6.56-0.12,13.14-0.11,19.72c0,0.48-0.12,1.18,0.15,1.41c1.43,1.27-0.05,3.62,1.8,4.67 c0.34,3.04,0.98,6.08,0.99,9.12c0.06,52.79,0.04,105.58,0.04,158.37c0,3.16,0,6.33-0.03,9.49c0,0.57-0.12,1.14-0.26,1.69 c-0.19,0.72-0.64,1.41-0.66,2.11c-0.11,3.56-0.11,7.11-0.16,10.67c-0.01,0.42-0.1,0.85-0.21,1.27c-0.2,0.8-0.52,1.58-0.66,2.4 c-0.17,0.95-0.16,1.93-0.31,2.89c-0.16,1.01-0.64,2.01-0.6,2.99c0.16,3.93,0.47,7.84,0.73,11.76c0.01,0.09,0.01,0.19,0.03,0.29 c0.02,0.09,0.03,0.25,0.09,0.26c1.53,0.52,1.01,1.83,1.01,2.84c0.04,8.82,0.12,17.63-0.03,26.45c-0.05,2.65,0.87,5.42-0.97,8.02 c-0.8,1.12-0.72,2.87-1.05,4.32c-0.05,0.23-0.17,0.43-0.26,0.64c-0.55,1.3-1.35,2.55-1.59,3.9c-0.47,2.59-1.33,5.12-1.07,7.86 c0.22,2.37-0.05,4.78,0.08,7.16c0.1,1.83,0.58,3.64,0.72,5.47c0.11,1.56-0.68,2.28-2.23,2.29c-2.87,0.02-5.74-0.01-8.61,0.03 c-0.6,0.01-1.54,0.04-1.74,0.4c-0.54,0.93-1.29,0.71-2.03,0.74c-1.89,0.09-3.92-0.26-5.63,0.33c-1.64,0.56-3.18,0.44-4.77,0.55 c-0.77,0.05-1.56,0-2.33,0.04c-0.39,0.03-0.99,0.03-1.1,0.25c-0.72,1.33-1.93,0.77-2.95,0.89c-0.68,0.07-1.56-0.12-1.99,0.24 c-1.51,1.3-3.91-0.13-5.14,1.79c-2.12-0.02-4.15,0.22-6.23,0.82c-1.96,0.56-2.12,0.32-2.18,2.44c-0.01,0.34-0.01,0.69,0,1.03 c0.06,1.68,2.24,2.98,3.84,2.46c2.01-0.65,4.08-1.5,6.15-1.56c7.1-0.21,14.21-0.12,21.31-0.12c0.47-0.01,0.99,0.07,1.4,0.28 c1.67,0.85,3.32,1.62,5.27,1.47c0.64-0.05,1.32,0.15,1.95,0.35c0.64,0.19,1.22,0.71,1.84,0.75c3.19,0.16,3.22,0.16,3.33,3.45 c0.02,0.47,0.05,1.22,0.31,1.34c2.07,0.98,1.89,2.8,1.64,4.51c-0.1,0.64-0.81,1.33-1.41,1.69c-0.29,0.17-1-0.36-1.53-0.56 c-0.43-0.16-0.87-0.4-1.32-0.42c-1.21-0.07-2.43-0.01-3.65-0.06c-0.4-0.01-0.97-0.03-1.18-0.29c-1.01-1.21-2.46-2.07-2.96-3.72 c-0.12-0.39-0.73-0.77-1.18-0.88c-0.64-0.15-1.36,0-2.03-0.08c-3.01-0.39-4.31,2.14-4.4,4.43c-0.18,4.77-0.13,9.54-0.14,14.31 c-0.01,2.82,2.03,4.69,4.86,4.52c0.33-0.03,0.71,0,1-0.14c0.39-0.2,0.79-0.49,1.05-0.84c0.57-0.81,0.87-2.08,1.62-2.43 c1.73-0.79,3.65-1.22,5.52-1.65c1.12-0.26,2.33-0.11,3.44-0.37c0.5-0.12,0.83-1.12,1.47-0.21c0.36,0.51,0.86,1.02,0.95,1.59 c0.16,0.95,0.03,1.94,0.06,2.91c0.02,0.73-0.3,1.6,0.72,2.02c0.1,0.04,0.07,0.87-0.06,0.92c-0.9,0.37-1.84,0.86-2.77,0.87 c-4.38,0.09-8.76-0.08-13.14,0.08c-4.25,0.15-8.48,0.6-12.73,0.93c-0.14,0.01-0.29,0.04-0.42,0.1c-0.18,0.06-0.46,0.13-0.49,0.24 c-0.27,1.05-1.1,0.74-1.78,0.78c-1.26,0.07-2.71-0.25-3.73,0.27c-1.56,0.79-3.07,0.49-4.61,0.6c-0.83,0.06-1.66-0.02-2.48,0.05 c-0.46,0.04-0.92,0.23-1.36,0.4c-0.57,0.22-1.11,0.68-1.66,0.69c-5.74,0.12-11.48,0.25-17.22,0.19c-2.94-0.03-5.8,0.32-8.66,0.89 c-1.92,0.38-3.87,0.56-5.81,0.84c-0.14,0.02-0.37,0.03-0.41,0.11c-0.64,1.38-1.89,0.79-2.91,0.91c-0.67,0.07-1.58-0.17-1.99,0.19 c-1.16,1-2.45,0.58-3.69,0.69c-0.83,0.07-1.68,0-2.47,0.2c-0.46,0.12-0.79,0.86-1.24,0.91c-2.91,0.37-5.84,0.62-8.76,0.91 c-0.15,0.01-0.35-0.02-0.43,0.06c-0.65,0.68-1.53,1.29-1.85,2.11c-0.31,0.78,0.21,1.51,0.84,2.36c1.3,1.76,2.87,2,4.54,1.69 c2.76-0.49,5.54,0.64,8.38-0.92c1.96-1.08,4.67-0.8,7.06-1.06c1.06-0.12,2.14-0.03,3.21-0.09c0.36-0.02,0.71-0.16,1.05-0.3 c0.57-0.23,1.13-0.71,1.7-0.71c7.2-0.09,14.42,0.25,21.57-0.98c0.95-0.16,1.86-0.79,2.8-0.8c8.27-0.06,16.54-0.03,24.81-0.02 c0.44,0,1.03-0.11,1.28,0.12c1.16,1.09,2.55,0.69,3.86,0.72c2.62,0.06,5.26-0.04,7.88,0.09c3.92,0.2,7.83,0.57,11.75,0.79 c0.98,0.06,1.1,0.61,1.1,1.33c0.03,2.39,0.05,4.78,0.05,7.16c-0.01,2.02-1.87,3.14-3.77,2.39c-0.95-0.37-1.99-0.7-2.98-0.7 c-10.76-0.06-21.51-0.02-32.27-0.07c-1.58-0.01-3.37,0.66-4.65-0.97c-0.08-0.09-0.27-0.11-0.41-0.13 c-2.93-0.32-5.86-0.62-8.79-0.95c-0.4-0.04-0.8-0.18-1.18-0.33c-0.57-0.24-1.13-0.77-1.69-0.77c-7.35-0.03-14.69,0-22.04,0.04 c-0.95,0-2.27,1.35-2.31,2.29c-0.03,0.86-0.1,1.62,1.01,2.08c0.65,0.27,0.96,1.53,1.59,1.68c1.92,0.48,3.91,0.63,5.87,0.93 c1.04,0.15,2.37-0.55,2.94,1.01c0.04,0.1,0.36,0.11,0.55,0.12c3.51,0.33,7.01,0.67,10.52,0.95c1.16,0.1,2.34,0.02,3.5,0.08 c0.4,0.02,0.79,0.25,1.19,0.39c0.5,0.18,1.01,0.52,1.52,0.53c2.43,0.06,4.86,0.01,7.3,0.06c0.65,0.01,1.3,0.23,1.94,0.4 c0.48,0.13,0.93,0.46,1.4,0.46c7.84,0.09,15.67,0.05,23.5,0.23c5.81,0.13,11.61,0.48,17.4,0.86c0.64,0.05,1.54,0.85,1.76,1.49 c0.49,1.43,1.55,2.76,1.15,4.45c-0.06,0.27,0.33,0.63,0.48,0.97c0.55,1.25,1.09,2.51,1.63,3.77c-0.137,0.184-0.17,0.23-0.307,0.414 c-0.944-0.093-1.899-0.132-2.823-0.294c-0.59-0.1-1.13-0.53-1.7-0.54c-6.96-0.1-13.91-0.14-20.87-0.22 c-1.08-0.01-2.29,0.4-3.09-0.88c-0.16-0.27-0.9-0.25-1.38-0.26c-1.6-0.03-3.21-0.01-4.82-0.01c-0.33-0.01-0.83,0.09-0.99-0.09 c-0.91-1.09-2.14-0.72-3.26-0.77c-1.26-0.05-2.53,0.01-3.79-0.02c-0.36-0.01-0.72-0.14-1.05-0.29c-0.58-0.25-1.11-0.75-1.7-0.82 c-2.88-0.32-5.74-0.13-8.66-0.74c-3.27-0.68-6.78-0.21-10.19-0.18c-0.48,0-1.14,0.2-1.4,0.55c-0.9,1.21,0.09,4.17,1.51,4.44 c2.01,0.39,4.05,0.6,6.08,0.87c0.72,0.1,1.84-0.1,2.09,0.29c0.78,1.21,1.85,0.74,2.83,0.84c0.92,0.1,2.04-0.16,2.7,0.29 c1.05,0.71,2.08,0.6,3.16,0.65c1.06,0.05,2.18-0.07,3.19,0.21c1.63,0.45,3.16,1.3,4.8,1.72c1.71,0.45,3.48,0.08,5.27,1.06 c1.43,0.78,3.44,0.32,5.23,0.91c2.13,0.71,4.5-0.02,6.83,0.88c2.46,0.95,5.22,0.01,8.01,1.07c3.13,1.19,6.86,0.81,10.33,1.12 c0.57,0.05,1.18,0.03,1.68,0.26c0.64,0.3,1.17,0.82,1.75,1.24c0.15-0.02,0.31-0.05,0.46-0.08c-0.1,1.18,0.17,2.59-0.39,3.5 c-0.86,1.38-2.53,1.97-4.19,2.02c-3.25,0.08-6.51,0.02-9.76,0.07c-1.86,0.03-2.68,0.94-2.66,2.81c0.01,0.93,1.47,3.14,2.4,3.36 c1.65,0.4,3.33,0.82,5.01,0.9c3.06,0.14,6.13,0.03,9.19,0.05c1.58,0,2.3,0.73,2.31,2.34c0.02,3.12,0.22,6.25-0.07,9.34 c-0.2,2.13,1.22,2.97,2.27,4.19c0.09,0.1,0.56,0.01,0.73-0.14c0.99-0.82,1.37-1.83,1.28-3.18c-0.06-1.03,0.45-2.08,0.6-3.13 c0.26-1.95-0.25-4.06,1.26-5.73c0.28-5.74,0.56-11.48,0.85-17.22c0.04-0.83,0.14-1.66,0.12-2.48c-0.08-3.46,0.65-6.86,0.83-10.28 c0.13-2.46-0.51-4.96-0.75-7.44c-0.12-1.26,0.28-2.76-0.28-3.74c-0.87-1.54-0.47-3.05-0.63-4.58c-0.05-0.53,0.01-1.07-0.06-1.6 c-0.05-0.37-0.12-0.96-0.36-1.06c-0.97-0.44-0.73-1.24-0.75-1.98c-0.04-1.8,0.39-3.78-0.24-5.34c-0.66-1.64-0.54-3.17-0.62-4.76 c-0.07-1.22-0.02-2.44-0.04-3.65c-0.01-0.44,0.04-1.1-0.2-1.26c-1.41-0.94-0.74-2.36-0.95-3.57c-0.24-1.44-0.63-2.87-0.69-4.32 c-0.07-1.59-0.67-3.32,0.58-4.74c0.21-0.24,0.92-0.42,1-0.32c0.42,0.54,0.88,1.15,1.01,1.8c0.31,1.52-0.14,3.06,1.03,4.58 c1.02,1.3,1.22,3.22,1.85,4.85c0.34,0.86,0.86,1.64,1.25,2.49c0.27,0.58,0.43,1.22,0.69,1.82c0.46,1.07,0.96,2.13,1.45,3.19 c0.52,1.12,1.04,2.24,1.56,3.35c0.41,0.87,1.05,1.69,1.2,2.59c0.41,2.58,0.73,5.18,0.87,7.78c0.17,3.21,0.12,6.43,0.19,9.64 c0.01,0.43-0.01,1.08,0.24,1.23c1.04,0.66,0.84,1.66,0.91,2.6c0.27,3.54-0.37,7.08,0.66,10.64c0.5,1.72,1.74,2.57,2.66,3.79 c0.16,0.21,0.75,0.19,1.12,0.12c0.62-0.12,2.42-2.53,2.46-3.18c0.51-8.75-0.35-17.53,0.71-26.29c0.41-3.38-0.31-6.91-0.58-10.36 c-0.09-1.15,0.49-2.57-1.1-3.24c-0.11-0.04-0.11-0.35-0.13-0.54c-0.3-2.81-0.59-5.62-0.9-8.42c-0.05-0.47-0.11-1.21-0.38-1.33 c-1.02-0.43-0.73-1.26-0.78-1.97c-0.08-1.11,0.3-2.53-0.25-3.27c-0.83-1.1-0.52-2.02-0.49-3.05c1.99-0.43,3.75-1.81,5.74-0.95 c0.39,2.88,0.85,5.69,1.14,8.52c0.23,2.29,1.01,4.26,2.89,5.63c0.45,0.33,1.22,0.47,1.77,0.35c0.76-0.15,1.45-0.63,2.3-1.03 c0-2.53-0.02-5.15,0.02-7.78c0.01-0.86-0.14-1.96,0.31-2.53c0.91-1.16,0.53-1.98-0.12-2.77c0.48-1.75,1.76-1.6,3.07-1.64 c6.71-0.25,13.42-0.57,20.13-0.87c0.19,0,0.39-0.03,0.58-0.06c2.915-0.587,5.795-1.362,8.816-1.146 c1.388,0.099,2.779,0.185,4.166,0.067c1.583-0.135,3.2,0.101,4.658-0.921c0.97-0.68,1.69-1.88,1.18-3.28 c-0.25-0.68-1.16-1.55-1.81-1.58c-5.95-0.3-11.92-0.12-17.83-1.11c-0.37-0.06-0.98-0.04-1.06-0.23c-0.47-1.12-1.42-0.85-2.25-0.88 c-1.79-0.07-3.78,0.4-5.34-0.22c-1.54-0.62-2.97-0.51-4.46-0.69c-4.45-0.53-9.09,1.2-13.37-1.14c-0.57-0.31-1.22-0.55-1.66-0.99 c-1.16-1.18-2.18-2.5-3.35-3.68c-1.89-1.9-3.88-3.71-5.77-5.62c-1.11-1.1-1.9-2.74-3.21-3.36c-1.71-0.81-2.94-1.96-4.27-3.2 c-1.45-1.36-3.25-2.35-5.13-3.67v-1.37c2.39,0.23,4.78-0.38,6.81,1.6c0.74,0.73,2.1,1.17,3.17,1.15c2.07-0.06,2.81-1.1,2.83-3.22 c0.012-1.029,0.105-2.072-0.135-3.065c-0.126-0.522-0.594-1.242-0.983-1.612c-0.994-0.944-2.204-1.718-2.982-2.803 c-1.18-1.62-2.71-2.7-4.3-3.8c-0.66-0.45-1.27-1.04-1.77-1.68c-0.62-0.77-1.01-1.75-1.67-2.48c-0.7-0.79-1.07-1.55-1.07-2.66 c0.04-25.52,0.02-51.03,0.09-76.55c0.01-2.45,0.54-4.89,0.86-7.33c0.02-0.2,0.28-0.36,0.38-0.56c0.51-1.02,1.37-2.03,1.42-3.07 c0.2-4.67,0.37-9.36,0.15-14.02c-0.23-4.6,0.89-9.24-0.91-13.86c-0.97-2.5-0.76-5.45-1.08-8.2c-0.06-0.53-0.12-1.06-0.22-1.59 c-0.17-0.92-0.53-1.84-0.54-2.75c0-1.6-0.1-3.16,0.52-4.8c0.54-1.42,0.41-3.2,0.21-4.77c-0.37-2.8,0.82-5.35,0.97-8.05 c0.01-0.14,0.05-0.36,0.14-0.4c1.26-0.61,0.84-1.8,0.99-2.79c0.06-0.43-0.11-1.04,0.12-1.27c1.46-1.45,0.73-3.5,1.61-5.25 c1.1-2.2-0.12-5.19,1.07-7.68c0.04-9.5,0.1-18.99,0.12-28.49c0-1.74,0.34-3.72-0.35-5.18c-0.85-1.83-0.55-3.56-0.74-5.33 c-0.04-0.36-0.16-0.73-0.31-1.07c-0.25-0.56-0.68-1.08-0.79-1.67c-0.37-2.01-0.64-4.05-0.95-6.07 c-0.018-0.064-0.035-0.126-0.053-0.19c-0.547-1.29-1.442-2.513-1.707-3.87c-0.47-2.46-0.88-4.98-0.88-7.47 c-0.04-51.72-0.02-103.44-0.05-155.15c0-2.24,0.68-3.89,2.54-5.13c0.81-0.53,1.5-1.26,2.19-1.96c1.11-1.12,2.13-2.32,3.27-3.39 c0.39-0.36,1.19-0.28,1.57-0.64c1.32-1.26,2.51-2.66,3.81-3.95c1.03-1.02,2.18-1.94,3.2-2.97c1.34-1.36,2.58-2.82,3.92-4.18 c1.21-1.22,2.62-2.26,3.72-3.58c1.17-1.4,2.28-2.77,4.14-3.27c0.14-0.04,0.24-0.28,0.35-0.43c1.26-1.87,1.11-3.98,0.97-6.07 c-0.02-0.38-0.44-0.97-0.78-1.06c-2.42-0.64-4.68,0.12-6.93,0.92c-0.29,1.52-1.89,1.12-2.8,1.7c-1.15,0.74-2.85,0.01-4.3,1.16 c-0.88,0.7-2.61,0.58-3.96,0.92c-1.74,0.44-3.32,1.03-4.92,2.07c-0.1-0.55-0.25-1.01-0.25-1.47c0-2.48-0.03-4.97,0.07-7.45 c0.23-5.62,0.14-11.24,0.73-16.88c0.56-5.39-0.01-10.89-0.04-16.34c-0.03-6.04,0.03-12.08-0.03-18.12 c-0.03-2.15,0.05-4.26-0.48-6.46c-0.76-3.17-0.78-6.51-1.2-9.77c-0.11-0.84-0.54-1.64-0.8-2.46c-0.06-0.22-0.15-0.54-0.04-0.67 c0.72-0.89,1.46-1.75,2.24-2.59c1.82-1.97,3.8-3.81,5.45-5.92c1.33-1.69,2.58-3.28,4.76-3.9c0.76-0.21,1.55-0.62,2.13-1.15 c1.19-1.11,2.12-2.36,3.81-3.06c1.74-0.72,3.12-2.32,4.64-3.56c0.41-0.33,0.73-0.78,1.16-1.07c2.04-1.42,4.11-2.79,6.15-4.21 c0.29-0.2,0.44-0.61,0.73-0.8c1.46-0.91,3.01-1.69,4.41-2.68c1.16-0.81,2.17-1.83,3.2-2.8c0.46-0.44,0.86-0.97,1.18-1.51 c0.4-0.68,0.54-1.55,1.06-2.09c1.159-1.21,1.822-2.544,1.82-4.222c0-0.258,0.046-0.516,0.159-0.747c0.97-1.97,2.06-3.9,2.95-5.92 c1.15-2.6,2.08-5.3,3.24-7.89c1.04-2.33,2.44-4.52,3.34-6.89c0.61-1.59,1.59-2.02,3.03-2.03c3.99-0.03,7.99-0.22,11.96,0.02 c2.25,0.14,3.79-1.49,5.85-1.66c0.717-0.051,1.424-0.522,2.077-0.886c0.846-0.472,1.672-0.976,2.476-1.516 c0.646-0.434,1.381-0.838,1.917-1.398C230.441,131.98,230.311,130.27,230.071,128.64z M111.437,192.42 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z\"\n ],\n clocks: {\n size: 169,\n 0: { x: 111.011, y: 108.5 }\n }\n },\n 2: {\n height: 625.438,\n width: 197.009,\n path: \"M193.86,271.21c-2.234-2.626-5.64-4.792-8.929-5.835c-6.793-2.153-11.841,2.196-17.463,7.369 c-5.009-25.727-17.583-43.987-38.477-54.246l-18.909-21.56v-12l20.773-23.686c19.55-10.446,31.402-28.304,36.229-53.096 c5.622,5.174,10.67,9.523,17.463,7.369c3.289-1.043,6.695-3.208,8.929-5.835c4.877-5.734,3.879-14.302-1.542-19.605 c-6.442-6.301-13.569-5.549-24.852,3.382c-4.816-25.231-17.183-43.587-38.409-54.031h0.158c-1.506-0.732-3.056-1.394-4.625-2.025 c-2.997-1.25-6.144-2.365-9.463-3.327c0,0-0.527-0.089-1.457-0.217c-2.421-0.731-4.757-2.02-7.743-3.273 c2.103-2.282,3.255-3.455,4.321-4.703c5.176-6.057,4.821-14.978-0.792-20.538c-5.647-5.594-14.543-5.829-20.352-0.539 c-6.101,5.556-6.808,14.49-1.648,20.831c4.153,5.103,3.905,5.403-2.49,8.055c-1.793,0.744-3.604,1.465-5.417,2.187 c-10.281,3.032-16.092,6.929-22.875,12.001c-12.415,9.284-19.739,22.385-23.521,37.515c-0.673,2.693-2.08,5.2-3.437,8.492 c-2.262-2.122-3.424-3.284-4.661-4.36c-6.003-5.222-14.845-4.864-20.356,0.799c-5.544,5.698-5.778,14.673-0.534,20.534 c5.507,6.156,14.361,6.869,20.646,1.662c5.058-4.19,5.355-3.94,7.984,2.512c3.394,8.33,6.292,17.054,10.972,24.62 c6.032,9.752,14.303,16.873,24.096,21.915l21.601,23.357v12l-20.223,21.867c-10.232,5.068-18.855,12.348-25.091,22.43 c-4.68,7.566-7.578,16.29-10.972,24.62c-2.629,6.452-2.926,6.702-7.984,2.512c-6.285-5.206-15.139-4.493-20.646,1.662 c-5.243,5.861-5.01,14.837,0.534,20.534c5.511,5.663,14.352,6.021,20.356,0.799c1.237-1.076,2.399-2.238,4.661-4.36 c1.356,3.292,2.764,5.799,3.437,8.492c3.782,15.13,11.106,28.232,23.521,37.515c7.877,5.89,14.425,10.198,28.206,13.404 c1.38,0.321,2.787,0.579,4.201,0.789c0.031,27.796,0.06,69.604,0.085,105.236c0.009,13.829,0.018,26.73,0.026,37.518 c0,0.826-0.08,1.652-0.121,2.436c-3.447,0.597-4.58-0.495-4.682-4.511c-0.072-2.822-0.002-5.649-0.016-8.473 c-0.024-4.802-0.891-5.97-4.609-5.976c-14.432-0.022-28.864-0.01-43.295-0.009c-4.627,0-9.255,0.084-13.881-0.022 c-3.054-0.07-4.428,1.698-4.326,5.623c0.079,3.039,0.085,6.08-0.001,9.119c-0.111,3.933,1.27,5.674,4.317,5.646 c8.372-0.076,16.745-0.038,25.118-0.024c4.14,0.007,4.933,1.055,4.947,6.397c0.024,9.702,0.024,9.702-7.67,9.702 c-7.381-0.001-14.762-0.025-22.143,0.006c-3.558,0.015-4.54,1.209-4.551,5.611c-0.035,13.947-0.943,13.109,10.004,13.035 c6.61-0.045,13.22-0.032,19.83,0.002c3.528,0.018,4.463,1.226,4.534,5.638c0.17,10.455,0.17,10.455-8.056,10.455 c-7.271,0-14.542-0.024-21.813,0.01c-3.492,0.016-4.48,1.263-4.503,5.672c-0.067,12.642-0.701,12.243,9.397,12.129 c6.83-0.077,13.661-0.04,20.491-0.004c3.466,0.018,4.419,1.281,4.484,5.702c0.154,10.39,0.154,10.39-8.106,10.39 c-7.271,0-14.542-0.026-21.813,0.01c-3.447,0.017-4.439,1.296-4.452,5.736c-0.039,13.671-0.908,12.955,9.772,12.916 c17.076-0.063,34.152-0.012,51.227-0.02c4.329-0.002,5.098-1.02,5.1-6.63c0.001-1.977-0.037-3.956,0.007-5.931 c0.094-4.282,1.178-5.371,4.197-4.937c1.031,10.07,1.909,19.99,3.129,29.842c0.425,3.429,1.312,6.98,2.695,9.93 c1.2,2.56,3.388,5.993,5.16,6.013c1.744,0.02,4.469-3.383,5.098-5.954c2.029-8.292,4.037-16.802,4.667-25.395 c0.85-11.612,0.501-23.379,0.517-35.079c0.042-30.977,0.078-68.798,0.115-106.572c0.037-37.246,0.075-74.445,0.121-104.988 c3.105-0.304,5.045-0.635,5.045-0.635c29.872-8.658,46.55-29.062,52.338-59.383c11.283,8.931,18.409,9.683,24.852,3.382 C197.739,285.512,198.737,276.945,193.86,271.21z M44.186,100.381c0-29.823,24.177-54,54-54s54,24.177,54,54 c0,29.823-24.177,54-54,54S44.186,130.205,44.186,100.381z M98.186,334.381c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 s54,24.177,54,54C152.186,310.205,128.009,334.381,98.186,334.381z\",\n clocks: {\n size: 108,\n 0: { x: 98.579, y: 280 },\n 1: { x: 98.579, y: 100 }\n }\n },\n 3: {\n height: 915.936,\n width: 277.634,\n path: \"M263.752,257.836c-13.719,1.508,3.345-15.515,3.955-23.109l-0.113,0.113 c8.127-22.574,2.75-46.079-10.802-65.608c14.365-1.735,19.981-6.287,20.122-15.339c0.118-7.617-5.228-14.388-12.762-14.963 c-3.451-0.263-7.412,0.636-10.496,2.245c-6.369,3.324-6.896,10.001-7.248,17.67c-12.146-8.157-24.329-12.988-36.575-14.34 c-2.94-2.54-4.264-6.236-3.879-10.997c0.451-5.587,0.239-11.066-0.572-16.359c0.828-2.872,1.549-5.847,2.156-8.934 c5.672,5.174,10.766,9.523,17.62,7.369c3.319-1.043,6.755-3.208,9.009-5.835c4.921-5.734,3.914-14.302-1.556-19.605 c-6.5-6.301-13.69-5.549-25.075,3.382c-5.055-30.578-25.967-51.62-54.619-60.047c-2.447-0.732-4.807-2.023-7.825-3.278 c2.125-2.286,3.29-3.461,4.367-4.71c11.938-14.551-7.15-33.181-21.367-21.111c-6.165,5.565-6.879,14.513-1.665,20.864 c4.197,5.111,3.946,5.411-2.516,8.068c-1.812,0.745-3.642,1.467-5.474,2.19c-24.645,7.648-40.948,25.21-46.886,49.595 c-0.68,2.698-2.102,5.208-3.473,8.505c-2.286-2.125-3.461-3.29-4.71-4.367c-14.552-11.938-33.18,7.152-21.111,21.367 c5.565,6.165,14.513,6.879,20.864,1.665c4.71-3.867,5.338-3.944,7.487,1.123c-1.309,6.465-1.74,13.174-1.396,20.102 c0.3,6.03-1.497,10.097-5.356,12.617c-8.889,2.044-17.148,6.132-25.567,9.656c-6.448,2.691-6.837,2.656-7.484-3.926 c-0.804-8.178-7.636-14-15.931-13.576c-18.581,1.516-18.918,28.187-0.181,30.036c1.645,0.122,3.299,0.129,6.419,0.243 c-1.366,3.319-2.113,5.992-3.558,8.47c-3.428,5.74-6.123,11.683-7.912,17.811c-4.722,16.154-2.533,34.602,5.996,50.411 c1.801,5.691,8.569,13.392-1.603,12.903c-40,12.971,18.416,54.114,16.704,9.691c34.782,3.225,46.692,41.92,80.447,49.674 c7.963,2.791,11.179,6.671,12.046,13.724c0.012,3.241,0.01,6.503,0,9.829h-0.223c0,2.086,0,5.309,0,5.309s0.065,0.184-0.069,0.268 c-7.211-0.002-14.005-0.041-20.79,0.015c-4.483,0.037-6.154,1.09-6.592,4.667c-0.352,4.638-0.043,9.45-0.131,14.122 c0.062,5.274,1.49,6.69,6.861,6.724c6.999,0.045,13.998,0.011,21.721,0.011v5.671c-7.723,0-14.722-0.034-21.721,0.011 c-5.372,0.035-6.799,1.45-6.861,6.724c0.087,4.671-0.221,9.484,0.131,14.122c0.438,3.577,2.109,4.63,6.592,4.667 c6.785,0.056,13.579,0.017,20.79,0.015c0.134,0.084,0.279,0.175,0.069,0.268v5.406h0.599c0.031,3.784,0.031,7.619,0,12h-0.599 v4.809c0,0,0.065,0.184-0.069,0.268c-7.211-0.002-14.005-0.041-20.79,0.015c-4.483,0.037-6.154,1.09-6.592,4.667 c-0.352,4.638-0.043,9.45-0.131,14.122c0.062,5.274,1.49,6.69,6.861,6.724c6.999,0.045,13.998,0.011,21.721,0.011v5.671 c-7.723,0-14.722-0.034-21.721,0.011c-5.372,0.035-6.799,1.45-6.861,6.724c0.087,4.671-0.221,9.484,0.131,14.122 c0.438,3.577,2.109,4.63,6.592,4.667c6.785,0.056,13.579,0.017,20.79,0.015c0.134,0.084,0.279,0.175,0.069,0.268v4.906h0.599 c0.031,4.284,0.031,8.119,0,12h-0.599v5.309c0.211,0.092,0.065,0.184-0.069,0.268c-7.211-0.002-14.005-0.041-20.79,0.015 c-4.483,0.037-6.154,1.09-6.592,4.667c-0.352,4.638-0.043,9.45-0.131,14.122c0.062,5.274,1.49,6.69,6.861,6.724 c6.999,0.045,21.721,0.011,21.721,0.011v5.671c0,0-14.722-0.034-21.721,0.011c-5.372,0.035-6.799,1.45-6.861,6.724 c0.087,4.671-0.221,9.484,0.131,14.122c0.438,3.577,2.109,4.63,6.592,4.667c6.785,0.056,13.579,0.017,20.79,0.015 c0.134,0.084,0.279,0.175,0.457,0.268c0,1.594,4.559,168.228,4.51,209.286c-0.005,4.1,0.442,9.128,0.442,10.259 c-3.396,0-6.234,0.133-9.054-0.034c-3.499-0.206-5.37,1.456-6.735,4.558c-1.281,2.913-2.803,5.866-4.843,8.27 c-6.58,7.751-16.578,7.84-23.206,0.144c-2.209-2.565-3.736-5.81-5.169-8.932c-1.239-2.699-2.939-4.083-5.916-4.024 c-3.712,0.073-7.428,0.078-11.14-0.009c-3.163-0.074-4.936,1.432-6.143,4.306c-1.141,2.716-2.476,5.469-4.285,7.764 c-8.725,11.281-23.01,6.923-27.966-5.357c-1.496-5.628-5.039-7.274-10.521-6.767c-4.485,0.415-6.285,1.937-6.286,6.612 c-0.001,15.755-0.002,31.511-0.003,47.266c-0.001,16.376-0.012,32.752,0.006,49.127c0.004,3.646,2.039,5.706,5.586,5.765 c4.244-0.151,7.724,1.078,9.747-3.72c1.63-3.566,3.31-7.297,5.811-10.239c5.927-6.969,15.25-7.396,21.596-0.827 c2.91,3.012,4.885,7.078,6.716,10.936c1.245,2.623,2.748,3.896,5.573,3.857c3.96-0.055,7.925-0.102,11.882,0.027 c3.041,0.099,4.629-1.359,5.914-4.011c1.386-2.861,3.016-5.766,5.166-8.063c10.107-10.412,22.254-3.718,27.139,8.037 c1.337,2.907,3.18,4.141,6.281,4.034c3.442-0.119,6.891-0.027,10.523-0.027c1.065,5.652,2.167,11.021,3.856,16.453 c1.228,3.675,2.407,8.536,7.056,8.594c4.923,0.061,6.042-4.987,7.307-8.743c1.456-4.322,2.867-8.847,3.125-13.35 c0.728-12.721,1.152-25.477,1.174-38.219c0.19-111.404,0.292,50.177,0.366-61.227c0.003-5.129,0.201-18.49,0.201-22.46 c0-41.693,4.098-203.286,4.098-209.558c8.112,0,15.82-0.053,23.528,0.021c5.544,0.13,6.64-3.323,6.288-8.201 c0.033-3.547,0.038-7.095-0.007-10.642c-0.066-5.278-1.476-6.669-6.885-6.701c-7.529-0.044-23.121-0.011-23.121-0.011v-5.671 c0,0,15.592,0.033,23.121-0.011c5.408-0.032,6.819-1.423,6.885-6.701c0.044-3.547,0.04-7.095,0.007-10.642 c0.351-4.882-0.742-8.33-6.288-8.201c-7.707,0.073-15.416,0.021-22.724,0.021v-22.76c7.308,0,15.017-0.053,22.724,0.021 c5.544,0.13,6.64-3.323,6.288-8.201c0.033-3.547,0.038-7.095-0.007-10.642c-0.066-5.278-1.476-6.669-6.885-6.701 c-7.529-0.044-15.059-0.011-23.121-0.011v-5.671c8.062,0,15.592,0.033,23.121-0.011c5.408-0.032,6.819-1.423,6.885-6.701 c0.044-3.547,0.04-7.095,0.007-10.642c0.351-4.882-0.742-8.33-6.288-8.201c-7.707,0.073-15.416,0.021-22.724,0.021v-22.76 c7.308,0,15.017-0.053,22.724,0.021c5.544,0.13,6.64-3.323,6.288-8.201c0.033-3.547,0.038-7.095-0.007-10.642 c-0.066-5.278-1.476-6.669-6.885-6.701c-7.529-0.044-15.059-0.011-23.121-0.011v-5.671c8.062,0,15.592,0.033,23.121-0.011 c5.408-0.032,6.819-1.423,6.885-6.701c0.044-3.547,0.04-7.095,0.007-10.642c0.351-4.882-0.742-8.33-6.288-8.201 c-7.707,0.073-15.416,0.021-22.724,0.021v-13.831c0.379-7.638,5.186-13.149,13.162-15.825 c28.456-7.104,41.808-33.352,64.888-48.287c17.492-10.743,9.354,22.937,28.518,19.129 C282.127,286.309,282.455,259.681,263.752,257.836z M105.697,839.074c0.498,2.38,0.15,4.934-3.302,4.884 c-2.295-0.033-3.176,1.042-3.702,3.217c-0.26,1.076-1.713,2.383-2.793,2.559c-0.723,0.118-2.36-1.479-2.505-2.467 c-0.409-2.804-2.004-3.344-4.385-3.299c-3.709,0.07-7.424,0.116-11.131-0.006c-3.83-0.126-3.945,2.278-3.981,5.13 c-0.038,2.976,0.755,4.826,4.142,4.589c1.477-0.103,2.968,0.015,4.451-0.025c2.202-0.059,4.543-0.006,4.579,2.901 c0.039,3.187-2.477,3.119-4.78,3.068c-1.36-0.03-2.728,0.082-4.08-0.025c-3.258-0.257-4.5,1.312-4.272,4.425 c-0.041,4.353,1.027,8.028-4.883,7.506c-7.022,0.039-7.951,0.802-7.543-7.405c0.169-3.39-1.192-4.855-4.554-4.524 c-0.857,0.085-1.922,0.329-2.555-0.056c-1.2-0.729-2.156-1.861-3.213-2.825c1.006-1.017,1.944-2.121,3.057-3.004 c0.38-0.301,1.199-0.042,1.817-0.044c5.007-0.022,7.131-2.986,5.196-7.646c-0.392-0.945-1.974-1.785-3.11-1.944 c-3.651-0.437-7.442,0.158-11.117-0.121c-3.786-0.387-5.894,0.721-5.698,5.061c0.045,0.996-1.78,2.077-2.744,3.119 c-0.848-1.038-2.451-2.105-2.412-3.108c0.153-3.932-1.445-5.27-5.269-5.225c-1.017,0.012-2.491-1.899-2.973-3.215 c-0.52-1.421-0.127-3.18-0.126-4.791c0-5.24-0.002-5.268,5.3-5.954c2.366-0.306,3.023-1.787,2.927-3.889 c-0.098-2.143,0.268-4.425,2.848-4.073c1.034,0.141,2.342,2.528,2.49,3.998c0.282,2.788,1.314,4.039,4.131,3.976 c3.956-0.088,7.919-0.125,11.873,0.011c3.063,0.105,4.168-1.204,4.13-4.212c-0.036-2.816-0.326-5.041-3.916-4.755 c-2.559,0.203-4.468-0.474-4.367-3.527c0.095-2.865,2.016-3.344,4.358-3.173c2.898,0.212,3.849-1.243,3.979-4.019 c0.085-1.821,0.73-5.002,1.563-5.153c3.046-0.553,6.308-0.31,9.408,0.165c0.646,0.099,1.284,2.453,1.345,3.795 c0.224,4.967,0.374,5.207,5.401,5.214c1.361,0.002,2.929-0.422,4.027,0.116c1.271,0.623,2.94,2.09,2.942,3.194 c0.002,1.125-1.621,2.815-2.876,3.241c-1.665,0.565-3.667,0.223-5.518,0.132c-3.18-0.157-3.971,1.57-3.952,4.398 c0.019,2.703,0.495,4.64,3.783,4.569c3.956-0.085,7.916-0.055,11.873-0.012c2.165,0.024,3.322-0.763,3.826-3.068 c0.241-1.105,1.771-1.927,2.718-2.877c0.905,0.971,2.333,1.814,2.605,2.939c0.545,2.256,1.757,2.7,3.843,3.111 C108.401,831.102,105.035,835.914,105.697,839.074z M139.108,46c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54 s-54-24.177-54-54C85.108,70.176,109.285,46,139.108,46z M19.108,212c0-29.823,24.177-54,54-54s54,24.177,54,54 c0,29.823-24.177,54-54,54S19.108,241.823,19.108,212z M144.944,857.898c-2.09,2.578-1.865,5.176-1.942,7.953 c-0.024,0.854,0.131,1.914-0.302,2.509c-2.403,3.147-3.159,2.809-5.436-0.185c-0.264-0.306-0.178-0.948-0.184-1.437 c-0.041-3.271,0.536-6.657-2.369-9.253c-0.531-0.475-0.479-1.605-0.957-3.425c1.21-1.271,2.47-3.306,4.294-4.333 c2.379-1.339,5.236-0.58,6.441,1.819C145.405,853.367,145.95,856.658,144.944,857.898z M144.996,807.941 c-2.224,2.677-1.877,5.438-1.992,8.318c-0.086,2.146-0.2,4.578-2.99,4.544c-2.765-0.034-2.874-2.475-2.933-4.614 c-0.08-2.895,0.543-5.919-2.179-8.193c-0.631-0.527-0.645-1.797-1.234-3.633c1.265-1.382,2.48-3.465,4.292-4.5 c2.341-1.338,5.233-0.649,6.476,1.731C145.382,803.404,145.991,806.744,144.996,807.941z M80.062,279.694 c17.171-3.582,56.234-25.446,59.296-50.487c5.518,22.114,30,48.729,61,48.729C162.77,319.773,120.431,321.28,80.062,279.694z M205.108,266c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54C259.108,241.823,234.932,266,205.108,266z\",\n clocks: {\n size: 108,\n 0: { x: 138.892, y: 100 },\n 1: { x: 72.892, y: 212 },\n 2: { x: 204.892, y: 212 }\n }\n },\n 4: {\n height: 1041,\n width: 368.697,\n path: \"M365.949,178.882c-2.159-2.705-5.464-5.038-8.725-6.201c-7.211-2.57-12.634,1.794-18.155,7.261 c-1.008-3.182-1.811-5.292-2.346-7.468c-7.207-29.311-25.676-46.993-55.052-53.142c-3.565-0.746-4.337-2.365-5.721-5.525 c-10.917-24.928-15.917-32.928-31.863-49.408c-1.625-1.679-3.453-3.192-5.144-4.761c-15.909-14.758-20.909-17.758-43.492-26.71 c-1.882-0.746-3.781-1.782-6.866-3.302c2.349-1.876,3.694-2.659,4.662-3.772c4.695-5.397,4.837-13.436,0.452-19.014 c-5.3-6.742-15-7.806-21.456-2.354c-6.714,5.67-7.304,15.417-1.328,21.919c3.617,3.935,3.297,5.361-1.725,7.153 c-2.044,0.73-4.17,1.226-6.237,1.896c-12.766,4.137-23.255,11.604-31.918,21.798c-2.372,2.791-4.778,5.622-7.539,8.002 c-15.564,13.413-26.166,29.895-31.108,49.904c-0.68,2.752-1.741,4.084-4.825,4.54c-29.053,4.299-51.461,25.809-57.16,54.556 c-0.307,1.549-0.792,3.062-1.25,4.806c-11.35-8.302-18-8.998-24.401-2.862c-5.321,5.101-6.467,13.398-1.935,19.203 c2.036,2.608,5.192,4.836,8.302,6.005c7.137,2.683,12.59-1.579,17.735-6.353c0.583,1.299,1.01,1.874,1.096,2.496 c4.046,29.315,27.997,53.277,57.825,57.393c2.223,0.307,4.062,1.874,4.644,4.041c1.308,4.861,2.891,9.682,4.787,14.345 c9.432,23.198,28.811,38.203,45.823,55.084c5.104,5.065,11.204,9.197,17.156,13.308c5.563,3.842,7.792,8.391,7.788,15.456 c-0.129,188.254-0.004,308.508,0.065,496.762c0,0.102-0.005,0.205-0.006,0.307v41.241c-2.701,0.026-5.102,0.092-7.461-0.047 c-3.499-0.206-5.37,1.456-6.735,4.558c-1.282,2.913-2.803,5.866-4.844,8.27c-6.581,7.751-16.578,7.84-23.206,0.144 c-2.254-2.617-3.797-5.94-5.255-9.119c-1.087-2.369-3.472-3.882-6.078-3.833c-3.63,0.068-7.263,0.071-10.893-0.013 c-3.163-0.074-4.936,1.432-6.143,4.306c-1.141,2.716-2.476,5.469-4.285,7.764c-8.725,11.281-23.01,6.923-27.966-5.357 c-1.496-5.628-5.039-7.274-10.521-6.767c-4.485,0.415-6.285,1.937-6.286,6.612c-0.001,15.755-0.002,31.511-0.003,47.266 c-0.001,16.376-0.012,32.752,0.006,49.127c0.004,3.646,2.039,5.706,5.586,5.765c4.244-0.151,7.724,1.078,9.747-3.72 c1.63-3.566,3.31-7.297,5.811-10.239c5.927-6.969,15.25-7.396,21.596-0.827c2.91,3.012,4.885,7.078,6.716,10.936 c1.457,3.071,3.269,4.292,7.14,3.723c2.897-0.426,5.844-0.506,8.73-0.009c4.108,0.708,6.007-0.762,7.499-3.84 c1.386-2.861,3.016-5.766,5.166-8.063c10.107-10.412,22.254-3.718,27.139,8.037c1.337,2.907,3.181,4.141,6.281,4.034 c2.715-0.094,5.446-0.058,8.257-0.038v2.091c0.319,0.001,0.631,0.004,0.951,0.004c0.362,2.11,0.473,3.786,0.947,5.352 c2.41,7.972,4.19,16.244,7.596,23.773c3.168,7.005,9.289,6.901,12.709-0.011c2.932-5.925,5.134-12.395,6.525-18.868 c4.01-18.662,2.675-37.664,2.696-56.567c0.133-118.853,0.314,0.295,0.392-118.558c0.068-103.934,0.013-377.867,0.064-481.801 c0.001-2.781-0.281-6.125,1.073-8.24c4.886-7.634,8.978-15.851,18.168-20.058c5.139-2.352,9.257-7.045,13.652-10.893 c4.267-3.736,8.16-7.904,12.459-11.599c15.452-13.278,26.023-29.619,30.885-49.451c0.909-3.707,2.926-4.598,6.161-5.73 c8.764-3.067,17.943-5.775,25.742-10.598c14.82-9.164,23.822-23.162,28.263-40.071c0.703-2.678,1.909-5.223,2.991-8.122 c11.076,8.596,18.006,9.328,24.489,3.223C369.187,192.953,370.464,184.538,365.949,178.882z M146.765,952.539 c0.498,2.38,0.15,4.934-3.302,4.884c-2.294-0.033-3.176,1.042-3.702,3.217c-0.26,1.076-1.713,2.383-2.793,2.559 c-0.723,0.118-2.36-1.479-2.504-2.467c-0.409-2.804-2.004-3.344-4.384-3.299c-3.709,0.07-7.424,0.116-11.131-0.006 c-3.83-0.126-3.945,2.278-3.981,5.13c-0.038,2.976,0.755,4.826,4.142,4.589c1.477-0.103,2.968,0.015,4.451-0.025 c2.202-0.059,4.543-0.006,4.579,2.901c0.04,3.187-2.477,3.119-4.78,3.068c-1.36-0.03-2.728,0.082-4.08-0.025 c-3.258-0.257-4.5,1.312-4.272,4.425c-0.041,4.353,1.027,8.028-4.883,7.506c-7.022,0.039-7.951,0.802-7.542-7.405 c0.168-3.39-1.192-4.855-4.555-4.524c-0.857,0.085-1.922,0.329-2.555-0.056c-1.2-0.729-2.156-1.861-3.213-2.825 c1.006-1.017,1.944-2.121,3.057-3.004c0.379-0.301,1.199-0.042,1.817-0.044c5.007-0.022,7.131-2.986,5.197-7.646 c-0.393-0.945-1.975-1.785-3.11-1.944c-3.651-0.437-7.442,0.158-11.117-0.121c-3.786-0.387-5.894,0.721-5.698,5.061 c0.045,0.996-1.78,2.077-2.744,3.119c-0.848-1.038-2.451-2.105-2.412-3.108c0.153-3.932-1.445-5.27-5.269-5.225 c-1.017,0.012-2.491-1.899-2.973-3.215c-0.52-1.422-0.127-3.18-0.126-4.791c0.001-5.24-0.002-5.268,5.3-5.954 c2.366-0.306,3.023-1.787,2.927-3.889c-0.098-2.143,0.268-4.425,2.848-4.073c1.034,0.141,2.342,2.528,2.49,3.998 c0.282,2.788,1.314,4.039,4.131,3.976c3.956-0.088,7.919-0.125,11.872,0.011c3.063,0.105,4.168-1.204,4.13-4.212 c-0.035-2.816-0.326-5.041-3.916-4.755c-2.559,0.203-4.468-0.474-4.367-3.527c0.095-2.865,2.016-3.344,4.358-3.173 c2.898,0.212,3.849-1.243,3.979-4.019c0.085-1.821,0.73-5.002,1.563-5.153c3.046-0.553,6.308-0.31,9.408,0.165 c0.646,0.099,1.284,2.453,1.345,3.795c0.224,4.967,0.375,5.207,5.402,5.214c1.361,0.002,2.928-0.423,4.027,0.116 c1.272,0.623,2.94,2.09,2.943,3.194c0.002,1.125-1.621,2.815-2.876,3.241c-1.666,0.565-3.668,0.223-5.518,0.132 c-3.18-0.157-3.971,1.57-3.952,4.398c0.019,2.703,0.495,4.64,3.783,4.569c3.957-0.085,7.916-0.055,11.874-0.012 c2.166,0.024,3.322-0.763,3.826-3.068c0.242-1.105,1.771-1.927,2.718-2.877c0.905,0.971,2.333,1.814,2.605,2.939 c0.545,2.256,1.757,2.7,3.843,3.111C149.469,944.566,146.104,949.379,146.765,952.539z M252.621,98.898 c0.287-0.167,0.574-0.334,0.861-0.502c2.841,6.521,5.683,13.042,8.739,20.056c-4.719,1.002-8.414,1.787-12.443,2.642 C250.758,113.446,251.689,106.172,252.621,98.898z M184.136,46.188c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54 s-54-24.177-54-54C130.136,70.365,154.313,46.188,184.136,46.188z M162.097,165.903c14.218,3.796,27.946,4.565,42.414-0.072 c-3.942,14.414-4.001,28.063,0.302,42.583c-14.189-3.96-27.779-4.487-42.527-0.062C166.547,193.78,166.444,180.286,162.097,165.903 z M114.049,99.643c0.292,0.134,0.583,0.269,0.875,0.403c1.095,7.133,2.19,14.267,3.378,22.01 c-3.852-0.843-7.747-1.695-12.458-2.726C108.69,112.502,111.369,106.072,114.049,99.643z M114.09,275.17 c-2.992-7.299-5.446-13.283-8.044-19.622c4.192-0.951,7.557-1.714,11.303-2.564C116.293,260.174,115.314,266.84,114.09,275.17z M97.136,240.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C151.136,216.012,126.96,240.188,97.136,240.188z M190.317,961.816c-2.889,3.631-2.59,7.316-2.675,11.229 c-0.063,2.929-0.301,6.185-4.102,6.083c-3.718-0.099-3.92-3.373-3.912-6.266c0.01-3.961,0.532-7.956-2.966-11.069 c-0.843-0.75-0.86-2.433-1.653-4.938c1.737-1.842,3.427-4.577,5.876-5.996c3.218-1.864,7.078-0.801,8.743,2.361 C190.908,955.651,191.666,960.12,190.317,961.816z M190.377,894.286c-2.75,3.639-2.754,7.277-2.731,11.231 c0.017,2.954-0.303,6.162-3.967,6.219c-3.722,0.058-4.036-3.156-4.069-6.118c-0.044-3.915,0.729-7.982-2.898-11.07 c-0.855-0.728-0.902-2.408-1.792-5.047c1.877-1.885,3.726-5.163,6.313-5.925c2.41-0.711,6.606,0.411,8.177,2.279 C190.999,887.744,191.681,892.56,190.377,894.286z M190.399,830.196c-3.107,3.329-2.592,6.926-2.795,10.682 c-0.086,1.597-0.323,3.33-1.04,4.717c-1.41,2.725-4.298,2.744-5.822,0.114c-0.63-1.087-1.04-2.453-1.075-3.706 c-0.125-4.43,0.653-9.009-3.304-12.472c-0.62-0.543-0.572-1.852-0.833-2.806c-0.315-0.34-0.629-0.679-0.944-1.019 c2.103-2.244,3.85-5.571,6.413-6.415c2.391-0.788,6.184,0.324,8.392,1.933C192.319,823.355,192.864,827.555,190.399,830.196z M184.136,328.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C238.136,304.012,213.96,328.188,184.136,328.188z M252.789,277.752c-0.265-0.133-0.531-0.265-0.796-0.398 c-1.015-8.257-2.029-16.515-3.086-25.115c4.167,0.862,8.324,1.721,13.585,2.809C259.162,262.841,255.975,270.297,252.789,277.752z M271.136,240.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54c29.823,0,54,24.177,54,54 C325.137,216.012,300.96,240.188,271.136,240.188z\",\n clocks: {\n size: 108,\n 0: { x: 184.245, y: 100 },\n 1: { x: 97.245, y: 186 },\n 2: { x: 271.245, y: 186 },\n 3: { x: 184.245, y: 274 }\n }\n },\n 5: {\n height: 1148.657,\n width: 368.698,\n path: \"M364.919,177.185c-5.856-6.593-15.147-6.888-21.897-0.694c-3.717,3.411-4.299,3.242-5.541-1.587 c-0.25-0.972-0.571-1.926-0.803-2.901c-6.223-26.032-22.396-42.736-47.523-51.238c-2.474-0.837-4.808-2.72-6.666-4.641 c-6.618-6.844-12.426-14.598-19.638-20.709c-7.25-6.144-14.426-11.753-15.964-21.863c-0.145-0.952-0.81-1.83-1.262-2.728 c-10.14-20.142-26.293-32.5-48.2-37.503c-2.572-0.587-5.014-1.743-8.025-2.817c1.316-1.702,1.86-2.531,2.526-3.247 c6.502-6.986,6.698-15.783,0.465-21.94c-5.785-5.714-15.027-5.762-20.84-0.11c-6.368,6.191-6.436,15.084,0.239,21.857 c2.991,3.035,1.728,4.561-1.167,5.98c-1.334,0.654-2.844,0.952-4.281,1.387c-24.857,7.514-40.936,23.712-48.399,48.654 c-0.748,2.499-2.69,4.83-4.561,6.77c-8.684,9.004-17.485,17.897-26.377,26.695c-1.782,1.764-3.95,3.591-6.269,4.287 c-27.272,8.186-44.245,25.906-50.386,53.864c-0.306,1.391-0.752,2.75-1.182,4.299c-11.942-8.326-18.43-8.891-24.733-2.424 c-5.16,5.294-6.085,13.716-1.351,19.24c2.253,2.629,5.655,4.841,8.962,5.874c6.77,2.115,12.009-1.8,16.717-6.757 c0.647,1.364,1.068,1.923,1.182,2.539c5.495,29.672,22.939,48.289,51.806,56.504c1.891,0.538,3.666,2.056,5.112,3.503 c8.725,8.731,17.397,17.519,25.942,26.426c1.755,1.83,3.532,4.061,4.227,6.423c5.507,18.702,16.574,32.696,33.076,43.228 c6.667,4.255,11.428,11.52,16.987,17.48c0.5,0.535,0.688,1.544,0.692,2.334c0.044,10.877,0.03,21.753,0.03,32.638 c-1.577,0.516-2.845,0.932-4.113,1.346c-17.135,5.597-30.511,16.033-39.024,31.952c-3.426,6.407-5.333,13.646-7.754,20.57 c-1.76,5.033-3.129,5.54-6.907,2.08c-2.706-2.478-6.172-4.068-9.837-4.235c-8.598-0.392-15.176,6.223-15.67,13.97 c-0.384,6.021,2.865,11.744,8.198,14.44c5.638,2.851,12.01,2.021,16.818-2.189c2.562-2.243,5.668-1.656,6.923,1.51 c1.187,2.993,1.799,6.229,3.124,9.149c2.549,5.62,4.886,11.444,8.247,16.568c9.497,14.478,39.422,28.018,39.422,28.018v28.542 c0,0-0.496,0.466-0.788,0.469c-5.522,0.049-11.045,0.088-16.568,0.095c-9.805,0.013-10.191,0.382-10.188,9.959 c0.001,2.347-0.002,4.695,0,7.042c0.008,7.059,1.061,8.147,7.942,8.157c6.643,0.01,13.286,0.002,20.223,0.002 c-0.115,2.368-0.198,4.098-0.292,6.035c-7.528,0-14.546,0.054-21.562-0.02c-3.56-0.037-6.383,2.854-6.323,6.415 c0.064,3.826-0.011,7.654,0.01,11.481c0.033,5.918,1.364,7.248,7.324,7.269c6.815,0.024,21.22,0.006,21.22,0.006v7.044 c0,0-14.435-0.017-21.108,0.005c-6.069,0.02-7.373,1.289-7.434,7.19c-0.028,2.682,0.18,5.38-0.039,8.044 c-0.443,5.389,0.07,10.039,6.912,10.524c-3.015,31.457-2.572,62.398,2.234,93.196c2.98,19.097,7.19,37.854,16.599,55.063 c1.443,2.639,2.397,5.924,2.406,8.914c0.209,63.543,0.251,127.087,0.325,190.631c0.002,1.795,0,3.59,0,5.442 c-5.238,0.679-7.397-1.369-7.347-5.986c0.035-3.185,0.024-6.371,0.006-9.557c-0.034-5.945-1.325-7.274-7.309-7.285 c-17.074-0.032-34.148-0.022-51.222-0.026c-11.718-0.003-23.435-0.029-35.153,0.013c-5.235,0.019-6.699,1.54-6.756,6.814 c-0.038,3.521-0.04,7.042,0.004,10.563c0.066,5.255,1.516,6.725,6.823,6.744c11.215,0.04,22.431,0.01,33.646,0.013 c11.868,0.003,11.868,0.005,11.75,11.912c-0.059,5.922-1.3,7.16-7.407,7.176c-12.22,0.031-24.439,0.018-36.659,0.029 c-7.054,0.006-8.155,1.08-8.167,7.935c-0.004,2.18-0.006,4.359,0.001,6.539c0.021,6.383,1.222,7.644,7.439,7.655 c11.048,0.02,22.096,0.002,33.144,0.006c11.791,0.005,11.791,0.008,11.648,12.012c-0.067,5.703-1.367,7.062-7.047,7.083 c-10.378,0.04-20.758,0.096-31.135-0.002c-15.122-0.144-14.146-0.478-14.047,14.132c0.038,5.646,1.377,6.992,7.074,7.008 c11.048,0.031,22.096,0.007,33.144,0.01c12.19,0.003,12.19,0.005,12.011,12.153c-0.083,5.597-1.413,6.924-7.187,6.944 c-10.211,0.034-20.423,0.089-30.633-0.001c-15.773-0.139-14.465-0.577-14.406,14.774c0.024,6.173,1.313,7.37,7.73,7.375 c13.726,0.011,27.452,0.005,41.179,0.003c14.898-0.002,29.796,0.018,44.694-0.027c5.339-0.016,6.767-1.487,6.831-6.742 c0.033-2.682-0.046-5.366,0.02-8.047c0.126-5.106,1.839-6.469,8.044-5.697c0,5.722-0.455,11.611,0.097,17.404 c1.078,11.308,2.634,22.631,8.667,32.623c3.709,6.143,9.563,5.816,12.753-0.612c2.984-6.015,5.833-12.625,6.409-19.174 c1.579-17.969,2.543-36.045,2.614-54.083c0.36-91.878,0.35-183.757,0.553-275.636c0.005-2.049,0.733-4.214,1.576-6.124 c3.369-7.639,7.748-14.934,10.257-22.833c11.421-35.946,13.433-72.997,11.755-110.391c-0.269-5.99-0.801-11.968-1.209-17.909 c7.452-1.534,7.775-1.945,7.779-9.588c0.001-2.515,0.011-5.03,0.007-7.545c-0.013-7.75-0.894-8.656-8.46-8.663 c-7.141-0.007-22.406-0.001-22.406-0.001v-7.045c0,0,16.742-0.048,24.561,0.019c4.359,0.038,6.392-2,6.312-6.351 c-0.071-3.855,0.016-7.712-0.019-11.568c-0.053-5.938-1.345-7.219-7.35-7.242c-7.485-0.029-22.504-0.007-22.504-0.007v-6.035 c0,0,15.454,0.033,22.967-0.011c5.362-0.031,6.803-1.454,6.876-6.683c0.049-3.52,0.028-7.042,0.018-10.563 c-0.019-6.708-1.157-7.881-7.7-7.895c-7.319-0.016-21.161-0.004-21.161-0.004v-28.963c0,0,51.319-18.506,51.418-58.803 c13.274,8.8,19.828,9.143,25.982,1.96c4.843-5.653,4.919-13.758,0.181-19.362c-6.121-7.24-12.687-6.904-26.259,1.909 c-5.709-30.27-22.672-50.541-52.587-59.137c0-11.198-0.038-22.249,0.053-33.298c0.01-1.247,0.394-2.826,1.206-3.677 c5.143-5.394,9.736-11.741,15.851-15.695c15.582-10.074,26.618-23.168,32.069-40.997c0.628-2.052,2.154-4.251,3.897-5.472 c12.064-8.448,22.297-18.658,30.858-30.639c1.235-1.728,3.009-3,5.027-3.661c25.276-8.284,41.218-25.241,47.865-51.029 c0.549-2.129,1.536-4.145,2.62-7.008c2.028,1.88,3.182,3.03,4.418,4.083c5.813,4.951,14.202,4.893,19.761-0.107 C369.847,192.788,370.428,183.388,364.919,177.185z M252.394,107.492c4.098,3.415,7.887,6.574,11.677,9.733 c-0.404,0.395-0.807,0.791-1.211,1.186c-4.169,0.785-8.338,1.57-13.15,2.476C250.666,116.112,251.516,111.872,252.394,107.492z M184.406,46c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54s-54-24.177-54-54C130.406,70.177,154.583,46,184.406,46z M162.373,165.581c14.357,4.18,28.096,4.578,42.513,0.199c-4.092,14.47-3.946,28.113,0.227,42.523 c-14.26-4.037-27.868-4.509-42.273-0.152C166.659,193.831,166.896,180.189,162.373,165.581z M115.827,107.593 c1.197,5.466,2.101,9.598,3.149,14.382c-4.547-0.964-8.521-1.806-13.675-2.899C108.835,115.221,111.958,111.814,115.827,107.593z M43.406,186c0-29.823,24.177-54,54-54s54,24.177,54,54c0,29.823-24.177,54-54,54S43.406,215.823,43.406,186z M115.278,265.909 c-3.402-3.626-6.248-6.661-9.67-10.309c4.662-1.06,8.192-1.862,12.324-2.801C117.071,257.051,116.27,261.011,115.278,265.909z M238.406,453c0,29.823-24.177,54-54,54s-54-24.177-54-54s24.177-54,54-54S238.406,423.177,238.406,453z M184.406,328 c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54C238.406,303.823,214.23,328,184.406,328z M251.958,267.927 c-1.167-5.669-2.154-10.46-3.262-15.84c5.154,0.97,9.935,1.87,14.716,2.77c0.446,0.541,0.892,1.082,1.338,1.623 C260.673,260.129,256.595,263.778,251.958,267.927z M271.406,240c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 c29.823,0,54,24.177,54,54C325.406,215.823,301.23,240,271.406,240z\",\n clocks: {\n size: 108,\n 0: { x: 184.245, y: 100 },\n 1: { x: 97.245, y: 186 },\n 2: { x: 271.245, y: 186 },\n 3: { x: 184.245, y: 274 },\n 4: { x: 184.245, y: 453 }\n }\n },\n 6: {\n height: 1148.98,\n width: 370.141,\n path: \"M365.84,176.489c-5.689-5.831-14.774-6.109-20.983-0.642c-4.677,4.118-4.976,4.085-6.414-2.269 c-6.187-27.333-22.732-44.97-49.412-53.347c-1.887-0.593-3.769-2.168-4.983-3.788c-8.33-11.115-18.008-20.785-29.318-28.894 c-1.84-1.32-3.239-3.825-3.948-6.065c-8.013-25.306-24.804-41.278-50.453-47.985c-1.299-0.34-2.628-0.562-3.93-0.89 c-6.029-1.519-6.346-2.456-2.44-7.102c5.378-6.396,4.93-15.201-1.065-20.921c-5.702-5.442-14.806-5.447-20.582-0.013 c-6.006,5.651-6.507,14.545-1.066,20.88c0.962,1.12,2.36,1.865,5.102,3.969c-3.997,1.969-6.466,3.647-9.192,4.455 c-21.058,6.239-37.094,18.816-44.941,39.357c-3.899,10.207-9.562,17.625-17.758,24.394c-6.646,5.489-11.704,12.883-17.615,19.294 c-1.38,1.497-3.203,3.002-5.097,3.546c-28.343,8.127-45.563,26.507-51.567,55.389c-0.195,0.941-0.595,1.84-1.211,3.697 c-4.56-5.357-9.738-8.928-16.367-7.261c-3.226,0.811-6.599,2.778-8.897,5.184c-5.104,5.343-4.779,13.776,0.038,19.336 c6.068,7.004,12.02,6.721,25.619-1.458c0.72,3.007,1.322,5.896,2.106,8.735c7.133,25.831,23.797,42.127,49.404,49.659 c2.498,0.735,4.874,2.61,6.784,4.488c8.593,8.445,17.053,17.028,25.427,25.692c1.767,1.828,3.636,4.007,4.323,6.356 c5.597,19.138,16.997,33.318,33.994,43.913c6.567,4.094,11.118,11.439,16.51,17.374c0.48,0.528,0.534,1.578,0.536,2.386 c0.033,10.743,0.022,21.486,0.022,30.697c-9.552,5.427-18.816,9.569-26.776,15.469c-12.547,9.299-19.949,22.422-23.771,37.578 c-0.68,2.698-2.102,5.208-3.473,8.506c-2.286-2.126-3.461-3.29-4.711-4.367c-6.067-5.231-15.003-4.872-20.573,0.801 c-5.603,5.707-5.839,14.698-0.54,20.569c5.565,6.166,14.515,6.88,20.866,1.665c5.112-4.197,5.412-3.946,8.069,2.516 c3.43,8.344,6.359,17.082,11.089,24.661c8.379,13.426,21.019,21.894,36.078,26.785c1.434,0.466,3.551,2,3.587,3.097 c0.294,8.853,0.165,17.72,0.165,27.124c-7.476,0-14.485-0.043-21.493,0.014c-5.306,0.044-6.687,1.494-6.735,6.878 c-0.033,3.697-0.03,7.394-0.004,11.091c0.042,5.943,1.284,7.157,7.436,7.185c6.702,0.031,13.405,0.007,20.448,0.007 c0,2.034,0,5.598,0,5.598s-13.784-0.034-20.783,0.011c-5.372,0.035-6.799,1.45-6.861,6.724c-0.047,4.026,0.044,8.054-0.023,12.079 c-0.072,4.325,1.898,6.385,6.299,6.345c6.876-0.063,13.753,0.049,20.629,0.113c0.289,0.003,1.739,0.534,1.739,0.534v6.407 c0,0-14.692-0.032-21.682,0.01c-5.652,0.034-7.334,1.395-6.872,7.119c0.694,8.601-1.289,15.249-8.006,21.638 c-8.605,8.185-13.036,19.34-15.463,31.089c-1.309,6.335-2.096,6.555-6.889,2.398c-6.287-5.453-15.195-5.103-20.871,0.819 c-5.657,5.902-5.624,15.003,0.076,20.896c5.702,5.895,14.51,6.153,20.855,0.613c1.117-0.975,2.238-1.945,4.238-3.682 c1.129,2.807,2.274,4.924,2.843,7.186c4.769,18.938,15.137,33.728,31.864,44.051c1.736,1.072,3.27,3.377,3.775,5.392 c3.397,13.548,7.363,26.834,14.685,38.904c0.804,1.325,1.03,3.177,1.033,4.786c0.118,64.926,0.18,129.852,0.239,194.778 c0.001,0.981-0.122,1.963-0.184,2.894c-5.249,0.709-6.974-0.588-7.13-5.358c-0.109-3.352-0.003-6.71-0.024-10.065 c-0.036-5.705-1.357-7.092-7.019-7.099c-21.978-0.026-43.956-0.012-65.933-0.011c-7.046,0-14.094,0.1-21.138-0.026 c-4.635-0.083-6.728,2.003-6.589,6.633c0.109,3.639,0.121,7.278-0.002,10.917c-0.157,4.646,1.947,6.703,6.575,6.67 c12.75-0.09,25.501-0.045,38.251-0.028c6.305,0.008,7.513,1.253,7.533,7.599c0.038,11.525,0.038,11.526-11.68,11.525 c-11.24-0.001-22.481-0.03-33.722,0.007c-5.418,0.018-6.914,1.437-6.931,6.666c-0.053,16.568-1.437,15.572,15.235,15.484 c10.066-0.053,20.132-0.038,30.198,0.002c5.373,0.021,6.796,1.457,6.905,6.697c0.259,12.419,0.259,12.42-12.268,12.419 c-11.073,0-22.146-0.028-33.218,0.011c-5.319,0.019-6.822,1.501-6.857,6.738c-0.102,15.018-1.068,14.544,14.31,14.408 c10.401-0.092,20.803-0.047,31.205-0.005c5.279,0.022,6.729,1.522,6.828,6.773c0.234,12.342,0.234,12.342-12.345,12.342 c-11.073,0-22.146-0.031-33.218,0.012c-5.25,0.02-6.76,1.539-6.779,6.814c-0.06,16.24-1.382,15.39,14.882,15.343 c26.004-0.075,52.009-0.015,78.013-0.024c6.592-0.002,7.763-1.211,7.767-7.876c0.001-2.349-0.056-4.699,0.01-7.046 c0.144-5.087,1.794-6.38,6.391-5.865c1.57,11.962,2.907,23.747,4.765,35.449c0.647,4.073,1.998,8.292,4.104,11.797 c1.828,3.041,5.159,7.119,7.859,7.143c2.656,0.024,6.805-4.019,7.763-7.073c3.09-9.85,6.148-19.959,7.106-30.167 c1.295-13.794,0.763-27.772,0.787-41.671c0.158-91.433,0.238-182.866,0.46-274.299c0.006-2.499,0.844-5.29,2.131-7.444 c7.151-11.972,11.314-25.021,14.283-38.502c0.767-3.483,2.275-5.895,5.318-7.958c14.472-9.809,23.801-23.321,28.184-40.279 c0.711-2.753,1.981-5.361,3.281-8.798c2.096,1.947,3.257,3.114,4.508,4.173c6.274,5.312,15.319,4.747,20.867-1.276 c5.371-5.83,5.28-14.718-0.209-20.541c-5.593-5.933-14.657-6.313-20.861-0.875c-4.91,4.304-5.502,4.183-6.871-2.32 c-2.843-13.501-9.129-25.091-18.636-35.051c-1.059-1.109-1.624-3.064-1.703-4.662c-0.225-4.519-0.177-9.058-0.049-13.584 c0.13-4.584-1.863-6.712-6.52-6.641c-7.688,0.117-23.46,0.032-23.46,0.032v-7.081c0,0,15.513,0.035,23.187-0.012 c5.264-0.032,6.699-1.51,6.757-6.834c0.042-3.858,0.047-7.718-0.001-11.576c-0.066-5.278-1.476-6.669-6.885-6.701 c-7.529-0.044-22.059-0.011-22.059-0.011v-6.073c0,0,14.421,0.036,22.088-0.012c5.373-0.034,6.792-1.451,6.855-6.73 c0.048-4.026-0.055-8.054,0.028-12.079c0.089-4.361-1.944-6.374-6.308-6.332c-7.707,0.073-23.662,0.021-23.662,0.021 s0-18.743,0-28.6c29.397-8.459,46.462-28.621,52.535-59.535c5.681,5.182,10.784,9.539,17.649,7.382 c3.324-1.045,6.767-3.214,9.025-5.845c4.929-5.744,3.921-14.326-1.559-19.637c-6.511-6.312-13.714-5.558-25.117,3.388 c-5.85-30.371-22.706-50.809-52.896-59.482c0-11.328-1.021-22.855,0.356-34.088c0.927-7.564,7.385-13.291,13.943-17.092 c17.546-10.17,29.776-24.263,35.419-43.925c0.495-1.726,2.182-3.403,3.745-4.482c12.023-8.304,22.113-18.494,30.667-30.315 c1.255-1.734,3.402-3.24,5.446-3.923c25.095-8.384,41.101-25.168,47.682-50.873c0.553-2.159,1.517-4.212,2.638-7.26 c1.992,1.814,3.143,2.911,4.345,3.949c6.307,5.446,15.194,5.081,20.928-0.844C371.579,191.607,371.538,182.33,365.84,176.489z M253.55,107.072c4.157,3.613,7.747,6.732,11.337,9.852c-0.326,0.501-0.652,1.003-0.979,1.504 c-4.182,0.798-8.365,1.596-13.163,2.512C251.718,116.132,252.577,111.882,253.55,107.072z M185.289,45.98c29.823,0,54,24.177,54,54 c0,29.823-24.177,54-54,54s-54-24.177-54-54C131.289,70.157,155.466,45.98,185.289,45.98z M164.151,165.773 c13.581,4.334,27.363,4.22,41.777,0.199c-4.474,14.48-3.87,28.139,0.027,42.429c-14.232-4.098-27.748-4.399-41.531-0.444 c0.777-7.312,2.093-14.066,2.044-20.809C166.419,180.244,165.032,173.349,164.151,165.773z M116.538,107.809 c1.209,5.322,2.145,9.436,3.252,14.311c-4.762-1.06-8.731-1.943-13.791-3.07C109.65,115.157,112.775,111.823,116.538,107.809z M98.289,239.98c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C152.289,215.804,128.113,239.98,98.289,239.98z M115.949,265.97c-3.407-3.594-6.205-6.546-9.77-10.308 c5.012-1.059,8.587-1.815,12.604-2.664C117.803,257.484,116.976,261.266,115.949,265.97z M239.289,683.98c0,29.823-24.177,54-54,54 s-54-24.177-54-54s24.177-54,54-54S239.289,654.157,239.289,683.98z M239.289,452.98c0,29.823-24.177,54-54,54s-54-24.177-54-54 s24.177-54,54-54S239.289,423.157,239.289,452.98z M185.289,327.98c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 s54,24.177,54,54C239.289,303.804,215.113,327.98,185.289,327.98z M253.079,268.69c-1.271-6.405-2.241-11.297-3.279-16.525 c5.356,1.047,10.057,1.966,16.634,3.251C261.644,260.177,257.764,264.034,253.079,268.69z M272.289,239.98 c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54c29.823,0,54,24.177,54,54C326.289,215.804,302.113,239.98,272.289,239.98z\",\n clocks: {\n size: 108,\n 0: { x: 185.128, y: 100 },\n 1: { x: 98.128, y: 186 },\n 2: { x: 272.128, y: 186 },\n 3: { x: 185.128, y: 274 },\n 4: { x: 185.128, y: 453 },\n 5: { x: 185.128, y: 684 }\n }\n }\n};\nconst SVGDATA = {\n teeth: {\n tall: {\n viewBox: \"0 0 512 1540\",\n paths: {\n frame: \"M0,0v1540l512-244.2V0H0z M451,1263.5l-390,186V61h390V1263.5z\",\n half: \"M0,0v748l512-244.2V0H0z\",\n full: \"M0,0v1540l512-244.2V0H0z\"\n }\n },\n med: {\n viewBox: \"0 0 512 1540\",\n paths: {\n frame: \"M0,0v1388l512-395.6V0H0z M458,965.7L54,1278V53h404V965.7z\",\n full: \"M0,0v1540l512-244.2V0H0z\"\n }\n },\n short: {\n viewBox: \"0 0 512 1540\",\n paths: {\n frame: \"M0,0v991l511.4-247L512,0H0z M470.5,715.2L41,922.6V40h430L470.5,715.2z\",\n full: \"M0,0v991l511.4-247L512,0H0z\"\n }\n }\n },\n armor: {\n viewBox: \"0 0 512 512\",\n paths: {\n heavy: \"M157.5,80.7c-20.6,13.7-46,22.5-69.4,26c6.8,48.9,26.1,84.1,46,97.8 c10.5,7.3,20.4,9,30.4,5.6c8.9-3.1,18.6-11,27.8-25.6C165.3,154.3,160.6,113.5,157.5,80.7L157.5,80.7z M354.5,80.8 c-3.1,32.8-7.8,73.6-34.7,103.8c9.1,14.6,18.9,22.5,27.8,25.6c10,3.4,19.8,1.7,30.4-5.6c19.8-13.7,39.1-48.8,45.9-97.7 C399.3,103.7,376,95.5,354.5,80.8L354.5,80.8z M254.4,67.9c-37.1,0-69.8,8.3-89.6,21c1.2,6.5,2.6,13,4.2,19.3 c19.2-8.2,50.3-16.7,85.4-16.7c35.2,0,66.3,8.5,85.4,16.7c1.7-6.3,3.1-12.8,4.2-19.3C324.2,76.2,291.5,67.9,254.4,67.9z M64.9,127.9l-47.7,45.5c29.8,37.2,63,56.8,86.5,58.7c1.1,0.1,2.3,0.1,3.3,0.2c1.8-7.6,4-15.1,6.5-22.3 C91.7,194.9,74.4,166.1,64.9,127.9L64.9,127.9z M447.1,127.9c-9.6,38.3-26.9,67-48.6,82c0,0-0.1,0-0.1,0.1 c2.5,7.3,4.7,14.7,6.5,22.3c1.1,0,2.2-0.1,3.4-0.2c23.4-1.9,56.8-21.5,86.5-58.7L447.1,127.9L447.1,127.9z M176,139.4 c5.7,12.2,13.1,23.3,22.9,32.8l6.4,6.2l-4.3,7.8c-2.3,4.1-4.6,8-7,11.7c40.8,15,85,14,124-0.2c-2.4-3.6-4.6-7.4-6.9-11.4l-4.3-7.8 l6.4-6.2c9.4-9.1,16.7-19.9,22.3-31.5C280.8,153.8,228.5,151.3,176,139.4L176,139.4z M401.7,243.6c0,0-3.7,38.1-22.9,76.1 l-121.7-32.7l-1.8-0.4l-1.8,0.4l-120.3,32.7c-19-38-22.7-76.1-22.7-76.1s12,3.8,19.5-18.7c10.7,3.2,22,3.3,32.8-0.4 c9.2-3.2,17.8-8.8,25.8-16.9c21.6,8.9,44.2,13.1,66.7,13.1c22.7,0,45.6-4.2,67.4-13.1c8,8,16.8,13.7,26.1,16.9 c10.9,3.7,22.3,3.6,33.1,0.4C389.6,247.4,401.7,243.6,401.7,243.6z M486.1,210.7c-25.4,24.2-52.1,38-76.2,40c-0.4,0-0.9,0-1.3,0.1 c1.2,8.1,2,16.2,2.3,24.4c22.8,3.8,54.7,0.1,90-14.3L486.1,210.7L486.1,210.7z M25.9,210.8l-14.8,50.1c35.3,14.4,67.2,18.1,90,14.3 c0.3-8.2,1.1-16.3,2.3-24.4c-0.4,0-0.9,0-1.3-0.1C78,248.7,51.3,234.9,25.9,210.8L25.9,210.8z M256,305.2l-114.8,28.1 c1.9,7.7,10.1,17.6,15.4,23.8c31.8-7.3,59.3-11.4,94.7-11.6c2.6,0,5.3,0,7.9,0c38.2,0.3,64.9,4.3,95.9,11.6 c5.1-6.2,15.2-15.8,16.8-23.6L256,305.2L256,305.2z M254.1,347.8l-79.3,22.1c5.8,4.8,16,8.5,23.2,13.3c18-5,33.5-7.8,53.5-7.9 c1.5,0,3,0,4.5,0c21.6,0.2,36.6,3,54.1,7.9c9.9-1.8,16.8-6.8,25.5-12.3L254.1,347.8L254.1,347.8z M373.3,377.7 c-68.3,55.6-166.9,55.7-235.3,0.3l-1.8,35.9c4.7,7.9,18.3,17,38,23c21,6.4,48,9.9,75.6,10.2c27.6,0.3,55.8-2.6,79.4-8.7 c21.6-5.6,39.3-14.2,48.8-23.9L373.3,377.7L373.3,377.7z\",\n light: \"M254.9,88c-23.1,0-44.1,2.8-59.8,8.8c-7.9,3-14.5,6.8-19.5,11.9c-5,5.1-8.4,12.1-8.4,19.9 c0,3.2,0.5,6.2,1.5,9.1c2,37.1-20.9,83.9-46,107.5c5.9,35.9,19.4,72.7,39.6,106.3c23.8,23,54.6,35.4,85.9,37.1v-24 c-9.6-0.1-19-0.5-26.5-1.1l0.8-13.2c7.1,0.6,16.2,1,25.7,1.1v-28.3c-9.1,0.4-17.9,1.8-24.4,4.2l-3.3-12.7 c8.1-2.9,17.8-4.6,27.7-5.1v-23.8c-2.9,0.2-5.8,0.5-8.7,1c-17.2,1-31.8,3.6-45.2,7.5l-0.1-0.2c16.7-14.8,38.1-22.2,59.6-22.2 c21.4,0,42.9,7.4,59.6,22.2l-0.1,0.1c-13.4-3.9-28.1-6.5-45.4-7.5c-2.8-0.5-5.7-0.8-8.5-1v23.8c10,0.5,19.7,2.1,27.7,5.1l-3.3,12.7 c-6.6-2.4-15.4-3.8-24.5-4.2v28.3c9.4-0.1,18.6-0.4,25.7-1.1l0.8,13.2c-7.5,0.7-16.9,1-26.5,1.1v24.1c32.4-0.8,64.6-13,89.4-36.5 c21.1-33.6,34.9-69.9,40.8-105.3c-26.2-23.2-50.7-72.5-47.8-110.7c0.7-2.5,1-5,1-7.7c0-7.8-3.4-14.8-8.4-19.9 c-5-5.1-11.7-8.9-19.6-11.9C298.9,90.8,278,88,254.9,88L254.9,88z M254.9,101.3c22.3,0,42.5,2.9,56.4,8.2c7,2.7,12.4,6,15.7,9.3 c3.3,3.4,4.5,6.3,4.5,9.9c0,1.8-0.3,3.6-1.1,5.5c-21.9-11.9-49.3-17.9-76.7-17.9c-26.6,0-53.2,5.6-74.7,16.8 c-0.5-1.5-0.7-2.9-0.7-4.4c0-3.5,1.2-6.5,4.5-9.9c3.3-3.4,8.7-6.7,15.7-9.3C212.4,104.1,232.6,101.3,254.9,101.3L254.9,101.3z M253.7,130c24.6,0,49.2,4.8,68.6,14.3c-3.1,2.6-6.9,5.1-11.4,7.3c-13.9,7-33.9,11.5-56,11.5s-42-4.5-56-11.5 c-4.9-2.4-9-5.2-12.2-8C205.8,134.5,229.7,130,253.7,130z M232.3,174.9c3.7,0.5,7.5,0.9,11.4,1.2c0.5,3.6,1,7.5,1.6,11.8 c1.6,13,3.3,27.9,3.3,37.5c0,10.8-3.5,20.6-9.5,28.1c-6.1,7.5-14.5,13-24.6,16.5c-11.2,3.9-24.5,5.6-39.3,4.8 c-14.2-2.5-25.1-9.3-35.7-19.6c29.1,8.3,54.5,8.2,71.9,2.1c8.7-3.1,15.4-7.6,19.7-13c4.3-5.4,6.5-11.4,6.5-18.9 c0-7.7-1.6-22.8-3.1-35.6C233.6,184.1,232.9,179,232.3,174.9L232.3,174.9z M275,175.2c-0.6,4-1.3,9-2,14.6 c-1.6,12.7-3.1,27.9-3.1,35.6c0,7.5,2.1,13.6,6.5,18.9c4.3,5.4,11,9.9,19.7,13c17.3,6.1,42.6,6.2,71.6-2.1 c-10.6,10.3-21.5,17.1-35.7,19.6c-14.8,0.8-28-0.9-39.1-4.8c-10.1-3.5-18.5-9-24.6-16.5s-9.5-17.3-9.5-28.1 c0-9.7,1.7-24.6,3.3-37.5c0.5-4.3,1.1-8.2,1.5-11.7C267.4,176,271.2,175.7,275,175.2L275,175.2z M347.1,370.2 c-52.9,43.1-129.3,43.2-182.3,0.3l-1.4,27.8c3.6,6.1,14.2,13.2,29.4,17.8c16.3,4.9,37.2,7.7,58.5,7.9c21.4,0.2,43.2-2,61.5-6.7 c16.8-4.3,30.4-11,37.8-18.5L347.1,370.2L347.1,370.2z\",\n special: \"M256,14.2c-65.6,98.3-131.1,90.2-196.7,106.5c0,262.3,65.6,327.8,196.7,377 c131.1-49.2,196.7-114.7,196.7-377C387.1,104.4,321.6,112.6,256,14.2z M256,47c5.1,0,9.2,4.1,9.2,9.2s-4.1,9.2-9.2,9.2 s-9.2-4.1-9.2-9.2S250.9,47,256,47z M70.6,138.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2s-4.1,9.2-9.2,9.2S70.6,143.3,70.6,138.2z M92.1,301.1c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2C101.3,296.9,97.2,301.1,92.1,301.1z M157.7,432.2 c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2C166.9,428.1,162.7,432.2,157.7,432.2z M256,483.4 c-5.1,0-9.2-4.1-9.2-9.2s4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2S261.1,483.4,256,483.4z M354.3,432.2c-5.1,0-9.2-4.1-9.2-9.2 c0-5.1,4.1-9.2,9.2-9.2c5.1,0,9.2,4.1,9.2,9.2C363.6,428.1,359.4,432.2,354.3,432.2z M314.4,426.7c-15.8,11.1-33.7,18.7-51.1,26.8 c-6.7,4.7-14-0.5-20.7-2.5c-44.7-18.3-86.5-49.8-107.6-94.5c-29.8-63.5-33.8-135-36.7-204.3c58.8-9,115.3-28.5,156.2-72.1l1.9-2.1 c4.5,5,9.3,9.8,14.2,14.5c35.8,36.3,85,47,133.9,57.8c2.8,1.2,6.8,0.5,9.1,2c-2.7,66.4-5.7,134.9-33.1,196.4 C367.3,380.9,343.2,407.7,314.4,426.7z M419.9,301.1c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2 C429.1,296.9,425,301.1,419.9,301.1z M432.2,147.4c-5.1,0-9.2-4.1-9.2-9.2s4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2 S437.3,147.4,432.2,147.4z M301.1,154.9c0.2,23.3,0.3,46.6,0.5,69.9c0,1,0.4,2.2,0.9,3.1c4.9,8.4,9.8,16.9,15,25.1 c1.6,2.6,0.8,5.1,0.6,7.6c-0.7,9.5-1.7,19-2.6,28.5c-1,10.5-2,21-3,31.6c-0.8,9-1.6,17.9-2.4,26.9c-0.8,9-1.7,17.9-2.5,26.9 c-0.7,7.3-1.3,14.6-2,22c-0.1,1.2-0.6,2.7-1.4,3.6c-12,12-24.1,23.9-36.2,35.9c-0.2,0.2-0.5,0.5-1.1,1c0-1.1,0-1.8,0-2.5 c0.1-66.5,0.3-133,0.5-199.5c0-1.5,0.8-3.2,1.7-4.4c2.2-2.9,2.8-6,2.8-9.6c0-28.5,0.1-57.1,0.2-85.6c0-0.7,0-1.5,0-2.5 c0.8,0,1.5-0.1,2.3-0.1c13.9,0.1,27.8,0.1,41.7,0.1c1.2,0,1.9,0.3,2.3,1.5c0.8,2.2,1.7,4.3,2.7,6.6c-6.2,3.9-12.2,7.6-18.2,11.3 C301.6,152.6,301.1,153.4,301.1,154.9z M245.2,433.7c0,0.9,0,1.7,0,2.6c-0.2,0.1-0.4,0.2-0.6,0.3c-1.4-1.5-2.8-3.1-4.3-4.5 c-10.7-10.6-21.5-21.2-32.2-31.9c-0.9-0.9-1.6-2.5-1.7-3.9c-1-9.2-1.8-18.4-2.6-27.5c-0.7-7.2-1.3-14.3-2-21.5 c-0.8-9.2-1.7-18.4-2.6-27.5c-0.7-7.1-1.3-14.2-1.9-21.3c-0.9-9.3-1.7-18.5-2.6-27.8c-0.5-4.9-1-9.9-1.3-14.8 c-0.1-0.7,0.4-1.6,0.8-2.2c5.1-8.6,10.2-17.1,15.2-25.7c0.5-0.9,0.9-2.1,0.9-3.1c0.2-23.2,0.3-46.4,0.5-69.6c0-1.6-0.5-2.5-1.9-3.4 c-6-3.6-11.9-7.3-18-11.2c1-2.5,2-4.9,3.1-7.4c0.2-0.3,0.8-0.6,1.2-0.6c14.6-0.1,29.3-0.1,43.9-0.1c0.1,0,0.3,0.1,0.6,0.3 c0,0.7,0.1,1.5,0.1,2.3c0.1,29.2,0.2,58.4,0.3,87.7c0,2.1,0.3,4,1.7,5.6c2.5,2.9,3,6.2,3,10C244.9,303.4,245.1,368.5,245.2,433.7z\",\n specialBg: \"M316.9,432.4c-16.5,11.6-35,19.4-53.1,27.8c-7,4.9-14.6-0.5-21.6-2.6 c-46.5-19-90-51.8-111.9-98.3c-31-66.1-35.1-140.5-38.2-212.4c61.2-9.4,119.9-29.6,162.4-75l2-2.1c4.7,5.2,9.6,10.2,14.7,15.1 c37.2,37.7,88.4,48.9,139.2,60.1c2.9,1.3,7.1,0.5,9.4,2.1c-2.9,69.1-5.9,140.3-34.4,204.3C372,384.8,346.8,412.7,316.9,432.4z\"\n }\n },\n [ConsequenceType.ReducedEffect]: {\n viewBox: \"0 0 512 512\",\n paths: {\n main: \"M260.7,487.55C133,487.55,28.39,382.92,28.39,255.23S133,24.45,260.7,24.45A230.5,230.5,0,0,1,491.49,255.23c0,127.69-103.1,232.32-230.78,232.32Zm-1.06-82L377,287.58l-23.94-25.1-65.41,37.94V128a167.28,167.28,0,0,1,103.6,268.91,193.71,193.71,0,0,0,61.22-141.63A191.18,191.18,0,0,0,260.7,63.45c-106.39,0-193.31,85.39-193.31,191.78A192.9,192.9,0,0,0,128,395.55,167.3,167.3,0,0,1,231,128.2V296.92l-62.5-35.62-25.09,26.28Z\"\n },\n classes: {\n main: \"fill-linear\"\n }\n },\n [ConsequenceType.ComplicationMinor]: {\n viewBox: \"0 0 512 512\",\n paths: {\n main: \"M345.58,263.18l39.74-8.31,73.29-15.3,22.83-4.79,2.81-.58,9.56-2V213.1l-6.33,1.33-79.55,16.62-26.49,5.54-55.93,11.69c-13-11.18-20-24.73-27.16-39.89l-1.67-3.53,34.18-46.76,57.87-79.18,3-4.1,41.19-56.33H409.77L375.26,65.7l-4.09,5.59-60.51,82.78-32.91,45c-15.06-6.36-26.14-17.76-38.57-30.33l-2.34-2.37-4.59-30.28L216.72,33.5l-1-6.47-1.29-8.54h-18.9l2.84,18.75-.11-4.41,15.2,104.1,5.59,37c-11.18,7.5-24.44,12.15-39,15.49l-22.9-28.89L93.8,80.58,44.58,18.49H20.74l53,66.83,4.18,5.26,66.54,84,19.15,24.16-.08.7c-1.93,17.37-8.88,29.63-16.65,43.07L115.3,234.2,25.49,210.61,23.08,210l-4.31-1.14v19.32l2.56.67L112,252.65l27.61,7.25.56,1.4c6.1,15.15,5.39,31.77,2.9,49.71l-30.31,14.2L23.15,367.14l-4.38,2.06v20.62l9.18-4.3,67.92-31.77,17.13-8,28.92-13.54,1.52,1.53c5.85,5.86,10,10.29,11.22,20.75l-31.14,31.3L56.27,453.39l-37.5,37.69v2.43h24l20.91-21h0l77.94-78.36,24.11-24.24,1-.23c23.75-5.79,59.86-6.75,80.11-6.78,4,0,6.81,0,9.35.08l10.4,32.29L293,477.73l1.54,4.78,3.54,11h19.63l-5.19-16.14-2.24-6.95-25.77-80.06-11-34.32c3.55-3.17,8.73-7.63,15-12.42,11.42-8.73,26.21-17.7,35.68-19.62l4.24-.87,25.37,10L442,368.08l4.18,1.66,47.6,18.83V368.48l-37.78-15-5.21-2-82.75-32.74-36.59-14.48c0-13.16,1.4-22.85,9.12-33.93Zm-61.35-41.29c5.12,10.41,11.11,21.1,19.66,30.91l-31.15,6.52a39.69,39.69,0,0,0-6.93-12.22Zm-62.13-28,6,39.74a39.25,39.25,0,0,0-10.25,3.48l-25.18-31.77A132,132,0,0,0,222.1,193.9Zm-43.39,23.92,24.91,31.43a38.6,38.6,0,0,0-4.08,7.07l-33.92-8.92C170.58,238.65,175.45,229.15,178.71,217.82Zm17.49,56.93a39.32,39.32,0,0,0,2.08,10.45L163,301.7c1.05-11.91.92-24.05-2-36.2ZM160,324.27l.09-.55,47.15-22.07h0L169.55,339.5A54.79,54.79,0,0,0,160,324.27Zm28.37,22.85,36.61-36.8a39.43,39.43,0,0,0,10.6,1.45,35.54,35.54,0,0,0,4-.2L250,344.11C236.7,344,212.41,344.2,188.33,347.12ZM250.78,236a35.39,35.39,0,0,0-3.61-1.32L241.46,197a109.45,109.45,0,0,0,25.15,17.38Zm26.37,92.76c-3.9,3-7.1,5.61-9.88,8l-10.1-31.4a39.81,39.81,0,0,0,8.16-7.16l36.5,14.44A169,169,0,0,0,277.15,328.76Zm36-31.76L273.9,281.47c.26-1.14.47-2.29.64-3.44l45.58-9.53C315.5,277.93,313.74,287.39,313.17,297Z\"\n },\n classes: {\n main: \"fill-radial\"\n }\n },\n [ConsequenceType.ComplicationMajor]: {\n viewBox: \"0 0 512 512\",\n paths: {\n main: \"M458.26,239.57l22.83-4.78,2.81-.59,9.56-2v-19.1l-6.33,1.33-79.55,16.62-26.49,5.54-55.93,11.69c-13-11.18-20-24.73-27.16-39.89l-1.67-3.53,34.18-46.76.58-.79c9.76,28.37,24.84,58.48,51.36,78.35l24.6-5,1.83-.54L407.07,229c-37.27-19.15-50.45-51.64-61.94-88.83l-.44-1.43,43.69-59.78,3-4.1,41.19-56.34H409.42L374.91,65.7l-4.09,5.6-46.71,63.9c-34.73.23-70.42-3-95.76-22.5l-12-79.19-1-6.47-1.29-8.55H195.2L198,37.24l-.11-4.4,12.18,83.44c-17,16.89-39.15,28.73-67.39,26.48L93.45,80.59,44.23,18.49H20.39l53,66.83,4.18,5.27L129,155.51c-3.16,27.24-16.63,53.33-32.88,73.74l-71-18.63L22.73,210l-4.31-1.13v19.32l2.56.67,71.38,18.74c8.29,26.73,6.3,57.28,2.12,86L22.8,367.15l-4.38,2.05v20.63l9.18-4.3,67.92-31.78,1.09-.51A190.52,190.52,0,0,1,104.47,382c1.33,7.25,2.58,14.68,3.19,19.36l-51.74,52-37.5,37.69v2.43H42.37l20.91-21h0l58.27-58.57c10.1-.83,33.7-2.28,59.06-3.17,7.9-.28,16.15-.45,24.46-.47,23.47-.05,49.4,1.12,67.34,4.45l20.27,63,1.54,4.79,3.54,11h19.63l-5.19-16.14L310,470.43,291.2,412.17c23.43-27.05,48.62-54.87,86-69.58l64.45,25.5,4.18,1.65,47.6,18.84v-20.1l-37.78-15-5.21-2.06-62.74-24.82c-3.11-24.21,8.64-50.64,20.2-76.57ZM266.92,336.72l-10.1-31.4a39.76,39.76,0,0,0,8.16-7.15l36.5,14.44a169,169,0,0,0-24.68,16.16C272.9,331.76,269.7,334.38,266.92,336.72Zm-71.07-62a39.17,39.17,0,0,0,2.08,10.44l-35.27,16.5c1.05-11.9.92-24-2-36.19Zm-30.58-27.35c5-8.75,9.83-18.25,13.09-29.59l24.91,31.43a39.28,39.28,0,0,0-4.08,7.07Zm41.58,54.25h0L169.2,339.51a54.79,54.79,0,0,0-9.59-15.23l.09-.56Zm17.74,8.67a39.43,39.43,0,0,0,10.6,1.45,38,38,0,0,0,4-.2l10.47,32.54c-13.32-.16-37.61.08-61.69,3Zm22.23-75.64L241.11,197a109.17,109.17,0,0,0,25.15,17.39L250.43,236A37.88,37.88,0,0,0,246.82,234.69Zm26.73,46.78c.26-1.13.47-2.28.64-3.43l45.58-9.53c-4.62,9.43-6.38,18.89-6.95,28.5Zm30-28.66-31.15,6.51a39.53,39.53,0,0,0-6.93-12.21l18.42-25.21C289,232.31,295,243,303.54,252.81ZM232.78,136.13c23.18,13.26,50.47,17.92,77,18.68l-32.37,44.3c-15.06-6.37-26.14-17.76-38.57-30.33l-2.34-2.37-4.59-30.28,0-.12Zm-5,97.52a39.25,39.25,0,0,0-10.25,3.48l-25.18-31.77a132,132,0,0,0,29.42-11.45Zm-14.52-96,5.48,36.25c-11.18,7.5-24.44,12.15-39.05,15.49l-22.46-28.34C178.25,159.21,198.58,149.44,213.24,137.65Zm-69.67,36.28.5.63,19.15,24.15-.08.71c-1.93,17.37-8.88,29.63-16.65,43.06L115,234.2l-.07,0C127,217.56,138.38,195.1,143.57,173.93ZM123.4,385.56c-.42-2.17-1.06-4.9-1.43-6.92-1.84-10-4.7-23.39-8.85-33.12l28.45-13.32,1.52,1.53c5.85,5.87,10,10.3,11.22,20.75Zm15.89-125.65.56,1.4c6.1,15.14,5.39,31.77,2.9,49.71l-29,13.58c2.87-22.76,3.42-48.28-2.06-71.93h0Zm72.18,131.64h-6.55c-8.5.05-16.9.25-25,.53-15.57.55-28,1.33-37.85,2.07l.07-.07a7.94,7.94,0,0,1-.82-.06l24-24.11,1-.23c23.75-5.79,59.86-6.75,80.11-6.78,4,0,6.81,0,9.35.07l10.29,32C249.77,392.55,229.58,391.66,211.47,391.55Zm73.59-1.18-.71.53-.17-.53-11-34.32c3.55-3.17,8.73-7.63,15-12.42,11.42-8.73,26.21-17.7,35.68-19.63l4.24-.86,25.37,10C324.89,348,303.58,369.47,285.06,390.37ZM368.49,319l-.77-.31-36.59-14.48c0-13.15,1.4-22.84,9.12-33.92l5-7.14L385,254.88l.12,0C376.44,274.07,368.18,297,368.49,319Z\"\n },\n classes: {\n main: \"fill-radial\"\n }\n },\n [ConsequenceType.ComplicationSerious]: {\n viewBox: \"0 0 512 512\",\n paths: {\n main: \"M21.42,17.34,78.56,89.45c-2.73,48.59-23.75,85.79-52.39,120l-6.72-1.76V227l2.56.67C37.36,272.78,31.1,318.54,23.83,366l-4.38,2.05v20.63l9.18-4.29c6.52,10.7,13.66,27,19.06,41.33,4.29,11.33,7.48,21,9.26,26.53l-37.5,37.69v2.43h24L72,463.67c9.27-.36,41.77-1.47,82.7-.75,46.74.83,102.61,4.3,139,13.67l5.08,15.78h19.63L311,469.28c35.94-41.51,71.91-80.52,131.73-102.34l51.78,20.49v-20.1l-43-17c-6.37-39.21,12.76-76.67,30.62-116.68l12.37-2.59V212l-6.33,1.32-5.45-2.8c-56.09-28.83-76.33-78-93.3-132.7L433.6,17.34H410.45l-38.6,52.81c-58.28,1.26-112.48-2.46-154.45-37.79l-2.27-15h-18.9l2.83,18.75c-27.13,29-57.56,48-104.58,43.36L45.26,17.34Zm199.92,41c40.6,26.3,88.49,30.89,136.75,30.63L325,134.32c-36.59.39-69.86-3-95.85-24.64l-7.76-51.33Zm-18.84.44,8.29,54.77c-17.81,18.62-37.29,30.18-68,26.86L109.72,98.68c38.59-.74,68.36-17.15,92.78-39.89ZM375.83,96.38c15.53,47,37.05,92.69,84.55,122.72l-51.77,10.82-.82-.42c-37.27-19.14-50.44-51.64-61.93-88.83l-.72-2.31,30.68-42ZM95.09,110.3l34.39,43.39c-2.52,29.59-15.41,52.66-33.14,74.21L45.93,214.67c23.72-29.78,42.64-63.39,49.16-104.37ZM232.93,135c23.94,13.69,51.05,17.4,78.41,17.94l-32.91,45c-15.06-6.36-26.14-17.75-38.57-30.32l-2.35-2.37L232.93,135Zm-18.77.81,5.59,36.95c-11.18,7.5-24.44,12.15-39.05,15.49l-22.9-28.89c22.71-1.4,41.09-10.68,56.36-23.55ZM331.54,157c9.74,29.15,23.14,58,50.58,78.49l-55.93,11.69c-13-11.18-20-24.74-27.16-39.89l-1.67-3.53ZM145.1,173.41l19.15,24.16-.08.71c-1.93,17.36-8.88,29.63-16.65,43.06L116,233.06c13.21-17.36,23.94-36.83,29.12-59.65Zm77.68,19.35,6,39.75A38.88,38.88,0,0,0,218.54,236l-25.18-31.77a132.49,132.49,0,0,0,29.42-11.45Zm19.36,3.05a109.17,109.17,0,0,0,25.15,17.39l-15.83,21.66c-1.18-.49-2.38-.94-3.61-1.32l-5.71-37.73Zm-62.75,20.86L204.3,248.1a39.37,39.37,0,0,0-4.08,7.07l-33.92-8.9c5-8.76,9.83-18.25,13.09-29.6Zm105.52,4.08c5.12,10.42,11.11,21.1,19.66,30.92l-31.15,6.5A39.64,39.64,0,0,0,266.49,246l18.42-25.21ZM43.14,233.26,92,246.09c9.23,28.21,5.8,57.08,1.2,87.45l-49.07,23c6-40.15,10.29-81.42-1-123.24Zm416.14,5.16c-14.93,32.63-30.11,66.73-27.43,104.13l-43.74-17.31c-3.6-25,8.78-49.44,20.72-76.28l50.45-10.54Zm-346.57,13.1,27.61,7.25.56,1.4c6.1,15.13,5.39,31.77,2.9,49.71l-30.32,14.18c3.22-23.51,5-47.81-.75-72.54ZM386,253.74c-9,19.81-17.8,40.8-17.25,63.84l-36.59-14.47c0-13.15,1.4-22.84,9.12-33.92l5-7.15,39.74-8.3ZM161.64,264.36l35.24,9.26A39.33,39.33,0,0,0,199,284.06l-35.27,16.5c1.05-11.9.92-24.05-2.05-36.2Zm159.16,3c-4.62,9.44-6.38,18.89-6.95,28.5l-39.27-15.54c.26-1.12.47-2.27.64-3.43l45.58-9.53ZM266,297l36.5,14.44a169,169,0,0,0-24.68,16.16c-3.9,3-7.1,5.6-9.88,7.94l-10.11-31.4A39.76,39.76,0,0,0,266,297Zm-58.12,3.48-37.66,37.86a54.85,54.85,0,0,0-9.59-15.24l.09-.55,47.15-22.07Zm17.73,8.67a39.43,39.43,0,0,0,10.6,1.46c1.35,0,2.69-.07,4-.2L250.7,343c-13.32-.16-37.62.07-61.7,3l36.61-36.81ZM329.1,322l25.36,10c-29.4,14.92-50.37,35.89-69.25,57.2l-11-34.32c3.55-3.18,8.73-7.63,15-12.43,11.42-8.73,26.21-17.7,35.68-19.63l4.24-.86Zm-186.5,9.07,1.52,1.52c5.85,5.88,10,10.31,11.22,20.75L124.2,384.64c-.35-2.27-.74-4.63-1.2-7.14-2-10.95-4.45-22.94-9.32-32.9l28.92-13.54Zm235.93,10.49,39.22,15.52c-49.42,22.5-82.92,56.68-113.45,91.47l-12.44-38.65c24.11-27.84,47.68-53.61,86.67-68.34Zm-282,11.06c3,6.84,6.22,18.17,8.07,28.26,1.58,8.61,2.5,16.08,3,20.45L71.72,437.4c-1.68-5-3.78-11-6.55-18.29-5.37-14.22-12-30-19.61-42.64l51-23.86Zm150.86,9.15c4,0,6.81,0,9.35.06l10.39,32.3c-26.25-4.15-58.63-4.19-87-3.18-15.58.55-28,1.32-37.86,2.06l24.11-24.24,1-.23C191,362.74,227.16,361.79,247.41,361.76Zm-42.19,47.39c24.92-.06,50.36,1.26,68.41,5.1L287.06,456c-38.71-8.23-89-11-132.09-11.74-27.22-.48-49.23-.19-63.87.17l30.8-31c7.77-.76,30.71-2.84,58.86-3.84,7.9-.28,16.15-.45,24.46-.47Z\"\n },\n classes: {\n main: \"fill-radial\"\n }\n },\n [ConsequenceType.LostOpportunity]: {\n viewBox: \"0 0 512 512\",\n paths: {\n main: \"M373.33,52.76A234.57,234.57,0,0,0,52.77,138.67C-12,250.93,26.41,394.41,138.67,459.23s255.75,26.36,320.56-85.91S485.59,117.58,373.33,52.76Zm-211.87,367A189.1,189.1,0,0,1,81,184.37L327.62,431A188.73,188.73,0,0,1,161.46,419.76Zm211.18-14.87L107.14,139.38a187.3,187.3,0,0,1,32.24-32.29L404.89,372.6A187.71,187.71,0,0,1,372.64,404.89ZM431,327.6,184.41,81A189.12,189.12,0,0,1,431,327.6Z\"\n },\n classes: {\n main: \"fill-linear\"\n }\n },\n [ConsequenceType.WorsePosition]: {\n viewBox: \"0 0 512 512\",\n paths: {\n horizon: \"M18.36,227.8v18.68h86.37a98.45,98.45,0,0,0-4.43-18.68Zm379.4,0a110.51,110.51,0,0,1,9.44,18.68h86.44V227.8H397.76Z\",\n boot: \"M218.67,18.73a162.14,162.14,0,0,0-20,1.32C164,24.39,123.5,39.4,91.23,67.36L124.7,257.55l.35,10.12c42.26,15.79,100.82,24.55,152.87,24.25,27.19-.15,52.64-2.74,73-7.78s35.2-12.82,41.81-20.94l.44.35a113,113,0,0,0-6.53-17.06h.19a95.88,95.88,0,0,0-4.85-8.66c-.09-.14-.16-.3-.25-.44l-.31-.47c-21.46-34.89-63.5-55.87-124.28-29.37l-.16.06a215.37,215.37,0,0,0-34,20.19h-.81c11-15.72,23.26-28.12,35.91-37.28l1.12-11.16c-14.68-4-38.08-4.06-53.53-.09L201,161.14a130.33,130.33,0,0,1,30.34-3.84c1.5,0,3,0,4.5,0a117.66,117.66,0,0,1,25.25,3.12l3.19-32c-21.06-8.07-42.12-6.6-64.57-1.59l-4.06-18.25A170.07,170.07,0,0,1,231,104.17c1.72,0,3.44,0,5.16.07a107,107,0,0,1,30.06,5.12l3.16-31.47c-25.6-7.69-51-8.1-76.91-2.78l-3.78-18.28A188.53,188.53,0,0,1,221.52,53c1.14,0,2.29-.05,3.43-.06A167.36,167.36,0,0,1,271.23,59l.47-4.6c5-23.31-18.75-35.71-53-35.65ZM397.26,284.45c-10.84,8.13-25.26,13.7-41.87,17.82-22.37,5.54-49.07,8.18-77.38,8.34a526.46,526.46,0,0,1-65.09-3.75L225.36,329c80.16,9.44,141.5-1.19,172-21.78a113.13,113.13,0,0,0-.13-22.75ZM125.7,287.77l1,30.47,58.6,8.43,9.59-22.31c-24.55-3.82-48.21-9.37-69.19-16.59Z\",\n ice: \"M92.61,309.3C82.3,312.37,74,315.76,68,319.36l-.21.12L37.58,334.2,18.36,322v22.16L32,352.8l4.41,2.81,4.72-2.31,22-10.72c11.71,9.8,40.46,18.23,79.4,23.87l-60,28.25,26.63,21L18.36,454.23v39H145.14L188.86,447l51,46.28h27.84L159.11,394.8l35.06-23c20,1.37,41.34,2.15,63.56,2.15,20.7,0,40.66-.67,59.44-1.87l39.06,24.69-66.9,35.71,62.28,60.75H475.52L385,440.64l51.32-39.78-71.5-33.28c45.88-6,79.18-15.67,89.81-27l18,6.43,21.06,22.57V342.17l-8.94-9.56L483.17,331l-2.15-.78L439.8,315.42a141.57,141.57,0,0,0-16.66-6c5.37,3.24,8.28,6.7,8.28,10.28,0,18.59-77.73,33.66-173.62,33.66S84.14,338.29,84.14,319.7c0-3.63,3-7.13,8.47-10.4Z\"\n },\n classes: {\n horizon: \"fill-dark\",\n boot: \"fill-bright\",\n ice: \"fill-radial\"\n }\n },\n [ConsequenceType.InsightHarm1]: {\n viewBox: \"0 0 512 512\",\n paths: {\n eye: \"M406.09,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,409.07,204h45.2C435.64,222.23,417,244.72,406.09,282.69ZM494.83,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-89-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,82.64,223.9C74.76,216.85,66,208.81,57.89,200c-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C241.41-14.68,416.3,37.68,494.83,158.8Zm-29.17-.36C373.78,11.86,140.41,12.08,57.19,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C324.81,246.14,397.81,215.94,465.66,158.44Z\",\n iris: \"M303.7,99.51a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Zm45.4-68.13a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Zm45.4-68.13a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Z\"\n },\n classes: {\n eye: \"fill-dark\",\n iris: \"fill-med\"\n }\n },\n [ConsequenceType.InsightHarm2]: {\n viewBox: \"0 0 512 512\",\n paths: {\n eye: \"M305.51,89.71A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Zm54.8-82.26A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Zm54.8-82.26A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Z\",\n iris: \"M398.59,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,401.57,204h45.2C428.14,222.23,409.46,244.72,398.59,282.69Zm-264-17.94A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86,11.79,18.34,22,39.48,27.42,60.27v50c-4.76,10.14-12.06,17.21-12.06,28.41,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-11.36-7.31-17.81-11.87-27V278.22C103,265.1,117.78,261.12,134.61,264.75ZM487.33,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-88.95-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C233.91-14.68,408.8,37.68,487.33,158.8Zm-29.17-.36C366.28,11.86,132.91,12.08,49.69,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C317.31,246.14,390.31,215.94,458.16,158.44Z\"\n },\n classes: {\n eye: \"fill-med\",\n iris: \"fill-med\"\n }\n },\n [ConsequenceType.InsightHarm3]: {\n viewBox: \"0 0 512 512\",\n paths: {\n eye: \"M398.31,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,401.29,204h45.2C427.86,222.23,409.18,244.72,398.31,282.69Zm-264-17.94A239.65,239.65,0,0,1,74.86,223.9C67,216.85,58.19,208.81,50.11,200c11.79,18.34,22,39.48,27.42,60.27v50c-4.76,10.14-12.06,17.21-12.06,28.41,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-11.36-7.31-17.81-11.87-27V278.22C102.75,265.1,117.5,261.12,134.33,264.75Zm114.3,24.56a256.33,256.33,0,0,1-88.95-14,109.79,109.79,0,0,1,42.38,48.58v80.59c-6.36,10.47-13.62,16.95-13.62,28.87,0,17.89,11.76,24.5,23.93,24.5,11.91,0,21.6-5.66,21.6-24.5,0-9.3-7.44-16.63-13.22-31.06V324.1C227.16,309.18,237.5,294.45,248.63,289.31ZM487.05,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-88.95-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,74.86,223.9C67,216.85,58.19,208.81,50.11,200c-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C233.63-14.68,408.52,37.68,487.05,158.8Zm-29.17-.36C366,11.86,132.63,12.08,49.41,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C317,246.14,390,215.94,457.88,158.44Z\",\n iris: \"M314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25ZM314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25ZM314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25Z\"\n },\n classes: {\n eye: \"fill-med\",\n iris: \"fill-bright\"\n }\n },\n [ConsequenceType.InsightHarm4]: {\n viewBox: \"0 0 512 512\",\n paths: {\n eye: \"M244,27.44c-46.86,0-93.53,12.25-134.7,39.08-36,22.91-64.47,54.55-84.66,92.29,4.06,14.72,14.18,28.71,25.72,41.23,8.08,8.77,16.87,16.81,24.75,23.86a239.65,239.65,0,0,0,59.47,40.85A239,239,0,0,0,160,275.27a256.33,256.33,0,0,0,88.95,14q7.22-.1,14.42-.62a291.28,291.28,0,0,0,90-21.07A299.94,299.94,0,0,0,430.12,222a286.46,286.46,0,0,0,57.21-63.16C434.75,77.71,339,27.44,244,27.44ZM245.4,245.9h-.22c-48.05-.19-95.61-14-140.82-42.29a353,353,0,0,1-54.67-42.55l.46-.39-.46-.39c83.22-148.2,316.59-148.42,408.47-1.84C390.31,215.94,317.31,246.14,245.4,245.9Zm17.93,42.79c7.16,3,14.11,11.57,20,28.08,3.54,9.85,6.71,22.54,9.33,38.58v74.84C287.27,440.69,281,449.64,281,462.5s10,22.19,21,22.19c10.74,0,22.18-9.73,22.18-23.34,0-14.45-7.09-23.42-12.81-34.57V342.22h-.22a223.26,223.26,0,0,1,7.48-25.45c9.57-26.37,22.57-44.47,34.73-48.86v-.29A291.28,291.28,0,0,1,263.33,288.69Zm-38.82,28.08c6.37-12.19,15.11-23.17,24.4-27.46a256.33,256.33,0,0,1-88.95-14,109.62,109.62,0,0,1,38.91,41.5q1.84,3.45,3.47,7.08v80.59c-6.36,10.47-13.62,16.95-13.62,28.87,0,17.89,11.76,24.5,23.93,24.5,11.91,0,21.6-5.66,21.6-24.5,0-9.3-7.44-16.63-13.22-31.06V324.1C222.09,321.64,223.26,319.18,224.51,316.77Zm-89.9-52A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86,11.79,18.34,22,39.48,27.42,60.27v50c-1.08,2.29-2.28,4.43-3.51,6.49-4.18,7.06-8.55,13.25-8.55,21.92,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-8.63-4.22-14.43-8.25-20.76a67,67,0,0,1-3.62-6.27V278.22C103,265.1,117.78,261.12,134.61,264.75Zm267-60.78a401.64,401.64,0,0,1-48.21,22.27v41.67c10.32-3.73,20,2.4,26.54,21.72v59.78c-4.46,8.95-9.56,17.37-9.56,29.59,0,13.94,9.56,23.94,18.69,23.94,9.34,0,18.09-9.54,18.09-22.78,0-10.83-4.34-19-8.53-27.56V282.69c7.59-26.52,19-45.48,31.53-60.73a225.7,225.7,0,0,1,16.65-18Z\",\n iris: \"M326.5,67.65a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Zm76-114.06a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Zm76-114.06a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Z\"\n },\n classes: {\n eye: \"fill-bright\",\n iris: \"fill-med\"\n }\n },\n [ConsequenceType.ProwessHarm1]: {\n viewBox: \"0 0 512 512\",\n paths: {\n scar: \"M443.44,434.53Q408.7,409.87,376,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L237.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L167.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q91.79,90.29,68.44,58.49q43,32.32,83.86,67.06L188.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L266,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L319.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q412.66,394.28,443.44,434.53Z\"\n },\n classes: {\n scar: \"fill-dark\"\n }\n },\n [ConsequenceType.ProwessHarm2]: {\n viewBox: \"0 0 512 512\",\n paths: {\n scarTissue: \"M399,355.08c-15-32.31-18.67-65.87-6.23-94.7-47.19,58.41-76.14,4.41-4.09-70.72-101.67,62.7-147.78,31.47-14-88.26-103,54.66-182.49,69.22-130.93,15.19-37.19,10.63-58.21,5.21-76-2.43A643.42,643.42,0,0,0,55.28,58.49a789.14,789.14,0,0,0,47,77.56c7,18.27,3,38.71-31.46,63.44,124.85-33.45,88.52,47-9.36,104.92,166.21-61.68,207.52-47.41,100.64,78,84-61.07,150.14-44.57,122.89,31.29,31.63-24.51,57.9-29.74,78-20.87q43.39,30.7,90.32,59C436.25,418.27,418.25,386,399,355.08ZM352.11,362c-16.61-9.9-26.17.25-36.79,14,7.32-15.11,11.12-30.72,2.69-42.28l-3.7-3.19L277,301.11l-39.68,22,14.29-21.06c6.08-10.31,2.85-22.58-4.7-34.2q-13.6-13.56-26.78-27.46c-1.38-1-2.75-2-4.11-2.91l-55.23,15.68,18.09-21.41c8.78-14.64,0-34.57-8.18-46.3q-7-8.15-13.82-16.42l-36.3,6.06c15.32-6.06,26.08-18.6,14-33.28l-1.89-2.13c.69.72,1.31,1.42,1.89,2.13l1.71,1.94q-20.43-25.65-39.84-52.09,35.76,26.88,69.71,55.75l30.44-7.93-18.38,18.27q19.44,16.88,38.31,34.41l59.73-25.32L260.68,191l.25-.2c-17.91,22.9,15.6,71.52,38.24,65.19l26.52-14.71-20.6,30.37,30.65,43.82.66.74c11.34,10.39,26,1.42,35.79-12.07L355.9,339q26.72,31.78,52.3,65.24Q379.31,383.76,352.11,362Z\"\n },\n classes: {\n scarTissue: \"fill-med\"\n }\n },\n [ConsequenceType.ProwessHarm3]: {\n viewBox: \"0 0 512 512\",\n paths: {\n scar: \"M447.44,434.53Q412.7,409.87,380,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L241.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L171.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q95.79,90.29,72.44,58.49q43,32.32,83.86,67.06L192.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L270,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L323.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q416.66,394.28,447.44,434.53Z\",\n scarTissue: \"M436.33,375.37c-18.07-38.87-22.46-79.24-7.49-113.92-56.77,70.27-91.6,5.3-4.93-85.08C301.61,251.8,246.13,214.23,407,70.19,283.18,136,187.5,153.46,249.53,88.47c-44.75,12.79-70,6.27-91.47-2.93a773.7,773.7,0,0,0-135.18-67,949.58,949.58,0,0,0,56.49,93.31c8.39,22,3.6,46.57-37.84,76.32C191.72,148,148,244.71,30.26,314.42c200-74.2,249.65-57,121.08,93.78C252.42,334.73,332,354.59,299.17,445.84c38.06-29.48,69.66-35.77,93.87-25.1q52.21,36.94,108.66,70.93C481.19,451.39,459.54,412.52,436.33,375.37ZM380,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L241.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L171.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40L116,116.26c.83.86,1.57,1.71,2.27,2.56l2.06,2.33Q95.79,90.29,72.44,58.49q43,32.32,83.86,67.06L192.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L270,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L323.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42q32.13,38.23,62.91,78.49Q412.7,409.87,380,383.64Z\"\n },\n classes: {\n scar: \"fill-dark\",\n scarTissue: \"fill-med\"\n }\n },\n [ConsequenceType.ProwessHarm4]: {\n viewBox: \"0 0 512 512\",\n paths: {\n scar: \"M441.44,434.53Q406.7,409.87,374,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L235.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L165.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q89.79,90.29,66.44,58.49q43,32.32,83.86,67.06L186.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L264,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L317.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q410.66,394.28,441.44,434.53Z\",\n scarTissue: \"M430.33,375.37c-18.07-38.87-22.46-79.24-7.49-113.92-56.77,70.27-91.6,5.3-4.93-85.08C295.61,251.8,240.13,214.23,401,70.19,277.18,136,181.5,153.46,243.53,88.47c-44.75,12.79-70,6.27-91.47-2.93a773.7,773.7,0,0,0-135.18-67,949.58,949.58,0,0,0,56.49,93.31c8.39,22,3.6,46.57-37.84,76.32C185.72,148,142,244.71,24.26,314.42c200-74.2,249.65-57,121.08,93.78C246.42,334.73,326,354.59,293.17,445.84c38.06-29.48,69.66-35.77,93.87-25.1q52.21,36.94,108.66,70.93C475.19,451.39,453.54,412.52,430.33,375.37ZM374,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L235.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L165.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40L110,116.26c.83.86,1.57,1.71,2.27,2.56l2.06,2.33Q89.79,90.29,66.44,58.49q43,32.32,83.86,67.06L186.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L264,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L317.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42q32.13,38.23,62.91,78.49Q406.7,409.87,374,383.64Z\",\n welts: \"M414.13,84.19a39.5,39.5,0,1,0,39.57,39.5,39.2,39.2,0,0,0-39.57-39.5ZM308.33,29.83A28.66,28.66,0,1,0,337,58.51a28.51,28.51,0,0,0-28.67-28.68ZM90.17,322.56a49.51,49.51,0,1,0,49.53,49.52A49.36,49.36,0,0,0,90.17,322.56Zm258-171.24A22.79,22.79,0,1,0,371,174.11a22.61,22.61,0,0,0-22.83-22.79ZM261.49,89.88a16.72,16.72,0,1,0,16.73,16.73,16.63,16.63,0,0,0-16.73-16.73ZM91.15,187.65a21.18,21.18,0,1,0,21.18,21.18,21,21,0,0,0-21.18-21.18Zm77.51,94.54a32.09,32.09,0,1,0,32.07,32.1,32,32,0,0,0-32.07-32.1ZM391.6,243.05a16.51,16.51,0,1,0,16.49,16.52,16.41,16.41,0,0,0-16.49-16.52ZM238.11,374.85a48.43,48.43,0,1,0,48.44,48.45A48.29,48.29,0,0,0,238.11,374.85Zm137,59.88A22.86,22.86,0,1,0,398,457.59a22.69,22.69,0,0,0-22.86-22.86Z\"\n },\n classes: {\n scar: \"fill-bright\",\n scarTissue: \"fill-dark\",\n welts: \"fill-bright\"\n }\n },\n [ConsequenceType.ResolveHarm1]: {\n viewBox: \"0 0 512 512\",\n paths: {\n spikes: \"M256.09,19.1A237.5,237.5,0,0,0,197,27.22C70.63,61.08-4.36,191,29.5,317.31,62.59,440.8,187.39,515.21,311,486.92A132.35,132.35,0,0,1,279.74,475,207,207,0,0,1,122,417.49l-13.48-14.55L94.89,385.42a205.62,205.62,0,0,1-24-47.36l-7.2-17.33L60.71,296.5a205.83,205.83,0,0,1-.18-54.37l3-24.36,7.67-19.51a208.28,208.28,0,0,1,29.16-53.84l105,60.61-68.63-98a205.85,205.85,0,0,1,63.68-34.49l27.24-8.18,23.18-1.89q6.46-.48,12.89-.54a205.54,205.54,0,0,1,61.66,8.84l23.65,11,22,9.09A207.05,207.05,0,0,1,428.2,140.9l13.1,14.44L448.93,173a208,208,0,0,1,16.41,42.22,205.89,205.89,0,0,1,2.52,96.73,133,133,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C458.51,88.09,361.59,18.05,256.09,19.1Z\",\n eyeball: \"M344.58,242.53a45.61,45.61,0,0,1,8.95,6.95c12.22,12.21,16.07,29.9,13.26,47.35S354.74,332,340,346.82s-32.54,24-50,26.83-35.13-1-47.35-13.26a48,48,0,0,1-13-24.74,114.74,114.74,0,1,0,114.92-93.12Z\",\n iris: \"M316.24,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.56,9.39-39.76,21.59S249.91,303,247.81,316s.75,23.89,8,31.16S274,357.3,287,355.2s27.56-9.39,39.76-21.59,19.5-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.49,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.38,5.23-5.16-22,5.22-32.38c6.17-6.16,13.78-9.49,20.52-9.6Z\"\n },\n classes: {\n spikes: \"fill-dark\",\n eyeball: \"fill-dark\",\n iris: \"fill-med\"\n }\n },\n [ConsequenceType.ResolveHarm2]: {\n viewBox: \"0 0 512 512\",\n paths: {\n spikes: \"M261.25,19.1a237.64,237.64,0,0,0-59.11,8.12C75.79,61.08.8,191,34.66,317.31,67.75,440.8,192.55,515.21,316.15,486.92A132.59,132.59,0,0,1,284.89,475a207,207,0,0,1-157.72-57.52l-11.44-12.15-15.68-19.92a205.62,205.62,0,0,1-24-47.36l-7.32-17.33L65.87,296.5a205.41,205.41,0,0,1-.18-54.37l91.84,19.32L76.38,198.26a208,208,0,0,1,29.16-53.84L259.93,252.78,141.87,107a205.79,205.79,0,0,1,63.67-34.49L263.45,141,256,62.45q6.46-.48,12.89-.54a205.54,205.54,0,0,1,61.66,8.84l22.84,8.32,22.83,11.78a207,207,0,0,1,57.17,50.05l13.41,16.85L454.08,173a207.52,207.52,0,0,1,18.93,139,132.67,132.67,0,0,1,7.75,38.31,235.92,235.92,0,0,0,11.48-155.53C463.67,88.09,366.74,18.05,261.25,19.1Z\",\n eyeball: \"M349.74,242.53a45.61,45.61,0,0,1,8.95,6.95c12.21,12.21,16.07,29.9,13.26,47.35s-12.05,35.21-26.83,50-32.54,24-50,26.83-35.14-1-47.35-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z\",\n iris: \"M321.4,254a50.42,50.42,0,0,0-7.08.66c-13,2.09-27.56,9.39-39.76,21.59S255.06,303,253,316s.75,23.89,8,31.16,18.16,10.12,31.16,8,27.56-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.46-5.45-13-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.85,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.87,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.52-9.6Z\"\n },\n classes: {\n spikes: \"fill-med\",\n eyeball: \"fill-dark\",\n iris: \"fill-bright\"\n }\n },\n [ConsequenceType.ResolveHarm3]: {\n viewBox: \"0 0 512 512\",\n paths: {\n spikes: \"M261.31,19.1a237.51,237.51,0,0,0-59.11,8.12C75.84,61.08.86,191,34.71,317.31,67.8,440.8,192.61,515.21,316.2,486.92A132.35,132.35,0,0,1,285,475a207,207,0,0,1-157.72-57.52l-13.81-16.37-13.31-15.7a206,206,0,0,1-24.06-47.36l83.63-17.33L65.93,296.5a205.41,205.41,0,0,1-.18-54.37l164.66,47.21-154-91.08a208,208,0,0,1,29.15-53.84L260,252.78,141.92,107A205.85,205.85,0,0,1,205.6,72.52l95.49,158.21L256,62.45q6.47-.48,12.9-.54a205.43,205.43,0,0,1,61.65,8.84L353.08,169l23.17-78.14a206.76,206.76,0,0,1,57.16,50.05l13.08,22.41,7.65,9.67a207.52,207.52,0,0,1,18.93,139,132.33,132.33,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C463.73,88.09,366.8,18.05,261.31,19.1Z\",\n eyeball: \"M349.79,242.53a45.38,45.38,0,0,1,9,6.95c12.21,12.21,16.07,29.9,13.25,47.35s-12,35.21-26.82,50-32.54,24-50,26.83-35.13-1-47.34-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z\",\n iris: \"M321.45,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.55,9.39-39.75,21.59S255.12,303,253,316s.75,23.89,8,31.16,18.16,10.12,31.16,8,27.56-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.51-9.6Z\"\n },\n classes: {\n spikes: \"fill-bright\",\n eyeball: \"fill-med\",\n iris: \"fill-bright\"\n }\n },\n [ConsequenceType.ResolveHarm4]: {\n viewBox: \"0 0 512 512\",\n paths: {\n spikes: \"M261.14,19.1A237.51,237.51,0,0,0,202,27.22C75.67,61.08.69,191,34.54,317.31,67.63,440.8,192.44,515.21,316,486.92A132.35,132.35,0,0,1,284.78,475a207,207,0,0,1-157.72-57.52l89.22-30-116.34-2a206,206,0,0,1-24.06-47.36L214,333.21,65.76,296.5a205.41,205.41,0,0,1-.18-54.37l164.66,47.21-154-91.08a208,208,0,0,1,29.15-53.84l154.4,108.36L141.75,107a205.85,205.85,0,0,1,63.68-34.49l95.49,158.21L255.85,62.45q6.47-.48,12.9-.54a205.43,205.43,0,0,1,61.65,8.84L359.77,223.5,376.08,90.85a206.76,206.76,0,0,1,57.16,50.05L415.61,243.13,454,173a207.52,207.52,0,0,1,18.93,139,132.33,132.33,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C463.55,88.09,366.63,18.05,261.14,19.1Z\",\n eyeball: \"M349.62,242.53a45.38,45.38,0,0,1,9,6.95c12.21,12.21,16.07,29.9,13.25,47.35s-12,35.21-26.82,50-32.55,24-50,26.83-35.13-1-47.34-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z\",\n iris: \"M321.28,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.55,9.39-39.75,21.59S255,303,252.86,316s.75,23.89,8,31.16S279,357.3,292,355.2s27.55-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.51-9.6Z\"\n },\n classes: {\n spikes: \"fill-bright\",\n eyeball: \"fill-bright\",\n iris: \"fill-bright\"\n }\n }\n};\n// #endregion\n/* harmony default export */ __webpack_exports__[\"default\"] = (C);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jb3JlL2NvbnN0YW50cy50cyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsOENBQThDO0FBQ3hDO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsMENBQTBDO0FBQ3BDO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsd0NBQXdDO0FBQ2xDO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsZ0NBQWdDO0FBQzFCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsZ0NBQWdDO0FBQzFCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsa0RBQWtEO0FBQzVDO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLG9EQUFvRDtBQUM5QztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLGtEQUFrRDtBQUM1QztBQUNQO0FBQ0E7QUFDQSxDQUFDLDRDQUE0QztBQUN0QztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyw0QkFBNEI7QUFDdEI7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsb0NBQW9DO0FBQzlCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLHNDQUFzQztBQUNoQztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyx3Q0FBd0M7QUFDbEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyx3Q0FBd0M7QUFDbEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyx3Q0FBd0M7QUFDbEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyx3Q0FBd0M7QUFDbEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsa0NBQWtDO0FBQzVCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLHdDQUF3QztBQUNsQztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLDBDQUEwQztBQUNwQztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLDRCQUE0QjtBQUN0QjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsa0NBQWtDO0FBQzVCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLGtDQUFrQztBQUM1QjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLDBDQUEwQztBQUNwQztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyxzQ0FBc0M7QUFDaEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLHdDQUF3QztBQUNsQztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyw0QkFBNEI7QUFDdEI7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLHdCQUF3QjtBQUNsQjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLHdCQUF3QjtBQUNsQjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLGdDQUFnQztBQUMxQjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsOEJBQThCO0FBQ3hCO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsb0JBQW9CO0FBQ2Q7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsb0JBQW9CO0FBQ2Q7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLDRCQUE0QjtBQUN0QjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyw0Q0FBNEM7QUFDdEM7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQyxrQ0FBa0M7QUFDNUI7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUsseUNBQXlDO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssbUNBQW1DO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssNkJBQTZCO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdDQUF3QztBQUN4QyxLQUFLLGtEQUFrRDtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSywyREFBMkQ7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUssZ0NBQWdDO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLLCtDQUErQztBQUNwRCxDQUFDLGtCQUFrQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtB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QUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVSxnREFBZ0Q7QUFDMUQsVUFBVSxpREFBaUQ7QUFDM0QsVUFBVSxtREFBbUQ7QUFDN0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxtREFBbUQ7QUFDN0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxtREFBbUQ7QUFDN0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxxREFBcUQ7QUFDL0QsVUFBVSxtREFBbUQ7QUFDN0QsVUFBVSxtREFBbUQ7QUFDN0QsVUFBVSxrREFBa0Q7QUFDNUQsVUFBVSxrREFBa0Q7QUFDNUQsVUFBVSxnREFBZ0Q7QUFDMUQsVUFBVSxrREFBa0Q7QUFDNUQsVUFBVSxrREFBa0Q7QUFDNUQsVUFBVSxrREFBa0Q7QUFDNUQsVUFBVSxnREFBZ0Q7QUFDMUQsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxjQUFjLGdJQUFnSTtBQUM5SSxjQUFjLGdJQUFnSTtBQUM5SSxjQUFjLGdJQUFnSTtBQUM5SSxjQUFjLHdMQUF3TDtBQUN0TSxjQUFjLHdMQUF3TDtBQUN0TSxjQUFjLHdMQUF3TDtBQUN0TSxjQUFjLHFOQUFxTjtBQUNuTyxjQUFjLHFOQUFxTjtBQUNuTyxjQUFjLHFOQUFxTjtBQUNuTyxjQUFjLDROQUE0TjtBQUMxTyxjQUFjLDROQUE0TjtBQUMxTyxjQUFjLDROQUE0TjtBQUMxTyxjQUFjLHNOQUFzTjtBQUNwTyxjQUFjLHNOQUFzTjtBQUNwTyxjQUFjLHNOQUFzTjtBQUNwTyxjQUFjLHdKQUF3SjtBQUN0SyxjQUFjLHdKQUF3SjtB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QTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1EO0FBQ25EO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsK0xBQStMO0FBQy9MO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBFQUEwRTtBQUMxRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNEVBQTRFO0FBQzVFO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLGdLQUFnSztBQUNoSztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzR0FBc0c7QUFDdEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnREFBZ0Q7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVFQUF1RTtBQUN2RTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvRkFBb0Y7QUFDcEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLHFEQUFxRDtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzSEFBc0g7QUFDdEg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZIQUE2SDtBQUM3SCxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1HQUFtRztBQUNuRyxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBLHlMQUF5TDtBQUN6TDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQSxtREFBbUQ7QUFDbkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0EsaUxBQWlMO0FBQ2pMO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0Esc1FBQXNRO0FBQ3RRO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixtQkFBbUI7QUFDcEMsaUJBQWlCO0FBQ2pCO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCLG1CQUFtQjtBQUNwQyxpQkFBaUI7QUFDakI7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLG9CQUFvQjtBQUNyQyxpQkFBaUIsbUJBQW1CO0FBQ3BDLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCO0FBQ2pCO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCLG1CQUFtQjtBQUNwQyxpQkFBaUIsb0JBQW9CO0FBQ3JDLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCO0FBQ2pCO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCLG1CQUFtQjtBQUNwQyxpQkFBaUIsb0JBQW9CO0FBQ3JDLGlCQUFpQixvQkFBb0I7QUFDckMsaUJBQWlCLG9CQUFvQjtBQUNyQyxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxDQUFDLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jb3JlL2NvbnN0YW50cy50cz8xZjdkIl0sInNvdXJjZXNDb250ZW50IjpbIi8vICNyZWdpb24gRU5VTVMgflxuZXhwb3J0IHZhciBCbGFkZXNQZXJtaXNzaW9ucztcbihmdW5jdGlvbiAoQmxhZGVzUGVybWlzc2lvbnMpIHtcbiAgICBCbGFkZXNQZXJtaXNzaW9uc1tCbGFkZXNQZXJtaXNzaW9uc1tcIk5PTkVcIl0gPSBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5OT05FXSA9IFwiTk9ORVwiO1xuICAgIEJsYWRlc1Blcm1pc3Npb25zW0JsYWRlc1Blcm1pc3Npb25zW1wiQkFTSUNcIl0gPSBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5MSU1JVEVEXSA9IFwiQkFTSUNcIjtcbiAgICBCbGFkZXNQZXJtaXNzaW9uc1tCbGFkZXNQZXJtaXNzaW9uc1tcIkZVTExcIl0gPSBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5PQlNFUlZFUl0gPSBcIkZVTExcIjtcbiAgICBCbGFkZXNQZXJtaXNzaW9uc1tCbGFkZXNQZXJtaXNzaW9uc1tcIk9XTkVSXCJdID0gQ09OU1QuRE9DVU1FTlRfUEVSTUlTU0lPTl9MRVZFTFMuT1dORVJdID0gXCJPV05FUlwiO1xufSkoQmxhZGVzUGVybWlzc2lvbnMgfHwgKEJsYWRlc1Blcm1pc3Npb25zID0ge30pKTtcbmV4cG9ydCB2YXIgQmxhZGVzQWN0b3JUeXBlO1xuKGZ1bmN0aW9uIChCbGFkZXNBY3RvclR5cGUpIHtcbiAgICBCbGFkZXNBY3RvclR5cGVbXCJwY1wiXSA9IFwicGNcIjtcbiAgICBCbGFkZXNBY3RvclR5cGVbXCJucGNcIl0gPSBcIm5wY1wiO1xuICAgIEJsYWRlc0FjdG9yVHlwZVtcImNyZXdcIl0gPSBcImNyZXdcIjtcbiAgICBCbGFkZXNBY3RvclR5cGVbXCJmYWN0aW9uXCJdID0gXCJmYWN0aW9uXCI7XG59KShCbGFkZXNBY3RvclR5cGUgfHwgKEJsYWRlc0FjdG9yVHlwZSA9IHt9KSk7XG5leHBvcnQgdmFyIEJsYWRlc0l0ZW1UeXBlO1xuKGZ1bmN0aW9uIChCbGFkZXNJdGVtVHlwZSkge1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiYWJpbGl0eVwiXSA9IFwiYWJpbGl0eVwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiYmFja2dyb3VuZFwiXSA9IFwiYmFja2dyb3VuZFwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiY2xvY2tfa2VlcGVyXCJdID0gXCJjbG9ja19rZWVwZXJcIjtcbiAgICBCbGFkZXNJdGVtVHlwZVtcImNvaG9ydF9nYW5nXCJdID0gXCJjb2hvcnRfZ2FuZ1wiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiY29ob3J0X2V4cGVydFwiXSA9IFwiY29ob3J0X2V4cGVydFwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiY3Jld19hYmlsaXR5XCJdID0gXCJjcmV3X2FiaWxpdHlcIjtcbiAgICBCbGFkZXNJdGVtVHlwZVtcImNyZXdfcmVwdXRhdGlvblwiXSA9IFwiY3Jld19yZXB1dGF0aW9uXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJjcmV3X3BsYXlib29rXCJdID0gXCJjcmV3X3BsYXlib29rXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJjcmV3X3VwZ3JhZGVcIl0gPSBcImNyZXdfdXBncmFkZVwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiZmVhdHVyZVwiXSA9IFwiZmVhdHVyZVwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiZ21fdHJhY2tlclwiXSA9IFwiZ21fdHJhY2tlclwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wiaGVyaXRhZ2VcIl0gPSBcImhlcml0YWdlXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJnZWFyXCJdID0gXCJnZWFyXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJwbGF5Ym9va1wiXSA9IFwicGxheWJvb2tcIjtcbiAgICBCbGFkZXNJdGVtVHlwZVtcInByZWZlcnJlZF9vcFwiXSA9IFwicHJlZmVycmVkX29wXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJzdHJpY3R1cmVcIl0gPSBcInN0cmljdHVyZVwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1widmljZVwiXSA9IFwidmljZVwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wicHJvamVjdFwiXSA9IFwicHJvamVjdFwiO1xuICAgIEJsYWRlc0l0ZW1UeXBlW1wicml0dWFsXCJdID0gXCJyaXR1YWxcIjtcbiAgICBCbGFkZXNJdGVtVHlwZVtcImRlc2lnblwiXSA9IFwiZGVzaWduXCI7XG4gICAgQmxhZGVzSXRlbVR5cGVbXCJsb2NhdGlvblwiXSA9IFwibG9jYXRpb25cIjtcbiAgICBCbGFkZXNJdGVtVHlwZVtcInNjb3JlXCJdID0gXCJzY29yZVwiO1xufSkoQmxhZGVzSXRlbVR5cGUgfHwgKEJsYWRlc0l0ZW1UeXBlID0ge30pKTtcbmV4cG9ydCB2YXIgUHJlcmVxVHlwZTtcbihmdW5jdGlvbiAoUHJlcmVxVHlwZSkge1xuICAgIFByZXJlcVR5cGVbXCJIYXNBY3RpdmVJdGVtXCJdID0gXCJIYXNBY3RpdmVJdGVtXCI7XG4gICAgUHJlcmVxVHlwZVtcIkhhc0FjdGl2ZUl0ZW1zQnlUYWdcIl0gPSBcIkhhc0FjdGl2ZUl0ZW1CeVRhZ1wiO1xuICAgIFByZXJlcVR5cGVbXCJBZHZhbmNlZFBsYXlib29rXCJdID0gXCJBZHZhbmNlZFBsYXlib29rXCI7XG4gICAgUHJlcmVxVHlwZVtcIkhhc0FsbFRhZ3NcIl0gPSBcIkhhc0FsbFRhZ3NcIjtcbiAgICBQcmVyZXFUeXBlW1wiSGFzQW55VGFnXCJdID0gXCJIYXNBbnlUYWdcIjtcbiAgICBQcmVyZXFUeXBlW1wiTm90X0hhc0FjdGl2ZUl0ZW1cIl0gPSBcIk5vdF9IYXNBY3RpdmVJdGVtXCI7XG4gICAgUHJlcmVxVHlwZVtcIk5vdF9IYXNBY3RpdmVJdGVtc0J5VGFnXCJdID0gXCJOb3RfSGFzQWN0aXZlSXRlbXNCeVRhZ1wiO1xuICAgIFByZXJlcVR5cGVbXCJOb3RfQWR2YW5jZWRQbGF5Ym9va1wiXSA9IFwiTm90X0FkdmFuY2VkUGxheWJvb2tcIjtcbiAgICBQcmVyZXFUeXBlW1wiTm90X0hhc0FsbFRhZ3NcIl0gPSBcIk5vdF9IYXNBbGxUYWdzXCI7XG4gICAgUHJlcmVxVHlwZVtcIk5vdF9IYXNBbnlUYWdcIl0gPSBcIk5vdF9IYXNBbnlUYWdcIjtcbn0pKFByZXJlcVR5cGUgfHwgKFByZXJlcVR5cGUgPSB7fSkpO1xuZXhwb3J0IHZhciBDbG9ja0NvbG9yO1xuKGZ1bmN0aW9uIChDbG9ja0NvbG9yKSB7XG4gICAgQ2xvY2tDb2xvcltcInllbGxvd1wiXSA9IFwieWVsbG93XCI7XG4gICAgQ2xvY2tDb2xvcltcInJlZFwiXSA9IFwicmVkXCI7XG4gICAgQ2xvY2tDb2xvcltcIndoaXRlXCJdID0gXCJ3aGl0ZVwiO1xuICAgIENsb2NrQ29sb3JbXCJjeWFuXCJdID0gXCJjeWFuXCI7XG59KShDbG9ja0NvbG9yIHx8IChDbG9ja0NvbG9yID0ge30pKTtcbmV4cG9ydCB2YXIgQ2xvY2tEaXNwbGF5Q29udGV4dDtcbihmdW5jdGlvbiAoQ2xvY2tEaXNwbGF5Q29udGV4dCkge1xuICAgIENsb2NrRGlzcGxheUNvbnRleHRbXCJvdmVybGF5XCJdID0gXCJvdmVybGF5XCI7XG4gICAgQ2xvY2tEaXNwbGF5Q29udGV4dFtcInBjU2hlZXRcIl0gPSBcInBjU2hlZXRcIjtcbiAgICBDbG9ja0Rpc3BsYXlDb250ZXh0W1wiZmFjdGlvblNoZWV0XCJdID0gXCJmYWN0aW9uU2hlZXRcIjtcbiAgICBDbG9ja0Rpc3BsYXlDb250ZXh0W1wicHJvamVjdFNoZWV0XCJdID0gXCJwcm9qZWN0U2hlZXRcIjtcbiAgICBDbG9ja0Rpc3BsYXlDb250ZXh0W1wic2NvcmVTaGVldFwiXSA9IFwic2NvcmVTaGVldFwiO1xuICAgIENsb2NrRGlzcGxheUNvbnRleHRbXCJyb2xsQ29sbGFiXCJdID0gXCJyb2xsQ29sbGFiXCI7XG4gICAgQ2xvY2tEaXNwbGF5Q29udGV4dFtcImNoYXRNZXNzYWdlXCJdID0gXCJjaGF0TWVzc2FnZVwiO1xufSkoQ2xvY2tEaXNwbGF5Q29udGV4dCB8fCAoQ2xvY2tEaXNwbGF5Q29udGV4dCA9IHt9KSk7XG5leHBvcnQgdmFyIENsb2NrS2V5VXBkYXRlQWN0aW9uO1xuKGZ1bmN0aW9uIChDbG9ja0tleVVwZGF0ZUFjdGlvbikge1xuICAgIENsb2NrS2V5VXBkYXRlQWN0aW9uW1wiUmVuZGVyQWxsXCJdID0gXCJSZW5kZXJBbGxcIjtcbiAgICBDbG9ja0tleVVwZGF0ZUFjdGlvbltcIlJlbmRlck5vbkNsb2NrS2VlcGVyXCJdID0gXCJSZW5kZXJOb25DbG9ja0tlZXBlclwiO1xuICAgIENsb2NrS2V5VXBkYXRlQWN0aW9uW1wiUmVuZGVyTm9uZVwiXSA9IFwiUmVuZGVyTm9uZVwiO1xufSkoQ2xvY2tLZXlVcGRhdGVBY3Rpb24gfHwgKENsb2NrS2V5VXBkYXRlQWN0aW9uID0ge30pKTtcbmV4cG9ydCB2YXIgQ2xvY2tLZXlEaXNwbGF5TW9kZTtcbihmdW5jdGlvbiAoQ2xvY2tLZXlEaXNwbGF5TW9kZSkge1xuICAgIENsb2NrS2V5RGlzcGxheU1vZGVbXCJmdWxsXCJdID0gXCJmdWxsXCI7XG4gICAgQ2xvY2tLZXlEaXNwbGF5TW9kZVtcImNsb2Nrc1wiXSA9IFwiY2xvY2tzXCI7XG4gICAgQ2xvY2tLZXlEaXNwbGF5TW9kZVtcImFjdGl2ZUNsb2Nrc1wiXSA9IFwiYWN0aXZlQ2xvY2tzXCI7XG4gICAgQ2xvY2tLZXlEaXNwbGF5TW9kZVtcInByZXNlbnRDdXJyZW50Q2xvY2tcIl0gPSBcInByZXNlbnRDdXJyZW50Q2xvY2tcIjtcbiAgICBDbG9ja0tleURpc3BsYXlNb2RlW1wicHJlc2VudDBcIl0gPSBcInByZXNlbnQwXCI7XG4gICAgQ2xvY2tLZXlEaXNwbGF5TW9kZVtcInByZXNlbnQxXCJdID0gXCJwcmVzZW50MVwiO1xuICAgIENsb2NrS2V5RGlzcGxheU1vZGVbXCJwcmVzZW50MlwiXSA9IFwicHJlc2VudDJcIjtcbiAgICBDbG9ja0tleURpc3BsYXlNb2RlW1wicHJlc2VudDNcIl0gPSBcInByZXNlbnQzXCI7XG4gICAgQ2xvY2tLZXlEaXNwbGF5TW9kZVtcInByZXNlbnQ0XCJdID0gXCJwcmVzZW50NFwiO1xuICAgIENsb2NrS2V5RGlzcGxheU1vZGVbXCJwcmVzZW50NVwiXSA9IFwicHJlc2VudDVcIjtcbn0pKENsb2NrS2V5RGlzcGxheU1vZGUgfHwgKENsb2NrS2V5RGlzcGxheU1vZGUgPSB7fSkpO1xuZXhwb3J0IHZhciBCbGFkZXNOb3RpY2VUeXBlO1xuKGZ1bmN0aW9uIChCbGFkZXNOb3RpY2VUeXBlKSB7XG4gICAgQmxhZGVzTm90aWNlVHlwZVtcInB1c2hcIl0gPSBcInB1c2hcIjtcbn0pKEJsYWRlc05vdGljZVR5cGUgfHwgKEJsYWRlc05vdGljZVR5cGUgPSB7fSkpO1xuZXhwb3J0IHZhciBEaXN0cmljdDtcbihmdW5jdGlvbiAoRGlzdHJpY3QpIHtcbiAgICBEaXN0cmljdFtcIkJhcnJvd2NsZWZ0XCJdID0gXCJCYXJyb3djbGVmdFwiO1xuICAgIERpc3RyaWN0W1wiQnJpZ2h0c3RvbmVcIl0gPSBcIkJyaWdodHN0b25lXCI7XG4gICAgRGlzdHJpY3RbXCJDaGFyaG9sbG93XCJdID0gXCJDaGFyaG9sbG93XCI7XG4gICAgRGlzdHJpY3RbXCJDaGFydGVyaGFsbFwiXSA9IFwiQ2hhcnRlcmhhbGxcIjtcbiAgICBEaXN0cmljdFtcIkNvYWxyaWRnZVwiXSA9IFwiQ29hbHJpZGdlXCI7XG4gICAgRGlzdHJpY3RbXCJDcm93cyBGb290XCJdID0gXCJDcm93cyBGb290XCI7XG4gICAgRGlzdHJpY3RbXCJUaGUgRG9ja3NcIl0gPSBcIlRoZSBEb2Nrc1wiO1xuICAgIERpc3RyaWN0W1wiRHVuc2xvdWdoXCJdID0gXCJEdW5zbG91Z2hcIjtcbiAgICBEaXN0cmljdFtcIk5pZ2h0bWFya2V0XCJdID0gXCJOaWdodG1hcmtldFwiO1xuICAgIERpc3RyaWN0W1wiU2lsa3Nob3JlXCJdID0gXCJTaWxrc2hvcmVcIjtcbiAgICBEaXN0cmljdFtcIlNpeCBUb3dlcnNcIl0gPSBcIlNpeCBUb3dlcnNcIjtcbiAgICBEaXN0cmljdFtcIldoaXRlY3Jvd25cIl0gPSBcIldoaXRlY3Jvd25cIjtcbiAgICBEaXN0cmljdFtcIkdhZGRvYyBTdGF0aW9uXCJdID0gXCJHYWRkb2MgU3RhdGlvblwiO1xuICAgIERpc3RyaWN0W1wiVGhlIExvc3QgRGlzdHJpY3RcIl0gPSBcIlRoZSBMb3N0IERpc3RyaWN0XCI7XG4gICAgRGlzdHJpY3RbXCJUaGUgVm9pZCBTZWFcIl0gPSBcIlRoZSBWb2lkIFNlYVwiO1xuICAgIERpc3RyaWN0W1wiSXJvbmhvb2sgUHJpc29uXCJdID0gXCJJcm9uaG9vayBQcmlzb25cIjtcbiAgICBEaXN0cmljdFtcIk9sZCBOb3J0aCBQb3J0XCJdID0gXCJPbGQgTm9ydGggUG9ydFwiO1xuICAgIERpc3RyaWN0W1wiRGVhdGhsYW5kc1wiXSA9IFwiRGVhdGhsYW5kc1wiO1xufSkoRGlzdHJpY3QgfHwgKERpc3RyaWN0ID0ge30pKTtcbmV4cG9ydCB2YXIgTWFpbkRpc3RyaWN0O1xuKGZ1bmN0aW9uIChNYWluRGlzdHJpY3QpIHtcbiAgICBNYWluRGlzdHJpY3RbXCJCYXJyb3djbGVmdFwiXSA9IFwiQmFycm93Y2xlZnRcIjtcbiAgICBNYWluRGlzdHJpY3RbXCJCcmlnaHRzdG9uZVwiXSA9IFwiQnJpZ2h0c3RvbmVcIjtcbiAgICBNYWluRGlzdHJpY3RbXCJDaGFyaG9sbG93XCJdID0gXCJDaGFyaG9sbG93XCI7XG4gICAgTWFpbkRpc3RyaWN0W1wiQ2hhcnRlcmhhbGxcIl0gPSBcIkNoYXJ0ZXJoYWxsXCI7XG4gICAgTWFpbkRpc3RyaWN0W1wiQ29hbHJpZGdlXCJdID0gXCJDb2FscmlkZ2VcIjtcbiAgICBNYWluRGlzdHJpY3RbXCJDcm93cyBGb290XCJdID0gXCJDcm93cyBGb290XCI7XG4gICAgTWFpbkRpc3RyaWN0W1wiVGhlIERvY2tzXCJdID0gXCJUaGUgRG9ja3NcIjtcbiAgICBNYWluRGlzdHJpY3RbXCJEdW5zbG91Z2hcIl0gPSBcIkR1bnNsb3VnaFwiO1xuICAgIE1haW5EaXN0cmljdFtcIk5pZ2h0bWFya2V0XCJdID0gXCJOaWdodG1hcmtldFwiO1xuICAgIE1haW5EaXN0cmljdFtcIlNpbGtzaG9yZVwiXSA9IFwiU2lsa3Nob3JlXCI7XG4gICAgTWFpbkRpc3RyaWN0W1wiU2l4IFRvd2Vyc1wiXSA9IFwiU2l4IFRvd2Vyc1wiO1xuICAgIE1haW5EaXN0cmljdFtcIldoaXRlY3Jvd25cIl0gPSBcIldoaXRlY3Jvd25cIjtcbn0pKE1haW5EaXN0cmljdCB8fCAoTWFpbkRpc3RyaWN0ID0ge30pKTtcbmV4cG9ydCB2YXIgT3RoZXJEaXN0cmljdDtcbihmdW5jdGlvbiAoT3RoZXJEaXN0cmljdCkge1xuICAgIE90aGVyRGlzdHJpY3RbXCJHYWRkb2MgU3RhdGlvblwiXSA9IFwiR2FkZG9jIFN0YXRpb25cIjtcbiAgICBPdGhlckRpc3RyaWN0W1wiVGhlIExvc3QgRGlzdHJpY3RcIl0gPSBcIlRoZSBMb3N0IERpc3RyaWN0XCI7XG4gICAgT3RoZXJEaXN0cmljdFtcIlRoZSBWb2lkIFNlYVwiXSA9IFwiVGhlIFZvaWQgU2VhXCI7XG4gICAgT3RoZXJEaXN0cmljdFtcIklyb25ob29rIFByaXNvblwiXSA9IFwiSXJvbmhvb2sgUHJpc29uXCI7XG4gICAgT3RoZXJEaXN0cmljdFtcIk9sZCBOb3J0aCBQb3J0XCJdID0gXCJPbGQgTm9ydGggUG9ydFwiO1xuICAgIE90aGVyRGlzdHJpY3RbXCJEZWF0aGxhbmRzXCJdID0gXCJEZWF0aGxhbmRzXCI7XG59KShPdGhlckRpc3RyaWN0IHx8IChPdGhlckRpc3RyaWN0ID0ge30pKTtcbmV4cG9ydCB2YXIgQXR0cmlidXRlVHJhaXQ7XG4oZnVuY3Rpb24gKEF0dHJpYnV0ZVRyYWl0KSB7XG4gICAgQXR0cmlidXRlVHJhaXRbXCJpbnNpZ2h0XCJdID0gXCJpbnNpZ2h0XCI7XG4gICAgQXR0cmlidXRlVHJhaXRbXCJwcm93ZXNzXCJdID0gXCJwcm93ZXNzXCI7XG4gICAgQXR0cmlidXRlVHJhaXRbXCJyZXNvbHZlXCJdID0gXCJyZXNvbHZlXCI7XG59KShBdHRyaWJ1dGVUcmFpdCB8fCAoQXR0cmlidXRlVHJhaXQgPSB7fSkpO1xuZXhwb3J0IHZhciBJbnNpZ2h0QWN0aW9ucztcbihmdW5jdGlvbiAoSW5zaWdodEFjdGlvbnMpIHtcbiAgICBJbnNpZ2h0QWN0aW9uc1tcImh1bnRcIl0gPSBcImh1bnRcIjtcbiAgICBJbnNpZ2h0QWN0aW9uc1tcInN0dWR5XCJdID0gXCJzdHVkeVwiO1xuICAgIEluc2lnaHRBY3Rpb25zW1wic3VydmV5XCJdID0gXCJzdXJ2ZXlcIjtcbiAgICBJbnNpZ2h0QWN0aW9uc1tcInRpbmtlclwiXSA9IFwidGlua2VyXCI7XG59KShJbnNpZ2h0QWN0aW9ucyB8fCAoSW5zaWdodEFjdGlvbnMgPSB7fSkpO1xuZXhwb3J0IHZhciBQcm93ZXNzQWN0aW9ucztcbihmdW5jdGlvbiAoUHJvd2Vzc0FjdGlvbnMpIHtcbiAgICBQcm93ZXNzQWN0aW9uc1tcImZpbmVzc2VcIl0gPSBcImZpbmVzc2VcIjtcbiAgICBQcm93ZXNzQWN0aW9uc1tcInByb3dsXCJdID0gXCJwcm93bFwiO1xuICAgIFByb3dlc3NBY3Rpb25zW1wic2tpcm1pc2hcIl0gPSBcInNraXJtaXNoXCI7XG4gICAgUHJvd2Vzc0FjdGlvbnNbXCJ3cmVja1wiXSA9IFwid3JlY2tcIjtcbn0pKFByb3dlc3NBY3Rpb25zIHx8IChQcm93ZXNzQWN0aW9ucyA9IHt9KSk7XG5leHBvcnQgdmFyIFJlc29sdmVBY3Rpb25zO1xuKGZ1bmN0aW9uIChSZXNvbHZlQWN0aW9ucykge1xuICAgIFJlc29sdmVBY3Rpb25zW1wiYXR0dW5lXCJdID0gXCJhdHR1bmVcIjtcbiAgICBSZXNvbHZlQWN0aW9uc1tcImNvbW1hbmRcIl0gPSBcImNvbW1hbmRcIjtcbiAgICBSZXNvbHZlQWN0aW9uc1tcImNvbnNvcnRcIl0gPSBcImNvbnNvcnRcIjtcbiAgICBSZXNvbHZlQWN0aW9uc1tcInN3YXlcIl0gPSBcInN3YXlcIjtcbn0pKFJlc29sdmVBY3Rpb25zIHx8IChSZXNvbHZlQWN0aW9ucyA9IHt9KSk7XG5leHBvcnQgdmFyIEFjdGlvblRyYWl0O1xuKGZ1bmN0aW9uIChBY3Rpb25UcmFpdCkge1xuICAgIEFjdGlvblRyYWl0W1wiaHVudFwiXSA9IFwiaHVudFwiO1xuICAgIEFjdGlvblRyYWl0W1wic3R1ZHlcIl0gPSBcInN0dWR5XCI7XG4gICAgQWN0aW9uVHJhaXRbXCJzdXJ2ZXlcIl0gPSBcInN1cnZleVwiO1xuICAgIEFjdGlvblRyYWl0W1widGlua2VyXCJdID0gXCJ0aW5rZXJcIjtcbiAgICBBY3Rpb25UcmFpdFtcImZpbmVzc2VcIl0gPSBcImZpbmVzc2VcIjtcbiAgICBBY3Rpb25UcmFpdFtcInByb3dsXCJdID0gXCJwcm93bFwiO1xuICAgIEFjdGlvblRyYWl0W1wic2tpcm1pc2hcIl0gPSBcInNraXJtaXNoXCI7XG4gICAgQWN0aW9uVHJhaXRbXCJ3cmVja1wiXSA9IFwid3JlY2tcIjtcbiAgICBBY3Rpb25UcmFpdFtcImF0dHVuZVwiXSA9IFwiYXR0dW5lXCI7XG4gICAgQWN0aW9uVHJhaXRbXCJjb21tYW5kXCJdID0gXCJjb21tYW5kXCI7XG4gICAgQWN0aW9uVHJhaXRbXCJjb25zb3J0XCJdID0gXCJjb25zb3J0XCI7XG4gICAgQWN0aW9uVHJhaXRbXCJzd2F5XCJdID0gXCJzd2F5XCI7XG59KShBY3Rpb25UcmFpdCB8fCAoQWN0aW9uVHJhaXQgPSB7fSkpO1xuZXhwb3J0IHZhciBEb3dudGltZUFjdGlvbjtcbihmdW5jdGlvbiAoRG93bnRpbWVBY3Rpb24pIHtcbiAgICBEb3dudGltZUFjdGlvbltcIkFjcXVpcmVBc3NldFwiXSA9IFwiQWNxdWlyZUFzc2V0XCI7XG4gICAgRG93bnRpbWVBY3Rpb25bXCJJbmR1bGdlVmljZVwiXSA9IFwiSW5kdWxnZVZpY2VcIjtcbiAgICBEb3dudGltZUFjdGlvbltcIkxvbmdUZXJtUHJvamVjdFwiXSA9IFwiTG9uZ1Rlcm1Qcm9qZWN0XCI7XG4gICAgRG93bnRpbWVBY3Rpb25bXCJSZWNvdmVyXCJdID0gXCJSZWNvdmVyXCI7XG4gICAgRG93bnRpbWVBY3Rpb25bXCJSZWR1Y2VIZWF0XCJdID0gXCJSZWR1Y2VIZWF0XCI7XG4gICAgRG93bnRpbWVBY3Rpb25bXCJUcmFpblwiXSA9IFwiVHJhaW5cIjtcbn0pKERvd250aW1lQWN0aW9uIHx8IChEb3dudGltZUFjdGlvbiA9IHt9KSk7XG5leHBvcnQgdmFyIFJvbGxQZXJtaXNzaW9ucztcbihmdW5jdGlvbiAoUm9sbFBlcm1pc3Npb25zKSB7XG4gICAgUm9sbFBlcm1pc3Npb25zW1wiUHJpbWFyeVwiXSA9IFwiUHJpbWFyeVwiO1xuICAgIFJvbGxQZXJtaXNzaW9uc1tcIk9ic2VydmVyXCJdID0gXCJPYnNlcnZlclwiO1xuICAgIFJvbGxQZXJtaXNzaW9uc1tcIkdNXCJdID0gXCJHTVwiO1xuICAgIFJvbGxQZXJtaXNzaW9uc1tcIlBhcnRpY2lwYW50XCJdID0gXCJQYXJ0aWNpcGFudFwiO1xufSkoUm9sbFBlcm1pc3Npb25zIHx8IChSb2xsUGVybWlzc2lvbnMgPSB7fSkpO1xuZXhwb3J0IHZhciBSb2xsVHlwZTtcbihmdW5jdGlvbiAoUm9sbFR5cGUpIHtcbiAgICBSb2xsVHlwZVtcIkFjdGlvblwiXSA9IFwiQWN0aW9uXCI7XG4gICAgUm9sbFR5cGVbXCJSZXNpc3RhbmNlXCJdID0gXCJSZXNpc3RhbmNlXCI7XG4gICAgUm9sbFR5cGVbXCJGb3J0dW5lXCJdID0gXCJGb3J0dW5lXCI7XG4gICAgUm9sbFR5cGVbXCJJbmR1bGdlVmljZVwiXSA9IFwiSW5kdWxnZVZpY2VcIjtcbn0pKFJvbGxUeXBlIHx8IChSb2xsVHlwZSA9IHt9KSk7XG5leHBvcnQgdmFyIFJvbGxTdWJUeXBlO1xuKGZ1bmN0aW9uIChSb2xsU3ViVHlwZSkge1xuICAgIFJvbGxTdWJUeXBlW1wiSW5jYXJjZXJhdGlvblwiXSA9IFwiSW5jYXJjZXJhdGlvblwiO1xuICAgIFJvbGxTdWJUeXBlW1wiRW5nYWdlbWVudFwiXSA9IFwiRW5nYWdlbWVudFwiO1xuICAgIFJvbGxTdWJUeXBlW1wiR2F0aGVySW5mb1wiXSA9IFwiR2F0aGVySW5mb1wiO1xuICAgIFJvbGxTdWJUeXBlW1wiR3JvdXBMZWFkXCJdID0gXCJHcm91cExlYWRcIjtcbiAgICBSb2xsU3ViVHlwZVtcIkdyb3VwUGFydGljaXBhbnRcIl0gPSBcIkdyb3VwUGFydGljaXBhbnRcIjtcbn0pKFJvbGxTdWJUeXBlIHx8IChSb2xsU3ViVHlwZSA9IHt9KSk7XG5leHBvcnQgdmFyIFJvbGxNb2RUeXBlO1xuKGZ1bmN0aW9uIChSb2xsTW9kVHlwZSkge1xuICAgIFJvbGxNb2RUeXBlW1wiZ2VuZXJhbFwiXSA9IFwiZ2VuZXJhbFwiO1xuICAgIFJvbGxNb2RUeXBlW1wiaGFybVwiXSA9IFwiaGFybVwiO1xuICAgIFJvbGxNb2RUeXBlW1widGVhbXdvcmtcIl0gPSBcInRlYW13b3JrXCI7XG4gICAgUm9sbE1vZFR5cGVbXCJhYmlsaXR5XCJdID0gXCJhYmlsaXR5XCI7XG4gICAgUm9sbE1vZFR5cGVbXCJnZWFyXCJdID0gXCJnZWFyXCI7XG4gICAgUm9sbE1vZFR5cGVbXCJjcmV3X2FiaWxpdHlcIl0gPSBcImNyZXdfYWJpbGl0eVwiO1xuICAgIFJvbGxNb2RUeXBlW1wiY3Jld191cGdyYWRlXCJdID0gXCJjcmV3X3VwZ3JhZGVcIjtcbiAgICBSb2xsTW9kVHlwZVtcImFkdmFudGFnZVwiXSA9IFwiYWR2YW50YWdlXCI7XG4gICAgUm9sbE1vZFR5cGVbXCJkaXNhZHZhbnRhZ2VcIl0gPSBcImRpc2FkdmFudGFnZVwiO1xufSkoUm9sbE1vZFR5cGUgfHwgKFJvbGxNb2RUeXBlID0ge30pKTtcbmV4cG9ydCB2YXIgQ29uc2VxdWVuY2VUeXBlO1xuKGZ1bmN0aW9uIChDb25zZXF1ZW5jZVR5cGUpIHtcbiAgICBDb25zZXF1ZW5jZVR5cGVbXCJSZWR1Y2VkRWZmZWN0XCJdID0gXCJSZWR1Y2VkRWZmZWN0XCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiQ29tcGxpY2F0aW9uTWlub3JcIl0gPSBcIkNvbXBsaWNhdGlvbk1pbm9yXCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiQ29tcGxpY2F0aW9uTWFqb3JcIl0gPSBcIkNvbXBsaWNhdGlvbk1ham9yXCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiQ29tcGxpY2F0aW9uU2VyaW91c1wiXSA9IFwiQ29tcGxpY2F0aW9uU2VyaW91c1wiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIkxvc3RPcHBvcnR1bml0eVwiXSA9IFwiTG9zdE9wcG9ydHVuaXR5XCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiV29yc2VQb3NpdGlvblwiXSA9IFwiV29yc2VQb3NpdGlvblwiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIkluc2lnaHRIYXJtMVwiXSA9IFwiSW5zaWdodEhhcm0xXCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiSW5zaWdodEhhcm0yXCJdID0gXCJJbnNpZ2h0SGFybTJcIjtcbiAgICBDb25zZXF1ZW5jZVR5cGVbXCJJbnNpZ2h0SGFybTNcIl0gPSBcIkluc2lnaHRIYXJtM1wiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIkluc2lnaHRIYXJtNFwiXSA9IFwiSW5zaWdodEhhcm00XCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiUHJvd2Vzc0hhcm0xXCJdID0gXCJQcm93ZXNzSGFybTFcIjtcbiAgICBDb25zZXF1ZW5jZVR5cGVbXCJQcm93ZXNzSGFybTJcIl0gPSBcIlByb3dlc3NIYXJtMlwiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIlByb3dlc3NIYXJtM1wiXSA9IFwiUHJvd2Vzc0hhcm0zXCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiUHJvd2Vzc0hhcm00XCJdID0gXCJQcm93ZXNzSGFybTRcIjtcbiAgICBDb25zZXF1ZW5jZVR5cGVbXCJSZXNvbHZlSGFybTFcIl0gPSBcIlJlc29sdmVIYXJtMVwiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIlJlc29sdmVIYXJtMlwiXSA9IFwiUmVzb2x2ZUhhcm0yXCI7XG4gICAgQ29uc2VxdWVuY2VUeXBlW1wiUmVzb2x2ZUhhcm0zXCJdID0gXCJSZXNvbHZlSGFybTNcIjtcbiAgICBDb25zZXF1ZW5jZVR5cGVbXCJSZXNvbHZlSGFybTRcIl0gPSBcIlJlc29sdmVIYXJtNFwiO1xuICAgIENvbnNlcXVlbmNlVHlwZVtcIk5vbmVcIl0gPSBcIk5vbmVcIjtcbn0pKENvbnNlcXVlbmNlVHlwZSB8fCAoQ29uc2VxdWVuY2VUeXBlID0ge30pKTtcbmV4cG9ydCB2YXIgUm9sbE1vZFN0YXR1cztcbihmdW5jdGlvbiAoUm9sbE1vZFN0YXR1cykge1xuICAgIFJvbGxNb2RTdGF0dXNbXCJIaWRkZW5cIl0gPSBcIkhpZGRlblwiO1xuICAgIFJvbGxNb2RTdGF0dXNbXCJGb3JjZWRPZmZcIl0gPSBcIkZvcmNlZE9mZlwiO1xuICAgIFJvbGxNb2RTdGF0dXNbXCJUb2dnbGVkT2ZmXCJdID0gXCJUb2dnbGVkT2ZmXCI7XG4gICAgUm9sbE1vZFN0YXR1c1tcIlRvZ2dsZWRPblwiXSA9IFwiVG9nZ2xlZE9uXCI7XG4gICAgUm9sbE1vZFN0YXR1c1tcIkZvcmNlZE9uXCJdID0gXCJGb3JjZWRPblwiO1xuICAgIFJvbGxNb2RTdGF0dXNbXCJEb21pbmFudFwiXSA9IFwiRG9taW5hbnRcIjtcbn0pKFJvbGxNb2RTdGF0dXMgfHwgKFJvbGxNb2RTdGF0dXMgPSB7fSkpO1xuZXhwb3J0IHZhciBSb2xsTW9kU2VjdGlvbjtcbihmdW5jdGlvbiAoUm9sbE1vZFNlY3Rpb24pIHtcbiAgICBSb2xsTW9kU2VjdGlvbltcInJvbGxcIl0gPSBcInJvbGxcIjtcbiAgICBSb2xsTW9kU2VjdGlvbltcInBvc2l0aW9uXCJdID0gXCJwb3NpdGlvblwiO1xuICAgIFJvbGxNb2RTZWN0aW9uW1wiZWZmZWN0XCJdID0gXCJlZmZlY3RcIjtcbiAgICBSb2xsTW9kU2VjdGlvbltcInJlc3VsdFwiXSA9IFwicmVzdWx0XCI7XG4gICAgUm9sbE1vZFNlY3Rpb25bXCJhZnRlclwiXSA9IFwiYWZ0ZXJcIjtcbn0pKFJvbGxNb2RTZWN0aW9uIHx8IChSb2xsTW9kU2VjdGlvbiA9IHt9KSk7XG5leHBvcnQgdmFyIFBvc2l0aW9uO1xuKGZ1bmN0aW9uIChQb3NpdGlvbikge1xuICAgIFBvc2l0aW9uW1wiZGVzcGVyYXRlXCJdID0gXCJkZXNwZXJhdGVcIjtcbiAgICBQb3NpdGlvbltcInJpc2t5XCJdID0gXCJyaXNreVwiO1xuICAgIFBvc2l0aW9uW1wiY29udHJvbGxlZFwiXSA9IFwiY29udHJvbGxlZFwiO1xufSkoUG9zaXRpb24gfHwgKFBvc2l0aW9uID0ge30pKTtcbmV4cG9ydCB2YXIgRWZmZWN0O1xuKGZ1bmN0aW9uIChFZmZlY3QpIHtcbiAgICBFZmZlY3RbXCJ6ZXJvXCJdID0gXCJ6ZXJvXCI7XG4gICAgRWZmZWN0W1wibGltaXRlZFwiXSA9IFwibGltaXRlZFwiO1xuICAgIEVmZmVjdFtcInN0YW5kYXJkXCJdID0gXCJzdGFuZGFyZFwiO1xuICAgIEVmZmVjdFtcImdyZWF0XCJdID0gXCJncmVhdFwiO1xuICAgIEVmZmVjdFtcImV4dHJlbWVcIl0gPSBcImV4dHJlbWVcIjtcbn0pKEVmZmVjdCB8fCAoRWZmZWN0ID0ge30pKTtcbmV4cG9ydCB2YXIgRmFjdG9yO1xuKGZ1bmN0aW9uIChGYWN0b3IpIHtcbiAgICBGYWN0b3JbXCJ0aWVyXCJdID0gXCJ0aWVyXCI7XG4gICAgRmFjdG9yW1wicXVhbGl0eVwiXSA9IFwicXVhbGl0eVwiO1xuICAgIEZhY3RvcltcInNjYWxlXCJdID0gXCJzY2FsZVwiO1xuICAgIEZhY3RvcltcIm1hZ25pdHVkZVwiXSA9IFwibWFnbml0dWRlXCI7XG59KShGYWN0b3IgfHwgKEZhY3RvciA9IHt9KSk7XG5leHBvcnQgdmFyIFJvbGxSZXN1bHQ7XG4oZnVuY3Rpb24gKFJvbGxSZXN1bHQpIHtcbiAgICBSb2xsUmVzdWx0W1wiY3JpdGljYWxcIl0gPSBcImNyaXRpY2FsXCI7XG4gICAgUm9sbFJlc3VsdFtcInN1Y2Nlc3NcIl0gPSBcInN1Y2Nlc3NcIjtcbiAgICBSb2xsUmVzdWx0W1wicGFydGlhbFwiXSA9IFwicGFydGlhbFwiO1xuICAgIFJvbGxSZXN1bHRbXCJmYWlsXCJdID0gXCJmYWlsXCI7XG59KShSb2xsUmVzdWx0IHx8IChSb2xsUmVzdWx0ID0ge30pKTtcbmV4cG9ydCB2YXIgUm9sbFBoYXNlO1xuKGZ1bmN0aW9uIChSb2xsUGhhc2UpIHtcbiAgICAvLyBDb2xsYWJvcmF0aW9uOiBCZWZvcmUgR00gdG9nZ2xlcyBcIlJvbGxcIiBidXR0b24gZm9yIHBsYXllciB0byBjbGljay5cbiAgICBSb2xsUGhhc2VbXCJDb2xsYWJvcmF0aW9uXCJdID0gXCJDb2xsYWJvcmF0aW9uXCI7XG4gICAgLy8gQXdhaXRpbmdSb2xsOiBXYWl0aW5nIGZvciBwbGF5ZXIgdG8gY2xpY2sgXCJST0xMXCJcbiAgICBSb2xsUGhhc2VbXCJBd2FpdGluZ1JvbGxcIl0gPSBcIkF3YWl0aW5nUm9sbFwiO1xuICAgIC8vIEF3YWl0aW5nQ29uc2VxdWVuY2VzOiBXYWl0aW5nIGZvciBwbGF5ZXIgdG8gcmVzaXN0IG9yIGFjY2VwdCBjb25zZXF1ZW5jZXNcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgIGluIGNoYXQuIE9ubHkgbW92ZXMgdG8gJ0NvbXBsZXRlJyB3aGVuIGFsbCBjb25zZXF1ZW5jZXNcbiAgICAvLyAgICAgICAgICAgICAgICAgICAgICAgIGhhdmUgYmVlbiBhY2NlcHRlZCBvciBuZWdhdGVkLiAoUmVzaXN0ZWQgY29uc2VxdWVuY2VzXG4gICAgLy8gICAgICAgICAgICAgICAgICAgICAgICBtdXN0IHN0aWxsIGJlIGFjY2VwdGVkLCBzaW5jZSBwbGF5ZXIgY291bGQgZWxlY3QgdG8gdXNlIGFybW9yLilcbiAgICBSb2xsUGhhc2VbXCJBd2FpdGluZ0NvbnNlcXVlbmNlc1wiXSA9IFwiQXdhaXRpbmdDb25zZXF1ZW5jZXNcIjtcbiAgICAvLyBDb21wbGV0ZTogUm9sbCBmaW5pc2hlZC5cbiAgICBSb2xsUGhhc2VbXCJDb21wbGV0ZVwiXSA9IFwiQ29tcGxldGVcIjtcbn0pKFJvbGxQaGFzZSB8fCAoUm9sbFBoYXNlID0ge30pKTtcbmV4cG9ydCB2YXIgSGFybTtcbihmdW5jdGlvbiAoSGFybSkge1xuICAgIEhhcm1bXCJXZWFrZW5lZFwiXSA9IFwiV2Vha2VuZWRcIjtcbiAgICBIYXJtW1wiSW1wYWlyZWRcIl0gPSBcIkltcGFpcmVkXCI7XG4gICAgSGFybVtcIkJyb2tlblwiXSA9IFwiQnJva2VuXCI7XG4gICAgSGFybVtcIkRlYWRcIl0gPSBcIkRlYWRcIjtcbn0pKEhhcm0gfHwgKEhhcm0gPSB7fSkpO1xuZXhwb3J0IHZhciBWaWNlO1xuKGZ1bmN0aW9uIChWaWNlKSB7XG4gICAgVmljZVtcIkZhaXRoXCJdID0gXCJGYWl0aFwiO1xuICAgIFZpY2VbXCJHYW1ibGluZ1wiXSA9IFwiR2FtYmxpbmdcIjtcbiAgICBWaWNlW1wiTHV4dXJ5XCJdID0gXCJMdXh1cnlcIjtcbiAgICBWaWNlW1wiT2JsaWdhdGlvblwiXSA9IFwiT2JsaWdhdGlvblwiO1xuICAgIFZpY2VbXCJQbGVhc3VyZVwiXSA9IFwiUGxlYXN1cmVcIjtcbiAgICBWaWNlW1wiU3R1cG9yXCJdID0gXCJTdHVwb3JcIjtcbiAgICBWaWNlW1wiV2VpcmRcIl0gPSBcIldlaXJkXCI7XG4gICAgVmljZVtcIldvcnNoaXBcIl0gPSBcIldvcnNoaXBcIjtcbiAgICBWaWNlW1wiTGlmZV9Fc3NlbmNlXCJdID0gXCJMaWZlX0Vzc2VuY2VcIjtcbiAgICBWaWNlW1wiTGl2aW5nX0Vzc2VuY2VcIl0gPSBcIkxpdmluZ19Fc3NlbmNlXCI7XG4gICAgVmljZVtcIkVsZWN0cm9wbGFzbWljX1Bvd2VyXCJdID0gXCJFbGVjdHJvcGxhc21pY19Qb3dlclwiO1xuICAgIFZpY2VbXCJTZXJ2aXR1ZGVcIl0gPSBcIlNlcnZpdHVkZVwiO1xufSkoVmljZSB8fCAoVmljZSA9IHt9KSk7XG5leHBvcnQgdmFyIFBsYXlib29rO1xuKGZ1bmN0aW9uIChQbGF5Ym9vaykge1xuICAgIFBsYXlib29rW1wiQ3V0dGVyXCJdID0gXCJDdXR0ZXJcIjtcbiAgICBQbGF5Ym9va1tcIkhvdW5kXCJdID0gXCJIb3VuZFwiO1xuICAgIFBsYXlib29rW1wiTGVlY2hcIl0gPSBcIkxlZWNoXCI7XG4gICAgUGxheWJvb2tbXCJMdXJrXCJdID0gXCJMdXJrXCI7XG4gICAgUGxheWJvb2tbXCJTbGlkZVwiXSA9IFwiU2xpZGVcIjtcbiAgICBQbGF5Ym9va1tcIlNwaWRlclwiXSA9IFwiU3BpZGVyXCI7XG4gICAgUGxheWJvb2tbXCJXaGlzcGVyXCJdID0gXCJXaGlzcGVyXCI7XG4gICAgUGxheWJvb2tbXCJWYW1waXJlXCJdID0gXCJWYW1waXJlXCI7XG4gICAgUGxheWJvb2tbXCJIdWxsXCJdID0gXCJIdWxsXCI7XG4gICAgUGxheWJvb2tbXCJHaG9zdFwiXSA9IFwiR2hvc3RcIjtcbiAgICBQbGF5Ym9va1tcIkFzc2Fzc2luc1wiXSA9IFwiQXNzYXNzaW5zXCI7XG4gICAgUGxheWJvb2tbXCJCcmF2b3NcIl0gPSBcIkJyYXZvc1wiO1xuICAgIFBsYXlib29rW1wiQ3VsdFwiXSA9IFwiQ3VsdFwiO1xuICAgIFBsYXlib29rW1wiSGF3a2Vyc1wiXSA9IFwiSGF3a2Vyc1wiO1xuICAgIFBsYXlib29rW1wiU2hhZG93c1wiXSA9IFwiU2hhZG93c1wiO1xuICAgIFBsYXlib29rW1wiU211Z2dsZXJzXCJdID0gXCJTbXVnZ2xlcnNcIjtcbiAgICBQbGF5Ym9va1tcIlZpZ2lsYW50ZXNcIl0gPSBcIlZpZ2lsYW50ZXNcIjtcbn0pKFBsYXlib29rIHx8IChQbGF5Ym9vayA9IHt9KSk7XG5leHBvcnQgdmFyIEFkdmFuY2VtZW50UG9pbnQ7XG4oZnVuY3Rpb24gKEFkdmFuY2VtZW50UG9pbnQpIHtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiVXBncmFkZU9yQWJpbGl0eVwiXSA9IFwiVXBncmFkZU9yQWJpbGl0eVwiO1xuICAgIEFkdmFuY2VtZW50UG9pbnRbXCJBYmlsaXR5XCJdID0gXCJBYmlsaXR5XCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcIlVwZ3JhZGVcIl0gPSBcIlVwZ3JhZGVcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiQ29ob3J0XCJdID0gXCJDb2hvcnRcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiQ29ob3J0VHlwZVwiXSA9IFwiQ29ob3J0VHlwZVwiO1xuICAgIEFkdmFuY2VtZW50UG9pbnRbXCJHZW5lcmFsQWN0aW9uXCJdID0gXCJHZW5lcmFsQWN0aW9uXCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcIkdlbmVyYWxJbnNpZ2h0XCJdID0gXCJHZW5lcmFsSW5zaWdodFwiO1xuICAgIEFkdmFuY2VtZW50UG9pbnRbXCJHZW5lcmFsUHJvd2Vzc1wiXSA9IFwiR2VuZXJhbFByb3dlc3NcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiR2VuZXJhbFJlc29sdmVcIl0gPSBcIkdlbmVyYWxSZXNvbHZlXCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcImh1bnRcIl0gPSBcImh1bnRcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wic3R1ZHlcIl0gPSBcInN0dWR5XCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcInN1cnZleVwiXSA9IFwic3VydmV5XCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcInRpbmtlclwiXSA9IFwidGlua2VyXCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcImZpbmVzc2VcIl0gPSBcImZpbmVzc2VcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wicHJvd2xcIl0gPSBcInByb3dsXCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcInNraXJtaXNoXCJdID0gXCJza2lybWlzaFwiO1xuICAgIEFkdmFuY2VtZW50UG9pbnRbXCJ3cmVja1wiXSA9IFwid3JlY2tcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiYXR0dW5lXCJdID0gXCJhdHR1bmVcIjtcbiAgICBBZHZhbmNlbWVudFBvaW50W1wiY29tbWFuZFwiXSA9IFwiY29tbWFuZFwiO1xuICAgIEFkdmFuY2VtZW50UG9pbnRbXCJjb25zb3J0XCJdID0gXCJjb25zb3J0XCI7XG4gICAgQWR2YW5jZW1lbnRQb2ludFtcInN3YXlcIl0gPSBcInN3YXlcIjtcbn0pKEFkdmFuY2VtZW50UG9pbnQgfHwgKEFkdmFuY2VtZW50UG9pbnQgPSB7fSkpO1xuZXhwb3J0IHZhciBCbGFkZXNQaGFzZTtcbihmdW5jdGlvbiAoQmxhZGVzUGhhc2UpIHtcbiAgICBCbGFkZXNQaGFzZVtcIkNoYXJHZW5cIl0gPSBcIkNoYXJHZW5cIjtcbiAgICBCbGFkZXNQaGFzZVtcIkZyZWVwbGF5XCJdID0gXCJGcmVlcGxheVwiO1xuICAgIEJsYWRlc1BoYXNlW1wiU2NvcmVcIl0gPSBcIlNjb3JlXCI7XG4gICAgQmxhZGVzUGhhc2VbXCJEb3dudGltZVwiXSA9IFwiRG93bnRpbWVcIjtcbn0pKEJsYWRlc1BoYXNlIHx8IChCbGFkZXNQaGFzZSA9IHt9KSk7XG5leHBvcnQgdmFyIFRhZztcbihmdW5jdGlvbiAoVGFnKSB7XG4gICAgbGV0IFN5c3RlbTtcbiAgICAoZnVuY3Rpb24gKFN5c3RlbSkge1xuICAgICAgICBTeXN0ZW1bXCJBcmNoaXZlZFwiXSA9IFwiQXJjaGl2ZWRcIjtcbiAgICAgICAgU3lzdGVtW1wiRmVhdHVyZWRcIl0gPSBcIkZlYXR1cmVkXCI7XG4gICAgICAgIFN5c3RlbVtcIkhpZGRlblwiXSA9IFwiSGlkZGVuXCI7XG4gICAgICAgIFN5c3RlbVtcIk11bHRpcGxlc09LXCJdID0gXCJNdWx0aXBsZXNPS1wiO1xuICAgIH0pKFN5c3RlbSA9IFRhZy5TeXN0ZW0gfHwgKFRhZy5TeXN0ZW0gPSB7fSkpO1xuICAgIGxldCBHZWFyO1xuICAgIChmdW5jdGlvbiAoR2Vhcikge1xuICAgICAgICBHZWFyW1wiRmluZVwiXSA9IFwiRmluZVwiO1xuICAgICAgICBHZWFyW1wiR2VuZXJhbFwiXSA9IFwiR2VuZXJhbFwiO1xuICAgICAgICBHZWFyW1wiQWR2YW5jZWRcIl0gPSBcIkFkdmFuY2VkXCI7XG4gICAgICAgIEdlYXJbXCJVcGdyYWRlZFwiXSA9IFwiVXBncmFkZWRcIjtcbiAgICB9KShHZWFyID0gVGFnLkdlYXIgfHwgKFRhZy5HZWFyID0ge30pKTtcbiAgICBsZXQgUEM7XG4gICAgKGZ1bmN0aW9uIChQQykge1xuICAgICAgICBQQ1tcIk1lbWJlclwiXSA9IFwiTWVtYmVyXCI7XG4gICAgICAgIFBDW1wiQ2hhcmFjdGVyQ3Jld1wiXSA9IFwiQ2hhcmFjdGVyQ3Jld1wiO1xuICAgICAgICBQQ1tcIkFjdGl2ZVBDXCJdID0gXCJBY3RpdmVQQ1wiO1xuICAgICAgICBQQ1tcIlNtYWxsXCJdID0gXCJTbWFsbFwiO1xuICAgICAgICBQQ1tcIk1lZGl1bVwiXSA9IFwiTWVkaXVtXCI7XG4gICAgICAgIFBDW1wiTGFyZ2VcIl0gPSBcIkxhcmdlXCI7XG4gICAgICAgIFBDW1wiQ2FuSGVhbFwiXSA9IFwiQ2FuSGVhbFwiO1xuICAgIH0pKFBDID0gVGFnLlBDIHx8IChUYWcuUEMgPSB7fSkpO1xuICAgIGxldCBJbnZlbnRpb247XG4gICAgKGZ1bmN0aW9uIChJbnZlbnRpb24pIHtcbiAgICAgICAgSW52ZW50aW9uW1wiQXJjYW5lXCJdID0gXCJBcmNhbmVcIjtcbiAgICAgICAgSW52ZW50aW9uW1wiU3BhcmtDcmFmdFwiXSA9IFwiU3BhcmtDcmFmdFwiO1xuICAgICAgICBJbnZlbnRpb25bXCJBbGNoZW1pY2FsXCJdID0gXCJBbGNoZW1pY2FsXCI7XG4gICAgICAgIEludmVudGlvbltcIk11bmRhbmVcIl0gPSBcIk11bmRhbmVcIjtcbiAgICAgICAgSW52ZW50aW9uW1wiUml0dWFsXCJdID0gXCJSaXR1YWxcIjsgLy8gUml0dWFsc1xuICAgIH0pKEludmVudGlvbiA9IFRhZy5JbnZlbnRpb24gfHwgKFRhZy5JbnZlbnRpb24gPSB7fSkpO1xuICAgIGxldCBHZWFyQ2F0ZWdvcnk7XG4gICAgKGZ1bmN0aW9uIChHZWFyQ2F0ZWdvcnkpIHtcbiAgICAgICAgR2VhckNhdGVnb3J5W1wiQXJjYW5lSW1wbGVtZW50XCJdID0gXCJBcmNhbmVJbXBsZW1lbnRcIjtcbiAgICAgICAgR2VhckNhdGVnb3J5W1wiRG9jdW1lbnRcIl0gPSBcIkRvY3VtZW50XCI7XG4gICAgICAgIEdlYXJDYXRlZ29yeVtcIkdlYXJLaXRcIl0gPSBcIkdlYXJLaXRcIjtcbiAgICAgICAgR2VhckNhdGVnb3J5W1wiU3VidGVyZnVnZVN1cHBsaWVzXCJdID0gXCJTdWJ0ZXJmdWdlU3VwcGxpZXNcIjtcbiAgICAgICAgR2VhckNhdGVnb3J5W1wiVG9vbFwiXSA9IFwiVG9vbFwiO1xuICAgICAgICBHZWFyQ2F0ZWdvcnlbXCJXZWFwb25cIl0gPSBcIldlYXBvblwiO1xuICAgIH0pKEdlYXJDYXRlZ29yeSA9IFRhZy5HZWFyQ2F0ZWdvcnkgfHwgKFRhZy5HZWFyQ2F0ZWdvcnkgPSB7fSkpO1xuICAgIGxldCBOUEM7XG4gICAgKGZ1bmN0aW9uIChOUEMpIHtcbiAgICAgICAgTlBDW1wiQWNxdWFpbnRhbmNlXCJdID0gXCJBY3F1YWludGFuY2VcIjtcbiAgICAgICAgTlBDW1wiVmljZVB1cnZleW9yXCJdID0gXCJWaWNlUHVydmV5b3JcIjtcbiAgICAgICAgTlBDW1wiQ2FuSGVhbFwiXSA9IFwiQ2FuSGVhbFwiO1xuICAgIH0pKE5QQyA9IFRhZy5OUEMgfHwgKFRhZy5OUEMgPSB7fSkpO1xuICAgIGxldCBHYW5nVHlwZTtcbiAgICAoZnVuY3Rpb24gKEdhbmdUeXBlKSB7XG4gICAgICAgIEdhbmdUeXBlW1wiVGh1Z3NcIl0gPSBcIlRodWdzXCI7XG4gICAgICAgIEdhbmdUeXBlW1wiUm9va3NcIl0gPSBcIlJvb2tzXCI7XG4gICAgICAgIEdhbmdUeXBlW1wiQWRlcHRzXCJdID0gXCJBZGVwdHNcIjtcbiAgICAgICAgR2FuZ1R5cGVbXCJSb3ZlcnNcIl0gPSBcIlJvdmVyc1wiO1xuICAgICAgICBHYW5nVHlwZVtcIlNrdWxrc1wiXSA9IFwiU2t1bGtzXCI7XG4gICAgICAgIEdhbmdUeXBlW1wiVmVoaWNsZVwiXSA9IFwiVmVoaWNsZVwiO1xuICAgIH0pKEdhbmdUeXBlID0gVGFnLkdhbmdUeXBlIHx8IChUYWcuR2FuZ1R5cGUgPSB7fSkpO1xufSkoVGFnIHx8IChUYWcgPSB7fSkpO1xuLy8gI2VuZHJlZ2lvblxuLy8gI3JlZ2lvbiAnQycgQ09OU1RBTlRTIERFRklOSVRJT05TIH5cbmNvbnN0IEMgPSB7XG4gICAgU1lTVEVNX0lEOiBcImV1bm9zLWJsYWRlc1wiLFxuICAgIFNZU1RFTV9OQU1FOiBcIkV1bm8ncyBCbGFkZXNcIixcbiAgICBTWVNURU1fRlVMTF9OQU1FOiBcIkV1bm8ncyBCbGFkZXMgSW4gVGhlIERhcmtcIixcbiAgICBURU1QTEFURV9ST09UOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlc1wiLFxuICAgIEFJX01PREVMUzoge1xuICAgICAgICBiYXNlQ29udGV4dDogW1xuICAgICAgICAgICAgXCJiYWJiYWdlLTAwMlwiLFxuICAgICAgICAgICAgXCJncHQtMy41LXR1cmJvXCIsXG4gICAgICAgICAgICBcImdwdC00XCJcbiAgICAgICAgXSxcbiAgICAgICAgZXh0ZW5kZWRDb250ZXh0OiBbXG4gICAgICAgICAgICBcImdwdC0zLjUtdHVyYm8tMTZrXCIsXG4gICAgICAgICAgICBcImdwdC0zLjUtdHVyYm8tMTZrXCIsXG4gICAgICAgICAgICBcImdwdC00LTMya1wiXG4gICAgICAgIF1cbiAgICB9LFxuICAgIE1JTl9NT1VTRV9NT1ZFTUVOVF9USFJFU0hPTEQ6IDIwMDAsXG4gICAgQUlfRklMRV9JRFM6IHtcbiAgICAgICAgQmxhZGVzUERGOiBcImZpbGUtbjcySFRUTnd0MDUxcGlQYnN3UThpc1VhXCJcbiAgICB9LFxuICAgIENsb2NrS2V5U3F1YXJlU2l6ZTogMTAwLFxuICAgIERvd250aW1lQWN0aW9uRGlzcGxheToge1xuICAgICAgICBbRG93bnRpbWVBY3Rpb24uQWNxdWlyZUFzc2V0XTogXCJBY3F1aXJlIGFuIEFzc2V0XCIsXG4gICAgICAgIFtEb3dudGltZUFjdGlvbi5JbmR1bGdlVmljZV06IFwiSW5kdWxnZSBZb3VyIFZpY2VcIixcbiAgICAgICAgW0Rvd250aW1lQWN0aW9uLkxvbmdUZXJtUHJvamVjdF06IFwiV29yayBvbiBhIFByb2plY3RcIixcbiAgICAgICAgW0Rvd250aW1lQWN0aW9uLlJlY292ZXJdOiBcIkhlYWxcIixcbiAgICAgICAgW0Rvd250aW1lQWN0aW9uLlJlZHVjZUhlYXRdOiBcIlJlZHVjZSB0aGUgQ3JldydzIEhlYXRcIixcbiAgICAgICAgW0Rvd250aW1lQWN0aW9uLlRyYWluXTogXCJUcmFpblwiXG4gICAgfSxcbiAgICBDb25zZXF1ZW5jZVZhbHVlczoge1xuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlZHVjZWRFZmZlY3RdOiB1bmRlZmluZWQsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuTG9zdE9wcG9ydHVuaXR5XTogMixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Xb3JzZVBvc2l0aW9uXTogdW5kZWZpbmVkLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLk5vbmVdOiAwLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtNF06IDQsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0zXTogMyxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTJdOiAyLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtMV06IDEsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm00XTogNCxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTNdOiAzLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtMl06IDIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0xXTogMSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTRdOiA0LFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtM106IDMsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0yXTogMixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTFdOiAxLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkNvbXBsaWNhdGlvblNlcmlvdXNdOiAzLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkNvbXBsaWNhdGlvbk1ham9yXTogMixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25NaW5vcl06IDFcbiAgICB9LFxuICAgIFJlc2lzdGVkQ29uc2VxdWVuY2VUeXBlczoge1xuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLk5vbmVdOiBbXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTRdOiBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtM10sXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0zXTogW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTJdLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtMl06IFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0xXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTFdOiBbQ29uc2VxdWVuY2VUeXBlLk5vbmVdLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtNF06IFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0zXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTNdOiBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtMl0sXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0yXTogW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTFdLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtMV06IFtDb25zZXF1ZW5jZVR5cGUuTm9uZV0sXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm00XTogW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTNdLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtM106IFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0yXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTJdOiBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtMV0sXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0xXTogW0NvbnNlcXVlbmNlVHlwZS5Ob25lXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25TZXJpb3VzXTogW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25NYWpvcl0sXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuQ29tcGxpY2F0aW9uTWFqb3JdOiBbQ29uc2VxdWVuY2VUeXBlLkNvbXBsaWNhdGlvbk1pbm9yXSxcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25NaW5vcl06IFtDb25zZXF1ZW5jZVR5cGUuTm9uZV1cbiAgICB9LFxuICAgIENvbnNlcXVlbmNlRGlzcGxheToge1xuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlZHVjZWRFZmZlY3RdOiBcIlJlZHVjZWQgRWZmZWN0XCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuQ29tcGxpY2F0aW9uTWlub3JdOiBcIk1pbm9yIENvbXBsaWNhdGlvblwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkNvbXBsaWNhdGlvbk1ham9yXTogXCJNYWpvciBDb21wbGljYXRpb25cIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25TZXJpb3VzXTogXCJTZXJpb3VzIENvbXBsaWNhdGlvblwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkxvc3RPcHBvcnR1bml0eV06IFwiTG9zdCBPcHBvcnR1bml0eVwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLldvcnNlUG9zaXRpb25dOiBcIldvcnNlIFBvc2l0aW9uXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0xXTogXCJMZXZlbCAxIEhhcm0gKExlc3NlcilcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTJdOiBcIkxldmVsIDIgSGFybSAoTW9kZXJhdGUpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0zXTogXCJMZXZlbCAzIEhhcm0gKFNldmVyZSlcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTRdOiBcIkxldmVsIDQgSGFybSAoRkFUQUwpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0xXTogXCJMZXZlbCAxIEhhcm0gKExlc3NlcilcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTJdOiBcIkxldmVsIDIgSGFybSAoTW9kZXJhdGUpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0zXTogXCJMZXZlbCAzIEhhcm0gKFNldmVyZSlcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTRdOiBcIkxldmVsIDQgSGFybSAoRkFUQUwpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0xXTogXCJMZXZlbCAxIEhhcm0gKExlc3NlcilcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTJdOiBcIkxldmVsIDIgSGFybSAoTW9kZXJhdGUpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0zXTogXCJMZXZlbCAzIEhhcm0gKFNldmVyZSlcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTRdOiBcIkxldmVsIDQgSGFybSAoRkFUQUwpXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuTm9uZV06IFwiTm9uZVwiXG4gICAgfSxcbiAgICBDb25zZXF1ZW5jZUljb25zOiB7XG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVkdWNlZEVmZmVjdF06IFwicmVkdWNlZC1lZmZlY3RcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25NaW5vcl06IFwiY29tcGxpY2F0aW9uLW1pbm9yXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuQ29tcGxpY2F0aW9uTWFqb3JdOiBcImNvbXBsaWNhdGlvbi1tYWpvclwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkNvbXBsaWNhdGlvblNlcmlvdXNdOiBcImNvbXBsaWNhdGlvbi1zZXJpb3VzXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuTG9zdE9wcG9ydHVuaXR5XTogXCJsb3N0LW9wcG9ydHVuaXR5XCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuV29yc2VQb3NpdGlvbl06IFwid29yc2UtcG9zaXRpb25cIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTFdOiBcImhhcm0taW5zaWdodC0xXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0yXTogXCJoYXJtLWluc2lnaHQtMlwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtM106IFwiaGFybS1pbnNpZ2h0LTNcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5JbnNpZ2h0SGFybTRdOiBcImhhcm0taW5zaWdodC00XCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm0xXTogXCJoYXJtLXByb3dlc3MtMVwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtMl06IFwiaGFybS1wcm93ZXNzLTJcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTNdOiBcImhhcm0tcHJvd2Vzcy0zXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm00XTogXCJoYXJtLXByb3dlc3MtNFwiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtMV06IFwiaGFybS1yZXNvbHZlLTFcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTJdOiBcImhhcm0tcmVzb2x2ZS0yXCIsXG4gICAgICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0zXTogXCJoYXJtLXJlc29sdmUtM1wiLFxuICAgICAgICBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtNF06IFwiaGFybS1yZXNvbHZlLTRcIixcbiAgICAgICAgW0NvbnNlcXVlbmNlVHlwZS5Ob25lXTogXCJcIlxuICAgIH0sXG4gICAgUm9sbFJlc3VsdERlc2NyaXB0aW9uczoge1xuICAgICAgICBbUG9zaXRpb24uY29udHJvbGxlZF06IHtcbiAgICAgICAgICAgIFtSb2xsUmVzdWx0LmNyaXRpY2FsXTogXCJZb3UgY3JpdGljYWxseSBzdWNjZWVkIGZyb20gYSBjb250cm9sbGVkIHBvc2l0aW9uIVwiLFxuICAgICAgICAgICAgW1JvbGxSZXN1bHQuc3VjY2Vzc106IFwiWW91IGZ1bGx5IHN1Y2NlZWQgZnJvbSBhIGNvbnRyb2xsZWQgcG9zaXRpb24hXCIsXG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5wYXJ0aWFsXTogXCJZb3UgcGFydGlhbGx5IHN1Y2NlZWQgZnJvbSBhIGNvbnRyb2xsZWQgcG9zaXRpb24hXCIsXG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5mYWlsXTogXCJZb3UgZmFpbCBmcm9tIGEgY29udHJvbGxlZCBwb3NpdGlvbiFcIlxuICAgICAgICB9LFxuICAgICAgICBbUG9zaXRpb24ucmlza3ldOiB7XG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5jcml0aWNhbF06IFwiWW91IGNyaXRpY2FsbHkgc3VjY2VlZCBmcm9tIGEgcmlza3kgcG9zaXRpb24hXCIsXG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5zdWNjZXNzXTogXCJZb3UgZnVsbHkgc3VjY2VlZCBmcm9tIGEgcmlza3kgcG9zaXRpb24hXCIsXG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5wYXJ0aWFsXTogXCJZb3UgcGFydGlhbGx5IHN1Y2NlZWQgZnJvbSBhIHJpc2t5IHBvc2l0aW9uIVwiLFxuICAgICAgICAgICAgW1JvbGxSZXN1bHQuZmFpbF06IFwiWW91IGZhaWwgZnJvbSBhIHJpc2t5IHBvc2l0aW9uIVwiXG4gICAgICAgIH0sXG4gICAgICAgIFtQb3NpdGlvbi5kZXNwZXJhdGVdOiB7XG4gICAgICAgICAgICBbUm9sbFJlc3VsdC5jcml0aWNhbF06IFwiWW91IGNyaXRpY2FsbHkgc3VjY2VlZCBmcm9tIGEgZGVzcGVyYXRlIHBvc2l0aW9uIVwiLFxuICAgICAgICAgICAgW1JvbGxSZXN1bHQuc3VjY2Vzc106IFwiWW91IGZ1bGx5IHN1Y2NlZWQgZnJvbSBhIGRlc3BlcmF0ZSBwb3NpdGlvbiFcIixcbiAgICAgICAgICAgIFtSb2xsUmVzdWx0LnBhcnRpYWxdOiBcIllvdSBwYXJ0aWFsbHkgc3VjY2VlZCBmcm9tIGEgZGVzcGVyYXRlIHBvc2l0aW9uIVwiLFxuICAgICAgICAgICAgW1JvbGxSZXN1bHQuZmFpbF06IFwiWW91IGZhaWwgZnJvbSBhIGRlc3BlcmF0ZSBwb3NpdGlvbiFcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBDb2xvcnM6IHtcbiAgICAgICAgYldISVRFOiBcInJnYmEoMjU1LCAyNTUsIDI1NSwgMSlcIixcbiAgICAgICAgV0hJVEU6IFwicmdiYSgyMDAsIDIwMCwgMjAwLCAxKVwiLFxuICAgICAgICBiR1JFWTogXCJyZ2JhKDE3MCwgMTcwLCAxNzAsIDEpXCIsXG4gICAgICAgIEdSRVk6IFwicmdiYSgxMTksIDExOSwgMTE5LCAxKVwiLFxuICAgICAgICBkR1JFWTogXCJyZ2JhKDY4LCA2OCwgNjgsIDEpXCIsXG4gICAgICAgIEJMQUNLOiBcInJnYmEoMzIsIDMyLCAzMiwgMSlcIixcbiAgICAgICAgZEJMQUNLOiBcInJnYmEoMCwgMCwgMCwgMSlcIixcbiAgICAgICAgYkdPTEQ6IFwicmdiYSgyNTUsMjE2LCA0NCwgMSlcIixcbiAgICAgICAgR09MRDogXCJyZ2JhKDIxNSwxNzUsICAwLCAxKVwiLFxuICAgICAgICBkR09MRDogXCJyZ2JhKDE2NSwxMzQsICAwLCAxKVwiLFxuICAgICAgICBkZEdPTEQ6IFwicmdiYSgxMDMsIDgzLCAgMCwgMSlcIixcbiAgICAgICAgYlJFRDogXCJyZ2JhKDI1NSwgMCwgMCwgMSlcIixcbiAgICAgICAgUkVEOiBcInJnYmEoMjAwLCAwLCAwLCAxKVwiLFxuICAgICAgICBkUkVEOiBcInJnYmEoMTUwLCAgMCwgIDAsIDEpXCIsXG4gICAgICAgIGRkUkVEOiBcInJnYmEoNTAsICAwLCAgMCwgMSlcIixcbiAgICAgICAgYkJMVUU6IFwicmdiYSggICAwLDIyNCwyMjQsIDEpXCIsXG4gICAgICAgIEJMVUU6IFwicmdiYSg1MiwyMTMsMjEzLCAxKVwiLFxuICAgICAgICBkQkxVRTogXCJyZ2JhKDAsMTE4LDExOCwgMSlcIixcbiAgICAgICAgZGRCTFVFOiBcInJnYmEoMCwgNzcsIDc3LCAxKVwiXG4gICAgfSxcbiAgICAvLyBDbG9ja0tleVBvc2l0aW9uczoge1xuICAgIC8vICAgZWxlbVNxdWFyZVNpemU6IDEwMCxcbiAgICAvLyAgIDA6IHtcbiAgICAvLyAgICAga2V5RGltZW5zaW9uczoge3dpZHRoOiAwLCBoZWlnaHQ6IDB9LFxuICAgIC8vICAgICBrZXlDZW50ZXI6IHt4OiAwLCB5OiAwfSxcbiAgICAvLyAgICAgY2xvY2tzQ2VudGVyOiB7eDogMCwgeTogMH0sXG4gICAgLy8gICAgIGNsb2Nrc0NlbnRlckRpbWVuc2lvbnM6IHt3aWR0aDogMCwgaGVpZ2h0OiAwfSxcbiAgICAvLyAgICAgY2xvY2tzOiB7fVxuICAgIC8vICAgfSxcbiAgICAvLyAgIDE6IHtcbiAgICAvLyAgICAga2V5RGltZW5zaW9uczoge3dpZHRoOiAyMzAsIGhlaWdodDogODM2fSxcbiAgICAvLyAgICAga2V5Q2VudGVyOiB7eDogMTE1LCB5OiA0MTh9LFxuICAgIC8vICAgICBjbG9ja3NDZW50ZXI6IHt4OiAxMTEuMDExLCB5OiAxMDguNX0sXG4gICAgLy8gICAgIGNsb2Nrc0NlbnRlckRpbWVuc2lvbnM6IHt3aWR0aDogMTY5LCBoZWlnaHQ6IDE2OX0sXG4gICAgLy8gICAgIGNsb2Nrczoge1xuICAgIC8vICAgICAgIDA6IHt4OiAxMTEuMDExLCB5OiAxMDguNSwgc2l6ZTogMTY5fVxuICAgIC8vICAgICB9XG4gICAgLy8gICB9LFxuICAgIC8vICAgMjoge1xuICAgIC8vICAgICBrZXlEaW1lbnNpb25zOiB7d2lkdGg6IDIwMiwgaGVpZ2h0OiA2MjV9LFxuICAgIC8vICAgICBrZXlDZW50ZXI6IHt4OiAxMDEsIHk6IDMxMn0sXG4gICAgLy8gICAgIGNsb2Nrc0NlbnRlcjoge3g6IDEwMSwgeTogMTg5fSxcbiAgICAvLyAgICAgY2xvY2tzQ2VudGVyRGltZW5zaW9uczoge3dpZHRoOiAxMTAsIGhlaWdodDogMjkwfSxcbiAgICAvLyAgICAgY2xvY2tzOiB7XG4gICAgLy8gICAgICAgMDoge3g6IDEwMSwgeTogOTksIHNpemU6IDEwOH0sXG4gICAgLy8gICAgICAgMToge3g6IDEwMSwgeTogMjc5LCBzaXplOiAxMDh9XG4gICAgLy8gICAgIH1cbiAgICAvLyAgIH0sXG4gICAgLy8gICAzOiB7XG4gICAgLy8gICAgIGtleURpbWVuc2lvbnM6IHt3aWR0aDogMjgwLCBoZWlnaHQ6IDkxNX0sXG4gICAgLy8gICAgIGtleUNlbnRlcjoge3g6IDE0MCwgeTogNDU3fSxcbiAgICAvLyAgICAgY2xvY2tzQ2VudGVyOiB7eDogMTQwLCB5OiAxNjl9LFxuICAgIC8vICAgICBjbG9ja3NDZW50ZXJEaW1lbnNpb25zOiB7d2lkdGg6IDI0MiwgaGVpZ2h0OiAyMjJ9LFxuICAgIC8vICAgICBjbG9ja3M6IHtcbiAgICAvLyAgICAgICAwOiB7eDogMTQwLCB5OiA5OSwgc2l6ZTogMTA4fSxcbiAgICAvLyAgICAgICAxOiB7eDogNzQsIHk6IDIxMSwgc2l6ZTogMTA4fSxcbiAgICAvLyAgICAgICAyOiB7eDogMjA2LCB5OiAyMTEsIHNpemU6IDEwOH1cbiAgICAvLyAgICAgfVxuICAgIC8vICAgfSxcbiAgICAvLyAgIDQ6IHtcbiAgICAvLyAgICAga2V5RGltZW5zaW9uczoge3dpZHRoOiAzNzYsIGhlaWdodDogMTE0MH0sXG4gICAgLy8gICAgIGtleUNlbnRlcjoge3g6IDE4OCwgeTogNTcwfSxcbiAgICAvLyAgICAgY2xvY2tzQ2VudGVyOiB7eDogMTg4LCB5OiAxODV9LFxuICAgIC8vICAgICBjbG9ja3NDZW50ZXJEaW1lbnNpb25zOiB7d2lkdGg6IDI4NCwgaGVpZ2h0OiAyODJ9LFxuICAgIC8vICAgICBjbG9ja3M6IHtcbiAgICAvLyAgICAgICAwOiB7eDogMTg4LCB5OiA5OSwgc2l6ZTogMTA4fSwgLy8geVRvcCA9IDQ1XG4gICAgLy8gICAgICAgMToge3g6IDEwMSwgeTogMTg1LCBzaXplOiAxMDh9LFxuICAgIC8vICAgICAgIDI6IHt4OiAyNzUsIHk6IDE4NSwgc2l6ZTogMTA4fSxcbiAgICAvLyAgICAgICAzOiB7eDogMTg4LCB5OiAyNzMsIHNpemU6IDEwOH0gLy8geUJvdHRvbSA9IDMyN1xuICAgIC8vICAgICB9XG4gICAgLy8gICB9LFxuICAgIC8vICAgNToge1xuICAgIC8vICAgICBrZXlEaW1lbnNpb25zOiB7d2lkdGg6IDM3NiwgaGVpZ2h0OiAxMTQwfSxcbiAgICAvLyAgICAga2V5Q2VudGVyOiB7eDogMTg4LCB5OiA1NzB9LFxuICAgIC8vICAgICBjbG9ja3NDZW50ZXI6IHt4OiAxODgsIHk6IDE4NX0sXG4gICAgLy8gICAgIGNsb2Nrc0NlbnRlckRpbWVuc2lvbnM6IHt3aWR0aDogMjg0LCBoZWlnaHQ6IDM4NH0sXG4gICAgLy8gICAgIGNsb2Nrczoge1xuICAgIC8vICAgICAgIDA6IHt4OiAxODgsIHk6IDk5LCBzaXplOiAxMDh9LCAvLyB5VG9wID0gNDVcbiAgICAvLyAgICAgICAxOiB7eDogMTAxLCB5OiAxODUsIHNpemU6IDEwOH0sXG4gICAgLy8gICAgICAgMjoge3g6IDI3NSwgeTogMTg1LCBzaXplOiAxMDh9LFxuICAgIC8vICAgICAgIDM6IHt4OiAxODgsIHk6IDI3Mywgc2l6ZTogMTA4fSxcbiAgICAvLyAgICAgICA0OiB7eDogMTg4LCB5OiA0NTIsIHNpemU6IDEwOH0gLy8geUJvdHRvbSA9IDUwNlxuICAgIC8vICAgICB9XG4gICAgLy8gICB9LFxuICAgIC8vICAgNjoge1xuICAgIC8vICAgICBrZXlEaW1lbnNpb25zOiB7d2lkdGg6IDM3NiwgaGVpZ2h0OiAxMTQwfSxcbiAgICAvLyAgICAga2V5Q2VudGVyOiB7eDogMTg4LCB5OiA1NzB9LFxuICAgIC8vICAgICBjbG9ja3NDZW50ZXI6IHt4OiAxODgsIHk6IDM5MX0sXG4gICAgLy8gICAgIGNsb2Nrc0NlbnRlckRpbWVuc2lvbnM6IHt3aWR0aDogMjg0LCBoZWlnaHQ6IDY5Mn0sXG4gICAgLy8gICAgIGNsb2Nrczoge1xuICAgIC8vICAgICAgIDA6IHt4OiAxODgsIHk6IDk5LCBzaXplOiAxMDh9LCAvLyB5VG9wID0gNDVcbiAgICAvLyAgICAgICAxOiB7eDogMTAxLCB5OiAxODUsIHNpemU6IDEwOH0sXG4gICAgLy8gICAgICAgMjoge3g6IDI3NSwgeTogMTg1LCBzaXplOiAxMDh9LFxuICAgIC8vICAgICAgIDM6IHt4OiAxODgsIHk6IDI3Mywgc2l6ZTogMTA4fSxcbiAgICAvLyAgICAgICA0OiB7eDogMTg4LCB5OiA0NTIsIHNpemU6IDEwOH0sXG4gICAgLy8gICAgICAgNToge3g6IDE4OCwgeTogNjgzLCBzaXplOiAxMDh9IC8vIHlCb3R0b20gPSA3MzdcbiAgICAvLyAgICAgfVxuICAgIC8vICAgfVxuICAgIC8vIH0sXG4gICAgTG9hZG91dDoge1xuICAgICAgICBzZWxlY3Rpb25zOiBbXG4gICAgICAgICAgICB7IHZhbHVlOiBcIkxpZ2h0XCIsIGRpc3BsYXk6IFwiTGlnaHRcIiB9LFxuICAgICAgICAgICAgeyB2YWx1ZTogXCJOb3JtYWxcIiwgZGlzcGxheTogXCJOb3JtYWxcIiB9LFxuICAgICAgICAgICAgeyB2YWx1ZTogXCJIZWF2eVwiLCBkaXNwbGF5OiBcIkhlYXZ5XCIgfVxuICAgICAgICBdLFxuICAgICAgICBsZXZlbHM6IFtcIkJJVEQuTGlnaHRcIiwgXCJCSVRELk5vcm1hbFwiLCBcIkJJVEQuSGVhdnlcIiwgXCJCSVRELkVuY3VtYmVyZWRcIiwgXCJCSVRELk92ZXJNYXhcIl1cbiAgICB9LFxuICAgIEF0dHJpYnV0ZVRvb2x0aXBzOiB7XG4gICAgICAgIFtBdHRyaWJ1dGVUcmFpdC5pbnNpZ2h0XTogXCI8cD5SZXNpc3RzIGNvbnNlcXVlbmNlcyBmcm9tIDxzdHJvbmc+ZGVjZXB0aW9uPC9zdHJvbmc+IG9yIDxzdHJvbmc+dW5kZXJzdGFuZGluZzwvc3Ryb25nPjwvcD5cIixcbiAgICAgICAgW0F0dHJpYnV0ZVRyYWl0LnByb3dlc3NdOiBcIjxwPlJlc2lzdHMgY29uc2VxdWVuY2VzIGZyb20gPHN0cm9uZz5waHlzaWNhbCBzdHJhaW48L3N0cm9uZz4gb3IgPHN0cm9uZz5pbmp1cnk8L3N0cm9uZz48L3A+XCIsXG4gICAgICAgIFtBdHRyaWJ1dGVUcmFpdC5yZXNvbHZlXTogXCI8cD5SZXNpc3RzIGNvbnNlcXVlbmNlcyBmcm9tIDxzdHJvbmc+bWVudGFsIHN0cmFpbjwvc3Ryb25nPiBvciA8c3Ryb25nPndpbGxwb3dlcjwvc3Ryb25nPjwvcD5cIlxuICAgIH0sXG4gICAgU2hvcnRBdHRyaWJ1dGVUb29sdGlwczoge1xuICAgICAgICBbQXR0cmlidXRlVHJhaXQuaW5zaWdodF06IFwidnMuIDxzdHJvbmc+ZGVjZXB0aW9uPC9zdHJvbmc+IG9yIDxzdHJvbmc+KG1pcyl1bmRlcnN0YW5kaW5nPC9zdHJvbmc+XCIsXG4gICAgICAgIFtBdHRyaWJ1dGVUcmFpdC5wcm93ZXNzXTogXCJ2cy4gPHN0cm9uZz5waHlzaWNhbCBzdHJhaW48L3N0cm9uZz4gb3IgPHN0cm9uZz5pbmp1cnk8L3N0cm9uZz5cIixcbiAgICAgICAgW0F0dHJpYnV0ZVRyYWl0LnJlc29sdmVdOiBcInZzLiA8c3Ryb25nPm1lbnRhbCBzdHJhaW48L3N0cm9uZz4gb3IgPHN0cm9uZz53aWxscG93ZXI8L3N0cm9uZz5cIlxuICAgIH0sXG4gICAgU2hvcnRBY3Rpb25Ub29sdGlwczoge1xuICAgICAgICBbQWN0aW9uVHJhaXQuaHVudF06IFwiY2FyZWZ1bGx5IHRyYWNrIGEgdGFyZ2V0XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zdHVkeV06IFwic2NydXRpbml6ZSBkZXRhaWxzIGFuZCBpbnRlcnByZXQgZXZpZGVuY2VcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnN1cnZleV06IFwib2JzZXJ2ZSB0aGUgc2l0dWF0aW9uIGFuZCBhbnRpY2lwYXRlIG91dGNvbWVzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC50aW5rZXJdOiBcImZpZGRsZSB3aXRoIGRldmljZXMgYW5kIG1lY2hhbmlzbXNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LmZpbmVzc2VdOiBcImVtcGxveSBkZXh0ZXJpdHkgb3Igc3VidGxlIG1pc2RpcmVjdGlvblwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQucHJvd2xdOiBcInRyYXZlcnNlIHNraWxsZnVsbHkgYW5kIHF1aWV0bHlcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnNraXJtaXNoXTogXCJlbnRhbmdsZSBhIHRhcmdldCBpbiBtZWxlZSBzbyB0aGV5IGNhbid0IGVzY2FwZVwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQud3JlY2tdOiBcInVubGVhc2ggc2F2YWdlIGZvcmNlXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5hdHR1bmVdOiBcIm9wZW4geW91ciBtaW5kIHRvIHRoZSBnaG9zdCBmaWVsZCBvciBjaGFubmVsIG5lYXJieSBlbGVjdHJvcGxhc21pYyBlbmVyZ3kgdGhyb3VnaCB5b3VyIGJvZHlcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LmNvbW1hbmRdOiBcImNvbXBlbCBzd2lmdCBvYmVkaWVuY2VcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LmNvbnNvcnRdOiBcInNvY2lhbGl6ZSB3aXRoIGZyaWVuZHMgYW5kIGNvbnRhY3RzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zd2F5XTogXCJpbmZsdWVuY2Ugc29tZW9uZSB3aXRoIGd1aWxlLCBjaGFybSwgb3IgYXJndW1lbnRcIlxuICAgIH0sXG4gICAgQWN0aW9uVG9vbHRpcHM6IHtcbiAgICAgICAgW0FjdGlvblRyYWl0Lmh1bnRdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+SHVudDwvc3Ryb25nPiwgeW91IGNhcmVmdWxseSB0cmFjayBhIHRhcmdldC48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgZm9sbG93IGEgcGVyc29uIG9yIGRpc2NvdmVyIHRoZWlyIGxvY2F0aW9uLjwvbGk+PGxpPllvdSBtaWdodCBhcnJhbmdlIGFuIGFtYnVzaC48L2xpPjxsaT5Zb3UgbWlnaHQgYXR0YWNrIHdpdGggcHJlY2lzaW9uIHNob290aW5nIGZyb20gYSBkaXN0YW5jZS48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHdpZWxkIHlvdXIgZ3VucyBpbiBhIG1lbGVlIDxlbT4oYnV0IDxzdHJvbmc+U2tpcm1pc2hpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PC91bD5cIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnN0dWR5XTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPlN0dWR5PC9zdHJvbmc+LCB5b3Ugc2NydXRpbml6ZSBkZXRhaWxzIGFuZCBpbnRlcnByZXQgZXZpZGVuY2UuPC9wPjx1bD48bGk+WW91IG1pZ2h0IGdhdGhlciBpbmZvcm1hdGlvbiBmcm9tIGRvY3VtZW50cywgbmV3c3BhcGVycywgYW5kIGJvb2tzLjwvbGk+PGxpPllvdSBtaWdodCBkbyByZXNlYXJjaCBvbiBhbiBlc290ZXJpYyB0b3BpYy48L2xpPjxsaT5Zb3UgbWlnaHQgY2xvc2VseSBhbmFseXplIGEgcGVyc29uIHRvIGRldGVjdCBsaWVzIG9yIHRydWUgZmVlbGluZ3MuPC9saT48L3VsPjx1bD48bGk+WW91IGNvdWxkIHRyeSB0byB1bmRlcnN0YW5kIGEgcHJlc3Npbmcgc2l0dWF0aW9uIDxlbT4oYnV0IDxzdHJvbmc+U3VydmV5aW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zdXJ2ZXldOiBcIjxwPldoZW4geW91IDxzdHJvbmc+U3VydmV5PC9zdHJvbmc+LCB5b3Ugb2JzZXJ2ZSB0aGUgc2l0dWF0aW9uIGFuZCBhbnRpY2lwYXRlIG91dGNvbWVzLjwvcD48dWw+PGxpPllvdSBtaWdodCBzcG90IHRlbGx0YWxlIHNpZ25zIG9mIHRyb3VibGUgYmVmb3JlIGl0IGhhcHBlbnMuPC9saT48bGk+WW91IG1pZ2h0IHVuY292ZXIgb3Bwb3J0dW5pdGllcyBvciB3ZWFrbmVzc2VzLjwvbGk+PC91bD48dWw+PGxpPllvdSBtaWdodCBkZXRlY3QgYSBwZXJzb24ncyBtb3RpdmVzIG9yIGludGVudGlvbnMgPGVtPihidXQgPHN0cm9uZz5TdHVkeWluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48bGk+WW91IGNvdWxkIHRyeSB0byBzcG90IGEgZ29vZCBhbWJ1c2ggcG9pbnQgPGVtPihidXQgPHN0cm9uZz5IdW50aW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC50aW5rZXJdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+VGlua2VyPC9zdHJvbmc+LCB5b3UgZmlkZGxlIHdpdGggZGV2aWNlcyBhbmQgbWVjaGFuaXNtcy48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgY3JlYXRlIGEgbmV3IGdhZGdldCBvciBhbHRlciBhbiBleGlzdGluZyBpdGVtLjwvbGk+PGxpPllvdSBtaWdodCBwaWNrIGEgbG9jayBvciBjcmFjayBhIHNhZmUuPC9saT48bGk+WW91IG1pZ2h0IGRpc2FibGUgYW4gYWxhcm0gb3IgdHJhcC48L2xpPjxsaT5Zb3UgbWlnaHQgdHVybiB0aGUgc3BhcmtjcmFmdCBhbmQgZWxlY3Ryb3BsYXNtaWMgZGV2aWNlcyBhcm91bmQgdGhlIGNpdHkgdG8geW91ciBhZHZhbnRhZ2UuPC9saT48L3VsPjx1bD48bGk+WW91IGNvdWxkIHRyeSB0byBjb250cm9sIGEgdmVoaWNsZSB3aXRoIHlvdXIgdGVjaC1zYXZ2eSA8ZW0+KGJ1dCA8c3Ryb25nPkZpbmVzc2luZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuZmluZXNzZV06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5GaW5lc3NlPC9zdHJvbmc+LCB5b3UgZW1wbG95IGRleHRlcml0eSBvciBzdWJ0bGUgbWlzZGlyZWN0aW9uLjwvcD48dWw+PGxpPllvdSBtaWdodCBwaWNrIHNvbWVvbmUncyBwb2NrZXQuPC9saT48bGk+WW91IG1pZ2h0IGhhbmRsZSB0aGUgY29udHJvbHMgb2YgYSB2ZWhpY2xlIG9yIGRpcmVjdCBhIG1vdW50LjwvbGk+PGxpPllvdSBtaWdodCBmb3JtYWxseSBkdWVsIGFuIG9wcG9uZW50IHdpdGggZ3JhY2VmdWwgZmlnaHRpbmcgYXJ0cy48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIGxldmVyYWdlIGFnaWxpdHkgaW4gYSBtZWxlZSA8ZW0+KGJ1dCA8c3Ryb25nPlNraXJtaXNoaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHBpY2sgYSBsb2NrIDxlbT4oYnV0IDxzdHJvbmc+VGlua2VyaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5wcm93bF06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5Qcm93bDwvc3Ryb25nPiwgeW91IHRyYXZlcnNlIHNraWxsZnVsbHkgYW5kIHF1aWV0bHkuPC9wPjx1bD48bGk+WW91IG1pZ2h0IHNuZWFrIHBhc3QgYSBndWFyZCBvciBoaWRlIGluIHRoZSBzaGFkb3dzLjwvbGk+PGxpPllvdSBtaWdodCBydW4gYW5kIGxlYXAgYWNyb3NzIHRoZSByb29mdG9wcy48L2xpPjxsaT5Zb3UgbWlnaHQgYXR0YWNrIHNvbWVvbmUgZnJvbSBoaWRpbmcgd2l0aCBhIGJhY2stc3RhYiBvciBibGFja2phY2suPC9saT48L3VsPjx1bD48bGk+WW91IGNvdWxkIHRyeSB0byB3YXlsYXkgYSB2aWN0aW0gZHVyaW5nIGNvbWJhdCA8ZW0+KGJ1dCA8c3Ryb25nPlNraXJtaXNoaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5za2lybWlzaF06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5Ta2lybWlzaDwvc3Ryb25nPiwgeW91IGVudGFuZ2xlIGEgdGFyZ2V0IGluIG1lbGVlIHNvIHRoZXkgY2FuJ3QgZXNjYXBlLjwvcD48dWw+PGxpPllvdSBtaWdodCBicmF3bCBvciB3cmVzdGxlIHdpdGggdGhlbS48L2xpPjxsaT5Zb3UgbWlnaHQgaGFjayBhbmQgc2xhc2guPC9saT48bGk+WW91IG1pZ2h0IHNlaXplIG9yIGhvbGQgYSBwb3NpdGlvbiBpbiBiYXR0bGUuPC9saT48L3VsPjx1bD48bGk+WW91IGNvdWxkIHRyeSB0byBmaWdodCBpbiBhIGZvcm1hbCBkdWVsIDxlbT4oYnV0IDxzdHJvbmc+RmluZXNzaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC53cmVja106IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5XcmVjazwvc3Ryb25nPiwgeW91IHVubGVhc2ggc2F2YWdlIGZvcmNlLjwvcD48dWw+PGxpPllvdSBtaWdodCBzbWFzaCBkb3duIGEgZG9vciBvciB3YWxsIHdpdGggYSBzbGVkZ2VoYW1tZXIuPC9saT48bGk+WW91IG1pZ2h0IHVzZSBhbiBleHBsb3NpdmUgdG8gZG8gdGhlIHNhbWUuPC9saT48bGk+WW91IG1pZ2h0IHVzZSBjaGFvcyBvciBzYWJvdGFnZSB0byBjcmVhdGUgZGlzdHJhY3Rpb25zIG9yIG92ZXJjb21lIG9ic3RhY2xlcy48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIG92ZXJ3aGVsbSBhbiBlbmVteSB3aXRoIHNoZWVyIGZvcmNlIGluIGJhdHRsZSA8ZW0+KGJ1dCA8c3Ryb25nPlNraXJtaXNoaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5hdHR1bmVdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+QXR0dW5lPC9zdHJvbmc+LCB5b3Ugb3BlbiB5b3VyIG1pbmQgdG8gdGhlIGdob3N0IGZpZWxkIG9yIGNoYW5uZWwgbmVhcmJ5IGVsZWN0cm9wbGFzbWljIGVuZXJneSB0aHJvdWdoIHlvdXIgYm9keS48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgY29tbXVuaWNhdGUgd2l0aCBhIGdob3N0IG9yIHVuZGVyc3RhbmQgYXNwZWN0cyBvZiBzcGVjdHJvbG9neS48L2xpPjxsaT5Zb3UgbWlnaHQgcGVlciBpbnRvIHRoZSBlY2hvIG9mIERvc2t2b2wgaW4gdGhlIGdob3N0IGZpZWxkLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gcGVyY2VpdmUgYmV5b25kIHNpZ2h0IGluIG9yZGVyIHRvIGJldHRlciB1bmRlcnN0YW5kIHlvdXIgc2l0dWF0aW9uIDxlbT4oYnV0IDxzdHJvbmc+U3VydmV5aW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5jb21tYW5kXTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPkNvbW1hbmQ8L3N0cm9uZz4sIHlvdSBjb21wZWwgc3dpZnQgb2JlZGllbmNlLjwvcD48dWw+PGxpPllvdSBtaWdodCBpbnRpbWlkYXRlIG9yIHRocmVhdGVuIHRvIGdldCB3aGF0IHlvdSB3YW50LjwvbGk+PGxpPllvdSBtaWdodCBsZWFkIGEgZ2FuZyBpbiBhIGdyb3VwIGFjdGlvbi48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHBlcnN1YWRlIHBlb3BsZSBieSBnaXZpbmcgb3JkZXJzIDxlbT4oYnV0IDxzdHJvbmc+Q29uc29ydGluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuY29uc29ydF06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5Db25zb3J0PC9zdHJvbmc+LCB5b3Ugc29jaWFsaXplIHdpdGggZnJpZW5kcyBhbmQgY29udGFjdHMuPC9wPjx1bD48bGk+WW91IG1pZ2h0IGdhaW4gYWNjZXNzIHRvIHJlc291cmNlcywgaW5mb3JtYXRpb24sIHBlb3BsZSwgb3IgcGxhY2VzLjwvbGk+PGxpPllvdSBtaWdodCBtYWtlIGEgZ29vZCBpbXByZXNzaW9uIG9yIHdpbiBzb21lb25lIG92ZXIgd2l0aCBjaGFybSBhbmQgc3R5bGUuPC9saT48bGk+WW91IG1pZ2h0IG1ha2UgbmV3IGZyaWVuZHMgb3IgY29ubmVjdCB3aXRoIHlvdXIgaGVyaXRhZ2Ugb3IgYmFja2dyb3VuZC48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIGRpcmVjdCBhbGxpZXMgd2l0aCBzb2NpYWwgcHJlc3N1cmUgPGVtPihidXQgPHN0cm9uZz5Db21tYW5kaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zd2F5XTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPlN3YXk8L3N0cm9uZz4sIHlvdSBpbmZsdWVuY2Ugc29tZW9uZSB3aXRoIGd1aWxlLCBjaGFybSwgb3IgYXJndW1lbnQuPC9wPjx1bD48bGk+WW91IG1pZ2h0IGxpZSBjb252aW5jaW5nbHkuPC9saT48bGk+WW91IG1pZ2h0IHBlcnN1YWRlIHNvbWVvbmUgdG8gZG8gd2hhdCB5b3Ugd2FudC48L2xpPjxsaT5Zb3UgbWlnaHQgYXJndWUgYSBjYXNlIHRoYXQgbGVhdmVzIG5vIGNsZWFyIHJlYnV0dGFsLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gdHJpY2sgcGVvcGxlIGludG8gYWZmZWN0aW9uIG9yIG9iZWRpZW5jZSA8ZW0+KGJ1dCA8c3Ryb25nPkNvbnNvcnRpbmc8L3N0cm9uZz4gb3IgPHN0cm9uZz5Db21tYW5kaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+XCJcbiAgICB9LFxuICAgIEFjdGlvblRvb2x0aXBzR006IHtcbiAgICAgICAgW0FjdGlvblRyYWl0Lmh1bnRdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+SHVudDwvc3Ryb25nPiwgeW91IGNhcmVmdWxseSB0cmFjayBhIHRhcmdldC48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgZm9sbG93IGEgcGVyc29uIG9yIGRpc2NvdmVyIHRoZWlyIGxvY2F0aW9uLjwvbGk+PGxpPllvdSBtaWdodCBhcnJhbmdlIGFuIGFtYnVzaC48L2xpPjxsaT5Zb3UgbWlnaHQgYXR0YWNrIHdpdGggcHJlY2lzaW9uIHNob290aW5nIGZyb20gYSBkaXN0YW5jZS48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHdpZWxkIHlvdXIgZ3VucyBpbiBhIG1lbGVlIDxlbT4oYnV0IDxzdHJvbmc+U2tpcm1pc2hpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PC91bD48aHI+PHVsPjxsaT5Ib3cgZG8geW91IGh1bnQgdGhlbSBkb3duPzwvbGk+PGxpPldoYXQgbWV0aG9kcyBkbyB5b3UgdXNlPzwvbGk+PGxpPldoYXQgZG8geW91IGhvcGUgdG8gYWNoaWV2ZT88L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zdHVkeV06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5TdHVkeTwvc3Ryb25nPiwgeW91IHNjcnV0aW5pemUgZGV0YWlscyBhbmQgaW50ZXJwcmV0IGV2aWRlbmNlLjwvcD48dWw+PGxpPllvdSBtaWdodCBnYXRoZXIgaW5mb3JtYXRpb24gZnJvbSBkb2N1bWVudHMsIG5ld3NwYXBlcnMsIGFuZCBib29rcy48L2xpPjxsaT5Zb3UgbWlnaHQgZG8gcmVzZWFyY2ggb24gYW4gZXNvdGVyaWMgdG9waWMuPC9saT48bGk+WW91IG1pZ2h0IGNsb3NlbHkgYW5hbHl6ZSBhIHBlcnNvbiB0byBkZXRlY3QgbGllcyBvciB0cnVlIGZlZWxpbmdzLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gdW5kZXJzdGFuZCBhIHByZXNzaW5nIHNpdHVhdGlvbiA8ZW0+KGJ1dCA8c3Ryb25nPlN1cnZleWluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPldoYXQgZG8geW91IHN0dWR5PzwvbGk+PGxpPldoYXQgZGV0YWlscyBvciBldmlkZW5jZSBkbyB5b3Ugc2NydXRpbml6ZT88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRvIHVuZGVyc3RhbmQ/PC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuc3VydmV5XTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPlN1cnZleTwvc3Ryb25nPiwgeW91IG9ic2VydmUgdGhlIHNpdHVhdGlvbiBhbmQgYW50aWNpcGF0ZSBvdXRjb21lcy48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgc3BvdCB0ZWxsdGFsZSBzaWducyBvZiB0cm91YmxlIGJlZm9yZSBpdCBoYXBwZW5zLjwvbGk+PGxpPllvdSBtaWdodCB1bmNvdmVyIG9wcG9ydHVuaXRpZXMgb3Igd2Vha25lc3Nlcy48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgbWlnaHQgZGV0ZWN0IGEgcGVyc29uJ3MgbW90aXZlcyBvciBpbnRlbnRpb25zIDxlbT4oYnV0IDxzdHJvbmc+U3R1ZHlpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PGxpPllvdSBjb3VsZCB0cnkgdG8gc3BvdCBhIGdvb2QgYW1idXNoIHBvaW50IDxlbT4oYnV0IDxzdHJvbmc+SHVudGluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPkhvdyBkbyB5b3Ugc3VydmV5IHRoZSBzaXR1YXRpb24/PC9saT48bGk+SXMgdGhlcmUgYW55dGhpbmcgc3BlY2lhbCB5b3UncmUgbG9va2luZyBvdXQgZm9yPzwvbGk+PGxpPldoYXQgZG8geW91IGhvcGUgdG8gdW5kZXJzdGFuZD88L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC50aW5rZXJdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+VGlua2VyPC9zdHJvbmc+LCB5b3UgZmlkZGxlIHdpdGggZGV2aWNlcyBhbmQgbWVjaGFuaXNtcy48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgY3JlYXRlIGEgbmV3IGdhZGdldCBvciBhbHRlciBhbiBleGlzdGluZyBpdGVtLjwvbGk+PGxpPllvdSBtaWdodCBwaWNrIGEgbG9jayBvciBjcmFjayBhIHNhZmUuPC9saT48bGk+WW91IG1pZ2h0IGRpc2FibGUgYW4gYWxhcm0gb3IgdHJhcC48L2xpPjxsaT5Zb3UgbWlnaHQgdHVybiB0aGUgc3BhcmtjcmFmdCBhbmQgZWxlY3Ryb3BsYXNtaWMgZGV2aWNlcyBhcm91bmQgdGhlIGNpdHkgdG8geW91ciBhZHZhbnRhZ2UuPC9saT48L3VsPjx1bD48bGk+WW91IGNvdWxkIHRyeSB0byBjb250cm9sIGEgdmVoaWNsZSB3aXRoIHlvdXIgdGVjaC1zYXZ2eSA8ZW0+KGJ1dCA8c3Ryb25nPkZpbmVzc2luZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPldoYXQgZG8geW91IHRpbmtlciB3aXRoPzwvbGk+PGxpPldoYXQgZG8geW91IGhvcGUgdG8gYWNjb21wbGlzaD88L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5maW5lc3NlXTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPkZpbmVzc2U8L3N0cm9uZz4sIHlvdSBlbXBsb3kgZGV4dGVyaXR5IG9yIHN1YnRsZSBtaXNkaXJlY3Rpb24uPC9wPjx1bD48bGk+WW91IG1pZ2h0IHBpY2sgc29tZW9uZSdzIHBvY2tldC48L2xpPjxsaT5Zb3UgbWlnaHQgaGFuZGxlIHRoZSBjb250cm9scyBvZiBhIHZlaGljbGUgb3IgZGlyZWN0IGEgbW91bnQuPC9saT48bGk+WW91IG1pZ2h0IGZvcm1hbGx5IGR1ZWwgYW4gb3Bwb25lbnQgd2l0aCBncmFjZWZ1bCBmaWdodGluZyBhcnRzLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gbGV2ZXJhZ2UgYWdpbGl0eSBpbiBhIG1lbGVlIDxlbT4oYnV0IDxzdHJvbmc+U2tpcm1pc2hpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PGxpPllvdSBjb3VsZCB0cnkgdG8gcGljayBhIGxvY2sgPGVtPihidXQgPHN0cm9uZz5UaW5rZXJpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PC91bD48aHI+PHVsPjxsaT5XaGF0IGRvIHlvdSBmaW5lc3NlPzwvbGk+PGxpPldoYXQncyBncmFjZWZ1bCBvciBzdWJ0bGUgYWJvdXQgdGhpcz88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRvIGFjaGlldmU/PC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQucHJvd2xdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+UHJvd2w8L3N0cm9uZz4sIHlvdSB0cmF2ZXJzZSBza2lsbGZ1bGx5IGFuZCBxdWlldGx5LjwvcD48dWw+PGxpPllvdSBtaWdodCBzbmVhayBwYXN0IGEgZ3VhcmQgb3IgaGlkZSBpbiB0aGUgc2hhZG93cy48L2xpPjxsaT5Zb3UgbWlnaHQgcnVuIGFuZCBsZWFwIGFjcm9zcyB0aGUgcm9vZnRvcHMuPC9saT48bGk+WW91IG1pZ2h0IGF0dGFjayBzb21lb25lIGZyb20gaGlkaW5nIHdpdGggYSBiYWNrLXN0YWIgb3IgYmxhY2tqYWNrLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gd2F5bGF5IGEgdmljdGltIGR1cmluZyBjb21iYXQgPGVtPihidXQgPHN0cm9uZz5Ta2lybWlzaGluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPkhvdyBkbyB5b3UgcHJvd2w/PC9saT48bGk+SG93IGRvIHlvdSB1c2UgdGhlIGVudmlyb25tZW50IGFyb3VuZCB5b3U/PC9saT48bGk+V2hhdCBkbyB5b3UgaG9wZSB0byBhY2hpZXZlPzwvbGk+PC91bD5cIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnNraXJtaXNoXTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPlNraXJtaXNoPC9zdHJvbmc+LCB5b3UgZW50YW5nbGUgYSB0YXJnZXQgaW4gbWVsZWUgc28gdGhleSBjYW4ndCBlc2NhcGUuPC9wPjx1bD48bGk+WW91IG1pZ2h0IGJyYXdsIG9yIHdyZXN0bGUgd2l0aCB0aGVtLjwvbGk+PGxpPllvdSBtaWdodCBoYWNrIGFuZCBzbGFzaC48L2xpPjxsaT5Zb3UgbWlnaHQgc2VpemUgb3IgaG9sZCBhIHBvc2l0aW9uIGluIGJhdHRsZS48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIGZpZ2h0IGluIGEgZm9ybWFsIGR1ZWwgPGVtPihidXQgPHN0cm9uZz5GaW5lc3Npbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PC91bD48aHI+PHVsPjxsaT5Ib3cgZG8geW91IHNraXJtaXNoIHdpdGggdGhlbT88L2xpPjxsaT5XaGF0IGNvbWJhdCBtZXRob2RzIGRvIHlvdSB1c2U/PC9saT48bGk+V2hhdCBkbyB5b3UgaG9wZSB0byBhY2hpZXZlPzwvbGk+PC91bD5cIixcbiAgICAgICAgW0FjdGlvblRyYWl0LndyZWNrXTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPldyZWNrPC9zdHJvbmc+LCB5b3UgdW5sZWFzaCBzYXZhZ2UgZm9yY2UuPC9wPjx1bD48bGk+WW91IG1pZ2h0IHNtYXNoIGRvd24gYSBkb29yIG9yIHdhbGwgd2l0aCBhIHNsZWRnZWhhbW1lci48L2xpPjxsaT5Zb3UgbWlnaHQgdXNlIGFuIGV4cGxvc2l2ZSB0byBkbyB0aGUgc2FtZS48L2xpPjxsaT5Zb3UgbWlnaHQgdXNlIGNoYW9zIG9yIHNhYm90YWdlIHRvIGNyZWF0ZSBkaXN0cmFjdGlvbnMgb3Igb3ZlcmNvbWUgb2JzdGFjbGVzLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gb3ZlcndoZWxtIGFuIGVuZW15IHdpdGggc2hlZXIgZm9yY2UgaW4gYmF0dGxlIDxlbT4oYnV0IDxzdHJvbmc+U2tpcm1pc2hpbmc8L3N0cm9uZz4gbWlnaHQgYmUgYmV0dGVyKTwvZW0+LjwvbGk+PC91bD48aHI+PHVsPjxsaT5XaGF0IGRvIHlvdSB3cmVjaz88L2xpPjxsaT5XaGF0IGZvcmNlIGRvIHlvdSBicmluZyB0byBiZWFyPzwvbGk+PGxpPldoYXQgZG8geW91IGhvcGUgdG8gYWNjb21wbGlzaD88L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5hdHR1bmVdOiBcIjxwPldoZW4geW91IDxzdHJvbmc+QXR0dW5lPC9zdHJvbmc+LCB5b3Ugb3BlbiB5b3VyIG1pbmQgdG8gdGhlIGdob3N0IGZpZWxkIG9yIGNoYW5uZWwgbmVhcmJ5IGVsZWN0cm9wbGFzbWljIGVuZXJneSB0aHJvdWdoIHlvdXIgYm9keS48L3A+PHVsPjxsaT5Zb3UgbWlnaHQgY29tbXVuaWNhdGUgd2l0aCBhIGdob3N0IG9yIHVuZGVyc3RhbmQgYXNwZWN0cyBvZiBzcGVjdHJvbG9neS48L2xpPjxsaT5Zb3UgbWlnaHQgcGVlciBpbnRvIHRoZSBlY2hvIG9mIERvc2t2b2wgaW4gdGhlIGdob3N0IGZpZWxkLjwvbGk+PC91bD48dWw+PGxpPllvdSBjb3VsZCB0cnkgdG8gcGVyY2VpdmUgYmV5b25kIHNpZ2h0IGluIG9yZGVyIHRvIGJldHRlciB1bmRlcnN0YW5kIHlvdXIgc2l0dWF0aW9uIDxlbT4oYnV0IDxzdHJvbmc+U3VydmV5aW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+PGhyPjx1bD48bGk+SG93IGRvIHlvdSBvcGVuIHlvdXIgbWluZCB0byB0aGUgZ2hvc3QgZmllbGQ/PC9saT48bGk+V2hhdCBkb2VzIHRoYXQgbG9vayBsaWtlPzwvbGk+PGxpPldoYXQgZW5lcmd5IGFyZSB5b3UgYXR0dW5pbmcgdG8/PC9saT48bGk+SG93IGFyZSB5b3UgY2hhbm5lbGluZyB0aGF0IGVuZXJneT88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRoZSBlbmVyZ3kgd2lsbCBkbz88L2xpPjwvdWw+XCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5jb21tYW5kXTogXCI8cD5XaGVuIHlvdSA8c3Ryb25nPkNvbW1hbmQ8L3N0cm9uZz4sIHlvdSBjb21wZWwgc3dpZnQgb2JlZGllbmNlLjwvcD48dWw+PGxpPllvdSBtaWdodCBpbnRpbWlkYXRlIG9yIHRocmVhdGVuIHRvIGdldCB3aGF0IHlvdSB3YW50LjwvbGk+PGxpPllvdSBtaWdodCBsZWFkIGEgZ2FuZyBpbiBhIGdyb3VwIGFjdGlvbi48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHBlcnN1YWRlIHBlb3BsZSBieSBnaXZpbmcgb3JkZXJzIDxlbT4oYnV0IDxzdHJvbmc+Q29uc29ydGluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPldobyBkbyB5b3UgY29tbWFuZD88L2xpPjxsaT5Ib3cgZG8geW91IGRvIGl04oCUd2hhdCdzIHlvdXIgbGV2ZXJhZ2UgaGVyZT88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRoZXknbGwgZG8/PC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuY29uc29ydF06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5Db25zb3J0PC9zdHJvbmc+LCB5b3Ugc29jaWFsaXplIHdpdGggZnJpZW5kcyBhbmQgY29udGFjdHMuPC9wPjx1bD48bGk+WW91IG1pZ2h0IGdhaW4gYWNjZXNzIHRvIHJlc291cmNlcywgaW5mb3JtYXRpb24sIHBlb3BsZSwgb3IgcGxhY2VzLjwvbGk+PGxpPllvdSBtaWdodCBtYWtlIGEgZ29vZCBpbXByZXNzaW9uIG9yIHdpbiBzb21lb25lIG92ZXIgd2l0aCBjaGFybSBhbmQgc3R5bGUuPC9saT48bGk+WW91IG1pZ2h0IG1ha2UgbmV3IGZyaWVuZHMgb3IgY29ubmVjdCB3aXRoIHlvdXIgaGVyaXRhZ2Ugb3IgYmFja2dyb3VuZC48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIGRpcmVjdCBhbGxpZXMgd2l0aCBzb2NpYWwgcHJlc3N1cmUgPGVtPihidXQgPHN0cm9uZz5Db21tYW5kaW5nPC9zdHJvbmc+IG1pZ2h0IGJlIGJldHRlcik8L2VtPi48L2xpPjwvdWw+PGhyPjx1bD48bGk+V2hvIGRvIHlvdSBjb25zb3J0IHdpdGg/PC9saT48bGk+V2hlcmUgZG8geW91IG1lZXQ/PC9saT48bGk+V2hhdCBkbyB5b3UgdGFsayBhYm91dD88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRvIGFjaGlldmU/PC9saT48L3VsPlwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuc3dheV06IFwiPHA+V2hlbiB5b3UgPHN0cm9uZz5Td2F5PC9zdHJvbmc+LCB5b3UgaW5mbHVlbmNlIHNvbWVvbmUgd2l0aCBndWlsZSwgY2hhcm0sIG9yIGFyZ3VtZW50LjwvcD48dWw+PGxpPllvdSBtaWdodCBsaWUgY29udmluY2luZ2x5LjwvbGk+PGxpPllvdSBtaWdodCBwZXJzdWFkZSBzb21lb25lIHRvIGRvIHdoYXQgeW91IHdhbnQuPC9saT48bGk+WW91IG1pZ2h0IGFyZ3VlIGEgY2FzZSB0aGF0IGxlYXZlcyBubyBjbGVhciByZWJ1dHRhbC48L2xpPjwvdWw+PHVsPjxsaT5Zb3UgY291bGQgdHJ5IHRvIHRyaWNrIHBlb3BsZSBpbnRvIGFmZmVjdGlvbiBvciBvYmVkaWVuY2UgPGVtPihidXQgPHN0cm9uZz5Db25zb3J0aW5nPC9zdHJvbmc+IG9yIDxzdHJvbmc+Q29tbWFuZGluZzwvc3Ryb25nPiBtaWdodCBiZSBiZXR0ZXIpPC9lbT4uPC9saT48L3VsPjxocj48dWw+PGxpPldobyBkbyB5b3Ugc3dheT88L2xpPjxsaT5XaGF0IGtpbmQgb2YgbGV2ZXJhZ2UgZG8geW91IGhhdmUgaGVyZT88L2xpPjxsaT5XaGF0IGRvIHlvdSBob3BlIHRoZXknbGwgZG8/PC9saT48L3VsPlwiXG4gICAgfSxcbiAgICBBY3Rpb25WZXJiczoge1xuICAgICAgICBbQWN0aW9uVHJhaXQuaHVudF06IFwiaHVudHNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnN0dWR5XTogXCJzdHVkaWVzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zdXJ2ZXldOiBcInN1cnZleXNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnRpbmtlcl06IFwidGlua2Vyc1wiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuZmluZXNzZV06IFwiZmluZXNzZXNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnByb3dsXTogXCJwcm93bHNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnNraXJtaXNoXTogXCJza2lybWlzaGVzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC53cmVja106IFwid3JlY2tzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5hdHR1bmVdOiBcImF0dHVuZXNcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LmNvbW1hbmRdOiBcImNvbW1hbmRzXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5jb25zb3J0XTogXCJjb25zb3J0c1wiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuc3dheV06IFwic3dheXNcIlxuICAgIH0sXG4gICAgQWN0aW9uUGFzdFZlcmJzOiB7XG4gICAgICAgIFtBY3Rpb25UcmFpdC5odW50XTogXCJodW50ZWRcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnN0dWR5XTogXCJzdHVkaWVkXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5zdXJ2ZXldOiBcInN1cnZleWVkXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC50aW5rZXJdOiBcInRpbmtlcmVkXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5maW5lc3NlXTogXCJmaW5lc3NlZFwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQucHJvd2xdOiBcInByb3dsZWRcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LnNraXJtaXNoXTogXCJza2lybWlzaGVkXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC53cmVja106IFwid3JlY2tlZFwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuYXR0dW5lXTogXCJhdHR1bmVkXCIsXG4gICAgICAgIFtBY3Rpb25UcmFpdC5jb21tYW5kXTogXCJjb21tYW5kZWRcIixcbiAgICAgICAgW0FjdGlvblRyYWl0LmNvbnNvcnRdOiBcImNvbnNvcnRlZFwiLFxuICAgICAgICBbQWN0aW9uVHJhaXQuc3dheV06IFwic3dheWVkXCJcbiAgICB9LFxuICAgIFRyYXVtYVRvb2x0aXBzOiB7XG4gICAgICAgIENvbGQ6IFwiWW91J3JlIG5vdCBtb3ZlZCBieSBlbW90aW9uYWwgYXBwZWFscyBvciBzb2NpYWwgYm9uZHMuXCIsXG4gICAgICAgIEhhdW50ZWQ6IFwiWW91J3JlIG9mdGVuIGxvc3QgaW4gcmV2ZXJpZSwgcmVsaXZpbmcgcGFzdCBob3Jyb3JzLCBzZWVpbmcgdGhpbmdzLlwiLFxuICAgICAgICBPYnNlc3NlZDogXCJZb3UncmUgZW50aHJhbGxlZCBieSBvbmUgdGhpbmc6IGFuIGFjdGl2aXR5LCBhIHBlcnNvbiwgYW4gaWRlb2xvZ3kuXCIsXG4gICAgICAgIFBhcmFub2lkOiBcIllvdSBpbWFnaW5lIGRhbmdlciBldmVyeXdoZXJlOyB5b3UgY2FuJ3QgdHJ1c3Qgb3RoZXJzLlwiLFxuICAgICAgICBSZWNrbGVzczogXCJZb3UgaGF2ZSBsaXR0bGUgcmVnYXJkIGZvciB5b3VyIG93biBzYWZldHkgb3IgYmVzdCBpbnRlcmVzdHMuXCIsXG4gICAgICAgIFNvZnQ6IFwiWW91IGxvc2UgeW91ciBlZGdlOyB5b3UgYmVjb21lIHNlbnRpbWVudGFsLCBwYXNzaXZlLCBnZW50bGUuXCIsXG4gICAgICAgIFVuc3RhYmxlOiBcIllvdXIgZW1vdGlvbmFsIHN0YXRlIGlzIHZvbGF0aWxlLiBZb3UgY2FuIGluc3RhbnRseSByYWdlLCBvciBmYWxsIGludG8gZGVzcGFpciwgYWN0IGltcHVsc2l2ZWx5LCBvciBmcmVlemUgdXAuXCIsXG4gICAgICAgIFZpY2lvdXM6IFwiWW91IHNlZWsgb3V0IG9wcG9ydHVuaXRpZXMgdG8gaHVydCBwZW9wbGUsIGV2ZW4gZm9yIG5vIGdvb2QgcmVhc29uLlwiLFxuICAgICAgICBDaGFvdGljOiBcIllvdSd2ZSBiZWNvbWUgc28gZGV0YWNoZWQgZnJvbSB0aGUgbGl2aW5nIHRoYXQgaW5oaWJpdGlvbnMgZmFsbCBhd2F5LCBsZWF2aW5nIHlvdSBpbXB1bHNpdmUgYW5kIHVucHJlZGljdGFibGUuXCIsXG4gICAgICAgIERlc3RydWN0aXZlOiBcIllvdSBhcmUgZWFzaWx5IGFuZ2VyZWQgYnkgcmVtaW5kZXJzIG9mIGFsbCB5b3UndmUgbG9zdCwgYW5kIGNhbiBsYXNoIG91dCB2aW9sZW50bHkgYWdhaW5zdCB0aGUgdHJhcHBpbmdzIG9mIHRoZSBsaXZpbmcgd29ybGQuXCIsXG4gICAgICAgIEZ1cmlvdXM6IFwiWW91ciByYXZhZ2VkIHNvdWwgaXMgZmVydGlsZSBraW5kbGluZyBmb3IgcmFnZSwgYW5kIHlvdXIgZnVyeSBpcyBlYXNpbHkgaWduaXRlZC5cIixcbiAgICAgICAgT2JzZXNzaXZlOiBcIllvdXIgd2FudHMgYW5kIGRlc2lyZXMgYmVjb21lIGZpeGF0aW9ucyBhbmQgY29tcHVsc2lvbnMsIGRyaXZpbmcgeW91IHRvIGFjaGlldmUgdGhlbSBhdCBhbnkgY29zdC5cIixcbiAgICAgICAgVGVycml0b3JpYWw6IFwiWW91IHNlZSBzb21lIHBsYWNlIGFzIHlvdXJzOiBUcmVzcGFzc2VycyBhcmUgZGVhbHQgd2l0aCwgYW5kIGV2ZW4gZ3Vlc3RzIG11c3QgcmVzcGVjdCB5b3VyIGNsYWltLlwiLFxuICAgICAgICBTYXZhZ2U6IFwiV2hlbiBtb3ZlZCB0byBhbmdlciBvciB2aW9sZW5jZSwgeW91IGFjdCB3aXRoIGNydWVsdHkgYW5kIGZlcmFsIG1hbGV2b2xlbmNlLlwiLFxuICAgICAgICBDbGFua2luZzogXCJZb3VyIGZyYW1lIGhhcyBkZXZlbG9wZWQgYSBwZXJzaXN0ZW50IG1ldGFsbGljIGNsYW5nIHdpdGggZWFjaCBzdGVwLCBtYWtpbmcgc3RlYWx0aCBkaWZmaWN1bHQuXCIsXG4gICAgICAgIExlYWtpbmc6IFwiWW91IGNvbnRpbnVvdXNseSBsZWFrIG9pbCwgbGV2aWF0aGFuIGJsb29kLCBkaXN0aWxsZWQgZWxlY3Ryb3BsYXNtIG9yIHNvbWUgb3RoZXIgcG90ZW50aWFsbHktZGFuZ2Vyb3VzIHN1YnN0YW5jZS5cIixcbiAgICAgICAgRml4YXRlZDogXCJZb3UgaGF2ZSBiZWNvbWUgZml4YXRlZCBvbiBhIGZ1bmN0aW9uIG9mIHlvdXIgY2hvaWNlLCBhbmQgbG9zZSBhbGwgbWVtb3J5IG9mIHlvdXIgaHVtYW5pdHkgd2hlbiB5b3UgcHVyc3VlIGl0LlwiLFxuICAgICAgICBTbW9raW5nOiBcIllvdXIgZnJhbWUgZXh1ZGVzIGEgY29uc3RhbnQgbWlhc21hIG9mIGFjcmlkLCBmb3VsLXNtZWxsaW5nIHNtb2tlLlwiLFxuICAgICAgICBTcGFya2luZzogXCJFbGVjdHJvcGxhc21pYyBlbmVyZ3kgZXJ1cHRzIGluIGFyY2luZyBzcGFya3MgZnJvbSBqb2ludHMgYW5kIGp1bmN0aW9ucyB0aHJvdWdob3V0IHlvdXIgZnJhbWUuXCIsXG4gICAgICAgIFJ1dGhsZXNzOiBcIllvdSBsb3NlIGFueSBzZW5zZSBvZiBodW1hbml0eSB3aGVuIGluZHVsZ2luZyB5b3VyIFZpY2Ugb3IgcHVyc3VpbmcgeW91ciBtb3N0IGltcG9ydGFudCBnb2FsLlwiLFxuICAgICAgICBTZWNyZXRpdmU6IFwiS25vd2xlZGdlIGhhcyBiZWNvbWUgc28gcHJlY2lvdXMgdG8geW91LCB0aGF0IGV2ZW4geW91ciBjbG9zZXN0IGFsbGllcyBhcmUgb24gYSBuZWVkLXRvLWtub3cgYmFzaXMuXCJcbiAgICB9LFxuICAgIEVkZ2VUb29sdGlwczoge1xuICAgICAgICBGZWFyc29tZTogXCI8cD5UaGUgY29ob3J0IGlzIHRlcnJpZnlpbmcgaW4gYXNwZWN0IGFuZCByZXB1dGF0aW9uLjwvcD5cIixcbiAgICAgICAgSW5kZXBlbmRlbnQ6IFwiPHA+VGhlIGNvaG9ydCBjYW4gYmUgdHJ1c3RlZCB0byBtYWtlIGdvb2QgZGVjaXNpb25zIGFuZCBhY3Qgb24gdGhlaXIgb3duIGluaXRpYXRpdmUgaW4gdGhlIGFic2VuY2Ugb2YgZGlyZWN0IG9yZGVycy48L3A+XCIsXG4gICAgICAgIExveWFsOiBcIjxwPlRoZSBjb2hvcnQgY2FuJ3QgYmUgYnJpYmVkIG9yIHR1cm5lZCBhZ2FpbnN0IHlvdS4gPC9wPlwiLFxuICAgICAgICBUZW5hY2lvdXM6IFwiPHA+VGhlIGNvaG9ydCB3b24ndCBiZSBkZXRlcnJlZCBmcm9tIGEgdGFzay48L3A+XCIsXG4gICAgICAgIE5pbWJsZTogXCI8cD5UaGUgdmVoaWNsZSBoYW5kbGVzIGVhc2lseS4gQ29uc2lkZXIgdGhpcyBhbiA8c3Ryb25nPmFzc2lzdDwvc3Ryb25nPiBmb3IgdHJpY2t5IG1hbmV1dmVycy48L3A+XCIsXG4gICAgICAgIFNpbXBsZTogXCI8cD5UaGUgdmVoaWNsZSBpcyBlYXN5IHRvIHJlcGFpci4gUmVtb3ZlIGFsbCBvZiBpdHMgPHN0cm9uZz5IYXJtPC9zdHJvbmc+IGR1cmluZyA8c3Ryb25nPmRvd250aW1lPC9zdHJvbmc+PC9wPlwiLFxuICAgICAgICBTdHVyZHk6IFwiPHA+VGhlIHZlaGljbGUga2VlcHMgb3BlcmF0aW5nIGV2ZW4gd2hlbiA8c3Ryb25nPkJyb2tlbjwvc3Ryb25nPi48L3A+XCIsXG4gICAgICAgIFwiQXJyb3ctU3dpZnRcIjogXCI8cD5Zb3VyIHBldCBnYWlucyA8c3Ryb25nPlBvdGVuY3k8L3N0cm9uZz4gd2hlbiB0cmFja2luZyBvciBmaWdodGluZyB0aGUgc3VwZXJuYXR1cmFsLjwvcD48cD5JdCBjYW4gbW92ZSBleHRyZW1lbHkgcXVpY2tseSwgb3V0cGFjaW5nIGFueSBvdGhlciBjcmVhdHVyZSBvciB2ZWhpY2xlLjwvcD5cIixcbiAgICAgICAgXCJHaG9zdCBGb3JtXCI6IFwiPHA+WW91ciBwZXQgZ2FpbnMgPHN0cm9uZz5Qb3RlbmN5PC9zdHJvbmc+IHdoZW4gdHJhY2tpbmcgb3IgZmlnaHRpbmcgdGhlIHN1cGVybmF0dXJhbC48L3A+PHA+SXQgY2FuIHRyYW5zZm9ybSBpbnRvIGVsZWN0cm9wbGFzbWljIHZhcG9yIGFzIGlmIGl0IHdlcmUgYSBzcGlyaXQuPC9wPlwiLFxuICAgICAgICBcIk1pbmQgTGlua1wiOiBcIjxwPllvdXIgcGV0IGdhaW5zIDxzdHJvbmc+UG90ZW5jeTwvc3Ryb25nPiB3aGVuIHRyYWNraW5nIG9yIGZpZ2h0aW5nIHRoZSBzdXBlcm5hdHVyYWwuPC9wPjxwPllvdSBhbmQgeW91ciBwZXQgY2FuIHNoYXJlIHNlbnNlcyBhbmQgdGhvdWdodHMgdGVsZXBhdGhpY2FsbHkuPC9wPlwiXG4gICAgfSxcbiAgICBGbGF3VG9vbHRpcHM6IHtcbiAgICAgICAgUHJpbmNpcGxlZDogXCI8cD5UaGUgY29ob3J0IGhhcyBhbiBldGhpYyBvciB2YWx1ZXMgdGhhdCBpdCB3b24ndCBiZXRyYXkuPC9wPlwiLFxuICAgICAgICBTYXZhZ2U6IFwiPHA+VGhlIGNvaG9ydCBpcyBleGNlc3NpdmVseSB2aW9sZW50IGFuZCBjcnVlbC48L3A+XCIsXG4gICAgICAgIFVucmVsaWFibGU6IFwiPHA+VGhlIGNvaG9ydCBpc24ndCBhbHdheXMgYXZhaWxhYmxlLCBkdWUgdG8gb3RoZXIgb2JsaWdhdGlvbnMsIHN0dXBlZmFjdGlvbiBmcm9tIHRoZWlyIHZpY2VzLCBldGMuPC9wPlwiLFxuICAgICAgICBXaWxkOiBcIjxwPlRoZSBjb2hvcnQgaXMgZHJ1bmtlbiwgZGViYXVjaGVkLCBhbmQgbG91ZC1tb3V0aGVkLjwvcD5cIixcbiAgICAgICAgQ29zdGx5OiBcIjxwPlRoZSB2ZWhpY2xlIGNvc3RzIDxzdHJvbmc+MSBDb2luPC9zdHJvbmc+IHBlciA8c3Ryb25nPmRvd250aW1lPC9zdHJvbmc+IHRvIGtlZXAgaXQgaW4gb3BlcmF0aW9uLjwvcD5cIixcbiAgICAgICAgRGlzdGluY3Q6IFwiPHA+VGhlIHZlaGljbGUgaGFzIG1lbW9yYWJsZSBmZWF0dXJlcy4gVGFrZSA8c3Ryb25nPisxIEhlYXQ8L3N0cm9uZz4gd2hlbiB5b3UgdXNlIGl0IG9uIGEgc2NvcmUuPC9wPlwiLFxuICAgICAgICBGaW5pY2t5OiBcIjxwPlRoZSB2ZWhpY2xlIGhhcyBxdWlya3MgdGhhdCBvbmx5IG9uZSBwZXJzb24gdW5kZXJzdGFuZHMuIFdoZW4gb3BlcmF0ZWQgd2l0aG91dCB0aGVtLCBpdCBoYXMgPHN0cm9uZz4tMSBRdWFsaXR5PC9zdHJvbmc+LjwvcD5cIlxuICAgIH0sXG4gICAgUXVhbGl0eURlc2NyaXB0b3JzOiBbXG4gICAgICAgIFwiUG9vclwiLFxuICAgICAgICBcIkFkZXF1YXRlXCIsXG4gICAgICAgIFwiR29vZFwiLFxuICAgICAgICBcIkV4Y2VsbGVudFwiLFxuICAgICAgICBcIlN1cGVyaW9yXCIsXG4gICAgICAgIFwiSW1wZWNjYWJsZVwiLFxuICAgICAgICBcIkxlZ2VuZGFyeVwiXG4gICAgXSxcbiAgICBGb3JjZURlc2NyaXB0b3JzOiBbXG4gICAgICAgIFwiV2Vha1wiLFxuICAgICAgICBcIk1vZGVyYXRlXCIsXG4gICAgICAgIFwiU3Ryb25nXCIsXG4gICAgICAgIFwiU2VyaW91c1wiLFxuICAgICAgICBcIlBvd2VyZnVsXCIsXG4gICAgICAgIFwiT3ZlcndoZWxtaW5nXCIsXG4gICAgICAgIFwiRGV2YXN0YXRpbmdcIlxuICAgIF0sXG4gICAgVmVoaWNsZURlc2NyaXB0b3JzOiBbXG4gICAgICAgIFwiQSBWZWhpY2xlP1wiLFxuICAgICAgICBcIkEgVmVoaWNsZVwiLFxuICAgICAgICBcIkEgUmVzcGVjdGFibGUgVmVoaWNsZVwiLFxuICAgICAgICBcIkEgUmVzcGVjdGVkIFZlaGljbGVcIixcbiAgICAgICAgXCJBIFByZWNpc2lvbi1CdWlsdCBWZWhpY2xlXCIsXG4gICAgICAgIFwiQSBQb3dlcmZ1bCwgQWR2YW5jZWQgVmVoaWNsZVwiLFxuICAgICAgICBcIkEgVW5pcXVlbHkgU3Ryb25nLCBFeHRyZW1lbHkgQWR2YW5jZWQgVmVoaWNsZVwiXG4gICAgXSxcbiAgICBQZXREZXNjcmlwdG9yczogW1xuICAgICAgICBcIkEgV2VhayBIdW50aW5nIFBldFwiLFxuICAgICAgICBcIkEgSHVudGluZyBQZXRcIixcbiAgICAgICAgXCJBIFN0cm9uZyBIdW50aW5nIFBldFwiLFxuICAgICAgICBcIkEgU2VyaW91cyBIdW50aW5nIFBldFwiLFxuICAgICAgICBcIkEgUG93ZXJmdWwgSHVudGluZyBQZXRcIixcbiAgICAgICAgXCJBbiBPdmVyd2hlbG1pbmdseSBQb3dlcmZ1bCBIdW50aW5nIFBldFwiLFxuICAgICAgICBcIkEgRGV2YXN0YXRpbmcgSHVudGluZyBQZXRcIlxuICAgIF0sXG4gICAgQXJlYUV4YW1wbGVzOiBbXG4gICAgICAgIFwiYSBjbG9zZXRcIixcbiAgICAgICAgXCJhIHNtYWxsIHJvb21cIixcbiAgICAgICAgXCJhIGxhcmdlIHJvb21cIixcbiAgICAgICAgXCJzZXZlcmFsIHJvb21zXCIsXG4gICAgICAgIFwiYSBzbWFsbCBidWlsZGluZ1wiLFxuICAgICAgICBcImEgbGFyZ2UgYnVpbGRpbmdcIixcbiAgICAgICAgXCJhIGNpdHkgYmxvY2tcIlxuICAgIF0sXG4gICAgU2NhbGVFeGFtcGxlczogW1xuICAgICAgICBcIigxIG9yIDIgbWVtYmVycylcIixcbiAgICAgICAgXCIoMyAtIDYgbWVtYmVycylcIixcbiAgICAgICAgXCIofjEyIG1lbWJlcnMpXCIsXG4gICAgICAgIFwiKH4yMCBtZW1iZXJzKVwiLFxuICAgICAgICBcIih+NDAgbWVtYmVycylcIixcbiAgICAgICAgXCIofjgwIG1lbWJlcnMpXCIsXG4gICAgICAgIFwiKH4xNjAgbWVtYmVycylcIlxuICAgIF0sXG4gICAgU2NhbGVTaXplczogW1xuICAgICAgICBcIkEgRmV3IFwiLFxuICAgICAgICBcIkEgU21hbGwgR2FuZyBvZiBcIixcbiAgICAgICAgXCJBIEdhbmcgb2YgXCIsXG4gICAgICAgIFwiQSBMYXJnZSBHYW5nIG9mIFwiLFxuICAgICAgICBcIkEgU21hbGwgQXJteSBvZiBcIixcbiAgICAgICAgXCJBbiBBcm15IG9mIFwiLFxuICAgICAgICBcIkEgTWFzc2l2ZSBBcm15IG9mIFwiXG4gICAgXSxcbiAgICBEaWNlT2Rkc1N0YW5kYXJkOiBbXG4gICAgICAgIHsgY3JpdDogMCwgc3VjY2VzczogMi44LCBwYXJ0aWFsOiAyMi4yLCBmYWlsOiA3NSB9LFxuICAgICAgICB7IGNyaXQ6IDAsIHN1Y2Nlc3M6IDE2LjcsIHBhcnRpYWw6IDMzLjMsIGZhaWw6IDUwIH0sXG4gICAgICAgIHsgY3JpdDogMi44LCBzdWNjZXNzOiAyNy44LCBwYXJ0aWFsOiA0NC40LCBmYWlsOiAyNSB9LFxuICAgICAgICB7IGNyaXQ6IDcuNCwgc3VjY2VzczogMzQuNywgcGFydGlhbDogNDUuNCwgZmFpbDogMTIuNSB9LFxuICAgICAgICB7IGNyaXQ6IDEzLjIsIHN1Y2Nlc3M6IDM4LjYsIHBhcnRpYWw6IDQyLCBmYWlsOiA2LjMgfSxcbiAgICAgICAgeyBjcml0OiAxOS42LCBzdWNjZXNzOiA0MC4yLCBwYXJ0aWFsOiAzNy4xLCBmYWlsOiAzLjEgfSxcbiAgICAgICAgeyBjcml0OiAyNi4zLCBzdWNjZXNzOiA0MC4yLCBwYXJ0aWFsOiAzMS45LCBmYWlsOiAxLjYgfSxcbiAgICAgICAgeyBjcml0OiAzMywgc3VjY2VzczogMzkuMSwgcGFydGlhbDogMjcuMSwgZmFpbDogMC44IH0sXG4gICAgICAgIHsgY3JpdDogMzkuNSwgc3VjY2VzczogMzcuMiwgcGFydGlhbDogMjIuOSwgZmFpbDogMC40IH0sXG4gICAgICAgIHsgY3JpdDogNDUuNywgc3VjY2VzczogMzQuOSwgcGFydGlhbDogMTkuMiwgZmFpbDogMC4yIH0sXG4gICAgICAgIHsgY3JpdDogNTEuNSwgc3VjY2VzczogMzIuMywgcGFydGlhbDogMTYuMSwgZmFpbDogMC4xIH0sXG4gICAgICAgIHsgY3JpdDogNTYuOSwgc3VjY2VzczogMjkuNiwgcGFydGlhbDogMTMuNCwgZmFpbDogMCB9LFxuICAgICAgICB7IGNyaXQ6IDYxLjksIHN1Y2Nlc3M6IDI2LjksIHBhcnRpYWw6IDExLjIsIGZhaWw6IDAgfSxcbiAgICAgICAgeyBjcml0OiA2Ni4zLCBzdWNjZXNzOiAyNC4zLCBwYXJ0aWFsOiA5LjMsIGZhaWw6IDAgfSxcbiAgICAgICAgeyBjcml0OiA3MC40LCBzdWNjZXNzOiAyMS44LCBwYXJ0aWFsOiA3LjgsIGZhaWw6IDAgfSxcbiAgICAgICAgeyBjcml0OiA3NCwgc3VjY2VzczogMTkuNSwgcGFydGlhbDogNi41LCBmYWlsOiAwIH0sXG4gICAgICAgIHsgY3JpdDogNzcuMywgc3VjY2VzczogMTcuMywgcGFydGlhbDogNS40LCBmYWlsOiAwIH0sXG4gICAgICAgIHsgY3JpdDogODAuMiwgc3VjY2VzczogMTUuMywgcGFydGlhbDogNC41LCBmYWlsOiAwIH0sXG4gICAgICAgIHsgY3JpdDogODIuNywgc3VjY2VzczogMTMuNSwgcGFydGlhbDogMy44LCBmYWlsOiAwIH0sXG4gICAgICAgIHsgY3JpdDogODUsIHN1Y2Nlc3M6IDExLjksIHBhcnRpYWw6IDMuMSwgZmFpbDogMCB9LFxuICAgICAgICB7IGNyaXQ6IDg3LCBzdWNjZXNzOiAxMC40LCBwYXJ0aWFsOiAyLjYsIGZhaWw6IDAgfVxuICAgIF0sXG4gICAgRGljZU9kZHNSZXNpc3RhbmNlOiBbXG4gICAgICAgIFswLCAyLjgsIDguMywgMTMuOSwgMTkuNCwgMjUsIDMwLjZdLFxuICAgICAgICBbMCwgMTYuNywgMTYuNywgMTYuNywgMTYuNiwgMTYuNywgMTYuN10sXG4gICAgICAgIFsyLjgsIDI3LjgsIDI1LCAxOS40LCAxMy45LCA4LjMsIDIuOF0sXG4gICAgICAgIFs3LjQsIDM0LjcsIDI4LjMsIDE3LjEsIDguOCwgMy4yLCAwLjVdLFxuICAgICAgICBbMTMuMiwgMzguNiwgMjguNSwgMTMuNSwgNSwgMS4yLCAwLjFdLFxuICAgICAgICBbMTkuNiwgNDAuMiwgMjcsIDEwLjEsIDIuNywgMC40LCAwXSxcbiAgICAgICAgWzI2LjMsIDQwLjIsIDI0LjcsIDcuMiwgMS40LCAwLjEsIDBdXG4gICAgXSxcbiAgICBFeHBlcmllbmNlQ2x1ZXM6IHtcbiAgICAgICAgU2NvdW5kcmVsOiBbXG4gICAgICAgICAgICBcIllvdSBleHByZXNzZWQgeW91ciBiZWxpZWZzLCBkcml2ZXMsIGhlcml0YWdlLCBvciBiYWNrZ3JvdW5kLlwiLFxuICAgICAgICAgICAgXCJZb3Ugc3RydWdnbGVkIHdpdGggaXNzdWVzIGZyb20geW91ciB2aWNlIG9yIHRyYXVtYXMgZHVyaW5nIHRoZSBzZXNzaW9uLlwiXG4gICAgICAgIF0sXG4gICAgICAgIENyZXc6IFtcbiAgICAgICAgICAgIFwiWW91IGNvbnRlbmRlZCB3aXRoIGNoYWxsZW5nZXMgYWJvdmUgeW91ciBjdXJyZW50IHN0YXRpb24uXCIsXG4gICAgICAgICAgICBcIllvdSBib2xzdGVyZWQgeW91ciBjcmV3J3MgcmVwdXRhdGlvbiwgb3IgZGV2ZWxvcGVkIGEgbmV3IG9uZS5cIixcbiAgICAgICAgICAgIFwiWW91IGV4cHJlc3NlZCB0aGUgZ29hbHMsIGRyaXZlcywgaW5uZXIgY29uZmxpY3QsIG9yIGVzc2VudGlhbCBuYXR1cmUgb2YgdGhlIGNyZXcuXCJcbiAgICAgICAgXVxuICAgIH0sXG4gICAgR2F0aGVySW5mb1F1ZXN0aW9uczoge1xuICAgICAgICBDdXR0ZXI6IFtcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGh1cnQgdGhlbT9cIixcbiAgICAgICAgICAgIFwiV2hvJ3MgbW9zdCBhZnJhaWQgb2YgbWU/XCIsXG4gICAgICAgICAgICBcIldobydzIG1vc3QgZGFuZ2Vyb3VzIGhlcmU/XCIsXG4gICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICBcIkFyZSB0aGV5IHRlbGxpbmcgdGhlIHRydXRoP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgSG91bmQ6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgIFwiV2hhdCBhcmUgdGhleSByZWFsbHkgZmVlbGluZz9cIixcbiAgICAgICAgICAgIFwiV2hlcmUgYXJlIHRoZXkgdnVsbmVyYWJsZT9cIixcbiAgICAgICAgICAgIFwiV2hlcmUgZGlkIFtYXSBnbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgTGVlY2g6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgIFwiQXJlIHRoZXkgdGVsbGluZyB0aGUgdHJ1dGg/XCIsXG4gICAgICAgICAgICBcIldoYXQgY2FuIEkgdGlua2VyIHdpdGggaGVyZT9cIixcbiAgICAgICAgICAgIFwiV2hhdCBtaWdodCBoYXBwZW4gaWYgSSBbWF0/XCIsXG4gICAgICAgICAgICBcIkhvdyBjYW4gSSBmaW5kIFtYXT9cIixcbiAgICAgICAgICAgIFwiV2hhdCdzIHJlYWxseSBnb2luZyBvbiBoZXJlP1wiXG4gICAgICAgIF0sXG4gICAgICAgIEx1cms6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rIG91dCBmb3I/XCIsXG4gICAgICAgICAgICBcIldoYXQncyB0aGUgYmVzdCB3YXkgaW4/XCIsXG4gICAgICAgICAgICBcIldoZXJlIGNhbiBJIGhpZGUgaGVyZT9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgU2xpZGU6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgIFwiQXJlIHRoZXkgdGVsbGluZyB0aGUgdHJ1dGg/XCIsXG4gICAgICAgICAgICBcIldoYXQgYXJlIHRoZXkgcmVhbGx5IGZlZWxpbmc/XCIsXG4gICAgICAgICAgICBcIldoYXQgZG8gdGhleSByZWFsbHkgY2FyZSBhYm91dD9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGJsZW5kIGluIGhlcmU/XCIsXG4gICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICBdLFxuICAgICAgICBTcGlkZXI6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IHdhbnQgbW9zdD9cIixcbiAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rIG91dCBmb3I/XCIsXG4gICAgICAgICAgICBcIldoZXJlJ3MgdGhlIGxldmVyYWdlIGhlcmU/XCIsXG4gICAgICAgICAgICBcIkhvdyBjYW4gSSBkaXNjb3ZlciBbWF0/XCIsXG4gICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICBdLFxuICAgICAgICBXaGlzcGVyOiBbXG4gICAgICAgICAgICBcIldoYXQgaXMgYXJjYW5lIG9yIHdlaXJkIGhlcmU/XCIsXG4gICAgICAgICAgICBcIldoYXQgZWNob2VzIGluIHRoZSBnaG9zdCBmaWVsZD9cIixcbiAgICAgICAgICAgIFwiV2hhdCBpcyBoaWRkZW4gb3IgbG9zdCBoZXJlP1wiLFxuICAgICAgICAgICAgXCJXaGF0IGRvIHRoZXkgaW50ZW5kIHRvIGRvP1wiLFxuICAgICAgICAgICAgXCJXaGF0IGRyaXZlcyB0aGVtIHRvIGRvIHRoaXM/XCIsXG4gICAgICAgICAgICBcIkhvdyBjYW4gSSByZXZlYWwgW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgR2hvc3Q6IFtcbiAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgIFwiV2hhdCBhcmUgdGhleSByZWFsbHkgZmVlbGluZz9cIixcbiAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rb3V0IGZvcj9cIixcbiAgICAgICAgICAgIFwiV2hlcmUncyB0aGUgd2Vha25lc3MgaGVyZT9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgSHVsbDogW1xuICAgICAgICAgICAgXCJXaGF0IGRvIHRoZXkgaW50ZW5kIHRvIGRvP1wiLFxuICAgICAgICAgICAgXCJIb3cgY2FuIEkgZ2V0IHRoZW0gdG8gW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0IGFyZSB0aGV5IHJlYWxseSBkb2luZz9cIixcbiAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rb3V0IGZvcj9cIixcbiAgICAgICAgICAgIFwiV2hlcmUncyB0aGUgd2Vha25lc3MgaGVyZT9cIixcbiAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgXSxcbiAgICAgICAgVmFtcGlyZTogW1xuICAgICAgICAgICAgXCJXaGF0IGRvIHRoZXkgaW50ZW5kIHRvIGRvP1wiLFxuICAgICAgICAgICAgXCJIb3cgY2FuIEkgZ2V0IHRoZW0gdG8gW1hdP1wiLFxuICAgICAgICAgICAgXCJXaGF0IGFyZSB0aGV5IHJlYWxseSBmZWVsaW5nP1wiLFxuICAgICAgICAgICAgXCJXaGF0IHNob3VsZCBJIGxvb2tvdXQgZm9yP1wiLFxuICAgICAgICAgICAgXCJXaGVyZSdzIHRoZSB3ZWFrbmVzcyBoZXJlP1wiLFxuICAgICAgICAgICAgXCJIb3cgY2FuIEkgZmluZCBbWF0/XCIsXG4gICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICBdXG4gICAgfSxcbiAgICBQbGF5Ym9va3M6IHtcbiAgICAgICAgQ3V0dGVyOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5leHBlcmllbmNlX2NsdWVzXCI6IFtcbiAgICAgICAgICAgICAgICBcIllvdSBhZGRyZXNzZWQgYSBjaGFsbGVuZ2Ugd2l0aCB2aW9sZW5jZSBvciBjb2VyY2lvbi5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBleHByZXNzZWQgeW91ciBiZWxpZWZzLCBkcml2ZXMsIGhlcml0YWdlLCBvciBiYWNrZ3JvdW5kLlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IHN0cnVnZ2xlZCB3aXRoIGlzc3VlcyBmcm9tIHlvdXIgdmljZSBvciB0cmF1bWFzIGR1cmluZyB0aGUgc2Vzc2lvbi5cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLnRyYXVtYV9jb25kaXRpb25zXCI6IFtcIkNvbGRcIiwgXCJIYXVudGVkXCIsIFwiT2JzZXNzZWRcIiwgXCJQYXJhbm9pZFwiLCBcIlJlY2tsZXNzXCIsIFwiU29mdFwiLCBcIlVuc3RhYmxlXCIsIFwiVmljaW91c1wiXSxcbiAgICAgICAgICAgIFwic3lzdGVtLmdhdGhlcl9pbmZvX3F1ZXN0aW9uc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgaHVydCB0aGVtP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hvJ3MgbW9zdCBhZnJhaWQgb2YgbWU/XCIsXG4gICAgICAgICAgICAgICAgXCJXaG8ncyBtb3N0IGRhbmdlcm91cyBoZXJlP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICAgICAgXCJBcmUgdGhleSB0ZWxsaW5nIHRoZSB0cnV0aD9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLnN1Z2dlc3RlZF9hYmlsaXR5XCI6IFwiQmF0dGxlYm9yblwiXG4gICAgICAgIH0sXG4gICAgICAgIEhvdW5kOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5iZ0ltZ1wiOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9pY29ucy9jbGFzcy1pY29ucy9ob3VuZC10cmFucy5zdmdcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnRhZ2xpbmVcIjogXCJBIERlYWRseSBTaGFycHNob290ZXIgJiBUcmFja2VyXCIsXG4gICAgICAgICAgICAvLyBcInN5c3RlbS5hY3F1YWludGFuY2VzX25hbWVcIjogXCJEZWFkbHkgRnJpZW5kcyAmIFJpdmFsc1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZnJpZW5kc19uYW1lXCI6IFwiRGVhZGx5IEZyaWVuZHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnJpdmFsc19uYW1lXCI6IFwiRGVhZGxpZXIgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5zdGFydGluZ19zdGF0cy5jaGFyZ2VuXCI6IHtcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLmluc2lnaHQuaHVudC52YWx1ZVwiOiAyLFxuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMuaW5zaWdodC5zdXJ2ZXkudmFsdWVcIjogMVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXNcIjogW1xuICAgICAgICAgICAgICAgIFwiWW91IGFkZHJlc3NlZCBhIGNoYWxsZW5nZSB3aXRoIHRyYWNraW5nIG9yIHZpb2xlbmNlLlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IGV4cHJlc3NlZCB5b3VyIGJlbGllZnMsIGRyaXZlcywgaGVyaXRhZ2UsIG9yIGJhY2tncm91bmQuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3Ugc3RydWdnbGVkIHdpdGggaXNzdWVzIGZyb20geW91ciB2aWNlIG9yIHRyYXVtYXMgZHVyaW5nIHRoZSBzZXNzaW9uLlwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0udHJhdW1hX2NvbmRpdGlvbnNcIjogW1wiQ29sZFwiLCBcIkhhdW50ZWRcIiwgXCJPYnNlc3NlZFwiLCBcIlBhcmFub2lkXCIsIFwiUmVja2xlc3NcIiwgXCJTb2Z0XCIsIFwiVW5zdGFibGVcIiwgXCJWaWNpb3VzXCJdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZ2F0aGVyX2luZm9fcXVlc3Rpb25zXCI6IFtcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgZ2V0IHRoZW0gdG8gW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBhcmUgdGhleSByZWFsbHkgZmVlbGluZz9cIixcbiAgICAgICAgICAgICAgICBcIldoZXJlIGFyZSB0aGV5IHZ1bG5lcmFibGU/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGVyZSBkaWQgW1hdIGdvP1wiLFxuICAgICAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCdzIHJlYWxseSBnb2luZyBvbiBoZXJlP1wiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3VnZ2VzdGVkX2FiaWxpdHlcIjogXCJTaGFycHNob290ZXJcIlxuICAgICAgICB9LFxuICAgICAgICBMZWVjaDoge1xuICAgICAgICAgICAgXCJzeXN0ZW0uYmdJbWdcIjogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy9hc3NldHMvaWNvbnMvY2xhc3MtaWNvbnMvbGVlY2gtdHJhbnMuc3ZnXCIsXG4gICAgICAgICAgICBcInN5c3RlbS50YWdsaW5lXCI6IFwiQSBTYWJvdGV1ciAmIFRlY2huaWNpYW5cIixcbiAgICAgICAgICAgIC8vIFwic3lzdGVtLmFjcXVhaW50YW5jZXNfbmFtZVwiOiBcIkNsZXZlciBGcmllbmRzICYgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5mcmllbmRzX25hbWVcIjogXCJDbGV2ZXIgRnJpZW5kc1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0ucml2YWxzX25hbWVcIjogXCJDbGV2ZXJlciBSaXZhbHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnN0YXJ0aW5nX3N0YXRzLmNoYXJnZW5cIjoge1xuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMuaW5zaWdodC50aW5rZXIudmFsdWVcIjogMixcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnByb3dlc3Mud3JlY2sudmFsdWVcIjogMVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXNcIjogW1xuICAgICAgICAgICAgICAgIFwiWW91IGFkZHJlc3NlZCBhIGNoYWxsZW5nZSB3aXRoIHRlY2huaWNhbCBza2lsbCBvciBtYXloZW0uXCIsXG4gICAgICAgICAgICAgICAgXCJZb3UgZXhwcmVzc2VkIHlvdXIgYmVsaWVmcywgZHJpdmVzLCBoZXJpdGFnZSwgb3IgYmFja2dyb3VuZC5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBzdHJ1Z2dsZWQgd2l0aCBpc3N1ZXMgZnJvbSB5b3VyIHZpY2Ugb3IgdHJhdW1hcyBkdXJpbmcgdGhlIHNlc3Npb24uXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS50cmF1bWFfY29uZGl0aW9uc1wiOiBbXCJDb2xkXCIsIFwiSGF1bnRlZFwiLCBcIk9ic2Vzc2VkXCIsIFwiUGFyYW5vaWRcIiwgXCJSZWNrbGVzc1wiLCBcIlNvZnRcIiwgXCJVbnN0YWJsZVwiLCBcIlZpY2lvdXNcIl0sXG4gICAgICAgICAgICBcInN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnNcIjogW1xuICAgICAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICAgICAgXCJBcmUgdGhleSB0ZWxsaW5nIHRoZSB0cnV0aD9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgY2FuIEkgdGlua2VyIHdpdGggaGVyZT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgbWlnaHQgaGFwcGVuIGlmIEkgW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCdzIHJlYWxseSBnb2luZyBvbiBoZXJlP1wiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3VnZ2VzdGVkX2FiaWxpdHlcIjogXCJBbGNoZW1pc3RcIlxuICAgICAgICB9LFxuICAgICAgICBMdXJrOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5iZ0ltZ1wiOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9pY29ucy9jbGFzcy1pY29ucy9sdXJrLXRyYW5zLnN2Z1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0udGFnbGluZVwiOiBcIkEgU3RlYWx0aHkgSW5maWx0cmF0b3IgJiBCdXJnbGFyXCIsXG4gICAgICAgICAgICAvLyBcInN5c3RlbS5hY3F1YWludGFuY2VzX25hbWVcIjogXCJTaGFkeSBGcmllbmRzICYgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5mcmllbmRzX25hbWVcIjogXCJTaGFkeSBGcmllbmRzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5yaXZhbHNfbmFtZVwiOiBcIlNoYWRpZXIgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5zdGFydGluZ19zdGF0cy5jaGFyZ2VuXCI6IHtcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnByb3dlc3MucHJvd2wudmFsdWVcIjogMixcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnByb3dlc3MuZmluZXNzZS52YWx1ZVwiOiAxXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzeXN0ZW0uZXhwZXJpZW5jZV9jbHVlc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJZb3UgYWRkcmVzc2VkIGEgY2hhbGxlbmdlIHdpdGggc3RlYWx0aCBvciBldmFzaW9uLlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IGV4cHJlc3NlZCB5b3VyIGJlbGllZnMsIGRyaXZlcywgaGVyaXRhZ2UsIG9yIGJhY2tncm91bmQuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3Ugc3RydWdnbGVkIHdpdGggaXNzdWVzIGZyb20geW91ciB2aWNlIG9yIHRyYXVtYXMgZHVyaW5nIHRoZSBzZXNzaW9uLlwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0udHJhdW1hX2NvbmRpdGlvbnNcIjogW1wiQ29sZFwiLCBcIkhhdW50ZWRcIiwgXCJPYnNlc3NlZFwiLCBcIlBhcmFub2lkXCIsIFwiUmVja2xlc3NcIiwgXCJTb2Z0XCIsIFwiVW5zdGFibGVcIiwgXCJWaWNpb3VzXCJdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZ2F0aGVyX2luZm9fcXVlc3Rpb25zXCI6IFtcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgZ2V0IHRoZW0gdG8gW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rIG91dCBmb3I/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0J3MgdGhlIGJlc3Qgd2F5IGluP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hlcmUgY2FuIEkgaGlkZSBoZXJlP1wiLFxuICAgICAgICAgICAgICAgIFwiSG93IGNhbiBJIGZpbmQgW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCdzIHJlYWxseSBnb2luZyBvbiBoZXJlP1wiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3VnZ2VzdGVkX2FiaWxpdHlcIjogXCJJbmZpbHRyYXRvclwiXG4gICAgICAgIH0sXG4gICAgICAgIFNsaWRlOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5iZ0ltZ1wiOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9pY29ucy9jbGFzcy1pY29ucy9zbGlkZS10cmFucy5zdmdcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnRhZ2xpbmVcIjogXCJBIFN1YnRsZSBNYW5pcHVsYXRvciAmIFNweVwiLFxuICAgICAgICAgICAgLy8gXCJzeXN0ZW0uYWNxdWFpbnRhbmNlc19uYW1lXCI6IFwiU2x5IEZyaWVuZHMgJiBSaXZhbHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLmZyaWVuZHNfbmFtZVwiOiBcIlNseSBGcmllbmRzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5yaXZhbHNfbmFtZVwiOiBcIlNseWVyIFJpdmFsc1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3RhcnRpbmdfc3RhdHMuY2hhcmdlblwiOiB7XG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlLnN3YXkudmFsdWVcIjogMixcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnJlc29sdmUuY29uc29ydC52YWx1ZVwiOiAxXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzeXN0ZW0uZXhwZXJpZW5jZV9jbHVlc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJZb3UgYWRkcmVzc2VkIGEgY2hhbGxlbmdlIHdpdGggZGVjZXB0aW9uIG9yIGluZmx1ZW5jZS5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBleHByZXNzZWQgeW91ciBiZWxpZWZzLCBkcml2ZXMsIGhlcml0YWdlLCBvciBiYWNrZ3JvdW5kLlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IHN0cnVnZ2xlZCB3aXRoIGlzc3VlcyBmcm9tIHlvdXIgdmljZSBvciB0cmF1bWFzIGR1cmluZyB0aGUgc2Vzc2lvbi5cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLnRyYXVtYV9jb25kaXRpb25zXCI6IFtcIkNvbGRcIiwgXCJIYXVudGVkXCIsIFwiT2JzZXNzZWRcIiwgXCJQYXJhbm9pZFwiLCBcIlJlY2tsZXNzXCIsIFwiU29mdFwiLCBcIlVuc3RhYmxlXCIsIFwiVmljaW91c1wiXSxcbiAgICAgICAgICAgIFwic3lzdGVtLmdhdGhlcl9pbmZvX3F1ZXN0aW9uc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJXaGF0IGRvIHRoZXkgaW50ZW5kIHRvIGRvP1wiLFxuICAgICAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IHRlbGxpbmcgdGhlIHRydXRoP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBhcmUgdGhleSByZWFsbHkgZmVlbGluZz9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSByZWFsbHkgY2FyZSBhYm91dD9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBibGVuZCBpbiBoZXJlP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCdzIHJlYWxseSBnb2luZyBvbiBoZXJlP1wiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3VnZ2VzdGVkX2FiaWxpdHlcIjogXCJSb29rJ3MgR2FtYml0XCJcbiAgICAgICAgfSxcbiAgICAgICAgU3BpZGVyOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5iZ0ltZ1wiOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9pY29ucy9jbGFzcy1pY29ucy9zcGlkZXItdHJhbnMuc3ZnXCIsXG4gICAgICAgICAgICBcInN5c3RlbS50YWdsaW5lXCI6IFwiQSBEZXZpb3VzIE1hc3Rlcm1pbmRcIixcbiAgICAgICAgICAgIC8vIFwic3lzdGVtLmFjcXVhaW50YW5jZXNfbmFtZVwiOiBcIlNocmV3ZCBGcmllbmRzICYgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5mcmllbmRzX25hbWVcIjogXCJTaHJld2QgRnJpZW5kc1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0ucml2YWxzX25hbWVcIjogXCJWZXJ5IFNocmV3ZCBSaXZhbHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnN0YXJ0aW5nX3N0YXRzLmNoYXJnZW5cIjoge1xuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMucmVzb2x2ZS5jb25zb3J0LnZhbHVlXCI6IDIsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5pbnNpZ2h0LnN0dWR5LnZhbHVlXCI6IDFcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInN5c3RlbS5leHBlcmllbmNlX2NsdWVzXCI6IFtcbiAgICAgICAgICAgICAgICBcIllvdSBhZGRyZXNzZWQgYSBjaGFsbGVuZ2Ugd2l0aCBjYWxjdWxhdGlvbiBvciBjb25zcGlyYWN5LlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IGV4cHJlc3NlZCB5b3VyIGJlbGllZnMsIGRyaXZlcywgaGVyaXRhZ2UsIG9yIGJhY2tncm91bmQuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3Ugc3RydWdnbGVkIHdpdGggaXNzdWVzIGZyb20geW91ciB2aWNlIG9yIHRyYXVtYXMgZHVyaW5nIHRoZSBzZXNzaW9uLlwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0udHJhdW1hX2NvbmRpdGlvbnNcIjogW1wiQ29sZFwiLCBcIkhhdW50ZWRcIiwgXCJPYnNlc3NlZFwiLCBcIlBhcmFub2lkXCIsIFwiUmVja2xlc3NcIiwgXCJTb2Z0XCIsIFwiVW5zdGFibGVcIiwgXCJWaWNpb3VzXCJdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZ2F0aGVyX2luZm9fcXVlc3Rpb25zXCI6IFtcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSB3YW50IG1vc3Q/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0IHNob3VsZCBJIGxvb2sgb3V0IGZvcj9cIixcbiAgICAgICAgICAgICAgICBcIldoZXJlJ3MgdGhlIGxldmVyYWdlIGhlcmU/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgZGlzY292ZXIgW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS5zdWdnZXN0ZWRfYWJpbGl0eVwiOiBcIkZvcmVzaWdodFwiXG4gICAgICAgIH0sXG4gICAgICAgIFdoaXNwZXI6IHtcbiAgICAgICAgICAgIFwic3lzdGVtLmJnSW1nXCI6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2ljb25zL2NsYXNzLWljb25zL3doaXNwZXItdHJhbnMuc3ZnXCIsXG4gICAgICAgICAgICBcInN5c3RlbS50YWdsaW5lXCI6IFwiQW4gQXJjYW5lIEFkZXB0ICYgQ2hhbm5lbGVyXCIsXG4gICAgICAgICAgICAvLyBcInN5c3RlbS5hY3F1YWludGFuY2VzX25hbWVcIjogXCJTdHJhbmdlIEZyaWVuZHMgJiBSaXZhbHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLmZyaWVuZHNfbmFtZVwiOiBcIlN0cmFuZ2UgRnJpZW5kc1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0ucml2YWxzX25hbWVcIjogXCJTdHJhbmdlciBSaXZhbHNcIixcbiAgICAgICAgICAgIFwic3lzdGVtLnN0YXJ0aW5nX3N0YXRzLmNoYXJnZW5cIjoge1xuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMucmVzb2x2ZS5hdHR1bmUudmFsdWVcIjogMixcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLmluc2lnaHQuc3R1ZHkudmFsdWVcIjogMVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXNcIjogW1xuICAgICAgICAgICAgICAgIFwiWW91IGFkZHJlc3NlZCBhIGNoYWxsZW5nZSB3aXRoIGtub3dsZWRnZSBvciBhcmNhbmUgcG93ZXIuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3UgZXhwcmVzc2VkIHlvdXIgYmVsaWVmcywgZHJpdmVzLCBoZXJpdGFnZSwgb3IgYmFja2dyb3VuZC5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBzdHJ1Z2dsZWQgd2l0aCBpc3N1ZXMgZnJvbSB5b3VyIHZpY2Ugb3IgdHJhdW1hcyBkdXJpbmcgdGhlIHNlc3Npb24uXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS50cmF1bWFfY29uZGl0aW9uc1wiOiBbXCJDb2xkXCIsIFwiSGF1bnRlZFwiLCBcIk9ic2Vzc2VkXCIsIFwiUGFyYW5vaWRcIiwgXCJSZWNrbGVzc1wiLCBcIlNvZnRcIiwgXCJVbnN0YWJsZVwiLCBcIlZpY2lvdXNcIl0sXG4gICAgICAgICAgICBcInN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnNcIjogW1xuICAgICAgICAgICAgICAgIFwiV2hhdCBpcyBhcmNhbmUgb3Igd2VpcmQgaGVyZT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgZWNob2VzIGluIHRoZSBnaG9zdCBmaWVsZD9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgaXMgaGlkZGVuIG9yIGxvc3QgaGVyZT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0IGRyaXZlcyB0aGVtIHRvIGRvIHRoaXM/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgcmV2ZWFsIFtYXT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLnN1Z2dlc3RlZF9hYmlsaXR5XCI6IFwiQ29tcGVsXCJcbiAgICAgICAgfSxcbiAgICAgICAgR2hvc3Q6IHtcbiAgICAgICAgICAgIFwic3lzdGVtLmJnSW1nXCI6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2ljb25zL2NsYXNzLWljb25zL2dob3N0LXRyYW5zLnN2Z1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0udGFnbGluZVwiOiBcIkEgVmVuZ2VmdWwgRGlzZW1ib2RpZWQgU3Bpcml0XCIsXG4gICAgICAgICAgICBcInN5c3RlbS5hY3F1YWludGFuY2VzX25hbWVcIjogXCJFbmVtaWVzICYgUml2YWxzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5zdGFydGluZ19zdGF0cy5hZGRcIjoge1xuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMuaW5zaWdodC5odW50LnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5wcm93ZXNzLnByb3dsLnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlLmF0dHVuZS52YWx1ZVwiOiAxXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgXCJzeXN0ZW0uZXhwZXJpZW5jZV9jbHVlc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJZb3UgZXhhY3RlZCB2ZW5nZWFuY2UgdXBvbiB0aG9zZSB3aG9tIHlvdSBkZWVtIGRlc2VydmluZy5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBleHByZXNzZWQgeW91ciBvdXRyYWdlIG9yIGFuZ2VyLCBvciBzZXR0bGVkIHNjb3JlcyBmcm9tIHlvdXIgaGVyaXRhZ2UsIG9yIGJhY2tncm91bmQuXCIsXG4gICAgICAgICAgICAgICAgXCJZb3Ugc3RydWdnbGVkIHdpdGggaXNzdWVzIGZyb20geW91ciBuZWVkIG9yIGdsb29tcyBkdXJpbmcgdGhlIHNlc3Npb24uXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS50cmF1bWFfY29uZGl0aW9uc1wiOiBbXCJDaGFvdGljXCIsIFwiRGVzdHJ1Y3RpdmVcIiwgXCJGdXJpb3VzXCIsIFwiT2JzZXNzaXZlXCIsIFwiVGVycml0b3JpYWxcIiwgXCJTYXZhZ2VcIl0sXG4gICAgICAgICAgICBcInN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnNcIjogW1xuICAgICAgICAgICAgICAgIFwiV2hhdCBkbyB0aGV5IGludGVuZCB0byBkbz9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBnZXQgdGhlbSB0byBbWF0/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0IGFyZSB0aGV5IHJlYWxseSBmZWVsaW5nP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBzaG91bGQgSSBsb29rb3V0IGZvcj9cIixcbiAgICAgICAgICAgICAgICBcIldoZXJlJ3MgdGhlIHdlYWtuZXNzIGhlcmU/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgZmluZCBbWF0/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0J3MgcmVhbGx5IGdvaW5nIG9uIGhlcmU/XCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS5hdXRvX2FiaWxpdGllc1wiOiBbXCJHaG9zdCBGb3JtXCJdXG4gICAgICAgIH0sXG4gICAgICAgIEh1bGw6IHtcbiAgICAgICAgICAgIFwic3lzdGVtLmJnSW1nXCI6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2ljb25zL2NsYXNzLWljb25zL2h1bGwtdHJhbnMuc3ZnXCIsXG4gICAgICAgICAgICBcInN5c3RlbS50YWdsaW5lXCI6IFwiQW4gQW5pbWF0ZWQgU3BhcmstQ3JhZnQgRnJhbWVcIixcbiAgICAgICAgICAgIFwic3lzdGVtLmFjcXVhaW50YW5jZXNfbmFtZVwiOiBcIk1hc3RlclwiLFxuICAgICAgICAgICAgXCJzeXN0ZW0uc3RhcnRpbmdfc3RhdHMuYWRkXCI6IHtcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnByb3dlc3Muc2tpcm1pc2gudmFsdWVcIjogMSxcbiAgICAgICAgICAgICAgICBcInN5c3RlbS5hdHRyaWJ1dGVzLnJlc29sdmUuYXR0dW5lLnZhbHVlXCI6IDFcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBcInN5c3RlbS5leHBlcmllbmNlX2NsdWVzXCI6IFtcbiAgICAgICAgICAgICAgICBcIllvdSBmdWxmaWxsZWQgeW91ciBmdW5jdGlvbnMgZGVzcGl0ZSBkaWZmaWN1bHR5IG9yIGRhbmdlci5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBzdXBwcmVzc2VkIG9yIGlnbm9yZWQgeW91ciBmb3JtZXIgaHVtYW4gYmVsaWVmcywgZHJpdmVzLCBoZXJpdGFnZSwgb3IgYmFja2dyb3VuZC5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBzdHJ1Z2dsZWQgd2l0aCBpc3N1ZXMgZnJvbSB5b3VyIHdlYXIgZHVyaW5nIHRoZSBzZXNzaW9uLlwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgXCJzeXN0ZW0udHJhdW1hX2NvbmRpdGlvbnNcIjogW1wiQ2xhbmtpbmdcIiwgXCJMZWFraW5nXCIsIFwiRml4YXRlZFwiLCBcIlNtb2tpbmdcIiwgXCJTcGFya2luZ1wiLCBcIlVuc3RhYmxlXCJdLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZ2F0aGVyX2luZm9fcXVlc3Rpb25zXCI6IFtcbiAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSBpbnRlbmQgdG8gZG8/XCIsXG4gICAgICAgICAgICAgICAgXCJIb3cgY2FuIEkgZ2V0IHRoZW0gdG8gW1hdP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hhdCBhcmUgdGhleSByZWFsbHkgZG9pbmc/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0IHNob3VsZCBJIGxvb2tvdXQgZm9yP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hlcmUncyB0aGUgd2Vha25lc3MgaGVyZT9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBmaW5kIFtYXT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLmF1dG9fYWJpbGl0aWVzXCI6IFtcIkF1dG9tYXRvblwiXVxuICAgICAgICB9LFxuICAgICAgICBWYW1waXJlOiB7XG4gICAgICAgICAgICBcInN5c3RlbS5iZ0ltZ1wiOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9pY29ucy9jbGFzcy1pY29ucy92YW1waXJlLXRyYW5zLnN2Z1wiLFxuICAgICAgICAgICAgXCJzeXN0ZW0udGFnbGluZVwiOiBcIkFuIEFuaW1hdGVkIFVuZGVhZCBCb2R5XCIsXG4gICAgICAgICAgICBcInN5c3RlbS5hY3F1YWludGFuY2VzX25hbWVcIjogXCJEYXJrIFNlcnZhbnRzXCIsXG4gICAgICAgICAgICBcInN5c3RlbS5zdGFydGluZ19zdGF0cy5hZGRcIjoge1xuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMuaW5zaWdodC5odW50LnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5wcm93ZXNzLnByb3dsLnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5wcm93ZXNzLnNraXJtaXNoLnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlLmF0dHVuZS52YWx1ZVwiOiAxLFxuICAgICAgICAgICAgICAgIFwic3lzdGVtLmF0dHJpYnV0ZXMucmVzb2x2ZS5jb21tYW5kLnZhbHVlXCI6IDEsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlLnN3YXkudmFsdWVcIjogMVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIFwic3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXNcIjogW1xuICAgICAgICAgICAgICAgIFwiWW91IGRpc3BsYXllZCB5b3VyIGRvbWluYW5jZSBvciBzbGF5ZWQgd2l0aG91dCBtZXJjeS5cIixcbiAgICAgICAgICAgICAgICBcIllvdSBleHByZXNzZWQgeW91ciBiZWxpZWZzLCBkcml2ZXMsIGhlcml0YWdlLCBvciBiYWNrZ3JvdW5kLlwiLFxuICAgICAgICAgICAgICAgIFwiWW91IHN0cnVnZ2xlZCB3aXRoIGlzc3VlcyBmcm9tIHlvdXIgdmljZSwgdHJhdW1hcywgb3Igc3RyaWN0dXJlcyBkdXJpbmcgdGhlIHNlc3Npb24uXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBcInN5c3RlbS50cmF1bWFfY29uZGl0aW9uc1wiOiBbXCJDb2xkXCIsIFwiSGF1bnRlZFwiLCBcIk9ic2Vzc2VkXCIsIFwiUGFyYW5vaWRcIiwgXCJSdXRobGVzc1wiLCBcIlNlY3JldGl2ZVwiLCBcIlVuc3RhYmxlXCIsIFwiVmljaW91c1wiXSxcbiAgICAgICAgICAgIFwic3lzdGVtLmdhdGhlcl9pbmZvX3F1ZXN0aW9uc1wiOiBbXG4gICAgICAgICAgICAgICAgXCJXaGF0IGRvIHRoZXkgaW50ZW5kIHRvIGRvP1wiLFxuICAgICAgICAgICAgICAgIFwiSG93IGNhbiBJIGdldCB0aGVtIHRvIFtYXT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQgYXJlIHRoZXkgcmVhbGx5IGZlZWxpbmc/XCIsXG4gICAgICAgICAgICAgICAgXCJXaGF0IHNob3VsZCBJIGxvb2tvdXQgZm9yP1wiLFxuICAgICAgICAgICAgICAgIFwiV2hlcmUncyB0aGUgd2Vha25lc3MgaGVyZT9cIixcbiAgICAgICAgICAgICAgICBcIkhvdyBjYW4gSSBmaW5kIFtYXT9cIixcbiAgICAgICAgICAgICAgICBcIldoYXQncyByZWFsbHkgZ29pbmcgb24gaGVyZT9cIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwic3lzdGVtLmF1dG9fYWJpbGl0aWVzXCI6IFtcIlVuZGVhZFwiXVxuICAgICAgICB9XG4gICAgfSxcbiAgICBDbG9ja1NpemVzOiBbMSwgMiwgMywgNCwgNSwgNiwgOCwgMTAsIDEyXSxcbiAgICBBY3RvclR5cGVzOiBbXG4gICAgICAgIEJsYWRlc0FjdG9yVHlwZS5wYyxcbiAgICAgICAgQmxhZGVzQWN0b3JUeXBlLm5wYyxcbiAgICAgICAgQmxhZGVzQWN0b3JUeXBlLmNyZXcsXG4gICAgICAgIEJsYWRlc0FjdG9yVHlwZS5mYWN0aW9uXG4gICAgXSxcbiAgICBJdGVtVHlwZXM6IFtcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuYWJpbGl0eSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuYmFja2dyb3VuZCxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuY2xvY2tfa2VlcGVyLFxuICAgICAgICBCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZyxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuY3Jld19hYmlsaXR5LFxuICAgICAgICBCbGFkZXNJdGVtVHlwZS5jcmV3X3JlcHV0YXRpb24sXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmNyZXdfcGxheWJvb2ssXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmNyZXdfdXBncmFkZSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuZmVhdHVyZSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuZ21fdHJhY2tlcixcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuaGVyaXRhZ2UsXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmdlYXIsXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rLFxuICAgICAgICBCbGFkZXNJdGVtVHlwZS5wcmVmZXJyZWRfb3AsXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLnN0cmljdHVyZSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUudmljZSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUucHJvamVjdCxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUucml0dWFsLFxuICAgICAgICBCbGFkZXNJdGVtVHlwZS5kZXNpZ24sXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmxvY2F0aW9uLFxuICAgICAgICBCbGFkZXNJdGVtVHlwZS5zY29yZVxuICAgIF0sXG4gICAgU2ltcGxlSXRlbVR5cGVzOiBbXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmJhY2tncm91bmQsXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLmNyZXdfcmVwdXRhdGlvbixcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuZmVhdHVyZSxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuaGVyaXRhZ2UsXG4gICAgICAgIEJsYWRlc0l0ZW1UeXBlLnByZWZlcnJlZF9vcCxcbiAgICAgICAgQmxhZGVzSXRlbVR5cGUuc3RyaWN0dXJlXG4gICAgXSxcbiAgICBBdHRyaWJ1dGU6IFtcbiAgICAgICAgQXR0cmlidXRlVHJhaXQuaW5zaWdodCxcbiAgICAgICAgQXR0cmlidXRlVHJhaXQucHJvd2VzcyxcbiAgICAgICAgQXR0cmlidXRlVHJhaXQucmVzb2x2ZVxuICAgIF0sXG4gICAgQWN0aW9uOiB7XG4gICAgICAgIFtBdHRyaWJ1dGVUcmFpdC5pbnNpZ2h0XTogW0FjdGlvblRyYWl0Lmh1bnQsIEFjdGlvblRyYWl0LnN0dWR5LCBBY3Rpb25UcmFpdC5zdXJ2ZXksIEFjdGlvblRyYWl0LnRpbmtlcl0sXG4gICAgICAgIFtBdHRyaWJ1dGVUcmFpdC5wcm93ZXNzXTogW0FjdGlvblRyYWl0LmZpbmVzc2UsIEFjdGlvblRyYWl0LnByb3dsLCBBY3Rpb25UcmFpdC5za2lybWlzaCwgQWN0aW9uVHJhaXQud3JlY2tdLFxuICAgICAgICBbQXR0cmlidXRlVHJhaXQucmVzb2x2ZV06IFtBY3Rpb25UcmFpdC5hdHR1bmUsIEFjdGlvblRyYWl0LmNvbW1hbmQsIEFjdGlvblRyYWl0LmNvbnNvcnQsIEFjdGlvblRyYWl0LnN3YXldXG4gICAgfSxcbiAgICBWaWNlczogW1xuICAgICAgICBWaWNlLkZhaXRoLFxuICAgICAgICBWaWNlLkdhbWJsaW5nLFxuICAgICAgICBWaWNlLkx1eHVyeSxcbiAgICAgICAgVmljZS5PYmxpZ2F0aW9uLFxuICAgICAgICBWaWNlLlBsZWFzdXJlLFxuICAgICAgICBWaWNlLlN0dXBvcixcbiAgICAgICAgVmljZS5XZWlyZCxcbiAgICAgICAgVmljZS5Xb3JzaGlwLFxuICAgICAgICBWaWNlLkxpdmluZ19Fc3NlbmNlLFxuICAgICAgICBWaWNlLkxpZmVfRXNzZW5jZSxcbiAgICAgICAgVmljZS5FbGVjdHJvcGxhc21pY19Qb3dlclxuICAgIF1cbn07XG4vLyAjZW5kcmVnaW9uXG4vLyAjcmVnaW9uIFJBTkRPTUlaRVIgREFUQVxuZXhwb3J0IGNvbnN0IFJhbmRvbWl6ZXJzID0ge1xuICAgIE5QQzoge1xuICAgICAgICBoZXJpdGFnZTogW1xuICAgICAgICAgICAgXCJBa29yb3NpXCIsXG4gICAgICAgICAgICBcIkFrb3Jvc2lcIixcbiAgICAgICAgICAgIFwiQWtvcm9zaVwiLFxuICAgICAgICAgICAgXCJBa29yb3NpXCIsXG4gICAgICAgICAgICBcIkFrb3Jvc2lcIixcbiAgICAgICAgICAgIFwiQWtvcm9zaVwiLFxuICAgICAgICAgICAgXCJEYWdnZXIgSXNsYW5kZXJcIixcbiAgICAgICAgICAgIFwiSXJ1dmlhblwiLFxuICAgICAgICAgICAgXCJTZXZlcm9zaVwiLFxuICAgICAgICAgICAgXCJTa292bGFuZGVyXCIsXG4gICAgICAgICAgICBcIlNrb3ZsYW5kZXJcIixcbiAgICAgICAgICAgIFwiVHljaGVyb3NpXCJcbiAgICAgICAgXSxcbiAgICAgICAgYmFja2dyb3VuZDogW1xuICAgICAgICAgICAgXCJBY2FkZW1pY1wiLFxuICAgICAgICAgICAgXCJBY2FkZW1pY1wiLFxuICAgICAgICAgICAgXCJBY2FkZW1pY1wiLFxuICAgICAgICAgICAgXCJMYWJvclwiLFxuICAgICAgICAgICAgXCJMYWJvclwiLFxuICAgICAgICAgICAgXCJMYWJvclwiLFxuICAgICAgICAgICAgXCJMYWJvclwiLFxuICAgICAgICAgICAgXCJMYXdcIixcbiAgICAgICAgICAgIFwiTGF3XCIsXG4gICAgICAgICAgICBcIkxhd1wiLFxuICAgICAgICAgICAgXCJNaWxpdGFyeVwiLFxuICAgICAgICAgICAgXCJNaWxpdGFyeVwiLFxuICAgICAgICAgICAgXCJNaWxpdGFyeVwiLFxuICAgICAgICAgICAgXCJNaWxpdGFyeVwiLFxuICAgICAgICAgICAgXCJNaWxpdGFyeVwiLFxuICAgICAgICAgICAgXCJOZXcgTW9uZXlcIixcbiAgICAgICAgICAgIFwiTmV3IE1vbmV5XCIsXG4gICAgICAgICAgICBcIk9sZCBNb25leVwiLFxuICAgICAgICAgICAgXCJPbGQgTW9uZXlcIixcbiAgICAgICAgICAgIFwiUG9saXRpY3NcIixcbiAgICAgICAgICAgIFwiUG9saXRpY3NcIixcbiAgICAgICAgICAgIFwiVHJhZGVcIixcbiAgICAgICAgICAgIFwiVHJhZGVcIixcbiAgICAgICAgICAgIFwiVHJhZGVcIixcbiAgICAgICAgICAgIFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgXCJVbmRlcndvcmxkXCIsXG4gICAgICAgICAgICBcIlVuZGVyd29ybGRcIixcbiAgICAgICAgICAgIFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgXCJVbmRlcndvcmxkXCIsXG4gICAgICAgICAgICBcIldlaXJkXCJcbiAgICAgICAgXSxcbiAgICAgICAgZ2VuZGVyOiBbXG4gICAgICAgICAgICBcIk1cIixcbiAgICAgICAgICAgIFwiTVwiLFxuICAgICAgICAgICAgXCJNXCIsXG4gICAgICAgICAgICBcIk1cIixcbiAgICAgICAgICAgIFwiRlwiLFxuICAgICAgICAgICAgXCJGXCIsXG4gICAgICAgICAgICBcIkZcIixcbiAgICAgICAgICAgIFwiVVwiLFxuICAgICAgICAgICAgXCJYXCJcbiAgICAgICAgXSxcbiAgICAgICAgYXBwZWFyYW5jZTogW1xuICAgICAgICAgICAgXCJBdGhsZXRpY1wiLFxuICAgICAgICAgICAgXCJCZWFyZFwiLFxuICAgICAgICAgICAgXCJCb255XCIsXG4gICAgICAgICAgICBcIkNoaXNlbGVkXCIsXG4gICAgICAgICAgICBcIkNyaXBwbGVkIC8gUHJvc3RoZXRpY1wiLFxuICAgICAgICAgICAgXCJDdXRlXCIsXG4gICAgICAgICAgICBcIkRhcmtcIixcbiAgICAgICAgICAgIFwiRGVsaWNhdGVcIixcbiAgICAgICAgICAgIFwiRGlzZmlndXJlZCAvIE1haW1lZFwiLFxuICAgICAgICAgICAgXCJFbGVnYW50XCIsXG4gICAgICAgICAgICBcIkZhaXJcIixcbiAgICAgICAgICAgIFwiR2xhc3NlcyAvIE1vbm9jbGVcIixcbiAgICAgICAgICAgIFwiSGFuZHNvbWVcIixcbiAgICAgICAgICAgIFwiTGFyZ2VcIixcbiAgICAgICAgICAgIFwiTG9uZyBIYWlyXCIsXG4gICAgICAgICAgICBcIkxvdmVseVwiLFxuICAgICAgICAgICAgXCJPbGRcIixcbiAgICAgICAgICAgIFwiUGxhaW5cIixcbiAgICAgICAgICAgIFwiUGx1bXBcIixcbiAgICAgICAgICAgIFwiUm91Z2hcIixcbiAgICAgICAgICAgIFwiU2NhcnJlZFwiLFxuICAgICAgICAgICAgXCJTZXh5XCIsXG4gICAgICAgICAgICBcIlNoYXZlZCBCYWxkXCIsXG4gICAgICAgICAgICBcIlNob3J0XCIsXG4gICAgICAgICAgICBcIlNsaW1cIixcbiAgICAgICAgICAgIFwiU3Rvb3BlZFwiLFxuICAgICAgICAgICAgXCJTdG91dFwiLFxuICAgICAgICAgICAgXCJTdHJhbmdlXCIsXG4gICAgICAgICAgICBcIlN0cmlraW5nXCIsXG4gICAgICAgICAgICBcIlN0eWxpc2hcIixcbiAgICAgICAgICAgIFwiVGFsbFwiLFxuICAgICAgICAgICAgXCJUYXR0b29lZFwiLFxuICAgICAgICAgICAgXCJXZWF0aGVyZWRcIixcbiAgICAgICAgICAgIFwiV2lnXCIsXG4gICAgICAgICAgICBcIldpbGRcIixcbiAgICAgICAgICAgIFwiV2lyeVwiLFxuICAgICAgICAgICAgXCJXb3JuXCIsXG4gICAgICAgICAgICBcIllvdW5nXCJcbiAgICAgICAgXSxcbiAgICAgICAgZ29hbDogW1xuICAgICAgICAgICAgXCJBY2hpZXZlbWVudFwiLFxuICAgICAgICAgICAgXCJBdXRob3JpdHlcIixcbiAgICAgICAgICAgIFwiQ2hhbmdlXCIsXG4gICAgICAgICAgICBcIkNoYW9zIC8gRGVzdHJ1Y3Rpb25cIixcbiAgICAgICAgICAgIFwiQ29udHJvbFwiLFxuICAgICAgICAgICAgXCJDb29wZXJhdGlvblwiLFxuICAgICAgICAgICAgXCJGcmVlZG9tXCIsXG4gICAgICAgICAgICBcIkhhcHBpbmVzc1wiLFxuICAgICAgICAgICAgXCJJbmZhbXkgLyBGZWFyXCIsXG4gICAgICAgICAgICBcIkp1c3RpY2VcIixcbiAgICAgICAgICAgIFwiS25vd2xlZGdlXCIsXG4gICAgICAgICAgICBcIkxvdmVcIixcbiAgICAgICAgICAgIFwiUGxlYXN1cmVcIixcbiAgICAgICAgICAgIFwiUG93ZXJcIixcbiAgICAgICAgICAgIFwiUHJlc3RpZ2UgLyBGYW1lXCIsXG4gICAgICAgICAgICBcIlJlc3BlY3RcIixcbiAgICAgICAgICAgIFwiUmV2ZW5nZVwiLFxuICAgICAgICAgICAgXCJXZWFsdGhcIlxuICAgICAgICBdLFxuICAgICAgICBtZXRob2Q6IFtcbiAgICAgICAgICAgIFwiQWxjaGVteVwiLFxuICAgICAgICAgICAgXCJBcmNhbmVcIixcbiAgICAgICAgICAgIFwiQmxhY2ttYWlsXCIsXG4gICAgICAgICAgICBcIkNoYW9zXCIsXG4gICAgICAgICAgICBcIkNvbW1lcmNlXCIsXG4gICAgICAgICAgICBcIkVzcGlvbmFnZVwiLFxuICAgICAgICAgICAgXCJIYXJkIFdvcmtcIixcbiAgICAgICAgICAgIFwiTGF3IC8gUG9saXRpY3NcIixcbiAgICAgICAgICAgIFwiTWFuaXB1bGF0aW9uXCIsXG4gICAgICAgICAgICBcIk5lZ290aWF0aW9uXCIsXG4gICAgICAgICAgICBcIlNhYm90YWdlXCIsXG4gICAgICAgICAgICBcIlN0cmF0ZWd5XCIsXG4gICAgICAgICAgICBcIlN0dWR5XCIsXG4gICAgICAgICAgICBcIlN1YnRlcmZ1Z2VcIixcbiAgICAgICAgICAgIFwiVGVhbXdvcmtcIixcbiAgICAgICAgICAgIFwiVGhlZnRcIixcbiAgICAgICAgICAgIFwiVGhyZWF0c1wiLFxuICAgICAgICAgICAgXCJWaW9sZW5jZVwiXG4gICAgICAgIF0sXG4gICAgICAgIHByb2Zlc3Npb246IFtcbiAgICAgICAgICAgIFwiQWR2b2NhdGVcIixcbiAgICAgICAgICAgIFwiQXBpYXJpc3RcIixcbiAgICAgICAgICAgIFwiQXJjaGl0ZWN0XCIsXG4gICAgICAgICAgICBcIkFydGlzdFwiLFxuICAgICAgICAgICAgXCJBdXRob3JcIixcbiAgICAgICAgICAgIFwiQmFpbGlmZlwiLFxuICAgICAgICAgICAgXCJCYWtlclwiLFxuICAgICAgICAgICAgXCJCYWtlclwiLFxuICAgICAgICAgICAgXCJCYWtlclwiLFxuICAgICAgICAgICAgXCJCYW5rZXJcIixcbiAgICAgICAgICAgIFwiQmFyYmVyXCIsXG4gICAgICAgICAgICBcIkJhcmJlclwiLFxuICAgICAgICAgICAgXCJCYXJiZXJcIixcbiAgICAgICAgICAgIFwiQmxhY2tzbWl0aFwiLFxuICAgICAgICAgICAgXCJCbGFja3NtaXRoXCIsXG4gICAgICAgICAgICBcIkJsYWNrc21pdGhcIixcbiAgICAgICAgICAgIFwiQm91bnR5IEh1bnRlclwiLFxuICAgICAgICAgICAgXCJCcmV3ZXJcIixcbiAgICAgICAgICAgIFwiQnJld2VyXCIsXG4gICAgICAgICAgICBcIkJyZXdlclwiLFxuICAgICAgICAgICAgXCJCdXRjaGVyXCIsXG4gICAgICAgICAgICBcIkJ1dGNoZXJcIixcbiAgICAgICAgICAgIFwiQnV0Y2hlclwiLFxuICAgICAgICAgICAgXCJDYXB0YWluXCIsXG4gICAgICAgICAgICBcIkNhcnBlbnRlclwiLFxuICAgICAgICAgICAgXCJDYXJwZW50ZXJcIixcbiAgICAgICAgICAgIFwiQ2FycGVudGVyXCIsXG4gICAgICAgICAgICBcIkNhcnR3cmlnaHRcIixcbiAgICAgICAgICAgIFwiQ2FydHdyaWdodFwiLFxuICAgICAgICAgICAgXCJDYXJ0d3JpZ2h0XCIsXG4gICAgICAgICAgICBcIkNoYW5kbGVyXCIsXG4gICAgICAgICAgICBcIkNoYW5kbGVyXCIsXG4gICAgICAgICAgICBcIkNoYW5kbGVyXCIsXG4gICAgICAgICAgICBcIkNsZXJrXCIsXG4gICAgICAgICAgICBcIkNsZXJrXCIsXG4gICAgICAgICAgICBcIkNsZXJrXCIsXG4gICAgICAgICAgICBcIkNsb2NrbWFrZXJcIixcbiAgICAgICAgICAgIFwiQ29iYmxlclwiLFxuICAgICAgICAgICAgXCJDb2JibGVyXCIsXG4gICAgICAgICAgICBcIkNvYmJsZXJcIixcbiAgICAgICAgICAgIFwiQ29tcG9zZXJcIixcbiAgICAgICAgICAgIFwiQ29vcGVyXCIsXG4gICAgICAgICAgICBcIkNvb3BlclwiLFxuICAgICAgICAgICAgXCJDb29wZXJcIixcbiAgICAgICAgICAgIFwiQ291cnRlc2FuXCIsXG4gICAgICAgICAgICBcIkNyaW1pbmFsXCIsXG4gICAgICAgICAgICBcIkNyaW1pbmFsXCIsXG4gICAgICAgICAgICBcIkNyaW1pbmFsXCIsXG4gICAgICAgICAgICBcIkN1bHRpdmF0b3JcIixcbiAgICAgICAgICAgIFwiQ3VsdGl2YXRvclwiLFxuICAgICAgICAgICAgXCJDdWx0aXZhdG9yXCIsXG4gICAgICAgICAgICBcIkRpcGxvbWF0XCIsXG4gICAgICAgICAgICBcIkRyaXZlclwiLFxuICAgICAgICAgICAgXCJEcml2ZXJcIixcbiAgICAgICAgICAgIFwiRHJpdmVyXCIsXG4gICAgICAgICAgICBcIkR5ZXJcIixcbiAgICAgICAgICAgIFwiRHllclwiLFxuICAgICAgICAgICAgXCJEeWVyXCIsXG4gICAgICAgICAgICBcIkVtYnJvaWRlcmVyXCIsXG4gICAgICAgICAgICBcIkVtYnJvaWRlcmVyXCIsXG4gICAgICAgICAgICBcIkVtYnJvaWRlcmVyXCIsXG4gICAgICAgICAgICBcIkV4cGxvcmVyXCIsXG4gICAgICAgICAgICBcIkZpc2htb25nZXJcIixcbiAgICAgICAgICAgIFwiRmlzaG1vbmdlclwiLFxuICAgICAgICAgICAgXCJGaXNobW9uZ2VyXCIsXG4gICAgICAgICAgICBcIkZ1cnJpZXJcIixcbiAgICAgICAgICAgIFwiR2xhc3MgQmxvd2VyXCIsXG4gICAgICAgICAgICBcIkdvYXQgSGVyZFwiLFxuICAgICAgICAgICAgXCJHb2F0IEhlcmRcIixcbiAgICAgICAgICAgIFwiR29hdCBIZXJkXCIsXG4gICAgICAgICAgICBcIkdvbmRvbGllclwiLFxuICAgICAgICAgICAgXCJHb25kb2xpZXJcIixcbiAgICAgICAgICAgIFwiR29uZG9saWVyXCIsXG4gICAgICAgICAgICBcIkd1YXJkXCIsXG4gICAgICAgICAgICBcIkd1YXJkXCIsXG4gICAgICAgICAgICBcIkd1YXJkXCIsXG4gICAgICAgICAgICBcIkphaWxlclwiLFxuICAgICAgICAgICAgXCJKZXdlbGVyXCIsXG4gICAgICAgICAgICBcIkpvdXJuYWxpc3RcIixcbiAgICAgICAgICAgIFwiTGVhdGhlcndvcmtlclwiLFxuICAgICAgICAgICAgXCJMZWF0aGVyd29ya2VyXCIsXG4gICAgICAgICAgICBcIkxlYXRoZXJ3b3JrZXJcIixcbiAgICAgICAgICAgIFwiTGVlY2hcIixcbiAgICAgICAgICAgIFwiTG9ja3NtaXRoXCIsXG4gICAgICAgICAgICBcIk1hZ2lzdHJhdGVcIixcbiAgICAgICAgICAgIFwiTWFzb25cIixcbiAgICAgICAgICAgIFwiTWFzb25cIixcbiAgICAgICAgICAgIFwiTWFzb25cIixcbiAgICAgICAgICAgIFwiTWVyY2hhbnRcIixcbiAgICAgICAgICAgIFwiTWVyY2hhbnRcIixcbiAgICAgICAgICAgIFwiTWVyY2hhbnRcIixcbiAgICAgICAgICAgIFwiTWVzc2VuZ2VyXCIsXG4gICAgICAgICAgICBcIk1lc3NlbmdlclwiLFxuICAgICAgICAgICAgXCJNZXNzZW5nZXJcIixcbiAgICAgICAgICAgIFwiTXVzaWNpYW5cIixcbiAgICAgICAgICAgIFwiUGh5c2lja2VyXCIsXG4gICAgICAgICAgICBcIlBsdW1iZXJcIixcbiAgICAgICAgICAgIFwiUHJpbnRlclwiLFxuICAgICAgICAgICAgXCJSYWlsIEphY2tcIixcbiAgICAgICAgICAgIFwiUm9vZmVyXCIsXG4gICAgICAgICAgICBcIlJvb2ZlclwiLFxuICAgICAgICAgICAgXCJSb29mZXJcIixcbiAgICAgICAgICAgIFwiUm9wZW1ha2VyXCIsXG4gICAgICAgICAgICBcIlJvcGVtYWtlclwiLFxuICAgICAgICAgICAgXCJSb3BlbWFrZXJcIixcbiAgICAgICAgICAgIFwiUnVnIE1ha2VyXCIsXG4gICAgICAgICAgICBcIlJ1ZyBNYWtlclwiLFxuICAgICAgICAgICAgXCJSdWcgTWFrZXJcIixcbiAgICAgICAgICAgIFwiU2FpbG9yXCIsXG4gICAgICAgICAgICBcIlNhaWxvclwiLFxuICAgICAgICAgICAgXCJTYWlsb3JcIixcbiAgICAgICAgICAgIFwiU2Nob2xhclwiLFxuICAgICAgICAgICAgXCJTY3JpYmVcIixcbiAgICAgICAgICAgIFwiU2VydmFudFwiLFxuICAgICAgICAgICAgXCJTZXJ2YW50XCIsXG4gICAgICAgICAgICBcIlNlcnZhbnRcIixcbiAgICAgICAgICAgIFwiU2hpcHdyaWdodFwiLFxuICAgICAgICAgICAgXCJTaGlwd3JpZ2h0XCIsXG4gICAgICAgICAgICBcIlNoaXB3cmlnaHRcIixcbiAgICAgICAgICAgIFwiU29sZGllclwiLFxuICAgICAgICAgICAgXCJTcGFya3dyaWdodFwiLFxuICAgICAgICAgICAgXCJTcGlyaXQgV2FyZGVuXCIsXG4gICAgICAgICAgICBcIlN0ZXdhcmRcIixcbiAgICAgICAgICAgIFwiVGFpbG9yXCIsXG4gICAgICAgICAgICBcIlRhaWxvclwiLFxuICAgICAgICAgICAgXCJUYWlsb3JcIixcbiAgICAgICAgICAgIFwiVGFubmVyXCIsXG4gICAgICAgICAgICBcIlRhbm5lclwiLFxuICAgICAgICAgICAgXCJUYW5uZXJcIixcbiAgICAgICAgICAgIFwiVGF4IENvbGxlY3RvclwiLFxuICAgICAgICAgICAgXCJUaW5rZXJlclwiLFxuICAgICAgICAgICAgXCJUaW5rZXJlclwiLFxuICAgICAgICAgICAgXCJUaW5rZXJlclwiLFxuICAgICAgICAgICAgXCJUcmVhc3VyZXJcIixcbiAgICAgICAgICAgIFwiVmVuZG9yXCIsXG4gICAgICAgICAgICBcIlZlbmRvclwiLFxuICAgICAgICAgICAgXCJWZW5kb3JcIixcbiAgICAgICAgICAgIFwiV2VhdmVyXCIsXG4gICAgICAgICAgICBcIldlYXZlclwiLFxuICAgICAgICAgICAgXCJXZWF2ZXJcIixcbiAgICAgICAgICAgIFwiV2hpc3BlclwiLFxuICAgICAgICAgICAgXCJXb29kd29ya2VyXCIsXG4gICAgICAgICAgICBcIldvb2R3b3JrZXJcIixcbiAgICAgICAgICAgIFwiV29vZHdvcmtlclwiXG4gICAgICAgIF0sXG4gICAgICAgIHRyYWl0OiBbXG4gICAgICAgICAgICBcIkFyY2FuZVwiLFxuICAgICAgICAgICAgXCJBcnJvZ2FudFwiLFxuICAgICAgICAgICAgXCJBcnRpc3RpY1wiLFxuICAgICAgICAgICAgXCJCb2xkXCIsXG4gICAgICAgICAgICBcIkJyYXNoXCIsXG4gICAgICAgICAgICBcIkJyYXZlXCIsXG4gICAgICAgICAgICBcIkNhbGN1bGF0aW5nXCIsXG4gICAgICAgICAgICBcIkNhbG1cIixcbiAgICAgICAgICAgIFwiQ2FuZGlkXCIsXG4gICAgICAgICAgICBcIkNhcmVsZXNzXCIsXG4gICAgICAgICAgICBcIkNhdXRpb3VzXCIsXG4gICAgICAgICAgICBcIkNhdmFsaWVyXCIsXG4gICAgICAgICAgICBcIkNoYXJtaW5nXCIsXG4gICAgICAgICAgICBcIkNvbGRcIixcbiAgICAgICAgICAgIFwiQ29tbWFuZGluZ1wiLFxuICAgICAgICAgICAgXCJDb21wYXNzaW9uYXRlXCIsXG4gICAgICAgICAgICBcIkNvbmZpZGVudFwiLFxuICAgICAgICAgICAgXCJDb25uZWN0ZWRcIixcbiAgICAgICAgICAgIFwiQ29vcGVyYXRpdmVcIixcbiAgICAgICAgICAgIFwiQ3JlYXRpdmVcIixcbiAgICAgICAgICAgIFwiQ3J1ZWxcIixcbiAgICAgICAgICAgIFwiQ3VsdHVyZWRcIixcbiAgICAgICAgICAgIFwiRGFyaW5nXCIsXG4gICAgICAgICAgICBcIkRlZmlhbnRcIixcbiAgICAgICAgICAgIFwiRGlzaG9uZXN0XCIsXG4gICAgICAgICAgICBcIkRyYW1hdGljXCIsXG4gICAgICAgICAgICBcIkVsaXRpc3RcIixcbiAgICAgICAgICAgIFwiRW5pZ21hdGljXCIsXG4gICAgICAgICAgICBcIkVudGh1c2lhc3RpY1wiLFxuICAgICAgICAgICAgXCJFcnVkaXRlXCIsXG4gICAgICAgICAgICBcIkV4cGVyaWVuY2VkXCIsXG4gICAgICAgICAgICBcIkZpZXJjZVwiLFxuICAgICAgICAgICAgXCJGbGV4aWJsZVwiLFxuICAgICAgICAgICAgXCJGcmllbmRseVwiLFxuICAgICAgICAgICAgXCJHcmFjaW91c1wiLFxuICAgICAgICAgICAgXCJHcmVlZHlcIixcbiAgICAgICAgICAgIFwiSGF1bnRlZFwiLFxuICAgICAgICAgICAgXCJJbnNpZ2h0ZnVsXCIsXG4gICAgICAgICAgICBcIktpbmRcIixcbiAgICAgICAgICAgIFwiTWVsYW5jaG9seVwiLFxuICAgICAgICAgICAgXCJNb29keVwiLFxuICAgICAgICAgICAgXCJPYnNlc3NpdmVcIixcbiAgICAgICAgICAgIFwiUGFyYW5vaWRcIixcbiAgICAgICAgICAgIFwiUGF0aWVudFwiLFxuICAgICAgICAgICAgXCJQb3B1bGFyXCIsXG4gICAgICAgICAgICBcIlByaW5jaXBsZWRcIixcbiAgICAgICAgICAgIFwiUHJvdWRcIixcbiAgICAgICAgICAgIFwiUXVpZXRcIixcbiAgICAgICAgICAgIFwiUmVja2xlc3NcIixcbiAgICAgICAgICAgIFwiUmVzcGVjdGVkXCIsXG4gICAgICAgICAgICBcIlJ1dGhsZXNzXCIsXG4gICAgICAgICAgICBcIlNhZGlzdGljXCIsXG4gICAgICAgICAgICBcIlNhdmFnZVwiLFxuICAgICAgICAgICAgXCJTZWNyZXRpdmVcIixcbiAgICAgICAgICAgIFwiU2hyZXdkXCIsXG4gICAgICAgICAgICBcIlNpbmNlcmVcIixcbiAgICAgICAgICAgIFwiU25lYWt5XCIsXG4gICAgICAgICAgICBcIlNvcGhpc3RpY2F0ZWRcIixcbiAgICAgICAgICAgIFwiU3RyYW5nZVwiLFxuICAgICAgICAgICAgXCJTdHlsaXNoXCIsXG4gICAgICAgICAgICBcIlN1YnRsZVwiLFxuICAgICAgICAgICAgXCJTdXNwaWNpb3VzXCIsXG4gICAgICAgICAgICBcIlRvdWdoXCIsXG4gICAgICAgICAgICBcIlZhaW5cIixcbiAgICAgICAgICAgIFwiVmVuZ2VmdWxcIixcbiAgICAgICAgICAgIFwiVmljaW91c1wiLFxuICAgICAgICAgICAgXCJWaXNpb25hcnlcIixcbiAgICAgICAgICAgIFwiVm9sYXRpbGVcIixcbiAgICAgICAgICAgIFwiV2VpcmRcIixcbiAgICAgICAgICAgIFwiV2lzZVwiXG4gICAgICAgIF0sXG4gICAgICAgIGludGVyZXN0czogW1xuICAgICAgICAgICAgXCJBbGNoZW15LCBtZWRpY2luZVwiLFxuICAgICAgICAgICAgXCJBbnRpcXVlcywgYXJ0aWZhY3RzLCBjdXJpb3NcIixcbiAgICAgICAgICAgIFwiQXJjYW5lIGJvb2tzLCByaXR1YWxzXCIsXG4gICAgICAgICAgICBcIkFyY2hpdGVjdHVyZSwgZnVybmlzaGluZ3NcIixcbiAgICAgICAgICAgIFwiQ2h1cmNoIG9mIEVjc3Rhc3lcIixcbiAgICAgICAgICAgIFwiQ29va2luZywgZ2FyZGVuaW5nXCIsXG4gICAgICAgICAgICBcIkNyYWZ0IChsZWF0aGVyd29yaywgZXRjLilcIixcbiAgICAgICAgICAgIFwiRGVtb24gbG9yZSwgbGVnZW5kc1wiLFxuICAgICAgICAgICAgXCJEcnVncywgZXNzZW5jZXMsIHRvYmFjY29cIixcbiAgICAgICAgICAgIFwiRXNzZW5jZXMsIGFsY2hlbXlcIixcbiAgICAgICAgICAgIFwiRXhwbG9yYXRpb24sIGFkdmVudHVyZVwiLFxuICAgICAgICAgICAgXCJGaW5lIGFydHMsIG9wZXJhLCB0aGVhdGVyXCIsXG4gICAgICAgICAgICBcIkZpbmUgY2xvdGhlcywgamV3ZWxyeSwgZnVyc1wiLFxuICAgICAgICAgICAgXCJGaW5lIGZvb2QsIHJlc3RhdXJhbnRzXCIsXG4gICAgICAgICAgICBcIkZpbmUgd2hpc2tleSwgd2luZSwgYmVlclwiLFxuICAgICAgICAgICAgXCJGb3Jnb3R0ZW4gZ29kc1wiLFxuICAgICAgICAgICAgXCJHYWRnZXRzLCBuZXcgdGVjaG5vbG9neVwiLFxuICAgICAgICAgICAgXCJHYW1ibGluZywgY2FyZHMsIGRpY2VcIixcbiAgICAgICAgICAgIFwiSGlzdG9yeSwgbGVnZW5kc1wiLFxuICAgICAgICAgICAgXCJIb3JzZXMsIHJpZGluZ1wiLFxuICAgICAgICAgICAgXCJIdW50aW5nLCBzaG9vdGluZ1wiLFxuICAgICAgICAgICAgXCJMb3ZlcnMsIHJvbWFuY2UsIHRyeXN0c1wiLFxuICAgICAgICAgICAgXCJNdXNpYywgaW5zdHJ1bWVudHMsIGRhbmNlXCIsXG4gICAgICAgICAgICBcIk5hdHVyYWwgcGhpbG9zb3BoeVwiLFxuICAgICAgICAgICAgXCJQYWludGluZywgZHJhd2luZywgc2N1bHB0dXJlXCIsXG4gICAgICAgICAgICBcIlBhcnRpZXMsIHNvY2lhbCBldmVudHNcIixcbiAgICAgICAgICAgIFwiUGF0aCBvZiBFY2hvZXNcIixcbiAgICAgICAgICAgIFwiUGV0cyAoYmlyZHMsIGRvZ3MsIGNhdHMpXCIsXG4gICAgICAgICAgICBcIlBpdC1maWdodGluZywgZHVlbHNcIixcbiAgICAgICAgICAgIFwiUG9ldHJ5LCBub3ZlbHMsIHdyaXRpbmdcIixcbiAgICAgICAgICAgIFwiUG9saXRpY3MsIGpvdXJuYWxpc21cIixcbiAgICAgICAgICAgIFwiUHJlLWNhdGFjbHlzbSBsZWdlbmRzXCIsXG4gICAgICAgICAgICBcIlNoaXBzLCBib2F0aW5nXCIsXG4gICAgICAgICAgICBcIlNwZWN0cm9sb2d5LCBlbGVjdHJvcGxhc21cIixcbiAgICAgICAgICAgIFwiV2VhcG9ucyBjb2xsZWN0b3JcIixcbiAgICAgICAgICAgIFwiV2VlcGluZyBMYWR5LCBjaGFyaXR5XCJcbiAgICAgICAgXSxcbiAgICAgICAgcXVpcms6IFtcbiAgICAgICAgICAgIFwiQSBmcmF1ZC4gU29tZSBpbXBvcnRhbnQgYXNwZWN0IGlzIGZhYnJpY2F0ZWQuXCIsXG4gICAgICAgICAgICBcIkJpZ290ZWQgYWdhaW5zdCBjdWx0dXJlIC8gYmVsaWVmIC8gc29jaWFsIGNsYXNzLlwiLFxuICAgICAgICAgICAgXCJCbGFjayBzaGVlcCAvIG91dGNhc3QgZnJvbSBmYW1pbHkgb3Igb3JnYW5pemF0aW9uLlwiLFxuICAgICAgICAgICAgXCJCbGluZCB0byBmbGF3cyBpbiBmcmllbmRzLCBhbGxpZXMsIGZhbWlseSwgZXRjLlwiLFxuICAgICAgICAgICAgXCJDZWxlYnJpdHkuIFBvcHVsYXJpemVkIGluIHByaW50IC8gc29uZyAvIHRoZWF0ZXIuXCIsXG4gICAgICAgICAgICBcIkNvbmNlcm5lZCB3aXRoIGFwcGVhcmFuY2VzLCBnb3NzaXAsIHBlZXJzLlwiLFxuICAgICAgICAgICAgXCJDdXJzZWQsIGhhdW50ZWQsIGhhcmFzc2VkIGJ5IHNwaXJpdHMgb3IgZGVtb24uXCIsXG4gICAgICAgICAgICBcIkRlZXBseSB0cmFkaXRpb25hbC4gT3Bwb3NlZCB0byBuZXcgaWRlYXMuXCIsXG4gICAgICAgICAgICBcIkRldm90ZWQgdG8gdGhlaXIgZmFtaWx5LlwiLFxuICAgICAgICAgICAgXCJEcnVnIC8gYWxjb2hvbCBhYnVzZXIuIE9mdGVuIGltcGFpcmVkIGJ5IHRoZWlyIHZpY2UuXCIsXG4gICAgICAgICAgICBcIkV4dGVuc2l2ZSBlZHVjYXRpb24gb24gZXZlcnkgc2Nob2xhcmx5IHN1YmplY3QuXCIsXG4gICAgICAgICAgICBcIkhhcyBjaHJvbmljIGlsbG5lc3MgdGhhdCByZXF1aXJlcyBmcmVxdWVudCBjYXJlLlwiLFxuICAgICAgICAgICAgXCJIb2xkcyB0aGVpciBwb3NpdGlvbiBkdWUgdG8gYmxhY2ttYWlsLlwiLFxuICAgICAgICAgICAgXCJIb2xkcyB0aGVpciBwb3NpdGlvbiB0byBzcHkgZm9yIGFub3RoZXIgZmFjdGlvbi5cIixcbiAgICAgICAgICAgIFwiSW4gcHJpc29uIG9yIHVuZGVyIG5vYmxlJ3MgaG91c2UgYXJyZXN0LlwiLFxuICAgICAgICAgICAgXCJJbmhlcml0ZWQgdGhlaXIgcG9zaXRpb24uIE1heSBub3QgZGVzZXJ2ZSAvIHdhbnQgaXQuXCIsXG4gICAgICAgICAgICBcIkludGVuc2UsIHVucmVhc29uYWJsZSBwaG9iaWEgb3IgbG9hdGhpbmcuXCIsXG4gICAgICAgICAgICBcIkludm9sdmVkIHdpdGggd2FyIGNyaW1lcyBmcm9tIHRoZSBVbml0eSBXYXIuXCIsXG4gICAgICAgICAgICBcIklzIGJsaW5kbHkgZmFpdGhmdWwgdG8gYW4gaWRlYWwsIGdyb3VwLCBvciB0cmFkaXRpb24uXCIsXG4gICAgICAgICAgICBcIktlZXBzIGRldGFpbGVkIGpvdXJuYWxzLCBub3RlcywgcmVjb3JkcywgbGVkZ2Vycy5cIixcbiAgICAgICAgICAgIFwiTGVhZHMgYSBkb3VibGUgbGlmZSB1c2luZyBjb3ZlciBpZGVudGl0eS5cIixcbiAgICAgICAgICAgIFwiTWFycmllZCBpbnRvIGltcG9ydGFudCAvIHBvd2VyZnVsIGZhbWlseS5cIixcbiAgICAgICAgICAgIFwiTWFzc2l2ZSBkZWJ0cyAodG8gYmFua3MgLyBjcmltaW5hbHMgLyBmYW1pbHkpXCIsXG4gICAgICAgICAgICBcIk9uY2UgaG9sbG93ZWQsIHRoZW4gcmVzdG9yZWQuIEltbXVuZSB0byBzcGlyaXRzLlwiLFxuICAgICAgICAgICAgXCJQcm91ZCBvZiBoZXJpdGFnZSwgdHJhZGl0aW9ucywgbmF0aXZlIGxhbmd1YWdlLlwiLFxuICAgICAgICAgICAgXCJSZWNsdXNpdmUuIFByZWZlcnMgdG8gaW50ZXJhY3QgdmlhIG1lc3NlbmdlcnMuXCIsXG4gICAgICAgICAgICBcIlJlbGllcyBvbiBjb3VuY2lsIHRvIG1ha2UgZGVjaXNpb25zLlwiLFxuICAgICAgICAgICAgXCJSZXZvbHV0aW9uYXJ5LiBQbG90cyBhZ2FpbnN0IHRoZSBJbXBlcml1bS5cIixcbiAgICAgICAgICAgIFwiU2NhbmRhbG91cyByZXB1dGF0aW9uIChkZXNlcnZlZCBvciBub3QpLlwiLFxuICAgICAgICAgICAgXCJTZWNyZXRseSAob3Blbmx5PykgY29udHJvbGxlZCBieSBwb3NzZXNzaW5nIHNwaXJpdC5cIixcbiAgICAgICAgICAgIFwiU2VydmVzIGEgZGVtb24ncyBhZ2VuZGEgKGtub3dpbmdseSBvciBub3QpLlwiLFxuICAgICAgICAgICAgXCJTcG90bGVzcyByZXB1dGF0aW9uLiBIaWdobHkgcmVnYXJkZWQuXCIsXG4gICAgICAgICAgICBcIlN1cGVyc3RpdGlvdXMuIEJlbGlldmVzIGluIHNpZ25zLCBtYWdpYyBudW1iZXJzLlwiLFxuICAgICAgICAgICAgXCJTdXJyb3VuZGVkIGJ5IHN5Y29waGFudHMsIHN1cHBsaWNhbnRzLCB0b2FkaWVzLlwiLFxuICAgICAgICAgICAgXCJWaXNpb25hcnkuIEhvbGRzIHJhZGljYWwgdmlld3MgZm9yIGZ1dHVyZS5cIixcbiAgICAgICAgICAgIFwiV2VsbC10cmF2ZWxlZC4gQ29ubmVjdGlvbnMgb3V0c2lkZSBEb3Nrdm9sLlwiXG4gICAgICAgIF0sXG4gICAgICAgIHN0eWxlOiB7XG4gICAgICAgICAgICBtYWxlOiBbXG4gICAgICAgICAgICAgICAgXCJBcHJvblwiLFxuICAgICAgICAgICAgICAgIFwiQ2FuZVwiLFxuICAgICAgICAgICAgICAgIFwiQ29sbGFyZWQgU2hpcnRcIixcbiAgICAgICAgICAgICAgICBcIkNydXRjaGVzXCIsXG4gICAgICAgICAgICAgICAgXCJFZWxza2luIEJvZHlzdWl0XCIsXG4gICAgICAgICAgICAgICAgXCJGYWNlIE1hc2tcIixcbiAgICAgICAgICAgICAgICBcIkZpdHRlZCBMZWdnaW5nc1wiLFxuICAgICAgICAgICAgICAgIFwiSGVhdnkgQ2xvYWtcIixcbiAgICAgICAgICAgICAgICBcIkhlYXZ5IEdsb3Zlc1wiLFxuICAgICAgICAgICAgICAgIFwiSGlkZSAmIEZ1cnNcIixcbiAgICAgICAgICAgICAgICBcIkhvb2QgJiBWZWlsXCIsXG4gICAgICAgICAgICAgICAgXCJIb29kZWQgQ29hdFwiLFxuICAgICAgICAgICAgICAgIFwiS25pdCBDYXBcIixcbiAgICAgICAgICAgICAgICBcIkxlYXRoZXJzXCIsXG4gICAgICAgICAgICAgICAgXCJMb25nIENvYXRcIixcbiAgICAgICAgICAgICAgICBcIkxvbmcgU2NhcmZcIixcbiAgICAgICAgICAgICAgICBcIkxvb3NlIFNpbGtzXCIsXG4gICAgICAgICAgICAgICAgXCJNYXNrICYgUm9iZXNcIixcbiAgICAgICAgICAgICAgICBcIlJvdWdoIFR1bmljXCIsXG4gICAgICAgICAgICAgICAgXCJTaGFycCBUcm91c2Vyc1wiLFxuICAgICAgICAgICAgICAgIFwiU2hvcnQgQ2xvYWtcIixcbiAgICAgICAgICAgICAgICBcIlNsaW0gSmFja2V0XCIsXG4gICAgICAgICAgICAgICAgXCJTb2Z0IEJvb3RzXCIsXG4gICAgICAgICAgICAgICAgXCJTdWl0ICYgVmVzdFwiLFxuICAgICAgICAgICAgICAgIFwiU3VzcGVuZGVyc1wiLFxuICAgICAgICAgICAgICAgIFwiVGFsbCBCb290c1wiLFxuICAgICAgICAgICAgICAgIFwiVGF0dGVyc1wiLFxuICAgICAgICAgICAgICAgIFwiVGhpY2sgR3JlYXRjb2F0XCIsXG4gICAgICAgICAgICAgICAgXCJUb29sIEJlbHRcIixcbiAgICAgICAgICAgICAgICBcIlRyaWNvcm4gSGF0XCIsXG4gICAgICAgICAgICAgICAgXCJVbmlmb3JtXCIsXG4gICAgICAgICAgICAgICAgXCJXYXhlZCBDb2F0XCIsXG4gICAgICAgICAgICAgICAgXCJXaGVlbGNoYWlyXCIsXG4gICAgICAgICAgICAgICAgXCJXaWRlIEJlbHRcIixcbiAgICAgICAgICAgICAgICBcIldvcmsgQm9vdHNcIlxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIGZlbWFsZTogW1xuICAgICAgICAgICAgICAgIFwiQXByb25cIixcbiAgICAgICAgICAgICAgICBcIkNhbmVcIixcbiAgICAgICAgICAgICAgICBcIkNydXRjaGVzXCIsXG4gICAgICAgICAgICAgICAgXCJFZWxza2luIEJvZHlzdWl0XCIsXG4gICAgICAgICAgICAgICAgXCJGYWNlIE1hc2tcIixcbiAgICAgICAgICAgICAgICBcIkZpdHRlZCBEcmVzc1wiLFxuICAgICAgICAgICAgICAgIFwiRml0dGVkIExlZ2dpbmdzXCIsXG4gICAgICAgICAgICAgICAgXCJIZWF2eSBDbG9ha1wiLFxuICAgICAgICAgICAgICAgIFwiSGVhdnkgR2xvdmVzXCIsXG4gICAgICAgICAgICAgICAgXCJIaWRlICYgRnVyc1wiLFxuICAgICAgICAgICAgICAgIFwiSG9vZCAmIFZlaWxcIixcbiAgICAgICAgICAgICAgICBcIkhvb2RlZCBDb2F0XCIsXG4gICAgICAgICAgICAgICAgXCJLbml0IENhcFwiLFxuICAgICAgICAgICAgICAgIFwiTGVhdGhlcnNcIixcbiAgICAgICAgICAgICAgICBcIkxvbmcgQ29hdFwiLFxuICAgICAgICAgICAgICAgIFwiTG9uZyBTY2FyZlwiLFxuICAgICAgICAgICAgICAgIFwiTG9vc2UgU2lsa3NcIixcbiAgICAgICAgICAgICAgICBcIk1hc2sgJiBSb2Jlc1wiLFxuICAgICAgICAgICAgICAgIFwiUm91Z2ggVHVuaWNcIixcbiAgICAgICAgICAgICAgICBcIlNoYXJwIFRyb3VzZXJzXCIsXG4gICAgICAgICAgICAgICAgXCJTaG9ydCBDbG9ha1wiLFxuICAgICAgICAgICAgICAgIFwiU2tpcnQgJiBCbG91c2VcIixcbiAgICAgICAgICAgICAgICBcIlNsaW0gSmFja2V0XCIsXG4gICAgICAgICAgICAgICAgXCJTb2Z0IEJvb3RzXCIsXG4gICAgICAgICAgICAgICAgXCJTdXNwZW5kZXJzXCIsXG4gICAgICAgICAgICAgICAgXCJUYWxsIEJvb3RzXCIsXG4gICAgICAgICAgICAgICAgXCJUYXR0ZXJzXCIsXG4gICAgICAgICAgICAgICAgXCJUaGljayBHcmVhdGNvYXRcIixcbiAgICAgICAgICAgICAgICBcIlRvb2wgQmVsdFwiLFxuICAgICAgICAgICAgICAgIFwiVW5pZm9ybVwiLFxuICAgICAgICAgICAgICAgIFwiV2F4ZWQgQ29hdFwiLFxuICAgICAgICAgICAgICAgIFwiV2hlZWxjaGFpclwiLFxuICAgICAgICAgICAgICAgIFwiV2lkZSBCZWx0XCIsXG4gICAgICAgICAgICAgICAgXCJXb3JrIEJvb3RzXCJcbiAgICAgICAgICAgIF1cbiAgICAgICAgfSxcbiAgICAgICAgbmFtZV90aXRsZTogW1xuICAgICAgICAgICAgXCJBZGVwdFwiLFxuICAgICAgICAgICAgXCJBcmNoaXZpc3RcIixcbiAgICAgICAgICAgIFwiQ2FwdGFpblwiLFxuICAgICAgICAgICAgXCJDaGFydGVyXCIsXG4gICAgICAgICAgICBcIlNjcml2ZW5lclwiXG4gICAgICAgIF0sXG4gICAgICAgIG5hbWVfZmlyc3Q6IHtcbiAgICAgICAgICAgIG1hbGU6IFtcbiAgICAgICAgICAgICAgICBcIkFiZWxcIixcbiAgICAgICAgICAgICAgICBcIkFiZW50aHlcIixcbiAgICAgICAgICAgICAgICBcIkFkcmljXCIsXG4gICAgICAgICAgICAgICAgXCJBaXJpY1wiLFxuICAgICAgICAgICAgICAgIFwiQWxhYmFzdGVyXCIsXG4gICAgICAgICAgICAgICAgXCJBbGFzdGFpclwiLFxuICAgICAgICAgICAgICAgIFwiQWxkb1wiLFxuICAgICAgICAgICAgICAgIFwiQWxlblwiLFxuICAgICAgICAgICAgICAgIFwiQWxlcGhcIixcbiAgICAgICAgICAgICAgICBcIkFtYnJvc2VcIixcbiAgICAgICAgICAgICAgICBcIkFtb3NlblwiLFxuICAgICAgICAgICAgICAgIFwiQW5kYWxcIixcbiAgICAgICAgICAgICAgICBcIkFuZHJlbFwiLFxuICAgICAgICAgICAgICAgIFwiQW50b25cIixcbiAgICAgICAgICAgICAgICBcIkFxdWlsbGFcIixcbiAgICAgICAgICAgICAgICBcIkFyYWRhblwiLFxuICAgICAgICAgICAgICAgIFwiQXJhbVwiLFxuICAgICAgICAgICAgICAgIFwiQXJjaGliYWxkXCIsXG4gICAgICAgICAgICAgICAgXCJBcmNoaWVcIixcbiAgICAgICAgICAgICAgICBcIkFyZGVuXCIsXG4gICAgICAgICAgICAgICAgXCJBcmxpZGVuXCIsXG4gICAgICAgICAgICAgICAgXCJBcmx5blwiLFxuICAgICAgICAgICAgICAgIFwiQXJtYW5kXCIsXG4gICAgICAgICAgICAgICAgXCJBcnF1b1wiLFxuICAgICAgICAgICAgICAgIFwiQXJyZWxsXCIsXG4gICAgICAgICAgICAgICAgXCJBcnZ1c1wiLFxuICAgICAgICAgICAgICAgIFwiQXNoZXJcIixcbiAgICAgICAgICAgICAgICBcIkF1cmVsaW9cIixcbiAgICAgICAgICAgICAgICBcIkJlbmVkaWN0XCIsXG4gICAgICAgICAgICAgICAgXCJCb2xzdGVyXCIsXG4gICAgICAgICAgICAgICAgXCJCcmFjZVwiLFxuICAgICAgICAgICAgICAgIFwiQnJhblwiLFxuICAgICAgICAgICAgICAgIFwiQnJhbmNlXCIsXG4gICAgICAgICAgICAgICAgXCJCcmFub25cIixcbiAgICAgICAgICAgICAgICBcIkJyaWNrc1wiLFxuICAgICAgICAgICAgICAgIFwiQnJvY2tcIixcbiAgICAgICAgICAgICAgICBcIkJydXR1c1wiLFxuICAgICAgICAgICAgICAgIFwiQ2FpdXNcIixcbiAgICAgICAgICAgICAgICBcIkNhcnJvXCIsXG4gICAgICAgICAgICAgICAgXCJDYXNpYW5cIixcbiAgICAgICAgICAgICAgICBcIkNhdG9cIixcbiAgICAgICAgICAgICAgICBcIkNhdmVsbGVcIixcbiAgICAgICAgICAgICAgICBcIkNlZHJpY1wiLFxuICAgICAgICAgICAgICAgIFwiQ2hhbmNlXCIsXG4gICAgICAgICAgICAgICAgXCJDaGF1bmNleVwiLFxuICAgICAgICAgICAgICAgIFwiQ2lkXCIsXG4gICAgICAgICAgICAgICAgXCJDbGF2ZVwiLFxuICAgICAgICAgICAgICAgIFwiQ2xpZmZcIixcbiAgICAgICAgICAgICAgICBcIkNvcm5lbGl1c1wiLFxuICAgICAgICAgICAgICAgIFwiQ3Jvc3NcIixcbiAgICAgICAgICAgICAgICBcIkNyb3dsXCIsXG4gICAgICAgICAgICAgICAgXCJDeW1cIixcbiAgICAgICAgICAgICAgICBcIkN5cnVzXCIsXG4gICAgICAgICAgICAgICAgXCJEZWNsYW5cIixcbiAgICAgICAgICAgICAgICBcIkRlbFwiLFxuICAgICAgICAgICAgICAgIFwiRHJhdlwiLFxuICAgICAgICAgICAgICAgIFwiRHJhemhhblwiLFxuICAgICAgICAgICAgICAgIFwiRHJlbVwiLFxuICAgICAgICAgICAgICAgIFwiRWRsdW5cIixcbiAgICAgICAgICAgICAgICBcIkVkbXVuZFwiLFxuICAgICAgICAgICAgICAgIFwiRWRyb21cIixcbiAgICAgICAgICAgICAgICBcIkVkd2luXCIsXG4gICAgICAgICAgICAgICAgXCJFbGFuXCIsXG4gICAgICAgICAgICAgICAgXCJFbGVuZFwiLFxuICAgICAgICAgICAgICAgIFwiRWxpYXNcIixcbiAgICAgICAgICAgICAgICBcIkVsb2RpblwiLFxuICAgICAgICAgICAgICAgIFwiRXBocmltXCIsXG4gICAgICAgICAgICAgICAgXCJFcmFzbXVzXCIsXG4gICAgICAgICAgICAgICAgXCJFcmVtb25cIixcbiAgICAgICAgICAgICAgICBcIkV0aGFuXCIsXG4gICAgICAgICAgICAgICAgXCJFdmVyaXR0XCIsXG4gICAgICAgICAgICAgICAgXCJGZWxkc3BhclwiLFxuICAgICAgICAgICAgICAgIFwiRmVyb1wiLFxuICAgICAgICAgICAgICAgIFwiRmlublwiLFxuICAgICAgICAgICAgICAgIFwiRmlzaGVyXCIsXG4gICAgICAgICAgICAgICAgXCJHYWxlblwiLFxuICAgICAgICAgICAgICAgIFwiR2FsbGFoYWRcIixcbiAgICAgICAgICAgICAgICBcIkdhcm5lclwiLFxuICAgICAgICAgICAgICAgIFwiR2lsYmVydFwiLFxuICAgICAgICAgICAgICAgIFwiR2xpbnRcIixcbiAgICAgICAgICAgICAgICBcIkduaWtcIixcbiAgICAgICAgICAgICAgICBcIkdyZWdhbG9zXCIsXG4gICAgICAgICAgICAgICAgXCJHcmV5XCIsXG4gICAgICAgICAgICAgICAgXCJHcmV5c29uXCIsXG4gICAgICAgICAgICAgICAgXCJHcmlmdGVyXCIsXG4gICAgICAgICAgICAgICAgXCJHcmluZVwiLFxuICAgICAgICAgICAgICAgIFwiR3Jpc3RvZmVyXCIsXG4gICAgICAgICAgICAgICAgXCJIYWRyaWFuXCIsXG4gICAgICAgICAgICAgICAgXCJIYWdyYW5cIixcbiAgICAgICAgICAgICAgICBcIkhhbW1vbmRcIixcbiAgICAgICAgICAgICAgICBcIkhpeFwiLFxuICAgICAgICAgICAgICAgIFwiSG9sdHpcIixcbiAgICAgICAgICAgICAgICBcIkh1Z29cIixcbiAgICAgICAgICAgICAgICBcIklkZW5cIixcbiAgICAgICAgICAgICAgICBcIklydG9uXCIsXG4gICAgICAgICAgICAgICAgXCJJc2FhY1wiLFxuICAgICAgICAgICAgICAgIFwiSXZlbGxpb3NcIixcbiAgICAgICAgICAgICAgICBcIkphYmFyaVwiLFxuICAgICAgICAgICAgICAgIFwiSmVyaWNob1wiLFxuICAgICAgICAgICAgICAgIFwiSmVyb2RcIixcbiAgICAgICAgICAgICAgICBcIkthemltaXJcIixcbiAgICAgICAgICAgICAgICBcIktlbGxhblwiLFxuICAgICAgICAgICAgICAgIFwiS2VsdnluXCIsXG4gICAgICAgICAgICAgICAgXCJLZWx5clwiLFxuICAgICAgICAgICAgICAgIFwiS2hhZnJhXCIsXG4gICAgICAgICAgICAgICAgXCJLb2JiXCIsXG4gICAgICAgICAgICAgICAgXCJLcmlzdG92XCIsXG4gICAgICAgICAgICAgICAgXCJLeXJpbHVcIixcbiAgICAgICAgICAgICAgICBcIkxhZWxcIixcbiAgICAgICAgICAgICAgICBcIkxhZmF5ZXR0ZVwiLFxuICAgICAgICAgICAgICAgIFwiTGF1ZGl1c1wiLFxuICAgICAgICAgICAgICAgIFwiTGF3cmVuY2VcIixcbiAgICAgICAgICAgICAgICBcIkxlaWZcIixcbiAgICAgICAgICAgICAgICBcIkxlbVwiLFxuICAgICAgICAgICAgICAgIFwiTGVubnlcIixcbiAgICAgICAgICAgICAgICBcIkxvZ2FuXCIsXG4gICAgICAgICAgICAgICAgXCJMdWNhc1wiLFxuICAgICAgICAgICAgICAgIFwiTHVjaXVzXCIsXG4gICAgICAgICAgICAgICAgXCJMeXNhbmRlclwiLFxuICAgICAgICAgICAgICAgIFwiTWlsb3NcIixcbiAgICAgICAgICAgICAgICBcIk1vcmRcIixcbiAgICAgICAgICAgICAgICBcIk1vcmtldGhcIixcbiAgICAgICAgICAgICAgICBcIk1vcmxhblwiLFxuICAgICAgICAgICAgICAgIFwiTXlyZVwiLFxuICAgICAgICAgICAgICAgIFwiTmFyY3VzXCIsXG4gICAgICAgICAgICAgICAgXCJOZWhpXCIsXG4gICAgICAgICAgICAgICAgXCJOb2dnc1wiLFxuICAgICAgICAgICAgICAgIFwiTm9ydG9uXCIsXG4gICAgICAgICAgICAgICAgXCJPYmVsXCIsXG4gICAgICAgICAgICAgICAgXCJPYmVsYXNcIixcbiAgICAgICAgICAgICAgICBcIk9jdGF2aXVzXCIsXG4gICAgICAgICAgICAgICAgXCJPZGVsYXlcIixcbiAgICAgICAgICAgICAgICBcIk9yZW1cIixcbiAgICAgICAgICAgICAgICBcIk9ybGFuXCIsXG4gICAgICAgICAgICAgICAgXCJPcnRoXCIsXG4gICAgICAgICAgICAgICAgXCJPcnRvblwiLFxuICAgICAgICAgICAgICAgIFwiUGF2ZWxcIixcbiAgICAgICAgICAgICAgICBcIlBlcmNldmFsXCIsXG4gICAgICAgICAgICAgICAgXCJQZXJjaXZhbFwiLFxuICAgICAgICAgICAgICAgIFwiUGVyZWdyaW5lXCIsXG4gICAgICAgICAgICAgICAgXCJQaGluXCIsXG4gICAgICAgICAgICAgICAgXCJQaGluZWFzXCIsXG4gICAgICAgICAgICAgICAgXCJQb3J0b1wiLFxuICAgICAgICAgICAgICAgIFwiUHJlc3RvblwiLFxuICAgICAgICAgICAgICAgIFwiUHJpbW9cIixcbiAgICAgICAgICAgICAgICBcIlF1ZXNzXCIsXG4gICAgICAgICAgICAgICAgXCJRdWlsbFwiLFxuICAgICAgICAgICAgICAgIFwiUmFmZVwiLFxuICAgICAgICAgICAgICAgIFwiUmFzbXVzXCIsXG4gICAgICAgICAgICAgICAgXCJSYXVsXCIsXG4gICAgICAgICAgICAgICAgXCJSZXNoXCIsXG4gICAgICAgICAgICAgICAgXCJSaWFzXCIsXG4gICAgICAgICAgICAgICAgXCJSaW5nXCIsXG4gICAgICAgICAgICAgICAgXCJSaXZhbGxvXCIsXG4gICAgICAgICAgICAgICAgXCJSb2RtdW5kXCIsXG4gICAgICAgICAgICAgICAgXCJSb2V0aGVcIixcbiAgICAgICAgICAgICAgICBcIlJvb3NlXCIsXG4gICAgICAgICAgICAgICAgXCJSb3JpY1wiLFxuICAgICAgICAgICAgICAgIFwiU2V0aGxhXCIsXG4gICAgICAgICAgICAgICAgXCJTaWxhc1wiLFxuICAgICAgICAgICAgICAgIFwiU2luZHJpXCIsXG4gICAgICAgICAgICAgICAgXCJTbml0Y2hcIixcbiAgICAgICAgICAgICAgICBcIlNvbFwiLFxuICAgICAgICAgICAgICAgIFwiU29sb21vblwiLFxuICAgICAgICAgICAgICAgIFwiU3ByaWdcIixcbiAgICAgICAgICAgICAgICBcIlN0YXZydWxcIixcbiAgICAgICAgICAgICAgICBcIlN0ZWxsYW5cIixcbiAgICAgICAgICAgICAgICBcIlN0ZXZcIixcbiAgICAgICAgICAgICAgICBcIlN5bVwiLFxuICAgICAgICAgICAgICAgIFwiVGFjaXR1c1wiLFxuICAgICAgICAgICAgICAgIFwiVGFyblwiLFxuICAgICAgICAgICAgICAgIFwiVGF5bG9yXCIsXG4gICAgICAgICAgICAgICAgXCJUaGFja2VyYXlcIixcbiAgICAgICAgICAgICAgICBcIlRoYWRkZXVzXCIsXG4gICAgICAgICAgICAgICAgXCJUaGFuZVwiLFxuICAgICAgICAgICAgICAgIFwiVGhlbGlhblwiLFxuICAgICAgICAgICAgICAgIFwiVGhlb1wiLFxuICAgICAgICAgICAgICAgIFwiVGhlcm9uXCIsXG4gICAgICAgICAgICAgICAgXCJUaHVyc3RvblwiLFxuICAgICAgICAgICAgICAgIFwiVGltb3RoXCIsXG4gICAgICAgICAgICAgICAgXCJUaXNrXCIsXG4gICAgICAgICAgICAgICAgXCJUb2NrZXJcIixcbiAgICAgICAgICAgICAgICBcIlRyaXN0ZXJvXCIsXG4gICAgICAgICAgICAgICAgXCJVbHJpY1wiLFxuICAgICAgICAgICAgICAgIFwiVmFza1wiLFxuICAgICAgICAgICAgICAgIFwiVmVsZXJpc1wiLFxuICAgICAgICAgICAgICAgIFwiVmVudGFyb1wiLFxuICAgICAgICAgICAgICAgIFwiVmlyZ2lsXCIsXG4gICAgICAgICAgICAgICAgXCJWb25kXCIsXG4gICAgICAgICAgICAgICAgXCJXYXhcIixcbiAgICAgICAgICAgICAgICBcIldheW5lXCIsXG4gICAgICAgICAgICAgICAgXCJXZWF2ZXJcIixcbiAgICAgICAgICAgICAgICBcIldlc3RlclwiLFxuICAgICAgICAgICAgICAgIFwiV2luc2xleVwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgZmVtYWxlOiBbXG4gICAgICAgICAgICAgICAgXCJBZGFpcmVcIixcbiAgICAgICAgICAgICAgICBcIkFkZWxhaWRlXCIsXG4gICAgICAgICAgICAgICAgXCJBZGVsbGFcIixcbiAgICAgICAgICAgICAgICBcIkFkcm9pdFwiLFxuICAgICAgICAgICAgICAgIFwiQWlsZW5cIixcbiAgICAgICAgICAgICAgICBcIkFpbmFcIixcbiAgICAgICAgICAgICAgICBcIkFraWxhaFwiLFxuICAgICAgICAgICAgICAgIFwiQWxiaW5pYVwiLFxuICAgICAgICAgICAgICAgIFwiQWx0aGFlYVwiLFxuICAgICAgICAgICAgICAgIFwiQWx5b3NoYVwiLFxuICAgICAgICAgICAgICAgIFwiQW5zYVwiLFxuICAgICAgICAgICAgICAgIFwiQXJhYmVsbGFcIixcbiAgICAgICAgICAgICAgICBcIkFyd3lsXCIsXG4gICAgICAgICAgICAgICAgXCJBc2hseW5cIixcbiAgICAgICAgICAgICAgICBcIkF2b3JhXCIsXG4gICAgICAgICAgICAgICAgXCJCcmVuYVwiLFxuICAgICAgICAgICAgICAgIFwiQnJlbm5hXCIsXG4gICAgICAgICAgICAgICAgXCJDYWxpZW50aGVcIixcbiAgICAgICAgICAgICAgICBcIkNhbWlsbGFcIixcbiAgICAgICAgICAgICAgICBcIkNhbmRvclwiLFxuICAgICAgICAgICAgICAgIFwiQ2FuZHJhXCIsXG4gICAgICAgICAgICAgICAgXCJDYXJpc3NhXCIsXG4gICAgICAgICAgICAgICAgXCJDYXNjYWJlbFwiLFxuICAgICAgICAgICAgICAgIFwiQ2Fzc2x5blwiLFxuICAgICAgICAgICAgICAgIFwiQ2FzdGlsbGVcIixcbiAgICAgICAgICAgICAgICBcIkNlbGVzdGVcIixcbiAgICAgICAgICAgICAgICBcIkNoZW5cIixcbiAgICAgICAgICAgICAgICBcIkNsYXJldFwiLFxuICAgICAgICAgICAgICAgIFwiQ2xlbWVudGluZVwiLFxuICAgICAgICAgICAgICAgIFwiQ29uc3RhbmNlXCIsXG4gICAgICAgICAgICAgICAgXCJDb3JkZWxpYVwiLFxuICAgICAgICAgICAgICAgIFwiQ29yaWxsZVwiLFxuICAgICAgICAgICAgICAgIFwiQ29yc2ljYVwiLFxuICAgICAgICAgICAgICAgIFwiQ3lyZW5lXCIsXG4gICAgICAgICAgICAgICAgXCJEYWhsaWFcIixcbiAgICAgICAgICAgICAgICBcIkRhcGhuaWFcIixcbiAgICAgICAgICAgICAgICBcIkRlbGlhXCIsXG4gICAgICAgICAgICAgICAgXCJEZW5hXCIsXG4gICAgICAgICAgICAgICAgXCJEZW5uYVwiLFxuICAgICAgICAgICAgICAgIFwiRGVzbW9uYVwiLFxuICAgICAgICAgICAgICAgIFwiRG9sb3Jlc1wiLFxuICAgICAgICAgICAgICAgIFwiRHJlbm5hXCIsXG4gICAgICAgICAgICAgICAgXCJFZGllXCIsXG4gICAgICAgICAgICAgICAgXCJFaXJhXCIsXG4gICAgICAgICAgICAgICAgXCJFbHNpZVwiLFxuICAgICAgICAgICAgICAgIFwiRW1lbGluZVwiLFxuICAgICAgICAgICAgICAgIFwiRXR0YVwiLFxuICAgICAgICAgICAgICAgIFwiRmVsYVwiLFxuICAgICAgICAgICAgICAgIFwiRmVsaWNpdHlcIixcbiAgICAgICAgICAgICAgICBcIkdhbGVuaWNhXCIsXG4gICAgICAgICAgICAgICAgXCJHYWxpbmFcIixcbiAgICAgICAgICAgICAgICBcIkdpdHRhXCIsXG4gICAgICAgICAgICAgICAgXCJHbG9yaWFcIixcbiAgICAgICAgICAgICAgICBcIkd3ZW5cIixcbiAgICAgICAgICAgICAgICBcIkhlZHlcIixcbiAgICAgICAgICAgICAgICBcIkhlbGxhXCIsXG4gICAgICAgICAgICAgICAgXCJIZWxsZXNcIixcbiAgICAgICAgICAgICAgICBcIkhlbnJpZXR0YVwiLFxuICAgICAgICAgICAgICAgIFwiSWR1bmFcIixcbiAgICAgICAgICAgICAgICBcIklvbmFcIixcbiAgICAgICAgICAgICAgICBcIklzYVwiLFxuICAgICAgICAgICAgICAgIFwiSXNhYmVsbGFcIixcbiAgICAgICAgICAgICAgICBcIklza3JhXCIsXG4gICAgICAgICAgICAgICAgXCJJc29sZGVcIixcbiAgICAgICAgICAgICAgICBcIkphc25hXCIsXG4gICAgICAgICAgICAgICAgXCJKYXhpXCIsXG4gICAgICAgICAgICAgICAgXCJKb2FuXCIsXG4gICAgICAgICAgICAgICAgXCJKdW5vXCIsXG4gICAgICAgICAgICAgICAgXCJLYW1lbGluXCIsXG4gICAgICAgICAgICAgICAgXCJLYXJpXCIsXG4gICAgICAgICAgICAgICAgXCJLb2xpXCIsXG4gICAgICAgICAgICAgICAgXCJMYXVyaWFcIixcbiAgICAgICAgICAgICAgICBcIkxlbmlhXCIsXG4gICAgICAgICAgICAgICAgXCJMZW9uYVwiLFxuICAgICAgICAgICAgICAgIFwiTGV5dmFcIixcbiAgICAgICAgICAgICAgICBcIkxpZXVcIixcbiAgICAgICAgICAgICAgICBcIkxpbGl0aFwiLFxuICAgICAgICAgICAgICAgIFwiTGluXCIsXG4gICAgICAgICAgICAgICAgXCJMaXpldGVcIixcbiAgICAgICAgICAgICAgICBcIkxvcmV0dGVcIixcbiAgICAgICAgICAgICAgICBcIkx1Y2VsbGFcIixcbiAgICAgICAgICAgICAgICBcIkx5bnRoaWFcIixcbiAgICAgICAgICAgICAgICBcIkx5cmFcIixcbiAgICAgICAgICAgICAgICBcIk1haWFcIixcbiAgICAgICAgICAgICAgICBcIk1haWF0aGFoXCIsXG4gICAgICAgICAgICAgICAgXCJNYWllXCIsXG4gICAgICAgICAgICAgICAgXCJNYXJhXCIsXG4gICAgICAgICAgICAgICAgXCJNYXJhc2lcIixcbiAgICAgICAgICAgICAgICBcIk1hcmllbGRhXCIsXG4gICAgICAgICAgICAgICAgXCJNYXJpc29sXCIsXG4gICAgICAgICAgICAgICAgXCJNYXJyaXNcIixcbiAgICAgICAgICAgICAgICBcIk1pcmFcIixcbiAgICAgICAgICAgICAgICBcIk5hcmlhXCIsXG4gICAgICAgICAgICAgICAgXCJOYXNoYVwiLFxuICAgICAgICAgICAgICAgIFwiT2N0YXZpYVwiLFxuICAgICAgICAgICAgICAgIFwiT2RyaWVubmVcIixcbiAgICAgICAgICAgICAgICBcIk9saXZpYVwiLFxuICAgICAgICAgICAgICAgIFwiT3JhXCIsXG4gICAgICAgICAgICAgICAgXCJPcmRlbm5hXCIsXG4gICAgICAgICAgICAgICAgXCJPcmVzc2lhXCIsXG4gICAgICAgICAgICAgICAgXCJPcnNlbGxhXCIsXG4gICAgICAgICAgICAgICAgXCJQYXJkZW5uYVwiLFxuICAgICAgICAgICAgICAgIFwiUGVuZWxvcGVcIixcbiAgICAgICAgICAgICAgICBcIlBlbm55XCIsXG4gICAgICAgICAgICAgICAgXCJQaG9lYmVcIixcbiAgICAgICAgICAgICAgICBcIlBvbG9uaWFcIixcbiAgICAgICAgICAgICAgICBcIlByYXZkYVwiLFxuICAgICAgICAgICAgICAgIFwiUHJ1ZGVuY2VcIixcbiAgICAgICAgICAgICAgICBcIlF1ZWxlbm5hXCIsXG4gICAgICAgICAgICAgICAgXCJSYWlzYVwiLFxuICAgICAgICAgICAgICAgIFwiUmVkamlcIixcbiAgICAgICAgICAgICAgICBcIlJlbWlyYVwiLFxuICAgICAgICAgICAgICAgIFwiUmV5XCIsXG4gICAgICAgICAgICAgICAgXCJSaXZlblwiLFxuICAgICAgICAgICAgICAgIFwiUnVuYVwiLFxuICAgICAgICAgICAgICAgIFwiU2FiaW5hXCIsXG4gICAgICAgICAgICAgICAgXCJTYWJpbmlhXCIsXG4gICAgICAgICAgICAgICAgXCJTYWJyaW5hXCIsXG4gICAgICAgICAgICAgICAgXCJTYWRlaFwiLFxuICAgICAgICAgICAgICAgIFwiU2FoYXJcIixcbiAgICAgICAgICAgICAgICBcIlNlbG1hXCIsXG4gICAgICAgICAgICAgICAgXCJTZXNlcmV0aFwiLFxuICAgICAgICAgICAgICAgIFwiU2V2ZXJlYVwiLFxuICAgICAgICAgICAgICAgIFwiU2lsYXF1aVwiLFxuICAgICAgICAgICAgICAgIFwiU2thbm5vblwiLFxuICAgICAgICAgICAgICAgIFwiU3ByaWdcIixcbiAgICAgICAgICAgICAgICBcIlN0YWJpdGhhXCIsXG4gICAgICAgICAgICAgICAgXCJTeXJhXCIsXG4gICAgICAgICAgICAgICAgXCJUYWJpdGhhXCIsXG4gICAgICAgICAgICAgICAgXCJUYWxpdGhhXCIsXG4gICAgICAgICAgICAgICAgXCJUYW1zeW5cIixcbiAgICAgICAgICAgICAgICBcIlRhc2lcIixcbiAgICAgICAgICAgICAgICBcIlRlcnJhXCIsXG4gICAgICAgICAgICAgICAgXCJUZXNzbHluXCIsXG4gICAgICAgICAgICAgICAgXCJUaGF2YVwiLFxuICAgICAgICAgICAgICAgIFwiVGhlbmFcIixcbiAgICAgICAgICAgICAgICBcIlRpZmZcIixcbiAgICAgICAgICAgICAgICBcIlVuYVwiLFxuICAgICAgICAgICAgICAgIFwiVmF1cmluXCIsXG4gICAgICAgICAgICAgICAgXCJWZXJldHRhXCIsXG4gICAgICAgICAgICAgICAgXCJWZXNuYVwiLFxuICAgICAgICAgICAgICAgIFwiVmVzdGluZVwiLFxuICAgICAgICAgICAgICAgIFwiVmV5XCIsXG4gICAgICAgICAgICAgICAgXCJWaWN0b3JpYVwiLFxuICAgICAgICAgICAgICAgIFwiVmluXCIsXG4gICAgICAgICAgICAgICAgXCJWaXRhXCIsXG4gICAgICAgICAgICAgICAgXCJWb2xldHRlXCIsXG4gICAgICAgICAgICAgICAgXCJWb3JrYVwiLFxuICAgICAgICAgICAgICAgIFwiV2FuZGVyXCIsXG4gICAgICAgICAgICAgICAgXCJZbHZhXCIsXG4gICAgICAgICAgICAgICAgXCJaYWhyYVwiLFxuICAgICAgICAgICAgICAgIFwiWmFpZGFcIixcbiAgICAgICAgICAgICAgICBcIlphbWlyYVwiLFxuICAgICAgICAgICAgICAgIFwiWmFyeWFcIlxuICAgICAgICAgICAgXVxuICAgICAgICB9LFxuICAgICAgICBuYW1lX3N1cm5hbWU6IFtcbiAgICAgICAgICAgIFwiQWJiZXJ3aWNrXCIsXG4gICAgICAgICAgICBcIkFkZWxidXJ5XCIsXG4gICAgICAgICAgICBcIkFkbGV0b25cIixcbiAgICAgICAgICAgIFwiQWxvcm9cIixcbiAgICAgICAgICAgIFwiQWxzYVwiLFxuICAgICAgICAgICAgXCJBbmtoYXlhdFwiLFxuICAgICAgICAgICAgXCJBcnJhblwiLFxuICAgICAgICAgICAgXCJBc2h0b25cIixcbiAgICAgICAgICAgIFwiQXNod2VhdGhlclwiLFxuICAgICAgICAgICAgXCJBdGhhbm9jaFwiLFxuICAgICAgICAgICAgXCJBeGVscm9kXCIsXG4gICAgICAgICAgICBcIkJhY2t3b3J0aFwiLFxuICAgICAgICAgICAgXCJCYXJyb3dcIixcbiAgICAgICAgICAgIFwiQmFzcmFuXCIsXG4gICAgICAgICAgICBcIkJsYWNrXCIsXG4gICAgICAgICAgICBcIkJsYWNrZm9yZFwiLFxuICAgICAgICAgICAgXCJCbGFja3Bvb2xcIixcbiAgICAgICAgICAgIFwiQmxhY2t0aG9ybmVcIixcbiAgICAgICAgICAgIFwiQmx1ZmZcIixcbiAgICAgICAgICAgIFwiQm9kZW5cIixcbiAgICAgICAgICAgIFwiQm9va2VyXCIsXG4gICAgICAgICAgICBcIkJvdWxkZXJcIixcbiAgICAgICAgICAgIFwiQm93bWFuXCIsXG4gICAgICAgICAgICBcIkJyYWVzaWRlXCIsXG4gICAgICAgICAgICBcIkJyYW1ibGVcIixcbiAgICAgICAgICAgIFwiQnJhdW1cIixcbiAgICAgICAgICAgIFwiQnJheVwiLFxuICAgICAgICAgICAgXCJCcmVha2lyb25cIixcbiAgICAgICAgICAgIFwiQnJpc3RsZVwiLFxuICAgICAgICAgICAgXCJCcm9ja2VuXCIsXG4gICAgICAgICAgICBcIkJyb2dhblwiLFxuICAgICAgICAgICAgXCJCcm9tbGV5XCIsXG4gICAgICAgICAgICBcIkJ1cm5zaWRlc1wiLFxuICAgICAgICAgICAgXCJDYWVicmVrXCIsXG4gICAgICAgICAgICBcIkNhcnR3cmlnaHRcIixcbiAgICAgICAgICAgIFwiQ2FydmVyXCIsXG4gICAgICAgICAgICBcIkNoaWxkZXJtYXNzXCIsXG4gICAgICAgICAgICBcIkNsYXdcIixcbiAgICAgICAgICAgIFwiQ2xlbGxhbmRcIixcbiAgICAgICAgICAgIFwiQ2xlbW9udFwiLFxuICAgICAgICAgICAgXCJDbGVybW9udFwiLFxuICAgICAgICAgICAgXCJDb2JibGVjYXJ2ZXJcIixcbiAgICAgICAgICAgIFwiQ29sZWJ1cm5cIixcbiAgICAgICAgICAgIFwiQ29tYmVcIixcbiAgICAgICAgICAgIFwiQ29tYmVyXCIsXG4gICAgICAgICAgICBcIkNyb2Z0eVwiLFxuICAgICAgICAgICAgXCJDdW5uaW5naGFtXCIsXG4gICAgICAgICAgICBcIkRhYXZhXCIsXG4gICAgICAgICAgICBcIkRhbFwiLFxuICAgICAgICAgICAgXCJEYWxtb3JlXCIsXG4gICAgICAgICAgICBcIkRhbmZpZWxkXCIsXG4gICAgICAgICAgICBcIkRyYXdsaWdodFwiLFxuICAgICAgICAgICAgXCJEcmlnZ1wiLFxuICAgICAgICAgICAgXCJEdW52aWxcIixcbiAgICAgICAgICAgIFwiRWxtb3JlXCIsXG4gICAgICAgICAgICBcIkV2ZW5pbmdleWVzXCIsXG4gICAgICAgICAgICBcIkV2ZW5zdGVwc1wiLFxuICAgICAgICAgICAgXCJFdmVudGlkZVwiLFxuICAgICAgICAgICAgXCJFdmVycGVubnlcIixcbiAgICAgICAgICAgIFwiRmFpcnBsYXlcIixcbiAgICAgICAgICAgIFwiRmFycm9zXCIsXG4gICAgICAgICAgICBcIkZlbGx3YXRlclwiLFxuICAgICAgICAgICAgXCJGb2dnXCIsXG4gICAgICAgICAgICBcIkdhdGNvbWJlXCIsXG4gICAgICAgICAgICBcIkdsYXNzZXllXCIsXG4gICAgICAgICAgICBcIkdvbGRzd29ydGhcIixcbiAgICAgICAgICAgIFwiR3JhdmVcIixcbiAgICAgICAgICAgIFwiR3JheXRod2FpdGVcIixcbiAgICAgICAgICAgIFwiR3JleXN0ZWVsXCIsXG4gICAgICAgICAgICBcIkdyaW5lXCIsXG4gICAgICAgICAgICBcIkhhaWdcIixcbiAgICAgICAgICAgIFwiSGFsZi1PZmZcIixcbiAgICAgICAgICAgIFwiSGF2ZWx0b25cIixcbiAgICAgICAgICAgIFwiSGF2ZW5ob3JzdFwiLFxuICAgICAgICAgICAgXCJIZWN0YXJlc1wiLFxuICAgICAgICAgICAgXCJIZWxrZXJcIixcbiAgICAgICAgICAgIFwiSGVsbGVzXCIsXG4gICAgICAgICAgICBcIkhlbGx5ZXJzXCIsXG4gICAgICAgICAgICBcIkhlbW1lXCIsXG4gICAgICAgICAgICBcIkhpZ2h0b3dlclwiLFxuICAgICAgICAgICAgXCJIaWdodG93blwiLFxuICAgICAgICAgICAgXCJIaWdod2F0ZXJcIixcbiAgICAgICAgICAgIFwiSGlsbFwiLFxuICAgICAgICAgICAgXCJIaXRjaGNvY2tcIixcbiAgICAgICAgICAgIFwiSW5uZXJ3aWNrXCIsXG4gICAgICAgICAgICBcIkpheWFuXCIsXG4gICAgICAgICAgICBcIkplZHVpblwiLFxuICAgICAgICAgICAgXCJLYXJkZXJhXCIsXG4gICAgICAgICAgICBcIkthcnN0YXNcIixcbiAgICAgICAgICAgIFwiS2VlbFwiLFxuICAgICAgICAgICAgXCJLZW1wdFwiLFxuICAgICAgICAgICAgXCJLZXNzYXJpblwiLFxuICAgICAgICAgICAgXCJLaW5jbGFpdGhcIixcbiAgICAgICAgICAgIFwiS2luZ1wiLFxuICAgICAgICAgICAgXCJMYWtlXCIsXG4gICAgICAgICAgICBcIkxhcnJpc3RvblwiLFxuICAgICAgICAgICAgXCJMZWFrZVwiLFxuICAgICAgICAgICAgXCJMb21vbmRcIixcbiAgICAgICAgICAgIFwiTG9uZ3N0YWZmXCIsXG4gICAgICAgICAgICBcIkxvcmV3b29kXCIsXG4gICAgICAgICAgICBcIk1hcm9kZW5cIixcbiAgICAgICAgICAgIFwiTWF5c29uXCIsXG4gICAgICAgICAgICBcIk1lcnJpd2VhdGhlclwiLFxuICAgICAgICAgICAgXCJNaWNodGVyXCIsXG4gICAgICAgICAgICBcIk1pbmR3ZWxsXCIsXG4gICAgICAgICAgICBcIk1vcmNvbWJlXCIsXG4gICAgICAgICAgICBcIk1vcnJpc3RvblwiLFxuICAgICAgICAgICAgXCJNb3J0aW1lclwiLFxuICAgICAgICAgICAgXCJOZXRoZXJ0b25cIixcbiAgICAgICAgICAgIFwiTmlnaHRcIixcbiAgICAgICAgICAgIFwiTmlnaHRleXJlXCIsXG4gICAgICAgICAgICBcIk5pZ2h0bHlcIixcbiAgICAgICAgICAgIFwiTm9jdG9mdFwiLFxuICAgICAgICAgICAgXCJOb3RoZXJob21lXCIsXG4gICAgICAgICAgICBcIk9yY2hhcmRcIixcbiAgICAgICAgICAgIFwiT3JjaGlkXCIsXG4gICAgICAgICAgICBcIlBhdGhcIixcbiAgICAgICAgICAgIFwiUGVha1wiLFxuICAgICAgICAgICAgXCJQZWdnXCIsXG4gICAgICAgICAgICBcIlBlbmRlcnluXCIsXG4gICAgICAgICAgICBcIlBvbmRcIixcbiAgICAgICAgICAgIFwiUG9vbFwiLFxuICAgICAgICAgICAgXCJQcmljaGFyZFwiLFxuICAgICAgICAgICAgXCJSYWluZXNcIixcbiAgICAgICAgICAgIFwiUmF2ZW5nbGFzc1wiLFxuICAgICAgICAgICAgXCJSYXZlbndvb2RcIixcbiAgICAgICAgICAgIFwiUmVpZ25zXCIsXG4gICAgICAgICAgICBcIlJleWVzXCIsXG4gICAgICAgICAgICBcIlJleW5lc1wiLFxuICAgICAgICAgICAgXCJSaG9kZXNcIixcbiAgICAgICAgICAgIFwiUml2ZXJmb3JkXCIsXG4gICAgICAgICAgICBcIlJvYmVsXCIsXG4gICAgICAgICAgICBcIlJvd2FuXCIsXG4gICAgICAgICAgICBcIlNhYmxlXCIsXG4gICAgICAgICAgICBcIlNhZ2VcIixcbiAgICAgICAgICAgIFwiU2Fsa2FyYVwiLFxuICAgICAgICAgICAgXCJTYWxvc1wiLFxuICAgICAgICAgICAgXCJTZXZveVwiLFxuICAgICAgICAgICAgXCJTaGlsYm90dGxlXCIsXG4gICAgICAgICAgICBcIlNoaWxsbW9vclwiLFxuICAgICAgICAgICAgXCJTaG9va1wiLFxuICAgICAgICAgICAgXCJTa2Vsa2FsbGFuXCIsXG4gICAgICAgICAgICBcIlNrb3JhXCIsXG4gICAgICAgICAgICBcIlNsYW5lXCIsXG4gICAgICAgICAgICBcIlNvbmdcIixcbiAgICAgICAgICAgIFwiU3RlYWR5c3RlcFwiLFxuICAgICAgICAgICAgXCJTdG91dGFsZVwiLFxuICAgICAgICAgICAgXCJTdG92ZXN0b2tlclwiLFxuICAgICAgICAgICAgXCJTdHJhbmdlXCIsXG4gICAgICAgICAgICBcIlN0cmFuZ2ZvcmRcIixcbiAgICAgICAgICAgIFwiU3RyYXRobWlsbFwiLFxuICAgICAgICAgICAgXCJTdW5kZXJcIixcbiAgICAgICAgICAgIFwiU3VuZGVybGFuZFwiLFxuICAgICAgICAgICAgXCJTd2lmdHdoaXN0bGVcIixcbiAgICAgICAgICAgIFwiVGFpbG9yXCIsXG4gICAgICAgICAgICBcIlRhbGxmZWxsb3dcIixcbiAgICAgICAgICAgIFwiVGVtcGxldG9uXCIsXG4gICAgICAgICAgICBcIlRlbnBlbm55XCIsXG4gICAgICAgICAgICBcIlRldmlsdG9uXCIsXG4gICAgICAgICAgICBcIlRoaXN0bGVcIixcbiAgICAgICAgICAgIFwiVGhyeXN1c1wiLFxuICAgICAgICAgICAgXCJUaHVyc3RvblwiLFxuICAgICAgICAgICAgXCJUaW5tb3V0aFwiLFxuICAgICAgICAgICAgXCJUb3dlclwiLFxuICAgICAgICAgICAgXCJUcmlzdMOpXCIsXG4gICAgICAgICAgICBcIlR5cmNvbm5lbGxcIixcbiAgICAgICAgICAgIFwiVmFsZVwiLFxuICAgICAgICAgICAgXCJWYWxlbnRpbmVcIixcbiAgICAgICAgICAgIFwiVmVsZGFpcmVcIixcbiAgICAgICAgICAgIFwiVmVudHVyZVwiLFxuICAgICAgICAgICAgXCJXYWx1bmRcIixcbiAgICAgICAgICAgIFwiV2FycmVuXCIsXG4gICAgICAgICAgICBcIldhdGVyc1wiLFxuICAgICAgICAgICAgXCJXZWNrZXJcIixcbiAgICAgICAgICAgIFwiV2Vsa2VyXCIsXG4gICAgICAgICAgICBcIldlbmRcIixcbiAgICAgICAgICAgIFwiV2hhcnZlclwiLFxuICAgICAgICAgICAgXCJXaHl0aGVcIixcbiAgICAgICAgICAgIFwiV29vZGFsbFwiXG4gICAgICAgIF0sXG4gICAgICAgIG5hbWVfYWxpYXM6IFtcbiAgICAgICAgICAgIFwiQmVsbFwiLFxuICAgICAgICAgICAgXCJCaXJjaFwiLFxuICAgICAgICAgICAgXCJCaXJkXCIsXG4gICAgICAgICAgICBcIkJsaXNzXCIsXG4gICAgICAgICAgICBcIkJyaWNrc1wiLFxuICAgICAgICAgICAgXCJCdWdcIixcbiAgICAgICAgICAgIFwiQ2hpbWVcIixcbiAgICAgICAgICAgIFwiQ29pbFwiLFxuICAgICAgICAgICAgXCJDcmlja2V0XCIsXG4gICAgICAgICAgICBcIkNyb3NzXCIsXG4gICAgICAgICAgICBcIkNyb3dcIixcbiAgICAgICAgICAgIFwiRWNob1wiLFxuICAgICAgICAgICAgXCJGbGludFwiLFxuICAgICAgICAgICAgXCJGcm9nXCIsXG4gICAgICAgICAgICBcIkZyb3N0XCIsXG4gICAgICAgICAgICBcIkdvb2RzXCIsXG4gICAgICAgICAgICBcIkdyaXBcIixcbiAgICAgICAgICAgIFwiR3VubmVyXCIsXG4gICAgICAgICAgICBcIkhhbW1lclwiLFxuICAgICAgICAgICAgXCJIb29rXCIsXG4gICAgICAgICAgICBcIklua1wiLFxuICAgICAgICAgICAgXCJKdW5rZXJcIixcbiAgICAgICAgICAgIFwiTWlzdFwiLFxuICAgICAgICAgICAgXCJNb29uXCIsXG4gICAgICAgICAgICBcIk5haWxcIixcbiAgICAgICAgICAgIFwiTmVlZGxlXCIsXG4gICAgICAgICAgICBcIk9ncmVcIixcbiAgICAgICAgICAgIFwiUG9vbFwiLFxuICAgICAgICAgICAgXCJSaW5nXCIsXG4gICAgICAgICAgICBcIlJ1YnlcIixcbiAgICAgICAgICAgIFwiU2lsdmVyXCIsXG4gICAgICAgICAgICBcIlNraW5uZXJcIixcbiAgICAgICAgICAgIFwiU29uZ1wiLFxuICAgICAgICAgICAgXCJTcHVyXCIsXG4gICAgICAgICAgICBcIlRhY2tsZVwiLFxuICAgICAgICAgICAgXCJUaGlzdGxlXCIsXG4gICAgICAgICAgICBcIlRob3JuXCIsXG4gICAgICAgICAgICBcIlRpY2tcIixcbiAgICAgICAgICAgIFwiVGljay1Ub2NrXCIsXG4gICAgICAgICAgICBcIlRvY2tcIixcbiAgICAgICAgICAgIFwiVHJpY2tcIixcbiAgICAgICAgICAgIFwiVHdlbHZlc1wiLFxuICAgICAgICAgICAgXCJWaXhlblwiLFxuICAgICAgICAgICAgXCJXaGlwXCIsXG4gICAgICAgICAgICBcIldpY2tlclwiXG4gICAgICAgIF0sXG4gICAgICAgIG5hbWVfc3VmZml4OiBbXG4gICAgICAgICAgICBcIkpyLlwiLFxuICAgICAgICAgICAgXCJTci5cIixcbiAgICAgICAgICAgIFwiSUlJXCIsXG4gICAgICAgICAgICBcIklWXCJcbiAgICAgICAgXVxuICAgIH0sXG4gICAgR006IHtcbiAgICAgICAgQmFyZ2FpbnM6IFtcbiAgICAgICAgICAgIHsgbmFtZTogXCJJbmZlY3RlZCBXb3VuZFwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGUgbmV4dCB0aW1lIHlvdSBSZWNvdmVyIGZyb20gSGFybSwgeW91ciBQaHlzaWNrZXIgaXMgYXQgLTFkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSW5mZWN0ZWQgV291bmRcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhlIG5leHQgdGltZSB5b3UgUmVjb3ZlciBmcm9tIEhhcm0sIHlvdXIgUGh5c2lja2VyIGlzIGF0IC0xZC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkluZmVjdGVkIFdvdW5kXCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSBuZXh0IHRpbWUgeW91IFJlY292ZXIgZnJvbSBIYXJtLCB5b3VyIFBoeXNpY2tlciBpcyBhdCAtMWQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJJdCdzIE1pbmUgTm93XCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBkaXNjb3ZlciBhIHNtYWxsIGl0ZW0gdGhhdCBiZWxvbmdzIHRvIGEgcml2YWwuIFdoYXQgaXMgaXQ/IFdobyB1c2VkIHRvIG93biBpdD8gSG93IGRvZXMgdGhpcyBjaGFuZ2UgdGhpbmdzIGZvciB5b3U/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJJdCdzIE1pbmUgTm93XCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBkaXNjb3ZlciBhIHNtYWxsIGl0ZW0gdGhhdCBiZWxvbmdzIHRvIGEgcml2YWwuIFdoYXQgaXMgaXQ/IFdobyB1c2VkIHRvIG93biBpdD8gSG93IGRvZXMgdGhpcyBjaGFuZ2UgdGhpbmdzIGZvciB5b3U/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJJdCdzIE1pbmUgTm93XCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBkaXNjb3ZlciBhIHNtYWxsIGl0ZW0gdGhhdCBiZWxvbmdzIHRvIGEgcml2YWwuIFdoYXQgaXMgaXQ/IFdobyB1c2VkIHRvIG93biBpdD8gSG93IGRvZXMgdGhpcyBjaGFuZ2UgdGhpbmdzIGZvciB5b3U/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IEJsb29kXCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBkaXNjb3ZlciBldmlkZW5jZSBvZiB0aGUgZGVhdGggb2YgYSBmYW1pbHkgbWVtYmVyIGR1cmluZyB0aGUgU2NvcmUuIFdobyBpcyBpdD8gSG93IGRpZCB0aGV5IGRpZT8gSG93IGRvZXMgdGhpcyBjaGFuZ2UgdGhpbmdzIGZvciB5b3VyIGNoYXJhY3Rlcj9cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIk1pbmUgQnkgQmxvb2RcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGRpc2NvdmVyIGV2aWRlbmNlIG9mIHRoZSBkZWF0aCBvZiBhIGZhbWlseSBtZW1iZXIgZHVyaW5nIHRoZSBTY29yZS4gV2hvIGlzIGl0PyBIb3cgZGlkIHRoZXkgZGllPyBIb3cgZG9lcyB0aGlzIGNoYW5nZSB0aGluZ3MgZm9yIHlvdXIgY2hhcmFjdGVyP1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTWluZSBCeSBCbG9vZFwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgZGlzY292ZXIgZXZpZGVuY2Ugb2YgdGhlIGRlYXRoIG9mIGEgZmFtaWx5IG1lbWJlciBkdXJpbmcgdGhlIFNjb3JlLiBXaG8gaXMgaXQ/IEhvdyBkaWQgdGhleSBkaWU/IEhvdyBkb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IE5hbWVcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGRpc2NvdmVyIGFuIGVudmVsb3BlIGFkZHJlc3NlZCB0byB5b3UgZHVyaW5nIHRoZSBTY29yZS4gV2hhdCBpcyBpbiBpdD8gV2hvIGxlZnQgaXQgaGVyZSBmb3IgeW91IHRvIGZpbmQ/IEhvdyBkb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IE5hbWVcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGRpc2NvdmVyIGFuIGVudmVsb3BlIGFkZHJlc3NlZCB0byB5b3UgZHVyaW5nIHRoZSBTY29yZS4gV2hhdCBpcyBpbiBpdD8gV2hvIGxlZnQgaXQgaGVyZSBmb3IgeW91IHRvIGZpbmQ/IEhvdyBkb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IE5hbWVcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGRpc2NvdmVyIGFuIGVudmVsb3BlIGFkZHJlc3NlZCB0byB5b3UgZHVyaW5nIHRoZSBTY29yZS4gV2hhdCBpcyBpbiBpdD8gV2hvIGxlZnQgaXQgaGVyZSBmb3IgeW91IHRvIGZpbmQ/IEhvdyBkb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IFJpZ2h0c1wiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgZGlzY292ZXIgYSBzbWFsbCBpdGVtIGZyb20geW91ciBwYXN0IGR1cmluZyB0aGUgU2NvcmUuIFdoYXQgaXMgaXQ/IFdoYXQgZG9lcyBpdCBtZWFuIHRoYXQgaXQncyBoZXJlPyBEb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IFJpZ2h0c1wiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgZGlzY292ZXIgYSBzbWFsbCBpdGVtIGZyb20geW91ciBwYXN0IGR1cmluZyB0aGUgU2NvcmUuIFdoYXQgaXMgaXQ/IFdoYXQgZG9lcyBpdCBtZWFuIHRoYXQgaXQncyBoZXJlPyBEb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaW5lIEJ5IFJpZ2h0c1wiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgZGlzY292ZXIgYSBzbWFsbCBpdGVtIGZyb20geW91ciBwYXN0IGR1cmluZyB0aGUgU2NvcmUuIFdoYXQgaXMgaXQ/IFdoYXQgZG9lcyBpdCBtZWFuIHRoYXQgaXQncyBoZXJlPyBEb2VzIHRoaXMgY2hhbmdlIHRoaW5ncyBmb3IgeW91ciBjaGFyYWN0ZXI/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJOb3QgUGF5aW5nIEF0dGVudGlvblwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJVbmNoZWNrIG9uZSBvZiB0aGUgWFAgdHJpZ2dlcnMgYWxyZWFkeSBtYXJrZWQgZm9yIHlvdXIgY2hhcmFjdGVyIGZvciB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTm90IFBheWluZyBBdHRlbnRpb25cIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVW5jaGVjayBvbmUgb2YgdGhlIFhQIHRyaWdnZXJzIGFscmVhZHkgbWFya2VkIGZvciB5b3VyIGNoYXJhY3RlciBmb3IgdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlNoYWRvdyBGcm9tIHRoZSBQYXN0XCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdXIgaW50ZWwgbWlzc2VkIHRoYXQgc29tZW9uZSBmcm9tIHlvdXIgcGFzdCBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHRhcmdldCBvZiB0aGUgU2NvcmUuIFdobyBpcyBpdCwgYW5kIGhvdyBkb2VzIHRoYXQgY2hhbmdlIHRoaW5ncyBmb3IgeW91P1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiU2hhZG93IEZyb20gdGhlIFBhc3RcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91ciBpbnRlbCBtaXNzZWQgdGhhdCBzb21lb25lIGZyb20geW91ciBwYXN0IGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdGFyZ2V0IG9mIHRoZSBTY29yZS4gV2hvIGlzIGl0LCBhbmQgaG93IGRvZXMgdGhhdCBjaGFuZ2UgdGhpbmdzIGZvciB5b3U/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJTaGFkb3cgRnJvbSB0aGUgUGFzdFwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3VyIGludGVsIG1pc3NlZCB0aGF0IHNvbWVvbmUgZnJvbSB5b3VyIHBhc3QgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB0YXJnZXQgb2YgdGhlIFNjb3JlLiBXaG8gaXMgaXQsIGFuZCBob3cgZG9lcyB0aGF0IGNoYW5nZSB0aGluZ3MgZm9yIHlvdT9cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlRoaWNrZXIgdGhhbiBCbG9vZFwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3VyIGludGVsIG1pc3NlZCB0aGF0IG9uZSBvZiB5b3VyIGZhbWlseSBtZW1iZXJzIGlzIGFzc29jaWF0ZWQgd2l0aCB0aGUgdGFyZ2V0IG9mIHRoZSBTY29yZS4gSG93IGRvZXMgdGhhdCBjaGFuZ2UgdGhpbmdzIGZvciB5b3U/XCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaGlja2VyIHRoYW4gQmxvb2RcIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91ciBpbnRlbCBtaXNzZWQgdGhhdCBvbmUgb2YgeW91ciBmYW1pbHkgbWVtYmVycyBpcyBhc3NvY2lhdGVkIHdpdGggdGhlIHRhcmdldCBvZiB0aGUgU2NvcmUuIEhvdyBkb2VzIHRoYXQgY2hhbmdlIHRoaW5ncyBmb3IgeW91P1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVGhpY2tlciB0aGFuIEJsb29kXCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdXIgaW50ZWwgbWlzc2VkIHRoYXQgb25lIG9mIHlvdXIgZmFtaWx5IG1lbWJlcnMgaXMgYXNzb2NpYXRlZCB3aXRoIHRoZSB0YXJnZXQgb2YgdGhlIFNjb3JlLiBIb3cgZG9lcyB0aGF0IGNoYW5nZSB0aGluZ3MgZm9yIHlvdT9cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIldoeSdkIEl0IEhhdmUgVG8gQmUuLi5cIiwgY2F0ZWdvcnk6IFwiQ2hhcmFjdGVyIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhlIHJvb20geW91J3JlIGluIHRyaWdnZXJzIGEgcGhvYmlhIHRoYXQgdGhlIENyZXcgZGlkbid0IGtub3cgYWJvdXQgYmVmb3JlLiBEZXNjcmliZSB0aGUgcGhvYmlhIGFuZCB0YWtlIDIgU3RyZXNzLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiV2h5J2QgSXQgSGF2ZSBUbyBCZS4uLlwiLCBjYXRlZ29yeTogXCJDaGFyYWN0ZXIgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGUgcm9vbSB5b3UncmUgaW4gdHJpZ2dlcnMgYSBwaG9iaWEgdGhhdCB0aGUgQ3JldyBkaWRuJ3Qga25vdyBhYm91dCBiZWZvcmUuIERlc2NyaWJlIHRoZSBwaG9iaWEgYW5kIHRha2UgMiBTdHJlc3MuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXaHknZCBJdCBIYXZlIFRvIEJlLi4uXCIsIGNhdGVnb3J5OiBcIkNoYXJhY3RlciBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSByb29tIHlvdSdyZSBpbiB0cmlnZ2VycyBhIHBob2JpYSB0aGF0IHRoZSBDcmV3IGRpZG4ndCBrbm93IGFib3V0IGJlZm9yZS4gRGVzY3JpYmUgdGhlIHBob2JpYSBhbmQgdGFrZSAyIFN0cmVzcy5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkRlbW9uaWMgR3Vlc3RcIiwgY2F0ZWdvcnk6IFwiQ3JldyBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZGVtb25pYyBwcmVzZW5jZSBoYXMgYXBwZWFyZWQgaW4geW91ciBMYWlyIGFuZCB3aWxsIG5lZWQgdG8gYmUgZGVhbHQgd2l0aCBkdXJpbmcgRnJlZSBQbGF5LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiRGVtb25pYyBHdWVzdFwiLCBjYXRlZ29yeTogXCJDcmV3IEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBkZW1vbmljIHByZXNlbmNlIGhhcyBhcHBlYXJlZCBpbiB5b3VyIExhaXIgYW5kIHdpbGwgbmVlZCB0byBiZSBkZWFsdCB3aXRoIGR1cmluZyBGcmVlIFBsYXkuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJGcmFjdHVyaW5nIEZhY3Rpb25cIiwgY2F0ZWdvcnk6IFwiQ3JldyBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdXIgSG9sZCBpcyBTdHJvbmcsIHJlZHVjZSBpdCB0byBXZWFrLiBJZiB5b3VyIEhvbGQgaXMgV2VhaywgcmVkdWNlIHlvdXIgUmVwIHRvIHplcm8uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJMZXNzb24gTm90IExlYXJuZWRcIiwgY2F0ZWdvcnk6IFwiQ3JldyBFZmZlY3RcIiwgZWZmZWN0OiBcIlVuY2hlY2sgb25lIG9mIHRoZSBYUCB0cmlnZ2VycyBhbHJlYWR5IG1hcmtlZCBmb3IgeW91ciBjcmV3IGZvciB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTGVzc29uIE5vdCBMZWFybmVkXCIsIGNhdGVnb3J5OiBcIkNyZXcgRWZmZWN0XCIsIGVmZmVjdDogXCJVbmNoZWNrIG9uZSBvZiB0aGUgWFAgdHJpZ2dlcnMgYWxyZWFkeSBtYXJrZWQgZm9yIHlvdXIgY3JldyBmb3IgdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIk90aGVyd29ybGRseSBHdWVzdFwiLCBjYXRlZ29yeTogXCJDcmV3IEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBzY2lvbiBvZiBvbmUgb2YgdGhlIE9sZCBHb2RzIGhhcyBhcHBlYXJlZCBpbiB5b3VyIExhaXIgYW5kIHdpbGwgbmVlZCB0byBiZSBkZWFsdCB3aXRoIGR1cmluZyBGcmVlIFBsYXkuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJPdGhlcndvcmxkbHkgR3Vlc3RcIiwgY2F0ZWdvcnk6IFwiQ3JldyBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgc2Npb24gb2Ygb25lIG9mIHRoZSBPbGQgR29kcyBoYXMgYXBwZWFyZWQgaW4geW91ciBMYWlyIGFuZCB3aWxsIG5lZWQgdG8gYmUgZGVhbHQgd2l0aCBkdXJpbmcgRnJlZSBQbGF5LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUmViZWxsaW91cyBGYWN0aW9uXCIsIGNhdGVnb3J5OiBcIkNyZXcgRWZmZWN0XCIsIGVmZmVjdDogXCJBIG5ldyBjcmV3IGhhcyB0YWtlbiBwb3NzZXNzaW9uIG9mIG9uZSBvZiB5b3VyIENsYWltcywgYW5kIHdpbGwgaGF2ZSB0byBiZSBkZWFsdCB3aXRoIGluIEZyZWUgUGxheS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlNwZWN0cmFsIEd1ZXN0XCIsIGNhdGVnb3J5OiBcIkNyZXcgRWZmZWN0XCIsIGVmZmVjdDogXCJBIGdob3N0bHkgcHJlc2VuY2UgaGFzIGFwcGVhcmVkIGluIHlvdXIgTGFpciBhbmQgd2lsbCBuZWVkIHRvIGJlIGRlYWx0IHdpdGggZHVyaW5nIEZyZWUgUGxheS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlNwZWN0cmFsIEd1ZXN0XCIsIGNhdGVnb3J5OiBcIkNyZXcgRWZmZWN0XCIsIGVmZmVjdDogXCJBIGdob3N0bHkgcHJlc2VuY2UgaGFzIGFwcGVhcmVkIGluIHlvdXIgTGFpciBhbmQgd2lsbCBuZWVkIHRvIGJlIGRlYWx0IHdpdGggZHVyaW5nIEZyZWUgUGxheS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlR1cm5jb2F0XCIsIGNhdGVnb3J5OiBcIkNyZXcgRWZmZWN0XCIsIGVmZmVjdDogXCJPbmUgb2YgeW91ciBDb2hvcnRzIGxlYXZlcyB5b3VyIGNyZXcgYW5kIGpvaW5zIGEgcml2YWwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEb3VibGUtQ3Jvc3NlZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoZSBub3JtYWwgRW50YW5nbGVtZW50IHJvbGwgYW5kIHJlc3VsdCwgeW91ciBDcmV3IHRha2VzIGFuIGFkZGl0aW9uYWwgRmxpcHBlZCByZXN1bHQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEb3VibGUtQ3Jvc3NlZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoZSBub3JtYWwgRW50YW5nbGVtZW50IHJvbGwgYW5kIHJlc3VsdCwgeW91ciBDcmV3IHRha2VzIGFuIGFkZGl0aW9uYWwgRmxpcHBlZCByZXN1bHQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEb3VibGUtQ3Jvc3NlZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoZSBub3JtYWwgRW50YW5nbGVtZW50IHJvbGwgYW5kIHJlc3VsdCwgeW91ciBDcmV3IHRha2VzIGFuIGFkZGl0aW9uYWwgRmxpcHBlZCByZXN1bHQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJFYXNpbHkgSWRlbnRpZmllZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsZWZ0IHNvbWV0aGluZyBiZWhpbmQgdGhhdCBpcyBlYXNpbHkgdHJhY2VkIHRvIHlvdS4gQ2hvb3NlIGVpdGhlciArMiBIZWF0IGFuZCDiiJIyIFJlcCwgb3IgKzEgSGVhdCBhbmQg4oiSMSBSZXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJFYXNpbHkgSWRlbnRpZmllZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsZWZ0IHNvbWV0aGluZyBiZWhpbmQgdGhhdCBpcyBlYXNpbHkgdHJhY2VkIHRvIHlvdS4gQ2hvb3NlIGVpdGhlciArMiBIZWF0IGFuZCDiiJIyIFJlcCwgb3IgKzEgSGVhdCBhbmQg4oiSMSBSZXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJFYXNpbHkgSWRlbnRpZmllZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsZWZ0IHNvbWV0aGluZyBiZWhpbmQgdGhhdCBpcyBlYXNpbHkgdHJhY2VkIHRvIHlvdS4gQ2hvb3NlIGVpdGhlciArMiBIZWF0IGFuZCDiiJIyIFJlcCwgb3IgKzEgSGVhdCBhbmQg4oiSMSBSZXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJIaWdoIFByb2ZpbGVcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGlzIFNjb3JlIGdhaW5zICsyIEhlYXQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJIaWdoIFByb2ZpbGVcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGlzIFNjb3JlIGdhaW5zICsyIEhlYXQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJIaWdoIFByb2ZpbGVcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGlzIFNjb3JlIGdhaW5zICsyIEhlYXQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNb3N0IFdhbnRlZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoZSBub3JtYWwgRW50YW5nbGVtZW50IHJvbGwgYW5kIHJlc3VsdCwgeW91IGFyZSB0aGUgdGFyZ2V0IG9mIGFuIGFkZGl0aW9uYWwgQXJyZXN0IHJlc3VsdC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIk1vc3QgV2FudGVkXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQWZ0ZXIgdGhlIG5vcm1hbCBFbnRhbmdsZW1lbnQgcm9sbCBhbmQgcmVzdWx0LCB5b3UgYXJlIHRoZSB0YXJnZXQgb2YgYW4gYWRkaXRpb25hbCBBcnJlc3QgcmVzdWx0LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUHJvamVjdCBTZXRiYWNrXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiTWFyayBvbmUgbGVzcyBDbG9jayBzZWdtZW50IHRoZSBmaXJzdCB0aW1lIHlvdSB3b3JrIG9uIGEgTG9uZy1UZXJtIFByb2plY3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJQcm9qZWN0IFNldGJhY2tcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJNYXJrIG9uZSBsZXNzIENsb2NrIHNlZ21lbnQgdGhlIGZpcnN0IHRpbWUgeW91IHdvcmsgb24gYSBMb25nLVRlcm0gUHJvamVjdC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlByb2plY3QgU2V0YmFja1wiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIk1hcmsgb25lIGxlc3MgQ2xvY2sgc2VnbWVudCB0aGUgZmlyc3QgdGltZSB5b3Ugd29yayBvbiBhIExvbmctVGVybSBQcm9qZWN0LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUXVlbGxlIEhvcnJldXIhXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IHN1ZmZlciBuaWdodG1hcmVzIGZvciBhIHdlZWsuIOKIkjFkIHRvIGFsbCBEb3dudGltZSBBY3Rpb25zIGFmdGVyIHRoaXMgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJRdWVsbGUgSG9ycmV1ciFcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3Ugc3VmZmVyIG5pZ2h0bWFyZXMgZm9yIGEgd2Vlay4g4oiSMWQgdG8gYWxsIERvd250aW1lIEFjdGlvbnMgYWZ0ZXIgdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlNob3J0Y2hhbmdlZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoaXMgU2NvcmUncyBwYXlvZmYgaXMg4oiSMiBDb2luLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiU2hvcnRjaGFuZ2VkXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhpcyBTY29yZSdzIHBheW9mZiBpcyDiiJIyIENvaW4uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJTaG9ydGNoYW5nZWRcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGlzIFNjb3JlJ3MgcGF5b2ZmIGlzIOKIkjIgQ29pbi5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlN1cHBseSBDaGFsbGVuZ2VzXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhlIG5leHQgdGltZSB5b3UgcGF5IENvaW4gZm9yIGFuIEFjcXVpcmUgQXNzZXQgcm9sbCwgeW91IG11c3QgcGF5IDMgaW5zdGVhZCBvZiAyIENvaW4gcGVyIFRpZXIuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJTdXBwbHkgQ2hhbGxlbmdlc1wiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSBuZXh0IHRpbWUgeW91IHBheSBDb2luIGZvciBhbiBBY3F1aXJlIEFzc2V0IHJvbGwsIHlvdSBtdXN0IHBheSAzIGluc3RlYWQgb2YgMiBDb2luIHBlciBUaWVyLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiU3VwcGx5IERlbGF5c1wiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlN1ZmZlciAtMWQgdG8geW91ciBuZXh0IEFjcXVpcmUgQXNzZXQgcm9sbC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlN1cHBseSBEZWxheXNcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJTdWZmZXIgLTFkIHRvIHlvdXIgbmV4dCBBY3F1aXJlIEFzc2V0IHJvbGwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJTdXBwbHkgRGVsYXlzXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiU3VmZmVyIC0xZCB0byB5b3VyIG5leHQgQWNxdWlyZSBBc3NldCByb2xsLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVGFzdGVzIExpa2UgQXNoZXNcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGUgbmV4dCB0aW1lIHlvdSBpbmR1bGdlIHlvdXIgVmljZSwgb25seSBjbGVhciBoYWxmIGFzIG11Y2ggU3RyZXNzIChyb3VuZGVkIGRvd24pIGFzIG5vcm1hbC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlRhc3RlcyBMaWtlIEFzaGVzXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhlIG5leHQgdGltZSB5b3UgaW5kdWxnZSB5b3VyIFZpY2UsIG9ubHkgY2xlYXIgaGFsZiBhcyBtdWNoIFN0cmVzcyAocm91bmRlZCBkb3duKSBhcyBub3JtYWwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaHJpY2UtTmFtZWRcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJBZnRlciB0aGUgbm9ybWFsIEVudGFuZ2xlbWVudCByb2xsIGFuZCByZXN1bHQsIHlvdXIgQ3JldyB0YWtlcyBhbiBhZGRpdGlvbmFsIERlbW9uaWMgTm90aWNlIHJlc3VsdC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlRocmljZS1OYW1lZFwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoZSBub3JtYWwgRW50YW5nbGVtZW50IHJvbGwgYW5kIHJlc3VsdCwgeW91ciBDcmV3IHRha2VzIGFuIGFkZGl0aW9uYWwgRGVtb25pYyBOb3RpY2UgcmVzdWx0LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVGhyaWNlLU5hbWVkXCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQWZ0ZXIgdGhlIG5vcm1hbCBFbnRhbmdsZW1lbnQgcm9sbCBhbmQgcmVzdWx0LCB5b3VyIENyZXcgdGFrZXMgYW4gYWRkaXRpb25hbCBEZW1vbmljIE5vdGljZSByZXN1bHQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXYXJkZW4ncyBBdHRlbnRpb25cIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCIrNCBIZWF0IChpbnN0ZWFkIG9mIHRoZSBub3JtYWwgKzIgSGVhdCkgaWYgdGhlcmUgaXMgYSBkZWF0aCBkdXJpbmcgdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIldhcmRlbidzIEF0dGVudGlvblwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIis0IEhlYXQgKGluc3RlYWQgb2YgdGhlIG5vcm1hbCArMiBIZWF0KSBpZiB0aGVyZSBpcyBhIGRlYXRoIGR1cmluZyB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiV2UgV2FudCBhIEJpZ2dlciBUYWtlIVwiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSBnYW5nIHdhbnRzIGEgYmlnZ2VyIHBpZWNlIG9mIHRoZSBhY3Rpb24uIOKIkjIgQ29pbiB0byBQYXlvZmYgZm9yIGVhY2ggQ29ob3J0IHVzZWQgaW4gdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIldlIFdhbnQgYSBCaWdnZXIgVGFrZSFcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGUgZ2FuZyB3YW50cyBhIGJpZ2dlciBwaWVjZSBvZiB0aGUgYWN0aW9uLiDiiJIyIENvaW4gdG8gUGF5b2ZmIGZvciBlYWNoIENvaG9ydCB1c2VkIGluIHRoaXMgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXZWVrZW5kIEdldGF3YXlcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgaW5kdWxnZSB5b3VyIFZpY2UgYWZ0ZXIgdGhpcyBTY29yZSwgeW91IGF1dG9tYXRpY2FsbHkgb3ZlcmluZHVsZ2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXZWVrZW5kIEdldGF3YXlcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgaW5kdWxnZSB5b3VyIFZpY2UgYWZ0ZXIgdGhpcyBTY29yZSwgeW91IGF1dG9tYXRpY2FsbHkgb3ZlcmluZHVsZ2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXZWVrZW5kIEdldGF3YXlcIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgaW5kdWxnZSB5b3VyIFZpY2UgYWZ0ZXIgdGhpcyBTY29yZSwgeW91IGF1dG9tYXRpY2FsbHkgb3ZlcmluZHVsZ2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXaGF0J3MgT3VyIFRha2U/XCIsIGNhdGVnb3J5OiBcIkRvd250aW1lIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhlIGdhbmcgd2FudHMgYSBiaWdnZXIgcGllY2Ugb2YgdGhlIGFjdGlvbi4g4oiSMSBDb2luIHRvIFBheW9mZiBmb3IgZWFjaCBDb2hvcnQgdXNlZCBpbiB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiV2hhdCdzIE91ciBUYWtlP1wiLCBjYXRlZ29yeTogXCJEb3dudGltZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSBnYW5nIHdhbnRzIGEgYmlnZ2VyIHBpZWNlIG9mIHRoZSBhY3Rpb24uIOKIkjEgQ29pbiB0byBQYXlvZmYgZm9yIGVhY2ggQ29ob3J0IHVzZWQgaW4gdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIldoYXQncyBPdXIgVGFrZT9cIiwgY2F0ZWdvcnk6IFwiRG93bnRpbWUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGUgZ2FuZyB3YW50cyBhIGJpZ2dlciBwaWVjZSBvZiB0aGUgYWN0aW9uLiDiiJIxIENvaW4gdG8gUGF5b2ZmIGZvciBlYWNoIENvaG9ydCB1c2VkIGluIHRoaXMgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBY2NlbGVyYXRpbmcgUGxhbnNcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJBIHJpdmFsIGZhY3Rpb24gYWR2YW5jZXMgb25lIG9mIGl0cyBDbG9ja3MgYnkgdHdvIGJlZm9yZSB5b3VyIG5leHQgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBY2NlbGVyYXRpbmcgUGxhbnNcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJBIHJpdmFsIGZhY3Rpb24gYWR2YW5jZXMgb25lIG9mIGl0cyBDbG9ja3MgYnkgdHdvIGJlZm9yZSB5b3VyIG5leHQgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBY2NlbGVyYXRpbmcgUGxhbnNcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJBIHJpdmFsIGZhY3Rpb24gYWR2YW5jZXMgb25lIG9mIGl0cyBDbG9ja3MgYnkgdHdvIGJlZm9yZSB5b3VyIG5leHQgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJFc2NhbGF0aW5nIFRlbnNpb25zXCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBmYWN0aW9uIG9mIHlvdXIgY2hvaWNlIHRoYXQgaXMgdW5mcmllbmRseSB0byB5b3VyIGNyZXcgbW92ZXMgb25lIHN0ZXAgdG93YXJkcyBXYXIuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJFc2NhbGF0aW5nIFRlbnNpb25zXCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBmYWN0aW9uIG9mIHlvdXIgY2hvaWNlIHRoYXQgaXMgdW5mcmllbmRseSB0byB5b3VyIGNyZXcgbW92ZXMgb25lIHN0ZXAgdG93YXJkcyBXYXIuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJGb3JnaXZlbmVzcyBvciBWZW5nZWFuY2U/XCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRHVyaW5nIHRoZSBTY29yZSwgb25lIG9mIHlvdXIgQ29ob3J0cyBnb3QgaW4gYSBmaWdodCB3aXRoIGFuIG5ldXRyYWwgQ29ob3J0LiBDaG9vc2Ug4oiSMiBSZXAgYW5kICsxIGZhY3Rpb24gcmVsYXRpb25zaGlwLCBvciArMiBSZXAgYW5kIOKIkjEgZmFjdGlvbiByZWxhdGlvbnNoaXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJGb3JnaXZlbmVzcyBvciBWZW5nZWFuY2U/XCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRHVyaW5nIHRoZSBTY29yZSwgb25lIG9mIHlvdXIgQ29ob3J0cyBnb3QgaW4gYSBmaWdodCB3aXRoIGFuIG5ldXRyYWwgQ29ob3J0LiBDaG9vc2Ug4oiSMiBSZXAgYW5kICsxIGZhY3Rpb24gcmVsYXRpb25zaGlwLCBvciArMiBSZXAgYW5kIOKIkjEgZmFjdGlvbiByZWxhdGlvbnNoaXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJGb3JnaXZlbmVzcyBvciBWZW5nZWFuY2U/XCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRHVyaW5nIHRoZSBTY29yZSwgb25lIG9mIHlvdXIgQ29ob3J0cyBnb3QgaW4gYSBmaWdodCB3aXRoIGFuIG5ldXRyYWwgQ29ob3J0LiBDaG9vc2Ug4oiSMiBSZXAgYW5kICsxIGZhY3Rpb24gcmVsYXRpb25zaGlwLCBvciArMiBSZXAgYW5kIOKIkjEgZmFjdGlvbiByZWxhdGlvbnNoaXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJIb3QtSGVhZGVkIENvaG9ydFwiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkR1cmluZyB0aGUgU2NvcmUsIG9uZSBvZiB5b3VyIENvaG9ydHMgcGlja2VkIGEgZmlnaHQgd2l0aCBhbiBhbGxpZWQgQ29ob3J0LiBQYXkgMiBDb2luLCBsb3NlIDIgUmVwLCBvciDiiJIxIGZhY3Rpb24gcmVsYXRpb25zaGlwLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSG90LUhlYWRlZCBDb2hvcnRcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJEdXJpbmcgdGhlIFNjb3JlLCBvbmUgb2YgeW91ciBDb2hvcnRzIHBpY2tlZCBhIGZpZ2h0IHdpdGggYW4gYWxsaWVkIENvaG9ydC4gUGF5IDIgQ29pbiwgbG9zZSAyIFJlcCwgb3Ig4oiSMSBmYWN0aW9uIHJlbGF0aW9uc2hpcC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkhvdC1IZWFkZWQgQ29ob3J0XCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRHVyaW5nIHRoZSBTY29yZSwgb25lIG9mIHlvdXIgQ29ob3J0cyBwaWNrZWQgYSBmaWdodCB3aXRoIGFuIGFsbGllZCBDb2hvcnQuIFBheSAyIENvaW4sIGxvc2UgMiBSZXAsIG9yIOKIkjEgZmFjdGlvbiByZWxhdGlvbnNoaXAuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaXhlZCBNZXNzYWdlc1wiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZmFjdGlvbiBvZiB5b3VyIGNob2ljZSB0aGF0IGlzIGZyaWVuZGx5IHRvIHlvdXIgY3JldyBtb3ZlcyBvbmUgc3RlcCB0b3dhcmRzIE5ldXRyYWwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNaXhlZCBNZXNzYWdlc1wiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZmFjdGlvbiBvZiB5b3VyIGNob2ljZSB0aGF0IGlzIGZyaWVuZGx5IHRvIHlvdXIgY3JldyBtb3ZlcyBvbmUgc3RlcCB0b3dhcmRzIE5ldXRyYWwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNdXR1YWwgRGVmZW5zZVwiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZnJpZW5kbHkgRmFjdGlvbiBnb2VzIHRvIFdhciB3aXRoIGEgbmV1dHJhbCBGYWN0aW9uLiBFaXRoZXIgam9pbiB0aGVpciBXYXIsIG9yIHRoZXkgbW92ZSB0byDiiJIxIG9uIHRoZSByZWxhdGlvbnNoaXAgY2hhcnQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJNdXR1YWwgRGVmZW5zZVwiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZnJpZW5kbHkgRmFjdGlvbiBnb2VzIHRvIFdhciB3aXRoIGEgbmV1dHJhbCBGYWN0aW9uLiBFaXRoZXIgam9pbiB0aGVpciBXYXIsIG9yIHRoZXkgbW92ZSB0byDiiJIxIG9uIHRoZSByZWxhdGlvbnNoaXAgY2hhcnQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUZW5zaW9ucyBTcHJlYWRcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJPbmUgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIFdhciwgYW5kIGFub3RoZXIgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIEFsbHkuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUZW5zaW9ucyBTcHJlYWRcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJPbmUgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIFdhciwgYW5kIGFub3RoZXIgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIEFsbHkuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUZW5zaW9ucyBTcHJlYWRcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJPbmUgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIFdhciwgYW5kIGFub3RoZXIgTmV1dHJhbCBGYWN0aW9uIG1vdmVzIGEgc3RlcCB0b3dhcmRzIEFsbHkuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaGUgV2FsbHMgSGF2ZSBFYXJzXCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBmcmllbmRseSBmYWN0aW9uIGhlYXJzIHlvdSBkaWQgYSBTY29yZSBhZ2FpbnN0IHRoZWlyIGFsbHkuIOKIkjEgdG8gdGhhdCBmYWN0aW9uJ3MgcmVsYXRpb25zaGlwIHJhdGluZy5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlRoZSBXYWxscyBIYXZlIEVhcnNcIiwgY2F0ZWdvcnk6IFwiRmFjdGlvbiBSZWxhdGlvbnNoaXAgRWZmZWN0XCIsIGVmZmVjdDogXCJBIGZyaWVuZGx5IGZhY3Rpb24gaGVhcnMgeW91IGRpZCBhIFNjb3JlIGFnYWluc3QgdGhlaXIgYWxseS4g4oiSMSB0byB0aGF0IGZhY3Rpb24ncyByZWxhdGlvbnNoaXAgcmF0aW5nLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVGhlIFdhbGxzIEhhdmUgRWFyc1wiLCBjYXRlZ29yeTogXCJGYWN0aW9uIFJlbGF0aW9uc2hpcCBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgZnJpZW5kbHkgZmFjdGlvbiBoZWFycyB5b3UgZGlkIGEgU2NvcmUgYWdhaW5zdCB0aGVpciBhbGx5LiDiiJIxIHRvIHRoYXQgZmFjdGlvbidzIHJlbGF0aW9uc2hpcCByYXRpbmcuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaGUgV2FsbHMgSGF2ZSBFeWVzXCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBmcmllbmRseSBmYWN0aW9uIGhlYXJzIHlvdSBkaWQgYSBTY29yZSBhZ2FpbnN0IHRoZWlyIGFsbHkuIOKIkjEgdG8gYm90aCBmYWN0aW9ucycgcmVsYXRpb25zaGlwIHJhdGluZ3MuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaGUgV2FsbHMgSGF2ZSBFeWVzXCIsIGNhdGVnb3J5OiBcIkZhY3Rpb24gUmVsYXRpb25zaGlwIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBmcmllbmRseSBmYWN0aW9uIGhlYXJzIHlvdSBkaWQgYSBTY29yZSBhZ2FpbnN0IHRoZWlyIGFsbHkuIOKIkjEgdG8gYm90aCBmYWN0aW9ucycgcmVsYXRpb25zaGlwIHJhdGluZ3MuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCIuLi5hbmQgSW50byB0aGUgRmlyZVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgYXJlIGFtYnVzaGVkIGJ5IGFuIGFzc2Fzc2luIG9yIGJvdW50eSBodW50ZXIuIFN0YXJ0IGEgNC1DbG9jaywgJ0VsaXRlIEFtYnVzaGVyJyB0byBvdmVyY29tZSB0aGlzIG5ldyBmb2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCIuLi5hbmQgSW50byB0aGUgRmlyZVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgYXJlIGFtYnVzaGVkIGJ5IGFuIGFzc2Fzc2luIG9yIGJvdW50eSBodW50ZXIuIFN0YXJ0IGEgNC1DbG9jaywgJ0VsaXRlIEFtYnVzaGVyJyB0byBvdmVyY29tZSB0aGlzIG5ldyBmb2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBIEZhbWlsaWFyIEZhY2VcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IHJlY29nbml6ZSBhIGNvbnRhY3Qgb2YgeW91ciBjaG9pY2UgYW1vbmcgdGhlIHJpdmFscyB5b3UgYXJlIHJ1bm5pbmcgdGhlIFNjb3JlIGFnYWluc3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBIEZhbWlsaWFyIEZhY2VcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IHJlY29nbml6ZSBhIGNvbnRhY3Qgb2YgeW91ciBjaG9pY2UgYW1vbmcgdGhlIHJpdmFscyB5b3UgYXJlIHJ1bm5pbmcgdGhlIFNjb3JlIGFnYWluc3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBIEZhbWlsaWFyIEZhY2VcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IHJlY29nbml6ZSBhIGNvbnRhY3Qgb2YgeW91ciBjaG9pY2UgYW1vbmcgdGhlIHJpdmFscyB5b3UgYXJlIHJ1bm5pbmcgdGhlIFNjb3JlIGFnYWluc3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBY2NpZGVudGFsIERpc2NoYXJnZVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJBIHdlYXBvbiBvciBpdGVtIHlvdSBhcmUgY2FycnlpbmcgbG91ZGx5IGRpc2NoYXJnZXMgYW5kIG5lZWRzIHRvIGJlIHJlbG9hZGVkIGJlZm9yZSBpdCBjYW4gYmUgdXNlZC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkFjY2lkZW50YWwgRGlzY2hhcmdlXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgd2VhcG9uIG9yIGl0ZW0geW91IGFyZSBjYXJyeWluZyBsb3VkbHkgZGlzY2hhcmdlcyBhbmQgbmVlZHMgdG8gYmUgcmVsb2FkZWQgYmVmb3JlIGl0IGNhbiBiZSB1c2VkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiQWNjaWRlbnRhbCBEaXNjaGFyZ2VcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSB3ZWFwb24gb3IgaXRlbSB5b3UgYXJlIGNhcnJ5aW5nIGxvdWRseSBkaXNjaGFyZ2VzIGFuZCBuZWVkcyB0byBiZSByZWxvYWRlZCBiZWZvcmUgaXQgY2FuIGJlIHVzZWQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJBbGwgb3IgTm90aGluZ1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgZmFpbCB0aGlzIHJvbGwsIHlvdSBjYW5ub3QgcmVzaXN0IHRoZSBlZmZlY3RzIG9mIHRoYXQgZmFpbHVyZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkFsbCBvciBOb3RoaW5nXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdSBmYWlsIHRoaXMgcm9sbCwgeW91IGNhbm5vdCByZXNpc3QgdGhlIGVmZmVjdHMgb2YgdGhhdCBmYWlsdXJlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiQWxsIG9yIE5vdGhpbmdcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IGZhaWwgdGhpcyByb2xsLCB5b3UgY2Fubm90IHJlc2lzdCB0aGUgZWZmZWN0cyBvZiB0aGF0IGZhaWx1cmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJCaXNob3AncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IGFyZSBub3QgaW4gY29tYmF0LCBnYWluICsyZCBmb3IgdGhpcyByb2xsIGluc3RlYWQgb2YgdGhlIHN0YW5kYXJkICsxZDsgYnV0IHlvdSBjYW4gcm9sbCBubyBtb3JlIHRoYW4gMWQgZm9yIHlvdXIgbmV4dCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJCaXNob3AncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IGFyZSBub3QgaW4gY29tYmF0LCBnYWluICsyZCBmb3IgdGhpcyByb2xsIGluc3RlYWQgb2YgdGhlIHN0YW5kYXJkICsxZDsgYnV0IHlvdSBjYW4gcm9sbCBubyBtb3JlIHRoYW4gMWQgZm9yIHlvdXIgbmV4dCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJCaXNob3AncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IGFyZSBub3QgaW4gY29tYmF0LCBnYWluICsyZCBmb3IgdGhpcyByb2xsIGluc3RlYWQgb2YgdGhlIHN0YW5kYXJkICsxZDsgYnV0IHlvdSBjYW4gcm9sbCBubyBtb3JlIHRoYW4gMWQgZm9yIHlvdXIgbmV4dCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJCcnV0ZSBGb3JjZSBNZXRob2RcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IG5vaXNpbHkgYnJlYWsgYSB3ZWFwb24gb2YgeW91ciBjaG9pY2Ugd2hpbGUgYXR0ZW1wdGluZyB0aGlzIEFjdGlvbiwgZXZlbiBpZiBpdCBpcyBub3QgYSBjb21iYXQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiQnJ1dGUgRm9yY2UgTWV0aG9kXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBub2lzaWx5IGJyZWFrIGEgd2VhcG9uIG9mIHlvdXIgY2hvaWNlIHdoaWxlIGF0dGVtcHRpbmcgdGhpcyBBY3Rpb24sIGV2ZW4gaWYgaXQgaXMgbm90IGEgY29tYmF0IEFjdGlvbi5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkJydXRlIEZvcmNlIE1ldGhvZFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3Ugbm9pc2lseSBicmVhayBhIHdlYXBvbiBvZiB5b3VyIGNob2ljZSB3aGlsZSBhdHRlbXB0aW5nIHRoaXMgQWN0aW9uLCBldmVuIGlmIGl0IGlzIG5vdCBhIGNvbWJhdCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJDbGVhciB0aGUgQm9hcmRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IHN1Y2NlZWQgYXQgdGhpcyByb2xsLCBjbGVhciBvciBmaWxsIGEgU2NvcmUgQ2xvY2sgb2YgeW91ciBjaG9pY2UuIElmIHlvdSBmYWlsIHRoZSByb2xsLCB5b3UgVHJhdW1hIG91dCBvZiB0aGUgc2NlbmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJDbGVhciB0aGUgQm9hcmRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IHN1Y2NlZWQgYXQgdGhpcyByb2xsLCBjbGVhciBvciBmaWxsIGEgU2NvcmUgQ2xvY2sgb2YgeW91ciBjaG9pY2UuIElmIHlvdSBmYWlsIHRoZSByb2xsLCB5b3UgVHJhdW1hIG91dCBvZiB0aGUgc2NlbmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEZXZpbCdzIEV4Y2hhbmdlXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBnYWluIHRoZSBub3JtYWwgKzFkIHRvIHRoaXMgcm9sbCwgYnV0IHN1ZmZlciDiiJIxZCB0byB5b3VyIG5leHQgQWN0aW9uLCBhbmQgY2Fubm90IHRha2UgYSBEZXZpbCdzIEJhcmdhaW4gdG8gb2Zmc2V0IGl0LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiRGV2aWwncyBFeGNoYW5nZVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgZ2FpbiB0aGUgbm9ybWFsICsxZCB0byB0aGlzIHJvbGwsIGJ1dCBzdWZmZXIg4oiSMWQgdG8geW91ciBuZXh0IEFjdGlvbiwgYW5kIGNhbm5vdCB0YWtlIGEgRGV2aWwncyBCYXJnYWluIHRvIG9mZnNldCBpdC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkRldmlsJ3MgRXhjaGFuZ2VcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGdhaW4gdGhlIG5vcm1hbCArMWQgdG8gdGhpcyByb2xsLCBidXQgc3VmZmVyIOKIkjFkIHRvIHlvdXIgbmV4dCBBY3Rpb24sIGFuZCBjYW5ub3QgdGFrZSBhIERldmlsJ3MgQmFyZ2FpbiB0byBvZmZzZXQgaXQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaG9zdGx5IEF0dGVudGlvblwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIGEgZ2hvc3QgaW4gdGhlIGFyZWEgbm90aWNlcyB5b3UgYW5kIGJlZ2lucyBzdGFsa2luZyB5b3UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaG9zdGx5IEF0dGVudGlvblwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIGEgZ2hvc3QgaW4gdGhlIGFyZWEgbm90aWNlcyB5b3UgYW5kIGJlZ2lucyBzdGFsa2luZyB5b3UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaG9zdGx5IEF0dGVudGlvblwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIGEgZ2hvc3QgaW4gdGhlIGFyZWEgbm90aWNlcyB5b3UgYW5kIGJlZ2lucyBzdGFsa2luZyB5b3UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaW1jcmFjayBHZWFyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIldoYXRldmVyIHdlYXBvbiBvciB0b29sIHlvdSBhcmUgdXNpbmcgaXMgY2hlYXBseSBtYWRlIGFuZCBicmVha3Mgd2hldGhlciB0aGUgcm9sbCBzdWNjZWVkcyBvciBub3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaW1jcmFjayBHZWFyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIldoYXRldmVyIHdlYXBvbiBvciB0b29sIHlvdSBhcmUgdXNpbmcgaXMgY2hlYXBseSBtYWRlIGFuZCBicmVha3Mgd2hldGhlciB0aGUgcm9sbCBzdWNjZWVkcyBvciBub3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHaW1jcmFjayBHZWFyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIldoYXRldmVyIHdlYXBvbiBvciB0b29sIHlvdSBhcmUgdXNpbmcgaXMgY2hlYXBseSBtYWRlIGFuZCBicmVha3Mgd2hldGhlciB0aGUgcm9sbCBzdWNjZWVkcyBvciBub3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJHb25lIFJvZ3VlXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBjYW5ub3QgYWNjZXB0IGFuIEFzc2lzdCBmb3IgdGhlIHJlc3Qgb2YgdGhpcyBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkdvbmUgUm9ndWVcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGNhbm5vdCBhY2NlcHQgYW4gQXNzaXN0IGZvciB0aGUgcmVzdCBvZiB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSHVudGVyIEJlY29tZXMgSHVudGVkXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSd2ZSBiZWVuIHNvIHByZW9jY3VwaWVkIHdpdGggdGhlIG9ic3RhY2xlcyBpbiBmcm9udCBvZiB5b3UgdGhhdCB5b3UgZGlkbid0IG5vdGljZSB0aGUgcml2YWwgbGluaW5nIHVwIGEgc2hvdCBiZWhpbmQgeW91LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSHVudGVyIEJlY29tZXMgSHVudGVkXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSd2ZSBiZWVuIHNvIHByZW9jY3VwaWVkIHdpdGggdGhlIG9ic3RhY2xlcyBpbiBmcm9udCBvZiB5b3UgdGhhdCB5b3UgZGlkbid0IG5vdGljZSB0aGUgcml2YWwgbGluaW5nIHVwIGEgc2hvdCBiZWhpbmQgeW91LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSHVudGVyIEJlY29tZXMgSHVudGVkXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSd2ZSBiZWVuIHNvIHByZW9jY3VwaWVkIHdpdGggdGhlIG9ic3RhY2xlcyBpbiBmcm9udCBvZiB5b3UgdGhhdCB5b3UgZGlkbid0IG5vdGljZSB0aGUgcml2YWwgbGluaW5nIHVwIGEgc2hvdCBiZWhpbmQgeW91LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSSBLbm93IEkgUGFja2VkIEl0IVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgbXVzdCBpbW1lZGlhdGVseSBjaGVjayBvZmYgMSBMb2FkIHRvIG5vIGVmZmVjdCwgcmVwcmVzZW50aW5nIGVxdWlwbWVudCB5b3UndmUgbWlzcGxhY2VkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSSBLbm93IEkgUGFja2VkIEl0IVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgbXVzdCBpbW1lZGlhdGVseSBjaGVjayBvZmYgMSBMb2FkIHRvIG5vIGVmZmVjdCwgcmVwcmVzZW50aW5nIGVxdWlwbWVudCB5b3UndmUgbWlzcGxhY2VkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSSBLbm93IEkgUGFja2VkIEl0IVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgbXVzdCBpbW1lZGlhdGVseSBjaGVjayBvZmYgMSBMb2FkIHRvIG5vIGVmZmVjdCwgcmVwcmVzZW50aW5nIGVxdWlwbWVudCB5b3UndmUgbWlzcGxhY2VkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSSBLbm93IEkgUGFja2VkIFRoZW0hXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBtdXN0IGltbWVkaWF0ZWx5IGNoZWNrIG9mZiAyIExvYWQgdG8gbm8gZWZmZWN0LCByZXByZXNlbnRpbmcgZXF1aXBtZW50IHlvdSd2ZSBtaXNwbGFjZWQuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJJIEtub3cgSSBQYWNrZWQgVGhlbSFcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IG11c3QgaW1tZWRpYXRlbHkgY2hlY2sgb2ZmIDIgTG9hZCB0byBubyBlZmZlY3QsIHJlcHJlc2VudGluZyBlcXVpcG1lbnQgeW91J3ZlIG1pc3BsYWNlZC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkkgS25vdyBJIFBhY2tlZCBUaGVtIVwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgbXVzdCBpbW1lZGlhdGVseSBjaGVjayBvZmYgMiBMb2FkIHRvIG5vIGVmZmVjdCwgcmVwcmVzZW50aW5nIGVxdWlwbWVudCB5b3UndmUgbWlzcGxhY2VkLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSmFuZ2xlZCBOZXJ2ZXNcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRm9yIHRoZSByZXN0IG9mIHRoZSBTY29yZSwgYWxsIHJvbGxzIHRvIFJlc2lzdCBnZW5lcmF0ZSArMSBTdHJlc3MuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJKYW5nbGVkIE5lcnZlc1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJGb3IgdGhlIHJlc3Qgb2YgdGhlIFNjb3JlLCBhbGwgcm9sbHMgdG8gUmVzaXN0IGdlbmVyYXRlICsxIFN0cmVzcy5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkphbmdsZWQgTmVydmVzXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUsIGFsbCByb2xscyB0byBSZXNpc3QgZ2VuZXJhdGUgKzEgU3RyZXNzLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiSnVzdCBhIExpdHRsZSBTcGFya1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJBIGxhbXAgb3IgY2FuZGxlIGdldHMga25vY2tlZCBvdmVyLCBjYXRjaGluZyBhIGN1cnRhaW4gb3IgcnVnIG9uIGZpcmUuIFN0YXJ0IGEgQ2xvY2s6ICdCdWlsZGluZyBpcyBvbiBGaXJlJy5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkp1c3QgYSBMaXR0bGUgU3BhcmtcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBsYW1wIG9yIGNhbmRsZSBnZXRzIGtub2NrZWQgb3ZlciwgY2F0Y2hpbmcgYSBjdXJ0YWluIG9yIHJ1ZyBvbiBmaXJlLiBTdGFydCBhIENsb2NrOiAnQnVpbGRpbmcgaXMgb24gRmlyZScuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJKdXN0IGEgTGl0dGxlIFNwYXJrXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkEgbGFtcCBvciBjYW5kbGUgZ2V0cyBrbm9ja2VkIG92ZXIsIGNhdGNoaW5nIGEgY3VydGFpbiBvciBydWcgb24gZmlyZS4gU3RhcnQgYSBDbG9jazogJ0J1aWxkaW5nIGlzIG9uIEZpcmUnLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiS2luZydzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgZmFpbCBhdCB0aGlzIHJvbGwsIHlvdSBhcmUgaW1tdW5lIHRvIGFueSBIYXJtOyBidXQgeW91IGhhdmUgYSB6ZXJvIHJhdGluZyB0byB5b3VyIG5leHQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiS2luZydzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgZmFpbCBhdCB0aGlzIHJvbGwsIHlvdSBhcmUgaW1tdW5lIHRvIGFueSBIYXJtOyBidXQgeW91IGhhdmUgYSB6ZXJvIHJhdGluZyB0byB5b3VyIG5leHQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiS2luZydzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgZmFpbCBhdCB0aGlzIHJvbGwsIHlvdSBhcmUgaW1tdW5lIHRvIGFueSBIYXJtOyBidXQgeW91IGhhdmUgYSB6ZXJvIHJhdGluZyB0byB5b3VyIG5leHQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiS25pZ2h0J3MgR2FtYml0XCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdSBhcmUgaW4gY29tYmF0LCBnYWluICsyZCBmb3IgdGhpcyByb2xsIGluc3RlYWQgb2YgdGhlIHN0YW5kYXJkICsxZDsgYnV0IHlvdSBjYW4gcm9sbCBubyBtb3JlIHRoYW4gMWQgZm9yIHlvdXIgbmV4dCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJLbmlnaHQncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgeW91IGFyZSBpbiBjb21iYXQsIGdhaW4gKzJkIGZvciB0aGlzIHJvbGwgaW5zdGVhZCBvZiB0aGUgc3RhbmRhcmQgKzFkOyBidXQgeW91IGNhbiByb2xsIG5vIG1vcmUgdGhhbiAxZCBmb3IgeW91ciBuZXh0IEFjdGlvbi5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIktuaWdodCdzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiB5b3UgYXJlIGluIGNvbWJhdCwgZ2FpbiArMmQgZm9yIHRoaXMgcm9sbCBpbnN0ZWFkIG9mIHRoZSBzdGFuZGFyZCArMWQ7IGJ1dCB5b3UgY2FuIHJvbGwgbm8gbW9yZSB0aGFuIDFkIGZvciB5b3VyIG5leHQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiS251Y2tsZSBCdXN0ZXJcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiV2hldGhlciB0aGlzIEFjdGlvbiBzdWNjZWVkcyBvciBub3QsIHlvdSBhY2NpZGVudGFsbHkgaW5mbGljdCBsZXZlbCAxIEhhcm0gb24geW91ciBoYW5kLCAnQnVzdGVkIEtudWNrbGVzLidcIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIktudWNrbGUgQnVzdGVyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIldoZXRoZXIgdGhpcyBBY3Rpb24gc3VjY2VlZHMgb3Igbm90LCB5b3UgYWNjaWRlbnRhbGx5IGluZmxpY3QgbGV2ZWwgMSBIYXJtIG9uIHlvdXIgaGFuZCwgJ0J1c3RlZCBLbnVja2xlcy4nXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJLbnVja2xlIEJ1c3RlclwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHRoaXMgQWN0aW9uIHN1Y2NlZWRzIG9yIG5vdCwgeW91IGFjY2lkZW50YWxseSBpbmZsaWN0IGxldmVsIDEgSGFybSBvbiB5b3VyIGhhbmQsICdCdXN0ZWQgS251Y2tsZXMuJ1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTm93IG9yIE5ldmVyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdSBmYWlsIHRoaXMgcm9sbCwgeW91IGxvc2UgdGhpcyBvcHBvcnR1bml0eSBhbmQgY2Fubm90IHJldHJ5IGl0IGZvciB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTm93IG9yIE5ldmVyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdSBmYWlsIHRoaXMgcm9sbCwgeW91IGxvc2UgdGhpcyBvcHBvcnR1bml0eSBhbmQgY2Fubm90IHJldHJ5IGl0IGZvciB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiTm93IG9yIE5ldmVyXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIHlvdSBmYWlsIHRoaXMgcm9sbCwgeW91IGxvc2UgdGhpcyBvcHBvcnR1bml0eSBhbmQgY2Fubm90IHJldHJ5IGl0IGZvciB0aGlzIFNjb3JlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiT3V0IG9mIHRoZSBGcnlpbmcgUGFuLi4uXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoaW5ncyBhcmUgYWJvdXQgdG8gZ28gZnJvbSBiYWQgdG8gd29yc2UuIFN0YXJ0IGEgNC1DbG9jaywgJ1N1cnByaXNlIFJlaW5mb3JjZW1lbnRzJy5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIk91dCBvZiB0aGUgRnJ5aW5nIFBhbi4uLlwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJUaGluZ3MgYXJlIGFib3V0IHRvIGdvIGZyb20gYmFkIHRvIHdvcnNlLiBTdGFydCBhIDQtQ2xvY2ssICdTdXJwcmlzZSBSZWluZm9yY2VtZW50cycuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJPdXQgb2YgdGhlIEZyeWluZyBQYW4uLi5cIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhpbmdzIGFyZSBhYm91dCB0byBnbyBmcm9tIGJhZCB0byB3b3JzZS4gU3RhcnQgYSA0LUNsb2NrLCAnU3VycHJpc2UgUmVpbmZvcmNlbWVudHMnLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiT3ZlcmV4dGVuZGVkXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdXIgbmV4dCBBY3Rpb24gYXV0b21hdGljYWxseSBoYXMgcmVkdWNlZCBFZmZlY3QuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJPdmVyZXh0ZW5kZWRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91ciBuZXh0IEFjdGlvbiBhdXRvbWF0aWNhbGx5IGhhcyByZWR1Y2VkIEVmZmVjdC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIk92ZXJleHRlbmRlZFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3VyIG5leHQgQWN0aW9uIGF1dG9tYXRpY2FsbHkgaGFzIHJlZHVjZWQgRWZmZWN0LlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUGF3bidzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgY2Fubm90IHVzZSBMb2FkIGZvciBBcm1vciBkdXJpbmcgdGhpcyBTY29yZS4gWW91IGNhbm5vdCBhY2NlcHQgdGhpcyBiYXJnYWluIGlmIHlvdSBhbHJlYWR5IGhhdmUgdXNlZCBMb2FkIGZvciBBcm1vci5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlBhd24ncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGNhbm5vdCB1c2UgTG9hZCBmb3IgQXJtb3IgZHVyaW5nIHRoaXMgU2NvcmUuIFlvdSBjYW5ub3QgYWNjZXB0IHRoaXMgYmFyZ2FpbiBpZiB5b3UgYWxyZWFkeSBoYXZlIHVzZWQgTG9hZCBmb3IgQXJtb3IuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJQYXduJ3MgR2FtYml0XCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBjYW5ub3QgdXNlIExvYWQgZm9yIEFybW9yIGR1cmluZyB0aGlzIFNjb3JlLiBZb3UgY2Fubm90IGFjY2VwdCB0aGlzIGJhcmdhaW4gaWYgeW91IGFscmVhZHkgaGF2ZSB1c2VkIExvYWQgZm9yIEFybW9yLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUGxhbiBDLi4uXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoaW5ncyBhcmUgbm90IGdvaW5nIGFjY29yZGluZyB0byBwbGFuLiBGbGFzaGJhY2tzIGNvc3QgKzEgU3RyZXNzIGZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJQbGFuIEMuLi5cIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVGhpbmdzIGFyZSBub3QgZ29pbmcgYWNjb3JkaW5nIHRvIHBsYW4uIEZsYXNoYmFja3MgY29zdCArMSBTdHJlc3MgZm9yIHRoZSByZXN0IG9mIHRoZSBTY29yZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlF1ZWVuJ3MgR2FtYml0XCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBhdXRvbWF0aWNhbGx5IHN1Y2NlZWQgYXQgdGhpcyBBY3Rpb24gYXMgaWYgeW91IHJvbGxlZCBhIDY7IGJ1dCB5b3UgaGF2ZSBhIHplcm8gcmF0aW5nIHRvIHlvdXIgbmV4dCBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJRdWVlbidzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgYXV0b21hdGljYWxseSBzdWNjZWVkIGF0IHRoaXMgQWN0aW9uIGFzIGlmIHlvdSByb2xsZWQgYSA2OyBidXQgeW91IGhhdmUgYSB6ZXJvIHJhdGluZyB0byB5b3VyIG5leHQgQWN0aW9uLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUXVlZW4ncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGF1dG9tYXRpY2FsbHkgc3VjY2VlZCBhdCB0aGlzIEFjdGlvbiBhcyBpZiB5b3Ugcm9sbGVkIGEgNjsgYnV0IHlvdSBoYXZlIGEgemVybyByYXRpbmcgdG8geW91ciBuZXh0IEFjdGlvbi5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlF1aWNrc2lsdmVyIFBvaXNvbmluZ1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJVc2VkIGluIGVsZWN0cm9wbGFzbWljIGNvbnRhaW5lcnMgYW5kIGRldmljZXMsIHlvdSBnZXQgYSBub3NlZnVsIG9mIHF1aWNrc2lsdmVyIHZhcG9yLCBzdWZmZXJpbmcgbGV2ZWwgMSBIYXJtLCAnU2lsdmVybHVuZycgd2hpY2ggc3RhcnRzIGEgNC1DbG9jayBQcm9qZWN0IHRvIGhlYWwuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJRdWlja3NpbHZlciBQb2lzb25pbmdcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiVXNlZCBpbiBlbGVjdHJvcGxhc21pYyBjb250YWluZXJzIGFuZCBkZXZpY2VzLCB5b3UgZ2V0IGEgbm9zZWZ1bCBvZiBxdWlja3NpbHZlciB2YXBvciwgc3VmZmVyaW5nIGxldmVsIDEgSGFybSwgJ1NpbHZlcmx1bmcnIHdoaWNoIHN0YXJ0cyBhIDQtQ2xvY2sgUHJvamVjdCB0byBoZWFsLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUXVpY2tzaWx2ZXIgUG9pc29uaW5nXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIlVzZWQgaW4gZWxlY3Ryb3BsYXNtaWMgY29udGFpbmVycyBhbmQgZGV2aWNlcywgeW91IGdldCBhIG5vc2VmdWwgb2YgcXVpY2tzaWx2ZXIgdmFwb3IsIHN1ZmZlcmluZyBsZXZlbCAxIEhhcm0sICdTaWx2ZXJsdW5nJyB3aGljaCBzdGFydHMgYSA0LUNsb2NrIFByb2plY3QgdG8gaGVhbC5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlJvb2sncyBHYW1iaXRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91IGNhbm5vdCB1c2UgTG9hZCBmb3IgVW51c3VhbCBvciBTY2FyeSBXZWFwb25zIHRoaXMgU2NvcmUuIFlvdSBjYW5ub3QgYWNjZXB0IHRoaXMgYmFyZ2FpbiBpZiB5b3UgYWxyZWFkeSBoYXZlIHVzZWQgTG9hZCBmb3IgdGhlc2UuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJSb29rJ3MgR2FtYml0XCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBjYW5ub3QgdXNlIExvYWQgZm9yIFVudXN1YWwgb3IgU2NhcnkgV2VhcG9ucyB0aGlzIFNjb3JlLiBZb3UgY2Fubm90IGFjY2VwdCB0aGlzIGJhcmdhaW4gaWYgeW91IGFscmVhZHkgaGF2ZSB1c2VkIExvYWQgZm9yIHRoZXNlLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiUm9vaydzIEdhbWJpdFwiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJZb3UgY2Fubm90IHVzZSBMb2FkIGZvciBVbnVzdWFsIG9yIFNjYXJ5IFdlYXBvbnMgdGhpcyBTY29yZS4gWW91IGNhbm5vdCBhY2NlcHQgdGhpcyBiYXJnYWluIGlmIHlvdSBhbHJlYWR5IGhhdmUgdXNlZCBMb2FkIGZvciB0aGVzZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlNob3QgTmVydmVzXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUsIGFsbCByb2xscyB0byBSZXNpc3QgZ2VuZXJhdGUgKzIgU3RyZXNzLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiU2hvdCBOZXJ2ZXNcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiRm9yIHRoZSByZXN0IG9mIHRoZSBTY29yZSwgYWxsIHJvbGxzIHRvIFJlc2lzdCBnZW5lcmF0ZSArMiBTdHJlc3MuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUdXJuZWQgQXJvdW5kXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsb3NlIHRyYWNrIG9mIHlvdXIgcG9zaXRpb24uIFN0YXJ0IGEgNC1DbG9jaywgJ1doZXJlIEFtIEk/JyBZb3UgbXVzdCB1c2UgQWN0aW9ucyBsb29raW5nIGZvciB5b3VyIENyZXcgdG8gcmVqb2luIHRoZW0uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUdXJuZWQgQXJvdW5kXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsb3NlIHRyYWNrIG9mIHlvdXIgcG9zaXRpb24uIFN0YXJ0IGEgNC1DbG9jaywgJ1doZXJlIEFtIEk/JyBZb3UgbXVzdCB1c2UgQWN0aW9ucyBsb29raW5nIGZvciB5b3VyIENyZXcgdG8gcmVqb2luIHRoZW0uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUdXJuZWQgQXJvdW5kXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIllvdSBsb3NlIHRyYWNrIG9mIHlvdXIgcG9zaXRpb24uIFN0YXJ0IGEgNC1DbG9jaywgJ1doZXJlIEFtIEk/JyBZb3UgbXVzdCB1c2UgQWN0aW9ucyBsb29raW5nIGZvciB5b3VyIENyZXcgdG8gcmVqb2luIHRoZW0uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJVbnN1cmUgRm9vdGluZ1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIHlvdSBsb29zZSB5b3VyIGZvb3RpbmcgYW5kIGZhbGwgcHJvbmUgYWZ0ZXIgdGhpcyBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJVbnN1cmUgRm9vdGluZ1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIHlvdSBsb29zZSB5b3VyIGZvb3RpbmcgYW5kIGZhbGwgcHJvbmUgYWZ0ZXIgdGhpcyBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJVbnN1cmUgRm9vdGluZ1wiLCBjYXRlZ29yeTogXCJJbW1lZGlhdGUgRWZmZWN0XCIsIGVmZmVjdDogXCJXaGV0aGVyIHlvdSBzdWNjZWVkIGluIHRoaXMgcm9sbCBvciBub3QsIHlvdSBsb29zZSB5b3VyIGZvb3RpbmcgYW5kIGZhbGwgcHJvbmUgYWZ0ZXIgdGhpcyBBY3Rpb24uXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXb3JzZSB0aGFuIFdlIHRob3VnaHRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBDbG9jayBvZiB5b3VyIGNob2ljZSB0aGF0IGlzIHJ1bm5pbmcgZm9yIHRoaXMgU2NvcmUgaXMgZWl0aGVyIGFkdmFuY2VkIG9yIHNldCBiYWNrIGJ5IHR3byBzZWdtZW50cyAod2hpY2hldmVyIGlzIHdvcnNlIGZvciB0aGUgQ3JldykuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJXb3JzZSB0aGFuIFdlIHRob3VnaHRcIiwgY2F0ZWdvcnk6IFwiSW1tZWRpYXRlIEVmZmVjdFwiLCBlZmZlY3Q6IFwiQSBDbG9jayBvZiB5b3VyIGNob2ljZSB0aGF0IGlzIHJ1bm5pbmcgZm9yIHRoaXMgU2NvcmUgaXMgZWl0aGVyIGFkdmFuY2VkIG9yIHNldCBiYWNrIGJ5IHR3byBzZWdtZW50cyAod2hpY2hldmVyIGlzIHdvcnNlIGZvciB0aGUgQ3JldykuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJZb3UncmUgQWxsIE9uIFlvdXIgT3duXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoaXMgcm9sbCwgeW91IGNhbm5vdCBvZmZlciB0byBBc3Npc3Qgb24gYW55b25lIGVsc2UncyByb2xsIGZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJZb3UncmUgQWxsIE9uIFlvdXIgT3duXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoaXMgcm9sbCwgeW91IGNhbm5vdCBvZmZlciB0byBBc3Npc3Qgb24gYW55b25lIGVsc2UncyByb2xsIGZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJZb3UncmUgQWxsIE9uIFlvdXIgT3duXCIsIGNhdGVnb3J5OiBcIkltbWVkaWF0ZSBFZmZlY3RcIiwgZWZmZWN0OiBcIkFmdGVyIHRoaXMgcm9sbCwgeW91IGNhbm5vdCBvZmZlciB0byBBc3Npc3Qgb24gYW55b25lIGVsc2UncyByb2xsIGZvciB0aGUgcmVzdCBvZiB0aGUgU2NvcmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEZWF0aCBXaWxsIE5vdCBTdG9wIE1lXCIsIGNhdGVnb3J5OiBcIkxvbmctVGVybSBFZmZlY3RcIiwgZWZmZWN0OiBcIlRoZSBnaG9zdCBvZiBzb21lb25lIHlvdSBraWxsZWQgaXMgZHJpdmVuIHRvIHRha2UgeW91IHdpdGggaXQuIFN0YXJ0IGEgMTItQ2xvY2ssICdTcGVjdHJhbCBWZW5nZW5jZSdcIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIlRoYXQncyBFbm91Z2ggb2YgVGhhdFwiLCBjYXRlZ29yeTogXCJMb25nLVRlcm0gRWZmZWN0XCIsIGVmZmVjdDogXCJTb21lb25lIHdob3NlIGdvYWxzIGFyZSBhZmZlY3RlZCBieSB0aGlzIFNjb3JlIGlzIGdvaW5nIHRvIGZvY3VzIG9uIHlvdSBub3cuIFN0YXJ0IGEgOC1DbG9jaywgJ0NvbGQgVmVuZ2VuY2UnXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJUaGF0J3MgRW5vdWdoIG9mIFRoYXRcIiwgY2F0ZWdvcnk6IFwiTG9uZy1UZXJtIEVmZmVjdFwiLCBlZmZlY3Q6IFwiU29tZW9uZSB3aG9zZSBnb2FscyBhcmUgYWZmZWN0ZWQgYnkgdGhpcyBTY29yZSBpcyBnb2luZyB0byBmb2N1cyBvbiB5b3Ugbm93LiBTdGFydCBhIDgtQ2xvY2ssICdDb2xkIFZlbmdlbmNlJ1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVGhlIExhc3QgU3RyYXdcIiwgY2F0ZWdvcnk6IFwiTG9uZy1UZXJtIEVmZmVjdFwiLCBlZmZlY3Q6IFwiWW91J3ZlIHJveWFsbHkgcGlzc2VkIG9mZiBzb21lb25lIHdpdGggcmVhbCBjbG91dCBpbiB0aGUgY2l0eS4gU3RhcnQgYSAxMi1DbG9jaywgJ0Z1cmlvdXMgVmVuZ2VuY2UnXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJZb3UnbGwgUGF5IEZvciBUaGlzXCIsIGNhdGVnb3J5OiBcIkxvbmctVGVybSBFZmZlY3RcIiwgZWZmZWN0OiBcIlNvbWVvbmUgaHVydCBieSB0aGlzIFNjb3JlIHdpbGwgY29tZSBiYWNrIHRvIGNvbGxlY3Qgd2hhdCdzIG93ZWQuIFN0YXJ0IGEgNi1DbG9jaywgJ1BldHR5IFZlbmdlbmNlJ1wiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiWW91J2xsIFBheSBGb3IgVGhpc1wiLCBjYXRlZ29yeTogXCJMb25nLVRlcm0gRWZmZWN0XCIsIGVmZmVjdDogXCJTb21lb25lIGh1cnQgYnkgdGhpcyBTY29yZSB3aWxsIGNvbWUgYmFjayB0byBjb2xsZWN0IHdoYXQncyBvd2VkLiBTdGFydCBhIDYtQ2xvY2ssICdQZXR0eSBWZW5nZW5jZSdcIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIllvdSdsbCBQYXkgRm9yIFRoaXNcIiwgY2F0ZWdvcnk6IFwiTG9uZy1UZXJtIEVmZmVjdFwiLCBlZmZlY3Q6IFwiU29tZW9uZSBodXJ0IGJ5IHRoaXMgU2NvcmUgd2lsbCBjb21lIGJhY2sgdG8gY29sbGVjdCB3aGF0J3Mgb3dlZC4gU3RhcnQgYSA2LUNsb2NrLCAnUGV0dHkgVmVuZ2VuY2UnXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJEYWxnb211ciwgdGhlIEhlYXJ0IG9mIHRoZSBTdG9ybVwiLCBjYXRlZ29yeTogXCJNYW5kYXRvcnkgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiBvbmUgaXMgbm90IGFscmVhZHkgYWN0aXZlIGZvciB0aGUgY3Jldywgc3RhcnQgYSAxMi1DbG9jayBsYWJlbGVkICdUaGUgSGVhcnQgb2YgdGhlIFN0b3JtJyBhbmQgc2V0IGl0IHRvIG9uZS4gSWYgdGhlIENsb2NrIGlzIGFscmVhZHkgYWN0aXZlLCBhZHZhbmNlIGl0IGJ5IG9uZS5cIiB9LFxuICAgICAgICAgICAgeyBuYW1lOiBcIkRhbGdvbXVyLCB0aGUgSGVhcnQgb2YgdGhlIFN0b3JtXCIsIGNhdGVnb3J5OiBcIk1hbmRhdG9yeSBFZmZlY3RcIiwgZWZmZWN0OiBcIklmIG9uZSBpcyBub3QgYWxyZWFkeSBhY3RpdmUgZm9yIHRoZSBjcmV3LCBzdGFydCBhIDEyLUNsb2NrIGxhYmVsZWQgJ1RoZSBIZWFydCBvZiB0aGUgU3Rvcm0nIGFuZCBzZXQgaXQgdG8gb25lLiBJZiB0aGUgQ2xvY2sgaXMgYWxyZWFkeSBhY3RpdmUsIGFkdmFuY2UgaXQgYnkgb25lLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVWxmIElyb25ib3JuLCB0aGUgU2tvdmxhbiBBZ2l0YXRvclwiLCBjYXRlZ29yeTogXCJNYW5kYXRvcnkgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiBvbmUgaXMgbm90IGFscmVhZHkgYWN0aXZlIGZvciB0aGUgY3Jldywgc3RhcnQgYSA0LUNsb2NrIGxhYmVsZWQgJ1Nrb3ZsYW5kZXIgVXByaXNpbmcnIGFuZCBzZXQgaXQgdG8gb25lLiBJZiB0aGUgQ2xvY2sgaXMgYWxyZWFkeSBhY3RpdmUsIGFkdmFuY2UgaXQgYnkgb25lLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVWxmIElyb25ib3JuLCB0aGUgU2tvdmxhbiBBZ2l0YXRvclwiLCBjYXRlZ29yeTogXCJNYW5kYXRvcnkgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiBvbmUgaXMgbm90IGFscmVhZHkgYWN0aXZlIGZvciB0aGUgY3Jldywgc3RhcnQgYSA0LUNsb2NrIGxhYmVsZWQgJ1Nrb3ZsYW5kZXIgVXByaXNpbmcnIGFuZCBzZXQgaXQgdG8gb25lLiBJZiB0aGUgQ2xvY2sgaXMgYWxyZWFkeSBhY3RpdmUsIGFkdmFuY2UgaXQgYnkgb25lLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVXJ1bWJhciwgdGhlIENsb3NlZCBFeWVcIiwgY2F0ZWdvcnk6IFwiTWFuZGF0b3J5IEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgb25lIGlzIG5vdCBhbHJlYWR5IGFjdGl2ZSBmb3IgdGhlIGNyZXcsIHN0YXJ0IGFuIDgtQ2xvY2sgbGFiZWxlZCAnVGhlIENsb3NlZCBFeWUnIGFuZCBzZXQgaXQgdG8gb25lLiBJZiB0aGUgQ2xvY2sgaXMgYWxyZWFkeSBhY3RpdmUsIGFkdmFuY2UgaXQgYnkgb25lLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVXJ1bWJhciwgdGhlIENsb3NlZCBFeWVcIiwgY2F0ZWdvcnk6IFwiTWFuZGF0b3J5IEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgb25lIGlzIG5vdCBhbHJlYWR5IGFjdGl2ZSBmb3IgdGhlIGNyZXcsIHN0YXJ0IGFuIDgtQ2xvY2sgbGFiZWxlZCAnVGhlIENsb3NlZCBFeWUnIGFuZCBzZXQgaXQgdG8gb25lLiBJZiB0aGUgQ2xvY2sgaXMgYWxyZWFkeSBhY3RpdmUsIGFkdmFuY2UgaXQgYnkgb25lLlwiIH0sXG4gICAgICAgICAgICB7IG5hbWU6IFwiVmFza2FuaSwgdGhlIENyb3Nzcm9hZHMgRGVtb25cIiwgY2F0ZWdvcnk6IFwiTWFuZGF0b3J5IEVmZmVjdFwiLCBlZmZlY3Q6IFwiSWYgb25lIGlzIG5vdCBhbHJlYWR5IGFjdGl2ZSBmb3IgdGhlIGNyZXcsIHN0YXJ0IGEgNi1DbG9jayBsYWJlbGVkICdUaGUgQ3Jvc3Nyb2FkcyBEZW1vbicgYW5kIHNldCBpdCB0byBvbmUuIElmIHRoZSBDbG9jayBpcyBhbHJlYWR5IGFjdGl2ZSwgYWR2YW5jZSBpdCBieSBvbmUuXCIgfSxcbiAgICAgICAgICAgIHsgbmFtZTogXCJWYXNrYW5pLCB0aGUgQ3Jvc3Nyb2FkcyBEZW1vblwiLCBjYXRlZ29yeTogXCJNYW5kYXRvcnkgRWZmZWN0XCIsIGVmZmVjdDogXCJJZiBvbmUgaXMgbm90IGFscmVhZHkgYWN0aXZlIGZvciB0aGUgY3Jldywgc3RhcnQgYSA2LUNsb2NrIGxhYmVsZWQgJ1RoZSBDcm9zc3JvYWRzIERlbW9uJyBhbmQgc2V0IGl0IHRvIG9uZS4gSWYgdGhlIENsb2NrIGlzIGFscmVhZHkgYWN0aXZlLCBhZHZhbmNlIGl0IGJ5IG9uZS5cIiB9XG4gICAgICAgIF0sXG4gICAgICAgIE9ic3RhY2xlczogW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ2VudGlwZWRlc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkFuaW1hbCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkNlbnRpcGVkZXMgdGhlIGxlbmd0aCBvZiBhIGZvcmVhcm0gYXJlIGFsbW9zdCBub2lzZWxlc3MuIElmIHRoZXkgYml0ZSwgdGhlaXIgdG94aW4gY2F1c2VzIGxpdmluZyBmbGVzaCB0byBibGFja2VuIGFuZCBkaWUsIGxlYWRpbmcgdG8gYW1wdXRhdGlvbiBpZiB0aGUgcG9pc29uIGlzbid0IGNvdW50ZXJlZC4gUGVvcGxlIHRlbmQgdG8gc2NyZWFtIHdoZW4gYml0LlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIldlcmUgdGhlIGNlbnRpcGVkZXMgYnJvdWdodCBpbiBhcyBndWFyZGlhbnMsIG9yIGFyZSB0aGV5IGEgbG9jYWwgbnVpc2FuY2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlcmUgYXJlIG1hbnkgZGlmZmVyZW50IGJyZWVkcywgaG93IHdpbGwgeW91IGRlc2NyaWJlIHRoZSBhcHBlYXJhbmNlIG9mIHlvdXJzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZXkgaGF2ZSBhIG5hc3R5IGxvY2FsIG5pY2tuYW1lP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2hlbiBvbmUgYXR0YWNrcyBpdCByZWxlYXNlcyBhIHNjZW50IHRoYXQgZW5yYWdlcyBvdGhlcnMgbmVhcmJ5LCBzbyB0aGV5IHRlbmQgdG8gc3dhcm0uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgZXhjZWxsZW50IHN3aW1tZXJzLCBhbmQgdGhleSBodW50IGluIGJvZy1saWtlIGFyZWFzIHVuZGVyIHRoZSBzdXJmYWNlLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgYnJpZ2h0IHllbGxvdyBhbmQgcmVkLCBhbmQgaGlzcyBiZWZvcmUgc3RyaWtpbmcsIGdpdmluZyBhbGwgdGhlIHdhcm5pbmcgcG9zc2libGUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQWxsIHRoZSBndWFyZGlhbnMgYW5kIG5laWdoYm9ycyBjYXJyeSB0aGUgYW50aWRvdGUsIHRoZSBsb2NhbCBhcG90aGVjYXJ5IGtub3dzIHdoYXQgeW91IG5lZWQuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiR3JlYXQgQ2F0c1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkFuaW1hbCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIk9uZSBvciBtb3JlIGdyZWF0IGNhdHMgc2xpbmsgdGhyb3VnaCB0aGUgc2hhZG93cy4gVGhleSBsaWtlIHRvIGF0dGFjayBmcm9tIGhpZ2ggcGxhY2VzLiBUaGVpciBmdXIgbW90dGxlcyB0byBtYXRjaCB0aGUgY29sb3JzIGFuZCB0b25lcyBhbmQgdGV4dHVyZXMgYXJvdW5kIHRoZW0uXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiRGlkIHRoZSBjdXJyZW50IG93bmVycyBicmluZyB0aGVtIGluLCBvciBhcmUgdGhleSBpbmhlcml0ZWQgZnJvbSBhIHByZXZpb3VzIG93bmVyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZXkgc3RheSBvbiB0aGUgZXN0YXRlLCBvciBnbyBodW50aW5nIGluIHRoZSBsb2NhbCBuZWlnaGJvcmhvb2Q/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgY2F0cyBhcmUgdHJhaW5lZCB0byBhbGVydCBndWFyZHMgKG9yIHdlYXIgY2hhcm0gamV3ZWxyeSB0byBhbGVydCBzdXBlcm5hdHVyYWwgZ3VhcmRpYW5zKSB3aGVuIHRoZXkgZGV0ZWN0IGludHJ1ZGVycyB3aXRoIHRoZWlyIGtlZW4gc2Vuc2VzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIk1hc3NpdmUgb2xkIHRyZWVzIGRyYXBlZCB3aXRoIG1vc3MsIG9yIG1hbnkgbGVkZ2VzIGFuZCBvdmVybG9va3MsIHByb3ZpZGUgdGhlIGNhdHMgY292ZXIuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGVyZSBpcyBvbmx5IG9uZSwgd2l0aCBhIHJlZ3VsYXIgZmVlZGluZyB0aW1lIGFuZCBwbGFjZS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgY2F0cyBhcmUgd2VsbCBmZWQgYW5kIGxhenksIG1vc3RseSBmb3Igc2hvdyB1bmxlc3MgcHJvdm9rZWQuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSHVudGluZyBTcGlkZXJzXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiQW5pbWFsIEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlc2UgbGlnaHRuaW5nLWZhc3QgbmlnaHRtYXJlcyBhcmUgYWJvdXQgdHdlbnR5IHBvdW5kcyBhbmQgdGhyZWUgZmVldCBhY3Jvc3MsIGJ1aWx0IGxpa2UganVtcGluZyBzcGlkZXJzIGFuZCBsb2FkZWQgd2l0aCBwYXJhbHl0aWMgdmVub20uXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2VyZSB0aGVzZSBzcGlkZXJzIGJyZWQgZm9yIGEgZGVjYWRlbnQgYXJpc3RvY3JhdCwgb3Igd2FycGVkIHRvIHRoaXMgaW1wb3NzaWJsZSBzaXplIGJ5IGFuIGluc2FuZSB3aGlzcGVyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkNhbiB0aGV5IHN1cnZpdmUgYXdheSBmcm9tIGEgc3Bpcml0IHdlbGw/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBub2lzZSBkbyB0aGV5IG1ha2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGRvIHRoZXkgc21lbGw/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSBtb3N0bHkgdHJhaW5lZCwgdGhlaXIgaGFuZGxlciB1c2luZyBhIHNsaWRlIHdoaXN0bGUgdG8gZ2l2ZSBvcmRlcnMgdG8gaHVudCwgYXR0YWNrLCB3aXRoZHJhdywgb3IgZ3VhcmQuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGNvbG9yIG9mIHRoZSBzdG9uZSwgdGhlIHNoYXBlIG9mIHRoZSB1bmRlcmJydXNoLCB0aGUgbGVhZiBsaXR0ZXItLWV2ZXJ5dGhpbmcgbWF0Y2hlcyB0aGUgc3BpZGVyIGNvbG9yIHNjaGVtZSBhbmQgaGlkZXMgaXRzIG1vdmVtZW50LlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiTGl0dGxlIGxhc3RpbmcgaGFybSBhdCBmaXJzdDsgcGFyYWx5emVkIHByZXkgaXMgZHJhZ2dlZCBiYWNrIHRvIGEgbGFpciBhbmQgd2ViYmVkIHVwLiBZb3UgaGF2ZSBhIGRheSBvciBzbyB0byByZXNjdWUgdGhlIHByZXkgYmVmb3JlIHRoZSBzcGlkZXIgaW5qZWN0cyBhY2lkIGludG8gdGhlIHdlYiBidW5kbGUgc28gaXQgY2FuIGRyaW5rIGl0cyB2aWN0aW0uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHBvaXNvbiBpcyB3ZWFrIGFuZCBlYXN5IHRvIHJlc2lzdCwgcmVxdWlyaW5nIHNldmVyYWwgc3VjY2Vzc2Z1bCBiaXRlcyB0byBwdXQgYSBodW1hbiBkb3duLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk1hc3RpZmYgUGFja1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkFuaW1hbCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkEgcGFjayBvZiBtYXN0aWZmcyBoYXZlIHJ1biBvZiB0aGUgZ3VhcmRlZCBhcmVhIHdoZW4gaXQgaXMgbm90IGluIG1vcmUgcHVibGljIHVzZS4gVGhleSBvbmx5IHJlc3BvbmQgdG8gdGhlaXIgbWFzdGVycywgd2hvIGhhdmUgc3BlY2lhbCB0dW5pY3MsIHdoaXN0bGVzLCBhbmQgZ2xvdmVzLiBUaGV5IGtpbGwgYW55b25lIG9yIGFueXRoaW5nIGVsc2UuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBpcyB0aGVpciBoZXJhbGRyeT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgbWFueSBtYXN0aWZmcyBhcmUgaW4gdGhlIHBhY2s/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXkgdHJhaW5lZCB3ZWxsIGVub3VnaCB0byBpZ25vcmUgcG9pc29uZWQgbWVhdCBvciBsaXZlIGFuaW1hbCBkaXN0cmFjdGlvbnM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJFYWNoIG9uZSBpcyBwcmVjaW91cyB0byB0aGUgc2l0ZSBvd25lciwgd2hvIHdpbGwgdGlyZWxlc3NseSBzZWVrIHZlbmdlYW5jZSBpZiB0aGV5IGFyZSBodXJ0LlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBwYWNrIG1hc3RlcnMgYXJlIGVsaXRlIHZldGVyYW5zIHdpdGggZmlyZWFybXMgYW5kIGV4Y2VsbGVudCB0cmFja2luZyBhbmQgaHVudGluZyBza2lsbHMuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgZXF1aXBtZW50IGlzIHByb3Blcmx5IGluc3RhbGxlZCwgaXRzIHZ1bG5lcmFibGUgcGFydHMgYmVoaW5kIHRoZSBlbmVyZ3kgY3VydGFpbiwgZGlyZWN0bHkgZ3VhcmRpbmcgd2hhdCBuZWVkcyBwcm90ZWN0aW5nLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBsaWdodG5pbmcgd2FsbHMgYXR0cmFjdCBsb29zZSBzcGlyaXRzLCBpbnRydWRlcnMgbWF5IGFsc28gaGF2ZSB0byBjb250ZW5kIHdpdGggY29uZnVzZWQgZ2hvc3RzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlZlbm9tb3VzIFNuYWtlc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkFuaW1hbCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlZlbm9tb3VzIHNuYWtlcyBoYXZlIGxhaXJzIHByZXBhcmVkIGZvciB0aGVtIGluIHRoZSBndWFyZGVkIGFyZWEuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGZhc3QgYWN0aW5nIGlzIHRoZWlyIHZlbm9tP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkhvdyBhZ2dyZXNzaXZlIGFyZSB0aGV5P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIklzIHRoZWlyIGhpZGUgY2Ftb3VmbGFnZSBmb3IgaHVudGluZywgb3IgYnJpZ2h0IHRvIHdhcm4gYXdheSBwcmVkYXRvcnM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXJlIG9ubHkgYSBmZXcgYmlnIG9uZXMsIG9yIG1hbnkgc21hbGwgc25ha2VzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZSBzaXRlIGd1YXJkaWFucyBmZWVkIHRoZW0sIG9yIGNhbiB0aGV5IGZpbmQgZW5vdWdoIHZlcm1pbiBvbiB0aGVpciBvd24/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJLbmVlLWRlZXAgcGxhbnRzIGFuZCBlbGV2YXRpb24gc2hpZnRzIGludGVudGlvbmFsbHkgbWFrZSBpdCBkaWZmaWN1bHQgdG8gc2VlIHNuYWtlcy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJPdGhlciBndWFyZGlhbnMgaGF2ZSBhIHNpZGUgYnVzaW5lc3MgaW4gc2VsbGluZyB2ZW5vbSBhbmQgbWVhdCBhbmQgaGlkZXMuIFRoZXkgaGF2ZSB2ZW5vbSBibG93ZGFydHMgYW5kIHBvaXNvbmVkIGRhZ2dlcnMuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc25ha2VzIGRpc2xpa2UgYSBjZXJ0YWluIHdoaXN0bGUgdG9uZS4gTGV0IG91dCBhIGJsYXN0IG9jY2FzaW9uYWxseSBhbmQgdGhleSdsbCBzdGF5IGF3YXkuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQSBmb3JtZXIgZW1wbG95ZWUga25vd3MgaG93IGd1YXJkaWFucyBnb3QgYXJvdW5kIHRoZSBzaXRlIHdpdGggbWluaW1hbCByaXNrIG9mIHNuYWtlcy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJBcm1vciBIb3N0c1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkdob3N0bHkgR3VhcmRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJHdWFyZGlhbiBzcGlyaXRzIGFyZSBhYmxlIHRvIGluaGFiaXQgYSBjcnlzdGFsIG1lbGRlZCB0byBlYWNoIHN1aXQgb2YgYXJtb3IgaW4gYSBndWFyZGVkIGFyZWEuIFdoZW4gbWVsZGVkLCB0aGUgc3Bpcml0IGNhbiBjb250cm9sIHRoZSBhcm1vci4gU3Bpcml0cyB1c2UgdGhlIGFybW9yIHRvIGF0dGFjayBpbnRydWRlcnMuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2VyZSB0aGUgc3VpdHMgb2YgYXJtb3IgYnVpbHQgZm9yIHRoaXMgcHVycG9zZSwgb3IgcmV0cm9maXR0ZWQgYnkgYSBzcGlyaXQgdHJhZmZpY2tlcj9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIGd1YXJkaWFuIHNwaXJpdHMgbG95YWwsIG9yIHdlcmUgdGhleSBzdHJpcHBlZCBvZiB0aGVpciB3aWxsIGJ5IGEgcml0dWFsIG9yIG90aGVyIHBvd2VyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGUgc3VpdHMgdmlzaWJseSBwYXJhbm9ybWFsP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQSBzaW5nbGUgcG93ZXJmdWwgKHJlbGF0aXZlbHkgc2FuZSkgc3Bpcml0IGNhbiBmbGl0IGZyb20gYXJtb3IgdG8gYXJtb3IsIGJhY2tlZCB1cCBieSB0d28gc2xhdmUgc3Bpcml0cy4gVGhlIGd1YXJkaWFuIGNhbiBmb3JtIGFuIGVsZWN0cm9wbGFzbWljIGZhY2UgaW4gdGhlIGhlbG1ldCB0byBzbmVlciBhdCBpbnRydWRlcnMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQSBzd2FybSBvZiBzcGlyaXRzIGFyZSBlYWdlciB0byB0YWtlIHRoZWlyIHR1cm4gaW4gYXJtb3IuIFdoZW4gb25lIHRpcmVzIGFub3RoZXIgZHJvcHMgaW4uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQ2Vhc2VsZXNzIHBhdHJvbC5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBnaG9zdChzKSB0aGF0IGFuaW1hdGUgdGhlIGFybW9yIGFyZSBtdXJkZXJvdXMgYW5kIGRpZmZpY3VsdCB0byBjb250cm9sLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBndWFyZGlhbnMgY2FuIHBsYXkgYSBjaGltZSB0byByZWNhbGwgdGhlbSB0byBhIHJlc3RyYWluaW5nIHByaXNtLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzdWl0cyBvZiBhcm1vciBhcmUgb2xkLCBiYXR0ZXJlZCwgYW5kIHByb25lIHRvIHBoeXNpY2FsIGZhaWx1cmUuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ29sZHJvb21zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiR2hvc3RseSBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSBkZWZlbmRlZCBhcmVhIGlzIGtlcHQgY29sZC4gQm9keSBoZWF0IHJlZ2lzdGVycyBsaWtlIGEgcGx1bWUgb2YgYmxvb2QgaW4gdGhlIHdhdGVyLiBHaG9zdHMgZmxvb2QgbGl2aW5nIG1lYXQgd2l0aCBjb2xkLCBnb3JnaW5nIG9uIGJvZHkgaGVhdCwgYmVjb21pbmcgbW9yZSB2aXNpYmxlIGFzIHRoZWlyIG91dGxpbmVzIHN3aXJsIHdpdGggbGlmZS1ibG9vZC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJXZXJlIHRoZXkgY3JlYXRlZCBieSByaXR1YWxseSBzdGFydmluZyB2aWN0aW1zIHRvIGRlYXRoIGluIHRoZSBkZWZlbmRlZCBzcGFjZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXZXJlIHRoZXkgc3RvbGVuIGZyb20gdGhlIHNpdGUgb2YgYSBtYXNzaXZlIGhvcnJpZmljIGRpc2FzdGVyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvZXMgYSBzcGlyaXQgdHJhZmZpY2tlciBtYWludGFpbiB0aGUgd2FyZHMgb24gdGhlIHNwYWNlP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQSBkZWFkIHdoaXNwZXIgbGVhZHMgdGhlbSwgY291bnRlcmluZyBkZWZlbnNpdmUgY2hhcm1zIGFuZCBtYWdpYywgc25pZmZpbmcgb3V0IGJyZWF0aCBldmVuIGlmIGhlYXQgaXMgY29uY2VhbGVkLCBkdWVsaW5nIGFueSBzdXBlcm5hdHVyYWwgZGVmZW5zZS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgZ3VhcmRlZCBhcmVhIGlzIHBvd2VyZnVsbHkgd2FyZGVkIGFuZCB1bmRlcmdyb3VuZCB3aGVyZSB0ZW1wZXJhdHVyZSBpcyBlYXN5IHRvIG1haW50YWluLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGd1YXJkZWQgYXJlYSBpcyB2dWxuZXJhYmxlIHRvIHdlYXRoZXIgY29uZGl0aW9ucy4gSXQgaXMgc2hhcnAgaW4gdGhlIGNvbGQsIGJ1dCBhbG1vc3QgZG9ybWFudCBpbiB0aGUgaGVhdC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBIHJlbGF0aXZlbHkgc2ltcGxlIHNwaXJpdCBiYW5lIGNoYXJtIGNhbiBrZWVwIHRoZW0gYXQgYmF5IGlmIGNyZWF0ZWQgaW4gdHVuZSB3aXRoIHRoZSBzaXRlLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkN1cnNlZCBUcmVhc3VyZVwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkdob3N0bHkgR3VhcmRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUcmVhc3VyZXMgYXJlIGluZnVzZWQgd2l0aCBhIGhhdW50aW5nIHNwaXJpdC4gQW55b25lIHRvdWNoaW5nIHRoZSB0cmVhc3VyZSB3aWxsIGJlIGN1cnNlZCwgZHJlYW1pbmcgdGhlIGNyaW1lcyBvZiB0aGUgZ2hvc3QgYW5kIGF0dHJhY3RpbmcgYW5nZXIgYW5kIGRpc3Rhc3RlIGZyb20gc3RyYW5nZXJzLiBGcmllbmRzIGJlY29tZSB1bmNvbWZvcnRhYmxlIGFuZCBzdXNwaWNpb3VzIGFyb3VuZCB0aGUgY3Vyc2VkIHNjb3VuZHJlbC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJXZXJlIHRob3NlIHNhY3JpZmljZWQgdG8gbWFrZSB0aGUgaGF1bnRzIGxveWFsLCBzZXJ2aW5nIHBhc3QgZGVhdGgsIG9yIHB1bmlzaGVkIGJ5IHVuZGVhdGg/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlIHRyZWFzdXJlIG1hcmtlZCBhcyBjdXJzZWQ/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgaGF1bnRpbmcgaXMgc28gZGVhZGx5IHRoYXQgaXQgZHJpdmVzIG1vc3QgdmljdGltcyB0byBzdWljaWRlIHdpdGhpbiBhIHdlZWsuIFJlc291cmNlZnVsIHNjb3VuZHJlbHMgd2l0aCBhY2Nlc3MgdG8gc3Bpcml0IHRyYWZmaWNrZXJzIGhhdmUgZGF5cyB0byBzb21laG93IGJyZWFrIHRoZSBob2xkLiBPdGhlcnMgYXJlIGRvb21lZC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJFbGVjdHJvcGxhc21pYyBwb2lzb25pbmcgYmVnaW5zLCBhbmQgd2l0aGluIGEgd2VlayB0aGUgc2NvdW5kcmVsIHdpbGwgYmVjb21lIGEgdmFtcGlyZS5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkFsbCB0aGUgYmFkIGx1Y2sgd2FpdGluZyBpbiB0aGUgd2luZ3MgKHVuZmluaXNoZWQgY2xvY2tzIGZyb20gZm9lcywgcG9vcmx5IHByb3RlY3RlZCBzdGFzaGVzLCBqaWx0ZWQgbG92ZXJzLCBmYWxzZSBpZGVudGl0aWVzKSBnbyB3cm9uZyBpbiBxdWljayBzdWNjZXNzaW9uLiBUaGVuIHRoZSBjdXJzZSBpcyBvdmVyLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkEgY29tcGV0ZW50IG9jY3VsdGlzdCBjYW4gYnJlYWsgdGhlIGN1cnNlIGFzIGEgZG93biB0aW1lIHByb2plY3Qgd2l0aCBhIGZvdXIgc2VnbWVudCBjbG9jay5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJEYXJrcm9vbXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJHaG9zdGx5IEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIGRlZmVuZGVkIGFyZWEgaXMgZGFyay4gVGhlIHJhZ2dlZCBnaG9zdHMgaGF0ZSBsaWdodC4gVGhleSBzaHJpZWsgaG9ycmlibHkgYXMgdGhleSBhdHRhY2sgbGlnaHQgc291cmNlcyB3aXRoIHNsYXBwaW5nIGxlYXRoZXJ5IGhhbmRzLCBsaWtlIGJhdCB3aW5ncy4gSW50cnVkZXJzIG1heSBnbGltcHNlIHRoZWlyIGx1bWlub3VzIGZhbmdzLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIldlcmUgdGhlc2UgZ2hvc3RzIHBsYWNlZCBoZXJlIGludGVudGlvbmFsbHksIG9yIGFyZSB0aGV5IHRoZSByZXN1bHQgb2Ygc29tZSBob3Jyb3IgdGhhdCBsZWZ0IGEgcHJpbnQgaW4gdGhlIEdob3N0IEZpZWxkP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIklzIHRoaXMgZGVmZW5zZSBtYWludGFpbmVkLCBvciBwYXNzaXZlP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQW5vdGhlciBndWFyZGlhbiBsdXJrcyBpbiB0aGUgZGFyayBhbmQgdGFrZXMgYWR2YW50YWdlIG9mIHRoZSBkaXN0cmFjdGlvbiB0byBzdGVhbCBmcm9tIGludHJ1ZGVycywgcGVyaGFwcyBraWxsaW5nIHRoZW0gdG9vLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBnaG9zdHMgYXJlIGFnZ3Jlc3NpdmUsIHB1c2hpbmcgaW50cnVkZXJzLiBTdXJyb3VuZGluZ3MgaW5jbHVkZSBsb25nIGRyb3BzLCBzcGlrZXMsIG1hemVzLCBvciBvdGhlciBoYXphcmRzIGRpZmZpY3VsdCB0byBuYXZpZ2F0ZSBpbiBkYXJrbmVzcy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIldoaWxlIGFubm95aW5nLCB0aGV5IGRvIG5vIHJlYWwgZGFtYWdlLCBhbmQgZm9yZXdhcm5lZCBzY291bmRyZWxzIG1heSBwcmVwYXJlIHVuYnJlYWthYmxlIGxpZ2h0IHNvdXJjZXMgb3Igc3VwZXJuYXR1cmFsIGRhcmsgdmlzaW9uLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZXJlIGlzIGVub3VnaCBhbWJpZW50IGxpZ2h0IHRvIHNlZS5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJEeW5hc3RpYyBIaXZlXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiR2hvc3RseSBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkFuY2VzdG9ycyBoYXZlIGJlZW4gcml0dWFsbHkgaW5mdXNlZCBpbnRvIHRoZSBkZWZlbnNlIHNpdGUsIGl0IGlzIGEgZHluYXN0aWMgaG9sZGluZy4gVGhlIHNwaXJpdHMgYXJlIG9sZCwgYW5kIGluc2FuZSwgYnV0IHN0cmF0ZWdpY2FsbHkgcGxhY2VkIHRvIGFjdCBvdXQgdGhlaXIgbWFkbmVzcyBpbiB0aGUgbW9zdCBkYW1hZ2luZyB3YXkuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiRGlkIHRoZSBmYW1pbHkgZ2V0IHNwZWNpYWwgcGVybWlzc2lvbiB0byBoYXJib3IgZ2hvc3RzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZXkgaGF2ZSBjb25uZWN0aW9ucyB0byBsaW1tZXJzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSBzcGlyaXRzIHRpZWQgdG8gbGV2aWF0aGFuIGJvbmUgc2hhcmRzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IG1vdmluZyBwaWN0dXJlcywgb3IgY29udmVyc2F0aW9uYWxpc3RzIHdpdGggY2x1ZXM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgZ2hvc3RzIGFyZSBsZWdhbGx5IHByb3RlY3RlZCwgbGlrZSBsYW5kbWFya3Mgb3IgYXJ0d29yay4gRGFtYWdpbmcgdGhlbSBpcyBhIHNlcmlvdXMgY3JpbWUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiU29tZSBvZiB0aGUgbW9yZSBwb3dlcmZ1bCBvciBjYW5ueSBnaG9zdHMgYXJlIHN0aWxsIHNvbWV3aGF0IHNhbmUgY29sbGFib3JhdG9ycyB3aXRoIHRoZSBzaXRlIG93bmVycy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZXkgYXJlIG91dCBvZiBjb250cm9sLCBhbmQgZmV3IGRhcmUgdG8gZW50ZXIgdGhlIHNpdGUgbm93IChvciBpdCBpcyBhYmFuZG9uZWQuKVwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZXkgd2lsbCBub3QgaGFybSBmYW1pbHkgbWVtYmVycyAoYnV0IG1heSBub3QgcmVhY3Qgd2VsbCB0byBob3N0YWdlcy4pXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSHVudGluZyBHaG9zdHBhY2tcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJHaG9zdGx5IEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiQSBncm91cCBvZiB3ZWFwb25pemVkIGdob3N0cyBoYXVudHMgdGhlIGRlZmVuZGVkIGFyZWEuIFRoZXkgYXJlIGNhcGFibGUgb2Ygc2NvdXRpbmcgdG8gZmluZCBpbnRydWRlcnMsIGRlc2NlbmRpbmcgb24gdGhlbSB3aXRoIGxldGhhbCBmb3JjZS5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IGFwcGVhciBhcyBhIHBhY2sgd2l0aCBhIG1vdW50ZWQgaHVudGVyLCBzcGVjdHJhbCBob3VuZHMsIGFuZCBhIGdob3N0bHkgaG9ybiBjYWxsP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIk9yIGFuIGFybW9yZWQgd2FyYmFuZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJTaGFwZWxlc3MgbGV0aGFsIGVsZWN0cm9wbGFzbWljIHN0YWxrZXJzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGUgd291bmRzIHRoZXkgaW5mbGljdCBibG9vZHkgY3V0cywgb3IgaGFyZCBmcm9zdGJpdGU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlaXIgYXJlYSBzdXJyb3VuZGVkIHdpdGggcnVuZXMgdGhhdCBsZXQgdGhlbSBzZWUgaW50byB0aGUgbWF0ZXJpYWwgd29ybGQ/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgZ2hvc3QgbGVhZGVyIGZlZWxzIGFsbCBsaWZlIGZvcmNlIGluIGl0cyBodW50aW5nIGdyb3VuZCwga25vd2luZyBpdHMgbG9jYXRpb24uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGh1bnQgY2FuIG9ubHkgcmlzZSB3aGVuIGNlcnRhaW4gY29uZGl0aW9ucyBsaWtlIGFubml2ZXJzYXJpZXMsIG1vb24gcGhhc2VzLCBldGMuIGFyZSBtZXQuIEhvd2V2ZXIsIHRoZXkgaGF2ZSBhIHRyZWFzdXJlIHRoYXQgY2FuIG9ubHkgYmUgdGFrZW4gZnJvbSB0aGVtIHdoZW4gdGhleSBtYW5pZmVzdC5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBhdHRhY2sgaXMgcHVyZWx5IHBzeWNob2xvZ2ljYWwsIGtpbGxpbmcgd2l0aCBzdXBlcm5hdHVyYWwgZmVhci4gVGhlIGVmZmVjdCBjYW4gYmUgcmVzaXN0ZWQuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgc3VtbW9uZWQgYW5kIGRpcmVjdGVkIGJ5IGEgY29tbWFuZCBhcnRpZmFjdCBsaWtlIGEgaHVudGluZyBob3JuIG9yIHNwZWNpYWwgd2VhcG9uLiBJZiBzb21lb25lIGVsc2UgdHVuZXMgdG8gdGhlIHdlYXBvbiwgY29udHJvbCAoYW5kIGl0cyBvYmxpZ2F0aW9ucykgbWF5IHNoaWZ0IHRvIGEgbmV3IGJlYXJlci5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJQb3NzZXNzaW9uIEdhdGVcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJHaG9zdGx5IEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiSWYgYW4gaW50cnVkZXIgYnJlYWtzIGEgY2xlYXJseSBtYXJrZWQgc2VhbCwgdGhlIGludHJ1ZGVyIGlzIGF0dGFja2VkIGJ5IGEgcG9zc2Vzc2luZyBzcGlyaXQgdGhhdCB0YWtlcyBvbiB0aGUgdHJhaXRzIG9mIHRoZSBtb3N0IHN0cm9uZy13aWxsZWQsIGJydXRhbCBwZXJzb24gdGhlIHNlYWwtYnJlYWtlciBldmVyIGtpbGxlZC4gVGhlIHBvc3Nlc3Npbmcgc3Bpcml0IGFuZCB0aGUgc2VhbC1icmVha2VyIHN0cnVnZ2xlIGZvciBjb250cm9sLiBUaGlzIGNvdW50cyBhcyBhIGhhcm0uXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlIHBvc3Nlc3Npbmcgc3Bpcml0IGEgZ2hvc3QsIG9yIGEgc2hhcGUtc2hpZnRpbmcgY29uc3RydWN0IG1hZGUgYnkgYW4gZXhwZXJ0IHRoYXQgbWFrZXMgYSBzaGFwZSBvdXQgb2Ygc29tZXRoaW5nIGluIHRoZSB0YXJnZXQ/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSWYgYW4gaW5ub2NlbnQgdHJpZ2dlcnMgdGhlIHRyYXAsIHdoYXQgZm9ybSBkb2VzIHRoZSBzcGlyaXQgdGFrZSB0aGVuP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIG9ubHkgd2F5IHRvIGJlIGZyZWUgaXMgdG8gZGllLCB1bmRlcmdvIGVsZWN0cm9wbGFzbWljIHN1cmdlcnkgd2hpbGUgZGVhZCwgYW5kIGJlIHJldml2ZWQuIE90aGVyd2lzZSB0aGUgY3Vyc2UgaXMgcHJvdGVjdGVkIGJ5IHRoZSB2aWN0aW0ncyBsaWZlIGZvcmNlLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBoYXVudGluZyBzcGlyaXQgdHJpZXMgdG8gdGFrZSBwb3NzZXNzaW9uIG9uY2UgYSBkYXkgb3Igc28sIHNlbmRpbmcgdGhlIGhvc3QgaW50byBhIGJsYWNrb3V0IGFuZCBhY3Rpbmcgb3V0IHZpY2lvdXMgY3JpbWVzIGFnYWluc3QgYWxsaWVzLCBsb3ZlZCBvbmVzLCBhbmQgYmx1ZWNvYXRzLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGNvbmRpdGlvbiBjYW4gYmUgcmVkdWNlZCB3aXRoIGEgcmVzaXN0IHJvbGwsIGJ1dCBzdGlsbCBpcyBsaWtlbHkgYSA2IHNlZ21lbnQgY2xvY2sgdG8gY2xlYXIuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGN1cnNlIGhhdW50IHdvdWxkIHJhdGhlciBoYXZlIGEgaG9zdCBhbGx5IHRoYW4ga2lsbCBpdHMgdmljdGltLCBhbmQgbWF5IGJhcmdhaW4gZm9yIHNoYXJlZCBjb250cm9sLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNwaXJpdC1JbmZ1c2VkIEFydFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkdob3N0bHkgR3VhcmRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJBcnQgd29ya3MgYXJlIGhhdW50ZWQgYnkgc3Bpcml0cyB0aGF0IGFyZSBjYXBhYmxlIG9mIHNweWluZy4gVGhleSBvYnNlcnZlIHRoZWlyIGFyZWEsIGFuZCBtYXkgYmUgYWJsZSB0byBtdXJtdXIgYWJvdXQgd2hhdCB0aGV5IHNlZSB0byBhIGd1YXJkaWFuLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIldhcyBhcnQgcmVwdXJwb3NlZCB0byBob3N0IHNwaXJpdHMsIG9yIHdhcyBpdCBjcmVhdGVkIGZvciB0aGVtIGFuZCBhcm91bmQgdGhlbT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJJcyB0aGUgYXJ0IG1vc2FpY3MsIHBvcnRyYWl0cywgc3RhdHVlcywgb3Igc29tZSBvdGhlciBmb3JtP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkhvdyBzYW5lIGFuZCBjb2hlcmVudCBhcmUgdGhlIHNwaXJpdHM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGxveWFsIGFyZSB0aGV5P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZXkgaGF2ZSB0aGUgcG93ZXIgdG8gYXR0YWNrIGludHJ1ZGVycz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk9uZSBvciBtb3JlIGd1YXJkaWFucyBoYXMgYSBzaWduZXQgcmluZyB0dW5lZCB0byB0aGUgaGF1bnRlZCBhcnQgcGllY2VzLCBhbmQgY2FuIGhlYXIgd2hhdCB0aGV5IHdoaXNwZXIgYXMgdGhleSBzcHkuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGdob3N0cyBpbmhhYml0aW5nIHRoZSBhcnQgY2FuIG1vdmUgZnJvbSBvbmUgcGllY2UgdG8gYW5vdGhlciwgZm9sbG93aW5nIGludHJ1ZGVycyBvciByZXRyZWF0aW5nIHRvIHJlcG9ydC5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk9uZSBzcGlyaXQgcGVyIGFydCBwaWVjZSwgYW5kIGVhY2ggc3Bpcml0IGhhcyBpdHMgb3duIHVuYmFsYW5jZWQgcGVyc29uYWxpdHkuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVW5oaW5nZWQgYXJ0IGlzIHZpb2xlbnQsIHNvIGl0IGhhcyB0byBiZSBzaHJvdWRlZCBvciByZXN0cmFpbmVkIHdoZW4gZ3VhcmRpYW5zIGdvIHRocm91Z2ggdGhlIGRlZmVuZGVkIGFyZWEuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU3RhcnZpbmcgRm9nXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiR2hvc3RseSBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSBndWFyZGVkIGFyZWEgaXMgaW4gYSBjbGluZ2luZyBjb2xkIGZvZy4gRm9nIGRyYXdzIGVuZXJneSBmcm9tIHRob3NlIGJyZWF0aGluZyBpbiBpdCB1bnRpbCBpdCBtYW5pZmVzdHMgc2hhZG93cyB0aGF0IGluY3JlYXNlIHRhcmdldCBmZWFyLCB3aGljaCBmZWVkcyBpdCBtb3JlLiBFdmVudHVhbGx5IGl0IGNhbiBtYW5pZmVzdCBhIGtpbGxpbmcgc2hhcGUuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBkbyBpbnRydWRlcnMgaW4gdGhlIGZvZyBzZWUgd2hlbiBpdCByZWZsZWN0cyB0aGVpciBmZWFycz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlcmUgc291bmQgZWZmZWN0cywgc21lbGxzLCBhbmQgc291bmRzLCBvciBqdXN0IGZsZWV0aW5nIGdsaW1wc2VzIGFuZCBzaWxob3VldHRlcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIGl0IHByb2plY3QgaGFsbHVjaW5hdGlvbnMgb3IgdHJpZ2dlciBtZW1vcmllcz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBmb2cgc3RyZW5ndGhlbnMgdGhlIEdob3N0IEZpZWxkLCBtYWtpbmcgZ2hvc3RzIHdpdGhpbiBpdCBtb3JlIHBvd2VyZnVsLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBmb2cgY2FuIG1vdmUsIHN1bW1vbmVkIG9yIGNvbnRyb2xsZWQgYnkgb3RoZXIgZ3VhcmRpYW5zIHRvIHByb3ZpZGUgYmFja3VwIG9yIGhlbHAgc2VhcmNoLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGZvZyBpcyBnZW5lcmF0ZWQgYnkgYW4gYXJ0aWZhY3QuIElmIHRoZSBhcnRpZmFjdCBpcyBuZXV0cmFsaXplZCBzbyBpcyB0aGUgZm9nLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRob3NlIHdpdGggdGhlIHByb3BlciBlbmVyZ3kga2V5ZWQgYW11bGV0IG9yIG90aGVyIHRyaW5rZXQgYXJlIGludmlzaWJsZSB0byB0aGUgZm9nLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlN3ZWF0IE5lY3RhclwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkdob3N0bHkgR3VhcmRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgZGVmZW5kZWQgYXJlYSBpcyBrZXB0IGhvdC4gU3dlYXQgdGFzdGVzIGxpa2UgbmVjdGFyIHRvIHN3YXJtaW5nIGdob3N0cywgd2hvIGRlaHlkcmF0ZSB0YXJnZXRzIGludG8gbXVtbWllcy4gVGhlIHN0b2xlbiBsaWZlIGZvcmNlIGFuZCBtb2lzdHVyZSBmbG93cyB0byBwcmVwYXJlZCBjb3Jwc2VzLCBzbyBnaG9zdHMgY2FuIHJpZGUgdGhlbSBhZ2Fpbi5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJXZXJlIHRoZXkgY3JlYXRlZCBieSBkZWh5ZHJhdGluZyBzYWNyaWZpY2VzIHRvIGRlYXRoIGluIHRoZSBkZWZlbmRlZCBzcGFjZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXZXJlIHRoZXkgZ2F0aGVyZWQgZnJvbSBvdXRzaWRlIHRoZSBsaWdodG5pbmcgd2FsbHMgdG8gc3RhbmQgZ3VhcmQgaGVyZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIGEgc3Bpcml0IHRyYWZmaWNrZXIgbWFpbnRhaW4gdGhlIHdhcmRzIG9uIHRoZSBzcGFjZT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk1hbnkgcHJlcGFyZWQgY29ycHNlcyBhcmUgc3Rhc2hlZCBpbiB1bmV4cGVjdGVkIHBsYWNlcywgYnVyc3RpbmcgaW50byBjb21iYXQgd2hlbiByZWp1dmVuYXRlZC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJPbmNlIHRoZXkgcmlzZSwgdGhlIGRlc2ljY2F0ZWQgc3Bpcml0LXJpZGRlbiBjb3Jwc2VzIHdpbGwgY2hhc2UgaW50cnVkZXJzIHVudGlsIHRoZXkgY2FuJ3QuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJPbmx5IGEgZmV3IGNvcnBzZXMgYXJlIGxlZnQgdG8gcmV2aXZlLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzaXRlIGlzIGRpZmZpY3VsdCB0byBrZWVwIGhvdCBlbm91Z2ggdG8gZXh0cmFjdCB0aGUgbmVjZXNzYXJ5IHN3ZWF0IGZyb20gaW50cnVkZXJzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkRhcnR1cyBXZWVkXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiV2hlbiBzb21ldGhpbmcgbW92ZXMgbmVhciBhIHRhbmdsZWQgYmFuayBvZiBkYXJ0dXMgd2VlZCwgdGhlIHZpbmVzIGZsZXgsIGZsaWNraW5nIGJhcmJlZCB0aXBzIHRvd2FyZHMgdGhlIHNvdXJjZSBvZiBtb3Rpb24gd2l0aGluIGFybSdzIHJlYWNoLiBUaGUgZGFydHMgYXJlIHBhcmFseXRpYzsgYSB0YXJnZXQgd2lsbCBwYXNzIG91dCBmb3IgYWJvdXQgYW4gaG91ci5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IGhhdmUgYSBkaXN0aW5jdGl2ZSBmbG93ZXIgb3Igc21lbGw/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBpcyB0aGUgYWZ0ZXJ0YXN0ZSBvZiB0aGUgcG9pc29uJ3MgZWZmZWN0P1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSG91bmRzIHdpdGggY2hlbWljYWxseSB0b3VnaGVuZWQgaGlkZXMgcGF0cm9sIHRoZSB3ZWVkIGJhbmtzLCBicnV0YWxseSBraWxsaW5nIGludHJ1ZGVycy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXZWVkIGJhbmtzIGFyZSBjdWx0aXZhdGVkIHN0cmF0ZWdpY2FsbHksIGZsYW5raW5nIGltcG9ydGFudCBkb29yd2F5cyBvciBkcmFwZWQgb3ZlciBhcmJvcndhbGtzLCBzdHJhZ2dsaW5nIGFsb25nIHZlcmdlcy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSB3ZWVkcyBhcmUgeW91bmcuIERhcnRzIGNhbiBiZSBzdG9wcGVkIHdpdGggdGhpY2sgbGVhdGhlci5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXZWVkIGJhbmtzIGFyZSBvdXQgb2YgdGhlIHdheSBvZiBkZWZlbmRlZCB2YWx1YWJsZXMsIGJ1dCB0b28gY2xvc2UgdG8gdmVyeSBhbm5veWVkIG5laWdoYm9ycyB3aG8gbWF5IGhvbGQgYSBncnVkZ2UuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRHJlYW1zcG9yZSBTaHJvb21zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiUGxhY2VkIG9uIHRoZSBjZWlsaW5nLCB0aGV5IGRyaXp6bGUgc2FuZHkgc3BvcmVzIHdoZW4gdGhleSBzZW5zZSBtb3Rpb24gYmVsb3cuIFZpY3RpbXMgaGFsbHVjaW5hdGUsIGhlaWdodGVuaW5nIHN1YmNvbnNjaW91cyBlbW90aW9uIChzbyB0aGV5IGFyZSB2ZXJ5IG1lbGxvdywgb3Igc3VwZXIgYW54aW91cywgb3IgZmlsbGVkIHdpdGggcmFnZSwgZXRjLikuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2VyZSB0aGVzZSBpbnRlbmRlZCB0byBiZSBhIHNpdGUgZGVmZW5zZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEaWQgdGhleSBpbnN0ZWFkIHNlcnZlIGEgcmVsaWdpb3VzIG9yIHJlY3JlYXRpb25hbCBmdW5jdGlvbj9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlcmUgc3BlY2lhbCB0ZWNobmlxdWVzIGZvciBoYXJ2ZXN0aW5nIHRoZW0sIHBlcmhhcHMgc2VsbGluZyB0aGVtIHRvIGFsY2hlbWlzdHM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBIG1vcmUgaW50ZW5zZSBzdHJhaW4sIHRoZXNlIGNhbiBrbm9jayBvdXQgdGhvc2Ugd2hvIHN1Y2N1bWIsIGFuZCBnaXZlIHRoZW0gdml2aWQgZHJlYW1zIGZvciBzZXZlcmFsIGhvdXJzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZXkgYXJlIHBsYWNlZCBuZWFyIG90aGVyIGd1YXJkaWFucyBhcyB3ZWxsIGFzIGhhemFyZHMgbGlrZSBhIHN0ZWVwIGRyb3Agb3IgcnVubmluZyB3YXRlci5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk90aGVyIGd1YXJkaWFucyBjb21lIGhlcmUgcmVjcmVhdGlvbmFsbHksIHRoZWlyIGVmZmVjdGl2ZW5lc3MgcmVkdWNlZC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc3BvcmVzIGFyZSB3ZWFrIGFuZCBlYXNpZXIgdG8gcmVzaXN0LlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkZsb29ybWVzaFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlN1cGVybmF0dXJhbCBQbGFudHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkZsYXQgdmluZXMgZ3JvdyB0b2dldGhlciB0byBtYWtlIGZsb29yaW5nLiBDb25uZWN0ZWQgYmVsb3cgaXMgdGhlIGJ1bGIsIGNvdmVyZWQgaW4gdmVub21vdXMgc3Bpa2VzLiBBbnlvbmUgaGVhdmllciB0aGFuIGEgY2hpbGQgd2lsbCBmYWxsIHRocm91Z2guIEJsb29kIGFuZCByb3QgZmVlZCB0aGUgZmxvb3JtZXNoLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkhhdmUgc2l0ZSBkZWZlbmRlcnMgcHV0IGNhcnBldCBvdmVyIHRoZSBmbGF0IHZpbmVzIHRvIGZ1cnRoZXIgaGlkZSB0aGUgdGhyZWF0P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgY29sb3JzLCB0ZXh0dXJlcywgYW5kIHBhdHRlcm5zIGRvZXMgdGhpcyB2ZXJzaW9uIGhhdmU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGRhbmdlcm91cyBpcyB0aGUgdmVub20/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgYnVpbGRpbmcncyBhcmNoaXRlY3R1cmUgYXNzdW1lcyB1c2Ugb2YgZmxvb3JtZXNoLCB0aGUgY2FycGV0cyBhcmUgd292ZW4gdG8gbG9vayBsaWtlIGZsb29ybWVzaCBzbyB0aGUgZ3VhcmRpYW5zIGRvbid0IGhhdmUgdG8gY292ZXIgdGhlIGFjdHVhbCBwaXRzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBtZXNoIGl0c2VsZiBoYXMgdmVub21vdXMgdGhvcm5zIGluIGl0LCBzbyBzdGVwcGluZyBvbiBpdCBvciBmYWxsaW5nIHRocm91Z2ggcG9pc29ucyB0aGUgdGFyZ2V0LlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHBpdCBpcyBub3QgY2xlYW5lZCwgdGhlIGFyZWEgbmVhciBpdCBzdGlua3MgaGVhdmlseSBvZiBjb3Jwc2Vyb3QuIFRoZSBtZXNoIHNhZ3MgdmlzaWJseS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJGbG9vcm1lc2ggaXMgbW9zdGx5IGh1bmcgbGlrZSB0YXBlc3RyaWVzLCBsaXZpbmcgZGVjb3JhdGlvbnMsIHJhdGhlciB0aGFuIGZvcm1pbmcgcGl0IHRyYXBzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkdob3N0IENyeXN0YWwgVG9waWFyeVwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlN1cGVybmF0dXJhbCBQbGFudHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkdob3N0IGNyeXN0YWxzIGFyZSB3b3JrZWQgaW50byB0aGUgcm9vdHMgb2YgZmFuY2lmdWxseSB0cmltbWVkIGJ1c2hlcy4gR2hvc3RzIG1heSBiZSBhYmxlIHRvIGluaGFiaXQgdGhlIGJ1c2hlcyBhbmQgbWFrZSB0aGVtIG1vdmUuIFRoaXMgZ2FyZGVuaW5nIGN1cmlvc2l0eSBjYW4gYmUgd2VhcG9uaXplZC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJJcyB0aGlzIGEgY3VycmVudGx5IG1haW50YWluZWQgZ2FyZGVuLCBvciBvbmUgdGhhdCBpcyBvdmVyZ3Jvd24gYW5kIGFiYW5kb25lZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXaG8gcHJvdmlkZXMgdGhlIG5lY2Vzc2FyeSBza2lsbGVkIGNhcmUgdG8gY3JlYXRlIG9yIG1haW50YWluIHRoZSB0b3BpYXJ5P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIklzIHRoZXJlIGEgdGhlbWUgdG8gdGhlIHNjdWxwdHVyZXM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJDZXJ0YWluIG9mIHRoZSBtb3N0IHBvd2VyZnVsIGJ1c2hlcyBjYW4gdXByb290IGFuZCBtb3ZlIGFyb3VuZCBsaWtlIGxpdmluZyBncmVlbiBnb2xlbXMgZHJpdmVuIGJ5IGVsZWN0cm9wbGFzbWljIGVuZXJneS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgYnVzaGVzIGhhcmRseSBtb3ZlLCBidXQgdGhlIHBvd2VyZnVsIGVuZXJnaWVzIG9mIHRoZSBjcnlzdGFscyBtYWtlIGdob3N0cyBtdWNoIG1vcmUgY29oZXJlbnQgYW5kIHBvd2VyZnVsIGluIHRoZSBnYXJkZW4uXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJMZWZ0IHVucHJvdGVjdGVkIGF0IG9uZSBwb2ludCwgdGhlIGdhcmRlbiB3YXMgcmFpZGVkIGJ5IHRoaWV2ZXMgYWZ0ZXIgdGhlIGdob3N0IGNyeXN0YWxzLiBGZXcgY3J5c3RhbHMgYXJlIGxlZnQgaW4gdGhlIHNoYWdneSBidXNoZXMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSW5jb21wZXRlbnQgaGFuZGxpbmcgaGFzIGRyYWluZWQgbW9zdCBvZiB0aGUgcG93ZXIgZnJvbSB0aGUgY3J5c3RhbHMuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiS2VlbnNocm9vbXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJTdXBlcm5hdHVyYWwgUGxhbnRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGVzZSBmaXN0LXNpemVkIG11c2hyb29tcyBsZXQgb3V0IGEga2VlbmluZyB3YWlsIHdoZW4gbGlnaHQgY29tZXMgd2l0aGluIGFib3V0IHRoaXJ0eSBmZWV0LlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhleSBsb29rIGxpa2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlaXIgc21lbGwgZGlzdGluY3RpdmU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXkgZ29vZCBlYXRpbmc/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSBzdHJhdGVnaWNhbGx5IHBsYWNlZCB0byBzdXJwcmlzZSBpbnRydWRlcnM7IGluc2lkZSBkb29ycywgb24gY2VpbGluZ3MsIGluIGFsY292ZXMsIGJlaGluZCBzdGF0dWVzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIk1hc3NlcyBvZiBrZWVuc2hyb29tcyBoYXZlIGJlZW4gYWxsb3dlZCB0byBjb2F0IHdhbGxzIG9yIGZpbGwgcm9vbXMsIGFuZCB0aGVpciBrZWVuIGlzIHN0cm9uZyBlbm91Z2ggdG8gZGVhZmVuIG9yIGtpbGwuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUga2VlbnNocm9vbXMgd2VyZSBwbGFjZWQgdG9vIGNsb3NlIHRvIHRyYWZmaWNrZWQgcGF0aHMgaW5zaWRlIG9yIG91dHNpZGUgdGhlIGRlZmVuZGVkIHNpdGUuIENvbnN0YW50IGZhbHNlIGFsYXJtcyBkdWxsIHZpZ2lsYW5jZS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUb28gZmFyIGZyb20gc2l0ZSBkZWZlbmRlcnMsIHRoZWlyIGtlZW5zIGFyZSBzZWxkb20gaW52ZXN0aWdhdGVkLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk11cmRlciBUcmVlXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIHdpbGxvdyB0cmVlIGdyZXcgYXJvdW5kIGJvbmVzIHdpcmVkIHRvIGl0LCBzcGlyaXQgY3J5c3RhbHMgc3R1ZGRlZCBpbiBpdHMgYmFyaywgYW5kIGxldmlhdGhhbiBibG9vZCBhdCBpdHMgcm9vdHMuIGx0IGlzIGRpbWx5IHNlbGYtYXdhcmUuIEl0IHNlbnNlcyBhbmQgaGF0ZXMgbGlmZSwgd2hpcHBpbmcgYW5kIGNsdWJiaW5nIGFueSB3aG8gYXBwcm9hY2guXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGRvIGd1YXJkaWFucyBtb3ZlIGFyb3VuZCB0aGUgdHJlZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJTdWdnZXN0aW9ucyBpbmNsdWRlIGtub3dpbmcgcGFzc3dvcmRzLCBoYXZpbmcgZW5jaGFudGVkIGFtdWxldHMsIG9yIGF0dHVuaW5nIHRvIGl0cyBibGluZCBzcG90cy4gSG93IG1hbnkgZ3VhcmQgdGhlIHNpdGU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hvIGhhZCB0aGUgZXhwZXJ0aXNlIHRvIGN1bHRpdmF0ZSB0aGlzIGxpdmluZyB3ZWFwb24sIGhvdyBsb25nIGFnbz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBjaG9ydXMgb2Ygc2VtaS1hd2FyZSBzcGlyaXRzIHRoYXQgZnVlbCB0aGUgdHJlZSBhcmUgZW5zbGF2ZWQgYnkgb25lIGRvbWluZWVyaW5nIHdpbGwuIFRoZSB0cmVlIGlzIGFzIGNvaGVyZW50IGFzIGEgcGVyc29uLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIk11bHRpcGxlIG11cmRlciB0cmVlcyBhcmUgY29ubmVjdGVkIGJ5IHJvb3RzIGFuZCBzaGFyZSBrbm93bGVkZ2Ugd2l0aCBlYWNoIG90aGVyIChhbmQgYW55IG90aGVyIHNpdGUgZ3VhcmRpYW5zLilcIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk5vIG9uZSBjYW4gY29tbXVuaWNhdGUgd2l0aCB0aGUgbXVyZGVyIHRyZWUsIG9yIGNvbnRyb2wgaXQsIHNvIGl0IGlzIGlzb2xhdGVkIGZyb20gb3RoZXIgZGVmZW5zZXMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHRyZWUgc2xlZXBzIG1vc3Qgb2YgdGhlIHRpbWUsIGFuZCBpdCBpcyBkaWZmaWN1bHQgdG8gcm91c2UgaXQgdG8gZmlnaHRpbmcgZnVyeS5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTbmF0Y2h3ZWVkXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiSXQgZ3Jvd3MgaW4gZnJlc2ggd2F0ZXIsIGxlbmd0aGVuaW5nIGl0cyBsb25nIHdpbmRpbmcgdGVuZHJpbHMgYWxtb3N0IHRvIHRoZSBzdXJmYWNlLiBXaGVuIHRvdWNoZWQsIGl0IHNuYXRjaGVzIGFuZCBwdWxscywgY29pbGluZyBkb3duIHRvIHRoZSBib3R0b20gYW5kIGhvbGRpbmcgZm9yIGEgZmV3IG1pbnV0ZXMgYmVmb3JlIHJlbGF4aW5nIGJhY2sgdXAuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlaXIgZ3Jvd3RoIGJvb3N0ZWQgc3VwZXJuYXR1cmFsbHksIGFuZCBjYW4geW91IHNlZSBmYWNlcyByZWZsZWN0aW5nIGZyb20gdGhlIEdob3N0IEZpZWxkIGJlbmVhdGggdGhlaXIgZnJvbmRzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGUgbG9jYWxzIGF3YXJlIG9mIHRoZSB0aHJlYXQsIHdpbGxpbmcgdG8gdGFsayBhYm91dCBpdD9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlNuYXRjaHdlZWQgaXMgY3VsdGl2YXRlZCBpbiBhcmVhcyB3aGVyZSBpbnRydWRlcnMgbXVzdCBlbnRlciB0aGUgd2F0ZXIgdG8gZ2V0IHBhc3Qgb3RoZXIgb2JzdGFjbGVzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBib3R0b20gb2YgdGhlIHdhdGVyIGhhcyB0d28gZm9vdCBzcGlrZXMsIHZpY3RpbXMgYXJlIHB1bGxlZCBkb3duIG9udG8gdGhlbS5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkEgc2lnbiB3YXJucyBvZiB0aGUgaGF6YXJkLCBhcyByZXF1aXJlZCBieSBsYXcuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhpcyBwYXJ0aWN1bGFyIGJyZWVkIG9mIHNuYXRjaHdlZWQgcmVjb2lscyBmcm9tIHNhbHQ7IHB1dCBlbm91Z2ggb24gdGhlIHN1cmZhY2UgYW5kIHRlbmRyaWxzIHJlY29pbC5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUaGlyc3RjbGltYmVyXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIHZpbmVzIGFyZSByZWQsIGFuZCB3aGVuIGZsZXNoIHRvdWNoZXMgdGhlbSAoZXZlbiB0aHJvdWdoIGxlYXRoZXIpIHRoZSB2aW5lIGRyYXdzIGJsb29kIHRvIHRoZSBzdXJmYWNlIGluIGFsYXJtaW5nIHF1YW50aXRpZXMuIFRoZSB2aW5lcyBhcmUgc2xpcHBlcnksIGFuZCBhbG1vc3QgaW1wb3NzaWJsZSB0byBncmFzcCB3aXRoIHdldCBoYW5kcy5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIHZpbmVzIGNsZWFybHkgdmlzaWJsZSB0byB0aG9zZSB3aG8gY2FuIHNlZSBpbiB0aGUgR2hvc3QgRmllbGQ/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiRG8gdGhlIHZpbmVzIGNhdXNlIGRhbWFnZSB0aGF0IG11c3QgYmUgaGVhbGVkLCBvciBkb2VzIHRoZSBibG9vZCBvbmx5IGZsb3cgd2hlbiB0aGV5IGFyZSBuZWFyYnk/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc2l0ZSBoYXMgZ3VhcmQgY3JlYXR1cmVzIHRoYXQgdHJhY2sgYnkgc2NlbnQgYW5kIGFyZSBkcmF3biB0byBhdHRhY2sgdGhpbmdzIHRoYXQgc21lbGwgYmxvb2R5LlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoaXJzdGNsaW1iZXIgaXMgY3VsdGl2YXRlZCBhdCB0aGUgbWlkLXBvaW50IG9mIGEgcmVhbGx5IGRpZmZpY3VsdCBjbGltYi5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkFubm95ZWQgbG9jYWxzIGtlZXAgaXQgdHJpbW1lZCBiYWNrIG9uIG91dHNpZGUgd2FsbHMgcGVyaW9kaWNhbGx5IGluIHNwaXRlIG9mIHRoZSBndWFyZGlhbidzIHRocmVhdHMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiR3VhcmRzIGtub3cgdGhlIGluZ3JlZGllbnRzIHRvIG1ha2UgYSBzcGVjaWFsIHBhc3RlLCBhbmQgdGhlIHN5bWJvbCB0byBwYWludCBvbiBza2luIHdpdGggaXQsIHRvIHByb3RlY3QgZnJvbSB0aGUgcGxhbnQncyBlZmZlY3RzLiBBIGZvcm1lciBndWFyZCBtaWdodCBzaGFyZSB0aGUgc2VjcmV0LlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlRoaXJzdHkgVGhvcm5zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiU3RyYXRlZ2ljYWxseSBwbGFjZWQgdGhvcm5idXNoZXMgZ3JvdyBvbiB3YWxscyBhbmQgc2VydmUgYXMgZGVjb3JhdGlvbnMuIFRoZXkgbGl2ZSBvbiBibG9vZC4gVGhleSBvbmx5IGZsb3dlciBpZiBzb21ldGhpbmcgZGllcyBvbiB0aGVtOyB0aGUgYmlnZ2VyIHRoZSBsaWZlLCB0aGUgbW9yZSBpbXByZXNzaXZlIHRoZSBibG9vbS5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IGZlZWQgb24gcmFkaWFudCBsaWdodD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhleSBhbG9uZyB0aGUgaW50ZXJpb3Igd2FsbHMsIGxpbmluZyB0aGUgd2Fsa3MsIGFuZCBjbGltYmluZyB3YWxscyBvdXRzaWRlP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGVyZSB0aG9ybnMgaW5zaWRlLCBhbG9uZyB3aW5kb3dzIG9yIHByb3RlY3Rpbmcgc2VjcmV0IGRvb3JzP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHRob3JucyBhcmUgcG9pc29ub3VzLCBpbmZsaWN0aW5nIHNvbWUgY29uZGl0aW9uIG9uIHRob3NlIHdobyBmYWlsIHRvIHJlc2lzdC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJQb3NzaWJpbGl0aWVzIGluY2x1ZGUgc2xlZXAsIGRlYXRoIGJ5IGNob2tpbmcsIGJsaW5kaW5nIGJsb29kIGZyb20gdGhlIGV5ZXMsIG9yIHBhcmFseXNpcy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgdGhvcm5zIGFyZSBjb25zaWRlcmVkIGEgZ2FyZGVuaW5nIGFjaGlldmVtZW50LCB3aXRoIHNvbWUgZmFtZSBhbmQgc3VwcG9ydCBhcyBsb2NhbCBjdWx0dXJlLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQSBjdXN0b20gYW11bGV0IHR1bmVkIHRvIHRoZWlyIGxpZmUgZW5lcmd5IHR1cm5zIHRoZSB0aG9ybnMgYXdheSwgYWxsb3dpbmcgaXRzIGJlYXJlciB0byBwdXNoIHRocm91Z2ggdGhlbSB1bmhhcm1lZC4gQSBzaXRlIGRlZmVuZGVyIG1heSBoYXZlIG9uZSwgb3Igb25lIGNvdWxkIGJlIG1hZGUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgb2xkIGFuZCBicml0dGxlLCBkeWluZyBieSBpbmNoZXMgYW5kIG5lZ2xlY3RlZC5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJWaW5lIEN1cnRhaW5zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU3VwZXJuYXR1cmFsIFBsYW50c1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiQ3VydGFpbnMgb2YgdmluZXMgY29ubmVjdCBiYWNrIHRvIGEgcmFkaWFudCByb290IHRoYXQgaGFzIGdyb3duIHNlbWnCrWF3YXJlLCBmZWQgb24gcm9ndWUgc3Bpcml0cy4gSWYgdG91Y2hlZCwgdGhlIHZpbmVzIHNsaXRoZXIgYW5kIHdyaXRoZSB0byBlbnRhbmdsZSwgaG9pc3QsIGFuZCBidW5kbGUgdGhlIHRhcmdldCBmb3IgYSBndWFyZGlhbiB0byBmaW5kLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIldoYXQgZG8gdGhlIHZpbmVzIGxvb2sgbGlrZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IHVzZSB0aGVpciBzY2VudCB0byBhdHRyYWN0IG9yIHJlcGVsP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoZXJlIGlzIHRoZSByb290IHJlbGF0aXZlIHRvIHRoZSBjdXJ0YWluP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiTWFueSBjdXJ0YWlucyBhbmQgcm9vdHMgb2YgZGlmZmVyZW50IHNpemVzIChzb21lIHF1aXRlIGJpZykgY29ubmVjdCBiYWNrIHRvIGEgY2VudHJhbCBidWxiIHNvbWV3aGVyZSBpbiB0aGUgZGVmZW5zZSBzaXRlLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSB2aW5lcyBhbHNvIGhhdmUgYSBjb250YWN0IHBvaXNvbiB0aGF0IG1ha2VzIHRoZWlyIHRhcmdldCBnbyBsaW1wIGZvciAxMC02MCBtaW51dGVzLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHNpdGUgb3duZXIgZG9lcyBub3QgaGF2ZSBsZWdhbCBwZXJtaXNzaW9uIHRvIGhhdmUgdGhlIHZpbmUgY3VydGFpbnMsIHNvIHRoZXkgYXJlIG9ubHkgdXNlZCBpbnNpZGUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHZpbmUgY3VydGFpbnMgZ3JvdyB3aWxkIGFuZCB0aGUgbGF6eSBzaXRlIG93bmVyIGRvZXMgbm90IGtlZXAgdGhlbSB0cmltbWVkIGJhY2ssIHNvIG90aGVyIGd1YXJkcyBtdXN0IHN0YXkgYXdheSBmcm9tIHRoZW0uXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ2F1bCBQaWVyY2Vyc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlRyYXBzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJQaWVyY2VycyBhcmUgZGVzaWduZWQgdG8gcHVuY3R1cmUgd2hvZXZlciB0b3VjaGVzIHRoZW0uIFRoZXkgcGllcmNlIHRoZSBlbmVyZ3kgY2F1bCBvZiB0aGUgY2hhcmFjdGVyJ3MgbGlmZSBmb3JjZSBpbiB0aGUgR2hvc3QgRmllbGQuIFRoaXMgY2F1c2VzIGEgaGFybSBjb25kaXRpb24gdGhhdCB3b3JzZW5zIG9yIGNvc3RzIHN0cmVzcyBldmVyeSBkb3duIHRpbWUgY3ljbGUgdW50aWwgdGhlIGNhdWwgY2FuIGJlIG1lbmRlZCAoNiBzZWdtZW50IHByb2plY3QuKSBJbnRlcnByZXQgYXMgbmVlZGVkLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZSBwaWVyY2VycyByZXNlbWJsZSBrbml2ZXMsIG5haWxzLCBvciB0aG9ybi1saWtlIGNhcnZpbmdzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgc2FkaXN0aWMgZXhwZXJ0IGNyYWZ0ZWQgdGhlc2UgZGlyZSB0cmFwcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJJZiBwcmllZCBvdXQgb2YgdGhlaXIgc2V0dGluZ3MsIGhvdyBsb25nIGRvIHRoZXkgcmV0YWluIHBvdGVuY3k/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaG9zZSBhZmZlY3RlZCB3aWxsIHRyYWlsIGxpZmUgZW5lcmd5IGxpa2UgYSB3b3VuZGVkIGZpc2ggYmxlZWRpbmcgaW4gdGhlIHdhdGVyOyBkZW1vbnMgYW5kIGdob3N0cyBhbGlrZSB3aWxsIGludmVzdGlnYXRlIHRoZSBzY2VudC5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSB3b3JrZWQgaW50byBpbXBvcnRhbnQgZG9vcmtub2JzLCBzdHJhdGVnaWMgbGVkZ2VzLCBhbmQgY29uY2VhbGVkIGZsb29yaW5nLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhbGwgbG9vayBhbGlrZSBhbmQgYXJlIHNpbWlsYXJseSBwbGFjZWQsIHJlbHlpbmcgb24gc3VycHJpc2UgdG8gYmUgZWZmZWN0aXZlLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZXkgYXJlIG9ubHkgb24gdGhlIG1haW4gdHJlYXN1cmUuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ29sbGFwc2luZyBDZWlsaW5nc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlRyYXBzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJJZiB0cmlnZ2VyZWQsIHRoaXMgdHJhcCBkcm9wcyBhIG1hc3Mgb2Ygc3RvbmUuIFRoYXQgc2VhbHMgb2ZmIHRoZSB0aHJlYXRlbmVkIGFyZWEsIGFuZCBjcnVzaGVzIGFueW9uZSB0YW1wZXJpbmcgd2l0aCBpdHMgZGVmZW5zZXMuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2hvIHB1dCB2YWx1YWJsZXMgYmVoaW5kIGEgdHJhcCB0aGF0IGNvdWxkIHNlYWwgdGhlbSBhd2F5IGZvciBnb29kP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkhvdyBvbGQgaXMgdGhpcyBkZWZlbnNlLCBhbmQgd2hvIHRha2VzIGNhcmUgb2YgaXQ/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCB3YXJuaW5nIHNpZ25zIHRpcCBvZmYgYW4gaW50cnVkZXIgdGhhdCBjb250aW51aW5nIGlzIGRhbmdlcm91cz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkhpZGRlbiBtZWNoYW5pc21zIGNhbiByYWlzZSB0aGUgYmxvY2sgYmFjayB1cCB0byB0aGUgY2VpbGluZywgc28gdGhlIHRyYXAgY2FuIGJlIHJldXNlZCAob3IgZGVmZWF0ZWQgcmVtb3RlbHkuKVwiLFxuICAgICAgICAgICAgICAgICAgICBcIk1vcmUgdGhhbiBvbmUgYmxvY2sgZmFsbHM7IHRoZSBmaXJzdCBvbmUgY3V0cyBvZmYgZXNjYXBlLCB0aGVuIGRlYXRoIHNlZW1zIGluZXZpdGFibGUuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc3RvbmUgZHJvcHBlZCBsb25nIGFnby4gU2l0ZSBndWFyZGlhbnMgb3IgaW50cnVkZXJzIGhhdmUgZGV2ZWxvcGVkIHdheXMgdG8gY2xpbWIgb3ZlciBpdCBvciBnZXQgcGFzdCBpdC4gT3RoZXIgYmxvY2tzIG1heSBzdGlsbCBiZSB1bnRyaWdnZXJlZCwgYnV0IHNvbWUgb2YgdGhlbSBhcmUgbm8gbG9uZ2VyIGRhbmdlcm91cy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJNb3JlIGxpa2UgYSBtaW5lIGNvbGxhcHNlLCBkaWZmaWN1bHQgdG8gY29udHJvbCBhbmQgcG9zc2libGUgdG8gdHVubmVsIHBhc3QuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ29tYmluYXRpb24gb3IgVHJpY2tcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVmFyaW91cyBwb3J0YWxzIGFuZCBkZWZlbnNlcyBvZiB0aGUgc2l0ZSBhcmUgcHJvdGVjdGVkIGJ5IGNvbWJpbmF0aW9uIGxvY2tzIG9yIHJpZGRsZXMgdG8gc29sdmUuIExvY2twaWNrcyB3aWxsIG5vdCB3b3JrIGFnYWluc3QgdGhlbSwgdGhvdWdoIGZpbmVzc2UgbWF5IHNvbHZlIHRoZW0gZXZlbnR1YWxseS5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlcmUgYSBzZXJpZXMgb2YgY29tYmluYXRpb24gbG9ja3MgZXhwcmVzc2luZyBhIHJlbGlnaW91cyBvciBlY2NlbnRyaWMgd29ybGR2aWV3P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGVyZSBwaWN0dXJlIGFycmFuZ2luZyBwdXp6bGVzLCBvciB1bnVzdWFsICBrZXlzICB0byBnbyBpbiBzY3VscHR1cmUgbG9ja3M/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZSBsb2NrcyBtZWNoYW5pY2FsIG9yIHN1cGVybmF0dXJhbD9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlBvd2VyZnVsIHJ1bmljIHdvcmsgb3IgZW5zbGF2ZWQgZ2hvc3RzIG1ha2UgdGhlIG9ic3RhY2xlIGRpZmZpY3VsdCB0byBzbWFzaCBvciB0cmljay0tdGhlIHJpZ2h0IGNvbWJpbmF0aW9uIG9yIG9iamVjdCBtdXN0IGJlIHVzZWQgdG8gYnlwYXNzIGl0LlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkNsdWVzIGFuZCBuZWVkZWQgaXRlbXMgYXJlIHNwcmVhZCBhY3Jvc3MgYSBsYXJnZSBlc3RhdGUsIG9yIG11bHRpcGxlIGVzdGF0ZXMuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgY29tYmluYXRpb24gb3Igc29sdXRpb24gdG8gdGhlIHB1enpsZSBpcyBpbiBhIHNjaG9sYXJseSB3b3JrLCBhbmQgY2FuIGJlIGZvdW5kIG9yIGJvdWdodCBhaGVhZCBvZiB0aW1lLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzb2x1dGlvbnMgYXJlIHBhaW5mdWxseSBvYnZpb3VzIHRvIHNvbWVvbmUgd2l0aCB0aGUgcmlnaHQgdXBicmluZ2luZyBhbmQgYmFja2dyb3VuZC5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJDb250YWN0IE5lZWRsZXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiU21hbGwgbmVlZGxlcyBhcmUgd29ya2VkIGludG8gY29udGFjdCBzdXJmYWNlcyBhbmQgcG9pc29uZWQsIHRvIGRldGVyIGludHJ1ZGVycy4gVGhleSBtYXkgYmUgb24gZG9vcmtub2JzLCBzZWF0IGJhY2tzIG9yIGN1c2hpb25zLCBkb29yZnJhbWVzLCBzdGFpciB0cmVhZHMsIGxlZGdlcywgYmVkc+KAlGFueXdoZXJlLCByZWFsbHkuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZSBuZWVkbGVzIGVhc2lseSB2aXNpYmxlIGlmIHlvdSBsb29rIGZvciB0aGVtLCBvciBjYW1vdWZsYWdlZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhleSByZXRyYWN0YWJsZSBpZiB5b3Uga25vdyB3aGF0IHlvdSdyZSBkb2luZz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXaGF0IGtpbmQgb2YgcG9pc29uIGlzIG9uIHRoZW0/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2lsbCB0aGUgdmljdGltIHNsZWVwLCBmcmVlemUsIGRpZSwgb3IgaGFsbHVjaW5hdGU/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgbmVlZGxlcyBhcmUgb25seSBjb3Jwb3JlYWwgdG8gdGhvc2Ugd2hvIHRvdWNoIHRoZW0gd2l0aG91dCB3ZWFyaW5nIGEgY2VydGFpbiBhbXVsZXQuIEltcG9ydGFudCBzaXRlIGd1YXJkaWFucyBhcmUgaW1tdW5lIHRvIHRoZSBuZWVkbGVzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkFueXRoaW5nIGltcG9ydGFudCBvciBhdCBhbiB1bmd1YXJkZWQgZW50cnkgcG9pbnQgaXMgZ29pbmcgdG8gYmUgZmVzdG9vbmVkIHdpdGggbmVlZGxlcy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZXkgYXJlIG5vdCB3ZWxsIG1haW50YWluZWQuIE1hbnkgaGF2ZSBzbmFwcGVkIG9mZiwgYW5kIGZldyByZXRhaW4gbXVjaCBwb2lzb24uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgb25seSBvbiB0aGUgbW9zdCBpbXBvcnRhbnQgb2JqZWN0cyBvciB0aGUgbW9zdCB1c2VmdWwgdHJhcCBvYmplY3RzIChsaWtlIGEgY2hhaXIgZm9yIGd1ZXN0cy4pXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRXhjZWxsZW50IExvY2tzXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHJhcHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkJleW9uZCBzaW1wbGUgc2VjdXJpdHksIHRoZXNlIGxvY2tzIGFyZSB3b3JrcyBvZiBhcnQuIFRoZXkgYXJlIGhpZ2hlciBwb3RlbmN5IHRoYW4gdGhleSB3b3VsZCBub3JtYWxseSBiZS4gQWxzbywgdGhleSBhcmUgZXF1aXBwZWQgd2l0aCBwb2lzb24gbmVlZGxlIHRyYXBzLCBvciBwaWNrIGJyZWFrZXJzLCBvciByZWR1bmRhbmNpZXMuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2hvIHB1dCBpbiB0aGVzZSBzdXBlcmlvciBsb2NrcywgYW5kIGZvciB3aGF0IHJlYXNvbj9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIGxvY2tzIGRlc2lnbmVkIHRvIGRlZmVhdCBlbnRyeSwgb3IgYWN0aXZlbHkgcHVuaXNoIGludHJ1ZGVycz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGUgc3BlY2lhbGl6ZWQga2V5cyBoYXZlIGEgZGlzdGluY3RpdmUgbG9vaywgbGlrZSB0d28gZmxhbmdlcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJJcyB0aGVyZSBhIG1hc3RlciBrZXk/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJFdmVyeXRoaW5nIGlzIGxvY2tlZCwgYW5kIGFsbCB0aGUgbG9ja3MgYXJlIGdvb2QuIFNvbWVib2R5IGhhZCBhIHJlYWwgbG9jayBwcm9ibGVtLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBsb2NrcyBpbnZvbHZlIHN1cGVybmF0dXJhbCBjb21wb25lbnRzLCBsaWtlIGhpZGRlbiBrZXlob2xlcyBvciBwYXJhbHl6aW5nIGVuZXJneS5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBsb2NrcyBhcmUgaW4gcG9vciByZXBhaXIsIG9mIHZhcmlhYmxlIHF1YWxpdHkgYWZ0ZXIgaW5kaWZmZXJlbnQgbWFpbnRlbmFuY2UgYW5kIG1hbnkgaW50cnVzaW9uIGF0dGVtcHRzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlZlcnkgZmFuY3kgbG9ja3MsIGJ1dCB0aGV5IGFyZSBwYWRsb2NrcywgYW5kIGJvbHQgY3V0dGVycyBjYW4gY2lyY3VtdmVudCB0aGUgcHJvYmxlbS5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNdXJkZXIgSG9sZXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiSW50cnVkZXJzIGdvIHBhc3Qgb25lIGRvb3IsIGludG8gYSBoYWxsd2F5IG9yIHNtYWxsIHJvb20sIGFuZCB0aGUgZG9vciBjbG9zZXMgYmVoaW5kIHRoZW0uIEFycm93IHNsaXRzIG9wZW4gaW4gdGhlIHdhbGxzLCBhbmQgc2xvdHMgaW4gdGhlIGNlaWxpbmcgYWxsb3cgYm9pbGluZyBvaWwgdG8gYmUgcG91cmVkIGRvd24uIEludHJ1ZGVycyBhcmUgdHJhcHBlZCBhbmQgdnVsbmVyYWJsZS4gVGhlc2UgYXJlIG9mdGVuIGluIGRvb3JzIHRocm91Z2ggZGVmZW5zZXMuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiV2FzIHRoZSBvcmlnaW5hbCBzaXRlIGJ1aWxkZXIgb2Z0ZW4gdW5kZXIgc2llZ2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZSBtdXJkZXIgaG9sZXMgb2J2aW91cyBvciBjb25jZWFsZWQ/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJNdXJkZXIgaG9sZXMgYXJlIGF1dG9tYXRlZCB3aXRoIHNlbGYtIHNsYW1taW5nIGRvb3JzIGFuZCBwcmUtYm9pbGluZyBvaWwsIHNvIGEgZmV3IGRlZmVuZGVycyBjYW4gdHJhcCBhbmQvb3Iga2lsbCBtYW55IGludHJ1ZGVycy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgd2hvbGUgbGF5b3V0IGlzIGJ1aWx0IHdpdGggbWFueSBtdXJkZXIgaG9sZSBhcmVhcyB0byBkZXRlciBpbnZhc2lvbi5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSB3YWxscyBhcmUgd29vZGVuLCBhbmQgZGV0ZXJtaW5lZCBjYXB0aXZlcyBjYW4gYnJlYWsgdGhyb3VnaCB0byBmYWNlIHRoZWlyIGF0dGFja2Vycy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGlzIGFyZWEgZG9lcyBub3QgaGF2ZSBlbm91Z2ggc3RhZmYgdG8gbW9uaXRvciBpbnRydWRlcnMgYW5kIG1ha2UgYmVzdCB1c2Ugb2YgbXVyZGVyIGhvbGVzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlBpdCBUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlRyYXBzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgZGVmZW5kZWQgc2l0ZSBoYXMgcGl0IHRyYXBzIGluIHN0cmF0ZWdpYyBwbGFjZXMuIFRoZXkgYXJlIGJldHdlZW4gMTAgYW5kIDQwIGZlZXQgZGVlcC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IGhhdmUgc2xpY2sgc2lkZXM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXJlIHNwaWtlcyBhdCB0aGUgYm90dG9tP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGUgY292ZXJzIG1lY2hhbml6ZWQsIG9yIGZsaW1zeSBib2FyZHMgYW5kIGNhcnBldHMsIGdyYXNzIHR1cmYsIG9yIGxlYXZlcyBvdmVyIGNhbnZhcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIHNpZGVzIHN0b25lLCBlYXJ0aCwgb3IgY2xheT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkZpc3Qgc2l6ZWQgdHVubmVscyBjb25uZWN0IHBpdHMuIFByZWRhdG9yeSBjcmVhdHVyZXMgKGNyYWJzLCBzbmFrZXMsIHNwaWRlcnMsIHJhdHMpIHNjdXJyeSB0byBkZXZvdXIgdmljdGltcy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJPbmNlIHNvbWVvbmUgZmFsbHMgaW50byB0aGUgcGl0IHRoZSBjb3ZlcnMgY2xvc2UgYWdhaW4sIGFuZCB3aWxsIG5vdCBvcGVuIHVudGlsIHVubG9ja2VkLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHBpdHMgZHJvcCBpbnRvIGEgbG93ZXIgYXJlYSwgbW9zdGx5IGFiYW5kb25lZCBleGNlcHQgZm9yIHByZWRhdG9ycy4gSXQgaXMgcG9zc2libGUgdG8gZmluZCBhIHdheSBvdXQuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHBpdHMgYXJlIG1vc3RseSBvcGVuIGFuZCBmaWxsZWQgd2l0aCBqdW5rLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlJldHJhY3RhYmxlIFNwaWtlc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlRyYXBzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJTcHJpbmctbG9hZGVkIHNwZWFycyBvciByYWNrcyBvZiBzcGVhcnMgbGF1bmNoIGF0IGludHJ1ZGVycy4gVGhleSBjYW4gY29tZSBmcm9tIHRoZSBzaWRlLCBiZWhpbmQsIGFoZWFkLCBiZWxvdywgb3IgYWJvdmUuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZSBkZWZlbnNlcyBzdGFuZGFyZGl6ZWQgdG8gcHJvdGVjdCBndWFyZGlhbnMsIG9yIHJhbmRvbSB0byBjb25mdXNlIGludHJ1ZGVycz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhleSBpbiBhbiBhcmVhIHRoYXQgc2l0ZSBkZWZlbmRlcnMgdXNlLCBvciBpbiBhbiBpc29sYXRlZCBvZmYtbGltaXRzIGFyZWE/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGxvbmcgaGF2ZSB0aGV5IGJlZW4gaW4gdXNlLCBhbmQgaG93IG9mdGVuIGFyZSB0aGV5IG1haW50YWluZWQ/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBZnRlciBkb2luZyB0aGVpciBraWxsaW5nIHdvcmssIHRoZXkgcmV0cmFjdCwgYW5kIHRoZSBsYXVuY2ggcG9pbnRzIGFyZSBub3Qgb2J2aW91cy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc3BlYXJzIGFyZSBzbGF0aGVyZWQgd2l0aCBzb21lIHRveGluLCBmdXJ0aGVyIGFmZmVjdGluZyB0aGUgdmljdGltLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIG1lY2hhbmlzbXMgYXJlIG5vdCB3ZWxsIG1haW50YWluZWQuIFNvbWV0aW1lcyB0aGV5IGRvbid0IHdvcmssIGFuZCB3aGVuIHRoZXkgZG8sIHRoZXJlIGlzIGEgc2NyZWVjaCBhbmQgdGhleSBhcmUgYSBiaXQgc2xvdy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc3BlYXJzIGFyZSBkZXNpZ25lZCB0byBwaW4gYW4gaW50cnVkZXIgaW4gcGxhY2UsIHRvIGJlIGludGVycm9nYXRlZCBhbmQgcHVuaXNoZWQsIHJhdGhlciB0aGFuIHRvIGtpbGwgb3V0cmlnaHQuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU2VjcmV0IERvb3JzICYgU3B5aG9sZXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiR3VhcmRpYW5zIGFyZSB3ZWxsIHRyYWluZWQgaW4gdGhlIHVzZSBvZiBudW1lcm91cyBzZWNyZXQgZG9vcnMgYW5kIGhpZGRlbiBwYXNzYWdlcyB3aXRoIHNweWhvbGVzLiBUaGV5IGNhbiBhdHRhY2sgZnJvbSB1bmV4cGVjdGVkIGRpcmVjdGlvbnMsIGVzY2FwZSB3aXRob3V0IGEgdHJhY2UsIGFuZCB3YXRjaCBpbnRydWRlcnMgdW5vYnNlcnZlZC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJXYXMgdGhpcyBzaXRlIGJ1aWx0IGJ5IGEgc3B5LCBvciBhIGN1bHQsIG9yIGEgcGFyYW5vaWQgYXJpc3RvY3JhdD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlcmUgY29uc2lzdGVudCB0ZWxscywgYSBjb2RlIGJ1aWx0IGludG8gdGhlIGRlY29yIGFuZCBhcmNoaXRlY3R1cmUsIG9yIG11c3QgYWxsIHNlY3JldHMgYmUga25vd24gaW5kaXZpZHVhbGx5P1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiT25nb2luZyByZWFycmFuZ2VtZW50IGFuZCBjb25zdHJ1Y3Rpb24gbWVhbnMgb2xkIGluZm9ybWF0aW9uIGZyb20gcGxhbnMgb3IgcGVvcGxlIGFnZXMgb3V0IGZhc3QuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiU3VwZXJuYXR1cmFsIGxvY2tzIGFuZCBrZXlzIG1lYW4gdGhhdCB0cmlnZ2VycyBhbmQgc3B5aG9sZXMgYW5kIHNlYW1zIG1heSBub3QgYmUgdmlzaWJsZSBpbiB0aGUgbWF0ZXJpYWwgd29ybGQgYXQgYWxsLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiRnJlcXVlbnQgdXNlIGhhcyBtYWRlIHNlY3JldCBkb29ycyBlYXNpZXIgdG8gc3BvdC4gUG9vciBiYWZmbGluZyBvZiBsaWdodHMgbWF5IHJldmVhbCBzcHlob2xlcyBpbiB1c2UuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQ3VycmVudCByZXNpZGVudHMgYXJlIG9ubHkgYXdhcmUgb2Ygc29tZSBzZWNyZXRzOyBpbnRydWRlcnMgbWF5IHVzZSBiYWNrIHdheXMgdG8gZWx1ZGUgc2VjdXJpdHkuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU2hvY2sgR3JpcHNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUcmFwc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiT25lIG9yIG1vcmUgY29udGFjdCBwb2ludHMgYXJlIGNvbm5lY3RlZCB0byBlbmVyZ3kgc28gdGhleSB3aWxsIGJhZGx5IHNob2NrIGFueW9uZSB3aG8gdG91Y2hlcyB0aGVtLiBUaGVzZSBjb3VsZCBiZSBkb29ya25vYnMsIGNoZXN0IGxpZHMsIGZsb29yIHBsYXRlcywgbGFkZGVycywgYW5kIHNvIG9uLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IHBvd2VyZWQgYnkgYmF0dGVyaWVzIG9yIGVuc2xhdmVkIGdob3N0cz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIHRoZSBzaXRlIGhhdmUgbGVnYWwgcGVybWlzc2lvbiB0byB1c2UgdGhlbT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgbG91ZCBpcyB0aGUgc2hvY2s/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGRvIHNpdGUgZ3VhcmRpYW5zIGF2b2lkIGdldHRpbmcgc2hvY2tlZD9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzaG9jayBncmlwcyBhcmUgbnVtZXJvdXMgYW5kIGNvbmNlYWxlZCwgY29ubmVjdGVkIHRvIHRoZWlyIGVuZXJneSBzb3VyY2UgdGhyb3VnaCB0aGUgR2hvc3QgRmllbGQuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHNob2NrIGlzIGRlc2lnbmVkIHRvIHN0b3AgdGhlIGhlYXJ0IGFuZCBraWxsIHRoZSB2aWN0aW0gKHBvc3NpYmx5IHNldHRpbmcgaGFpciBvbiBmaXJlLilcIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzaG9jayBncmlwcyBhcmUgY29ubmVjdGVkIHRvIGNvbnRyb2wgYm94ZXMgYW5kIGVuZXJneSBzb3VyY2VzIGJ5IGNhYmxlcy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJTaG9jayBncmlwcyBhcmUgbWFya2VkIGJ5IGEgcnVuZSwgYW5kIHNoaW55LCBhbmQgYWxzbyBnaXZlIG91dCBhIHBhbHBhYmxlIGh1bSBvZiBlbmVyZ3kuIFRoZXkgYXJlIGVhc3kgdG8gZGV0ZWN0LlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkJydXRhbCBTYWRpc3RzXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHdpc3RlZCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIk9ubHkgYnJ1dGFsIHNhZGlzdHMgYXJlIGhpcmVkIG9uIGFzIGd1YXJkcy4gVGhleSBoYXZlIHBlcm1pc3Npb24gdG8gcGxheSB3aXRoIGNhcHR1cmVkIGludHJ1ZGVycy5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJJcyB0aGUgb3duZXIgb2YgdGhlIHByb3RlY3RlZCBwcm9wZXJ0eSBhd2FyZSBvZiB0aGlzIGN1bHR1cmFsIHJ1bGUsIG9yIGFyZSBndWFyZHMgaGlyZWQgYnkgYW4gZW1wbG95ZWU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiRG8gdGhleSBzaGFyZSBjdWx0dXJhbCByb290cyAoc2xhdWdodGVyaG91c2Ugd29ya2VycywgbGV2aWF0aGFuIGh1bnRlcnMsIHNvbGRpZXJzLCBjaXR5IGd1YXJkcywgZXRjKT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgZG8gdGhlIG5laWdoYm9ycyBmZWVsIGFib3V0IHRoZWlyIG9jY2FzaW9uYWwgc2NhbmRhbHM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJTZXZlcmFsIG9mIHRoZW0gYXJlIHNraWxsZWQgaW4gYm90aCB0b3J0dXJlIGFuZCBpbnRlcnJvZ2F0aW9uOyB0aGV5IGV4dHJhY3Qgc2VjcmV0cyBmcm9tIGludHJ1ZGVycy4gQSBzaWRlIGJ1c2luZXNzIGluIGJsYWNrbWFpbCBoZWxwcyB0aGVtIGF2b2lkIGxlZ2FsIHRyb3VibGUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBhcmUgaGFyZGVuZWQgdmV0ZXJhbnMsIGV4Y2VwdGlvbmFsbHkgdG91Z2ggYW5kIGRhbmdlcm91cy4gVGhleSBhaW0gdG8gaW5jYXBhY2l0YXRlLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlaXIgdWdseSB0YWN0aWNzIGFuZCBwb29ybHkgY2hvc2VuIHZpY3RpbXMgaGF2ZSBlYXJuZWQgdGhlbSAoYW5kIHRoZWlyIGVtcGxveWVyKSBlbmVtaWVzIGluIGxvdHMgb2YgdW5leHBlY3RlZCBwbGFjZXMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSByZWFsbHksIHJlYWxseSBsaWtlIHRvIGRyaW5rLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNsb3NlLUtuaXQgR3VhcmQgTmV0d29ya1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlR3aXN0ZWQgR3VhcmRzXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJHdWFyZHMgYXJlIG9ubHkgaGlyZWQgYnkgcmVmZXJyYWwuIEZhaWx1cmUgcmVzdWx0cyBpbiBwdW5pc2htZW50IGZvciBib3RoIHRoZSBndWFyZCBhbmQgdGhlIHNwb25zb3IuIFRoZWlyIGxveWFsdHkgaXMgdGVzdGVkIG1hbnkgd2F5cyBiZWZvcmUgYW5kIGFmdGVyIHRoZXkgYXJlIGhpcmVkLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZXkgZmF2b3IgYmFzdGFyZHMgb2YgdGhlIGVtcGxveWVyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IGNvbm5lY3RlZCB0byBvbmUgbWlsaXRhcnkgdW5pdD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhleSByZWZ1Z2VlcyBmcm9tIGFub3RoZXIgcGxhY2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiRG8gdGhleSBjb21lIGZyb20gYSBzaW5nbGUgbmVpZ2hib3Job29kP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvZXMgcHVuaXNobWVudCBleHRlbmQgdG8gdGhlaXIgZmFtaWxpZXM/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSBjb25uZWN0ZWQgdG8gYSBsYXJnZXIgc3BvbnNvcmluZyBvcmdhbml6YXRpb24gdGhhdCB3b3VsZCBzZWVrIHZlbmdlYW5jZSBpZiB0aGV5IGFyZSBhdHRhY2tlZCBvciBpbnN1bHRlZCwgYW5kIGFsc28gb2ZmZXIgdGhlbSBmYXZvcnMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBzcGVhayBpbiBjb2RlIGFuZCBoYXZlIHBhc3N3b3JkcyB0aGF0IGluY2x1ZGUgc2FmZXdvcmRzIGFuZCB3YXJuaW5ncy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk5lcG90aXNtIGhhcyBwdWxsZWQgaW4gc29tZSByZWFsbHkgaW5jb21wZXRlbnQgZ3VhcmRzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkVuZGxlc3MgZHJhbWEgZnJvbSB3b3JraW5nIHdpdGggZmFtaWx5IGFuZCBmcmllbmRzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNvbXB1bHNpdmUgRGV0YWlsIEZvY3VzXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHdpc3RlZCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIk9ubHkgYSBjZXJ0YWluIHR5cGUgaXMgaGlyZWQ7IGEgdHlwZSB0aGF0IGNoZWNrcyBldmVyeSBsb2NrIGFuZCBldmVyeSBkYXJrIGNvcm5lci4gU2NoZWR1bGVzIGFyZSBzdHJpY3QsIHRob3JvdWdobmVzcyBpcyBhIGd1YXJhbnRlZSwgYW5kIHRoZXkgc2VlbSB1bmFibGUgdG8gY3V0IGNvcm5lcnMgb3Igc2tpcCBzdGVwcy4gRXZlcnl0aGluZyBpcyBieSB0aGUgYm9vay5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhleSBhbHRlcmVkIHRvIGJlIGxpa2UgdGhpcywgb3IganVzdCBzY3JlZW5lZCBmb3IgYSBtaW5kc2V0P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgYXJlIHRoZSBkZXRhaWxlZCBwYXJ0cyBvZiB0aGUgZGVmZW5kZWQgc2l0ZSB0aGF0IG5lZWQgdGhpcyBraW5kIG9mIGF0dGVudGlvbj9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgZG9lcyB0aGVpciBnZWFyIHJlZmxlY3QgdGhpcyBmdXNzeSBhdHRlbnRpb24gdG8gZGV0YWlsP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlcmUgYXJlIG90aGVyIGVsZW1lbnRzIG9mIHRoZSBkZWZlbmRlZCBzaXRlIHRoYXQgcmVxdWlyZSB0aGVpciBmb2N1cywgbGlrZSBhIHBhdHRlcm4gb2Ygc3RlcHBpbmcgb3ZlciB0aWxlcyB0byBhdm9pZCB0cmlnZ2VyaW5nIHRyYXBzIG9yIGNvbXBsZXggY29tYmluYXRpb24gbG9ja3Mgb3IgZG96ZW5zIG9mIGNlbGxzIHdpdGggZGFuZ2Vyb3VzIHByaXNvbmVycy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSB0cnVzdGVkIHdpdGggc3BlY2lhbHR5IGl0ZW1zIGxpa2UgZmlyZWFybXMgb3IgY2hhcm1zIGJlY2F1c2UgdGhleSBhcmUgcmVzcG9uc2libGUgd2l0aCB0aGVtLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiRXZlcnlvbmUga25vd3MgdGhhdCB0aGV5IGZhbGwgYXBhcnQgaWYgdGhpbmdzIGRldmlhdGUgZnJvbSB0aGUgcGF0dGVybiwgbGlrZSBkaXN0cmFjdGlvbnMgb3IgY2hhb3MuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGxvY2FscyBwaWNrIG9uIHRoZW0gd2hlbiB0aGV5IGFyZSBvZmYgZHV0eSwgdGVhc2luZyB0aGVtIGZvciB0aGVpciBjb21wdWxzaW9ucy4gVGhleSBoYXZlIGVuZW1pZXMsIGFuZCBjb3VsZCB1c2UgZnJpZW5kcy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJDb252aWN0IFB1YmxpYyBTZXJ2aWNlXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHdpc3RlZCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkR1ZSB0byBwcmlzb24gb3ZlcmNyb3dkaW5nLCBzb21lIGNyaW1pbmFscyBhcmUgc2VudGVuY2VkIHRvIGluZGVudHVyZWQgc2VydmljZSB0byBhIG5vYmxlIHRvIHdvcmsgb2ZmIHRoZWlyIGRlYnQgdG8gc29jaWV0eS4gVGhpcyBzaXRlJ3MgZ3VhcmRpYW4gdXNlcyBjcmltaW5hbHMgYXMgZ3VhcmRzLCB1bmRlciB0aGUgc3Rlcm4gZXllIG9mIHByb2Zlc3Npb25hbHMuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIGNhc3VhbHRpZXMgaGlnaCBkdWUgdG8gZGFuZ2VyIGZyb20gaW50cnVkZXJzIG9yIG90aGVyIHNpdGUgZGVmZW5zZXM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSXMgdGhlIHBhdHJvbiBiZW5ldm9sZW50IGFuZCB0cnlpbmcgdG8gcmVoYWJpbGl0YXRlIGNyaW1pbmFscywgb3IgdXNpbmcgdGhlbSBhcyBkaXNwb3NhYmxlIGZvZGRlcj9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgZG8gdGhlIGNvbnZpY3RzIGxpa2UgdGhpcyBwbGFjZT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlNlcnZpbmcgaGVyZSBpcyBhIGtub3duIHBvc3QgYW1vbmcgY3JpbWluYWxzLCBib3RoIGEgcmVzdW1lIGJ1aWxkZXIgYW5kIG5ldHdvcmtpbmcgc2l0ZS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBbmdlcmluZyB0aGVzZSBndWFyZHMgY291bGQgYnJpbmcgY29uc2VxdWVuY2VzIGZyb20gdW5leHBlY3RlZCBkaXJlY3Rpb25zIGluIHRoZSBjcmltaW5hbCB1bmRlcndvcmxkLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkhhbmQgcGlja2VkIGFzIHRoZSBoYXJkZXN0IGFuZCBkZWFkbGllc3QsIHRoZXNlIGNyaW1pbmFsIGd1YXJkcyBhcmUgY2FubnkgYW5kIHRvdWdoLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQ29udmljdHMgYXJlIGVhZ2VyIHRvIGFzc2lzdCBhbnlvbmUgd2l0aCBlbm91Z2ggQ29pbiBvciBwdWxsIHRvIHNlY3VyZSB0aGVpciBwYXJkb24gYW5kIGZyZWVkb20uXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGNvbnZpY3RzIGFyZSBidWxsaWVkIGFuZCBzdWxsZW4sIGFzIG11Y2ggYSBoaW5kcmFuY2UgdG8gZGVmZW5kZXJzIGFzIGEgZGVmZW5zZSB0aGVtc2VsdmVzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkRlbW9uaWMgTXV0YXRpb25zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHdpc3RlZCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkFib3V0IGEgcXVhcnRlciBvZiB0aGUgZ3VhcmRzIGhhdmUgYmVlbiBtdXRhdGVkIGJ5IGNvbnRhY3Qgd2l0aCBkZW1vbmljIGVzc2VuY2UuIFRoZXkgYXJlIHN0cm9uZywgYW5kIHRoZWlyIHNlbnNlcyBhcmUgc2hhcnAuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiRG8gdGhleSBzaGFyZSBvbmUgZGVtb24gcGF0cm9uP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRpZCB0aGV5IGJlY29tZSBndWFyZHMgdG8gZ2FpbiB0aGlzIHBvd2VyP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IHdvcnNoaXBwZXJzIG9yIG1lcmNlbmFyaWVzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRpZCB0aGV5IHZvbHVudGVlciBvciBhcmUgdGhleSB2aWN0aW1zP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgZWxlbWVudCBpcyB0aGVpciBkZW1vbmljIGFmZmluaXR5P1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBzaGFyZSBhIHN1cGVybmF0dXJhbCBjb25uZWN0aW9uIGFuZCBjYW4gc2Vuc2Ugd2hlbiBvdGhlciBkZW1vbmljIGd1YXJkcyBhcmUgaW4gdHJvdWJsZS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGV5IGFyZSBoaWdobHkgcmVzaXN0YW50IHRvIG5vcm1hbCBkYW1hZ2UuIFRoZXkgbWF5IGJlIHZ1bG5lcmFibGUgdG8gc3VwZXJuYXR1cmFsIGF0dGFja3Mgb3IgYSBzcGVjaWZpYyBhbGxlcmd5IChzaWx2ZXIsIGdhcmxpYywgc2FsdCwgZXRjLikgT3IsIHRoZXkgbWF5IGJlIHJlc2lzdGFudCB0byBzdXBlcm5hdHVyYWwgYXR0YWNrcyBpbnN0ZWFkLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhleSBiZWNvbWUgcGh5c2ljYWxseSBpbXByZXNzaXZlLCBidXQgdGhlaXIgbWluZHMgYXJlIGxvc3QgdG8gaW5jb2hlcmVudCBsdXN0cyBhbmQgZnVyeS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgcmVzdCBvZiB0aGUgc3RhZmYgcmVzZW50IG9yIGZlYXIgdGhlIGRlbW9uaWMgZ3VhcmRzLiBMb3lhbHR5IGFuZCBtb3JhbGUgYXJlIGxvdyBhbW9uZyBtdW5kYW5lIGVtcGxveWVlcy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJFbmNoYW50ZWQgUHJvc3RoZXRpY3NcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUd2lzdGVkIEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiR3VhcmRzIGFyZSBhbGwgYW1wdXRlZXMgd2l0aCBhdCBsZWFzdCBvbmUgcHJvc3RoZXRpYy4gRWFjaCBwcm9zdGhldGljIHR1bmVzIHRvIGl0cyBvd25lci4gVGhlIHByb3N0aGV0aWNzIGNhbiBzdHVuIG9uIGNvbnRhY3QuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZSBmYWxzZSBsaW1icyB0aGUgd29yayBvZiBvbmUgZ2VuaXVzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGV5IHBhcnQgb2YgYSBjb2xsZWN0aW9uP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldlcmUgdGhleSBtYWRlIGZvciB0aGlzIHVzZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJJcyBhIGdob3N0IGJvdW5kIHRvIGVhY2g/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXkgc2NpZW50aWZpYywgd2l0aCBiYXR0ZXJpZXM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHRoZXkgcG93ZXJlZCBieSB0aGUgYmVhcmVyJ3MgbGlmZSBmb3JjZT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkFsbCBndWFyZHMgaGF2ZSBzb21lIGFkZXB0IHRyYWluaW5nIGFuZCBzcGlyaXQgYmFuZSBjaGFybXMsIGFsZXJ0IGFnYWluc3Qgc3VwZXJuYXR1cmFsIGZvcmNlcy5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJWZXRlcmFuIGd1YXJkcyBoYXZlIGxlYXJuZWQgdG8gdHVuZSB0byB0aGVpciBwcm9zdGhldGljcyB0byBnZXQgYW4gYWRkaXRpb25hbCBlZmZlY3QsIGxpa2UgbGlmZSBkZXRlY3Rpb24gb3IgZmlyaW5nIGVuZXJneSBibGFzdHMuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJPbmx5IG9uZSB1c2UgYmV0d2VlbiByZWNoYXJnZXMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGd1YXJkcyBhcmUgbW9zdGx5IG9sZCBvciBicm9rZW4sIHJlbHlpbmcgb24gcmVwdXRhdGlvbiBhbmQgc3VwZXJuYXR1cmFsIGVuZXJneSB0byBiZSBlZmZlY3RpdmUuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRmVyYWwgUGVuXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiVHdpc3RlZCBHdWFyZHNcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlNvbWUgYXJlYXMgb2YgdGhlIGRlZmVuZGVkIHNpdGUgaGF2ZSBmcmVlLXJhbmdlIG1hbmlhY3MuIERlc3RpdHV0ZSBhbmQgd3JldGNoZWQgYmVnZ2FycyBhcmUgdHJlYXRlZCBhcyBndWFyZCBkb2dzLCBleHBlY3RlZCB0byBhdHRhY2sgaW50cnVkZXJzIGFuZCBkcmF3IGF0dGVudGlvbiB0byBhbnl0aGluZyB1bnVzdWFsLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkRvZXMgdGhlIGd1YXJkZWQgc2l0ZSBwcmV0ZW5kIHRvIGJlIGNoYXJpdGFibGUsIG9yIGEgbWFkaG91c2UsIG9yIGEgcHJpc29uP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgcGhpbG9zb3BoeSBsZWFkcyB0byB0cmVhdGluZyBwZW9wbGUgdGhpcyB3YXk/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGRvIHRoZSBjaXR5IGF1dGhvcml0aWVzIGZlZWwgYWJvdXQgdGhlIHNpdGU/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiUmVsaWdpb3VzIGF1dGhvcml0aWVzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvZXMgdGhlIHNpdGUgZmVlZCBpbnRvIHRoZSBHaG9zdCBGaWVsZCBpbiBhbiB1bnVzdWFsIHdheT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIk1vc3Qgb2YgdGhlIGZlcmFsIGd1YXJkcyBhcmUga2lsbGVycywgcG9zc2libHkgaGF1bnRlZCwgYW5kIGV4dHJlbWVseSBkYW5nZXJvdXMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhpcyBwZXQgcHJvamVjdCBpcyBhcyBtdWNoIGFydCBhbmQgcmVsaWdpb24gYXMgZGVmZW5zZSwgYW5kIGhhcyBzdXBwb3J0IGZyb20gYSB2YXJpZXR5IG9mIGRlY2FkZW50IGFyaXN0b2NyYXRzIGluIHBvc2l0aW9ucyBvZiBwb3dlci5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSByZXN0IG9mIHRoZSBzaXRlIGd1YXJkcyBoYXRlIHRoZSBmZXJhbCBwZW4gYW5kIGlnbm9yZSBpdCBhcyBiZXN0IHRoZXkgY2FuLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkl0IGlzIGFzIG11Y2ggcHJpc29uIGhvc3BpY2UgYXMgZ3VhcmQgZG9nIGtlbm5lbC4gSXRzIHZpY3RpbXMgYXJlIHdlYWssIHNpY2ssIGFuZCBzdGFydmluZy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJGaWdodGluZyBTY2hvb2xcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUd2lzdGVkIEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiQW4gb25zaXRlIHRyYWluaW5nIHNjaG9vbCBmb2N1c2VzIG9uIHRoZSBsaWZlc3R5bGUgYW5kIHNraWxsIG9mIGEgc2Nob29sIG9mIGZpZ2h0aW5nLiBTaXRlIGRlZmVuZGVycyBhcmUgcGFydCBvZiBhIGdyb3VwIGlkZW50aXR5IHdpdGggc3BlY2lhbHR5IHRyYWluaW5nLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIklzIHRoZSBzY2hvb2wncyBmb2N1cyBvbiBkdWVsaW5nLCBhIG1hcnRpYWwgYXJ0LCBjb21tYW5kbyB0cmFpbmluZywgb3Igc29tZXRoaW5nIGVsc2U/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBpcyB0aGVpciBjcmVzdCwgdW5pZm9ybSwgbW90dG8sIGFuZCBsb3JlP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldoYXQgc29ydCBvZiB0cmFpbmluZyBzcGFjZSBkbyB0aGV5IGhhdmU/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgc2Nob29sIGl0c2VsZiBpcyBhbiBpbXByZXNzaXZlIGZvcnRyZXNzIG9yIGRlZmVuc2UuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHNjaG9vbCBoYXMgYW4gaW1wcmVzc2l2ZSBhbHVtbmkgbmV0d29yayB0aGF0IHZpc2l0cyBvY2Nhc2lvbmFsbHkgYW5kIHdvdWxkIGF2ZW5nZSB3cm9uZ3MgdG8gdGhlIGhvbm9yIG9mIHRoZSBzY2hvb2wuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGlzIGlzIGFuIG9mZi1zaXRlIHNocmluZSBvciBleHBhbnNpb24sIHdoZXJlIHRoZXkgc2VuZCB0cm91YmxlbWFrZXJzIGFuZCB0aG9zZSB0aGV5IGNhbid0IGVqZWN0IGZvciBwb2xpdGljYWwgb3IgZmluYW5jaWFsIHJlYXNvbnMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiTGVhZGVyc2hpcCBpcyByaWRkbGVkIHdpdGggcml2YWxyaWVzIGFuZCBwb3dlciBzdHJ1Z2dsZXMuIE91dHNpZGVycyBrbm93IHNvbWUgZGV0YWlscy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJQZXJmb3JtYW5jZSBFbmhhbmNlcnNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUd2lzdGVkIEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiR3VhcmRzIGhhdmUgcmVhZHkgYWNjZXNzIHRvIGRydWdzLiBTb21lIG9mIHRoZSBkcnVncyBlbmhhbmNlIHBlcmZvcm1hbmNlLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkRvIHRoZSBkcnVncyBnaXZlIHRoZW0gYSBidXJzdCBvZiBjb21iYXQgZWZmZWN0aXZlbmVzcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIGRydWdzIHJlY3JlYXRpb25hbCwgbWFraW5nIHRoZW0gcG9wdWxhciB3aXRoIGEgY3VzdG9tZXIgYmFzZSB0aGF0IHBheXMgd2VsbCBhbmQgb3dlcyBmYXZvcnM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hvIHByb3ZpZGVzIHRoZW0gd2l0aCBkcnVncz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIkFzIGRlYWxlcnMsIHRoZSBndWFyZHMgYXJlIGRpZmZpY3VsdCB0byBicmliZSBvciBpbnRpbWlkYXRlLCBhcyB0aGV5IGhhdmUgbW9uZXkgYW5kIHByZXN0aWdlLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkd1YXJkcyBjYW4gbWVkaWNhdGUgZmxleGlibHksIHdpdGggY29uY29jdGlvbnMgdG8gZW5oYW5jZSBwZXJjZXB0aW9uIChldmVuIHRvIHNlZSB0aGUgc3VwZXJuYXR1cmFsLCkgZ2FpbiBjb21iYXQgcHJvd2Vzcywgb3IgaGVhbC5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZWlyIHBlZGRsaW5nIG9mIGlsbGVnYWwgZHJ1Z3MgaGFzIG1hZGUgZW5lbWllcyBhbW9uZyBibHVlY29hdHMgYW5kIGluc3BlY3RvcnMuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGd1YXJkcyBhcmUganVua2llcy4gVGhlaXIgZW1wbG95ZXIgdXNlcyBhZGRpY3Rpb24gdG8gY29udHJvbCB0aGVtLCBrZWVwaW5nIHRoZW0gbmVhciB0aGUgZWRnZS4gVGhleSBhcmUgb2Z0ZW4gZGlzdHJhY3RpYmxlIG9yIHVuY29uc2Npb3VzLlwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlplYWxvdHNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJUd2lzdGVkIEd1YXJkc1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiR3VhcmRzIHNoYXJlIGEgcmVsaWdpb24gdGhhdCBiaW5kcyB0aGVtIHRvZ2V0aGVyIGFuZCBtYWtlcyB0aGVtIHJlc2lzdGFudCB0byBpbnRpbWlkYXRpb24gb3IgY29ycnVwdGlvbi5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEbyB0aGV5IHdvcnNoaXAgb25lIG9mIHRoZSBGb3Jnb3R0ZW4gR29kcz8gVGhlIENodXJjaCBvZiB0aGUgRWNzdGFzeSBvZiB0aGUgRmxlc2g/IFdlZXBpbmcgTGFkeT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIYXZlIHRoZXkgc3dvcm4gb2F0aHM/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hhdCBkb2VzIHJlbGlnaW9uIHJlcXVpcmUgdGhlbSB0byBoYXRlLCBvciB0byBsb3ZlP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGRlZmVuZGVkIHNpdGUgaW5jbHVkZXMgYSBzaHJpbmUgb3IgdGVtcGxlLiBWaW9sYXRpbmcgdGhlIHNpdGUgYW5nZXJzIG9mZmVuZGVkIHdvcnNoaXBwZXJzLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlNlcnZpbmcgYXMgYSBzaXRlIGd1YXJkaWFuIGlzIHBhcnQgb2YgYSByZWxpZ2lvdXMgZHV0eS4gVW5leHBlY3RlZGx5IHNlYXNvbmVkIHdhcnJpb3JzIG9yIGltcG9ydGFudCBwZW9wbGUgbWF5IHNlcnZlIGFzIGxvd2x5IGd1YXJkcyBmb3IgYSB0aW1lLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiTWFuZGF0b3J5IHByYXllciB0aW1lcywgdW5jbGVhbiBvYmplY3RzIG9yIHBsYWNlcyBsZWZ0IHVuaW5zcGVjdGVkLCBhbmQgcmVzdHJpY3RlZCBhcmVhcyBtYXkgY3JlYXRlIGhvbGVzIGluIHNlY3VyaXR5LlwiLFxuICAgICAgICAgICAgICAgICAgICBcIkVuZW1pZXMgb2YgdGhlaXIgcmVsaWdpb24gbWF5IG9mZmVyIGhlbHAgdG8gZW1iYXJyYXNzLCBkaXNjcmVkaXQsIG9yIGluanVyZSB0aGUgemVhbG90cy5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJHaG9zdHBvcnQgTG9ja1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIldlaXJkIFRlY2hcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIktleXMgYXJlIHR1bmVkIHRvIGxvY2tzIHRoYXQgY2Fubm90IGJlIHBpY2tlZCBieSBub3JtYWwgbWVhbnMsIG9yIGJ5cGFzc2VkIHdpdGhvdXQgd2hpc3BlciBleHBlcnRpc2UuIFRoZWlyIGFjY2VzcyBwb2ludCBpcyBpbiB0aGUgR2hvc3QgRmllbGQgdW50aWwgdGhlIGtleSBpcyBwcmVzZW50LlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIkFyZSB0aGVzZSBsb2NrcyBtb2RlbSBzY2llbnRpZmljIHRyaXVtcGhzLCBvciBvbGQgYXJjYW5lIGRlZmVuc2VzP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIkRvZXMgaGUga2V5IGxvb2sgbGlrZSBhIGtleSwgb3IgZG9lcyBpdCBsb29rIGxpa2UgYSBtaXNzaW5nIGRlY29yYXRpb24sIG9yIGEgZ2VtP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIklzIHRoZSBrZXkgcGh5c2ljYWwsIG9yIGVuZXJneSwgbGlrZSBsaXZpbmcgYmxvb2Qgb2YgdGhlIHJpZ2h0IGZhbWlseT9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBsb2NrcyBhcmUgaGlkZGVuIGFuZCB0cmFwcGVkLiBNZXNzaW5nIHdpdGggdGhlIGxvY2sgY291bGQgaG9sbG93IHRoZSBpbnRydWRlciAodGVhcmluZyB0aGUgc3Bpcml0IG91dCBvZiB0aGUgYm9keSkgb3Igb3RoZXIgdW5wbGVhc2FudG5lc3MuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHByZWNpc2UgbG9jYXRpb24gb2YgdGhlIGxvY2sgbXVzdCBiZSBrbm93biwgYW5kIGl0IGlzIG5vdCBuZWFyIHdoYXQgaXQgaXMgbG9ja2luZy5cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0Vhc2llcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBnaG9zdHBvcnQgbG9jayBoYXMgYmVlbiBhIGZhZCBzZXZlcmFsIHRpbWVzIGluIER1c2t3YWxsLiBFYWNoIHRpbWUsIHRoZXJlIHdhcyBzb21lIG1hc3MgcHJvZHVjdGlvbiwgYW5kIGEga2V5IHRvIGEgc2ltaWxhciBsb2NrIG1pZ2h0IHdvcmsgd2l0aCBhIGxpdHRsZSBoZWxwLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBvd25lciBtYXkgaGF2ZSBzdGlmZmVkIGEgd2hpc3BlciBsb2Nrc21pdGggb24gdGhlIGZlZSwgb3Igb3RoZXJ3aXNlIG9mZmVuZGVkIHRoZSBleHBlcnQsIHdobyBpcyBrbm93bGVkZ2VhYmxlIGFuZCBkaXNncnVudGxlZC5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMaWdodG5pbmcgV2FsbHNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJXZWlyZCBUZWNoXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJSdW5pYyBlbmVyZ3kgdHdpc3RpbmcgdGVjaG5vbG9neSBjYW4gbWFrZSBweWxvbnMgdGhhdCBwcm9qZWN0IGEgY3VydGFpbiBvZiBlbmVyZ3kgYmV0d2VlbiB0aGVtLiBUaGUgZ2xvd2luZyB3YWxscyBhcmUgdHJhbnNwYXJlbnQsIGJ1dCBjcmlwcGxpbmcgdG8gdG91Y2ggYW5kIGxldGhhbCB0byBwYXNzIHRocm91Z2guIFRoZXkgc3RvcCBwcm9qZWN0aWxlcy5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIHRoZSBzaXRlIGhhdmUgdGhlIHRlY2hub2xvZ3kgbGVnYWxseSwgb3IgaXMgaXQgc3RvbGVuP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIk1heWJlIGNvYmJsZWQgdG9nZXRoZXIgZnJvbSBsZWZ0b3ZlcnMgYnkgYSBtYWQgYWxjaGVtaXN0P1wiLFxuICAgICAgICAgICAgICAgICAgICBcIklzIGl0IG9uIGFsbCB0aGUgdGltZSAoZXhwZW5zaXZlIHRvIGZ1ZWwpIG9yIG9ubHkgaWYgdGhlIGFsYXJtIGlzIHJhaXNlZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXaGVyZSBhcmUgdGhlIGZ1ZWwgY2VsbHMga2VwdD9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBlcXVpcG1lbnQgaXMgcHJvcGVybHkgaW5zdGFsbGVkLCBpdHMgdnVsbmVyYWJsZSBwYXJ0cyBiZWhpbmQgdGhlIGVuZXJneSBjdXJ0YWluLCBkaXJlY3RseSBndWFyZGluZyB3aGF0IG5lZWRzIHByb3RlY3RpbmcuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGxpZ2h0bmluZyB3YWxscyBhdHRyYWN0IGxvb3NlIHNwaXJpdHMsIGludHJ1ZGVycyBtYXkgYWxzbyBoYXZlIHRvIGNvbnRlbmQgd2l0aCBjb25mdXNlZCBnaG9zdHMuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgd2FsbHMgZ3VhcmQgYSBmZXcga2V5IGFjY2VzcyBwb2ludHMsIGJ1dCB0aGVyZSBhcmUgbXVsdGlwbGUgd2F5cyBhcm91bmQuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIHdhbGxzIGFyZSBpbnN0YWxsZWQgcG9vcmx5LCBzbyB0aGVpciBtYWNoaW5lcnkgaXMgdnVsbmVyYWJsZSBmcm9tIHRoZSBvdXRzaWRlIHdoaWxlIGl0IGlzIG9uLiBJZiBubyBvdGhlciBndWFyZHMgYXJlIHByZXNlbnQsIHRoZXkgY2FuIGJlIHdyZWNrZWQuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiUGFub3B0aWNvblwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIldlaXJkIFRlY2hcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlNwZWNpYWwgY3J5c3RhbCBsZW5zZXMgdHJhbnNtaXQgdGhlaXIgc2lnaHQgdGhyb3VnaCB0aGUgR2hvc3QgRmllbGQgdG8gbWlycm9ycyBpbiBhIGNlbnRyYWwgbG9jYXRpb24uIEZyb20gb25lIHBsYWNlLCBhIGd1YXJkaWFuIGNhbiBtb25pdG9yIHZpZXdzIGFsbCBvdmVyIHRoZSBkZWZlbmRlZCBzaXRlLlwiLFxuICAgICAgICAgICAgICAgIHF1ZXN0aW9uczogW1xuICAgICAgICAgICAgICAgICAgICBcIklzIHRoaXMgbmV3IGluZHVzdHJpYWwgYWxjaGVtaWNhbCB0ZWNobm9sb2d5LCBvciBhbiBhbmNpZW50IGVuY2hhbnRlZCBjb25zdHJ1Y3Rpb24/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiRG9lcyB0aGUgY3VycmVudCBvd25lciBrbm93IGhvdyB0byBnZXQgdGhlIG1vc3QgZnVuY3Rpb25hbGl0eSBvdXQgb2YgaXQ/XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiV2hvIG1haW50YWlucyB0aGUgc3lzdGVtP1wiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzSGFyZGVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGxlbnNlcyBhcmUgaGlkZGVuIGluIG1pcnJvciBmcmFtZXMsIHN0YXR1ZXMsIGFuZCBvdGhlciBkZWNvci4gVGhleSBhcmUgZGlmZmljdWx0IHRvIHNwb3QuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGxlbnNlcyBjYW4gc2VlIGludG8gdGhlIEdob3N0IEZpZWxkIGFzIHdlbGwsIG9ic2VydmluZyBnaG9zdHMgb3Igb2NjdWx0IHdvcmssIGFuZCBsaWZlIGZvcmNlLlwiXG4gICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICBtb2RzRWFzaWVyOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGd1YXJkaWFucyB3YXRjaGluZyB0aGUgbWlycm9ycyBhcmUgc29tZXdoYXQgbGF4LlwiLFxuICAgICAgICAgICAgICAgICAgICBcIk92ZXIgdGltZSwgbWFueSBsZW5zZXMgaGF2ZSBub3QgYmVlbiByZXBsYWNlZCBvciByZXBhaXJlZC4gVmlld3MgYXJlIGxpbWl0ZWQuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU2hhZG93IExhbnRlcm5zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgVGVjaFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiR3VhcmRzIGFyZSBlcXVpcHBlZCB3aXRoIGxhbnRlcm5zIHRoYXQgZGV0ZWN0IHNoYWRvd3Mgb2YgcmVjZW50IGxpZmUgZm9yY2UgYXMgd2VsbCBhcyBzaGVkZGluZyBsaWdodC5cIixcbiAgICAgICAgICAgICAgICBxdWVzdGlvbnM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJBcmUgdGhlIGxhbnRlcm5zIHRyYWRpdGlvbmFsIGxhbnRlcm4gc2hhcGUsIG9yIGEgZ2xvd2luZyBiYWxsLCBvciBzb21ldGhpbmcgZWxzZT9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIGFuIGV4cGVydCBrZWVwIHRoZSBndWFyZGlhbnMgc3VwcGxpZWQsIG9yIGlzIHRoZWlyIHN1cHBseSBqZWFsb3VzbHkgZ3VhcmRlZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJEb2VzIGl0IGNvc3QgdGhlIGd1YXJkcyBzb21ldGhpbmcgdG8gYWN0aXZhdGUgdGhlIGxhbnRlcm5zP1wiLFxuICAgICAgICAgICAgICAgICAgICBcIldpbGwgdGhlIGxhbnRlcm5zIHdvcmsgaWYgdGFrZW4gb2ZmLXNpdGU/XCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNIYXJkZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJHdWFyZHMgYXJlIHRyYWluZWQgdG8gdHVuZSBpbnRvIHRoZSBsaWZlIGZvcmNlIGVuZXJneSB0byBhbHNvIGhlYXIgY29udmVyc2F0aW9ucyBvZiB0aGUgbGlmZSBzaGFkb3dzLiBHdWFyZHMgY2FuIHR1bmUgaW50byB0aGUgbGlmZSBmb3JjZSBlbmVyZ3kgdG8ga25vdyB0aGUgb3duZXIncyBjdXJyZW50IGxvY2F0aW9uLCBpZiBpbiB0aGUgZGVmZW5kZWQgYXJlYS5cIixcbiAgICAgICAgICAgICAgICAgICAgXCJVbnRlbmRlZCBsYW50ZXJucyBjYW4gYmUgc2V0IHRvIHRyYW5zbWl0IGRldGVjdGlvbiBvZiBhIGxpZmUgZm9yY2UgdG8gYSBuZWFyYnkgZ3VhcmRpYW4uXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGUgbGFudGVybnMgY2FuIGJlIHJlbmRlcmVkIGJsaW5kIGJ5IHByb3Blcmx5IHR1bmluZyBhIHNwaXJpdGJhbmUgY2hhcm0gd2hpbGUgbmVhciBvbmUuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiRXZlcnkgc3VucmlzZSB3aXBlcyBhbGwgdHJhY2VzIG9mIHBhc3QgbGlmZSBmb3JjZXMsIGFuZCB0aGV5IG9ubHkgd29yayBhdCBuaWdodC5cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTaGFkb3cgUm9vbXNcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJXZWlyZCBUZWNoXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgR2hvc3QgRmllbGQgc29tZXRpbWVzIHJlbWVtYmVycyByb29tcyBvciBlbnRpcmUgbmVpZ2hib3Job29kcyB0aGF0IG5vIGxvbmdlciBleGlzdCBpbiB0aGUgbWF0ZXJpYWwgd29ybGQuIFNvbWUgZGVmZW5kZWQgc2l0ZXMgaGlkZSB0cmVhc3VyZXMgaW4gdGhlc2Ugc3BhY2VzIHRoYXQgY2FuIG9ubHkgYmUgYWNjZXNzZWQgaWYgeW91IGtub3dob3cuXCIsXG4gICAgICAgICAgICAgICAgcXVlc3Rpb25zOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiSG93IGFyZSBjb2xvcnMgZGlmZmVyZW50IGluIHRoZXNlIHNoYWRvdyByb29tcz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJJcyB0aGVyZSBhIHNtZWxsIG9yIHNvdW5kIHRoYXQgbGluZ2Vycz9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJIb3cgZG9lcyBpdCBmZWVsIHRvIHN0ZXAgb3V0IG9mIHRoZSBtYXRlcmlhbCB3b3JsZD9cIixcbiAgICAgICAgICAgICAgICAgICAgXCJXaGF0IG5hdHVyYWwgbGF3cyB3b3JrIGRpZmZlcmVudGx5IGhlcmUsIGxpa2UgZmlyZSBub3QgZmxpY2tlcmluZz9cIlxuICAgICAgICAgICAgICAgIF0sXG4gICAgICAgICAgICAgICAgbW9kc0hhcmRlcjogW1xuICAgICAgICAgICAgICAgICAgICBcIlRoZSBhY2Nlc3MgcG9pbnQgdG8gdGhlIHNoYWRvdyByb29tcyBpcyBhbiBlbmNoYW50ZWQgbG9jaywgaXRzIGxvY2F0aW9uIGlzIGtub3duIGFuZCBndWFyZGVkLlwiLFxuICAgICAgICAgICAgICAgICAgICBcIlRoZSBzaGFkb3cgcm9vbXMgYXJlIG9ubHkgY29ubmVjdGVkIHRvIHRoZSBtYXRlcmlhbCB3b3JsZCBhIGZldyB0aW1lcyBhIHllYXIsIG9yIGxlc3MuXCJcbiAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgIG1vZHNFYXNpZXI6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJUcmFuc2l0aW9uaW5nIGZyb20gdGhlIG1hdGVyaWFsIHdvcmxkIHRvIHRoZSBzaGFkb3cgcm9vbXMgaW52b2x2ZXMgY2VydGFpbiBwcm9zY3JpYmVkIG1vdmVtZW50czsgY3Jvc3MgdGhlIGNvdXJ0eWFyZCB0aHJlZSB0aW1lcywgdGhlbiBiYWNrIGRvd24gc3RhaXJzIHdpdGggZXllcyBjbG9zZWQgKGZvciBleGFtcGxlLikgVG9vIG1hbnkgcGVvcGxlIGtub3cgdGhlIGZvcm11bGEuXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiVGhlIGN1cnJlbnQgc2l0ZSBvd25lcnMgZG8gbm90IGtub3cgdGhlc2Ugcm9vbXMgZXhpc3QuXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9XG4gICAgICAgIF0sXG4gICAgICAgIE5QQ3M6IFtcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkFydHVybyBNb250YXN0aWNcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiQWRkaWN0ZWQgR2FtYmxlclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk5ldyBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkhlIGlzIGltcG9zc2libHkgbHVja3kuIEhlIHdpbnMgZW5vdWdoIGF0IGdhbWVzIG9mIGNoYW5jZSB0byBwYXkgZm9yIGhpcyBhZGRpY3Rpb25zLCBhbmQgdG8gdHJlYXQgdGhlIGNvbnNlcXVlbmNlcyAodHJhbnNmdXNpb25zLCB0cmFuc3BsYW50cywgY3V0dGluZy1lZGdlIHRyZWF0bWVudHMuKSBIaXMgcmVsYXRpb25zaGlwcyBhcmUgaW50ZW5zZSBidXQgYnJpZWYuIEhlIG9mdGVuIGxvc2VzIGV2ZXJ5dGhpbmcsIGJ1dCB0aGVuIHdpbnMgaXQgYWxsIGJhY2sgYW5kIG1vcmUuIEhlIGhhcyBvd25lZCBlcGljIHRyZWFzdXJlcyBtYW55IHRpbWVzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIlJpc2stYXZlcnNlIGNvbGxlY3RvcnMgY2Fubm90IGJlYXIgaGlzIGNhdmFsaWVyIGF0dGl0dWRlIG9uIHdpbm5pbmcgYW5kIGxvc2luZyBwcmljZWxlc3MgYXJ0LiBIZSBkb2VzIG5vdCB0cnVseSBhcHByZWNpYXRlIGhpcyB0cmVhc3VyZXMsIGFuZCBzaG91bGQgbm90IGJlIHRydXN0ZWQgd2l0aCB0aGVtLiBMb3NlcnMgY2FuIHRha2UgdGhlaXIgbG9zc2VzIGhhcmQuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJCYXJvbiBLZWx5ciBTdHJhdGhtaWxsXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkhhcmRlbmVkIEluZHVzdHJpYWxpc3RcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJPbGQgTW9uZXlcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJIaXMgZmFtaWx5IGhhcyBjb250cm9sbGVkIHRoZSBkb2NrcyBmb3IgbWFueSBnZW5lcmF0aW9ucy4gVGhleSBxdWlldGx5IGRlc3Ryb3kgY29tcGV0aXRpb24sIGFuZCBnZXQgbHVjcmF0aXZlIGNpdHkgY29udHJhY3RzIHRvIHJlLWRldmVsb3AgYmxpZ2h0ZWQgYXJlYXMgaWYgdGhlIG1vbmV5IHNsb3dzIGRvd24uIEdyYWNlZnVsLCBlZHVjYXRlZCwgYW5kIHBsZWFzYW50LCBoZSBpcyBydXRobGVzcyBhcyBiYXJiZWQgc3RlZWwgdW5kZXIgYSBjdWx0dXJlZCB2ZW5lZXIuIEhlIGlzIHByb3VkIG9mIGhpcyBlc3RhdGUncyBnYXJkZW5zLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkNvbXBldGl0aW9uIGRvZXNuJ3QgbGlrZSBiZWluZyBjcmlwcGxlZC4gSGUgb2Z0ZW4gaGlyZXMgb3V0c2lkZXJzIGZvciB0aGUgZGlydGllc3Qgd29yaywgYW5kIGhpcyB2aWN0aW1zIG9mdGVuIGhpcmUgb3V0c2lkZXJzIHRvIGdldCByZXZlbmdlLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQmFyb25lc3MgVGhlbmEgSGVsbHllcnNcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiSGF6eSBBcnQgUGF0cm9uXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiT2xkIE1vbmV5XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiVGhlbmEgaXMgb25lIG9mIHRoZSBsZWFzdCBlbW90aW9uYWxseSBzY2FycmVkIHN1cnZpdm9ycyBpbiBoZXIgd2VpcmQgZmFtaWx5LiBTaGUgaXMgYSBsZWFkaW5nIGxpZ2h0IGluIHRoZSBhcnQgd29ybGQuIFNoZSBpcyBwYXRyb24gdG8gbWFueSBhcnRpc3RzIGFuZCBoZXIgY3JpdGljaXNtIGFuZCBldmFsdWF0aW9uIGRyaXZlcyBhIHNpZ25pZmljYW50IGVsZW1lbnQgb2YgRHVza3dhbGwncyBhcnQgc2NlbmUuIFdoaXNwZXJzIGhhdmUgbm90ZWQgc2hlIGhhcyBhbiB1bnVzdWFsIGNvbm5lY3Rpb24gdG8gdGhlIEdob3N0IEZpZWxkLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIlNvbWV0aW1lcyBzaGUgaGlyZXMgb3V0c2lkZXJzIHRvIHNvcnQgb3V0IG9uZSBvZiBoZXIgYXJ0aXN0cycgcHJvYmxlbXMuIFNoZSBoYXMgYSBwcml2YXRlIGdhbGxlcnkgdGhhdCBzaGUgdXBkYXRlcyB3aXRoIGhlciBjdXJyZW50IHRyZW5kaW5nIHRhc3Rlc+KAlHRob3NlIGluIHRoZSBhcnQgbWFya2V0IG5lZWQgdG8ga25vdyB3aGF0J3MgaW4gaXQuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJDYWx2aW4gRGFubm9zXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkVlcmllIEFzc2Fzc2luXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRoZSBJbmt2ZWluIHdhcyBhIGNhYmFsIG9mIHNldmVuIGFub255bW91cyBhc3Nhc3NpbnMsIG5hbWVkIGZvciB0aGVpciBtYXBzIG9mIHRoZSBjYW5hbHMuIElmIG9uZSBvZiB0aGVtIHdhcyBpZGVudGlmaWVkIGFzIGEgbWVtYmVyLCB0aGUgb3RoZXIgc2l4IHdlcmUgc3dvcm4gdG8ga2lsbCB0aGUgb3V0ZWQgYXNzYXNzaW4uIERhbm5vcyB3YXMgb3V0ZWQgYSBkZWNhZGUgYWdvLCBhbmQgaGUga2lsbGVkIHRoZSBvdGhlciBtZW1iZXJzIGFuZCB0aGVpciB1bmR5aW5nIGZvdW5kZXIuIE5vdyBoZSBJUyBJbmt2ZWluLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkVhc2lseSBib3JlZCwgaGUgcHJlZmVycyBpbnRlcmVzdGluZyBjaGFsbGVuZ2VzIHRvIGhpZ2ggcGF5aW5nIG9yIGVhc3kga2lsbHMuIE9mIGNvdXJzZSwgbWFueSBiZXJlYXZlZCBvciBwb3dlciBodW5ncnkgaW5kaXZpZHVhbHMgd2FudCBoaW0gZGVhZC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNvbW1pc3Npb25lciBOYXJpYSBIYWlnXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIlBvbGl0aWNhbCBNYXRjaG1ha2VyXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiQ2l0eSBMYXdcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTaGUgZXh1ZGVzIGEgcGx1bXAgZ3JhbmRtb3RoZXJseSBpbm5vY2VuY2UsIGJ1dCBzaGUgaXMgb25lIG9mIHRoZSBzaGFycGVzdCBwb2xpdGljaWFucyBpbiBEdXNrd2FsbC4gU2hlIHN1cGVydmlzZXMgb3ZlciB0aGUgbWVyZ2luZyBvZiB1bmV4cGVjdGVkIGFsbGllcyBhbmQgdGhlIHNjaGlzbSBvZiBtb25vbGl0aGljIGludGVyZXN0cy4gU2hlIGNhcmVzIGFib3V0IG9uZSB0aGluZ+KAlHRoZSBnb29kIG9mIER1c2t3YWxsIGFzIGEgd2hvbGUuIFNoZSBpcyBDaGFpciBvZiB0aGUgRXRoaWNzIE92ZXJzaWdodCBDb21taXR0ZWUuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiQWx3YXlzIHBsYXlpbmcgYSBiaWdnZXIgZ2FtZSwgc2hlIHVzZXMgb3V0c2lkZXJzIHRvIG1hbmFnZSBlcnJhbmRzIHdob3NlIHB1cnBvc2UgdGhleSBjYW5ub3Qgc2VlLiBUaG9zZSBzaGUgb3V0bWFuZXV2ZXJzIHRlbmQgdG8gd2FudCB0byBnZXQgYmFjayBhdCBoZXIgd2l0aCB2aW9sZW5jZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkRvYyBTYXJuaW5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiTGVjaGVyb3VzIExlZWNoXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkRvYyBjYW4ga2VlcCBsaWZlIGluIHlvdSBpZiB5b3UncmUgYWxpdmUgKG9yIHJlY2VudGx5IGRlYWQpIHdoZW4geW91IGdldCB0byBoaW0uIEhpcyBleHRyZW1lIG1ldGhvZHMgYXJlIG9mdGVuIGhvcnJpZnlpbmcuIFN0aWxsLCBoaXMgY29uY29jdGlvbnMgY2FuIGNydXNoIGdob3N0cywgcmUtYXR0YWNoIGxpbWJzLCBhbmQgbW9yZS4gVGhlIENyb3dzLCBhIHRvdWdoIGNyZXcsIHByb3RlY3QgaGltLiBUaGV5IGdpdmUgaGltIHZpY3RpbXMgZm9yIGhpcyBcXFwibmVlZHMsXFxcIiB3aGljaCBhcmUgZW1vdGlvbmFsLCBwaHlzaWNhbCwgYW5kIHNjaWVudGlmaWMuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiU29tZXRpbWVzIHRoZSBDcm93cyBoaXJlIG91dHNpZGVycyB0byBnbyBhZnRlciByYXJlIGNvbXBvbmVudHMgb3IgdmljdGltcyBmb3IgRG9jLiBIZSBoYXMgbWFueSwgbWFueSBlbmVtaWVzIHdobyB3YW50IHRvIGVpdGhlciBzdGVhbCBoaW0gYW5kIGZvcmNlIGhpbSB0byBzZXJ2ZSB0aGVtLCBvciBwdW5pc2ggaGltLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRG9jdG9yIEl4aXQgQ3JpY2hlbGxlXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkVsZWdhbnQgU3Bvb2tcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJPbGQgTW9uZXlcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJDcmVjaGVsbGUgY2FsbHMgaGltc2VsZiBhbiBPbmVpcmljIE1hc3Rlci4gSGUgaW50ZXJwcmV0cyBkcmVhbXMgZm9yIGEgZmVlLiBIZSBlbnRlcnMgdGhlbSwgYWx0ZXJzIHRoZW0sIGFuZCBtb3ZlcyB0aHJvdWdoIHZlaWxzIHRvIHVuZGVyc3RhbmQgdHJ1dGhzIGFuZCBzZWNyZXRzIHRoZSBkcmVhbWVyIG1heSBub3QgZ3Jhc3AuIElmIGhlIHRvdWNoZXMgYSB0YXJnZXQsIG9yIG9uZSBvZiB0aGVpciBwb3NzZXNzaW9ucywgaGUgbWF5IGVudGVyIHRoZWlyIGRyZWFtcy4gSGUgYXBwZWFycyBmZWVibGUsIGJ1dCBoaXMgbWluZCBpcyBkZWFkbHkuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiQXJpc3RvY3JhdGljIHBhdHJvbnMgaW52aXRlIGhpbSB0byBwYXJ0aWVzLiBIZSBuZWVkcyBhIHBlcnNvbidzIHBvc3Nlc3Npb24gdG8gc2VlIGludG8gdGhlaXIgZHJlYW1zOyBoZSBwYXlzIGZvciBvYmplY3RzIHRvIHZpc2l0IHNvbWUgcGVvcGxlJ3MgZHJlYW1zLiBWaWN0aW1zIHdpbGwgcGF5IHRvIGZyZWUgdGhlbXNlbHZlcyAuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJEci4gSGFuc2VsIEtyeXZhbm50aWNcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiQnJpbGxpYW50IFNjaWVudGlzdFwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIkZvcmVpZ25cIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJIZSBpcyBTZXZlcm9zaSwgYm93LWxlZ2dlZCBhbmQgd2lsZC1oYWlyZWQuIEhpcyB3b3JrIG9uIGVsZWN0cm9wbGFzbWljIHBvaXNvbmluZyBhbmQgbXV0YXRpb24gaW4gYW5pbWFscyBhbmQgaHVtYW5zIGlzIGdyb3VuZC1icmVha2luZy4gRmxlZWluZyBwZXJzZWN1dGlvbiBiZWNhdXNlIG9mIGhpcyBldGhpY2FsbHkgcXVlc3Rpb25hYmxlIG1ldGhvZHMgYmFjayBpbiBTZXZlcm9zLCBoZSBmb3VuZCBhIG1vcmUgb3Blbi1taW5kZWQgc2NpZW50aWZpYyBjb21tdW5pdHkgaW4gRHVza3dhbGwuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiSGlzIHJlc2VhcmNoIGhhcyBhcHBsaWNhdGlvbnMgaW4gYXJ0LCBtZWRpY2luZSwgYW5kIHdhci4gVGhvc2Ugd2l0aCBzdWZmaWNpZW50IHJlc291cmNlcyB0byBmdXJ0aGVyIGhpcyBzdHVkaWVzIHdhbnQgdG8gY29udHJvbCBoaW0uIEhlIGhhcyBodXJ0IGEgbG90IG9mIHBlb3BsZSwgb3ZlciB0aW1lLCBzbyBoZSBoYXMgbWFueSBlbmVtaWVzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRHIuIFllcmlhbCBDcmFiYnNraWRkaXRjaFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJTbGVhenkgTGF3eWVyXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiTmV3IE1vbmV5XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiSGUgZmlybWx5IGJlbGlldmVzIHRob3NlIHdobyBhcmUgd2VhbHRoeSBzaG91bGQgbm90IGJlIHBlc3RlcmVkIHdpdGggdGhlIGxhdy4gTm8gbWF0dGVyIHdoYXQgeW91IGRvLCBpZiB5b3UgaGF2ZSBtZWFucyB5b3UgY2FuIGFycmFuZ2UgZm9yIGFuIGFsdGVybmF0ZSBzdG9yeSB0aGF0IGZhdm9ycyB5b3UuIERlYXRocywgZnJhdWRzLCByb2JiZXJpZXMsIGFuZCBvdGhlciBjcmltZXMgY2FuIGJlIHJlZHVjZWQgdG8gYSBmZXcgZmluZXMuIEhlIHRocm93cyBtb25leSBhdCBwcm9ibGVtcyB1bnRpbCB0aGV5IGRpc2FwcGVhci5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJIZSByb3V0aW5lbHkgaGlyZXMgb3V0c2lkZXJzIHRvIGRlc3Ryb3kgZXZpZGVuY2UsIGludGltaWRhdGUgd2l0bmVzc2VzLCBjb21wZWwgY29uZmVzc2lvbnMsIGFuZCBzbyBmb3J0aC4gSGUgaGFzIGNvdW50bGVzcyBlbmVtaWVzLCBib3RoIHRob3NlIHNlZWtpbmcganVzdGljZSBhbmQgZm9ybWVyIGNsaWVudHMgd2hvIHJhbiBvdXQgb2YgbW9uZXkuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJEdXZyZWwgdGhlIFNuYWtlXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkN1bm5pbmcgU211Z2dsZXJcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJGb3JlaWduXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiU2hlIGlzIFR5Y2hlcm9zaWFuLCB3aXRoIHRoZSBleWVzIGFuZCBob3JucyBvZiBhIGdvYXQuIFNuYWtlIHRhdHRvb3MgY29pbCBhcm91bmQgaGVyIGFybXMuIEV4b3RpYyBkcnVncyBmcm9tIHRoZSBEYWdnZXIgSXNsZXMgZmxvdyB0aHJvdWdoIGhlciBkaXN0cmlidXRpb24gbmV0d29yayBpbiBEdXNrd2FsbC4gU2hlIGhpcmVzIG91dHNpZGVycyB0byByZW1vdmUgc3R1YmJvcm4gcGVvcGxlIHdoaWxlIHNoZSBoYXMgYW4gYWxpYmksIG9yIHRvIHJldHJpZXZlIGRydWdzIG1pc3BsYWNlZCBhdCBpbmNyaW1pbmF0aW5nIGxvY2F0aW9ucy5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJJbnNwZWN0b3JzIGhhdmUgb3JkZXJzIGZyb20gdGhlIFNwaXJpdCBXYXJkZW5zIHRvIHRha2UgaGVyIGFsaXZlLCB0byBzdHVkeSBoZXIgdW5jYW5ueSBhYmlsaXR5IHRvIGZsZXggd2l0aCB0aGUgR2hvc3QgRmllbGQgZm9yIHN1cGVybmF0dXJhbCBzdGVhbHRoLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRHlsYXl6aWEgRmluY2hlc3RlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJGYXNoaW9uYWJsZSBXaGlzcGVyXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiTmV3IE1vbmV5XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiSGVyIGV4b3RpYyBsb29rcywgdGF0dG9vcywgYW5kIGJyaWdodCBncmVlbiBleWVzIGRyYXcgYXR0ZW50aW9uLiBTaGUgcG9wdWxhcml6ZWQgdGhpZ2gtaGlnaCBidWNrbGVkIGxlYXRoZXIgYm9vdHMgYW5kIHNwaXJpdCBiYW5lIGNob2tlcnMuIEhlciBvcGluaW9ucyBlY2hvIGluIGRyYXdpbmcgcm9vbXMgYWNyb3NzIHRoZSBjaXR5LiBQZW9wbGUgZW5qb3kgaGVyIGZldWQgd2l0aCB0aGUgQ2h1cmNoIG9mIHRoZSBFY3N0YXN5IG9mIHRoZSBGbGVzaC5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJXZWFsdGh5IGZpZ3VyZXMgaW4gdGhlIGZhc2hpb24gd29ybGQgcGF5IHRvcCB3aW4gZm9yIHNuZWFrIHBlZWtzIGF0IGhlciBjbG90aGluZyBkZXNpZ25zLiBIZXIgb3BpbmlvbnMgaW5mbGFtZSBtYW55IGVuZW1pZXPCrS1lc3BlY2lhbGx5IHRoZSBDaHVyY2guIFNoZSBoaXJlcyBvdXRzaWRlcnMgdG8gZ2V0IHJhcmUgY29tcG9uZW50cyBmb3IgaGVyIHJpdHVhbHMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJFbWVsaW5lIENvbGVidXJuXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIldlYXJ5IFJlZ3VsYXRvclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIkNpdHkgTGF3XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiU2hlIGluc3BlY3RzIGJ1aWxkaW5ncyBhbmQgcmVwb3J0cyB0byB0aGUgRHVza3dhbGwgQ291bmNpbCB3aGV0aGVyIHRoZXkgYXJlIHNvdW5kLCBhbmQgd2hldGhlciB0aGV5IHNlcnZlIHRoZSBwdXJwb3NlIGxpc3RlZCBvbiB0aGUgb3duZXIncyB0YXhhdGlvbiBmb3JtLiBTaGUgaXMgZnJvbnQtbGluZSBpbiB0aGUgdHVnLW9mLXdhciBiZXR3ZWVuIGNyaW1pbmFscywgcG9saXRpY2lhbnMsIGFuZCBub2JsZXMuIFNoZSBubyBsb25nZXIgY2FyZXMgYWJvdXQgdGhlIGdyZWF0ZXIgZ29vZC4gTm93IGl0J3MgYWJvdXQga2lja2JhY2tzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIlNoZSB0YWtlcyB0aGUgcGF0aCBvZiBsZWFzdCByZXNpc3RhbmNlIGluIGhlciBldmFsdWF0aW9ucywgc28gcGVvcGxlIHBheSB0byBtYWtlIHRoZWlyIHByZWZlcmVuY2UgZWFzaWVyIGFuZCBvdGhlciByb2FkcyBoYXJkZXIuIFNoZSBoaXJlcyBvdXRzaWRlcnMgZm9yIG9mZi10aGUtYm9va3MgY29tbXVuaWNhdGlvbiB3aXRoIHB1c2h5IGN1c3RvbWVycy5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkVyaWMgdGhlIFdoaXRlXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIlZpZ2lsYW50ZSBSZWJlbFwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIkZvcmVpZ25cIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGUgV2FyIG9mIFNrb3ZsYW4gVW5pdHkgaXMgb3ZlciwgYnV0IHRoaXMgc2xlbmRlciBtYW5pYWMgd2l0aCBhIGJydXNoeSBiZWFyZCBjYW4ndCBsZXQgaXQgZ28uIEhlIHBsYW5zIHRvIGRlc3Ryb3kgdGhlIGdvdmVybm1lbnQgYW5kIHR1cm4gRHVza3dhbGwgaW50byBhIFNrb3ZsYW4gY29sb255IHRvIHB1bmlzaCB0aGVtIGZvciB0aGUgZGVzdHJ1Y3RpdmUgd2FyLiBIZSB3YW50cyB0byBkaXNjcmVkaXQgYW5kIGRpc3J1cHQgdGhlIGdvdmVybm1lbnQgYXQgZXZlcnkgdHVybi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJIZSB0YXJnZXRzIGdhdmVybm1lbnQgb2ZmaWNpYWxzIGFzIGhpZ2ggdXAgYXMgaGUgY2FuIHJlYWNoLCBob3BpbmcgdG8gY2F1c2UgZW5vdWdoIHRyb3VibGUgdG8gbWFrZSB0aGUgZ292ZXJubWVudCB2dWxuZXJhYmxlIHRvIGNoYW5nZS4gSGUgaGFzIGdhdGhlcmVkIHplYWxvdHMsIGFuZCBoZSB1c2VzIG91dHNpZGVycyBmb3IgZGlzcG9zYWJsZSB3b3JrLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiR2kgQW5pcnUgR2Egb2YgU3VsdGhhXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIlNhY3JpZmljaW5nIEN1bHRpc3RcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJTdXBlcm5hdHVyYWxcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTaGUgd29yc2hpcHMgdGhlIEdhcGluZyBNYXcsIHRoZSBSdW5uZWwgb2YgTGlmZSwgdGhlIENvc21pYyBUaGlyc3QuIFNoZSBidWlsZHMgYSBjdWx0LCB0ZWFjaGluZyB0aGVtIHRvIGh1bnQgYW5kIGNvbmR1Y3Qgcml0dWFscy4gVGhlbiBzaGUgbW92ZXMgb24uIFdpdG5lc3NlcyB1bmVhc2lseSBkZXNjcmliZSBoZXIgc3VwZXJuYXR1cmFsIGFiaWxpdGllcywgaW5jbHVkaW5nIHNoYXBlc2hpZnRpbmcsIGZsaWdodCwga2lsbGluZyBwZW9wbGUgYnkgYXR0YWNraW5nIHRoZWlyIHNoYWRvd3MsIGFuZCBzbyBvbi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJCZXJlYXZlZCByZWxhdGl2ZXMsIHJpdmFsIGN1bHRpc3RzLCBhbmQgbGF3IGVuZm9yY2VycyBhbGwgd2FudCBoZXIgc3RvcHBlZC4gU2hlIGhpcmVzIG91dHNpZGVycyB0byB0aHJlYXRlbiwgbWlzZGlyZWN0LCBvciBraWxsIGxhdyBlbmZvcmNlbWVudC4gRGV0ZXJtaW5lZCBpbnNwZWN0b3JzIGNydXNoIGN1bHRzIHNoZSB0cmFpbmVkLCBuZWVkIGhlbHAgdG8gY2F0Y2ggaGVyLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSG9sdHogQ2xlcm1vbnRcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiUmVmb3JtZWQgQ2xlcmtcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJDaXR5IExhd1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkhlIHVzZWQgdG8gYmUgYSBmb3JnZXIuIEFmdGVyIGhlIHNlcnZlZCBzdGludCBpbiBwcmlzb24sIHNvbWUgcmVzcGVjdGFibGUgZmFtaWx5IGZyaWVuZHMgZ290IGhpbSBhIHBvc2l0aW9uIGFzIENpdHkgQ2xlcmsgZm9yIHRoZSB3aG9sZSBkaXN0cmljdC4gSGUgbWFuYWdlcyBjb3JyZXNwb25kZW5jZSBmb3IgcGVybWl0IHJlcXVlc3RzIGFuZCBvZmZpY2lhbCBub3RpY2VzLiBXaGVuIGNvcnJ1cHQgcGVvcGxlIGluc2lkZSBhbmQgb3V0c2lkZSB0aGUgc3lzdGVtIG5lZWQgdG8gYWRqdXN0IGV2aWRlbmNlLCB0aGV5IGNvbWUgdG8gaGltLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkppbHRlZCBjbGllbnRzIGNhbiBiZSB0aHJlYXRlbmluZywgbGVhZGluZyBoaW0gdG8gdGFrZSBzdGVwcyB0byBhZGp1c3QgdGhlaXIgYXR0aXR1ZGUgYnkgaGlyaW5nIG91dHNpZGUgaGVscC4gSGUncyBzbWFydGVyIHRoYW4gaGUgbG9va3MsIGFuZCBrbm93cyBob3cgdG8gYmFjayBwZW9wbGUgb2ZmLiBIZSBhbHNvIG1pZ2h0IGtub3cgdG9vIG11Y2guXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJJbnNwZWN0b3IgTG9yZXR0ZSBTYWxraGFcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiQ3J1c2FkaW5nIEluc3BlY3RvclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIkNpdHkgTGF3XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiU2hlIG5lZWRzIGFsbGllcyBpbiBoZXIgaG9wZWxlc3MgcXVlc3QgdG8gY2xlYW4gdXAgdGhlIGNpdHkuIENvcnJ1cHRpb24gaXMgZXZlcnl3aGVyZSwgY3JpbWUgcnVucyByYW1wYW50LCBhbmQgdGhlIGJsdWVjb2F0cyBzZXJ2ZSB0aGUgcG93ZXJmdWwgKG9uIGJvdGggc2lkZXMgb2YgdGhlIGxhdy4pIFNvbWUgdHJhZ2VkeSBpbiBoZXIgcGFzdCBwcm9wZWxzIGhlciBpbnRvIGEgc3VpY2lkYWwgZWZmb3J0IHRvIHJlc3RvcmUgXFxcInJ1bGUgb2YgbGF3LuKAnSBIZXIgcGVlcnMgbXVzZSBpdCBpcyBhIHNoYW1lIHNoZSB3aWxsIGRpZSB5b3VuZy5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJTaGUgY291bGQgYmUgaGVscGZ1bCBpZiBzaGUgZm9jdXNlcyBvbiB0aGUgcmlnaHQgYmFkIGd1eXPigJR5b3VyIGVuZW1pZXMuIFNoZSBjYW4ndCBiZSBib3VnaHQsIHNvIG1heWJlIHNvbWVvbmUgbmVlZHMgaGVyIGtpbGxlZCAob3Igb3RoZXJ3aXNlIG5ldXRyYWxpemVkLilcIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkplbW1hIERyb3BraWNrXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkZlbWluaXN0IFZpZ2lsYW50ZVwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIlVuZGVyd29ybGRcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTaGUgaXMgYSBsZWdlbmQgaW4gdGhlIFNldmVuIFNoYWxsb3dzIG5laWdoYm9yaG9vZC4gU2hlIGF0dGFja3MgbWVuIHdobyBhYnVzZSB3b21lbi4gU2hlIHN1cnZpdmVzIGJlY2F1c2Ugc2hlIGhhcyBmcmllbmRz4oCUYSBmZXcgYmx1ZWNvYXRzLCBhIGdhbmcgb2YgdGh1Z3MsIGFuZCBhIGdyYXRlZnVsIHB1YmxpYy4gU2hlIGNhcmVmdWxseSBwbGFucyBhdHRhY2tzIHRvIGh1cnQgYWJ1c2Vycy4gTGYgaGVyIHZpY3RpbXMgYWJ1c2UgYWdhaW4sIHRoZXkgYXJlIG11dGlsYXRlZCwgcGFja2VkIGxpa2UgbHVnZ2FnZSwgYW5kIHNoaXBwZWQgb3V0IG9mIHRvd24uXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiTWFueSBwb3dlcmZ1bCBtZW4gd291bGQgcGF5IGZvciByZXZlbmdlIG9uIEplbW1hLiBTb21ldGltZXMgc2hlIGhpcmVzIG91dHNpZGVycyB0byBoZWxwIG91dC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIktoZWxkYXJpYSBXaGlubmljaFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJJbXBsYWNhYmxlIERldmVsb3BlclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk5ldyBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNoZSBoYXMgYSB2aXNpb24gZm9yIGRldmVsb3BpbmcgdGhlIENyb3cncyBGb290IGRpc3RyaWN0LiBJdCB3aWxsIGJlIGRpdmlkZWQgYmV0d2VlbiBidXNpbmVzc2VzLCBlc3RhdGVzLCBhbmQgcGFya3MuIFRvIHJlYWxpemUgaGVyIHZpc2lvbiwgc2hlIGhhcyBiZWVuIHNlbGVjdGl2ZWx5IGJ1eWluZyByZWFsIGVzdGF0ZSBhbGwgYXJvdW5kIHRoZSBjaXR5LCBiYXJ0ZXJpbmcgZm9yIGxhbmQgaW4gQ3JvdydzIEZvb3QsIGFuZCB1c2luZyB3aGF0ZXZlciBwZXJzdWFzaW9uIGlzIG5lZWRlZCB0byBjb252aW5jZSBvd25lcnMgdG8gc2VsbCB0byBoZXIuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiU2hlIGhhcyBhbiBlc3RhdGUgd2hlcmUgc2hlIHN0b3JlcyBpbmR1Y2XCrW1lbnRzIG9mIGFsbCBzb3J0cywgYSB2YXJpZXR5IG9mIHRyZWFzdXJlIGRlc2lnbmVkIHRvIHBlcnN1YWRlIG93bmVycyB0byBzZWxsIGluIGV4Y2hhbmdlIGZvciB3aGF0IHRoZXkgd2FudCBtb3N0LiBUaGV5IHNheSB5b3UgY291bGQgZmluZCBhbG1vc3QgYW55dGhpbmcgdGhlcmUuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMYWR5IEFzaGx5biBUeXJjb25uZWxcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiRGVjYWRlbnQgRHVlbGlzdFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkZvciBjZW50dXJpZXMsIGFyaXN0b2NyYXRzIG9mIER1c2t3YWxsIGhhdmUgbGVhcm5lZCB0aGUgVHlyY29ubmVsIE1ldGhvZCBvZiBzd29yZHBsYXkgYW5kIHNlbGYgZGVmZW5zZS4gVGhlIFR5cmNvbm5lbCBmYW1pbHkgcHJvZHVjZXMgY291bnRsZXNzIHB1YmxpYyBzZXJ2YW50cyBhbmQgd2FycmlvcnPigJRidXQgYWxzbyBhIHNoYXJlIG9mIHNjb3VuZHJlbHMuIEFzaGx5bidzIHRyYWRlbWFyayBzdWl0ZSBvZiBtb3ZlcyBpcyB0byBkdWVsLCB3aW4sIGJlZCBzb21lb25lLCBhbmQgZHJpbmsgdG8gdW5jb25zY2lvdXNuZXNzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIllvdSdyZSBoaXJlZCB0byBqb2luIHRoZSBzcHkgZ2FtZSBpbiB0aGUgVHlyY29ubmVsIGZhbWlseS4gT3IsIHNvbWVvbmUgaXMgdGFyZ2V0aW5nIGhlci4gRWl0aGVyIHdheS4gV2F0Y2ggeW91ciBiYWNrLiBPdXRzaWRlcnMgaW4gdGhlIGdhbWVzIG9mIG5vYmxlcyBhcmUgdW5pZm9ybWx5IGV4cGVuZGFibGUuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMYWR5IENhbmRyYSBEdW52aWxcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiQ29ycnVwdCBGaXhlclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk9sZCBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkhlciBmYW1pbHkgYnVpbHQgSXJvbmhvb2sgUHJpc29uLiBIZXIgd2VhbHRoIGlzIGJ1aWx0IG9uIGdlbmVyYXRpb25zIG9mIHNoYWR5IGRlYWxzIHdpdGggaW5jYXJjZXJhdGVkIGFyaXN0b2NyYXRzIGFuZCBidXNpbmVzcyBvd25lcnMuIFNoZSBzZWVzIHRoZSB3b3JsZCBhcyBhIHJpZ2dlZCBnYW1lIGFuZCBoYXMgY29udGVtcHQgZm9yIGFueW9uZSB3aG8gZmluZHMgY29ycnVwdGlvbiBzaG9ja2luZyBvciBmaXhhYmxlLiBTaGUgaXMgdmFpbiwgcHJhY3RpY2FsLCBhbmQgcnV0aGxlc3MuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiU2hlIGhpcmVzIG91dHNpZGVycyB0byBjYXJyeSBvdXQgcHJvbWlzZXMgc2hlIG1hZGUgdG8gaW5tYXRlcy4gSGVyIGZhbWlseSBoYXMgY2FzdWFsbHkgd3JlY2tlZCByZXB1dGF0aW9ucyBhbmQgbGl2ZXMgb3ZlciBjZW50dXJpZXMsIGFuZCB0aGF0IGxlYXZlcyBhIHRyYWlsIG9mIHZlbmdlYW5jZSBzZWVrZXJzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTGFkeSBQb2xvbmlhIEJyb2dhblwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJEZXNpcmFibGUgRG93cnlcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJPbGQgTW9uZXlcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJTaGUncyB1Z2x5LCBzbWVsbHksIHN0dXBpZCwgYW5kIHJ1ZGUtLWFuZCBhbHNvIHRoZSBrZXkgdG8gdGhlIEJyb2dhbiBmb3J0dW5lLiBIZXIgbHVja3kgc3BvdXNlIHdpbGwgaGF2ZSBhY2Nlc3MgdG8gbWFzc2l2ZSB3ZWFsdGggYW5kIGluZnJhc3RydWN0dXJlIGFtb25nIHByb2Zlc3Npb25hbCBidWlsZGVycyBhbmQgc2hpcHdyaWdodHMgb2YgRHVza3dhbGwuIE9ubHkgaGVyIGF1bnQsIENFQ0lMSUEgRFVSV0lUSEUsIGxvb2tzIG91dCBmb3IgaGVyIGJlc3QgaW50ZXJlc3RzIHdpdGggc2hhcnAgZGlzYXBwcm92YWwuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiQnJvZ2FuIGhpcmVzIG91dHNpZGVycyB0byBwdW5pc2ggdGhvc2Ugd2hvIHNsaWdodCBoZXIsIG9yIHRvIGludmVzdGlnYXRlIHBvdGVudGlhbCBwYXJ0bmVycy4gU2hlIGNvbGxlY3RzIGZha2Ugd2lsbHMgcm9ndWVzIGhhdmUgcGxhbnRlZCBkdXJpbmcgYXNzYXNzaW5hdGlvbiBhdHRlbXB0cywgdHJ5aW5nIHRvIGxlYXZlIGhlciBmb3J0dW5lIHRvIHVzdXJwZXJzIC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxvcmQgQnJhbm9uIEtpbmNsYWl0aFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJSb21hbnRpYyBIb3JzZW1hblwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk9sZCBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkJyYW5vbiBsb29rcyBsaWtlIGEgaGVybyBmcm9tIGEgbGVnZW5kYXJ5IHN0b3J5LiBIZSBtYW5hZ2VzIHRoZSBmYW1pbHkncyBzdGFibGVzLCB0aGUgZmluZXN0IGhvcnNlcyBpbiBEdXNrd2FsbCAod2hlcmUgaG9yc2VzIGFyZSBhIHJhcmUgbHV4dXJ5LikgSGlzIHR1bXVsdHVvdXMgdHJ5c3RzIHdpdGggYm90aCBtZW4gYW5kIHdvbWVuIGFyZSBjb21tb24ga25vd2xlZGdlLiBCdXNpbmVzcyBzdWZmZXJzIGZyb20gaGlzIGltcHVsc2l2ZSByb21hbnRpYyBnZXN0dXJlcywgYnV0IGJlbmVmaXRzIGZyb20gaGlzIGNoYXJtLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkJyYW5vbiBzb21ldGltZXMgcmVmdXNlcyB0byBzZWxsIGhvcnNlcywgb3IgYnJlZWQgdGhlbSwgaWYgaGUgZGlzbGlrZXMgdGhlIGJ1eWVyLiBTb21lIGJ1eWVycyB3YW50IGFjY2VzcyB0byBob3JzZWZsZXNoIGFueXdheS4gSWYgaGlzIGhvcnNlcyBhcmUgYXR0YWNrZWQsIGhlIGhpcmVzIG91dHNpZGVycyB0byBnZXQgcmV2ZW5nZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxvcmQgQnVsd2FyZCBTa2lubmVzdGVyXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkdyZWVkeSBCYW5rZXJcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJOZXcgTW9uZXlcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGlzIHBvcnRseSBjdXJtdWRnZW9uIGRvZXMgYSBicmlzayB0cmFkZSBpbiByZWFsIGVzdGF0ZSB0aXRsZXMsIGJvdGggbGVuZGluZyBhbmQgZm9yZWNsb3NpbmcuIEhlIGlzIGFjdXRlbHkgYXdhcmUgb2YgdGhlIHZhbHVlIG9mIHByb3BlcnRpZXMgYW5kIGhvdyBuZWlnaGJvcnMgYWZmZWN0IHZhbHVlLiBIZSB0YWtlcyBwYXJ0aWN1bGFyIGdsZWUgaW4gZm9yZWNsb3Npbmcgb24gYXJpc3RvY3JhY3kgYW5kIHNldHRpbmcgdXAgdGhlIG5ld2x5IHJpY2ggaW4gYW5jaWVudCBlc3RhdGVzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIlNvbWV0aW1lcyBoZSBoaXJlcyBvdXRzaWRlcnMgdG8gc29sdmUgcHJvYmxlbXMgdGhhdCBoaXMgaGlyZWQgYmx1ZWNvYXRzIGFuZCBicmliZWQgY291bmNpbG1lbiBjYW5ub3QgbWFuYWdlLiBIZSBjb2xsZWN0cyBzY3VscHR1cmUgYnkgRHVza3dhbGwgYXJ0aXN0cy4gSGUgaGFzIHJ1aW5lZCB0aGUgbGl2ZXMgb2YgbWFueSBmb3JtZXJseSBpbmZsdWVudGlhbCBwZW9wbGUuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMb3JkIE9ybGFuIEJvb2tlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJJbnN1bGF0ZWQgTWFzdGVybWluZFwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk9sZCBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkVubnVpIGlzIGEgZGFuZ2VyIHRvIHRoZSB3ZWFsdGh5LiBCb29rZXIgZmlsbHMgaGlzIGRheXMgYnkgZ2F0aGVyaW5nIGludGVsbGlnZW5jZSBhbmQgcGxhbm5pbmcgaGVpc3RzLCB0aGVuIHNlbGxpbmcgdGhlIHBsYW5zIHRvIGFtYml0aW91cyBnYW5ncyB0aGF0IGxhY2sgaGlzIHBhdGllbmNlLCBleHBlcmllbmNlLCByZXNvdXJjZXMsIGFuZCBpbnNpZ2h0LiBUd2ljZSBhIG1vbnRoIGhlIGdvZXMgdG8gdGhlIG9wZXJhLCBhbmQgbWVldHMgdGhvc2Ugd2hvIGhhdmUgYXJyYW5nZWQgdG8gcHVyY2hhc2UgYSBzY29yZS5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJTb21ldGltZXMgdGhpbmdzIGdvIHdyb25nLCBhbmQgaXQgaXMgbmF0dXJhbCB0byBibGFtZSB0aGUgcGxhbm5lciBhbmQgd2FudCByZXZlbmdlLiBTb21ldGltZXMgYSB0YXJnZXQgd2FudHMgdG8gcHVuaXNoIHRob3NlIHdobyBhY3RlZCBhZ2FpbnN0IHRoZW0sIGV2ZW4gaWYgdGhlIGFjdCB3YXMgcGxhbm5pbmcuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNYXN0ZXIgU2xlbiBEYWxsaWNvcmVcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiUHJvdGVjdGl2ZSBHdWlsZGVyXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiTmV3IE1vbmV5XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiTWFzdGVyIERhbGxpY29yZSBpcyB0aGUgR3VpbGRtYXN0ZXIgZm9yIHRoZSBEb2NrZXIncyBHdWlsZC4gVGhleSBtb3ZlIGFsbCBjYXJnbyBvbiBhbmQgb2ZmIHNoaXBzLCBib2F0cywgYW5kIGdvbmRvbGFzLiBUaGVpciByb2xlIGlzIHByb3RlY3RlZCBieSBsYXcsIGFzIGFyZSB0aGUgZmVlcyB0aGV5IGNoYXJnZS4gVGhlIGd1aWxkIHVzZXMgbG93LWxldmVsIHZpb2xlbmNlIHRvIGRpc2NvdXJhZ2Ugbm9uLWd1aWxkIGxhYm9yZXJzIGFuZCBzbXVnZ2xlcnMuIEhvd2V2ZXIsIHNvbWUgY2hhbGxlbmdlcyByZXF1aXJlIHByb3BlciBzY291bmRyZWxzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkRhbGxpY29yZSBpcyBub3QgYWJvdmUgaGlyaW5nIG91dHNpZGVycyB0byBwdW5pc2ggcG93ZXJmdWwgcGF0cm9ucyBvZiBzbXVnZ2xlcnMgb3IgaWxsZWdhbCBkb2NrIHdvcmtlcnMuIEhpcyBwb3NpdGlvbiBvZiBwb3dlciBhbHNvIGdpdmVzIGhpbSBhY2Nlc3MgdG8gcmFyZSBhbnRpcXVpdGllcywgYm90aCBwdXJjaGFzZWQgYW5kIGFjcXVpcmVkLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTWluaXN0ZXIgRm91cnRlZW5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiR3J1bmd5IEZpeGVyXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRoZSBibGluZCBTa292bGFuZGVyIGhvbGRzIGNvdXJ0IG9uIHRoZSBkb2NrcywgbW92aW5nIGZyb20gb25lIGJhc2VtZW50IHRvIGFub3RoZXIuIEhlIGZhdm9ycyBiYWdneSBzaGlydHMsIHN0YWluZWQgdmVzdHMsIHNoaW55IGpld2VscnksIGFuZCBmcmF5aW5nIGxhY2UuIEhlIG9mdGVuIGFjdHMgdGhyb3VnaCBoaXMgbWFzc2l2ZSBib2R5Z3VhcmQgU2V2ZXJlbiBhbmQgaGlzIHdlZWR5IG1lc3NlbmdlciBUb3Jvay5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJIZSBpcyBjb25uZWN0ZWQgaW4gdGhlIFNrb3ZsYW5kZXIgcmVmdWdlZSBjb21tdW5pdHksIGFuZCBpbiBTa292bGFuLiBGb3IgYSBwcmljZSAoZWl0aGVyIHdlYWx0aCBvciBhbiBlcnJhbmQpIGhlIHdpbGwgc2hhcmUgaW5mb3JtYXRpb24gYWJvdXQgU2tvdmxhbmRlcnMuIEhlIG9mdGVuIGhpcmVzIG91dHNpZGVycyB0byBoYW5kbGUgc2Vuc2l0aXZlIHRhc2tzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTW9vbnNsaWRlciB0aGUgVGhpcmRcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiRWNjZW50cmljIEFydGlzdFwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIk5ldyBNb25leVwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNoZSBmZWVscyBtb29uIHBoYXNlcy4gSGVyIGZhbWlseSBwdXQgaGVyIGluIGFuIGFzeWx1bSBmb3IgYSBkZWNhZGUuIExhdGVyLCBzaGUgd29uIGhlciBmcmVlZG9tIGFuZCBpbmhlcml0ZWQgdGhlIGZhbWlseSBib290bWFraW5nIGZvcnR1bmUuIFNoZSBtYWtlcyBhcnQuIFNoZSB0cmllcyB0byBjb21tdW5pY2F0ZSBoZXIgbW9vbiBmZWVsaW5ncy4gU2hlIHVzZXMgb2lsIHBhaW50LCBnbGFzcyBibG93aW5nLCBzY3VscHR1cmUsIHNvbmcsIGFuZCBkYW5jZSBpbiBtdWx0aW1lZGlhIHJlY2l0YWxzIGFuZCBhcnQgcGllY2VzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkhlciBmYW1pbHkgYm91Z2h0IG5pY2UgdGhpbmdzIGJlZm9yZSB0aGV5IGFsbCBkaWVkIGFuZCBzaGUgaW5oZXJpdGVkIHRoZW07IHNoZSBpZ25vcmVzIG1vc3Qgb2YgaXQuIFNoZSBuZWVkcyBleHBlbnNpdmUgZXF1aXBtZW50IGFuZCBzdXBwbGllcyBmb3IgaGVyIGJpemFycmUgYXJ0IHNob3dzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiT2ZmaWNlciBNaWxvcyBQZW5kZXJ5blwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJDb3JydXB0IEJhaWxpZmZcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJDaXR5IExhd1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk1pbG9zIGhhcyBhY2Nlc3MgdG8gdHJpYWwgZXZpZGVuY2UsIGFuZCB0byBwcmlzb25lcnMgYXdhaXRpbmcgdHJpYWwuIEhlIGNhbid0IGdldCBwZW9wbGUgb3V0LCBidXQgaGUgY2FuIHNpbGVuY2UgdGhlbS4gSGUgaGFzIGEgbmV0d29yayBvZiBjb3JydXB0IHBlZXJzLCBqdWRnZXMsIGJsdWVjb2F0cywgYW5kIG90aGVycyBzbyBoZSBjYW4gdHJhZGUgZmF2b3JzIHRvIGFjY29tcGxpc2ggdGhlIGltcG9zc2libGUuIEh1Z2UgYW5kIGdyZWFzeSwgaGUgaXMgYnVpbHQgbGlrZSBhIGJ1bGwgYW5kIGhlIGVuam95cyB0aGUgc2NlbnQgb2YgZmVhci5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJDb250cm9sbGluZyBNaWxvcyBjb3VsZCBtZWFuIHByb3RlY3Rpbmcgb3Iga2lsbGluZyBzb21lb25lIGluIGJsdWVjb2F0IGN1c3RvZHkuIEFuIGVuZGxlc3Mgc3RyZWFtIG9mIHBlb3BsZSB3YW50IHJldmVuZ2Ugb24gaGltLCBhbmQgYSBtb3JlIHNlbGVjdCBncm91cCB3b3VsZCBsaWtlIHRvIGNvbnRyb2wgb3IgdXNlIGhpbS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk9mZmljZXIgVmVsZXJpcyBXYWx1bmRcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiSGVyb2ljIEJsdWVjb2F0XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiVGhlcmUgYXJlIGFjdHVhbGx5IHNvbmdzIGFib3V0IGhpbS4gSGUgaXMgdmVyeSBwb3B1bGFyLiBWZWxlcmlzIGlzIGEgc2tpbGxlZCBvcmF0b3IgKHRob3VnaCBoZSByZXRyZWF0cyBpbnRvIG1vZGVzdHkpIGFuZCBhIGNhbm55IGp1ZGdlIG9mIGNoYXJhY3RlciBhbmQgc2l0dWF0aW9ucy4gKEhlIGluc2lzdHMgaGUganVzdCB0cmllcyB0byBkbyB0aGUgcmlnaHQgdGhpbmcuKSBIaXMgb3BpbmlvbiBpcyBpbmZsdWVudGlhbCBpbiBoaXMgZGlzdHJpY3QuIEhlIGlzIHRydXN0ZWQgdG8gZ3VhcmQgdmFsdWFibGVzLiBIaXMgbW91c3RhY2hlcyBhcmUgaGlzIHByaWRlIGFuZCBqb3kuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiSGUgaGFzIG5vIGZhbWlseSwgYW5kIGhlIHNlZW1zIHRvIGJlIGFuIGlkZWFsaXN0LiBTb21lIHRyeSB0byBwZXJzdWFkZSBoaW0sIG90aGVycyB0cnkgdG8gdGhyZWF0ZW4gaGltLiBUaHJlYXRzIGRvbid0IHNlZW0gdG8gd29yay4gSGUgaGFzIGJlZW4ga25vd24gdG8gcXVpZXRseSBoaXJlIG91dHNpZGVycyB0byBnZXQganVzdGljZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlBlYmJsZXJcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiRGVtb24gU3B5XCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiU3VwZXJuYXR1cmFsXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiVGhpcyBlYXJ0aCBkZW1vbiBsb29rcyBsaWtlIGEgZmF0IG1hbiBidWlsdCBhcm91bmQgYSBib3VsZGVyIGd1dCwgbGVha2luZyBzYW5kIGZyb20gam9pbnRzLiBJdCBpcyBhYmxlIHRvIHNlZSBhbmQgaGVhciB0aHJvdWdoIHNhbmQsIGVhcnRoLCBhbmQgc3RvbmUgd2l0aGluIGEgcmFuZ2Ugb2YgbWlsZXMuIEl0IHdvcmtzIHdpdGggbm9uLWN1bHRpc3RzIHZvbHVudGFyaWx5LCBzZWxsaW5nIGluZm9ybWF0aW9uIGluIGV4Y2hhbmdlIGZvciByYWlkcyBpbnRvIHRoZSByYXJlIGFyZWFzIHByb3RlY3RlZCBmcm9tIGl0cyBwcnlpbmcuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiRG96ZW5zIG9mIHBvd2VyZnVsIHBlb3BsZSB3YW50IFBlYmJsZXIgYmFuaXNoZWQgb3Igcm9iYmVkLiBIb3dldmVyLCB0aGUgZGVtb24gaXMgYSBwZWVybGVzcyBpbmZvcm1hdGlvbiBleGNoYW5nZSwgdmFsdWFibGUgZXZlbiBpZiBpdCBpcyBkaWZmaWN1bHQgdG8gY29udHJvbC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNhaXRoZXJub25cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiRXhvdGljIEZlbmNlXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkhlIGRyYXBlcyBoaXMgcHl0aG9uLCBERUxHUkFBWiwgYXJvdW5kIGhpcyBuZWNrLiBIZSB3ZWFycyBhIHR1cmJhbiB3aXRoIGEgamV3ZWwgb24gaXQuIEhlIGlzIHdpbGxpbmcgdG8gYnV5IGFsbW9zdCBhbnl0aGluZywgbm8gbWF0dGVyIGhvdyBzdHJhbmdlLiBIZSBhbHNvIGtub3dzIHdoYXQgeW91IG5lZWQsIHNvbWV0aW1lcyBiZWZvcmUgeW91IGtub3cgeW91IG5lZWQgaXQuIEhpcyBiYXphYXIgdW5mdXJscyBiZWxvdyB0aGUgS2VubmluZ3RvbiBtYXJrZXQgaW4gYW4gYWJhbmRvbmVkIGdvbmRvbGEgZG9jay5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJIZSBwYXlzIHBlb3BsZSB0byBnZXQgdGhpbmdzIGZvciBoaW0sIHRoZW4gc2VsbHMgdGhlbSBhdCB0cmVtZW5kb3VzbHkgaW5mbGF0ZWQgcHJpY2VzIHRvIHRob3NlIGRlc3BlcmF0ZSB0byBoYXZlIHRoZW0uIFRoaXMgY2FuIGNhdXNlIGh1cnQgZmVlbGluZ3MgYW1vbmcgdGhlIGRlc3BlcmF0ZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNlcmxldmljYSB0aGUgQnJhbmRlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJTcHkgV2hpc3BlclwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIlVuZGVyd29ybGRcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJHYXVudCBhbmQgZnJpenplZCwgdGhpcyBmb3VsLXNtZWxsaW5nIFdoaXNwZXIgaGFzIGEgc2VjcmV0IHJpdHVhbCB0aGF0IGFsbG93cyBoZXIgdG8gY29udHJvbCBhbmQgc2VlIHRocm91Z2ggcmF0cyBzaGUgYnJhbmRzLiBTaGUgc2VsbHMgaGVyIHNlcnZpY2VzIGFzIGEgc3B5IG9yIHNpdGUgZ3VhcmRpYW4uIFNoZSBoYXMgc3Vydml2ZWQgYnkgcmV0cmVhdGluZyBpbnRvIHNsdW1zIGFuZCBzZXdlcnMgd2hlbiB0aHJlYXRlbmVkLCBhbmQgc3RyaWtpbmcgZnJvbSB0aGUgc2hhZG93cyB1bnRpbCBpdCBpcyBzYWZlIHRvIGVtZXJnZSBhZ2Fpbi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJTaGUgaXMgY2xvc2VseSB0aWVkIHRvIHRoZSBpbmZvcm1hdGlvbiBtYXJrZXRwbGFjZSwgYnV5aW5nIGFuZCBzZWxsaW5nIHNlY3JldHMuIFNoZSBvZnRlbiBoaXJlcyBvdXRzaWRlcnMgdG8gZGVhbCB3aXRoIGhlciBlbmVtaWVzIHRocm91Z2ggdGhlZnQgb3IgdmlvbGVuY2UsIGFuZCBzaGUgaXMgaW4gdHVybiBhIGZyZXF1ZW50IHRhcmdldC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNpciBNb3VybnNlbGxlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJBbmFyY2hpc3QgR2hvc3RcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJTdXBlcm5hdHVyYWxcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGlzIGdob3N0IHBvc3Nlc3NlcyBvbGQgbWVuIGZyb20gdGhlIERyYXltYWNoIEFzeWx1bSwgYnJlYWtpbmcgdGhlbSBvdXQgdG8gZmluZCBhbmQgaGlyZSBzY291bmRyZWxzIGZvciBvYnNjdXJlIHRhc2tzIHdpdGggbm8gaW5kZXBlbmRlbnQgcHVycG9zZS4gRXhhbXBsZXMgaW5jbHVkZSBraWxsaW5nIGFuIGluc2lnbmlmaWNhbnQgY2hhbmRsZXIgb3Igc3RlYWxpbmcgYSBzcGVjaWZpYyBzdG9uZSBmcm9tIGEgd2FsbCBpbiBhIG5vYmxlJ3MgZXN0YXRlLiBQYXltZW50IGlzIHRoZSBsb2NhdGlvbiBvZiBoaWRkZW4gdHJlYXN1cmUuXCIsXG4gICAgICAgICAgICAgICAgbm90ZXM6IFwiQSBkZWNhZGUgYWdvLCBhbiBhc3R1dGUgaW5zcGVjdG9yIGJlZ2FuIHBpY2tpbmcgb3V0IHRoZSBjb25uZWN0aW9uIGJldHdlZW4gZXJyYW5kcywgc2VlaW5nIGEgdmVyeSBsb25nIGFuZCB2ZXJ5IGRhbmdlcm91cyBnYW1lIHRvIHVuc2VhdCB0aGUgY2l0eSdzIHJ1bGVycyBlbWVyZ2luZy5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNpciBPbGVuIExsYW53b2xkXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIlBpcmF0aWNhbCBJbmR1c3RyaWFsaXN0XCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiTmV3IE1vbmV5XCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiSGUgaXMgdGhpbiBhbmQgbmVydm91cywgZWFzeSB0byB1bmRlcmVzdGltYXRlLiBIZSBzcGVjaWFsaXplcyBpbiBzdHJpcHBpbmcgZm9lcyBvZiB0aGVpciBhc3NldHMgYW5kIHRha2luZyBvdmVyIHRoZWlyIG9wZXJhdGlvbnMuIEhpcyBmYXRoZXIgd2FzIGEgYnV0bGVyLCBhbmQgaGUgZ3JldyB1cCBoYXRpbmcgYXJpc3RvY3JhdHMuIEhlIHVuZGVyc3RhbmRzIHBvd2VyIHN0cnVjdHVyZXMgYW5kIGNvcnJ1cHRzIHJldGFpbmVycy4gSGlzIHRvcCBhZ2VudCwgRWxsc2ZpZWxkZXIsIGlzIGEgYmVhdXRpZnVsIGFuZCBydXRobGVzcyB3b21hbi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJNYW55IHJ1aW5lZCBhcmlzdG9jcmF0cyAoYW5kIHRoZWlyIGFsbGllcykgaGF0ZSBEYW53b2xkIHBhc3Npb25hdGVseS4gSGUgZG9lcyBub3QgaGVzaXRhdGUgdG8gdXNlIGhpcyBhc3NldHMsIGxlZ2FsIGFuZCBvdGhlcndpc2UsIHRvIGRlZmVuZCBoaW1zZWxmIGFuZCBjcmlwcGxlIGhpcyBmb2VzLiBIZSBoaXJlcyBvdXRzaWRlcnMgdGhyb3VnaCBwcm94aWVzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU2lyIFRvY2tlciBGYXJyb3NcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiUHJhZ21hdGljIENvdW5jaWxtYW5cIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJDaXR5IExhd1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNvbWV0aW1lcyB0aGUgbGF3IHdvcmtzLCBhbmQgc29tZXRpbWVzIGl0IGRvZXNuJ3QuIFJlZ2FyZGxlc3MsIHRoZSBDb3VuY2lsIG11c3QgcnVsZSBhbmQgdGhlcmUgbXVzdCBiZSBvcmRlci4gU2lyIEZhcnJvcyBlbnN1cmVzIHRoZSBkaXN0cmljdHMgaGUgc2VydmVzIGRvIG5vdCBnZXQgdG9vIGZhciBvdXQgb2YgaGFuZCBiZWZvcmUgbGF3bGVzcyBlbGVtZW50cyBhcmUgY3VyYmVkLiBPbmUgd2F5IG9yIGFub3RoZXIuIEhlIGxvb2tzIGxpa2UgYW4gYWZmYWJsZSBncmFuZGZhdGhlciwgYnV0IGhlIGhhcyBhIGRhcmsgcGFzdC5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJTaXIgRmFycm9zIHVzZXMgaW5zcGVjdG9ycyBvciBzY291bmRyZWxzLCBwb2xpdGljaWFucyBvciBob3VzZW1haWRz4oCUYW55b25lIHdobyB3aWxsIGdldCB0aGUgam9iIGRvbmUuIEhlIGhhcyBhbiBlbmRsZXNzIGxpc3Qgb2YgZW5lbWllcyB3aG8gZmVlbCBoZSB3cm9uZ2VkIHRoZW0sIGFuZCB3YW50IHJldmVuZ2UuIEhpcyBhZ2VudHMgYXJlIGRpc3Bvc2FibGUuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTTE9QU1BBVFRFUlwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJDYW5hbCBIdWxsXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiU3VwZXJuYXR1cmFsXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiVGhpcyBodWxsIGxlYXJuZWQgdG8gY29uc3VtZSBzcGlyaXRzIGFuZCBib2xzdGVyIGl0cyBzdHJlbmd0aCB3aXRoIHRoZWlycy4gSXQgY2FubmliYWxpemVzIG1hY2hpbmVyeSBhbmQgcnVtbWFnZXMgaW4gd3JlY2tlZCBib2F0cyBmb3IgcGFydHMuIEl0IGhhcyBnb25kb2xhIHByb3cgc2hvdWxkZXIgZ3VhcmRzIGFuZCBoZWxtLCBhbmQgc3RyYW5nZSBiYW5kZWQgYXJtb3IgbWFkZSBvZiB3YXRlci1sb2dnZWQgd29vZCBvdmVyIGludHJpY2F0ZSBtZWNoYW5pY2FsIHBhcnRzLiBJdCBmZWFycyBkZXN0cnVjdGlvbi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJJdCBhc3Nhc3NpbmF0ZXMgdGFyZ2V0cywgd2l0aCBpdHMgYm9keSBvciBieSBwb3NzZXNzaW5nIG1hY2hpbmVzIG5lYXIgdGhlbS4gSXQgaHVudHMgd2hpc3BlcnMsIGxlZWNoZXMsIGFuZCBzY2hvbGFycywgc3RlYWxpbmcgdGhlaXIga25vd2xlZGdlIGFuZCBraWxsaW5nIHRoZW0uIFRoZWlyIGFsbGllcyB3YW50IHJldmVuZ2UuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTeWxhIER1VG9ycml2ZXN0cmlhXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIkZhbW91cyBDb25ub2lzc2V1clwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIkZvcmVpZ25cIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGlzIG15c3RlcmlvdXMgSXJ1dmlhbiBoaWRlcyBiZWhpbmQgYSB2ZWlsLiBGb3IgeWVhcnMsIHNoZSBoYXMgYmVlbiB0aGUgZmluYWwgd29yZCBvbiBEdXNrd2FsbCBkZWxpY2FjaWVzLiBTaGUgc3BlY2lhbGl6ZXMgaW4gZXZhbHVhdGluZyBoaWdoLWVuZCBjdWlzaW5lIChpbmNsdWRpbmcgc3BvcmUgd2luZXMgYW5kIGNvb2tpbmcgd2l0aCBsZXZpYXRoYW4gYmxvb2QuKSBTaGUgc3RheXMgaW4gdGhlIHB1YmxpYyBleWUgd2l0aCByYWN5IHBvbGl0aWNzIGFuZCBhIHN0cmluZyBvZiBzY2FuZGFsb3VzIHJvbWFuY2VzLlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIlNoZSBtdXN0IGtlZXAgYW55IHJlYWwgY29tcGV0aXRvcnMgZm9yIGhlciBmYW1lIHdlYWtlbmVkIGFuZCBlbWJhcnJhc3NlZCwgYW5kIHNoZSBoYXMgY291bnRsZXNzIGVuZW1pZXMuIEV2ZXJ5b25lIFxcXCJrbm93c1xcXCIgc2hlIGlzIGFuIElydXZpYW4gc3B5LlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGhlIEhvbm9yYWJsZSBUZWxpYSBDcmF5XCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBjb25jZXB0OiBcIlN0ZXJuIFByb3NlY3V0b3JcIixcbiAgICAgICAgICAgICAgICBhcmVuYTogXCJDaXR5IExhd1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNoZSdzIG9sZCwgc2hlJ3Mgc291ciwgYW5kIHNoZSBoYXMgYSByZXB1dGF0aW9uIGZvciBqYWlsaW5nIER1c2t3YWxsJ3MgY3JpbWluYWxzLiBBcyB0aGluIGFuZCBoYXJkIGFzIGFuIGlyb24gcG9rZXIsIHNoZSByZWxlbnRsZXNzbHkgcHVyc3VlcyBoZXIgY2FzZXMsIGJlbmRpbmcgdGhlIGxhdyB3aXRoIGEgcGFzc2lvbmF0ZSBoYXRyZWQgb2Ygc2NvdW5kcmVscy4gU2hlIHJ1bnMgYSBzcGVjaWFsIHVuaXQgb2YgSW5zcGVjdG9ycyBkZWRpY2F0ZWQgdG8gaW52ZXN0aWdhdGluZyBoZXIgY2FzZXMsIHJ1biBieSBJTlNQRUNUT1IgVUxFSy5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJJZiBzaGUgaXMgdGFraW5nIGEgY2FzZSBwZXJzb25hbGx5ICggYXMgc2hlIG9mdGVuIGRvZXMpIHNoZSBtYXkgaGlyZSBvdXRzaWRlcnMgdG8gYWNxdWlyZSBvciBjcmVhdGUgZXZpZGVuY2UuIFNoZSBhbHNvIGNvbmR1ZHMgYSBicnV0YWwgd2FyIG9mIGNvdW50ZXItaW50ZWxsaWdlbmNlIGFnYWluc3Qgcm9ndWVzIGxvb2tpbmcgdG8gZnJlZSB0aGVpciBhc3NvY2lhdGVzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGhlIFdvb2RlbiBKdWRnZVwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgY29uY2VwdDogXCJIYXVudGVkIFB1cHBldFwiLFxuICAgICAgICAgICAgICAgIGFyZW5hOiBcIlVuZGVyd29ybGRcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGlzIGtuZWUtaGlnaCB2ZW50cmlsb3F1aXN0IGR1bW15IGxvb2tzIGxpa2UgYSBjYXJpY2F0dXJlIG9mIGEgZ3JpbSBKdWRnZS4gSXQgaXMgc3VwZXJuYXR1cmFsbHkgYW5pbWF0ZWQuIFRoZSBwdXBwZXQgYXBwZWFycyB1bmV4cGVjdGVkbHksIGludGVycnVwdGluZyBhIHNjb3VuZHJlbCdzIHJvdXRpbmUgYnkgb2ZmZXJpbmcgam9icyBpbiBhIHNxdWVha3kgdm9pY2UuIEhlIHBheXMgYnkgcmV2ZWFsaW5nIHRoZSBsb2NhdGlvbiBvZiBoaWRkZW4gY2FjaGVzIG9mIGFuY2llbnQgY29pbi5cIixcbiAgICAgICAgICAgICAgICBub3RlczogXCJNYW55IGFuZ3J5IHZpY3RpbXMgd2FudCB0byBrbm93IHdobyBwdWxscyB0aGUgc3RyaW5ncyBvZiB0aGUgV29vZGVuIEp1ZGdlLiBUaGUgcHVwcGV0IG9mdGVuIGhpcmVzIGZyZXNoIHRhbGVudCBmb3IgZHViaW91cyB3b3JrLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGhlb2RvcmUgTHlzYW5kZXJcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGNvbmNlcHQ6IFwiQmFyZCBQaW1wXCIsXG4gICAgICAgICAgICAgICAgYXJlbmE6IFwiVW5kZXJ3b3JsZFwiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkVsZWdhbnQgYW5kIGNoYXJpc21hdGljLCB0aGlzIHdlbGwtZHJlc3NlZCBtYW4gcnVucyB0aGUgVGVucGVubnkgQ291cnQgTmV0d29yay4gSGUgbWFuYWdlcyBwcm9zdGl0dXRlcyBhbmQgdGhlaXIgY3VzdG9tZXJzLCBoaXMgcGVyc29uYWwgY29ubmVjdGlvbnMgYW5kIGNoYXJtIG1vbmV0aXplZC4gSGUgaXMgYWxzbyBhIHNraWxsZWQgY29tcG9zZXIgYW5kIHBlcmZvcm1lciwgb2Z0ZW4gc2VlbiBhdCB0aGUgV29ybGRzZWRnZSBUaGVhdGVyIGluIENyb3cncyBGb290LlwiLFxuICAgICAgICAgICAgICAgIG5vdGVzOiBcIkhlIGlzIGEgc2tpbGxlZCBuZXR3b3JrZXIuIEhlIHRha2VzIHRoZSBzYWZldHkgb2YgaGlzIGZyaWVuZHMgc2VyaW91c2x5LCBhbmQgaXMgcHJvdGVkaXZlIG9mIGhpcyBlbXBsb3llZXMsIHRvIHRoZSBwb2ludCBvZiB1c2luZyBibGFja21haWwgdG8gZm9yY2UgcG93ZXJmdWwgcGF0cm9ucyB0byBiYWNrIG9mZi5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNoaWVmIFByaWNoYXJkXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJUaGUgaGVhZCBPdmVyc2VlciBvZiB0aGUgTWluaXN0cnkgb2YgUHJvdmlzaW9ucyBpbiBEdXNrd2FsbC4gTWFuYWdlcyB0aGUgd29ya2VycyBhbmQgZm9vZCBhbGxvdG1lbnRzIGZvciB0aGUgY2l0eSBkaXN0cmljdHMuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQmFycm93Y2xlZnRcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJjYWxjdWxhdGluZ1wiLFxuICAgICAgICAgICAgICAgICAgICBcImNvbmZpZGVudFwiLFxuICAgICAgICAgICAgICAgICAgICBcImNhbG1cIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMb3JkIFN0cmFuZ2ZvcmRcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk9wZXJhdGVzIG9uZSBvZiB0aGUgbGFyZ2VzdCBsZXZpYXRoYW4gaHVudGVyIGZsZWV0cywgc2VydmVzIG9uIHRoZSBDaXR5IENvdW5jaWwgYW5kIGlzIGEgaGlnaC1yYW5raW5nIG1lbWJlciBvZiB0aGUgc2VjcmV0IG9yZGVyIHdpdGhpbiB0aGUgQ2h1cmNoIG9mIEVjc3Rhc3kuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQnJpZ2h0c3RvbmVcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJzZWNyZXRpdmVcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjYWxjdWxhdGluZ1wiLFxuICAgICAgICAgICAgICAgICAgICBcImFycm9nYW50XCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSHV0dG9uXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBIFNrb3ZsYW5kZXIgcmVmdWdlZSBhbmQgZm9ybWVyIHNvbGRpZXIsIG5vdyB0aGUgbGVhZGVyIG9mIGFuIGFuYXJjaGlzdCByZXZvbHV0aW9uYXJ5IG1vdmVtZW50LCBiZW50IG9uIGZvcmNpbmcgdGhlIGdvdmVybm1lbnQgdG8gYWNrbm93bGVkZ2UgU2tvdmxhbmRlciByaWdodHMgaW4gdGhlIEVtcGlyZS5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDaGFyaG9sbG93XCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiYnJhdmVcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjb21wYXNzaW9uYXRlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwid2lzZVwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxhZHkgRHJha2VcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkEgbWFnaXN0cmF0ZSB3aG8gaXMgXFxcInJlYXNvbmFibGVcXFwiIHdoZW4gaXQgY29tZXMgdG8gc3RyZWV0IGNyaW1lLCBzbyBsb25nIGFzIHRoZSBvZmZlbmRlcidzIHB1cnNlIGlzIHN1ZmZpY2llbnQuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQ2hhcnRlcmhhbGxcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJmbGV4aWJsZVwiLFxuICAgICAgICAgICAgICAgICAgICBcInNocmV3ZFwiLFxuICAgICAgICAgICAgICAgICAgICBcInN1YnRsZVwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk1hc3RlciBTbGFuZVwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQSBub3RvcmlvdXMgZmFjdG9yeSBmb3JlbWFuIGtub3duIGZvciBleGNlc3NpdmUgYW5kIGNydWVsIHB1bmlzaG1lbnRzIGZvciB0aGUgc21hbGxlc3QgaW5mcmFjdGlvbnMuIE1hbnkgYXR0ZW1wdHMgaGF2ZSBiZWVuIG1hZGUgb24gaGlzIGxpZmUsIGJ1dCBhbGwgaGF2ZSBmYWlsZWQuIFNvbWUgc2F5IGhlJ3MgYSBkZXZpbC5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDb2FscmlkZ2VcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJjb2xkXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY3J1ZWxcIixcbiAgICAgICAgICAgICAgICAgICAgXCJzYWRpc3RpY1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlNlcmdlYW50IExvY2hsYW5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRoZSBzZW5pb3IgQmx1ZWNvYXQgc3F1YWQgbGVhZGVyIGluIHRoZSBkaXN0cmljdCwgcmVwb3J0aW5nIHRvIENhcHRhaW4gRHVudmlsLiBMb2NobGFuIGlzIGZsZXhpYmxlIGFuZCByZWFzb25hYmxlLCB0YWtpbmcgYnJpYmVzIGFuZCBwYXlvZmZzIHdoZW4gc2hlIGNhbjsgZW5mb3JjaW5nIHRoZSBsYXcgYW5kIG1ha2luZyBleGFtcGxlcyB3aGVuIG5lY2Vzc2FyeS5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDcm93J3MgRm9vdFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcInNocmV3ZFwiLFxuICAgICAgICAgICAgICAgICAgICBcInRvdWdoXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY29tbWFuZGluZ1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNoaWVmIEhlbGtlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiT25lIG9mIHRoZSBtb3N0IGluZmx1ZW50aWFsIHNlbmlvciBEb2NrZXJzLiBIZWxrZXIgaGFzIGEgbG90IG9mIHN3YXkgYXQgdGhlIGRvY2tzLCBhbmQgaWYgeW91IGNyb3NzIGhpbSwgeW91IG1pZ2h0IGZpbmQgeW91ciBjYXJnbyB0b3NzZWQgaW50byB0aGUgZHJpbmvigJRhbmQgcG9zc2libHkgeW91IGFsb25nIHdpdGggaXQuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiVGhlIERvY2tzXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiY2F1dGlvdXNcIixcbiAgICAgICAgICAgICAgICAgICAgXCJncmVlZHlcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ2ZW5nZWZ1bFwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk1hc3RlciBLcm9ja2V0XCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBbiB1bnNhdm9yeSwgZ3JlYXN5LWhhaXJlZCwgc2NhcmVjcm93IG9mIGEgbWFuIHdobyBydW5zIHRoZSBzbmFybGluZyBwYWNrIG9mIHZpY2lvdXMgZG9ncyB1c2VkIGJ5IElyb25ob29rIHRvIHRyYWNrIGRvd24gZXNjYXBlZXMgYW5kIHNuaWZmIG91dCBjb250cmFiYW5kIGFuZCB0dW5uZWxzLiBIaXMgZG9nLWhhbmRsZXJzIGNhbiBiZSBmb3VuZCBhcm91bmQgdGhlIGxhYm9yIGNhbXAgYW5kIGFsbCBhYm91dCBEdW5zbG91Z2gsIHVzaW5nIHRoZWlyIHN0YXR1cyB3aXRoIHRoZSBwcmlzb24gZm9yIGZhdm9ycyBhbmQgYnJpYmVzLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIkR1bnNsb3VnaFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImNydWVsXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZ3JlZWR5XCIsXG4gICAgICAgICAgICAgICAgICAgIFwicnV0aGxlc3NcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJKaXJhXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBIGRlYWxlciBvZiBmaW5lIHdlYXBvbnMgZnJvbSB0aGUgRGFnZ2VyIElzbGVzLiBHcmVhdGx5IHJlc3BlY3RlZCBieSBtYW55IHN0cmVldCB0b3VnaHMgaW4gVGhlIER1c2vigJRhIFxcXCJqaXJhIGJsYWRlXFxcIiBpcyBhIHN0YXR1cyBzeW1ib2wgdGhhdCBtYW55IGFzcGlyZSB0by5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJOaWdodG1hcmtldFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImJvbGRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3VnaFwiLFxuICAgICAgICAgICAgICAgICAgICBcImNvbmZpZGVudFwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxldnlyYVwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQSBtZWRpdW0gd2hvIGludml0ZXMgY2xpZW50cyB0byBicmluZyBnaG9zdHMgaW4gYm90dGxlcyB0byBwb3NzZXMgaGVyIHNvIHRoZXkgY2FuIHNoYXJlIGEgZmV3IGZpbmFsIHdvcmRzIGJlZm9yZSB0aGUgZ2hvc3QgaXMgXFxcImZyZWVkXFxcIiAoTGV2eXJhIGhhbmRzIGl0IG9mZiB0byB0aGUgd2FpdGluZyBTcGlyaXQgV2FyZGVucyBuZWFyYnkpLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIlNpbGtzaG9yZVwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcIndlaXJkXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZGFyaW5nXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZGlzaG9uZXN0XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTW90aGVyIE5hcnlhXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJSdW5zIHRoZSBBcm1zIG9mIHRoZSBXZWVwaW5nIExhZHkgY2hhcml0eSBob3VzZS5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJTaXggVG93ZXJzXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwia2luZFwiLFxuICAgICAgICAgICAgICAgICAgICBcInBhdGllbnRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJncmFjaW91c1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk1hZXN0cm8gSGVsbGVyZW5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlNlbmlvciBjb21wb3NlciBhbmQgY29uZHVjdG9yIG9mIHRoZSBTcGlyZWdhcmRlbiBUaGVhdGVyLCBwcmVtaWVyZSBwZXJmb3JtYW5jZSB2ZW51ZSBmb3IgdGhlIGVsaXRlIG9mIHRoZSBjaXR5LlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIldoaXRlY3Jvd25cIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJzaW5jZXJlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZHJhbWF0aWNcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ2YWluXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSGVzdGVyIFZhbGVcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk1hdHJpYXJjaCBvZiB0aGUgb2xkZXN0IGZhcm0gZmFtaWx5LiBUaGUgbGl2aW5nIGVtYm9kaW1lbnQgb2YgXFxcInRvdWdoIGJ1dCBmYWlyLlxcXCJcIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJCYXJyb3djbGVmdFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcInByb3VkXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZmllcmNlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwic3VzcGljaW91c1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNvbW1hbmRlciBCb3dtb3JlXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJDaGllZiBPZmZpY2VyIG9mIHRoZSBXYXRjaCBpbiBCcmlnaHRzdG9uZS4gQm93bW9yZSdzIGZhbWlseSBmaW5hbmNlZCBCb3dtb3JlIEJyaWRnZSBjZW50dXJpZXMgYWdvIGFuZCBub3cgaG9sZHMgbWFueSBwb3NpdGlvbnMgb2YgcG93ZXIuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQnJpZ2h0c3RvbmVcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJwcm91ZFwiLFxuICAgICAgICAgICAgICAgICAgICBcInByaW5jaXBsZWRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjb25uZWN0ZWRcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJCcmlnZ3NcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIlRoZSBvd25lciBvZiBhIG1lcmNoYW50IHN0YWxsIGF0IENoYXJob2xsb3cgbWFya2V0LCBjb3ZlciBmb3IgYSBuZXR3b3JrIG9mIGdvc3NpcHMsIHNwaWVzLCBhbmQgY29kZS1zbWl0aHMgYW1vbmcgdGhlIHdvcmtpbmcgY2xhc3MgcGVvcGxlIG9mIHRoZSBkaXN0cmljdCwgc2VsbGluZyB0aGVpciBzZXJ2aWNlcyB0byB0aG9zZSB3aG8gbmVlZCB0aGVtLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIkNoYXJob2xsb3dcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJzZWNyZXRpdmVcIixcbiAgICAgICAgICAgICAgICAgICAgXCJzbmVha3lcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjYXV0aW91c1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxvcmQgUGVuZGVyeW5cIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkNoaWVmIFNjaG9sYXIgb2YgdGhlIEFyY2hpdmUgb2YgRWNob2VzLCBhdXRob3JpemVkIGJ5IHRoZSBFbXBlcm9yIHRvIGtlZXAgYSBjb2xsZWN0aW9uIG9mIGFuY2llbnQgZ2hvc3RzIHRyYXBwZWQgaW4gc3Bpcml0IGJvdHRsZXMsIHRvIGJlIGNvbnN1bHRlZCBpbiBjYXNlcyB3aGVyZSBrbm93bGVkZ2UgZnJvbSB0aGUgZGlzdGFudCBwYXN0IHdvdWxkIGJlbmVmaXQgdGhlIG9wZXJhdGlvbiBvZiB0aGUgSW1wZXJpYWwgZ292ZXJubWVudC4gTG9yZCBQZW5kZXJ5biBhbHNvIGNvbnN1bHRzIHRoZSBzcGlyaXRzIG9uIGhpcyBvd24gdm9saXRpb24sIGZvcm1pbmcgdGhlIHJlYmVsbGlvdXMgUGF0aCBvZiBFY2hvZXMgc29jaWV0eSBmb3Igb3RoZXIgZWxpdGVzIGFuZCBub2JsZXMgd2hvIHNlZWsgY29tbXVuaW9uIHdpdGggdGhlIHNwZWN0cmFsIHJlYWxtLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIkNoYXJ0ZXJoYWxsXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwicmVja2xlc3NcIixcbiAgICAgICAgICAgICAgICAgICAgXCJzdHJhbmdlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwib2JzZXNzaXZlXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQmVsbGUgQnJvZ2FuXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBIFNrb3ZsYW5kZXIgZmFjdG9yeSB3b3JrZXIgd2hvJ3MgYmVlbiBnYWluaW5nIHBvcHVsYXJpdHkgYXMgYSBwb3RlbnRpYWwgdW5pb24gb3JnYW5pemVyLiBJdCdzIG9ubHkgYSBtYXR0ZXIgb2YgdGltZSBiZWZvcmUgYSBmYWN0b3J5IGJvc3MgdHJpZXMgbWFrZSBhbiBleGFtcGxlIG9mIGhlci5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDb2FscmlkZ2VcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJjaGFybWluZ1wiLFxuICAgICAgICAgICAgICAgICAgICBcImNvbmZpZGVudFwiLFxuICAgICAgICAgICAgICAgICAgICBcImJvbGRcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMZXdpdCwgSm9sLCBNeXJhLCBSZXlmXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJCbHVlY29hdCBjb25zdGFibGVzOyBydW4gYW4gZXh0b3J0aW9uIHJhY2tldC5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDcm93J3MgRm9vdFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImFycm9nYW50XCIsXG4gICAgICAgICAgICAgICAgICAgIFwidmFpblwiLFxuICAgICAgICAgICAgICAgICAgICBcInZvbGF0aWxlXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVHJpc1wiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQSBsZWdlbmRhcnkgdGF0dG9vaXN0IHdobyBvbmx5IGlua3MgdGhvc2UgdGhhdCBoYXZlIGxvb2tlZCB1cG9uIGEgbGV2aWF0aGFuIGFuZCBsaXZlZCB0byB0ZWxsIHRoZSB0YWxlLiBHZXR0aW5nIGEgdGF0dG9vIGZyb20gVHJpcyBpcyBhIHJpdGUgb2YgcGFzc2FnZSBmb3IgZXZlcnlvbmUgd2hvIGh1bnRzIHRoZSBkZW1vbnMgb2YgdGhlIHZvaWQgc2VhLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIlRoZSBEb2Nrc1wiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImFydGlzdGljXCIsXG4gICAgICAgICAgICAgICAgICAgIFwicG9wdWxhclwiLFxuICAgICAgICAgICAgICAgICAgICBcImluc2lnaHRmdWxcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJWYW5kcmFcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkEgZGVhdGhsYW5kcyBzY2F2ZW5nZXIgdGhhdCBzdXJ2aXZlZCBzaXggcnVucyBhbmQgd2FzIHBhcmRvbmVkLiBTaGUga25vd3MgdGhlIGxhbmRzY2FwZSBiZXlvbmQgdGhlIGJhcnJpZXIgdmVyeSB3ZWxs4oCUYnV0IGZldyBjYW4gbWFrZSBzZW5zZSBvZiBoZXIgaGF1bnRlZCBtdW1ibGluZ3MuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiRHVuc2xvdWdoXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwiaGF1bnRlZFwiLFxuICAgICAgICAgICAgICAgICAgICBcIndpc2VcIixcbiAgICAgICAgICAgICAgICAgICAgXCJkYXJpbmdcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMZWNsdXJlXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBIHB1cnZleW9yIG9mIHBlcnNvbmFsIGx1eHVyaWVzIChzb2FwcywgaGFpciBvaWxzLCBwZXJmdW1lLCBmaW5lIHNpbGtzKSB3aG8gZGFiYmxlcyBpbiBmb3J0dW5lIHRlbGxpbmcuIFNvbWUgc2F5IGhlciB0aGF0IGRyb3duZWQgbG92ZXIgaXMgYSBnaG9zdCB0aGF0IHdoaXNwZXJzIHNlY3JldHMgaW4gaGVyIGVhci5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJOaWdodG1hcmtldFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcInNocmV3ZFwiLFxuICAgICAgICAgICAgICAgICAgICBcInRvdWdoXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY29tbWFuZGluZ1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkhlbGVuZVwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiVGhlIGVsZWdhbnQgYW5kIG15c3RlcmlvdXMgcHJvcHJpZXRvciBvZiB0aGUgU2lsdmVyIFN0YWcgQ2FzaW5vLiBQZW9wbGUgc2F5IHNoZSB3b3VsZCBoYXZlIGJlZW4gYSBxdWVlbiBvZiBTZXZlcm9zIGhhZCBzaGUgbGl2ZWQgaW4gdGhlIG9sZCBkYXlzIGJlZm9yZSB0aGUgRW1waXJlLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIlNpbGtzaG9yZVwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImN1bHR1cmVkXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY2hhcm1pbmdcIixcbiAgICAgICAgICAgICAgICAgICAgXCJzZWNyZXRpdmVcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJDaGVmIFJvc2VsbGVcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIk9uZSBvZiB0aGUgYmVzdCBjb29rcyBpbiB0aGUgY2l0eSwgc3RpbGwgb3BlcmF0aW5nIHRoZSBsZWdlbmRhcnkgR29sZGVuIFBsdW0gcmVzdGF1cmFudOKAlHdvcnRoIHRoZSB0cmlwIGludG8gdGhlIGhhdW50ZWQgc3RyZWV0cyBvZiBTaXggVG93ZXJzLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIlNpeCBUb3dlcnNcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJjcmVhdGl2ZVwiLFxuICAgICAgICAgICAgICAgICAgICBcImluc2lnaHRmdWxcIixcbiAgICAgICAgICAgICAgICAgICAgXCJmcmllbmRseVwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkxhZHkgRnJleWxhXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJSZWdhcmRlZCBieSBzb21lIGFzIHRoZSBmaW5lc3Qgc29tbWVsaWVyIGluIHRoZSBFbXBpcmUuIFNoZSBzZXJ2ZXMgb25seSB0aGUgbW9zdCBkZXNlcnZpbmcgYXQgdGhlIEVtcGVyb3IncyBDYXNrLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIldoaXRlY3Jvd25cIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJlcnVkaXRlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY3VsdHVyZWRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjaGFybWluZ1wiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk1hcmEgS2VlbFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQSBmb3JtZXIgc211Z2dsZXIgd2hvJ3MgZ29uZSBpbnRvIGhpZGluZyBhbW9uZyB0aGUgZmFybSBsYWJvcmVycyBvZiBCYXJyb3djbGVmdC5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJCYXJyb3djbGVmdFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcInF1aWV0XCIsXG4gICAgICAgICAgICAgICAgICAgIFwic2VjcmV0aXZlXCIsXG4gICAgICAgICAgICAgICAgICAgIFwicGF0aWVudFwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlJvbGFuIFdvdHRcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkFuIGluZmx1ZW50aWFsIG1hZ2lzdHJhdGUgd2hvIGhhbmRsZXMgcHJvcGVydHksIGVuZG93bWVudHMsIGFuZCBmaW5hbmNpYWwgY2FzZXMuIEZhbW91cyBmb3IgaGlzIGV4dHJhdmFnYW50IHBhcnRpZXMuXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQnJpZ2h0c3RvbmVcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJzdHlsaXNoXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZWxpdGlzdFwiLFxuICAgICAgICAgICAgICAgICAgICBcInNocmV3ZFwiXG4gICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNvcmJlblwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQW4gZXgtbWlsaXRhcnkgU2tvdmxhbmRlciBvbiB0aGUgbGFtIGZvciBjcmltZXMgYWdhaW5zdCB0aGUgZW1waXJlLlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIkNoYXJob2xsb3dcIixcbiAgICAgICAgICAgICAgICB0cmFpdHM6IFtcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3VnaFwiLFxuICAgICAgICAgICAgICAgICAgICBcInJlY2tsZXNzXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiY2FuZGlkXCJcbiAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiSG9wcGVyXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJucGNcIixcbiAgICAgICAgICAgICAgICBkZXNjcmlwdGlvbjogXCJBIGRydWcgYWRkaWN0LCB3aGlzcGVyLCBhbmQgYWxsLWFyb3VuZCB3ZWlyZG8gd2hvIHBlcmNoZXMgb24gcm9vZnRvcHMgaW4gdGhlIGRpc3RyaWN0LiBIb3BwZXIgY2xhaW1zIHRvIHNlZSBcXFwiZ2hvc3QgcmFpbHNcXFwiIGFuZCBcXFwic3Bpcml0IHRyYWluc1xcXCIgb3JpZ2luYXRpbmcgZGVlcCBiZW5lYXRoIENvYWxyaWRnZSwgc3RyZXRjaGluZyBiZXlvbmQgdGhlIGhvcml6b24uXCIsXG4gICAgICAgICAgICAgICAgZGlzdHJpY3Q6IFwiQ29hbHJpZGdlXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwid2VpcmRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ2aXNpb25hcnlcIixcbiAgICAgICAgICAgICAgICAgICAgXCJlbnRodXNpYXN0aWNcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNYXJkaW4gR3VsbFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiT3duZXIgYW5kIG9wZXJhdG9yIG9mIHRoZSBMZWFreSBCdWNrZXQgcHVibGljIGhvdXNlLiBNYXJkaW4gd2FzIHRoZSBsZWFkZXIgb2YgdGhlIENyb3dzIG1hbnkgeWVhcnMgYWdvLCBiZWZvcmUgUm9yaWMgYW5kIEx5c3NhLCBhbmQgbm93IGVuam95cyBhIGNvbWZvcnRhYmxlIHJldGlyZW1lbnQgb3V0IG9mIHRoZSBzY291bmRyZWwgbGlmZS5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJDcm93J3MgRm9vdFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImNoYXJtaW5nXCIsXG4gICAgICAgICAgICAgICAgICAgIFwiZXhwZXJpZW5jZWRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJyZXNwZWN0ZWRcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNb3JkaXNcIixcbiAgICAgICAgICAgICAgICB0eXBlOiBcIm5wY1wiLFxuICAgICAgICAgICAgICAgIGRlc2NyaXB0aW9uOiBcIkEgc3RyYW5nZSBtZXJjaGFudCB3aGljaCBoaWRlcyBpdHMgdHJ1ZSBhcHBlYXJhbmNlIGJlbmVhdGggbWFueSBsYXllcnMgb2Ygcm9iZXMgYW5kIGhvb2RzLiBBbHNvIGZlbmNlcyBvY2N1bHQgYW5kIGFyY2FuZSBzdG9sZW4gZ29vZHMsIG5vIHF1ZXN0aW9ucyBhc2tlZC5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJOaWdodG1hcmtldFwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcInNlY3JldGl2ZVwiLFxuICAgICAgICAgICAgICAgICAgICBcImluc2lnaHRmdWxcIixcbiAgICAgICAgICAgICAgICAgICAgXCJhcmNhbmVcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNYWRhbWUgVGVzc2x5blwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiT3BlcmF0ZXMgdGhlIFJlZCBMYW1wIGJyb3RoZWwsIHRoZSBvbGRlc3QgYW5kIG1vc3QgcmVzcGVjdGVkIGluc3RpdHV0aW9uIG9mIGl0cyBzb3J0IGluIHRoZSBjaXR5LlwiLFxuICAgICAgICAgICAgICAgIGRpc3RyaWN0OiBcIlNpbGtzaG9yZVwiLFxuICAgICAgICAgICAgICAgIHRyYWl0czogW1xuICAgICAgICAgICAgICAgICAgICBcImNvbmZpZGVudFwiLFxuICAgICAgICAgICAgICAgICAgICBcImluc2lnaHRmdWxcIixcbiAgICAgICAgICAgICAgICAgICAgXCJlbnRodXNpYXN0aWNcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJGbGludFwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwibnBjXCIsXG4gICAgICAgICAgICAgICAgZGVzY3JpcHRpb246IFwiQSBzcGlyaXQgdHJhZmZpY2tlciB3aG8gdHJhZGVzIG91dCBvZiBhIGNvbmRlbW5lZCBtYW5vciBob3VzZS5cIixcbiAgICAgICAgICAgICAgICBkaXN0cmljdDogXCJTaXggVG93ZXJzXCIsXG4gICAgICAgICAgICAgICAgdHJhaXRzOiBbXG4gICAgICAgICAgICAgICAgICAgIFwid2VpcmRcIixcbiAgICAgICAgICAgICAgICAgICAgXCJjYWxjdWxhdGluZ1wiLFxuICAgICAgICAgICAgICAgICAgICBcInN1c3BpY2lvdXNcIlxuICAgICAgICAgICAgICAgIF1cbiAgICAgICAgICAgIH1cbiAgICAgICAgXSxcbiAgICAgICAgU2NvcmVzOiBbXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJBY2NpZGVudGFsIERlYXRoXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiU2VjcmV0IERpcnR5IFdvcmtcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIk5vdCBvbmx5IG11c3QgdGhlIHRhcmdldCBkaWUsIHRoZSB0YXJnZXQgbXVzdCBub3Qga25vdyBob3cgZGVhdGggY2FtZS4gSWYgYnkgc29tZSBtaXNmb3J0dW5lIHRoZSBnaG9zdCBvZiB0aGUgdmljdGltIGlzIGludGVycm9nYXRlZCwgaXQgbXVzdCBub3QgaGF2ZSBhbnkgc3BlY2lhbCBrbm93bGVkZ2UuIFRoZXJlIGlzIGEgcml0dWFsIGFuZCBhbiBhbXVsZXQgZm9yIHRoZSBhc3Nhc3NpbnMgdG8gZW5zdXJlIHNlY3JlY3kuIE5vIG9uZSBsaXZpbmcgb3IgZGVhZCBjYW4ga25vdyB3aG8gZGlkIHRoaXMgZGVlZC5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiQnkgdGhlIHRpbWUgdGhlIGNyZXcga25vd3MgdGhlIGpvYiwgdGhlcmUgaXMgYSBiZXR0ZXIgdGhhbiBldmVuIGNoYW5jZSB0aGVpciBrbm93bGVkZ2UgaXMgdG9vIG11Y2ggcmlzayBhbmQgdGhlaXIgZW1wbG95ZXIgcGxhbnMgdG8ga2lsbCB0aGVtLiBUaGV5IG1pZ2h0IHdhbnQgc29tZSBsZXZlcmFnZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkJheWVyJ3MgVHJhaW4gSGVpc3RcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJNaXNwbGFjZWQgRm9ydHVuZVwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiQmF5ZXIgd2FzIGEgcmFpbCBqYWNrIGZpcmVkIGZvciBiZWluZyBkcnVuay4gT3ZlciB5ZWFycywgaGUgYnVpbHQgYSBjcmV3IHdpdGggb25lIG1pc3Npb24gaW4gbWluZC0tcm9iYmluZyBhIHRyYWluLiBXaGVuIGxydXZpYSBjb21wbGV0ZWQgbmVnb3RpYXRpb25zIHdpdGggQWtvcm9zIHRvIGJ1eSBhbiB1bnByZWNlZGVudGVkIG1hc3Mgb2YgbGV2aWF0aGFuIGJsb29kIHRvIHBvdXIgaW50byBpbmR1c3RyaWFsaXphdGlvbiwgQmF5ZXIncyBjcmV3IGhpdCB0aGUgdHJhaW4gY2FycnlpbmcgdGhlIHBheW1lbnQsIHNhYm90YWdpbmcgYSBicmlkZ2UuIFJlc2N1ZXJzIGZvdW5kIHRoZSB0cmFpbiBpbiB0aGUgY2FueW9uLCBidXQgbm8gZ29sZC0tYW4gaW1wb3NzaWJsZSBmZWF0LiBCYXllcidzIGNyZXcgdmFuaXNoZWQuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkFuIElydXZpYW4gaW5nb3Qgc3RhbXBlZCB3aXRoIHRoZSB5ZWFyIFxcXCI4MDJcXFwiIHdpbGwgYXR0cmFjdCBhdHRlbnRpb24uXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJCZWxsd2VhdGhlciBBcmNoaXRlY3R1cmFsIFBsYW5zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiSGlzdG9yaWNhbCBDdXJpb3NpdHlcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSBEdXNrd2FsbCBBcmNoaXZlcyBoYXZlIHRoZSBzYW5pdGl6ZWQgYmx1ZXByaW50cyBvZiB0aGUgQmVsbHdlYXRoZXIgQ3JlbWF0b3JpdW0gb24gZmlsZS4gVGhlIG9yaWdpbmFsIHBsYW5zIHdlcmUgZHJhd24gYnkgYSBTcGlyaXQgV2FyZGVuIGRyaXZlbiBtYWQgYnkgYW4gaW50ZXJuYWwgcmlmdCwgc28gaGUgaGF1bnRlZCBoaW1zZWxmLiBIZSBkcmV3IHBlY3VsaWFyIHBsYW5zIHdpdGggb2NjdWx0IHVuZGVycGlubmluZ3MsIGFuZCB0aG9zZSBvcmlnaW5hbCBkcmF3aW5ncyB3ZXJlIGludGVycHJldGVkIGJ5IGFyY2hpdGVjdHMuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkFyZSB0aGVyZSBjb2RlZCBzZWNyZXRzIGluIHRoZSBvcmlnaW5hbCBwbGFucyB0aGF0IHJldmVhbCBhIHJlcGVsbGFudCBzZWNyZXQgb3Igb21pbm91cyB0aHJlYXQ/IE9yIGFyZSB0aGUgcGxhbnMgdGhlIHNjcmliYmxpbmcgb2YgYSBtYWRtYW4/IEVpdGhlciB3YXksIHNvbWUgcGVvcGxlIHdvdWxkIHBheSB0b3AgY29pbiB0byBnZXQgYSBnb29kIGxvb2suXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJCb29rIG9mIFdhbGxzXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiSGlzdG9yaWNhbCBDdXJpb3NpdHlcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkxvbmcgYWdvLCBhIG5hbWVsZXNzIHJvZ3VlIGN1bHRpdmF0ZWQgYSBtYXNzIG9mIGJsb29kd29ybXMgaW4gYSB3YWxsLiBIZSB3cm90ZSBhIGJvb2sgd2l0aCB0aGVpciBibG9vZC4gVGhlIHdvcmRzIHdlcmUgbm9uc2Vuc2UsIGJ1dCBzdHJhbmdlbHkgYWZmZWN0aW5nOyBpZiB0aGUgcmVhZGVyIHR1bmVkIGluIHRvIHRoZW0sIGFuZCBoZWxkIHRoZSBib29rLCB0aGUgcmVhZGVyIGNvdWxkIHdhbGsgdGhyb3VnaCBhIHdhbGwuIFNwaXJpdCBXYXJkZW5zIHJ1aW5lZCB0aGUgYm9vayB3aXRoIGhvbHkgc21va2UuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkEgbGVnZW5kLCBvciBpcyB0aGVyZSB0cnV0aCB0byBpdD8gV2Fsa2luZyB0aHJvdWdoIHdhbGxzIGlzIGEgbmVhdCB0cmljaywgYW5kIHRoZSBib29rIG1heSBob2xkIHRoZSBrZXkgdG8gbGVhcm5pbmcgaXQuIEl0IGlzIHNvdWdodCBieSBhIHdpZGUgdmFyaWV0eSBvZiB0aGUgY3VyaW91c+KAlHNjaG9sYXJzLCBjb2xsZWN0b3JzLCBhbmQgc2NvdW5kcmVscy5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNlbnNlciBNYWNlIG9mIFVkb2NoXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiUmVsaWdpb3VzIE9iamVjdFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIGhlYWQgb2YgdGhpcyBvcm5hdGVseSBjYXJ2ZWQgbWFjZSBvcGVucyBvbiBoaW5nZXMgc28gaW5jZW5zZSBjYW4gYmUgcHV0IGluc2lkZSB0byB3aXNwIGFzIHRoZSBtYWNlIHN3aW5ncy4gVGhlIGhhZnQgaGFzIGEgcmVjaXBlIGNhcnZlZCBpbnRvIGl0LCBpbnN0cnVjdGlvbnMgdG8gbWFrZSBzcGVjaWFsIGluY2Vuc2Ugb3V0IG9mIGJvbmUgYW5kIHJhcmUgc2FwIGFuZCB1bmd1ZW50cy4gSWYgdGhhdCBpbmNlbnNlIGJ1bXMgaW4gdGhlIG1hY2UsIGl0IGNhbiBkZXN0cm95IGdob3N0cyBvciBkZW1vbnMgd2l0aCBhIHNpbmdsZSBoaXQuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIlRoaXMgd2FzIGEgZm91bmRpbmcgYXJ0aWZhY3Qgb2YgdGhlIENodXJjaCBvZiB0aGUgRWNzdGFzeSBvZiB0aGUgRmxlc2guIElmIGl0IHdlcmUgcmV0dXJuZWQsIHRoZXkgd291bGQgZ2FpbiBhIGZyZXNoIGZvbGxvd2luZyBmcm9tIGNyaXRpY3Mgd2hvIGZlZWwgdGhlIGNodXJjaCBjYW5ub3QgcHJvdGVjdCBhZ2FpbnN0IHN1cGVybmF0dXJhbCB0aHJlYXRzLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ2hhcnRlciBvZiBDcm93c1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkhpc3RvcmljYWwgQ3VyaW9zaXR5XCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGlzIGdhdW50bGV0IGlzIG1hZGUgb3V0IG9mIGNyb3cgYmVha3MuIEVhY2ggYmVhayBpcyBjYXJ2ZWQgd2l0aCBhcmNhbmUgc3ltYm9scy4gQ29uc3VsdGluZyBXaGlzcGVycyBvZmZpY2lhbGx5IHJlcG9ydCBpdCBkb2VzIG5vdCBoYXZlIGFueSBwb3dlciBpbiB0aGUgR2hvc3QgRmllbGQuIEl0IHdhcyBtYWRlIGJ5IHRoZSBTcGlyaXQgV2FyZGVuIHdobyBmaXJzdCB0YW1lZCB0aGUgZGVhdGhzZWVrZXIgY3Jvd3M7IGhlIGNsYWltZWQgaXQgd2FzIGEgdHJlYXR5IHRoYXQgZ3VhcmFudGVlZCB0aGVpciBzZXJ2aWNlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJTcGlyaXQgV2FyZGVucyBsb3N0IHRoaXMgZ2F1bnRsZXQgZGVjYWRlcyBhZ28sIGJ1dCB0aGV5IHdhbnQgaXQgYmFjay4gVGhlIGlkZWEgaXQgaXMgYSB0cmVhdHkgd2l0aCB0aGUgZGVhdGhzZWVrZXIgY3Jvd3MgaXMgcHJvYmFibHkgbm9uc2Vuc2UuIFRoZXkgY2FuJ3QgdGFrZSB0aGF0IGNoYW5jZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkNvbWJpbmF0aW9uIEhhcnBzaWNob3JkXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgU2Nob2xhcnNoaXBcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRBUk5BTEkgd2FzIGEgV2hpc3BlciBjb21wb3NlciB3aG8gYnVpbHQgYSBzcGVjaWFsIGhhcnBzaWNob3JkLiBXaGVuIHR3byB0b25lcyBhcmUgcGxheWVkLCBvZnRlbiBhIHRoaXJkIFxcXCJnaG9zdFxcXCIgdG9uZSBjYW4gYmUgaGVhcmQuIEJ5IGF0dGFjaGluZyB0aGUgdHVuaW5nIHBlZ3MgdG8gY3J5c3RhbHMgYW5kIHJ1bmVzLCBUYXJuYWxpIGJ1aWx0IGEgaGFycHNpY2hvcmQgdGhhdCBjb3VsZCBpbnRlcmFjdCB3aXRoIHRoZSBHaG9zdCBGaWVsZCB0aHJvdWdoIGNhbGN1bGF0ZWQgcHJvZ3Jlc3Npb25zIG9mIHBsYXllZCB0b25lcy5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiVGhpcyBlZmZvcnQgaXMgaW50ZW5zZWx5IGludGVyZXN0aW5nIHRvIHRob3NlIHdobyB3YW50IHRvIGZpbmQgZG9vcnMgaGlkZGVuIGluIHRoZSBHaG9zdCBGaWVsZCwgZHJhdyBvciByZXBlbCB3aGF0IGx1cmtzIEJlaGluZCB0aGUgTWlycm9yLCBvciBkZXZlbG9wIG1vcmUgcG9ydGFibGUgdG9uYWwgZW5lcmdpZXMgZm9yIG5vbi1XaGlzcGVycyAuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJEeXZpaydzIENoYXNlciBNYXNrXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgQXJ0aWZhY3RcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoaXMgc2lsdmVyeSBmYWNlIG1hc2sgaGFzIHRoZSB3b3JkIOKAnEVsZWt0aGlhcm9u4oCdIGV0Y2hlZCBhbG9uZyBpdHMgaW5uZXIgZWRnZS4gV2hlbiB0aGUgd29yZCBpcyBzcG9rZW4sIHRoZSBwZXJzb25hbGl0eSBvZiB0aGUgb25lIHRvdWNoaW5nIHRoZSBtYXNrIGlzIHB1bGxlZCBpbnRvIGl0LiBUaGUgcGVyc29uYWxpdHkgdGhhdCB3YXMgaW4gdGhlIG1hc2sgZ29lcyBpbiB0aGUgYm9keS4gSWYgdGhlIG9uZSBpbiB0aGUgYm9keSBkb2Vzbid0IHRvdWNoIHRoZSBtYXNrIG9uY2UgYSB3ZWVrLCBtYWRuZXNzIHRocmVhdGVucy5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiSGFzIHNvbWVvbmUgYmVlbiB1c2luZyB0aGUgbWFzayB0byBwb3NlIGFzIHNvbWVvbmUgZWxzZT8gSG93IGxvbmcgaGFzIHRoYXQgYmVlbiBnb2luZyBvbj8gSXMgdGhlcmUgc29tZW9uZSBpbiB0aGUgbWFzayB0aGF0IG5lZWRzIHJlc2N1aW5nPyBXYXMgdGhlIG1hc2sgdXNlZCB0byBjaGVhdCBiaW9sb2dpY2FsIGRlYXRoP1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiRXZhcmRpYW4ncyBTb25nIEZvbGlvc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIldlaXJkIFNjaG9sYXJzaGlwXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJGb3VyIGxlYXRoZXItYm91bmQgdm9sdW1lcywgZnVsbCBvZiBtdXNpY2FsIG5vdGF0aW9uIHdpdGggaGVhdmlseSBhbm5vdGF0ZWQgbWFyZ2lucy4gVGhlIFxcXCJtdXNpY1xcXCIgaXMgc3VwcG9zZWQgdG8gYmUgdHJhbnNjcmliZWQgYW5kIHRyYW5zbGF0ZWQgbGV2aWF0aGFuIHNvbmcuIExlZ2VuZCBzdWdnZXN0cyBpZiB0aGUgbXVzaWMgaXMgcGxheWVkIGNvcnJlY3RseSwgaXQgY2FuIGRyaXZlIGh1bWFucyBpbnNhbmUgd2l0aCB2aXNpb25zIG9mIHRoZSBkZW1vbi1oYXVudGVkIGRlZXAuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkFyaXN0b2NyYXRzIHdpbGwgY29sbGVjdCBhbnl0aGluZy4gU2Nob2xhcnMgZ28gdG8gZ3JlYXQgbGVuZ3RocyBmb3IgcmVzZWFyY2ggbWF0ZXJpYWwuIEN1bHRpc3RzIG1heSBmaW5kIHJlbGlnaW91cyBzaWduaWZpY2FuY2UgaW4gdGhlIGZvbGlvcy4gKE93bmluZyB0aGUgZm9saW9zIGlzIGFnYWluc3QgdGhlIGxhdy4pXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJGYWxoZWltJ3MgUHJvZFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkhpc3RvcmljYWwgQ3VyaW9zaXR5XCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGlzIHJhZ2dlZCBwb2xlIHdpdGggYSBzcGVhciBhbmQgYSBzaWx2ZXItY2FibGUgbG9vcCB3YXMgdGhlIGZpcnN0IHByb3RvdHlwZSBvZiB3aGF0IGJlY2FtZSB0aGUgbGlnaHRuaW5nIGhvb2suIEl0IGRvZXNuJ3Qgd29yayB2ZXJ5IHdlbGwsIGJ1dCBpdCB3YXMgdGhlIGZpcnN0IGhpc3RvcmljYWxseSBrbm93biBjaGFyZ2VkIG9iamVjdCB0aGF0IGNvdWxkIGNvbnNpc3RlbnRseSBpbnRlcmFjdCB3aXRoIHRoZSBHaG9zdCBGaWVsZC5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiQXBwYXJlbnRseSB0aGlzIGJpdCBvZiBoaXN0b3J5IGlzIGFuIGltcG9ydGFudCBwcmVzdGlnZSBwaWVjZSBpbiB0aGUgdHVyYnVsZW50IGludHJpZ3VlcyBvZiBhIG51bWJlciBvZiB1bmRlcmdyb3VuZCBjdWx0cyBsZWQgYnkgV2hpc3BlcnMuIFRoZSBjaXR5IGdvdmVybm1lbnQgd291bGQgYWxzbyBsaWtlIHRvIGRpc3BsYXkgaXQgaW4gYSBtdXNldW0uXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJGYW5nIG9mIEliaXJpYVwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlJlbGlnaW91cyBPYmplY3RcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoaXMgYnJ1dGFsIHN0aWxldHRvIGhhcyBhIGdyZWVuIHN0b25lIGluIHRoZSBwb21tZWwsIGFuZCBhIHJ1bmljIHN5bWJvbCBvbiB0aGUgYmxhZGUuIFRoZSBibGFkZSB0cmFuc2Zvcm1zIGVsZWN0cm9wbGFzbSBpbnRvIGEgbXV0YWdlbi4gVGhlIGxvbmdlciB0aGUgYmxhZGUgaXMgaW4gYSB2aWN0aW0sIHRoZSBtb3JlIG1vbnN0cm91cyB0aGUgdmljdGltIGJlY29tZXMuIEEgY3V0IGdpdmVzIG5pZ2h0bWFyZXMsIG1pbnV0ZXMgZ2l2ZSBtdXRhdGlvbnMsIGhvdXJzIG9yIGRheXMgY3JlYXRlIGEgcmVhbCBtb25zdGVyLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJDdWx0aXN0cyB3YW50IHRoaXMgYmxhZGUgc28gdGhleSBjYW4gbWFrZSBvciBiZWNvbWUgbW9uc3RlcnMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJHb2JsZXQgb2YgRWxldHJhY2h0aWFuXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgQXJ0aWZhY3RcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSBzaWx2ZXIgYW5kIGdvbGQgY3VwIGlzIGJpZyBlbm91Z2ggdG8gaG9sZCB3aXRoIHR3byBoYW5kcywgY3J1c3RlZCB3aXRoIG9ic2lkaWFuIHN0b25lcy4gVGhlIG93bmVyIHB1dHMgYSBkcm9wIG9mIGEgZGVtb24ncyBibG9vZCBpbiB0aGUgZ29ibGV0IHdpdGggY2VydGFpbiBvdGhlciBsaXF1aWRzLCBhbmQgY29uZHVjdHMgYSByaXR1YWwuIEZvciBkYXlzIGFmdGVyd2FyZHMgKG1heWJlIGxvbmdlcikgdGhlIG93bmVyIGNhbiBzZWUgYW55dGhpbmcgdGhlIGRlbW9uIHVzZXMgcmVtb3RlIHZpc2lvbiB0byB2aWV3LCBqdXN0IGJ5IHdhdGNoaW5nIHRoZSBzdXJmYWNlJ3MgaWxsdXNvcnkgcmVmbGVjdGlvbnMuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIlRoZXJlIGFyZSBtYW55IGxlZ2VuZHMgYWJvdXQgdGhlIGNyZWF0aW9uIG9mIHRoZSBnb2JsZXQsIGFuZCB0aGUgZmF0ZSBvZiB0aGUgV2hpc3BlciB3aG8gZmlyc3QgZW5lcmdpemVkIGl0LiBSdW1vciBzdWdnZXN0cyB0aGUgRHVza3dhbGwgQ291bmNpbCBlbnRydXN0ZWQgdGhlIGdvYmxldCB0byBhIGNlcnRhaW4gZmFtaWx5IGZvciBzYWZla2VlcGluZy5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIkhvbGxvdyBTaHJvdWRcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJSZWxpZ2lvdXMgT2JqZWN0XCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgQ2h1cmNoIG9mIHRoZSBFY3N0YXN5IG9mIHRoZSBGbGVzaCBjbGVyZ3kgd3JhcHBlZCB0aGUgZnVuZXJhbCBzaHJvdWQgYXJvdW5kIGEgaGVyZXRpYywgdGhlbiBjb25kdWN0ZWQgYSByaXR1YWwgdGhhdCBzZXZlcmVkIHRoZSBoZXJldGljJ3MgY29ubmVjdGlvbiB0byB0aGUgYm9keSwgY3V0dGluZyB0aGUgc3Bpcml0IGxvb3NlIGFzIGEgZ2hvc3QuIFRoZSBzaHJvdWQgdHJhbnNmZXJyZWQgdGhlIHNwaXJpdCBvZiBhIGZhaXRoZnVsIGJ1dCBzaWNrbHkgbWVtYmVyIGludG8gdGhlIGhlcmV0aWMncyBib2R5LiBOZXcgbGlmZSFcIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiVGhlIFNocm91ZCB3YXMgc3RvbGVuIGFsbW9zdCB0d2VudHkgeWVhcnMgYWdvLCBhbmQgcnVtb3JzIHN1Z2dlc3QgaXQgaGFzIGJlZW4gdXNlZCBpbiBkZWJhc2VkIHJpdHVhbHMgdG8gc3VtbW9uIGRlbW9ucyBvciBlbmZsZXNoIGVjaG9lcyBvZiB0aGUgRm9yZ290dGVuIEdvZHMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJJZG9sIG9mIHRoZSBTbGVlcGluZyBMaW9uXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiUmVsaWdpb3VzIE9iamVjdFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIGhlZnR5IGlyb24gc3RhdHVlIGRlcGljdHMgYSBkZXZpbGZpc2gtaGVhZGVkIGh1bWFub2lkLCBjbG9ha2VkIGluIHdpbmdzLiBJdHMgcHJlc2VuY2UgaW5mbHVlbmNlcyBodW1hbiBkcmVhbXMsIHNvIHRoZXkgZHJpZnQgdGhyb3VnaCB0aGUgaW5rLWJsYWNrIHNlYSBidXQgY2FuIHBlcmNlaXZlIHRoZWlyIHN1cnJvdW5kaW5ncy4gU2FjcmlmaWNpbmcgdG8gdGhlIHN0YXR1ZSBnaXZlcyBhIGN1bHRpc3QgYSBjb3NtaWMgaW5mZWN0aW9uLCBpbnZvbHZpbmcgcHN5Y2hpYyBhYmlsaXR5IGFuZCBtdXRhdGlvbnMuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIlRoZSBzdGF0dWUgaGFzIGJlZW4gcmV0cmlldmVkIGJ5IG9mZmljZXJzIG9mIHRoZSBsYXcgc2V2ZXJhbCB0aW1lcywgYW5kIGRlc3Ryb3llZCBzZXZlcmFsIHRpbWVzIG1vcmUuIEFnYWluIGFuZCBhZ2FpbiwgaXQgZW1lcmdlcyBpbiB0aGUgaGVhcnQgb2YgZnJlc2ggdHJhZ2VkeSwgYmFsZWZ1bCBhbmQgc2luZ3VsYXIuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJJbmsgRmxlZWNlXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtaWx5IEhlaXJsb29tXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJMb25nIGFnbywgQ2FwdGFpbiBNYW5hcmlsbCBjbGFpbWVkIGhlIGNvdWxkIHByb3ZlIHRoYXQgbGV2aWF0aGFucyBoYWQgZnVyLCBvciBmbGVlY2UuIEhlIGJyb3VnaHQgYmFjayBhIHN3YXRjaCBvZiBjdXJsaW5nIGZ1ciBhcyBiaWcgYXMgYSBiZWRzcHJlYWQuIEhlIGNsYWltZWQgdG8gaGF2ZSBoYXJ2ZXN0ZWQgaXQgZnJvbSBhIGxldmlhdGhhbidzIHNraW4uIFRoZSBtYW50bGUgc2VydmVkIGFzIGEgc3ltYm9sIG9mIHRoZSBNYW5hcmlsbCBmYW1pbHkncyBoZXJpdGFnZSBvZiBleHBsb3JhdGlvbiBhbmQgZGFuZ2VyLiBCdXQgaXQgd2FzIHN0b2xlbi5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiRG9lcyBpdCBkbyBtb3JlIHRoYW4gcmVwcmVzZW50IGhlcml0YWdlPyBXaGF0IGRyZWFtcyBtaWdodCBvbmUgaGF2ZSB3aGlsZSB3cmFwcGVkIGluIGl0PyBNaWdodCBhIHdlYWx0aHkgV2hpc3BlciBwYXkgbW9yZSBmb3IgaXQgdGhhbiB0aGUgZmFtaWx5IHRoYXQgb3duZWQgaXQ/IFdobyB0b29rIGl0P1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiS2FzYXZhcmF5YSBUZWEgU2V0XCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtaWx5IEhlaXJsb29tXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJXaGVuIHRoZSBJbW1vcnRhbCBFbXBlcm9yIHZpc2l0ZWQgQWtvcm9zIGZvdXIgY2VudHVyaWVzIGFnbywgaGUgdXNlZCB0aGlzIHRlYSBzZXQgd2l0aCB0aGUgcGF0cmlhcmNoIG9mIHRoZSBLYXNhdmFyYXlhIGZhbWlseS4gVGhleSBhcmUgc3RpbGwgb25lIG9mIHRoZSBtb3N0IGRlY29yYXRlZCBhbmQgZW50cmVuY2hlZCBtaWxpdGFyeSBmYW1pbGllcyBpbiBEdXNrd2FsbC4gVGhlaXIgdGVhIHNldCBpcyBhIHN5bWJvbCBvZiBEdXNrd2FsbCdzIHByb21pbmVuY2UuIEhvd2V2ZXIsIGEgc2F1Y2VyIGFuZCBhIGN1cCBhcmUgbWlzc2luZy5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiVGhpcyBzdHVmZiBpcyBwcmljZWxlc3MsIGxpdGVyYWxseSwgc28gbmVnb3RpYXRpbmcgYSBwcmljZSBmb3IgaXRzIHJldHVybiBpcyB0cmlja3kuIElmIHlvdSBjb3VsZCBmaW5kIHRoZSBtaXNzaW5nIHBpZWNlcywgb3IgZm9yZ2UgdGhlbSBhZGVxdWF0ZWx5LCB0aGV5IHdvdWxkIGJlIGdyZWF0IGhvc3RhZ2VzIHRvIGFqZmVkIHRoZSBmYW1pbHkncyBiZWhhdmlvci5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIktpZG5hcCBUaGUgSGVpclwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlNlY3JldCBEaXJ0eSBXb3JrXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJQZW9wbGUgYXJlIGtleXMgdGhhdCBmaXQgaW50byBlc3RhdGUgbG9ja3MuIFRoZXkgY2FuIGJlIHR1cm5lZCB0byBvcGVuIHRoZSB3YXkgdG8gbG90cyBvZiBtb25leS4gWW91IG1pZ2h0IGJlIHRha2luZyBhIGNoaWxkIHRvIHJhbnNvbSBiYWNrIHRvIHRoZSBndWFyZGlhbiwgb3IgeW91IG1pZ2h0IGJlIGdldHRpbmcgc29tZW9uZSBvdXQgb2YgdGhlIHdheSBzbyBhIG1vcmUgZGlzdGFudCBoZWlyIGNhbiBpbmhlcml0LiBUaGlzIGlzIGFib3V0IGNvbnRyb2xsaW5nIHdoZXJlIHRoZSBtb25leSBnb2VzLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJIb3cgaGFyc2ggZG9lcyB0aGUgZW1wbG95ZXIgd2FudCB0aGlzIHRvIGJlPyBLaWQgZ2xvdmVzIHRyZWF0bWVudCwgb3IgaXMgdGhlIHBsYW4gdG8ga2lsbCB0aGUgaGVpciB3aGVuIGl0IGlzIGFsbCBvdmVyPyBIb3cgbXVjaCBpbnB1dCB3aWxsIHRoZSBlbXBsb3llciBhY2NlcHQgZnJvbSB0aGUgaGlyZWQgaGVscD8gSXMgdGhlIHBsYW4gYWxyZWFkeSBpbiBwbGFjZT9cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIktyb2dzIEJyb2tlbiBIZWFydFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIk1pc3BsYWNlZCBGb3J0dW5lXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJLcm9nIHdhcyBhIHNhdmFnZSBmcm9tIHRoZSBEYWdnZXIgSXNsZXMsIHByZXNzZWQgaW50byBzZXJ2aWNlIG9uIGEgaHVudGluZyBzaGlwLiBIZSBldmVudHVhbGx5IG93bmVkIGEgc21hbGwgZmxlZXQuIEhlIHdhcyBvbGQgd2hlbiBoZSBmZWxsIGluIGxvdmUgd2l0aCBhIHlvdW5nIHdvbWFuIHdobyByb2JiZWQgaGltLiBIZWFydGJyb2tlbiwgaGUgdG9vayB0aGUgcmVzdCBvZiBoaXMgdHJlYXN1cmUgYWJvYXJkIGhpcyBsYXN0IGh1bnRpbmcgc2hpcCwgSGVhcnRzb25nLCBhbmQgc2N1dHRsZWQgaGVyIGluIHRoZSBoYXJib3IuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIldoaXNwZXJzIGxpa2UgdG8gYnJhZyB0aGV5IGZvdW5kIGEgd2F5IHVuZGVyIHRoZSB3YXZlcyB0byBmaW5kIHRoZSB3ZWFsdGguIEdyYWNtYWFzIHRoZSBQaXJhdGUgY2xhaW1lZCB0byBoYXZlIHJlY292ZXJlZCBpdCBhbGwgdG8gaGlzIGhpZGRlbiBsYWly4oCUYmVmb3JlIGhlIHdhcyBraWxsZWQuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJMaW1wdHdpdGNoJ3MgU3Rhc2hcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJNaXNwbGFjZWQgRm9ydHVuZVwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiTGltcHR3aXRjaCB3YXMgYSBXaGlzcGVyIHdobyBpbnRlcnJvZ2F0ZWQgZ2hvc3RzIHRvIGZpbmQgdGhlIGxvY2F0aW9uIG9mIGhpZGRlbiB0cmVhc3VyZS4gSGUgd2FzIGZhbW91cyBmb3IgaGlzIEdyb3R0bywgdGhlIHBsYWNlIHdoZXJlIGhlIHN0b3JlZCBhbGwgaGlzIHNhbHZhZ2VkIHdlYWx0aC4gTWFueSBmYWN0aW9ucyB0cmllZCB0byBnZXQgaGlzIHRyZWFzdXJlLCBidXQgaGUgbmV2ZXIgZ2F2ZSB1cCB0aGUgc2VjcmV0LiBUaGVuIGhlIHdhcyBqYWlsZWQgYW5kIGhhbmdlZC4gVGhlIEdyb3R0byB3YXMgbmV2ZXIgZm91bmQuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkRpZCBhIGNlbGxtYXRlIGluIHByaXNvbiBoZWFyIG11dHRlcmVkIGhpbnRzIGFzIHRvIGl0cyBsb2NhdGlvbj8gTWF5YmUgYSBXaGlzcGVyIGhhcyBjbHVlcyBiYXNlZCBvbiB3aGVyZSBoZSBsZWZ0IGhpcyBtYXJrIGluIHRoZSBzZXdlcnMuIEhhcyBzb21lb25lIGZpbmFsbHkgZm91bmQgYSByZWFsIGxlYWQ/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJNYXJrIG9mIHRoZSBWb2lkXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiUmVsaWdpb3VzIE9iamVjdFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiSXQgaXMgYW4gZWVyaWUgYmxhY2sgZGlzayBvZiBsZXZpYXRoYW4gYm9uZSwgYWJvdXQgdGhlIHNpemUgb2YgYSBkaW5uZXIgcGxhdGUgYnV0IGZpdmUgdGltZXMgYXMgdGhpY2suIFRoZSBib25lIGlzIGNhcnZlZCB3aXRoIGEgc3RyYW5nZSBjaXJjdWxhciBwYXR0ZXJuIHdpdGggcmF5cyBjdXR0aW5nIHRocm91Z2ggaXQuIFRoZSBwcmltaXRpdmUgYXJ0d29yayB3YXMgcG9saXNoZWQsIGFuZCBzaWx2ZXIgaW5sYWlkIGluIHRoZSBwYXR0ZXJuLCBieSBhIGRlY2FkZW50IG5vYmxlbWFuLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJJbXByZXNzaW9uYWJsZSBwZW9wbGUgYWRtaXQgdGhlIGRpc2sgd2hpc3BlcnMgdG8gdGhlbSwgdGhleSBoZWFyIHRoZSBCYWNrIG9mIHRoZSBNaXJyb3Igd2hlbiBpdCB0aGUgZGlzayBpcyBuZWFyLiBNYW55IGN1bHRzIHNlZSB0aGlzIGRpc2sgYXMgYSBjb25kdWl0IHRvIGNsZWFyZXIgY29tbXVuaWNhdGlvbiB3aXRoIHRoZWlyIHN1cGVybmF0dXJhbCBwYXRyb25zLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTmFsYWRpY2hhJ3MgQ2FydG9ncmFwaHlcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJIaXN0b3JpY2FsIEN1cmlvc2l0eVwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIGZhbW91cyBjYXJ0b2dyYXBoZXIgTmFsYWRpY2hhIGRpZWQsIGFuZCBoaXMgZ2hvc3Qgd2FzIHdvdmVuIGludG8gYSBzcGlyaXQgYW5jaG9yIGNvbm5lY3RlZCB0byBhIHBlbiBvbiBhIHdpcmUuIFRoZSBkcm9vcGluZyBwZW4gc2NyaWJibGVkIG5vbnN0b3AsIGRpcHBpbmcgdG8gaW5kaWNhdGUgYSBwYWdlIHR1cm4uIFR3byBib29rcyB3ZXJlIGZpbGxlZCB3aXRoIHNjcmliYmxlcyBiZWZvcmUgdGhlIHBlbiBzdGlsbGVkLiBUaGVzZSBsaW5lcyBhbmQgc2hhcGVzIG1heSBiZSBtYXBzIG9mIHRoZSBHaG9zdCBGaWVsZC5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiT25lIGNvbnN1bHRpbmcgV2hpc3BlciByZXBvcnRlZCB0aGF0IHdoZW4gc2hlIGF0dHVuZWQgdG8gdGhlIGJvb2tzIHVzaW5nIGFuIGV4cGVuc2l2ZSBhbmQgZGlmZmljdWx0IHJpdHVhbCwgdGhlIG1hcHMgYmVjYW1lIGx1bWlub3VzIGFuZCBmb3VyIGRpbWVuc2lvbmFsLCByZXZlYWxpbmcgbG9zdCBzZWNyZXRzIGluIER1c2t3YWxsLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiTm9yc2N5ZSdzIExhbWVudFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkZhbW91cyBKZXdlbFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhpcyBydWJ5IGhhcyBiZWVuIHNldCBpbiBhIHNlcmllcyBvZiB3ZWFwb25zIGZvciB0aGUgbGFzdCB0aHJlZSBjZW50dXJpZXMuIE9uZSBlc3RpbWF0ZSB3YXMgdGhhdCB0aGUgZ2VtIGhhZCBwYXJ0aWNpcGF0ZWQgaW4gdXB3YXJkcyBvZiBhIHRob3VzYW5kIGRlYXRocy4gTGVnZW5kIHN1Z2dlc3RzIHRoYXQgdGhlIHJ1YnkgY2FuIGhvbGQgYSBzaW5nbGUgZ2hvc3QsIHN1cnZpdmluZyB0aGUgZGVzdHJ1Y3Rpb24gb2YgdGhlIGJvZHksIGJvdW5kIHRvIHRoZSBnZW0gdW50aWwgaXQgY2hvb3NlcyBhbm90aGVyIGd1ZXN0LlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJXaGlsZSB0aGUgZ2Vtc3RvbmUgaXMgcHJpY2VsZXNzIGJlY2F1c2Ugb2YgaXRzIHVubmF0dXJhbCBjbGFyaXR5LCBpdCBpcyBhbHNvIHBvc3NpYmxlIHRoYXQgYW4gaW1wb3J0YW50IGdob3N0IG1pZ2h0IGJlIGluc2lkZSwgYW5kIG1pZ2h0IGNob29zZSB0byBzcGVhayB0byBhIFdoaXNwZXIgb3IgYSBibG9vZCByZWxhdGl2ZS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIk9yYiBPZiBTZWxsaXZhc1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIldlaXJkIEFydGlmYWN0XCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGlzIGZpc3Qtc2l6ZWQgZ29sZGVuIG9yYiB0dW5lcyB0byBvbmUgYmVhcmVyIGF0IGEgdGltZSwgdGhvdWdoIGl0IG1heSByZXNwb25kIHRvIG90aGVycy4gSWYgY29tbWFuZGVkLCBpdCBjYW4gcmVsZWFzZSBhIHN0ZWFkeSBsaWdodCB0aGF0IHJhZGlhdGVzIGluIHRoZSBtYXRlcmlhbCB3b3JsZCBhbmQgdGhlIEdob3N0IEZpZWxkLCByZXZlYWxpbmcgd2hhdCBpcyBoaWRkZW4uIFRoZSByYWRpYXRpb24gY2FuIGFsc28gZHJhdyBvciByZXBlbCBnaG9zdHMgYW5kIGRlbW9ucy5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiVGhlIFNlbGxpdmFzIG9yZGVyIG9mIHdpdGNoZXMgd3JvdGUgdGhlaXIgcmVzZWFyY2ggam91cm5hbHMgaW4gYW4gaW5rIHRoYXQgY2FuIG9ubHkgYmUgcmVhZCBieSB0aGUgbGlnaHQgb2YgdGhlIE9yYi4gSWYgc29tZW9uZSBoYWQgdGhlIE9yYiBhbmQgdGhlIFxcXCJibGFua1xcXCIgYm9vaywgdGhleSBjb3VsZCBjcmFjayBhbmNpZW50IHNlY3JldHMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJQbGFudCBFdmlkZW5jZVwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlNlY3JldCBEaXJ0eSBXb3JrXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJTb21lb25lIG5lZWRzIHRvIGJlIGZvdW5kIGd1aWx0eSBvZiBkb2luZyBzb21ldGhpbmcuIEZvciB0aGF0IHRvIHdvcmsgb3V0LCB5b3UgbmVlZCBldmlkZW5jZSwgcHV0IGluIHRoZSB3cm9uZyBwbGFjZSBhdCB0aGUgd3JvbmcgdGltZS4gVG8gbWFuYWdlIHRoYXQsIHlvdSBuZWVkIHByb3BlciBzY291bmRyZWxzLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJEbyB5b3Uga25vdyB3aGF0IHRoZSB0YXJnZXQgd2lsbCBiZSBhY2N1c2VkIG9mIGRvaW5nPyBBcmUgeW91IHRvIGxlYWQgdGhlIGF1dGhvcml0aWVzIHRvIHRoZSBldmlkZW5jZT8gTXVzdCBzb21lb25lIGJlIHNlZHVjZWQgYmVmb3JlIGEgaGlkZGVuIHdpdG5lc3M/IEFyZSB0aGUgc2NvdW5kcmVscyBtYWtpbmcgZXZpZGVuY2UsIG9yIHVzaW5nIHdoYXQgdGhleSdyZSBnaXZlbj8gV2hhdCBpZiB0aGV5IGNvdWxkIGRvIGJldHRlcj8gTXVzdCB0aGUgZXZpZGVuY2UgZm9vbCBhIGNvdXJ0LCBvciBhIHBvd2VyZnVsIGluZGl2aWR1YWw/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJQbGFzbWljIEJsYWRlIEZsYWlsXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgQXJ0aWZhY3RcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoaXMgd2VhcG9uIGNhbiBzbGF5IGdob3N0cyBhbmQgZGVtb25zLiBJdCBhcHBlYXJzIHRvIGJlIGEgZ2xhZGl1cyBzdGl0Y2hlZCB3aXRoIHJ1bmVzLiBPbmNlIHRoZSBiZWFyZXIgYXR0dW5lcyB0byB0aGUgd2VhcG9uLCBpdCBjYW4gZGlzY29ubmVjdCBpbnRvIHZlcnRlYnJhdGUtbGlrZSB3ZWRnZXMgY29ubmVjdGVkIGJ5IGEgc3RlZWx5IGNlbnRyYWwgY2FibGUuIFRoZSBibGFkZS13aGlwIGlzIGZsZXhpYmxlIGFuZCBzaW1tZXJpbmcgd2l0aCBlbmVyZ3kuIEl0IGNhbiByZWZvcm0gaW50byBhIHN0cmFpZ2h0IGJsYWRlIGF0IHdpbGwuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIk9ubHkgZml2ZSBvZiB0aGVzZSBmbGFpbHMgZXZlciBleGlzdGVkLiBPbmUgaXMgY2FycmllZCBieSB0aGUgU3Bpcml0IFdhcmRlbiBhc3NpZ25lZCB0byB0aGUgSW1tb3J0YWwgRW1wZXJvcidzIGRlZmVuc2UuIFRoZSByZXN0IGFyZSB0aGUgc3R1ZmYgb2YgbGVnZW5kcy5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlJlbW90ZSBXcml0ZXJcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJXZWlyZCBBcnRpZmFjdFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhpcyBsaXR0bGUgYm9vayBoYXMgYSBwZWN1bGlhciBvY2N1bHQgc3ltYm9sIG9uIHRoZSBjb3Zlci4gSWYgYW4gb2JqZWN0IGlzIHBsYWNlZCBiZXR3ZWVuIHRoZSBjb3ZlcnMgZm9yIGEgZnVsbCAyNCBob3VycywgdGhlbiB0aGUgYm9vayB3aWxsIHRyYW5zY3JpYmUgYW55IGNvbnZlcnNhdGlvbiBoYXBwZW5pbmcgaW4gZWFyc2hvdCBvZiB0aGUgb2JqZWN0IHVudGlsIHJlc2V0LiBXaGVuIHRoZSBib29rIHJlYWNoZXMgdGhlIGVuZCwgdGhlIHdyaXRpbmcgc3RhcnRzIG92ZXIgb24gdGhlIGZpcnN0IHBhZ2UsIGNsZWFyaW5nIHBhZ2VzIGFzIGl0IGdvZXMuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIlRoZSBib29rIHByb3ZpZGVzIHJlbW90ZSByZWFkaW5nLCBlYXZlc2Ryb3BwaW5nIG9mIGEgc29ydC4gQSB0YXJnZXQncyBmYXZvcml0ZSBwZW4gb3IgbHVja3kgY29pbiBjYW4gYmVjb21lIHRoZSBicm9hZGNhc3RlciwgYW5kIGRldGVybWluZWQgc3BpZXMgY2FuIGNvcHkgdGhlIG1hZ2ljIGJvb2sgd3JpdGluZyBzbyB0aGV5IGRvbid0IGxvc2UgaXQuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJSeWxhcmlhJ3MgU2hpZWxkXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtaWx5IEhlaXJsb29tXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJSeWxhcmlhIEdyYWVmd29sZCB3YXMgYSBzb2xkaWVyIHdobyBnYWluZWQgdGl0bGUgYW5kIHdlYWx0aC4gU2hlIHdyb3RlIGhlciBsaWZlJ3Mgc3Rvcnkgb24gdGhlIGJhY2sgb2YgdGhlIHNoaWVsZCBzaGUgdXNlZCB0byBzYXZlIGEgZ2VuZXJhbC4gTGF0ZXIgZ2VuZXJhdGlvbnMgYWRkZWQgdG8gdGhlIGZhbWlseSBzdG9yeS4gVGhlIHNoaWVsZCByZXByZXNlbnRzIHRoZSBmYW1pbHkncyBob25vci4gSXQgd2FzIGxvc3QgYXQgc2VhIHdoZW4gdGhlaXIgZmlyc3QgbGV2aWF0aGFuIGh1bnRpbmcgc2hpcCB3YXMgd3JlY2tlZC4gT3Igd2FzIGl0P1wiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJOb3cgdGhlIGZhbWlseSBpcyB3ZWFsdGh5LCBhbmQgdGhpcyBhcnRpZmFjdCB3b3VsZCBiZSBpbXBvcnRhbnQgdG8gdGhlbS4gRG9lcyBpdCBoYXZlIGEgc2VjcmV0IGluIGNvZGU/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTa292bGFuIFNjcmlwXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiTWlzcGxhY2VkIEZvcnR1bmVcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIkEgZGVuc2UgbG9ja2JveCBmaWxsZWQgd2l0aCBwYXBlciBtb25leSBpc3N1ZWQgYnkgdGhlIEFrb3Jvc2lhbiBnb3Zlcm5tZW50IHRvIHBheSBzb2xkaWVycyBxdWVsbGluZyB0aGUgU2tvdmxhbmRlciBJbnN1cnJlY3Rpb24uIFRoZSBzY3JpcCBjYW4gYmUgZXhjaGFuZ2VkIGZvciBjb2lucyBvciBzZXJ2aWNlcyBpbiBEdXNrd2FsbC4gU2NyaXAgaXMgYmFzaWNhbGx5IHVudHJhY2VhYmxlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJTb21lIG9mIHRoZSBtaWxpdGFyeSBzdXBwbHkgdGhhdCBnb3QgbG9zdCBkdXJpbmcgdGhlIHdhci4gRG9lcyB0aGUgc3Rhc2hzIGxvY2F0aW9uIGltcGxpY2F0ZSBhIGNvcnJ1cHQgb2ZmaWNpYWwgb3Igb3RoZXIgdGhpZWY/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJTb251cmlhbiBHaG9zdCBLZXlcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJGYW1pbHkgSGVpcmxvb21cIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSBTb251cmlhIGZhbWlseSBoYWQgbWFuc2lvbnMgaW4gdGhlIGFyZWEgdGhhdCBpcyBub3cgdGhlIFNldmVuIFNoYWxsb3dzIHNsdW0uIFRoZXkgY3JlYXRlZCBhIHZhdWx0IGZvciB0aGUgcHJvdGVjdGVkIGRlYWQsIGFuZCBmb3IgdGhlaXIgbXVuZGFuZSB0cmVhc3VyZXMuIFRoZSBvbmx5IHdheSBpbiBpcyBmb3IgYSBmYW1pbHkgbWVtYmVyIHRvIHByZXNlbnQgdGhlIFNvbnVyaWFuIEdob3N0IEtleSBiZWZvcmUgdGhlIGhpZGRlbiBsb2NhdGlvbiBvZiB0aGUgdmF1bHQgaW4gdGhlIEdob3N0IEZpZWxkLiBUaGUga2V5IGhhcyBiZWVuIGxvc3QgZm9yIGRlY2FkZXMuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIlRoYXQga2V5IGNvdWxkIGJlIGhpZGRlbiBhbnl3aGVyZS4gSWYgaXQgd2VyZSBmb3VuZCwgZWl0aGVyIGEgZmFtaWx5IG1lbWJlciBjb3VsZCBiZSByZWNydWl0ZWQgdG8gb3BlbiB0aGUgZG9vciwgb3IgdGhlIGtleSBjb3VsZCBiZSBzb2xkIHRvIHRoZSBmYW1pbHkuIFdoYXQgZG9lcyB0aGUga2V5IGxvb2sgbGlrZT8gV2hhdCBpcyBpbnNpZGUgdGhlIHZhdWx0P1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiU291bHRyYXAgQ2FybmVsaWFuXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtb3VzIEpld2VsXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGlzIHNlbWktcHJlY2lvdXMgc3RvbmUgd2FzIGNhcnZlZCBieSB0aGUgV2hpc3BlciBJY2hyYWxpYS4gU2hlIHN1ZmZvY2F0ZWQgcGVvcGxlIHdpdGggaG90IHdheCBhbmQgYm91bmQgdGhlaXIgZnJlc2ggZ2hvc3RzIGluIHdheCBzZWFscyBvbiBzY3JvbGxzIG9yIGxldHRlcnMgd2l0aCB0aGUgU291bHRyYXAuIFdoZW4gdGhlIHNlYWwgd2FzIGJyb2tlbiwgdGhlIGluc2FuZSBnaG9zdCBhdHRhY2tlZCB0aGUgb3BlbmVyIGFuZCBhbnlvbmUgbmVhcmJ5LlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJUaGUgU3Bpcml0IFdhcmRlbnMgZGVzdHJveWVkIHRoaXMgb2JqZWN0IGRlY2FkZXMgYWdvLiBEaWRuJ3QgdGhleT8gTWF5YmUgc29tZW9uZSBlbHNlIG1hZGUgYW5vdGhlciBvbmUsIG9yIG1heWJlIHRoZSBvcmlnaW5hbCBzdXJ2aXZlZC5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlN0ZWFsIEJsYWNrbWFpbFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIlNlY3JldCBEaXJ0eSBXb3JrXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJTZWNyZXRzIG11c3QgYmUgcHJvdGVjdGVkLiBJZiB0aGV5IGNvbWUgb3V0LCBwZW9wbGUgY2FuIGdldCBodXJ0LCBydWluZWQsIGtpbGxlZCwgYW5kIHNvIG9uLiBZb3UgYXJlIGhpcmVkIHRvIGFkanVzdCB0aGUgY2lyY2xlIG9mIHBlb3BsZSB3aG8gY2FuIHByb3ZlIHNvbWV0aGluZy4gV2lsbCBpdCBiZSBiaWdnZXI/IE9yIHNtYWxsZXI/XCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIkRvIHlvdSBrbm93IHdoYXQgaW5mb3JtYXRpb24geW91J3JlIGFmdGVyLCBvciBpcyB0aGF0IHNlY3JldCBmcm9tIHlvdT8gSWYgeW91IGhhdmUgYSBjaGFuY2UsIHdpbGwgeW91IHBlZWsgYXQgaXQ/IEFyZSB5b3UgdGFyZ2V0aW5nIGEgYmxhY2ttYWlsZXIgdG8gcmVtb3ZlIHRoZWlyIGhvbGQsIG9yIGdldHRpbmcgZXZpZGVuY2UgdG8gZ2l2ZSBhIGJsYWNrbWFpbGVyPyBJcyB0aGUgZXZpZGVuY2UgdG8gYmUgZGVzdHJveWVkPyBEbyB5b3UgcGxhbiB0byBkbyBhcyB5b3UgYXJlIHRvbGQ/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUZXJyb3JpemVcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJTZWNyZXQgRGlydHkgV29ya1wiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiUGVvcGxlIGNhbiBiZSBzdHViYm9ybiwgdG8gdGhlIHBvaW50IHdoZXJlIG9ubHkgZmVhciBjYW4gdW5zZWF0IHRoZWlyIGRlY2lzaW9uLiBNYXliZSB0aGV5IGZlZWwgaW5kZXBlbmRlbnQgYW5kIG5lZWQgdG8gcmVtaW5kZWQgdGhhdCB0aGV5IG5lZWQgcHJvdGVjdGlvbi4gTWF5YmUgdGhleSBmZWVsIHNhZmUgYW5kIG5lZWQgdG8gYmUgcmVtaW5kZWQgdGhleSBhcmUgbm90IHVudG91Y2hhYmxlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJBcmUgeW91IHN1cHBvc2VkIHRvIGJlIHNvbWVvbmUgaW4gcGFydGljdWxhciwgbGlrZSBhIHJhbmRvbSBzdHJlZXQgdGh1ZyBvciByaXZhbCdzIGVtcGxveWVlIG9yIGJsdWVjb2F0PyBIb3cgZmFyIGNhbiB0aGUgdGVycm9yIGdvPyBEbyB5b3UgbmVlZCB0byB0cmFzaCBhIGhvbWUsIG9yIG1heWJlIGNvbnZlcnNlIHdpdGggYSBsb3ZlZCBvbmU/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUaGUgRW1lcmFsZCBXZWxsXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtb3VzIEpld2VsXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGlzIGRlcHRobGVzcyBnZW0gaXMgYSBjaGlsbHkgcGluaG9sZSBiZXR3ZWVuIHRoZSBtYXRlcmlhbCB3b3JsZCBhbmQgdGhlIEdob3N0IEZpZWxkLiBJdCBwcm92aWRlcyBlbmVyZ3kgdG8gV2hpc3BlcnMgYW5kIGF0dHJhY3RzIGdob3N0cy4gVGhlIEVtZXJhbGQgV2VsbCB3YXMgcHJvdGVjdGVkIGJ5IHRoZSBDaHVyY2ggb2YgdGhlIEVjc3Rhc3kgb2YgdGhlIEZsZXNoLCBidXQgYSB0aGllZiBzdG9sZSBpdCBkZWNhZGVzIGFnby4gSXQgaXMgYSBob3RzcG90IGZvciBzdXBlcm5hdHVyYWwgYWN0aXZpdHkuIERpc2FzdGVyIGZsb3dzIGluIGl0cyB3YWtlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJUaGlzIGlzIG9uZSBvZiB0aGUgZmV3IG9iamVjdHMgcHVyc3VlZCBieSBkZW1vbnMsIFdoaXNwZXJzLCBpbnNwZWN0b3JzLCBjbGVyZ3ksIGFuZCBjb2xsZWN0b3JzLiBTY2hvbGFycyBzdWdnZXN0IGRlbW9ucyBtYXkgYmUgYWJsZSB0byB0dXJuIGl0IGluc2lkZSBvdXQsIGNyZWF0aW5nIGEgZnJlc2ggZ2F0ZSB0byBpbmNhcm5hdGUgbW9yZSBkZW1vbnMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUaGUgSGVsbHdoaXNwZXIgUmluZ1wiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIldlaXJkIFNjaG9sYXJzaGlwXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgcmluZyBpcyBtYWRlIG9mIHRpbnkgYml0cyBvZiBib25lIHdpcmVkIHRvZ2V0aGVyLiBJdCBtdXN0IGJlIHdvcm4gZm9yIGF0IGxlYXN0IGEgZGF5IHBlciB5ZWFyIG9mIHRoZSBiZWFyZXIncyBsaWZlIGJlZm9yZSBpdCBiZWdpbnMgdG8gd29yay4gV2hlbiBwbGFjZWQgb24gYSBzb3VyY2Ugb2YgaW5mb3JtYXRpb24sIHRoZSByaW5nIHNpZnRzIGl0IHVudGlsIHRoZSByaW5nIHNwZWFrcyB0aGUgaW5mb3JtYXRpb24ncyBcXFwibGFuZ3VhZ2UuXFxcIiBUaGUgYmVhcmVyIGNhbiBzZWUgdGhyb3VnaCByaWRkbGVzLCByZWFkIGFyY2FuZSB0ZXh0cywgYW5kIGJyZWFrIGNvZGUgd2l0aCBlYXNlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJMZWdlbmQgc2F5cyAzMiBkZW1vbnMgdm9sdW50YXJpbHkgZ2F2ZSBzb21lIG9mIHRoZWlyIGJvbmUgdG8gYmUgcGFydCBvZiB0aGlzIHJpbmcsIGFuZCBpdCB3YXMgcmVsZWFzZWQgYW1vbmcgaHVtYW5zIHRvIGNhdXNlIGNoYW9zIHRocm91Z2ggZ3JlYXRlciB1bmRlcnN0YW5kaW5nLlwiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGhlIEhlbHNtYW4gSW5oZXJpdGFuY2VcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJNaXNwbGFjZWQgRm9ydHVuZVwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhlIGZpbmFsIHdpbGwgYW5kIHRlc3RhbWVudCBvZiB0aGUgY2xhbidzIHBhdHJpYXJjaCBpbmNsdWRlZCBhIDI0IGhvdXIgbG9ja2VkLWhvdXNlIGNvbmRpdGlvbi4gU3Vydml2b3JzIHdvdWxkIHNwbGl0IHRoZSBpbmhlcml0YW5jZS4gRGFyYXlsIEhlbHNtYW4gbGVmdCB0aGUgaG91c2UgYXQgdGhlIGVuZCBvZiB0aGUgdGltZSB3aXRoIGEgc21hbGwgYmFnLiBFeHBsb3JlcnMgZm91bmQgbm90aGluZyBidXQgY29ycHNlcyBpbiB0aGUgaG91c2UsIHRoZSBpbmhlcml0YW5jZSB3YXMgZ29uZS4gRGFyYXlsIHdhcyBmb3VuZCBkZWFkIHRoZSBuZXh0IGRheSwgdGhlIGJhZyBnb25lLiBUaGUgY2l0eSBsb2NrZWQgdGhlIGhvdXNlIGFuZCBndWFyZHMgYWdhaW5zdCB0cmVzcGFzc2Vycy5cIixcbiAgICAgICAgICAgICAgICBuYXJyYXRpdmU6IFwiU3VyZWx5IERhcmF5bCBoaWQgdGhlIGluaGVyaXRhbmNlIGluIHRoZSBHaG9zdCBGaWVsZC4gRmluZCB0aGUgZ2hvc3Qga2V5IGFuZCBsb2NrIGluIHRoZSBob3VzZSwgYW5kIGdldCBpdCBhbGwhIE9yLCBkaWQgc29tZW9uZSBlbHNlIGFscmVhZHkgZ2V0IGl0P1wiXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiVGhlIEtleSBMZW5zXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgU2Nob2xhcnNoaXBcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoZSByb3VuZCBmcmFtZSBoYXMgZm9ydHkgc3BlY2lhbCBsZW5zZXMgaGluZ2VkIG9uIGl0cyByaW0uIFRoZSBsZW5zZXMgY2FuIGxheWVyIG92ZXIgZWFjaCBvdGhlciwgZmxpcCBvdXQgcGFzdCB0aGUgZnJhbWUsIHJvdGF0ZSB0byB0YWtlIGFkdmFudGFnZSBvZiB0aGUgYW5nbGVzIGluc2lkZSB0aGUgZ3JvdW5kIGNyeXN0YWwsIGFuZCB0YWtlIHRyYW5zbHVjZW50IGNvbG9yZWQgZmlsdGVycy4gVGhlaXIgaW52ZW50b3IsIFZMQVMgSEFMREFLLCBzYWlkIGhlIGhhZCBmb3VuZCBcXFwidGhlIGtleS5cXFwiIEhlIGRpZWQgb2Ygc2hvY2ssIHRoZSBsZW5zIG9uIGhpcyB3b3JrIHRhYmxlLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJMZWdlbmRzIHZhcnkuIEl0IGNhbiBzZWUgaW50byB0aGUgR2hvc3QgRmllbGQsIGl0IGNhbiBzZWUgaW50byBwZW9wbGUsIGl0IGFsbG93cyByZWFkaW5nIGRlbW9uaWMgdGV4dHMsIGl0IGNhbiBzZWUgdGhlIHdheSBpbnRvIGdob3N0IG5laWdoYm9yaG9vZHMsIGV0Yy4gTmVlZHMgYSBXaGlzcGVyIHRvIHVzZSBwcm9wZXJseS5cIlxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlRoZSBMZXZpYXRoYW4ncyBFeWVcIixcbiAgICAgICAgICAgICAgICBjYXRlZ29yeTogXCJGYW1vdXMgSmV3ZWxcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIlRoaXMgc2FwcGhpcmUgdHVybnMgaW1wb3NzaWJseSBibGFjayBpZiBkaXBwZWQgaW4gbGV2aWF0aGFuIGJsb29kLiBJZiB0aGUgc3RpbGwtYmxvb2R5IHN0b25lIGlzIHByZXNzZWQgYWdhaW5zdCBhIHNlZXIncyBmb3JlaGVhZCwgdGhlIHNlbnNpdGl2ZSBjYW4gc2VlIHdoYXQgdGhlIG9jZWFuIHNlZXMsIGxvb2tpbmcgYWJvdmUgdGhlIHdhdmVzIG9yIHByb2JpbmcgdGhlIGRlZXBzLiBUaGUgZ2VtIHVzZWQgdG8gYmUgcGFzc2VkIGFyb3VuZCBiZXR3ZWVuIGxldmlhdGhhbiBodW50ZXIgY2FwdGFpbnMsIGJ1dCBoYXMgc2luY2UgYmVlbiBsb3N0LlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJPbmUgZXhwZXJ0IHNhaWQgdXNpbmcgdGhlIEV5ZSB3YXMgYXMgY2xvc2UgYXMgYSBodW1hbiBjb3VsZCBnZXQgdG8gYSBkZW1vbiBzZWVpbmcgdGhyb3VnaCBpdHMgZWxlbWVudGFsIGFmZmluaXR5LCBhbmQgdGhhdCBpdCBiZWdhbiBhIHNsb3cgY2hhbmdlIGluIHRoZSBpbmRpdmlkdWFsIHdobyB3YXMgZXhwb3NlZCB0byBpdHMgcG93ZXIuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUaGUgVGFiaXNzZXJhIERpYXJ5XCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiV2VpcmQgU2Nob2xhcnNoaXBcIixcbiAgICAgICAgICAgICAgICBkZXNjOiBcIldhcmRlbiBLaGFsYW5hIFVyZXNzIHdhcyB0aGUgSGVhZCBDb25mZXNzb3Igb2YgdGhlIFNwaXJpdCBXYXJkZW5zLiBTaGUgcmVjb3JkZWQgc2VjcmV0cyB0aGF0IHdlcmUgb25seSBmb3IgdGhlIHVzZSBvZiB0aGUgb3JkZXIgdXNpbmcgYSBib29rIGNvZGUsIGNvb3JkaW5hdGVzIHRoYXQgcG9pbnRlZCB0byB3b3JkcyBpbiBhIHNwZWNpZmljIGJvb2suIFdpdGhvdXQgdGhhdCBib29rLCB0aGUgY29kZSBjYW5ub3QgYmUgY3JhY2tlZC4gRGFyaW5nIHRoaWV2ZXMgdG9vayB0aGUgYm9vaywgdGhlbiBsb3N0IGl0LlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJGYWtlcyBjb21lIG9uIHRoZSBtYXJrZXQgYWxsIHRoZSB0aW1lLiBPbmx5IHRoZSBTcGlyaXQgV2FyZGVuIGxlYWRlcnNoaXAga25vdyB3aGF0IHRoZSBib29rIGxvb2tlZCBsaWtlLCBhbmQgdGhleSBhcmVuJ3QgdGVsbGluZy4gV2hhdCBpcyB0aGUgRGlhcnkgYWJvdXQ/XCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJUaGUgVGhvdXNhbmQgRmFjZXQgRGlhbW9uZFwiLFxuICAgICAgICAgICAgICAgIGNhdGVnb3J5OiBcIkZhbW91cyBKZXdlbFwiLFxuICAgICAgICAgICAgICAgIGRlc2M6IFwiVGhpcyBnZW0gaXMgdGhlIGVsZWdhbnQgY2VudGVycGllY2Ugb24gdGhlIGJhY2sgb2YgYSBwZWN1bGlhciBjbG9ja3dvcmsgZ2F1bnRsZXQuIEEgc2VlciBjYW4gdXNlIHRoZSBnYXVudGxldCB0byB0cmF2ZWwgaW50byB0aGUgR2hvc3QgRmllbGQgd2hpbGUgcmV0YWluaW5nIHBoeXNpY2FsIHByZXNlbmNlLCBvciBwb3NzaWJseSBldmVuIG90aGVyIGRpbWVuc2lvbnMuIEVhY2ggdXNlIGJ1cm5zIG91dCBzb21lIG9mIHRoZSBkaWFtb25kIGZhY2V0cy4gVGhlIGRldmljZSBpcyByZXBvcnRlZCB0byBoYXZlIGEgbWluZCBvZiBpdHMgb3duLlwiLFxuICAgICAgICAgICAgICAgIG5hcnJhdGl2ZTogXCJFdmVyIHNpbmNlIGl0cyB0aGVmdCBmcm9tIHRoZSBBZGVsYWlyZGUgZmFtaWx5LCB0aGUgZ2F1bnRsZXQgaGFzIHN1cmZhY2VkIG9ubHkgaW4gcnVtb3JzIG9mIGVzcGVjaWFsbHkgZGFyaW5nIGhlaXN0cyBvciBtaW5kLXNoYXR0ZXJpbmcgZXhwZXJpbWVudHMuXCJcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgbmFtZTogXCJXaGl0ZWNyb3duIFNpZ25ldCBSaW5nXCIsXG4gICAgICAgICAgICAgICAgY2F0ZWdvcnk6IFwiRmFtaWx5IEhlaXJsb29tXCIsXG4gICAgICAgICAgICAgICAgZGVzYzogXCJUaGUgV2hpdGVjcm93biBmYW1pbHkgc2NoaXNtZWQgaW4gdGhlIHdha2Ugb2YgdGhlIHRoZWZ0IG9mIHRoZSBtYXRyaWFyY2gncyBzaWduZXQgcmluZyBvdmVyIHR3byBjZW50dXJpZXMgYWdvLiBUaGV5IGZlbGwgZnJvbSBiZWluZyBwbGF5ZXJzIGluIHRoZSBpbnRyaWd1ZXMgYXJvdW5kIHRoZSB0aHJvbmUgdG8gYmlja2VyaW5nIG92ZXIgZHdpbmRsaW5nIGZhbWlseSBob2xkaW5ncy4gVGhlaXIgd2VhbHRoIGFuZCBpbmZsdWVuY2UgaXMgbG93LCBidXQgbm90IGJleW9uZCByZWNhbGwuXCIsXG4gICAgICAgICAgICAgICAgbmFycmF0aXZlOiBcIklmIHRoZSByaW5nIHJlc3VyZmFjZWQsIGVsZW1lbnRzIG9mIHRoZSBmZXVkIG1pZ2h0IHB1dCBhc2lkZSB0aGVpciBkaWZmZXJlbmNlcyBhbmQgcmV1bml0ZS4gQmVzaWRlcywgbGVnZW5kcyBzdWdnZXN0IGEgZ2hvc3QgbWF0cmlhcmNoIGlzIGJvdW5kIHRvIHRoZSByaW5nLCBhbmQgc2hlIGtub3dzIHRoZWlyIHNlY3JldHMuXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgXVxuICAgIH1cbn07XG5leHBvcnQgY29uc3QgQ2xvY2tLZXlfU1ZHREFUQSA9IHtcbiAgICAxOiB7XG4gICAgICAgIGhlaWdodDogODM2LFxuICAgICAgICB3aWR0aDogMjMwLFxuICAgICAgICBwYXRoczogW1xuICAgICAgICAgICAgXCJNMjE3LjAxNywxMjMuNTJjLTEuNi0wLjgtMi44NC0xLjQ0LTQuMS0yLjA0Yy0xLjEyLTAuNTMtMi4yNi0xLjA0LTMuNDItMS41MSBjLTEuMDUtMC40My0yLjE4LTAuNjgtMy4xOC0xLjE5Yy0wLjg5LTAuNDUtMS4yMy0xLjIzLTEuMi0yLjM2YzAuMDktNC40OC0wLjA3LTguOTcsMC4wNS0xMy40NWMwLjA4LTMuMzEtMC44My02LjQ3LTEuMTQtOS43MiBjLTAuMDEtMC4xNC0wLjA5LTAuMjgtMC4xNC0wLjQyYy0wLjU3LTIuMDEtMS4yLTQuMDEtMS42OS02LjA0Yy0wLjQ1LTEuODUtMC43NS0zLjc0LTEuMTEtNS42MSBjLTAuMDEyLTAuMDQzLTAuMDIzLTAuMDg1LTAuMDM1LTAuMTI3Yy0wLjYtMS42OS0xLjM0OC0zLjM1My0xLjgyNS01LjA4M2MtMC40Ni0xLjY2LTAuNjgtMy4zOC0xLjAzLTUuMDcgYy0wLjA0LTAuMjQtMC4xNi0wLjQ3LTAuMjUtMC43Yy0wLjQ5LTEuMzItMC45OC0yLjY1LTEuNDctMy45N2MtMC41NS0xLjQ0LTAuOTMtMi45Ny0xLjY5LTQuMjhjLTAuNzktMS4zNS0wLjY1LTMuMDMsMC42MS00LjE5IGMwLjQzLTAuMzksMC44NS0wLjg1LDEuMDgtMS4zNmMwLjU3LTEuMywxLjM1LTIuNjIsMS40NC0zLjk3YzAuMDgtMS4xMS0wLjQ2LTMuMDgtMS4xNC0zLjI5Yy0xLjU4LTAuNDctMy40OS0wLjQyLTUuMSwwLjAzIGMtMS40MSwwLjQtMi41OSwxLjYzLTQuMDcsMi42MmMtMS4xNS0xLjE4LTIuNDMtMi40MS0zLjYtMy43NWMtMC40MS0wLjQ3LTAuNDMtMS4yOS0wLjgyLTEuNzhjLTAuNjctMC44NC0xLjU2LTEuNS0yLjIzLTIuMzMgYy0wLjE4LTAuMjItMC4wOC0wLjksMC4xMy0xLjE2YzAuODUtMS4wMiwxLjc4LTEuOTcsMi43MS0yLjkyYzIuMTgtMi4yMiw0LjM3LTQuNDUsNi41Ny02LjY1YzAuODUtMC44NiwxLjc4LTEuNjQsMi42My0yLjUgYzEuMTYtMS4xNywyLjM4LTIuMjksMy4zNy0zLjU5YzAuNjYtMC44OCwwLjg5LTIuMDcsMS40Mi0zLjA2YzAuODYtMS42MywwLjAxLTMuMDItMC42OC00LjMxYy0wLjIzLTAuNDMtMS40LTAuNC0yLjE1LTAuNDggYy0wLjY5LTAuMDgtMS40LDAuMDItMi4wOS0wLjAyYy0xLjcxLTAuMTEtMy4xNCwwLjE3LTQuNTIsMS40N2MtMS4yMiwxLjE0LTIuOTYsMS43NC00LjQ0LDIuNjJjLTAuOTgsMC41OS0xLjg5LDEuMzEtMi44OCwxLjg4IGMtMi4wMiwxLjE3LTQuMiwyLjExLTYuMDcsMy40N2MtMS4xMiwwLjgxLTIuMTYsMS4xOC0zLjQ5LDEuNGMtMS4yOCwwLjIyLTIuNDQsMS4xLTMuNywxLjU5Yy0wLjU4LDAuMjMtMS43MiwwLjQ5LTEuODIsMC4zIGMtMC45MS0xLjYzLTIuNzUtMS43OS00LjAzLTIuNzdjLTAuMzMtMC4yNS0wLjU4LTAuNjItMC45My0wLjgyYy0xLjExLTAuNjQtMi4yNi0xLjIyLTMuMzgtMS44NWMtMS40OC0wLjgzLTIuOTQtMS43LTQuNDItMi41MyBjLTAuOTMtMC41My0xLjgzLTEuMjQtMi44NC0xLjVjLTEuMzctMC4zNS0yLjI0LTEuOTYtMy44OS0xLjVjLTAuMDgsMC4wMy0wLjE5LTAuMDItMC4yOS0wLjA0Yy0xLjk3LTAuNTgtMy45NC0xLjE2LTUuOTEtMS43MyBjLTAuMjgtMC4wOC0wLjc2LTAuMDItMC44NC0wLjE4Yy0wLjg5LTEuNy0yLjgtMS4yLTQuMS0xLjZjLTIuODMtMC44Ny01Ljk0LTAuODctOC45NC0xLjIyYy0wLjM5LTAuMDQtMS4wNSwwLjA2LTEuMTQtMC4xMyBjLTAuNzktMS41Ni0yLjIxLTEuMDEtMy40LTEuMDVjLTIuMDktMC4wOC0yLjY4LTAuNjItMi43Mi0yLjY1Yy0wLjAxLTAuODQtMC4xLTEuNjktMC4yNC0yLjUxYy0wLjE2LTAuODgtMC41NC0xLjcyLTAuNjItMi41OSBjLTAuMTMtMS4yNC0wLjAzLTIuNDktMC4xMS0zLjczYy0wLjA2LTAuODgtMC42MS0xLjQ1LTEuNS0xLjEzYy0wLjc5LDAuMjgtMS41OSwwLjcyLTIuMjEsMS4yOGMtMS40OCwxLjM2LTIuODUsMi44NC00LjI5LDQuMjUgYy0xLjEsMS4wOC0yLjA4LDIuMDYtMy44MSwyLjU1Yy0xLjU0LDAuNDQtMi45OSwxLjY5LTQuNjMsMi40MmMtMS43OSwwLjgtMy4yOCwyLjI1LTUuNDQsMi4xM2MtMC40NC0wLjAyLTEuMTYtMC4wMi0xLjI4LDAuMjIgYy0wLjcsMS4zNi0xLjk0LDAuODItMi45OCwwLjk3Yy0wLjQ5LDAuMDctMC45OSwwLjExLTEuNDcsMC4yNGMtMS45MiwwLjQ5LTMuODQsMC45OC01Ljc1LDEuNTJjLTEuNzQsMC40OS0zLjUxLDAuOTUtNS4xOSwxLjYxIGMtMS45MiwwLjc0LTMuNjcsMS45OS01LjYzLDIuNDZjLTEuNjQsMC4zOC0zLjAxLDEuMTMtNC41MSwxLjcyYy0wLjk5LDAuMzktMi41MiwwLjM4LTMuNDMtMC4xM2MtMS45My0xLjA5LTQuMjgtMS4wOS02LjAzLTIuNTQgYy0wLjIyLTAuMTktMC42Ny0wLjEyLTEuMDItMC4xM2MtMC45LTAuMDItMS43OS0wLjAyLTIuNjktMC4wMmMtMS4zNywwLjAxLTIuMTksMC43Mi0yLjM2LDIuMTVjLTAuMDksMC43OC0wLjA2LDEuNTktMC4wOSwyLjM4IGMtMC4wMSwwLjM1LDAuMTEsMC44Ny0wLjA2LDEuMDJjLTEuNjgsMS4zNS0wLjg5LDMuMjQtMS4xOCw0LjljLTAuMTYsMC44OC0wLjU2LDEuOC0xLjEsMi41MWMtMC43NSwwLjk5LTEuNzYsMS43OS0yLjYxLDIuNzIgYy0xLjAyLDEuMS0xLjk5LDIuMjYtMi45OSwzLjM5Yy0xLjQ5LDEuNjctMi45NiwzLjM3LTQuNSw1Yy0xLjM2LDEuNDUtMi44MSwyLjgzLTQuMiw0LjI1Yy0wLjE2LDAuMTctMC4xOSwwLjQ2LTAuMzEsMC42NyBjLTAuNzQsMS4yOS0xLjM5LDIuNjQtMi4yNSwzLjg0Yy0wLjg5LDEuMjUtMi42MywxLjg2LTIuNzIsMy43NWMtMC4wMiwwLjM4LTAuNTcsMC43My0wLjg2LDEuMTFjLTAuMzcsMC40OS0wLjc5LDAuOTYtMS4wNywxLjUgYy0wLjczLDEuMzktMS4yNiwyLjg5LTIuMSw0LjIxYy0xLjA4LDEuNzEtMi4yNSwzLjM0LTIuNjUsNS4zOGMtMC4wNywwLjMyLTAuMzksMC42LTAuNTcsMC45MWMtMC4yMSwwLjM0LTAuNDUsMC42Ny0wLjU5LDEuMDUgYy0wLjQzLDEuMjEtMC43MiwyLjQ4LTEuMjQsMy42NWMtMC43OSwxLjc2LTEuNzUsMy40NS0yLjYsNS4xOWMtMS4yNywyLjYtMi43NCw1LjEzLTMuNjksNy44NWMtMC41LDEuNDUtMC4xOCwzLjIzLTAuMDgsNC44NSBjMC4wNSwwLjcsMC42OCwxLjM3LDAuNjksMi4wNmMwLjA2LDYuMDcsMC4wNiwxMi4xNSwwLjAxLDE4LjIzYzAsMC43MS0wLjM3LDEuNDQtMC42MywyLjEzYy0wLjM1LDAuOTUtMS4wNCwxLjg1LTEuMDksMi44IGMtMC4wNywxLjMxLTEuMDQsMS45Mi0xLjYyLDIuODJjLTAuOTEsMS40My0yLjcxLDEuOS0zLjU5LDMuNTFjLTEuMDEsMS44NS0wLjk0LDMuOTEsMC40Niw1LjQxYzEuMTcsMS4yNCwyLjU5LDAuNzUsMy45MywwLjk3IGMxLjQxLDAuMjIsMy4wMSwwLjI2LDQuMTIsMC45OWMxLjExLDAuNzQsMS44NywyLjE2LDIuNSwzLjQzYzAuNzcsMS41NiwxLjM1LDMuMjQsMS44LDQuOTJjMC42NywyLjUsMC45NCw1LjEyLDIuMzIsNy40IGMwLjU2LDAuOTIsMS4wMywxLjksMS41MiwyLjg3YzAuNTEsMS4wMywwLjk2LDIuMDksMS40OCwzLjExYzAuNTYsMS4wOSwxLjEzLDIuMTgsMS43NywzLjIyYzAuMjksMC40OCwwLjg0LDAuOCwxLjE2LDEuMjYgYzAuNjEsMC44NywxLjExLDEuODIsMS43MSwyLjY5YzAuMzIsMC40NywwLjgzLDAuODEsMS4xNiwxLjI3YzAuOTMsMS4zLDEuNzksMi42NSwyLjczLDMuOTVjMC4zMSwwLjQzLDAuODMsMC42OSwxLjE1LDEuMTEgYzAuNTIsMC42OSwwLjg5LDEuNTEsMS40NCwyLjE2YzAuNDEsMC40OCwxLjEsMC43MiwxLjU0LDEuMThjMS41NywxLjY2LDMsMy40Niw0LjY1LDUuMDNjMS4zLDEuMjYsMi45MSwyLjE4LDQuMjUsMy40IGMxLjk5LDEuODQsMy44MiwzLjg1LDUuODEsNS43YzAuNTEsMC40NywxLjQyLDAuNDcsMS45OSwwLjljMC45NSwwLjcxLDEuNzgsMS41OSwyLjg4LDIuNTljLTAuNzIsMC42Ni0xLjYzLDEuNS0yLjU1LDIuMzMgYy0wLjc4LDAuNy0xLjYxLDEuMzQtMi4zNCwyLjA3Yy0xLjU0LDEuNTUtMy4wNSwzLjEzLTQuNTQsNC43M2MtMS4yNCwxLjMyLTIuNiwyLjU2LTMuNiw0LjA1Yy0wLjYsMC45MS0xLjEsMS44NS0xLjg5LDIuNjMgYy0xLjIzLDEuMjEtMS4yMSw0LjAzLDAuMjQsNC42NmMxLjAzLDAuNDUsMi42MSwwLjUzLDMuNTcsMC4wM2MxLjQxLTAuNzIsMi43Ni0wLjUsNC4xNC0wLjU3YzEuOTMtMC4wOSwzLjg5LDAuMDIsNS44LTAuMjEgYzEuMTktMC4xNCwyLjMzLTAuNzUsMy40Ni0xLjJjMC40OS0wLjE5LDAuODktMC42LDEuMzgtMC43NmMwLjQ2LTAuMTYsMS4xMywwLjA2LDEuNDUtMC4yMWMyLjE5LTEuODIsNS4xOC0xLjc5LDcuNTMtMy40OCBjMS40MS0xLjAxLDMuMjUtMi4yMSw1LjM2LTIuMDZjMC4yOCwwLjAyLDAuNTgtMC4yOSwwLjg4LTAuNDRjMC40Mi0wLjIyLDAuODUtMC42MSwxLjI5LTAuNjJjMy40My0wLjA0LDYuODYsMCwxMC4zLDAuMDMgYzAuMzgsMCwwLjk5LTAuMDEsMS4xMSwwLjIxYzAuNjQsMS4xMywxLjY5LDAuODUsMi42MywwLjkxYzEuMSwwLjA2LDIuMjQtMC4xMywzLjI3LDAuMTRjMi45NiwwLjc5LDUuOSwxLjU5LDksMS41OCBjNi4wMi0wLjAzLDEyLjA1LDAuMjcsMTguMDEtMC45M2MwLjgyLTAuMTcsMS42OS0wLjA4LDIuNTItMC4yNGMxLjA0LTAuMiwyLjA1LTAuNTIsMy4xNC0wLjgxYzAuMTMsMC42LDAuMjEsMC43OSwwLjIxLDAuOTggYzAuMDEsOC4yMjYsMC4wMywxNi40NjIsMC4wMSwyNC42OTljLTAuMDAxLDAuMzY4LTAuMjE3LDAuODgyLTAuNTE1LDEuMDk5Yy0wLjY3NiwwLjQ5My0xLjU3MiwwLjcxLTIuMTc2LDEuMjczIGMtMS4zNywxLjI2LTIuNiwyLjY4LTMuOTIsNGMtMC43MywwLjczLTEuNjEsMS4zMi0yLjMxLDIuMDhjLTAuOTgsMS4wNi0wLjk2LDIuNDItMC45LDMuNzhjMC4wNywxLjk1LDAuNjQsMi42MiwyLjU5LDIuNjcgYzEuNzEyLDAuMDYxLDMuNDM0LDAuMDE5LDUuMTQ2LDAuMDNjMS4xMTIsMC4wMDcsMi4wMTQsMC45MDgsMi4wMjQsMi4wMmMwLjA2LDYuNzIsMC4wOCwxMy40NCwwLjE1LDIwLjE2IGMwLjAxOSwxLjIwNS0wLjUzNywxLjkzNi0xLjQzNywyLjUzM2MtMC4yMywwLjE1My0wLjQ1MSwwLjMxOC0wLjY0NCwwLjUxNmMtMS42MDUsMS42NDMtMy4xNjUsMy4zMDgtNC43ODksNC45MzEgYy0wLjYzLDAuNjQtMS41NywxLjA1LTIuMDEsMS43OWMtMS4yOSwyLjE0LTMuMjIsMy41NS01LjMsNC42OWMtMi41MSwxLjM4LTIuNzYsMS41OC0yLjYxLDQuMzNjMC4wOSwxLjY1LDEuODQsMy40OCwzLjQxLDMuMTcgYzEuODItMC4zNSwzLjc0LTAuODUsNS4yNi0xLjg1YzAuNzctMC41MSwxLjM4LTAuNjgsMi4xNi0wLjcxYzAuOTUtMC4wNCwxLjktMC4wMSwyLjg0LTAuMDFjMi41OSwwLjAxLDMuMDMsMC40NiwzLjAzLDMuMSBjLTAuMDEsMzEuMTgtMC4wMiw2Mi4zNi0wLjA0LDkzLjU1YzAsMi44OC0wLjEzLDUuNzgsMC4wMyw4LjY2YzAuMTYsMi44LDAuNjcsNS41OCwwLjkxLDguMzljMC4xNSwxLjgzLDAuMDgsMy42OCwwLjE1LDUuNTIgYzAuMDIsMC40MiwwLjE0LDAuODUsMC4yOSwxLjI1YzAuMjMsMC41OCwwLjY2LDEuMTIsMC43NSwxLjcyYzAuMTMsMC45My0wLjM0LDIuMjEsMC4xMywyLjc4YzEuODIsMi4xOC0wLjM1LDQuMDQtMC4yMSw2LjA0IGMwLjAxLDAuMi0wLjIxLDAuNDEtMC4zMSwwLjYyYy0wLjUzLDEuMDgtMS40MywyLjE0LTEuNDksMy4yNGMtMC4yMSw0LjI3LTAuMTksOC41Ni0wLjE5LDEyLjg0IGMtMC4wMSw1MS45LDAuMDEsMTAzLjgxLTAuMDUsMTU1LjcxYzAsNC4zNi0wLjU0LDguNzEtMC44NCwxMy4wNmMtMC4wMywwLjM0LTAuMTksMC42Ni0wLjMxLDAuOThjLTAuMjUsMC42OS0wLjczLDEuMzYtMC43NCwyLjA1IGMtMC4xMiw1LjY4LTAuMDcsMTEuMzYtMC4yMywxNy4wM2MtMC4xMSwzLjY1LTAuNzgsNy4zMS0wLjY4LDEwLjk1YzAuMTIsNC41OS0wLjI3LDkuMTYsMC41OCwxMy44MiBjMC44NSw0LjYzLDAuMTksOS41MywwLjIxLDE0LjMxYzAuMDEsMS0wLjI3LDIuMzIsMC4yNCwyLjkyYzEuMiwxLjM5LDAuNjksMi44OSwwLjc5LDQuMzVjMC4wMywwLjMzLTAuMjIsMC43LTAuMzcsMS4wMyBjLTAuMjUsMC41NS0wLjU1LDEuMDYtMC43NiwxLjYyYy0wLjE3LDAuNDQtMC4yLDAuOTMtMC4zNiwxLjM4Yy0wLjQ3LDEuMzYtMC45NywyLjcyLTEuNDUsNC4wOGMtMC4xMSwwLjMxLTAuMTEsMC43LTAuMywwLjk0IGMtMS41OCwyLTIuMzMsNC4zNi0yLjUyLDYuOGMtMC4yMywzLjA3LTAuMDYsNi4xNy0wLjA4LDkuMjZjLTAuMDIsMy42MiwwLjA1LDcuMjQsMC45MywxMC43OGMwLjA3LDAuMywwLjM5LDAuNTYsMC40MiwwLjg2IGMwLjEzLDEuMjksMC4yLDIuNTksMC4yOSwzLjg4Yy0wLjkxLDAuMDUtMS44NCwwLjIzLTIuNzIsMC4wOWMtMC42Ni0wLjEtMS4yNC0wLjcxLTEuOTEtMC45Yy0xLjgzLTAuNTMtMy44MSwxLjY5LTMuNzQsMy4xNyBjMC4xLDIuMTYsMC4zLDQuMzMsMS41OSw2LjE1YzEuMTQsMS42LDIuNDQsMy4wOSwzLjczLDQuNTdjMS4xOCwxLjM2LDIuNjQsMi40NSwyLjI1LDQuNjZjLTAuNDcsMi42LTAuNjYsNS4yNS0xLjAxLDguMjYgYy00LjUyLDAuMjUtOC45LDAuNjUtMTMuMywwLjcyYy04LjY1LDAuMTMtMTcuMzIsMC4wOC0yNS45OCwwLjEzYy0wLjU4LDAtMS4yNC0wLjAyLTEuNzQsMC4yMmMtMS4wMywwLjQ5LTEuOTIsMS4yOC0yLjk3LDEuNyBjLTEuODUsMC43NS0zLjc3LDEuMzEtNS42NSwxLjk2Yy0wLjIyLDAuMDctMC40MiwwLjIyLTAuNjMsMC4zMmMtMS4xNiwwLjU3LTIuMjgsMS4zOC0zLjUxLDEuNjRjLTEuMDMsMC4yMS0xLjc5LDAuNjEtMi40OSwxLjI4IGMtMC4yLDAuMTktMC40LDAuNS0wLjYyLDAuNTFjLTEuMTQsMC4wOC0yLjAzLDAuMzktMi44NSwxLjM0Yy0wLjYzLDAuNzMtMS43NSwxLjA0LTIuNjcsMS40OWMtMS43MiwwLjg0LTMuNDgsMS42MS01LjE4LDIuNDkgYy0xLjQ4LDAuNzctMy4wNCwxLjQ5LTQuMzMsMi41M2MtMS40OSwxLjIxLTIuNjgsMi44LTQuMDksNC4xNGMtMC44NCwwLjc5LTEuNzUsMS43NS0yLjc5LDIuMDJjLTEuNDYsMC4zOS0yLjk3LDAuMzQtNC41MiwwLjgzIGMtMi4wNSwwLjY0LTQuMzksMC4wOC02LjU3LDAuOTVjLTEuMzgsMC41NC0zLjI1LTAuNDgtNC40LDEuMjFjLTAuMDcsMC4xLTAuMzgsMC4wMy0wLjU4LDAuMDVjLTIuNSwwLjI1LTQuOTUtMC4wNC03LjUzLDAuNzMgYy0zLjE5LDAuOTctNi43NCwwLjc0LTEwLjE0LDEuMDhjLTAuNTksMC4wNi0xLjM2LDAuMjMtMS43LDAuNjNjLTAuODMsMS4wMi0wLjQyLDMuNzUsMC42OSw0LjRjMC45MSwwLjU0LDIsMC44MiwzLjA1LDEuMDcgYzAuNjYsMC4xNSwxLjQtMC4wNiwyLjA4LDAuMDVjMS42OCwwLjI5LDMuNjctMC45MSw1LjAxLDEuMDVjMC4wNywwLjEsMC4zOCwwLjA2LDAuNTgsMC4wN2M0Ljg3LDAuMiw5LjcyLDAuMDksMTQuNjEsMC44IGM0LjM4LDAuNjQsOC45NC0wLjAxLDEzLjQyLDAuMThjMy4wMywwLjEzLDUuODYtMC44OCw4LjgyLTEuMDljMC4xNC0wLjAxLDAuMzUtMC4wNiwwLjQtMC4xNWMwLjYxLTEuMywxLjg0LTAuODUsMi44NS0xLjA2IGMwLjU3LTAuMTEsMS4yLTAuMywxLjY1LTAuNjVjMC44My0wLjY0LDEuNDUtMS42MywyLjM1LTIuMWMyLjUtMS4zMiw0LjU2LTMuMzEsNy4xOS00LjQ1YzEtMC40MywxLjU4LTAuNDMsMi41MSwwLjA0IGMwLjYyLDAuMzEsMS42OCwwLjI1LDIuMzMtMC4wOGMxLjA2LTAuNTMsMS44OC0wLjY0LDIuNzQsMC4yMmMwLjc2LDAuNzYsMS41MywxLjUxLDIuMzQsMi4yM2MxLjE0LDEuMDIsMi40MSwxLjkxLDMuNDYsMy4wMiBjMS4wNCwxLjA4LDEuODUsMi4zOCwyLjc4LDMuNTZjMS4xMSwxLjQsNC40OSwxLjcyLDUuOTQsMC41OGMxLjI5LTEuMDEsMS41Ny0yLjUyLDEuODUtMy45N2MwLjI0LTEuMjQsMC4wMy0yLjQ5LDAuNjgtMy43OCBjMC45LTEuNzUsMS4zOS0yLjM5LDMuNDEtMi4zNmMyLjI5LDAuMDIsNC41OCwwLjEsNi44NywwLjExYzEuMDQsMC4wMSwxLjYyLDAuNTIsMS44NCwxLjVjMC4zMSwxLjMxLDAuNDUsMi42OCwwLjk2LDMuOSBjMC4zNiwwLjg1LDEuMTEsMS43MSwxLjkxLDIuMTZjMS4yMywwLjcsNC42OS0wLjY2LDUuMDktMi4wMWMwLjUzLTEuNzMsMS4xNS0zLjYsMS01LjM1Yy0wLjI0LTIuODIsMS40NC00LjU0LDIuODktNi40MyBjMC4zLTAuMzksMS40NC0wLjY4LDEuNzItMC40NWMxLjQ1LDEuMjMsMy40NSwyLjE3LDMuMTgsNC42MmMtMC4wNiwwLjY0LDAuMDksMS4zLDAuMDIsMS45NGMtMC4zMSwzLjAxLTAuNjgsNi4wMS0wLjk4LDkuMDIgYy0wLjA4LDAuODYtMC4wMSwxLjc0LTAuMDEsMi43N2MxLjA4LTAuMDcsMS44OC0wLjA1LDIuNjQtMC4xOGMxLjEyLTAuMiwyLjItMC42MiwzLjMyLTAuNzNjMS4zOC0wLjEzLDIuNzgtMC4wNSw0LjE4LTAuMDQgYzEuODYsMC4wMSwyLjEzLDAuMjQsMS44MiwyLjA3Yy0wLjE3LDEtMC40MiwyLjM5LTEuMTIsMi44Yy0xLjEsMC42NS0wLjg2LDEuNDQtMC44NywyLjI0Yy0wLjA1LDIuMS0wLjAzLDQuMTktMC4wMSw2LjI4IGMwLjAxLDAuNDQsMCwxLjE5LDAuMiwxLjI2YzEuNDEsMC41MywwLjgxLDEuNzEsMC45OCwyLjY0YzAuMTcsMC45LDAuMzQsMS44MSwwLjY0LDIuNjZjMC4zOSwxLjA4LTAuMjMsMy41MS0xLjE5LDMuNzUgYy0xLjY3LDAuNDMtMy4zOSwwLjY2LTUuMDksMC45OWMtMS44NCwwLjM2LTMuNjcsMC43Mi01LjUsMS4xMWMtMC4yMiwwLjA1LTAuNCwwLjI4LTAuNjEsMC4zOWMtMC40MywwLjIzLTAuODUsMC41Ni0xLjMsMC42MyBjLTAuNTk0LDAuMDgxLTEuMjA4LDAuMDUtMS44MiwwLjAzNmMtMS4zODYtMC4wMzMtMi42NDMtMC45MDUtMy4wNzUtMi4yMjJjLTAuNjEzLTEuODctMC44MjItMy43MDQtMC45MzYtNS42MTQgYy0wLjAzLTAuMzMtMC42LTAuNTktMC43OS0wLjk2Yy0wLjQzLTAuODUtMS4xMy0xLjc3LTEuMDctMi42MmMwLjA3LTAuOTgsMS4wNS0xLjQ0LDIuMTktMS4zOGMwLjgxLDAuMDQsMS42NC0wLjIxLDIuNDQtMC40MyBjMC41OS0wLjE2LDEuMTItMC41NSwxLjcyLTAuNjljMC41Mi0wLjEyLDEuMDktMC4wNiwxLjYzLTAuMDJjMS4yNSwwLjA4LDEuOC0wLjQzLDEuNzYtMS43MmMtMC4wNS0xLjg5LDAuMDEtMy43OC0wLjAxLTUuNjggYy0wLjAxLTEuNjYtMC44My0yLjU1LTIuNTYtMi41N2MtMy44NC0wLjA0LTcuNjctMC4wMi0xMS41LDAuMDJjLTEuMTYsMC4wMS0xLjc0LDAuNy0xLjg1LDEuODNjLTAuMDUsMC41NC0wLjA4LDEuMDktMC4yNCwxLjYgYy0wLjQ4LDEuNi0xLjM4LDMuMTctMS40NSw0Ljc4Yy0wLjA4LDEuODMtMC43NCwzLjAxLTIuMDgsNC4xYy0wLjgzLDAuNjctMS41NiwwLjc5LTIuMjMsMC4wNGMtMS4wOC0xLjIyLTIuMDktMi41MS0zLjA0LTMuODMgYy0xLjA2LTEuNDgtMS44OC0zLjE3LTMuMDgtNC41MWMtMC45MS0xLjAzLTEuOTItMi40MS0zLjctMS44NGMtMC41MSwwLjE3LTAuOTMsMC42OS0xLjQ0LDAuNzljLTIuNTgsMC40Ni00LjMzLDIuMzMtNi4zNSwzLjcgYy0yLjEzLDEuNDUtNC4yLDIuNTMtNi45MywyLjMzYy0zLjE3LTAuMjQtNi4zNy0wLjA3LTkuNTUtMC4wOWMtMC40LDAtMC45MywwLjEtMS4xNi0wLjFjLTEuNzUtMS41MS00LjMyLTIuMDctNS4yOS00LjUgYy0wLjA2LTAuMTMtMC4zMy0wLjI0LTAuNS0wLjI1Yy0yLjEtMC4xLTMuOTUtMS41Ni02LjE2LTEuMDdjLTAuMzEsMC4wNy0wLjY4LTAuMDgtMS4wMi0wLjE3Yy0wLjktMC4yNS0xLjgtMC43My0yLjcxLTAuNzUgYy00LjYyLTAuMDgtOS4yNS0wLjAzLTEzLjg4LTAuMDVjLTAuNDYsMC0wLjk0LTAuMTMtMS4zOC0wLjI5Yy0wLjYzLTAuMjQtMS4yMy0wLjgtMS44NS0wLjgxYy02Ljk3LTAuMDYtMTMuOTQtMC4wMS0yMC45MS0wLjA2IGMtMS40Ny0wLjAxLTIuNCwwLjktMy4xMSwxLjgxYy0xLjU4LDIuMDIsMC40Myw1LjgsMy4xOSw2LjI5YzEuNzEsMC4zMSwzLjQxLDAuNjQsNS4xMiwwLjk2YzAuMTksMC4wNCwwLjQ5LDAuMDUsMC41NSwwLjE3IGMwLjY1LDEuMTgsMS43OCwwLjgzLDIuNzcsMC45NGMyLjksMC4zMSw1Ljc4LDAuNjYsOC42NywxYzAuMTAzLDAuMDE5LDAuMjA2LDAuMDM4LDAuMzA4LDAuMDU3YzIuMTU0LDAuNTQ1LDQuMjk2LDEuMTkzLDYuNDgxLDEuNiBjMS4yNDEsMC4yMzIsMi41MDcsMC4xNSwzLjc2OSwwLjE4M2MwLjI4NCwwLjAwNywwLjU2OCwwLjExOSwwLjgyMSwwLjI0YzAuNjIsMC4yOCwxLjIyLDAuNiwxLjgzLDAuOSBjMS4zMywwLjY1LDIuNjgsMS4yNSwzLjk4LDEuOTZjMC40LDAuMjIsMC42LDAuNzYsMC45NiwxLjA2YzEuNDUsMS4yMywyLjkzLDIuNDEsNC4zNywzLjY0YzAuOTcsMC44MiwxLjkyLDEuNjcsMi44NCwyLjU0IGMxLjk4LDEuODYsMy45OCwzLjcxLDUuODksNS42NGMxLjcyLDEuNzIsMy40NiwzLjQ1LDQuOTcsNS4zNmMxLjU0LDEuOTMsMy4zNCwyLjUyLDUuNzksMi41MWMxOC40Ny0wLjA4LDM2Ljk0LTAuMDEsNTUuNCwwLjAyIGMyLjE3LDAsNC4xOSwwLjE0LDUuNy0yLjE0YzEuMDktMS42NCwyLjk5LTIuNzMsNC4zOS00LjJjMC43NC0wLjc3LDEuMS0xLjg3LDEuNzctMi43M2MwLjY4LTAuODgsMS40Ny0xLjY5LDIuMy0yLjQ1IGMxLjU2LTEuNDUsMi44MS0zLjEyLDMuOTEtNC45NGMwLjQ2LTAuNzYsMS41MS0xLjIyLDEuODYtMi4wMWMwLjc2LTEuNzQsMS41Ni0zLjM4LDMuMDgtNC42MWMwLjQyLTAuMzQsMC44OC0wLjk3LDAuODYtMS40NCBjLTAuMDgtMS40NywwLjk5LTIuMjgsMS41Ny0zLjM5YzAuNzUtMS40MiwxLjYxLTIuNzMsMS41Mi00LjU5Yy0wLjIxLTQuNDItMC4wOC04Ljg2LTAuMDUtMTMuMjljMC0wLjYxLDAuMTktMS4yMywwLjM1LTEuODMgYzAuMTQtMC40OSwwLjU1LTAuOTgsMC40OS0xLjQzYy0wLjM5LTMsMC45NS01Ljc3LDEuMS04LjdjMC4wMS0wLjIsMC4yMy0wLjM5LDAuMzQtMC41OWMwLjI2LTAuNDcsMC41Ni0wLjkyLDAuNzgtMS40MSBjMC41OS0xLjM3LDEuMS0yLjc3LDEuNzUtNC4xMWMwLjE5LTAuMzksMC44NS0wLjU0LDEuMS0wLjkzYzEuMjUtMS44NywyLjU2LTMuNzEsMy41OC01LjdjMC43My0xLjQxLDEuOC0yLjgzLDEuMzctNC42IGMtMC4xLTAuNDEtMC40NC0xLjAzLTAuNzMtMS4wN2MtMi4zLTAuMjgtNC40My0xLjQ2LTYuODctMS4wOWMtMS40MSwwLjIxLTIuODgsMC4wMy00LjMyLDAuMDNjLTIuMjIsMC0yLjU2LTAuNTEtMi43Ni0yLjc0IGMtMC4yLTIuMTksMS4wMy00LjY2LTEuMS02LjUzYy0wLjA4LTAuMDctMC4wMi0wLjI5LTAuMDQtMC40NGMtMC4yNi0yLjY1LDAuMTctNS4yNy0wLjc1LTcuOTljLTAuODItMi40NCwwLjAyLTUuMjMtMC45My03LjkyIGMtMC44Ny0yLjUxLDAuMTUtNS4zMS0xLjA2LTguMTFjLTEuMTQtMi42NC0wLjc2LTUuOTItMS4xNi04LjkxYy0wLjMxLTIuMzEsMC4zOC00Ljc3LTAuOTYtNi45NGMtMC4zMS0wLjUtMC45MS0wLjkzLTEtMS40NiBjLTAuNDEtMi4yNC0wLjY4LTQuNS0xLjAxLTYuNzZjLTAuMzItMi4yLTAuNjUtNC40LTAuOTktNi42Yy0wLjAzLTAuMTktMC4wOS0wLjQ3LTAuMjMtMC41M2MtMS4yMS0wLjU1LTAuODYtMS42MS0wLjg4LTIuNTUgYy0wLjI1LTEyLjk1LDAuMjYtMjUuODktMC43Ni0zOC44NGMtMC42NDUtOC4xNTktMC4yMDctMTYuNDA3LTAuMjEtMjQuNjA2YzAtMC4zMjYsMC4wMy0wLjY1NSwwLjEzMi0wLjk2NCBjMC40OTgtMS41MDUsMS42MjgtMi45MDksMS44MDgtNC40MzljMC4zMi0yLjc0LDAuNTctNS41MiwwLjgyLTguMjZjMC41MjEtNS43NDQsMC4xNjgtMTEuNTY5LDAuMTUtMTcuMzYzIGMtMC4wMDEtMC40MTEtMC4wNTQtMC44MjMtMC4yMDEtMS4yMDdjLTAuNTE5LTEuMzU4LTEuMzU2LTIuNjQzLTEuNjE5LTQuMDM5Yy0wLjUtMi42Ny0wLjctNS4zOS0xLjAyLTguMDkgYy0wLjA0LTAuMzktMC4wOC0wLjc5LTAuMDctMS4xOWMwLjA3LTMuMTUtMC4zLTYuMzIsMC42OS05LjQyYzAuNDEtMS4yOS0wLjE3LTIuODcsMS4yMi0zLjg4YzAuMS0wLjA3LDAuMDYtMC4zNywwLjA2LTAuNTcgYzAuMDQtOC4zMiwwLjA4LTE2LjY0LDAuMDgtMjQuOTZjMC0wLjQzLTAuMjgtMC44OC0wLjQ1LTEuMzFjLTAuMTktMC40Ni0wLjU2LTAuOS0wLjU4LTEuMzZjLTAuNDgtMTEuMDUsMC41My0yMi4xLTAuNzUtMzMuMTcgYy0wLjc3LTYuNjgtMC4xNS0xMy41Mi0wLjE5LTIwLjI5Yy0wLjAyLTQuMTMtMC4xNS04LjI2LTAuMTUtMTIuMzljLTAuMDEtNDQuMDYzLTAuMDEtODguMTE1LDAtMTMyLjE3OCBjMC0wLjg4MywwLjAxMS0xLjc3LDAuMTE3LTIuNjQ3YzAuMzIzLTIuNjg3LTAuMzk0LTUuNDE3LDAuODEzLTguMDk1YzAuNTQtMS4yLDAuMDktMi44NSwwLjE0LTQuMjljMC4wMS0wLjQyLDAuMTItMC44NiwwLjI4LTEuMjUgYzAuMjYtMC42MiwwLjYzLTEuMiwwLjg4LTEuODJjMC4xNC0wLjM2LDAuMS0wLjc4LDAuMTktMS4xNmMwLjQ4LTIuMDIsMS00LjAzLDEuNDQtNi4wNWMwLjI1LTEuMTctMC40Ny0yLjYzLDEuMDktMy4zOSBjMC4xMS0wLjA1LDAuMS0wLjM2LDAuMTEtMC41NmMwLjI4LTQuNTEsMC4zMS05LDAuODgtMTMuNTNjMC43LTUuNDksMC40NC0xMS4xNSwwLjEzLTE2LjcxYy0wLjMxLTUuNTUsMS4xOC0xMC45NSwwLjk0LTE2LjQ2IGMtMC4wMi0wLjYyLDAtMS4yNSwwLTEuOTJjMC45OC0wLjEsMS43NC0wLjEsMi40NS0wLjI3YzAuNy0wLjE3LDEuMzUtMC41MywyLjAzLTAuNzVjMS45Mi0wLjYyLDIuNDUtMS4zMywyLjQyLTMuMzkgYzAtMC40My0wLjA3LTAuODYtMC4xMi0xLjQ4aC00Ljk3Yy0xLjk4LTAuMDEtMi42NC0wLjctMi42NS0yLjczYy0wLjAxLTAuNzUsMC4wNS0xLjUtMC4wMS0yLjI1Yy0wLjUzLTYuODYsMS4zLTEzLjk3LTIuMDYtMjAuNTUgYzAuNDktMi4yNC0xLjM1LTQuNzksMC45Ni02LjhjMS4yMy0xLjA4LDIuMjctMi40MiwzLjYyLTMuMzNjMS4yMy0wLjgzLDIuNTItMS40NywzLjMtMi44NGMwLjgtMS40MiwyLjg5LTIuMzEsNC4zMS0xLjk1IGMxLjA1LDAuMjgsMi4xMiwwLjUzLDMuMTMsMC45MmMyLjI2LDAuODYsNC40NiwxLjg5LDYuNzUsMi42NWMwLjk0LDAuMzIsMi4yMywwLjQ3LDMuMDUsMC4wNmMxLjc3LTAuODksMi44OS0yLjc3LDMuMzQtNC41MSBjMC43Ni0yLjkyLDAtNS45MS0xLjEyLTguNjljLTAuNS0xLjI0LTAuNC0xLjkyLDAuNzYtMi40M2MxLjcxLTAuNzUsMy4zNy0xLjU5LDUuMDctMi4zN2MyLjA3LTAuOTUsMy45My0yLjQzLDYuMzQtMi41NiBjMC4yOS0wLjAyLDAuNTUtMC4zMywwLjg0LTAuNWMwLjM3LTAuMjMsMC43OC0wLjY1LDEuMTQtMC42M2MxLjU5LDAuMTMsMy4wNi0wLjIzLDQuNzQsMC45MmMxLjYxLDEuMTEsNC4xMywwLjk5LDYuMjcsMS4xOSBjMS45MywwLjE3LDIuODItMC44MiwzLTIuNzhjMC4wNC0wLjQzLDAuMjYtMC44OCwwLjQ3LTEuMjhjMC4zOS0wLjc1LDEuMTYtMS40NiwxLjItMi4yMmMwLjA3LTEuNDIsMC43NS0zLTEuNi0zLjg1IGMtMS43Mi0wLjYxLTIuOTMtMi41Mi00LjUyLTMuNjJjLTEuMzgtMC45Ni0yLjk4LTEuNi00LjczLTIuNTFjMC4yNC0wLjYsMC40Ni0xLjI0LDAuNzUtMS44NWMwLjgyLTEuNzIsMS42Ny0zLjQyLDIuNDktNS4xMyBjMC4zNC0wLjczLDAuNS0xLjYsMS4wMS0yLjE3YzEuNDItMS42MywxLjk4LTMuNjQsMi43OS01LjU1YzAuMzYtMC44NywwLjQ1LTEuOTksMS4wNi0yLjU5YzEuMDktMS4wNiwxLjUyLTIuMzQsMS45OC0zLjY5IGMwLjI5LTAuODUsMC42Ni0xLjY4LDEuMDktMi40NmMwLjUxLTAuOTMsMS4zMy0xLjczLDEuNjctMi43YzAuODEtMi4zOSwyLjE0LTMuMTgsNC40NS0yLjM4YzAuMzEsMC4xLDAuNywwLjExLDEuMDMsMC4wNCBjMS4xNy0wLjIyLDIuMzYtMC40MSwzLjUtMC43NmMxLjI0LTAuMzgsMi40NC0wLjksMy42Mi0xLjQzYzAuMjEtMC4wOCwwLjM3LTAuNSwwLjM3LTAuNzcgQzIxNy4wMjYsMTI2LjI4LDIxNy4wMTcsMTI0LjY2LDIxNy4wMTcsMTIzLjUyeiBNMTQzLjUwNywxODYuMWMtMC44MiwwLjY1LTEuNzIsMC45NS0yLjcsMS4wNmMtOS4xNSwzLjQtMTkuMDQsNS4yNi0yOS4zNyw1LjI2IGMtNDYuNTcsMC04NC4zMi0zNy43NS04NC4zMi04NC4zMmMwLTQ2LjU2LDM3Ljc1LTg0LjMxLDg0LjMyLTg0LjMxYzQ2LjU2LDAsODQuMzEsMzcuNzUsODQuMzEsODQuMzEgQzE5NS43NDcsMTQzLjMxLDE3NC4xNjcsMTczLjQ4LDE0My41MDcsMTg2LjF6XCIsXG4gICAgICAgICAgICBcIk0yMTQuMzI3LDEzMy42NWMtMS4wNy0wLjc3LTIuNTgtMS4yNC0zLjIxLTIuMjdjLTIuMjUtMy42LTYuMzEtNy42NS01Ljg4LTExLjA1IGMxLjUyLTEyLjA0LTAuMzMtMjMuNTItMi44LTM1LjFjLTEuMTctNS40OS0yLjE4LTEwLjk5LDQuNzItMTQuMDZjMS4wOC0wLjQ4LDEuODgtMy4xMywxLjYzLTQuNTdjLTAuMTktMS4wNy0yLjE2LTIuMTktMy41NS0yLjY0IGMtNi43LTIuMTQtMTIuOTgtNC44OC0xNy40LTEwLjY5Yy04Ljg2LTExLjY1LTE5LjI0LTIxLjY5LTMyLjY0LTI3Ljg1Yy02LjY0LTMuMDUtMTEuODYtNi4yNC0xMS4wOS0xNC41NCBjMC4wNy0wLjc4LTAuMzEtMS42NC0wLjY0LTIuNGMtMS4yNS0yLjg0LTIuNTYtNS42Ni0zLjg0LTguNDhjLTIuMDksMi42LTQuMTUsNS4yMy02LjI3LDcuODFjLTEuNDEsMS43My0yLjY4LDQuNS00LjQxLDQuODUgYy01LjMyLDEuMS0xMC44NSwxLjc2LTE2LjI4LDEuNjdjLTEwLjYzLTAuMTgtMjAuOTksMS4xNC0zMC45Nyw0LjY3Yy03Ljg1LDIuNzgtMTUuMTQsMy43Ny0yMi43Mi0xLjMxIGMtMy40Mi0yLjI5LTguMDktMi42OS0xMy40OC00LjM1YzEuMSwzLjQxLDEuNjgsNS4yNSwyLjMsNy4wOGMyLjY2LDcuODcsMi45LDE0Ljk0LTQuMTEsMjEuMjhjLTkuNzYsOC44My0xNi43OCwxOS43NC0yMS43NCwzMS45NiBjLTMuNDMsOC40My03LjA5LDE2Ljc3LTEwLjQsMjUuMjVjLTAuNjksMS43Ny0wLjc2LDQuMDctMC4zMSw1LjkzYzEuNjEsNi41OCwzLjQsMTMuMTMsNS40MywxOS41OWMzLjA5LDkuNzcsNS42LDE5Ljg2LDkuOTMsMjkuMDggYzMuNjgsNy44Myw5LjU4LDE0LjYzLDE0LjY4LDIyLjE0Yy0wLjc5LDAuOTYtMi4xLDIuMS0yLjgsMy41M2MtMS4zNiwyLjgyLTIuMzcsNS44MS0zLjUzLDguNzJjMy4xMiwwLjExLDYuNTUsMS4xMSw5LjI5LDAuMTUgYzguMDktMi44NiwxNC40LTAuMzUsMjAuNTQsNC43M2MyLjM5LDEuOTgsMi4wNSwzLjM2LDAuNDYsNS4zMmMtNS44Myw3LjE1LTEwLjcxLDE1LjE1LTE4Ljk5LDIwLjA2IGMtMC45OCwwLjU3LTAuODIsMy4wNS0xLjE4LDQuNjVjMS40LDAuMjQsMy4wOCwxLjEyLDQuMTYsMC42M2MxMC40NS00LjY3LDIwLjc2LTkuNjcsMzEuMi0xNC4zOGM2LjMxLTIuODQsMTIuNDMtNS44OCwxOS44NC01Ljg1IGMxMC40MiwwLjA1LDIwLjg0LTEuMDcsMzEuMjYtMS43YzEuNzYtMC4xMSwzLjUxLTAuMjgsNS40Mi0wLjQzYzAuMTYsMS41NCwwLjM2LDIuNTEsMC4zNiwzLjQ5IGMtMC4wMiw1OS41MSwwLjA5LDExOS4wMi0wLjI4LDE3OC41MmMtMC4wNCw2Ljc2LTIuMDEsMTMuNjYtNi42MywxOS40NmMtNS43OCw3LjI2LTExLjEzLDE0Ljg4LTE2LjQ2LDIyLjQ5IGMtMC43MiwxLjAzLTAuMiwyLjkzLTAuMjYsNC40M2MxLjMtMC4wMiwyLjY2LDAuMjQsMy44Ny0wLjA5YzUuNzYtMS41NiwxMS40Ny0zLjI4LDE4LjE0LTUuMjJjMC42Miw2LjI1LDEuNDksMTAuOTgsMS41LDE1LjczIGMwLjEzLDQ3LDAuMjEsOTQuMDEsMC4wOSwxNDEuMDFjLTAuMDIsOS40NS0wLjgxLDE4LjktMS40MywyOC4zNGMtMC41MSw3LjYyLTEuODcsMTUuMjItMS44MSwyMi44MiBjMC4wOSwxMS4yNywxLjM1LDIyLjUyLDEuNTksMzMuOGMwLjExLDQuODctMS4wNyw5Ljc3LTEuNjksMTQuNjVjLTAuOTUsNy41LTIuMzYsMTQuOTgtMi43MywyMi41MWMtMC4zLDYuMSwxLjU1LDEyLjM4LDAuNzgsMTguMzcgYy0wLjk3LDcuNDktNS4wMSwxNC41My0xMS40NiwxOC4zMmMtNS4yOSwzLjEzLTEyLjA0LDQuNTItMTguMjksNS4wOWMtNy4yMywwLjY2LTE0LjYxLTAuNDctMjEuOTItMC43NSBjLTcuNTYtMC4yOS0xMy4zNi01LjAxLTE1LjE4LTEyLjMxYy0wLjI0LTAuOTctMC45Ny0yLjA0LTEuNzktMi42Yy0zLjU0LTIuNDQtNy4xOS00LjctMTEuMDItNy4xNyBjLTYuODMsOC44OC03LjgyLDExLjMzLTcuNjUsMjEuMTNjMC4yNywxNS43OCwxLjI4LDMxLjU4LDAuODcsNDcuMzRjLTAuMTksNy4xMi0wLjM2LDEzLjg0LDIuOTEsMjAuMjcgYzAuNTcsMS4xMywxLjQsMi44NiwyLjI5LDIuOTdjNi40LDAuODIsMTIuNjksMy41NSwxOS4xOC0xLjE2YzMuMzUtMi40Miw4LjIzLTMuMjEsMTIuNTQtMy43MmM3LjQxLTAuODgsMTQuOTItMC44NCwyMi4zNy0xLjQzIGM0LjA4LTAuMzIsNy40OS0xLjksNy42NC02Ljc4YzAuMTYtNC45NSwyLjQ5LTcuNDYsNy40MS03LjI1YzEuMjYsMy4yMiwyLjM1LDYuMzUsMy43Myw5LjM0YzAuNDgsMS4wNSwxLjU2LDIuMzQsMi41NSwyLjU0IGMzLjI0LDAuNjIsNi41NywwLjc0LDkuODYsMS4xNmMzLjM4LDAuNDIsNS4wOS0wLjkyLDYuMDEtNC4zYzEuNzgtNi41NiwzLjkyLTEzLjAyLDYuMDgtMTkuNDdjMS45Mi01LjcxLDIuMzEtMTEuMjgtMC4yNi0xNi45MyBjLTAuNjktMS41MS0wLjYtMy4zNy0xLjAyLTUuOTljMi40NiwwLjY0LDMuOTcsMS4xOCw1LjUyLDEuNDFjMi4zLDAuMzMsNC42MiwwLjQ0LDYuOTMsMC42NWMtMC4wNy0yLjcsMC41LTUuNjQtMC4zNy04LjA2IGMtMS4zOS0zLjg4LTQuMDUtNy4zLTUuNi0xMS4xNGMtMi4zNC01Ljc5LTUuODYtMTEuNzUtNS45Ni0xNy42OWMtMC41OC0zNS42Ni0wLjM0LTcxLjM0LTAuMzMtMTA3LjAxYzAtMS44MSwwLjEyLTMuNjgsMC41Ny01LjQyIGMzLjM4LTEzLjEsMy41Ni0yNi41LDEuNjgtMzkuNjNjLTEuNTMtMTAuNzUtMS41NC0yMC45NywxLjE1LTMxLjQ0YzEuMDktNC4yMywxLjI5LTguODQsMS4wMi0xMy4yMyBjLTEuMjEtMTkuODgtMy43LTM5LjczLTMuOTQtNTkuNjFjLTAuNjItNTAuOTktMC4yOS0xMDItMC4zNC0xNTMuMDFjMC0xLjY2LTAuMDctMy4zNSwwLjE4LTQuOThjMS45MS0xMi40Myw0Ljk2LTI0Ljc4LDUuNjItMzcuMjYgYzEuMjgtMjQuMDEsMy4zNi00OC4xNS0xLjg3LTcyLjA2Yy0wLjI3LTEuMjUsMC43My0zLjM0LDEuOC00LjIzYzkuNzMtOC4wNSw5Ljc4LTgsMjAuMzEtMS4xMWMwLjcsMC40NiwxLjM5LDEuMDUsMi4xNywxLjIzIGMyLjM2LDAuNTUsNi41MSwxLjg1LDYuODUsMS4yMWMxLjM1LTIuNTQsMi42LTUuOTksMS45Mi04LjZjLTIuMzgtOS4yMi0yLjQzLTE3Ljc4LDMuODItMjUuNTljMi44OC0zLjYsNS4wNy04LjExLDguNjYtMTAuNzEgYzQuNzUtMy40NSwxMC42NS01LjI4LDE1Ljg4LTguMTNjMi40MS0xLjMsNS4zMi0yLjkyLDYuNC01LjE3QzIyMC43MDcsMTM2LjM2LDIxNi42MzcsMTM1LjMxLDIxNC4zMjcsMTMzLjY1eiBNMTExLjQzNywxOTIuNDIgYy00Ni41NywwLTg0LjMyLTM3Ljc1LTg0LjMyLTg0LjMyYzAtNDYuNTYsMzcuNzUtODQuMzEsODQuMzItODQuMzFjNDYuNTYsMCw4NC4zMSwzNy43NSw4NC4zMSw4NC4zMSBDMTk1Ljc0NywxNTQuNjcsMTU3Ljk5NywxOTIuNDIsMTExLjQzNywxOTIuNDJ6XCIsXG4gICAgICAgICAgICBcIk0yMTYuMDg2LDEwOS42OWMtMC4wOC0wLjQ4LDAuMDItMS0wLjAyLTEuNWMtMC4wNy0wLjk1LDAuMTYtMi4yMi0wLjM2LTIuNzYgYy0wLjczLTAuNzYtMi4wMy0wLjk3LTMuMDctMS40NmMtMC42My0wLjMtMS4yNC0wLjY3LTEuODMtMS4wNWMtMC41My0wLjMzLTEuMDgtMC42NS0xLjUzLTEuMDdjLTAuOC0wLjc0LTEuOTItMC44MS0yLjU3LTIuMDkgYy0xLjEzLTIuMjItMC40OS00LjctMS43NS02Ljk0Yy0xLTEuOCwwLjA3LTQuMzItMC45MS02LjUxYy0wLjMtMC42NywwLjg5LTIsMS4zNy0zLjA0YzAuNjUtMS4zOSwyLjMxLTIuMDMsMi41Ny0zLjc1IGMwLjEyLTAuODEsMC42NC0xLjYxLDEuMTUtMi4yOGMxLjc4LTIuMzgsMS4xNi01LjMzLTEuMzEtNi4wMmMtMS40OS0wLjQyLTIuNTUtMS4xNi0zLjcyLTIuMDZjLTEuMjEtMC45Mi0yLjc3LTEuNDktNC4yNS0xLjkyIGMtMS41NC0wLjQ0LTIuMTUtMS42MS0yLjg0LTIuNzljLTAuNTktMS4wMi0xLjA5LTIuMTEtMS43Ni0zLjA4Yy0wLjcxLTEuMDItMS41OS0xLjkzLTIuNDctMi45OGMwLjM1LTAuMTMsMC43NC0wLjE2LDAuODYtMC4zNSBjMS4yNy0yLjAyLDMuMjUtMiw1LjI4LTEuOTVjMS4xNSwwLjAyLDIuNCwwLjIxLDMuNDQtMC4xNmMxLjI4LTAuNDUsMi43MS0xLjE2LDMuNDktMi4xOWMxLjI0LTEuNjUtMC40Mi00LjQ4LTIuNDYtNC43NCBjLTEuOTgtMC4yNS0zLjk0LTAuNTgtNS45MS0wLjg5Yy0wLjE4LTAuMDMtMC4zNC0wLjE1LTAuNTEtMC4yMmMtMC43Ny0wLjMzLTEuNTItMC43Mi0yLjMyLTAuOTVjLTAuNTctMC4xNi0xLjIyLDAuMDEtMS43OS0wLjEzIGMtMi4xNC0wLjUzLTQuMjQtMS40My02LjQxLTEuNjFjLTEuNjktMC4xNC0yLjg3LTAuNjYtNC4wMi0xLjhjLTEuMjgtMS4yNi0yLjgyLTIuMjYtNC4xLTMuNTJjLTAuMy0wLjI5LTAuMjMtMS4yNCwwLTEuNzMgYzAuNDQtMC45MSwxLjU0LTAuOTcsMi4zMi0xLjQ0YzEuNzQtMS4wNSwzLjI5LTIuNDUsNC44OS0zLjc0YzAuNTItMC40MiwxLjMxLTAuOSwxLjM4LTEuNDJjMC4xOS0xLjQ2LDAuMDYtMi45NiwwLjA2LTQuNSBjLTIuNTQtMC4zMy00Ljk1LTAuNjctNy4zOC0wLjk0Yy0wLjg5LTAuMS0xLjgxLTAuMDEtMi43MS0wLjAzYy0wLjM0LTAuMDEtMC42OC0wLjA3LTEuMDEtMC4xNmMtMC44OS0wLjIzLTEuNzYtMC42OS0yLjY0LTAuNyBjLTQuMDItMC4wOC04LjA0LTAuMDMtMTIuMDctMC4wNWMtMC40MiwwLTEuMTEsMC0xLjIzLTAuMjNjLTEuMTItMi4wOS0zLjAyLTEuOTYtNC45Mi0xLjg4Yy0xLjE0LDAuMDQtMS44LTAuNDYtMi4wNi0xLjYyIGMtMC4yNy0xLjIyLTAuMzQtMi43Ni0xLjEyLTMuNTRjLTEuMTctMS4xNi0wLjY4LTIuNDUtMS4wNS0zLjY0Yy0wLjMzLTEuMDgtMC44MS0yLjc2LTEuNTItMi45M2MtMi4wMS0wLjUtNC4yMS0wLjg3LTYuMjMsMC4zMSBjLTAuOTMsMC41NC0xLjg4LDEuMDUtMi44NywxLjQ0Yy0xLjIxLDAuNDgtMi42MSwwLjYxLTMuNywxLjI3Yy0xLjc3LDEuMDgtMy43OSwwLjg5LTUuMywwLjM0Yy0xLjM4LTAuNS0yLjY2LTAuNTYtNC0wLjY4IGMtMC43NS0wLjA2LTEuNS0wLjAyLTIuMjMtMC4xNmMtMC45NC0wLjE4LTEuODctMC43Ny0yLjc2LTAuNjljLTEuOSwwLjE4LTMuMDMtMC45MS0zLjk3LTIuMTRjLTEuMjktMS43Mi0yLjE0LTMuNzktMy41My01LjQxIGMtMS4zMS0xLjU0LTEuOC0zLjcxLTMuNzQtNC43M2MtMC40OS0wLjI2LTAuOTYtMC42Ny0xLjQ4LTAuNzNjLTAuOTQtMC4xMi0xLjkyLTAuMTQtMi44NSwwYy0wLjU5LDAuMDgtMS4yNiwwLjQxLTEuNjYsMC44NSBjLTAuNTUsMC41OS0wLjc1LDEuNDktMS4zLDIuMDdjLTEuNDQsMS41NS0yLjk5LDMtNC40OCw0LjVjLTAuMTMsMC4xMi0wLjEyLDAuMzgtMC4yMiwwLjU1Yy0wLjQ2LDAuNzUtMC45LDEuNTItMS40MiwyLjIyIGMtMC41LDAuNjctMS4xMiwxLjI0LTEuNjIsMS45MWMtMC40OCwwLjYyLTAuNzksMS4zOC0xLjMxLDEuOTZjLTEuMzksMS41NC0zLjU0LDAuNTQtNS4zNSwxLjczYy0yLjEzLDEuMzktNS4xNCwxLjYtNy44MSwxLjkyIGMtMi40MywwLjI5LTQuOTcsMC4zMi03LjM3LTAuMDZjLTEuNDQtMC4yMy0yLjg0LTEuMzItNC4wNC0yLjNjLTEuNDQtMS4xOC0yLjU3LTIuNzEtNC43Ny0yLjQ3Yy0wLjYxLDAuMDYtMS4yNy0wLjQzLTIuMjMtMC43OCBjLTAuMjcsMC45MS0wLjc5LDEuOTEtMC44MywyLjkyYy0wLjEzLDMuMjItMC4xLDYuNDQtMC4xLDkuNjZjMCwwLjcyLTAuMTMsMS4xNi0wLjg0LDEuNjZjLTEuNzksMS4yNC0zLjM5LDIuNzQtNS4xMiw0LjA4IGMtMC4zMywwLjI2LTAuOSwwLjI2LTEuMzYsMC4zM2MtMC42OSwwLjEtMS43NS0wLjA5LTIuMDIsMC4yOGMtMC44NCwxLjIxLTEuOTcsMC44NC0zLjA1LDAuOTZjLTAuNTMsMC4wNi0xLjA1LDAuMjctMS41NiwwLjQzIGMtMS40MSwwLjQ0LTIuNzksMC45OC00LjIzLDEuMzJjLTEuNCwwLjMzLTMuMTMtMC42LTQuMTYsMS4xNmMtMC4wNiwwLjEtMC4zOCwwLjA3LTAuNTgsMC4wOGMtMS4xNSwwLjA3LTIuMywwLjE3LTMuNDUsMC4yIGMtMi4xOCwwLjA3LTIuOTQsMC45MS0yLjQ3LDIuOTdjMC4xMiwwLjU1LDAuNTUsMS4wOSwwLjk3LDEuNTFjMC44NSwwLjgyLDEuODMsMS41MSwyLjY3LDIuMzVjMS4wOSwxLjA5LDIuMSwyLjI3LDIuOTksMy4yNCBjLTAuOTksMS41LTEuOCwyLjg0LTIuNzMsNC4wOWMtMC42MiwwLjgzLTEuNTEsMS40Ny0yLjA5LDIuMzJjLTEuMTEsMS42LTIuMDksMy4zLTMuMTIsNC45NmMtMC4zMSwwLjUtMC43MywwLjk2LTAuOTMsMS41MSBjLTAuNSwxLjMzLTIuMzgsMi43My0zLjgsMi43NmMtMS4xNSwwLjAzLTIuNDktMC4yNC0zLjQsMC4yNmMtMS4zLDAuNzEtMi41NSwwLjY1LTMuODYsMC42NmMtMi4xNCwwLjAxLTQuMDMsMC41Ny01LjM2LDIuMzUgYy0wLjMsMC40MS0wLjMyLDEuMDItMC41NiwxLjQ4Yy0wLjcsMS4zMS0wLjQ2LDMuNTQsMC42Nyw0LjQ0YzAuODgsMC43MSwxLjk3LDEuMTcsMi44NiwxLjg3YzAuNzUsMC41OCwxLjI0LDEuNiwyLjA2LDEuOTcgYzEuMjYsMC41NywxLjg1LDEuMzgsMS41NCwyLjY0Yy0wLjQxLDEuNjgsMC40LDMuNDQtMC43Nyw1LjE0Yy0wLjY3LDEsMC4zNCwyLjg1LTEuMjYsMy43NmMtMC4wOCwwLjA0LTAuMDUsMC4yOC0wLjA2LDAuNDMgYy0wLjA3LDEuMi0wLjMyLDIuMy0wLjcyLDMuNDljLTAuNjksMi4wOC0xLjA2LDQuMjQtMi40NCw2LjA2Yy0xLjA2LDEuNDEtMS45OSwyLjk3LTIuOTksNC4zN2MtMS40NywyLjA1LTMuOTEsMy4zOC01LjkzLDUuMDQgYy0wLjc3LDAuNjMtMS40NCwxLjQtMi4yNiwxLjk0Yy0yLjI0LDEuNDctMi40LDQuNDQtMC41Miw2LjMxYzEuMDIsMS4wMiwyLjExLDAuNjMsMy4xOSwwLjgxYzAuNTIsMC4wOCwxLjA4LDAuMDgsMS41NiwwLjI4IGMxLjM3LDAuNTgsMi43MSwxLjIxLDQuMDUsMS44N2MwLjY2LDAuMzMsMS41NCwwLjYzLDEuODYsMS4yYzAuNTQsMC45OSwwLjczLDIuMTgsMS4wNiwzLjI5YzAuMTEsMC4zOCwwLjE1LDAuOCwwLjMzLDEuMTQgYzAuNTQsMC45NiwxLjI2LDEuODQsMS42NywyLjg1YzEuMSwyLjY5LDAuODQsNS43MywyLjE4LDguNDFjMC42NiwxLjMxLDAuNzYsMi45MSwxLjE1LDQuMzdjMC4zLDEuMTMsMC4zNCwyLjUzLDEuMDUsMy4zIGMwLjksMC45NywwLjc3LDEuOTUsMC45MSwzYzAuMDksMC42MywwLjM3LDEuMjQsMC42LDEuOTVjLTAuNTUsMC40NS0xLjM4LDAuODctMS44MiwxLjU1Yy0wLjk2LDEuNDctMS41MiwzLjE4LTIuOTgsNC4zNCBjLTEuMzMsMS4wNi0wLjgsMi42NC0wLjgyLDQuMDNjLTAuMDIsMS4yNywxLjYxLDMuMTgsMi44NCwzLjMyYzMuMDIsMC4zNiw2LjA0LDAuNjQsOS4wNiwwLjk2YzAuMzMsMC4wNCwwLjgxLDAuMDQsMC45NSwwLjI0IGMxLDEuNDUsMi45OCwyLjQ0LDIuMTcsNC43NWMtMC4xMSwwLjMxLDAuMzksMC43OCwwLjM5LDEuMThjMC4wMiwxLjMyLDAuMTEsMi42OC0wLjE3LDMuOTVjLTAuMjIsMS4wMS0xLjEsMS44Ni0xLjQxLDIuODcgYy0wLjU0LDEuNzEsMC40MSwzLjAyLDEuNTUsNC4xNWMxLjI4LDEuMjcsMS45NCwxLjI0LDMuNjYsMC4yNmMwLjk2LTAuNTUsMS45OS0xLjEyLDMuMDYtMS4zMmMxLjk0LTAuMzUsMy4xLDEuNCw0LjY0LDIuMTMgYzEuMTcsMC41NSwyLjE3LDEuNDMsMy4zNCwxLjk4YzEuNTEsMC43MiwzLjEsMS4xOSw0LjA1LDIuOGMwLjMzLDAuNTcsMS4yNiwwLjc4LDEuOSwxLjE5YzAuNiwwLjM4LDEuNCwwLjcsMS42OSwxLjI2IGMwLjUxLDEuMDMsMC42OSwyLjIzLDEuMDUsMy4zNGMwLjE0LDAuNCwwLjM1LDAuODMsMC42NSwxLjExYzAuNjksMC42NiwwLjgyLDMuNCwwLjEzLDQuMDJjLTEuMDMsMC45Mi0xLDEuNTksMC4wMSwyLjQ5IGMwLjgyLDAuNzMsMS40NSwxLjc5LDIuMzksMi4yM2MwLjc1LDAuMzYsMS44NSwwLjA1LDIuNzgtMC4wN2MwLjMxLTAuMDQsMC41OC0wLjUzLDAuOS0wLjU1YzMuMS0wLjI0LDUuODktMS4zNCw4LjU4LTIuODQgYzAuMy0wLjE2LDAuOTUtMC4xNywxLjE0LDAuMDNjMC43NiwwLjgyLDIuMDIsMS4yOCwxLjY5LDIuODhjLTAuMzMsMS42NywwLjIsMy4zOC0xLjE3LDQuOTljLTEuMjMsMS40NS0yLjAxLDMuMzktMi42NCw1LjIzIGMtMC4zOCwxLjEyLTAuNTQsMi42Ny0wLjA1LDMuNjdjMS4yLDIuNDUsNC43LDIuNjEsNi42NSwwLjU3YzAuODEtMC44NiwxLjY5LTEuNjcsMi42LTIuNDJjMC42Ny0wLjU1LDEuNDctMC45NSwyLjE4LTEuNDYgYzAuMzItMC4yMiwwLjU4LTAuNTIsMC44NS0wLjc5YzAuOTItMC45MSwxLjc5LTEuODgsMy4yMy0xLjkxYzAuMDctMC4wMSwwLjEyLTAuMjUsMC4yMS0wLjM2YzAuNDctMC41NSwwLjg3LTEuMjMsMS40NS0xLjYyIGMxLjUyLTEuMDIsMy4xMS0xLjkzLDQuNzEtMi44M2MwLjI2LTAuMTUsMC43NC0wLjEzLDEuMDMsMC4wMWMwLjkyLDAuNDQsMi4xLDAuNzcsMi42NSwxLjUzYzEuMjcsMS43MiwyLjQ1LDMuNTgsMy4yNSw1LjU1IGMwLjgzLDIuMDYsMy4zNSwzLjQ4LDUuMTcsMi41N2MxLjY3LTAuODMsMi42My0yLjUyLDQuNTMtMy4xOGMxLjQ4LTAuNTEsMi42Mi0yLDMuOTMtMy4wM2MwLjI5LTAuMjIsMC42NC0wLjQ0LDAuOTgtMC40OSBjMi40Ni0wLjQsNC45My0wLjc1LDcuMzktMS4xM2MwLjItMC4wMywwLjQtMC4wNiwwLjU4LTAuMTRjMi4yMS0xLjAyLDMuMzItMC4zMSwzLjMyLDIuMTJjMCwxNC4xOS0wLjA1LDI4LjM4LDAuMDUsNDIuNTcgYzAuMDEsMS44Ni0wLjk2LDIuNy0yLjE4LDMuNjJjLTEuNzQsMS4yOS0zLjUxLDIuNTUtNS4xNywzLjk0Yy0xLjAzLDAuODUtMS43MywyLjM2LTIuODYsMi43N2MtMi4wNywwLjc0LTMuNSwyLjMtNS4zLDMuMzYgYy0wLjc4LDAuNDYtMi4zOCwxLjMtMS41MiwyLjQ2YzAuNzMsMC45OCwxLjUxLDIuNDIsMy4yOSwyLjI5YzEuNzUtMC4xMiwzLjUyLTAuMDEsNS4yOCwwLjA0YzAuMzYsMC4wMSwwLjc5LDAuMTEsMS4wNywwLjMyIGMwLjYyLDAuNDcsMS4wOCwxLjMsMS43NiwxLjUxYzIuNDUsMC43NiwyLjk0LDIuNzUsMy40LDQuODRjMC4wOSwwLjM4LDAuMjIsMC45LDAuNDksMS4wNWMxLjcxLDAuOTgsMS43NCwyLjUzLDEuNjUsNC4yIGMtMC4wNiwxLjMsMC4wMywyLjYxLDAuMDMsMy45MmMwLDI5Ljg0LDAuMDQsNTkuNjctMC4wNiw4OS41Yy0wLjAxLDIuMzEsMC44OCw0LjczLTAuOTYsNy4wN2MtMC44NywxLjA5LTAuNTQsMy4yLTAuOTQsNC44NiBjLTAuNTgsMi40NS0wLjU3LDQuOTUtMi4wNSw3LjIzYy0wLjc4LDEuMjEtMC43NiwyLjk0LTEuMTEsNC40NGMtMC4zNCwxLjQ5LTAuNjgsMi45OC0xLjAzLDQuNDZjLTAuMDMsMC4xMy0wLjE0LDAuMzQtMC4yMywwLjM1IGMtMS4xNSwwLjE4LTAuODgsMS4wOS0wLjg0LDEuNzZjMC4wNSwwLjk0LTAuMjcsMS44MywwLjg3LDIuNzJjMC44MiwwLjYzLDAuODMsMi4zNSwxLjEyLDMuNmMwLjQsMS43NCwwLjczLDMuNTEsMS4wOSw1LjI2IGMwLjAzLDAuMTUsMC4wNSwwLjMyLDAuMTMsMC40MmMxLjI5LDEuNTIsMS42NiwzLjM1LDEuOTYsNS4yNWMwLjIsMS4yNywwLjU5LDIuNTEsMC45MiwzLjc2YzAuMDMsMC4xMiwwLjIsMC4yLDAuMjYsMC4zMyBjMC4yOCwwLjU1LDAuNzcsMS4xMSwwLjc5LDEuNjhjMC4wOSwzLjE3LDAuMDksNi4zNCwwLjA4LDkuNTFjLTAuMDEsNTMuMjItMC4wMiwxMDYuNDUtMC4wOCwxNTkuNjhjMCwxLjUxLDAuNzgsMy4zNC0xLjA2LDQuNDcgYy0wLjA4LDAuMDUtMC4wNiwwLjI5LTAuMDcsMC40M2MtMC4yOSwzLjU4LTAuNTgsNy4xNi0wLjg2LDEwLjczYy0wLjMyLDQuMTUtMC42Myw4LjMtMC45NywxMi40NWMtMC4wMywwLjM3LTAuMjYsMC43My0wLjQsMS4wOSBjLTAuMjIsMC41NS0wLjY0LDEuMTEtMC42MywxLjY2YzAuMDEsMi4yMSwwLjE3LDQuMzEsMC45LDYuNTZjMC45NSwyLjk1LDAuNDgsNi4zMSwwLjg5LDkuNTFjMC42LDQuNzYsMC4xOSw5LjY0LDAuMjIsMTQuNDcgYzAsMC41LTAuMSwxLjExLDAuMTQsMS40OGMxLjQyLDIuMTksMC40OCw0LjU3LDAuNTQsNi44NGMwLjA0LDEuNDctMC40NCwyLjk4LTAuODQsNC40M2MtMC4yOCwwLjk5LTAuNjcsMi4wMi0xLjI5LDIuODIgYy0wLjgzLDEuMDgtMS43NywyLjAxLTEuNjQsMy41MmMwLjA1LDAuNDksMC4xNSwxLjIxLTAuMTEsMS40NmMtMS4xMywxLjA5LTAuNjUsMi40NC0wLjgzLDMuNjljLTAuMzEsMi4wNiwwLjE2LDQuMDQtMC44Miw2LjI0IGMtMC45NiwyLjE5LTAuMjYsNS4xNC0wLjE2LDcuNzVjMC4wMiwwLjUsMC44NywwLjk1LDAuOTMsMS40N2MwLjI5LDIuNzctMC4wMyw1LjUzLDAuODUsOC4zMmMwLjY1LDIuMDcsMC4yNiw0LjQ5LDAuMjEsNi43NSBjLTAuMDQsMi4yMiwwLjUxLDQuMzgsMC4xNSw2LjY2Yy0wLjQxLDIuNTYtMC4yLDUuMjEtMC4yOSw3LjgzYy0wLjAxLDAuNDMtMC4wMiwxLjEyLTAuMjcsMS4yNmMtMS40LDAuNzctMi44MywxLjU3LTQuMzQsMi4wNCBjLTEuNywwLjUzLTMuNTEsMC43Mi01LjI2LDEuMDdjLTAuMTUsMC4wMi0wLjM1LDAuMDYtMC40MiwwLjE2Yy0xLjA1LDEuNi0yLjk2LDEuMDYtNC40MiwxLjY5Yy0xLjgyLDAuNzktMy45OCwwLjgtNS45OSwxLjE2IGMtMC4yOSwwLjA1LTAuNjcsMC4xLTAuODMsMC4zYy0xLjA3LDEuMzctMi45LDEuNC00LjE4LDEuNTRjLTIuMzUsMC4yNS00LjgtMC40OS03LjIxLTAuODJjLTAuMTQtMC4wMi0wLjMyLTAuMS0wLjM5LTAuMjEgYy0xLjEzLTEuNzYtMi43OC0wLjcyLTQuMTktMC43MWMtMC40NSwwLTAuODYsMC43NS0xLjM2LDAuOWMtMS40OSwwLjQ0LTMuMDIsMC43NC00LjUzLDEuMTRjLTAuMjIsMC4wNi0wLjM1LDAuNDMtMC41NywwLjU4IGMtMC42NywwLjQ3LTEuMzYsMS4yNi0yLjA2LDEuMjljLTMuNTYsMC4xMy03LjE0LDAuMDctMTAuNzEsMC4wNGMtMC4zNCwwLTAuNzEtMC4yMS0xLjA0LTAuMzdjLTAuNTQtMC4yNi0xLjA1LTAuNTYtMS41OC0wLjg0IGMtMC44Mi0wLjQzLTEuNjktMC43OS0yLjQzLTEuMzJjLTAuNDctMC4zNC0wLjY0LTEuMS0xLjEyLTEuMzljLTEuODctMS4xNC0zLjEtMi43NS00LjExLTQuNjZjLTAuMjktMC41NS0xLjA1LTEuMTctMS42NC0xLjIyIGMtMi43MS0wLjIyLTUuNTQtMC41OC03LjY5LDEuNzJjLTAuODMsMC45LTEuOCwxLjA2LTIuOTIsMS4wNGMtMC4zOCwwLTAuODcsMC4wNC0xLjE0LDAuMjZjLTEuNTcsMS4yOS0zLjUsMS41MS01LjM4LDEuODIgYy0yLjM5LDAuMzktNC43OCwwLjY3LTcuMTcsMS4wMmMtMC4yMiwwLjAzLTAuMzksMC4yOS0wLjYxLDAuMzljLTEuMTEsMC41LTIuMiwxLjI2LTMuMzUsMS40MWMtMi4wOSwwLjI1LTMuMDEsMC45OC0yLjY0LDMuMDQgYzAuMTksMS4wNywwLjY0LDIuNDksMS40MywyLjk1YzEuMjEsMC43MiwyLjgzLDAuNyw0LjI2LDEuMDZjMS42NSwwLjQzLDMuMjgsMC45Myw0LjkyLDEuNDJjMS4wMSwwLjMsMi4wMSwwLjYzLDMuMDMsMC45MiBjMS44OCwwLjU0LDMuNzQsMS4zNSw1LjY2LDEuNTNjMy4wNCwwLjI4LDYuMTMsMC4xOCw5LjE5LDAuMThjMTMuNTIsMC4wMiwyNy4wNSwwLDQwLjU3LDAuMDRjMS40MSwwLjAxLDMuMDMtMC42Miw0LjEzLDAuOTQgYzAuMSwwLjE0LDAuNDgsMC4wNywwLjczLDAuMDljNS40OCwwLjQsMTEuMDMtMC42MSwxNi40NiwwLjk5YzEuOTUsMC41OCw0LjA1LDAuNjgsNi4xMSwxYzAuMDcsMS4yNiwwLjYxLDIuNDctMC43LDMuMyBjLTAuODUsMC41NC0xLjY1LDEuMjItMi41NywxLjU4Yy0yLjIsMC44NS00LjQ0LDEuNTctNi42OCwyLjMyYy0wLjk5LDAuMzQtMi4wMiwwLjU5LTMuMDEsMC45NGMtMS42NywwLjU4LTMuMzIsMS4yMS00Ljk4LDEuODIgYy0wLjIzLDAuMDktMC40NCwwLjIxLTAuNjYsMC4zMWMtMC41MywwLjI0LTEuMDQsMC42NC0xLjU4LDAuNjljLTUuMTgsMC40OC0xMC4zNS0wLjE3LTE1LjYxLDAuNjggYy01Ljc2LDAuOTMtMTEuNzktMC4xOC0xNy42NCwxLjFjLTAuODIsMC4xOC0xLjczLTAuMDktMi41NSwwLjA4Yy0xLjgsMC4zNy0zLjYxLDAuNzctNS4zMiwxLjQyYy0wLjU4LDAuMjEtMS4wOCwxLjEzLTEuMjYsMS44MiBjLTAuNjYsMi40NSwxLjAyLDUuMjksNC4wMyw1LjA3YzEuODMtMC4xMywzLjcyLDAuNTQsNS41OSwwLjg3YzAuMTIsMC4wMiwwLjIyLDAuMTgsMC4zNCwwLjI0YzAuNzIsMC4zMSwxLjQzLDAuODUsMi4xNywwLjg4IGMyLjUxLDAuMTEsNS4wMywwLjA5LDcuNTQsMC4wM2MxLjE4LTAuMDMsMi41NiwwLjQxLDMuMzMtMS4wOGMwLjA3LTAuMTUsMC41Ni0wLjExLDAuODYtMC4xMWM1LjIyLDAuMDEsMTAuNDQsMC4wMiwxNS42NiwwLjA1IGMwLjM0LDAsMC43OSwwLDEsMC4xOWMxLjMyLDEuMjUsMi44NiwxLjgyLDQuNjcsMS43OWMxLjYzLTAuMDIsMy4yNiwwLjAxLDQuNiwxLjI1YzAuMDYsMC45OS0wLjEyLDEuODMtMS40MSwxLjk1IGMtMC4yMywwLjAyLTAuNDYsMC4zMS0wLjY2LDAuNWMtMS4zMiwxLjMzLTIuNTYsMi43Ny0zLjk5LDMuOThjLTEuMDYsMC44OS0yLjM0LDIuMDctMy41NiwyLjEyYy0yLjUsMC4xLTQuMDYsMi4wMy02LjMsMi42IGMtMS4zMSwwLjM0LTIuNDYsMS40NS0zLjk4LDEuNTJjLTAuMjksMC4wMS0wLjY3LDAuMDctMC44MywwLjI2Yy0xLjExLDEuMzEtMi42MiwxLjY2LTQuMiwxLjc2Yy0xLjgsMC4xMi0zLjc2LTAuMjYtNS4zNywwLjMzIGMtMS41OCwwLjU5LTMuMDcsMC41NC00LjYxLDAuNTljLTEuOTYsMC4wNS0zLjkyLDAuMDItNS44OCwwYy0wLjM5LDAtMC43OS0wLjA3LTEuMTYtMC4xN2MtMC44My0wLjIyLTEuNjQtMC41OS0yLjQ4LTAuNzEgYy0yLjYxLTAuMzYtNS4yNC0wLjY0LTcuODUtMC45NmMtMC4xNS0wLjAyLTAuMzgtMC4wNi0wLjQxLTAuMTRjLTAuNTQtMS4zNi0xLjc0LTAuOTgtMi43MS0wLjk5Yy00LjAyLTAuMDYtOC4wNC0wLjA0LTEyLjA3LTAuMDUgYy0wLjQsMC0wLjgxLDAtMS4xOS0wLjA4Yy0xLjE4LTAuMjUtMi4zNC0wLjU3LTMuNTEtMC44MWMtMC40OS0wLjA5LTEuMTksMC4xNy0xLjQ3LTAuMDljLTEuNDktMS4zMi0zLjI1LTAuNjQtNC44OC0wLjgyIGMtMC40NS0wLjA1LTEuMiwwLjA2LTEuMy0wLjE0Yy0wLjY4LTEuNDItMS45My0xLjAzLTMuMDItMS4wNmMtMi4wNi0wLjA1LTUuMjctMi41OC02LjI0LTQuMzljLTAuODctMS42NC0yLjIzLTMuMDUtMy40OC00LjQ2IGMtMS4wNC0xLjE3LTIuMzYtMi4wOC0zLjMzLTMuMjljLTAuODctMS4wNy0xLjE2LTIuODQtMi4yMS0zLjQ5Yy0xLjkzLTEuMi0yLjc2LTMuNzctNS41My0zLjkyYy0wLjExLDAuMDgtMC41OCwwLjI4LTAuNzUsMC42MyBjLTAuMjgsMC41NC0wLjYzLDEuMjktMC40NSwxLjc3YzAuNDgsMS4zLDEuNTcsMi40NSwxLjc4LDMuNzZjMC4zNiwyLjIxLDIuMDEsMy43MywyLjU5LDUuODhjMC40NSwxLjY3LDEuMjYsMy40OCwyLjQxLDUuMDggYzEuMTQsMS41NiwxLjQxLDMuNzQsMi4xMyw1LjYzYzAuNDMsMS4xNiwwLjg5LDIuMzMsMS41MSwzLjRjMC4zNiwwLjYzLDEuMDEsMS4xMywxLjYxLDEuNTljMC42NywwLjUsMS41MiwwLjc5LDIuMTMsMS4zNSBjMC43OCwwLjcsMS4yNSwxLjgzLDIuMTEsMi4zMmMxLjgxLDEuMDIsNC4wNiwxLjA3LDUuNzcsMi4zOGMwLjA3LDAuMDYsMC4yMSwwLjA2LDAuMywwLjA0YzIuNDMtMC41Myw0LjM2LDEuMDgsNi4wNiwyLjEyIGMyLDEuMjQsNC41MiwyLjEyLDUuNzQsNC42MWMwLjQ3LDAuOTUsMS42NywxLjU1LDMuMTIsMC41NGMwLjktMC42MiwyLjE4LTAuNjksMy4xOC0xLjQ4YzEuMTUtMC45MSwyLjU5LTEuNDUsMy44OS0yLjE2IGMwLjM0LTAuMTgsMC42NS0wLjU1LDAuOTctMC41NmMyLjIxLTAuMDcsNC41My0wLjUsNi41OSwwLjA1YzEuNjUsMC40NCwzLjI5LDAuNDQsNC45MSwwLjc1YzMuMzQsMC42Myw2LjY4LDEuMjMsMTAuMTEsMS4wMSBjMC4xOS0wLjAyLDAuNDctMC4wNCwwLjU4LDAuMDdjMS42OSwxLjY5LDQuNS0wLjI3LDYuMDQsMS44OGMyLjY0LTAuMDYsNS4yMSwwLjMzLDcuNzUsMS4wNWMxLjM1LDAuMzgsMi43NCwwLjY1LDQuMSwwLjk4IGMwLjEzLDAuMDMsMC4yMSwwLjIsMC4zNCwwLjI3YzEuMTgsMC41OCwyLjMzLDEuMjgsMy41NywxLjdjMS4zNiwwLjQ3LDIuODEsMC42OCw0LjIyLDEuMDFjMC4xMiwwLjAzLDAuMjIsMC4xNiwwLjM0LDAuMjQgYzAuOTMsMC41OCwxLjgyLDEuMjIsMi44LDEuNzFjMS4wMywwLjUxLDIuNjgsMC41NywzLjEsMS4zNWMxLjAzLDEuOTIsMi45MywyLjc2LDQuNSwzLjY0YzEuMywwLjczLDMuNDUsMC4yNiw1LjA5LTAuMTggYzAuNDYtMC4xMiwwLjQ0LTIuMDUsMC42LTMuMTZjMC4wNi0wLjM0LTAuMDMtMC43MSwwLjAyLTEuMDVjMC4yOS0xLjg4LTEuMTItMy0xLjg0LTQuNDZjLTAuNy0xLjQyLTIuMjQtMS4xMi0zLjAzLTIuMTMgYy0wLjU3LTAuNzEtMS4xMS0xLjUyLTEuODUtMS45OWMtMS45OS0xLjI2LTQuMi0yLjA3LTUuOTgtMy43OWMtMS40Mi0xLjM4LTMuMzYtMi4yMS01LjA1LTMuMzNjLTAuNTMtMC4zNi0wLjk3LTAuODYtMS42LTEuNDMgYzEuNTktMC4yOCwyLjc5LTAuMzgsMy45MS0wLjczYzEuMzMtMC40MiwyLjU2LTEuMTUsMy44OC0xLjU5YzEuMjMtMC40MSwyLjUyLTAuMDgsMy44Ni0wLjczYzEuMDctMC41MSwyLjQ0LTEuMjgsMy41NC0xLjI3IGM0LjksMC4wNiw5Ljg3LTEuNDIsMTQuNzQsMC43N2MxLjg1LDAuODQsNC4xLDAuODksNi4xOSwxLjA4YzIuMiwwLjIsNC40MiwwLjA4LDYuNjMsMC4xOWMxLjM5LDAuMDcsMi44Ny0wLjM2LDMuMTUtMS41MiBjMC4zNS0xLjQzLTAuMTEtMy4wNy0wLjMxLTQuNjFjLTAuMDUtMC4zNS0wLjQzLTAuODYtMC43NS0wLjk0Yy0xLjg5LTAuNDUtMy4wMy0yLjYxLTUuMjgtMi4yOWMtMC4yOSwwLjA1LTAuNzYtMC40NC0wLjk4LTAuNzkgYy0wLjU1LTAuODctMS4wNC0xLjc4LTEuNDYtMi43MmMtMC43Mi0xLjU4LTEuMDctMy40Ny0yLjE1LTQuNzJjLTEuMDMtMS4yMS0xLjAxLTIuNjUtMS42NC0zLjkxYy0wLjk1LTEuOSwxLjE5LTQuODIsMy41NS01LjUxIGMxLjY0LTAuNDcsMi41Ni0xLjkyLDMuMTEtMy4yM2MwLjU2LTEuMywxLjQ4LTIuMTYsMi40Ny0yLjY1YzEuOTUtMSwzLjEzLTIuMjMsMi44NS00LjQ4Yy0wLjE1LTEuMTksMC4zNS0xLjk1LDEuMDQtMi4zOCBjMSwwLjI5LDEuNzUsMC41NywyLjU0LDAuNzFjMC42OCwwLjEyLDEuNjUtMC4yMSwyLjA1LDAuMTVjMS40MiwxLjI1LDMuMDYsMC43Myw0LjU5LDAuNzljMS42NCwwLjA3LDIuODItMS4xNywyLjcyLTIuODMgYy0wLjE0LTIuMzIsMC43MS00Ljc2LTEuMTctNi45Yy0xLjIzLTEuNDEtMi4wMi0zLjItMy4wNS00Ljc5Yy0wLjIyLTAuMzQtMC43Mi0wLjUyLTAuODctMC44N2MtMC40Ni0xLjA2LTAuNzctMi4xOS0xLjIzLTMuMjUgYy0wLjI5LTAuNzEtMC42OC0xLjM5LTEuMTMtMi4wMWMtMS4xLTEuNTYtMi4wNC0zLjE0LTEuNTMtNS4zN2MxLjQ5LTAuMDQsMi43OC0wLjA5LDMuODktMS4zMmMxLjEtMS4yMSwxLjItMi40OSwxLjI1LTMuOTIgYzAuMDEtMC4yMywwLjExLTAuNDgsMC4yNC0wLjY3YzEuMjQtMS44NCwwLjQ4LTMuODgsMC41OC01LjgzYzAuMDEtMC4xNS0wLjI5LTAuMzUtMC40OS0wLjQ2Yy0xLTAuNTYtMi4wMy0xLjA1LTMtMS42NCBjLTAuNS0wLjMtMC44NC0wLjg5LTEuMzUtMS4xM2MtMS0wLjQ2LTIuMTQtMC42Ni0zLjA5LTEuMmMtMC41MS0wLjI4LTAuOTQtMS0xLjA3LTEuNTljLTAuNDMtMi4wNC0wLjY5LTQuMTItMS4wOC02LjE3IGMtMC4wOC0wLjM5LTAuNTUtMC43LTAuNjMtMS4wOGMtMC4xOS0wLjkzLTAuNTYtMi0wLjI2LTIuNzhjMC4yLTAuNTYsMS43My0xLjI0LDIuMDctMWMxLjM0LDAuOTEsMi43NiwwLjU1LDQuMTMsMC43NSBjMC4zLDAuMDQsMC41NywwLjI4LDAuODcsMC40MWMwLjUsMC4yMywwLjk5LDAuNTgsMS41MiwwLjY1YzMuNDYsMC40OCw2Ljk4LTAuNDIsMTAuNDgsMC44NGMxLjg4LDAuNjcsNC4xOCwwLjIzLDYuMjksMC4xOSBjMC40Ny0wLjAxLDEuMjgtMC4zNywxLjM0LTAuNjljMC4yLTEuMDYsMC4yOS0yLjIsMC4wOS0zLjI1Yy0wLjA4LTAuNDEtMS4wNC0wLjY1LTEuNTktMWMtMC4xOC0wLjEyLTAuMy0wLjM0LTAuNDktMC40NyBjLTEuNTktMS4xMi0zLjQ3LTEuODYtNC41OC0zLjU5Yy0wLjA1LTAuMDctMC4yLTAuMDYtMC4yOC0wLjExYy0wLjcxLTAuNDMtMS40NS0wLjgxLTIuMTEtMS4zMWMtMC42MS0wLjQ3LTEuMS0xLjExLTEuNzItMS41NyBjLTAuNjgtMC41LTEuNDktMC44Mi0yLjE2LTEuMzNjLTAuNjUtMC40OS0xLjE0LTEuMjEtMS44MS0xLjY3Yy0xLjU3LTEuMDgtMy4yMS0yLjA2LTQuODMtMy4wOGMtMC41NS0wLjM1LTEuMS0wLjczLTEuNjktMS4wMSBjLTAuODItMC4zOC0xLjgtMC41My0yLjQ5LTEuMDZjLTAuNTMtMC40MS0wLjk1LTEuMjItMS4wNC0xLjkxYy0wLjI5LTIuMTgsMC40NC00LjQ3LTAuOTYtNi41M2MtMC41My0wLjc5LTEuMTEtMS43Ny0xLjExLTIuNjYgYy0wLjA2LTIwLjczLTAuMDUtNDEuNDYtMC4wMy02Mi4xOGMwLTAuNDIsMC4xNS0wLjg2LDAuMzEtMS4yNWMwLjIxLTAuNSwwLjY0LTAuOTQsMC43NC0xLjQ1YzAuMjktMS42MiwwLjE4LTMuMjIsMC43OC00LjkgYzAuODMtMi4zNCwwLjg4LTQuOTksMS4wOS03LjUyYzAuMTctMS45NSwwLjA1LTMuOTIsMC4xMS01Ljg4YzAuMDEtMC40NywwLjItMC45MywwLjM3LTEuMzhjMC4yLTAuNTEsMC42OC0wLjk5LDAuNjktMS40OSBjMC4wNS00LjA4LDAuMDQtOC4xNSwwLjAxLTEyLjIzYzAtMC40OC0wLjA0LTEuMjUtMC4zMi0xLjM5Yy0wLjk5LTAuNDktMC43LTEuMzMtMC43OC0yLjA4Yy0wLjM1LTMuMDUtMC4zMS02LjIxLTEuMi05LjA5IGMtMC43LTIuMjktMC42OS00LjQ5LTAuNjItNi43MmMwLjEyLTMuNjQtMC40Ni03LjMxLDAuNjctMTAuOTVjMC43MS0yLjI2LDAuNzgtNC43MSwxLjE0LTcuMDdjMC4wNC0wLjI0LDAuMDUtMC41MywwLjE5LTAuNzIgYzEuMjctMS42NywxLjA4LTMuNzksMS42Ni01LjY3YzAuNDQtMS4zOSwwLjEtMywwLjI2LTQuNWMwLjEtMC45MywwLjItMi4xNiwwLjgtMi42OGMxLjQyLTEuMjMsMS4wNS0yLjcxLDEuMTEtNC4xOCBjMC4wMi0wLjc1LDAuMDgtMS41LDAuMDgtMi4yNmMwLTcuOTQsMC0xNS44OS0wLjAzLTIzLjg0YzAtMC40LTAuMjUtMC44MS0wLjQyLTEuMmMtMC4yMS0wLjUtMC42LTAuOTctMC42NC0xLjQ4IGMtMC4xLTEuMywwLjA2LTIuNjMtMC4wOS0zLjkyYy0wLjEzLTEuMDMtMC45LTIuMDYtMC43OC0zLjAyYzAuMzEtMi40Ny0wLjktNC42Mi0xLjEyLTYuOTVjLTAuMDItMC4yMi0wLjIzLTAuNDEtMC4zMy0wLjYzIGMtMC4yNS0wLjUyLTAuNjItMS4wMy0wLjctMS41OGMtMC4xOS0xLjM0LDAuMDQtMi44LTAuMzktNC4wM2MtMC44LTIuMjQtMS42Mi00LjQyLTEuNjItNi44NGMwLjAxLTE3LjY1LDAuMDEtMzUuMzEsMC4wMS01Mi45NyBjMC0wLjM1LDAuMDEtMC43LDAtMS4wNWMtMC4wMi0xLjA1LDAuNDEtMS41LDEuNTQtMS40OGMyLjk2LDAuMDcsNS45MywwLjE0LDguODktMC4wMmMxLjM2LTAuMDgsMi43OS0wLjUsMy45OS0xLjEyIGMwLjc1LTAuMzksMS40Ni0xLjM5LDEuNjItMi4yM2MwLjI3LTEuMzYsMC4xNy0yLjgyLDAuMDEtNC4yYy0wLjA2LTAuNTMtMC42Ni0xLjEyLTEuMTYtMS40NWMtMC45NS0wLjYyLTItMS4wOC0zLjAyLTEuNiBjLTAuOTktMC41LTEuOTYtMS4wNi0yLjk4LTEuNDdjLTEuNzgtMC43My0zLjYxLTEuMzUtNS40LTIuMDZjLTAuNDMtMC4xOC0wLjczLTAuNy0xLjE2LTAuODRjLTIuMjQtMC42OC0yLjM3LTAuODEtMi4zNy0zLjAzIGMwLjAxLTI1LjYxLDAtNTEuMjEsMC4wMi03Ni44MmMwLTMuMDcsMC4xNC02LjEzLDAuMjEtOS4yYzAuMDEtMC4yNCwwLjAyLTAuNSwwLjA3LTAuNzRjMC4yNy0xLjIyLDAuNjMtMi40MiwwLjgxLTMuNjYgYzAuMzctMi41NSwwLjY0LTUuMTMsMC45Ny03LjY5YzAuMDItMC4xOCwwLjEyLTAuNCwwLjI2LTAuNTFjMS4yNS0xLjAxLDEuNi0yLjMxLDEuNy0zLjg5YzAuMjItMy4yOSwwLjY3LTYuNTYsMS4wNC05Ljg0IGMwLjAyLTAuMTgsMC4xMS0wLjQ3LDAuMjMtMC41MWMxLjEyLTAuMzksMC44MS0xLjM2LDAuOS0yLjE2YzAuMDUtMC41NS0wLjA4LTEuMTMsMC4wNi0xLjY1YzAuNDgtMS43NSwxLjMyLTMuNDUsMS41My01LjIzIGMwLjI5LTIuMzcsMC42NS00Ljk2LTAuMDEtNy4xNmMtMC42My0yLjEtMC40NS00LjA4LTAuNjQtNi4xMWMtMC4wNi0wLjc1LDAuMTQtMS42Ny0wLjIyLTIuMjJjLTEuMDctMS42Mi0wLjUzLTMuMzYtMC42OC01LjA0IGMtMC4wNC0wLjQ1LDAtMC45MSwwLTEuMzZjLTAuMDQtMTEuNzctMC4wNy0yMy41NC0wLjEyLTM1LjMyYzAtMC43NCwwLjMxLTEuNjQtMC43Ni0yLjA1Yy0wLjE4LTAuMDctMC4yNi0wLjUxLTAuMy0wLjc5IGMtMC4yOC0xLjcxLTAuNTMtMy40Mi0wLjc5LTUuMTNjLTAuMDItMC4xNC0wLjA0LTAuMzQsMC4wNC0wLjQzYzAuODUtMS4wOSwxLjQyLTIuNTIsMy4xOC0yLjQ4YzAuNDgsMC4wMSwxLjAxLTAuMSwxLjQ1LTAuMyBjMS45My0wLjg3LDMuODMtMS44Miw1Ljc2LTIuN2MwLjkxLTAuNDEsMS44OC0wLjY5LDIuOC0xLjA2YzAuNzktMC4zMiwxLjg3LTAuNDYsMi4yOC0xLjA2YzEuMDQtMS41MSwyLjk0LTAuNjUsNC4wOC0xLjc1IGMwLjItMC4yLDAuOTQtMC4wOSwxLjI3LDAuMTNjMS4wMiwwLjY4LDEuOTEsMS41NywyLjk1LDIuMjFjMC45NywwLjYsMi4wNSwxLjAxLDMuMTEsMS40NWMwLjc3LDAuMzIsMS41NywwLjU0LDIuNiwwLjg4IGMwLjA4LTAuMDYsMC40My0wLjUsMC44OC0wLjY4YzEuOTktMC44LDIuMjgtMS4xOSwyLjMyLTMuMzNjMC4wMi0wLjgtMC4xNi0yLjA1LDAuMjQtMi4zYzEuMDUtMC42NSwwLjgtMS41MywwLjg0LTIuMzcgYzAuMS0xLjg1LDAuMS0zLjcxLDAuMi01LjU3YzAuMDItMC40NiwwLjE0LTEsMC40Mi0xLjM1YzEuMTktMS40OCwyLjQzLTIuOTIsMy43Mi00LjMzYzEuODUtMi4wMiwzLjc2LTMuOTgsNS42Mi01Ljk5IGMxLjItMS4zLDIuNDEtMi41OCwzLjUxLTMuOTZjMC45MS0xLjE1LDIuMzQtMS44MiwyLjczLTMuNDhjMC4yMi0wLjk2LDEuMDQtMS43NywxLjU4LTIuNjZjMS4wMS0xLjY4LDIuMDgtMy4zNCwyLjk5LTUuMDcgYzAuODYtMS42MywxLjUzLTMuMzYsMi4zMy01LjAxYzAuMTItMC4yNCwwLjU1LTAuNDgsMC44Mi0wLjQ3YzAuODUsMC4wNiwxLjcsMC4yMywyLjU2LDAuMzZjMS42NC0wLjM3LDMuMzQtMC42NCw1LjA0LTAuNjEgYzIuMiwwLjA0LDQuMTgtMC4xNiw1LjI1LTIuNTVjLTAuNDItMC42Ni0wLjc1LTEuNTMtMS4zNy0yLjA3Yy0xLjI2LTEuMTMtMi42NC0yLjA4LTIuNTQtNC4wN2MwLjAyLTAuNDMtMC4yOS0wLjk3LTAuNi0xLjMyIGMtMC45OC0xLjA5LTEuODgtMi4yMy0yLjI3LTMuNjhjLTAuMjUtMC45Mi0wLjQ1LTEuODUtMC43LTIuOTJjMC4xLTAuMTYsMC40Ny0wLjQ5LDAuNTMtMC44N2MwLjQxLTIuODEsMC42NC01LjY2LDEuMTktOC40NCBjMC4zNi0xLjc4LDEuMTQtMy40OCwxLjgxLTUuMTljMC4xMy0wLjMzLDAuNTgtMC41OCwwLjkyLTAuNzhjMS4yMS0wLjcsMi43Mi0xLjExLDMuNTgtMi4xYzAuODctMSwxLjg5LTEuNDMsMi45My0yLjA1IEMyMTUuMzQ2LDExMi4yLDIxNi4zNzcsMTExLjI4LDIxNi4wODYsMTA5LjY5eiBNMTExLjQzNywxOTIuNDJjLTQ2LjU3LDAtODQuMzItMzcuNzUtODQuMzItODQuMzJjMC00Ni41NiwzNy43NS04NC4zMSw4NC4zMi04NC4zMSBjNDYuNTYsMCw4NC4zMSwzNy43NSw4NC4zMSw4NC4zMUMxOTUuNzQ3LDE1NC42NywxNTcuOTk3LDE5Mi40MiwxMTEuNDM3LDE5Mi40MnpcIixcbiAgICAgICAgICAgIFwiTTIyMC4wNDEsMTU3Ljg1Yy0wLjU1LTEuNTktMS45OS0yLjkxLTMuMTktNC4yMmMtMS40NC0xLjU1LTMuMDYtMi45My00LjU0LTQuNDQgYy0wLjk0LTAuOTctMi4wOS0xLjkxLTIuNTctMy4xYy0wLjcxLTEuNzUtMi4wMy0yLjY5LTMuMzktMy43N2MtMC44Mi0wLjY1LTEuNDUtMS42LTIuMDUtMi40OGMtMC41LTAuNzQtMC42NS0xLjk2LTEuMzEtMi4zMSBjLTEuMTItMC42Mi0wLjkyLTEuNDEtMC44NC0yLjI2YzAuMDgtMC45LTAuMDctMi4xLDAuNDQtMi42YzAuNzgtMC43OCwwLjctMS41OSwwLjgyLTIuNDVjMC4wOC0wLjU2LTAuMS0xLjI1LDAuMTYtMS42OSBjMS4zNS0yLjM1LTAuMTItNS4zNSwxLjgxLTcuNTJjMC4yNy00LjM2LDAuNzctOC43MiwwLjc0LTEzLjA3Yy0wLjAyLTQuNi0wLjU1LTkuMTktMC44Ni0xMy43OGMtMC4wMi0wLjIzLTAuMDQtMC42LTAuMTgtMC42NyBjLTEuMi0wLjU4LTAuNzQtMS42OS0wLjg4LTIuNjJjLTAuMy0yLjAzLTAuNjItNC4wNi0wLjk0LTYuMDljLTAuMDMtMC4xNy0wLjE2LTAuMzItMC4yNC0wLjQ5Yy0wLjI0LTAuNTQtMC42LTEuMDYtMC42OS0xLjYyIGMtMC4xMy0wLjc1LDAuMDEtMS41NC0wLjA2LTIuM2MtMC4xNC0xLjU2LDAuMzktMy4yMi0wLjc5LTQuNjVjLTAuMjItMC4yOC0wLjItMS4xNCwwLjA1LTEuMzZjMS4xOS0xLjA4LDEuOTYtMi41OCwzLjY4LTMuMTggYzAuOS0wLjMyLDEuODctMS40MiwyLjExLTIuMzVjMC4zNi0xLjM4LDAuMDktMi45MiwwLjA5LTQuNTljLTEuNzMsMC0zLjMsMC4wMi00Ljg3LDBjLTAuMzYtMC4wMS0wLjk4LTAuMDItMS4wNS0wLjIgYy0wLjQ2LTEuMDktMS40My0wLjcyLTIuMjEtMC45M2MtMC42LTAuMTYtMS40Ny0wLjMtMS42OS0wLjczYy0wLjY1LTEuMjYtMS45NS0xLjkxLTIuNTEtMy4zNWMtMC41NC0xLjM5LTEuOTQtMi40OC0zLjA2LTMuNiBjLTEuNTctMS41OC0zLjI5LTMuMDEtNC44Mi00LjYzYy0wLjktMC45Ni0xLjQ1LTIuMjMtMi4zLTMuMjRjLTEuMzctMS42My0zLjEzLTIuODQtMy45My01LjA0Yy0wLjc1LTIuMDQtMC45My0yLjI4LDAuOTEtMy4zNCBjMS4xMy0wLjY1LDIuNDYtMS4yNiwzLjE0LTIuMjdjMC42MS0wLjkxLDEuMzgtMS4zMywyLjE4LTEuNThjMS4yMi0wLjM2LDEuODctMS4yNywyLjA0LTIuMjJjMC4yNi0xLjUyLDAuMDctMy4xMiwwLjA3LTQuNjUgYy0wLjctMC4xOC0xLjUzLTAuMTYtMS43My0wLjVjLTAuNTQtMC45My0xLjM0LTAuODgtMi4xLTAuOGMtMi4yNiwwLjIyLTQuNDMtMC4xLTYuODEsMC45MWMtMi41LDEuMDYtNS43LDAuMDYtOC41OCwwLjk3IGMtMS4zOSwwLjQ0LTMuMDQsMC4wMS00LjYzLTAuNDljLTEuNzItMC41NC0zLjIzLTEuMzktNC44MS0yLjEyYy0wLjUzLTAuMjQtMC44Ni0wLjkyLTEuMzktMS4yMWMtMS42NS0wLjkxLTMuMzQtMS43NS01LjAzLTIuNTggYy0xLjEzLTAuNTUtMi4yNy0xLjEyLTMuNDYtMS41Yy0xLjMtMC40Mi0yLjY3LTAuNjQtNC4wMS0wLjk2Yy0wLjEyLTAuMDMtMC4yLTAuMTgtMC4zMi0wLjI1Yy0wLjQ5LTAuMjgtMC45Ni0wLjY5LTEuNS0wLjgxIGMtMS41OC0wLjM4LTMuMTgtMC42NC00Ljc4LTAuOTZjLTAuMTQtMC4wMi0wLjMxLTAuMDQtMC4zOS0wLjEzYy0xLjI4LTEuNTMtMy4zMy0wLjkzLTQuODgtMS43N2MtMC41NC0wLjMtMS4xNi0wLjI1LTEuNzYtMC44IGMtMC43NC0wLjY5LTEuOTUtMC44Ni0yLjk1LTEuMjdjLTAuMzEtMC4xMy0wLjU3LTAuMzYtMC44OC0wLjUyYy0xLjgyLTAuOTEtMi40NC0zLjQxLTQuODUtMy42M2MtMC4zNy0wLjAzLTAuODQtMC45Ny0wLjkzLTEuNTQgYy0wLjE2LTAuOTctMC4wNC0yLTAuMDQtMi43N2MtMS4yOS0xLjQtMi43MS0xLjY2LTQuMzEtMS41Yy0xLjA0LDAuMS0zLjI2LDEuODktMy43NywyLjc5Yy0wLjY4LDEuMjEtMC40OSwzLjA2LTIuNSwzLjQgYy0wLjU0LDAuMS0xLjAyLDAuODUtMS40MSwxLjM5Yy0wLjU4LDAuODItMS4yNCwxLjI3LTIuMywxLjI0Yy0yLjAxLTAuMDYtNC4wMy0wLjA0LTYuMDQsMC4wMmMtMC41MiwwLjAyLTEuMDMsMC4zMS0xLjUzLDAuNTEgYy0wLjQsMC4xNi0wLjc1LDAuNS0xLjE1LDAuNTVjLTMuMDksMC40LTYuMiwwLjc0LTkuMywxLjExYy0wLjE0LDAuMDItMC4zMSwwLjAxLTAuNDEsMC4xYy0xLjc0LDEuNDYtNC4wNSwxLjI2LTYuMDEsMS41MiBjLTIuMDIsMC4yNy0zLjU3LDEuMzItNS40LDEuODJjLTEuMjcsMC4zNS0yLjQ1LDEuMDItMy42OSwxLjUxYy0yLjA2LDAuODItNC4xMywxLjYxLTYuMiwyLjRjLTAuNjQsMC4yNC0xLjM1LDAuMzctMS45MSwwLjczIGMtMS40NiwwLjk0LTIuODMsMi4wMS00LjI4LDIuOTdjLTEuMDcsMC43Mi0yLjIsMS4zNy0zLjMxLDIuMDRjLTAuOTgsMC41OS0xLjk4LDEuMTQtMi45NCwxLjc2Yy0wLjQ5LDAuMzItMC44OSwwLjc5LTEuMzgsMS4xMSBjLTAuNTYsMC4zNS0xLjQxLDAuNDctMS43MSwwLjk1Yy0wLjQ5LDAuNzktMS4wOSwxLjA2LTEuOTIsMS4yNmMtMC41NiwwLjE0LTEuMDksMC42MS0xLjUyLDEuMDRjLTAuOTEsMC45MS0xLjcsMS45Mi0yLjYsMi44NCBjLTEuNDcsMS41Mi0zLjAxLDIuOTYtNC40Nyw0LjQ5Yy0xLjA0LDEuMS0xLjk0LDIuMzQtMi45OSwzLjQyYy0xLjA1LDEuMDctMi4yMywyLjAyLTMuMzQsMy4wM2MtMC4xNiwwLjE1LTAuNDIsMC4zNC0wLjQyLDAuNDkgYzAuMSwxLjc0LTIuMDYsMS45Ny0yLjI5LDMuNDdjLTEuOTUsMC4yOS0xLjY3LDIuNDItMi43OSwzLjQ5Yy0xLjE2LDEuMTEtMS42MSwyLjk0LTIuMzksNC40NWMtMC4zNiwwLjY4LTAuNjIsMS41MS0xLjE3LDEuOTggYy0wLjk2LDAuODEtMS40NSwxLjc0LTEuNTIsMi45NmMtMC4wMiwwLjM4LTAuMDIsMC44MS0wLjIsMS4xMWMtMC44NCwxLjQ1LTEuNzQsMi44Ny0yLjYyLDQuMjljLTAuNCwwLjYzLTEuMDMsMS4yMi0xLjE2LDEuOSBjLTAuMjUsMS4yOS0wLjk0LDEuNi0yLjE0LDEuNzNjLTIuNTMsMC4yNy01LjE3LTAuODUtNy42MiwwLjk3Yy0wLjc4LDAuNTctMS4yOSwwLjktMS4yOCwxLjgyYzAuMDIsMS4xNSwwLjA0LDIuMywwLjA5LDMuNDUgYzAuMDEsMC4yOCwwLjAyLDAuNjQsMC4xOCwwLjgyYzAuOTEsMS4wMSwxLjg3LDEuOTksMi44MiwyLjk3YzAuMywwLjMxLDAuNjYsMC41NiwwLjkyLDAuODljMC41NCwwLjcsMC45MSwxLjU4LDEuNTcsMi4xMSBjMS4zMiwxLjA1LDEuNzYsMi43LDAuOTEsNC4xNmMtMC4xOSwwLjMyLTAuMzEsMC43LTAuMzcsMS4wN2MtMC4zMywyLjM2LTAuMTksNC42OC0wLjkzLDcuMTJjLTEuMDQsMy4zOS0wLjc2LDcuMTktMC45OSwxMC44MiBjLTAuMDg0LDEuMy0wLjAyOCwyLjYwOS0wLjAwNCwzLjkxYzAuMDA2LDAuMzQ3LDAuMDQyLDAuOTEzLDAuMTEzLDEuMjUzYzAuMjE1LDEuMDMxLDAuNjA3LDIuMDM4LDAuNzEyLDMuMDc3IGMwLjEzLDEuMTgsMC4wMiwyLjM5LDAuMDgsMy41OWMwLjAyLDAuMzksMC4yNCwwLjc3LDAuMzksMS4xNWMwLjE5LDAuNSwwLjUsMC45NywwLjYsMS40OWMwLjM2LDEuODgsMC42NiwzLjc4LDAuOTgsNS42NyBjMC4wMiwwLjE0LDAuMDQsMC4zNiwwLjEyLDAuMzljMS4zMSwwLjU4LDAuNzksMS43OCwwLjk1LDIuNzRjMC4wOCwwLjQ3LTAuMDQsMS4wOSwwLjIxLDEuNGMxLjA3LDEuMjcsMC43NiwyLjk4LDEuNjQsNC40MSBjMC45MiwxLjQ5LDAuODMsMy41MywxLjk1LDUuMTVjMS4wNywxLjUzLDEuMTEsMy41MiwyLjA5LDUuMjNjMS4xNCwyLDEuNzYsNC4zMywzLjEyLDYuMjljMC45OSwxLjQzLDEuODYsMi45NCwyLjgxLDQuMzkgYzAuNDMsMC42NCwxLjA1LDEuMTcsMS4zOCwxLjg2YzAuMzIsMC42NiwwLjUyLDEuNDYsMC40NiwyLjE3Yy0wLjAyLDAuMjEtMS4xMSwwLjM3LTEuNzIsMC40N2MtMC44OSwwLjE0LTIuMDMtMC4xLTIuNjQsMC4zNyBjLTEuMjcsMC45OS0yLjU4LDEuNi00LjE2LDEuNzVjLTAuMjcsMC4wMi0wLjY2LDAuMTItMC43OCwwLjMxYy0wLjc0LDEuMi0yLjE4LDAuOTQtMy4xOSwxLjYyYy0wLjksMC42LTEuOTcsMC45NS0yLjk1LDEuNDUgYy0wLjEzLDAuMDYtMC4xNSwwLjMzLTAuMjIsMC41Yy0wLjI5LDAuNjEtMC41NywxLjIyLTAuODgsMS44OGMwLjIyLDAuMTQsMC42NiwwLjI2LDAuNzMsMC40OWMwLjQ0LDEuNTYsMS42MiwxLjcxLDIuOTUsMS42OSBjNi0wLjEsMTIsMC4yOCwxNy45OC0wLjZjMi4wMi0wLjMsMi4zNS0wLjA0LDIuMjcsMS44N2MtMC4wMSwwLjMzLDAuMzMsMC42NSwwLjQyLDFjMC4yOCwxLjA4LDAuOTMsMi4xOC0wLjMsMy4xOCBjLTAuNzIsMC41OS0xLjI4LDEuMzktMS45NywyLjA0Yy0wLjU3LDAuNTUtMS4xNiwxLjEzLTEuODQsMS41MWMtMS41MywwLjg1LTMuMjksMS4zMy00LjM3LDIuODdjLTAuMTEsMC4xNi0wLjM4LDAuMjEtMC41NywwLjMyIGMtMS41MywwLjg5LTMuMywxLjU0LTQuNTQsMi43NGMtMS42NywxLjYzLTQuMDMsMS44My01LjcyLDMuM2MtMC42MiwwLjUzLTEuNCwwLjktMi4xLDEuMzRjLTAuMzUsMC4yMi0wLjY4LDAuNTctMS4wNSwwLjY0IGMtMS42NywwLjMzLTIuNjEsMS44MS0yLjEyLDMuNDdjMC4zOCwxLjI5LDIuMDUsMS42MywzLjI5LDEuMDhjMS41LTAuNjcsMi44My0yLDQuNzItMS42YzAuMjMsMC4wNSwwLjQ4LTAuMDMsMC43MSwwLjAxIGMzLjI5LDAuNTksNi4zOC0wLjgxLDkuNi0wLjljMC4xNCwwLDAuMzctMC4wMiwwLjQtMC4wOWMwLjU5LTEuNDcsMS45LTAuODIsMi45Mi0xLjA3YzEuMDgtMC4yNywyLjMxLTAuNDgsMy4xMi0xLjE0IGMxLjM0LTEuMSwzLjAxLTEuNDIsNC40My0xLjUyYzIuMDctMC4xNCwzLjU1LTEuNjQsNS41NC0xLjcxYzAuNTMtMC4wMiwxLjA0LTAuMywxLjU1LTAuNDZjMC40NS0wLjE0LDAuOTItMC4yMiwxLjMzLTAuNDMgYzAuOTUtMC40OSwxLjg3LTEuNDgsMi44LTEuNDdjMi4xNywwLjAzLDQuMzMsMC41MSw2LjUsMC44M2MwLjEsMC4wMiwwLjE2LDAuMjQsMC4yNywwLjI5YzAuNTYsMC4yOCwxLjExLDAuNjEsMS43LDAuNzggYzEuMjgsMC4zNywyLjk4LDAuMjUsMy44LDEuMDZjMS40MSwxLjM3LDMuMjQsMC44OCw0LjczLDEuNzNjMC45MiwwLjUzLDIuNDItMC4yNSwzLjI1LDEuMDVjMC4xMSwwLjE3LDAuNTUsMC4yMSwwLjgyLDAuMTggYzMuMjgtMC40NSw1LjQsMi4wMyw4LjA1LDMuMThjMS4wMiwwLjQ0LDEuOSwxLjIsMi45NCwxLjZjMi4yOCwwLjg3LDQuNzcsMC43NSw3LjEyLDEuODVjMi4xLDAuOTksNC43NiwxLjA5LDcuMTYsMS4wMyBjNi43Mi0wLjE5LDEzLjQ5LDAuOTUsMjAuMTctMC43MWMxLjEzLTAuMjgsMi4zOS0wLjA4LDMuNTgtMC4xN2MwLjM5LTAuMDIsMC43OC0wLjIxLDEuMTUtMC4zN2MwLjQ3LTAuMjEsMC45MS0wLjYsMS4zOS0wLjY3IGMxLjE0LTAuMTUsMi40OSwwLjIxLDMuMzktMC4zYzEuNTItMC44NCwyLjkxLTAuNDIsNC40Ny0wLjQ3YzAuMDMsMC44MSwwLjA5LDEuNDcsMC4wOSwyLjEzdjE3MC4zOWMwLDEuOTIsMC4wMSwzLjg0LTAuMDEsNS43NiBjMCwwLjQyLDAuMDMsMS4xMy0wLjE3LDEuMjJjLTEuNDgsMC42Ni0wLjg4LDEuOTQtMC45MywyLjk3Yy0wLjEsMS42Ny0wLjE1LDMuMzYtMC4wMiw1LjAzYzAuMTQsMS45NS0wLjc2LDQuMSwxLDUuNzkgYzAuMTQsMC4xMywwLjA3LDAuNDYsMC4xMywwLjY5YzAuMzIsMS4xNiwwLjY0LDIuMzEsMSwzLjQ1YzAuMDUsMC4xOCwwLjMyLDAuMzMsMC41MiwwLjQyYzEuMzUsMC41NywxLjY4LDEuNDUsMS4wMiwyLjgxIGMtMC4xNCwwLjI5LTAuNDIsMC43MS0wLjMxLDAuODhjMS4xMSwxLjgxLDAuNjksMy44MywwLjYzLDUuNzNjLTAuMSwyLjk4LTAuNTksNS45NC0wLjc2LDguOTNjLTAuMTQsMi40My0wLjAzLDQuODktMC4wOCw3LjMzIGMtMC4wMSwwLjYsMC4yMywxLjQxLTAuOCwxLjU3Yy0wLjEyLDAuMDItMC4yOCwwLjM3LTAuMjksMC41N2MtMC4xNiwzLjA4LTAuMzYsNi4xNS0wLjcyLDkuMjRjLTAuNTksNC45Ny0wLjIxLDEwLjA1LTAuMjEsMTUuMDkgYzAsNDQuMTgsMC4wMSw4OC4zNiwwLDEzMi41NGMwLDYuMjMtMC4wMiwxMi40Ny0wLjEyLDE4LjdjLTAuMDMsMS4zNywwLjEzLDIuNjctMC43OSw0LjEyYy0wLjkyLDEuNDMtMC45MywzLjU2LTEuMDIsNS4zOSBjLTAuMTYsMy4xMS0wLjA3LDYuMjQtMC4xMSw5LjM2Yy0wLjAxLDAuNTEtMC4wMiwxLjQtMC4yNCwxLjQ3Yy0xLjIxLDAuNC0wLjgsMS4zNS0wLjg5LDIuMTNjLTAuMDgsMC42Mi0wLjAzLDEuMjgtMC4yNiwxLjg0IGMtMS4wMywyLjU0LTAuODYsNS4zMS0wLjI1LDcuNzFjMC40NCwxLjc0LDAuNDEsMy4zOSwwLjYxLDUuMDhjMC4wOSwwLjcxLTAuMTcsMS43NSwwLjIyLDIuMDhjMS4xMiwwLjk3LDAuODUsMi4xNiwwLjg2LDMuMyBjMC4wNSwxMC4wOCwwLjA4LDIwLjE1LDAuMDcsMzAuMjJjMCwxLjIxLDAuMzMsMi41OS0xLjAzLDMuNDVjLTAuMTgsMC4xMS0wLjE4LDAuNTMtMC4yNCwwLjhjLTAuMywxLjQ1LTAuNTksMi45MS0wLjkyLDQuMzYgYy0wLjA0LDAuMTgtMC4zMiwwLjI5LTAuNDUsMC40N2MtMC4yMywwLjM0LTAuNTMsMC42OC0wLjYxLDEuMDZjLTAuMzYsMS42OS0wLjY0LDMuMzgtMC45Niw1LjA4Yy0wLjAyLDAuMTMtMC4wMywwLjM2LTAuMTEsMC4zOSBjLTEuMzcsMC41Ny0wLjgyLDEuNzctMC44NywyLjczYy0wLjA3LDEuNDgsMC4wOSwyLjk4LTAuMDYsNC40NWMtMC4wNywwLjY0LTAuNTYsMS41OC0xLjA3LDEuNzRjLTEuNTMsMC40OC0zLjM5LTAuMjItNC42NiwxLjI4IGMtNi4xMSwwLjA1LTEyLjItMC4wNC0xOC4yOSwwLjgzYy0zLjU3LDAuNTEtNy4yNywwLjA5LTEwLjkxLDAuMTFjLTAuNTIsMC0xLjM0LTAuMDgtMS41MiwwLjJjLTAuODgsMS40LTIuMiwwLjc5LTMuMzQsMC44NSBjLTEuNjgsMC4wOS0zLjM2LDAuMDEtNS4wMywwLjAzYy0yLjIyLDAuMDMtMi44NywwLjYxLTIuODgsMi41MmMtMC4wMSwxLjc0LDEuNTYsMy42NiwzLjA2LDMuNjdjMi40NCwwLjAyLDQuODktMC4wMyw3LjMzLDAuMDMgYzAuNTQsMC4wMSwxLjEsMC4yOSwxLjU5LDAuNTZjMC42NiwwLjM1LDEuMjMsMS4xMywxLjg4LDEuMTdjMi43NywwLjE5LDUuNSwwLjMsOC4yNywwLjhjMy40LDAuNjIsNi45NywwLjI2LDEwLjQ2LDAuMzkgYzEuMzEsMC4wNCwyLjc3LTAuNTEsMy44MSwwLjg2YzAuMTMsMC4xNiwwLjU1LDAuMTEsMC44MywwLjE2YzEuOTgsMC4zMSwzLjk3LDAuNTcsNS45MywwLjk0YzEuMDksMC4yMSwyLjEzLDAuNjEsMy4xOSwwLjkzIGMwLjEzLDAuMDQsMC4yMywwLjE1LDAuMzUsMC4yMWMwLjYyLDAuMzEsMS4yNSwwLjU5LDEuODcsMC45YzAuNzEsMC4zNywxLjc5LDAuNTksMi4wNSwxLjE3YzAuNTYsMS4yMywwLjg1LDIuNjQsMC45Niw0LjAxIGMwLjE5LDIuNTMsMC4xNSw1LjA3LDAuMjUsNy42MWMwLjAxLDAuMzgsMC4yMiwwLjc3LDAuMzksMS4xMmMwLjIxLDAuNDMsMC42NywwLjgzLDAuNjgsMS4yNGMwLjA2LDIuNTQsMC4wMyw1LjA4LDAuMDMsOC4wMiBjLTEuNjYsMC4xOC0zLjI0LDAuNDUtNC44MiwwLjVjLTIuOTIsMC4wNy01Ljg1LDAtOC43NywwLjAzYy0wLjc5LDAtMS41OSwwLjEzLTIuNDksMC4yMmMwLjA0LDEuNjItMC43MywzLjA0LDAuODMsNC40OSBjMS4zNywxLjI2LDIuNDIsMi43LDQuNTIsMi41NWMwLjQyOS0wLjAzMSwwLjg2MSwwLjA1NywxLjI2MiwwLjIxMWMyLjExOSwwLjgxLDQuMTQ5LDEuODg5LDYuNTE4LDEuODU5IGMyLjY0Ny0wLjAyMiwzLjAwNywwLjY3MywyLjkzMiwzLjc3NmMtMC4wMTcsMC43MDgsMC4wMjUsMS40MTUsMC4wNjEsMi4xMjJjMC4wNjUsMS4yOTUtMC40NCwxLjgzMS0xLjgyMywxLjgxMiBjLTMuNjktMC4wNy03LjM4LTAuMDMtMTEuMDcsMGMtMC41NiwwLjAxLTEuNDItMC4wMi0xLjYyLDAuMjljLTAuNzQsMS4xNi0xLjgsMC44NC0yLjc4LDAuODRjLTIuNzgsMC4wMi01LjU2LDAuMDEtOC4zNCwwLjAxIGMtMi42NCwwLTUuMjcsMC4wNi03LjktMC4wMWMtMS4xNS0wLjAzLTIuMDgsMC41NS0yLjMzLDEuMzljLTAuNywyLjQsMC4yNyw1LjU2LDMuNTksNS42M2MxLjIsMC4wMiwyLjc3LTAuMzgsMy41MSwwLjIyIGMxLjQsMS4xNSwyLjg0LDAuNzUsNC4yOCwwLjk1YzEuOTcsMC4yNywzLjkzLDAuNTcsNS45LDAuODljMC4xNywwLjAzLDAuMywwLjMsMC40NiwwLjQ1YzAuOTEsMC44MiwxLjc2LDEuNzEsMy4yMSwxLjQ3IGMwLjQ5LTAuMDksMS4wNywwLjE2LDEuNTcsMC4zNWMwLjUxLDAuMTksMC45NSwwLjY2LDEuNDUsMC43M2MzLjIsMC40Myw2LjQsMC43OCw5LjY5LDEuMTZjMC4wNCwwLjE3LDAuMTMsMC4zOSwwLjE0LDAuNjIgYzAuMDMsMS44MiwwLjAzLDMuNjUsMC4wNiw1LjQ3YzAuMDEsMC43Ni0wLjEsMS41NywwLjExLDIuMjhjMC41LDEuNjQsMC4xMiwyLjI4LTEuNjEsMi4yOGMtNC4xMiwwLTguMjQtMC4wMS0xMi4zNiwwLjAyIGMtMC43LDAuMDEtMS43NywwLTIuMDIsMC40Yy0wLjU5LDAuOTYtMS4zNiwwLjctMi4xMSwwLjczYy0xLjgxLDAuMDctMy42NCwwLjA0LTUuNDQsMC4xOWMtMS4xMywwLjEtMi4yMywwLjY0LTMuMzUsMC42NCBjLTguNjcsMC4wNi0xNy4zNSwwLjAzLTI2LjAyLDAuMDVjLTAuNjYsMC0xLjcxLTAuMDQtMS44OSwwLjNjLTAuNTUsMS4wMy0xLjM4LDAuNzktMi4xOCwwLjg4Yy0xLjMxLDAuMTctMi4wNywxLTIuMTIsMi4yOSBjLTAuMSwyLjcxLDEuMzgsNC40Miw0LjA1LDQuNjRjMC42NiwwLjA2LDEuMzQsMC4wNiwyLjAxLDAuMDZjMTEuNTksMCwyMy4xOS0wLjA0LDM0Ljc5LDAuMDRjMi4xMSwwLjAxLDQuMjMsMC41Myw2LjM0LDAuODQgYzAuMTYsMC4wMiwwLjMsMC4xNywwLjQ2LDAuMjZjMC40NiwwLjI0LDAuOSwwLjYxLDEuMzgsMC43YzIuMDUsMC4zOCw0LjEyLDAuNjgsNi4xOCwxLjAyYzAuMTcsMC4wMiwwLjMyLDAuMTQsMC40OSwwLjIyIGMwLjU5LDAuMjcsMS4xNiwwLjcxLDEuNzcsMC43N2MxLjc4LDAuMTgsMi4yNiwwLjU1LDIuMTgsMi4zOWMtMC4xMywyLjg5LDAuMyw1Ljc5LTAuNTYsOC42OWMtMC41NCwxLjgyLDAuNDQsNC4wMi0xLjI4LDUuNjEgYy0xLjA3LDAuOTktMS4wMywyLjcyLTIuNDUsMy41MmMtMC42LDAuMzMtMS4xMSwwLjk0LTEuNDksMS41M2MtMC44NCwxLjMxLTEuNTIsMi43Mi0yLjM3LDQuMDJjLTAuMzksMC41OS0xLjA4LDAuOTctMS41MywxLjUzIGMtMC44MiwxLjA1LTEuNzcsMi4wNy0yLjI5LDMuMjdjLTAuNzMsMS43LDAuNzIsMy42LDIuNTYsMy42MWMxLjIsMCwyLjM5LTAuMDcsMy41OS0wLjE0YzAuMjgtMC4wMSwwLjc2LTAuMDYsMC43OS0wLjE4IGMwLjM3LTEuNDgsMS45LTEuMjIsMi43OS0xLjZjMS40Ny0wLjYzLDIuOTEtMS4yLDQuMTgtMi4yYzAuNi0wLjQ3LDEuNTYtMC42NSwxLjkxLTEuMjRjMC42NS0xLjEsMC45OC0yLjM5LDEuNDQtMy42IGMwLjE3LTAuNDMsMC4zNy0wLjg0LDAuNS0xLjI4YzAuNC0xLjQxLDAuODItMi44MSwxLjE0LTQuMjRjMC4xNS0wLjY5LDAuMjItMS40NiwwLjA4LTIuMTRjLTAuMjgtMS4zNiwwLjkzLTEuNzIsMS40NC0yLjU1IGMwLjg0LTEuMzgsMS41My0xLjMzLDIuMzYtMC4wOGMwLjA0LDAuMDYsMC4xOCwwLjA5LDAuMjcsMC4wOWg1LjEyYy0wLjI3LTIuMjcsMC41NC00LjItMC45NC02LjM5Yy0xLjE4LTEuNzItMi4zNS0zLjk1LTIuMjUtNi4zNyBjMC4wMi0wLjI4LTAuMDctMC41Ny0wLjEzLTAuODVjLTAuMzEtMS4zNi0wLjYyLTIuNzItMC45OC00LjMzYzQuNSwwLDguNDMtMC4wMSwxMi4zNSwwLjAyYzAuMjcsMCwwLjU5LDAuMjQsMC43OCwwLjQ2IGMwLjgyLDAuOTYsMS43NSwxLjQ0LDMuMDksMS40YzIuNzMtMC4wOCw1LjQ2LDAuMDYsOC4xOSwwLjA2YzE0LjI0LDAuMDEsMjguNDcsMCw0Mi43LDBjMC42NywwLDEuMzUsMC4wMiwyLjAxLTAuMDcgYzAuMzItMC4wNSwwLjc1LTAuMjgsMC44OC0wLjU1YzAuNjktMS4zOCwxLjI0LTIuNzgsMS4wNy00LjQyYy0wLjIyLTItMC45MS0yLjc5LTIuOTEtMi44MWMtMi41OS0wLjAzLTUuMTcsMC03Ljc2LTAuMDMgYy0wLjQsMC0wLjgyLTAuMDktMS4yMS0wLjIyYy0wLjc5LTAuMjgtMS41Ni0wLjg2LTIuMzUtMC44N2MtNC4wOC0wLjEtOC4xNS0wLjA1LTEyLjIyLTAuMDZjLTAuMzksMC0wLjkxLDAuMTQtMS4xMy0wLjA1IGMtMS40OS0xLjMtMy4yNy0wLjYzLTQuOTItMC44MmMtMS40Mi0wLjE2LTMuMDMsMC41OS00LjE3LTAuOTNjLTAuMTctMC4yMi0wLjcyLTAuMTgtMS4xLTAuMThjLTEuMjktMC4wMy0yLjU4LTAuMDItMy44Ni0wLjAzIGMtMC42MywwLTEuNDksMC4yMy0xLjgzLTAuMDljLTEuNDktMS40MS0zLjU4LTAuNDMtNS4yOS0xLjYyYy0xLjQ3LTEuMDMtMy43OS0wLjEzLTUuNzEtMS4wNWMtMS4yNi0wLjYtMi44NywwLjEtNC4yOS0xLjA3IGMtMS42NC0xLjM1LTMuOS0xLjEyLTUuOTgtMS4wN2MtMS4xNywwLjAyLTEuOTYtMC43OC0yLjAxLTEuOTZjLTAuMDItMC42MSwwLTEuMjIsMC0xLjkzYzAuNy0wLjA0LDEuMjctMC4wNSwxLjgzLTAuMTIgYzAuMzEtMC4wNCwwLjYyLTAuMTYsMC45LTAuM2MwLjQ4LTAuMjQsMC45My0wLjczLDEuNDItMC43OGMzLjY2LTAuMzIsNy4zMy0wLjU2LDEwLjk5LTAuODJjMC4wNS0wLjAxLDAuMS0wLjAxLDAuMTUtMC4wMSBjMS4xNy0wLjEyLDIuNDEtMS4xOSwyLjUxLTIuMzVjMC4xLTEuMjMsMC4wMi0yLjQ3LDAuMDItMy43Yy0xLjczLTAuMzYtMy4zLTAuOS00LjktMC45OGMtMy4wMS0wLjEzLTYuMDMsMC05LjA1LDAuMDMgYy0wLjQzLDAtMC45OS0wLjA2LTEuMjUsMC4xN2MtMS4wNywwLjk1LTIuMzIsMC41OS0zLjUxLDAuNjZjLTEuNTcsMC4wOC0yLjYyLTAuOTctMi45Ny0yLjE2Yy0wLjM0LTEuMTgtMC4xOS0yLjY3LDAuMjQtMy44NSBjMC40MS0xLjEzLDMuMjEtMS4yLDQuNDItMC40NGMwLjk3LDAuNjEsMi4wMSwxLjE2LDMuMDksMS41MmMwLjc5LDAuMjYsMS43LDAuMjEsMi41NiwwLjIyYzIuNDIsMC4wNSwzLjI4LTAuNzksMy4zMi0zLjIxIGMwLjAyLTEuMTUsMC4xMS0yLjMxLTAuMDItMy40NWMtMC4xMS0wLjk0LTAuNDktMS44NS0wLjc3LTIuNzdjLTAuMzUtMS4xLTAuNzItMi4xOC0xLjE0LTMuNDVjMC42OS0wLjA1LDAuOTYtMC4wOSwxLjI0LTAuMDkgYzQuMzEtMC4wOCw4LjYyLTAuMTQsMTIuOTMtMC4yM2MwLjUxLTAuMDEsMS4wMy0wLjEyLDEuNTItMC4yNmMwLjY4LTAuMTksMS4zMy0wLjY2LDEuOTktMC42N2M2Ljg1LTAuMDUsMTMuNzEtMC4wMiwyMC41Ni0wLjA0IGMwLjcxLDAsMS42MSwwLjEzLDIuMS0wLjIzYzEuMTgtMC44NywyLjQ0LTAuNTYsMy42Ny0wLjYyYzEuMjktMC4wNSwyLjYsMC4wNSwzLjg3LTAuMTNjMC43Ni0wLjExLDEuNDItMC44MywyLjE4LTAuOTMgYzIuMzEtMC4zLDQuNjQsMC4wNCw2Ljk4LTAuNzhjMS4zNi0wLjQ4LDEuODktMC45MiwxLjg5LTIuMjFjLTAuMDEtMS4wNSwwLTIuMDksMC0zLjA3Yy0xLjk4LTAuNC0zLjc0LTAuODItNS41Mi0xLjA3IGMtMS4wMy0wLjE1LTIuMS0wLjAyLTMuMTUtMC4wNGMtMC4zMywwLTAuODcsMC4wNC0wLjk1LTAuMTNjLTAuNjgtMS4yOC0xLjg4LTAuOTMtMi45LTAuOTRjLTQuMzYtMC4wNS04LjcyLTAuMDItMTMuMDgtMC4wMyBjLTAuNDIsMC0wLjg0LTAuMDYtMS4yNS0wLjE2Yy0wLjg1LTAuMjEtMS42OS0wLjY1LTIuNTMtMC42NmMtMy43NC0wLjA4LTcuNDgtMC4wNC0xMS4yMi0wLjA3Yy0wLjM5LDAtMC44MS0wLjExLTEuMTktMC4yNSBjLTAuNjUtMC4yNi0xLjI3LTAuNzYtMS45My0wLjgyYy0xLjY2MS0wLjE1MS0zLjMzNS0wLjAxOS01LjAwNy0wLjA3M2MtMC42MjktMC4wMjEtMS42MzgtMC4yMDQtMi4yNDMtMC4zNzUgYy0wLjY2LTAuMTg2LTEuMzIxLTAuMzc2LTEuOTktMC40MzJjLTEuNTctMC4xMy0zLjE2LTAuMDItNC43NC0wLjA1Yy0wLjM2LDAtMC43My0wLjEtMS4wNi0wLjIyYy0wLjc1LTAuMjgtMS40Ni0wLjgzLTIuMjEtMC44NyBjLTIuMjktMC4xMi00LjYyLDAuMTMtNi44OS0wLjEzYy0xLTAuMTEtMi4zNC0wLjktMi43My0xLjc0Yy0wLjQtMC44Ny0wLjEzLTIuMzcsMC40LTMuMjdjMC42NDEtMS4wOTUsMS44MzctMS44NzgsMi43OTEtMi44MDIgYzAuMTc2LTAuMTcsMC4zMTQtMC4zNzcsMC40MDYtMC42MDRjMC40MTgtMS4wMzQsMC42OTItMi4wOSwxLjg4My0yLjY0NGMwLjQ5LTAuMjIsMC43My0wLjk2LDEuMDktMS40NiBjMC41OC0wLjgsMS4wMS0xLjgzLDEuNzktMi4zNGMxLjM0LTAuODYsMi43LTEuOCw0LjM5LTIuMDVjMC45NC0wLjE0LDIuMTktMC40MSwyLjY1LTEuMDdjMC44My0xLjIxLDIuMTYtMC45OCwzLjE2LTEuNjMgYzEuNDUtMC45NCwzLjEtMS41Nyw0LjY1LTIuMzljMC4yLTAuMSwwLjM2LTAuNDgsMC4zNy0wLjczYzAuMDMtMS42NiwwLjAyLTMuMzIsMC4wMi01LjFjLTEuOTMsMC0zLjczLTAuMi01LjQ2LDAuMDUgYy0xLjc3LDAuMjYtMy41NCwwLjgyLTUuMTksMS41M2MtMC45NSwwLjQxLTEuNTUsMC40Ni0yLjUyLDAuMDFjLTEuNjctMC43Ni0zLjIxLTIuMDktNS4zMS0xLjYyYy0wLjc3LDAuMTctMS42MiwwLjA1LTIuNDMsMC4wMiBjLTEuMzEtMC4wMy0yLjAxLTAuNzctMi4wNC0yLjA3Yy0wLjAzLTEuMSwwLjI0LTIuMzktMC4yNC0zLjI2Yy0wLjgyLTEuNDctMC41LTIuOTMtMC41Ny00LjRjLTAuMDctMS4zNSwwLjU3LTEuOTQsMS45My0xLjk2IGMxLjgxLTAuMDQsMy42NSwwLjAzLDUuNDUtMC4xNmMxLjQ1LTAuMTUsMi44NS0wLjc4LDQuMy0wLjkxYzIuMS0wLjIsNC4yMS0wLjA5LDYuMzItMC4xOWM1LjY0LTAuMjcsMTEuMjctMC41OCwxNi45MS0wLjg5IGMwLjI5LTAuMDEsMC41OS0wLjE4LDAuODctMC4zMWMwLjQ2LTAuMjIsMC45LTAuNjYsMS4zNi0wLjY4YzIuODctMC4xMiw1Ljc0LTAuMTgsOC42MS0wLjIxYzEuODYtMC4wMSwzLjQ5LTAuNDYsNC43Mi0xLjk4IGMwLjczLTAuOTEsMC4zMy0zLjQtMC41LTMuOTVjLTEuNTQtMS4wMi0zLjIxLTAuODctNC44OS0wLjkxYy0wLjQtMC4wMS0wLjgxLTAuMTEtMS4xOS0wLjI1Yy0wLjc2LTAuMjctMS40OC0wLjgzLTIuMjMtMC44NSBjLTMuMjE0LTAuMTAyLTYuNDI4LTAuMDM4LTkuNjQyLTAuMDYxYy0wLjM1NC0wLjAwMy0wLjcxMS0wLjAyOS0xLjA1My0wLjEyMmMtMC44NTktMC4yMzQtMS42ODMtMC42My0yLjU0NC0wLjY5NyBjLTEuNDgtMC4xMi0yLjk3LTAuMDEtNC40Ni0wLjA0Yy0wLjM1LDAtMC43Mi0wLjEtMS4wNS0wLjIzYy0wLjctMC4yOC0xLjM2LTAuNzktMi4wNy0wLjg3Yy0xLjM3LTAuMTQtMi43OCwwLjA1LTQuMTYtMC4wNiBjLTQuMzYtMC4zNi04Ljc4LDAuNzQtMTMuMTQtMC43MmMtMS4wMS0wLjM0LTEuODgtMC44NC0yLjctMS4zNWMtMC41MS0wLjMxLTAuODUtMS40MS0wLjczLTIuMDZjMC4xLTAuNTUsMC45LTEuMjQsMS41MS0xLjM4IGMxLjY5LTAuMzksMy41MiwwLjIzLDUuMTEtMS4yYzAuNjgtMC42LDEuNzMtMC43OSwyLjAzLTEuODdjMC40Ni0xLjU5LDAuMDMtMy4yLTEuMDItNC4xNWMtMS4xNS0xLjA1LTIuOC0xLjU3LTQuMy0yLjE3IGMtMC45NS0wLjM3LTEuNDktMC44NC0xLjQ4LTEuODljMC4wMy0xLjU4LDAuMDItMy4xNy0wLjAxLTQuNzVjLTAuMDEtMC41NywwLjA4LTEuNDItMC4yNC0xLjY1Yy0xLjM0LTAuOTctMS4wMy0yLjM1LTEuMDMtMy42IGMtMC4wMy0xMi41Ny0wLjItMjUuMTQsMC4wOS0zNy43YzAuMDktNC4wNS0wLjk0LTguMiwwLjkzLTEyLjI3YzAuOTMtMi4wMiwwLjcxLTQuNTgsMS4wMy02Ljg5YzAuMTYtMS4yNC0wLjQ3LTIuNjksMS0zLjYgYzAuMTQtMC4wOSwwLjA5LTAuNTQsMC4wOS0wLjgzYzAtNC4xMiwwLjAxLTguMjUtMC4wMi0xMi4zN2MwLTAuNDEtMC4xNi0wLjgyLTAuMjktMS4yMmMtMC4xOS0wLjU5LTAuNTQtMS4xNi0wLjYtMS43NyBjLTAuMzYtMy40NS0wLjY1LTYuOS0wLjk4LTEwLjM1Yy0wLjAzLTAuMzEtMC4yNC0wLjYtMC4zOC0wLjg5Yy0wLjIyLTAuNTEtMC41OC0xLTAuNjYtMS41M2MtMC4yNC0xLjY5LDAuNDctMy41MS0wLjgxLTUuMDcgYy0wLjE5LTAuMjMtMC4xOS0wLjg5LDAtMS4xYzEuMTMtMS4yMSwwLjY2LTIuNjksMC44MS00LjA3YzAuMDMtMC4zMy0wLjAxLTAuODUsMC4xNy0wLjk0YzEuMTgtMC42MSwwLjc4LTEuNzEsMC45LTIuNjQgYzAuMzEtMi40MSwwLjYtNC44MiwwLjkyLTcuMjNjMC4wMi0wLjE3LDAuMTYtMC4zMiwwLjI0LTAuNDhjMC4yOC0wLjY0LDAuNTYtMS4yOCwwLjg1LTEuOTFjMC4zMi0wLjcsMC41OS0xLjkzLDEtMS45OCBjMS42My0wLjE5LDIuNDMtMS40MiwzLjQzLTIuMzVjMS4xMS0xLjAyLDEuOTktMi4yOSwzLjM0LTMuODhjMS44OC0wLjI3LDQuNDMtMC42Miw2Ljk3LTAuOTljMC4yNDQtMC4wMzUsMC42MzQtMC4xMjcsMC44NjQtMC4yMTQgYzEuNDQxLTAuNTQ2LDIuODY1LTEuMzk5LDQuMzI2LTEuNDg2YzIuNDItMC4xNiwzLjg4LTEuNCw1LjEtMy4yMWMwLjQyLTAuNjMsMC43NC0xLjMyLDEuMTQtMS45NWMwLjczLTEuMTMsMC40Ni0yLjQ1LTAuNy0zLjEzIGMtMS4wNi0wLjY0LTIuMTQtMS4yNi0zLjIyLTEuODZjLTAuNzktMC40My0xLjY2LTAuNzItMi4zOS0xLjIzYy0xLjIzNS0wLjg3LTIuMzg4LTEuODc0LTMuNTkzLTIuODE0IGMtMC40OTctMC4zODgtMS4zNzEtMC45MzQtMS45MzMtMS4yMjFjLTAuOTcxLTAuNDk3LTEuOTUyLTAuOTc0LTIuOTM0LTEuNDY1Yy0xLTAuNS0yLjAyLTAuOTctMy4wMS0xLjUgYy0xLjYtMC44NC0zLjIxLTEuNjctNC43NS0yLjZjLTAuMzctMC4yMy0wLjcxLTAuODQtMC43Mi0xLjI5Yy0wLjEyLTQuNDUtMC4xNC04LjkxLTAuMjQtMTMuMzdjLTAuMDEtMC42My0wLjI0LTEuMjctMC40Ny0xLjg3IGMtMC40LTEuMDQtMS4wMS0yLjAxLTEuMjctMy4wN2MtMC40MS0xLjYyLTAuNTItMy4zMi0wLjktNC45NWMtMC4xOS0wLjgtMS4wMy0xLjUyLTEuMDQtMi4yOGMtMC4wMy0yLjU5LTEuNS00Ljk1LTEuMDUtNy42MiBjMC4yMy0xLjM1LDAuMDctMi43OCwwLjAxLTQuMTdjLTAuMDItMC40OS0wLjIyLTAuOTktMC40MS0xLjQ2Yy0wLjE4LTAuNDctMC42My0wLjkxLTAuNjQtMS4zN2MtMC4xLTUuODktMC4xOS0xMS43OS0wLjItMTcuNjkgYy0wLjAxLTQzLjM2LTAuMDEtODYuNzIsMC4wMS0xMzAuMDljMC0zLjU5LDAuMS03LjE5LDAuMTgtMTAuNzhjMC0wLjM1LDAuMTMtMC43MiwwLjI4LTEuMDRjMC4yMy0wLjUyLDAuNjktMC45OCwwLjc1LTEuNTEgYzAuMTQtMS4xMy0wLjAxLTIuMzEsMC4xNS0zLjQ0YzAuMjEtMS40MSwwLjI0LTMuMDYsMS4wMS00LjEyYzEuMjMtMS42OSwwLjkzLTMuNjYsMS42LTUuNDRjMC44Ni0yLjI2LTAuNTQtNC45MywxLjE0LTcuMjkgYzEuMTUtMS42MiwxLjc0LTMuNjUsMi41Ni01LjVjMC4yNy0wLjU5LDAuNDEtMS4yNCwwLjcyLTEuODFjMC41NC0xLjAyLDEuMTktMS45OCwxLjc1LTIuOTljMC41OC0xLjA0LDEuMTQtMi4wOSwxLjYzLTMuMTcgYzAuNjctMS41MiwyLjIyLTEuODgsMy40My0yLjY2YzAuOTItMC41OSwyLjAzLTAuODksMy4wNC0xLjM2YzEuNTEtMC42OSwzLjAyLTEuMzgsNC41LTIuMTJjMC41LTAuMjYsMS4xOC0wLjU5LDEuMzMtMS4wNCBjMC40Ni0xLjQsMC43OS0yLjg1LDEuMDItNC4zMWMwLjEzLTAuODItMC40LTEuMzktMS4yNy0xLjM5Yy0zLjI2LDAtNi41MSwwLjAzLTkuNzcsMC4wNmMtMC4yNCwwLTAuNTEsMC0wLjcsMC4xMSBjLTIuMjksMS4yOS00LjcsMC4yNi03LjA2LDAuNjZjLTAuMDUtMC41My0wLjEtMC44MS0wLjEtMS4xYzAtOC41MywwLjEzLTE3LjA4LTAuMDQtMjUuNjFjLTAuMTgtOC40OSwwLjg2LTE3LjAyLTAuODQtMjUuNDYgYy0wLjE3LTAuODctMC4yNi0xLjc1LTAuNDgtMi42MWMtMC4xMy0wLjUzLTAuNTYtMC45OS0wLjYzLTEuNTFjLTAuMTYtMS4yOCwwLjExLTIuNjktMC4zMy0zLjgzYy0wLjkzLTIuMzctMC4zNS0zLjg3LDIuMDgtNC42MSBjMS40Ny0wLjQ0LDIuMDktMi40MiwzLjk0LTIuMjdjMC4wMywwLDAuMDYtMC4xNywwLjEzLTAuMjNjMC44NS0wLjg2LDEuNTgtMi4xMiwyLjYxLTIuNDdjMS42NS0wLjU1LDIuNDQtMS45NiwzLjcyLTIuODQgYzAuOTgtMC42NywxLjg2LTEuNSwyLjgyLTIuMmMwLjYyLTAuNDYsMS4zMS0wLjgxLDEuOTYtMS4yM2MwLjY2LTAuNDIsMS4zMS0wLjg2LDEuOTUtMS4zMWMwLjI3LTAuMiwwLjQ5LTAuNDYsMC43Ni0wLjY3IGMwLjgtMC42MywxLjY1LTEuMiwyLjQtMS44OGMxLjA4LTAuOTcsMi4wNS0yLjA1LDMuMTMtMy4wM2MxLjIxLTEuMSwyLjc3LTEuOTQsMy42NC0zLjI1YzEuMjUtMS44NywyLjUzLTMuNjQsNC4xMy01LjI0IGMxLjQ3LTEuNDcsMi44OC0zLjA4LDMuOTctNC44NGMwLjcyLTEuMTgsMi4zNy0xLjY1LDIuNC0zLjI5YzAtMC4wNiwwLjE0LTAuMTQsMC4yMi0wLjE2YzEuMzItMC4zNSwyLjYxLTAuODQsMy45NS0xIGMxLjM2LTAuMTYsMi45My0wLjM5LDMuOTMsMC44NWMxLjIsMS41MSwyLjc2LDAuOTcsNC4yMiwxLjA1YzAuOTYsMC4wNiwxLjkzLDAuMTUsMi44OCwwLjA0YzIuMjktMC4yNyw0LjE4LDAuNjksNi4wNiwxLjc4IGMwLjY4LDAuNCwxLjQsMC43NSwyLjA5LDEuMTNjMC45MiwwLjUxLDEuODMsMS4wMywyLjg1LDEuNmMwLTAuMDEsMC4wNy0wLjE3LDAuMTktMC4yN2MwLjk3LTAuODYsMi40NS0xLjU0LDIuNzktMi42IEMyMjAuNDExLDE2MS4zNywyMjAuNTYxLDE1OS4zOCwyMjAuMDQxLDE1Ny44NXogTTExMS40MzcsMTkyLjQyYy00My45NiwwLTgwLjA2LTMzLjYzLTgzLjk2LTc2LjU3Yy0wLjI3LTAuNzItMC4zLTEuNTMtMC4xOC0yLjQgYy0wLjEyLTEuNzctMC4xOC0zLjU1LTAuMTgtNS4zNWMwLTQ2LjU2LDM3Ljc1LTg0LjMxLDg0LjMyLTg0LjMxYzQ2LjU2LDAsODQuMzEsMzcuNzUsODQuMzEsODQuMzEgQzE5NS43NDcsMTU0LjY3LDE1Ny45OTcsMTkyLjQyLDExMS40MzcsMTkyLjQyelwiLFxuICAgICAgICAgICAgXCJNMjMwLjA3MSwxMjguNjRjLTAuMTUtMS4wOC0wLjctMi4wNC0yLjA4LTIuMDRjLTAuMjgsMC0wLjU3LTAuMjUtMC44NC0wLjM5IGMtMC40Ny0wLjI1LTAuOTItMC42MS0xLjQyLTAuNzNjLTEuNDUtMC4zNi0yLjkzLTAuNjEtNC4zOS0wLjkyYy0wLjEyLTAuMDMtMC4yMi0wLjE4LTAuMzQtMC4yM2MtMC42OS0wLjMxLTEuMzctMC42Ny0yLjA5LTAuODkgYy0wLjUtMC4xNS0xLjA5LDAuMDEtMS41OC0wLjE1Yy0xLjU5LTAuNDktMy4xMi0xLjIxLTQuNzMtMS41NmMtMC44NC0wLjE4LTEuNTYtMC4yNS0xLjktMS4xYy0wLjI2LTAuNjQtMC40NC0xLjMtMC41OC0xLjcxIGMtMC43Mi0wLjYxLTEuNjYtMS0xLjgxLTEuNTljLTAuNDctMS45Ny0wLjg0LTQtMC45Mi02LjAxYy0wLjE3LTQuMzgtMC4xMy04Ljc2LTAuMTktMTMuMTRjMC0wLjM5LDAuMDgtMC45OC0wLjEyLTEuMTMgYy0xLjUyLTEuMTEtMC44OC0yLjcyLTEuMDUtNC4xM2MtMC4wOS0wLjcyLTAuMDQtMS40Ny0wLjI0LTIuMTZjLTAuNTItMS44MS0xLjI0LTMuNTgtMS42OC01LjQxYy0wLjQ3LTEuOTktMC43MS00LjAzLTEuMDUtNi4wNSBjLTAuMDItMC4xNS0wLjAzLTAuMzUtMC4xMi0wLjQxYy0xLjUxLTAuOTgtMS4yOC0yLjgyLTEuNTMtNC4xMmMtMC40NC0yLjMyLTEuOTctNC4wMi0yLjYxLTYuMTZjLTAuNC0xLjM0LTEuMTctMi41Ny0xLjcxLTMuODcgYy0wLjY4LTEuNjItMS4xOC0zLjMyLTEuOTktNC44NmMtMC44MS0xLjU0LTIuMDgtMi44NS0yLjg0LTQuNDJjLTAuNjYtMS4zNS0wLjg1LTIuOTQtMi4wNS00LjA0Yy0wLjEtMC4wOS0wLjA1LTAuNTEsMC4wNy0wLjY2IGMwLjU2LTAuNjYsMS4wNS0xLjUsMS43OC0xLjg4YzEuMy0wLjY4LDEuMy0xLjc2LDEuMzEtMi45MWMwLjAxLTEuMTctMC4wNC0yLjM0LDAuMDEtMy41MWMwLjA3LTEuNDgtMC42Mi0yLjA2LTIuMDctMi4wNCBjLTMuMjYsMC4wNC02LjUyLDAuMDYtOS43OC0wLjAxYy0wLjctMC4wMi0xLjQ2LTAuMzMtMi4wNS0wLjcyYy0xLjEtMC43Mi0yLjEyLTEuNTYtMy4xMy0yLjRjLTAuNTQtMC40NS0wLjk2LTEuMDMtMS40OC0xLjUgYy0wLjQzLTAuMzktMC45OS0wLjY1LTEuNC0xLjA2Yy0xLjEtMS4wOC0yLjg1LTEuMjctMy42NC0yLjhjLTAuMjYtMC41MS0wLjgtMC45My0xLjMxLTEuMjZjLTEuOTA0LTEuMjQxLTMuOTkyLTIuMjQyLTUuNzExLTMuNzEyIGMtMC44ODEtMC43NTQtMS44OS0xLjMzNS0yLjg2LTEuOTdjLTAuNjA3LTAuMzk3LTEuMDU0LTEuMTExLTEuNjk5LTEuMzQ4Yy0yLjItMC44LTMuMjgtMi45MS01LjA5LTQuMTUgYy0xLjMzLTAuOTItMS44NC0yLjcyLTMuNzQtMy4xMWMtMC44My0wLjE4LTEuODgtMS4wOS0yLjE0LTEuODljLTAuODgtMi43MS0yLjE0LTUuMzctMS44NC04LjM2YzAuMDUtMC40OCwwLjAxLTAuOTYsMC4wMS0xLjM0IGMtMS4yNS0xLjA5LTIuMzgtMC45Ny0zLjM2LDAuMWMtMC44OSwwLjk3LTEuNTcsMi4xNS0yLjU0LDMuMDJjLTEuNDMsMS4yOS0yLjk3LDIuNTEtNC42MSwzLjUyYy0wLjY5LDAuNDItMS4zOCwwLjY3LTIuMDIsMS4zMSBjLTAuOSwwLjg5LTIuMiwxLjY0LTMuNDMsMS44NWMtMS44LDAuMy0zLjY5LDAuMDctNS41MywwLjA1Yy0wLjE4LDAtMC40OC0wLjA3LTAuNTMtMC4xOGMtMC40Ny0xLjE0LTEuNDctMC45My0yLjM2LTAuOTQgYy02LjU2LTAuMDEtMTMuMTQtMC4wNC0xOS43LDAuMDRjLTEuNTQsMC4wMi0zLjA0LTAuMjUtNC41OCwwLjk3Yy0xLjE0LDAuOS0zLjE0LDAuNzMtNC43NiwxLjAyYy0yLjA5LDAuMzYtNC4xOSwwLjY5LTYuMjksMS4wNyBjLTAuMTksMC4wMy0wLjMzLDAuMjgtMC41MywwLjM5Yy0wLjM3LDAuMjItMC43NCwwLjU0LTEuMTQsMC41OWMtMi4xOSwwLjI5LTQuMjYsMC43MS02LjIzLDEuOTRjLTEuNTMsMC45Ni0zLjQ0LDEuNjgtNS4yMiwxLjc3IGMtMS43NSwwLjA5LTIuNjcsMS40MS00LjE0LDEuODJjLTEuNTUsMC40Mi0yLjk5LDAuNjUtNC40OC0wLjFjLTAuODEtMC40MDUtMS42MjYtMC44MTYtMi40NTItMS4yMDEgYy0wLjY4LTAuMzE3LTEuODM1LTAuNzM1LTIuNTU4LTAuOTM0Yy0xLjU0LTAuNDI1LTMuMTA2LTAuNzk2LTQuNjYtMS4yMjVjLTAuMzYtMC4xLTAuNzUtMC4yOC0xLTAuNTQgYy0xLjEzLTEuMjItMy45Ny0xLjk1LTUuNTMtMS4zNWMtMC4xNywwLjA2LTAuNDQsMC4yMS0wLjQzLDAuMzFjMC4wMiwxLjY5LTAuNDQsMy42OSwwLjMxLDQuOTZjMC42MiwxLjA1LDAuNjcsMS45MywwLjg1LDIuOTQgYzAuMywxLjcxLDAuNjUsMy40LDAuOTksNS4xYzAuMDMsMC4xMywwLjExLDAuMzEsMC4yMiwwLjM2YzEuMjEsMC41MiwwLjY4LDEuMzUsMC40OCwyLjIxYy0yLjY1LDAtNS4yMywwLTcuOC0wLjAxIGMtMC4yNCwwLTAuNTksMC4wMS0wLjY5LTAuMTNjLTEuMjUtMS42Ni0zLjAyLTAuOTctNC41My0wLjgzYy0wLjY3LDAuMDctMS41NiwxLjA5LTEuNzksMS44NmMtMC4zLDAuOTctMC4wNywyLjExLDAuMDIsMy4xOCBjMC4wMywwLjMsMC4zMiwwLjY4LDAuNiwwLjg1YzAuNzksMC40OSwxLjYzLDAuODgsMi40MSwxLjI5YzAsMS42MS0wLjI1LDMuMTgsMC4wNiw0LjYxYzAuNDQsMS45OC0wLjc5LDMuMy0xLjQxLDQuODQgYy0wLjM3LDAuOTEtMS4xMiwxLjY4LTEuNzQsMi40OGMtMC42NSwwLjg2LTEuNDcsMS42Mi0xLjk3LDIuNTZjLTEuMDU2LDEuOTYxLTIuMTIzLDMuODc1LTMuNjY1LDUuNTE4IGMtMC4wNDUsMC4wNDgtMC4wODUsMC4xMDMtMC4xMTUsMC4xNjJjLTAuNjIsMS4yLTEuMjYsMi4zOC0xLjgxLDMuNjFjLTAuNTIsMS4xNS0wLjY1LDIuNDEtMS41MSwzLjVjLTAuOCwxLTEuMDksMi40MS0xLjYzLDMuNjMgYy0wLjQsMC45MS0wLjg5LDEuNzktMS4yMywyLjczYy0wLjY1LDEuNzctMC41MywzLjc0LTEuOTEsNS4zNmMtMC45NiwxLjEyLTEuMzEsMi43NS0yLjAzLDQuMWMtMC43NCwxLjM3LTEuNjksMi40NS0zLjQ5LDIuNSBjLTEuODYsMC4wNC0zLjM3LDEuOTItMy42LDMuNzdjLTAuNDQsMy42MiwyLjQ5LDUuMTYsNC4zMyw3LjM4YzAuMjksMC4zNiwwLjczLDAuNzcsMC43NCwxLjE3YzAuMDYsMS45NSwwLDMuOS0wLjA0LDUuODQgYzAsMC4yNy0wLjE2LDAuNTMtMC4yNywwLjc5Yy0wLjIyLDAuNTgtMC42MiwxLjE0LTAuNjYsMS43M2MtMC4xLDEuMzEtMC4wNSwyLjYzLTAuMDIsMy45NGMwLDAuMzgsMC4wNywwLjc3LDAuMTksMS4xMyBjMC4yNywwLjc3LDAuNzgsMS41MSwwLjg0LDIuMjljMC4xNSwxLjc5LDAuMDgsMy42LDAuMTEsNS40YzAuMDEsMC43OC0wLjI4LDEuNzksMC4xLDIuMjljMS40MiwxLjkxLDAuMTIsNC40NCwxLjcyLDYuMzYgYzAuNzIsMC44NiwwLjY0LDIuNDEsMC45LDMuNjVjMC41LDIuMzUsMS4xOCw0LjY2LDEuODMsNi45NmMwLjY4LDIuNDEsMi41MSw0LjM2LDIuNTIsNy4wMmMwLDAuODEsMC45MSwxLjU5LDEuMzIsMi40MyBjMC41MiwxLjA3LDAuOTUsMi4xOSwxLjQzLDMuMjhjMC4xMSwwLjI0LDAuMjgsMC40NSwwLjQxLDAuNjhjMC41NiwxLDEuMTIsMS45OSwxLjY3LDIuOTljMC4zMiwwLjU5LDAuNDgsMS41LDAuOTgsMS43NSBjMS4zOSwwLjY5LDEuMDcsMi4yMiwxLjgzLDMuMThjMC40NywwLjYsMC44MiwxLjI5LDEuMjUsMS45MmMwLjI2LDAuMzcsMC41NiwwLjcxLDAuODMsMS4wOGMwLjUyLDAuNzIsMS4wOSwxLjQxLDEuNTQsMi4xNyBjMC41MiwwLjg5LDEuNDcsMi4wMiwxLjI0LDIuNzFjLTAuMzEsMC45MS0xLjUsMS42My0yLjQ2LDIuMThjLTEuNTksMC45LTMuMjksMS42LTQuOTQsMi4zOGMtMC40NSwwLjIxLTAuOSwwLjQxLTEuMzUsMC42MyBjLTAuOTUsMC40Ny0xLjkyLDAuOTItMi44NSwxLjQ1Yy0wLjcxLDAuNDItMS4zNSwwLjk4LTIuMDUsMS40MmMtMC45OSwwLjYzLTIuMDYsMS4xNC0zLDEuODJjLTAuODEsMC41OC0xLjQ2LDEuMzktMi4yNywxLjk4IGMtMC41MywwLjQtMS40MSwwLjQzLTEuODEsMC45Yy0wLjg3LDEuMDQtMS43OCwyLTIuNDMsMy4zMWMtMC45MywxLjg1LTAuNjIsMy4yOCwwLjM2LDQuNjdjMC43MSwxLDEuODEsMS43LDMuMjIsMS40NCBjMi43OS0wLjUxLDUuNjgsMC41OSw4LjQ3LTAuOGMxLjA4LTAuNTQsMi41OS0wLjE4LDMuOS0wLjI3YzAuNDItMC4wMiwxLjA5LTAuMDIsMS4yMS0wLjI2YzAuNTItMS4wMywxLjQ0LTAuNzYsMi4yNi0wLjkgYzEuNzYtMC4yOCwzLjUyLTAuNiw1LjI4LTAuOTJjMC4xMy0wLjAyLDAuMzMtMC4xLDAuMzctMC4yMWMwLjQzLTEuMDcsMS4zOS0wLjgzLDIuMjItMC45YzAuNjMtMC4wNiwxLjI3LTAuMDMsMS44OC0wLjE1IGMyLjIxLTAuNDMsNC4zOS0xLDYuNjEtMS4zNmMxLjc3LTAuMjksMy41Ny0wLjAyLDUuMDksMC45M2MxLjMzLDAuODMsMi40MywyLjA2LDQuMTksMS45MmMwLjA3LDAsMC4xNCwwLjI0LDAuMjUsMC4zMiBjMC45NiwwLjcxLDEuOTQsMS40MSwzLjExLDIuMjZjLTAuMDMsMC43OCwwLjcyLDIuMDEtMC45LDIuNjJjLTAuMTEsMC4wNS0wLjEyLDAuMzUtMC4yMSwwLjUyYy0wLjY4LDEuMzEtMS4zNSwyLjYzLTIuMDYsMy45MyBjLTAuNDEsMC43NS0wLjg2LDEuNDctMS4zMiwyLjE3Yy0wLjUyLDAuNzktMS4xNiwxLjUtMS42LDIuMzNjLTAuNDYsMC44Ni0wLjcsMS44NC0xLjExLDIuNzNjLTAuNTYsMS4yMi0xLjQ2LDIuMzUtMS43NCwzLjYzIGMtMC4zMSwxLjM0LTAuMTIsMi44MS0wLjAzLDQuMjJjMC4wOCwxLjE3LDAuODcsMS45NSwyLDIuMDNjMS4zOCwwLjA5LDIuODMsMC41OCw0LjEtMC42NGMwLjc1LTAuNzMsMS44Mi0xLjExLDIuNjYtMS43NiBjMC42Ni0wLjUsMS40NS0xLjA4LDEuNzMtMS44YzAuODctMi4zLDIuOTMtMy41MSw0LjQ4LTUuMThjMC40Ny0wLjUxLDEuMjktMC42OCwxLjgzLTEuMTVjMS4zOS0xLjIyLDIuNTYtMi43Nyw0LjEtMy43MSBjMS40Ni0wLjg4LDMuMjYtMS4zMSw0Ljk3LTEuNjVjMS4yNC0wLjI0LDIuMzgsMC4xOCwzLjY0LDAuODljMi4zMSwxLjMxLDUuMjgsMC41Nyw3Ljc1LDIuMDZjMS4xMiwwLjY4LDIuODQsMC42Nyw0LjIsMC44MiBjMi4yMywwLjI1LDQuMjksMC43Myw2LjUzLDEuNzljLTAuMjQsMC40My0wLjQ2LDAuOTQtMC43NywxLjRjLTAuNCwwLjU3LTAuOTksMS4wNS0xLjI4LDEuNjdjLTAuNzksMS42Ny0xLjM1LDMuMzktMS4wNyw1LjMxIGMwLjE5LDEuMjUsMi4yMywzLjM5LDMuNDIsMy4xMmMxLjIzLTAuMjcsMi41NC0wLjgxLDMuNDgtMS42MmMxLjQ4LTEuMjgsMi42My0yLjkzLDQuMDEtNC4zM2MxLjEtMS4xMiwyLjM2LTIuMDgsMy41My0zLjEyIGMwLjcxLTAuNjQsMS4zLTEuNjQsMi4xMi0xLjg5YzEuNzYtMC41MiwzLjY0LTAuNjEsNS40NS0wLjk3YzEuNzktMC4zNSwzLjU1LDAuMTcsNS40Ni0wLjkxYzEuODktMS4wNiw0LjUxLTAuOTgsNi44Mi0xLjA5IGMyLjgyLTAuMTMsMi42My0wLjYyLDIuNjMsMi41OWMwLDU3LjQyLDAuMDIsMTE0LjgzLTAuMDYsMTcyLjI1YzAsNC4yMywwLjgzLDguNTQtMC43OSwxMi43M2MtMC42MiwxLjYtMC4yNSwzLjM4LTEsNS4xNyBjLTAuODEsMS45NC0wLjg5LDQuNDMtMS4wMSw2LjYyYy0wLjM0LDYuNTYtMC4xMiwxMy4xNC0wLjExLDE5LjcyYzAsMC40OC0wLjEyLDEuMTgsMC4xNSwxLjQxYzEuNDMsMS4yNy0wLjA1LDMuNjIsMS44LDQuNjcgYzAuMzQsMy4wNCwwLjk4LDYuMDgsMC45OSw5LjEyYzAuMDYsNTIuNzksMC4wNCwxMDUuNTgsMC4wNCwxNTguMzdjMCwzLjE2LDAsNi4zMy0wLjAzLDkuNDljMCwwLjU3LTAuMTIsMS4xNC0wLjI2LDEuNjkgYy0wLjE5LDAuNzItMC42NCwxLjQxLTAuNjYsMi4xMWMtMC4xMSwzLjU2LTAuMTEsNy4xMS0wLjE2LDEwLjY3Yy0wLjAxLDAuNDItMC4xLDAuODUtMC4yMSwxLjI3Yy0wLjIsMC44LTAuNTIsMS41OC0wLjY2LDIuNCBjLTAuMTcsMC45NS0wLjE2LDEuOTMtMC4zMSwyLjg5Yy0wLjE2LDEuMDEtMC42NCwyLjAxLTAuNiwyLjk5YzAuMTYsMy45MywwLjQ3LDcuODQsMC43MywxMS43NmMwLjAxLDAuMDksMC4wMSwwLjE5LDAuMDMsMC4yOSBjMC4wMiwwLjA5LDAuMDMsMC4yNSwwLjA5LDAuMjZjMS41MywwLjUyLDEuMDEsMS44MywxLjAxLDIuODRjMC4wNCw4LjgyLDAuMTIsMTcuNjMtMC4wMywyNi40NWMtMC4wNSwyLjY1LDAuODcsNS40Mi0wLjk3LDguMDIgYy0wLjgsMS4xMi0wLjcyLDIuODctMS4wNSw0LjMyYy0wLjA1LDAuMjMtMC4xNywwLjQzLTAuMjYsMC42NGMtMC41NSwxLjMtMS4zNSwyLjU1LTEuNTksMy45Yy0wLjQ3LDIuNTktMS4zMyw1LjEyLTEuMDcsNy44NiBjMC4yMiwyLjM3LTAuMDUsNC43OCwwLjA4LDcuMTZjMC4xLDEuODMsMC41OCwzLjY0LDAuNzIsNS40N2MwLjExLDEuNTYtMC42OCwyLjI4LTIuMjMsMi4yOWMtMi44NywwLjAyLTUuNzQtMC4wMS04LjYxLDAuMDMgYy0wLjYsMC4wMS0xLjU0LDAuMDQtMS43NCwwLjRjLTAuNTQsMC45My0xLjI5LDAuNzEtMi4wMywwLjc0Yy0xLjg5LDAuMDktMy45Mi0wLjI2LTUuNjMsMC4zM2MtMS42NCwwLjU2LTMuMTgsMC40NC00Ljc3LDAuNTUgYy0wLjc3LDAuMDUtMS41NiwwLTIuMzMsMC4wNGMtMC4zOSwwLjAzLTAuOTksMC4wMy0xLjEsMC4yNWMtMC43MiwxLjMzLTEuOTMsMC43Ny0yLjk1LDAuODljLTAuNjgsMC4wNy0xLjU2LTAuMTItMS45OSwwLjI0IGMtMS41MSwxLjMtMy45MS0wLjEzLTUuMTQsMS43OWMtMi4xMi0wLjAyLTQuMTUsMC4yMi02LjIzLDAuODJjLTEuOTYsMC41Ni0yLjEyLDAuMzItMi4xOCwyLjQ0Yy0wLjAxLDAuMzQtMC4wMSwwLjY5LDAsMS4wMyBjMC4wNiwxLjY4LDIuMjQsMi45OCwzLjg0LDIuNDZjMi4wMS0wLjY1LDQuMDgtMS41LDYuMTUtMS41NmM3LjEtMC4yMSwxNC4yMS0wLjEyLDIxLjMxLTAuMTJjMC40Ny0wLjAxLDAuOTksMC4wNywxLjQsMC4yOCBjMS42NywwLjg1LDMuMzIsMS42Miw1LjI3LDEuNDdjMC42NC0wLjA1LDEuMzIsMC4xNSwxLjk1LDAuMzVjMC42NCwwLjE5LDEuMjIsMC43MSwxLjg0LDAuNzVjMy4xOSwwLjE2LDMuMjIsMC4xNiwzLjMzLDMuNDUgYzAuMDIsMC40NywwLjA1LDEuMjIsMC4zMSwxLjM0YzIuMDcsMC45OCwxLjg5LDIuOCwxLjY0LDQuNTFjLTAuMSwwLjY0LTAuODEsMS4zMy0xLjQxLDEuNjljLTAuMjksMC4xNy0xLTAuMzYtMS41My0wLjU2IGMtMC40My0wLjE2LTAuODctMC40LTEuMzItMC40MmMtMS4yMS0wLjA3LTIuNDMtMC4wMS0zLjY1LTAuMDZjLTAuNC0wLjAxLTAuOTctMC4wMy0xLjE4LTAuMjljLTEuMDEtMS4yMS0yLjQ2LTIuMDctMi45Ni0zLjcyIGMtMC4xMi0wLjM5LTAuNzMtMC43Ny0xLjE4LTAuODhjLTAuNjQtMC4xNS0xLjM2LDAtMi4wMy0wLjA4Yy0zLjAxLTAuMzktNC4zMSwyLjE0LTQuNCw0LjQzYy0wLjE4LDQuNzctMC4xMyw5LjU0LTAuMTQsMTQuMzEgYy0wLjAxLDIuODIsMi4wMyw0LjY5LDQuODYsNC41MmMwLjMzLTAuMDMsMC43MSwwLDEtMC4xNGMwLjM5LTAuMiwwLjc5LTAuNDksMS4wNS0wLjg0YzAuNTctMC44MSwwLjg3LTIuMDgsMS42Mi0yLjQzIGMxLjczLTAuNzksMy42NS0xLjIyLDUuNTItMS42NWMxLjEyLTAuMjYsMi4zMy0wLjExLDMuNDQtMC4zN2MwLjUtMC4xMiwwLjgzLTEuMTIsMS40Ny0wLjIxYzAuMzYsMC41MSwwLjg2LDEuMDIsMC45NSwxLjU5IGMwLjE2LDAuOTUsMC4wMywxLjk0LDAuMDYsMi45MWMwLjAyLDAuNzMtMC4zLDEuNiwwLjcyLDIuMDJjMC4xLDAuMDQsMC4wNywwLjg3LTAuMDYsMC45MmMtMC45LDAuMzctMS44NCwwLjg2LTIuNzcsMC44NyBjLTQuMzgsMC4wOS04Ljc2LTAuMDgtMTMuMTQsMC4wOGMtNC4yNSwwLjE1LTguNDgsMC42LTEyLjczLDAuOTNjLTAuMTQsMC4wMS0wLjI5LDAuMDQtMC40MiwwLjFjLTAuMTgsMC4wNi0wLjQ2LDAuMTMtMC40OSwwLjI0IGMtMC4yNywxLjA1LTEuMSwwLjc0LTEuNzgsMC43OGMtMS4yNiwwLjA3LTIuNzEtMC4yNS0zLjczLDAuMjdjLTEuNTYsMC43OS0zLjA3LDAuNDktNC42MSwwLjZjLTAuODMsMC4wNi0xLjY2LTAuMDItMi40OCwwLjA1IGMtMC40NiwwLjA0LTAuOTIsMC4yMy0xLjM2LDAuNGMtMC41NywwLjIyLTEuMTEsMC42OC0xLjY2LDAuNjljLTUuNzQsMC4xMi0xMS40OCwwLjI1LTE3LjIyLDAuMTljLTIuOTQtMC4wMy01LjgsMC4zMi04LjY2LDAuODkgYy0xLjkyLDAuMzgtMy44NywwLjU2LTUuODEsMC44NGMtMC4xNCwwLjAyLTAuMzcsMC4wMy0wLjQxLDAuMTFjLTAuNjQsMS4zOC0xLjg5LDAuNzktMi45MSwwLjkxYy0wLjY3LDAuMDctMS41OC0wLjE3LTEuOTksMC4xOSBjLTEuMTYsMS0yLjQ1LDAuNTgtMy42OSwwLjY5Yy0wLjgzLDAuMDctMS42OCwwLTIuNDcsMC4yYy0wLjQ2LDAuMTItMC43OSwwLjg2LTEuMjQsMC45MWMtMi45MSwwLjM3LTUuODQsMC42Mi04Ljc2LDAuOTEgYy0wLjE1LDAuMDEtMC4zNS0wLjAyLTAuNDMsMC4wNmMtMC42NSwwLjY4LTEuNTMsMS4yOS0xLjg1LDIuMTFjLTAuMzEsMC43OCwwLjIxLDEuNTEsMC44NCwyLjM2YzEuMywxLjc2LDIuODcsMiw0LjU0LDEuNjkgYzIuNzYtMC40OSw1LjU0LDAuNjQsOC4zOC0wLjkyYzEuOTYtMS4wOCw0LjY3LTAuOCw3LjA2LTEuMDZjMS4wNi0wLjEyLDIuMTQtMC4wMywzLjIxLTAuMDljMC4zNi0wLjAyLDAuNzEtMC4xNiwxLjA1LTAuMyBjMC41Ny0wLjIzLDEuMTMtMC43MSwxLjctMC43MWM3LjItMC4wOSwxNC40MiwwLjI1LDIxLjU3LTAuOThjMC45NS0wLjE2LDEuODYtMC43OSwyLjgtMC44YzguMjctMC4wNiwxNi41NC0wLjAzLDI0LjgxLTAuMDIgYzAuNDQsMCwxLjAzLTAuMTEsMS4yOCwwLjEyYzEuMTYsMS4wOSwyLjU1LDAuNjksMy44NiwwLjcyYzIuNjIsMC4wNiw1LjI2LTAuMDQsNy44OCwwLjA5YzMuOTIsMC4yLDcuODMsMC41NywxMS43NSwwLjc5IGMwLjk4LDAuMDYsMS4xLDAuNjEsMS4xLDEuMzNjMC4wMywyLjM5LDAuMDUsNC43OCwwLjA1LDcuMTZjLTAuMDEsMi4wMi0xLjg3LDMuMTQtMy43NywyLjM5Yy0wLjk1LTAuMzctMS45OS0wLjctMi45OC0wLjcgYy0xMC43Ni0wLjA2LTIxLjUxLTAuMDItMzIuMjctMC4wN2MtMS41OC0wLjAxLTMuMzcsMC42Ni00LjY1LTAuOTdjLTAuMDgtMC4wOS0wLjI3LTAuMTEtMC40MS0wLjEzIGMtMi45My0wLjMyLTUuODYtMC42Mi04Ljc5LTAuOTVjLTAuNC0wLjA0LTAuOC0wLjE4LTEuMTgtMC4zM2MtMC41Ny0wLjI0LTEuMTMtMC43Ny0xLjY5LTAuNzdjLTcuMzUtMC4wMy0xNC42OSwwLTIyLjA0LDAuMDQgYy0wLjk1LDAtMi4yNywxLjM1LTIuMzEsMi4yOWMtMC4wMywwLjg2LTAuMSwxLjYyLDEuMDEsMi4wOGMwLjY1LDAuMjcsMC45NiwxLjUzLDEuNTksMS42OGMxLjkyLDAuNDgsMy45MSwwLjYzLDUuODcsMC45MyBjMS4wNCwwLjE1LDIuMzctMC41NSwyLjk0LDEuMDFjMC4wNCwwLjEsMC4zNiwwLjExLDAuNTUsMC4xMmMzLjUxLDAuMzMsNy4wMSwwLjY3LDEwLjUyLDAuOTVjMS4xNiwwLjEsMi4zNCwwLjAyLDMuNSwwLjA4IGMwLjQsMC4wMiwwLjc5LDAuMjUsMS4xOSwwLjM5YzAuNSwwLjE4LDEuMDEsMC41MiwxLjUyLDAuNTNjMi40MywwLjA2LDQuODYsMC4wMSw3LjMsMC4wNmMwLjY1LDAuMDEsMS4zLDAuMjMsMS45NCwwLjQgYzAuNDgsMC4xMywwLjkzLDAuNDYsMS40LDAuNDZjNy44NCwwLjA5LDE1LjY3LDAuMDUsMjMuNSwwLjIzYzUuODEsMC4xMywxMS42MSwwLjQ4LDE3LjQsMC44NmMwLjY0LDAuMDUsMS41NCwwLjg1LDEuNzYsMS40OSBjMC40OSwxLjQzLDEuNTUsMi43NiwxLjE1LDQuNDVjLTAuMDYsMC4yNywwLjMzLDAuNjMsMC40OCwwLjk3YzAuNTUsMS4yNSwxLjA5LDIuNTEsMS42MywzLjc3Yy0wLjEzNywwLjE4NC0wLjE3LDAuMjMtMC4zMDcsMC40MTQgYy0wLjk0NC0wLjA5My0xLjg5OS0wLjEzMi0yLjgyMy0wLjI5NGMtMC41OS0wLjEtMS4xMy0wLjUzLTEuNy0wLjU0Yy02Ljk2LTAuMS0xMy45MS0wLjE0LTIwLjg3LTAuMjIgYy0xLjA4LTAuMDEtMi4yOSwwLjQtMy4wOS0wLjg4Yy0wLjE2LTAuMjctMC45LTAuMjUtMS4zOC0wLjI2Yy0xLjYtMC4wMy0zLjIxLTAuMDEtNC44Mi0wLjAxYy0wLjMzLTAuMDEtMC44MywwLjA5LTAuOTktMC4wOSBjLTAuOTEtMS4wOS0yLjE0LTAuNzItMy4yNi0wLjc3Yy0xLjI2LTAuMDUtMi41MywwLjAxLTMuNzktMC4wMmMtMC4zNi0wLjAxLTAuNzItMC4xNC0xLjA1LTAuMjljLTAuNTgtMC4yNS0xLjExLTAuNzUtMS43LTAuODIgYy0yLjg4LTAuMzItNS43NC0wLjEzLTguNjYtMC43NGMtMy4yNy0wLjY4LTYuNzgtMC4yMS0xMC4xOS0wLjE4Yy0wLjQ4LDAtMS4xNCwwLjItMS40LDAuNTVjLTAuOSwxLjIxLDAuMDksNC4xNywxLjUxLDQuNDQgYzIuMDEsMC4zOSw0LjA1LDAuNiw2LjA4LDAuODdjMC43MiwwLjEsMS44NC0wLjEsMi4wOSwwLjI5YzAuNzgsMS4yMSwxLjg1LDAuNzQsMi44MywwLjg0YzAuOTIsMC4xLDIuMDQtMC4xNiwyLjcsMC4yOSBjMS4wNSwwLjcxLDIuMDgsMC42LDMuMTYsMC42NWMxLjA2LDAuMDUsMi4xOC0wLjA3LDMuMTksMC4yMWMxLjYzLDAuNDUsMy4xNiwxLjMsNC44LDEuNzJjMS43MSwwLjQ1LDMuNDgsMC4wOCw1LjI3LDEuMDYgYzEuNDMsMC43OCwzLjQ0LDAuMzIsNS4yMywwLjkxYzIuMTMsMC43MSw0LjUtMC4wMiw2LjgzLDAuODhjMi40NiwwLjk1LDUuMjIsMC4wMSw4LjAxLDEuMDdjMy4xMywxLjE5LDYuODYsMC44MSwxMC4zMywxLjEyIGMwLjU3LDAuMDUsMS4xOCwwLjAzLDEuNjgsMC4yNmMwLjY0LDAuMywxLjE3LDAuODIsMS43NSwxLjI0YzAuMTUtMC4wMiwwLjMxLTAuMDUsMC40Ni0wLjA4Yy0wLjEsMS4xOCwwLjE3LDIuNTktMC4zOSwzLjUgYy0wLjg2LDEuMzgtMi41MywxLjk3LTQuMTksMi4wMmMtMy4yNSwwLjA4LTYuNTEsMC4wMi05Ljc2LDAuMDdjLTEuODYsMC4wMy0yLjY4LDAuOTQtMi42NiwyLjgxYzAuMDEsMC45MywxLjQ3LDMuMTQsMi40LDMuMzYgYzEuNjUsMC40LDMuMzMsMC44Miw1LjAxLDAuOWMzLjA2LDAuMTQsNi4xMywwLjAzLDkuMTksMC4wNWMxLjU4LDAsMi4zLDAuNzMsMi4zMSwyLjM0YzAuMDIsMy4xMiwwLjIyLDYuMjUtMC4wNyw5LjM0IGMtMC4yLDIuMTMsMS4yMiwyLjk3LDIuMjcsNC4xOWMwLjA5LDAuMSwwLjU2LDAuMDEsMC43My0wLjE0YzAuOTktMC44MiwxLjM3LTEuODMsMS4yOC0zLjE4Yy0wLjA2LTEuMDMsMC40NS0yLjA4LDAuNi0zLjEzIGMwLjI2LTEuOTUtMC4yNS00LjA2LDEuMjYtNS43M2MwLjI4LTUuNzQsMC41Ni0xMS40OCwwLjg1LTE3LjIyYzAuMDQtMC44MywwLjE0LTEuNjYsMC4xMi0yLjQ4Yy0wLjA4LTMuNDYsMC42NS02Ljg2LDAuODMtMTAuMjggYzAuMTMtMi40Ni0wLjUxLTQuOTYtMC43NS03LjQ0Yy0wLjEyLTEuMjYsMC4yOC0yLjc2LTAuMjgtMy43NGMtMC44Ny0xLjU0LTAuNDctMy4wNS0wLjYzLTQuNThjLTAuMDUtMC41MywwLjAxLTEuMDctMC4wNi0xLjYgYy0wLjA1LTAuMzctMC4xMi0wLjk2LTAuMzYtMS4wNmMtMC45Ny0wLjQ0LTAuNzMtMS4yNC0wLjc1LTEuOThjLTAuMDQtMS44LDAuMzktMy43OC0wLjI0LTUuMzRjLTAuNjYtMS42NC0wLjU0LTMuMTctMC42Mi00Ljc2IGMtMC4wNy0xLjIyLTAuMDItMi40NC0wLjA0LTMuNjVjLTAuMDEtMC40NCwwLjA0LTEuMS0wLjItMS4yNmMtMS40MS0wLjk0LTAuNzQtMi4zNi0wLjk1LTMuNTdjLTAuMjQtMS40NC0wLjYzLTIuODctMC42OS00LjMyIGMtMC4wNy0xLjU5LTAuNjctMy4zMiwwLjU4LTQuNzRjMC4yMS0wLjI0LDAuOTItMC40MiwxLTAuMzJjMC40MiwwLjU0LDAuODgsMS4xNSwxLjAxLDEuOGMwLjMxLDEuNTItMC4xNCwzLjA2LDEuMDMsNC41OCBjMS4wMiwxLjMsMS4yMiwzLjIyLDEuODUsNC44NWMwLjM0LDAuODYsMC44NiwxLjY0LDEuMjUsMi40OWMwLjI3LDAuNTgsMC40MywxLjIyLDAuNjksMS44MmMwLjQ2LDEuMDcsMC45NiwyLjEzLDEuNDUsMy4xOSBjMC41MiwxLjEyLDEuMDQsMi4yNCwxLjU2LDMuMzVjMC40MSwwLjg3LDEuMDUsMS42OSwxLjIsMi41OWMwLjQxLDIuNTgsMC43Myw1LjE4LDAuODcsNy43OGMwLjE3LDMuMjEsMC4xMiw2LjQzLDAuMTksOS42NCBjMC4wMSwwLjQzLTAuMDEsMS4wOCwwLjI0LDEuMjNjMS4wNCwwLjY2LDAuODQsMS42NiwwLjkxLDIuNmMwLjI3LDMuNTQtMC4zNyw3LjA4LDAuNjYsMTAuNjRjMC41LDEuNzIsMS43NCwyLjU3LDIuNjYsMy43OSBjMC4xNiwwLjIxLDAuNzUsMC4xOSwxLjEyLDAuMTJjMC42Mi0wLjEyLDIuNDItMi41MywyLjQ2LTMuMThjMC41MS04Ljc1LTAuMzUtMTcuNTMsMC43MS0yNi4yOWMwLjQxLTMuMzgtMC4zMS02LjkxLTAuNTgtMTAuMzYgYy0wLjA5LTEuMTUsMC40OS0yLjU3LTEuMS0zLjI0Yy0wLjExLTAuMDQtMC4xMS0wLjM1LTAuMTMtMC41NGMtMC4zLTIuODEtMC41OS01LjYyLTAuOS04LjQyYy0wLjA1LTAuNDctMC4xMS0xLjIxLTAuMzgtMS4zMyBjLTEuMDItMC40My0wLjczLTEuMjYtMC43OC0xLjk3Yy0wLjA4LTEuMTEsMC4zLTIuNTMtMC4yNS0zLjI3Yy0wLjgzLTEuMS0wLjUyLTIuMDItMC40OS0zLjA1YzEuOTktMC40MywzLjc1LTEuODEsNS43NC0wLjk1IGMwLjM5LDIuODgsMC44NSw1LjY5LDEuMTQsOC41MmMwLjIzLDIuMjksMS4wMSw0LjI2LDIuODksNS42M2MwLjQ1LDAuMzMsMS4yMiwwLjQ3LDEuNzcsMC4zNWMwLjc2LTAuMTUsMS40NS0wLjYzLDIuMy0xLjAzIGMwLTIuNTMtMC4wMi01LjE1LDAuMDItNy43OGMwLjAxLTAuODYtMC4xNC0xLjk2LDAuMzEtMi41M2MwLjkxLTEuMTYsMC41My0xLjk4LTAuMTItMi43N2MwLjQ4LTEuNzUsMS43Ni0xLjYsMy4wNy0xLjY0IGM2LjcxLTAuMjUsMTMuNDItMC41NywyMC4xMy0wLjg3YzAuMTksMCwwLjM5LTAuMDMsMC41OC0wLjA2YzIuOTE1LTAuNTg3LDUuNzk1LTEuMzYyLDguODE2LTEuMTQ2IGMxLjM4OCwwLjA5OSwyLjc3OSwwLjE4NSw0LjE2NiwwLjA2N2MxLjU4My0wLjEzNSwzLjIsMC4xMDEsNC42NTgtMC45MjFjMC45Ny0wLjY4LDEuNjktMS44OCwxLjE4LTMuMjggYy0wLjI1LTAuNjgtMS4xNi0xLjU1LTEuODEtMS41OGMtNS45NS0wLjMtMTEuOTItMC4xMi0xNy44My0xLjExYy0wLjM3LTAuMDYtMC45OC0wLjA0LTEuMDYtMC4yM2MtMC40Ny0xLjEyLTEuNDItMC44NS0yLjI1LTAuODggYy0xLjc5LTAuMDctMy43OCwwLjQtNS4zNC0wLjIyYy0xLjU0LTAuNjItMi45Ny0wLjUxLTQuNDYtMC42OWMtNC40NS0wLjUzLTkuMDksMS4yLTEzLjM3LTEuMTRjLTAuNTctMC4zMS0xLjIyLTAuNTUtMS42Ni0wLjk5IGMtMS4xNi0xLjE4LTIuMTgtMi41LTMuMzUtMy42OGMtMS44OS0xLjktMy44OC0zLjcxLTUuNzctNS42MmMtMS4xMS0xLjEtMS45LTIuNzQtMy4yMS0zLjM2Yy0xLjcxLTAuODEtMi45NC0xLjk2LTQuMjctMy4yIGMtMS40NS0xLjM2LTMuMjUtMi4zNS01LjEzLTMuNjd2LTEuMzdjMi4zOSwwLjIzLDQuNzgtMC4zOCw2LjgxLDEuNmMwLjc0LDAuNzMsMi4xLDEuMTcsMy4xNywxLjE1YzIuMDctMC4wNiwyLjgxLTEuMSwyLjgzLTMuMjIgYzAuMDEyLTEuMDI5LDAuMTA1LTIuMDcyLTAuMTM1LTMuMDY1Yy0wLjEyNi0wLjUyMi0wLjU5NC0xLjI0Mi0wLjk4My0xLjYxMmMtMC45OTQtMC45NDQtMi4yMDQtMS43MTgtMi45ODItMi44MDMgYy0xLjE4LTEuNjItMi43MS0yLjctNC4zLTMuOGMtMC42Ni0wLjQ1LTEuMjctMS4wNC0xLjc3LTEuNjhjLTAuNjItMC43Ny0xLjAxLTEuNzUtMS42Ny0yLjQ4Yy0wLjctMC43OS0xLjA3LTEuNTUtMS4wNy0yLjY2IGMwLjA0LTI1LjUyLDAuMDItNTEuMDMsMC4wOS03Ni41NWMwLjAxLTIuNDUsMC41NC00Ljg5LDAuODYtNy4zM2MwLjAyLTAuMiwwLjI4LTAuMzYsMC4zOC0wLjU2YzAuNTEtMS4wMiwxLjM3LTIuMDMsMS40Mi0zLjA3IGMwLjItNC42NywwLjM3LTkuMzYsMC4xNS0xNC4wMmMtMC4yMy00LjYsMC44OS05LjI0LTAuOTEtMTMuODZjLTAuOTctMi41LTAuNzYtNS40NS0xLjA4LTguMmMtMC4wNi0wLjUzLTAuMTItMS4wNi0wLjIyLTEuNTkgYy0wLjE3LTAuOTItMC41My0xLjg0LTAuNTQtMi43NWMwLTEuNi0wLjEtMy4xNiwwLjUyLTQuOGMwLjU0LTEuNDIsMC40MS0zLjIsMC4yMS00Ljc3Yy0wLjM3LTIuOCwwLjgyLTUuMzUsMC45Ny04LjA1IGMwLjAxLTAuMTQsMC4wNS0wLjM2LDAuMTQtMC40YzEuMjYtMC42MSwwLjg0LTEuOCwwLjk5LTIuNzljMC4wNi0wLjQzLTAuMTEtMS4wNCwwLjEyLTEuMjdjMS40Ni0xLjQ1LDAuNzMtMy41LDEuNjEtNS4yNSBjMS4xLTIuMi0wLjEyLTUuMTksMS4wNy03LjY4YzAuMDQtOS41LDAuMS0xOC45OSwwLjEyLTI4LjQ5YzAtMS43NCwwLjM0LTMuNzItMC4zNS01LjE4Yy0wLjg1LTEuODMtMC41NS0zLjU2LTAuNzQtNS4zMyBjLTAuMDQtMC4zNi0wLjE2LTAuNzMtMC4zMS0xLjA3Yy0wLjI1LTAuNTYtMC42OC0xLjA4LTAuNzktMS42N2MtMC4zNy0yLjAxLTAuNjQtNC4wNS0wLjk1LTYuMDcgYy0wLjAxOC0wLjA2NC0wLjAzNS0wLjEyNi0wLjA1My0wLjE5Yy0wLjU0Ny0xLjI5LTEuNDQyLTIuNTEzLTEuNzA3LTMuODdjLTAuNDctMi40Ni0wLjg4LTQuOTgtMC44OC03LjQ3IGMtMC4wNC01MS43Mi0wLjAyLTEwMy40NC0wLjA1LTE1NS4xNWMwLTIuMjQsMC42OC0zLjg5LDIuNTQtNS4xM2MwLjgxLTAuNTMsMS41LTEuMjYsMi4xOS0xLjk2YzEuMTEtMS4xMiwyLjEzLTIuMzIsMy4yNy0zLjM5IGMwLjM5LTAuMzYsMS4xOS0wLjI4LDEuNTctMC42NGMxLjMyLTEuMjYsMi41MS0yLjY2LDMuODEtMy45NWMxLjAzLTEuMDIsMi4xOC0xLjk0LDMuMi0yLjk3YzEuMzQtMS4zNiwyLjU4LTIuODIsMy45Mi00LjE4IGMxLjIxLTEuMjIsMi42Mi0yLjI2LDMuNzItMy41OGMxLjE3LTEuNCwyLjI4LTIuNzcsNC4xNC0zLjI3YzAuMTQtMC4wNCwwLjI0LTAuMjgsMC4zNS0wLjQzYzEuMjYtMS44NywxLjExLTMuOTgsMC45Ny02LjA3IGMtMC4wMi0wLjM4LTAuNDQtMC45Ny0wLjc4LTEuMDZjLTIuNDItMC42NC00LjY4LDAuMTItNi45MywwLjkyYy0wLjI5LDEuNTItMS44OSwxLjEyLTIuOCwxLjdjLTEuMTUsMC43NC0yLjg1LDAuMDEtNC4zLDEuMTYgYy0wLjg4LDAuNy0yLjYxLDAuNTgtMy45NiwwLjkyYy0xLjc0LDAuNDQtMy4zMiwxLjAzLTQuOTIsMi4wN2MtMC4xLTAuNTUtMC4yNS0xLjAxLTAuMjUtMS40N2MwLTIuNDgtMC4wMy00Ljk3LDAuMDctNy40NSBjMC4yMy01LjYyLDAuMTQtMTEuMjQsMC43My0xNi44OGMwLjU2LTUuMzktMC4wMS0xMC44OS0wLjA0LTE2LjM0Yy0wLjAzLTYuMDQsMC4wMy0xMi4wOC0wLjAzLTE4LjEyIGMtMC4wMy0yLjE1LDAuMDUtNC4yNi0wLjQ4LTYuNDZjLTAuNzYtMy4xNy0wLjc4LTYuNTEtMS4yLTkuNzdjLTAuMTEtMC44NC0wLjU0LTEuNjQtMC44LTIuNDZjLTAuMDYtMC4yMi0wLjE1LTAuNTQtMC4wNC0wLjY3IGMwLjcyLTAuODksMS40Ni0xLjc1LDIuMjQtMi41OWMxLjgyLTEuOTcsMy44LTMuODEsNS40NS01LjkyYzEuMzMtMS42OSwyLjU4LTMuMjgsNC43Ni0zLjljMC43Ni0wLjIxLDEuNTUtMC42MiwyLjEzLTEuMTUgYzEuMTktMS4xMSwyLjEyLTIuMzYsMy44MS0zLjA2YzEuNzQtMC43MiwzLjEyLTIuMzIsNC42NC0zLjU2YzAuNDEtMC4zMywwLjczLTAuNzgsMS4xNi0xLjA3YzIuMDQtMS40Miw0LjExLTIuNzksNi4xNS00LjIxIGMwLjI5LTAuMiwwLjQ0LTAuNjEsMC43My0wLjhjMS40Ni0wLjkxLDMuMDEtMS42OSw0LjQxLTIuNjhjMS4xNi0wLjgxLDIuMTctMS44MywzLjItMi44YzAuNDYtMC40NCwwLjg2LTAuOTcsMS4xOC0xLjUxIGMwLjQtMC42OCwwLjU0LTEuNTUsMS4wNi0yLjA5YzEuMTU5LTEuMjEsMS44MjItMi41NDQsMS44Mi00LjIyMmMwLTAuMjU4LDAuMDQ2LTAuNTE2LDAuMTU5LTAuNzQ3YzAuOTctMS45NywyLjA2LTMuOSwyLjk1LTUuOTIgYzEuMTUtMi42LDIuMDgtNS4zLDMuMjQtNy44OWMxLjA0LTIuMzMsMi40NC00LjUyLDMuMzQtNi44OWMwLjYxLTEuNTksMS41OS0yLjAyLDMuMDMtMi4wM2MzLjk5LTAuMDMsNy45OS0wLjIyLDExLjk2LDAuMDIgYzIuMjUsMC4xNCwzLjc5LTEuNDksNS44NS0xLjY2YzAuNzE3LTAuMDUxLDEuNDI0LTAuNTIyLDIuMDc3LTAuODg2YzAuODQ2LTAuNDcyLDEuNjcyLTAuOTc2LDIuNDc2LTEuNTE2IGMwLjY0Ni0wLjQzNCwxLjM4MS0wLjgzOCwxLjkxNy0xLjM5OEMyMzAuNDQxLDEzMS45OCwyMzAuMzExLDEzMC4yNywyMzAuMDcxLDEyOC42NHogTTExMS40MzcsMTkyLjQyIGMtNDYuNTcsMC04NC4zMi0zNy43NS04NC4zMi04NC4zMmMwLTQ2LjU2LDM3Ljc1LTg0LjMxLDg0LjMyLTg0LjMxYzQ2LjU2LDAsODQuMzEsMzcuNzUsODQuMzEsODQuMzEgQzE5NS43NDcsMTU0LjY3LDE1Ny45OTcsMTkyLjQyLDExMS40MzcsMTkyLjQyelwiXG4gICAgICAgIF0sXG4gICAgICAgIGNsb2Nrczoge1xuICAgICAgICAgICAgc2l6ZTogMTY5LFxuICAgICAgICAgICAgMDogeyB4OiAxMTEuMDExLCB5OiAxMDguNSB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIDI6IHtcbiAgICAgICAgaGVpZ2h0OiA2MjUuNDM4LFxuICAgICAgICB3aWR0aDogMTk3LjAwOSxcbiAgICAgICAgcGF0aDogXCJNMTkzLjg2LDI3MS4yMWMtMi4yMzQtMi42MjYtNS42NC00Ljc5Mi04LjkyOS01LjgzNWMtNi43OTMtMi4xNTMtMTEuODQxLDIuMTk2LTE3LjQ2Myw3LjM2OSBjLTUuMDA5LTI1LjcyNy0xNy41ODMtNDMuOTg3LTM4LjQ3Ny01NC4yNDZsLTE4LjkwOS0yMS41NnYtMTJsMjAuNzczLTIzLjY4NmMxOS41NS0xMC40NDYsMzEuNDAyLTI4LjMwNCwzNi4yMjktNTMuMDk2IGM1LjYyMiw1LjE3NCwxMC42Nyw5LjUyMywxNy40NjMsNy4zNjljMy4yODktMS4wNDMsNi42OTUtMy4yMDgsOC45MjktNS44MzVjNC44NzctNS43MzQsMy44NzktMTQuMzAyLTEuNTQyLTE5LjYwNSBjLTYuNDQyLTYuMzAxLTEzLjU2OS01LjU0OS0yNC44NTIsMy4zODJjLTQuODE2LTI1LjIzMS0xNy4xODMtNDMuNTg3LTM4LjQwOS01NC4wMzFoMC4xNThjLTEuNTA2LTAuNzMyLTMuMDU2LTEuMzk0LTQuNjI1LTIuMDI1IGMtMi45OTctMS4yNS02LjE0NC0yLjM2NS05LjQ2My0zLjMyN2MwLDAtMC41MjctMC4wODktMS40NTctMC4yMTdjLTIuNDIxLTAuNzMxLTQuNzU3LTIuMDItNy43NDMtMy4yNzMgYzIuMTAzLTIuMjgyLDMuMjU1LTMuNDU1LDQuMzIxLTQuNzAzYzUuMTc2LTYuMDU3LDQuODIxLTE0Ljk3OC0wLjc5Mi0yMC41MzhjLTUuNjQ3LTUuNTk0LTE0LjU0My01LjgyOS0yMC4zNTItMC41MzkgYy02LjEwMSw1LjU1Ni02LjgwOCwxNC40OS0xLjY0OCwyMC44MzFjNC4xNTMsNS4xMDMsMy45MDUsNS40MDMtMi40OSw4LjA1NWMtMS43OTMsMC43NDQtMy42MDQsMS40NjUtNS40MTcsMi4xODcgYy0xMC4yODEsMy4wMzItMTYuMDkyLDYuOTI5LTIyLjg3NSwxMi4wMDFjLTEyLjQxNSw5LjI4NC0xOS43MzksMjIuMzg1LTIzLjUyMSwzNy41MTVjLTAuNjczLDIuNjkzLTIuMDgsNS4yLTMuNDM3LDguNDkyIGMtMi4yNjItMi4xMjItMy40MjQtMy4yODQtNC42NjEtNC4zNmMtNi4wMDMtNS4yMjItMTQuODQ1LTQuODY0LTIwLjM1NiwwLjc5OWMtNS41NDQsNS42OTgtNS43NzgsMTQuNjczLTAuNTM0LDIwLjUzNCBjNS41MDcsNi4xNTYsMTQuMzYxLDYuODY5LDIwLjY0NiwxLjY2MmM1LjA1OC00LjE5LDUuMzU1LTMuOTQsNy45ODQsMi41MTJjMy4zOTQsOC4zMyw2LjI5MiwxNy4wNTQsMTAuOTcyLDI0LjYyIGM2LjAzMiw5Ljc1MiwxNC4zMDMsMTYuODczLDI0LjA5NiwyMS45MTVsMjEuNjAxLDIzLjM1N3YxMmwtMjAuMjIzLDIxLjg2N2MtMTAuMjMyLDUuMDY4LTE4Ljg1NSwxMi4zNDgtMjUuMDkxLDIyLjQzIGMtNC42OCw3LjU2Ni03LjU3OCwxNi4yOS0xMC45NzIsMjQuNjJjLTIuNjI5LDYuNDUyLTIuOTI2LDYuNzAyLTcuOTg0LDIuNTEyYy02LjI4NS01LjIwNi0xNS4xMzktNC40OTMtMjAuNjQ2LDEuNjYyIGMtNS4yNDMsNS44NjEtNS4wMSwxNC44MzcsMC41MzQsMjAuNTM0YzUuNTExLDUuNjYzLDE0LjM1Miw2LjAyMSwyMC4zNTYsMC43OTljMS4yMzctMS4wNzYsMi4zOTktMi4yMzgsNC42NjEtNC4zNiBjMS4zNTYsMy4yOTIsMi43NjQsNS43OTksMy40MzcsOC40OTJjMy43ODIsMTUuMTMsMTEuMTA2LDI4LjIzMiwyMy41MjEsMzcuNTE1YzcuODc3LDUuODksMTQuNDI1LDEwLjE5OCwyOC4yMDYsMTMuNDA0IGMxLjM4LDAuMzIxLDIuNzg3LDAuNTc5LDQuMjAxLDAuNzg5YzAuMDMxLDI3Ljc5NiwwLjA2LDY5LjYwNCwwLjA4NSwxMDUuMjM2YzAuMDA5LDEzLjgyOSwwLjAxOCwyNi43MywwLjAyNiwzNy41MTggYzAsMC44MjYtMC4wOCwxLjY1Mi0wLjEyMSwyLjQzNmMtMy40NDcsMC41OTctNC41OC0wLjQ5NS00LjY4Mi00LjUxMWMtMC4wNzItMi44MjItMC4wMDItNS42NDktMC4wMTYtOC40NzMgYy0wLjAyNC00LjgwMi0wLjg5MS01Ljk3LTQuNjA5LTUuOTc2Yy0xNC40MzItMC4wMjItMjguODY0LTAuMDEtNDMuMjk1LTAuMDA5Yy00LjYyNywwLTkuMjU1LDAuMDg0LTEzLjg4MS0wLjAyMiBjLTMuMDU0LTAuMDctNC40MjgsMS42OTgtNC4zMjYsNS42MjNjMC4wNzksMy4wMzksMC4wODUsNi4wOC0wLjAwMSw5LjExOWMtMC4xMTEsMy45MzMsMS4yNyw1LjY3NCw0LjMxNyw1LjY0NiBjOC4zNzItMC4wNzYsMTYuNzQ1LTAuMDM4LDI1LjExOC0wLjAyNGM0LjE0LDAuMDA3LDQuOTMzLDEuMDU1LDQuOTQ3LDYuMzk3YzAuMDI0LDkuNzAyLDAuMDI0LDkuNzAyLTcuNjcsOS43MDIgYy03LjM4MS0wLjAwMS0xNC43NjItMC4wMjUtMjIuMTQzLDAuMDA2Yy0zLjU1OCwwLjAxNS00LjU0LDEuMjA5LTQuNTUxLDUuNjExYy0wLjAzNSwxMy45NDctMC45NDMsMTMuMTA5LDEwLjAwNCwxMy4wMzUgYzYuNjEtMC4wNDUsMTMuMjItMC4wMzIsMTkuODMsMC4wMDJjMy41MjgsMC4wMTgsNC40NjMsMS4yMjYsNC41MzQsNS42MzhjMC4xNywxMC40NTUsMC4xNywxMC40NTUtOC4wNTYsMTAuNDU1IGMtNy4yNzEsMC0xNC41NDItMC4wMjQtMjEuODEzLDAuMDFjLTMuNDkyLDAuMDE2LTQuNDgsMS4yNjMtNC41MDMsNS42NzJjLTAuMDY3LDEyLjY0Mi0wLjcwMSwxMi4yNDMsOS4zOTcsMTIuMTI5IGM2LjgzLTAuMDc3LDEzLjY2MS0wLjA0LDIwLjQ5MS0wLjAwNGMzLjQ2NiwwLjAxOCw0LjQxOSwxLjI4MSw0LjQ4NCw1LjcwMmMwLjE1NCwxMC4zOSwwLjE1NCwxMC4zOS04LjEwNiwxMC4zOSBjLTcuMjcxLDAtMTQuNTQyLTAuMDI2LTIxLjgxMywwLjAxYy0zLjQ0NywwLjAxNy00LjQzOSwxLjI5Ni00LjQ1Miw1LjczNmMtMC4wMzksMTMuNjcxLTAuOTA4LDEyLjk1NSw5Ljc3MiwxMi45MTYgYzE3LjA3Ni0wLjA2MywzNC4xNTItMC4wMTIsNTEuMjI3LTAuMDJjNC4zMjktMC4wMDIsNS4wOTgtMS4wMiw1LjEtNi42M2MwLjAwMS0xLjk3Ny0wLjAzNy0zLjk1NiwwLjAwNy01LjkzMSBjMC4wOTQtNC4yODIsMS4xNzgtNS4zNzEsNC4xOTctNC45MzdjMS4wMzEsMTAuMDcsMS45MDksMTkuOTksMy4xMjksMjkuODQyYzAuNDI1LDMuNDI5LDEuMzEyLDYuOTgsMi42OTUsOS45MyBjMS4yLDIuNTYsMy4zODgsNS45OTMsNS4xNiw2LjAxM2MxLjc0NCwwLjAyLDQuNDY5LTMuMzgzLDUuMDk4LTUuOTU0YzIuMDI5LTguMjkyLDQuMDM3LTE2LjgwMiw0LjY2Ny0yNS4zOTUgYzAuODUtMTEuNjEyLDAuNTAxLTIzLjM3OSwwLjUxNy0zNS4wNzljMC4wNDItMzAuOTc3LDAuMDc4LTY4Ljc5OCwwLjExNS0xMDYuNTcyYzAuMDM3LTM3LjI0NiwwLjA3NS03NC40NDUsMC4xMjEtMTA0Ljk4OCBjMy4xMDUtMC4zMDQsNS4wNDUtMC42MzUsNS4wNDUtMC42MzVjMjkuODcyLTguNjU4LDQ2LjU1LTI5LjA2Miw1Mi4zMzgtNTkuMzgzYzExLjI4Myw4LjkzMSwxOC40MDksOS42ODMsMjQuODUyLDMuMzgyIEMxOTcuNzM5LDI4NS41MTIsMTk4LjczNywyNzYuOTQ1LDE5My44NiwyNzEuMjF6IE00NC4xODYsMTAwLjM4MWMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTRzNTQsMjQuMTc3LDU0LDU0IGMwLDI5LjgyMy0yNC4xNzcsNTQtNTQsNTRTNDQuMTg2LDEzMC4yMDUsNDQuMTg2LDEwMC4zODF6IE05OC4xODYsMzM0LjM4MWMtMjkuODIzLDAtNTQtMjQuMTc3LTU0LTU0YzAtMjkuODIzLDI0LjE3Ny01NCw1NC01NCBzNTQsMjQuMTc3LDU0LDU0QzE1Mi4xODYsMzEwLjIwNSwxMjguMDA5LDMzNC4zODEsOTguMTg2LDMzNC4zODF6XCIsXG4gICAgICAgIGNsb2Nrczoge1xuICAgICAgICAgICAgc2l6ZTogMTA4LFxuICAgICAgICAgICAgMDogeyB4OiA5OC41NzksIHk6IDI4MCB9LFxuICAgICAgICAgICAgMTogeyB4OiA5OC41NzksIHk6IDEwMCB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIDM6IHtcbiAgICAgICAgaGVpZ2h0OiA5MTUuOTM2LFxuICAgICAgICB3aWR0aDogMjc3LjYzNCxcbiAgICAgICAgcGF0aDogXCJNMjYzLjc1MiwyNTcuODM2Yy0xMy43MTksMS41MDgsMy4zNDUtMTUuNTE1LDMuOTU1LTIzLjEwOWwtMC4xMTMsMC4xMTMgYzguMTI3LTIyLjU3NCwyLjc1LTQ2LjA3OS0xMC44MDItNjUuNjA4YzE0LjM2NS0xLjczNSwxOS45ODEtNi4yODcsMjAuMTIyLTE1LjMzOWMwLjExOC03LjYxNy01LjIyOC0xNC4zODgtMTIuNzYyLTE0Ljk2MyBjLTMuNDUxLTAuMjYzLTcuNDEyLDAuNjM2LTEwLjQ5NiwyLjI0NWMtNi4zNjksMy4zMjQtNi44OTYsMTAuMDAxLTcuMjQ4LDE3LjY3Yy0xMi4xNDYtOC4xNTctMjQuMzI5LTEyLjk4OC0zNi41NzUtMTQuMzQgYy0yLjk0LTIuNTQtNC4yNjQtNi4yMzYtMy44NzktMTAuOTk3YzAuNDUxLTUuNTg3LDAuMjM5LTExLjA2Ni0wLjU3Mi0xNi4zNTljMC44MjgtMi44NzIsMS41NDktNS44NDcsMi4xNTYtOC45MzQgYzUuNjcyLDUuMTc0LDEwLjc2Niw5LjUyMywxNy42Miw3LjM2OWMzLjMxOS0xLjA0Myw2Ljc1NS0zLjIwOCw5LjAwOS01LjgzNWM0LjkyMS01LjczNCwzLjkxNC0xNC4zMDItMS41NTYtMTkuNjA1IGMtNi41LTYuMzAxLTEzLjY5LTUuNTQ5LTI1LjA3NSwzLjM4MmMtNS4wNTUtMzAuNTc4LTI1Ljk2Ny01MS42Mi01NC42MTktNjAuMDQ3Yy0yLjQ0Ny0wLjczMi00LjgwNy0yLjAyMy03LjgyNS0zLjI3OCBjMi4xMjUtMi4yODYsMy4yOS0zLjQ2MSw0LjM2Ny00LjcxYzExLjkzOC0xNC41NTEtNy4xNS0zMy4xODEtMjEuMzY3LTIxLjExMWMtNi4xNjUsNS41NjUtNi44NzksMTQuNTEzLTEuNjY1LDIwLjg2NCBjNC4xOTcsNS4xMTEsMy45NDYsNS40MTEtMi41MTYsOC4wNjhjLTEuODEyLDAuNzQ1LTMuNjQyLDEuNDY3LTUuNDc0LDIuMTljLTI0LjY0NSw3LjY0OC00MC45NDgsMjUuMjEtNDYuODg2LDQ5LjU5NSBjLTAuNjgsMi42OTgtMi4xMDIsNS4yMDgtMy40NzMsOC41MDVjLTIuMjg2LTIuMTI1LTMuNDYxLTMuMjktNC43MS00LjM2N2MtMTQuNTUyLTExLjkzOC0zMy4xOCw3LjE1Mi0yMS4xMTEsMjEuMzY3IGM1LjU2NSw2LjE2NSwxNC41MTMsNi44NzksMjAuODY0LDEuNjY1YzQuNzEtMy44NjcsNS4zMzgtMy45NDQsNy40ODcsMS4xMjNjLTEuMzA5LDYuNDY1LTEuNzQsMTMuMTc0LTEuMzk2LDIwLjEwMiBjMC4zLDYuMDMtMS40OTcsMTAuMDk3LTUuMzU2LDEyLjYxN2MtOC44ODksMi4wNDQtMTcuMTQ4LDYuMTMyLTI1LjU2Nyw5LjY1NmMtNi40NDgsMi42OTEtNi44MzcsMi42NTYtNy40ODQtMy45MjYgYy0wLjgwNC04LjE3OC03LjYzNi0xNC0xNS45MzEtMTMuNTc2Yy0xOC41ODEsMS41MTYtMTguOTE4LDI4LjE4Ny0wLjE4MSwzMC4wMzZjMS42NDUsMC4xMjIsMy4yOTksMC4xMjksNi40MTksMC4yNDMgYy0xLjM2NiwzLjMxOS0yLjExMyw1Ljk5Mi0zLjU1OCw4LjQ3Yy0zLjQyOCw1Ljc0LTYuMTIzLDExLjY4My03LjkxMiwxNy44MTFjLTQuNzIyLDE2LjE1NC0yLjUzMywzNC42MDIsNS45OTYsNTAuNDExIGMxLjgwMSw1LjY5MSw4LjU2OSwxMy4zOTItMS42MDMsMTIuOTAzYy00MCwxMi45NzEsMTguNDE2LDU0LjExNCwxNi43MDQsOS42OTFjMzQuNzgyLDMuMjI1LDQ2LjY5Miw0MS45Miw4MC40NDcsNDkuNjc0IGM3Ljk2MywyLjc5MSwxMS4xNzksNi42NzEsMTIuMDQ2LDEzLjcyNGMwLjAxMiwzLjI0MSwwLjAxLDYuNTAzLDAsOS44MjloLTAuMjIzYzAsMi4wODYsMCw1LjMwOSwwLDUuMzA5czAuMDY1LDAuMTg0LTAuMDY5LDAuMjY4IGMtNy4yMTEtMC4wMDItMTQuMDA1LTAuMDQxLTIwLjc5LDAuMDE1Yy00LjQ4MywwLjAzNy02LjE1NCwxLjA5LTYuNTkyLDQuNjY3Yy0wLjM1Miw0LjYzOC0wLjA0Myw5LjQ1LTAuMTMxLDE0LjEyMiBjMC4wNjIsNS4yNzQsMS40OSw2LjY5LDYuODYxLDYuNzI0YzYuOTk5LDAuMDQ1LDEzLjk5OCwwLjAxMSwyMS43MjEsMC4wMTF2NS42NzFjLTcuNzIzLDAtMTQuNzIyLTAuMDM0LTIxLjcyMSwwLjAxMSBjLTUuMzcyLDAuMDM1LTYuNzk5LDEuNDUtNi44NjEsNi43MjRjMC4wODcsNC42NzEtMC4yMjEsOS40ODQsMC4xMzEsMTQuMTIyYzAuNDM4LDMuNTc3LDIuMTA5LDQuNjMsNi41OTIsNC42NjcgYzYuNzg1LDAuMDU2LDEzLjU3OSwwLjAxNywyMC43OSwwLjAxNWMwLjEzNCwwLjA4NCwwLjI3OSwwLjE3NSwwLjA2OSwwLjI2OHY1LjQwNmgwLjU5OWMwLjAzMSwzLjc4NCwwLjAzMSw3LjYxOSwwLDEyaC0wLjU5OSB2NC44MDljMCwwLDAuMDY1LDAuMTg0LTAuMDY5LDAuMjY4Yy03LjIxMS0wLjAwMi0xNC4wMDUtMC4wNDEtMjAuNzksMC4wMTVjLTQuNDgzLDAuMDM3LTYuMTU0LDEuMDktNi41OTIsNC42NjcgYy0wLjM1Miw0LjYzOC0wLjA0Myw5LjQ1LTAuMTMxLDE0LjEyMmMwLjA2Miw1LjI3NCwxLjQ5LDYuNjksNi44NjEsNi43MjRjNi45OTksMC4wNDUsMTMuOTk4LDAuMDExLDIxLjcyMSwwLjAxMXY1LjY3MSBjLTcuNzIzLDAtMTQuNzIyLTAuMDM0LTIxLjcyMSwwLjAxMWMtNS4zNzIsMC4wMzUtNi43OTksMS40NS02Ljg2MSw2LjcyNGMwLjA4Nyw0LjY3MS0wLjIyMSw5LjQ4NCwwLjEzMSwxNC4xMjIgYzAuNDM4LDMuNTc3LDIuMTA5LDQuNjMsNi41OTIsNC42NjdjNi43ODUsMC4wNTYsMTMuNTc5LDAuMDE3LDIwLjc5LDAuMDE1YzAuMTM0LDAuMDg0LDAuMjc5LDAuMTc1LDAuMDY5LDAuMjY4djQuOTA2aDAuNTk5IGMwLjAzMSw0LjI4NCwwLjAzMSw4LjExOSwwLDEyaC0wLjU5OXY1LjMwOWMwLjIxMSwwLjA5MiwwLjA2NSwwLjE4NC0wLjA2OSwwLjI2OGMtNy4yMTEtMC4wMDItMTQuMDA1LTAuMDQxLTIwLjc5LDAuMDE1IGMtNC40ODMsMC4wMzctNi4xNTQsMS4wOS02LjU5Miw0LjY2N2MtMC4zNTIsNC42MzgtMC4wNDMsOS40NS0wLjEzMSwxNC4xMjJjMC4wNjIsNS4yNzQsMS40OSw2LjY5LDYuODYxLDYuNzI0IGM2Ljk5OSwwLjA0NSwyMS43MjEsMC4wMTEsMjEuNzIxLDAuMDExdjUuNjcxYzAsMC0xNC43MjItMC4wMzQtMjEuNzIxLDAuMDExYy01LjM3MiwwLjAzNS02Ljc5OSwxLjQ1LTYuODYxLDYuNzI0IGMwLjA4Nyw0LjY3MS0wLjIyMSw5LjQ4NCwwLjEzMSwxNC4xMjJjMC40MzgsMy41NzcsMi4xMDksNC42Myw2LjU5Miw0LjY2N2M2Ljc4NSwwLjA1NiwxMy41NzksMC4wMTcsMjAuNzksMC4wMTUgYzAuMTM0LDAuMDg0LDAuMjc5LDAuMTc1LDAuNDU3LDAuMjY4YzAsMS41OTQsNC41NTksMTY4LjIyOCw0LjUxLDIwOS4yODZjLTAuMDA1LDQuMSwwLjQ0Miw5LjEyOCwwLjQ0MiwxMC4yNTkgYy0zLjM5NiwwLTYuMjM0LDAuMTMzLTkuMDU0LTAuMDM0Yy0zLjQ5OS0wLjIwNi01LjM3LDEuNDU2LTYuNzM1LDQuNTU4Yy0xLjI4MSwyLjkxMy0yLjgwMyw1Ljg2Ni00Ljg0Myw4LjI3IGMtNi41OCw3Ljc1MS0xNi41NzgsNy44NC0yMy4yMDYsMC4xNDRjLTIuMjA5LTIuNTY1LTMuNzM2LTUuODEtNS4xNjktOC45MzJjLTEuMjM5LTIuNjk5LTIuOTM5LTQuMDgzLTUuOTE2LTQuMDI0IGMtMy43MTIsMC4wNzMtNy40MjgsMC4wNzgtMTEuMTQtMC4wMDljLTMuMTYzLTAuMDc0LTQuOTM2LDEuNDMyLTYuMTQzLDQuMzA2Yy0xLjE0MSwyLjcxNi0yLjQ3Niw1LjQ2OS00LjI4NSw3Ljc2NCBjLTguNzI1LDExLjI4MS0yMy4wMSw2LjkyMy0yNy45NjYtNS4zNTdjLTEuNDk2LTUuNjI4LTUuMDM5LTcuMjc0LTEwLjUyMS02Ljc2N2MtNC40ODUsMC40MTUtNi4yODUsMS45MzctNi4yODYsNi42MTIgYy0wLjAwMSwxNS43NTUtMC4wMDIsMzEuNTExLTAuMDAzLDQ3LjI2NmMtMC4wMDEsMTYuMzc2LTAuMDEyLDMyLjc1MiwwLjAwNiw0OS4xMjdjMC4wMDQsMy42NDYsMi4wMzksNS43MDYsNS41ODYsNS43NjUgYzQuMjQ0LTAuMTUxLDcuNzI0LDEuMDc4LDkuNzQ3LTMuNzJjMS42My0zLjU2NiwzLjMxLTcuMjk3LDUuODExLTEwLjIzOWM1LjkyNy02Ljk2OSwxNS4yNS03LjM5NiwyMS41OTYtMC44MjcgYzIuOTEsMy4wMTIsNC44ODUsNy4wNzgsNi43MTYsMTAuOTM2YzEuMjQ1LDIuNjIzLDIuNzQ4LDMuODk2LDUuNTczLDMuODU3YzMuOTYtMC4wNTUsNy45MjUtMC4xMDIsMTEuODgyLDAuMDI3IGMzLjA0MSwwLjA5OSw0LjYyOS0xLjM1OSw1LjkxNC00LjAxMWMxLjM4Ni0yLjg2MSwzLjAxNi01Ljc2Niw1LjE2Ni04LjA2M2MxMC4xMDctMTAuNDEyLDIyLjI1NC0zLjcxOCwyNy4xMzksOC4wMzcgYzEuMzM3LDIuOTA3LDMuMTgsNC4xNDEsNi4yODEsNC4wMzRjMy40NDItMC4xMTksNi44OTEtMC4wMjcsMTAuNTIzLTAuMDI3YzEuMDY1LDUuNjUyLDIuMTY3LDExLjAyMSwzLjg1NiwxNi40NTMgYzEuMjI4LDMuNjc1LDIuNDA3LDguNTM2LDcuMDU2LDguNTk0YzQuOTIzLDAuMDYxLDYuMDQyLTQuOTg3LDcuMzA3LTguNzQzYzEuNDU2LTQuMzIyLDIuODY3LTguODQ3LDMuMTI1LTEzLjM1IGMwLjcyOC0xMi43MjEsMS4xNTItMjUuNDc3LDEuMTc0LTM4LjIxOWMwLjE5LTExMS40MDQsMC4yOTIsNTAuMTc3LDAuMzY2LTYxLjIyN2MwLjAwMy01LjEyOSwwLjIwMS0xOC40OSwwLjIwMS0yMi40NiBjMC00MS42OTMsNC4wOTgtMjAzLjI4Niw0LjA5OC0yMDkuNTU4YzguMTEyLDAsMTUuODItMC4wNTMsMjMuNTI4LDAuMDIxYzUuNTQ0LDAuMTMsNi42NC0zLjMyMyw2LjI4OC04LjIwMSBjMC4wMzMtMy41NDcsMC4wMzgtNy4wOTUtMC4wMDctMTAuNjQyYy0wLjA2Ni01LjI3OC0xLjQ3Ni02LjY2OS02Ljg4NS02LjcwMWMtNy41MjktMC4wNDQtMjMuMTIxLTAuMDExLTIzLjEyMS0wLjAxMXYtNS42NzEgYzAsMCwxNS41OTIsMC4wMzMsMjMuMTIxLTAuMDExYzUuNDA4LTAuMDMyLDYuODE5LTEuNDIzLDYuODg1LTYuNzAxYzAuMDQ0LTMuNTQ3LDAuMDQtNy4wOTUsMC4wMDctMTAuNjQyIGMwLjM1MS00Ljg4Mi0wLjc0Mi04LjMzLTYuMjg4LTguMjAxYy03LjcwNywwLjA3My0xNS40MTYsMC4wMjEtMjIuNzI0LDAuMDIxdi0yMi43NmM3LjMwOCwwLDE1LjAxNy0wLjA1MywyMi43MjQsMC4wMjEgYzUuNTQ0LDAuMTMsNi42NC0zLjMyMyw2LjI4OC04LjIwMWMwLjAzMy0zLjU0NywwLjAzOC03LjA5NS0wLjAwNy0xMC42NDJjLTAuMDY2LTUuMjc4LTEuNDc2LTYuNjY5LTYuODg1LTYuNzAxIGMtNy41MjktMC4wNDQtMTUuMDU5LTAuMDExLTIzLjEyMS0wLjAxMXYtNS42NzFjOC4wNjIsMCwxNS41OTIsMC4wMzMsMjMuMTIxLTAuMDExYzUuNDA4LTAuMDMyLDYuODE5LTEuNDIzLDYuODg1LTYuNzAxIGMwLjA0NC0zLjU0NywwLjA0LTcuMDk1LDAuMDA3LTEwLjY0MmMwLjM1MS00Ljg4Mi0wLjc0Mi04LjMzLTYuMjg4LTguMjAxYy03LjcwNywwLjA3My0xNS40MTYsMC4wMjEtMjIuNzI0LDAuMDIxdi0yMi43NiBjNy4zMDgsMCwxNS4wMTctMC4wNTMsMjIuNzI0LDAuMDIxYzUuNTQ0LDAuMTMsNi42NC0zLjMyMyw2LjI4OC04LjIwMWMwLjAzMy0zLjU0NywwLjAzOC03LjA5NS0wLjAwNy0xMC42NDIgYy0wLjA2Ni01LjI3OC0xLjQ3Ni02LjY2OS02Ljg4NS02LjcwMWMtNy41MjktMC4wNDQtMTUuMDU5LTAuMDExLTIzLjEyMS0wLjAxMXYtNS42NzFjOC4wNjIsMCwxNS41OTIsMC4wMzMsMjMuMTIxLTAuMDExIGM1LjQwOC0wLjAzMiw2LjgxOS0xLjQyMyw2Ljg4NS02LjcwMWMwLjA0NC0zLjU0NywwLjA0LTcuMDk1LDAuMDA3LTEwLjY0MmMwLjM1MS00Ljg4Mi0wLjc0Mi04LjMzLTYuMjg4LTguMjAxIGMtNy43MDcsMC4wNzMtMTUuNDE2LDAuMDIxLTIyLjcyNCwwLjAyMXYtMTMuODMxYzAuMzc5LTcuNjM4LDUuMTg2LTEzLjE0OSwxMy4xNjItMTUuODI1IGMyOC40NTYtNy4xMDQsNDEuODA4LTMzLjM1Miw2NC44ODgtNDguMjg3YzE3LjQ5Mi0xMC43NDMsOS4zNTQsMjIuOTM3LDI4LjUxOCwxOS4xMjkgQzI4Mi4xMjcsMjg2LjMwOSwyODIuNDU1LDI1OS42ODEsMjYzLjc1MiwyNTcuODM2eiBNMTA1LjY5Nyw4MzkuMDc0YzAuNDk4LDIuMzgsMC4xNSw0LjkzNC0zLjMwMiw0Ljg4NCBjLTIuMjk1LTAuMDMzLTMuMTc2LDEuMDQyLTMuNzAyLDMuMjE3Yy0wLjI2LDEuMDc2LTEuNzEzLDIuMzgzLTIuNzkzLDIuNTU5Yy0wLjcyMywwLjExOC0yLjM2LTEuNDc5LTIuNTA1LTIuNDY3IGMtMC40MDktMi44MDQtMi4wMDQtMy4zNDQtNC4zODUtMy4yOTljLTMuNzA5LDAuMDctNy40MjQsMC4xMTYtMTEuMTMxLTAuMDA2Yy0zLjgzLTAuMTI2LTMuOTQ1LDIuMjc4LTMuOTgxLDUuMTMgYy0wLjAzOCwyLjk3NiwwLjc1NSw0LjgyNiw0LjE0Miw0LjU4OWMxLjQ3Ny0wLjEwMywyLjk2OCwwLjAxNSw0LjQ1MS0wLjAyNWMyLjIwMi0wLjA1OSw0LjU0My0wLjAwNiw0LjU3OSwyLjkwMSBjMC4wMzksMy4xODctMi40NzcsMy4xMTktNC43OCwzLjA2OGMtMS4zNi0wLjAzLTIuNzI4LDAuMDgyLTQuMDgtMC4wMjVjLTMuMjU4LTAuMjU3LTQuNSwxLjMxMi00LjI3Miw0LjQyNSBjLTAuMDQxLDQuMzUzLDEuMDI3LDguMDI4LTQuODgzLDcuNTA2Yy03LjAyMiwwLjAzOS03Ljk1MSwwLjgwMi03LjU0My03LjQwNWMwLjE2OS0zLjM5LTEuMTkyLTQuODU1LTQuNTU0LTQuNTI0IGMtMC44NTcsMC4wODUtMS45MjIsMC4zMjktMi41NTUtMC4wNTZjLTEuMi0wLjcyOS0yLjE1Ni0xLjg2MS0zLjIxMy0yLjgyNWMxLjAwNi0xLjAxNywxLjk0NC0yLjEyMSwzLjA1Ny0zLjAwNCBjMC4zOC0wLjMwMSwxLjE5OS0wLjA0MiwxLjgxNy0wLjA0NGM1LjAwNy0wLjAyMiw3LjEzMS0yLjk4Niw1LjE5Ni03LjY0NmMtMC4zOTItMC45NDUtMS45NzQtMS43ODUtMy4xMS0xLjk0NCBjLTMuNjUxLTAuNDM3LTcuNDQyLDAuMTU4LTExLjExNy0wLjEyMWMtMy43ODYtMC4zODctNS44OTQsMC43MjEtNS42OTgsNS4wNjFjMC4wNDUsMC45OTYtMS43OCwyLjA3Ny0yLjc0NCwzLjExOSBjLTAuODQ4LTEuMDM4LTIuNDUxLTIuMTA1LTIuNDEyLTMuMTA4YzAuMTUzLTMuOTMyLTEuNDQ1LTUuMjctNS4yNjktNS4yMjVjLTEuMDE3LDAuMDEyLTIuNDkxLTEuODk5LTIuOTczLTMuMjE1IGMtMC41Mi0xLjQyMS0wLjEyNy0zLjE4LTAuMTI2LTQuNzkxYzAtNS4yNC0wLjAwMi01LjI2OCw1LjMtNS45NTRjMi4zNjYtMC4zMDYsMy4wMjMtMS43ODcsMi45MjctMy44ODkgYy0wLjA5OC0yLjE0MywwLjI2OC00LjQyNSwyLjg0OC00LjA3M2MxLjAzNCwwLjE0MSwyLjM0MiwyLjUyOCwyLjQ5LDMuOTk4YzAuMjgyLDIuNzg4LDEuMzE0LDQuMDM5LDQuMTMxLDMuOTc2IGMzLjk1Ni0wLjA4OCw3LjkxOS0wLjEyNSwxMS44NzMsMC4wMTFjMy4wNjMsMC4xMDUsNC4xNjgtMS4yMDQsNC4xMy00LjIxMmMtMC4wMzYtMi44MTYtMC4zMjYtNS4wNDEtMy45MTYtNC43NTUgYy0yLjU1OSwwLjIwMy00LjQ2OC0wLjQ3NC00LjM2Ny0zLjUyN2MwLjA5NS0yLjg2NSwyLjAxNi0zLjM0NCw0LjM1OC0zLjE3M2MyLjg5OCwwLjIxMiwzLjg0OS0xLjI0MywzLjk3OS00LjAxOSBjMC4wODUtMS44MjEsMC43My01LjAwMiwxLjU2My01LjE1M2MzLjA0Ni0wLjU1Myw2LjMwOC0wLjMxLDkuNDA4LDAuMTY1YzAuNjQ2LDAuMDk5LDEuMjg0LDIuNDUzLDEuMzQ1LDMuNzk1IGMwLjIyNCw0Ljk2NywwLjM3NCw1LjIwNyw1LjQwMSw1LjIxNGMxLjM2MSwwLjAwMiwyLjkyOS0wLjQyMiw0LjAyNywwLjExNmMxLjI3MSwwLjYyMywyLjk0LDIuMDksMi45NDIsMy4xOTQgYzAuMDAyLDEuMTI1LTEuNjIxLDIuODE1LTIuODc2LDMuMjQxYy0xLjY2NSwwLjU2NS0zLjY2NywwLjIyMy01LjUxOCwwLjEzMmMtMy4xOC0wLjE1Ny0zLjk3MSwxLjU3LTMuOTUyLDQuMzk4IGMwLjAxOSwyLjcwMywwLjQ5NSw0LjY0LDMuNzgzLDQuNTY5YzMuOTU2LTAuMDg1LDcuOTE2LTAuMDU1LDExLjg3My0wLjAxMmMyLjE2NSwwLjAyNCwzLjMyMi0wLjc2MywzLjgyNi0zLjA2OCBjMC4yNDEtMS4xMDUsMS43NzEtMS45MjcsMi43MTgtMi44NzdjMC45MDUsMC45NzEsMi4zMzMsMS44MTQsMi42MDUsMi45MzljMC41NDUsMi4yNTYsMS43NTcsMi43LDMuODQzLDMuMTExIEMxMDguNDAxLDgzMS4xMDIsMTA1LjAzNSw4MzUuOTE0LDEwNS42OTcsODM5LjA3NHogTTEzOS4xMDgsNDZjMjkuODIzLDAsNTQsMjQuMTc3LDU0LDU0YzAsMjkuODIzLTI0LjE3Nyw1NC01NCw1NCBzLTU0LTI0LjE3Ny01NC01NEM4NS4xMDgsNzAuMTc2LDEwOS4yODUsNDYsMTM5LjEwOCw0NnogTTE5LjEwOCwyMTJjMC0yOS44MjMsMjQuMTc3LTU0LDU0LTU0czU0LDI0LjE3Nyw1NCw1NCBjMCwyOS44MjMtMjQuMTc3LDU0LTU0LDU0UzE5LjEwOCwyNDEuODIzLDE5LjEwOCwyMTJ6IE0xNDQuOTQ0LDg1Ny44OThjLTIuMDksMi41NzgtMS44NjUsNS4xNzYtMS45NDIsNy45NTMgYy0wLjAyNCwwLjg1NCwwLjEzMSwxLjkxNC0wLjMwMiwyLjUwOWMtMi40MDMsMy4xNDctMy4xNTksMi44MDktNS40MzYtMC4xODVjLTAuMjY0LTAuMzA2LTAuMTc4LTAuOTQ4LTAuMTg0LTEuNDM3IGMtMC4wNDEtMy4yNzEsMC41MzYtNi42NTctMi4zNjktOS4yNTNjLTAuNTMxLTAuNDc1LTAuNDc5LTEuNjA1LTAuOTU3LTMuNDI1YzEuMjEtMS4yNzEsMi40Ny0zLjMwNiw0LjI5NC00LjMzMyBjMi4zNzktMS4zMzksNS4yMzYtMC41OCw2LjQ0MSwxLjgxOUMxNDUuNDA1LDg1My4zNjcsMTQ1Ljk1LDg1Ni42NTgsMTQ0Ljk0NCw4NTcuODk4eiBNMTQ0Ljk5Niw4MDcuOTQxIGMtMi4yMjQsMi42NzctMS44NzcsNS40MzgtMS45OTIsOC4zMThjLTAuMDg2LDIuMTQ2LTAuMiw0LjU3OC0yLjk5LDQuNTQ0Yy0yLjc2NS0wLjAzNC0yLjg3NC0yLjQ3NS0yLjkzMy00LjYxNCBjLTAuMDgtMi44OTUsMC41NDMtNS45MTktMi4xNzktOC4xOTNjLTAuNjMxLTAuNTI3LTAuNjQ1LTEuNzk3LTEuMjM0LTMuNjMzYzEuMjY1LTEuMzgyLDIuNDgtMy40NjUsNC4yOTItNC41IGMyLjM0MS0xLjMzOCw1LjIzMy0wLjY0OSw2LjQ3NiwxLjczMUMxNDUuMzgyLDgwMy40MDQsMTQ1Ljk5MSw4MDYuNzQ0LDE0NC45OTYsODA3Ljk0MXogTTgwLjA2MiwyNzkuNjk0IGMxNy4xNzEtMy41ODIsNTYuMjM0LTI1LjQ0Niw1OS4yOTYtNTAuNDg3YzUuNTE4LDIyLjExNCwzMCw0OC43MjksNjEsNDguNzI5QzE2Mi43NywzMTkuNzczLDEyMC40MzEsMzIxLjI4LDgwLjA2MiwyNzkuNjk0eiBNMjA1LjEwOCwyNjZjLTI5LjgyMywwLTU0LTI0LjE3Ny01NC01NGMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTRzNTQsMjQuMTc3LDU0LDU0QzI1OS4xMDgsMjQxLjgyMywyMzQuOTMyLDI2NiwyMDUuMTA4LDI2NnpcIixcbiAgICAgICAgY2xvY2tzOiB7XG4gICAgICAgICAgICBzaXplOiAxMDgsXG4gICAgICAgICAgICAwOiB7IHg6IDEzOC44OTIsIHk6IDEwMCB9LFxuICAgICAgICAgICAgMTogeyB4OiA3Mi44OTIsIHk6IDIxMiB9LFxuICAgICAgICAgICAgMjogeyB4OiAyMDQuODkyLCB5OiAyMTIgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICA0OiB7XG4gICAgICAgIGhlaWdodDogMTA0MSxcbiAgICAgICAgd2lkdGg6IDM2OC42OTcsXG4gICAgICAgIHBhdGg6IFwiTTM2NS45NDksMTc4Ljg4MmMtMi4xNTktMi43MDUtNS40NjQtNS4wMzgtOC43MjUtNi4yMDFjLTcuMjExLTIuNTctMTIuNjM0LDEuNzk0LTE4LjE1NSw3LjI2MSBjLTEuMDA4LTMuMTgyLTEuODExLTUuMjkyLTIuMzQ2LTcuNDY4Yy03LjIwNy0yOS4zMTEtMjUuNjc2LTQ2Ljk5My01NS4wNTItNTMuMTQyYy0zLjU2NS0wLjc0Ni00LjMzNy0yLjM2NS01LjcyMS01LjUyNSBjLTEwLjkxNy0yNC45MjgtMTUuOTE3LTMyLjkyOC0zMS44NjMtNDkuNDA4Yy0xLjYyNS0xLjY3OS0zLjQ1My0zLjE5Mi01LjE0NC00Ljc2MWMtMTUuOTA5LTE0Ljc1OC0yMC45MDktMTcuNzU4LTQzLjQ5Mi0yNi43MSBjLTEuODgyLTAuNzQ2LTMuNzgxLTEuNzgyLTYuODY2LTMuMzAyYzIuMzQ5LTEuODc2LDMuNjk0LTIuNjU5LDQuNjYyLTMuNzcyYzQuNjk1LTUuMzk3LDQuODM3LTEzLjQzNiwwLjQ1Mi0xOS4wMTQgYy01LjMtNi43NDItMTUtNy44MDYtMjEuNDU2LTIuMzU0Yy02LjcxNCw1LjY3LTcuMzA0LDE1LjQxNy0xLjMyOCwyMS45MTljMy42MTcsMy45MzUsMy4yOTcsNS4zNjEtMS43MjUsNy4xNTMgYy0yLjA0NCwwLjczLTQuMTcsMS4yMjYtNi4yMzcsMS44OTZjLTEyLjc2Niw0LjEzNy0yMy4yNTUsMTEuNjA0LTMxLjkxOCwyMS43OThjLTIuMzcyLDIuNzkxLTQuNzc4LDUuNjIyLTcuNTM5LDguMDAyIGMtMTUuNTY0LDEzLjQxMy0yNi4xNjYsMjkuODk1LTMxLjEwOCw0OS45MDRjLTAuNjgsMi43NTItMS43NDEsNC4wODQtNC44MjUsNC41NGMtMjkuMDUzLDQuMjk5LTUxLjQ2MSwyNS44MDktNTcuMTYsNTQuNTU2IGMtMC4zMDcsMS41NDktMC43OTIsMy4wNjItMS4yNSw0LjgwNmMtMTEuMzUtOC4zMDItMTgtOC45OTgtMjQuNDAxLTIuODYyYy01LjMyMSw1LjEwMS02LjQ2NywxMy4zOTgtMS45MzUsMTkuMjAzIGMyLjAzNiwyLjYwOCw1LjE5Miw0LjgzNiw4LjMwMiw2LjAwNWM3LjEzNywyLjY4MywxMi41OS0xLjU3OSwxNy43MzUtNi4zNTNjMC41ODMsMS4yOTksMS4wMSwxLjg3NCwxLjA5NiwyLjQ5NiBjNC4wNDYsMjkuMzE1LDI3Ljk5Nyw1My4yNzcsNTcuODI1LDU3LjM5M2MyLjIyMywwLjMwNyw0LjA2MiwxLjg3NCw0LjY0NCw0LjA0MWMxLjMwOCw0Ljg2MSwyLjg5MSw5LjY4Miw0Ljc4NywxNC4zNDUgYzkuNDMyLDIzLjE5OCwyOC44MTEsMzguMjAzLDQ1LjgyMyw1NS4wODRjNS4xMDQsNS4wNjUsMTEuMjA0LDkuMTk3LDE3LjE1NiwxMy4zMDhjNS41NjMsMy44NDIsNy43OTIsOC4zOTEsNy43ODgsMTUuNDU2IGMtMC4xMjksMTg4LjI1NC0wLjAwNCwzMDguNTA4LDAuMDY1LDQ5Ni43NjJjMCwwLjEwMi0wLjAwNSwwLjIwNS0wLjAwNiwwLjMwN3Y0MS4yNDFjLTIuNzAxLDAuMDI2LTUuMTAyLDAuMDkyLTcuNDYxLTAuMDQ3IGMtMy40OTktMC4yMDYtNS4zNywxLjQ1Ni02LjczNSw0LjU1OGMtMS4yODIsMi45MTMtMi44MDMsNS44NjYtNC44NDQsOC4yN2MtNi41ODEsNy43NTEtMTYuNTc4LDcuODQtMjMuMjA2LDAuMTQ0IGMtMi4yNTQtMi42MTctMy43OTctNS45NC01LjI1NS05LjExOWMtMS4wODctMi4zNjktMy40NzItMy44ODItNi4wNzgtMy44MzNjLTMuNjMsMC4wNjgtNy4yNjMsMC4wNzEtMTAuODkzLTAuMDEzIGMtMy4xNjMtMC4wNzQtNC45MzYsMS40MzItNi4xNDMsNC4zMDZjLTEuMTQxLDIuNzE2LTIuNDc2LDUuNDY5LTQuMjg1LDcuNzY0Yy04LjcyNSwxMS4yODEtMjMuMDEsNi45MjMtMjcuOTY2LTUuMzU3IGMtMS40OTYtNS42MjgtNS4wMzktNy4yNzQtMTAuNTIxLTYuNzY3Yy00LjQ4NSwwLjQxNS02LjI4NSwxLjkzNy02LjI4Niw2LjYxMmMtMC4wMDEsMTUuNzU1LTAuMDAyLDMxLjUxMS0wLjAwMyw0Ny4yNjYgYy0wLjAwMSwxNi4zNzYtMC4wMTIsMzIuNzUyLDAuMDA2LDQ5LjEyN2MwLjAwNCwzLjY0NiwyLjAzOSw1LjcwNiw1LjU4Niw1Ljc2NWM0LjI0NC0wLjE1MSw3LjcyNCwxLjA3OCw5Ljc0Ny0zLjcyIGMxLjYzLTMuNTY2LDMuMzEtNy4yOTcsNS44MTEtMTAuMjM5YzUuOTI3LTYuOTY5LDE1LjI1LTcuMzk2LDIxLjU5Ni0wLjgyN2MyLjkxLDMuMDEyLDQuODg1LDcuMDc4LDYuNzE2LDEwLjkzNiBjMS40NTcsMy4wNzEsMy4yNjksNC4yOTIsNy4xNCwzLjcyM2MyLjg5Ny0wLjQyNiw1Ljg0NC0wLjUwNiw4LjczLTAuMDA5YzQuMTA4LDAuNzA4LDYuMDA3LTAuNzYyLDcuNDk5LTMuODQgYzEuMzg2LTIuODYxLDMuMDE2LTUuNzY2LDUuMTY2LTguMDYzYzEwLjEwNy0xMC40MTIsMjIuMjU0LTMuNzE4LDI3LjEzOSw4LjAzN2MxLjMzNywyLjkwNywzLjE4MSw0LjE0MSw2LjI4MSw0LjAzNCBjMi43MTUtMC4wOTQsNS40NDYtMC4wNTgsOC4yNTctMC4wMzh2Mi4wOTFjMC4zMTksMC4wMDEsMC42MzEsMC4wMDQsMC45NTEsMC4wMDRjMC4zNjIsMi4xMSwwLjQ3MywzLjc4NiwwLjk0Nyw1LjM1MiBjMi40MSw3Ljk3Miw0LjE5LDE2LjI0NCw3LjU5NiwyMy43NzNjMy4xNjgsNy4wMDUsOS4yODksNi45MDEsMTIuNzA5LTAuMDExYzIuOTMyLTUuOTI1LDUuMTM0LTEyLjM5NSw2LjUyNS0xOC44NjggYzQuMDEtMTguNjYyLDIuNjc1LTM3LjY2NCwyLjY5Ni01Ni41NjdjMC4xMzMtMTE4Ljg1MywwLjMxNCwwLjI5NSwwLjM5Mi0xMTguNTU4YzAuMDY4LTEwMy45MzQsMC4wMTMtMzc3Ljg2NywwLjA2NC00ODEuODAxIGMwLjAwMS0yLjc4MS0wLjI4MS02LjEyNSwxLjA3My04LjI0YzQuODg2LTcuNjM0LDguOTc4LTE1Ljg1MSwxOC4xNjgtMjAuMDU4YzUuMTM5LTIuMzUyLDkuMjU3LTcuMDQ1LDEzLjY1Mi0xMC44OTMgYzQuMjY3LTMuNzM2LDguMTYtNy45MDQsMTIuNDU5LTExLjU5OWMxNS40NTItMTMuMjc4LDI2LjAyMy0yOS42MTksMzAuODg1LTQ5LjQ1MWMwLjkwOS0zLjcwNywyLjkyNi00LjU5OCw2LjE2MS01LjczIGM4Ljc2NC0zLjA2NywxNy45NDMtNS43NzUsMjUuNzQyLTEwLjU5OGMxNC44Mi05LjE2NCwyMy44MjItMjMuMTYyLDI4LjI2My00MC4wNzFjMC43MDMtMi42NzgsMS45MDktNS4yMjMsMi45OTEtOC4xMjIgYzExLjA3Niw4LjU5NiwxOC4wMDYsOS4zMjgsMjQuNDg5LDMuMjIzQzM2OS4xODcsMTkyLjk1MywzNzAuNDY0LDE4NC41MzgsMzY1Ljk0OSwxNzguODgyeiBNMTQ2Ljc2NSw5NTIuNTM5IGMwLjQ5OCwyLjM4LDAuMTUsNC45MzQtMy4zMDIsNC44ODRjLTIuMjk0LTAuMDMzLTMuMTc2LDEuMDQyLTMuNzAyLDMuMjE3Yy0wLjI2LDEuMDc2LTEuNzEzLDIuMzgzLTIuNzkzLDIuNTU5IGMtMC43MjMsMC4xMTgtMi4zNi0xLjQ3OS0yLjUwNC0yLjQ2N2MtMC40MDktMi44MDQtMi4wMDQtMy4zNDQtNC4zODQtMy4yOTljLTMuNzA5LDAuMDctNy40MjQsMC4xMTYtMTEuMTMxLTAuMDA2IGMtMy44My0wLjEyNi0zLjk0NSwyLjI3OC0zLjk4MSw1LjEzYy0wLjAzOCwyLjk3NiwwLjc1NSw0LjgyNiw0LjE0Miw0LjU4OWMxLjQ3Ny0wLjEwMywyLjk2OCwwLjAxNSw0LjQ1MS0wLjAyNSBjMi4yMDItMC4wNTksNC41NDMtMC4wMDYsNC41NzksMi45MDFjMC4wNCwzLjE4Ny0yLjQ3NywzLjExOS00Ljc4LDMuMDY4Yy0xLjM2LTAuMDMtMi43MjgsMC4wODItNC4wOC0wLjAyNSBjLTMuMjU4LTAuMjU3LTQuNSwxLjMxMi00LjI3Miw0LjQyNWMtMC4wNDEsNC4zNTMsMS4wMjcsOC4wMjgtNC44ODMsNy41MDZjLTcuMDIyLDAuMDM5LTcuOTUxLDAuODAyLTcuNTQyLTcuNDA1IGMwLjE2OC0zLjM5LTEuMTkyLTQuODU1LTQuNTU1LTQuNTI0Yy0wLjg1NywwLjA4NS0xLjkyMiwwLjMyOS0yLjU1NS0wLjA1NmMtMS4yLTAuNzI5LTIuMTU2LTEuODYxLTMuMjEzLTIuODI1IGMxLjAwNi0xLjAxNywxLjk0NC0yLjEyMSwzLjA1Ny0zLjAwNGMwLjM3OS0wLjMwMSwxLjE5OS0wLjA0MiwxLjgxNy0wLjA0NGM1LjAwNy0wLjAyMiw3LjEzMS0yLjk4Niw1LjE5Ny03LjY0NiBjLTAuMzkzLTAuOTQ1LTEuOTc1LTEuNzg1LTMuMTEtMS45NDRjLTMuNjUxLTAuNDM3LTcuNDQyLDAuMTU4LTExLjExNy0wLjEyMWMtMy43ODYtMC4zODctNS44OTQsMC43MjEtNS42OTgsNS4wNjEgYzAuMDQ1LDAuOTk2LTEuNzgsMi4wNzctMi43NDQsMy4xMTljLTAuODQ4LTEuMDM4LTIuNDUxLTIuMTA1LTIuNDEyLTMuMTA4YzAuMTUzLTMuOTMyLTEuNDQ1LTUuMjctNS4yNjktNS4yMjUgYy0xLjAxNywwLjAxMi0yLjQ5MS0xLjg5OS0yLjk3My0zLjIxNWMtMC41Mi0xLjQyMi0wLjEyNy0zLjE4LTAuMTI2LTQuNzkxYzAuMDAxLTUuMjQtMC4wMDItNS4yNjgsNS4zLTUuOTU0IGMyLjM2Ni0wLjMwNiwzLjAyMy0xLjc4NywyLjkyNy0zLjg4OWMtMC4wOTgtMi4xNDMsMC4yNjgtNC40MjUsMi44NDgtNC4wNzNjMS4wMzQsMC4xNDEsMi4zNDIsMi41MjgsMi40OSwzLjk5OCBjMC4yODIsMi43ODgsMS4zMTQsNC4wMzksNC4xMzEsMy45NzZjMy45NTYtMC4wODgsNy45MTktMC4xMjUsMTEuODcyLDAuMDExYzMuMDYzLDAuMTA1LDQuMTY4LTEuMjA0LDQuMTMtNC4yMTIgYy0wLjAzNS0yLjgxNi0wLjMyNi01LjA0MS0zLjkxNi00Ljc1NWMtMi41NTksMC4yMDMtNC40NjgtMC40NzQtNC4zNjctMy41MjdjMC4wOTUtMi44NjUsMi4wMTYtMy4zNDQsNC4zNTgtMy4xNzMgYzIuODk4LDAuMjEyLDMuODQ5LTEuMjQzLDMuOTc5LTQuMDE5YzAuMDg1LTEuODIxLDAuNzMtNS4wMDIsMS41NjMtNS4xNTNjMy4wNDYtMC41NTMsNi4zMDgtMC4zMSw5LjQwOCwwLjE2NSBjMC42NDYsMC4wOTksMS4yODQsMi40NTMsMS4zNDUsMy43OTVjMC4yMjQsNC45NjcsMC4zNzUsNS4yMDcsNS40MDIsNS4yMTRjMS4zNjEsMC4wMDIsMi45MjgtMC40MjMsNC4wMjcsMC4xMTYgYzEuMjcyLDAuNjIzLDIuOTQsMi4wOSwyLjk0MywzLjE5NGMwLjAwMiwxLjEyNS0xLjYyMSwyLjgxNS0yLjg3NiwzLjI0MWMtMS42NjYsMC41NjUtMy42NjgsMC4yMjMtNS41MTgsMC4xMzIgYy0zLjE4LTAuMTU3LTMuOTcxLDEuNTctMy45NTIsNC4zOThjMC4wMTksMi43MDMsMC40OTUsNC42NCwzLjc4Myw0LjU2OWMzLjk1Ny0wLjA4NSw3LjkxNi0wLjA1NSwxMS44NzQtMC4wMTIgYzIuMTY2LDAuMDI0LDMuMzIyLTAuNzYzLDMuODI2LTMuMDY4YzAuMjQyLTEuMTA1LDEuNzcxLTEuOTI3LDIuNzE4LTIuODc3YzAuOTA1LDAuOTcxLDIuMzMzLDEuODE0LDIuNjA1LDIuOTM5IGMwLjU0NSwyLjI1NiwxLjc1NywyLjcsMy44NDMsMy4xMTFDMTQ5LjQ2OSw5NDQuNTY2LDE0Ni4xMDQsOTQ5LjM3OSwxNDYuNzY1LDk1Mi41Mzl6IE0yNTIuNjIxLDk4Ljg5OCBjMC4yODctMC4xNjcsMC41NzQtMC4zMzQsMC44NjEtMC41MDJjMi44NDEsNi41MjEsNS42ODMsMTMuMDQyLDguNzM5LDIwLjA1NmMtNC43MTksMS4wMDItOC40MTQsMS43ODctMTIuNDQzLDIuNjQyIEMyNTAuNzU4LDExMy40NDYsMjUxLjY4OSwxMDYuMTcyLDI1Mi42MjEsOTguODk4eiBNMTg0LjEzNiw0Ni4xODhjMjkuODIzLDAsNTQsMjQuMTc3LDU0LDU0YzAsMjkuODIzLTI0LjE3Nyw1NC01NCw1NCBzLTU0LTI0LjE3Ny01NC01NEMxMzAuMTM2LDcwLjM2NSwxNTQuMzEzLDQ2LjE4OCwxODQuMTM2LDQ2LjE4OHogTTE2Mi4wOTcsMTY1LjkwM2MxNC4yMTgsMy43OTYsMjcuOTQ2LDQuNTY1LDQyLjQxNC0wLjA3MiBjLTMuOTQyLDE0LjQxNC00LjAwMSwyOC4wNjMsMC4zMDIsNDIuNTgzYy0xNC4xODktMy45Ni0yNy43NzktNC40ODctNDIuNTI3LTAuMDYyQzE2Ni41NDcsMTkzLjc4LDE2Ni40NDQsMTgwLjI4NiwxNjIuMDk3LDE2NS45MDMgeiBNMTE0LjA0OSw5OS42NDNjMC4yOTIsMC4xMzQsMC41ODMsMC4yNjksMC44NzUsMC40MDNjMS4wOTUsNy4xMzMsMi4xOSwxNC4yNjcsMy4zNzgsMjIuMDEgYy0zLjg1Mi0wLjg0My03Ljc0Ny0xLjY5NS0xMi40NTgtMi43MjZDMTA4LjY5LDExMi41MDIsMTExLjM2OSwxMDYuMDcyLDExNC4wNDksOTkuNjQzeiBNMTE0LjA5LDI3NS4xNyBjLTIuOTkyLTcuMjk5LTUuNDQ2LTEzLjI4My04LjA0NC0xOS42MjJjNC4xOTItMC45NTEsNy41NTctMS43MTQsMTEuMzAzLTIuNTY0QzExNi4yOTMsMjYwLjE3NCwxMTUuMzE0LDI2Ni44NCwxMTQuMDksMjc1LjE3eiAgTTk3LjEzNiwyNDAuMTg4Yy0yOS44MjMsMC01NC0yNC4xNzctNTQtNTRjMC0yOS44MjMsMjQuMTc3LTU0LDU0LTU0czU0LDI0LjE3Nyw1NCw1NCBDMTUxLjEzNiwyMTYuMDEyLDEyNi45NiwyNDAuMTg4LDk3LjEzNiwyNDAuMTg4eiBNMTkwLjMxNyw5NjEuODE2Yy0yLjg4OSwzLjYzMS0yLjU5LDcuMzE2LTIuNjc1LDExLjIyOSBjLTAuMDYzLDIuOTI5LTAuMzAxLDYuMTg1LTQuMTAyLDYuMDgzYy0zLjcxOC0wLjA5OS0zLjkyLTMuMzczLTMuOTEyLTYuMjY2YzAuMDEtMy45NjEsMC41MzItNy45NTYtMi45NjYtMTEuMDY5IGMtMC44NDMtMC43NS0wLjg2LTIuNDMzLTEuNjUzLTQuOTM4YzEuNzM3LTEuODQyLDMuNDI3LTQuNTc3LDUuODc2LTUuOTk2YzMuMjE4LTEuODY0LDcuMDc4LTAuODAxLDguNzQzLDIuMzYxIEMxOTAuOTA4LDk1NS42NTEsMTkxLjY2Niw5NjAuMTIsMTkwLjMxNyw5NjEuODE2eiBNMTkwLjM3Nyw4OTQuMjg2Yy0yLjc1LDMuNjM5LTIuNzU0LDcuMjc3LTIuNzMxLDExLjIzMSBjMC4wMTcsMi45NTQtMC4zMDMsNi4xNjItMy45NjcsNi4yMTljLTMuNzIyLDAuMDU4LTQuMDM2LTMuMTU2LTQuMDY5LTYuMTE4Yy0wLjA0NC0zLjkxNSwwLjcyOS03Ljk4Mi0yLjg5OC0xMS4wNyBjLTAuODU1LTAuNzI4LTAuOTAyLTIuNDA4LTEuNzkyLTUuMDQ3YzEuODc3LTEuODg1LDMuNzI2LTUuMTYzLDYuMzEzLTUuOTI1YzIuNDEtMC43MTEsNi42MDYsMC40MTEsOC4xNzcsMi4yNzkgQzE5MC45OTksODg3Ljc0NCwxOTEuNjgxLDg5Mi41NiwxOTAuMzc3LDg5NC4yODZ6IE0xOTAuMzk5LDgzMC4xOTZjLTMuMTA3LDMuMzI5LTIuNTkyLDYuOTI2LTIuNzk1LDEwLjY4MiBjLTAuMDg2LDEuNTk3LTAuMzIzLDMuMzMtMS4wNCw0LjcxN2MtMS40MSwyLjcyNS00LjI5OCwyLjc0NC01LjgyMiwwLjExNGMtMC42My0xLjA4Ny0xLjA0LTIuNDUzLTEuMDc1LTMuNzA2IGMtMC4xMjUtNC40MywwLjY1My05LjAwOS0zLjMwNC0xMi40NzJjLTAuNjItMC41NDMtMC41NzItMS44NTItMC44MzMtMi44MDZjLTAuMzE1LTAuMzQtMC42MjktMC42NzktMC45NDQtMS4wMTkgYzIuMTAzLTIuMjQ0LDMuODUtNS41NzEsNi40MTMtNi40MTVjMi4zOTEtMC43ODgsNi4xODQsMC4zMjQsOC4zOTIsMS45MzNDMTkyLjMxOSw4MjMuMzU1LDE5Mi44NjQsODI3LjU1NSwxOTAuMzk5LDgzMC4xOTZ6ICBNMTg0LjEzNiwzMjguMTg4Yy0yOS44MjMsMC01NC0yNC4xNzctNTQtNTRjMC0yOS44MjMsMjQuMTc3LTU0LDU0LTU0czU0LDI0LjE3Nyw1NCw1NCBDMjM4LjEzNiwzMDQuMDEyLDIxMy45NiwzMjguMTg4LDE4NC4xMzYsMzI4LjE4OHogTTI1Mi43ODksMjc3Ljc1MmMtMC4yNjUtMC4xMzMtMC41MzEtMC4yNjUtMC43OTYtMC4zOTggYy0xLjAxNS04LjI1Ny0yLjAyOS0xNi41MTUtMy4wODYtMjUuMTE1YzQuMTY3LDAuODYyLDguMzI0LDEuNzIxLDEzLjU4NSwyLjgwOUMyNTkuMTYyLDI2Mi44NDEsMjU1Ljk3NSwyNzAuMjk3LDI1Mi43ODksMjc3Ljc1MnogIE0yNzEuMTM2LDI0MC4xODhjLTI5LjgyMywwLTU0LTI0LjE3Ny01NC01NGMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTRjMjkuODIzLDAsNTQsMjQuMTc3LDU0LDU0IEMzMjUuMTM3LDIxNi4wMTIsMzAwLjk2LDI0MC4xODgsMjcxLjEzNiwyNDAuMTg4elwiLFxuICAgICAgICBjbG9ja3M6IHtcbiAgICAgICAgICAgIHNpemU6IDEwOCxcbiAgICAgICAgICAgIDA6IHsgeDogMTg0LjI0NSwgeTogMTAwIH0sXG4gICAgICAgICAgICAxOiB7IHg6IDk3LjI0NSwgeTogMTg2IH0sXG4gICAgICAgICAgICAyOiB7IHg6IDI3MS4yNDUsIHk6IDE4NiB9LFxuICAgICAgICAgICAgMzogeyB4OiAxODQuMjQ1LCB5OiAyNzQgfVxuICAgICAgICB9XG4gICAgfSxcbiAgICA1OiB7XG4gICAgICAgIGhlaWdodDogMTE0OC42NTcsXG4gICAgICAgIHdpZHRoOiAzNjguNjk4LFxuICAgICAgICBwYXRoOiBcIk0zNjQuOTE5LDE3Ny4xODVjLTUuODU2LTYuNTkzLTE1LjE0Ny02Ljg4OC0yMS44OTctMC42OTRjLTMuNzE3LDMuNDExLTQuMjk5LDMuMjQyLTUuNTQxLTEuNTg3IGMtMC4yNS0wLjk3Mi0wLjU3MS0xLjkyNi0wLjgwMy0yLjkwMWMtNi4yMjMtMjYuMDMyLTIyLjM5Ni00Mi43MzYtNDcuNTIzLTUxLjIzOGMtMi40NzQtMC44MzctNC44MDgtMi43Mi02LjY2Ni00LjY0MSBjLTYuNjE4LTYuODQ0LTEyLjQyNi0xNC41OTgtMTkuNjM4LTIwLjcwOWMtNy4yNS02LjE0NC0xNC40MjYtMTEuNzUzLTE1Ljk2NC0yMS44NjNjLTAuMTQ1LTAuOTUyLTAuODEtMS44My0xLjI2Mi0yLjcyOCBjLTEwLjE0LTIwLjE0Mi0yNi4yOTMtMzIuNS00OC4yLTM3LjUwM2MtMi41NzItMC41ODctNS4wMTQtMS43NDMtOC4wMjUtMi44MTdjMS4zMTYtMS43MDIsMS44Ni0yLjUzMSwyLjUyNi0zLjI0NyBjNi41MDItNi45ODYsNi42OTgtMTUuNzgzLDAuNDY1LTIxLjk0Yy01Ljc4NS01LjcxNC0xNS4wMjctNS43NjItMjAuODQtMC4xMWMtNi4zNjgsNi4xOTEtNi40MzYsMTUuMDg0LDAuMjM5LDIxLjg1NyBjMi45OTEsMy4wMzUsMS43MjgsNC41NjEtMS4xNjcsNS45OGMtMS4zMzQsMC42NTQtMi44NDQsMC45NTItNC4yODEsMS4zODdjLTI0Ljg1Nyw3LjUxNC00MC45MzYsMjMuNzEyLTQ4LjM5OSw0OC42NTQgYy0wLjc0OCwyLjQ5OS0yLjY5LDQuODMtNC41NjEsNi43N2MtOC42ODQsOS4wMDQtMTcuNDg1LDE3Ljg5Ny0yNi4zNzcsMjYuNjk1Yy0xLjc4MiwxLjc2NC0zLjk1LDMuNTkxLTYuMjY5LDQuMjg3IGMtMjcuMjcyLDguMTg2LTQ0LjI0NSwyNS45MDYtNTAuMzg2LDUzLjg2NGMtMC4zMDYsMS4zOTEtMC43NTIsMi43NS0xLjE4Miw0LjI5OWMtMTEuOTQyLTguMzI2LTE4LjQzLTguODkxLTI0LjczMy0yLjQyNCBjLTUuMTYsNS4yOTQtNi4wODUsMTMuNzE2LTEuMzUxLDE5LjI0YzIuMjUzLDIuNjI5LDUuNjU1LDQuODQxLDguOTYyLDUuODc0YzYuNzcsMi4xMTUsMTIuMDA5LTEuOCwxNi43MTctNi43NTcgYzAuNjQ3LDEuMzY0LDEuMDY4LDEuOTIzLDEuMTgyLDIuNTM5YzUuNDk1LDI5LjY3MiwyMi45MzksNDguMjg5LDUxLjgwNiw1Ni41MDRjMS44OTEsMC41MzgsMy42NjYsMi4wNTYsNS4xMTIsMy41MDMgYzguNzI1LDguNzMxLDE3LjM5NywxNy41MTksMjUuOTQyLDI2LjQyNmMxLjc1NSwxLjgzLDMuNTMyLDQuMDYxLDQuMjI3LDYuNDIzYzUuNTA3LDE4LjcwMiwxNi41NzQsMzIuNjk2LDMzLjA3Niw0My4yMjggYzYuNjY3LDQuMjU1LDExLjQyOCwxMS41MiwxNi45ODcsMTcuNDhjMC41LDAuNTM1LDAuNjg4LDEuNTQ0LDAuNjkyLDIuMzM0YzAuMDQ0LDEwLjg3NywwLjAzLDIxLjc1MywwLjAzLDMyLjYzOCBjLTEuNTc3LDAuNTE2LTIuODQ1LDAuOTMyLTQuMTEzLDEuMzQ2Yy0xNy4xMzUsNS41OTctMzAuNTExLDE2LjAzMy0zOS4wMjQsMzEuOTUyYy0zLjQyNiw2LjQwNy01LjMzMywxMy42NDYtNy43NTQsMjAuNTcgYy0xLjc2LDUuMDMzLTMuMTI5LDUuNTQtNi45MDcsMi4wOGMtMi43MDYtMi40NzgtNi4xNzItNC4wNjgtOS44MzctNC4yMzVjLTguNTk4LTAuMzkyLTE1LjE3Niw2LjIyMy0xNS42NywxMy45NyBjLTAuMzg0LDYuMDIxLDIuODY1LDExLjc0NCw4LjE5OCwxNC40NGM1LjYzOCwyLjg1MSwxMi4wMSwyLjAyMSwxNi44MTgtMi4xODljMi41NjItMi4yNDMsNS42NjgtMS42NTYsNi45MjMsMS41MSBjMS4xODcsMi45OTMsMS43OTksNi4yMjksMy4xMjQsOS4xNDljMi41NDksNS42Miw0Ljg4NiwxMS40NDQsOC4yNDcsMTYuNTY4YzkuNDk3LDE0LjQ3OCwzOS40MjIsMjguMDE4LDM5LjQyMiwyOC4wMTh2MjguNTQyIGMwLDAtMC40OTYsMC40NjYtMC43ODgsMC40NjljLTUuNTIyLDAuMDQ5LTExLjA0NSwwLjA4OC0xNi41NjgsMC4wOTVjLTkuODA1LDAuMDEzLTEwLjE5MSwwLjM4Mi0xMC4xODgsOS45NTkgYzAuMDAxLDIuMzQ3LTAuMDAyLDQuNjk1LDAsNy4wNDJjMC4wMDgsNy4wNTksMS4wNjEsOC4xNDcsNy45NDIsOC4xNTdjNi42NDMsMC4wMSwxMy4yODYsMC4wMDIsMjAuMjIzLDAuMDAyIGMtMC4xMTUsMi4zNjgtMC4xOTgsNC4wOTgtMC4yOTIsNi4wMzVjLTcuNTI4LDAtMTQuNTQ2LDAuMDU0LTIxLjU2Mi0wLjAyYy0zLjU2LTAuMDM3LTYuMzgzLDIuODU0LTYuMzIzLDYuNDE1IGMwLjA2NCwzLjgyNi0wLjAxMSw3LjY1NCwwLjAxLDExLjQ4MWMwLjAzMyw1LjkxOCwxLjM2NCw3LjI0OCw3LjMyNCw3LjI2OWM2LjgxNSwwLjAyNCwyMS4yMiwwLjAwNiwyMS4yMiwwLjAwNnY3LjA0NCBjMCwwLTE0LjQzNS0wLjAxNy0yMS4xMDgsMC4wMDVjLTYuMDY5LDAuMDItNy4zNzMsMS4yODktNy40MzQsNy4xOWMtMC4wMjgsMi42ODIsMC4xOCw1LjM4LTAuMDM5LDguMDQ0IGMtMC40NDMsNS4zODksMC4wNywxMC4wMzksNi45MTIsMTAuNTI0Yy0zLjAxNSwzMS40NTctMi41NzIsNjIuMzk4LDIuMjM0LDkzLjE5NmMyLjk4LDE5LjA5Nyw3LjE5LDM3Ljg1NCwxNi41OTksNTUuMDYzIGMxLjQ0MywyLjYzOSwyLjM5Nyw1LjkyNCwyLjQwNiw4LjkxNGMwLjIwOSw2My41NDMsMC4yNTEsMTI3LjA4NywwLjMyNSwxOTAuNjMxYzAuMDAyLDEuNzk1LDAsMy41OSwwLDUuNDQyIGMtNS4yMzgsMC42NzktNy4zOTctMS4zNjktNy4zNDctNS45ODZjMC4wMzUtMy4xODUsMC4wMjQtNi4zNzEsMC4wMDYtOS41NTdjLTAuMDM0LTUuOTQ1LTEuMzI1LTcuMjc0LTcuMzA5LTcuMjg1IGMtMTcuMDc0LTAuMDMyLTM0LjE0OC0wLjAyMi01MS4yMjItMC4wMjZjLTExLjcxOC0wLjAwMy0yMy40MzUtMC4wMjktMzUuMTUzLDAuMDEzYy01LjIzNSwwLjAxOS02LjY5OSwxLjU0LTYuNzU2LDYuODE0IGMtMC4wMzgsMy41MjEtMC4wNCw3LjA0MiwwLjAwNCwxMC41NjNjMC4wNjYsNS4yNTUsMS41MTYsNi43MjUsNi44MjMsNi43NDRjMTEuMjE1LDAuMDQsMjIuNDMxLDAuMDEsMzMuNjQ2LDAuMDEzIGMxMS44NjgsMC4wMDMsMTEuODY4LDAuMDA1LDExLjc1LDExLjkxMmMtMC4wNTksNS45MjItMS4zLDcuMTYtNy40MDcsNy4xNzZjLTEyLjIyLDAuMDMxLTI0LjQzOSwwLjAxOC0zNi42NTksMC4wMjkgYy03LjA1NCwwLjAwNi04LjE1NSwxLjA4LTguMTY3LDcuOTM1Yy0wLjAwNCwyLjE4LTAuMDA2LDQuMzU5LDAuMDAxLDYuNTM5YzAuMDIxLDYuMzgzLDEuMjIyLDcuNjQ0LDcuNDM5LDcuNjU1IGMxMS4wNDgsMC4wMiwyMi4wOTYsMC4wMDIsMzMuMTQ0LDAuMDA2YzExLjc5MSwwLjAwNSwxMS43OTEsMC4wMDgsMTEuNjQ4LDEyLjAxMmMtMC4wNjcsNS43MDMtMS4zNjcsNy4wNjItNy4wNDcsNy4wODMgYy0xMC4zNzgsMC4wNC0yMC43NTgsMC4wOTYtMzEuMTM1LTAuMDAyYy0xNS4xMjItMC4xNDQtMTQuMTQ2LTAuNDc4LTE0LjA0NywxNC4xMzJjMC4wMzgsNS42NDYsMS4zNzcsNi45OTIsNy4wNzQsNy4wMDggYzExLjA0OCwwLjAzMSwyMi4wOTYsMC4wMDcsMzMuMTQ0LDAuMDFjMTIuMTksMC4wMDMsMTIuMTksMC4wMDUsMTIuMDExLDEyLjE1M2MtMC4wODMsNS41OTctMS40MTMsNi45MjQtNy4xODcsNi45NDQgYy0xMC4yMTEsMC4wMzQtMjAuNDIzLDAuMDg5LTMwLjYzMy0wLjAwMWMtMTUuNzczLTAuMTM5LTE0LjQ2NS0wLjU3Ny0xNC40MDYsMTQuNzc0YzAuMDI0LDYuMTczLDEuMzEzLDcuMzcsNy43Myw3LjM3NSBjMTMuNzI2LDAuMDExLDI3LjQ1MiwwLjAwNSw0MS4xNzksMC4wMDNjMTQuODk4LTAuMDAyLDI5Ljc5NiwwLjAxOCw0NC42OTQtMC4wMjdjNS4zMzktMC4wMTYsNi43NjctMS40ODcsNi44MzEtNi43NDIgYzAuMDMzLTIuNjgyLTAuMDQ2LTUuMzY2LDAuMDItOC4wNDdjMC4xMjYtNS4xMDYsMS44MzktNi40NjksOC4wNDQtNS42OTdjMCw1LjcyMi0wLjQ1NSwxMS42MTEsMC4wOTcsMTcuNDA0IGMxLjA3OCwxMS4zMDgsMi42MzQsMjIuNjMxLDguNjY3LDMyLjYyM2MzLjcwOSw2LjE0Myw5LjU2Myw1LjgxNiwxMi43NTMtMC42MTJjMi45ODQtNi4wMTUsNS44MzMtMTIuNjI1LDYuNDA5LTE5LjE3NCBjMS41NzktMTcuOTY5LDIuNTQzLTM2LjA0NSwyLjYxNC01NC4wODNjMC4zNi05MS44NzgsMC4zNS0xODMuNzU3LDAuNTUzLTI3NS42MzZjMC4wMDUtMi4wNDksMC43MzMtNC4yMTQsMS41NzYtNi4xMjQgYzMuMzY5LTcuNjM5LDcuNzQ4LTE0LjkzNCwxMC4yNTctMjIuODMzYzExLjQyMS0zNS45NDYsMTMuNDMzLTcyLjk5NywxMS43NTUtMTEwLjM5MWMtMC4yNjktNS45OS0wLjgwMS0xMS45NjgtMS4yMDktMTcuOTA5IGM3LjQ1Mi0xLjUzNCw3Ljc3NS0xLjk0NSw3Ljc3OS05LjU4OGMwLjAwMS0yLjUxNSwwLjAxMS01LjAzLDAuMDA3LTcuNTQ1Yy0wLjAxMy03Ljc1LTAuODk0LTguNjU2LTguNDYtOC42NjMgYy03LjE0MS0wLjAwNy0yMi40MDYtMC4wMDEtMjIuNDA2LTAuMDAxdi03LjA0NWMwLDAsMTYuNzQyLTAuMDQ4LDI0LjU2MSwwLjAxOWM0LjM1OSwwLjAzOCw2LjM5Mi0yLDYuMzEyLTYuMzUxIGMtMC4wNzEtMy44NTUsMC4wMTYtNy43MTItMC4wMTktMTEuNTY4Yy0wLjA1My01LjkzOC0xLjM0NS03LjIxOS03LjM1LTcuMjQyYy03LjQ4NS0wLjAyOS0yMi41MDQtMC4wMDctMjIuNTA0LTAuMDA3di02LjAzNSBjMCwwLDE1LjQ1NCwwLjAzMywyMi45NjctMC4wMTFjNS4zNjItMC4wMzEsNi44MDMtMS40NTQsNi44NzYtNi42ODNjMC4wNDktMy41MiwwLjAyOC03LjA0MiwwLjAxOC0xMC41NjMgYy0wLjAxOS02LjcwOC0xLjE1Ny03Ljg4MS03LjctNy44OTVjLTcuMzE5LTAuMDE2LTIxLjE2MS0wLjAwNC0yMS4xNjEtMC4wMDR2LTI4Ljk2M2MwLDAsNTEuMzE5LTE4LjUwNiw1MS40MTgtNTguODAzIGMxMy4yNzQsOC44LDE5LjgyOCw5LjE0MywyNS45ODIsMS45NmM0Ljg0My01LjY1Myw0LjkxOS0xMy43NTgsMC4xODEtMTkuMzYyYy02LjEyMS03LjI0LTEyLjY4Ny02LjkwNC0yNi4yNTksMS45MDkgYy01LjcwOS0zMC4yNy0yMi42NzItNTAuNTQxLTUyLjU4Ny01OS4xMzdjMC0xMS4xOTgtMC4wMzgtMjIuMjQ5LDAuMDUzLTMzLjI5OGMwLjAxLTEuMjQ3LDAuMzk0LTIuODI2LDEuMjA2LTMuNjc3IGM1LjE0My01LjM5NCw5LjczNi0xMS43NDEsMTUuODUxLTE1LjY5NWMxNS41ODItMTAuMDc0LDI2LjYxOC0yMy4xNjgsMzIuMDY5LTQwLjk5N2MwLjYyOC0yLjA1MiwyLjE1NC00LjI1MSwzLjg5Ny01LjQ3MiBjMTIuMDY0LTguNDQ4LDIyLjI5Ny0xOC42NTgsMzAuODU4LTMwLjYzOWMxLjIzNS0xLjcyOCwzLjAwOS0zLDUuMDI3LTMuNjYxYzI1LjI3Ni04LjI4NCw0MS4yMTgtMjUuMjQxLDQ3Ljg2NS01MS4wMjkgYzAuNTQ5LTIuMTI5LDEuNTM2LTQuMTQ1LDIuNjItNy4wMDhjMi4wMjgsMS44OCwzLjE4MiwzLjAzLDQuNDE4LDQuMDgzYzUuODEzLDQuOTUxLDE0LjIwMiw0Ljg5MywxOS43NjEtMC4xMDcgQzM2OS44NDcsMTkyLjc4OCwzNzAuNDI4LDE4My4zODgsMzY0LjkxOSwxNzcuMTg1eiBNMjUyLjM5NCwxMDcuNDkyYzQuMDk4LDMuNDE1LDcuODg3LDYuNTc0LDExLjY3Nyw5LjczMyBjLTAuNDA0LDAuMzk1LTAuODA3LDAuNzkxLTEuMjExLDEuMTg2Yy00LjE2OSwwLjc4NS04LjMzOCwxLjU3LTEzLjE1LDIuNDc2QzI1MC42NjYsMTE2LjExMiwyNTEuNTE2LDExMS44NzIsMjUyLjM5NCwxMDcuNDkyeiAgTTE4NC40MDYsNDZjMjkuODIzLDAsNTQsMjQuMTc3LDU0LDU0YzAsMjkuODIzLTI0LjE3Nyw1NC01NCw1NHMtNTQtMjQuMTc3LTU0LTU0QzEzMC40MDYsNzAuMTc3LDE1NC41ODMsNDYsMTg0LjQwNiw0NnogIE0xNjIuMzczLDE2NS41ODFjMTQuMzU3LDQuMTgsMjguMDk2LDQuNTc4LDQyLjUxMywwLjE5OWMtNC4wOTIsMTQuNDctMy45NDYsMjguMTEzLDAuMjI3LDQyLjUyMyBjLTE0LjI2LTQuMDM3LTI3Ljg2OC00LjUwOS00Mi4yNzMtMC4xNTJDMTY2LjY1OSwxOTMuODMxLDE2Ni44OTYsMTgwLjE4OSwxNjIuMzczLDE2NS41ODF6IE0xMTUuODI3LDEwNy41OTMgYzEuMTk3LDUuNDY2LDIuMTAxLDkuNTk4LDMuMTQ5LDE0LjM4MmMtNC41NDctMC45NjQtOC41MjEtMS44MDYtMTMuNjc1LTIuODk5QzEwOC44MzUsMTE1LjIyMSwxMTEuOTU4LDExMS44MTQsMTE1LjgyNywxMDcuNTkzeiAgTTQzLjQwNiwxODZjMC0yOS44MjMsMjQuMTc3LTU0LDU0LTU0czU0LDI0LjE3Nyw1NCw1NGMwLDI5LjgyMy0yNC4xNzcsNTQtNTQsNTRTNDMuNDA2LDIxNS44MjMsNDMuNDA2LDE4NnogTTExNS4yNzgsMjY1LjkwOSBjLTMuNDAyLTMuNjI2LTYuMjQ4LTYuNjYxLTkuNjctMTAuMzA5YzQuNjYyLTEuMDYsOC4xOTItMS44NjIsMTIuMzI0LTIuODAxQzExNy4wNzEsMjU3LjA1MSwxMTYuMjcsMjYxLjAxMSwxMTUuMjc4LDI2NS45MDl6ICBNMjM4LjQwNiw0NTNjMCwyOS44MjMtMjQuMTc3LDU0LTU0LDU0cy01NC0yNC4xNzctNTQtNTRzMjQuMTc3LTU0LDU0LTU0UzIzOC40MDYsNDIzLjE3NywyMzguNDA2LDQ1M3ogTTE4NC40MDYsMzI4IGMtMjkuODIzLDAtNTQtMjQuMTc3LTU0LTU0YzAtMjkuODIzLDI0LjE3Ny01NCw1NC01NHM1NCwyNC4xNzcsNTQsNTRDMjM4LjQwNiwzMDMuODIzLDIxNC4yMywzMjgsMTg0LjQwNiwzMjh6IE0yNTEuOTU4LDI2Ny45MjcgYy0xLjE2Ny01LjY2OS0yLjE1NC0xMC40Ni0zLjI2Mi0xNS44NGM1LjE1NCwwLjk3LDkuOTM1LDEuODcsMTQuNzE2LDIuNzdjMC40NDYsMC41NDEsMC44OTIsMS4wODIsMS4zMzgsMS42MjMgQzI2MC42NzMsMjYwLjEyOSwyNTYuNTk1LDI2My43NzgsMjUxLjk1OCwyNjcuOTI3eiBNMjcxLjQwNiwyNDBjLTI5LjgyMywwLTU0LTI0LjE3Ny01NC01NGMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTQgYzI5LjgyMywwLDU0LDI0LjE3Nyw1NCw1NEMzMjUuNDA2LDIxNS44MjMsMzAxLjIzLDI0MCwyNzEuNDA2LDI0MHpcIixcbiAgICAgICAgY2xvY2tzOiB7XG4gICAgICAgICAgICBzaXplOiAxMDgsXG4gICAgICAgICAgICAwOiB7IHg6IDE4NC4yNDUsIHk6IDEwMCB9LFxuICAgICAgICAgICAgMTogeyB4OiA5Ny4yNDUsIHk6IDE4NiB9LFxuICAgICAgICAgICAgMjogeyB4OiAyNzEuMjQ1LCB5OiAxODYgfSxcbiAgICAgICAgICAgIDM6IHsgeDogMTg0LjI0NSwgeTogMjc0IH0sXG4gICAgICAgICAgICA0OiB7IHg6IDE4NC4yNDUsIHk6IDQ1MyB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIDY6IHtcbiAgICAgICAgaGVpZ2h0OiAxMTQ4Ljk4LFxuICAgICAgICB3aWR0aDogMzcwLjE0MSxcbiAgICAgICAgcGF0aDogXCJNMzY1Ljg0LDE3Ni40ODljLTUuNjg5LTUuODMxLTE0Ljc3NC02LjEwOS0yMC45ODMtMC42NDJjLTQuNjc3LDQuMTE4LTQuOTc2LDQuMDg1LTYuNDE0LTIuMjY5IGMtNi4xODctMjcuMzMzLTIyLjczMi00NC45Ny00OS40MTItNTMuMzQ3Yy0xLjg4Ny0wLjU5My0zLjc2OS0yLjE2OC00Ljk4My0zLjc4OGMtOC4zMy0xMS4xMTUtMTguMDA4LTIwLjc4NS0yOS4zMTgtMjguODk0IGMtMS44NC0xLjMyLTMuMjM5LTMuODI1LTMuOTQ4LTYuMDY1Yy04LjAxMy0yNS4zMDYtMjQuODA0LTQxLjI3OC01MC40NTMtNDcuOTg1Yy0xLjI5OS0wLjM0LTIuNjI4LTAuNTYyLTMuOTMtMC44OSBjLTYuMDI5LTEuNTE5LTYuMzQ2LTIuNDU2LTIuNDQtNy4xMDJjNS4zNzgtNi4zOTYsNC45My0xNS4yMDEtMS4wNjUtMjAuOTIxYy01LjcwMi01LjQ0Mi0xNC44MDYtNS40NDctMjAuNTgyLTAuMDEzIGMtNi4wMDYsNS42NTEtNi41MDcsMTQuNTQ1LTEuMDY2LDIwLjg4YzAuOTYyLDEuMTIsMi4zNiwxLjg2NSw1LjEwMiwzLjk2OWMtMy45OTcsMS45NjktNi40NjYsMy42NDctOS4xOTIsNC40NTUgYy0yMS4wNTgsNi4yMzktMzcuMDk0LDE4LjgxNi00NC45NDEsMzkuMzU3Yy0zLjg5OSwxMC4yMDctOS41NjIsMTcuNjI1LTE3Ljc1OCwyNC4zOTRjLTYuNjQ2LDUuNDg5LTExLjcwNCwxMi44ODMtMTcuNjE1LDE5LjI5NCBjLTEuMzgsMS40OTctMy4yMDMsMy4wMDItNS4wOTcsMy41NDZjLTI4LjM0Myw4LjEyNy00NS41NjMsMjYuNTA3LTUxLjU2Nyw1NS4zODljLTAuMTk1LDAuOTQxLTAuNTk1LDEuODQtMS4yMTEsMy42OTcgYy00LjU2LTUuMzU3LTkuNzM4LTguOTI4LTE2LjM2Ny03LjI2MWMtMy4yMjYsMC44MTEtNi41OTksMi43NzgtOC44OTcsNS4xODRjLTUuMTA0LDUuMzQzLTQuNzc5LDEzLjc3NiwwLjAzOCwxOS4zMzYgYzYuMDY4LDcuMDA0LDEyLjAyLDYuNzIxLDI1LjYxOS0xLjQ1OGMwLjcyLDMuMDA3LDEuMzIyLDUuODk2LDIuMTA2LDguNzM1YzcuMTMzLDI1LjgzMSwyMy43OTcsNDIuMTI3LDQ5LjQwNCw0OS42NTkgYzIuNDk4LDAuNzM1LDQuODc0LDIuNjEsNi43ODQsNC40ODhjOC41OTMsOC40NDUsMTcuMDUzLDE3LjAyOCwyNS40MjcsMjUuNjkyYzEuNzY3LDEuODI4LDMuNjM2LDQuMDA3LDQuMzIzLDYuMzU2IGM1LjU5NywxOS4xMzgsMTYuOTk3LDMzLjMxOCwzMy45OTQsNDMuOTEzYzYuNTY3LDQuMDk0LDExLjExOCwxMS40MzksMTYuNTEsMTcuMzc0YzAuNDgsMC41MjgsMC41MzQsMS41NzgsMC41MzYsMi4zODYgYzAuMDMzLDEwLjc0MywwLjAyMiwyMS40ODYsMC4wMjIsMzAuNjk3Yy05LjU1Miw1LjQyNy0xOC44MTYsOS41NjktMjYuNzc2LDE1LjQ2OWMtMTIuNTQ3LDkuMjk5LTE5Ljk0OSwyMi40MjItMjMuNzcxLDM3LjU3OCBjLTAuNjgsMi42OTgtMi4xMDIsNS4yMDgtMy40NzMsOC41MDZjLTIuMjg2LTIuMTI2LTMuNDYxLTMuMjktNC43MTEtNC4zNjdjLTYuMDY3LTUuMjMxLTE1LjAwMy00Ljg3Mi0yMC41NzMsMC44MDEgYy01LjYwMyw1LjcwNy01LjgzOSwxNC42OTgtMC41NCwyMC41NjljNS41NjUsNi4xNjYsMTQuNTE1LDYuODgsMjAuODY2LDEuNjY1YzUuMTEyLTQuMTk3LDUuNDEyLTMuOTQ2LDguMDY5LDIuNTE2IGMzLjQzLDguMzQ0LDYuMzU5LDE3LjA4MiwxMS4wODksMjQuNjYxYzguMzc5LDEzLjQyNiwyMS4wMTksMjEuODk0LDM2LjA3OCwyNi43ODVjMS40MzQsMC40NjYsMy41NTEsMiwzLjU4NywzLjA5NyBjMC4yOTQsOC44NTMsMC4xNjUsMTcuNzIsMC4xNjUsMjcuMTI0Yy03LjQ3NiwwLTE0LjQ4NS0wLjA0My0yMS40OTMsMC4wMTRjLTUuMzA2LDAuMDQ0LTYuNjg3LDEuNDk0LTYuNzM1LDYuODc4IGMtMC4wMzMsMy42OTctMC4wMyw3LjM5NC0wLjAwNCwxMS4wOTFjMC4wNDIsNS45NDMsMS4yODQsNy4xNTcsNy40MzYsNy4xODVjNi43MDIsMC4wMzEsMTMuNDA1LDAuMDA3LDIwLjQ0OCwwLjAwNyBjMCwyLjAzNCwwLDUuNTk4LDAsNS41OThzLTEzLjc4NC0wLjAzNC0yMC43ODMsMC4wMTFjLTUuMzcyLDAuMDM1LTYuNzk5LDEuNDUtNi44NjEsNi43MjRjLTAuMDQ3LDQuMDI2LDAuMDQ0LDguMDU0LTAuMDIzLDEyLjA3OSBjLTAuMDcyLDQuMzI1LDEuODk4LDYuMzg1LDYuMjk5LDYuMzQ1YzYuODc2LTAuMDYzLDEzLjc1MywwLjA0OSwyMC42MjksMC4xMTNjMC4yODksMC4wMDMsMS43MzksMC41MzQsMS43MzksMC41MzR2Ni40MDcgYzAsMC0xNC42OTItMC4wMzItMjEuNjgyLDAuMDFjLTUuNjUyLDAuMDM0LTcuMzM0LDEuMzk1LTYuODcyLDcuMTE5YzAuNjk0LDguNjAxLTEuMjg5LDE1LjI0OS04LjAwNiwyMS42MzggYy04LjYwNSw4LjE4NS0xMy4wMzYsMTkuMzQtMTUuNDYzLDMxLjA4OWMtMS4zMDksNi4zMzUtMi4wOTYsNi41NTUtNi44ODksMi4zOThjLTYuMjg3LTUuNDUzLTE1LjE5NS01LjEwMy0yMC44NzEsMC44MTkgYy01LjY1Nyw1LjkwMi01LjYyNCwxNS4wMDMsMC4wNzYsMjAuODk2YzUuNzAyLDUuODk1LDE0LjUxLDYuMTUzLDIwLjg1NSwwLjYxM2MxLjExNy0wLjk3NSwyLjIzOC0xLjk0NSw0LjIzOC0zLjY4MiBjMS4xMjksMi44MDcsMi4yNzQsNC45MjQsMi44NDMsNy4xODZjNC43NjksMTguOTM4LDE1LjEzNywzMy43MjgsMzEuODY0LDQ0LjA1MWMxLjczNiwxLjA3MiwzLjI3LDMuMzc3LDMuNzc1LDUuMzkyIGMzLjM5NywxMy41NDgsNy4zNjMsMjYuODM0LDE0LjY4NSwzOC45MDRjMC44MDQsMS4zMjUsMS4wMywzLjE3NywxLjAzMyw0Ljc4NmMwLjExOCw2NC45MjYsMC4xOCwxMjkuODUyLDAuMjM5LDE5NC43NzggYzAuMDAxLDAuOTgxLTAuMTIyLDEuOTYzLTAuMTg0LDIuODk0Yy01LjI0OSwwLjcwOS02Ljk3NC0wLjU4OC03LjEzLTUuMzU4Yy0wLjEwOS0zLjM1Mi0wLjAwMy02LjcxLTAuMDI0LTEwLjA2NSBjLTAuMDM2LTUuNzA1LTEuMzU3LTcuMDkyLTcuMDE5LTcuMDk5Yy0yMS45NzgtMC4wMjYtNDMuOTU2LTAuMDEyLTY1LjkzMy0wLjAxMWMtNy4wNDYsMC0xNC4wOTQsMC4xLTIxLjEzOC0wLjAyNiBjLTQuNjM1LTAuMDgzLTYuNzI4LDIuMDAzLTYuNTg5LDYuNjMzYzAuMTA5LDMuNjM5LDAuMTIxLDcuMjc4LTAuMDAyLDEwLjkxN2MtMC4xNTcsNC42NDYsMS45NDcsNi43MDMsNi41NzUsNi42NyBjMTIuNzUtMC4wOSwyNS41MDEtMC4wNDUsMzguMjUxLTAuMDI4YzYuMzA1LDAuMDA4LDcuNTEzLDEuMjUzLDcuNTMzLDcuNTk5YzAuMDM4LDExLjUyNSwwLjAzOCwxMS41MjYtMTEuNjgsMTEuNTI1IGMtMTEuMjQtMC4wMDEtMjIuNDgxLTAuMDMtMzMuNzIyLDAuMDA3Yy01LjQxOCwwLjAxOC02LjkxNCwxLjQzNy02LjkzMSw2LjY2NmMtMC4wNTMsMTYuNTY4LTEuNDM3LDE1LjU3MiwxNS4yMzUsMTUuNDg0IGMxMC4wNjYtMC4wNTMsMjAuMTMyLTAuMDM4LDMwLjE5OCwwLjAwMmM1LjM3MywwLjAyMSw2Ljc5NiwxLjQ1Nyw2LjkwNSw2LjY5N2MwLjI1OSwxMi40MTksMC4yNTksMTIuNDItMTIuMjY4LDEyLjQxOSBjLTExLjA3MywwLTIyLjE0Ni0wLjAyOC0zMy4yMTgsMC4wMTFjLTUuMzE5LDAuMDE5LTYuODIyLDEuNTAxLTYuODU3LDYuNzM4Yy0wLjEwMiwxNS4wMTgtMS4wNjgsMTQuNTQ0LDE0LjMxLDE0LjQwOCBjMTAuNDAxLTAuMDkyLDIwLjgwMy0wLjA0NywzMS4yMDUtMC4wMDVjNS4yNzksMC4wMjIsNi43MjksMS41MjIsNi44MjgsNi43NzNjMC4yMzQsMTIuMzQyLDAuMjM0LDEyLjM0Mi0xMi4zNDUsMTIuMzQyIGMtMTEuMDczLDAtMjIuMTQ2LTAuMDMxLTMzLjIxOCwwLjAxMmMtNS4yNSwwLjAyLTYuNzYsMS41MzktNi43NzksNi44MTRjLTAuMDYsMTYuMjQtMS4zODIsMTUuMzksMTQuODgyLDE1LjM0MyBjMjYuMDA0LTAuMDc1LDUyLjAwOS0wLjAxNSw3OC4wMTMtMC4wMjRjNi41OTItMC4wMDIsNy43NjMtMS4yMTEsNy43NjctNy44NzZjMC4wMDEtMi4zNDktMC4wNTYtNC42OTksMC4wMS03LjA0NiBjMC4xNDQtNS4wODcsMS43OTQtNi4zOCw2LjM5MS01Ljg2NWMxLjU3LDExLjk2MiwyLjkwNywyMy43NDcsNC43NjUsMzUuNDQ5YzAuNjQ3LDQuMDczLDEuOTk4LDguMjkyLDQuMTA0LDExLjc5NyBjMS44MjgsMy4wNDEsNS4xNTksNy4xMTksNy44NTksNy4xNDNjMi42NTYsMC4wMjQsNi44MDUtNC4wMTksNy43NjMtNy4wNzNjMy4wOS05Ljg1LDYuMTQ4LTE5Ljk1OSw3LjEwNi0zMC4xNjcgYzEuMjk1LTEzLjc5NCwwLjc2My0yNy43NzIsMC43ODctNDEuNjcxYzAuMTU4LTkxLjQzMywwLjIzOC0xODIuODY2LDAuNDYtMjc0LjI5OWMwLjAwNi0yLjQ5OSwwLjg0NC01LjI5LDIuMTMxLTcuNDQ0IGM3LjE1MS0xMS45NzIsMTEuMzE0LTI1LjAyMSwxNC4yODMtMzguNTAyYzAuNzY3LTMuNDgzLDIuMjc1LTUuODk1LDUuMzE4LTcuOTU4YzE0LjQ3Mi05LjgwOSwyMy44MDEtMjMuMzIxLDI4LjE4NC00MC4yNzkgYzAuNzExLTIuNzUzLDEuOTgxLTUuMzYxLDMuMjgxLTguNzk4YzIuMDk2LDEuOTQ3LDMuMjU3LDMuMTE0LDQuNTA4LDQuMTczYzYuMjc0LDUuMzEyLDE1LjMxOSw0Ljc0NywyMC44NjctMS4yNzYgYzUuMzcxLTUuODMsNS4yOC0xNC43MTgtMC4yMDktMjAuNTQxYy01LjU5My01LjkzMy0xNC42NTctNi4zMTMtMjAuODYxLTAuODc1Yy00LjkxLDQuMzA0LTUuNTAyLDQuMTgzLTYuODcxLTIuMzIgYy0yLjg0My0xMy41MDEtOS4xMjktMjUuMDkxLTE4LjYzNi0zNS4wNTFjLTEuMDU5LTEuMTA5LTEuNjI0LTMuMDY0LTEuNzAzLTQuNjYyYy0wLjIyNS00LjUxOS0wLjE3Ny05LjA1OC0wLjA0OS0xMy41ODQgYzAuMTMtNC41ODQtMS44NjMtNi43MTItNi41Mi02LjY0MWMtNy42ODgsMC4xMTctMjMuNDYsMC4wMzItMjMuNDYsMC4wMzJ2LTcuMDgxYzAsMCwxNS41MTMsMC4wMzUsMjMuMTg3LTAuMDEyIGM1LjI2NC0wLjAzMiw2LjY5OS0xLjUxLDYuNzU3LTYuODM0YzAuMDQyLTMuODU4LDAuMDQ3LTcuNzE4LTAuMDAxLTExLjU3NmMtMC4wNjYtNS4yNzgtMS40NzYtNi42NjktNi44ODUtNi43MDEgYy03LjUyOS0wLjA0NC0yMi4wNTktMC4wMTEtMjIuMDU5LTAuMDExdi02LjA3M2MwLDAsMTQuNDIxLDAuMDM2LDIyLjA4OC0wLjAxMmM1LjM3My0wLjAzNCw2Ljc5Mi0xLjQ1MSw2Ljg1NS02LjczIGMwLjA0OC00LjAyNi0wLjA1NS04LjA1NCwwLjAyOC0xMi4wNzljMC4wODktNC4zNjEtMS45NDQtNi4zNzQtNi4zMDgtNi4zMzJjLTcuNzA3LDAuMDczLTIzLjY2MiwwLjAyMS0yMy42NjIsMC4wMjEgczAtMTguNzQzLDAtMjguNmMyOS4zOTctOC40NTksNDYuNDYyLTI4LjYyMSw1Mi41MzUtNTkuNTM1YzUuNjgxLDUuMTgyLDEwLjc4NCw5LjUzOSwxNy42NDksNy4zODIgYzMuMzI0LTEuMDQ1LDYuNzY3LTMuMjE0LDkuMDI1LTUuODQ1YzQuOTI5LTUuNzQ0LDMuOTIxLTE0LjMyNi0xLjU1OS0xOS42MzdjLTYuNTExLTYuMzEyLTEzLjcxNC01LjU1OC0yNS4xMTcsMy4zODggYy01Ljg1LTMwLjM3MS0yMi43MDYtNTAuODA5LTUyLjg5Ni01OS40ODJjMC0xMS4zMjgtMS4wMjEtMjIuODU1LDAuMzU2LTM0LjA4OGMwLjkyNy03LjU2NCw3LjM4NS0xMy4yOTEsMTMuOTQzLTE3LjA5MiBjMTcuNTQ2LTEwLjE3LDI5Ljc3Ni0yNC4yNjMsMzUuNDE5LTQzLjkyNWMwLjQ5NS0xLjcyNiwyLjE4Mi0zLjQwMywzLjc0NS00LjQ4MmMxMi4wMjMtOC4zMDQsMjIuMTEzLTE4LjQ5NCwzMC42NjctMzAuMzE1IGMxLjI1NS0xLjczNCwzLjQwMi0zLjI0LDUuNDQ2LTMuOTIzYzI1LjA5NS04LjM4NCw0MS4xMDEtMjUuMTY4LDQ3LjY4Mi01MC44NzNjMC41NTMtMi4xNTksMS41MTctNC4yMTIsMi42MzgtNy4yNiBjMS45OTIsMS44MTQsMy4xNDMsMi45MTEsNC4zNDUsMy45NDljNi4zMDcsNS40NDYsMTUuMTk0LDUuMDgxLDIwLjkyOC0wLjg0NEMzNzEuNTc5LDE5MS42MDcsMzcxLjUzOCwxODIuMzMsMzY1Ljg0LDE3Ni40ODl6IE0yNTMuNTUsMTA3LjA3MmM0LjE1NywzLjYxMyw3Ljc0Nyw2LjczMiwxMS4zMzcsOS44NTJjLTAuMzI2LDAuNTAxLTAuNjUyLDEuMDAzLTAuOTc5LDEuNTA0IGMtNC4xODIsMC43OTgtOC4zNjUsMS41OTYtMTMuMTYzLDIuNTEyQzI1MS43MTgsMTE2LjEzMiwyNTIuNTc3LDExMS44ODIsMjUzLjU1LDEwNy4wNzJ6IE0xODUuMjg5LDQ1Ljk4YzI5LjgyMywwLDU0LDI0LjE3Nyw1NCw1NCBjMCwyOS44MjMtMjQuMTc3LDU0LTU0LDU0cy01NC0yNC4xNzctNTQtNTRDMTMxLjI4OSw3MC4xNTcsMTU1LjQ2Niw0NS45OCwxODUuMjg5LDQ1Ljk4eiBNMTY0LjE1MSwxNjUuNzczIGMxMy41ODEsNC4zMzQsMjcuMzYzLDQuMjIsNDEuNzc3LDAuMTk5Yy00LjQ3NCwxNC40OC0zLjg3LDI4LjEzOSwwLjAyNyw0Mi40MjljLTE0LjIzMi00LjA5OC0yNy43NDgtNC4zOTktNDEuNTMxLTAuNDQ0IGMwLjc3Ny03LjMxMiwyLjA5My0xNC4wNjYsMi4wNDQtMjAuODA5QzE2Ni40MTksMTgwLjI0NCwxNjUuMDMyLDE3My4zNDksMTY0LjE1MSwxNjUuNzczeiBNMTE2LjUzOCwxMDcuODA5IGMxLjIwOSw1LjMyMiwyLjE0NSw5LjQzNiwzLjI1MiwxNC4zMTFjLTQuNzYyLTEuMDYtOC43MzEtMS45NDMtMTMuNzkxLTMuMDdDMTA5LjY1LDExNS4xNTcsMTEyLjc3NSwxMTEuODIzLDExNi41MzgsMTA3LjgwOXogTTk4LjI4OSwyMzkuOThjLTI5LjgyMywwLTU0LTI0LjE3Ny01NC01NGMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTRzNTQsMjQuMTc3LDU0LDU0IEMxNTIuMjg5LDIxNS44MDQsMTI4LjExMywyMzkuOTgsOTguMjg5LDIzOS45OHogTTExNS45NDksMjY1Ljk3Yy0zLjQwNy0zLjU5NC02LjIwNS02LjU0Ni05Ljc3LTEwLjMwOCBjNS4wMTItMS4wNTksOC41ODctMS44MTUsMTIuNjA0LTIuNjY0QzExNy44MDMsMjU3LjQ4NCwxMTYuOTc2LDI2MS4yNjYsMTE1Ljk0OSwyNjUuOTd6IE0yMzkuMjg5LDY4My45OGMwLDI5LjgyMy0yNC4xNzcsNTQtNTQsNTQgcy01NC0yNC4xNzctNTQtNTRzMjQuMTc3LTU0LDU0LTU0UzIzOS4yODksNjU0LjE1NywyMzkuMjg5LDY4My45OHogTTIzOS4yODksNDUyLjk4YzAsMjkuODIzLTI0LjE3Nyw1NC01NCw1NHMtNTQtMjQuMTc3LTU0LTU0IHMyNC4xNzctNTQsNTQtNTRTMjM5LjI4OSw0MjMuMTU3LDIzOS4yODksNDUyLjk4eiBNMTg1LjI4OSwzMjcuOThjLTI5LjgyMywwLTU0LTI0LjE3Ny01NC01NGMwLTI5LjgyMywyNC4xNzctNTQsNTQtNTQgczU0LDI0LjE3Nyw1NCw1NEMyMzkuMjg5LDMwMy44MDQsMjE1LjExMywzMjcuOTgsMTg1LjI4OSwzMjcuOTh6IE0yNTMuMDc5LDI2OC42OWMtMS4yNzEtNi40MDUtMi4yNDEtMTEuMjk3LTMuMjc5LTE2LjUyNSBjNS4zNTYsMS4wNDcsMTAuMDU3LDEuOTY2LDE2LjYzNCwzLjI1MUMyNjEuNjQ0LDI2MC4xNzcsMjU3Ljc2NCwyNjQuMDM0LDI1My4wNzksMjY4LjY5eiBNMjcyLjI4OSwyMzkuOTggYy0yOS44MjMsMC01NC0yNC4xNzctNTQtNTRjMC0yOS44MjMsMjQuMTc3LTU0LDU0LTU0YzI5LjgyMywwLDU0LDI0LjE3Nyw1NCw1NEMzMjYuMjg5LDIxNS44MDQsMzAyLjExMywyMzkuOTgsMjcyLjI4OSwyMzkuOTh6XCIsXG4gICAgICAgIGNsb2Nrczoge1xuICAgICAgICAgICAgc2l6ZTogMTA4LFxuICAgICAgICAgICAgMDogeyB4OiAxODUuMTI4LCB5OiAxMDAgfSxcbiAgICAgICAgICAgIDE6IHsgeDogOTguMTI4LCB5OiAxODYgfSxcbiAgICAgICAgICAgIDI6IHsgeDogMjcyLjEyOCwgeTogMTg2IH0sXG4gICAgICAgICAgICAzOiB7IHg6IDE4NS4xMjgsIHk6IDI3NCB9LFxuICAgICAgICAgICAgNDogeyB4OiAxODUuMTI4LCB5OiA0NTMgfSxcbiAgICAgICAgICAgIDU6IHsgeDogMTg1LjEyOCwgeTogNjg0IH1cbiAgICAgICAgfVxuICAgIH1cbn07XG5leHBvcnQgY29uc3QgU1ZHREFUQSA9IHtcbiAgICB0ZWV0aDoge1xuICAgICAgICB0YWxsOiB7XG4gICAgICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgMTU0MFwiLFxuICAgICAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgICAgICBmcmFtZTogXCJNMCwwdjE1NDBsNTEyLTI0NC4yVjBIMHogTTQ1MSwxMjYzLjVsLTM5MCwxODZWNjFoMzkwVjEyNjMuNXpcIixcbiAgICAgICAgICAgICAgICBoYWxmOiBcIk0wLDB2NzQ4bDUxMi0yNDQuMlYwSDB6XCIsXG4gICAgICAgICAgICAgICAgZnVsbDogXCJNMCwwdjE1NDBsNTEyLTI0NC4yVjBIMHpcIlxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBtZWQ6IHtcbiAgICAgICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiAxNTQwXCIsXG4gICAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgICAgIGZyYW1lOiBcIk0wLDB2MTM4OGw1MTItMzk1LjZWMEgweiBNNDU4LDk2NS43TDU0LDEyNzhWNTNoNDA0Vjk2NS43elwiLFxuICAgICAgICAgICAgICAgIGZ1bGw6IFwiTTAsMHYxNTQwbDUxMi0yNDQuMlYwSDB6XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgc2hvcnQ6IHtcbiAgICAgICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiAxNTQwXCIsXG4gICAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgICAgIGZyYW1lOiBcIk0wLDB2OTkxbDUxMS40LTI0N0w1MTIsMEgweiBNNDcwLjUsNzE1LjJMNDEsOTIyLjZWNDBoNDMwTDQ3MC41LDcxNS4yelwiLFxuICAgICAgICAgICAgICAgIGZ1bGw6IFwiTTAsMHY5OTFsNTExLjQtMjQ3TDUxMiwwSDB6XCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgYXJtb3I6IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgaGVhdnk6IFwiTTE1Ny41LDgwLjdjLTIwLjYsMTMuNy00NiwyMi41LTY5LjQsMjZjNi44LDQ4LjksMjYuMSw4NC4xLDQ2LDk3LjggYzEwLjUsNy4zLDIwLjQsOSwzMC40LDUuNmM4LjktMy4xLDE4LjYtMTEsMjcuOC0yNS42QzE2NS4zLDE1NC4zLDE2MC42LDExMy41LDE1Ny41LDgwLjdMMTU3LjUsODAuN3ogTTM1NC41LDgwLjggYy0zLjEsMzIuOC03LjgsNzMuNi0zNC43LDEwMy44YzkuMSwxNC42LDE4LjksMjIuNSwyNy44LDI1LjZjMTAsMy40LDE5LjgsMS43LDMwLjQtNS42YzE5LjgtMTMuNywzOS4xLTQ4LjgsNDUuOS05Ny43IEMzOTkuMywxMDMuNywzNzYsOTUuNSwzNTQuNSw4MC44TDM1NC41LDgwLjh6IE0yNTQuNCw2Ny45Yy0zNy4xLDAtNjkuOCw4LjMtODkuNiwyMWMxLjIsNi41LDIuNiwxMyw0LjIsMTkuMyBjMTkuMi04LjIsNTAuMy0xNi43LDg1LjQtMTYuN2MzNS4yLDAsNjYuMyw4LjUsODUuNCwxNi43YzEuNy02LjMsMy4xLTEyLjgsNC4yLTE5LjNDMzI0LjIsNzYuMiwyOTEuNSw2Ny45LDI1NC40LDY3Ljl6IE02NC45LDEyNy45bC00Ny43LDQ1LjVjMjkuOCwzNy4yLDYzLDU2LjgsODYuNSw1OC43YzEuMSwwLjEsMi4zLDAuMSwzLjMsMC4yYzEuOC03LjYsNC0xNS4xLDYuNS0yMi4zIEM5MS43LDE5NC45LDc0LjQsMTY2LjEsNjQuOSwxMjcuOUw2NC45LDEyNy45eiBNNDQ3LjEsMTI3LjljLTkuNiwzOC4zLTI2LjksNjctNDguNiw4MmMwLDAtMC4xLDAtMC4xLDAuMSBjMi41LDcuMyw0LjcsMTQuNyw2LjUsMjIuM2MxLjEsMCwyLjItMC4xLDMuNC0wLjJjMjMuNC0xLjksNTYuOC0yMS41LDg2LjUtNTguN0w0NDcuMSwxMjcuOUw0NDcuMSwxMjcuOXogTTE3NiwxMzkuNCBjNS43LDEyLjIsMTMuMSwyMy4zLDIyLjksMzIuOGw2LjQsNi4ybC00LjMsNy44Yy0yLjMsNC4xLTQuNiw4LTcsMTEuN2M0MC44LDE1LDg1LDE0LDEyNC0wLjJjLTIuNC0zLjYtNC42LTcuNC02LjktMTEuNGwtNC4zLTcuOCBsNi40LTYuMmM5LjQtOS4xLDE2LjctMTkuOSwyMi4zLTMxLjVDMjgwLjgsMTUzLjgsMjI4LjUsMTUxLjMsMTc2LDEzOS40TDE3NiwxMzkuNHogTTQwMS43LDI0My42YzAsMC0zLjcsMzguMS0yMi45LDc2LjEgbC0xMjEuNy0zMi43bC0xLjgtMC40bC0xLjgsMC40bC0xMjAuMywzMi43Yy0xOS0zOC0yMi43LTc2LjEtMjIuNy03Ni4xczEyLDMuOCwxOS41LTE4LjdjMTAuNywzLjIsMjIsMy4zLDMyLjgtMC40IGM5LjItMy4yLDE3LjgtOC44LDI1LjgtMTYuOWMyMS42LDguOSw0NC4yLDEzLjEsNjYuNywxMy4xYzIyLjcsMCw0NS42LTQuMiw2Ny40LTEzLjFjOCw4LDE2LjgsMTMuNywyNi4xLDE2LjkgYzEwLjksMy43LDIyLjMsMy42LDMzLjEsMC40QzM4OS42LDI0Ny40LDQwMS43LDI0My42LDQwMS43LDI0My42eiBNNDg2LjEsMjEwLjdjLTI1LjQsMjQuMi01Mi4xLDM4LTc2LjIsNDBjLTAuNCwwLTAuOSwwLTEuMywwLjEgYzEuMiw4LjEsMiwxNi4yLDIuMywyNC40YzIyLjgsMy44LDU0LjcsMC4xLDkwLTE0LjNMNDg2LjEsMjEwLjdMNDg2LjEsMjEwLjd6IE0yNS45LDIxMC44bC0xNC44LDUwLjFjMzUuMywxNC40LDY3LjIsMTguMSw5MCwxNC4zIGMwLjMtOC4yLDEuMS0xNi4zLDIuMy0yNC40Yy0wLjQsMC0wLjksMC0xLjMtMC4xQzc4LDI0OC43LDUxLjMsMjM0LjksMjUuOSwyMTAuOEwyNS45LDIxMC44eiBNMjU2LDMwNS4ybC0xMTQuOCwyOC4xIGMxLjksNy43LDEwLjEsMTcuNiwxNS40LDIzLjhjMzEuOC03LjMsNTkuMy0xMS40LDk0LjctMTEuNmMyLjYsMCw1LjMsMCw3LjksMGMzOC4yLDAuMyw2NC45LDQuMyw5NS45LDExLjYgYzUuMS02LjIsMTUuMi0xNS44LDE2LjgtMjMuNkwyNTYsMzA1LjJMMjU2LDMwNS4yeiBNMjU0LjEsMzQ3LjhsLTc5LjMsMjIuMWM1LjgsNC44LDE2LDguNSwyMy4yLDEzLjNjMTgtNSwzMy41LTcuOCw1My41LTcuOSBjMS41LDAsMywwLDQuNSwwYzIxLjYsMC4yLDM2LjYsMyw1NC4xLDcuOWM5LjktMS44LDE2LjgtNi44LDI1LjUtMTIuM0wyNTQuMSwzNDcuOEwyNTQuMSwzNDcuOHogTTM3My4zLDM3Ny43IGMtNjguMyw1NS42LTE2Ni45LDU1LjctMjM1LjMsMC4zbC0xLjgsMzUuOWM0LjcsNy45LDE4LjMsMTcsMzgsMjNjMjEsNi40LDQ4LDkuOSw3NS42LDEwLjJjMjcuNiwwLjMsNTUuOC0yLjYsNzkuNC04LjcgYzIxLjYtNS42LDM5LjMtMTQuMiw0OC44LTIzLjlMMzczLjMsMzc3LjdMMzczLjMsMzc3Ljd6XCIsXG4gICAgICAgICAgICBsaWdodDogXCJNMjU0LjksODhjLTIzLjEsMC00NC4xLDIuOC01OS44LDguOGMtNy45LDMtMTQuNSw2LjgtMTkuNSwxMS45Yy01LDUuMS04LjQsMTIuMS04LjQsMTkuOSBjMCwzLjIsMC41LDYuMiwxLjUsOS4xYzIsMzcuMS0yMC45LDgzLjktNDYsMTA3LjVjNS45LDM1LjksMTkuNCw3Mi43LDM5LjYsMTA2LjNjMjMuOCwyMyw1NC42LDM1LjQsODUuOSwzNy4xdi0yNCBjLTkuNi0wLjEtMTktMC41LTI2LjUtMS4xbDAuOC0xMy4yYzcuMSwwLjYsMTYuMiwxLDI1LjcsMS4xdi0yOC4zYy05LjEsMC40LTE3LjksMS44LTI0LjQsNC4ybC0zLjMtMTIuNyBjOC4xLTIuOSwxNy44LTQuNiwyNy43LTUuMXYtMjMuOGMtMi45LDAuMi01LjgsMC41LTguNywxYy0xNy4yLDEtMzEuOCwzLjYtNDUuMiw3LjVsLTAuMS0wLjJjMTYuNy0xNC44LDM4LjEtMjIuMiw1OS42LTIyLjIgYzIxLjQsMCw0Mi45LDcuNCw1OS42LDIyLjJsLTAuMSwwLjFjLTEzLjQtMy45LTI4LjEtNi41LTQ1LjQtNy41Yy0yLjgtMC41LTUuNy0wLjgtOC41LTF2MjMuOGMxMCwwLjUsMTkuNywyLjEsMjcuNyw1LjFsLTMuMywxMi43IGMtNi42LTIuNC0xNS40LTMuOC0yNC41LTQuMnYyOC4zYzkuNC0wLjEsMTguNi0wLjQsMjUuNy0xLjFsMC44LDEzLjJjLTcuNSwwLjctMTYuOSwxLTI2LjUsMS4xdjI0LjFjMzIuNC0wLjgsNjQuNi0xMyw4OS40LTM2LjUgYzIxLjEtMzMuNiwzNC45LTY5LjksNDAuOC0xMDUuM2MtMjYuMi0yMy4yLTUwLjctNzIuNS00Ny44LTExMC43YzAuNy0yLjUsMS01LDEtNy43YzAtNy44LTMuNC0xNC44LTguNC0xOS45IGMtNS01LjEtMTEuNy04LjktMTkuNi0xMS45QzI5OC45LDkwLjgsMjc4LDg4LDI1NC45LDg4TDI1NC45LDg4eiBNMjU0LjksMTAxLjNjMjIuMywwLDQyLjUsMi45LDU2LjQsOC4yYzcsMi43LDEyLjQsNiwxNS43LDkuMyBjMy4zLDMuNCw0LjUsNi4zLDQuNSw5LjljMCwxLjgtMC4zLDMuNi0xLjEsNS41Yy0yMS45LTExLjktNDkuMy0xNy45LTc2LjctMTcuOWMtMjYuNiwwLTUzLjIsNS42LTc0LjcsMTYuOCBjLTAuNS0xLjUtMC43LTIuOS0wLjctNC40YzAtMy41LDEuMi02LjUsNC41LTkuOWMzLjMtMy40LDguNy02LjcsMTUuNy05LjNDMjEyLjQsMTA0LjEsMjMyLjYsMTAxLjMsMjU0LjksMTAxLjNMMjU0LjksMTAxLjN6IE0yNTMuNywxMzBjMjQuNiwwLDQ5LjIsNC44LDY4LjYsMTQuM2MtMy4xLDIuNi02LjksNS4xLTExLjQsNy4zYy0xMy45LDctMzMuOSwxMS41LTU2LDExLjVzLTQyLTQuNS01Ni0xMS41IGMtNC45LTIuNC05LTUuMi0xMi4yLThDMjA1LjgsMTM0LjUsMjI5LjcsMTMwLDI1My43LDEzMHogTTIzMi4zLDE3NC45YzMuNywwLjUsNy41LDAuOSwxMS40LDEuMmMwLjUsMy42LDEsNy41LDEuNiwxMS44IGMxLjYsMTMsMy4zLDI3LjksMy4zLDM3LjVjMCwxMC44LTMuNSwyMC42LTkuNSwyOC4xYy02LjEsNy41LTE0LjUsMTMtMjQuNiwxNi41Yy0xMS4yLDMuOS0yNC41LDUuNi0zOS4zLDQuOCBjLTE0LjItMi41LTI1LjEtOS4zLTM1LjctMTkuNmMyOS4xLDguMyw1NC41LDguMiw3MS45LDIuMWM4LjctMy4xLDE1LjQtNy42LDE5LjctMTNjNC4zLTUuNCw2LjUtMTEuNCw2LjUtMTguOSBjMC03LjctMS42LTIyLjgtMy4xLTM1LjZDMjMzLjYsMTg0LjEsMjMyLjksMTc5LDIzMi4zLDE3NC45TDIzMi4zLDE3NC45eiBNMjc1LDE3NS4yYy0wLjYsNC0xLjMsOS0yLDE0LjYgYy0xLjYsMTIuNy0zLjEsMjcuOS0zLjEsMzUuNmMwLDcuNSwyLjEsMTMuNiw2LjUsMTguOWM0LjMsNS40LDExLDkuOSwxOS43LDEzYzE3LjMsNi4xLDQyLjYsNi4yLDcxLjYtMi4xIGMtMTAuNiwxMC4zLTIxLjUsMTcuMS0zNS43LDE5LjZjLTE0LjgsMC44LTI4LTAuOS0zOS4xLTQuOGMtMTAuMS0zLjUtMTguNS05LTI0LjYtMTYuNXMtOS41LTE3LjMtOS41LTI4LjEgYzAtOS43LDEuNy0yNC42LDMuMy0zNy41YzAuNS00LjMsMS4xLTguMiwxLjUtMTEuN0MyNjcuNCwxNzYsMjcxLjIsMTc1LjcsMjc1LDE3NS4yTDI3NSwxNzUuMnogTTM0Ny4xLDM3MC4yIGMtNTIuOSw0My4xLTEyOS4zLDQzLjItMTgyLjMsMC4zbC0xLjQsMjcuOGMzLjYsNi4xLDE0LjIsMTMuMiwyOS40LDE3LjhjMTYuMyw0LjksMzcuMiw3LjcsNTguNSw3LjljMjEuNCwwLjIsNDMuMi0yLDYxLjUtNi43IGMxNi44LTQuMywzMC40LTExLDM3LjgtMTguNUwzNDcuMSwzNzAuMkwzNDcuMSwzNzAuMnpcIixcbiAgICAgICAgICAgIHNwZWNpYWw6IFwiTTI1NiwxNC4yYy02NS42LDk4LjMtMTMxLjEsOTAuMi0xOTYuNywxMDYuNWMwLDI2Mi4zLDY1LjYsMzI3LjgsMTk2LjcsMzc3IGMxMzEuMS00OS4yLDE5Ni43LTExNC43LDE5Ni43LTM3N0MzODcuMSwxMDQuNCwzMjEuNiwxMTIuNiwyNTYsMTQuMnogTTI1Niw0N2M1LjEsMCw5LjIsNC4xLDkuMiw5LjJzLTQuMSw5LjItOS4yLDkuMiBzLTkuMi00LjEtOS4yLTkuMlMyNTAuOSw0NywyNTYsNDd6IE03MC42LDEzOC4yYzAtNS4xLDQuMS05LjIsOS4yLTkuMnM5LjIsNC4xLDkuMiw5LjJzLTQuMSw5LjItOS4yLDkuMlM3MC42LDE0My4zLDcwLjYsMTM4LjJ6IE05Mi4xLDMwMS4xYy01LjEsMC05LjItNC4xLTkuMi05LjJjMC01LjEsNC4xLTkuMiw5LjItOS4yczkuMiw0LjEsOS4yLDkuMkMxMDEuMywyOTYuOSw5Ny4yLDMwMS4xLDkyLjEsMzAxLjF6IE0xNTcuNyw0MzIuMiBjLTUuMSwwLTkuMi00LjEtOS4yLTkuMmMwLTUuMSw0LjEtOS4yLDkuMi05LjJzOS4yLDQuMSw5LjIsOS4yQzE2Ni45LDQyOC4xLDE2Mi43LDQzMi4yLDE1Ny43LDQzMi4yeiBNMjU2LDQ4My40IGMtNS4xLDAtOS4yLTQuMS05LjItOS4yczQuMS05LjIsOS4yLTkuMnM5LjIsNC4xLDkuMiw5LjJTMjYxLjEsNDgzLjQsMjU2LDQ4My40eiBNMzU0LjMsNDMyLjJjLTUuMSwwLTkuMi00LjEtOS4yLTkuMiBjMC01LjEsNC4xLTkuMiw5LjItOS4yYzUuMSwwLDkuMiw0LjEsOS4yLDkuMkMzNjMuNiw0MjguMSwzNTkuNCw0MzIuMiwzNTQuMyw0MzIuMnogTTMxNC40LDQyNi43Yy0xNS44LDExLjEtMzMuNywxOC43LTUxLjEsMjYuOCBjLTYuNyw0LjctMTQtMC41LTIwLjctMi41Yy00NC43LTE4LjMtODYuNS00OS44LTEwNy42LTk0LjVjLTI5LjgtNjMuNS0zMy44LTEzNS0zNi43LTIwNC4zYzU4LjgtOSwxMTUuMy0yOC41LDE1Ni4yLTcyLjFsMS45LTIuMSBjNC41LDUsOS4zLDkuOCwxNC4yLDE0LjVjMzUuOCwzNi4zLDg1LDQ3LDEzMy45LDU3LjhjMi44LDEuMiw2LjgsMC41LDkuMSwyYy0yLjcsNjYuNC01LjcsMTM0LjktMzMuMSwxOTYuNCBDMzY3LjMsMzgwLjksMzQzLjIsNDA3LjcsMzE0LjQsNDI2Ljd6IE00MTkuOSwzMDEuMWMtNS4xLDAtOS4yLTQuMS05LjItOS4yYzAtNS4xLDQuMS05LjIsOS4yLTkuMnM5LjIsNC4xLDkuMiw5LjIgQzQyOS4xLDI5Ni45LDQyNSwzMDEuMSw0MTkuOSwzMDEuMXogTTQzMi4yLDE0Ny40Yy01LjEsMC05LjItNC4xLTkuMi05LjJzNC4xLTkuMiw5LjItOS4yczkuMiw0LjEsOS4yLDkuMiBTNDM3LjMsMTQ3LjQsNDMyLjIsMTQ3LjR6IE0zMDEuMSwxNTQuOWMwLjIsMjMuMywwLjMsNDYuNiwwLjUsNjkuOWMwLDEsMC40LDIuMiwwLjksMy4xYzQuOSw4LjQsOS44LDE2LjksMTUsMjUuMSBjMS42LDIuNiwwLjgsNS4xLDAuNiw3LjZjLTAuNyw5LjUtMS43LDE5LTIuNiwyOC41Yy0xLDEwLjUtMiwyMS0zLDMxLjZjLTAuOCw5LTEuNiwxNy45LTIuNCwyNi45Yy0wLjgsOS0xLjcsMTcuOS0yLjUsMjYuOSBjLTAuNyw3LjMtMS4zLDE0LjYtMiwyMmMtMC4xLDEuMi0wLjYsMi43LTEuNCwzLjZjLTEyLDEyLTI0LjEsMjMuOS0zNi4yLDM1LjljLTAuMiwwLjItMC41LDAuNS0xLjEsMWMwLTEuMSwwLTEuOCwwLTIuNSBjMC4xLTY2LjUsMC4zLTEzMywwLjUtMTk5LjVjMC0xLjUsMC44LTMuMiwxLjctNC40YzIuMi0yLjksMi44LTYsMi44LTkuNmMwLTI4LjUsMC4xLTU3LjEsMC4yLTg1LjZjMC0wLjcsMC0xLjUsMC0yLjUgYzAuOCwwLDEuNS0wLjEsMi4zLTAuMWMxMy45LDAuMSwyNy44LDAuMSw0MS43LDAuMWMxLjIsMCwxLjksMC4zLDIuMywxLjVjMC44LDIuMiwxLjcsNC4zLDIuNyw2LjZjLTYuMiwzLjktMTIuMiw3LjYtMTguMiwxMS4zIEMzMDEuNiwxNTIuNiwzMDEuMSwxNTMuNCwzMDEuMSwxNTQuOXogTTI0NS4yLDQzMy43YzAsMC45LDAsMS43LDAsMi42Yy0wLjIsMC4xLTAuNCwwLjItMC42LDAuM2MtMS40LTEuNS0yLjgtMy4xLTQuMy00LjUgYy0xMC43LTEwLjYtMjEuNS0yMS4yLTMyLjItMzEuOWMtMC45LTAuOS0xLjYtMi41LTEuNy0zLjljLTEtOS4yLTEuOC0xOC40LTIuNi0yNy41Yy0wLjctNy4yLTEuMy0xNC4zLTItMjEuNSBjLTAuOC05LjItMS43LTE4LjQtMi42LTI3LjVjLTAuNy03LjEtMS4zLTE0LjItMS45LTIxLjNjLTAuOS05LjMtMS43LTE4LjUtMi42LTI3LjhjLTAuNS00LjktMS05LjktMS4zLTE0LjggYy0wLjEtMC43LDAuNC0xLjYsMC44LTIuMmM1LjEtOC42LDEwLjItMTcuMSwxNS4yLTI1LjdjMC41LTAuOSwwLjktMi4xLDAuOS0zLjFjMC4yLTIzLjIsMC4zLTQ2LjQsMC41LTY5LjZjMC0xLjYtMC41LTIuNS0xLjktMy40IGMtNi0zLjYtMTEuOS03LjMtMTgtMTEuMmMxLTIuNSwyLTQuOSwzLjEtNy40YzAuMi0wLjMsMC44LTAuNiwxLjItMC42YzE0LjYtMC4xLDI5LjMtMC4xLDQzLjktMC4xYzAuMSwwLDAuMywwLjEsMC42LDAuMyBjMCwwLjcsMC4xLDEuNSwwLjEsMi4zYzAuMSwyOS4yLDAuMiw1OC40LDAuMyw4Ny43YzAsMi4xLDAuMyw0LDEuNyw1LjZjMi41LDIuOSwzLDYuMiwzLDEwQzI0NC45LDMwMy40LDI0NS4xLDM2OC41LDI0NS4yLDQzMy43elwiLFxuICAgICAgICAgICAgc3BlY2lhbEJnOiBcIk0zMTYuOSw0MzIuNGMtMTYuNSwxMS42LTM1LDE5LjQtNTMuMSwyNy44Yy03LDQuOS0xNC42LTAuNS0yMS42LTIuNiBjLTQ2LjUtMTktOTAtNTEuOC0xMTEuOS05OC4zYy0zMS02Ni4xLTM1LjEtMTQwLjUtMzguMi0yMTIuNGM2MS4yLTkuNCwxMTkuOS0yOS42LDE2Mi40LTc1bDItMi4xYzQuNyw1LjIsOS42LDEwLjIsMTQuNywxNS4xIGMzNy4yLDM3LjcsODguNCw0OC45LDEzOS4yLDYwLjFjMi45LDEuMyw3LjEsMC41LDkuNCwyLjFjLTIuOSw2OS4xLTUuOSwxNDAuMy0zNC40LDIwNC4zQzM3MiwzODQuOCwzNDYuOCw0MTIuNywzMTYuOSw0MzIuNHpcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLlJlZHVjZWRFZmZlY3RdOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIG1haW46IFwiTTI2MC43LDQ4Ny41NUMxMzMsNDg3LjU1LDI4LjM5LDM4Mi45MiwyOC4zOSwyNTUuMjNTMTMzLDI0LjQ1LDI2MC43LDI0LjQ1QTIzMC41LDIzMC41LDAsMCwxLDQ5MS40OSwyNTUuMjNjMCwxMjcuNjktMTAzLjEsMjMyLjMyLTIzMC43OCwyMzIuMzJabS0xLjA2LTgyTDM3NywyODcuNThsLTIzLjk0LTI1LjEtNjUuNDEsMzcuOTRWMTI4YTE2Ny4yOCwxNjcuMjgsMCwwLDEsMTAzLjYsMjY4LjkxLDE5My43MSwxOTMuNzEsMCwwLDAsNjEuMjItMTQxLjYzQTE5MS4xOCwxOTEuMTgsMCwwLDAsMjYwLjcsNjMuNDVjLTEwNi4zOSwwLTE5My4zMSw4NS4zOS0xOTMuMzEsMTkxLjc4QTE5Mi45LDE5Mi45LDAsMCwwLDEyOCwzOTUuNTUsMTY3LjMsMTY3LjMsMCwwLDEsMjMxLDEyOC4yVjI5Ni45MmwtNjIuNS0zNS42Mi0yNS4wOSwyNi4yOFpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBtYWluOiBcImZpbGwtbGluZWFyXCJcbiAgICAgICAgfVxuICAgIH0sXG4gICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25NaW5vcl06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgbWFpbjogXCJNMzQ1LjU4LDI2My4xOGwzOS43NC04LjMxLDczLjI5LTE1LjMsMjIuODMtNC43OSwyLjgxLS41OCw5LjU2LTJWMjEzLjFsLTYuMzMsMS4zMy03OS41NSwxNi42Mi0yNi40OSw1LjU0LTU1LjkzLDExLjY5Yy0xMy0xMS4xOC0yMC0yNC43My0yNy4xNi0zOS44OWwtMS42Ny0zLjUzLDM0LjE4LTQ2Ljc2LDU3Ljg3LTc5LjE4LDMtNC4xLDQxLjE5LTU2LjMzSDQwOS43N0wzNzUuMjYsNjUuN2wtNC4wOSw1LjU5LTYwLjUxLDgyLjc4LTMyLjkxLDQ1Yy0xNS4wNi02LjM2LTI2LjE0LTE3Ljc2LTM4LjU3LTMwLjMzbC0yLjM0LTIuMzctNC41OS0zMC4yOEwyMTYuNzIsMzMuNWwtMS02LjQ3LTEuMjktOC41NGgtMTguOWwyLjg0LDE4Ljc1LS4xMS00LjQxLDE1LjIsMTA0LjEsNS41OSwzN2MtMTEuMTgsNy41LTI0LjQ0LDEyLjE1LTM5LDE1LjQ5bC0yMi45LTI4Ljg5TDkzLjgsODAuNTgsNDQuNTgsMTguNDlIMjAuNzRsNTMsNjYuODMsNC4xOCw1LjI2LDY2LjU0LDg0LDE5LjE1LDI0LjE2LS4wOC43Yy0xLjkzLDE3LjM3LTguODgsMjkuNjMtMTYuNjUsNDMuMDdMMTE1LjMsMjM0LjIsMjUuNDksMjEwLjYxLDIzLjA4LDIxMGwtNC4zMS0xLjE0djE5LjMybDIuNTYuNjdMMTEyLDI1Mi42NWwyNy42MSw3LjI1LjU2LDEuNGM2LjEsMTUuMTUsNS4zOSwzMS43NywyLjksNDkuNzFsLTMwLjMxLDE0LjJMMjMuMTUsMzY3LjE0bC00LjM4LDIuMDZ2MjAuNjJsOS4xOC00LjMsNjcuOTItMzEuNzcsMTcuMTMtOCwyOC45Mi0xMy41NCwxLjUyLDEuNTNjNS44NSw1Ljg2LDEwLDEwLjI5LDExLjIyLDIwLjc1bC0zMS4xNCwzMS4zTDU2LjI3LDQ1My4zOWwtMzcuNSwzNy42OXYyLjQzaDI0bDIwLjkxLTIxaDBsNzcuOTQtNzguMzYsMjQuMTEtMjQuMjQsMS0uMjNjMjMuNzUtNS43OSw1OS44Ni02Ljc1LDgwLjExLTYuNzgsNCwwLDYuODEsMCw5LjM1LjA4bDEwLjQsMzIuMjlMMjkzLDQ3Ny43M2wxLjU0LDQuNzgsMy41NCwxMWgxOS42M2wtNS4xOS0xNi4xNC0yLjI0LTYuOTUtMjUuNzctODAuMDYtMTEtMzQuMzJjMy41NS0zLjE3LDguNzMtNy42MywxNS0xMi40MiwxMS40Mi04LjczLDI2LjIxLTE3LjcsMzUuNjgtMTkuNjJsNC4yNC0uODcsMjUuMzcsMTBMNDQyLDM2OC4wOGw0LjE4LDEuNjYsNDcuNiwxOC44M1YzNjguNDhsLTM3Ljc4LTE1LTUuMjEtMi04Mi43NS0zMi43NC0zNi41OS0xNC40OGMwLTEzLjE2LDEuNC0yMi44NSw5LjEyLTMzLjkzWm0tNjEuMzUtNDEuMjljNS4xMiwxMC40MSwxMS4xMSwyMS4xLDE5LjY2LDMwLjkxbC0zMS4xNSw2LjUyYTM5LjY5LDM5LjY5LDAsMCwwLTYuOTMtMTIuMjJabS02Mi4xMy0yOCw2LDM5Ljc0YTM5LjI1LDM5LjI1LDAsMCwwLTEwLjI1LDMuNDhsLTI1LjE4LTMxLjc3QTEzMiwxMzIsMCwwLDAsMjIyLjEsMTkzLjlabS00My4zOSwyMy45MiwyNC45MSwzMS40M2EzOC42LDM4LjYsMCwwLDAtNC4wOCw3LjA3bC0zMy45Mi04LjkyQzE3MC41OCwyMzguNjUsMTc1LjQ1LDIyOS4xNSwxNzguNzEsMjE3LjgyWm0xNy40OSw1Ni45M2EzOS4zMiwzOS4zMiwwLDAsMCwyLjA4LDEwLjQ1TDE2MywzMDEuN2MxLjA1LTExLjkxLjkyLTI0LjA1LTItMzYuMlpNMTYwLDMyNC4yN2wuMDktLjU1LDQ3LjE1LTIyLjA3aDBMMTY5LjU1LDMzOS41QTU0Ljc5LDU0Ljc5LDAsMCwwLDE2MCwzMjQuMjdabTI4LjM3LDIyLjg1LDM2LjYxLTM2LjhhMzkuNDMsMzkuNDMsMCwwLDAsMTAuNiwxLjQ1LDM1LjU0LDM1LjU0LDAsMCwwLDQtLjJMMjUwLDM0NC4xMUMyMzYuNywzNDQsMjEyLjQxLDM0NC4yLDE4OC4zMywzNDcuMTJaTTI1MC43OCwyMzZhMzUuMzksMzUuMzksMCwwLDAtMy42MS0xLjMyTDI0MS40NiwxOTdhMTA5LjQ1LDEwOS40NSwwLDAsMCwyNS4xNSwxNy4zOFptMjYuMzcsOTIuNzZjLTMuOSwzLTcuMSw1LjYxLTkuODgsOGwtMTAuMS0zMS40YTM5LjgxLDM5LjgxLDAsMCwwLDguMTYtNy4xNmwzNi41LDE0LjQ0QTE2OSwxNjksMCwwLDAsMjc3LjE1LDMyOC43NlptMzYtMzEuNzZMMjczLjksMjgxLjQ3Yy4yNi0xLjE0LjQ3LTIuMjkuNjQtMy40NGw0NS41OC05LjUzQzMxNS41LDI3Ny45MywzMTMuNzQsMjg3LjM5LDMxMy4xNywyOTdaXCJcbiAgICAgICAgfSxcbiAgICAgICAgY2xhc3Nlczoge1xuICAgICAgICAgICAgbWFpbjogXCJmaWxsLXJhZGlhbFwiXG4gICAgICAgIH1cbiAgICB9LFxuICAgIFtDb25zZXF1ZW5jZVR5cGUuQ29tcGxpY2F0aW9uTWFqb3JdOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIG1haW46IFwiTTQ1OC4yNiwyMzkuNTdsMjIuODMtNC43OCwyLjgxLS41OSw5LjU2LTJ2LTE5LjFsLTYuMzMsMS4zMy03OS41NSwxNi42Mi0yNi40OSw1LjU0LTU1LjkzLDExLjY5Yy0xMy0xMS4xOC0yMC0yNC43My0yNy4xNi0zOS44OWwtMS42Ny0zLjUzLDM0LjE4LTQ2Ljc2LjU4LS43OWM5Ljc2LDI4LjM3LDI0Ljg0LDU4LjQ4LDUxLjM2LDc4LjM1bDI0LjYtNSwxLjgzLS41NEw0MDcuMDcsMjI5Yy0zNy4yNy0xOS4xNS01MC40NS01MS42NC02MS45NC04OC44M2wtLjQ0LTEuNDMsNDMuNjktNTkuNzgsMy00LjEsNDEuMTktNTYuMzRINDA5LjQyTDM3NC45MSw2NS43bC00LjA5LDUuNi00Ni43MSw2My45Yy0zNC43My4yMy03MC40Mi0zLTk1Ljc2LTIyLjVsLTEyLTc5LjE5LTEtNi40Ny0xLjI5LTguNTVIMTk1LjJMMTk4LDM3LjI0bC0uMTEtNC40LDEyLjE4LDgzLjQ0Yy0xNywxNi44OS0zOS4xNSwyOC43My02Ny4zOSwyNi40OEw5My40NSw4MC41OSw0NC4yMywxOC40OUgyMC4zOWw1Myw2Ni44Myw0LjE4LDUuMjdMMTI5LDE1NS41MWMtMy4xNiwyNy4yNC0xNi42Myw1My4zMy0zMi44OCw3My43NGwtNzEtMTguNjNMMjIuNzMsMjEwbC00LjMxLTEuMTN2MTkuMzJsMi41Ni42Nyw3MS4zOCwxOC43NGM4LjI5LDI2LjczLDYuMyw1Ny4yOCwyLjEyLDg2TDIyLjgsMzY3LjE1bC00LjM4LDIuMDV2MjAuNjNsOS4xOC00LjMsNjcuOTItMzEuNzgsMS4wOS0uNTFBMTkwLjUyLDE5MC41MiwwLDAsMSwxMDQuNDcsMzgyYzEuMzMsNy4yNSwyLjU4LDE0LjY4LDMuMTksMTkuMzZsLTUxLjc0LDUyLTM3LjUsMzcuNjl2Mi40M0g0Mi4zN2wyMC45MS0yMWgwbDU4LjI3LTU4LjU3YzEwLjEtLjgzLDMzLjctMi4yOCw1OS4wNi0zLjE3LDcuOS0uMjgsMTYuMTUtLjQ1LDI0LjQ2LS40NywyMy40Ny0uMDUsNDkuNCwxLjEyLDY3LjM0LDQuNDVsMjAuMjcsNjMsMS41NCw0Ljc5LDMuNTQsMTFoMTkuNjNsLTUuMTktMTYuMTRMMzEwLDQ3MC40MywyOTEuMiw0MTIuMTdjMjMuNDMtMjcuMDUsNDguNjItNTQuODcsODYtNjkuNThsNjQuNDUsMjUuNSw0LjE4LDEuNjUsNDcuNiwxOC44NHYtMjAuMWwtMzcuNzgtMTUtNS4yMS0yLjA2LTYyLjc0LTI0LjgyYy0zLjExLTI0LjIxLDguNjQtNTAuNjQsMjAuMi03Ni41N1pNMjY2LjkyLDMzNi43MmwtMTAuMS0zMS40YTM5Ljc2LDM5Ljc2LDAsMCwwLDguMTYtNy4xNWwzNi41LDE0LjQ0YTE2OSwxNjksMCwwLDAtMjQuNjgsMTYuMTZDMjcyLjksMzMxLjc2LDI2OS43LDMzNC4zOCwyNjYuOTIsMzM2LjcyWm0tNzEuMDctNjJhMzkuMTcsMzkuMTcsMCwwLDAsMi4wOCwxMC40NGwtMzUuMjcsMTYuNWMxLjA1LTExLjkuOTItMjQtMi0zNi4xOVptLTMwLjU4LTI3LjM1YzUtOC43NSw5LjgzLTE4LjI1LDEzLjA5LTI5LjU5bDI0LjkxLDMxLjQzYTM5LjI4LDM5LjI4LDAsMCwwLTQuMDgsNy4wN1ptNDEuNTgsNTQuMjVoMEwxNjkuMiwzMzkuNTFhNTQuNzksNTQuNzksMCwwLDAtOS41OS0xNS4yM2wuMDktLjU2Wm0xNy43NCw4LjY3YTM5LjQzLDM5LjQzLDAsMCwwLDEwLjYsMS40NSwzOCwzOCwwLDAsMCw0LS4ybDEwLjQ3LDMyLjU0Yy0xMy4zMi0uMTYtMzcuNjEuMDgtNjEuNjksM1ptMjIuMjMtNzUuNjRMMjQxLjExLDE5N2ExMDkuMTcsMTA5LjE3LDAsMCwwLDI1LjE1LDE3LjM5TDI1MC40MywyMzZBMzcuODgsMzcuODgsMCwwLDAsMjQ2LjgyLDIzNC42OVptMjYuNzMsNDYuNzhjLjI2LTEuMTMuNDctMi4yOC42NC0zLjQzbDQ1LjU4LTkuNTNjLTQuNjIsOS40My02LjM4LDE4Ljg5LTYuOTUsMjguNVptMzAtMjguNjYtMzEuMTUsNi41MWEzOS41MywzOS41MywwLDAsMC02LjkzLTEyLjIxbDE4LjQyLTI1LjIxQzI4OSwyMzIuMzEsMjk1LDI0MywzMDMuNTQsMjUyLjgxWk0yMzIuNzgsMTM2LjEzYzIzLjE4LDEzLjI2LDUwLjQ3LDE3LjkyLDc3LDE4LjY4bC0zMi4zNyw0NC4zYy0xNS4wNi02LjM3LTI2LjE0LTE3Ljc2LTM4LjU3LTMwLjMzbC0yLjM0LTIuMzctNC41OS0zMC4yOCwwLS4xMlptLTUsOTcuNTJhMzkuMjUsMzkuMjUsMCwwLDAtMTAuMjUsMy40OGwtMjUuMTgtMzEuNzdhMTMyLDEzMiwwLDAsMCwyOS40Mi0xMS40NVptLTE0LjUyLTk2LDUuNDgsMzYuMjVjLTExLjE4LDcuNS0yNC40NCwxMi4xNS0zOS4wNSwxNS40OWwtMjIuNDYtMjguMzRDMTc4LjI1LDE1OS4yMSwxOTguNTgsMTQ5LjQ0LDIxMy4yNCwxMzcuNjVabS02OS42NywzNi4yOC41LjYzLDE5LjE1LDI0LjE1LS4wOC43MWMtMS45MywxNy4zNy04Ljg4LDI5LjYzLTE2LjY1LDQzLjA2TDExNSwyMzQuMmwtLjA3LDBDMTI3LDIxNy41NiwxMzguMzgsMTk1LjEsMTQzLjU3LDE3My45M1pNMTIzLjQsMzg1LjU2Yy0uNDItMi4xNy0xLjA2LTQuOS0xLjQzLTYuOTItMS44NC0xMC00LjctMjMuMzktOC44NS0zMy4xMmwyOC40NS0xMy4zMiwxLjUyLDEuNTNjNS44NSw1Ljg3LDEwLDEwLjMsMTEuMjIsMjAuNzVabTE1Ljg5LTEyNS42NS41NiwxLjRjNi4xLDE1LjE0LDUuMzksMzEuNzcsMi45LDQ5LjcxbC0yOSwxMy41OGMyLjg3LTIyLjc2LDMuNDItNDguMjgtMi4wNi03MS45M2gwWm03Mi4xOCwxMzEuNjRoLTYuNTVjLTguNS4wNS0xNi45LjI1LTI1LC41My0xNS41Ny41NS0yOCwxLjMzLTM3Ljg1LDIuMDdsLjA3LS4wN2E3Ljk0LDcuOTQsMCwwLDEtLjgyLS4wNmwyNC0yNC4xMSwxLS4yM2MyMy43NS01Ljc5LDU5Ljg2LTYuNzUsODAuMTEtNi43OCw0LDAsNi44MSwwLDkuMzUuMDdsMTAuMjksMzJDMjQ5Ljc3LDM5Mi41NSwyMjkuNTgsMzkxLjY2LDIxMS40NywzOTEuNTVabTczLjU5LTEuMTgtLjcxLjUzLS4xNy0uNTMtMTEtMzQuMzJjMy41NS0zLjE3LDguNzMtNy42MywxNS0xMi40MiwxMS40Mi04LjczLDI2LjIxLTE3LjcsMzUuNjgtMTkuNjNsNC4yNC0uODYsMjUuMzcsMTBDMzI0Ljg5LDM0OCwzMDMuNTgsMzY5LjQ3LDI4NS4wNiwzOTAuMzdaTTM2OC40OSwzMTlsLS43Ny0uMzEtMzYuNTktMTQuNDhjMC0xMy4xNSwxLjQtMjIuODQsOS4xMi0zMy45Mmw1LTcuMTRMMzg1LDI1NC44OGwuMTIsMEMzNzYuNDQsMjc0LjA3LDM2OC4xOCwyOTcsMzY4LjQ5LDMxOVpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBtYWluOiBcImZpbGwtcmFkaWFsXCJcbiAgICAgICAgfVxuICAgIH0sXG4gICAgW0NvbnNlcXVlbmNlVHlwZS5Db21wbGljYXRpb25TZXJpb3VzXToge1xuICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgNTEyXCIsXG4gICAgICAgIHBhdGhzOiB7XG4gICAgICAgICAgICBtYWluOiBcIk0yMS40MiwxNy4zNCw3OC41Niw4OS40NWMtMi43Myw0OC41OS0yMy43NSw4NS43OS01Mi4zOSwxMjBsLTYuNzItMS43NlYyMjdsMi41Ni42N0MzNy4zNiwyNzIuNzgsMzEuMSwzMTguNTQsMjMuODMsMzY2bC00LjM4LDIuMDV2MjAuNjNsOS4xOC00LjI5YzYuNTIsMTAuNywxMy42NiwyNywxOS4wNiw0MS4zMyw0LjI5LDExLjMzLDcuNDgsMjEsOS4yNiwyNi41M2wtMzcuNSwzNy42OXYyLjQzaDI0TDcyLDQ2My42N2M5LjI3LS4zNiw0MS43Ny0xLjQ3LDgyLjctLjc1LDQ2Ljc0LjgzLDEwMi42MSw0LjMsMTM5LDEzLjY3bDUuMDgsMTUuNzhoMTkuNjNMMzExLDQ2OS4yOGMzNS45NC00MS41MSw3MS45MS04MC41MiwxMzEuNzMtMTAyLjM0bDUxLjc4LDIwLjQ5di0yMC4xbC00My0xN2MtNi4zNy0zOS4yMSwxMi43Ni03Ni42NywzMC42Mi0xMTYuNjhsMTIuMzctMi41OVYyMTJsLTYuMzMsMS4zMi01LjQ1LTIuOGMtNTYuMDktMjguODMtNzYuMzMtNzgtOTMuMy0xMzIuN0w0MzMuNiwxNy4zNEg0MTAuNDVsLTM4LjYsNTIuODFjLTU4LjI4LDEuMjYtMTEyLjQ4LTIuNDYtMTU0LjQ1LTM3Ljc5bC0yLjI3LTE1aC0xOC45bDIuODMsMTguNzVjLTI3LjEzLDI5LTU3LjU2LDQ4LTEwNC41OCw0My4zNkw0NS4yNiwxNy4zNFptMTk5LjkyLDQxYzQwLjYsMjYuMyw4OC40OSwzMC44OSwxMzYuNzUsMzAuNjNMMzI1LDEzNC4zMmMtMzYuNTkuMzktNjkuODYtMy05NS44NS0yNC42NGwtNy43Ni01MS4zM1ptLTE4Ljg0LjQ0LDguMjksNTQuNzdjLTE3LjgxLDE4LjYyLTM3LjI5LDMwLjE4LTY4LDI2Ljg2TDEwOS43Miw5OC42OGMzOC41OS0uNzQsNjguMzYtMTcuMTUsOTIuNzgtMzkuODlaTTM3NS44Myw5Ni4zOGMxNS41Myw0NywzNy4wNSw5Mi42OSw4NC41NSwxMjIuNzJsLTUxLjc3LDEwLjgyLS44Mi0uNDJjLTM3LjI3LTE5LjE0LTUwLjQ0LTUxLjY0LTYxLjkzLTg4LjgzbC0uNzItMi4zMSwzMC42OC00MlpNOTUuMDksMTEwLjNsMzQuMzksNDMuMzljLTIuNTIsMjkuNTktMTUuNDEsNTIuNjYtMzMuMTQsNzQuMjFMNDUuOTMsMjE0LjY3YzIzLjcyLTI5Ljc4LDQyLjY0LTYzLjM5LDQ5LjE2LTEwNC4zN1pNMjMyLjkzLDEzNWMyMy45NCwxMy42OSw1MS4wNSwxNy40LDc4LjQxLDE3Ljk0bC0zMi45MSw0NWMtMTUuMDYtNi4zNi0yNi4xNC0xNy43NS0zOC41Ny0zMC4zMmwtMi4zNS0yLjM3TDIzMi45MywxMzVabS0xOC43Ny44MSw1LjU5LDM2Ljk1Yy0xMS4xOCw3LjUtMjQuNDQsMTIuMTUtMzkuMDUsMTUuNDlsLTIyLjktMjguODljMjIuNzEtMS40LDQxLjA5LTEwLjY4LDU2LjM2LTIzLjU1Wk0zMzEuNTQsMTU3YzkuNzQsMjkuMTUsMjMuMTQsNTgsNTAuNTgsNzguNDlsLTU1LjkzLDExLjY5Yy0xMy0xMS4xOC0yMC0yNC43NC0yNy4xNi0zOS44OWwtMS42Ny0zLjUzWk0xNDUuMSwxNzMuNDFsMTkuMTUsMjQuMTYtLjA4LjcxYy0xLjkzLDE3LjM2LTguODgsMjkuNjMtMTYuNjUsNDMuMDZMMTE2LDIzMy4wNmMxMy4yMS0xNy4zNiwyMy45NC0zNi44MywyOS4xMi01OS42NVptNzcuNjgsMTkuMzUsNiwzOS43NUEzOC44OCwzOC44OCwwLDAsMCwyMTguNTQsMjM2bC0yNS4xOC0zMS43N2ExMzIuNDksMTMyLjQ5LDAsMCwwLDI5LjQyLTExLjQ1Wm0xOS4zNiwzLjA1YTEwOS4xNywxMDkuMTcsMCwwLDAsMjUuMTUsMTcuMzlsLTE1LjgzLDIxLjY2Yy0xLjE4LS40OS0yLjM4LS45NC0zLjYxLTEuMzJsLTUuNzEtMzcuNzNabS02Mi43NSwyMC44NkwyMDQuMywyNDguMWEzOS4zNywzOS4zNywwLDAsMC00LjA4LDcuMDdsLTMzLjkyLTguOWM1LTguNzYsOS44My0xOC4yNSwxMy4wOS0yOS42Wm0xMDUuNTIsNC4wOGM1LjEyLDEwLjQyLDExLjExLDIxLjEsMTkuNjYsMzAuOTJsLTMxLjE1LDYuNUEzOS42NCwzOS42NCwwLDAsMCwyNjYuNDksMjQ2bDE4LjQyLTI1LjIxWk00My4xNCwyMzMuMjYsOTIsMjQ2LjA5YzkuMjMsMjguMjEsNS44LDU3LjA4LDEuMiw4Ny40NWwtNDkuMDcsMjNjNi00MC4xNSwxMC4yOS04MS40Mi0xLTEyMy4yNFptNDE2LjE0LDUuMTZjLTE0LjkzLDMyLjYzLTMwLjExLDY2LjczLTI3LjQzLDEwNC4xM2wtNDMuNzQtMTcuMzFjLTMuNi0yNSw4Ljc4LTQ5LjQ0LDIwLjcyLTc2LjI4bDUwLjQ1LTEwLjU0Wm0tMzQ2LjU3LDEzLjEsMjcuNjEsNy4yNS41NiwxLjRjNi4xLDE1LjEzLDUuMzksMzEuNzcsMi45LDQ5LjcxbC0zMC4zMiwxNC4xOGMzLjIyLTIzLjUxLDUtNDcuODEtLjc1LTcyLjU0Wk0zODYsMjUzLjc0Yy05LDE5LjgxLTE3LjgsNDAuOC0xNy4yNSw2My44NGwtMzYuNTktMTQuNDdjMC0xMy4xNSwxLjQtMjIuODQsOS4xMi0zMy45Mmw1LTcuMTUsMzkuNzQtOC4zWk0xNjEuNjQsMjY0LjM2bDM1LjI0LDkuMjZBMzkuMzMsMzkuMzMsMCwwLDAsMTk5LDI4NC4wNmwtMzUuMjcsMTYuNWMxLjA1LTExLjkuOTItMjQuMDUtMi4wNS0zNi4yWm0xNTkuMTYsM2MtNC42Miw5LjQ0LTYuMzgsMTguODktNi45NSwyOC41bC0zOS4yNy0xNS41NGMuMjYtMS4xMi40Ny0yLjI3LjY0LTMuNDNsNDUuNTgtOS41M1pNMjY2LDI5N2wzNi41LDE0LjQ0YTE2OSwxNjksMCwwLDAtMjQuNjgsMTYuMTZjLTMuOSwzLTcuMSw1LjYtOS44OCw3Ljk0bC0xMC4xMS0zMS40QTM5Ljc2LDM5Ljc2LDAsMCwwLDI2NiwyOTdabS01OC4xMiwzLjQ4LTM3LjY2LDM3Ljg2YTU0Ljg1LDU0Ljg1LDAsMCwwLTkuNTktMTUuMjRsLjA5LS41NSw0Ny4xNS0yMi4wN1ptMTcuNzMsOC42N2EzOS40MywzOS40MywwLDAsMCwxMC42LDEuNDZjMS4zNSwwLDIuNjktLjA3LDQtLjJMMjUwLjcsMzQzYy0xMy4zMi0uMTYtMzcuNjIuMDctNjEuNywzbDM2LjYxLTM2LjgxWk0zMjkuMSwzMjJsMjUuMzYsMTBjLTI5LjQsMTQuOTItNTAuMzcsMzUuODktNjkuMjUsNTcuMmwtMTEtMzQuMzJjMy41NS0zLjE4LDguNzMtNy42MywxNS0xMi40MywxMS40Mi04LjczLDI2LjIxLTE3LjcsMzUuNjgtMTkuNjNsNC4yNC0uODZabS0xODYuNSw5LjA3LDEuNTIsMS41MmM1Ljg1LDUuODgsMTAsMTAuMzEsMTEuMjIsMjAuNzVMMTI0LjIsMzg0LjY0Yy0uMzUtMi4yNy0uNzQtNC42My0xLjItNy4xNC0yLTEwLjk1LTQuNDUtMjIuOTQtOS4zMi0zMi45bDI4LjkyLTEzLjU0Wm0yMzUuOTMsMTAuNDksMzkuMjIsMTUuNTJjLTQ5LjQyLDIyLjUtODIuOTIsNTYuNjgtMTEzLjQ1LDkxLjQ3bC0xMi40NC0zOC42NWMyNC4xMS0yNy44NCw0Ny42OC01My42MSw4Ni42Ny02OC4zNFptLTI4MiwxMS4wNmMzLDYuODQsNi4yMiwxOC4xNyw4LjA3LDI4LjI2LDEuNTgsOC42MSwyLjUsMTYuMDgsMywyMC40NUw3MS43Miw0MzcuNGMtMS42OC01LTMuNzgtMTEtNi41NS0xOC4yOS01LjM3LTE0LjIyLTEyLTMwLTE5LjYxLTQyLjY0bDUxLTIzLjg2Wm0xNTAuODYsOS4xNWM0LDAsNi44MSwwLDkuMzUuMDZsMTAuMzksMzIuM2MtMjYuMjUtNC4xNS01OC42My00LjE5LTg3LTMuMTgtMTUuNTguNTUtMjgsMS4zMi0zNy44NiwyLjA2bDI0LjExLTI0LjI0LDEtLjIzQzE5MSwzNjIuNzQsMjI3LjE2LDM2MS43OSwyNDcuNDEsMzYxLjc2Wm0tNDIuMTksNDcuMzljMjQuOTItLjA2LDUwLjM2LDEuMjYsNjguNDEsNS4xTDI4Ny4wNiw0NTZjLTM4LjcxLTguMjMtODktMTEtMTMyLjA5LTExLjc0LTI3LjIyLS40OC00OS4yMy0uMTktNjMuODcuMTdsMzAuOC0zMWM3Ljc3LS43NiwzMC43MS0yLjg0LDU4Ljg2LTMuODQsNy45LS4yOCwxNi4xNS0uNDUsMjQuNDYtLjQ3WlwiXG4gICAgICAgIH0sXG4gICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIG1haW46IFwiZmlsbC1yYWRpYWxcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLkxvc3RPcHBvcnR1bml0eV06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgbWFpbjogXCJNMzczLjMzLDUyLjc2QTIzNC41NywyMzQuNTcsMCwwLDAsNTIuNzcsMTM4LjY3Qy0xMiwyNTAuOTMsMjYuNDEsMzk0LjQxLDEzOC42Nyw0NTkuMjNzMjU1Ljc1LDI2LjM2LDMyMC41Ni04NS45MVM0ODUuNTksMTE3LjU4LDM3My4zMyw1Mi43NlptLTIxMS44NywzNjdBMTg5LjEsMTg5LjEsMCwwLDEsODEsMTg0LjM3TDMyNy42Miw0MzFBMTg4LjczLDE4OC43MywwLDAsMSwxNjEuNDYsNDE5Ljc2Wm0yMTEuMTgtMTQuODdMMTA3LjE0LDEzOS4zOGExODcuMywxODcuMywwLDAsMSwzMi4yNC0zMi4yOUw0MDQuODksMzcyLjZBMTg3LjcxLDE4Ny43MSwwLDAsMSwzNzIuNjQsNDA0Ljg5Wk00MzEsMzI3LjYsMTg0LjQxLDgxQTE4OS4xMiwxODkuMTIsMCwwLDEsNDMxLDMyNy42WlwiXG4gICAgICAgIH0sXG4gICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIG1haW46IFwiZmlsbC1saW5lYXJcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLldvcnNlUG9zaXRpb25dOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIGhvcml6b246IFwiTTE4LjM2LDIyNy44djE4LjY4aDg2LjM3YTk4LjQ1LDk4LjQ1LDAsMCwwLTQuNDMtMTguNjhabTM3OS40LDBhMTEwLjUxLDExMC41MSwwLDAsMSw5LjQ0LDE4LjY4aDg2LjQ0VjIyNy44SDM5Ny43NlpcIixcbiAgICAgICAgICAgIGJvb3Q6IFwiTTIxOC42NywxOC43M2ExNjIuMTQsMTYyLjE0LDAsMCwwLTIwLDEuMzJDMTY0LDI0LjM5LDEyMy41LDM5LjQsOTEuMjMsNjcuMzZMMTI0LjcsMjU3LjU1bC4zNSwxMC4xMmM0Mi4yNiwxNS43OSwxMDAuODIsMjQuNTUsMTUyLjg3LDI0LjI1LDI3LjE5LS4xNSw1Mi42NC0yLjc0LDczLTcuNzhzMzUuMi0xMi44Miw0MS44MS0yMC45NGwuNDQuMzVhMTEzLDExMywwLDAsMC02LjUzLTE3LjA2aC4xOWE5NS44OCw5NS44OCwwLDAsMC00Ljg1LTguNjZjLS4wOS0uMTQtLjE2LS4zLS4yNS0uNDRsLS4zMS0uNDdjLTIxLjQ2LTM0Ljg5LTYzLjUtNTUuODctMTI0LjI4LTI5LjM3bC0uMTYuMDZhMjE1LjM3LDIxNS4zNywwLDAsMC0zNCwyMC4xOWgtLjgxYzExLTE1LjcyLDIzLjI2LTI4LjEyLDM1LjkxLTM3LjI4bDEuMTItMTEuMTZjLTE0LjY4LTQtMzguMDgtNC4wNi01My41My0uMDlMMjAxLDE2MS4xNGExMzAuMzMsMTMwLjMzLDAsMCwxLDMwLjM0LTMuODRjMS41LDAsMywwLDQuNSwwYTExNy42NiwxMTcuNjYsMCwwLDEsMjUuMjUsMy4xMmwzLjE5LTMyYy0yMS4wNi04LjA3LTQyLjEyLTYuNi02NC41Ny0xLjU5bC00LjA2LTE4LjI1QTE3MC4wNywxNzAuMDcsMCwwLDEsMjMxLDEwNC4xN2MxLjcyLDAsMy40NCwwLDUuMTYuMDdhMTA3LDEwNywwLDAsMSwzMC4wNiw1LjEybDMuMTYtMzEuNDdjLTI1LjYtNy42OS01MS04LjEtNzYuOTEtMi43OGwtMy43OC0xOC4yOEExODguNTMsMTg4LjUzLDAsMCwxLDIyMS41Miw1M2MxLjE0LDAsMi4yOS0uMDUsMy40My0uMDZBMTY3LjM2LDE2Ny4zNiwwLDAsMSwyNzEuMjMsNTlsLjQ3LTQuNmM1LTIzLjMxLTE4Ljc1LTM1LjcxLTUzLTM1LjY1Wk0zOTcuMjYsMjg0LjQ1Yy0xMC44NCw4LjEzLTI1LjI2LDEzLjctNDEuODcsMTcuODItMjIuMzcsNS41NC00OS4wNyw4LjE4LTc3LjM4LDguMzRhNTI2LjQ2LDUyNi40NiwwLDAsMS02NS4wOS0zLjc1TDIyNS4zNiwzMjljODAuMTYsOS40NCwxNDEuNS0xLjE5LDE3Mi0yMS43OGExMTMuMTMsMTEzLjEzLDAsMCwwLS4xMy0yMi43NVpNMTI1LjcsMjg3Ljc3bDEsMzAuNDcsNTguNiw4LjQzLDkuNTktMjIuMzFjLTI0LjU1LTMuODItNDguMjEtOS4zNy02OS4xOS0xNi41OVpcIixcbiAgICAgICAgICAgIGljZTogXCJNOTIuNjEsMzA5LjNDODIuMywzMTIuMzcsNzQsMzE1Ljc2LDY4LDMxOS4zNmwtLjIxLjEyTDM3LjU4LDMzNC4yLDE4LjM2LDMyMnYyMi4xNkwzMiwzNTIuOGw0LjQxLDIuODEsNC43Mi0yLjMxLDIyLTEwLjcyYzExLjcxLDkuOCw0MC40NiwxOC4yMyw3OS40LDIzLjg3bC02MCwyOC4yNSwyNi42MywyMUwxOC4zNiw0NTQuMjN2MzlIMTQ1LjE0TDE4OC44Niw0NDdsNTEsNDYuMjhoMjcuODRMMTU5LjExLDM5NC44bDM1LjA2LTIzYzIwLDEuMzcsNDEuMzQsMi4xNSw2My41NiwyLjE1LDIwLjcsMCw0MC42Ni0uNjcsNTkuNDQtMS44N2wzOS4wNiwyNC42OS02Ni45LDM1LjcxLDYyLjI4LDYwLjc1SDQ3NS41MkwzODUsNDQwLjY0bDUxLjMyLTM5Ljc4LTcxLjUtMzMuMjhjNDUuODgtNiw3OS4xOC0xNS42Nyw4OS44MS0yN2wxOCw2LjQzLDIxLjA2LDIyLjU3VjM0Mi4xN2wtOC45NC05LjU2TDQ4My4xNywzMzFsLTIuMTUtLjc4TDQzOS44LDMxNS40MmExNDEuNTcsMTQxLjU3LDAsMCwwLTE2LjY2LTZjNS4zNywzLjI0LDguMjgsNi43LDguMjgsMTAuMjgsMCwxOC41OS03Ny43MywzMy42Ni0xNzMuNjIsMzMuNjZTODQuMTQsMzM4LjI5LDg0LjE0LDMxOS43YzAtMy42MywzLTcuMTMsOC40Ny0xMC40WlwiXG4gICAgICAgIH0sXG4gICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIGhvcml6b246IFwiZmlsbC1kYXJrXCIsXG4gICAgICAgICAgICBib290OiBcImZpbGwtYnJpZ2h0XCIsXG4gICAgICAgICAgICBpY2U6IFwiZmlsbC1yYWRpYWxcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtMV06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgZXllOiBcIk00MDYuMDksMjgyLjY5VjM1Mi42YzQuMTksOC41NCw4LjUzLDE2LjczLDguNTMsMjcuNTYsMCwxMy4yNC04Ljc1LDIyLjc4LTE4LjA5LDIyLjc4LTkuMTMsMC0xOC42OS0xMC0xOC42OS0yMy45NCwwLTEyLjIyLDUuMS0yMC42NCw5LjU2LTI5LjU5VjI4OS42M2MtNi41MS0xOS4zMi0xNi4yMi0yNS40NS0yNi41NC0yMS43MlYyMjYuMjRBNDAxLjY0LDQwMS42NCwwLDAsMCw0MDkuMDcsMjA0aDQ1LjJDNDM1LjY0LDIyMi4yMyw0MTcsMjQ0LjcyLDQwNi4wOSwyODIuNjlaTTQ5NC44MywxNTguOGMtMzMsNDkuODMtODAuNzcsODcuMTItMTM0LDEwOC44MmEyOTEuMjgsMjkxLjI4LDAsMCwxLTkwLDIxLjA3cS03LjIuNTEtMTQuNDIuNjJhMjU2LjMzLDI1Ni4zMywwLDAsMS04OS0xNCwyMzksMjM5LDAsMCwxLTI1LjM1LTEwLjUyQTIzOS42NSwyMzkuNjUsMCwwLDEsODIuNjQsMjIzLjlDNzQuNzYsMjE2Ljg1LDY2LDIwOC44MSw1Ny44OSwyMDBjLTExLjU0LTEyLjUyLTIxLjY2LTI2LjUxLTI1LjcyLTQxLjIzLDIwLjE5LTM3Ljc0LDQ4LjctNjkuMzgsODQuNjYtOTIuMjlDMjQxLjQxLTE0LjY4LDQxNi4zLDM3LjY4LDQ5NC44MywxNTguOFptLTI5LjE3LS4zNkMzNzMuNzgsMTEuODYsMTQwLjQxLDEyLjA4LDU3LjE5LDE2MC4yOGwuNDYuMzktLjQ2LjM5YTM1MywzNTMsMCwwLDAsNTQuNjcsNDIuNTVjNDUuMjEsMjguMzIsOTIuNzcsNDIuMSwxNDAuODIsNDIuMjloLjIyQzMyNC44MSwyNDYuMTQsMzk3LjgxLDIxNS45NCw0NjUuNjYsMTU4LjQ0WlwiLFxuICAgICAgICAgICAgaXJpczogXCJNMzAzLjcsOTkuNTFhNjUsNjUsMCwwLDAtNDUtMThoMGE2NS4yNiw2NS4yNiwwLDEsMCw0NSwxOFptLTQ1LjQsNjguMTNhMjMuNCwyMy40LDAsMSwxLDIzLjM5LTIzLjQxQTIzLjQyLDIzLjQyLDAsMCwxLDI1OC4zLDE2Ny42NFptNDUuNC02OC4xM2E2NSw2NSwwLDAsMC00NS0xOGgwYTY1LjI2LDY1LjI2LDAsMSwwLDQ1LDE4Wm0tNDUuNCw2OC4xM2EyMy40LDIzLjQsMCwxLDEsMjMuMzktMjMuNDFBMjMuNDIsMjMuNDIsMCwwLDEsMjU4LjMsMTY3LjY0Wm00NS40LTY4LjEzYTY1LDY1LDAsMCwwLTQ1LTE4aDBhNjUuMjYsNjUuMjYsMCwxLDAsNDUsMThabS00NS40LDY4LjEzYTIzLjQsMjMuNCwwLDEsMSwyMy4zOS0yMy40MUEyMy40MiwyMy40MiwwLDAsMSwyNTguMywxNjcuNjRaXCJcbiAgICAgICAgfSxcbiAgICAgICAgY2xhc3Nlczoge1xuICAgICAgICAgICAgZXllOiBcImZpbGwtZGFya1wiLFxuICAgICAgICAgICAgaXJpczogXCJmaWxsLW1lZFwiXG4gICAgICAgIH1cbiAgICB9LFxuICAgIFtDb25zZXF1ZW5jZVR5cGUuSW5zaWdodEhhcm0yXToge1xuICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgNTEyXCIsXG4gICAgICAgIHBhdGhzOiB7XG4gICAgICAgICAgICBleWU6IFwiTTMwNS41MSw4OS43MUE3OC41LDc4LjUsMCwwLDAsMjUxLjIyLDY4aDBhNzguODEsNzguODEsMCwxLDAsNTQuMjksMjEuNzFaTTI1MC43MSwxNzJhMjguMjUsMjguMjUsMCwxLDEsMjguMjMtMjguMjdBMjguMjgsMjguMjgsMCwwLDEsMjUwLjcxLDE3MlptNTQuOC04Mi4yNkE3OC41LDc4LjUsMCwwLDAsMjUxLjIyLDY4aDBhNzguODEsNzguODEsMCwxLDAsNTQuMjksMjEuNzFaTTI1MC43MSwxNzJhMjguMjUsMjguMjUsMCwxLDEsMjguMjMtMjguMjdBMjguMjgsMjguMjgsMCwwLDEsMjUwLjcxLDE3MlptNTQuOC04Mi4yNkE3OC41LDc4LjUsMCwwLDAsMjUxLjIyLDY4aDBhNzguODEsNzguODEsMCwxLDAsNTQuMjksMjEuNzFaTTI1MC43MSwxNzJhMjguMjUsMjguMjUsMCwxLDEsMjguMjMtMjguMjdBMjguMjgsMjguMjgsMCwwLDEsMjUwLjcxLDE3MlpcIixcbiAgICAgICAgICAgIGlyaXM6IFwiTTM5OC41OSwyODIuNjlWMzUyLjZjNC4xOSw4LjU0LDguNTMsMTYuNzMsOC41MywyNy41NiwwLDEzLjI0LTguNzUsMjIuNzgtMTguMDksMjIuNzgtOS4xMywwLTE4LjY5LTEwLTE4LjY5LTIzLjk0LDAtMTIuMjIsNS4xLTIwLjY0LDkuNTYtMjkuNTlWMjg5LjYzYy02LjUxLTE5LjMyLTE2LjIyLTI1LjQ1LTI2LjU0LTIxLjcyVjIyNi4yNEE0MDEuNjQsNDAxLjY0LDAsMCwwLDQwMS41NywyMDRoNDUuMkM0MjguMTQsMjIyLjIzLDQwOS40NiwyNDQuNzIsMzk4LjU5LDI4Mi42OVptLTI2NC0xNy45NEEyMzkuNjUsMjM5LjY1LDAsMCwxLDc1LjE0LDIyMy45Yy03Ljg4LTcuMDUtMTYuNjctMTUuMDktMjQuNzUtMjMuODYsMTEuNzksMTguMzQsMjIsMzkuNDgsMjcuNDIsNjAuMjd2NTBjLTQuNzYsMTAuMTQtMTIuMDYsMTcuMjEtMTIuMDYsMjguNDEsMCw5LjA5LDExLjYzLDE4LjA5LDIxLDE4LjA5LDkuMiwwLDIxLjYtOS42NywyMS41OS0xOS4yNSwwLTExLjM2LTcuMzEtMTcuODEtMTEuODctMjdWMjc4LjIyQzEwMywyNjUuMSwxMTcuNzgsMjYxLjEyLDEzNC42MSwyNjQuNzVaTTQ4Ny4zMywxNTguOGMtMzMsNDkuODMtODAuNzcsODcuMTItMTM0LDEwOC44MmEyOTEuMjgsMjkxLjI4LDAsMCwxLTkwLDIxLjA3cS03LjIuNTEtMTQuNDIuNjJhMjU2LjMzLDI1Ni4zMywwLDAsMS04OC45NS0xNCwyMzksMjM5LDAsMCwxLTI1LjM1LTEwLjUyQTIzOS42NSwyMzkuNjUsMCwwLDEsNzUuMTQsMjIzLjljLTcuODgtNy4wNS0xNi42Ny0xNS4wOS0yNC43NS0yMy44Ni0xMS41NC0xMi41Mi0yMS42Ni0yNi41MS0yNS43Mi00MS4yMywyMC4xOS0zNy43NCw0OC43LTY5LjM4LDg0LjY2LTkyLjI5QzIzMy45MS0xNC42OCw0MDguOCwzNy42OCw0ODcuMzMsMTU4LjhabS0yOS4xNy0uMzZDMzY2LjI4LDExLjg2LDEzMi45MSwxMi4wOCw0OS42OSwxNjAuMjhsLjQ2LjM5LS40Ni4zOWEzNTMsMzUzLDAsMCwwLDU0LjY3LDQyLjU1YzQ1LjIxLDI4LjMyLDkyLjc3LDQyLjEsMTQwLjgyLDQyLjI5aC4yMkMzMTcuMzEsMjQ2LjE0LDM5MC4zMSwyMTUuOTQsNDU4LjE2LDE1OC40NFpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBleWU6IFwiZmlsbC1tZWRcIixcbiAgICAgICAgICAgIGlyaXM6IFwiZmlsbC1tZWRcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtM106IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgZXllOiBcIk0zOTguMzEsMjgyLjY5VjM1Mi42YzQuMTksOC41NCw4LjUzLDE2LjczLDguNTMsMjcuNTYsMCwxMy4yNC04Ljc1LDIyLjc4LTE4LjA5LDIyLjc4LTkuMTMsMC0xOC42OS0xMC0xOC42OS0yMy45NCwwLTEyLjIyLDUuMS0yMC42NCw5LjU2LTI5LjU5VjI4OS42M2MtNi41MS0xOS4zMi0xNi4yMi0yNS40NS0yNi41NC0yMS43MlYyMjYuMjRBNDAxLjY0LDQwMS42NCwwLDAsMCw0MDEuMjksMjA0aDQ1LjJDNDI3Ljg2LDIyMi4yMyw0MDkuMTgsMjQ0LjcyLDM5OC4zMSwyODIuNjlabS0yNjQtMTcuOTRBMjM5LjY1LDIzOS42NSwwLDAsMSw3NC44NiwyMjMuOUM2NywyMTYuODUsNTguMTksMjA4LjgxLDUwLjExLDIwMGMxMS43OSwxOC4zNCwyMiwzOS40OCwyNy40Miw2MC4yN3Y1MGMtNC43NiwxMC4xNC0xMi4wNiwxNy4yMS0xMi4wNiwyOC40MSwwLDkuMDksMTEuNjMsMTguMDksMjEsMTguMDksOS4yLDAsMjEuNi05LjY3LDIxLjU5LTE5LjI1LDAtMTEuMzYtNy4zMS0xNy44MS0xMS44Ny0yN1YyNzguMjJDMTAyLjc1LDI2NS4xLDExNy41LDI2MS4xMiwxMzQuMzMsMjY0Ljc1Wm0xMTQuMywyNC41NmEyNTYuMzMsMjU2LjMzLDAsMCwxLTg4Ljk1LTE0LDEwOS43OSwxMDkuNzksMCwwLDEsNDIuMzgsNDguNTh2ODAuNTljLTYuMzYsMTAuNDctMTMuNjIsMTYuOTUtMTMuNjIsMjguODcsMCwxNy44OSwxMS43NiwyNC41LDIzLjkzLDI0LjUsMTEuOTEsMCwyMS42LTUuNjYsMjEuNi0yNC41LDAtOS4zLTcuNDQtMTYuNjMtMTMuMjItMzEuMDZWMzI0LjFDMjI3LjE2LDMwOS4xOCwyMzcuNSwyOTQuNDUsMjQ4LjYzLDI4OS4zMVpNNDg3LjA1LDE1OC44Yy0zMyw0OS44My04MC43Nyw4Ny4xMi0xMzQsMTA4LjgyYTI5MS4yOCwyOTEuMjgsMCwwLDEtOTAsMjEuMDdxLTcuMi41MS0xNC40Mi42MmEyNTYuMzMsMjU2LjMzLDAsMCwxLTg4Ljk1LTE0LDIzOSwyMzksMCwwLDEtMjUuMzUtMTAuNTJBMjM5LjY1LDIzOS42NSwwLDAsMSw3NC44NiwyMjMuOUM2NywyMTYuODUsNTguMTksMjA4LjgxLDUwLjExLDIwMGMtMTEuNTQtMTIuNTItMjEuNjYtMjYuNTEtMjUuNzItNDEuMjMsMjAuMTktMzcuNzQsNDguNy02OS4zOCw4NC42Ni05Mi4yOUMyMzMuNjMtMTQuNjgsNDA4LjUyLDM3LjY4LDQ4Ny4wNSwxNTguOFptLTI5LjE3LS4zNkMzNjYsMTEuODYsMTMyLjYzLDEyLjA4LDQ5LjQxLDE2MC4yOGwuNDYuMzktLjQ2LjM5YTM1MywzNTMsMCwwLDAsNTQuNjcsNDIuNTVjNDUuMjEsMjguMzIsOTIuNzcsNDIuMSwxNDAuODIsNDIuMjloLjIyQzMxNywyNDYuMTQsMzkwLDIxNS45NCw0NTcuODgsMTU4LjQ0WlwiLFxuICAgICAgICAgICAgaXJpczogXCJNMzE0LjQ2LDgwYTkxLjg0LDkxLjg0LDAsMCwwLTYzLjUyLTI1LjM5aDBBOTIuMiw5Mi4yLDAsMSwwLDMxNC40Niw4MFptLTY0LjEyLDk2LjI0YTMzLjA1LDMzLjA1LDAsMSwxLDMzLTMzLjA3QTMzLjA4LDMzLjA4LDAsMCwxLDI1MC4zNCwxNzYuMjVaTTMxNC40Niw4MGE5MS44NCw5MS44NCwwLDAsMC02My41Mi0yNS4zOWgwQTkyLjIsOTIuMiwwLDEsMCwzMTQuNDYsODBabS02NC4xMiw5Ni4yNGEzMy4wNSwzMy4wNSwwLDEsMSwzMy0zMy4wN0EzMy4wOCwzMy4wOCwwLDAsMSwyNTAuMzQsMTc2LjI1Wk0zMTQuNDYsODBhOTEuODQsOTEuODQsMCwwLDAtNjMuNTItMjUuMzloMEE5Mi4yLDkyLjIsMCwxLDAsMzE0LjQ2LDgwWm0tNjQuMTIsOTYuMjRhMzMuMDUsMzMuMDUsMCwxLDEsMzMtMzMuMDdBMzMuMDgsMzMuMDgsMCwwLDEsMjUwLjM0LDE3Ni4yNVpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBleWU6IFwiZmlsbC1tZWRcIixcbiAgICAgICAgICAgIGlyaXM6IFwiZmlsbC1icmlnaHRcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLkluc2lnaHRIYXJtNF06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgZXllOiBcIk0yNDQsMjcuNDRjLTQ2Ljg2LDAtOTMuNTMsMTIuMjUtMTM0LjcsMzkuMDgtMzYsMjIuOTEtNjQuNDcsNTQuNTUtODQuNjYsOTIuMjksNC4wNiwxNC43MiwxNC4xOCwyOC43MSwyNS43Miw0MS4yMyw4LjA4LDguNzcsMTYuODcsMTYuODEsMjQuNzUsMjMuODZhMjM5LjY1LDIzOS42NSwwLDAsMCw1OS40Nyw0MC44NUEyMzksMjM5LDAsMCwwLDE2MCwyNzUuMjdhMjU2LjMzLDI1Ni4zMywwLDAsMCw4OC45NSwxNHE3LjIyLS4xLDE0LjQyLS42MmEyOTEuMjgsMjkxLjI4LDAsMCwwLDkwLTIxLjA3QTI5OS45NCwyOTkuOTQsMCwwLDAsNDMwLjEyLDIyMmEyODYuNDYsMjg2LjQ2LDAsMCwwLDU3LjIxLTYzLjE2QzQzNC43NSw3Ny43MSwzMzksMjcuNDQsMjQ0LDI3LjQ0Wk0yNDUuNCwyNDUuOWgtLjIyYy00OC4wNS0uMTktOTUuNjEtMTQtMTQwLjgyLTQyLjI5YTM1MywzNTMsMCwwLDEtNTQuNjctNDIuNTVsLjQ2LS4zOS0uNDYtLjM5YzgzLjIyLTE0OC4yLDMxNi41OS0xNDguNDIsNDA4LjQ3LTEuODRDMzkwLjMxLDIxNS45NCwzMTcuMzEsMjQ2LjE0LDI0NS40LDI0NS45Wm0xNy45Myw0Mi43OWM3LjE2LDMsMTQuMTEsMTEuNTcsMjAsMjguMDgsMy41NCw5Ljg1LDYuNzEsMjIuNTQsOS4zMywzOC41OHY3NC44NEMyODcuMjcsNDQwLjY5LDI4MSw0NDkuNjQsMjgxLDQ2Mi41czEwLDIyLjE5LDIxLDIyLjE5YzEwLjc0LDAsMjIuMTgtOS43MywyMi4xOC0yMy4zNCwwLTE0LjQ1LTcuMDktMjMuNDItMTIuODEtMzQuNTdWMzQyLjIyaC0uMjJhMjIzLjI2LDIyMy4yNiwwLDAsMSw3LjQ4LTI1LjQ1YzkuNTctMjYuMzcsMjIuNTctNDQuNDcsMzQuNzMtNDguODZ2LS4yOUEyOTEuMjgsMjkxLjI4LDAsMCwxLDI2My4zMywyODguNjlabS0zOC44MiwyOC4wOGM2LjM3LTEyLjE5LDE1LjExLTIzLjE3LDI0LjQtMjcuNDZhMjU2LjMzLDI1Ni4zMywwLDAsMS04OC45NS0xNCwxMDkuNjIsMTA5LjYyLDAsMCwxLDM4LjkxLDQxLjVxMS44NCwzLjQ1LDMuNDcsNy4wOHY4MC41OWMtNi4zNiwxMC40Ny0xMy42MiwxNi45NS0xMy42MiwyOC44NywwLDE3Ljg5LDExLjc2LDI0LjUsMjMuOTMsMjQuNSwxMS45MSwwLDIxLjYtNS42NiwyMS42LTI0LjUsMC05LjMtNy40NC0xNi42My0xMy4yMi0zMS4wNlYzMjQuMUMyMjIuMDksMzIxLjY0LDIyMy4yNiwzMTkuMTgsMjI0LjUxLDMxNi43N1ptLTg5LjktNTJBMjM5LjY1LDIzOS42NSwwLDAsMSw3NS4xNCwyMjMuOWMtNy44OC03LjA1LTE2LjY3LTE1LjA5LTI0Ljc1LTIzLjg2LDExLjc5LDE4LjM0LDIyLDM5LjQ4LDI3LjQyLDYwLjI3djUwYy0xLjA4LDIuMjktMi4yOCw0LjQzLTMuNTEsNi40OS00LjE4LDcuMDYtOC41NSwxMy4yNS04LjU1LDIxLjkyLDAsOS4wOSwxMS42MywxOC4wOSwyMSwxOC4wOSw5LjIsMCwyMS42LTkuNjcsMjEuNTktMTkuMjUsMC04LjYzLTQuMjItMTQuNDMtOC4yNS0yMC43NmE2Nyw2NywwLDAsMS0zLjYyLTYuMjdWMjc4LjIyQzEwMywyNjUuMSwxMTcuNzgsMjYxLjEyLDEzNC42MSwyNjQuNzVabTI2Ny02MC43OGE0MDEuNjQsNDAxLjY0LDAsMCwxLTQ4LjIxLDIyLjI3djQxLjY3YzEwLjMyLTMuNzMsMjAsMi40LDI2LjU0LDIxLjcydjU5Ljc4Yy00LjQ2LDguOTUtOS41NiwxNy4zNy05LjU2LDI5LjU5LDAsMTMuOTQsOS41NiwyMy45NCwxOC42OSwyMy45NCw5LjM0LDAsMTguMDktOS41NCwxOC4wOS0yMi43OCwwLTEwLjgzLTQuMzQtMTktOC41My0yNy41NlYyODIuNjljNy41OS0yNi41MiwxOS00NS40OCwzMS41My02MC43M2EyMjUuNywyMjUuNywwLDAsMSwxNi42NS0xOFpcIixcbiAgICAgICAgICAgIGlyaXM6IFwiTTMyNi41LDY3LjY1YTEwOC44NCwxMDguODQsMCwwLDAtNzUuMjgtMzAuMDhoMEExMDkuMjIsMTA5LjIyLDAsMSwwLDMyNi41LDY3LjY1Wm0tNzYsMTE0LjA2YTM5LjE3LDM5LjE3LDAsMSwxLDM5LjE1LTM5LjE5QTM5LjIsMzkuMiwwLDAsMSwyNTAuNTEsMTgxLjcxWm03Ni0xMTQuMDZhMTA4Ljg0LDEwOC44NCwwLDAsMC03NS4yOC0zMC4wOGgwQTEwOS4yMiwxMDkuMjIsMCwxLDAsMzI2LjUsNjcuNjVabS03NiwxMTQuMDZhMzkuMTcsMzkuMTcsMCwxLDEsMzkuMTUtMzkuMTlBMzkuMiwzOS4yLDAsMCwxLDI1MC41MSwxODEuNzFabTc2LTExNC4wNmExMDguODQsMTA4Ljg0LDAsMCwwLTc1LjI4LTMwLjA4aDBBMTA5LjIyLDEwOS4yMiwwLDEsMCwzMjYuNSw2Ny42NVptLTc2LDExNC4wNmEzOS4xNywzOS4xNywwLDEsMSwzOS4xNS0zOS4xOUEzOS4yLDM5LjIsMCwwLDEsMjUwLjUxLDE4MS43MVpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBleWU6IFwiZmlsbC1icmlnaHRcIixcbiAgICAgICAgICAgIGlyaXM6IFwiZmlsbC1tZWRcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLlByb3dlc3NIYXJtMV06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgc2NhcjogXCJNNDQzLjQ0LDQzNC41M1E0MDguNyw0MDkuODcsMzc2LDM4My42NGMtMjAtMTEuOTEtMzEuNDkuMy00NC4yNiwxNi44Niw4LjgtMTguMTcsMTMuMzgtMzYuOTUsMy4yNC01MC44NmwtNC40Ni0zLjg0LTQ0Ljg1LTM1LjM1TDIzNy45LDMzNi45M2wxNy4xOS0yNS4zNGM3LjMxLTEyLjQsMy40My0yNy4xNy01LjY1LTQxLjE0cS0xNi4zNy0xNi4zMi0zMi4yMi0zM2MtMS42Ni0xLjIzLTMuMzEtMi4zOC00Ljk1LTMuNWwtNjYuNDQsMTguODdMMTY3LjU5LDIyN2MxMC41Ny0xNy42MiwwLTQxLjU5LTkuODQtNTUuN3EtOC40LTkuODEtMTYuNjItMTkuNzVsLTQzLjY3LDcuMjljMTguNDMtNy4zLDMxLjM3LTIyLjM4LDE2Ljg1LTQwbDIuMDYsMi4zM1E5MS43OSw5MC4yOSw2OC40NCw1OC40OXE0MywzMi4zMiw4My44Niw2Ny4wNkwxODguOTIsMTE2bC0yMi4xMSwyMnEyMy4zOCwyMC4zLDQ2LjA5LDQxLjM5bDcxLjg2LTMwLjQ2TDI2NiwxNzhsLjMtLjI0Yy0yMS41NSwyNy41NCwxOC43Nyw4Niw0Niw3OC40MmwzMS45MS0xNy43TDMxOS40LDI3NWwzNi44OCw1Mi43MWMuMjYuMy41My41OS43OS45LDEzLjY0LDEyLjUsMzEuMjMsMS43MSw0My4wNS0xNC41M2wtMTkuNTksNDJRNDEyLjY2LDM5NC4yOCw0NDMuNDQsNDM0LjUzWlwiXG4gICAgICAgIH0sXG4gICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIHNjYXI6IFwiZmlsbC1kYXJrXCJcbiAgICAgICAgfVxuICAgIH0sXG4gICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTJdOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIHNjYXJUaXNzdWU6IFwiTTM5OSwzNTUuMDhjLTE1LTMyLjMxLTE4LjY3LTY1Ljg3LTYuMjMtOTQuNy00Ny4xOSw1OC40MS03Ni4xNCw0LjQxLTQuMDktNzAuNzItMTAxLjY3LDYyLjctMTQ3Ljc4LDMxLjQ3LTE0LTg4LjI2LTEwMyw1NC42Ni0xODIuNDksNjkuMjItMTMwLjkzLDE1LjE5LTM3LjE5LDEwLjYzLTU4LjIxLDUuMjEtNzYtMi40M0E2NDMuNDIsNjQzLjQyLDAsMCwwLDU1LjI4LDU4LjQ5YTc4OS4xNCw3ODkuMTQsMCwwLDAsNDcsNzcuNTZjNywxOC4yNywzLDM4LjcxLTMxLjQ2LDYzLjQ0LDEyNC44NS0zMy40NSw4OC41Miw0Ny05LjM2LDEwNC45MiwxNjYuMjEtNjEuNjgsMjA3LjUyLTQ3LjQxLDEwMC42NCw3OCw4NC02MS4wNywxNTAuMTQtNDQuNTcsMTIyLjg5LDMxLjI5LDMxLjYzLTI0LjUxLDU3LjktMjkuNzQsNzgtMjAuODdxNDMuMzksMzAuNyw5MC4zMiw1OUM0MzYuMjUsNDE4LjI3LDQxOC4yNSwzODYsMzk5LDM1NS4wOFpNMzUyLjExLDM2MmMtMTYuNjEtOS45LTI2LjE3LjI1LTM2Ljc5LDE0LDcuMzItMTUuMTEsMTEuMTItMzAuNzIsMi42OS00Mi4yOGwtMy43LTMuMTlMMjc3LDMwMS4xMWwtMzkuNjgsMjIsMTQuMjktMjEuMDZjNi4wOC0xMC4zMSwyLjg1LTIyLjU4LTQuNy0zNC4ycS0xMy42LTEzLjU2LTI2Ljc4LTI3LjQ2Yy0xLjM4LTEtMi43NS0yLTQuMTEtMi45MWwtNTUuMjMsMTUuNjgsMTguMDktMjEuNDFjOC43OC0xNC42NCwwLTM0LjU3LTguMTgtNDYuM3EtNy04LjE1LTEzLjgyLTE2LjQybC0zNi4zLDYuMDZjMTUuMzItNi4wNiwyNi4wOC0xOC42LDE0LTMzLjI4bC0xLjg5LTIuMTNjLjY5LjcyLDEuMzEsMS40MiwxLjg5LDIuMTNsMS43MSwxLjk0cS0yMC40My0yNS42NS0zOS44NC01Mi4wOSwzNS43NiwyNi44OCw2OS43MSw1NS43NWwzMC40NC03LjkzLTE4LjM4LDE4LjI3cTE5LjQ0LDE2Ljg4LDM4LjMxLDM0LjQxbDU5LjczLTI1LjMyTDI2MC42OCwxOTFsLjI1LS4yYy0xNy45MSwyMi45LDE1LjYsNzEuNTIsMzguMjQsNjUuMTlsMjYuNTItMTQuNzEtMjAuNiwzMC4zNywzMC42NSw0My44Mi42Ni43NGMxMS4zNCwxMC4zOSwyNiwxLjQyLDM1Ljc5LTEyLjA3TDM1NS45LDMzOXEyNi43MiwzMS43OCw1Mi4zLDY1LjI0UTM3OS4zMSwzODMuNzYsMzUyLjExLDM2MlpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzY2FyVGlzc3VlOiBcImZpbGwtbWVkXCJcbiAgICAgICAgfVxuICAgIH0sXG4gICAgW0NvbnNlcXVlbmNlVHlwZS5Qcm93ZXNzSGFybTNdOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIHNjYXI6IFwiTTQ0Ny40NCw0MzQuNTNRNDEyLjcsNDA5Ljg3LDM4MCwzODMuNjRjLTIwLTExLjkxLTMxLjQ5LjMtNDQuMjYsMTYuODYsOC44LTE4LjE3LDEzLjM4LTM2Ljk1LDMuMjQtNTAuODZsLTQuNDYtMy44NC00NC44NS0zNS4zNUwyNDEuOSwzMzYuOTNsMTcuMTktMjUuMzRjNy4zMS0xMi40LDMuNDMtMjcuMTctNS42NS00MS4xNHEtMTYuMzctMTYuMzItMzIuMjItMzNjLTEuNjYtMS4yMy0zLjMxLTIuMzgtNC45NS0zLjVsLTY2LjQ0LDE4Ljg3TDE3MS41OSwyMjdjMTAuNTctMTcuNjIsMC00MS41OS05Ljg0LTU1LjdxLTguNC05LjgxLTE2LjYyLTE5Ljc1bC00My42Nyw3LjI5YzE4LjQzLTcuMywzMS4zNy0yMi4zOCwxNi44NS00MGwyLjA2LDIuMzNROTUuNzksOTAuMjksNzIuNDQsNTguNDlxNDMsMzIuMzIsODMuODYsNjcuMDZMMTkyLjkyLDExNmwtMjIuMTEsMjJxMjMuMzgsMjAuMyw0Ni4wOSw0MS4zOWw3MS44Ni0zMC40NkwyNzAsMTc4bC4zLS4yNGMtMjEuNTUsMjcuNTQsMTguNzcsODYsNDYsNzguNDJsMzEuOTEtMTcuN0wzMjMuNCwyNzVsMzYuODgsNTIuNzFjLjI2LjMuNTMuNTkuNzkuOSwxMy42NCwxMi41LDMxLjIzLDEuNzEsNDMuMDUtMTQuNTNsLTE5LjU5LDQyUTQxNi42NiwzOTQuMjgsNDQ3LjQ0LDQzNC41M1pcIixcbiAgICAgICAgICAgIHNjYXJUaXNzdWU6IFwiTTQzNi4zMywzNzUuMzdjLTE4LjA3LTM4Ljg3LTIyLjQ2LTc5LjI0LTcuNDktMTEzLjkyLTU2Ljc3LDcwLjI3LTkxLjYsNS4zLTQuOTMtODUuMDhDMzAxLjYxLDI1MS44LDI0Ni4xMywyMTQuMjMsNDA3LDcwLjE5LDI4My4xOCwxMzYsMTg3LjUsMTUzLjQ2LDI0OS41Myw4OC40N2MtNDQuNzUsMTIuNzktNzAsNi4yNy05MS40Ny0yLjkzYTc3My43LDc3My43LDAsMCwwLTEzNS4xOC02Nyw5NDkuNTgsOTQ5LjU4LDAsMCwwLDU2LjQ5LDkzLjMxYzguMzksMjIsMy42LDQ2LjU3LTM3Ljg0LDc2LjMyQzE5MS43MiwxNDgsMTQ4LDI0NC43MSwzMC4yNiwzMTQuNDJjMjAwLTc0LjIsMjQ5LjY1LTU3LDEyMS4wOCw5My43OEMyNTIuNDIsMzM0LjczLDMzMiwzNTQuNTksMjk5LjE3LDQ0NS44NGMzOC4wNi0yOS40OCw2OS42Ni0zNS43Nyw5My44Ny0yNS4xcTUyLjIxLDM2Ljk0LDEwOC42Niw3MC45M0M0ODEuMTksNDUxLjM5LDQ1OS41NCw0MTIuNTIsNDM2LjMzLDM3NS4zN1pNMzgwLDM4My42NGMtMjAtMTEuOTEtMzEuNDkuMy00NC4yNiwxNi44Niw4LjgtMTguMTcsMTMuMzgtMzYuOTUsMy4yNC01MC44NmwtNC40Ni0zLjg0LTQ0Ljg1LTM1LjM1TDI0MS45LDMzNi45M2wxNy4xOS0yNS4zNGM3LjMxLTEyLjQsMy40My0yNy4xNy01LjY1LTQxLjE0cS0xNi4zNy0xNi4zMi0zMi4yMi0zM2MtMS42Ni0xLjIzLTMuMzEtMi4zOC00Ljk1LTMuNWwtNjYuNDQsMTguODdMMTcxLjU5LDIyN2MxMC41Ny0xNy42MiwwLTQxLjU5LTkuODQtNTUuN3EtOC40LTkuODEtMTYuNjItMTkuNzVsLTQzLjY3LDcuMjljMTguNDMtNy4zLDMxLjM3LTIyLjM4LDE2Ljg1LTQwTDExNiwxMTYuMjZjLjgzLjg2LDEuNTcsMS43MSwyLjI3LDIuNTZsMi4wNiwyLjMzUTk1Ljc5LDkwLjI5LDcyLjQ0LDU4LjQ5cTQzLDMyLjMyLDgzLjg2LDY3LjA2TDE5Mi45MiwxMTZsLTIyLjExLDIycTIzLjM4LDIwLjMsNDYuMDksNDEuMzlsNzEuODYtMzAuNDZMMjcwLDE3OGwuMy0uMjRjLTIxLjU1LDI3LjU0LDE4Ljc3LDg2LDQ2LDc4LjQybDMxLjkxLTE3LjdMMzIzLjQsMjc1bDM2Ljg4LDUyLjcxYy4yNi4zLjUzLjU5Ljc5LjksMTMuNjQsMTIuNSwzMS4yMywxLjcxLDQzLjA1LTE0LjUzbC0xOS41OSw0MnEzMi4xMywzOC4yMyw2Mi45MSw3OC40OVE0MTIuNyw0MDkuODcsMzgwLDM4My42NFpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzY2FyOiBcImZpbGwtZGFya1wiLFxuICAgICAgICAgICAgc2NhclRpc3N1ZTogXCJmaWxsLW1lZFwiXG4gICAgICAgIH1cbiAgICB9LFxuICAgIFtDb25zZXF1ZW5jZVR5cGUuUHJvd2Vzc0hhcm00XToge1xuICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgNTEyXCIsXG4gICAgICAgIHBhdGhzOiB7XG4gICAgICAgICAgICBzY2FyOiBcIk00NDEuNDQsNDM0LjUzUTQwNi43LDQwOS44NywzNzQsMzgzLjY0Yy0yMC0xMS45MS0zMS40OS4zLTQ0LjI2LDE2Ljg2LDguOC0xOC4xNywxMy4zOC0zNi45NSwzLjI0LTUwLjg2bC00LjQ2LTMuODQtNDQuODUtMzUuMzVMMjM1LjksMzM2LjkzbDE3LjE5LTI1LjM0YzcuMzEtMTIuNCwzLjQzLTI3LjE3LTUuNjUtNDEuMTRxLTE2LjM3LTE2LjMyLTMyLjIyLTMzYy0xLjY2LTEuMjMtMy4zMS0yLjM4LTQuOTUtMy41bC02Ni40NCwxOC44N0wxNjUuNTksMjI3YzEwLjU3LTE3LjYyLDAtNDEuNTktOS44NC01NS43cS04LjQtOS44MS0xNi42Mi0xOS43NWwtNDMuNjcsNy4yOWMxOC40My03LjMsMzEuMzctMjIuMzgsMTYuODUtNDBsMi4wNiwyLjMzUTg5Ljc5LDkwLjI5LDY2LjQ0LDU4LjQ5cTQzLDMyLjMyLDgzLjg2LDY3LjA2TDE4Ni45MiwxMTZsLTIyLjExLDIycTIzLjM4LDIwLjMsNDYuMDksNDEuMzlsNzEuODYtMzAuNDZMMjY0LDE3OGwuMy0uMjRjLTIxLjU1LDI3LjU0LDE4Ljc3LDg2LDQ2LDc4LjQybDMxLjkxLTE3LjdMMzE3LjQsMjc1bDM2Ljg4LDUyLjcxYy4yNi4zLjUzLjU5Ljc5LjksMTMuNjQsMTIuNSwzMS4yMywxLjcxLDQzLjA1LTE0LjUzbC0xOS41OSw0MlE0MTAuNjYsMzk0LjI4LDQ0MS40NCw0MzQuNTNaXCIsXG4gICAgICAgICAgICBzY2FyVGlzc3VlOiBcIk00MzAuMzMsMzc1LjM3Yy0xOC4wNy0zOC44Ny0yMi40Ni03OS4yNC03LjQ5LTExMy45Mi01Ni43Nyw3MC4yNy05MS42LDUuMy00LjkzLTg1LjA4QzI5NS42MSwyNTEuOCwyNDAuMTMsMjE0LjIzLDQwMSw3MC4xOSwyNzcuMTgsMTM2LDE4MS41LDE1My40NiwyNDMuNTMsODguNDdjLTQ0Ljc1LDEyLjc5LTcwLDYuMjctOTEuNDctMi45M2E3NzMuNyw3NzMuNywwLDAsMC0xMzUuMTgtNjcsOTQ5LjU4LDk0OS41OCwwLDAsMCw1Ni40OSw5My4zMWM4LjM5LDIyLDMuNiw0Ni41Ny0zNy44NCw3Ni4zMkMxODUuNzIsMTQ4LDE0MiwyNDQuNzEsMjQuMjYsMzE0LjQyYzIwMC03NC4yLDI0OS42NS01NywxMjEuMDgsOTMuNzhDMjQ2LjQyLDMzNC43MywzMjYsMzU0LjU5LDI5My4xNyw0NDUuODRjMzguMDYtMjkuNDgsNjkuNjYtMzUuNzcsOTMuODctMjUuMXE1Mi4yMSwzNi45NCwxMDguNjYsNzAuOTNDNDc1LjE5LDQ1MS4zOSw0NTMuNTQsNDEyLjUyLDQzMC4zMywzNzUuMzdaTTM3NCwzODMuNjRjLTIwLTExLjkxLTMxLjQ5LjMtNDQuMjYsMTYuODYsOC44LTE4LjE3LDEzLjM4LTM2Ljk1LDMuMjQtNTAuODZsLTQuNDYtMy44NC00NC44NS0zNS4zNUwyMzUuOSwzMzYuOTNsMTcuMTktMjUuMzRjNy4zMS0xMi40LDMuNDMtMjcuMTctNS42NS00MS4xNHEtMTYuMzctMTYuMzItMzIuMjItMzNjLTEuNjYtMS4yMy0zLjMxLTIuMzgtNC45NS0zLjVsLTY2LjQ0LDE4Ljg3TDE2NS41OSwyMjdjMTAuNTctMTcuNjIsMC00MS41OS05Ljg0LTU1LjdxLTguNC05LjgxLTE2LjYyLTE5Ljc1bC00My42Nyw3LjI5YzE4LjQzLTcuMywzMS4zNy0yMi4zOCwxNi44NS00MEwxMTAsMTE2LjI2Yy44My44NiwxLjU3LDEuNzEsMi4yNywyLjU2bDIuMDYsMi4zM1E4OS43OSw5MC4yOSw2Ni40NCw1OC40OXE0MywzMi4zMiw4My44Niw2Ny4wNkwxODYuOTIsMTE2bC0yMi4xMSwyMnEyMy4zOCwyMC4zLDQ2LjA5LDQxLjM5bDcxLjg2LTMwLjQ2TDI2NCwxNzhsLjMtLjI0Yy0yMS41NSwyNy41NCwxOC43Nyw4Niw0Niw3OC40MmwzMS45MS0xNy43TDMxNy40LDI3NWwzNi44OCw1Mi43MWMuMjYuMy41My41OS43OS45LDEzLjY0LDEyLjUsMzEuMjMsMS43MSw0My4wNS0xNC41M2wtMTkuNTksNDJxMzIuMTMsMzguMjMsNjIuOTEsNzguNDlRNDA2LjcsNDA5Ljg3LDM3NCwzODMuNjRaXCIsXG4gICAgICAgICAgICB3ZWx0czogXCJNNDE0LjEzLDg0LjE5YTM5LjUsMzkuNSwwLDEsMCwzOS41NywzOS41LDM5LjIsMzkuMiwwLDAsMC0zOS41Ny0zOS41Wk0zMDguMzMsMjkuODNBMjguNjYsMjguNjYsMCwxLDAsMzM3LDU4LjUxYTI4LjUxLDI4LjUxLDAsMCwwLTI4LjY3LTI4LjY4Wk05MC4xNywzMjIuNTZhNDkuNTEsNDkuNTEsMCwxLDAsNDkuNTMsNDkuNTJBNDkuMzYsNDkuMzYsMCwwLDAsOTAuMTcsMzIyLjU2Wm0yNTgtMTcxLjI0QTIyLjc5LDIyLjc5LDAsMSwwLDM3MSwxNzQuMTFhMjIuNjEsMjIuNjEsMCwwLDAtMjIuODMtMjIuNzlaTTI2MS40OSw4OS44OGExNi43MiwxNi43MiwwLDEsMCwxNi43MywxNi43MywxNi42MywxNi42MywwLDAsMC0xNi43My0xNi43M1pNOTEuMTUsMTg3LjY1YTIxLjE4LDIxLjE4LDAsMSwwLDIxLjE4LDIxLjE4LDIxLDIxLDAsMCwwLTIxLjE4LTIxLjE4Wm03Ny41MSw5NC41NGEzMi4wOSwzMi4wOSwwLDEsMCwzMi4wNywzMi4xLDMyLDMyLDAsMCwwLTMyLjA3LTMyLjFaTTM5MS42LDI0My4wNWExNi41MSwxNi41MSwwLDEsMCwxNi40OSwxNi41MiwxNi40MSwxNi40MSwwLDAsMC0xNi40OS0xNi41MlpNMjM4LjExLDM3NC44NWE0OC40Myw0OC40MywwLDEsMCw0OC40NCw0OC40NUE0OC4yOSw0OC4yOSwwLDAsMCwyMzguMTEsMzc0Ljg1Wm0xMzcsNTkuODhBMjIuODYsMjIuODYsMCwxLDAsMzk4LDQ1Ny41OWEyMi42OSwyMi42OSwwLDAsMC0yMi44Ni0yMi44NlpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzY2FyOiBcImZpbGwtYnJpZ2h0XCIsXG4gICAgICAgICAgICBzY2FyVGlzc3VlOiBcImZpbGwtZGFya1wiLFxuICAgICAgICAgICAgd2VsdHM6IFwiZmlsbC1icmlnaHRcIlxuICAgICAgICB9XG4gICAgfSxcbiAgICBbQ29uc2VxdWVuY2VUeXBlLlJlc29sdmVIYXJtMV06IHtcbiAgICAgICAgdmlld0JveDogXCIwIDAgNTEyIDUxMlwiLFxuICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgc3Bpa2VzOiBcIk0yNTYuMDksMTkuMUEyMzcuNSwyMzcuNSwwLDAsMCwxOTcsMjcuMjJDNzAuNjMsNjEuMDgtNC4zNiwxOTEsMjkuNSwzMTcuMzEsNjIuNTksNDQwLjgsMTg3LjM5LDUxNS4yMSwzMTEsNDg2LjkyQTEzMi4zNSwxMzIuMzUsMCwwLDEsMjc5Ljc0LDQ3NSwyMDcsMjA3LDAsMCwxLDEyMiw0MTcuNDlsLTEzLjQ4LTE0LjU1TDk0Ljg5LDM4NS40MmEyMDUuNjIsMjA1LjYyLDAsMCwxLTI0LTQ3LjM2bC03LjItMTcuMzNMNjAuNzEsMjk2LjVhMjA1LjgzLDIwNS44MywwLDAsMS0uMTgtNTQuMzdsMy0yNC4zNiw3LjY3LTE5LjUxYTIwOC4yOCwyMDguMjgsMCwwLDEsMjkuMTYtNTMuODRsMTA1LDYwLjYxLTY4LjYzLTk4YTIwNS44NSwyMDUuODUsMCwwLDEsNjMuNjgtMzQuNDlsMjcuMjQtOC4xOCwyMy4xOC0xLjg5cTYuNDYtLjQ4LDEyLjg5LS41NGEyMDUuNTQsMjA1LjU0LDAsMCwxLDYxLjY2LDguODRsMjMuNjUsMTEsMjIsOS4wOUEyMDcuMDUsMjA3LjA1LDAsMCwxLDQyOC4yLDE0MC45bDEzLjEsMTQuNDRMNDQ4LjkzLDE3M2EyMDgsMjA4LDAsMCwxLDE2LjQxLDQyLjIyLDIwNS44OSwyMDUuODksMCwwLDEsMi41Miw5Ni43MywxMzMsMTMzLDAsMCwxLDcuNzQsMzguMzEsMjM1LjgsMjM1LjgsMCwwLDAsMTEuNDgtMTU1LjUzQzQ1OC41MSw4OC4wOSwzNjEuNTksMTguMDUsMjU2LjA5LDE5LjFaXCIsXG4gICAgICAgICAgICBleWViYWxsOiBcIk0zNDQuNTgsMjQyLjUzYTQ1LjYxLDQ1LjYxLDAsMCwxLDguOTUsNi45NWMxMi4yMiwxMi4yMSwxNi4wNywyOS45LDEzLjI2LDQ3LjM1UzM1NC43NCwzMzIsMzQwLDM0Ni44MnMtMzIuNTQsMjQtNTAsMjYuODMtMzUuMTMtMS00Ny4zNS0xMy4yNmE0OCw0OCwwLDAsMS0xMy0yNC43NCwxMTQuNzQsMTE0Ljc0LDAsMSwwLDExNC45Mi05My4xMlpcIixcbiAgICAgICAgICAgIGlyaXM6IFwiTTMxNi4yNCwyNTRhNTAuNTYsNTAuNTYsMCwwLDAtNy4wOC42NmMtMTMsMi4wOS0yNy41Niw5LjM5LTM5Ljc2LDIxLjU5UzI0OS45MSwzMDMsMjQ3LjgxLDMxNnMuNzUsMjMuODksOCwzMS4xNlMyNzQsMzU3LjMsMjg3LDM1NS4yczI3LjU2LTkuMzksMzkuNzYtMjEuNTksMTkuNS0yNi43NiwyMS41OS0zOS43Ni0uNzUtMjMuODktOC0zMS4xNmMtNS40NS01LjQ1LTEyLjk0LTguNDItMjEuODMtOC42OC0uNzQsMC0xLjQ5LDAtMi4yNSwwWm0tMTMuODEsMjAuMzVhMTYsMTYsMCwwLDEsMTEuODYsNC4zOGM3LjQ5LDcuNSw1LjE2LDIyLTUuMjIsMzIuMzdzLTI0Ljg4LDEyLjcyLTMyLjM4LDUuMjMtNS4xNi0yMiw1LjIyLTMyLjM4YzYuMTctNi4xNiwxMy43OC05LjQ5LDIwLjUyLTkuNlpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzcGlrZXM6IFwiZmlsbC1kYXJrXCIsXG4gICAgICAgICAgICBleWViYWxsOiBcImZpbGwtZGFya1wiLFxuICAgICAgICAgICAgaXJpczogXCJmaWxsLW1lZFwiXG4gICAgICAgIH1cbiAgICB9LFxuICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm0yXToge1xuICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgNTEyXCIsXG4gICAgICAgIHBhdGhzOiB7XG4gICAgICAgICAgICBzcGlrZXM6IFwiTTI2MS4yNSwxOS4xYTIzNy42NCwyMzcuNjQsMCwwLDAtNTkuMTEsOC4xMkM3NS43OSw2MS4wOC44LDE5MSwzNC42NiwzMTcuMzEsNjcuNzUsNDQwLjgsMTkyLjU1LDUxNS4yMSwzMTYuMTUsNDg2LjkyQTEzMi41OSwxMzIuNTksMCwwLDEsMjg0Ljg5LDQ3NWEyMDcsMjA3LDAsMCwxLTE1Ny43Mi01Ny41MmwtMTEuNDQtMTIuMTUtMTUuNjgtMTkuOTJhMjA1LjYyLDIwNS42MiwwLDAsMS0yNC00Ny4zNmwtNy4zMi0xNy4zM0w2NS44NywyOTYuNWEyMDUuNDEsMjA1LjQxLDAsMCwxLS4xOC01NC4zN2w5MS44NCwxOS4zMkw3Ni4zOCwxOTguMjZhMjA4LDIwOCwwLDAsMSwyOS4xNi01My44NEwyNTkuOTMsMjUyLjc4LDE0MS44NywxMDdhMjA1Ljc5LDIwNS43OSwwLDAsMSw2My42Ny0zNC40OUwyNjMuNDUsMTQxLDI1Niw2Mi40NXE2LjQ2LS40OCwxMi44OS0uNTRhMjA1LjU0LDIwNS41NCwwLDAsMSw2MS42Niw4Ljg0bDIyLjg0LDguMzIsMjIuODMsMTEuNzhhMjA3LDIwNywwLDAsMSw1Ny4xNyw1MC4wNWwxMy40MSwxNi44NUw0NTQuMDgsMTczYTIwNy41MiwyMDcuNTIsMCwwLDEsMTguOTMsMTM5LDEzMi42NywxMzIuNjcsMCwwLDEsNy43NSwzOC4zMSwyMzUuOTIsMjM1LjkyLDAsMCwwLDExLjQ4LTE1NS41M0M0NjMuNjcsODguMDksMzY2Ljc0LDE4LjA1LDI2MS4yNSwxOS4xWlwiLFxuICAgICAgICAgICAgZXllYmFsbDogXCJNMzQ5Ljc0LDI0Mi41M2E0NS42MSw0NS42MSwwLDAsMSw4Ljk1LDYuOTVjMTIuMjEsMTIuMjEsMTYuMDcsMjkuOSwxMy4yNiw0Ny4zNXMtMTIuMDUsMzUuMjEtMjYuODMsNTAtMzIuNTQsMjQtNTAsMjYuODMtMzUuMTQtMS00Ny4zNS0xMy4yNmE0OCw0OCwwLDAsMS0xMy0yNC43NCwxMTYuMTksMTE2LjE5LDAsMCwwLTIsMjEuNTgsMTE0LjczLDExNC43MywwLDEsMCwxMTctMTE0LjdaXCIsXG4gICAgICAgICAgICBpcmlzOiBcIk0zMjEuNCwyNTRhNTAuNDIsNTAuNDIsMCwwLDAtNy4wOC42NmMtMTMsMi4wOS0yNy41Niw5LjM5LTM5Ljc2LDIxLjU5UzI1NS4wNiwzMDMsMjUzLDMxNnMuNzUsMjMuODksOCwzMS4xNiwxOC4xNiwxMC4xMiwzMS4xNiw4LDI3LjU2LTkuMzksMzkuNzYtMjEuNTksMTkuNDktMjYuNzYsMjEuNTktMzkuNzYtLjc1LTIzLjg5LTgtMzEuMTZjLTUuNDYtNS40NS0xMy04LjQyLTIxLjgzLTguNjgtLjc0LDAtMS40OSwwLTIuMjUsMFptLTEzLjgxLDIwLjM1YTE2LDE2LDAsMCwxLDExLjg1LDQuMzhjNy41LDcuNSw1LjE2LDIyLTUuMjIsMzIuMzdzLTI0Ljg3LDEyLjcyLTMyLjM3LDUuMjMtNS4xNi0yMiw1LjIyLTMyLjM4YzYuMTYtNi4xNiwxMy43OC05LjQ5LDIwLjUyLTkuNlpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzcGlrZXM6IFwiZmlsbC1tZWRcIixcbiAgICAgICAgICAgIGV5ZWJhbGw6IFwiZmlsbC1kYXJrXCIsXG4gICAgICAgICAgICBpcmlzOiBcImZpbGwtYnJpZ2h0XCJcbiAgICAgICAgfVxuICAgIH0sXG4gICAgW0NvbnNlcXVlbmNlVHlwZS5SZXNvbHZlSGFybTNdOiB7XG4gICAgICAgIHZpZXdCb3g6IFwiMCAwIDUxMiA1MTJcIixcbiAgICAgICAgcGF0aHM6IHtcbiAgICAgICAgICAgIHNwaWtlczogXCJNMjYxLjMxLDE5LjFhMjM3LjUxLDIzNy41MSwwLDAsMC01OS4xMSw4LjEyQzc1Ljg0LDYxLjA4Ljg2LDE5MSwzNC43MSwzMTcuMzEsNjcuOCw0NDAuOCwxOTIuNjEsNTE1LjIxLDMxNi4yLDQ4Ni45MkExMzIuMzUsMTMyLjM1LDAsMCwxLDI4NSw0NzVhMjA3LDIwNywwLDAsMS0xNTcuNzItNTcuNTJsLTEzLjgxLTE2LjM3LTEzLjMxLTE1LjdhMjA2LDIwNiwwLDAsMS0yNC4wNi00Ny4zNmw4My42My0xNy4zM0w2NS45MywyOTYuNWEyMDUuNDEsMjA1LjQxLDAsMCwxLS4xOC01NC4zN2wxNjQuNjYsNDcuMjEtMTU0LTkxLjA4YTIwOCwyMDgsMCwwLDEsMjkuMTUtNTMuODRMMjYwLDI1Mi43OCwxNDEuOTIsMTA3QTIwNS44NSwyMDUuODUsMCwwLDEsMjA1LjYsNzIuNTJsOTUuNDksMTU4LjIxTDI1Niw2Mi40NXE2LjQ3LS40OCwxMi45LS41NGEyMDUuNDMsMjA1LjQzLDAsMCwxLDYxLjY1LDguODRMMzUzLjA4LDE2OWwyMy4xNy03OC4xNGEyMDYuNzYsMjA2Ljc2LDAsMCwxLDU3LjE2LDUwLjA1bDEzLjA4LDIyLjQxLDcuNjUsOS42N2EyMDcuNTIsMjA3LjUyLDAsMCwxLDE4LjkzLDEzOSwxMzIuMzMsMTMyLjMzLDAsMCwxLDcuNzQsMzguMzEsMjM1LjgsMjM1LjgsMCwwLDAsMTEuNDgtMTU1LjUzQzQ2My43Myw4OC4wOSwzNjYuOCwxOC4wNSwyNjEuMzEsMTkuMVpcIixcbiAgICAgICAgICAgIGV5ZWJhbGw6IFwiTTM0OS43OSwyNDIuNTNhNDUuMzgsNDUuMzgsMCwwLDEsOSw2Ljk1YzEyLjIxLDEyLjIxLDE2LjA3LDI5LjksMTMuMjUsNDcuMzVzLTEyLDM1LjIxLTI2LjgyLDUwLTMyLjU0LDI0LTUwLDI2LjgzLTM1LjEzLTEtNDcuMzQtMTMuMjZhNDgsNDgsMCwwLDEtMTMtMjQuNzQsMTE2LjE5LDExNi4xOSwwLDAsMC0yLDIxLjU4LDExNC43MywxMTQuNzMsMCwxLDAsMTE3LTExNC43WlwiLFxuICAgICAgICAgICAgaXJpczogXCJNMzIxLjQ1LDI1NGE1MC41Niw1MC41NiwwLDAsMC03LjA4LjY2Yy0xMywyLjA5LTI3LjU1LDkuMzktMzkuNzUsMjEuNTlTMjU1LjEyLDMwMywyNTMsMzE2cy43NSwyMy44OSw4LDMxLjE2LDE4LjE2LDEwLjEyLDMxLjE2LDgsMjcuNTYtOS4zOSwzOS43Ni0yMS41OSwxOS40OS0yNi43NiwyMS41OS0zOS43Ni0uNzUtMjMuODktOC0zMS4xNmMtNS40NS01LjQ1LTEyLjk0LTguNDItMjEuODMtOC42OC0uNzQsMC0xLjQ5LDAtMi4yNSwwWm0tMTMuODEsMjAuMzVhMTYsMTYsMCwwLDEsMTEuODYsNC4zOGM3LjUsNy41LDUuMTYsMjItNS4yMiwzMi4zN3MtMjQuODgsMTIuNzItMzIuMzcsNS4yMy01LjE2LTIyLDUuMjItMzIuMzhjNi4xNi02LjE2LDEzLjc4LTkuNDksMjAuNTEtOS42WlwiXG4gICAgICAgIH0sXG4gICAgICAgIGNsYXNzZXM6IHtcbiAgICAgICAgICAgIHNwaWtlczogXCJmaWxsLWJyaWdodFwiLFxuICAgICAgICAgICAgZXllYmFsbDogXCJmaWxsLW1lZFwiLFxuICAgICAgICAgICAgaXJpczogXCJmaWxsLWJyaWdodFwiXG4gICAgICAgIH1cbiAgICB9LFxuICAgIFtDb25zZXF1ZW5jZVR5cGUuUmVzb2x2ZUhhcm00XToge1xuICAgICAgICB2aWV3Qm94OiBcIjAgMCA1MTIgNTEyXCIsXG4gICAgICAgIHBhdGhzOiB7XG4gICAgICAgICAgICBzcGlrZXM6IFwiTTI2MS4xNCwxOS4xQTIzNy41MSwyMzcuNTEsMCwwLDAsMjAyLDI3LjIyQzc1LjY3LDYxLjA4LjY5LDE5MSwzNC41NCwzMTcuMzEsNjcuNjMsNDQwLjgsMTkyLjQ0LDUxNS4yMSwzMTYsNDg2LjkyQTEzMi4zNSwxMzIuMzUsMCwwLDEsMjg0Ljc4LDQ3NWEyMDcsMjA3LDAsMCwxLTE1Ny43Mi01Ny41Mmw4OS4yMi0zMC0xMTYuMzQtMmEyMDYsMjA2LDAsMCwxLTI0LjA2LTQ3LjM2TDIxNCwzMzMuMjEsNjUuNzYsMjk2LjVhMjA1LjQxLDIwNS40MSwwLDAsMS0uMTgtNTQuMzdsMTY0LjY2LDQ3LjIxLTE1NC05MS4wOGEyMDgsMjA4LDAsMCwxLDI5LjE1LTUzLjg0bDE1NC40LDEwOC4zNkwxNDEuNzUsMTA3YTIwNS44NSwyMDUuODUsMCwwLDEsNjMuNjgtMzQuNDlsOTUuNDksMTU4LjIxTDI1NS44NSw2Mi40NXE2LjQ3LS40OCwxMi45LS41NGEyMDUuNDMsMjA1LjQzLDAsMCwxLDYxLjY1LDguODRMMzU5Ljc3LDIyMy41LDM3Ni4wOCw5MC44NWEyMDYuNzYsMjA2Ljc2LDAsMCwxLDU3LjE2LDUwLjA1TDQxNS42MSwyNDMuMTMsNDU0LDE3M2EyMDcuNTIsMjA3LjUyLDAsMCwxLDE4LjkzLDEzOSwxMzIuMzMsMTMyLjMzLDAsMCwxLDcuNzQsMzguMzEsMjM1LjgsMjM1LjgsMCwwLDAsMTEuNDgtMTU1LjUzQzQ2My41NSw4OC4wOSwzNjYuNjMsMTguMDUsMjYxLjE0LDE5LjFaXCIsXG4gICAgICAgICAgICBleWViYWxsOiBcIk0zNDkuNjIsMjQyLjUzYTQ1LjM4LDQ1LjM4LDAsMCwxLDksNi45NWMxMi4yMSwxMi4yMSwxNi4wNywyOS45LDEzLjI1LDQ3LjM1cy0xMiwzNS4yMS0yNi44Miw1MC0zMi41NSwyNC01MCwyNi44My0zNS4xMy0xLTQ3LjM0LTEzLjI2YTQ4LDQ4LDAsMCwxLTEzLTI0Ljc0LDExNi4xOSwxMTYuMTksMCwwLDAtMiwyMS41OCwxMTQuNzMsMTE0LjczLDAsMSwwLDExNy0xMTQuN1pcIixcbiAgICAgICAgICAgIGlyaXM6IFwiTTMyMS4yOCwyNTRhNTAuNTYsNTAuNTYsMCwwLDAtNy4wOC42NmMtMTMsMi4wOS0yNy41NSw5LjM5LTM5Ljc1LDIxLjU5UzI1NSwzMDMsMjUyLjg2LDMxNnMuNzUsMjMuODksOCwzMS4xNlMyNzksMzU3LjMsMjkyLDM1NS4yczI3LjU1LTkuMzksMzkuNzYtMjEuNTksMTkuNDktMjYuNzYsMjEuNTktMzkuNzYtLjc1LTIzLjg5LTgtMzEuMTZjLTUuNDUtNS40NS0xMi45NC04LjQyLTIxLjgzLTguNjgtLjc0LDAtMS40OSwwLTIuMjUsMFptLTEzLjgxLDIwLjM1YTE2LDE2LDAsMCwxLDExLjg2LDQuMzhjNy41LDcuNSw1LjE2LDIyLTUuMjIsMzIuMzdzLTI0Ljg4LDEyLjcyLTMyLjM3LDUuMjMtNS4xNi0yMiw1LjIyLTMyLjM4YzYuMTYtNi4xNiwxMy43OC05LjQ5LDIwLjUxLTkuNlpcIlxuICAgICAgICB9LFxuICAgICAgICBjbGFzc2VzOiB7XG4gICAgICAgICAgICBzcGlrZXM6IFwiZmlsbC1icmlnaHRcIixcbiAgICAgICAgICAgIGV5ZWJhbGw6IFwiZmlsbC1icmlnaHRcIixcbiAgICAgICAgICAgIGlyaXM6IFwiZmlsbC1icmlnaHRcIlxuICAgICAgICB9XG4gICAgfVxufTtcbi8vICNlbmRyZWdpb25cbmV4cG9ydCBkZWZhdWx0IEM7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/core/constants.ts\n"); + +/***/ }), + +/***/ "./ts/core/debug.ts": +/*!**************************!*\ + !*** ./ts/core/debug.ts ***! + \**************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~\n\n\n\nclass BladesDebug {\n static async GetSampleSchemas(docNames = {}) {\n // Documents\n const SAMPLE_USER_NAME = docNames.user || \"Alistair\";\n const SAMPLE_PC_NAME = docNames.pc || \"Alistair\";\n const SAMPLE_NPC_NAME = docNames.npc || \"Setarra\";\n const SAMPLE_FACTION_NAME = docNames.faction || \"the Bluecoats\";\n const sampleUser = game.users.getName(SAMPLE_USER_NAME);\n if (!sampleUser) {\n throw new Error(`Sample user with name \"${SAMPLE_USER_NAME}\" not found.`);\n }\n const samplePC = game.actors.getName(SAMPLE_PC_NAME);\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesPC.IsType(samplePC)) {\n throw new Error(`Sample BladesPC with name \"${SAMPLE_PC_NAME}\" not found.`);\n }\n const sampleNPC = game.actors.getName(SAMPLE_NPC_NAME);\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesNPC.IsType(sampleNPC)) {\n throw new Error(`Sample BladesNPC with name \"${SAMPLE_NPC_NAME}\" not found or is not a valid BladesNPC.`);\n }\n const sampleFaction = game.actors.getName(SAMPLE_FACTION_NAME);\n if (!_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesFaction.IsType(sampleFaction)) {\n throw new Error(`Sample BladesFaction with name \"${SAMPLE_FACTION_NAME}\" not found or is not a valid BladesFaction.`);\n }\n // BladesActionRoll\n const BladesActionRoll_Schema = {\n rollType: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollType.Action,\n // rollSubType: RollSubType.GatherInfo,\n // rollPrompt: \"Gathering Information\",\n rollTrait: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ActionTrait.skirmish,\n // rollUserID: sampleUser.id,\n // rollDowntimeAction: DowntimeAction.AcquireAsset,\n // rollClockKey: U.getLast(game.eunoblades.ClockKeys.contents)?.id,\n rollPrimaryData: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_2__.BladesRollPrimary.GetDataFromDoc(samplePC),\n rollOppData: _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_2__.BladesRollOpposition.GetDataFromDoc(sampleFaction),\n // rollParticipantData: {},\n // consequenceData: {},\n // resistanceData: {\n // consequence: {}\n // },\n rollModsData: {},\n rollPositionInitial: _core_constants__WEBPACK_IMPORTED_MODULE_0__.Position.risky,\n rollEffectInitial: _core_constants__WEBPACK_IMPORTED_MODULE_0__.Effect.standard,\n rollPosEffectTrade: false,\n rollPhase: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollPhase.Collaboration,\n GMBoosts: {},\n GMOppBoosts: {},\n GMOverrides: {},\n rollFactorToggles: {\n source: {},\n opposition: {}\n },\n userPermissions: {\n [sampleUser.id]: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollPermissions.Primary\n }\n // rollPositionFinal: Position.risky,\n // rollEffectFinal: Effect.standard,\n // rollResult: RollResult.success,\n // rollResultDelta: 0,\n // rollResultFinal: RollResult.success,\n // rollTraitVerb: \"skirmishes\",\n // rollTraitPastVerb: \"skirmished\",\n // finalDiceData: [],\n // isInlineResistanceRoll: false\n };\n return {\n BladesActionRoll_Schema\n };\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesDebug);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jb3JlL2RlYnVnLnRzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ3dHO0FBQ3JCO0FBQ0g7QUFDaEY7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzREFBc0QsaUJBQWlCO0FBQ3ZFO0FBQ0E7QUFDQSxhQUFhLGlFQUFRO0FBQ3JCLDBEQUEwRCxlQUFlO0FBQ3pFO0FBQ0E7QUFDQSxhQUFhLGtFQUFTO0FBQ3RCLDJEQUEyRCxnQkFBZ0I7QUFDM0U7QUFDQTtBQUNBLGFBQWEsc0VBQWE7QUFDMUIsK0RBQStELG9CQUFvQjtBQUNuRjtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IscURBQVE7QUFDOUI7QUFDQTtBQUNBLHVCQUF1Qix3REFBVztBQUNsQztBQUNBO0FBQ0E7QUFDQSw2QkFBNkIsa0VBQWlCO0FBQzlDLHlCQUF5QixxRUFBb0I7QUFDN0Msc0NBQXNDO0FBQ3RDLGtDQUFrQztBQUNsQztBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCLDRCQUE0QjtBQUM1QixpQ0FBaUMscURBQVE7QUFDekMsK0JBQStCLG1EQUFNO0FBQ3JDO0FBQ0EsdUJBQXVCLHNEQUFTO0FBQ2hDLHdCQUF3QjtBQUN4QiwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0EsYUFBYTtBQUNiO0FBQ0EsaUNBQWlDLDREQUFlO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0RBQWUsV0FBVyxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvY29yZS9kZWJ1Zy50cz85OTk3Il0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuLy8gI3JlZ2lvbiDilq7ilq7ilq7ilq7ilq7ilq7ilq4gSU1QT1JUUyDilq7ilq7ilq7ilq7ilq7ilq7ilq4gflxuaW1wb3J0IHsgUm9sbFBlcm1pc3Npb25zLCBBY3Rpb25UcmFpdCwgUm9sbFBoYXNlLCBFZmZlY3QsIFJvbGxUeXBlLCBQb3NpdGlvbiB9IGZyb20gXCIuLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IHsgQmxhZGVzUEMsIEJsYWRlc05QQywgQmxhZGVzRmFjdGlvbiB9IGZyb20gXCIuLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuaW1wb3J0IHsgQmxhZGVzUm9sbFByaW1hcnksIEJsYWRlc1JvbGxPcHBvc2l0aW9uIH0gZnJvbSBcIi4uL2NsYXNzZXMvQmxhZGVzUm9sbFwiO1xuY2xhc3MgQmxhZGVzRGVidWcge1xuICAgIHN0YXRpYyBhc3luYyBHZXRTYW1wbGVTY2hlbWFzKGRvY05hbWVzID0ge30pIHtcbiAgICAgICAgLy8gRG9jdW1lbnRzXG4gICAgICAgIGNvbnN0IFNBTVBMRV9VU0VSX05BTUUgPSBkb2NOYW1lcy51c2VyIHx8IFwiQWxpc3RhaXJcIjtcbiAgICAgICAgY29uc3QgU0FNUExFX1BDX05BTUUgPSBkb2NOYW1lcy5wYyB8fCBcIkFsaXN0YWlyXCI7XG4gICAgICAgIGNvbnN0IFNBTVBMRV9OUENfTkFNRSA9IGRvY05hbWVzLm5wYyB8fCBcIlNldGFycmFcIjtcbiAgICAgICAgY29uc3QgU0FNUExFX0ZBQ1RJT05fTkFNRSA9IGRvY05hbWVzLmZhY3Rpb24gfHwgXCJ0aGUgQmx1ZWNvYXRzXCI7XG4gICAgICAgIGNvbnN0IHNhbXBsZVVzZXIgPSBnYW1lLnVzZXJzLmdldE5hbWUoU0FNUExFX1VTRVJfTkFNRSk7XG4gICAgICAgIGlmICghc2FtcGxlVXNlcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTYW1wbGUgdXNlciB3aXRoIG5hbWUgXCIke1NBTVBMRV9VU0VSX05BTUV9XCIgbm90IGZvdW5kLmApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHNhbXBsZVBDID0gZ2FtZS5hY3RvcnMuZ2V0TmFtZShTQU1QTEVfUENfTkFNRSk7XG4gICAgICAgIGlmICghQmxhZGVzUEMuSXNUeXBlKHNhbXBsZVBDKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTYW1wbGUgQmxhZGVzUEMgd2l0aCBuYW1lIFwiJHtTQU1QTEVfUENfTkFNRX1cIiBub3QgZm91bmQuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc2FtcGxlTlBDID0gZ2FtZS5hY3RvcnMuZ2V0TmFtZShTQU1QTEVfTlBDX05BTUUpO1xuICAgICAgICBpZiAoIUJsYWRlc05QQy5Jc1R5cGUoc2FtcGxlTlBDKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBTYW1wbGUgQmxhZGVzTlBDIHdpdGggbmFtZSBcIiR7U0FNUExFX05QQ19OQU1FfVwiIG5vdCBmb3VuZCBvciBpcyBub3QgYSB2YWxpZCBCbGFkZXNOUEMuYCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc2FtcGxlRmFjdGlvbiA9IGdhbWUuYWN0b3JzLmdldE5hbWUoU0FNUExFX0ZBQ1RJT05fTkFNRSk7XG4gICAgICAgIGlmICghQmxhZGVzRmFjdGlvbi5Jc1R5cGUoc2FtcGxlRmFjdGlvbikpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgU2FtcGxlIEJsYWRlc0ZhY3Rpb24gd2l0aCBuYW1lIFwiJHtTQU1QTEVfRkFDVElPTl9OQU1FfVwiIG5vdCBmb3VuZCBvciBpcyBub3QgYSB2YWxpZCBCbGFkZXNGYWN0aW9uLmApO1xuICAgICAgICB9XG4gICAgICAgIC8vIEJsYWRlc0FjdGlvblJvbGxcbiAgICAgICAgY29uc3QgQmxhZGVzQWN0aW9uUm9sbF9TY2hlbWEgPSB7XG4gICAgICAgICAgICByb2xsVHlwZTogUm9sbFR5cGUuQWN0aW9uLFxuICAgICAgICAgICAgLy8gcm9sbFN1YlR5cGU6IFJvbGxTdWJUeXBlLkdhdGhlckluZm8sXG4gICAgICAgICAgICAvLyByb2xsUHJvbXB0OiBcIkdhdGhlcmluZyBJbmZvcm1hdGlvblwiLFxuICAgICAgICAgICAgcm9sbFRyYWl0OiBBY3Rpb25UcmFpdC5za2lybWlzaCxcbiAgICAgICAgICAgIC8vIHJvbGxVc2VySUQ6IHNhbXBsZVVzZXIuaWQsXG4gICAgICAgICAgICAvLyByb2xsRG93bnRpbWVBY3Rpb246IERvd250aW1lQWN0aW9uLkFjcXVpcmVBc3NldCxcbiAgICAgICAgICAgIC8vIHJvbGxDbG9ja0tleTogVS5nZXRMYXN0KGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuY29udGVudHMpPy5pZCxcbiAgICAgICAgICAgIHJvbGxQcmltYXJ5RGF0YTogQmxhZGVzUm9sbFByaW1hcnkuR2V0RGF0YUZyb21Eb2Moc2FtcGxlUEMpLFxuICAgICAgICAgICAgcm9sbE9wcERhdGE6IEJsYWRlc1JvbGxPcHBvc2l0aW9uLkdldERhdGFGcm9tRG9jKHNhbXBsZUZhY3Rpb24pLFxuICAgICAgICAgICAgLy8gcm9sbFBhcnRpY2lwYW50RGF0YToge30sXG4gICAgICAgICAgICAvLyBjb25zZXF1ZW5jZURhdGE6IHt9LFxuICAgICAgICAgICAgLy8gcmVzaXN0YW5jZURhdGE6IHtcbiAgICAgICAgICAgIC8vICAgY29uc2VxdWVuY2U6IHt9XG4gICAgICAgICAgICAvLyB9LFxuICAgICAgICAgICAgcm9sbE1vZHNEYXRhOiB7fSxcbiAgICAgICAgICAgIHJvbGxQb3NpdGlvbkluaXRpYWw6IFBvc2l0aW9uLnJpc2t5LFxuICAgICAgICAgICAgcm9sbEVmZmVjdEluaXRpYWw6IEVmZmVjdC5zdGFuZGFyZCxcbiAgICAgICAgICAgIHJvbGxQb3NFZmZlY3RUcmFkZTogZmFsc2UsXG4gICAgICAgICAgICByb2xsUGhhc2U6IFJvbGxQaGFzZS5Db2xsYWJvcmF0aW9uLFxuICAgICAgICAgICAgR01Cb29zdHM6IHt9LFxuICAgICAgICAgICAgR01PcHBCb29zdHM6IHt9LFxuICAgICAgICAgICAgR01PdmVycmlkZXM6IHt9LFxuICAgICAgICAgICAgcm9sbEZhY3RvclRvZ2dsZXM6IHtcbiAgICAgICAgICAgICAgICBzb3VyY2U6IHt9LFxuICAgICAgICAgICAgICAgIG9wcG9zaXRpb246IHt9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgdXNlclBlcm1pc3Npb25zOiB7XG4gICAgICAgICAgICAgICAgW3NhbXBsZVVzZXIuaWRdOiBSb2xsUGVybWlzc2lvbnMuUHJpbWFyeVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gcm9sbFBvc2l0aW9uRmluYWw6IFBvc2l0aW9uLnJpc2t5LFxuICAgICAgICAgICAgLy8gcm9sbEVmZmVjdEZpbmFsOiBFZmZlY3Quc3RhbmRhcmQsXG4gICAgICAgICAgICAvLyByb2xsUmVzdWx0OiBSb2xsUmVzdWx0LnN1Y2Nlc3MsXG4gICAgICAgICAgICAvLyByb2xsUmVzdWx0RGVsdGE6IDAsXG4gICAgICAgICAgICAvLyByb2xsUmVzdWx0RmluYWw6IFJvbGxSZXN1bHQuc3VjY2VzcyxcbiAgICAgICAgICAgIC8vIHJvbGxUcmFpdFZlcmI6IFwic2tpcm1pc2hlc1wiLFxuICAgICAgICAgICAgLy8gcm9sbFRyYWl0UGFzdFZlcmI6IFwic2tpcm1pc2hlZFwiLFxuICAgICAgICAgICAgLy8gZmluYWxEaWNlRGF0YTogW10sXG4gICAgICAgICAgICAvLyBpc0lubGluZVJlc2lzdGFuY2VSb2xsOiBmYWxzZVxuICAgICAgICB9O1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgQmxhZGVzQWN0aW9uUm9sbF9TY2hlbWFcbiAgICAgICAgfTtcbiAgICB9XG59XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNEZWJ1ZztcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/core/debug.ts\n"); + +/***/ }), + +/***/ "./ts/core/gsap.ts": +/*!*************************!*\ + !*** ./ts/core/gsap.ts ***! + \*************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ ApplyTooltipAnimations: function() { return /* binding */ ApplyTooltipAnimations; },\n/* harmony export */ CustomBounce: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomBounce; },\n/* harmony export */ CustomEase: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomEase; },\n/* harmony export */ CustomWiggle: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomWiggle; },\n/* harmony export */ Dragger: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.Draggable; },\n/* harmony export */ EasePack: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.EasePack; },\n/* harmony export */ Flip: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.Flip; },\n/* harmony export */ Initialize: function() { return /* binding */ Initialize; },\n/* harmony export */ MotionPathPlugin: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.MotionPathPlugin; },\n/* harmony export */ Observer: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.Observer; },\n/* harmony export */ SplitText: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.SplitText; },\n/* harmony export */ TextPlugin: function() { return /* reexport safe */ gsap_all__WEBPACK_IMPORTED_MODULE_2__.TextPlugin; },\n/* harmony export */ gsapEffects: function() { return /* binding */ gsapEffects; }\n/* harmony export */ });\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var gsap_all__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! gsap/all */ \"gsap/all\");\n/* harmony import */ var gsap_all__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(gsap_all__WEBPACK_IMPORTED_MODULE_2__);\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n// eslint-disable-next-line import/no-unresolved\n\nconst gsapPlugins = [\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.TextPlugin,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.Flip,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.MotionPathPlugin,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.Draggable,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.SplitText,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.Observer,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomEase,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomWiggle,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomBounce,\n gsap_all__WEBPACK_IMPORTED_MODULE_2__.EasePack\n];\nconst gsapEffects = {\n // #region CLOCK KEYS\n keyDrop: {\n effect: (clockKey, config) => {\n const [keyContainer] = $(clockKey).closest(\".clock-key-container\");\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n onComplete() {\n if (config.callback) {\n config.callback();\n }\n }\n })\n .fromTo(keyContainer, {\n y: config.yShift\n }, {\n y: 0,\n autoAlpha: 1,\n ease: \"bounce\",\n duration: config.duration\n });\n },\n defaults: {\n duration: 1,\n yShift: -800\n },\n extendTimeline: true\n },\n keyPull: {\n effect: (clockKey, config) => {\n const [keyContainer] = $(clockKey).closest(\".clock-key-container\");\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n onComplete() {\n if (config.callback) {\n config.callback();\n }\n }\n })\n .to(keyContainer, {\n y: config.yDelta,\n ease: config.ease,\n duration: 0.75 * config.duration\n })\n .to(keyContainer, {\n opacity: 0,\n ease: \"power2.out\",\n duration: 0.25 * config.duration\n }, 0.75 * config.duration);\n },\n defaults: {\n yDelta: -800,\n duration: 1,\n ease: \"back.in(1)\"\n },\n extendTimeline: true\n },\n keyControlPanelFlip: {\n effect: (target, config) => {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n delay: config.delay,\n onStart() {\n if (target) {\n const target$ = $(target);\n // Get the next sibling of the target element if it has the class \"clock-control\"\n const nextSibling$ = target$.next(\".clock-control-flipper\");\n // Check if the nextSibling element exists\n if (nextSibling$.length) {\n _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.keyControlPanelFlip(nextSibling$[0], {\n ...config,\n delay: 0.15\n });\n }\n }\n }\n })\n .to(target, {\n rotateX: config.angle,\n duration: 0.5,\n ease: \"back.inOut(2)\"\n });\n },\n defaults: {\n angle: 180,\n delay: 0\n },\n extendTimeline: true\n },\n // #endregion\n // #region CHAT CONSEQUENCE EFFECTS\n csqEnter: {\n effect: (csqContainer, config) => {\n const csqRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqContainer);\n // ELog.checkLog3(\"gsap\", \"gsapEffects.consequenceEnter -> THIS\", {this: this, csqRoot});\n const csqIconCircle = csqRoot(\".consequence-icon-circle.base-consequence\");\n // const csqBaseElems = csqRoot(\".base-consequence:not(.consequence-icon-circle)\");\n const csqBaseTypeElem = csqRoot(\".consequence-type.base-consequence\");\n const csqAcceptTypeElem = csqRoot(\".consequence-type.accept-consequence\");\n const csqBaseNameElem = csqRoot(\".consequence-name.base-consequence\");\n const csqAcceptNameElem = csqRoot(\".consequence-name.accept-consequence\");\n // const csqAcceptElems = csqRoot(\".accept-consequence:not(.consequence-icon-circle):not(.consequence-button-container)\");\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ paused: true, defaults: {} });\n // Initialize name and type opacities.\n if (csqAcceptTypeElem.length > 0) {\n tl.set(csqAcceptTypeElem, { opacity: 0 }, 0);\n }\n if (csqAcceptNameElem.length > 0) {\n tl.set(csqAcceptNameElem, { opacity: 0 }, 0);\n }\n // Crossfade base/accept type lines\n if (csqBaseTypeElem.length > 0) {\n tl.fromTo(csqBaseTypeElem, {\n opacity: 1\n }, {\n opacity: 0,\n duration: 0.25,\n ease: \"sine\"\n }, 0);\n }\n if (csqAcceptTypeElem.length > 0) {\n tl.fromTo(csqAcceptTypeElem, {\n opacity: 0\n }, {\n opacity: 1,\n duration: 0.25,\n ease: \"sine\"\n }, 0);\n }\n // Crossfade base/accept name lines\n if (csqBaseNameElem.length > 0) {\n tl.fromTo(csqBaseNameElem, {\n opacity: 1\n }, {\n opacity: 0,\n duration: 0.25,\n ease: \"sine\"\n }, 0);\n }\n if (csqAcceptNameElem.length > 0) {\n tl.fromTo(csqAcceptNameElem, {\n opacity: 0\n }, {\n opacity: 1,\n duration: 0.25,\n ease: \"sine\"\n }, 0);\n }\n // Brighten the entire container slightly\n if (csqContainer) {\n tl.fromTo(csqContainer, {\n filter: \"brightness(1)\"\n }, {\n filter: `brightness(${config.brightness})`,\n duration: config.duration / 3,\n ease: \"none\"\n }, 0);\n }\n // Enlarge the icon circle, add stroke\n if (csqIconCircle.length > 0) {\n tl.fromTo(csqIconCircle, {\n scale: 0.75,\n outlineColor: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n outlineWidth: 0\n }, {\n scale: 0.85,\n outlineColor: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n outlineWidth: 1,\n duration: 0.55,\n ease: \"sine.out\"\n }, 0);\n }\n return tl;\n },\n defaults: {\n brightness: 1.5,\n duration: 0.5,\n scale: 1.5,\n stagger: 0.05,\n ease: \"sine\",\n easeStrength: 1.5\n }\n },\n csqClickIcon: {\n effect: (csqIconContainer, config) => {\n const csqContainer = $(csqIconContainer).closest(\".comp.consequence-display-container\");\n const csqRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqContainer[0]);\n const iconRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqIconContainer);\n const csqBackgroundImg = csqRoot(\".consequence-bg-image\");\n const csqInteractionPads = csqRoot(\".consequence-interaction-pad\");\n const csqIconCircleBase = iconRoot(\".consequence-icon-circle.base-consequence\");\n const csqIconCircleAccept = iconRoot(\".consequence-icon-circle.accept-consequence\");\n const csqButtonContainers = iconRoot(\".consequence-button-container\");\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n paused: true,\n onComplete: function () {\n $(csqInteractionPads).css(\"pointerEvents\", \"auto\");\n },\n onReverseComplete: function () {\n $(csqInteractionPads).css(\"pointerEvents\", \"none\");\n }\n });\n // Slide out the background\n if (csqBackgroundImg.length) {\n tl.fromTo(csqBackgroundImg, {\n xPercent: 110,\n yPercent: -50\n }, {\n xPercent: -60,\n yPercent: -50,\n duration: 0.5,\n ease: \"back\"\n }, 0);\n }\n // Fade out the base consequence icon circle\n if (csqIconCircleBase.length > 0) {\n tl.fromTo(csqIconCircleBase, {\n opacity: 1\n }, {\n opacity: 0,\n duration: 0.25,\n ease: \"sine.out\"\n }, 0);\n }\n // Fade in the accept consequence icon circle, enlarging the stroke\n if (csqIconCircleAccept.length > 0) {\n tl.fromTo(csqIconCircleAccept, {\n opacity: 0\n }, {\n opacity: 1,\n duration: 0.15,\n ease: \"sine\"\n }, 0)\n .fromTo(csqIconCircleAccept, {\n outlineWidth: 1,\n scale: 0.85\n }, {\n outlineWidth: 2,\n scale: 1,\n duration: 0.25,\n ease: \"sine\"\n }, 0.175);\n }\n // Scale and fade in the button containers\n if (csqButtonContainers.length > 0) {\n tl.fromTo(csqButtonContainers, {\n scale: config.scale,\n opacity: 0,\n filter: \"blur(25px)\"\n }, {\n scale: 1,\n opacity: 1,\n filter: \"blur(0px)\",\n stagger: config.stagger,\n duration: config.duration,\n ease: `${config.ease}.inOut(${config.easeStrength})`\n }, 0);\n }\n return tl;\n },\n defaults: {\n duration: 0.5,\n scale: 1.5,\n stagger: 0.05,\n ease: \"sine\",\n easeStrength: 1.5\n }\n },\n csqEnterRight: {\n effect: (csqContainer) => {\n const csqRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqContainer);\n const typeLine = csqRoot(\".consequence-type-container .consequence-type.accept-consequence\");\n const typeLineBg = csqRoot(\".consequence-type-container .consequence-type-bg.accept-consequence\");\n const buttonRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqRoot(\".consequence-button-container.consequence-accept-button-container\"));\n const buttonBg = buttonRoot(\".consequence-button-bg\");\n const buttonIcon = buttonRoot(\".button-icon i\");\n const buttonLabel = buttonRoot(\".consequence-button-label\");\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ paused: true, defaults: {} });\n // Turn type line white\n if (typeLine.length > 0) {\n tl.fromTo(typeLine, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.RED\n }, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.WHITE,\n duration: 0.5,\n ease: \"sine.inOut\"\n }, 0);\n }\n // Slide type line background out from under icon\n if (typeLineBg.length > 0) {\n tl.fromTo(typeLineBg, {\n x: 5,\n scaleX: 0,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.RED,\n skewX: 0\n }, {\n scaleX: 1,\n skewX: -45,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.RED,\n duration: 0.5,\n ease: \"back.out\"\n }, 0);\n }\n // Slide accept button background out from under icon\n if (buttonBg.length > 0) {\n tl.fromTo(buttonBg, {\n scaleX: 0,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.RED,\n skewX: 0\n }, {\n x: 0,\n scaleX: 1,\n skewX: -45,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.RED,\n duration: 0.25,\n ease: \"back.out\"\n }, 0);\n }\n // Turn button icon black and scale\n if (buttonIcon.length > 0) {\n tl.fromTo(buttonIcon, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n opacity: 0.75,\n scale: 1\n }, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n scale: 1.25,\n opacity: 1,\n duration: 0.5,\n ease: \"sine\"\n }, 0);\n }\n // Turn button label black, add letter-spacing, bold\n if (buttonLabel.length > 0) {\n tl.fromTo(buttonLabel, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n fontWeight: 400,\n scale: 1\n }, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n fontWeight: 800,\n duration: 0.75,\n ease: \"sine\"\n }, 0);\n }\n return tl;\n },\n defaults: {}\n },\n csqEnterLeft: {\n effect: (csqContainer) => {\n const csqRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqContainer);\n const typeLine = csqRoot(\".consequence-type-container .consequence-type.accept-consequence\");\n const nameLine = csqRoot(\".consequence-name-container .consequence-name.accept-consequence\");\n const acceptIconCircle = csqRoot(\".consequence-icon-circle.accept-consequence\");\n const acceptButton = csqRoot(\".consequence-button-container.consequence-accept-button-container\");\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ paused: true, defaults: {} });\n // Fade out type line\n if (typeLine.length > 0) {\n tl.to(typeLine, {\n opacity: 0,\n duration: 0.15,\n ease: \"sine.inOut\"\n }, 0);\n }\n // Fade out name\n if (nameLine.length > 0) {\n tl.to(nameLine, {\n opacity: 0,\n duration: 0.15,\n ease: \"sine.inOut\"\n }, 0);\n }\n // Fade out icon\n if (acceptIconCircle.length > 0) {\n tl.to(acceptIconCircle, {\n opacity: 0,\n duration: 0.15,\n ease: \"sine.inOut\"\n }, 0);\n }\n // Fade out accept button\n if (acceptButton.length > 0) {\n tl.fromTo(acceptButton, {\n opacity: 1\n }, {\n opacity: 0,\n duration: 0.25,\n ease: \"sine.inOut\"\n }, 0);\n }\n return tl;\n },\n defaults: {}\n },\n csqEnterSubLeft: {\n effect: (csqContainer, config) => {\n const csqRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqContainer);\n const iconCircle = csqRoot(`.consequence-icon-circle.${config.type}-consequence`);\n const typeLine = csqRoot(`.consequence-type-container .consequence-type.${config.type}-consequence`);\n const nameLine = csqRoot(`.consequence-name.${config.type}-consequence`);\n const footerBg = csqRoot(`.consequence-footer-container .consequence-footer-bg.${config.type}-consequence`);\n const specialFooterMsg = csqRoot(`.consequence-footer-container .consequence-footer-message.${config.type}-consequence`);\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ paused: true, defaults: {} });\n // Fade in icon circle\n if (iconCircle.length > 0) {\n tl.fromTo(iconCircle, {\n opacity: 0\n }, {\n opacity: 1,\n duration: 0.5,\n ease: \"back.out\"\n }, 0);\n }\n // Fade in typeLine\n if (typeLine.length > 0) {\n tl.fromTo(typeLine, {\n opacity: 0\n }, {\n opacity: 1,\n duration: 0.5,\n ease: \"back.out\"\n }, 0);\n }\n // Slide out nameLine from left\n if (nameLine.length > 0) {\n tl.fromTo(nameLine, {\n scaleX: 0\n }, {\n scaleX: 1,\n duration: 0.5,\n ease: \"back.inOut\"\n }, 0);\n }\n // Slide out footer background from left\n if (footerBg.length > 0) {\n tl.fromTo(footerBg, {\n scaleX: 0,\n skewX: 0,\n opacity: 1\n }, {\n scaleX: 1,\n skewX: -45,\n opacity: 1,\n duration: 0.5,\n ease: \"back.inOut\"\n }, 0);\n }\n // Slide out attribute from left\n if (specialFooterMsg.length > 0) {\n tl.fromTo(specialFooterMsg, {\n scaleX: 0,\n opacity: 1\n }, {\n scaleX: 1,\n opacity: 1,\n duration: 0.5,\n ease: \"back.inOut\"\n }, 0);\n }\n if (csqRoot(`.consequence-button-container.consequence-${config.type}-button-container`).length > 0) {\n const buttonRoot = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.selector(csqRoot(`.consequence-button-container.consequence-${config.type}-button-container`));\n const buttonBg = buttonRoot(\".consequence-button-bg\");\n const buttonIcon = buttonRoot(\".button-icon i\");\n const buttonLabel = buttonRoot(\".consequence-button-label\");\n // Slide out button background from right\n if (buttonBg.length > 0) {\n tl.fromTo(buttonBg, {\n scaleX: 0,\n skewX: 0,\n opacity: 1\n }, {\n scaleX: 1,\n skewX: -45,\n opacity: 1,\n duration: 0.5,\n ease: \"back.inOut\"\n }, 0);\n }\n // Turn button icon black and scale\n if (buttonIcon.length > 0) {\n tl.fromTo(buttonIcon, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n opacity: 0.75,\n scale: 1\n }, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n scale: 1.25,\n opacity: 1,\n duration: 0.5,\n ease: \"sine\"\n }, 0);\n }\n // Turn button label black, bold\n if (buttonLabel.length > 0) {\n tl.fromTo(buttonLabel, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n fontWeight: 400,\n scale: 1\n }, {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n fontWeight: 800,\n duration: 0.75,\n ease: \"sine\"\n }, 0);\n }\n }\n return tl;\n },\n defaults: {}\n },\n // #endregion\n // #region CHARACTER SHEET EFFECTS\n fillCoins: {\n effect: (targets, config) => {\n // Targets will be all coins from zero to where fill currently is\n // Some will already be full, others not.\n // Stagger in timeline\n // Pulse in size and color\n // Shimmer as they shrink back ?\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.to(targets, {\n duration: config.duration / 2,\n scale: config.scale,\n filter: config.filter,\n ease: config.ease,\n stagger: {\n amount: 0.25,\n from: \"start\",\n repeat: 1,\n yoyo: true\n }\n });\n },\n defaults: {\n duration: 1,\n scale: 1,\n filter: \"saturate(1) brightness(2)\",\n ease: \"power2.in\"\n },\n extendTimeline: true\n },\n // #endregion\n // #region GENERAL: 'blurRemove', 'hoverTooltip', 'textJitter'\n blurRemove: {\n effect: (targets, config) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({ stagger: config.stagger })\n .to(targets, {\n skewX: config.skewX,\n duration: config.duration / 2,\n ease: \"power4.out\"\n })\n .to(targets, {\n x: config.x,\n marginBottom: config.ignoreMargin\n ? undefined\n : function (i, target) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(target, \"height\") * -1;\n },\n marginRight: config.ignoreMargin\n ? undefined\n : function (i, target) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(target, \"width\") * -1;\n },\n scale: config.scale,\n filter: `blur(${config.blur}px)`,\n duration: (3 / 4) * config.duration\n }, config.duration / 4)\n .to(targets, {\n autoAlpha: 0,\n duration: config.duration / 2,\n ease: \"power3.in\"\n }, config.duration / 2),\n defaults: {\n ignoreMargin: false,\n skewX: -20,\n duration: 0.5,\n x: \"+=300\",\n scale: 1.5,\n blur: 10,\n stagger: 0\n },\n extendTimeline: true\n },\n blurReveal: {\n effect: (targets, config) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .fromTo(targets, {\n x: config.x,\n marginBottom: config.ignoreMargin\n ? undefined\n : function (i, target) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(target, \"height\") * -1;\n },\n marginRight: config.ignoreMargin\n ? undefined\n : function (i, target) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].get(target, \"width\") * -1;\n },\n scale: config.scale,\n filter: `blur(${config.blur}px)`\n }, {\n x: 0,\n marginBottom: 0,\n marginRight: 0,\n scale: 1,\n filter: \"blur(0px)\",\n duration: (3 / 4) * config.duration\n }, 0)\n .fromTo(targets, {\n autoAlpha: 0\n }, {\n autoAlpha: 1,\n duration: config.duration / 2,\n ease: \"power3.in\"\n }, 0)\n .fromTo(targets, {\n skewX: config.skewX\n }, {\n skewX: 0,\n duration: config.duration / 2,\n ease: \"power4.out\"\n }, config.duration / 2),\n defaults: {\n ignoreMargin: false,\n skewX: -20,\n duration: 0.5,\n x: \"+=300\",\n scale: 1.5,\n blur: 10\n },\n extendTimeline: true\n },\n scaleUpReveal: {\n effect: (target, config) => {\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .fromTo(target, {\n autoAlpha: 0,\n scale: 0.5 * config.scale\n }, {\n autoAlpha: 1,\n scale: config.scale,\n duration: config.duration,\n ease: config.ease\n });\n return tl;\n },\n defaults: {\n scale: 1,\n duration: 0.5,\n ease: \"power2\"\n },\n extendTimeline: true\n },\n scaleDownRemove: {\n effect: (target, config) => {\n const tl = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .to(target, {\n autoAlpha: 0,\n scale: 0.5 * config.scale,\n duration: config.duration,\n ease: config.ease\n });\n return tl;\n },\n defaults: {\n scale: 1,\n duration: 0.5,\n ease: \"power2\"\n },\n extendTimeline: true\n },\n blurRevealTooltip: {\n effect: (target, config) => {\n if (!target) {\n throw new Error(`blurRevealTooltip effect: tooltip element is ${target === null ? \"null\" : typeof target}`);\n }\n const tooltip$ = $(target);\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline({\n paused: true,\n onReverseComplete: config.onReverseComplete\n })\n .fromTo(tooltip$, {\n filter: `blur(${config.blurStrength}px)`,\n autoAlpha: 0,\n xPercent: 50,\n yPercent: -200,\n scale: config.scale\n }, {\n filter: \"blur(0px)\",\n autoAlpha: 1,\n xPercent: -50,\n yPercent: -100,\n scale: 1,\n ease: config.ease,\n duration: config.duration\n });\n },\n defaults: {\n scale: 1.5,\n blurStrength: 15,\n ease: \"back.out\",\n duration: 0.25,\n onReverseComplete: undefined\n },\n extendTimeline: true\n },\n textJitter: {\n effect: (target, config) => {\n const [targetElem] = $(target);\n if (!targetElem) {\n throw new Error(\"textJitter effect: target not found\");\n }\n const split = new gsap_all__WEBPACK_IMPORTED_MODULE_2__.SplitText(targetElem, { type: \"chars\" });\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.timeline()\n .to(targetElem, {\n autoAlpha: 1,\n duration: config.duration,\n ease: \"none\"\n })\n .fromTo(split.chars, {\n y: -config.yAmp\n }, {\n y: config.yAmp,\n duration: config.duration,\n ease: \"sine.inOut\",\n stagger: {\n repeat: -1,\n yoyo: true,\n from: \"random\",\n each: config.stagger\n }\n }, 0)\n .fromTo(split.chars, {\n rotateZ: -config.rotateAmp\n }, {\n rotateZ: config.rotateAmp,\n duration: config.duration,\n ease: gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomWiggle.create(\"myWiggle\", { wiggles: 10, type: \"random\" }),\n stagger: {\n repeat: -1,\n from: \"random\",\n yoyo: true,\n each: config.stagger\n }\n }, 0);\n },\n defaults: {\n yAmp: 2,\n rotateAmp: 2,\n duration: 1,\n stagger: 0.05\n },\n extendTimeline: true\n }\n // #endregion\n};\n/**\n * Registers relevant GSAP plugins and effects.\n */\nfunction Initialize() {\n if (gsapPlugins.length) {\n _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.config({\n nullTargetWarn: true\n });\n _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.registerPlugin(...gsapPlugins);\n Object.assign(globalThis, {\n TextPlugin: gsap_all__WEBPACK_IMPORTED_MODULE_2__.TextPlugin,\n Flip: gsap_all__WEBPACK_IMPORTED_MODULE_2__.Flip,\n MotionPathPlugin: gsap_all__WEBPACK_IMPORTED_MODULE_2__.MotionPathPlugin,\n Dragger: gsap_all__WEBPACK_IMPORTED_MODULE_2__.Draggable,\n SplitText: gsap_all__WEBPACK_IMPORTED_MODULE_2__.SplitText,\n Observer: gsap_all__WEBPACK_IMPORTED_MODULE_2__.Observer,\n CustomEase: gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomEase,\n CustomWiggle: gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomWiggle,\n CustomBounce: gsap_all__WEBPACK_IMPORTED_MODULE_2__.CustomBounce,\n EasePack: gsap_all__WEBPACK_IMPORTED_MODULE_2__.EasePack\n });\n }\n Object.entries(gsapEffects).forEach(([name, effect]) => {\n _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.registerEffect(Object.assign(effect, { name }));\n });\n}\n/**\n * Applies listeners to '.tooltip-trigger' elements in the document.\n * @param {JQuery} html The document to be searched.\n */\nfunction ApplyTooltipAnimations(html) {\n html.find(\".tooltip-trigger\").each((_, el) => {\n const tooltipElem = $(el).find(\".tooltip\")[0] ?? $(el).next(\".tooltip\")[0];\n if (!tooltipElem) {\n return;\n }\n const tooltip$ = $(tooltipElem);\n /**\n * Use the .tooltip-trigger element as the definitive positioning element for the tooltip itself.\n * If the tooltip-trigger's absolute position relative to the viewport is, e.g., near the top,\n * then the tooltip should appear beneath, etc\n */\n // Find the tooltip's parent container. If its position isn't relative or absolute, set it to relative.\n const tooltipContainer$ = tooltip$.parent();\n if (tooltipContainer$.css(\"position\") !== \"relative\"\n && tooltipContainer$.css(\"position\") !== \"absolute\") {\n tooltipContainer$.css(\"position\", \"relative\");\n }\n // Set the tooltip itself to absolute positioning\n tooltip$.css(\"position\", \"absolute\");\n // Assign a unique ID to the tooltip element\n const tooltipID = `tooltip-${randomID()}`;\n tooltip$.attr(\"id\", tooltipID);\n // For .tooltip-wide tooltips, adjust the aspect ratio accordingly\n if (tooltip$.hasClass(\"tooltip-wide\")) {\n _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].adjustTextContainerAspectRatio(tooltipElem, 6);\n }\n $(el).on({\n mouseenter: function () {\n game.eunoblades.Director.displayTooltip(tooltipElem);\n },\n mouseleave: function () {\n game.eunoblades.Director.clearTooltip(tooltipID);\n }\n });\n });\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFDQTtBQUNBLFNBQVM7QUFDVCxLQUFLO0FBQ0w7QUFDOEg7QUFDOUgsK0RBQWUsa0RBQUMsS0FBSyxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvY29yZS9nc2FwLnRzPzQyNTgiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgVSBmcm9tIFwiLi91dGlsaXRpZXNcIjtcbmltcG9ydCBDIGZyb20gXCIuL2NvbnN0YW50c1wiO1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby11bnJlc29sdmVkXG5pbXBvcnQgeyBUZXh0UGx1Z2luLCBGbGlwLCBEcmFnZ2FibGUgYXMgRHJhZ2dlciwgTW90aW9uUGF0aFBsdWdpbiwgU3BsaXRUZXh0LCBPYnNlcnZlciwgQ3VzdG9tRWFzZSwgQ3VzdG9tV2lnZ2xlLCBDdXN0b21Cb3VuY2UsIEVhc2VQYWNrIH0gZnJvbSBcImdzYXAvYWxsXCI7XG5jb25zdCBnc2FwUGx1Z2lucyA9IFtcbiAgICBUZXh0UGx1Z2luLFxuICAgIEZsaXAsXG4gICAgTW90aW9uUGF0aFBsdWdpbixcbiAgICBEcmFnZ2VyLFxuICAgIFNwbGl0VGV4dCxcbiAgICBPYnNlcnZlcixcbiAgICBDdXN0b21FYXNlLFxuICAgIEN1c3RvbVdpZ2dsZSxcbiAgICBDdXN0b21Cb3VuY2UsXG4gICAgRWFzZVBhY2tcbl07XG5leHBvcnQgY29uc3QgZ3NhcEVmZmVjdHMgPSB7XG4gICAgLy8gI3JlZ2lvbiBDTE9DSyBLRVlTXG4gICAga2V5RHJvcDoge1xuICAgICAgICBlZmZlY3Q6IChjbG9ja0tleSwgY29uZmlnKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBba2V5Q29udGFpbmVyXSA9ICQoY2xvY2tLZXkpLmNsb3Nlc3QoXCIuY2xvY2sta2V5LWNvbnRhaW5lclwiKTtcbiAgICAgICAgICAgIHJldHVybiBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgICAgIG9uQ29tcGxldGUoKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjb25maWcuY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbmZpZy5jYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAuZnJvbVRvKGtleUNvbnRhaW5lciwge1xuICAgICAgICAgICAgICAgIHk6IGNvbmZpZy55U2hpZnRcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICB5OiAwLFxuICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogMSxcbiAgICAgICAgICAgICAgICBlYXNlOiBcImJvdW5jZVwiLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBjb25maWcuZHVyYXRpb25cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0czoge1xuICAgICAgICAgICAgZHVyYXRpb246IDEsXG4gICAgICAgICAgICB5U2hpZnQ6IC04MDBcbiAgICAgICAgfSxcbiAgICAgICAgZXh0ZW5kVGltZWxpbmU6IHRydWVcbiAgICB9LFxuICAgIGtleVB1bGw6IHtcbiAgICAgICAgZWZmZWN0OiAoY2xvY2tLZXksIGNvbmZpZykgPT4ge1xuICAgICAgICAgICAgY29uc3QgW2tleUNvbnRhaW5lcl0gPSAkKGNsb2NrS2V5KS5jbG9zZXN0KFwiLmNsb2NrLWtleS1jb250YWluZXJcIik7XG4gICAgICAgICAgICByZXR1cm4gVS5nc2FwLnRpbWVsaW5lKHtcbiAgICAgICAgICAgICAgICBvbkNvbXBsZXRlKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoY29uZmlnLmNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25maWcuY2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRvKGtleUNvbnRhaW5lciwge1xuICAgICAgICAgICAgICAgIHk6IGNvbmZpZy55RGVsdGEsXG4gICAgICAgICAgICAgICAgZWFzZTogY29uZmlnLmVhc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNzUgKiBjb25maWcuZHVyYXRpb25cbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnRvKGtleUNvbnRhaW5lciwge1xuICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAsXG4gICAgICAgICAgICAgICAgZWFzZTogXCJwb3dlcjIub3V0XCIsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDAuMjUgKiBjb25maWcuZHVyYXRpb25cbiAgICAgICAgICAgIH0sIDAuNzUgKiBjb25maWcuZHVyYXRpb24pO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0czoge1xuICAgICAgICAgICAgeURlbHRhOiAtODAwLFxuICAgICAgICAgICAgZHVyYXRpb246IDEsXG4gICAgICAgICAgICBlYXNlOiBcImJhY2suaW4oMSlcIlxuICAgICAgICB9LFxuICAgICAgICBleHRlbmRUaW1lbGluZTogdHJ1ZVxuICAgIH0sXG4gICAga2V5Q29udHJvbFBhbmVsRmxpcDoge1xuICAgICAgICBlZmZlY3Q6ICh0YXJnZXQsIGNvbmZpZykgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIFUuZ3NhcC50aW1lbGluZSh7XG4gICAgICAgICAgICAgICAgZGVsYXk6IGNvbmZpZy5kZWxheSxcbiAgICAgICAgICAgICAgICBvblN0YXJ0KCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGFyZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB0YXJnZXQkID0gJCh0YXJnZXQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBuZXh0IHNpYmxpbmcgb2YgdGhlIHRhcmdldCBlbGVtZW50IGlmIGl0IGhhcyB0aGUgY2xhc3MgXCJjbG9jay1jb250cm9sXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IG5leHRTaWJsaW5nJCA9IHRhcmdldCQubmV4dChcIi5jbG9jay1jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgbmV4dFNpYmxpbmcgZWxlbWVudCBleGlzdHNcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChuZXh0U2libGluZyQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVS5nc2FwLmVmZmVjdHMua2V5Q29udHJvbFBhbmVsRmxpcChuZXh0U2libGluZyRbMF0sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uY29uZmlnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZWxheTogMC4xNVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICAudG8odGFyZ2V0LCB7XG4gICAgICAgICAgICAgICAgcm90YXRlWDogY29uZmlnLmFuZ2xlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrLmluT3V0KDIpXCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0czoge1xuICAgICAgICAgICAgYW5nbGU6IDE4MCxcbiAgICAgICAgICAgIGRlbGF5OiAwXG4gICAgICAgIH0sXG4gICAgICAgIGV4dGVuZFRpbWVsaW5lOiB0cnVlXG4gICAgfSxcbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBDSEFUIENPTlNFUVVFTkNFIEVGRkVDVFNcbiAgICBjc3FFbnRlcjoge1xuICAgICAgICBlZmZlY3Q6IChjc3FDb250YWluZXIsIGNvbmZpZykgPT4ge1xuICAgICAgICAgICAgY29uc3QgY3NxUm9vdCA9IFUuZ3NhcC51dGlscy5zZWxlY3Rvcihjc3FDb250YWluZXIpO1xuICAgICAgICAgICAgLy8gRUxvZy5jaGVja0xvZzMoXCJnc2FwXCIsIFwiZ3NhcEVmZmVjdHMuY29uc2VxdWVuY2VFbnRlciAtPiBUSElTXCIsIHt0aGlzOiB0aGlzLCBjc3FSb290fSk7XG4gICAgICAgICAgICBjb25zdCBjc3FJY29uQ2lyY2xlID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS1pY29uLWNpcmNsZS5iYXNlLWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgLy8gY29uc3QgY3NxQmFzZUVsZW1zID0gY3NxUm9vdChcIi5iYXNlLWNvbnNlcXVlbmNlOm5vdCguY29uc2VxdWVuY2UtaWNvbi1jaXJjbGUpXCIpO1xuICAgICAgICAgICAgY29uc3QgY3NxQmFzZVR5cGVFbGVtID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS10eXBlLmJhc2UtY29uc2VxdWVuY2VcIik7XG4gICAgICAgICAgICBjb25zdCBjc3FBY2NlcHRUeXBlRWxlbSA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtdHlwZS5hY2NlcHQtY29uc2VxdWVuY2VcIik7XG4gICAgICAgICAgICBjb25zdCBjc3FCYXNlTmFtZUVsZW0gPSBjc3FSb290KFwiLmNvbnNlcXVlbmNlLW5hbWUuYmFzZS1jb25zZXF1ZW5jZVwiKTtcbiAgICAgICAgICAgIGNvbnN0IGNzcUFjY2VwdE5hbWVFbGVtID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS1uYW1lLmFjY2VwdC1jb25zZXF1ZW5jZVwiKTtcbiAgICAgICAgICAgIC8vIGNvbnN0IGNzcUFjY2VwdEVsZW1zID0gY3NxUm9vdChcIi5hY2NlcHQtY29uc2VxdWVuY2U6bm90KC5jb25zZXF1ZW5jZS1pY29uLWNpcmNsZSk6bm90KC5jb25zZXF1ZW5jZS1idXR0b24tY29udGFpbmVyKVwiKTtcbiAgICAgICAgICAgIGNvbnN0IHRsID0gVS5nc2FwLnRpbWVsaW5lKHsgcGF1c2VkOiB0cnVlLCBkZWZhdWx0czoge30gfSk7XG4gICAgICAgICAgICAvLyBJbml0aWFsaXplIG5hbWUgYW5kIHR5cGUgb3BhY2l0aWVzLlxuICAgICAgICAgICAgaWYgKGNzcUFjY2VwdFR5cGVFbGVtLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB0bC5zZXQoY3NxQWNjZXB0VHlwZUVsZW0sIHsgb3BhY2l0eTogMCB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjc3FBY2NlcHROYW1lRWxlbS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuc2V0KGNzcUFjY2VwdE5hbWVFbGVtLCB7IG9wYWNpdHk6IDAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBDcm9zc2ZhZGUgYmFzZS9hY2NlcHQgdHlwZSBsaW5lc1xuICAgICAgICAgICAgaWYgKGNzcUJhc2VUeXBlRWxlbS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGNzcUJhc2VUeXBlRWxlbSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4yNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lXCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjc3FBY2NlcHRUeXBlRWxlbS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGNzcUFjY2VwdFR5cGVFbGVtLCB7XG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDBcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjI1LFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcInNpbmVcIlxuICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gQ3Jvc3NmYWRlIGJhc2UvYWNjZXB0IG5hbWUgbGluZXNcbiAgICAgICAgICAgIGlmIChjc3FCYXNlTmFtZUVsZW0ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21Ubyhjc3FCYXNlTmFtZUVsZW0sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMVxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuMjUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZVwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY3NxQWNjZXB0TmFtZUVsZW0ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21Ubyhjc3FBY2NlcHROYW1lRWxlbSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAwXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4yNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lXCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEJyaWdodGVuIHRoZSBlbnRpcmUgY29udGFpbmVyIHNsaWdodGx5XG4gICAgICAgICAgICBpZiAoY3NxQ29udGFpbmVyKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGNzcUNvbnRhaW5lciwge1xuICAgICAgICAgICAgICAgICAgICBmaWx0ZXI6IFwiYnJpZ2h0bmVzcygxKVwiXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBmaWx0ZXI6IGBicmlnaHRuZXNzKCR7Y29uZmlnLmJyaWdodG5lc3N9KWAsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBjb25maWcuZHVyYXRpb24gLyAzLFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcIm5vbmVcIlxuICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRW5sYXJnZSB0aGUgaWNvbiBjaXJjbGUsIGFkZCBzdHJva2VcbiAgICAgICAgICAgIGlmIChjc3FJY29uQ2lyY2xlLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB0bC5mcm9tVG8oY3NxSWNvbkNpcmNsZSwge1xuICAgICAgICAgICAgICAgICAgICBzY2FsZTogMC43NSxcbiAgICAgICAgICAgICAgICAgICAgb3V0bGluZUNvbG9yOiBDLkNvbG9ycy5kQkxBQ0ssXG4gICAgICAgICAgICAgICAgICAgIG91dGxpbmVXaWR0aDogMFxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgc2NhbGU6IDAuODUsXG4gICAgICAgICAgICAgICAgICAgIG91dGxpbmVDb2xvcjogQy5Db2xvcnMuR1JFWSxcbiAgICAgICAgICAgICAgICAgICAgb3V0bGluZVdpZHRoOiAxLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41NSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lLm91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGw7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHRzOiB7XG4gICAgICAgICAgICBicmlnaHRuZXNzOiAxLjUsXG4gICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgc2NhbGU6IDEuNSxcbiAgICAgICAgICAgIHN0YWdnZXI6IDAuMDUsXG4gICAgICAgICAgICBlYXNlOiBcInNpbmVcIixcbiAgICAgICAgICAgIGVhc2VTdHJlbmd0aDogMS41XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGNzcUNsaWNrSWNvbjoge1xuICAgICAgICBlZmZlY3Q6IChjc3FJY29uQ29udGFpbmVyLCBjb25maWcpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNzcUNvbnRhaW5lciA9ICQoY3NxSWNvbkNvbnRhaW5lcikuY2xvc2VzdChcIi5jb21wLmNvbnNlcXVlbmNlLWRpc3BsYXktY29udGFpbmVyXCIpO1xuICAgICAgICAgICAgY29uc3QgY3NxUm9vdCA9IFUuZ3NhcC51dGlscy5zZWxlY3Rvcihjc3FDb250YWluZXJbMF0pO1xuICAgICAgICAgICAgY29uc3QgaWNvblJvb3QgPSBVLmdzYXAudXRpbHMuc2VsZWN0b3IoY3NxSWNvbkNvbnRhaW5lcik7XG4gICAgICAgICAgICBjb25zdCBjc3FCYWNrZ3JvdW5kSW1nID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS1iZy1pbWFnZVwiKTtcbiAgICAgICAgICAgIGNvbnN0IGNzcUludGVyYWN0aW9uUGFkcyA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtaW50ZXJhY3Rpb24tcGFkXCIpO1xuICAgICAgICAgICAgY29uc3QgY3NxSWNvbkNpcmNsZUJhc2UgPSBpY29uUm9vdChcIi5jb25zZXF1ZW5jZS1pY29uLWNpcmNsZS5iYXNlLWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgY29uc3QgY3NxSWNvbkNpcmNsZUFjY2VwdCA9IGljb25Sb290KFwiLmNvbnNlcXVlbmNlLWljb24tY2lyY2xlLmFjY2VwdC1jb25zZXF1ZW5jZVwiKTtcbiAgICAgICAgICAgIGNvbnN0IGNzcUJ1dHRvbkNvbnRhaW5lcnMgPSBpY29uUm9vdChcIi5jb25zZXF1ZW5jZS1idXR0b24tY29udGFpbmVyXCIpO1xuICAgICAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgICAgIHBhdXNlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBvbkNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICQoY3NxSW50ZXJhY3Rpb25QYWRzKS5jc3MoXCJwb2ludGVyRXZlbnRzXCIsIFwiYXV0b1wiKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIG9uUmV2ZXJzZUNvbXBsZXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICQoY3NxSW50ZXJhY3Rpb25QYWRzKS5jc3MoXCJwb2ludGVyRXZlbnRzXCIsIFwibm9uZVwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIC8vIFNsaWRlIG91dCB0aGUgYmFja2dyb3VuZFxuICAgICAgICAgICAgaWYgKGNzcUJhY2tncm91bmRJbWcubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGNzcUJhY2tncm91bmRJbWcsIHtcbiAgICAgICAgICAgICAgICAgICAgeFBlcmNlbnQ6IDExMCxcbiAgICAgICAgICAgICAgICAgICAgeVBlcmNlbnQ6IC01MFxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgeFBlcmNlbnQ6IC02MCxcbiAgICAgICAgICAgICAgICAgICAgeVBlcmNlbnQ6IC01MCxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrXCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZhZGUgb3V0IHRoZSBiYXNlIGNvbnNlcXVlbmNlIGljb24gY2lyY2xlXG4gICAgICAgICAgICBpZiAoY3NxSWNvbkNpcmNsZUJhc2UubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21Ubyhjc3FJY29uQ2lyY2xlQmFzZSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4yNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lLm91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGYWRlIGluIHRoZSBhY2NlcHQgY29uc2VxdWVuY2UgaWNvbiBjaXJjbGUsIGVubGFyZ2luZyB0aGUgc3Ryb2tlXG4gICAgICAgICAgICBpZiAoY3NxSWNvbkNpcmNsZUFjY2VwdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGNzcUljb25DaXJjbGVBY2NlcHQsIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMFxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuMTUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZVwiXG4gICAgICAgICAgICAgICAgfSwgMClcbiAgICAgICAgICAgICAgICAgICAgLmZyb21Ubyhjc3FJY29uQ2lyY2xlQWNjZXB0LCB7XG4gICAgICAgICAgICAgICAgICAgIG91dGxpbmVXaWR0aDogMSxcbiAgICAgICAgICAgICAgICAgICAgc2NhbGU6IDAuODVcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIG91dGxpbmVXaWR0aDogMixcbiAgICAgICAgICAgICAgICAgICAgc2NhbGU6IDEsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjI1LFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcInNpbmVcIlxuICAgICAgICAgICAgICAgIH0sIDAuMTc1KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNjYWxlIGFuZCBmYWRlIGluIHRoZSBidXR0b24gY29udGFpbmVyc1xuICAgICAgICAgICAgaWYgKGNzcUJ1dHRvbkNvbnRhaW5lcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21Ubyhjc3FCdXR0b25Db250YWluZXJzLCB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlOiBjb25maWcuc2NhbGUsXG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAsXG4gICAgICAgICAgICAgICAgICAgIGZpbHRlcjogXCJibHVyKDI1cHgpXCJcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlOiAxLFxuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxLFxuICAgICAgICAgICAgICAgICAgICBmaWx0ZXI6IFwiYmx1cigwcHgpXCIsXG4gICAgICAgICAgICAgICAgICAgIHN0YWdnZXI6IGNvbmZpZy5zdGFnZ2VyLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBgJHtjb25maWcuZWFzZX0uaW5PdXQoJHtjb25maWcuZWFzZVN0cmVuZ3RofSlgXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGw7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHRzOiB7XG4gICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgc2NhbGU6IDEuNSxcbiAgICAgICAgICAgIHN0YWdnZXI6IDAuMDUsXG4gICAgICAgICAgICBlYXNlOiBcInNpbmVcIixcbiAgICAgICAgICAgIGVhc2VTdHJlbmd0aDogMS41XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGNzcUVudGVyUmlnaHQ6IHtcbiAgICAgICAgZWZmZWN0OiAoY3NxQ29udGFpbmVyKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjc3FSb290ID0gVS5nc2FwLnV0aWxzLnNlbGVjdG9yKGNzcUNvbnRhaW5lcik7XG4gICAgICAgICAgICBjb25zdCB0eXBlTGluZSA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtdHlwZS1jb250YWluZXIgLmNvbnNlcXVlbmNlLXR5cGUuYWNjZXB0LWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgY29uc3QgdHlwZUxpbmVCZyA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtdHlwZS1jb250YWluZXIgLmNvbnNlcXVlbmNlLXR5cGUtYmcuYWNjZXB0LWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgY29uc3QgYnV0dG9uUm9vdCA9IFUuZ3NhcC51dGlscy5zZWxlY3Rvcihjc3FSb290KFwiLmNvbnNlcXVlbmNlLWJ1dHRvbi1jb250YWluZXIuY29uc2VxdWVuY2UtYWNjZXB0LWJ1dHRvbi1jb250YWluZXJcIikpO1xuICAgICAgICAgICAgY29uc3QgYnV0dG9uQmcgPSBidXR0b25Sb290KFwiLmNvbnNlcXVlbmNlLWJ1dHRvbi1iZ1wiKTtcbiAgICAgICAgICAgIGNvbnN0IGJ1dHRvbkljb24gPSBidXR0b25Sb290KFwiLmJ1dHRvbi1pY29uIGlcIik7XG4gICAgICAgICAgICBjb25zdCBidXR0b25MYWJlbCA9IGJ1dHRvblJvb3QoXCIuY29uc2VxdWVuY2UtYnV0dG9uLWxhYmVsXCIpO1xuICAgICAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoeyBwYXVzZWQ6IHRydWUsIGRlZmF1bHRzOiB7fSB9KTtcbiAgICAgICAgICAgIC8vIFR1cm4gdHlwZSBsaW5lIHdoaXRlXG4gICAgICAgICAgICBpZiAodHlwZUxpbmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21Ubyh0eXBlTGluZSwge1xuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuUkVEXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuV0hJVEUsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZS5pbk91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBTbGlkZSB0eXBlIGxpbmUgYmFja2dyb3VuZCBvdXQgZnJvbSB1bmRlciBpY29uXG4gICAgICAgICAgICBpZiAodHlwZUxpbmVCZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKHR5cGVMaW5lQmcsIHtcbiAgICAgICAgICAgICAgICAgICAgeDogNSxcbiAgICAgICAgICAgICAgICAgICAgc2NhbGVYOiAwLFxuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuUkVELFxuICAgICAgICAgICAgICAgICAgICBza2V3WDogMFxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgc2NhbGVYOiAxLFxuICAgICAgICAgICAgICAgICAgICBza2V3WDogLTQ1LFxuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuUkVELFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC41LFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcImJhY2sub3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNsaWRlIGFjY2VwdCBidXR0b24gYmFja2dyb3VuZCBvdXQgZnJvbSB1bmRlciBpY29uXG4gICAgICAgICAgICBpZiAoYnV0dG9uQmcubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21UbyhidXR0b25CZywge1xuICAgICAgICAgICAgICAgICAgICBzY2FsZVg6IDAsXG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBDLkNvbG9ycy5SRUQsXG4gICAgICAgICAgICAgICAgICAgIHNrZXdYOiAwXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICB4OiAwLFxuICAgICAgICAgICAgICAgICAgICBzY2FsZVg6IDEsXG4gICAgICAgICAgICAgICAgICAgIHNrZXdYOiAtNDUsXG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBDLkNvbG9ycy5SRUQsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjI1LFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcImJhY2sub3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFR1cm4gYnV0dG9uIGljb24gYmxhY2sgYW5kIHNjYWxlXG4gICAgICAgICAgICBpZiAoYnV0dG9uSWNvbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGJ1dHRvbkljb24sIHtcbiAgICAgICAgICAgICAgICAgICAgY29sb3I6IEMuQ29sb3JzLkdSRVksXG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAuNzUsXG4gICAgICAgICAgICAgICAgICAgIHNjYWxlOiAxXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuZEJMQUNLLFxuICAgICAgICAgICAgICAgICAgICBzY2FsZTogMS4yNSxcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lXCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFR1cm4gYnV0dG9uIGxhYmVsIGJsYWNrLCBhZGQgbGV0dGVyLXNwYWNpbmcsIGJvbGRcbiAgICAgICAgICAgIGlmIChidXR0b25MYWJlbC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGJ1dHRvbkxhYmVsLCB7XG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBDLkNvbG9ycy5HUkVZLFxuICAgICAgICAgICAgICAgICAgICBmb250V2VpZ2h0OiA0MDAsXG4gICAgICAgICAgICAgICAgICAgIHNjYWxlOiAxXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuZEJMQUNLLFxuICAgICAgICAgICAgICAgICAgICBmb250V2VpZ2h0OiA4MDAsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjc1LFxuICAgICAgICAgICAgICAgICAgICBlYXNlOiBcInNpbmVcIlxuICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRsO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0czoge31cbiAgICB9LFxuICAgIGNzcUVudGVyTGVmdDoge1xuICAgICAgICBlZmZlY3Q6IChjc3FDb250YWluZXIpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGNzcVJvb3QgPSBVLmdzYXAudXRpbHMuc2VsZWN0b3IoY3NxQ29udGFpbmVyKTtcbiAgICAgICAgICAgIGNvbnN0IHR5cGVMaW5lID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS10eXBlLWNvbnRhaW5lciAuY29uc2VxdWVuY2UtdHlwZS5hY2NlcHQtY29uc2VxdWVuY2VcIik7XG4gICAgICAgICAgICBjb25zdCBuYW1lTGluZSA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtbmFtZS1jb250YWluZXIgLmNvbnNlcXVlbmNlLW5hbWUuYWNjZXB0LWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgY29uc3QgYWNjZXB0SWNvbkNpcmNsZSA9IGNzcVJvb3QoXCIuY29uc2VxdWVuY2UtaWNvbi1jaXJjbGUuYWNjZXB0LWNvbnNlcXVlbmNlXCIpO1xuICAgICAgICAgICAgY29uc3QgYWNjZXB0QnV0dG9uID0gY3NxUm9vdChcIi5jb25zZXF1ZW5jZS1idXR0b24tY29udGFpbmVyLmNvbnNlcXVlbmNlLWFjY2VwdC1idXR0b24tY29udGFpbmVyXCIpO1xuICAgICAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoeyBwYXVzZWQ6IHRydWUsIGRlZmF1bHRzOiB7fSB9KTtcbiAgICAgICAgICAgIC8vIEZhZGUgb3V0IHR5cGUgbGluZVxuICAgICAgICAgICAgaWYgKHR5cGVMaW5lLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB0bC50byh0eXBlTGluZSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4xNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lLmluT3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZhZGUgb3V0IG5hbWVcbiAgICAgICAgICAgIGlmIChuYW1lTGluZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwudG8obmFtZUxpbmUsIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuMTUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZS5pbk91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGYWRlIG91dCBpY29uXG4gICAgICAgICAgICBpZiAoYWNjZXB0SWNvbkNpcmNsZS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwudG8oYWNjZXB0SWNvbkNpcmNsZSwge1xuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAwLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogMC4xNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lLmluT3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEZhZGUgb3V0IGFjY2VwdCBidXR0b25cbiAgICAgICAgICAgIGlmIChhY2NlcHRCdXR0b24ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21UbyhhY2NlcHRCdXR0b24sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMVxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMCxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuMjUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZS5pbk91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGw7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHRzOiB7fVxuICAgIH0sXG4gICAgY3NxRW50ZXJTdWJMZWZ0OiB7XG4gICAgICAgIGVmZmVjdDogKGNzcUNvbnRhaW5lciwgY29uZmlnKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBjc3FSb290ID0gVS5nc2FwLnV0aWxzLnNlbGVjdG9yKGNzcUNvbnRhaW5lcik7XG4gICAgICAgICAgICBjb25zdCBpY29uQ2lyY2xlID0gY3NxUm9vdChgLmNvbnNlcXVlbmNlLWljb24tY2lyY2xlLiR7Y29uZmlnLnR5cGV9LWNvbnNlcXVlbmNlYCk7XG4gICAgICAgICAgICBjb25zdCB0eXBlTGluZSA9IGNzcVJvb3QoYC5jb25zZXF1ZW5jZS10eXBlLWNvbnRhaW5lciAuY29uc2VxdWVuY2UtdHlwZS4ke2NvbmZpZy50eXBlfS1jb25zZXF1ZW5jZWApO1xuICAgICAgICAgICAgY29uc3QgbmFtZUxpbmUgPSBjc3FSb290KGAuY29uc2VxdWVuY2UtbmFtZS4ke2NvbmZpZy50eXBlfS1jb25zZXF1ZW5jZWApO1xuICAgICAgICAgICAgY29uc3QgZm9vdGVyQmcgPSBjc3FSb290KGAuY29uc2VxdWVuY2UtZm9vdGVyLWNvbnRhaW5lciAuY29uc2VxdWVuY2UtZm9vdGVyLWJnLiR7Y29uZmlnLnR5cGV9LWNvbnNlcXVlbmNlYCk7XG4gICAgICAgICAgICBjb25zdCBzcGVjaWFsRm9vdGVyTXNnID0gY3NxUm9vdChgLmNvbnNlcXVlbmNlLWZvb3Rlci1jb250YWluZXIgLmNvbnNlcXVlbmNlLWZvb3Rlci1tZXNzYWdlLiR7Y29uZmlnLnR5cGV9LWNvbnNlcXVlbmNlYCk7XG4gICAgICAgICAgICBjb25zdCB0bCA9IFUuZ3NhcC50aW1lbGluZSh7IHBhdXNlZDogdHJ1ZSwgZGVmYXVsdHM6IHt9IH0pO1xuICAgICAgICAgICAgLy8gRmFkZSBpbiBpY29uIGNpcmNsZVxuICAgICAgICAgICAgaWYgKGljb25DaXJjbGUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21UbyhpY29uQ2lyY2xlLCB7XG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDBcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwiYmFjay5vdXRcIlxuICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRmFkZSBpbiB0eXBlTGluZVxuICAgICAgICAgICAgaWYgKHR5cGVMaW5lLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICB0bC5mcm9tVG8odHlwZUxpbmUsIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMFxuICAgICAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrLm91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBTbGlkZSBvdXQgbmFtZUxpbmUgZnJvbSBsZWZ0XG4gICAgICAgICAgICBpZiAobmFtZUxpbmUubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIHRsLmZyb21UbyhuYW1lTGluZSwge1xuICAgICAgICAgICAgICAgICAgICBzY2FsZVg6IDBcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlWDogMSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrLmluT3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNsaWRlIG91dCBmb290ZXIgYmFja2dyb3VuZCBmcm9tIGxlZnRcbiAgICAgICAgICAgIGlmIChmb290ZXJCZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKGZvb3RlckJnLCB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlWDogMCxcbiAgICAgICAgICAgICAgICAgICAgc2tld1g6IDAsXG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDFcbiAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgIHNjYWxlWDogMSxcbiAgICAgICAgICAgICAgICAgICAgc2tld1g6IC00NSxcbiAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgZWFzZTogXCJiYWNrLmluT3V0XCJcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFNsaWRlIG91dCBhdHRyaWJ1dGUgZnJvbSBsZWZ0XG4gICAgICAgICAgICBpZiAoc3BlY2lhbEZvb3Rlck1zZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdGwuZnJvbVRvKHNwZWNpYWxGb290ZXJNc2csIHtcbiAgICAgICAgICAgICAgICAgICAgc2NhbGVYOiAwLFxuICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxXG4gICAgICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgICAgICBzY2FsZVg6IDEsXG4gICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDEsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgICAgIGVhc2U6IFwiYmFjay5pbk91dFwiXG4gICAgICAgICAgICAgICAgfSwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY3NxUm9vdChgLmNvbnNlcXVlbmNlLWJ1dHRvbi1jb250YWluZXIuY29uc2VxdWVuY2UtJHtjb25maWcudHlwZX0tYnV0dG9uLWNvbnRhaW5lcmApLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICBjb25zdCBidXR0b25Sb290ID0gVS5nc2FwLnV0aWxzLnNlbGVjdG9yKGNzcVJvb3QoYC5jb25zZXF1ZW5jZS1idXR0b24tY29udGFpbmVyLmNvbnNlcXVlbmNlLSR7Y29uZmlnLnR5cGV9LWJ1dHRvbi1jb250YWluZXJgKSk7XG4gICAgICAgICAgICAgICAgY29uc3QgYnV0dG9uQmcgPSBidXR0b25Sb290KFwiLmNvbnNlcXVlbmNlLWJ1dHRvbi1iZ1wiKTtcbiAgICAgICAgICAgICAgICBjb25zdCBidXR0b25JY29uID0gYnV0dG9uUm9vdChcIi5idXR0b24taWNvbiBpXCIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGJ1dHRvbkxhYmVsID0gYnV0dG9uUm9vdChcIi5jb25zZXF1ZW5jZS1idXR0b24tbGFiZWxcIik7XG4gICAgICAgICAgICAgICAgLy8gU2xpZGUgb3V0IGJ1dHRvbiBiYWNrZ3JvdW5kIGZyb20gcmlnaHRcbiAgICAgICAgICAgICAgICBpZiAoYnV0dG9uQmcubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB0bC5mcm9tVG8oYnV0dG9uQmcsIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNjYWxlWDogMCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNrZXdYOiAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMVxuICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZVg6IDEsXG4gICAgICAgICAgICAgICAgICAgICAgICBza2V3WDogLTQ1LFxuICAgICAgICAgICAgICAgICAgICAgICAgb3BhY2l0eTogMSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICAgICAgICAgICAgICBlYXNlOiBcImJhY2suaW5PdXRcIlxuICAgICAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gVHVybiBidXR0b24gaWNvbiBibGFjayBhbmQgc2NhbGVcbiAgICAgICAgICAgICAgICBpZiAoYnV0dG9uSWNvbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRsLmZyb21UbyhidXR0b25JY29uLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuR1JFWSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wYWNpdHk6IDAuNzUsXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZTogMVxuICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuZEJMQUNLLFxuICAgICAgICAgICAgICAgICAgICAgICAgc2NhbGU6IDEuMjUsXG4gICAgICAgICAgICAgICAgICAgICAgICBvcGFjaXR5OiAxLFxuICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVhc2U6IFwic2luZVwiXG4gICAgICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBUdXJuIGJ1dHRvbiBsYWJlbCBibGFjaywgYm9sZFxuICAgICAgICAgICAgICAgIGlmIChidXR0b25MYWJlbC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHRsLmZyb21UbyhidXR0b25MYWJlbCwge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29sb3I6IEMuQ29sb3JzLkdSRVksXG4gICAgICAgICAgICAgICAgICAgICAgICBmb250V2VpZ2h0OiA0MDAsXG4gICAgICAgICAgICAgICAgICAgICAgICBzY2FsZTogMVxuICAgICAgICAgICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2xvcjogQy5Db2xvcnMuZEJMQUNLLFxuICAgICAgICAgICAgICAgICAgICAgICAgZm9udFdlaWdodDogODAwLFxuICAgICAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IDAuNzUsXG4gICAgICAgICAgICAgICAgICAgICAgICBlYXNlOiBcInNpbmVcIlxuICAgICAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdGw7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHRzOiB7fVxuICAgIH0sXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gQ0hBUkFDVEVSIFNIRUVUIEVGRkVDVFNcbiAgICBmaWxsQ29pbnM6IHtcbiAgICAgICAgZWZmZWN0OiAodGFyZ2V0cywgY29uZmlnKSA9PiB7XG4gICAgICAgICAgICAvLyBUYXJnZXRzIHdpbGwgYmUgYWxsIGNvaW5zIGZyb20gemVybyB0byB3aGVyZSBmaWxsIGN1cnJlbnRseSBpc1xuICAgICAgICAgICAgLy8gU29tZSB3aWxsIGFscmVhZHkgYmUgZnVsbCwgb3RoZXJzIG5vdC5cbiAgICAgICAgICAgIC8vIFN0YWdnZXIgaW4gdGltZWxpbmVcbiAgICAgICAgICAgIC8vIFB1bHNlIGluIHNpemUgYW5kIGNvbG9yXG4gICAgICAgICAgICAvLyBTaGltbWVyIGFzIHRoZXkgc2hyaW5rIGJhY2sgP1xuICAgICAgICAgICAgcmV0dXJuIFUuZ3NhcC50byh0YXJnZXRzLCB7XG4gICAgICAgICAgICAgICAgZHVyYXRpb246IGNvbmZpZy5kdXJhdGlvbiAvIDIsXG4gICAgICAgICAgICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZSxcbiAgICAgICAgICAgICAgICBmaWx0ZXI6IGNvbmZpZy5maWx0ZXIsXG4gICAgICAgICAgICAgICAgZWFzZTogY29uZmlnLmVhc2UsXG4gICAgICAgICAgICAgICAgc3RhZ2dlcjoge1xuICAgICAgICAgICAgICAgICAgICBhbW91bnQ6IDAuMjUsXG4gICAgICAgICAgICAgICAgICAgIGZyb206IFwic3RhcnRcIixcbiAgICAgICAgICAgICAgICAgICAgcmVwZWF0OiAxLFxuICAgICAgICAgICAgICAgICAgICB5b3lvOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHRzOiB7XG4gICAgICAgICAgICBkdXJhdGlvbjogMSxcbiAgICAgICAgICAgIHNjYWxlOiAxLFxuICAgICAgICAgICAgZmlsdGVyOiBcInNhdHVyYXRlKDEpIGJyaWdodG5lc3MoMilcIixcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIyLmluXCJcbiAgICAgICAgfSxcbiAgICAgICAgZXh0ZW5kVGltZWxpbmU6IHRydWVcbiAgICB9LFxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEdFTkVSQUw6ICdibHVyUmVtb3ZlJywgJ2hvdmVyVG9vbHRpcCcsICd0ZXh0Sml0dGVyJ1xuICAgIGJsdXJSZW1vdmU6IHtcbiAgICAgICAgZWZmZWN0OiAodGFyZ2V0cywgY29uZmlnKSA9PiBVLmdzYXAudGltZWxpbmUoeyBzdGFnZ2VyOiBjb25maWcuc3RhZ2dlciB9KVxuICAgICAgICAgICAgLnRvKHRhcmdldHMsIHtcbiAgICAgICAgICAgIHNrZXdYOiBjb25maWcuc2tld1gsXG4gICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uIC8gMixcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXI0Lm91dFwiXG4gICAgICAgIH0pXG4gICAgICAgICAgICAudG8odGFyZ2V0cywge1xuICAgICAgICAgICAgeDogY29uZmlnLngsXG4gICAgICAgICAgICBtYXJnaW5Cb3R0b206IGNvbmZpZy5pZ25vcmVNYXJnaW5cbiAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIDogZnVuY3Rpb24gKGksIHRhcmdldCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gVS5nZXQodGFyZ2V0LCBcImhlaWdodFwiKSAqIC0xO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBtYXJnaW5SaWdodDogY29uZmlnLmlnbm9yZU1hcmdpblxuICAgICAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgOiBmdW5jdGlvbiAoaSwgdGFyZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBVLmdldCh0YXJnZXQsIFwid2lkdGhcIikgKiAtMTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZSxcbiAgICAgICAgICAgIGZpbHRlcjogYGJsdXIoJHtjb25maWcuYmx1cn1weClgLFxuICAgICAgICAgICAgZHVyYXRpb246ICgzIC8gNCkgKiBjb25maWcuZHVyYXRpb25cbiAgICAgICAgfSwgY29uZmlnLmR1cmF0aW9uIC8gNClcbiAgICAgICAgICAgIC50byh0YXJnZXRzLCB7XG4gICAgICAgICAgICBhdXRvQWxwaGE6IDAsXG4gICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uIC8gMixcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIzLmluXCJcbiAgICAgICAgfSwgY29uZmlnLmR1cmF0aW9uIC8gMiksXG4gICAgICAgIGRlZmF1bHRzOiB7XG4gICAgICAgICAgICBpZ25vcmVNYXJnaW46IGZhbHNlLFxuICAgICAgICAgICAgc2tld1g6IC0yMCxcbiAgICAgICAgICAgIGR1cmF0aW9uOiAwLjUsXG4gICAgICAgICAgICB4OiBcIis9MzAwXCIsXG4gICAgICAgICAgICBzY2FsZTogMS41LFxuICAgICAgICAgICAgYmx1cjogMTAsXG4gICAgICAgICAgICBzdGFnZ2VyOiAwXG4gICAgICAgIH0sXG4gICAgICAgIGV4dGVuZFRpbWVsaW5lOiB0cnVlXG4gICAgfSxcbiAgICBibHVyUmV2ZWFsOiB7XG4gICAgICAgIGVmZmVjdDogKHRhcmdldHMsIGNvbmZpZykgPT4gVS5nc2FwLnRpbWVsaW5lKClcbiAgICAgICAgICAgIC5mcm9tVG8odGFyZ2V0cywge1xuICAgICAgICAgICAgeDogY29uZmlnLngsXG4gICAgICAgICAgICBtYXJnaW5Cb3R0b206IGNvbmZpZy5pZ25vcmVNYXJnaW5cbiAgICAgICAgICAgICAgICA/IHVuZGVmaW5lZFxuICAgICAgICAgICAgICAgIDogZnVuY3Rpb24gKGksIHRhcmdldCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gVS5nZXQodGFyZ2V0LCBcImhlaWdodFwiKSAqIC0xO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBtYXJnaW5SaWdodDogY29uZmlnLmlnbm9yZU1hcmdpblxuICAgICAgICAgICAgICAgID8gdW5kZWZpbmVkXG4gICAgICAgICAgICAgICAgOiBmdW5jdGlvbiAoaSwgdGFyZ2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBVLmdldCh0YXJnZXQsIFwid2lkdGhcIikgKiAtMTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZSxcbiAgICAgICAgICAgIGZpbHRlcjogYGJsdXIoJHtjb25maWcuYmx1cn1weClgXG4gICAgICAgIH0sIHtcbiAgICAgICAgICAgIHg6IDAsXG4gICAgICAgICAgICBtYXJnaW5Cb3R0b206IDAsXG4gICAgICAgICAgICBtYXJnaW5SaWdodDogMCxcbiAgICAgICAgICAgIHNjYWxlOiAxLFxuICAgICAgICAgICAgZmlsdGVyOiBcImJsdXIoMHB4KVwiLFxuICAgICAgICAgICAgZHVyYXRpb246ICgzIC8gNCkgKiBjb25maWcuZHVyYXRpb25cbiAgICAgICAgfSwgMClcbiAgICAgICAgICAgIC5mcm9tVG8odGFyZ2V0cywge1xuICAgICAgICAgICAgYXV0b0FscGhhOiAwXG4gICAgICAgIH0sIHtcbiAgICAgICAgICAgIGF1dG9BbHBoYTogMSxcbiAgICAgICAgICAgIGR1cmF0aW9uOiBjb25maWcuZHVyYXRpb24gLyAyLFxuICAgICAgICAgICAgZWFzZTogXCJwb3dlcjMuaW5cIlxuICAgICAgICB9LCAwKVxuICAgICAgICAgICAgLmZyb21Ubyh0YXJnZXRzLCB7XG4gICAgICAgICAgICBza2V3WDogY29uZmlnLnNrZXdYXG4gICAgICAgIH0sIHtcbiAgICAgICAgICAgIHNrZXdYOiAwLFxuICAgICAgICAgICAgZHVyYXRpb246IGNvbmZpZy5kdXJhdGlvbiAvIDIsXG4gICAgICAgICAgICBlYXNlOiBcInBvd2VyNC5vdXRcIlxuICAgICAgICB9LCBjb25maWcuZHVyYXRpb24gLyAyKSxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIGlnbm9yZU1hcmdpbjogZmFsc2UsXG4gICAgICAgICAgICBza2V3WDogLTIwLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIHg6IFwiKz0zMDBcIixcbiAgICAgICAgICAgIHNjYWxlOiAxLjUsXG4gICAgICAgICAgICBibHVyOiAxMFxuICAgICAgICB9LFxuICAgICAgICBleHRlbmRUaW1lbGluZTogdHJ1ZVxuICAgIH0sXG4gICAgc2NhbGVVcFJldmVhbDoge1xuICAgICAgICBlZmZlY3Q6ICh0YXJnZXQsIGNvbmZpZykgPT4ge1xuICAgICAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoKVxuICAgICAgICAgICAgICAgIC5mcm9tVG8odGFyZ2V0LCB7XG4gICAgICAgICAgICAgICAgYXV0b0FscGhhOiAwLFxuICAgICAgICAgICAgICAgIHNjYWxlOiAwLjUgKiBjb25maWcuc2NhbGVcbiAgICAgICAgICAgIH0sIHtcbiAgICAgICAgICAgICAgICBhdXRvQWxwaGE6IDEsXG4gICAgICAgICAgICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgIGVhc2U6IGNvbmZpZy5lYXNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0bDtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHNjYWxlOiAxLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIyXCJcbiAgICAgICAgfSxcbiAgICAgICAgZXh0ZW5kVGltZWxpbmU6IHRydWVcbiAgICB9LFxuICAgIHNjYWxlRG93blJlbW92ZToge1xuICAgICAgICBlZmZlY3Q6ICh0YXJnZXQsIGNvbmZpZykgPT4ge1xuICAgICAgICAgICAgY29uc3QgdGwgPSBVLmdzYXAudGltZWxpbmUoKVxuICAgICAgICAgICAgICAgIC50byh0YXJnZXQsIHtcbiAgICAgICAgICAgICAgICBhdXRvQWxwaGE6IDAsXG4gICAgICAgICAgICAgICAgc2NhbGU6IDAuNSAqIGNvbmZpZy5zY2FsZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgIGVhc2U6IGNvbmZpZy5lYXNlXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0bDtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHNjYWxlOiAxLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuNSxcbiAgICAgICAgICAgIGVhc2U6IFwicG93ZXIyXCJcbiAgICAgICAgfSxcbiAgICAgICAgZXh0ZW5kVGltZWxpbmU6IHRydWVcbiAgICB9LFxuICAgIGJsdXJSZXZlYWxUb29sdGlwOiB7XG4gICAgICAgIGVmZmVjdDogKHRhcmdldCwgY29uZmlnKSA9PiB7XG4gICAgICAgICAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgYmx1clJldmVhbFRvb2x0aXAgZWZmZWN0OiB0b29sdGlwIGVsZW1lbnQgaXMgJHt0YXJnZXQgPT09IG51bGwgPyBcIm51bGxcIiA6IHR5cGVvZiB0YXJnZXR9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCB0b29sdGlwJCA9ICQodGFyZ2V0KTtcbiAgICAgICAgICAgIHJldHVybiBVLmdzYXAudGltZWxpbmUoe1xuICAgICAgICAgICAgICAgIHBhdXNlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBvblJldmVyc2VDb21wbGV0ZTogY29uZmlnLm9uUmV2ZXJzZUNvbXBsZXRlXG4gICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIC5mcm9tVG8odG9vbHRpcCQsIHtcbiAgICAgICAgICAgICAgICBmaWx0ZXI6IGBibHVyKCR7Y29uZmlnLmJsdXJTdHJlbmd0aH1weClgLFxuICAgICAgICAgICAgICAgIGF1dG9BbHBoYTogMCxcbiAgICAgICAgICAgICAgICB4UGVyY2VudDogNTAsXG4gICAgICAgICAgICAgICAgeVBlcmNlbnQ6IC0yMDAsXG4gICAgICAgICAgICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZVxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIGZpbHRlcjogXCJibHVyKDBweClcIixcbiAgICAgICAgICAgICAgICBhdXRvQWxwaGE6IDEsXG4gICAgICAgICAgICAgICAgeFBlcmNlbnQ6IC01MCxcbiAgICAgICAgICAgICAgICB5UGVyY2VudDogLTEwMCxcbiAgICAgICAgICAgICAgICBzY2FsZTogMSxcbiAgICAgICAgICAgICAgICBlYXNlOiBjb25maWcuZWFzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHNjYWxlOiAxLjUsXG4gICAgICAgICAgICBibHVyU3RyZW5ndGg6IDE1LFxuICAgICAgICAgICAgZWFzZTogXCJiYWNrLm91dFwiLFxuICAgICAgICAgICAgZHVyYXRpb246IDAuMjUsXG4gICAgICAgICAgICBvblJldmVyc2VDb21wbGV0ZTogdW5kZWZpbmVkXG4gICAgICAgIH0sXG4gICAgICAgIGV4dGVuZFRpbWVsaW5lOiB0cnVlXG4gICAgfSxcbiAgICB0ZXh0Sml0dGVyOiB7XG4gICAgICAgIGVmZmVjdDogKHRhcmdldCwgY29uZmlnKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBbdGFyZ2V0RWxlbV0gPSAkKHRhcmdldCk7XG4gICAgICAgICAgICBpZiAoIXRhcmdldEVsZW0pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJ0ZXh0Sml0dGVyIGVmZmVjdDogdGFyZ2V0IG5vdCBmb3VuZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNwbGl0ID0gbmV3IFNwbGl0VGV4dCh0YXJnZXRFbGVtLCB7IHR5cGU6IFwiY2hhcnNcIiB9KTtcbiAgICAgICAgICAgIHJldHVybiBVLmdzYXAudGltZWxpbmUoKVxuICAgICAgICAgICAgICAgIC50byh0YXJnZXRFbGVtLCB7XG4gICAgICAgICAgICAgICAgYXV0b0FscGhhOiAxLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBjb25maWcuZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgZWFzZTogXCJub25lXCJcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLmZyb21UbyhzcGxpdC5jaGFycywge1xuICAgICAgICAgICAgICAgIHk6IC1jb25maWcueUFtcFxuICAgICAgICAgICAgfSwge1xuICAgICAgICAgICAgICAgIHk6IGNvbmZpZy55QW1wLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiBjb25maWcuZHVyYXRpb24sXG4gICAgICAgICAgICAgICAgZWFzZTogXCJzaW5lLmluT3V0XCIsXG4gICAgICAgICAgICAgICAgc3RhZ2dlcjoge1xuICAgICAgICAgICAgICAgICAgICByZXBlYXQ6IC0xLFxuICAgICAgICAgICAgICAgICAgICB5b3lvOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBmcm9tOiBcInJhbmRvbVwiLFxuICAgICAgICAgICAgICAgICAgICBlYWNoOiBjb25maWcuc3RhZ2dlclxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sIDApXG4gICAgICAgICAgICAgICAgLmZyb21UbyhzcGxpdC5jaGFycywge1xuICAgICAgICAgICAgICAgIHJvdGF0ZVo6IC1jb25maWcucm90YXRlQW1wXG4gICAgICAgICAgICB9LCB7XG4gICAgICAgICAgICAgICAgcm90YXRlWjogY29uZmlnLnJvdGF0ZUFtcCxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogY29uZmlnLmR1cmF0aW9uLFxuICAgICAgICAgICAgICAgIGVhc2U6IEN1c3RvbVdpZ2dsZS5jcmVhdGUoXCJteVdpZ2dsZVwiLCB7IHdpZ2dsZXM6IDEwLCB0eXBlOiBcInJhbmRvbVwiIH0pLFxuICAgICAgICAgICAgICAgIHN0YWdnZXI6IHtcbiAgICAgICAgICAgICAgICAgICAgcmVwZWF0OiAtMSxcbiAgICAgICAgICAgICAgICAgICAgZnJvbTogXCJyYW5kb21cIixcbiAgICAgICAgICAgICAgICAgICAgeW95bzogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgZWFjaDogY29uZmlnLnN0YWdnZXJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdHM6IHtcbiAgICAgICAgICAgIHlBbXA6IDIsXG4gICAgICAgICAgICByb3RhdGVBbXA6IDIsXG4gICAgICAgICAgICBkdXJhdGlvbjogMSxcbiAgICAgICAgICAgIHN0YWdnZXI6IDAuMDVcbiAgICAgICAgfSxcbiAgICAgICAgZXh0ZW5kVGltZWxpbmU6IHRydWVcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxufTtcbi8qKlxuICogUmVnaXN0ZXJzIHJlbGV2YW50IEdTQVAgcGx1Z2lucyBhbmQgZWZmZWN0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIEluaXRpYWxpemUoKSB7XG4gICAgaWYgKGdzYXBQbHVnaW5zLmxlbmd0aCkge1xuICAgICAgICBVLmdzYXAuY29uZmlnKHtcbiAgICAgICAgICAgIG51bGxUYXJnZXRXYXJuOiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBVLmdzYXAucmVnaXN0ZXJQbHVnaW4oLi4uZ3NhcFBsdWdpbnMpO1xuICAgICAgICBPYmplY3QuYXNzaWduKGdsb2JhbFRoaXMsIHtcbiAgICAgICAgICAgIFRleHRQbHVnaW4sXG4gICAgICAgICAgICBGbGlwLFxuICAgICAgICAgICAgTW90aW9uUGF0aFBsdWdpbixcbiAgICAgICAgICAgIERyYWdnZXIsXG4gICAgICAgICAgICBTcGxpdFRleHQsXG4gICAgICAgICAgICBPYnNlcnZlcixcbiAgICAgICAgICAgIEN1c3RvbUVhc2UsXG4gICAgICAgICAgICBDdXN0b21XaWdnbGUsXG4gICAgICAgICAgICBDdXN0b21Cb3VuY2UsXG4gICAgICAgICAgICBFYXNlUGFja1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgT2JqZWN0LmVudHJpZXMoZ3NhcEVmZmVjdHMpLmZvckVhY2goKFtuYW1lLCBlZmZlY3RdKSA9PiB7XG4gICAgICAgIFUuZ3NhcC5yZWdpc3RlckVmZmVjdChPYmplY3QuYXNzaWduKGVmZmVjdCwgeyBuYW1lIH0pKTtcbiAgICB9KTtcbn1cbi8qKlxuICogQXBwbGllcyBsaXN0ZW5lcnMgdG8gJy50b29sdGlwLXRyaWdnZXInIGVsZW1lbnRzIGluIHRoZSBkb2N1bWVudC5cbiAqIEBwYXJhbSB7SlF1ZXJ5PEhUTUxFbGVtZW50Pn0gaHRtbCBUaGUgZG9jdW1lbnQgdG8gYmUgc2VhcmNoZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBBcHBseVRvb2x0aXBBbmltYXRpb25zKGh0bWwpIHtcbiAgICBodG1sLmZpbmQoXCIudG9vbHRpcC10cmlnZ2VyXCIpLmVhY2goKF8sIGVsKSA9PiB7XG4gICAgICAgIGNvbnN0IHRvb2x0aXBFbGVtID0gJChlbCkuZmluZChcIi50b29sdGlwXCIpWzBdID8/ICQoZWwpLm5leHQoXCIudG9vbHRpcFwiKVswXTtcbiAgICAgICAgaWYgKCF0b29sdGlwRWxlbSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHRvb2x0aXAkID0gJCh0b29sdGlwRWxlbSk7XG4gICAgICAgIC8qKlxuICAgICAgICAgKiBVc2UgdGhlIC50b29sdGlwLXRyaWdnZXIgZWxlbWVudCBhcyB0aGUgZGVmaW5pdGl2ZSBwb3NpdGlvbmluZyBlbGVtZW50IGZvciB0aGUgdG9vbHRpcCBpdHNlbGYuXG4gICAgICAgICAqIElmIHRoZSB0b29sdGlwLXRyaWdnZXIncyBhYnNvbHV0ZSBwb3NpdGlvbiByZWxhdGl2ZSB0byB0aGUgdmlld3BvcnQgaXMsIGUuZy4sIG5lYXIgdGhlIHRvcCxcbiAgICAgICAgICogdGhlbiB0aGUgdG9vbHRpcCBzaG91bGQgYXBwZWFyIGJlbmVhdGgsIGV0Y1xuICAgICAgICAgKi9cbiAgICAgICAgLy8gRmluZCB0aGUgdG9vbHRpcCdzIHBhcmVudCBjb250YWluZXIuIElmIGl0cyBwb3NpdGlvbiBpc24ndCByZWxhdGl2ZSBvciBhYnNvbHV0ZSwgc2V0IGl0IHRvIHJlbGF0aXZlLlxuICAgICAgICBjb25zdCB0b29sdGlwQ29udGFpbmVyJCA9IHRvb2x0aXAkLnBhcmVudCgpO1xuICAgICAgICBpZiAodG9vbHRpcENvbnRhaW5lciQuY3NzKFwicG9zaXRpb25cIikgIT09IFwicmVsYXRpdmVcIlxuICAgICAgICAgICAgJiYgdG9vbHRpcENvbnRhaW5lciQuY3NzKFwicG9zaXRpb25cIikgIT09IFwiYWJzb2x1dGVcIikge1xuICAgICAgICAgICAgdG9vbHRpcENvbnRhaW5lciQuY3NzKFwicG9zaXRpb25cIiwgXCJyZWxhdGl2ZVwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBTZXQgdGhlIHRvb2x0aXAgaXRzZWxmIHRvIGFic29sdXRlIHBvc2l0aW9uaW5nXG4gICAgICAgIHRvb2x0aXAkLmNzcyhcInBvc2l0aW9uXCIsIFwiYWJzb2x1dGVcIik7XG4gICAgICAgIC8vIEFzc2lnbiBhIHVuaXF1ZSBJRCB0byB0aGUgdG9vbHRpcCBlbGVtZW50XG4gICAgICAgIGNvbnN0IHRvb2x0aXBJRCA9IGB0b29sdGlwLSR7cmFuZG9tSUQoKX1gO1xuICAgICAgICB0b29sdGlwJC5hdHRyKFwiaWRcIiwgdG9vbHRpcElEKTtcbiAgICAgICAgLy8gRm9yIC50b29sdGlwLXdpZGUgdG9vbHRpcHMsIGFkanVzdCB0aGUgYXNwZWN0IHJhdGlvIGFjY29yZGluZ2x5XG4gICAgICAgIGlmICh0b29sdGlwJC5oYXNDbGFzcyhcInRvb2x0aXAtd2lkZVwiKSkge1xuICAgICAgICAgICAgVS5hZGp1c3RUZXh0Q29udGFpbmVyQXNwZWN0UmF0aW8odG9vbHRpcEVsZW0sIDYpO1xuICAgICAgICB9XG4gICAgICAgICQoZWwpLm9uKHtcbiAgICAgICAgICAgIG1vdXNlZW50ZXI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuZGlzcGxheVRvb2x0aXAodG9vbHRpcEVsZW0pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG1vdXNlbGVhdmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IuY2xlYXJUb29sdGlwKHRvb2x0aXBJRCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pO1xufVxuZXhwb3J0IHsgVGV4dFBsdWdpbiwgRmxpcCwgTW90aW9uUGF0aFBsdWdpbiwgRHJhZ2dlciwgU3BsaXRUZXh0LCBPYnNlcnZlciwgQ3VzdG9tRWFzZSwgQ3VzdG9tV2lnZ2xlLCBDdXN0b21Cb3VuY2UsIEVhc2VQYWNrIH07XG5leHBvcnQgZGVmYXVsdCBVLmdzYXA7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/core/gsap.ts\n"); + +/***/ }), + +/***/ "./ts/core/helpers.ts": +/*!****************************!*\ + !*** ./ts/core/helpers.ts ***! + \****************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ preloadHandlebarsTemplates: function() { return /* binding */ preloadHandlebarsTemplates; },\n/* harmony export */ registerHandlebarHelpers: function() { return /* binding */ registerHandlebarHelpers; }\n/* harmony export */ });\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~\n\n// #endregion ▮▮▮▮[IMPORTS]▮▮▮▮\n// #region ░░░░░░░[Templates]░░░░ Preload Partials, Components & Overlay Templates ░░░░░░░ ~\n/**\n * Define a set of template paths to pre-load\n * Pre-loaded templates are compiled and cached for fast access when rendering\n */\nasync function preloadHandlebarsTemplates() {\n // Define template paths to load\n const templatePaths = [\n // General Components\n \"systems/eunos-blades/templates/components/toggle-icon.hbs\",\n \"systems/eunos-blades/templates/components/button-icon.hbs\",\n \"systems/eunos-blades/templates/components/dotline.hbs\",\n \"systems/eunos-blades/templates/components/armor.hbs\",\n \"systems/eunos-blades/templates/components/comp.hbs\",\n \"systems/eunos-blades/templates/components/select.hbs\",\n \"systems/eunos-blades/templates/components/portrait.hbs\",\n \"systems/eunos-blades/templates/components/clock.hbs\",\n \"systems/eunos-blades/templates/components/roll-collab-mod.hbs\",\n \"systems/eunos-blades/templates/components/slide-out-controls.hbs\",\n \"systems/eunos-blades/templates/components/consequence.hbs\",\n \"systems/eunos-blades/templates/components/consequence-accepted.hbs\",\n // Partials\n \"systems/eunos-blades/templates/parts/tier-block.hbs\",\n \"systems/eunos-blades/templates/parts/turf-list.hbs\",\n \"systems/eunos-blades/templates/parts/cohort-block.hbs\",\n \"systems/eunos-blades/templates/parts/roll-opposition-creator.hbs\",\n \"systems/eunos-blades/templates/parts/active-effects.hbs\",\n \"systems/eunos-blades/templates/parts/gm-pc-summary.hbs\",\n \"systems/eunos-blades/templates/components/clock-key.hbs\"\n ];\n // Load the template parts\n return loadTemplates(templatePaths);\n}\n// #endregion ░░░░[Preload Templates]░░░░\n// #region ████████ Handlebars: Handlebar Helpers Definitions ████████ ~\nconst handlebarHelpers = {\n randString(param1 = 10) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].randString(param1);\n },\n test(param1, operator, param2) {\n const stringMap = {\n true: true,\n false: false,\n null: null,\n undefined\n };\n if ([\"!\", \"not\", \"=??\"].includes(String(param1))) {\n [operator, param1] = [String(param1), operator];\n }\n if (typeof param1 === \"string\" && param1 in stringMap) {\n param1 = stringMap[param1];\n }\n if (typeof param2 === \"string\" && param2 in stringMap) {\n param2 = stringMap[param2];\n }\n switch (operator) {\n case \"!\":\n case \"not\": {\n return !param1;\n }\n case \"=??\": {\n return [undefined, null].includes(param1);\n }\n case \"&&\": {\n return param1 && param2;\n }\n case \"||\": {\n return param1 || param2;\n }\n case \"==\": {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].areFuzzyEqual(param1, param2);\n }\n case \"===\": {\n return param1 === param2;\n }\n case \"!=\":\n case \"!==\": {\n return param1 !== param2;\n }\n case \">\": {\n return typeof param1 === \"number\" && typeof param2 === \"number\" && param1 > param2;\n }\n case \"<\": {\n return typeof param1 === \"number\" && typeof param2 === \"number\" && param1 < param2;\n }\n case \">=\": {\n return typeof param1 === \"number\" && typeof param2 === \"number\" && param1 >= param2;\n }\n case \"<=\": {\n return typeof param1 === \"number\" && typeof param2 === \"number\" && param1 <= param2;\n }\n case \"??\": {\n return param1 ?? param2;\n }\n case \"includes\": {\n return Array.isArray(param1) && param1.includes(param2);\n }\n case \"in\": {\n if (Array.isArray(param2)) {\n return param2.includes(param1);\n }\n if (_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(param2) && (typeof param1 === \"number\" || typeof param1 === \"string\")) {\n return param1 in param2;\n }\n if (typeof param2 === \"string\") {\n return new RegExp(String(param1), \"gu\").test(String(param2));\n }\n return false;\n }\n default: {\n return false;\n }\n }\n },\n calc(...params) {\n const calcs = {\n \"+\": (p1, p2) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1) + _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2),\n \"-\": (p1, p2) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1) - _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2),\n \"*\": (p1, p2) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1) * _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2),\n \"/\": (p1, p2) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1) / _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2),\n \"%\": (p1, p2) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1) % _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2),\n max: (p1, p2) => Math.max(_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1), _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2)),\n min: (p1, p2) => Math.min(_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p1), _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(p2)),\n ceil: (p1) => Math.ceil(_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pFloat(p1)),\n floor: (p1) => Math.floor(_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pFloat(p1))\n };\n const [param1, operator, param2] = typeof params[0] === \"string\" && params[0] in calcs\n ? [params[1], params[0]]\n : params;\n return calcs[operator](param1, param2);\n },\n isIn(...args) {\n const [testStr, ...contents] = args;\n return contents.includes(testStr);\n },\n case(mode, str) {\n switch (mode) {\n case \"upper\": return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].uCase(str);\n case \"lower\": return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(str);\n case \"sentence\": return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sCase(str);\n case \"title\": return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(str);\n default: return str;\n }\n },\n romanize(val) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(val));\n },\n count(param) {\n if (Array.isArray(param) || _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isList(param)) {\n return Object.values(param).filter((val) => val !== null && val !== undefined).length;\n }\n else if (typeof param === \"string\") {\n return param.length;\n }\n return param ? 1 : 0;\n },\n // Concat helper\n // Usage: (concat 'first 'second')\n concat(...args) {\n let outStr = \"\";\n for (const arg of args) {\n if (typeof arg === \"string\" || typeof arg === \"number\") {\n outStr += arg;\n }\n }\n return outStr;\n },\n // Merge helper - To merge additional properties into a template's context\n merge(context, ...args) {\n args.pop();\n return args.reduce((acc, val) => Object.assign(acc, val), context);\n },\n // For loop: {{#for [from = 0, to, stepSize = 1]}}{{/for}}\n for: (...args) => {\n const options = args.pop();\n let [from, to, stepSize] = args;\n from = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(from);\n to = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(to);\n stepSize = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(stepSize) || 1;\n if (from > to) {\n return \"\";\n }\n let html = \"\";\n for (let i = parseInt(from || 0, 10); i <= parseInt(to || 0, 10); i += stepSize) {\n html += options.fn(i);\n }\n return html;\n },\n signNum(num) {\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].signNum(num);\n },\n compileSvg(...args) {\n const [svgDotKey, svgPaths] = args;\n return _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getSvgCode(svgDotKey, svgPaths);\n },\n eLog(...args) {\n args.pop();\n let dbLevel = 3;\n if ([0, 1, 2, 3, 4, 5].includes(args[0])) {\n dbLevel = args.shift();\n }\n eLog.hbsLog(...args, dbLevel);\n },\n // Does the name of this turf block represent a standard 'Turf' claim?\n isTurfBlock: (name) => _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].fuzzyMatch(name, \"Turf\"),\n // Which other connection does this connector overlap with?\n getConnectorPartner: (index, direction) => {\n index = parseInt(`${index}`, 10);\n const partners = {\n 1: { right: 2, bottom: 6 },\n 2: { left: 1, right: 3, bottom: 7 },\n 3: { left: 2, right: 4, bottom: 8 },\n 4: { left: 3, right: 5, bottom: 9 },\n 5: { left: 4, bottom: 10 },\n 6: { top: 1, right: 7, bottom: 11 },\n 7: { top: 2, left: 6, right: 8, bottom: 12 },\n 8: { top: 3, left: 7, right: 9, bottom: 13 },\n 9: { top: 4, left: 8, right: 10, bottom: 14 },\n 10: { top: 5, left: 9, bottom: 15 },\n 11: { top: 6, right: 12 },\n 12: { top: 7, left: 11, right: 13 },\n 13: { top: 8, left: 12, right: 14 },\n 14: { top: 9, left: 13, right: 15 },\n 15: { top: 10, left: 14 }\n };\n const partnerDir = { left: \"right\", right: \"left\", top: \"bottom\", bottom: \"top\" }[direction];\n const partnerNum = partners[index][direction] ?? 0;\n if (partnerNum) {\n return `${partnerNum}-${partnerDir}`;\n }\n return null;\n },\n // Is the value Turf side.\n isTurfOnEdge: (index, direction) => {\n index = parseInt(`${index}`, 10);\n const edges = {\n 1: [\"top\", \"left\"],\n 2: [\"top\"],\n 3: [\"top\"],\n 4: [\"top\"],\n 5: [\"top\", \"right\"],\n 6: [\"left\"],\n 7: [],\n 8: [],\n 9: [],\n 10: [\"right\"],\n 11: [\"left\", \"bottom\"],\n 12: [\"bottom\"],\n 13: [\"bottom\"],\n 14: [\"bottom\"],\n 15: [\"right\", \"bottom\"]\n };\n if (!(index in edges)) {\n return true;\n }\n return edges[index].includes(direction);\n },\n // Multiboxes\n multiboxes(selected, options) {\n let html = options.fn(this);\n selected = [selected].flat(1);\n selected.forEach((selectedVal) => {\n if (selectedVal !== false) {\n const escapedValue = RegExp.escape(Handlebars.escapeExpression(String(selectedVal)));\n const rgx = new RegExp(` value=\"${escapedValue}\"`);\n html = html.replace(rgx, \"$& checked=\\\"checked\\\"\");\n }\n });\n return html;\n },\n repturf: (turfsAmount, options) => {\n let html = options.fn(undefined);\n let turfsAmountInt = parseInt(turfsAmount, 10);\n // Can't be more than 6.\n if (turfsAmountInt > 6) {\n turfsAmountInt = 6;\n }\n for (let i = 13 - turfsAmountInt; i <= 12; i++) {\n const rgx = new RegExp(` value=\"${i}\"`);\n html = html.replace(rgx, \"$& disabled=\\\"disabled\\\"\");\n }\n return html;\n }\n};\nhandlebarHelpers.eLog1 = function (...args) { handlebarHelpers.eLog(...[1, ...args.slice(0, 7)]); };\nhandlebarHelpers.eLog2 = function (...args) { handlebarHelpers.eLog(...[2, ...args.slice(0, 7)]); };\nhandlebarHelpers.eLog3 = function (...args) { handlebarHelpers.eLog(...[3, ...args.slice(0, 7)]); };\nhandlebarHelpers.eLog4 = function (...args) { handlebarHelpers.eLog(...[4, ...args.slice(0, 7)]); };\nhandlebarHelpers.eLog5 = function (...args) { handlebarHelpers.eLog(...[5, ...args.slice(0, 7)]); };\nObject.assign(handlebarHelpers);\n/**\n *\n */\nfunction registerHandlebarHelpers() {\n Object.entries(handlebarHelpers).forEach(([name, func]) => Handlebars.registerHelper(name, func));\n}\n// #endregion ▄▄▄▄▄ Handlebars ▄▄▄▄▄\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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LHVDQUF1QztBQUN4RCxpQkFBaUIsd0NBQXdDO0FBQ3pELGtCQUFrQiw2QkFBNkI7QUFDL0Msa0JBQWtCLG1CQUFtQjtBQUNyQyxrQkFBa0IsNkJBQTZCO0FBQy9DLGtCQUFrQiw2QkFBNkI7QUFDL0Msa0JBQWtCLDZCQUE2QjtBQUMvQyxrQkFBa0I7QUFDbEI7QUFDQSw2QkFBNkIsNERBQTREO0FBQ3pGO0FBQ0E7QUFDQSxzQkFBc0IsV0FBVyxHQUFHLFdBQVc7QUFDL0M7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsNEJBQTRCLE1BQU07QUFDbEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtELGFBQWE7QUFDL0Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTDtBQUNBLDhCQUE4QixTQUFJO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsU0FBUztBQUNuRCw4Q0FBOEMsRUFBRTtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDO0FBQzlDLDhDQUE4QztBQUM5Qyw4Q0FBOEM7QUFDOUMsOENBQThDO0FBQzlDLDhDQUE4QztBQUM5QztBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvY29yZS9oZWxwZXJzLnRzP2U1ZWEiXSwic291cmNlc0NvbnRlbnQiOlsiLy8gI3JlZ2lvbiDilq7ilq7ilq7ilq7ilq7ilq7ilq4gSU1QT1JUUyDilq7ilq7ilq7ilq7ilq7ilq7ilq4gflxuaW1wb3J0IFUgZnJvbSBcIi4vdXRpbGl0aWVzXCI7XG4vLyAjZW5kcmVnaW9uIOKWruKWruKWruKWrltJTVBPUlRTXeKWruKWruKWruKWrlxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbVGVtcGxhdGVzXeKWkeKWkeKWkeKWkSBQcmVsb2FkIFBhcnRpYWxzLCBDb21wb25lbnRzICYgT3ZlcmxheSBUZW1wbGF0ZXMg4paR4paR4paR4paR4paR4paR4paRIH5cbi8qKlxuICogRGVmaW5lIGEgc2V0IG9mIHRlbXBsYXRlIHBhdGhzIHRvIHByZS1sb2FkXG4gKiBQcmUtbG9hZGVkIHRlbXBsYXRlcyBhcmUgY29tcGlsZWQgYW5kIGNhY2hlZCBmb3IgZmFzdCBhY2Nlc3Mgd2hlbiByZW5kZXJpbmdcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHByZWxvYWRIYW5kbGViYXJzVGVtcGxhdGVzKCkge1xuICAgIC8vIERlZmluZSB0ZW1wbGF0ZSBwYXRocyB0byBsb2FkXG4gICAgY29uc3QgdGVtcGxhdGVQYXRocyA9IFtcbiAgICAgICAgLy8gR2VuZXJhbCBDb21wb25lbnRzXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NvbXBvbmVudHMvdG9nZ2xlLWljb24uaGJzXCIsXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NvbXBvbmVudHMvYnV0dG9uLWljb24uaGJzXCIsXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NvbXBvbmVudHMvZG90bGluZS5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9hcm1vci5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9jb21wLmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jb21wb25lbnRzL3NlbGVjdC5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9wb3J0cmFpdC5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9jbG9jay5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY29tcG9uZW50cy9yb2xsLWNvbGxhYi1tb2QuaGJzXCIsXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2NvbXBvbmVudHMvc2xpZGUtb3V0LWNvbnRyb2xzLmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jb21wb25lbnRzL2NvbnNlcXVlbmNlLmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jb21wb25lbnRzL2NvbnNlcXVlbmNlLWFjY2VwdGVkLmhic1wiLFxuICAgICAgICAvLyBQYXJ0aWFsc1xuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9wYXJ0cy90aWVyLWJsb2NrLmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9wYXJ0cy90dXJmLWxpc3QuaGJzXCIsXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3BhcnRzL2NvaG9ydC1ibG9jay5oYnNcIixcbiAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvcGFydHMvcm9sbC1vcHBvc2l0aW9uLWNyZWF0b3IuaGJzXCIsXG4gICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL3BhcnRzL2FjdGl2ZS1lZmZlY3RzLmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9wYXJ0cy9nbS1wYy1zdW1tYXJ5Lmhic1wiLFxuICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jb21wb25lbnRzL2Nsb2NrLWtleS5oYnNcIlxuICAgIF07XG4gICAgLy8gTG9hZCB0aGUgdGVtcGxhdGUgcGFydHNcbiAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyh0ZW1wbGF0ZVBhdGhzKTtcbn1cbi8vICNlbmRyZWdpb24g4paR4paR4paR4paRW1ByZWxvYWQgVGVtcGxhdGVzXeKWkeKWkeKWkeKWkVxuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggSGFuZGxlYmFyczogSGFuZGxlYmFyIEhlbHBlcnMgRGVmaW5pdGlvbnMg4paI4paI4paI4paI4paI4paI4paI4paIIH5cbmNvbnN0IGhhbmRsZWJhckhlbHBlcnMgPSB7XG4gICAgcmFuZFN0cmluZyhwYXJhbTEgPSAxMCkge1xuICAgICAgICByZXR1cm4gVS5yYW5kU3RyaW5nKHBhcmFtMSk7XG4gICAgfSxcbiAgICB0ZXN0KHBhcmFtMSwgb3BlcmF0b3IsIHBhcmFtMikge1xuICAgICAgICBjb25zdCBzdHJpbmdNYXAgPSB7XG4gICAgICAgICAgICB0cnVlOiB0cnVlLFxuICAgICAgICAgICAgZmFsc2U6IGZhbHNlLFxuICAgICAgICAgICAgbnVsbDogbnVsbCxcbiAgICAgICAgICAgIHVuZGVmaW5lZFxuICAgICAgICB9O1xuICAgICAgICBpZiAoW1wiIVwiLCBcIm5vdFwiLCBcIj0/P1wiXS5pbmNsdWRlcyhTdHJpbmcocGFyYW0xKSkpIHtcbiAgICAgICAgICAgIFtvcGVyYXRvciwgcGFyYW0xXSA9IFtTdHJpbmcocGFyYW0xKSwgb3BlcmF0b3JdO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW0xID09PSBcInN0cmluZ1wiICYmIHBhcmFtMSBpbiBzdHJpbmdNYXApIHtcbiAgICAgICAgICAgIHBhcmFtMSA9IHN0cmluZ01hcFtwYXJhbTFdO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2YgcGFyYW0yID09PSBcInN0cmluZ1wiICYmIHBhcmFtMiBpbiBzdHJpbmdNYXApIHtcbiAgICAgICAgICAgIHBhcmFtMiA9IHN0cmluZ01hcFtwYXJhbTJdO1xuICAgICAgICB9XG4gICAgICAgIHN3aXRjaCAob3BlcmF0b3IpIHtcbiAgICAgICAgICAgIGNhc2UgXCIhXCI6XG4gICAgICAgICAgICBjYXNlIFwibm90XCI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gIXBhcmFtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCI9Pz9cIjoge1xuICAgICAgICAgICAgICAgIHJldHVybiBbdW5kZWZpbmVkLCBudWxsXS5pbmNsdWRlcyhwYXJhbTEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBcIiYmXCI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcGFyYW0xICYmIHBhcmFtMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCJ8fFwiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHBhcmFtMSB8fCBwYXJhbTI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiPT1cIjoge1xuICAgICAgICAgICAgICAgIHJldHVybiBVLmFyZUZ1enp5RXF1YWwocGFyYW0xLCBwYXJhbTIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBcIj09PVwiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHBhcmFtMSA9PT0gcGFyYW0yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBcIiE9XCI6XG4gICAgICAgICAgICBjYXNlIFwiIT09XCI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcGFyYW0xICE9PSBwYXJhbTI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiPlwiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBwYXJhbTEgPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIHBhcmFtMiA9PT0gXCJudW1iZXJcIiAmJiBwYXJhbTEgPiBwYXJhbTI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiPFwiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBwYXJhbTEgPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIHBhcmFtMiA9PT0gXCJudW1iZXJcIiAmJiBwYXJhbTEgPCBwYXJhbTI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIFwiPj1cIjoge1xuICAgICAgICAgICAgICAgIHJldHVybiB0eXBlb2YgcGFyYW0xID09PSBcIm51bWJlclwiICYmIHR5cGVvZiBwYXJhbTIgPT09IFwibnVtYmVyXCIgJiYgcGFyYW0xID49IHBhcmFtMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCI8PVwiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHR5cGVvZiBwYXJhbTEgPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIHBhcmFtMiA9PT0gXCJudW1iZXJcIiAmJiBwYXJhbTEgPD0gcGFyYW0yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBcIj8/XCI6IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gcGFyYW0xID8/IHBhcmFtMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCJpbmNsdWRlc1wiOiB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEFycmF5LmlzQXJyYXkocGFyYW0xKSAmJiBwYXJhbTEuaW5jbHVkZXMocGFyYW0yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgXCJpblwiOiB7XG4gICAgICAgICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGFyYW0yKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gcGFyYW0yLmluY2x1ZGVzKHBhcmFtMSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChVLmlzTGlzdChwYXJhbTIpICYmICh0eXBlb2YgcGFyYW0xID09PSBcIm51bWJlclwiIHx8IHR5cGVvZiBwYXJhbTEgPT09IFwic3RyaW5nXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJhbTEgaW4gcGFyYW0yO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHBhcmFtMiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IFJlZ0V4cChTdHJpbmcocGFyYW0xKSwgXCJndVwiKS50ZXN0KFN0cmluZyhwYXJhbTIpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGVmYXVsdDoge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgY2FsYyguLi5wYXJhbXMpIHtcbiAgICAgICAgY29uc3QgY2FsY3MgPSB7XG4gICAgICAgICAgICBcIitcIjogKHAxLCBwMikgPT4gVS5wSW50KHAxKSArIFUucEludChwMiksXG4gICAgICAgICAgICBcIi1cIjogKHAxLCBwMikgPT4gVS5wSW50KHAxKSAtIFUucEludChwMiksXG4gICAgICAgICAgICBcIipcIjogKHAxLCBwMikgPT4gVS5wSW50KHAxKSAqIFUucEludChwMiksXG4gICAgICAgICAgICBcIi9cIjogKHAxLCBwMikgPT4gVS5wSW50KHAxKSAvIFUucEludChwMiksXG4gICAgICAgICAgICBcIiVcIjogKHAxLCBwMikgPT4gVS5wSW50KHAxKSAlIFUucEludChwMiksXG4gICAgICAgICAgICBtYXg6IChwMSwgcDIpID0+IE1hdGgubWF4KFUucEludChwMSksIFUucEludChwMikpLFxuICAgICAgICAgICAgbWluOiAocDEsIHAyKSA9PiBNYXRoLm1pbihVLnBJbnQocDEpLCBVLnBJbnQocDIpKSxcbiAgICAgICAgICAgIGNlaWw6IChwMSkgPT4gTWF0aC5jZWlsKFUucEZsb2F0KHAxKSksXG4gICAgICAgICAgICBmbG9vcjogKHAxKSA9PiBNYXRoLmZsb29yKFUucEZsb2F0KHAxKSlcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgW3BhcmFtMSwgb3BlcmF0b3IsIHBhcmFtMl0gPSB0eXBlb2YgcGFyYW1zWzBdID09PSBcInN0cmluZ1wiICYmIHBhcmFtc1swXSBpbiBjYWxjc1xuICAgICAgICAgICAgPyBbcGFyYW1zWzFdLCBwYXJhbXNbMF1dXG4gICAgICAgICAgICA6IHBhcmFtcztcbiAgICAgICAgcmV0dXJuIGNhbGNzW29wZXJhdG9yXShwYXJhbTEsIHBhcmFtMik7XG4gICAgfSxcbiAgICBpc0luKC4uLmFyZ3MpIHtcbiAgICAgICAgY29uc3QgW3Rlc3RTdHIsIC4uLmNvbnRlbnRzXSA9IGFyZ3M7XG4gICAgICAgIHJldHVybiBjb250ZW50cy5pbmNsdWRlcyh0ZXN0U3RyKTtcbiAgICB9LFxuICAgIGNhc2UobW9kZSwgc3RyKSB7XG4gICAgICAgIHN3aXRjaCAobW9kZSkge1xuICAgICAgICAgICAgY2FzZSBcInVwcGVyXCI6IHJldHVybiBVLnVDYXNlKHN0cik7XG4gICAgICAgICAgICBjYXNlIFwibG93ZXJcIjogcmV0dXJuIFUubENhc2Uoc3RyKTtcbiAgICAgICAgICAgIGNhc2UgXCJzZW50ZW5jZVwiOiByZXR1cm4gVS5zQ2FzZShzdHIpO1xuICAgICAgICAgICAgY2FzZSBcInRpdGxlXCI6IHJldHVybiBVLnRDYXNlKHN0cik7XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gc3RyO1xuICAgICAgICB9XG4gICAgfSxcbiAgICByb21hbml6ZSh2YWwpIHtcbiAgICAgICAgcmV0dXJuIFUucm9tYW5pemVOdW0oVS5wSW50KHZhbCkpO1xuICAgIH0sXG4gICAgY291bnQocGFyYW0pIHtcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkocGFyYW0pIHx8IFUuaXNMaXN0KHBhcmFtKSkge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMocGFyYW0pLmZpbHRlcigodmFsKSA9PiB2YWwgIT09IG51bGwgJiYgdmFsICE9PSB1bmRlZmluZWQpLmxlbmd0aDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2YgcGFyYW0gPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBwYXJhbS5sZW5ndGg7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhcmFtID8gMSA6IDA7XG4gICAgfSxcbiAgICAvLyBDb25jYXQgaGVscGVyXG4gICAgLy8gVXNhZ2U6IChjb25jYXQgJ2ZpcnN0ICdzZWNvbmQnKVxuICAgIGNvbmNhdCguLi5hcmdzKSB7XG4gICAgICAgIGxldCBvdXRTdHIgPSBcIlwiO1xuICAgICAgICBmb3IgKGNvbnN0IGFyZyBvZiBhcmdzKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGFyZyA9PT0gXCJzdHJpbmdcIiB8fCB0eXBlb2YgYXJnID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgb3V0U3RyICs9IGFyZztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gb3V0U3RyO1xuICAgIH0sXG4gICAgLy8gTWVyZ2UgaGVscGVyIC0gVG8gbWVyZ2UgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGludG8gYSB0ZW1wbGF0ZSdzIGNvbnRleHRcbiAgICBtZXJnZShjb250ZXh0LCAuLi5hcmdzKSB7XG4gICAgICAgIGFyZ3MucG9wKCk7XG4gICAgICAgIHJldHVybiBhcmdzLnJlZHVjZSgoYWNjLCB2YWwpID0+IE9iamVjdC5hc3NpZ24oYWNjLCB2YWwpLCBjb250ZXh0KTtcbiAgICB9LFxuICAgIC8vIEZvciBsb29wOiB7eyNmb3IgW2Zyb20gPSAwLCB0bywgc3RlcFNpemUgPSAxXX19PGh0bWwgY29udGVudCwgdGhpcyA9IGluZGV4Pnt7L2Zvcn19XG4gICAgZm9yOiAoLi4uYXJncykgPT4ge1xuICAgICAgICBjb25zdCBvcHRpb25zID0gYXJncy5wb3AoKTtcbiAgICAgICAgbGV0IFtmcm9tLCB0bywgc3RlcFNpemVdID0gYXJncztcbiAgICAgICAgZnJvbSA9IFUucEludChmcm9tKTtcbiAgICAgICAgdG8gPSBVLnBJbnQodG8pO1xuICAgICAgICBzdGVwU2l6ZSA9IFUucEludChzdGVwU2l6ZSkgfHwgMTtcbiAgICAgICAgaWYgKGZyb20gPiB0bykge1xuICAgICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGh0bWwgPSBcIlwiO1xuICAgICAgICBmb3IgKGxldCBpID0gcGFyc2VJbnQoZnJvbSB8fCAwLCAxMCk7IGkgPD0gcGFyc2VJbnQodG8gfHwgMCwgMTApOyBpICs9IHN0ZXBTaXplKSB7XG4gICAgICAgICAgICBodG1sICs9IG9wdGlvbnMuZm4oaSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGh0bWw7XG4gICAgfSxcbiAgICBzaWduTnVtKG51bSkge1xuICAgICAgICByZXR1cm4gVS5zaWduTnVtKG51bSk7XG4gICAgfSxcbiAgICBjb21waWxlU3ZnKC4uLmFyZ3MpIHtcbiAgICAgICAgY29uc3QgW3N2Z0RvdEtleSwgc3ZnUGF0aHNdID0gYXJncztcbiAgICAgICAgcmV0dXJuIFUuZ2V0U3ZnQ29kZShzdmdEb3RLZXksIHN2Z1BhdGhzKTtcbiAgICB9LFxuICAgIGVMb2coLi4uYXJncykge1xuICAgICAgICBhcmdzLnBvcCgpO1xuICAgICAgICBsZXQgZGJMZXZlbCA9IDM7XG4gICAgICAgIGlmIChbMCwgMSwgMiwgMywgNCwgNV0uaW5jbHVkZXMoYXJnc1swXSkpIHtcbiAgICAgICAgICAgIGRiTGV2ZWwgPSBhcmdzLnNoaWZ0KCk7XG4gICAgICAgIH1cbiAgICAgICAgZUxvZy5oYnNMb2coLi4uYXJncywgZGJMZXZlbCk7XG4gICAgfSxcbiAgICAvLyBEb2VzIHRoZSBuYW1lIG9mIHRoaXMgdHVyZiBibG9jayByZXByZXNlbnQgYSBzdGFuZGFyZCAnVHVyZicgY2xhaW0/XG4gICAgaXNUdXJmQmxvY2s6IChuYW1lKSA9PiBVLmZ1enp5TWF0Y2gobmFtZSwgXCJUdXJmXCIpLFxuICAgIC8vIFdoaWNoIG90aGVyIGNvbm5lY3Rpb24gZG9lcyB0aGlzIGNvbm5lY3RvciBvdmVybGFwIHdpdGg/XG4gICAgZ2V0Q29ubmVjdG9yUGFydG5lcjogKGluZGV4LCBkaXJlY3Rpb24pID0+IHtcbiAgICAgICAgaW5kZXggPSBwYXJzZUludChgJHtpbmRleH1gLCAxMCk7XG4gICAgICAgIGNvbnN0IHBhcnRuZXJzID0ge1xuICAgICAgICAgICAgMTogeyByaWdodDogMiwgYm90dG9tOiA2IH0sXG4gICAgICAgICAgICAyOiB7IGxlZnQ6IDEsIHJpZ2h0OiAzLCBib3R0b206IDcgfSxcbiAgICAgICAgICAgIDM6IHsgbGVmdDogMiwgcmlnaHQ6IDQsIGJvdHRvbTogOCB9LFxuICAgICAgICAgICAgNDogeyBsZWZ0OiAzLCByaWdodDogNSwgYm90dG9tOiA5IH0sXG4gICAgICAgICAgICA1OiB7IGxlZnQ6IDQsIGJvdHRvbTogMTAgfSxcbiAgICAgICAgICAgIDY6IHsgdG9wOiAxLCByaWdodDogNywgYm90dG9tOiAxMSB9LFxuICAgICAgICAgICAgNzogeyB0b3A6IDIsIGxlZnQ6IDYsIHJpZ2h0OiA4LCBib3R0b206IDEyIH0sXG4gICAgICAgICAgICA4OiB7IHRvcDogMywgbGVmdDogNywgcmlnaHQ6IDksIGJvdHRvbTogMTMgfSxcbiAgICAgICAgICAgIDk6IHsgdG9wOiA0LCBsZWZ0OiA4LCByaWdodDogMTAsIGJvdHRvbTogMTQgfSxcbiAgICAgICAgICAgIDEwOiB7IHRvcDogNSwgbGVmdDogOSwgYm90dG9tOiAxNSB9LFxuICAgICAgICAgICAgMTE6IHsgdG9wOiA2LCByaWdodDogMTIgfSxcbiAgICAgICAgICAgIDEyOiB7IHRvcDogNywgbGVmdDogMTEsIHJpZ2h0OiAxMyB9LFxuICAgICAgICAgICAgMTM6IHsgdG9wOiA4LCBsZWZ0OiAxMiwgcmlnaHQ6IDE0IH0sXG4gICAgICAgICAgICAxNDogeyB0b3A6IDksIGxlZnQ6IDEzLCByaWdodDogMTUgfSxcbiAgICAgICAgICAgIDE1OiB7IHRvcDogMTAsIGxlZnQ6IDE0IH1cbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgcGFydG5lckRpciA9IHsgbGVmdDogXCJyaWdodFwiLCByaWdodDogXCJsZWZ0XCIsIHRvcDogXCJib3R0b21cIiwgYm90dG9tOiBcInRvcFwiIH1bZGlyZWN0aW9uXTtcbiAgICAgICAgY29uc3QgcGFydG5lck51bSA9IHBhcnRuZXJzW2luZGV4XVtkaXJlY3Rpb25dID8/IDA7XG4gICAgICAgIGlmIChwYXJ0bmVyTnVtKSB7XG4gICAgICAgICAgICByZXR1cm4gYCR7cGFydG5lck51bX0tJHtwYXJ0bmVyRGlyfWA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICAvLyBJcyB0aGUgdmFsdWUgVHVyZiBzaWRlLlxuICAgIGlzVHVyZk9uRWRnZTogKGluZGV4LCBkaXJlY3Rpb24pID0+IHtcbiAgICAgICAgaW5kZXggPSBwYXJzZUludChgJHtpbmRleH1gLCAxMCk7XG4gICAgICAgIGNvbnN0IGVkZ2VzID0ge1xuICAgICAgICAgICAgMTogW1widG9wXCIsIFwibGVmdFwiXSxcbiAgICAgICAgICAgIDI6IFtcInRvcFwiXSxcbiAgICAgICAgICAgIDM6IFtcInRvcFwiXSxcbiAgICAgICAgICAgIDQ6IFtcInRvcFwiXSxcbiAgICAgICAgICAgIDU6IFtcInRvcFwiLCBcInJpZ2h0XCJdLFxuICAgICAgICAgICAgNjogW1wibGVmdFwiXSxcbiAgICAgICAgICAgIDc6IFtdLFxuICAgICAgICAgICAgODogW10sXG4gICAgICAgICAgICA5OiBbXSxcbiAgICAgICAgICAgIDEwOiBbXCJyaWdodFwiXSxcbiAgICAgICAgICAgIDExOiBbXCJsZWZ0XCIsIFwiYm90dG9tXCJdLFxuICAgICAgICAgICAgMTI6IFtcImJvdHRvbVwiXSxcbiAgICAgICAgICAgIDEzOiBbXCJib3R0b21cIl0sXG4gICAgICAgICAgICAxNDogW1wiYm90dG9tXCJdLFxuICAgICAgICAgICAgMTU6IFtcInJpZ2h0XCIsIFwiYm90dG9tXCJdXG4gICAgICAgIH07XG4gICAgICAgIGlmICghKGluZGV4IGluIGVkZ2VzKSkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGVkZ2VzW2luZGV4XS5pbmNsdWRlcyhkaXJlY3Rpb24pO1xuICAgIH0sXG4gICAgLy8gTXVsdGlib3hlc1xuICAgIG11bHRpYm94ZXMoc2VsZWN0ZWQsIG9wdGlvbnMpIHtcbiAgICAgICAgbGV0IGh0bWwgPSBvcHRpb25zLmZuKHRoaXMpO1xuICAgICAgICBzZWxlY3RlZCA9IFtzZWxlY3RlZF0uZmxhdCgxKTtcbiAgICAgICAgc2VsZWN0ZWQuZm9yRWFjaCgoc2VsZWN0ZWRWYWwpID0+IHtcbiAgICAgICAgICAgIGlmIChzZWxlY3RlZFZhbCAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBlc2NhcGVkVmFsdWUgPSBSZWdFeHAuZXNjYXBlKEhhbmRsZWJhcnMuZXNjYXBlRXhwcmVzc2lvbihTdHJpbmcoc2VsZWN0ZWRWYWwpKSk7XG4gICAgICAgICAgICAgICAgY29uc3Qgcmd4ID0gbmV3IFJlZ0V4cChgIHZhbHVlPVwiJHtlc2NhcGVkVmFsdWV9XCJgKTtcbiAgICAgICAgICAgICAgICBodG1sID0gaHRtbC5yZXBsYWNlKHJneCwgXCIkJiBjaGVja2VkPVxcXCJjaGVja2VkXFxcIlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBodG1sO1xuICAgIH0sXG4gICAgcmVwdHVyZjogKHR1cmZzQW1vdW50LCBvcHRpb25zKSA9PiB7XG4gICAgICAgIGxldCBodG1sID0gb3B0aW9ucy5mbih0aGlzKTtcbiAgICAgICAgbGV0IHR1cmZzQW1vdW50SW50ID0gcGFyc2VJbnQodHVyZnNBbW91bnQsIDEwKTtcbiAgICAgICAgLy8gQ2FuJ3QgYmUgbW9yZSB0aGFuIDYuXG4gICAgICAgIGlmICh0dXJmc0Ftb3VudEludCA+IDYpIHtcbiAgICAgICAgICAgIHR1cmZzQW1vdW50SW50ID0gNjtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKGxldCBpID0gMTMgLSB0dXJmc0Ftb3VudEludDsgaSA8PSAxMjsgaSsrKSB7XG4gICAgICAgICAgICBjb25zdCByZ3ggPSBuZXcgUmVnRXhwKGAgdmFsdWU9XCIke2l9XCJgKTtcbiAgICAgICAgICAgIGh0bWwgPSBodG1sLnJlcGxhY2Uocmd4LCBcIiQmIGRpc2FibGVkPVxcXCJkaXNhYmxlZFxcXCJcIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGh0bWw7XG4gICAgfVxufTtcbmhhbmRsZWJhckhlbHBlcnMuZUxvZzEgPSBmdW5jdGlvbiAoLi4uYXJncykgeyBoYW5kbGViYXJIZWxwZXJzLmVMb2coLi4uWzEsIC4uLmFyZ3Muc2xpY2UoMCwgNyldKTsgfTtcbmhhbmRsZWJhckhlbHBlcnMuZUxvZzIgPSBmdW5jdGlvbiAoLi4uYXJncykgeyBoYW5kbGViYXJIZWxwZXJzLmVMb2coLi4uWzIsIC4uLmFyZ3Muc2xpY2UoMCwgNyldKTsgfTtcbmhhbmRsZWJhckhlbHBlcnMuZUxvZzMgPSBmdW5jdGlvbiAoLi4uYXJncykgeyBoYW5kbGViYXJIZWxwZXJzLmVMb2coLi4uWzMsIC4uLmFyZ3Muc2xpY2UoMCwgNyldKTsgfTtcbmhhbmRsZWJhckhlbHBlcnMuZUxvZzQgPSBmdW5jdGlvbiAoLi4uYXJncykgeyBoYW5kbGViYXJIZWxwZXJzLmVMb2coLi4uWzQsIC4uLmFyZ3Muc2xpY2UoMCwgNyldKTsgfTtcbmhhbmRsZWJhckhlbHBlcnMuZUxvZzUgPSBmdW5jdGlvbiAoLi4uYXJncykgeyBoYW5kbGViYXJIZWxwZXJzLmVMb2coLi4uWzUsIC4uLmFyZ3Muc2xpY2UoMCwgNyldKTsgfTtcbk9iamVjdC5hc3NpZ24oaGFuZGxlYmFySGVscGVycyk7XG4vKipcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiByZWdpc3RlckhhbmRsZWJhckhlbHBlcnMoKSB7XG4gICAgT2JqZWN0LmVudHJpZXMoaGFuZGxlYmFySGVscGVycykuZm9yRWFjaCgoW25hbWUsIGZ1bmNdKSA9PiBIYW5kbGViYXJzLnJlZ2lzdGVySGVscGVyKG5hbWUsIGZ1bmMpKTtcbn1cbi8vICNlbmRyZWdpb24g4paE4paE4paE4paE4paEIEhhbmRsZWJhcnMg4paE4paE4paE4paE4paEXG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/core/helpers.ts\n"); + +/***/ }), + +/***/ "./ts/core/logger.ts": +/*!***************************!*\ + !*** ./ts/core/logger.ts ***! + \***************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n\n\nconst LOGGERCONFIG = {\n fullName: \"eLogger\",\n aliases: [\"dbLog\"],\n stackTraceExclusions: {\n handlebars: [/scripts\\/handlebars/] // From internal Handlebars module\n }\n};\nconst STYLES = {\n base: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.BLACK,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGOLD,\n \"font-family\": \"Pragmata Pro\",\n padding: \"0 25px\",\n \"margin-right\": \"25px\"\n },\n log0: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGOLD,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n \"font-size\": \"16px\"\n },\n log1: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bGOLD,\n \"font-size\": \"16px\"\n },\n log2: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGOLD,\n \"font-size\": \"16px\"\n },\n log3: {\n \"font-size\": \"14px\"\n },\n log4: {\n \"font-size\": \"12px\"\n },\n log5: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGREY,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bGREY,\n \"font-size\": \"10px\"\n },\n display: {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bGOLD,\n \"font-family\": \"Kirsty\",\n \"font-size\": \"16px\",\n \"margin-left\": \"-100px\",\n padding: \"0 100px\"\n },\n warn: {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGOLD,\n \"font-weight\": 500\n },\n error: {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bRED,\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.ddRED,\n \"font-weight\": 500\n },\n handlebars: {\n background: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GREY,\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.BLUE,\n \"font-family\": \"Pragmata Pro\",\n padding: \"0\",\n \"margin-right\": \"25px\"\n },\n stack: {\n color: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.GOLD,\n \"font-weight\": 100,\n \"font-size\": \"10px\",\n \"font-family\": \"Pragmata Pro\"\n }\n};\nconst { base: baseStyles, ...typeStyles } = STYLES;\nconst STYLELINES = Object.fromEntries(Object.entries(typeStyles)\n .map(([styleName, styles]) => [\n styleName,\n Object.entries({ ...baseStyles, ...styles })\n .map(([prop, val]) => `${prop}: ${val};`).join(\" \")\n]));\nconst eLogger = (type = \"base\", ...content) => {\n if (!([\"error\", \"display\"].includes(type) || CONFIG.debug.logging)) {\n return;\n }\n const lastElem = _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getLast(content);\n let dbLevel = typeof lastElem === \"number\" && [0, 1, 2, 3, 4, 5].includes(lastElem)\n ? content.pop()\n : 3;\n let key = false;\n if (type === \"checkLog\") {\n key = content.shift();\n type = `log${dbLevel}`;\n }\n const [message, ...data] = content;\n if (key) {\n const blacklist = (_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getSetting(\"blacklist\") ?? \"\").split(/,/).map((pat) => new RegExp(`\\\\b${pat.trim()}\\\\b`, \"igu\"));\n const whitelist = (_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getSetting(\"whitelist\") ?? \"\").split(/,/).map((pat) => new RegExp(`\\\\b${pat.trim()}\\\\b`, \"igu\"));\n const isBlack = blacklist.some((pat) => pat.test(key));\n const isWhite = whitelist.some((pat) => pat.test(key));\n if (isBlack && !isWhite) {\n dbLevel = Math.max(4, Math.min(5, dbLevel + 2));\n }\n if (isWhite && !isBlack) {\n dbLevel = Math.min(3, Math.max(1, dbLevel - 2));\n }\n }\n if ((_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].getSetting(\"debug\") ?? 5) < dbLevel) {\n return;\n }\n if (type === \"log\") {\n type = `${type}${dbLevel}`;\n }\n const stackTrace = type === \"display\"\n ? null\n : getStackTrace(LOGGERCONFIG.stackTraceExclusions[type] ?? []);\n let logFunc;\n if (stackTrace) {\n logFunc = console.groupCollapsed;\n }\n else if (data.length <= 1) {\n logFunc = console.log;\n }\n else {\n logFunc = console.group;\n }\n if (data.length === 0) {\n if (typeof message === \"string\") {\n logFunc(`%c${message}`, STYLELINES[type]);\n }\n else {\n logFunc(\"%o\", message);\n }\n }\n else {\n logFunc(`%c${message}${typeof data[0] === \"string\" ? \"\" : \" %o\"}`, STYLELINES[type], data.shift());\n data.forEach((line) => {\n if (typeof line === \"string\") {\n console.log(line);\n }\n else {\n console.log(\"%o\", line);\n }\n });\n }\n if (stackTrace) {\n console.group(\"%cSTACK TRACE\", `color: ${_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dGOLD}; font-family: \"Pragmata Pro\"; font-size: 12px; background: ${_constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.BLACK}; font-weight: bold; padding: 0 10px;`);\n console.log(`%c${stackTrace}`, Object.entries(STYLES.stack).map(([prop, val]) => `${prop}: ${val};`).join(\" \"));\n console.groupEnd();\n }\n console.groupEnd();\n /**\n *\n * @param regExpFilters\n */\n function getStackTrace(regExpFilters = []) {\n regExpFilters.push(new RegExp(`at (getStackTrace|${LOGGERCONFIG.fullName}|${LOGGERCONFIG.aliases.map(String).join(\"|\")}|Object\\\\.(log|display|hbsLog|error))`), /^Error/);\n return ((new Error()).stack ?? \"\")\n .split(/\\n/)\n .map((sLine) => sLine.trim())\n .filter((sLine) => !regExpFilters.some((rTest) => rTest.test(sLine)))\n .join(\"\\n\");\n }\n};\nconst logger = {\n display: (...content) => eLogger(\"display\", ...content),\n log0: (...content) => eLogger(\"log\", ...content, 0),\n log1: (...content) => eLogger(\"log\", ...content, 1),\n log2: (...content) => eLogger(\"log\", ...content, 2),\n log: (...content) => eLogger(\"log\", ...content, 3),\n log3: (...content) => eLogger(\"log\", ...content, 3),\n log4: (...content) => eLogger(\"log\", ...content, 4),\n log5: (...content) => eLogger(\"log\", ...content, 5),\n checkLog0: (...content) => eLogger(\"checkLog\", ...content, 0),\n checkLog1: (...content) => eLogger(\"checkLog\", ...content, 1),\n checkLog2: (...content) => eLogger(\"checkLog\", ...content, 2),\n checkLog: (...content) => eLogger(\"checkLog\", ...content, 3),\n checkLog3: (...content) => eLogger(\"checkLog\", ...content, 3),\n checkLog4: (...content) => eLogger(\"checkLog\", ...content, 4),\n checkLog5: (...content) => eLogger(\"checkLog\", ...content, 5),\n warn: (...content) => eLogger(\"warn\", ...content),\n error: (...content) => eLogger(\"error\", ...content),\n hbsLog: (...content) => eLogger(\"handlebars\", ...content)\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (logger);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jb3JlL2xvZ2dlci50cyIsIm1hcHBpbmdzIjoiOzs7QUFBNEI7QUFDQTtBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0Isa0RBQUM7QUFDckIsZUFBZSxrREFBQztBQUNoQjtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxvQkFBb0Isa0RBQUM7QUFDckIsZUFBZSxrREFBQztBQUNoQjtBQUNBLEtBQUs7QUFDTDtBQUNBLG9CQUFvQixrREFBQztBQUNyQixlQUFlLGtEQUFDO0FBQ2hCO0FBQ0EsS0FBSztBQUNMO0FBQ0Esb0JBQW9CLGtEQUFDO0FBQ3JCLGVBQWUsa0RBQUM7QUFDaEI7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0Esb0JBQW9CLGtEQUFDO0FBQ3JCLGVBQWUsa0RBQUM7QUFDaEI7QUFDQSxLQUFLO0FBQ0w7QUFDQSxlQUFlLGtEQUFDO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsZUFBZSxrREFBQztBQUNoQixvQkFBb0Isa0RBQUM7QUFDckI7QUFDQSxLQUFLO0FBQ0w7QUFDQSxlQUFlLGtEQUFDO0FBQ2hCLG9CQUFvQixrREFBQztBQUNyQjtBQUNBLEtBQUs7QUFDTDtBQUNBLG9CQUFvQixrREFBQztBQUNyQixlQUFlLGtEQUFDO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLGVBQWUsa0RBQUM7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVEsa0NBQWtDO0FBQzFDO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQiwwQkFBMEI7QUFDL0MsaUNBQWlDLEtBQUssSUFBSSxLQUFLO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsa0RBQUM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLFFBQVE7QUFDN0I7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCLGtEQUFDLHlFQUF5RSxXQUFXO0FBQ2hILDJCQUEyQixrREFBQyx5RUFBeUUsV0FBVztBQUNoSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTLGtEQUFDO0FBQ1Y7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLEtBQUssRUFBRSxRQUFRO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLFFBQVE7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLFFBQVEsRUFBRSx5Q0FBeUM7QUFDeEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLGlEQUFpRCxrREFBQyxnQkFBZ0IsNkJBQTZCLGlCQUFpQixjQUFjLGtEQUFDLGdCQUFnQixtQkFBbUIsZ0JBQWdCO0FBQ2xMLHlCQUF5QixXQUFXLHdEQUF3RCxLQUFLLElBQUksS0FBSztBQUMxRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkRBQTJELHNCQUFzQixHQUFHLDJDQUEyQztBQUMvSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxNQUFNLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jb3JlL2xvZ2dlci50cz9hZmMyIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBVIGZyb20gXCIuL3V0aWxpdGllc1wiO1xuaW1wb3J0IEMgZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5jb25zdCBMT0dHRVJDT05GSUcgPSB7XG4gICAgZnVsbE5hbWU6IFwiZUxvZ2dlclwiLFxuICAgIGFsaWFzZXM6IFtcImRiTG9nXCJdLFxuICAgIHN0YWNrVHJhY2VFeGNsdXNpb25zOiB7XG4gICAgICAgIGhhbmRsZWJhcnM6IFsvc2NyaXB0c1xcL2hhbmRsZWJhcnMvXSAvLyBGcm9tIGludGVybmFsIEhhbmRsZWJhcnMgbW9kdWxlXG4gICAgfVxufTtcbmNvbnN0IFNUWUxFUyA9IHtcbiAgICBiYXNlOiB7XG4gICAgICAgIGJhY2tncm91bmQ6IEMuQ29sb3JzLkJMQUNLLFxuICAgICAgICBjb2xvcjogQy5Db2xvcnMuZEdPTEQsXG4gICAgICAgIFwiZm9udC1mYW1pbHlcIjogXCJQcmFnbWF0YSBQcm9cIixcbiAgICAgICAgcGFkZGluZzogXCIwIDI1cHhcIixcbiAgICAgICAgXCJtYXJnaW4tcmlnaHRcIjogXCIyNXB4XCJcbiAgICB9LFxuICAgIGxvZzA6IHtcbiAgICAgICAgYmFja2dyb3VuZDogQy5Db2xvcnMuZEdPTEQsXG4gICAgICAgIGNvbG9yOiBDLkNvbG9ycy5kQkxBQ0ssXG4gICAgICAgIFwiZm9udC1zaXplXCI6IFwiMTZweFwiXG4gICAgfSxcbiAgICBsb2cxOiB7XG4gICAgICAgIGJhY2tncm91bmQ6IEMuQ29sb3JzLmRCTEFDSyxcbiAgICAgICAgY29sb3I6IEMuQ29sb3JzLmJHT0xELFxuICAgICAgICBcImZvbnQtc2l6ZVwiOiBcIjE2cHhcIlxuICAgIH0sXG4gICAgbG9nMjoge1xuICAgICAgICBiYWNrZ3JvdW5kOiBDLkNvbG9ycy5kQkxBQ0ssXG4gICAgICAgIGNvbG9yOiBDLkNvbG9ycy5kR09MRCxcbiAgICAgICAgXCJmb250LXNpemVcIjogXCIxNnB4XCJcbiAgICB9LFxuICAgIGxvZzM6IHtcbiAgICAgICAgXCJmb250LXNpemVcIjogXCIxNHB4XCJcbiAgICB9LFxuICAgIGxvZzQ6IHtcbiAgICAgICAgXCJmb250LXNpemVcIjogXCIxMnB4XCJcbiAgICB9LFxuICAgIGxvZzU6IHtcbiAgICAgICAgYmFja2dyb3VuZDogQy5Db2xvcnMuZEdSRVksXG4gICAgICAgIGNvbG9yOiBDLkNvbG9ycy5iR1JFWSxcbiAgICAgICAgXCJmb250LXNpemVcIjogXCIxMHB4XCJcbiAgICB9LFxuICAgIGRpc3BsYXk6IHtcbiAgICAgICAgY29sb3I6IEMuQ29sb3JzLmJHT0xELFxuICAgICAgICBcImZvbnQtZmFtaWx5XCI6IFwiS2lyc3R5XCIsXG4gICAgICAgIFwiZm9udC1zaXplXCI6IFwiMTZweFwiLFxuICAgICAgICBcIm1hcmdpbi1sZWZ0XCI6IFwiLTEwMHB4XCIsXG4gICAgICAgIHBhZGRpbmc6IFwiMCAxMDBweFwiXG4gICAgfSxcbiAgICB3YXJuOiB7XG4gICAgICAgIGNvbG9yOiBDLkNvbG9ycy5kQkxBQ0ssXG4gICAgICAgIGJhY2tncm91bmQ6IEMuQ29sb3JzLmRHT0xELFxuICAgICAgICBcImZvbnQtd2VpZ2h0XCI6IDUwMFxuICAgIH0sXG4gICAgZXJyb3I6IHtcbiAgICAgICAgY29sb3I6IEMuQ29sb3JzLmJSRUQsXG4gICAgICAgIGJhY2tncm91bmQ6IEMuQ29sb3JzLmRkUkVELFxuICAgICAgICBcImZvbnQtd2VpZ2h0XCI6IDUwMFxuICAgIH0sXG4gICAgaGFuZGxlYmFyczoge1xuICAgICAgICBiYWNrZ3JvdW5kOiBDLkNvbG9ycy5HUkVZLFxuICAgICAgICBjb2xvcjogQy5Db2xvcnMuQkxVRSxcbiAgICAgICAgXCJmb250LWZhbWlseVwiOiBcIlByYWdtYXRhIFByb1wiLFxuICAgICAgICBwYWRkaW5nOiBcIjBcIixcbiAgICAgICAgXCJtYXJnaW4tcmlnaHRcIjogXCIyNXB4XCJcbiAgICB9LFxuICAgIHN0YWNrOiB7XG4gICAgICAgIGNvbG9yOiBDLkNvbG9ycy5HT0xELFxuICAgICAgICBcImZvbnQtd2VpZ2h0XCI6IDEwMCxcbiAgICAgICAgXCJmb250LXNpemVcIjogXCIxMHB4XCIsXG4gICAgICAgIFwiZm9udC1mYW1pbHlcIjogXCJQcmFnbWF0YSBQcm9cIlxuICAgIH1cbn07XG5jb25zdCB7IGJhc2U6IGJhc2VTdHlsZXMsIC4uLnR5cGVTdHlsZXMgfSA9IFNUWUxFUztcbmNvbnN0IFNUWUxFTElORVMgPSBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModHlwZVN0eWxlcylcbiAgICAubWFwKChbc3R5bGVOYW1lLCBzdHlsZXNdKSA9PiBbXG4gICAgc3R5bGVOYW1lLFxuICAgIE9iamVjdC5lbnRyaWVzKHsgLi4uYmFzZVN0eWxlcywgLi4uc3R5bGVzIH0pXG4gICAgICAgIC5tYXAoKFtwcm9wLCB2YWxdKSA9PiBgJHtwcm9wfTogJHt2YWx9O2ApLmpvaW4oXCIgXCIpXG5dKSk7XG5jb25zdCBlTG9nZ2VyID0gKHR5cGUgPSBcImJhc2VcIiwgLi4uY29udGVudCkgPT4ge1xuICAgIGlmICghKFtcImVycm9yXCIsIFwiZGlzcGxheVwiXS5pbmNsdWRlcyh0eXBlKSB8fCBDT05GSUcuZGVidWcubG9nZ2luZykpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjb25zdCBsYXN0RWxlbSA9IFUuZ2V0TGFzdChjb250ZW50KTtcbiAgICBsZXQgZGJMZXZlbCA9IHR5cGVvZiBsYXN0RWxlbSA9PT0gXCJudW1iZXJcIiAmJiBbMCwgMSwgMiwgMywgNCwgNV0uaW5jbHVkZXMobGFzdEVsZW0pXG4gICAgICAgID8gY29udGVudC5wb3AoKVxuICAgICAgICA6IDM7XG4gICAgbGV0IGtleSA9IGZhbHNlO1xuICAgIGlmICh0eXBlID09PSBcImNoZWNrTG9nXCIpIHtcbiAgICAgICAga2V5ID0gY29udGVudC5zaGlmdCgpO1xuICAgICAgICB0eXBlID0gYGxvZyR7ZGJMZXZlbH1gO1xuICAgIH1cbiAgICBjb25zdCBbbWVzc2FnZSwgLi4uZGF0YV0gPSBjb250ZW50O1xuICAgIGlmIChrZXkpIHtcbiAgICAgICAgY29uc3QgYmxhY2tsaXN0ID0gKFUuZ2V0U2V0dGluZyhcImJsYWNrbGlzdFwiKSA/PyBcIlwiKS5zcGxpdCgvLC8pLm1hcCgocGF0KSA9PiBuZXcgUmVnRXhwKGBcXFxcYiR7cGF0LnRyaW0oKX1cXFxcYmAsIFwiaWd1XCIpKTtcbiAgICAgICAgY29uc3Qgd2hpdGVsaXN0ID0gKFUuZ2V0U2V0dGluZyhcIndoaXRlbGlzdFwiKSA/PyBcIlwiKS5zcGxpdCgvLC8pLm1hcCgocGF0KSA9PiBuZXcgUmVnRXhwKGBcXFxcYiR7cGF0LnRyaW0oKX1cXFxcYmAsIFwiaWd1XCIpKTtcbiAgICAgICAgY29uc3QgaXNCbGFjayA9IGJsYWNrbGlzdC5zb21lKChwYXQpID0+IHBhdC50ZXN0KGtleSkpO1xuICAgICAgICBjb25zdCBpc1doaXRlID0gd2hpdGVsaXN0LnNvbWUoKHBhdCkgPT4gcGF0LnRlc3Qoa2V5KSk7XG4gICAgICAgIGlmIChpc0JsYWNrICYmICFpc1doaXRlKSB7XG4gICAgICAgICAgICBkYkxldmVsID0gTWF0aC5tYXgoNCwgTWF0aC5taW4oNSwgZGJMZXZlbCArIDIpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNXaGl0ZSAmJiAhaXNCbGFjaykge1xuICAgICAgICAgICAgZGJMZXZlbCA9IE1hdGgubWluKDMsIE1hdGgubWF4KDEsIGRiTGV2ZWwgLSAyKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKChVLmdldFNldHRpbmcoXCJkZWJ1Z1wiKSA/PyA1KSA8IGRiTGV2ZWwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAodHlwZSA9PT0gXCJsb2dcIikge1xuICAgICAgICB0eXBlID0gYCR7dHlwZX0ke2RiTGV2ZWx9YDtcbiAgICB9XG4gICAgY29uc3Qgc3RhY2tUcmFjZSA9IHR5cGUgPT09IFwiZGlzcGxheVwiXG4gICAgICAgID8gbnVsbFxuICAgICAgICA6IGdldFN0YWNrVHJhY2UoTE9HR0VSQ09ORklHLnN0YWNrVHJhY2VFeGNsdXNpb25zW3R5cGVdID8/IFtdKTtcbiAgICBsZXQgbG9nRnVuYztcbiAgICBpZiAoc3RhY2tUcmFjZSkge1xuICAgICAgICBsb2dGdW5jID0gY29uc29sZS5ncm91cENvbGxhcHNlZDtcbiAgICB9XG4gICAgZWxzZSBpZiAoZGF0YS5sZW5ndGggPD0gMSkge1xuICAgICAgICBsb2dGdW5jID0gY29uc29sZS5sb2c7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBsb2dGdW5jID0gY29uc29sZS5ncm91cDtcbiAgICB9XG4gICAgaWYgKGRhdGEubGVuZ3RoID09PSAwKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgbG9nRnVuYyhgJWMke21lc3NhZ2V9YCwgU1RZTEVMSU5FU1t0eXBlXSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBsb2dGdW5jKFwiJW9cIiwgbWVzc2FnZSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGxvZ0Z1bmMoYCVjJHttZXNzYWdlfSR7dHlwZW9mIGRhdGFbMF0gPT09IFwic3RyaW5nXCIgPyBcIlwiIDogXCIgJW9cIn1gLCBTVFlMRUxJTkVTW3R5cGVdLCBkYXRhLnNoaWZ0KCkpO1xuICAgICAgICBkYXRhLmZvckVhY2goKGxpbmUpID0+IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbGluZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKGxpbmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCIlb1wiLCBsaW5lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChzdGFja1RyYWNlKSB7XG4gICAgICAgIGNvbnNvbGUuZ3JvdXAoXCIlY1NUQUNLIFRSQUNFXCIsIGBjb2xvcjogJHtDLkNvbG9ycy5kR09MRH07IGZvbnQtZmFtaWx5OiBcIlByYWdtYXRhIFByb1wiOyBmb250LXNpemU6IDEycHg7IGJhY2tncm91bmQ6ICR7Qy5Db2xvcnMuQkxBQ0t9OyBmb250LXdlaWdodDogYm9sZDsgcGFkZGluZzogMCAxMHB4O2ApO1xuICAgICAgICBjb25zb2xlLmxvZyhgJWMke3N0YWNrVHJhY2V9YCwgT2JqZWN0LmVudHJpZXMoU1RZTEVTLnN0YWNrKS5tYXAoKFtwcm9wLCB2YWxdKSA9PiBgJHtwcm9wfTogJHt2YWx9O2ApLmpvaW4oXCIgXCIpKTtcbiAgICAgICAgY29uc29sZS5ncm91cEVuZCgpO1xuICAgIH1cbiAgICBjb25zb2xlLmdyb3VwRW5kKCk7XG4gICAgLyoqXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVnRXhwRmlsdGVyc1xuICAgICAqL1xuICAgIGZ1bmN0aW9uIGdldFN0YWNrVHJhY2UocmVnRXhwRmlsdGVycyA9IFtdKSB7XG4gICAgICAgIHJlZ0V4cEZpbHRlcnMucHVzaChuZXcgUmVnRXhwKGBhdCAoZ2V0U3RhY2tUcmFjZXwke0xPR0dFUkNPTkZJRy5mdWxsTmFtZX18JHtMT0dHRVJDT05GSUcuYWxpYXNlcy5tYXAoU3RyaW5nKS5qb2luKFwifFwiKX18T2JqZWN0XFxcXC4obG9nfGRpc3BsYXl8aGJzTG9nfGVycm9yKSlgKSwgL15FcnJvci8pO1xuICAgICAgICByZXR1cm4gKChuZXcgRXJyb3IoKSkuc3RhY2sgPz8gXCJcIilcbiAgICAgICAgICAgIC5zcGxpdCgvXFxuLylcbiAgICAgICAgICAgIC5tYXAoKHNMaW5lKSA9PiBzTGluZS50cmltKCkpXG4gICAgICAgICAgICAuZmlsdGVyKChzTGluZSkgPT4gIXJlZ0V4cEZpbHRlcnMuc29tZSgoclRlc3QpID0+IHJUZXN0LnRlc3Qoc0xpbmUpKSlcbiAgICAgICAgICAgIC5qb2luKFwiXFxuXCIpO1xuICAgIH1cbn07XG5jb25zdCBsb2dnZXIgPSB7XG4gICAgZGlzcGxheTogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJkaXNwbGF5XCIsIC4uLmNvbnRlbnQpLFxuICAgIGxvZzA6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwibG9nXCIsIC4uLmNvbnRlbnQsIDApLFxuICAgIGxvZzE6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwibG9nXCIsIC4uLmNvbnRlbnQsIDEpLFxuICAgIGxvZzI6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwibG9nXCIsIC4uLmNvbnRlbnQsIDIpLFxuICAgIGxvZzogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJsb2dcIiwgLi4uY29udGVudCwgMyksXG4gICAgbG9nMzogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJsb2dcIiwgLi4uY29udGVudCwgMyksXG4gICAgbG9nNDogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJsb2dcIiwgLi4uY29udGVudCwgNCksXG4gICAgbG9nNTogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJsb2dcIiwgLi4uY29udGVudCwgNSksXG4gICAgY2hlY2tMb2cwOiAoLi4uY29udGVudCkgPT4gZUxvZ2dlcihcImNoZWNrTG9nXCIsIC4uLmNvbnRlbnQsIDApLFxuICAgIGNoZWNrTG9nMTogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJjaGVja0xvZ1wiLCAuLi5jb250ZW50LCAxKSxcbiAgICBjaGVja0xvZzI6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwiY2hlY2tMb2dcIiwgLi4uY29udGVudCwgMiksXG4gICAgY2hlY2tMb2c6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwiY2hlY2tMb2dcIiwgLi4uY29udGVudCwgMyksXG4gICAgY2hlY2tMb2czOiAoLi4uY29udGVudCkgPT4gZUxvZ2dlcihcImNoZWNrTG9nXCIsIC4uLmNvbnRlbnQsIDMpLFxuICAgIGNoZWNrTG9nNDogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJjaGVja0xvZ1wiLCAuLi5jb250ZW50LCA0KSxcbiAgICBjaGVja0xvZzU6ICguLi5jb250ZW50KSA9PiBlTG9nZ2VyKFwiY2hlY2tMb2dcIiwgLi4uY29udGVudCwgNSksXG4gICAgd2FybjogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJ3YXJuXCIsIC4uLmNvbnRlbnQpLFxuICAgIGVycm9yOiAoLi4uY29udGVudCkgPT4gZUxvZ2dlcihcImVycm9yXCIsIC4uLmNvbnRlbnQpLFxuICAgIGhic0xvZzogKC4uLmNvbnRlbnQpID0+IGVMb2dnZXIoXCJoYW5kbGViYXJzXCIsIC4uLmNvbnRlbnQpXG59O1xuZXhwb3J0IGRlZmF1bHQgbG9nZ2VyO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/core/logger.ts\n"); + +/***/ }), + +/***/ "./ts/core/settings.ts": +/*!*****************************!*\ + !*** ./ts/core/settings.ts ***! + \*****************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ initCanvasStyles: function() { return /* binding */ initCanvasStyles; },\n/* harmony export */ initDOMStyles: function() { return /* binding */ initDOMStyles; },\n/* harmony export */ initTinyMCEStyles: function() { return /* binding */ initTinyMCEStyles; }\n/* harmony export */ });\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n\n\nconst registerSettings = function () {\n game.settings.register(\"eunos-blades\", \"debug\", {\n name: \"Debug Level\",\n hint: \"The verbosity of the debug messages to console.\",\n scope: \"client\", // This specifies a world-level setting\n config: true, // This specifies that the setting appears in the configuration view\n type: Number,\n range: {\n min: 0,\n max: 5,\n step: 1\n },\n default: 3 // The default value for the setting\n });\n game.settings.register(\"eunos-blades\", \"debugHooks\", {\n name: \"Debug HOOKS\",\n hint: \"Whether all Hooks are logged to the console.\",\n scope: \"client\",\n config: true,\n type: Boolean,\n default: false\n });\n game.settings.register(\"eunos-blades\", \"openAPIModelLevel\", {\n name: \"AI Base Quality\",\n hint: \"Lower values are cheaper to run, at the cost of quality.\",\n scope: \"client\", // This specifies a world-level setting\n config: true, // This specifies that the setting appears in the configuration view\n type: Number,\n range: {\n min: 0,\n max: 2,\n step: 1\n }\n });\n game.settings.register(\"eunos-blades\", \"blacklist\", {\n name: \"Debug Blacklist\",\n hint: \"Comma-delimited list of categories of debug messages to silence.\",\n scope: \"client\", // This specifies a world-level setting\n config: true, // This specifies that the setting appears in the configuration view\n type: String,\n default: \"\" // The default value for the setting\n });\n game.settings.register(\"eunos-blades\", \"openAPIKey\", {\n name: \"OpenAI API Key\",\n hint: \"Your personal OpenAI API Key (necessary to enable AI functionality)\",\n scope: \"client\", // This specifies a world-level setting\n config: true, // This specifies that the setting appears in the configuration view\n type: String,\n default: \"\" // The default value for the setting\n });\n game.settings.register(\"eunos-blades\", \"whitelist\", {\n name: \"Debug Whitelist\",\n hint: \"Comma-delimited list of categories of debug messages to promote.\",\n scope: \"client\", // This specifies a world-level setting\n config: true, // This specifies that the setting appears in the configuration view\n type: String,\n default: \"\" // The default value for the setting\n });\n /**\n * Track the system version upon which point a migration was last applied\n */\n game.settings.register(\"eunos-blades\", \"systemMigrationVersion\", {\n name: \"System Migration Version\",\n scope: \"world\",\n config: false,\n type: Number,\n default: 0\n });\n};\n/**\n *\n */\nfunction initTinyMCEStyles() {\n CONFIG.TinyMCE = {\n ...CONFIG.TinyMCE,\n ...{\n skin: \"skin\",\n skin_url: \"systems/eunos-blades/css/tinymce/skin\",\n content_css: `systems/eunos-blades/css/tinymce/content.css?${new Date().getTime()}`,\n font_css: \"systems/eunos-blades/css/fonts.css\",\n max_height: 500,\n min_height: 40,\n autoresize_overflow_padding: 0,\n autoresize_bottom_margin: 0, // 25,\n menubar: false,\n statusbar: false, // True,\n elementPath: true,\n branding: false,\n resize: false,\n plugins: \"lists image table code save autoresize searchreplace quickbars template\",\n save_enablewhendirty: false,\n // Table_default_styles: {},\n style_formats: [\n {\n title: \"Headings\",\n items: [\n { title: \"Heading 1\", block: \"h1\", wrapper: false },\n { title: \"Heading 2\", block: \"h2\", wrapper: false },\n { title: \"Heading 3\", block: \"h3\", wrapper: false },\n { title: \"Heading 4\", block: \"h4\", wrapper: false }\n ]\n },\n {\n title: \"Blocks\",\n items: [\n { title: \"Paragraph\", block: \"p\", wrapper: false },\n { title: \"Block Quote\", block: \"blockquote\", wrapper: true }\n // {title: \"Secret\", block: \"span\", classes: \"text-secret\", attributes: {\"data-is-secret\": \"true\"}, wrapper: false}\n ]\n },\n {\n title: \"Inline\",\n items: [\n { title: \"Bold\", inline: \"b\", wrapper: false },\n { title: \"Italics\", inline: \"i\", wrapper: false },\n { title: \"Underline\", inline: \"u\", wrapper: false },\n { title: \"Secret\", inline: \"span\", classes: \"text-secret\", attributes: { \"data-is-secret\": \"true\" }, wrapper: false }\n ]\n }\n ],\n style_formats_merge: false,\n toolbar: \"styles | searchreplace | formatting alignment lists elements | removeformat | code | save\",\n toolbar_groups: {\n formatting: {\n icon: \"color-picker\",\n tooltip: \"Formatting\",\n items: \"bold italic underline\"\n },\n alignment: {\n icon: \"align-left\",\n tooltip: \"Alignment\",\n items: \"alignleft aligncenter alignright alignjustify | outdent indent\"\n },\n lists: {\n icon: \"unordered-list\",\n tooltip: \"Lists\",\n items: \"bullist numlist\"\n },\n elements: {\n icon: \"duplicate\",\n tooltip: \"Insert Element\",\n items: \"tableinsertdialog image hr | template\"\n }\n },\n toolbar_mode: \"floating\",\n quickbars_link_toolbar: false,\n quickbars_selection_toolbar: \"styles | bold italic underline\",\n quickbars_insert_toolbar: \"hr image table\",\n quickbars_table_toolbar: \"tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol\"\n }\n };\n}\n/**\n *\n */\nfunction initCanvasStyles() {\n CONFIG.canvasTextStyle = new PIXI.TextStyle({\n align: \"center\",\n dropShadow: true,\n dropShadowAngle: _utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].degToRad(45),\n dropShadowBlur: 8,\n dropShadowColor: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.BLACK,\n dropShadowDistance: 4,\n fill: [\n _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bWHITE,\n _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.bGREY\n ],\n fillGradientType: 1,\n fillGradientStops: [\n 0,\n 0.3\n ],\n fontFamily: \"Kirsty\",\n fontSize: 32,\n letterSpacing: 2,\n lineHeight: 32,\n lineJoin: \"round\",\n padding: 4,\n stroke: _constants__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Colors.dBLACK,\n strokeThickness: 3,\n trim: true,\n whiteSpace: \"normal\",\n wordWrap: true,\n wordWrapWidth: 0.1\n });\n}\nfunction initDOMStyles() {\n // Create a full-screen background gradient that resembles the gradient described in CONFIG-canvasTextStyles\n // This will serve as a fallback background when the canvas has been disabled or is not available\n $(\"body.vtt.game.system-eunos-blades\")\n .append(`
`);\n // Append lightning-barrier background to #sidebar\n $(\"#interface\")\n .append(`
\r\n
`); /*\n \n \n \n \n \n \n `); */\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (registerSettings);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jb3JlL3NldHRpbmdzLnRzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBQTRCO0FBQ0E7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlFQUF5RSxxQkFBcUI7QUFDOUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLGlEQUFpRDtBQUMzRSwwQkFBMEIsaURBQWlEO0FBQzNFLDBCQUEwQixpREFBaUQ7QUFDM0UsMEJBQTBCO0FBQzFCO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQixnREFBZ0Q7QUFDMUUsMEJBQTBCO0FBQzFCLDRCQUE0QixxRUFBcUUseUJBQXlCO0FBQzFIO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQiw0Q0FBNEM7QUFDdEUsMEJBQTBCLCtDQUErQztBQUN6RSwwQkFBMEIsaURBQWlEO0FBQzNFLDBCQUEwQix1RUFBdUUsMEJBQTBCO0FBQzNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNPO0FBQ1A7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLGtEQUFDO0FBQzFCO0FBQ0EseUJBQXlCLGtEQUFDO0FBQzFCO0FBQ0E7QUFDQSxZQUFZLGtEQUFDO0FBQ2IsWUFBWSxrREFBQztBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixrREFBQztBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ087QUFDUDtBQUNBO0FBQ0E7QUFDQSwyREFBMkQsYUFBYSxvQkFBb0IsYUFBYSxxQ0FBcUMsa0RBQUMsYUFBYSxJQUFJLGtEQUFDLGNBQWMsRUFBRTtBQUNqTDtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0EsK0RBQWUsZ0JBQWdCLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jb3JlL3NldHRpbmdzLnRzP2M5ODgiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFUgZnJvbSBcIi4vdXRpbGl0aWVzXCI7XG5pbXBvcnQgQyBmcm9tIFwiLi9jb25zdGFudHNcIjtcbmNvbnN0IHJlZ2lzdGVyU2V0dGluZ3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgZ2FtZS5zZXR0aW5ncy5yZWdpc3RlcihcImV1bm9zLWJsYWRlc1wiLCBcImRlYnVnXCIsIHtcbiAgICAgICAgbmFtZTogXCJEZWJ1ZyBMZXZlbFwiLFxuICAgICAgICBoaW50OiBcIlRoZSB2ZXJib3NpdHkgb2YgdGhlIGRlYnVnIG1lc3NhZ2VzIHRvIGNvbnNvbGUuXCIsXG4gICAgICAgIHNjb3BlOiBcImNsaWVudFwiLCAvLyBUaGlzIHNwZWNpZmllcyBhIHdvcmxkLWxldmVsIHNldHRpbmdcbiAgICAgICAgY29uZmlnOiB0cnVlLCAvLyBUaGlzIHNwZWNpZmllcyB0aGF0IHRoZSBzZXR0aW5nIGFwcGVhcnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24gdmlld1xuICAgICAgICB0eXBlOiBOdW1iZXIsXG4gICAgICAgIHJhbmdlOiB7XG4gICAgICAgICAgICBtaW46IDAsXG4gICAgICAgICAgICBtYXg6IDUsXG4gICAgICAgICAgICBzdGVwOiAxXG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHQ6IDMgLy8gVGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoZSBzZXR0aW5nXG4gICAgfSk7XG4gICAgZ2FtZS5zZXR0aW5ncy5yZWdpc3RlcihcImV1bm9zLWJsYWRlc1wiLCBcImRlYnVnSG9va3NcIiwge1xuICAgICAgICBuYW1lOiBcIkRlYnVnIEhPT0tTXCIsXG4gICAgICAgIGhpbnQ6IFwiV2hldGhlciBhbGwgSG9va3MgYXJlIGxvZ2dlZCB0byB0aGUgY29uc29sZS5cIixcbiAgICAgICAgc2NvcGU6IFwiY2xpZW50XCIsXG4gICAgICAgIGNvbmZpZzogdHJ1ZSxcbiAgICAgICAgdHlwZTogQm9vbGVhbixcbiAgICAgICAgZGVmYXVsdDogZmFsc2VcbiAgICB9KTtcbiAgICBnYW1lLnNldHRpbmdzLnJlZ2lzdGVyKFwiZXVub3MtYmxhZGVzXCIsIFwib3BlbkFQSU1vZGVsTGV2ZWxcIiwge1xuICAgICAgICBuYW1lOiBcIkFJIEJhc2UgUXVhbGl0eVwiLFxuICAgICAgICBoaW50OiBcIkxvd2VyIHZhbHVlcyBhcmUgY2hlYXBlciB0byBydW4sIGF0IHRoZSBjb3N0IG9mIHF1YWxpdHkuXCIsXG4gICAgICAgIHNjb3BlOiBcImNsaWVudFwiLCAvLyBUaGlzIHNwZWNpZmllcyBhIHdvcmxkLWxldmVsIHNldHRpbmdcbiAgICAgICAgY29uZmlnOiB0cnVlLCAvLyBUaGlzIHNwZWNpZmllcyB0aGF0IHRoZSBzZXR0aW5nIGFwcGVhcnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24gdmlld1xuICAgICAgICB0eXBlOiBOdW1iZXIsXG4gICAgICAgIHJhbmdlOiB7XG4gICAgICAgICAgICBtaW46IDAsXG4gICAgICAgICAgICBtYXg6IDIsXG4gICAgICAgICAgICBzdGVwOiAxXG4gICAgICAgIH1cbiAgICB9KTtcbiAgICBnYW1lLnNldHRpbmdzLnJlZ2lzdGVyKFwiZXVub3MtYmxhZGVzXCIsIFwiYmxhY2tsaXN0XCIsIHtcbiAgICAgICAgbmFtZTogXCJEZWJ1ZyBCbGFja2xpc3RcIixcbiAgICAgICAgaGludDogXCJDb21tYS1kZWxpbWl0ZWQgbGlzdCBvZiBjYXRlZ29yaWVzIG9mIGRlYnVnIG1lc3NhZ2VzIHRvIHNpbGVuY2UuXCIsXG4gICAgICAgIHNjb3BlOiBcImNsaWVudFwiLCAvLyBUaGlzIHNwZWNpZmllcyBhIHdvcmxkLWxldmVsIHNldHRpbmdcbiAgICAgICAgY29uZmlnOiB0cnVlLCAvLyBUaGlzIHNwZWNpZmllcyB0aGF0IHRoZSBzZXR0aW5nIGFwcGVhcnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24gdmlld1xuICAgICAgICB0eXBlOiBTdHJpbmcsXG4gICAgICAgIGRlZmF1bHQ6IFwiXCIgLy8gVGhlIGRlZmF1bHQgdmFsdWUgZm9yIHRoZSBzZXR0aW5nXG4gICAgfSk7XG4gICAgZ2FtZS5zZXR0aW5ncy5yZWdpc3RlcihcImV1bm9zLWJsYWRlc1wiLCBcIm9wZW5BUElLZXlcIiwge1xuICAgICAgICBuYW1lOiBcIk9wZW5BSSBBUEkgS2V5XCIsXG4gICAgICAgIGhpbnQ6IFwiWW91ciBwZXJzb25hbCBPcGVuQUkgQVBJIEtleSAobmVjZXNzYXJ5IHRvIGVuYWJsZSBBSSBmdW5jdGlvbmFsaXR5KVwiLFxuICAgICAgICBzY29wZTogXCJjbGllbnRcIiwgLy8gVGhpcyBzcGVjaWZpZXMgYSB3b3JsZC1sZXZlbCBzZXR0aW5nXG4gICAgICAgIGNvbmZpZzogdHJ1ZSwgLy8gVGhpcyBzcGVjaWZpZXMgdGhhdCB0aGUgc2V0dGluZyBhcHBlYXJzIGluIHRoZSBjb25maWd1cmF0aW9uIHZpZXdcbiAgICAgICAgdHlwZTogU3RyaW5nLFxuICAgICAgICBkZWZhdWx0OiBcIlwiIC8vIFRoZSBkZWZhdWx0IHZhbHVlIGZvciB0aGUgc2V0dGluZ1xuICAgIH0pO1xuICAgIGdhbWUuc2V0dGluZ3MucmVnaXN0ZXIoXCJldW5vcy1ibGFkZXNcIiwgXCJ3aGl0ZWxpc3RcIiwge1xuICAgICAgICBuYW1lOiBcIkRlYnVnIFdoaXRlbGlzdFwiLFxuICAgICAgICBoaW50OiBcIkNvbW1hLWRlbGltaXRlZCBsaXN0IG9mIGNhdGVnb3JpZXMgb2YgZGVidWcgbWVzc2FnZXMgdG8gcHJvbW90ZS5cIixcbiAgICAgICAgc2NvcGU6IFwiY2xpZW50XCIsIC8vIFRoaXMgc3BlY2lmaWVzIGEgd29ybGQtbGV2ZWwgc2V0dGluZ1xuICAgICAgICBjb25maWc6IHRydWUsIC8vIFRoaXMgc3BlY2lmaWVzIHRoYXQgdGhlIHNldHRpbmcgYXBwZWFycyBpbiB0aGUgY29uZmlndXJhdGlvbiB2aWV3XG4gICAgICAgIHR5cGU6IFN0cmluZyxcbiAgICAgICAgZGVmYXVsdDogXCJcIiAvLyBUaGUgZGVmYXVsdCB2YWx1ZSBmb3IgdGhlIHNldHRpbmdcbiAgICB9KTtcbiAgICAvKipcbiAgICAgKiBUcmFjayB0aGUgc3lzdGVtIHZlcnNpb24gdXBvbiB3aGljaCBwb2ludCBhIG1pZ3JhdGlvbiB3YXMgbGFzdCBhcHBsaWVkXG4gICAgICovXG4gICAgZ2FtZS5zZXR0aW5ncy5yZWdpc3RlcihcImV1bm9zLWJsYWRlc1wiLCBcInN5c3RlbU1pZ3JhdGlvblZlcnNpb25cIiwge1xuICAgICAgICBuYW1lOiBcIlN5c3RlbSBNaWdyYXRpb24gVmVyc2lvblwiLFxuICAgICAgICBzY29wZTogXCJ3b3JsZFwiLFxuICAgICAgICBjb25maWc6IGZhbHNlLFxuICAgICAgICB0eXBlOiBOdW1iZXIsXG4gICAgICAgIGRlZmF1bHQ6IDBcbiAgICB9KTtcbn07XG4vKipcbiAqXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpbml0VGlueU1DRVN0eWxlcygpIHtcbiAgICBDT05GSUcuVGlueU1DRSA9IHtcbiAgICAgICAgLi4uQ09ORklHLlRpbnlNQ0UsXG4gICAgICAgIC4uLntcbiAgICAgICAgICAgIHNraW46IFwic2tpblwiLFxuICAgICAgICAgICAgc2tpbl91cmw6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvY3NzL3RpbnltY2Uvc2tpblwiLFxuICAgICAgICAgICAgY29udGVudF9jc3M6IGBzeXN0ZW1zL2V1bm9zLWJsYWRlcy9jc3MvdGlueW1jZS9jb250ZW50LmNzcz8ke25ldyBEYXRlKCkuZ2V0VGltZSgpfWAsXG4gICAgICAgICAgICBmb250X2NzczogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy9jc3MvZm9udHMuY3NzXCIsXG4gICAgICAgICAgICBtYXhfaGVpZ2h0OiA1MDAsXG4gICAgICAgICAgICBtaW5faGVpZ2h0OiA0MCxcbiAgICAgICAgICAgIGF1dG9yZXNpemVfb3ZlcmZsb3dfcGFkZGluZzogMCxcbiAgICAgICAgICAgIGF1dG9yZXNpemVfYm90dG9tX21hcmdpbjogMCwgLy8gMjUsXG4gICAgICAgICAgICBtZW51YmFyOiBmYWxzZSxcbiAgICAgICAgICAgIHN0YXR1c2JhcjogZmFsc2UsIC8vIFRydWUsXG4gICAgICAgICAgICBlbGVtZW50UGF0aDogdHJ1ZSxcbiAgICAgICAgICAgIGJyYW5kaW5nOiBmYWxzZSxcbiAgICAgICAgICAgIHJlc2l6ZTogZmFsc2UsXG4gICAgICAgICAgICBwbHVnaW5zOiBcImxpc3RzIGltYWdlIHRhYmxlIGNvZGUgc2F2ZSBhdXRvcmVzaXplIHNlYXJjaHJlcGxhY2UgcXVpY2tiYXJzIHRlbXBsYXRlXCIsXG4gICAgICAgICAgICBzYXZlX2VuYWJsZXdoZW5kaXJ0eTogZmFsc2UsXG4gICAgICAgICAgICAvLyBUYWJsZV9kZWZhdWx0X3N0eWxlczoge30sXG4gICAgICAgICAgICBzdHlsZV9mb3JtYXRzOiBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogXCJIZWFkaW5nc1wiLFxuICAgICAgICAgICAgICAgICAgICBpdGVtczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJIZWFkaW5nIDFcIiwgYmxvY2s6IFwiaDFcIiwgd3JhcHBlcjogZmFsc2UgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHsgdGl0bGU6IFwiSGVhZGluZyAyXCIsIGJsb2NrOiBcImgyXCIsIHdyYXBwZXI6IGZhbHNlIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHRpdGxlOiBcIkhlYWRpbmcgM1wiLCBibG9jazogXCJoM1wiLCB3cmFwcGVyOiBmYWxzZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJIZWFkaW5nIDRcIiwgYmxvY2s6IFwiaDRcIiwgd3JhcHBlcjogZmFsc2UgfVxuICAgICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHRpdGxlOiBcIkJsb2Nrc1wiLFxuICAgICAgICAgICAgICAgICAgICBpdGVtczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJQYXJhZ3JhcGhcIiwgYmxvY2s6IFwicFwiLCB3cmFwcGVyOiBmYWxzZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJCbG9jayBRdW90ZVwiLCBibG9jazogXCJibG9ja3F1b3RlXCIsIHdyYXBwZXI6IHRydWUgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8ge3RpdGxlOiBcIlNlY3JldFwiLCBibG9jazogXCJzcGFuXCIsIGNsYXNzZXM6IFwidGV4dC1zZWNyZXRcIiwgYXR0cmlidXRlczoge1wiZGF0YS1pcy1zZWNyZXRcIjogXCJ0cnVlXCJ9LCB3cmFwcGVyOiBmYWxzZX1cbiAgICAgICAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB0aXRsZTogXCJJbmxpbmVcIixcbiAgICAgICAgICAgICAgICAgICAgaXRlbXM6IFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHsgdGl0bGU6IFwiQm9sZFwiLCBpbmxpbmU6IFwiYlwiLCB3cmFwcGVyOiBmYWxzZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJJdGFsaWNzXCIsIGlubGluZTogXCJpXCIsIHdyYXBwZXI6IGZhbHNlIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7IHRpdGxlOiBcIlVuZGVybGluZVwiLCBpbmxpbmU6IFwidVwiLCB3cmFwcGVyOiBmYWxzZSB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgeyB0aXRsZTogXCJTZWNyZXRcIiwgaW5saW5lOiBcInNwYW5cIiwgY2xhc3NlczogXCJ0ZXh0LXNlY3JldFwiLCBhdHRyaWJ1dGVzOiB7IFwiZGF0YS1pcy1zZWNyZXRcIjogXCJ0cnVlXCIgfSwgd3JhcHBlcjogZmFsc2UgfVxuICAgICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIHN0eWxlX2Zvcm1hdHNfbWVyZ2U6IGZhbHNlLFxuICAgICAgICAgICAgdG9vbGJhcjogXCJzdHlsZXMgfCBzZWFyY2hyZXBsYWNlIHwgZm9ybWF0dGluZyBhbGlnbm1lbnQgbGlzdHMgZWxlbWVudHMgfCByZW1vdmVmb3JtYXQgfCBjb2RlIHwgc2F2ZVwiLFxuICAgICAgICAgICAgdG9vbGJhcl9ncm91cHM6IHtcbiAgICAgICAgICAgICAgICBmb3JtYXR0aW5nOiB7XG4gICAgICAgICAgICAgICAgICAgIGljb246IFwiY29sb3ItcGlja2VyXCIsXG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiRm9ybWF0dGluZ1wiLFxuICAgICAgICAgICAgICAgICAgICBpdGVtczogXCJib2xkIGl0YWxpYyB1bmRlcmxpbmVcIlxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgYWxpZ25tZW50OiB7XG4gICAgICAgICAgICAgICAgICAgIGljb246IFwiYWxpZ24tbGVmdFwiLFxuICAgICAgICAgICAgICAgICAgICB0b29sdGlwOiBcIkFsaWdubWVudFwiLFxuICAgICAgICAgICAgICAgICAgICBpdGVtczogXCJhbGlnbmxlZnQgYWxpZ25jZW50ZXIgYWxpZ25yaWdodCBhbGlnbmp1c3RpZnkgfCBvdXRkZW50IGluZGVudFwiXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBsaXN0czoge1xuICAgICAgICAgICAgICAgICAgICBpY29uOiBcInVub3JkZXJlZC1saXN0XCIsXG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiTGlzdHNcIixcbiAgICAgICAgICAgICAgICAgICAgaXRlbXM6IFwiYnVsbGlzdCBudW1saXN0XCJcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGVsZW1lbnRzOiB7XG4gICAgICAgICAgICAgICAgICAgIGljb246IFwiZHVwbGljYXRlXCIsXG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IFwiSW5zZXJ0IEVsZW1lbnRcIixcbiAgICAgICAgICAgICAgICAgICAgaXRlbXM6IFwidGFibGVpbnNlcnRkaWFsb2cgaW1hZ2UgaHIgfCB0ZW1wbGF0ZVwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHRvb2xiYXJfbW9kZTogXCJmbG9hdGluZ1wiLFxuICAgICAgICAgICAgcXVpY2tiYXJzX2xpbmtfdG9vbGJhcjogZmFsc2UsXG4gICAgICAgICAgICBxdWlja2JhcnNfc2VsZWN0aW9uX3Rvb2xiYXI6IFwic3R5bGVzIHwgYm9sZCBpdGFsaWMgdW5kZXJsaW5lXCIsXG4gICAgICAgICAgICBxdWlja2JhcnNfaW5zZXJ0X3Rvb2xiYXI6IFwiaHIgaW1hZ2UgdGFibGVcIixcbiAgICAgICAgICAgIHF1aWNrYmFyc190YWJsZV90b29sYmFyOiBcInRhYmxlcHJvcHMgdGFibGVkZWxldGUgfCB0YWJsZWluc2VydHJvd2JlZm9yZSB0YWJsZWluc2VydHJvd2FmdGVyIHRhYmxlZGVsZXRlcm93IHwgdGFibGVpbnNlcnRjb2xiZWZvcmUgdGFibGVpbnNlcnRjb2xhZnRlciB0YWJsZWRlbGV0ZWNvbFwiXG4gICAgICAgIH1cbiAgICB9O1xufVxuLyoqXG4gKlxuICovXG5leHBvcnQgZnVuY3Rpb24gaW5pdENhbnZhc1N0eWxlcygpIHtcbiAgICBDT05GSUcuY2FudmFzVGV4dFN0eWxlID0gbmV3IFBJWEkuVGV4dFN0eWxlKHtcbiAgICAgICAgYWxpZ246IFwiY2VudGVyXCIsXG4gICAgICAgIGRyb3BTaGFkb3c6IHRydWUsXG4gICAgICAgIGRyb3BTaGFkb3dBbmdsZTogVS5kZWdUb1JhZCg0NSksXG4gICAgICAgIGRyb3BTaGFkb3dCbHVyOiA4LFxuICAgICAgICBkcm9wU2hhZG93Q29sb3I6IEMuQ29sb3JzLkJMQUNLLFxuICAgICAgICBkcm9wU2hhZG93RGlzdGFuY2U6IDQsXG4gICAgICAgIGZpbGw6IFtcbiAgICAgICAgICAgIEMuQ29sb3JzLmJXSElURSxcbiAgICAgICAgICAgIEMuQ29sb3JzLmJHUkVZXG4gICAgICAgIF0sXG4gICAgICAgIGZpbGxHcmFkaWVudFR5cGU6IDEsXG4gICAgICAgIGZpbGxHcmFkaWVudFN0b3BzOiBbXG4gICAgICAgICAgICAwLFxuICAgICAgICAgICAgMC4zXG4gICAgICAgIF0sXG4gICAgICAgIGZvbnRGYW1pbHk6IFwiS2lyc3R5XCIsXG4gICAgICAgIGZvbnRTaXplOiAzMixcbiAgICAgICAgbGV0dGVyU3BhY2luZzogMixcbiAgICAgICAgbGluZUhlaWdodDogMzIsXG4gICAgICAgIGxpbmVKb2luOiBcInJvdW5kXCIsXG4gICAgICAgIHBhZGRpbmc6IDQsXG4gICAgICAgIHN0cm9rZTogQy5Db2xvcnMuZEJMQUNLLFxuICAgICAgICBzdHJva2VUaGlja25lc3M6IDMsXG4gICAgICAgIHRyaW06IHRydWUsXG4gICAgICAgIHdoaXRlU3BhY2U6IFwibm9ybWFsXCIsXG4gICAgICAgIHdvcmRXcmFwOiB0cnVlLFxuICAgICAgICB3b3JkV3JhcFdpZHRoOiAwLjFcbiAgICB9KTtcbn1cbmV4cG9ydCBmdW5jdGlvbiBpbml0RE9NU3R5bGVzKCkge1xuICAgIC8vIENyZWF0ZSBhIGZ1bGwtc2NyZWVuIGJhY2tncm91bmQgZ3JhZGllbnQgdGhhdCByZXNlbWJsZXMgdGhlIGdyYWRpZW50IGRlc2NyaWJlZCBpbiBDT05GSUctY2FudmFzVGV4dFN0eWxlc1xuICAgIC8vIFRoaXMgd2lsbCBzZXJ2ZSBhcyBhIGZhbGxiYWNrIGJhY2tncm91bmQgd2hlbiB0aGUgY2FudmFzIGhhcyBiZWVuIGRpc2FibGVkIG9yIGlzIG5vdCBhdmFpbGFibGVcbiAgICAkKFwiYm9keS52dHQuZ2FtZS5zeXN0ZW0tZXVub3MtYmxhZGVzXCIpXG4gICAgICAgIC5hcHBlbmQoYDxkaXYgaWQ9XCJiYWNrc3BsYXNoXCIgc3R5bGU9XCJoZWlnaHQ6IDEwMCU7IHdpZHRoOiAxMDAlOyBwb3NpdGlvbjogYWJzb2x1dGU7IHotaW5kZXg6IC0xOyBiYWNrZ3JvdW5kOiBsaW5lYXItZ3JhZGllbnQoMzVkZWcsICR7Qy5Db2xvcnMuR1JFWX0sICR7Qy5Db2xvcnMuQkxBQ0t9KTtcIj48L2Rpdj5gKTtcbiAgICAvLyBBcHBlbmQgbGlnaHRuaW5nLWJhcnJpZXIgYmFja2dyb3VuZCB0byAjc2lkZWJhclxuICAgICQoXCIjaW50ZXJmYWNlXCIpXG4gICAgICAgIC5hcHBlbmQoYDxkaXYgY2xhc3M9XCJsaWdodG5pbmctYm9yZGVyLWNvbnRhaW5lclwiPlxyXG4gICAgPC9kaXY+YCk7IC8qXG4gICAgICA8aW1nIGNsYXNzPVwiYm9yZGVyLWxpZ2h0bmluZyByaWdodC1saWdodG5pbmcgcmlnaHQtbGlnaHRuaW5nLWFcIiBzcmM9XCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy9hc3NldHMvYW5pbWF0aW9ucy9jaGF0L2VuZXJneS1iZWFtLndlYnBcIiAvPlxuICAgICAgPGltZyBjbGFzcz1cImJvcmRlci1saWdodG5pbmcgcmlnaHQtbGlnaHRuaW5nIHJpZ2h0LWxpZ2h0bmluZy1iXCIgc3JjPVwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2FuaW1hdGlvbnMvY2hhdC9saWdodG5pbmctcmF5LndlYnBcIiAvPlxuICAgICAgPGltZyBjbGFzcz1cImJvcmRlci1saWdodG5pbmcgcmlnaHQtbGlnaHRuaW5nIHJpZ2h0LWxpZ2h0bmluZy1jXCIgc3JjPVwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2FuaW1hdGlvbnMvY2hhdC9saWdodG5pbmctcmF5LndlYnBcIiAvPlxuICAgICAgPGltZyBjbGFzcz1cImJvcmRlci1saWdodG5pbmcgbGVmdC1saWdodG5pbmcgbGVmdC1saWdodG5pbmctYVwiIHNyYz1cInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9hbmltYXRpb25zL2NoYXQvZW5lcmd5LWJlYW0ud2VicFwiIC8+XG4gICAgICA8aW1nIGNsYXNzPVwiYm9yZGVyLWxpZ2h0bmluZyBsZWZ0LWxpZ2h0bmluZyBsZWZ0LWxpZ2h0bmluZy1iXCIgc3JjPVwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2FuaW1hdGlvbnMvY2hhdC9saWdodG5pbmctcmF5LndlYnBcIiAvPlxuICAgICAgPGltZyBjbGFzcz1cImJvcmRlci1saWdodG5pbmcgbGVmdC1saWdodG5pbmcgbGVmdC1saWdodG5pbmctY1wiIHNyYz1cInN5c3RlbXMvZXVub3MtYmxhZGVzL2Fzc2V0cy9hbmltYXRpb25zL2NoYXQvbGlnaHRuaW5nLXJheS53ZWJwXCIgLz5cbiAgICA8L2Rpdj5gKTsgKi9cbn1cbmV4cG9ydCBkZWZhdWx0IHJlZ2lzdGVyU2V0dGluZ3M7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/core/settings.ts\n"); + +/***/ }), + +/***/ "./ts/core/tags.ts": +/*!*************************!*\ + !*** ./ts/core/tags.ts ***! + \*************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _lib_tagify_tagify_esm__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../lib/tagify/tagify.esm */ \"./lib/tagify/tagify.esm.js\");\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./utilities */ \"./ts/core/utilities.ts\");\n\n\n\nconst _onTagifyChange = (event, doc, targetKey) => {\n const tagString = event.target.value;\n if (tagString) {\n const tags = JSON.parse(tagString).map(({ value }) => value);\n doc.update({ [targetKey]: tags });\n }\n else {\n doc.update({ [targetKey]: [] });\n }\n};\nconst Tags = {\n InitListeners: (html, doc) => {\n /**\n * Applies tags and Tagify functionality to a specified HTML element.\n * @param {HTMLElement} elem The element to tagify.\n * @param {Record} tags The tags, sorted into groups, to apply.\n */\n function makeTagInput(elem, tags) {\n // Create tagify instance; populate dropdown list with tags\n const tagify = new _lib_tagify_tagify_esm__WEBPACK_IMPORTED_MODULE_0__[\"default\"](elem, {\n enforceWhitelist: true,\n editTags: false,\n whitelist: Object.entries(tags)\n .map(([dataGroup, tagList]) => tagList\n .map((tag) => ({\n value: (new Handlebars.SafeString(tag)).toString(),\n \"data-group\": dataGroup\n })))\n .flat(),\n dropdown: {\n enabled: 0,\n maxItems: 10000,\n placeAbove: false,\n appendTarget: html[0]\n }\n });\n tagify.dropdown.createListHTML = (optionsArr) => {\n const map = {};\n return structuredClone(optionsArr)\n .map((suggestion, idx) => {\n const value = tagify.dropdown.getMappedValue.call(tagify, suggestion);\n let tagHTMLString = \"\";\n if (!map[suggestion[\"data-group\"]]) {\n map[suggestion[\"data-group\"]] = true;\n if (Object.keys(map).length) {\n tagHTMLString += \"\";\n }\n tagHTMLString += `\r\n
\r\n

${suggestion[\"data-group\"]}

\r\n `;\n }\n suggestion.value =\n value && typeof value === \"string\" ? _utilities__WEBPACK_IMPORTED_MODULE_2__[\"default\"].escapeHTML(value) : value;\n tagHTMLString += tagify.settings.templates.dropdownItem.apply(tagify, [suggestion, idx]);\n return tagHTMLString;\n })\n .join(\"\");\n };\n /**\n * Returns the tag group to which a tag belongs, or false if no group found.\n * @param {BladesTag|string} tag\n * @returns {string|false} Either the group containing the given tag, or false if no group found.\n */\n function findDataGroup(tag) {\n for (const [group, tagList] of Object.entries(tags)) {\n if (tagList.includes(tag)) {\n return group;\n }\n }\n return false;\n }\n // Check if element specifies an alternate schema target from doc.tags\n const targetKey = $(elem).data(\"tagTarget\") ?? \"system.tags\";\n const curTags = [getProperty(doc, targetKey) ?? []].flat().filter(Boolean);\n tagify.addTags(curTags\n .filter(findDataGroup)\n .map((tag) => ({\n value: (new Handlebars.SafeString(tag)).toString(),\n \"data-group\": findDataGroup(tag)\n })), true, true);\n // Add event listener for tag changes, setting defined target\n // Wait briefly, so other tag elements' tags can be set before listener initializes\n setTimeout(() => elem.addEventListener(\"change\", (event) => { _onTagifyChange(event, doc, targetKey); }), 1000);\n }\n const systemTags = {\n \"System Tags\": Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.System),\n \"Gear Tags\": [\n ...Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Gear),\n ...Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.GearCategory)\n ],\n \"Actor Tags\": [\n ...Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.PC),\n ...Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.NPC)\n ],\n Vices: Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Vice),\n Playbooks: Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Playbook),\n Inventions: Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.Invention),\n \"Gang Types\": Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.GangType)\n };\n const districtTags = {\n \"City Districts\": Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.MainDistrict),\n \"Other Districts\": Object.values(_constants__WEBPACK_IMPORTED_MODULE_1__.OtherDistrict)\n };\n const factionTags = { Factions: game.actors\n .filter((actor) => actor.type === _constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.faction && actor.name !== null)\n .map((faction) => faction.name) };\n $(html).find(\".tags-gm\").each((_, e) => makeTagInput(e, systemTags));\n $(html).find(\".tags-district\").each((_, e) => makeTagInput(e, districtTags));\n $(html).find(\".tags-faction\").each((_, e) => makeTagInput(e, factionTags));\n }\n};\n/* harmony default export */ __webpack_exports__[\"default\"] = (Tags);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9jb3JlL3RhZ3MudHMiLCJtYXBwaW5ncyI6Ijs7OztBQUFpRDtBQUMrQztBQUNwRTtBQUM1QjtBQUNBO0FBQ0E7QUFDQSxrREFBa0QsT0FBTztBQUN6RCxxQkFBcUIsbUJBQW1CO0FBQ3hDO0FBQ0E7QUFDQSxxQkFBcUIsaUJBQWlCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixhQUFhO0FBQ2hDLG1CQUFtQiw0QkFBNEI7QUFDL0M7QUFDQTtBQUNBLHVDQUF1QztBQUN2QywrQkFBK0IsOERBQU07QUFDckM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IseUJBQXlCO0FBQy9DO0FBQ0E7QUFDQTtBQUNBLDZEQUE2RCxrREFBQztBQUM5RDtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLGtCQUFrQjtBQUN6Qyx5QkFBeUIsY0FBYztBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSwwRUFBMEUseUNBQXlDO0FBQ25IO0FBQ0E7QUFDQSx5Q0FBeUMsMkNBQUc7QUFDNUM7QUFDQSxpQ0FBaUMsMkNBQUc7QUFDcEMsaUNBQWlDLDJDQUFHO0FBQ3BDO0FBQ0E7QUFDQSxpQ0FBaUMsMkNBQUc7QUFDcEMsaUNBQWlDLDJDQUFHO0FBQ3BDO0FBQ0EsaUNBQWlDLDRDQUFJO0FBQ3JDLHFDQUFxQyxnREFBUTtBQUM3QyxzQ0FBc0MsMkNBQUc7QUFDekMsd0NBQXdDLDJDQUFHO0FBQzNDO0FBQ0E7QUFDQSw0Q0FBNEMsb0RBQVk7QUFDeEQsNkNBQTZDLHFEQUFhO0FBQzFEO0FBQ0EsOEJBQThCO0FBQzlCLGtEQUFrRCx1REFBZTtBQUNqRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxJQUFJLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9jb3JlL3RhZ3MudHM/MGQ4OSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgVGFnaWZ5IGZyb20gXCIuLi8uLi9saWIvdGFnaWZ5L3RhZ2lmeS5lc21cIjtcbmltcG9ydCB7IFRhZywgTWFpbkRpc3RyaWN0LCBPdGhlckRpc3RyaWN0LCBWaWNlLCBQbGF5Ym9vaywgQmxhZGVzQWN0b3JUeXBlIH0gZnJvbSBcIi4vY29uc3RhbnRzXCI7XG5pbXBvcnQgVSBmcm9tIFwiLi91dGlsaXRpZXNcIjtcbmNvbnN0IF9vblRhZ2lmeUNoYW5nZSA9IChldmVudCwgZG9jLCB0YXJnZXRLZXkpID0+IHtcbiAgICBjb25zdCB0YWdTdHJpbmcgPSBldmVudC50YXJnZXQudmFsdWU7XG4gICAgaWYgKHRhZ1N0cmluZykge1xuICAgICAgICBjb25zdCB0YWdzID0gSlNPTi5wYXJzZSh0YWdTdHJpbmcpLm1hcCgoeyB2YWx1ZSB9KSA9PiB2YWx1ZSk7XG4gICAgICAgIGRvYy51cGRhdGUoeyBbdGFyZ2V0S2V5XTogdGFncyB9KTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIGRvYy51cGRhdGUoeyBbdGFyZ2V0S2V5XTogW10gfSk7XG4gICAgfVxufTtcbmNvbnN0IFRhZ3MgPSB7XG4gICAgSW5pdExpc3RlbmVyczogKGh0bWwsIGRvYykgPT4ge1xuICAgICAgICAvKipcbiAgICAgICAgICogQXBwbGllcyB0YWdzIGFuZCBUYWdpZnkgZnVuY3Rpb25hbGl0eSB0byBhIHNwZWNpZmllZCBIVE1MIGVsZW1lbnQuXG4gICAgICAgICAqIEBwYXJhbSB7SFRNTEVsZW1lbnR9IGVsZW0gVGhlIGVsZW1lbnQgdG8gdGFnaWZ5LlxuICAgICAgICAgKiBAcGFyYW0ge1JlY29yZDxzdHJpbmcsQmxhZGVzVGFnW10+fSB0YWdzIFRoZSB0YWdzLCBzb3J0ZWQgaW50byBncm91cHMsIHRvIGFwcGx5LlxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gbWFrZVRhZ0lucHV0KGVsZW0sIHRhZ3MpIHtcbiAgICAgICAgICAgIC8vIENyZWF0ZSB0YWdpZnkgaW5zdGFuY2U7IHBvcHVsYXRlIGRyb3Bkb3duIGxpc3Qgd2l0aCB0YWdzXG4gICAgICAgICAgICBjb25zdCB0YWdpZnkgPSBuZXcgVGFnaWZ5KGVsZW0sIHtcbiAgICAgICAgICAgICAgICBlbmZvcmNlV2hpdGVsaXN0OiB0cnVlLFxuICAgICAgICAgICAgICAgIGVkaXRUYWdzOiBmYWxzZSxcbiAgICAgICAgICAgICAgICB3aGl0ZWxpc3Q6IE9iamVjdC5lbnRyaWVzKHRhZ3MpXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKFtkYXRhR3JvdXAsIHRhZ0xpc3RdKSA9PiB0YWdMaXN0XG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKHRhZykgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IChuZXcgSGFuZGxlYmFycy5TYWZlU3RyaW5nKHRhZykpLnRvU3RyaW5nKCksXG4gICAgICAgICAgICAgICAgICAgIFwiZGF0YS1ncm91cFwiOiBkYXRhR3JvdXBcbiAgICAgICAgICAgICAgICB9KSkpXG4gICAgICAgICAgICAgICAgICAgIC5mbGF0KCksXG4gICAgICAgICAgICAgICAgZHJvcGRvd246IHtcbiAgICAgICAgICAgICAgICAgICAgZW5hYmxlZDogMCxcbiAgICAgICAgICAgICAgICAgICAgbWF4SXRlbXM6IDEwMDAwLFxuICAgICAgICAgICAgICAgICAgICBwbGFjZUFib3ZlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgYXBwZW5kVGFyZ2V0OiBodG1sWzBdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB0YWdpZnkuZHJvcGRvd24uY3JlYXRlTGlzdEhUTUwgPSAob3B0aW9uc0FycikgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IG1hcCA9IHt9O1xuICAgICAgICAgICAgICAgIHJldHVybiBzdHJ1Y3R1cmVkQ2xvbmUob3B0aW9uc0FycilcbiAgICAgICAgICAgICAgICAgICAgLm1hcCgoc3VnZ2VzdGlvbiwgaWR4KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gdGFnaWZ5LmRyb3Bkb3duLmdldE1hcHBlZFZhbHVlLmNhbGwodGFnaWZ5LCBzdWdnZXN0aW9uKTtcbiAgICAgICAgICAgICAgICAgICAgbGV0IHRhZ0hUTUxTdHJpbmcgPSBcIlwiO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIW1hcFtzdWdnZXN0aW9uW1wiZGF0YS1ncm91cFwiXV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hcFtzdWdnZXN0aW9uW1wiZGF0YS1ncm91cFwiXV0gPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKE9iamVjdC5rZXlzKG1hcCkubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFnSFRNTFN0cmluZyArPSBcIjwvZGl2PlwiO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdGFnSFRNTFN0cmluZyArPSBgXHJcbiAgICAgICAgICAgICAgICA8ZGl2IGNsYXNzPVwidGFnaWZ5X19kcm9wZG93bl9faXRlbXNHcm91cFwiPlxyXG4gICAgICAgICAgICAgICAgPGgzPiR7c3VnZ2VzdGlvbltcImRhdGEtZ3JvdXBcIl19PC9oMz5cclxuICAgICAgICAgICAgICBgO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHN1Z2dlc3Rpb24udmFsdWUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiID8gVS5lc2NhcGVIVE1MKHZhbHVlKSA6IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICB0YWdIVE1MU3RyaW5nICs9IHRhZ2lmeS5zZXR0aW5ncy50ZW1wbGF0ZXMuZHJvcGRvd25JdGVtLmFwcGx5KHRhZ2lmeSwgW3N1Z2dlc3Rpb24sIGlkeF0pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGFnSFRNTFN0cmluZztcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuam9pbihcIlwiKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAqIFJldHVybnMgdGhlIHRhZyBncm91cCB0byB3aGljaCBhIHRhZyBiZWxvbmdzLCBvciBmYWxzZSBpZiBubyBncm91cCBmb3VuZC5cbiAgICAgICAgICAgICAqIEBwYXJhbSB7QmxhZGVzVGFnfHN0cmluZ30gdGFnXG4gICAgICAgICAgICAgKiBAcmV0dXJucyB7c3RyaW5nfGZhbHNlfSBFaXRoZXIgdGhlIGdyb3VwIGNvbnRhaW5pbmcgdGhlIGdpdmVuIHRhZywgb3IgZmFsc2UgaWYgbm8gZ3JvdXAgZm91bmQuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIGZ1bmN0aW9uIGZpbmREYXRhR3JvdXAodGFnKSB7XG4gICAgICAgICAgICAgICAgZm9yIChjb25zdCBbZ3JvdXAsIHRhZ0xpc3RdIG9mIE9iamVjdC5lbnRyaWVzKHRhZ3MpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0YWdMaXN0LmluY2x1ZGVzKHRhZykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBncm91cDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBDaGVjayBpZiBlbGVtZW50IHNwZWNpZmllcyBhbiBhbHRlcm5hdGUgc2NoZW1hIHRhcmdldCBmcm9tIGRvYy50YWdzXG4gICAgICAgICAgICBjb25zdCB0YXJnZXRLZXkgPSAkKGVsZW0pLmRhdGEoXCJ0YWdUYXJnZXRcIikgPz8gXCJzeXN0ZW0udGFnc1wiO1xuICAgICAgICAgICAgY29uc3QgY3VyVGFncyA9IFtnZXRQcm9wZXJ0eShkb2MsIHRhcmdldEtleSkgPz8gW11dLmZsYXQoKS5maWx0ZXIoQm9vbGVhbik7XG4gICAgICAgICAgICB0YWdpZnkuYWRkVGFncyhjdXJUYWdzXG4gICAgICAgICAgICAgICAgLmZpbHRlcihmaW5kRGF0YUdyb3VwKVxuICAgICAgICAgICAgICAgIC5tYXAoKHRhZykgPT4gKHtcbiAgICAgICAgICAgICAgICB2YWx1ZTogKG5ldyBIYW5kbGViYXJzLlNhZmVTdHJpbmcodGFnKSkudG9TdHJpbmcoKSxcbiAgICAgICAgICAgICAgICBcImRhdGEtZ3JvdXBcIjogZmluZERhdGFHcm91cCh0YWcpXG4gICAgICAgICAgICB9KSksIHRydWUsIHRydWUpO1xuICAgICAgICAgICAgLy8gQWRkIGV2ZW50IGxpc3RlbmVyIGZvciB0YWcgY2hhbmdlcywgc2V0dGluZyBkZWZpbmVkIHRhcmdldFxuICAgICAgICAgICAgLy8gV2FpdCBicmllZmx5LCBzbyBvdGhlciB0YWcgZWxlbWVudHMnIHRhZ3MgY2FuIGJlIHNldCBiZWZvcmUgbGlzdGVuZXIgaW5pdGlhbGl6ZXNcbiAgICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4gZWxlbS5hZGRFdmVudExpc3RlbmVyKFwiY2hhbmdlXCIsIChldmVudCkgPT4geyBfb25UYWdpZnlDaGFuZ2UoZXZlbnQsIGRvYywgdGFyZ2V0S2V5KTsgfSksIDEwMDApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHN5c3RlbVRhZ3MgPSB7XG4gICAgICAgICAgICBcIlN5c3RlbSBUYWdzXCI6IE9iamVjdC52YWx1ZXMoVGFnLlN5c3RlbSksXG4gICAgICAgICAgICBcIkdlYXIgVGFnc1wiOiBbXG4gICAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyhUYWcuR2VhciksXG4gICAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyhUYWcuR2VhckNhdGVnb3J5KVxuICAgICAgICAgICAgXSxcbiAgICAgICAgICAgIFwiQWN0b3IgVGFnc1wiOiBbXG4gICAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyhUYWcuUEMpLFxuICAgICAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXMoVGFnLk5QQylcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBWaWNlczogT2JqZWN0LnZhbHVlcyhWaWNlKSxcbiAgICAgICAgICAgIFBsYXlib29rczogT2JqZWN0LnZhbHVlcyhQbGF5Ym9vayksXG4gICAgICAgICAgICBJbnZlbnRpb25zOiBPYmplY3QudmFsdWVzKFRhZy5JbnZlbnRpb24pLFxuICAgICAgICAgICAgXCJHYW5nIFR5cGVzXCI6IE9iamVjdC52YWx1ZXMoVGFnLkdhbmdUeXBlKVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBkaXN0cmljdFRhZ3MgPSB7XG4gICAgICAgICAgICBcIkNpdHkgRGlzdHJpY3RzXCI6IE9iamVjdC52YWx1ZXMoTWFpbkRpc3RyaWN0KSxcbiAgICAgICAgICAgIFwiT3RoZXIgRGlzdHJpY3RzXCI6IE9iamVjdC52YWx1ZXMoT3RoZXJEaXN0cmljdClcbiAgICAgICAgfTtcbiAgICAgICAgY29uc3QgZmFjdGlvblRhZ3MgPSB7IEZhY3Rpb25zOiBnYW1lLmFjdG9yc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGFjdG9yKSA9PiBhY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUuZmFjdGlvbiAmJiBhY3Rvci5uYW1lICE9PSBudWxsKVxuICAgICAgICAgICAgICAgIC5tYXAoKGZhY3Rpb24pID0+IGZhY3Rpb24ubmFtZSkgfTtcbiAgICAgICAgJChodG1sKS5maW5kKFwiLnRhZ3MtZ21cIikuZWFjaCgoXywgZSkgPT4gbWFrZVRhZ0lucHV0KGUsIHN5c3RlbVRhZ3MpKTtcbiAgICAgICAgJChodG1sKS5maW5kKFwiLnRhZ3MtZGlzdHJpY3RcIikuZWFjaCgoXywgZSkgPT4gbWFrZVRhZ0lucHV0KGUsIGRpc3RyaWN0VGFncykpO1xuICAgICAgICAkKGh0bWwpLmZpbmQoXCIudGFncy1mYWN0aW9uXCIpLmVhY2goKF8sIGUpID0+IG1ha2VUYWdJbnB1dChlLCBmYWN0aW9uVGFncykpO1xuICAgIH1cbn07XG5leHBvcnQgZGVmYXVsdCBUYWdzO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/core/tags.ts\n"); + +/***/ }), + +/***/ "./ts/core/utilities.ts": +/*!******************************!*\ + !*** ./ts/core/utilities.ts ***! + \******************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var gsap_all__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! gsap/all */ \"gsap/all\");\n/* harmony import */ var gsap_all__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(gsap_all__WEBPACK_IMPORTED_MODULE_1__);\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// /// \n// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~\n\n// eslint-disable-next-line import/no-unresolved\n\ngsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.registerPlugin(gsap_all__WEBPACK_IMPORTED_MODULE_1__.MotionPathPlugin);\n// #endregion ▮▮▮▮ IMPORTS ▮▮▮▮\n// #region ▮▮▮▮▮▮▮ [HELPERS] Internal Functions, Data & References Used by Utility Functions ▮▮▮▮▮▮▮ ~\n// _noCapWords -- Patterns matching words that should NOT be capitalized when converting to TITLE case.\nconst _noCapWords = \"a|above|after|an|and|at|below|but|by|down|for|for|from|in|nor|of|off|on|onto|or|out|so|the|to|under|up|with|yet\"\n .split(\"|\")\n .map((word) => new RegExp(`\\\\b${word}\\\\b`, \"gui\"));\n// _capWords -- Patterns matching words that should ALWAYS be capitalized when converting to SENTENCE case.\nconst _capWords = [\n \"I\", /[^a-z]{3,}|[.0-9]/gu\n].map((word) => (/RegExp/.test(Object.prototype.toString.call(word)) ? word : new RegExp(`\\\\b${word}\\\\b`, \"gui\")));\n// _loremIpsumText -- Boilerplate lorem ipsum\nconst _loremIpsumText = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ultricies\r\nnibh sed massa euismod lacinia. Aliquam nec est ac nunc ultricies scelerisque porta vulputate odio.\r\nInteger gravida mattis odio, semper volutpat tellus. Ut elit leo, auctor eget fermentum hendrerit,\r\naliquet ac nunc. Suspendisse porta turpis vitae mi posuere molestie. Cras lectus lacus, vulputate a\r\nvestibulum in, mattis vel mi. Mauris quis semper mauris. Praesent blandit nec diam eget tincidunt. Nunc\r\naliquet consequat massa ac lacinia. Ut posuere velit sagittis, vehicula nisl eget, fringilla nibh. Duis\r\nvolutpat mattis libero, a porttitor sapien viverra ut. Phasellus vulputate imperdiet ligula, eget\r\neleifend metus tempor nec. Nam eget sapien risus. Praesent id suscipit elit. Sed pellentesque ligula\r\ndiam, non aliquet magna feugiat vitae. Pellentesque ut tortor id erat placerat dignissim. Pellentesque\r\nut dui vel leo laoreet sodales nec ac tellus. In hac habitasse platea dictumst. Proin sed ex sed augue\r\nsollicitudin interdum. Sed id lacus porttitor nisi vestibulum tincidunt. Nulla facilisi. Vestibulum\r\nfeugiat finibus magna in pretium. Proin consectetur lectus nisi, non commodo lectus tempor et. Cras\r\nviverra, mi in consequat aliquet, justo mauris fringilla tellus, at accumsan magna metus in eros. Sed\r\nvehicula, diam ut sagittis semper, purus massa mattis dolor, in posuere.`;\n// _randomWords -- A collection of random words for various debugging purposes.\nconst _randomWords = `\r\naboveboard|account|achiever|acoustics|act|action|activity|actor|addition|adjustment|advertisement|advice|afterglow|afterimage|afterlife|aftermath|afternoon|afterthought|agreement\r\nair|aircraft|airfield|airlift|airline|airmen|airplane|airport|airtime|alarm|allover|allspice|alongside|also|amount|amusement|anger|angle|animal|another|ants|anyhow|anymore\r\nanyone|anyplace|anytime|anywhere|apparatus|apparel|appliance|approval|arch|argument|arithmetic|arm|army|around|art|ashtray|attack|attraction|aunt|authority|babies|baby|babysitter\r\nback|backache|backbone|backbreaker|backdrop|backfire|background|backhand|backlash|backlog|backpack|backside|backslap|backslide|backspace|backspin|backstroke|backtrack|backward\r\nbadge|bag|bait|balance|ball|ballroom|bankbook|bankroll|base|baseball|basin|basket|basketball|bat|bath|battle|beachcomb|bead|bear|because|become|bed|bedrock|bedroll|bedroom\r\nbeds|bee|beef|beginner|behavior|belief|believe|bell|bellboy|bellhop|bells|below|berry|bike|bikes|bird|birds|birth|birthday|bit|bite|blackball|blackberries|blackbird|blackboard\r\nblackjack|blacklist|blackmail|blackout|blacksmith|blacktop|blade|blood|blow|blowgun|bluebell|blueberry|bluebird|bluefish|bluegrass|blueprint|board|boardwalk|boat|bodyguard\r\nbomb|bone|book|bookcase|bookend|bookkeeper|bookmark|bookmobile|books|bookseller|bookshelf|bookworm|boot|border|bottle|boundary|bowlegs|bowtie|box|boy|brainchild|brake|branch\r\nbrass|breath|brick|bridge|brother|bubble|bucket|bugspray|building|bulb|burst|bushes|business|butter|butterball|buttercup|butterfingers|buttermilk|butternut|butterscotch|button\r\nbypass|cabbage|cabdriver|cable|cactus|cake|cakes|calculator|calendar|camera|camp|can|cancan|candlelight|candlestick|cannon|cannot|canvas|cap|caption|car|card|cardsharp|care\r\ncarefree|careworn|carfare|carload|carpenter|carpool|carport|carriage|cars|carsick|cart|cartwheel|cast|cat|cats|cattle|catwalk|cause|cave|caveman|celery|cellar|cemetery|cent\r\ncentercut|chalk|chance|change|channel|cheese|cheeseburger|cherries|cherry|chess|chicken|chickens|children|chin|church|circle|clam|class|clockwise|cloth|clover|club|coach|coal\r\ncoast|coat|cobweb|coffeemaker|coil|collar|color|comeback|committee|commonplace|commonwealth|company|comparison|competition|condition|connection|control|cook|copper|corn|cornmeal\r\ncough|country|courthouse|cover|cow|cows|crack|cracker|crate|crayon|cream|creator|creature|credit|crewcut|crib|crime|crook|crossbow|crossbreed|crosscut|crossover|crosswalk\r\ncrow|crowd|crown|cub|cup|current|curtain|curve|cushion|dad|dairymaid|daisywheel|daughter|day|daybed|daybook|daybreak|daydream|daylight|daytime|deadend|deadline|death|debt\r\ndecision|deer|degree|design|desire|desk|destruction|detail|development|digestion|dime|dinner|dinosaurs|direction|dirt|discovery|discussion|dishcloth|dishpan|dishwasher|dishwater\r\ndiskdrive|distance|distribution|division|dock|doctor|dog|dogs|doll|dolls|donkey|door|doorstop|downtown|downunder|drain|drawbridge|drawer|dress|drink|driveway|driving|drop\r\nduck|duckbill|duckpin|ducks|dust|ear|earache|earring|earth|earthquake|earthward|earthworm|edge|education|effect|egg|egghead|eggnog|eggs|eggshell|elbow|end|engine|error|event\r\neverything|example|exchange|existence|expansion|experience|expert|eye|eyeballs|eyecatching|eyeglasses|eyelash|eyelid|eyes|eyesight|eyewitness|face|fact|fairies|fall|fang|farm\r\nfatherland|fear|feeling|field|finger|fire|fireball|fireboat|firebomb|firebreak|firecracker|firefighter|firehouse|fireman|fireproof|fireworks|fish|fishbowl|fisherman|fisheye\r\nfishhook|fishmonger|fishnet|fishpond|fishtail|flag|flame|flavor|flesh|flight|flock|floor|flower|flowers|fly|fog|fold|food|foot|football|foothill|footlights|footlocker|footprints\r\nforbearer|force|forearm|forebear|forebrain|forecast|foreclose|foreclosure|foredoom|forefather|forefeet|forefinger|forefoot|forego|foregone|forehand|forehead|foreknowledge\r\nforeleg|foreman|forepaws|foresee|foreshadow|forestall|forethought|foretold|forever|forewarn|foreword|forget|fork|forklift|form|fowl|frame|friction|friend|friends|frog|frogs\r\nfront|fruit|fruitcup|fuel|furniture|gate|gearshift|geese|ghost|giants|giraffe|girl|girls|glass|glassmaking|glove|gold|goodbye|goodnight|government|governor|grade|grain|grandaunt\r\ngranddaughter|grandfather|grandmaster|grandmother|grandnephew|grandparent|grandson|grandstand|granduncle|grape|grass|grassland|graveyard|grip|ground|group|growth|guide|guitar\r\ngumball|gun|hair|haircut|hall|hamburger|hammer|hand|handbook|handgun|handmade|handout|hands|harbor|harmony|hat|hate|head|headache|headlight|headline|headquarters|health|heat\r\nhereafter|hereby|herein|hereupon|highchair|highland|highway|hill|himself|history|hobbies|hole|holiday|home|homemade|hometown|honey|honeybee|honeydew|honeysuckle|hook|hookup\r\nhope|horn|horse|horseback|horsefly|horsehair|horseman|horseplay|horsepower|horseradish|horses|hose|hospital|hot|hour|house|houseboat|household|housekeeper|houses|housetop\r\nhowever|humor|hydrant|ice|icicle|idea|impulse|income|increase|industry|ink|insect|inside|instrument|insurance|intake|interest|invention|iron|island|itself|jail|jailbait|jam\r\njar|jeans|jelly|jellybean|jellyfish|jetliner|jetport|jewel|join|judge|juice|jump|jumpshot|kettle|key|keyboard|keyhole|keynote|keypad|keypunch|keystone|keystroke|keyword|kick\r\nkiss|kittens|kitty|knee|knife|knot|knowledge|laborer|lace|ladybug|lake|lamp|land|language|laugh|leather|leg|legs|letter|letters|lettuce|level|library|lifeblood|lifeguard|lifelike\r\nlifeline|lifelong|lifetime|lifework|limelight|limestone|limit|line|linen|lip|liquid|loaf|lock|locket|longhand|look|loss|love|low|lukewarm|lumber|lunch|lunchroom|machine|magic\r\nmaid|mailbox|mainline|man|marble|mark|market|mask|mass|match|matchbox|meal|meantime|meanwhile|measure|meat|meeting|memory|men|metal|mice|middle|milk|mind|mine|minister|mint\r\nminute|mist|mitten|mom|money|monkey|month|moon|moonbeam|moonlight|moonlit|moonscape|moonshine|moonstruck|moonwalk|moreover|morning|mother|motion|motorcycle|mountain|mouth\r\nmove|muscle|name|nation|nearby|neck|need|needle|nerve|nest|nevermore|newsboy|newsbreak|newscaster|newsdealer|newsletter|newsman|newspaper|newsprint|newsreel|newsroom|night\r\nnightfall|nobody|noise|noisemaker|north|northeast|nose|note|notebook|nowhere|number|nursemaid|nut|nutcracker|oatmeal|observation|ocean|offer|office|oil|oneself|onetime|orange\r\noranges|order|oven|overboard|overcoat|overflow|overland|pacemaker|page|pail|pan|pancake|paper|parcel|part|partner|party|passbook|passenger|passkey|Passover|passport|payment\r\npeace|pear|pen|pencil|peppermint|person|pest|pet|pets|pickle|pickup|picture|pie|pies|pig|pigs|pin|pinhole|pinstripe|pinup|pinwheel|pipe|pizzas|place|plane|planes|plant|plantation\r\nplants|plastic|plate|play|playback|playground|playhouse|playthings|pleasure|plot|plough|pocket|point|poison|pollution|ponytail|popcorn|porter|position|postcard|pot|potato\r\npowder|power|price|produce|profit|property|prose|protest|pull|pump|punishment|purpose|push|quarter|quartz|queen|question|quicksand|quiet|quill|quilt|quince|quiver|rabbit|rabbits\r\nracquetball|rail|railroad|railway|rain|raincheck|raincoat|rainstorm|rainwater|rake|range|rat|rate|rattlesnake|rattletrap|ray|reaction|reading|reason|receipt|recess|record\r\nregret|relation|religion|repairman|representative|request|respect|rest|reward|rhythm|rice|riddle|rifle|ring|rings|river|riverbanks|road|robin|rock|rod|roll|roof|room|root\r\nrose|route|rub|rubberband|rule|run|sack|sail|sailboat|salesclerk|salt|sand|sandlot|sandstone|saucepan|scale|scapegoat|scarecrow|scarf|scene|scent|school|schoolbook|schoolboy\r\nschoolbus|schoolhouse|science|scissors|screw|sea|seashore|seat|secretary|seed|selection|self|sense|servant|shade|shadyside|shake|shame|shape|sharecropper|sharpshooter|sheep\r\nsheepskin|sheet|shelf|ship|shirt|shock|shoe|shoelace|shoemaker|shoes|shop|shortbread|show|showoff|showplace|side|sidekick|sidewalk|sign|silk|silver|silversmith|sink|sister\r\nsisterhood|sisters|sixfold|size|skate|skateboard|skin|skintight|skirt|sky|skylark|skylight|slave|sleep|sleet|slip|slope|slowdown|slumlord|smash|smell|smile|smoke|snail|snails\r\nsnake|snakes|snakeskin|sneeze|snow|snowball|snowbank|snowbird|snowdrift|snowshovel|soap|society|sock|soda|sofa|softball|somebody|someday|somehow|someone|someplace|something\r\nsometimes|somewhat|somewhere|son|song|songs|sort|sound|soundproof|soup|southeast|southwest|soybean|space|spacewalk|spade|spark|spearmint|spiders|spillway|spokesperson|sponge\r\nspoon|spot|spring|spy|square|squirrel|stage|stagehand|stamp|standby|standoff|standout|standpoint|star|starfish|start|statement|station|steam|steamship|steel|stem|step|stepson\r\nstew|stick|sticks|stitch|stocking|stockroom|stomach|stone|stop|stoplight|stopwatch|store|story|stove|stranger|straw|stream|street|stretch|string|stronghold|structure|substance\r\nsubway|sugar|suggestion|suit|summer|sun|sunbaked|sunbathe|sundial|sundown|sunfish|sunflower|sunglasses|sunlit|sunray|sunroof|sunup|supercargo|supercharge|supercool|superego\r\nsuperfine|supergiant|superhero|superhighways|superhuman|superimpose|supermarket|supermen|supernatural|superpower|superscript|supersensitive|supersonic|superstar|superstrong\r\nsuperstructure|supertanker|superweapon|superwoman|support|surprise|sweater|sweetheart|sweetmeat|swim|swing|system|table|tablecloth|tablespoon|tabletop|tableware|tail|tailcoat\r\ntailgate|taillight|taillike|tailpiece|tailspin|takeoff|takeout|takeover|talebearer|taleteller|talk|tank|tapeworm|taproom|taproot|target|taskmaster|taste|tax|taxicab|taxpayer\r\nteaching|teacup|team|teammate|teamwork|teapot|teaspoon|teenager|teeth|telltale|temper|tendency|tenderfoot|tenfold|tent|territory|test|textbook|texture|theory|therefore|thing\r\nthings|thought|thread|thrill|throat|throne|throwaway|throwback|thumb|thunder|thunderbird|thunderstorm|ticket|tiger|time|timekeeper|timesaving|timeshare|timetable|tin|title\r\ntoad|toe|toes|together|tomatoes|tongue|toolbox|tooth|toothbrush|toothpaste|toothpick|top|touch|touchdown|town|township|toy|toys|trade|trail|train|trains|tramp|transport|tray\r\ntreatment|tree|trees|trick|trip|trouble|trousers|truck|trucks|tub|turkey|turn|turnabout|turnaround|turnbuckle|turndown|turnkey|turnoff|turntable|twig|twist|typewriter|umbrella\r\nuncle|underachieve|underage|underarm|underbelly|underbid|undercharge|underclothes|undercover|undercut|underdevelop|underestimate|underexpose|underfoot|underground|underwear\r\nunit|upbeat|upbringing|upcoming|update|upend|upgrade|upheaval|uphill|uphold|upkeep|upland|uplift|upload|upmarket|upon|uppercase|upperclassman|uppercut|uproar|uproot|upset\r\nupshot|upside|upstage|upstairs|upstanding|upstart|upstate|upstream|uptake|upthrust|uptight|uptime|uptown|upward|upwind|use|vacation|value|van|vase|vegetable|veil|vein|verse\r\nvessel|vest|view|visitor|voice|volcano|volleyball|voyage|waistline|walk|walkways|wall|walleyed|wallpaper|war|wardroom|warfare|warmblooded|warpath|wash|washbowl|washcloth|washhouse\r\nwashout|washrag|washroom|washstand|washtub|waste|wastebasket|wasteland|wastepaper|wastewater|watch|watchband|watchdog|watchmaker|watchman|watchtower|watchword|water|watercolor\r\nwatercooler|watercraft|waterfall|waterfront|waterline|waterlog|watermelon|waterpower|waterproof|waterscape|watershed|waterside|waterspout|watertight|wave|wavelike|waves|wax\r\nwaxwork|way|waybill|wayfarer|waylaid|wayside|wayward|wealth|weather|weathercock|weatherman|weatherproof|week|weekday|weekend|weeknight|weight|whatever|whatsoever|wheel|wheelchair\r\nwheelhouse|whip|whistle|whitecap|whitefish|whitewall|whitewash|widespread|wilderness|wind|window|wine|wing|winter|wipeout|wire|wish|without|woman|women|wood|woodshop|wool\r\nword|work|worm|wound|wren|wrench|wrist|writer|writing|yak|yam|yard|yarn|year|yoke|zebra|zephyr|zinc|zipper|zoo\r\n`.split(\"|\");\nconst _numberWords = {\n ones: [\n \"zero\", \"one\", \"two\", \"three\", \"four\", \"five\", \"six\", \"seven\", \"eight\", \"nine\",\n \"ten\", \"eleven\", \"twelve\", \"thirteen\", \"fourteen\", \"fifteen\", \"sixteen\", \"seventeen\", \"eighteen\", \"nineteen\",\n \"twenty\"\n ],\n tens: [\"\", \"\", \"twenty\", \"thirty\", \"forty\", \"fifty\", \"sixty\", \"seventy\", \"eighty\", \"ninety\"],\n tiers: [\"\", \"thousand\", \"million\", \"billion\", \"trillion\", \"quadrillion\", \"quintillion\", \"sextillion\", \"septillion\", \"octillion\", \"nonillion\"],\n bigPrefixes: [\"\", \"un\", \"duo\", \"tre\", \"quattuor\", \"quin\", \"sex\", \"octo\", \"novem\"],\n bigSuffixes: [\"\", \"decillion\", \"vigintillion\", \"trigintillion\", \"quadragintillion\", \"quinquagintillion\", \"sexagintillion\", \"septuagintillion\", \"octogintillion\", \"nonagintillion\", \"centillion\"]\n};\nconst _ordinals = {\n zero: \"zeroeth\", one: \"first\", two: \"second\", three: \"third\", four: \"fourth\", five: \"fifth\", eight: \"eighth\", nine: \"ninth\", twelve: \"twelfth\",\n twenty: \"twentieth\", thirty: \"thirtieth\", forty: \"fortieth\", fifty: \"fiftieth\", sixty: \"sixtieth\", seventy: \"seventieth\", eighty: \"eightieth\", ninety: \"ninetieth\"\n};\nconst _romanNumerals = {\n grouped: [\n [\"\", \"Ⅰ\", \"Ⅱ\", \"Ⅲ\", \"Ⅳ\", \"Ⅴ\", \"Ⅵ\", \"Ⅶ\", \"Ⅷ\", \"Ⅸ\"],\n [\"\", \"Ⅹ\", \"ⅩⅩ\", \"ⅩⅩⅩ\", \"ⅩⅬ\", \"Ⅼ\", \"ⅬⅩ\", \"ⅬⅩⅩ\", \"ⅬⅩⅩⅩ\", \"ⅩⅭ\"],\n [\"\", \"Ⅽ\", \"ⅭⅭ\", \"ⅭⅭⅭ\", \"ⅭⅮ\", \"Ⅾ\", \"ⅮⅭ\", \"ⅮⅭⅭ\", \"ⅮⅭⅭⅭ\", \"ⅭⅯ\"],\n [\"\", \"Ⅿ\", \"ⅯⅯ\", \"ⅯⅯⅯ\", \"Ⅿↁ\", \"ↁ\", \"ↁⅯ\", \"ↁⅯⅯ\", \"ↁⅯⅯⅯ\", \"ↁↂ\"],\n [\"\", \"ↂ\", \"ↂↂ\", \"ↂↂↂ\", \"ↂↇ\", \"ↇ\", \"ↇↂ\", \"ↇↂↂ\", \"ↇↂↂↂ\", \"ↇↈ\"],\n [\"\", \"ↈ\", \"ↈↈ\", \"ↈↈↈ\"]\n ],\n ungrouped: [\n [\"\", \"Ⅰ\", \"ⅠⅠ\", \"ⅠⅠⅠ\", \"ⅠⅤ\", \"Ⅴ\", \"ⅤⅠ\", \"ⅤⅠⅠ\", \"ⅤⅠⅠⅠ\", \"ⅠⅩ\"],\n [\"\", \"Ⅹ\", \"ⅩⅩ\", \"ⅩⅩⅩ\", \"ⅩⅬ\", \"Ⅼ\", \"ⅬⅩ\", \"ⅬⅩⅩ\", \"ⅬⅩⅩⅩ\", \"ⅩⅭ\"],\n [\"\", \"Ⅽ\", \"ⅭⅭ\", \"ⅭⅭⅭ\", \"ⅭⅮ\", \"Ⅾ\", \"ⅮⅭ\", \"ⅮⅭⅭ\", \"ⅮⅭⅭⅭ\", \"ⅭⅯ\"],\n [\"\", \"Ⅿ\", \"ⅯⅯ\", \"ⅯⅯⅯ\", \"Ⅿↁ\", \"ↁ\", \"ↁⅯ\", \"ↁⅯⅯ\", \"ↁⅯⅯⅯ\", \"ↁↂ\"],\n [\"\", \"ↂ\", \"ↂↂ\", \"ↂↂↂ\", \"ↂↇ\", \"ↇ\", \"ↇↂ\", \"ↇↂↂ\", \"ↇↂↂↂ\", \"ↇↈ\"],\n [\"\", \"ↈ\", \"ↈↈ\", \"ↈↈↈ\"]\n ]\n};\nconst UUIDLOG = [];\n// #endregion ▮▮▮▮[HELPERS]▮▮▮▮\n// #region ████████ GETTERS: Basic Data Lookup & Retrieval ████████ ~\n// @ts-expect-error Leauge of foundry developers is wrong about user not being on game.\nconst GMID = () => game?.user?.find((user) => user.isGM)?.id ?? false;\n// #endregion ▄▄▄▄▄ GETTERS ▄▄▄▄▄\n// #region ████████ TYPES: Type Checking, Validation, Conversion, Casting ████████ ~\nconst isNumber = (ref) => typeof ref === \"number\" && !isNaN(ref);\nconst isNumString = (ref) => typeof ref === \"string\"\n && !isNaN(parseFloat(ref))\n && isFinite(parseFloat(ref));\nconst isBooleanString = (ref) => typeof ref === \"string\"\n && (ref === \"true\" || ref === \"false\");\nconst isArray = (ref) => Array.isArray(ref);\nconst isSimpleObj = (ref) => ref === Object(ref) && !isArray(ref);\nconst isList = (ref) => ref === Object(ref) && !isArray(ref);\nconst isFunc = (ref) => typeof ref === \"function\";\nconst isInt = (ref) => isNumber(ref) && Math.round(ref) === ref;\nconst isFloat = (ref) => isNumber(ref) && /\\./.test(`${ref}`);\nconst isPosInt = (ref) => isInt(ref) && ref >= 0;\nconst isIndex = (ref) => isList(ref) || isArray(ref);\nconst isIterable = (ref) => typeof ref === \"object\" && ref !== null && Symbol.iterator in ref;\nconst isHTMLCode = (ref) => typeof ref === \"string\" && /^<.*>$/u.test(ref);\nconst isHexColor = (ref) => typeof ref === \"string\" && /^#(([0-9a-fA-F]{2}){3,4}|[0-9a-fA-F]{3,4})$/.test(ref);\nconst isRGBColor = (ref) => typeof ref === \"string\" && /^rgba?\\((\\d{1,3},\\s*){1,2}?\\d{1,3},\\s*\\d{1,3}(\\.\\d+)?\\)$/.test(ref);\nconst isUndefined = (ref) => ref === undefined;\nconst isDefined = (ref) => !isUndefined(ref);\nconst isEmpty = (ref) => Object.keys(ref).length === 0;\nconst hasItems = (ref) => !isEmpty(ref);\nconst isInstance = (classRef, ref) => ref instanceof classRef;\nconst isNullish = (ref) => isUndefined(ref) || ref === null;\n/**\n * Asserts that a given value is of a specified type.\n * Throws an error if the value is not of the expected type.\n *\n * @template T The expected type of the value.\n * @param {unknown} val The value to check.\n * @param {(new(...args: unknown[]) => T) | string} type The expected type of the value.\n * @throws {Error} If the value is not of the expected type.\n */\nfunction assertNonNullType(val, type) {\n let valStr;\n // Attempt to convert the value to a string for error messaging.\n try {\n valStr = JSON.stringify(val);\n }\n catch {\n valStr = String(val);\n }\n // Check if the value is undefined\n if (val === undefined) {\n throw new Error(`Value ${valStr} is undefined!`);\n }\n // If the type is a string, compare the typeof the value to the type string.\n if (typeof type === \"string\") {\n // eslint-disable-next-line valid-typeof\n if (typeof val !== type) {\n throw new Error(`Value ${valStr} is not a ${type}!`);\n }\n }\n else if (!(val instanceof type)) {\n // If the type is a function (constructor), check if the value is an instance of the type.\n throw new Error(`Value ${valStr} is not a ${type.name}!`);\n }\n}\n/**\n * Checks if two values are \"fuzzy\" equal, simulating the behavior of the \"==\" operator.\n * This function does not use the \"==\" operator directly to comply with linting rules.\n *\n * @param {unknown} val1 The first value to compare.\n * @param {unknown} val2 The second value to compare.\n * @returns {boolean} True if the values are \"fuzzy\" equal, false otherwise.\n */\nconst areFuzzyEqual = (val1, val2) => {\n // If both values are null or undefined, they are considered equal\n if ([null, undefined].includes(val1)\n && [null, undefined].includes(val2)) {\n return true;\n }\n // If only one of the values is null or undefined, they are not equal\n if ([null, undefined].includes(val1)\n || [null, undefined].includes(val2)) {\n return false;\n }\n // If both values are numbers, they are considered equal if they are numerically equal\n if (typeof val1 === \"number\" && typeof val2 === \"number\") {\n return val1 === val2;\n }\n // If both values are booleans, they are considered equal if they are both true or both false\n if (typeof val1 === \"boolean\" && typeof val2 === \"boolean\") {\n return val1 === val2;\n }\n // If both values are strings, they are considered equal if they are identical\n if (typeof val1 === \"string\" && typeof val2 === \"string\") {\n return val1 === val2;\n }\n // If one value is a number and the other is a string, they are considered\n // equal if the string can be converted to the number\n if (typeof val1 === \"number\" && typeof val2 === \"string\") {\n return val1 === Number(val2);\n }\n if (typeof val1 === \"string\" && typeof val2 === \"number\") {\n return Number(val1) === val2;\n }\n // If one value is a boolean and the other is a non-null object, they are not equal\n if (typeof val1 === \"boolean\" && typeof val2 === \"object\") {\n return false;\n }\n if (typeof val1 === \"object\" && typeof val2 === \"boolean\") {\n return false;\n }\n // If one value is a boolean and the other is a string, they are considered equal ID:\n // ... the boolean is true and the string is not empty, or\n // ... the boolean is false and the string is empty\n if (typeof val1 === \"boolean\"\n && typeof val2 === \"string\") {\n return (val1 && val2 !== \"\") || (!val1 && val2 === \"\");\n }\n if (typeof val1 === \"string\"\n && typeof val2 === \"boolean\") {\n return (val2 && val1 !== \"\") || (!val2 && val1 === \"\");\n }\n // If one value is a number or a string and the other is an object, they are not equal\n if ((typeof val1 === \"number\" || typeof val1 === \"string\") && typeof val2 === \"object\") {\n return false;\n }\n if (typeof val1 === \"object\" && (typeof val2 === \"number\" || typeof val2 === \"string\")) {\n return false;\n }\n // If both values are objects, they are considered equal if they are identical\n if (typeof val1 === \"object\" && typeof val2 === \"object\") {\n return val1 === val2;\n }\n // If none of the above conditions are met, the values are not equal\n return false;\n};\nconst areEqual = (...refs) => {\n do {\n const ref = refs.pop();\n if (refs.length && !areFuzzyEqual(ref, refs[0])) {\n return false;\n }\n } while (refs.length);\n return true;\n};\nconst pFloat = (ref, sigDigits, isStrict = false) => {\n if (typeof ref === \"string\") {\n ref = parseFloat(ref);\n }\n if (typeof ref === \"number\") {\n if (isNaN(ref)) {\n return isStrict ? NaN : 0;\n }\n if (isUndefined(sigDigits)) {\n return ref;\n }\n return Math.round(ref * (10 ** sigDigits)) / (10 ** sigDigits);\n }\n return isStrict ? NaN : 0;\n};\nconst pInt = (ref, isStrictOrIndex, _arr) => {\n let isStrict = false;\n if (typeof isStrictOrIndex === \"boolean\") {\n isStrict = isStrictOrIndex;\n }\n return (isNaN(pFloat(ref, 0, isStrict)) ? NaN : Math.round(pFloat(ref, 0, isStrict)));\n};\nconst pBool = (ref) => {\n if (typeof ref === \"boolean\") {\n return ref;\n }\n if ([0, null, undefined, \"\"].includes(ref)) {\n return false;\n }\n if (typeof ref === \"string\") {\n return ![\"0\", \"false\", \"null\", \"undefined\", \"\"].includes(ref);\n }\n if (isArray(ref) && ref.length === 0) {\n return false;\n }\n if (isList(ref) && isEmpty(ref)) {\n return false;\n }\n return true;\n};\nconst radToDeg = (rad, isConstrained = true) => {\n rad = isConstrained ? rad % (2 * Math.PI) : rad;\n rad *= 180 / Math.PI;\n return rad;\n};\nconst degToRad = (deg, isConstrained = true) => {\n deg = isConstrained ? deg % 360 : deg;\n deg *= Math.PI / 180;\n return deg;\n};\nconst getKey = (key, obj) => {\n if (key in obj) {\n return obj[key];\n }\n return null;\n};\nconst FILTERS = {\n IsInstance: ((classRef) => ((item) => typeof classRef === \"function\" && item instanceof classRef))\n};\n// #endregion ▄▄▄▄▄ TYPES ▄▄▄▄▄\n// #region ████████ STRINGS: String Parsing, Manipulation, Conversion, Regular Expressions ████████\n// #region ░░░░░░░[Case Conversion]░░░░ Upper, Lower, Sentence & Title Case ░░░░░░░ ~\nconst uCase = (str) => String(str).toUpperCase();\nconst lCase = (str) => String(str).toLowerCase();\nconst sCase = (str) => {\n let [first, ...rest] = `${str ?? \"\"}`.split(/\\s+/);\n first = testRegExp(first, _capWords) ? first : `${uCase(first.charAt(0))}${lCase(first.slice(1))}`;\n if (hasItems(rest)) {\n rest = rest.map((word) => (testRegExp(word, _capWords) ? word : lCase(word)));\n }\n return [first, ...rest].join(\" \").trim();\n};\nconst tCase = (str) => String(str).split(/\\s/)\n .map((word, i) => (i && testRegExp(word, _noCapWords) ? lCase(word) : sCase(word)))\n .join(\" \").trim();\n// #endregion ░░░░[Case Conversion]░░░░\n// #region ░░░░░░░[RegExp]░░░░ Regular Expressions ░░░░░░░ ~\nconst testRegExp = (str, patterns = [], flags = \"gui\", isTestingAll = false) => patterns\n .map((pattern) => (pattern instanceof RegExp\n ? pattern\n : new RegExp(`\\\\b${pattern}\\\\b`, flags)))[isTestingAll ? \"every\" : \"some\"]((pattern) => pattern.test(`${str}`));\nconst regExtract = (ref, pattern, flags) => {\n /* Wrapper around String.match() that removes the need to worry about match()'s different handling of the 'g' flag.\n - IF your pattern contains unescaped parentheses -> Returns Array of all matching groups.\n - OTHERWISE -> Returns string that matches the provided pattern. */\n const splitFlags = [];\n [...(flags ?? \"\").replace(/g/g, \"\"), \"u\"].forEach((flag) => {\n if (flag && !splitFlags.includes(flag)) {\n splitFlags.push(flag);\n }\n });\n const isGrouping = /[)(]/.test(pattern.toString().replace(/\\\\\\)|\\\\\\(/g, \"\"));\n if (isGrouping) {\n splitFlags.push(\"g\");\n }\n flags = splitFlags.join(\"\");\n pattern = new RegExp(pattern, flags);\n const matches = `${ref}`.match(pattern) || [];\n return isGrouping ? Array.from(matches) : matches.pop();\n};\n// #endregion ░░░░[RegExp]░░░░\n// #region ░░░░░░░[Formatting]░░░░ Hyphenation, Pluralization, \"a\"/\"an\" Fixing ░░░░░░░ ~\n// const hyphenate = (str: unknown) => (/^<|\\u00AD|\\u200B/.test(`${str}`) ? `${str}` : _hyph(`${str}`));\nconst unhyphenate = (str) => `${str}`.replace(/[\\u00AD\\u200B]/gu, \"\");\nconst parseArticles = (str) => `${str}`.replace(/\\b([aA])\\s([aeiouAEIOU])/gu, \"$1n $2\");\nconst pluralize = (singular, num = 2, plural) => {\n if (pFloat(num) === 1) {\n return singular;\n }\n return plural ?? `${singular.replace(/y$/, \"ie\").replace(/s$/, \"se\")}s`;\n};\nconst oxfordize = (items, useOxfordComma = true, andString = \"and\") => {\n if (items.length === 0) {\n return \"\";\n }\n if (items.length === 1) {\n return `${items[0]}`;\n }\n const lastItem = items.pop();\n return [\n items.join(\", \"),\n useOxfordComma ? \",\" : \"\",\n ` ${andString} `,\n lastItem\n ].join(\"\");\n};\nconst ellipsize = (text, maxLength) => {\n const str = String(text);\n return str.length > maxLength ? `${str.slice(0, maxLength - 3)}…` : str;\n};\nconst pad = (text, minLength, delim = \" \") => {\n const str = `${text}`;\n if (str.length < minLength) {\n return `${delim.repeat(minLength - str.length)}${str}`;\n }\n return str;\n};\nconst toKey = (text) => (text ?? \"\").toLowerCase().replace(/ /g, \"-\").replace(/default/, \"DEFAULT\");\n// #region ========== Numbers: Formatting Numbers Into Strings =========== ~\nconst signNum = (num, delim = \"\", zeroSign = \"+\") => {\n let sign;\n const parsedNum = pFloat(num);\n if (parsedNum < 0) {\n sign = \"-\";\n }\n else if (parsedNum === 0) {\n sign = zeroSign;\n }\n else {\n sign = \"+\";\n }\n return `${sign}${delim}${Math.abs(parsedNum)}`;\n};\nconst padNum = (num, numDecDigits, includePlus = false) => {\n const prefix = (includePlus && num >= 0) ? \"+\" : \"\";\n const [leftDigits, rightDigits] = `${pFloat(num)}`.split(/\\./);\n if (getType(rightDigits) === \"int\") {\n if (rightDigits.length > numDecDigits) {\n return `${prefix}${pFloat(num, numDecDigits)}`;\n }\n else if (rightDigits.length < numDecDigits) {\n return `${prefix}${leftDigits}.${rightDigits}${\"0\".repeat(numDecDigits - rightDigits.length)}`;\n }\n else {\n return `${prefix}${pFloat(num)}`;\n }\n }\n return `${prefix}${leftDigits}.${\"0\".repeat(numDecDigits)}`;\n};\nconst stringifyNum = (num) => {\n // Can take string representations of numbers, either in standard or scientific/engineering notation.\n // Returns a string representation of the number in standard notation.\n if (pFloat(num) === 0) {\n return \"0\";\n }\n const stringyNum = lCase(num).replace(/[^\\d.e+-]/g, \"\");\n const base = regExtract(stringyNum, /^-?[\\d.]+/);\n const exp = pInt(regExtract(stringyNum, /e([+-]?\\d+)$/));\n if (typeof base === \"string\" && typeof exp === \"string\") {\n let baseInts = regExtract(base, /^-?(\\d+)/);\n let baseDecs = regExtract(base, /\\.(\\d+)/);\n if (isArray(baseInts) && isArray(baseDecs)) {\n baseInts = baseInts.pop()?.replace(/^0+/, \"\");\n baseDecs = lCase(baseDecs?.pop()).replace(/0+$/, \"\");\n if (!isUndefined(baseInts) && !isUndefined(baseDecs)) {\n const numFinalInts = Math.max(0, baseInts.length + exp);\n const numFinalDecs = Math.max(0, baseDecs.length - exp);\n const finalInts = [\n baseInts.slice(0, numFinalInts),\n baseDecs.slice(0, Math.max(0, exp))\n ].join(\"\") || \"0\";\n const finalDecs = [\n baseInts.length - numFinalInts > 0\n ? baseInts.slice(baseInts.length - numFinalInts - 1)\n : \"\",\n baseDecs.slice(baseDecs.length - numFinalDecs)\n ].join(\"\");\n return [\n stringyNum.charAt(0) === \"-\" ? \"-\" : \"\",\n finalInts,\n \"0\".repeat(Math.max(0, numFinalInts - finalInts.length)),\n finalDecs.length ? \".\" : \"\",\n \"0\".repeat(Math.max(0, numFinalDecs - finalDecs.length)),\n finalDecs\n ].join(\"\");\n }\n }\n }\n return `${num}`;\n};\nconst verbalizeNum = (num) => {\n // Converts a float with absolute magnitude <= 9.99e303 into words.\n num = stringifyNum(num);\n const getTier = (trioNum) => {\n if (trioNum < _numberWords.tiers.length) {\n return _numberWords.tiers[trioNum];\n }\n return [\n _numberWords.bigPrefixes[(trioNum % 10) - 1],\n _numberWords.bigSuffixes[Math.floor(trioNum / 10)]\n ].join(\"\");\n };\n const parseThreeDigits = (trio) => {\n if (pInt(trio) === 0) {\n return \"\";\n }\n const digits = `${trio}`.split(\"\").map((digit) => pInt(digit));\n let result = \"\";\n if (digits.length === 3) {\n const hundreds = digits.shift();\n if (isUndefined(hundreds)) {\n throw new Error(`[U.verbalizeNum] Undefined digit in trio '${digits.join(\"\")}'.`);\n }\n result += hundreds > 0 ? `${_numberWords.ones[hundreds]} hundred` : \"\";\n if (hundreds && (digits[0] || digits[1])) {\n result += \" and \";\n }\n }\n if (pInt(digits.join(\"\")) <= _numberWords.ones.length) {\n result += _numberWords.ones[pInt(digits.join(\"\"))];\n }\n else {\n const tens = _numberWords.tens[pInt(digits.shift())];\n const ones = pInt(digits[0]) > 0 ? `-${_numberWords.ones[pInt(digits[0])]}` : \"\";\n result += `${tens}${ones}`;\n }\n return result;\n };\n const numWords = [];\n if (num.charAt(0) === \"-\") {\n numWords.push(\"negative\");\n }\n const [integers, decimals] = num.replace(/[,\\s-]/g, \"\").split(\".\");\n const intArray = [...integers.split(\"\")].reverse().join(\"\")\n .match(/.{1,3}/g)\n ?.map((v) => [...v.split(\"\")].reverse().join(\"\")) ?? [];\n const intStrings = [];\n while (intArray.length) {\n const thisTrio = intArray.pop();\n if (thisTrio) {\n const theseWords = parseThreeDigits(thisTrio);\n if (theseWords) {\n intStrings.push(`${theseWords} ${getTier(intArray.length)}`);\n }\n }\n }\n numWords.push(intStrings.join(\", \").trim());\n if (getType(decimals) === \"int\") {\n if (integers === \"0\") {\n numWords.push(\"zero\");\n }\n numWords.push(\"point\");\n for (const digit of decimals.split(\"\")) {\n numWords.push(_numberWords.ones[pInt(digit)]);\n }\n }\n return numWords.join(\" \");\n};\nconst ordinalizeNum = (num, isReturningWords = false) => {\n if (isReturningWords) {\n const [numText, suffix] = lCase(verbalizeNum(num)).match(/.*?[-\\s]?(\\w*)$/i) ?? [\"\", \"\"];\n return numText.replace(new RegExp(`${suffix}$`), suffix in _ordinals ? _ordinals[suffix] : `${suffix}th`);\n }\n if (/(\\.)|(1[1-3]$)/.test(`${num}`)) {\n return `${num}th`;\n }\n return `${num}${[\"th\", \"st\", \"nd\", \"rd\", \"th\", \"th\", \"th\", \"th\", \"th\", \"th\"][pInt(`${num}`.charAt(`${num}`.length - 1))]}`;\n};\nconst romanizeNum = (num, isUsingGroupedChars = true) => {\n if (isFloat(num)) {\n throw new Error(`Error: Can't Romanize Floats (${num})`);\n }\n if (num >= 400000) {\n throw new Error(`Error: Can't Romanize >= 400,000 (${num})`);\n }\n if (num < 0) {\n throw new Error(`Error: Can't Romanize Negative Numbers (${num})`);\n }\n if (num === 0) {\n return \"0\";\n }\n const romanRef = _romanNumerals[isUsingGroupedChars ? \"grouped\" : \"ungrouped\"];\n const romanNum = [...stringifyNum(num).split(\"\")]\n .reverse()\n .map((digit, i) => romanRef[i][pInt(digit)])\n .reverse()\n .join(\"\");\n return isUsingGroupedChars\n ? romanNum.replace(/ⅩⅠ/gu, \"Ⅺ\").replace(/ⅩⅡ/gu, \"Ⅻ\")\n : romanNum;\n};\n// #endregion _______ Numbers _______\n// #endregion ░░░░[Formatting]░░░░\n// #region ░░░░░░░[Content]░░░░ Lorem Ipsum, Random Content Generation, Randum UUID ░░░░░░░ ~\nconst loremIpsum = (numWords = 200) => {\n const lrWordList = _loremIpsumText.split(/\\n?\\s+/g);\n const words = [...lrWordList[randNum(0, lrWordList.length - 1)]];\n while (words.length < numWords) {\n words.push(...lrWordList);\n }\n words.length = numWords;\n return `${sCase(words.join(\" \")).trim().replace(/[^a-z\\s]*$/ui, \"\")}.`;\n};\nconst randString = (length = 5) => Array.from({ length })\n .map(() => String.fromCharCode(randInt(...[\"a\", \"z\"].map((char) => char.charCodeAt(0)))))\n .join(\"\");\nconst randWord = (numWords = 1, wordList = _randomWords) => Array.from({ length: numWords }).map(() => randElem([...wordList])).join(\" \");\nconst getUID = (id) => {\n const indexNum = Math.max(0, ...UUIDLOG.filter(([genericID]) => genericID.startsWith(id)).map(([, , num]) => num)) + 1;\n const uuid = indexNum === 1 ? id : `${id}_${indexNum}`;\n UUIDLOG.push([id, uuid, indexNum]);\n eLog.log(`UUIDify(${id}) --> [${uuid}, ${indexNum}]`);\n Object.assign(globalThis, { UUIDLOG });\n return uuid;\n};\n// #endregion ░░░░[Content]░░░░\n// #endregion ▄▄▄▄▄ STRINGS ▄▄▄▄▄\n// #region ████████ SEARCHING: Searching Various Data Types w/ Fuzzy Matching ████████ ~\nconst fuzzyMatch = (val1, val2) => {\n const [str1, str2] = [val1, val2].map((val) => lCase(String(val).replace(/[^a-zA-Z0-9.+-]/g, \"\").trim()));\n return str1.length > 0 && str1 === str2;\n};\nconst isIn = (needle, haystack = [], fuzziness = 0) => {\n // Looks for needle in haystack using fuzzy matching, then returns value as it appears in haystack.\n // STEP ONE: POPULATE SEARCH TESTS ACCORDING TO FUZZINESS SETTING\n const SearchTests = [\n (ndl, item) => new RegExp(`^${ndl}$`, \"gu\").test(`${item}`),\n (ndl, item) => new RegExp(`^${ndl}$`, \"gui\").test(`${item}`)\n ];\n if (fuzziness >= 1) {\n const fuzzyTests = [\n (ndl, item) => new RegExp(`^${ndl}`, \"gui\").test(`${item}`),\n (ndl, item) => new RegExp(`${ndl}$`, \"gui\").test(`${item}`),\n (ndl, item) => new RegExp(`${ndl}`, \"gui\").test(`${item}`),\n (ndl, item) => new RegExp(`${item}`, \"gui\").test(`${ndl}`)\n ];\n SearchTests.push(...fuzzyTests);\n if (fuzziness >= 2) {\n SearchTests.push(...fuzzyTests\n .map((func) => (ndl, item) => func(`${ndl}`.replace(/\\W/g, \"\"), `${item}`.replace(/\\W/gu, \"\"))));\n if (fuzziness >= 3) {\n SearchTests.push(() => false); // Have to implement Fuse matching\n }\n }\n }\n // STEP TWO: PARSE NEEDLE & CONSTRUCT SEARCHABLE HAYSTACK.\n const searchNeedle = `${needle}`;\n const searchStack = (() => {\n if (isArray(haystack)) {\n return [...haystack];\n }\n if (isList(haystack)) {\n return Object.keys(haystack);\n }\n try {\n return Array.from(haystack);\n }\n catch {\n throw new Error(`Haystack type must be [list, array], not ${typeof haystack}: ${JSON.stringify(haystack)}`);\n }\n })();\n if (!isArray(searchStack)) {\n return false;\n }\n // STEP THREE: SEARCH HAY FOR NEEDLE USING PROGRESSIVELY MORE FUZZY SEARCH TESTS\n let matchIndex = -1;\n while (!isPosInt(matchIndex)) {\n const testFunc = SearchTests.shift();\n if (!testFunc) {\n return false;\n }\n matchIndex = searchStack.findIndex((item) => testFunc(searchNeedle, `${item}`));\n }\n if (isPosInt(matchIndex)) {\n return isList(haystack) ? Object.values(haystack)[matchIndex] : haystack[matchIndex];\n }\n return false;\n};\nconst isInExact = (needle, haystack) => isIn(needle, haystack, 0);\n// #endregion ▄▄▄▄▄ SEARCHING ▄▄▄▄▄\n// #region ████████ NUMBERS: Number Casting, Mathematics, Conversion ████████ ~\nconst randNum = (min, max, snap = 0) => gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.random(min, max, snap);\nconst randInt = (min, max) => randNum(min, max, 1);\nconst coinFlip = () => randNum(0, 1, 1) === 1;\nconst cycleNum = (num, [min = 0, max = Infinity] = []) => gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.wrap(min, max, num);\nconst clampNum = (num, [min = 0, max = Infinity] = []) => gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.clamp(min, max, num);\nconst cycleAngle = (angle, range = [0, 360]) => cycleNum(angle, range);\nconst roundNum = (num, sigDigits = 0) => (sigDigits === 0 ? pInt(num) : pFloat(num, sigDigits));\nconst sum = (...nums) => Object.values(nums.flat()).reduce((num, tot) => tot + num, 0);\nconst average = (...nums) => sum(...nums) / nums.flat().length;\n// #region ░░░░░░░[Positioning]░░░░ Relationships On 2D Cartesian Plane ░░░░░░░ ~\nconst getDistance = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => (((x1 - x2) ** 2) + ((y1 - y2) ** 2)) ** 0.5;\nconst getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }, { x: xO, y: yO } = { x: 0, y: 0 }, range = [0, 360]) => {\n x1 -= xO;\n y1 -= yO;\n x2 -= xO;\n y2 -= yO;\n return cycleAngle(radToDeg(Math.atan2(y2 - y1, x2 - x1)), range);\n};\nconst getAngleDelta = (angleStart, angleEnd, range = [0, 360]) => cycleAngle(angleEnd - angleStart, range);\n/**\n * Function to calculate the smallest rectangle that can contain all the given shapes.\n * @param arrayOfShapes - Array of objects, each describing a shape's position and size.\n * @returns An object describing the position (center) and size of the smallest rectangle that can contain all the shapes.\n */\nconst getBoundingRectangle = (arrayOfShapes) => {\n // Initialize the minimum and maximum x and y coordinates.\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n // Iterate over the array of shapes.\n for (const shape of arrayOfShapes) {\n // Calculate the minimum and maximum x and y coordinates for the current shape.\n let shapeMinX;\n let shapeMinY;\n let shapeMaxX;\n let shapeMaxY;\n if (shape.radius !== undefined) {\n // The shape is a circle.\n shapeMinX = shape.x - shape.radius;\n shapeMinY = shape.y - shape.radius;\n shapeMaxX = shape.x + shape.radius;\n shapeMaxY = shape.y + shape.radius;\n }\n else if (shape.size !== undefined) {\n // The shape is a square.\n shapeMinX = (shape.x - shape.size) / 2;\n shapeMinY = (shape.y - shape.size) / 2;\n shapeMaxX = (shape.x + shape.size) / 2;\n shapeMaxY = (shape.y + shape.size) / 2;\n }\n else if (shape.width !== undefined || shape.height !== undefined) {\n // The shape is a rectangle (or possibly a square).\n shape.width ??= shape.height;\n shape.height ??= shape.width;\n shapeMinX = (shape.x - shape.width) / 2;\n shapeMinY = (shape.y - shape.height) / 2;\n shapeMaxX = (shape.x + shape.width) / 2;\n shapeMaxY = (shape.y + shape.height) / 2;\n }\n else {\n throw new Error(`[getBoundingRectangle] Error: shape must be a circle, square, or rectangle, not ${JSON.stringify(shape)}`);\n }\n // Update the overall minimum and maximum x and y coordinates.\n minX = Math.min(minX, shapeMinX);\n minY = Math.min(minY, shapeMinY);\n maxX = Math.max(maxX, shapeMaxX);\n maxY = Math.max(maxY, shapeMaxY);\n }\n // Calculate the width and height of the smallest rectangle.\n const width = maxX - minX;\n const height = maxY - minY;\n // Calculate the center of the rectangle.\n const x = (minX + width) / 2;\n const y = (minY + height) / 2;\n // Return the position (center) and size of the smallest rectangle.\n return { x, y, width, height };\n};\n// #endregion ░░░░[Positioning]░░░░\n// #endregion ▄▄▄▄▄ NUMBERS ▄▄▄▄▄\n// #region ████████ ARRAYS: Array Manipulation ████████ ~\nconst randElem = (array) => gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.random(array);\nconst randIndex = (array) => randInt(0, array.length - 1);\nconst makeIntRange = (min, max) => {\n const intRange = [];\n for (let i = min; i <= max; i++) {\n intRange.push(i);\n }\n return intRange;\n};\nconst makeCycler = (array, index = 0) => {\n // Given an array and a starting index, returns a generator function that can be used\n // to iterate over the array indefinitely, or wrap out-of-bounds index values\n const wrapper = gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.wrap(array);\n index--;\n return (function* () {\n while (true) {\n index++;\n yield wrapper(index);\n }\n })();\n};\n/**\n * Returns the last element of an array, or the last value of an object literal.\n *\n * @param {Index} array An array or object literal\n * @returns {Type|undefined} The last element, or undefined if empty.\n */\nfunction getLast(array) {\n array = Object.values(array);\n if (array.length === 0) {\n throw new Error(\"Cannot get last element of an empty array.\");\n }\n return array[array.length - 1];\n}\n// Const getLast = (array: Type[]): typeof array extends [] ? undefined : Type => ;\nconst unique = (array) => {\n const returnArray = [];\n array.forEach((item) => { if (!returnArray.includes(item)) {\n returnArray.push(item);\n } });\n return returnArray;\n};\nconst group = (array, key) => {\n const returnObj = {};\n array.forEach((item) => {\n const returnKey = item[key];\n let returnVal = returnObj[returnKey];\n if (!returnVal) {\n returnVal = [];\n returnObj[returnKey] = returnVal;\n }\n returnVal.push(item);\n });\n return returnObj;\n};\nconst sample = (array, numElems = 1, isUniqueOnly = true, uniqueTestFunc = (e, a) => !a.includes(e)) => {\n const elems = [];\n let overloadCounter = 0;\n while (elems.length < numElems && overloadCounter < 1000000) {\n const randomElem = randElem(array);\n if (isUniqueOnly && uniqueTestFunc(randomElem, elems)) {\n elems.push(randomElem);\n }\n overloadCounter++;\n }\n return elems;\n};\nconst removeFirst = (array, element) => array.splice(array.findIndex((v) => v === element));\n/**\n * This function removes and returns the first element in an array that equals the provided value\n * or satisfies the provided testing function.\n * If no elements satisfy the testing function, the function will return undefined.\n *\n * @param {T[]} array The array to be searched.\n * @param {(T|((_v: T, _i?: number, _a?: T[]) => boolean))} checkFunc The testing function or value to be searched for.\n * @returns {T | undefined} The first element in the array that passes the test.\n * If no elements pass the test, return undefined.\n */\nfunction pullElement(array, checkFunc) {\n // Define the test function\n let testFunction;\n // If checkFunc is not a function, create a function that checks for equality with checkFunc\n if (typeof checkFunc !== \"function\") {\n testFunction = (_v) => _v === checkFunc;\n }\n else {\n testFunction = checkFunc;\n }\n // Find the index of the first element that passes the test\n const index = array.findIndex((v, i, a) => testFunction(v, i, a));\n // If no element passes the test, return undefined\n if (index === -1) {\n return undefined;\n }\n // Remove the element from the array and return it\n return array.splice(index, 1).pop();\n}\nconst pullIndex = (array, index) => pullElement(array, (_, i) => i === index);\nconst subGroup = (array, groupSize) => {\n const subArrays = [];\n while (array.length > groupSize) {\n const subArray = [];\n while (subArray.length < groupSize) {\n subArray.push(array.shift());\n }\n subArrays.push(subArray);\n }\n subArrays.push(array);\n return subArrays;\n};\nconst shuffle = (array) => {\n let currentIndex = array.length;\n let randomIndex;\n // While there remain elements to shuffle.\n while (currentIndex !== 0) {\n // Pick a remaining element.\n randomIndex = Math.floor(Math.random() * currentIndex);\n currentIndex--;\n // And swap it with the current element.\n [array[currentIndex], array[randomIndex]] = [\n array[randomIndex], array[currentIndex]\n ];\n }\n return array;\n};\nconst toArray = (target) => {\n return gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.toArray(target);\n};\n// #endregion ▄▄▄▄▄ ARRAYS ▄▄▄▄▄\n// #region ████████ OBJECTS: Manipulation of Simple Key/Val Objects ████████ ~\nconst checkVal = ({ k, v }, checkTest) => {\n if (typeof checkTest === \"function\") {\n if (isDefined(v)) {\n return checkTest(v, k);\n }\n return checkTest(k);\n }\n if (typeof checkTest === \"number\") {\n checkTest = `${checkTest}`;\n }\n return (new RegExp(checkTest)).test(`${v}`);\n};\n/**\n * Given an array or list and a search function, will remove the first matching element and return it.\n * @param {Index} obj The array or list to be searched.\n * @param {testFunc | number | string} checkTest The search function.\n * @returns {unknown | false} - The removed element or false if no element was found.\n */\nconst remove = (obj, checkTest) => {\n if (isArray(obj)) {\n const index = obj.findIndex((v) => checkVal({ v }, checkTest));\n if (index >= 0) {\n return removeElementFromArray(obj, index);\n }\n }\n else if (isList(obj)) {\n const [remKey] = Object.entries(obj).find(([k, v]) => checkVal({ k, v }, checkTest)) ?? [];\n if (remKey) {\n return removeElementFromList(obj, remKey);\n }\n }\n return false;\n};\n/**\n * Removes an element from an array at a given index and returns it.\n * @param {unknown[]} array The array to remove the element from.\n * @param {number} index The index of the element to remove.\n * @returns {unknown} - The removed element.\n */\nconst removeElementFromArray = (array, index) => {\n let remVal;\n for (let i = 0; i <= array.length; i++) {\n if (i === index) {\n remVal = array.shift();\n }\n else {\n array.push(array.shift());\n }\n }\n return remVal;\n};\n/**\n * Removes an element from a list at a given key and returns it.\n * @param {List} list The list to remove the element from.\n * @param {string} key The key of the element to remove.\n * @returns {unknown} - The removed element.\n */\nconst removeElementFromList = (list, key) => {\n const remVal = list[key];\n delete list[key];\n return remVal;\n};\nconst replace = (obj, checkTest, repVal) => {\n // As remove, except instead replaces the element with the provided value.\n // Returns true/false to indicate whether the replace action succeeded.\n let repKey;\n if (isList(obj)) {\n [repKey] = Object.entries(obj).find((v) => checkVal({ v }, checkTest)) || [false];\n if (repKey === false) {\n return false;\n }\n }\n else if (isArray(obj)) {\n repKey = obj.findIndex((v) => checkVal({ v }, checkTest));\n if (repKey === -1) {\n return false;\n }\n }\n if (typeof repKey !== \"number\") {\n repKey = `${repKey}`;\n }\n if (typeof repVal === \"function\") {\n // @ts-expect-error Need to figure out how to properly define testFunc (keyFunc/valFunc types?)\n obj[repKey] = repVal(obj[repKey], repKey);\n }\n else {\n // @ts-expect-error Need to figure out how to properly define testFunc (keyFunc/valFunc types?)\n obj[repKey] = repVal;\n }\n return true;\n};\n/**\n * Cleans an object or value by removing specified values recursively.\n *\n * @template T - The type of the input object or value.\n * @param {T} data The object or value to be cleaned.\n * @param {Array} [remVals] An array of values to be removed during the cleaning process.\n * @returns {T | Partial | \"KILL\"} - The cleaned version of the input object or value.\n * If marked for removal, returns \"KILL\".\n */\nconst objClean = (data, remVals = [undefined, null, \"\", {}, []]) => {\n const remStrings = remVals.map((rVal) => JSON.stringify(rVal));\n if (remStrings.includes(JSON.stringify(data)) || remVals.includes(data)) {\n return \"KILL\";\n }\n if (Array.isArray(data)) {\n const newData = data.map((elem) => objClean(elem, remVals))\n .filter((elem) => elem !== \"KILL\");\n return Array.isArray(newData) && newData.length ? newData : \"KILL\";\n }\n if (data && typeof data === \"object\" && JSON.stringify(data).startsWith(\"{\")) {\n const newData = Object.entries(data)\n .map(([key, val]) => [key, objClean(val, remVals)])\n .filter(([, val]) => val !== \"KILL\");\n return newData.length ? Object.fromEntries(newData) : \"KILL\";\n }\n return data;\n};\n// Given an object and a predicate function, returns array of two objects:\n// one with entries that pass, one with entries that fail.\nconst partition = (obj, predicate = () => true) => [\n objFilter(obj, predicate),\n objFilter(obj, (v, k) => !predicate(v, k))\n];\n/**\n * Zips two arrays into an object.\n *\n * @template T - The type of the keys.\n * @template U - The type of the values.\n * @param {T[]} keys - The array of keys.\n * @param {U[]} values - The array of values.\n * @returns {Record} - The resulting object.\n * @throws {Error} - Throws an error if the arrays are not of equal length, if the keys are not unique, or if the keys are not of a type that can be used as object keys.\n */\nconst zip = (keys, values) => {\n // Check that the arrays are of equal length\n if (keys.length !== values.length) {\n throw new Error(\"The arrays must be of equal length.\");\n }\n // Check that the keys are unique\n if (new Set(keys).size !== keys.length) {\n throw new Error(\"The keys must be unique.\");\n }\n // Zip the arrays into an object\n const result = {};\n keys.forEach((key, i) => {\n result[key] = values[i];\n });\n return result;\n};\nfunction objMap(obj, keyFunc, valFunc) {\n let valFuncTyped = valFunc;\n let keyFuncTyped = keyFunc;\n if (!valFuncTyped) {\n valFuncTyped = keyFunc;\n keyFuncTyped = false;\n }\n if (!keyFuncTyped) {\n keyFuncTyped = ((k) => k);\n }\n if (Array.isArray(obj)) {\n return obj.map(valFuncTyped);\n }\n return Object.fromEntries(Object.entries(obj).map(([key, val]) => {\n assertNonNullType(valFuncTyped, \"function\");\n return [keyFuncTyped(key, val), valFuncTyped(val, key)];\n }));\n}\n/**\n * This function returns the 'size' of any reference passed into it, following these rules:\n * - object: the number of enumerable keys\n * - array: the number of elements\n * - false/null/undefined: 0\n * - anything else: 1\n */\nconst objSize = (obj) => {\n if (isSimpleObj(obj)) {\n return Object.keys(obj).length;\n }\n if (isArray(obj)) {\n return obj.length;\n }\n if (obj === false || obj === null || obj === undefined) {\n return 0;\n }\n return 1;\n};\n/**\n * This function is an object-equivalent of Array.findIndex() function.\n * It accepts check functions for both keys and/or values.\n * If only one function is provided, it's assumed to be searching via values and will receive (v, k) args.\n *\n * @param {Type} obj The object to be searched.\n * @param {testFunc | testFunc | false} keyFunc The testing function for keys.\n * @param {testFunc} valFunc The testing function for values.\n * @returns {KeyOf | false} The key of the first entry that passes the test.\n * If no entries pass the test, return false.\n */\nfunction objFindKey(obj, keyFunc, valFunc) {\n // If valFunc is not provided, assume keyFunc is meant to be valFunc\n if (!valFunc) {\n valFunc = keyFunc;\n keyFunc = false;\n }\n // If keyFunc is not provided, create a function that returns the key\n if (!keyFunc) {\n keyFunc = ((k) => k);\n }\n // If obj is an array, find the index of the first element that passes the test\n if (isArray(obj)) {\n return obj.findIndex(valFunc);\n }\n // Define the testing functions for keys and values\n const kFunc = keyFunc || (() => true);\n const vFunc = valFunc || (() => true);\n // Find the first entry that passes the test\n const validEntry = Object.entries(obj).find(([k, v]) => kFunc(k, v) && vFunc(v, k));\n // If an entry passes the test, return its key\n if (validEntry) {\n return validEntry[0];\n }\n // If no entries pass the test, return false\n return false;\n}\n/**\n * An object-equivalent Array.filter() function, which accepts filter functions for both keys and/or values.\n * If only one function is provided, it's assumed to be mapping the values and will receive (v, k) args.\n *\n * @param {Type} obj The object to be searched.\n * @param {testFunc | testFunc | false} keyFunc The testing function for keys.\n * @param {testFunc} [valFunc] The testing function for values.\n * @returns {Type} The filtered object.\n */\nconst objFilter = (obj, keyFunc, valFunc, isMutating = false) => {\n //\n if (!valFunc) {\n valFunc = keyFunc;\n keyFunc = false;\n }\n if (!keyFunc) {\n keyFunc = ((k) => k);\n }\n if (isArray(obj)) {\n const keptValues = obj.filter(valFunc);\n if (isMutating) {\n obj.splice(0, obj.length, ...keptValues);\n return obj;\n }\n return keptValues;\n }\n const kFunc = keyFunc || (() => true);\n const vFunc = valFunc || (() => true);\n if (isMutating) {\n const entriesToRemove = Object.entries(obj)\n .filter(([key, val]) => !(kFunc(key, val) && vFunc(val, key)));\n for (const [key] of entriesToRemove) {\n delete obj[key];\n }\n return obj;\n }\n return Object.fromEntries(Object.entries(obj)\n .filter(([key, val]) => kFunc(key, val) && vFunc(val, key)));\n};\nconst objForEach = (obj, func) => {\n // An object-equivalent Array.forEach() function, which accepts one function(val, key) to perform for each member.\n if (isArray(obj)) {\n obj.forEach(func);\n }\n else {\n Object.entries(obj).forEach(([key, val]) => func(val, key));\n }\n};\n// Prunes an object of given set of values, [undefined, null] default\nconst objCompact = (obj, removeWhiteList = [undefined, null], isMutating = false) => objFilter(obj, (val) => !removeWhiteList.includes(val), undefined, isMutating);\nconst objClone = (obj, isStrictlySafe = false) => {\n const cloneArray = (arr) => [...arr];\n const cloneObject = (o) => ({ ...o });\n try {\n return JSON.parse(JSON.stringify(obj));\n }\n catch (err) {\n if (isStrictlySafe) {\n throw err;\n }\n if (Array.isArray(obj)) {\n return cloneArray(obj);\n }\n if (typeof obj === \"object\") {\n return cloneObject(obj);\n }\n }\n return obj;\n};\n/**\n * Returns a deep merge of source into target. Does not mutate target unless isMutatingOk = true.\n * @param {Tx} target The target object to be merged.\n * @param {Ty} source The source object to be merged.\n * @param {object} options An object containing various options for the merge operation.\n * @param {boolean} options.isMutatingOk\n * @param {boolean} options.isStrictlySafe\n * @param {boolean} options.isConcatenatingArrays\n * @param {boolean} options.isReplacingArrays\n * @returns {Tx & Ty} - The merged object.\n */\nfunction objMerge(target, source, { isMutatingOk = false, isStrictlySafe = false, isConcatenatingArrays = true, isReplacingArrays = false } = {}) {\n // Clone the target if mutation is not allowed\n target = isMutatingOk ? target : objClone(target, isStrictlySafe);\n // If source is an instance of or target is undefined, return source\n if ((source && typeof source === \"object\" && \"id\" in source && isDocID(source.id)) || isUndefined(target)) {\n return source;\n }\n // If source is undefined, return target\n if (isUndefined(source)) {\n return target;\n }\n // If source is not an index, return target\n if (!isIndex(source)) {\n return target;\n }\n // Iterate over each entry in the source object\n for (const [key, val] of Object.entries(source)) {\n const targetVal = target[key];\n // If replacing arrays is enabled and both target and source values are\n // arrays, replace target value with source value\n if (isReplacingArrays && isArray(targetVal) && isArray(val)) {\n target[key] = val;\n }\n else if (isConcatenatingArrays && isArray(targetVal) && isArray(val)) {\n // If concatenating arrays is enabled and both target and source values\n // are arrays, concatenate source value to target value\n target[key].push(...val);\n }\n else if (val !== null && typeof val === \"object\") {\n // If source value is an object and not null, merge it into target value\n if (isUndefined(targetVal) && !(val instanceof Application)) {\n target[key] = new (Object.getPrototypeOf(val).constructor)();\n }\n target[key] = objMerge(target[key], val, { isMutatingOk: true, isStrictlySafe });\n }\n else {\n // For all other cases, assign source value to target\n target[key] = val;\n }\n }\n // Return the merged target\n return target;\n}\n/**\n * Deep-compares two objects and returns an object containing only the keys and values\n * in the second object that differ from the first.\n * If the second object is missing a key or value contained in the first, it sets the\n * value in the returned object to null, and prefixes the key with \"-=\".\n * @param {Tx} obj1 The first object to be compared.\n * @param {Ty} obj2 The second object to be compared.\n * @returns {Record} - An object containing the differences between the two input objects.\n */\nfunction objDiff(obj1, obj2) {\n const diff = {};\n const bothObj1AndObj2Keys = Object.keys(obj2).filter((key) => Object.hasOwn(obj2, key) && Object.hasOwn(obj1, key));\n const onlyObj2Keys = Object.keys(obj2).filter((key) => Object.hasOwn(obj2, key) && !Object.hasOwn(obj1, key));\n for (const key of bothObj1AndObj2Keys) {\n // If both values are non-array objects, recursively compare them\n if (typeof obj1[key] === \"object\" && typeof obj2[key] === \"object\" && !Array.isArray(obj1[key]) && !Array.isArray(obj2[key])) {\n const nestedDiff = objDiff(obj1[key], obj2[key]);\n if (Object.keys(nestedDiff).length > 0) {\n diff[key] = nestedDiff;\n }\n }\n else if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) {\n const array1 = obj1[key];\n const array2 = obj2[key];\n if (array1.toString() !== array2.toString()) {\n // If both values are arrays and they are not equal, add the second array to the diff\n diff[key] = obj2[key];\n }\n }\n else if (obj1[key] !== obj2[key]) {\n // If the values are not equal, add the second value to the diff\n diff[key] = obj2[key];\n }\n }\n for (const key of onlyObj2Keys) {\n // If the second object has a key that the first does not, add it to the diff with a \"-=\" prefix\n diff[`-=${key}`] = obj2[key];\n }\n return diff;\n}\nconst objExpand = (obj) => {\n const expObj = {};\n for (const [key, val] of Object.entries(obj)) {\n if (isList(val)) {\n const expandedVal = objExpand(val);\n setProperty(expObj, key, expandedVal);\n }\n else {\n setProperty(expObj, key, val);\n }\n }\n // Iterate through expanded Object, converting object literals to arrays where it makes sense\n /**\n *\n * @param o\n */\n function arrayify(o) {\n if (isList(o)) {\n if (/^\\d+$/.test(Object.keys(o).join(\"\"))) {\n return Object.values(o).map(arrayify);\n }\n return objMap(o, (v) => arrayify(v));\n }\n if (isArray(o)) {\n return o.map(arrayify);\n }\n return o;\n }\n return arrayify(expObj);\n};\nconst objFlatten = (obj) => {\n const flatObj = {};\n for (const [key, val] of Object.entries(obj)) {\n if ((isArray(val) || isList(val)) && hasItems(val)) {\n for (const [subKey, subVal] of Object.entries(objFlatten(val))) {\n flatObj[`${key}.${subKey}`] = subVal;\n }\n }\n else {\n flatObj[key] = val;\n }\n }\n return flatObj;\n};\n/**\n *\n * @param obj\n */\nfunction objNullify(obj) {\n // Check if the input is an object or an array\n if (!isIndex(obj)) {\n return obj;\n }\n // If the input is an array, nullify all its elements\n if (Array.isArray(obj)) {\n obj.forEach((_, i) => {\n obj[i] = null;\n });\n return obj;\n }\n // If the input is an object, nullify all its properties\n Object.keys(obj).forEach((objKey) => {\n obj[objKey] = null;\n });\n return obj;\n}\n/**\n * This function freezes the properties of an object based on a provided schema or keys.\n * If a property is missing, it throws an error.\n * @param {Partial} data The object whose properties are to be frozen.\n * @param {...Array | [T]} keysOrSchema The keys or schema to freeze the properties.\n * @returns {T} - The object with frozen properties.\n * @throws {Error} - Throws an error if a property is missing.\n */\nfunction objFreezeProps(data, ...keysOrSchema) {\n const firstArg = keysOrSchema[0];\n // If the first argument is an object and not an array, treat it as a schema\n if (firstArg instanceof Object && !Array.isArray(firstArg)) {\n const schema = firstArg;\n for (const key in schema) {\n if (data[key] === undefined) {\n throw new Error(`Missing value for ${key}`);\n }\n }\n }\n else {\n // If the first argument is not an object or is an array, treat it as an array of keys\n for (const key of keysOrSchema) {\n if (data[key] === undefined) {\n throw new Error(`Missing value for ${String(key)}`);\n }\n }\n }\n // Return the data as type T\n return data;\n}\n// #endregion ▄▄▄▄▄ OBJECTS ▄▄▄▄▄\n// #region ████████ FUNCTIONS: Function Wrapping, Queuing, Manipulation ████████ ~\nconst getDynamicFunc = (funcName, func, context) => {\n if (typeof func === \"function\") {\n const dFunc = { [funcName](...args) { return func(...args); } }[funcName];\n return context ? dFunc.bind(context) : dFunc;\n }\n return false;\n};\nconst withLog = (fn) => {\n return (...args) => {\n console.log(`calling ${fn.name}`);\n return fn(...args);\n };\n};\n// #endregion ▄▄▄▄▄ FUNCTIONS ▄▄▄▄▄\n// #region ████████ HTML: Parsing HTML Code, Manipulating DOM Objects ████████ ~\nconst changeContainer = (elem, container, isCloning = false) => {\n elem = $(elem)[0];\n container = $(container)[0];\n // Get the element's current container, which defines its current coordinate space.\n const curContainer = $(elem).parent()[0];\n // Get the element's current position in its current coordinate space.\n const curPosition = {\n x: gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.getProperty(elem, \"x\"),\n y: gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.getProperty(elem, \"y\")\n };\n // Convert the element's position in its current space, to the equivalent position in the target space.\n const relPos = gsap_all__WEBPACK_IMPORTED_MODULE_1__.MotionPathPlugin.convertCoordinates(curContainer, container, curPosition);\n eLog.checkLog3(\"changeContainer\", \"Target Element\", { elem, container, curContainer, curPosition, relPos });\n // Clone the element, if indicated\n if (isCloning) {\n elem = $(elem).clone()[0];\n }\n // Append the element to the new container, and set its new position\n $(elem).appendTo($(container));\n gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.set(elem, relPos);\n return elem;\n};\n/**\n * Adjusts the aspect ratio of a text container to match a target ratio by modifying its font size and line height.\n * This function recursively adjusts the font size and line height until the container's aspect ratio or maximum dimensions are met.\n *\n * @param {HTMLElement|JQuery} textContainer - The text container element or jQuery object to adjust.\n * @param {number} targetRatio - The target aspect ratio (width / height) to achieve.\n * @param {number} [maxHeight] - Optional maximum height for the text container.\n * @param {number} [maxWidth] - Optional maximum width for the text container.\n * @param {number} [minFontSize=8] - Optional minimum font size to prevent the text from becoming too small.\n * @returns {void}\n */\nconst adjustTextContainerAspectRatio = (textContainer, targetRatio, maxHeight, maxWidth, minFontSize = 8) => {\n // Ensure textContainer is an HTMLElement\n textContainer = $(textContainer)[0];\n // If no maxWidth is provided, initialize textContainer's width to maximum possible\n if (!maxWidth) {\n textContainer.style.setProperty(\"width\", \"max-content\", \"important\");\n }\n else {\n textContainer.style.setProperty(\"width\", `${maxWidth}px`, \"important\");\n }\n /**\n * Recursively adjusts the font size and line height of the text container.\n * This function is called if the current adjustments do not meet the target aspect ratio or maximum dimensions.\n *\n * @returns {boolean} - Returns false if the new font size is below the minimum font size, indicating no further adjustments should be made.\n */\n function recurAdjustment() {\n // Ensure textContainer is an HTMLElement for each recursive call\n textContainer = $(textContainer)[0];\n // Calculate new font size and line height as 80% of their current values\n const newFontSize = parseFloat(style.fontSize) * 0.8;\n const newLineHeight = parseFloat(style.lineHeight) * 0.8;\n // Stop recursion if the new font size is below the minimum\n if (newFontSize < minFontSize) {\n return false;\n }\n // Apply the new font size and line height\n textContainer.style.fontSize = `${newFontSize}px`;\n textContainer.style.lineHeight = `${newLineHeight}px`;\n // Recursively call adjustTextContainerAspectRatio with updated parameters\n return adjustTextContainerAspectRatio(textContainer, targetRatio, lineCount ?? maxHeight, maxWidth, minFontSize);\n }\n // Get computed styles of the text container\n const style = window.getComputedStyle(textContainer);\n const lineHeight = parseFloat(style.lineHeight);\n // Initialize lineCount as undefined\n let lineCount = undefined;\n // If maxHeight is provided and is an integer less than lineHeight, calculate lineCount\n if (isInt(maxHeight) && maxHeight < lineHeight) {\n lineCount = maxHeight;\n }\n // Get the initial width of the text container\n const initialWidth = parseFloat(style.width);\n // Initialize bestWidth with the initial width\n let bestWidth = initialWidth;\n // Flag to indicate if the maximum line count has been reached\n let isAtMaxLineCount = false;\n // Loop to find the best width that matches the target aspect ratio\n for (let lines = 1;; lines++) {\n const expectedHeight = lineHeight * lines;\n const expectedWidth = initialWidth / lines;\n const expectedRatio = expectedWidth / expectedHeight;\n // Break the loop if the expected ratio is less than the target ratio\n if (expectedRatio < targetRatio) {\n break;\n }\n // Handle cases where lineCount is defined\n if (isInt(lineCount)) {\n if (lines > lineCount) {\n if (recurAdjustment()) {\n return;\n }\n break;\n }\n }\n else if (maxHeight && expectedHeight > maxHeight) {\n // Handle cases where maxHeight is exceeded\n if (recurAdjustment()) {\n return;\n }\n break;\n }\n // Update bestWidth with the expected width\n bestWidth = expectedWidth;\n // Check if the current line count matches the maximum line count\n if (isInt(lineCount) && lines === lineCount) {\n isAtMaxLineCount = true;\n break;\n }\n }\n // If the best width exceeds maxWidth, attempt to adjust font size and line height\n if (!isAtMaxLineCount && maxWidth && bestWidth > maxWidth) {\n if (recurAdjustment()) {\n return;\n }\n }\n // Apply the best width to the text container\n textContainer.style.setProperty(\"width\", `${bestWidth}px`, \"important\");\n};\nconst getSvgCode = (svgDotKey, svgPathKeys) => {\n const svgData = getProperty(_constants__WEBPACK_IMPORTED_MODULE_0__.SVGDATA, svgDotKey);\n // eLog.checkLog3(\"compileSvg\", {svgDotKey, svgPaths, svgData});\n if (!svgData) {\n return \"\";\n }\n const { viewBox, paths, classes } = svgData;\n svgPathKeys ??= Object.keys(paths).join(\"|\");\n if (typeof svgPathKeys === \"string\") {\n svgPathKeys = svgPathKeys.split(\"|\");\n }\n return [\n ``,\n ...svgPathKeys\n .map((path) => ``),\n \"\"\n ].join(\"\\n\");\n};\n// #region ░░░░░░░[SVG]░░░░ SVG Generation & Manipulation ░░░░░░░ ~\nconst getRawCirclePath = (r, { x: xO, y: yO } = { x: 0, y: 0 }) => {\n [r, xO, yO] = [r, xO, yO].map((val) => roundNum(val, 2));\n const [b1, b2] = [0.4475 * r, (1 - 0.4475) * r];\n const [xT, yT] = [xO, yO - r];\n return [[\n ...[xT, yT],\n ...[b2, 0, r, b1, r, r],\n ...[0, b2, -b1, r, -r, r],\n ...[-b2, 0, -r, -b1, -r, -r],\n ...[0, -b2, b1, -r, r, -r]\n ]];\n};\nconst drawCirclePath = (radius, origin) => {\n const [[xT, yT, ...segments]] = getRawCirclePath(radius, origin);\n const path = [`m ${xT} ${yT}`];\n segments.forEach((coord, i) => {\n if (i % 6 === 0) {\n path.push(\"c\");\n }\n path.push(coord);\n });\n path.push(\"z\");\n return path.join(\" \");\n};\n// #endregion ░░░░[SVG]░░░░\n// #region ░░░░░░░[Colors]░░░░ Color Manipulation ░░░░░░░ ~\nconst getColorVals = (red, green, blue, alpha) => {\n if (isRGBColor(red)) {\n [red, green, blue, alpha] = red\n .replace(/[^\\d.,]/g, \"\")\n .split(/,/)\n .map((color) => (isUndefined(color) ? undefined : parseFloat(color)));\n }\n if (isHexColor(red)) {\n if ([4, 5].includes(red.length)) {\n red = red.replace(/([^#])/g, \"$1$1\");\n }\n [red, green, blue, alpha] = red\n .match(/[^#]{2}/g)\n ?.map((val) => parseInt(val, 16)) ?? [];\n }\n if ([red, green, blue].every((color) => /^\\d+$/.test(`${color}`))) {\n return [red, green, blue, alpha]\n .filter((color) => /^[\\d.]+$/.test(`${color}`));\n }\n return null;\n};\nconst getRGBString = (red, green, blue, alpha) => {\n if (isRGBColor(red) || isHexColor(red)) {\n [red, green, blue, alpha] = getColorVals(red) ?? [];\n }\n if ([red, green, blue].every((color) => /^[.\\d]+$/.test(`${color}`))) {\n let colorString = \"rgb\";\n const colors = [red, green, blue];\n if (/^[.\\d]+$/.test(`${alpha}`)) {\n colors.push(alpha >= 1 ? pInt(alpha) : pFloat(alpha, 2));\n colorString += \"a\";\n }\n return `${colorString}(${colors.join(\", \")})`;\n }\n return null;\n};\nconst getHEXString = (red, green, blue) => {\n function componentToHex(c) {\n const hex = c.toString(16);\n return hex.length === 1 ? `0${hex}` : hex;\n }\n if (isHexColor(red)) {\n return red;\n }\n if (isRGBColor(red)) {\n [red, green, blue] = getColorVals(red) ?? [];\n }\n if (isDefined(red) && isDefined(green) && isDefined(blue) && [red, green, blue].every((color) => /^[.\\d]+$/.test(`${color}`))) {\n return `#${componentToHex(red ?? 0)}${componentToHex(green ?? 0)}${componentToHex(blue ?? 0)}`;\n }\n return null;\n};\nconst getContrastingColor = (...colorVals) => {\n const [red, green, blue] = getColorVals(...colorVals) ?? [];\n if ([red, green, blue].every(isNumber)) {\n const YIQ = ((red * 299) + (green * 587) + (blue * 114)) / 1000;\n return (YIQ >= 128) ? \"rgba(0, 0, 0, 1)\" : \"rgba(255, 255, 255, 0.8)\";\n }\n return null;\n};\nconst getRandomColor = () => getRGBString(gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.random(0, 255, 1), gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.random(0, 255, 1), gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.random(0, 255, 1));\n// #endregion ░░░░[Colors]░░░░\n// #region ░░░░░░░[DOM]░░░░ DOM Manipulation ░░░░░░░ ~\nconst getSiblings = (elem) => {\n const siblings = [];\n // If no parent, return no sibling\n if (!elem.parentNode) {\n return siblings;\n }\n Array.from(elem.parentNode.children).forEach((sibling) => {\n if (sibling !== elem) {\n siblings.push(sibling);\n }\n });\n return siblings;\n};\n// #endregion ░░░░[DOM]░░░░\nconst escapeHTML = (str) => (typeof str === \"string\"\n ? str\n .replace(/&/g, \"&\")\n .replace(//g, \">\")\n .replace(/\"/g, \""\")\n .replace(/[`']/g, \"'\")\n : str);\n// #region ████████ PERFORMANCE: Performance Testing & Metrics ████████\n/**\n * Test the performance of a function (synchronous or asynchronous).\n * The function will be called repeatedly for 10 seconds, and the total and average execution times will be logged.\n * @param func - The function to test. Can be synchronous or asynchronous.\n * @param params - The parameters to pass to the function.\n */\nconst testFuncPerformance = (func, ...params) => {\n const start = performance.now(); // Start the timer\n let tally = 0; // Keep track of how many times the function is called\n // This function will be called each time 'func' finishes executing\n const handleResult = () => {\n // Check if 10 seconds have passed\n if (performance.now() - start < 10000) {\n runFunc(); // If not, call 'func' again\n tally++; // And increment the tally\n }\n else {\n // If 10 seconds have passed, calculate the total and average time and log them\n const elapsedTime = performance.now() - start;\n const timePerCall = roundNum(elapsedTime / tally / 4000, 4);\n eLog.checkLog3(\"performance\", `[TestPerformance] Function Ran ${tally} Times in ${roundNum(elapsedTime / 1000, 4)}s, Averaging ${timePerCall}s per Call`);\n }\n };\n // This function calls 'func' and handles its result, whether it's a Promise or not\n const runFunc = () => {\n const result = func(...params); // Call 'func' with the provided parameters\n if (result instanceof Promise) {\n // If 'func' is asynchronous, wait for the Promise to resolve before handling the result\n result.then(handleResult);\n }\n else {\n // If 'func' is synchronous, handle the result immediately\n handleResult();\n }\n };\n runFunc(); // Start the first call to 'func'\n};\n// #endregion\n// #region ░░░░░░░[GreenSock]░░░░ Wrappers for GreenSock Functions ░░░░░░░ ~\nconst set = (targets, vars) => gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.set(targets, vars);\n/**\n *\n * @param target\n * @param property\n * @param unit\n */\nfunction get(target, property, unit) {\n if (unit) {\n const propVal = regExtract(gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.getProperty(target, property, unit), /[\\d.]+/);\n if (typeof propVal === \"string\") {\n return pFloat(propVal);\n }\n throw new Error(`Unable to extract property '${property}' in '${unit}' units from ${target}`);\n }\n return gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.getProperty(target, property);\n}\nconst getGSAngleDelta = (startAngle, endAngle) => signNum(roundNum(getAngleDelta(startAngle, endAngle), 2)).replace(/^(.)/, \"$1=\");\nconst getNearestLabel = (tl, matchTest) => {\n if (!tl) {\n return undefined;\n }\n if (!objSize(tl.labels)) {\n return undefined;\n }\n if (typeof matchTest === \"string\") {\n matchTest = new RegExp(matchTest);\n }\n // Filter the labels against the matchTest, if one provided, and sort by time in ascending order.\n const labelTimes = Object.entries(tl.labels)\n .filter(([label]) => {\n return matchTest instanceof RegExp\n ? matchTest.test(label)\n : true;\n })\n .sort((a, b) => a[1] - b[1]);\n // Snap the current time of the timeline to the values in labelTimes\n const nearestTime = gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.utils.snap(labelTimes.map(([_label, time]) => time), tl.time());\n // Get the associated label for the nearest time\n const [nearestLabel] = labelTimes.find(([_label, time]) => time === nearestTime);\n return nearestLabel;\n};\nconst reverseRepeatingTimeline = (tl) => {\n // FIRST: Determine if timeline itself is repeating, or if most-recent child tween of timeline is repeating\n if (tl.repeat() === -1) {\n // Timeline itself is repeating. Set totalTime equal to time, reverse.\n tl.totalTime(tl.time());\n }\n else {\n // Get currently-running child tween, check if that is repeating.\n const [tw] = tl.getChildren(false, true, true, tl.time());\n if (tw && tw.repeat() === -1) {\n // Child tween is repeating. Set totalTime of TWEEN equal to time, reverse TIMELINE.\n tw.totalTime(tw.time());\n }\n tl.reverse();\n }\n return tl;\n};\n// #endregion ░░░░[GreenSock]░░░░\n// #endregion ▄▄▄▄▄ HTML ▄▄▄▄▄\n// #region ████████ ASYNC: Async Functions, Asynchronous Flow Control ████████ ~\nconst sleep = (duration) => new Promise((resolve) => {\n setTimeout(resolve, duration >= 100 ? duration : duration * 1000);\n});\nfunction waitFor(waitForTarget) {\n return new Promise((resolve, reject) => {\n if (waitForTarget instanceof Promise\n || waitForTarget instanceof gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap.core.Animation) {\n waitForTarget.then(() => resolve()).catch(reject);\n }\n else if (Array.isArray(waitForTarget)) {\n Promise.all(waitForTarget.map((target) => waitFor(target))).then(() => resolve()).catch(reject);\n }\n else {\n resolve();\n }\n });\n}\n// #endregion ▄▄▄▄▄ ASYNC ▄▄▄▄▄\nconst EventHandlers = {\n onTextInputBlur: async (inst, event) => {\n const elem = event.target;\n const { action, target, flagTarget } = elem.dataset;\n if (!action) {\n throw new Error(\"Input text elements require a data-action attribute.\");\n }\n if (!target && !flagTarget) {\n throw new Error(\"Input text elements require a 'data-target' or 'data-flag-target' attribute.\");\n }\n if (target) {\n await inst.document.update({ [target]: elem.value });\n }\n else if (flagTarget) {\n if (elem.value === \"\") {\n await inst.document.unsetFlag(_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID, flagTarget);\n }\n else {\n await inst.document.setFlag(_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID, flagTarget, elem.value);\n }\n }\n },\n onSelectChange: async (inst, event) => {\n const elem = event.currentTarget;\n const { action, dtype, target, flagTarget } = elem.dataset;\n if (!action) {\n throw new Error(\"Select elements require a data-action attribute.\");\n }\n if (!target && !flagTarget) {\n throw new Error(\"Select elements require a 'data-target' or 'data-flag-target' attribute.\");\n }\n const dataType = lCase(dtype);\n let value;\n switch (dataType) {\n case \"number\":\n value = pFloat(elem.value);\n break;\n case \"boolean\":\n value = lCase(`${elem.value}`) === \"true\";\n break;\n case \"string\":\n value = `${elem.value}`;\n break;\n default: {\n if (isNumString(value)) {\n throw new Error(\"You must set 'data-dtype=\\\"Number\\\"' for elements with boolean values.\");\n }\n value = `${elem.value}`;\n break;\n }\n }\n if (target) {\n await inst.document.update({ [target]: value });\n }\n else if (flagTarget) {\n if (elem.value === \"\") {\n await inst.document.unsetFlag(_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID, flagTarget);\n }\n else {\n await inst.document.setFlag(_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID, flagTarget, value);\n }\n }\n }\n};\n// #region ████████ FOUNDRY: Requires Configuration of System ID in constants.ts ████████ ~\nconst isDocID = (ref) => {\n return typeof ref === \"string\" && /^[A-Za-z0-9]{16}$/.test(ref);\n};\nconst isDocUUID = (ref) => {\n if (typeof ref !== \"string\") {\n return false;\n }\n const [docName, docID] = ref.split(/\\./);\n if (!isDocID(docID)) {\n return false;\n }\n return game.collections.has(docName);\n};\nconst isDotKey = (ref) => {\n return typeof ref === \"string\";\n};\nconst isTargetKey = (ref) => {\n if (!isDotKey(ref)) {\n return false;\n }\n if ([\"name\", \"img\", \"id\", \"_id\"].includes(ref)) {\n return true;\n }\n if (ref.startsWith(\"system\")) {\n return true;\n }\n if (ref.startsWith(\"flag\")) {\n return true;\n }\n return false;\n};\nconst isTargetFlagKey = (ref) => {\n if (!isDotKey(ref)) {\n return false;\n }\n if (isTargetKey(ref)) {\n return false;\n }\n return true;\n};\nconst parseDocRefToUUID = (ref) => {\n if (isDocUUID(ref)) {\n return ref;\n }\n else if (isDocID(ref)) {\n const doc = game.collections.find((collection) => collection.has(ref))?.get(ref);\n if (doc && \"uuid\" in doc) {\n return doc.uuid;\n }\n throw new Error(`[U.parseDocRefToUUID] Unable to find document with id '${ref}'`);\n }\n else if (ref && typeof ref === \"object\" && \"uuid\" in ref && typeof ref.uuid === \"string\") {\n return ref.uuid;\n }\n throw new Error(`[U.parseDocRefToUUID] Unrecognized reference: '${ref}'`);\n};\nconst loc = (locRef, formatDict = {}) => {\n if (/[a-z]/.test(locRef)) { // Reference contains lower-case characters: add system ID namespacing to dot notation\n locRef = locRef.replace(new RegExp(`^(${_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID}.)*`), `${_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID}.`);\n }\n if (typeof game.i18n.localize(locRef) === \"string\") {\n for (const [key, val] of Object.entries(formatDict)) {\n formatDict[key] = loc(val);\n }\n return game.i18n.format(locRef, formatDict) || game.i18n.localize(locRef) || locRef;\n }\n return locRef;\n};\nconst getSetting = (setting) => {\n if (game.settings.settings.has(`${_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID}.${setting}`)) {\n return game.settings.get(_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID, setting);\n }\n return undefined;\n};\n/**\n *\n * @param subFolder\n * @param fileName\n */\nfunction getTemplatePath(subFolder, fileName) {\n if (typeof fileName === \"string\") {\n return `${_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].TEMPLATE_ROOT}/${subFolder}/${fileName.replace(/\\..*$/, \"\")}.hbs`;\n }\n return fileName.map((fName) => getTemplatePath(subFolder, fName));\n}\n// DisplayImageSelector: Displays a file selector in tiles mode at the indicated path root.\n/**\n *\n * @param callback\n * @param pathRoot\n * @param position\n * @param position.top\n * @param position.left\n */\nfunction displayImageSelector(callback, pathRoot = `systems/${_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SYSTEM_ID}/assets`, position = { top: 200, left: 200 }) {\n const fp = new FilePicker({\n type: \"image\",\n activeSource: \"public\",\n displayMode: \"tiles\",\n callback,\n top: position.top ?? 200 + 40,\n left: position.left ?? 200 + 10\n });\n return fp.browse(pathRoot);\n}\n// #endregion ▄▄▄▄▄ FOUNDRY ▄▄▄▄▄\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n // ████████ GETTERS: Basic Data Lookup & Retrieval ████████\n GMID, getUID,\n // ████████ TYPES: Type Checking, Validation, Conversion, Casting ████████\n isNumber, isNumString, isBooleanString, isSimpleObj, isList, isArray, isFunc, isInt, isFloat, isPosInt, isIterable,\n isHTMLCode, isRGBColor, isHexColor,\n isUndefined, isDefined, isEmpty, hasItems, isInstance, isNullish,\n areEqual, areFuzzyEqual,\n pFloat, pInt, pBool, radToDeg, degToRad,\n getKey,\n assertNonNullType,\n FILTERS,\n // ████████ REGEXP: Regular Expressions, Replacing, Matching ████████\n testRegExp,\n regExtract,\n // ████████ STRINGS: String Parsing, Manipulation, Conversion ████████\n // ░░░░░░░ Case Conversion ░░░░░░░\n uCase, lCase, sCase, tCase,\n // ░░░░░░░ Formatting ░░░░░░░\n /* hyphenate, */ unhyphenate, pluralize, oxfordize, ellipsize, pad,\n toKey,\n parseArticles,\n signNum, padNum, stringifyNum, verbalizeNum, ordinalizeNum, romanizeNum,\n // ░░░░░░░ Content ░░░░░░░\n loremIpsum, randString, randWord,\n // ████████ SEARCHING: Searching Various Data Types w/ Fuzzy Matching ████████\n fuzzyMatch, isIn, isInExact,\n // ████████ NUMBERS: Number Casting, Mathematics, Conversion ████████\n randNum, randInt,\n coinFlip,\n cycleNum, cycleAngle, roundNum, clampNum,\n sum, average,\n // ░░░░░░░ Positioning ░░░░░░░\n getDistance,\n getAngle, getAngleDelta,\n getBoundingRectangle,\n // ████████ ARRAYS: Array Manipulation ████████\n randElem, randIndex,\n makeIntRange,\n makeCycler,\n unique, group, sample,\n getLast, removeFirst, pullElement, pullIndex,\n subGroup, shuffle,\n toArray,\n // ████████ OBJECTS: Manipulation of Simple Key/Val Objects ████████\n remove, replace, partition, zip,\n objClean, objSize, objMap, objFindKey, objFilter, objForEach, objCompact,\n objClone, objMerge, objDiff, objExpand, objFlatten, objNullify,\n objFreezeProps,\n // ████████ FUNCTIONS: Function Wrapping, Queuing, Manipulation ████████\n getDynamicFunc, withLog,\n // ████████ HTML: Parsing HTML Code, Manipulating DOM Objects ████████\n getSvgCode,\n changeContainer, adjustTextContainerAspectRatio,\n getRawCirclePath, drawCirclePath,\n getColorVals, getRGBString, getHEXString, getContrastingColor, getRandomColor,\n getSiblings,\n escapeHTML,\n // ████████ PERFORMANCE: Performance Testing & Metrics ████████\n testFuncPerformance,\n // ░░░░░░░ GreenSock ░░░░░░░\n gsap: gsap_all__WEBPACK_IMPORTED_MODULE_1__.gsap, get, set, getGSAngleDelta, getNearestLabel, reverseRepeatingTimeline, /* to, from, fromTo, */\n TextPlugin: gsap_all__WEBPACK_IMPORTED_MODULE_1__.TextPlugin, Flip: gsap_all__WEBPACK_IMPORTED_MODULE_1__.Flip, MotionPathPlugin: gsap_all__WEBPACK_IMPORTED_MODULE_1__.MotionPathPlugin,\n // ████████ ASYNC: Async Functions, Asynchronous Flow Control ████████\n sleep, waitFor,\n // EVENT HANDLERS\n EventHandlers,\n // ░░░░░░░ SYSTEM: System-Specific Functions (Requires Configuration of System ID in constants.js) ░░░░░░░\n isDocID, isDocUUID, isDotKey, isTargetKey, isTargetFlagKey,\n parseDocRefToUUID,\n loc, getSetting, getTemplatePath, displayImageSelector\n});\n// #endregion ▄▄▄▄▄ EXPORTS ▄▄▄▄▄\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSLGNBQWMsd0RBQU0sOERBQWtCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDLEVBQUM7QUFDRiIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2NvcmUvdXRpbGl0aWVzLnRzPzFhYmQiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG4vLyAvLy8gPHJlZmVyZW5jZSB0eXBlcz1cImdzYXBcIiAvPlxuLy8gI3JlZ2lvbiDilq7ilq7ilq7ilq7ilq7ilq7ilq4gSU1QT1JUUyDilq7ilq7ilq7ilq7ilq7ilq7ilq4gflxuaW1wb3J0IEMsIHsgU1ZHREFUQSB9IGZyb20gXCIuL2NvbnN0YW50c1wiO1xuLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby11bnJlc29sdmVkXG5pbXBvcnQgeyBnc2FwLCBUZXh0UGx1Z2luLCBGbGlwLCBNb3Rpb25QYXRoUGx1Z2luIH0gZnJvbSBcImdzYXAvYWxsXCI7XG5nc2FwLnJlZ2lzdGVyUGx1Z2luKE1vdGlvblBhdGhQbHVnaW4pO1xuLy8gI2VuZHJlZ2lvbiDilq7ilq7ilq7ilq4gSU1QT1JUUyDilq7ilq7ilq7ilq5cbi8vICNyZWdpb24g4pau4pau4pau4pau4pau4pau4pauIFtIRUxQRVJTXSBJbnRlcm5hbCBGdW5jdGlvbnMsIERhdGEgJiBSZWZlcmVuY2VzIFVzZWQgYnkgVXRpbGl0eSBGdW5jdGlvbnMg4pau4pau4pau4pau4pau4pau4pauIH5cbi8vIF9ub0NhcFdvcmRzIC0tIFBhdHRlcm5zIG1hdGNoaW5nIHdvcmRzIHRoYXQgc2hvdWxkIE5PVCBiZSBjYXBpdGFsaXplZCB3aGVuIGNvbnZlcnRpbmcgdG8gVElUTEUgY2FzZS5cbmNvbnN0IF9ub0NhcFdvcmRzID0gXCJhfGFib3ZlfGFmdGVyfGFufGFuZHxhdHxiZWxvd3xidXR8Ynl8ZG93bnxmb3J8Zm9yfGZyb218aW58bm9yfG9mfG9mZnxvbnxvbnRvfG9yfG91dHxzb3x0aGV8dG98dW5kZXJ8dXB8d2l0aHx5ZXRcIlxuICAgIC5zcGxpdChcInxcIilcbiAgICAubWFwKCh3b3JkKSA9PiBuZXcgUmVnRXhwKGBcXFxcYiR7d29yZH1cXFxcYmAsIFwiZ3VpXCIpKTtcbi8vIF9jYXBXb3JkcyAtLSBQYXR0ZXJucyBtYXRjaGluZyB3b3JkcyB0aGF0IHNob3VsZCBBTFdBWVMgYmUgY2FwaXRhbGl6ZWQgd2hlbiBjb252ZXJ0aW5nIHRvIFNFTlRFTkNFIGNhc2UuXG5jb25zdCBfY2FwV29yZHMgPSBbXG4gICAgXCJJXCIsIC9bXmEtel17Myx9fFsuMC05XS9ndVxuXS5tYXAoKHdvcmQpID0+ICgvUmVnRXhwLy50ZXN0KE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh3b3JkKSkgPyB3b3JkIDogbmV3IFJlZ0V4cChgXFxcXGIke3dvcmR9XFxcXGJgLCBcImd1aVwiKSkpO1xuLy8gX2xvcmVtSXBzdW1UZXh0IC0tIEJvaWxlcnBsYXRlIGxvcmVtIGlwc3VtXG5jb25zdCBfbG9yZW1JcHN1bVRleHQgPSBgTG9yZW0gaXBzdW0gZG9sb3Igc2l0IGFtZXQsIGNvbnNlY3RldHVyIGFkaXBpc2NpbmcgZWxpdC4gU3VzcGVuZGlzc2UgdWx0cmljaWVzXHJcbm5pYmggc2VkIG1hc3NhIGV1aXNtb2QgbGFjaW5pYS4gQWxpcXVhbSBuZWMgZXN0IGFjIG51bmMgdWx0cmljaWVzIHNjZWxlcmlzcXVlIHBvcnRhIHZ1bHB1dGF0ZSBvZGlvLlxyXG5JbnRlZ2VyIGdyYXZpZGEgbWF0dGlzIG9kaW8sIHNlbXBlciB2b2x1dHBhdCB0ZWxsdXMuIFV0IGVsaXQgbGVvLCBhdWN0b3IgZWdldCBmZXJtZW50dW0gaGVuZHJlcml0LFxyXG5hbGlxdWV0IGFjIG51bmMuIFN1c3BlbmRpc3NlIHBvcnRhIHR1cnBpcyB2aXRhZSBtaSBwb3N1ZXJlIG1vbGVzdGllLiBDcmFzIGxlY3R1cyBsYWN1cywgdnVscHV0YXRlIGFcclxudmVzdGlidWx1bSBpbiwgbWF0dGlzIHZlbCBtaS4gTWF1cmlzIHF1aXMgc2VtcGVyIG1hdXJpcy4gUHJhZXNlbnQgYmxhbmRpdCBuZWMgZGlhbSBlZ2V0IHRpbmNpZHVudC4gTnVuY1xyXG5hbGlxdWV0IGNvbnNlcXVhdCBtYXNzYSBhYyBsYWNpbmlhLiBVdCBwb3N1ZXJlIHZlbGl0IHNhZ2l0dGlzLCB2ZWhpY3VsYSBuaXNsIGVnZXQsIGZyaW5naWxsYSBuaWJoLiBEdWlzXHJcbnZvbHV0cGF0IG1hdHRpcyBsaWJlcm8sIGEgcG9ydHRpdG9yIHNhcGllbiB2aXZlcnJhIHV0LiBQaGFzZWxsdXMgdnVscHV0YXRlIGltcGVyZGlldCBsaWd1bGEsIGVnZXRcclxuZWxlaWZlbmQgbWV0dXMgdGVtcG9yIG5lYy4gTmFtIGVnZXQgc2FwaWVuIHJpc3VzLiBQcmFlc2VudCBpZCBzdXNjaXBpdCBlbGl0LiBTZWQgcGVsbGVudGVzcXVlIGxpZ3VsYVxyXG5kaWFtLCBub24gYWxpcXVldCBtYWduYSBmZXVnaWF0IHZpdGFlLiBQZWxsZW50ZXNxdWUgdXQgdG9ydG9yIGlkIGVyYXQgcGxhY2VyYXQgZGlnbmlzc2ltLiBQZWxsZW50ZXNxdWVcclxudXQgZHVpIHZlbCBsZW8gbGFvcmVldCBzb2RhbGVzIG5lYyBhYyB0ZWxsdXMuIEluIGhhYyBoYWJpdGFzc2UgcGxhdGVhIGRpY3R1bXN0LiBQcm9pbiBzZWQgZXggc2VkIGF1Z3VlXHJcbnNvbGxpY2l0dWRpbiBpbnRlcmR1bS4gU2VkIGlkIGxhY3VzIHBvcnR0aXRvciBuaXNpIHZlc3RpYnVsdW0gdGluY2lkdW50LiBOdWxsYSBmYWNpbGlzaS4gVmVzdGlidWx1bVxyXG5mZXVnaWF0IGZpbmlidXMgbWFnbmEgaW4gcHJldGl1bS4gUHJvaW4gY29uc2VjdGV0dXIgbGVjdHVzIG5pc2ksIG5vbiBjb21tb2RvIGxlY3R1cyB0ZW1wb3IgZXQuIENyYXNcclxudml2ZXJyYSwgbWkgaW4gY29uc2VxdWF0IGFsaXF1ZXQsIGp1c3RvIG1hdXJpcyBmcmluZ2lsbGEgdGVsbHVzLCBhdCBhY2N1bXNhbiBtYWduYSBtZXR1cyBpbiBlcm9zLiBTZWRcclxudmVoaWN1bGEsIGRpYW0gdXQgc2FnaXR0aXMgc2VtcGVyLCBwdXJ1cyBtYXNzYSBtYXR0aXMgZG9sb3IsIGluIHBvc3VlcmUuYDtcbi8vIF9yYW5kb21Xb3JkcyAtLSBBIGNvbGxlY3Rpb24gb2YgcmFuZG9tIHdvcmRzIGZvciB2YXJpb3VzIGRlYnVnZ2luZyBwdXJwb3Nlcy5cbmNvbnN0IF9yYW5kb21Xb3JkcyA9IGBcclxuYWJvdmVib2FyZHxhY2NvdW50fGFjaGlldmVyfGFjb3VzdGljc3xhY3R8YWN0aW9ufGFjdGl2aXR5fGFjdG9yfGFkZGl0aW9ufGFkanVzdG1lbnR8YWR2ZXJ0aXNlbWVudHxhZHZpY2V8YWZ0ZXJnbG93fGFmdGVyaW1hZ2V8YWZ0ZXJsaWZlfGFmdGVybWF0aHxhZnRlcm5vb258YWZ0ZXJ0aG91Z2h0fGFncmVlbWVudFxyXG5haXJ8YWlyY3JhZnR8YWlyZmllbGR8YWlybGlmdHxhaXJsaW5lfGFpcm1lbnxhaXJwbGFuZXxhaXJwb3J0fGFpcnRpbWV8YWxhcm18YWxsb3ZlcnxhbGxzcGljZXxhbG9uZ3NpZGV8YWxzb3xhbW91bnR8YW11c2VtZW50fGFuZ2VyfGFuZ2xlfGFuaW1hbHxhbm90aGVyfGFudHN8YW55aG93fGFueW1vcmVcclxuYW55b25lfGFueXBsYWNlfGFueXRpbWV8YW55d2hlcmV8YXBwYXJhdHVzfGFwcGFyZWx8YXBwbGlhbmNlfGFwcHJvdmFsfGFyY2h8YXJndW1lbnR8YXJpdGhtZXRpY3xhcm18YXJteXxhcm91bmR8YXJ0fGFzaHRyYXl8YXR0YWNrfGF0dHJhY3Rpb258YXVudHxhdXRob3JpdHl8YmFiaWVzfGJhYnl8YmFieXNpdHRlclxyXG5iYWNrfGJhY2thY2hlfGJhY2tib25lfGJhY2ticmVha2VyfGJhY2tkcm9wfGJhY2tmaXJlfGJhY2tncm91bmR8YmFja2hhbmR8YmFja2xhc2h8YmFja2xvZ3xiYWNrcGFja3xiYWNrc2lkZXxiYWNrc2xhcHxiYWNrc2xpZGV8YmFja3NwYWNlfGJhY2tzcGlufGJhY2tzdHJva2V8YmFja3RyYWNrfGJhY2t3YXJkXHJcbmJhZGdlfGJhZ3xiYWl0fGJhbGFuY2V8YmFsbHxiYWxscm9vbXxiYW5rYm9va3xiYW5rcm9sbHxiYXNlfGJhc2ViYWxsfGJhc2lufGJhc2tldHxiYXNrZXRiYWxsfGJhdHxiYXRofGJhdHRsZXxiZWFjaGNvbWJ8YmVhZHxiZWFyfGJlY2F1c2V8YmVjb21lfGJlZHxiZWRyb2NrfGJlZHJvbGx8YmVkcm9vbVxyXG5iZWRzfGJlZXxiZWVmfGJlZ2lubmVyfGJlaGF2aW9yfGJlbGllZnxiZWxpZXZlfGJlbGx8YmVsbGJveXxiZWxsaG9wfGJlbGxzfGJlbG93fGJlcnJ5fGJpa2V8YmlrZXN8YmlyZHxiaXJkc3xiaXJ0aHxiaXJ0aGRheXxiaXR8Yml0ZXxibGFja2JhbGx8YmxhY2tiZXJyaWVzfGJsYWNrYmlyZHxibGFja2JvYXJkXHJcbmJsYWNramFja3xibGFja2xpc3R8YmxhY2ttYWlsfGJsYWNrb3V0fGJsYWNrc21pdGh8YmxhY2t0b3B8YmxhZGV8Ymxvb2R8Ymxvd3xibG93Z3VufGJsdWViZWxsfGJsdWViZXJyeXxibHVlYmlyZHxibHVlZmlzaHxibHVlZ3Jhc3N8Ymx1ZXByaW50fGJvYXJkfGJvYXJkd2Fsa3xib2F0fGJvZHlndWFyZFxyXG5ib21ifGJvbmV8Ym9va3xib29rY2FzZXxib29rZW5kfGJvb2trZWVwZXJ8Ym9va21hcmt8Ym9va21vYmlsZXxib29rc3xib29rc2VsbGVyfGJvb2tzaGVsZnxib29rd29ybXxib290fGJvcmRlcnxib3R0bGV8Ym91bmRhcnl8Ym93bGVnc3xib3d0aWV8Ym94fGJveXxicmFpbmNoaWxkfGJyYWtlfGJyYW5jaFxyXG5icmFzc3xicmVhdGh8YnJpY2t8YnJpZGdlfGJyb3RoZXJ8YnViYmxlfGJ1Y2tldHxidWdzcHJheXxidWlsZGluZ3xidWxifGJ1cnN0fGJ1c2hlc3xidXNpbmVzc3xidXR0ZXJ8YnV0dGVyYmFsbHxidXR0ZXJjdXB8YnV0dGVyZmluZ2Vyc3xidXR0ZXJtaWxrfGJ1dHRlcm51dHxidXR0ZXJzY290Y2h8YnV0dG9uXHJcbmJ5cGFzc3xjYWJiYWdlfGNhYmRyaXZlcnxjYWJsZXxjYWN0dXN8Y2FrZXxjYWtlc3xjYWxjdWxhdG9yfGNhbGVuZGFyfGNhbWVyYXxjYW1wfGNhbnxjYW5jYW58Y2FuZGxlbGlnaHR8Y2FuZGxlc3RpY2t8Y2Fubm9ufGNhbm5vdHxjYW52YXN8Y2FwfGNhcHRpb258Y2FyfGNhcmR8Y2FyZHNoYXJwfGNhcmVcclxuY2FyZWZyZWV8Y2FyZXdvcm58Y2FyZmFyZXxjYXJsb2FkfGNhcnBlbnRlcnxjYXJwb29sfGNhcnBvcnR8Y2FycmlhZ2V8Y2Fyc3xjYXJzaWNrfGNhcnR8Y2FydHdoZWVsfGNhc3R8Y2F0fGNhdHN8Y2F0dGxlfGNhdHdhbGt8Y2F1c2V8Y2F2ZXxjYXZlbWFufGNlbGVyeXxjZWxsYXJ8Y2VtZXRlcnl8Y2VudFxyXG5jZW50ZXJjdXR8Y2hhbGt8Y2hhbmNlfGNoYW5nZXxjaGFubmVsfGNoZWVzZXxjaGVlc2VidXJnZXJ8Y2hlcnJpZXN8Y2hlcnJ5fGNoZXNzfGNoaWNrZW58Y2hpY2tlbnN8Y2hpbGRyZW58Y2hpbnxjaHVyY2h8Y2lyY2xlfGNsYW18Y2xhc3N8Y2xvY2t3aXNlfGNsb3RofGNsb3ZlcnxjbHVifGNvYWNofGNvYWxcclxuY29hc3R8Y29hdHxjb2J3ZWJ8Y29mZmVlbWFrZXJ8Y29pbHxjb2xsYXJ8Y29sb3J8Y29tZWJhY2t8Y29tbWl0dGVlfGNvbW1vbnBsYWNlfGNvbW1vbndlYWx0aHxjb21wYW55fGNvbXBhcmlzb258Y29tcGV0aXRpb258Y29uZGl0aW9ufGNvbm5lY3Rpb258Y29udHJvbHxjb29rfGNvcHBlcnxjb3JufGNvcm5tZWFsXHJcbmNvdWdofGNvdW50cnl8Y291cnRob3VzZXxjb3Zlcnxjb3d8Y293c3xjcmFja3xjcmFja2VyfGNyYXRlfGNyYXlvbnxjcmVhbXxjcmVhdG9yfGNyZWF0dXJlfGNyZWRpdHxjcmV3Y3V0fGNyaWJ8Y3JpbWV8Y3Jvb2t8Y3Jvc3Nib3d8Y3Jvc3NicmVlZHxjcm9zc2N1dHxjcm9zc292ZXJ8Y3Jvc3N3YWxrXHJcbmNyb3d8Y3Jvd2R8Y3Jvd258Y3VifGN1cHxjdXJyZW50fGN1cnRhaW58Y3VydmV8Y3VzaGlvbnxkYWR8ZGFpcnltYWlkfGRhaXN5d2hlZWx8ZGF1Z2h0ZXJ8ZGF5fGRheWJlZHxkYXlib29rfGRheWJyZWFrfGRheWRyZWFtfGRheWxpZ2h0fGRheXRpbWV8ZGVhZGVuZHxkZWFkbGluZXxkZWF0aHxkZWJ0XHJcbmRlY2lzaW9ufGRlZXJ8ZGVncmVlfGRlc2lnbnxkZXNpcmV8ZGVza3xkZXN0cnVjdGlvbnxkZXRhaWx8ZGV2ZWxvcG1lbnR8ZGlnZXN0aW9ufGRpbWV8ZGlubmVyfGRpbm9zYXVyc3xkaXJlY3Rpb258ZGlydHxkaXNjb3Zlcnl8ZGlzY3Vzc2lvbnxkaXNoY2xvdGh8ZGlzaHBhbnxkaXNod2FzaGVyfGRpc2h3YXRlclxyXG5kaXNrZHJpdmV8ZGlzdGFuY2V8ZGlzdHJpYnV0aW9ufGRpdmlzaW9ufGRvY2t8ZG9jdG9yfGRvZ3xkb2dzfGRvbGx8ZG9sbHN8ZG9ua2V5fGRvb3J8ZG9vcnN0b3B8ZG93bnRvd258ZG93bnVuZGVyfGRyYWlufGRyYXdicmlkZ2V8ZHJhd2VyfGRyZXNzfGRyaW5rfGRyaXZld2F5fGRyaXZpbmd8ZHJvcFxyXG5kdWNrfGR1Y2tiaWxsfGR1Y2twaW58ZHVja3N8ZHVzdHxlYXJ8ZWFyYWNoZXxlYXJyaW5nfGVhcnRofGVhcnRocXVha2V8ZWFydGh3YXJkfGVhcnRod29ybXxlZGdlfGVkdWNhdGlvbnxlZmZlY3R8ZWdnfGVnZ2hlYWR8ZWdnbm9nfGVnZ3N8ZWdnc2hlbGx8ZWxib3d8ZW5kfGVuZ2luZXxlcnJvcnxldmVudFxyXG5ldmVyeXRoaW5nfGV4YW1wbGV8ZXhjaGFuZ2V8ZXhpc3RlbmNlfGV4cGFuc2lvbnxleHBlcmllbmNlfGV4cGVydHxleWV8ZXllYmFsbHN8ZXllY2F0Y2hpbmd8ZXllZ2xhc3Nlc3xleWVsYXNofGV5ZWxpZHxleWVzfGV5ZXNpZ2h0fGV5ZXdpdG5lc3N8ZmFjZXxmYWN0fGZhaXJpZXN8ZmFsbHxmYW5nfGZhcm1cclxuZmF0aGVybGFuZHxmZWFyfGZlZWxpbmd8ZmllbGR8ZmluZ2VyfGZpcmV8ZmlyZWJhbGx8ZmlyZWJvYXR8ZmlyZWJvbWJ8ZmlyZWJyZWFrfGZpcmVjcmFja2VyfGZpcmVmaWdodGVyfGZpcmVob3VzZXxmaXJlbWFufGZpcmVwcm9vZnxmaXJld29ya3N8ZmlzaHxmaXNoYm93bHxmaXNoZXJtYW58ZmlzaGV5ZVxyXG5maXNoaG9va3xmaXNobW9uZ2VyfGZpc2huZXR8ZmlzaHBvbmR8ZmlzaHRhaWx8ZmxhZ3xmbGFtZXxmbGF2b3J8Zmxlc2h8ZmxpZ2h0fGZsb2NrfGZsb29yfGZsb3dlcnxmbG93ZXJzfGZseXxmb2d8Zm9sZHxmb29kfGZvb3R8Zm9vdGJhbGx8Zm9vdGhpbGx8Zm9vdGxpZ2h0c3xmb290bG9ja2VyfGZvb3RwcmludHNcclxuZm9yYmVhcmVyfGZvcmNlfGZvcmVhcm18Zm9yZWJlYXJ8Zm9yZWJyYWlufGZvcmVjYXN0fGZvcmVjbG9zZXxmb3JlY2xvc3VyZXxmb3JlZG9vbXxmb3JlZmF0aGVyfGZvcmVmZWV0fGZvcmVmaW5nZXJ8Zm9yZWZvb3R8Zm9yZWdvfGZvcmVnb25lfGZvcmVoYW5kfGZvcmVoZWFkfGZvcmVrbm93bGVkZ2VcclxuZm9yZWxlZ3xmb3JlbWFufGZvcmVwYXdzfGZvcmVzZWV8Zm9yZXNoYWRvd3xmb3Jlc3RhbGx8Zm9yZXRob3VnaHR8Zm9yZXRvbGR8Zm9yZXZlcnxmb3Jld2Fybnxmb3Jld29yZHxmb3JnZXR8Zm9ya3xmb3JrbGlmdHxmb3JtfGZvd2x8ZnJhbWV8ZnJpY3Rpb258ZnJpZW5kfGZyaWVuZHN8ZnJvZ3xmcm9nc1xyXG5mcm9udHxmcnVpdHxmcnVpdGN1cHxmdWVsfGZ1cm5pdHVyZXxnYXRlfGdlYXJzaGlmdHxnZWVzZXxnaG9zdHxnaWFudHN8Z2lyYWZmZXxnaXJsfGdpcmxzfGdsYXNzfGdsYXNzbWFraW5nfGdsb3ZlfGdvbGR8Z29vZGJ5ZXxnb29kbmlnaHR8Z292ZXJubWVudHxnb3Zlcm5vcnxncmFkZXxncmFpbnxncmFuZGF1bnRcclxuZ3JhbmRkYXVnaHRlcnxncmFuZGZhdGhlcnxncmFuZG1hc3RlcnxncmFuZG1vdGhlcnxncmFuZG5lcGhld3xncmFuZHBhcmVudHxncmFuZHNvbnxncmFuZHN0YW5kfGdyYW5kdW5jbGV8Z3JhcGV8Z3Jhc3N8Z3Jhc3NsYW5kfGdyYXZleWFyZHxncmlwfGdyb3VuZHxncm91cHxncm93dGh8Z3VpZGV8Z3VpdGFyXHJcbmd1bWJhbGx8Z3VufGhhaXJ8aGFpcmN1dHxoYWxsfGhhbWJ1cmdlcnxoYW1tZXJ8aGFuZHxoYW5kYm9va3xoYW5kZ3VufGhhbmRtYWRlfGhhbmRvdXR8aGFuZHN8aGFyYm9yfGhhcm1vbnl8aGF0fGhhdGV8aGVhZHxoZWFkYWNoZXxoZWFkbGlnaHR8aGVhZGxpbmV8aGVhZHF1YXJ0ZXJzfGhlYWx0aHxoZWF0XHJcbmhlcmVhZnRlcnxoZXJlYnl8aGVyZWlufGhlcmV1cG9ufGhpZ2hjaGFpcnxoaWdobGFuZHxoaWdod2F5fGhpbGx8aGltc2VsZnxoaXN0b3J5fGhvYmJpZXN8aG9sZXxob2xpZGF5fGhvbWV8aG9tZW1hZGV8aG9tZXRvd258aG9uZXl8aG9uZXliZWV8aG9uZXlkZXd8aG9uZXlzdWNrbGV8aG9va3xob29rdXBcclxuaG9wZXxob3JufGhvcnNlfGhvcnNlYmFja3xob3JzZWZseXxob3JzZWhhaXJ8aG9yc2VtYW58aG9yc2VwbGF5fGhvcnNlcG93ZXJ8aG9yc2VyYWRpc2h8aG9yc2VzfGhvc2V8aG9zcGl0YWx8aG90fGhvdXJ8aG91c2V8aG91c2Vib2F0fGhvdXNlaG9sZHxob3VzZWtlZXBlcnxob3VzZXN8aG91c2V0b3BcclxuaG93ZXZlcnxodW1vcnxoeWRyYW50fGljZXxpY2ljbGV8aWRlYXxpbXB1bHNlfGluY29tZXxpbmNyZWFzZXxpbmR1c3RyeXxpbmt8aW5zZWN0fGluc2lkZXxpbnN0cnVtZW50fGluc3VyYW5jZXxpbnRha2V8aW50ZXJlc3R8aW52ZW50aW9ufGlyb258aXNsYW5kfGl0c2VsZnxqYWlsfGphaWxiYWl0fGphbVxyXG5qYXJ8amVhbnN8amVsbHl8amVsbHliZWFufGplbGx5ZmlzaHxqZXRsaW5lcnxqZXRwb3J0fGpld2VsfGpvaW58anVkZ2V8anVpY2V8anVtcHxqdW1wc2hvdHxrZXR0bGV8a2V5fGtleWJvYXJkfGtleWhvbGV8a2V5bm90ZXxrZXlwYWR8a2V5cHVuY2h8a2V5c3RvbmV8a2V5c3Ryb2tlfGtleXdvcmR8a2lja1xyXG5raXNzfGtpdHRlbnN8a2l0dHl8a25lZXxrbmlmZXxrbm90fGtub3dsZWRnZXxsYWJvcmVyfGxhY2V8bGFkeWJ1Z3xsYWtlfGxhbXB8bGFuZHxsYW5ndWFnZXxsYXVnaHxsZWF0aGVyfGxlZ3xsZWdzfGxldHRlcnxsZXR0ZXJzfGxldHR1Y2V8bGV2ZWx8bGlicmFyeXxsaWZlYmxvb2R8bGlmZWd1YXJkfGxpZmVsaWtlXHJcbmxpZmVsaW5lfGxpZmVsb25nfGxpZmV0aW1lfGxpZmV3b3JrfGxpbWVsaWdodHxsaW1lc3RvbmV8bGltaXR8bGluZXxsaW5lbnxsaXB8bGlxdWlkfGxvYWZ8bG9ja3xsb2NrZXR8bG9uZ2hhbmR8bG9va3xsb3NzfGxvdmV8bG93fGx1a2V3YXJtfGx1bWJlcnxsdW5jaHxsdW5jaHJvb218bWFjaGluZXxtYWdpY1xyXG5tYWlkfG1haWxib3h8bWFpbmxpbmV8bWFufG1hcmJsZXxtYXJrfG1hcmtldHxtYXNrfG1hc3N8bWF0Y2h8bWF0Y2hib3h8bWVhbHxtZWFudGltZXxtZWFud2hpbGV8bWVhc3VyZXxtZWF0fG1lZXRpbmd8bWVtb3J5fG1lbnxtZXRhbHxtaWNlfG1pZGRsZXxtaWxrfG1pbmR8bWluZXxtaW5pc3RlcnxtaW50XHJcbm1pbnV0ZXxtaXN0fG1pdHRlbnxtb218bW9uZXl8bW9ua2V5fG1vbnRofG1vb258bW9vbmJlYW18bW9vbmxpZ2h0fG1vb25saXR8bW9vbnNjYXBlfG1vb25zaGluZXxtb29uc3RydWNrfG1vb253YWxrfG1vcmVvdmVyfG1vcm5pbmd8bW90aGVyfG1vdGlvbnxtb3RvcmN5Y2xlfG1vdW50YWlufG1vdXRoXHJcbm1vdmV8bXVzY2xlfG5hbWV8bmF0aW9ufG5lYXJieXxuZWNrfG5lZWR8bmVlZGxlfG5lcnZlfG5lc3R8bmV2ZXJtb3JlfG5ld3Nib3l8bmV3c2JyZWFrfG5ld3NjYXN0ZXJ8bmV3c2RlYWxlcnxuZXdzbGV0dGVyfG5ld3NtYW58bmV3c3BhcGVyfG5ld3NwcmludHxuZXdzcmVlbHxuZXdzcm9vbXxuaWdodFxyXG5uaWdodGZhbGx8bm9ib2R5fG5vaXNlfG5vaXNlbWFrZXJ8bm9ydGh8bm9ydGhlYXN0fG5vc2V8bm90ZXxub3RlYm9va3xub3doZXJlfG51bWJlcnxudXJzZW1haWR8bnV0fG51dGNyYWNrZXJ8b2F0bWVhbHxvYnNlcnZhdGlvbnxvY2VhbnxvZmZlcnxvZmZpY2V8b2lsfG9uZXNlbGZ8b25ldGltZXxvcmFuZ2Vcclxub3Jhbmdlc3xvcmRlcnxvdmVufG92ZXJib2FyZHxvdmVyY29hdHxvdmVyZmxvd3xvdmVybGFuZHxwYWNlbWFrZXJ8cGFnZXxwYWlsfHBhbnxwYW5jYWtlfHBhcGVyfHBhcmNlbHxwYXJ0fHBhcnRuZXJ8cGFydHl8cGFzc2Jvb2t8cGFzc2VuZ2VyfHBhc3NrZXl8UGFzc292ZXJ8cGFzc3BvcnR8cGF5bWVudFxyXG5wZWFjZXxwZWFyfHBlbnxwZW5jaWx8cGVwcGVybWludHxwZXJzb258cGVzdHxwZXR8cGV0c3xwaWNrbGV8cGlja3VwfHBpY3R1cmV8cGllfHBpZXN8cGlnfHBpZ3N8cGlufHBpbmhvbGV8cGluc3RyaXBlfHBpbnVwfHBpbndoZWVsfHBpcGV8cGl6emFzfHBsYWNlfHBsYW5lfHBsYW5lc3xwbGFudHxwbGFudGF0aW9uXHJcbnBsYW50c3xwbGFzdGljfHBsYXRlfHBsYXl8cGxheWJhY2t8cGxheWdyb3VuZHxwbGF5aG91c2V8cGxheXRoaW5nc3xwbGVhc3VyZXxwbG90fHBsb3VnaHxwb2NrZXR8cG9pbnR8cG9pc29ufHBvbGx1dGlvbnxwb255dGFpbHxwb3Bjb3JufHBvcnRlcnxwb3NpdGlvbnxwb3N0Y2FyZHxwb3R8cG90YXRvXHJcbnBvd2Rlcnxwb3dlcnxwcmljZXxwcm9kdWNlfHByb2ZpdHxwcm9wZXJ0eXxwcm9zZXxwcm90ZXN0fHB1bGx8cHVtcHxwdW5pc2htZW50fHB1cnBvc2V8cHVzaHxxdWFydGVyfHF1YXJ0enxxdWVlbnxxdWVzdGlvbnxxdWlja3NhbmR8cXVpZXR8cXVpbGx8cXVpbHR8cXVpbmNlfHF1aXZlcnxyYWJiaXR8cmFiYml0c1xyXG5yYWNxdWV0YmFsbHxyYWlsfHJhaWxyb2FkfHJhaWx3YXl8cmFpbnxyYWluY2hlY2t8cmFpbmNvYXR8cmFpbnN0b3JtfHJhaW53YXRlcnxyYWtlfHJhbmdlfHJhdHxyYXRlfHJhdHRsZXNuYWtlfHJhdHRsZXRyYXB8cmF5fHJlYWN0aW9ufHJlYWRpbmd8cmVhc29ufHJlY2VpcHR8cmVjZXNzfHJlY29yZFxyXG5yZWdyZXR8cmVsYXRpb258cmVsaWdpb258cmVwYWlybWFufHJlcHJlc2VudGF0aXZlfHJlcXVlc3R8cmVzcGVjdHxyZXN0fHJld2FyZHxyaHl0aG18cmljZXxyaWRkbGV8cmlmbGV8cmluZ3xyaW5nc3xyaXZlcnxyaXZlcmJhbmtzfHJvYWR8cm9iaW58cm9ja3xyb2R8cm9sbHxyb29mfHJvb218cm9vdFxyXG5yb3NlfHJvdXRlfHJ1YnxydWJiZXJiYW5kfHJ1bGV8cnVufHNhY2t8c2FpbHxzYWlsYm9hdHxzYWxlc2NsZXJrfHNhbHR8c2FuZHxzYW5kbG90fHNhbmRzdG9uZXxzYXVjZXBhbnxzY2FsZXxzY2FwZWdvYXR8c2NhcmVjcm93fHNjYXJmfHNjZW5lfHNjZW50fHNjaG9vbHxzY2hvb2xib29rfHNjaG9vbGJveVxyXG5zY2hvb2xidXN8c2Nob29saG91c2V8c2NpZW5jZXxzY2lzc29yc3xzY3Jld3xzZWF8c2Vhc2hvcmV8c2VhdHxzZWNyZXRhcnl8c2VlZHxzZWxlY3Rpb258c2VsZnxzZW5zZXxzZXJ2YW50fHNoYWRlfHNoYWR5c2lkZXxzaGFrZXxzaGFtZXxzaGFwZXxzaGFyZWNyb3BwZXJ8c2hhcnBzaG9vdGVyfHNoZWVwXHJcbnNoZWVwc2tpbnxzaGVldHxzaGVsZnxzaGlwfHNoaXJ0fHNob2NrfHNob2V8c2hvZWxhY2V8c2hvZW1ha2VyfHNob2VzfHNob3B8c2hvcnRicmVhZHxzaG93fHNob3dvZmZ8c2hvd3BsYWNlfHNpZGV8c2lkZWtpY2t8c2lkZXdhbGt8c2lnbnxzaWxrfHNpbHZlcnxzaWx2ZXJzbWl0aHxzaW5rfHNpc3RlclxyXG5zaXN0ZXJob29kfHNpc3RlcnN8c2l4Zm9sZHxzaXplfHNrYXRlfHNrYXRlYm9hcmR8c2tpbnxza2ludGlnaHR8c2tpcnR8c2t5fHNreWxhcmt8c2t5bGlnaHR8c2xhdmV8c2xlZXB8c2xlZXR8c2xpcHxzbG9wZXxzbG93ZG93bnxzbHVtbG9yZHxzbWFzaHxzbWVsbHxzbWlsZXxzbW9rZXxzbmFpbHxzbmFpbHNcclxuc25ha2V8c25ha2VzfHNuYWtlc2tpbnxzbmVlemV8c25vd3xzbm93YmFsbHxzbm93YmFua3xzbm93YmlyZHxzbm93ZHJpZnR8c25vd3Nob3ZlbHxzb2FwfHNvY2lldHl8c29ja3xzb2RhfHNvZmF8c29mdGJhbGx8c29tZWJvZHl8c29tZWRheXxzb21laG93fHNvbWVvbmV8c29tZXBsYWNlfHNvbWV0aGluZ1xyXG5zb21ldGltZXN8c29tZXdoYXR8c29tZXdoZXJlfHNvbnxzb25nfHNvbmdzfHNvcnR8c291bmR8c291bmRwcm9vZnxzb3VwfHNvdXRoZWFzdHxzb3V0aHdlc3R8c295YmVhbnxzcGFjZXxzcGFjZXdhbGt8c3BhZGV8c3Bhcmt8c3BlYXJtaW50fHNwaWRlcnN8c3BpbGx3YXl8c3Bva2VzcGVyc29ufHNwb25nZVxyXG5zcG9vbnxzcG90fHNwcmluZ3xzcHl8c3F1YXJlfHNxdWlycmVsfHN0YWdlfHN0YWdlaGFuZHxzdGFtcHxzdGFuZGJ5fHN0YW5kb2ZmfHN0YW5kb3V0fHN0YW5kcG9pbnR8c3RhcnxzdGFyZmlzaHxzdGFydHxzdGF0ZW1lbnR8c3RhdGlvbnxzdGVhbXxzdGVhbXNoaXB8c3RlZWx8c3RlbXxzdGVwfHN0ZXBzb25cclxuc3Rld3xzdGlja3xzdGlja3N8c3RpdGNofHN0b2NraW5nfHN0b2Nrcm9vbXxzdG9tYWNofHN0b25lfHN0b3B8c3RvcGxpZ2h0fHN0b3B3YXRjaHxzdG9yZXxzdG9yeXxzdG92ZXxzdHJhbmdlcnxzdHJhd3xzdHJlYW18c3RyZWV0fHN0cmV0Y2h8c3RyaW5nfHN0cm9uZ2hvbGR8c3RydWN0dXJlfHN1YnN0YW5jZVxyXG5zdWJ3YXl8c3VnYXJ8c3VnZ2VzdGlvbnxzdWl0fHN1bW1lcnxzdW58c3VuYmFrZWR8c3VuYmF0aGV8c3VuZGlhbHxzdW5kb3dufHN1bmZpc2h8c3VuZmxvd2VyfHN1bmdsYXNzZXN8c3VubGl0fHN1bnJheXxzdW5yb29mfHN1bnVwfHN1cGVyY2FyZ298c3VwZXJjaGFyZ2V8c3VwZXJjb29sfHN1cGVyZWdvXHJcbnN1cGVyZmluZXxzdXBlcmdpYW50fHN1cGVyaGVyb3xzdXBlcmhpZ2h3YXlzfHN1cGVyaHVtYW58c3VwZXJpbXBvc2V8c3VwZXJtYXJrZXR8c3VwZXJtZW58c3VwZXJuYXR1cmFsfHN1cGVycG93ZXJ8c3VwZXJzY3JpcHR8c3VwZXJzZW5zaXRpdmV8c3VwZXJzb25pY3xzdXBlcnN0YXJ8c3VwZXJzdHJvbmdcclxuc3VwZXJzdHJ1Y3R1cmV8c3VwZXJ0YW5rZXJ8c3VwZXJ3ZWFwb258c3VwZXJ3b21hbnxzdXBwb3J0fHN1cnByaXNlfHN3ZWF0ZXJ8c3dlZXRoZWFydHxzd2VldG1lYXR8c3dpbXxzd2luZ3xzeXN0ZW18dGFibGV8dGFibGVjbG90aHx0YWJsZXNwb29ufHRhYmxldG9wfHRhYmxld2FyZXx0YWlsfHRhaWxjb2F0XHJcbnRhaWxnYXRlfHRhaWxsaWdodHx0YWlsbGlrZXx0YWlscGllY2V8dGFpbHNwaW58dGFrZW9mZnx0YWtlb3V0fHRha2VvdmVyfHRhbGViZWFyZXJ8dGFsZXRlbGxlcnx0YWxrfHRhbmt8dGFwZXdvcm18dGFwcm9vbXx0YXByb290fHRhcmdldHx0YXNrbWFzdGVyfHRhc3RlfHRheHx0YXhpY2FifHRheHBheWVyXHJcbnRlYWNoaW5nfHRlYWN1cHx0ZWFtfHRlYW1tYXRlfHRlYW13b3JrfHRlYXBvdHx0ZWFzcG9vbnx0ZWVuYWdlcnx0ZWV0aHx0ZWxsdGFsZXx0ZW1wZXJ8dGVuZGVuY3l8dGVuZGVyZm9vdHx0ZW5mb2xkfHRlbnR8dGVycml0b3J5fHRlc3R8dGV4dGJvb2t8dGV4dHVyZXx0aGVvcnl8dGhlcmVmb3JlfHRoaW5nXHJcbnRoaW5nc3x0aG91Z2h0fHRocmVhZHx0aHJpbGx8dGhyb2F0fHRocm9uZXx0aHJvd2F3YXl8dGhyb3diYWNrfHRodW1ifHRodW5kZXJ8dGh1bmRlcmJpcmR8dGh1bmRlcnN0b3JtfHRpY2tldHx0aWdlcnx0aW1lfHRpbWVrZWVwZXJ8dGltZXNhdmluZ3x0aW1lc2hhcmV8dGltZXRhYmxlfHRpbnx0aXRsZVxyXG50b2FkfHRvZXx0b2VzfHRvZ2V0aGVyfHRvbWF0b2VzfHRvbmd1ZXx0b29sYm94fHRvb3RofHRvb3RoYnJ1c2h8dG9vdGhwYXN0ZXx0b290aHBpY2t8dG9wfHRvdWNofHRvdWNoZG93bnx0b3dufHRvd25zaGlwfHRveXx0b3lzfHRyYWRlfHRyYWlsfHRyYWlufHRyYWluc3x0cmFtcHx0cmFuc3BvcnR8dHJheVxyXG50cmVhdG1lbnR8dHJlZXx0cmVlc3x0cmlja3x0cmlwfHRyb3VibGV8dHJvdXNlcnN8dHJ1Y2t8dHJ1Y2tzfHR1Ynx0dXJrZXl8dHVybnx0dXJuYWJvdXR8dHVybmFyb3VuZHx0dXJuYnVja2xlfHR1cm5kb3dufHR1cm5rZXl8dHVybm9mZnx0dXJudGFibGV8dHdpZ3x0d2lzdHx0eXBld3JpdGVyfHVtYnJlbGxhXHJcbnVuY2xlfHVuZGVyYWNoaWV2ZXx1bmRlcmFnZXx1bmRlcmFybXx1bmRlcmJlbGx5fHVuZGVyYmlkfHVuZGVyY2hhcmdlfHVuZGVyY2xvdGhlc3x1bmRlcmNvdmVyfHVuZGVyY3V0fHVuZGVyZGV2ZWxvcHx1bmRlcmVzdGltYXRlfHVuZGVyZXhwb3NlfHVuZGVyZm9vdHx1bmRlcmdyb3VuZHx1bmRlcndlYXJcclxudW5pdHx1cGJlYXR8dXBicmluZ2luZ3x1cGNvbWluZ3x1cGRhdGV8dXBlbmR8dXBncmFkZXx1cGhlYXZhbHx1cGhpbGx8dXBob2xkfHVwa2VlcHx1cGxhbmR8dXBsaWZ0fHVwbG9hZHx1cG1hcmtldHx1cG9ufHVwcGVyY2FzZXx1cHBlcmNsYXNzbWFufHVwcGVyY3V0fHVwcm9hcnx1cHJvb3R8dXBzZXRcclxudXBzaG90fHVwc2lkZXx1cHN0YWdlfHVwc3RhaXJzfHVwc3RhbmRpbmd8dXBzdGFydHx1cHN0YXRlfHVwc3RyZWFtfHVwdGFrZXx1cHRocnVzdHx1cHRpZ2h0fHVwdGltZXx1cHRvd258dXB3YXJkfHVwd2luZHx1c2V8dmFjYXRpb258dmFsdWV8dmFufHZhc2V8dmVnZXRhYmxlfHZlaWx8dmVpbnx2ZXJzZVxyXG52ZXNzZWx8dmVzdHx2aWV3fHZpc2l0b3J8dm9pY2V8dm9sY2Fub3x2b2xsZXliYWxsfHZveWFnZXx3YWlzdGxpbmV8d2Fsa3x3YWxrd2F5c3x3YWxsfHdhbGxleWVkfHdhbGxwYXBlcnx3YXJ8d2FyZHJvb218d2FyZmFyZXx3YXJtYmxvb2RlZHx3YXJwYXRofHdhc2h8d2FzaGJvd2x8d2FzaGNsb3RofHdhc2hob3VzZVxyXG53YXNob3V0fHdhc2hyYWd8d2FzaHJvb218d2FzaHN0YW5kfHdhc2h0dWJ8d2FzdGV8d2FzdGViYXNrZXR8d2FzdGVsYW5kfHdhc3RlcGFwZXJ8d2FzdGV3YXRlcnx3YXRjaHx3YXRjaGJhbmR8d2F0Y2hkb2d8d2F0Y2htYWtlcnx3YXRjaG1hbnx3YXRjaHRvd2VyfHdhdGNod29yZHx3YXRlcnx3YXRlcmNvbG9yXHJcbndhdGVyY29vbGVyfHdhdGVyY3JhZnR8d2F0ZXJmYWxsfHdhdGVyZnJvbnR8d2F0ZXJsaW5lfHdhdGVybG9nfHdhdGVybWVsb258d2F0ZXJwb3dlcnx3YXRlcnByb29mfHdhdGVyc2NhcGV8d2F0ZXJzaGVkfHdhdGVyc2lkZXx3YXRlcnNwb3V0fHdhdGVydGlnaHR8d2F2ZXx3YXZlbGlrZXx3YXZlc3x3YXhcclxud2F4d29ya3x3YXl8d2F5YmlsbHx3YXlmYXJlcnx3YXlsYWlkfHdheXNpZGV8d2F5d2FyZHx3ZWFsdGh8d2VhdGhlcnx3ZWF0aGVyY29ja3x3ZWF0aGVybWFufHdlYXRoZXJwcm9vZnx3ZWVrfHdlZWtkYXl8d2Vla2VuZHx3ZWVrbmlnaHR8d2VpZ2h0fHdoYXRldmVyfHdoYXRzb2V2ZXJ8d2hlZWx8d2hlZWxjaGFpclxyXG53aGVlbGhvdXNlfHdoaXB8d2hpc3RsZXx3aGl0ZWNhcHx3aGl0ZWZpc2h8d2hpdGV3YWxsfHdoaXRld2FzaHx3aWRlc3ByZWFkfHdpbGRlcm5lc3N8d2luZHx3aW5kb3d8d2luZXx3aW5nfHdpbnRlcnx3aXBlb3V0fHdpcmV8d2lzaHx3aXRob3V0fHdvbWFufHdvbWVufHdvb2R8d29vZHNob3B8d29vbFxyXG53b3JkfHdvcmt8d29ybXx3b3VuZHx3cmVufHdyZW5jaHx3cmlzdHx3cml0ZXJ8d3JpdGluZ3x5YWt8eWFtfHlhcmR8eWFybnx5ZWFyfHlva2V8emVicmF8emVwaHlyfHppbmN8emlwcGVyfHpvb1xyXG5gLnNwbGl0KFwifFwiKTtcbmNvbnN0IF9udW1iZXJXb3JkcyA9IHtcbiAgICBvbmVzOiBbXG4gICAgICAgIFwiemVyb1wiLCBcIm9uZVwiLCBcInR3b1wiLCBcInRocmVlXCIsIFwiZm91clwiLCBcImZpdmVcIiwgXCJzaXhcIiwgXCJzZXZlblwiLCBcImVpZ2h0XCIsIFwibmluZVwiLFxuICAgICAgICBcInRlblwiLCBcImVsZXZlblwiLCBcInR3ZWx2ZVwiLCBcInRoaXJ0ZWVuXCIsIFwiZm91cnRlZW5cIiwgXCJmaWZ0ZWVuXCIsIFwic2l4dGVlblwiLCBcInNldmVudGVlblwiLCBcImVpZ2h0ZWVuXCIsIFwibmluZXRlZW5cIixcbiAgICAgICAgXCJ0d2VudHlcIlxuICAgIF0sXG4gICAgdGVuczogW1wiXCIsIFwiXCIsIFwidHdlbnR5XCIsIFwidGhpcnR5XCIsIFwiZm9ydHlcIiwgXCJmaWZ0eVwiLCBcInNpeHR5XCIsIFwic2V2ZW50eVwiLCBcImVpZ2h0eVwiLCBcIm5pbmV0eVwiXSxcbiAgICB0aWVyczogW1wiXCIsIFwidGhvdXNhbmRcIiwgXCJtaWxsaW9uXCIsIFwiYmlsbGlvblwiLCBcInRyaWxsaW9uXCIsIFwicXVhZHJpbGxpb25cIiwgXCJxdWludGlsbGlvblwiLCBcInNleHRpbGxpb25cIiwgXCJzZXB0aWxsaW9uXCIsIFwib2N0aWxsaW9uXCIsIFwibm9uaWxsaW9uXCJdLFxuICAgIGJpZ1ByZWZpeGVzOiBbXCJcIiwgXCJ1blwiLCBcImR1b1wiLCBcInRyZVwiLCBcInF1YXR0dW9yXCIsIFwicXVpblwiLCBcInNleFwiLCBcIm9jdG9cIiwgXCJub3ZlbVwiXSxcbiAgICBiaWdTdWZmaXhlczogW1wiXCIsIFwiZGVjaWxsaW9uXCIsIFwidmlnaW50aWxsaW9uXCIsIFwidHJpZ2ludGlsbGlvblwiLCBcInF1YWRyYWdpbnRpbGxpb25cIiwgXCJxdWlucXVhZ2ludGlsbGlvblwiLCBcInNleGFnaW50aWxsaW9uXCIsIFwic2VwdHVhZ2ludGlsbGlvblwiLCBcIm9jdG9naW50aWxsaW9uXCIsIFwibm9uYWdpbnRpbGxpb25cIiwgXCJjZW50aWxsaW9uXCJdXG59O1xuY29uc3QgX29yZGluYWxzID0ge1xuICAgIHplcm86IFwiemVyb2V0aFwiLCBvbmU6IFwiZmlyc3RcIiwgdHdvOiBcInNlY29uZFwiLCB0aHJlZTogXCJ0aGlyZFwiLCBmb3VyOiBcImZvdXJ0aFwiLCBmaXZlOiBcImZpZnRoXCIsIGVpZ2h0OiBcImVpZ2h0aFwiLCBuaW5lOiBcIm5pbnRoXCIsIHR3ZWx2ZTogXCJ0d2VsZnRoXCIsXG4gICAgdHdlbnR5OiBcInR3ZW50aWV0aFwiLCB0aGlydHk6IFwidGhpcnRpZXRoXCIsIGZvcnR5OiBcImZvcnRpZXRoXCIsIGZpZnR5OiBcImZpZnRpZXRoXCIsIHNpeHR5OiBcInNpeHRpZXRoXCIsIHNldmVudHk6IFwic2V2ZW50aWV0aFwiLCBlaWdodHk6IFwiZWlnaHRpZXRoXCIsIG5pbmV0eTogXCJuaW5ldGlldGhcIlxufTtcbmNvbnN0IF9yb21hbk51bWVyYWxzID0ge1xuICAgIGdyb3VwZWQ6IFtcbiAgICAgICAgW1wiXCIsIFwi4oWgXCIsIFwi4oWhXCIsIFwi4oWiXCIsIFwi4oWjXCIsIFwi4oWkXCIsIFwi4oWlXCIsIFwi4oWmXCIsIFwi4oWnXCIsIFwi4oWoXCJdLFxuICAgICAgICBbXCJcIiwgXCLihalcIiwgXCLihanihalcIiwgXCLihanihanihalcIiwgXCLihanihaxcIiwgXCLihaxcIiwgXCLihazihalcIiwgXCLihazihanihalcIiwgXCLihazihanihanihalcIiwgXCLihaniha1cIl0sXG4gICAgICAgIFtcIlwiLCBcIuKFrVwiLCBcIuKFreKFrVwiLCBcIuKFreKFreKFrVwiLCBcIuKFreKFrlwiLCBcIuKFrlwiLCBcIuKFruKFrVwiLCBcIuKFruKFreKFrVwiLCBcIuKFruKFreKFreKFrVwiLCBcIuKFreKFr1wiXSxcbiAgICAgICAgW1wiXCIsIFwi4oWvXCIsIFwi4oWv4oWvXCIsIFwi4oWv4oWv4oWvXCIsIFwi4oWv4oaBXCIsIFwi4oaBXCIsIFwi4oaB4oWvXCIsIFwi4oaB4oWv4oWvXCIsIFwi4oaB4oWv4oWv4oWvXCIsIFwi4oaB4oaCXCJdLFxuICAgICAgICBbXCJcIiwgXCLihoJcIiwgXCLihoLihoJcIiwgXCLihoLihoLihoJcIiwgXCLihoLihodcIiwgXCLihodcIiwgXCLihofihoJcIiwgXCLihofihoLihoJcIiwgXCLihofihoLihoLihoJcIiwgXCLihofihohcIl0sXG4gICAgICAgIFtcIlwiLCBcIuKGiFwiLCBcIuKGiOKGiFwiLCBcIuKGiOKGiOKGiFwiXVxuICAgIF0sXG4gICAgdW5ncm91cGVkOiBbXG4gICAgICAgIFtcIlwiLCBcIuKFoFwiLCBcIuKFoOKFoFwiLCBcIuKFoOKFoOKFoFwiLCBcIuKFoOKFpFwiLCBcIuKFpFwiLCBcIuKFpOKFoFwiLCBcIuKFpOKFoOKFoFwiLCBcIuKFpOKFoOKFoOKFoFwiLCBcIuKFoOKFqVwiXSxcbiAgICAgICAgW1wiXCIsIFwi4oWpXCIsIFwi4oWp4oWpXCIsIFwi4oWp4oWp4oWpXCIsIFwi4oWp4oWsXCIsIFwi4oWsXCIsIFwi4oWs4oWpXCIsIFwi4oWs4oWp4oWpXCIsIFwi4oWs4oWp4oWp4oWpXCIsIFwi4oWp4oWtXCJdLFxuICAgICAgICBbXCJcIiwgXCLiha1cIiwgXCLiha3iha1cIiwgXCLiha3iha3iha1cIiwgXCLiha3iha5cIiwgXCLiha5cIiwgXCLiha7iha1cIiwgXCLiha7iha3iha1cIiwgXCLiha7iha3iha3iha1cIiwgXCLiha3iha9cIl0sXG4gICAgICAgIFtcIlwiLCBcIuKFr1wiLCBcIuKFr+KFr1wiLCBcIuKFr+KFr+KFr1wiLCBcIuKFr+KGgVwiLCBcIuKGgVwiLCBcIuKGgeKFr1wiLCBcIuKGgeKFr+KFr1wiLCBcIuKGgeKFr+KFr+KFr1wiLCBcIuKGgeKGglwiXSxcbiAgICAgICAgW1wiXCIsIFwi4oaCXCIsIFwi4oaC4oaCXCIsIFwi4oaC4oaC4oaCXCIsIFwi4oaC4oaHXCIsIFwi4oaHXCIsIFwi4oaH4oaCXCIsIFwi4oaH4oaC4oaCXCIsIFwi4oaH4oaC4oaC4oaCXCIsIFwi4oaH4oaIXCJdLFxuICAgICAgICBbXCJcIiwgXCLihohcIiwgXCLihojihohcIiwgXCLihojihojihohcIl1cbiAgICBdXG59O1xuY29uc3QgVVVJRExPRyA9IFtdO1xuLy8gI2VuZHJlZ2lvbiDilq7ilq7ilq7ilq5bSEVMUEVSU13ilq7ilq7ilq7ilq5cbi8vICNyZWdpb24g4paI4paI4paI4paI4paI4paI4paI4paIIEdFVFRFUlM6IEJhc2ljIERhdGEgTG9va3VwICYgUmV0cmlldmFsIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCB+XG4vLyBAdHMtZXhwZWN0LWVycm9yIExlYXVnZSBvZiBmb3VuZHJ5IGRldmVsb3BlcnMgaXMgd3JvbmcgYWJvdXQgdXNlciBub3QgYmVpbmcgb24gZ2FtZS5cbmNvbnN0IEdNSUQgPSAoKSA9PiBnYW1lPy51c2VyPy5maW5kKCh1c2VyKSA9PiB1c2VyLmlzR00pPy5pZCA/PyBmYWxzZTtcbi8vICNlbmRyZWdpb24g4paE4paE4paE4paE4paEIEdFVFRFUlMg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBUWVBFUzogVHlwZSBDaGVja2luZywgVmFsaWRhdGlvbiwgQ29udmVyc2lvbiwgQ2FzdGluZyDilojilojilojilojilojilojilojiloggflxuY29uc3QgaXNOdW1iZXIgPSAocmVmKSA9PiB0eXBlb2YgcmVmID09PSBcIm51bWJlclwiICYmICFpc05hTihyZWYpO1xuY29uc3QgaXNOdW1TdHJpbmcgPSAocmVmKSA9PiB0eXBlb2YgcmVmID09PSBcInN0cmluZ1wiXG4gICAgJiYgIWlzTmFOKHBhcnNlRmxvYXQocmVmKSlcbiAgICAmJiBpc0Zpbml0ZShwYXJzZUZsb2F0KHJlZikpO1xuY29uc3QgaXNCb29sZWFuU3RyaW5nID0gKHJlZikgPT4gdHlwZW9mIHJlZiA9PT0gXCJzdHJpbmdcIlxuICAgICYmIChyZWYgPT09IFwidHJ1ZVwiIHx8IHJlZiA9PT0gXCJmYWxzZVwiKTtcbmNvbnN0IGlzQXJyYXkgPSAocmVmKSA9PiBBcnJheS5pc0FycmF5KHJlZik7XG5jb25zdCBpc1NpbXBsZU9iaiA9IChyZWYpID0+IHJlZiA9PT0gT2JqZWN0KHJlZikgJiYgIWlzQXJyYXkocmVmKTtcbmNvbnN0IGlzTGlzdCA9IChyZWYpID0+IHJlZiA9PT0gT2JqZWN0KHJlZikgJiYgIWlzQXJyYXkocmVmKTtcbmNvbnN0IGlzRnVuYyA9IChyZWYpID0+IHR5cGVvZiByZWYgPT09IFwiZnVuY3Rpb25cIjtcbmNvbnN0IGlzSW50ID0gKHJlZikgPT4gaXNOdW1iZXIocmVmKSAmJiBNYXRoLnJvdW5kKHJlZikgPT09IHJlZjtcbmNvbnN0IGlzRmxvYXQgPSAocmVmKSA9PiBpc051bWJlcihyZWYpICYmIC9cXC4vLnRlc3QoYCR7cmVmfWApO1xuY29uc3QgaXNQb3NJbnQgPSAocmVmKSA9PiBpc0ludChyZWYpICYmIHJlZiA+PSAwO1xuY29uc3QgaXNJbmRleCA9IChyZWYpID0+IGlzTGlzdChyZWYpIHx8IGlzQXJyYXkocmVmKTtcbmNvbnN0IGlzSXRlcmFibGUgPSAocmVmKSA9PiB0eXBlb2YgcmVmID09PSBcIm9iamVjdFwiICYmIHJlZiAhPT0gbnVsbCAmJiBTeW1ib2wuaXRlcmF0b3IgaW4gcmVmO1xuY29uc3QgaXNIVE1MQ29kZSA9IChyZWYpID0+IHR5cGVvZiByZWYgPT09IFwic3RyaW5nXCIgJiYgL148Lio+JC91LnRlc3QocmVmKTtcbmNvbnN0IGlzSGV4Q29sb3IgPSAocmVmKSA9PiB0eXBlb2YgcmVmID09PSBcInN0cmluZ1wiICYmIC9eIygoWzAtOWEtZkEtRl17Mn0pezMsNH18WzAtOWEtZkEtRl17Myw0fSkkLy50ZXN0KHJlZik7XG5jb25zdCBpc1JHQkNvbG9yID0gKHJlZikgPT4gdHlwZW9mIHJlZiA9PT0gXCJzdHJpbmdcIiAmJiAvXnJnYmE/XFwoKFxcZHsxLDN9LFxccyopezEsMn0/XFxkezEsM30sXFxzKlxcZHsxLDN9KFxcLlxcZCspP1xcKSQvLnRlc3QocmVmKTtcbmNvbnN0IGlzVW5kZWZpbmVkID0gKHJlZikgPT4gcmVmID09PSB1bmRlZmluZWQ7XG5jb25zdCBpc0RlZmluZWQgPSAocmVmKSA9PiAhaXNVbmRlZmluZWQocmVmKTtcbmNvbnN0IGlzRW1wdHkgPSAocmVmKSA9PiBPYmplY3Qua2V5cyhyZWYpLmxlbmd0aCA9PT0gMDtcbmNvbnN0IGhhc0l0ZW1zID0gKHJlZikgPT4gIWlzRW1wdHkocmVmKTtcbmNvbnN0IGlzSW5zdGFuY2UgPSAoY2xhc3NSZWYsIHJlZikgPT4gcmVmIGluc3RhbmNlb2YgY2xhc3NSZWY7XG5jb25zdCBpc051bGxpc2ggPSAocmVmKSA9PiBpc1VuZGVmaW5lZChyZWYpIHx8IHJlZiA9PT0gbnVsbDtcbi8qKlxuICogQXNzZXJ0cyB0aGF0IGEgZ2l2ZW4gdmFsdWUgaXMgb2YgYSBzcGVjaWZpZWQgdHlwZS5cbiAqIFRocm93cyBhbiBlcnJvciBpZiB0aGUgdmFsdWUgaXMgbm90IG9mIHRoZSBleHBlY3RlZCB0eXBlLlxuICpcbiAqIEB0ZW1wbGF0ZSBUIFRoZSBleHBlY3RlZCB0eXBlIG9mIHRoZSB2YWx1ZS5cbiAqIEBwYXJhbSB7dW5rbm93bn0gdmFsIFRoZSB2YWx1ZSB0byBjaGVjay5cbiAqIEBwYXJhbSB7KG5ldyguLi5hcmdzOiB1bmtub3duW10pID0+IFQpIHwgc3RyaW5nfSB0eXBlIFRoZSBleHBlY3RlZCB0eXBlIG9mIHRoZSB2YWx1ZS5cbiAqIEB0aHJvd3Mge0Vycm9yfSBJZiB0aGUgdmFsdWUgaXMgbm90IG9mIHRoZSBleHBlY3RlZCB0eXBlLlxuICovXG5mdW5jdGlvbiBhc3NlcnROb25OdWxsVHlwZSh2YWwsIHR5cGUpIHtcbiAgICBsZXQgdmFsU3RyO1xuICAgIC8vIEF0dGVtcHQgdG8gY29udmVydCB0aGUgdmFsdWUgdG8gYSBzdHJpbmcgZm9yIGVycm9yIG1lc3NhZ2luZy5cbiAgICB0cnkge1xuICAgICAgICB2YWxTdHIgPSBKU09OLnN0cmluZ2lmeSh2YWwpO1xuICAgIH1cbiAgICBjYXRjaCB7XG4gICAgICAgIHZhbFN0ciA9IFN0cmluZyh2YWwpO1xuICAgIH1cbiAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgaXMgdW5kZWZpbmVkXG4gICAgaWYgKHZhbCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVmFsdWUgJHt2YWxTdHJ9IGlzIHVuZGVmaW5lZCFgKTtcbiAgICB9XG4gICAgLy8gSWYgdGhlIHR5cGUgaXMgYSBzdHJpbmcsIGNvbXBhcmUgdGhlIHR5cGVvZiB0aGUgdmFsdWUgdG8gdGhlIHR5cGUgc3RyaW5nLlxuICAgIGlmICh0eXBlb2YgdHlwZSA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgdmFsaWQtdHlwZW9mXG4gICAgICAgIGlmICh0eXBlb2YgdmFsICE9PSB0eXBlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFZhbHVlICR7dmFsU3RyfSBpcyBub3QgYSAke3R5cGV9IWApO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKCEodmFsIGluc3RhbmNlb2YgdHlwZSkpIHtcbiAgICAgICAgLy8gSWYgdGhlIHR5cGUgaXMgYSBmdW5jdGlvbiAoY29uc3RydWN0b3IpLCBjaGVjayBpZiB0aGUgdmFsdWUgaXMgYW4gaW5zdGFuY2Ugb2YgdGhlIHR5cGUuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVmFsdWUgJHt2YWxTdHJ9IGlzIG5vdCBhICR7dHlwZS5uYW1lfSFgKTtcbiAgICB9XG59XG4vKipcbiAqIENoZWNrcyBpZiB0d28gdmFsdWVzIGFyZSBcImZ1enp5XCIgZXF1YWwsIHNpbXVsYXRpbmcgdGhlIGJlaGF2aW9yIG9mIHRoZSBcIj09XCIgb3BlcmF0b3IuXG4gKiBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHVzZSB0aGUgXCI9PVwiIG9wZXJhdG9yIGRpcmVjdGx5IHRvIGNvbXBseSB3aXRoIGxpbnRpbmcgcnVsZXMuXG4gKlxuICogQHBhcmFtIHt1bmtub3dufSB2YWwxIFRoZSBmaXJzdCB2YWx1ZSB0byBjb21wYXJlLlxuICogQHBhcmFtIHt1bmtub3dufSB2YWwyIFRoZSBzZWNvbmQgdmFsdWUgdG8gY29tcGFyZS5cbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSB2YWx1ZXMgYXJlIFwiZnV6enlcIiBlcXVhbCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5jb25zdCBhcmVGdXp6eUVxdWFsID0gKHZhbDEsIHZhbDIpID0+IHtcbiAgICAvLyBJZiBib3RoIHZhbHVlcyBhcmUgbnVsbCBvciB1bmRlZmluZWQsIHRoZXkgYXJlIGNvbnNpZGVyZWQgZXF1YWxcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXModmFsMSlcbiAgICAgICAgJiYgW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXModmFsMikpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIC8vIElmIG9ubHkgb25lIG9mIHRoZSB2YWx1ZXMgaXMgbnVsbCBvciB1bmRlZmluZWQsIHRoZXkgYXJlIG5vdCBlcXVhbFxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyh2YWwxKVxuICAgICAgICB8fCBbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyh2YWwyKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIElmIGJvdGggdmFsdWVzIGFyZSBudW1iZXJzLCB0aGV5IGFyZSBjb25zaWRlcmVkIGVxdWFsIGlmIHRoZXkgYXJlIG51bWVyaWNhbGx5IGVxdWFsXG4gICAgaWYgKHR5cGVvZiB2YWwxID09PSBcIm51bWJlclwiICYmIHR5cGVvZiB2YWwyID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgIHJldHVybiB2YWwxID09PSB2YWwyO1xuICAgIH1cbiAgICAvLyBJZiBib3RoIHZhbHVlcyBhcmUgYm9vbGVhbnMsIHRoZXkgYXJlIGNvbnNpZGVyZWQgZXF1YWwgaWYgdGhleSBhcmUgYm90aCB0cnVlIG9yIGJvdGggZmFsc2VcbiAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwiYm9vbGVhblwiICYmIHR5cGVvZiB2YWwyID09PSBcImJvb2xlYW5cIikge1xuICAgICAgICByZXR1cm4gdmFsMSA9PT0gdmFsMjtcbiAgICB9XG4gICAgLy8gSWYgYm90aCB2YWx1ZXMgYXJlIHN0cmluZ3MsIHRoZXkgYXJlIGNvbnNpZGVyZWQgZXF1YWwgaWYgdGhleSBhcmUgaWRlbnRpY2FsXG4gICAgaWYgKHR5cGVvZiB2YWwxID09PSBcInN0cmluZ1wiICYmIHR5cGVvZiB2YWwyID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiB2YWwxID09PSB2YWwyO1xuICAgIH1cbiAgICAvLyBJZiBvbmUgdmFsdWUgaXMgYSBudW1iZXIgYW5kIHRoZSBvdGhlciBpcyBhIHN0cmluZywgdGhleSBhcmUgY29uc2lkZXJlZFxuICAgIC8vICAgICAgICAgICAgICAgICAgICAgICAgIGVxdWFsIGlmIHRoZSBzdHJpbmcgY2FuIGJlIGNvbnZlcnRlZCB0byB0aGUgbnVtYmVyXG4gICAgaWYgKHR5cGVvZiB2YWwxID09PSBcIm51bWJlclwiICYmIHR5cGVvZiB2YWwyID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiB2YWwxID09PSBOdW1iZXIodmFsMik7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgdmFsMSA9PT0gXCJzdHJpbmdcIiAmJiB0eXBlb2YgdmFsMiA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICByZXR1cm4gTnVtYmVyKHZhbDEpID09PSB2YWwyO1xuICAgIH1cbiAgICAvLyBJZiBvbmUgdmFsdWUgaXMgYSBib29sZWFuIGFuZCB0aGUgb3RoZXIgaXMgYSBub24tbnVsbCBvYmplY3QsIHRoZXkgYXJlIG5vdCBlcXVhbFxuICAgIGlmICh0eXBlb2YgdmFsMSA9PT0gXCJib29sZWFuXCIgJiYgdHlwZW9mIHZhbDIgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIHZhbDIgPT09IFwiYm9vbGVhblwiKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gSWYgb25lIHZhbHVlIGlzIGEgYm9vbGVhbiBhbmQgdGhlIG90aGVyIGlzIGEgc3RyaW5nLCB0aGV5IGFyZSBjb25zaWRlcmVkIGVxdWFsIElEOlxuICAgIC8vICAgICAgLi4uIHRoZSBib29sZWFuIGlzIHRydWUgYW5kIHRoZSBzdHJpbmcgaXMgbm90IGVtcHR5LCBvclxuICAgIC8vICAgICAgLi4uIHRoZSBib29sZWFuIGlzIGZhbHNlIGFuZCB0aGUgc3RyaW5nIGlzIGVtcHR5XG4gICAgaWYgKHR5cGVvZiB2YWwxID09PSBcImJvb2xlYW5cIlxuICAgICAgICAmJiB0eXBlb2YgdmFsMiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICByZXR1cm4gKHZhbDEgJiYgdmFsMiAhPT0gXCJcIikgfHwgKCF2YWwxICYmIHZhbDIgPT09IFwiXCIpO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwic3RyaW5nXCJcbiAgICAgICAgJiYgdHlwZW9mIHZhbDIgPT09IFwiYm9vbGVhblwiKSB7XG4gICAgICAgIHJldHVybiAodmFsMiAmJiB2YWwxICE9PSBcIlwiKSB8fCAoIXZhbDIgJiYgdmFsMSA9PT0gXCJcIik7XG4gICAgfVxuICAgIC8vIElmIG9uZSB2YWx1ZSBpcyBhIG51bWJlciBvciBhIHN0cmluZyBhbmQgdGhlIG90aGVyIGlzIGFuIG9iamVjdCwgdGhleSBhcmUgbm90IGVxdWFsXG4gICAgaWYgKCh0eXBlb2YgdmFsMSA9PT0gXCJudW1iZXJcIiB8fCB0eXBlb2YgdmFsMSA9PT0gXCJzdHJpbmdcIikgJiYgdHlwZW9mIHZhbDIgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIHZhbDEgPT09IFwib2JqZWN0XCIgJiYgKHR5cGVvZiB2YWwyID09PSBcIm51bWJlclwiIHx8IHR5cGVvZiB2YWwyID09PSBcInN0cmluZ1wiKSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIC8vIElmIGJvdGggdmFsdWVzIGFyZSBvYmplY3RzLCB0aGV5IGFyZSBjb25zaWRlcmVkIGVxdWFsIGlmIHRoZXkgYXJlIGlkZW50aWNhbFxuICAgIGlmICh0eXBlb2YgdmFsMSA9PT0gXCJvYmplY3RcIiAmJiB0eXBlb2YgdmFsMiA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICByZXR1cm4gdmFsMSA9PT0gdmFsMjtcbiAgICB9XG4gICAgLy8gSWYgbm9uZSBvZiB0aGUgYWJvdmUgY29uZGl0aW9ucyBhcmUgbWV0LCB0aGUgdmFsdWVzIGFyZSBub3QgZXF1YWxcbiAgICByZXR1cm4gZmFsc2U7XG59O1xuY29uc3QgYXJlRXF1YWwgPSAoLi4ucmVmcykgPT4ge1xuICAgIGRvIHtcbiAgICAgICAgY29uc3QgcmVmID0gcmVmcy5wb3AoKTtcbiAgICAgICAgaWYgKHJlZnMubGVuZ3RoICYmICFhcmVGdXp6eUVxdWFsKHJlZiwgcmVmc1swXSkpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgIH0gd2hpbGUgKHJlZnMubGVuZ3RoKTtcbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5jb25zdCBwRmxvYXQgPSAocmVmLCBzaWdEaWdpdHMsIGlzU3RyaWN0ID0gZmFsc2UpID0+IHtcbiAgICBpZiAodHlwZW9mIHJlZiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICByZWYgPSBwYXJzZUZsb2F0KHJlZik7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcmVmID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgIGlmIChpc05hTihyZWYpKSB7XG4gICAgICAgICAgICByZXR1cm4gaXNTdHJpY3QgPyBOYU4gOiAwO1xuICAgICAgICB9XG4gICAgICAgIGlmIChpc1VuZGVmaW5lZChzaWdEaWdpdHMpKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVmO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBNYXRoLnJvdW5kKHJlZiAqICgxMCAqKiBzaWdEaWdpdHMpKSAvICgxMCAqKiBzaWdEaWdpdHMpO1xuICAgIH1cbiAgICByZXR1cm4gaXNTdHJpY3QgPyBOYU4gOiAwO1xufTtcbmNvbnN0IHBJbnQgPSAocmVmLCBpc1N0cmljdE9ySW5kZXgsIF9hcnIpID0+IHtcbiAgICBsZXQgaXNTdHJpY3QgPSBmYWxzZTtcbiAgICBpZiAodHlwZW9mIGlzU3RyaWN0T3JJbmRleCA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgICAgaXNTdHJpY3QgPSBpc1N0cmljdE9ySW5kZXg7XG4gICAgfVxuICAgIHJldHVybiAoaXNOYU4ocEZsb2F0KHJlZiwgMCwgaXNTdHJpY3QpKSA/IE5hTiA6IE1hdGgucm91bmQocEZsb2F0KHJlZiwgMCwgaXNTdHJpY3QpKSk7XG59O1xuY29uc3QgcEJvb2wgPSAocmVmKSA9PiB7XG4gICAgaWYgKHR5cGVvZiByZWYgPT09IFwiYm9vbGVhblwiKSB7XG4gICAgICAgIHJldHVybiByZWY7XG4gICAgfVxuICAgIGlmIChbMCwgbnVsbCwgdW5kZWZpbmVkLCBcIlwiXS5pbmNsdWRlcyhyZWYpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHR5cGVvZiByZWYgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgcmV0dXJuICFbXCIwXCIsIFwiZmFsc2VcIiwgXCJudWxsXCIsIFwidW5kZWZpbmVkXCIsIFwiXCJdLmluY2x1ZGVzKHJlZik7XG4gICAgfVxuICAgIGlmIChpc0FycmF5KHJlZikgJiYgcmVmLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGlmIChpc0xpc3QocmVmKSAmJiBpc0VtcHR5KHJlZikpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5jb25zdCByYWRUb0RlZyA9IChyYWQsIGlzQ29uc3RyYWluZWQgPSB0cnVlKSA9PiB7XG4gICAgcmFkID0gaXNDb25zdHJhaW5lZCA/IHJhZCAlICgyICogTWF0aC5QSSkgOiByYWQ7XG4gICAgcmFkICo9IDE4MCAvIE1hdGguUEk7XG4gICAgcmV0dXJuIHJhZDtcbn07XG5jb25zdCBkZWdUb1JhZCA9IChkZWcsIGlzQ29uc3RyYWluZWQgPSB0cnVlKSA9PiB7XG4gICAgZGVnID0gaXNDb25zdHJhaW5lZCA/IGRlZyAlIDM2MCA6IGRlZztcbiAgICBkZWcgKj0gTWF0aC5QSSAvIDE4MDtcbiAgICByZXR1cm4gZGVnO1xufTtcbmNvbnN0IGdldEtleSA9IChrZXksIG9iaikgPT4ge1xuICAgIGlmIChrZXkgaW4gb2JqKSB7XG4gICAgICAgIHJldHVybiBvYmpba2V5XTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59O1xuY29uc3QgRklMVEVSUyA9IHtcbiAgICBJc0luc3RhbmNlOiAoKGNsYXNzUmVmKSA9PiAoKGl0ZW0pID0+IHR5cGVvZiBjbGFzc1JlZiA9PT0gXCJmdW5jdGlvblwiICYmIGl0ZW0gaW5zdGFuY2VvZiBjbGFzc1JlZikpXG59O1xuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgVFlQRVMg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBTVFJJTkdTOiBTdHJpbmcgUGFyc2luZywgTWFuaXB1bGF0aW9uLCBDb252ZXJzaW9uLCBSZWd1bGFyIEV4cHJlc3Npb25zIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiFxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbQ2FzZSBDb252ZXJzaW9uXeKWkeKWkeKWkeKWkSBVcHBlciwgTG93ZXIsIFNlbnRlbmNlICYgVGl0bGUgQ2FzZSDilpHilpHilpHilpHilpHilpHilpEgflxuY29uc3QgdUNhc2UgPSAoc3RyKSA9PiBTdHJpbmcoc3RyKS50b1VwcGVyQ2FzZSgpO1xuY29uc3QgbENhc2UgPSAoc3RyKSA9PiBTdHJpbmcoc3RyKS50b0xvd2VyQ2FzZSgpO1xuY29uc3Qgc0Nhc2UgPSAoc3RyKSA9PiB7XG4gICAgbGV0IFtmaXJzdCwgLi4ucmVzdF0gPSBgJHtzdHIgPz8gXCJcIn1gLnNwbGl0KC9cXHMrLyk7XG4gICAgZmlyc3QgPSB0ZXN0UmVnRXhwKGZpcnN0LCBfY2FwV29yZHMpID8gZmlyc3QgOiBgJHt1Q2FzZShmaXJzdC5jaGFyQXQoMCkpfSR7bENhc2UoZmlyc3Quc2xpY2UoMSkpfWA7XG4gICAgaWYgKGhhc0l0ZW1zKHJlc3QpKSB7XG4gICAgICAgIHJlc3QgPSByZXN0Lm1hcCgod29yZCkgPT4gKHRlc3RSZWdFeHAod29yZCwgX2NhcFdvcmRzKSA/IHdvcmQgOiBsQ2FzZSh3b3JkKSkpO1xuICAgIH1cbiAgICByZXR1cm4gW2ZpcnN0LCAuLi5yZXN0XS5qb2luKFwiIFwiKS50cmltKCk7XG59O1xuY29uc3QgdENhc2UgPSAoc3RyKSA9PiBTdHJpbmcoc3RyKS5zcGxpdCgvXFxzLylcbiAgICAubWFwKCh3b3JkLCBpKSA9PiAoaSAmJiB0ZXN0UmVnRXhwKHdvcmQsIF9ub0NhcFdvcmRzKSA/IGxDYXNlKHdvcmQpIDogc0Nhc2Uod29yZCkpKVxuICAgIC5qb2luKFwiIFwiKS50cmltKCk7XG4vLyAjZW5kcmVnaW9uIOKWkeKWkeKWkeKWkVtDYXNlIENvbnZlcnNpb25d4paR4paR4paR4paRXG4vLyAjcmVnaW9uIOKWkeKWkeKWkeKWkeKWkeKWkeKWkVtSZWdFeHBd4paR4paR4paR4paRIFJlZ3VsYXIgRXhwcmVzc2lvbnMg4paR4paR4paR4paR4paR4paR4paRIH5cbmNvbnN0IHRlc3RSZWdFeHAgPSAoc3RyLCBwYXR0ZXJucyA9IFtdLCBmbGFncyA9IFwiZ3VpXCIsIGlzVGVzdGluZ0FsbCA9IGZhbHNlKSA9PiBwYXR0ZXJuc1xuICAgIC5tYXAoKHBhdHRlcm4pID0+IChwYXR0ZXJuIGluc3RhbmNlb2YgUmVnRXhwXG4gICAgPyBwYXR0ZXJuXG4gICAgOiBuZXcgUmVnRXhwKGBcXFxcYiR7cGF0dGVybn1cXFxcYmAsIGZsYWdzKSkpW2lzVGVzdGluZ0FsbCA/IFwiZXZlcnlcIiA6IFwic29tZVwiXSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGAke3N0cn1gKSk7XG5jb25zdCByZWdFeHRyYWN0ID0gKHJlZiwgcGF0dGVybiwgZmxhZ3MpID0+IHtcbiAgICAvKiBXcmFwcGVyIGFyb3VuZCBTdHJpbmcubWF0Y2goKSB0aGF0IHJlbW92ZXMgdGhlIG5lZWQgdG8gd29ycnkgYWJvdXQgbWF0Y2goKSdzIGRpZmZlcmVudCBoYW5kbGluZyBvZiB0aGUgJ2cnIGZsYWcuXG4gICAgICAgIC0gSUYgeW91ciBwYXR0ZXJuIGNvbnRhaW5zIHVuZXNjYXBlZCBwYXJlbnRoZXNlcyAtPiBSZXR1cm5zIEFycmF5IG9mIGFsbCBtYXRjaGluZyBncm91cHMuXG4gICAgICAgIC0gT1RIRVJXSVNFIC0+IFJldHVybnMgc3RyaW5nIHRoYXQgbWF0Y2hlcyB0aGUgcHJvdmlkZWQgcGF0dGVybi4gKi9cbiAgICBjb25zdCBzcGxpdEZsYWdzID0gW107XG4gICAgWy4uLihmbGFncyA/PyBcIlwiKS5yZXBsYWNlKC9nL2csIFwiXCIpLCBcInVcIl0uZm9yRWFjaCgoZmxhZykgPT4ge1xuICAgICAgICBpZiAoZmxhZyAmJiAhc3BsaXRGbGFncy5pbmNsdWRlcyhmbGFnKSkge1xuICAgICAgICAgICAgc3BsaXRGbGFncy5wdXNoKGZsYWcpO1xuICAgICAgICB9XG4gICAgfSk7XG4gICAgY29uc3QgaXNHcm91cGluZyA9IC9bKShdLy50ZXN0KHBhdHRlcm4udG9TdHJpbmcoKS5yZXBsYWNlKC9cXFxcXFwpfFxcXFxcXCgvZywgXCJcIikpO1xuICAgIGlmIChpc0dyb3VwaW5nKSB7XG4gICAgICAgIHNwbGl0RmxhZ3MucHVzaChcImdcIik7XG4gICAgfVxuICAgIGZsYWdzID0gc3BsaXRGbGFncy5qb2luKFwiXCIpO1xuICAgIHBhdHRlcm4gPSBuZXcgUmVnRXhwKHBhdHRlcm4sIGZsYWdzKTtcbiAgICBjb25zdCBtYXRjaGVzID0gYCR7cmVmfWAubWF0Y2gocGF0dGVybikgfHwgW107XG4gICAgcmV0dXJuIGlzR3JvdXBpbmcgPyBBcnJheS5mcm9tKG1hdGNoZXMpIDogbWF0Y2hlcy5wb3AoKTtcbn07XG4vLyAjZW5kcmVnaW9uIOKWkeKWkeKWkeKWkVtSZWdFeHBd4paR4paR4paR4paRXG4vLyAjcmVnaW9uIOKWkeKWkeKWkeKWkeKWkeKWkeKWkVtGb3JtYXR0aW5nXeKWkeKWkeKWkeKWkSBIeXBoZW5hdGlvbiwgUGx1cmFsaXphdGlvbiwgXCJhXCIvXCJhblwiIEZpeGluZyDilpHilpHilpHilpHilpHilpHilpEgflxuLy8gY29uc3QgaHlwaGVuYXRlID0gKHN0cjogdW5rbm93bikgPT4gKC9ePHxcXHUwMEFEfFxcdTIwMEIvLnRlc3QoYCR7c3RyfWApID8gYCR7c3RyfWAgOiBfaHlwaChgJHtzdHJ9YCkpO1xuY29uc3QgdW5oeXBoZW5hdGUgPSAoc3RyKSA9PiBgJHtzdHJ9YC5yZXBsYWNlKC9bXFx1MDBBRFxcdTIwMEJdL2d1LCBcIlwiKTtcbmNvbnN0IHBhcnNlQXJ0aWNsZXMgPSAoc3RyKSA9PiBgJHtzdHJ9YC5yZXBsYWNlKC9cXGIoW2FBXSlcXHMoW2FlaW91QUVJT1VdKS9ndSwgXCIkMW4gJDJcIik7XG5jb25zdCBwbHVyYWxpemUgPSAoc2luZ3VsYXIsIG51bSA9IDIsIHBsdXJhbCkgPT4ge1xuICAgIGlmIChwRmxvYXQobnVtKSA9PT0gMSkge1xuICAgICAgICByZXR1cm4gc2luZ3VsYXI7XG4gICAgfVxuICAgIHJldHVybiBwbHVyYWwgPz8gYCR7c2luZ3VsYXIucmVwbGFjZSgveSQvLCBcImllXCIpLnJlcGxhY2UoL3MkLywgXCJzZVwiKX1zYDtcbn07XG5jb25zdCBveGZvcmRpemUgPSAoaXRlbXMsIHVzZU94Zm9yZENvbW1hID0gdHJ1ZSwgYW5kU3RyaW5nID0gXCJhbmRcIikgPT4ge1xuICAgIGlmIChpdGVtcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuICAgIGlmIChpdGVtcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIGAke2l0ZW1zWzBdfWA7XG4gICAgfVxuICAgIGNvbnN0IGxhc3RJdGVtID0gaXRlbXMucG9wKCk7XG4gICAgcmV0dXJuIFtcbiAgICAgICAgaXRlbXMuam9pbihcIiwgXCIpLFxuICAgICAgICB1c2VPeGZvcmRDb21tYSA/IFwiLFwiIDogXCJcIixcbiAgICAgICAgYCAke2FuZFN0cmluZ30gYCxcbiAgICAgICAgbGFzdEl0ZW1cbiAgICBdLmpvaW4oXCJcIik7XG59O1xuY29uc3QgZWxsaXBzaXplID0gKHRleHQsIG1heExlbmd0aCkgPT4ge1xuICAgIGNvbnN0IHN0ciA9IFN0cmluZyh0ZXh0KTtcbiAgICByZXR1cm4gc3RyLmxlbmd0aCA+IG1heExlbmd0aCA/IGAke3N0ci5zbGljZSgwLCBtYXhMZW5ndGggLSAzKX3igKZgIDogc3RyO1xufTtcbmNvbnN0IHBhZCA9ICh0ZXh0LCBtaW5MZW5ndGgsIGRlbGltID0gXCIgXCIpID0+IHtcbiAgICBjb25zdCBzdHIgPSBgJHt0ZXh0fWA7XG4gICAgaWYgKHN0ci5sZW5ndGggPCBtaW5MZW5ndGgpIHtcbiAgICAgICAgcmV0dXJuIGAke2RlbGltLnJlcGVhdChtaW5MZW5ndGggLSBzdHIubGVuZ3RoKX0ke3N0cn1gO1xuICAgIH1cbiAgICByZXR1cm4gc3RyO1xufTtcbmNvbnN0IHRvS2V5ID0gKHRleHQpID0+ICh0ZXh0ID8/IFwiXCIpLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgvIC9nLCBcIi1cIikucmVwbGFjZSgvZGVmYXVsdC8sIFwiREVGQVVMVFwiKTtcbi8vICNyZWdpb24gPT09PT09PT09PSBOdW1iZXJzOiBGb3JtYXR0aW5nIE51bWJlcnMgSW50byBTdHJpbmdzID09PT09PT09PT09IH5cbmNvbnN0IHNpZ25OdW0gPSAobnVtLCBkZWxpbSA9IFwiXCIsIHplcm9TaWduID0gXCIrXCIpID0+IHtcbiAgICBsZXQgc2lnbjtcbiAgICBjb25zdCBwYXJzZWROdW0gPSBwRmxvYXQobnVtKTtcbiAgICBpZiAocGFyc2VkTnVtIDwgMCkge1xuICAgICAgICBzaWduID0gXCItXCI7XG4gICAgfVxuICAgIGVsc2UgaWYgKHBhcnNlZE51bSA9PT0gMCkge1xuICAgICAgICBzaWduID0gemVyb1NpZ247XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBzaWduID0gXCIrXCI7XG4gICAgfVxuICAgIHJldHVybiBgJHtzaWdufSR7ZGVsaW19JHtNYXRoLmFicyhwYXJzZWROdW0pfWA7XG59O1xuY29uc3QgcGFkTnVtID0gKG51bSwgbnVtRGVjRGlnaXRzLCBpbmNsdWRlUGx1cyA9IGZhbHNlKSA9PiB7XG4gICAgY29uc3QgcHJlZml4ID0gKGluY2x1ZGVQbHVzICYmIG51bSA+PSAwKSA/IFwiK1wiIDogXCJcIjtcbiAgICBjb25zdCBbbGVmdERpZ2l0cywgcmlnaHREaWdpdHNdID0gYCR7cEZsb2F0KG51bSl9YC5zcGxpdCgvXFwuLyk7XG4gICAgaWYgKGdldFR5cGUocmlnaHREaWdpdHMpID09PSBcImludFwiKSB7XG4gICAgICAgIGlmIChyaWdodERpZ2l0cy5sZW5ndGggPiBudW1EZWNEaWdpdHMpIHtcbiAgICAgICAgICAgIHJldHVybiBgJHtwcmVmaXh9JHtwRmxvYXQobnVtLCBudW1EZWNEaWdpdHMpfWA7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAocmlnaHREaWdpdHMubGVuZ3RoIDwgbnVtRGVjRGlnaXRzKSB7XG4gICAgICAgICAgICByZXR1cm4gYCR7cHJlZml4fSR7bGVmdERpZ2l0c30uJHtyaWdodERpZ2l0c30ke1wiMFwiLnJlcGVhdChudW1EZWNEaWdpdHMgLSByaWdodERpZ2l0cy5sZW5ndGgpfWA7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gYCR7cHJlZml4fSR7cEZsb2F0KG51bSl9YDtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYCR7cHJlZml4fSR7bGVmdERpZ2l0c30uJHtcIjBcIi5yZXBlYXQobnVtRGVjRGlnaXRzKX1gO1xufTtcbmNvbnN0IHN0cmluZ2lmeU51bSA9IChudW0pID0+IHtcbiAgICAvLyBDYW4gdGFrZSBzdHJpbmcgcmVwcmVzZW50YXRpb25zIG9mIG51bWJlcnMsIGVpdGhlciBpbiBzdGFuZGFyZCBvciBzY2llbnRpZmljL2VuZ2luZWVyaW5nIG5vdGF0aW9uLlxuICAgIC8vIFJldHVybnMgYSBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIG51bWJlciBpbiBzdGFuZGFyZCBub3RhdGlvbi5cbiAgICBpZiAocEZsb2F0KG51bSkgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIFwiMFwiO1xuICAgIH1cbiAgICBjb25zdCBzdHJpbmd5TnVtID0gbENhc2UobnVtKS5yZXBsYWNlKC9bXlxcZC5lKy1dL2csIFwiXCIpO1xuICAgIGNvbnN0IGJhc2UgPSByZWdFeHRyYWN0KHN0cmluZ3lOdW0sIC9eLT9bXFxkLl0rLyk7XG4gICAgY29uc3QgZXhwID0gcEludChyZWdFeHRyYWN0KHN0cmluZ3lOdW0sIC9lKFsrLV0/XFxkKykkLykpO1xuICAgIGlmICh0eXBlb2YgYmFzZSA9PT0gXCJzdHJpbmdcIiAmJiB0eXBlb2YgZXhwID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIGxldCBiYXNlSW50cyA9IHJlZ0V4dHJhY3QoYmFzZSwgL14tPyhcXGQrKS8pO1xuICAgICAgICBsZXQgYmFzZURlY3MgPSByZWdFeHRyYWN0KGJhc2UsIC9cXC4oXFxkKykvKTtcbiAgICAgICAgaWYgKGlzQXJyYXkoYmFzZUludHMpICYmIGlzQXJyYXkoYmFzZURlY3MpKSB7XG4gICAgICAgICAgICBiYXNlSW50cyA9IGJhc2VJbnRzLnBvcCgpPy5yZXBsYWNlKC9eMCsvLCBcIlwiKTtcbiAgICAgICAgICAgIGJhc2VEZWNzID0gbENhc2UoYmFzZURlY3M/LnBvcCgpKS5yZXBsYWNlKC8wKyQvLCBcIlwiKTtcbiAgICAgICAgICAgIGlmICghaXNVbmRlZmluZWQoYmFzZUludHMpICYmICFpc1VuZGVmaW5lZChiYXNlRGVjcykpIHtcbiAgICAgICAgICAgICAgICBjb25zdCBudW1GaW5hbEludHMgPSBNYXRoLm1heCgwLCBiYXNlSW50cy5sZW5ndGggKyBleHApO1xuICAgICAgICAgICAgICAgIGNvbnN0IG51bUZpbmFsRGVjcyA9IE1hdGgubWF4KDAsIGJhc2VEZWNzLmxlbmd0aCAtIGV4cCk7XG4gICAgICAgICAgICAgICAgY29uc3QgZmluYWxJbnRzID0gW1xuICAgICAgICAgICAgICAgICAgICBiYXNlSW50cy5zbGljZSgwLCBudW1GaW5hbEludHMpLFxuICAgICAgICAgICAgICAgICAgICBiYXNlRGVjcy5zbGljZSgwLCBNYXRoLm1heCgwLCBleHApKVxuICAgICAgICAgICAgICAgIF0uam9pbihcIlwiKSB8fCBcIjBcIjtcbiAgICAgICAgICAgICAgICBjb25zdCBmaW5hbERlY3MgPSBbXG4gICAgICAgICAgICAgICAgICAgIGJhc2VJbnRzLmxlbmd0aCAtIG51bUZpbmFsSW50cyA+IDBcbiAgICAgICAgICAgICAgICAgICAgICAgID8gYmFzZUludHMuc2xpY2UoYmFzZUludHMubGVuZ3RoIC0gbnVtRmluYWxJbnRzIC0gMSlcbiAgICAgICAgICAgICAgICAgICAgICAgIDogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgYmFzZURlY3Muc2xpY2UoYmFzZURlY3MubGVuZ3RoIC0gbnVtRmluYWxEZWNzKVxuICAgICAgICAgICAgICAgIF0uam9pbihcIlwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgICAgICBzdHJpbmd5TnVtLmNoYXJBdCgwKSA9PT0gXCItXCIgPyBcIi1cIiA6IFwiXCIsXG4gICAgICAgICAgICAgICAgICAgIGZpbmFsSW50cyxcbiAgICAgICAgICAgICAgICAgICAgXCIwXCIucmVwZWF0KE1hdGgubWF4KDAsIG51bUZpbmFsSW50cyAtIGZpbmFsSW50cy5sZW5ndGgpKSxcbiAgICAgICAgICAgICAgICAgICAgZmluYWxEZWNzLmxlbmd0aCA/IFwiLlwiIDogXCJcIixcbiAgICAgICAgICAgICAgICAgICAgXCIwXCIucmVwZWF0KE1hdGgubWF4KDAsIG51bUZpbmFsRGVjcyAtIGZpbmFsRGVjcy5sZW5ndGgpKSxcbiAgICAgICAgICAgICAgICAgICAgZmluYWxEZWNzXG4gICAgICAgICAgICAgICAgXS5qb2luKFwiXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBgJHtudW19YDtcbn07XG5jb25zdCB2ZXJiYWxpemVOdW0gPSAobnVtKSA9PiB7XG4gICAgLy8gQ29udmVydHMgYSBmbG9hdCB3aXRoIGFic29sdXRlIG1hZ25pdHVkZSA8PSA5Ljk5ZTMwMyBpbnRvIHdvcmRzLlxuICAgIG51bSA9IHN0cmluZ2lmeU51bShudW0pO1xuICAgIGNvbnN0IGdldFRpZXIgPSAodHJpb051bSkgPT4ge1xuICAgICAgICBpZiAodHJpb051bSA8IF9udW1iZXJXb3Jkcy50aWVycy5sZW5ndGgpIHtcbiAgICAgICAgICAgIHJldHVybiBfbnVtYmVyV29yZHMudGllcnNbdHJpb051bV07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIF9udW1iZXJXb3Jkcy5iaWdQcmVmaXhlc1sodHJpb051bSAlIDEwKSAtIDFdLFxuICAgICAgICAgICAgX251bWJlcldvcmRzLmJpZ1N1ZmZpeGVzW01hdGguZmxvb3IodHJpb051bSAvIDEwKV1cbiAgICAgICAgXS5qb2luKFwiXCIpO1xuICAgIH07XG4gICAgY29uc3QgcGFyc2VUaHJlZURpZ2l0cyA9ICh0cmlvKSA9PiB7XG4gICAgICAgIGlmIChwSW50KHRyaW8pID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gXCJcIjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkaWdpdHMgPSBgJHt0cmlvfWAuc3BsaXQoXCJcIikubWFwKChkaWdpdCkgPT4gcEludChkaWdpdCkpO1xuICAgICAgICBsZXQgcmVzdWx0ID0gXCJcIjtcbiAgICAgICAgaWYgKGRpZ2l0cy5sZW5ndGggPT09IDMpIHtcbiAgICAgICAgICAgIGNvbnN0IGh1bmRyZWRzID0gZGlnaXRzLnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAoaXNVbmRlZmluZWQoaHVuZHJlZHMpKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBbVS52ZXJiYWxpemVOdW1dIFVuZGVmaW5lZCBkaWdpdCBpbiB0cmlvICcke2RpZ2l0cy5qb2luKFwiXCIpfScuYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXN1bHQgKz0gaHVuZHJlZHMgPiAwID8gYCR7X251bWJlcldvcmRzLm9uZXNbaHVuZHJlZHNdfSBodW5kcmVkYCA6IFwiXCI7XG4gICAgICAgICAgICBpZiAoaHVuZHJlZHMgJiYgKGRpZ2l0c1swXSB8fCBkaWdpdHNbMV0pKSB7XG4gICAgICAgICAgICAgICAgcmVzdWx0ICs9IFwiIGFuZCBcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAocEludChkaWdpdHMuam9pbihcIlwiKSkgPD0gX251bWJlcldvcmRzLm9uZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXN1bHQgKz0gX251bWJlcldvcmRzLm9uZXNbcEludChkaWdpdHMuam9pbihcIlwiKSldO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY29uc3QgdGVucyA9IF9udW1iZXJXb3Jkcy50ZW5zW3BJbnQoZGlnaXRzLnNoaWZ0KCkpXTtcbiAgICAgICAgICAgIGNvbnN0IG9uZXMgPSBwSW50KGRpZ2l0c1swXSkgPiAwID8gYC0ke19udW1iZXJXb3Jkcy5vbmVzW3BJbnQoZGlnaXRzWzBdKV19YCA6IFwiXCI7XG4gICAgICAgICAgICByZXN1bHQgKz0gYCR7dGVuc30ke29uZXN9YDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH07XG4gICAgY29uc3QgbnVtV29yZHMgPSBbXTtcbiAgICBpZiAobnVtLmNoYXJBdCgwKSA9PT0gXCItXCIpIHtcbiAgICAgICAgbnVtV29yZHMucHVzaChcIm5lZ2F0aXZlXCIpO1xuICAgIH1cbiAgICBjb25zdCBbaW50ZWdlcnMsIGRlY2ltYWxzXSA9IG51bS5yZXBsYWNlKC9bLFxccy1dL2csIFwiXCIpLnNwbGl0KFwiLlwiKTtcbiAgICBjb25zdCBpbnRBcnJheSA9IFsuLi5pbnRlZ2Vycy5zcGxpdChcIlwiKV0ucmV2ZXJzZSgpLmpvaW4oXCJcIilcbiAgICAgICAgLm1hdGNoKC8uezEsM30vZylcbiAgICAgICAgPy5tYXAoKHYpID0+IFsuLi52LnNwbGl0KFwiXCIpXS5yZXZlcnNlKCkuam9pbihcIlwiKSkgPz8gW107XG4gICAgY29uc3QgaW50U3RyaW5ncyA9IFtdO1xuICAgIHdoaWxlIChpbnRBcnJheS5sZW5ndGgpIHtcbiAgICAgICAgY29uc3QgdGhpc1RyaW8gPSBpbnRBcnJheS5wb3AoKTtcbiAgICAgICAgaWYgKHRoaXNUcmlvKSB7XG4gICAgICAgICAgICBjb25zdCB0aGVzZVdvcmRzID0gcGFyc2VUaHJlZURpZ2l0cyh0aGlzVHJpbyk7XG4gICAgICAgICAgICBpZiAodGhlc2VXb3Jkcykge1xuICAgICAgICAgICAgICAgIGludFN0cmluZ3MucHVzaChgJHt0aGVzZVdvcmRzfSAke2dldFRpZXIoaW50QXJyYXkubGVuZ3RoKX1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cbiAgICBudW1Xb3Jkcy5wdXNoKGludFN0cmluZ3Muam9pbihcIiwgXCIpLnRyaW0oKSk7XG4gICAgaWYgKGdldFR5cGUoZGVjaW1hbHMpID09PSBcImludFwiKSB7XG4gICAgICAgIGlmIChpbnRlZ2VycyA9PT0gXCIwXCIpIHtcbiAgICAgICAgICAgIG51bVdvcmRzLnB1c2goXCJ6ZXJvXCIpO1xuICAgICAgICB9XG4gICAgICAgIG51bVdvcmRzLnB1c2goXCJwb2ludFwiKTtcbiAgICAgICAgZm9yIChjb25zdCBkaWdpdCBvZiBkZWNpbWFscy5zcGxpdChcIlwiKSkge1xuICAgICAgICAgICAgbnVtV29yZHMucHVzaChfbnVtYmVyV29yZHMub25lc1twSW50KGRpZ2l0KV0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBudW1Xb3Jkcy5qb2luKFwiIFwiKTtcbn07XG5jb25zdCBvcmRpbmFsaXplTnVtID0gKG51bSwgaXNSZXR1cm5pbmdXb3JkcyA9IGZhbHNlKSA9PiB7XG4gICAgaWYgKGlzUmV0dXJuaW5nV29yZHMpIHtcbiAgICAgICAgY29uc3QgW251bVRleHQsIHN1ZmZpeF0gPSBsQ2FzZSh2ZXJiYWxpemVOdW0obnVtKSkubWF0Y2goLy4qP1stXFxzXT8oXFx3KikkL2kpID8/IFtcIlwiLCBcIlwiXTtcbiAgICAgICAgcmV0dXJuIG51bVRleHQucmVwbGFjZShuZXcgUmVnRXhwKGAke3N1ZmZpeH0kYCksIHN1ZmZpeCBpbiBfb3JkaW5hbHMgPyBfb3JkaW5hbHNbc3VmZml4XSA6IGAke3N1ZmZpeH10aGApO1xuICAgIH1cbiAgICBpZiAoLyhcXC4pfCgxWzEtM10kKS8udGVzdChgJHtudW19YCkpIHtcbiAgICAgICAgcmV0dXJuIGAke251bX10aGA7XG4gICAgfVxuICAgIHJldHVybiBgJHtudW19JHtbXCJ0aFwiLCBcInN0XCIsIFwibmRcIiwgXCJyZFwiLCBcInRoXCIsIFwidGhcIiwgXCJ0aFwiLCBcInRoXCIsIFwidGhcIiwgXCJ0aFwiXVtwSW50KGAke251bX1gLmNoYXJBdChgJHtudW19YC5sZW5ndGggLSAxKSldfWA7XG59O1xuY29uc3Qgcm9tYW5pemVOdW0gPSAobnVtLCBpc1VzaW5nR3JvdXBlZENoYXJzID0gdHJ1ZSkgPT4ge1xuICAgIGlmIChpc0Zsb2F0KG51bSkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvcjogQ2FuJ3QgUm9tYW5pemUgRmxvYXRzICgke251bX0pYCk7XG4gICAgfVxuICAgIGlmIChudW0gPj0gNDAwMDAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgRXJyb3I6IENhbid0IFJvbWFuaXplID49IDQwMCwwMDAgKCR7bnVtfSlgKTtcbiAgICB9XG4gICAgaWYgKG51bSA8IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBFcnJvcjogQ2FuJ3QgUm9tYW5pemUgTmVnYXRpdmUgTnVtYmVycyAoJHtudW19KWApO1xuICAgIH1cbiAgICBpZiAobnVtID09PSAwKSB7XG4gICAgICAgIHJldHVybiBcIjBcIjtcbiAgICB9XG4gICAgY29uc3Qgcm9tYW5SZWYgPSBfcm9tYW5OdW1lcmFsc1tpc1VzaW5nR3JvdXBlZENoYXJzID8gXCJncm91cGVkXCIgOiBcInVuZ3JvdXBlZFwiXTtcbiAgICBjb25zdCByb21hbk51bSA9IFsuLi5zdHJpbmdpZnlOdW0obnVtKS5zcGxpdChcIlwiKV1cbiAgICAgICAgLnJldmVyc2UoKVxuICAgICAgICAubWFwKChkaWdpdCwgaSkgPT4gcm9tYW5SZWZbaV1bcEludChkaWdpdCldKVxuICAgICAgICAucmV2ZXJzZSgpXG4gICAgICAgIC5qb2luKFwiXCIpO1xuICAgIHJldHVybiBpc1VzaW5nR3JvdXBlZENoYXJzXG4gICAgICAgID8gcm9tYW5OdW0ucmVwbGFjZSgv4oWp4oWgL2d1LCBcIuKFqlwiKS5yZXBsYWNlKC/ihanihaEvZ3UsIFwi4oWrXCIpXG4gICAgICAgIDogcm9tYW5OdW07XG59O1xuLy8gI2VuZHJlZ2lvbiBfX19fX19fIE51bWJlcnMgX19fX19fX1xuLy8gI2VuZHJlZ2lvbiDilpHilpHilpHilpFbRm9ybWF0dGluZ13ilpHilpHilpHilpFcbi8vICNyZWdpb24g4paR4paR4paR4paR4paR4paR4paRW0NvbnRlbnRd4paR4paR4paR4paRIExvcmVtIElwc3VtLCBSYW5kb20gQ29udGVudCBHZW5lcmF0aW9uLCBSYW5kdW0gVVVJRCDilpHilpHilpHilpHilpHilpHilpEgflxuY29uc3QgbG9yZW1JcHN1bSA9IChudW1Xb3JkcyA9IDIwMCkgPT4ge1xuICAgIGNvbnN0IGxyV29yZExpc3QgPSBfbG9yZW1JcHN1bVRleHQuc3BsaXQoL1xcbj9cXHMrL2cpO1xuICAgIGNvbnN0IHdvcmRzID0gWy4uLmxyV29yZExpc3RbcmFuZE51bSgwLCBscldvcmRMaXN0Lmxlbmd0aCAtIDEpXV07XG4gICAgd2hpbGUgKHdvcmRzLmxlbmd0aCA8IG51bVdvcmRzKSB7XG4gICAgICAgIHdvcmRzLnB1c2goLi4ubHJXb3JkTGlzdCk7XG4gICAgfVxuICAgIHdvcmRzLmxlbmd0aCA9IG51bVdvcmRzO1xuICAgIHJldHVybiBgJHtzQ2FzZSh3b3Jkcy5qb2luKFwiIFwiKSkudHJpbSgpLnJlcGxhY2UoL1teYS16XFxzXSokL3VpLCBcIlwiKX0uYDtcbn07XG5jb25zdCByYW5kU3RyaW5nID0gKGxlbmd0aCA9IDUpID0+IEFycmF5LmZyb20oeyBsZW5ndGggfSlcbiAgICAubWFwKCgpID0+IFN0cmluZy5mcm9tQ2hhckNvZGUocmFuZEludCguLi5bXCJhXCIsIFwielwiXS5tYXAoKGNoYXIpID0+IGNoYXIuY2hhckNvZGVBdCgwKSkpKSlcbiAgICAuam9pbihcIlwiKTtcbmNvbnN0IHJhbmRXb3JkID0gKG51bVdvcmRzID0gMSwgd29yZExpc3QgPSBfcmFuZG9tV29yZHMpID0+IEFycmF5LmZyb20oeyBsZW5ndGg6IG51bVdvcmRzIH0pLm1hcCgoKSA9PiByYW5kRWxlbShbLi4ud29yZExpc3RdKSkuam9pbihcIiBcIik7XG5jb25zdCBnZXRVSUQgPSAoaWQpID0+IHtcbiAgICBjb25zdCBpbmRleE51bSA9IE1hdGgubWF4KDAsIC4uLlVVSURMT0cuZmlsdGVyKChbZ2VuZXJpY0lEXSkgPT4gZ2VuZXJpY0lELnN0YXJ0c1dpdGgoaWQpKS5tYXAoKFssICwgbnVtXSkgPT4gbnVtKSkgKyAxO1xuICAgIGNvbnN0IHV1aWQgPSBpbmRleE51bSA9PT0gMSA/IGlkIDogYCR7aWR9XyR7aW5kZXhOdW19YDtcbiAgICBVVUlETE9HLnB1c2goW2lkLCB1dWlkLCBpbmRleE51bV0pO1xuICAgIGVMb2cubG9nKGBVVUlEaWZ5KCR7aWR9KSAtLT4gWyR7dXVpZH0sICR7aW5kZXhOdW19XWApO1xuICAgIE9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywgeyBVVUlETE9HIH0pO1xuICAgIHJldHVybiB1dWlkO1xufTtcbi8vICNlbmRyZWdpb24g4paR4paR4paR4paRW0NvbnRlbnRd4paR4paR4paR4paRXG4vLyAjZW5kcmVnaW9uIOKWhOKWhOKWhOKWhOKWhCBTVFJJTkdTIOKWhOKWhOKWhOKWhOKWhFxuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggU0VBUkNISU5HOiBTZWFyY2hpbmcgVmFyaW91cyBEYXRhIFR5cGVzIHcvIEZ1enp5IE1hdGNoaW5nIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCB+XG5jb25zdCBmdXp6eU1hdGNoID0gKHZhbDEsIHZhbDIpID0+IHtcbiAgICBjb25zdCBbc3RyMSwgc3RyMl0gPSBbdmFsMSwgdmFsMl0ubWFwKCh2YWwpID0+IGxDYXNlKFN0cmluZyh2YWwpLnJlcGxhY2UoL1teYS16QS1aMC05ListXS9nLCBcIlwiKS50cmltKCkpKTtcbiAgICByZXR1cm4gc3RyMS5sZW5ndGggPiAwICYmIHN0cjEgPT09IHN0cjI7XG59O1xuY29uc3QgaXNJbiA9IChuZWVkbGUsIGhheXN0YWNrID0gW10sIGZ1enppbmVzcyA9IDApID0+IHtcbiAgICAvLyBMb29rcyBmb3IgbmVlZGxlIGluIGhheXN0YWNrIHVzaW5nIGZ1enp5IG1hdGNoaW5nLCB0aGVuIHJldHVybnMgdmFsdWUgYXMgaXQgYXBwZWFycyBpbiBoYXlzdGFjay5cbiAgICAvLyBTVEVQIE9ORTogUE9QVUxBVEUgU0VBUkNIIFRFU1RTIEFDQ09SRElORyBUTyBGVVpaSU5FU1MgU0VUVElOR1xuICAgIGNvbnN0IFNlYXJjaFRlc3RzID0gW1xuICAgICAgICAobmRsLCBpdGVtKSA9PiBuZXcgUmVnRXhwKGBeJHtuZGx9JGAsIFwiZ3VcIikudGVzdChgJHtpdGVtfWApLFxuICAgICAgICAobmRsLCBpdGVtKSA9PiBuZXcgUmVnRXhwKGBeJHtuZGx9JGAsIFwiZ3VpXCIpLnRlc3QoYCR7aXRlbX1gKVxuICAgIF07XG4gICAgaWYgKGZ1enppbmVzcyA+PSAxKSB7XG4gICAgICAgIGNvbnN0IGZ1enp5VGVzdHMgPSBbXG4gICAgICAgICAgICAobmRsLCBpdGVtKSA9PiBuZXcgUmVnRXhwKGBeJHtuZGx9YCwgXCJndWlcIikudGVzdChgJHtpdGVtfWApLFxuICAgICAgICAgICAgKG5kbCwgaXRlbSkgPT4gbmV3IFJlZ0V4cChgJHtuZGx9JGAsIFwiZ3VpXCIpLnRlc3QoYCR7aXRlbX1gKSxcbiAgICAgICAgICAgIChuZGwsIGl0ZW0pID0+IG5ldyBSZWdFeHAoYCR7bmRsfWAsIFwiZ3VpXCIpLnRlc3QoYCR7aXRlbX1gKSxcbiAgICAgICAgICAgIChuZGwsIGl0ZW0pID0+IG5ldyBSZWdFeHAoYCR7aXRlbX1gLCBcImd1aVwiKS50ZXN0KGAke25kbH1gKVxuICAgICAgICBdO1xuICAgICAgICBTZWFyY2hUZXN0cy5wdXNoKC4uLmZ1enp5VGVzdHMpO1xuICAgICAgICBpZiAoZnV6emluZXNzID49IDIpIHtcbiAgICAgICAgICAgIFNlYXJjaFRlc3RzLnB1c2goLi4uZnV6enlUZXN0c1xuICAgICAgICAgICAgICAgIC5tYXAoKGZ1bmMpID0+IChuZGwsIGl0ZW0pID0+IGZ1bmMoYCR7bmRsfWAucmVwbGFjZSgvXFxXL2csIFwiXCIpLCBgJHtpdGVtfWAucmVwbGFjZSgvXFxXL2d1LCBcIlwiKSkpKTtcbiAgICAgICAgICAgIGlmIChmdXp6aW5lc3MgPj0gMykge1xuICAgICAgICAgICAgICAgIFNlYXJjaFRlc3RzLnB1c2goKCkgPT4gZmFsc2UpOyAvLyBIYXZlIHRvIGltcGxlbWVudCBGdXNlIG1hdGNoaW5nXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gU1RFUCBUV086IFBBUlNFIE5FRURMRSAmIENPTlNUUlVDVCBTRUFSQ0hBQkxFIEhBWVNUQUNLLlxuICAgIGNvbnN0IHNlYXJjaE5lZWRsZSA9IGAke25lZWRsZX1gO1xuICAgIGNvbnN0IHNlYXJjaFN0YWNrID0gKCgpID0+IHtcbiAgICAgICAgaWYgKGlzQXJyYXkoaGF5c3RhY2spKSB7XG4gICAgICAgICAgICByZXR1cm4gWy4uLmhheXN0YWNrXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNMaXN0KGhheXN0YWNrKSkge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKGhheXN0YWNrKTtcbiAgICAgICAgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuIEFycmF5LmZyb20oaGF5c3RhY2spO1xuICAgICAgICB9XG4gICAgICAgIGNhdGNoIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSGF5c3RhY2sgdHlwZSBtdXN0IGJlIFtsaXN0LCBhcnJheV0sIG5vdCAke3R5cGVvZiBoYXlzdGFja306ICR7SlNPTi5zdHJpbmdpZnkoaGF5c3RhY2spfWApO1xuICAgICAgICB9XG4gICAgfSkoKTtcbiAgICBpZiAoIWlzQXJyYXkoc2VhcmNoU3RhY2spKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gU1RFUCBUSFJFRTogU0VBUkNIIEhBWSBGT1IgTkVFRExFIFVTSU5HIFBST0dSRVNTSVZFTFkgTU9SRSBGVVpaWSBTRUFSQ0ggVEVTVFNcbiAgICBsZXQgbWF0Y2hJbmRleCA9IC0xO1xuICAgIHdoaWxlICghaXNQb3NJbnQobWF0Y2hJbmRleCkpIHtcbiAgICAgICAgY29uc3QgdGVzdEZ1bmMgPSBTZWFyY2hUZXN0cy5zaGlmdCgpO1xuICAgICAgICBpZiAoIXRlc3RGdW5jKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgbWF0Y2hJbmRleCA9IHNlYXJjaFN0YWNrLmZpbmRJbmRleCgoaXRlbSkgPT4gdGVzdEZ1bmMoc2VhcmNoTmVlZGxlLCBgJHtpdGVtfWApKTtcbiAgICB9XG4gICAgaWYgKGlzUG9zSW50KG1hdGNoSW5kZXgpKSB7XG4gICAgICAgIHJldHVybiBpc0xpc3QoaGF5c3RhY2spID8gT2JqZWN0LnZhbHVlcyhoYXlzdGFjaylbbWF0Y2hJbmRleF0gOiBoYXlzdGFja1ttYXRjaEluZGV4XTtcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xufTtcbmNvbnN0IGlzSW5FeGFjdCA9IChuZWVkbGUsIGhheXN0YWNrKSA9PiBpc0luKG5lZWRsZSwgaGF5c3RhY2ssIDApO1xuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgU0VBUkNISU5HIOKWhOKWhOKWhOKWhOKWhFxuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggTlVNQkVSUzogTnVtYmVyIENhc3RpbmcsIE1hdGhlbWF0aWNzLCBDb252ZXJzaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCB+XG5jb25zdCByYW5kTnVtID0gKG1pbiwgbWF4LCBzbmFwID0gMCkgPT4gZ3NhcC51dGlscy5yYW5kb20obWluLCBtYXgsIHNuYXApO1xuY29uc3QgcmFuZEludCA9IChtaW4sIG1heCkgPT4gcmFuZE51bShtaW4sIG1heCwgMSk7XG5jb25zdCBjb2luRmxpcCA9ICgpID0+IHJhbmROdW0oMCwgMSwgMSkgPT09IDE7XG5jb25zdCBjeWNsZU51bSA9IChudW0sIFttaW4gPSAwLCBtYXggPSBJbmZpbml0eV0gPSBbXSkgPT4gZ3NhcC51dGlscy53cmFwKG1pbiwgbWF4LCBudW0pO1xuY29uc3QgY2xhbXBOdW0gPSAobnVtLCBbbWluID0gMCwgbWF4ID0gSW5maW5pdHldID0gW10pID0+IGdzYXAudXRpbHMuY2xhbXAobWluLCBtYXgsIG51bSk7XG5jb25zdCBjeWNsZUFuZ2xlID0gKGFuZ2xlLCByYW5nZSA9IFswLCAzNjBdKSA9PiBjeWNsZU51bShhbmdsZSwgcmFuZ2UpO1xuY29uc3Qgcm91bmROdW0gPSAobnVtLCBzaWdEaWdpdHMgPSAwKSA9PiAoc2lnRGlnaXRzID09PSAwID8gcEludChudW0pIDogcEZsb2F0KG51bSwgc2lnRGlnaXRzKSk7XG5jb25zdCBzdW0gPSAoLi4ubnVtcykgPT4gT2JqZWN0LnZhbHVlcyhudW1zLmZsYXQoKSkucmVkdWNlKChudW0sIHRvdCkgPT4gdG90ICsgbnVtLCAwKTtcbmNvbnN0IGF2ZXJhZ2UgPSAoLi4ubnVtcykgPT4gc3VtKC4uLm51bXMpIC8gbnVtcy5mbGF0KCkubGVuZ3RoO1xuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbUG9zaXRpb25pbmdd4paR4paR4paR4paRIFJlbGF0aW9uc2hpcHMgT24gMkQgQ2FydGVzaWFuIFBsYW5lIOKWkeKWkeKWkeKWkeKWkeKWkeKWkSB+XG5jb25zdCBnZXREaXN0YW5jZSA9ICh7IHg6IHgxLCB5OiB5MSB9LCB7IHg6IHgyLCB5OiB5MiB9KSA9PiAoKCh4MSAtIHgyKSAqKiAyKSArICgoeTEgLSB5MikgKiogMikpICoqIDAuNTtcbmNvbnN0IGdldEFuZ2xlID0gKHsgeDogeDEsIHk6IHkxIH0sIHsgeDogeDIsIHk6IHkyIH0sIHsgeDogeE8sIHk6IHlPIH0gPSB7IHg6IDAsIHk6IDAgfSwgcmFuZ2UgPSBbMCwgMzYwXSkgPT4ge1xuICAgIHgxIC09IHhPO1xuICAgIHkxIC09IHlPO1xuICAgIHgyIC09IHhPO1xuICAgIHkyIC09IHlPO1xuICAgIHJldHVybiBjeWNsZUFuZ2xlKHJhZFRvRGVnKE1hdGguYXRhbjIoeTIgLSB5MSwgeDIgLSB4MSkpLCByYW5nZSk7XG59O1xuY29uc3QgZ2V0QW5nbGVEZWx0YSA9IChhbmdsZVN0YXJ0LCBhbmdsZUVuZCwgcmFuZ2UgPSBbMCwgMzYwXSkgPT4gY3ljbGVBbmdsZShhbmdsZUVuZCAtIGFuZ2xlU3RhcnQsIHJhbmdlKTtcbi8qKlxuICogRnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBzbWFsbGVzdCByZWN0YW5nbGUgdGhhdCBjYW4gY29udGFpbiBhbGwgdGhlIGdpdmVuIHNoYXBlcy5cbiAqIEBwYXJhbSBhcnJheU9mU2hhcGVzIC0gQXJyYXkgb2Ygb2JqZWN0cywgZWFjaCBkZXNjcmliaW5nIGEgc2hhcGUncyBwb3NpdGlvbiBhbmQgc2l6ZS5cbiAqIEByZXR1cm5zIEFuIG9iamVjdCBkZXNjcmliaW5nIHRoZSBwb3NpdGlvbiAoY2VudGVyKSBhbmQgc2l6ZSBvZiB0aGUgc21hbGxlc3QgcmVjdGFuZ2xlIHRoYXQgY2FuIGNvbnRhaW4gYWxsIHRoZSBzaGFwZXMuXG4gKi9cbmNvbnN0IGdldEJvdW5kaW5nUmVjdGFuZ2xlID0gKGFycmF5T2ZTaGFwZXMpID0+IHtcbiAgICAvLyBJbml0aWFsaXplIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIHggYW5kIHkgY29vcmRpbmF0ZXMuXG4gICAgbGV0IG1pblggPSBJbmZpbml0eTtcbiAgICBsZXQgbWluWSA9IEluZmluaXR5O1xuICAgIGxldCBtYXhYID0gLUluZmluaXR5O1xuICAgIGxldCBtYXhZID0gLUluZmluaXR5O1xuICAgIC8vIEl0ZXJhdGUgb3ZlciB0aGUgYXJyYXkgb2Ygc2hhcGVzLlxuICAgIGZvciAoY29uc3Qgc2hhcGUgb2YgYXJyYXlPZlNoYXBlcykge1xuICAgICAgICAvLyBDYWxjdWxhdGUgdGhlIG1pbmltdW0gYW5kIG1heGltdW0geCBhbmQgeSBjb29yZGluYXRlcyBmb3IgdGhlIGN1cnJlbnQgc2hhcGUuXG4gICAgICAgIGxldCBzaGFwZU1pblg7XG4gICAgICAgIGxldCBzaGFwZU1pblk7XG4gICAgICAgIGxldCBzaGFwZU1heFg7XG4gICAgICAgIGxldCBzaGFwZU1heFk7XG4gICAgICAgIGlmIChzaGFwZS5yYWRpdXMgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgLy8gVGhlIHNoYXBlIGlzIGEgY2lyY2xlLlxuICAgICAgICAgICAgc2hhcGVNaW5YID0gc2hhcGUueCAtIHNoYXBlLnJhZGl1cztcbiAgICAgICAgICAgIHNoYXBlTWluWSA9IHNoYXBlLnkgLSBzaGFwZS5yYWRpdXM7XG4gICAgICAgICAgICBzaGFwZU1heFggPSBzaGFwZS54ICsgc2hhcGUucmFkaXVzO1xuICAgICAgICAgICAgc2hhcGVNYXhZID0gc2hhcGUueSArIHNoYXBlLnJhZGl1cztcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChzaGFwZS5zaXplICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIFRoZSBzaGFwZSBpcyBhIHNxdWFyZS5cbiAgICAgICAgICAgIHNoYXBlTWluWCA9IChzaGFwZS54IC0gc2hhcGUuc2l6ZSkgLyAyO1xuICAgICAgICAgICAgc2hhcGVNaW5ZID0gKHNoYXBlLnkgLSBzaGFwZS5zaXplKSAvIDI7XG4gICAgICAgICAgICBzaGFwZU1heFggPSAoc2hhcGUueCArIHNoYXBlLnNpemUpIC8gMjtcbiAgICAgICAgICAgIHNoYXBlTWF4WSA9IChzaGFwZS55ICsgc2hhcGUuc2l6ZSkgLyAyO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHNoYXBlLndpZHRoICE9PSB1bmRlZmluZWQgfHwgc2hhcGUuaGVpZ2h0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIC8vIFRoZSBzaGFwZSBpcyBhIHJlY3RhbmdsZSAob3IgcG9zc2libHkgYSBzcXVhcmUpLlxuICAgICAgICAgICAgc2hhcGUud2lkdGggPz89IHNoYXBlLmhlaWdodDtcbiAgICAgICAgICAgIHNoYXBlLmhlaWdodCA/Pz0gc2hhcGUud2lkdGg7XG4gICAgICAgICAgICBzaGFwZU1pblggPSAoc2hhcGUueCAtIHNoYXBlLndpZHRoKSAvIDI7XG4gICAgICAgICAgICBzaGFwZU1pblkgPSAoc2hhcGUueSAtIHNoYXBlLmhlaWdodCkgLyAyO1xuICAgICAgICAgICAgc2hhcGVNYXhYID0gKHNoYXBlLnggKyBzaGFwZS53aWR0aCkgLyAyO1xuICAgICAgICAgICAgc2hhcGVNYXhZID0gKHNoYXBlLnkgKyBzaGFwZS5oZWlnaHQpIC8gMjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgW2dldEJvdW5kaW5nUmVjdGFuZ2xlXSBFcnJvcjogc2hhcGUgbXVzdCBiZSBhIGNpcmNsZSwgc3F1YXJlLCBvciByZWN0YW5nbGUsIG5vdCAke0pTT04uc3RyaW5naWZ5KHNoYXBlKX1gKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBVcGRhdGUgdGhlIG92ZXJhbGwgbWluaW11bSBhbmQgbWF4aW11bSB4IGFuZCB5IGNvb3JkaW5hdGVzLlxuICAgICAgICBtaW5YID0gTWF0aC5taW4obWluWCwgc2hhcGVNaW5YKTtcbiAgICAgICAgbWluWSA9IE1hdGgubWluKG1pblksIHNoYXBlTWluWSk7XG4gICAgICAgIG1heFggPSBNYXRoLm1heChtYXhYLCBzaGFwZU1heFgpO1xuICAgICAgICBtYXhZID0gTWF0aC5tYXgobWF4WSwgc2hhcGVNYXhZKTtcbiAgICB9XG4gICAgLy8gQ2FsY3VsYXRlIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSBzbWFsbGVzdCByZWN0YW5nbGUuXG4gICAgY29uc3Qgd2lkdGggPSBtYXhYIC0gbWluWDtcbiAgICBjb25zdCBoZWlnaHQgPSBtYXhZIC0gbWluWTtcbiAgICAvLyBDYWxjdWxhdGUgdGhlIGNlbnRlciBvZiB0aGUgcmVjdGFuZ2xlLlxuICAgIGNvbnN0IHggPSAobWluWCArIHdpZHRoKSAvIDI7XG4gICAgY29uc3QgeSA9IChtaW5ZICsgaGVpZ2h0KSAvIDI7XG4gICAgLy8gUmV0dXJuIHRoZSBwb3NpdGlvbiAoY2VudGVyKSBhbmQgc2l6ZSBvZiB0aGUgc21hbGxlc3QgcmVjdGFuZ2xlLlxuICAgIHJldHVybiB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfTtcbn07XG4vLyAjZW5kcmVnaW9uIOKWkeKWkeKWkeKWkVtQb3NpdGlvbmluZ13ilpHilpHilpHilpFcbi8vICNlbmRyZWdpb24g4paE4paE4paE4paE4paEIE5VTUJFUlMg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBBUlJBWVM6IEFycmF5IE1hbmlwdWxhdGlvbiDilojilojilojilojilojilojilojiloggflxuY29uc3QgcmFuZEVsZW0gPSAoYXJyYXkpID0+IGdzYXAudXRpbHMucmFuZG9tKGFycmF5KTtcbmNvbnN0IHJhbmRJbmRleCA9IChhcnJheSkgPT4gcmFuZEludCgwLCBhcnJheS5sZW5ndGggLSAxKTtcbmNvbnN0IG1ha2VJbnRSYW5nZSA9IChtaW4sIG1heCkgPT4ge1xuICAgIGNvbnN0IGludFJhbmdlID0gW107XG4gICAgZm9yIChsZXQgaSA9IG1pbjsgaSA8PSBtYXg7IGkrKykge1xuICAgICAgICBpbnRSYW5nZS5wdXNoKGkpO1xuICAgIH1cbiAgICByZXR1cm4gaW50UmFuZ2U7XG59O1xuY29uc3QgbWFrZUN5Y2xlciA9IChhcnJheSwgaW5kZXggPSAwKSA9PiB7XG4gICAgLy8gR2l2ZW4gYW4gYXJyYXkgYW5kIGEgc3RhcnRpbmcgaW5kZXgsIHJldHVybnMgYSBnZW5lcmF0b3IgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZFxuICAgIC8vIHRvIGl0ZXJhdGUgb3ZlciB0aGUgYXJyYXkgaW5kZWZpbml0ZWx5LCBvciB3cmFwIG91dC1vZi1ib3VuZHMgaW5kZXggdmFsdWVzXG4gICAgY29uc3Qgd3JhcHBlciA9IGdzYXAudXRpbHMud3JhcChhcnJheSk7XG4gICAgaW5kZXgtLTtcbiAgICByZXR1cm4gKGZ1bmN0aW9uKiAoKSB7XG4gICAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgICAgICBpbmRleCsrO1xuICAgICAgICAgICAgeWllbGQgd3JhcHBlcihpbmRleCk7XG4gICAgICAgIH1cbiAgICB9KSgpO1xufTtcbi8qKlxuICogUmV0dXJucyB0aGUgbGFzdCBlbGVtZW50IG9mIGFuIGFycmF5LCBvciB0aGUgbGFzdCB2YWx1ZSBvZiBhbiBvYmplY3QgbGl0ZXJhbC5cbiAqXG4gKiBAcGFyYW0ge0luZGV4PFR5cGU+fSBhcnJheSBBbiBhcnJheSBvciBvYmplY3QgbGl0ZXJhbFxuICogQHJldHVybnMge1R5cGV8dW5kZWZpbmVkfSBUaGUgbGFzdCBlbGVtZW50LCBvciB1bmRlZmluZWQgaWYgZW1wdHkuXG4gKi9cbmZ1bmN0aW9uIGdldExhc3QoYXJyYXkpIHtcbiAgICBhcnJheSA9IE9iamVjdC52YWx1ZXMoYXJyYXkpO1xuICAgIGlmIChhcnJheS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IGdldCBsYXN0IGVsZW1lbnQgb2YgYW4gZW1wdHkgYXJyYXkuXCIpO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXlbYXJyYXkubGVuZ3RoIC0gMV07XG59XG4vLyBDb25zdCBnZXRMYXN0ID0gPFR5cGU+KGFycmF5OiBUeXBlW10pOiB0eXBlb2YgYXJyYXkgZXh0ZW5kcyBbXSA/IHVuZGVmaW5lZCA6IFR5cGUgPT4gO1xuY29uc3QgdW5pcXVlID0gKGFycmF5KSA9PiB7XG4gICAgY29uc3QgcmV0dXJuQXJyYXkgPSBbXTtcbiAgICBhcnJheS5mb3JFYWNoKChpdGVtKSA9PiB7IGlmICghcmV0dXJuQXJyYXkuaW5jbHVkZXMoaXRlbSkpIHtcbiAgICAgICAgcmV0dXJuQXJyYXkucHVzaChpdGVtKTtcbiAgICB9IH0pO1xuICAgIHJldHVybiByZXR1cm5BcnJheTtcbn07XG5jb25zdCBncm91cCA9IChhcnJheSwga2V5KSA9PiB7XG4gICAgY29uc3QgcmV0dXJuT2JqID0ge307XG4gICAgYXJyYXkuZm9yRWFjaCgoaXRlbSkgPT4ge1xuICAgICAgICBjb25zdCByZXR1cm5LZXkgPSBpdGVtW2tleV07XG4gICAgICAgIGxldCByZXR1cm5WYWwgPSByZXR1cm5PYmpbcmV0dXJuS2V5XTtcbiAgICAgICAgaWYgKCFyZXR1cm5WYWwpIHtcbiAgICAgICAgICAgIHJldHVyblZhbCA9IFtdO1xuICAgICAgICAgICAgcmV0dXJuT2JqW3JldHVybktleV0gPSByZXR1cm5WYWw7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuVmFsLnB1c2goaXRlbSk7XG4gICAgfSk7XG4gICAgcmV0dXJuIHJldHVybk9iajtcbn07XG5jb25zdCBzYW1wbGUgPSAoYXJyYXksIG51bUVsZW1zID0gMSwgaXNVbmlxdWVPbmx5ID0gdHJ1ZSwgdW5pcXVlVGVzdEZ1bmMgPSAoZSwgYSkgPT4gIWEuaW5jbHVkZXMoZSkpID0+IHtcbiAgICBjb25zdCBlbGVtcyA9IFtdO1xuICAgIGxldCBvdmVybG9hZENvdW50ZXIgPSAwO1xuICAgIHdoaWxlIChlbGVtcy5sZW5ndGggPCBudW1FbGVtcyAmJiBvdmVybG9hZENvdW50ZXIgPCAxMDAwMDAwKSB7XG4gICAgICAgIGNvbnN0IHJhbmRvbUVsZW0gPSByYW5kRWxlbShhcnJheSk7XG4gICAgICAgIGlmIChpc1VuaXF1ZU9ubHkgJiYgdW5pcXVlVGVzdEZ1bmMocmFuZG9tRWxlbSwgZWxlbXMpKSB7XG4gICAgICAgICAgICBlbGVtcy5wdXNoKHJhbmRvbUVsZW0pO1xuICAgICAgICB9XG4gICAgICAgIG92ZXJsb2FkQ291bnRlcisrO1xuICAgIH1cbiAgICByZXR1cm4gZWxlbXM7XG59O1xuY29uc3QgcmVtb3ZlRmlyc3QgPSAoYXJyYXksIGVsZW1lbnQpID0+IGFycmF5LnNwbGljZShhcnJheS5maW5kSW5kZXgoKHYpID0+IHYgPT09IGVsZW1lbnQpKTtcbi8qKlxuICogVGhpcyBmdW5jdGlvbiByZW1vdmVzIGFuZCByZXR1cm5zIHRoZSBmaXJzdCBlbGVtZW50IGluIGFuIGFycmF5IHRoYXQgZXF1YWxzIHRoZSBwcm92aWRlZCB2YWx1ZVxuICogICBvciBzYXRpc2ZpZXMgdGhlIHByb3ZpZGVkIHRlc3RpbmcgZnVuY3Rpb24uXG4gKiBJZiBubyBlbGVtZW50cyBzYXRpc2Z5IHRoZSB0ZXN0aW5nIGZ1bmN0aW9uLCB0aGUgZnVuY3Rpb24gd2lsbCByZXR1cm4gdW5kZWZpbmVkLlxuICpcbiAqIEBwYXJhbSB7VFtdfSBhcnJheSBUaGUgYXJyYXkgdG8gYmUgc2VhcmNoZWQuXG4gKiBAcGFyYW0geyhUfCgoX3Y6IFQsIF9pPzogbnVtYmVyLCBfYT86IFRbXSkgPT4gYm9vbGVhbikpfSBjaGVja0Z1bmMgVGhlIHRlc3RpbmcgZnVuY3Rpb24gb3IgdmFsdWUgdG8gYmUgc2VhcmNoZWQgZm9yLlxuICogQHJldHVybnMge1QgfCB1bmRlZmluZWR9IFRoZSBmaXJzdCBlbGVtZW50IGluIHRoZSBhcnJheSB0aGF0IHBhc3NlcyB0aGUgdGVzdC5cbiAqICAgICAgICAgICAgICAgICAgICAgICAgICBJZiBubyBlbGVtZW50cyBwYXNzIHRoZSB0ZXN0LCByZXR1cm4gdW5kZWZpbmVkLlxuICovXG5mdW5jdGlvbiBwdWxsRWxlbWVudChhcnJheSwgY2hlY2tGdW5jKSB7XG4gICAgLy8gRGVmaW5lIHRoZSB0ZXN0IGZ1bmN0aW9uXG4gICAgbGV0IHRlc3RGdW5jdGlvbjtcbiAgICAvLyBJZiBjaGVja0Z1bmMgaXMgbm90IGEgZnVuY3Rpb24sIGNyZWF0ZSBhIGZ1bmN0aW9uIHRoYXQgY2hlY2tzIGZvciBlcXVhbGl0eSB3aXRoIGNoZWNrRnVuY1xuICAgIGlmICh0eXBlb2YgY2hlY2tGdW5jICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgdGVzdEZ1bmN0aW9uID0gKF92KSA9PiBfdiA9PT0gY2hlY2tGdW5jO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgdGVzdEZ1bmN0aW9uID0gY2hlY2tGdW5jO1xuICAgIH1cbiAgICAvLyBGaW5kIHRoZSBpbmRleCBvZiB0aGUgZmlyc3QgZWxlbWVudCB0aGF0IHBhc3NlcyB0aGUgdGVzdFxuICAgIGNvbnN0IGluZGV4ID0gYXJyYXkuZmluZEluZGV4KCh2LCBpLCBhKSA9PiB0ZXN0RnVuY3Rpb24odiwgaSwgYSkpO1xuICAgIC8vIElmIG5vIGVsZW1lbnQgcGFzc2VzIHRoZSB0ZXN0LCByZXR1cm4gdW5kZWZpbmVkXG4gICAgaWYgKGluZGV4ID09PSAtMSkge1xuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbiAgICAvLyBSZW1vdmUgdGhlIGVsZW1lbnQgZnJvbSB0aGUgYXJyYXkgYW5kIHJldHVybiBpdFxuICAgIHJldHVybiBhcnJheS5zcGxpY2UoaW5kZXgsIDEpLnBvcCgpO1xufVxuY29uc3QgcHVsbEluZGV4ID0gKGFycmF5LCBpbmRleCkgPT4gcHVsbEVsZW1lbnQoYXJyYXksIChfLCBpKSA9PiBpID09PSBpbmRleCk7XG5jb25zdCBzdWJHcm91cCA9IChhcnJheSwgZ3JvdXBTaXplKSA9PiB7XG4gICAgY29uc3Qgc3ViQXJyYXlzID0gW107XG4gICAgd2hpbGUgKGFycmF5Lmxlbmd0aCA+IGdyb3VwU2l6ZSkge1xuICAgICAgICBjb25zdCBzdWJBcnJheSA9IFtdO1xuICAgICAgICB3aGlsZSAoc3ViQXJyYXkubGVuZ3RoIDwgZ3JvdXBTaXplKSB7XG4gICAgICAgICAgICBzdWJBcnJheS5wdXNoKGFycmF5LnNoaWZ0KCkpO1xuICAgICAgICB9XG4gICAgICAgIHN1YkFycmF5cy5wdXNoKHN1YkFycmF5KTtcbiAgICB9XG4gICAgc3ViQXJyYXlzLnB1c2goYXJyYXkpO1xuICAgIHJldHVybiBzdWJBcnJheXM7XG59O1xuY29uc3Qgc2h1ZmZsZSA9IChhcnJheSkgPT4ge1xuICAgIGxldCBjdXJyZW50SW5kZXggPSBhcnJheS5sZW5ndGg7XG4gICAgbGV0IHJhbmRvbUluZGV4O1xuICAgIC8vIFdoaWxlIHRoZXJlIHJlbWFpbiBlbGVtZW50cyB0byBzaHVmZmxlLlxuICAgIHdoaWxlIChjdXJyZW50SW5kZXggIT09IDApIHtcbiAgICAgICAgLy8gUGljayBhIHJlbWFpbmluZyBlbGVtZW50LlxuICAgICAgICByYW5kb21JbmRleCA9IE1hdGguZmxvb3IoTWF0aC5yYW5kb20oKSAqIGN1cnJlbnRJbmRleCk7XG4gICAgICAgIGN1cnJlbnRJbmRleC0tO1xuICAgICAgICAvLyBBbmQgc3dhcCBpdCB3aXRoIHRoZSBjdXJyZW50IGVsZW1lbnQuXG4gICAgICAgIFthcnJheVtjdXJyZW50SW5kZXhdLCBhcnJheVtyYW5kb21JbmRleF1dID0gW1xuICAgICAgICAgICAgYXJyYXlbcmFuZG9tSW5kZXhdLCBhcnJheVtjdXJyZW50SW5kZXhdXG4gICAgICAgIF07XG4gICAgfVxuICAgIHJldHVybiBhcnJheTtcbn07XG5jb25zdCB0b0FycmF5ID0gKHRhcmdldCkgPT4ge1xuICAgIHJldHVybiBnc2FwLnV0aWxzLnRvQXJyYXkodGFyZ2V0KTtcbn07XG4vLyAjZW5kcmVnaW9uIOKWhOKWhOKWhOKWhOKWhCBBUlJBWVMg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBPQkpFQ1RTOiBNYW5pcHVsYXRpb24gb2YgU2ltcGxlIEtleS9WYWwgT2JqZWN0cyDilojilojilojilojilojilojilojiloggflxuY29uc3QgY2hlY2tWYWwgPSAoeyBrLCB2IH0sIGNoZWNrVGVzdCkgPT4ge1xuICAgIGlmICh0eXBlb2YgY2hlY2tUZXN0ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgaWYgKGlzRGVmaW5lZCh2KSkge1xuICAgICAgICAgICAgcmV0dXJuIGNoZWNrVGVzdCh2LCBrKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY2hlY2tUZXN0KGspO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGNoZWNrVGVzdCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICBjaGVja1Rlc3QgPSBgJHtjaGVja1Rlc3R9YDtcbiAgICB9XG4gICAgcmV0dXJuIChuZXcgUmVnRXhwKGNoZWNrVGVzdCkpLnRlc3QoYCR7dn1gKTtcbn07XG4vKipcbiAqIEdpdmVuIGFuIGFycmF5IG9yIGxpc3QgYW5kIGEgc2VhcmNoIGZ1bmN0aW9uLCB3aWxsIHJlbW92ZSB0aGUgZmlyc3QgbWF0Y2hpbmcgZWxlbWVudCBhbmQgcmV0dXJuIGl0LlxuICogQHBhcmFtIHtJbmRleDx1bmtub3duPn0gb2JqIFRoZSBhcnJheSBvciBsaXN0IHRvIGJlIHNlYXJjaGVkLlxuICogQHBhcmFtIHt0ZXN0RnVuYzxrZXlGdW5jIHwgdmFsRnVuYz4gfCBudW1iZXIgfCBzdHJpbmd9IGNoZWNrVGVzdCBUaGUgc2VhcmNoIGZ1bmN0aW9uLlxuICogQHJldHVybnMge3Vua25vd24gfCBmYWxzZX0gLSBUaGUgcmVtb3ZlZCBlbGVtZW50IG9yIGZhbHNlIGlmIG5vIGVsZW1lbnQgd2FzIGZvdW5kLlxuICovXG5jb25zdCByZW1vdmUgPSAob2JqLCBjaGVja1Rlc3QpID0+IHtcbiAgICBpZiAoaXNBcnJheShvYmopKSB7XG4gICAgICAgIGNvbnN0IGluZGV4ID0gb2JqLmZpbmRJbmRleCgodikgPT4gY2hlY2tWYWwoeyB2IH0sIGNoZWNrVGVzdCkpO1xuICAgICAgICBpZiAoaW5kZXggPj0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIHJlbW92ZUVsZW1lbnRGcm9tQXJyYXkob2JqLCBpbmRleCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSBpZiAoaXNMaXN0KG9iaikpIHtcbiAgICAgICAgY29uc3QgW3JlbUtleV0gPSBPYmplY3QuZW50cmllcyhvYmopLmZpbmQoKFtrLCB2XSkgPT4gY2hlY2tWYWwoeyBrLCB2IH0sIGNoZWNrVGVzdCkpID8/IFtdO1xuICAgICAgICBpZiAocmVtS2V5KSB7XG4gICAgICAgICAgICByZXR1cm4gcmVtb3ZlRWxlbWVudEZyb21MaXN0KG9iaiwgcmVtS2V5KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZmFsc2U7XG59O1xuLyoqXG4gKiBSZW1vdmVzIGFuIGVsZW1lbnQgZnJvbSBhbiBhcnJheSBhdCBhIGdpdmVuIGluZGV4IGFuZCByZXR1cm5zIGl0LlxuICogQHBhcmFtIHt1bmtub3duW119IGFycmF5IFRoZSBhcnJheSB0byByZW1vdmUgdGhlIGVsZW1lbnQgZnJvbS5cbiAqIEBwYXJhbSB7bnVtYmVyfSBpbmRleCBUaGUgaW5kZXggb2YgdGhlIGVsZW1lbnQgdG8gcmVtb3ZlLlxuICogQHJldHVybnMge3Vua25vd259IC0gVGhlIHJlbW92ZWQgZWxlbWVudC5cbiAqL1xuY29uc3QgcmVtb3ZlRWxlbWVudEZyb21BcnJheSA9IChhcnJheSwgaW5kZXgpID0+IHtcbiAgICBsZXQgcmVtVmFsO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDw9IGFycmF5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpID09PSBpbmRleCkge1xuICAgICAgICAgICAgcmVtVmFsID0gYXJyYXkuc2hpZnQoKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGFycmF5LnB1c2goYXJyYXkuc2hpZnQoKSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlbVZhbDtcbn07XG4vKipcbiAqIFJlbW92ZXMgYW4gZWxlbWVudCBmcm9tIGEgbGlzdCBhdCBhIGdpdmVuIGtleSBhbmQgcmV0dXJucyBpdC5cbiAqIEBwYXJhbSB7TGlzdDx1bmtub3duPn0gbGlzdCBUaGUgbGlzdCB0byByZW1vdmUgdGhlIGVsZW1lbnQgZnJvbS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBrZXkgVGhlIGtleSBvZiB0aGUgZWxlbWVudCB0byByZW1vdmUuXG4gKiBAcmV0dXJucyB7dW5rbm93bn0gLSBUaGUgcmVtb3ZlZCBlbGVtZW50LlxuICovXG5jb25zdCByZW1vdmVFbGVtZW50RnJvbUxpc3QgPSAobGlzdCwga2V5KSA9PiB7XG4gICAgY29uc3QgcmVtVmFsID0gbGlzdFtrZXldO1xuICAgIGRlbGV0ZSBsaXN0W2tleV07XG4gICAgcmV0dXJuIHJlbVZhbDtcbn07XG5jb25zdCByZXBsYWNlID0gKG9iaiwgY2hlY2tUZXN0LCByZXBWYWwpID0+IHtcbiAgICAvLyBBcyByZW1vdmUsIGV4Y2VwdCBpbnN0ZWFkIHJlcGxhY2VzIHRoZSBlbGVtZW50IHdpdGggdGhlIHByb3ZpZGVkIHZhbHVlLlxuICAgIC8vIFJldHVybnMgdHJ1ZS9mYWxzZSB0byBpbmRpY2F0ZSB3aGV0aGVyIHRoZSByZXBsYWNlIGFjdGlvbiBzdWNjZWVkZWQuXG4gICAgbGV0IHJlcEtleTtcbiAgICBpZiAoaXNMaXN0KG9iaikpIHtcbiAgICAgICAgW3JlcEtleV0gPSBPYmplY3QuZW50cmllcyhvYmopLmZpbmQoKHYpID0+IGNoZWNrVmFsKHsgdiB9LCBjaGVja1Rlc3QpKSB8fCBbZmFsc2VdO1xuICAgICAgICBpZiAocmVwS2V5ID09PSBmYWxzZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYgKGlzQXJyYXkob2JqKSkge1xuICAgICAgICByZXBLZXkgPSBvYmouZmluZEluZGV4KCh2KSA9PiBjaGVja1ZhbCh7IHYgfSwgY2hlY2tUZXN0KSk7XG4gICAgICAgIGlmIChyZXBLZXkgPT09IC0xKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9XG4gICAgaWYgKHR5cGVvZiByZXBLZXkgIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgcmVwS2V5ID0gYCR7cmVwS2V5fWA7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgcmVwVmFsID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBOZWVkIHRvIGZpZ3VyZSBvdXQgaG93IHRvIHByb3Blcmx5IGRlZmluZSB0ZXN0RnVuYzxrZXlGdW5jIHwgdmFsRnVuYz4gKGtleUZ1bmMvdmFsRnVuYyB0eXBlcz8pXG4gICAgICAgIG9ialtyZXBLZXldID0gcmVwVmFsKG9ialtyZXBLZXldLCByZXBLZXkpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy8gQHRzLWV4cGVjdC1lcnJvciBOZWVkIHRvIGZpZ3VyZSBvdXQgaG93IHRvIHByb3Blcmx5IGRlZmluZSB0ZXN0RnVuYzxrZXlGdW5jIHwgdmFsRnVuYz4gKGtleUZ1bmMvdmFsRnVuYyB0eXBlcz8pXG4gICAgICAgIG9ialtyZXBLZXldID0gcmVwVmFsO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG4vKipcbiAqIENsZWFucyBhbiBvYmplY3Qgb3IgdmFsdWUgYnkgcmVtb3Zpbmcgc3BlY2lmaWVkIHZhbHVlcyByZWN1cnNpdmVseS5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIHRoZSBpbnB1dCBvYmplY3Qgb3IgdmFsdWUuXG4gKiBAcGFyYW0ge1R9IGRhdGEgVGhlIG9iamVjdCBvciB2YWx1ZSB0byBiZSBjbGVhbmVkLlxuICogQHBhcmFtIHtBcnJheTxhbnk+fSBbcmVtVmFsc10gQW4gYXJyYXkgb2YgdmFsdWVzIHRvIGJlIHJlbW92ZWQgZHVyaW5nIHRoZSBjbGVhbmluZyBwcm9jZXNzLlxuICogQHJldHVybnMge1QgfCBQYXJ0aWFsPFQ+IHwgXCJLSUxMXCJ9IC0gVGhlIGNsZWFuZWQgdmVyc2lvbiBvZiB0aGUgaW5wdXQgb2JqZWN0IG9yIHZhbHVlLlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElmIG1hcmtlZCBmb3IgcmVtb3ZhbCwgcmV0dXJucyBcIktJTExcIi5cbiAqL1xuY29uc3Qgb2JqQ2xlYW4gPSAoZGF0YSwgcmVtVmFscyA9IFt1bmRlZmluZWQsIG51bGwsIFwiXCIsIHt9LCBbXV0pID0+IHtcbiAgICBjb25zdCByZW1TdHJpbmdzID0gcmVtVmFscy5tYXAoKHJWYWwpID0+IEpTT04uc3RyaW5naWZ5KHJWYWwpKTtcbiAgICBpZiAocmVtU3RyaW5ncy5pbmNsdWRlcyhKU09OLnN0cmluZ2lmeShkYXRhKSkgfHwgcmVtVmFscy5pbmNsdWRlcyhkYXRhKSkge1xuICAgICAgICByZXR1cm4gXCJLSUxMXCI7XG4gICAgfVxuICAgIGlmIChBcnJheS5pc0FycmF5KGRhdGEpKSB7XG4gICAgICAgIGNvbnN0IG5ld0RhdGEgPSBkYXRhLm1hcCgoZWxlbSkgPT4gb2JqQ2xlYW4oZWxlbSwgcmVtVmFscykpXG4gICAgICAgICAgICAuZmlsdGVyKChlbGVtKSA9PiBlbGVtICE9PSBcIktJTExcIik7XG4gICAgICAgIHJldHVybiBBcnJheS5pc0FycmF5KG5ld0RhdGEpICYmIG5ld0RhdGEubGVuZ3RoID8gbmV3RGF0YSA6IFwiS0lMTFwiO1xuICAgIH1cbiAgICBpZiAoZGF0YSAmJiB0eXBlb2YgZGF0YSA9PT0gXCJvYmplY3RcIiAmJiBKU09OLnN0cmluZ2lmeShkYXRhKS5zdGFydHNXaXRoKFwie1wiKSkge1xuICAgICAgICBjb25zdCBuZXdEYXRhID0gT2JqZWN0LmVudHJpZXMoZGF0YSlcbiAgICAgICAgICAgIC5tYXAoKFtrZXksIHZhbF0pID0+IFtrZXksIG9iakNsZWFuKHZhbCwgcmVtVmFscyldKVxuICAgICAgICAgICAgLmZpbHRlcigoWywgdmFsXSkgPT4gdmFsICE9PSBcIktJTExcIik7XG4gICAgICAgIHJldHVybiBuZXdEYXRhLmxlbmd0aCA/IE9iamVjdC5mcm9tRW50cmllcyhuZXdEYXRhKSA6IFwiS0lMTFwiO1xuICAgIH1cbiAgICByZXR1cm4gZGF0YTtcbn07XG4vLyBHaXZlbiBhbiBvYmplY3QgYW5kIGEgcHJlZGljYXRlIGZ1bmN0aW9uLCByZXR1cm5zIGFycmF5IG9mIHR3byBvYmplY3RzOlxuLy8gICBvbmUgd2l0aCBlbnRyaWVzIHRoYXQgcGFzcywgb25lIHdpdGggZW50cmllcyB0aGF0IGZhaWwuXG5jb25zdCBwYXJ0aXRpb24gPSAob2JqLCBwcmVkaWNhdGUgPSAoKSA9PiB0cnVlKSA9PiBbXG4gICAgb2JqRmlsdGVyKG9iaiwgcHJlZGljYXRlKSxcbiAgICBvYmpGaWx0ZXIob2JqLCAodiwgaykgPT4gIXByZWRpY2F0ZSh2LCBrKSlcbl07XG4vKipcbiAqIFppcHMgdHdvIGFycmF5cyBpbnRvIGFuIG9iamVjdC5cbiAqXG4gKiBAdGVtcGxhdGUgVCAtIFRoZSB0eXBlIG9mIHRoZSBrZXlzLlxuICogQHRlbXBsYXRlIFUgLSBUaGUgdHlwZSBvZiB0aGUgdmFsdWVzLlxuICogQHBhcmFtIHtUW119IGtleXMgLSBUaGUgYXJyYXkgb2Yga2V5cy5cbiAqIEBwYXJhbSB7VVtdfSB2YWx1ZXMgLSBUaGUgYXJyYXkgb2YgdmFsdWVzLlxuICogQHJldHVybnMge1JlY29yZDxULCBVPn0gLSBUaGUgcmVzdWx0aW5nIG9iamVjdC5cbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgYXJyYXlzIGFyZSBub3Qgb2YgZXF1YWwgbGVuZ3RoLCBpZiB0aGUga2V5cyBhcmUgbm90IHVuaXF1ZSwgb3IgaWYgdGhlIGtleXMgYXJlIG5vdCBvZiBhIHR5cGUgdGhhdCBjYW4gYmUgdXNlZCBhcyBvYmplY3Qga2V5cy5cbiAqL1xuY29uc3QgemlwID0gKGtleXMsIHZhbHVlcykgPT4ge1xuICAgIC8vIENoZWNrIHRoYXQgdGhlIGFycmF5cyBhcmUgb2YgZXF1YWwgbGVuZ3RoXG4gICAgaWYgKGtleXMubGVuZ3RoICE9PSB2YWx1ZXMubGVuZ3RoKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihcIlRoZSBhcnJheXMgbXVzdCBiZSBvZiBlcXVhbCBsZW5ndGguXCIpO1xuICAgIH1cbiAgICAvLyBDaGVjayB0aGF0IHRoZSBrZXlzIGFyZSB1bmlxdWVcbiAgICBpZiAobmV3IFNldChrZXlzKS5zaXplICE9PSBrZXlzLmxlbmd0aCkge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJUaGUga2V5cyBtdXN0IGJlIHVuaXF1ZS5cIik7XG4gICAgfVxuICAgIC8vIFppcCB0aGUgYXJyYXlzIGludG8gYW4gb2JqZWN0XG4gICAgY29uc3QgcmVzdWx0ID0ge307XG4gICAga2V5cy5mb3JFYWNoKChrZXksIGkpID0+IHtcbiAgICAgICAgcmVzdWx0W2tleV0gPSB2YWx1ZXNbaV07XG4gICAgfSk7XG4gICAgcmV0dXJuIHJlc3VsdDtcbn07XG5mdW5jdGlvbiBvYmpNYXAob2JqLCBrZXlGdW5jLCB2YWxGdW5jKSB7XG4gICAgbGV0IHZhbEZ1bmNUeXBlZCA9IHZhbEZ1bmM7XG4gICAgbGV0IGtleUZ1bmNUeXBlZCA9IGtleUZ1bmM7XG4gICAgaWYgKCF2YWxGdW5jVHlwZWQpIHtcbiAgICAgICAgdmFsRnVuY1R5cGVkID0ga2V5RnVuYztcbiAgICAgICAga2V5RnVuY1R5cGVkID0gZmFsc2U7XG4gICAgfVxuICAgIGlmICgha2V5RnVuY1R5cGVkKSB7XG4gICAgICAgIGtleUZ1bmNUeXBlZCA9ICgoaykgPT4gayk7XG4gICAgfVxuICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iai5tYXAodmFsRnVuY1R5cGVkKTtcbiAgICB9XG4gICAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhvYmopLm1hcCgoW2tleSwgdmFsXSkgPT4ge1xuICAgICAgICBhc3NlcnROb25OdWxsVHlwZSh2YWxGdW5jVHlwZWQsIFwiZnVuY3Rpb25cIik7XG4gICAgICAgIHJldHVybiBba2V5RnVuY1R5cGVkKGtleSwgdmFsKSwgdmFsRnVuY1R5cGVkKHZhbCwga2V5KV07XG4gICAgfSkpO1xufVxuLyoqXG4gKiBUaGlzIGZ1bmN0aW9uIHJldHVybnMgdGhlICdzaXplJyBvZiBhbnkgcmVmZXJlbmNlIHBhc3NlZCBpbnRvIGl0LCBmb2xsb3dpbmcgdGhlc2UgcnVsZXM6XG4gKiAtIG9iamVjdDogdGhlIG51bWJlciBvZiBlbnVtZXJhYmxlIGtleXNcbiAqIC0gYXJyYXk6IHRoZSBudW1iZXIgb2YgZWxlbWVudHNcbiAqIC0gZmFsc2UvbnVsbC91bmRlZmluZWQ6IDBcbiAqIC0gYW55dGhpbmcgZWxzZTogMVxuICovXG5jb25zdCBvYmpTaXplID0gKG9iaikgPT4ge1xuICAgIGlmIChpc1NpbXBsZU9iaihvYmopKSB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyhvYmopLmxlbmd0aDtcbiAgICB9XG4gICAgaWYgKGlzQXJyYXkob2JqKSkge1xuICAgICAgICByZXR1cm4gb2JqLmxlbmd0aDtcbiAgICB9XG4gICAgaWYgKG9iaiA9PT0gZmFsc2UgfHwgb2JqID09PSBudWxsIHx8IG9iaiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICByZXR1cm4gMTtcbn07XG4vKipcbiAqIFRoaXMgZnVuY3Rpb24gaXMgYW4gb2JqZWN0LWVxdWl2YWxlbnQgb2YgQXJyYXkuZmluZEluZGV4KCkgZnVuY3Rpb24uXG4gKiBJdCBhY2NlcHRzIGNoZWNrIGZ1bmN0aW9ucyBmb3IgYm90aCBrZXlzIGFuZC9vciB2YWx1ZXMuXG4gKiBJZiBvbmx5IG9uZSBmdW5jdGlvbiBpcyBwcm92aWRlZCwgaXQncyBhc3N1bWVkIHRvIGJlIHNlYXJjaGluZyB2aWEgdmFsdWVzIGFuZCB3aWxsIHJlY2VpdmUgKHYsIGspIGFyZ3MuXG4gKlxuICogQHBhcmFtIHtUeXBlfSBvYmogVGhlIG9iamVjdCB0byBiZSBzZWFyY2hlZC5cbiAqIEBwYXJhbSB7dGVzdEZ1bmM8a2V5RnVuYz4gfCB0ZXN0RnVuYzx2YWxGdW5jPiB8IGZhbHNlfSBrZXlGdW5jIFRoZSB0ZXN0aW5nIGZ1bmN0aW9uIGZvciBrZXlzLlxuICogQHBhcmFtIHt0ZXN0RnVuYzx2YWxGdW5jPn0gdmFsRnVuYyBUaGUgdGVzdGluZyBmdW5jdGlvbiBmb3IgdmFsdWVzLlxuICogQHJldHVybnMge0tleU9mPFR5cGU+IHwgZmFsc2V9IFRoZSBrZXkgb2YgdGhlIGZpcnN0IGVudHJ5IHRoYXQgcGFzc2VzIHRoZSB0ZXN0LlxuICogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIElmIG5vIGVudHJpZXMgcGFzcyB0aGUgdGVzdCwgcmV0dXJuIGZhbHNlLlxuICovXG5mdW5jdGlvbiBvYmpGaW5kS2V5KG9iaiwga2V5RnVuYywgdmFsRnVuYykge1xuICAgIC8vIElmIHZhbEZ1bmMgaXMgbm90IHByb3ZpZGVkLCBhc3N1bWUga2V5RnVuYyBpcyBtZWFudCB0byBiZSB2YWxGdW5jXG4gICAgaWYgKCF2YWxGdW5jKSB7XG4gICAgICAgIHZhbEZ1bmMgPSBrZXlGdW5jO1xuICAgICAgICBrZXlGdW5jID0gZmFsc2U7XG4gICAgfVxuICAgIC8vIElmIGtleUZ1bmMgaXMgbm90IHByb3ZpZGVkLCBjcmVhdGUgYSBmdW5jdGlvbiB0aGF0IHJldHVybnMgdGhlIGtleVxuICAgIGlmICgha2V5RnVuYykge1xuICAgICAgICBrZXlGdW5jID0gKChrKSA9PiBrKTtcbiAgICB9XG4gICAgLy8gSWYgb2JqIGlzIGFuIGFycmF5LCBmaW5kIHRoZSBpbmRleCBvZiB0aGUgZmlyc3QgZWxlbWVudCB0aGF0IHBhc3NlcyB0aGUgdGVzdFxuICAgIGlmIChpc0FycmF5KG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iai5maW5kSW5kZXgodmFsRnVuYyk7XG4gICAgfVxuICAgIC8vIERlZmluZSB0aGUgdGVzdGluZyBmdW5jdGlvbnMgZm9yIGtleXMgYW5kIHZhbHVlc1xuICAgIGNvbnN0IGtGdW5jID0ga2V5RnVuYyB8fCAoKCkgPT4gdHJ1ZSk7XG4gICAgY29uc3QgdkZ1bmMgPSB2YWxGdW5jIHx8ICgoKSA9PiB0cnVlKTtcbiAgICAvLyBGaW5kIHRoZSBmaXJzdCBlbnRyeSB0aGF0IHBhc3NlcyB0aGUgdGVzdFxuICAgIGNvbnN0IHZhbGlkRW50cnkgPSBPYmplY3QuZW50cmllcyhvYmopLmZpbmQoKFtrLCB2XSkgPT4ga0Z1bmMoaywgdikgJiYgdkZ1bmModiwgaykpO1xuICAgIC8vIElmIGFuIGVudHJ5IHBhc3NlcyB0aGUgdGVzdCwgcmV0dXJuIGl0cyBrZXlcbiAgICBpZiAodmFsaWRFbnRyeSkge1xuICAgICAgICByZXR1cm4gdmFsaWRFbnRyeVswXTtcbiAgICB9XG4gICAgLy8gSWYgbm8gZW50cmllcyBwYXNzIHRoZSB0ZXN0LCByZXR1cm4gZmFsc2VcbiAgICByZXR1cm4gZmFsc2U7XG59XG4vKipcbiAqIEFuIG9iamVjdC1lcXVpdmFsZW50IEFycmF5LmZpbHRlcigpIGZ1bmN0aW9uLCB3aGljaCBhY2NlcHRzIGZpbHRlciBmdW5jdGlvbnMgZm9yIGJvdGgga2V5cyBhbmQvb3IgdmFsdWVzLlxuICogSWYgb25seSBvbmUgZnVuY3Rpb24gaXMgcHJvdmlkZWQsIGl0J3MgYXNzdW1lZCB0byBiZSBtYXBwaW5nIHRoZSB2YWx1ZXMgYW5kIHdpbGwgcmVjZWl2ZSAodiwgaykgYXJncy5cbiAqXG4gKiBAcGFyYW0ge1R5cGV9IG9iaiBUaGUgb2JqZWN0IHRvIGJlIHNlYXJjaGVkLlxuICogQHBhcmFtIHt0ZXN0RnVuYzxrZXlGdW5jPiB8IHRlc3RGdW5jPHZhbEZ1bmM+IHwgZmFsc2V9IGtleUZ1bmMgVGhlIHRlc3RpbmcgZnVuY3Rpb24gZm9yIGtleXMuXG4gKiBAcGFyYW0ge3Rlc3RGdW5jPHZhbEZ1bmM+fSBbdmFsRnVuY10gVGhlIHRlc3RpbmcgZnVuY3Rpb24gZm9yIHZhbHVlcy5cbiAqIEByZXR1cm5zIHtUeXBlfSBUaGUgZmlsdGVyZWQgb2JqZWN0LlxuICovXG5jb25zdCBvYmpGaWx0ZXIgPSAob2JqLCBrZXlGdW5jLCB2YWxGdW5jLCBpc011dGF0aW5nID0gZmFsc2UpID0+IHtcbiAgICAvL1xuICAgIGlmICghdmFsRnVuYykge1xuICAgICAgICB2YWxGdW5jID0ga2V5RnVuYztcbiAgICAgICAga2V5RnVuYyA9IGZhbHNlO1xuICAgIH1cbiAgICBpZiAoIWtleUZ1bmMpIHtcbiAgICAgICAga2V5RnVuYyA9ICgoaykgPT4gayk7XG4gICAgfVxuICAgIGlmIChpc0FycmF5KG9iaikpIHtcbiAgICAgICAgY29uc3Qga2VwdFZhbHVlcyA9IG9iai5maWx0ZXIodmFsRnVuYyk7XG4gICAgICAgIGlmIChpc011dGF0aW5nKSB7XG4gICAgICAgICAgICBvYmouc3BsaWNlKDAsIG9iai5sZW5ndGgsIC4uLmtlcHRWYWx1ZXMpO1xuICAgICAgICAgICAgcmV0dXJuIG9iajtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ga2VwdFZhbHVlcztcbiAgICB9XG4gICAgY29uc3Qga0Z1bmMgPSBrZXlGdW5jIHx8ICgoKSA9PiB0cnVlKTtcbiAgICBjb25zdCB2RnVuYyA9IHZhbEZ1bmMgfHwgKCgpID0+IHRydWUpO1xuICAgIGlmIChpc011dGF0aW5nKSB7XG4gICAgICAgIGNvbnN0IGVudHJpZXNUb1JlbW92ZSA9IE9iamVjdC5lbnRyaWVzKG9iailcbiAgICAgICAgICAgIC5maWx0ZXIoKFtrZXksIHZhbF0pID0+ICEoa0Z1bmMoa2V5LCB2YWwpICYmIHZGdW5jKHZhbCwga2V5KSkpO1xuICAgICAgICBmb3IgKGNvbnN0IFtrZXldIG9mIGVudHJpZXNUb1JlbW92ZSkge1xuICAgICAgICAgICAgZGVsZXRlIG9ialtrZXldO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvYmo7XG4gICAgfVxuICAgIHJldHVybiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMob2JqKVxuICAgICAgICAuZmlsdGVyKChba2V5LCB2YWxdKSA9PiBrRnVuYyhrZXksIHZhbCkgJiYgdkZ1bmModmFsLCBrZXkpKSk7XG59O1xuY29uc3Qgb2JqRm9yRWFjaCA9IChvYmosIGZ1bmMpID0+IHtcbiAgICAvLyBBbiBvYmplY3QtZXF1aXZhbGVudCBBcnJheS5mb3JFYWNoKCkgZnVuY3Rpb24sIHdoaWNoIGFjY2VwdHMgb25lIGZ1bmN0aW9uKHZhbCwga2V5KSB0byBwZXJmb3JtIGZvciBlYWNoIG1lbWJlci5cbiAgICBpZiAoaXNBcnJheShvYmopKSB7XG4gICAgICAgIG9iai5mb3JFYWNoKGZ1bmMpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgT2JqZWN0LmVudHJpZXMob2JqKS5mb3JFYWNoKChba2V5LCB2YWxdKSA9PiBmdW5jKHZhbCwga2V5KSk7XG4gICAgfVxufTtcbi8vIFBydW5lcyBhbiBvYmplY3Qgb2YgZ2l2ZW4gc2V0IG9mIHZhbHVlcywgW3VuZGVmaW5lZCwgbnVsbF0gZGVmYXVsdFxuY29uc3Qgb2JqQ29tcGFjdCA9IChvYmosIHJlbW92ZVdoaXRlTGlzdCA9IFt1bmRlZmluZWQsIG51bGxdLCBpc011dGF0aW5nID0gZmFsc2UpID0+IG9iakZpbHRlcihvYmosICh2YWwpID0+ICFyZW1vdmVXaGl0ZUxpc3QuaW5jbHVkZXModmFsKSwgdW5kZWZpbmVkLCBpc011dGF0aW5nKTtcbmNvbnN0IG9iakNsb25lID0gKG9iaiwgaXNTdHJpY3RseVNhZmUgPSBmYWxzZSkgPT4ge1xuICAgIGNvbnN0IGNsb25lQXJyYXkgPSAoYXJyKSA9PiBbLi4uYXJyXTtcbiAgICBjb25zdCBjbG9uZU9iamVjdCA9IChvKSA9PiAoeyAuLi5vIH0pO1xuICAgIHRyeSB7XG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKEpTT04uc3RyaW5naWZ5KG9iaikpO1xuICAgIH1cbiAgICBjYXRjaCAoZXJyKSB7XG4gICAgICAgIGlmIChpc1N0cmljdGx5U2FmZSkge1xuICAgICAgICAgICAgdGhyb3cgZXJyO1xuICAgICAgICB9XG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG9iaikpIHtcbiAgICAgICAgICAgIHJldHVybiBjbG9uZUFycmF5KG9iaik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHR5cGVvZiBvYmogPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHJldHVybiBjbG9uZU9iamVjdChvYmopO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvYmo7XG59O1xuLyoqXG4gKiBSZXR1cm5zIGEgZGVlcCBtZXJnZSBvZiBzb3VyY2UgaW50byB0YXJnZXQuIERvZXMgbm90IG11dGF0ZSB0YXJnZXQgdW5sZXNzIGlzTXV0YXRpbmdPayA9IHRydWUuXG4gKiBAcGFyYW0ge1R4fSB0YXJnZXQgVGhlIHRhcmdldCBvYmplY3QgdG8gYmUgbWVyZ2VkLlxuICogQHBhcmFtIHtUeX0gc291cmNlIFRoZSBzb3VyY2Ugb2JqZWN0IHRvIGJlIG1lcmdlZC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIEFuIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgb3B0aW9ucyBmb3IgdGhlIG1lcmdlIG9wZXJhdGlvbi5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gb3B0aW9ucy5pc011dGF0aW5nT2tcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gb3B0aW9ucy5pc1N0cmljdGx5U2FmZVxuICogQHBhcmFtIHtib29sZWFufSBvcHRpb25zLmlzQ29uY2F0ZW5hdGluZ0FycmF5c1xuICogQHBhcmFtIHtib29sZWFufSBvcHRpb25zLmlzUmVwbGFjaW5nQXJyYXlzXG4gKiBAcmV0dXJucyB7VHggJiBUeX0gLSBUaGUgbWVyZ2VkIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gb2JqTWVyZ2UodGFyZ2V0LCBzb3VyY2UsIHsgaXNNdXRhdGluZ09rID0gZmFsc2UsIGlzU3RyaWN0bHlTYWZlID0gZmFsc2UsIGlzQ29uY2F0ZW5hdGluZ0FycmF5cyA9IHRydWUsIGlzUmVwbGFjaW5nQXJyYXlzID0gZmFsc2UgfSA9IHt9KSB7XG4gICAgLy8gQ2xvbmUgdGhlIHRhcmdldCBpZiBtdXRhdGlvbiBpcyBub3QgYWxsb3dlZFxuICAgIHRhcmdldCA9IGlzTXV0YXRpbmdPayA/IHRhcmdldCA6IG9iakNsb25lKHRhcmdldCwgaXNTdHJpY3RseVNhZmUpO1xuICAgIC8vIElmIHNvdXJjZSBpcyBhbiBpbnN0YW5jZSBvZiAgb3IgdGFyZ2V0IGlzIHVuZGVmaW5lZCwgcmV0dXJuIHNvdXJjZVxuICAgIGlmICgoc291cmNlICYmIHR5cGVvZiBzb3VyY2UgPT09IFwib2JqZWN0XCIgJiYgXCJpZFwiIGluIHNvdXJjZSAmJiBpc0RvY0lEKHNvdXJjZS5pZCkpIHx8IGlzVW5kZWZpbmVkKHRhcmdldCkpIHtcbiAgICAgICAgcmV0dXJuIHNvdXJjZTtcbiAgICB9XG4gICAgLy8gSWYgc291cmNlIGlzIHVuZGVmaW5lZCwgcmV0dXJuIHRhcmdldFxuICAgIGlmIChpc1VuZGVmaW5lZChzb3VyY2UpKSB7XG4gICAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuICAgIC8vIElmIHNvdXJjZSBpcyBub3QgYW4gaW5kZXgsIHJldHVybiB0YXJnZXRcbiAgICBpZiAoIWlzSW5kZXgoc291cmNlKSkge1xuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH1cbiAgICAvLyBJdGVyYXRlIG92ZXIgZWFjaCBlbnRyeSBpbiB0aGUgc291cmNlIG9iamVjdFxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsXSBvZiBPYmplY3QuZW50cmllcyhzb3VyY2UpKSB7XG4gICAgICAgIGNvbnN0IHRhcmdldFZhbCA9IHRhcmdldFtrZXldO1xuICAgICAgICAvLyBJZiByZXBsYWNpbmcgYXJyYXlzIGlzIGVuYWJsZWQgYW5kIGJvdGggdGFyZ2V0IGFuZCBzb3VyY2UgdmFsdWVzIGFyZVxuICAgICAgICAvLyBhcnJheXMsIHJlcGxhY2UgdGFyZ2V0IHZhbHVlIHdpdGggc291cmNlIHZhbHVlXG4gICAgICAgIGlmIChpc1JlcGxhY2luZ0FycmF5cyAmJiBpc0FycmF5KHRhcmdldFZhbCkgJiYgaXNBcnJheSh2YWwpKSB7XG4gICAgICAgICAgICB0YXJnZXRba2V5XSA9IHZhbDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChpc0NvbmNhdGVuYXRpbmdBcnJheXMgJiYgaXNBcnJheSh0YXJnZXRWYWwpICYmIGlzQXJyYXkodmFsKSkge1xuICAgICAgICAgICAgLy8gSWYgY29uY2F0ZW5hdGluZyBhcnJheXMgaXMgZW5hYmxlZCBhbmQgYm90aCB0YXJnZXQgYW5kIHNvdXJjZSB2YWx1ZXNcbiAgICAgICAgICAgIC8vIGFyZSBhcnJheXMsIGNvbmNhdGVuYXRlIHNvdXJjZSB2YWx1ZSB0byB0YXJnZXQgdmFsdWVcbiAgICAgICAgICAgIHRhcmdldFtrZXldLnB1c2goLi4udmFsKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh2YWwgIT09IG51bGwgJiYgdHlwZW9mIHZhbCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgLy8gSWYgc291cmNlIHZhbHVlIGlzIGFuIG9iamVjdCBhbmQgbm90IG51bGwsIG1lcmdlIGl0IGludG8gdGFyZ2V0IHZhbHVlXG4gICAgICAgICAgICBpZiAoaXNVbmRlZmluZWQodGFyZ2V0VmFsKSAmJiAhKHZhbCBpbnN0YW5jZW9mIEFwcGxpY2F0aW9uKSkge1xuICAgICAgICAgICAgICAgIHRhcmdldFtrZXldID0gbmV3IChPYmplY3QuZ2V0UHJvdG90eXBlT2YodmFsKS5jb25zdHJ1Y3RvcikoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRhcmdldFtrZXldID0gb2JqTWVyZ2UodGFyZ2V0W2tleV0sIHZhbCwgeyBpc011dGF0aW5nT2s6IHRydWUsIGlzU3RyaWN0bHlTYWZlIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gRm9yIGFsbCBvdGhlciBjYXNlcywgYXNzaWduIHNvdXJjZSB2YWx1ZSB0byB0YXJnZXRcbiAgICAgICAgICAgIHRhcmdldFtrZXldID0gdmFsO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIFJldHVybiB0aGUgbWVyZ2VkIHRhcmdldFxuICAgIHJldHVybiB0YXJnZXQ7XG59XG4vKipcbiAqIERlZXAtY29tcGFyZXMgdHdvIG9iamVjdHMgYW5kIHJldHVybnMgYW4gb2JqZWN0IGNvbnRhaW5pbmcgb25seSB0aGUga2V5cyBhbmQgdmFsdWVzXG4gKiBpbiB0aGUgc2Vjb25kIG9iamVjdCB0aGF0IGRpZmZlciBmcm9tIHRoZSBmaXJzdC5cbiAqIElmIHRoZSBzZWNvbmQgb2JqZWN0IGlzIG1pc3NpbmcgYSBrZXkgb3IgdmFsdWUgY29udGFpbmVkIGluIHRoZSBmaXJzdCwgaXQgc2V0cyB0aGVcbiAqIHZhbHVlIGluIHRoZSByZXR1cm5lZCBvYmplY3QgdG8gbnVsbCwgYW5kIHByZWZpeGVzIHRoZSBrZXkgd2l0aCBcIi09XCIuXG4gKiBAcGFyYW0ge1R4fSBvYmoxIFRoZSBmaXJzdCBvYmplY3QgdG8gYmUgY29tcGFyZWQuXG4gKiBAcGFyYW0ge1R5fSBvYmoyIFRoZSBzZWNvbmQgb2JqZWN0IHRvIGJlIGNvbXBhcmVkLlxuICogQHJldHVybnMge1JlY29yZDxzdHJpbmcsIHVua25vd24+fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBkaWZmZXJlbmNlcyBiZXR3ZWVuIHRoZSB0d28gaW5wdXQgb2JqZWN0cy5cbiAqL1xuZnVuY3Rpb24gb2JqRGlmZihvYmoxLCBvYmoyKSB7XG4gICAgY29uc3QgZGlmZiA9IHt9O1xuICAgIGNvbnN0IGJvdGhPYmoxQW5kT2JqMktleXMgPSBPYmplY3Qua2V5cyhvYmoyKS5maWx0ZXIoKGtleSkgPT4gT2JqZWN0Lmhhc093bihvYmoyLCBrZXkpICYmIE9iamVjdC5oYXNPd24ob2JqMSwga2V5KSk7XG4gICAgY29uc3Qgb25seU9iajJLZXlzID0gT2JqZWN0LmtleXMob2JqMikuZmlsdGVyKChrZXkpID0+IE9iamVjdC5oYXNPd24ob2JqMiwga2V5KSAmJiAhT2JqZWN0Lmhhc093bihvYmoxLCBrZXkpKTtcbiAgICBmb3IgKGNvbnN0IGtleSBvZiBib3RoT2JqMUFuZE9iajJLZXlzKSB7XG4gICAgICAgIC8vIElmIGJvdGggdmFsdWVzIGFyZSBub24tYXJyYXkgb2JqZWN0cywgcmVjdXJzaXZlbHkgY29tcGFyZSB0aGVtXG4gICAgICAgIGlmICh0eXBlb2Ygb2JqMVtrZXldID09PSBcIm9iamVjdFwiICYmIHR5cGVvZiBvYmoyW2tleV0gPT09IFwib2JqZWN0XCIgJiYgIUFycmF5LmlzQXJyYXkob2JqMVtrZXldKSAmJiAhQXJyYXkuaXNBcnJheShvYmoyW2tleV0pKSB7XG4gICAgICAgICAgICBjb25zdCBuZXN0ZWREaWZmID0gb2JqRGlmZihvYmoxW2tleV0sIG9iajJba2V5XSk7XG4gICAgICAgICAgICBpZiAoT2JqZWN0LmtleXMobmVzdGVkRGlmZikubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGRpZmZba2V5XSA9IG5lc3RlZERpZmY7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvYmoxW2tleV0pICYmIEFycmF5LmlzQXJyYXkob2JqMltrZXldKSkge1xuICAgICAgICAgICAgY29uc3QgYXJyYXkxID0gb2JqMVtrZXldO1xuICAgICAgICAgICAgY29uc3QgYXJyYXkyID0gb2JqMltrZXldO1xuICAgICAgICAgICAgaWYgKGFycmF5MS50b1N0cmluZygpICE9PSBhcnJheTIudG9TdHJpbmcoKSkge1xuICAgICAgICAgICAgICAgIC8vIElmIGJvdGggdmFsdWVzIGFyZSBhcnJheXMgYW5kIHRoZXkgYXJlIG5vdCBlcXVhbCwgYWRkIHRoZSBzZWNvbmQgYXJyYXkgdG8gdGhlIGRpZmZcbiAgICAgICAgICAgICAgICBkaWZmW2tleV0gPSBvYmoyW2tleV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAob2JqMVtrZXldICE9PSBvYmoyW2tleV0pIHtcbiAgICAgICAgICAgIC8vIElmIHRoZSB2YWx1ZXMgYXJlIG5vdCBlcXVhbCwgYWRkIHRoZSBzZWNvbmQgdmFsdWUgdG8gdGhlIGRpZmZcbiAgICAgICAgICAgIGRpZmZba2V5XSA9IG9iajJba2V5XTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmb3IgKGNvbnN0IGtleSBvZiBvbmx5T2JqMktleXMpIHtcbiAgICAgICAgLy8gSWYgdGhlIHNlY29uZCBvYmplY3QgaGFzIGEga2V5IHRoYXQgdGhlIGZpcnN0IGRvZXMgbm90LCBhZGQgaXQgdG8gdGhlIGRpZmYgd2l0aCBhIFwiLT1cIiBwcmVmaXhcbiAgICAgICAgZGlmZltgLT0ke2tleX1gXSA9IG9iajJba2V5XTtcbiAgICB9XG4gICAgcmV0dXJuIGRpZmY7XG59XG5jb25zdCBvYmpFeHBhbmQgPSAob2JqKSA9PiB7XG4gICAgY29uc3QgZXhwT2JqID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWxdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICAgICAgaWYgKGlzTGlzdCh2YWwpKSB7XG4gICAgICAgICAgICBjb25zdCBleHBhbmRlZFZhbCA9IG9iakV4cGFuZCh2YWwpO1xuICAgICAgICAgICAgc2V0UHJvcGVydHkoZXhwT2JqLCBrZXksIGV4cGFuZGVkVmFsKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHNldFByb3BlcnR5KGV4cE9iaiwga2V5LCB2YWwpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIEl0ZXJhdGUgdGhyb3VnaCBleHBhbmRlZCBPYmplY3QsIGNvbnZlcnRpbmcgb2JqZWN0IGxpdGVyYWxzIHRvIGFycmF5cyB3aGVyZSBpdCBtYWtlcyBzZW5zZVxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIG9cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBhcnJheWlmeShvKSB7XG4gICAgICAgIGlmIChpc0xpc3QobykpIHtcbiAgICAgICAgICAgIGlmICgvXlxcZCskLy50ZXN0KE9iamVjdC5rZXlzKG8pLmpvaW4oXCJcIikpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMobykubWFwKGFycmF5aWZ5KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBvYmpNYXAobywgKHYpID0+IGFycmF5aWZ5KHYpKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNBcnJheShvKSkge1xuICAgICAgICAgICAgcmV0dXJuIG8ubWFwKGFycmF5aWZ5KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbztcbiAgICB9XG4gICAgcmV0dXJuIGFycmF5aWZ5KGV4cE9iaik7XG59O1xuY29uc3Qgb2JqRmxhdHRlbiA9IChvYmopID0+IHtcbiAgICBjb25zdCBmbGF0T2JqID0ge307XG4gICAgZm9yIChjb25zdCBba2V5LCB2YWxdIG9mIE9iamVjdC5lbnRyaWVzKG9iaikpIHtcbiAgICAgICAgaWYgKChpc0FycmF5KHZhbCkgfHwgaXNMaXN0KHZhbCkpICYmIGhhc0l0ZW1zKHZhbCkpIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW3N1YktleSwgc3ViVmFsXSBvZiBPYmplY3QuZW50cmllcyhvYmpGbGF0dGVuKHZhbCkpKSB7XG4gICAgICAgICAgICAgICAgZmxhdE9ialtgJHtrZXl9LiR7c3ViS2V5fWBdID0gc3ViVmFsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZmxhdE9ialtrZXldID0gdmFsO1xuICAgICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmbGF0T2JqO1xufTtcbi8qKlxuICpcbiAqIEBwYXJhbSBvYmpcbiAqL1xuZnVuY3Rpb24gb2JqTnVsbGlmeShvYmopIHtcbiAgICAvLyBDaGVjayBpZiB0aGUgaW5wdXQgaXMgYW4gb2JqZWN0IG9yIGFuIGFycmF5XG4gICAgaWYgKCFpc0luZGV4KG9iaikpIHtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gICAgLy8gSWYgdGhlIGlucHV0IGlzIGFuIGFycmF5LCBudWxsaWZ5IGFsbCBpdHMgZWxlbWVudHNcbiAgICBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgICAgIG9iai5mb3JFYWNoKChfLCBpKSA9PiB7XG4gICAgICAgICAgICBvYmpbaV0gPSBudWxsO1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIG9iajtcbiAgICB9XG4gICAgLy8gSWYgdGhlIGlucHV0IGlzIGFuIG9iamVjdCwgbnVsbGlmeSBhbGwgaXRzIHByb3BlcnRpZXNcbiAgICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKG9iaktleSkgPT4ge1xuICAgICAgICBvYmpbb2JqS2V5XSA9IG51bGw7XG4gICAgfSk7XG4gICAgcmV0dXJuIG9iajtcbn1cbi8qKlxuICogVGhpcyBmdW5jdGlvbiBmcmVlemVzIHRoZSBwcm9wZXJ0aWVzIG9mIGFuIG9iamVjdCBiYXNlZCBvbiBhIHByb3ZpZGVkIHNjaGVtYSBvciBrZXlzLlxuICogSWYgYSBwcm9wZXJ0eSBpcyBtaXNzaW5nLCBpdCB0aHJvd3MgYW4gZXJyb3IuXG4gKiBAcGFyYW0ge1BhcnRpYWw8VD59IGRhdGEgVGhlIG9iamVjdCB3aG9zZSBwcm9wZXJ0aWVzIGFyZSB0byBiZSBmcm96ZW4uXG4gKiBAcGFyYW0gey4uLkFycmF5PGtleW9mIFQ+IHwgW1RdfSBrZXlzT3JTY2hlbWEgVGhlIGtleXMgb3Igc2NoZW1hIHRvIGZyZWV6ZSB0aGUgcHJvcGVydGllcy5cbiAqIEByZXR1cm5zIHtUfSAtIFRoZSBvYmplY3Qgd2l0aCBmcm96ZW4gcHJvcGVydGllcy5cbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiBhIHByb3BlcnR5IGlzIG1pc3NpbmcuXG4gKi9cbmZ1bmN0aW9uIG9iakZyZWV6ZVByb3BzKGRhdGEsIC4uLmtleXNPclNjaGVtYSkge1xuICAgIGNvbnN0IGZpcnN0QXJnID0ga2V5c09yU2NoZW1hWzBdO1xuICAgIC8vIElmIHRoZSBmaXJzdCBhcmd1bWVudCBpcyBhbiBvYmplY3QgYW5kIG5vdCBhbiBhcnJheSwgdHJlYXQgaXQgYXMgYSBzY2hlbWFcbiAgICBpZiAoZmlyc3RBcmcgaW5zdGFuY2VvZiBPYmplY3QgJiYgIUFycmF5LmlzQXJyYXkoZmlyc3RBcmcpKSB7XG4gICAgICAgIGNvbnN0IHNjaGVtYSA9IGZpcnN0QXJnO1xuICAgICAgICBmb3IgKGNvbnN0IGtleSBpbiBzY2hlbWEpIHtcbiAgICAgICAgICAgIGlmIChkYXRhW2tleV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTWlzc2luZyB2YWx1ZSBmb3IgJHtrZXl9YCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIC8vIElmIHRoZSBmaXJzdCBhcmd1bWVudCBpcyBub3QgYW4gb2JqZWN0IG9yIGlzIGFuIGFycmF5LCB0cmVhdCBpdCBhcyBhbiBhcnJheSBvZiBrZXlzXG4gICAgICAgIGZvciAoY29uc3Qga2V5IG9mIGtleXNPclNjaGVtYSkge1xuICAgICAgICAgICAgaWYgKGRhdGFba2V5XSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBNaXNzaW5nIHZhbHVlIGZvciAke1N0cmluZyhrZXkpfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuICAgIC8vIFJldHVybiB0aGUgZGF0YSBhcyB0eXBlIFRcbiAgICByZXR1cm4gZGF0YTtcbn1cbi8vICNlbmRyZWdpb24g4paE4paE4paE4paE4paEIE9CSkVDVFMg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBGVU5DVElPTlM6IEZ1bmN0aW9uIFdyYXBwaW5nLCBRdWV1aW5nLCBNYW5pcHVsYXRpb24g4paI4paI4paI4paI4paI4paI4paI4paIIH5cbmNvbnN0IGdldER5bmFtaWNGdW5jID0gKGZ1bmNOYW1lLCBmdW5jLCBjb250ZXh0KSA9PiB7XG4gICAgaWYgKHR5cGVvZiBmdW5jID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgY29uc3QgZEZ1bmMgPSB7IFtmdW5jTmFtZV0oLi4uYXJncykgeyByZXR1cm4gZnVuYyguLi5hcmdzKTsgfSB9W2Z1bmNOYW1lXTtcbiAgICAgICAgcmV0dXJuIGNvbnRleHQgPyBkRnVuYy5iaW5kKGNvbnRleHQpIDogZEZ1bmM7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn07XG5jb25zdCB3aXRoTG9nID0gKGZuKSA9PiB7XG4gICAgcmV0dXJuICguLi5hcmdzKSA9PiB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBjYWxsaW5nICR7Zm4ubmFtZX1gKTtcbiAgICAgICAgcmV0dXJuIGZuKC4uLmFyZ3MpO1xuICAgIH07XG59O1xuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgRlVOQ1RJT05TIOKWhOKWhOKWhOKWhOKWhFxuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggSFRNTDogUGFyc2luZyBIVE1MIENvZGUsIE1hbmlwdWxhdGluZyBET00gT2JqZWN0cyDilojilojilojilojilojilojilojiloggflxuY29uc3QgY2hhbmdlQ29udGFpbmVyID0gKGVsZW0sIGNvbnRhaW5lciwgaXNDbG9uaW5nID0gZmFsc2UpID0+IHtcbiAgICBlbGVtID0gJChlbGVtKVswXTtcbiAgICBjb250YWluZXIgPSAkKGNvbnRhaW5lcilbMF07XG4gICAgLy8gR2V0IHRoZSBlbGVtZW50J3MgY3VycmVudCBjb250YWluZXIsIHdoaWNoIGRlZmluZXMgaXRzIGN1cnJlbnQgY29vcmRpbmF0ZSBzcGFjZS5cbiAgICBjb25zdCBjdXJDb250YWluZXIgPSAkKGVsZW0pLnBhcmVudCgpWzBdO1xuICAgIC8vIEdldCB0aGUgZWxlbWVudCdzIGN1cnJlbnQgcG9zaXRpb24gaW4gaXRzIGN1cnJlbnQgY29vcmRpbmF0ZSBzcGFjZS5cbiAgICBjb25zdCBjdXJQb3NpdGlvbiA9IHtcbiAgICAgICAgeDogZ3NhcC5nZXRQcm9wZXJ0eShlbGVtLCBcInhcIiksXG4gICAgICAgIHk6IGdzYXAuZ2V0UHJvcGVydHkoZWxlbSwgXCJ5XCIpXG4gICAgfTtcbiAgICAvLyBDb252ZXJ0IHRoZSBlbGVtZW50J3MgcG9zaXRpb24gaW4gaXRzIGN1cnJlbnQgc3BhY2UsIHRvIHRoZSBlcXVpdmFsZW50IHBvc2l0aW9uIGluIHRoZSB0YXJnZXQgc3BhY2UuXG4gICAgY29uc3QgcmVsUG9zID0gTW90aW9uUGF0aFBsdWdpbi5jb252ZXJ0Q29vcmRpbmF0ZXMoY3VyQ29udGFpbmVyLCBjb250YWluZXIsIGN1clBvc2l0aW9uKTtcbiAgICBlTG9nLmNoZWNrTG9nMyhcImNoYW5nZUNvbnRhaW5lclwiLCBcIlRhcmdldCBFbGVtZW50XCIsIHsgZWxlbSwgY29udGFpbmVyLCBjdXJDb250YWluZXIsIGN1clBvc2l0aW9uLCByZWxQb3MgfSk7XG4gICAgLy8gQ2xvbmUgdGhlIGVsZW1lbnQsIGlmIGluZGljYXRlZFxuICAgIGlmIChpc0Nsb25pbmcpIHtcbiAgICAgICAgZWxlbSA9ICQoZWxlbSkuY2xvbmUoKVswXTtcbiAgICB9XG4gICAgLy8gQXBwZW5kIHRoZSBlbGVtZW50IHRvIHRoZSBuZXcgY29udGFpbmVyLCBhbmQgc2V0IGl0cyBuZXcgcG9zaXRpb25cbiAgICAkKGVsZW0pLmFwcGVuZFRvKCQoY29udGFpbmVyKSk7XG4gICAgZ3NhcC5zZXQoZWxlbSwgcmVsUG9zKTtcbiAgICByZXR1cm4gZWxlbTtcbn07XG4vKipcbiAqIEFkanVzdHMgdGhlIGFzcGVjdCByYXRpbyBvZiBhIHRleHQgY29udGFpbmVyIHRvIG1hdGNoIGEgdGFyZ2V0IHJhdGlvIGJ5IG1vZGlmeWluZyBpdHMgZm9udCBzaXplIGFuZCBsaW5lIGhlaWdodC5cbiAqIFRoaXMgZnVuY3Rpb24gcmVjdXJzaXZlbHkgYWRqdXN0cyB0aGUgZm9udCBzaXplIGFuZCBsaW5lIGhlaWdodCB1bnRpbCB0aGUgY29udGFpbmVyJ3MgYXNwZWN0IHJhdGlvIG9yIG1heGltdW0gZGltZW5zaW9ucyBhcmUgbWV0LlxuICpcbiAqIEBwYXJhbSB7SFRNTEVsZW1lbnR8SlF1ZXJ5PEhUTUxFbGVtZW50Pn0gdGV4dENvbnRhaW5lciAtIFRoZSB0ZXh0IGNvbnRhaW5lciBlbGVtZW50IG9yIGpRdWVyeSBvYmplY3QgdG8gYWRqdXN0LlxuICogQHBhcmFtIHtudW1iZXJ9IHRhcmdldFJhdGlvIC0gVGhlIHRhcmdldCBhc3BlY3QgcmF0aW8gKHdpZHRoIC8gaGVpZ2h0KSB0byBhY2hpZXZlLlxuICogQHBhcmFtIHtudW1iZXJ9IFttYXhIZWlnaHRdIC0gT3B0aW9uYWwgbWF4aW11bSBoZWlnaHQgZm9yIHRoZSB0ZXh0IGNvbnRhaW5lci5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbbWF4V2lkdGhdIC0gT3B0aW9uYWwgbWF4aW11bSB3aWR0aCBmb3IgdGhlIHRleHQgY29udGFpbmVyLlxuICogQHBhcmFtIHtudW1iZXJ9IFttaW5Gb250U2l6ZT04XSAtIE9wdGlvbmFsIG1pbmltdW0gZm9udCBzaXplIHRvIHByZXZlbnQgdGhlIHRleHQgZnJvbSBiZWNvbWluZyB0b28gc21hbGwuXG4gKiBAcmV0dXJucyB7dm9pZH1cbiAqL1xuY29uc3QgYWRqdXN0VGV4dENvbnRhaW5lckFzcGVjdFJhdGlvID0gKHRleHRDb250YWluZXIsIHRhcmdldFJhdGlvLCBtYXhIZWlnaHQsIG1heFdpZHRoLCBtaW5Gb250U2l6ZSA9IDgpID0+IHtcbiAgICAvLyBFbnN1cmUgdGV4dENvbnRhaW5lciBpcyBhbiBIVE1MRWxlbWVudFxuICAgIHRleHRDb250YWluZXIgPSAkKHRleHRDb250YWluZXIpWzBdO1xuICAgIC8vIElmIG5vIG1heFdpZHRoIGlzIHByb3ZpZGVkLCBpbml0aWFsaXplIHRleHRDb250YWluZXIncyB3aWR0aCB0byBtYXhpbXVtIHBvc3NpYmxlXG4gICAgaWYgKCFtYXhXaWR0aCkge1xuICAgICAgICB0ZXh0Q29udGFpbmVyLnN0eWxlLnNldFByb3BlcnR5KFwid2lkdGhcIiwgXCJtYXgtY29udGVudFwiLCBcImltcG9ydGFudFwiKTtcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHRleHRDb250YWluZXIuc3R5bGUuc2V0UHJvcGVydHkoXCJ3aWR0aFwiLCBgJHttYXhXaWR0aH1weGAsIFwiaW1wb3J0YW50XCIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKiBSZWN1cnNpdmVseSBhZGp1c3RzIHRoZSBmb250IHNpemUgYW5kIGxpbmUgaGVpZ2h0IG9mIHRoZSB0ZXh0IGNvbnRhaW5lci5cbiAgICAgKiBUaGlzIGZ1bmN0aW9uIGlzIGNhbGxlZCBpZiB0aGUgY3VycmVudCBhZGp1c3RtZW50cyBkbyBub3QgbWVldCB0aGUgdGFyZ2V0IGFzcGVjdCByYXRpbyBvciBtYXhpbXVtIGRpbWVuc2lvbnMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBuZXcgZm9udCBzaXplIGlzIGJlbG93IHRoZSBtaW5pbXVtIGZvbnQgc2l6ZSwgaW5kaWNhdGluZyBubyBmdXJ0aGVyIGFkanVzdG1lbnRzIHNob3VsZCBiZSBtYWRlLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHJlY3VyQWRqdXN0bWVudCgpIHtcbiAgICAgICAgLy8gRW5zdXJlIHRleHRDb250YWluZXIgaXMgYW4gSFRNTEVsZW1lbnQgZm9yIGVhY2ggcmVjdXJzaXZlIGNhbGxcbiAgICAgICAgdGV4dENvbnRhaW5lciA9ICQodGV4dENvbnRhaW5lcilbMF07XG4gICAgICAgIC8vIENhbGN1bGF0ZSBuZXcgZm9udCBzaXplIGFuZCBsaW5lIGhlaWdodCBhcyA4MCUgb2YgdGhlaXIgY3VycmVudCB2YWx1ZXNcbiAgICAgICAgY29uc3QgbmV3Rm9udFNpemUgPSBwYXJzZUZsb2F0KHN0eWxlLmZvbnRTaXplKSAqIDAuODtcbiAgICAgICAgY29uc3QgbmV3TGluZUhlaWdodCA9IHBhcnNlRmxvYXQoc3R5bGUubGluZUhlaWdodCkgKiAwLjg7XG4gICAgICAgIC8vIFN0b3AgcmVjdXJzaW9uIGlmIHRoZSBuZXcgZm9udCBzaXplIGlzIGJlbG93IHRoZSBtaW5pbXVtXG4gICAgICAgIGlmIChuZXdGb250U2l6ZSA8IG1pbkZvbnRTaXplKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQXBwbHkgdGhlIG5ldyBmb250IHNpemUgYW5kIGxpbmUgaGVpZ2h0XG4gICAgICAgIHRleHRDb250YWluZXIuc3R5bGUuZm9udFNpemUgPSBgJHtuZXdGb250U2l6ZX1weGA7XG4gICAgICAgIHRleHRDb250YWluZXIuc3R5bGUubGluZUhlaWdodCA9IGAke25ld0xpbmVIZWlnaHR9cHhgO1xuICAgICAgICAvLyBSZWN1cnNpdmVseSBjYWxsIGFkanVzdFRleHRDb250YWluZXJBc3BlY3RSYXRpbyB3aXRoIHVwZGF0ZWQgcGFyYW1ldGVyc1xuICAgICAgICByZXR1cm4gYWRqdXN0VGV4dENvbnRhaW5lckFzcGVjdFJhdGlvKHRleHRDb250YWluZXIsIHRhcmdldFJhdGlvLCBsaW5lQ291bnQgPz8gbWF4SGVpZ2h0LCBtYXhXaWR0aCwgbWluRm9udFNpemUpO1xuICAgIH1cbiAgICAvLyBHZXQgY29tcHV0ZWQgc3R5bGVzIG9mIHRoZSB0ZXh0IGNvbnRhaW5lclxuICAgIGNvbnN0IHN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUodGV4dENvbnRhaW5lcik7XG4gICAgY29uc3QgbGluZUhlaWdodCA9IHBhcnNlRmxvYXQoc3R5bGUubGluZUhlaWdodCk7XG4gICAgLy8gSW5pdGlhbGl6ZSBsaW5lQ291bnQgYXMgdW5kZWZpbmVkXG4gICAgbGV0IGxpbmVDb3VudCA9IHVuZGVmaW5lZDtcbiAgICAvLyBJZiBtYXhIZWlnaHQgaXMgcHJvdmlkZWQgYW5kIGlzIGFuIGludGVnZXIgbGVzcyB0aGFuIGxpbmVIZWlnaHQsIGNhbGN1bGF0ZSBsaW5lQ291bnRcbiAgICBpZiAoaXNJbnQobWF4SGVpZ2h0KSAmJiBtYXhIZWlnaHQgPCBsaW5lSGVpZ2h0KSB7XG4gICAgICAgIGxpbmVDb3VudCA9IG1heEhlaWdodDtcbiAgICB9XG4gICAgLy8gR2V0IHRoZSBpbml0aWFsIHdpZHRoIG9mIHRoZSB0ZXh0IGNvbnRhaW5lclxuICAgIGNvbnN0IGluaXRpYWxXaWR0aCA9IHBhcnNlRmxvYXQoc3R5bGUud2lkdGgpO1xuICAgIC8vIEluaXRpYWxpemUgYmVzdFdpZHRoIHdpdGggdGhlIGluaXRpYWwgd2lkdGhcbiAgICBsZXQgYmVzdFdpZHRoID0gaW5pdGlhbFdpZHRoO1xuICAgIC8vIEZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIG1heGltdW0gbGluZSBjb3VudCBoYXMgYmVlbiByZWFjaGVkXG4gICAgbGV0IGlzQXRNYXhMaW5lQ291bnQgPSBmYWxzZTtcbiAgICAvLyBMb29wIHRvIGZpbmQgdGhlIGJlc3Qgd2lkdGggdGhhdCBtYXRjaGVzIHRoZSB0YXJnZXQgYXNwZWN0IHJhdGlvXG4gICAgZm9yIChsZXQgbGluZXMgPSAxOzsgbGluZXMrKykge1xuICAgICAgICBjb25zdCBleHBlY3RlZEhlaWdodCA9IGxpbmVIZWlnaHQgKiBsaW5lcztcbiAgICAgICAgY29uc3QgZXhwZWN0ZWRXaWR0aCA9IGluaXRpYWxXaWR0aCAvIGxpbmVzO1xuICAgICAgICBjb25zdCBleHBlY3RlZFJhdGlvID0gZXhwZWN0ZWRXaWR0aCAvIGV4cGVjdGVkSGVpZ2h0O1xuICAgICAgICAvLyBCcmVhayB0aGUgbG9vcCBpZiB0aGUgZXhwZWN0ZWQgcmF0aW8gaXMgbGVzcyB0aGFuIHRoZSB0YXJnZXQgcmF0aW9cbiAgICAgICAgaWYgKGV4cGVjdGVkUmF0aW8gPCB0YXJnZXRSYXRpbykge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSGFuZGxlIGNhc2VzIHdoZXJlIGxpbmVDb3VudCBpcyBkZWZpbmVkXG4gICAgICAgIGlmIChpc0ludChsaW5lQ291bnQpKSB7XG4gICAgICAgICAgICBpZiAobGluZXMgPiBsaW5lQ291bnQpIHtcbiAgICAgICAgICAgICAgICBpZiAocmVjdXJBZGp1c3RtZW50KCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChtYXhIZWlnaHQgJiYgZXhwZWN0ZWRIZWlnaHQgPiBtYXhIZWlnaHQpIHtcbiAgICAgICAgICAgIC8vIEhhbmRsZSBjYXNlcyB3aGVyZSBtYXhIZWlnaHQgaXMgZXhjZWVkZWRcbiAgICAgICAgICAgIGlmIChyZWN1ckFkanVzdG1lbnQoKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIC8vIFVwZGF0ZSBiZXN0V2lkdGggd2l0aCB0aGUgZXhwZWN0ZWQgd2lkdGhcbiAgICAgICAgYmVzdFdpZHRoID0gZXhwZWN0ZWRXaWR0aDtcbiAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGN1cnJlbnQgbGluZSBjb3VudCBtYXRjaGVzIHRoZSBtYXhpbXVtIGxpbmUgY291bnRcbiAgICAgICAgaWYgKGlzSW50KGxpbmVDb3VudCkgJiYgbGluZXMgPT09IGxpbmVDb3VudCkge1xuICAgICAgICAgICAgaXNBdE1heExpbmVDb3VudCA9IHRydWU7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBJZiB0aGUgYmVzdCB3aWR0aCBleGNlZWRzIG1heFdpZHRoLCBhdHRlbXB0IHRvIGFkanVzdCBmb250IHNpemUgYW5kIGxpbmUgaGVpZ2h0XG4gICAgaWYgKCFpc0F0TWF4TGluZUNvdW50ICYmIG1heFdpZHRoICYmIGJlc3RXaWR0aCA+IG1heFdpZHRoKSB7XG4gICAgICAgIGlmIChyZWN1ckFkanVzdG1lbnQoKSkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vIEFwcGx5IHRoZSBiZXN0IHdpZHRoIHRvIHRoZSB0ZXh0IGNvbnRhaW5lclxuICAgIHRleHRDb250YWluZXIuc3R5bGUuc2V0UHJvcGVydHkoXCJ3aWR0aFwiLCBgJHtiZXN0V2lkdGh9cHhgLCBcImltcG9ydGFudFwiKTtcbn07XG5jb25zdCBnZXRTdmdDb2RlID0gKHN2Z0RvdEtleSwgc3ZnUGF0aEtleXMpID0+IHtcbiAgICBjb25zdCBzdmdEYXRhID0gZ2V0UHJvcGVydHkoU1ZHREFUQSwgc3ZnRG90S2V5KTtcbiAgICAvLyBlTG9nLmNoZWNrTG9nMyhcImNvbXBpbGVTdmdcIiwge3N2Z0RvdEtleSwgc3ZnUGF0aHMsIHN2Z0RhdGF9KTtcbiAgICBpZiAoIXN2Z0RhdGEpIHtcbiAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgfVxuICAgIGNvbnN0IHsgdmlld0JveCwgcGF0aHMsIGNsYXNzZXMgfSA9IHN2Z0RhdGE7XG4gICAgc3ZnUGF0aEtleXMgPz89IE9iamVjdC5rZXlzKHBhdGhzKS5qb2luKFwifFwiKTtcbiAgICBpZiAodHlwZW9mIHN2Z1BhdGhLZXlzID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHN2Z1BhdGhLZXlzID0gc3ZnUGF0aEtleXMuc3BsaXQoXCJ8XCIpO1xuICAgIH1cbiAgICByZXR1cm4gW1xuICAgICAgICBgPHN2ZyB2aWV3Qm94PVwiJHt2aWV3Qm94fVwiPmAsXG4gICAgICAgIC4uLnN2Z1BhdGhLZXlzXG4gICAgICAgICAgICAubWFwKChwYXRoKSA9PiBgPHBhdGggY2xhc3M9XCIke3BhdGh9ICR7Y2xhc3Nlcz8uW3BhdGhdID8/IFwiXCJ9XCIgZD1cIiR7cGF0aHNbcGF0aF0gPz8gXCJcIn1cIiAvPmApLFxuICAgICAgICBcIjwvc3ZnPlwiXG4gICAgXS5qb2luKFwiXFxuXCIpO1xufTtcbi8vICNyZWdpb24g4paR4paR4paR4paR4paR4paR4paRW1NWR13ilpHilpHilpHilpEgU1ZHIEdlbmVyYXRpb24gJiBNYW5pcHVsYXRpb24g4paR4paR4paR4paR4paR4paR4paRIH5cbmNvbnN0IGdldFJhd0NpcmNsZVBhdGggPSAociwgeyB4OiB4TywgeTogeU8gfSA9IHsgeDogMCwgeTogMCB9KSA9PiB7XG4gICAgW3IsIHhPLCB5T10gPSBbciwgeE8sIHlPXS5tYXAoKHZhbCkgPT4gcm91bmROdW0odmFsLCAyKSk7XG4gICAgY29uc3QgW2IxLCBiMl0gPSBbMC40NDc1ICogciwgKDEgLSAwLjQ0NzUpICogcl07XG4gICAgY29uc3QgW3hULCB5VF0gPSBbeE8sIHlPIC0gcl07XG4gICAgcmV0dXJuIFtbXG4gICAgICAgICAgICAuLi5beFQsIHlUXSxcbiAgICAgICAgICAgIC4uLltiMiwgMCwgciwgYjEsIHIsIHJdLFxuICAgICAgICAgICAgLi4uWzAsIGIyLCAtYjEsIHIsIC1yLCByXSxcbiAgICAgICAgICAgIC4uLlstYjIsIDAsIC1yLCAtYjEsIC1yLCAtcl0sXG4gICAgICAgICAgICAuLi5bMCwgLWIyLCBiMSwgLXIsIHIsIC1yXVxuICAgICAgICBdXTtcbn07XG5jb25zdCBkcmF3Q2lyY2xlUGF0aCA9IChyYWRpdXMsIG9yaWdpbikgPT4ge1xuICAgIGNvbnN0IFtbeFQsIHlULCAuLi5zZWdtZW50c11dID0gZ2V0UmF3Q2lyY2xlUGF0aChyYWRpdXMsIG9yaWdpbik7XG4gICAgY29uc3QgcGF0aCA9IFtgbSAke3hUfSAke3lUfWBdO1xuICAgIHNlZ21lbnRzLmZvckVhY2goKGNvb3JkLCBpKSA9PiB7XG4gICAgICAgIGlmIChpICUgNiA9PT0gMCkge1xuICAgICAgICAgICAgcGF0aC5wdXNoKFwiY1wiKTtcbiAgICAgICAgfVxuICAgICAgICBwYXRoLnB1c2goY29vcmQpO1xuICAgIH0pO1xuICAgIHBhdGgucHVzaChcInpcIik7XG4gICAgcmV0dXJuIHBhdGguam9pbihcIiBcIik7XG59O1xuLy8gI2VuZHJlZ2lvbiDilpHilpHilpHilpFbU1ZHXeKWkeKWkeKWkeKWkVxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbQ29sb3JzXeKWkeKWkeKWkeKWkSBDb2xvciBNYW5pcHVsYXRpb24g4paR4paR4paR4paR4paR4paR4paRIH5cbmNvbnN0IGdldENvbG9yVmFscyA9IChyZWQsIGdyZWVuLCBibHVlLCBhbHBoYSkgPT4ge1xuICAgIGlmIChpc1JHQkNvbG9yKHJlZCkpIHtcbiAgICAgICAgW3JlZCwgZ3JlZW4sIGJsdWUsIGFscGhhXSA9IHJlZFxuICAgICAgICAgICAgLnJlcGxhY2UoL1teXFxkLixdL2csIFwiXCIpXG4gICAgICAgICAgICAuc3BsaXQoLywvKVxuICAgICAgICAgICAgLm1hcCgoY29sb3IpID0+IChpc1VuZGVmaW5lZChjb2xvcikgPyB1bmRlZmluZWQgOiBwYXJzZUZsb2F0KGNvbG9yKSkpO1xuICAgIH1cbiAgICBpZiAoaXNIZXhDb2xvcihyZWQpKSB7XG4gICAgICAgIGlmIChbNCwgNV0uaW5jbHVkZXMocmVkLmxlbmd0aCkpIHtcbiAgICAgICAgICAgIHJlZCA9IHJlZC5yZXBsYWNlKC8oW14jXSkvZywgXCIkMSQxXCIpO1xuICAgICAgICB9XG4gICAgICAgIFtyZWQsIGdyZWVuLCBibHVlLCBhbHBoYV0gPSByZWRcbiAgICAgICAgICAgIC5tYXRjaCgvW14jXXsyfS9nKVxuICAgICAgICAgICAgPy5tYXAoKHZhbCkgPT4gcGFyc2VJbnQodmFsLCAxNikpID8/IFtdO1xuICAgIH1cbiAgICBpZiAoW3JlZCwgZ3JlZW4sIGJsdWVdLmV2ZXJ5KChjb2xvcikgPT4gL15cXGQrJC8udGVzdChgJHtjb2xvcn1gKSkpIHtcbiAgICAgICAgcmV0dXJuIFtyZWQsIGdyZWVuLCBibHVlLCBhbHBoYV1cbiAgICAgICAgICAgIC5maWx0ZXIoKGNvbG9yKSA9PiAvXltcXGQuXSskLy50ZXN0KGAke2NvbG9yfWApKTtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59O1xuY29uc3QgZ2V0UkdCU3RyaW5nID0gKHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhKSA9PiB7XG4gICAgaWYgKGlzUkdCQ29sb3IocmVkKSB8fCBpc0hleENvbG9yKHJlZCkpIHtcbiAgICAgICAgW3JlZCwgZ3JlZW4sIGJsdWUsIGFscGhhXSA9IGdldENvbG9yVmFscyhyZWQpID8/IFtdO1xuICAgIH1cbiAgICBpZiAoW3JlZCwgZ3JlZW4sIGJsdWVdLmV2ZXJ5KChjb2xvcikgPT4gL15bLlxcZF0rJC8udGVzdChgJHtjb2xvcn1gKSkpIHtcbiAgICAgICAgbGV0IGNvbG9yU3RyaW5nID0gXCJyZ2JcIjtcbiAgICAgICAgY29uc3QgY29sb3JzID0gW3JlZCwgZ3JlZW4sIGJsdWVdO1xuICAgICAgICBpZiAoL15bLlxcZF0rJC8udGVzdChgJHthbHBoYX1gKSkge1xuICAgICAgICAgICAgY29sb3JzLnB1c2goYWxwaGEgPj0gMSA/IHBJbnQoYWxwaGEpIDogcEZsb2F0KGFscGhhLCAyKSk7XG4gICAgICAgICAgICBjb2xvclN0cmluZyArPSBcImFcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYCR7Y29sb3JTdHJpbmd9KCR7Y29sb3JzLmpvaW4oXCIsIFwiKX0pYDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59O1xuY29uc3QgZ2V0SEVYU3RyaW5nID0gKHJlZCwgZ3JlZW4sIGJsdWUpID0+IHtcbiAgICBmdW5jdGlvbiBjb21wb25lbnRUb0hleChjKSB7XG4gICAgICAgIGNvbnN0IGhleCA9IGMudG9TdHJpbmcoMTYpO1xuICAgICAgICByZXR1cm4gaGV4Lmxlbmd0aCA9PT0gMSA/IGAwJHtoZXh9YCA6IGhleDtcbiAgICB9XG4gICAgaWYgKGlzSGV4Q29sb3IocmVkKSkge1xuICAgICAgICByZXR1cm4gcmVkO1xuICAgIH1cbiAgICBpZiAoaXNSR0JDb2xvcihyZWQpKSB7XG4gICAgICAgIFtyZWQsIGdyZWVuLCBibHVlXSA9IGdldENvbG9yVmFscyhyZWQpID8/IFtdO1xuICAgIH1cbiAgICBpZiAoaXNEZWZpbmVkKHJlZCkgJiYgaXNEZWZpbmVkKGdyZWVuKSAmJiBpc0RlZmluZWQoYmx1ZSkgJiYgW3JlZCwgZ3JlZW4sIGJsdWVdLmV2ZXJ5KChjb2xvcikgPT4gL15bLlxcZF0rJC8udGVzdChgJHtjb2xvcn1gKSkpIHtcbiAgICAgICAgcmV0dXJuIGAjJHtjb21wb25lbnRUb0hleChyZWQgPz8gMCl9JHtjb21wb25lbnRUb0hleChncmVlbiA/PyAwKX0ke2NvbXBvbmVudFRvSGV4KGJsdWUgPz8gMCl9YDtcbiAgICB9XG4gICAgcmV0dXJuIG51bGw7XG59O1xuY29uc3QgZ2V0Q29udHJhc3RpbmdDb2xvciA9ICguLi5jb2xvclZhbHMpID0+IHtcbiAgICBjb25zdCBbcmVkLCBncmVlbiwgYmx1ZV0gPSBnZXRDb2xvclZhbHMoLi4uY29sb3JWYWxzKSA/PyBbXTtcbiAgICBpZiAoW3JlZCwgZ3JlZW4sIGJsdWVdLmV2ZXJ5KGlzTnVtYmVyKSkge1xuICAgICAgICBjb25zdCBZSVEgPSAoKHJlZCAqIDI5OSkgKyAoZ3JlZW4gKiA1ODcpICsgKGJsdWUgKiAxMTQpKSAvIDEwMDA7XG4gICAgICAgIHJldHVybiAoWUlRID49IDEyOCkgPyBcInJnYmEoMCwgMCwgMCwgMSlcIiA6IFwicmdiYSgyNTUsIDI1NSwgMjU1LCAwLjgpXCI7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xufTtcbmNvbnN0IGdldFJhbmRvbUNvbG9yID0gKCkgPT4gZ2V0UkdCU3RyaW5nKGdzYXAudXRpbHMucmFuZG9tKDAsIDI1NSwgMSksIGdzYXAudXRpbHMucmFuZG9tKDAsIDI1NSwgMSksIGdzYXAudXRpbHMucmFuZG9tKDAsIDI1NSwgMSkpO1xuLy8gI2VuZHJlZ2lvbiDilpHilpHilpHilpFbQ29sb3JzXeKWkeKWkeKWkeKWkVxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbRE9NXeKWkeKWkeKWkeKWkSBET00gTWFuaXB1bGF0aW9uIOKWkeKWkeKWkeKWkeKWkeKWkeKWkSB+XG5jb25zdCBnZXRTaWJsaW5ncyA9IChlbGVtKSA9PiB7XG4gICAgY29uc3Qgc2libGluZ3MgPSBbXTtcbiAgICAvLyBJZiBubyBwYXJlbnQsIHJldHVybiBubyBzaWJsaW5nXG4gICAgaWYgKCFlbGVtLnBhcmVudE5vZGUpIHtcbiAgICAgICAgcmV0dXJuIHNpYmxpbmdzO1xuICAgIH1cbiAgICBBcnJheS5mcm9tKGVsZW0ucGFyZW50Tm9kZS5jaGlsZHJlbikuZm9yRWFjaCgoc2libGluZykgPT4ge1xuICAgICAgICBpZiAoc2libGluZyAhPT0gZWxlbSkge1xuICAgICAgICAgICAgc2libGluZ3MucHVzaChzaWJsaW5nKTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIHJldHVybiBzaWJsaW5ncztcbn07XG4vLyAjZW5kcmVnaW9uIOKWkeKWkeKWkeKWkVtET01d4paR4paR4paR4paRXG5jb25zdCBlc2NhcGVIVE1MID0gKHN0cikgPT4gKHR5cGVvZiBzdHIgPT09IFwic3RyaW5nXCJcbiAgICA/IHN0clxuICAgICAgICAucmVwbGFjZSgvJi9nLCBcIiZhbXA7XCIpXG4gICAgICAgIC5yZXBsYWNlKC88L2csIFwiJmx0O1wiKVxuICAgICAgICAucmVwbGFjZSgvPi9nLCBcIiZndDtcIilcbiAgICAgICAgLnJlcGxhY2UoL1wiL2csIFwiJnF1b3Q7XCIpXG4gICAgICAgIC5yZXBsYWNlKC9bYCddL2csIFwiJiMwMzk7XCIpXG4gICAgOiBzdHIpO1xuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggUEVSRk9STUFOQ0U6IFBlcmZvcm1hbmNlIFRlc3RpbmcgJiBNZXRyaWNzIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiFxuLyoqXG4gKiBUZXN0IHRoZSBwZXJmb3JtYW5jZSBvZiBhIGZ1bmN0aW9uIChzeW5jaHJvbm91cyBvciBhc3luY2hyb25vdXMpLlxuICogVGhlIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIHJlcGVhdGVkbHkgZm9yIDEwIHNlY29uZHMsIGFuZCB0aGUgdG90YWwgYW5kIGF2ZXJhZ2UgZXhlY3V0aW9uIHRpbWVzIHdpbGwgYmUgbG9nZ2VkLlxuICogQHBhcmFtIGZ1bmMgLSBUaGUgZnVuY3Rpb24gdG8gdGVzdC4gQ2FuIGJlIHN5bmNocm9ub3VzIG9yIGFzeW5jaHJvbm91cy5cbiAqIEBwYXJhbSBwYXJhbXMgLSBUaGUgcGFyYW1ldGVycyB0byBwYXNzIHRvIHRoZSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgdGVzdEZ1bmNQZXJmb3JtYW5jZSA9IChmdW5jLCAuLi5wYXJhbXMpID0+IHtcbiAgICBjb25zdCBzdGFydCA9IHBlcmZvcm1hbmNlLm5vdygpOyAvLyBTdGFydCB0aGUgdGltZXJcbiAgICBsZXQgdGFsbHkgPSAwOyAvLyBLZWVwIHRyYWNrIG9mIGhvdyBtYW55IHRpbWVzIHRoZSBmdW5jdGlvbiBpcyBjYWxsZWRcbiAgICAvLyBUaGlzIGZ1bmN0aW9uIHdpbGwgYmUgY2FsbGVkIGVhY2ggdGltZSAnZnVuYycgZmluaXNoZXMgZXhlY3V0aW5nXG4gICAgY29uc3QgaGFuZGxlUmVzdWx0ID0gKCkgPT4ge1xuICAgICAgICAvLyBDaGVjayBpZiAxMCBzZWNvbmRzIGhhdmUgcGFzc2VkXG4gICAgICAgIGlmIChwZXJmb3JtYW5jZS5ub3coKSAtIHN0YXJ0IDwgMTAwMDApIHtcbiAgICAgICAgICAgIHJ1bkZ1bmMoKTsgLy8gSWYgbm90LCBjYWxsICdmdW5jJyBhZ2FpblxuICAgICAgICAgICAgdGFsbHkrKzsgLy8gQW5kIGluY3JlbWVudCB0aGUgdGFsbHlcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIC8vIElmIDEwIHNlY29uZHMgaGF2ZSBwYXNzZWQsIGNhbGN1bGF0ZSB0aGUgdG90YWwgYW5kIGF2ZXJhZ2UgdGltZSBhbmQgbG9nIHRoZW1cbiAgICAgICAgICAgIGNvbnN0IGVsYXBzZWRUaW1lID0gcGVyZm9ybWFuY2Uubm93KCkgLSBzdGFydDtcbiAgICAgICAgICAgIGNvbnN0IHRpbWVQZXJDYWxsID0gcm91bmROdW0oZWxhcHNlZFRpbWUgLyB0YWxseSAvIDQwMDAsIDQpO1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJwZXJmb3JtYW5jZVwiLCBgW1Rlc3RQZXJmb3JtYW5jZV0gRnVuY3Rpb24gUmFuICR7dGFsbHl9IFRpbWVzIGluICR7cm91bmROdW0oZWxhcHNlZFRpbWUgLyAxMDAwLCA0KX1zLCBBdmVyYWdpbmcgJHt0aW1lUGVyQ2FsbH1zIHBlciBDYWxsYCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIC8vIFRoaXMgZnVuY3Rpb24gY2FsbHMgJ2Z1bmMnIGFuZCBoYW5kbGVzIGl0cyByZXN1bHQsIHdoZXRoZXIgaXQncyBhIFByb21pc2Ugb3Igbm90XG4gICAgY29uc3QgcnVuRnVuYyA9ICgpID0+IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gZnVuYyguLi5wYXJhbXMpOyAvLyBDYWxsICdmdW5jJyB3aXRoIHRoZSBwcm92aWRlZCBwYXJhbWV0ZXJzXG4gICAgICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBQcm9taXNlKSB7XG4gICAgICAgICAgICAvLyBJZiAnZnVuYycgaXMgYXN5bmNocm9ub3VzLCB3YWl0IGZvciB0aGUgUHJvbWlzZSB0byByZXNvbHZlIGJlZm9yZSBoYW5kbGluZyB0aGUgcmVzdWx0XG4gICAgICAgICAgICByZXN1bHQudGhlbihoYW5kbGVSZXN1bHQpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gSWYgJ2Z1bmMnIGlzIHN5bmNocm9ub3VzLCBoYW5kbGUgdGhlIHJlc3VsdCBpbW1lZGlhdGVseVxuICAgICAgICAgICAgaGFuZGxlUmVzdWx0KCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHJ1bkZ1bmMoKTsgLy8gU3RhcnQgdGhlIGZpcnN0IGNhbGwgdG8gJ2Z1bmMnXG59O1xuLy8gI2VuZHJlZ2lvblxuLy8gI3JlZ2lvbiDilpHilpHilpHilpHilpHilpHilpFbR3JlZW5Tb2NrXeKWkeKWkeKWkeKWkSBXcmFwcGVycyBmb3IgR3JlZW5Tb2NrIEZ1bmN0aW9ucyDilpHilpHilpHilpHilpHilpHilpEgflxuY29uc3Qgc2V0ID0gKHRhcmdldHMsIHZhcnMpID0+IGdzYXAuc2V0KHRhcmdldHMsIHZhcnMpO1xuLyoqXG4gKlxuICogQHBhcmFtIHRhcmdldFxuICogQHBhcmFtIHByb3BlcnR5XG4gKiBAcGFyYW0gdW5pdFxuICovXG5mdW5jdGlvbiBnZXQodGFyZ2V0LCBwcm9wZXJ0eSwgdW5pdCkge1xuICAgIGlmICh1bml0KSB7XG4gICAgICAgIGNvbnN0IHByb3BWYWwgPSByZWdFeHRyYWN0KGdzYXAuZ2V0UHJvcGVydHkodGFyZ2V0LCBwcm9wZXJ0eSwgdW5pdCksIC9bXFxkLl0rLyk7XG4gICAgICAgIGlmICh0eXBlb2YgcHJvcFZhbCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgcmV0dXJuIHBGbG9hdChwcm9wVmFsKTtcbiAgICAgICAgfVxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYFVuYWJsZSB0byBleHRyYWN0IHByb3BlcnR5ICcke3Byb3BlcnR5fScgaW4gJyR7dW5pdH0nIHVuaXRzIGZyb20gJHt0YXJnZXR9YCk7XG4gICAgfVxuICAgIHJldHVybiBnc2FwLmdldFByb3BlcnR5KHRhcmdldCwgcHJvcGVydHkpO1xufVxuY29uc3QgZ2V0R1NBbmdsZURlbHRhID0gKHN0YXJ0QW5nbGUsIGVuZEFuZ2xlKSA9PiBzaWduTnVtKHJvdW5kTnVtKGdldEFuZ2xlRGVsdGEoc3RhcnRBbmdsZSwgZW5kQW5nbGUpLCAyKSkucmVwbGFjZSgvXiguKS8sIFwiJDE9XCIpO1xuY29uc3QgZ2V0TmVhcmVzdExhYmVsID0gKHRsLCBtYXRjaFRlc3QpID0+IHtcbiAgICBpZiAoIXRsKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGlmICghb2JqU2l6ZSh0bC5sYWJlbHMpKSB7XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgbWF0Y2hUZXN0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIG1hdGNoVGVzdCA9IG5ldyBSZWdFeHAobWF0Y2hUZXN0KTtcbiAgICB9XG4gICAgLy8gRmlsdGVyIHRoZSBsYWJlbHMgYWdhaW5zdCB0aGUgbWF0Y2hUZXN0LCBpZiBvbmUgcHJvdmlkZWQsIGFuZCBzb3J0IGJ5IHRpbWUgaW4gYXNjZW5kaW5nIG9yZGVyLlxuICAgIGNvbnN0IGxhYmVsVGltZXMgPSBPYmplY3QuZW50cmllcyh0bC5sYWJlbHMpXG4gICAgICAgIC5maWx0ZXIoKFtsYWJlbF0pID0+IHtcbiAgICAgICAgcmV0dXJuIG1hdGNoVGVzdCBpbnN0YW5jZW9mIFJlZ0V4cFxuICAgICAgICAgICAgPyBtYXRjaFRlc3QudGVzdChsYWJlbClcbiAgICAgICAgICAgIDogdHJ1ZTtcbiAgICB9KVxuICAgICAgICAuc29ydCgoYSwgYikgPT4gYVsxXSAtIGJbMV0pO1xuICAgIC8vIFNuYXAgdGhlIGN1cnJlbnQgdGltZSBvZiB0aGUgdGltZWxpbmUgdG8gdGhlIHZhbHVlcyBpbiBsYWJlbFRpbWVzXG4gICAgY29uc3QgbmVhcmVzdFRpbWUgPSBnc2FwLnV0aWxzLnNuYXAobGFiZWxUaW1lcy5tYXAoKFtfbGFiZWwsIHRpbWVdKSA9PiB0aW1lKSwgdGwudGltZSgpKTtcbiAgICAvLyBHZXQgdGhlIGFzc29jaWF0ZWQgbGFiZWwgZm9yIHRoZSBuZWFyZXN0IHRpbWVcbiAgICBjb25zdCBbbmVhcmVzdExhYmVsXSA9IGxhYmVsVGltZXMuZmluZCgoW19sYWJlbCwgdGltZV0pID0+IHRpbWUgPT09IG5lYXJlc3RUaW1lKTtcbiAgICByZXR1cm4gbmVhcmVzdExhYmVsO1xufTtcbmNvbnN0IHJldmVyc2VSZXBlYXRpbmdUaW1lbGluZSA9ICh0bCkgPT4ge1xuICAgIC8vIEZJUlNUOiBEZXRlcm1pbmUgaWYgdGltZWxpbmUgaXRzZWxmIGlzIHJlcGVhdGluZywgb3IgaWYgbW9zdC1yZWNlbnQgY2hpbGQgdHdlZW4gb2YgdGltZWxpbmUgaXMgcmVwZWF0aW5nXG4gICAgaWYgKHRsLnJlcGVhdCgpID09PSAtMSkge1xuICAgICAgICAvLyBUaW1lbGluZSBpdHNlbGYgaXMgcmVwZWF0aW5nLiBTZXQgdG90YWxUaW1lIGVxdWFsIHRvIHRpbWUsIHJldmVyc2UuXG4gICAgICAgIHRsLnRvdGFsVGltZSh0bC50aW1lKCkpO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgICAgLy8gR2V0IGN1cnJlbnRseS1ydW5uaW5nIGNoaWxkIHR3ZWVuLCBjaGVjayBpZiB0aGF0IGlzIHJlcGVhdGluZy5cbiAgICAgICAgY29uc3QgW3R3XSA9IHRsLmdldENoaWxkcmVuKGZhbHNlLCB0cnVlLCB0cnVlLCB0bC50aW1lKCkpO1xuICAgICAgICBpZiAodHcgJiYgdHcucmVwZWF0KCkgPT09IC0xKSB7XG4gICAgICAgICAgICAvLyBDaGlsZCB0d2VlbiBpcyByZXBlYXRpbmcuIFNldCB0b3RhbFRpbWUgb2YgVFdFRU4gZXF1YWwgdG8gdGltZSwgcmV2ZXJzZSBUSU1FTElORS5cbiAgICAgICAgICAgIHR3LnRvdGFsVGltZSh0dy50aW1lKCkpO1xuICAgICAgICB9XG4gICAgICAgIHRsLnJldmVyc2UoKTtcbiAgICB9XG4gICAgcmV0dXJuIHRsO1xufTtcbi8vICNlbmRyZWdpb24g4paR4paR4paR4paRW0dyZWVuU29ja13ilpHilpHilpHilpFcbi8vICNlbmRyZWdpb24g4paE4paE4paE4paE4paEIEhUTUwg4paE4paE4paE4paE4paEXG4vLyAjcmVnaW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBBU1lOQzogQXN5bmMgRnVuY3Rpb25zLCBBc3luY2hyb25vdXMgRmxvdyBDb250cm9sIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCB+XG5jb25zdCBzbGVlcCA9IChkdXJhdGlvbikgPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICBzZXRUaW1lb3V0KHJlc29sdmUsIGR1cmF0aW9uID49IDEwMCA/IGR1cmF0aW9uIDogZHVyYXRpb24gKiAxMDAwKTtcbn0pO1xuZnVuY3Rpb24gd2FpdEZvcih3YWl0Rm9yVGFyZ2V0KSB7XG4gICAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgaWYgKHdhaXRGb3JUYXJnZXQgaW5zdGFuY2VvZiBQcm9taXNlXG4gICAgICAgICAgICB8fCB3YWl0Rm9yVGFyZ2V0IGluc3RhbmNlb2YgZ3NhcC5jb3JlLkFuaW1hdGlvbikge1xuICAgICAgICAgICAgd2FpdEZvclRhcmdldC50aGVuKCgpID0+IHJlc29sdmUoKSkuY2F0Y2gocmVqZWN0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChBcnJheS5pc0FycmF5KHdhaXRGb3JUYXJnZXQpKSB7XG4gICAgICAgICAgICBQcm9taXNlLmFsbCh3YWl0Rm9yVGFyZ2V0Lm1hcCgodGFyZ2V0KSA9PiB3YWl0Rm9yKHRhcmdldCkpKS50aGVuKCgpID0+IHJlc29sdmUoKSkuY2F0Y2gocmVqZWN0KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJlc29sdmUoKTtcbiAgICAgICAgfVxuICAgIH0pO1xufVxuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgQVNZTkMg4paE4paE4paE4paE4paEXG5jb25zdCBFdmVudEhhbmRsZXJzID0ge1xuICAgIG9uVGV4dElucHV0Qmx1cjogYXN5bmMgKGluc3QsIGV2ZW50KSA9PiB7XG4gICAgICAgIGNvbnN0IGVsZW0gPSBldmVudC50YXJnZXQ7XG4gICAgICAgIGNvbnN0IHsgYWN0aW9uLCB0YXJnZXQsIGZsYWdUYXJnZXQgfSA9IGVsZW0uZGF0YXNldDtcbiAgICAgICAgaWYgKCFhY3Rpb24pIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIklucHV0IHRleHQgZWxlbWVudHMgcmVxdWlyZSBhIGRhdGEtYWN0aW9uIGF0dHJpYnV0ZS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0YXJnZXQgJiYgIWZsYWdUYXJnZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIklucHV0IHRleHQgZWxlbWVudHMgcmVxdWlyZSBhICdkYXRhLXRhcmdldCcgb3IgJ2RhdGEtZmxhZy10YXJnZXQnIGF0dHJpYnV0ZS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRhcmdldCkge1xuICAgICAgICAgICAgYXdhaXQgaW5zdC5kb2N1bWVudC51cGRhdGUoeyBbdGFyZ2V0XTogZWxlbS52YWx1ZSB9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChmbGFnVGFyZ2V0KSB7XG4gICAgICAgICAgICBpZiAoZWxlbS52YWx1ZSA9PT0gXCJcIikge1xuICAgICAgICAgICAgICAgIGF3YWl0IGluc3QuZG9jdW1lbnQudW5zZXRGbGFnKEMuU1lTVEVNX0lELCBmbGFnVGFyZ2V0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIGF3YWl0IGluc3QuZG9jdW1lbnQuc2V0RmxhZyhDLlNZU1RFTV9JRCwgZmxhZ1RhcmdldCwgZWxlbS52YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIG9uU2VsZWN0Q2hhbmdlOiBhc3luYyAoaW5zdCwgZXZlbnQpID0+IHtcbiAgICAgICAgY29uc3QgZWxlbSA9IGV2ZW50LmN1cnJlbnRUYXJnZXQ7XG4gICAgICAgIGNvbnN0IHsgYWN0aW9uLCBkdHlwZSwgdGFyZ2V0LCBmbGFnVGFyZ2V0IH0gPSBlbGVtLmRhdGFzZXQ7XG4gICAgICAgIGlmICghYWN0aW9uKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJTZWxlY3QgZWxlbWVudHMgcmVxdWlyZSBhIGRhdGEtYWN0aW9uIGF0dHJpYnV0ZS5cIik7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0YXJnZXQgJiYgIWZsYWdUYXJnZXQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlNlbGVjdCBlbGVtZW50cyByZXF1aXJlIGEgJ2RhdGEtdGFyZ2V0JyBvciAnZGF0YS1mbGFnLXRhcmdldCcgYXR0cmlidXRlLlwiKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBkYXRhVHlwZSA9IGxDYXNlKGR0eXBlKTtcbiAgICAgICAgbGV0IHZhbHVlO1xuICAgICAgICBzd2l0Y2ggKGRhdGFUeXBlKSB7XG4gICAgICAgICAgICBjYXNlIFwibnVtYmVyXCI6XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBwRmxvYXQoZWxlbS52YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiYm9vbGVhblwiOlxuICAgICAgICAgICAgICAgIHZhbHVlID0gbENhc2UoYCR7ZWxlbS52YWx1ZX1gKSA9PT0gXCJ0cnVlXCI7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwic3RyaW5nXCI6XG4gICAgICAgICAgICAgICAgdmFsdWUgPSBgJHtlbGVtLnZhbHVlfWA7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OiB7XG4gICAgICAgICAgICAgICAgaWYgKGlzTnVtU3RyaW5nKHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJZb3UgbXVzdCBzZXQgJ2RhdGEtZHR5cGU9XFxcIk51bWJlclxcXCInIGZvciA8c2VsZWN0PiBlbGVtZW50cyB3aXRoIG51bWJlciB2YWx1ZXMuXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoaXNCb29sZWFuU3RyaW5nKHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJZb3UgbXVzdCBzZXQgJ2RhdGEtZHR5cGU9XFxcIkJvb2xlYW5cXFwiJyBmb3IgPHNlbGVjdD4gZWxlbWVudHMgd2l0aCBib29sZWFuIHZhbHVlcy5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHZhbHVlID0gYCR7ZWxlbS52YWx1ZX1gO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICh0YXJnZXQpIHtcbiAgICAgICAgICAgIGF3YWl0IGluc3QuZG9jdW1lbnQudXBkYXRlKHsgW3RhcmdldF06IHZhbHVlIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGZsYWdUYXJnZXQpIHtcbiAgICAgICAgICAgIGlmIChlbGVtLnZhbHVlID09PSBcIlwiKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgaW5zdC5kb2N1bWVudC51bnNldEZsYWcoQy5TWVNURU1fSUQsIGZsYWdUYXJnZXQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgaW5zdC5kb2N1bWVudC5zZXRGbGFnKEMuU1lTVEVNX0lELCBmbGFnVGFyZ2V0LCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG59O1xuLy8gI3JlZ2lvbiDilojilojilojilojilojilojilojiloggRk9VTkRSWTogUmVxdWlyZXMgQ29uZmlndXJhdGlvbiBvZiBTeXN0ZW0gSUQgaW4gY29uc3RhbnRzLnRzIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCB+XG5jb25zdCBpc0RvY0lEID0gKHJlZikgPT4ge1xuICAgIHJldHVybiB0eXBlb2YgcmVmID09PSBcInN0cmluZ1wiICYmIC9eW0EtWmEtejAtOV17MTZ9JC8udGVzdChyZWYpO1xufTtcbmNvbnN0IGlzRG9jVVVJRCA9IChyZWYpID0+IHtcbiAgICBpZiAodHlwZW9mIHJlZiAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNvbnN0IFtkb2NOYW1lLCBkb2NJRF0gPSByZWYuc3BsaXQoL1xcLi8pO1xuICAgIGlmICghaXNEb2NJRChkb2NJRCkpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gZ2FtZS5jb2xsZWN0aW9ucy5oYXMoZG9jTmFtZSk7XG59O1xuY29uc3QgaXNEb3RLZXkgPSAocmVmKSA9PiB7XG4gICAgcmV0dXJuIHR5cGVvZiByZWYgPT09IFwic3RyaW5nXCI7XG59O1xuY29uc3QgaXNUYXJnZXRLZXkgPSAocmVmKSA9PiB7XG4gICAgaWYgKCFpc0RvdEtleShyZWYpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKFtcIm5hbWVcIiwgXCJpbWdcIiwgXCJpZFwiLCBcIl9pZFwiXS5pbmNsdWRlcyhyZWYpKSB7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgICBpZiAocmVmLnN0YXJ0c1dpdGgoXCJzeXN0ZW1cIikpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChyZWYuc3RhcnRzV2l0aChcImZsYWdcIikpIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn07XG5jb25zdCBpc1RhcmdldEZsYWdLZXkgPSAocmVmKSA9PiB7XG4gICAgaWYgKCFpc0RvdEtleShyZWYpKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKGlzVGFyZ2V0S2V5KHJlZikpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbn07XG5jb25zdCBwYXJzZURvY1JlZlRvVVVJRCA9IChyZWYpID0+IHtcbiAgICBpZiAoaXNEb2NVVUlEKHJlZikpIHtcbiAgICAgICAgcmV0dXJuIHJlZjtcbiAgICB9XG4gICAgZWxzZSBpZiAoaXNEb2NJRChyZWYpKSB7XG4gICAgICAgIGNvbnN0IGRvYyA9IGdhbWUuY29sbGVjdGlvbnMuZmluZCgoY29sbGVjdGlvbikgPT4gY29sbGVjdGlvbi5oYXMocmVmKSk/LmdldChyZWYpO1xuICAgICAgICBpZiAoZG9jICYmIFwidXVpZFwiIGluIGRvYykge1xuICAgICAgICAgICAgcmV0dXJuIGRvYy51dWlkO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgW1UucGFyc2VEb2NSZWZUb1VVSURdIFVuYWJsZSB0byBmaW5kIGRvY3VtZW50IHdpdGggaWQgJyR7cmVmfSdgKTtcbiAgICB9XG4gICAgZWxzZSBpZiAocmVmICYmIHR5cGVvZiByZWYgPT09IFwib2JqZWN0XCIgJiYgXCJ1dWlkXCIgaW4gcmVmICYmIHR5cGVvZiByZWYudXVpZCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICByZXR1cm4gcmVmLnV1aWQ7XG4gICAgfVxuICAgIHRocm93IG5ldyBFcnJvcihgW1UucGFyc2VEb2NSZWZUb1VVSURdIFVucmVjb2duaXplZCByZWZlcmVuY2U6ICcke3JlZn0nYCk7XG59O1xuY29uc3QgbG9jID0gKGxvY1JlZiwgZm9ybWF0RGljdCA9IHt9KSA9PiB7XG4gICAgaWYgKC9bYS16XS8udGVzdChsb2NSZWYpKSB7IC8vIFJlZmVyZW5jZSBjb250YWlucyBsb3dlci1jYXNlIGNoYXJhY3RlcnM6IGFkZCBzeXN0ZW0gSUQgbmFtZXNwYWNpbmcgdG8gZG90IG5vdGF0aW9uXG4gICAgICAgIGxvY1JlZiA9IGxvY1JlZi5yZXBsYWNlKG5ldyBSZWdFeHAoYF4oJHtDLlNZU1RFTV9JRH0uKSpgKSwgYCR7Qy5TWVNURU1fSUR9LmApO1xuICAgIH1cbiAgICBpZiAodHlwZW9mIGdhbWUuaTE4bi5sb2NhbGl6ZShsb2NSZWYpID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIGZvciAoY29uc3QgW2tleSwgdmFsXSBvZiBPYmplY3QuZW50cmllcyhmb3JtYXREaWN0KSkge1xuICAgICAgICAgICAgZm9ybWF0RGljdFtrZXldID0gbG9jKHZhbCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGdhbWUuaTE4bi5mb3JtYXQobG9jUmVmLCBmb3JtYXREaWN0KSB8fCBnYW1lLmkxOG4ubG9jYWxpemUobG9jUmVmKSB8fCBsb2NSZWY7XG4gICAgfVxuICAgIHJldHVybiBsb2NSZWY7XG59O1xuY29uc3QgZ2V0U2V0dGluZyA9IChzZXR0aW5nKSA9PiB7XG4gICAgaWYgKGdhbWUuc2V0dGluZ3Muc2V0dGluZ3MuaGFzKGAke0MuU1lTVEVNX0lEfS4ke3NldHRpbmd9YCkpIHtcbiAgICAgICAgcmV0dXJuIGdhbWUuc2V0dGluZ3MuZ2V0KEMuU1lTVEVNX0lELCBzZXR0aW5nKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbn07XG4vKipcbiAqXG4gKiBAcGFyYW0gc3ViRm9sZGVyXG4gKiBAcGFyYW0gZmlsZU5hbWVcbiAqL1xuZnVuY3Rpb24gZ2V0VGVtcGxhdGVQYXRoKHN1YkZvbGRlciwgZmlsZU5hbWUpIHtcbiAgICBpZiAodHlwZW9mIGZpbGVOYW1lID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgIHJldHVybiBgJHtDLlRFTVBMQVRFX1JPT1R9LyR7c3ViRm9sZGVyfS8ke2ZpbGVOYW1lLnJlcGxhY2UoL1xcLi4qJC8sIFwiXCIpfS5oYnNgO1xuICAgIH1cbiAgICByZXR1cm4gZmlsZU5hbWUubWFwKChmTmFtZSkgPT4gZ2V0VGVtcGxhdGVQYXRoKHN1YkZvbGRlciwgZk5hbWUpKTtcbn1cbi8vIERpc3BsYXlJbWFnZVNlbGVjdG9yOiBEaXNwbGF5cyBhIGZpbGUgc2VsZWN0b3IgaW4gdGlsZXMgbW9kZSBhdCB0aGUgaW5kaWNhdGVkIHBhdGggcm9vdC5cbi8qKlxuICpcbiAqIEBwYXJhbSBjYWxsYmFja1xuICogQHBhcmFtIHBhdGhSb290XG4gKiBAcGFyYW0gcG9zaXRpb25cbiAqIEBwYXJhbSBwb3NpdGlvbi50b3BcbiAqIEBwYXJhbSBwb3NpdGlvbi5sZWZ0XG4gKi9cbmZ1bmN0aW9uIGRpc3BsYXlJbWFnZVNlbGVjdG9yKGNhbGxiYWNrLCBwYXRoUm9vdCA9IGBzeXN0ZW1zLyR7Qy5TWVNURU1fSUR9L2Fzc2V0c2AsIHBvc2l0aW9uID0geyB0b3A6IDIwMCwgbGVmdDogMjAwIH0pIHtcbiAgICBjb25zdCBmcCA9IG5ldyBGaWxlUGlja2VyKHtcbiAgICAgICAgdHlwZTogXCJpbWFnZVwiLFxuICAgICAgICBhY3RpdmVTb3VyY2U6IFwicHVibGljXCIsXG4gICAgICAgIGRpc3BsYXlNb2RlOiBcInRpbGVzXCIsXG4gICAgICAgIGNhbGxiYWNrLFxuICAgICAgICB0b3A6IHBvc2l0aW9uLnRvcCA/PyAyMDAgKyA0MCxcbiAgICAgICAgbGVmdDogcG9zaXRpb24ubGVmdCA/PyAyMDAgKyAxMFxuICAgIH0pO1xuICAgIHJldHVybiBmcC5icm93c2UocGF0aFJvb3QpO1xufVxuLy8gI2VuZHJlZ2lvbiDiloTiloTiloTiloTiloQgRk9VTkRSWSDiloTiloTiloTiloTiloRcbmV4cG9ydCBkZWZhdWx0IHtcbiAgICAvLyDilojilojilojilojilojilojilojiloggR0VUVEVSUzogQmFzaWMgRGF0YSBMb29rdXAgJiBSZXRyaWV2YWwg4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgR01JRCwgZ2V0VUlELFxuICAgIC8vIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBUWVBFUzogVHlwZSBDaGVja2luZywgVmFsaWRhdGlvbiwgQ29udmVyc2lvbiwgQ2FzdGluZyDilojilojilojilojilojilojilojilohcbiAgICBpc051bWJlciwgaXNOdW1TdHJpbmcsIGlzQm9vbGVhblN0cmluZywgaXNTaW1wbGVPYmosIGlzTGlzdCwgaXNBcnJheSwgaXNGdW5jLCBpc0ludCwgaXNGbG9hdCwgaXNQb3NJbnQsIGlzSXRlcmFibGUsXG4gICAgaXNIVE1MQ29kZSwgaXNSR0JDb2xvciwgaXNIZXhDb2xvcixcbiAgICBpc1VuZGVmaW5lZCwgaXNEZWZpbmVkLCBpc0VtcHR5LCBoYXNJdGVtcywgaXNJbnN0YW5jZSwgaXNOdWxsaXNoLFxuICAgIGFyZUVxdWFsLCBhcmVGdXp6eUVxdWFsLFxuICAgIHBGbG9hdCwgcEludCwgcEJvb2wsIHJhZFRvRGVnLCBkZWdUb1JhZCxcbiAgICBnZXRLZXksXG4gICAgYXNzZXJ0Tm9uTnVsbFR5cGUsXG4gICAgRklMVEVSUyxcbiAgICAvLyDilojilojilojilojilojilojilojiloggUkVHRVhQOiBSZWd1bGFyIEV4cHJlc3Npb25zLCBSZXBsYWNpbmcsIE1hdGNoaW5nIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiFxuICAgIHRlc3RSZWdFeHAsXG4gICAgcmVnRXh0cmFjdCxcbiAgICAvLyDilojilojilojilojilojilojilojiloggU1RSSU5HUzogU3RyaW5nIFBhcnNpbmcsIE1hbmlwdWxhdGlvbiwgQ29udmVyc2lvbiDilojilojilojilojilojilojilojilohcbiAgICAvLyDilpHilpHilpHilpHilpHilpHilpEgQ2FzZSBDb252ZXJzaW9uIOKWkeKWkeKWkeKWkeKWkeKWkeKWkVxuICAgIHVDYXNlLCBsQ2FzZSwgc0Nhc2UsIHRDYXNlLFxuICAgIC8vIOKWkeKWkeKWkeKWkeKWkeKWkeKWkSBGb3JtYXR0aW5nIOKWkeKWkeKWkeKWkeKWkeKWkeKWkVxuICAgIC8qIGh5cGhlbmF0ZSwgKi8gdW5oeXBoZW5hdGUsIHBsdXJhbGl6ZSwgb3hmb3JkaXplLCBlbGxpcHNpemUsIHBhZCxcbiAgICB0b0tleSxcbiAgICBwYXJzZUFydGljbGVzLFxuICAgIHNpZ25OdW0sIHBhZE51bSwgc3RyaW5naWZ5TnVtLCB2ZXJiYWxpemVOdW0sIG9yZGluYWxpemVOdW0sIHJvbWFuaXplTnVtLFxuICAgIC8vIOKWkeKWkeKWkeKWkeKWkeKWkeKWkSBDb250ZW50IOKWkeKWkeKWkeKWkeKWkeKWkeKWkVxuICAgIGxvcmVtSXBzdW0sIHJhbmRTdHJpbmcsIHJhbmRXb3JkLFxuICAgIC8vIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBTRUFSQ0hJTkc6IFNlYXJjaGluZyBWYXJpb3VzIERhdGEgVHlwZXMgdy8gRnV6enkgTWF0Y2hpbmcg4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgZnV6enlNYXRjaCwgaXNJbiwgaXNJbkV4YWN0LFxuICAgIC8vIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBOVU1CRVJTOiBOdW1iZXIgQ2FzdGluZywgTWF0aGVtYXRpY3MsIENvbnZlcnNpb24g4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgcmFuZE51bSwgcmFuZEludCxcbiAgICBjb2luRmxpcCxcbiAgICBjeWNsZU51bSwgY3ljbGVBbmdsZSwgcm91bmROdW0sIGNsYW1wTnVtLFxuICAgIHN1bSwgYXZlcmFnZSxcbiAgICAvLyDilpHilpHilpHilpHilpHilpHilpEgUG9zaXRpb25pbmcg4paR4paR4paR4paR4paR4paR4paRXG4gICAgZ2V0RGlzdGFuY2UsXG4gICAgZ2V0QW5nbGUsIGdldEFuZ2xlRGVsdGEsXG4gICAgZ2V0Qm91bmRpbmdSZWN0YW5nbGUsXG4gICAgLy8g4paI4paI4paI4paI4paI4paI4paI4paIIEFSUkFZUzogQXJyYXkgTWFuaXB1bGF0aW9uIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiFxuICAgIHJhbmRFbGVtLCByYW5kSW5kZXgsXG4gICAgbWFrZUludFJhbmdlLFxuICAgIG1ha2VDeWNsZXIsXG4gICAgdW5pcXVlLCBncm91cCwgc2FtcGxlLFxuICAgIGdldExhc3QsIHJlbW92ZUZpcnN0LCBwdWxsRWxlbWVudCwgcHVsbEluZGV4LFxuICAgIHN1Ykdyb3VwLCBzaHVmZmxlLFxuICAgIHRvQXJyYXksXG4gICAgLy8g4paI4paI4paI4paI4paI4paI4paI4paIIE9CSkVDVFM6IE1hbmlwdWxhdGlvbiBvZiBTaW1wbGUgS2V5L1ZhbCBPYmplY3RzIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiFxuICAgIHJlbW92ZSwgcmVwbGFjZSwgcGFydGl0aW9uLCB6aXAsXG4gICAgb2JqQ2xlYW4sIG9ialNpemUsIG9iak1hcCwgb2JqRmluZEtleSwgb2JqRmlsdGVyLCBvYmpGb3JFYWNoLCBvYmpDb21wYWN0LFxuICAgIG9iakNsb25lLCBvYmpNZXJnZSwgb2JqRGlmZiwgb2JqRXhwYW5kLCBvYmpGbGF0dGVuLCBvYmpOdWxsaWZ5LFxuICAgIG9iakZyZWV6ZVByb3BzLFxuICAgIC8vIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBGVU5DVElPTlM6IEZ1bmN0aW9uIFdyYXBwaW5nLCBRdWV1aW5nLCBNYW5pcHVsYXRpb24g4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgZ2V0RHluYW1pY0Z1bmMsIHdpdGhMb2csXG4gICAgLy8g4paI4paI4paI4paI4paI4paI4paI4paIIEhUTUw6IFBhcnNpbmcgSFRNTCBDb2RlLCBNYW5pcHVsYXRpbmcgRE9NIE9iamVjdHMg4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgZ2V0U3ZnQ29kZSxcbiAgICBjaGFuZ2VDb250YWluZXIsIGFkanVzdFRleHRDb250YWluZXJBc3BlY3RSYXRpbyxcbiAgICBnZXRSYXdDaXJjbGVQYXRoLCBkcmF3Q2lyY2xlUGF0aCxcbiAgICBnZXRDb2xvclZhbHMsIGdldFJHQlN0cmluZywgZ2V0SEVYU3RyaW5nLCBnZXRDb250cmFzdGluZ0NvbG9yLCBnZXRSYW5kb21Db2xvcixcbiAgICBnZXRTaWJsaW5ncyxcbiAgICBlc2NhcGVIVE1MLFxuICAgIC8vIOKWiOKWiOKWiOKWiOKWiOKWiOKWiOKWiCBQRVJGT1JNQU5DRTogUGVyZm9ybWFuY2UgVGVzdGluZyAmIE1ldHJpY3Mg4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgdGVzdEZ1bmNQZXJmb3JtYW5jZSxcbiAgICAvLyDilpHilpHilpHilpHilpHilpHilpEgR3JlZW5Tb2NrIOKWkeKWkeKWkeKWkeKWkeKWkeKWkVxuICAgIGdzYXAsIGdldCwgc2V0LCBnZXRHU0FuZ2xlRGVsdGEsIGdldE5lYXJlc3RMYWJlbCwgcmV2ZXJzZVJlcGVhdGluZ1RpbWVsaW5lLCAvKiB0bywgZnJvbSwgZnJvbVRvLCAqL1xuICAgIFRleHRQbHVnaW4sIEZsaXAsIE1vdGlvblBhdGhQbHVnaW4sXG4gICAgLy8g4paI4paI4paI4paI4paI4paI4paI4paIIEFTWU5DOiBBc3luYyBGdW5jdGlvbnMsIEFzeW5jaHJvbm91cyBGbG93IENvbnRyb2wg4paI4paI4paI4paI4paI4paI4paI4paIXG4gICAgc2xlZXAsIHdhaXRGb3IsXG4gICAgLy8gRVZFTlQgSEFORExFUlNcbiAgICBFdmVudEhhbmRsZXJzLFxuICAgIC8vIOKWkeKWkeKWkeKWkeKWkeKWkeKWkSBTWVNURU06IFN5c3RlbS1TcGVjaWZpYyBGdW5jdGlvbnMgKFJlcXVpcmVzIENvbmZpZ3VyYXRpb24gb2YgU3lzdGVtIElEIGluIGNvbnN0YW50cy5qcykg4paR4paR4paR4paR4paR4paR4paRXG4gICAgaXNEb2NJRCwgaXNEb2NVVUlELCBpc0RvdEtleSwgaXNUYXJnZXRLZXksIGlzVGFyZ2V0RmxhZ0tleSxcbiAgICBwYXJzZURvY1JlZlRvVVVJRCxcbiAgICBsb2MsIGdldFNldHRpbmcsIGdldFRlbXBsYXRlUGF0aCwgZGlzcGxheUltYWdlU2VsZWN0b3Jcbn07XG4vLyAjZW5kcmVnaW9uIOKWhOKWhOKWhOKWhOKWhCBFWFBPUlRTIOKWhOKWhOKWhOKWhOKWhFxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/core/utilities.ts\n"); + +/***/ }), + +/***/ "./ts/documents/BladesActiveEffect.ts": +/*!********************************************!*\ + !*** ./ts/documents/BladesActiveEffect.ts ***! + \********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n\n\n\nconst FUNCQUEUE = {};\n// {type: \"ability\", name: \"rX:/^(?!Ghost)/\"}\nconst CUSTOMFUNCS = {\n addItem: async (actor, funcData, _, isReversing = false) => {\n eLog.checkLog(\"activeEffects\", \"addItem\", { actor, funcData, isReversing });\n if (actor.hasActiveSubItemOf(funcData)) {\n if (isReversing) {\n return actor.remSubItem(funcData);\n }\n }\n else if (!isReversing) {\n return actor.addSubItem(funcData);\n }\n return undefined;\n },\n addIfChargen: async (actor, funcData, _, isReversing = false) => {\n eLog.checkLog(\"activeEffects\", \"addIfChargen\", { actor, funcData, isReversing });\n if (!isReversing && game.eunoblades.Tracker?.system.phase !== _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesPhase.CharGen) {\n return;\n }\n const [target, qty] = funcData.split(/:/);\n if (isReversing) {\n await actor.update({ [target]: _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(getProperty(actor, target)) - _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(qty) });\n return;\n }\n await actor.update({ [target]: _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(getProperty(actor, target)) + _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(qty) });\n },\n upgradeIfChargen: async (actor, funcData, _, isReversing = false) => {\n eLog.checkLog(\"activeEffects\", \"upgradeIfChargen\", { actor, funcData, isReversing });\n if (!isReversing && game.eunoblades.Tracker?.system.phase !== _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesPhase.CharGen) {\n return;\n }\n const [target, qty] = funcData.split(/:/);\n if (getProperty(actor, target) < _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(qty)) {\n await actor.update({ [target]: _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(qty) });\n }\n },\n APPLYTOMEMBERS: async () => undefined,\n APPLYTOCOHORTS: async () => undefined,\n remItem: async (actor, funcData, _, isReversing = false) => {\n function testString(targetString, testDef) {\n if (testDef.startsWith(\"rX\")) {\n const pat = new RegExp(testDef.replace(/^rX:\\/(.*?)\\//, \"$1\"));\n return pat.test(targetString);\n }\n return targetString === testDef;\n }\n if (funcData.startsWith(\"{\")) {\n if (isReversing) {\n console.error(\"Cannot reverse a 'remItem' custom effect that was defined with a JSON object.\");\n return undefined;\n }\n const { type, tags, name } = JSON.parse(funcData);\n let activeSubItems = actor.activeSubItems;\n if (activeSubItems.length === 0) {\n return undefined;\n }\n if (name) {\n activeSubItems = activeSubItems.filter((item) => testString(item.name, name));\n }\n if (activeSubItems.length === 0) {\n return undefined;\n }\n if (type) {\n activeSubItems = activeSubItems.filter((item) => testString(item.type, type));\n }\n if (activeSubItems.length === 0) {\n return undefined;\n }\n if (tags) {\n activeSubItems = activeSubItems.filter((item) => item.hasTag(...tags));\n }\n if (activeSubItems.length === 0) {\n return undefined;\n }\n eLog.checkLog(\"activeEffects\", \"remItem - JSON OBJECT\", { actor, funcData: JSON.parse(funcData), isReversing, activeSubItems });\n activeSubItems.forEach((item) => actor.remSubItem(item));\n }\n eLog.checkLog(\"activeEffects\", \"remItem\", { actor, funcData, isReversing });\n if (actor.hasActiveSubItemOf(funcData)) {\n return actor.remSubItem(funcData);\n }\n if (isReversing) {\n return actor.addSubItem(funcData);\n }\n return undefined;\n }\n};\nvar EffectMode;\n(function (EffectMode) {\n EffectMode[EffectMode[\"Custom\"] = 0] = \"Custom\";\n EffectMode[EffectMode[\"Multiply\"] = 1] = \"Multiply\";\n EffectMode[EffectMode[\"Add\"] = 2] = \"Add\";\n EffectMode[EffectMode[\"Downgrade\"] = 3] = \"Downgrade\";\n EffectMode[EffectMode[\"Upgrade\"] = 4] = \"Upgrade\";\n EffectMode[EffectMode[\"Override\"] = 5] = \"Override\";\n})(EffectMode || (EffectMode = {}));\nclass BladesActiveEffect extends ActiveEffect {\n static Initialize() {\n CONFIG.ActiveEffect.documentClass = BladesActiveEffect;\n Hooks.on(\"preCreateActiveEffect\", async (effect) => {\n eLog.checkLog3(\"effect\", \"PRECREATE ActiveEffect\", { effect, parent: effect.parent?.name });\n if (!(effect.parent instanceof _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\n return;\n }\n // Does this effect have an \"APPLYTOMEMBERS\" or \"APPLYTOCOHORTS\" CUSTOM effect?\n if (effect.changes.some((change) => change.key === \"APPLYTOMEMBERS\")) {\n if (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc)\n && _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent.crew, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew)) {\n const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id);\n if (otherMembers.length > 0) {\n // If PC & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key, leave PC's effect unchanged.\n effect.changes = effect.changes.filter((change) => change.key !== \"APPLYTOMEMBERS\");\n await Promise.all(otherMembers.map(async (member) => member.createEmbeddedDocuments(\"ActiveEffect\", [effect.toJSON()])));\n // Set flag with effect's data on member, so future members can have effect applied to them.\n await effect.parent.setFlag(\"eunos-blades\", `memberEffects.${effect.id}`, {\n appliedTo: otherMembers.map((member) => member.id),\n effect: effect.toJSON()\n });\n }\n }\n else if (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew)) {\n const changeKey = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pullElement(effect.changes, (change) => change.key === \"APPLYTOMEMBERS\");\n if (!changeKey) {\n return;\n }\n if (effect.parent.members.length > 0) {\n // If Crew & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key\n await Promise.all(effect.parent.members.map(async (member) => member.createEmbeddedDocuments(\"ActiveEffect\", [effect.toJSON()])));\n }\n // Set flag with effect's data on crew, so future members can have effect applied to them.\n await effect.parent.setFlag(\"eunos-blades\", `memberEffects.${effect.id}`, {\n appliedTo: effect.parent.members.map((member) => member.id),\n effect\n });\n // Update effect on crew-parent to only include 'APPLYTOMEMBERS' change\n await effect.updateSource({ changes: [changeKey] });\n }\n }\n else if (effect.changes.some((change) => change.key === \"APPLYTOCOHORTS\")\n && (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc)\n || _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew))) {\n if (effect.parent.cohorts.length > 0) {\n // If APPLYTOCOHORTS --> Create effect on cohorts\n await Promise.all(effect.parent.cohorts.map(async (cohort) => cohort.createEmbeddedDocuments(\"ActiveEffect\", [effect.toJSON()])));\n }\n // Set flag with effect's data on parent, so future cohorts can have effect applied to them.\n await effect.parent.setFlag(\"eunos-blades\", `cohortEffects.${effect.id}`, {\n appliedTo: effect.parent.cohorts.map((cohort) => cohort.id),\n effect\n });\n // Update effect on parent to only include 'APPLYTOCOHORTS' change\n await effect.updateSource({ changes: effect.changes.filter((change) => change.key === \"APPLYTOCOHORTS\") });\n }\n // Partition effect.changes into permanent and non-permanent changes:\n const [permChanges, changes] = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].partition(effect.changes, (change) => change.key.startsWith(\"perm\"));\n await effect.updateSource({ changes });\n for (const permChange of permChanges) {\n const { key, value } = permChange;\n const permFuncName = key.replace(/^perm/, \"\");\n if (permFuncName in CUSTOMFUNCS) {\n const funcData = {\n funcName: permFuncName,\n funcData: value,\n isReversing: false,\n effect\n };\n BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData);\n }\n else if (permFuncName === \"Add\") {\n const [target, qty] = value.split(/:/);\n effect.parent.update({ [target]: _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(getProperty(effect.parent, target)) + _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(qty) });\n }\n }\n });\n Hooks.on(\"applyActiveEffect\", (actor, changeData) => {\n if (!(actor instanceof _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\n return;\n }\n if (changeData.key in CUSTOMFUNCS) {\n const funcData = {\n funcName: changeData.key,\n funcData: changeData.value,\n isReversing: false,\n effect: changeData.effect\n };\n BladesActiveEffect.ThrottleCustomFunc(actor, funcData);\n }\n });\n Hooks.on(\"updateActiveEffect\", (effect, { disabled }) => {\n if (!(effect.parent instanceof _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\n return;\n }\n const customEffects = effect.changes.filter((changes) => changes.mode === 0);\n customEffects.forEach(({ key, value }) => {\n const funcData = {\n funcName: key,\n funcData: value,\n isReversing: disabled,\n effect\n };\n BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData);\n });\n });\n Hooks.on(\"deleteActiveEffect\", async (effect) => {\n if (!(effect.parent instanceof _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"])) {\n return;\n }\n // Does this effect have an \"APPLYTOMEMBERS\" or \"APPLYTOCOHORTS\" CUSTOM effect?\n if (effect.changes.some((change) => change.key === \"APPLYTOMEMBERS\")) {\n if (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc)\n && _BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent.crew, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew)) {\n const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id);\n if (otherMembers.length > 0) {\n // If PC & APPLYTOMEMBERS --> Delete effect on all other members.\n await Promise.all(otherMembers\n .map(async (member) => Promise.all(member.effects\n .filter((e) => e.name === effect.name)\n .map(async (e) => e.delete()))));\n }\n // Clear flag from parent\n await effect.parent.unsetFlag(\"eunos-blades\", `memberEffects.${effect.id}`);\n }\n else if (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew)) {\n if (effect.parent.members.length > 0) {\n // If CREW & APPLYTOMEMBERS --> Delete effect on all other members.\n await Promise.all(effect.parent.members\n .map(async (member) => Promise.all(member.effects\n .filter((e) => e.name === effect.name)\n .map(async (e) => e.delete()))));\n }\n // Clear flag from parent\n await effect.parent.unsetFlag(\"eunos-blades\", `memberEffects.${effect.id}`);\n }\n }\n else if (effect.changes.some((change) => change.key === \"APPLYTOCOHORTS\")\n && (_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(effect.parent, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew))) {\n if (effect.parent.cohorts.length > 0) {\n // If APPLYTOCOHORTS --> Delete effect on cohorts.\n await Promise.all(effect.parent.cohorts\n .map(async (cohort) => Promise.all(cohort.effects\n .filter((e) => e.name === effect.name)\n .map(async (e) => e.delete()))));\n }\n // Clear flag from parent\n await effect.parent.unsetFlag(\"eunos-blades\", `cohortEffects.${effect.id}`);\n }\n const customEffects = effect.changes.filter((changes) => changes.mode === 0);\n customEffects.forEach(({ key, value }) => {\n const funcData = {\n funcName: key,\n funcData: value,\n isReversing: true,\n effect\n };\n BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData);\n });\n });\n }\n static async AddActiveEffect(doc, name, eChanges, icon = \"systems/eunos-blades/assets/icons/effect-icons/default.png\") {\n const changes = [eChanges].flat();\n await doc.createEmbeddedDocuments(\"ActiveEffect\", [{ name, icon, changes }]);\n }\n static ThrottleCustomFunc(actor, data) {\n const { funcName, funcData, isReversing, effect } = data;\n if (!actor.id) {\n return;\n }\n eLog.checkLog3(\"activeEffect\", `Throttling Func: ${funcName}(${funcData}, ${isReversing})`);\n // Is there a currently-running function for this actor?\n if (actor.id && actor.id in FUNCQUEUE) {\n // Is this a duplicate of a function already queued?\n const matchingQueue = FUNCQUEUE[actor.id].queue\n .find((fData) => JSON.stringify(fData) === JSON.stringify(data));\n eLog.checkLog(\"activeEffects\", \"... Checking Queue\", { data, FUNCQUEUE: FUNCQUEUE[actor.id], matchingQueue });\n if (matchingQueue) {\n eLog.error(\"... Function ALREADY QUEUED, SKIPPING\");\n return;\n }\n FUNCQUEUE[actor.id].queue.push(data);\n return;\n }\n // If not, create FUNCQUEUE entry and run first function.\n eLog.checkLog3(\"activeEffect\", \"... Creating New FUNCQUEUE, RUNNING:\");\n FUNCQUEUE[actor.id] = {\n curFunc: BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing)),\n queue: []\n };\n }\n static async RunCustomFunc(actor, funcPromise) {\n if (!actor.id) {\n return;\n }\n eLog.checkLog(\"activeEffects\", \"... Running Func ...\");\n await funcPromise;\n eLog.checkLog(\"activeEffects\", \"... Function Complete!\");\n if (FUNCQUEUE[actor.id].queue.length) {\n const { funcName, funcData, isReversing, effect } = FUNCQUEUE[actor.id].queue.shift() ?? {};\n if (!funcName || !(funcName in CUSTOMFUNCS)) {\n return;\n }\n if (!funcData) {\n return;\n }\n eLog.checkLog3(\"activeEffect\", `Progressing Queue: ${funcName}(${funcData}, ${isReversing}) -- ${FUNCQUEUE[actor.id].queue.length} remaining funcs.`);\n FUNCQUEUE[actor.id].curFunc = BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing));\n }\n else {\n eLog.checkLog3(\"activeEffect\", \"Function Queue Complete! Deleting.\");\n delete FUNCQUEUE[actor.id];\n }\n }\n /**\n * Manage Active Effect instances through the Actor Sheet via effect control buttons.\n * @param {MouseEvent} event The left-click event on the effect control\n * @param {Actor|Item} owner The owning entity which manages this effect\n */\n static onManageActiveEffect(event, owner) {\n event.preventDefault();\n const a = event.currentTarget;\n if (a.dataset.action === \"create\") {\n return owner.createEmbeddedDocuments(\"ActiveEffect\", [{\n name: owner.name,\n icon: owner.img,\n origin: owner.uuid\n }]);\n }\n const selector = a.closest(\"tr\");\n if (selector === null) {\n return null;\n }\n const effect = selector.dataset.effectId\n ? owner.effects.get(selector.dataset.effectId)\n : null;\n if (!effect) {\n return null;\n }\n switch (a.dataset.action) {\n case \"edit\":\n return effect.sheet?.render(true);\n case \"delete\":\n eLog.checkLog(\"activeEffects\", \"delete effect\");\n return effect.delete();\n case \"toggle\":\n return effect.update({ disabled: !effect.disabled });\n default: return null;\n }\n }\n async _preCreate(data, options, user) {\n eLog.checkLog3(\"effect\", \"ActiveEffect._preCreate()\", { data, options, user });\n await super._preCreate(data, options, user);\n }\n _onDelete(options, userID) {\n eLog.checkLog3(\"effect\", \"ActiveEffect._onDelete()\", { options, userID });\n super._onDelete(options, userID);\n }\n get isSuppressed() {\n // Get source item from 'origin' field -- of form 'Actor..Item.'\n if (!/Actor.*Item/.test(this.origin)) {\n return super.isSuppressed;\n }\n const [actorID, itemID] = this.origin.replace(/Actor\\.|Item\\./g, \"\").split(\".\");\n const actor = game.actors.get(actorID);\n const item = actor.items.get(itemID);\n return super.isSuppressed || item?.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Tag.System.Archived);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesActiveEffect);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QUFZO0FBQzNCLGVBQWUsWUFBWTtBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUNBQXVDLDRCQUE0QjtBQUNuRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdFQUFnRSxxQkFBcUI7QUFDckY7QUFDQTtBQUNBO0FBQ0EsK0RBQStELGlCQUFpQjtBQUNoRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtEQUFrRCxnREFBRztBQUNyRDtBQUNBO0FBQ0EsK0RBQWUsa0JBQWtCLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9kb2N1bWVudHMvQmxhZGVzQWN0aXZlRWZmZWN0LnRzP2U5ZTkiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEJsYWRlc0FjdG9yIGZyb20gXCIuLi9CbGFkZXNBY3RvclwiO1xuaW1wb3J0IFUgZnJvbSBcIi4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBUYWcsIEJsYWRlc1BoYXNlLCBCbGFkZXNBY3RvclR5cGUgfSBmcm9tIFwiLi4vY29yZS9jb25zdGFudHNcIjtcbmNvbnN0IEZVTkNRVUVVRSA9IHt9O1xuLy8ge3R5cGU6IFwiYWJpbGl0eVwiLCBuYW1lOiBcInJYOi9eKD8hR2hvc3QpL1wifVxuY29uc3QgQ1VTVE9NRlVOQ1MgPSB7XG4gICAgYWRkSXRlbTogYXN5bmMgKGFjdG9yLCBmdW5jRGF0YSwgXywgaXNSZXZlcnNpbmcgPSBmYWxzZSkgPT4ge1xuICAgICAgICBlTG9nLmNoZWNrTG9nKFwiYWN0aXZlRWZmZWN0c1wiLCBcImFkZEl0ZW1cIiwgeyBhY3RvciwgZnVuY0RhdGEsIGlzUmV2ZXJzaW5nIH0pO1xuICAgICAgICBpZiAoYWN0b3IuaGFzQWN0aXZlU3ViSXRlbU9mKGZ1bmNEYXRhKSkge1xuICAgICAgICAgICAgaWYgKGlzUmV2ZXJzaW5nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjdG9yLnJlbVN1Ykl0ZW0oZnVuY0RhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCFpc1JldmVyc2luZykge1xuICAgICAgICAgICAgcmV0dXJuIGFjdG9yLmFkZFN1Ykl0ZW0oZnVuY0RhdGEpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfSxcbiAgICBhZGRJZkNoYXJnZW46IGFzeW5jIChhY3RvciwgZnVuY0RhdGEsIF8sIGlzUmV2ZXJzaW5nID0gZmFsc2UpID0+IHtcbiAgICAgICAgZUxvZy5jaGVja0xvZyhcImFjdGl2ZUVmZmVjdHNcIiwgXCJhZGRJZkNoYXJnZW5cIiwgeyBhY3RvciwgZnVuY0RhdGEsIGlzUmV2ZXJzaW5nIH0pO1xuICAgICAgICBpZiAoIWlzUmV2ZXJzaW5nICYmIGdhbWUuZXVub2JsYWRlcy5UcmFja2VyPy5zeXN0ZW0ucGhhc2UgIT09IEJsYWRlc1BoYXNlLkNoYXJHZW4pIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBbdGFyZ2V0LCBxdHldID0gZnVuY0RhdGEuc3BsaXQoLzovKTtcbiAgICAgICAgaWYgKGlzUmV2ZXJzaW5nKSB7XG4gICAgICAgICAgICBhd2FpdCBhY3Rvci51cGRhdGUoeyBbdGFyZ2V0XTogVS5wSW50KGdldFByb3BlcnR5KGFjdG9yLCB0YXJnZXQpKSAtIFUucEludChxdHkpIH0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IGFjdG9yLnVwZGF0ZSh7IFt0YXJnZXRdOiBVLnBJbnQoZ2V0UHJvcGVydHkoYWN0b3IsIHRhcmdldCkpICsgVS5wSW50KHF0eSkgfSk7XG4gICAgfSxcbiAgICB1cGdyYWRlSWZDaGFyZ2VuOiBhc3luYyAoYWN0b3IsIGZ1bmNEYXRhLCBfLCBpc1JldmVyc2luZyA9IGZhbHNlKSA9PiB7XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RpdmVFZmZlY3RzXCIsIFwidXBncmFkZUlmQ2hhcmdlblwiLCB7IGFjdG9yLCBmdW5jRGF0YSwgaXNSZXZlcnNpbmcgfSk7XG4gICAgICAgIGlmICghaXNSZXZlcnNpbmcgJiYgZ2FtZS5ldW5vYmxhZGVzLlRyYWNrZXI/LnN5c3RlbS5waGFzZSAhPT0gQmxhZGVzUGhhc2UuQ2hhckdlbikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IFt0YXJnZXQsIHF0eV0gPSBmdW5jRGF0YS5zcGxpdCgvOi8pO1xuICAgICAgICBpZiAoZ2V0UHJvcGVydHkoYWN0b3IsIHRhcmdldCkgPCBVLnBJbnQocXR5KSkge1xuICAgICAgICAgICAgYXdhaXQgYWN0b3IudXBkYXRlKHsgW3RhcmdldF06IFUucEludChxdHkpIH0pO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBBUFBMWVRPTUVNQkVSUzogYXN5bmMgKCkgPT4gdW5kZWZpbmVkLFxuICAgIEFQUExZVE9DT0hPUlRTOiBhc3luYyAoKSA9PiB1bmRlZmluZWQsXG4gICAgcmVtSXRlbTogYXN5bmMgKGFjdG9yLCBmdW5jRGF0YSwgXywgaXNSZXZlcnNpbmcgPSBmYWxzZSkgPT4ge1xuICAgICAgICBmdW5jdGlvbiB0ZXN0U3RyaW5nKHRhcmdldFN0cmluZywgdGVzdERlZikge1xuICAgICAgICAgICAgaWYgKHRlc3REZWYuc3RhcnRzV2l0aChcInJYXCIpKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgcGF0ID0gbmV3IFJlZ0V4cCh0ZXN0RGVmLnJlcGxhY2UoL15yWDpcXC8oLio/KVxcLy8sIFwiJDFcIikpO1xuICAgICAgICAgICAgICAgIHJldHVybiBwYXQudGVzdCh0YXJnZXRTdHJpbmcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRhcmdldFN0cmluZyA9PT0gdGVzdERlZjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoZnVuY0RhdGEuc3RhcnRzV2l0aChcIntcIikpIHtcbiAgICAgICAgICAgIGlmIChpc1JldmVyc2luZykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJDYW5ub3QgcmV2ZXJzZSBhICdyZW1JdGVtJyBjdXN0b20gZWZmZWN0IHRoYXQgd2FzIGRlZmluZWQgd2l0aCBhIEpTT04gb2JqZWN0LlwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgeyB0eXBlLCB0YWdzLCBuYW1lIH0gPSBKU09OLnBhcnNlKGZ1bmNEYXRhKTtcbiAgICAgICAgICAgIGxldCBhY3RpdmVTdWJJdGVtcyA9IGFjdG9yLmFjdGl2ZVN1Ykl0ZW1zO1xuICAgICAgICAgICAgaWYgKGFjdGl2ZVN1Ykl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobmFtZSkge1xuICAgICAgICAgICAgICAgIGFjdGl2ZVN1Ykl0ZW1zID0gYWN0aXZlU3ViSXRlbXMuZmlsdGVyKChpdGVtKSA9PiB0ZXN0U3RyaW5nKGl0ZW0ubmFtZSwgbmFtZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGFjdGl2ZVN1Ykl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodHlwZSkge1xuICAgICAgICAgICAgICAgIGFjdGl2ZVN1Ykl0ZW1zID0gYWN0aXZlU3ViSXRlbXMuZmlsdGVyKChpdGVtKSA9PiB0ZXN0U3RyaW5nKGl0ZW0udHlwZSwgdHlwZSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGFjdGl2ZVN1Ykl0ZW1zLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGFncykge1xuICAgICAgICAgICAgICAgIGFjdGl2ZVN1Ykl0ZW1zID0gYWN0aXZlU3ViSXRlbXMuZmlsdGVyKChpdGVtKSA9PiBpdGVtLmhhc1RhZyguLi50YWdzKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoYWN0aXZlU3ViSXRlbXMubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RpdmVFZmZlY3RzXCIsIFwicmVtSXRlbSAtIEpTT04gT0JKRUNUXCIsIHsgYWN0b3IsIGZ1bmNEYXRhOiBKU09OLnBhcnNlKGZ1bmNEYXRhKSwgaXNSZXZlcnNpbmcsIGFjdGl2ZVN1Ykl0ZW1zIH0pO1xuICAgICAgICAgICAgYWN0aXZlU3ViSXRlbXMuZm9yRWFjaCgoaXRlbSkgPT4gYWN0b3IucmVtU3ViSXRlbShpdGVtKSk7XG4gICAgICAgIH1cbiAgICAgICAgZUxvZy5jaGVja0xvZyhcImFjdGl2ZUVmZmVjdHNcIiwgXCJyZW1JdGVtXCIsIHsgYWN0b3IsIGZ1bmNEYXRhLCBpc1JldmVyc2luZyB9KTtcbiAgICAgICAgaWYgKGFjdG9yLmhhc0FjdGl2ZVN1Ykl0ZW1PZihmdW5jRGF0YSkpIHtcbiAgICAgICAgICAgIHJldHVybiBhY3Rvci5yZW1TdWJJdGVtKGZ1bmNEYXRhKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNSZXZlcnNpbmcpIHtcbiAgICAgICAgICAgIHJldHVybiBhY3Rvci5hZGRTdWJJdGVtKGZ1bmNEYXRhKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgIH1cbn07XG52YXIgRWZmZWN0TW9kZTtcbihmdW5jdGlvbiAoRWZmZWN0TW9kZSkge1xuICAgIEVmZmVjdE1vZGVbRWZmZWN0TW9kZVtcIkN1c3RvbVwiXSA9IDBdID0gXCJDdXN0b21cIjtcbiAgICBFZmZlY3RNb2RlW0VmZmVjdE1vZGVbXCJNdWx0aXBseVwiXSA9IDFdID0gXCJNdWx0aXBseVwiO1xuICAgIEVmZmVjdE1vZGVbRWZmZWN0TW9kZVtcIkFkZFwiXSA9IDJdID0gXCJBZGRcIjtcbiAgICBFZmZlY3RNb2RlW0VmZmVjdE1vZGVbXCJEb3duZ3JhZGVcIl0gPSAzXSA9IFwiRG93bmdyYWRlXCI7XG4gICAgRWZmZWN0TW9kZVtFZmZlY3RNb2RlW1wiVXBncmFkZVwiXSA9IDRdID0gXCJVcGdyYWRlXCI7XG4gICAgRWZmZWN0TW9kZVtFZmZlY3RNb2RlW1wiT3ZlcnJpZGVcIl0gPSA1XSA9IFwiT3ZlcnJpZGVcIjtcbn0pKEVmZmVjdE1vZGUgfHwgKEVmZmVjdE1vZGUgPSB7fSkpO1xuY2xhc3MgQmxhZGVzQWN0aXZlRWZmZWN0IGV4dGVuZHMgQWN0aXZlRWZmZWN0IHtcbiAgICBzdGF0aWMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgQ09ORklHLkFjdGl2ZUVmZmVjdC5kb2N1bWVudENsYXNzID0gQmxhZGVzQWN0aXZlRWZmZWN0O1xuICAgICAgICBIb29rcy5vbihcInByZUNyZWF0ZUFjdGl2ZUVmZmVjdFwiLCBhc3luYyAoZWZmZWN0KSA9PiB7XG4gICAgICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImVmZmVjdFwiLCBcIlBSRUNSRUFURSBBY3RpdmVFZmZlY3RcIiwgeyBlZmZlY3QsIHBhcmVudDogZWZmZWN0LnBhcmVudD8ubmFtZSB9KTtcbiAgICAgICAgICAgIGlmICghKGVmZmVjdC5wYXJlbnQgaW5zdGFuY2VvZiBCbGFkZXNBY3RvcikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBEb2VzIHRoaXMgZWZmZWN0IGhhdmUgYW4gXCJBUFBMWVRPTUVNQkVSU1wiIG9yIFwiQVBQTFlUT0NPSE9SVFNcIiBDVVNUT00gZWZmZWN0P1xuICAgICAgICAgICAgaWYgKGVmZmVjdC5jaGFuZ2VzLnNvbWUoKGNoYW5nZSkgPT4gY2hhbmdlLmtleSA9PT0gXCJBUFBMWVRPTUVNQkVSU1wiKSkge1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudCwgQmxhZGVzQWN0b3JUeXBlLnBjKVxuICAgICAgICAgICAgICAgICAgICAmJiBCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudC5jcmV3LCBCbGFkZXNBY3RvclR5cGUuY3JldykpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3Qgb3RoZXJNZW1iZXJzID0gZWZmZWN0LnBhcmVudC5jcmV3Lm1lbWJlcnMuZmlsdGVyKChtZW1iZXIpID0+IG1lbWJlci5pZCAhPT0gZWZmZWN0LnBhcmVudD8uaWQpO1xuICAgICAgICAgICAgICAgICAgICBpZiAob3RoZXJNZW1iZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIFBDICYgQVBQTFlUT01FTUJFUlMgICAtLT4gQ3JlYXRlIGVmZmVjdCBvbiBtZW1iZXJzIE1JTlVTIHRoZSAnQVBQTFlUT01FTUJFUlMnIGtleSwgbGVhdmUgUEMncyBlZmZlY3QgdW5jaGFuZ2VkLlxuICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0LmNoYW5nZXMgPSBlZmZlY3QuY2hhbmdlcy5maWx0ZXIoKGNoYW5nZSkgPT4gY2hhbmdlLmtleSAhPT0gXCJBUFBMWVRPTUVNQkVSU1wiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IFByb21pc2UuYWxsKG90aGVyTWVtYmVycy5tYXAoYXN5bmMgKG1lbWJlcikgPT4gbWVtYmVyLmNyZWF0ZUVtYmVkZGVkRG9jdW1lbnRzKFwiQWN0aXZlRWZmZWN0XCIsIFtlZmZlY3QudG9KU09OKCldKSkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU2V0IGZsYWcgd2l0aCBlZmZlY3QncyBkYXRhIG9uIG1lbWJlciwgc28gZnV0dXJlIG1lbWJlcnMgY2FuIGhhdmUgZWZmZWN0IGFwcGxpZWQgdG8gdGhlbS5cbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IGVmZmVjdC5wYXJlbnQuc2V0RmxhZyhcImV1bm9zLWJsYWRlc1wiLCBgbWVtYmVyRWZmZWN0cy4ke2VmZmVjdC5pZH1gLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXBwbGllZFRvOiBvdGhlck1lbWJlcnMubWFwKChtZW1iZXIpID0+IG1lbWJlci5pZCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0OiBlZmZlY3QudG9KU09OKClcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKEJsYWRlc0FjdG9yLklzVHlwZShlZmZlY3QucGFyZW50LCBCbGFkZXNBY3RvclR5cGUuY3JldykpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY2hhbmdlS2V5ID0gVS5wdWxsRWxlbWVudChlZmZlY3QuY2hhbmdlcywgKGNoYW5nZSkgPT4gY2hhbmdlLmtleSA9PT0gXCJBUFBMWVRPTUVNQkVSU1wiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFjaGFuZ2VLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoZWZmZWN0LnBhcmVudC5tZW1iZXJzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIElmIENyZXcgJiBBUFBMWVRPTUVNQkVSUyAtLT4gQ3JlYXRlIGVmZmVjdCBvbiBtZW1iZXJzIE1JTlVTIHRoZSAnQVBQTFlUT01FTUJFUlMnIGtleVxuICAgICAgICAgICAgICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoZWZmZWN0LnBhcmVudC5tZW1iZXJzLm1hcChhc3luYyAobWVtYmVyKSA9PiBtZW1iZXIuY3JlYXRlRW1iZWRkZWREb2N1bWVudHMoXCJBY3RpdmVFZmZlY3RcIiwgW2VmZmVjdC50b0pTT04oKV0pKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gU2V0IGZsYWcgd2l0aCBlZmZlY3QncyBkYXRhIG9uIGNyZXcsIHNvIGZ1dHVyZSBtZW1iZXJzIGNhbiBoYXZlIGVmZmVjdCBhcHBsaWVkIHRvIHRoZW0uXG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVmZmVjdC5wYXJlbnQuc2V0RmxhZyhcImV1bm9zLWJsYWRlc1wiLCBgbWVtYmVyRWZmZWN0cy4ke2VmZmVjdC5pZH1gLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcHBsaWVkVG86IGVmZmVjdC5wYXJlbnQubWVtYmVycy5tYXAoKG1lbWJlcikgPT4gbWVtYmVyLmlkKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGVmZmVjdFxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgLy8gVXBkYXRlIGVmZmVjdCBvbiBjcmV3LXBhcmVudCB0byBvbmx5IGluY2x1ZGUgJ0FQUExZVE9NRU1CRVJTJyBjaGFuZ2VcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgZWZmZWN0LnVwZGF0ZVNvdXJjZSh7IGNoYW5nZXM6IFtjaGFuZ2VLZXldIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKGVmZmVjdC5jaGFuZ2VzLnNvbWUoKGNoYW5nZSkgPT4gY2hhbmdlLmtleSA9PT0gXCJBUFBMWVRPQ09IT1JUU1wiKVxuICAgICAgICAgICAgICAgICYmIChCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudCwgQmxhZGVzQWN0b3JUeXBlLnBjKVxuICAgICAgICAgICAgICAgICAgICB8fCBCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudCwgQmxhZGVzQWN0b3JUeXBlLmNyZXcpKSkge1xuICAgICAgICAgICAgICAgIGlmIChlZmZlY3QucGFyZW50LmNvaG9ydHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiBBUFBMWVRPQ09IT1JUUyAgIC0tPiBDcmVhdGUgZWZmZWN0IG9uIGNvaG9ydHNcbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoZWZmZWN0LnBhcmVudC5jb2hvcnRzLm1hcChhc3luYyAoY29ob3J0KSA9PiBjb2hvcnQuY3JlYXRlRW1iZWRkZWREb2N1bWVudHMoXCJBY3RpdmVFZmZlY3RcIiwgW2VmZmVjdC50b0pTT04oKV0pKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIFNldCBmbGFnIHdpdGggZWZmZWN0J3MgZGF0YSBvbiBwYXJlbnQsIHNvIGZ1dHVyZSBjb2hvcnRzIGNhbiBoYXZlIGVmZmVjdCBhcHBsaWVkIHRvIHRoZW0uXG4gICAgICAgICAgICAgICAgYXdhaXQgZWZmZWN0LnBhcmVudC5zZXRGbGFnKFwiZXVub3MtYmxhZGVzXCIsIGBjb2hvcnRFZmZlY3RzLiR7ZWZmZWN0LmlkfWAsIHtcbiAgICAgICAgICAgICAgICAgICAgYXBwbGllZFRvOiBlZmZlY3QucGFyZW50LmNvaG9ydHMubWFwKChjb2hvcnQpID0+IGNvaG9ydC5pZCksXG4gICAgICAgICAgICAgICAgICAgIGVmZmVjdFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIC8vIFVwZGF0ZSBlZmZlY3Qgb24gcGFyZW50IHRvIG9ubHkgaW5jbHVkZSAnQVBQTFlUT0NPSE9SVFMnIGNoYW5nZVxuICAgICAgICAgICAgICAgIGF3YWl0IGVmZmVjdC51cGRhdGVTb3VyY2UoeyBjaGFuZ2VzOiBlZmZlY3QuY2hhbmdlcy5maWx0ZXIoKGNoYW5nZSkgPT4gY2hhbmdlLmtleSA9PT0gXCJBUFBMWVRPQ09IT1JUU1wiKSB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFBhcnRpdGlvbiBlZmZlY3QuY2hhbmdlcyBpbnRvIHBlcm1hbmVudCBhbmQgbm9uLXBlcm1hbmVudCBjaGFuZ2VzOlxuICAgICAgICAgICAgY29uc3QgW3Blcm1DaGFuZ2VzLCBjaGFuZ2VzXSA9IFUucGFydGl0aW9uKGVmZmVjdC5jaGFuZ2VzLCAoY2hhbmdlKSA9PiBjaGFuZ2Uua2V5LnN0YXJ0c1dpdGgoXCJwZXJtXCIpKTtcbiAgICAgICAgICAgIGF3YWl0IGVmZmVjdC51cGRhdGVTb3VyY2UoeyBjaGFuZ2VzIH0pO1xuICAgICAgICAgICAgZm9yIChjb25zdCBwZXJtQ2hhbmdlIG9mIHBlcm1DaGFuZ2VzKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgeyBrZXksIHZhbHVlIH0gPSBwZXJtQ2hhbmdlO1xuICAgICAgICAgICAgICAgIGNvbnN0IHBlcm1GdW5jTmFtZSA9IGtleS5yZXBsYWNlKC9ecGVybS8sIFwiXCIpO1xuICAgICAgICAgICAgICAgIGlmIChwZXJtRnVuY05hbWUgaW4gQ1VTVE9NRlVOQ1MpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZnVuY0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5jTmFtZTogcGVybUZ1bmNOYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY0RhdGE6IHZhbHVlLFxuICAgICAgICAgICAgICAgICAgICAgICAgaXNSZXZlcnNpbmc6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgICAgIEJsYWRlc0FjdGl2ZUVmZmVjdC5UaHJvdHRsZUN1c3RvbUZ1bmMoZWZmZWN0LnBhcmVudCwgZnVuY0RhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChwZXJtRnVuY05hbWUgPT09IFwiQWRkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgW3RhcmdldCwgcXR5XSA9IHZhbHVlLnNwbGl0KC86Lyk7XG4gICAgICAgICAgICAgICAgICAgIGVmZmVjdC5wYXJlbnQudXBkYXRlKHsgW3RhcmdldF06IFUucEludChnZXRQcm9wZXJ0eShlZmZlY3QucGFyZW50LCB0YXJnZXQpKSArIFUucEludChxdHkpIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIEhvb2tzLm9uKFwiYXBwbHlBY3RpdmVFZmZlY3RcIiwgKGFjdG9yLCBjaGFuZ2VEYXRhKSA9PiB7XG4gICAgICAgICAgICBpZiAoIShhY3RvciBpbnN0YW5jZW9mIEJsYWRlc0FjdG9yKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjaGFuZ2VEYXRhLmtleSBpbiBDVVNUT01GVU5DUykge1xuICAgICAgICAgICAgICAgIGNvbnN0IGZ1bmNEYXRhID0ge1xuICAgICAgICAgICAgICAgICAgICBmdW5jTmFtZTogY2hhbmdlRGF0YS5rZXksXG4gICAgICAgICAgICAgICAgICAgIGZ1bmNEYXRhOiBjaGFuZ2VEYXRhLnZhbHVlLFxuICAgICAgICAgICAgICAgICAgICBpc1JldmVyc2luZzogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGVmZmVjdDogY2hhbmdlRGF0YS5lZmZlY3RcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIEJsYWRlc0FjdGl2ZUVmZmVjdC5UaHJvdHRsZUN1c3RvbUZ1bmMoYWN0b3IsIGZ1bmNEYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIEhvb2tzLm9uKFwidXBkYXRlQWN0aXZlRWZmZWN0XCIsIChlZmZlY3QsIHsgZGlzYWJsZWQgfSkgPT4ge1xuICAgICAgICAgICAgaWYgKCEoZWZmZWN0LnBhcmVudCBpbnN0YW5jZW9mIEJsYWRlc0FjdG9yKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGN1c3RvbUVmZmVjdHMgPSBlZmZlY3QuY2hhbmdlcy5maWx0ZXIoKGNoYW5nZXMpID0+IGNoYW5nZXMubW9kZSA9PT0gMCk7XG4gICAgICAgICAgICBjdXN0b21FZmZlY3RzLmZvckVhY2goKHsga2V5LCB2YWx1ZSB9KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZnVuY0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmNOYW1lOiBrZXksXG4gICAgICAgICAgICAgICAgICAgIGZ1bmNEYXRhOiB2YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgaXNSZXZlcnNpbmc6IGRpc2FibGVkLFxuICAgICAgICAgICAgICAgICAgICBlZmZlY3RcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIEJsYWRlc0FjdGl2ZUVmZmVjdC5UaHJvdHRsZUN1c3RvbUZ1bmMoZWZmZWN0LnBhcmVudCwgZnVuY0RhdGEpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBIb29rcy5vbihcImRlbGV0ZUFjdGl2ZUVmZmVjdFwiLCBhc3luYyAoZWZmZWN0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIShlZmZlY3QucGFyZW50IGluc3RhbmNlb2YgQmxhZGVzQWN0b3IpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRG9lcyB0aGlzIGVmZmVjdCBoYXZlIGFuIFwiQVBQTFlUT01FTUJFUlNcIiBvciBcIkFQUExZVE9DT0hPUlRTXCIgQ1VTVE9NIGVmZmVjdD9cbiAgICAgICAgICAgIGlmIChlZmZlY3QuY2hhbmdlcy5zb21lKChjaGFuZ2UpID0+IGNoYW5nZS5rZXkgPT09IFwiQVBQTFlUT01FTUJFUlNcIikpIHtcbiAgICAgICAgICAgICAgICBpZiAoQmxhZGVzQWN0b3IuSXNUeXBlKGVmZmVjdC5wYXJlbnQsIEJsYWRlc0FjdG9yVHlwZS5wYylcbiAgICAgICAgICAgICAgICAgICAgJiYgQmxhZGVzQWN0b3IuSXNUeXBlKGVmZmVjdC5wYXJlbnQuY3JldywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IG90aGVyTWVtYmVycyA9IGVmZmVjdC5wYXJlbnQuY3Jldy5tZW1iZXJzLmZpbHRlcigobWVtYmVyKSA9PiBtZW1iZXIuaWQgIT09IGVmZmVjdC5wYXJlbnQ/LmlkKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG90aGVyTWVtYmVycy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBQQyAmIEFQUExZVE9NRU1CRVJTICAgLS0+IERlbGV0ZSBlZmZlY3Qgb24gYWxsIG90aGVyIG1lbWJlcnMuXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChvdGhlck1lbWJlcnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKGFzeW5jIChtZW1iZXIpID0+IFByb21pc2UuYWxsKG1lbWJlci5lZmZlY3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZSkgPT4gZS5uYW1lID09PSBlZmZlY3QubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKGFzeW5jIChlKSA9PiBlLmRlbGV0ZSgpKSkpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBDbGVhciBmbGFnIGZyb20gcGFyZW50XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVmZmVjdC5wYXJlbnQudW5zZXRGbGFnKFwiZXVub3MtYmxhZGVzXCIsIGBtZW1iZXJFZmZlY3RzLiR7ZWZmZWN0LmlkfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudCwgQmxhZGVzQWN0b3JUeXBlLmNyZXcpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlZmZlY3QucGFyZW50Lm1lbWJlcnMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gSWYgQ1JFVyAmIEFQUExZVE9NRU1CRVJTICAgLS0+IERlbGV0ZSBlZmZlY3Qgb24gYWxsIG90aGVyIG1lbWJlcnMuXG4gICAgICAgICAgICAgICAgICAgICAgICBhd2FpdCBQcm9taXNlLmFsbChlZmZlY3QucGFyZW50Lm1lbWJlcnNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKGFzeW5jIChtZW1iZXIpID0+IFByb21pc2UuYWxsKG1lbWJlci5lZmZlY3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZSkgPT4gZS5uYW1lID09PSBlZmZlY3QubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKGFzeW5jIChlKSA9PiBlLmRlbGV0ZSgpKSkpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBDbGVhciBmbGFnIGZyb20gcGFyZW50XG4gICAgICAgICAgICAgICAgICAgIGF3YWl0IGVmZmVjdC5wYXJlbnQudW5zZXRGbGFnKFwiZXVub3MtYmxhZGVzXCIsIGBtZW1iZXJFZmZlY3RzLiR7ZWZmZWN0LmlkfWApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKGVmZmVjdC5jaGFuZ2VzLnNvbWUoKGNoYW5nZSkgPT4gY2hhbmdlLmtleSA9PT0gXCJBUFBMWVRPQ09IT1JUU1wiKVxuICAgICAgICAgICAgICAgICYmIChCbGFkZXNBY3Rvci5Jc1R5cGUoZWZmZWN0LnBhcmVudCwgQmxhZGVzQWN0b3JUeXBlLnBjLCBCbGFkZXNBY3RvclR5cGUuY3JldykpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVmZmVjdC5wYXJlbnQuY29ob3J0cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIEFQUExZVE9DT0hPUlRTICAgLS0+IERlbGV0ZSBlZmZlY3Qgb24gY29ob3J0cy5cbiAgICAgICAgICAgICAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoZWZmZWN0LnBhcmVudC5jb2hvcnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAubWFwKGFzeW5jIChjb2hvcnQpID0+IFByb21pc2UuYWxsKGNvaG9ydC5lZmZlY3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChlKSA9PiBlLm5hbWUgPT09IGVmZmVjdC5uYW1lKVxuICAgICAgICAgICAgICAgICAgICAgICAgLm1hcChhc3luYyAoZSkgPT4gZS5kZWxldGUoKSkpKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIENsZWFyIGZsYWcgZnJvbSBwYXJlbnRcbiAgICAgICAgICAgICAgICBhd2FpdCBlZmZlY3QucGFyZW50LnVuc2V0RmxhZyhcImV1bm9zLWJsYWRlc1wiLCBgY29ob3J0RWZmZWN0cy4ke2VmZmVjdC5pZH1gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGN1c3RvbUVmZmVjdHMgPSBlZmZlY3QuY2hhbmdlcy5maWx0ZXIoKGNoYW5nZXMpID0+IGNoYW5nZXMubW9kZSA9PT0gMCk7XG4gICAgICAgICAgICBjdXN0b21FZmZlY3RzLmZvckVhY2goKHsga2V5LCB2YWx1ZSB9KSA9PiB7XG4gICAgICAgICAgICAgICAgY29uc3QgZnVuY0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgICAgIGZ1bmNOYW1lOiBrZXksXG4gICAgICAgICAgICAgICAgICAgIGZ1bmNEYXRhOiB2YWx1ZSxcbiAgICAgICAgICAgICAgICAgICAgaXNSZXZlcnNpbmc6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGVmZmVjdFxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgQmxhZGVzQWN0aXZlRWZmZWN0LlRocm90dGxlQ3VzdG9tRnVuYyhlZmZlY3QucGFyZW50LCBmdW5jRGF0YSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN0YXRpYyBhc3luYyBBZGRBY3RpdmVFZmZlY3QoZG9jLCBuYW1lLCBlQ2hhbmdlcywgaWNvbiA9IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2ljb25zL2VmZmVjdC1pY29ucy9kZWZhdWx0LnBuZ1wiKSB7XG4gICAgICAgIGNvbnN0IGNoYW5nZXMgPSBbZUNoYW5nZXNdLmZsYXQoKTtcbiAgICAgICAgYXdhaXQgZG9jLmNyZWF0ZUVtYmVkZGVkRG9jdW1lbnRzKFwiQWN0aXZlRWZmZWN0XCIsIFt7IG5hbWUsIGljb24sIGNoYW5nZXMgfV0pO1xuICAgIH1cbiAgICBzdGF0aWMgVGhyb3R0bGVDdXN0b21GdW5jKGFjdG9yLCBkYXRhKSB7XG4gICAgICAgIGNvbnN0IHsgZnVuY05hbWUsIGZ1bmNEYXRhLCBpc1JldmVyc2luZywgZWZmZWN0IH0gPSBkYXRhO1xuICAgICAgICBpZiAoIWFjdG9yLmlkKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJhY3RpdmVFZmZlY3RcIiwgYFRocm90dGxpbmcgRnVuYzogJHtmdW5jTmFtZX0oJHtmdW5jRGF0YX0sICR7aXNSZXZlcnNpbmd9KWApO1xuICAgICAgICAvLyBJcyB0aGVyZSBhIGN1cnJlbnRseS1ydW5uaW5nIGZ1bmN0aW9uIGZvciB0aGlzIGFjdG9yP1xuICAgICAgICBpZiAoYWN0b3IuaWQgJiYgYWN0b3IuaWQgaW4gRlVOQ1FVRVVFKSB7XG4gICAgICAgICAgICAvLyBJcyB0aGlzIGEgZHVwbGljYXRlIG9mIGEgZnVuY3Rpb24gYWxyZWFkeSBxdWV1ZWQ/XG4gICAgICAgICAgICBjb25zdCBtYXRjaGluZ1F1ZXVlID0gRlVOQ1FVRVVFW2FjdG9yLmlkXS5xdWV1ZVxuICAgICAgICAgICAgICAgIC5maW5kKChmRGF0YSkgPT4gSlNPTi5zdHJpbmdpZnkoZkRhdGEpID09PSBKU09OLnN0cmluZ2lmeShkYXRhKSk7XG4gICAgICAgICAgICBlTG9nLmNoZWNrTG9nKFwiYWN0aXZlRWZmZWN0c1wiLCBcIi4uLiBDaGVja2luZyBRdWV1ZVwiLCB7IGRhdGEsIEZVTkNRVUVVRTogRlVOQ1FVRVVFW2FjdG9yLmlkXSwgbWF0Y2hpbmdRdWV1ZSB9KTtcbiAgICAgICAgICAgIGlmIChtYXRjaGluZ1F1ZXVlKSB7XG4gICAgICAgICAgICAgICAgZUxvZy5lcnJvcihcIi4uLiBGdW5jdGlvbiBBTFJFQURZIFFVRVVFRCwgU0tJUFBJTkdcIik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgRlVOQ1FVRVVFW2FjdG9yLmlkXS5xdWV1ZS5wdXNoKGRhdGEpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIElmIG5vdCwgY3JlYXRlIEZVTkNRVUVVRSBlbnRyeSBhbmQgcnVuIGZpcnN0IGZ1bmN0aW9uLlxuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImFjdGl2ZUVmZmVjdFwiLCBcIi4uLiBDcmVhdGluZyBOZXcgRlVOQ1FVRVVFLCBSVU5OSU5HOlwiKTtcbiAgICAgICAgRlVOQ1FVRVVFW2FjdG9yLmlkXSA9IHtcbiAgICAgICAgICAgIGN1ckZ1bmM6IEJsYWRlc0FjdGl2ZUVmZmVjdC5SdW5DdXN0b21GdW5jKGFjdG9yLCBDVVNUT01GVU5DU1tmdW5jTmFtZV0oYWN0b3IsIGZ1bmNEYXRhLCBlZmZlY3QsIGlzUmV2ZXJzaW5nKSksXG4gICAgICAgICAgICBxdWV1ZTogW11cbiAgICAgICAgfTtcbiAgICB9XG4gICAgc3RhdGljIGFzeW5jIFJ1bkN1c3RvbUZ1bmMoYWN0b3IsIGZ1bmNQcm9taXNlKSB7XG4gICAgICAgIGlmICghYWN0b3IuaWQpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBlTG9nLmNoZWNrTG9nKFwiYWN0aXZlRWZmZWN0c1wiLCBcIi4uLiBSdW5uaW5nIEZ1bmMgLi4uXCIpO1xuICAgICAgICBhd2FpdCBmdW5jUHJvbWlzZTtcbiAgICAgICAgZUxvZy5jaGVja0xvZyhcImFjdGl2ZUVmZmVjdHNcIiwgXCIuLi4gRnVuY3Rpb24gQ29tcGxldGUhXCIpO1xuICAgICAgICBpZiAoRlVOQ1FVRVVFW2FjdG9yLmlkXS5xdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgICAgIGNvbnN0IHsgZnVuY05hbWUsIGZ1bmNEYXRhLCBpc1JldmVyc2luZywgZWZmZWN0IH0gPSBGVU5DUVVFVUVbYWN0b3IuaWRdLnF1ZXVlLnNoaWZ0KCkgPz8ge307XG4gICAgICAgICAgICBpZiAoIWZ1bmNOYW1lIHx8ICEoZnVuY05hbWUgaW4gQ1VTVE9NRlVOQ1MpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFmdW5jRGF0YSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVMb2cuY2hlY2tMb2czKFwiYWN0aXZlRWZmZWN0XCIsIGBQcm9ncmVzc2luZyBRdWV1ZTogJHtmdW5jTmFtZX0oJHtmdW5jRGF0YX0sICR7aXNSZXZlcnNpbmd9KSAtLSAke0ZVTkNRVUVVRVthY3Rvci5pZF0ucXVldWUubGVuZ3RofSByZW1haW5pbmcgZnVuY3MuYCk7XG4gICAgICAgICAgICBGVU5DUVVFVUVbYWN0b3IuaWRdLmN1ckZ1bmMgPSBCbGFkZXNBY3RpdmVFZmZlY3QuUnVuQ3VzdG9tRnVuYyhhY3RvciwgQ1VTVE9NRlVOQ1NbZnVuY05hbWVdKGFjdG9yLCBmdW5jRGF0YSwgZWZmZWN0LCBpc1JldmVyc2luZykpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJhY3RpdmVFZmZlY3RcIiwgXCJGdW5jdGlvbiBRdWV1ZSBDb21wbGV0ZSEgRGVsZXRpbmcuXCIpO1xuICAgICAgICAgICAgZGVsZXRlIEZVTkNRVUVVRVthY3Rvci5pZF07XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogTWFuYWdlIEFjdGl2ZSBFZmZlY3QgaW5zdGFuY2VzIHRocm91Z2ggdGhlIEFjdG9yIFNoZWV0IHZpYSBlZmZlY3QgY29udHJvbCBidXR0b25zLlxuICAgICAqIEBwYXJhbSB7TW91c2VFdmVudH0gZXZlbnQgICAgICBUaGUgbGVmdC1jbGljayBldmVudCBvbiB0aGUgZWZmZWN0IGNvbnRyb2xcbiAgICAgKiBAcGFyYW0ge0FjdG9yfEl0ZW19IG93bmVyICAgICAgVGhlIG93bmluZyBlbnRpdHkgd2hpY2ggbWFuYWdlcyB0aGlzIGVmZmVjdFxuICAgICAqL1xuICAgIHN0YXRpYyBvbk1hbmFnZUFjdGl2ZUVmZmVjdChldmVudCwgb3duZXIpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgYSA9IGV2ZW50LmN1cnJlbnRUYXJnZXQ7XG4gICAgICAgIGlmIChhLmRhdGFzZXQuYWN0aW9uID09PSBcImNyZWF0ZVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gb3duZXIuY3JlYXRlRW1iZWRkZWREb2N1bWVudHMoXCJBY3RpdmVFZmZlY3RcIiwgW3tcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogb3duZXIubmFtZSxcbiAgICAgICAgICAgICAgICAgICAgaWNvbjogb3duZXIuaW1nLFxuICAgICAgICAgICAgICAgICAgICBvcmlnaW46IG93bmVyLnV1aWRcbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3Qgc2VsZWN0b3IgPSBhLmNsb3Nlc3QoXCJ0clwiKTtcbiAgICAgICAgaWYgKHNlbGVjdG9yID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBlZmZlY3QgPSBzZWxlY3Rvci5kYXRhc2V0LmVmZmVjdElkXG4gICAgICAgICAgICA/IG93bmVyLmVmZmVjdHMuZ2V0KHNlbGVjdG9yLmRhdGFzZXQuZWZmZWN0SWQpXG4gICAgICAgICAgICA6IG51bGw7XG4gICAgICAgIGlmICghZWZmZWN0KSB7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBzd2l0Y2ggKGEuZGF0YXNldC5hY3Rpb24pIHtcbiAgICAgICAgICAgIGNhc2UgXCJlZGl0XCI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGVmZmVjdC5zaGVldD8ucmVuZGVyKHRydWUpO1xuICAgICAgICAgICAgY2FzZSBcImRlbGV0ZVwiOlxuICAgICAgICAgICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RpdmVFZmZlY3RzXCIsIFwiZGVsZXRlIGVmZmVjdFwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gZWZmZWN0LmRlbGV0ZSgpO1xuICAgICAgICAgICAgY2FzZSBcInRvZ2dsZVwiOlxuICAgICAgICAgICAgICAgIHJldHVybiBlZmZlY3QudXBkYXRlKHsgZGlzYWJsZWQ6ICFlZmZlY3QuZGlzYWJsZWQgfSk7XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBfcHJlQ3JlYXRlKGRhdGEsIG9wdGlvbnMsIHVzZXIpIHtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJlZmZlY3RcIiwgXCJBY3RpdmVFZmZlY3QuX3ByZUNyZWF0ZSgpXCIsIHsgZGF0YSwgb3B0aW9ucywgdXNlciB9KTtcbiAgICAgICAgYXdhaXQgc3VwZXIuX3ByZUNyZWF0ZShkYXRhLCBvcHRpb25zLCB1c2VyKTtcbiAgICB9XG4gICAgX29uRGVsZXRlKG9wdGlvbnMsIHVzZXJJRCkge1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcImVmZmVjdFwiLCBcIkFjdGl2ZUVmZmVjdC5fb25EZWxldGUoKVwiLCB7IG9wdGlvbnMsIHVzZXJJRCB9KTtcbiAgICAgICAgc3VwZXIuX29uRGVsZXRlKG9wdGlvbnMsIHVzZXJJRCk7XG4gICAgfVxuICAgIGdldCBpc1N1cHByZXNzZWQoKSB7XG4gICAgICAgIC8vIEdldCBzb3VyY2UgaXRlbSBmcm9tICdvcmlnaW4nIGZpZWxkIC0tIG9mIGZvcm0gJ0FjdG9yLjxpZD4uSXRlbS48aWQ+J1xuICAgICAgICBpZiAoIS9BY3Rvci4qSXRlbS8udGVzdCh0aGlzLm9yaWdpbikpIHtcbiAgICAgICAgICAgIHJldHVybiBzdXBlci5pc1N1cHByZXNzZWQ7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgW2FjdG9ySUQsIGl0ZW1JRF0gPSB0aGlzLm9yaWdpbi5yZXBsYWNlKC9BY3RvclxcLnxJdGVtXFwuL2csIFwiXCIpLnNwbGl0KFwiLlwiKTtcbiAgICAgICAgY29uc3QgYWN0b3IgPSBnYW1lLmFjdG9ycy5nZXQoYWN0b3JJRCk7XG4gICAgICAgIGNvbnN0IGl0ZW0gPSBhY3Rvci5pdGVtcy5nZXQoaXRlbUlEKTtcbiAgICAgICAgcmV0dXJuIHN1cGVyLmlzU3VwcHJlc3NlZCB8fCBpdGVtPy5oYXNUYWcoVGFnLlN5c3RlbS5BcmNoaXZlZCk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQWN0aXZlRWZmZWN0O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/documents/BladesActiveEffect.ts\n"); + +/***/ }), + +/***/ "./ts/documents/BladesActorProxy.ts": +/*!******************************************!*\ + !*** ./ts/documents/BladesActorProxy.ts ***! + \******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesActor: function() { return /* reexport safe */ _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; },\n/* harmony export */ BladesCrew: function() { return /* reexport safe */ _actors_BladesCrew__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; },\n/* harmony export */ BladesFaction: function() { return /* reexport safe */ _actors_BladesFaction__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; },\n/* harmony export */ BladesNPC: function() { return /* reexport safe */ _actors_BladesNPC__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; },\n/* harmony export */ BladesPC: function() { return /* reexport safe */ _actors_BladesPC__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; }\n/* harmony export */ });\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _actors_BladesPC__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./actors/BladesPC */ \"./ts/documents/actors/BladesPC.ts\");\n/* harmony import */ var _actors_BladesNPC__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./actors/BladesNPC */ \"./ts/documents/actors/BladesNPC.ts\");\n/* harmony import */ var _actors_BladesFaction__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./actors/BladesFaction */ \"./ts/documents/actors/BladesFaction.ts\");\n/* harmony import */ var _actors_BladesCrew__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./actors/BladesCrew */ \"./ts/documents/actors/BladesCrew.ts\");\n\n\n\n\n\n\n\nconst ActorsMap = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc]: _actors_BladesPC__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.npc]: _actors_BladesNPC__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.faction]: _actors_BladesFaction__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.crew]: _actors_BladesCrew__WEBPACK_IMPORTED_MODULE_6__[\"default\"]\n};\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst BladesActorProxy = new Proxy(function () { }, {\n construct(_, args) {\n const [{ type }] = args;\n if (!type) {\n throw new Error(`Invalid Actor Type: ${String(type)}`);\n }\n const MappedConstructor = ActorsMap[type];\n if (!MappedConstructor) {\n return new _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"](...args);\n }\n return new MappedConstructor(...args);\n },\n get(_, prop) {\n switch (prop) {\n case \"create\":\n case \"createDocuments\":\n return function (data, options = {}) {\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isArray(data)) {\n return data.map((i) => CONFIG.Actor.documentClass.create(i, options));\n }\n const MappedConstructor = ActorsMap[data.type];\n if (!MappedConstructor) {\n return _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"].create(data, options);\n }\n return MappedConstructor.create(data, options);\n };\n case Symbol.hasInstance:\n return function (instance) {\n return Object.values(ActorsMap).some((i) => instance instanceof i);\n };\n default:\n return _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"][prop];\n }\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesActorProxy);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eS50cyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7QUFBa0M7QUFDa0I7QUFDWDtBQUNBO0FBQ0U7QUFDUTtBQUNOO0FBQzdDO0FBQ0EsS0FBSyw0REFBZSxNQUFNLHdEQUFRO0FBQ2xDLEtBQUssNERBQWUsT0FBTyx5REFBUztBQUNwQyxLQUFLLDREQUFlLFdBQVcsNkRBQWE7QUFDNUMsS0FBSyw0REFBZSxRQUFRLDBEQUFVO0FBQ3RDO0FBQ0E7QUFDQSxrREFBa0Q7QUFDbEQ7QUFDQSxpQkFBaUIsTUFBTTtBQUN2QjtBQUNBLG1EQUFtRCxhQUFhO0FBQ2hFO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixvREFBVztBQUNsQztBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1EO0FBQ25ELHdCQUF3Qix1REFBQztBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixvREFBVztBQUMxQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLG9EQUFXO0FBQ2xDO0FBQ0E7QUFDQSxDQUFDO0FBQ0QsK0RBQWUsZ0JBQWdCLEVBQUM7QUFDdUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eS50cz8zNDQ0Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBVIGZyb20gXCIuLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3JUeXBlIH0gZnJvbSBcIi4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgQmxhZGVzQWN0b3IgZnJvbSBcIi4uL0JsYWRlc0FjdG9yXCI7XG5pbXBvcnQgQmxhZGVzUEMgZnJvbSBcIi4vYWN0b3JzL0JsYWRlc1BDXCI7XG5pbXBvcnQgQmxhZGVzTlBDIGZyb20gXCIuL2FjdG9ycy9CbGFkZXNOUENcIjtcbmltcG9ydCBCbGFkZXNGYWN0aW9uIGZyb20gXCIuL2FjdG9ycy9CbGFkZXNGYWN0aW9uXCI7XG5pbXBvcnQgQmxhZGVzQ3JldyBmcm9tIFwiLi9hY3RvcnMvQmxhZGVzQ3Jld1wiO1xuY29uc3QgQWN0b3JzTWFwID0ge1xuICAgIFtCbGFkZXNBY3RvclR5cGUucGNdOiBCbGFkZXNQQyxcbiAgICBbQmxhZGVzQWN0b3JUeXBlLm5wY106IEJsYWRlc05QQyxcbiAgICBbQmxhZGVzQWN0b3JUeXBlLmZhY3Rpb25dOiBCbGFkZXNGYWN0aW9uLFxuICAgIFtCbGFkZXNBY3RvclR5cGUuY3Jld106IEJsYWRlc0NyZXdcbn07XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG5jb25zdCBCbGFkZXNBY3RvclByb3h5ID0gbmV3IFByb3h5KGZ1bmN0aW9uICgpIHsgfSwge1xuICAgIGNvbnN0cnVjdChfLCBhcmdzKSB7XG4gICAgICAgIGNvbnN0IFt7IHR5cGUgfV0gPSBhcmdzO1xuICAgICAgICBpZiAoIXR5cGUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBBY3RvciBUeXBlOiAke1N0cmluZyh0eXBlKX1gKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBNYXBwZWRDb25zdHJ1Y3RvciA9IEFjdG9yc01hcFt0eXBlXTtcbiAgICAgICAgaWYgKCFNYXBwZWRDb25zdHJ1Y3Rvcikge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBCbGFkZXNBY3RvciguLi5hcmdzKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbmV3IE1hcHBlZENvbnN0cnVjdG9yKC4uLmFyZ3MpO1xuICAgIH0sXG4gICAgZ2V0KF8sIHByb3ApIHtcbiAgICAgICAgc3dpdGNoIChwcm9wKSB7XG4gICAgICAgICAgICBjYXNlIFwiY3JlYXRlXCI6XG4gICAgICAgICAgICBjYXNlIFwiY3JlYXRlRG9jdW1lbnRzXCI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChkYXRhLCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKFUuaXNBcnJheShkYXRhKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRhdGEubWFwKChpKSA9PiBDT05GSUcuQWN0b3IuZG9jdW1lbnRDbGFzcy5jcmVhdGUoaSwgb3B0aW9ucykpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IE1hcHBlZENvbnN0cnVjdG9yID0gQWN0b3JzTWFwW2RhdGEudHlwZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICghTWFwcGVkQ29uc3RydWN0b3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNBY3Rvci5jcmVhdGUoZGF0YSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIE1hcHBlZENvbnN0cnVjdG9yLmNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgY2FzZSBTeW1ib2wuaGFzSW5zdGFuY2U6XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChpbnN0YW5jZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyhBY3RvcnNNYXApLnNvbWUoKGkpID0+IGluc3RhbmNlIGluc3RhbmNlb2YgaSk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuIEJsYWRlc0FjdG9yW3Byb3BdO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNBY3RvclByb3h5O1xuZXhwb3J0IHsgQmxhZGVzQWN0b3IsIEJsYWRlc1BDLCBCbGFkZXNDcmV3LCBCbGFkZXNOUEMsIEJsYWRlc0ZhY3Rpb24gfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/documents/BladesActorProxy.ts\n"); + +/***/ }), + +/***/ "./ts/documents/BladesItemProxy.ts": +/*!*****************************************!*\ + !*** ./ts/documents/BladesItemProxy.ts ***! + \*****************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesClockKeeper: function() { return /* reexport safe */ _items_BladesClockKeeper__WEBPACK_IMPORTED_MODULE_5__[\"default\"]; },\n/* harmony export */ BladesGMTracker: function() { return /* reexport safe */ _items_BladesGMTracker__WEBPACK_IMPORTED_MODULE_6__[\"default\"]; },\n/* harmony export */ BladesItem: function() { return /* reexport safe */ _BladesItem__WEBPACK_IMPORTED_MODULE_2__[\"default\"]; },\n/* harmony export */ BladesLocation: function() { return /* reexport safe */ _items_BladesLocation__WEBPACK_IMPORTED_MODULE_4__[\"default\"]; },\n/* harmony export */ BladesProject: function() { return /* reexport safe */ _items_BladesProject__WEBPACK_IMPORTED_MODULE_3__[\"default\"]; },\n/* harmony export */ BladesScore: function() { return /* reexport safe */ _items_BladesScore__WEBPACK_IMPORTED_MODULE_7__[\"default\"]; }\n/* harmony export */ });\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _items_BladesProject__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./items/BladesProject */ \"./ts/documents/items/BladesProject.ts\");\n/* harmony import */ var _items_BladesLocation__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./items/BladesLocation */ \"./ts/documents/items/BladesLocation.ts\");\n/* harmony import */ var _items_BladesClockKeeper__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./items/BladesClockKeeper */ \"./ts/documents/items/BladesClockKeeper.ts\");\n/* harmony import */ var _items_BladesGMTracker__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./items/BladesGMTracker */ \"./ts/documents/items/BladesGMTracker.ts\");\n/* harmony import */ var _items_BladesScore__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./items/BladesScore */ \"./ts/documents/items/BladesScore.ts\");\n\n\n\n\n\n\n\n\nconst ItemsMap = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.clock_keeper]: _items_BladesClockKeeper__WEBPACK_IMPORTED_MODULE_5__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gm_tracker]: _items_BladesGMTracker__WEBPACK_IMPORTED_MODULE_6__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.location]: _items_BladesLocation__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.project]: _items_BladesProject__WEBPACK_IMPORTED_MODULE_3__[\"default\"],\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.score]: _items_BladesScore__WEBPACK_IMPORTED_MODULE_7__[\"default\"]\n};\n// eslint-disable-next-line @typescript-eslint/no-empty-function\nconst BladesItemProxy = new Proxy(function () { }, {\n construct(_, args) {\n const [{ type }] = args;\n if (!type) {\n throw new Error(`Invalid Item Type: ${String(type)}`);\n }\n const MappedConstructor = ItemsMap[type];\n if (!MappedConstructor) {\n return new _BladesItem__WEBPACK_IMPORTED_MODULE_2__[\"default\"](...args);\n }\n return new MappedConstructor(...args);\n },\n get(_, prop) {\n switch (prop) {\n case \"create\":\n case \"createDocuments\":\n return function (data, options = {}) {\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isArray(data)) {\n return data.map((i) => CONFIG.Item.documentClass.create(i, options));\n }\n const MappedConstructor = ItemsMap[data.type];\n if (!MappedConstructor) {\n return _BladesItem__WEBPACK_IMPORTED_MODULE_2__[\"default\"].create(data, options);\n }\n return MappedConstructor.create(data, options);\n };\n case Symbol.hasInstance:\n return function (instance) {\n return Object.values(ItemsMap).some((i) => instance instanceof i);\n };\n default:\n return _BladesItem__WEBPACK_IMPORTED_MODULE_2__[\"default\"][prop];\n }\n }\n});\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesItemProxy);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvQmxhZGVzSXRlbVByb3h5LnRzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQWtDO0FBQ2lCO0FBQ1o7QUFDVztBQUNFO0FBQ007QUFDSjtBQUNSO0FBQzlDO0FBQ0EsS0FBSywyREFBYyxnQkFBZ0IsZ0VBQWlCO0FBQ3BELEtBQUssMkRBQWMsY0FBYyw4REFBZTtBQUNoRCxLQUFLLDJEQUFjLFlBQVksNkRBQWM7QUFDN0MsS0FBSywyREFBYyxXQUFXLDREQUFhO0FBQzNDLEtBQUssMkRBQWMsU0FBUywwREFBVztBQUN2QztBQUNBO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0EsaUJBQWlCLE1BQU07QUFDdkI7QUFDQSxrREFBa0QsYUFBYTtBQUMvRDtBQUNBO0FBQ0E7QUFDQSx1QkFBdUIsbURBQVU7QUFDakM7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1EQUFtRDtBQUNuRCx3QkFBd0IsdURBQUM7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQkFBK0IsbURBQVU7QUFDekM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixtREFBVTtBQUNqQztBQUNBO0FBQ0EsQ0FBQztBQUNELCtEQUFlLGVBQWUsRUFBQztBQUN1RSIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2RvY3VtZW50cy9CbGFkZXNJdGVtUHJveHkudHM/NjVjNyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgVSBmcm9tIFwiLi4vY29yZS91dGlsaXRpZXNcIjtcbmltcG9ydCB7IEJsYWRlc0l0ZW1UeXBlIH0gZnJvbSBcIi4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgQmxhZGVzSXRlbSBmcm9tIFwiLi4vQmxhZGVzSXRlbVwiO1xuaW1wb3J0IEJsYWRlc1Byb2plY3QgZnJvbSBcIi4vaXRlbXMvQmxhZGVzUHJvamVjdFwiO1xuaW1wb3J0IEJsYWRlc0xvY2F0aW9uIGZyb20gXCIuL2l0ZW1zL0JsYWRlc0xvY2F0aW9uXCI7XG5pbXBvcnQgQmxhZGVzQ2xvY2tLZWVwZXIgZnJvbSBcIi4vaXRlbXMvQmxhZGVzQ2xvY2tLZWVwZXJcIjtcbmltcG9ydCBCbGFkZXNHTVRyYWNrZXIgZnJvbSBcIi4vaXRlbXMvQmxhZGVzR01UcmFja2VyXCI7XG5pbXBvcnQgQmxhZGVzU2NvcmUgZnJvbSBcIi4vaXRlbXMvQmxhZGVzU2NvcmVcIjtcbmNvbnN0IEl0ZW1zTWFwID0ge1xuICAgIFtCbGFkZXNJdGVtVHlwZS5jbG9ja19rZWVwZXJdOiBCbGFkZXNDbG9ja0tlZXBlcixcbiAgICBbQmxhZGVzSXRlbVR5cGUuZ21fdHJhY2tlcl06IEJsYWRlc0dNVHJhY2tlcixcbiAgICBbQmxhZGVzSXRlbVR5cGUubG9jYXRpb25dOiBCbGFkZXNMb2NhdGlvbixcbiAgICBbQmxhZGVzSXRlbVR5cGUucHJvamVjdF06IEJsYWRlc1Byb2plY3QsXG4gICAgW0JsYWRlc0l0ZW1UeXBlLnNjb3JlXTogQmxhZGVzU2NvcmVcbn07XG4vLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgQHR5cGVzY3JpcHQtZXNsaW50L25vLWVtcHR5LWZ1bmN0aW9uXG5jb25zdCBCbGFkZXNJdGVtUHJveHkgPSBuZXcgUHJveHkoZnVuY3Rpb24gKCkgeyB9LCB7XG4gICAgY29uc3RydWN0KF8sIGFyZ3MpIHtcbiAgICAgICAgY29uc3QgW3sgdHlwZSB9XSA9IGFyZ3M7XG4gICAgICAgIGlmICghdHlwZSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIEl0ZW0gVHlwZTogJHtTdHJpbmcodHlwZSl9YCk7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgTWFwcGVkQ29uc3RydWN0b3IgPSBJdGVtc01hcFt0eXBlXTtcbiAgICAgICAgaWYgKCFNYXBwZWRDb25zdHJ1Y3Rvcikge1xuICAgICAgICAgICAgcmV0dXJuIG5ldyBCbGFkZXNJdGVtKC4uLmFyZ3MpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgTWFwcGVkQ29uc3RydWN0b3IoLi4uYXJncyk7XG4gICAgfSxcbiAgICBnZXQoXywgcHJvcCkge1xuICAgICAgICBzd2l0Y2ggKHByb3ApIHtcbiAgICAgICAgICAgIGNhc2UgXCJjcmVhdGVcIjpcbiAgICAgICAgICAgIGNhc2UgXCJjcmVhdGVEb2N1bWVudHNcIjpcbiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGRhdGEsIG9wdGlvbnMgPSB7fSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoVS5pc0FycmF5KGRhdGEpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZGF0YS5tYXAoKGkpID0+IENPTkZJRy5JdGVtLmRvY3VtZW50Q2xhc3MuY3JlYXRlKGksIG9wdGlvbnMpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zdCBNYXBwZWRDb25zdHJ1Y3RvciA9IEl0ZW1zTWFwW2RhdGEudHlwZV07XG4gICAgICAgICAgICAgICAgICAgIGlmICghTWFwcGVkQ29uc3RydWN0b3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNJdGVtLmNyZWF0ZShkYXRhLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gTWFwcGVkQ29uc3RydWN0b3IuY3JlYXRlKGRhdGEsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjYXNlIFN5bWJvbC5oYXNJbnN0YW5jZTpcbiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gKGluc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKEl0ZW1zTWFwKS5zb21lKChpKSA9PiBpbnN0YW5jZSBpbnN0YW5jZW9mIGkpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIHJldHVybiBCbGFkZXNJdGVtW3Byb3BdO1xuICAgICAgICB9XG4gICAgfVxufSk7XG5leHBvcnQgZGVmYXVsdCBCbGFkZXNJdGVtUHJveHk7XG5leHBvcnQgeyBCbGFkZXNJdGVtLCBCbGFkZXNDbG9ja0tlZXBlciwgQmxhZGVzR01UcmFja2VyLCBCbGFkZXNMb2NhdGlvbiwgQmxhZGVzUHJvamVjdCwgQmxhZGVzU2NvcmUgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/documents/BladesItemProxy.ts\n"); + +/***/ }), + +/***/ "./ts/documents/actors/BladesCrew.ts": +/*!*******************************************!*\ + !*** ./ts/documents/actors/BladesCrew.ts ***! + \*******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _sheets_actor_BladesCrewSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../sheets/actor/BladesCrewSheet */ \"./ts/sheets/actor/BladesCrewSheet.ts\");\n/* harmony import */ var _BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../classes/BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\nclass BladesCrew extends _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesCrew, BladesCrewSheet: _sheets_actor_BladesCrewSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] });\n Actors.registerSheet(\"blades\", _sheets_actor_BladesCrewSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { types: [\"crew\"], makeDefault: true });\n return loadTemplates([\"systems/eunos-blades/templates/crew-sheet.hbs\"]);\n }\n // #endregion\n // #region Static Overrides: Create ~\n // static override IsType(doc: unknown): doc is BladesActorOfType {\n // return super.IsType(doc, BladesActorType.crew);\n // }\n static IsType(doc) {\n return super.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew);\n }\n static GetFromUser(userRef) {\n const actor = _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesPC.GetFromUser(userRef);\n if (!actor) {\n return undefined;\n }\n return actor.crew;\n }\n static GetFromPC(pcRef) {\n let actor;\n if (typeof pcRef === \"string\") {\n actor = game.actors.get(pcRef) ?? game.actors.getName(pcRef);\n }\n else if (pcRef instanceof _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesPC) {\n actor = pcRef;\n }\n else {\n actor ??= _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesPC.GetFromUser(pcRef);\n }\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesPC.IsType(actor)) {\n throw new Error(`Unable to find BladesPC from '${pcRef}'`);\n }\n return actor.crew;\n }\n static async create(data, options = {}) {\n data.token = data.token || {};\n data.system = data.system ?? {};\n eLog.checkLog2(\"actor\", \"BladesActor.create(data,options)\", { data, options });\n // ~ For Crew and PC set the Token to sync with charsheet.\n data.token.actorLink = true;\n // ~ Create world_name\n data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, \"\").trim().replace(/ /g, \"_\");\n // ~ Initialize generic experience clues.\n data.system.experience = {\n playbook: { value: 0, max: 8 },\n clues: [],\n ...data.system.experience ?? {}\n };\n return super.create(data, options);\n }\n // #endregion\n // #region BladesCrew Implementation\n getDialogItems(category) {\n const dialogData = {};\n const { playbookName } = this;\n if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__.SelectionCategory.Playbook) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__.SelectionCategory.Reputation) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_reputation));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__.SelectionCategory.Preferred_Op && playbookName !== null) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.preferred_op, playbookName));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__.SelectionCategory.Ability) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_ability, this.playbookName));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_4__.SelectionCategory.Upgrade && playbookName !== null) {\n dialogData[playbookName] = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_upgrade, playbookName));\n dialogData.General = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_3__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_upgrade, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.General));\n }\n return dialogData;\n }\n get members() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew)) {\n return [];\n }\n const self = this;\n return _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc).filter((actor) => actor.isMember(self));\n }\n get contacts() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew) || !this.playbook) {\n return [];\n }\n const self = this;\n return this.activeSubActors.filter((actor) => actor.hasTag(self.playbookName));\n }\n get claims() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew) || !this.playbook) {\n return {};\n }\n return this.playbook.system.turfs;\n }\n get turfCount() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew) || !this.playbook) {\n return 0;\n }\n return Object.values(this.playbook.system.turfs)\n .filter((claim) => claim.isTurf && claim.value).length;\n }\n get upgrades() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew) || !this.playbook) {\n return [];\n }\n return this.activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_upgrade);\n }\n get cohorts() {\n return this.activeSubItems\n .filter((item) => [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert].includes(item.type));\n }\n getTaggedItemBonuses(tags) {\n // Given a list of item tags, will return the total bonuses to that item\n // Won't return a number, but an object literal that includes things like extra load space or concealability\n // Check ACTIVE EFFECTS supplied by upgrade/ability against submitted tags?\n return tags.length; // Placeholder to avoid linter error\n }\n // #endregion\n // #region BladesRoll Implementation\n // #region BladesRoll.ParticipantDoc Implementation\n get rollParticipantID() { return this.id; }\n get rollParticipantDoc() { return this; }\n get rollParticipantIcon() { return this.playbook?.img ?? this.img; }\n get rollParticipantName() { return this.name; }\n get rollParticipantType() { return this.type; }\n get rollParticipantModsSchemaSet() { return []; }\n async applyHarm(_amount, _name) {\n console.error(\"Attempt to apply harm directly to a Crew document.\");\n }\n async applyWorsePosition() {\n console.error(\"Attempt to apply worse position directly to a Crew document.\");\n }\n // #endregion\n // #endregion\n get abilities() {\n if (!this.playbook) {\n return [];\n }\n return this.activeSubItems\n .filter((item) => [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_ability].includes(item.type));\n }\n get playbookName() {\n return this.playbook?.name;\n }\n get playbook() {\n return this.activeSubItems\n .find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesCrew);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvYWN0b3JzL0JsYWRlc0NyZXcudHMiLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQUE7QUFDNEU7QUFDaEI7QUFDSztBQUNqQjtBQUNlO0FBQy9ELHlCQUF5QiwwREFBVztBQUNwQztBQUNBO0FBQ0Esb0NBQW9DLDJCQUEyQix5RUFBRTtBQUNqRSx1Q0FBdUMscUVBQWUsSUFBSSxvQ0FBb0M7QUFDOUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyw0REFBZTtBQUNoRDtBQUNBO0FBQ0Esc0JBQXNCLHVEQUFRO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDLHVEQUFRO0FBQzFDO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQix1REFBUTtBQUM5QjtBQUNBLGFBQWEsdURBQVE7QUFDckIsNkRBQTZELE1BQU07QUFDbkU7QUFDQTtBQUNBO0FBQ0EsMENBQTBDO0FBQzFDO0FBQ0E7QUFDQSxzRUFBc0UsZUFBZTtBQUNyRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx3QkFBd0Isa0JBQWtCO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixlQUFlO0FBQy9CLHlCQUF5QixvRUFBaUI7QUFDMUMsK0RBQStELHdEQUFVLGlCQUFpQiwyREFBYztBQUN4RztBQUNBLDhCQUE4QixvRUFBaUI7QUFDL0MsK0RBQStELHdEQUFVLGlCQUFpQiwyREFBYztBQUN4RztBQUNBLDhCQUE4QixvRUFBaUI7QUFDL0MsK0RBQStELHdEQUFVLGlCQUFpQiwyREFBYztBQUN4RztBQUNBLDhCQUE4QixvRUFBaUI7QUFDL0MsK0RBQStELHdEQUFVLGlCQUFpQiwyREFBYztBQUN4RztBQUNBLDhCQUE4QixvRUFBaUI7QUFDL0Msd0VBQXdFLHdEQUFVLGlCQUFpQiwyREFBYztBQUNqSCxrRUFBa0Usd0RBQVUsaUJBQWlCLDJEQUFjLGVBQWUsZ0RBQUc7QUFDN0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDBEQUFXLGNBQWMsNERBQWU7QUFDckQ7QUFDQTtBQUNBO0FBQ0EsZUFBZSwwREFBVyxpQkFBaUIsNERBQWU7QUFDMUQ7QUFDQTtBQUNBLGFBQWEsMERBQVcsY0FBYyw0REFBZTtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDBEQUFXLGNBQWMsNERBQWU7QUFDckQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWEsMERBQVcsY0FBYyw0REFBZTtBQUNyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDBEQUFXLGNBQWMsNERBQWU7QUFDckQ7QUFDQTtBQUNBO0FBQ0EsNENBQTRDLDJEQUFjO0FBQzFEO0FBQ0E7QUFDQTtBQUNBLCtCQUErQiwyREFBYyxjQUFjLDJEQUFjO0FBQ3pFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0QkFBNEI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7QUFDOUIsK0JBQStCO0FBQy9CLGdDQUFnQztBQUNoQyxnQ0FBZ0M7QUFDaEMsZ0NBQWdDO0FBQ2hDLHlDQUF5QztBQUN6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQiwyREFBYyxVQUFVLDJEQUFjO0FBQ3JFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQywyREFBYztBQUN4RDtBQUNBO0FBQ0EsK0RBQWUsVUFBVSxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2FjdG9ycy9CbGFkZXNDcmV3LnRzPzk5OTAiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgeyBCbGFkZXNBY3RvclR5cGUsIEJsYWRlc0l0ZW1UeXBlLCBUYWcgfSBmcm9tIFwiLi4vLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCB7IEJsYWRlc0FjdG9yLCBCbGFkZXNQQyB9IGZyb20gXCIuLi9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgQmxhZGVzQ3Jld1NoZWV0IGZyb20gXCIuLi8uLi9zaGVldHMvYWN0b3IvQmxhZGVzQ3Jld1NoZWV0XCI7XG5pbXBvcnQgeyBCbGFkZXNJdGVtIH0gZnJvbSBcIi4uL0JsYWRlc0l0ZW1Qcm94eVwiO1xuaW1wb3J0IHsgU2VsZWN0aW9uQ2F0ZWdvcnkgfSBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNEaWFsb2dcIjtcbmNsYXNzIEJsYWRlc0NyZXcgZXh0ZW5kcyBCbGFkZXNBY3RvciB7XG4gICAgLy8gI3JlZ2lvbiBJTklUSUFMSVpBVElPTiB+XG4gICAgc3RhdGljIGFzeW5jIEluaXRpYWxpemUoKSB7XG4gICAgICAgIE9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywgeyBCbGFkZXNDcmV3LCBCbGFkZXNDcmV3U2hlZXQgfSk7XG4gICAgICAgIEFjdG9ycy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc0NyZXdTaGVldCwgeyB0eXBlczogW1wiY3Jld1wiXSwgbWFrZURlZmF1bHQ6IHRydWUgfSk7XG4gICAgICAgIHJldHVybiBsb2FkVGVtcGxhdGVzKFtcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9jcmV3LXNoZWV0Lmhic1wiXSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFN0YXRpYyBPdmVycmlkZXM6IENyZWF0ZSB+XG4gICAgLy8gc3RhdGljIG92ZXJyaWRlIElzVHlwZTxUIGV4dGVuZHMgQmxhZGVzQWN0b3JUeXBlID0gQmxhZGVzQWN0b3JUeXBlLmNyZXc+KGRvYzogdW5rbm93bik6IGRvYyBpcyBCbGFkZXNBY3Rvck9mVHlwZTxUPiB7XG4gICAgLy8gICByZXR1cm4gc3VwZXIuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpO1xuICAgIC8vIH1cbiAgICBzdGF0aWMgSXNUeXBlKGRvYykge1xuICAgICAgICByZXR1cm4gc3VwZXIuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpO1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RnJvbVVzZXIodXNlclJlZikge1xuICAgICAgICBjb25zdCBhY3RvciA9IEJsYWRlc1BDLkdldEZyb21Vc2VyKHVzZXJSZWYpO1xuICAgICAgICBpZiAoIWFjdG9yKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhY3Rvci5jcmV3O1xuICAgIH1cbiAgICBzdGF0aWMgR2V0RnJvbVBDKHBjUmVmKSB7XG4gICAgICAgIGxldCBhY3RvcjtcbiAgICAgICAgaWYgKHR5cGVvZiBwY1JlZiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgYWN0b3IgPSBnYW1lLmFjdG9ycy5nZXQocGNSZWYpID8/IGdhbWUuYWN0b3JzLmdldE5hbWUocGNSZWYpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHBjUmVmIGluc3RhbmNlb2YgQmxhZGVzUEMpIHtcbiAgICAgICAgICAgIGFjdG9yID0gcGNSZWY7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBhY3RvciA/Pz0gQmxhZGVzUEMuR2V0RnJvbVVzZXIocGNSZWYpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghQmxhZGVzUEMuSXNUeXBlKGFjdG9yKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gZmluZCBCbGFkZXNQQyBmcm9tICcke3BjUmVmfSdgKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWN0b3IuY3JldztcbiAgICB9XG4gICAgc3RhdGljIGFzeW5jIGNyZWF0ZShkYXRhLCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgZGF0YS50b2tlbiA9IGRhdGEudG9rZW4gfHwge307XG4gICAgICAgIGRhdGEuc3lzdGVtID0gZGF0YS5zeXN0ZW0gPz8ge307XG4gICAgICAgIGVMb2cuY2hlY2tMb2cyKFwiYWN0b3JcIiwgXCJCbGFkZXNBY3Rvci5jcmVhdGUoZGF0YSxvcHRpb25zKVwiLCB7IGRhdGEsIG9wdGlvbnMgfSk7XG4gICAgICAgIC8vIH4gRm9yIENyZXcgYW5kIFBDIHNldCB0aGUgVG9rZW4gdG8gc3luYyB3aXRoIGNoYXJzaGVldC5cbiAgICAgICAgZGF0YS50b2tlbi5hY3RvckxpbmsgPSB0cnVlO1xuICAgICAgICAvLyB+IENyZWF0ZSB3b3JsZF9uYW1lXG4gICAgICAgIGRhdGEuc3lzdGVtLndvcmxkX25hbWUgPSBkYXRhLnN5c3RlbS53b3JsZF9uYW1lID8/IGRhdGEubmFtZS5yZXBsYWNlKC9bXkEtWmEtel8wLTkgXS9nLCBcIlwiKS50cmltKCkucmVwbGFjZSgvIC9nLCBcIl9cIik7XG4gICAgICAgIC8vIH4gSW5pdGlhbGl6ZSBnZW5lcmljIGV4cGVyaWVuY2UgY2x1ZXMuXG4gICAgICAgIGRhdGEuc3lzdGVtLmV4cGVyaWVuY2UgPSB7XG4gICAgICAgICAgICBwbGF5Ym9vazogeyB2YWx1ZTogMCwgbWF4OiA4IH0sXG4gICAgICAgICAgICBjbHVlczogW10sXG4gICAgICAgICAgICAuLi5kYXRhLnN5c3RlbS5leHBlcmllbmNlID8/IHt9XG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBzdXBlci5jcmVhdGUoZGF0YSwgb3B0aW9ucyk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc0NyZXcgSW1wbGVtZW50YXRpb25cbiAgICBnZXREaWFsb2dJdGVtcyhjYXRlZ29yeSkge1xuICAgICAgICBjb25zdCBkaWFsb2dEYXRhID0ge307XG4gICAgICAgIGNvbnN0IHsgcGxheWJvb2tOYW1lIH0gPSB0aGlzO1xuICAgICAgICBpZiAoY2F0ZWdvcnkgPT09IFNlbGVjdGlvbkNhdGVnb3J5LlBsYXlib29rKSB7XG4gICAgICAgICAgICBkaWFsb2dEYXRhLk1haW4gPSB0aGlzLl9wcm9jZXNzRW1iZWRkZWRJdGVtTWF0Y2hlcyhCbGFkZXNJdGVtLkdldFR5cGVXaXRoVGFncyhCbGFkZXNJdGVtVHlwZS5jcmV3X3BsYXlib29rKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2F0ZWdvcnkgPT09IFNlbGVjdGlvbkNhdGVnb3J5LlJlcHV0YXRpb24pIHtcbiAgICAgICAgICAgIGRpYWxvZ0RhdGEuTWFpbiA9IHRoaXMuX3Byb2Nlc3NFbWJlZGRlZEl0ZW1NYXRjaGVzKEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLmNyZXdfcmVwdXRhdGlvbikpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNhdGVnb3J5ID09PSBTZWxlY3Rpb25DYXRlZ29yeS5QcmVmZXJyZWRfT3AgJiYgcGxheWJvb2tOYW1lICE9PSBudWxsKSB7XG4gICAgICAgICAgICBkaWFsb2dEYXRhLk1haW4gPSB0aGlzLl9wcm9jZXNzRW1iZWRkZWRJdGVtTWF0Y2hlcyhCbGFkZXNJdGVtLkdldFR5cGVXaXRoVGFncyhCbGFkZXNJdGVtVHlwZS5wcmVmZXJyZWRfb3AsIHBsYXlib29rTmFtZSkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNhdGVnb3J5ID09PSBTZWxlY3Rpb25DYXRlZ29yeS5BYmlsaXR5KSB7XG4gICAgICAgICAgICBkaWFsb2dEYXRhLk1haW4gPSB0aGlzLl9wcm9jZXNzRW1iZWRkZWRJdGVtTWF0Y2hlcyhCbGFkZXNJdGVtLkdldFR5cGVXaXRoVGFncyhCbGFkZXNJdGVtVHlwZS5jcmV3X2FiaWxpdHksIHRoaXMucGxheWJvb2tOYW1lKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2F0ZWdvcnkgPT09IFNlbGVjdGlvbkNhdGVnb3J5LlVwZ3JhZGUgJiYgcGxheWJvb2tOYW1lICE9PSBudWxsKSB7XG4gICAgICAgICAgICBkaWFsb2dEYXRhW3BsYXlib29rTmFtZV0gPSB0aGlzLl9wcm9jZXNzRW1iZWRkZWRJdGVtTWF0Y2hlcyhCbGFkZXNJdGVtLkdldFR5cGVXaXRoVGFncyhCbGFkZXNJdGVtVHlwZS5jcmV3X3VwZ3JhZGUsIHBsYXlib29rTmFtZSkpO1xuICAgICAgICAgICAgZGlhbG9nRGF0YS5HZW5lcmFsID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUuY3Jld191cGdyYWRlLCBUYWcuR2Vhci5HZW5lcmFsKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRpYWxvZ0RhdGE7XG4gICAgfVxuICAgIGdldCBtZW1iZXJzKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUuY3JldykpIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgcmV0dXJuIEJsYWRlc0FjdG9yLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUucGMpLmZpbHRlcigoYWN0b3IpID0+IGFjdG9yLmlzTWVtYmVyKHNlbGYpKTtcbiAgICB9XG4gICAgZ2V0IGNvbnRhY3RzKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUuY3JldykgfHwgIXRoaXMucGxheWJvb2spIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgcmV0dXJuIHRoaXMuYWN0aXZlU3ViQWN0b3JzLmZpbHRlcigoYWN0b3IpID0+IGFjdG9yLmhhc1RhZyhzZWxmLnBsYXlib29rTmFtZSkpO1xuICAgIH1cbiAgICBnZXQgY2xhaW1zKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUuY3JldykgfHwgIXRoaXMucGxheWJvb2spIHtcbiAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5wbGF5Ym9vay5zeXN0ZW0udHVyZnM7XG4gICAgfVxuICAgIGdldCB0dXJmQ291bnQoKSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSB8fCAhdGhpcy5wbGF5Ym9vaykge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5wbGF5Ym9vay5zeXN0ZW0udHVyZnMpXG4gICAgICAgICAgICAuZmlsdGVyKChjbGFpbSkgPT4gY2xhaW0uaXNUdXJmICYmIGNsYWltLnZhbHVlKS5sZW5ndGg7XG4gICAgfVxuICAgIGdldCB1cGdyYWRlcygpIHtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLmNyZXcpIHx8ICF0aGlzLnBsYXlib29rKSB7XG4gICAgICAgICAgICByZXR1cm4gW107XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXMuYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgIC5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gQmxhZGVzSXRlbVR5cGUuY3Jld191cGdyYWRlKTtcbiAgICB9XG4gICAgZ2V0IGNvaG9ydHMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBbQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnRdLmluY2x1ZGVzKGl0ZW0udHlwZSkpO1xuICAgIH1cbiAgICBnZXRUYWdnZWRJdGVtQm9udXNlcyh0YWdzKSB7XG4gICAgICAgIC8vIEdpdmVuIGEgbGlzdCBvZiBpdGVtIHRhZ3MsIHdpbGwgcmV0dXJuIHRoZSB0b3RhbCBib251c2VzIHRvIHRoYXQgaXRlbVxuICAgICAgICAvLyBXb24ndCByZXR1cm4gYSBudW1iZXIsIGJ1dCBhbiBvYmplY3QgbGl0ZXJhbCB0aGF0IGluY2x1ZGVzIHRoaW5ncyBsaWtlIGV4dHJhIGxvYWQgc3BhY2Ugb3IgY29uY2VhbGFiaWxpdHlcbiAgICAgICAgLy8gQ2hlY2sgQUNUSVZFIEVGRkVDVFMgc3VwcGxpZWQgYnkgdXBncmFkZS9hYmlsaXR5IGFnYWluc3Qgc3VibWl0dGVkIHRhZ3M/XG4gICAgICAgIHJldHVybiB0YWdzLmxlbmd0aDsgLy8gUGxhY2Vob2xkZXIgdG8gYXZvaWQgbGludGVyIGVycm9yXG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwgSW1wbGVtZW50YXRpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwuUGFydGljaXBhbnREb2MgSW1wbGVtZW50YXRpb25cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50SUQoKSB7IHJldHVybiB0aGlzLmlkOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudERvYygpIHsgcmV0dXJuIHRoaXM7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50SWNvbigpIHsgcmV0dXJuIHRoaXMucGxheWJvb2s/LmltZyA/PyB0aGlzLmltZzsgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnROYW1lKCkgeyByZXR1cm4gdGhpcy5uYW1lOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudFR5cGUoKSB7IHJldHVybiB0aGlzLnR5cGU7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50TW9kc1NjaGVtYVNldCgpIHsgcmV0dXJuIFtdOyB9XG4gICAgYXN5bmMgYXBwbHlIYXJtKF9hbW91bnQsIF9uYW1lKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoXCJBdHRlbXB0IHRvIGFwcGx5IGhhcm0gZGlyZWN0bHkgdG8gYSBDcmV3IGRvY3VtZW50LlwiKTtcbiAgICB9XG4gICAgYXN5bmMgYXBwbHlXb3JzZVBvc2l0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiQXR0ZW1wdCB0byBhcHBseSB3b3JzZSBwb3NpdGlvbiBkaXJlY3RseSB0byBhIENyZXcgZG9jdW1lbnQuXCIpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIGdldCBhYmlsaXRpZXMoKSB7XG4gICAgICAgIGlmICghdGhpcy5wbGF5Ym9vaykge1xuICAgICAgICAgICAgcmV0dXJuIFtdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBbQmxhZGVzSXRlbVR5cGUuYWJpbGl0eSwgQmxhZGVzSXRlbVR5cGUuY3Jld19hYmlsaXR5XS5pbmNsdWRlcyhpdGVtLnR5cGUpKTtcbiAgICB9XG4gICAgZ2V0IHBsYXlib29rTmFtZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGxheWJvb2s/Lm5hbWU7XG4gICAgfVxuICAgIGdldCBwbGF5Ym9vaygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgIC5maW5kKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmNyZXdfcGxheWJvb2spO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0NyZXc7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/actors/BladesCrew.ts\n"); + +/***/ }), + +/***/ "./ts/documents/actors/BladesFaction.ts": +/*!**********************************************!*\ + !*** ./ts/documents/actors/BladesFaction.ts ***! + \**********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _sheets_actor_BladesFactionSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../sheets/actor/BladesFactionSheet */ \"./ts/sheets/actor/BladesFactionSheet.ts\");\n/* harmony import */ var _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../classes/BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n\n\n\n\nclass BladesFaction extends _BladesActorProxy__WEBPACK_IMPORTED_MODULE_1__.BladesActor {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesFaction, BladesFactionSheet: _sheets_actor_BladesFactionSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] });\n Actors.registerSheet(\"blades\", _sheets_actor_BladesFactionSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { types: [\"faction\"], makeDefault: true });\n return loadTemplates([\"systems/eunos-blades/templates/faction-sheet.hbs\"]);\n }\n // #endregion\n static get All() {\n return new Collection(super.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.faction)\n .map((faction) => [faction.id, faction]));\n }\n static IsType(doc) {\n return super.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.faction);\n }\n // #region BladesRoll Implementation\n // #region BladesRoll.OppositionDoc Implementation\n get rollOppID() { return this.id; }\n get rollOppDoc() { return this; }\n get rollOppImg() { return this.img ?? \"\"; }\n get rollOppName() { return this.name ?? \"\"; }\n get rollOppSubName() { return this.system.subtitle || this.system.concept || \" \"; }\n get rollOppType() { return this.type; }\n get rollOppModsSchemaSet() { return []; }\n // #endregion\n // #endregion\n // _clocks: Collection = new Collection();\n // get clocks(): Collection = {\n // return new Collection()\n // }\n get clocks() {\n return new Collection(Object.entries(this.system.clocksData ?? {})\n .map(([id, data]) => [\n id,\n game.eunoblades.ClockKeys.get(id) ?? new _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_3__[\"default\"](data)\n ]));\n }\n async addClock() {\n return await _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_3__[\"default\"].Create({\n target: this,\n targetKey: \"system.clocksData\"\n });\n }\n async deleteClock(clockKeyID) {\n await game.eunoblades.ClockKeys.get(clockKeyID)?.delete(game.eunoblades.ClockKeys);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesFaction);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvYWN0b3JzL0JsYWRlc0ZhY3Rpb24udHMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFBdUQ7QUFDTDtBQUNxQjtBQUNiO0FBQzFELDRCQUE0QiwwREFBVztBQUN2QztBQUNBO0FBQ0Esb0NBQW9DLGlDQUFpQyw0RUFBRTtBQUN2RSx1Q0FBdUMsd0VBQWtCLElBQUksdUNBQXVDO0FBQ3BHO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0RBQW9ELDREQUFlO0FBQ25FO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyw0REFBZTtBQUNoRDtBQUNBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIsdUJBQXVCO0FBQ3ZCLHVCQUF1QjtBQUN2Qix3QkFBd0I7QUFDeEIsMkJBQTJCO0FBQzNCLHdCQUF3QjtBQUN4QixpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5RUFBeUU7QUFDekU7QUFDQTtBQUNBLHFEQUFxRCwrREFBYztBQUNuRTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsK0RBQWM7QUFDbkM7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0RBQWUsYUFBYSxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2FjdG9ycy9CbGFkZXNGYWN0aW9uLnRzPzNmNjIiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQmxhZGVzQWN0b3JUeXBlIH0gZnJvbSBcIi4uLy4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBCbGFkZXNBY3RvciB9IGZyb20gXCIuLi9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgQmxhZGVzRmFjdGlvblNoZWV0IGZyb20gXCIuLi8uLi9zaGVldHMvYWN0b3IvQmxhZGVzRmFjdGlvblNoZWV0XCI7XG5pbXBvcnQgQmxhZGVzQ2xvY2tLZXkgZnJvbSBcIi4uLy4uL2NsYXNzZXMvQmxhZGVzQ2xvY2tLZXlcIjtcbmNsYXNzIEJsYWRlc0ZhY3Rpb24gZXh0ZW5kcyBCbGFkZXNBY3RvciB7XG4gICAgLy8gI3JlZ2lvbiBJTklUSUFMSVpBVElPTiB+XG4gICAgc3RhdGljIGFzeW5jIEluaXRpYWxpemUoKSB7XG4gICAgICAgIE9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywgeyBCbGFkZXNGYWN0aW9uLCBCbGFkZXNGYWN0aW9uU2hlZXQgfSk7XG4gICAgICAgIEFjdG9ycy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc0ZhY3Rpb25TaGVldCwgeyB0eXBlczogW1wiZmFjdGlvblwiXSwgbWFrZURlZmF1bHQ6IHRydWUgfSk7XG4gICAgICAgIHJldHVybiBsb2FkVGVtcGxhdGVzKFtcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9mYWN0aW9uLXNoZWV0Lmhic1wiXSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBzdGF0aWMgZ2V0IEFsbCgpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKHN1cGVyLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUuZmFjdGlvbilcbiAgICAgICAgICAgIC5tYXAoKGZhY3Rpb24pID0+IFtmYWN0aW9uLmlkLCBmYWN0aW9uXSkpO1xuICAgIH1cbiAgICBzdGF0aWMgSXNUeXBlKGRvYykge1xuICAgICAgICByZXR1cm4gc3VwZXIuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLmZhY3Rpb24pO1xuICAgIH1cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwgSW1wbGVtZW50YXRpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwuT3Bwb3NpdGlvbkRvYyBJbXBsZW1lbnRhdGlvblxuICAgIGdldCByb2xsT3BwSUQoKSB7IHJldHVybiB0aGlzLmlkOyB9XG4gICAgZ2V0IHJvbGxPcHBEb2MoKSB7IHJldHVybiB0aGlzOyB9XG4gICAgZ2V0IHJvbGxPcHBJbWcoKSB7IHJldHVybiB0aGlzLmltZyA/PyBcIlwiOyB9XG4gICAgZ2V0IHJvbGxPcHBOYW1lKCkgeyByZXR1cm4gdGhpcy5uYW1lID8/IFwiXCI7IH1cbiAgICBnZXQgcm9sbE9wcFN1Yk5hbWUoKSB7IHJldHVybiB0aGlzLnN5c3RlbS5zdWJ0aXRsZSB8fCB0aGlzLnN5c3RlbS5jb25jZXB0IHx8IFwiIFwiOyB9XG4gICAgZ2V0IHJvbGxPcHBUeXBlKCkgeyByZXR1cm4gdGhpcy50eXBlOyB9XG4gICAgZ2V0IHJvbGxPcHBNb2RzU2NoZW1hU2V0KCkgeyByZXR1cm4gW107IH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vIF9jbG9ja3M6IENvbGxlY3Rpb248QmxhZGVzQ2xvY2s+ID0gbmV3IENvbGxlY3Rpb24oKTtcbiAgICAvLyBnZXQgY2xvY2tzKCk6IENvbGxlY3Rpb248QmxhZGVzQ2xvY2s+ID0ge1xuICAgIC8vICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKClcbiAgICAvLyB9XG4gICAgZ2V0IGNsb2NrcygpIHtcbiAgICAgICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKE9iamVjdC5lbnRyaWVzKHRoaXMuc3lzdGVtLmNsb2Nrc0RhdGEgPz8ge30pXG4gICAgICAgICAgICAubWFwKChbaWQsIGRhdGFdKSA9PiBbXG4gICAgICAgICAgICBpZCxcbiAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGlkKSA/PyBuZXcgQmxhZGVzQ2xvY2tLZXkoZGF0YSlcbiAgICAgICAgXSkpO1xuICAgIH1cbiAgICBhc3luYyBhZGRDbG9jaygpIHtcbiAgICAgICAgcmV0dXJuIGF3YWl0IEJsYWRlc0Nsb2NrS2V5LkNyZWF0ZSh7XG4gICAgICAgICAgICB0YXJnZXQ6IHRoaXMsXG4gICAgICAgICAgICB0YXJnZXRLZXk6IFwic3lzdGVtLmNsb2Nrc0RhdGFcIlxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZGVsZXRlQ2xvY2soY2xvY2tLZXlJRCkge1xuICAgICAgICBhd2FpdCBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChjbG9ja0tleUlEKT8uZGVsZXRlKGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0ZhY3Rpb247XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/actors/BladesFaction.ts\n"); + +/***/ }), + +/***/ "./ts/documents/actors/BladesNPC.ts": +/*!******************************************!*\ + !*** ./ts/documents/actors/BladesNPC.ts ***! + \******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _sheets_actor_BladesNPCSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../sheets/actor/BladesNPCSheet */ \"./ts/sheets/actor/BladesNPCSheet.ts\");\n\n\n\nclass BladesNPC extends _BladesActor__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesNPC, BladesNPCSheet: _sheets_actor_BladesNPCSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] });\n Actors.registerSheet(\"blades\", _sheets_actor_BladesNPCSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"], { types: [\"npc\"], makeDefault: true });\n return loadTemplates([\"systems/eunos-blades/templates/npc-sheet.hbs\"]);\n }\n // #endregion\n static IsType(doc) {\n return super.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.npc);\n }\n // #region BladesRoll Implementation\n get rollFactors() {\n const factorData = super.rollFactors;\n factorData[_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale] = {\n name: _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale,\n display: \"Scale\",\n value: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale),\n max: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale),\n baseVal: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.scale),\n cssClasses: \"factor-grey\",\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n };\n factorData[_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude] = {\n name: _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude,\n display: \"Magnitude\",\n value: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude),\n max: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude),\n baseVal: this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.magnitude),\n isActive: false,\n isPrimary: false,\n isDominant: false,\n highFavorsPC: true\n };\n return factorData;\n }\n // #region BladesRoll.OppositionDoc Implementation\n get rollOppID() { return this.id; }\n get rollOppDoc() { return this; }\n get rollOppImg() { return this.img; }\n get rollOppName() { return this.name; }\n get rollOppSubName() { return this.system.subtitle || this.system.concept || \" \"; }\n get rollOppType() { return this.type; }\n get rollOppModsSchemaSet() { return []; }\n // #endregion\n // #region BladesRoll.ParticipantDoc Implementation\n get rollParticipantID() { return this.id; }\n get rollParticipantDoc() { return this; }\n get rollParticipantIcon() { return this.img; }\n get rollParticipantName() { return this.name; }\n get rollParticipantType() { return this.type; }\n get rollParticipantModsSchemaSet() { return []; }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesNPC);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvYWN0b3JzL0JsYWRlc05QQy50cyIsIm1hcHBpbmdzIjoiOzs7O0FBQStEO0FBQ25CO0FBQ21CO0FBQy9ELHdCQUF3QixvREFBVztBQUNuQztBQUNBO0FBQ0Esb0NBQW9DLHlCQUF5Qix3RUFBRTtBQUMvRCx1Q0FBdUMsb0VBQWMsSUFBSSxtQ0FBbUM7QUFDNUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQ0FBaUMsNERBQWU7QUFDaEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsbURBQU07QUFDekIsa0JBQWtCLG1EQUFNO0FBQ3hCO0FBQ0EsdUNBQXVDLG1EQUFNO0FBQzdDLHFDQUFxQyxtREFBTTtBQUMzQyx5Q0FBeUMsbURBQU07QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLG1EQUFNO0FBQ3pCLGtCQUFrQixtREFBTTtBQUN4QjtBQUNBLHVDQUF1QyxtREFBTTtBQUM3QyxxQ0FBcUMsbURBQU07QUFDM0MseUNBQXlDLG1EQUFNO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIsdUJBQXVCO0FBQ3ZCLHVCQUF1QjtBQUN2Qix3QkFBd0I7QUFDeEIsMkJBQTJCO0FBQzNCLHdCQUF3QjtBQUN4QixpQ0FBaUM7QUFDakM7QUFDQTtBQUNBLDhCQUE4QjtBQUM5QiwrQkFBK0I7QUFDL0IsZ0NBQWdDO0FBQ2hDLGdDQUFnQztBQUNoQyxnQ0FBZ0M7QUFDaEMseUNBQXlDO0FBQ3pDO0FBQ0EsK0RBQWUsU0FBUyxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2FjdG9ycy9CbGFkZXNOUEMudHM/YmRiMyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBCbGFkZXNBY3RvclR5cGUsIEZhY3RvciB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IEJsYWRlc0FjdG9yIGZyb20gXCIuLi8uLi9CbGFkZXNBY3RvclwiO1xuaW1wb3J0IEJsYWRlc05QQ1NoZWV0IGZyb20gXCIuLi8uLi9zaGVldHMvYWN0b3IvQmxhZGVzTlBDU2hlZXRcIjtcbmNsYXNzIEJsYWRlc05QQyBleHRlbmRzIEJsYWRlc0FjdG9yIHtcbiAgICAvLyAjcmVnaW9uIElOSVRJQUxJWkFUSU9OIH5cbiAgICBzdGF0aWMgYXN5bmMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihnbG9iYWxUaGlzLCB7IEJsYWRlc05QQywgQmxhZGVzTlBDU2hlZXQgfSk7XG4gICAgICAgIEFjdG9ycy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc05QQ1NoZWV0LCB7IHR5cGVzOiBbXCJucGNcIl0sIG1ha2VEZWZhdWx0OiB0cnVlIH0pO1xuICAgICAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyhbXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvbnBjLXNoZWV0Lmhic1wiXSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBzdGF0aWMgSXNUeXBlKGRvYykge1xuICAgICAgICByZXR1cm4gc3VwZXIuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLm5wYyk7XG4gICAgfVxuICAgIC8vICNyZWdpb24gQmxhZGVzUm9sbCBJbXBsZW1lbnRhdGlvblxuICAgIGdldCByb2xsRmFjdG9ycygpIHtcbiAgICAgICAgY29uc3QgZmFjdG9yRGF0YSA9IHN1cGVyLnJvbGxGYWN0b3JzO1xuICAgICAgICBmYWN0b3JEYXRhW0ZhY3Rvci5zY2FsZV0gPSB7XG4gICAgICAgICAgICBuYW1lOiBGYWN0b3Iuc2NhbGUsXG4gICAgICAgICAgICBkaXNwbGF5OiBcIlNjYWxlXCIsXG4gICAgICAgICAgICB2YWx1ZTogdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3Iuc2NhbGUpLFxuICAgICAgICAgICAgbWF4OiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5zY2FsZSksXG4gICAgICAgICAgICBiYXNlVmFsOiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5zY2FsZSksXG4gICAgICAgICAgICBjc3NDbGFzc2VzOiBcImZhY3Rvci1ncmV5XCIsXG4gICAgICAgICAgICBpc0FjdGl2ZTogZmFsc2UsXG4gICAgICAgICAgICBpc1ByaW1hcnk6IGZhbHNlLFxuICAgICAgICAgICAgaXNEb21pbmFudDogZmFsc2UsXG4gICAgICAgICAgICBoaWdoRmF2b3JzUEM6IHRydWVcbiAgICAgICAgfTtcbiAgICAgICAgZmFjdG9yRGF0YVtGYWN0b3IubWFnbml0dWRlXSA9IHtcbiAgICAgICAgICAgIG5hbWU6IEZhY3Rvci5tYWduaXR1ZGUsXG4gICAgICAgICAgICBkaXNwbGF5OiBcIk1hZ25pdHVkZVwiLFxuICAgICAgICAgICAgdmFsdWU6IHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLm1hZ25pdHVkZSksXG4gICAgICAgICAgICBtYXg6IHRoaXMuZ2V0RmFjdG9yVG90YWwoRmFjdG9yLm1hZ25pdHVkZSksXG4gICAgICAgICAgICBiYXNlVmFsOiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci5tYWduaXR1ZGUpLFxuICAgICAgICAgICAgaXNBY3RpdmU6IGZhbHNlLFxuICAgICAgICAgICAgaXNQcmltYXJ5OiBmYWxzZSxcbiAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgaGlnaEZhdm9yc1BDOiB0cnVlXG4gICAgICAgIH07XG4gICAgICAgIHJldHVybiBmYWN0b3JEYXRhO1xuICAgIH1cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwuT3Bwb3NpdGlvbkRvYyBJbXBsZW1lbnRhdGlvblxuICAgIGdldCByb2xsT3BwSUQoKSB7IHJldHVybiB0aGlzLmlkOyB9XG4gICAgZ2V0IHJvbGxPcHBEb2MoKSB7IHJldHVybiB0aGlzOyB9XG4gICAgZ2V0IHJvbGxPcHBJbWcoKSB7IHJldHVybiB0aGlzLmltZzsgfVxuICAgIGdldCByb2xsT3BwTmFtZSgpIHsgcmV0dXJuIHRoaXMubmFtZTsgfVxuICAgIGdldCByb2xsT3BwU3ViTmFtZSgpIHsgcmV0dXJuIHRoaXMuc3lzdGVtLnN1YnRpdGxlIHx8IHRoaXMuc3lzdGVtLmNvbmNlcHQgfHwgXCIgXCI7IH1cbiAgICBnZXQgcm9sbE9wcFR5cGUoKSB7IHJldHVybiB0aGlzLnR5cGU7IH1cbiAgICBnZXQgcm9sbE9wcE1vZHNTY2hlbWFTZXQoKSB7IHJldHVybiBbXTsgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIEJsYWRlc1JvbGwuUGFydGljaXBhbnREb2MgSW1wbGVtZW50YXRpb25cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50SUQoKSB7IHJldHVybiB0aGlzLmlkOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudERvYygpIHsgcmV0dXJuIHRoaXM7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50SWNvbigpIHsgcmV0dXJuIHRoaXMuaW1nOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudE5hbWUoKSB7IHJldHVybiB0aGlzLm5hbWU7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50VHlwZSgpIHsgcmV0dXJuIHRoaXMudHlwZTsgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnRNb2RzU2NoZW1hU2V0KCkgeyByZXR1cm4gW107IH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc05QQztcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/documents/actors/BladesNPC.ts\n"); + +/***/ }), + +/***/ "./ts/documents/actors/BladesPC.ts": +/*!*****************************************!*\ + !*** ./ts/documents/actors/BladesPC.ts ***! + \*****************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _sheets_actor_BladesPCSheet__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../sheets/actor/BladesPCSheet */ \"./ts/sheets/actor/BladesPCSheet.ts\");\n/* harmony import */ var _BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../classes/BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n/* harmony import */ var _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../classes/BladesDirector */ \"./ts/classes/BladesDirector.ts\");\n/* harmony import */ var _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../classes/BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n\n\n\n\n\n\n\n\nclass BladesPC extends _BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesPC, BladesPCSheet: _sheets_actor_BladesPCSheet__WEBPACK_IMPORTED_MODULE_3__[\"default\"] });\n Actors.registerSheet(\"blades\", _sheets_actor_BladesPCSheet__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { types: [\"pc\"], makeDefault: true });\n Hooks.on(\"dropActorSheetData\", async (parentActor, _, { uuid }) => {\n const doc = fromUuidSync(uuid);\n if (doc instanceof _BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor) {\n if (parentActor.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew && doc.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc) {\n // Dropping a PC onto a Crew Sheet: Add Crew to PC\n doc.addSubActor(parentActor);\n }\n else if (parentActor.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc && doc.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew) {\n // Dropping a Crew onto a PC Sheet: Add\n parentActor.addSubActor(doc);\n }\n }\n });\n return loadTemplates([\"systems/eunos-blades/templates/actor-sheet.hbs\"]);\n }\n // #endregion\n // #region Static Overrides: Create, get All ~\n // static override IsType(doc: unknown): doc is BladesActorOfType {\n // return super.IsType(doc, BladesActorType.pc);\n // }\n static IsType(doc) {\n return super.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc);\n }\n static GetUser(userRef) {\n let user;\n if (typeof userRef === \"string\") {\n user = game.users.get(userRef) ?? game.users.getName(userRef);\n }\n else if (userRef instanceof User) {\n user = userRef;\n }\n return user;\n }\n static GetFromUser(userRef) {\n const user = BladesPC.GetUser(userRef);\n if (!user) {\n throw new Error(`Unable to find user '${userRef}'`);\n }\n const actor = game.actors.get(user.character?.id ?? \"\");\n if (BladesPC.IsType(actor)) {\n return actor;\n }\n return undefined;\n }\n static async create(data, options = {}) {\n data.token = data.token || {};\n data.system = data.system ?? {};\n eLog.checkLog2(\"actor\", \"BladesPC.create(data,options)\", { data, options });\n // ~ Set the Token to sync with charsheet.\n data.token.actorLink = true;\n // ~ Initialize generic experience clues.\n data.system.experience = {\n playbook: { value: 0, max: 8 },\n insight: { value: 0, max: 6 },\n prowess: { value: 0, max: 6 },\n resolve: { value: 0, max: 6 },\n clues: [],\n ...data.system.experience ?? {}\n };\n const pc = (await super.create(data, options));\n await _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_5__[\"default\"].Create({\n name: \"\",\n target: pc,\n targetKey: \"system.clocksData\",\n isVisible: true,\n isNameVisible: false,\n isSpotlit: false\n }, undefined, [\n {\n color: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.white,\n value: 0,\n max: 4,\n index: 0,\n isVisible: true,\n isActive: true,\n isNameVisible: false,\n isHighlighted: false\n }\n ]);\n return pc;\n }\n static get All() {\n return new Collection(super.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)\n .map((pc) => [pc.id, pc]));\n }\n // #endregion\n constructor(data) {\n super(data);\n eLog.checkLog3(\"pcConstructor\", \"new BladesPC()\", { data });\n }\n // #region BladesPrimaryActor Implementation ~\n get primaryUser() {\n return game.users?.find((user) => user.character?.id === this?.id) || null;\n }\n async clearLoadout() {\n await this.update({ \"system.loadout.selected\": \"\" });\n this.updateEmbeddedDocuments(\"Item\", [\n ...this.activeSubItems\n .filter((item) => _BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)\n && !item.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.System.Archived))\n .map((item) => ({\n _id: item.id,\n \"system.tags\": [...item.tags, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.System.Archived],\n \"system.uses_per_score.value\": 0\n })),\n ...this.activeSubItems\n .filter((item) => _BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability)\n && item.system.uses_per_score.max)\n .map((item) => ({\n _id: item.id,\n \"system.uses_per_score.value\": 0\n }))\n ]);\n }\n // #endregion\n getSubActor(actorRef) {\n const actor = super.getSubActor(actorRef);\n if (!actor) {\n return undefined;\n }\n if (this.primaryUser?.id) {\n actor.ownership[this.primaryUser.id] = CONST.DOCUMENT_PERMISSION_LEVELS.OWNER;\n }\n return actor;\n }\n get isLightArmorEquipped() { return this.system.armor.active.light; }\n get isLightArmorEquippable() { return !this.isLightArmorEquipped && this.remainingLoad >= 2; }\n get isLightArmorUsed() { return this.system.armor.checked.light; }\n get isLightArmorAvailable() {\n return (this.isLightArmorEquipped || this.isLightArmorEquippable)\n && !this.isLightArmorUsed;\n }\n get isHeavyArmorEquipped() { return this.system.armor.active.heavy; }\n get isHeavyArmorEquippable() {\n if (this.isHeavyArmorEquipped) {\n return false;\n }\n if (this.isLightArmorEquipped) {\n return this.remainingLoad >= 3;\n }\n return this.remainingLoad >= 5;\n }\n get isHeavyArmorUsed() { return this.system.armor.checked.heavy; }\n get isHeavyArmorAvailable() {\n return (this.isHeavyArmorEquipped || this.isHeavyArmorEquippable)\n && !this.isHeavyArmorUsed;\n }\n get availableArmor() {\n const armor = [];\n if (this.isLightArmorAvailable) {\n armor.push(\"Light Armor\");\n }\n if (this.isHeavyArmorAvailable) {\n armor.push(\"Heavy Armor\");\n }\n return armor;\n }\n get isSpecialArmorAvailable() {\n return this.system.armor.active.special && !this.system.armor.checked.special;\n }\n // #region BladesScoundrel Implementation ~\n isMember(crew) { return this.crew?.id === crew.id; }\n get vice() {\n if (this.type !== _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc) {\n return undefined;\n }\n return this.activeSubItems.find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice);\n }\n get crew() {\n return this.activeSubActors\n .find((subActor) => _BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(subActor, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew));\n }\n get abilities() {\n if (!this.playbook) {\n return [];\n }\n return this.activeSubItems\n .filter((item) => [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_ability].includes(item.type));\n }\n get cohorts() {\n return this.activeSubItems\n .filter((item) => _BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert));\n }\n get playbookName() {\n return this.playbook?.name;\n }\n get playbook() {\n return this.activeSubItems\n .find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook);\n }\n get attributes() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return undefined;\n }\n return {\n insight: Object.values(this.system.attributes.insight)\n .filter(({ value }) => value > 0).length\n + this.system.resistance_bonus.insight,\n prowess: Object.values(this.system.attributes.prowess)\n .filter(({ value }) => value > 0).length\n + this.system.resistance_bonus.prowess,\n resolve: Object.values(this.system.attributes.resolve)\n .filter(({ value }) => value > 0).length\n + this.system.resistance_bonus.resolve\n };\n }\n get actions() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return undefined;\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objMap({\n ...this.system.attributes.insight,\n ...this.system.attributes.prowess,\n ...this.system.attributes.resolve\n }, ({ value, max }) => _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.utils.clamp(0, max, value));\n }\n get rollable() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return undefined;\n }\n return {\n ...this.attributes,\n ...this.actions\n };\n }\n get stress() {\n return this.system.stress.value;\n }\n get stressMax() {\n return this.system.stress.max;\n }\n get isHealingClockReady() {\n const [clockKeyID] = Object.keys(this.system.clocksData);\n return game.eunoblades.ClockKeys.has(clockKeyID ?? \"\");\n }\n get healingClock() {\n if (!this.isHealingClockReady) {\n return undefined;\n }\n const [clockKeyID] = Object.keys(this.system.clocksData);\n const clockKey = game.eunoblades.ClockKeys.get(clockKeyID ?? \"\");\n return clockKey;\n }\n get harmLevel() {\n if (this.system.harm.severe.one.length > 1) {\n return 3;\n }\n if ((this.system.harm.moderate.one.length + this.system.harm.moderate.two.length) > 0) {\n return 2;\n }\n if ((this.system.harm.lesser.one.length + this.system.harm.lesser.two.length) > 0) {\n return 1;\n }\n return 0;\n }\n get trauma() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return 0;\n }\n return Object.keys(this.system.trauma.checked)\n .filter((traumaName) => \n // @ts-ignore Compiler linter mismatch.\n this.system.trauma.active[traumaName] && this.system.trauma.checked[traumaName])\n .length;\n }\n get traumaList() {\n // @ts-ignore Compiler linter mismatch.\n return _BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)\n ? Object.keys(this.system.trauma.active).filter((key) => this.system.trauma.active[key])\n : [];\n }\n get activeTraumaConditions() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return {};\n }\n return _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objFilter(this.system.trauma.checked, \n // @ts-ignore Compiler linter mismatch.\n (_v, traumaName) => Boolean(traumaName in this.system.trauma.active\n && this.system.trauma.active[traumaName]));\n }\n get currentLoad() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return 0;\n }\n const activeLoadItems = this.activeSubItems.filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear);\n return _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].gsap.utils.clamp(0, 10, activeLoadItems.reduce((tot, i) => tot + _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt(i.system.load), 0));\n }\n get remainingLoad() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return 0;\n }\n if (!this.system.loadout.selected) {\n return 0;\n }\n const maxLoad = this.system.loadout.levels[game.i18n.localize(this.system.loadout.selected.toString())\n .toLowerCase()];\n return Math.max(0, maxLoad - this.currentLoad);\n }\n async addStash(amount) {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return;\n }\n await this.update({ \"system.stash.value\": Math.min(this.system.stash.value + amount, this.system.stash.max) });\n }\n get projects() {\n return this.getSubItemsOfType(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project);\n }\n get remainingDowntimeActions() {\n if (!_BladesActorProxy__WEBPACK_IMPORTED_MODULE_2__.BladesActor.IsType(this, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return 0;\n }\n return this.system.downtime_actions.max + this.system.downtime_action_bonus - this.system.downtime_actions.value;\n }\n _processAbilityDialogItems(dialogData) {\n if (!this.playbookName) {\n return;\n }\n dialogData[this.playbookName] = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability, this.playbookName));\n dialogData.Veteran = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability))\n .filter((item) => !item.hasTag(this.playbookName))\n // Remove featured class from Veteran items\n .map((item) => {\n if (item.dialogCSSClasses) {\n item.dialogCSSClasses = item.dialogCSSClasses.replace(/featured-item\\s?/g, \"\");\n }\n return item;\n })\n // Re-sort by world_name\n .sort((a, b) => {\n if (a.system.world_name > b.system.world_name) {\n return 1;\n }\n if (a.system.world_name < b.system.world_name) {\n return -1;\n }\n return 0;\n });\n }\n processGearDialogItems(dialogData) {\n if (this.playbookName === null) {\n return;\n }\n const gearItems = this._processEmbeddedItemMatches([\n ..._BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear, this.playbookName),\n ..._BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.General)\n ])\n .filter((item) => this.remainingLoad >= item.system.load);\n // Two tabs, one for playbook and the other for general items\n dialogData[this.playbookName] = gearItems.filter((item) => item.hasTag(this.playbookName));\n dialogData.General = gearItems\n .filter((item) => item.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.General))\n // Remove featured class from General items\n .map((item) => {\n if (item.dialogCSSClasses) {\n item.dialogCSSClasses = item.dialogCSSClasses.replace(/featured-item\\s?/g, \"\");\n }\n return item;\n })\n // Re-sort by world_name\n .sort((a, b) => {\n if (a.system.world_name > b.system.world_name) {\n return 1;\n }\n if (a.system.world_name < b.system.world_name) {\n return -1;\n }\n return 0;\n });\n }\n getDialogItems(category) {\n const dialogData = {};\n const { playbookName } = this;\n if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Heritage) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.heritage));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Background) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.background));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Vice && playbookName !== null) {\n dialogData.Main = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice, playbookName));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Playbook) {\n dialogData.Basic = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook)\n .filter((item) => !item.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.Advanced)));\n dialogData.Advanced = this._processEmbeddedItemMatches(_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesItem.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.Advanced));\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Gear) {\n this.processGearDialogItems(dialogData);\n }\n else if (category === _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_7__.SelectionCategory.Ability) {\n this._processAbilityDialogItems(dialogData);\n }\n return dialogData;\n }\n getTaggedItemBonuses(tags) {\n // Given a list of item tags, will return the total bonuses to that item\n // Won't return a number, but an object literal that includes things like extra load space or concealability\n // Check ACTIVE EFFECTS supplied by ability against submitted tags?\n // Should INCLUDE bonuses from crew.\n return tags.length; // Placeholder to avoid linter error\n }\n // #endregion\n // #region BladesRoll.PrimaryDoc Implementation\n get rollPrimaryModsSchemaSet() {\n const rollModsSchemaSet = super.rollPrimaryModsSchemaSet;\n // Add roll mods from harm\n [\n [/1d/, _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModSection.roll],\n [/Less Effect/, _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModSection.effect]\n ].forEach(([effectPat, effectCat]) => {\n const { one: harmConditionOne, two: harmConditionTwo } = Object.values(this.system.harm)\n .find((harmData) => effectPat.test(harmData.effect)) ?? {};\n const harmString = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objCompact([harmConditionOne, harmConditionTwo === \"\" ? null : harmConditionTwo]).join(\" & \");\n if (harmString.length > 0) {\n rollModsSchemaSet.push({\n key: `Harm-negative-${effectCat}`,\n name: harmString,\n section: effectCat,\n posNeg: \"negative\",\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModStatus.ToggledOn,\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModType.harm,\n value: 1,\n tooltip: [\n `

${effectCat === _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModSection.roll ? _core_constants__WEBPACK_IMPORTED_MODULE_0__.Harm.Impaired : _core_constants__WEBPACK_IMPORTED_MODULE_0__.Harm.Weakened} (Harm)

`,\n `

${harmString}

`,\n effectCat === _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModSection.roll\n ? \"

If your injuries apply to the situation at hand, you suffer −1d to your roll.

\"\n : \"

If your injuries apply to the situation at hand, you suffer −1 effect.\"\n ].join(\"\")\n });\n }\n });\n const { one: harmCondition } = Object.values(this.system.harm)\n .find((harmData) => /Need Help/.test(harmData.effect)) ?? {};\n if (harmCondition && harmCondition.trim() !== \"\") {\n rollModsSchemaSet.push({\n key: \"Push-negative-roll\",\n name: \"PUSH\",\n sideString: harmCondition.trim(),\n section: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModSection.roll,\n posNeg: \"negative\",\n base_status: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModStatus.ToggledOn,\n modType: _core_constants__WEBPACK_IMPORTED_MODULE_0__.RollModType.harm,\n value: 0,\n effectKeys: [\"Cost-Stress2\"],\n tooltip: [\n \"

Broken (Harm)

\",\n `

${harmCondition.trim()}

`,\n \"

If your injuries apply to the situation at hand, you must Push to act.

\"\n ].join(\"\")\n });\n }\n return rollModsSchemaSet;\n }\n async applyHarm(num, name) {\n if (num === 4) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} Suffers FATAL Harm: ${name}`,\n body: `${this.name}, will you continue as a Ghost, or create a new character?`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"harm-alert fatal-harm-alert\"\n });\n return;\n }\n // Construct sequence of harm keys to check, starting with given harm level.\n const harmSequence = [\n [[\"lesser\", \"one\"], [\"lesser\", \"two\"]],\n [[\"moderate\", \"one\"], [\"moderate\", \"two\"]],\n [[\"severe\", \"one\"]]\n ].slice(num - 1).flat(1);\n while (harmSequence.length) {\n const theseHarmKeys = harmSequence.shift();\n if (!theseHarmKeys) {\n break;\n }\n const [thisHarmLevel, thisHarmKey] = theseHarmKeys;\n const thisHarmVal = this.system.harm[thisHarmLevel][thisHarmKey];\n if (!thisHarmVal) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} Suffers ${_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].tCase(thisHarmLevel)} Harm: ${name}`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"harm-alert\"\n });\n await this.update({ [`system.harm.${thisHarmLevel}.${thisHarmKey}`]: name });\n return;\n }\n }\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} Suffers a Catastrophic, Permanent Injury!`,\n body: `${this.name}, you're out of the action - either left for dead, or otherwise dropped from the action. You can choose to return at the beginning of the next Phase with a permanent injury, or die.`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"harm-alert fatal-harm-alert\"\n });\n }\n async applyWorsePosition() {\n this.setFlag(\"eunos-blades\", \"isWorsePosition\", true);\n }\n // #endregion\n // #region BladesRoll.ParticipantDoc Implementation\n get rollParticipantID() { return this.id; }\n get rollParticipantDoc() { return this; }\n get rollParticipantIcon() { return this.playbook?.img ?? this.img; }\n get rollParticipantName() { return this.name ?? \"\"; }\n get rollParticipantType() { return this.type; }\n get rollParticipantModsSchemaSet() { return []; }\n // #endregion\n async adjustStress(deltaStress) {\n const newStress = Math.min(this.stressMax, Math.max(0, this.stress + deltaStress));\n if (newStress === this.stressMax) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} breaks under the stress!`,\n body: `${this.name}: Select a Trauma Condition on your sheet. You are taken out of action and will no longer participate in this score. Narrate what happens.`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"stress-alert\"\n });\n await this.update({ \"system.stress.value\": 0 });\n return;\n }\n await this.update({ \"system.stress.value\": newStress });\n }\n async indulgeStress(deltaStress) {\n if (deltaStress > this.stress) {\n _classes_BladesDirector__WEBPACK_IMPORTED_MODULE_6__[\"default\"].getInstance().pushNotice_SocketCall(\"ALL\", {\n title: `${this.name} Overindulges!`,\n body: `${this.name}: Select an option from the list below, and narrate how overindulging your vice led to this result:
  • Attract Trouble: Roll for an Entanglement.
  • Brag About Your Exploits: +2 Heat
  • Go AWOL Vanish for a few weeks. (You will play a different character until the next Downtime Phase, at which point you will return with all Harm healed.)
  • Tapped: Your current Vice Purveyor cuts you off. (Until you find a new source for your vice, you will be unable to Indulge Vice during Downtime.)
`,\n type: _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesNoticeType.push,\n cssClasses: \"stress-alert\"\n });\n }\n await this.update({ \"system.stress.value\": this.stress - deltaStress });\n }\n async spendArmor(amount) {\n const updateData = {};\n while (amount > 0) {\n if (this.isLightArmorAvailable) {\n if (!this.isLightArmorEquipped) {\n updateData[\"system.armor.active.light\"] = true;\n }\n updateData[\"system.armor.checked.light\"] = true;\n }\n else if (this.isHeavyArmorAvailable) {\n if (!this.isHeavyArmorEquipped) {\n updateData[\"system.armor.active.heavy\"] = true;\n }\n updateData[\"system.armor.checked.heavy\"] = true;\n }\n else {\n throw new Error(\"No armor available to spend\");\n }\n amount--;\n }\n this.update(updateData);\n }\n async spendSpecialArmor() {\n if (this.system.armor.active.special && !this.system.armor.checked.special) {\n await this.update({ \"system.armor.checked.special\": true });\n }\n }\n get rollTraitPCTooltipActions() {\n const tooltipStrings = [\"\"];\n const actionRatings = this.actions;\n Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait).forEach((attribute) => {\n _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Action[attribute].forEach((action) => {\n tooltipStrings.push([\n \"\",\n ``,\n ``,\n ``,\n \"\"\n ].join(\"\"));\n });\n });\n tooltipStrings.push(\"
${_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].uCase(action)}${\"⚪\".repeat(actionRatings[action])}(${_core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ShortActionTooltips[action]})
\");\n return tooltipStrings.join(\"\");\n }\n get rollTraitPCTooltipAttributes() {\n const tooltipStrings = [\"\"];\n const attributeRatings = this.attributes;\n Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait).forEach((attribute) => {\n tooltipStrings.push([\n \"\",\n ``,\n ``,\n ``,\n \"\"\n ].join(\"\"));\n });\n tooltipStrings.push(\"
${_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].uCase(attribute)}${\"⚪\".repeat(attributeRatings[attribute])}(${_core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ShortAttributeTooltips[attribute]})
\");\n return tooltipStrings.join(\"\");\n }\n // #endregion\n render(force) {\n if (!this.isHealingClockReady) {\n setTimeout(() => this.render(force), 1000);\n return;\n }\n super.render(force);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesPC);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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O0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsK0RBQWUsUUFBUSxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2FjdG9ycy9CbGFkZXNQQy50cz84OTdlIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBDLCB7IEJsYWRlc05vdGljZVR5cGUsIENsb2NrQ29sb3IsIEF0dHJpYnV0ZVRyYWl0LCBIYXJtLCBCbGFkZXNBY3RvclR5cGUsIEJsYWRlc0l0ZW1UeXBlLCBUYWcsIFJvbGxNb2RUeXBlLCBSb2xsTW9kU2VjdGlvbiwgUm9sbE1vZFN0YXR1cyB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IFUgZnJvbSBcIi4uLy4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBCbGFkZXNBY3RvciB9IGZyb20gXCIuLi9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgQmxhZGVzUENTaGVldCBmcm9tIFwiLi4vLi4vc2hlZXRzL2FjdG9yL0JsYWRlc1BDU2hlZXRcIjtcbmltcG9ydCB7IEJsYWRlc0l0ZW0gfSBmcm9tIFwiLi4vQmxhZGVzSXRlbVByb3h5XCI7XG5pbXBvcnQgQmxhZGVzQ2xvY2tLZXkgZnJvbSBcIi4uLy4uL2NsYXNzZXMvQmxhZGVzQ2xvY2tLZXlcIjtcbmltcG9ydCBCbGFkZXNEaXJlY3RvciBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNEaXJlY3RvclwiO1xuaW1wb3J0IHsgU2VsZWN0aW9uQ2F0ZWdvcnkgfSBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNEaWFsb2dcIjtcbmNsYXNzIEJsYWRlc1BDIGV4dGVuZHMgQmxhZGVzQWN0b3Ige1xuICAgIC8vICNyZWdpb24gSU5JVElBTElaQVRJT04gflxuICAgIHN0YXRpYyBhc3luYyBJbml0aWFsaXplKCkge1xuICAgICAgICBPYmplY3QuYXNzaWduKGdsb2JhbFRoaXMsIHsgQmxhZGVzUEMsIEJsYWRlc1BDU2hlZXQgfSk7XG4gICAgICAgIEFjdG9ycy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc1BDU2hlZXQsIHsgdHlwZXM6IFtcInBjXCJdLCBtYWtlRGVmYXVsdDogdHJ1ZSB9KTtcbiAgICAgICAgSG9va3Mub24oXCJkcm9wQWN0b3JTaGVldERhdGFcIiwgYXN5bmMgKHBhcmVudEFjdG9yLCBfLCB7IHV1aWQgfSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZG9jID0gZnJvbVV1aWRTeW5jKHV1aWQpO1xuICAgICAgICAgICAgaWYgKGRvYyBpbnN0YW5jZW9mIEJsYWRlc0FjdG9yKSB7XG4gICAgICAgICAgICAgICAgaWYgKHBhcmVudEFjdG9yLnR5cGUgPT09IEJsYWRlc0FjdG9yVHlwZS5jcmV3ICYmIGRvYy50eXBlID09PSBCbGFkZXNBY3RvclR5cGUucGMpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRHJvcHBpbmcgYSBQQyBvbnRvIGEgQ3JldyBTaGVldDogQWRkIENyZXcgdG8gUENcbiAgICAgICAgICAgICAgICAgICAgZG9jLmFkZFN1YkFjdG9yKHBhcmVudEFjdG9yKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAocGFyZW50QWN0b3IudHlwZSA9PT0gQmxhZGVzQWN0b3JUeXBlLnBjICYmIGRvYy50eXBlID09PSBCbGFkZXNBY3RvclR5cGUuY3Jldykge1xuICAgICAgICAgICAgICAgICAgICAvLyBEcm9wcGluZyBhIENyZXcgb250byBhIFBDIFNoZWV0OiBBZGRcbiAgICAgICAgICAgICAgICAgICAgcGFyZW50QWN0b3IuYWRkU3ViQWN0b3IoZG9jKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyhbXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvYWN0b3Itc2hlZXQuaGJzXCJdKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIC8vICNyZWdpb24gU3RhdGljIE92ZXJyaWRlczogQ3JlYXRlLCBnZXQgQWxsIH5cbiAgICAvLyBzdGF0aWMgb3ZlcnJpZGUgSXNUeXBlPFQgZXh0ZW5kcyBCbGFkZXNBY3RvclR5cGUgPSBCbGFkZXNBY3RvclR5cGUucGM+KGRvYzogdW5rbm93bik6IGRvYyBpcyBCbGFkZXNBY3Rvck9mVHlwZTxUPiB7XG4gICAgLy8gICByZXR1cm4gc3VwZXIuSXNUeXBlKGRvYywgQmxhZGVzQWN0b3JUeXBlLnBjKTtcbiAgICAvLyB9XG4gICAgc3RhdGljIElzVHlwZShkb2MpIHtcbiAgICAgICAgcmV0dXJuIHN1cGVyLklzVHlwZShkb2MsIEJsYWRlc0FjdG9yVHlwZS5wYyk7XG4gICAgfVxuICAgIHN0YXRpYyBHZXRVc2VyKHVzZXJSZWYpIHtcbiAgICAgICAgbGV0IHVzZXI7XG4gICAgICAgIGlmICh0eXBlb2YgdXNlclJlZiA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgdXNlciA9IGdhbWUudXNlcnMuZ2V0KHVzZXJSZWYpID8/IGdhbWUudXNlcnMuZ2V0TmFtZSh1c2VyUmVmKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh1c2VyUmVmIGluc3RhbmNlb2YgVXNlcikge1xuICAgICAgICAgICAgdXNlciA9IHVzZXJSZWY7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVzZXI7XG4gICAgfVxuICAgIHN0YXRpYyBHZXRGcm9tVXNlcih1c2VyUmVmKSB7XG4gICAgICAgIGNvbnN0IHVzZXIgPSBCbGFkZXNQQy5HZXRVc2VyKHVzZXJSZWYpO1xuICAgICAgICBpZiAoIXVzZXIpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5hYmxlIHRvIGZpbmQgdXNlciAnJHt1c2VyUmVmfSdgKTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBhY3RvciA9IGdhbWUuYWN0b3JzLmdldCh1c2VyLmNoYXJhY3Rlcj8uaWQgPz8gXCJcIik7XG4gICAgICAgIGlmIChCbGFkZXNQQy5Jc1R5cGUoYWN0b3IpKSB7XG4gICAgICAgICAgICByZXR1cm4gYWN0b3I7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc3RhdGljIGFzeW5jIGNyZWF0ZShkYXRhLCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgZGF0YS50b2tlbiA9IGRhdGEudG9rZW4gfHwge307XG4gICAgICAgIGRhdGEuc3lzdGVtID0gZGF0YS5zeXN0ZW0gPz8ge307XG4gICAgICAgIGVMb2cuY2hlY2tMb2cyKFwiYWN0b3JcIiwgXCJCbGFkZXNQQy5jcmVhdGUoZGF0YSxvcHRpb25zKVwiLCB7IGRhdGEsIG9wdGlvbnMgfSk7XG4gICAgICAgIC8vIH4gU2V0IHRoZSBUb2tlbiB0byBzeW5jIHdpdGggY2hhcnNoZWV0LlxuICAgICAgICBkYXRhLnRva2VuLmFjdG9yTGluayA9IHRydWU7XG4gICAgICAgIC8vIH4gSW5pdGlhbGl6ZSBnZW5lcmljIGV4cGVyaWVuY2UgY2x1ZXMuXG4gICAgICAgIGRhdGEuc3lzdGVtLmV4cGVyaWVuY2UgPSB7XG4gICAgICAgICAgICBwbGF5Ym9vazogeyB2YWx1ZTogMCwgbWF4OiA4IH0sXG4gICAgICAgICAgICBpbnNpZ2h0OiB7IHZhbHVlOiAwLCBtYXg6IDYgfSxcbiAgICAgICAgICAgIHByb3dlc3M6IHsgdmFsdWU6IDAsIG1heDogNiB9LFxuICAgICAgICAgICAgcmVzb2x2ZTogeyB2YWx1ZTogMCwgbWF4OiA2IH0sXG4gICAgICAgICAgICBjbHVlczogW10sXG4gICAgICAgICAgICAuLi5kYXRhLnN5c3RlbS5leHBlcmllbmNlID8/IHt9XG4gICAgICAgIH07XG4gICAgICAgIGNvbnN0IHBjID0gKGF3YWl0IHN1cGVyLmNyZWF0ZShkYXRhLCBvcHRpb25zKSk7XG4gICAgICAgIGF3YWl0IEJsYWRlc0Nsb2NrS2V5LkNyZWF0ZSh7XG4gICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgICAgICAgICAgdGFyZ2V0OiBwYyxcbiAgICAgICAgICAgIHRhcmdldEtleTogXCJzeXN0ZW0uY2xvY2tzRGF0YVwiLFxuICAgICAgICAgICAgaXNWaXNpYmxlOiB0cnVlLFxuICAgICAgICAgICAgaXNOYW1lVmlzaWJsZTogZmFsc2UsXG4gICAgICAgICAgICBpc1Nwb3RsaXQ6IGZhbHNlXG4gICAgICAgIH0sIHVuZGVmaW5lZCwgW1xuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGNvbG9yOiBDbG9ja0NvbG9yLndoaXRlLFxuICAgICAgICAgICAgICAgIHZhbHVlOiAwLFxuICAgICAgICAgICAgICAgIG1heDogNCxcbiAgICAgICAgICAgICAgICBpbmRleDogMCxcbiAgICAgICAgICAgICAgICBpc1Zpc2libGU6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNOYW1lVmlzaWJsZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgaXNIaWdobGlnaHRlZDogZmFsc2VcbiAgICAgICAgICAgIH1cbiAgICAgICAgXSk7XG4gICAgICAgIHJldHVybiBwYztcbiAgICB9XG4gICAgc3RhdGljIGdldCBBbGwoKSB7XG4gICAgICAgIHJldHVybiBuZXcgQ29sbGVjdGlvbihzdXBlci5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzQWN0b3JUeXBlLnBjKVxuICAgICAgICAgICAgLm1hcCgocGMpID0+IFtwYy5pZCwgcGNdKSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBjb25zdHJ1Y3RvcihkYXRhKSB7XG4gICAgICAgIHN1cGVyKGRhdGEpO1xuICAgICAgICBlTG9nLmNoZWNrTG9nMyhcInBjQ29uc3RydWN0b3JcIiwgXCJuZXcgQmxhZGVzUEMoKVwiLCB7IGRhdGEgfSk7XG4gICAgfVxuICAgIC8vICNyZWdpb24gQmxhZGVzUHJpbWFyeUFjdG9yIEltcGxlbWVudGF0aW9uIH5cbiAgICBnZXQgcHJpbWFyeVVzZXIoKSB7XG4gICAgICAgIHJldHVybiBnYW1lLnVzZXJzPy5maW5kKCh1c2VyKSA9PiB1c2VyLmNoYXJhY3Rlcj8uaWQgPT09IHRoaXM/LmlkKSB8fCBudWxsO1xuICAgIH1cbiAgICBhc3luYyBjbGVhckxvYWRvdXQoKSB7XG4gICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0ubG9hZG91dC5zZWxlY3RlZFwiOiBcIlwiIH0pO1xuICAgICAgICB0aGlzLnVwZGF0ZUVtYmVkZGVkRG9jdW1lbnRzKFwiSXRlbVwiLCBbXG4gICAgICAgICAgICAuLi50aGlzLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gQmxhZGVzSXRlbS5Jc1R5cGUoaXRlbSwgQmxhZGVzSXRlbVR5cGUuZ2VhcilcbiAgICAgICAgICAgICAgICAmJiAhaXRlbS5oYXNUYWcoVGFnLlN5c3RlbS5BcmNoaXZlZCkpXG4gICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4gKHtcbiAgICAgICAgICAgICAgICBfaWQ6IGl0ZW0uaWQsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0udGFnc1wiOiBbLi4uaXRlbS50YWdzLCBUYWcuU3lzdGVtLkFyY2hpdmVkXSxcbiAgICAgICAgICAgICAgICBcInN5c3RlbS51c2VzX3Blcl9zY29yZS52YWx1ZVwiOiAwXG4gICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAuLi50aGlzLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gQmxhZGVzSXRlbS5Jc1R5cGUoaXRlbSwgQmxhZGVzSXRlbVR5cGUuYWJpbGl0eSlcbiAgICAgICAgICAgICAgICAmJiBpdGVtLnN5c3RlbS51c2VzX3Blcl9zY29yZS5tYXgpXG4gICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4gKHtcbiAgICAgICAgICAgICAgICBfaWQ6IGl0ZW0uaWQsXG4gICAgICAgICAgICAgICAgXCJzeXN0ZW0udXNlc19wZXJfc2NvcmUudmFsdWVcIjogMFxuICAgICAgICAgICAgfSkpXG4gICAgICAgIF0pO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgZ2V0U3ViQWN0b3IoYWN0b3JSZWYpIHtcbiAgICAgICAgY29uc3QgYWN0b3IgPSBzdXBlci5nZXRTdWJBY3RvcihhY3RvclJlZik7XG4gICAgICAgIGlmICghYWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMucHJpbWFyeVVzZXI/LmlkKSB7XG4gICAgICAgICAgICBhY3Rvci5vd25lcnNoaXBbdGhpcy5wcmltYXJ5VXNlci5pZF0gPSBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5PV05FUjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gYWN0b3I7XG4gICAgfVxuICAgIGdldCBpc0xpZ2h0QXJtb3JFcXVpcHBlZCgpIHsgcmV0dXJuIHRoaXMuc3lzdGVtLmFybW9yLmFjdGl2ZS5saWdodDsgfVxuICAgIGdldCBpc0xpZ2h0QXJtb3JFcXVpcHBhYmxlKCkgeyByZXR1cm4gIXRoaXMuaXNMaWdodEFybW9yRXF1aXBwZWQgJiYgdGhpcy5yZW1haW5pbmdMb2FkID49IDI7IH1cbiAgICBnZXQgaXNMaWdodEFybW9yVXNlZCgpIHsgcmV0dXJuIHRoaXMuc3lzdGVtLmFybW9yLmNoZWNrZWQubGlnaHQ7IH1cbiAgICBnZXQgaXNMaWdodEFybW9yQXZhaWxhYmxlKCkge1xuICAgICAgICByZXR1cm4gKHRoaXMuaXNMaWdodEFybW9yRXF1aXBwZWQgfHwgdGhpcy5pc0xpZ2h0QXJtb3JFcXVpcHBhYmxlKVxuICAgICAgICAgICAgJiYgIXRoaXMuaXNMaWdodEFybW9yVXNlZDtcbiAgICB9XG4gICAgZ2V0IGlzSGVhdnlBcm1vckVxdWlwcGVkKCkgeyByZXR1cm4gdGhpcy5zeXN0ZW0uYXJtb3IuYWN0aXZlLmhlYXZ5OyB9XG4gICAgZ2V0IGlzSGVhdnlBcm1vckVxdWlwcGFibGUoKSB7XG4gICAgICAgIGlmICh0aGlzLmlzSGVhdnlBcm1vckVxdWlwcGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuaXNMaWdodEFybW9yRXF1aXBwZWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnJlbWFpbmluZ0xvYWQgPj0gMztcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5yZW1haW5pbmdMb2FkID49IDU7XG4gICAgfVxuICAgIGdldCBpc0hlYXZ5QXJtb3JVc2VkKCkgeyByZXR1cm4gdGhpcy5zeXN0ZW0uYXJtb3IuY2hlY2tlZC5oZWF2eTsgfVxuICAgIGdldCBpc0hlYXZ5QXJtb3JBdmFpbGFibGUoKSB7XG4gICAgICAgIHJldHVybiAodGhpcy5pc0hlYXZ5QXJtb3JFcXVpcHBlZCB8fCB0aGlzLmlzSGVhdnlBcm1vckVxdWlwcGFibGUpXG4gICAgICAgICAgICAmJiAhdGhpcy5pc0hlYXZ5QXJtb3JVc2VkO1xuICAgIH1cbiAgICBnZXQgYXZhaWxhYmxlQXJtb3IoKSB7XG4gICAgICAgIGNvbnN0IGFybW9yID0gW107XG4gICAgICAgIGlmICh0aGlzLmlzTGlnaHRBcm1vckF2YWlsYWJsZSkge1xuICAgICAgICAgICAgYXJtb3IucHVzaChcIkxpZ2h0IEFybW9yXCIpO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmlzSGVhdnlBcm1vckF2YWlsYWJsZSkge1xuICAgICAgICAgICAgYXJtb3IucHVzaChcIkhlYXZ5IEFybW9yXCIpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBhcm1vcjtcbiAgICB9XG4gICAgZ2V0IGlzU3BlY2lhbEFybW9yQXZhaWxhYmxlKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5zeXN0ZW0uYXJtb3IuYWN0aXZlLnNwZWNpYWwgJiYgIXRoaXMuc3lzdGVtLmFybW9yLmNoZWNrZWQuc3BlY2lhbDtcbiAgICB9XG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNTY291bmRyZWwgSW1wbGVtZW50YXRpb24gflxuICAgIGlzTWVtYmVyKGNyZXcpIHsgcmV0dXJuIHRoaXMuY3Jldz8uaWQgPT09IGNyZXcuaWQ7IH1cbiAgICBnZXQgdmljZSgpIHtcbiAgICAgICAgaWYgKHRoaXMudHlwZSAhPT0gQmxhZGVzQWN0b3JUeXBlLnBjKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmFjdGl2ZVN1Ykl0ZW1zLmZpbmQoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gQmxhZGVzSXRlbVR5cGUudmljZSk7XG4gICAgfVxuICAgIGdldCBjcmV3KCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hY3RpdmVTdWJBY3RvcnNcbiAgICAgICAgICAgIC5maW5kKChzdWJBY3RvcikgPT4gQmxhZGVzQWN0b3IuSXNUeXBlKHN1YkFjdG9yLCBCbGFkZXNBY3RvclR5cGUuY3JldykpO1xuICAgIH1cbiAgICBnZXQgYWJpbGl0aWVzKCkge1xuICAgICAgICBpZiAoIXRoaXMucGxheWJvb2spIHtcbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5hY3RpdmVTdWJJdGVtc1xuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gW0JsYWRlc0l0ZW1UeXBlLmFiaWxpdHksIEJsYWRlc0l0ZW1UeXBlLmNyZXdfYWJpbGl0eV0uaW5jbHVkZXMoaXRlbS50eXBlKSk7XG4gICAgfVxuICAgIGdldCBjb2hvcnRzKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5hY3RpdmVTdWJJdGVtc1xuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gQmxhZGVzSXRlbS5Jc1R5cGUoaXRlbSwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKTtcbiAgICB9XG4gICAgZ2V0IHBsYXlib29rTmFtZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucGxheWJvb2s/Lm5hbWU7XG4gICAgfVxuICAgIGdldCBwbGF5Ym9vaygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgIC5maW5kKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rKTtcbiAgICB9XG4gICAgZ2V0IGF0dHJpYnV0ZXMoKSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGluc2lnaHQ6IE9iamVjdC52YWx1ZXModGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5pbnNpZ2h0KVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHsgdmFsdWUgfSkgPT4gdmFsdWUgPiAwKS5sZW5ndGhcbiAgICAgICAgICAgICAgICArIHRoaXMuc3lzdGVtLnJlc2lzdGFuY2VfYm9udXMuaW5zaWdodCxcbiAgICAgICAgICAgIHByb3dlc3M6IE9iamVjdC52YWx1ZXModGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5wcm93ZXNzKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHsgdmFsdWUgfSkgPT4gdmFsdWUgPiAwKS5sZW5ndGhcbiAgICAgICAgICAgICAgICArIHRoaXMuc3lzdGVtLnJlc2lzdGFuY2VfYm9udXMucHJvd2VzcyxcbiAgICAgICAgICAgIHJlc29sdmU6IE9iamVjdC52YWx1ZXModGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlKVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKHsgdmFsdWUgfSkgPT4gdmFsdWUgPiAwKS5sZW5ndGhcbiAgICAgICAgICAgICAgICArIHRoaXMuc3lzdGVtLnJlc2lzdGFuY2VfYm9udXMucmVzb2x2ZVxuICAgICAgICB9O1xuICAgIH1cbiAgICBnZXQgYWN0aW9ucygpIHtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gVS5vYmpNYXAoe1xuICAgICAgICAgICAgLi4udGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5pbnNpZ2h0LFxuICAgICAgICAgICAgLi4udGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5wcm93ZXNzLFxuICAgICAgICAgICAgLi4udGhpcy5zeXN0ZW0uYXR0cmlidXRlcy5yZXNvbHZlXG4gICAgICAgIH0sICh7IHZhbHVlLCBtYXggfSkgPT4gVS5nc2FwLnV0aWxzLmNsYW1wKDAsIG1heCwgdmFsdWUpKTtcbiAgICB9XG4gICAgZ2V0IHJvbGxhYmxlKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMpKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi50aGlzLmF0dHJpYnV0ZXMsXG4gICAgICAgICAgICAuLi50aGlzLmFjdGlvbnNcbiAgICAgICAgfTtcbiAgICB9XG4gICAgZ2V0IHN0cmVzcygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnN0cmVzcy52YWx1ZTtcbiAgICB9XG4gICAgZ2V0IHN0cmVzc01heCgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc3lzdGVtLnN0cmVzcy5tYXg7XG4gICAgfVxuICAgIGdldCBpc0hlYWxpbmdDbG9ja1JlYWR5KCkge1xuICAgICAgICBjb25zdCBbY2xvY2tLZXlJRF0gPSBPYmplY3Qua2V5cyh0aGlzLnN5c3RlbS5jbG9ja3NEYXRhKTtcbiAgICAgICAgcmV0dXJuIGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuaGFzKGNsb2NrS2V5SUQgPz8gXCJcIik7XG4gICAgfVxuICAgIGdldCBoZWFsaW5nQ2xvY2soKSB7XG4gICAgICAgIGlmICghdGhpcy5pc0hlYWxpbmdDbG9ja1JlYWR5KSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IFtjbG9ja0tleUlEXSA9IE9iamVjdC5rZXlzKHRoaXMuc3lzdGVtLmNsb2Nrc0RhdGEpO1xuICAgICAgICBjb25zdCBjbG9ja0tleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGNsb2NrS2V5SUQgPz8gXCJcIik7XG4gICAgICAgIHJldHVybiBjbG9ja0tleTtcbiAgICB9XG4gICAgZ2V0IGhhcm1MZXZlbCgpIHtcbiAgICAgICAgaWYgKHRoaXMuc3lzdGVtLmhhcm0uc2V2ZXJlLm9uZS5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICByZXR1cm4gMztcbiAgICAgICAgfVxuICAgICAgICBpZiAoKHRoaXMuc3lzdGVtLmhhcm0ubW9kZXJhdGUub25lLmxlbmd0aCArIHRoaXMuc3lzdGVtLmhhcm0ubW9kZXJhdGUudHdvLmxlbmd0aCkgPiAwKSB7XG4gICAgICAgICAgICByZXR1cm4gMjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKHRoaXMuc3lzdGVtLmhhcm0ubGVzc2VyLm9uZS5sZW5ndGggKyB0aGlzLnN5c3RlbS5oYXJtLmxlc3Nlci50d28ubGVuZ3RoKSA+IDApIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBnZXQgdHJhdW1hKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMpKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gT2JqZWN0LmtleXModGhpcy5zeXN0ZW0udHJhdW1hLmNoZWNrZWQpXG4gICAgICAgICAgICAuZmlsdGVyKCh0cmF1bWFOYW1lKSA9PiBcbiAgICAgICAgLy8gQHRzLWlnbm9yZSBDb21waWxlciBsaW50ZXIgbWlzbWF0Y2guXG4gICAgICAgIHRoaXMuc3lzdGVtLnRyYXVtYS5hY3RpdmVbdHJhdW1hTmFtZV0gJiYgdGhpcy5zeXN0ZW0udHJhdW1hLmNoZWNrZWRbdHJhdW1hTmFtZV0pXG4gICAgICAgICAgICAubGVuZ3RoO1xuICAgIH1cbiAgICBnZXQgdHJhdW1hTGlzdCgpIHtcbiAgICAgICAgLy8gQHRzLWlnbm9yZSBDb21waWxlciBsaW50ZXIgbWlzbWF0Y2guXG4gICAgICAgIHJldHVybiBCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKVxuICAgICAgICAgICAgPyBPYmplY3Qua2V5cyh0aGlzLnN5c3RlbS50cmF1bWEuYWN0aXZlKS5maWx0ZXIoKGtleSkgPT4gdGhpcy5zeXN0ZW0udHJhdW1hLmFjdGl2ZVtrZXldKVxuICAgICAgICAgICAgOiBbXTtcbiAgICB9XG4gICAgZ2V0IGFjdGl2ZVRyYXVtYUNvbmRpdGlvbnMoKSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIHJldHVybiB7fTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gVS5vYmpGaWx0ZXIodGhpcy5zeXN0ZW0udHJhdW1hLmNoZWNrZWQsIFxuICAgICAgICAvLyBAdHMtaWdub3JlIENvbXBpbGVyIGxpbnRlciBtaXNtYXRjaC5cbiAgICAgICAgKF92LCB0cmF1bWFOYW1lKSA9PiBCb29sZWFuKHRyYXVtYU5hbWUgaW4gdGhpcy5zeXN0ZW0udHJhdW1hLmFjdGl2ZVxuICAgICAgICAgICAgJiYgdGhpcy5zeXN0ZW0udHJhdW1hLmFjdGl2ZVt0cmF1bWFOYW1lXSkpO1xuICAgIH1cbiAgICBnZXQgY3VycmVudExvYWQoKSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGFjdGl2ZUxvYWRJdGVtcyA9IHRoaXMuYWN0aXZlU3ViSXRlbXMuZmlsdGVyKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmdlYXIpO1xuICAgICAgICByZXR1cm4gVS5nc2FwLnV0aWxzLmNsYW1wKDAsIDEwLCBhY3RpdmVMb2FkSXRlbXMucmVkdWNlKCh0b3QsIGkpID0+IHRvdCArIFUucEludChpLnN5c3RlbS5sb2FkKSwgMCkpO1xuICAgIH1cbiAgICBnZXQgcmVtYWluaW5nTG9hZCgpIHtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcywgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCF0aGlzLnN5c3RlbS5sb2Fkb3V0LnNlbGVjdGVkKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBtYXhMb2FkID0gdGhpcy5zeXN0ZW0ubG9hZG91dC5sZXZlbHNbZ2FtZS5pMThuLmxvY2FsaXplKHRoaXMuc3lzdGVtLmxvYWRvdXQuc2VsZWN0ZWQudG9TdHJpbmcoKSlcbiAgICAgICAgICAgIC50b0xvd2VyQ2FzZSgpXTtcbiAgICAgICAgcmV0dXJuIE1hdGgubWF4KDAsIG1heExvYWQgLSB0aGlzLmN1cnJlbnRMb2FkKTtcbiAgICB9XG4gICAgYXN5bmMgYWRkU3Rhc2goYW1vdW50KSB7XG4gICAgICAgIGlmICghQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZSh7IFwic3lzdGVtLnN0YXNoLnZhbHVlXCI6IE1hdGgubWluKHRoaXMuc3lzdGVtLnN0YXNoLnZhbHVlICsgYW1vdW50LCB0aGlzLnN5c3RlbS5zdGFzaC5tYXgpIH0pO1xuICAgIH1cbiAgICBnZXQgcHJvamVjdHMoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldFN1Ykl0ZW1zT2ZUeXBlKEJsYWRlc0l0ZW1UeXBlLnByb2plY3QpO1xuICAgIH1cbiAgICBnZXQgcmVtYWluaW5nRG93bnRpbWVBY3Rpb25zKCkge1xuICAgICAgICBpZiAoIUJsYWRlc0FjdG9yLklzVHlwZSh0aGlzLCBCbGFkZXNBY3RvclR5cGUucGMpKSB7XG4gICAgICAgICAgICByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5zeXN0ZW0uZG93bnRpbWVfYWN0aW9ucy5tYXggKyB0aGlzLnN5c3RlbS5kb3dudGltZV9hY3Rpb25fYm9udXMgLSB0aGlzLnN5c3RlbS5kb3dudGltZV9hY3Rpb25zLnZhbHVlO1xuICAgIH1cbiAgICBfcHJvY2Vzc0FiaWxpdHlEaWFsb2dJdGVtcyhkaWFsb2dEYXRhKSB7XG4gICAgICAgIGlmICghdGhpcy5wbGF5Ym9va05hbWUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBkaWFsb2dEYXRhW3RoaXMucGxheWJvb2tOYW1lXSA9IHRoaXMuX3Byb2Nlc3NFbWJlZGRlZEl0ZW1NYXRjaGVzKEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLmFiaWxpdHksIHRoaXMucGxheWJvb2tOYW1lKSk7XG4gICAgICAgIGRpYWxvZ0RhdGEuVmV0ZXJhbiA9IHRoaXMuX3Byb2Nlc3NFbWJlZGRlZEl0ZW1NYXRjaGVzKEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLmFiaWxpdHkpKVxuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gIWl0ZW0uaGFzVGFnKHRoaXMucGxheWJvb2tOYW1lKSlcbiAgICAgICAgICAgIC8vIFJlbW92ZSBmZWF0dXJlZCBjbGFzcyBmcm9tIFZldGVyYW4gaXRlbXNcbiAgICAgICAgICAgIC5tYXAoKGl0ZW0pID0+IHtcbiAgICAgICAgICAgIGlmIChpdGVtLmRpYWxvZ0NTU0NsYXNzZXMpIHtcbiAgICAgICAgICAgICAgICBpdGVtLmRpYWxvZ0NTU0NsYXNzZXMgPSBpdGVtLmRpYWxvZ0NTU0NsYXNzZXMucmVwbGFjZSgvZmVhdHVyZWQtaXRlbVxccz8vZywgXCJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gaXRlbTtcbiAgICAgICAgfSlcbiAgICAgICAgICAgIC8vIFJlLXNvcnQgYnkgd29ybGRfbmFtZVxuICAgICAgICAgICAgLnNvcnQoKGEsIGIpID0+IHtcbiAgICAgICAgICAgIGlmIChhLnN5c3RlbS53b3JsZF9uYW1lID4gYi5zeXN0ZW0ud29ybGRfbmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGEuc3lzdGVtLndvcmxkX25hbWUgPCBiLnN5c3RlbS53b3JsZF9uYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBwcm9jZXNzR2VhckRpYWxvZ0l0ZW1zKGRpYWxvZ0RhdGEpIHtcbiAgICAgICAgaWYgKHRoaXMucGxheWJvb2tOYW1lID09PSBudWxsKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZ2Vhckl0ZW1zID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoW1xuICAgICAgICAgICAgLi4uQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUuZ2VhciwgdGhpcy5wbGF5Ym9va05hbWUpLFxuICAgICAgICAgICAgLi4uQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUuZ2VhciwgVGFnLkdlYXIuR2VuZXJhbClcbiAgICAgICAgXSlcbiAgICAgICAgICAgIC5maWx0ZXIoKGl0ZW0pID0+IHRoaXMucmVtYWluaW5nTG9hZCA+PSBpdGVtLnN5c3RlbS5sb2FkKTtcbiAgICAgICAgLy8gVHdvIHRhYnMsIG9uZSBmb3IgcGxheWJvb2sgYW5kIHRoZSBvdGhlciBmb3IgZ2VuZXJhbCBpdGVtc1xuICAgICAgICBkaWFsb2dEYXRhW3RoaXMucGxheWJvb2tOYW1lXSA9IGdlYXJJdGVtcy5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0uaGFzVGFnKHRoaXMucGxheWJvb2tOYW1lKSk7XG4gICAgICAgIGRpYWxvZ0RhdGEuR2VuZXJhbCA9IGdlYXJJdGVtc1xuICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gaXRlbS5oYXNUYWcoVGFnLkdlYXIuR2VuZXJhbCkpXG4gICAgICAgICAgICAvLyBSZW1vdmUgZmVhdHVyZWQgY2xhc3MgZnJvbSBHZW5lcmFsIGl0ZW1zXG4gICAgICAgICAgICAubWFwKChpdGVtKSA9PiB7XG4gICAgICAgICAgICBpZiAoaXRlbS5kaWFsb2dDU1NDbGFzc2VzKSB7XG4gICAgICAgICAgICAgICAgaXRlbS5kaWFsb2dDU1NDbGFzc2VzID0gaXRlbS5kaWFsb2dDU1NDbGFzc2VzLnJlcGxhY2UoL2ZlYXR1cmVkLWl0ZW1cXHM/L2csIFwiXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgIH0pXG4gICAgICAgICAgICAvLyBSZS1zb3J0IGJ5IHdvcmxkX25hbWVcbiAgICAgICAgICAgIC5zb3J0KChhLCBiKSA9PiB7XG4gICAgICAgICAgICBpZiAoYS5zeXN0ZW0ud29ybGRfbmFtZSA+IGIuc3lzdGVtLndvcmxkX25hbWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChhLnN5c3RlbS53b3JsZF9uYW1lIDwgYi5zeXN0ZW0ud29ybGRfbmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAwO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0RGlhbG9nSXRlbXMoY2F0ZWdvcnkpIHtcbiAgICAgICAgY29uc3QgZGlhbG9nRGF0YSA9IHt9O1xuICAgICAgICBjb25zdCB7IHBsYXlib29rTmFtZSB9ID0gdGhpcztcbiAgICAgICAgaWYgKGNhdGVnb3J5ID09PSBTZWxlY3Rpb25DYXRlZ29yeS5IZXJpdGFnZSkge1xuICAgICAgICAgICAgZGlhbG9nRGF0YS5NYWluID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUuaGVyaXRhZ2UpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChjYXRlZ29yeSA9PT0gU2VsZWN0aW9uQ2F0ZWdvcnkuQmFja2dyb3VuZCkge1xuICAgICAgICAgICAgZGlhbG9nRGF0YS5NYWluID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUuYmFja2dyb3VuZCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNhdGVnb3J5ID09PSBTZWxlY3Rpb25DYXRlZ29yeS5WaWNlICYmIHBsYXlib29rTmFtZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgZGlhbG9nRGF0YS5NYWluID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUudmljZSwgcGxheWJvb2tOYW1lKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2F0ZWdvcnkgPT09IFNlbGVjdGlvbkNhdGVnb3J5LlBsYXlib29rKSB7XG4gICAgICAgICAgICBkaWFsb2dEYXRhLkJhc2ljID0gdGhpcy5fcHJvY2Vzc0VtYmVkZGVkSXRlbU1hdGNoZXMoQmxhZGVzSXRlbS5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzSXRlbVR5cGUucGxheWJvb2spXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gIWl0ZW0uaGFzVGFnKFRhZy5HZWFyLkFkdmFuY2VkKSkpO1xuICAgICAgICAgICAgZGlhbG9nRGF0YS5BZHZhbmNlZCA9IHRoaXMuX3Byb2Nlc3NFbWJlZGRlZEl0ZW1NYXRjaGVzKEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rLCBUYWcuR2Vhci5BZHZhbmNlZCkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNhdGVnb3J5ID09PSBTZWxlY3Rpb25DYXRlZ29yeS5HZWFyKSB7XG4gICAgICAgICAgICB0aGlzLnByb2Nlc3NHZWFyRGlhbG9nSXRlbXMoZGlhbG9nRGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2F0ZWdvcnkgPT09IFNlbGVjdGlvbkNhdGVnb3J5LkFiaWxpdHkpIHtcbiAgICAgICAgICAgIHRoaXMuX3Byb2Nlc3NBYmlsaXR5RGlhbG9nSXRlbXMoZGlhbG9nRGF0YSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRpYWxvZ0RhdGE7XG4gICAgfVxuICAgIGdldFRhZ2dlZEl0ZW1Cb251c2VzKHRhZ3MpIHtcbiAgICAgICAgLy8gR2l2ZW4gYSBsaXN0IG9mIGl0ZW0gdGFncywgd2lsbCByZXR1cm4gdGhlIHRvdGFsIGJvbnVzZXMgdG8gdGhhdCBpdGVtXG4gICAgICAgIC8vIFdvbid0IHJldHVybiBhIG51bWJlciwgYnV0IGFuIG9iamVjdCBsaXRlcmFsIHRoYXQgaW5jbHVkZXMgdGhpbmdzIGxpa2UgZXh0cmEgbG9hZCBzcGFjZSBvciBjb25jZWFsYWJpbGl0eVxuICAgICAgICAvLyBDaGVjayBBQ1RJVkUgRUZGRUNUUyBzdXBwbGllZCBieSBhYmlsaXR5IGFnYWluc3Qgc3VibWl0dGVkIHRhZ3M/XG4gICAgICAgIC8vIFNob3VsZCBJTkNMVURFIGJvbnVzZXMgZnJvbSBjcmV3LlxuICAgICAgICByZXR1cm4gdGFncy5sZW5ndGg7IC8vIFBsYWNlaG9sZGVyIHRvIGF2b2lkIGxpbnRlciBlcnJvclxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLlByaW1hcnlEb2MgSW1wbGVtZW50YXRpb25cbiAgICBnZXQgcm9sbFByaW1hcnlNb2RzU2NoZW1hU2V0KCkge1xuICAgICAgICBjb25zdCByb2xsTW9kc1NjaGVtYVNldCA9IHN1cGVyLnJvbGxQcmltYXJ5TW9kc1NjaGVtYVNldDtcbiAgICAgICAgLy8gQWRkIHJvbGwgbW9kcyBmcm9tIGhhcm1cbiAgICAgICAgW1xuICAgICAgICAgICAgWy8xZC8sIFJvbGxNb2RTZWN0aW9uLnJvbGxdLFxuICAgICAgICAgICAgWy9MZXNzIEVmZmVjdC8sIFJvbGxNb2RTZWN0aW9uLmVmZmVjdF1cbiAgICAgICAgXS5mb3JFYWNoKChbZWZmZWN0UGF0LCBlZmZlY3RDYXRdKSA9PiB7XG4gICAgICAgICAgICBjb25zdCB7IG9uZTogaGFybUNvbmRpdGlvbk9uZSwgdHdvOiBoYXJtQ29uZGl0aW9uVHdvIH0gPSBPYmplY3QudmFsdWVzKHRoaXMuc3lzdGVtLmhhcm0pXG4gICAgICAgICAgICAgICAgLmZpbmQoKGhhcm1EYXRhKSA9PiBlZmZlY3RQYXQudGVzdChoYXJtRGF0YS5lZmZlY3QpKSA/PyB7fTtcbiAgICAgICAgICAgIGNvbnN0IGhhcm1TdHJpbmcgPSBVLm9iakNvbXBhY3QoW2hhcm1Db25kaXRpb25PbmUsIGhhcm1Db25kaXRpb25Ud28gPT09IFwiXCIgPyBudWxsIDogaGFybUNvbmRpdGlvblR3b10pLmpvaW4oXCIgJiBcIik7XG4gICAgICAgICAgICBpZiAoaGFybVN0cmluZy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgcm9sbE1vZHNTY2hlbWFTZXQucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIGtleTogYEhhcm0tbmVnYXRpdmUtJHtlZmZlY3RDYXR9YCxcbiAgICAgICAgICAgICAgICAgICAgbmFtZTogaGFybVN0cmluZyxcbiAgICAgICAgICAgICAgICAgICAgc2VjdGlvbjogZWZmZWN0Q2F0LFxuICAgICAgICAgICAgICAgICAgICBwb3NOZWc6IFwibmVnYXRpdmVcIixcbiAgICAgICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9uLFxuICAgICAgICAgICAgICAgICAgICBtb2RUeXBlOiBSb2xsTW9kVHlwZS5oYXJtLFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgICAgICAgICAgICAgdG9vbHRpcDogW1xuICAgICAgICAgICAgICAgICAgICAgICAgYDxoMSBjbGFzcz0nc3VyLXRpdGxlJz4ke2VmZmVjdENhdCA9PT0gUm9sbE1vZFNlY3Rpb24ucm9sbCA/IEhhcm0uSW1wYWlyZWQgOiBIYXJtLldlYWtlbmVkfSAoSGFybSk8L2gxPmAsXG4gICAgICAgICAgICAgICAgICAgICAgICBgPGgxIGNsYXNzPSdyZWQtYnJpZ2h0Jz4ke2hhcm1TdHJpbmd9PC9oMT5gLFxuICAgICAgICAgICAgICAgICAgICAgICAgZWZmZWN0Q2F0ID09PSBSb2xsTW9kU2VjdGlvbi5yb2xsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPyBcIjxwPklmIHlvdXIgaW5qdXJpZXMgYXBwbHkgdG8gdGhlIHNpdHVhdGlvbiBhdCBoYW5kLCB5b3Ugc3VmZmVyIDxzdHJvbmcgY2xhc3M9J3JlZC1icmlnaHQnPuKIkjFkPC9zdHJvbmc+IHRvIHlvdXIgcm9sbC48L3A+XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICA6IFwiPHA+SWYgeW91ciBpbmp1cmllcyBhcHBseSB0byB0aGUgc2l0dWF0aW9uIGF0IGhhbmQsIHlvdSBzdWZmZXIgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+4oiSMSBlZmZlY3Q8L3N0cm9uZz4uXCJcbiAgICAgICAgICAgICAgICAgICAgXS5qb2luKFwiXCIpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBjb25zdCB7IG9uZTogaGFybUNvbmRpdGlvbiB9ID0gT2JqZWN0LnZhbHVlcyh0aGlzLnN5c3RlbS5oYXJtKVxuICAgICAgICAgICAgLmZpbmQoKGhhcm1EYXRhKSA9PiAvTmVlZCBIZWxwLy50ZXN0KGhhcm1EYXRhLmVmZmVjdCkpID8/IHt9O1xuICAgICAgICBpZiAoaGFybUNvbmRpdGlvbiAmJiBoYXJtQ29uZGl0aW9uLnRyaW0oKSAhPT0gXCJcIikge1xuICAgICAgICAgICAgcm9sbE1vZHNTY2hlbWFTZXQucHVzaCh7XG4gICAgICAgICAgICAgICAga2V5OiBcIlB1c2gtbmVnYXRpdmUtcm9sbFwiLFxuICAgICAgICAgICAgICAgIG5hbWU6IFwiUFVTSFwiLFxuICAgICAgICAgICAgICAgIHNpZGVTdHJpbmc6IGhhcm1Db25kaXRpb24udHJpbSgpLFxuICAgICAgICAgICAgICAgIHNlY3Rpb246IFJvbGxNb2RTZWN0aW9uLnJvbGwsXG4gICAgICAgICAgICAgICAgcG9zTmVnOiBcIm5lZ2F0aXZlXCIsXG4gICAgICAgICAgICAgICAgYmFzZV9zdGF0dXM6IFJvbGxNb2RTdGF0dXMuVG9nZ2xlZE9uLFxuICAgICAgICAgICAgICAgIG1vZFR5cGU6IFJvbGxNb2RUeXBlLmhhcm0sXG4gICAgICAgICAgICAgICAgdmFsdWU6IDAsXG4gICAgICAgICAgICAgICAgZWZmZWN0S2V5czogW1wiQ29zdC1TdHJlc3MyXCJdLFxuICAgICAgICAgICAgICAgIHRvb2x0aXA6IFtcbiAgICAgICAgICAgICAgICAgICAgXCI8aDEgY2xhc3M9J3N1ci10aXRsZSc+QnJva2VuIChIYXJtKTwvaDE+XCIsXG4gICAgICAgICAgICAgICAgICAgIGA8aDEgY2xhc3M9J3JlZC1icmlnaHQnPiR7aGFybUNvbmRpdGlvbi50cmltKCl9PC9oMT5gLFxuICAgICAgICAgICAgICAgICAgICBcIjxwPklmIHlvdXIgaW5qdXJpZXMgYXBwbHkgdG8gdGhlIHNpdHVhdGlvbiBhdCBoYW5kLCB5b3UgbXVzdCA8c3Ryb25nPlB1c2g8L3N0cm9uZz4gdG8gYWN0LjwvcD5cIlxuICAgICAgICAgICAgICAgIF0uam9pbihcIlwiKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHJvbGxNb2RzU2NoZW1hU2V0O1xuICAgIH1cbiAgICBhc3luYyBhcHBseUhhcm0obnVtLCBuYW1lKSB7XG4gICAgICAgIGlmIChudW0gPT09IDQpIHtcbiAgICAgICAgICAgIEJsYWRlc0RpcmVjdG9yLmdldEluc3RhbmNlKCkucHVzaE5vdGljZV9Tb2NrZXRDYWxsKFwiQUxMXCIsIHtcbiAgICAgICAgICAgICAgICB0aXRsZTogYCR7dGhpcy5uYW1lfSBTdWZmZXJzIDx1PjxzdHJvbmc+RkFUQUw8L3N0cm9uZz48L3U+IEhhcm06ICR7bmFtZX1gLFxuICAgICAgICAgICAgICAgIGJvZHk6IGAke3RoaXMubmFtZX0sIHdpbGwgeW91IGNvbnRpbnVlIGFzIGEgR2hvc3QsIG9yIGNyZWF0ZSBhIG5ldyBjaGFyYWN0ZXI/YCxcbiAgICAgICAgICAgICAgICB0eXBlOiBCbGFkZXNOb3RpY2VUeXBlLnB1c2gsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJoYXJtLWFsZXJ0IGZhdGFsLWhhcm0tYWxlcnRcIlxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ29uc3RydWN0IHNlcXVlbmNlIG9mIGhhcm0ga2V5cyB0byBjaGVjaywgc3RhcnRpbmcgd2l0aCBnaXZlbiBoYXJtIGxldmVsLlxuICAgICAgICBjb25zdCBoYXJtU2VxdWVuY2UgPSBbXG4gICAgICAgICAgICBbW1wibGVzc2VyXCIsIFwib25lXCJdLCBbXCJsZXNzZXJcIiwgXCJ0d29cIl1dLFxuICAgICAgICAgICAgW1tcIm1vZGVyYXRlXCIsIFwib25lXCJdLCBbXCJtb2RlcmF0ZVwiLCBcInR3b1wiXV0sXG4gICAgICAgICAgICBbW1wic2V2ZXJlXCIsIFwib25lXCJdXVxuICAgICAgICBdLnNsaWNlKG51bSAtIDEpLmZsYXQoMSk7XG4gICAgICAgIHdoaWxlIChoYXJtU2VxdWVuY2UubGVuZ3RoKSB7XG4gICAgICAgICAgICBjb25zdCB0aGVzZUhhcm1LZXlzID0gaGFybVNlcXVlbmNlLnNoaWZ0KCk7XG4gICAgICAgICAgICBpZiAoIXRoZXNlSGFybUtleXMpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IFt0aGlzSGFybUxldmVsLCB0aGlzSGFybUtleV0gPSB0aGVzZUhhcm1LZXlzO1xuICAgICAgICAgICAgY29uc3QgdGhpc0hhcm1WYWwgPSB0aGlzLnN5c3RlbS5oYXJtW3RoaXNIYXJtTGV2ZWxdW3RoaXNIYXJtS2V5XTtcbiAgICAgICAgICAgIGlmICghdGhpc0hhcm1WYWwpIHtcbiAgICAgICAgICAgICAgICBCbGFkZXNEaXJlY3Rvci5nZXRJbnN0YW5jZSgpLnB1c2hOb3RpY2VfU29ja2V0Q2FsbChcIkFMTFwiLCB7XG4gICAgICAgICAgICAgICAgICAgIHRpdGxlOiBgJHt0aGlzLm5hbWV9IFN1ZmZlcnMgJHtVLnRDYXNlKHRoaXNIYXJtTGV2ZWwpfSBIYXJtOiAke25hbWV9YCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogQmxhZGVzTm90aWNlVHlwZS5wdXNoLFxuICAgICAgICAgICAgICAgICAgICBjc3NDbGFzc2VzOiBcImhhcm0tYWxlcnRcIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgW2BzeXN0ZW0uaGFybS4ke3RoaXNIYXJtTGV2ZWx9LiR7dGhpc0hhcm1LZXl9YF06IG5hbWUgfSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIEJsYWRlc0RpcmVjdG9yLmdldEluc3RhbmNlKCkucHVzaE5vdGljZV9Tb2NrZXRDYWxsKFwiQUxMXCIsIHtcbiAgICAgICAgICAgIHRpdGxlOiBgJHt0aGlzLm5hbWV9IFN1ZmZlcnMgYSBDYXRhc3Ryb3BoaWMsIFBlcm1hbmVudCBJbmp1cnkhYCxcbiAgICAgICAgICAgIGJvZHk6IGAke3RoaXMubmFtZX0sIHlvdSdyZSBvdXQgb2YgdGhlIGFjdGlvbiAtIGVpdGhlciBsZWZ0IGZvciBkZWFkLCBvciBvdGhlcndpc2UgZHJvcHBlZCBmcm9tIHRoZSBhY3Rpb24uIFlvdSBjYW4gY2hvb3NlIHRvIHJldHVybiBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBuZXh0IFBoYXNlIHdpdGggYSBwZXJtYW5lbnQgaW5qdXJ5LCBvciBkaWUuYCxcbiAgICAgICAgICAgIHR5cGU6IEJsYWRlc05vdGljZVR5cGUucHVzaCxcbiAgICAgICAgICAgIGNzc0NsYXNzZXM6IFwiaGFybS1hbGVydCBmYXRhbC1oYXJtLWFsZXJ0XCJcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGFzeW5jIGFwcGx5V29yc2VQb3NpdGlvbigpIHtcbiAgICAgICAgdGhpcy5zZXRGbGFnKFwiZXVub3MtYmxhZGVzXCIsIFwiaXNXb3JzZVBvc2l0aW9uXCIsIHRydWUpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLlBhcnRpY2lwYW50RG9jIEltcGxlbWVudGF0aW9uXG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudElEKCkgeyByZXR1cm4gdGhpcy5pZDsgfVxuICAgIGdldCByb2xsUGFydGljaXBhbnREb2MoKSB7IHJldHVybiB0aGlzOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudEljb24oKSB7IHJldHVybiB0aGlzLnBsYXlib29rPy5pbWcgPz8gdGhpcy5pbWc7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50TmFtZSgpIHsgcmV0dXJuIHRoaXMubmFtZSA/PyBcIlwiOyB9XG4gICAgZ2V0IHJvbGxQYXJ0aWNpcGFudFR5cGUoKSB7IHJldHVybiB0aGlzLnR5cGU7IH1cbiAgICBnZXQgcm9sbFBhcnRpY2lwYW50TW9kc1NjaGVtYVNldCgpIHsgcmV0dXJuIFtdOyB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIGFzeW5jIGFkanVzdFN0cmVzcyhkZWx0YVN0cmVzcykge1xuICAgICAgICBjb25zdCBuZXdTdHJlc3MgPSBNYXRoLm1pbih0aGlzLnN0cmVzc01heCwgTWF0aC5tYXgoMCwgdGhpcy5zdHJlc3MgKyBkZWx0YVN0cmVzcykpO1xuICAgICAgICBpZiAobmV3U3RyZXNzID09PSB0aGlzLnN0cmVzc01heCkge1xuICAgICAgICAgICAgQmxhZGVzRGlyZWN0b3IuZ2V0SW5zdGFuY2UoKS5wdXNoTm90aWNlX1NvY2tldENhbGwoXCJBTExcIiwge1xuICAgICAgICAgICAgICAgIHRpdGxlOiBgJHt0aGlzLm5hbWV9IGJyZWFrcyB1bmRlciB0aGUgc3RyZXNzIWAsXG4gICAgICAgICAgICAgICAgYm9keTogYCR7dGhpcy5uYW1lfTogU2VsZWN0IGEgVHJhdW1hIENvbmRpdGlvbiBvbiB5b3VyIHNoZWV0LiBZb3UgYXJlIHRha2VuIG91dCBvZiBhY3Rpb24gYW5kIHdpbGwgbm8gbG9uZ2VyIHBhcnRpY2lwYXRlIGluIHRoaXMgc2NvcmUuIE5hcnJhdGUgd2hhdCBoYXBwZW5zLmAsXG4gICAgICAgICAgICAgICAgdHlwZTogQmxhZGVzTm90aWNlVHlwZS5wdXNoLFxuICAgICAgICAgICAgICAgIGNzc0NsYXNzZXM6IFwic3RyZXNzLWFsZXJ0XCJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBcInN5c3RlbS5zdHJlc3MudmFsdWVcIjogMCB9KTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhd2FpdCB0aGlzLnVwZGF0ZSh7IFwic3lzdGVtLnN0cmVzcy52YWx1ZVwiOiBuZXdTdHJlc3MgfSk7XG4gICAgfVxuICAgIGFzeW5jIGluZHVsZ2VTdHJlc3MoZGVsdGFTdHJlc3MpIHtcbiAgICAgICAgaWYgKGRlbHRhU3RyZXNzID4gdGhpcy5zdHJlc3MpIHtcbiAgICAgICAgICAgIEJsYWRlc0RpcmVjdG9yLmdldEluc3RhbmNlKCkucHVzaE5vdGljZV9Tb2NrZXRDYWxsKFwiQUxMXCIsIHtcbiAgICAgICAgICAgICAgICB0aXRsZTogYCR7dGhpcy5uYW1lfSBPdmVyaW5kdWxnZXMhYCxcbiAgICAgICAgICAgICAgICBib2R5OiBgJHt0aGlzLm5hbWV9OiBTZWxlY3QgYW4gb3B0aW9uIGZyb20gdGhlIGxpc3QgYmVsb3csIGFuZCBuYXJyYXRlIGhvdyBvdmVyaW5kdWxnaW5nIHlvdXIgdmljZSBsZWQgdG8gdGhpcyByZXN1bHQ6IDx1bD48bGk+PHN0cm9uZz5BdHRyYWN0IFRyb3VibGU6PC9zdHJvbmc+IFJvbGwgZm9yIGFuIDxzdHJvbmc+RW50YW5nbGVtZW50PC9zdHJvbmc+LjwvbGk+PGxpPjxzdHJvbmc+QnJhZyBBYm91dCBZb3VyIEV4cGxvaXRzOjwvc3Ryb25nPiArMiBIZWF0PC9saT48bGk+PHN0cm9uZz5HbyBBV09MPC9zdHJvbmc+IFZhbmlzaCBmb3IgYSBmZXcgd2Vla3MuIDxlbT4oWW91IHdpbGwgcGxheSBhIGRpZmZlcmVudCBjaGFyYWN0ZXIgdW50aWwgdGhlIG5leHQgRG93bnRpbWUgUGhhc2UsIGF0IHdoaWNoIHBvaW50IHlvdSB3aWxsIHJldHVybiB3aXRoIGFsbCBIYXJtIGhlYWxlZC4pPC9lbT48L2xpPjxsaT48c3Ryb25nPlRhcHBlZDo8L3N0cm9uZz4gWW91ciBjdXJyZW50IFZpY2UgUHVydmV5b3IgY3V0cyB5b3Ugb2ZmLiA8ZW0+KFVudGlsIHlvdSBmaW5kIGEgbmV3IHNvdXJjZSBmb3IgeW91ciB2aWNlLCB5b3Ugd2lsbCBiZSB1bmFibGUgdG8gSW5kdWxnZSBWaWNlIGR1cmluZyBEb3dudGltZS4pPC9lbT48L2xpPjwvdWw+YCxcbiAgICAgICAgICAgICAgICB0eXBlOiBCbGFkZXNOb3RpY2VUeXBlLnB1c2gsXG4gICAgICAgICAgICAgICAgY3NzQ2xhc3NlczogXCJzdHJlc3MtYWxlcnRcIlxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgdGhpcy51cGRhdGUoeyBcInN5c3RlbS5zdHJlc3MudmFsdWVcIjogdGhpcy5zdHJlc3MgLSBkZWx0YVN0cmVzcyB9KTtcbiAgICB9XG4gICAgYXN5bmMgc3BlbmRBcm1vcihhbW91bnQpIHtcbiAgICAgICAgY29uc3QgdXBkYXRlRGF0YSA9IHt9O1xuICAgICAgICB3aGlsZSAoYW1vdW50ID4gMCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuaXNMaWdodEFybW9yQXZhaWxhYmxlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmlzTGlnaHRBcm1vckVxdWlwcGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZURhdGFbXCJzeXN0ZW0uYXJtb3IuYWN0aXZlLmxpZ2h0XCJdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtcInN5c3RlbS5hcm1vci5jaGVja2VkLmxpZ2h0XCJdID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHRoaXMuaXNIZWF2eUFybW9yQXZhaWxhYmxlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmlzSGVhdnlBcm1vckVxdWlwcGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZURhdGFbXCJzeXN0ZW0uYXJtb3IuYWN0aXZlLmhlYXZ5XCJdID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdXBkYXRlRGF0YVtcInN5c3RlbS5hcm1vci5jaGVja2VkLmhlYXZ5XCJdID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGFybW9yIGF2YWlsYWJsZSB0byBzcGVuZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGFtb3VudC0tO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMudXBkYXRlKHVwZGF0ZURhdGEpO1xuICAgIH1cbiAgICBhc3luYyBzcGVuZFNwZWNpYWxBcm1vcigpIHtcbiAgICAgICAgaWYgKHRoaXMuc3lzdGVtLmFybW9yLmFjdGl2ZS5zcGVjaWFsICYmICF0aGlzLnN5c3RlbS5hcm1vci5jaGVja2VkLnNwZWNpYWwpIHtcbiAgICAgICAgICAgIGF3YWl0IHRoaXMudXBkYXRlKHsgXCJzeXN0ZW0uYXJtb3IuY2hlY2tlZC5zcGVjaWFsXCI6IHRydWUgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0IHJvbGxUcmFpdFBDVG9vbHRpcEFjdGlvbnMoKSB7XG4gICAgICAgIGNvbnN0IHRvb2x0aXBTdHJpbmdzID0gW1wiPHRhYmxlPjx0Ym9keT5cIl07XG4gICAgICAgIGNvbnN0IGFjdGlvblJhdGluZ3MgPSB0aGlzLmFjdGlvbnM7XG4gICAgICAgIE9iamVjdC52YWx1ZXMoQXR0cmlidXRlVHJhaXQpLmZvckVhY2goKGF0dHJpYnV0ZSkgPT4ge1xuICAgICAgICAgICAgQy5BY3Rpb25bYXR0cmlidXRlXS5mb3JFYWNoKChhY3Rpb24pID0+IHtcbiAgICAgICAgICAgICAgICB0b29sdGlwU3RyaW5ncy5wdXNoKFtcbiAgICAgICAgICAgICAgICAgICAgXCI8dHI+XCIsXG4gICAgICAgICAgICAgICAgICAgIGA8dGQ+PHN0cm9uZz4ke1UudUNhc2UoYWN0aW9uKX08L3N0cm9uZz48L3RkPmAsXG4gICAgICAgICAgICAgICAgICAgIGA8dGQ+JHtcIuKaqlwiLnJlcGVhdChhY3Rpb25SYXRpbmdzW2FjdGlvbl0pfTwvdGQ+YCxcbiAgICAgICAgICAgICAgICAgICAgYDx0ZD48ZW0gc3R5bGU9XCJmb250LWZhbWlseTogJ01pbmlvbiBQcm8gQ29uZCc7IGZvbnQtc2l6ZTogMTBweDtcIj4oJHtDLlNob3J0QWN0aW9uVG9vbHRpcHNbYWN0aW9uXX0pPC9lbT48L3RkPmAsXG4gICAgICAgICAgICAgICAgICAgIFwiPC90cj5cIlxuICAgICAgICAgICAgICAgIF0uam9pbihcIlwiKSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRvb2x0aXBTdHJpbmdzLnB1c2goXCI8L3Rib2R5PjwvdGFibGU+XCIpO1xuICAgICAgICByZXR1cm4gdG9vbHRpcFN0cmluZ3Muam9pbihcIlwiKTtcbiAgICB9XG4gICAgZ2V0IHJvbGxUcmFpdFBDVG9vbHRpcEF0dHJpYnV0ZXMoKSB7XG4gICAgICAgIGNvbnN0IHRvb2x0aXBTdHJpbmdzID0gW1wiPHRhYmxlPjx0Ym9keT5cIl07XG4gICAgICAgIGNvbnN0IGF0dHJpYnV0ZVJhdGluZ3MgPSB0aGlzLmF0dHJpYnV0ZXM7XG4gICAgICAgIE9iamVjdC52YWx1ZXMoQXR0cmlidXRlVHJhaXQpLmZvckVhY2goKGF0dHJpYnV0ZSkgPT4ge1xuICAgICAgICAgICAgdG9vbHRpcFN0cmluZ3MucHVzaChbXG4gICAgICAgICAgICAgICAgXCI8dHI+XCIsXG4gICAgICAgICAgICAgICAgYDx0ZD48c3Ryb25nPiR7VS51Q2FzZShhdHRyaWJ1dGUpfTwvc3Ryb25nPjwvdGQ+YCxcbiAgICAgICAgICAgICAgICBgPHRkPiR7XCLimqpcIi5yZXBlYXQoYXR0cmlidXRlUmF0aW5nc1thdHRyaWJ1dGVdKX08L3RkPmAsXG4gICAgICAgICAgICAgICAgYDx0ZD48ZW0+KCR7Qy5TaG9ydEF0dHJpYnV0ZVRvb2x0aXBzW2F0dHJpYnV0ZV19KTwvZW0+PC90ZD5gLFxuICAgICAgICAgICAgICAgIFwiPC90cj5cIlxuICAgICAgICAgICAgXS5qb2luKFwiXCIpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHRvb2x0aXBTdHJpbmdzLnB1c2goXCI8L3Rib2R5PjwvdGFibGU+XCIpO1xuICAgICAgICByZXR1cm4gdG9vbHRpcFN0cmluZ3Muam9pbihcIlwiKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIHJlbmRlcihmb3JjZSkge1xuICAgICAgICBpZiAoIXRoaXMuaXNIZWFsaW5nQ2xvY2tSZWFkeSkge1xuICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlbmRlcihmb3JjZSksIDEwMDApO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHN1cGVyLnJlbmRlcihmb3JjZSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzUEM7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/actors/BladesPC.ts\n"); + +/***/ }), + +/***/ "./ts/documents/items/BladesClockKeeper.ts": +/*!*************************************************!*\ + !*** ./ts/documents/items/BladesClockKeeper.ts ***! + \*************************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesItemProxy__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../classes/BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n\n\nclass BladesClockKeeper extends _BladesItemProxy__WEBPACK_IMPORTED_MODULE_0__.BladesItem {\n static async Initialize() {\n const clockKeeper = game.items.find((item) => item.type === \"clock_keeper\");\n if (!clockKeeper) {\n game.eunoblades.ClockKeeper = (await BladesClockKeeper.create({\n name: \"Clock Keeper\",\n type: \"clock_keeper\",\n img: \"systems/eunos-blades/assets/icons/misc-icons/clock-keeper.svg\"\n }));\n }\n else {\n game.eunoblades.ClockKeeper = clockKeeper;\n }\n return loadTemplates([\n \"systems/eunos-blades/templates/parts/clock-sheet-key-controls.hbs\",\n \"systems/eunos-blades/templates/parts/clock-sheet-clock-controls.hbs\"\n ]);\n }\n showClockKeyControls(keyID) {\n if (this.sheet?.element) {\n // Find the key controls row, flip it over to controls row.\n }\n }\n hideClockKeyControls(keyID) {\n if (this.sheet?.element) {\n // Find the key controls row, flip it back to minimal summary\n }\n }\n // #region CLOCKS OVERLAY\n get clockKeys() { return this.getSceneKeys(); }\n get currentScene() { return game.scenes?.current?.id; }\n get currentSceneID() {\n if (!game.scenes?.current) {\n throw new Error(\"[BladesClockKeeper.currentScene] Error retrieving 'game.scenes.current'.\");\n }\n return game.scenes.current.id;\n }\n get targetSceneID() { return this.system.targetScene ?? this.currentSceneID; }\n get keys() {\n return new Collection(Object.entries(this.system.clocksData ?? {})\n .map(([id, data]) => [\n id,\n game.eunoblades.ClockKeys.get(id) ?? new _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_1__[\"default\"](data)\n ]));\n }\n getSceneKeys(sceneID) {\n sceneID ??= this.targetSceneID;\n return new Collection(Array.from(game.eunoblades.ClockKeys)\n .filter((clockKey) => clockKey.sceneIDs.includes(sceneID))\n .map((clockKey) => [clockKey.id, clockKey]));\n }\n async addClockKey(clockKeyConfig = {}) {\n if (!clockKeyConfig.sceneIDs?.length) {\n clockKeyConfig.sceneIDs = [this.targetSceneID];\n }\n const key = await _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_1__[\"default\"].Create({\n target: this,\n targetKey: \"system.clocksData\",\n ...clockKeyConfig\n });\n // super.update({});\n return key;\n }\n async deleteClockKey(keyID) {\n await game.eunoblades.ClockKeys.get(keyID)?.delete(game.eunoblades.ClockKeys);\n }\n async addClockToKey(keyID, clockData) {\n const key = await game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n await key.addClock(clockData);\n }\n async deleteClockFromKey(keyID, clockID) {\n const key = await game.eunoblades.ClockKeys.get(keyID);\n if (!key) {\n return;\n }\n await key.deleteClock(clockID);\n }\n // #endregion\n // #region OVERRIDES: prepareDerivedData, _onUpdate\n prepareDerivedData() {\n super.prepareDerivedData();\n this.system.targetScene ??= game.scenes.current?.id || null;\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesClockKeeper);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzQ2xvY2tLZWVwZXIudHMiLCJtYXBwaW5ncyI6Ijs7O0FBQWdEO0FBQ1U7QUFDMUQsZ0NBQWdDLHdEQUFVO0FBQzFDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEIseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBCQUEwQjtBQUMxQjtBQUNBLHlFQUF5RTtBQUN6RTtBQUNBO0FBQ0EscURBQXFELCtEQUFjO0FBQ25FO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5Q0FBeUM7QUFDekM7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLCtEQUFjO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVCwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUFlLGlCQUFpQixFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2l0ZW1zL0JsYWRlc0Nsb2NrS2VlcGVyLnRzP2E5Y2EiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQmxhZGVzSXRlbSB9IGZyb20gXCIuLi9CbGFkZXNJdGVtUHJveHlcIjtcbmltcG9ydCBCbGFkZXNDbG9ja0tleSBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNDbG9ja0tleVwiO1xuY2xhc3MgQmxhZGVzQ2xvY2tLZWVwZXIgZXh0ZW5kcyBCbGFkZXNJdGVtIHtcbiAgICBzdGF0aWMgYXN5bmMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgY29uc3QgY2xvY2tLZWVwZXIgPSBnYW1lLml0ZW1zLmZpbmQoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gXCJjbG9ja19rZWVwZXJcIik7XG4gICAgICAgIGlmICghY2xvY2tLZWVwZXIpIHtcbiAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5DbG9ja0tlZXBlciA9IChhd2FpdCBCbGFkZXNDbG9ja0tlZXBlci5jcmVhdGUoe1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiQ2xvY2sgS2VlcGVyXCIsXG4gICAgICAgICAgICAgICAgdHlwZTogXCJjbG9ja19rZWVwZXJcIixcbiAgICAgICAgICAgICAgICBpbWc6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzL2ljb25zL21pc2MtaWNvbnMvY2xvY2sta2VlcGVyLnN2Z1wiXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZWVwZXIgPSBjbG9ja0tlZXBlcjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbG9hZFRlbXBsYXRlcyhbXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9wYXJ0cy9jbG9jay1zaGVldC1rZXktY29udHJvbHMuaGJzXCIsXG4gICAgICAgICAgICBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9wYXJ0cy9jbG9jay1zaGVldC1jbG9jay1jb250cm9scy5oYnNcIlxuICAgICAgICBdKTtcbiAgICB9XG4gICAgc2hvd0Nsb2NrS2V5Q29udHJvbHMoa2V5SUQpIHtcbiAgICAgICAgaWYgKHRoaXMuc2hlZXQ/LmVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIEZpbmQgdGhlIGtleSBjb250cm9scyByb3csIGZsaXAgaXQgb3ZlciB0byBjb250cm9scyByb3cuXG4gICAgICAgIH1cbiAgICB9XG4gICAgaGlkZUNsb2NrS2V5Q29udHJvbHMoa2V5SUQpIHtcbiAgICAgICAgaWYgKHRoaXMuc2hlZXQ/LmVsZW1lbnQpIHtcbiAgICAgICAgICAgIC8vIEZpbmQgdGhlIGtleSBjb250cm9scyByb3csIGZsaXAgaXQgYmFjayB0byBtaW5pbWFsIHN1bW1hcnlcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjcmVnaW9uIENMT0NLUyBPVkVSTEFZXG4gICAgZ2V0IGNsb2NrS2V5cygpIHsgcmV0dXJuIHRoaXMuZ2V0U2NlbmVLZXlzKCk7IH1cbiAgICBnZXQgY3VycmVudFNjZW5lKCkgeyByZXR1cm4gZ2FtZS5zY2VuZXM/LmN1cnJlbnQ/LmlkOyB9XG4gICAgZ2V0IGN1cnJlbnRTY2VuZUlEKCkge1xuICAgICAgICBpZiAoIWdhbWUuc2NlbmVzPy5jdXJyZW50KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJbQmxhZGVzQ2xvY2tLZWVwZXIuY3VycmVudFNjZW5lXSBFcnJvciByZXRyaWV2aW5nICdnYW1lLnNjZW5lcy5jdXJyZW50Jy5cIik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQ7XG4gICAgfVxuICAgIGdldCB0YXJnZXRTY2VuZUlEKCkgeyByZXR1cm4gdGhpcy5zeXN0ZW0udGFyZ2V0U2NlbmUgPz8gdGhpcy5jdXJyZW50U2NlbmVJRDsgfVxuICAgIGdldCBrZXlzKCkge1xuICAgICAgICByZXR1cm4gbmV3IENvbGxlY3Rpb24oT2JqZWN0LmVudHJpZXModGhpcy5zeXN0ZW0uY2xvY2tzRGF0YSA/PyB7fSlcbiAgICAgICAgICAgIC5tYXAoKFtpZCwgZGF0YV0pID0+IFtcbiAgICAgICAgICAgIGlkLFxuICAgICAgICAgICAgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoaWQpID8/IG5ldyBCbGFkZXNDbG9ja0tleShkYXRhKVxuICAgICAgICBdKSk7XG4gICAgfVxuICAgIGdldFNjZW5lS2V5cyhzY2VuZUlEKSB7XG4gICAgICAgIHNjZW5lSUQgPz89IHRoaXMudGFyZ2V0U2NlbmVJRDtcbiAgICAgICAgcmV0dXJuIG5ldyBDb2xsZWN0aW9uKEFycmF5LmZyb20oZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cylcbiAgICAgICAgICAgIC5maWx0ZXIoKGNsb2NrS2V5KSA9PiBjbG9ja0tleS5zY2VuZUlEcy5pbmNsdWRlcyhzY2VuZUlEKSlcbiAgICAgICAgICAgIC5tYXAoKGNsb2NrS2V5KSA9PiBbY2xvY2tLZXkuaWQsIGNsb2NrS2V5XSkpO1xuICAgIH1cbiAgICBhc3luYyBhZGRDbG9ja0tleShjbG9ja0tleUNvbmZpZyA9IHt9KSB7XG4gICAgICAgIGlmICghY2xvY2tLZXlDb25maWcuc2NlbmVJRHM/Lmxlbmd0aCkge1xuICAgICAgICAgICAgY2xvY2tLZXlDb25maWcuc2NlbmVJRHMgPSBbdGhpcy50YXJnZXRTY2VuZUlEXTtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBrZXkgPSBhd2FpdCBCbGFkZXNDbG9ja0tleS5DcmVhdGUoe1xuICAgICAgICAgICAgdGFyZ2V0OiB0aGlzLFxuICAgICAgICAgICAgdGFyZ2V0S2V5OiBcInN5c3RlbS5jbG9ja3NEYXRhXCIsXG4gICAgICAgICAgICAuLi5jbG9ja0tleUNvbmZpZ1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gc3VwZXIudXBkYXRlKHt9KTtcbiAgICAgICAgcmV0dXJuIGtleTtcbiAgICB9XG4gICAgYXN5bmMgZGVsZXRlQ2xvY2tLZXkoa2V5SUQpIHtcbiAgICAgICAgYXdhaXQgZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoa2V5SUQpPy5kZWxldGUoZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cyk7XG4gICAgfVxuICAgIGFzeW5jIGFkZENsb2NrVG9LZXkoa2V5SUQsIGNsb2NrRGF0YSkge1xuICAgICAgICBjb25zdCBrZXkgPSBhd2FpdCBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQga2V5LmFkZENsb2NrKGNsb2NrRGF0YSk7XG4gICAgfVxuICAgIGFzeW5jIGRlbGV0ZUNsb2NrRnJvbUtleShrZXlJRCwgY2xvY2tJRCkge1xuICAgICAgICBjb25zdCBrZXkgPSBhd2FpdCBnYW1lLmV1bm9ibGFkZXMuQ2xvY2tLZXlzLmdldChrZXlJRCk7XG4gICAgICAgIGlmICgha2V5KSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQga2V5LmRlbGV0ZUNsb2NrKGNsb2NrSUQpO1xuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBPVkVSUklERVM6IHByZXBhcmVEZXJpdmVkRGF0YSwgX29uVXBkYXRlXG4gICAgcHJlcGFyZURlcml2ZWREYXRhKCkge1xuICAgICAgICBzdXBlci5wcmVwYXJlRGVyaXZlZERhdGEoKTtcbiAgICAgICAgdGhpcy5zeXN0ZW0udGFyZ2V0U2NlbmUgPz89IGdhbWUuc2NlbmVzLmN1cnJlbnQ/LmlkIHx8IG51bGw7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQ2xvY2tLZWVwZXI7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/items/BladesClockKeeper.ts\n"); + +/***/ }), + +/***/ "./ts/documents/items/BladesGMTracker.ts": +/*!***********************************************!*\ + !*** ./ts/documents/items/BladesGMTracker.ts ***! + \***********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../BladesActor */ \"./ts/BladesActor.ts\");\n\n\n\nclass BladesGMTracker extends _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n static async Initialize() {\n const tracker = game.items\n .find((item) => _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(item, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.gm_tracker));\n if (tracker) {\n game.eunoblades.Tracker = tracker;\n }\n else {\n game.eunoblades.Tracker = (await BladesGMTracker.create({\n name: \"GM Tracker\",\n type: \"gm_tracker\",\n img: \"systems/eunos-blades/assets/icons/misc-icons/gm-tracker.svg\"\n }));\n }\n }\n get phase() { return this.system.phase ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Freeplay; }\n set phase(phase) {\n this.update({ \"system.phase\": phase });\n }\n prepareDerivedData() {\n this.system.phases = Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase);\n }\n // #region OVERRIDES: prepareDerivedData, _onUpdate\n async _onUpdate(...args) {\n await super.callOnUpdate(...args);\n _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"].GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc).forEach((actor) => actor.render());\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesGMTracker);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzR01UcmFja2VyLnRzIiwibWFwcGluZ3MiOiI7Ozs7QUFBMEM7QUFDMEM7QUFDeEM7QUFDNUMsOEJBQThCLG1EQUFVO0FBQ3hDO0FBQ0E7QUFDQSw0QkFBNEIsbURBQVUsY0FBYywyREFBYztBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQSxrQkFBa0IsNEJBQTRCLHdEQUFXO0FBQ3pEO0FBQ0Esc0JBQXNCLHVCQUF1QjtBQUM3QztBQUNBO0FBQ0EsMkNBQTJDLHdEQUFXO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUSxvREFBVyxpQkFBaUIsNERBQWU7QUFDbkQ7QUFDQTtBQUNBLCtEQUFlLGVBQWUsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL2RvY3VtZW50cy9pdGVtcy9CbGFkZXNHTVRyYWNrZXIudHM/ODFjNyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgQmxhZGVzSXRlbSBmcm9tIFwiLi4vLi4vQmxhZGVzSXRlbVwiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3JUeXBlLCBCbGFkZXNJdGVtVHlwZSwgQmxhZGVzUGhhc2UgfSBmcm9tIFwiLi4vLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBCbGFkZXNBY3RvciBmcm9tIFwiLi4vLi4vQmxhZGVzQWN0b3JcIjtcbmNsYXNzIEJsYWRlc0dNVHJhY2tlciBleHRlbmRzIEJsYWRlc0l0ZW0ge1xuICAgIHN0YXRpYyBhc3luYyBJbml0aWFsaXplKCkge1xuICAgICAgICBjb25zdCB0cmFja2VyID0gZ2FtZS5pdGVtc1xuICAgICAgICAgICAgLmZpbmQoKGl0ZW0pID0+IEJsYWRlc0l0ZW0uSXNUeXBlKGl0ZW0sIEJsYWRlc0l0ZW1UeXBlLmdtX3RyYWNrZXIpKTtcbiAgICAgICAgaWYgKHRyYWNrZXIpIHtcbiAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5UcmFja2VyID0gdHJhY2tlcjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIGdhbWUuZXVub2JsYWRlcy5UcmFja2VyID0gKGF3YWl0IEJsYWRlc0dNVHJhY2tlci5jcmVhdGUoe1xuICAgICAgICAgICAgICAgIG5hbWU6IFwiR00gVHJhY2tlclwiLFxuICAgICAgICAgICAgICAgIHR5cGU6IFwiZ21fdHJhY2tlclwiLFxuICAgICAgICAgICAgICAgIGltZzogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy9hc3NldHMvaWNvbnMvbWlzYy1pY29ucy9nbS10cmFja2VyLnN2Z1wiXG4gICAgICAgICAgICB9KSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZ2V0IHBoYXNlKCkgeyByZXR1cm4gdGhpcy5zeXN0ZW0ucGhhc2UgPz8gQmxhZGVzUGhhc2UuRnJlZXBsYXk7IH1cbiAgICBzZXQgcGhhc2UocGhhc2UpIHtcbiAgICAgICAgdGhpcy51cGRhdGUoeyBcInN5c3RlbS5waGFzZVwiOiBwaGFzZSB9KTtcbiAgICB9XG4gICAgcHJlcGFyZURlcml2ZWREYXRhKCkge1xuICAgICAgICB0aGlzLnN5c3RlbS5waGFzZXMgPSBPYmplY3QudmFsdWVzKEJsYWRlc1BoYXNlKTtcbiAgICB9XG4gICAgLy8gI3JlZ2lvbiBPVkVSUklERVM6IHByZXBhcmVEZXJpdmVkRGF0YSwgX29uVXBkYXRlXG4gICAgYXN5bmMgX29uVXBkYXRlKC4uLmFyZ3MpIHtcbiAgICAgICAgYXdhaXQgc3VwZXIuY2FsbE9uVXBkYXRlKC4uLmFyZ3MpO1xuICAgICAgICBCbGFkZXNBY3Rvci5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzQWN0b3JUeXBlLnBjKS5mb3JFYWNoKChhY3RvcikgPT4gYWN0b3IucmVuZGVyKCkpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0dNVHJhY2tlcjtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/documents/items/BladesGMTracker.ts\n"); + +/***/ }), + +/***/ "./ts/documents/items/BladesLocation.ts": +/*!**********************************************!*\ + !*** ./ts/documents/items/BladesLocation.ts ***! + \**********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\nclass BladesLocation extends _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n get rollFactors() {\n const factorData = {};\n [\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality,\n _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale\n ].forEach((factor, i) => {\n const factorTotal = this.getFactorTotal(factor);\n factorData[factor] = {\n name: factor,\n value: factorTotal,\n max: factorTotal,\n baseVal: factorTotal,\n display: factor === _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier ? _core_utilities__WEBPACK_IMPORTED_MODULE_2__[\"default\"].romanizeNum(factorTotal) : `${factorTotal}`,\n isActive: i === 0,\n isPrimary: i === 0,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: `factor-gold${i === 0 ? \" factor-main\" : \"\"}`\n };\n });\n return factorData;\n }\n getFactorTotal(factor) {\n switch (factor) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier: return this.system.tier.value;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality: return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier);\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale: return this.system.scale;\n // no default\n }\n return 0;\n }\n get rollOppImg() { return this.img ?? \"\"; }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesLocation);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzTG9jYXRpb24udHMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQzBDO0FBQ0k7QUFDVDtBQUNyQyw2QkFBNkIsbURBQVU7QUFDdkM7QUFDQTtBQUNBO0FBQ0EsWUFBWSxtREFBTTtBQUNsQixZQUFZLG1EQUFNO0FBQ2xCLFlBQVksbURBQU07QUFDbEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0MsbURBQU0sUUFBUSx1REFBQywrQkFBK0IsWUFBWTtBQUM5RjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQyw4QkFBOEI7QUFDeEU7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsbURBQU07QUFDdkIsaUJBQWlCLG1EQUFNLHFDQUFxQyxtREFBTTtBQUNsRSxpQkFBaUIsbURBQU07QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQSwrREFBZSxjQUFjLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzTG9jYXRpb24udHM/MjNmMCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmltcG9ydCBCbGFkZXNJdGVtIGZyb20gXCIuLi8uLi9CbGFkZXNJdGVtXCI7XG5pbXBvcnQgeyBGYWN0b3IgfSBmcm9tIFwiLi4vLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuY2xhc3MgQmxhZGVzTG9jYXRpb24gZXh0ZW5kcyBCbGFkZXNJdGVtIHtcbiAgICBnZXQgcm9sbEZhY3RvcnMoKSB7XG4gICAgICAgIGNvbnN0IGZhY3RvckRhdGEgPSB7fTtcbiAgICAgICAgW1xuICAgICAgICAgICAgRmFjdG9yLnRpZXIsXG4gICAgICAgICAgICBGYWN0b3IucXVhbGl0eSxcbiAgICAgICAgICAgIEZhY3Rvci5zY2FsZVxuICAgICAgICBdLmZvckVhY2goKGZhY3RvciwgaSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZmFjdG9yVG90YWwgPSB0aGlzLmdldEZhY3RvclRvdGFsKGZhY3Rvcik7XG4gICAgICAgICAgICBmYWN0b3JEYXRhW2ZhY3Rvcl0gPSB7XG4gICAgICAgICAgICAgICAgbmFtZTogZmFjdG9yLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBmYWN0b3JUb3RhbCxcbiAgICAgICAgICAgICAgICBtYXg6IGZhY3RvclRvdGFsLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IGZhY3RvclRvdGFsLFxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGZhY3RvciA9PT0gRmFjdG9yLnRpZXIgPyBVLnJvbWFuaXplTnVtKGZhY3RvclRvdGFsKSA6IGAke2ZhY3RvclRvdGFsfWAsXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IGkgPT09IDAsXG4gICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBpID09PSAwLFxuICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjc3NDbGFzc2VzOiBgZmFjdG9yLWdvbGQke2kgPT09IDAgPyBcIiBmYWN0b3ItbWFpblwiIDogXCJcIn1gXG4gICAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGZhY3RvckRhdGE7XG4gICAgfVxuICAgIGdldEZhY3RvclRvdGFsKGZhY3Rvcikge1xuICAgICAgICBzd2l0Y2ggKGZhY3Rvcikge1xuICAgICAgICAgICAgY2FzZSBGYWN0b3IudGllcjogcmV0dXJuIHRoaXMuc3lzdGVtLnRpZXIudmFsdWU7XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5xdWFsaXR5OiByZXR1cm4gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcik7XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5zY2FsZTogcmV0dXJuIHRoaXMuc3lzdGVtLnNjYWxlO1xuICAgICAgICAgICAgLy8gbm8gZGVmYXVsdFxuICAgICAgICB9XG4gICAgICAgIHJldHVybiAwO1xuICAgIH1cbiAgICBnZXQgcm9sbE9wcEltZygpIHsgcmV0dXJuIHRoaXMuaW1nID8/IFwiXCI7IH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0xvY2F0aW9uO1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/documents/items/BladesLocation.ts\n"); + +/***/ }), + +/***/ "./ts/documents/items/BladesProject.ts": +/*!*********************************************!*\ + !*** ./ts/documents/items/BladesProject.ts ***! + \*********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesItemProxy__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _sheets_item_BladesProjectSheet__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../sheets/item/BladesProjectSheet */ \"./ts/sheets/item/BladesProjectSheet.ts\");\n/* harmony import */ var _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../classes/BladesClockKey */ \"./ts/classes/BladesClockKey.ts\");\n\n\n\n\n\nclass BladesProject extends _BladesItemProxy__WEBPACK_IMPORTED_MODULE_2__.BladesItem {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesProject, BladesProjectSheet: _sheets_item_BladesProjectSheet__WEBPACK_IMPORTED_MODULE_3__[\"default\"] });\n Items.registerSheet(\"blades\", _sheets_item_BladesProjectSheet__WEBPACK_IMPORTED_MODULE_3__[\"default\"], { types: [\"project\"], makeDefault: true });\n return loadTemplates([\"systems/eunos-blades/templates/items/project-sheet.hbs\"]);\n }\n // #endregion\n static IsType(doc) {\n return super.IsType(doc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project);\n }\n static async create(data, options = {}) {\n const project = (await super.create(data, { ...options, renderSheet: false }));\n if (!project._clockKey) {\n project._clockKey = await _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_4__[\"default\"].Create({\n name: project.name,\n target: project,\n targetKey: \"system.clocksData\",\n isNameVisible: false,\n isSpotlit: false,\n isVisible: true,\n displayMode: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockKeyDisplayMode.clocks\n // oneKeyIndex: U.gsap.utils.random(0, 4, 1) as OneKeyImgIndex\n }, undefined, [{\n name: \"\",\n index: 0,\n color: _core_constants__WEBPACK_IMPORTED_MODULE_0__.ClockColor.yellow,\n value: 0,\n max: 8,\n isVisible: true,\n isActive: true,\n isNameVisible: false,\n isHighlighted: false\n }]);\n }\n return project;\n }\n _clockKey;\n get clockKey() {\n if (this._clockKey) {\n return this._clockKey;\n }\n const keysData = Object.values(this.system.clocksData);\n if (keysData.length === 0) {\n throw new Error(`ClockKey not initialized for Project ${this.name}`);\n }\n let keyID;\n if (keysData.length === 1) {\n keyID = keysData[0].id;\n }\n else if (this.isEmbedded) {\n // Find the key data with a targetID that includes the parent document's id\n keyID = keysData.find((keyData) => keyData.targetID.includes(this.parent?.id))?.id;\n if (!keyID) {\n throw new Error(`ClockKey not initialized for Project ${this.name} embedded in document '${this.parent?.name}'.`);\n }\n }\n else {\n // Find the key of form 'Item.' in the ClockKeys collection\n keyID = keysData.find((keyData) => /^Item\\.[^.]{16}$/.exec(keyData.targetID))?.id;\n if (!keyID) {\n throw new Error(`ClockKey not initialized for Project ${this.name}.`);\n }\n }\n this._clockKey = game.eunoblades.ClockKeys.get(keyID) ?? new _classes_BladesClockKey__WEBPACK_IMPORTED_MODULE_4__[\"default\"](this.system.clocksData[keyID]);\n if (!this._clockKey) {\n throw new Error(`ClockKey not initialized for Project ${this.name}`);\n }\n return this._clockKey;\n }\n get ownerName() {\n if (this.parent) {\n return this.parent.name;\n }\n return undefined;\n }\n get currentClock() {\n return this.clockKey.currentClock;\n }\n get isComplete() {\n return this.clockKey.isComplete;\n }\n get rollOppClock() { return this.currentClock?.data; }\n async advanceClock(segments = 1) {\n if (!this.currentClock) {\n return undefined;\n }\n return this.currentClock.fillSegments(segments);\n }\n get rollFactors() {\n const factorData = {};\n [\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier,\n _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality\n ].forEach((factor, i) => {\n const factorTotal = this.getFactorTotal(factor);\n factorData[factor] = {\n name: factor,\n value: factorTotal,\n max: factorTotal,\n baseVal: factorTotal,\n display: factor === _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier ? _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].romanizeNum(factorTotal) : `${factorTotal}`,\n isActive: i === 0,\n isPrimary: i === 0,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: `factor-gold${i === 0 ? \" factor-main\" : \"\"}`\n };\n });\n return factorData;\n }\n getFactorTotal(factor) {\n switch (factor) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier: return this.system.tier.value;\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.quality: return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier);\n // no default\n }\n return 0;\n }\n get rollOppImg() { return \"\"; }\n get keyElem() {\n if (!this.clockKey) {\n return undefined;\n }\n return $(`#${this.clockKey.id}`)[0];\n }\n get currentClockElem() {\n if (!this.keyElem) {\n return undefined;\n }\n if (!this.currentClock) {\n return undefined;\n }\n return $(this.keyElem).find(`.clock[data-id=\"${this.currentClock.id}\"]`)[0];\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesProject);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzUHJvamVjdC50cyIsIm1hcHBpbmdzIjoiOzs7Ozs7QUFBK0Y7QUFDMUQ7QUFDVztBQUNzQjtBQUNaO0FBQzFELDRCQUE0Qix3REFBVTtBQUN0QztBQUNBO0FBQ0Esb0NBQW9DLGlDQUFpQywyRUFBRTtBQUN2RSxzQ0FBc0MsdUVBQWtCLElBQUksdUNBQXVDO0FBQ25HO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUNBQWlDLDJEQUFjO0FBQy9DO0FBQ0EsMENBQTBDO0FBQzFDLG9EQUFvRCxnQ0FBZ0M7QUFDcEY7QUFDQSxzQ0FBc0MsK0RBQWM7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLGdFQUFtQjtBQUNoRDtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0EsMkJBQTJCLHVEQUFVO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9FQUFvRSxVQUFVO0FBQzlFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdFQUF3RSxXQUFXLHdCQUF3QixrQkFBa0I7QUFDN0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSw0REFBNEQsR0FBRztBQUMvRDtBQUNBLHdFQUF3RSxVQUFVO0FBQ2xGO0FBQ0E7QUFDQSxxRUFBcUUsK0RBQWM7QUFDbkY7QUFDQSxvRUFBb0UsVUFBVTtBQUM5RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUI7QUFDekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxtREFBTTtBQUNsQixZQUFZLG1EQUFNO0FBQ2xCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLG1EQUFNLFFBQVEsdURBQUMsK0JBQStCLFlBQVk7QUFDOUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEMsOEJBQThCO0FBQ3hFO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLG1EQUFNO0FBQ3ZCLGlCQUFpQixtREFBTSxxQ0FBcUMsbURBQU07QUFDbEU7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsaUJBQWlCO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1REFBdUQscUJBQXFCO0FBQzVFO0FBQ0E7QUFDQSwrREFBZSxhQUFhLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzUHJvamVjdC50cz82Y2IxIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEJsYWRlc0l0ZW1UeXBlLCBGYWN0b3IsIENsb2NrQ29sb3IsIENsb2NrS2V5RGlzcGxheU1vZGUgfSBmcm9tIFwiLi4vLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IHsgQmxhZGVzSXRlbSB9IGZyb20gXCIuLi9CbGFkZXNJdGVtUHJveHlcIjtcbmltcG9ydCBCbGFkZXNQcm9qZWN0U2hlZXQgZnJvbSBcIi4uLy4uL3NoZWV0cy9pdGVtL0JsYWRlc1Byb2plY3RTaGVldFwiO1xuaW1wb3J0IEJsYWRlc0Nsb2NrS2V5IGZyb20gXCIuLi8uLi9jbGFzc2VzL0JsYWRlc0Nsb2NrS2V5XCI7XG5jbGFzcyBCbGFkZXNQcm9qZWN0IGV4dGVuZHMgQmxhZGVzSXRlbSB7XG4gICAgLy8gI3JlZ2lvbiBJTklUSUFMSVpBVElPTiB+XG4gICAgc3RhdGljIGFzeW5jIEluaXRpYWxpemUoKSB7XG4gICAgICAgIE9iamVjdC5hc3NpZ24oZ2xvYmFsVGhpcywgeyBCbGFkZXNQcm9qZWN0LCBCbGFkZXNQcm9qZWN0U2hlZXQgfSk7XG4gICAgICAgIEl0ZW1zLnJlZ2lzdGVyU2hlZXQoXCJibGFkZXNcIiwgQmxhZGVzUHJvamVjdFNoZWV0LCB7IHR5cGVzOiBbXCJwcm9qZWN0XCJdLCBtYWtlRGVmYXVsdDogdHJ1ZSB9KTtcbiAgICAgICAgcmV0dXJuIGxvYWRUZW1wbGF0ZXMoW1wic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2l0ZW1zL3Byb2plY3Qtc2hlZXQuaGJzXCJdKTtcbiAgICB9XG4gICAgLy8gI2VuZHJlZ2lvblxuICAgIHN0YXRpYyBJc1R5cGUoZG9jKSB7XG4gICAgICAgIHJldHVybiBzdXBlci5Jc1R5cGUoZG9jLCBCbGFkZXNJdGVtVHlwZS5wcm9qZWN0KTtcbiAgICB9XG4gICAgc3RhdGljIGFzeW5jIGNyZWF0ZShkYXRhLCBvcHRpb25zID0ge30pIHtcbiAgICAgICAgY29uc3QgcHJvamVjdCA9IChhd2FpdCBzdXBlci5jcmVhdGUoZGF0YSwgeyAuLi5vcHRpb25zLCByZW5kZXJTaGVldDogZmFsc2UgfSkpO1xuICAgICAgICBpZiAoIXByb2plY3QuX2Nsb2NrS2V5KSB7XG4gICAgICAgICAgICBwcm9qZWN0Ll9jbG9ja0tleSA9IGF3YWl0IEJsYWRlc0Nsb2NrS2V5LkNyZWF0ZSh7XG4gICAgICAgICAgICAgICAgbmFtZTogcHJvamVjdC5uYW1lLFxuICAgICAgICAgICAgICAgIHRhcmdldDogcHJvamVjdCxcbiAgICAgICAgICAgICAgICB0YXJnZXRLZXk6IFwic3lzdGVtLmNsb2Nrc0RhdGFcIixcbiAgICAgICAgICAgICAgICBpc05hbWVWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBpc1Nwb3RsaXQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGlzVmlzaWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICBkaXNwbGF5TW9kZTogQ2xvY2tLZXlEaXNwbGF5TW9kZS5jbG9ja3NcbiAgICAgICAgICAgICAgICAvLyBvbmVLZXlJbmRleDogVS5nc2FwLnV0aWxzLnJhbmRvbSgwLCA0LCAxKSBhcyBPbmVLZXlJbWdJbmRleFxuICAgICAgICAgICAgfSwgdW5kZWZpbmVkLCBbe1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiBcIlwiLFxuICAgICAgICAgICAgICAgICAgICBpbmRleDogMCxcbiAgICAgICAgICAgICAgICAgICAgY29sb3I6IENsb2NrQ29sb3IueWVsbG93LFxuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgICAgICAgICAgICAgbWF4OiA4LFxuICAgICAgICAgICAgICAgICAgICBpc1Zpc2libGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIGlzQWN0aXZlOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBpc05hbWVWaXNpYmxlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgaXNIaWdobGlnaHRlZDogZmFsc2VcbiAgICAgICAgICAgICAgICB9XSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHByb2plY3Q7XG4gICAgfVxuICAgIF9jbG9ja0tleTtcbiAgICBnZXQgY2xvY2tLZXkoKSB7XG4gICAgICAgIGlmICh0aGlzLl9jbG9ja0tleSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2Nsb2NrS2V5O1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IGtleXNEYXRhID0gT2JqZWN0LnZhbHVlcyh0aGlzLnN5c3RlbS5jbG9ja3NEYXRhKTtcbiAgICAgICAgaWYgKGtleXNEYXRhLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDbG9ja0tleSBub3QgaW5pdGlhbGl6ZWQgZm9yIFByb2plY3QgJHt0aGlzLm5hbWV9YCk7XG4gICAgICAgIH1cbiAgICAgICAgbGV0IGtleUlEO1xuICAgICAgICBpZiAoa2V5c0RhdGEubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICBrZXlJRCA9IGtleXNEYXRhWzBdLmlkO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuaXNFbWJlZGRlZCkge1xuICAgICAgICAgICAgLy8gRmluZCB0aGUga2V5IGRhdGEgd2l0aCBhIHRhcmdldElEIHRoYXQgaW5jbHVkZXMgdGhlIHBhcmVudCBkb2N1bWVudCdzIGlkXG4gICAgICAgICAgICBrZXlJRCA9IGtleXNEYXRhLmZpbmQoKGtleURhdGEpID0+IGtleURhdGEudGFyZ2V0SUQuaW5jbHVkZXModGhpcy5wYXJlbnQ/LmlkKSk/LmlkO1xuICAgICAgICAgICAgaWYgKCFrZXlJRCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2xvY2tLZXkgbm90IGluaXRpYWxpemVkIGZvciBQcm9qZWN0ICR7dGhpcy5uYW1lfSBlbWJlZGRlZCBpbiBkb2N1bWVudCAnJHt0aGlzLnBhcmVudD8ubmFtZX0nLmApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy8gRmluZCB0aGUga2V5IG9mIGZvcm0gJ0l0ZW0uPElEU3RyaW5nPicgaW4gdGhlIENsb2NrS2V5cyBjb2xsZWN0aW9uXG4gICAgICAgICAgICBrZXlJRCA9IGtleXNEYXRhLmZpbmQoKGtleURhdGEpID0+IC9eSXRlbVxcLlteLl17MTZ9JC8uZXhlYyhrZXlEYXRhLnRhcmdldElEKSk/LmlkO1xuICAgICAgICAgICAgaWYgKCFrZXlJRCkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2xvY2tLZXkgbm90IGluaXRpYWxpemVkIGZvciBQcm9qZWN0ICR7dGhpcy5uYW1lfS5gKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLl9jbG9ja0tleSA9IGdhbWUuZXVub2JsYWRlcy5DbG9ja0tleXMuZ2V0KGtleUlEKSA/PyBuZXcgQmxhZGVzQ2xvY2tLZXkodGhpcy5zeXN0ZW0uY2xvY2tzRGF0YVtrZXlJRF0pO1xuICAgICAgICBpZiAoIXRoaXMuX2Nsb2NrS2V5KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENsb2NrS2V5IG5vdCBpbml0aWFsaXplZCBmb3IgUHJvamVjdCAke3RoaXMubmFtZX1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5fY2xvY2tLZXk7XG4gICAgfVxuICAgIGdldCBvd25lck5hbWUoKSB7XG4gICAgICAgIGlmICh0aGlzLnBhcmVudCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucGFyZW50Lm5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICB9XG4gICAgZ2V0IGN1cnJlbnRDbG9jaygpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xvY2tLZXkuY3VycmVudENsb2NrO1xuICAgIH1cbiAgICBnZXQgaXNDb21wbGV0ZSgpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuY2xvY2tLZXkuaXNDb21wbGV0ZTtcbiAgICB9XG4gICAgZ2V0IHJvbGxPcHBDbG9jaygpIHsgcmV0dXJuIHRoaXMuY3VycmVudENsb2NrPy5kYXRhOyB9XG4gICAgYXN5bmMgYWR2YW5jZUNsb2NrKHNlZ21lbnRzID0gMSkge1xuICAgICAgICBpZiAoIXRoaXMuY3VycmVudENsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0aGlzLmN1cnJlbnRDbG9jay5maWxsU2VnbWVudHMoc2VnbWVudHMpO1xuICAgIH1cbiAgICBnZXQgcm9sbEZhY3RvcnMoKSB7XG4gICAgICAgIGNvbnN0IGZhY3RvckRhdGEgPSB7fTtcbiAgICAgICAgW1xuICAgICAgICAgICAgRmFjdG9yLnRpZXIsXG4gICAgICAgICAgICBGYWN0b3IucXVhbGl0eVxuICAgICAgICBdLmZvckVhY2goKGZhY3RvciwgaSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZmFjdG9yVG90YWwgPSB0aGlzLmdldEZhY3RvclRvdGFsKGZhY3Rvcik7XG4gICAgICAgICAgICBmYWN0b3JEYXRhW2ZhY3Rvcl0gPSB7XG4gICAgICAgICAgICAgICAgbmFtZTogZmFjdG9yLFxuICAgICAgICAgICAgICAgIHZhbHVlOiBmYWN0b3JUb3RhbCxcbiAgICAgICAgICAgICAgICBtYXg6IGZhY3RvclRvdGFsLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IGZhY3RvclRvdGFsLFxuICAgICAgICAgICAgICAgIGRpc3BsYXk6IGZhY3RvciA9PT0gRmFjdG9yLnRpZXIgPyBVLnJvbWFuaXplTnVtKGZhY3RvclRvdGFsKSA6IGAke2ZhY3RvclRvdGFsfWAsXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IGkgPT09IDAsXG4gICAgICAgICAgICAgICAgaXNQcmltYXJ5OiBpID09PSAwLFxuICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjc3NDbGFzc2VzOiBgZmFjdG9yLWdvbGQke2kgPT09IDAgPyBcIiBmYWN0b3ItbWFpblwiIDogXCJcIn1gXG4gICAgICAgICAgICB9O1xuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGZhY3RvckRhdGE7XG4gICAgfVxuICAgIGdldEZhY3RvclRvdGFsKGZhY3Rvcikge1xuICAgICAgICBzd2l0Y2ggKGZhY3Rvcikge1xuICAgICAgICAgICAgY2FzZSBGYWN0b3IudGllcjogcmV0dXJuIHRoaXMuc3lzdGVtLnRpZXIudmFsdWU7XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci5xdWFsaXR5OiByZXR1cm4gdGhpcy5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcik7XG4gICAgICAgICAgICAvLyBubyBkZWZhdWx0XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIDA7XG4gICAgfVxuICAgIGdldCByb2xsT3BwSW1nKCkgeyByZXR1cm4gXCJcIjsgfVxuICAgIGdldCBrZXlFbGVtKCkge1xuICAgICAgICBpZiAoIXRoaXMuY2xvY2tLZXkpIHtcbiAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuICQoYCMke3RoaXMuY2xvY2tLZXkuaWR9YClbMF07XG4gICAgfVxuICAgIGdldCBjdXJyZW50Q2xvY2tFbGVtKCkge1xuICAgICAgICBpZiAoIXRoaXMua2V5RWxlbSkge1xuICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXRoaXMuY3VycmVudENsb2NrKSB7XG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAkKHRoaXMua2V5RWxlbSkuZmluZChgLmNsb2NrW2RhdGEtaWQ9XCIke3RoaXMuY3VycmVudENsb2NrLmlkfVwiXWApWzBdO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc1Byb2plY3Q7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/items/BladesProject.ts\n"); + +/***/ }), + +/***/ "./ts/documents/items/BladesScore.ts": +/*!*******************************************!*\ + !*** ./ts/documents/items/BladesScore.ts ***! + \*******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _sheets_item_BladesScoreSheet__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../sheets/item/BladesScoreSheet */ \"./ts/sheets/item/BladesScoreSheet.ts\");\n\n\n\n\n\nclass BladesScore extends _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n // #region INITIALIZATION ~\n static async Initialize() {\n Object.assign(globalThis, { BladesScore, BladesScoreSheet: _sheets_item_BladesScoreSheet__WEBPACK_IMPORTED_MODULE_4__[\"default\"] });\n Items.registerSheet(\"blades\", _sheets_item_BladesScoreSheet__WEBPACK_IMPORTED_MODULE_4__[\"default\"], { types: [\"score\"], makeDefault: true });\n return loadTemplates([\"systems/eunos-blades/templates/items/score-sheet.hbs\"]);\n }\n // #endregion\n static get Active() {\n return _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"].GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.score).find((score) => score.system.isActive);\n }\n static set Active(val) {\n _BladesItem__WEBPACK_IMPORTED_MODULE_0__[\"default\"].GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.score)\n .find((score) => score.system.isActive)?.update({ \"system.isActive\": false })\n .then(() => {\n if (val) {\n val.update({ \"system.isActive\": true });\n }\n });\n }\n // #region BladesRoll.OppositionData Implementation\n get rollFactors() {\n const tierTotal = this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier);\n return {\n [_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier]: {\n name: \"Tier\",\n value: tierTotal,\n max: tierTotal,\n baseVal: tierTotal,\n display: _core_utilities__WEBPACK_IMPORTED_MODULE_2__[\"default\"].romanizeNum(tierTotal),\n isActive: true,\n isPrimary: true,\n isDominant: false,\n highFavorsPC: true,\n cssClasses: \"factor-gold factor-main\"\n }\n };\n }\n get rollOppImg() { return this.img ?? \"\"; }\n getFactorTotal(factor) {\n switch (factor) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier: return this.system.tier.value;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.quality: return this.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.tier);\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.scale: return 0;\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.Factor.magnitude: return 0;\n default: return 0;\n }\n }\n // #endregion\n // #region OVERRIDES: _onUpdate\n async _onUpdate(changed, options, userId) {\n super._onUpdate(changed, options, userId);\n _BladesActor__WEBPACK_IMPORTED_MODULE_3__[\"default\"].GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc).forEach((actor) => actor.render());\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesScore);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9kb2N1bWVudHMvaXRlbXMvQmxhZGVzU2NvcmUudHMiLCJtYXBwaW5ncyI6Ijs7Ozs7O0FBQTBDO0FBQ3FDO0FBQzFDO0FBQ087QUFDc0I7QUFDbEUsMEJBQTBCLG1EQUFVO0FBQ3BDO0FBQ0E7QUFDQSxvQ0FBb0MsNkJBQTZCLHlFQUFFO0FBQ25FLHNDQUFzQyxxRUFBZ0IsSUFBSSxxQ0FBcUM7QUFDL0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLG1EQUFVLGlCQUFpQiwyREFBYztBQUN4RDtBQUNBO0FBQ0EsUUFBUSxtREFBVSxpQkFBaUIsMkRBQWM7QUFDakQsOERBQThELDBCQUEwQjtBQUN4RjtBQUNBO0FBQ0EsNkJBQTZCLHlCQUF5QjtBQUN0RDtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSw4Q0FBOEMsbURBQU07QUFDcEQ7QUFDQSxhQUFhLG1EQUFNO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHVEQUFDO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBLGlCQUFpQixtREFBTTtBQUN2QixpQkFBaUIsbURBQU0scUNBQXFDLG1EQUFNO0FBQ2xFLGlCQUFpQixtREFBTTtBQUN2QixpQkFBaUIsbURBQU07QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLG9EQUFXLGlCQUFpQiw0REFBZTtBQUNuRDtBQUNBO0FBQ0EsK0RBQWUsV0FBVyxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvZG9jdW1lbnRzL2l0ZW1zL0JsYWRlc1Njb3JlLnRzP2FlMjMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEJsYWRlc0l0ZW0gZnJvbSBcIi4uLy4uL0JsYWRlc0l0ZW1cIjtcbmltcG9ydCB7IEJsYWRlc0FjdG9yVHlwZSwgQmxhZGVzSXRlbVR5cGUsIEZhY3RvciB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IFUgZnJvbSBcIi4uLy4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgQmxhZGVzQWN0b3IgZnJvbSBcIi4uLy4uL0JsYWRlc0FjdG9yXCI7XG5pbXBvcnQgQmxhZGVzU2NvcmVTaGVldCBmcm9tIFwiLi4vLi4vc2hlZXRzL2l0ZW0vQmxhZGVzU2NvcmVTaGVldFwiO1xuY2xhc3MgQmxhZGVzU2NvcmUgZXh0ZW5kcyBCbGFkZXNJdGVtIHtcbiAgICAvLyAjcmVnaW9uIElOSVRJQUxJWkFUSU9OIH5cbiAgICBzdGF0aWMgYXN5bmMgSW5pdGlhbGl6ZSgpIHtcbiAgICAgICAgT2JqZWN0LmFzc2lnbihnbG9iYWxUaGlzLCB7IEJsYWRlc1Njb3JlLCBCbGFkZXNTY29yZVNoZWV0IH0pO1xuICAgICAgICBJdGVtcy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc1Njb3JlU2hlZXQsIHsgdHlwZXM6IFtcInNjb3JlXCJdLCBtYWtlRGVmYXVsdDogdHJ1ZSB9KTtcbiAgICAgICAgcmV0dXJuIGxvYWRUZW1wbGF0ZXMoW1wic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2l0ZW1zL3Njb3JlLXNoZWV0Lmhic1wiXSk7XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICBzdGF0aWMgZ2V0IEFjdGl2ZSgpIHtcbiAgICAgICAgcmV0dXJuIEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLnNjb3JlKS5maW5kKChzY29yZSkgPT4gc2NvcmUuc3lzdGVtLmlzQWN0aXZlKTtcbiAgICB9XG4gICAgc3RhdGljIHNldCBBY3RpdmUodmFsKSB7XG4gICAgICAgIEJsYWRlc0l0ZW0uR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0l0ZW1UeXBlLnNjb3JlKVxuICAgICAgICAgICAgLmZpbmQoKHNjb3JlKSA9PiBzY29yZS5zeXN0ZW0uaXNBY3RpdmUpPy51cGRhdGUoeyBcInN5c3RlbS5pc0FjdGl2ZVwiOiBmYWxzZSB9KVxuICAgICAgICAgICAgLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHZhbCkge1xuICAgICAgICAgICAgICAgIHZhbC51cGRhdGUoeyBcInN5c3RlbS5pc0FjdGl2ZVwiOiB0cnVlIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgLy8gI3JlZ2lvbiBCbGFkZXNSb2xsLk9wcG9zaXRpb25EYXRhIEltcGxlbWVudGF0aW9uXG4gICAgZ2V0IHJvbGxGYWN0b3JzKCkge1xuICAgICAgICBjb25zdCB0aWVyVG90YWwgPSB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIFtGYWN0b3IudGllcl06IHtcbiAgICAgICAgICAgICAgICBuYW1lOiBcIlRpZXJcIixcbiAgICAgICAgICAgICAgICB2YWx1ZTogdGllclRvdGFsLFxuICAgICAgICAgICAgICAgIG1heDogdGllclRvdGFsLFxuICAgICAgICAgICAgICAgIGJhc2VWYWw6IHRpZXJUb3RhbCxcbiAgICAgICAgICAgICAgICBkaXNwbGF5OiBVLnJvbWFuaXplTnVtKHRpZXJUb3RhbCksXG4gICAgICAgICAgICAgICAgaXNBY3RpdmU6IHRydWUsXG4gICAgICAgICAgICAgICAgaXNQcmltYXJ5OiB0cnVlLFxuICAgICAgICAgICAgICAgIGlzRG9taW5hbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGhpZ2hGYXZvcnNQQzogdHJ1ZSxcbiAgICAgICAgICAgICAgICBjc3NDbGFzc2VzOiBcImZhY3Rvci1nb2xkIGZhY3Rvci1tYWluXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG4gICAgZ2V0IHJvbGxPcHBJbWcoKSB7IHJldHVybiB0aGlzLmltZyA/PyBcIlwiOyB9XG4gICAgZ2V0RmFjdG9yVG90YWwoZmFjdG9yKSB7XG4gICAgICAgIHN3aXRjaCAoZmFjdG9yKSB7XG4gICAgICAgICAgICBjYXNlIEZhY3Rvci50aWVyOiByZXR1cm4gdGhpcy5zeXN0ZW0udGllci52YWx1ZTtcbiAgICAgICAgICAgIGNhc2UgRmFjdG9yLnF1YWxpdHk6IHJldHVybiB0aGlzLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKTtcbiAgICAgICAgICAgIGNhc2UgRmFjdG9yLnNjYWxlOiByZXR1cm4gMDtcbiAgICAgICAgICAgIGNhc2UgRmFjdG9yLm1hZ25pdHVkZTogcmV0dXJuIDA7XG4gICAgICAgICAgICBkZWZhdWx0OiByZXR1cm4gMDtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBPVkVSUklERVM6IF9vblVwZGF0ZVxuICAgIGFzeW5jIF9vblVwZGF0ZShjaGFuZ2VkLCBvcHRpb25zLCB1c2VySWQpIHtcbiAgICAgICAgc3VwZXIuX29uVXBkYXRlKGNoYW5nZWQsIG9wdGlvbnMsIHVzZXJJZCk7XG4gICAgICAgIEJsYWRlc0FjdG9yLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUucGMpLmZvckVhY2goKGFjdG9yKSA9PiBhY3Rvci5yZW5kZXIoKSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzU2NvcmU7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/documents/items/BladesScore.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/actor/BladesActorSheet.ts": +/*!*********************************************!*\ + !*** ./ts/sheets/actor/BladesActorSheet.ts ***! + \*********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_tags__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../core/tags */ \"./ts/core/tags.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ../../classes/BladesDialog */ \"./ts/classes/BladesDialog.ts\");\n/* harmony import */ var _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ../../documents/BladesActiveEffect */ \"./ts/documents/BladesActiveEffect.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ../../classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n// #region IMPORTS~\n\n\n\n\n\n\n\n\n\n// #endregion\nclass BladesActorSheet extends ActorSheet {\n /**\n * Override the default getData method to provide additional data for the actor sheet.\n * This includes: cssClass, editable, isGM, actor, system, tierTotal, rollData, activeEffects,\n * hasFullVision, hasLimitedVision, hasControl, preparedItems.\n * @returns {BladesActorSheetData} The data object for the actor sheet.\n */\n getData() {\n // Get the base data context from the parent class.\n const context = super.getData();\n // Prepare additional data specific to this actor's sheet.\n const sheetData = {\n // Basic actor data.\n cssClass: this.actor.type,\n editable: this.options.editable,\n isGM: game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM,\n actor: this.actor,\n system: this.actor.system,\n gamePhase: game.eunoblades.Tracker?.phase || _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesPhase.Freeplay,\n tierTotal: this.actor.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier) > 0 ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(this.actor.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier)) : \"0\",\n rollData: this.actor.getRollData(),\n activeEffects: Array.from(this.actor.effects),\n hasFullVision: game.user.isGM\n || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OBSERVER),\n hasLimitedVision: game.user.isGM\n || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.LIMITED),\n hasControl: game.user.isGM || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER)\n };\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.actor) || _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesCrew.IsType(this.actor)) {\n // Prepare items for display on the actor sheet.\n sheetData.preparedItems = {\n abilities: [],\n loadout: [],\n cohorts: {\n gang: this.actor.cohorts\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesItemType.cohort_gang)\n .map((item) => {\n // Prepare gang cohort items.\n const subtypes = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique(Object.values(item.system.subtypes)\n .map((subtype) => subtype.trim())\n .filter((subtype) => /[A-Za-z]/.test(subtype)));\n const eliteSubtypes = [\n ...Object.values(item.system.elite_subtypes)\n ];\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesCrew.IsType(item.parent)) {\n eliteSubtypes.push(...(item.parent.upgrades ?? [])\n .map((upgrade) => (upgrade.name ?? \"\").trim().replace(/^Elite /, \"\")));\n }\n // Prepare images for gang cohort items.\n const imgTypes = [..._core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique(eliteSubtypes.map((subtype) => subtype.trim())\n .filter((subtype) => /[A-Za-z]/\n .test(subtype) && subtypes.includes(subtype)))];\n if (imgTypes.length < 2) {\n imgTypes.push(...subtypes.filter((subtype) => !imgTypes.includes(subtype)));\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique(imgTypes).length === 1) {\n item.system.image = Object.values(item.system.elite_subtypes).includes(imgTypes[0]) ? `elite-${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(imgTypes[0])}.svg` : `${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(imgTypes[0])}.svg`;\n }\n else if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].unique(imgTypes).length > 1) {\n const [rightType, leftType] = imgTypes;\n item.system.imageLeft = Object.values(item.system.elite_subtypes).includes(leftType) ? `elite-${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(leftType)}.svg` : `${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(leftType)}.svg`;\n item.system.imageRight = Object.values(item.system.elite_subtypes).includes(rightType) ? `elite-${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(rightType)}.svg` : `${_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(rightType)}.svg`;\n }\n // Prepare additional data for gang cohort items.\n Object.assign(item.system, {\n tierTotal: item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier) > 0 ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier)) : \"0\",\n cohortRollData: [\n { mode: \"untrained\", label: \"Untrained\", color: \"transparent\", tooltip: \"

Roll Untrained

\" }\n ],\n edgeData: Object.fromEntries(Object.values(item.system.edges ?? [])\n .filter((edge) => /[A-Za-z]/.test(edge))\n .map((edge) => [edge.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_2__[\"default\"].EdgeTooltips[edge]])),\n flawData: Object.fromEntries(Object.values(item.system.flaws ?? [])\n .filter((flaw) => /[A-Za-z]/.test(flaw))\n .map((flaw) => [flaw.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_2__[\"default\"].FlawTooltips[flaw]]))\n });\n return item;\n }),\n expert: this.actor.activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesItemType.cohort_expert)\n .map((item) => {\n // Prepare expert cohort items.\n Object.assign(item.system, {\n tierTotal: item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier) > 0 ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].romanizeNum(item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor.tier)) : \"0\",\n cohortRollData: [\n { mode: \"untrained\", label: \"Untrained\", tooltip: \"

Roll Untrained

\" }\n ],\n edgeData: Object.fromEntries(Object.values(item.system.edges ?? [])\n .filter((edge) => /[A-Za-z]/.test(edge))\n .map((edge) => [edge.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_2__[\"default\"].EdgeTooltips[edge]])),\n flawData: Object.fromEntries(Object.values(item.system.flaws ?? [])\n .filter((flaw) => /[A-Za-z]/.test(flaw))\n .map((flaw) => [flaw.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_2__[\"default\"].FlawTooltips[flaw]]))\n });\n return item;\n })\n },\n projects: []\n };\n }\n // Prepare additional data for PC and Crew actors.\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesActor.IsType(this.actor, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc) || _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesActor.IsType(this.actor, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.crew)) {\n sheetData.playbookData = {\n dotline: {\n data: this.actor.system.experience.playbook,\n dotlineClass: \"xp-playbook\",\n target: \"system.experience.playbook.value\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|frame\",\n svgEmpty: \"full|half|frame\",\n advanceButton: \"advance-playbook\"\n }\n };\n if (this.actor.system.experience.playbook.value !== this.actor.system.experience.playbook.max) {\n sheetData.playbookData.tooltip = (new Handlebars.SafeString([\n \"

At the End of the Session, Gain XP If ...

\",\n \"
    \",\n ...Object.values(this.actor.system.experience.clues ?? []).map((line) => `
  • ${line.replace(/^Y/, \"... y\")}
  • `) ?? [],\n \"
\"\n ].join(\"\"))).toString();\n }\n sheetData.coinsData = {\n dotline: {\n data: this.actor.system.coins,\n target: \"system.coins.value\",\n iconEmpty: \"coin-full.svg\",\n iconFull: \"coin-full.svg\"\n }\n };\n }\n // Return the combined data context for the actor sheet.\n return {\n ...context,\n ...sheetData\n };\n }\n // #region LISTENERS & EVENT HANDLERS\n activateListeners(html) {\n super.activateListeners(html);\n // Handle removal or revealing of secret information content.\n if (game.user.isGM) {\n html.attr(\"style\", \"--secret-text-display: initial\");\n }\n else {\n html.find('.editor:not(.tinymce) [data-is-secret=\"true\"]').remove();\n }\n // ~ Tooltips\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_1__.ApplyTooltipAnimations)(html);\n _core_tags__WEBPACK_IMPORTED_MODULE_3__[\"default\"].InitListeners(html, this.actor);\n // Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n // Add dotline functionality\n html.find(\".dotline\").each((__, elem) => {\n if ($(elem).hasClass(\"locked\")) {\n return;\n }\n let targetDoc = this.actor;\n let targetField = $(elem).data(\"target\");\n const comp$ = $(elem).closest(\"comp\");\n if (targetField.startsWith(\"item\")) {\n targetField = targetField.replace(/^item\\./, \"\");\n const itemId = $(elem).closest(\"[data-comp-id]\").data(\"compId\");\n if (!itemId) {\n return;\n }\n const item = this.actor.items.get(itemId);\n if (!item) {\n return;\n }\n targetDoc = item;\n }\n const curValue = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt($(elem).data(\"value\"));\n $(elem)\n .find(\".dot\")\n .each((_, dot) => {\n $(dot).on(\"click\", (event) => {\n event.preventDefault();\n const thisValue = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt($(dot).data(\"value\"));\n if (thisValue !== curValue) {\n if (comp$.hasClass(\"comp-coins\")\n || comp$.hasClass(\"comp-stash\")) {\n _core_gsap__WEBPACK_IMPORTED_MODULE_1__[\"default\"].effects\n .fillCoins($(dot).prevAll(\".dot\"))\n .then(() => targetDoc.update({ [targetField]: thisValue }));\n }\n else {\n targetDoc.update({ [targetField]: thisValue });\n }\n }\n });\n $(dot).on(\"contextmenu\", (event) => {\n event.preventDefault();\n const thisValue = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt($(dot).data(\"value\")) - 1;\n if (thisValue !== curValue) {\n targetDoc.update({ [targetField]: thisValue });\n }\n });\n });\n });\n // Component Functionality: Open, Add (via SelectorDialog), Archive, Delete, Toggle, Select\n html\n .find(\"[data-comp-id]\")\n .find(\".comp-title\")\n .on({ click: this._onItemOpenClick.bind(this) });\n html\n .find(\".comp-control.comp-add\")\n .on({ click: this._onItemAddClick.bind(this) });\n html\n .find(\".comp-control.comp-delete\")\n .on({ click: this._onItemRemoveClick.bind(this) });\n html\n .find(\".comp-control.comp-delete-full\")\n .on({ click: this._onItemFullRemoveClick.bind(this) });\n html\n .find(\".comp-control.comp-toggle\")\n .on({ click: this._onItemToggleClick.bind(this) });\n html\n .find(`\r\n select[data-action='player-select'],\r\n select[data-action='gm-select']\r\n `)\n .on({ change: this._onSelectChange.bind(this) });\n html\n .find(\"[data-action='toggle-value'\")\n .on({ click: this._onToggleValueClick.bind(this) });\n html\n .find(\".advance-button\")\n .on({ click: this._onAdvanceClick.bind(this) });\n // Active Effects Functionality\n html\n .find(\".effect-control\")\n .on({ click: this._onActiveEffectControlClick.bind(this) });\n // Roll Functionality\n html\n .find(\"[data-roll-trait]\")\n .on({ click: this._onRollTraitClick.bind(this) });\n // Downtime Actions\n html\n .find(\"[data-action*='downtime-action-']\")\n .on({ click: this._onDowntimeActionClick.bind(this) });\n // This is a workaround until is being fixed in FoundryVTT.\n if (this.options.submitOnChange) {\n html.on(\"change\", \"textarea\", this._onChangeInput.bind(this)); // Use delegated listener on the form\n }\n }\n async _onSubmit(event, params = {}) {\n if (!game.user.isGM && !this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER)) {\n eLog.checkLog(\"actorSheetTrigger\", \"User does not have permission to edit this actor\", { user: game.user, actor: this.actor });\n return {};\n }\n return super._onSubmit(event, params);\n }\n async close(options) {\n if (this.actor.type === _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.pc) {\n return super.close(options).then(() => this.actor.clearSubActors());\n }\n else if (this.actor.type === _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.npc && this.actor.parentActor) {\n return super.close(options).then(() => this.actor.clearParentActor(false));\n }\n return super.close(options);\n }\n // #region Component Handlers\n _getCompData(event) {\n const elem$ = $(event.currentTarget).closest(\".comp\");\n const compData = {\n elem$,\n docID: elem$.data(\"compId\"),\n docCat: elem$.data(\"compCat\"),\n docType: elem$.data(\"compType\"),\n docTags: (elem$.data(\"compTags\") ?? \"\").split(/\\s+/g)\n };\n eLog.checkLog2(\"dialog\", \"Component Data\", { elem: elem$, ...compData });\n if (compData.docID && compData.docType) {\n compData.doc = {\n Actor: this.actor.getSubActor(compData.docID),\n Item: this.actor.getSubItem(compData.docID)\n }[compData.docType];\n }\n if (compData.docCat && compData.docType && (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.actor) || _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesCrew.IsType(this.actor))) {\n compData.dialogDocs = {\n Actor: this.actor.getDialogActors(compData.docCat),\n Item: this.actor.getDialogItems(compData.docCat)\n }[compData.docType];\n }\n return compData;\n }\n _onItemOpenClick(event) {\n event.preventDefault();\n const { doc } = this._getCompData(event);\n if (!doc) {\n return;\n }\n doc.sheet?.render(true);\n }\n async _onItemAddClick(event) {\n event.preventDefault();\n const addType = $(event.currentTarget).closest(\".comp\").data(\"addType\");\n if (addType && addType in _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesItemType) {\n await this.actor.createEmbeddedDocuments(\"Item\", [\n {\n name: {\n [_core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesItemType.cohort_gang]: \"A Gang\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesItemType.cohort_expert]: \"An Expert\"\n }[addType] ?? randomID(),\n type: addType\n }\n ]);\n return;\n }\n const { docCat, docType, dialogDocs, docTags } = this._getCompData(event);\n if (!dialogDocs || !docCat || !docType) {\n return;\n }\n await _classes_BladesDialog__WEBPACK_IMPORTED_MODULE_6__[\"default\"].DisplaySelectionDialog(this.actor, _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(`Add ${docCat.replace(/_/g, \" \")}`), docType, dialogDocs, docTags);\n }\n async _onItemRemoveClick(event) {\n event.preventDefault();\n const { elem$, doc } = this._getCompData(event);\n if (!doc) {\n return;\n }\n await _core_gsap__WEBPACK_IMPORTED_MODULE_1__[\"default\"].effects.blurRemove(elem$).then(async () => {\n if (doc instanceof _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesItem) {\n await this.actor.remSubItem(doc);\n }\n else {\n await this.actor.remSubActor(doc);\n }\n });\n }\n async _onItemFullRemoveClick(event) {\n event.preventDefault();\n const { elem$, doc } = this._getCompData(event);\n if (!doc) {\n return;\n }\n await _core_gsap__WEBPACK_IMPORTED_MODULE_1__[\"default\"].effects.blurRemove(elem$).then(async () => await doc.delete());\n }\n async _onItemToggleClick(event) {\n event.preventDefault();\n const target = $(event.currentTarget).data(\"target\");\n await this.actor.update({\n [target]: !getProperty(this.actor, target)\n });\n }\n async _onSelectChange(event) {\n event.preventDefault();\n await _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].EventHandlers.onSelectChange(this, event);\n }\n async _onToggleValueClick(event) {\n event.preventDefault();\n const elem$ = $(event.currentTarget);\n const targetKey = elem$.data(\"target\");\n const toggleOnVal = elem$.data(\"toggleOnVal\") || \"\";\n const toggleOffVal = elem$.data(\"toggleOffVal\") || \"\";\n if (getProperty(this.actor, targetKey) === toggleOnVal) {\n await this.actor.update({ [targetKey]: toggleOffVal });\n }\n else {\n await this.actor.update({ [targetKey]: toggleOnVal });\n }\n }\n async _onAdvanceClick(event) {\n event.preventDefault();\n if ($(event.currentTarget).data(\"action\") === \"advance-playbook\") {\n await this.actor.advancePlaybook();\n }\n }\n // #endregion\n // #region Roll Handlers\n async _onRollTraitClick(event) {\n const traitName = $(event.currentTarget).data(\"rollTrait\");\n const rollType = $(event.currentTarget).data(\"rollType\");\n const rollData = {\n target: this.actor,\n targetFlagKey: \"rollCollab\"\n };\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(traitName) in { ..._core_constants__WEBPACK_IMPORTED_MODULE_2__.ActionTrait, ..._core_constants__WEBPACK_IMPORTED_MODULE_2__.AttributeTrait, ..._core_constants__WEBPACK_IMPORTED_MODULE_2__.Factor }) {\n rollData.rollTrait = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].lCase(traitName);\n }\n else if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(traitName)) {\n rollData.rollTrait = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(traitName);\n }\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(rollType) in _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType) {\n rollData.rollType = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].tCase(rollType);\n }\n else if (typeof rollData.rollTrait === \"string\") {\n if (rollData.rollTrait in _core_constants__WEBPACK_IMPORTED_MODULE_2__.AttributeTrait) {\n rollData.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Resistance;\n }\n else if (rollData.rollTrait in _core_constants__WEBPACK_IMPORTED_MODULE_2__.ActionTrait) {\n rollData.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Action;\n }\n }\n if (game.user.isGM) {\n if (_classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesRollPrimary.IsDoc(this.actor)) {\n rollData.rollPrimaryData = this.actor;\n }\n else if (_classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesRollOpposition.IsDoc(this.actor)) {\n rollData.rollOppData = this.actor;\n }\n }\n await _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesActionRoll.New(rollData);\n }\n // Returns TRUE if can proceed, FALSE if action should stop (i.e. panel revealed for another user click)\n async _validateOrRevealSubData(downtimeAction, actionSubData) {\n switch (downtimeAction) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.LongTermProject: {\n // actionSubData must be \"NewProject\" or an id string to a project owned by this actor.\n if (actionSubData === \"NewProject\") {\n // Create new blank project owned by this.actor and render it for actor to edit.\n return false;\n }\n const projectItem = game.items.get(actionSubData ?? \"\");\n if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_5__.BladesProject.IsType(projectItem)) {\n return true;\n }\n // actionSubData isn't provided, which means this was the basic \"Project\" action button and sub-buttons must be revealed.\n // Record Flip state of Downtime mid-bar\n // Construct sub-button container, append it to Downtime mid-bar\n // Construct \"NewProject\" button, append it to sub-button container\n // Construct buttons for each owned project, append to sub-button container\n // Run Flip.from animation\n return false;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.Recover: {\n // actionSubData must be a valid actor ID, who will become rollPrimary.\n const healerActor = game.actors.get(actionSubData ?? \"\");\n if (healerActor instanceof _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesActor && healerActor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_2__.Tag.NPC.CanHeal)) {\n return true;\n }\n // actionSubData isn't provided, which means this was the basic \"Recover\" action button and sub-buttons must be revealed.\n // Record Flip state of Downtime mid-bar\n // Construct sub-button container, append it to Downtime mid-bar\n // Compile list of PC characters with CanHeal tag.\n // Compile list of _visible_ NPC characters with CanHeal tag.\n // Append buttons to sub-button container\n // Run Flip.from animation\n return false;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.Train: {\n // actionSubData must be of form 'playbook:2'\n return Boolean(/^[a-z]+:\\d$/.exec(actionSubData ?? \"\"));\n }\n // Other actions do not need subData validation and can always proceed:\n default: return true;\n }\n }\n async _onDowntimeActionClick(event) {\n const elem$ = $(event.currentTarget);\n // Extract the downtimeAction -- the substring of elem$.data(\"action\") following the last hyphen (-)\n const downtimeAction = elem$.data(\"action\").substring(elem$.data(\"action\").lastIndexOf(\"-\") + 1);\n // Extract the subData attribute\n const actionSubData = elem$.data(\"actionSubData\");\n // Validate subData: If invalid, subData buttons will be revealed -- return and wait for one to be clicked.\n if (!(await this._validateOrRevealSubData(downtimeAction, actionSubData))) {\n $(\"#eunos-blades-tooltips\").children(\".tooltip\").remove();\n await this.actor.update({ \"system.downtime_actions_open_submenu\": downtimeAction });\n $(\"#eunos-blades-tooltips\").children(\".tooltip\").remove();\n return;\n }\n const config = {\n target: this.actor,\n targetFlagKey: \"rollCollab\",\n rollDowntimeAction: downtimeAction\n };\n // Set necessary fields on roll construction config object, depending on downtime action\n switch (downtimeAction) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.AcquireAsset:\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.LongTermProject:\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.ReduceHeat: {\n config.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Action;\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.Recover: {\n config.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Action;\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.actor) && this.actor.healingClock) {\n config.rollClockKey = this.actor.healingClock.id;\n }\n // rollOpposition = user character's healing clock\n // rollPrimary = this.actor is NPC?\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.IndulgeVice: {\n config.rollType = _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.IndulgeVice;\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.Train: {\n const [attr, value] = actionSubData.split(/:/);\n if (attr === \"playbook\") {\n this.actor.update({ [`system.experience.${attr}.value`]: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt((this.actor.system.experience?.playbook?.value ?? 0)) + _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(value) });\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_4__.BladesPC.IsType(this.actor)) {\n this.actor.update({ [`system.experience.${attr}.value`]: _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(this.actor.system.experience[attr].value) + _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(value) });\n }\n // Increase track XP: If above max, set rollover value\n break;\n }\n default: {\n // This is for custom downtime actions added by, e.g., ActiveEffects.\n break;\n }\n }\n // Clear any open submenus, and add one to downtime actions used.\n await this.actor.update({\n \"system.downtime_actions_open_submenu\": \"\",\n \"system.downtime_actions.value\": (this.actor.system.downtime_actions?.value ?? 0) + 1\n });\n if (\"rollType\" in config) {\n if (downtimeAction === _core_constants__WEBPACK_IMPORTED_MODULE_2__.DowntimeAction.IndulgeVice) {\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesIndulgeViceRoll.New(config);\n }\n else {\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesActionRoll.New(config);\n }\n }\n }\n async _onGatherInfoClick(event) {\n const elem$ = $(event.currentTarget);\n if (elem$.data(\"isFortuneRoll\")) {\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesFortuneRoll.New({\n target: this.actor,\n targetFlagKey: \"rollCollab\",\n rollType: _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Fortune\n });\n }\n else {\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_8__.BladesActionRoll.New({\n target: this.actor,\n targetFlagKey: \"rollCollab\",\n rollType: _core_constants__WEBPACK_IMPORTED_MODULE_2__.RollType.Action,\n rollTrait: \"\"\n });\n }\n }\n // #endregion\n // #region Active Effect Handlers\n _onActiveEffectControlClick(event) {\n _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_7__[\"default\"].onManageActiveEffect(event, this.actor);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesActorSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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LFNBQVM7QUFDVDtBQUNBLG1DQUFtQywyREFBYztBQUNqRCxnQkFBZ0Isc0VBQXFCO0FBQ3JDO0FBQ0E7QUFDQSxnQkFBZ0IsaUVBQWdCO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksa0VBQWlCO0FBQzdCO0FBQ0E7QUFDQSwwQkFBMEIscURBQVE7QUFDbEMsYUFBYTtBQUNiO0FBQ0E7QUFDQSxZQUFZLGlFQUFnQjtBQUM1QjtBQUNBO0FBQ0EsMEJBQTBCLHFEQUFRO0FBQ2xDO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRLHFFQUFrQjtBQUMxQjtBQUNBO0FBQ0EsK0RBQWUsZ0JBQWdCLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9zaGVldHMvYWN0b3IvQmxhZGVzQWN0b3JTaGVldC50cz9hYTFlIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuLy8gI3JlZ2lvbiBJTVBPUlRTflxuaW1wb3J0IFUgZnJvbSBcIi4uLy4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgRywgeyBBcHBseVRvb2x0aXBBbmltYXRpb25zIH0gZnJvbSBcIi4uLy4uL2NvcmUvZ3NhcFwiO1xuaW1wb3J0IEMsIHsgQmxhZGVzQWN0b3JUeXBlLCBCbGFkZXNQaGFzZSwgQmxhZGVzSXRlbVR5cGUsIERvd250aW1lQWN0aW9uLCBBdHRyaWJ1dGVUcmFpdCwgVGFnLCBBY3Rpb25UcmFpdCwgRmFjdG9yLCBSb2xsVHlwZSB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IFRhZ3MgZnJvbSBcIi4uLy4uL2NvcmUvdGFnc1wiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3IsIEJsYWRlc1BDLCBCbGFkZXNDcmV3IH0gZnJvbSBcIi4uLy4uL2RvY3VtZW50cy9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgeyBCbGFkZXNJdGVtLCBCbGFkZXNQcm9qZWN0IH0gZnJvbSBcIi4uLy4uL2RvY3VtZW50cy9CbGFkZXNJdGVtUHJveHlcIjtcbmltcG9ydCBCbGFkZXNEaWFsb2cgZnJvbSBcIi4uLy4uL2NsYXNzZXMvQmxhZGVzRGlhbG9nXCI7XG5pbXBvcnQgQmxhZGVzQWN0aXZlRWZmZWN0IGZyb20gXCIuLi8uLi9kb2N1bWVudHMvQmxhZGVzQWN0aXZlRWZmZWN0XCI7XG5pbXBvcnQgeyBCbGFkZXNSb2xsUHJpbWFyeSwgQmxhZGVzUm9sbE9wcG9zaXRpb24sIEJsYWRlc0FjdGlvblJvbGwsIEJsYWRlc0ZvcnR1bmVSb2xsLCBCbGFkZXNJbmR1bGdlVmljZVJvbGwgfSBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNSb2xsXCI7XG4vLyAjZW5kcmVnaW9uXG5jbGFzcyBCbGFkZXNBY3RvclNoZWV0IGV4dGVuZHMgQWN0b3JTaGVldCB7XG4gICAgLyoqXG4gICAgICogT3ZlcnJpZGUgdGhlIGRlZmF1bHQgZ2V0RGF0YSBtZXRob2QgdG8gcHJvdmlkZSBhZGRpdGlvbmFsIGRhdGEgZm9yIHRoZSBhY3RvciBzaGVldC5cbiAgICAgKiBUaGlzIGluY2x1ZGVzOiBjc3NDbGFzcywgZWRpdGFibGUsIGlzR00sIGFjdG9yLCBzeXN0ZW0sIHRpZXJUb3RhbCwgcm9sbERhdGEsIGFjdGl2ZUVmZmVjdHMsXG4gICAgICogICAgICAgICAgICAgICAgIGhhc0Z1bGxWaXNpb24sIGhhc0xpbWl0ZWRWaXNpb24sIGhhc0NvbnRyb2wsIHByZXBhcmVkSXRlbXMuXG4gICAgICogQHJldHVybnMge0JsYWRlc0FjdG9yU2hlZXREYXRhfSBUaGUgZGF0YSBvYmplY3QgZm9yIHRoZSBhY3RvciBzaGVldC5cbiAgICAgKi9cbiAgICBnZXREYXRhKCkge1xuICAgICAgICAvLyBHZXQgdGhlIGJhc2UgZGF0YSBjb250ZXh0IGZyb20gdGhlIHBhcmVudCBjbGFzcy5cbiAgICAgICAgY29uc3QgY29udGV4dCA9IHN1cGVyLmdldERhdGEoKTtcbiAgICAgICAgLy8gUHJlcGFyZSBhZGRpdGlvbmFsIGRhdGEgc3BlY2lmaWMgdG8gdGhpcyBhY3RvcidzIHNoZWV0LlxuICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7XG4gICAgICAgICAgICAvLyBCYXNpYyBhY3RvciBkYXRhLlxuICAgICAgICAgICAgY3NzQ2xhc3M6IHRoaXMuYWN0b3IudHlwZSxcbiAgICAgICAgICAgIGVkaXRhYmxlOiB0aGlzLm9wdGlvbnMuZWRpdGFibGUsXG4gICAgICAgICAgICBpc0dNOiBnYW1lLmV1bm9ibGFkZXMuVHJhY2tlcj8uc3lzdGVtLmlzX3Nwb29maW5nX3BsYXllciA/IGZhbHNlIDogZ2FtZS51c2VyLmlzR00sXG4gICAgICAgICAgICBhY3RvcjogdGhpcy5hY3RvcixcbiAgICAgICAgICAgIHN5c3RlbTogdGhpcy5hY3Rvci5zeXN0ZW0sXG4gICAgICAgICAgICBnYW1lUGhhc2U6IGdhbWUuZXVub2JsYWRlcy5UcmFja2VyPy5waGFzZSB8fCBCbGFkZXNQaGFzZS5GcmVlcGxheSxcbiAgICAgICAgICAgIHRpZXJUb3RhbDogdGhpcy5hY3Rvci5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcikgPiAwID8gVS5yb21hbml6ZU51bSh0aGlzLmFjdG9yLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSkgOiBcIjBcIixcbiAgICAgICAgICAgIHJvbGxEYXRhOiB0aGlzLmFjdG9yLmdldFJvbGxEYXRhKCksXG4gICAgICAgICAgICBhY3RpdmVFZmZlY3RzOiBBcnJheS5mcm9tKHRoaXMuYWN0b3IuZWZmZWN0cyksXG4gICAgICAgICAgICBoYXNGdWxsVmlzaW9uOiBnYW1lLnVzZXIuaXNHTVxuICAgICAgICAgICAgICAgIHx8IHRoaXMuYWN0b3IudGVzdFVzZXJQZXJtaXNzaW9uKGdhbWUudXNlciwgQ09OU1QuRE9DVU1FTlRfUEVSTUlTU0lPTl9MRVZFTFMuT0JTRVJWRVIpLFxuICAgICAgICAgICAgaGFzTGltaXRlZFZpc2lvbjogZ2FtZS51c2VyLmlzR01cbiAgICAgICAgICAgICAgICB8fCB0aGlzLmFjdG9yLnRlc3RVc2VyUGVybWlzc2lvbihnYW1lLnVzZXIsIENPTlNULkRPQ1VNRU5UX1BFUk1JU1NJT05fTEVWRUxTLkxJTUlURUQpLFxuICAgICAgICAgICAgaGFzQ29udHJvbDogZ2FtZS51c2VyLmlzR00gfHwgdGhpcy5hY3Rvci50ZXN0VXNlclBlcm1pc3Npb24oZ2FtZS51c2VyLCBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5PV05FUilcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKEJsYWRlc1BDLklzVHlwZSh0aGlzLmFjdG9yKSB8fCBCbGFkZXNDcmV3LklzVHlwZSh0aGlzLmFjdG9yKSkge1xuICAgICAgICAgICAgLy8gUHJlcGFyZSBpdGVtcyBmb3IgZGlzcGxheSBvbiB0aGUgYWN0b3Igc2hlZXQuXG4gICAgICAgICAgICBzaGVldERhdGEucHJlcGFyZWRJdGVtcyA9IHtcbiAgICAgICAgICAgICAgICBhYmlsaXRpZXM6IFtdLFxuICAgICAgICAgICAgICAgIGxvYWRvdXQ6IFtdLFxuICAgICAgICAgICAgICAgIGNvaG9ydHM6IHtcbiAgICAgICAgICAgICAgICAgICAgZ2FuZzogdGhpcy5hY3Rvci5jb2hvcnRzXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nKVxuICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJlcGFyZSBnYW5nIGNvaG9ydCBpdGVtcy5cbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHN1YnR5cGVzID0gVS51bmlxdWUoT2JqZWN0LnZhbHVlcyhpdGVtLnN5c3RlbS5zdWJ0eXBlcylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChzdWJ0eXBlKSA9PiBzdWJ0eXBlLnRyaW0oKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChzdWJ0eXBlKSA9PiAvW0EtWmEtel0vLnRlc3Qoc3VidHlwZSkpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IGVsaXRlU3VidHlwZXMgPSBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLi4uT2JqZWN0LnZhbHVlcyhpdGVtLnN5c3RlbS5lbGl0ZV9zdWJ0eXBlcylcbiAgICAgICAgICAgICAgICAgICAgICAgIF07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoQmxhZGVzQ3Jldy5Jc1R5cGUoaXRlbS5wYXJlbnQpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxpdGVTdWJ0eXBlcy5wdXNoKC4uLihpdGVtLnBhcmVudC51cGdyYWRlcyA/PyBbXSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgodXBncmFkZSkgPT4gKHVwZ3JhZGUubmFtZSA/PyBcIlwiKS50cmltKCkucmVwbGFjZSgvXkVsaXRlIC8sIFwiXCIpKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBQcmVwYXJlIGltYWdlcyBmb3IgZ2FuZyBjb2hvcnQgaXRlbXMuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBpbWdUeXBlcyA9IFsuLi5VLnVuaXF1ZShlbGl0ZVN1YnR5cGVzLm1hcCgoc3VidHlwZSkgPT4gc3VidHlwZS50cmltKCkpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKHN1YnR5cGUpID0+IC9bQS1aYS16XS9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnRlc3Qoc3VidHlwZSkgJiYgc3VidHlwZXMuaW5jbHVkZXMoc3VidHlwZSkpKV07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaW1nVHlwZXMubGVuZ3RoIDwgMikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGltZ1R5cGVzLnB1c2goLi4uc3VidHlwZXMuZmlsdGVyKChzdWJ0eXBlKSA9PiAhaW1nVHlwZXMuaW5jbHVkZXMoc3VidHlwZSkpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChVLnVuaXF1ZShpbWdUeXBlcykubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5zeXN0ZW0uaW1hZ2UgPSBPYmplY3QudmFsdWVzKGl0ZW0uc3lzdGVtLmVsaXRlX3N1YnR5cGVzKS5pbmNsdWRlcyhpbWdUeXBlc1swXSkgPyBgZWxpdGUtJHtVLmxDYXNlKGltZ1R5cGVzWzBdKX0uc3ZnYCA6IGAke1UubENhc2UoaW1nVHlwZXNbMF0pfS5zdmdgO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiAoVS51bmlxdWUoaW1nVHlwZXMpLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zdCBbcmlnaHRUeXBlLCBsZWZ0VHlwZV0gPSBpbWdUeXBlcztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpdGVtLnN5c3RlbS5pbWFnZUxlZnQgPSBPYmplY3QudmFsdWVzKGl0ZW0uc3lzdGVtLmVsaXRlX3N1YnR5cGVzKS5pbmNsdWRlcyhsZWZ0VHlwZSkgPyBgZWxpdGUtJHtVLmxDYXNlKGxlZnRUeXBlKX0uc3ZnYCA6IGAke1UubENhc2UobGVmdFR5cGUpfS5zdmdgO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGl0ZW0uc3lzdGVtLmltYWdlUmlnaHQgPSBPYmplY3QudmFsdWVzKGl0ZW0uc3lzdGVtLmVsaXRlX3N1YnR5cGVzKS5pbmNsdWRlcyhyaWdodFR5cGUpID8gYGVsaXRlLSR7VS5sQ2FzZShyaWdodFR5cGUpfS5zdmdgIDogYCR7VS5sQ2FzZShyaWdodFR5cGUpfS5zdmdgO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUHJlcGFyZSBhZGRpdGlvbmFsIGRhdGEgZm9yIGdhbmcgY29ob3J0IGl0ZW1zLlxuICAgICAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihpdGVtLnN5c3RlbSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpZXJUb3RhbDogaXRlbS5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcikgPiAwID8gVS5yb21hbml6ZU51bShpdGVtLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSkgOiBcIjBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2hvcnRSb2xsRGF0YTogW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7IG1vZGU6IFwidW50cmFpbmVkXCIsIGxhYmVsOiBcIlVudHJhaW5lZFwiLCBjb2xvcjogXCJ0cmFuc3BhcmVudFwiLCB0b29sdGlwOiBcIjxwPlJvbGwgVW50cmFpbmVkPC9wPlwiIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVkZ2VEYXRhOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LnZhbHVlcyhpdGVtLnN5c3RlbS5lZGdlcyA/PyBbXSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZWRnZSkgPT4gL1tBLVphLXpdLy50ZXN0KGVkZ2UpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChlZGdlKSA9PiBbZWRnZS50cmltKCksIEMuRWRnZVRvb2x0aXBzW2VkZ2VdXSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZsYXdEYXRhOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LnZhbHVlcyhpdGVtLnN5c3RlbS5mbGF3cyA/PyBbXSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmZpbHRlcigoZmxhdykgPT4gL1tBLVphLXpdLy50ZXN0KGZsYXcpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChmbGF3KSA9PiBbZmxhdy50cmltKCksIEMuRmxhd1Rvb2x0aXBzW2ZsYXddXSkpXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBpdGVtO1xuICAgICAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICAgICAgZXhwZXJ0OiB0aGlzLmFjdG9yLmFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpXG4gICAgICAgICAgICAgICAgICAgICAgICAubWFwKChpdGVtKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBQcmVwYXJlIGV4cGVydCBjb2hvcnQgaXRlbXMuXG4gICAgICAgICAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKGl0ZW0uc3lzdGVtLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGllclRvdGFsOiBpdGVtLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSA+IDAgPyBVLnJvbWFuaXplTnVtKGl0ZW0uZ2V0RmFjdG9yVG90YWwoRmFjdG9yLnRpZXIpKSA6IFwiMFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvaG9ydFJvbGxEYXRhOiBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHsgbW9kZTogXCJ1bnRyYWluZWRcIiwgbGFiZWw6IFwiVW50cmFpbmVkXCIsIHRvb2x0aXA6IFwiPGgyPlJvbGwgVW50cmFpbmVkPC9oMj5cIiB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlZGdlRGF0YTogT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC52YWx1ZXMoaXRlbS5zeXN0ZW0uZWRnZXMgPz8gW10pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGVkZ2UpID0+IC9bQS1aYS16XS8udGVzdChlZGdlKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgoZWRnZSkgPT4gW2VkZ2UudHJpbSgpLCBDLkVkZ2VUb29sdGlwc1tlZGdlXV0pKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmbGF3RGF0YTogT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC52YWx1ZXMoaXRlbS5zeXN0ZW0uZmxhd3MgPz8gW10pXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5maWx0ZXIoKGZsYXcpID0+IC9bQS1aYS16XS8udGVzdChmbGF3KSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgoZmxhdykgPT4gW2ZsYXcudHJpbSgpLCBDLkZsYXdUb29sdGlwc1tmbGF3XV0pKVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaXRlbTtcbiAgICAgICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHByb2plY3RzOiBbXVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICAvLyBQcmVwYXJlIGFkZGl0aW9uYWwgZGF0YSBmb3IgUEMgYW5kIENyZXcgYWN0b3JzLlxuICAgICAgICBpZiAoQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMuYWN0b3IsIEJsYWRlc0FjdG9yVHlwZS5wYykgfHwgQmxhZGVzQWN0b3IuSXNUeXBlKHRoaXMuYWN0b3IsIEJsYWRlc0FjdG9yVHlwZS5jcmV3KSkge1xuICAgICAgICAgICAgc2hlZXREYXRhLnBsYXlib29rRGF0YSA9IHtcbiAgICAgICAgICAgICAgICBkb3RsaW5lOiB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IHRoaXMuYWN0b3Iuc3lzdGVtLmV4cGVyaWVuY2UucGxheWJvb2ssXG4gICAgICAgICAgICAgICAgICAgIGRvdGxpbmVDbGFzczogXCJ4cC1wbGF5Ym9va1wiLFxuICAgICAgICAgICAgICAgICAgICB0YXJnZXQ6IFwic3lzdGVtLmV4cGVyaWVuY2UucGxheWJvb2sudmFsdWVcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnS2V5OiBcInRlZXRoLnRhbGxcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnRnVsbDogXCJmdWxsfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0VtcHR5OiBcImZ1bGx8aGFsZnxmcmFtZVwiLFxuICAgICAgICAgICAgICAgICAgICBhZHZhbmNlQnV0dG9uOiBcImFkdmFuY2UtcGxheWJvb2tcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAodGhpcy5hY3Rvci5zeXN0ZW0uZXhwZXJpZW5jZS5wbGF5Ym9vay52YWx1ZSAhPT0gdGhpcy5hY3Rvci5zeXN0ZW0uZXhwZXJpZW5jZS5wbGF5Ym9vay5tYXgpIHtcbiAgICAgICAgICAgICAgICBzaGVldERhdGEucGxheWJvb2tEYXRhLnRvb2x0aXAgPSAobmV3IEhhbmRsZWJhcnMuU2FmZVN0cmluZyhbXG4gICAgICAgICAgICAgICAgICAgIFwiPGgyPkF0IHRoZSBFbmQgb2YgdGhlIFNlc3Npb24sIEdhaW4gWFAgSWYgLi4uPC9oMj5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8dWw+XCIsXG4gICAgICAgICAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXModGhpcy5hY3Rvci5zeXN0ZW0uZXhwZXJpZW5jZS5jbHVlcyA/PyBbXSkubWFwKChsaW5lKSA9PiBgPGxpPiR7bGluZS5yZXBsYWNlKC9eWS8sIFwiLi4uIHlcIil9PC9saT5gKSA/PyBbXSxcbiAgICAgICAgICAgICAgICAgICAgXCI8L3VsPlwiXG4gICAgICAgICAgICAgICAgXS5qb2luKFwiXCIpKSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNoZWV0RGF0YS5jb2luc0RhdGEgPSB7XG4gICAgICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgICAgICBkYXRhOiB0aGlzLmFjdG9yLnN5c3RlbS5jb2lucyxcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcInN5c3RlbS5jb2lucy52YWx1ZVwiLFxuICAgICAgICAgICAgICAgICAgICBpY29uRW1wdHk6IFwiY29pbi1mdWxsLnN2Z1wiLFxuICAgICAgICAgICAgICAgICAgICBpY29uRnVsbDogXCJjb2luLWZ1bGwuc3ZnXCJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG4gICAgICAgIC8vIFJldHVybiB0aGUgY29tYmluZWQgZGF0YSBjb250ZXh0IGZvciB0aGUgYWN0b3Igc2hlZXQuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgLi4uc2hlZXREYXRhXG4gICAgICAgIH07XG4gICAgfVxuICAgIC8vICNyZWdpb24gTElTVEVORVJTICYgRVZFTlQgSEFORExFUlNcbiAgICBhY3RpdmF0ZUxpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIHN1cGVyLmFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpO1xuICAgICAgICAvLyBIYW5kbGUgcmVtb3ZhbCBvciByZXZlYWxpbmcgb2Ygc2VjcmV0IGluZm9ybWF0aW9uIGNvbnRlbnQuXG4gICAgICAgIGlmIChnYW1lLnVzZXIuaXNHTSkge1xuICAgICAgICAgICAgaHRtbC5hdHRyKFwic3R5bGVcIiwgXCItLXNlY3JldC10ZXh0LWRpc3BsYXk6IGluaXRpYWxcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBodG1sLmZpbmQoJy5lZGl0b3I6bm90KC50aW55bWNlKSBbZGF0YS1pcy1zZWNyZXQ9XCJ0cnVlXCJdJykucmVtb3ZlKCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gfiBUb29sdGlwc1xuICAgICAgICBBcHBseVRvb2x0aXBBbmltYXRpb25zKGh0bWwpO1xuICAgICAgICBUYWdzLkluaXRMaXN0ZW5lcnMoaHRtbCwgdGhpcy5hY3Rvcik7XG4gICAgICAgIC8vIEV2ZXJ5dGhpbmcgYmVsb3cgaGVyZSBpcyBvbmx5IG5lZWRlZCBpZiB0aGUgc2hlZXQgaXMgZWRpdGFibGVcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZWRpdGFibGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBBZGQgZG90bGluZSBmdW5jdGlvbmFsaXR5XG4gICAgICAgIGh0bWwuZmluZChcIi5kb3RsaW5lXCIpLmVhY2goKF9fLCBlbGVtKSA9PiB7XG4gICAgICAgICAgICBpZiAoJChlbGVtKS5oYXNDbGFzcyhcImxvY2tlZFwiKSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxldCB0YXJnZXREb2MgPSB0aGlzLmFjdG9yO1xuICAgICAgICAgICAgbGV0IHRhcmdldEZpZWxkID0gJChlbGVtKS5kYXRhKFwidGFyZ2V0XCIpO1xuICAgICAgICAgICAgY29uc3QgY29tcCQgPSAkKGVsZW0pLmNsb3Nlc3QoXCJjb21wXCIpO1xuICAgICAgICAgICAgaWYgKHRhcmdldEZpZWxkLnN0YXJ0c1dpdGgoXCJpdGVtXCIpKSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0RmllbGQgPSB0YXJnZXRGaWVsZC5yZXBsYWNlKC9eaXRlbVxcLi8sIFwiXCIpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGl0ZW1JZCA9ICQoZWxlbSkuY2xvc2VzdChcIltkYXRhLWNvbXAtaWRdXCIpLmRhdGEoXCJjb21wSWRcIik7XG4gICAgICAgICAgICAgICAgaWYgKCFpdGVtSWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb25zdCBpdGVtID0gdGhpcy5hY3Rvci5pdGVtcy5nZXQoaXRlbUlkKTtcbiAgICAgICAgICAgICAgICBpZiAoIWl0ZW0pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0YXJnZXREb2MgPSBpdGVtO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgY3VyVmFsdWUgPSBVLnBJbnQoJChlbGVtKS5kYXRhKFwidmFsdWVcIikpO1xuICAgICAgICAgICAgJChlbGVtKVxuICAgICAgICAgICAgICAgIC5maW5kKFwiLmRvdFwiKVxuICAgICAgICAgICAgICAgIC5lYWNoKChfLCBkb3QpID0+IHtcbiAgICAgICAgICAgICAgICAkKGRvdCkub24oXCJjbGlja1wiLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGhpc1ZhbHVlID0gVS5wSW50KCQoZG90KS5kYXRhKFwidmFsdWVcIikpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpc1ZhbHVlICE9PSBjdXJWYWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGNvbXAkLmhhc0NsYXNzKFwiY29tcC1jb2luc1wiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IGNvbXAkLmhhc0NsYXNzKFwiY29tcC1zdGFzaFwiKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEcuZWZmZWN0c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuZmlsbENvaW5zKCQoZG90KS5wcmV2QWxsKFwiLmRvdFwiKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnRoZW4oKCkgPT4gdGFyZ2V0RG9jLnVwZGF0ZSh7IFt0YXJnZXRGaWVsZF06IHRoaXNWYWx1ZSB9KSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXREb2MudXBkYXRlKHsgW3RhcmdldEZpZWxkXTogdGhpc1ZhbHVlIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgJChkb3QpLm9uKFwiY29udGV4dG1lbnVcIiwgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHRoaXNWYWx1ZSA9IFUucEludCgkKGRvdCkuZGF0YShcInZhbHVlXCIpKSAtIDE7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzVmFsdWUgIT09IGN1clZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXREb2MudXBkYXRlKHsgW3RhcmdldEZpZWxkXTogdGhpc1ZhbHVlIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIENvbXBvbmVudCBGdW5jdGlvbmFsaXR5OiBPcGVuLCBBZGQgKHZpYSBTZWxlY3RvckRpYWxvZyksIEFyY2hpdmUsIERlbGV0ZSwgVG9nZ2xlLCBTZWxlY3RcbiAgICAgICAgaHRtbFxuICAgICAgICAgICAgLmZpbmQoXCJbZGF0YS1jb21wLWlkXVwiKVxuICAgICAgICAgICAgLmZpbmQoXCIuY29tcC10aXRsZVwiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uSXRlbU9wZW5DbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIi5jb21wLWNvbnRyb2wuY29tcC1hZGRcIilcbiAgICAgICAgICAgIC5vbih7IGNsaWNrOiB0aGlzLl9vbkl0ZW1BZGRDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIi5jb21wLWNvbnRyb2wuY29tcC1kZWxldGVcIilcbiAgICAgICAgICAgIC5vbih7IGNsaWNrOiB0aGlzLl9vbkl0ZW1SZW1vdmVDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIi5jb21wLWNvbnRyb2wuY29tcC1kZWxldGUtZnVsbFwiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uSXRlbUZ1bGxSZW1vdmVDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIi5jb21wLWNvbnRyb2wuY29tcC10b2dnbGVcIilcbiAgICAgICAgICAgIC5vbih7IGNsaWNrOiB0aGlzLl9vbkl0ZW1Ub2dnbGVDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChgXHJcbiAgICAgICAgc2VsZWN0W2RhdGEtYWN0aW9uPSdwbGF5ZXItc2VsZWN0J10sXHJcbiAgICAgICAgc2VsZWN0W2RhdGEtYWN0aW9uPSdnbS1zZWxlY3QnXVxyXG4gICAgICBgKVxuICAgICAgICAgICAgLm9uKHsgY2hhbmdlOiB0aGlzLl9vblNlbGVjdENoYW5nZS5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIltkYXRhLWFjdGlvbj0ndG9nZ2xlLXZhbHVlJ1wiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uVG9nZ2xlVmFsdWVDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIi5hZHZhbmNlLWJ1dHRvblwiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uQWR2YW5jZUNsaWNrLmJpbmQodGhpcykgfSk7XG4gICAgICAgIC8vIEFjdGl2ZSBFZmZlY3RzIEZ1bmN0aW9uYWxpdHlcbiAgICAgICAgaHRtbFxuICAgICAgICAgICAgLmZpbmQoXCIuZWZmZWN0LWNvbnRyb2xcIilcbiAgICAgICAgICAgIC5vbih7IGNsaWNrOiB0aGlzLl9vbkFjdGl2ZUVmZmVjdENvbnRyb2xDbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICAvLyBSb2xsIEZ1bmN0aW9uYWxpdHlcbiAgICAgICAgaHRtbFxuICAgICAgICAgICAgLmZpbmQoXCJbZGF0YS1yb2xsLXRyYWl0XVwiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uUm9sbFRyYWl0Q2xpY2suYmluZCh0aGlzKSB9KTtcbiAgICAgICAgLy8gRG93bnRpbWUgQWN0aW9uc1xuICAgICAgICBodG1sXG4gICAgICAgICAgICAuZmluZChcIltkYXRhLWFjdGlvbio9J2Rvd250aW1lLWFjdGlvbi0nXVwiKVxuICAgICAgICAgICAgLm9uKHsgY2xpY2s6IHRoaXMuX29uRG93bnRpbWVBY3Rpb25DbGljay5iaW5kKHRoaXMpIH0pO1xuICAgICAgICAvLyBUaGlzIGlzIGEgd29ya2Fyb3VuZCB1bnRpbCBpcyBiZWluZyBmaXhlZCBpbiBGb3VuZHJ5VlRULlxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnN1Ym1pdE9uQ2hhbmdlKSB7XG4gICAgICAgICAgICBodG1sLm9uKFwiY2hhbmdlXCIsIFwidGV4dGFyZWFcIiwgdGhpcy5fb25DaGFuZ2VJbnB1dC5iaW5kKHRoaXMpKTsgLy8gVXNlIGRlbGVnYXRlZCBsaXN0ZW5lciBvbiB0aGUgZm9ybVxuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIF9vblN1Ym1pdChldmVudCwgcGFyYW1zID0ge30pIHtcbiAgICAgICAgaWYgKCFnYW1lLnVzZXIuaXNHTSAmJiAhdGhpcy5hY3Rvci50ZXN0VXNlclBlcm1pc3Npb24oZ2FtZS51c2VyLCBDT05TVC5ET0NVTUVOVF9QRVJNSVNTSU9OX0xFVkVMUy5PV05FUikpIHtcbiAgICAgICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RvclNoZWV0VHJpZ2dlclwiLCBcIlVzZXIgZG9lcyBub3QgaGF2ZSBwZXJtaXNzaW9uIHRvIGVkaXQgdGhpcyBhY3RvclwiLCB7IHVzZXI6IGdhbWUudXNlciwgYWN0b3I6IHRoaXMuYWN0b3IgfSk7XG4gICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHN1cGVyLl9vblN1Ym1pdChldmVudCwgcGFyYW1zKTtcbiAgICB9XG4gICAgYXN5bmMgY2xvc2Uob3B0aW9ucykge1xuICAgICAgICBpZiAodGhpcy5hY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUucGMpIHtcbiAgICAgICAgICAgIHJldHVybiBzdXBlci5jbG9zZShvcHRpb25zKS50aGVuKCgpID0+IHRoaXMuYWN0b3IuY2xlYXJTdWJBY3RvcnMoKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAodGhpcy5hY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUubnBjICYmIHRoaXMuYWN0b3IucGFyZW50QWN0b3IpIHtcbiAgICAgICAgICAgIHJldHVybiBzdXBlci5jbG9zZShvcHRpb25zKS50aGVuKCgpID0+IHRoaXMuYWN0b3IuY2xlYXJQYXJlbnRBY3RvcihmYWxzZSkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdXBlci5jbG9zZShvcHRpb25zKTtcbiAgICB9XG4gICAgLy8gI3JlZ2lvbiBDb21wb25lbnQgSGFuZGxlcnNcbiAgICBfZ2V0Q29tcERhdGEoZXZlbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmNsb3Nlc3QoXCIuY29tcFwiKTtcbiAgICAgICAgY29uc3QgY29tcERhdGEgPSB7XG4gICAgICAgICAgICBlbGVtJCxcbiAgICAgICAgICAgIGRvY0lEOiBlbGVtJC5kYXRhKFwiY29tcElkXCIpLFxuICAgICAgICAgICAgZG9jQ2F0OiBlbGVtJC5kYXRhKFwiY29tcENhdFwiKSxcbiAgICAgICAgICAgIGRvY1R5cGU6IGVsZW0kLmRhdGEoXCJjb21wVHlwZVwiKSxcbiAgICAgICAgICAgIGRvY1RhZ3M6IChlbGVtJC5kYXRhKFwiY29tcFRhZ3NcIikgPz8gXCJcIikuc3BsaXQoL1xccysvZylcbiAgICAgICAgfTtcbiAgICAgICAgZUxvZy5jaGVja0xvZzIoXCJkaWFsb2dcIiwgXCJDb21wb25lbnQgRGF0YVwiLCB7IGVsZW06IGVsZW0kLCAuLi5jb21wRGF0YSB9KTtcbiAgICAgICAgaWYgKGNvbXBEYXRhLmRvY0lEICYmIGNvbXBEYXRhLmRvY1R5cGUpIHtcbiAgICAgICAgICAgIGNvbXBEYXRhLmRvYyA9IHtcbiAgICAgICAgICAgICAgICBBY3RvcjogdGhpcy5hY3Rvci5nZXRTdWJBY3Rvcihjb21wRGF0YS5kb2NJRCksXG4gICAgICAgICAgICAgICAgSXRlbTogdGhpcy5hY3Rvci5nZXRTdWJJdGVtKGNvbXBEYXRhLmRvY0lEKVxuICAgICAgICAgICAgfVtjb21wRGF0YS5kb2NUeXBlXTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29tcERhdGEuZG9jQ2F0ICYmIGNvbXBEYXRhLmRvY1R5cGUgJiYgKEJsYWRlc1BDLklzVHlwZSh0aGlzLmFjdG9yKSB8fCBCbGFkZXNDcmV3LklzVHlwZSh0aGlzLmFjdG9yKSkpIHtcbiAgICAgICAgICAgIGNvbXBEYXRhLmRpYWxvZ0RvY3MgPSB7XG4gICAgICAgICAgICAgICAgQWN0b3I6IHRoaXMuYWN0b3IuZ2V0RGlhbG9nQWN0b3JzKGNvbXBEYXRhLmRvY0NhdCksXG4gICAgICAgICAgICAgICAgSXRlbTogdGhpcy5hY3Rvci5nZXREaWFsb2dJdGVtcyhjb21wRGF0YS5kb2NDYXQpXG4gICAgICAgICAgICB9W2NvbXBEYXRhLmRvY1R5cGVdO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBjb21wRGF0YTtcbiAgICB9XG4gICAgX29uSXRlbU9wZW5DbGljayhldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBjb25zdCB7IGRvYyB9ID0gdGhpcy5fZ2V0Q29tcERhdGEoZXZlbnQpO1xuICAgICAgICBpZiAoIWRvYykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGRvYy5zaGVldD8ucmVuZGVyKHRydWUpO1xuICAgIH1cbiAgICBhc3luYyBfb25JdGVtQWRkQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgYWRkVHlwZSA9ICQoZXZlbnQuY3VycmVudFRhcmdldCkuY2xvc2VzdChcIi5jb21wXCIpLmRhdGEoXCJhZGRUeXBlXCIpO1xuICAgICAgICBpZiAoYWRkVHlwZSAmJiBhZGRUeXBlIGluIEJsYWRlc0l0ZW1UeXBlKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLmNyZWF0ZUVtYmVkZGVkRG9jdW1lbnRzKFwiSXRlbVwiLCBbXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBuYW1lOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBbQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmddOiBcIkEgR2FuZ1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnRdOiBcIkFuIEV4cGVydFwiXG4gICAgICAgICAgICAgICAgICAgIH1bYWRkVHlwZV0gPz8gcmFuZG9tSUQoKSxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogYWRkVHlwZVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIF0pO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHsgZG9jQ2F0LCBkb2NUeXBlLCBkaWFsb2dEb2NzLCBkb2NUYWdzIH0gPSB0aGlzLl9nZXRDb21wRGF0YShldmVudCk7XG4gICAgICAgIGlmICghZGlhbG9nRG9jcyB8fCAhZG9jQ2F0IHx8ICFkb2NUeXBlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgQmxhZGVzRGlhbG9nLkRpc3BsYXlTZWxlY3Rpb25EaWFsb2codGhpcy5hY3RvciwgVS50Q2FzZShgQWRkICR7ZG9jQ2F0LnJlcGxhY2UoL18vZywgXCIgXCIpfWApLCBkb2NUeXBlLCBkaWFsb2dEb2NzLCBkb2NUYWdzKTtcbiAgICB9XG4gICAgYXN5bmMgX29uSXRlbVJlbW92ZUNsaWNrKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IHsgZWxlbSQsIGRvYyB9ID0gdGhpcy5fZ2V0Q29tcERhdGEoZXZlbnQpO1xuICAgICAgICBpZiAoIWRvYykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IEcuZWZmZWN0cy5ibHVyUmVtb3ZlKGVsZW0kKS50aGVuKGFzeW5jICgpID0+IHtcbiAgICAgICAgICAgIGlmIChkb2MgaW5zdGFuY2VvZiBCbGFkZXNJdGVtKSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5hY3Rvci5yZW1TdWJJdGVtKGRvYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLnJlbVN1YkFjdG9yKGRvYyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhc3luYyBfb25JdGVtRnVsbFJlbW92ZUNsaWNrKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IHsgZWxlbSQsIGRvYyB9ID0gdGhpcy5fZ2V0Q29tcERhdGEoZXZlbnQpO1xuICAgICAgICBpZiAoIWRvYykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGF3YWl0IEcuZWZmZWN0cy5ibHVyUmVtb3ZlKGVsZW0kKS50aGVuKGFzeW5jICgpID0+IGF3YWl0IGRvYy5kZWxldGUoKSk7XG4gICAgfVxuICAgIGFzeW5jIF9vbkl0ZW1Ub2dnbGVDbGljayhldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICBjb25zdCB0YXJnZXQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJ0YXJnZXRcIik7XG4gICAgICAgIGF3YWl0IHRoaXMuYWN0b3IudXBkYXRlKHtcbiAgICAgICAgICAgIFt0YXJnZXRdOiAhZ2V0UHJvcGVydHkodGhpcy5hY3RvciwgdGFyZ2V0KVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgX29uU2VsZWN0Q2hhbmdlKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGF3YWl0IFUuRXZlbnRIYW5kbGVycy5vblNlbGVjdENoYW5nZSh0aGlzLCBldmVudCk7XG4gICAgfVxuICAgIGFzeW5jIF9vblRvZ2dsZVZhbHVlQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCB0YXJnZXRLZXkgPSBlbGVtJC5kYXRhKFwidGFyZ2V0XCIpO1xuICAgICAgICBjb25zdCB0b2dnbGVPblZhbCA9IGVsZW0kLmRhdGEoXCJ0b2dnbGVPblZhbFwiKSB8fCBcIlwiO1xuICAgICAgICBjb25zdCB0b2dnbGVPZmZWYWwgPSBlbGVtJC5kYXRhKFwidG9nZ2xlT2ZmVmFsXCIpIHx8IFwiXCI7XG4gICAgICAgIGlmIChnZXRQcm9wZXJ0eSh0aGlzLmFjdG9yLCB0YXJnZXRLZXkpID09PSB0b2dnbGVPblZhbCkge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5hY3Rvci51cGRhdGUoeyBbdGFyZ2V0S2V5XTogdG9nZ2xlT2ZmVmFsIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgYXdhaXQgdGhpcy5hY3Rvci51cGRhdGUoeyBbdGFyZ2V0S2V5XTogdG9nZ2xlT25WYWwgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgX29uQWR2YW5jZUNsaWNrKGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGlmICgkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJhY3Rpb25cIikgPT09IFwiYWR2YW5jZS1wbGF5Ym9va1wiKSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLmFkdmFuY2VQbGF5Ym9vaygpO1xuICAgICAgICB9XG4gICAgfVxuICAgIC8vICNlbmRyZWdpb25cbiAgICAvLyAjcmVnaW9uIFJvbGwgSGFuZGxlcnNcbiAgICBhc3luYyBfb25Sb2xsVHJhaXRDbGljayhldmVudCkge1xuICAgICAgICBjb25zdCB0cmFpdE5hbWUgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJyb2xsVHJhaXRcIik7XG4gICAgICAgIGNvbnN0IHJvbGxUeXBlID0gJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwicm9sbFR5cGVcIik7XG4gICAgICAgIGNvbnN0IHJvbGxEYXRhID0ge1xuICAgICAgICAgICAgdGFyZ2V0OiB0aGlzLmFjdG9yLFxuICAgICAgICAgICAgdGFyZ2V0RmxhZ0tleTogXCJyb2xsQ29sbGFiXCJcbiAgICAgICAgfTtcbiAgICAgICAgaWYgKFUubENhc2UodHJhaXROYW1lKSBpbiB7IC4uLkFjdGlvblRyYWl0LCAuLi5BdHRyaWJ1dGVUcmFpdCwgLi4uRmFjdG9yIH0pIHtcbiAgICAgICAgICAgIHJvbGxEYXRhLnJvbGxUcmFpdCA9IFUubENhc2UodHJhaXROYW1lKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmIChVLmlzSW50KHRyYWl0TmFtZSkpIHtcbiAgICAgICAgICAgIHJvbGxEYXRhLnJvbGxUcmFpdCA9IFUucEludCh0cmFpdE5hbWUpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChVLnRDYXNlKHJvbGxUeXBlKSBpbiBSb2xsVHlwZSkge1xuICAgICAgICAgICAgcm9sbERhdGEucm9sbFR5cGUgPSBVLnRDYXNlKHJvbGxUeXBlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICh0eXBlb2Ygcm9sbERhdGEucm9sbFRyYWl0ID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICBpZiAocm9sbERhdGEucm9sbFRyYWl0IGluIEF0dHJpYnV0ZVRyYWl0KSB7XG4gICAgICAgICAgICAgICAgcm9sbERhdGEucm9sbFR5cGUgPSBSb2xsVHlwZS5SZXNpc3RhbmNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAocm9sbERhdGEucm9sbFRyYWl0IGluIEFjdGlvblRyYWl0KSB7XG4gICAgICAgICAgICAgICAgcm9sbERhdGEucm9sbFR5cGUgPSBSb2xsVHlwZS5BY3Rpb247XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGdhbWUudXNlci5pc0dNKSB7XG4gICAgICAgICAgICBpZiAoQmxhZGVzUm9sbFByaW1hcnkuSXNEb2ModGhpcy5hY3RvcikpIHtcbiAgICAgICAgICAgICAgICByb2xsRGF0YS5yb2xsUHJpbWFyeURhdGEgPSB0aGlzLmFjdG9yO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAoQmxhZGVzUm9sbE9wcG9zaXRpb24uSXNEb2ModGhpcy5hY3RvcikpIHtcbiAgICAgICAgICAgICAgICByb2xsRGF0YS5yb2xsT3BwRGF0YSA9IHRoaXMuYWN0b3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgYXdhaXQgQmxhZGVzQWN0aW9uUm9sbC5OZXcocm9sbERhdGEpO1xuICAgIH1cbiAgICAvLyBSZXR1cm5zIFRSVUUgaWYgY2FuIHByb2NlZWQsIEZBTFNFIGlmIGFjdGlvbiBzaG91bGQgc3RvcCAoaS5lLiBwYW5lbCByZXZlYWxlZCBmb3IgYW5vdGhlciB1c2VyIGNsaWNrKVxuICAgIGFzeW5jIF92YWxpZGF0ZU9yUmV2ZWFsU3ViRGF0YShkb3dudGltZUFjdGlvbiwgYWN0aW9uU3ViRGF0YSkge1xuICAgICAgICBzd2l0Y2ggKGRvd250aW1lQWN0aW9uKSB7XG4gICAgICAgICAgICBjYXNlIERvd250aW1lQWN0aW9uLkxvbmdUZXJtUHJvamVjdDoge1xuICAgICAgICAgICAgICAgIC8vIGFjdGlvblN1YkRhdGEgbXVzdCBiZSBcIk5ld1Byb2plY3RcIiBvciBhbiBpZCBzdHJpbmcgdG8gYSBwcm9qZWN0IG93bmVkIGJ5IHRoaXMgYWN0b3IuXG4gICAgICAgICAgICAgICAgaWYgKGFjdGlvblN1YkRhdGEgPT09IFwiTmV3UHJvamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBuZXcgYmxhbmsgcHJvamVjdCBvd25lZCBieSB0aGlzLmFjdG9yIGFuZCByZW5kZXIgaXQgZm9yIGFjdG9yIHRvIGVkaXQuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY29uc3QgcHJvamVjdEl0ZW0gPSBnYW1lLml0ZW1zLmdldChhY3Rpb25TdWJEYXRhID8/IFwiXCIpO1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNQcm9qZWN0LklzVHlwZShwcm9qZWN0SXRlbSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGFjdGlvblN1YkRhdGEgaXNuJ3QgcHJvdmlkZWQsIHdoaWNoIG1lYW5zIHRoaXMgd2FzIHRoZSBiYXNpYyBcIlByb2plY3RcIiBhY3Rpb24gYnV0dG9uIGFuZCBzdWItYnV0dG9ucyBtdXN0IGJlIHJldmVhbGVkLlxuICAgICAgICAgICAgICAgIC8vIFJlY29yZCBGbGlwIHN0YXRlIG9mIERvd250aW1lIG1pZC1iYXJcbiAgICAgICAgICAgICAgICAvLyBDb25zdHJ1Y3Qgc3ViLWJ1dHRvbiBjb250YWluZXIsIGFwcGVuZCBpdCB0byBEb3dudGltZSBtaWQtYmFyXG4gICAgICAgICAgICAgICAgLy8gQ29uc3RydWN0IFwiTmV3UHJvamVjdFwiIGJ1dHRvbiwgYXBwZW5kIGl0IHRvIHN1Yi1idXR0b24gY29udGFpbmVyXG4gICAgICAgICAgICAgICAgLy8gQ29uc3RydWN0IGJ1dHRvbnMgZm9yIGVhY2ggb3duZWQgcHJvamVjdCwgYXBwZW5kIHRvIHN1Yi1idXR0b24gY29udGFpbmVyXG4gICAgICAgICAgICAgICAgLy8gUnVuIEZsaXAuZnJvbSBhbmltYXRpb25cbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIERvd250aW1lQWN0aW9uLlJlY292ZXI6IHtcbiAgICAgICAgICAgICAgICAvLyBhY3Rpb25TdWJEYXRhIG11c3QgYmUgYSB2YWxpZCBhY3RvciBJRCwgd2hvIHdpbGwgYmVjb21lIHJvbGxQcmltYXJ5LlxuICAgICAgICAgICAgICAgIGNvbnN0IGhlYWxlckFjdG9yID0gZ2FtZS5hY3RvcnMuZ2V0KGFjdGlvblN1YkRhdGEgPz8gXCJcIik7XG4gICAgICAgICAgICAgICAgaWYgKGhlYWxlckFjdG9yIGluc3RhbmNlb2YgQmxhZGVzQWN0b3IgJiYgaGVhbGVyQWN0b3IuaGFzVGFnKFRhZy5OUEMuQ2FuSGVhbCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIGFjdGlvblN1YkRhdGEgaXNuJ3QgcHJvdmlkZWQsIHdoaWNoIG1lYW5zIHRoaXMgd2FzIHRoZSBiYXNpYyBcIlJlY292ZXJcIiBhY3Rpb24gYnV0dG9uIGFuZCBzdWItYnV0dG9ucyBtdXN0IGJlIHJldmVhbGVkLlxuICAgICAgICAgICAgICAgIC8vIFJlY29yZCBGbGlwIHN0YXRlIG9mIERvd250aW1lIG1pZC1iYXJcbiAgICAgICAgICAgICAgICAvLyBDb25zdHJ1Y3Qgc3ViLWJ1dHRvbiBjb250YWluZXIsIGFwcGVuZCBpdCB0byBEb3dudGltZSBtaWQtYmFyXG4gICAgICAgICAgICAgICAgLy8gQ29tcGlsZSBsaXN0IG9mIFBDIGNoYXJhY3RlcnMgd2l0aCBDYW5IZWFsIHRhZy5cbiAgICAgICAgICAgICAgICAvLyBDb21waWxlIGxpc3Qgb2YgX3Zpc2libGVfIE5QQyBjaGFyYWN0ZXJzIHdpdGggQ2FuSGVhbCB0YWcuXG4gICAgICAgICAgICAgICAgLy8gQXBwZW5kIGJ1dHRvbnMgdG8gc3ViLWJ1dHRvbiBjb250YWluZXJcbiAgICAgICAgICAgICAgICAvLyBSdW4gRmxpcC5mcm9tIGFuaW1hdGlvblxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgRG93bnRpbWVBY3Rpb24uVHJhaW46IHtcbiAgICAgICAgICAgICAgICAvLyBhY3Rpb25TdWJEYXRhIG11c3QgYmUgb2YgZm9ybSAncGxheWJvb2s6MidcbiAgICAgICAgICAgICAgICByZXR1cm4gQm9vbGVhbigvXlthLXpdKzpcXGQkLy5leGVjKGFjdGlvblN1YkRhdGEgPz8gXCJcIikpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gT3RoZXIgYWN0aW9ucyBkbyBub3QgbmVlZCBzdWJEYXRhIHZhbGlkYXRpb24gYW5kIGNhbiBhbHdheXMgcHJvY2VlZDpcbiAgICAgICAgICAgIGRlZmF1bHQ6IHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuICAgIGFzeW5jIF9vbkRvd250aW1lQWN0aW9uQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICAvLyBFeHRyYWN0IHRoZSBkb3dudGltZUFjdGlvbiAtLSB0aGUgc3Vic3RyaW5nIG9mIGVsZW0kLmRhdGEoXCJhY3Rpb25cIikgZm9sbG93aW5nIHRoZSBsYXN0IGh5cGhlbiAoLSlcbiAgICAgICAgY29uc3QgZG93bnRpbWVBY3Rpb24gPSBlbGVtJC5kYXRhKFwiYWN0aW9uXCIpLnN1YnN0cmluZyhlbGVtJC5kYXRhKFwiYWN0aW9uXCIpLmxhc3RJbmRleE9mKFwiLVwiKSArIDEpO1xuICAgICAgICAvLyBFeHRyYWN0IHRoZSBzdWJEYXRhIGF0dHJpYnV0ZVxuICAgICAgICBjb25zdCBhY3Rpb25TdWJEYXRhID0gZWxlbSQuZGF0YShcImFjdGlvblN1YkRhdGFcIik7XG4gICAgICAgIC8vIFZhbGlkYXRlIHN1YkRhdGE6IElmIGludmFsaWQsIHN1YkRhdGEgYnV0dG9ucyB3aWxsIGJlIHJldmVhbGVkIC0tIHJldHVybiBhbmQgd2FpdCBmb3Igb25lIHRvIGJlIGNsaWNrZWQuXG4gICAgICAgIGlmICghKGF3YWl0IHRoaXMuX3ZhbGlkYXRlT3JSZXZlYWxTdWJEYXRhKGRvd250aW1lQWN0aW9uLCBhY3Rpb25TdWJEYXRhKSkpIHtcbiAgICAgICAgICAgICQoXCIjZXVub3MtYmxhZGVzLXRvb2x0aXBzXCIpLmNoaWxkcmVuKFwiLnRvb2x0aXBcIikucmVtb3ZlKCk7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLnVwZGF0ZSh7IFwic3lzdGVtLmRvd250aW1lX2FjdGlvbnNfb3Blbl9zdWJtZW51XCI6IGRvd250aW1lQWN0aW9uIH0pO1xuICAgICAgICAgICAgJChcIiNldW5vcy1ibGFkZXMtdG9vbHRpcHNcIikuY2hpbGRyZW4oXCIudG9vbHRpcFwiKS5yZW1vdmUoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBjb25maWcgPSB7XG4gICAgICAgICAgICB0YXJnZXQ6IHRoaXMuYWN0b3IsXG4gICAgICAgICAgICB0YXJnZXRGbGFnS2V5OiBcInJvbGxDb2xsYWJcIixcbiAgICAgICAgICAgIHJvbGxEb3dudGltZUFjdGlvbjogZG93bnRpbWVBY3Rpb25cbiAgICAgICAgfTtcbiAgICAgICAgLy8gU2V0IG5lY2Vzc2FyeSBmaWVsZHMgb24gcm9sbCBjb25zdHJ1Y3Rpb24gY29uZmlnIG9iamVjdCwgZGVwZW5kaW5nIG9uIGRvd250aW1lIGFjdGlvblxuICAgICAgICBzd2l0Y2ggKGRvd250aW1lQWN0aW9uKSB7XG4gICAgICAgICAgICBjYXNlIERvd250aW1lQWN0aW9uLkFjcXVpcmVBc3NldDpcbiAgICAgICAgICAgIGNhc2UgRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0OlxuICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5SZWR1Y2VIZWF0OiB7XG4gICAgICAgICAgICAgICAgY29uZmlnLnJvbGxUeXBlID0gUm9sbFR5cGUuQWN0aW9uO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5SZWNvdmVyOiB7XG4gICAgICAgICAgICAgICAgY29uZmlnLnJvbGxUeXBlID0gUm9sbFR5cGUuQWN0aW9uO1xuICAgICAgICAgICAgICAgIGlmIChCbGFkZXNQQy5Jc1R5cGUodGhpcy5hY3RvcikgJiYgdGhpcy5hY3Rvci5oZWFsaW5nQ2xvY2spIHtcbiAgICAgICAgICAgICAgICAgICAgY29uZmlnLnJvbGxDbG9ja0tleSA9IHRoaXMuYWN0b3IuaGVhbGluZ0Nsb2NrLmlkO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyByb2xsT3Bwb3NpdGlvbiA9IHVzZXIgY2hhcmFjdGVyJ3MgaGVhbGluZyBjbG9ja1xuICAgICAgICAgICAgICAgIC8vIHJvbGxQcmltYXJ5ID0gdGhpcy5hY3RvciBpcyBOUEM/XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIERvd250aW1lQWN0aW9uLkluZHVsZ2VWaWNlOiB7XG4gICAgICAgICAgICAgICAgY29uZmlnLnJvbGxUeXBlID0gUm9sbFR5cGUuSW5kdWxnZVZpY2U7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIERvd250aW1lQWN0aW9uLlRyYWluOiB7XG4gICAgICAgICAgICAgICAgY29uc3QgW2F0dHIsIHZhbHVlXSA9IGFjdGlvblN1YkRhdGEuc3BsaXQoLzovKTtcbiAgICAgICAgICAgICAgICBpZiAoYXR0ciA9PT0gXCJwbGF5Ym9va1wiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuYWN0b3IudXBkYXRlKHsgW2BzeXN0ZW0uZXhwZXJpZW5jZS4ke2F0dHJ9LnZhbHVlYF06IFUucEludCgodGhpcy5hY3Rvci5zeXN0ZW0uZXhwZXJpZW5jZT8ucGxheWJvb2s/LnZhbHVlID8/IDApKSArIFUucEludCh2YWx1ZSkgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKEJsYWRlc1BDLklzVHlwZSh0aGlzLmFjdG9yKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmFjdG9yLnVwZGF0ZSh7IFtgc3lzdGVtLmV4cGVyaWVuY2UuJHthdHRyfS52YWx1ZWBdOiBVLnBJbnQodGhpcy5hY3Rvci5zeXN0ZW0uZXhwZXJpZW5jZVthdHRyXS52YWx1ZSkgKyBVLnBJbnQodmFsdWUpIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBJbmNyZWFzZSB0cmFjayBYUDogSWYgYWJvdmUgbWF4LCBzZXQgcm9sbG92ZXIgdmFsdWVcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRlZmF1bHQ6IHtcbiAgICAgICAgICAgICAgICAvLyBUaGlzIGlzIGZvciBjdXN0b20gZG93bnRpbWUgYWN0aW9ucyBhZGRlZCBieSwgZS5nLiwgQWN0aXZlRWZmZWN0cy5cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICAvLyBDbGVhciBhbnkgb3BlbiBzdWJtZW51cywgYW5kIGFkZCBvbmUgdG8gZG93bnRpbWUgYWN0aW9ucyB1c2VkLlxuICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLnVwZGF0ZSh7XG4gICAgICAgICAgICBcInN5c3RlbS5kb3dudGltZV9hY3Rpb25zX29wZW5fc3VibWVudVwiOiBcIlwiLFxuICAgICAgICAgICAgXCJzeXN0ZW0uZG93bnRpbWVfYWN0aW9ucy52YWx1ZVwiOiAodGhpcy5hY3Rvci5zeXN0ZW0uZG93bnRpbWVfYWN0aW9ucz8udmFsdWUgPz8gMCkgKyAxXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoXCJyb2xsVHlwZVwiIGluIGNvbmZpZykge1xuICAgICAgICAgICAgaWYgKGRvd250aW1lQWN0aW9uID09PSBEb3dudGltZUFjdGlvbi5JbmR1bGdlVmljZSkge1xuICAgICAgICAgICAgICAgIEJsYWRlc0luZHVsZ2VWaWNlUm9sbC5OZXcoY29uZmlnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgIEJsYWRlc0FjdGlvblJvbGwuTmV3KGNvbmZpZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgX29uR2F0aGVySW5mb0NsaWNrKGV2ZW50KSB7XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgaWYgKGVsZW0kLmRhdGEoXCJpc0ZvcnR1bmVSb2xsXCIpKSB7XG4gICAgICAgICAgICBCbGFkZXNGb3J0dW5lUm9sbC5OZXcoe1xuICAgICAgICAgICAgICAgIHRhcmdldDogdGhpcy5hY3RvcixcbiAgICAgICAgICAgICAgICB0YXJnZXRGbGFnS2V5OiBcInJvbGxDb2xsYWJcIixcbiAgICAgICAgICAgICAgICByb2xsVHlwZTogUm9sbFR5cGUuRm9ydHVuZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBCbGFkZXNBY3Rpb25Sb2xsLk5ldyh7XG4gICAgICAgICAgICAgICAgdGFyZ2V0OiB0aGlzLmFjdG9yLFxuICAgICAgICAgICAgICAgIHRhcmdldEZsYWdLZXk6IFwicm9sbENvbGxhYlwiLFxuICAgICAgICAgICAgICAgIHJvbGxUeXBlOiBSb2xsVHlwZS5BY3Rpb24sXG4gICAgICAgICAgICAgICAgcm9sbFRyYWl0OiBcIlwiXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyAjZW5kcmVnaW9uXG4gICAgLy8gI3JlZ2lvbiBBY3RpdmUgRWZmZWN0IEhhbmRsZXJzXG4gICAgX29uQWN0aXZlRWZmZWN0Q29udHJvbENsaWNrKGV2ZW50KSB7XG4gICAgICAgIEJsYWRlc0FjdGl2ZUVmZmVjdC5vbk1hbmFnZUFjdGl2ZUVmZmVjdChldmVudCwgdGhpcy5hY3Rvcik7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQWN0b3JTaGVldDtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/sheets/actor/BladesActorSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/actor/BladesCrewSheet.ts": +/*!********************************************!*\ + !*** ./ts/sheets/actor/BladesCrewSheet.ts ***! + \********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesActorSheet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BladesActorSheet */ \"./ts/sheets/actor/BladesActorSheet.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n\n\nclass BladesCrewSheet extends _BladesActorSheet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"actor\", \"crew\"],\n template: \"systems/eunos-blades/templates/crew-sheet.hbs\",\n width: 940,\n height: 820,\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"claims\" }]\n });\n }\n getData() {\n const context = super.getData();\n eLog.checkLog(\"actor\", \"[BladesCrewSheet] super.getData()\", { ...context });\n const { activeSubItems } = this.actor;\n const sheetData = {};\n // ~ Assemble embedded actors and items\n sheetData.preparedItems = Object.assign(context.preparedItems ?? {}, {\n abilities: activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_ability),\n playbook: this.actor.playbook,\n reputation: activeSubItems\n .find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_reputation),\n upgrades: activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.crew_upgrade),\n preferredOp: activeSubItems\n .find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesItemType.preferred_op)\n });\n sheetData.preparedActors = {\n members: this.actor.members,\n contacts: this.actor.contacts\n };\n sheetData.tierData = {\n label: \"Tier\",\n dotline: {\n data: this.actor.system.tier,\n target: \"system.tier.value\",\n iconEmpty: \"dot-empty.svg\",\n iconEmptyHover: \"dot-empty-hover.svg\",\n iconFull: \"dot-full.svg\",\n iconFullHover: \"dot-full-hover.svg\"\n }\n };\n sheetData.upgradeData = {\n dotline: {\n dotlineClass: \"dotline-right\",\n data: {\n value: this.actor.availableUpgradePoints,\n max: this.actor.availableUpgradePoints\n },\n dotlineLabel: \"Available Upgrade Points\",\n isLocked: true,\n iconFull: \"dot-full.svg\"\n }\n };\n sheetData.abilityData = {\n dotline: {\n dotlineClass: \"dotline-right\",\n data: {\n value: this.actor.availableAbilityPoints,\n max: this.actor.availableAbilityPoints\n },\n dotlineLabel: \"Available Ability Points\",\n isLocked: true,\n iconFull: \"dot-full.svg\"\n }\n };\n sheetData.cohortData = {\n dotline: {\n dotlineClass: \"dotline-right\",\n data: {\n value: this.actor.availableCohortPoints,\n max: this.actor.availableCohortPoints\n },\n dotlineLabel: \"Available Cohort Points\",\n isLocked: true,\n iconFull: \"dot-full.svg\"\n }\n };\n sheetData.repData = {\n label: \"Rep\",\n dotlines: [\n {\n data: {\n value: Math.min(this.actor.system.rep.value, this.actor.system.rep.max - this.actor.turfCount),\n max: this.actor.system.rep.max - this.actor.turfCount\n },\n target: \"system.rep.value\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|half|frame\",\n svgEmpty: \"full|half|frame\"\n },\n {\n data: {\n value: this.actor.turfCount,\n max: this.actor.turfCount\n },\n target: \"none\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|half|frame\",\n svgEmpty: \"full|half|frame\",\n dotlineClass: \"flex-row-reverse\",\n isLocked: true\n }\n ]\n };\n sheetData.heatData = {\n label: \"Heat\",\n dotline: {\n data: this.actor.system.heat,\n target: \"system.heat.value\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|half|frame\",\n svgEmpty: \"full|half|frame\"\n }\n };\n sheetData.wantedData = {\n label: \"Wanted\",\n dotline: {\n data: this.actor.system.wanted,\n target: \"system.wanted.value\",\n svgKey: \"teeth.short\",\n svgFull: \"full|frame\",\n svgEmpty: \"frame\"\n }\n };\n eLog.checkLog(\"actor\", \"[BladesCrewSheet] return getData()\", { ...context, ...sheetData });\n return { ...context, ...sheetData };\n }\n activateListeners(html) {\n super.activateListeners(html);\n // Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n // Update Inventory Item\n html.find(\".item-sheet-open\").on(\"click\", (event) => {\n const element = $(event.currentTarget).parents(\".item\");\n const item = this.actor.items.get(element.data(\"itemId\"));\n item?.sheet?.render(true);\n });\n // Toggle Hold\n html.find(\".hold-toggle\").on(\"click\", () => {\n this.actor.update({ \"system.hold\": this.actor.system.hold === \"weak\" ? \"strong\" : \"weak\" });\n });\n // Toggle Turf\n html.find(\".turf-select\").on(\"click\", async (event) => {\n const turf_id = $(event.currentTarget).data(\"turfId\");\n const turf_current_status = $(event.currentTarget).data(\"turfStatus\");\n this.actor.playbook?.update({ [`system.turfs.${turf_id}.value`]: !turf_current_status })\n .then(() => this.render(false));\n });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesCrewSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvYWN0b3IvQmxhZGVzQ3Jld1NoZWV0LnRzIiwibWFwcGluZ3MiOiI7OztBQUFrRDtBQUNJO0FBQ3RELDhCQUE4Qix5REFBZ0I7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLDhFQUE4RTtBQUNuRyxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0Esc0VBQXNFLFlBQVk7QUFDbEYsZ0JBQWdCLGlCQUFpQjtBQUNqQztBQUNBO0FBQ0EsMkVBQTJFO0FBQzNFO0FBQ0EsZ0RBQWdELDJEQUFjO0FBQzlEO0FBQ0E7QUFDQSw4Q0FBOEMsMkRBQWM7QUFDNUQ7QUFDQSxnREFBZ0QsMkRBQWM7QUFDOUQ7QUFDQSw4Q0FBOEMsMkRBQWM7QUFDNUQsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUUsMEJBQTBCO0FBQ2pHLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLGdDQUFnQyxzRUFBc0U7QUFDdEcsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMENBQTBDLGlCQUFpQixRQUFRLGdDQUFnQztBQUNuRztBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsK0RBQWUsZUFBZSxFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvc2hlZXRzL2FjdG9yL0JsYWRlc0NyZXdTaGVldC50cz85MWViIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBCbGFkZXNBY3RvclNoZWV0IGZyb20gXCIuL0JsYWRlc0FjdG9yU2hlZXRcIjtcbmltcG9ydCB7IEJsYWRlc0l0ZW1UeXBlIH0gZnJvbSBcIi4uLy4uL2NvcmUvY29uc3RhbnRzXCI7XG5jbGFzcyBCbGFkZXNDcmV3U2hlZXQgZXh0ZW5kcyBCbGFkZXNBY3RvclNoZWV0IHtcbiAgICBzdGF0aWMgZ2V0IGRlZmF1bHRPcHRpb25zKCkge1xuICAgICAgICByZXR1cm4gZm91bmRyeS51dGlscy5tZXJnZU9iamVjdChzdXBlci5kZWZhdWx0T3B0aW9ucywge1xuICAgICAgICAgICAgY2xhc3NlczogW1wiZXVub3MtYmxhZGVzXCIsIFwic2hlZXRcIiwgXCJhY3RvclwiLCBcImNyZXdcIl0sXG4gICAgICAgICAgICB0ZW1wbGF0ZTogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvY3Jldy1zaGVldC5oYnNcIixcbiAgICAgICAgICAgIHdpZHRoOiA5NDAsXG4gICAgICAgICAgICBoZWlnaHQ6IDgyMCxcbiAgICAgICAgICAgIHRhYnM6IFt7IG5hdlNlbGVjdG9yOiBcIi5uYXYtdGFic1wiLCBjb250ZW50U2VsZWN0b3I6IFwiLnRhYi1jb250ZW50XCIsIGluaXRpYWw6IFwiY2xhaW1zXCIgfV1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGdldERhdGEoKSB7XG4gICAgICAgIGNvbnN0IGNvbnRleHQgPSBzdXBlci5nZXREYXRhKCk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RvclwiLCBcIltCbGFkZXNDcmV3U2hlZXRdIHN1cGVyLmdldERhdGEoKVwiLCB7IC4uLmNvbnRleHQgfSk7XG4gICAgICAgIGNvbnN0IHsgYWN0aXZlU3ViSXRlbXMgfSA9IHRoaXMuYWN0b3I7XG4gICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAvLyB+IEFzc2VtYmxlIGVtYmVkZGVkIGFjdG9ycyBhbmQgaXRlbXNcbiAgICAgICAgc2hlZXREYXRhLnByZXBhcmVkSXRlbXMgPSBPYmplY3QuYXNzaWduKGNvbnRleHQucHJlcGFyZWRJdGVtcyA/PyB7fSwge1xuICAgICAgICAgICAgYWJpbGl0aWVzOiBhY3RpdmVTdWJJdGVtc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gQmxhZGVzSXRlbVR5cGUuY3Jld19hYmlsaXR5KSxcbiAgICAgICAgICAgIHBsYXlib29rOiB0aGlzLmFjdG9yLnBsYXlib29rLFxuICAgICAgICAgICAgcmVwdXRhdGlvbjogYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgICAgICAuZmluZCgoaXRlbSkgPT4gaXRlbS50eXBlID09PSBCbGFkZXNJdGVtVHlwZS5jcmV3X3JlcHV0YXRpb24pLFxuICAgICAgICAgICAgdXBncmFkZXM6IGFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoaXRlbSkgPT4gaXRlbS50eXBlID09PSBCbGFkZXNJdGVtVHlwZS5jcmV3X3VwZ3JhZGUpLFxuICAgICAgICAgICAgcHJlZmVycmVkT3A6IGFjdGl2ZVN1Ykl0ZW1zXG4gICAgICAgICAgICAgICAgLmZpbmQoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gQmxhZGVzSXRlbVR5cGUucHJlZmVycmVkX29wKVxuICAgICAgICB9KTtcbiAgICAgICAgc2hlZXREYXRhLnByZXBhcmVkQWN0b3JzID0ge1xuICAgICAgICAgICAgbWVtYmVyczogdGhpcy5hY3Rvci5tZW1iZXJzLFxuICAgICAgICAgICAgY29udGFjdHM6IHRoaXMuYWN0b3IuY29udGFjdHNcbiAgICAgICAgfTtcbiAgICAgICAgc2hlZXREYXRhLnRpZXJEYXRhID0ge1xuICAgICAgICAgICAgbGFiZWw6IFwiVGllclwiLFxuICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgIGRhdGE6IHRoaXMuYWN0b3Iuc3lzdGVtLnRpZXIsXG4gICAgICAgICAgICAgICAgdGFyZ2V0OiBcInN5c3RlbS50aWVyLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgaWNvbkVtcHR5OiBcImRvdC1lbXB0eS5zdmdcIixcbiAgICAgICAgICAgICAgICBpY29uRW1wdHlIb3ZlcjogXCJkb3QtZW1wdHktaG92ZXIuc3ZnXCIsXG4gICAgICAgICAgICAgICAgaWNvbkZ1bGw6IFwiZG90LWZ1bGwuc3ZnXCIsXG4gICAgICAgICAgICAgICAgaWNvbkZ1bGxIb3ZlcjogXCJkb3QtZnVsbC1ob3Zlci5zdmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBzaGVldERhdGEudXBncmFkZURhdGEgPSB7XG4gICAgICAgICAgICBkb3RsaW5lOiB7XG4gICAgICAgICAgICAgICAgZG90bGluZUNsYXNzOiBcImRvdGxpbmUtcmlnaHRcIixcbiAgICAgICAgICAgICAgICBkYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmFjdG9yLmF2YWlsYWJsZVVwZ3JhZGVQb2ludHMsXG4gICAgICAgICAgICAgICAgICAgIG1heDogdGhpcy5hY3Rvci5hdmFpbGFibGVVcGdyYWRlUG9pbnRzXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBkb3RsaW5lTGFiZWw6IFwiQXZhaWxhYmxlIFVwZ3JhZGUgUG9pbnRzXCIsXG4gICAgICAgICAgICAgICAgaXNMb2NrZWQ6IHRydWUsXG4gICAgICAgICAgICAgICAgaWNvbkZ1bGw6IFwiZG90LWZ1bGwuc3ZnXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgc2hlZXREYXRhLmFiaWxpdHlEYXRhID0ge1xuICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgIGRvdGxpbmVDbGFzczogXCJkb3RsaW5lLXJpZ2h0XCIsXG4gICAgICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rvci5hdmFpbGFibGVBYmlsaXR5UG9pbnRzLFxuICAgICAgICAgICAgICAgICAgICBtYXg6IHRoaXMuYWN0b3IuYXZhaWxhYmxlQWJpbGl0eVBvaW50c1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZG90bGluZUxhYmVsOiBcIkF2YWlsYWJsZSBBYmlsaXR5IFBvaW50c1wiLFxuICAgICAgICAgICAgICAgIGlzTG9ja2VkOiB0cnVlLFxuICAgICAgICAgICAgICAgIGljb25GdWxsOiBcImRvdC1mdWxsLnN2Z1wiXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHNoZWV0RGF0YS5jb2hvcnREYXRhID0ge1xuICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgIGRvdGxpbmVDbGFzczogXCJkb3RsaW5lLXJpZ2h0XCIsXG4gICAgICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rvci5hdmFpbGFibGVDb2hvcnRQb2ludHMsXG4gICAgICAgICAgICAgICAgICAgIG1heDogdGhpcy5hY3Rvci5hdmFpbGFibGVDb2hvcnRQb2ludHNcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGRvdGxpbmVMYWJlbDogXCJBdmFpbGFibGUgQ29ob3J0IFBvaW50c1wiLFxuICAgICAgICAgICAgICAgIGlzTG9ja2VkOiB0cnVlLFxuICAgICAgICAgICAgICAgIGljb25GdWxsOiBcImRvdC1mdWxsLnN2Z1wiXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIHNoZWV0RGF0YS5yZXBEYXRhID0ge1xuICAgICAgICAgICAgbGFiZWw6IFwiUmVwXCIsXG4gICAgICAgICAgICBkb3RsaW5lczogW1xuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IE1hdGgubWluKHRoaXMuYWN0b3Iuc3lzdGVtLnJlcC52YWx1ZSwgdGhpcy5hY3Rvci5zeXN0ZW0ucmVwLm1heCAtIHRoaXMuYWN0b3IudHVyZkNvdW50KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heDogdGhpcy5hY3Rvci5zeXN0ZW0ucmVwLm1heCAtIHRoaXMuYWN0b3IudHVyZkNvdW50XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHRhcmdldDogXCJzeXN0ZW0ucmVwLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0tleTogXCJ0ZWV0aC50YWxsXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0Z1bGw6IFwiZnVsbHxoYWxmfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0VtcHR5OiBcImZ1bGx8aGFsZnxmcmFtZVwiXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiB0aGlzLmFjdG9yLnR1cmZDb3VudCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1heDogdGhpcy5hY3Rvci50dXJmQ291bnRcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcIm5vbmVcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnS2V5OiBcInRlZXRoLnRhbGxcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnRnVsbDogXCJmdWxsfGhhbGZ8ZnJhbWVcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnRW1wdHk6IFwiZnVsbHxoYWxmfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIGRvdGxpbmVDbGFzczogXCJmbGV4LXJvdy1yZXZlcnNlXCIsXG4gICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiB0cnVlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgXVxuICAgICAgICB9O1xuICAgICAgICBzaGVldERhdGEuaGVhdERhdGEgPSB7XG4gICAgICAgICAgICBsYWJlbDogXCJIZWF0XCIsXG4gICAgICAgICAgICBkb3RsaW5lOiB7XG4gICAgICAgICAgICAgICAgZGF0YTogdGhpcy5hY3Rvci5zeXN0ZW0uaGVhdCxcbiAgICAgICAgICAgICAgICB0YXJnZXQ6IFwic3lzdGVtLmhlYXQudmFsdWVcIixcbiAgICAgICAgICAgICAgICBzdmdLZXk6IFwidGVldGgudGFsbFwiLFxuICAgICAgICAgICAgICAgIHN2Z0Z1bGw6IFwiZnVsbHxoYWxmfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgc3ZnRW1wdHk6IFwiZnVsbHxoYWxmfGZyYW1lXCJcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICAgICAgc2hlZXREYXRhLndhbnRlZERhdGEgPSB7XG4gICAgICAgICAgICBsYWJlbDogXCJXYW50ZWRcIixcbiAgICAgICAgICAgIGRvdGxpbmU6IHtcbiAgICAgICAgICAgICAgICBkYXRhOiB0aGlzLmFjdG9yLnN5c3RlbS53YW50ZWQsXG4gICAgICAgICAgICAgICAgdGFyZ2V0OiBcInN5c3RlbS53YW50ZWQudmFsdWVcIixcbiAgICAgICAgICAgICAgICBzdmdLZXk6IFwidGVldGguc2hvcnRcIixcbiAgICAgICAgICAgICAgICBzdmdGdWxsOiBcImZ1bGx8ZnJhbWVcIixcbiAgICAgICAgICAgICAgICBzdmdFbXB0eTogXCJmcmFtZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGVMb2cuY2hlY2tMb2coXCJhY3RvclwiLCBcIltCbGFkZXNDcmV3U2hlZXRdIHJldHVybiBnZXREYXRhKClcIiwgeyAuLi5jb250ZXh0LCAuLi5zaGVldERhdGEgfSk7XG4gICAgICAgIHJldHVybiB7IC4uLmNvbnRleHQsIC4uLnNoZWV0RGF0YSB9O1xuICAgIH1cbiAgICBhY3RpdmF0ZUxpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIHN1cGVyLmFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpO1xuICAgICAgICAvLyBFdmVyeXRoaW5nIGJlbG93IGhlcmUgaXMgb25seSBuZWVkZWQgaWYgdGhlIHNoZWV0IGlzIGVkaXRhYmxlXG4gICAgICAgIGlmICghdGhpcy5vcHRpb25zLmVkaXRhYmxlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gVXBkYXRlIEludmVudG9yeSBJdGVtXG4gICAgICAgIGh0bWwuZmluZChcIi5pdGVtLXNoZWV0LW9wZW5cIikub24oXCJjbGlja1wiLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW1lbnQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLnBhcmVudHMoXCIuaXRlbVwiKTtcbiAgICAgICAgICAgIGNvbnN0IGl0ZW0gPSB0aGlzLmFjdG9yLml0ZW1zLmdldChlbGVtZW50LmRhdGEoXCJpdGVtSWRcIikpO1xuICAgICAgICAgICAgaXRlbT8uc2hlZXQ/LnJlbmRlcih0cnVlKTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIFRvZ2dsZSBIb2xkXG4gICAgICAgIGh0bWwuZmluZChcIi5ob2xkLXRvZ2dsZVwiKS5vbihcImNsaWNrXCIsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuYWN0b3IudXBkYXRlKHsgXCJzeXN0ZW0uaG9sZFwiOiB0aGlzLmFjdG9yLnN5c3RlbS5ob2xkID09PSBcIndlYWtcIiA/IFwic3Ryb25nXCIgOiBcIndlYWtcIiB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIFRvZ2dsZSBUdXJmXG4gICAgICAgIGh0bWwuZmluZChcIi50dXJmLXNlbGVjdFwiKS5vbihcImNsaWNrXCIsIGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgdHVyZl9pZCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShcInR1cmZJZFwiKTtcbiAgICAgICAgICAgIGNvbnN0IHR1cmZfY3VycmVudF9zdGF0dXMgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJ0dXJmU3RhdHVzXCIpO1xuICAgICAgICAgICAgdGhpcy5hY3Rvci5wbGF5Ym9vaz8udXBkYXRlKHsgW2BzeXN0ZW0udHVyZnMuJHt0dXJmX2lkfS52YWx1ZWBdOiAhdHVyZl9jdXJyZW50X3N0YXR1cyB9KVxuICAgICAgICAgICAgICAgIC50aGVuKCgpID0+IHRoaXMucmVuZGVyKGZhbHNlKSk7XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0NyZXdTaGVldDtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/sheets/actor/BladesCrewSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/actor/BladesFactionSheet.ts": +/*!***********************************************!*\ + !*** ./ts/sheets/actor/BladesFactionSheet.ts ***! + \***********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _BladesActorSheet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./BladesActorSheet */ \"./ts/sheets/actor/BladesActorSheet.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n\n\n\nclass BladesFactionSheet extends _BladesActorSheet__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"actor\", \"faction\"],\n template: \"systems/eunos-blades/templates/faction-sheet.hbs\",\n width: 900,\n height: \"auto\",\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"overview\" }]\n });\n }\n getData() {\n const context = super.getData();\n if (!_BladesActor__WEBPACK_IMPORTED_MODULE_0__[\"default\"].IsType(this.actor, _core_constants__WEBPACK_IMPORTED_MODULE_2__.BladesActorType.faction)) {\n return context;\n }\n const sheetData = {\n tierData: {\n class: \"comp-tier comp-vertical comp-teeth\",\n label: \"Tier\",\n labelClass: \"filled-label full-width\",\n dotline: {\n data: this.actor.system.tier,\n target: \"system.tier.value\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|half|frame\",\n svgEmpty: \"full|half|frame\"\n }\n },\n clockKeys: this.actor.clocks\n };\n return {\n ...context,\n ...sheetData\n };\n }\n async _onClockAddClick(event) {\n event.preventDefault();\n this.actor.addClock();\n }\n async _onClockDeleteClick(event) {\n event.preventDefault();\n const clockID = $(event.currentTarget).data(\"clockId\");\n if (!clockID) {\n return;\n }\n this.actor.deleteClock(clockID);\n }\n activateListeners(html) {\n super.activateListeners(html);\n // Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n // Update Inventory Item\n html.find(\".item-body\").on(\"click\", (event) => {\n const element = $(event.currentTarget).parents(\".item\");\n const item = this.actor.items.get(element.data(\"itemId\"));\n item?.sheet?.render(true);\n });\n html\n .find(\".comp-control.comp-add-clock\")\n .on(\"click\", this._onClockAddClick.bind(this));\n html\n .find(\".comp-control.comp-delete-clock\")\n .on(\"click\", this._onClockDeleteClick.bind(this));\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesFactionSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvYWN0b3IvQmxhZGVzRmFjdGlvblNoZWV0LnRzIiwibWFwcGluZ3MiOiI7Ozs7QUFBNEM7QUFDTTtBQUNLO0FBQ3ZELGlDQUFpQyx5REFBZ0I7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLGdGQUFnRjtBQUNyRyxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0EsYUFBYSxvREFBVyxvQkFBb0IsNERBQWU7QUFDM0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUFlLGtCQUFrQixFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvc2hlZXRzL2FjdG9yL0JsYWRlc0ZhY3Rpb25TaGVldC50cz8zNDQwIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBCbGFkZXNBY3RvciBmcm9tIFwiLi4vLi4vQmxhZGVzQWN0b3JcIjtcbmltcG9ydCBCbGFkZXNBY3RvclNoZWV0IGZyb20gXCIuL0JsYWRlc0FjdG9yU2hlZXRcIjtcbmltcG9ydCB7IEJsYWRlc0FjdG9yVHlwZSB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuY2xhc3MgQmxhZGVzRmFjdGlvblNoZWV0IGV4dGVuZHMgQmxhZGVzQWN0b3JTaGVldCB7XG4gICAgc3RhdGljIGdldCBkZWZhdWx0T3B0aW9ucygpIHtcbiAgICAgICAgcmV0dXJuIGZvdW5kcnkudXRpbHMubWVyZ2VPYmplY3Qoc3VwZXIuZGVmYXVsdE9wdGlvbnMsIHtcbiAgICAgICAgICAgIGNsYXNzZXM6IFtcImV1bm9zLWJsYWRlc1wiLCBcInNoZWV0XCIsIFwiYWN0b3JcIiwgXCJmYWN0aW9uXCJdLFxuICAgICAgICAgICAgdGVtcGxhdGU6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2ZhY3Rpb24tc2hlZXQuaGJzXCIsXG4gICAgICAgICAgICB3aWR0aDogOTAwLFxuICAgICAgICAgICAgaGVpZ2h0OiBcImF1dG9cIixcbiAgICAgICAgICAgIHRhYnM6IFt7IG5hdlNlbGVjdG9yOiBcIi5uYXYtdGFic1wiLCBjb250ZW50U2VsZWN0b3I6IFwiLnRhYi1jb250ZW50XCIsIGluaXRpYWw6IFwib3ZlcnZpZXdcIiB9XVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0RGF0YSgpIHtcbiAgICAgICAgY29uc3QgY29udGV4dCA9IHN1cGVyLmdldERhdGEoKTtcbiAgICAgICAgaWYgKCFCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcy5hY3RvciwgQmxhZGVzQWN0b3JUeXBlLmZhY3Rpb24pKSB7XG4gICAgICAgICAgICByZXR1cm4gY29udGV4dDtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7XG4gICAgICAgICAgICB0aWVyRGF0YToge1xuICAgICAgICAgICAgICAgIGNsYXNzOiBcImNvbXAtdGllciBjb21wLXZlcnRpY2FsIGNvbXAtdGVldGhcIixcbiAgICAgICAgICAgICAgICBsYWJlbDogXCJUaWVyXCIsXG4gICAgICAgICAgICAgICAgbGFiZWxDbGFzczogXCJmaWxsZWQtbGFiZWwgZnVsbC13aWR0aFwiLFxuICAgICAgICAgICAgICAgIGRvdGxpbmU6IHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogdGhpcy5hY3Rvci5zeXN0ZW0udGllcixcbiAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcInN5c3RlbS50aWVyLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0tleTogXCJ0ZWV0aC50YWxsXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0Z1bGw6IFwiZnVsbHxoYWxmfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0VtcHR5OiBcImZ1bGx8aGFsZnxmcmFtZVwiXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGNsb2NrS2V5czogdGhpcy5hY3Rvci5jbG9ja3NcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgfTtcbiAgICB9XG4gICAgYXN5bmMgX29uQ2xvY2tBZGRDbGljayhldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLmFjdG9yLmFkZENsb2NrKCk7XG4gICAgfVxuICAgIGFzeW5jIF9vbkNsb2NrRGVsZXRlQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgY29uc3QgY2xvY2tJRCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShcImNsb2NrSWRcIik7XG4gICAgICAgIGlmICghY2xvY2tJRCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuYWN0b3IuZGVsZXRlQ2xvY2soY2xvY2tJRCk7XG4gICAgfVxuICAgIGFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpIHtcbiAgICAgICAgc3VwZXIuYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgIC8vIEV2ZXJ5dGhpbmcgYmVsb3cgaGVyZSBpcyBvbmx5IG5lZWRlZCBpZiB0aGUgc2hlZXQgaXMgZWRpdGFibGVcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZWRpdGFibGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBVcGRhdGUgSW52ZW50b3J5IEl0ZW1cbiAgICAgICAgaHRtbC5maW5kKFwiLml0ZW0tYm9keVwiKS5vbihcImNsaWNrXCIsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbWVudCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCkucGFyZW50cyhcIi5pdGVtXCIpO1xuICAgICAgICAgICAgY29uc3QgaXRlbSA9IHRoaXMuYWN0b3IuaXRlbXMuZ2V0KGVsZW1lbnQuZGF0YShcIml0ZW1JZFwiKSk7XG4gICAgICAgICAgICBpdGVtPy5zaGVldD8ucmVuZGVyKHRydWUpO1xuICAgICAgICB9KTtcbiAgICAgICAgaHRtbFxuICAgICAgICAgICAgLmZpbmQoXCIuY29tcC1jb250cm9sLmNvbXAtYWRkLWNsb2NrXCIpXG4gICAgICAgICAgICAub24oXCJjbGlja1wiLCB0aGlzLl9vbkNsb2NrQWRkQ2xpY2suYmluZCh0aGlzKSk7XG4gICAgICAgIGh0bWxcbiAgICAgICAgICAgIC5maW5kKFwiLmNvbXAtY29udHJvbC5jb21wLWRlbGV0ZS1jbG9ja1wiKVxuICAgICAgICAgICAgLm9uKFwiY2xpY2tcIiwgdGhpcy5fb25DbG9ja0RlbGV0ZUNsaWNrLmJpbmQodGhpcykpO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0ZhY3Rpb25TaGVldDtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/sheets/actor/BladesFactionSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/actor/BladesNPCSheet.ts": +/*!*******************************************!*\ + !*** ./ts/sheets/actor/BladesNPCSheet.ts ***! + \*******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _BladesActorSheet__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./BladesActorSheet */ \"./ts/sheets/actor/BladesActorSheet.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n\n\nclass BladesNPCSheet extends _BladesActorSheet__WEBPACK_IMPORTED_MODULE_0__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"actor\", \"npc\"],\n template: \"systems/eunos-blades/templates/npc-sheet.hbs\",\n width: 500,\n height: 400,\n // height: \"auto\",\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"description\" }]\n });\n }\n getData() {\n const context = super.getData();\n context.isSubActor = context.actor.isSubActor;\n context.parentActor = context.actor.parentActor;\n context.persona = context.actor.system.persona;\n context.random = context.actor.system.random;\n context.secret = context.actor.system.secret;\n const rStatus = {\n name: { size: 3, label: \"Name\" },\n gender: { size: \"half\", label: \"Gender\" },\n heritage: { size: \"third\", label: \"Heritage\" },\n background: { size: \"third\", label: \"Background\" },\n profession: { size: \"third\", label: \"Profession\" },\n appearance: { size: 2, label: \"Appearance\" },\n style: { size: 2, label: \"Style\" },\n quirk: { size: 4, label: \"Quirk\" },\n goal: { size: 2, label: \"Goal\" },\n method: { size: 2, label: \"Method\" },\n interests: { size: 4, label: \"Interests\" },\n trait: { size: \"half\", label: \"Trait\" },\n trait1: { size: \"half\", label: null },\n trait2: { size: \"half\", label: null },\n trait3: { size: \"half\", label: null }\n };\n for (const cat of [\"persona\", \"random\", \"secret\"]) {\n for (const [key] of Object.entries(context[cat])) {\n if (key in rStatus) {\n Object.assign(context[cat][key], rStatus[key]);\n }\n }\n }\n console.log({ persona: context.persona, random: context.random, secret: context.secret });\n return context;\n }\n activateListeners(html) {\n super.activateListeners(html);\n // Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n html.find(\".gm-alert-header\").on(\"click\", async (event) => {\n event.preventDefault();\n this.actor.clearParentActor();\n });\n // ~ Configure Tagify input elements\n // const inputElement = document.querySelector('input[name=\"system.harm.severe.one\"]');\n // if (inputElement instanceof HTMLInputElement) { new Tagify(inputElement, {}) } else { console.log(\"Not an HTMLInputElement\")}\n // ~ Enable Randomize Button for NPCs\n html.find(\"[data-action=\\\"randomize\\\"\").on(\"click\", () => {\n this.actor.updateRandomizers();\n });\n // ~ Enable status toggles for NPC subactors\n html.find(\".comp-status-toggle\")\n .on(\"click\", () => {\n const { tags } = this.actor;\n if (this.actor.system.status === 1) {\n _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].remove(tags, \"Friend\");\n tags.push(\"Rival\");\n this.actor.update({\n \"system.status\": -1,\n \"system.tags\": _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].unique(tags)\n });\n }\n else {\n _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].remove(tags, \"Rival\");\n tags.push(\"Friend\");\n this.actor.update({\n \"system.status\": 1,\n \"system.tags\": _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].unique(tags)\n });\n }\n })\n .on(\"contextmenu\", () => {\n this.actor.update({ \"system.status\": 0 });\n });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesNPCSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvYWN0b3IvQmxhZGVzTlBDU2hlZXQudHMiLCJtYXBwaW5ncyI6Ijs7O0FBQWtEO0FBQ2I7QUFDckMsNkJBQTZCLHlEQUFnQjtBQUM3QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQixtRkFBbUY7QUFDeEcsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQix3QkFBd0I7QUFDNUMsc0JBQXNCLCtCQUErQjtBQUNyRCx3QkFBd0Isa0NBQWtDO0FBQzFELDBCQUEwQixvQ0FBb0M7QUFDOUQsMEJBQTBCLG9DQUFvQztBQUM5RCwwQkFBMEIsOEJBQThCO0FBQ3hELHFCQUFxQix5QkFBeUI7QUFDOUMscUJBQXFCLHlCQUF5QjtBQUM5QyxvQkFBb0Isd0JBQXdCO0FBQzVDLHNCQUFzQiwwQkFBMEI7QUFDaEQseUJBQXlCLDZCQUE2QjtBQUN0RCxxQkFBcUIsOEJBQThCO0FBQ25ELHNCQUFzQiwyQkFBMkI7QUFDakQsc0JBQXNCLDJCQUEyQjtBQUNqRCxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQiwwRUFBMEU7QUFDaEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsMkRBQTJELDJCQUEyQixJQUFJLE9BQU87QUFDakc7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixPQUFPO0FBQzNCO0FBQ0EsZ0JBQWdCLHVEQUFDO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyx1REFBQztBQUNwQyxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLGdCQUFnQix1REFBQztBQUNqQjtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsdURBQUM7QUFDcEMsaUJBQWlCO0FBQ2pCO0FBQ0EsU0FBUztBQUNUO0FBQ0EsZ0NBQWdDLG9CQUFvQjtBQUNwRCxTQUFTO0FBQ1Q7QUFDQTtBQUNBLCtEQUFlLGNBQWMsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL3NoZWV0cy9hY3Rvci9CbGFkZXNOUENTaGVldC50cz9kMzlhIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBCbGFkZXNBY3RvclNoZWV0IGZyb20gXCIuL0JsYWRlc0FjdG9yU2hlZXRcIjtcbmltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuY2xhc3MgQmxhZGVzTlBDU2hlZXQgZXh0ZW5kcyBCbGFkZXNBY3RvclNoZWV0IHtcbiAgICBzdGF0aWMgZ2V0IGRlZmF1bHRPcHRpb25zKCkge1xuICAgICAgICByZXR1cm4gZm91bmRyeS51dGlscy5tZXJnZU9iamVjdChzdXBlci5kZWZhdWx0T3B0aW9ucywge1xuICAgICAgICAgICAgY2xhc3NlczogW1wiZXVub3MtYmxhZGVzXCIsIFwic2hlZXRcIiwgXCJhY3RvclwiLCBcIm5wY1wiXSxcbiAgICAgICAgICAgIHRlbXBsYXRlOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9ucGMtc2hlZXQuaGJzXCIsXG4gICAgICAgICAgICB3aWR0aDogNTAwLFxuICAgICAgICAgICAgaGVpZ2h0OiA0MDAsXG4gICAgICAgICAgICAvLyBoZWlnaHQ6IFwiYXV0b1wiLFxuICAgICAgICAgICAgdGFiczogW3sgbmF2U2VsZWN0b3I6IFwiLm5hdi10YWJzXCIsIGNvbnRlbnRTZWxlY3RvcjogXCIudGFiLWNvbnRlbnRcIiwgaW5pdGlhbDogXCJkZXNjcmlwdGlvblwiIH1dXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBnZXREYXRhKCkge1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gc3VwZXIuZ2V0RGF0YSgpO1xuICAgICAgICBjb250ZXh0LmlzU3ViQWN0b3IgPSBjb250ZXh0LmFjdG9yLmlzU3ViQWN0b3I7XG4gICAgICAgIGNvbnRleHQucGFyZW50QWN0b3IgPSBjb250ZXh0LmFjdG9yLnBhcmVudEFjdG9yO1xuICAgICAgICBjb250ZXh0LnBlcnNvbmEgPSBjb250ZXh0LmFjdG9yLnN5c3RlbS5wZXJzb25hO1xuICAgICAgICBjb250ZXh0LnJhbmRvbSA9IGNvbnRleHQuYWN0b3Iuc3lzdGVtLnJhbmRvbTtcbiAgICAgICAgY29udGV4dC5zZWNyZXQgPSBjb250ZXh0LmFjdG9yLnN5c3RlbS5zZWNyZXQ7XG4gICAgICAgIGNvbnN0IHJTdGF0dXMgPSB7XG4gICAgICAgICAgICBuYW1lOiB7IHNpemU6IDMsIGxhYmVsOiBcIk5hbWVcIiB9LFxuICAgICAgICAgICAgZ2VuZGVyOiB7IHNpemU6IFwiaGFsZlwiLCBsYWJlbDogXCJHZW5kZXJcIiB9LFxuICAgICAgICAgICAgaGVyaXRhZ2U6IHsgc2l6ZTogXCJ0aGlyZFwiLCBsYWJlbDogXCJIZXJpdGFnZVwiIH0sXG4gICAgICAgICAgICBiYWNrZ3JvdW5kOiB7IHNpemU6IFwidGhpcmRcIiwgbGFiZWw6IFwiQmFja2dyb3VuZFwiIH0sXG4gICAgICAgICAgICBwcm9mZXNzaW9uOiB7IHNpemU6IFwidGhpcmRcIiwgbGFiZWw6IFwiUHJvZmVzc2lvblwiIH0sXG4gICAgICAgICAgICBhcHBlYXJhbmNlOiB7IHNpemU6IDIsIGxhYmVsOiBcIkFwcGVhcmFuY2VcIiB9LFxuICAgICAgICAgICAgc3R5bGU6IHsgc2l6ZTogMiwgbGFiZWw6IFwiU3R5bGVcIiB9LFxuICAgICAgICAgICAgcXVpcms6IHsgc2l6ZTogNCwgbGFiZWw6IFwiUXVpcmtcIiB9LFxuICAgICAgICAgICAgZ29hbDogeyBzaXplOiAyLCBsYWJlbDogXCJHb2FsXCIgfSxcbiAgICAgICAgICAgIG1ldGhvZDogeyBzaXplOiAyLCBsYWJlbDogXCJNZXRob2RcIiB9LFxuICAgICAgICAgICAgaW50ZXJlc3RzOiB7IHNpemU6IDQsIGxhYmVsOiBcIkludGVyZXN0c1wiIH0sXG4gICAgICAgICAgICB0cmFpdDogeyBzaXplOiBcImhhbGZcIiwgbGFiZWw6IFwiVHJhaXRcIiB9LFxuICAgICAgICAgICAgdHJhaXQxOiB7IHNpemU6IFwiaGFsZlwiLCBsYWJlbDogbnVsbCB9LFxuICAgICAgICAgICAgdHJhaXQyOiB7IHNpemU6IFwiaGFsZlwiLCBsYWJlbDogbnVsbCB9LFxuICAgICAgICAgICAgdHJhaXQzOiB7IHNpemU6IFwiaGFsZlwiLCBsYWJlbDogbnVsbCB9XG4gICAgICAgIH07XG4gICAgICAgIGZvciAoY29uc3QgY2F0IG9mIFtcInBlcnNvbmFcIiwgXCJyYW5kb21cIiwgXCJzZWNyZXRcIl0pIHtcbiAgICAgICAgICAgIGZvciAoY29uc3QgW2tleV0gb2YgT2JqZWN0LmVudHJpZXMoY29udGV4dFtjYXRdKSkge1xuICAgICAgICAgICAgICAgIGlmIChrZXkgaW4gclN0YXR1cykge1xuICAgICAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKGNvbnRleHRbY2F0XVtrZXldLCByU3RhdHVzW2tleV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjb25zb2xlLmxvZyh7IHBlcnNvbmE6IGNvbnRleHQucGVyc29uYSwgcmFuZG9tOiBjb250ZXh0LnJhbmRvbSwgc2VjcmV0OiBjb250ZXh0LnNlY3JldCB9KTtcbiAgICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgfVxuICAgIGFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpIHtcbiAgICAgICAgc3VwZXIuYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgIC8vIEV2ZXJ5dGhpbmcgYmVsb3cgaGVyZSBpcyBvbmx5IG5lZWRlZCBpZiB0aGUgc2hlZXQgaXMgZWRpdGFibGVcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZWRpdGFibGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBodG1sLmZpbmQoXCIuZ20tYWxlcnQtaGVhZGVyXCIpLm9uKFwiY2xpY2tcIiwgYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgdGhpcy5hY3Rvci5jbGVhclBhcmVudEFjdG9yKCk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyB+IENvbmZpZ3VyZSBUYWdpZnkgaW5wdXQgZWxlbWVudHNcbiAgICAgICAgLy8gY29uc3QgaW5wdXRFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcignaW5wdXRbbmFtZT1cInN5c3RlbS5oYXJtLnNldmVyZS5vbmVcIl0nKTtcbiAgICAgICAgLy8gaWYgKGlucHV0RWxlbWVudCBpbnN0YW5jZW9mIEhUTUxJbnB1dEVsZW1lbnQpIHsgbmV3IFRhZ2lmeShpbnB1dEVsZW1lbnQsIHt9KSB9IGVsc2UgeyBjb25zb2xlLmxvZyhcIk5vdCBhbiBIVE1MSW5wdXRFbGVtZW50XCIpfVxuICAgICAgICAvLyB+IEVuYWJsZSBSYW5kb21pemUgQnV0dG9uIGZvciBOUENzXG4gICAgICAgIGh0bWwuZmluZChcIltkYXRhLWFjdGlvbj1cXFwicmFuZG9taXplXFxcIlwiKS5vbihcImNsaWNrXCIsICgpID0+IHtcbiAgICAgICAgICAgIHRoaXMuYWN0b3IudXBkYXRlUmFuZG9taXplcnMoKTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIH4gRW5hYmxlIHN0YXR1cyB0b2dnbGVzIGZvciBOUEMgc3ViYWN0b3JzXG4gICAgICAgIGh0bWwuZmluZChcIi5jb21wLXN0YXR1cy10b2dnbGVcIilcbiAgICAgICAgICAgIC5vbihcImNsaWNrXCIsICgpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHsgdGFncyB9ID0gdGhpcy5hY3RvcjtcbiAgICAgICAgICAgIGlmICh0aGlzLmFjdG9yLnN5c3RlbS5zdGF0dXMgPT09IDEpIHtcbiAgICAgICAgICAgICAgICBVLnJlbW92ZSh0YWdzLCBcIkZyaWVuZFwiKTtcbiAgICAgICAgICAgICAgICB0YWdzLnB1c2goXCJSaXZhbFwiKTtcbiAgICAgICAgICAgICAgICB0aGlzLmFjdG9yLnVwZGF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIFwic3lzdGVtLnN0YXR1c1wiOiAtMSxcbiAgICAgICAgICAgICAgICAgICAgXCJzeXN0ZW0udGFnc1wiOiBVLnVuaXF1ZSh0YWdzKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgVS5yZW1vdmUodGFncywgXCJSaXZhbFwiKTtcbiAgICAgICAgICAgICAgICB0YWdzLnB1c2goXCJGcmllbmRcIik7XG4gICAgICAgICAgICAgICAgdGhpcy5hY3Rvci51cGRhdGUoe1xuICAgICAgICAgICAgICAgICAgICBcInN5c3RlbS5zdGF0dXNcIjogMSxcbiAgICAgICAgICAgICAgICAgICAgXCJzeXN0ZW0udGFnc1wiOiBVLnVuaXF1ZSh0YWdzKVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAgICAgLm9uKFwiY29udGV4dG1lbnVcIiwgKCkgPT4ge1xuICAgICAgICAgICAgdGhpcy5hY3Rvci51cGRhdGUoeyBcInN5c3RlbS5zdGF0dXNcIjogMCB9KTtcbiAgICAgICAgfSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzTlBDU2hlZXQ7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/sheets/actor/BladesNPCSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/actor/BladesPCSheet.ts": +/*!******************************************!*\ + !*** ./ts/sheets/actor/BladesPCSheet.ts ***! + \******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesActorSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesActorSheet */ \"./ts/sheets/actor/BladesActorSheet.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\nclass BladesPCSheet extends _BladesActorSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"actor\", \"pc\"],\n template: \"systems/eunos-blades/templates/actor-sheet.hbs\",\n width: 775,\n height: 775,\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"abilities\" }]\n });\n }\n getData() {\n const context = super.getData();\n const { activeSubItems, activeSubActors } = this.actor;\n const sheetData = {};\n // ~ Assemble embedded actors and items\n sheetData.preparedItems = Object.assign(context.preparedItems ?? {}, {\n abilities: activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability)\n .map((item) => {\n // ~ Assign dotlines to abilities with usage data\n if (item.system.uses_per_score.max) {\n Object.assign(item, {\n inRuleDotline: {\n data: item.system.uses_per_score,\n dotlineLabel: \"Uses\",\n target: \"item.system.uses_per_score.value\",\n iconEmpty: \"dot-empty.svg\",\n iconEmptyHover: \"dot-empty-hover.svg\",\n iconFull: \"dot-full.svg\",\n iconFullHover: \"dot-full-hover.svg\"\n }\n });\n }\n return item;\n }),\n background: activeSubItems.find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.background),\n heritage: activeSubItems.find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.heritage),\n vice: activeSubItems.find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice),\n loadout: activeSubItems\n .filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)\n .map((item) => {\n // Assign load and usage data to gear\n if (item.system.load) {\n Object.assign(item, {\n numberCircle: item.system.load,\n numberCircleClass: \"item-load\"\n });\n }\n if (item.system.uses_per_score.max) {\n Object.assign(item, {\n inRuleDotline: {\n data: item.system.uses_per_score,\n dotlineLabel: \"Uses\",\n target: \"item.system.uses_per_score.value\",\n iconEmpty: \"dot-empty.svg\",\n iconEmptyHover: \"dot-empty-hover.svg\",\n iconFull: \"dot-full.svg\",\n iconFullHover: \"dot-full-hover.svg\"\n }\n });\n }\n return item;\n }),\n playbook: this.actor.playbook,\n projects: activeSubItems.filter((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.project),\n cohorts: context.preparedItems?.cohorts\n });\n sheetData.preparedActors = {\n crew: activeSubActors\n .find((actor) => actor.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.crew),\n vice_purveyor: activeSubActors\n .find((actor) => actor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.NPC.VicePurveyor)),\n acquaintances: activeSubActors\n .filter((actor) => actor.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.NPC.Acquaintance))\n };\n sheetData.hasVicePurveyor = Boolean(this.actor.playbook?.hasTag(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.Gear.Advanced) === false\n && activeSubItems.find((item) => item.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice));\n sheetData.healing_clock = this.actor.healingClock;\n sheetData.stashData = {\n label: \"Stash:\",\n dotline: {\n data: this.actor.system.stash,\n target: \"system.stash.value\",\n iconEmpty: \"coin-empty.svg\",\n iconEmptyHover: \"coin-empty-hover.svg\",\n iconFull: \"coin-full.svg\",\n iconFullHover: \"coin-full-hover.svg\",\n altIconFull: \"coin-ten.svg\",\n altIconFullHover: \"coin-ten-hover.svg\",\n altIconStep: 10\n }\n };\n sheetData.stressData = {\n label: this.actor.system.stress.name,\n dotline: {\n data: this.actor.system.stress,\n dotlineClass: this.actor.system.stress.max >= 13 ? \"narrow-stress\" : \"\",\n target: \"system.stress.value\",\n svgKey: \"teeth.tall\",\n svgFull: \"full|half|frame\",\n svgEmpty: \"full|half|frame\"\n }\n };\n if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.IsType(this.actor, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n sheetData.traumaData = {\n label: this.actor.system.trauma.name,\n dotline: {\n data: { value: this.actor.trauma, max: this.actor.system.trauma.max },\n svgKey: \"teeth.short\",\n svgFull: \"full|frame\",\n svgEmpty: \"frame\",\n isLocked: true\n },\n compContainer: {\n class: \"comp-trauma-conditions comp-vertical full-width\",\n blocks: [\n this.actor.traumaList.slice(0, Math.ceil(this.actor.traumaList.length / 2))\n .map((tName) => ({\n checkLabel: tName,\n checkClasses: {\n active: \"comp-toggle-red\",\n inactive: \"comp-toggle-grey\"\n },\n checkTarget: `system.trauma.checked.${tName}`,\n checkValue: this.actor.system.trauma.checked[tName] ?? false,\n tooltip: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].TraumaTooltips[tName],\n tooltipClass: \"tooltip-trauma\"\n })),\n this.actor.traumaList.slice(Math.ceil(this.actor.traumaList.length / 2))\n .map((tName) => ({\n checkLabel: tName,\n checkClasses: {\n active: \"comp-toggle-red\",\n inactive: \"comp-toggle-grey\"\n },\n checkTarget: `system.trauma.checked.${tName}`,\n checkValue: this.actor.system.trauma.checked[tName] ?? false,\n tooltip: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].TraumaTooltips[tName],\n tooltipClass: \"tooltip-trauma\"\n }))\n ]\n }\n };\n }\n sheetData.abilityData = {\n dotline: {\n dotlineClass: \"dotline-right dotline-glow\",\n data: {\n value: this.actor.getAvailableAdvancements(\"Ability\"),\n max: this.actor.getAvailableAdvancements(\"Ability\")\n },\n dotlineLabel: \"Available Abilities\",\n isLocked: true,\n iconFull: \"dot-full.svg\"\n }\n };\n sheetData.loadData = {\n curLoad: this.actor.currentLoad,\n selLoadCount: this.actor.system.loadout.levels[_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].lCase(this.actor.system.loadout.selected)],\n options: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].Loadout.selections,\n selected: this.actor.system.loadout.selected ?? \"\"\n };\n sheetData.armor = Object.fromEntries(Object.entries(this.actor.system.armor.active)\n .filter(([, isActive]) => isActive)\n .map(([armor]) => [\n armor,\n this.actor.system.armor.checked[armor]\n ]));\n sheetData.attributeData = {};\n const attrEntries = Object.entries(this.actor.system.attributes);\n for (const [attribute, attrData] of attrEntries) {\n sheetData.attributeData[attribute] = {\n tooltip: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].AttributeTooltips[attribute],\n actions: {}\n };\n const actionEntries = Object.entries(attrData);\n for (const [action, actionData] of actionEntries) {\n sheetData.attributeData[attribute].actions[action] = {\n tooltip: _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].ActionTooltips[action],\n value: actionData.value,\n max: game.eunoblades.Tracker.phase === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.CharGen\n ? 2\n : this.actor.system.attributes[attribute][action].max\n };\n }\n }\n if (game.eunoblades.Tracker?.phase === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Downtime) {\n const actionsList = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.AcquireAsset]: \"Acquire Asset\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.IndulgeVice]: \"Indulge Vice\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.LongTermProject]: \"Project\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Recover]: \"Recover\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.ReduceHeat]: \"Reduce Heat\",\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Train]: \"Train\"\n };\n // Get PCs, NPCs capable of rolling for the Recover action\n const healCapableDocs = [\n ..._documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.PC.CanHeal),\n ..._documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.npc, _core_constants__WEBPACK_IMPORTED_MODULE_0__.Tag.NPC.CanHeal)\n /* ALSO NEED TO INCLUDE EXPERT COHORTS WITH CANHEAL TAG */\n ];\n // delete any Actions that aren't applicable\n if (this.actor.stress === 0) {\n delete actionsList[_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.IndulgeVice];\n }\n if (this.actor.harmLevel === 0 || healCapableDocs.length === 0) {\n delete actionsList[_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Recover];\n }\n if (!this.actor.crew || this.actor.crew.system.heat.value === 0) {\n delete actionsList[_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.ReduceHeat];\n }\n let actionsSubmenuData = undefined;\n switch (this.actor.system.downtime_actions_open_submenu) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.LongTermProject: {\n actionsSubmenuData = [\n {\n actionSubData: \"NewProject\",\n display: \"New Project\"\n }\n ];\n // ... and add one for each Project on the PC.\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Recover: {\n actionsSubmenuData = [];\n healCapableDocs.forEach((hDoc) => {\n if (hDoc.id === this.actor.id) {\n actionsSubmenuData?.unshift({\n actionSubData: this.actor.id,\n display: \"Heal Self\"\n });\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesPC.IsType(hDoc)) {\n actionsSubmenuData?.push({\n actionSubData: hDoc.id,\n display: _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].uCase(hDoc.name)\n });\n }\n else if (_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesNPC.IsType(hDoc)) {\n actionsSubmenuData?.push({\n actionSubData: hDoc.id,\n display: hDoc.name\n });\n } /* NEED CHECK FOR COHORT HEALERS TOO */\n });\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Train: {\n const crewTrainingUpgrades = (this.actor.crew?.upgrades\n .filter((upgrade) => /^Training_/.exec(upgrade.system.world_name))\n .map((upgrade) => _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].lCase(upgrade.system.world_name.split(/_/)[1])) ?? []);\n actionsSubmenuData = [\n {\n actionSubData: `playbook:${crewTrainingUpgrades.includes(\"playbook\") ? 2 : 1}`,\n display: `${crewTrainingUpgrades.includes(\"playbook\") ? 2 : 1} Playbook XP`\n },\n {\n actionSubData: `insight:${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.insight) ? 2 : 1}`,\n display: `${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.insight) ? 2 : 1} Insight XP`\n },\n {\n actionSubData: `prowess:${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.prowess) ? 2 : 1}`,\n display: `${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.prowess) ? 2 : 1} Prowess XP`\n },\n {\n actionSubData: `resolve:${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.resolve) ? 2 : 1}`,\n display: `${crewTrainingUpgrades.includes(_core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait.resolve) ? 2 : 1} Resolve XP`\n }\n ];\n break;\n }\n }\n const actionsTooltips = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.AcquireAsset]: `

Acquire an Asset

\r\n

Roll your Tier to acquire temporary use of an asset or service.

\r\n

The Quality of the acquired asset depends on the result of your roll:

\r\n
    \r\n
  • Critical SuccessTier + 2
  • \r\n
  • SuccessTier + 2
  • \r\n
  • Partial SuccessTier
  • \r\n
  • FailTier − 1
  • \r\n
`,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.IndulgeVice]: `

Indulge Your Vice

\r\n

Roll your lowest Attribute. Clear Stress equal to the highest die result.

\r\n

Warning: If you clear more Stress than you have, you will overindulge.

`,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.LongTermProject]: `

Work on a Long-Term Project

\r\n

Work to advance the clock of one of your existing Long-Term Projects, or begin a new one.

\r\n

Roll the Action most appropriate to the work you are doing. The results of your roll determine how far you will advance the clock:

\r\n
    \r\n
  • Critical SuccessFive Segments
  • \r\n
  • SuccessThree Segments
  • \r\n
  • Partial SuccessTwo Segments
  • \r\n
  • FailOne Segment
  • \r\n
`,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Recover]: `

Recover from Harm

\r\n

Make a healing treatment roll using the appropriate trait of the character healing you:

\r\n
    \r\n
  • A PC with 'Physicker'Tinker. (You can heal yourself this way, but suffer 2 Stress for doing so.)
  • \r\n
  • An NPCQuality
  • \r\n
\r\n

The results of your roll determine how far you will Advance your healing clock:

\r\n
    \r\n
  • Critical SuccessFive Segments
  • \r\n
  • SuccessThree Segments
  • \r\n
  • Partial SuccessTwo Segments
  • \r\n
  • FailOne Segment
  • \r\n
\r\n

When your healing clock is filled, reduce each Harm by one level of severity.

`,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.ReduceHeat]: `

Reduce Heat

\r\n

Work to reduce the Heat on your Crew.

\r\n

Roll the Action most appropriate to the measures you are taking. The results of your roll determine how much Heat you clear:

\r\n
    \r\n
  • Critical SuccessFive Heat
  • \r\n
  • SuccessThree Heat
  • \r\n
  • Partial SuccessTwo Heat
  • \r\n
  • FailOne Heat
  • \r\n
`,\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.DowntimeAction.Train]: `

Train

\r\n

Select an Experience Track (i.e. Insight, Prowess, Resolve, or your Playbook). Gain 1 XP in that track, or 2 XP if your Crew has the corresponding Training Upgrade.

`\n };\n const actionsRemaining = this.actor.system.downtime_actions.max\n + this.actor.system.downtime_action_bonus\n - this.actor.system.downtime_actions.value\n - (this.actor.isAtWar ? 1 : 0);\n const canPayCoin = Boolean(this.actor.system.coins.value >= 1\n || this.actor.system.stash.value >= 2);\n const canPayRep = Boolean(this.actor.crew\n && this.actor.crew.system.rep.value >= 1);\n const isDisplayingCosts = actionsRemaining <= 0;\n const isDisplayingActions = actionsRemaining > 0\n || (canPayCoin && this.actor.system.downtime_action_selected_cost === \"Coin\")\n || (canPayRep && this.actor.system.downtime_action_selected_cost === \"Rep\");\n sheetData.downtimeData = {\n actionsList,\n actionsTooltips,\n actionsRemaining,\n actionsSubmenuData,\n canPayCoin,\n canPayRep,\n isDisplayingCosts,\n isDisplayingActions,\n dotline: {\n dotlineClass: \"dotline-right dotline-glow\",\n data: {\n value: actionsRemaining,\n max: actionsRemaining\n },\n dotlineLabel: \"Actions Remaining\",\n isLocked: true,\n iconFull: \"dot-full.svg\"\n }\n };\n }\n sheetData.gatherInfoTooltip = (new Handlebars.SafeString([\n \"

Gathering Information

\",\n \"

Questions to Consider

\",\n \"
    \",\n ...Object.values(this.actor.system.gather_info ?? []).map((line) => `
  • ${line}
  • `) ?? [],\n \"
\"\n ].join(\"\"))).toString();\n eLog.checkLog(\"Attribute\", \"[BladesPCSheet] attributeData\", { attributeData: sheetData.attributeData });\n eLog.checkLog(\"actor\", \"[BladesPCSheet] getData()\", { ...context, ...sheetData });\n return { ...context, ...sheetData };\n }\n get activeArmor() {\n return Object.keys(_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objFilter(this.actor.system.armor.active, (val) => val === true));\n }\n get checkedArmor() {\n return Object.keys(_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objFilter(this.actor.system.armor.checked, (val, key) => val === true\n && this.actor.system.armor.active[key] === true));\n }\n get uncheckedArmor() {\n return Object.keys(_core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].objFilter(this.actor.system.armor.active, (val, key) => val === true\n && this.actor.system.armor.checked[key] === false));\n }\n _getHoverArmor() {\n if (!this.activeArmor.length) {\n return false;\n }\n if (this.activeArmor.includes(\"heavy\")) {\n return this.checkedArmor.includes(\"heavy\") ? \"light\" : \"heavy\";\n }\n else if (this.activeArmor.includes(\"light\")) {\n return \"light\";\n }\n return \"special\";\n }\n _getClickArmor() {\n if (!this.uncheckedArmor.length) {\n return false;\n }\n if (this.uncheckedArmor.includes(\"heavy\")) {\n return \"heavy\";\n }\n if (this.uncheckedArmor.includes(\"light\")) {\n return \"light\";\n }\n return \"special\";\n }\n _getContextMenuArmor() {\n if (!this.checkedArmor.length) {\n return false;\n }\n if (this.checkedArmor.includes(\"light\")) {\n return \"light\";\n }\n if (this.checkedArmor.includes(\"heavy\")) {\n return \"heavy\";\n }\n return \"special\";\n }\n async _onAdvanceClick(event) {\n event.preventDefault();\n super._onAdvanceClick(event);\n const action = $(event.currentTarget).data(\"action\").replace(/^advance-/, \"\");\n if (action in _core_constants__WEBPACK_IMPORTED_MODULE_0__.AttributeTrait) {\n await this.actor.advanceAttribute(action);\n }\n }\n activateListeners(html) {\n super.activateListeners(html);\n // ~ Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n const self = this;\n // ~ Armor Control\n html.find(\".main-armor-control\").on({\n click() {\n const targetArmor = self._getClickArmor();\n if (!targetArmor) {\n return;\n }\n self.actor.update({ [`system.armor.checked.${targetArmor}`]: true });\n },\n contextmenu() {\n const targetArmor = self._getContextMenuArmor();\n if (!targetArmor) {\n return;\n }\n self.actor.update({ [`system.armor.checked.${targetArmor}`]: false });\n },\n mouseenter() {\n const targetArmor = self._getHoverArmor();\n eLog.log4(\"Mouse Enter\", targetArmor, this, $(this), $(this).next());\n if (!targetArmor) {\n return;\n }\n $(this).siblings(`.svg-armor.armor-${targetArmor}`).addClass(\"hover-over\");\n },\n mouseleave() {\n const targetArmor = self._getHoverArmor();\n if (!targetArmor) {\n return;\n }\n $(this).siblings(`.svg-armor.armor-${targetArmor}`).removeClass(\"hover-over\");\n }\n });\n html.find(\".special-control\").on({\n click() {\n if (!self.activeArmor.includes(\"special\")) {\n return;\n }\n self.actor.update({ \"system.armor.checked.special\": self.uncheckedArmor.includes(\"special\") });\n },\n contextmenu() {\n if (!self.activeArmor.includes(\"special\")) {\n return;\n }\n self.actor.update({ \"system.armor.checked.special\": self.uncheckedArmor.includes(\"special\") });\n },\n mouseenter() {\n if (!self.activeArmor.includes(\"special\") || self.activeArmor.length === 1) {\n return;\n }\n $(this).siblings(\".svg-armor.armor-special\").addClass(\"hover-over\");\n },\n mouseleave() {\n if (!self.activeArmor.includes(\"special\") || self.activeArmor.length === 1) {\n return;\n }\n $(this).siblings(\".svg-armor.armor-special\").removeClass(\"hover-over\");\n }\n });\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesPCSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvYWN0b3IvQmxhZGVzUENTaGVldC50cyIsIm1hcHBpbmdzIjoiOzs7OztBQUFBO0FBQzRIO0FBQ3ZGO0FBQ2E7QUFDa0M7QUFDcEYsNEJBQTRCLHlEQUFnQjtBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsaUZBQWlGO0FBQ3RHLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0Isa0NBQWtDO0FBQ2xEO0FBQ0E7QUFDQSwyRUFBMkU7QUFDM0U7QUFDQSxnREFBZ0QsMkRBQWM7QUFDOUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBLGFBQWE7QUFDYixvRUFBb0UsMkRBQWM7QUFDbEYsa0VBQWtFLDJEQUFjO0FBQ2hGLDhEQUE4RCwyREFBYztBQUM1RTtBQUNBLGdEQUFnRCwyREFBYztBQUM5RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUI7QUFDckI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQSxvRUFBb0UsMkRBQWM7QUFDbEY7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLGdEQUFnRCw0REFBZTtBQUMvRDtBQUNBLDhDQUE4QyxnREFBRztBQUNqRDtBQUNBLGdEQUFnRCxnREFBRztBQUNuRDtBQUNBLHdFQUF3RSxnREFBRztBQUMzRSwyREFBMkQsMkRBQWM7QUFDekU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksb0VBQVcsb0JBQW9CLDREQUFlO0FBQzFEO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qiw2REFBNkQ7QUFDekY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCLGtFQUFrRSxNQUFNO0FBQ3hFO0FBQ0EscUNBQXFDLHVEQUFDO0FBQ3RDO0FBQ0EseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QjtBQUM3QixrRUFBa0UsTUFBTTtBQUN4RTtBQUNBLHFDQUFxQyx1REFBQztBQUN0QztBQUNBLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJEQUEyRCx1REFBQztBQUM1RCxxQkFBcUIsdURBQUM7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLHVEQUFDO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkIsdURBQUM7QUFDOUI7QUFDQSwyREFBMkQsd0RBQVc7QUFDdEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQyx3REFBVztBQUMxRDtBQUNBLGlCQUFpQiwyREFBYztBQUMvQixpQkFBaUIsMkRBQWM7QUFDL0IsaUJBQWlCLDJEQUFjO0FBQy9CLGlCQUFpQiwyREFBYztBQUMvQixpQkFBaUIsMkRBQWM7QUFDL0IsaUJBQWlCLDJEQUFjO0FBQy9CO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixvRUFBVyxpQkFBaUIsNERBQWUsS0FBSyxnREFBRztBQUN0RSxtQkFBbUIsb0VBQVcsaUJBQWlCLDREQUFlLE1BQU0sZ0RBQUc7QUFDdkU7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsMkRBQWM7QUFDakQ7QUFDQTtBQUNBLG1DQUFtQywyREFBYztBQUNqRDtBQUNBO0FBQ0EsbUNBQW1DLDJEQUFjO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQiwyREFBYztBQUNuQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsMkRBQWM7QUFDbkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0EsaUNBQWlDLGlFQUFRO0FBQ3pDO0FBQ0E7QUFDQSx5Q0FBeUMsdURBQUM7QUFDMUMsNkJBQTZCO0FBQzdCO0FBQ0EsaUNBQWlDLGtFQUFTO0FBQzFDO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QjtBQUM3QiwwQkFBMEI7QUFDMUIscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQSxxQkFBcUIsMkRBQWM7QUFDbkM7QUFDQTtBQUNBLDBDQUEwQyx1REFBQztBQUMzQztBQUNBO0FBQ0EsdURBQXVELGtEQUFrRDtBQUN6Ryx3Q0FBd0MsbURBQW1EO0FBQzNGLHlCQUF5QjtBQUN6QjtBQUNBLHNEQUFzRCw4QkFBOEIsMkRBQWMsa0JBQWtCO0FBQ3BILHdDQUF3Qyw4QkFBOEIsMkRBQWMsbUJBQW1CO0FBQ3ZHLHlCQUF5QjtBQUN6QjtBQUNBLHNEQUFzRCw4QkFBOEIsMkRBQWMsa0JBQWtCO0FBQ3BILHdDQUF3Qyw4QkFBOEIsMkRBQWMsbUJBQW1CO0FBQ3ZHLHlCQUF5QjtBQUN6QjtBQUNBLHNEQUFzRCw4QkFBOEIsMkRBQWMsa0JBQWtCO0FBQ3BILHdDQUF3Qyw4QkFBOEIsMkRBQWMsbUJBQW1CO0FBQ3ZHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQiwyREFBYztBQUMvQjtBQUNBO0FBQ0E7QUFDQSwwRUFBMEU7QUFDMUUsNkNBQTZDO0FBQzdDLDJDQUEyQztBQUMzQyw2REFBNkQ7QUFDN0Q7QUFDQSxpQkFBaUIsMkRBQWM7QUFDL0I7QUFDQTtBQUNBLGlCQUFpQiwyREFBYztBQUMvQjtBQUNBO0FBQ0E7QUFDQSwwRUFBMEU7QUFDMUUsOENBQThDO0FBQzlDLDJDQUEyQztBQUMzQyw2REFBNkQ7QUFDN0Q7QUFDQSxpQkFBaUIsMkRBQWM7QUFDL0I7QUFDQTtBQUNBLDJEQUEyRDtBQUMzRCw0Q0FBNEM7QUFDNUM7QUFDQTtBQUNBO0FBQ0EsMEVBQTBFO0FBQzFFLDhDQUE4QztBQUM5QywyQ0FBMkM7QUFDM0MsNkRBQTZEO0FBQzdEO0FBQ0E7QUFDQSxpQkFBaUIsMkRBQWM7QUFDL0I7QUFDQTtBQUNBO0FBQ0EsMEVBQTBFO0FBQzFFLDhDQUE4QztBQUM5QywyQ0FBMkM7QUFDM0MsNkRBQTZEO0FBQzdEO0FBQ0EsaUJBQWlCLDJEQUFjO0FBQy9CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUZBQXVGLEtBQUs7QUFDNUY7QUFDQTtBQUNBLHNFQUFzRSx3Q0FBd0M7QUFDOUcsOERBQThELDBCQUEwQjtBQUN4RixpQkFBaUI7QUFDakI7QUFDQTtBQUNBLDJCQUEyQix1REFBQztBQUM1QjtBQUNBO0FBQ0EsMkJBQTJCLHVEQUFDO0FBQzVCO0FBQ0E7QUFDQTtBQUNBLDJCQUEyQix1REFBQztBQUM1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsMkRBQWM7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyx5QkFBeUIsWUFBWSxVQUFVO0FBQ25GLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLHlCQUF5QixZQUFZLFdBQVc7QUFDcEYsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFEQUFxRCxZQUFZO0FBQ2pFLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscURBQXFELFlBQVk7QUFDakU7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQyx5RUFBeUU7QUFDN0csYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLHlFQUF5RTtBQUM3RyxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLCtEQUFlLGFBQWEsRUFBQyIsInNvdXJjZXMiOlsid2VicGFjazovL2V1bm9zLWJsYWRlcy8uL3RzL3NoZWV0cy9hY3Rvci9CbGFkZXNQQ1NoZWV0LnRzP2ZiMjYiXSwic291cmNlc0NvbnRlbnQiOlsiLyogZXNsaW50LWRpc2FibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgQywgeyBCbGFkZXNBY3RvclR5cGUsIEJsYWRlc0l0ZW1UeXBlLCBBdHRyaWJ1dGVUcmFpdCwgVGFnLCBEb3dudGltZUFjdGlvbiwgQmxhZGVzUGhhc2UgfSBmcm9tIFwiLi4vLi4vY29yZS9jb25zdGFudHNcIjtcbmltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IEJsYWRlc0FjdG9yU2hlZXQgZnJvbSBcIi4vQmxhZGVzQWN0b3JTaGVldFwiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3IsIEJsYWRlc1BDLCBCbGFkZXNOUEMgfSBmcm9tIFwiLi4vLi4vZG9jdW1lbnRzL0JsYWRlc0FjdG9yUHJveHlcIjtcbmNsYXNzIEJsYWRlc1BDU2hlZXQgZXh0ZW5kcyBCbGFkZXNBY3RvclNoZWV0IHtcbiAgICBzdGF0aWMgZ2V0IGRlZmF1bHRPcHRpb25zKCkge1xuICAgICAgICByZXR1cm4gZm91bmRyeS51dGlscy5tZXJnZU9iamVjdChzdXBlci5kZWZhdWx0T3B0aW9ucywge1xuICAgICAgICAgICAgY2xhc3NlczogW1wiZXVub3MtYmxhZGVzXCIsIFwic2hlZXRcIiwgXCJhY3RvclwiLCBcInBjXCJdLFxuICAgICAgICAgICAgdGVtcGxhdGU6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2FjdG9yLXNoZWV0Lmhic1wiLFxuICAgICAgICAgICAgd2lkdGg6IDc3NSxcbiAgICAgICAgICAgIGhlaWdodDogNzc1LFxuICAgICAgICAgICAgdGFiczogW3sgbmF2U2VsZWN0b3I6IFwiLm5hdi10YWJzXCIsIGNvbnRlbnRTZWxlY3RvcjogXCIudGFiLWNvbnRlbnRcIiwgaW5pdGlhbDogXCJhYmlsaXRpZXNcIiB9XVxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0RGF0YSgpIHtcbiAgICAgICAgY29uc3QgY29udGV4dCA9IHN1cGVyLmdldERhdGEoKTtcbiAgICAgICAgY29uc3QgeyBhY3RpdmVTdWJJdGVtcywgYWN0aXZlU3ViQWN0b3JzIH0gPSB0aGlzLmFjdG9yO1xuICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgLy8gfiBBc3NlbWJsZSBlbWJlZGRlZCBhY3RvcnMgYW5kIGl0ZW1zXG4gICAgICAgIHNoZWV0RGF0YS5wcmVwYXJlZEl0ZW1zID0gT2JqZWN0LmFzc2lnbihjb250ZXh0LnByZXBhcmVkSXRlbXMgPz8ge30sIHtcbiAgICAgICAgICAgIGFiaWxpdGllczogYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmFiaWxpdHkpXG4gICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIH4gQXNzaWduIGRvdGxpbmVzIHRvIGFiaWxpdGllcyB3aXRoIHVzYWdlIGRhdGFcbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5zeXN0ZW0udXNlc19wZXJfc2NvcmUubWF4KSB7XG4gICAgICAgICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oaXRlbSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5SdWxlRG90bGluZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IGl0ZW0uc3lzdGVtLnVzZXNfcGVyX3Njb3JlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvdGxpbmVMYWJlbDogXCJVc2VzXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcIml0ZW0uc3lzdGVtLnVzZXNfcGVyX3Njb3JlLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkVtcHR5OiBcImRvdC1lbXB0eS5zdmdcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpY29uRW1wdHlIb3ZlcjogXCJkb3QtZW1wdHktaG92ZXIuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkZ1bGw6IFwiZG90LWZ1bGwuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkZ1bGxIb3ZlcjogXCJkb3QtZnVsbC1ob3Zlci5zdmdcIlxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIGJhY2tncm91bmQ6IGFjdGl2ZVN1Ykl0ZW1zLmZpbmQoKGl0ZW0pID0+IGl0ZW0udHlwZSA9PT0gQmxhZGVzSXRlbVR5cGUuYmFja2dyb3VuZCksXG4gICAgICAgICAgICBoZXJpdGFnZTogYWN0aXZlU3ViSXRlbXMuZmluZCgoaXRlbSkgPT4gaXRlbS50eXBlID09PSBCbGFkZXNJdGVtVHlwZS5oZXJpdGFnZSksXG4gICAgICAgICAgICB2aWNlOiBhY3RpdmVTdWJJdGVtcy5maW5kKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLnZpY2UpLFxuICAgICAgICAgICAgbG9hZG91dDogYWN0aXZlU3ViSXRlbXNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLmdlYXIpXG4gICAgICAgICAgICAgICAgLm1hcCgoaXRlbSkgPT4ge1xuICAgICAgICAgICAgICAgIC8vIEFzc2lnbiBsb2FkIGFuZCB1c2FnZSBkYXRhIHRvIGdlYXJcbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5zeXN0ZW0ubG9hZCkge1xuICAgICAgICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKGl0ZW0sIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlckNpcmNsZTogaXRlbS5zeXN0ZW0ubG9hZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG51bWJlckNpcmNsZUNsYXNzOiBcIml0ZW0tbG9hZFwiXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoaXRlbS5zeXN0ZW0udXNlc19wZXJfc2NvcmUubWF4KSB7XG4gICAgICAgICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oaXRlbSwge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5SdWxlRG90bGluZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IGl0ZW0uc3lzdGVtLnVzZXNfcGVyX3Njb3JlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRvdGxpbmVMYWJlbDogXCJVc2VzXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcIml0ZW0uc3lzdGVtLnVzZXNfcGVyX3Njb3JlLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkVtcHR5OiBcImRvdC1lbXB0eS5zdmdcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpY29uRW1wdHlIb3ZlcjogXCJkb3QtZW1wdHktaG92ZXIuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkZ1bGw6IFwiZG90LWZ1bGwuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkZ1bGxIb3ZlcjogXCJkb3QtZnVsbC1ob3Zlci5zdmdcIlxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIGl0ZW07XG4gICAgICAgICAgICB9KSxcbiAgICAgICAgICAgIHBsYXlib29rOiB0aGlzLmFjdG9yLnBsYXlib29rLFxuICAgICAgICAgICAgcHJvamVjdHM6IGFjdGl2ZVN1Ykl0ZW1zLmZpbHRlcigoaXRlbSkgPT4gaXRlbS50eXBlID09PSBCbGFkZXNJdGVtVHlwZS5wcm9qZWN0KSxcbiAgICAgICAgICAgIGNvaG9ydHM6IGNvbnRleHQucHJlcGFyZWRJdGVtcz8uY29ob3J0c1xuICAgICAgICB9KTtcbiAgICAgICAgc2hlZXREYXRhLnByZXBhcmVkQWN0b3JzID0ge1xuICAgICAgICAgICAgY3JldzogYWN0aXZlU3ViQWN0b3JzXG4gICAgICAgICAgICAgICAgLmZpbmQoKGFjdG9yKSA9PiBhY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUuY3JldyksXG4gICAgICAgICAgICB2aWNlX3B1cnZleW9yOiBhY3RpdmVTdWJBY3RvcnNcbiAgICAgICAgICAgICAgICAuZmluZCgoYWN0b3IpID0+IGFjdG9yLmhhc1RhZyhUYWcuTlBDLlZpY2VQdXJ2ZXlvcikpLFxuICAgICAgICAgICAgYWNxdWFpbnRhbmNlczogYWN0aXZlU3ViQWN0b3JzXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoYWN0b3IpID0+IGFjdG9yLmhhc1RhZyhUYWcuTlBDLkFjcXVhaW50YW5jZSkpXG4gICAgICAgIH07XG4gICAgICAgIHNoZWV0RGF0YS5oYXNWaWNlUHVydmV5b3IgPSBCb29sZWFuKHRoaXMuYWN0b3IucGxheWJvb2s/Lmhhc1RhZyhUYWcuR2Vhci5BZHZhbmNlZCkgPT09IGZhbHNlXG4gICAgICAgICAgICAmJiBhY3RpdmVTdWJJdGVtcy5maW5kKChpdGVtKSA9PiBpdGVtLnR5cGUgPT09IEJsYWRlc0l0ZW1UeXBlLnZpY2UpKTtcbiAgICAgICAgc2hlZXREYXRhLmhlYWxpbmdfY2xvY2sgPSB0aGlzLmFjdG9yLmhlYWxpbmdDbG9jaztcbiAgICAgICAgc2hlZXREYXRhLnN0YXNoRGF0YSA9IHtcbiAgICAgICAgICAgIGxhYmVsOiBcIlN0YXNoOlwiLFxuICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgIGRhdGE6IHRoaXMuYWN0b3Iuc3lzdGVtLnN0YXNoLFxuICAgICAgICAgICAgICAgIHRhcmdldDogXCJzeXN0ZW0uc3Rhc2gudmFsdWVcIixcbiAgICAgICAgICAgICAgICBpY29uRW1wdHk6IFwiY29pbi1lbXB0eS5zdmdcIixcbiAgICAgICAgICAgICAgICBpY29uRW1wdHlIb3ZlcjogXCJjb2luLWVtcHR5LWhvdmVyLnN2Z1wiLFxuICAgICAgICAgICAgICAgIGljb25GdWxsOiBcImNvaW4tZnVsbC5zdmdcIixcbiAgICAgICAgICAgICAgICBpY29uRnVsbEhvdmVyOiBcImNvaW4tZnVsbC1ob3Zlci5zdmdcIixcbiAgICAgICAgICAgICAgICBhbHRJY29uRnVsbDogXCJjb2luLXRlbi5zdmdcIixcbiAgICAgICAgICAgICAgICBhbHRJY29uRnVsbEhvdmVyOiBcImNvaW4tdGVuLWhvdmVyLnN2Z1wiLFxuICAgICAgICAgICAgICAgIGFsdEljb25TdGVwOiAxMFxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBzaGVldERhdGEuc3RyZXNzRGF0YSA9IHtcbiAgICAgICAgICAgIGxhYmVsOiB0aGlzLmFjdG9yLnN5c3RlbS5zdHJlc3MubmFtZSxcbiAgICAgICAgICAgIGRvdGxpbmU6IHtcbiAgICAgICAgICAgICAgICBkYXRhOiB0aGlzLmFjdG9yLnN5c3RlbS5zdHJlc3MsXG4gICAgICAgICAgICAgICAgZG90bGluZUNsYXNzOiB0aGlzLmFjdG9yLnN5c3RlbS5zdHJlc3MubWF4ID49IDEzID8gXCJuYXJyb3ctc3RyZXNzXCIgOiBcIlwiLFxuICAgICAgICAgICAgICAgIHRhcmdldDogXCJzeXN0ZW0uc3RyZXNzLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgc3ZnS2V5OiBcInRlZXRoLnRhbGxcIixcbiAgICAgICAgICAgICAgICBzdmdGdWxsOiBcImZ1bGx8aGFsZnxmcmFtZVwiLFxuICAgICAgICAgICAgICAgIHN2Z0VtcHR5OiBcImZ1bGx8aGFsZnxmcmFtZVwiXG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGlmIChCbGFkZXNBY3Rvci5Jc1R5cGUodGhpcy5hY3RvciwgQmxhZGVzQWN0b3JUeXBlLnBjKSkge1xuICAgICAgICAgICAgc2hlZXREYXRhLnRyYXVtYURhdGEgPSB7XG4gICAgICAgICAgICAgICAgbGFiZWw6IHRoaXMuYWN0b3Iuc3lzdGVtLnRyYXVtYS5uYW1lLFxuICAgICAgICAgICAgICAgIGRvdGxpbmU6IHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogeyB2YWx1ZTogdGhpcy5hY3Rvci50cmF1bWEsIG1heDogdGhpcy5hY3Rvci5zeXN0ZW0udHJhdW1hLm1heCB9LFxuICAgICAgICAgICAgICAgICAgICBzdmdLZXk6IFwidGVldGguc2hvcnRcIixcbiAgICAgICAgICAgICAgICAgICAgc3ZnRnVsbDogXCJmdWxsfGZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIHN2Z0VtcHR5OiBcImZyYW1lXCIsXG4gICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiB0cnVlXG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBjb21wQ29udGFpbmVyOiB7XG4gICAgICAgICAgICAgICAgICAgIGNsYXNzOiBcImNvbXAtdHJhdW1hLWNvbmRpdGlvbnMgY29tcC12ZXJ0aWNhbCBmdWxsLXdpZHRoXCIsXG4gICAgICAgICAgICAgICAgICAgIGJsb2NrczogW1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hY3Rvci50cmF1bWFMaXN0LnNsaWNlKDAsIE1hdGguY2VpbCh0aGlzLmFjdG9yLnRyYXVtYUxpc3QubGVuZ3RoIC8gMikpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLm1hcCgodE5hbWUpID0+ICh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tMYWJlbDogdE5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tDbGFzc2VzOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFjdGl2ZTogXCJjb21wLXRvZ2dsZS1yZWRcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5hY3RpdmU6IFwiY29tcC10b2dnbGUtZ3JleVwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja1RhcmdldDogYHN5c3RlbS50cmF1bWEuY2hlY2tlZC4ke3ROYW1lfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hlY2tWYWx1ZTogdGhpcy5hY3Rvci5zeXN0ZW0udHJhdW1hLmNoZWNrZWRbdE5hbWVdID8/IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IEMuVHJhdW1hVG9vbHRpcHNbdE5hbWVdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvb2x0aXBDbGFzczogXCJ0b29sdGlwLXRyYXVtYVwiXG4gICAgICAgICAgICAgICAgICAgICAgICB9KSksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmFjdG9yLnRyYXVtYUxpc3Quc2xpY2UoTWF0aC5jZWlsKHRoaXMuYWN0b3IudHJhdW1hTGlzdC5sZW5ndGggLyAyKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKCh0TmFtZSkgPT4gKHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja0xhYmVsOiB0TmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja0NsYXNzZXM6IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aXZlOiBcImNvbXAtdG9nZ2xlLXJlZFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbmFjdGl2ZTogXCJjb21wLXRvZ2dsZS1ncmV5XCJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNoZWNrVGFyZ2V0OiBgc3lzdGVtLnRyYXVtYS5jaGVja2VkLiR7dE5hbWV9YCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGVja1ZhbHVlOiB0aGlzLmFjdG9yLnN5c3RlbS50cmF1bWEuY2hlY2tlZFt0TmFtZV0gPz8gZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbHRpcDogQy5UcmF1bWFUb29sdGlwc1t0TmFtZV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9vbHRpcENsYXNzOiBcInRvb2x0aXAtdHJhdW1hXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgICAgICBdXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICBzaGVldERhdGEuYWJpbGl0eURhdGEgPSB7XG4gICAgICAgICAgICBkb3RsaW5lOiB7XG4gICAgICAgICAgICAgICAgZG90bGluZUNsYXNzOiBcImRvdGxpbmUtcmlnaHQgZG90bGluZS1nbG93XCIsXG4gICAgICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgICAgICB2YWx1ZTogdGhpcy5hY3Rvci5nZXRBdmFpbGFibGVBZHZhbmNlbWVudHMoXCJBYmlsaXR5XCIpLFxuICAgICAgICAgICAgICAgICAgICBtYXg6IHRoaXMuYWN0b3IuZ2V0QXZhaWxhYmxlQWR2YW5jZW1lbnRzKFwiQWJpbGl0eVwiKVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZG90bGluZUxhYmVsOiBcIkF2YWlsYWJsZSBBYmlsaXRpZXNcIixcbiAgICAgICAgICAgICAgICBpc0xvY2tlZDogdHJ1ZSxcbiAgICAgICAgICAgICAgICBpY29uRnVsbDogXCJkb3QtZnVsbC5zdmdcIlxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICBzaGVldERhdGEubG9hZERhdGEgPSB7XG4gICAgICAgICAgICBjdXJMb2FkOiB0aGlzLmFjdG9yLmN1cnJlbnRMb2FkLFxuICAgICAgICAgICAgc2VsTG9hZENvdW50OiB0aGlzLmFjdG9yLnN5c3RlbS5sb2Fkb3V0LmxldmVsc1tVLmxDYXNlKHRoaXMuYWN0b3Iuc3lzdGVtLmxvYWRvdXQuc2VsZWN0ZWQpXSxcbiAgICAgICAgICAgIG9wdGlvbnM6IEMuTG9hZG91dC5zZWxlY3Rpb25zLFxuICAgICAgICAgICAgc2VsZWN0ZWQ6IHRoaXMuYWN0b3Iuc3lzdGVtLmxvYWRvdXQuc2VsZWN0ZWQgPz8gXCJcIlxuICAgICAgICB9O1xuICAgICAgICBzaGVldERhdGEuYXJtb3IgPSBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXModGhpcy5hY3Rvci5zeXN0ZW0uYXJtb3IuYWN0aXZlKVxuICAgICAgICAgICAgLmZpbHRlcigoWywgaXNBY3RpdmVdKSA9PiBpc0FjdGl2ZSlcbiAgICAgICAgICAgIC5tYXAoKFthcm1vcl0pID0+IFtcbiAgICAgICAgICAgIGFybW9yLFxuICAgICAgICAgICAgdGhpcy5hY3Rvci5zeXN0ZW0uYXJtb3IuY2hlY2tlZFthcm1vcl1cbiAgICAgICAgXSkpO1xuICAgICAgICBzaGVldERhdGEuYXR0cmlidXRlRGF0YSA9IHt9O1xuICAgICAgICBjb25zdCBhdHRyRW50cmllcyA9IE9iamVjdC5lbnRyaWVzKHRoaXMuYWN0b3Iuc3lzdGVtLmF0dHJpYnV0ZXMpO1xuICAgICAgICBmb3IgKGNvbnN0IFthdHRyaWJ1dGUsIGF0dHJEYXRhXSBvZiBhdHRyRW50cmllcykge1xuICAgICAgICAgICAgc2hlZXREYXRhLmF0dHJpYnV0ZURhdGFbYXR0cmlidXRlXSA9IHtcbiAgICAgICAgICAgICAgICB0b29sdGlwOiBDLkF0dHJpYnV0ZVRvb2x0aXBzW2F0dHJpYnV0ZV0sXG4gICAgICAgICAgICAgICAgYWN0aW9uczoge31cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25FbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoYXR0ckRhdGEpO1xuICAgICAgICAgICAgZm9yIChjb25zdCBbYWN0aW9uLCBhY3Rpb25EYXRhXSBvZiBhY3Rpb25FbnRyaWVzKSB7XG4gICAgICAgICAgICAgICAgc2hlZXREYXRhLmF0dHJpYnV0ZURhdGFbYXR0cmlidXRlXS5hY3Rpb25zW2FjdGlvbl0gPSB7XG4gICAgICAgICAgICAgICAgICAgIHRvb2x0aXA6IEMuQWN0aW9uVG9vbHRpcHNbYWN0aW9uXSxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGFjdGlvbkRhdGEudmFsdWUsXG4gICAgICAgICAgICAgICAgICAgIG1heDogZ2FtZS5ldW5vYmxhZGVzLlRyYWNrZXIucGhhc2UgPT09IEJsYWRlc1BoYXNlLkNoYXJHZW5cbiAgICAgICAgICAgICAgICAgICAgICAgID8gMlxuICAgICAgICAgICAgICAgICAgICAgICAgOiB0aGlzLmFjdG9yLnN5c3RlbS5hdHRyaWJ1dGVzW2F0dHJpYnV0ZV1bYWN0aW9uXS5tYXhcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChnYW1lLmV1bm9ibGFkZXMuVHJhY2tlcj8ucGhhc2UgPT09IEJsYWRlc1BoYXNlLkRvd250aW1lKSB7XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zTGlzdCA9IHtcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uQWNxdWlyZUFzc2V0XTogXCJBY3F1aXJlIEFzc2V0XCIsXG4gICAgICAgICAgICAgICAgW0Rvd250aW1lQWN0aW9uLkluZHVsZ2VWaWNlXTogXCJJbmR1bGdlIFZpY2VcIixcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0XTogXCJQcm9qZWN0XCIsXG4gICAgICAgICAgICAgICAgW0Rvd250aW1lQWN0aW9uLlJlY292ZXJdOiBcIlJlY292ZXJcIixcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uUmVkdWNlSGVhdF06IFwiUmVkdWNlIEhlYXRcIixcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uVHJhaW5dOiBcIlRyYWluXCJcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICAvLyBHZXQgUENzLCBOUENzIGNhcGFibGUgb2Ygcm9sbGluZyBmb3IgdGhlIFJlY292ZXIgYWN0aW9uXG4gICAgICAgICAgICBjb25zdCBoZWFsQ2FwYWJsZURvY3MgPSBbXG4gICAgICAgICAgICAgICAgLi4uQmxhZGVzQWN0b3IuR2V0VHlwZVdpdGhUYWdzKEJsYWRlc0FjdG9yVHlwZS5wYywgVGFnLlBDLkNhbkhlYWwpLFxuICAgICAgICAgICAgICAgIC4uLkJsYWRlc0FjdG9yLkdldFR5cGVXaXRoVGFncyhCbGFkZXNBY3RvclR5cGUubnBjLCBUYWcuTlBDLkNhbkhlYWwpXG4gICAgICAgICAgICAgICAgLyogQUxTTyBORUVEIFRPIElOQ0xVREUgRVhQRVJUIENPSE9SVFMgV0lUSCBDQU5IRUFMIFRBRyAqL1xuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIC8vIGRlbGV0ZSBhbnkgQWN0aW9ucyB0aGF0IGFyZW4ndCBhcHBsaWNhYmxlXG4gICAgICAgICAgICBpZiAodGhpcy5hY3Rvci5zdHJlc3MgPT09IDApIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgYWN0aW9uc0xpc3RbRG93bnRpbWVBY3Rpb24uSW5kdWxnZVZpY2VdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHRoaXMuYWN0b3IuaGFybUxldmVsID09PSAwIHx8IGhlYWxDYXBhYmxlRG9jcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgYWN0aW9uc0xpc3RbRG93bnRpbWVBY3Rpb24uUmVjb3Zlcl07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIXRoaXMuYWN0b3IuY3JldyB8fCB0aGlzLmFjdG9yLmNyZXcuc3lzdGVtLmhlYXQudmFsdWUgPT09IDApIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgYWN0aW9uc0xpc3RbRG93bnRpbWVBY3Rpb24uUmVkdWNlSGVhdF07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZXQgYWN0aW9uc1N1Ym1lbnVEYXRhID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgc3dpdGNoICh0aGlzLmFjdG9yLnN5c3RlbS5kb3dudGltZV9hY3Rpb25zX29wZW5fc3VibWVudSkge1xuICAgICAgICAgICAgICAgIGNhc2UgRG93bnRpbWVBY3Rpb24uTG9uZ1Rlcm1Qcm9qZWN0OiB7XG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbnNTdWJtZW51RGF0YSA9IFtcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25TdWJEYXRhOiBcIk5ld1Byb2plY3RcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIk5ldyBQcm9qZWN0XCJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgLy8gLi4uIGFuZCBhZGQgb25lIGZvciBlYWNoIFByb2plY3Qgb24gdGhlIFBDLlxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5SZWNvdmVyOiB7XG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbnNTdWJtZW51RGF0YSA9IFtdO1xuICAgICAgICAgICAgICAgICAgICBoZWFsQ2FwYWJsZURvY3MuZm9yRWFjaCgoaERvYykgPT4ge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGhEb2MuaWQgPT09IHRoaXMuYWN0b3IuaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25zU3VibWVudURhdGE/LnVuc2hpZnQoe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25TdWJEYXRhOiB0aGlzLmFjdG9yLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBcIkhlYWwgU2VsZlwiXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChCbGFkZXNQQy5Jc1R5cGUoaERvYykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25zU3VibWVudURhdGE/LnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25TdWJEYXRhOiBoRG9jLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBVLnVDYXNlKGhEb2MubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKEJsYWRlc05QQy5Jc1R5cGUoaERvYykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25zU3VibWVudURhdGE/LnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25TdWJEYXRhOiBoRG9jLmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaXNwbGF5OiBoRG9jLm5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gLyogTkVFRCBDSEVDSyBGT1IgQ09IT1JUIEhFQUxFUlMgVE9PICovXG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FzZSBEb3dudGltZUFjdGlvbi5UcmFpbjoge1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjcmV3VHJhaW5pbmdVcGdyYWRlcyA9ICh0aGlzLmFjdG9yLmNyZXc/LnVwZ3JhZGVzXG4gICAgICAgICAgICAgICAgICAgICAgICAuZmlsdGVyKCh1cGdyYWRlKSA9PiAvXlRyYWluaW5nXy8uZXhlYyh1cGdyYWRlLnN5c3RlbS53b3JsZF9uYW1lKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5tYXAoKHVwZ3JhZGUpID0+IFUubENhc2UodXBncmFkZS5zeXN0ZW0ud29ybGRfbmFtZS5zcGxpdCgvXy8pWzFdKSkgPz8gW10pO1xuICAgICAgICAgICAgICAgICAgICBhY3Rpb25zU3VibWVudURhdGEgPSBbXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uU3ViRGF0YTogYHBsYXlib29rOiR7Y3Jld1RyYWluaW5nVXBncmFkZXMuaW5jbHVkZXMoXCJwbGF5Ym9va1wiKSA/IDIgOiAxfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogYCR7Y3Jld1RyYWluaW5nVXBncmFkZXMuaW5jbHVkZXMoXCJwbGF5Ym9va1wiKSA/IDIgOiAxfSBQbGF5Ym9vayBYUGBcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uU3ViRGF0YTogYGluc2lnaHQ6JHtjcmV3VHJhaW5pbmdVcGdyYWRlcy5pbmNsdWRlcyhBdHRyaWJ1dGVUcmFpdC5pbnNpZ2h0KSA/IDIgOiAxfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogYCR7Y3Jld1RyYWluaW5nVXBncmFkZXMuaW5jbHVkZXMoQXR0cmlidXRlVHJhaXQuaW5zaWdodCkgPyAyIDogMX0gSW5zaWdodCBYUGBcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uU3ViRGF0YTogYHByb3dlc3M6JHtjcmV3VHJhaW5pbmdVcGdyYWRlcy5pbmNsdWRlcyhBdHRyaWJ1dGVUcmFpdC5wcm93ZXNzKSA/IDIgOiAxfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogYCR7Y3Jld1RyYWluaW5nVXBncmFkZXMuaW5jbHVkZXMoQXR0cmlidXRlVHJhaXQucHJvd2VzcykgPyAyIDogMX0gUHJvd2VzcyBYUGBcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uU3ViRGF0YTogYHJlc29sdmU6JHtjcmV3VHJhaW5pbmdVcGdyYWRlcy5pbmNsdWRlcyhBdHRyaWJ1dGVUcmFpdC5yZXNvbHZlKSA/IDIgOiAxfWAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheTogYCR7Y3Jld1RyYWluaW5nVXBncmFkZXMuaW5jbHVkZXMoQXR0cmlidXRlVHJhaXQucmVzb2x2ZSkgPyAyIDogMX0gUmVzb2x2ZSBYUGBcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgYWN0aW9uc1Rvb2x0aXBzID0ge1xuICAgICAgICAgICAgICAgIFtEb3dudGltZUFjdGlvbi5BY3F1aXJlQXNzZXRdOiBgPGgxPkFjcXVpcmUgYW4gQXNzZXQ8L2gxPlxyXG4gICAgICAgIDxwPlJvbGwgeW91ciA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+VGllcjwvc3Ryb25nPiB0byBhY3F1aXJlIHRlbXBvcmFyeSB1c2Ugb2YgYW4gYXNzZXQgb3Igc2VydmljZS48L3A+XHJcbiAgICAgICAgPHA+VGhlIDxzdHJvbmc+UXVhbGl0eTwvc3Ryb25nPiBvZiB0aGUgYWNxdWlyZWQgYXNzZXQgZGVwZW5kcyBvbiB0aGUgcmVzdWx0IG9mIHlvdXIgcm9sbDo8L3A+XHJcbiAgICAgICAgPHVsPlxyXG4gICAgICAgIDxsaT48c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+Q3JpdGljYWwgU3VjY2Vzczwvc3Ryb25nPiAmbWRhc2g7IDxzdHJvbmcgY2xhc3M9J2dvbGQtYnJpZ2h0Jz5UaWVyPC9zdHJvbmc+IDxzdHJvbmc+KyAyPC9zdHJvbmc+PC9saT5cclxuICAgICAgICA8bGk+PHN0cm9uZz5TdWNjZXNzPC9zdHJvbmc+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPlRpZXI8L3N0cm9uZz4gPHN0cm9uZz4rIDI8L3N0cm9uZz48L2xpPlxyXG4gICAgICAgIDxsaT48Yj5QYXJ0aWFsIFN1Y2Nlc3M8L2I+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPlRpZXI8L3N0cm9uZz48L2xpPlxyXG4gICAgICAgIDxsaT48c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5GYWlsPC9zdHJvbmc+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPlRpZXI8L3N0cm9uZz4gPHN0cm9uZz7iiJIgMTwvc3Ryb25nPjwvbGk+XHJcbiAgICAgICAgPC91bD5gLFxuICAgICAgICAgICAgICAgIFtEb3dudGltZUFjdGlvbi5JbmR1bGdlVmljZV06IGA8aDE+SW5kdWxnZSBZb3VyIFZpY2U8L2gxPlxyXG4gICAgICAgIDxwPlJvbGwgeW91ciA8c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5sb3dlc3Q8L3N0cm9uZz4gPHN0cm9uZz5BdHRyaWJ1dGU8L3N0cm9uZz4uIENsZWFyIDxzdHJvbmc+U3RyZXNzPC9zdHJvbmc+IGVxdWFsIHRvIHRoZSA8c3Ryb25nPmhpZ2hlc3Q8L3N0cm9uZz4gZGllIHJlc3VsdC48L3A+XHJcbiAgICAgICAgPHA+PHN0cm9uZyBjbGFzcz1cInJlZC1icmlnaHRcIj5XYXJuaW5nOjwvc3Ryb25nPiBJZiB5b3UgY2xlYXIgbW9yZSA8c3Ryb25nPlN0cmVzczwvc3Ryb25nPiB0aGFuIHlvdSBoYXZlLCB5b3Ugd2lsbCA8c3Ryb25nIGNsYXNzPVwicmVkLWJyaWdodFwiPm92ZXJpbmR1bGdlPC9zdHJvbmc+LjwvcD5gLFxuICAgICAgICAgICAgICAgIFtEb3dudGltZUFjdGlvbi5Mb25nVGVybVByb2plY3RdOiBgPGgxPldvcmsgb24gYSBMb25nLVRlcm0gUHJvamVjdDwvaDE+XHJcbiAgICAgICAgPHA+V29yayB0byA8c3Ryb25nPmFkdmFuY2UgdGhlIGNsb2NrPC9zdHJvbmc+IG9mIG9uZSBvZiB5b3VyIGV4aXN0aW5nIDxzdHJvbmc+TG9uZy1UZXJtIFByb2plY3RzPC9zdHJvbmc+LCBvciBiZWdpbiBhIG5ldyBvbmUuPC9wPlxyXG4gICAgICAgIDxwPlJvbGwgdGhlIDxzdHJvbmc+QWN0aW9uPC9zdHJvbmc+IG1vc3QgYXBwcm9wcmlhdGUgdG8gdGhlIHdvcmsgeW91IGFyZSBkb2luZy4gVGhlIHJlc3VsdHMgb2YgeW91ciByb2xsIGRldGVybWluZSBob3cgZmFyIHlvdSB3aWxsIDxzdHJvbmc+YWR2YW5jZSB0aGUgY2xvY2s8L3N0cm9uZz46PC9wPlxyXG4gICAgICAgIDx1bD5cclxuICAgICAgICA8bGk+PHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPkNyaXRpY2FsIFN1Y2Nlc3M8L3N0cm9uZz4gJm1kYXNoOyA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+Rml2ZTwvc3Ryb25nPiBTZWdtZW50czwvbGk+XHJcbiAgICAgICAgPGxpPjxzdHJvbmc+U3VjY2Vzczwvc3Ryb25nPiAmbWRhc2g7ICA8c3Ryb25nPlRocmVlPC9zdHJvbmc+IFNlZ21lbnRzPC9saT5cclxuICAgICAgICA8bGk+PGI+UGFydGlhbCBTdWNjZXNzPC9iPiAmbWRhc2g7IDxiPlR3bzwvYj4gU2VnbWVudHM8L2xpPlxyXG4gICAgICAgIDxsaT48c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5GYWlsPC9zdHJvbmc+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+T25lPC9zdHJvbmc+IFNlZ21lbnQ8L2xpPlxyXG4gICAgICAgIDwvdWw+YCxcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uUmVjb3Zlcl06IGA8aDE+UmVjb3ZlciBmcm9tIEhhcm08L2gxPlxyXG4gICAgICAgIDxwPk1ha2UgYSA8c3Ryb25nPmhlYWxpbmcgdHJlYXRtZW50IHJvbGw8L3N0cm9uZz4gdXNpbmcgdGhlIGFwcHJvcHJpYXRlIHRyYWl0IG9mIHRoZSBjaGFyYWN0ZXIgaGVhbGluZyB5b3U6PC9wPlxyXG4gICAgICAgIDx1bD5cclxuICAgICAgICA8bGk+PHN0cm9uZz5BIFBDIHdpdGggJ1BoeXNpY2tlcic8L3N0cm9uZz4gJm1kYXNoOyA8c3Ryb25nPlRpbmtlcjwvc3Ryb25nPi4gPGVtPihZb3UgY2FuIGhlYWwgeW91cnNlbGYgdGhpcyB3YXksIGJ1dCBzdWZmZXIgPHN0cm9uZyBjbGFzcz1cInJlZC1icmlnaHRcIj4yIFN0cmVzczwvc3Ryb25nPiBmb3IgZG9pbmcgc28uKTwvZW0+PC9saT5cclxuICAgICAgICA8bGk+PHN0cm9uZz5BbiBOUEM8L3N0cm9uZz4gJm1kYXNoOyA8c3Ryb25nPlF1YWxpdHk8L3N0cm9uZz48L2xpPlxyXG4gICAgICAgIDwvdWw+XHJcbiAgICAgICAgPHA+VGhlIHJlc3VsdHMgb2YgeW91ciByb2xsIGRldGVybWluZSBob3cgZmFyIHlvdSB3aWxsIDxzdHJvbmc+QWR2YW5jZSB5b3VyIGhlYWxpbmcgY2xvY2s8L3N0cm9uZz46PC9wPlxyXG4gICAgICAgIDx1bD5cclxuICAgICAgICA8bGk+PHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPkNyaXRpY2FsIFN1Y2Nlc3M8L3N0cm9uZz4gJm1kYXNoOyA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+Rml2ZTwvc3Ryb25nPiBTZWdtZW50czwvbGk+XHJcbiAgICAgICAgPGxpPjxzdHJvbmc+U3VjY2Vzczwvc3Ryb25nPiAmbWRhc2g7ICA8c3Ryb25nPlRocmVlPC9zdHJvbmc+IFNlZ21lbnRzPC9saT5cclxuICAgICAgICA8bGk+PGI+UGFydGlhbCBTdWNjZXNzPC9iPiAmbWRhc2g7IDxiPlR3bzwvYj4gU2VnbWVudHM8L2xpPlxyXG4gICAgICAgIDxsaT48c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5GYWlsPC9zdHJvbmc+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+T25lPC9zdHJvbmc+IFNlZ21lbnQ8L2xpPlxyXG4gICAgICAgIDwvdWw+XHJcbiAgICAgICAgPHA+V2hlbiB5b3VyIDxzdHJvbmc+aGVhbGluZyBjbG9jazwvc3Ryb25nPiBpcyBmaWxsZWQsIHJlZHVjZSBlYWNoIEhhcm0gYnkgb25lIGxldmVsIG9mIHNldmVyaXR5LjwvcD5gLFxuICAgICAgICAgICAgICAgIFtEb3dudGltZUFjdGlvbi5SZWR1Y2VIZWF0XTogYDxoMT5SZWR1Y2UgSGVhdDwvaDE+XHJcbiAgICAgICAgPHA+V29yayB0byA8c3Ryb25nPnJlZHVjZSB0aGUgSGVhdDwvc3Ryb25nPiBvbiB5b3VyIENyZXcuPC9wPlxyXG4gICAgICAgIDxwPlJvbGwgdGhlIDxzdHJvbmc+QWN0aW9uPC9zdHJvbmc+IG1vc3QgYXBwcm9wcmlhdGUgdG8gdGhlIG1lYXN1cmVzIHlvdSBhcmUgdGFraW5nLiBUaGUgcmVzdWx0cyBvZiB5b3VyIHJvbGwgZGV0ZXJtaW5lIGhvdyBtdWNoIDxzdHJvbmcgY2xhc3M9XCJyZWQtYnJpZ2h0XCI+SGVhdDwvc3Ryb25nPiB5b3UgY2xlYXI6PC9wPlxyXG4gICAgICAgIDx1bD5cclxuICAgICAgICA8bGk+PHN0cm9uZyBjbGFzcz0nZ29sZC1icmlnaHQnPkNyaXRpY2FsIFN1Y2Nlc3M8L3N0cm9uZz4gJm1kYXNoOyA8c3Ryb25nIGNsYXNzPSdnb2xkLWJyaWdodCc+Rml2ZTwvc3Ryb25nPiBIZWF0PC9saT5cclxuICAgICAgICA8bGk+PHN0cm9uZz5TdWNjZXNzPC9zdHJvbmc+ICZtZGFzaDsgIDxzdHJvbmc+VGhyZWU8L3N0cm9uZz4gSGVhdDwvbGk+XHJcbiAgICAgICAgPGxpPjxiPlBhcnRpYWwgU3VjY2VzczwvYj4gJm1kYXNoOyA8Yj5Ud288L2I+IEhlYXQ8L2xpPlxyXG4gICAgICAgIDxsaT48c3Ryb25nIGNsYXNzPSdyZWQtYnJpZ2h0Jz5GYWlsPC9zdHJvbmc+ICZtZGFzaDsgPHN0cm9uZyBjbGFzcz0ncmVkLWJyaWdodCc+T25lPC9zdHJvbmc+IEhlYXQ8L2xpPlxyXG4gICAgICAgIDwvdWw+YCxcbiAgICAgICAgICAgICAgICBbRG93bnRpbWVBY3Rpb24uVHJhaW5dOiBgPGgxPlRyYWluPC9oMT5cclxuICAgICAgICA8cD5TZWxlY3QgYW4gPHN0cm9uZz5FeHBlcmllbmNlIFRyYWNrPC9zdHJvbmc+IDxlbT4oaS5lLiBJbnNpZ2h0LCBQcm93ZXNzLCBSZXNvbHZlLCBvciB5b3VyIFBsYXlib29rKTwvZW0+LiBHYWluIDxzdHJvbmc+MSBYUDwvc3Ryb25nPiBpbiB0aGF0IHRyYWNrLCBvciA8c3Ryb25nPjIgWFA8L3N0cm9uZz4gaWYgeW91ciBDcmV3IGhhcyB0aGUgY29ycmVzcG9uZGluZyA8c3Ryb25nPlRyYWluaW5nIFVwZ3JhZGU8L3N0cm9uZz4uPC9wPmBcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBjb25zdCBhY3Rpb25zUmVtYWluaW5nID0gdGhpcy5hY3Rvci5zeXN0ZW0uZG93bnRpbWVfYWN0aW9ucy5tYXhcbiAgICAgICAgICAgICAgICArIHRoaXMuYWN0b3Iuc3lzdGVtLmRvd250aW1lX2FjdGlvbl9ib251c1xuICAgICAgICAgICAgICAgIC0gdGhpcy5hY3Rvci5zeXN0ZW0uZG93bnRpbWVfYWN0aW9ucy52YWx1ZVxuICAgICAgICAgICAgICAgIC0gKHRoaXMuYWN0b3IuaXNBdFdhciA/IDEgOiAwKTtcbiAgICAgICAgICAgIGNvbnN0IGNhblBheUNvaW4gPSBCb29sZWFuKHRoaXMuYWN0b3Iuc3lzdGVtLmNvaW5zLnZhbHVlID49IDFcbiAgICAgICAgICAgICAgICB8fCB0aGlzLmFjdG9yLnN5c3RlbS5zdGFzaC52YWx1ZSA+PSAyKTtcbiAgICAgICAgICAgIGNvbnN0IGNhblBheVJlcCA9IEJvb2xlYW4odGhpcy5hY3Rvci5jcmV3XG4gICAgICAgICAgICAgICAgJiYgdGhpcy5hY3Rvci5jcmV3LnN5c3RlbS5yZXAudmFsdWUgPj0gMSk7XG4gICAgICAgICAgICBjb25zdCBpc0Rpc3BsYXlpbmdDb3N0cyA9IGFjdGlvbnNSZW1haW5pbmcgPD0gMDtcbiAgICAgICAgICAgIGNvbnN0IGlzRGlzcGxheWluZ0FjdGlvbnMgPSBhY3Rpb25zUmVtYWluaW5nID4gMFxuICAgICAgICAgICAgICAgIHx8IChjYW5QYXlDb2luICYmIHRoaXMuYWN0b3Iuc3lzdGVtLmRvd250aW1lX2FjdGlvbl9zZWxlY3RlZF9jb3N0ID09PSBcIkNvaW5cIilcbiAgICAgICAgICAgICAgICB8fCAoY2FuUGF5UmVwICYmIHRoaXMuYWN0b3Iuc3lzdGVtLmRvd250aW1lX2FjdGlvbl9zZWxlY3RlZF9jb3N0ID09PSBcIlJlcFwiKTtcbiAgICAgICAgICAgIHNoZWV0RGF0YS5kb3dudGltZURhdGEgPSB7XG4gICAgICAgICAgICAgICAgYWN0aW9uc0xpc3QsXG4gICAgICAgICAgICAgICAgYWN0aW9uc1Rvb2x0aXBzLFxuICAgICAgICAgICAgICAgIGFjdGlvbnNSZW1haW5pbmcsXG4gICAgICAgICAgICAgICAgYWN0aW9uc1N1Ym1lbnVEYXRhLFxuICAgICAgICAgICAgICAgIGNhblBheUNvaW4sXG4gICAgICAgICAgICAgICAgY2FuUGF5UmVwLFxuICAgICAgICAgICAgICAgIGlzRGlzcGxheWluZ0Nvc3RzLFxuICAgICAgICAgICAgICAgIGlzRGlzcGxheWluZ0FjdGlvbnMsXG4gICAgICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgICAgICBkb3RsaW5lQ2xhc3M6IFwiZG90bGluZS1yaWdodCBkb3RsaW5lLWdsb3dcIixcbiAgICAgICAgICAgICAgICAgICAgZGF0YToge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGFjdGlvbnNSZW1haW5pbmcsXG4gICAgICAgICAgICAgICAgICAgICAgICBtYXg6IGFjdGlvbnNSZW1haW5pbmdcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZG90bGluZUxhYmVsOiBcIkFjdGlvbnMgUmVtYWluaW5nXCIsXG4gICAgICAgICAgICAgICAgICAgIGlzTG9ja2VkOiB0cnVlLFxuICAgICAgICAgICAgICAgICAgICBpY29uRnVsbDogXCJkb3QtZnVsbC5zdmdcIlxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cbiAgICAgICAgc2hlZXREYXRhLmdhdGhlckluZm9Ub29sdGlwID0gKG5ldyBIYW5kbGViYXJzLlNhZmVTdHJpbmcoW1xuICAgICAgICAgICAgXCI8aDE+R2F0aGVyaW5nIEluZm9ybWF0aW9uPC9oMT5cIixcbiAgICAgICAgICAgIFwiPGgyPlF1ZXN0aW9ucyB0byBDb25zaWRlcjwvaDI+XCIsXG4gICAgICAgICAgICBcIjx1bD5cIixcbiAgICAgICAgICAgIC4uLk9iamVjdC52YWx1ZXModGhpcy5hY3Rvci5zeXN0ZW0uZ2F0aGVyX2luZm8gPz8gW10pLm1hcCgobGluZSkgPT4gYDxsaT4ke2xpbmV9PC9saT5gKSA/PyBbXSxcbiAgICAgICAgICAgIFwiPC91bD5cIlxuICAgICAgICBdLmpvaW4oXCJcIikpKS50b1N0cmluZygpO1xuICAgICAgICBlTG9nLmNoZWNrTG9nKFwiQXR0cmlidXRlXCIsIFwiW0JsYWRlc1BDU2hlZXRdIGF0dHJpYnV0ZURhdGFcIiwgeyBhdHRyaWJ1dGVEYXRhOiBzaGVldERhdGEuYXR0cmlidXRlRGF0YSB9KTtcbiAgICAgICAgZUxvZy5jaGVja0xvZyhcImFjdG9yXCIsIFwiW0JsYWRlc1BDU2hlZXRdIGdldERhdGEoKVwiLCB7IC4uLmNvbnRleHQsIC4uLnNoZWV0RGF0YSB9KTtcbiAgICAgICAgcmV0dXJuIHsgLi4uY29udGV4dCwgLi4uc2hlZXREYXRhIH07XG4gICAgfVxuICAgIGdldCBhY3RpdmVBcm1vcigpIHtcbiAgICAgICAgcmV0dXJuIE9iamVjdC5rZXlzKFUub2JqRmlsdGVyKHRoaXMuYWN0b3Iuc3lzdGVtLmFybW9yLmFjdGl2ZSwgKHZhbCkgPT4gdmFsID09PSB0cnVlKSk7XG4gICAgfVxuICAgIGdldCBjaGVja2VkQXJtb3IoKSB7XG4gICAgICAgIHJldHVybiBPYmplY3Qua2V5cyhVLm9iakZpbHRlcih0aGlzLmFjdG9yLnN5c3RlbS5hcm1vci5jaGVja2VkLCAodmFsLCBrZXkpID0+IHZhbCA9PT0gdHJ1ZVxuICAgICAgICAgICAgJiYgdGhpcy5hY3Rvci5zeXN0ZW0uYXJtb3IuYWN0aXZlW2tleV0gPT09IHRydWUpKTtcbiAgICB9XG4gICAgZ2V0IHVuY2hlY2tlZEFybW9yKCkge1xuICAgICAgICByZXR1cm4gT2JqZWN0LmtleXMoVS5vYmpGaWx0ZXIodGhpcy5hY3Rvci5zeXN0ZW0uYXJtb3IuYWN0aXZlLCAodmFsLCBrZXkpID0+IHZhbCA9PT0gdHJ1ZVxuICAgICAgICAgICAgJiYgdGhpcy5hY3Rvci5zeXN0ZW0uYXJtb3IuY2hlY2tlZFtrZXldID09PSBmYWxzZSkpO1xuICAgIH1cbiAgICBfZ2V0SG92ZXJBcm1vcigpIHtcbiAgICAgICAgaWYgKCF0aGlzLmFjdGl2ZUFybW9yLmxlbmd0aCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLmFjdGl2ZUFybW9yLmluY2x1ZGVzKFwiaGVhdnlcIikpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmNoZWNrZWRBcm1vci5pbmNsdWRlcyhcImhlYXZ5XCIpID8gXCJsaWdodFwiIDogXCJoZWF2eVwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHRoaXMuYWN0aXZlQXJtb3IuaW5jbHVkZXMoXCJsaWdodFwiKSkge1xuICAgICAgICAgICAgcmV0dXJuIFwibGlnaHRcIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJzcGVjaWFsXCI7XG4gICAgfVxuICAgIF9nZXRDbGlja0FybW9yKCkge1xuICAgICAgICBpZiAoIXRoaXMudW5jaGVja2VkQXJtb3IubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMudW5jaGVja2VkQXJtb3IuaW5jbHVkZXMoXCJoZWF2eVwiKSkge1xuICAgICAgICAgICAgcmV0dXJuIFwiaGVhdnlcIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy51bmNoZWNrZWRBcm1vci5pbmNsdWRlcyhcImxpZ2h0XCIpKSB7XG4gICAgICAgICAgICByZXR1cm4gXCJsaWdodFwiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBcInNwZWNpYWxcIjtcbiAgICB9XG4gICAgX2dldENvbnRleHRNZW51QXJtb3IoKSB7XG4gICAgICAgIGlmICghdGhpcy5jaGVja2VkQXJtb3IubGVuZ3RoKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuY2hlY2tlZEFybW9yLmluY2x1ZGVzKFwibGlnaHRcIikpIHtcbiAgICAgICAgICAgIHJldHVybiBcImxpZ2h0XCI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMuY2hlY2tlZEFybW9yLmluY2x1ZGVzKFwiaGVhdnlcIikpIHtcbiAgICAgICAgICAgIHJldHVybiBcImhlYXZ5XCI7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFwic3BlY2lhbFwiO1xuICAgIH1cbiAgICBhc3luYyBfb25BZHZhbmNlQ2xpY2soZXZlbnQpIHtcbiAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgc3VwZXIuX29uQWR2YW5jZUNsaWNrKGV2ZW50KTtcbiAgICAgICAgY29uc3QgYWN0aW9uID0gJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwiYWN0aW9uXCIpLnJlcGxhY2UoL15hZHZhbmNlLS8sIFwiXCIpO1xuICAgICAgICBpZiAoYWN0aW9uIGluIEF0dHJpYnV0ZVRyYWl0KSB7XG4gICAgICAgICAgICBhd2FpdCB0aGlzLmFjdG9yLmFkdmFuY2VBdHRyaWJ1dGUoYWN0aW9uKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBhY3RpdmF0ZUxpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIHN1cGVyLmFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpO1xuICAgICAgICAvLyB+IEV2ZXJ5dGhpbmcgYmVsb3cgaGVyZSBpcyBvbmx5IG5lZWRlZCBpZiB0aGUgc2hlZXQgaXMgZWRpdGFibGVcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZWRpdGFibGUpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBjb25zdCBzZWxmID0gdGhpcztcbiAgICAgICAgLy8gfiBBcm1vciBDb250cm9sXG4gICAgICAgIGh0bWwuZmluZChcIi5tYWluLWFybW9yLWNvbnRyb2xcIikub24oe1xuICAgICAgICAgICAgY2xpY2soKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0QXJtb3IgPSBzZWxmLl9nZXRDbGlja0FybW9yKCk7XG4gICAgICAgICAgICAgICAgaWYgKCF0YXJnZXRBcm1vcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHNlbGYuYWN0b3IudXBkYXRlKHsgW2BzeXN0ZW0uYXJtb3IuY2hlY2tlZC4ke3RhcmdldEFybW9yfWBdOiB0cnVlIH0pO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGNvbnRleHRtZW51KCkge1xuICAgICAgICAgICAgICAgIGNvbnN0IHRhcmdldEFybW9yID0gc2VsZi5fZ2V0Q29udGV4dE1lbnVBcm1vcigpO1xuICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0QXJtb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZWxmLmFjdG9yLnVwZGF0ZSh7IFtgc3lzdGVtLmFybW9yLmNoZWNrZWQuJHt0YXJnZXRBcm1vcn1gXTogZmFsc2UgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbW91c2VlbnRlcigpIHtcbiAgICAgICAgICAgICAgICBjb25zdCB0YXJnZXRBcm1vciA9IHNlbGYuX2dldEhvdmVyQXJtb3IoKTtcbiAgICAgICAgICAgICAgICBlTG9nLmxvZzQoXCJNb3VzZSBFbnRlclwiLCB0YXJnZXRBcm1vciwgdGhpcywgJCh0aGlzKSwgJCh0aGlzKS5uZXh0KCkpO1xuICAgICAgICAgICAgICAgIGlmICghdGFyZ2V0QXJtb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAkKHRoaXMpLnNpYmxpbmdzKGAuc3ZnLWFybW9yLmFybW9yLSR7dGFyZ2V0QXJtb3J9YCkuYWRkQ2xhc3MoXCJob3Zlci1vdmVyXCIpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIG1vdXNlbGVhdmUoKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgdGFyZ2V0QXJtb3IgPSBzZWxmLl9nZXRIb3ZlckFybW9yKCk7XG4gICAgICAgICAgICAgICAgaWYgKCF0YXJnZXRBcm1vcikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICQodGhpcykuc2libGluZ3MoYC5zdmctYXJtb3IuYXJtb3ItJHt0YXJnZXRBcm1vcn1gKS5yZW1vdmVDbGFzcyhcImhvdmVyLW92ZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBodG1sLmZpbmQoXCIuc3BlY2lhbC1jb250cm9sXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrKCkge1xuICAgICAgICAgICAgICAgIGlmICghc2VsZi5hY3RpdmVBcm1vci5pbmNsdWRlcyhcInNwZWNpYWxcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZWxmLmFjdG9yLnVwZGF0ZSh7IFwic3lzdGVtLmFybW9yLmNoZWNrZWQuc3BlY2lhbFwiOiBzZWxmLnVuY2hlY2tlZEFybW9yLmluY2x1ZGVzKFwic3BlY2lhbFwiKSB9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBjb250ZXh0bWVudSgpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNlbGYuYWN0aXZlQXJtb3IuaW5jbHVkZXMoXCJzcGVjaWFsXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc2VsZi5hY3Rvci51cGRhdGUoeyBcInN5c3RlbS5hcm1vci5jaGVja2VkLnNwZWNpYWxcIjogc2VsZi51bmNoZWNrZWRBcm1vci5pbmNsdWRlcyhcInNwZWNpYWxcIikgfSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbW91c2VlbnRlcigpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNlbGYuYWN0aXZlQXJtb3IuaW5jbHVkZXMoXCJzcGVjaWFsXCIpIHx8IHNlbGYuYWN0aXZlQXJtb3IubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJCh0aGlzKS5zaWJsaW5ncyhcIi5zdmctYXJtb3IuYXJtb3Itc3BlY2lhbFwiKS5hZGRDbGFzcyhcImhvdmVyLW92ZXJcIik7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgbW91c2VsZWF2ZSgpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXNlbGYuYWN0aXZlQXJtb3IuaW5jbHVkZXMoXCJzcGVjaWFsXCIpIHx8IHNlbGYuYWN0aXZlQXJtb3IubGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgJCh0aGlzKS5zaWJsaW5ncyhcIi5zdmctYXJtb3IuYXJtb3Itc3BlY2lhbFwiKS5yZW1vdmVDbGFzcyhcImhvdmVyLW92ZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc1BDU2hlZXQ7XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/sheets/actor/BladesPCSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/item/BladesClockKeeperSheet.ts": +/*!**************************************************!*\ + !*** ./ts/sheets/item/BladesClockKeeperSheet.ts ***! + \**************************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _BladesItemSheet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./BladesItemSheet */ \"./ts/sheets/item/BladesItemSheet.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n// import U from \"../../core/utilities\";\n\n\nclass BladesClockKeeperSheet extends _BladesItemSheet__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n // static Get() { return game.eunoblades.ClockKeeper as BladesClockKeeper; }\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"item\", \"clock-keeper\"],\n template: \"systems/eunos-blades/templates/items/clock_keeper-sheet.hbs\",\n width: 700,\n height: 970,\n // submitOnChange: false,\n tabs: [{ navSelector: \".nav-tabs\", contentSelector: \".tab-content\", initial: \"scene-keys\" }]\n });\n }\n static async Initialize() {\n Items.registerSheet(\"blades\", BladesClockKeeperSheet, { types: [\"clock_keeper\"], makeDefault: true });\n return loadTemplates([\n \"systems/eunos-blades/templates/items/clock_keeper-sheet.hbs\"\n ]);\n }\n getData() {\n const context = super.getData();\n const sheetData = {\n currentScene: game.scenes.current.id,\n targetScene: this.item.targetSceneID,\n sceneOptions: Array.from(game.scenes),\n sceneKeys: this.item.getSceneKeys(this.item.system.targetScene ?? game.scenes.current.id),\n pcsWithProjects: _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesPC.All.filter((pc) => pc.projects.length > 0),\n factions: Array.from(_documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesFaction.All)\n };\n return { ...context, ...sheetData };\n }\n addKey(event) {\n event.preventDefault();\n this.item.addClockKey();\n }\n deleteKey(event) {\n event.preventDefault();\n const keyID = event.currentTarget.dataset.id;\n if (keyID) {\n this.item.deleteClockKey(keyID);\n }\n }\n setSelectColor(select$, value) {\n value ??= select$.data(\"value\");\n switch (value) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockColor.yellow: {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(select$, {\n color: \"var(--blades-black)\",\n background: \"var(--blades-gold-bright)\",\n textShadow: \"none\"\n });\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockColor.red: {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(select$, {\n color: \"var(--blades-white)\",\n background: \"var(--blades-red)\"\n });\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockColor.cyan: {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(select$, {\n color: \"var(--blades-black)\",\n background: \"var(--blades-blue-bright)\",\n textShadow: \"none\"\n });\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockColor.white: {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.set(select$, {\n color: \"var(--blades-black)\",\n background: \"var(--blades-white)\",\n textShadow: \"none\"\n });\n break;\n }\n default: break;\n }\n }\n async activateListeners(html) {\n await super.activateListeners(html);\n // *** CREATE CLOCK KEY *** ~\n html.find(\"[data-action=\\\"create-clock-key\\\"\").on({\n click: async (event) => {\n event.preventDefault();\n await this.item.addClockKey();\n // Notify GM\n }\n });\n // #region Helper Functions to Retrieve Clock Keys & Clocks ~\n function getClockKeyFromEvent(event) {\n const id = $(event.currentTarget).data(\"keyId\")\n || $(event.currentTarget).closest(\".control-flipper\").data(\"clockKeyId\");\n if (!id) {\n throw new Error(\"No id found on element\");\n }\n const clockKey = game.eunoblades.ClockKeys.get(id);\n if (!clockKey) {\n throw new Error(`Clock key with id ${id} not found`);\n }\n return clockKey;\n }\n function getClockFromEvent(event) {\n const clockKey = getClockKeyFromEvent(event);\n const clockID = $(event.currentTarget).data(\"clockId\")\n || $(event.currentTarget).closest(\".control-flipper\").data(\"clockId\");\n if (!clockID) {\n throw new Error(\"No clockID found on element\");\n }\n const clock = clockKey.getClockByID(clockID);\n if (!clock) {\n throw new Error(`Clock with id ${clockID} not found`);\n }\n return [clockKey, clock];\n }\n // #endregion\n // #region Initializing Flip Control Panels ~\n // const flipControls$ = html.find(\".control-flipper\");\n // setTimeout(() => {\n // U.gsap.set(flipControls$.find(\".controls-back\"), {\n // translateZ: -2,\n // rotateX: 180,\n // autoAlpha: 1\n // });\n // U.gsap.set(flipControls$.find(\".controls-front\"), {\n // translateZ: 2,\n // autoAlpha: 1\n // });\n // U.gsap.set(html.find(\".control-flipper.controls-flipped\"), {\n // rotateX: 180\n // });\n // }, 500);\n // #endregion\n // #region *** CLOCK KEYS *** ~\n const clockKeyControls$ = html.find(\".clock-key-control-flipper\");\n // #region isOnDisplay === TRUE OR FALSE (Conditional Animation Checks Required) ~\n clockKeyControls$.find(\"[data-action=\\\"toggle-name-visibility\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-key-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const clockKey = getClockKeyFromEvent(event);\n const isNameVisible = !clockKey.isNameVisible;\n clockKey.updateTarget(\"isNameVisible\", isNameVisible);\n // If clockKey is on display (in scene & visible), sent out animation socket calls\n if (clockKey.isInScene() && clockKey.isVisible) {\n if (isNameVisible) {\n clockKey.fadeInName_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n else {\n clockKey.fadeOutName_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-name-visibility\\\"] i\")\n .toggleClass(\"fa-signature\")\n .toggleClass(\"fa-signature-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n clockKeyControls$.find(\"[data-action=\\\"toggle-spotlight\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-key-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const clockKey = getClockKeyFromEvent(event);\n const isSpotlit = !clockKey.isSpotlit;\n clockKey.updateTarget(\"isSpotlit\", isSpotlit);\n // If clockKey is on display (in scene & visible), sent out animation socket calls\n if (clockKey.isInScene() && clockKey.isVisible) {\n if (isSpotlit) {\n // clockKey.unspotlight_SocketCall(ClockDisplayContext.overlay);\n }\n else {\n // clockKey.spotlight_SocketCall(ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-spotlight\\\"] i\")\n .toggleClass(\"fa-message\")\n .toggleClass(\"fa-message-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n // #endregion\n // #region isOnDisplay === TRUE ~\n clockKeyControls$.find(\"[data-action=\\\"pull-clock-key\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-key-control-flipper\");\n elem$.on({\n click: (event) => {\n event.preventDefault();\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.keyControlPanelFlip(control$, { angle: 180 });\n const clockKey = getClockKeyFromEvent(event);\n clockKey.updateTarget(\"isVisible\", false);\n game.eunoblades.Director.pullKey_SocketCall(clockKey.id);\n }\n });\n });\n // #endregion\n // #region isOnDisplay === FALSE ~\n clockKeyControls$.find(\"[data-action=\\\"drop-clock-key\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-key-control-flipper\");\n elem$.on({\n click: (event) => {\n event.preventDefault();\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.effects.keyControlPanelFlip(control$, { angle: 0 });\n const clockKey = getClockKeyFromEvent(event);\n clockKey.updateTarget(\"isVisible\", true);\n game.eunoblades.Director.renderClockKey_SocketCall(clockKey.id);\n }\n });\n });\n clockKeyControls$.find(\"[data-action=\\\"spawn-position-dragger\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n const clockKey = getClockKeyFromEvent(event);\n clockKey.spawnPositionDragger(game.eunoblades.Director.clockKeySection$);\n }\n });\n clockKeyControls$.find(\"[data-action=\\\"delete-clock-key\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n await getClockKeyFromEvent(event).delete(game.eunoblades.ClockKeys);\n }\n });\n clockKeyControls$.find(\"[data-action=\\\"add-key-to-scene\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n await getClockKeyFromEvent(event).addToScene(this.document.targetSceneID);\n }\n });\n clockKeyControls$.find(\"[data-action=\\\"remove-key-from-scene\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n await getClockKeyFromEvent(event).removeFromScene(this.document.targetSceneID);\n }\n });\n clockKeyControls$.find(\"[data-action=\\\"add-clock-to-key\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n await getClockKeyFromEvent(event).addClock();\n }\n });\n clockKeyControls$.find(\"input.clock-key-input:not([readonly])\").on({\n change: async (event) => {\n event.preventDefault();\n const input$ = $(event.currentTarget);\n const inputVal = input$.val();\n if (typeof inputVal === \"string\") {\n getClockKeyFromEvent(event).updateTarget(input$.data(\"targetProp\"), inputVal);\n clockKeyControls$.find(\"input.clock-key-input\").val(inputVal);\n }\n }\n });\n // #endregion\n // #endregion\n // #region *** CLOCKS *** ~\n const clockControls$ = html.find(\".clock-control-flipper\");\n // #region isOnDisplay === TRUE OR FALSE (Conditional Animation Checks Required) ~\n clockControls$.find(\"[data-action=\\\"toggle-visible\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const [clockKey, clock] = getClockFromEvent(event);\n const isVisible = !clock.isVisible;\n clock.updateTarget(\"isVisible\", isVisible);\n // If clock key is on display (in scene & visible), sent out animation socket calls\n if (clockKey.isInScene() && clockKey.isVisible) {\n if (isVisible) {\n clock.reveal_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n else {\n clock.hide_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-visible\\\"] i\")\n .toggleClass(\"fa-eye\")\n .toggleClass(\"fa-eye-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n clockControls$.find(\"[data-action=\\\"toggle-active\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const [clockKey, clock] = getClockFromEvent(event);\n const isActive = !clock.isActive;\n clock.updateTarget(\"isActive\", isActive);\n // If clock AND clock key is on display (in scene & visible), sent out animation socket calls\n if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) {\n if (isActive) {\n clock.activate_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n else {\n clock.deactivate_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-active\\\"] i\")\n .toggleClass(\"fa-bolt\")\n .toggleClass(\"fa-bolt-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n clockControls$.find(\"[data-action=\\\"toggle-name-visibility\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const clock = getClockFromEvent(event)[1];\n const isNameVisible = !clock.isNameVisible;\n clock.updateTarget(\"isNameVisible\", isNameVisible);\n // If clock is on display (in scene & visible), sent out animation socket calls\n if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) {\n if (isNameVisible) {\n clock.fadeInClockName_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n else {\n clock.fadeOutClockName_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-name-visibility\\\"] i\")\n .toggleClass(\"fa-signature\")\n .toggleClass(\"fa-signature-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n clockControls$.find(\"[data-action=\\\"toggle-highlight\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const [clockKey, clock] = getClockFromEvent(event);\n const isHighlighted = !clock.isHighlighted;\n clock.updateTarget(\"isHighlighted\", isHighlighted);\n // If clock is on display (in scene & visible), sent out animation socket calls\n if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) {\n if (isHighlighted) {\n clock.highlight_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n else {\n clock.unhighlight_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay);\n }\n }\n // Toggle class names on icon\n control$.find(\"[data-action=\\\"toggle-highlight\\\"] i\")\n .toggleClass(\"fa-lightbulb\")\n .toggleClass(\"fa-lightbulb-slash\")\n .toggleClass(\"fa-solid\")\n .toggleClass(\"fa-regular\");\n }\n });\n });\n // #endregion\n // #region isOnDisplay === TRUE ~\n clockControls$.find(\"[data-action=\\\"change-segments\\\"]\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n click: async (event) => {\n event.preventDefault();\n const [clockKey, clock] = getClockFromEvent(event);\n const delta = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt($(event.currentTarget).data(\"value\"));\n const finalVal = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].gsap.utils.clamp(0, clock.max, clock.value + delta);\n if (delta > 0) {\n clock.fillSegments(delta, true);\n }\n else {\n clock.clearSegments(Math.abs(delta), true);\n }\n control$.find(\"select.clock-select-value\").val(finalVal);\n clock.changeSegments_SocketCall(_core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockDisplayContext.overlay, clock.value, finalVal);\n }\n });\n });\n // #endregion\n // #region isOnDisplay === FALSE ~\n clockControls$.find(\"select.clock-control-select\")\n .each((i, elem) => {\n const elem$ = $(elem);\n if (elem$.hasClass(\"clock-select-color\")) {\n // this.setSelectColor(elem$);\n }\n })\n .on({\n change: (event) => {\n event.preventDefault();\n const select$ = $(event.currentTarget);\n const value = select$.data(\"dtype\") === \"number\"\n ? _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(select$.val())\n : select$.val();\n const prop = select$.data(\"targetProp\");\n getClockFromEvent(event)[1].updateTarget(prop, value);\n if (prop === \"color\" && typeof value === \"string\" && value in _core_constants__WEBPACK_IMPORTED_MODULE_2__.ClockColor) {\n this.setSelectColor(select$, value);\n }\n }\n });\n clockControls$.find(\"input.clock-input:not([readonly])\")\n .each((i, elem) => {\n const elem$ = $(elem);\n const control$ = elem$.closest(\".clock-control-flipper\");\n elem$.on({\n change: (event) => {\n event.preventDefault();\n const input$ = $(event.currentTarget);\n const inputVal = input$.val();\n if (typeof inputVal === \"string\") {\n getClockFromEvent(event)[1].updateTarget(input$.data(\"targetProp\"), inputVal);\n control$.find(\"input.clock-input\").val(inputVal);\n }\n }\n });\n });\n clockControls$.find(\"[data-action=\\\"delete-clock\\\"]\").on({\n click: async (event) => {\n event.preventDefault();\n await getClockFromEvent(event)[1].delete();\n }\n });\n // #endregion\n // #endregion\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesClockKeeperSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvaXRlbS9CbGFkZXNDbG9ja0tlZXBlclNoZWV0LnRzIiwibWFwcGluZ3MiOiI7Ozs7O0FBQUE7QUFDcUM7QUFDVztBQUNoRDtBQUN1RTtBQUNJO0FBQzNFLHFDQUFxQyx3REFBZTtBQUNwRCxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsa0ZBQWtGO0FBQ3ZHLFNBQVM7QUFDVDtBQUNBO0FBQ0EsZ0VBQWdFLDRDQUE0QztBQUM1RztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLGlFQUFRO0FBQ3JDLGlDQUFpQyxzRUFBYTtBQUM5QztBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUIsdURBQVU7QUFDM0IsZ0JBQWdCLHVEQUFDO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsaUJBQWlCLHVEQUFVO0FBQzNCLGdCQUFnQix1REFBQztBQUNqQjtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCO0FBQ0E7QUFDQSxpQkFBaUIsdURBQVU7QUFDM0IsZ0JBQWdCLHVEQUFDO0FBQ2pCO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0EsaUJBQWlCLHVEQUFVO0FBQzNCLGdCQUFnQix1REFBQztBQUNqQjtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxxREFBcUQsSUFBSTtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNB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cUNBQXFDLHVEQUFDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0RBQW9ELGdFQUFtQjtBQUN2RTtBQUNBLGFBQWE7QUFDYixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLHVEQUFDO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBLDhFQUE4RSx1REFBVTtBQUN4RjtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUFlLHNCQUFzQixFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvc2hlZXRzL2l0ZW0vQmxhZGVzQ2xvY2tLZWVwZXJTaGVldC50cz82ZGMyIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuaW1wb3J0IFUgZnJvbSBcIi4uLy4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgQmxhZGVzSXRlbVNoZWV0IGZyb20gXCIuL0JsYWRlc0l0ZW1TaGVldFwiO1xuLy8gaW1wb3J0IFUgZnJvbSBcIi4uLy4uL2NvcmUvdXRpbGl0aWVzXCI7XG5pbXBvcnQgeyBDbG9ja0NvbG9yLCBDbG9ja0Rpc3BsYXlDb250ZXh0IH0gZnJvbSBcIi4uLy4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBCbGFkZXNQQywgQmxhZGVzRmFjdGlvbiB9IGZyb20gXCIuLi8uLi9kb2N1bWVudHMvQmxhZGVzQWN0b3JQcm94eVwiO1xuY2xhc3MgQmxhZGVzQ2xvY2tLZWVwZXJTaGVldCBleHRlbmRzIEJsYWRlc0l0ZW1TaGVldCB7XG4gICAgLy8gc3RhdGljIEdldCgpIHsgcmV0dXJuIGdhbWUuZXVub2JsYWRlcy5DbG9ja0tlZXBlciBhcyBCbGFkZXNDbG9ja0tlZXBlcjsgfVxuICAgIHN0YXRpYyBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBmb3VuZHJ5LnV0aWxzLm1lcmdlT2JqZWN0KHN1cGVyLmRlZmF1bHRPcHRpb25zLCB7XG4gICAgICAgICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcIml0ZW1cIiwgXCJjbG9jay1rZWVwZXJcIl0sXG4gICAgICAgICAgICB0ZW1wbGF0ZTogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvaXRlbXMvY2xvY2tfa2VlcGVyLXNoZWV0Lmhic1wiLFxuICAgICAgICAgICAgd2lkdGg6IDcwMCxcbiAgICAgICAgICAgIGhlaWdodDogOTcwLFxuICAgICAgICAgICAgLy8gc3VibWl0T25DaGFuZ2U6IGZhbHNlLFxuICAgICAgICAgICAgdGFiczogW3sgbmF2U2VsZWN0b3I6IFwiLm5hdi10YWJzXCIsIGNvbnRlbnRTZWxlY3RvcjogXCIudGFiLWNvbnRlbnRcIiwgaW5pdGlhbDogXCJzY2VuZS1rZXlzXCIgfV1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN0YXRpYyBhc3luYyBJbml0aWFsaXplKCkge1xuICAgICAgICBJdGVtcy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc0Nsb2NrS2VlcGVyU2hlZXQsIHsgdHlwZXM6IFtcImNsb2NrX2tlZXBlclwiXSwgbWFrZURlZmF1bHQ6IHRydWUgfSk7XG4gICAgICAgIHJldHVybiBsb2FkVGVtcGxhdGVzKFtcbiAgICAgICAgICAgIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2l0ZW1zL2Nsb2NrX2tlZXBlci1zaGVldC5oYnNcIlxuICAgICAgICBdKTtcbiAgICB9XG4gICAgZ2V0RGF0YSgpIHtcbiAgICAgICAgY29uc3QgY29udGV4dCA9IHN1cGVyLmdldERhdGEoKTtcbiAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge1xuICAgICAgICAgICAgY3VycmVudFNjZW5lOiBnYW1lLnNjZW5lcy5jdXJyZW50LmlkLFxuICAgICAgICAgICAgdGFyZ2V0U2NlbmU6IHRoaXMuaXRlbS50YXJnZXRTY2VuZUlELFxuICAgICAgICAgICAgc2NlbmVPcHRpb25zOiBBcnJheS5mcm9tKGdhbWUuc2NlbmVzKSxcbiAgICAgICAgICAgIHNjZW5lS2V5czogdGhpcy5pdGVtLmdldFNjZW5lS2V5cyh0aGlzLml0ZW0uc3lzdGVtLnRhcmdldFNjZW5lID8/IGdhbWUuc2NlbmVzLmN1cnJlbnQuaWQpLFxuICAgICAgICAgICAgcGNzV2l0aFByb2plY3RzOiBCbGFkZXNQQy5BbGwuZmlsdGVyKChwYykgPT4gcGMucHJvamVjdHMubGVuZ3RoID4gMCksXG4gICAgICAgICAgICBmYWN0aW9uczogQXJyYXkuZnJvbShCbGFkZXNGYWN0aW9uLkFsbClcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHsgLi4uY29udGV4dCwgLi4uc2hlZXREYXRhIH07XG4gICAgfVxuICAgIGFkZEtleShldmVudCkge1xuICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB0aGlzLml0ZW0uYWRkQ2xvY2tLZXkoKTtcbiAgICB9XG4gICAgZGVsZXRlS2V5KGV2ZW50KSB7XG4gICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgIGNvbnN0IGtleUlEID0gZXZlbnQuY3VycmVudFRhcmdldC5kYXRhc2V0LmlkO1xuICAgICAgICBpZiAoa2V5SUQpIHtcbiAgICAgICAgICAgIHRoaXMuaXRlbS5kZWxldGVDbG9ja0tleShrZXlJRCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgc2V0U2VsZWN0Q29sb3Ioc2VsZWN0JCwgdmFsdWUpIHtcbiAgICAgICAgdmFsdWUgPz89IHNlbGVjdCQuZGF0YShcInZhbHVlXCIpO1xuICAgICAgICBzd2l0Y2ggKHZhbHVlKSB7XG4gICAgICAgICAgICBjYXNlIENsb2NrQ29sb3IueWVsbG93OiB7XG4gICAgICAgICAgICAgICAgVS5nc2FwLnNldChzZWxlY3QkLCB7XG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBcInZhcigtLWJsYWRlcy1ibGFjaylcIixcbiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogXCJ2YXIoLS1ibGFkZXMtZ29sZC1icmlnaHQpXCIsXG4gICAgICAgICAgICAgICAgICAgIHRleHRTaGFkb3c6IFwibm9uZVwiXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrQ29sb3IucmVkOiB7XG4gICAgICAgICAgICAgICAgVS5nc2FwLnNldChzZWxlY3QkLCB7XG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBcInZhcigtLWJsYWRlcy13aGl0ZSlcIixcbiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogXCJ2YXIoLS1ibGFkZXMtcmVkKVwiXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlIENsb2NrQ29sb3IuY3lhbjoge1xuICAgICAgICAgICAgICAgIFUuZ3NhcC5zZXQoc2VsZWN0JCwge1xuICAgICAgICAgICAgICAgICAgICBjb2xvcjogXCJ2YXIoLS1ibGFkZXMtYmxhY2spXCIsXG4gICAgICAgICAgICAgICAgICAgIGJhY2tncm91bmQ6IFwidmFyKC0tYmxhZGVzLWJsdWUtYnJpZ2h0KVwiLFxuICAgICAgICAgICAgICAgICAgICB0ZXh0U2hhZG93OiBcIm5vbmVcIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FzZSBDbG9ja0NvbG9yLndoaXRlOiB7XG4gICAgICAgICAgICAgICAgVS5nc2FwLnNldChzZWxlY3QkLCB7XG4gICAgICAgICAgICAgICAgICAgIGNvbG9yOiBcInZhcigtLWJsYWRlcy1ibGFjaylcIixcbiAgICAgICAgICAgICAgICAgICAgYmFja2dyb3VuZDogXCJ2YXIoLS1ibGFkZXMtd2hpdGUpXCIsXG4gICAgICAgICAgICAgICAgICAgIHRleHRTaGFkb3c6IFwibm9uZVwiXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBkZWZhdWx0OiBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICBhc3luYyBhY3RpdmF0ZUxpc3RlbmVycyhodG1sKSB7XG4gICAgICAgIGF3YWl0IHN1cGVyLmFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpO1xuICAgICAgICAvLyAqKiogQ1JFQVRFIENMT0NLIEtFWSAqKiogflxuICAgICAgICBodG1sLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcImNyZWF0ZS1jbG9jay1rZXlcXFwiXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuaXRlbS5hZGRDbG9ja0tleSgpO1xuICAgICAgICAgICAgICAgIC8vIE5vdGlmeSBHTVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gI3JlZ2lvbiBIZWxwZXIgRnVuY3Rpb25zIHRvIFJldHJpZXZlIENsb2NrIEtleXMgJiBDbG9ja3MgflxuICAgICAgICBmdW5jdGlvbiBnZXRDbG9ja0tleUZyb21FdmVudChldmVudCkge1xuICAgICAgICAgICAgY29uc3QgaWQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJrZXlJZFwiKVxuICAgICAgICAgICAgICAgIHx8ICQoZXZlbnQuY3VycmVudFRhcmdldCkuY2xvc2VzdChcIi5jb250cm9sLWZsaXBwZXJcIikuZGF0YShcImNsb2NrS2V5SWRcIik7XG4gICAgICAgICAgICBpZiAoIWlkKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gaWQgZm91bmQgb24gZWxlbWVudFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IGNsb2NrS2V5ID0gZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cy5nZXQoaWQpO1xuICAgICAgICAgICAgaWYgKCFjbG9ja0tleSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2xvY2sga2V5IHdpdGggaWQgJHtpZH0gbm90IGZvdW5kYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gY2xvY2tLZXk7XG4gICAgICAgIH1cbiAgICAgICAgZnVuY3Rpb24gZ2V0Q2xvY2tGcm9tRXZlbnQoZXZlbnQpIHtcbiAgICAgICAgICAgIGNvbnN0IGNsb2NrS2V5ID0gZ2V0Q2xvY2tLZXlGcm9tRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgY29uc3QgY2xvY2tJRCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShcImNsb2NrSWRcIilcbiAgICAgICAgICAgICAgICB8fCAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmNsb3Nlc3QoXCIuY29udHJvbC1mbGlwcGVyXCIpLmRhdGEoXCJjbG9ja0lkXCIpO1xuICAgICAgICAgICAgaWYgKCFjbG9ja0lEKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiTm8gY2xvY2tJRCBmb3VuZCBvbiBlbGVtZW50XCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgY2xvY2sgPSBjbG9ja0tleS5nZXRDbG9ja0J5SUQoY2xvY2tJRCk7XG4gICAgICAgICAgICBpZiAoIWNsb2NrKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBDbG9jayB3aXRoIGlkICR7Y2xvY2tJRH0gbm90IGZvdW5kYCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gW2Nsb2NrS2V5LCBjbG9ja107XG4gICAgICAgIH1cbiAgICAgICAgLy8gI2VuZHJlZ2lvblxuICAgICAgICAvLyAjcmVnaW9uIEluaXRpYWxpemluZyBGbGlwIENvbnRyb2wgUGFuZWxzIH5cbiAgICAgICAgLy8gY29uc3QgZmxpcENvbnRyb2xzJCA9IGh0bWwuZmluZChcIi5jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgIC8vIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAvLyAgIFUuZ3NhcC5zZXQoZmxpcENvbnRyb2xzJC5maW5kKFwiLmNvbnRyb2xzLWJhY2tcIiksIHtcbiAgICAgICAgLy8gICAgIHRyYW5zbGF0ZVo6IC0yLFxuICAgICAgICAvLyAgICAgcm90YXRlWDogMTgwLFxuICAgICAgICAvLyAgICAgYXV0b0FscGhhOiAxXG4gICAgICAgIC8vICAgfSk7XG4gICAgICAgIC8vICAgVS5nc2FwLnNldChmbGlwQ29udHJvbHMkLmZpbmQoXCIuY29udHJvbHMtZnJvbnRcIiksIHtcbiAgICAgICAgLy8gICAgIHRyYW5zbGF0ZVo6IDIsXG4gICAgICAgIC8vICAgICBhdXRvQWxwaGE6IDFcbiAgICAgICAgLy8gICB9KTtcbiAgICAgICAgLy8gICBVLmdzYXAuc2V0KGh0bWwuZmluZChcIi5jb250cm9sLWZsaXBwZXIuY29udHJvbHMtZmxpcHBlZFwiKSwge1xuICAgICAgICAvLyAgICAgcm90YXRlWDogMTgwXG4gICAgICAgIC8vICAgfSk7XG4gICAgICAgIC8vIH0sIDUwMCk7XG4gICAgICAgIC8vICNlbmRyZWdpb25cbiAgICAgICAgLy8gI3JlZ2lvbiAqKiogQ0xPQ0sgS0VZUyAqKiogflxuICAgICAgICBjb25zdCBjbG9ja0tleUNvbnRyb2xzJCA9IGh0bWwuZmluZChcIi5jbG9jay1rZXktY29udHJvbC1mbGlwcGVyXCIpO1xuICAgICAgICAvLyAjcmVnaW9uIGlzT25EaXNwbGF5ID09PSBUUlVFIE9SIEZBTFNFIChDb25kaXRpb25hbCBBbmltYXRpb24gQ2hlY2tzIFJlcXVpcmVkKSB+XG4gICAgICAgIGNsb2NrS2V5Q29udHJvbHMkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInRvZ2dsZS1uYW1lLXZpc2liaWxpdHlcXFwiXVwiKVxuICAgICAgICAgICAgLmVhY2goKGksIGVsZW0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW0kID0gJChlbGVtKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRyb2wkID0gZWxlbSQuY2xvc2VzdChcIi5jbG9jay1rZXktY29udHJvbC1mbGlwcGVyXCIpO1xuICAgICAgICAgICAgZWxlbSQub24oe1xuICAgICAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgY2xvY2tLZXkgPSBnZXRDbG9ja0tleUZyb21FdmVudChldmVudCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzTmFtZVZpc2libGUgPSAhY2xvY2tLZXkuaXNOYW1lVmlzaWJsZTtcbiAgICAgICAgICAgICAgICAgICAgY2xvY2tLZXkudXBkYXRlVGFyZ2V0KFwiaXNOYW1lVmlzaWJsZVwiLCBpc05hbWVWaXNpYmxlKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgY2xvY2tLZXkgaXMgb24gZGlzcGxheSAoaW4gc2NlbmUgJiB2aXNpYmxlKSwgc2VudCBvdXQgYW5pbWF0aW9uIHNvY2tldCBjYWxsc1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2xvY2tLZXkuaXNJblNjZW5lKCkgJiYgY2xvY2tLZXkuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNOYW1lVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrS2V5LmZhZGVJbk5hbWVfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2tLZXkuZmFkZU91dE5hbWVfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIFRvZ2dsZSBjbGFzcyBuYW1lcyBvbiBpY29uXG4gICAgICAgICAgICAgICAgICAgIGNvbnRyb2wkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInRvZ2dsZS1uYW1lLXZpc2liaWxpdHlcXFwiXSBpXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1zaWduYXR1cmVcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXNpZ25hdHVyZS1zbGFzaFwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtc29saWRcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXJlZ3VsYXJcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBjbG9ja0tleUNvbnRyb2xzJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJ0b2dnbGUtc3BvdGxpZ2h0XFxcIl1cIilcbiAgICAgICAgICAgIC5lYWNoKChpLCBlbGVtKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBlbGVtJCA9ICQoZWxlbSk7XG4gICAgICAgICAgICBjb25zdCBjb250cm9sJCA9IGVsZW0kLmNsb3Nlc3QoXCIuY2xvY2sta2V5LWNvbnRyb2wtZmxpcHBlclwiKTtcbiAgICAgICAgICAgIGVsZW0kLm9uKHtcbiAgICAgICAgICAgICAgICBjbGljazogYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNsb2NrS2V5ID0gZ2V0Q2xvY2tLZXlGcm9tRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpc1Nwb3RsaXQgPSAhY2xvY2tLZXkuaXNTcG90bGl0O1xuICAgICAgICAgICAgICAgICAgICBjbG9ja0tleS51cGRhdGVUYXJnZXQoXCJpc1Nwb3RsaXRcIiwgaXNTcG90bGl0KTtcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgY2xvY2tLZXkgaXMgb24gZGlzcGxheSAoaW4gc2NlbmUgJiB2aXNpYmxlKSwgc2VudCBvdXQgYW5pbWF0aW9uIHNvY2tldCBjYWxsc1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2xvY2tLZXkuaXNJblNjZW5lKCkgJiYgY2xvY2tLZXkuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNTcG90bGl0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2xvY2tLZXkudW5zcG90bGlnaHRfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2xvY2tLZXkuc3BvdGxpZ2h0X1NvY2tldENhbGwoQ2xvY2tEaXNwbGF5Q29udGV4dC5vdmVybGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBUb2dnbGUgY2xhc3MgbmFtZXMgb24gaWNvblxuICAgICAgICAgICAgICAgICAgICBjb250cm9sJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJ0b2dnbGUtc3BvdGxpZ2h0XFxcIl0gaVwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtbWVzc2FnZVwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtbWVzc2FnZS1zbGFzaFwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtc29saWRcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXJlZ3VsYXJcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyAjZW5kcmVnaW9uXG4gICAgICAgIC8vICNyZWdpb24gaXNPbkRpc3BsYXkgPT09IFRSVUUgflxuICAgICAgICBjbG9ja0tleUNvbnRyb2xzJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJwdWxsLWNsb2NrLWtleVxcXCJdXCIpXG4gICAgICAgICAgICAuZWFjaCgoaSwgZWxlbSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbSQgPSAkKGVsZW0pO1xuICAgICAgICAgICAgY29uc3QgY29udHJvbCQgPSBlbGVtJC5jbG9zZXN0KFwiLmNsb2NrLWtleS1jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgICAgICBlbGVtJC5vbih7XG4gICAgICAgICAgICAgICAgY2xpY2s6IChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBVLmdzYXAuZWZmZWN0cy5rZXlDb250cm9sUGFuZWxGbGlwKGNvbnRyb2wkLCB7IGFuZ2xlOiAxODAgfSk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNsb2NrS2V5ID0gZ2V0Q2xvY2tLZXlGcm9tRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICBjbG9ja0tleS51cGRhdGVUYXJnZXQoXCJpc1Zpc2libGVcIiwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IucHVsbEtleV9Tb2NrZXRDYWxsKGNsb2NrS2V5LmlkKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vICNlbmRyZWdpb25cbiAgICAgICAgLy8gI3JlZ2lvbiBpc09uRGlzcGxheSA9PT0gRkFMU0UgflxuICAgICAgICBjbG9ja0tleUNvbnRyb2xzJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJkcm9wLWNsb2NrLWtleVxcXCJdXCIpXG4gICAgICAgICAgICAuZWFjaCgoaSwgZWxlbSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbSQgPSAkKGVsZW0pO1xuICAgICAgICAgICAgY29uc3QgY29udHJvbCQgPSBlbGVtJC5jbG9zZXN0KFwiLmNsb2NrLWtleS1jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgICAgICBlbGVtJC5vbih7XG4gICAgICAgICAgICAgICAgY2xpY2s6IChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBVLmdzYXAuZWZmZWN0cy5rZXlDb250cm9sUGFuZWxGbGlwKGNvbnRyb2wkLCB7IGFuZ2xlOiAwIH0pO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBjbG9ja0tleSA9IGdldENsb2NrS2V5RnJvbUV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgY2xvY2tLZXkudXBkYXRlVGFyZ2V0KFwiaXNWaXNpYmxlXCIsIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBnYW1lLmV1bm9ibGFkZXMuRGlyZWN0b3IucmVuZGVyQ2xvY2tLZXlfU29ja2V0Q2FsbChjbG9ja0tleS5pZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICBjbG9ja0tleUNvbnRyb2xzJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJzcGF3bi1wb3NpdGlvbi1kcmFnZ2VyXFxcIl1cIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgY29uc3QgY2xvY2tLZXkgPSBnZXRDbG9ja0tleUZyb21FdmVudChldmVudCk7XG4gICAgICAgICAgICAgICAgY2xvY2tLZXkuc3Bhd25Qb3NpdGlvbkRyYWdnZXIoZ2FtZS5ldW5vYmxhZGVzLkRpcmVjdG9yLmNsb2NrS2V5U2VjdGlvbiQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgY2xvY2tLZXlDb250cm9scyQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZGVsZXRlLWNsb2NrLWtleVxcXCJdXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGdldENsb2NrS2V5RnJvbUV2ZW50KGV2ZW50KS5kZWxldGUoZ2FtZS5ldW5vYmxhZGVzLkNsb2NrS2V5cyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICBjbG9ja0tleUNvbnRyb2xzJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJhZGQta2V5LXRvLXNjZW5lXFxcIl1cIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgZ2V0Q2xvY2tLZXlGcm9tRXZlbnQoZXZlbnQpLmFkZFRvU2NlbmUodGhpcy5kb2N1bWVudC50YXJnZXRTY2VuZUlEKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGNsb2NrS2V5Q29udHJvbHMkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInJlbW92ZS1rZXktZnJvbS1zY2VuZVxcXCJdXCIpLm9uKHtcbiAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGF3YWl0IGdldENsb2NrS2V5RnJvbUV2ZW50KGV2ZW50KS5yZW1vdmVGcm9tU2NlbmUodGhpcy5kb2N1bWVudC50YXJnZXRTY2VuZUlEKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGNsb2NrS2V5Q29udHJvbHMkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcImFkZC1jbG9jay10by1rZXlcXFwiXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBhd2FpdCBnZXRDbG9ja0tleUZyb21FdmVudChldmVudCkuYWRkQ2xvY2soKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIGNsb2NrS2V5Q29udHJvbHMkLmZpbmQoXCJpbnB1dC5jbG9jay1rZXktaW5wdXQ6bm90KFtyZWFkb25seV0pXCIpLm9uKHtcbiAgICAgICAgICAgIGNoYW5nZTogYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBjb25zdCBpbnB1dCQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IGlucHV0VmFsID0gaW5wdXQkLnZhbCgpO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXRWYWwgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgZ2V0Q2xvY2tLZXlGcm9tRXZlbnQoZXZlbnQpLnVwZGF0ZVRhcmdldChpbnB1dCQuZGF0YShcInRhcmdldFByb3BcIiksIGlucHV0VmFsKTtcbiAgICAgICAgICAgICAgICAgICAgY2xvY2tLZXlDb250cm9scyQuZmluZChcImlucHV0LmNsb2NrLWtleS1pbnB1dFwiKS52YWwoaW5wdXRWYWwpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8vICNlbmRyZWdpb25cbiAgICAgICAgLy8gI2VuZHJlZ2lvblxuICAgICAgICAvLyAjcmVnaW9uICoqKiBDTE9DS1MgKioqIH5cbiAgICAgICAgY29uc3QgY2xvY2tDb250cm9scyQgPSBodG1sLmZpbmQoXCIuY2xvY2stY29udHJvbC1mbGlwcGVyXCIpO1xuICAgICAgICAvLyAjcmVnaW9uIGlzT25EaXNwbGF5ID09PSBUUlVFIE9SIEZBTFNFIChDb25kaXRpb25hbCBBbmltYXRpb24gQ2hlY2tzIFJlcXVpcmVkKSB+XG4gICAgICAgIGNsb2NrQ29udHJvbHMkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInRvZ2dsZS12aXNpYmxlXFxcIl1cIilcbiAgICAgICAgICAgIC5lYWNoKChpLCBlbGVtKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBlbGVtJCA9ICQoZWxlbSk7XG4gICAgICAgICAgICBjb25zdCBjb250cm9sJCA9IGVsZW0kLmNsb3Nlc3QoXCIuY2xvY2stY29udHJvbC1mbGlwcGVyXCIpO1xuICAgICAgICAgICAgZWxlbSQub24oe1xuICAgICAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgW2Nsb2NrS2V5LCBjbG9ja10gPSBnZXRDbG9ja0Zyb21FdmVudChldmVudCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGlzVmlzaWJsZSA9ICFjbG9jay5pc1Zpc2libGU7XG4gICAgICAgICAgICAgICAgICAgIGNsb2NrLnVwZGF0ZVRhcmdldChcImlzVmlzaWJsZVwiLCBpc1Zpc2libGUpO1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiBjbG9jayBrZXkgaXMgb24gZGlzcGxheSAoaW4gc2NlbmUgJiB2aXNpYmxlKSwgc2VudCBvdXQgYW5pbWF0aW9uIHNvY2tldCBjYWxsc1xuICAgICAgICAgICAgICAgICAgICBpZiAoY2xvY2tLZXkuaXNJblNjZW5lKCkgJiYgY2xvY2tLZXkuaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoaXNWaXNpYmxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2sucmV2ZWFsX1NvY2tldENhbGwoQ2xvY2tEaXNwbGF5Q29udGV4dC5vdmVybGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrLmhpZGVfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIC8vIFRvZ2dsZSBjbGFzcyBuYW1lcyBvbiBpY29uXG4gICAgICAgICAgICAgICAgICAgIGNvbnRyb2wkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInRvZ2dsZS12aXNpYmxlXFxcIl0gaVwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtZXllXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1leWUtc2xhc2hcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXNvbGlkXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1yZWd1bGFyXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgY2xvY2tDb250cm9scyQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwidG9nZ2xlLWFjdGl2ZVxcXCJdXCIpXG4gICAgICAgICAgICAuZWFjaCgoaSwgZWxlbSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbSQgPSAkKGVsZW0pO1xuICAgICAgICAgICAgY29uc3QgY29udHJvbCQgPSBlbGVtJC5jbG9zZXN0KFwiLmNsb2NrLWNvbnRyb2wtZmxpcHBlclwiKTtcbiAgICAgICAgICAgIGVsZW0kLm9uKHtcbiAgICAgICAgICAgICAgICBjbGljazogYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IFtjbG9ja0tleSwgY2xvY2tdID0gZ2V0Q2xvY2tGcm9tRXZlbnQoZXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpc0FjdGl2ZSA9ICFjbG9jay5pc0FjdGl2ZTtcbiAgICAgICAgICAgICAgICAgICAgY2xvY2sudXBkYXRlVGFyZ2V0KFwiaXNBY3RpdmVcIiwgaXNBY3RpdmUpO1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiBjbG9jayBBTkQgY2xvY2sga2V5IGlzIG9uIGRpc3BsYXkgKGluIHNjZW5lICYgdmlzaWJsZSksIHNlbnQgb3V0IGFuaW1hdGlvbiBzb2NrZXQgY2FsbHNcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNsb2NrLnBhcmVudEtleS5pc0luU2NlbmUoKSAmJiBjbG9jay5wYXJlbnRLZXkuaXNWaXNpYmxlICYmIGNsb2NrLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzQWN0aXZlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2suYWN0aXZhdGVfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2suZGVhY3RpdmF0ZV9Tb2NrZXRDYWxsKENsb2NrRGlzcGxheUNvbnRleHQub3ZlcmxheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gVG9nZ2xlIGNsYXNzIG5hbWVzIG9uIGljb25cbiAgICAgICAgICAgICAgICAgICAgY29udHJvbCQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwidG9nZ2xlLWFjdGl2ZVxcXCJdIGlcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLWJvbHRcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLWJvbHQtc2xhc2hcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXNvbGlkXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1yZWd1bGFyXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgY2xvY2tDb250cm9scyQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwidG9nZ2xlLW5hbWUtdmlzaWJpbGl0eVxcXCJdXCIpXG4gICAgICAgICAgICAuZWFjaCgoaSwgZWxlbSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbSQgPSAkKGVsZW0pO1xuICAgICAgICAgICAgY29uc3QgY29udHJvbCQgPSBlbGVtJC5jbG9zZXN0KFwiLmNsb2NrLWNvbnRyb2wtZmxpcHBlclwiKTtcbiAgICAgICAgICAgIGVsZW0kLm9uKHtcbiAgICAgICAgICAgICAgICBjbGljazogYXN5bmMgKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGNsb2NrID0gZ2V0Q2xvY2tGcm9tRXZlbnQoZXZlbnQpWzFdO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBpc05hbWVWaXNpYmxlID0gIWNsb2NrLmlzTmFtZVZpc2libGU7XG4gICAgICAgICAgICAgICAgICAgIGNsb2NrLnVwZGF0ZVRhcmdldChcImlzTmFtZVZpc2libGVcIiwgaXNOYW1lVmlzaWJsZSk7XG4gICAgICAgICAgICAgICAgICAgIC8vIElmIGNsb2NrIGlzIG9uIGRpc3BsYXkgKGluIHNjZW5lICYgdmlzaWJsZSksIHNlbnQgb3V0IGFuaW1hdGlvbiBzb2NrZXQgY2FsbHNcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNsb2NrLnBhcmVudEtleS5pc0luU2NlbmUoKSAmJiBjbG9jay5wYXJlbnRLZXkuaXNWaXNpYmxlICYmIGNsb2NrLmlzVmlzaWJsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzTmFtZVZpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbG9jay5mYWRlSW5DbG9ja05hbWVfU29ja2V0Q2FsbChDbG9ja0Rpc3BsYXlDb250ZXh0Lm92ZXJsYXkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2suZmFkZU91dENsb2NrTmFtZV9Tb2NrZXRDYWxsKENsb2NrRGlzcGxheUNvbnRleHQub3ZlcmxheSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gVG9nZ2xlIGNsYXNzIG5hbWVzIG9uIGljb25cbiAgICAgICAgICAgICAgICAgICAgY29udHJvbCQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwidG9nZ2xlLW5hbWUtdmlzaWJpbGl0eVxcXCJdIGlcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXNpZ25hdHVyZVwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtc2lnbmF0dXJlLXNsYXNoXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1zb2xpZFwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtcmVndWxhclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIGNsb2NrQ29udHJvbHMkLmZpbmQoXCJbZGF0YS1hY3Rpb249XFxcInRvZ2dsZS1oaWdobGlnaHRcXFwiXVwiKVxuICAgICAgICAgICAgLmVhY2goKGksIGVsZW0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW0kID0gJChlbGVtKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRyb2wkID0gZWxlbSQuY2xvc2VzdChcIi5jbG9jay1jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgICAgICBlbGVtJC5vbih7XG4gICAgICAgICAgICAgICAgY2xpY2s6IGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBbY2xvY2tLZXksIGNsb2NrXSA9IGdldENsb2NrRnJvbUV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaXNIaWdobGlnaHRlZCA9ICFjbG9jay5pc0hpZ2hsaWdodGVkO1xuICAgICAgICAgICAgICAgICAgICBjbG9jay51cGRhdGVUYXJnZXQoXCJpc0hpZ2hsaWdodGVkXCIsIGlzSGlnaGxpZ2h0ZWQpO1xuICAgICAgICAgICAgICAgICAgICAvLyBJZiBjbG9jayBpcyBvbiBkaXNwbGF5IChpbiBzY2VuZSAmIHZpc2libGUpLCBzZW50IG91dCBhbmltYXRpb24gc29ja2V0IGNhbGxzXG4gICAgICAgICAgICAgICAgICAgIGlmIChjbG9jay5wYXJlbnRLZXkuaXNJblNjZW5lKCkgJiYgY2xvY2sucGFyZW50S2V5LmlzVmlzaWJsZSAmJiBjbG9jay5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChpc0hpZ2hsaWdodGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2suaGlnaGxpZ2h0X1NvY2tldENhbGwoQ2xvY2tEaXNwbGF5Q29udGV4dC5vdmVybGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrLnVuaGlnaGxpZ2h0X1NvY2tldENhbGwoQ2xvY2tEaXNwbGF5Q29udGV4dC5vdmVybGF5KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBUb2dnbGUgY2xhc3MgbmFtZXMgb24gaWNvblxuICAgICAgICAgICAgICAgICAgICBjb250cm9sJC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJ0b2dnbGUtaGlnaGxpZ2h0XFxcIl0gaVwiKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnRvZ2dsZUNsYXNzKFwiZmEtbGlnaHRidWxiXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1saWdodGJ1bGItc2xhc2hcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIC50b2dnbGVDbGFzcyhcImZhLXNvbGlkXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAudG9nZ2xlQ2xhc3MoXCJmYS1yZWd1bGFyXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gI2VuZHJlZ2lvblxuICAgICAgICAvLyAjcmVnaW9uIGlzT25EaXNwbGF5ID09PSBUUlVFIH5cbiAgICAgICAgY2xvY2tDb250cm9scyQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiY2hhbmdlLXNlZ21lbnRzXFxcIl1cIilcbiAgICAgICAgICAgIC5lYWNoKChpLCBlbGVtKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBlbGVtJCA9ICQoZWxlbSk7XG4gICAgICAgICAgICBjb25zdCBjb250cm9sJCA9IGVsZW0kLmNsb3Nlc3QoXCIuY2xvY2stY29udHJvbC1mbGlwcGVyXCIpO1xuICAgICAgICAgICAgZWxlbSQub24oe1xuICAgICAgICAgICAgICAgIGNsaWNrOiBhc3luYyAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgW2Nsb2NrS2V5LCBjbG9ja10gPSBnZXRDbG9ja0Zyb21FdmVudChldmVudCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRlbHRhID0gVS5wSW50KCQoZXZlbnQuY3VycmVudFRhcmdldCkuZGF0YShcInZhbHVlXCIpKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgZmluYWxWYWwgPSBVLmdzYXAudXRpbHMuY2xhbXAoMCwgY2xvY2subWF4LCBjbG9jay52YWx1ZSArIGRlbHRhKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGRlbHRhID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2xvY2suZmlsbFNlZ21lbnRzKGRlbHRhLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNsb2NrLmNsZWFyU2VnbWVudHMoTWF0aC5hYnMoZGVsdGEpLCB0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb250cm9sJC5maW5kKFwic2VsZWN0LmNsb2NrLXNlbGVjdC12YWx1ZVwiKS52YWwoZmluYWxWYWwpO1xuICAgICAgICAgICAgICAgICAgICBjbG9jay5jaGFuZ2VTZWdtZW50c19Tb2NrZXRDYWxsKENsb2NrRGlzcGxheUNvbnRleHQub3ZlcmxheSwgY2xvY2sudmFsdWUsIGZpbmFsVmFsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vICNlbmRyZWdpb25cbiAgICAgICAgLy8gI3JlZ2lvbiBpc09uRGlzcGxheSA9PT0gRkFMU0UgflxuICAgICAgICBjbG9ja0NvbnRyb2xzJC5maW5kKFwic2VsZWN0LmNsb2NrLWNvbnRyb2wtc2VsZWN0XCIpXG4gICAgICAgICAgICAuZWFjaCgoaSwgZWxlbSkgPT4ge1xuICAgICAgICAgICAgY29uc3QgZWxlbSQgPSAkKGVsZW0pO1xuICAgICAgICAgICAgaWYgKGVsZW0kLmhhc0NsYXNzKFwiY2xvY2stc2VsZWN0LWNvbG9yXCIpKSB7XG4gICAgICAgICAgICAgICAgLy8gdGhpcy5zZXRTZWxlY3RDb2xvcihlbGVtJCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICAgICAgICAub24oe1xuICAgICAgICAgICAgY2hhbmdlOiAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHNlbGVjdCQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gc2VsZWN0JC5kYXRhKFwiZHR5cGVcIikgPT09IFwibnVtYmVyXCJcbiAgICAgICAgICAgICAgICAgICAgPyBVLnBJbnQoc2VsZWN0JC52YWwoKSlcbiAgICAgICAgICAgICAgICAgICAgOiBzZWxlY3QkLnZhbCgpO1xuICAgICAgICAgICAgICAgIGNvbnN0IHByb3AgPSBzZWxlY3QkLmRhdGEoXCJ0YXJnZXRQcm9wXCIpO1xuICAgICAgICAgICAgICAgIGdldENsb2NrRnJvbUV2ZW50KGV2ZW50KVsxXS51cGRhdGVUYXJnZXQocHJvcCwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIGlmIChwcm9wID09PSBcImNvbG9yXCIgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmIHZhbHVlIGluIENsb2NrQ29sb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXRTZWxlY3RDb2xvcihzZWxlY3QkLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgY2xvY2tDb250cm9scyQuZmluZChcImlucHV0LmNsb2NrLWlucHV0Om5vdChbcmVhZG9ubHldKVwiKVxuICAgICAgICAgICAgLmVhY2goKGksIGVsZW0pID0+IHtcbiAgICAgICAgICAgIGNvbnN0IGVsZW0kID0gJChlbGVtKTtcbiAgICAgICAgICAgIGNvbnN0IGNvbnRyb2wkID0gZWxlbSQuY2xvc2VzdChcIi5jbG9jay1jb250cm9sLWZsaXBwZXJcIik7XG4gICAgICAgICAgICBlbGVtJC5vbih7XG4gICAgICAgICAgICAgICAgY2hhbmdlOiAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5wdXQkID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgaW5wdXRWYWwgPSBpbnB1dCQudmFsKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgaW5wdXRWYWwgPT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGdldENsb2NrRnJvbUV2ZW50KGV2ZW50KVsxXS51cGRhdGVUYXJnZXQoaW5wdXQkLmRhdGEoXCJ0YXJnZXRQcm9wXCIpLCBpbnB1dFZhbCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb250cm9sJC5maW5kKFwiaW5wdXQuY2xvY2staW5wdXRcIikudmFsKGlucHV0VmFsKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICAgICAgY2xvY2tDb250cm9scyQuZmluZChcIltkYXRhLWFjdGlvbj1cXFwiZGVsZXRlLWNsb2NrXFxcIl1cIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IGFzeW5jIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgYXdhaXQgZ2V0Q2xvY2tGcm9tRXZlbnQoZXZlbnQpWzFdLmRlbGV0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgLy8gI2VuZHJlZ2lvblxuICAgICAgICAvLyAjZW5kcmVnaW9uXG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzQ2xvY2tLZWVwZXJTaGVldDtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/sheets/item/BladesClockKeeperSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/item/BladesGMTrackerSheet.ts": +/*!************************************************!*\ + !*** ./ts/sheets/item/BladesGMTrackerSheet.ts ***! + \************************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesTipContext: function() { return /* binding */ BladesTipContext; },\n/* harmony export */ BladesTipGenerator: function() { return /* binding */ BladesTipGenerator; }\n/* harmony export */ });\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesItemSheet__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./BladesItemSheet */ \"./ts/sheets/item/BladesItemSheet.ts\");\n/* harmony import */ var _BladesActor__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../BladesActor */ \"./ts/BladesActor.ts\");\n/* harmony import */ var _documents_actors_BladesPC__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../documents/actors/BladesPC */ \"./ts/documents/actors/BladesPC.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\nvar BladesTipContext;\n(function (BladesTipContext) {\n BladesTipContext[\"DiceRoll\"] = \"DiceRoll\";\n BladesTipContext[\"Combat\"] = \"Combat\";\n BladesTipContext[\"General\"] = \"General\";\n})(BladesTipContext || (BladesTipContext = {}));\nclass BladesTipGenerator {\n static Test(pcActor) {\n if (_BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"].IsType(pcActor, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)) {\n return pcActor;\n }\n return undefined;\n }\n testActor = new _documents_actors_BladesPC__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({ name: \"blah\", type: \"pc\" });\n static get Tips() {\n return {\n [BladesTipContext.DiceRoll]: [],\n [BladesTipContext.Combat]: [\n \"Every combat encounter should advance the main plot, or else it's filler.\",\n \"Inject dialogue into combat encounters, especially from important adversaries.\",\n \"Combat encounters should be a challenge, but not a slog. Don't be afraid to end them early.\",\n \"Infiltrate/Rescue/Destroy: Use these as additional/secondary goals in combat encounters.\",\n \"Tell the next player in the initiative order that they're on deck.\",\n \"Don't trigger combats automatically: Use alternate objectives to incite the players to fight, giving them agency.\",\n \"Add another layer by drawing focus to collateral effects of the combat: a fire, a hostage, a collapsing building, innocents in danger\"\n ],\n [BladesTipContext.General]: [\n \"Rolling the dice always means SOMETHING happens.\",\n \"Jump straight to the action; don't waste time on establishing scenes or filler.\",\n \"Invoke elements of characters' backstories or beliefs to make any scene more personal.\"\n ]\n };\n }\n tipContext;\n constructor(tipContext) {\n this.tipContext = tipContext;\n }\n}\nclass BladesGMTrackerSheet extends _BladesItemSheet__WEBPACK_IMPORTED_MODULE_1__[\"default\"] {\n // static Get() { return game.eunoblades.Tracker as BladesGMTracker; }\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"item\", \"gm-tracker\"],\n template: \"systems/eunos-blades/templates/items/gm_tracker-sheet.hbs\",\n width: 700,\n height: 970\n });\n }\n static async Initialize() {\n Items.registerSheet(\"blades\", BladesGMTrackerSheet, { types: [\"gm_tracker\"], makeDefault: true });\n return loadTemplates([\n \"systems/eunos-blades/templates/items/gm_tracker-sheet.hbs\"\n ]);\n }\n async activateListeners(html) {\n super.activateListeners(html);\n }\n async _onSubmit(event, params = {}) {\n const prevPhase = this.item.system.phase;\n const submitData = await super._onSubmit(event, params);\n const newPhase = this.item.system.phase;\n let isForcingRender = true;\n if (prevPhase !== newPhase) {\n switch (prevPhase) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.CharGen: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Freeplay: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Score: {\n isForcingRender = false;\n game.actors.filter((actor) => _BladesActor__WEBPACK_IMPORTED_MODULE_2__[\"default\"].IsType(actor, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc))\n .forEach((actor) => actor.clearLoadout());\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Downtime: {\n break;\n }\n default: break;\n }\n switch (newPhase) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.CharGen: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Freeplay: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Score: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase.Downtime: {\n break;\n }\n default: break;\n }\n }\n if (isForcingRender) {\n game.actors.filter((actor) => actor.type === _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesActorType.pc)\n .forEach((actor) => actor.sheet?.render());\n }\n return submitData;\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesGMTrackerSheet);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvaXRlbS9CbGFkZXNHTVRyYWNrZXJTaGVldC50cyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7QUFBQTtBQUNvRTtBQUNwQjtBQUNKO0FBQ1c7QUFDaEQ7QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUMsNENBQTRDO0FBQzdDO0FBQ0E7QUFDQSxZQUFZLG9EQUFXLGlCQUFpQiw0REFBZTtBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQixrRUFBUSxHQUFHLDBCQUEwQjtBQUN6RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOENBQThDO0FBQzlDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQyx3REFBZTtBQUNsRCxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSw4REFBOEQsMENBQTBDO0FBQ3hHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0NBQXNDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBO0FBQ0EscUJBQXFCLHdEQUFXO0FBQ2hDO0FBQ0E7QUFDQSxxQkFBcUIsd0RBQVc7QUFDaEM7QUFDQSxrREFBa0Qsb0RBQVcsZUFBZSw0REFBZTtBQUMzRjtBQUNBO0FBQ0E7QUFDQSxxQkFBcUIsd0RBQVc7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBO0FBQ0EscUJBQXFCLHdEQUFXO0FBQ2hDO0FBQ0E7QUFDQSxxQkFBcUIsd0RBQVc7QUFDaEM7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx5REFBeUQsNERBQWU7QUFDeEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUFlLG9CQUFvQixFQUFDO0FBQ04iLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9zaGVldHMvaXRlbS9CbGFkZXNHTVRyYWNrZXJTaGVldC50cz85YTQzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qIGVzbGludC1kaXNhYmxlIEB0eXBlc2NyaXB0LWVzbGludC9uby11bnVzZWQtdmFycyAqL1xuaW1wb3J0IHsgQmxhZGVzQWN0b3JUeXBlLCBCbGFkZXNQaGFzZSB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IEJsYWRlc0l0ZW1TaGVldCBmcm9tIFwiLi9CbGFkZXNJdGVtU2hlZXRcIjtcbmltcG9ydCBCbGFkZXNBY3RvciBmcm9tIFwiLi4vLi4vQmxhZGVzQWN0b3JcIjtcbmltcG9ydCBCbGFkZXNQQyBmcm9tIFwiLi4vLi4vZG9jdW1lbnRzL2FjdG9ycy9CbGFkZXNQQ1wiO1xuZXhwb3J0IHZhciBCbGFkZXNUaXBDb250ZXh0O1xuKGZ1bmN0aW9uIChCbGFkZXNUaXBDb250ZXh0KSB7XG4gICAgQmxhZGVzVGlwQ29udGV4dFtcIkRpY2VSb2xsXCJdID0gXCJEaWNlUm9sbFwiO1xuICAgIEJsYWRlc1RpcENvbnRleHRbXCJDb21iYXRcIl0gPSBcIkNvbWJhdFwiO1xuICAgIEJsYWRlc1RpcENvbnRleHRbXCJHZW5lcmFsXCJdID0gXCJHZW5lcmFsXCI7XG59KShCbGFkZXNUaXBDb250ZXh0IHx8IChCbGFkZXNUaXBDb250ZXh0ID0ge30pKTtcbmNsYXNzIEJsYWRlc1RpcEdlbmVyYXRvciB7XG4gICAgc3RhdGljIFRlc3QocGNBY3Rvcikge1xuICAgICAgICBpZiAoQmxhZGVzQWN0b3IuSXNUeXBlKHBjQWN0b3IsIEJsYWRlc0FjdG9yVHlwZS5wYykpIHtcbiAgICAgICAgICAgIHJldHVybiBwY0FjdG9yO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgfVxuICAgIHRlc3RBY3RvciA9IG5ldyBCbGFkZXNQQyh7IG5hbWU6IFwiYmxhaFwiLCB0eXBlOiBcInBjXCIgfSk7XG4gICAgc3RhdGljIGdldCBUaXBzKCkge1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgW0JsYWRlc1RpcENvbnRleHQuRGljZVJvbGxdOiBbXSxcbiAgICAgICAgICAgIFtCbGFkZXNUaXBDb250ZXh0LkNvbWJhdF06IFtcbiAgICAgICAgICAgICAgICBcIkV2ZXJ5IGNvbWJhdCBlbmNvdW50ZXIgc2hvdWxkIGFkdmFuY2UgdGhlIG1haW4gcGxvdCwgb3IgZWxzZSBpdCdzIGZpbGxlci5cIixcbiAgICAgICAgICAgICAgICBcIkluamVjdCBkaWFsb2d1ZSBpbnRvIGNvbWJhdCBlbmNvdW50ZXJzLCBlc3BlY2lhbGx5IGZyb20gaW1wb3J0YW50IGFkdmVyc2FyaWVzLlwiLFxuICAgICAgICAgICAgICAgIFwiQ29tYmF0IGVuY291bnRlcnMgc2hvdWxkIGJlIGEgY2hhbGxlbmdlLCBidXQgbm90IGEgc2xvZy4gRG9uJ3QgYmUgYWZyYWlkIHRvIGVuZCB0aGVtIGVhcmx5LlwiLFxuICAgICAgICAgICAgICAgIFwiSW5maWx0cmF0ZS9SZXNjdWUvRGVzdHJveTogVXNlIHRoZXNlIGFzIGFkZGl0aW9uYWwvc2Vjb25kYXJ5IGdvYWxzIGluIGNvbWJhdCBlbmNvdW50ZXJzLlwiLFxuICAgICAgICAgICAgICAgIFwiVGVsbCB0aGUgbmV4dCBwbGF5ZXIgaW4gdGhlIGluaXRpYXRpdmUgb3JkZXIgdGhhdCB0aGV5J3JlIG9uIGRlY2suXCIsXG4gICAgICAgICAgICAgICAgXCJEb24ndCB0cmlnZ2VyIGNvbWJhdHMgYXV0b21hdGljYWxseTogVXNlIGFsdGVybmF0ZSBvYmplY3RpdmVzIHRvIGluY2l0ZSB0aGUgcGxheWVycyB0byBmaWdodCwgZ2l2aW5nIHRoZW0gYWdlbmN5LlwiLFxuICAgICAgICAgICAgICAgIFwiQWRkIGFub3RoZXIgbGF5ZXIgYnkgZHJhd2luZyBmb2N1cyB0byBjb2xsYXRlcmFsIGVmZmVjdHMgb2YgdGhlIGNvbWJhdDogYSBmaXJlLCBhIGhvc3RhZ2UsIGEgY29sbGFwc2luZyBidWlsZGluZywgaW5ub2NlbnRzIGluIGRhbmdlclwiXG4gICAgICAgICAgICBdLFxuICAgICAgICAgICAgW0JsYWRlc1RpcENvbnRleHQuR2VuZXJhbF06IFtcbiAgICAgICAgICAgICAgICBcIlJvbGxpbmcgdGhlIGRpY2UgYWx3YXlzIG1lYW5zIFNPTUVUSElORyBoYXBwZW5zLlwiLFxuICAgICAgICAgICAgICAgIFwiSnVtcCBzdHJhaWdodCB0byB0aGUgYWN0aW9uOyBkb24ndCB3YXN0ZSB0aW1lIG9uIGVzdGFibGlzaGluZyBzY2VuZXMgb3IgZmlsbGVyLlwiLFxuICAgICAgICAgICAgICAgIFwiSW52b2tlIGVsZW1lbnRzIG9mIGNoYXJhY3RlcnMnIGJhY2tzdG9yaWVzIG9yIGJlbGllZnMgdG8gbWFrZSBhbnkgc2NlbmUgbW9yZSBwZXJzb25hbC5cIlxuICAgICAgICAgICAgXVxuICAgICAgICB9O1xuICAgIH1cbiAgICB0aXBDb250ZXh0O1xuICAgIGNvbnN0cnVjdG9yKHRpcENvbnRleHQpIHtcbiAgICAgICAgdGhpcy50aXBDb250ZXh0ID0gdGlwQ29udGV4dDtcbiAgICB9XG59XG5jbGFzcyBCbGFkZXNHTVRyYWNrZXJTaGVldCBleHRlbmRzIEJsYWRlc0l0ZW1TaGVldCB7XG4gICAgLy8gc3RhdGljIEdldCgpIHsgcmV0dXJuIGdhbWUuZXVub2JsYWRlcy5UcmFja2VyIGFzIEJsYWRlc0dNVHJhY2tlcjsgfVxuICAgIHN0YXRpYyBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBmb3VuZHJ5LnV0aWxzLm1lcmdlT2JqZWN0KHN1cGVyLmRlZmF1bHRPcHRpb25zLCB7XG4gICAgICAgICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcIml0ZW1cIiwgXCJnbS10cmFja2VyXCJdLFxuICAgICAgICAgICAgdGVtcGxhdGU6IFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvdGVtcGxhdGVzL2l0ZW1zL2dtX3RyYWNrZXItc2hlZXQuaGJzXCIsXG4gICAgICAgICAgICB3aWR0aDogNzAwLFxuICAgICAgICAgICAgaGVpZ2h0OiA5NzBcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN0YXRpYyBhc3luYyBJbml0aWFsaXplKCkge1xuICAgICAgICBJdGVtcy5yZWdpc3RlclNoZWV0KFwiYmxhZGVzXCIsIEJsYWRlc0dNVHJhY2tlclNoZWV0LCB7IHR5cGVzOiBbXCJnbV90cmFja2VyXCJdLCBtYWtlRGVmYXVsdDogdHJ1ZSB9KTtcbiAgICAgICAgcmV0dXJuIGxvYWRUZW1wbGF0ZXMoW1xuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvaXRlbXMvZ21fdHJhY2tlci1zaGVldC5oYnNcIlxuICAgICAgICBdKTtcbiAgICB9XG4gICAgYXN5bmMgYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCkge1xuICAgICAgICBzdXBlci5hY3RpdmF0ZUxpc3RlbmVycyhodG1sKTtcbiAgICB9XG4gICAgYXN5bmMgX29uU3VibWl0KGV2ZW50LCBwYXJhbXMgPSB7fSkge1xuICAgICAgICBjb25zdCBwcmV2UGhhc2UgPSB0aGlzLml0ZW0uc3lzdGVtLnBoYXNlO1xuICAgICAgICBjb25zdCBzdWJtaXREYXRhID0gYXdhaXQgc3VwZXIuX29uU3VibWl0KGV2ZW50LCBwYXJhbXMpO1xuICAgICAgICBjb25zdCBuZXdQaGFzZSA9IHRoaXMuaXRlbS5zeXN0ZW0ucGhhc2U7XG4gICAgICAgIGxldCBpc0ZvcmNpbmdSZW5kZXIgPSB0cnVlO1xuICAgICAgICBpZiAocHJldlBoYXNlICE9PSBuZXdQaGFzZSkge1xuICAgICAgICAgICAgc3dpdGNoIChwcmV2UGhhc2UpIHtcbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLkNoYXJHZW46IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuRnJlZXBsYXk6IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuU2NvcmU6IHtcbiAgICAgICAgICAgICAgICAgICAgaXNGb3JjaW5nUmVuZGVyID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIGdhbWUuYWN0b3JzLmZpbHRlcigoYWN0b3IpID0+IEJsYWRlc0FjdG9yLklzVHlwZShhY3RvciwgQmxhZGVzQWN0b3JUeXBlLnBjKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC5mb3JFYWNoKChhY3RvcikgPT4gYWN0b3IuY2xlYXJMb2Fkb3V0KCkpO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2FzZSBCbGFkZXNQaGFzZS5Eb3dudGltZToge1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGVmYXVsdDogYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzd2l0Y2ggKG5ld1BoYXNlKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBCbGFkZXNQaGFzZS5DaGFyR2VuOiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLkZyZWVwbGF5OiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLlNjb3JlOiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLkRvd250aW1lOiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkZWZhdWx0OiBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNGb3JjaW5nUmVuZGVyKSB7XG4gICAgICAgICAgICBnYW1lLmFjdG9ycy5maWx0ZXIoKGFjdG9yKSA9PiBhY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUucGMpXG4gICAgICAgICAgICAgICAgLmZvckVhY2goKGFjdG9yKSA9PiBhY3Rvci5zaGVldD8ucmVuZGVyKCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdWJtaXREYXRhO1xuICAgIH1cbn1cbmV4cG9ydCBkZWZhdWx0IEJsYWRlc0dNVHJhY2tlclNoZWV0O1xuZXhwb3J0IHsgQmxhZGVzVGlwR2VuZXJhdG9yIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/sheets/item/BladesGMTrackerSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/item/BladesItemSheet.ts": +/*!*******************************************!*\ + !*** ./ts/sheets/item/BladesItemSheet.ts ***! + \*******************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_gsap__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../core/gsap */ \"./ts/core/gsap.ts\");\n/* harmony import */ var _BladesItem__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../BladesItem */ \"./ts/BladesItem.ts\");\n/* harmony import */ var _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../documents/BladesActiveEffect */ \"./ts/documents/BladesActiveEffect.ts\");\n/* harmony import */ var _core_tags__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../core/tags */ \"./ts/core/tags.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\n\n\n// import {ApplyClockListeners} from \"../../classes/BladesClocks\";\n/* eslint-enable @typescript-eslint/no-unused-vars */\n\nclass BladesItemSheet extends ItemSheet {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"item\"],\n width: 560,\n height: 500,\n tabs: [{ navSelector: \".sheet-tabs\", contentSelector: \".sheet-body\", initial: \"description\" }]\n });\n }\n /* -------------------------------------------- */\n // constructor(item: BladesItem, options: Partial = {}) {\n // options.classes = [...options.classes ?? [], \"eunos-blades\", \"sheet\", \"item\", item.type];\n // super(item, options);\n // }\n // override async getData() {\n getData() {\n const context = super.getData();\n const sheetData = {\n cssClass: this.item.type,\n editable: this.options.editable,\n isGM: (game.eunoblades.Tracker?.system.is_spoofing_player ? false : Boolean(game.user.isGM)),\n isEmbeddedItem: Boolean(this.item.parent),\n item: this.item,\n system: this.item.system,\n tierTotal: this.item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier) > 0 ? _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].romanizeNum(this.item.getFactorTotal(_core_constants__WEBPACK_IMPORTED_MODULE_0__.Factor.tier)) : \"0\",\n activeEffects: Array.from(this.item.effects)\n };\n const typedItemData = this._getTypedItemData[this.item.type];\n if (typedItemData) {\n return typedItemData({ ...context, ...sheetData });\n }\n return {\n ...context,\n ...sheetData\n };\n }\n _getTypedItemData = {\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ability)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.background]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.background)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.clock_keeper]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.clock_keeper)) {\n return undefined;\n }\n const sheetData = {\n phases: Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase)\n };\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert)) {\n return undefined;\n }\n context.tierTotal = this.item.system.quality > 0 ? _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].romanizeNum(this.item.system.quality) : \"0\";\n context.system.subtypes ??= {};\n context.system.elite_subtypes ??= {};\n const sheetData = {\n tierData: {\n class: \"comp-tier comp-vertical comp-teeth\",\n dotline: {\n data: this.item.system.tier,\n target: \"system.tier.value\",\n iconEmpty: \"dot-empty.svg\",\n iconEmptyHover: \"dot-empty-hover.svg\",\n iconFull: \"dot-full.svg\",\n iconFullHover: \"dot-full-hover.svg\"\n }\n }\n };\n sheetData.edgeData = Object.fromEntries(Object.values(context.system.edges ?? [])\n .filter((edge) => /[A-Za-z]/.test(edge))\n .map((edge) => [edge.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].EdgeTooltips[edge]]));\n sheetData.flawData = Object.fromEntries(Object.values(context.system.flaws ?? [])\n .filter((flaw) => /[A-Za-z]/.test(flaw))\n .map((flaw) => [flaw.trim(), _core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].FlawTooltips[flaw]]));\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert]: (context) => {\n const typedItemData = this._getTypedItemData[_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang];\n if (!typedItemData) {\n throw new Error(`No data for type ${this.item.type}`);\n }\n return typedItemData(context);\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_ability]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_ability)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_reputation]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_reputation)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_playbook)) {\n return undefined;\n }\n if (context.isGM) {\n const expClueData = {};\n [...Object.values(context.system.experience_clues ?? []).filter((clue) => /[A-Za-z]/.test(clue)), \" \"].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; });\n context.system.experience_clues = expClueData;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_upgrade]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.crew_upgrade)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.feature]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.feature)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gm_tracker]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gm_tracker)) {\n return undefined;\n }\n const sheetData = {\n phase: this.item.system.phase,\n phases: Object.values(_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesPhase)\n };\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.heritage]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.heritage)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.gear)) {\n return undefined;\n }\n const sheetData = {\n tierData: {\n class: \"comp-tier comp-vertical comp-teeth\",\n label: \"Quality\",\n labelClass: \"filled-label full-width\",\n dotline: {\n data: this.item.system.tier,\n target: \"system.tier.value\",\n iconEmpty: \"dot-empty.svg\",\n iconEmptyHover: \"dot-empty-hover.svg\",\n iconFull: \"dot-full.svg\",\n iconFullHover: \"dot-full-hover.svg\"\n }\n }\n };\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.playbook)) {\n return undefined;\n }\n if (context.isGM) {\n const expClueData = {};\n [...Object.values(context.system.experience_clues ?? []).filter((clue) => /[A-Za-z]/.test(clue)), \" \"].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; });\n context.system.experience_clues = expClueData;\n const gatherInfoData = {};\n [...Object.values(context.system.gather_info_questions ?? []).filter((question) => /[A-Za-z]/.test(question)), \" \"].forEach((question, i) => { gatherInfoData[(i + 1).toString()] = question; });\n context.system.gather_info_questions = gatherInfoData;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.preferred_op]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.preferred_op)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.stricture]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.stricture)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.vice)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.ritual)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.design)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.location]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.location)) {\n return undefined;\n }\n const sheetData = {};\n return {\n ...context,\n ...sheetData\n };\n },\n [_core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.score]: (context) => {\n if (!_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.score)) {\n return undefined;\n }\n return context;\n }\n };\n get template() {\n const pathComps = [\n \"systems/eunos-blades/templates/items\"\n ];\n if (_core_constants__WEBPACK_IMPORTED_MODULE_0__[\"default\"].SimpleItemTypes.includes(this.item.type)) {\n pathComps.push(\"simple-sheet.hbs\");\n }\n else {\n pathComps.push(`${this.item.type}-sheet.hbs`);\n }\n return pathComps.join(\"/\");\n }\n /* -------------------------------------------- */\n addDotlineListeners(html) {\n html.find(\".dotline\").each((__, elem) => {\n if ($(elem).hasClass(\"locked\")) {\n return;\n }\n const targetDoc = this.item;\n const targetField = $(elem).data(\"target\");\n const comp$ = $(elem).closest(\"comp\");\n const curValue = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(elem).data(\"value\"));\n $(elem)\n .find(\".dot\")\n .each((_, dot) => {\n $(dot).on(\"click\", (event) => {\n event.preventDefault();\n const thisValue = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(dot).data(\"value\"));\n if (thisValue !== curValue) {\n if (comp$.hasClass(\"comp-coins\")\n || comp$.hasClass(\"comp-stash\")) {\n _core_gsap__WEBPACK_IMPORTED_MODULE_2__[\"default\"].effects\n .fillCoins($(dot).prevAll(\".dot\"))\n .then(() => targetDoc.update({ [targetField]: thisValue }));\n }\n else {\n targetDoc.update({ [targetField]: thisValue });\n }\n }\n });\n $(dot).on(\"contextmenu\", (event) => {\n event.preventDefault();\n const thisValue = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(dot).data(\"value\")) - 1;\n if (thisValue !== curValue) {\n targetDoc.update({ [targetField]: thisValue });\n }\n });\n });\n });\n }\n async activateListeners(html) {\n await super.activateListeners(html);\n const self = this;\n _core_tags__WEBPACK_IMPORTED_MODULE_5__[\"default\"].InitListeners(html, this.item);\n (0,_core_gsap__WEBPACK_IMPORTED_MODULE_2__.ApplyTooltipAnimations)(html);\n // Everything below here is only needed if the sheet is editable\n if (!this.options.editable) {\n return;\n }\n // Add dotline functionality\n this.addDotlineListeners(html);\n // Harm Bar Functionality for Cohorts\n if (_BladesItem__WEBPACK_IMPORTED_MODULE_3__[\"default\"].IsType(this.item, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_expert, _core_constants__WEBPACK_IMPORTED_MODULE_0__.BladesItemType.cohort_gang)) {\n html.find(\"[data-harm-click]\").on({\n click: (event) => {\n event.preventDefault();\n const harmLevel = _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(event.currentTarget).data(\"harmClick\"));\n if (this.item.system.harm?.value !== harmLevel) {\n this.item.update({ \"system.harm.value\": harmLevel });\n }\n },\n contextmenu: (event) => {\n event.preventDefault();\n const harmLevel = Math.max(0, _core_utilities__WEBPACK_IMPORTED_MODULE_1__[\"default\"].pInt($(event.currentTarget).data(\"harmClick\")) - 1);\n if (this.item.system.harm?.value !== harmLevel) {\n this.item.update({ \"system.harm.value\": harmLevel });\n }\n }\n });\n }\n // This is a workaround until is being fixed in FoundryVTT.\n if (this.options.submitOnChange) {\n html.on(\"change\", \"textarea\", this._onChangeInput.bind(this)); // Use delegated listener on the form\n }\n html.find(\".effect-control\").on(\"click\", (ev) => {\n if (self.item.isOwned) {\n ui.notifications?.warn(game.i18n.localize(\"BITD.EffectWarning\"));\n return;\n }\n _documents_BladesActiveEffect__WEBPACK_IMPORTED_MODULE_4__[\"default\"].onManageActiveEffect(ev, self.item);\n });\n html.find(\"[data-action=\\\"toggle-turf-connection\\\"\").on(\"click\", this.toggleTurfConnection.bind(this));\n }\n toggleTurfConnection(event) {\n const button$ = $(event.currentTarget);\n const connector$ = button$.parent();\n const turfNum = parseInt(connector$.data(\"index\") ?? 0, 10);\n const turfDir = connector$.data(\"dir\");\n if (!turfNum || !turfDir) {\n return;\n }\n const toggleState = connector$.hasClass(\"no-connect\");\n const updateData = {\n [`system.turfs.${turfNum}.connects.${turfDir}`]: toggleState\n };\n const partner = connector$.data(\"partner\");\n if (typeof partner === \"string\" && /-/.test(partner)) {\n const [partnerNum, partnerDir] = partner.split(\"-\");\n updateData[`system.turfs.${partnerNum}.connects.${partnerDir}`] = toggleState;\n }\n this.item.update(updateData);\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesItemSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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QTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsV0FBVyxZQUFZLFdBQVc7QUFDekU7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrREFBZSxlQUFlLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9zaGVldHMvaXRlbS9CbGFkZXNJdGVtU2hlZXQudHM/M2VlZCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmltcG9ydCBDLCB7IEJsYWRlc0l0ZW1UeXBlLCBCbGFkZXNQaGFzZSwgRmFjdG9yIH0gZnJvbSBcIi4uLy4uL2NvcmUvY29uc3RhbnRzXCI7XG5pbXBvcnQgVSBmcm9tIFwiLi4vLi4vY29yZS91dGlsaXRpZXNcIjtcbmltcG9ydCBHLCB7IEFwcGx5VG9vbHRpcEFuaW1hdGlvbnMgfSBmcm9tIFwiLi4vLi4vY29yZS9nc2FwXCI7XG5pbXBvcnQgQmxhZGVzSXRlbSBmcm9tIFwiLi4vLi4vQmxhZGVzSXRlbVwiO1xuaW1wb3J0IEJsYWRlc0FjdGl2ZUVmZmVjdCBmcm9tIFwiLi4vLi4vZG9jdW1lbnRzL0JsYWRlc0FjdGl2ZUVmZmVjdFwiO1xuLy8gaW1wb3J0IHtBcHBseUNsb2NrTGlzdGVuZXJzfSBmcm9tIFwiLi4vLi4vY2xhc3Nlcy9CbGFkZXNDbG9ja3NcIjtcbi8qIGVzbGludC1lbmFibGUgQHR5cGVzY3JpcHQtZXNsaW50L25vLXVudXNlZC12YXJzICovXG5pbXBvcnQgVGFncyBmcm9tIFwiLi4vLi4vY29yZS90YWdzXCI7XG5jbGFzcyBCbGFkZXNJdGVtU2hlZXQgZXh0ZW5kcyBJdGVtU2hlZXQge1xuICAgIHN0YXRpYyBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBmb3VuZHJ5LnV0aWxzLm1lcmdlT2JqZWN0KHN1cGVyLmRlZmF1bHRPcHRpb25zLCB7XG4gICAgICAgICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcIml0ZW1cIl0sXG4gICAgICAgICAgICB3aWR0aDogNTYwLFxuICAgICAgICAgICAgaGVpZ2h0OiA1MDAsXG4gICAgICAgICAgICB0YWJzOiBbeyBuYXZTZWxlY3RvcjogXCIuc2hlZXQtdGFic1wiLCBjb250ZW50U2VsZWN0b3I6IFwiLnNoZWV0LWJvZHlcIiwgaW5pdGlhbDogXCJkZXNjcmlwdGlvblwiIH1dXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICAvKiAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSAqL1xuICAgIC8vIGNvbnN0cnVjdG9yKGl0ZW06IEJsYWRlc0l0ZW0sIG9wdGlvbnM6IFBhcnRpYWw8SXRlbVNoZWV0Lk9wdGlvbnM+ID0ge30pIHtcbiAgICAvLyAgIG9wdGlvbnMuY2xhc3NlcyA9IFsuLi5vcHRpb25zLmNsYXNzZXMgPz8gW10sIFwiZXVub3MtYmxhZGVzXCIsIFwic2hlZXRcIiwgXCJpdGVtXCIsIGl0ZW0udHlwZV07XG4gICAgLy8gICBzdXBlcihpdGVtLCBvcHRpb25zKTtcbiAgICAvLyB9XG4gICAgLy8gb3ZlcnJpZGUgYXN5bmMgZ2V0RGF0YSgpIHtcbiAgICBnZXREYXRhKCkge1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gc3VwZXIuZ2V0RGF0YSgpO1xuICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7XG4gICAgICAgICAgICBjc3NDbGFzczogdGhpcy5pdGVtLnR5cGUsXG4gICAgICAgICAgICBlZGl0YWJsZTogdGhpcy5vcHRpb25zLmVkaXRhYmxlLFxuICAgICAgICAgICAgaXNHTTogKGdhbWUuZXVub2JsYWRlcy5UcmFja2VyPy5zeXN0ZW0uaXNfc3Bvb2ZpbmdfcGxheWVyID8gZmFsc2UgOiBCb29sZWFuKGdhbWUudXNlci5pc0dNKSksXG4gICAgICAgICAgICBpc0VtYmVkZGVkSXRlbTogQm9vbGVhbih0aGlzLml0ZW0ucGFyZW50KSxcbiAgICAgICAgICAgIGl0ZW06IHRoaXMuaXRlbSxcbiAgICAgICAgICAgIHN5c3RlbTogdGhpcy5pdGVtLnN5c3RlbSxcbiAgICAgICAgICAgIHRpZXJUb3RhbDogdGhpcy5pdGVtLmdldEZhY3RvclRvdGFsKEZhY3Rvci50aWVyKSA+IDAgPyBVLnJvbWFuaXplTnVtKHRoaXMuaXRlbS5nZXRGYWN0b3JUb3RhbChGYWN0b3IudGllcikpIDogXCIwXCIsXG4gICAgICAgICAgICBhY3RpdmVFZmZlY3RzOiBBcnJheS5mcm9tKHRoaXMuaXRlbS5lZmZlY3RzKVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCB0eXBlZEl0ZW1EYXRhID0gdGhpcy5fZ2V0VHlwZWRJdGVtRGF0YVt0aGlzLml0ZW0udHlwZV07XG4gICAgICAgIGlmICh0eXBlZEl0ZW1EYXRhKSB7XG4gICAgICAgICAgICByZXR1cm4gdHlwZWRJdGVtRGF0YSh7IC4uLmNvbnRleHQsIC4uLnNoZWV0RGF0YSB9KTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICB9O1xuICAgIH1cbiAgICBfZ2V0VHlwZWRJdGVtRGF0YSA9IHtcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmFiaWxpdHldOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLmFiaWxpdHkpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmJhY2tncm91bmRdOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLmJhY2tncm91bmQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNsb2NrX2tlZXBlcl06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuY2xvY2tfa2VlcGVyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7XG4gICAgICAgICAgICAgICAgcGhhc2VzOiBPYmplY3QudmFsdWVzKEJsYWRlc1BoYXNlKVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZ2FuZ106IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcsIEJsYWRlc0l0ZW1UeXBlLmNvaG9ydF9leHBlcnQpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnRleHQudGllclRvdGFsID0gdGhpcy5pdGVtLnN5c3RlbS5xdWFsaXR5ID4gMCA/IFUucm9tYW5pemVOdW0odGhpcy5pdGVtLnN5c3RlbS5xdWFsaXR5KSA6IFwiMFwiO1xuICAgICAgICAgICAgY29udGV4dC5zeXN0ZW0uc3VidHlwZXMgPz89IHt9O1xuICAgICAgICAgICAgY29udGV4dC5zeXN0ZW0uZWxpdGVfc3VidHlwZXMgPz89IHt9O1xuICAgICAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge1xuICAgICAgICAgICAgICAgIHRpZXJEYXRhOiB7XG4gICAgICAgICAgICAgICAgICAgIGNsYXNzOiBcImNvbXAtdGllciBjb21wLXZlcnRpY2FsIGNvbXAtdGVldGhcIixcbiAgICAgICAgICAgICAgICAgICAgZG90bGluZToge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YTogdGhpcy5pdGVtLnN5c3RlbS50aWVyLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGFyZ2V0OiBcInN5c3RlbS50aWVyLnZhbHVlXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpY29uRW1wdHk6IFwiZG90LWVtcHR5LnN2Z1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkVtcHR5SG92ZXI6IFwiZG90LWVtcHR5LWhvdmVyLnN2Z1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgaWNvbkZ1bGw6IFwiZG90LWZ1bGwuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpY29uRnVsbEhvdmVyOiBcImRvdC1mdWxsLWhvdmVyLnN2Z1wiXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgc2hlZXREYXRhLmVkZ2VEYXRhID0gT2JqZWN0LmZyb21FbnRyaWVzKE9iamVjdC52YWx1ZXMoY29udGV4dC5zeXN0ZW0uZWRnZXMgPz8gW10pXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoZWRnZSkgPT4gL1tBLVphLXpdLy50ZXN0KGVkZ2UpKVxuICAgICAgICAgICAgICAgIC5tYXAoKGVkZ2UpID0+IFtlZGdlLnRyaW0oKSwgQy5FZGdlVG9vbHRpcHNbZWRnZV1dKSk7XG4gICAgICAgICAgICBzaGVldERhdGEuZmxhd0RhdGEgPSBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LnZhbHVlcyhjb250ZXh0LnN5c3RlbS5mbGF3cyA/PyBbXSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChmbGF3KSA9PiAvW0EtWmEtel0vLnRlc3QoZmxhdykpXG4gICAgICAgICAgICAgICAgLm1hcCgoZmxhdykgPT4gW2ZsYXcudHJpbSgpLCBDLkZsYXdUb29sdGlwc1tmbGF3XV0pKTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5jb2hvcnRfZXhwZXJ0XTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHR5cGVkSXRlbURhdGEgPSB0aGlzLl9nZXRUeXBlZEl0ZW1EYXRhW0JsYWRlc0l0ZW1UeXBlLmNvaG9ydF9nYW5nXTtcbiAgICAgICAgICAgIGlmICghdHlwZWRJdGVtRGF0YSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgTm8gZGF0YSBmb3IgdHlwZSAke3RoaXMuaXRlbS50eXBlfWApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHR5cGVkSXRlbURhdGEoY29udGV4dCk7XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5jcmV3X2FiaWxpdHldOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLmNyZXdfYWJpbGl0eSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge307XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgLi4uc2hlZXREYXRhXG4gICAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICBbQmxhZGVzSXRlbVR5cGUuY3Jld19yZXB1dGF0aW9uXTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5pdGVtLCBCbGFkZXNJdGVtVHlwZS5jcmV3X3JlcHV0YXRpb24pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNyZXdfcGxheWJvb2tdOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLmNyZXdfcGxheWJvb2spKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChjb250ZXh0LmlzR00pIHtcbiAgICAgICAgICAgICAgICBjb25zdCBleHBDbHVlRGF0YSA9IHt9O1xuICAgICAgICAgICAgICAgIFsuLi5PYmplY3QudmFsdWVzKGNvbnRleHQuc3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXMgPz8gW10pLmZpbHRlcigoY2x1ZSkgPT4gL1tBLVphLXpdLy50ZXN0KGNsdWUpKSwgXCIgXCJdLmZvckVhY2goKGNsdWUsIGkpID0+IHsgZXhwQ2x1ZURhdGFbKGkgKyAxKS50b1N0cmluZygpXSA9IGNsdWU7IH0pO1xuICAgICAgICAgICAgICAgIGNvbnRleHQuc3lzdGVtLmV4cGVyaWVuY2VfY2x1ZXMgPSBleHBDbHVlRGF0YTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmNyZXdfdXBncmFkZV06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuY3Jld191cGdyYWRlKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5mZWF0dXJlXTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5pdGVtLCBCbGFkZXNJdGVtVHlwZS5mZWF0dXJlKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5nbV90cmFja2VyXTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5pdGVtLCBCbGFkZXNJdGVtVHlwZS5nbV90cmFja2VyKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7XG4gICAgICAgICAgICAgICAgcGhhc2U6IHRoaXMuaXRlbS5zeXN0ZW0ucGhhc2UsXG4gICAgICAgICAgICAgICAgcGhhc2VzOiBPYmplY3QudmFsdWVzKEJsYWRlc1BoYXNlKVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5oZXJpdGFnZV06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuaGVyaXRhZ2UpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmdlYXJdOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLmdlYXIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHtcbiAgICAgICAgICAgICAgICB0aWVyRGF0YToge1xuICAgICAgICAgICAgICAgICAgICBjbGFzczogXCJjb21wLXRpZXIgY29tcC12ZXJ0aWNhbCBjb21wLXRlZXRoXCIsXG4gICAgICAgICAgICAgICAgICAgIGxhYmVsOiBcIlF1YWxpdHlcIixcbiAgICAgICAgICAgICAgICAgICAgbGFiZWxDbGFzczogXCJmaWxsZWQtbGFiZWwgZnVsbC13aWR0aFwiLFxuICAgICAgICAgICAgICAgICAgICBkb3RsaW5lOiB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhOiB0aGlzLml0ZW0uc3lzdGVtLnRpZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXQ6IFwic3lzdGVtLnRpZXIudmFsdWVcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25FbXB0eTogXCJkb3QtZW1wdHkuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpY29uRW1wdHlIb3ZlcjogXCJkb3QtZW1wdHktaG92ZXIuc3ZnXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBpY29uRnVsbDogXCJkb3QtZnVsbC5zdmdcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGljb25GdWxsSG92ZXI6IFwiZG90LWZ1bGwtaG92ZXIuc3ZnXCJcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgLi4uc2hlZXREYXRhXG4gICAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICBbQmxhZGVzSXRlbVR5cGUucGxheWJvb2tdOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLnBsYXlib29rKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoY29udGV4dC5pc0dNKSB7XG4gICAgICAgICAgICAgICAgY29uc3QgZXhwQ2x1ZURhdGEgPSB7fTtcbiAgICAgICAgICAgICAgICBbLi4uT2JqZWN0LnZhbHVlcyhjb250ZXh0LnN5c3RlbS5leHBlcmllbmNlX2NsdWVzID8/IFtdKS5maWx0ZXIoKGNsdWUpID0+IC9bQS1aYS16XS8udGVzdChjbHVlKSksIFwiIFwiXS5mb3JFYWNoKChjbHVlLCBpKSA9PiB7IGV4cENsdWVEYXRhWyhpICsgMSkudG9TdHJpbmcoKV0gPSBjbHVlOyB9KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN5c3RlbS5leHBlcmllbmNlX2NsdWVzID0gZXhwQ2x1ZURhdGE7XG4gICAgICAgICAgICAgICAgY29uc3QgZ2F0aGVySW5mb0RhdGEgPSB7fTtcbiAgICAgICAgICAgICAgICBbLi4uT2JqZWN0LnZhbHVlcyhjb250ZXh0LnN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnMgPz8gW10pLmZpbHRlcigocXVlc3Rpb24pID0+IC9bQS1aYS16XS8udGVzdChxdWVzdGlvbikpLCBcIiBcIl0uZm9yRWFjaCgocXVlc3Rpb24sIGkpID0+IHsgZ2F0aGVySW5mb0RhdGFbKGkgKyAxKS50b1N0cmluZygpXSA9IHF1ZXN0aW9uOyB9KTtcbiAgICAgICAgICAgICAgICBjb250ZXh0LnN5c3RlbS5nYXRoZXJfaW5mb19xdWVzdGlvbnMgPSBnYXRoZXJJbmZvRGF0YTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLnByZWZlcnJlZF9vcF06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUucHJlZmVycmVkX29wKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5zdHJpY3R1cmVdOiAoY29udGV4dCkgPT4ge1xuICAgICAgICAgICAgaWYgKCFCbGFkZXNJdGVtLklzVHlwZSh0aGlzLml0ZW0sIEJsYWRlc0l0ZW1UeXBlLnN0cmljdHVyZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge307XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgLi4uc2hlZXREYXRhXG4gICAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICBbQmxhZGVzSXRlbVR5cGUudmljZV06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUudmljZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge307XG4gICAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgICAgIC4uLmNvbnRleHQsXG4gICAgICAgICAgICAgICAgLi4uc2hlZXREYXRhXG4gICAgICAgICAgICB9O1xuICAgICAgICB9LFxuICAgICAgICBbQmxhZGVzSXRlbVR5cGUucml0dWFsXTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5pdGVtLCBCbGFkZXNJdGVtVHlwZS5yaXR1YWwpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLmRlc2lnbl06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuZGVzaWduKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB1bmRlZmluZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgICAgICAuLi5zaGVldERhdGFcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0sXG4gICAgICAgIFtCbGFkZXNJdGVtVHlwZS5sb2NhdGlvbl06IChjb250ZXh0KSA9PiB7XG4gICAgICAgICAgICBpZiAoIUJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUubG9jYXRpb24pKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IHNoZWV0RGF0YSA9IHt9O1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICAuLi5jb250ZXh0LFxuICAgICAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcbiAgICAgICAgW0JsYWRlc0l0ZW1UeXBlLnNjb3JlXTogKGNvbnRleHQpID0+IHtcbiAgICAgICAgICAgIGlmICghQmxhZGVzSXRlbS5Jc1R5cGUodGhpcy5pdGVtLCBCbGFkZXNJdGVtVHlwZS5zY29yZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGdldCB0ZW1wbGF0ZSgpIHtcbiAgICAgICAgY29uc3QgcGF0aENvbXBzID0gW1xuICAgICAgICAgICAgXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvaXRlbXNcIlxuICAgICAgICBdO1xuICAgICAgICBpZiAoQy5TaW1wbGVJdGVtVHlwZXMuaW5jbHVkZXModGhpcy5pdGVtLnR5cGUpKSB7XG4gICAgICAgICAgICBwYXRoQ29tcHMucHVzaChcInNpbXBsZS1zaGVldC5oYnNcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBwYXRoQ29tcHMucHVzaChgJHt0aGlzLml0ZW0udHlwZX0tc2hlZXQuaGJzYCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHBhdGhDb21wcy5qb2luKFwiL1wiKTtcbiAgICB9XG4gICAgLyogLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cbiAgICBhZGREb3RsaW5lTGlzdGVuZXJzKGh0bWwpIHtcbiAgICAgICAgaHRtbC5maW5kKFwiLmRvdGxpbmVcIikuZWFjaCgoX18sIGVsZW0pID0+IHtcbiAgICAgICAgICAgIGlmICgkKGVsZW0pLmhhc0NsYXNzKFwibG9ja2VkXCIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc3QgdGFyZ2V0RG9jID0gdGhpcy5pdGVtO1xuICAgICAgICAgICAgY29uc3QgdGFyZ2V0RmllbGQgPSAkKGVsZW0pLmRhdGEoXCJ0YXJnZXRcIik7XG4gICAgICAgICAgICBjb25zdCBjb21wJCA9ICQoZWxlbSkuY2xvc2VzdChcImNvbXBcIik7XG4gICAgICAgICAgICBjb25zdCBjdXJWYWx1ZSA9IFUucEludCgkKGVsZW0pLmRhdGEoXCJ2YWx1ZVwiKSk7XG4gICAgICAgICAgICAkKGVsZW0pXG4gICAgICAgICAgICAgICAgLmZpbmQoXCIuZG90XCIpXG4gICAgICAgICAgICAgICAgLmVhY2goKF8sIGRvdCkgPT4ge1xuICAgICAgICAgICAgICAgICQoZG90KS5vbihcImNsaWNrXCIsIChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCB0aGlzVmFsdWUgPSBVLnBJbnQoJChkb3QpLmRhdGEoXCJ2YWx1ZVwiKSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzVmFsdWUgIT09IGN1clZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoY29tcCQuaGFzQ2xhc3MoXCJjb21wLWNvaW5zXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfHwgY29tcCQuaGFzQ2xhc3MoXCJjb21wLXN0YXNoXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgRy5lZmZlY3RzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5maWxsQ29pbnMoJChkb3QpLnByZXZBbGwoXCIuZG90XCIpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAudGhlbigoKSA9PiB0YXJnZXREb2MudXBkYXRlKHsgW3RhcmdldEZpZWxkXTogdGhpc1ZhbHVlIH0pKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldERvYy51cGRhdGUoeyBbdGFyZ2V0RmllbGRdOiB0aGlzVmFsdWUgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAkKGRvdCkub24oXCJjb250ZXh0bWVudVwiLCAoZXZlbnQpID0+IHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnQucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgdGhpc1ZhbHVlID0gVS5wSW50KCQoZG90KS5kYXRhKFwidmFsdWVcIikpIC0gMTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXNWYWx1ZSAhPT0gY3VyVmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldERvYy51cGRhdGUoeyBbdGFyZ2V0RmllbGRdOiB0aGlzVmFsdWUgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCkge1xuICAgICAgICBhd2FpdCBzdXBlci5hY3RpdmF0ZUxpc3RlbmVycyhodG1sKTtcbiAgICAgICAgY29uc3Qgc2VsZiA9IHRoaXM7XG4gICAgICAgIFRhZ3MuSW5pdExpc3RlbmVycyhodG1sLCB0aGlzLml0ZW0pO1xuICAgICAgICBBcHBseVRvb2x0aXBBbmltYXRpb25zKGh0bWwpO1xuICAgICAgICAvLyBFdmVyeXRoaW5nIGJlbG93IGhlcmUgaXMgb25seSBuZWVkZWQgaWYgdGhlIHNoZWV0IGlzIGVkaXRhYmxlXG4gICAgICAgIGlmICghdGhpcy5vcHRpb25zLmVkaXRhYmxlKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gQWRkIGRvdGxpbmUgZnVuY3Rpb25hbGl0eVxuICAgICAgICB0aGlzLmFkZERvdGxpbmVMaXN0ZW5lcnMoaHRtbCk7XG4gICAgICAgIC8vIEhhcm0gQmFyIEZ1bmN0aW9uYWxpdHkgZm9yIENvaG9ydHNcbiAgICAgICAgaWYgKEJsYWRlc0l0ZW0uSXNUeXBlKHRoaXMuaXRlbSwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2V4cGVydCwgQmxhZGVzSXRlbVR5cGUuY29ob3J0X2dhbmcpKSB7XG4gICAgICAgICAgICBodG1sLmZpbmQoXCJbZGF0YS1oYXJtLWNsaWNrXVwiKS5vbih7XG4gICAgICAgICAgICAgICAgY2xpY2s6IChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zdCBoYXJtTGV2ZWwgPSBVLnBJbnQoJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwiaGFybUNsaWNrXCIpKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuaXRlbS5zeXN0ZW0uaGFybT8udmFsdWUgIT09IGhhcm1MZXZlbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5pdGVtLnVwZGF0ZSh7IFwic3lzdGVtLmhhcm0udmFsdWVcIjogaGFybUxldmVsIH0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBjb250ZXh0bWVudTogKGV2ZW50KSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGhhcm1MZXZlbCA9IE1hdGgubWF4KDAsIFUucEludCgkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLmRhdGEoXCJoYXJtQ2xpY2tcIikpIC0gMSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLml0ZW0uc3lzdGVtLmhhcm0/LnZhbHVlICE9PSBoYXJtTGV2ZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuaXRlbS51cGRhdGUoeyBcInN5c3RlbS5oYXJtLnZhbHVlXCI6IGhhcm1MZXZlbCB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIC8vIFRoaXMgaXMgYSB3b3JrYXJvdW5kIHVudGlsIGlzIGJlaW5nIGZpeGVkIGluIEZvdW5kcnlWVFQuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc3VibWl0T25DaGFuZ2UpIHtcbiAgICAgICAgICAgIGh0bWwub24oXCJjaGFuZ2VcIiwgXCJ0ZXh0YXJlYVwiLCB0aGlzLl9vbkNoYW5nZUlucHV0LmJpbmQodGhpcykpOyAvLyBVc2UgZGVsZWdhdGVkIGxpc3RlbmVyIG9uIHRoZSBmb3JtXG4gICAgICAgIH1cbiAgICAgICAgaHRtbC5maW5kKFwiLmVmZmVjdC1jb250cm9sXCIpLm9uKFwiY2xpY2tcIiwgKGV2KSA9PiB7XG4gICAgICAgICAgICBpZiAoc2VsZi5pdGVtLmlzT3duZWQpIHtcbiAgICAgICAgICAgICAgICB1aS5ub3RpZmljYXRpb25zPy53YXJuKGdhbWUuaTE4bi5sb2NhbGl6ZShcIkJJVEQuRWZmZWN0V2FybmluZ1wiKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgQmxhZGVzQWN0aXZlRWZmZWN0Lm9uTWFuYWdlQWN0aXZlRWZmZWN0KGV2LCBzZWxmLml0ZW0pO1xuICAgICAgICB9KTtcbiAgICAgICAgaHRtbC5maW5kKFwiW2RhdGEtYWN0aW9uPVxcXCJ0b2dnbGUtdHVyZi1jb25uZWN0aW9uXFxcIlwiKS5vbihcImNsaWNrXCIsIHRoaXMudG9nZ2xlVHVyZkNvbm5lY3Rpb24uYmluZCh0aGlzKSk7XG4gICAgfVxuICAgIHRvZ2dsZVR1cmZDb25uZWN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGNvbnN0IGJ1dHRvbiQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBjb25uZWN0b3IkID0gYnV0dG9uJC5wYXJlbnQoKTtcbiAgICAgICAgY29uc3QgdHVyZk51bSA9IHBhcnNlSW50KGNvbm5lY3RvciQuZGF0YShcImluZGV4XCIpID8/IDAsIDEwKTtcbiAgICAgICAgY29uc3QgdHVyZkRpciA9IGNvbm5lY3RvciQuZGF0YShcImRpclwiKTtcbiAgICAgICAgaWYgKCF0dXJmTnVtIHx8ICF0dXJmRGlyKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgdG9nZ2xlU3RhdGUgPSBjb25uZWN0b3IkLmhhc0NsYXNzKFwibm8tY29ubmVjdFwiKTtcbiAgICAgICAgY29uc3QgdXBkYXRlRGF0YSA9IHtcbiAgICAgICAgICAgIFtgc3lzdGVtLnR1cmZzLiR7dHVyZk51bX0uY29ubmVjdHMuJHt0dXJmRGlyfWBdOiB0b2dnbGVTdGF0ZVxuICAgICAgICB9O1xuICAgICAgICBjb25zdCBwYXJ0bmVyID0gY29ubmVjdG9yJC5kYXRhKFwicGFydG5lclwiKTtcbiAgICAgICAgaWYgKHR5cGVvZiBwYXJ0bmVyID09PSBcInN0cmluZ1wiICYmIC8tLy50ZXN0KHBhcnRuZXIpKSB7XG4gICAgICAgICAgICBjb25zdCBbcGFydG5lck51bSwgcGFydG5lckRpcl0gPSBwYXJ0bmVyLnNwbGl0KFwiLVwiKTtcbiAgICAgICAgICAgIHVwZGF0ZURhdGFbYHN5c3RlbS50dXJmcy4ke3BhcnRuZXJOdW19LmNvbm5lY3RzLiR7cGFydG5lckRpcn1gXSA9IHRvZ2dsZVN0YXRlO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMuaXRlbS51cGRhdGUodXBkYXRlRGF0YSk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzSXRlbVNoZWV0O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/sheets/item/BladesItemSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/item/BladesProjectSheet.ts": +/*!**********************************************!*\ + !*** ./ts/sheets/item/BladesProjectSheet.ts ***! + \**********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesItemSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesItemSheet */ \"./ts/sheets/item/BladesItemSheet.ts\");\n/* eslint-disable @typescript-eslint/no-unused-vars */\n\n\n\nclass BladesProjectSheet extends _BladesItemSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"item\", \"project-sheet\"],\n template: \"systems/eunos-blades/templates/items/project-sheet.hbs\"\n });\n }\n getData() {\n const context = super.getData();\n const sheetData = {};\n sheetData.presentingClock = this.presentedClock;\n return {\n ...context,\n ...sheetData\n };\n }\n get presentedClock() {\n const { clockKey } = this.document;\n if (!clockKey) {\n throw new Error(`ClockKey not initialized for Project ${this.document.name}`);\n }\n let focusedClockIndex;\n if (_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].isInt(clockKey.displayMode)) {\n focusedClockIndex = clockKey.displayMode;\n }\n else if (clockKey.displayMode === _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKeyDisplayMode.presentCurrentClock) {\n focusedClockIndex = this.document.currentClock.index;\n }\n else if (clockKey.displayMode.startsWith(\"present\")) {\n focusedClockIndex = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(clockKey.displayMode.slice(7));\n }\n else {\n return false;\n }\n return this.document.clockKey.getClockByIndex(focusedClockIndex) ?? false;\n }\n getClockKeyComponents(html) {\n const { clockKey } = this.document;\n if (!clockKey) {\n throw new Error(`ClockKey not initialized for Project ${this.document.name}`);\n }\n return {\n clockKey,\n keyElems$: clockKey.getElements$(html.find(\".clock-key-panel\"))\n };\n }\n switchToPresentAllClocks(clockKey, keyElems$) {\n const { clocks } = keyElems$;\n const timeline = clockKey.switchToMode(keyElems$, _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKeyDisplayMode.clocks);\n // If there are multiple clocks, reveal labels of visible clocks\n if (clockKey.size > 1) {\n clockKey.visibleClocks.forEach((clock, i) => {\n const { clockLabel$ } = clocks[clock.id];\n timeline.blurReveal(clockLabel$, i === 0\n ? \">\"\n : \"<+0.05\");\n });\n }\n timeline.play().then(() => {\n // Change subtitle element to name of current clock\n if (this._htmlContext && this.document.currentClock) {\n this._htmlContext.find(\".sheet-subtitle\")\n .attr(\"data-action\", \"current-clock-name\")\n .val(this.document.currentClock.name);\n }\n });\n }\n switchToPresentClock(clockRef, clockKey, keyElems$) {\n const timeline = clockKey.switchToMode(keyElems$, clockRef === _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKeyDisplayMode.presentCurrentClock\n ? clockRef\n : (`present${clockRef}`), undefined, undefined, true, () => {\n eLog.checkLog3(\"BladesProject\", \"Clock Switch\", { clockRef, clockKey, keyElems$, htmlContext: this._htmlContext, presentedClock: this.presentedClock });\n // Change subtitle element to name of presented clock\n if (this._htmlContext && this.presentedClock) {\n this._htmlContext.find(\".sheet-subtitle\")\n .attr(\"data-action\", \"presented-clock-name\")\n .val(this.presentedClock.name);\n }\n });\n // Fade out any visible label elements\n timeline.to(keyElems$.container$.find(\".clock-label, .clock-key-label\"), { autoAlpha: 0, duration: 0.5, ease: \"sine\" }, 0);\n timeline.play().then();\n }\n activateClockKeyListeners(clockKey, keyElems$) {\n eLog.checkLog2(\"BladesProject\", \"Clock Key Data\", { clockKey, keyElems$ });\n const { container$ } = keyElems$;\n // Activate pointer events on the container element\n container$.css(\"pointer-events\", \"auto\");\n container$.on(\"contextmenu\", () => {\n this.switchToPresentAllClocks(clockKey, keyElems$);\n });\n // Add click listeners for player interaction to clock elements\n Object.entries(keyElems$.clocks).forEach(([clockId, clockElems$]) => {\n clockElems$.clockContainer$.css(\"pointer-events\", \"auto\");\n clockElems$.clockContainer$.on(\"click\", () => {\n this.switchToPresentClock(clockKey.clocks.get(clockId)?.index ?? _core_constants__WEBPACK_IMPORTED_MODULE_1__.ClockKeyDisplayMode.presentCurrentClock, clockKey, keyElems$);\n });\n });\n }\n _htmlContext;\n async activateListeners(html) {\n this._htmlContext = html;\n await super.activateListeners(html);\n // Get clock key and rendered clock key elements\n const { clockKey, keyElems$ } = this.getClockKeyComponents(html);\n // Add listener for contextual clock name depending on display mode\n html.find(\"input.sheet-subtitle\")\n .on({\n change: (event) => {\n event.preventDefault();\n const action = $(event.currentTarget).data(\"action\");\n eLog.checkLog3(\"BladesProject\", \"Clock Name Change\", { action, value: $(event.currentTarget).val() });\n if (action === \"presented-clock-name\" && this.presentedClock) {\n this.presentedClock.updateTarget(\"name\", $(event.currentTarget).val());\n keyElems$.clocks[this.presentedClock.id].clockLabel$\n .text($(event.currentTarget).val());\n }\n else if (action === \"current-clock-name\") {\n this.document.clockKey.currentClock.updateTarget(\"name\", $(event.currentTarget).val());\n keyElems$.clocks[this.document.clockKey.currentClock.id].clockLabel$\n .text($(event.currentTarget).val());\n }\n clockKey.formatLabels(keyElems$);\n }\n });\n // Initialize clock key elements\n clockKey.initElementsInContext(html);\n // Activate listeners for the rendered key\n this.activateClockKeyListeners(clockKey, keyElems$);\n // Reveal & activate clocks\n await Promise.all([\n ...clockKey.visibleClocks.map((clock) => new Promise((resolve) => {\n const clockElems$ = keyElems$.clocks[clock.id];\n clock.reveal_Animation(clockElems$, () => { resolve(); });\n })),\n ...clockKey.activeClocks.map((clock) => new Promise((resolve) => {\n const clockElems$ = keyElems$.clocks[clock.id];\n clock.activate_Animation(clockElems$, () => { resolve(); });\n }))\n ]);\n // // Animate to present the currently-active clock\n // clockKey.switchToMode(keyElems$, `present${this.document.currentClock.index}` as ClockKeyDisplayMode)\n // .play();\n }\n}\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesProjectSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiLi90cy9zaGVldHMvaXRlbS9CbGFkZXNQcm9qZWN0U2hlZXQudHMiLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ3FDO0FBQ3NCO0FBQ1g7QUFDaEQsaUNBQWlDLHdEQUFlO0FBQ2hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsV0FBVztBQUMzQjtBQUNBLG9FQUFvRSxtQkFBbUI7QUFDdkY7QUFDQTtBQUNBLFlBQVksdURBQUM7QUFDYjtBQUNBO0FBQ0EsMENBQTBDLGdFQUFtQjtBQUM3RDtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsdURBQUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsV0FBVztBQUMzQjtBQUNBLG9FQUFvRSxtQkFBbUI7QUFDdkY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsU0FBUztBQUN6QiwwREFBMEQsZ0VBQW1CO0FBQzdFO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixjQUFjO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBLGFBQWE7QUFDYjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSx1RUFBdUUsZ0VBQW1CO0FBQzFGO0FBQ0EseUJBQXlCLFNBQVM7QUFDbEMsOERBQThELG9HQUFvRztBQUNsSztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQSxtRkFBbUYsMkNBQTJDO0FBQzlIO0FBQ0E7QUFDQTtBQUNBLDREQUE0RCxxQkFBcUI7QUFDakYsZ0JBQWdCLGFBQWE7QUFDN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpRkFBaUYsZ0VBQW1CO0FBQ3BHLGFBQWE7QUFDYixTQUFTO0FBQ1Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLHNCQUFzQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1RUFBdUUsNkNBQTZDO0FBQ3BIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsNERBQTRELFlBQVk7QUFDeEUsYUFBYTtBQUNiO0FBQ0E7QUFDQSw4REFBOEQsWUFBWTtBQUMxRSxhQUFhO0FBQ2I7QUFDQTtBQUNBLHNEQUFzRCxpQ0FBaUM7QUFDdkY7QUFDQTtBQUNBO0FBQ0EsK0RBQWUsa0JBQWtCLEVBQUMiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi90cy9zaGVldHMvaXRlbS9CbGFkZXNQcm9qZWN0U2hlZXQudHM/ZWFiOSJdLCJzb3VyY2VzQ29udGVudCI6WyIvKiBlc2xpbnQtZGlzYWJsZSBAdHlwZXNjcmlwdC1lc2xpbnQvbm8tdW51c2VkLXZhcnMgKi9cbmltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IHsgQ2xvY2tLZXlEaXNwbGF5TW9kZSB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IEJsYWRlc0l0ZW1TaGVldCBmcm9tIFwiLi9CbGFkZXNJdGVtU2hlZXRcIjtcbmNsYXNzIEJsYWRlc1Byb2plY3RTaGVldCBleHRlbmRzIEJsYWRlc0l0ZW1TaGVldCB7XG4gICAgc3RhdGljIGdldCBkZWZhdWx0T3B0aW9ucygpIHtcbiAgICAgICAgcmV0dXJuIGZvdW5kcnkudXRpbHMubWVyZ2VPYmplY3Qoc3VwZXIuZGVmYXVsdE9wdGlvbnMsIHtcbiAgICAgICAgICAgIGNsYXNzZXM6IFtcImV1bm9zLWJsYWRlc1wiLCBcInNoZWV0XCIsIFwiaXRlbVwiLCBcInByb2plY3Qtc2hlZXRcIl0sXG4gICAgICAgICAgICB0ZW1wbGF0ZTogXCJzeXN0ZW1zL2V1bm9zLWJsYWRlcy90ZW1wbGF0ZXMvaXRlbXMvcHJvamVjdC1zaGVldC5oYnNcIlxuICAgICAgICB9KTtcbiAgICB9XG4gICAgZ2V0RGF0YSgpIHtcbiAgICAgICAgY29uc3QgY29udGV4dCA9IHN1cGVyLmdldERhdGEoKTtcbiAgICAgICAgY29uc3Qgc2hlZXREYXRhID0ge307XG4gICAgICAgIHNoZWV0RGF0YS5wcmVzZW50aW5nQ2xvY2sgPSB0aGlzLnByZXNlbnRlZENsb2NrO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICB9O1xuICAgIH1cbiAgICBnZXQgcHJlc2VudGVkQ2xvY2soKSB7XG4gICAgICAgIGNvbnN0IHsgY2xvY2tLZXkgfSA9IHRoaXMuZG9jdW1lbnQ7XG4gICAgICAgIGlmICghY2xvY2tLZXkpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihgQ2xvY2tLZXkgbm90IGluaXRpYWxpemVkIGZvciBQcm9qZWN0ICR7dGhpcy5kb2N1bWVudC5uYW1lfWApO1xuICAgICAgICB9XG4gICAgICAgIGxldCBmb2N1c2VkQ2xvY2tJbmRleDtcbiAgICAgICAgaWYgKFUuaXNJbnQoY2xvY2tLZXkuZGlzcGxheU1vZGUpKSB7XG4gICAgICAgICAgICBmb2N1c2VkQ2xvY2tJbmRleCA9IGNsb2NrS2V5LmRpc3BsYXlNb2RlO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKGNsb2NrS2V5LmRpc3BsYXlNb2RlID09PSBDbG9ja0tleURpc3BsYXlNb2RlLnByZXNlbnRDdXJyZW50Q2xvY2spIHtcbiAgICAgICAgICAgIGZvY3VzZWRDbG9ja0luZGV4ID0gdGhpcy5kb2N1bWVudC5jdXJyZW50Q2xvY2suaW5kZXg7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY2xvY2tLZXkuZGlzcGxheU1vZGUuc3RhcnRzV2l0aChcInByZXNlbnRcIikpIHtcbiAgICAgICAgICAgIGZvY3VzZWRDbG9ja0luZGV4ID0gVS5wSW50KGNsb2NrS2V5LmRpc3BsYXlNb2RlLnNsaWNlKDcpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdGhpcy5kb2N1bWVudC5jbG9ja0tleS5nZXRDbG9ja0J5SW5kZXgoZm9jdXNlZENsb2NrSW5kZXgpID8/IGZhbHNlO1xuICAgIH1cbiAgICBnZXRDbG9ja0tleUNvbXBvbmVudHMoaHRtbCkge1xuICAgICAgICBjb25zdCB7IGNsb2NrS2V5IH0gPSB0aGlzLmRvY3VtZW50O1xuICAgICAgICBpZiAoIWNsb2NrS2V5KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoYENsb2NrS2V5IG5vdCBpbml0aWFsaXplZCBmb3IgUHJvamVjdCAke3RoaXMuZG9jdW1lbnQubmFtZX1gKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2xvY2tLZXksXG4gICAgICAgICAgICBrZXlFbGVtcyQ6IGNsb2NrS2V5LmdldEVsZW1lbnRzJChodG1sLmZpbmQoXCIuY2xvY2sta2V5LXBhbmVsXCIpKVxuICAgICAgICB9O1xuICAgIH1cbiAgICBzd2l0Y2hUb1ByZXNlbnRBbGxDbG9ja3MoY2xvY2tLZXksIGtleUVsZW1zJCkge1xuICAgICAgICBjb25zdCB7IGNsb2NrcyB9ID0ga2V5RWxlbXMkO1xuICAgICAgICBjb25zdCB0aW1lbGluZSA9IGNsb2NrS2V5LnN3aXRjaFRvTW9kZShrZXlFbGVtcyQsIENsb2NrS2V5RGlzcGxheU1vZGUuY2xvY2tzKTtcbiAgICAgICAgLy8gSWYgdGhlcmUgYXJlIG11bHRpcGxlIGNsb2NrcywgcmV2ZWFsIGxhYmVscyBvZiB2aXNpYmxlIGNsb2Nrc1xuICAgICAgICBpZiAoY2xvY2tLZXkuc2l6ZSA+IDEpIHtcbiAgICAgICAgICAgIGNsb2NrS2V5LnZpc2libGVDbG9ja3MuZm9yRWFjaCgoY2xvY2ssIGkpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCB7IGNsb2NrTGFiZWwkIH0gPSBjbG9ja3NbY2xvY2suaWRdO1xuICAgICAgICAgICAgICAgIHRpbWVsaW5lLmJsdXJSZXZlYWwoY2xvY2tMYWJlbCQsIGkgPT09IDBcbiAgICAgICAgICAgICAgICAgICAgPyBcIj5cIlxuICAgICAgICAgICAgICAgICAgICA6IFwiPCswLjA1XCIpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgdGltZWxpbmUucGxheSgpLnRoZW4oKCkgPT4ge1xuICAgICAgICAgICAgLy8gQ2hhbmdlIHN1YnRpdGxlIGVsZW1lbnQgdG8gbmFtZSBvZiBjdXJyZW50IGNsb2NrXG4gICAgICAgICAgICBpZiAodGhpcy5faHRtbENvbnRleHQgJiYgdGhpcy5kb2N1bWVudC5jdXJyZW50Q2xvY2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9odG1sQ29udGV4dC5maW5kKFwiLnNoZWV0LXN1YnRpdGxlXCIpXG4gICAgICAgICAgICAgICAgICAgIC5hdHRyKFwiZGF0YS1hY3Rpb25cIiwgXCJjdXJyZW50LWNsb2NrLW5hbWVcIilcbiAgICAgICAgICAgICAgICAgICAgLnZhbCh0aGlzLmRvY3VtZW50LmN1cnJlbnRDbG9jay5uYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN3aXRjaFRvUHJlc2VudENsb2NrKGNsb2NrUmVmLCBjbG9ja0tleSwga2V5RWxlbXMkKSB7XG4gICAgICAgIGNvbnN0IHRpbWVsaW5lID0gY2xvY2tLZXkuc3dpdGNoVG9Nb2RlKGtleUVsZW1zJCwgY2xvY2tSZWYgPT09IENsb2NrS2V5RGlzcGxheU1vZGUucHJlc2VudEN1cnJlbnRDbG9ja1xuICAgICAgICAgICAgPyBjbG9ja1JlZlxuICAgICAgICAgICAgOiAoYHByZXNlbnQke2Nsb2NrUmVmfWApLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdHJ1ZSwgKCkgPT4ge1xuICAgICAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJCbGFkZXNQcm9qZWN0XCIsIFwiQ2xvY2sgU3dpdGNoXCIsIHsgY2xvY2tSZWYsIGNsb2NrS2V5LCBrZXlFbGVtcyQsIGh0bWxDb250ZXh0OiB0aGlzLl9odG1sQ29udGV4dCwgcHJlc2VudGVkQ2xvY2s6IHRoaXMucHJlc2VudGVkQ2xvY2sgfSk7XG4gICAgICAgICAgICAvLyBDaGFuZ2Ugc3VidGl0bGUgZWxlbWVudCB0byBuYW1lIG9mIHByZXNlbnRlZCBjbG9ja1xuICAgICAgICAgICAgaWYgKHRoaXMuX2h0bWxDb250ZXh0ICYmIHRoaXMucHJlc2VudGVkQ2xvY2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9odG1sQ29udGV4dC5maW5kKFwiLnNoZWV0LXN1YnRpdGxlXCIpXG4gICAgICAgICAgICAgICAgICAgIC5hdHRyKFwiZGF0YS1hY3Rpb25cIiwgXCJwcmVzZW50ZWQtY2xvY2stbmFtZVwiKVxuICAgICAgICAgICAgICAgICAgICAudmFsKHRoaXMucHJlc2VudGVkQ2xvY2submFtZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBGYWRlIG91dCBhbnkgdmlzaWJsZSBsYWJlbCBlbGVtZW50c1xuICAgICAgICB0aW1lbGluZS50byhrZXlFbGVtcyQuY29udGFpbmVyJC5maW5kKFwiLmNsb2NrLWxhYmVsLCAuY2xvY2sta2V5LWxhYmVsXCIpLCB7IGF1dG9BbHBoYTogMCwgZHVyYXRpb246IDAuNSwgZWFzZTogXCJzaW5lXCIgfSwgMCk7XG4gICAgICAgIHRpbWVsaW5lLnBsYXkoKS50aGVuKCk7XG4gICAgfVxuICAgIGFjdGl2YXRlQ2xvY2tLZXlMaXN0ZW5lcnMoY2xvY2tLZXksIGtleUVsZW1zJCkge1xuICAgICAgICBlTG9nLmNoZWNrTG9nMihcIkJsYWRlc1Byb2plY3RcIiwgXCJDbG9jayBLZXkgRGF0YVwiLCB7IGNsb2NrS2V5LCBrZXlFbGVtcyQgfSk7XG4gICAgICAgIGNvbnN0IHsgY29udGFpbmVyJCB9ID0ga2V5RWxlbXMkO1xuICAgICAgICAvLyBBY3RpdmF0ZSBwb2ludGVyIGV2ZW50cyBvbiB0aGUgY29udGFpbmVyIGVsZW1lbnRcbiAgICAgICAgY29udGFpbmVyJC5jc3MoXCJwb2ludGVyLWV2ZW50c1wiLCBcImF1dG9cIik7XG4gICAgICAgIGNvbnRhaW5lciQub24oXCJjb250ZXh0bWVudVwiLCAoKSA9PiB7XG4gICAgICAgICAgICB0aGlzLnN3aXRjaFRvUHJlc2VudEFsbENsb2NrcyhjbG9ja0tleSwga2V5RWxlbXMkKTtcbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEFkZCBjbGljayBsaXN0ZW5lcnMgZm9yIHBsYXllciBpbnRlcmFjdGlvbiB0byBjbG9jayBlbGVtZW50c1xuICAgICAgICBPYmplY3QuZW50cmllcyhrZXlFbGVtcyQuY2xvY2tzKS5mb3JFYWNoKChbY2xvY2tJZCwgY2xvY2tFbGVtcyRdKSA9PiB7XG4gICAgICAgICAgICBjbG9ja0VsZW1zJC5jbG9ja0NvbnRhaW5lciQuY3NzKFwicG9pbnRlci1ldmVudHNcIiwgXCJhdXRvXCIpO1xuICAgICAgICAgICAgY2xvY2tFbGVtcyQuY2xvY2tDb250YWluZXIkLm9uKFwiY2xpY2tcIiwgKCkgPT4ge1xuICAgICAgICAgICAgICAgIHRoaXMuc3dpdGNoVG9QcmVzZW50Q2xvY2soY2xvY2tLZXkuY2xvY2tzLmdldChjbG9ja0lkKT8uaW5kZXggPz8gQ2xvY2tLZXlEaXNwbGF5TW9kZS5wcmVzZW50Q3VycmVudENsb2NrLCBjbG9ja0tleSwga2V5RWxlbXMkKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgX2h0bWxDb250ZXh0O1xuICAgIGFzeW5jIGFjdGl2YXRlTGlzdGVuZXJzKGh0bWwpIHtcbiAgICAgICAgdGhpcy5faHRtbENvbnRleHQgPSBodG1sO1xuICAgICAgICBhd2FpdCBzdXBlci5hY3RpdmF0ZUxpc3RlbmVycyhodG1sKTtcbiAgICAgICAgLy8gR2V0IGNsb2NrIGtleSBhbmQgcmVuZGVyZWQgY2xvY2sga2V5IGVsZW1lbnRzXG4gICAgICAgIGNvbnN0IHsgY2xvY2tLZXksIGtleUVsZW1zJCB9ID0gdGhpcy5nZXRDbG9ja0tleUNvbXBvbmVudHMoaHRtbCk7XG4gICAgICAgIC8vIEFkZCBsaXN0ZW5lciBmb3IgY29udGV4dHVhbCBjbG9jayBuYW1lIGRlcGVuZGluZyBvbiBkaXNwbGF5IG1vZGVcbiAgICAgICAgaHRtbC5maW5kKFwiaW5wdXQuc2hlZXQtc3VidGl0bGVcIilcbiAgICAgICAgICAgIC5vbih7XG4gICAgICAgICAgICBjaGFuZ2U6IChldmVudCkgPT4ge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgY29uc3QgYWN0aW9uID0gJChldmVudC5jdXJyZW50VGFyZ2V0KS5kYXRhKFwiYWN0aW9uXCIpO1xuICAgICAgICAgICAgICAgIGVMb2cuY2hlY2tMb2czKFwiQmxhZGVzUHJvamVjdFwiLCBcIkNsb2NrIE5hbWUgQ2hhbmdlXCIsIHsgYWN0aW9uLCB2YWx1ZTogJChldmVudC5jdXJyZW50VGFyZ2V0KS52YWwoKSB9KTtcbiAgICAgICAgICAgICAgICBpZiAoYWN0aW9uID09PSBcInByZXNlbnRlZC1jbG9jay1uYW1lXCIgJiYgdGhpcy5wcmVzZW50ZWRDbG9jaykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnByZXNlbnRlZENsb2NrLnVwZGF0ZVRhcmdldChcIm5hbWVcIiwgJChldmVudC5jdXJyZW50VGFyZ2V0KS52YWwoKSk7XG4gICAgICAgICAgICAgICAgICAgIGtleUVsZW1zJC5jbG9ja3NbdGhpcy5wcmVzZW50ZWRDbG9jay5pZF0uY2xvY2tMYWJlbCRcbiAgICAgICAgICAgICAgICAgICAgICAgIC50ZXh0KCQoZXZlbnQuY3VycmVudFRhcmdldCkudmFsKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChhY3Rpb24gPT09IFwiY3VycmVudC1jbG9jay1uYW1lXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kb2N1bWVudC5jbG9ja0tleS5jdXJyZW50Q2xvY2sudXBkYXRlVGFyZ2V0KFwibmFtZVwiLCAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpLnZhbCgpKTtcbiAgICAgICAgICAgICAgICAgICAga2V5RWxlbXMkLmNsb2Nrc1t0aGlzLmRvY3VtZW50LmNsb2NrS2V5LmN1cnJlbnRDbG9jay5pZF0uY2xvY2tMYWJlbCRcbiAgICAgICAgICAgICAgICAgICAgICAgIC50ZXh0KCQoZXZlbnQuY3VycmVudFRhcmdldCkudmFsKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjbG9ja0tleS5mb3JtYXRMYWJlbHMoa2V5RWxlbXMkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIC8vIEluaXRpYWxpemUgY2xvY2sga2V5IGVsZW1lbnRzXG4gICAgICAgIGNsb2NrS2V5LmluaXRFbGVtZW50c0luQ29udGV4dChodG1sKTtcbiAgICAgICAgLy8gQWN0aXZhdGUgbGlzdGVuZXJzIGZvciB0aGUgcmVuZGVyZWQga2V5XG4gICAgICAgIHRoaXMuYWN0aXZhdGVDbG9ja0tleUxpc3RlbmVycyhjbG9ja0tleSwga2V5RWxlbXMkKTtcbiAgICAgICAgLy8gUmV2ZWFsICYgYWN0aXZhdGUgY2xvY2tzXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICAgIC4uLmNsb2NrS2V5LnZpc2libGVDbG9ja3MubWFwKChjbG9jaykgPT4gbmV3IFByb21pc2UoKHJlc29sdmUpID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCBjbG9ja0VsZW1zJCA9IGtleUVsZW1zJC5jbG9ja3NbY2xvY2suaWRdO1xuICAgICAgICAgICAgICAgIGNsb2NrLnJldmVhbF9BbmltYXRpb24oY2xvY2tFbGVtcyQsICgpID0+IHsgcmVzb2x2ZSgpOyB9KTtcbiAgICAgICAgICAgIH0pKSxcbiAgICAgICAgICAgIC4uLmNsb2NrS2V5LmFjdGl2ZUNsb2Nrcy5tYXAoKGNsb2NrKSA9PiBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IGNsb2NrRWxlbXMkID0ga2V5RWxlbXMkLmNsb2Nrc1tjbG9jay5pZF07XG4gICAgICAgICAgICAgICAgY2xvY2suYWN0aXZhdGVfQW5pbWF0aW9uKGNsb2NrRWxlbXMkLCAoKSA9PiB7IHJlc29sdmUoKTsgfSk7XG4gICAgICAgICAgICB9KSlcbiAgICAgICAgXSk7XG4gICAgICAgIC8vIC8vIEFuaW1hdGUgdG8gcHJlc2VudCB0aGUgY3VycmVudGx5LWFjdGl2ZSBjbG9ja1xuICAgICAgICAvLyBjbG9ja0tleS5zd2l0Y2hUb01vZGUoa2V5RWxlbXMkLCBgcHJlc2VudCR7dGhpcy5kb2N1bWVudC5jdXJyZW50Q2xvY2suaW5kZXh9YCBhcyBDbG9ja0tleURpc3BsYXlNb2RlKVxuICAgICAgICAvLyAgIC5wbGF5KCk7XG4gICAgfVxufVxuZXhwb3J0IGRlZmF1bHQgQmxhZGVzUHJvamVjdFNoZWV0O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///./ts/sheets/item/BladesProjectSheet.ts\n"); + +/***/ }), + +/***/ "./ts/sheets/item/BladesScoreSheet.ts": +/*!********************************************!*\ + !*** ./ts/sheets/item/BladesScoreSheet.ts ***! + \********************************************/ +/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ BladesTipContext: function() { return /* binding */ BladesTipContext; },\n/* harmony export */ BladesTipGenerator: function() { return /* binding */ BladesTipGenerator; }\n/* harmony export */ });\n/* harmony import */ var _core_utilities__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../../core/utilities */ \"./ts/core/utilities.ts\");\n/* harmony import */ var _core_constants__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../../core/constants */ \"./ts/core/constants.ts\");\n/* harmony import */ var _BladesItemSheet__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./BladesItemSheet */ \"./ts/sheets/item/BladesItemSheet.ts\");\n/* harmony import */ var _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../../documents/BladesActorProxy */ \"./ts/documents/BladesActorProxy.ts\");\n/* harmony import */ var _documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ../../documents/BladesItemProxy */ \"./ts/documents/BladesItemProxy.ts\");\n/* harmony import */ var _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ../../classes/BladesRoll */ \"./ts/classes/BladesRoll.ts\");\n\n\n\n\n\n\n/* #region BladesTipGenerator */\nvar BladesTipContext;\n(function (BladesTipContext) {\n BladesTipContext[\"DiceRoll\"] = \"DiceRoll\";\n BladesTipContext[\"Combat\"] = \"Combat\";\n BladesTipContext[\"General\"] = \"General\";\n})(BladesTipContext || (BladesTipContext = {}));\nclass BladesTipGenerator {\n static get Tips() {\n return {\n [BladesTipContext.DiceRoll]: [],\n [BladesTipContext.Combat]: [\n \"Every combat encounter should advance the main plot, or else it's filler.\",\n \"Inject dialogue into combat encounters, especially from important adversaries.\",\n \"Combat encounters should be a challenge, but not a slog. Don't be afraid to end them early.\",\n \"Infiltrate/Rescue/Destroy: Use these as additional/secondary goals in combat encounters.\",\n \"Tell the next player in the initiative order that they're on deck.\",\n \"Don't trigger combats automatically: Use alternate objectives to incite the players to fight, giving them agency.\",\n \"Add another layer by drawing focus to collateral effects of the combat: a fire, a hostage, a collapsing building, innocents in danger\"\n ],\n [BladesTipContext.General]: [\n \"Rolling the dice always means SOMETHING happens.\",\n \"Jump straight to the action; don't waste time on establishing scenes or filler.\",\n \"Invoke elements of characters' backstories or beliefs to make any scene more personal.\"\n ]\n };\n }\n tipContext;\n constructor(tipContext) {\n this.tipContext = tipContext;\n }\n}\n/* #endregion */\nclass BladesScoreSheet extends _BladesItemSheet__WEBPACK_IMPORTED_MODULE_2__[\"default\"] {\n static get defaultOptions() {\n return foundry.utils.mergeObject(super.defaultOptions, {\n classes: [\"eunos-blades\", \"sheet\", \"item\", \"score-sheet\"],\n template: \"systems/eunos-blades/templates/items/score-sheet.hbs\",\n width: 900,\n submitOnChange: false,\n height: 970\n });\n }\n async generateRandomizerData(category) {\n // Generate full set of random data.\n const randomData = {\n Bargains: Object.fromEntries(Object.entries(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sample(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.GM.Bargains\n .filter((bData) => !Object.values(this.document.system.randomizers.Bargains)\n .some((_bData) => _bData.name === bData.name || _bData.effect === bData.effect)), 3, true, (e, a) => a\n .filter((_e) => e.category === _e.category).length === 0))\n .map(([k, v]) => {\n k = `${k}`;\n Object.assign(v, { notes: \"\" });\n return [k, v];\n })),\n Obstacles: Object.fromEntries(Object.entries(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sample(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.GM.Obstacles\n .filter((bData) => !Object.values(this.document.system.randomizers.Obstacles)\n .some((_bData) => _bData.name === bData.name || _bData.desc === bData.desc)), 3, true, (e, a) => a\n .filter((_e) => e.category === _e.category).length === 0))\n .map(([k, v]) => {\n k = `${k}`;\n Object.assign(v, { notes: \"\" });\n return [k, v];\n })),\n NPCs: Object.fromEntries(Object.entries(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sample(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.GM.NPCs\n .filter((bData) => !Object.values(this.document.system.randomizers.NPCs)\n .some((_bData) => _bData.name === bData.name\n || _bData.description === bData.description)), 3, true, (e, a) => a\n .filter((_e) => e.arena === _e.arena).length === 0))\n .map(([k, v]) => {\n k = `${k}`;\n Object.assign(v, { notes: \"\" });\n return [k, v];\n })),\n Scores: Object.fromEntries(Object.entries(_core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].sample(_core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.GM.Scores\n .filter((bData) => !Object.values(this.document.system.randomizers.Scores)\n .some((_bData) => _bData.name === bData.name || _bData.desc === bData.desc)), 3, true, (e, a) => a\n .filter((_e) => e.category === _e.category).length === 0))\n .map(([k, v]) => {\n k = `${k}`;\n Object.assign(v, { notes: \"\" });\n return [k, v];\n }))\n };\n // If category specified, replace all other categories with stored data\n if (category) {\n Object.keys(randomData)\n .filter((cat) => cat !== category)\n .forEach((cat) => {\n const _cat = cat;\n randomData[_cat] = this.document.system.randomizers[_cat];\n });\n }\n // Combine locked data stored in system with randomly-generated data\n const finalRandomData = {\n Bargains: {},\n Obstacles: {},\n NPCs: {},\n Scores: {}\n };\n // Iterate through all randomizer categories. If system entry isLocked, use that, or use newly-generated data\n Object.keys(randomData).forEach((cat) => {\n const _cat = cat;\n Object.keys(randomData[_cat]).forEach((index) => {\n if (this.document.system.randomizers?.[_cat][index].isLocked) {\n finalRandomData[_cat][index] = this.document.system.randomizers[_cat][index];\n }\n else {\n finalRandomData[_cat][index] = randomData[_cat][index];\n }\n });\n });\n // Overwrite stored data with newly generated & merged randomizer data\n await this.document.update({ \"system.randomizers\": finalRandomData });\n }\n getData() {\n const context = super.getData();\n const sheetData = {};\n // Get player characters, assign simplified actionData that I probably should have coded them with from the start\n sheetData.playerCharacters = _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.GetTypeWithTags(_core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc, _core_constants__WEBPACK_IMPORTED_MODULE_1__.Tag.PC.ActivePC)\n .map((pc) => {\n return Object.assign(pc, {\n actionData: Object.fromEntries(Object.entries(pc.system.attributes)\n .map(([attrName, attrData]) => {\n return [\n attrName,\n Object.fromEntries(Object.entries(attrData)\n .map(([actionName, actionData]) => {\n return [\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].uCase(actionName).slice(0, 3),\n actionData\n ];\n }))\n ];\n }))\n });\n });\n // Prune system data for blank/empty opposition entries\n const validOppositions = {};\n for (const [id, data] of Object.entries(context.system.oppositions)) {\n if (!data.rollOppName && !data.rollOppSubName) {\n continue;\n }\n validOppositions[id] = data;\n }\n context.system.oppositions = validOppositions;\n return {\n ...context,\n ...sheetData\n };\n }\n _toggleRandomizerLock(event) {\n const elem$ = $(event.currentTarget);\n const elemCat = elem$.data(\"category\");\n const elemIndex = `${elem$.data(\"index\")}`;\n const elemValue = elem$.data(\"value\");\n if (`${elemValue}` === \"true\") {\n this.document.update({ [`system.randomizers.${elemCat}.${elemIndex}.isLocked`]: false });\n }\n else {\n this.document.update({ [`system.randomizers.${elemCat}.${elemIndex}.isLocked`]: true });\n }\n }\n _selectImage(event) {\n const elem$ = $(event.currentTarget);\n const imageNum = elem$.data(\"imgNum\");\n this.document.update({ \"system.imageSelected\": imageNum });\n }\n _deselectOrDeleteImage(event) {\n const elem$ = $(event.currentTarget);\n const imageNum = elem$.data(\"imgNum\");\n if (this.document.system.imageSelected === imageNum) {\n this.document.update({ \"system.-=imageSelected\": null });\n return;\n }\n const images = { ...this.document.system.images };\n this.document.update({ \"system.-=images\": null }).then(() => this.document.update({\n \"system.images\": Object.fromEntries(Object.entries(Object.values(images)\n .filter((_, i) => _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].pInt(imageNum) !== i)))\n }));\n }\n _addImage() {\n _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].displayImageSelector((path) => {\n const imgIndex = _core_utilities__WEBPACK_IMPORTED_MODULE_0__[\"default\"].objSize(this.document.system.images);\n return this.document.update({ [`system.images.${imgIndex}`]: path });\n }, \"systems/eunos-blades/assets\", this.position);\n }\n _selectRollOpposition(event) {\n eLog.checkLog3(\"Select Roll Opposition\", { event });\n const elem$ = $(event.currentTarget);\n const oppId = elem$.data(\"oppId\");\n this.document.update({ \"system.oppositionSelected\": oppId });\n if (_documents_BladesItemProxy__WEBPACK_IMPORTED_MODULE_4__.BladesScore.Active?.id === this.document.id && _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_5__[\"default\"].Active) {\n _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_5__[\"default\"].Active.rollOpposition = new _classes_BladesRoll__WEBPACK_IMPORTED_MODULE_5__.BladesRollOpposition(_classes_BladesRoll__WEBPACK_IMPORTED_MODULE_5__[\"default\"].Active, this.document.system.oppositions[oppId]);\n }\n }\n _triggerRandomize(event) {\n const elem$ = $(event.currentTarget);\n const category = elem$.data(\"category\");\n if (category && category in _core_constants__WEBPACK_IMPORTED_MODULE_1__.Randomizers.GM) {\n this.generateRandomizerData(category);\n }\n else {\n this.generateRandomizerData();\n }\n }\n async _updateGMNotesOnPC(event) {\n const elem$ = $(event.currentTarget);\n const actor = _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.Get(elem$.data(\"id\"));\n if (!actor) {\n throw new Error(`Unable to retrieve actor with id '${elem$.data(\"id\")}'`);\n }\n const updateText = event.currentTarget.innerHTML;\n eLog.checkLog3(\"scoreSheet\", \"Retrieved Text, Updating ...\", { updateText });\n await actor.update({ \"system.gm_notes\": updateText });\n eLog.checkLog3(\"scoreSheet\", \"Updated!\", { gm_notes: actor.system.gm_notes });\n }\n async activateListeners(html) {\n super.activateListeners(html);\n html.find(\"[data-action='select-image']\").on({\n click: this._selectImage.bind(this),\n contextmenu: this._deselectOrDeleteImage.bind(this)\n });\n html.find(\"[data-action='add-image']\").on({\n click: this._addImage.bind(this)\n });\n html.find(\".roll-opposition-name\").on({\n dblclick: this._selectRollOpposition.bind(this)\n });\n html.find(\".toggle-lock\").on({\n click: this._toggleRandomizerLock.bind(this)\n });\n html.find(\"[data-action='randomize'\").on({\n click: this._triggerRandomize.bind(this)\n });\n html.find(\"textarea.pc-summary-notes-body\").on({\n change: this._updateGMNotesOnPC.bind(this)\n });\n }\n async _onSubmit(event, params = {}) {\n // eLog.checkLog3(\"scoreSheet\", \"_onSubmit()\", {event, params, elemText: event.currentTarget.innerHTML});\n let isForcingRender = true;\n const prevPhase = this.item.system.phase;\n const submitData = await super._onSubmit(event, params);\n const newPhase = this.item.system.phase;\n if (prevPhase !== newPhase) {\n switch (prevPhase) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.CharGen: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Freeplay: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Score: {\n isForcingRender = false;\n game.actors.filter((actor) => _documents_BladesActorProxy__WEBPACK_IMPORTED_MODULE_3__.BladesActor.IsType(actor, _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc))\n .forEach((actor) => actor.clearLoadout());\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Downtime: {\n break;\n }\n // No default\n }\n switch (newPhase) {\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.CharGen: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Freeplay: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Score: {\n break;\n }\n case _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesPhase.Downtime: {\n break;\n }\n // No default\n }\n }\n if (isForcingRender) {\n game.actors.filter((actor) => actor.type === _core_constants__WEBPACK_IMPORTED_MODULE_1__.BladesActorType.pc)\n .forEach((actor) => actor.sheet?.render());\n }\n return submitData;\n }\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (BladesScoreSheet);\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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Q2xGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0Msd0RBQVc7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQixvRUFBVztBQUNqQztBQUNBLGlFQUFpRSxpQkFBaUI7QUFDbEY7QUFDQTtBQUNBLHVFQUF1RSxZQUFZO0FBQ25GLDZCQUE2QiwrQkFBK0I7QUFDNUQsbURBQW1ELGlDQUFpQztBQUNwRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0E7QUFDQSxTQUFTO0FBQ1Q7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsU0FBUztBQUNUO0FBQ0Esc0NBQXNDO0FBQ3RDLHdEQUF3RCx1REFBdUQ7QUFDL0c7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLHdEQUFXO0FBQ2hDO0FBQ0E7QUFDQSxxQkFBcUIsd0RBQVc7QUFDaEM7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBLGtEQUFrRCxvRUFBVyxlQUFlLDREQUFlO0FBQzNGO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUJBQXFCLHdEQUFXO0FBQ2hDO0FBQ0E7QUFDQSxxQkFBcUIsd0RBQVc7QUFDaEM7QUFDQTtBQUNBLHFCQUFxQix3REFBVztBQUNoQztBQUNBO0FBQ0EscUJBQXFCLHdEQUFXO0FBQ2hDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHlEQUF5RCw0REFBZTtBQUN4RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQzhCO0FBQzlCLCtEQUFlLGdCQUFnQixFQUFDIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vZXVub3MtYmxhZGVzLy4vdHMvc2hlZXRzL2l0ZW0vQmxhZGVzU2NvcmVTaGVldC50cz85ZWE4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBVIGZyb20gXCIuLi8uLi9jb3JlL3V0aWxpdGllc1wiO1xuaW1wb3J0IHsgQmxhZGVzQWN0b3JUeXBlLCBCbGFkZXNQaGFzZSwgVGFnLCBSYW5kb21pemVycyB9IGZyb20gXCIuLi8uLi9jb3JlL2NvbnN0YW50c1wiO1xuaW1wb3J0IEJsYWRlc0l0ZW1TaGVldCBmcm9tIFwiLi9CbGFkZXNJdGVtU2hlZXRcIjtcbmltcG9ydCB7IEJsYWRlc0FjdG9yIH0gZnJvbSBcIi4uLy4uL2RvY3VtZW50cy9CbGFkZXNBY3RvclByb3h5XCI7XG5pbXBvcnQgeyBCbGFkZXNTY29yZSB9IGZyb20gXCIuLi8uLi9kb2N1bWVudHMvQmxhZGVzSXRlbVByb3h5XCI7XG5pbXBvcnQgQmxhZGVzUm9sbCwgeyBCbGFkZXNSb2xsT3Bwb3NpdGlvbiB9IGZyb20gXCIuLi8uLi9jbGFzc2VzL0JsYWRlc1JvbGxcIjtcbi8qICNyZWdpb24gQmxhZGVzVGlwR2VuZXJhdG9yICovXG5leHBvcnQgdmFyIEJsYWRlc1RpcENvbnRleHQ7XG4oZnVuY3Rpb24gKEJsYWRlc1RpcENvbnRleHQpIHtcbiAgICBCbGFkZXNUaXBDb250ZXh0W1wiRGljZVJvbGxcIl0gPSBcIkRpY2VSb2xsXCI7XG4gICAgQmxhZGVzVGlwQ29udGV4dFtcIkNvbWJhdFwiXSA9IFwiQ29tYmF0XCI7XG4gICAgQmxhZGVzVGlwQ29udGV4dFtcIkdlbmVyYWxcIl0gPSBcIkdlbmVyYWxcIjtcbn0pKEJsYWRlc1RpcENvbnRleHQgfHwgKEJsYWRlc1RpcENvbnRleHQgPSB7fSkpO1xuY2xhc3MgQmxhZGVzVGlwR2VuZXJhdG9yIHtcbiAgICBzdGF0aWMgZ2V0IFRpcHMoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBbQmxhZGVzVGlwQ29udGV4dC5EaWNlUm9sbF06IFtdLFxuICAgICAgICAgICAgW0JsYWRlc1RpcENvbnRleHQuQ29tYmF0XTogW1xuICAgICAgICAgICAgICAgIFwiRXZlcnkgY29tYmF0IGVuY291bnRlciBzaG91bGQgYWR2YW5jZSB0aGUgbWFpbiBwbG90LCBvciBlbHNlIGl0J3MgZmlsbGVyLlwiLFxuICAgICAgICAgICAgICAgIFwiSW5qZWN0IGRpYWxvZ3VlIGludG8gY29tYmF0IGVuY291bnRlcnMsIGVzcGVjaWFsbHkgZnJvbSBpbXBvcnRhbnQgYWR2ZXJzYXJpZXMuXCIsXG4gICAgICAgICAgICAgICAgXCJDb21iYXQgZW5jb3VudGVycyBzaG91bGQgYmUgYSBjaGFsbGVuZ2UsIGJ1dCBub3QgYSBzbG9nLiBEb24ndCBiZSBhZnJhaWQgdG8gZW5kIHRoZW0gZWFybHkuXCIsXG4gICAgICAgICAgICAgICAgXCJJbmZpbHRyYXRlL1Jlc2N1ZS9EZXN0cm95OiBVc2UgdGhlc2UgYXMgYWRkaXRpb25hbC9zZWNvbmRhcnkgZ29hbHMgaW4gY29tYmF0IGVuY291bnRlcnMuXCIsXG4gICAgICAgICAgICAgICAgXCJUZWxsIHRoZSBuZXh0IHBsYXllciBpbiB0aGUgaW5pdGlhdGl2ZSBvcmRlciB0aGF0IHRoZXkncmUgb24gZGVjay5cIixcbiAgICAgICAgICAgICAgICBcIkRvbid0IHRyaWdnZXIgY29tYmF0cyBhdXRvbWF0aWNhbGx5OiBVc2UgYWx0ZXJuYXRlIG9iamVjdGl2ZXMgdG8gaW5jaXRlIHRoZSBwbGF5ZXJzIHRvIGZpZ2h0LCBnaXZpbmcgdGhlbSBhZ2VuY3kuXCIsXG4gICAgICAgICAgICAgICAgXCJBZGQgYW5vdGhlciBsYXllciBieSBkcmF3aW5nIGZvY3VzIHRvIGNvbGxhdGVyYWwgZWZmZWN0cyBvZiB0aGUgY29tYmF0OiBhIGZpcmUsIGEgaG9zdGFnZSwgYSBjb2xsYXBzaW5nIGJ1aWxkaW5nLCBpbm5vY2VudHMgaW4gZGFuZ2VyXCJcbiAgICAgICAgICAgIF0sXG4gICAgICAgICAgICBbQmxhZGVzVGlwQ29udGV4dC5HZW5lcmFsXTogW1xuICAgICAgICAgICAgICAgIFwiUm9sbGluZyB0aGUgZGljZSBhbHdheXMgbWVhbnMgU09NRVRISU5HIGhhcHBlbnMuXCIsXG4gICAgICAgICAgICAgICAgXCJKdW1wIHN0cmFpZ2h0IHRvIHRoZSBhY3Rpb247IGRvbid0IHdhc3RlIHRpbWUgb24gZXN0YWJsaXNoaW5nIHNjZW5lcyBvciBmaWxsZXIuXCIsXG4gICAgICAgICAgICAgICAgXCJJbnZva2UgZWxlbWVudHMgb2YgY2hhcmFjdGVycycgYmFja3N0b3JpZXMgb3IgYmVsaWVmcyB0byBtYWtlIGFueSBzY2VuZSBtb3JlIHBlcnNvbmFsLlwiXG4gICAgICAgICAgICBdXG4gICAgICAgIH07XG4gICAgfVxuICAgIHRpcENvbnRleHQ7XG4gICAgY29uc3RydWN0b3IodGlwQ29udGV4dCkge1xuICAgICAgICB0aGlzLnRpcENvbnRleHQgPSB0aXBDb250ZXh0O1xuICAgIH1cbn1cbi8qICNlbmRyZWdpb24gKi9cbmNsYXNzIEJsYWRlc1Njb3JlU2hlZXQgZXh0ZW5kcyBCbGFkZXNJdGVtU2hlZXQge1xuICAgIHN0YXRpYyBnZXQgZGVmYXVsdE9wdGlvbnMoKSB7XG4gICAgICAgIHJldHVybiBmb3VuZHJ5LnV0aWxzLm1lcmdlT2JqZWN0KHN1cGVyLmRlZmF1bHRPcHRpb25zLCB7XG4gICAgICAgICAgICBjbGFzc2VzOiBbXCJldW5vcy1ibGFkZXNcIiwgXCJzaGVldFwiLCBcIml0ZW1cIiwgXCJzY29yZS1zaGVldFwiXSxcbiAgICAgICAgICAgIHRlbXBsYXRlOiBcInN5c3RlbXMvZXVub3MtYmxhZGVzL3RlbXBsYXRlcy9pdGVtcy9zY29yZS1zaGVldC5oYnNcIixcbiAgICAgICAgICAgIHdpZHRoOiA5MDAsXG4gICAgICAgICAgICBzdWJtaXRPbkNoYW5nZTogZmFsc2UsXG4gICAgICAgICAgICBoZWlnaHQ6IDk3MFxuICAgICAgICB9KTtcbiAgICB9XG4gICAgYXN5bmMgZ2VuZXJhdGVSYW5kb21pemVyRGF0YShjYXRlZ29yeSkge1xuICAgICAgICAvLyBHZW5lcmF0ZSBmdWxsIHNldCBvZiByYW5kb20gZGF0YS5cbiAgICAgICAgY29uc3QgcmFuZG9tRGF0YSA9IHtcbiAgICAgICAgICAgIEJhcmdhaW5zOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoVS5zYW1wbGUoUmFuZG9taXplcnMuR00uQmFyZ2FpbnNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChiRGF0YSkgPT4gIU9iamVjdC52YWx1ZXModGhpcy5kb2N1bWVudC5zeXN0ZW0ucmFuZG9taXplcnMuQmFyZ2FpbnMpXG4gICAgICAgICAgICAgICAgLnNvbWUoKF9iRGF0YSkgPT4gX2JEYXRhLm5hbWUgPT09IGJEYXRhLm5hbWUgfHwgX2JEYXRhLmVmZmVjdCA9PT0gYkRhdGEuZWZmZWN0KSksIDMsIHRydWUsIChlLCBhKSA9PiBhXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoX2UpID0+IGUuY2F0ZWdvcnkgPT09IF9lLmNhdGVnb3J5KS5sZW5ndGggPT09IDApKVxuICAgICAgICAgICAgICAgIC5tYXAoKFtrLCB2XSkgPT4ge1xuICAgICAgICAgICAgICAgIGsgPSBgJHtrfWA7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih2LCB7IG5vdGVzOiBcIlwiIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiBbaywgdl07XG4gICAgICAgICAgICB9KSksXG4gICAgICAgICAgICBPYnN0YWNsZXM6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhVLnNhbXBsZShSYW5kb21pemVycy5HTS5PYnN0YWNsZXNcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChiRGF0YSkgPT4gIU9iamVjdC52YWx1ZXModGhpcy5kb2N1bWVudC5zeXN0ZW0ucmFuZG9taXplcnMuT2JzdGFjbGVzKVxuICAgICAgICAgICAgICAgIC5zb21lKChfYkRhdGEpID0+IF9iRGF0YS5uYW1lID09PSBiRGF0YS5uYW1lIHx8IF9iRGF0YS5kZXNjID09PSBiRGF0YS5kZXNjKSksIDMsIHRydWUsIChlLCBhKSA9PiBhXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoX2UpID0+IGUuY2F0ZWdvcnkgPT09IF9lLmNhdGVnb3J5KS5sZW5ndGggPT09IDApKVxuICAgICAgICAgICAgICAgIC5tYXAoKFtrLCB2XSkgPT4ge1xuICAgICAgICAgICAgICAgIGsgPSBgJHtrfWA7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih2LCB7IG5vdGVzOiBcIlwiIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiBbaywgdl07XG4gICAgICAgICAgICB9KSksXG4gICAgICAgICAgICBOUENzOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoVS5zYW1wbGUoUmFuZG9taXplcnMuR00uTlBDc1xuICAgICAgICAgICAgICAgIC5maWx0ZXIoKGJEYXRhKSA9PiAhT2JqZWN0LnZhbHVlcyh0aGlzLmRvY3VtZW50LnN5c3RlbS5yYW5kb21pemVycy5OUENzKVxuICAgICAgICAgICAgICAgIC5zb21lKChfYkRhdGEpID0+IF9iRGF0YS5uYW1lID09PSBiRGF0YS5uYW1lXG4gICAgICAgICAgICAgICAgfHwgX2JEYXRhLmRlc2NyaXB0aW9uID09PSBiRGF0YS5kZXNjcmlwdGlvbikpLCAzLCB0cnVlLCAoZSwgYSkgPT4gYVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKF9lKSA9PiBlLmFyZW5hID09PSBfZS5hcmVuYSkubGVuZ3RoID09PSAwKSlcbiAgICAgICAgICAgICAgICAubWFwKChbaywgdl0pID0+IHtcbiAgICAgICAgICAgICAgICBrID0gYCR7a31gO1xuICAgICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24odiwgeyBub3RlczogXCJcIiB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gW2ssIHZdO1xuICAgICAgICAgICAgfSkpLFxuICAgICAgICAgICAgU2NvcmVzOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMoVS5zYW1wbGUoUmFuZG9taXplcnMuR00uU2NvcmVzXG4gICAgICAgICAgICAgICAgLmZpbHRlcigoYkRhdGEpID0+ICFPYmplY3QudmFsdWVzKHRoaXMuZG9jdW1lbnQuc3lzdGVtLnJhbmRvbWl6ZXJzLlNjb3JlcylcbiAgICAgICAgICAgICAgICAuc29tZSgoX2JEYXRhKSA9PiBfYkRhdGEubmFtZSA9PT0gYkRhdGEubmFtZSB8fCBfYkRhdGEuZGVzYyA9PT0gYkRhdGEuZGVzYykpLCAzLCB0cnVlLCAoZSwgYSkgPT4gYVxuICAgICAgICAgICAgICAgIC5maWx0ZXIoKF9lKSA9PiBlLmNhdGVnb3J5ID09PSBfZS5jYXRlZ29yeSkubGVuZ3RoID09PSAwKSlcbiAgICAgICAgICAgICAgICAubWFwKChbaywgdl0pID0+IHtcbiAgICAgICAgICAgICAgICBrID0gYCR7a31gO1xuICAgICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24odiwgeyBub3RlczogXCJcIiB9KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gW2ssIHZdO1xuICAgICAgICAgICAgfSkpXG4gICAgICAgIH07XG4gICAgICAgIC8vIElmIGNhdGVnb3J5IHNwZWNpZmllZCwgcmVwbGFjZSBhbGwgb3RoZXIgY2F0ZWdvcmllcyB3aXRoIHN0b3JlZCBkYXRhXG4gICAgICAgIGlmIChjYXRlZ29yeSkge1xuICAgICAgICAgICAgT2JqZWN0LmtleXMocmFuZG9tRGF0YSlcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChjYXQpID0+IGNhdCAhPT0gY2F0ZWdvcnkpXG4gICAgICAgICAgICAgICAgLmZvckVhY2goKGNhdCkgPT4ge1xuICAgICAgICAgICAgICAgIGNvbnN0IF9jYXQgPSBjYXQ7XG4gICAgICAgICAgICAgICAgcmFuZG9tRGF0YVtfY2F0XSA9IHRoaXMuZG9jdW1lbnQuc3lzdGVtLnJhbmRvbWl6ZXJzW19jYXRdO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ29tYmluZSBsb2NrZWQgZGF0YSBzdG9yZWQgaW4gc3lzdGVtIHdpdGggcmFuZG9tbHktZ2VuZXJhdGVkIGRhdGFcbiAgICAgICAgY29uc3QgZmluYWxSYW5kb21EYXRhID0ge1xuICAgICAgICAgICAgQmFyZ2FpbnM6IHt9LFxuICAgICAgICAgICAgT2JzdGFjbGVzOiB7fSxcbiAgICAgICAgICAgIE5QQ3M6IHt9LFxuICAgICAgICAgICAgU2NvcmVzOiB7fVxuICAgICAgICB9O1xuICAgICAgICAvLyBJdGVyYXRlIHRocm91Z2ggYWxsIHJhbmRvbWl6ZXIgY2F0ZWdvcmllcy4gSWYgc3lzdGVtIGVudHJ5IGlzTG9ja2VkLCB1c2UgdGhhdCwgb3IgdXNlIG5ld2x5LWdlbmVyYXRlZCBkYXRhXG4gICAgICAgIE9iamVjdC5rZXlzKHJhbmRvbURhdGEpLmZvckVhY2goKGNhdCkgPT4ge1xuICAgICAgICAgICAgY29uc3QgX2NhdCA9IGNhdDtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHJhbmRvbURhdGFbX2NhdF0pLmZvckVhY2goKGluZGV4KSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZG9jdW1lbnQuc3lzdGVtLnJhbmRvbWl6ZXJzPy5bX2NhdF1baW5kZXhdLmlzTG9ja2VkKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbmFsUmFuZG9tRGF0YVtfY2F0XVtpbmRleF0gPSB0aGlzLmRvY3VtZW50LnN5c3RlbS5yYW5kb21pemVyc1tfY2F0XVtpbmRleF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBmaW5hbFJhbmRvbURhdGFbX2NhdF1baW5kZXhdID0gcmFuZG9tRGF0YVtfY2F0XVtpbmRleF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBPdmVyd3JpdGUgc3RvcmVkIGRhdGEgd2l0aCBuZXdseSBnZW5lcmF0ZWQgJiBtZXJnZWQgcmFuZG9taXplciBkYXRhXG4gICAgICAgIGF3YWl0IHRoaXMuZG9jdW1lbnQudXBkYXRlKHsgXCJzeXN0ZW0ucmFuZG9taXplcnNcIjogZmluYWxSYW5kb21EYXRhIH0pO1xuICAgIH1cbiAgICBnZXREYXRhKCkge1xuICAgICAgICBjb25zdCBjb250ZXh0ID0gc3VwZXIuZ2V0RGF0YSgpO1xuICAgICAgICBjb25zdCBzaGVldERhdGEgPSB7fTtcbiAgICAgICAgLy8gR2V0IHBsYXllciBjaGFyYWN0ZXJzLCBhc3NpZ24gc2ltcGxpZmllZCBhY3Rpb25EYXRhIHRoYXQgSSBwcm9iYWJseSBzaG91bGQgaGF2ZSBjb2RlZCB0aGVtIHdpdGggZnJvbSB0aGUgc3RhcnRcbiAgICAgICAgc2hlZXREYXRhLnBsYXllckNoYXJhY3RlcnMgPSBCbGFkZXNBY3Rvci5HZXRUeXBlV2l0aFRhZ3MoQmxhZGVzQWN0b3JUeXBlLnBjLCBUYWcuUEMuQWN0aXZlUEMpXG4gICAgICAgICAgICAubWFwKChwYykgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5hc3NpZ24ocGMsIHtcbiAgICAgICAgICAgICAgICBhY3Rpb25EYXRhOiBPYmplY3QuZnJvbUVudHJpZXMoT2JqZWN0LmVudHJpZXMocGMuc3lzdGVtLmF0dHJpYnV0ZXMpXG4gICAgICAgICAgICAgICAgICAgIC5tYXAoKFthdHRyTmFtZSwgYXR0ckRhdGFdKSA9PiB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICAgICAgICAgICAgICBhdHRyTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhhdHRyRGF0YSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAubWFwKChbYWN0aW9uTmFtZSwgYWN0aW9uRGF0YV0pID0+IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBVLnVDYXNlKGFjdGlvbk5hbWUpLnNsaWNlKDAsIDMpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBhY3Rpb25EYXRhXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgICAgICAgICBdO1xuICAgICAgICAgICAgICAgIH0pKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgICAvLyBQcnVuZSBzeXN0ZW0gZGF0YSBmb3IgYmxhbmsvZW1wdHkgb3Bwb3NpdGlvbiBlbnRyaWVzXG4gICAgICAgIGNvbnN0IHZhbGlkT3Bwb3NpdGlvbnMgPSB7fTtcbiAgICAgICAgZm9yIChjb25zdCBbaWQsIGRhdGFdIG9mIE9iamVjdC5lbnRyaWVzKGNvbnRleHQuc3lzdGVtLm9wcG9zaXRpb25zKSkge1xuICAgICAgICAgICAgaWYgKCFkYXRhLnJvbGxPcHBOYW1lICYmICFkYXRhLnJvbGxPcHBTdWJOYW1lKSB7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWxpZE9wcG9zaXRpb25zW2lkXSA9IGRhdGE7XG4gICAgICAgIH1cbiAgICAgICAgY29udGV4dC5zeXN0ZW0ub3Bwb3NpdGlvbnMgPSB2YWxpZE9wcG9zaXRpb25zO1xuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgLi4uY29udGV4dCxcbiAgICAgICAgICAgIC4uLnNoZWV0RGF0YVxuICAgICAgICB9O1xuICAgIH1cbiAgICBfdG9nZ2xlUmFuZG9taXplckxvY2soZXZlbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBlbGVtQ2F0ID0gZWxlbSQuZGF0YShcImNhdGVnb3J5XCIpO1xuICAgICAgICBjb25zdCBlbGVtSW5kZXggPSBgJHtlbGVtJC5kYXRhKFwiaW5kZXhcIil9YDtcbiAgICAgICAgY29uc3QgZWxlbVZhbHVlID0gZWxlbSQuZGF0YShcInZhbHVlXCIpO1xuICAgICAgICBpZiAoYCR7ZWxlbVZhbHVlfWAgPT09IFwidHJ1ZVwiKSB7XG4gICAgICAgICAgICB0aGlzLmRvY3VtZW50LnVwZGF0ZSh7IFtgc3lzdGVtLnJhbmRvbWl6ZXJzLiR7ZWxlbUNhdH0uJHtlbGVtSW5kZXh9LmlzTG9ja2VkYF06IGZhbHNlIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5kb2N1bWVudC51cGRhdGUoeyBbYHN5c3RlbS5yYW5kb21pemVycy4ke2VsZW1DYXR9LiR7ZWxlbUluZGV4fS5pc0xvY2tlZGBdOiB0cnVlIH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIF9zZWxlY3RJbWFnZShldmVudCkge1xuICAgICAgICBjb25zdCBlbGVtJCA9ICQoZXZlbnQuY3VycmVudFRhcmdldCk7XG4gICAgICAgIGNvbnN0IGltYWdlTnVtID0gZWxlbSQuZGF0YShcImltZ051bVwiKTtcbiAgICAgICAgdGhpcy5kb2N1bWVudC51cGRhdGUoeyBcInN5c3RlbS5pbWFnZVNlbGVjdGVkXCI6IGltYWdlTnVtIH0pO1xuICAgIH1cbiAgICBfZGVzZWxlY3RPckRlbGV0ZUltYWdlKGV2ZW50KSB7XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgaW1hZ2VOdW0gPSBlbGVtJC5kYXRhKFwiaW1nTnVtXCIpO1xuICAgICAgICBpZiAodGhpcy5kb2N1bWVudC5zeXN0ZW0uaW1hZ2VTZWxlY3RlZCA9PT0gaW1hZ2VOdW0pIHtcbiAgICAgICAgICAgIHRoaXMuZG9jdW1lbnQudXBkYXRlKHsgXCJzeXN0ZW0uLT1pbWFnZVNlbGVjdGVkXCI6IG51bGwgfSk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgaW1hZ2VzID0geyAuLi50aGlzLmRvY3VtZW50LnN5c3RlbS5pbWFnZXMgfTtcbiAgICAgICAgdGhpcy5kb2N1bWVudC51cGRhdGUoeyBcInN5c3RlbS4tPWltYWdlc1wiOiBudWxsIH0pLnRoZW4oKCkgPT4gdGhpcy5kb2N1bWVudC51cGRhdGUoe1xuICAgICAgICAgICAgXCJzeXN0ZW0uaW1hZ2VzXCI6IE9iamVjdC5mcm9tRW50cmllcyhPYmplY3QuZW50cmllcyhPYmplY3QudmFsdWVzKGltYWdlcylcbiAgICAgICAgICAgICAgICAuZmlsdGVyKChfLCBpKSA9PiBVLnBJbnQoaW1hZ2VOdW0pICE9PSBpKSkpXG4gICAgICAgIH0pKTtcbiAgICB9XG4gICAgX2FkZEltYWdlKCkge1xuICAgICAgICBVLmRpc3BsYXlJbWFnZVNlbGVjdG9yKChwYXRoKSA9PiB7XG4gICAgICAgICAgICBjb25zdCBpbWdJbmRleCA9IFUub2JqU2l6ZSh0aGlzLmRvY3VtZW50LnN5c3RlbS5pbWFnZXMpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZG9jdW1lbnQudXBkYXRlKHsgW2BzeXN0ZW0uaW1hZ2VzLiR7aW1nSW5kZXh9YF06IHBhdGggfSk7XG4gICAgICAgIH0sIFwic3lzdGVtcy9ldW5vcy1ibGFkZXMvYXNzZXRzXCIsIHRoaXMucG9zaXRpb24pO1xuICAgIH1cbiAgICBfc2VsZWN0Um9sbE9wcG9zaXRpb24oZXZlbnQpIHtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJTZWxlY3QgUm9sbCBPcHBvc2l0aW9uXCIsIHsgZXZlbnQgfSk7XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3Qgb3BwSWQgPSBlbGVtJC5kYXRhKFwib3BwSWRcIik7XG4gICAgICAgIHRoaXMuZG9jdW1lbnQudXBkYXRlKHsgXCJzeXN0ZW0ub3Bwb3NpdGlvblNlbGVjdGVkXCI6IG9wcElkIH0pO1xuICAgICAgICBpZiAoQmxhZGVzU2NvcmUuQWN0aXZlPy5pZCA9PT0gdGhpcy5kb2N1bWVudC5pZCAmJiBCbGFkZXNSb2xsLkFjdGl2ZSkge1xuICAgICAgICAgICAgQmxhZGVzUm9sbC5BY3RpdmUucm9sbE9wcG9zaXRpb24gPSBuZXcgQmxhZGVzUm9sbE9wcG9zaXRpb24oQmxhZGVzUm9sbC5BY3RpdmUsIHRoaXMuZG9jdW1lbnQuc3lzdGVtLm9wcG9zaXRpb25zW29wcElkXSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgX3RyaWdnZXJSYW5kb21pemUoZXZlbnQpIHtcbiAgICAgICAgY29uc3QgZWxlbSQgPSAkKGV2ZW50LmN1cnJlbnRUYXJnZXQpO1xuICAgICAgICBjb25zdCBjYXRlZ29yeSA9IGVsZW0kLmRhdGEoXCJjYXRlZ29yeVwiKTtcbiAgICAgICAgaWYgKGNhdGVnb3J5ICYmIGNhdGVnb3J5IGluIFJhbmRvbWl6ZXJzLkdNKSB7XG4gICAgICAgICAgICB0aGlzLmdlbmVyYXRlUmFuZG9taXplckRhdGEoY2F0ZWdvcnkpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5nZW5lcmF0ZVJhbmRvbWl6ZXJEYXRhKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgYXN5bmMgX3VwZGF0ZUdNTm90ZXNPblBDKGV2ZW50KSB7XG4gICAgICAgIGNvbnN0IGVsZW0kID0gJChldmVudC5jdXJyZW50VGFyZ2V0KTtcbiAgICAgICAgY29uc3QgYWN0b3IgPSBCbGFkZXNBY3Rvci5HZXQoZWxlbSQuZGF0YShcImlkXCIpKTtcbiAgICAgICAgaWYgKCFhY3Rvcikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbmFibGUgdG8gcmV0cmlldmUgYWN0b3Igd2l0aCBpZCAnJHtlbGVtJC5kYXRhKFwiaWRcIil9J2ApO1xuICAgICAgICB9XG4gICAgICAgIGNvbnN0IHVwZGF0ZVRleHQgPSBldmVudC5jdXJyZW50VGFyZ2V0LmlubmVySFRNTDtcbiAgICAgICAgZUxvZy5jaGVja0xvZzMoXCJzY29yZVNoZWV0XCIsIFwiUmV0cmlldmVkIFRleHQsIFVwZGF0aW5nIC4uLlwiLCB7IHVwZGF0ZVRleHQgfSk7XG4gICAgICAgIGF3YWl0IGFjdG9yLnVwZGF0ZSh7IFwic3lzdGVtLmdtX25vdGVzXCI6IHVwZGF0ZVRleHQgfSk7XG4gICAgICAgIGVMb2cuY2hlY2tMb2czKFwic2NvcmVTaGVldFwiLCBcIlVwZGF0ZWQhXCIsIHsgZ21fbm90ZXM6IGFjdG9yLnN5c3RlbS5nbV9ub3RlcyB9KTtcbiAgICB9XG4gICAgYXN5bmMgYWN0aXZhdGVMaXN0ZW5lcnMoaHRtbCkge1xuICAgICAgICBzdXBlci5hY3RpdmF0ZUxpc3RlbmVycyhodG1sKTtcbiAgICAgICAgaHRtbC5maW5kKFwiW2RhdGEtYWN0aW9uPSdzZWxlY3QtaW1hZ2UnXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fc2VsZWN0SW1hZ2UuYmluZCh0aGlzKSxcbiAgICAgICAgICAgIGNvbnRleHRtZW51OiB0aGlzLl9kZXNlbGVjdE9yRGVsZXRlSW1hZ2UuYmluZCh0aGlzKVxuICAgICAgICB9KTtcbiAgICAgICAgaHRtbC5maW5kKFwiW2RhdGEtYWN0aW9uPSdhZGQtaW1hZ2UnXVwiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fYWRkSW1hZ2UuYmluZCh0aGlzKVxuICAgICAgICB9KTtcbiAgICAgICAgaHRtbC5maW5kKFwiLnJvbGwtb3Bwb3NpdGlvbi1uYW1lXCIpLm9uKHtcbiAgICAgICAgICAgIGRibGNsaWNrOiB0aGlzLl9zZWxlY3RSb2xsT3Bwb3NpdGlvbi5iaW5kKHRoaXMpXG4gICAgICAgIH0pO1xuICAgICAgICBodG1sLmZpbmQoXCIudG9nZ2xlLWxvY2tcIikub24oe1xuICAgICAgICAgICAgY2xpY2s6IHRoaXMuX3RvZ2dsZVJhbmRvbWl6ZXJMb2NrLmJpbmQodGhpcylcbiAgICAgICAgfSk7XG4gICAgICAgIGh0bWwuZmluZChcIltkYXRhLWFjdGlvbj0ncmFuZG9taXplJ1wiKS5vbih7XG4gICAgICAgICAgICBjbGljazogdGhpcy5fdHJpZ2dlclJhbmRvbWl6ZS5iaW5kKHRoaXMpXG4gICAgICAgIH0pO1xuICAgICAgICBodG1sLmZpbmQoXCJ0ZXh0YXJlYS5wYy1zdW1tYXJ5LW5vdGVzLWJvZHlcIikub24oe1xuICAgICAgICAgICAgY2hhbmdlOiB0aGlzLl91cGRhdGVHTU5vdGVzT25QQy5iaW5kKHRoaXMpXG4gICAgICAgIH0pO1xuICAgIH1cbiAgICBhc3luYyBfb25TdWJtaXQoZXZlbnQsIHBhcmFtcyA9IHt9KSB7XG4gICAgICAgIC8vIGVMb2cuY2hlY2tMb2czKFwic2NvcmVTaGVldFwiLCBcIl9vblN1Ym1pdCgpXCIsIHtldmVudCwgcGFyYW1zLCBlbGVtVGV4dDogZXZlbnQuY3VycmVudFRhcmdldC5pbm5lckhUTUx9KTtcbiAgICAgICAgbGV0IGlzRm9yY2luZ1JlbmRlciA9IHRydWU7XG4gICAgICAgIGNvbnN0IHByZXZQaGFzZSA9IHRoaXMuaXRlbS5zeXN0ZW0ucGhhc2U7XG4gICAgICAgIGNvbnN0IHN1Ym1pdERhdGEgPSBhd2FpdCBzdXBlci5fb25TdWJtaXQoZXZlbnQsIHBhcmFtcyk7XG4gICAgICAgIGNvbnN0IG5ld1BoYXNlID0gdGhpcy5pdGVtLnN5c3RlbS5waGFzZTtcbiAgICAgICAgaWYgKHByZXZQaGFzZSAhPT0gbmV3UGhhc2UpIHtcbiAgICAgICAgICAgIHN3aXRjaCAocHJldlBoYXNlKSB7XG4gICAgICAgICAgICAgICAgY2FzZSBCbGFkZXNQaGFzZS5DaGFyR2VuOiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLkZyZWVwbGF5OiB7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLlNjb3JlOiB7XG4gICAgICAgICAgICAgICAgICAgIGlzRm9yY2luZ1JlbmRlciA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICBnYW1lLmFjdG9ycy5maWx0ZXIoKGFjdG9yKSA9PiBCbGFkZXNBY3Rvci5Jc1R5cGUoYWN0b3IsIEJsYWRlc0FjdG9yVHlwZS5wYykpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZm9yRWFjaCgoYWN0b3IpID0+IGFjdG9yLmNsZWFyTG9hZG91dCgpKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuRG93bnRpbWU6IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIE5vIGRlZmF1bHRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHN3aXRjaCAobmV3UGhhc2UpIHtcbiAgICAgICAgICAgICAgICBjYXNlIEJsYWRlc1BoYXNlLkNoYXJHZW46IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuRnJlZXBsYXk6IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuU2NvcmU6IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhc2UgQmxhZGVzUGhhc2UuRG93bnRpbWU6IHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIE5vIGRlZmF1bHRcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoaXNGb3JjaW5nUmVuZGVyKSB7XG4gICAgICAgICAgICBnYW1lLmFjdG9ycy5maWx0ZXIoKGFjdG9yKSA9PiBhY3Rvci50eXBlID09PSBCbGFkZXNBY3RvclR5cGUucGMpXG4gICAgICAgICAgICAgICAgLmZvckVhY2goKGFjdG9yKSA9PiBhY3Rvci5zaGVldD8ucmVuZGVyKCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBzdWJtaXREYXRhO1xuICAgIH1cbn1cbmV4cG9ydCB7IEJsYWRlc1RpcEdlbmVyYXRvciB9O1xuZXhwb3J0IGRlZmF1bHQgQmxhZGVzU2NvcmVTaGVldDtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./ts/sheets/item/BladesScoreSheet.ts\n"); + +/***/ }), + +/***/ "gsap/all": +/*!***********************!*\ + !*** external "gsap" ***! + \***********************/ +/***/ (function(module) { + +module.exports = gsap; + +/***/ }), + +/***/ "./lib/tagify/tagify.esm.js": +/*!**********************************!*\ + !*** ./lib/tagify/tagify.esm.js ***! + \**********************************/ +/***/ (function(__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) { + +eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": function() { return /* binding */ Tagify; }\n/* harmony export */ });\nfunction _defineProperty2(obj, key, value) { key = _toPropertyKey2(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }\nfunction _toPropertyKey2(t) { var i = _toPrimitive2(t, \"string\"); return \"symbol\" == _typeof(i) ? i : String(i); }\nfunction _toPrimitive2(t, r) { if (\"object\" != _typeof(t) || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || \"default\"); if (\"object\" != _typeof(i)) return i; throw new TypeError(\"@@toPrimitive must return a primitive value.\"); } return (\"string\" === r ? String : Number)(t); }\nfunction _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }\nfunction _nonIterableSpread() { throw new TypeError(\"Invalid attempt to spread non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); }\nfunction _iterableToArray(iter) { if (typeof Symbol !== \"undefined\" && iter[Symbol.iterator] != null || iter[\"@@iterator\"] != null) return Array.from(iter); }\nfunction _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }\nfunction _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== \"undefined\" && o[Symbol.iterator] || o[\"@@iterator\"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === \"number\") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError(\"Invalid attempt to iterate non-iterable instance.\\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.\"); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it.return != null) it.return(); } finally { if (didErr) throw err; } } }; }\nfunction _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === \"string\") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === \"Object\" && o.constructor) n = o.constructor.name; if (n === \"Map\" || n === \"Set\") return Array.from(o); if (n === \"Arguments\" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }\nfunction _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) arr2[i] = arr[i]; return arr2; }\nfunction _typeof(o) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && \"function\" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? \"symbol\" : typeof o; }, _typeof(o); }\n/**\n * Tagify (v 4.17.8) - tags input component\n * By undefined\n * https://github.com/yairEO/tagify\n * Permission is hereby granted, free of charge, to any person obtaining a copy\r\n * of this software and associated documentation files (the \"Software\"), to deal\r\n * in the Software without restriction, including without limitation the rights\r\n * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r\n * copies of the Software, and to permit persons to whom the Software is\r\n * furnished to do so, subject to the following conditions:\r\n * \r\n * The above copyright notice and this permission notice shall be included in\r\n * all copies or substantial portions of the Software.\r\n * \r\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r\n * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r\n * THE SOFTWARE.\r\n * \r\n * THE SOFTWARE IS NOT PERMISSIBLE TO BE SOLD.\n */\n\nfunction ownKeys(object, enumerableOnly) {\n var keys = Object.keys(object);\n if (Object.getOwnPropertySymbols) {\n var symbols = Object.getOwnPropertySymbols(object);\n enumerableOnly && (symbols = symbols.filter(function (sym) {\n return Object.getOwnPropertyDescriptor(object, sym).enumerable;\n })), keys.push.apply(keys, symbols);\n }\n return keys;\n}\nfunction _objectSpread2(target) {\n for (var i = 1; i < arguments.length; i++) {\n var source = null != arguments[i] ? arguments[i] : {};\n i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {\n _defineProperty(target, key, source[key]);\n }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {\n Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));\n });\n }\n return target;\n}\nfunction _defineProperty(obj, key, value) {\n key = _toPropertyKey(key);\n if (key in obj) {\n Object.defineProperty(obj, key, {\n value: value,\n enumerable: true,\n configurable: true,\n writable: true\n });\n } else {\n obj[key] = value;\n }\n return obj;\n}\nfunction _toPrimitive(input, hint) {\n if (_typeof(input) !== \"object\" || input === null) return input;\n var prim = input[Symbol.toPrimitive];\n if (prim !== undefined) {\n var res = prim.call(input, hint || \"default\");\n if (_typeof(res) !== \"object\") return res;\n throw new TypeError(\"@@toPrimitive must return a primitive value.\");\n }\n return (hint === \"string\" ? String : Number)(input);\n}\nfunction _toPropertyKey(arg) {\n var key = _toPrimitive(arg, \"string\");\n return _typeof(key) === \"symbol\" ? key : String(key);\n}\n\n// console.json = console.json || function(argument){\n// for(var arg=0; arg < arguments.length; ++arg)\n// console.log( JSON.stringify(arguments[arg], null, 4) )\n// }\n\n// const isEdge = /Edge/.test(navigator.userAgent)\nvar sameStr = function sameStr(s1, s2, caseSensitive, trim) {\n // cast to String\n s1 = \"\" + s1;\n s2 = \"\" + s2;\n if (trim) {\n s1 = s1.trim();\n s2 = s2.trim();\n }\n return caseSensitive ? s1 == s2 : s1.toLowerCase() == s2.toLowerCase();\n};\n\n// const getUID = () => (new Date().getTime() + Math.floor((Math.random()*10000)+1)).toString(16)\nvar removeCollectionProp = function removeCollectionProp(collection, unwantedProps) {\n return collection && Array.isArray(collection) && collection.map(function (v) {\n return omit(v, unwantedProps);\n });\n};\nfunction omit(obj, props) {\n var newObj = {},\n p;\n for (p in obj) if (props.indexOf(p) < 0) newObj[p] = obj[p];\n return newObj;\n}\nfunction decode(s) {\n var el = document.createElement('div');\n return s.replace(/\\&#?[0-9a-z]+;/gi, function (enc) {\n el.innerHTML = enc;\n return el.innerText;\n });\n}\n\n/**\r\n * utility method\r\n * https://stackoverflow.com/a/35385518/104380\r\n * @param {String} s [HTML string]\r\n * @return {Object} [DOM node]\r\n */\nfunction parseHTML(s) {\n var parser = new DOMParser(),\n node = parser.parseFromString(s.trim(), \"text/html\");\n return node.body.firstElementChild;\n}\n\n/**\r\n * Removed new lines and irrelevant spaces which might affect layout, and are better gone\r\n * @param {string} s [HTML string]\r\n */\nfunction minify(s) {\n return s ? s.replace(/\\>[\\r\\n ]+\\<\").replace(/(<.*?>)|\\s+/g, function (m, $1) {\n return $1 ? $1 : ' ';\n }) // https://stackoverflow.com/a/44841484/104380\n : \"\";\n}\nfunction removeTextChildNodes(elm) {\n var iter = document.createNodeIterator(elm, NodeFilter.SHOW_TEXT, null, false),\n textnode;\n\n // print all text nodes\n while (textnode = iter.nextNode()) {\n if (!textnode.textContent.trim()) textnode.parentNode.removeChild(textnode);\n }\n}\nfunction getfirstTextNode(elm, action) {\n action = action || 'previous';\n while (elm = elm[action + 'Sibling']) if (elm.nodeType == 3) return elm;\n}\n\n/**\r\n * utility method\r\n * https://stackoverflow.com/a/6234804/104380\r\n */\nfunction escapeHTML(s) {\n return typeof s == 'string' ? s.replace(/&/g, \"&\").replace(//g, \">\").replace(/\"/g, \""\").replace(/`|'/g, \"'\") : s;\n}\n\n/**\r\n * Checks if an argument is a javascript Object\r\n */\nfunction isObject(obj) {\n var type = Object.prototype.toString.call(obj).split(' ')[1].slice(0, -1);\n return obj === Object(obj) && type != 'Array' && type != 'Function' && type != 'RegExp' && type != 'HTMLUnknownElement';\n}\n\n/**\r\n * merge objects into a single new one\r\n * TEST: extend({}, {a:{foo:1}, b:[]}, {a:{bar:2}, b:[1], c:()=>{}})\r\n */\nfunction extend(o, o1, o2) {\n if (!(o instanceof Object)) o = {};\n copy(o, o1);\n if (o2) copy(o, o2);\n function copy(a, b) {\n // copy o2 to o\n for (var key in b) if (b.hasOwnProperty(key)) {\n if (isObject(b[key])) {\n if (!isObject(a[key])) a[key] = Object.assign({}, b[key]);else copy(a[key], b[key]);\n continue;\n }\n if (Array.isArray(b[key])) {\n a[key] = Object.assign([], b[key]);\n continue;\n }\n a[key] = b[key];\n }\n }\n return o;\n}\n\n/**\r\n * concatenates N arrays without dups.\r\n * If an array's item is an Object, compare by `value`\r\n */\nfunction concatWithoutDups() {\n var newArr = [],\n existingObj = {};\n var _iterator = _createForOfIteratorHelper(arguments),\n _step;\n try {\n for (_iterator.s(); !(_step = _iterator.n()).done;) {\n var arr = _step.value;\n var _iterator2 = _createForOfIteratorHelper(arr),\n _step2;\n try {\n for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {\n var item = _step2.value;\n // if current item is an object which has yet to be added to the new array\n if (isObject(item)) {\n if (!existingObj[item.value]) {\n newArr.push(item);\n existingObj[item.value] = 1;\n }\n }\n\n // if current item is not an object and is not in the new array\n else if (!newArr.includes(item)) newArr.push(item);\n }\n } catch (err) {\n _iterator2.e(err);\n } finally {\n _iterator2.f();\n }\n }\n } catch (err) {\n _iterator.e(err);\n } finally {\n _iterator.f();\n }\n return newArr;\n}\n\n/**\r\n * Extracted from: https://stackoverflow.com/a/37511463/104380\r\n * @param {String} s\r\n */\nfunction unaccent(s) {\n // if not supported, do not continue.\n // developers should use a polyfill:\n // https://github.com/walling/unorm\n if (!String.prototype.normalize) return s;\n if (typeof s === 'string') return s.normalize(\"NFD\").replace(/[\\u0300-\\u036f]/g, \"\");\n}\n\n/**\r\n * Meassures an element's height, which might yet have been added DOM\r\n * https://stackoverflow.com/q/5944038/104380\r\n * @param {DOM} node\r\n */\nfunction getNodeHeight(node) {\n var height,\n clone = node.cloneNode(true);\n clone.style.cssText = \"position:fixed; top:-9999px; opacity:0\";\n document.body.appendChild(clone);\n height = clone.clientHeight;\n clone.parentNode.removeChild(clone);\n return height;\n}\nvar isChromeAndroidBrowser = function isChromeAndroidBrowser() {\n return /(?=.*chrome)(?=.*android)/i.test(navigator.userAgent);\n};\nfunction getUID() {\n return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, function (c) {\n return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16);\n });\n}\nfunction isNodeTag(node) {\n return node && node.classList && node.classList.contains(this.settings.classNames.tag);\n}\n\n/**\r\n* Get the caret position relative to the viewport\r\n* https://stackoverflow.com/q/58985076/104380\r\n*\r\n* @returns {object} left, top distance in pixels\r\n*/\nfunction getCaretGlobalPosition() {\n var sel = document.getSelection();\n if (sel.rangeCount) {\n var r = sel.getRangeAt(0);\n var node = r.startContainer;\n var offset = r.startOffset;\n var rect, r2;\n if (offset > 0) {\n r2 = document.createRange();\n r2.setStart(node, offset - 1);\n r2.setEnd(node, offset);\n rect = r2.getBoundingClientRect();\n return {\n left: rect.right,\n top: rect.top,\n bottom: rect.bottom\n };\n }\n if (node.getBoundingClientRect) return node.getBoundingClientRect();\n }\n return {\n left: -9999,\n top: -9999\n };\n}\n\n/**\r\n * Injects content (either string or node) at the current the current (or specificed) caret position\r\n * @param {content} string/node\r\n * @param {range} Object (optional, a range other than the current window selection)\r\n */\nfunction _injectAtCaret(content, range) {\n var selection = window.getSelection();\n range = range || selection.getRangeAt(0);\n if (typeof content == 'string') content = document.createTextNode(content);\n if (range) {\n range.deleteContents();\n range.insertNode(content);\n }\n return content;\n}\n\n/** Setter/Getter\r\n * Each tag DOM node contains a custom property called \"__tagifyTagData\" which hosts its data\r\n * @param {Node} tagElm\r\n * @param {Object} data\r\n */\nfunction getSetTagData(tagElm, data, override) {\n if (!tagElm) {\n console.warn(\"tag element doesn't exist\", tagElm, data);\n return data;\n }\n if (data) tagElm.__tagifyTagData = override ? data : extend({}, tagElm.__tagifyTagData || {}, data);\n return tagElm.__tagifyTagData;\n}\nvar DEFAULTS = {\n delimiters: \",\",\n // [RegEx] split tags by any of these delimiters (\"null\" to cancel) Example: \",| |.\"\n pattern: null,\n // RegEx pattern to validate input by. Ex: /[1-9]/\n tagTextProp: 'value',\n // tag data Object property which will be displayed as the tag's text\n maxTags: Infinity,\n // Maximum number of tags\n callbacks: {},\n // Exposed callbacks object to be triggered on certain events\n addTagOnBlur: true,\n // automatically adds the text which was inputed as a tag when blur event happens\n onChangeAfterBlur: true,\n // By default, the native way of inputs' onChange events is kept, and it only fires when the field is blured.\n duplicates: false,\n // \"true\" - allow duplicate tags\n whitelist: [],\n // Array of tags to suggest as the user types (can be used along with \"enforceWhitelist\" setting)\n blacklist: [],\n // A list of non-allowed tags\n enforceWhitelist: false,\n // Only allow tags from the whitelist\n userInput: true,\n // disable manually typing/pasting/editing tags (tags may only be added from the whitelist)\n keepInvalidTags: false,\n // if true, do not remove tags which did not pass validation\n createInvalidTags: true,\n // if false, do not create invalid tags from invalid user input\n mixTagsAllowedAfter: /,|\\.|\\:|\\s/,\n // RegEx - Define conditions in which mix-tags content allows a tag to be added after\n mixTagsInterpolator: ['[[', ']]'],\n // Interpolation for mix mode. Everything between these will become a tag, if is a valid Object\n backspace: true,\n // false / true / \"edit\"\n skipInvalid: false,\n // If `true`, do not add invalid, temporary, tags before automatically removing them\n pasteAsTags: true,\n // automatically converts pasted text into tags. if \"false\", allows for further text editing\n\n editTags: {\n clicks: 2,\n // clicks to enter \"edit-mode\": 1 for single click. any other value is considered as double-click\n keepInvalid: true // keeps invalid edits as-is until `esc` is pressed while in focus\n },\n // 1 or 2 clicks to edit a tag. false/null for not allowing editing\n transformTag: function transformTag() {},\n // Takes a tag input string as argument and returns a transformed value\n trim: true,\n // whether or not the value provided should be trimmed, before being added as a tag\n a11y: {\n focusableTags: false\n },\n mixMode: {\n insertAfterTag: \"\\xA0\" // String/Node to inject after a tag has been added (see #588)\n },\n autoComplete: {\n enabled: true,\n // Tries to suggest the input's value while typing (match from whitelist) by adding the rest of term as grayed-out text\n rightKey: false // If `true`, when Right key is pressed, use the suggested value to create a tag, else just auto-completes the input. in mixed-mode this is set to \"true\"\n },\n classNames: {\n namespace: 'tagify',\n mixMode: 'tagify--mix',\n selectMode: 'tagify--select',\n input: 'tagify__input',\n focus: 'tagify--focus',\n tagNoAnimation: 'tagify--noAnim',\n tagInvalid: 'tagify--invalid',\n tagNotAllowed: 'tagify--notAllowed',\n scopeLoading: 'tagify--loading',\n hasMaxTags: 'tagify--hasMaxTags',\n hasNoTags: 'tagify--noTags',\n empty: 'tagify--empty',\n inputInvalid: 'tagify__input--invalid',\n dropdown: 'tagify__dropdown',\n dropdownWrapper: 'tagify__dropdown__wrapper',\n dropdownHeader: 'tagify__dropdown__header',\n dropdownFooter: 'tagify__dropdown__footer',\n dropdownItem: 'tagify__dropdown__item',\n dropdownItemActive: 'tagify__dropdown__item--active',\n dropdownItemHidden: 'tagify__dropdown__item--hidden',\n dropdownInital: 'tagify__dropdown--initial',\n tag: 'tagify__tag',\n tagText: 'tagify__tag-text',\n tagX: 'tagify__tag__removeBtn',\n tagLoading: 'tagify__tag--loading',\n tagEditing: 'tagify__tag--editable',\n tagFlash: 'tagify__tag--flash',\n tagHide: 'tagify__tag--hide'\n },\n dropdown: {\n classname: '',\n enabled: 2,\n // minimum input characters to be typed for the suggestions dropdown to show\n maxItems: 10,\n searchKeys: [\"value\", \"searchBy\"],\n fuzzySearch: true,\n caseSensitive: false,\n accentedSearch: true,\n includeSelectedTags: false,\n // Should the suggestions list Include already-selected tags (after filtering)\n highlightFirst: false,\n // highlights first-matched item in the list\n closeOnSelect: true,\n // closes the dropdown after selecting an item, if `enabled:0` (which means always show dropdown)\n clearOnSelect: true,\n // after selecting a suggetion, should the typed text input remain or be cleared\n position: 'all',\n // 'manual' / 'text' / 'all'\n appendTarget: null // defaults to document.body once DOM has been loaded\n },\n hooks: {\n beforeRemoveTag: function beforeRemoveTag() {\n return Promise.resolve();\n },\n beforePaste: function beforePaste() {\n return Promise.resolve();\n },\n suggestionClick: function suggestionClick() {\n return Promise.resolve();\n }\n }\n};\nfunction initDropdown() {\n this.dropdown = {};\n\n // auto-bind \"this\" to all the dropdown methods\n for (var p in this._dropdown) this.dropdown[p] = typeof this._dropdown[p] === 'function' ? this._dropdown[p].bind(this) : this._dropdown[p];\n this.dropdown.refs();\n}\nvar _dropdown = {\n refs: function refs() {\n this.DOM.dropdown = this.parseTemplate('dropdown', [this.settings]);\n this.DOM.dropdown.content = this.DOM.dropdown.querySelector(\"[data-selector='tagify-suggestions-wrapper']\");\n },\n getHeaderRef: function getHeaderRef() {\n return this.DOM.dropdown.querySelector(\"[data-selector='tagify-suggestions-header']\");\n },\n getFooterRef: function getFooterRef() {\n return this.DOM.dropdown.querySelector(\"[data-selector='tagify-suggestions-footer']\");\n },\n getAllSuggestionsRefs: function getAllSuggestionsRefs() {\n return _toConsumableArray(this.DOM.dropdown.content.querySelectorAll(this.settings.classNames.dropdownItemSelector));\n },\n /**\r\n * shows the suggestions select box\r\n * @param {String} value [optional, filter the whitelist by this value]\r\n */\n show: function show(value) {\n var _this2 = this;\n var _s = this.settings,\n firstListItem,\n firstListItemValue,\n allowNewTags = _s.mode == 'mix' && !_s.enforceWhitelist,\n noWhitelist = !_s.whitelist || !_s.whitelist.length,\n noMatchListItem,\n isManual = _s.dropdown.position == 'manual';\n\n // if text still exists in the input, and `show` method has no argument, then the input's text should be used\n value = value === undefined ? this.state.inputText : value;\n\n // ⚠️ Do not render suggestions list if:\n // 1. there's no whitelist (can happen while async loading) AND new tags arn't allowed\n // 2. dropdown is disabled\n // 3. loader is showing (controlled outside of this code)\n if (noWhitelist && !allowNewTags && !_s.templates.dropdownItemNoMatch || _s.dropdown.enable === false || this.state.isLoading || this.settings.readonly) return;\n clearTimeout(this.dropdownHide__bindEventsTimeout);\n\n // if no value was supplied, show all the \"whitelist\" items in the dropdown\n // @type [Array] listItems\n // TODO: add a Setting to control items' sort order for \"listItems\"\n this.suggestedListItems = this.dropdown.filterListItems(value);\n\n // trigger at this exact point to let the developer the chance to manually set \"this.suggestedListItems\"\n if (value && !this.suggestedListItems.length) {\n this.trigger('dropdown:noMatch', value);\n if (_s.templates.dropdownItemNoMatch) noMatchListItem = _s.templates.dropdownItemNoMatch.call(this, {\n value: value\n });\n }\n\n // if \"dropdownItemNoMatch\" was no defined, procceed regular flow.\n //\n if (!noMatchListItem) {\n // in mix-mode, if the value isn't included in the whilelist & \"enforceWhitelist\" setting is \"false\",\n // then add a custom suggestion item to the dropdown\n if (this.suggestedListItems.length) {\n if (value && allowNewTags && !this.state.editing.scope && !sameStr(this.suggestedListItems[0].value, value)) this.suggestedListItems.unshift({\n value: value\n });\n } else {\n if (value && allowNewTags && !this.state.editing.scope) {\n this.suggestedListItems = [{\n value: value\n }];\n }\n // hide suggestions list if no suggestion matched\n else {\n this.input.autocomplete.suggest.call(this);\n this.dropdown.hide();\n return;\n }\n }\n firstListItem = this.suggestedListItems[0];\n firstListItemValue = \"\" + (isObject(firstListItem) ? firstListItem.value : firstListItem);\n if (_s.autoComplete && firstListItemValue) {\n // only fill the sugegstion if the value of the first list item STARTS with the input value (regardless of \"fuzzysearch\" setting)\n if (firstListItemValue.indexOf(value) == 0) this.input.autocomplete.suggest.call(this, firstListItem);\n }\n }\n this.dropdown.fill(noMatchListItem);\n if (_s.dropdown.highlightFirst) {\n this.dropdown.highlightOption(this.DOM.dropdown.content.querySelector(_s.classNames.dropdownItemSelector));\n }\n\n // bind events, exactly at this stage of the code. \"dropdown.show\" method is allowed to be\n // called multiple times, regardless if the dropdown is currently visible, but the events-binding\n // should only be called if the dropdown wasn't previously visible.\n if (!this.state.dropdown.visible)\n // timeout is needed for when pressing arrow down to show the dropdown,\n // so the key event won't get registered in the dropdown events listeners\n setTimeout(this.dropdown.events.binding.bind(this));\n\n // set the dropdown visible state to be the same as the searched value.\n // MUST be set *before* position() is called\n this.state.dropdown.visible = value || true;\n this.state.dropdown.query = value;\n this.setStateSelection();\n\n // try to positioning the dropdown (it might not yet be on the page, doesn't matter, next code handles this)\n if (!isManual) {\n // a slight delay is needed if the dropdown \"position\" setting is \"text\", and nothing was typed in the input,\n // so sadly the \"getCaretGlobalPosition\" method doesn't recognize the caret position without this delay\n setTimeout(function () {\n _this2.dropdown.position();\n _this2.dropdown.render();\n });\n }\n\n // a delay is needed because of the previous delay reason.\n // this event must be fired after the dropdown was rendered & positioned\n setTimeout(function () {\n _this2.trigger(\"dropdown:show\", _this2.DOM.dropdown);\n });\n },\n /**\r\n * Hides the dropdown (if it's not managed manually by the developer)\r\n * @param {Boolean} overrideManual\r\n */\n hide: function hide(overrideManual) {\n var _this3 = this;\n var _this$DOM = this.DOM,\n scope = _this$DOM.scope,\n dropdown = _this$DOM.dropdown,\n isManual = this.settings.dropdown.position == 'manual' && !overrideManual;\n\n // if there's no dropdown, this means the dropdown events aren't binded\n if (!dropdown || !document.body.contains(dropdown) || isManual) return;\n window.removeEventListener('resize', this.dropdown.position);\n this.dropdown.events.binding.call(this, false); // unbind all events\n\n // if the dropdown is open, and the input (scope) is clicked,\n // the dropdown should be now \"close\", and the next click (on the scope)\n // should re-open it, and without a timeout, clicking to close will re-open immediately\n // clearTimeout(this.dropdownHide__bindEventsTimeout)\n // this.dropdownHide__bindEventsTimeout = setTimeout(this.events.binding.bind(this), 250) // re-bind main events\n\n scope.setAttribute(\"aria-expanded\", false);\n dropdown.parentNode.removeChild(dropdown);\n\n // scenario: clicking the scope to show the dropdown, clicking again to hide -> calls dropdown.hide() and then re-focuses the input\n // which casues another onFocus event, which checked \"this.state.dropdown.visible\" and see it as \"false\" and re-open the dropdown\n setTimeout(function () {\n _this3.state.dropdown.visible = false;\n }, 100);\n this.state.dropdown.query = this.state.ddItemData = this.state.ddItemElm = this.state.selection = null;\n\n // if the user closed the dropdown (in mix-mode) while a potential tag was detected, flag the current tag\n // so the dropdown won't be shown on following user input for that \"tag\"\n if (this.state.tag && this.state.tag.value.length) {\n this.state.flaggedTags[this.state.tag.baseOffset] = this.state.tag;\n }\n this.trigger(\"dropdown:hide\", dropdown);\n return this;\n },\n /**\r\n * Toggles dropdown show/hide\r\n * @param {Boolean} show forces the dropdown to show\r\n */\n toggle: function toggle(show) {\n this.dropdown[this.state.dropdown.visible && !show ? 'hide' : 'show']();\n },\n render: function render() {\n var _this4 = this;\n // let the element render in the DOM first, to accurately measure it.\n // this.DOM.dropdown.style.cssText = \"left:-9999px; top:-9999px;\";\n var ddHeight = getNodeHeight(this.DOM.dropdown),\n _s = this.settings,\n enabled = typeof _s.dropdown.enabled == 'number' && _s.dropdown.enabled >= 0;\n if (!enabled) return this;\n this.DOM.scope.setAttribute(\"aria-expanded\", true);\n\n // if the dropdown has yet to be appended to the DOM,\n // append the dropdown to the body element & handle events\n if (!document.body.contains(this.DOM.dropdown)) {\n this.DOM.dropdown.classList.add(_s.classNames.dropdownInital);\n this.dropdown.position(ddHeight);\n _s.dropdown.appendTarget.appendChild(this.DOM.dropdown);\n setTimeout(function () {\n return _this4.DOM.dropdown.classList.remove(_s.classNames.dropdownInital);\n });\n }\n return this;\n },\n /**\r\n * re-renders the dropdown content element (see \"dropdownContent\" in templates file)\r\n * @param {String/Array} HTMLContent - optional\r\n */\n fill: function fill(HTMLContent) {\n HTMLContent = typeof HTMLContent == 'string' ? HTMLContent : this.dropdown.createListHTML(HTMLContent || this.suggestedListItems);\n var dropdownContent = this.settings.templates.dropdownContent.call(this, HTMLContent);\n this.DOM.dropdown.content.innerHTML = minify(dropdownContent);\n },\n /**\r\n * Re-renders only the header & footer.\r\n * Used when selecting a suggestion and it is wanted that the suggestions dropdown stays open.\r\n * Since the list of sugegstions is not being re-rendered completely every time a suggestion is selected (the item is transitioned-out)\r\n * then the header & footer should be kept in sync with the suggestions data change\r\n */\n fillHeaderFooter: function fillHeaderFooter() {\n var suggestions = this.dropdown.filterListItems(this.state.dropdown.query),\n newHeaderElem = this.parseTemplate('dropdownHeader', [suggestions]),\n newFooterElem = this.parseTemplate('dropdownFooter', [suggestions]),\n headerRef = this.dropdown.getHeaderRef(),\n footerRef = this.dropdown.getFooterRef();\n newHeaderElem && (headerRef === null || headerRef === void 0 ? void 0 : headerRef.parentNode.replaceChild(newHeaderElem, headerRef));\n newFooterElem && (footerRef === null || footerRef === void 0 ? void 0 : footerRef.parentNode.replaceChild(newFooterElem, footerRef));\n },\n /**\r\n * fill data into the suggestions list\r\n * (mainly used to update the list when removing tags while the suggestions dropdown is visible, so they will be re-added to the list. not efficient)\r\n */\n refilter: function refilter(value) {\n value = value || this.state.dropdown.query || '';\n this.suggestedListItems = this.dropdown.filterListItems(value);\n this.dropdown.fill();\n if (!this.suggestedListItems.length) this.dropdown.hide();\n this.trigger(\"dropdown:updated\", this.DOM.dropdown);\n },\n position: function position(ddHeight) {\n var _sd = this.settings.dropdown;\n if (_sd.position == 'manual') return;\n var rect,\n top,\n bottom,\n left,\n width,\n parentsPositions,\n ddElm = this.DOM.dropdown,\n placeAbove = _sd.placeAbove,\n isDefaultAppendTarget = _sd.appendTarget === document.body,\n appendTargetScrollTop = isDefaultAppendTarget ? window.pageYOffset : _sd.appendTarget.scrollTop,\n root = document.fullscreenElement || document.webkitFullscreenElement || document.documentElement,\n viewportHeight = root.clientHeight,\n viewportWidth = Math.max(root.clientWidth || 0, window.innerWidth || 0),\n positionTo = viewportWidth > 480 ? _sd.position : 'all',\n ddTarget = this.DOM[positionTo == 'input' ? 'input' : 'scope'];\n ddHeight = ddHeight || ddElm.clientHeight;\n function getParentsPositions(p) {\n var left = 0,\n top = 0;\n\n // when in element-fullscreen mode, do not go above the fullscreened-element\n while (p && p != root) {\n left += p.offsetLeft || 0;\n top += p.offsetTop || 0;\n p = p.parentNode;\n }\n return {\n left: left,\n top: top\n };\n }\n function getAccumulatedAncestorsScrollTop() {\n var scrollTop = 0,\n p = _sd.appendTarget.parentNode;\n while (p) {\n scrollTop += p.scrollTop || 0;\n p = p.parentNode;\n }\n return scrollTop;\n }\n if (!this.state.dropdown.visible) return;\n if (positionTo == 'text') {\n rect = getCaretGlobalPosition();\n bottom = rect.bottom;\n top = rect.top;\n left = rect.left;\n width = 'auto';\n } else {\n parentsPositions = getParentsPositions(_sd.appendTarget);\n rect = ddTarget.getBoundingClientRect();\n top = rect.top - parentsPositions.top;\n bottom = rect.bottom - 1 - parentsPositions.top;\n left = rect.left - parentsPositions.left;\n width = rect.width + 'px';\n }\n\n // if the \"append target\" isn't the default, correct the `top` variable by ignoring any scrollTop of the target's Ancestors\n if (!isDefaultAppendTarget) {\n var accumulatedAncestorsScrollTop = getAccumulatedAncestorsScrollTop();\n top += accumulatedAncestorsScrollTop;\n bottom += accumulatedAncestorsScrollTop;\n }\n top = Math.floor(top);\n bottom = Math.ceil(bottom);\n placeAbove = placeAbove === undefined ? viewportHeight - rect.bottom < ddHeight : placeAbove;\n\n // flip vertically if there is no space for the dropdown below the input\n ddElm.style.cssText = \"left:\" + (left + window.pageXOffset) + \"px; width:\" + width + \";\" + (placeAbove ? \"top: \" + (top + appendTargetScrollTop) + \"px\" : \"top: \" + (bottom + appendTargetScrollTop) + \"px\");\n ddElm.setAttribute('placement', placeAbove ? \"top\" : \"bottom\");\n ddElm.setAttribute('position', positionTo);\n },\n events: {\n /**\r\n * Events should only be binded when the dropdown is rendered and removed when isn't\r\n * because there might be multiple Tagify instances on a certain page\r\n * @param {Boolean} bindUnbind [optional. true when wanting to unbind all the events]\r\n */\n binding: function binding() {\n var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n // references to the \".bind()\" methods must be saved so they could be unbinded later\n var _CB = this.dropdown.events.callbacks,\n // callback-refs\n _CBR = this.listeners.dropdown = this.listeners.dropdown || {\n position: this.dropdown.position.bind(this, null),\n onKeyDown: _CB.onKeyDown.bind(this),\n onMouseOver: _CB.onMouseOver.bind(this),\n onMouseLeave: _CB.onMouseLeave.bind(this),\n onClick: _CB.onClick.bind(this),\n onScroll: _CB.onScroll.bind(this)\n },\n action = bindUnbind ? 'addEventListener' : 'removeEventListener';\n if (this.settings.dropdown.position != 'manual') {\n document[action]('scroll', _CBR.position, true);\n window[action]('resize', _CBR.position);\n window[action]('keydown', _CBR.onKeyDown);\n }\n this.DOM.dropdown[action]('mouseover', _CBR.onMouseOver);\n this.DOM.dropdown[action]('mouseleave', _CBR.onMouseLeave);\n this.DOM.dropdown[action]('mousedown', _CBR.onClick);\n this.DOM.dropdown.content[action]('scroll', _CBR.onScroll);\n },\n callbacks: {\n onKeyDown: function onKeyDown(e) {\n var _this5 = this;\n // ignore keys during IME composition\n if (!this.state.hasFocus || this.state.composing) return;\n\n // get the \"active\" element, and if there was none (yet) active, use first child\n var selectedElm = this.DOM.dropdown.querySelector(this.settings.classNames.dropdownItemActiveSelector),\n selectedElmData = this.dropdown.getSuggestionDataByNode(selectedElm);\n switch (e.key) {\n case 'ArrowDown':\n case 'ArrowUp':\n case 'Down': // >IE11\n case 'Up':\n {\n // >IE11\n e.preventDefault();\n var dropdownItems = this.dropdown.getAllSuggestionsRefs(),\n actionUp = e.key == 'ArrowUp' || e.key == 'Up';\n if (selectedElm) {\n selectedElm = this.dropdown.getNextOrPrevOption(selectedElm, !actionUp);\n }\n\n // if no element was found OR current item is not a \"real\" item, loop\n if (!selectedElm || !selectedElm.matches(this.settings.classNames.dropdownItemSelector)) {\n selectedElm = dropdownItems[actionUp ? dropdownItems.length - 1 : 0];\n }\n this.dropdown.highlightOption(selectedElm, true);\n // selectedElm.scrollIntoView({inline: 'nearest', behavior: 'smooth'})\n break;\n }\n case 'Escape':\n case 'Esc':\n // IE11\n this.dropdown.hide();\n break;\n case 'ArrowRight':\n if (this.state.actions.ArrowLeft) return;\n case 'Tab':\n {\n // in mix-mode, treat arrowRight like Enter key, so a tag will be created\n if (this.settings.mode != 'mix' && selectedElm && !this.settings.autoComplete.rightKey && !this.state.editing) {\n e.preventDefault(); // prevents blur so the autocomplete suggestion will not become a tag\n var value = this.dropdown.getMappedValue(selectedElmData);\n this.input.autocomplete.set.call(this, value);\n return false;\n }\n return true;\n }\n case 'Enter':\n {\n e.preventDefault();\n this.settings.hooks.suggestionClick(e, {\n tagify: this,\n tagData: selectedElmData,\n suggestionElm: selectedElm\n }).then(function () {\n if (selectedElm) {\n _this5.dropdown.selectOption(selectedElm);\n // highlight next option\n selectedElm = _this5.dropdown.getNextOrPrevOption(selectedElm, !actionUp);\n _this5.dropdown.highlightOption(selectedElm);\n return;\n } else _this5.dropdown.hide();\n if (_this5.settings.mode != 'mix') _this5.addTags(_this5.state.inputText.trim(), true);\n }).catch(function (err) {\n return err;\n });\n break;\n }\n case 'Backspace':\n {\n if (this.settings.mode == 'mix' || this.state.editing.scope) return;\n var _value = this.input.raw.call(this);\n if (_value == \"\" || _value.charCodeAt(0) == 8203) {\n if (this.settings.backspace === true) this.removeTags();else if (this.settings.backspace == 'edit') setTimeout(this.editTag.bind(this), 0);\n }\n }\n }\n },\n onMouseOver: function onMouseOver(e) {\n var ddItem = e.target.closest(this.settings.classNames.dropdownItemSelector);\n // event delegation check\n ddItem && this.dropdown.highlightOption(ddItem);\n },\n onMouseLeave: function onMouseLeave(e) {\n // de-highlight any previously highlighted option\n this.dropdown.highlightOption();\n },\n onClick: function onClick(e) {\n var _this6 = this;\n if (e.button != 0 || e.target == this.DOM.dropdown || e.target == this.DOM.dropdown.content) return; // allow only mouse left-clicks\n\n var selectedElm = e.target.closest(this.settings.classNames.dropdownItemSelector),\n selectedElmData = this.dropdown.getSuggestionDataByNode(selectedElm);\n\n // temporary set the \"actions\" state to indicate to the main \"blur\" event it shouldn't run\n this.state.actions.selectOption = true;\n setTimeout(function () {\n return _this6.state.actions.selectOption = false;\n }, 50);\n this.settings.hooks.suggestionClick(e, {\n tagify: this,\n tagData: selectedElmData,\n suggestionElm: selectedElm\n }).then(function () {\n if (selectedElm) _this6.dropdown.selectOption(selectedElm, e);else _this6.dropdown.hide();\n }).catch(function (err) {\n return console.warn(err);\n });\n },\n onScroll: function onScroll(e) {\n var elm = e.target,\n pos = elm.scrollTop / (elm.scrollHeight - elm.parentNode.clientHeight) * 100;\n this.trigger(\"dropdown:scroll\", {\n percentage: Math.round(pos)\n });\n }\n }\n },\n /**\r\n * Given a suggestion-item, return the data associated with it\r\n * @param {HTMLElement} tagElm\r\n * @returns Object\r\n */\n getSuggestionDataByNode: function getSuggestionDataByNode(tagElm) {\n var value = tagElm && tagElm.getAttribute('value');\n return this.suggestedListItems.find(function (item) {\n return item.value == value;\n }) || null;\n },\n getNextOrPrevOption: function getNextOrPrevOption(selected) {\n var next = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var dropdownItems = this.dropdown.getAllSuggestionsRefs(),\n selectedIdx = dropdownItems.findIndex(function (item) {\n return item === selected;\n });\n return next ? dropdownItems[selectedIdx + 1] : dropdownItems[selectedIdx - 1];\n },\n /**\r\n * mark the currently active suggestion option\r\n * @param {Object} elm option DOM node\r\n * @param {Boolean} adjustScroll when navigation with keyboard arrows (up/down), aut-scroll to always show the highlighted element\r\n */\n highlightOption: function highlightOption(elm, adjustScroll) {\n var className = this.settings.classNames.dropdownItemActive,\n itemData;\n\n // focus casues a bug in Firefox with the placeholder been shown on the input element\n // if( this.settings.dropdown.position != 'manual' )\n // elm.focus();\n\n if (this.state.ddItemElm) {\n this.state.ddItemElm.classList.remove(className);\n this.state.ddItemElm.removeAttribute(\"aria-selected\");\n }\n if (!elm) {\n this.state.ddItemData = null;\n this.state.ddItemElm = null;\n this.input.autocomplete.suggest.call(this);\n return;\n }\n itemData = this.dropdown.getSuggestionDataByNode(elm);\n this.state.ddItemData = itemData;\n this.state.ddItemElm = elm;\n\n // this.DOM.dropdown.querySelectorAll(\".\" + this.settings.classNames.dropdownItemActive).forEach(activeElm => activeElm.classList.remove(className));\n elm.classList.add(className);\n elm.setAttribute(\"aria-selected\", true);\n if (adjustScroll) elm.parentNode.scrollTop = elm.clientHeight + elm.offsetTop - elm.parentNode.clientHeight;\n\n // Try to autocomplete the typed value with the currently highlighted dropdown item\n if (this.settings.autoComplete) {\n this.input.autocomplete.suggest.call(this, itemData);\n this.dropdown.position(); // suggestions might alter the height of the tagify wrapper because of unkown suggested term length that could drop to the next line\n }\n },\n /**\r\n * Create a tag from the currently active suggestion option\r\n * @param {Object} elm DOM node to select\r\n * @param {Object} event The original Click event, if available (since keyboard ENTER key also triggers this method)\r\n */\n selectOption: function selectOption(elm, event) {\n var _this7 = this;\n var _this$settings$dropdo = this.settings.dropdown,\n clearOnSelect = _this$settings$dropdo.clearOnSelect,\n closeOnSelect = _this$settings$dropdo.closeOnSelect;\n if (!elm) {\n this.addTags(this.state.inputText, true);\n closeOnSelect && this.dropdown.hide();\n return;\n }\n event = event || {};\n\n // if in edit-mode, do not continue but instead replace the tag's text.\n // the scenario is that \"addTags\" was called from a dropdown suggested option selected while editing\n\n var value = elm.getAttribute('value'),\n isNoMatch = value == 'noMatch',\n tagData = this.suggestedListItems.find(function (item) {\n var _item$value;\n return ((_item$value = item.value) !== null && _item$value !== void 0 ? _item$value : item) == value;\n });\n\n // The below event must be triggered, regardless of anything else which might go wrong\n this.trigger('dropdown:select', {\n data: tagData,\n elm: elm,\n event: event\n });\n if (!value || !tagData && !isNoMatch) {\n closeOnSelect && setTimeout(this.dropdown.hide.bind(this));\n return;\n }\n if (this.state.editing) {\n // normalizing value, because \"tagData\" might be a string, and therefore will not be able to extend the object\n this.onEditTagDone(null, extend({\n __isValid: true\n }, this.normalizeTags([tagData])[0]));\n }\n // Tagify instances should re-focus to the input element once an option was selected, to allow continuous typing\n else {\n this[this.settings.mode == 'mix' ? \"addMixTags\" : \"addTags\"]([tagData || this.input.raw.call(this)], clearOnSelect);\n }\n\n // todo: consider not doing this on mix-mode\n if (!this.DOM.input.parentNode) return;\n setTimeout(function () {\n _this7.DOM.input.focus();\n _this7.toggleFocusClass(true);\n });\n closeOnSelect && setTimeout(this.dropdown.hide.bind(this));\n\n // hide selected suggestion\n elm.addEventListener('transitionend', function () {\n _this7.dropdown.fillHeaderFooter();\n setTimeout(function () {\n return elm.remove();\n }, 100);\n }, {\n once: true\n });\n elm.classList.add(this.settings.classNames.dropdownItemHidden);\n },\n // adds all the suggested items, including the ones which are not currently rendered,\n // unless specified otherwise (by the \"onlyRendered\" argument)\n selectAll: function selectAll(onlyRendered) {\n // having suggestedListItems with items messes with \"normalizeTags\" when wanting\n // to add all tags\n this.suggestedListItems.length = 0;\n this.dropdown.hide();\n this.dropdown.filterListItems('');\n var tagsToAdd = this.dropdown.filterListItems('');\n if (!onlyRendered) tagsToAdd = this.state.dropdown.suggestions;\n\n // some whitelist items might have already been added as tags so when addings all of them,\n // skip adding already-added ones, so best to use \"filterListItems\" method over \"settings.whitelist\"\n this.addTags(tagsToAdd, true);\n return this;\n },\n /**\r\n * returns an HTML string of the suggestions' list items\r\n * @param {String} value string to filter the whitelist by\r\n * @param {Object} options \"exact\" - for exact complete match\r\n * @return {Array} list of filtered whitelist items according to the settings provided and current value\r\n */\n filterListItems: function filterListItems(value, options) {\n var _this8 = this;\n var _s = this.settings,\n _sd = _s.dropdown,\n options = options || {},\n list = [],\n exactMatchesList = [],\n whitelist = _s.whitelist,\n suggestionsCount = _sd.maxItems >= 0 ? _sd.maxItems : Infinity,\n searchKeys = _sd.searchKeys,\n whitelistItem,\n valueIsInWhitelist,\n searchBy,\n isDuplicate,\n niddle,\n i = 0;\n value = _s.mode == 'select' && this.value.length && this.value[0][_s.tagTextProp] == value ? '' // do not filter if the tag, which is already selecetd in \"select\" mode, is the same as the typed text\n : value;\n if (!value || !searchKeys.length) {\n list = _sd.includeSelectedTags ? whitelist : whitelist.filter(function (item) {\n return !_this8.isTagDuplicate(isObject(item) ? item.value : item);\n }); // don't include tags which have already been added.\n\n this.state.dropdown.suggestions = list;\n return list.slice(0, suggestionsCount); // respect \"maxItems\" dropdown setting\n }\n niddle = _sd.caseSensitive ? \"\" + value : (\"\" + value).toLowerCase();\n\n // checks if ALL of the words in the search query exists in the current whitelist item, regardless of their order\n function stringHasAll(s, query) {\n return query.toLowerCase().split(' ').every(function (q) {\n return s.includes(q.toLowerCase());\n });\n }\n var _loop = function _loop() {\n var startsWithMatch, exactMatch;\n whitelistItem = whitelist[i] instanceof Object ? whitelist[i] : {\n value: whitelist[i]\n }; //normalize value as an Object\n\n var itemWithoutSearchKeys = !Object.keys(whitelistItem).some(function (k) {\n return searchKeys.includes(k);\n }),\n _searchKeys = itemWithoutSearchKeys ? [\"value\"] : searchKeys;\n if (_sd.fuzzySearch && !options.exact) {\n searchBy = _searchKeys.reduce(function (values, k) {\n return values + \" \" + (whitelistItem[k] || \"\");\n }, \"\").toLowerCase().trim();\n if (_sd.accentedSearch) {\n searchBy = unaccent(searchBy);\n niddle = unaccent(niddle);\n }\n startsWithMatch = searchBy.indexOf(niddle) == 0;\n exactMatch = searchBy === niddle;\n valueIsInWhitelist = stringHasAll(searchBy, niddle);\n } else {\n startsWithMatch = true;\n valueIsInWhitelist = _searchKeys.some(function (k) {\n var v = '' + (whitelistItem[k] || ''); // if key exists, cast to type String\n\n if (_sd.accentedSearch) {\n v = unaccent(v);\n niddle = unaccent(niddle);\n }\n if (!_sd.caseSensitive) v = v.toLowerCase();\n exactMatch = v === niddle;\n return options.exact ? v === niddle : v.indexOf(niddle) == 0;\n });\n }\n isDuplicate = !_sd.includeSelectedTags && _this8.isTagDuplicate(isObject(whitelistItem) ? whitelistItem.value : whitelistItem);\n\n // match for the value within each \"whitelist\" item\n if (valueIsInWhitelist && !isDuplicate) if (exactMatch && startsWithMatch) exactMatchesList.push(whitelistItem);else if (_sd.sortby == 'startsWith' && startsWithMatch) list.unshift(whitelistItem);else list.push(whitelistItem);\n };\n for (; i < whitelist.length; i++) {\n _loop();\n }\n this.state.dropdown.suggestions = exactMatchesList.concat(list);\n\n // custom sorting function\n return typeof _sd.sortby == 'function' ? _sd.sortby(exactMatchesList.concat(list), niddle) : exactMatchesList.concat(list).slice(0, suggestionsCount);\n },\n /**\r\n * Returns the final value of a tag data (object) with regards to the \"mapValueTo\" dropdown setting\r\n * @param {Object} tagData\r\n * @returns\r\n */\n getMappedValue: function getMappedValue(tagData) {\n var mapValueTo = this.settings.dropdown.mapValueTo,\n value = mapValueTo ? typeof mapValueTo == 'function' ? mapValueTo(tagData) : tagData[mapValueTo] || tagData.value : tagData.value;\n return value;\n },\n /**\r\n * Creates the dropdown items' HTML\r\n * @param {Array} sugegstionsList [Array of Objects]\r\n * @return {String}\r\n */\n createListHTML: function createListHTML(sugegstionsList) {\n var _this9 = this;\n return extend([], sugegstionsList).map(function (suggestion, idx) {\n if (typeof suggestion == 'string' || typeof suggestion == 'number') suggestion = {\n value: suggestion\n };\n var mappedValue = _this9.dropdown.getMappedValue(suggestion);\n mappedValue = typeof mappedValue == 'string' ? escapeHTML(mappedValue) : mappedValue;\n return _this9.settings.templates.dropdownItem.apply(_this9, [_objectSpread2(_objectSpread2({}, suggestion), {}, {\n mappedValue: mappedValue\n }), _this9]);\n }).join(\"\");\n }\n};\nvar VERSION = 1; // current version of persisted data. if code change breaks persisted data, verison number should be bumped.\nvar STORE_KEY = '@yaireo/tagify/';\nvar getPersistedData = function getPersistedData(id) {\n return function (key) {\n // if \"persist\" is \"false\", do not save to localstorage\n var customKey = '/' + key,\n persistedData,\n versionMatch = localStorage.getItem(STORE_KEY + id + '/v', VERSION) == VERSION;\n if (versionMatch) {\n try {\n persistedData = JSON.parse(localStorage[STORE_KEY + id + customKey]);\n } catch (err) {}\n }\n return persistedData;\n };\n};\nvar setPersistedData = function setPersistedData(id) {\n if (!id) return function () {};\n\n // for storage invalidation\n localStorage.setItem(STORE_KEY + id + '/v', VERSION);\n return function (data, key) {\n var customKey = '/' + key,\n persistedData = JSON.stringify(data);\n if (data && key) {\n localStorage.setItem(STORE_KEY + id + customKey, persistedData);\n dispatchEvent(new Event('storage'));\n }\n };\n};\nvar clearPersistedData = function clearPersistedData(id) {\n return function (key) {\n var base = STORE_KEY + '/' + id + '/';\n\n // delete specific key in the storage\n if (key) localStorage.removeItem(base + key);\n\n // delete all keys in the storage with a specific tagify id\n else {\n for (var k in localStorage) if (k.includes(base)) localStorage.removeItem(k);\n }\n };\n};\nvar TEXTS = {\n empty: \"empty\",\n exceed: \"number of tags exceeded\",\n pattern: \"pattern mismatch\",\n duplicate: \"already exists\",\n notAllowed: \"not allowed\"\n};\nvar templates = {\n /**\r\n *\r\n * @param {DOM Object} input Original input DOm element\r\n * @param {Object} settings Tagify instance settings Object\r\n */\n wrapper: function wrapper(input, _s) {\n return \"\\n \\n ​\\n \");\n },\n tag: function tag(tagData, _ref) {\n var _s = _ref.settings;\n return \"\\n \\n
\\n \").concat(tagData[_s.tagTextProp] || tagData.value, \"\\n
\\n
\");\n },\n dropdown: function dropdown(settings) {\n var _sd = settings.dropdown,\n isManual = _sd.position == 'manual',\n className = \"\".concat(settings.classNames.dropdown);\n return \"
\\n
\\n
\");\n },\n dropdownContent: function dropdownContent(HTMLContent) {\n var _s = this.settings,\n suggestions = this.state.dropdown.suggestions;\n return \"\\n \".concat(_s.templates.dropdownHeader.call(this, suggestions), \"\\n \").concat(HTMLContent, \"\\n \").concat(_s.templates.dropdownFooter.call(this, suggestions), \"\\n \");\n },\n dropdownItem: function dropdownItem(item) {\n return \"
\").concat(item.mappedValue || item.value, \"
\");\n },\n /**\r\n * @param {Array} suggestions An array of all the matched suggested items, including those which were sliced away due to the \"dropdown.maxItems\" setting\r\n */\n dropdownHeader: function dropdownHeader(suggestions) {\n return \"
\");\n },\n dropdownFooter: function dropdownFooter(suggestions) {\n var hasMore = suggestions.length - this.settings.dropdown.maxItems;\n return hasMore > 0 ? \"
\\n \").concat(hasMore, \" more items. Refine your search.\\n
\") : '';\n },\n dropdownItemNoMatch: null\n};\nfunction EventDispatcher(instance) {\n // Create a DOM EventTarget object\n var target = document.createTextNode('');\n function addRemove(op, events, cb) {\n if (cb) events.split(/\\s+/g).forEach(function (name) {\n return target[op + 'EventListener'].call(target, name, cb);\n });\n }\n\n // Pass EventTarget interface calls to DOM EventTarget object\n return {\n off: function off(events, cb) {\n addRemove('remove', events, cb);\n return this;\n },\n on: function on(events, cb) {\n if (cb && typeof cb == 'function') addRemove('add', events, cb);\n return this;\n },\n trigger: function trigger(eventName, data, opts) {\n var e;\n opts = opts || {\n cloneData: true\n };\n if (!eventName) return;\n if (instance.settings.isJQueryPlugin) {\n if (eventName == 'remove') eventName = 'removeTag'; // issue #222\n jQuery(instance.DOM.originalInput).triggerHandler(eventName, [data]);\n } else {\n try {\n var eventData = _typeof(data) === 'object' ? data : {\n value: data\n };\n eventData = opts.cloneData ? extend({}, eventData) : eventData;\n eventData.tagify = this;\n if (data.event) eventData.event = this.cloneEvent(data.event);\n\n // TODO: move the below to the \"extend\" function\n if (data instanceof Object) for (var prop in data) if (data[prop] instanceof HTMLElement) eventData[prop] = data[prop];\n e = new CustomEvent(eventName, {\n \"detail\": eventData\n });\n } catch (err) {\n console.warn(err);\n }\n target.dispatchEvent(e);\n }\n }\n };\n}\nvar deleteBackspaceTimeout;\nfunction triggerChangeEvent() {\n if (this.settings.mixMode.integrated) return;\n var inputElm = this.DOM.originalInput,\n changed = this.state.lastOriginalValueReported !== inputElm.value,\n event = new CustomEvent(\"change\", {\n bubbles: true\n }); // must use \"CustomEvent\" and not \"Event\" to support IE\n\n if (!changed) return;\n\n // must apply this BEFORE triggering the simulated event\n this.state.lastOriginalValueReported = inputElm.value;\n\n // React hack: https://github.com/facebook/react/issues/11488\n event.simulated = true;\n if (inputElm._valueTracker) inputElm._valueTracker.setValue(Math.random());\n inputElm.dispatchEvent(event);\n\n // also trigger a Tagify event\n this.trigger(\"change\", this.state.lastOriginalValueReported);\n\n // React, for some reason, clears the input's value after \"dispatchEvent\" is fired\n inputElm.value = this.state.lastOriginalValueReported;\n}\nvar events = {\n // bind custom events which were passed in the settings\n customBinding: function customBinding() {\n var _this10 = this;\n this.customEventsList.forEach(function (name) {\n _this10.on(name, _this10.settings.callbacks[name]);\n });\n },\n binding: function binding() {\n var bindUnbind = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;\n var _CB = this.events.callbacks,\n _CBR,\n action = bindUnbind ? 'addEventListener' : 'removeEventListener';\n\n // do not allow the main events to be bound more than once\n if (this.state.mainEvents && bindUnbind) return;\n\n // set the binding state of the main events, so they will not be bound more than once\n this.state.mainEvents = bindUnbind;\n\n // everything inside gets executed only once-per instance\n if (bindUnbind && !this.listeners.main) {\n this.events.bindGlobal.call(this);\n if (this.settings.isJQueryPlugin) jQuery(this.DOM.originalInput).on('tagify.removeAllTags', this.removeAllTags.bind(this));\n }\n\n // setup callback references so events could be removed later\n _CBR = this.listeners.main = this.listeners.main || {\n focus: ['input', _CB.onFocusBlur.bind(this)],\n keydown: ['input', _CB.onKeydown.bind(this)],\n click: ['scope', _CB.onClickScope.bind(this)],\n dblclick: ['scope', _CB.onDoubleClickScope.bind(this)],\n paste: ['input', _CB.onPaste.bind(this)],\n drop: ['input', _CB.onDrop.bind(this)],\n compositionstart: ['input', _CB.onCompositionStart.bind(this)],\n compositionend: ['input', _CB.onCompositionEnd.bind(this)]\n };\n for (var eventName in _CBR) {\n this.DOM[_CBR[eventName][0]][action](eventName, _CBR[eventName][1]);\n }\n\n // listen to original input changes (unfortunetly this is the best way...)\n // https://stackoverflow.com/a/1949416/104380\n clearInterval(this.listeners.main.originalInputValueObserverInterval);\n this.listeners.main.originalInputValueObserverInterval = setInterval(_CB.observeOriginalInputValue.bind(this), 500);\n\n // observers\n var inputMutationObserver = this.listeners.main.inputMutationObserver || new MutationObserver(_CB.onInputDOMChange.bind(this));\n\n // cleaup just-in-case\n inputMutationObserver.disconnect();\n\n // observe stuff\n if (this.settings.mode == 'mix') inputMutationObserver.observe(this.DOM.input, {\n childList: true\n });\n },\n bindGlobal: function bindGlobal(unbind) {\n var _CB = this.events.callbacks,\n action = unbind ? 'removeEventListener' : 'addEventListener',\n e;\n if (!this.listeners || !unbind && this.listeners.global) return; // do not re-bind\n\n // these events are global event should never be unbinded, unless the instance is destroyed:\n this.listeners.global = this.listeners.global || [{\n type: this.isIE ? 'keydown' : 'input',\n // IE cannot register \"input\" events on contenteditable elements, so the \"keydown\" should be used instead..\n target: this.DOM.input,\n cb: _CB[this.isIE ? 'onInputIE' : 'onInput'].bind(this)\n }, {\n type: 'keydown',\n target: window,\n cb: _CB.onWindowKeyDown.bind(this)\n }, {\n type: 'blur',\n target: this.DOM.input,\n cb: _CB.onFocusBlur.bind(this)\n }, {\n type: 'click',\n target: document,\n cb: _CB.onClickAnywhere.bind(this)\n }];\n var _iterator3 = _createForOfIteratorHelper(this.listeners.global),\n _step3;\n try {\n for (_iterator3.s(); !(_step3 = _iterator3.n()).done;) {\n e = _step3.value;\n e.target[action](e.type, e.cb);\n }\n } catch (err) {\n _iterator3.e(err);\n } finally {\n _iterator3.f();\n }\n },\n unbindGlobal: function unbindGlobal() {\n this.events.bindGlobal.call(this, true);\n },\n /**\r\n * DOM events callbacks\r\n */\n callbacks: {\n onFocusBlur: function onFocusBlur(e) {\n var _this$value;\n var _s = this.settings,\n text = e.target ? this.trim(e.target.textContent) : '',\n // a string\n currentDisplayValue = (_this$value = this.value) === null || _this$value === void 0 || (_this$value = _this$value[0]) === null || _this$value === void 0 ? void 0 : _this$value[_s.tagTextProp],\n type = e.type,\n ddEnabled = _s.dropdown.enabled >= 0,\n eventData = {\n relatedTarget: e.relatedTarget\n },\n isTargetSelectOption = this.state.actions.selectOption && (ddEnabled || !_s.dropdown.closeOnSelect),\n isTargetAddNewBtn = this.state.actions.addNew && ddEnabled,\n isRelatedTargetX = e.relatedTarget && isNodeTag.call(this, e.relatedTarget) && this.DOM.scope.contains(e.relatedTarget),\n shouldAddTags;\n if (type == 'blur') {\n if (e.relatedTarget === this.DOM.scope) {\n this.dropdown.hide();\n this.DOM.input.focus();\n return;\n }\n this.postUpdate();\n _s.onChangeAfterBlur && this.triggerChangeEvent();\n }\n if (isTargetSelectOption || isTargetAddNewBtn) return;\n this.state.hasFocus = type == \"focus\" ? +new Date() : false;\n this.toggleFocusClass(this.state.hasFocus);\n if (_s.mode == 'mix') {\n if (type == \"focus\") {\n this.trigger(\"focus\", eventData);\n } else if (e.type == \"blur\") {\n this.trigger(\"blur\", eventData);\n this.loading(false);\n this.dropdown.hide();\n // reset state which needs reseting\n this.state.dropdown.visible = undefined;\n this.setStateSelection();\n }\n return;\n }\n if (type == \"focus\") {\n this.trigger(\"focus\", eventData);\n // e.target.classList.remove('placeholder');\n if (_s.dropdown.enabled === 0 || !_s.userInput) {\n // && _s.mode != \"select\"\n this.dropdown.show(this.value.length ? '' : undefined);\n }\n return;\n } else if (type == \"blur\") {\n this.trigger(\"blur\", eventData);\n this.loading(false);\n\n // when clicking the X button of a selected tag, it is unwanted for it to be added back\n // again in a few more lines of code (shouldAddTags && addTags)\n if (_s.mode == 'select') {\n if (isRelatedTargetX) {\n this.removeTags();\n text = '';\n }\n\n // if nothing has changed (same display value), do not add a tag\n if (currentDisplayValue === text) text = '';\n }\n shouldAddTags = text && !this.state.actions.selectOption && _s.addTagOnBlur;\n\n // do not add a tag if \"selectOption\" action was just fired (this means a tag was just added from the dropdown)\n shouldAddTags && this.addTags(text, true);\n }\n this.DOM.input.removeAttribute('style');\n this.dropdown.hide();\n },\n onCompositionStart: function onCompositionStart(e) {\n this.state.composing = true;\n },\n onCompositionEnd: function onCompositionEnd(e) {\n this.state.composing = false;\n },\n onWindowKeyDown: function onWindowKeyDown(e) {\n var focusedElm = document.activeElement,\n isTag = isNodeTag.call(this, focusedElm),\n isBelong = isTag && this.DOM.scope.contains(document.activeElement),\n isReadyOnlyTag = isBelong && focusedElm.hasAttribute('readonly'),\n nextTag;\n if (!isBelong || isReadyOnlyTag) return;\n nextTag = focusedElm.nextElementSibling;\n switch (e.key) {\n // remove tag if has focus\n case 'Backspace':\n {\n if (!this.settings.readonly) {\n this.removeTags(focusedElm);\n (nextTag ? nextTag : this.DOM.input).focus();\n }\n break;\n }\n\n // edit tag if has focus\n case 'Enter':\n {\n setTimeout(this.editTag.bind(this), 0, focusedElm);\n break;\n }\n }\n },\n onKeydown: function onKeydown(e) {\n var _this11 = this;\n var _s = this.settings;\n\n // ignore keys during IME composition or when user input is not allowed\n if (this.state.composing || !_s.userInput) return;\n if (_s.mode == 'select' && _s.enforceWhitelist && this.value.length && e.key != 'Tab') {\n e.preventDefault();\n }\n var s = this.trim(e.target.textContent);\n this.trigger(\"keydown\", {\n event: e\n });\n\n /**\r\n * ONLY FOR MIX-MODE:\r\n */\n if (_s.mode == 'mix') {\n switch (e.key) {\n case 'Left':\n case 'ArrowLeft':\n {\n // when left arrow was pressed, set a flag so when the dropdown is shown, right-arrow will be ignored\n // because it seems likely the user wishes to use the arrows to move the caret\n this.state.actions.ArrowLeft = true;\n break;\n }\n case 'Delete':\n case 'Backspace':\n {\n if (this.state.editing) return;\n var sel = document.getSelection(),\n deleteKeyTagDetected = e.key == 'Delete' && sel.anchorOffset == (sel.anchorNode.length || 0),\n prevAnchorSibling = sel.anchorNode.previousSibling,\n isCaretAfterTag = sel.anchorNode.nodeType == 1 || !sel.anchorOffset && prevAnchorSibling && prevAnchorSibling.nodeType == 1 && sel.anchorNode.previousSibling;\n decode(this.DOM.input.innerHTML);\n var lastTagElems = this.getTagElms(),\n // isCaretInsideTag = sel.anchorNode.parentNode('.' + _s.classNames.tag),\n tagBeforeCaret,\n tagElmToBeDeleted,\n firstTextNodeBeforeTag;\n if (_s.backspace == 'edit' && isCaretAfterTag) {\n tagBeforeCaret = sel.anchorNode.nodeType == 1 ? null : sel.anchorNode.previousElementSibling;\n setTimeout(this.editTag.bind(this), 0, tagBeforeCaret); // timeout is needed to the last cahacrter in the edited tag won't get deleted\n e.preventDefault(); // needed so the tag elm won't get deleted\n return;\n }\n if (isChromeAndroidBrowser() && isCaretAfterTag instanceof Element) {\n firstTextNodeBeforeTag = getfirstTextNode(isCaretAfterTag);\n if (!isCaretAfterTag.hasAttribute('readonly')) isCaretAfterTag.remove(); // since this is Chrome, can safetly use this \"new\" DOM API\n\n // Android-Chrome wrongly hides the keyboard, and loses focus,\n // so this hack below is needed to regain focus at the correct place:\n this.DOM.input.focus();\n setTimeout(function () {\n _this11.placeCaretAfterNode(firstTextNodeBeforeTag);\n _this11.DOM.input.click();\n });\n return;\n }\n if (sel.anchorNode.nodeName == 'BR') return;\n if ((deleteKeyTagDetected || isCaretAfterTag) && sel.anchorNode.nodeType == 1) {\n if (sel.anchorOffset == 0)\n // caret is at the very begining, before a tag\n tagElmToBeDeleted = deleteKeyTagDetected // delete key pressed\n ? lastTagElems[0] : null;else tagElmToBeDeleted = lastTagElems[Math.min(lastTagElems.length, sel.anchorOffset) - 1];\n\n // find out if a tag *might* be a candidate for deletion, and if so, which\n } else if (deleteKeyTagDetected) tagElmToBeDeleted = sel.anchorNode.nextElementSibling;else if (isCaretAfterTag instanceof Element) tagElmToBeDeleted = isCaretAfterTag;\n\n // tagElm.hasAttribute('readonly')\n if (sel.anchorNode.nodeType == 3 &&\n // node at caret location is a Text node\n !sel.anchorNode.nodeValue &&\n // has some text\n sel.anchorNode.previousElementSibling)\n // text node has a Tag node before it\n e.preventDefault();\n\n // if backspace not allowed, do nothing\n // TODO: a better way to detect if nodes were deleted is to simply check the \"this.value\" before & after\n if ((isCaretAfterTag || deleteKeyTagDetected) && !_s.backspace) {\n e.preventDefault();\n return;\n }\n if (sel.type != 'Range' && !sel.anchorOffset && sel.anchorNode == this.DOM.input && e.key != 'Delete') {\n e.preventDefault();\n return;\n }\n if (sel.type != 'Range' && tagElmToBeDeleted && tagElmToBeDeleted.hasAttribute('readonly')) {\n // allows the continuation of deletion by placing the caret on the first previous textNode.\n // since a few readonly-tags might be one after the other, iteration is needed:\n\n this.placeCaretAfterNode(getfirstTextNode(tagElmToBeDeleted));\n return;\n }\n\n // update regarding https://github.com/yairEO/tagify/issues/762#issuecomment-786464317:\n // the bug described is more severe than the fix below, therefore I disable the fix until a solution\n // is found which work well for both cases.\n // -------\n // nodeType is \"1\" only when the caret is at the end after last tag (no text after), or before first first (no text before)\n /*\r\n if( this.isFirefox && sel.anchorNode.nodeType == 1 && sel.anchorOffset != 0 ){\r\n this.removeTags() // removes last tag by default if no parameter supplied\r\n // place caret inside last textNode, if exist. it's an annoying bug only in FF,\r\n // if the last tag is removed, and there is a textNode before it, the caret is not placed at its end\r\n this.placeCaretAfterNode( setRangeAtStartEnd(false, this.DOM.input) )\r\n }\r\n */\n\n clearTimeout(deleteBackspaceTimeout);\n // a minimum delay is needed before the node actually gets detached from the document (don't know why),\n // to know exactly which tag was deleted. This is the easiest way of knowing besides using MutationObserver\n deleteBackspaceTimeout = setTimeout(function () {\n var sel = document.getSelection();\n decode(_this11.DOM.input.innerHTML);\n !deleteKeyTagDetected && sel.anchorNode.previousSibling;\n\n // fixes #384, where the first and only tag will not get removed with backspace\n /*\r\n * [UPDATE DEC 3, 22] SEEMS BELOEW CODE IS NOT NEEDED ANY MORE\r\n *\r\n if( currentValue.length > lastInputValue.length && prevElm ){\r\n if( isNodeTag.call(this, prevElm) && !prevElm.hasAttribute('readonly') ){\r\n this.removeTags(prevElm)\r\n this.fixFirefoxLastTagNoCaret()\r\n // the above \"removeTag\" methods removes the tag with a transition. Chrome adds a
element for some reason at this stage\r\n if( this.DOM.input.children.length == 2 && this.DOM.input.children[1].tagName == \"BR\" ){\r\n this.DOM.input.innerHTML = \"\"\r\n this.value.length = 0\r\n return true\r\n }\r\n }\r\n else\r\n prevElm.remove()\r\n }\r\n */\n\n // find out which tag(s) were deleted and trigger \"remove\" event\n // iterate over the list of tags still in the document and then filter only those from the \"this.value\" collection\n _this11.value = [].map.call(lastTagElems, function (node, nodeIdx) {\n var tagData = getSetTagData(node);\n\n // since readonly cannot be removed (it's technically resurrected if removed somehow)\n if (node.parentNode || tagData.readonly) return tagData;else _this11.trigger('remove', {\n tag: node,\n index: nodeIdx,\n data: tagData\n });\n }).filter(function (n) {\n return n;\n }); // remove empty items in the mapped array\n }, 20); // Firefox needs this higher duration for some reason or things get buggy when deleting text from the end\n break;\n }\n // currently commented to allow new lines in mixed-mode\n // case 'Enter' :\n // // e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380\n }\n return true;\n }\n switch (e.key) {\n case 'Backspace':\n if (_s.mode == 'select' && _s.enforceWhitelist && this.value.length) this.removeTags();else if (!this.state.dropdown.visible || _s.dropdown.position == 'manual') {\n if (e.target.textContent == \"\" || s.charCodeAt(0) == 8203) {\n // 8203: ZERO WIDTH SPACE unicode\n if (_s.backspace === true) this.removeTags();else if (_s.backspace == 'edit') setTimeout(this.editTag.bind(this), 0); // timeout reason: when edited tag gets focused and the caret is placed at the end, the last character gets deletec (because of backspace)\n }\n }\n break;\n case 'Esc':\n case 'Escape':\n if (this.state.dropdown.visible) return;\n e.target.blur();\n break;\n case 'Down':\n case 'ArrowDown':\n // if( _s.mode == 'select' ) // issue #333\n if (!this.state.dropdown.visible) this.dropdown.show();\n break;\n case 'ArrowRight':\n {\n var tagData = this.state.inputSuggestion || this.state.ddItemData;\n if (tagData && _s.autoComplete.rightKey) {\n this.addTags([tagData], true);\n return;\n }\n break;\n }\n case 'Tab':\n {\n var selectMode = _s.mode == 'select';\n if (s && !selectMode) e.preventDefault();else return true;\n }\n case 'Enter':\n // manual suggestion boxes are assumed to always be visible\n if (this.state.dropdown.visible && _s.dropdown.position != 'manual') return;\n e.preventDefault(); // solves Chrome bug - http://stackoverflow.com/a/20398191/104380\n // because the main \"keydown\" event is bound before the dropdown events, this will fire first and will not *yet*\n // know if an option was just selected from the dropdown menu. If an option was selected,\n // the dropdown events should handle adding the tag\n setTimeout(function () {\n if (_this11.state.dropdown.visible || _this11.state.actions.selectOption) return;\n _this11.addTags(s, true);\n });\n }\n },\n onInput: function onInput(e) {\n this.postUpdate(); // toggles \"tagify--empty\" class\n\n var _s = this.settings;\n if (_s.mode == 'mix') return this.events.callbacks.onMixTagsInput.call(this, e);\n var value = this.input.normalize.call(this),\n showSuggestions = value.length >= _s.dropdown.enabled,\n eventData = {\n value: value,\n inputElm: this.DOM.input\n },\n validation = this.validateTag({\n value: value\n });\n if (_s.mode == 'select') {\n this.toggleScopeValidation(validation);\n }\n eventData.isValid = validation;\n\n // for IE; since IE doesn't have an \"input\" event so \"keyDown\" is used instead to trigger the \"onInput\" callback,\n // and so many keys do not change the input, and for those do not continue.\n if (this.state.inputText == value) return;\n\n // save the value on the input's State object\n this.input.set.call(this, value, false); // update the input with the normalized value and run validations\n // this.setRangeAtStartEnd(false, this.DOM.input); // fix caret position\n\n // if delimiters detected, add tags\n if (value.search(_s.delimiters) != -1) {\n if (this.addTags(value)) {\n this.input.set.call(this); // clear the input field's value\n }\n } else if (_s.dropdown.enabled >= 0) {\n this.dropdown[showSuggestions ? \"show\" : \"hide\"](value);\n }\n this.trigger('input', eventData); // \"input\" event must be triggered at this point, before the dropdown is shown\n },\n onMixTagsInput: function onMixTagsInput(e) {\n var _this12 = this;\n var rangeText,\n match,\n matchedPatternCount,\n tag,\n showSuggestions,\n selection,\n _s = this.settings,\n lastTagsCount = this.value.length,\n matchFlaggedTag,\n matchDelimiters,\n tagsElems = this.getTagElms(),\n fragment = document.createDocumentFragment(),\n range = window.getSelection().getRangeAt(0),\n remainingTagsValues = [].map.call(tagsElems, function (node) {\n return getSetTagData(node).value;\n });\n\n // Android Chrome \"keydown\" event argument does not report the correct \"key\".\n // this workaround is needed to manually call \"onKeydown\" method with a synthesized event object\n if (e.inputType == \"deleteContentBackward\" && isChromeAndroidBrowser()) {\n this.events.callbacks.onKeydown.call(this, {\n target: e.target,\n key: \"Backspace\"\n });\n }\n\n // re-add \"readonly\" tags which might have been removed\n this.value.slice().forEach(function (item) {\n if (item.readonly && !remainingTagsValues.includes(item.value)) fragment.appendChild(_this12.createTagElem(item));\n });\n if (fragment.childNodes.length) {\n range.insertNode(fragment);\n this.setRangeAtStartEnd(false, fragment.lastChild);\n }\n\n // check if tags were \"magically\" added/removed (browser redo/undo or CTRL-A -> delete)\n if (tagsElems.length != lastTagsCount) {\n this.value = [].map.call(this.getTagElms(), function (node) {\n return getSetTagData(node);\n });\n this.update({\n withoutChangeEvent: true\n });\n return;\n }\n if (this.hasMaxTags()) return true;\n if (window.getSelection) {\n selection = window.getSelection();\n\n // only detect tags if selection is inside a textNode (not somehow on already-existing tag)\n if (selection.rangeCount > 0 && selection.anchorNode.nodeType == 3) {\n range = selection.getRangeAt(0).cloneRange();\n range.collapse(true);\n range.setStart(selection.focusNode, 0);\n rangeText = range.toString().slice(0, range.endOffset); // slice the range so everything AFTER the caret will be trimmed\n // split = range.toString().split(_s.mixTagsAllowedAfter) // [\"foo\", \"bar\", \"@baz\"]\n matchedPatternCount = rangeText.split(_s.pattern).length - 1;\n match = rangeText.match(_s.pattern);\n if (match)\n // tag string, example: \"@aaa ccc\"\n tag = rangeText.slice(rangeText.lastIndexOf(match[match.length - 1]));\n if (tag) {\n this.state.actions.ArrowLeft = false; // start fresh, assuming the user did not (yet) used any arrow to move the caret\n this.state.tag = {\n prefix: tag.match(_s.pattern)[0],\n value: tag.replace(_s.pattern, '') // get rid of the prefix\n };\n this.state.tag.baseOffset = selection.baseOffset - this.state.tag.value.length;\n matchDelimiters = this.state.tag.value.match(_s.delimiters);\n // if a delimeter exists, add the value as tag (exluding the delimiter)\n if (matchDelimiters) {\n this.state.tag.value = this.state.tag.value.replace(_s.delimiters, '');\n this.state.tag.delimiters = matchDelimiters[0];\n this.addTags(this.state.tag.value, _s.dropdown.clearOnSelect);\n this.dropdown.hide();\n return;\n }\n showSuggestions = this.state.tag.value.length >= _s.dropdown.enabled;\n\n // When writing something that might look like a tag (an email address) but isn't one - it is unwanted\n // the suggestions dropdown be shown, so the user can close it (in any way), and while continue typing,\n // dropdown should stay closed until another tag is typed.\n // if( this.state.tag.value.length && this.state.dropdown.visible === false )\n // showSuggestions = false\n\n // test for similar flagged tags to the current tag\n\n try {\n matchFlaggedTag = this.state.flaggedTags[this.state.tag.baseOffset];\n matchFlaggedTag = matchFlaggedTag.prefix == this.state.tag.prefix && matchFlaggedTag.value[0] == this.state.tag.value[0];\n\n // reset\n if (this.state.flaggedTags[this.state.tag.baseOffset] && !this.state.tag.value) delete this.state.flaggedTags[this.state.tag.baseOffset];\n } catch (err) {}\n\n // scenario: (do not show suggestions of another matched tag, if more than one detected)\n // (2 tags exist) \" a@a.com and @\"\n // (second tag is removed by backspace) \" a@a.com and \"\n if (matchFlaggedTag || matchedPatternCount < this.state.mixMode.matchedPatternCount) showSuggestions = false;\n }\n // no (potential) tag found\n else {\n this.state.flaggedTags = {};\n }\n this.state.mixMode.matchedPatternCount = matchedPatternCount;\n }\n }\n\n // wait until the \"this.value\" has been updated (see \"onKeydown\" method for \"mix-mode\")\n // the dropdown must be shown only after this event has been triggered, so an implementer could\n // dynamically change the whitelist.\n setTimeout(function () {\n _this12.update({\n withoutChangeEvent: true\n });\n _this12.trigger(\"input\", extend({}, _this12.state.tag, {\n textContent: _this12.DOM.input.textContent\n }));\n if (_this12.state.tag) _this12.dropdown[showSuggestions ? \"show\" : \"hide\"](_this12.state.tag.value);\n }, 10);\n },\n onInputIE: function onInputIE(e) {\n var _this = this;\n // for the \"e.target.textContent\" to be changed, the browser requires a small delay\n setTimeout(function () {\n _this.events.callbacks.onInput.call(_this, e);\n });\n },\n observeOriginalInputValue: function observeOriginalInputValue() {\n // if, for some reason, the Tagified element is no longer in the DOM,\n // call the \"destroy\" method to kill all references to timeouts/intervals\n if (!this.DOM.originalInput.parentNode) this.destroy();\n\n // if original input value changed for some reason (for exmaple a form reset)\n if (this.DOM.originalInput.value != this.DOM.originalInput.tagifyValue) this.loadOriginalValues();\n },\n onClickAnywhere: function onClickAnywhere(e) {\n if (e.target != this.DOM.scope && !this.DOM.scope.contains(e.target)) {\n this.toggleFocusClass(false);\n this.state.hasFocus = false;\n }\n },\n onClickScope: function onClickScope(e) {\n var _s = this.settings,\n tagElm = e.target.closest('.' + _s.classNames.tag),\n timeDiffFocus = +new Date() - this.state.hasFocus;\n if (e.target == this.DOM.scope) {\n // if( !this.state.hasFocus )\n this.DOM.input.focus();\n return;\n } else if (e.target.classList.contains(_s.classNames.tagX)) {\n this.removeTags(e.target.parentNode);\n return;\n } else if (tagElm) {\n this.trigger(\"click\", {\n tag: tagElm,\n index: this.getNodeIndex(tagElm),\n data: getSetTagData(tagElm),\n event: e\n });\n if (_s.editTags === 1 || _s.editTags.clicks === 1) this.events.callbacks.onDoubleClickScope.call(this, e);\n return;\n }\n\n // when clicking on the input itself\n else if (e.target == this.DOM.input) {\n if (_s.mode == 'mix') {\n // firefox won't show caret if last element is a tag (and not a textNode),\n // so an empty textnode should be added\n this.fixFirefoxLastTagNoCaret();\n }\n if (timeDiffFocus > 500) {\n if (this.state.dropdown.visible) this.dropdown.hide();else if (_s.dropdown.enabled === 0 && _s.mode != 'mix') this.dropdown.show(this.value.length ? '' : undefined);\n return;\n }\n }\n if (_s.mode == 'select' && _s.dropdown.enabled === 0 && !this.state.dropdown.visible) this.dropdown.show();\n },\n // special proccess is needed for pasted content in order to \"clean\" it\n onPaste: function onPaste(e) {\n var _this13 = this;\n e.preventDefault();\n var _s = this.settings,\n selectModeWithoutInput = _s.mode == 'select' && _s.enforceWhitelist;\n if (selectModeWithoutInput || !_s.userInput) {\n return false;\n }\n var clipboardData, pastedText;\n if (_s.readonly) return;\n\n // Get pasted data via clipboard API\n clipboardData = e.clipboardData || window.clipboardData;\n pastedText = clipboardData.getData('Text');\n _s.hooks.beforePaste(e, {\n tagify: this,\n pastedText: pastedText,\n clipboardData: clipboardData\n }).then(function (result) {\n if (result === undefined) result = pastedText;\n if (result) {\n _this13.injectAtCaret(result, window.getSelection().getRangeAt(0));\n if (_this13.settings.mode == 'mix') {\n _this13.events.callbacks.onMixTagsInput.call(_this13, e);\n } else if (_this13.settings.pasteAsTags) {\n _this13.addTags(_this13.state.inputText + result, true);\n } else _this13.state.inputText = result;\n }\n }).catch(function (err) {\n return err;\n });\n },\n onDrop: function onDrop(e) {\n e.preventDefault();\n },\n onEditTagInput: function onEditTagInput(editableElm, e) {\n var tagElm = editableElm.closest('.' + this.settings.classNames.tag),\n tagElmIdx = this.getNodeIndex(tagElm),\n tagData = getSetTagData(tagElm),\n textValue = this.input.normalize.call(this, editableElm),\n dataForChangedProp = _defineProperty2(_defineProperty2({}, this.settings.tagTextProp, textValue), \"__tagId\", tagData.__tagId),\n // \"__tagId\" is needed so validation will skip current tag when checking for dups\n isValid = this.validateTag(dataForChangedProp),\n // the value could have been invalid in the first-place so make sure to re-validate it (via \"addEmptyTag\" method)\n hasChanged = this.editTagChangeDetected(extend(tagData, dataForChangedProp));\n\n // if the value is same as before-editing and the tag was valid before as well, ignore the current \"isValid\" result, which is false-positive\n if (!hasChanged && editableElm.originalIsValid === true) isValid = true;\n tagElm.classList.toggle(this.settings.classNames.tagInvalid, isValid !== true);\n tagData.__isValid = isValid;\n tagElm.title = isValid === true ? tagData.title || tagData.value : isValid; // change the tag's title to indicate why is the tag invalid (if it's so)\n\n // show dropdown if typed text is equal or more than the \"enabled\" dropdown setting\n if (textValue.length >= this.settings.dropdown.enabled) {\n // this check is needed apparently because doing browser \"undo\" will fire\n // \"onEditTagInput\" but \"this.state.editing\" will be \"false\"\n if (this.state.editing) this.state.editing.value = textValue;\n this.dropdown.show(textValue);\n }\n this.trigger(\"edit:input\", {\n tag: tagElm,\n index: tagElmIdx,\n data: extend({}, this.value[tagElmIdx], {\n newValue: textValue\n }),\n event: e\n });\n },\n onEditTagPaste: function onEditTagPaste(tagElm, e) {\n // Get pasted data via clipboard API\n var clipboardData = e.clipboardData || window.clipboardData,\n pastedText = clipboardData.getData('Text');\n e.preventDefault();\n var newNode = _injectAtCaret(pastedText);\n this.setRangeAtStartEnd(false, newNode);\n },\n onEditTagFocus: function onEditTagFocus(tagElm) {\n this.state.editing = {\n scope: tagElm,\n input: tagElm.querySelector(\"[contenteditable]\")\n };\n },\n onEditTagBlur: function onEditTagBlur(editableElm) {\n if (!this.state.hasFocus) this.toggleFocusClass();\n\n // one scenario is when selecting a suggestion from the dropdown, when editing, and by selecting it\n // the \"onEditTagDone\" is called directly, already replacing the tag, so the argument \"editableElm\"\n // node isn't in the DOM anynmore because it has been replaced.\n if (!this.DOM.scope.contains(editableElm)) return;\n var _s = this.settings,\n tagElm = editableElm.closest('.' + _s.classNames.tag),\n tagData = getSetTagData(tagElm),\n textValue = this.input.normalize.call(this, editableElm),\n dataForChangedProp = _defineProperty2(_defineProperty2({}, _s.tagTextProp, textValue), \"__tagId\", tagData.__tagId),\n // \"__tagId\" is needed so validation will skip current tag when checking for dups\n originalData = tagData.__originalData,\n // pre-edit data\n hasChanged = this.editTagChangeDetected(extend(tagData, dataForChangedProp)),\n isValid = this.validateTag(dataForChangedProp),\n // \"__tagId\" is needed so validation will skip current tag when checking for dups\n hasMaxTags,\n newTagData;\n if (!textValue) {\n this.onEditTagDone(tagElm);\n return;\n }\n\n // if nothing changed revert back to how it was before editing\n if (!hasChanged) {\n this.onEditTagDone(tagElm, originalData);\n return;\n }\n\n // need to know this because if \"keepInvalidTags\" setting is \"true\" and an invalid tag is edited as a valid one,\n // but the maximum number of tags have alreay been reached, so it should not allow saving the new valid value.\n // only if the tag was already valid before editing, ignore this check (see a few lines below)\n hasMaxTags = this.hasMaxTags();\n newTagData = extend({}, originalData, _defineProperty2(_defineProperty2({}, _s.tagTextProp, this.trim(textValue)), \"__isValid\", isValid));\n\n // pass through optional transformer defined in settings\n _s.transformTag.call(this, newTagData, originalData);\n\n // MUST re-validate after tag transformation\n // only validate the \"tagTextProp\" because is the only thing that metters for validating an edited tag.\n // -- Scenarios: --\n // 1. max 3 tags allowd. there are 4 tags, one has invalid input and is edited to a valid one, and now should be marked as \"not allowed\" because limit of tags has reached\n // 2. max 3 tags allowed. there are 3 tags, one is edited, and so max-tags vaildation should be OK\n isValid = (!hasMaxTags || originalData.__isValid === true) && this.validateTag(newTagData);\n if (isValid !== true) {\n this.trigger(\"invalid\", {\n data: newTagData,\n tag: tagElm,\n message: isValid\n });\n\n // do nothing if invalid, stay in edit-mode until corrected or reverted by presssing esc\n if (_s.editTags.keepInvalid) return;\n if (_s.keepInvalidTags) newTagData.__isValid = isValid;else\n // revert back if not specified to keep\n newTagData = originalData;\n } else if (_s.keepInvalidTags) {\n // cleaup any previous leftovers if the tag was invalid\n delete newTagData.title;\n delete newTagData[\"aria-invalid\"];\n delete newTagData.class;\n }\n\n // tagElm.classList.toggle(_s.classNames.tagInvalid, true)\n\n this.onEditTagDone(tagElm, newTagData);\n },\n onEditTagkeydown: function onEditTagkeydown(e, tagElm) {\n // ignore keys during IME composition\n if (this.state.composing) return;\n this.trigger(\"edit:keydown\", {\n event: e\n });\n switch (e.key) {\n case 'Esc':\n case 'Escape':\n {\n // revert the tag to how it was before editing\n // replace current tag with original one (pre-edited one)\n tagElm.parentNode.replaceChild(tagElm.__tagifyTagData.__originalHTML, tagElm);\n this.state.editing = false;\n }\n case 'Enter':\n case 'Tab':\n e.preventDefault();\n e.target.blur();\n }\n },\n onDoubleClickScope: function onDoubleClickScope(e) {\n var tagElm = e.target.closest('.' + this.settings.classNames.tag),\n tagData = getSetTagData(tagElm),\n _s = this.settings,\n isEditingTag,\n isReadyOnlyTag;\n if (!tagElm || !_s.userInput || tagData.editable === false) return;\n isEditingTag = tagElm.classList.contains(this.settings.classNames.tagEditing);\n isReadyOnlyTag = tagElm.hasAttribute('readonly');\n if (_s.mode != 'select' && !_s.readonly && !isEditingTag && !isReadyOnlyTag && this.settings.editTags) this.editTag(tagElm);\n this.toggleFocusClass(true);\n this.trigger('dblclick', {\n tag: tagElm,\n index: this.getNodeIndex(tagElm),\n data: getSetTagData(tagElm)\n });\n },\n /**\r\n *\r\n * @param {Object} m an object representing the observed DOM changes\r\n */\n onInputDOMChange: function onInputDOMChange(m) {\n var _this14 = this;\n // iterate all DOm mutation\n m.forEach(function (record) {\n // only the ADDED nodes\n record.addedNodes.forEach(function (addedNode) {\n // fix chrome's placing '

' everytime ENTER key is pressed, and replace with just `
') {\n addedNode.replaceWith(document.createElement('br'));\n }\n\n // if the added element is a div containing a tag within it (chrome does this when pressing ENTER before a tag)\n else if (addedNode.nodeType == 1 && addedNode.querySelector(_this14.settings.classNames.tagSelector)) {\n var newlineText = document.createTextNode('');\n if (addedNode.childNodes[0].nodeType == 3 && addedNode.previousSibling.nodeName != 'BR') newlineText = document.createTextNode('\\n');\n\n // unwrap the useless div\n // chrome adds a BR at the end which should be removed\n addedNode.replaceWith.apply(addedNode, [newlineText].concat(_toConsumableArray(_toConsumableArray(addedNode.childNodes).slice(0, -1))));\n _this14.placeCaretAfterNode(newlineText);\n }\n\n // if this is a tag\n else if (isNodeTag.call(_this14, addedNode)) {\n var _addedNode$previousSi;\n if (((_addedNode$previousSi = addedNode.previousSibling) === null || _addedNode$previousSi === void 0 ? void 0 : _addedNode$previousSi.nodeType) == 3 && !addedNode.previousSibling.textContent) addedNode.previousSibling.remove();\n // and it is the first node in a new line\n if (addedNode.previousSibling && addedNode.previousSibling.nodeName == 'BR') {\n // allows placing the caret just before the tag, when the tag is the first node in that line\n addedNode.previousSibling.replaceWith(\"\\n\\u200B\");\n var nextNode = addedNode.nextSibling,\n anythingAfterNode = '';\n while (nextNode) {\n anythingAfterNode += nextNode.textContent;\n nextNode = nextNode.nextSibling;\n }\n\n // when hitting ENTER for new line just before an existing tag, but skip below logic when a tag has been addded\n anythingAfterNode.trim() && _this14.placeCaretAfterNode(addedNode.previousSibling);\n }\n }\n });\n record.removedNodes.forEach(function (removedNode) {\n // when trying to delete a tag which is in a new line and there's nothing else there (caret is after the tag)\n if (removedNode && removedNode.nodeName == 'BR' && isNodeTag.call(_this14, lastInputChild)) {\n _this14.removeTags(lastInputChild);\n _this14.fixFirefoxLastTagNoCaret();\n }\n });\n });\n\n // get the last child only after the above DOM modifications\n // check these scenarios:\n // 1. after a single line, press ENTER once - should add only 1 BR\n // 2. presss ENTER right before a tag\n // 3. press enter within a text node before a tag\n var lastInputChild = this.DOM.input.lastChild;\n if (lastInputChild && lastInputChild.nodeValue == '') lastInputChild.remove();\n\n // make sure the last element is always a BR\n if (!lastInputChild || lastInputChild.nodeName != 'BR') {\n this.DOM.input.appendChild(document.createElement('br'));\n }\n }\n }\n};\n\n/**\r\n * @constructor\r\n * @param {Object} input DOM element\r\n * @param {Object} settings settings object\r\n */\nfunction Tagify(input, settings) {\n if (!input) {\n console.warn('Tagify:', 'input element not found', input);\n // return an empty mock of all methods, so the code using tagify will not break\n // because it might be calling methods even though the input element does not exist\n var mockInstance = new Proxy(this, {\n get: function get() {\n return function () {\n return mockInstance;\n };\n }\n });\n return mockInstance;\n }\n if (input.__tagify) {\n console.warn('Tagify: ', 'input element is already Tagified - Same instance is returned.', input);\n return input.__tagify;\n }\n extend(this, EventDispatcher(this));\n this.isFirefox = /firefox|fxios/i.test(navigator.userAgent) && !/seamonkey/i.test(navigator.userAgent);\n this.isIE = window.document.documentMode; // https://developer.mozilla.org/en-US/docs/Web/API/Document/compatMode#Browser_compatibility\n\n settings = settings || {};\n this.getPersistedData = getPersistedData(settings.id);\n this.setPersistedData = setPersistedData(settings.id);\n this.clearPersistedData = clearPersistedData(settings.id);\n this.applySettings(input, settings);\n this.state = {\n inputText: '',\n editing: false,\n composing: false,\n actions: {},\n // UI actions for state-locking\n mixMode: {},\n dropdown: {},\n flaggedTags: {} // in mix-mode, when a string is detetced as potential tag, and the user has chocen to close the suggestions dropdown, keep the record of the tasg here\n };\n this.value = []; // tags' data\n\n // events' callbacks references will be stores here, so events could be unbinded\n this.listeners = {};\n this.DOM = {}; // Store all relevant DOM elements in an Object\n\n this.build(input);\n initDropdown.call(this);\n this.getCSSVars();\n this.loadOriginalValues();\n this.events.customBinding.call(this);\n this.events.binding.call(this);\n input.autofocus && this.DOM.input.focus();\n input.__tagify = this;\n}\nTagify.prototype = {\n _dropdown: _dropdown,\n getSetTagData: getSetTagData,\n helpers: {\n sameStr: sameStr,\n removeCollectionProp: removeCollectionProp,\n omit: omit,\n isObject: isObject,\n parseHTML: parseHTML,\n escapeHTML: escapeHTML,\n extend: extend,\n concatWithoutDups: concatWithoutDups,\n getUID: getUID,\n isNodeTag: isNodeTag\n },\n customEventsList: ['change', 'add', 'remove', 'invalid', 'input', 'click', 'keydown', 'focus', 'blur', 'edit:input', 'edit:beforeUpdate', 'edit:updated', 'edit:start', 'edit:keydown', 'dropdown:show', 'dropdown:hide', 'dropdown:select', 'dropdown:updated', 'dropdown:noMatch', 'dropdown:scroll'],\n dataProps: ['__isValid', '__removed', '__originalData', '__originalHTML', '__tagId'],\n // internal-uasge props\n trim: function trim(text) {\n return this.settings.trim && text && typeof text == \"string\" ? text.trim() : text;\n },\n // expose this handy utility function\n parseHTML: parseHTML,\n templates: templates,\n parseTemplate: function parseTemplate(template, data) {\n template = this.settings.templates[template] || template;\n return parseHTML(template.apply(this, data));\n },\n set whitelist(arr) {\n var isArray = arr && Array.isArray(arr);\n this.settings.whitelist = isArray ? arr : [];\n this.setPersistedData(isArray ? arr : [], 'whitelist');\n },\n get whitelist() {\n return this.settings.whitelist;\n },\n generateClassSelectors: function generateClassSelectors(classNames) {\n var _loop2 = function _loop2() {\n var currentName = name;\n Object.defineProperty(classNames, currentName + \"Selector\", {\n get: function get() {\n return \".\" + this[currentName].split(\" \")[0];\n }\n });\n };\n for (var name in classNames) {\n _loop2();\n }\n },\n applySettings: function applySettings(input, settings) {\n var _settings$dropdown, _settings$dropdown2;\n DEFAULTS.templates = this.templates;\n var mixModeDefaults = {\n dropdown: {\n position: \"text\"\n }\n };\n var mergedDefaults = extend({}, DEFAULTS, settings.mode == 'mix' ? mixModeDefaults : {});\n var _s = this.settings = extend({}, mergedDefaults, settings);\n _s.disabled = input.hasAttribute('disabled');\n _s.readonly = _s.readonly || input.hasAttribute('readonly');\n _s.placeholder = escapeHTML(input.getAttribute('placeholder') || _s.placeholder || \"\");\n _s.required = input.hasAttribute('required');\n this.generateClassSelectors(_s.classNames);\n if (_s.dropdown.includeSelectedTags === undefined) _s.dropdown.includeSelectedTags = _s.duplicates;\n if (this.isIE) _s.autoComplete = false; // IE goes crazy if this isn't false\n\n [\"whitelist\", \"blacklist\"].forEach(function (name) {\n var attrVal = input.getAttribute('data-' + name);\n if (attrVal) {\n attrVal = attrVal.split(_s.delimiters);\n if (attrVal instanceof Array) _s[name] = attrVal;\n }\n });\n\n // backward-compatibility for old version of \"autoComplete\" setting:\n if (\"autoComplete\" in settings && !isObject(settings.autoComplete)) {\n _s.autoComplete = DEFAULTS.autoComplete;\n _s.autoComplete.enabled = settings.autoComplete;\n }\n if (_s.mode == 'mix') {\n _s.pattern = _s.pattern || /@/;\n _s.autoComplete.rightKey = true;\n _s.delimiters = settings.delimiters || null; // default dlimiters in mix-mode must be NULL\n\n // needed for \"filterListItems\". This assumes the user might have forgotten to manually\n // define the same term in \"dropdown.searchKeys\" as defined in \"tagTextProp\" setting, so\n // by automatically adding it, tagify is \"helping\" out, guessing the intesntions of the developer.\n if (_s.tagTextProp && !_s.dropdown.searchKeys.includes(_s.tagTextProp)) _s.dropdown.searchKeys.push(_s.tagTextProp);\n }\n if (input.pattern) try {\n _s.pattern = new RegExp(input.pattern);\n } catch (e) {}\n\n // Convert the \"delimiters\" setting into a REGEX object\n if (_s.delimiters) {\n _s._delimiters = _s.delimiters;\n try {\n _s.delimiters = new RegExp(this.settings.delimiters, \"g\");\n } catch (e) {}\n }\n if (_s.disabled) _s.userInput = false;\n this.TEXTS = _objectSpread2(_objectSpread2({}, TEXTS), _s.texts || {});\n\n // make sure the dropdown will be shown on \"focus\" and not only after typing something (in \"select\" mode)\n if (_s.mode == 'select' && !((_settings$dropdown = settings.dropdown) !== null && _settings$dropdown !== void 0 && _settings$dropdown.enabled) || !_s.userInput) {\n _s.dropdown.enabled = 0;\n }\n _s.dropdown.appendTarget = ((_settings$dropdown2 = settings.dropdown) === null || _settings$dropdown2 === void 0 ? void 0 : _settings$dropdown2.appendTarget) || document.body;\n\n // get & merge persisted data with current data\n var persistedWhitelist = this.getPersistedData('whitelist');\n if (Array.isArray(persistedWhitelist)) this.whitelist = Array.isArray(_s.whitelist) ? concatWithoutDups(_s.whitelist, persistedWhitelist) : persistedWhitelist;\n },\n /**\r\n * Returns a string of HTML element attributes\r\n * @param {Object} data [Tag data]\r\n */\n getAttributes: function getAttributes(data) {\n var attrs = this.getCustomAttributes(data),\n s = '',\n k;\n for (k in attrs) s += \" \" + k + (data[k] !== undefined ? \"=\\\"\".concat(attrs[k], \"\\\"\") : \"\");\n return s;\n },\n /**\r\n * Returns an object of attributes to be used for the templates\r\n */\n getCustomAttributes: function getCustomAttributes(data) {\n // only items which are objects have properties which can be used as attributes\n if (!isObject(data)) return '';\n var output = {},\n propName;\n for (propName in data) {\n if (propName.slice(0, 2) != '__' && propName != 'class' && data.hasOwnProperty(propName) && data[propName] !== undefined) output[propName] = escapeHTML(data[propName]);\n }\n return output;\n },\n setStateSelection: function setStateSelection() {\n var selection = window.getSelection();\n\n // save last selection place to be able to inject anything from outside to that specific place\n var sel = {\n anchorOffset: selection.anchorOffset,\n anchorNode: selection.anchorNode,\n range: selection.getRangeAt && selection.rangeCount && selection.getRangeAt(0)\n };\n this.state.selection = sel;\n return sel;\n },\n /**\r\n * Get specific CSS variables which are relevant to this script and parse them as needed.\r\n * The result is saved on the instance in \"this.CSSVars\"\r\n */\n getCSSVars: function getCSSVars() {\n var compStyle = getComputedStyle(this.DOM.scope, null);\n var getProp = function getProp(name) {\n return compStyle.getPropertyValue('--' + name);\n };\n function seprateUnitFromValue(a) {\n if (!a) return {};\n a = a.trim().split(' ')[0];\n var unit = a.split(/\\d+/g).filter(function (n) {\n return n;\n }).pop().trim(),\n value = +a.split(unit).filter(function (n) {\n return n;\n })[0].trim();\n return {\n value: value,\n unit: unit\n };\n }\n this.CSSVars = {\n tagHideTransition: function (_ref) {\n var value = _ref.value,\n unit = _ref.unit;\n return unit == 's' ? value * 1000 : value;\n }(seprateUnitFromValue(getProp('tag-hide-transition')))\n };\n },\n /**\r\n * builds the HTML of this component\r\n * @param {Object} input [DOM element which would be \"transformed\" into \"Tags\"]\r\n */\n build: function build(input) {\n var DOM = this.DOM;\n if (this.settings.mixMode.integrated) {\n DOM.originalInput = null;\n DOM.scope = input;\n DOM.input = input;\n } else {\n DOM.originalInput = input;\n DOM.originalInput_tabIndex = input.tabIndex;\n DOM.scope = this.parseTemplate('wrapper', [input, this.settings]);\n DOM.input = DOM.scope.querySelector(this.settings.classNames.inputSelector);\n input.parentNode.insertBefore(DOM.scope, input);\n input.tabIndex = -1; // do not allow focus or typing directly, once tagified\n }\n },\n /**\r\n * revert any changes made by this component\r\n */\n destroy: function destroy() {\n this.events.unbindGlobal.call(this);\n this.DOM.scope.parentNode.removeChild(this.DOM.scope);\n this.DOM.originalInput.tabIndex = this.DOM.originalInput_tabIndex;\n delete this.DOM.originalInput.__tagify;\n this.dropdown.hide(true);\n clearTimeout(this.dropdownHide__bindEventsTimeout);\n clearInterval(this.listeners.main.originalInputValueObserverInterval);\n },\n /**\r\n * if the original input has any values, add them as tags\r\n */\n loadOriginalValues: function loadOriginalValues(value) {\n var lastChild,\n _s = this.settings;\n\n // temporarily block firing the \"change\" event on the original input until\n // this method finish removing current value and adding a new one\n this.state.blockChangeEvent = true;\n if (value === undefined) {\n var persistedOriginalValue = this.getPersistedData('value');\n\n // if the field already has a field, trust its the desired\n // one to be rendered and do not use the persisted one\n if (persistedOriginalValue && !this.DOM.originalInput.value) value = persistedOriginalValue;else value = _s.mixMode.integrated ? this.DOM.input.textContent : this.DOM.originalInput.value;\n }\n this.removeAllTags();\n if (value) {\n if (_s.mode == 'mix') {\n this.parseMixTags(value);\n lastChild = this.DOM.input.lastChild;\n\n // fixes a Chrome bug, when the last node in `mix-mode` is a tag, the caret appears at the far-top-top, outside the field\n if (!lastChild || lastChild.tagName != 'BR') this.DOM.input.insertAdjacentHTML('beforeend', '
');\n } else {\n try {\n if (JSON.parse(value) instanceof Array) value = JSON.parse(value);\n } catch (err) {}\n this.addTags(value, true).forEach(function (tag) {\n return tag && tag.classList.add(_s.classNames.tagNoAnimation);\n });\n }\n } else this.postUpdate();\n this.state.lastOriginalValueReported = _s.mixMode.integrated ? '' : this.DOM.originalInput.value;\n },\n cloneEvent: function cloneEvent(e) {\n var clonedEvent = {};\n for (var v in e) if (v != 'path') clonedEvent[v] = e[v];\n return clonedEvent;\n },\n /**\r\n * Toogle global loading state on/off\r\n * Useful when fetching async whitelist while user is typing\r\n * @param {Boolean} isLoading\r\n */\n loading: function loading(isLoading) {\n this.state.isLoading = isLoading;\n // IE11 doesn't support toggle with second parameter\n this.DOM.scope.classList[isLoading ? \"add\" : \"remove\"](this.settings.classNames.scopeLoading);\n return this;\n },\n /**\r\n * Toogle a tag loading state on/off\r\n * @param {Boolean} isLoading\r\n */\n tagLoading: function tagLoading(tagElm, isLoading) {\n if (tagElm)\n // IE11 doesn't support toggle with second parameter\n tagElm.classList[isLoading ? \"add\" : \"remove\"](this.settings.classNames.tagLoading);\n return this;\n },\n /**\r\n * Toggles class on the main tagify container (\"scope\")\r\n * @param {String} className\r\n * @param {Boolean} force\r\n */\n toggleClass: function toggleClass(className, force) {\n if (typeof className == 'string') this.DOM.scope.classList.toggle(className, force);\n },\n toggleScopeValidation: function toggleScopeValidation(validation) {\n var isValid = validation === true || validation === undefined; // initially it is undefined\n\n if (!this.settings.required && validation && validation === this.TEXTS.empty) isValid = true;\n this.toggleClass(this.settings.classNames.tagInvalid, !isValid);\n this.DOM.scope.title = isValid ? '' : validation;\n },\n toggleFocusClass: function toggleFocusClass(force) {\n this.toggleClass(this.settings.classNames.focus, !!force);\n },\n triggerChangeEvent: triggerChangeEvent,\n events: events,\n fixFirefoxLastTagNoCaret: function fixFirefoxLastTagNoCaret() {\n return; // seems to be fixed in newer version of FF, so retiring below code (for now)\n // var inputElm = this.DOM.input\n\n // if( this.isFirefox && inputElm.childNodes.length && inputElm.lastChild.nodeType == 1 ){\n // inputElm.appendChild(document.createTextNode(\"\\u200b\"))\n // this.setRangeAtStartEnd(true, inputElm)\n // return true\n // }\n },\n /** https://stackoverflow.com/a/59156872/104380\r\n * @param {Boolean} start indicating where to place it (start or end of the node)\r\n * @param {Object} node DOM node to place the caret at\r\n */\n setRangeAtStartEnd: function setRangeAtStartEnd(start, node) {\n if (!node) return;\n start = typeof start == 'number' ? start : !!start;\n node = node.lastChild || node;\n var sel = document.getSelection();\n\n // do not force caret placement if the current selection (focus) is on another element (not this tagify instance)\n if (sel.focusNode instanceof Element && !this.DOM.input.contains(sel.focusNode)) {\n return true;\n }\n try {\n if (sel.rangeCount >= 1) {\n ['Start', 'End'].forEach(function (pos) {\n return sel.getRangeAt(0)[\"set\" + pos](node, start ? start : node.length);\n });\n }\n } catch (err) {\n // console.warn(\"Tagify: \", err)\n }\n },\n placeCaretAfterNode: function placeCaretAfterNode(node) {\n if (!node || !node.parentNode) return;\n var nextSibling = node,\n sel = window.getSelection(),\n range = sel.getRangeAt(0);\n if (sel.rangeCount) {\n range.setStartAfter(nextSibling);\n range.collapse(true);\n // range.setEndBefore(nextSibling || node);\n sel.removeAllRanges();\n sel.addRange(range);\n }\n },\n insertAfterTag: function insertAfterTag(tagElm, newNode) {\n newNode = newNode || this.settings.mixMode.insertAfterTag;\n if (!tagElm || !tagElm.parentNode || !newNode) return;\n newNode = typeof newNode == 'string' ? document.createTextNode(newNode) : newNode;\n tagElm.parentNode.insertBefore(newNode, tagElm.nextSibling);\n return newNode;\n },\n // compares all \"__originalData\" property values with the current \"tagData\" properties\n // and returns \"true\" if something changed.\n editTagChangeDetected: function editTagChangeDetected(tagData) {\n var originalData = tagData.__originalData;\n for (var prop in originalData) if (!this.dataProps.includes(prop) && tagData[prop] != originalData[prop]) return true;\n return false; // not changed\n },\n // returns the node which has the actual tag's content\n getTagTextNode: function getTagTextNode(tagElm) {\n return tagElm.querySelector(this.settings.classNames.tagTextSelector);\n },\n // sets the text of a tag\n setTagTextNode: function setTagTextNode(tagElm, HTML) {\n this.getTagTextNode(tagElm).innerHTML = escapeHTML(HTML);\n },\n /**\r\n * Enters a tag into \"edit\" mode\r\n * @param {Node} tagElm the tag element to edit. if nothing specified, use last last\r\n */\n editTag: function editTag(tagElm, opts) {\n var _this15 = this;\n tagElm = tagElm || this.getLastTag();\n opts = opts || {};\n this.dropdown.hide();\n var _s = this.settings,\n editableElm = this.getTagTextNode(tagElm),\n tagIdx = this.getNodeIndex(tagElm),\n tagData = getSetTagData(tagElm),\n _CB = this.events.callbacks,\n that = this,\n isValid = true,\n delayed_onEditTagBlur = function delayed_onEditTagBlur() {\n setTimeout(function () {\n return _CB.onEditTagBlur.call(that, that.getTagTextNode(tagElm));\n });\n };\n if (!editableElm) {\n console.warn('Cannot find element in Tag template: .', _s.classNames.tagTextSelector);\n return;\n }\n if (tagData instanceof Object && \"editable\" in tagData && !tagData.editable) return;\n\n // cache the original data, on the DOM node, before any modification ocurs, for possible revert\n tagData = getSetTagData(tagElm, {\n __originalData: extend({}, tagData),\n __originalHTML: tagElm.cloneNode(true)\n });\n // re-set the tagify custom-prop on the clones element (because cloning removed it)\n getSetTagData(tagData.__originalHTML, tagData.__originalData);\n editableElm.setAttribute('contenteditable', true);\n tagElm.classList.add(_s.classNames.tagEditing);\n editableElm.addEventListener('focus', _CB.onEditTagFocus.bind(this, tagElm));\n editableElm.addEventListener('blur', delayed_onEditTagBlur);\n editableElm.addEventListener('input', _CB.onEditTagInput.bind(this, editableElm));\n editableElm.addEventListener('paste', _CB.onEditTagPaste.bind(this, editableElm));\n editableElm.addEventListener('keydown', function (e) {\n return _CB.onEditTagkeydown.call(_this15, e, tagElm);\n });\n editableElm.addEventListener('compositionstart', _CB.onCompositionStart.bind(this));\n editableElm.addEventListener('compositionend', _CB.onCompositionEnd.bind(this));\n if (!opts.skipValidation) isValid = this.editTagToggleValidity(tagElm);\n editableElm.originalIsValid = isValid;\n this.trigger(\"edit:start\", {\n tag: tagElm,\n index: tagIdx,\n data: tagData,\n isValid: isValid\n });\n editableElm.focus();\n this.setRangeAtStartEnd(false, editableElm); // place the caret at the END of the editable tag text\n\n return this;\n },\n /**\r\n * If a tag is invalid, for any reason, set its class to \"not allowed\" (see defaults file)\r\n * @param {Node} tagElm required\r\n * @param {Object} tagData optional\r\n * @returns true if valid, a string (reason) if not\r\n */\n editTagToggleValidity: function editTagToggleValidity(tagElm, tagData) {\n var tagData = tagData || getSetTagData(tagElm),\n isValid;\n if (!tagData) {\n console.warn(\"tag has no data: \", tagElm, tagData);\n return;\n }\n isValid = !(\"__isValid\" in tagData) || tagData.__isValid === true;\n if (!isValid) {\n this.removeTagsFromValue(tagElm);\n }\n this.update();\n\n //this.validateTag(tagData);\n\n tagElm.classList.toggle(this.settings.classNames.tagNotAllowed, !isValid);\n return tagData.__isValid;\n },\n onEditTagDone: function onEditTagDone(tagElm, tagData) {\n tagElm = tagElm || this.state.editing.scope;\n tagData = tagData || {};\n var eventData = {\n tag: tagElm,\n index: this.getNodeIndex(tagElm),\n previousData: getSetTagData(tagElm),\n data: tagData\n };\n this.trigger(\"edit:beforeUpdate\", eventData, {\n cloneData: false\n });\n this.state.editing = false;\n delete tagData.__originalData;\n delete tagData.__originalHTML;\n if (tagElm && tagData[this.settings.tagTextProp]) {\n tagElm = this.replaceTag(tagElm, tagData);\n this.editTagToggleValidity(tagElm, tagData);\n if (this.settings.a11y.focusableTags) tagElm.focus();else\n // place caret after edited tag\n this.placeCaretAfterNode(tagElm);\n } else if (tagElm) this.removeTags(tagElm);\n this.trigger(\"edit:updated\", eventData);\n this.dropdown.hide();\n\n // check if any of the current tags which might have been marked as \"duplicate\" should be now un-marked\n if (this.settings.keepInvalidTags) this.reCheckInvalidTags();\n },\n /**\r\n * Replaces an exisitng tag with a new one. Used for updating a tag's data\r\n * @param {Object} tagElm [DOM node to replace]\r\n * @param {Object} tagData [data to create new tag from]\r\n */\n replaceTag: function replaceTag(tagElm, tagData) {\n if (!tagData || !tagData.value) tagData = tagElm.__tagifyTagData;\n\n // if tag is invalid, make the according changes in the newly created element\n if (tagData.__isValid && tagData.__isValid != true) extend(tagData, this.getInvalidTagAttrs(tagData, tagData.__isValid));\n var newTagElm = this.createTagElem(tagData);\n\n // update DOM\n tagElm.parentNode.replaceChild(newTagElm, tagElm);\n this.updateValueByDOMTags();\n return newTagElm;\n },\n /**\r\n * update \"value\" (Array of Objects) by traversing all valid tags\r\n */\n updateValueByDOMTags: function updateValueByDOMTags() {\n var _this16 = this;\n this.value.length = 0;\n [].forEach.call(this.getTagElms(), function (node) {\n if (node.classList.contains(_this16.settings.classNames.tagNotAllowed.split(' ')[0])) return;\n _this16.value.push(getSetTagData(node));\n });\n this.update();\n },\n /**\r\n * injects nodes/text at caret position, which is saved on the \"state\" when \"blur\" event gets triggered\r\n * @param {Node} injectedNode [the node to inject at the caret position]\r\n * @param {Object} selection [optional range Object. must have \"anchorNode\" & \"anchorOffset\"]\r\n */\n injectAtCaret: function injectAtCaret(injectedNode, range) {\n var _this$state$selection;\n range = range || ((_this$state$selection = this.state.selection) === null || _this$state$selection === void 0 ? void 0 : _this$state$selection.range);\n if (!range && injectedNode) {\n this.appendMixTags(injectedNode);\n return this;\n }\n _injectAtCaret(injectedNode, range);\n this.setRangeAtStartEnd(false, injectedNode);\n this.updateValueByDOMTags(); // updates internal \"this.value\"\n this.update(); // updates original input/textarea\n\n return this;\n },\n /**\r\n * input bridge for accessing & setting\r\n * @type {Object}\r\n */\n input: {\n set: function set() {\n var s = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';\n var updateDOM = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true;\n var hideDropdown = this.settings.dropdown.closeOnSelect;\n this.state.inputText = s;\n if (updateDOM) this.DOM.input.innerHTML = escapeHTML(\"\" + s);\n if (!s && hideDropdown) this.dropdown.hide.bind(this);\n this.input.autocomplete.suggest.call(this);\n this.input.validate.call(this);\n },\n raw: function raw() {\n return this.DOM.input.textContent;\n },\n /**\r\n * Marks the tagify's input as \"invalid\" if the value did not pass \"validateTag()\"\r\n */\n validate: function validate() {\n var isValid = !this.state.inputText || this.validateTag({\n value: this.state.inputText\n }) === true;\n this.DOM.input.classList.toggle(this.settings.classNames.inputInvalid, !isValid);\n return isValid;\n },\n // remove any child DOM elements that aren't of type TEXT (like
)\n normalize: function normalize(node) {\n var clone = node || this.DOM.input,\n //.cloneNode(true),\n v = [];\n\n // when a text was pasted in FF, the \"this.DOM.input\" element will have
but no newline symbols (\\n), and this will\n // result in tags not being properly created if one wishes to create a separate tag per newline.\n clone.childNodes.forEach(function (n) {\n return n.nodeType == 3 && v.push(n.nodeValue);\n });\n v = v.join(\"\\n\");\n try {\n // \"delimiters\" might be of a non-regex value, where this will fail (\"Tags With Properties\" example in demo page):\n v = v.replace(/(?:\\r\\n|\\r|\\n)/g, this.settings.delimiters.source.charAt(0));\n } catch (err) {}\n v = v.replace(/\\s/g, ' '); // replace NBSPs with spaces characters\n\n return this.trim(v);\n },\n /**\r\n * suggest the rest of the input's value (via CSS \"::after\" using \"content:attr(...)\")\r\n * @param {String} s [description]\r\n */\n autocomplete: {\n suggest: function suggest(data) {\n if (!this.settings.autoComplete.enabled) return;\n data = data || {\n value: ''\n };\n if (typeof data == 'string') data = {\n value: data\n };\n var suggestedText = this.dropdown.getMappedValue(data);\n if (typeof suggestedText === 'number') return;\n var suggestionStart = suggestedText.substr(0, this.state.inputText.length).toLowerCase(),\n suggestionTrimmed = suggestedText.substring(this.state.inputText.length);\n if (!suggestedText || !this.state.inputText || suggestionStart != this.state.inputText.toLowerCase()) {\n this.DOM.input.removeAttribute(\"data-suggest\");\n delete this.state.inputSuggestion;\n } else {\n this.DOM.input.setAttribute(\"data-suggest\", suggestionTrimmed);\n this.state.inputSuggestion = data;\n }\n },\n /**\r\n * sets the suggested text as the input's value & cleanup the suggestion autocomplete.\r\n * @param {String} s [text]\r\n */\n set: function set(s) {\n var dataSuggest = this.DOM.input.getAttribute('data-suggest'),\n suggestion = s || (dataSuggest ? this.state.inputText + dataSuggest : null);\n if (suggestion) {\n if (this.settings.mode == 'mix') {\n this.replaceTextWithNode(document.createTextNode(this.state.tag.prefix + suggestion));\n } else {\n this.input.set.call(this, suggestion);\n this.setRangeAtStartEnd(false, this.DOM.input);\n }\n this.input.autocomplete.suggest.call(this);\n this.dropdown.hide();\n return true;\n }\n return false;\n }\n }\n },\n /**\r\n * returns the index of the the tagData within the \"this.value\" array collection.\r\n * since values should be unique, it is suffice to only search by \"value\" property\r\n * @param {Object} tagData\r\n */\n getTagIdx: function getTagIdx(tagData) {\n return this.value.findIndex(function (item) {\n return item.__tagId == (tagData || {}).__tagId;\n });\n },\n getNodeIndex: function getNodeIndex(node) {\n var index = 0;\n if (node) while (node = node.previousElementSibling) index++;\n return index;\n },\n getTagElms: function getTagElms() {\n for (var _len = arguments.length, classess = new Array(_len), _key = 0; _key < _len; _key++) {\n classess[_key] = arguments[_key];\n }\n var classname = '.' + [].concat(_toConsumableArray(this.settings.classNames.tag.split(' ')), classess).join('.');\n return [].slice.call(this.DOM.scope.querySelectorAll(classname)); // convert nodeList to Array - https://stackoverflow.com/a/3199627/104380\n },\n /**\r\n * gets the last non-readonly, not-in-the-proccess-of-removal tag\r\n */\n getLastTag: function getLastTag() {\n var lastTag = this.DOM.scope.querySelectorAll(\"\".concat(this.settings.classNames.tagSelector, \":not(.\").concat(this.settings.classNames.tagHide, \"):not([readonly])\"));\n return lastTag[lastTag.length - 1];\n },\n /**\r\n * Searches if any tag with a certain value already exis\r\n * @param {String/Object} value [text value / tag data object]\r\n * @param {Boolean} caseSensitive\r\n * @return {Number}\r\n */\n isTagDuplicate: function isTagDuplicate(value, caseSensitive, tagId) {\n var dupsCount = 0,\n _s = this.settings;\n\n // duplications are irrelevant for this scenario\n if (_s.mode == 'select') return false;\n var _iterator4 = _createForOfIteratorHelper(this.value),\n _step4;\n try {\n for (_iterator4.s(); !(_step4 = _iterator4.n()).done;) {\n var item = _step4.value;\n var isSameStr = sameStr(this.trim(\"\" + value), item.value, caseSensitive);\n if (isSameStr && tagId != item.__tagId) dupsCount++;\n }\n } catch (err) {\n _iterator4.e(err);\n } finally {\n _iterator4.f();\n }\n return dupsCount;\n },\n getTagIndexByValue: function getTagIndexByValue(value) {\n var _this17 = this;\n var indices = [];\n this.getTagElms().forEach(function (tagElm, i) {\n if (sameStr(_this17.trim(tagElm.textContent), value, _this17.settings.dropdown.caseSensitive)) indices.push(i);\n });\n return indices;\n },\n getTagElmByValue: function getTagElmByValue(value) {\n var tagIdx = this.getTagIndexByValue(value)[0];\n return this.getTagElms()[tagIdx];\n },\n /**\r\n * Temporarily marks a tag element (by value or Node argument)\r\n * @param {Object} tagElm [a specific \"tag\" element to compare to the other tag elements siblings]\r\n */\n flashTag: function flashTag(tagElm) {\n var _this18 = this;\n if (tagElm) {\n tagElm.classList.add(this.settings.classNames.tagFlash);\n setTimeout(function () {\n tagElm.classList.remove(_this18.settings.classNames.tagFlash);\n }, 100);\n }\n },\n /**\r\n * checks if text is in the blacklist\r\n */\n isTagBlacklisted: function isTagBlacklisted(v) {\n v = this.trim(v.toLowerCase());\n return this.settings.blacklist.filter(function (x) {\n return (\"\" + x).toLowerCase() == v;\n }).length;\n },\n /**\r\n * checks if text is in the whitelist\r\n */\n isTagWhitelisted: function isTagWhitelisted(v) {\n return !!this.getWhitelistItem(v);\n /*\r\n return this.settings.whitelist.some(item =>\r\n typeof v == 'string'\r\n ? sameStr(this.trim(v), (item.value || item))\r\n : sameStr(JSON.stringify(item), JSON.stringify(v))\r\n )\r\n */\n },\n /**\r\n * Returns the first whitelist item matched, by value (if match found)\r\n * @param {String} value [text to match by]\r\n */\n getWhitelistItem: function getWhitelistItem(value, prop, whitelist) {\n var result,\n prop = prop || 'value',\n _s = this.settings,\n whitelist = whitelist || _s.whitelist;\n whitelist.some(function (_wi) {\n var _wiv = typeof _wi == 'string' ? _wi : _wi[prop] || _wi.value,\n isSameStr = sameStr(_wiv, value, _s.dropdown.caseSensitive, _s.trim);\n if (isSameStr) {\n result = typeof _wi == 'string' ? {\n value: _wi\n } : _wi;\n return true;\n }\n });\n\n // first iterate the whitelist, try find matches by \"value\" and if that fails\n // and a \"tagTextProp\" is set to be other than \"value\", try that also\n if (!result && prop == 'value' && _s.tagTextProp != 'value') {\n // if found, adds the first which matches\n result = this.getWhitelistItem(value, _s.tagTextProp, whitelist);\n }\n return result;\n },\n /**\r\n * validate a tag object BEFORE the actual tag will be created & appeneded\r\n * @param {String} s\r\n * @param {String} uid [unique ID, to not inclue own tag when cheking for duplicates]\r\n * @return {Boolean/String} [\"true\" if validation has passed, String for a fail]\r\n */\n validateTag: function validateTag(tagData) {\n var _s = this.settings,\n // when validating a tag in edit-mode, need to take \"tagTextProp\" into consideration\n prop = \"value\" in tagData ? \"value\" : _s.tagTextProp,\n v = this.trim(tagData[prop] + \"\");\n\n // check for definitive empty value\n if (!(tagData[prop] + \"\").trim()) return this.TEXTS.empty;\n\n // check if pattern should be used and if so, use it to test the value\n if (_s.pattern && _s.pattern instanceof RegExp && !_s.pattern.test(v)) return this.TEXTS.pattern;\n\n // check for duplicates\n if (!_s.duplicates && this.isTagDuplicate(v, _s.dropdown.caseSensitive, tagData.__tagId)) return this.TEXTS.duplicate;\n if (this.isTagBlacklisted(v) || _s.enforceWhitelist && !this.isTagWhitelisted(v)) return this.TEXTS.notAllowed;\n if (_s.validate) return _s.validate(tagData);\n return true;\n },\n getInvalidTagAttrs: function getInvalidTagAttrs(tagData, validation) {\n return {\n \"aria-invalid\": true,\n \"class\": \"\".concat(tagData.class || '', \" \").concat(this.settings.classNames.tagNotAllowed).trim(),\n \"title\": validation\n };\n },\n hasMaxTags: function hasMaxTags() {\n return this.value.length >= this.settings.maxTags ? this.TEXTS.exceed : false;\n },\n setReadonly: function setReadonly(toggle, attrribute) {\n var _s = this.settings;\n document.activeElement.blur(); // exit possible edit-mode\n _s[attrribute || 'readonly'] = toggle;\n this.DOM.scope[(toggle ? 'set' : 'remove') + 'Attribute'](attrribute || 'readonly', true);\n this.setContentEditable(!toggle);\n },\n setContentEditable: function setContentEditable(state) {\n if (!this.settings.userInput) return;\n this.DOM.input.contentEditable = state;\n this.DOM.input.tabIndex = !!state ? 0 : -1;\n },\n setDisabled: function setDisabled(isDisabled) {\n this.setReadonly(isDisabled, 'disabled');\n },\n /**\r\n * pre-proccess the tagsItems, which can be a complex tagsItems like an Array of Objects or a string comprised of multiple words\r\n * so each item should be iterated on and a tag created for.\r\n * @return {Array} [Array of Objects]\r\n */\n normalizeTags: function normalizeTags(tagsItems) {\n var _this19 = this;\n var _this$settings = this.settings,\n whitelist = _this$settings.whitelist,\n delimiters = _this$settings.delimiters,\n mode = _this$settings.mode,\n tagTextProp = _this$settings.tagTextProp,\n whitelistMatches = [],\n whitelistWithProps = whitelist ? whitelist[0] instanceof Object : false,\n isArray = Array.isArray(tagsItems),\n isCollection = isArray && tagsItems[0].value,\n mapStringToCollection = function mapStringToCollection(s) {\n return (s + \"\").split(delimiters).filter(function (n) {\n return n;\n }).map(function (v) {\n return _defineProperty2(_defineProperty2({}, tagTextProp, _this19.trim(v)), \"value\", _this19.trim(v));\n });\n };\n if (typeof tagsItems == 'number') tagsItems = tagsItems.toString();\n\n // if the argument is a \"simple\" String, ex: \"aaa, bbb, ccc\"\n if (typeof tagsItems == 'string') {\n if (!tagsItems.trim()) return [];\n\n // go over each tag and add it (if there were multiple ones)\n tagsItems = mapStringToCollection(tagsItems);\n }\n\n // if is an Array of Strings, convert to an Array of Objects\n else if (isArray) {\n var _ref3;\n // flatten the 2D array\n tagsItems = (_ref3 = []).concat.apply(_ref3, _toConsumableArray(tagsItems.map(function (item) {\n return item.value != undefined ? item // mapStringToCollection(item.value).map(newItem => ({...item,...newItem}))\n : mapStringToCollection(item);\n })));\n }\n\n // search if the tag exists in the whitelist as an Object (has props),\n // to be able to use its properties.\n // skip matching collections with whitelist items as they are considered \"whole\"\n if (whitelistWithProps && !isCollection) {\n tagsItems.forEach(function (item) {\n var whitelistMatchesValues = whitelistMatches.map(function (a) {\n return a.value;\n });\n\n // if suggestions are shown, they are already filtered, so it's easier to use them,\n // because the whitelist might also include items which have already been added\n var filteredList = _this19.dropdown.filterListItems.call(_this19, item[tagTextProp], {\n exact: true\n });\n if (!_this19.settings.duplicates)\n // also filter out items which have already been matched in previous iterations\n filteredList = filteredList.filter(function (filteredItem) {\n return !whitelistMatchesValues.includes(filteredItem.value);\n });\n\n // get the best match out of list of possible matches.\n // if there was a single item in the filtered list, use that one\n var matchObj = filteredList.length > 1 ? _this19.getWhitelistItem(item[tagTextProp], tagTextProp, filteredList) : filteredList[0];\n if (matchObj && matchObj instanceof Object) {\n whitelistMatches.push(matchObj); // set the Array (with the found Object) as the new value\n } else if (mode != 'mix') {\n if (item.value == undefined) item.value = item[tagTextProp];\n whitelistMatches.push(item);\n }\n });\n if (whitelistMatches.length) tagsItems = whitelistMatches;\n }\n return tagsItems;\n },\n /**\r\n * Parse the initial value of a textarea (or input) element and generate mixed text w/ tags\r\n * https://stackoverflow.com/a/57598892/104380\r\n * @param {String} s\r\n */\n parseMixTags: function parseMixTags(s) {\n var _this20 = this;\n var _this$settings2 = this.settings,\n mixTagsInterpolator = _this$settings2.mixTagsInterpolator,\n duplicates = _this$settings2.duplicates,\n transformTag = _this$settings2.transformTag,\n enforceWhitelist = _this$settings2.enforceWhitelist,\n maxTags = _this$settings2.maxTags,\n tagTextProp = _this$settings2.tagTextProp,\n tagsDataSet = [];\n s = s.split(mixTagsInterpolator[0]).map(function (s1, i) {\n var s2 = s1.split(mixTagsInterpolator[1]),\n preInterpolated = s2[0],\n maxTagsReached = tagsDataSet.length == maxTags,\n textProp,\n tagData,\n tagElm;\n try {\n // skip numbers and go straight to the \"catch\" statement\n if (preInterpolated == +preInterpolated) throw Error;\n tagData = JSON.parse(preInterpolated);\n } catch (err) {\n tagData = _this20.normalizeTags(preInterpolated)[0] || {\n value: preInterpolated\n };\n }\n transformTag.call(_this20, tagData);\n if (!maxTagsReached && s2.length > 1 && (!enforceWhitelist || _this20.isTagWhitelisted(tagData.value)) && !(!duplicates && _this20.isTagDuplicate(tagData.value))) {\n // in case \"tagTextProp\" setting is set to other than \"value\" and this tag does not have this prop\n textProp = tagData[tagTextProp] ? tagTextProp : 'value';\n tagData[textProp] = _this20.trim(tagData[textProp]);\n tagElm = _this20.createTagElem(tagData);\n tagsDataSet.push(tagData);\n tagElm.classList.add(_this20.settings.classNames.tagNoAnimation);\n s2[0] = tagElm.outerHTML; //+ \"⁠\" // put a zero-space at the end so the caret won't jump back to the start (when the last input's child element is a tag)\n _this20.value.push(tagData);\n } else if (s1) return i ? mixTagsInterpolator[0] + s1 : s1;\n return s2.join('');\n }).join('');\n this.DOM.input.innerHTML = s;\n this.DOM.input.appendChild(document.createTextNode(''));\n this.DOM.input.normalize();\n this.getTagElms().forEach(function (elm, idx) {\n return getSetTagData(elm, tagsDataSet[idx]);\n });\n this.update({\n withoutChangeEvent: true\n });\n return s;\n },\n /**\r\n * For mixed-mode: replaces a text starting with a prefix with a wrapper element (tag or something)\r\n * First there *has* to be a \"this.state.tag\" which is a string that was just typed and is staring with a prefix\r\n */\n replaceTextWithNode: function replaceTextWithNode(newWrapperNode, strToReplace) {\n if (!this.state.tag && !strToReplace) return;\n strToReplace = strToReplace || this.state.tag.prefix + this.state.tag.value;\n var idx,\n nodeToReplace,\n selection = this.state.selection || window.getSelection(),\n nodeAtCaret = selection.anchorNode,\n firstSplitOffset = this.state.tag.delimiters ? this.state.tag.delimiters.length : 0;\n\n // STEP 1: ex. replace #ba with the tag \"bart\" where \"|\" is where the caret is:\n // CURRENT STATE: \"foo #ba #ba| #ba\"\n\n // split the text node at the index of the caret\n nodeAtCaret.splitText(selection.anchorOffset - firstSplitOffset);\n\n // node 0: \"foo #ba #ba|\"\n // node 1: \" #ba\"\n\n // get index of LAST occurence of \"#ba\"\n idx = nodeAtCaret.nodeValue.lastIndexOf(strToReplace);\n if (idx == -1) return true;\n nodeToReplace = nodeAtCaret.splitText(idx);\n\n // node 0: \"foo #ba \"\n // node 1: \"#ba\" <- nodeToReplace\n\n newWrapperNode && nodeAtCaret.parentNode.replaceChild(newWrapperNode, nodeToReplace);\n\n // must NOT normalize contenteditable or it will cause unwanted issues:\n // https://monosnap.com/file/ZDVmRvq5upYkidiFedvrwzSswegWk7\n // nodeAtCaret.parentNode.normalize()\n\n return true;\n },\n /**\r\n * For selecting a single option (not used for multiple tags, but for \"mode:select\" only)\r\n * @param {Object} tagElm Tag DOM node\r\n * @param {Object} tagData Tag data\r\n */\n selectTag: function selectTag(tagElm, tagData) {\n var _this21 = this;\n var _s = this.settings;\n if (_s.enforceWhitelist && !this.isTagWhitelisted(tagData.value)) return;\n this.input.set.call(this, tagData[_s.tagTextProp] || tagData.value, true);\n\n // place the caret at the end of the input, only if a dropdown option was selected (and not by manually typing another value and clicking \"TAB\")\n if (this.state.actions.selectOption) setTimeout(function () {\n return _this21.setRangeAtStartEnd(false, _this21.DOM.input);\n });\n var lastTagElm = this.getLastTag();\n if (lastTagElm) this.replaceTag(lastTagElm, tagData);else this.appendTag(tagElm);\n\n // if( _s.enforceWhitelist )\n // this.setContentEditable(false);\n\n this.value[0] = tagData;\n this.update();\n this.trigger('add', {\n tag: tagElm,\n data: tagData\n });\n return [tagElm];\n },\n /**\r\n * add an empty \"tag\" element in an editable state\r\n */\n addEmptyTag: function addEmptyTag(initialData) {\n var tagData = extend({\n value: \"\"\n }, initialData || {}),\n tagElm = this.createTagElem(tagData);\n getSetTagData(tagElm, tagData);\n\n // add the tag to the component's DOM\n this.appendTag(tagElm);\n this.editTag(tagElm, {\n skipValidation: true\n });\n },\n /**\r\n * add a \"tag\" element to the \"tags\" component\r\n * @param {String/Array} tagsItems [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]\r\n * @param {Boolean} clearInput [flag if the input's value should be cleared after adding tags]\r\n * @param {Boolean} skipInvalid [do not add, mark & remove invalid tags]\r\n * @return {Array} Array of DOM elements (tags)\r\n */\n addTags: function addTags(tagsItems, clearInput, skipInvalid) {\n var _this22 = this;\n var tagElems = [],\n _s = this.settings,\n aggregatedinvalidInput = [],\n frag = document.createDocumentFragment();\n skipInvalid = skipInvalid || _s.skipInvalid;\n if (!tagsItems || tagsItems.length == 0) {\n return tagElems;\n }\n\n // converts Array/String/Object to an Array of Objects\n tagsItems = this.normalizeTags(tagsItems);\n switch (_s.mode) {\n case 'mix':\n return this.addMixTags(tagsItems);\n case 'select':\n {\n clearInput = false;\n this.removeAllTags();\n }\n }\n this.DOM.input.removeAttribute('style');\n tagsItems.forEach(function (tagData) {\n var tagElm,\n tagElmParams = {},\n originalData = Object.assign({}, tagData, {\n value: tagData.value + \"\"\n });\n\n // shallow-clone tagData so later modifications will not apply to the source\n tagData = Object.assign({}, originalData);\n _s.transformTag.call(_this22, tagData);\n tagData.__isValid = _this22.hasMaxTags() || _this22.validateTag(tagData);\n if (tagData.__isValid !== true) {\n if (skipInvalid) return;\n\n // originalData is kept because it might be that this tag is invalid because it is a duplicate of another,\n // and if that other tags is edited/deleted, this one should be re-validated and if is no more a duplicate - restored\n extend(tagElmParams, _this22.getInvalidTagAttrs(tagData, tagData.__isValid), {\n __preInvalidData: originalData\n });\n if (tagData.__isValid == _this22.TEXTS.duplicate)\n // mark, for a brief moment, the tag (this this one) which THIS CURRENT tag is a duplcate of\n _this22.flashTag(_this22.getTagElmByValue(tagData.value));\n if (!_s.createInvalidTags) {\n aggregatedinvalidInput.push(tagData.value);\n return;\n }\n }\n if ('readonly' in tagData) {\n if (tagData.readonly) tagElmParams[\"aria-readonly\"] = true;\n // if \"readonly\" is \"false\", remove it from the tagData so it won't be added as an attribute in the template\n else delete tagData.readonly;\n }\n\n // Create tag HTML element\n tagElm = _this22.createTagElem(tagData, tagElmParams);\n tagElems.push(tagElm);\n\n // mode-select overrides\n if (_s.mode == 'select') {\n return _this22.selectTag(tagElm, tagData);\n }\n\n // add the tag to the component's DOM\n // this.appendTag(tagElm)\n frag.appendChild(tagElm);\n if (tagData.__isValid && tagData.__isValid === true) {\n // update state\n _this22.value.push(tagData);\n _this22.trigger('add', {\n tag: tagElm,\n index: _this22.value.length - 1,\n data: tagData\n });\n } else {\n _this22.trigger(\"invalid\", {\n data: tagData,\n index: _this22.value.length,\n tag: tagElm,\n message: tagData.__isValid\n });\n if (!_s.keepInvalidTags)\n // remove invalid tags (if \"keepInvalidTags\" is set to \"false\")\n setTimeout(function () {\n return _this22.removeTags(tagElm, true);\n }, 1000);\n }\n _this22.dropdown.position(); // reposition the dropdown because the just-added tag might cause a new-line\n });\n this.appendTag(frag);\n this.update();\n if (tagsItems.length && clearInput) {\n this.input.set.call(this, _s.createInvalidTags ? '' : aggregatedinvalidInput.join(_s._delimiters));\n this.setRangeAtStartEnd(false, this.DOM.input);\n }\n _s.dropdown.enabled && this.dropdown.refilter();\n return tagElems;\n },\n /**\r\n * Adds a mix-content tag\r\n * @param {String/Array} tagData A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings\r\n */\n addMixTags: function addMixTags(tagsData) {\n var _this23 = this;\n tagsData = this.normalizeTags(tagsData);\n if (tagsData[0].prefix || this.state.tag) {\n return this.prefixedTextToTag(tagsData[0]);\n }\n var frag = document.createDocumentFragment();\n tagsData.forEach(function (tagData) {\n var tagElm = _this23.createTagElem(tagData);\n frag.appendChild(tagElm);\n });\n this.appendMixTags(frag);\n return frag;\n },\n appendMixTags: function appendMixTags(node) {\n var selection = !!this.state.selection;\n\n // if \"selection\" exists, assumes intention of inecting the new tag at the last\n // saved location of the caret inside \"this.DOM.input\"\n if (selection) {\n this.injectAtCaret(node);\n }\n // else, create a range and inject the new tag as the last child of \"this.DOM.input\"\n else {\n this.DOM.input.focus();\n selection = this.setStateSelection();\n selection.range.setStart(this.DOM.input, selection.range.endOffset);\n selection.range.setEnd(this.DOM.input, selection.range.endOffset);\n this.DOM.input.appendChild(node);\n this.updateValueByDOMTags(); // updates internal \"this.value\"\n this.update(); // updates original input/textarea\n }\n },\n /**\r\n * Adds a tag which was activly typed by the user\r\n * @param {String/Array} tagItem [A string (single or multiple values with a delimiter), or an Array of Objects or just Array of Strings]\r\n */\n prefixedTextToTag: function prefixedTextToTag(tagItem) {\n var _this24 = this;\n var _s = this.settings,\n tagElm,\n createdFromDelimiters = this.state.tag.delimiters;\n _s.transformTag.call(this, tagItem);\n tagItem.prefix = tagItem.prefix || this.state.tag ? this.state.tag.prefix : (_s.pattern.source || _s.pattern)[0];\n\n // TODO: should check if the tag is valid\n tagElm = this.createTagElem(tagItem);\n\n // tries to replace a taged textNode with a tagElm, and if not able,\n // insert the new tag to the END if \"addTags\" was called from outside\n if (!this.replaceTextWithNode(tagElm)) {\n this.DOM.input.appendChild(tagElm);\n }\n setTimeout(function () {\n return tagElm.classList.add(_this24.settings.classNames.tagNoAnimation);\n }, 300);\n this.value.push(tagItem);\n this.update();\n if (!createdFromDelimiters) {\n var elm = this.insertAfterTag(tagElm) || tagElm;\n // a timeout is needed when selecting a tag from the suggestions via mouse.\n // Without it, it seems the caret is placed right after the tag and not after the\n // node which was inserted after the tag (whitespace by default)\n setTimeout(this.placeCaretAfterNode, 0, elm);\n }\n this.state.tag = null;\n this.trigger('add', extend({}, {\n tag: tagElm\n }, {\n data: tagItem\n }));\n return tagElm;\n },\n /**\r\n * appened (validated) tag to the component's DOM scope\r\n */\n appendTag: function appendTag(tagElm) {\n var DOM = this.DOM,\n insertBeforeNode = DOM.input;\n\n //if( insertBeforeNode === DOM.input )\n DOM.scope.insertBefore(tagElm, insertBeforeNode);\n //else\n // DOM.scope.appendChild(tagElm)\n },\n /**\r\n * creates a DOM tag element and injects it into the component (this.DOM.scope)\r\n * @param {Object} tagData [text value & properties for the created tag]\r\n * @param {Object} extraData [properties which are for the HTML template only]\r\n * @return {Object} [DOM element]\r\n */\n createTagElem: function createTagElem(tagData, extraData) {\n tagData.__tagId = getUID();\n var tagElm,\n templateData = extend({}, tagData, _objectSpread2({\n value: escapeHTML(tagData.value + \"\")\n }, extraData));\n\n // if( this.settings.readonly )\n // tagData.readonly = true\n\n tagElm = this.parseTemplate('tag', [templateData, this]);\n\n // crucial for proper caret placement when deleting content. if textNodes are allowed as children of a tag element,\n // a browser bug casues the caret to be misplaced inside the tag element (especially affects \"readonly\" tags)\n removeTextChildNodes(tagElm);\n // while( tagElm.lastChild.nodeType == 3 )\n // tagElm.lastChild.parentNode.removeChild(tagElm.lastChild)\n\n getSetTagData(tagElm, tagData);\n return tagElm;\n },\n /**\r\n * re-check all invalid tags.\r\n * called after a tag was edited or removed\r\n */\n reCheckInvalidTags: function reCheckInvalidTags() {\n var _this25 = this;\n var _s = this.settings;\n this.getTagElms(_s.classNames.tagNotAllowed).forEach(function (tagElm, i) {\n var tagData = getSetTagData(tagElm),\n hasMaxTags = _this25.hasMaxTags(),\n tagValidation = _this25.validateTag(tagData),\n isValid = tagValidation === true && !hasMaxTags;\n if (_s.mode == 'select') _this25.toggleScopeValidation(tagValidation);\n\n // if the tag has become valid\n if (isValid) {\n tagData = tagData.__preInvalidData ? tagData.__preInvalidData : {\n value: tagData.value\n };\n return _this25.replaceTag(tagElm, tagData);\n }\n\n // if the tag is still invaild, set its title as such (reson of invalid might have changed)\n tagElm.title = hasMaxTags || tagValidation;\n });\n },\n /**\r\n * Removes a tag\r\n * @param {Array|Node|String} tagElms [DOM element(s) or a String value. if undefined or null, remove last added tag]\r\n * @param {Boolean} silent [A flag, which when turned on, does not remove any value and does not update the original input value but simply removes the tag from tagify]\r\n * @param {Number} tranDuration [Transition duration in MS]\r\n * TODO: Allow multiple tags to be removed at-once\r\n */\n removeTags: function removeTags(tagElms, silent, tranDuration) {\n var _this26 = this;\n var tagsToRemove,\n _s = this.settings;\n tagElms = tagElms && tagElms instanceof HTMLElement ? [tagElms] : tagElms instanceof Array ? tagElms : tagElms ? [tagElms] : [this.getLastTag()];\n\n // normalize tagElms array values:\n // 1. removing invalid items\n // 2, if an item is String try to get the matching Tag HTML node\n // 3. get the tag data\n // 4. return a collection of Objects\n tagsToRemove = tagElms.reduce(function (elms, tagElm) {\n if (tagElm && typeof tagElm == 'string') tagElm = _this26.getTagElmByValue(tagElm);\n var tagData = getSetTagData(tagElm);\n if (tagElm && tagData && !tagData.readonly)\n // make sure it's a tag and not some other node\n // because the DOM node might be removed by async animation, the state will be updated while\n // the node might still be in the DOM, so the \"update\" method should know which nodes to ignore\n elms.push({\n node: tagElm,\n idx: _this26.getTagIdx(tagData),\n // this.getNodeIndex(tagElm); // this.getTagIndexByValue(tagElm.textContent)\n data: getSetTagData(tagElm, {\n '__removed': true\n })\n });\n return elms;\n }, []);\n tranDuration = typeof tranDuration == \"number\" ? tranDuration : this.CSSVars.tagHideTransition;\n if (_s.mode == 'select') {\n tranDuration = 0;\n this.input.set.call(this);\n }\n\n // if only a single tag is to be removed.\n // skip \"select\" mode because invalid tags are actually set to `this.value`\n if (tagsToRemove.length == 1 && _s.mode != 'select') {\n if (tagsToRemove[0].node.classList.contains(_s.classNames.tagNotAllowed)) silent = true;\n }\n if (!tagsToRemove.length) return;\n return _s.hooks.beforeRemoveTag(tagsToRemove, {\n tagify: this\n }).then(function () {\n function removeNode(tag) {\n if (!tag.node.parentNode) return;\n tag.node.parentNode.removeChild(tag.node);\n if (!silent) {\n // this.removeValueById(tagData.__uid)\n this.trigger('remove', {\n tag: tag.node,\n index: tag.idx,\n data: tag.data\n });\n this.dropdown.refilter();\n this.dropdown.position();\n this.DOM.input.normalize(); // best-practice when in mix-mode (safe to do always anyways)\n\n // check if any of the current tags which might have been marked as \"duplicate\" should be un-marked\n if (_s.keepInvalidTags) this.reCheckInvalidTags();\n\n // below code is unfinished. it should iterate all currently invalid edited tags, which their edits have not\n // changed the value yet, and should re-trigger the check, but since nothing has changed, it does not work...\n // this.getTagElms(_s.classNames.tagEditing).forEach( this.events.callbacks.onEditTagBlur.bind )\n } else if (_s.keepInvalidTags) this.trigger('remove', {\n tag: tag.node,\n index: tag.idx\n });\n }\n function animation(tag) {\n tag.node.style.width = parseFloat(window.getComputedStyle(tag.node).width) + 'px';\n document.body.clientTop; // force repaint for the width to take affect before the \"hide\" class below\n tag.node.classList.add(_s.classNames.tagHide);\n\n // manual timeout (hack, since transitionend cannot be used because of hover)\n setTimeout(removeNode.bind(this), tranDuration, tag);\n }\n if (tranDuration && tranDuration > 10 && tagsToRemove.length == 1) animation.call(_this26, tagsToRemove[0]);else tagsToRemove.forEach(removeNode.bind(_this26));\n\n // update state regardless of animation\n if (!silent) {\n _this26.removeTagsFromValue(tagsToRemove.map(function (tag) {\n return tag.node;\n }));\n _this26.update(); // update the original input with the current value\n\n if (_s.mode == 'select') _this26.setContentEditable(true);\n }\n }).catch(function (reason) {});\n },\n removeTagsFromDOM: function removeTagsFromDOM() {\n [].slice.call(this.getTagElms()).forEach(function (elm) {\n return elm.parentNode.removeChild(elm);\n });\n },\n /**\r\n * @param {Array/Node} tags to be removed from the this.value array\r\n */\n removeTagsFromValue: function removeTagsFromValue(tags) {\n var _this27 = this;\n tags = Array.isArray(tags) ? tags : [tags];\n tags.forEach(function (tag) {\n var tagData = getSetTagData(tag),\n tagIdx = _this27.getTagIdx(tagData);\n\n // delete tagData.__removed\n\n if (tagIdx > -1) _this27.value.splice(tagIdx, 1);\n });\n },\n removeAllTags: function removeAllTags(opts) {\n var _this28 = this;\n opts = opts || {};\n this.value = [];\n if (this.settings.mode == 'mix') this.DOM.input.innerHTML = '';else this.removeTagsFromDOM();\n this.dropdown.refilter();\n this.dropdown.position();\n if (this.state.dropdown.visible) setTimeout(function () {\n _this28.DOM.input.focus();\n });\n if (this.settings.mode == 'select') {\n this.input.set.call(this);\n this.setContentEditable(true);\n }\n\n // technically for now only \"withoutChangeEvent\" exists in the opts.\n // if more properties will be added later, only pass what's needed to \"update\"\n this.update(opts);\n },\n postUpdate: function postUpdate() {\n this.state.blockChangeEvent = false;\n var _s = this.settings,\n classNames = _s.classNames,\n hasValue = _s.mode == 'mix' ? _s.mixMode.integrated ? this.DOM.input.textContent : this.DOM.originalInput.value.trim() : this.value.length + this.input.raw.call(this).length;\n this.toggleClass(classNames.hasMaxTags, this.value.length >= _s.maxTags);\n this.toggleClass(classNames.hasNoTags, !this.value.length);\n this.toggleClass(classNames.empty, !hasValue);\n\n // specifically the \"select mode\" might have the \"invalid\" classname set when the field is changed, so it must be toggled on add/remove/edit\n if (_s.mode == 'select') {\n var _this$value2;\n this.toggleScopeValidation((_this$value2 = this.value) === null || _this$value2 === void 0 || (_this$value2 = _this$value2[0]) === null || _this$value2 === void 0 ? void 0 : _this$value2.__isValid);\n }\n },\n setOriginalInputValue: function setOriginalInputValue(v) {\n var inputElm = this.DOM.originalInput;\n if (!this.settings.mixMode.integrated) {\n inputElm.value = v;\n inputElm.tagifyValue = inputElm.value; // must set to \"inputElm.value\" and not again to \"inputValue\" because for some reason the browser changes the string afterwards a bit.\n this.setPersistedData(v, 'value');\n }\n },\n /**\r\n * update the origianl (hidden) input field's value\r\n * see - https://stackoverflow.com/q/50957841/104380\r\n */\n update: function update(args) {\n var UPDATE_DELAY = 100;\n clearTimeout(this.debouncedUpdateTimeout);\n this.debouncedUpdateTimeout = setTimeout(reallyUpdate.bind(this), UPDATE_DELAY);\n function reallyUpdate() {\n var inputValue = this.getInputValue();\n this.setOriginalInputValue(inputValue);\n if ((!this.settings.onChangeAfterBlur || !(args || {}).withoutChangeEvent) && !this.state.blockChangeEvent) this.triggerChangeEvent();\n this.postUpdate();\n }\n },\n getInputValue: function getInputValue() {\n var value = this.getCleanValue();\n return this.settings.mode == 'mix' ? this.getMixedTagsAsString(value) : value.length ? this.settings.originalInputValueFormat ? this.settings.originalInputValueFormat(value) : JSON.stringify(value) : \"\";\n },\n /**\r\n * removes properties from `this.value` which are only used internally\r\n */\n getCleanValue: function getCleanValue(v) {\n return removeCollectionProp(v || this.value, this.dataProps);\n },\n getMixedTagsAsString: function getMixedTagsAsString() {\n var result = \"\",\n that = this,\n _s = this.settings,\n originalInputValueFormat = _s.originalInputValueFormat || JSON.stringify,\n _interpolator = _s.mixTagsInterpolator;\n function iterateChildren(rootNode) {\n rootNode.childNodes.forEach(function (node) {\n if (node.nodeType == 1) {\n var tagData = getSetTagData(node);\n if (node.tagName == 'BR') {\n result += \"\\r\\n\";\n }\n if (tagData && isNodeTag.call(that, node)) {\n if (tagData.__removed) return;else result += _interpolator[0] + originalInputValueFormat(omit(tagData, that.dataProps)) + _interpolator[1];\n } else if (node.getAttribute('style') || ['B', 'I', 'U'].includes(node.tagName)) result += node.textContent;else if (node.tagName == 'DIV' || node.tagName == 'P') {\n result += \"\\r\\n\";\n // if( !node.children.length && node.textContent )\n // result += node.textContent;\n iterateChildren(node);\n }\n } else result += node.textContent;\n });\n }\n iterateChildren(this.DOM.input);\n return result;\n }\n};\n\n// legacy support for changed methods names\nTagify.prototype.removeTag = Tagify.prototype.removeTags;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,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LE1BQU0sSUFBSTl5QixJQUFJLENBQUM4VSxZQUFZLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDN1IsUUFBUSxDQUFDakQsSUFBSSxDQUFDMHBCLE9BQU8sQ0FBQyxFQUFFcEYsTUFBTSxJQUFJdGtCLElBQUksQ0FBQ2UsV0FBVyxDQUFDLEtBQUssSUFBSWYsSUFBSSxDQUFDMHBCLE9BQU8sSUFBSSxLQUFLLElBQUkxcEIsSUFBSSxDQUFDMHBCLE9BQU8sSUFBSSxHQUFHLEVBQUU7WUFDaktwRixNQUFNLElBQUksTUFBTTtZQUNoQjtZQUNBO1lBQ0F5TyxlQUFlLENBQUMveUIsSUFBSSxDQUFDO1VBQ3ZCO1FBQ0YsQ0FBQyxNQUFNc2tCLE1BQU0sSUFBSXRrQixJQUFJLENBQUNlLFdBQVc7TUFDbkMsQ0FBQyxDQUFDO0lBQ0o7SUFDQWd5QixlQUFlLENBQUMsSUFBSSxDQUFDam5CLEdBQUcsQ0FBQ3pPLEtBQUssQ0FBQztJQUMvQixPQUFPaW5CLE1BQU07RUFDZjtBQUNGLENBQUM7O0FBRUQ7QUFDQXNDLE1BQU0sQ0FBQ3BsQixTQUFTLENBQUMweEIsU0FBUyxHQUFHdE0sTUFBTSxDQUFDcGxCLFNBQVMsQ0FBQzRTLFVBQVUiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9ldW5vcy1ibGFkZXMvLi9saWIvdGFnaWZ5L3RhZ2lmeS5lc20uanM/NjBmNiJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFRhZ2lmeSAodiA0LjE3LjgpIC0gdGFncyBpbnB1dCBjb21wb25lbnRcbiAqIEJ5IHVuZGVmaW5lZFxuICogaHR0cHM6Ly9naXRodWIuY29tL3lhaXJFTy90YWdpZnlcbiAqIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhIGNvcHlcclxuICogb2YgdGhpcyBzb2Z0d2FyZSBhbmQgYXNzb2NpYXRlZCBkb2N1bWVudGF0aW9uIGZpbGVzICh0aGUgXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbFxyXG4gKiBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzXHJcbiAqIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCwgZGlzdHJpYnV0ZSwgc3VibGljZW5zZSwgYW5kL29yIHNlbGxcclxuICogY29waWVzIG9mIHRoZSBTb2Z0d2FyZSwgYW5kIHRvIHBlcm1pdCBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzXHJcbiAqIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnM6XHJcbiAqIFxyXG4gKiBUaGUgYWJvdmUgY29weXJpZ2h0IG5vdGljZSBhbmQgdGhpcyBwZXJtaXNzaW9uIG5vdGljZSBzaGFsbCBiZSBpbmNsdWRlZCBpblxyXG4gKiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cclxuICogXHJcbiAqIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1MgT1JcclxuICogSU1QTElFRCwgSU5DTFVESU5HIEJVVCBOT1QgTElNSVRFRCBUTyBUSEUgV0FSUkFOVElFUyBPRiBNRVJDSEFOVEFCSUxJVFksXHJcbiAqIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOIE5PIEVWRU5UIFNIQUxMIFRIRVxyXG4gKiBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLCBEQU1BR0VTIE9SIE9USEVSXHJcbiAqIExJQUJJTElUWSwgV0hFVEhFUiBJTiBBTiBBQ1RJT04gT0YgQ09OVFJBQ1QsIFRPUlQgT1IgT1RIRVJXSVNFLCBBUklTSU5HIEZST00sXHJcbiAqIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRSBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU5cclxuICogVEhFIFNPRlRXQVJFLlxyXG4gKiBcclxuICogVEhFIFNPRlRXQVJFIElTIE5PVCBQRVJNSVNTSUJMRSBUTyBCRSBTT0xELlxuICovXG5cbmZ1bmN0aW9uIG93bktleXMob2JqZWN0LCBlbnVtZXJhYmxlT25seSkge1xuICB2YXIga2V5cyA9IE9iamVjdC5rZXlzKG9iamVjdCk7XG4gIGlmIChPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKSB7XG4gICAgdmFyIHN5bWJvbHMgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlTeW1ib2xzKG9iamVjdCk7XG4gICAgZW51bWVyYWJsZU9ubHkgJiYgKHN5bWJvbHMgPSBzeW1ib2xzLmZpbHRlcihmdW5jdGlvbiAoc3ltKSB7XG4gICAgICByZXR1cm4gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihvYmplY3QsIHN5bSkuZW51bWVyYWJsZTtcbiAgICB9KSksIGtleXMucHVzaC5hcHBseShrZXlzLCBzeW1ib2xzKTtcbiAgfVxuICByZXR1cm4ga2V5cztcbn1cbmZ1bmN0aW9uIF9vYmplY3RTcHJlYWQyKHRhcmdldCkge1xuICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgIHZhciBzb3VyY2UgPSBudWxsICE9IGFyZ3VtZW50c1tpXSA/IGFyZ3VtZW50c1tpXSA6IHt9O1xuICAgIGkgJSAyID8gb3duS2V5cyhPYmplY3Qoc291cmNlKSwgITApLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICAgICAgX2RlZmluZVByb3BlcnR5KHRhcmdldCwga2V5LCBzb3VyY2Vba2V5XSk7XG4gICAgfSkgOiBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9ycyA/IE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKHRhcmdldCwgT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcnMoc291cmNlKSkgOiBvd25LZXlzKE9iamVjdChzb3VyY2UpKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSh0YXJnZXQsIGtleSwgT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihzb3VyY2UsIGtleSkpO1xuICAgIH0pO1xuICB9XG4gIHJldHVybiB0YXJnZXQ7XG59XG5mdW5jdGlvbiBfZGVmaW5lUHJvcGVydHkob2JqLCBrZXksIHZhbHVlKSB7XG4gIGtleSA9IF90b1Byb3BlcnR5S2V5KGtleSk7XG4gIGlmIChrZXkgaW4gb2JqKSB7XG4gICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iaiwga2V5LCB7XG4gICAgICB2YWx1ZTogdmFsdWUsXG4gICAgICBlbnVtZXJhYmxlOiB0cnVlLFxuICAgICAgY29uZmlndXJhYmxlOiB0cnVlLFxuICAgICAgd3JpdGFibGU6IHRydWVcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICBvYmpba2V5XSA9IHZhbHVlO1xuICB9XG4gIHJldHVybiBvYmo7XG59XG5mdW5jdGlvbiBfdG9QcmltaXRpdmUoaW5wdXQsIGhpbnQpIHtcbiAgaWYgKHR5cGVvZiBpbnB1dCAhPT0gXCJvYmplY3RcIiB8fCBpbnB1dCA9PT0gbnVsbCkgcmV0dXJuIGlucHV0O1xuICB2YXIgcHJpbSA9IGlucHV0W1N5bWJvbC50b1ByaW1pdGl2ZV07XG4gIGlmIChwcmltICE9PSB1bmRlZmluZWQpIHtcbiAgICB2YXIgcmVzID0gcHJpbS5jYWxsKGlucHV0LCBoaW50IHx8IFwiZGVmYXVsdFwiKTtcbiAgICBpZiAodHlwZW9mIHJlcyAhPT0gXCJvYmplY3RcIikgcmV0dXJuIHJlcztcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiQEB0b1ByaW1pdGl2ZSBtdXN0IHJldHVybiBhIHByaW1pdGl2ZSB2YWx1ZS5cIik7XG4gIH1cbiAgcmV0dXJuIChoaW50ID09PSBcInN0cmluZ1wiID8gU3RyaW5nIDogTnVtYmVyKShpbnB1dCk7XG59XG5mdW5jdGlvbiBfdG9Qcm9wZXJ0eUtleShhcmcpIHtcbiAgdmFyIGtleSA9IF90b1ByaW1pdGl2ZShhcmcsIFwic3RyaW5nXCIpO1xuICByZXR1cm4gdHlwZW9mIGtleSA9PT0gXCJzeW1ib2xcIiA/IGtleSA6IFN0cmluZyhrZXkpO1xufVxuXG4vLyBjb25zb2xlLmpzb24gPSBjb25zb2xlLmpzb24gfHwgZnVuY3Rpb24oYXJndW1lbnQpe1xuLy8gICAgIGZvcih2YXIgYXJnPTA7IGFyZyA8IGFyZ3VtZW50cy5sZW5ndGg7ICsrYXJnKVxuLy8gICAgICAgICBjb25zb2xlLmxvZyggIEpTT04uc3RyaW5naWZ5KGFyZ3VtZW50c1thcmddLCBudWxsLCA0KSAgKVxuLy8gfVxuXG4vLyBjb25zdCBpc0VkZ2UgPSAvRWRnZS8udGVzdChuYXZpZ2F0b3IudXNlckFnZW50KVxuY29uc3Qgc2FtZVN0ciA9IChzMSwgczIsIGNhc2VTZW5zaXRpdmUsIHRyaW0pID0+IHtcbiAgLy8gY2FzdCB0byBTdHJpbmdcbiAgczEgPSBcIlwiICsgczE7XG4gIHMyID0gXCJcIiArIHMyO1xuICBpZiAodHJpbSkge1xuICAgIHMxID0gczEudHJpbSgpO1xuICAgIHMyID0gczIudHJpbSgpO1xuICB9XG4gIHJldHVybiBjYXNlU2Vuc2l0aXZlID8gczEgPT0gczIgOiBzMS50b0xvd2VyQ2FzZSgpID09IHMyLnRvTG93ZXJDYXNlKCk7XG59O1xuXG4vLyBjb25zdCBnZXRVSUQgPSAoKSA9PiAobmV3IERhdGUoKS5nZXRUaW1lKCkgKyBNYXRoLmZsb29yKChNYXRoLnJhbmRvbSgpKjEwMDAwKSsxKSkudG9TdHJpbmcoMTYpXG5jb25zdCByZW1vdmVDb2xsZWN0aW9uUHJvcCA9IChjb2xsZWN0aW9uLCB1bndhbnRlZFByb3BzKSA9PiBjb2xsZWN0aW9uICYmIEFycmF5LmlzQXJyYXkoY29sbGVjdGlvbikgJiYgY29sbGVjdGlvbi5tYXAodiA9PiBvbWl0KHYsIHVud2FudGVkUHJvcHMpKTtcbmZ1bmN0aW9uIG9taXQob2JqLCBwcm9wcykge1xuICB2YXIgbmV3T2JqID0ge30sXG4gICAgcDtcbiAgZm9yIChwIGluIG9iaikgaWYgKHByb3BzLmluZGV4T2YocCkgPCAwKSBuZXdPYmpbcF0gPSBvYmpbcF07XG4gIHJldHVybiBuZXdPYmo7XG59XG5mdW5jdGlvbiBkZWNvZGUocykge1xuICB2YXIgZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgcmV0dXJuIHMucmVwbGFjZSgvXFwmIz9bMC05YS16XSs7L2dpLCBmdW5jdGlvbiAoZW5jKSB7XG4gICAgZWwuaW5uZXJIVE1MID0gZW5jO1xuICAgIHJldHVybiBlbC5pbm5lclRleHQ7XG4gIH0pO1xufVxuXG4vKipcclxuICogdXRpbGl0eSBtZXRob2RcclxuICogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzM1Mzg1NTE4LzEwNDM4MFxyXG4gKiBAcGFyYW0gIHtTdHJpbmd9IHMgW0hUTUwgc3RyaW5nXVxyXG4gKiBAcmV0dXJuIHtPYmplY3R9ICAgW0RPTSBub2RlXVxyXG4gKi9cbmZ1bmN0aW9uIHBhcnNlSFRNTChzKSB7XG4gIHZhciBwYXJzZXIgPSBuZXcgRE9NUGFyc2VyKCksXG4gICAgbm9kZSA9IHBhcnNlci5wYXJzZUZyb21TdHJpbmcocy50cmltKCksIFwidGV4dC9odG1sXCIpO1xuICByZXR1cm4gbm9kZS5ib2R5LmZpcnN0RWxlbWVudENoaWxkO1xufVxuXG4vKipcclxuICogUmVtb3ZlZCBuZXcgbGluZXMgYW5kIGlycmVsZXZhbnQgc3BhY2VzIHdoaWNoIG1pZ2h0IGFmZmVjdCBsYXlvdXQsIGFuZCBhcmUgYmV0dGVyIGdvbmVcclxuICogQHBhcmFtIHtzdHJpbmd9IHMgW0hUTUwgc3RyaW5nXVxyXG4gKi9cbmZ1bmN0aW9uIG1pbmlmeShzKSB7XG4gIHJldHVybiBzID8gcy5yZXBsYWNlKC9cXD5bXFxyXFxuIF0rXFw8L2csIFwiPjxcIikucmVwbGFjZSgvKDwuKj8+KXxcXHMrL2csIChtLCAkMSkgPT4gJDEgPyAkMSA6ICcgJykgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzQ0ODQxNDg0LzEwNDM4MFxuICA6IFwiXCI7XG59XG5mdW5jdGlvbiByZW1vdmVUZXh0Q2hpbGROb2RlcyhlbG0pIHtcbiAgdmFyIGl0ZXIgPSBkb2N1bWVudC5jcmVhdGVOb2RlSXRlcmF0b3IoZWxtLCBOb2RlRmlsdGVyLlNIT1dfVEVYVCwgbnVsbCwgZmFsc2UpLFxuICAgIHRleHRub2RlO1xuXG4gIC8vIHByaW50IGFsbCB0ZXh0IG5vZGVzXG4gIHdoaWxlICh0ZXh0bm9kZSA9IGl0ZXIubmV4dE5vZGUoKSkge1xuICAgIGlmICghdGV4dG5vZGUudGV4dENvbnRlbnQudHJpbSgpKSB0ZXh0bm9kZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRleHRub2RlKTtcbiAgfVxufVxuZnVuY3Rpb24gZ2V0Zmlyc3RUZXh0Tm9kZShlbG0sIGFjdGlvbikge1xuICBhY3Rpb24gPSBhY3Rpb24gfHwgJ3ByZXZpb3VzJztcbiAgd2hpbGUgKGVsbSA9IGVsbVthY3Rpb24gKyAnU2libGluZyddKSBpZiAoZWxtLm5vZGVUeXBlID09IDMpIHJldHVybiBlbG07XG59XG5cbi8qKlxyXG4gKiB1dGlsaXR5IG1ldGhvZFxyXG4gKiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvNjIzNDgwNC8xMDQzODBcclxuICovXG5mdW5jdGlvbiBlc2NhcGVIVE1MKHMpIHtcbiAgcmV0dXJuIHR5cGVvZiBzID09ICdzdHJpbmcnID8gcy5yZXBsYWNlKC8mL2csIFwiJmFtcDtcIikucmVwbGFjZSgvPC9nLCBcIiZsdDtcIikucmVwbGFjZSgvPi9nLCBcIiZndDtcIikucmVwbGFjZSgvXCIvZywgXCImcXVvdDtcIikucmVwbGFjZSgvYHwnL2csIFwiJiMwMzk7XCIpIDogcztcbn1cblxuLyoqXHJcbiAqIENoZWNrcyBpZiBhbiBhcmd1bWVudCBpcyBhIGphdmFzY3JpcHQgT2JqZWN0XHJcbiAqL1xuZnVuY3Rpb24gaXNPYmplY3Qob2JqKSB7XG4gIHZhciB0eXBlID0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikuc3BsaXQoJyAnKVsxXS5zbGljZSgwLCAtMSk7XG4gIHJldHVybiBvYmogPT09IE9iamVjdChvYmopICYmIHR5cGUgIT0gJ0FycmF5JyAmJiB0eXBlICE9ICdGdW5jdGlvbicgJiYgdHlwZSAhPSAnUmVnRXhwJyAmJiB0eXBlICE9ICdIVE1MVW5rbm93bkVsZW1lbnQnO1xufVxuXG4vKipcclxuICogbWVyZ2Ugb2JqZWN0cyBpbnRvIGEgc2luZ2xlIG5ldyBvbmVcclxuICogVEVTVDogZXh0ZW5kKHt9LCB7YTp7Zm9vOjF9LCBiOltdfSwge2E6e2JhcjoyfSwgYjpbMV0sIGM6KCk9Pnt9fSlcclxuICovXG5mdW5jdGlvbiBleHRlbmQobywgbzEsIG8yKSB7XG4gIGlmICghKG8gaW5zdGFuY2VvZiBPYmplY3QpKSBvID0ge307XG4gIGNvcHkobywgbzEpO1xuICBpZiAobzIpIGNvcHkobywgbzIpO1xuICBmdW5jdGlvbiBjb3B5KGEsIGIpIHtcbiAgICAvLyBjb3B5IG8yIHRvIG9cbiAgICBmb3IgKHZhciBrZXkgaW4gYikgaWYgKGIuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgaWYgKGlzT2JqZWN0KGJba2V5XSkpIHtcbiAgICAgICAgaWYgKCFpc09iamVjdChhW2tleV0pKSBhW2tleV0gPSBPYmplY3QuYXNzaWduKHt9LCBiW2tleV0pO2Vsc2UgY29weShhW2tleV0sIGJba2V5XSk7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgaWYgKEFycmF5LmlzQXJyYXkoYltrZXldKSkge1xuICAgICAgICBhW2tleV0gPSBPYmplY3QuYXNzaWduKFtdLCBiW2tleV0pO1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGFba2V5XSA9IGJba2V5XTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG87XG59XG5cbi8qKlxyXG4gKiBjb25jYXRlbmF0ZXMgTiBhcnJheXMgd2l0aG91dCBkdXBzLlxyXG4gKiBJZiBhbiBhcnJheSdzIGl0ZW0gaXMgYW4gT2JqZWN0LCBjb21wYXJlIGJ5IGB2YWx1ZWBcclxuICovXG5mdW5jdGlvbiBjb25jYXRXaXRob3V0RHVwcygpIHtcbiAgY29uc3QgbmV3QXJyID0gW10sXG4gICAgZXhpc3RpbmdPYmogPSB7fTtcbiAgZm9yIChsZXQgYXJyIG9mIGFyZ3VtZW50cykge1xuICAgIGZvciAobGV0IGl0ZW0gb2YgYXJyKSB7XG4gICAgICAvLyBpZiBjdXJyZW50IGl0ZW0gaXMgYW4gb2JqZWN0IHdoaWNoIGhhcyB5ZXQgdG8gYmUgYWRkZWQgdG8gdGhlIG5ldyBhcnJheVxuICAgICAgaWYgKGlzT2JqZWN0KGl0ZW0pKSB7XG4gICAgICAgIGlmICghZXhpc3RpbmdPYmpbaXRlbS52YWx1ZV0pIHtcbiAgICAgICAgICBuZXdBcnIucHVzaChpdGVtKTtcbiAgICAgICAgICBleGlzdGluZ09ialtpdGVtLnZhbHVlXSA9IDE7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gaWYgY3VycmVudCBpdGVtIGlzIG5vdCBhbiBvYmplY3QgYW5kIGlzIG5vdCBpbiB0aGUgbmV3IGFycmF5XG4gICAgICBlbHNlIGlmICghbmV3QXJyLmluY2x1ZGVzKGl0ZW0pKSBuZXdBcnIucHVzaChpdGVtKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG5ld0Fycjtcbn1cblxuLyoqXHJcbiAqICBFeHRyYWN0ZWQgZnJvbTogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzM3NTExNDYzLzEwNDM4MFxyXG4gKiBAcGFyYW0ge1N0cmluZ30gc1xyXG4gKi9cbmZ1bmN0aW9uIHVuYWNjZW50KHMpIHtcbiAgLy8gaWYgbm90IHN1cHBvcnRlZCwgZG8gbm90IGNvbnRpbnVlLlxuICAvLyBkZXZlbG9wZXJzIHNob3VsZCB1c2UgYSBwb2x5ZmlsbDpcbiAgLy8gaHR0cHM6Ly9naXRodWIuY29tL3dhbGxpbmcvdW5vcm1cbiAgaWYgKCFTdHJpbmcucHJvdG90eXBlLm5vcm1hbGl6ZSkgcmV0dXJuIHM7XG4gIGlmICh0eXBlb2YgcyA9PT0gJ3N0cmluZycpIHJldHVybiBzLm5vcm1hbGl6ZShcIk5GRFwiKS5yZXBsYWNlKC9bXFx1MDMwMC1cXHUwMzZmXS9nLCBcIlwiKTtcbn1cblxuLyoqXHJcbiAqIE1lYXNzdXJlcyBhbiBlbGVtZW50J3MgaGVpZ2h0LCB3aGljaCBtaWdodCB5ZXQgaGF2ZSBiZWVuIGFkZGVkIERPTVxyXG4gKiBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL3EvNTk0NDAzOC8xMDQzODBcclxuICogQHBhcmFtIHtET019IG5vZGVcclxuICovXG5mdW5jdGlvbiBnZXROb2RlSGVpZ2h0KG5vZGUpIHtcbiAgdmFyIGhlaWdodCxcbiAgICBjbG9uZSA9IG5vZGUuY2xvbmVOb2RlKHRydWUpO1xuICBjbG9uZS5zdHlsZS5jc3NUZXh0ID0gXCJwb3NpdGlvbjpmaXhlZDsgdG9wOi05OTk5cHg7IG9wYWNpdHk6MFwiO1xuICBkb2N1bWVudC5ib2R5LmFwcGVuZENoaWxkKGNsb25lKTtcbiAgaGVpZ2h0ID0gY2xvbmUuY2xpZW50SGVpZ2h0O1xuICBjbG9uZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGNsb25lKTtcbiAgcmV0dXJuIGhlaWdodDtcbn1cbnZhciBpc0Nocm9tZUFuZHJvaWRCcm93c2VyID0gKCkgPT4gLyg/PS4qY2hyb21lKSg/PS4qYW5kcm9pZCkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuZnVuY3Rpb24gZ2V0VUlEKCkge1xuICByZXR1cm4gKFsxZTddICsgLTFlMyArIC00ZTMgKyAtOGUzICsgLTFlMTEpLnJlcGxhY2UoL1swMThdL2csIGMgPT4gKGMgXiBjcnlwdG8uZ2V0UmFuZG9tVmFsdWVzKG5ldyBVaW50OEFycmF5KDEpKVswXSAmIDE1ID4+IGMgLyA0KS50b1N0cmluZygxNikpO1xufVxuZnVuY3Rpb24gaXNOb2RlVGFnKG5vZGUpIHtcbiAgcmV0dXJuIG5vZGUgJiYgbm9kZS5jbGFzc0xpc3QgJiYgbm9kZS5jbGFzc0xpc3QuY29udGFpbnModGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZyk7XG59XG5cbi8qKlxyXG4qIEdldCB0aGUgY2FyZXQgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHZpZXdwb3J0XHJcbiogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xLzU4OTg1MDc2LzEwNDM4MFxyXG4qXHJcbiogQHJldHVybnMge29iamVjdH0gbGVmdCwgdG9wIGRpc3RhbmNlIGluIHBpeGVsc1xyXG4qL1xuZnVuY3Rpb24gZ2V0Q2FyZXRHbG9iYWxQb3NpdGlvbigpIHtcbiAgY29uc3Qgc2VsID0gZG9jdW1lbnQuZ2V0U2VsZWN0aW9uKCk7XG4gIGlmIChzZWwucmFuZ2VDb3VudCkge1xuICAgIGNvbnN0IHIgPSBzZWwuZ2V0UmFuZ2VBdCgwKTtcbiAgICBjb25zdCBub2RlID0gci5zdGFydENvbnRhaW5lcjtcbiAgICBjb25zdCBvZmZzZXQgPSByLnN0YXJ0T2Zmc2V0O1xuICAgIGxldCByZWN0LCByMjtcbiAgICBpZiAob2Zmc2V0ID4gMCkge1xuICAgICAgcjIgPSBkb2N1bWVudC5jcmVhdGVSYW5nZSgpO1xuICAgICAgcjIuc2V0U3RhcnQobm9kZSwgb2Zmc2V0IC0gMSk7XG4gICAgICByMi5zZXRFbmQobm9kZSwgb2Zmc2V0KTtcbiAgICAgIHJlY3QgPSByMi5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQ6IHJlY3QucmlnaHQsXG4gICAgICAgIHRvcDogcmVjdC50b3AsXG4gICAgICAgIGJvdHRvbTogcmVjdC5ib3R0b21cbiAgICAgIH07XG4gICAgfVxuICAgIGlmIChub2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCkgcmV0dXJuIG5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gIH1cbiAgcmV0dXJuIHtcbiAgICBsZWZ0OiAtOTk5OSxcbiAgICB0b3A6IC05OTk5XG4gIH07XG59XG5cbi8qKlxyXG4gKiBJbmplY3RzIGNvbnRlbnQgKGVpdGhlciBzdHJpbmcgb3Igbm9kZSkgYXQgdGhlIGN1cnJlbnQgdGhlIGN1cnJlbnQgKG9yIHNwZWNpZmljZWQpIGNhcmV0IHBvc2l0aW9uXHJcbiAqIEBwYXJhbSB7Y29udGVudH0gc3RyaW5nL25vZGVcclxuICogQHBhcmFtIHtyYW5nZX0gT2JqZWN0IChvcHRpb25hbCwgYSByYW5nZSBvdGhlciB0aGFuIHRoZSBjdXJyZW50IHdpbmRvdyBzZWxlY3Rpb24pXHJcbiAqL1xuZnVuY3Rpb24gaW5qZWN0QXRDYXJldChjb250ZW50LCByYW5nZSkge1xuICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuICByYW5nZSA9IHJhbmdlIHx8IHNlbGVjdGlvbi5nZXRSYW5nZUF0KDApO1xuICBpZiAodHlwZW9mIGNvbnRlbnQgPT0gJ3N0cmluZycpIGNvbnRlbnQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjb250ZW50KTtcbiAgaWYgKHJhbmdlKSB7XG4gICAgcmFuZ2UuZGVsZXRlQ29udGVudHMoKTtcbiAgICByYW5nZS5pbnNlcnROb2RlKGNvbnRlbnQpO1xuICB9XG4gIHJldHVybiBjb250ZW50O1xufVxuXG4vKiogU2V0dGVyL0dldHRlclxyXG4gKiBFYWNoIHRhZyBET00gbm9kZSBjb250YWlucyBhIGN1c3RvbSBwcm9wZXJ0eSBjYWxsZWQgXCJfX3RhZ2lmeVRhZ0RhdGFcIiB3aGljaCBob3N0cyBpdHMgZGF0YVxyXG4gKiBAcGFyYW0ge05vZGV9ICAgdGFnRWxtXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhXHJcbiAqL1xuZnVuY3Rpb24gZ2V0U2V0VGFnRGF0YSh0YWdFbG0sIGRhdGEsIG92ZXJyaWRlKSB7XG4gIGlmICghdGFnRWxtKSB7XG4gICAgY29uc29sZS53YXJuKFwidGFnIGVsZW1lbnQgZG9lc24ndCBleGlzdFwiLCB0YWdFbG0sIGRhdGEpO1xuICAgIHJldHVybiBkYXRhO1xuICB9XG4gIGlmIChkYXRhKSB0YWdFbG0uX190YWdpZnlUYWdEYXRhID0gb3ZlcnJpZGUgPyBkYXRhIDogZXh0ZW5kKHt9LCB0YWdFbG0uX190YWdpZnlUYWdEYXRhIHx8IHt9LCBkYXRhKTtcbiAgcmV0dXJuIHRhZ0VsbS5fX3RhZ2lmeVRhZ0RhdGE7XG59XG5cbnZhciBERUZBVUxUUyA9IHtcbiAgZGVsaW1pdGVyczogXCIsXCIsXG4gIC8vIFtSZWdFeF0gc3BsaXQgdGFncyBieSBhbnkgb2YgdGhlc2UgZGVsaW1pdGVycyAoXCJudWxsXCIgdG8gY2FuY2VsKSBFeGFtcGxlOiBcIix8IHwuXCJcbiAgcGF0dGVybjogbnVsbCxcbiAgLy8gUmVnRXggcGF0dGVybiB0byB2YWxpZGF0ZSBpbnB1dCBieS4gRXg6IC9bMS05XS9cbiAgdGFnVGV4dFByb3A6ICd2YWx1ZScsXG4gIC8vIHRhZyBkYXRhIE9iamVjdCBwcm9wZXJ0eSB3aGljaCB3aWxsIGJlIGRpc3BsYXllZCBhcyB0aGUgdGFnJ3MgdGV4dFxuICBtYXhUYWdzOiBJbmZpbml0eSxcbiAgLy8gTWF4aW11bSBudW1iZXIgb2YgdGFnc1xuICBjYWxsYmFja3M6IHt9LFxuICAvLyBFeHBvc2VkIGNhbGxiYWNrcyBvYmplY3QgdG8gYmUgdHJpZ2dlcmVkIG9uIGNlcnRhaW4gZXZlbnRzXG4gIGFkZFRhZ09uQmx1cjogdHJ1ZSxcbiAgLy8gYXV0b21hdGljYWxseSBhZGRzIHRoZSB0ZXh0IHdoaWNoIHdhcyBpbnB1dGVkIGFzIGEgdGFnIHdoZW4gYmx1ciBldmVudCBoYXBwZW5zXG4gIG9uQ2hhbmdlQWZ0ZXJCbHVyOiB0cnVlLFxuICAvLyBCeSBkZWZhdWx0LCB0aGUgbmF0aXZlIHdheSBvZiBpbnB1dHMnIG9uQ2hhbmdlIGV2ZW50cyBpcyBrZXB0LCBhbmQgaXQgb25seSBmaXJlcyB3aGVuIHRoZSBmaWVsZCBpcyBibHVyZWQuXG4gIGR1cGxpY2F0ZXM6IGZhbHNlLFxuICAvLyBcInRydWVcIiAtIGFsbG93IGR1cGxpY2F0ZSB0YWdzXG4gIHdoaXRlbGlzdDogW10sXG4gIC8vIEFycmF5IG9mIHRhZ3MgdG8gc3VnZ2VzdCBhcyB0aGUgdXNlciB0eXBlcyAoY2FuIGJlIHVzZWQgYWxvbmcgd2l0aCBcImVuZm9yY2VXaGl0ZWxpc3RcIiBzZXR0aW5nKVxuICBibGFja2xpc3Q6IFtdLFxuICAvLyBBIGxpc3Qgb2Ygbm9uLWFsbG93ZWQgdGFnc1xuICBlbmZvcmNlV2hpdGVsaXN0OiBmYWxzZSxcbiAgLy8gT25seSBhbGxvdyB0YWdzIGZyb20gdGhlIHdoaXRlbGlzdFxuICB1c2VySW5wdXQ6IHRydWUsXG4gIC8vIGRpc2FibGUgbWFudWFsbHkgdHlwaW5nL3Bhc3RpbmcvZWRpdGluZyB0YWdzICh0YWdzIG1heSBvbmx5IGJlIGFkZGVkIGZyb20gdGhlIHdoaXRlbGlzdClcbiAga2VlcEludmFsaWRUYWdzOiBmYWxzZSxcbiAgLy8gaWYgdHJ1ZSwgZG8gbm90IHJlbW92ZSB0YWdzIHdoaWNoIGRpZCBub3QgcGFzcyB2YWxpZGF0aW9uXG4gIGNyZWF0ZUludmFsaWRUYWdzOiB0cnVlLFxuICAvLyBpZiBmYWxzZSwgZG8gbm90IGNyZWF0ZSBpbnZhbGlkIHRhZ3MgZnJvbSBpbnZhbGlkIHVzZXIgaW5wdXRcbiAgbWl4VGFnc0FsbG93ZWRBZnRlcjogLyx8XFwufFxcOnxcXHMvLFxuICAvLyBSZWdFeCAtIERlZmluZSBjb25kaXRpb25zIGluIHdoaWNoIG1peC10YWdzIGNvbnRlbnQgYWxsb3dzIGEgdGFnIHRvIGJlIGFkZGVkIGFmdGVyXG4gIG1peFRhZ3NJbnRlcnBvbGF0b3I6IFsnW1snLCAnXV0nXSxcbiAgLy8gSW50ZXJwb2xhdGlvbiBmb3IgbWl4IG1vZGUuIEV2ZXJ5dGhpbmcgYmV0d2VlbiB0aGVzZSB3aWxsIGJlY29tZSBhIHRhZywgaWYgaXMgYSB2YWxpZCBPYmplY3RcbiAgYmFja3NwYWNlOiB0cnVlLFxuICAvLyBmYWxzZSAvIHRydWUgLyBcImVkaXRcIlxuICBza2lwSW52YWxpZDogZmFsc2UsXG4gIC8vIElmIGB0cnVlYCwgZG8gbm90IGFkZCBpbnZhbGlkLCB0ZW1wb3JhcnksIHRhZ3MgYmVmb3JlIGF1dG9tYXRpY2FsbHkgcmVtb3ZpbmcgdGhlbVxuICBwYXN0ZUFzVGFnczogdHJ1ZSxcbiAgLy8gYXV0b21hdGljYWxseSBjb252ZXJ0cyBwYXN0ZWQgdGV4dCBpbnRvIHRhZ3MuIGlmIFwiZmFsc2VcIiwgYWxsb3dzIGZvciBmdXJ0aGVyIHRleHQgZWRpdGluZ1xuXG4gIGVkaXRUYWdzOiB7XG4gICAgY2xpY2tzOiAyLFxuICAgIC8vIGNsaWNrcyB0byBlbnRlciBcImVkaXQtbW9kZVwiOiAxIGZvciBzaW5nbGUgY2xpY2suIGFueSBvdGhlciB2YWx1ZSBpcyBjb25zaWRlcmVkIGFzIGRvdWJsZS1jbGlja1xuICAgIGtlZXBJbnZhbGlkOiB0cnVlIC8vIGtlZXBzIGludmFsaWQgZWRpdHMgYXMtaXMgdW50aWwgYGVzY2AgaXMgcHJlc3NlZCB3aGlsZSBpbiBmb2N1c1xuICB9LFxuXG4gIC8vIDEgb3IgMiBjbGlja3MgdG8gZWRpdCBhIHRhZy4gZmFsc2UvbnVsbCBmb3Igbm90IGFsbG93aW5nIGVkaXRpbmdcbiAgdHJhbnNmb3JtVGFnOiAoKSA9PiB7fSxcbiAgLy8gVGFrZXMgYSB0YWcgaW5wdXQgc3RyaW5nIGFzIGFyZ3VtZW50IGFuZCByZXR1cm5zIGEgdHJhbnNmb3JtZWQgdmFsdWVcbiAgdHJpbTogdHJ1ZSxcbiAgLy8gd2hldGhlciBvciBub3QgdGhlIHZhbHVlIHByb3ZpZGVkIHNob3VsZCBiZSB0cmltbWVkLCBiZWZvcmUgYmVpbmcgYWRkZWQgYXMgYSB0YWdcbiAgYTExeToge1xuICAgIGZvY3VzYWJsZVRhZ3M6IGZhbHNlXG4gIH0sXG4gIG1peE1vZGU6IHtcbiAgICBpbnNlcnRBZnRlclRhZzogJ1xcdTAwQTAnIC8vIFN0cmluZy9Ob2RlIHRvIGluamVjdCBhZnRlciBhIHRhZyBoYXMgYmVlbiBhZGRlZCAoc2VlICM1ODgpXG4gIH0sXG5cbiAgYXV0b0NvbXBsZXRlOiB7XG4gICAgZW5hYmxlZDogdHJ1ZSxcbiAgICAvLyBUcmllcyB0byBzdWdnZXN0IHRoZSBpbnB1dCdzIHZhbHVlIHdoaWxlIHR5cGluZyAobWF0Y2ggZnJvbSB3aGl0ZWxpc3QpIGJ5IGFkZGluZyB0aGUgcmVzdCBvZiB0ZXJtIGFzIGdyYXllZC1vdXQgdGV4dFxuICAgIHJpZ2h0S2V5OiBmYWxzZSAvLyBJZiBgdHJ1ZWAsIHdoZW4gUmlnaHQga2V5IGlzIHByZXNzZWQsIHVzZSB0aGUgc3VnZ2VzdGVkIHZhbHVlIHRvIGNyZWF0ZSBhIHRhZywgZWxzZSBqdXN0IGF1dG8tY29tcGxldGVzIHRoZSBpbnB1dC4gaW4gbWl4ZWQtbW9kZSB0aGlzIGlzIHNldCB0byBcInRydWVcIlxuICB9LFxuXG4gIGNsYXNzTmFtZXM6IHtcbiAgICBuYW1lc3BhY2U6ICd0YWdpZnknLFxuICAgIG1peE1vZGU6ICd0YWdpZnktLW1peCcsXG4gICAgc2VsZWN0TW9kZTogJ3RhZ2lmeS0tc2VsZWN0JyxcbiAgICBpbnB1dDogJ3RhZ2lmeV9faW5wdXQnLFxuICAgIGZvY3VzOiAndGFnaWZ5LS1mb2N1cycsXG4gICAgdGFnTm9BbmltYXRpb246ICd0YWdpZnktLW5vQW5pbScsXG4gICAgdGFnSW52YWxpZDogJ3RhZ2lmeS0taW52YWxpZCcsXG4gICAgdGFnTm90QWxsb3dlZDogJ3RhZ2lmeS0tbm90QWxsb3dlZCcsXG4gICAgc2NvcGVMb2FkaW5nOiAndGFnaWZ5LS1sb2FkaW5nJyxcbiAgICBoYXNNYXhUYWdzOiAndGFnaWZ5LS1oYXNNYXhUYWdzJyxcbiAgICBoYXNOb1RhZ3M6ICd0YWdpZnktLW5vVGFncycsXG4gICAgZW1wdHk6ICd0YWdpZnktLWVtcHR5JyxcbiAgICBpbnB1dEludmFsaWQ6ICd0YWdpZnlfX2lucHV0LS1pbnZhbGlkJyxcbiAgICBkcm9wZG93bjogJ3RhZ2lmeV9fZHJvcGRvd24nLFxuICAgIGRyb3Bkb3duV3JhcHBlcjogJ3RhZ2lmeV9fZHJvcGRvd25fX3dyYXBwZXInLFxuICAgIGRyb3Bkb3duSGVhZGVyOiAndGFnaWZ5X19kcm9wZG93bl9faGVhZGVyJyxcbiAgICBkcm9wZG93bkZvb3RlcjogJ3RhZ2lmeV9fZHJvcGRvd25fX2Zvb3RlcicsXG4gICAgZHJvcGRvd25JdGVtOiAndGFnaWZ5X19kcm9wZG93bl9faXRlbScsXG4gICAgZHJvcGRvd25JdGVtQWN0aXZlOiAndGFnaWZ5X19kcm9wZG93bl9faXRlbS0tYWN0aXZlJyxcbiAgICBkcm9wZG93bkl0ZW1IaWRkZW46ICd0YWdpZnlfX2Ryb3Bkb3duX19pdGVtLS1oaWRkZW4nLFxuICAgIGRyb3Bkb3duSW5pdGFsOiAndGFnaWZ5X19kcm9wZG93bi0taW5pdGlhbCcsXG4gICAgdGFnOiAndGFnaWZ5X190YWcnLFxuICAgIHRhZ1RleHQ6ICd0YWdpZnlfX3RhZy10ZXh0JyxcbiAgICB0YWdYOiAndGFnaWZ5X190YWdfX3JlbW92ZUJ0bicsXG4gICAgdGFnTG9hZGluZzogJ3RhZ2lmeV9fdGFnLS1sb2FkaW5nJyxcbiAgICB0YWdFZGl0aW5nOiAndGFnaWZ5X190YWctLWVkaXRhYmxlJyxcbiAgICB0YWdGbGFzaDogJ3RhZ2lmeV9fdGFnLS1mbGFzaCcsXG4gICAgdGFnSGlkZTogJ3RhZ2lmeV9fdGFnLS1oaWRlJ1xuICB9LFxuICBkcm9wZG93bjoge1xuICAgIGNsYXNzbmFtZTogJycsXG4gICAgZW5hYmxlZDogMixcbiAgICAvLyBtaW5pbXVtIGlucHV0IGNoYXJhY3RlcnMgdG8gYmUgdHlwZWQgZm9yIHRoZSBzdWdnZXN0aW9ucyBkcm9wZG93biB0byBzaG93XG4gICAgbWF4SXRlbXM6IDEwLFxuICAgIHNlYXJjaEtleXM6IFtcInZhbHVlXCIsIFwic2VhcmNoQnlcIl0sXG4gICAgZnV6enlTZWFyY2g6IHRydWUsXG4gICAgY2FzZVNlbnNpdGl2ZTogZmFsc2UsXG4gICAgYWNjZW50ZWRTZWFyY2g6IHRydWUsXG4gICAgaW5jbHVkZVNlbGVjdGVkVGFnczogZmFsc2UsXG4gICAgLy8gU2hvdWxkIHRoZSBzdWdnZXN0aW9ucyBsaXN0IEluY2x1ZGUgYWxyZWFkeS1zZWxlY3RlZCB0YWdzIChhZnRlciBmaWx0ZXJpbmcpXG4gICAgaGlnaGxpZ2h0Rmlyc3Q6IGZhbHNlLFxuICAgIC8vIGhpZ2hsaWdodHMgZmlyc3QtbWF0Y2hlZCBpdGVtIGluIHRoZSBsaXN0XG4gICAgY2xvc2VPblNlbGVjdDogdHJ1ZSxcbiAgICAvLyBjbG9zZXMgdGhlIGRyb3Bkb3duIGFmdGVyIHNlbGVjdGluZyBhbiBpdGVtLCBpZiBgZW5hYmxlZDowYCAod2hpY2ggbWVhbnMgYWx3YXlzIHNob3cgZHJvcGRvd24pXG4gICAgY2xlYXJPblNlbGVjdDogdHJ1ZSxcbiAgICAvLyBhZnRlciBzZWxlY3RpbmcgYSBzdWdnZXRpb24sIHNob3VsZCB0aGUgdHlwZWQgdGV4dCBpbnB1dCByZW1haW4gb3IgYmUgY2xlYXJlZFxuICAgIHBvc2l0aW9uOiAnYWxsJyxcbiAgICAvLyAnbWFudWFsJyAvICd0ZXh0JyAvICdhbGwnXG4gICAgYXBwZW5kVGFyZ2V0OiBudWxsIC8vIGRlZmF1bHRzIHRvIGRvY3VtZW50LmJvZHkgb25jZSBET00gaGFzIGJlZW4gbG9hZGVkXG4gIH0sXG5cbiAgaG9va3M6IHtcbiAgICBiZWZvcmVSZW1vdmVUYWc6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpLFxuICAgIGJlZm9yZVBhc3RlOiAoKSA9PiBQcm9taXNlLnJlc29sdmUoKSxcbiAgICBzdWdnZXN0aW9uQ2xpY2s6ICgpID0+IFByb21pc2UucmVzb2x2ZSgpXG4gIH1cbn07XG5cbmZ1bmN0aW9uIGluaXREcm9wZG93bigpIHtcbiAgdGhpcy5kcm9wZG93biA9IHt9O1xuXG4gIC8vIGF1dG8tYmluZCBcInRoaXNcIiB0byBhbGwgdGhlIGRyb3Bkb3duIG1ldGhvZHNcbiAgZm9yIChsZXQgcCBpbiB0aGlzLl9kcm9wZG93bikgdGhpcy5kcm9wZG93bltwXSA9IHR5cGVvZiB0aGlzLl9kcm9wZG93bltwXSA9PT0gJ2Z1bmN0aW9uJyA/IHRoaXMuX2Ryb3Bkb3duW3BdLmJpbmQodGhpcykgOiB0aGlzLl9kcm9wZG93bltwXTtcbiAgdGhpcy5kcm9wZG93bi5yZWZzKCk7XG59XG52YXIgX2Ryb3Bkb3duID0ge1xuICByZWZzKCkge1xuICAgIHRoaXMuRE9NLmRyb3Bkb3duID0gdGhpcy5wYXJzZVRlbXBsYXRlKCdkcm9wZG93bicsIFt0aGlzLnNldHRpbmdzXSk7XG4gICAgdGhpcy5ET00uZHJvcGRvd24uY29udGVudCA9IHRoaXMuRE9NLmRyb3Bkb3duLnF1ZXJ5U2VsZWN0b3IoXCJbZGF0YS1zZWxlY3Rvcj0ndGFnaWZ5LXN1Z2dlc3Rpb25zLXdyYXBwZXInXVwiKTtcbiAgfSxcbiAgZ2V0SGVhZGVyUmVmKCkge1xuICAgIHJldHVybiB0aGlzLkRPTS5kcm9wZG93bi5xdWVyeVNlbGVjdG9yKFwiW2RhdGEtc2VsZWN0b3I9J3RhZ2lmeS1zdWdnZXN0aW9ucy1oZWFkZXInXVwiKTtcbiAgfSxcbiAgZ2V0Rm9vdGVyUmVmKCkge1xuICAgIHJldHVybiB0aGlzLkRPTS5kcm9wZG93bi5xdWVyeVNlbGVjdG9yKFwiW2RhdGEtc2VsZWN0b3I9J3RhZ2lmeS1zdWdnZXN0aW9ucy1mb290ZXInXVwiKTtcbiAgfSxcbiAgZ2V0QWxsU3VnZ2VzdGlvbnNSZWZzKCkge1xuICAgIHJldHVybiBbLi4udGhpcy5ET00uZHJvcGRvd24uY29udGVudC5xdWVyeVNlbGVjdG9yQWxsKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1TZWxlY3RvcildO1xuICB9LFxuICAvKipcclxuICAgKiBzaG93cyB0aGUgc3VnZ2VzdGlvbnMgc2VsZWN0IGJveFxyXG4gICAqIEBwYXJhbSB7U3RyaW5nfSB2YWx1ZSBbb3B0aW9uYWwsIGZpbHRlciB0aGUgd2hpdGVsaXN0IGJ5IHRoaXMgdmFsdWVdXHJcbiAgICovXG4gIHNob3codmFsdWUpIHtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgZmlyc3RMaXN0SXRlbSxcbiAgICAgIGZpcnN0TGlzdEl0ZW1WYWx1ZSxcbiAgICAgIGFsbG93TmV3VGFncyA9IF9zLm1vZGUgPT0gJ21peCcgJiYgIV9zLmVuZm9yY2VXaGl0ZWxpc3QsXG4gICAgICBub1doaXRlbGlzdCA9ICFfcy53aGl0ZWxpc3QgfHwgIV9zLndoaXRlbGlzdC5sZW5ndGgsXG4gICAgICBub01hdGNoTGlzdEl0ZW0sXG4gICAgICBpc01hbnVhbCA9IF9zLmRyb3Bkb3duLnBvc2l0aW9uID09ICdtYW51YWwnO1xuXG4gICAgLy8gaWYgdGV4dCBzdGlsbCBleGlzdHMgaW4gdGhlIGlucHV0LCBhbmQgYHNob3dgIG1ldGhvZCBoYXMgbm8gYXJndW1lbnQsIHRoZW4gdGhlIGlucHV0J3MgdGV4dCBzaG91bGQgYmUgdXNlZFxuICAgIHZhbHVlID0gdmFsdWUgPT09IHVuZGVmaW5lZCA/IHRoaXMuc3RhdGUuaW5wdXRUZXh0IDogdmFsdWU7XG5cbiAgICAvLyDimqDvuI8gRG8gbm90IHJlbmRlciBzdWdnZXN0aW9ucyBsaXN0ICBpZjpcbiAgICAvLyAxLiB0aGVyZSdzIG5vIHdoaXRlbGlzdCAoY2FuIGhhcHBlbiB3aGlsZSBhc3luYyBsb2FkaW5nKSBBTkQgbmV3IHRhZ3MgYXJuJ3QgYWxsb3dlZFxuICAgIC8vIDIuIGRyb3Bkb3duIGlzIGRpc2FibGVkXG4gICAgLy8gMy4gbG9hZGVyIGlzIHNob3dpbmcgKGNvbnRyb2xsZWQgb3V0c2lkZSBvZiB0aGlzIGNvZGUpXG4gICAgaWYgKG5vV2hpdGVsaXN0ICYmICFhbGxvd05ld1RhZ3MgJiYgIV9zLnRlbXBsYXRlcy5kcm9wZG93bkl0ZW1Ob01hdGNoIHx8IF9zLmRyb3Bkb3duLmVuYWJsZSA9PT0gZmFsc2UgfHwgdGhpcy5zdGF0ZS5pc0xvYWRpbmcgfHwgdGhpcy5zZXR0aW5ncy5yZWFkb25seSkgcmV0dXJuO1xuICAgIGNsZWFyVGltZW91dCh0aGlzLmRyb3Bkb3duSGlkZV9fYmluZEV2ZW50c1RpbWVvdXQpO1xuXG4gICAgLy8gaWYgbm8gdmFsdWUgd2FzIHN1cHBsaWVkLCBzaG93IGFsbCB0aGUgXCJ3aGl0ZWxpc3RcIiBpdGVtcyBpbiB0aGUgZHJvcGRvd25cbiAgICAvLyBAdHlwZSBbQXJyYXldIGxpc3RJdGVtc1xuICAgIC8vIFRPRE86IGFkZCBhIFNldHRpbmcgdG8gY29udHJvbCBpdGVtcycgc29ydCBvcmRlciBmb3IgXCJsaXN0SXRlbXNcIlxuICAgIHRoaXMuc3VnZ2VzdGVkTGlzdEl0ZW1zID0gdGhpcy5kcm9wZG93bi5maWx0ZXJMaXN0SXRlbXModmFsdWUpO1xuXG4gICAgLy8gdHJpZ2dlciBhdCB0aGlzIGV4YWN0IHBvaW50IHRvIGxldCB0aGUgZGV2ZWxvcGVyIHRoZSBjaGFuY2UgdG8gbWFudWFsbHkgc2V0IFwidGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXNcIlxuICAgIGlmICh2YWx1ZSAmJiAhdGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXMubGVuZ3RoKSB7XG4gICAgICB0aGlzLnRyaWdnZXIoJ2Ryb3Bkb3duOm5vTWF0Y2gnLCB2YWx1ZSk7XG4gICAgICBpZiAoX3MudGVtcGxhdGVzLmRyb3Bkb3duSXRlbU5vTWF0Y2gpIG5vTWF0Y2hMaXN0SXRlbSA9IF9zLnRlbXBsYXRlcy5kcm9wZG93bkl0ZW1Ob01hdGNoLmNhbGwodGhpcywge1xuICAgICAgICB2YWx1ZVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gaWYgXCJkcm9wZG93bkl0ZW1Ob01hdGNoXCIgd2FzIG5vIGRlZmluZWQsIHByb2NjZWVkIHJlZ3VsYXIgZmxvdy5cbiAgICAvL1xuICAgIGlmICghbm9NYXRjaExpc3RJdGVtKSB7XG4gICAgICAvLyBpbiBtaXgtbW9kZSwgaWYgdGhlIHZhbHVlIGlzbid0IGluY2x1ZGVkIGluIHRoZSB3aGlsZWxpc3QgJiBcImVuZm9yY2VXaGl0ZWxpc3RcIiBzZXR0aW5nIGlzIFwiZmFsc2VcIixcbiAgICAgIC8vIHRoZW4gYWRkIGEgY3VzdG9tIHN1Z2dlc3Rpb24gaXRlbSB0byB0aGUgZHJvcGRvd25cbiAgICAgIGlmICh0aGlzLnN1Z2dlc3RlZExpc3RJdGVtcy5sZW5ndGgpIHtcbiAgICAgICAgaWYgKHZhbHVlICYmIGFsbG93TmV3VGFncyAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nLnNjb3BlICYmICFzYW1lU3RyKHRoaXMuc3VnZ2VzdGVkTGlzdEl0ZW1zWzBdLnZhbHVlLCB2YWx1ZSkpIHRoaXMuc3VnZ2VzdGVkTGlzdEl0ZW1zLnVuc2hpZnQoe1xuICAgICAgICAgIHZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHZhbHVlICYmIGFsbG93TmV3VGFncyAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nLnNjb3BlKSB7XG4gICAgICAgICAgdGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXMgPSBbe1xuICAgICAgICAgICAgdmFsdWVcbiAgICAgICAgICB9XTtcbiAgICAgICAgfVxuICAgICAgICAvLyBoaWRlIHN1Z2dlc3Rpb25zIGxpc3QgaWYgbm8gc3VnZ2VzdGlvbiBtYXRjaGVkXG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgIHRoaXMuaW5wdXQuYXV0b2NvbXBsZXRlLnN1Z2dlc3QuY2FsbCh0aGlzKTtcbiAgICAgICAgICB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGZpcnN0TGlzdEl0ZW0gPSB0aGlzLnN1Z2dlc3RlZExpc3RJdGVtc1swXTtcbiAgICAgIGZpcnN0TGlzdEl0ZW1WYWx1ZSA9IFwiXCIgKyAoaXNPYmplY3QoZmlyc3RMaXN0SXRlbSkgPyBmaXJzdExpc3RJdGVtLnZhbHVlIDogZmlyc3RMaXN0SXRlbSk7XG4gICAgICBpZiAoX3MuYXV0b0NvbXBsZXRlICYmIGZpcnN0TGlzdEl0ZW1WYWx1ZSkge1xuICAgICAgICAvLyBvbmx5IGZpbGwgdGhlIHN1Z2Vnc3Rpb24gaWYgdGhlIHZhbHVlIG9mIHRoZSBmaXJzdCBsaXN0IGl0ZW0gU1RBUlRTIHdpdGggdGhlIGlucHV0IHZhbHVlIChyZWdhcmRsZXNzIG9mIFwiZnV6enlzZWFyY2hcIiBzZXR0aW5nKVxuICAgICAgICBpZiAoZmlyc3RMaXN0SXRlbVZhbHVlLmluZGV4T2YodmFsdWUpID09IDApIHRoaXMuaW5wdXQuYXV0b2NvbXBsZXRlLnN1Z2dlc3QuY2FsbCh0aGlzLCBmaXJzdExpc3RJdGVtKTtcbiAgICAgIH1cbiAgICB9XG4gICAgdGhpcy5kcm9wZG93bi5maWxsKG5vTWF0Y2hMaXN0SXRlbSk7XG4gICAgaWYgKF9zLmRyb3Bkb3duLmhpZ2hsaWdodEZpcnN0KSB7XG4gICAgICB0aGlzLmRyb3Bkb3duLmhpZ2hsaWdodE9wdGlvbih0aGlzLkRPTS5kcm9wZG93bi5jb250ZW50LnF1ZXJ5U2VsZWN0b3IoX3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1TZWxlY3RvcikpO1xuICAgIH1cblxuICAgIC8vIGJpbmQgZXZlbnRzLCBleGFjdGx5IGF0IHRoaXMgc3RhZ2Ugb2YgdGhlIGNvZGUuIFwiZHJvcGRvd24uc2hvd1wiIG1ldGhvZCBpcyBhbGxvd2VkIHRvIGJlXG4gICAgLy8gY2FsbGVkIG11bHRpcGxlIHRpbWVzLCByZWdhcmRsZXNzIGlmIHRoZSBkcm9wZG93biBpcyBjdXJyZW50bHkgdmlzaWJsZSwgYnV0IHRoZSBldmVudHMtYmluZGluZ1xuICAgIC8vIHNob3VsZCBvbmx5IGJlIGNhbGxlZCBpZiB0aGUgZHJvcGRvd24gd2Fzbid0IHByZXZpb3VzbHkgdmlzaWJsZS5cbiAgICBpZiAoIXRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSlcbiAgICAgIC8vIHRpbWVvdXQgaXMgbmVlZGVkIGZvciB3aGVuIHByZXNzaW5nIGFycm93IGRvd24gdG8gc2hvdyB0aGUgZHJvcGRvd24sXG4gICAgICAvLyBzbyB0aGUga2V5IGV2ZW50IHdvbid0IGdldCByZWdpc3RlcmVkIGluIHRoZSBkcm9wZG93biBldmVudHMgbGlzdGVuZXJzXG4gICAgICBzZXRUaW1lb3V0KHRoaXMuZHJvcGRvd24uZXZlbnRzLmJpbmRpbmcuYmluZCh0aGlzKSk7XG5cbiAgICAvLyBzZXQgdGhlIGRyb3Bkb3duIHZpc2libGUgc3RhdGUgdG8gYmUgdGhlIHNhbWUgYXMgdGhlIHNlYXJjaGVkIHZhbHVlLlxuICAgIC8vIE1VU1QgYmUgc2V0ICpiZWZvcmUqIHBvc2l0aW9uKCkgaXMgY2FsbGVkXG4gICAgdGhpcy5zdGF0ZS5kcm9wZG93bi52aXNpYmxlID0gdmFsdWUgfHwgdHJ1ZTtcbiAgICB0aGlzLnN0YXRlLmRyb3Bkb3duLnF1ZXJ5ID0gdmFsdWU7XG4gICAgdGhpcy5zZXRTdGF0ZVNlbGVjdGlvbigpO1xuXG4gICAgLy8gdHJ5IHRvIHBvc2l0aW9uaW5nIHRoZSBkcm9wZG93biAoaXQgbWlnaHQgbm90IHlldCBiZSBvbiB0aGUgcGFnZSwgZG9lc24ndCBtYXR0ZXIsIG5leHQgY29kZSBoYW5kbGVzIHRoaXMpXG4gICAgaWYgKCFpc01hbnVhbCkge1xuICAgICAgLy8gYSBzbGlnaHQgZGVsYXkgaXMgbmVlZGVkIGlmIHRoZSBkcm9wZG93biBcInBvc2l0aW9uXCIgc2V0dGluZyBpcyBcInRleHRcIiwgYW5kIG5vdGhpbmcgd2FzIHR5cGVkIGluIHRoZSBpbnB1dCxcbiAgICAgIC8vIHNvIHNhZGx5IHRoZSBcImdldENhcmV0R2xvYmFsUG9zaXRpb25cIiBtZXRob2QgZG9lc24ndCByZWNvZ25pemUgdGhlIGNhcmV0IHBvc2l0aW9uIHdpdGhvdXQgdGhpcyBkZWxheVxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMuZHJvcGRvd24ucG9zaXRpb24oKTtcbiAgICAgICAgdGhpcy5kcm9wZG93bi5yZW5kZXIoKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIGEgZGVsYXkgaXMgbmVlZGVkIGJlY2F1c2Ugb2YgdGhlIHByZXZpb3VzIGRlbGF5IHJlYXNvbi5cbiAgICAvLyB0aGlzIGV2ZW50IG11c3QgYmUgZmlyZWQgYWZ0ZXIgdGhlIGRyb3Bkb3duIHdhcyByZW5kZXJlZCAmIHBvc2l0aW9uZWRcbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMudHJpZ2dlcihcImRyb3Bkb3duOnNob3dcIiwgdGhpcy5ET00uZHJvcGRvd24pO1xuICAgIH0pO1xuICB9LFxuICAvKipcclxuICAgKiBIaWRlcyB0aGUgZHJvcGRvd24gKGlmIGl0J3Mgbm90IG1hbmFnZWQgbWFudWFsbHkgYnkgdGhlIGRldmVsb3BlcilcclxuICAgKiBAcGFyYW0ge0Jvb2xlYW59IG92ZXJyaWRlTWFudWFsXHJcbiAgICovXG4gIGhpZGUob3ZlcnJpZGVNYW51YWwpIHtcbiAgICB2YXIgX3RoaXMkRE9NID0gdGhpcy5ET00sXG4gICAgICBzY29wZSA9IF90aGlzJERPTS5zY29wZSxcbiAgICAgIGRyb3Bkb3duID0gX3RoaXMkRE9NLmRyb3Bkb3duLFxuICAgICAgaXNNYW51YWwgPSB0aGlzLnNldHRpbmdzLmRyb3Bkb3duLnBvc2l0aW9uID09ICdtYW51YWwnICYmICFvdmVycmlkZU1hbnVhbDtcblxuICAgIC8vIGlmIHRoZXJlJ3Mgbm8gZHJvcGRvd24sIHRoaXMgbWVhbnMgdGhlIGRyb3Bkb3duIGV2ZW50cyBhcmVuJ3QgYmluZGVkXG4gICAgaWYgKCFkcm9wZG93biB8fCAhZG9jdW1lbnQuYm9keS5jb250YWlucyhkcm9wZG93bikgfHwgaXNNYW51YWwpIHJldHVybjtcbiAgICB3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcigncmVzaXplJywgdGhpcy5kcm9wZG93bi5wb3NpdGlvbik7XG4gICAgdGhpcy5kcm9wZG93bi5ldmVudHMuYmluZGluZy5jYWxsKHRoaXMsIGZhbHNlKTsgLy8gdW5iaW5kIGFsbCBldmVudHNcblxuICAgIC8vIGlmIHRoZSBkcm9wZG93biBpcyBvcGVuLCBhbmQgdGhlIGlucHV0IChzY29wZSkgaXMgY2xpY2tlZCxcbiAgICAvLyB0aGUgZHJvcGRvd24gc2hvdWxkIGJlIG5vdyBcImNsb3NlXCIsIGFuZCB0aGUgbmV4dCBjbGljayAob24gdGhlIHNjb3BlKVxuICAgIC8vIHNob3VsZCByZS1vcGVuIGl0LCBhbmQgd2l0aG91dCBhIHRpbWVvdXQsIGNsaWNraW5nIHRvIGNsb3NlIHdpbGwgcmUtb3BlbiBpbW1lZGlhdGVseVxuICAgIC8vICBjbGVhclRpbWVvdXQodGhpcy5kcm9wZG93bkhpZGVfX2JpbmRFdmVudHNUaW1lb3V0KVxuICAgIC8vICB0aGlzLmRyb3Bkb3duSGlkZV9fYmluZEV2ZW50c1RpbWVvdXQgPSBzZXRUaW1lb3V0KHRoaXMuZXZlbnRzLmJpbmRpbmcuYmluZCh0aGlzKSwgMjUwKSAgLy8gcmUtYmluZCBtYWluIGV2ZW50c1xuXG4gICAgc2NvcGUuc2V0QXR0cmlidXRlKFwiYXJpYS1leHBhbmRlZFwiLCBmYWxzZSk7XG4gICAgZHJvcGRvd24ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChkcm9wZG93bik7XG5cbiAgICAvLyBzY2VuYXJpbzogY2xpY2tpbmcgdGhlIHNjb3BlIHRvIHNob3cgdGhlIGRyb3Bkb3duLCBjbGlja2luZyBhZ2FpbiB0byBoaWRlIC0+IGNhbGxzIGRyb3Bkb3duLmhpZGUoKSBhbmQgdGhlbiByZS1mb2N1c2VzIHRoZSBpbnB1dFxuICAgIC8vIHdoaWNoIGNhc3VlcyBhbm90aGVyIG9uRm9jdXMgZXZlbnQsIHdoaWNoIGNoZWNrZWQgXCJ0aGlzLnN0YXRlLmRyb3Bkb3duLnZpc2libGVcIiBhbmQgc2VlIGl0IGFzIFwiZmFsc2VcIiBhbmQgcmUtb3BlbiB0aGUgZHJvcGRvd25cbiAgICBzZXRUaW1lb3V0KCgpID0+IHtcbiAgICAgIHRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSA9IGZhbHNlO1xuICAgIH0sIDEwMCk7XG4gICAgdGhpcy5zdGF0ZS5kcm9wZG93bi5xdWVyeSA9IHRoaXMuc3RhdGUuZGRJdGVtRGF0YSA9IHRoaXMuc3RhdGUuZGRJdGVtRWxtID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb24gPSBudWxsO1xuXG4gICAgLy8gaWYgdGhlIHVzZXIgY2xvc2VkIHRoZSBkcm9wZG93biAoaW4gbWl4LW1vZGUpIHdoaWxlIGEgcG90ZW50aWFsIHRhZyB3YXMgZGV0ZWN0ZWQsIGZsYWcgdGhlIGN1cnJlbnQgdGFnXG4gICAgLy8gc28gdGhlIGRyb3Bkb3duIHdvbid0IGJlIHNob3duIG9uIGZvbGxvd2luZyB1c2VyIGlucHV0IGZvciB0aGF0IFwidGFnXCJcbiAgICBpZiAodGhpcy5zdGF0ZS50YWcgJiYgdGhpcy5zdGF0ZS50YWcudmFsdWUubGVuZ3RoKSB7XG4gICAgICB0aGlzLnN0YXRlLmZsYWdnZWRUYWdzW3RoaXMuc3RhdGUudGFnLmJhc2VPZmZzZXRdID0gdGhpcy5zdGF0ZS50YWc7XG4gICAgfVxuICAgIHRoaXMudHJpZ2dlcihcImRyb3Bkb3duOmhpZGVcIiwgZHJvcGRvd24pO1xuICAgIHJldHVybiB0aGlzO1xuICB9LFxuICAvKipcclxuICAgKiBUb2dnbGVzIGRyb3Bkb3duIHNob3cvaGlkZVxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gc2hvdyBmb3JjZXMgdGhlIGRyb3Bkb3duIHRvIHNob3dcclxuICAgKi9cbiAgdG9nZ2xlKHNob3cpIHtcbiAgICB0aGlzLmRyb3Bkb3duW3RoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSAmJiAhc2hvdyA/ICdoaWRlJyA6ICdzaG93J10oKTtcbiAgfSxcbiAgcmVuZGVyKCkge1xuICAgIC8vIGxldCB0aGUgZWxlbWVudCByZW5kZXIgaW4gdGhlIERPTSBmaXJzdCwgdG8gYWNjdXJhdGVseSBtZWFzdXJlIGl0LlxuICAgIC8vIHRoaXMuRE9NLmRyb3Bkb3duLnN0eWxlLmNzc1RleHQgPSBcImxlZnQ6LTk5OTlweDsgdG9wOi05OTk5cHg7XCI7XG4gICAgdmFyIGRkSGVpZ2h0ID0gZ2V0Tm9kZUhlaWdodCh0aGlzLkRPTS5kcm9wZG93biksXG4gICAgICBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICBlbmFibGVkID0gdHlwZW9mIF9zLmRyb3Bkb3duLmVuYWJsZWQgPT0gJ251bWJlcicgJiYgX3MuZHJvcGRvd24uZW5hYmxlZCA+PSAwO1xuICAgIGlmICghZW5hYmxlZCkgcmV0dXJuIHRoaXM7XG4gICAgdGhpcy5ET00uc2NvcGUuc2V0QXR0cmlidXRlKFwiYXJpYS1leHBhbmRlZFwiLCB0cnVlKTtcblxuICAgIC8vIGlmIHRoZSBkcm9wZG93biBoYXMgeWV0IHRvIGJlIGFwcGVuZGVkIHRvIHRoZSBET00sXG4gICAgLy8gYXBwZW5kIHRoZSBkcm9wZG93biB0byB0aGUgYm9keSBlbGVtZW50ICYgaGFuZGxlIGV2ZW50c1xuICAgIGlmICghZG9jdW1lbnQuYm9keS5jb250YWlucyh0aGlzLkRPTS5kcm9wZG93bikpIHtcbiAgICAgIHRoaXMuRE9NLmRyb3Bkb3duLmNsYXNzTGlzdC5hZGQoX3MuY2xhc3NOYW1lcy5kcm9wZG93bkluaXRhbCk7XG4gICAgICB0aGlzLmRyb3Bkb3duLnBvc2l0aW9uKGRkSGVpZ2h0KTtcbiAgICAgIF9zLmRyb3Bkb3duLmFwcGVuZFRhcmdldC5hcHBlbmRDaGlsZCh0aGlzLkRPTS5kcm9wZG93bik7XG4gICAgICBzZXRUaW1lb3V0KCgpID0+IHRoaXMuRE9NLmRyb3Bkb3duLmNsYXNzTGlzdC5yZW1vdmUoX3MuY2xhc3NOYW1lcy5kcm9wZG93bkluaXRhbCkpO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfSxcbiAgLyoqXHJcbiAgICogcmUtcmVuZGVycyB0aGUgZHJvcGRvd24gY29udGVudCBlbGVtZW50IChzZWUgXCJkcm9wZG93bkNvbnRlbnRcIiBpbiB0ZW1wbGF0ZXMgZmlsZSlcclxuICAgKiBAcGFyYW0ge1N0cmluZy9BcnJheX0gSFRNTENvbnRlbnQgLSBvcHRpb25hbFxyXG4gICAqL1xuICBmaWxsKEhUTUxDb250ZW50KSB7XG4gICAgSFRNTENvbnRlbnQgPSB0eXBlb2YgSFRNTENvbnRlbnQgPT0gJ3N0cmluZycgPyBIVE1MQ29udGVudCA6IHRoaXMuZHJvcGRvd24uY3JlYXRlTGlzdEhUTUwoSFRNTENvbnRlbnQgfHwgdGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXMpO1xuICAgIHZhciBkcm9wZG93bkNvbnRlbnQgPSB0aGlzLnNldHRpbmdzLnRlbXBsYXRlcy5kcm9wZG93bkNvbnRlbnQuY2FsbCh0aGlzLCBIVE1MQ29udGVudCk7XG4gICAgdGhpcy5ET00uZHJvcGRvd24uY29udGVudC5pbm5lckhUTUwgPSBtaW5pZnkoZHJvcGRvd25Db250ZW50KTtcbiAgfSxcbiAgLyoqXHJcbiAgICogUmUtcmVuZGVycyBvbmx5IHRoZSBoZWFkZXIgJiBmb290ZXIuXHJcbiAgICogVXNlZCB3aGVuIHNlbGVjdGluZyBhIHN1Z2dlc3Rpb24gYW5kIGl0IGlzIHdhbnRlZCB0aGF0IHRoZSBzdWdnZXN0aW9ucyBkcm9wZG93biBzdGF5cyBvcGVuLlxyXG4gICAqIFNpbmNlIHRoZSBsaXN0IG9mIHN1Z2Vnc3Rpb25zIGlzIG5vdCBiZWluZyByZS1yZW5kZXJlZCBjb21wbGV0ZWx5IGV2ZXJ5IHRpbWUgYSBzdWdnZXN0aW9uIGlzIHNlbGVjdGVkICh0aGUgaXRlbSBpcyB0cmFuc2l0aW9uZWQtb3V0KVxyXG4gICAqIHRoZW4gdGhlIGhlYWRlciAmIGZvb3RlciBzaG91bGQgYmUga2VwdCBpbiBzeW5jIHdpdGggdGhlIHN1Z2dlc3Rpb25zIGRhdGEgY2hhbmdlXHJcbiAgICovXG4gIGZpbGxIZWFkZXJGb290ZXIoKSB7XG4gICAgdmFyIHN1Z2dlc3Rpb25zID0gdGhpcy5kcm9wZG93bi5maWx0ZXJMaXN0SXRlbXModGhpcy5zdGF0ZS5kcm9wZG93bi5xdWVyeSksXG4gICAgICBuZXdIZWFkZXJFbGVtID0gdGhpcy5wYXJzZVRlbXBsYXRlKCdkcm9wZG93bkhlYWRlcicsIFtzdWdnZXN0aW9uc10pLFxuICAgICAgbmV3Rm9vdGVyRWxlbSA9IHRoaXMucGFyc2VUZW1wbGF0ZSgnZHJvcGRvd25Gb290ZXInLCBbc3VnZ2VzdGlvbnNdKSxcbiAgICAgIGhlYWRlclJlZiA9IHRoaXMuZHJvcGRvd24uZ2V0SGVhZGVyUmVmKCksXG4gICAgICBmb290ZXJSZWYgPSB0aGlzLmRyb3Bkb3duLmdldEZvb3RlclJlZigpO1xuICAgIG5ld0hlYWRlckVsZW0gJiYgaGVhZGVyUmVmPy5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChuZXdIZWFkZXJFbGVtLCBoZWFkZXJSZWYpO1xuICAgIG5ld0Zvb3RlckVsZW0gJiYgZm9vdGVyUmVmPy5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChuZXdGb290ZXJFbGVtLCBmb290ZXJSZWYpO1xuICB9LFxuICAvKipcclxuICAgKiBmaWxsIGRhdGEgaW50byB0aGUgc3VnZ2VzdGlvbnMgbGlzdFxyXG4gICAqIChtYWlubHkgdXNlZCB0byB1cGRhdGUgdGhlIGxpc3Qgd2hlbiByZW1vdmluZyB0YWdzIHdoaWxlIHRoZSBzdWdnZXN0aW9ucyBkcm9wZG93biBpcyB2aXNpYmxlLCBzbyB0aGV5IHdpbGwgYmUgcmUtYWRkZWQgdG8gdGhlIGxpc3QuIG5vdCBlZmZpY2llbnQpXHJcbiAgICovXG4gIHJlZmlsdGVyKHZhbHVlKSB7XG4gICAgdmFsdWUgPSB2YWx1ZSB8fCB0aGlzLnN0YXRlLmRyb3Bkb3duLnF1ZXJ5IHx8ICcnO1xuICAgIHRoaXMuc3VnZ2VzdGVkTGlzdEl0ZW1zID0gdGhpcy5kcm9wZG93bi5maWx0ZXJMaXN0SXRlbXModmFsdWUpO1xuICAgIHRoaXMuZHJvcGRvd24uZmlsbCgpO1xuICAgIGlmICghdGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXMubGVuZ3RoKSB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICB0aGlzLnRyaWdnZXIoXCJkcm9wZG93bjp1cGRhdGVkXCIsIHRoaXMuRE9NLmRyb3Bkb3duKTtcbiAgfSxcbiAgcG9zaXRpb24oZGRIZWlnaHQpIHtcbiAgICB2YXIgX3NkID0gdGhpcy5zZXR0aW5ncy5kcm9wZG93bjtcbiAgICBpZiAoX3NkLnBvc2l0aW9uID09ICdtYW51YWwnKSByZXR1cm47XG4gICAgdmFyIHJlY3QsXG4gICAgICB0b3AsXG4gICAgICBib3R0b20sXG4gICAgICBsZWZ0LFxuICAgICAgd2lkdGgsXG4gICAgICBwYXJlbnRzUG9zaXRpb25zLFxuICAgICAgZGRFbG0gPSB0aGlzLkRPTS5kcm9wZG93bixcbiAgICAgIHBsYWNlQWJvdmUgPSBfc2QucGxhY2VBYm92ZSxcbiAgICAgIGlzRGVmYXVsdEFwcGVuZFRhcmdldCA9IF9zZC5hcHBlbmRUYXJnZXQgPT09IGRvY3VtZW50LmJvZHksXG4gICAgICBhcHBlbmRUYXJnZXRTY3JvbGxUb3AgPSBpc0RlZmF1bHRBcHBlbmRUYXJnZXQgPyB3aW5kb3cucGFnZVlPZmZzZXQgOiBfc2QuYXBwZW5kVGFyZ2V0LnNjcm9sbFRvcCxcbiAgICAgIHJvb3QgPSBkb2N1bWVudC5mdWxsc2NyZWVuRWxlbWVudCB8fCBkb2N1bWVudC53ZWJraXRGdWxsc2NyZWVuRWxlbWVudCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQsXG4gICAgICB2aWV3cG9ydEhlaWdodCA9IHJvb3QuY2xpZW50SGVpZ2h0LFxuICAgICAgdmlld3BvcnRXaWR0aCA9IE1hdGgubWF4KHJvb3QuY2xpZW50V2lkdGggfHwgMCwgd2luZG93LmlubmVyV2lkdGggfHwgMCksXG4gICAgICBwb3NpdGlvblRvID0gdmlld3BvcnRXaWR0aCA+IDQ4MCA/IF9zZC5wb3NpdGlvbiA6ICdhbGwnLFxuICAgICAgZGRUYXJnZXQgPSB0aGlzLkRPTVtwb3NpdGlvblRvID09ICdpbnB1dCcgPyAnaW5wdXQnIDogJ3Njb3BlJ107XG4gICAgZGRIZWlnaHQgPSBkZEhlaWdodCB8fCBkZEVsbS5jbGllbnRIZWlnaHQ7XG4gICAgZnVuY3Rpb24gZ2V0UGFyZW50c1Bvc2l0aW9ucyhwKSB7XG4gICAgICB2YXIgbGVmdCA9IDAsXG4gICAgICAgIHRvcCA9IDA7XG5cbiAgICAgIC8vIHdoZW4gaW4gZWxlbWVudC1mdWxsc2NyZWVuIG1vZGUsIGRvIG5vdCBnbyBhYm92ZSB0aGUgZnVsbHNjcmVlbmVkLWVsZW1lbnRcbiAgICAgIHdoaWxlIChwICYmIHAgIT0gcm9vdCkge1xuICAgICAgICBsZWZ0ICs9IHAub2Zmc2V0TGVmdCB8fCAwO1xuICAgICAgICB0b3AgKz0gcC5vZmZzZXRUb3AgfHwgMDtcbiAgICAgICAgcCA9IHAucGFyZW50Tm9kZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB7XG4gICAgICAgIGxlZnQsXG4gICAgICAgIHRvcFxuICAgICAgfTtcbiAgICB9XG4gICAgZnVuY3Rpb24gZ2V0QWNjdW11bGF0ZWRBbmNlc3RvcnNTY3JvbGxUb3AoKSB7XG4gICAgICB2YXIgc2Nyb2xsVG9wID0gMCxcbiAgICAgICAgcCA9IF9zZC5hcHBlbmRUYXJnZXQucGFyZW50Tm9kZTtcbiAgICAgIHdoaWxlIChwKSB7XG4gICAgICAgIHNjcm9sbFRvcCArPSBwLnNjcm9sbFRvcCB8fCAwO1xuICAgICAgICBwID0gcC5wYXJlbnROb2RlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHNjcm9sbFRvcDtcbiAgICB9XG4gICAgaWYgKCF0aGlzLnN0YXRlLmRyb3Bkb3duLnZpc2libGUpIHJldHVybjtcbiAgICBpZiAocG9zaXRpb25UbyA9PSAndGV4dCcpIHtcbiAgICAgIHJlY3QgPSBnZXRDYXJldEdsb2JhbFBvc2l0aW9uKCk7XG4gICAgICBib3R0b20gPSByZWN0LmJvdHRvbTtcbiAgICAgIHRvcCA9IHJlY3QudG9wO1xuICAgICAgbGVmdCA9IHJlY3QubGVmdDtcbiAgICAgIHdpZHRoID0gJ2F1dG8nO1xuICAgIH0gZWxzZSB7XG4gICAgICBwYXJlbnRzUG9zaXRpb25zID0gZ2V0UGFyZW50c1Bvc2l0aW9ucyhfc2QuYXBwZW5kVGFyZ2V0KTtcbiAgICAgIHJlY3QgPSBkZFRhcmdldC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIHRvcCA9IHJlY3QudG9wIC0gcGFyZW50c1Bvc2l0aW9ucy50b3A7XG4gICAgICBib3R0b20gPSByZWN0LmJvdHRvbSAtIDEgLSBwYXJlbnRzUG9zaXRpb25zLnRvcDtcbiAgICAgIGxlZnQgPSByZWN0LmxlZnQgLSBwYXJlbnRzUG9zaXRpb25zLmxlZnQ7XG4gICAgICB3aWR0aCA9IHJlY3Qud2lkdGggKyAncHgnO1xuICAgIH1cblxuICAgIC8vIGlmIHRoZSBcImFwcGVuZCB0YXJnZXRcIiBpc24ndCB0aGUgZGVmYXVsdCwgY29ycmVjdCB0aGUgYHRvcGAgdmFyaWFibGUgYnkgaWdub3JpbmcgYW55IHNjcm9sbFRvcCBvZiB0aGUgdGFyZ2V0J3MgQW5jZXN0b3JzXG4gICAgaWYgKCFpc0RlZmF1bHRBcHBlbmRUYXJnZXQpIHtcbiAgICAgIGxldCBhY2N1bXVsYXRlZEFuY2VzdG9yc1Njcm9sbFRvcCA9IGdldEFjY3VtdWxhdGVkQW5jZXN0b3JzU2Nyb2xsVG9wKCk7XG4gICAgICB0b3AgKz0gYWNjdW11bGF0ZWRBbmNlc3RvcnNTY3JvbGxUb3A7XG4gICAgICBib3R0b20gKz0gYWNjdW11bGF0ZWRBbmNlc3RvcnNTY3JvbGxUb3A7XG4gICAgfVxuICAgIHRvcCA9IE1hdGguZmxvb3IodG9wKTtcbiAgICBib3R0b20gPSBNYXRoLmNlaWwoYm90dG9tKTtcbiAgICBwbGFjZUFib3ZlID0gcGxhY2VBYm92ZSA9PT0gdW5kZWZpbmVkID8gdmlld3BvcnRIZWlnaHQgLSByZWN0LmJvdHRvbSA8IGRkSGVpZ2h0IDogcGxhY2VBYm92ZTtcblxuICAgIC8vIGZsaXAgdmVydGljYWxseSBpZiB0aGVyZSBpcyBubyBzcGFjZSBmb3IgdGhlIGRyb3Bkb3duIGJlbG93IHRoZSBpbnB1dFxuICAgIGRkRWxtLnN0eWxlLmNzc1RleHQgPSBcImxlZnQ6XCIgKyAobGVmdCArIHdpbmRvdy5wYWdlWE9mZnNldCkgKyBcInB4OyB3aWR0aDpcIiArIHdpZHRoICsgXCI7XCIgKyAocGxhY2VBYm92ZSA/IFwidG9wOiBcIiArICh0b3AgKyBhcHBlbmRUYXJnZXRTY3JvbGxUb3ApICsgXCJweFwiIDogXCJ0b3A6IFwiICsgKGJvdHRvbSArIGFwcGVuZFRhcmdldFNjcm9sbFRvcCkgKyBcInB4XCIpO1xuICAgIGRkRWxtLnNldEF0dHJpYnV0ZSgncGxhY2VtZW50JywgcGxhY2VBYm92ZSA/IFwidG9wXCIgOiBcImJvdHRvbVwiKTtcbiAgICBkZEVsbS5zZXRBdHRyaWJ1dGUoJ3Bvc2l0aW9uJywgcG9zaXRpb25Ubyk7XG4gIH0sXG4gIGV2ZW50czoge1xuICAgIC8qKlxyXG4gICAgICogRXZlbnRzIHNob3VsZCBvbmx5IGJlIGJpbmRlZCB3aGVuIHRoZSBkcm9wZG93biBpcyByZW5kZXJlZCBhbmQgcmVtb3ZlZCB3aGVuIGlzbid0XHJcbiAgICAgKiBiZWNhdXNlIHRoZXJlIG1pZ2h0IGJlIG11bHRpcGxlIFRhZ2lmeSBpbnN0YW5jZXMgb24gYSBjZXJ0YWluIHBhZ2VcclxuICAgICAqIEBwYXJhbSAge0Jvb2xlYW59IGJpbmRVbmJpbmQgW29wdGlvbmFsLiB0cnVlIHdoZW4gd2FudGluZyB0byB1bmJpbmQgYWxsIHRoZSBldmVudHNdXHJcbiAgICAgKi9cbiAgICBiaW5kaW5nKCkge1xuICAgICAgbGV0IGJpbmRVbmJpbmQgPSBhcmd1bWVudHMubGVuZ3RoID4gMCAmJiBhcmd1bWVudHNbMF0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1swXSA6IHRydWU7XG4gICAgICAvLyByZWZlcmVuY2VzIHRvIHRoZSBcIi5iaW5kKClcIiBtZXRob2RzIG11c3QgYmUgc2F2ZWQgc28gdGhleSBjb3VsZCBiZSB1bmJpbmRlZCBsYXRlclxuICAgICAgdmFyIF9DQiA9IHRoaXMuZHJvcGRvd24uZXZlbnRzLmNhbGxiYWNrcyxcbiAgICAgICAgLy8gY2FsbGJhY2stcmVmc1xuICAgICAgICBfQ0JSID0gdGhpcy5saXN0ZW5lcnMuZHJvcGRvd24gPSB0aGlzLmxpc3RlbmVycy5kcm9wZG93biB8fCB7XG4gICAgICAgICAgcG9zaXRpb246IHRoaXMuZHJvcGRvd24ucG9zaXRpb24uYmluZCh0aGlzLCBudWxsKSxcbiAgICAgICAgICBvbktleURvd246IF9DQi5vbktleURvd24uYmluZCh0aGlzKSxcbiAgICAgICAgICBvbk1vdXNlT3ZlcjogX0NCLm9uTW91c2VPdmVyLmJpbmQodGhpcyksXG4gICAgICAgICAgb25Nb3VzZUxlYXZlOiBfQ0Iub25Nb3VzZUxlYXZlLmJpbmQodGhpcyksXG4gICAgICAgICAgb25DbGljazogX0NCLm9uQ2xpY2suYmluZCh0aGlzKSxcbiAgICAgICAgICBvblNjcm9sbDogX0NCLm9uU2Nyb2xsLmJpbmQodGhpcylcbiAgICAgICAgfSxcbiAgICAgICAgYWN0aW9uID0gYmluZFVuYmluZCA/ICdhZGRFdmVudExpc3RlbmVyJyA6ICdyZW1vdmVFdmVudExpc3RlbmVyJztcbiAgICAgIGlmICh0aGlzLnNldHRpbmdzLmRyb3Bkb3duLnBvc2l0aW9uICE9ICdtYW51YWwnKSB7XG4gICAgICAgIGRvY3VtZW50W2FjdGlvbl0oJ3Njcm9sbCcsIF9DQlIucG9zaXRpb24sIHRydWUpO1xuICAgICAgICB3aW5kb3dbYWN0aW9uXSgncmVzaXplJywgX0NCUi5wb3NpdGlvbik7XG4gICAgICAgIHdpbmRvd1thY3Rpb25dKCdrZXlkb3duJywgX0NCUi5vbktleURvd24pO1xuICAgICAgfVxuICAgICAgdGhpcy5ET00uZHJvcGRvd25bYWN0aW9uXSgnbW91c2VvdmVyJywgX0NCUi5vbk1vdXNlT3Zlcik7XG4gICAgICB0aGlzLkRPTS5kcm9wZG93blthY3Rpb25dKCdtb3VzZWxlYXZlJywgX0NCUi5vbk1vdXNlTGVhdmUpO1xuICAgICAgdGhpcy5ET00uZHJvcGRvd25bYWN0aW9uXSgnbW91c2Vkb3duJywgX0NCUi5vbkNsaWNrKTtcbiAgICAgIHRoaXMuRE9NLmRyb3Bkb3duLmNvbnRlbnRbYWN0aW9uXSgnc2Nyb2xsJywgX0NCUi5vblNjcm9sbCk7XG4gICAgfSxcbiAgICBjYWxsYmFja3M6IHtcbiAgICAgIG9uS2V5RG93bihlKSB7XG4gICAgICAgIC8vIGlnbm9yZSBrZXlzIGR1cmluZyBJTUUgY29tcG9zaXRpb25cbiAgICAgICAgaWYgKCF0aGlzLnN0YXRlLmhhc0ZvY3VzIHx8IHRoaXMuc3RhdGUuY29tcG9zaW5nKSByZXR1cm47XG5cbiAgICAgICAgLy8gZ2V0IHRoZSBcImFjdGl2ZVwiIGVsZW1lbnQsIGFuZCBpZiB0aGVyZSB3YXMgbm9uZSAoeWV0KSBhY3RpdmUsIHVzZSBmaXJzdCBjaGlsZFxuICAgICAgICB2YXIgc2VsZWN0ZWRFbG0gPSB0aGlzLkRPTS5kcm9wZG93bi5xdWVyeVNlbGVjdG9yKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1BY3RpdmVTZWxlY3RvciksXG4gICAgICAgICAgc2VsZWN0ZWRFbG1EYXRhID0gdGhpcy5kcm9wZG93bi5nZXRTdWdnZXN0aW9uRGF0YUJ5Tm9kZShzZWxlY3RlZEVsbSk7XG4gICAgICAgIHN3aXRjaCAoZS5rZXkpIHtcbiAgICAgICAgICBjYXNlICdBcnJvd0Rvd24nOlxuICAgICAgICAgIGNhc2UgJ0Fycm93VXAnOlxuICAgICAgICAgIGNhc2UgJ0Rvd24nOiAvLyA+SUUxMVxuICAgICAgICAgIGNhc2UgJ1VwJzpcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgLy8gPklFMTFcbiAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICB2YXIgZHJvcGRvd25JdGVtcyA9IHRoaXMuZHJvcGRvd24uZ2V0QWxsU3VnZ2VzdGlvbnNSZWZzKCksXG4gICAgICAgICAgICAgICAgYWN0aW9uVXAgPSBlLmtleSA9PSAnQXJyb3dVcCcgfHwgZS5rZXkgPT0gJ1VwJztcbiAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkRWxtKSB7XG4gICAgICAgICAgICAgICAgc2VsZWN0ZWRFbG0gPSB0aGlzLmRyb3Bkb3duLmdldE5leHRPclByZXZPcHRpb24oc2VsZWN0ZWRFbG0sICFhY3Rpb25VcCk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBpZiBubyBlbGVtZW50IHdhcyBmb3VuZCBPUiBjdXJyZW50IGl0ZW0gaXMgbm90IGEgXCJyZWFsXCIgaXRlbSwgbG9vcFxuICAgICAgICAgICAgICBpZiAoIXNlbGVjdGVkRWxtIHx8ICFzZWxlY3RlZEVsbS5tYXRjaGVzKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1TZWxlY3RvcikpIHtcbiAgICAgICAgICAgICAgICBzZWxlY3RlZEVsbSA9IGRyb3Bkb3duSXRlbXNbYWN0aW9uVXAgPyBkcm9wZG93bkl0ZW1zLmxlbmd0aCAtIDEgOiAwXTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB0aGlzLmRyb3Bkb3duLmhpZ2hsaWdodE9wdGlvbihzZWxlY3RlZEVsbSwgdHJ1ZSk7XG4gICAgICAgICAgICAgIC8vIHNlbGVjdGVkRWxtLnNjcm9sbEludG9WaWV3KHtpbmxpbmU6ICduZWFyZXN0JywgYmVoYXZpb3I6ICdzbW9vdGgnfSlcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgY2FzZSAnRXNjYXBlJzpcbiAgICAgICAgICBjYXNlICdFc2MnOlxuICAgICAgICAgICAgLy8gSUUxMVxuICAgICAgICAgICAgdGhpcy5kcm9wZG93bi5oaWRlKCk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlICdBcnJvd1JpZ2h0JzpcbiAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmFjdGlvbnMuQXJyb3dMZWZ0KSByZXR1cm47XG4gICAgICAgICAgY2FzZSAnVGFiJzpcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgLy8gaW4gbWl4LW1vZGUsIHRyZWF0IGFycm93UmlnaHQgbGlrZSBFbnRlciBrZXksIHNvIGEgdGFnIHdpbGwgYmUgY3JlYXRlZFxuICAgICAgICAgICAgICBpZiAodGhpcy5zZXR0aW5ncy5tb2RlICE9ICdtaXgnICYmIHNlbGVjdGVkRWxtICYmICF0aGlzLnNldHRpbmdzLmF1dG9Db21wbGV0ZS5yaWdodEtleSAmJiAhdGhpcy5zdGF0ZS5lZGl0aW5nKSB7XG4gICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpOyAvLyBwcmV2ZW50cyBibHVyIHNvIHRoZSBhdXRvY29tcGxldGUgc3VnZ2VzdGlvbiB3aWxsIG5vdCBiZWNvbWUgYSB0YWdcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSB0aGlzLmRyb3Bkb3duLmdldE1hcHBlZFZhbHVlKHNlbGVjdGVkRWxtRGF0YSk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbnB1dC5hdXRvY29tcGxldGUuc2V0LmNhbGwodGhpcywgdmFsdWUpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICdFbnRlcic6XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgdGhpcy5zZXR0aW5ncy5ob29rcy5zdWdnZXN0aW9uQ2xpY2soZSwge1xuICAgICAgICAgICAgICAgIHRhZ2lmeTogdGhpcyxcbiAgICAgICAgICAgICAgICB0YWdEYXRhOiBzZWxlY3RlZEVsbURhdGEsXG4gICAgICAgICAgICAgICAgc3VnZ2VzdGlvbkVsbTogc2VsZWN0ZWRFbG1cbiAgICAgICAgICAgICAgfSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHNlbGVjdGVkRWxtKSB7XG4gICAgICAgICAgICAgICAgICB0aGlzLmRyb3Bkb3duLnNlbGVjdE9wdGlvbihzZWxlY3RlZEVsbSk7XG4gICAgICAgICAgICAgICAgICAvLyBoaWdobGlnaHQgbmV4dCBvcHRpb25cbiAgICAgICAgICAgICAgICAgIHNlbGVjdGVkRWxtID0gdGhpcy5kcm9wZG93bi5nZXROZXh0T3JQcmV2T3B0aW9uKHNlbGVjdGVkRWxtLCAhYWN0aW9uVXApO1xuICAgICAgICAgICAgICAgICAgdGhpcy5kcm9wZG93bi5oaWdobGlnaHRPcHRpb24oc2VsZWN0ZWRFbG0pO1xuICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zZXR0aW5ncy5tb2RlICE9ICdtaXgnKSB0aGlzLmFkZFRhZ3ModGhpcy5zdGF0ZS5pbnB1dFRleHQudHJpbSgpLCB0cnVlKTtcbiAgICAgICAgICAgICAgfSkuY2F0Y2goZXJyID0+IGVycik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIGNhc2UgJ0JhY2tzcGFjZSc6XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLnNldHRpbmdzLm1vZGUgPT0gJ21peCcgfHwgdGhpcy5zdGF0ZS5lZGl0aW5nLnNjb3BlKSByZXR1cm47XG4gICAgICAgICAgICAgIGNvbnN0IHZhbHVlID0gdGhpcy5pbnB1dC5yYXcuY2FsbCh0aGlzKTtcbiAgICAgICAgICAgICAgaWYgKHZhbHVlID09IFwiXCIgfHwgdmFsdWUuY2hhckNvZGVBdCgwKSA9PSA4MjAzKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc2V0dGluZ3MuYmFja3NwYWNlID09PSB0cnVlKSB0aGlzLnJlbW92ZVRhZ3MoKTtlbHNlIGlmICh0aGlzLnNldHRpbmdzLmJhY2tzcGFjZSA9PSAnZWRpdCcpIHNldFRpbWVvdXQodGhpcy5lZGl0VGFnLmJpbmQodGhpcyksIDApO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBvbk1vdXNlT3ZlcihlKSB7XG4gICAgICAgIHZhciBkZEl0ZW0gPSBlLnRhcmdldC5jbG9zZXN0KHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1TZWxlY3Rvcik7XG4gICAgICAgIC8vIGV2ZW50IGRlbGVnYXRpb24gY2hlY2tcbiAgICAgICAgZGRJdGVtICYmIHRoaXMuZHJvcGRvd24uaGlnaGxpZ2h0T3B0aW9uKGRkSXRlbSk7XG4gICAgICB9LFxuICAgICAgb25Nb3VzZUxlYXZlKGUpIHtcbiAgICAgICAgLy8gZGUtaGlnaGxpZ2h0IGFueSBwcmV2aW91c2x5IGhpZ2hsaWdodGVkIG9wdGlvblxuICAgICAgICB0aGlzLmRyb3Bkb3duLmhpZ2hsaWdodE9wdGlvbigpO1xuICAgICAgfSxcbiAgICAgIG9uQ2xpY2soZSkge1xuICAgICAgICBpZiAoZS5idXR0b24gIT0gMCB8fCBlLnRhcmdldCA9PSB0aGlzLkRPTS5kcm9wZG93biB8fCBlLnRhcmdldCA9PSB0aGlzLkRPTS5kcm9wZG93bi5jb250ZW50KSByZXR1cm47IC8vIGFsbG93IG9ubHkgbW91c2UgbGVmdC1jbGlja3NcblxuICAgICAgICB2YXIgc2VsZWN0ZWRFbG0gPSBlLnRhcmdldC5jbG9zZXN0KHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1TZWxlY3RvciksXG4gICAgICAgICAgc2VsZWN0ZWRFbG1EYXRhID0gdGhpcy5kcm9wZG93bi5nZXRTdWdnZXN0aW9uRGF0YUJ5Tm9kZShzZWxlY3RlZEVsbSk7XG5cbiAgICAgICAgLy8gdGVtcG9yYXJ5IHNldCB0aGUgXCJhY3Rpb25zXCIgc3RhdGUgdG8gaW5kaWNhdGUgdG8gdGhlIG1haW4gXCJibHVyXCIgZXZlbnQgaXQgc2hvdWxkbid0IHJ1blxuICAgICAgICB0aGlzLnN0YXRlLmFjdGlvbnMuc2VsZWN0T3B0aW9uID0gdHJ1ZTtcbiAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnN0YXRlLmFjdGlvbnMuc2VsZWN0T3B0aW9uID0gZmFsc2UsIDUwKTtcbiAgICAgICAgdGhpcy5zZXR0aW5ncy5ob29rcy5zdWdnZXN0aW9uQ2xpY2soZSwge1xuICAgICAgICAgIHRhZ2lmeTogdGhpcyxcbiAgICAgICAgICB0YWdEYXRhOiBzZWxlY3RlZEVsbURhdGEsXG4gICAgICAgICAgc3VnZ2VzdGlvbkVsbTogc2VsZWN0ZWRFbG1cbiAgICAgICAgfSkudGhlbigoKSA9PiB7XG4gICAgICAgICAgaWYgKHNlbGVjdGVkRWxtKSB0aGlzLmRyb3Bkb3duLnNlbGVjdE9wdGlvbihzZWxlY3RlZEVsbSwgZSk7ZWxzZSB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICAgICAgfSkuY2F0Y2goZXJyID0+IGNvbnNvbGUud2FybihlcnIpKTtcbiAgICAgIH0sXG4gICAgICBvblNjcm9sbChlKSB7XG4gICAgICAgIHZhciBlbG0gPSBlLnRhcmdldCxcbiAgICAgICAgICBwb3MgPSBlbG0uc2Nyb2xsVG9wIC8gKGVsbS5zY3JvbGxIZWlnaHQgLSBlbG0ucGFyZW50Tm9kZS5jbGllbnRIZWlnaHQpICogMTAwO1xuICAgICAgICB0aGlzLnRyaWdnZXIoXCJkcm9wZG93bjpzY3JvbGxcIiwge1xuICAgICAgICAgIHBlcmNlbnRhZ2U6IE1hdGgucm91bmQocG9zKVxuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIC8qKlxyXG4gICAqIEdpdmVuIGEgc3VnZ2VzdGlvbi1pdGVtLCByZXR1cm4gdGhlIGRhdGEgYXNzb2NpYXRlZCB3aXRoIGl0XHJcbiAgICogQHBhcmFtIHtIVE1MRWxlbWVudH0gdGFnRWxtXHJcbiAgICogQHJldHVybnMgT2JqZWN0XHJcbiAgICovXG4gIGdldFN1Z2dlc3Rpb25EYXRhQnlOb2RlKHRhZ0VsbSkge1xuICAgIHZhciB2YWx1ZSA9IHRhZ0VsbSAmJiB0YWdFbG0uZ2V0QXR0cmlidXRlKCd2YWx1ZScpO1xuICAgIHJldHVybiB0aGlzLnN1Z2dlc3RlZExpc3RJdGVtcy5maW5kKGl0ZW0gPT4gaXRlbS52YWx1ZSA9PSB2YWx1ZSkgfHwgbnVsbDtcbiAgfSxcbiAgZ2V0TmV4dE9yUHJldk9wdGlvbihzZWxlY3RlZCkge1xuICAgIGxldCBuZXh0ID0gYXJndW1lbnRzLmxlbmd0aCA+IDEgJiYgYXJndW1lbnRzWzFdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMV0gOiB0cnVlO1xuICAgIHZhciBkcm9wZG93bkl0ZW1zID0gdGhpcy5kcm9wZG93bi5nZXRBbGxTdWdnZXN0aW9uc1JlZnMoKSxcbiAgICAgIHNlbGVjdGVkSWR4ID0gZHJvcGRvd25JdGVtcy5maW5kSW5kZXgoaXRlbSA9PiBpdGVtID09PSBzZWxlY3RlZCk7XG4gICAgcmV0dXJuIG5leHQgPyBkcm9wZG93bkl0ZW1zW3NlbGVjdGVkSWR4ICsgMV0gOiBkcm9wZG93bkl0ZW1zW3NlbGVjdGVkSWR4IC0gMV07XG4gIH0sXG4gIC8qKlxyXG4gICAqIG1hcmsgdGhlIGN1cnJlbnRseSBhY3RpdmUgc3VnZ2VzdGlvbiBvcHRpb25cclxuICAgKiBAcGFyYW0ge09iamVjdH0gIGVsbSAgICAgICAgICAgIG9wdGlvbiBET00gbm9kZVxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gYWRqdXN0U2Nyb2xsICAgd2hlbiBuYXZpZ2F0aW9uIHdpdGgga2V5Ym9hcmQgYXJyb3dzICh1cC9kb3duKSwgYXV0LXNjcm9sbCB0byBhbHdheXMgc2hvdyB0aGUgaGlnaGxpZ2h0ZWQgZWxlbWVudFxyXG4gICAqL1xuICBoaWdobGlnaHRPcHRpb24oZWxtLCBhZGp1c3RTY3JvbGwpIHtcbiAgICB2YXIgY2xhc3NOYW1lID0gdGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLmRyb3Bkb3duSXRlbUFjdGl2ZSxcbiAgICAgIGl0ZW1EYXRhO1xuXG4gICAgLy8gZm9jdXMgY2FzdWVzIGEgYnVnIGluIEZpcmVmb3ggd2l0aCB0aGUgcGxhY2Vob2xkZXIgYmVlbiBzaG93biBvbiB0aGUgaW5wdXQgZWxlbWVudFxuICAgIC8vIGlmKCB0aGlzLnNldHRpbmdzLmRyb3Bkb3duLnBvc2l0aW9uICE9ICdtYW51YWwnIClcbiAgICAvLyAgICAgZWxtLmZvY3VzKCk7XG5cbiAgICBpZiAodGhpcy5zdGF0ZS5kZEl0ZW1FbG0pIHtcbiAgICAgIHRoaXMuc3RhdGUuZGRJdGVtRWxtLmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lKTtcbiAgICAgIHRoaXMuc3RhdGUuZGRJdGVtRWxtLnJlbW92ZUF0dHJpYnV0ZShcImFyaWEtc2VsZWN0ZWRcIik7XG4gICAgfVxuICAgIGlmICghZWxtKSB7XG4gICAgICB0aGlzLnN0YXRlLmRkSXRlbURhdGEgPSBudWxsO1xuICAgICAgdGhpcy5zdGF0ZS5kZEl0ZW1FbG0gPSBudWxsO1xuICAgICAgdGhpcy5pbnB1dC5hdXRvY29tcGxldGUuc3VnZ2VzdC5jYWxsKHRoaXMpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpdGVtRGF0YSA9IHRoaXMuZHJvcGRvd24uZ2V0U3VnZ2VzdGlvbkRhdGFCeU5vZGUoZWxtKTtcbiAgICB0aGlzLnN0YXRlLmRkSXRlbURhdGEgPSBpdGVtRGF0YTtcbiAgICB0aGlzLnN0YXRlLmRkSXRlbUVsbSA9IGVsbTtcblxuICAgIC8vIHRoaXMuRE9NLmRyb3Bkb3duLnF1ZXJ5U2VsZWN0b3JBbGwoXCIuXCIgKyB0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMuZHJvcGRvd25JdGVtQWN0aXZlKS5mb3JFYWNoKGFjdGl2ZUVsbSA9PiBhY3RpdmVFbG0uY2xhc3NMaXN0LnJlbW92ZShjbGFzc05hbWUpKTtcbiAgICBlbG0uY2xhc3NMaXN0LmFkZChjbGFzc05hbWUpO1xuICAgIGVsbS5zZXRBdHRyaWJ1dGUoXCJhcmlhLXNlbGVjdGVkXCIsIHRydWUpO1xuICAgIGlmIChhZGp1c3RTY3JvbGwpIGVsbS5wYXJlbnROb2RlLnNjcm9sbFRvcCA9IGVsbS5jbGllbnRIZWlnaHQgKyBlbG0ub2Zmc2V0VG9wIC0gZWxtLnBhcmVudE5vZGUuY2xpZW50SGVpZ2h0O1xuXG4gICAgLy8gVHJ5IHRvIGF1dG9jb21wbGV0ZSB0aGUgdHlwZWQgdmFsdWUgd2l0aCB0aGUgY3VycmVudGx5IGhpZ2hsaWdodGVkIGRyb3Bkb3duIGl0ZW1cbiAgICBpZiAodGhpcy5zZXR0aW5ncy5hdXRvQ29tcGxldGUpIHtcbiAgICAgIHRoaXMuaW5wdXQuYXV0b2NvbXBsZXRlLnN1Z2dlc3QuY2FsbCh0aGlzLCBpdGVtRGF0YSk7XG4gICAgICB0aGlzLmRyb3Bkb3duLnBvc2l0aW9uKCk7IC8vIHN1Z2dlc3Rpb25zIG1pZ2h0IGFsdGVyIHRoZSBoZWlnaHQgb2YgdGhlIHRhZ2lmeSB3cmFwcGVyIGJlY2F1c2Ugb2YgdW5rb3duIHN1Z2dlc3RlZCB0ZXJtIGxlbmd0aCB0aGF0IGNvdWxkIGRyb3AgdG8gdGhlIG5leHQgbGluZVxuICAgIH1cbiAgfSxcblxuICAvKipcclxuICAgKiBDcmVhdGUgYSB0YWcgZnJvbSB0aGUgY3VycmVudGx5IGFjdGl2ZSBzdWdnZXN0aW9uIG9wdGlvblxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBlbG0gIERPTSBub2RlIHRvIHNlbGVjdFxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBldmVudCBUaGUgb3JpZ2luYWwgQ2xpY2sgZXZlbnQsIGlmIGF2YWlsYWJsZSAoc2luY2Uga2V5Ym9hcmQgRU5URVIga2V5IGFsc28gdHJpZ2dlcnMgdGhpcyBtZXRob2QpXHJcbiAgICovXG4gIHNlbGVjdE9wdGlvbihlbG0sIGV2ZW50KSB7XG4gICAgdmFyIF90aGlzJHNldHRpbmdzJGRyb3BkbyA9IHRoaXMuc2V0dGluZ3MuZHJvcGRvd24sXG4gICAgICBjbGVhck9uU2VsZWN0ID0gX3RoaXMkc2V0dGluZ3MkZHJvcGRvLmNsZWFyT25TZWxlY3QsXG4gICAgICBjbG9zZU9uU2VsZWN0ID0gX3RoaXMkc2V0dGluZ3MkZHJvcGRvLmNsb3NlT25TZWxlY3Q7XG4gICAgaWYgKCFlbG0pIHtcbiAgICAgIHRoaXMuYWRkVGFncyh0aGlzLnN0YXRlLmlucHV0VGV4dCwgdHJ1ZSk7XG4gICAgICBjbG9zZU9uU2VsZWN0ICYmIHRoaXMuZHJvcGRvd24uaGlkZSgpO1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBldmVudCA9IGV2ZW50IHx8IHt9O1xuXG4gICAgLy8gaWYgaW4gZWRpdC1tb2RlLCBkbyBub3QgY29udGludWUgYnV0IGluc3RlYWQgcmVwbGFjZSB0aGUgdGFnJ3MgdGV4dC5cbiAgICAvLyB0aGUgc2NlbmFyaW8gaXMgdGhhdCBcImFkZFRhZ3NcIiB3YXMgY2FsbGVkIGZyb20gYSBkcm9wZG93biBzdWdnZXN0ZWQgb3B0aW9uIHNlbGVjdGVkIHdoaWxlIGVkaXRpbmdcblxuICAgIHZhciB2YWx1ZSA9IGVsbS5nZXRBdHRyaWJ1dGUoJ3ZhbHVlJyksXG4gICAgICBpc05vTWF0Y2ggPSB2YWx1ZSA9PSAnbm9NYXRjaCcsXG4gICAgICB0YWdEYXRhID0gdGhpcy5zdWdnZXN0ZWRMaXN0SXRlbXMuZmluZChpdGVtID0+IChpdGVtLnZhbHVlID8/IGl0ZW0pID09IHZhbHVlKTtcblxuICAgIC8vIFRoZSBiZWxvdyBldmVudCBtdXN0IGJlIHRyaWdnZXJlZCwgcmVnYXJkbGVzcyBvZiBhbnl0aGluZyBlbHNlIHdoaWNoIG1pZ2h0IGdvIHdyb25nXG4gICAgdGhpcy50cmlnZ2VyKCdkcm9wZG93bjpzZWxlY3QnLCB7XG4gICAgICBkYXRhOiB0YWdEYXRhLFxuICAgICAgZWxtLFxuICAgICAgZXZlbnRcbiAgICB9KTtcbiAgICBpZiAoIXZhbHVlIHx8ICF0YWdEYXRhICYmICFpc05vTWF0Y2gpIHtcbiAgICAgIGNsb3NlT25TZWxlY3QgJiYgc2V0VGltZW91dCh0aGlzLmRyb3Bkb3duLmhpZGUuYmluZCh0aGlzKSk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmcpIHtcbiAgICAgIC8vIG5vcm1hbGl6aW5nIHZhbHVlLCBiZWNhdXNlIFwidGFnRGF0YVwiIG1pZ2h0IGJlIGEgc3RyaW5nLCBhbmQgdGhlcmVmb3JlIHdpbGwgbm90IGJlIGFibGUgdG8gZXh0ZW5kIHRoZSBvYmplY3RcbiAgICAgIHRoaXMub25FZGl0VGFnRG9uZShudWxsLCBleHRlbmQoe1xuICAgICAgICBfX2lzVmFsaWQ6IHRydWVcbiAgICAgIH0sIHRoaXMubm9ybWFsaXplVGFncyhbdGFnRGF0YV0pWzBdKSk7XG4gICAgfVxuICAgIC8vIFRhZ2lmeSBpbnN0YW5jZXMgc2hvdWxkIHJlLWZvY3VzIHRvIHRoZSBpbnB1dCBlbGVtZW50IG9uY2UgYW4gb3B0aW9uIHdhcyBzZWxlY3RlZCwgdG8gYWxsb3cgY29udGludW91cyB0eXBpbmdcbiAgICBlbHNlIHtcbiAgICAgIHRoaXNbdGhpcy5zZXR0aW5ncy5tb2RlID09ICdtaXgnID8gXCJhZGRNaXhUYWdzXCIgOiBcImFkZFRhZ3NcIl0oW3RhZ0RhdGEgfHwgdGhpcy5pbnB1dC5yYXcuY2FsbCh0aGlzKV0sIGNsZWFyT25TZWxlY3QpO1xuICAgIH1cblxuICAgIC8vIHRvZG86IGNvbnNpZGVyIG5vdCBkb2luZyB0aGlzIG9uIG1peC1tb2RlXG4gICAgaWYgKCF0aGlzLkRPTS5pbnB1dC5wYXJlbnROb2RlKSByZXR1cm47XG4gICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLkRPTS5pbnB1dC5mb2N1cygpO1xuICAgICAgdGhpcy50b2dnbGVGb2N1c0NsYXNzKHRydWUpO1xuICAgIH0pO1xuICAgIGNsb3NlT25TZWxlY3QgJiYgc2V0VGltZW91dCh0aGlzLmRyb3Bkb3duLmhpZGUuYmluZCh0aGlzKSk7XG5cbiAgICAvLyBoaWRlIHNlbGVjdGVkIHN1Z2dlc3Rpb25cbiAgICBlbG0uYWRkRXZlbnRMaXN0ZW5lcigndHJhbnNpdGlvbmVuZCcsICgpID0+IHtcbiAgICAgIHRoaXMuZHJvcGRvd24uZmlsbEhlYWRlckZvb3RlcigpO1xuICAgICAgc2V0VGltZW91dCgoKSA9PiBlbG0ucmVtb3ZlKCksIDEwMCk7XG4gICAgfSwge1xuICAgICAgb25jZTogdHJ1ZVxuICAgIH0pO1xuICAgIGVsbS5jbGFzc0xpc3QuYWRkKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkl0ZW1IaWRkZW4pO1xuICB9LFxuICAvLyBhZGRzIGFsbCB0aGUgc3VnZ2VzdGVkIGl0ZW1zLCBpbmNsdWRpbmcgdGhlIG9uZXMgd2hpY2ggYXJlIG5vdCBjdXJyZW50bHkgcmVuZGVyZWQsXG4gIC8vIHVubGVzcyBzcGVjaWZpZWQgb3RoZXJ3aXNlIChieSB0aGUgXCJvbmx5UmVuZGVyZWRcIiBhcmd1bWVudClcbiAgc2VsZWN0QWxsKG9ubHlSZW5kZXJlZCkge1xuICAgIC8vIGhhdmluZyBzdWdnZXN0ZWRMaXN0SXRlbXMgd2l0aCBpdGVtcyBtZXNzZXMgd2l0aCBcIm5vcm1hbGl6ZVRhZ3NcIiB3aGVuIHdhbnRpbmdcbiAgICAvLyB0byBhZGQgYWxsIHRhZ3NcbiAgICB0aGlzLnN1Z2dlc3RlZExpc3RJdGVtcy5sZW5ndGggPSAwO1xuICAgIHRoaXMuZHJvcGRvd24uaGlkZSgpO1xuICAgIHRoaXMuZHJvcGRvd24uZmlsdGVyTGlzdEl0ZW1zKCcnKTtcbiAgICB2YXIgdGFnc1RvQWRkID0gdGhpcy5kcm9wZG93bi5maWx0ZXJMaXN0SXRlbXMoJycpO1xuICAgIGlmICghb25seVJlbmRlcmVkKSB0YWdzVG9BZGQgPSB0aGlzLnN0YXRlLmRyb3Bkb3duLnN1Z2dlc3Rpb25zO1xuXG4gICAgLy8gc29tZSB3aGl0ZWxpc3QgaXRlbXMgbWlnaHQgaGF2ZSBhbHJlYWR5IGJlZW4gYWRkZWQgYXMgdGFncyBzbyB3aGVuIGFkZGluZ3MgYWxsIG9mIHRoZW0sXG4gICAgLy8gc2tpcCBhZGRpbmcgYWxyZWFkeS1hZGRlZCBvbmVzLCBzbyBiZXN0IHRvIHVzZSBcImZpbHRlckxpc3RJdGVtc1wiIG1ldGhvZCBvdmVyIFwic2V0dGluZ3Mud2hpdGVsaXN0XCJcbiAgICB0aGlzLmFkZFRhZ3ModGFnc1RvQWRkLCB0cnVlKTtcbiAgICByZXR1cm4gdGhpcztcbiAgfSxcbiAgLyoqXHJcbiAgICogcmV0dXJucyBhbiBIVE1MIHN0cmluZyBvZiB0aGUgc3VnZ2VzdGlvbnMnIGxpc3QgaXRlbXNcclxuICAgKiBAcGFyYW0ge1N0cmluZ30gdmFsdWUgc3RyaW5nIHRvIGZpbHRlciB0aGUgd2hpdGVsaXN0IGJ5XHJcbiAgICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgXCJleGFjdFwiIC0gZm9yIGV4YWN0IGNvbXBsZXRlIG1hdGNoXHJcbiAgICogQHJldHVybiB7QXJyYXl9IGxpc3Qgb2YgZmlsdGVyZWQgd2hpdGVsaXN0IGl0ZW1zIGFjY29yZGluZyB0byB0aGUgc2V0dGluZ3MgcHJvdmlkZWQgYW5kIGN1cnJlbnQgdmFsdWVcclxuICAgKi9cbiAgZmlsdGVyTGlzdEl0ZW1zKHZhbHVlLCBvcHRpb25zKSB7XG4gICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgIF9zZCA9IF9zLmRyb3Bkb3duLFxuICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge30sXG4gICAgICBsaXN0ID0gW10sXG4gICAgICBleGFjdE1hdGNoZXNMaXN0ID0gW10sXG4gICAgICB3aGl0ZWxpc3QgPSBfcy53aGl0ZWxpc3QsXG4gICAgICBzdWdnZXN0aW9uc0NvdW50ID0gX3NkLm1heEl0ZW1zID49IDAgPyBfc2QubWF4SXRlbXMgOiBJbmZpbml0eSxcbiAgICAgIHNlYXJjaEtleXMgPSBfc2Quc2VhcmNoS2V5cyxcbiAgICAgIHdoaXRlbGlzdEl0ZW0sXG4gICAgICB2YWx1ZUlzSW5XaGl0ZWxpc3QsXG4gICAgICBzZWFyY2hCeSxcbiAgICAgIGlzRHVwbGljYXRlLFxuICAgICAgbmlkZGxlLFxuICAgICAgaSA9IDA7XG4gICAgdmFsdWUgPSBfcy5tb2RlID09ICdzZWxlY3QnICYmIHRoaXMudmFsdWUubGVuZ3RoICYmIHRoaXMudmFsdWVbMF1bX3MudGFnVGV4dFByb3BdID09IHZhbHVlID8gJycgLy8gZG8gbm90IGZpbHRlciBpZiB0aGUgdGFnLCB3aGljaCBpcyBhbHJlYWR5IHNlbGVjZXRkIGluIFwic2VsZWN0XCIgbW9kZSwgaXMgdGhlIHNhbWUgYXMgdGhlIHR5cGVkIHRleHRcbiAgICA6IHZhbHVlO1xuICAgIGlmICghdmFsdWUgfHwgIXNlYXJjaEtleXMubGVuZ3RoKSB7XG4gICAgICBsaXN0ID0gX3NkLmluY2x1ZGVTZWxlY3RlZFRhZ3MgPyB3aGl0ZWxpc3QgOiB3aGl0ZWxpc3QuZmlsdGVyKGl0ZW0gPT4gIXRoaXMuaXNUYWdEdXBsaWNhdGUoaXNPYmplY3QoaXRlbSkgPyBpdGVtLnZhbHVlIDogaXRlbSkpOyAvLyBkb24ndCBpbmNsdWRlIHRhZ3Mgd2hpY2ggaGF2ZSBhbHJlYWR5IGJlZW4gYWRkZWQuXG5cbiAgICAgIHRoaXMuc3RhdGUuZHJvcGRvd24uc3VnZ2VzdGlvbnMgPSBsaXN0O1xuICAgICAgcmV0dXJuIGxpc3Quc2xpY2UoMCwgc3VnZ2VzdGlvbnNDb3VudCk7IC8vIHJlc3BlY3QgXCJtYXhJdGVtc1wiIGRyb3Bkb3duIHNldHRpbmdcbiAgICB9XG5cbiAgICBuaWRkbGUgPSBfc2QuY2FzZVNlbnNpdGl2ZSA/IFwiXCIgKyB2YWx1ZSA6IChcIlwiICsgdmFsdWUpLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAvLyBjaGVja3MgaWYgQUxMIG9mIHRoZSB3b3JkcyBpbiB0aGUgc2VhcmNoIHF1ZXJ5IGV4aXN0cyBpbiB0aGUgY3VycmVudCB3aGl0ZWxpc3QgaXRlbSwgcmVnYXJkbGVzcyBvZiB0aGVpciBvcmRlclxuICAgIGZ1bmN0aW9uIHN0cmluZ0hhc0FsbChzLCBxdWVyeSkge1xuICAgICAgcmV0dXJuIHF1ZXJ5LnRvTG93ZXJDYXNlKCkuc3BsaXQoJyAnKS5ldmVyeShxID0+IHMuaW5jbHVkZXMocS50b0xvd2VyQ2FzZSgpKSk7XG4gICAgfVxuICAgIGZvciAoOyBpIDwgd2hpdGVsaXN0Lmxlbmd0aDsgaSsrKSB7XG4gICAgICBsZXQgc3RhcnRzV2l0aE1hdGNoLCBleGFjdE1hdGNoO1xuICAgICAgd2hpdGVsaXN0SXRlbSA9IHdoaXRlbGlzdFtpXSBpbnN0YW5jZW9mIE9iamVjdCA/IHdoaXRlbGlzdFtpXSA6IHtcbiAgICAgICAgdmFsdWU6IHdoaXRlbGlzdFtpXVxuICAgICAgfTsgLy9ub3JtYWxpemUgdmFsdWUgYXMgYW4gT2JqZWN0XG5cbiAgICAgIGxldCBpdGVtV2l0aG91dFNlYXJjaEtleXMgPSAhT2JqZWN0LmtleXMod2hpdGVsaXN0SXRlbSkuc29tZShrID0+IHNlYXJjaEtleXMuaW5jbHVkZXMoaykpLFxuICAgICAgICBfc2VhcmNoS2V5cyA9IGl0ZW1XaXRob3V0U2VhcmNoS2V5cyA/IFtcInZhbHVlXCJdIDogc2VhcmNoS2V5cztcbiAgICAgIGlmIChfc2QuZnV6enlTZWFyY2ggJiYgIW9wdGlvbnMuZXhhY3QpIHtcbiAgICAgICAgc2VhcmNoQnkgPSBfc2VhcmNoS2V5cy5yZWR1Y2UoKHZhbHVlcywgaykgPT4gdmFsdWVzICsgXCIgXCIgKyAod2hpdGVsaXN0SXRlbVtrXSB8fCBcIlwiKSwgXCJcIikudG9Mb3dlckNhc2UoKS50cmltKCk7XG4gICAgICAgIGlmIChfc2QuYWNjZW50ZWRTZWFyY2gpIHtcbiAgICAgICAgICBzZWFyY2hCeSA9IHVuYWNjZW50KHNlYXJjaEJ5KTtcbiAgICAgICAgICBuaWRkbGUgPSB1bmFjY2VudChuaWRkbGUpO1xuICAgICAgICB9XG4gICAgICAgIHN0YXJ0c1dpdGhNYXRjaCA9IHNlYXJjaEJ5LmluZGV4T2YobmlkZGxlKSA9PSAwO1xuICAgICAgICBleGFjdE1hdGNoID0gc2VhcmNoQnkgPT09IG5pZGRsZTtcbiAgICAgICAgdmFsdWVJc0luV2hpdGVsaXN0ID0gc3RyaW5nSGFzQWxsKHNlYXJjaEJ5LCBuaWRkbGUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RhcnRzV2l0aE1hdGNoID0gdHJ1ZTtcbiAgICAgICAgdmFsdWVJc0luV2hpdGVsaXN0ID0gX3NlYXJjaEtleXMuc29tZShrID0+IHtcbiAgICAgICAgICB2YXIgdiA9ICcnICsgKHdoaXRlbGlzdEl0ZW1ba10gfHwgJycpOyAvLyBpZiBrZXkgZXhpc3RzLCBjYXN0IHRvIHR5cGUgU3RyaW5nXG5cbiAgICAgICAgICBpZiAoX3NkLmFjY2VudGVkU2VhcmNoKSB7XG4gICAgICAgICAgICB2ID0gdW5hY2NlbnQodik7XG4gICAgICAgICAgICBuaWRkbGUgPSB1bmFjY2VudChuaWRkbGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoIV9zZC5jYXNlU2Vuc2l0aXZlKSB2ID0gdi50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgIGV4YWN0TWF0Y2ggPSB2ID09PSBuaWRkbGU7XG4gICAgICAgICAgcmV0dXJuIG9wdGlvbnMuZXhhY3QgPyB2ID09PSBuaWRkbGUgOiB2LmluZGV4T2YobmlkZGxlKSA9PSAwO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIGlzRHVwbGljYXRlID0gIV9zZC5pbmNsdWRlU2VsZWN0ZWRUYWdzICYmIHRoaXMuaXNUYWdEdXBsaWNhdGUoaXNPYmplY3Qod2hpdGVsaXN0SXRlbSkgPyB3aGl0ZWxpc3RJdGVtLnZhbHVlIDogd2hpdGVsaXN0SXRlbSk7XG5cbiAgICAgIC8vIG1hdGNoIGZvciB0aGUgdmFsdWUgd2l0aGluIGVhY2ggXCJ3aGl0ZWxpc3RcIiBpdGVtXG4gICAgICBpZiAodmFsdWVJc0luV2hpdGVsaXN0ICYmICFpc0R1cGxpY2F0ZSkgaWYgKGV4YWN0TWF0Y2ggJiYgc3RhcnRzV2l0aE1hdGNoKSBleGFjdE1hdGNoZXNMaXN0LnB1c2god2hpdGVsaXN0SXRlbSk7ZWxzZSBpZiAoX3NkLnNvcnRieSA9PSAnc3RhcnRzV2l0aCcgJiYgc3RhcnRzV2l0aE1hdGNoKSBsaXN0LnVuc2hpZnQod2hpdGVsaXN0SXRlbSk7ZWxzZSBsaXN0LnB1c2god2hpdGVsaXN0SXRlbSk7XG4gICAgfVxuICAgIHRoaXMuc3RhdGUuZHJvcGRvd24uc3VnZ2VzdGlvbnMgPSBleGFjdE1hdGNoZXNMaXN0LmNvbmNhdChsaXN0KTtcblxuICAgIC8vIGN1c3RvbSBzb3J0aW5nIGZ1bmN0aW9uXG4gICAgcmV0dXJuIHR5cGVvZiBfc2Quc29ydGJ5ID09ICdmdW5jdGlvbicgPyBfc2Quc29ydGJ5KGV4YWN0TWF0Y2hlc0xpc3QuY29uY2F0KGxpc3QpLCBuaWRkbGUpIDogZXhhY3RNYXRjaGVzTGlzdC5jb25jYXQobGlzdCkuc2xpY2UoMCwgc3VnZ2VzdGlvbnNDb3VudCk7XG4gIH0sXG4gIC8qKlxyXG4gICAqIFJldHVybnMgdGhlIGZpbmFsIHZhbHVlIG9mIGEgdGFnIGRhdGEgKG9iamVjdCkgd2l0aCByZWdhcmRzIHRvIHRoZSBcIm1hcFZhbHVlVG9cIiBkcm9wZG93biBzZXR0aW5nXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0RhdGFcclxuICAgKiBAcmV0dXJuc1xyXG4gICAqL1xuICBnZXRNYXBwZWRWYWx1ZSh0YWdEYXRhKSB7XG4gICAgdmFyIG1hcFZhbHVlVG8gPSB0aGlzLnNldHRpbmdzLmRyb3Bkb3duLm1hcFZhbHVlVG8sXG4gICAgICB2YWx1ZSA9IG1hcFZhbHVlVG8gPyB0eXBlb2YgbWFwVmFsdWVUbyA9PSAnZnVuY3Rpb24nID8gbWFwVmFsdWVUbyh0YWdEYXRhKSA6IHRhZ0RhdGFbbWFwVmFsdWVUb10gfHwgdGFnRGF0YS52YWx1ZSA6IHRhZ0RhdGEudmFsdWU7XG4gICAgcmV0dXJuIHZhbHVlO1xuICB9LFxuICAvKipcclxuICAgKiBDcmVhdGVzIHRoZSBkcm9wZG93biBpdGVtcycgSFRNTFxyXG4gICAqIEBwYXJhbSAge0FycmF5fSBzdWdlZ3N0aW9uc0xpc3QgIFtBcnJheSBvZiBPYmplY3RzXVxyXG4gICAqIEByZXR1cm4ge1N0cmluZ31cclxuICAgKi9cbiAgY3JlYXRlTGlzdEhUTUwoc3VnZWdzdGlvbnNMaXN0KSB7XG4gICAgcmV0dXJuIGV4dGVuZChbXSwgc3VnZWdzdGlvbnNMaXN0KS5tYXAoKHN1Z2dlc3Rpb24sIGlkeCkgPT4ge1xuICAgICAgaWYgKHR5cGVvZiBzdWdnZXN0aW9uID09ICdzdHJpbmcnIHx8IHR5cGVvZiBzdWdnZXN0aW9uID09ICdudW1iZXInKSBzdWdnZXN0aW9uID0ge1xuICAgICAgICB2YWx1ZTogc3VnZ2VzdGlvblxuICAgICAgfTtcbiAgICAgIHZhciBtYXBwZWRWYWx1ZSA9IHRoaXMuZHJvcGRvd24uZ2V0TWFwcGVkVmFsdWUoc3VnZ2VzdGlvbik7XG4gICAgICBtYXBwZWRWYWx1ZSA9IHR5cGVvZiBtYXBwZWRWYWx1ZSA9PSAnc3RyaW5nJyA/IGVzY2FwZUhUTUwobWFwcGVkVmFsdWUpIDogbWFwcGVkVmFsdWU7XG4gICAgICByZXR1cm4gdGhpcy5zZXR0aW5ncy50ZW1wbGF0ZXMuZHJvcGRvd25JdGVtLmFwcGx5KHRoaXMsIFtfb2JqZWN0U3ByZWFkMihfb2JqZWN0U3ByZWFkMih7fSwgc3VnZ2VzdGlvbiksIHt9LCB7XG4gICAgICAgIG1hcHBlZFZhbHVlXG4gICAgICB9KSwgdGhpc10pO1xuICAgIH0pLmpvaW4oXCJcIik7XG4gIH1cbn07XG5cbmNvbnN0IFZFUlNJT04gPSAxOyAvLyBjdXJyZW50IHZlcnNpb24gb2YgcGVyc2lzdGVkIGRhdGEuIGlmIGNvZGUgY2hhbmdlIGJyZWFrcyBwZXJzaXN0ZWQgZGF0YSwgdmVyaXNvbiBudW1iZXIgc2hvdWxkIGJlIGJ1bXBlZC5cbmNvbnN0IFNUT1JFX0tFWSA9ICdAeWFpcmVvL3RhZ2lmeS8nO1xuY29uc3QgZ2V0UGVyc2lzdGVkRGF0YSA9IGlkID0+IGtleSA9PiB7XG4gIC8vIGlmIFwicGVyc2lzdFwiIGlzIFwiZmFsc2VcIiwgZG8gbm90IHNhdmUgdG8gbG9jYWxzdG9yYWdlXG4gIGxldCBjdXN0b21LZXkgPSAnLycgKyBrZXksXG4gICAgcGVyc2lzdGVkRGF0YSxcbiAgICB2ZXJzaW9uTWF0Y2ggPSBsb2NhbFN0b3JhZ2UuZ2V0SXRlbShTVE9SRV9LRVkgKyBpZCArICcvdicsIFZFUlNJT04pID09IFZFUlNJT047XG4gIGlmICh2ZXJzaW9uTWF0Y2gpIHtcbiAgICB0cnkge1xuICAgICAgcGVyc2lzdGVkRGF0YSA9IEpTT04ucGFyc2UobG9jYWxTdG9yYWdlW1NUT1JFX0tFWSArIGlkICsgY3VzdG9tS2V5XSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7fVxuICB9XG4gIHJldHVybiBwZXJzaXN0ZWREYXRhO1xufTtcbmNvbnN0IHNldFBlcnNpc3RlZERhdGEgPSBpZCA9PiB7XG4gIGlmICghaWQpIHJldHVybiAoKSA9PiB7fTtcblxuICAvLyBmb3Igc3RvcmFnZSBpbnZhbGlkYXRpb25cbiAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oU1RPUkVfS0VZICsgaWQgKyAnL3YnLCBWRVJTSU9OKTtcbiAgcmV0dXJuIChkYXRhLCBrZXkpID0+IHtcbiAgICBsZXQgY3VzdG9tS2V5ID0gJy8nICsga2V5LFxuICAgICAgcGVyc2lzdGVkRGF0YSA9IEpTT04uc3RyaW5naWZ5KGRhdGEpO1xuICAgIGlmIChkYXRhICYmIGtleSkge1xuICAgICAgbG9jYWxTdG9yYWdlLnNldEl0ZW0oU1RPUkVfS0VZICsgaWQgKyBjdXN0b21LZXksIHBlcnNpc3RlZERhdGEpO1xuICAgICAgZGlzcGF0Y2hFdmVudChuZXcgRXZlbnQoJ3N0b3JhZ2UnKSk7XG4gICAgfVxuICB9O1xufTtcbmNvbnN0IGNsZWFyUGVyc2lzdGVkRGF0YSA9IGlkID0+IGtleSA9PiB7XG4gIGNvbnN0IGJhc2UgPSBTVE9SRV9LRVkgKyAnLycgKyBpZCArICcvJztcblxuICAvLyBkZWxldGUgc3BlY2lmaWMga2V5IGluIHRoZSBzdG9yYWdlXG4gIGlmIChrZXkpIGxvY2FsU3RvcmFnZS5yZW1vdmVJdGVtKGJhc2UgKyBrZXkpO1xuXG4gIC8vIGRlbGV0ZSBhbGwga2V5cyBpbiB0aGUgc3RvcmFnZSB3aXRoIGEgc3BlY2lmaWMgdGFnaWZ5IGlkXG4gIGVsc2Uge1xuICAgIGZvciAobGV0IGsgaW4gbG9jYWxTdG9yYWdlKSBpZiAoay5pbmNsdWRlcyhiYXNlKSkgbG9jYWxTdG9yYWdlLnJlbW92ZUl0ZW0oayk7XG4gIH1cbn07XG5cbnZhciBURVhUUyA9IHtcbiAgZW1wdHk6IFwiZW1wdHlcIixcbiAgZXhjZWVkOiBcIm51bWJlciBvZiB0YWdzIGV4Y2VlZGVkXCIsXG4gIHBhdHRlcm46IFwicGF0dGVybiBtaXNtYXRjaFwiLFxuICBkdXBsaWNhdGU6IFwiYWxyZWFkeSBleGlzdHNcIixcbiAgbm90QWxsb3dlZDogXCJub3QgYWxsb3dlZFwiXG59O1xuXG52YXIgdGVtcGxhdGVzID0ge1xuICAvKipcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RE9NIE9iamVjdH0gaW5wdXQgICAgIE9yaWdpbmFsIGlucHV0IERPbSBlbGVtZW50XHJcbiAgICogQHBhcmFtIHtPYmplY3R9ICAgICBzZXR0aW5ncyAgVGFnaWZ5IGluc3RhbmNlIHNldHRpbmdzIE9iamVjdFxyXG4gICAqL1xuICB3cmFwcGVyKGlucHV0LCBfcykge1xuICAgIHJldHVybiBgPHRhZ3MgY2xhc3M9XCIke19zLmNsYXNzTmFtZXMubmFtZXNwYWNlfSAke19zLm1vZGUgPyBgJHtfcy5jbGFzc05hbWVzW19zLm1vZGUgKyBcIk1vZGVcIl19YCA6IFwiXCJ9ICR7aW5wdXQuY2xhc3NOYW1lfVwiXG4gICAgICAgICAgICAgICAgICAgICR7X3MucmVhZG9ubHkgPyAncmVhZG9ubHknIDogJyd9XG4gICAgICAgICAgICAgICAgICAgICR7X3MuZGlzYWJsZWQgPyAnZGlzYWJsZWQnIDogJyd9XG4gICAgICAgICAgICAgICAgICAgICR7X3MucmVxdWlyZWQgPyAncmVxdWlyZWQnIDogJyd9XG4gICAgICAgICAgICAgICAgICAgICR7X3MubW9kZSA9PT0gJ3NlbGVjdCcgPyBcInNwZWxsY2hlY2s9J2ZhbHNlJ1wiIDogJyd9XG4gICAgICAgICAgICAgICAgICAgIHRhYkluZGV4PVwiLTFcIj5cbiAgICAgICAgICAgIDxzcGFuICR7IV9zLnJlYWRvbmx5ICYmIF9zLnVzZXJJbnB1dCA/ICdjb250ZW50ZWRpdGFibGUnIDogJyd9IHRhYkluZGV4PVwiMFwiIGRhdGEtcGxhY2Vob2xkZXI9XCIke19zLnBsYWNlaG9sZGVyIHx8ICcmIzgyMDM7J31cIiBhcmlhLXBsYWNlaG9sZGVyPVwiJHtfcy5wbGFjZWhvbGRlciB8fCAnJ31cIlxuICAgICAgICAgICAgICAgIGNsYXNzPVwiJHtfcy5jbGFzc05hbWVzLmlucHV0fVwiXG4gICAgICAgICAgICAgICAgcm9sZT1cInRleHRib3hcIlxuICAgICAgICAgICAgICAgIGFyaWEtYXV0b2NvbXBsZXRlPVwiYm90aFwiXG4gICAgICAgICAgICAgICAgYXJpYS1tdWx0aWxpbmU9XCIke19zLm1vZGUgPT0gJ21peCcgPyB0cnVlIDogZmFsc2V9XCI+PC9zcGFuPlxuICAgICAgICAgICAgICAgICYjODIwMztcbiAgICAgICAgPC90YWdzPmA7XG4gIH0sXG4gIHRhZyh0YWdEYXRhLCBfcmVmKSB7XG4gICAgbGV0IF9zID0gX3JlZi5zZXR0aW5ncztcbiAgICByZXR1cm4gYDx0YWcgdGl0bGU9XCIke3RhZ0RhdGEudGl0bGUgfHwgdGFnRGF0YS52YWx1ZX1cIlxuICAgICAgICAgICAgICAgICAgICBjb250ZW50ZWRpdGFibGU9J2ZhbHNlJ1xuICAgICAgICAgICAgICAgICAgICBzcGVsbGNoZWNrPSdmYWxzZSdcbiAgICAgICAgICAgICAgICAgICAgdGFiSW5kZXg9XCIke19zLmExMXkuZm9jdXNhYmxlVGFncyA/IDAgOiAtMX1cIlxuICAgICAgICAgICAgICAgICAgICBjbGFzcz1cIiR7X3MuY2xhc3NOYW1lcy50YWd9ICR7dGFnRGF0YS5jbGFzcyB8fCBcIlwifVwiXG4gICAgICAgICAgICAgICAgICAgICR7dGhpcy5nZXRBdHRyaWJ1dGVzKHRhZ0RhdGEpfT5cbiAgICAgICAgICAgIDx4IHRpdGxlPScnIGNsYXNzPVwiJHtfcy5jbGFzc05hbWVzLnRhZ1h9XCIgcm9sZT0nYnV0dG9uJyBhcmlhLWxhYmVsPSdyZW1vdmUgdGFnJz48L3g+XG4gICAgICAgICAgICA8ZGl2PlxuICAgICAgICAgICAgICAgIDxzcGFuIGNsYXNzPVwiJHtfcy5jbGFzc05hbWVzLnRhZ1RleHR9XCI+JHt0YWdEYXRhW19zLnRhZ1RleHRQcm9wXSB8fCB0YWdEYXRhLnZhbHVlfTwvc3Bhbj5cbiAgICAgICAgICAgIDwvZGl2PlxuICAgICAgICA8L3RhZz5gO1xuICB9LFxuICBkcm9wZG93bihzZXR0aW5ncykge1xuICAgIHZhciBfc2QgPSBzZXR0aW5ncy5kcm9wZG93bixcbiAgICAgIGlzTWFudWFsID0gX3NkLnBvc2l0aW9uID09ICdtYW51YWwnLFxuICAgICAgY2xhc3NOYW1lID0gYCR7c2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bn1gO1xuICAgIHJldHVybiBgPGRpdiBjbGFzcz1cIiR7aXNNYW51YWwgPyBcIlwiIDogY2xhc3NOYW1lfSAke19zZC5jbGFzc25hbWV9XCIgcm9sZT1cImxpc3Rib3hcIiBhcmlhLWxhYmVsbGVkYnk9XCJkcm9wZG93blwiPlxuICAgICAgICAgICAgICAgICAgICA8ZGl2IGRhdGEtc2VsZWN0b3I9J3RhZ2lmeS1zdWdnZXN0aW9ucy13cmFwcGVyJyBjbGFzcz1cIiR7c2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bldyYXBwZXJ9XCI+PC9kaXY+XG4gICAgICAgICAgICAgICAgPC9kaXY+YDtcbiAgfSxcbiAgZHJvcGRvd25Db250ZW50KEhUTUxDb250ZW50KSB7XG4gICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgIHN1Z2dlc3Rpb25zID0gdGhpcy5zdGF0ZS5kcm9wZG93bi5zdWdnZXN0aW9ucztcbiAgICByZXR1cm4gYFxuICAgICAgICAgICAgJHtfcy50ZW1wbGF0ZXMuZHJvcGRvd25IZWFkZXIuY2FsbCh0aGlzLCBzdWdnZXN0aW9ucyl9XG4gICAgICAgICAgICAke0hUTUxDb250ZW50fVxuICAgICAgICAgICAgJHtfcy50ZW1wbGF0ZXMuZHJvcGRvd25Gb290ZXIuY2FsbCh0aGlzLCBzdWdnZXN0aW9ucyl9XG4gICAgICAgIGA7XG4gIH0sXG4gIGRyb3Bkb3duSXRlbShpdGVtKSB7XG4gICAgcmV0dXJuIGA8ZGl2ICR7dGhpcy5nZXRBdHRyaWJ1dGVzKGl0ZW0pfVxuICAgICAgICAgICAgICAgICAgICBjbGFzcz0nJHt0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMuZHJvcGRvd25JdGVtfSAke2l0ZW0uY2xhc3MgPyBpdGVtLmNsYXNzIDogXCJcIn0nXG4gICAgICAgICAgICAgICAgICAgIHRhYmluZGV4PVwiMFwiXG4gICAgICAgICAgICAgICAgICAgIHJvbGU9XCJvcHRpb25cIj4ke2l0ZW0ubWFwcGVkVmFsdWUgfHwgaXRlbS52YWx1ZX08L2Rpdj5gO1xuICB9LFxuICAvKipcclxuICAgKiBAcGFyYW0ge0FycmF5fSBzdWdnZXN0aW9ucyBBbiBhcnJheSBvZiBhbGwgdGhlIG1hdGNoZWQgc3VnZ2VzdGVkIGl0ZW1zLCBpbmNsdWRpbmcgdGhvc2Ugd2hpY2ggd2VyZSBzbGljZWQgYXdheSBkdWUgdG8gdGhlIFwiZHJvcGRvd24ubWF4SXRlbXNcIiBzZXR0aW5nXHJcbiAgICovXG4gIGRyb3Bkb3duSGVhZGVyKHN1Z2dlc3Rpb25zKSB7XG4gICAgcmV0dXJuIGA8aGVhZGVyIGRhdGEtc2VsZWN0b3I9J3RhZ2lmeS1zdWdnZXN0aW9ucy1oZWFkZXInIGNsYXNzPVwiJHt0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMuZHJvcGRvd25IZWFkZXJ9XCI+PC9oZWFkZXI+YDtcbiAgfSxcbiAgZHJvcGRvd25Gb290ZXIoc3VnZ2VzdGlvbnMpIHtcbiAgICB2YXIgaGFzTW9yZSA9IHN1Z2dlc3Rpb25zLmxlbmd0aCAtIHRoaXMuc2V0dGluZ3MuZHJvcGRvd24ubWF4SXRlbXM7XG4gICAgcmV0dXJuIGhhc01vcmUgPiAwID8gYDxmb290ZXIgZGF0YS1zZWxlY3Rvcj0ndGFnaWZ5LXN1Z2dlc3Rpb25zLWZvb3RlcicgY2xhc3M9XCIke3RoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5kcm9wZG93bkZvb3Rlcn1cIj5cbiAgICAgICAgICAgICAgICAke2hhc01vcmV9IG1vcmUgaXRlbXMuIFJlZmluZSB5b3VyIHNlYXJjaC5cbiAgICAgICAgICAgIDwvZm9vdGVyPmAgOiAnJztcbiAgfSxcbiAgZHJvcGRvd25JdGVtTm9NYXRjaDogbnVsbFxufTtcblxuZnVuY3Rpb24gRXZlbnREaXNwYXRjaGVyKGluc3RhbmNlKSB7XG4gIC8vIENyZWF0ZSBhIERPTSBFdmVudFRhcmdldCBvYmplY3RcbiAgdmFyIHRhcmdldCA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCcnKTtcbiAgZnVuY3Rpb24gYWRkUmVtb3ZlKG9wLCBldmVudHMsIGNiKSB7XG4gICAgaWYgKGNiKSBldmVudHMuc3BsaXQoL1xccysvZykuZm9yRWFjaChuYW1lID0+IHRhcmdldFtvcCArICdFdmVudExpc3RlbmVyJ10uY2FsbCh0YXJnZXQsIG5hbWUsIGNiKSk7XG4gIH1cblxuICAvLyBQYXNzIEV2ZW50VGFyZ2V0IGludGVyZmFjZSBjYWxscyB0byBET00gRXZlbnRUYXJnZXQgb2JqZWN0XG4gIHJldHVybiB7XG4gICAgb2ZmKGV2ZW50cywgY2IpIHtcbiAgICAgIGFkZFJlbW92ZSgncmVtb3ZlJywgZXZlbnRzLCBjYik7XG4gICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuICAgIG9uKGV2ZW50cywgY2IpIHtcbiAgICAgIGlmIChjYiAmJiB0eXBlb2YgY2IgPT0gJ2Z1bmN0aW9uJykgYWRkUmVtb3ZlKCdhZGQnLCBldmVudHMsIGNiKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG4gICAgdHJpZ2dlcihldmVudE5hbWUsIGRhdGEsIG9wdHMpIHtcbiAgICAgIHZhciBlO1xuICAgICAgb3B0cyA9IG9wdHMgfHwge1xuICAgICAgICBjbG9uZURhdGE6IHRydWVcbiAgICAgIH07XG4gICAgICBpZiAoIWV2ZW50TmFtZSkgcmV0dXJuO1xuICAgICAgaWYgKGluc3RhbmNlLnNldHRpbmdzLmlzSlF1ZXJ5UGx1Z2luKSB7XG4gICAgICAgIGlmIChldmVudE5hbWUgPT0gJ3JlbW92ZScpIGV2ZW50TmFtZSA9ICdyZW1vdmVUYWcnOyAvLyBpc3N1ZSAjMjIyXG4gICAgICAgIGpRdWVyeShpbnN0YW5jZS5ET00ub3JpZ2luYWxJbnB1dCkudHJpZ2dlckhhbmRsZXIoZXZlbnROYW1lLCBbZGF0YV0pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB2YXIgZXZlbnREYXRhID0gdHlwZW9mIGRhdGEgPT09ICdvYmplY3QnID8gZGF0YSA6IHtcbiAgICAgICAgICAgIHZhbHVlOiBkYXRhXG4gICAgICAgICAgfTtcbiAgICAgICAgICBldmVudERhdGEgPSBvcHRzLmNsb25lRGF0YSA/IGV4dGVuZCh7fSwgZXZlbnREYXRhKSA6IGV2ZW50RGF0YTtcbiAgICAgICAgICBldmVudERhdGEudGFnaWZ5ID0gdGhpcztcbiAgICAgICAgICBpZiAoZGF0YS5ldmVudCkgZXZlbnREYXRhLmV2ZW50ID0gdGhpcy5jbG9uZUV2ZW50KGRhdGEuZXZlbnQpO1xuXG4gICAgICAgICAgLy8gVE9ETzogbW92ZSB0aGUgYmVsb3cgdG8gdGhlIFwiZXh0ZW5kXCIgZnVuY3Rpb25cbiAgICAgICAgICBpZiAoZGF0YSBpbnN0YW5jZW9mIE9iamVjdCkgZm9yICh2YXIgcHJvcCBpbiBkYXRhKSBpZiAoZGF0YVtwcm9wXSBpbnN0YW5jZW9mIEhUTUxFbGVtZW50KSBldmVudERhdGFbcHJvcF0gPSBkYXRhW3Byb3BdO1xuICAgICAgICAgIGUgPSBuZXcgQ3VzdG9tRXZlbnQoZXZlbnROYW1lLCB7XG4gICAgICAgICAgICBcImRldGFpbFwiOiBldmVudERhdGFcbiAgICAgICAgICB9KTtcbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgY29uc29sZS53YXJuKGVycik7XG4gICAgICAgIH1cbiAgICAgICAgdGFyZ2V0LmRpc3BhdGNoRXZlbnQoZSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG52YXIgZGVsZXRlQmFja3NwYWNlVGltZW91dDtcbmZ1bmN0aW9uIHRyaWdnZXJDaGFuZ2VFdmVudCgpIHtcbiAgaWYgKHRoaXMuc2V0dGluZ3MubWl4TW9kZS5pbnRlZ3JhdGVkKSByZXR1cm47XG4gIHZhciBpbnB1dEVsbSA9IHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQsXG4gICAgY2hhbmdlZCA9IHRoaXMuc3RhdGUubGFzdE9yaWdpbmFsVmFsdWVSZXBvcnRlZCAhPT0gaW5wdXRFbG0udmFsdWUsXG4gICAgZXZlbnQgPSBuZXcgQ3VzdG9tRXZlbnQoXCJjaGFuZ2VcIiwge1xuICAgICAgYnViYmxlczogdHJ1ZVxuICAgIH0pOyAvLyBtdXN0IHVzZSBcIkN1c3RvbUV2ZW50XCIgYW5kIG5vdCBcIkV2ZW50XCIgdG8gc3VwcG9ydCBJRVxuXG4gIGlmICghY2hhbmdlZCkgcmV0dXJuO1xuXG4gIC8vIG11c3QgYXBwbHkgdGhpcyBCRUZPUkUgdHJpZ2dlcmluZyB0aGUgc2ltdWxhdGVkIGV2ZW50XG4gIHRoaXMuc3RhdGUubGFzdE9yaWdpbmFsVmFsdWVSZXBvcnRlZCA9IGlucHV0RWxtLnZhbHVlO1xuXG4gIC8vIFJlYWN0IGhhY2s6IGh0dHBzOi8vZ2l0aHViLmNvbS9mYWNlYm9vay9yZWFjdC9pc3N1ZXMvMTE0ODhcbiAgZXZlbnQuc2ltdWxhdGVkID0gdHJ1ZTtcbiAgaWYgKGlucHV0RWxtLl92YWx1ZVRyYWNrZXIpIGlucHV0RWxtLl92YWx1ZVRyYWNrZXIuc2V0VmFsdWUoTWF0aC5yYW5kb20oKSk7XG4gIGlucHV0RWxtLmRpc3BhdGNoRXZlbnQoZXZlbnQpO1xuXG4gIC8vIGFsc28gdHJpZ2dlciBhIFRhZ2lmeSBldmVudFxuICB0aGlzLnRyaWdnZXIoXCJjaGFuZ2VcIiwgdGhpcy5zdGF0ZS5sYXN0T3JpZ2luYWxWYWx1ZVJlcG9ydGVkKTtcblxuICAvLyBSZWFjdCwgZm9yIHNvbWUgcmVhc29uLCBjbGVhcnMgdGhlIGlucHV0J3MgdmFsdWUgYWZ0ZXIgXCJkaXNwYXRjaEV2ZW50XCIgaXMgZmlyZWRcbiAgaW5wdXRFbG0udmFsdWUgPSB0aGlzLnN0YXRlLmxhc3RPcmlnaW5hbFZhbHVlUmVwb3J0ZWQ7XG59XG52YXIgZXZlbnRzID0ge1xuICAvLyBiaW5kIGN1c3RvbSBldmVudHMgd2hpY2ggd2VyZSBwYXNzZWQgaW4gdGhlIHNldHRpbmdzXG4gIGN1c3RvbUJpbmRpbmcoKSB7XG4gICAgdGhpcy5jdXN0b21FdmVudHNMaXN0LmZvckVhY2gobmFtZSA9PiB7XG4gICAgICB0aGlzLm9uKG5hbWUsIHRoaXMuc2V0dGluZ3MuY2FsbGJhY2tzW25hbWVdKTtcbiAgICB9KTtcbiAgfSxcbiAgYmluZGluZygpIHtcbiAgICBsZXQgYmluZFVuYmluZCA9IGFyZ3VtZW50cy5sZW5ndGggPiAwICYmIGFyZ3VtZW50c1swXSAhPT0gdW5kZWZpbmVkID8gYXJndW1lbnRzWzBdIDogdHJ1ZTtcbiAgICB2YXIgX0NCID0gdGhpcy5ldmVudHMuY2FsbGJhY2tzLFxuICAgICAgX0NCUixcbiAgICAgIGFjdGlvbiA9IGJpbmRVbmJpbmQgPyAnYWRkRXZlbnRMaXN0ZW5lcicgOiAncmVtb3ZlRXZlbnRMaXN0ZW5lcic7XG5cbiAgICAvLyBkbyBub3QgYWxsb3cgdGhlIG1haW4gZXZlbnRzIHRvIGJlIGJvdW5kIG1vcmUgdGhhbiBvbmNlXG4gICAgaWYgKHRoaXMuc3RhdGUubWFpbkV2ZW50cyAmJiBiaW5kVW5iaW5kKSByZXR1cm47XG5cbiAgICAvLyBzZXQgdGhlIGJpbmRpbmcgc3RhdGUgb2YgdGhlIG1haW4gZXZlbnRzLCBzbyB0aGV5IHdpbGwgbm90IGJlIGJvdW5kIG1vcmUgdGhhbiBvbmNlXG4gICAgdGhpcy5zdGF0ZS5tYWluRXZlbnRzID0gYmluZFVuYmluZDtcblxuICAgIC8vIGV2ZXJ5dGhpbmcgaW5zaWRlIGdldHMgZXhlY3V0ZWQgb25seSBvbmNlLXBlciBpbnN0YW5jZVxuICAgIGlmIChiaW5kVW5iaW5kICYmICF0aGlzLmxpc3RlbmVycy5tYWluKSB7XG4gICAgICB0aGlzLmV2ZW50cy5iaW5kR2xvYmFsLmNhbGwodGhpcyk7XG4gICAgICBpZiAodGhpcy5zZXR0aW5ncy5pc0pRdWVyeVBsdWdpbikgalF1ZXJ5KHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQpLm9uKCd0YWdpZnkucmVtb3ZlQWxsVGFncycsIHRoaXMucmVtb3ZlQWxsVGFncy5iaW5kKHRoaXMpKTtcbiAgICB9XG5cbiAgICAvLyBzZXR1cCBjYWxsYmFjayByZWZlcmVuY2VzIHNvIGV2ZW50cyBjb3VsZCBiZSByZW1vdmVkIGxhdGVyXG4gICAgX0NCUiA9IHRoaXMubGlzdGVuZXJzLm1haW4gPSB0aGlzLmxpc3RlbmVycy5tYWluIHx8IHtcbiAgICAgIGZvY3VzOiBbJ2lucHV0JywgX0NCLm9uRm9jdXNCbHVyLmJpbmQodGhpcyldLFxuICAgICAga2V5ZG93bjogWydpbnB1dCcsIF9DQi5vbktleWRvd24uYmluZCh0aGlzKV0sXG4gICAgICBjbGljazogWydzY29wZScsIF9DQi5vbkNsaWNrU2NvcGUuYmluZCh0aGlzKV0sXG4gICAgICBkYmxjbGljazogWydzY29wZScsIF9DQi5vbkRvdWJsZUNsaWNrU2NvcGUuYmluZCh0aGlzKV0sXG4gICAgICBwYXN0ZTogWydpbnB1dCcsIF9DQi5vblBhc3RlLmJpbmQodGhpcyldLFxuICAgICAgZHJvcDogWydpbnB1dCcsIF9DQi5vbkRyb3AuYmluZCh0aGlzKV0sXG4gICAgICBjb21wb3NpdGlvbnN0YXJ0OiBbJ2lucHV0JywgX0NCLm9uQ29tcG9zaXRpb25TdGFydC5iaW5kKHRoaXMpXSxcbiAgICAgIGNvbXBvc2l0aW9uZW5kOiBbJ2lucHV0JywgX0NCLm9uQ29tcG9zaXRpb25FbmQuYmluZCh0aGlzKV1cbiAgICB9O1xuICAgIGZvciAodmFyIGV2ZW50TmFtZSBpbiBfQ0JSKSB7XG4gICAgICB0aGlzLkRPTVtfQ0JSW2V2ZW50TmFtZV1bMF1dW2FjdGlvbl0oZXZlbnROYW1lLCBfQ0JSW2V2ZW50TmFtZV1bMV0pO1xuICAgIH1cblxuICAgIC8vIGxpc3RlbiB0byBvcmlnaW5hbCBpbnB1dCBjaGFuZ2VzICh1bmZvcnR1bmV0bHkgdGhpcyBpcyB0aGUgYmVzdCB3YXkuLi4pXG4gICAgLy8gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzE5NDk0MTYvMTA0MzgwXG4gICAgY2xlYXJJbnRlcnZhbCh0aGlzLmxpc3RlbmVycy5tYWluLm9yaWdpbmFsSW5wdXRWYWx1ZU9ic2VydmVySW50ZXJ2YWwpO1xuICAgIHRoaXMubGlzdGVuZXJzLm1haW4ub3JpZ2luYWxJbnB1dFZhbHVlT2JzZXJ2ZXJJbnRlcnZhbCA9IHNldEludGVydmFsKF9DQi5vYnNlcnZlT3JpZ2luYWxJbnB1dFZhbHVlLmJpbmQodGhpcyksIDUwMCk7XG5cbiAgICAvLyBvYnNlcnZlcnNcbiAgICB2YXIgaW5wdXRNdXRhdGlvbk9ic2VydmVyID0gdGhpcy5saXN0ZW5lcnMubWFpbi5pbnB1dE11dGF0aW9uT2JzZXJ2ZXIgfHwgbmV3IE11dGF0aW9uT2JzZXJ2ZXIoX0NCLm9uSW5wdXRET01DaGFuZ2UuYmluZCh0aGlzKSk7XG5cbiAgICAvLyBjbGVhdXAganVzdC1pbi1jYXNlXG4gICAgaW5wdXRNdXRhdGlvbk9ic2VydmVyLmRpc2Nvbm5lY3QoKTtcblxuICAgIC8vIG9ic2VydmUgc3R1ZmZcbiAgICBpZiAodGhpcy5zZXR0aW5ncy5tb2RlID09ICdtaXgnKSBpbnB1dE11dGF0aW9uT2JzZXJ2ZXIub2JzZXJ2ZSh0aGlzLkRPTS5pbnB1dCwge1xuICAgICAgY2hpbGRMaXN0OiB0cnVlXG4gICAgfSk7XG4gIH0sXG4gIGJpbmRHbG9iYWwodW5iaW5kKSB7XG4gICAgdmFyIF9DQiA9IHRoaXMuZXZlbnRzLmNhbGxiYWNrcyxcbiAgICAgIGFjdGlvbiA9IHVuYmluZCA/ICdyZW1vdmVFdmVudExpc3RlbmVyJyA6ICdhZGRFdmVudExpc3RlbmVyJyxcbiAgICAgIGU7XG4gICAgaWYgKCF0aGlzLmxpc3RlbmVycyB8fCAhdW5iaW5kICYmIHRoaXMubGlzdGVuZXJzLmdsb2JhbCkgcmV0dXJuOyAvLyBkbyBub3QgcmUtYmluZFxuXG4gICAgLy8gdGhlc2UgZXZlbnRzIGFyZSBnbG9iYWwgZXZlbnQgc2hvdWxkIG5ldmVyIGJlIHVuYmluZGVkLCB1bmxlc3MgdGhlIGluc3RhbmNlIGlzIGRlc3Ryb3llZDpcbiAgICB0aGlzLmxpc3RlbmVycy5nbG9iYWwgPSB0aGlzLmxpc3RlbmVycy5nbG9iYWwgfHwgW3tcbiAgICAgIHR5cGU6IHRoaXMuaXNJRSA/ICdrZXlkb3duJyA6ICdpbnB1dCcsXG4gICAgICAvLyBJRSBjYW5ub3QgcmVnaXN0ZXIgXCJpbnB1dFwiIGV2ZW50cyBvbiBjb250ZW50ZWRpdGFibGUgZWxlbWVudHMsIHNvIHRoZSBcImtleWRvd25cIiBzaG91bGQgYmUgdXNlZCBpbnN0ZWFkLi5cbiAgICAgIHRhcmdldDogdGhpcy5ET00uaW5wdXQsXG4gICAgICBjYjogX0NCW3RoaXMuaXNJRSA/ICdvbklucHV0SUUnIDogJ29uSW5wdXQnXS5iaW5kKHRoaXMpXG4gICAgfSwge1xuICAgICAgdHlwZTogJ2tleWRvd24nLFxuICAgICAgdGFyZ2V0OiB3aW5kb3csXG4gICAgICBjYjogX0NCLm9uV2luZG93S2V5RG93bi5iaW5kKHRoaXMpXG4gICAgfSwge1xuICAgICAgdHlwZTogJ2JsdXInLFxuICAgICAgdGFyZ2V0OiB0aGlzLkRPTS5pbnB1dCxcbiAgICAgIGNiOiBfQ0Iub25Gb2N1c0JsdXIuYmluZCh0aGlzKVxuICAgIH0sIHtcbiAgICAgIHR5cGU6ICdjbGljaycsXG4gICAgICB0YXJnZXQ6IGRvY3VtZW50LFxuICAgICAgY2I6IF9DQi5vbkNsaWNrQW55d2hlcmUuYmluZCh0aGlzKVxuICAgIH1dO1xuICAgIGZvciAoZSBvZiB0aGlzLmxpc3RlbmVycy5nbG9iYWwpIGUudGFyZ2V0W2FjdGlvbl0oZS50eXBlLCBlLmNiKTtcbiAgfSxcbiAgdW5iaW5kR2xvYmFsKCkge1xuICAgIHRoaXMuZXZlbnRzLmJpbmRHbG9iYWwuY2FsbCh0aGlzLCB0cnVlKTtcbiAgfSxcbiAgLyoqXHJcbiAgICogRE9NIGV2ZW50cyBjYWxsYmFja3NcclxuICAgKi9cbiAgY2FsbGJhY2tzOiB7XG4gICAgb25Gb2N1c0JsdXIoZSkge1xuICAgICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgICAgdGV4dCA9IGUudGFyZ2V0ID8gdGhpcy50cmltKGUudGFyZ2V0LnRleHRDb250ZW50KSA6ICcnLFxuICAgICAgICAvLyBhIHN0cmluZ1xuICAgICAgICBjdXJyZW50RGlzcGxheVZhbHVlID0gdGhpcy52YWx1ZT8uWzBdPy5bX3MudGFnVGV4dFByb3BdLFxuICAgICAgICB0eXBlID0gZS50eXBlLFxuICAgICAgICBkZEVuYWJsZWQgPSBfcy5kcm9wZG93bi5lbmFibGVkID49IDAsXG4gICAgICAgIGV2ZW50RGF0YSA9IHtcbiAgICAgICAgICByZWxhdGVkVGFyZ2V0OiBlLnJlbGF0ZWRUYXJnZXRcbiAgICAgICAgfSxcbiAgICAgICAgaXNUYXJnZXRTZWxlY3RPcHRpb24gPSB0aGlzLnN0YXRlLmFjdGlvbnMuc2VsZWN0T3B0aW9uICYmIChkZEVuYWJsZWQgfHwgIV9zLmRyb3Bkb3duLmNsb3NlT25TZWxlY3QpLFxuICAgICAgICBpc1RhcmdldEFkZE5ld0J0biA9IHRoaXMuc3RhdGUuYWN0aW9ucy5hZGROZXcgJiYgZGRFbmFibGVkLFxuICAgICAgICBpc1JlbGF0ZWRUYXJnZXRYID0gZS5yZWxhdGVkVGFyZ2V0ICYmIGlzTm9kZVRhZy5jYWxsKHRoaXMsIGUucmVsYXRlZFRhcmdldCkgJiYgdGhpcy5ET00uc2NvcGUuY29udGFpbnMoZS5yZWxhdGVkVGFyZ2V0KSxcbiAgICAgICAgc2hvdWxkQWRkVGFncztcbiAgICAgIGlmICh0eXBlID09ICdibHVyJykge1xuICAgICAgICBpZiAoZS5yZWxhdGVkVGFyZ2V0ID09PSB0aGlzLkRPTS5zY29wZSkge1xuICAgICAgICAgIHRoaXMuZHJvcGRvd24uaGlkZSgpO1xuICAgICAgICAgIHRoaXMuRE9NLmlucHV0LmZvY3VzKCk7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucG9zdFVwZGF0ZSgpO1xuICAgICAgICBfcy5vbkNoYW5nZUFmdGVyQmx1ciAmJiB0aGlzLnRyaWdnZXJDaGFuZ2VFdmVudCgpO1xuICAgICAgfVxuICAgICAgaWYgKGlzVGFyZ2V0U2VsZWN0T3B0aW9uIHx8IGlzVGFyZ2V0QWRkTmV3QnRuKSByZXR1cm47XG4gICAgICB0aGlzLnN0YXRlLmhhc0ZvY3VzID0gdHlwZSA9PSBcImZvY3VzXCIgPyArbmV3IERhdGUoKSA6IGZhbHNlO1xuICAgICAgdGhpcy50b2dnbGVGb2N1c0NsYXNzKHRoaXMuc3RhdGUuaGFzRm9jdXMpO1xuICAgICAgaWYgKF9zLm1vZGUgPT0gJ21peCcpIHtcbiAgICAgICAgaWYgKHR5cGUgPT0gXCJmb2N1c1wiKSB7XG4gICAgICAgICAgdGhpcy50cmlnZ2VyKFwiZm9jdXNcIiwgZXZlbnREYXRhKTtcbiAgICAgICAgfSBlbHNlIGlmIChlLnR5cGUgPT0gXCJibHVyXCIpIHtcbiAgICAgICAgICB0aGlzLnRyaWdnZXIoXCJibHVyXCIsIGV2ZW50RGF0YSk7XG4gICAgICAgICAgdGhpcy5sb2FkaW5nKGZhbHNlKTtcbiAgICAgICAgICB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICAgICAgICAvLyByZXNldCBzdGF0ZSB3aGljaCBuZWVkcyByZXNldGluZ1xuICAgICAgICAgIHRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICB0aGlzLnNldFN0YXRlU2VsZWN0aW9uKCk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKHR5cGUgPT0gXCJmb2N1c1wiKSB7XG4gICAgICAgIHRoaXMudHJpZ2dlcihcImZvY3VzXCIsIGV2ZW50RGF0YSk7XG4gICAgICAgIC8vICBlLnRhcmdldC5jbGFzc0xpc3QucmVtb3ZlKCdwbGFjZWhvbGRlcicpO1xuICAgICAgICBpZiAoX3MuZHJvcGRvd24uZW5hYmxlZCA9PT0gMCB8fCAhX3MudXNlcklucHV0KSB7XG4gICAgICAgICAgLy8gJiYgX3MubW9kZSAhPSBcInNlbGVjdFwiXG4gICAgICAgICAgdGhpcy5kcm9wZG93bi5zaG93KHRoaXMudmFsdWUubGVuZ3RoID8gJycgOiB1bmRlZmluZWQpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcImJsdXJcIikge1xuICAgICAgICB0aGlzLnRyaWdnZXIoXCJibHVyXCIsIGV2ZW50RGF0YSk7XG4gICAgICAgIHRoaXMubG9hZGluZyhmYWxzZSk7XG5cbiAgICAgICAgLy8gd2hlbiBjbGlja2luZyB0aGUgWCBidXR0b24gb2YgYSBzZWxlY3RlZCB0YWcsIGl0IGlzIHVud2FudGVkIGZvciBpdCB0byBiZSBhZGRlZCBiYWNrXG4gICAgICAgIC8vIGFnYWluIGluIGEgZmV3IG1vcmUgbGluZXMgb2YgY29kZSAoc2hvdWxkQWRkVGFncyAmJiBhZGRUYWdzKVxuICAgICAgICBpZiAoX3MubW9kZSA9PSAnc2VsZWN0Jykge1xuICAgICAgICAgIGlmIChpc1JlbGF0ZWRUYXJnZXRYKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW92ZVRhZ3MoKTtcbiAgICAgICAgICAgIHRleHQgPSAnJztcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBpZiBub3RoaW5nIGhhcyBjaGFuZ2VkIChzYW1lIGRpc3BsYXkgdmFsdWUpLCBkbyBub3QgYWRkIGEgdGFnXG4gICAgICAgICAgaWYgKGN1cnJlbnREaXNwbGF5VmFsdWUgPT09IHRleHQpIHRleHQgPSAnJztcbiAgICAgICAgfVxuICAgICAgICBzaG91bGRBZGRUYWdzID0gdGV4dCAmJiAhdGhpcy5zdGF0ZS5hY3Rpb25zLnNlbGVjdE9wdGlvbiAmJiBfcy5hZGRUYWdPbkJsdXI7XG5cbiAgICAgICAgLy8gZG8gbm90IGFkZCBhIHRhZyBpZiBcInNlbGVjdE9wdGlvblwiIGFjdGlvbiB3YXMganVzdCBmaXJlZCAodGhpcyBtZWFucyBhIHRhZyB3YXMganVzdCBhZGRlZCBmcm9tIHRoZSBkcm9wZG93bilcbiAgICAgICAgc2hvdWxkQWRkVGFncyAmJiB0aGlzLmFkZFRhZ3ModGV4dCwgdHJ1ZSk7XG4gICAgICB9XG4gICAgICB0aGlzLkRPTS5pbnB1dC5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG4gICAgICB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICB9LFxuICAgIG9uQ29tcG9zaXRpb25TdGFydChlKSB7XG4gICAgICB0aGlzLnN0YXRlLmNvbXBvc2luZyA9IHRydWU7XG4gICAgfSxcbiAgICBvbkNvbXBvc2l0aW9uRW5kKGUpIHtcbiAgICAgIHRoaXMuc3RhdGUuY29tcG9zaW5nID0gZmFsc2U7XG4gICAgfSxcbiAgICBvbldpbmRvd0tleURvd24oZSkge1xuICAgICAgdmFyIGZvY3VzZWRFbG0gPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50LFxuICAgICAgICBpc1RhZyA9IGlzTm9kZVRhZy5jYWxsKHRoaXMsIGZvY3VzZWRFbG0pLFxuICAgICAgICBpc0JlbG9uZyA9IGlzVGFnICYmIHRoaXMuRE9NLnNjb3BlLmNvbnRhaW5zKGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQpLFxuICAgICAgICBpc1JlYWR5T25seVRhZyA9IGlzQmVsb25nICYmIGZvY3VzZWRFbG0uaGFzQXR0cmlidXRlKCdyZWFkb25seScpLFxuICAgICAgICBuZXh0VGFnO1xuICAgICAgaWYgKCFpc0JlbG9uZyB8fCBpc1JlYWR5T25seVRhZykgcmV0dXJuO1xuICAgICAgbmV4dFRhZyA9IGZvY3VzZWRFbG0ubmV4dEVsZW1lbnRTaWJsaW5nO1xuICAgICAgc3dpdGNoIChlLmtleSkge1xuICAgICAgICAvLyByZW1vdmUgdGFnIGlmIGhhcyBmb2N1c1xuICAgICAgICBjYXNlICdCYWNrc3BhY2UnOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5zZXR0aW5ncy5yZWFkb25seSkge1xuICAgICAgICAgICAgICB0aGlzLnJlbW92ZVRhZ3MoZm9jdXNlZEVsbSk7XG4gICAgICAgICAgICAgIChuZXh0VGFnID8gbmV4dFRhZyA6IHRoaXMuRE9NLmlucHV0KS5mb2N1cygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuXG4gICAgICAgIC8vIGVkaXQgdGFnIGlmIGhhcyBmb2N1c1xuICAgICAgICBjYXNlICdFbnRlcic6XG4gICAgICAgICAge1xuICAgICAgICAgICAgc2V0VGltZW91dCh0aGlzLmVkaXRUYWcuYmluZCh0aGlzKSwgMCwgZm9jdXNlZEVsbSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICB9XG4gICAgfSxcbiAgICBvbktleWRvd24oZSkge1xuICAgICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncztcblxuICAgICAgLy8gaWdub3JlIGtleXMgZHVyaW5nIElNRSBjb21wb3NpdGlvbiBvciB3aGVuIHVzZXIgaW5wdXQgaXMgbm90IGFsbG93ZWRcbiAgICAgIGlmICh0aGlzLnN0YXRlLmNvbXBvc2luZyB8fCAhX3MudXNlcklucHV0KSByZXR1cm47XG4gICAgICBpZiAoX3MubW9kZSA9PSAnc2VsZWN0JyAmJiBfcy5lbmZvcmNlV2hpdGVsaXN0ICYmIHRoaXMudmFsdWUubGVuZ3RoICYmIGUua2V5ICE9ICdUYWInKSB7XG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIH1cbiAgICAgIHZhciBzID0gdGhpcy50cmltKGUudGFyZ2V0LnRleHRDb250ZW50KTtcbiAgICAgIHRoaXMudHJpZ2dlcihcImtleWRvd25cIiwge1xuICAgICAgICBldmVudDogZVxuICAgICAgfSk7XG5cbiAgICAgIC8qKlxyXG4gICAgICAgKiBPTkxZIEZPUiBNSVgtTU9ERTpcclxuICAgICAgICovXG4gICAgICBpZiAoX3MubW9kZSA9PSAnbWl4Jykge1xuICAgICAgICBzd2l0Y2ggKGUua2V5KSB7XG4gICAgICAgICAgY2FzZSAnTGVmdCc6XG4gICAgICAgICAgY2FzZSAnQXJyb3dMZWZ0JzpcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgLy8gd2hlbiBsZWZ0IGFycm93IHdhcyBwcmVzc2VkLCBzZXQgYSBmbGFnIHNvIHdoZW4gdGhlIGRyb3Bkb3duIGlzIHNob3duLCByaWdodC1hcnJvdyB3aWxsIGJlIGlnbm9yZWRcbiAgICAgICAgICAgICAgLy8gYmVjYXVzZSBpdCBzZWVtcyBsaWtlbHkgdGhlIHVzZXIgd2lzaGVzIHRvIHVzZSB0aGUgYXJyb3dzIHRvIG1vdmUgdGhlIGNhcmV0XG4gICAgICAgICAgICAgIHRoaXMuc3RhdGUuYWN0aW9ucy5BcnJvd0xlZnQgPSB0cnVlO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICBjYXNlICdEZWxldGUnOlxuICAgICAgICAgIGNhc2UgJ0JhY2tzcGFjZSc6XG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmcpIHJldHVybjtcbiAgICAgICAgICAgICAgdmFyIHNlbCA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpLFxuICAgICAgICAgICAgICAgIGRlbGV0ZUtleVRhZ0RldGVjdGVkID0gZS5rZXkgPT0gJ0RlbGV0ZScgJiYgc2VsLmFuY2hvck9mZnNldCA9PSAoc2VsLmFuY2hvck5vZGUubGVuZ3RoIHx8IDApLFxuICAgICAgICAgICAgICAgIHByZXZBbmNob3JTaWJsaW5nID0gc2VsLmFuY2hvck5vZGUucHJldmlvdXNTaWJsaW5nLFxuICAgICAgICAgICAgICAgIGlzQ2FyZXRBZnRlclRhZyA9IHNlbC5hbmNob3JOb2RlLm5vZGVUeXBlID09IDEgfHwgIXNlbC5hbmNob3JPZmZzZXQgJiYgcHJldkFuY2hvclNpYmxpbmcgJiYgcHJldkFuY2hvclNpYmxpbmcubm9kZVR5cGUgPT0gMSAmJiBzZWwuYW5jaG9yTm9kZS5wcmV2aW91c1NpYmxpbmc7XG4gICAgICAgICAgICAgICAgZGVjb2RlKHRoaXMuRE9NLmlucHV0LmlubmVySFRNTCk7XG4gICAgICAgICAgICAgICAgdmFyIGxhc3RUYWdFbGVtcyA9IHRoaXMuZ2V0VGFnRWxtcygpLFxuICAgICAgICAgICAgICAgIC8vICBpc0NhcmV0SW5zaWRlVGFnID0gc2VsLmFuY2hvck5vZGUucGFyZW50Tm9kZSgnLicgKyBfcy5jbGFzc05hbWVzLnRhZyksXG4gICAgICAgICAgICAgICAgdGFnQmVmb3JlQ2FyZXQsXG4gICAgICAgICAgICAgICAgdGFnRWxtVG9CZURlbGV0ZWQsXG4gICAgICAgICAgICAgICAgZmlyc3RUZXh0Tm9kZUJlZm9yZVRhZztcbiAgICAgICAgICAgICAgaWYgKF9zLmJhY2tzcGFjZSA9PSAnZWRpdCcgJiYgaXNDYXJldEFmdGVyVGFnKSB7XG4gICAgICAgICAgICAgICAgdGFnQmVmb3JlQ2FyZXQgPSBzZWwuYW5jaG9yTm9kZS5ub2RlVHlwZSA9PSAxID8gbnVsbCA6IHNlbC5hbmNob3JOb2RlLnByZXZpb3VzRWxlbWVudFNpYmxpbmc7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dCh0aGlzLmVkaXRUYWcuYmluZCh0aGlzKSwgMCwgdGFnQmVmb3JlQ2FyZXQpOyAvLyB0aW1lb3V0IGlzIG5lZWRlZCB0byB0aGUgbGFzdCBjYWhhY3J0ZXIgaW4gdGhlIGVkaXRlZCB0YWcgd29uJ3QgZ2V0IGRlbGV0ZWRcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7IC8vIG5lZWRlZCBzbyB0aGUgdGFnIGVsbSB3b24ndCBnZXQgZGVsZXRlZFxuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoaXNDaHJvbWVBbmRyb2lkQnJvd3NlcigpICYmIGlzQ2FyZXRBZnRlclRhZyBpbnN0YW5jZW9mIEVsZW1lbnQpIHtcbiAgICAgICAgICAgICAgICBmaXJzdFRleHROb2RlQmVmb3JlVGFnID0gZ2V0Zmlyc3RUZXh0Tm9kZShpc0NhcmV0QWZ0ZXJUYWcpO1xuICAgICAgICAgICAgICAgIGlmICghaXNDYXJldEFmdGVyVGFnLmhhc0F0dHJpYnV0ZSgncmVhZG9ubHknKSkgaXNDYXJldEFmdGVyVGFnLnJlbW92ZSgpOyAvLyBzaW5jZSB0aGlzIGlzIENocm9tZSwgY2FuIHNhZmV0bHkgdXNlIHRoaXMgXCJuZXdcIiBET00gQVBJXG5cbiAgICAgICAgICAgICAgICAvLyBBbmRyb2lkLUNocm9tZSB3cm9uZ2x5IGhpZGVzIHRoZSBrZXlib2FyZCwgYW5kIGxvc2VzIGZvY3VzLFxuICAgICAgICAgICAgICAgIC8vIHNvIHRoaXMgaGFjayBiZWxvdyBpcyBuZWVkZWQgdG8gcmVnYWluIGZvY3VzIGF0IHRoZSBjb3JyZWN0IHBsYWNlOlxuICAgICAgICAgICAgICAgIHRoaXMuRE9NLmlucHV0LmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgICB0aGlzLnBsYWNlQ2FyZXRBZnRlck5vZGUoZmlyc3RUZXh0Tm9kZUJlZm9yZVRhZyk7XG4gICAgICAgICAgICAgICAgICB0aGlzLkRPTS5pbnB1dC5jbGljaygpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoc2VsLmFuY2hvck5vZGUubm9kZU5hbWUgPT0gJ0JSJykgcmV0dXJuO1xuICAgICAgICAgICAgICBpZiAoKGRlbGV0ZUtleVRhZ0RldGVjdGVkIHx8IGlzQ2FyZXRBZnRlclRhZykgJiYgc2VsLmFuY2hvck5vZGUubm9kZVR5cGUgPT0gMSkge1xuICAgICAgICAgICAgICAgIGlmIChzZWwuYW5jaG9yT2Zmc2V0ID09IDApXG4gICAgICAgICAgICAgICAgICAvLyBjYXJldCBpcyBhdCB0aGUgdmVyeSBiZWdpbmluZywgYmVmb3JlIGEgdGFnXG4gICAgICAgICAgICAgICAgICB0YWdFbG1Ub0JlRGVsZXRlZCA9IGRlbGV0ZUtleVRhZ0RldGVjdGVkIC8vIGRlbGV0ZSBrZXkgcHJlc3NlZFxuICAgICAgICAgICAgICAgICAgPyBsYXN0VGFnRWxlbXNbMF0gOiBudWxsO2Vsc2UgdGFnRWxtVG9CZURlbGV0ZWQgPSBsYXN0VGFnRWxlbXNbTWF0aC5taW4obGFzdFRhZ0VsZW1zLmxlbmd0aCwgc2VsLmFuY2hvck9mZnNldCkgLSAxXTtcblxuICAgICAgICAgICAgICAgIC8vIGZpbmQgb3V0IGlmIGEgdGFnICptaWdodCogYmUgYSBjYW5kaWRhdGUgZm9yIGRlbGV0aW9uLCBhbmQgaWYgc28sIHdoaWNoXG4gICAgICAgICAgICAgIH0gZWxzZSBpZiAoZGVsZXRlS2V5VGFnRGV0ZWN0ZWQpIHRhZ0VsbVRvQmVEZWxldGVkID0gc2VsLmFuY2hvck5vZGUubmV4dEVsZW1lbnRTaWJsaW5nO2Vsc2UgaWYgKGlzQ2FyZXRBZnRlclRhZyBpbnN0YW5jZW9mIEVsZW1lbnQpIHRhZ0VsbVRvQmVEZWxldGVkID0gaXNDYXJldEFmdGVyVGFnO1xuXG4gICAgICAgICAgICAgIC8vIHRhZ0VsbS5oYXNBdHRyaWJ1dGUoJ3JlYWRvbmx5JylcbiAgICAgICAgICAgICAgaWYgKHNlbC5hbmNob3JOb2RlLm5vZGVUeXBlID09IDMgJiZcbiAgICAgICAgICAgICAgLy8gbm9kZSBhdCBjYXJldCBsb2NhdGlvbiBpcyBhIFRleHQgbm9kZVxuICAgICAgICAgICAgICAhc2VsLmFuY2hvck5vZGUubm9kZVZhbHVlICYmXG4gICAgICAgICAgICAgIC8vIGhhcyBzb21lIHRleHRcbiAgICAgICAgICAgICAgc2VsLmFuY2hvck5vZGUucHJldmlvdXNFbGVtZW50U2libGluZylcbiAgICAgICAgICAgICAgICAvLyB0ZXh0IG5vZGUgaGFzIGEgVGFnIG5vZGUgYmVmb3JlIGl0XG4gICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG4gICAgICAgICAgICAgIC8vIGlmIGJhY2tzcGFjZSBub3QgYWxsb3dlZCwgZG8gbm90aGluZ1xuICAgICAgICAgICAgICAvLyBUT0RPOiBhIGJldHRlciB3YXkgdG8gZGV0ZWN0IGlmIG5vZGVzIHdlcmUgZGVsZXRlZCBpcyB0byBzaW1wbHkgY2hlY2sgdGhlIFwidGhpcy52YWx1ZVwiIGJlZm9yZSAmIGFmdGVyXG4gICAgICAgICAgICAgIGlmICgoaXNDYXJldEFmdGVyVGFnIHx8IGRlbGV0ZUtleVRhZ0RldGVjdGVkKSAmJiAhX3MuYmFja3NwYWNlKSB7XG4gICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBpZiAoc2VsLnR5cGUgIT0gJ1JhbmdlJyAmJiAhc2VsLmFuY2hvck9mZnNldCAmJiBzZWwuYW5jaG9yTm9kZSA9PSB0aGlzLkRPTS5pbnB1dCAmJiBlLmtleSAhPSAnRGVsZXRlJykge1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKHNlbC50eXBlICE9ICdSYW5nZScgJiYgdGFnRWxtVG9CZURlbGV0ZWQgJiYgdGFnRWxtVG9CZURlbGV0ZWQuaGFzQXR0cmlidXRlKCdyZWFkb25seScpKSB7XG4gICAgICAgICAgICAgICAgLy8gYWxsb3dzIHRoZSBjb250aW51YXRpb24gb2YgZGVsZXRpb24gYnkgcGxhY2luZyB0aGUgY2FyZXQgb24gdGhlIGZpcnN0IHByZXZpb3VzIHRleHROb2RlLlxuICAgICAgICAgICAgICAgIC8vIHNpbmNlIGEgZmV3IHJlYWRvbmx5LXRhZ3MgbWlnaHQgYmUgb25lIGFmdGVyIHRoZSBvdGhlciwgaXRlcmF0aW9uIGlzIG5lZWRlZDpcblxuICAgICAgICAgICAgICAgIHRoaXMucGxhY2VDYXJldEFmdGVyTm9kZShnZXRmaXJzdFRleHROb2RlKHRhZ0VsbVRvQmVEZWxldGVkKSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gdXBkYXRlIHJlZ2FyZGluZyBodHRwczovL2dpdGh1Yi5jb20veWFpckVPL3RhZ2lmeS9pc3N1ZXMvNzYyI2lzc3VlY29tbWVudC03ODY0NjQzMTc6XG4gICAgICAgICAgICAgIC8vIHRoZSBidWcgZGVzY3JpYmVkIGlzIG1vcmUgc2V2ZXJlIHRoYW4gdGhlIGZpeCBiZWxvdywgdGhlcmVmb3JlIEkgZGlzYWJsZSB0aGUgZml4IHVudGlsIGEgc29sdXRpb25cbiAgICAgICAgICAgICAgLy8gaXMgZm91bmQgd2hpY2ggd29yayB3ZWxsIGZvciBib3RoIGNhc2VzLlxuICAgICAgICAgICAgICAvLyAtLS0tLS0tXG4gICAgICAgICAgICAgIC8vIG5vZGVUeXBlIGlzIFwiMVwiIG9ubHkgd2hlbiB0aGUgY2FyZXQgaXMgYXQgdGhlIGVuZCBhZnRlciBsYXN0IHRhZyAobm8gdGV4dCBhZnRlciksIG9yIGJlZm9yZSBmaXJzdCBmaXJzdCAobm8gdGV4dCBiZWZvcmUpXG4gICAgICAgICAgICAgIC8qXHJcbiAgICAgICAgICAgICAgaWYoIHRoaXMuaXNGaXJlZm94ICYmIHNlbC5hbmNob3JOb2RlLm5vZGVUeXBlID09IDEgJiYgc2VsLmFuY2hvck9mZnNldCAhPSAwICl7XHJcbiAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlVGFncygpIC8vIHJlbW92ZXMgbGFzdCB0YWcgYnkgZGVmYXVsdCBpZiBubyBwYXJhbWV0ZXIgc3VwcGxpZWRcclxuICAgICAgICAgICAgICAgICAgLy8gcGxhY2UgY2FyZXQgaW5zaWRlIGxhc3QgdGV4dE5vZGUsIGlmIGV4aXN0LiBpdCdzIGFuIGFubm95aW5nIGJ1ZyBvbmx5IGluIEZGLFxyXG4gICAgICAgICAgICAgICAgICAvLyBpZiB0aGUgbGFzdCB0YWcgaXMgcmVtb3ZlZCwgYW5kIHRoZXJlIGlzIGEgdGV4dE5vZGUgYmVmb3JlIGl0LCB0aGUgY2FyZXQgaXMgbm90IHBsYWNlZCBhdCBpdHMgZW5kXHJcbiAgICAgICAgICAgICAgICAgIHRoaXMucGxhY2VDYXJldEFmdGVyTm9kZSggc2V0UmFuZ2VBdFN0YXJ0RW5kKGZhbHNlLCB0aGlzLkRPTS5pbnB1dCkgKVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICAgIGNsZWFyVGltZW91dChkZWxldGVCYWNrc3BhY2VUaW1lb3V0KTtcbiAgICAgICAgICAgICAgLy8gYSBtaW5pbXVtIGRlbGF5IGlzIG5lZWRlZCBiZWZvcmUgdGhlIG5vZGUgYWN0dWFsbHkgZ2V0cyBkZXRhY2hlZCBmcm9tIHRoZSBkb2N1bWVudCAoZG9uJ3Qga25vdyB3aHkpLFxuICAgICAgICAgICAgICAvLyB0byBrbm93IGV4YWN0bHkgd2hpY2ggdGFnIHdhcyBkZWxldGVkLiBUaGlzIGlzIHRoZSBlYXNpZXN0IHdheSBvZiBrbm93aW5nIGJlc2lkZXMgdXNpbmcgTXV0YXRpb25PYnNlcnZlclxuICAgICAgICAgICAgICBkZWxldGVCYWNrc3BhY2VUaW1lb3V0ID0gc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgICAgICAgICAgdmFyIHNlbCA9IGRvY3VtZW50LmdldFNlbGVjdGlvbigpO1xuICAgICAgICAgICAgICAgICAgZGVjb2RlKHRoaXMuRE9NLmlucHV0LmlubmVySFRNTCk7XG4gICAgICAgICAgICAgICAgICAhZGVsZXRlS2V5VGFnRGV0ZWN0ZWQgJiYgc2VsLmFuY2hvck5vZGUucHJldmlvdXNTaWJsaW5nO1xuXG4gICAgICAgICAgICAgICAgLy8gZml4ZXMgIzM4NCwgd2hlcmUgdGhlIGZpcnN0IGFuZCBvbmx5IHRhZyB3aWxsIG5vdCBnZXQgcmVtb3ZlZCB3aXRoIGJhY2tzcGFjZVxuICAgICAgICAgICAgICAgIC8qXHJcbiAgICAgICAgICAgICAgICAgKiBbVVBEQVRFIERFQyAzLCAyMl0gU0VFTVMgQkVMT0VXIENPREUgSVMgTk9UIE5FRURFRCBBTlkgTU9SRVxyXG4gICAgICAgICAgICAgICAgICpcclxuICAgICAgICAgICAgICAgIGlmKCBjdXJyZW50VmFsdWUubGVuZ3RoID4gbGFzdElucHV0VmFsdWUubGVuZ3RoICYmIHByZXZFbG0gKXtcclxuICAgICAgICAgICAgICAgICAgICBpZiggaXNOb2RlVGFnLmNhbGwodGhpcywgcHJldkVsbSkgJiYgIXByZXZFbG0uaGFzQXR0cmlidXRlKCdyZWFkb25seScpICl7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3ZlVGFncyhwcmV2RWxtKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZpeEZpcmVmb3hMYXN0VGFnTm9DYXJldCgpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGFib3ZlIFwicmVtb3ZlVGFnXCIgbWV0aG9kcyByZW1vdmVzIHRoZSB0YWcgd2l0aCBhIHRyYW5zaXRpb24uIENocm9tZSBhZGRzIGEgPGJyPiBlbGVtZW50IGZvciBzb21lIHJlYXNvbiBhdCB0aGlzIHN0YWdlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKCB0aGlzLkRPTS5pbnB1dC5jaGlsZHJlbi5sZW5ndGggPT0gMiAmJiB0aGlzLkRPTS5pbnB1dC5jaGlsZHJlblsxXS50YWdOYW1lID09IFwiQlJcIiApe1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5ET00uaW5wdXQuaW5uZXJIVE1MID0gXCJcIlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy52YWx1ZS5sZW5ndGggPSAwXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgICAgZWxzZVxyXG4gICAgICAgICAgICAgICAgICAgICAgICBwcmV2RWxtLnJlbW92ZSgpXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAqL1xuXG4gICAgICAgICAgICAgICAgLy8gZmluZCBvdXQgd2hpY2ggdGFnKHMpIHdlcmUgZGVsZXRlZCBhbmQgdHJpZ2dlciBcInJlbW92ZVwiIGV2ZW50XG4gICAgICAgICAgICAgICAgLy8gaXRlcmF0ZSBvdmVyIHRoZSBsaXN0IG9mIHRhZ3Mgc3RpbGwgaW4gdGhlIGRvY3VtZW50IGFuZCB0aGVuIGZpbHRlciBvbmx5IHRob3NlIGZyb20gdGhlIFwidGhpcy52YWx1ZVwiIGNvbGxlY3Rpb25cbiAgICAgICAgICAgICAgICB0aGlzLnZhbHVlID0gW10ubWFwLmNhbGwobGFzdFRhZ0VsZW1zLCAobm9kZSwgbm9kZUlkeCkgPT4ge1xuICAgICAgICAgICAgICAgICAgdmFyIHRhZ0RhdGEgPSBnZXRTZXRUYWdEYXRhKG5vZGUpO1xuXG4gICAgICAgICAgICAgICAgICAvLyBzaW5jZSByZWFkb25seSBjYW5ub3QgYmUgcmVtb3ZlZCAoaXQncyB0ZWNobmljYWxseSByZXN1cnJlY3RlZCBpZiByZW1vdmVkIHNvbWVob3cpXG4gICAgICAgICAgICAgICAgICBpZiAobm9kZS5wYXJlbnROb2RlIHx8IHRhZ0RhdGEucmVhZG9ubHkpIHJldHVybiB0YWdEYXRhO2Vsc2UgdGhpcy50cmlnZ2VyKCdyZW1vdmUnLCB7XG4gICAgICAgICAgICAgICAgICAgIHRhZzogbm9kZSxcbiAgICAgICAgICAgICAgICAgICAgaW5kZXg6IG5vZGVJZHgsXG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IHRhZ0RhdGFcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pLmZpbHRlcihuID0+IG4pOyAvLyByZW1vdmUgZW1wdHkgaXRlbXMgaW4gdGhlIG1hcHBlZCBhcnJheVxuICAgICAgICAgICAgICB9LCAyMCk7IC8vIEZpcmVmb3ggbmVlZHMgdGhpcyBoaWdoZXIgZHVyYXRpb24gZm9yIHNvbWUgcmVhc29uIG9yIHRoaW5ncyBnZXQgYnVnZ3kgd2hlbiBkZWxldGluZyB0ZXh0IGZyb20gdGhlIGVuZFxuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAvLyBjdXJyZW50bHkgY29tbWVudGVkIHRvIGFsbG93IG5ldyBsaW5lcyBpbiBtaXhlZC1tb2RlXG4gICAgICAgICAgLy8gY2FzZSAnRW50ZXInIDpcbiAgICAgICAgICAvLyAgICAgLy8gZS5wcmV2ZW50RGVmYXVsdCgpOyAvLyBzb2x2ZXMgQ2hyb21lIGJ1ZyAtIGh0dHA6Ly9zdGFja292ZXJmbG93LmNvbS9hLzIwMzk4MTkxLzEwNDM4MFxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgICBzd2l0Y2ggKGUua2V5KSB7XG4gICAgICAgIGNhc2UgJ0JhY2tzcGFjZSc6XG4gICAgICAgICAgaWYgKF9zLm1vZGUgPT0gJ3NlbGVjdCcgJiYgX3MuZW5mb3JjZVdoaXRlbGlzdCAmJiB0aGlzLnZhbHVlLmxlbmd0aCkgdGhpcy5yZW1vdmVUYWdzKCk7ZWxzZSBpZiAoIXRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSB8fCBfcy5kcm9wZG93bi5wb3NpdGlvbiA9PSAnbWFudWFsJykge1xuICAgICAgICAgICAgaWYgKGUudGFyZ2V0LnRleHRDb250ZW50ID09IFwiXCIgfHwgcy5jaGFyQ29kZUF0KDApID09IDgyMDMpIHtcbiAgICAgICAgICAgICAgLy8gODIwMzogWkVSTyBXSURUSCBTUEFDRSB1bmljb2RlXG4gICAgICAgICAgICAgIGlmIChfcy5iYWNrc3BhY2UgPT09IHRydWUpIHRoaXMucmVtb3ZlVGFncygpO2Vsc2UgaWYgKF9zLmJhY2tzcGFjZSA9PSAnZWRpdCcpIHNldFRpbWVvdXQodGhpcy5lZGl0VGFnLmJpbmQodGhpcyksIDApOyAvLyB0aW1lb3V0IHJlYXNvbjogd2hlbiBlZGl0ZWQgdGFnIGdldHMgZm9jdXNlZCBhbmQgdGhlIGNhcmV0IGlzIHBsYWNlZCBhdCB0aGUgZW5kLCB0aGUgbGFzdCBjaGFyYWN0ZXIgZ2V0cyBkZWxldGVjIChiZWNhdXNlIG9mIGJhY2tzcGFjZSlcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnRXNjJzpcbiAgICAgICAgY2FzZSAnRXNjYXBlJzpcbiAgICAgICAgICBpZiAodGhpcy5zdGF0ZS5kcm9wZG93bi52aXNpYmxlKSByZXR1cm47XG4gICAgICAgICAgZS50YXJnZXQuYmx1cigpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdEb3duJzpcbiAgICAgICAgY2FzZSAnQXJyb3dEb3duJzpcbiAgICAgICAgICAvLyBpZiggX3MubW9kZSA9PSAnc2VsZWN0JyApIC8vIGlzc3VlICMzMzNcbiAgICAgICAgICBpZiAoIXRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSkgdGhpcy5kcm9wZG93bi5zaG93KCk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ0Fycm93UmlnaHQnOlxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGxldCB0YWdEYXRhID0gdGhpcy5zdGF0ZS5pbnB1dFN1Z2dlc3Rpb24gfHwgdGhpcy5zdGF0ZS5kZEl0ZW1EYXRhO1xuICAgICAgICAgICAgaWYgKHRhZ0RhdGEgJiYgX3MuYXV0b0NvbXBsZXRlLnJpZ2h0S2V5KSB7XG4gICAgICAgICAgICAgIHRoaXMuYWRkVGFncyhbdGFnRGF0YV0sIHRydWUpO1xuICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIGNhc2UgJ1RhYic6XG4gICAgICAgICAge1xuICAgICAgICAgICAgbGV0IHNlbGVjdE1vZGUgPSBfcy5tb2RlID09ICdzZWxlY3QnO1xuICAgICAgICAgICAgaWYgKHMgJiYgIXNlbGVjdE1vZGUpIGUucHJldmVudERlZmF1bHQoKTtlbHNlIHJldHVybiB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgY2FzZSAnRW50ZXInOlxuICAgICAgICAgIC8vIG1hbnVhbCBzdWdnZXN0aW9uIGJveGVzIGFyZSBhc3N1bWVkIHRvIGFsd2F5cyBiZSB2aXNpYmxlXG4gICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSAmJiBfcy5kcm9wZG93bi5wb3NpdGlvbiAhPSAnbWFudWFsJykgcmV0dXJuO1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTsgLy8gc29sdmVzIENocm9tZSBidWcgLSBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8yMDM5ODE5MS8xMDQzODBcbiAgICAgICAgICAvLyBiZWNhdXNlIHRoZSBtYWluIFwia2V5ZG93blwiIGV2ZW50IGlzIGJvdW5kIGJlZm9yZSB0aGUgZHJvcGRvd24gZXZlbnRzLCB0aGlzIHdpbGwgZmlyZSBmaXJzdCBhbmQgd2lsbCBub3QgKnlldCpcbiAgICAgICAgICAvLyBrbm93IGlmIGFuIG9wdGlvbiB3YXMganVzdCBzZWxlY3RlZCBmcm9tIHRoZSBkcm9wZG93biBtZW51LiBJZiBhbiBvcHRpb24gd2FzIHNlbGVjdGVkLFxuICAgICAgICAgIC8vIHRoZSBkcm9wZG93biBldmVudHMgc2hvdWxkIGhhbmRsZSBhZGRpbmcgdGhlIHRhZ1xuICAgICAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSB8fCB0aGlzLnN0YXRlLmFjdGlvbnMuc2VsZWN0T3B0aW9uKSByZXR1cm47XG4gICAgICAgICAgICB0aGlzLmFkZFRhZ3MocywgdHJ1ZSk7XG4gICAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfSxcbiAgICBvbklucHV0KGUpIHtcbiAgICAgIHRoaXMucG9zdFVwZGF0ZSgpOyAvLyB0b2dnbGVzIFwidGFnaWZ5LS1lbXB0eVwiIGNsYXNzXG5cbiAgICAgIHZhciBfcyA9IHRoaXMuc2V0dGluZ3M7XG4gICAgICBpZiAoX3MubW9kZSA9PSAnbWl4JykgcmV0dXJuIHRoaXMuZXZlbnRzLmNhbGxiYWNrcy5vbk1peFRhZ3NJbnB1dC5jYWxsKHRoaXMsIGUpO1xuICAgICAgdmFyIHZhbHVlID0gdGhpcy5pbnB1dC5ub3JtYWxpemUuY2FsbCh0aGlzKSxcbiAgICAgICAgc2hvd1N1Z2dlc3Rpb25zID0gdmFsdWUubGVuZ3RoID49IF9zLmRyb3Bkb3duLmVuYWJsZWQsXG4gICAgICAgIGV2ZW50RGF0YSA9IHtcbiAgICAgICAgICB2YWx1ZSxcbiAgICAgICAgICBpbnB1dEVsbTogdGhpcy5ET00uaW5wdXRcbiAgICAgICAgfSxcbiAgICAgICAgdmFsaWRhdGlvbiA9IHRoaXMudmFsaWRhdGVUYWcoe1xuICAgICAgICAgIHZhbHVlXG4gICAgICAgIH0pO1xuICAgICAgaWYgKF9zLm1vZGUgPT0gJ3NlbGVjdCcpIHtcbiAgICAgICAgdGhpcy50b2dnbGVTY29wZVZhbGlkYXRpb24odmFsaWRhdGlvbik7XG4gICAgICB9XG4gICAgICBldmVudERhdGEuaXNWYWxpZCA9IHZhbGlkYXRpb247XG5cbiAgICAgIC8vIGZvciBJRTsgc2luY2UgSUUgZG9lc24ndCBoYXZlIGFuIFwiaW5wdXRcIiBldmVudCBzbyBcImtleURvd25cIiBpcyB1c2VkIGluc3RlYWQgdG8gdHJpZ2dlciB0aGUgXCJvbklucHV0XCIgY2FsbGJhY2ssXG4gICAgICAvLyBhbmQgc28gbWFueSBrZXlzIGRvIG5vdCBjaGFuZ2UgdGhlIGlucHV0LCBhbmQgZm9yIHRob3NlIGRvIG5vdCBjb250aW51ZS5cbiAgICAgIGlmICh0aGlzLnN0YXRlLmlucHV0VGV4dCA9PSB2YWx1ZSkgcmV0dXJuO1xuXG4gICAgICAvLyBzYXZlIHRoZSB2YWx1ZSBvbiB0aGUgaW5wdXQncyBTdGF0ZSBvYmplY3RcbiAgICAgIHRoaXMuaW5wdXQuc2V0LmNhbGwodGhpcywgdmFsdWUsIGZhbHNlKTsgLy8gdXBkYXRlIHRoZSBpbnB1dCB3aXRoIHRoZSBub3JtYWxpemVkIHZhbHVlIGFuZCBydW4gdmFsaWRhdGlvbnNcbiAgICAgIC8vIHRoaXMuc2V0UmFuZ2VBdFN0YXJ0RW5kKGZhbHNlLCB0aGlzLkRPTS5pbnB1dCk7IC8vIGZpeCBjYXJldCBwb3NpdGlvblxuXG4gICAgICAvLyBpZiBkZWxpbWl0ZXJzIGRldGVjdGVkLCBhZGQgdGFnc1xuICAgICAgaWYgKHZhbHVlLnNlYXJjaChfcy5kZWxpbWl0ZXJzKSAhPSAtMSkge1xuICAgICAgICBpZiAodGhpcy5hZGRUYWdzKHZhbHVlKSkge1xuICAgICAgICAgIHRoaXMuaW5wdXQuc2V0LmNhbGwodGhpcyk7IC8vIGNsZWFyIHRoZSBpbnB1dCBmaWVsZCdzIHZhbHVlXG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoX3MuZHJvcGRvd24uZW5hYmxlZCA+PSAwKSB7XG4gICAgICAgIHRoaXMuZHJvcGRvd25bc2hvd1N1Z2dlc3Rpb25zID8gXCJzaG93XCIgOiBcImhpZGVcIl0odmFsdWUpO1xuICAgICAgfVxuICAgICAgdGhpcy50cmlnZ2VyKCdpbnB1dCcsIGV2ZW50RGF0YSk7IC8vIFwiaW5wdXRcIiBldmVudCBtdXN0IGJlIHRyaWdnZXJlZCBhdCB0aGlzIHBvaW50LCBiZWZvcmUgdGhlIGRyb3Bkb3duIGlzIHNob3duXG4gICAgfSxcblxuICAgIG9uTWl4VGFnc0lucHV0KGUpIHtcbiAgICAgIHZhciByYW5nZVRleHQsXG4gICAgICAgIG1hdGNoLFxuICAgICAgICBtYXRjaGVkUGF0dGVybkNvdW50LFxuICAgICAgICB0YWcsXG4gICAgICAgIHNob3dTdWdnZXN0aW9ucyxcbiAgICAgICAgc2VsZWN0aW9uLFxuICAgICAgICBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICAgIGxhc3RUYWdzQ291bnQgPSB0aGlzLnZhbHVlLmxlbmd0aCxcbiAgICAgICAgbWF0Y2hGbGFnZ2VkVGFnLFxuICAgICAgICBtYXRjaERlbGltaXRlcnMsXG4gICAgICAgIHRhZ3NFbGVtcyA9IHRoaXMuZ2V0VGFnRWxtcygpLFxuICAgICAgICBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxcbiAgICAgICAgcmFuZ2UgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCkuZ2V0UmFuZ2VBdCgwKSxcbiAgICAgICAgcmVtYWluaW5nVGFnc1ZhbHVlcyA9IFtdLm1hcC5jYWxsKHRhZ3NFbGVtcywgbm9kZSA9PiBnZXRTZXRUYWdEYXRhKG5vZGUpLnZhbHVlKTtcblxuICAgICAgLy8gQW5kcm9pZCBDaHJvbWUgXCJrZXlkb3duXCIgZXZlbnQgYXJndW1lbnQgZG9lcyBub3QgcmVwb3J0IHRoZSBjb3JyZWN0IFwia2V5XCIuXG4gICAgICAvLyB0aGlzIHdvcmthcm91bmQgaXMgbmVlZGVkIHRvIG1hbnVhbGx5IGNhbGwgXCJvbktleWRvd25cIiBtZXRob2Qgd2l0aCBhIHN5bnRoZXNpemVkIGV2ZW50IG9iamVjdFxuICAgICAgaWYgKGUuaW5wdXRUeXBlID09IFwiZGVsZXRlQ29udGVudEJhY2t3YXJkXCIgJiYgaXNDaHJvbWVBbmRyb2lkQnJvd3NlcigpKSB7XG4gICAgICAgIHRoaXMuZXZlbnRzLmNhbGxiYWNrcy5vbktleWRvd24uY2FsbCh0aGlzLCB7XG4gICAgICAgICAgdGFyZ2V0OiBlLnRhcmdldCxcbiAgICAgICAgICBrZXk6IFwiQmFja3NwYWNlXCJcbiAgICAgICAgfSk7XG4gICAgICB9XG5cbiAgICAgIC8vIHJlLWFkZCBcInJlYWRvbmx5XCIgdGFncyB3aGljaCBtaWdodCBoYXZlIGJlZW4gcmVtb3ZlZFxuICAgICAgdGhpcy52YWx1ZS5zbGljZSgpLmZvckVhY2goaXRlbSA9PiB7XG4gICAgICAgIGlmIChpdGVtLnJlYWRvbmx5ICYmICFyZW1haW5pbmdUYWdzVmFsdWVzLmluY2x1ZGVzKGl0ZW0udmFsdWUpKSBmcmFnbWVudC5hcHBlbmRDaGlsZCh0aGlzLmNyZWF0ZVRhZ0VsZW0oaXRlbSkpO1xuICAgICAgfSk7XG4gICAgICBpZiAoZnJhZ21lbnQuY2hpbGROb2Rlcy5sZW5ndGgpIHtcbiAgICAgICAgcmFuZ2UuaW5zZXJ0Tm9kZShmcmFnbWVudCk7XG4gICAgICAgIHRoaXMuc2V0UmFuZ2VBdFN0YXJ0RW5kKGZhbHNlLCBmcmFnbWVudC5sYXN0Q2hpbGQpO1xuICAgICAgfVxuXG4gICAgICAvLyBjaGVjayBpZiB0YWdzIHdlcmUgXCJtYWdpY2FsbHlcIiBhZGRlZC9yZW1vdmVkIChicm93c2VyIHJlZG8vdW5kbyBvciBDVFJMLUEgLT4gZGVsZXRlKVxuICAgICAgaWYgKHRhZ3NFbGVtcy5sZW5ndGggIT0gbGFzdFRhZ3NDb3VudCkge1xuICAgICAgICB0aGlzLnZhbHVlID0gW10ubWFwLmNhbGwodGhpcy5nZXRUYWdFbG1zKCksIG5vZGUgPT4gZ2V0U2V0VGFnRGF0YShub2RlKSk7XG4gICAgICAgIHRoaXMudXBkYXRlKHtcbiAgICAgICAgICB3aXRob3V0Q2hhbmdlRXZlbnQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmhhc01heFRhZ3MoKSkgcmV0dXJuIHRydWU7XG4gICAgICBpZiAod2luZG93LmdldFNlbGVjdGlvbikge1xuICAgICAgICBzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG5cbiAgICAgICAgLy8gb25seSBkZXRlY3QgdGFncyBpZiBzZWxlY3Rpb24gaXMgaW5zaWRlIGEgdGV4dE5vZGUgKG5vdCBzb21laG93IG9uIGFscmVhZHktZXhpc3RpbmcgdGFnKVxuICAgICAgICBpZiAoc2VsZWN0aW9uLnJhbmdlQ291bnQgPiAwICYmIHNlbGVjdGlvbi5hbmNob3JOb2RlLm5vZGVUeXBlID09IDMpIHtcbiAgICAgICAgICByYW5nZSA9IHNlbGVjdGlvbi5nZXRSYW5nZUF0KDApLmNsb25lUmFuZ2UoKTtcbiAgICAgICAgICByYW5nZS5jb2xsYXBzZSh0cnVlKTtcbiAgICAgICAgICByYW5nZS5zZXRTdGFydChzZWxlY3Rpb24uZm9jdXNOb2RlLCAwKTtcbiAgICAgICAgICByYW5nZVRleHQgPSByYW5nZS50b1N0cmluZygpLnNsaWNlKDAsIHJhbmdlLmVuZE9mZnNldCk7IC8vIHNsaWNlIHRoZSByYW5nZSBzbyBldmVyeXRoaW5nIEFGVEVSIHRoZSBjYXJldCB3aWxsIGJlIHRyaW1tZWRcbiAgICAgICAgICAvLyBzcGxpdCA9IHJhbmdlLnRvU3RyaW5nKCkuc3BsaXQoX3MubWl4VGFnc0FsbG93ZWRBZnRlcikgIC8vIFtcImZvb1wiLCBcImJhclwiLCBcIkBiYXpcIl1cbiAgICAgICAgICBtYXRjaGVkUGF0dGVybkNvdW50ID0gcmFuZ2VUZXh0LnNwbGl0KF9zLnBhdHRlcm4pLmxlbmd0aCAtIDE7XG4gICAgICAgICAgbWF0Y2ggPSByYW5nZVRleHQubWF0Y2goX3MucGF0dGVybik7XG4gICAgICAgICAgaWYgKG1hdGNoKVxuICAgICAgICAgICAgLy8gdGFnIHN0cmluZywgZXhhbXBsZTogXCJAYWFhIGNjY1wiXG4gICAgICAgICAgICB0YWcgPSByYW5nZVRleHQuc2xpY2UocmFuZ2VUZXh0Lmxhc3RJbmRleE9mKG1hdGNoW21hdGNoLmxlbmd0aCAtIDFdKSk7XG4gICAgICAgICAgaWYgKHRhZykge1xuICAgICAgICAgICAgdGhpcy5zdGF0ZS5hY3Rpb25zLkFycm93TGVmdCA9IGZhbHNlOyAvLyBzdGFydCBmcmVzaCwgYXNzdW1pbmcgdGhlIHVzZXIgZGlkIG5vdCAoeWV0KSB1c2VkIGFueSBhcnJvdyB0byBtb3ZlIHRoZSBjYXJldFxuICAgICAgICAgICAgdGhpcy5zdGF0ZS50YWcgPSB7XG4gICAgICAgICAgICAgIHByZWZpeDogdGFnLm1hdGNoKF9zLnBhdHRlcm4pWzBdLFxuICAgICAgICAgICAgICB2YWx1ZTogdGFnLnJlcGxhY2UoX3MucGF0dGVybiwgJycpIC8vIGdldCByaWQgb2YgdGhlIHByZWZpeFxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgdGhpcy5zdGF0ZS50YWcuYmFzZU9mZnNldCA9IHNlbGVjdGlvbi5iYXNlT2Zmc2V0IC0gdGhpcy5zdGF0ZS50YWcudmFsdWUubGVuZ3RoO1xuICAgICAgICAgICAgbWF0Y2hEZWxpbWl0ZXJzID0gdGhpcy5zdGF0ZS50YWcudmFsdWUubWF0Y2goX3MuZGVsaW1pdGVycyk7XG4gICAgICAgICAgICAvLyBpZiBhIGRlbGltZXRlciBleGlzdHMsIGFkZCB0aGUgdmFsdWUgYXMgdGFnIChleGx1ZGluZyB0aGUgZGVsaW1pdGVyKVxuICAgICAgICAgICAgaWYgKG1hdGNoRGVsaW1pdGVycykge1xuICAgICAgICAgICAgICB0aGlzLnN0YXRlLnRhZy52YWx1ZSA9IHRoaXMuc3RhdGUudGFnLnZhbHVlLnJlcGxhY2UoX3MuZGVsaW1pdGVycywgJycpO1xuICAgICAgICAgICAgICB0aGlzLnN0YXRlLnRhZy5kZWxpbWl0ZXJzID0gbWF0Y2hEZWxpbWl0ZXJzWzBdO1xuICAgICAgICAgICAgICB0aGlzLmFkZFRhZ3ModGhpcy5zdGF0ZS50YWcudmFsdWUsIF9zLmRyb3Bkb3duLmNsZWFyT25TZWxlY3QpO1xuICAgICAgICAgICAgICB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2hvd1N1Z2dlc3Rpb25zID0gdGhpcy5zdGF0ZS50YWcudmFsdWUubGVuZ3RoID49IF9zLmRyb3Bkb3duLmVuYWJsZWQ7XG5cbiAgICAgICAgICAgIC8vIFdoZW4gd3JpdGluZyBzb21ldGhpbmcgdGhhdCBtaWdodCBsb29rIGxpa2UgYSB0YWcgKGFuIGVtYWlsIGFkZHJlc3MpIGJ1dCBpc24ndCBvbmUgLSBpdCBpcyB1bndhbnRlZFxuICAgICAgICAgICAgLy8gdGhlIHN1Z2dlc3Rpb25zIGRyb3Bkb3duIGJlIHNob3duLCBzbyB0aGUgdXNlciBjYW4gY2xvc2UgaXQgKGluIGFueSB3YXkpLCBhbmQgd2hpbGUgY29udGludWUgdHlwaW5nLFxuICAgICAgICAgICAgLy8gZHJvcGRvd24gc2hvdWxkIHN0YXkgY2xvc2VkIHVudGlsIGFub3RoZXIgdGFnIGlzIHR5cGVkLlxuICAgICAgICAgICAgLy8gaWYoIHRoaXMuc3RhdGUudGFnLnZhbHVlLmxlbmd0aCAmJiB0aGlzLnN0YXRlLmRyb3Bkb3duLnZpc2libGUgPT09IGZhbHNlIClcbiAgICAgICAgICAgIC8vICAgICBzaG93U3VnZ2VzdGlvbnMgPSBmYWxzZVxuXG4gICAgICAgICAgICAvLyB0ZXN0IGZvciBzaW1pbGFyIGZsYWdnZWQgdGFncyB0byB0aGUgY3VycmVudCB0YWdcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgbWF0Y2hGbGFnZ2VkVGFnID0gdGhpcy5zdGF0ZS5mbGFnZ2VkVGFnc1t0aGlzLnN0YXRlLnRhZy5iYXNlT2Zmc2V0XTtcbiAgICAgICAgICAgICAgbWF0Y2hGbGFnZ2VkVGFnID0gbWF0Y2hGbGFnZ2VkVGFnLnByZWZpeCA9PSB0aGlzLnN0YXRlLnRhZy5wcmVmaXggJiYgbWF0Y2hGbGFnZ2VkVGFnLnZhbHVlWzBdID09IHRoaXMuc3RhdGUudGFnLnZhbHVlWzBdO1xuXG4gICAgICAgICAgICAgIC8vIHJlc2V0XG4gICAgICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmZsYWdnZWRUYWdzW3RoaXMuc3RhdGUudGFnLmJhc2VPZmZzZXRdICYmICF0aGlzLnN0YXRlLnRhZy52YWx1ZSkgZGVsZXRlIHRoaXMuc3RhdGUuZmxhZ2dlZFRhZ3NbdGhpcy5zdGF0ZS50YWcuYmFzZU9mZnNldF07XG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHt9XG5cbiAgICAgICAgICAgIC8vIHNjZW5hcmlvOiAoZG8gbm90IHNob3cgc3VnZ2VzdGlvbnMgb2YgYW5vdGhlciBtYXRjaGVkIHRhZywgaWYgbW9yZSB0aGFuIG9uZSBkZXRlY3RlZClcbiAgICAgICAgICAgIC8vICgyIHRhZ3MgZXhpc3QpICAgICAgICAgICAgICAgICAgICAgICAgICBcIiBhQGEuY29tIGFuZCBAXCJcbiAgICAgICAgICAgIC8vIChzZWNvbmQgdGFnIGlzIHJlbW92ZWQgYnkgYmFja3NwYWNlKSAgICBcIiBhQGEuY29tIGFuZCBcIlxuICAgICAgICAgICAgaWYgKG1hdGNoRmxhZ2dlZFRhZyB8fCBtYXRjaGVkUGF0dGVybkNvdW50IDwgdGhpcy5zdGF0ZS5taXhNb2RlLm1hdGNoZWRQYXR0ZXJuQ291bnQpIHNob3dTdWdnZXN0aW9ucyA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgICAvLyBubyAocG90ZW50aWFsKSB0YWcgZm91bmRcbiAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuZmxhZ2dlZFRhZ3MgPSB7fTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5zdGF0ZS5taXhNb2RlLm1hdGNoZWRQYXR0ZXJuQ291bnQgPSBtYXRjaGVkUGF0dGVybkNvdW50O1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIHdhaXQgdW50aWwgdGhlIFwidGhpcy52YWx1ZVwiIGhhcyBiZWVuIHVwZGF0ZWQgKHNlZSBcIm9uS2V5ZG93blwiIG1ldGhvZCBmb3IgXCJtaXgtbW9kZVwiKVxuICAgICAgLy8gdGhlIGRyb3Bkb3duIG11c3QgYmUgc2hvd24gb25seSBhZnRlciB0aGlzIGV2ZW50IGhhcyBiZWVuIHRyaWdnZXJlZCwgc28gYW4gaW1wbGVtZW50ZXIgY291bGRcbiAgICAgIC8vIGR5bmFtaWNhbGx5IGNoYW5nZSB0aGUgd2hpdGVsaXN0LlxuICAgICAgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICAgIHRoaXMudXBkYXRlKHtcbiAgICAgICAgICB3aXRob3V0Q2hhbmdlRXZlbnQ6IHRydWVcbiAgICAgICAgfSk7XG4gICAgICAgIHRoaXMudHJpZ2dlcihcImlucHV0XCIsIGV4dGVuZCh7fSwgdGhpcy5zdGF0ZS50YWcsIHtcbiAgICAgICAgICB0ZXh0Q29udGVudDogdGhpcy5ET00uaW5wdXQudGV4dENvbnRlbnRcbiAgICAgICAgfSkpO1xuICAgICAgICBpZiAodGhpcy5zdGF0ZS50YWcpIHRoaXMuZHJvcGRvd25bc2hvd1N1Z2dlc3Rpb25zID8gXCJzaG93XCIgOiBcImhpZGVcIl0odGhpcy5zdGF0ZS50YWcudmFsdWUpO1xuICAgICAgfSwgMTApO1xuICAgIH0sXG4gICAgb25JbnB1dElFKGUpIHtcbiAgICAgIHZhciBfdGhpcyA9IHRoaXM7XG4gICAgICAvLyBmb3IgdGhlIFwiZS50YXJnZXQudGV4dENvbnRlbnRcIiB0byBiZSBjaGFuZ2VkLCB0aGUgYnJvd3NlciByZXF1aXJlcyBhIHNtYWxsIGRlbGF5XG4gICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgX3RoaXMuZXZlbnRzLmNhbGxiYWNrcy5vbklucHV0LmNhbGwoX3RoaXMsIGUpO1xuICAgICAgfSk7XG4gICAgfSxcbiAgICBvYnNlcnZlT3JpZ2luYWxJbnB1dFZhbHVlKCkge1xuICAgICAgLy8gaWYsIGZvciBzb21lIHJlYXNvbiwgdGhlIFRhZ2lmaWVkIGVsZW1lbnQgaXMgbm8gbG9uZ2VyIGluIHRoZSBET00sXG4gICAgICAvLyBjYWxsIHRoZSBcImRlc3Ryb3lcIiBtZXRob2QgdG8ga2lsbCBhbGwgcmVmZXJlbmNlcyB0byB0aW1lb3V0cy9pbnRlcnZhbHNcbiAgICAgIGlmICghdGhpcy5ET00ub3JpZ2luYWxJbnB1dC5wYXJlbnROb2RlKSB0aGlzLmRlc3Ryb3koKTtcblxuICAgICAgLy8gaWYgb3JpZ2luYWwgaW5wdXQgdmFsdWUgY2hhbmdlZCBmb3Igc29tZSByZWFzb24gKGZvciBleG1hcGxlIGEgZm9ybSByZXNldClcbiAgICAgIGlmICh0aGlzLkRPTS5vcmlnaW5hbElucHV0LnZhbHVlICE9IHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQudGFnaWZ5VmFsdWUpIHRoaXMubG9hZE9yaWdpbmFsVmFsdWVzKCk7XG4gICAgfSxcbiAgICBvbkNsaWNrQW55d2hlcmUoZSkge1xuICAgICAgaWYgKGUudGFyZ2V0ICE9IHRoaXMuRE9NLnNjb3BlICYmICF0aGlzLkRPTS5zY29wZS5jb250YWlucyhlLnRhcmdldCkpIHtcbiAgICAgICAgdGhpcy50b2dnbGVGb2N1c0NsYXNzKGZhbHNlKTtcbiAgICAgICAgdGhpcy5zdGF0ZS5oYXNGb2N1cyA9IGZhbHNlO1xuICAgICAgfVxuICAgIH0sXG4gICAgb25DbGlja1Njb3BlKGUpIHtcbiAgICAgIHZhciBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICAgIHRhZ0VsbSA9IGUudGFyZ2V0LmNsb3Nlc3QoJy4nICsgX3MuY2xhc3NOYW1lcy50YWcpLFxuICAgICAgICB0aW1lRGlmZkZvY3VzID0gK25ldyBEYXRlKCkgLSB0aGlzLnN0YXRlLmhhc0ZvY3VzO1xuICAgICAgaWYgKGUudGFyZ2V0ID09IHRoaXMuRE9NLnNjb3BlKSB7XG4gICAgICAgIC8vIGlmKCAhdGhpcy5zdGF0ZS5oYXNGb2N1cyApXG4gICAgICAgIHRoaXMuRE9NLmlucHV0LmZvY3VzKCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH0gZWxzZSBpZiAoZS50YXJnZXQuY2xhc3NMaXN0LmNvbnRhaW5zKF9zLmNsYXNzTmFtZXMudGFnWCkpIHtcbiAgICAgICAgdGhpcy5yZW1vdmVUYWdzKGUudGFyZ2V0LnBhcmVudE5vZGUpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9IGVsc2UgaWYgKHRhZ0VsbSkge1xuICAgICAgICB0aGlzLnRyaWdnZXIoXCJjbGlja1wiLCB7XG4gICAgICAgICAgdGFnOiB0YWdFbG0sXG4gICAgICAgICAgaW5kZXg6IHRoaXMuZ2V0Tm9kZUluZGV4KHRhZ0VsbSksXG4gICAgICAgICAgZGF0YTogZ2V0U2V0VGFnRGF0YSh0YWdFbG0pLFxuICAgICAgICAgIGV2ZW50OiBlXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoX3MuZWRpdFRhZ3MgPT09IDEgfHwgX3MuZWRpdFRhZ3MuY2xpY2tzID09PSAxKSB0aGlzLmV2ZW50cy5jYWxsYmFja3Mub25Eb3VibGVDbGlja1Njb3BlLmNhbGwodGhpcywgZSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gd2hlbiBjbGlja2luZyBvbiB0aGUgaW5wdXQgaXRzZWxmXG4gICAgICBlbHNlIGlmIChlLnRhcmdldCA9PSB0aGlzLkRPTS5pbnB1dCkge1xuICAgICAgICBpZiAoX3MubW9kZSA9PSAnbWl4Jykge1xuICAgICAgICAgIC8vIGZpcmVmb3ggd29uJ3Qgc2hvdyBjYXJldCBpZiBsYXN0IGVsZW1lbnQgaXMgYSB0YWcgKGFuZCBub3QgYSB0ZXh0Tm9kZSksXG4gICAgICAgICAgLy8gc28gYW4gZW1wdHkgdGV4dG5vZGUgc2hvdWxkIGJlIGFkZGVkXG4gICAgICAgICAgdGhpcy5maXhGaXJlZm94TGFzdFRhZ05vQ2FyZXQoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGltZURpZmZGb2N1cyA+IDUwMCkge1xuICAgICAgICAgIGlmICh0aGlzLnN0YXRlLmRyb3Bkb3duLnZpc2libGUpIHRoaXMuZHJvcGRvd24uaGlkZSgpO2Vsc2UgaWYgKF9zLmRyb3Bkb3duLmVuYWJsZWQgPT09IDAgJiYgX3MubW9kZSAhPSAnbWl4JykgdGhpcy5kcm9wZG93bi5zaG93KHRoaXMudmFsdWUubGVuZ3RoID8gJycgOiB1bmRlZmluZWQpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKF9zLm1vZGUgPT0gJ3NlbGVjdCcgJiYgX3MuZHJvcGRvd24uZW5hYmxlZCA9PT0gMCAmJiAhdGhpcy5zdGF0ZS5kcm9wZG93bi52aXNpYmxlKSB0aGlzLmRyb3Bkb3duLnNob3coKTtcbiAgICB9LFxuICAgIC8vIHNwZWNpYWwgcHJvY2Nlc3MgaXMgbmVlZGVkIGZvciBwYXN0ZWQgY29udGVudCBpbiBvcmRlciB0byBcImNsZWFuXCIgaXRcbiAgICBvblBhc3RlKGUpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIHZhciBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICAgIHNlbGVjdE1vZGVXaXRob3V0SW5wdXQgPSBfcy5tb2RlID09ICdzZWxlY3QnICYmIF9zLmVuZm9yY2VXaGl0ZWxpc3Q7XG4gICAgICBpZiAoc2VsZWN0TW9kZVdpdGhvdXRJbnB1dCB8fCAhX3MudXNlcklucHV0KSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHZhciBjbGlwYm9hcmREYXRhLCBwYXN0ZWRUZXh0O1xuICAgICAgaWYgKF9zLnJlYWRvbmx5KSByZXR1cm47XG5cbiAgICAgIC8vIEdldCBwYXN0ZWQgZGF0YSB2aWEgY2xpcGJvYXJkIEFQSVxuICAgICAgY2xpcGJvYXJkRGF0YSA9IGUuY2xpcGJvYXJkRGF0YSB8fCB3aW5kb3cuY2xpcGJvYXJkRGF0YTtcbiAgICAgIHBhc3RlZFRleHQgPSBjbGlwYm9hcmREYXRhLmdldERhdGEoJ1RleHQnKTtcbiAgICAgIF9zLmhvb2tzLmJlZm9yZVBhc3RlKGUsIHtcbiAgICAgICAgdGFnaWZ5OiB0aGlzLFxuICAgICAgICBwYXN0ZWRUZXh0LFxuICAgICAgICBjbGlwYm9hcmREYXRhXG4gICAgICB9KS50aGVuKHJlc3VsdCA9PiB7XG4gICAgICAgIGlmIChyZXN1bHQgPT09IHVuZGVmaW5lZCkgcmVzdWx0ID0gcGFzdGVkVGV4dDtcbiAgICAgICAgaWYgKHJlc3VsdCkge1xuICAgICAgICAgIHRoaXMuaW5qZWN0QXRDYXJldChyZXN1bHQsIHdpbmRvdy5nZXRTZWxlY3Rpb24oKS5nZXRSYW5nZUF0KDApKTtcbiAgICAgICAgICBpZiAodGhpcy5zZXR0aW5ncy5tb2RlID09ICdtaXgnKSB7XG4gICAgICAgICAgICB0aGlzLmV2ZW50cy5jYWxsYmFja3Mub25NaXhUYWdzSW5wdXQuY2FsbCh0aGlzLCBlKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMuc2V0dGluZ3MucGFzdGVBc1RhZ3MpIHtcbiAgICAgICAgICAgIHRoaXMuYWRkVGFncyh0aGlzLnN0YXRlLmlucHV0VGV4dCArIHJlc3VsdCwgdHJ1ZSk7XG4gICAgICAgICAgfSBlbHNlIHRoaXMuc3RhdGUuaW5wdXRUZXh0ID0gcmVzdWx0O1xuICAgICAgICB9XG4gICAgICB9KS5jYXRjaChlcnIgPT4gZXJyKTtcbiAgICB9LFxuICAgIG9uRHJvcChlKSB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfSxcbiAgICBvbkVkaXRUYWdJbnB1dChlZGl0YWJsZUVsbSwgZSkge1xuICAgICAgdmFyIHRhZ0VsbSA9IGVkaXRhYmxlRWxtLmNsb3Nlc3QoJy4nICsgdGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZyksXG4gICAgICAgIHRhZ0VsbUlkeCA9IHRoaXMuZ2V0Tm9kZUluZGV4KHRhZ0VsbSksXG4gICAgICAgIHRhZ0RhdGEgPSBnZXRTZXRUYWdEYXRhKHRhZ0VsbSksXG4gICAgICAgIHRleHRWYWx1ZSA9IHRoaXMuaW5wdXQubm9ybWFsaXplLmNhbGwodGhpcywgZWRpdGFibGVFbG0pLFxuICAgICAgICBkYXRhRm9yQ2hhbmdlZFByb3AgPSB7XG4gICAgICAgICAgW3RoaXMuc2V0dGluZ3MudGFnVGV4dFByb3BdOiB0ZXh0VmFsdWUsXG4gICAgICAgICAgX190YWdJZDogdGFnRGF0YS5fX3RhZ0lkXG4gICAgICAgIH0sXG4gICAgICAgIC8vIFwiX190YWdJZFwiIGlzIG5lZWRlZCBzbyB2YWxpZGF0aW9uIHdpbGwgc2tpcCBjdXJyZW50IHRhZyB3aGVuIGNoZWNraW5nIGZvciBkdXBzXG4gICAgICAgIGlzVmFsaWQgPSB0aGlzLnZhbGlkYXRlVGFnKGRhdGFGb3JDaGFuZ2VkUHJvcCksXG4gICAgICAgIC8vIHRoZSB2YWx1ZSBjb3VsZCBoYXZlIGJlZW4gaW52YWxpZCBpbiB0aGUgZmlyc3QtcGxhY2Ugc28gbWFrZSBzdXJlIHRvIHJlLXZhbGlkYXRlIGl0ICh2aWEgXCJhZGRFbXB0eVRhZ1wiIG1ldGhvZClcbiAgICAgICAgaGFzQ2hhbmdlZCA9IHRoaXMuZWRpdFRhZ0NoYW5nZURldGVjdGVkKGV4dGVuZCh0YWdEYXRhLCBkYXRhRm9yQ2hhbmdlZFByb3ApKTtcblxuICAgICAgLy8gaWYgdGhlIHZhbHVlIGlzIHNhbWUgYXMgYmVmb3JlLWVkaXRpbmcgYW5kIHRoZSB0YWcgd2FzIHZhbGlkIGJlZm9yZSBhcyB3ZWxsLCBpZ25vcmUgdGhlICBjdXJyZW50IFwiaXNWYWxpZFwiIHJlc3VsdCwgd2hpY2ggaXMgZmFsc2UtcG9zaXRpdmVcbiAgICAgIGlmICghaGFzQ2hhbmdlZCAmJiBlZGl0YWJsZUVsbS5vcmlnaW5hbElzVmFsaWQgPT09IHRydWUpIGlzVmFsaWQgPSB0cnVlO1xuICAgICAgdGFnRWxtLmNsYXNzTGlzdC50b2dnbGUodGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ0ludmFsaWQsIGlzVmFsaWQgIT09IHRydWUpO1xuICAgICAgdGFnRGF0YS5fX2lzVmFsaWQgPSBpc1ZhbGlkO1xuICAgICAgdGFnRWxtLnRpdGxlID0gaXNWYWxpZCA9PT0gdHJ1ZSA/IHRhZ0RhdGEudGl0bGUgfHwgdGFnRGF0YS52YWx1ZSA6IGlzVmFsaWQ7IC8vIGNoYW5nZSB0aGUgdGFnJ3MgdGl0bGUgdG8gaW5kaWNhdGUgd2h5IGlzIHRoZSB0YWcgaW52YWxpZCAoaWYgaXQncyBzbylcblxuICAgICAgLy8gc2hvdyBkcm9wZG93biBpZiB0eXBlZCB0ZXh0IGlzIGVxdWFsIG9yIG1vcmUgdGhhbiB0aGUgXCJlbmFibGVkXCIgZHJvcGRvd24gc2V0dGluZ1xuICAgICAgaWYgKHRleHRWYWx1ZS5sZW5ndGggPj0gdGhpcy5zZXR0aW5ncy5kcm9wZG93bi5lbmFibGVkKSB7XG4gICAgICAgIC8vIHRoaXMgY2hlY2sgaXMgbmVlZGVkIGFwcGFyZW50bHkgYmVjYXVzZSBkb2luZyBicm93c2VyIFwidW5kb1wiIHdpbGwgZmlyZVxuICAgICAgICAvLyAgXCJvbkVkaXRUYWdJbnB1dFwiIGJ1dCBcInRoaXMuc3RhdGUuZWRpdGluZ1wiIHdpbGwgYmUgXCJmYWxzZVwiXG4gICAgICAgIGlmICh0aGlzLnN0YXRlLmVkaXRpbmcpIHRoaXMuc3RhdGUuZWRpdGluZy52YWx1ZSA9IHRleHRWYWx1ZTtcbiAgICAgICAgdGhpcy5kcm9wZG93bi5zaG93KHRleHRWYWx1ZSk7XG4gICAgICB9XG4gICAgICB0aGlzLnRyaWdnZXIoXCJlZGl0OmlucHV0XCIsIHtcbiAgICAgICAgdGFnOiB0YWdFbG0sXG4gICAgICAgIGluZGV4OiB0YWdFbG1JZHgsXG4gICAgICAgIGRhdGE6IGV4dGVuZCh7fSwgdGhpcy52YWx1ZVt0YWdFbG1JZHhdLCB7XG4gICAgICAgICAgbmV3VmFsdWU6IHRleHRWYWx1ZVxuICAgICAgICB9KSxcbiAgICAgICAgZXZlbnQ6IGVcbiAgICAgIH0pO1xuICAgIH0sXG4gICAgb25FZGl0VGFnUGFzdGUodGFnRWxtLCBlKSB7XG4gICAgICAvLyBHZXQgcGFzdGVkIGRhdGEgdmlhIGNsaXBib2FyZCBBUElcbiAgICAgIHZhciBjbGlwYm9hcmREYXRhID0gZS5jbGlwYm9hcmREYXRhIHx8IHdpbmRvdy5jbGlwYm9hcmREYXRhLFxuICAgICAgICBwYXN0ZWRUZXh0ID0gY2xpcGJvYXJkRGF0YS5nZXREYXRhKCdUZXh0Jyk7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB2YXIgbmV3Tm9kZSA9IGluamVjdEF0Q2FyZXQocGFzdGVkVGV4dCk7XG4gICAgICB0aGlzLnNldFJhbmdlQXRTdGFydEVuZChmYWxzZSwgbmV3Tm9kZSk7XG4gICAgfSxcbiAgICBvbkVkaXRUYWdGb2N1cyh0YWdFbG0pIHtcbiAgICAgIHRoaXMuc3RhdGUuZWRpdGluZyA9IHtcbiAgICAgICAgc2NvcGU6IHRhZ0VsbSxcbiAgICAgICAgaW5wdXQ6IHRhZ0VsbS5xdWVyeVNlbGVjdG9yKFwiW2NvbnRlbnRlZGl0YWJsZV1cIilcbiAgICAgIH07XG4gICAgfSxcbiAgICBvbkVkaXRUYWdCbHVyKGVkaXRhYmxlRWxtKSB7XG4gICAgICBpZiAoIXRoaXMuc3RhdGUuaGFzRm9jdXMpIHRoaXMudG9nZ2xlRm9jdXNDbGFzcygpO1xuXG4gICAgICAvLyBvbmUgc2NlbmFyaW8gaXMgd2hlbiBzZWxlY3RpbmcgYSBzdWdnZXN0aW9uIGZyb20gdGhlIGRyb3Bkb3duLCB3aGVuIGVkaXRpbmcsIGFuZCBieSBzZWxlY3RpbmcgaXRcbiAgICAgIC8vIHRoZSBcIm9uRWRpdFRhZ0RvbmVcIiBpcyBjYWxsZWQgZGlyZWN0bHksIGFscmVhZHkgcmVwbGFjaW5nIHRoZSB0YWcsIHNvIHRoZSBhcmd1bWVudCBcImVkaXRhYmxlRWxtXCJcbiAgICAgIC8vIG5vZGUgaXNuJ3QgaW4gdGhlIERPTSBhbnlubW9yZSBiZWNhdXNlIGl0IGhhcyBiZWVuIHJlcGxhY2VkLlxuICAgICAgaWYgKCF0aGlzLkRPTS5zY29wZS5jb250YWlucyhlZGl0YWJsZUVsbSkpIHJldHVybjtcbiAgICAgIHZhciBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICAgIHRhZ0VsbSA9IGVkaXRhYmxlRWxtLmNsb3Nlc3QoJy4nICsgX3MuY2xhc3NOYW1lcy50YWcpLFxuICAgICAgICB0YWdEYXRhID0gZ2V0U2V0VGFnRGF0YSh0YWdFbG0pLFxuICAgICAgICB0ZXh0VmFsdWUgPSB0aGlzLmlucHV0Lm5vcm1hbGl6ZS5jYWxsKHRoaXMsIGVkaXRhYmxlRWxtKSxcbiAgICAgICAgZGF0YUZvckNoYW5nZWRQcm9wID0ge1xuICAgICAgICAgIFtfcy50YWdUZXh0UHJvcF06IHRleHRWYWx1ZSxcbiAgICAgICAgICBfX3RhZ0lkOiB0YWdEYXRhLl9fdGFnSWRcbiAgICAgICAgfSxcbiAgICAgICAgLy8gXCJfX3RhZ0lkXCIgaXMgbmVlZGVkIHNvIHZhbGlkYXRpb24gd2lsbCBza2lwIGN1cnJlbnQgdGFnIHdoZW4gY2hlY2tpbmcgZm9yIGR1cHNcbiAgICAgICAgb3JpZ2luYWxEYXRhID0gdGFnRGF0YS5fX29yaWdpbmFsRGF0YSxcbiAgICAgICAgLy8gcHJlLWVkaXQgZGF0YVxuICAgICAgICBoYXNDaGFuZ2VkID0gdGhpcy5lZGl0VGFnQ2hhbmdlRGV0ZWN0ZWQoZXh0ZW5kKHRhZ0RhdGEsIGRhdGFGb3JDaGFuZ2VkUHJvcCkpLFxuICAgICAgICBpc1ZhbGlkID0gdGhpcy52YWxpZGF0ZVRhZyhkYXRhRm9yQ2hhbmdlZFByb3ApLFxuICAgICAgICAvLyBcIl9fdGFnSWRcIiBpcyBuZWVkZWQgc28gdmFsaWRhdGlvbiB3aWxsIHNraXAgY3VycmVudCB0YWcgd2hlbiBjaGVja2luZyBmb3IgZHVwc1xuICAgICAgICBoYXNNYXhUYWdzLFxuICAgICAgICBuZXdUYWdEYXRhO1xuICAgICAgaWYgKCF0ZXh0VmFsdWUpIHtcbiAgICAgICAgdGhpcy5vbkVkaXRUYWdEb25lKHRhZ0VsbSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gaWYgbm90aGluZyBjaGFuZ2VkIHJldmVydCBiYWNrIHRvIGhvdyBpdCB3YXMgYmVmb3JlIGVkaXRpbmdcbiAgICAgIGlmICghaGFzQ2hhbmdlZCkge1xuICAgICAgICB0aGlzLm9uRWRpdFRhZ0RvbmUodGFnRWxtLCBvcmlnaW5hbERhdGEpO1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cbiAgICAgIC8vIG5lZWQgdG8ga25vdyB0aGlzIGJlY2F1c2UgaWYgXCJrZWVwSW52YWxpZFRhZ3NcIiBzZXR0aW5nIGlzIFwidHJ1ZVwiIGFuZCBhbiBpbnZhbGlkIHRhZyBpcyBlZGl0ZWQgYXMgYSB2YWxpZCBvbmUsXG4gICAgICAvLyBidXQgdGhlIG1heGltdW0gbnVtYmVyIG9mIHRhZ3MgaGF2ZSBhbHJlYXkgYmVlbiByZWFjaGVkLCBzbyBpdCBzaG91bGQgbm90IGFsbG93IHNhdmluZyB0aGUgbmV3IHZhbGlkIHZhbHVlLlxuICAgICAgLy8gb25seSBpZiB0aGUgdGFnIHdhcyBhbHJlYWR5IHZhbGlkIGJlZm9yZSBlZGl0aW5nLCBpZ25vcmUgdGhpcyBjaGVjayAoc2VlIGEgZmV3IGxpbmVzIGJlbG93KVxuICAgICAgaGFzTWF4VGFncyA9IHRoaXMuaGFzTWF4VGFncygpO1xuICAgICAgbmV3VGFnRGF0YSA9IGV4dGVuZCh7fSwgb3JpZ2luYWxEYXRhLCB7XG4gICAgICAgIFtfcy50YWdUZXh0UHJvcF06IHRoaXMudHJpbSh0ZXh0VmFsdWUpLFxuICAgICAgICBfX2lzVmFsaWQ6IGlzVmFsaWRcbiAgICAgIH0pO1xuXG4gICAgICAvLyBwYXNzIHRocm91Z2ggb3B0aW9uYWwgdHJhbnNmb3JtZXIgZGVmaW5lZCBpbiBzZXR0aW5nc1xuICAgICAgX3MudHJhbnNmb3JtVGFnLmNhbGwodGhpcywgbmV3VGFnRGF0YSwgb3JpZ2luYWxEYXRhKTtcblxuICAgICAgLy8gTVVTVCByZS12YWxpZGF0ZSBhZnRlciB0YWcgdHJhbnNmb3JtYXRpb25cbiAgICAgIC8vIG9ubHkgdmFsaWRhdGUgdGhlIFwidGFnVGV4dFByb3BcIiBiZWNhdXNlIGlzIHRoZSBvbmx5IHRoaW5nIHRoYXQgbWV0dGVycyBmb3IgdmFsaWRhdGluZyBhbiBlZGl0ZWQgdGFnLlxuICAgICAgLy8gLS0gU2NlbmFyaW9zOiAtLVxuICAgICAgLy8gMS4gbWF4IDMgdGFncyBhbGxvd2QuIHRoZXJlIGFyZSA0IHRhZ3MsIG9uZSBoYXMgaW52YWxpZCBpbnB1dCBhbmQgaXMgZWRpdGVkIHRvIGEgdmFsaWQgb25lLCBhbmQgbm93IHNob3VsZCBiZSBtYXJrZWQgYXMgXCJub3QgYWxsb3dlZFwiIGJlY2F1c2UgbGltaXQgb2YgdGFncyBoYXMgcmVhY2hlZFxuICAgICAgLy8gMi4gbWF4IDMgdGFncyBhbGxvd2VkLiB0aGVyZSBhcmUgMyB0YWdzLCBvbmUgaXMgZWRpdGVkLCBhbmQgc28gbWF4LXRhZ3MgdmFpbGRhdGlvbiBzaG91bGQgYmUgT0tcbiAgICAgIGlzVmFsaWQgPSAoIWhhc01heFRhZ3MgfHwgb3JpZ2luYWxEYXRhLl9faXNWYWxpZCA9PT0gdHJ1ZSkgJiYgdGhpcy52YWxpZGF0ZVRhZyhuZXdUYWdEYXRhKTtcbiAgICAgIGlmIChpc1ZhbGlkICE9PSB0cnVlKSB7XG4gICAgICAgIHRoaXMudHJpZ2dlcihcImludmFsaWRcIiwge1xuICAgICAgICAgIGRhdGE6IG5ld1RhZ0RhdGEsXG4gICAgICAgICAgdGFnOiB0YWdFbG0sXG4gICAgICAgICAgbWVzc2FnZTogaXNWYWxpZFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBkbyBub3RoaW5nIGlmIGludmFsaWQsIHN0YXkgaW4gZWRpdC1tb2RlIHVudGlsIGNvcnJlY3RlZCBvciByZXZlcnRlZCBieSBwcmVzc3NpbmcgZXNjXG4gICAgICAgIGlmIChfcy5lZGl0VGFncy5rZWVwSW52YWxpZCkgcmV0dXJuO1xuICAgICAgICBpZiAoX3Mua2VlcEludmFsaWRUYWdzKSBuZXdUYWdEYXRhLl9faXNWYWxpZCA9IGlzVmFsaWQ7ZWxzZVxuICAgICAgICAgIC8vIHJldmVydCBiYWNrIGlmIG5vdCBzcGVjaWZpZWQgdG8ga2VlcFxuICAgICAgICAgIG5ld1RhZ0RhdGEgPSBvcmlnaW5hbERhdGE7XG4gICAgICB9IGVsc2UgaWYgKF9zLmtlZXBJbnZhbGlkVGFncykge1xuICAgICAgICAvLyBjbGVhdXAgYW55IHByZXZpb3VzIGxlZnRvdmVycyBpZiB0aGUgdGFnIHdhcyBpbnZhbGlkXG4gICAgICAgIGRlbGV0ZSBuZXdUYWdEYXRhLnRpdGxlO1xuICAgICAgICBkZWxldGUgbmV3VGFnRGF0YVtcImFyaWEtaW52YWxpZFwiXTtcbiAgICAgICAgZGVsZXRlIG5ld1RhZ0RhdGEuY2xhc3M7XG4gICAgICB9XG5cbiAgICAgIC8vIHRhZ0VsbS5jbGFzc0xpc3QudG9nZ2xlKF9zLmNsYXNzTmFtZXMudGFnSW52YWxpZCwgdHJ1ZSlcblxuICAgICAgdGhpcy5vbkVkaXRUYWdEb25lKHRhZ0VsbSwgbmV3VGFnRGF0YSk7XG4gICAgfSxcbiAgICBvbkVkaXRUYWdrZXlkb3duKGUsIHRhZ0VsbSkge1xuICAgICAgLy8gaWdub3JlIGtleXMgZHVyaW5nIElNRSBjb21wb3NpdGlvblxuICAgICAgaWYgKHRoaXMuc3RhdGUuY29tcG9zaW5nKSByZXR1cm47XG4gICAgICB0aGlzLnRyaWdnZXIoXCJlZGl0OmtleWRvd25cIiwge1xuICAgICAgICBldmVudDogZVxuICAgICAgfSk7XG4gICAgICBzd2l0Y2ggKGUua2V5KSB7XG4gICAgICAgIGNhc2UgJ0VzYyc6XG4gICAgICAgIGNhc2UgJ0VzY2FwZSc6XG4gICAgICAgICAge1xuICAgICAgICAgICAgLy8gcmV2ZXJ0IHRoZSB0YWcgdG8gaG93IGl0IHdhcyBiZWZvcmUgZWRpdGluZ1xuICAgICAgICAgICAgLy8gcmVwbGFjZSBjdXJyZW50IHRhZyB3aXRoIG9yaWdpbmFsIG9uZSAocHJlLWVkaXRlZCBvbmUpXG4gICAgICAgICAgICB0YWdFbG0ucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQodGFnRWxtLl9fdGFnaWZ5VGFnRGF0YS5fX29yaWdpbmFsSFRNTCwgdGFnRWxtKTtcbiAgICAgICAgICAgIHRoaXMuc3RhdGUuZWRpdGluZyA9IGZhbHNlO1xuICAgICAgICAgIH1cbiAgICAgICAgY2FzZSAnRW50ZXInOlxuICAgICAgICBjYXNlICdUYWInOlxuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICBlLnRhcmdldC5ibHVyKCk7XG4gICAgICB9XG4gICAgfSxcbiAgICBvbkRvdWJsZUNsaWNrU2NvcGUoZSkge1xuICAgICAgdmFyIHRhZ0VsbSA9IGUudGFyZ2V0LmNsb3Nlc3QoJy4nICsgdGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZyksXG4gICAgICAgIHRhZ0RhdGEgPSBnZXRTZXRUYWdEYXRhKHRhZ0VsbSksXG4gICAgICAgIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgICAgaXNFZGl0aW5nVGFnLFxuICAgICAgICBpc1JlYWR5T25seVRhZztcbiAgICAgIGlmICghdGFnRWxtIHx8ICFfcy51c2VySW5wdXQgfHwgdGFnRGF0YS5lZGl0YWJsZSA9PT0gZmFsc2UpIHJldHVybjtcbiAgICAgIGlzRWRpdGluZ1RhZyA9IHRhZ0VsbS5jbGFzc0xpc3QuY29udGFpbnModGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ0VkaXRpbmcpO1xuICAgICAgaXNSZWFkeU9ubHlUYWcgPSB0YWdFbG0uaGFzQXR0cmlidXRlKCdyZWFkb25seScpO1xuICAgICAgaWYgKF9zLm1vZGUgIT0gJ3NlbGVjdCcgJiYgIV9zLnJlYWRvbmx5ICYmICFpc0VkaXRpbmdUYWcgJiYgIWlzUmVhZHlPbmx5VGFnICYmIHRoaXMuc2V0dGluZ3MuZWRpdFRhZ3MpIHRoaXMuZWRpdFRhZyh0YWdFbG0pO1xuICAgICAgdGhpcy50b2dnbGVGb2N1c0NsYXNzKHRydWUpO1xuICAgICAgdGhpcy50cmlnZ2VyKCdkYmxjbGljaycsIHtcbiAgICAgICAgdGFnOiB0YWdFbG0sXG4gICAgICAgIGluZGV4OiB0aGlzLmdldE5vZGVJbmRleCh0YWdFbG0pLFxuICAgICAgICBkYXRhOiBnZXRTZXRUYWdEYXRhKHRhZ0VsbSlcbiAgICAgIH0pO1xuICAgIH0sXG4gICAgLyoqXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IG0gYW4gb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgb2JzZXJ2ZWQgRE9NIGNoYW5nZXNcclxuICAgICAqL1xuICAgIG9uSW5wdXRET01DaGFuZ2UobSkge1xuICAgICAgLy8gaXRlcmF0ZSBhbGwgRE9tIG11dGF0aW9uXG4gICAgICBtLmZvckVhY2gocmVjb3JkID0+IHtcbiAgICAgICAgLy8gb25seSB0aGUgQURERUQgbm9kZXNcbiAgICAgICAgcmVjb3JkLmFkZGVkTm9kZXMuZm9yRWFjaChhZGRlZE5vZGUgPT4ge1xuICAgICAgICAgIC8vIGZpeCBjaHJvbWUncyBwbGFjaW5nICc8ZGl2Pjxicj48L2Rpdj4nIGV2ZXJ5dGltZSBFTlRFUiBrZXkgaXMgcHJlc3NlZCwgYW5kIHJlcGxhY2Ugd2l0aCBqdXN0IGA8YnInXG4gICAgICAgICAgaWYgKGFkZGVkTm9kZS5vdXRlckhUTUwgPT0gJzxkaXY+PGJyPjwvZGl2PicpIHtcbiAgICAgICAgICAgIGFkZGVkTm9kZS5yZXBsYWNlV2l0aChkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdicicpKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBpZiB0aGUgYWRkZWQgZWxlbWVudCBpcyBhIGRpdiBjb250YWluaW5nIGEgdGFnIHdpdGhpbiBpdCAoY2hyb21lIGRvZXMgdGhpcyB3aGVuIHByZXNzaW5nIEVOVEVSIGJlZm9yZSBhIHRhZylcbiAgICAgICAgICBlbHNlIGlmIChhZGRlZE5vZGUubm9kZVR5cGUgPT0gMSAmJiBhZGRlZE5vZGUucXVlcnlTZWxlY3Rvcih0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMudGFnU2VsZWN0b3IpKSB7XG4gICAgICAgICAgICBsZXQgbmV3bGluZVRleHQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnJyk7XG4gICAgICAgICAgICBpZiAoYWRkZWROb2RlLmNoaWxkTm9kZXNbMF0ubm9kZVR5cGUgPT0gMyAmJiBhZGRlZE5vZGUucHJldmlvdXNTaWJsaW5nLm5vZGVOYW1lICE9ICdCUicpIG5ld2xpbmVUZXh0ID0gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoJ1xcbicpO1xuXG4gICAgICAgICAgICAvLyB1bndyYXAgdGhlIHVzZWxlc3MgZGl2XG4gICAgICAgICAgICAvLyBjaHJvbWUgYWRkcyBhIEJSIGF0IHRoZSBlbmQgd2hpY2ggc2hvdWxkIGJlIHJlbW92ZWRcbiAgICAgICAgICAgIGFkZGVkTm9kZS5yZXBsYWNlV2l0aCguLi5bbmV3bGluZVRleHQsIC4uLlsuLi5hZGRlZE5vZGUuY2hpbGROb2Rlc10uc2xpY2UoMCwgLTEpXSk7XG4gICAgICAgICAgICB0aGlzLnBsYWNlQ2FyZXRBZnRlck5vZGUobmV3bGluZVRleHQpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIGlmIHRoaXMgaXMgYSB0YWdcbiAgICAgICAgICBlbHNlIGlmIChpc05vZGVUYWcuY2FsbCh0aGlzLCBhZGRlZE5vZGUpKSB7XG4gICAgICAgICAgICBpZiAoYWRkZWROb2RlLnByZXZpb3VzU2libGluZz8ubm9kZVR5cGUgPT0gMyAmJiAhYWRkZWROb2RlLnByZXZpb3VzU2libGluZy50ZXh0Q29udGVudCkgYWRkZWROb2RlLnByZXZpb3VzU2libGluZy5yZW1vdmUoKTtcbiAgICAgICAgICAgIC8vIGFuZCBpdCBpcyB0aGUgZmlyc3Qgbm9kZSBpbiBhIG5ldyBsaW5lXG4gICAgICAgICAgICBpZiAoYWRkZWROb2RlLnByZXZpb3VzU2libGluZyAmJiBhZGRlZE5vZGUucHJldmlvdXNTaWJsaW5nLm5vZGVOYW1lID09ICdCUicpIHtcbiAgICAgICAgICAgICAgLy8gYWxsb3dzIHBsYWNpbmcgdGhlIGNhcmV0IGp1c3QgYmVmb3JlIHRoZSB0YWcsIHdoZW4gdGhlIHRhZyBpcyB0aGUgZmlyc3Qgbm9kZSBpbiB0aGF0IGxpbmVcbiAgICAgICAgICAgICAgYWRkZWROb2RlLnByZXZpb3VzU2libGluZy5yZXBsYWNlV2l0aCgnXFxuXFx1MjAwQicpO1xuICAgICAgICAgICAgICBsZXQgbmV4dE5vZGUgPSBhZGRlZE5vZGUubmV4dFNpYmxpbmcsXG4gICAgICAgICAgICAgICAgYW55dGhpbmdBZnRlck5vZGUgPSAnJztcbiAgICAgICAgICAgICAgd2hpbGUgKG5leHROb2RlKSB7XG4gICAgICAgICAgICAgICAgYW55dGhpbmdBZnRlck5vZGUgKz0gbmV4dE5vZGUudGV4dENvbnRlbnQ7XG4gICAgICAgICAgICAgICAgbmV4dE5vZGUgPSBuZXh0Tm9kZS5uZXh0U2libGluZztcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIHdoZW4gaGl0dGluZyBFTlRFUiBmb3IgbmV3IGxpbmUganVzdCBiZWZvcmUgYW4gZXhpc3RpbmcgdGFnLCBidXQgc2tpcCBiZWxvdyBsb2dpYyB3aGVuIGEgdGFnIGhhcyBiZWVuIGFkZGRlZFxuICAgICAgICAgICAgICBhbnl0aGluZ0FmdGVyTm9kZS50cmltKCkgJiYgdGhpcy5wbGFjZUNhcmV0QWZ0ZXJOb2RlKGFkZGVkTm9kZS5wcmV2aW91c1NpYmxpbmcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHJlY29yZC5yZW1vdmVkTm9kZXMuZm9yRWFjaChyZW1vdmVkTm9kZSA9PiB7XG4gICAgICAgICAgLy8gd2hlbiB0cnlpbmcgdG8gZGVsZXRlIGEgdGFnIHdoaWNoIGlzIGluIGEgbmV3IGxpbmUgYW5kIHRoZXJlJ3Mgbm90aGluZyBlbHNlIHRoZXJlIChjYXJldCBpcyBhZnRlciB0aGUgdGFnKVxuICAgICAgICAgIGlmIChyZW1vdmVkTm9kZSAmJiByZW1vdmVkTm9kZS5ub2RlTmFtZSA9PSAnQlInICYmIGlzTm9kZVRhZy5jYWxsKHRoaXMsIGxhc3RJbnB1dENoaWxkKSkge1xuICAgICAgICAgICAgdGhpcy5yZW1vdmVUYWdzKGxhc3RJbnB1dENoaWxkKTtcbiAgICAgICAgICAgIHRoaXMuZml4RmlyZWZveExhc3RUYWdOb0NhcmV0KCk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuXG4gICAgICAvLyBnZXQgdGhlIGxhc3QgY2hpbGQgb25seSBhZnRlciB0aGUgYWJvdmUgRE9NIG1vZGlmaWNhdGlvbnNcbiAgICAgIC8vIGNoZWNrIHRoZXNlIHNjZW5hcmlvczpcbiAgICAgIC8vIDEuIGFmdGVyIGEgc2luZ2xlIGxpbmUsIHByZXNzIEVOVEVSIG9uY2UgLSBzaG91bGQgYWRkIG9ubHkgMSBCUlxuICAgICAgLy8gMi4gcHJlc3NzIEVOVEVSIHJpZ2h0IGJlZm9yZSBhIHRhZ1xuICAgICAgLy8gMy4gcHJlc3MgZW50ZXIgd2l0aGluIGEgdGV4dCBub2RlIGJlZm9yZSBhIHRhZ1xuICAgICAgdmFyIGxhc3RJbnB1dENoaWxkID0gdGhpcy5ET00uaW5wdXQubGFzdENoaWxkO1xuICAgICAgaWYgKGxhc3RJbnB1dENoaWxkICYmIGxhc3RJbnB1dENoaWxkLm5vZGVWYWx1ZSA9PSAnJykgbGFzdElucHV0Q2hpbGQucmVtb3ZlKCk7XG5cbiAgICAgIC8vIG1ha2Ugc3VyZSB0aGUgbGFzdCBlbGVtZW50IGlzIGFsd2F5cyBhIEJSXG4gICAgICBpZiAoIWxhc3RJbnB1dENoaWxkIHx8IGxhc3RJbnB1dENoaWxkLm5vZGVOYW1lICE9ICdCUicpIHtcbiAgICAgICAgdGhpcy5ET00uaW5wdXQuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYnInKSk7XG4gICAgICB9XG4gICAgfVxuICB9XG59O1xuXG4vKipcclxuICogQGNvbnN0cnVjdG9yXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbnB1dCAgICBET00gZWxlbWVudFxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3Mgc2V0dGluZ3Mgb2JqZWN0XHJcbiAqL1xuZnVuY3Rpb24gVGFnaWZ5KGlucHV0LCBzZXR0aW5ncykge1xuICBpZiAoIWlucHV0KSB7XG4gICAgY29uc29sZS53YXJuKCdUYWdpZnk6JywgJ2lucHV0IGVsZW1lbnQgbm90IGZvdW5kJywgaW5wdXQpO1xuICAgIC8vIHJldHVybiBhbiBlbXB0eSBtb2NrIG9mIGFsbCBtZXRob2RzLCBzbyB0aGUgY29kZSB1c2luZyB0YWdpZnkgd2lsbCBub3QgYnJlYWtcbiAgICAvLyBiZWNhdXNlIGl0IG1pZ2h0IGJlIGNhbGxpbmcgbWV0aG9kcyBldmVuIHRob3VnaCB0aGUgaW5wdXQgZWxlbWVudCBkb2VzIG5vdCBleGlzdFxuICAgIGNvbnN0IG1vY2tJbnN0YW5jZSA9IG5ldyBQcm94eSh0aGlzLCB7XG4gICAgICBnZXQoKSB7XG4gICAgICAgIHJldHVybiAoKSA9PiBtb2NrSW5zdGFuY2U7XG4gICAgICB9XG4gICAgfSk7XG4gICAgcmV0dXJuIG1vY2tJbnN0YW5jZTtcbiAgfVxuICBpZiAoaW5wdXQuX190YWdpZnkpIHtcbiAgICBjb25zb2xlLndhcm4oJ1RhZ2lmeTogJywgJ2lucHV0IGVsZW1lbnQgaXMgYWxyZWFkeSBUYWdpZmllZCAtIFNhbWUgaW5zdGFuY2UgaXMgcmV0dXJuZWQuJywgaW5wdXQpO1xuICAgIHJldHVybiBpbnB1dC5fX3RhZ2lmeTtcbiAgfVxuICBleHRlbmQodGhpcywgRXZlbnREaXNwYXRjaGVyKHRoaXMpKTtcbiAgdGhpcy5pc0ZpcmVmb3ggPSAvZmlyZWZveHxmeGlvcy9pLnRlc3QobmF2aWdhdG9yLnVzZXJBZ2VudCkgJiYgIS9zZWFtb25rZXkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuICB0aGlzLmlzSUUgPSB3aW5kb3cuZG9jdW1lbnQuZG9jdW1lbnRNb2RlOyAvLyBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi1VUy9kb2NzL1dlYi9BUEkvRG9jdW1lbnQvY29tcGF0TW9kZSNCcm93c2VyX2NvbXBhdGliaWxpdHlcblxuICBzZXR0aW5ncyA9IHNldHRpbmdzIHx8IHt9O1xuICB0aGlzLmdldFBlcnNpc3RlZERhdGEgPSBnZXRQZXJzaXN0ZWREYXRhKHNldHRpbmdzLmlkKTtcbiAgdGhpcy5zZXRQZXJzaXN0ZWREYXRhID0gc2V0UGVyc2lzdGVkRGF0YShzZXR0aW5ncy5pZCk7XG4gIHRoaXMuY2xlYXJQZXJzaXN0ZWREYXRhID0gY2xlYXJQZXJzaXN0ZWREYXRhKHNldHRpbmdzLmlkKTtcbiAgdGhpcy5hcHBseVNldHRpbmdzKGlucHV0LCBzZXR0aW5ncyk7XG4gIHRoaXMuc3RhdGUgPSB7XG4gICAgaW5wdXRUZXh0OiAnJyxcbiAgICBlZGl0aW5nOiBmYWxzZSxcbiAgICBjb21wb3Npbmc6IGZhbHNlLFxuICAgIGFjdGlvbnM6IHt9LFxuICAgIC8vIFVJIGFjdGlvbnMgZm9yIHN0YXRlLWxvY2tpbmdcbiAgICBtaXhNb2RlOiB7fSxcbiAgICBkcm9wZG93bjoge30sXG4gICAgZmxhZ2dlZFRhZ3M6IHt9IC8vIGluIG1peC1tb2RlLCB3aGVuIGEgc3RyaW5nIGlzIGRldGV0Y2VkIGFzIHBvdGVudGlhbCB0YWcsIGFuZCB0aGUgdXNlciBoYXMgY2hvY2VuIHRvIGNsb3NlIHRoZSBzdWdnZXN0aW9ucyBkcm9wZG93biwga2VlcCB0aGUgcmVjb3JkIG9mIHRoZSB0YXNnIGhlcmVcbiAgfTtcblxuICB0aGlzLnZhbHVlID0gW107IC8vIHRhZ3MnIGRhdGFcblxuICAvLyBldmVudHMnIGNhbGxiYWNrcyByZWZlcmVuY2VzIHdpbGwgYmUgc3RvcmVzIGhlcmUsIHNvIGV2ZW50cyBjb3VsZCBiZSB1bmJpbmRlZFxuICB0aGlzLmxpc3RlbmVycyA9IHt9O1xuICB0aGlzLkRPTSA9IHt9OyAvLyBTdG9yZSBhbGwgcmVsZXZhbnQgRE9NIGVsZW1lbnRzIGluIGFuIE9iamVjdFxuXG4gIHRoaXMuYnVpbGQoaW5wdXQpO1xuICBpbml0RHJvcGRvd24uY2FsbCh0aGlzKTtcbiAgdGhpcy5nZXRDU1NWYXJzKCk7XG4gIHRoaXMubG9hZE9yaWdpbmFsVmFsdWVzKCk7XG4gIHRoaXMuZXZlbnRzLmN1c3RvbUJpbmRpbmcuY2FsbCh0aGlzKTtcbiAgdGhpcy5ldmVudHMuYmluZGluZy5jYWxsKHRoaXMpO1xuICBpbnB1dC5hdXRvZm9jdXMgJiYgdGhpcy5ET00uaW5wdXQuZm9jdXMoKTtcbiAgaW5wdXQuX190YWdpZnkgPSB0aGlzO1xufVxuVGFnaWZ5LnByb3RvdHlwZSA9IHtcbiAgX2Ryb3Bkb3duLFxuICBnZXRTZXRUYWdEYXRhLFxuICBoZWxwZXJzOiB7XG4gICAgc2FtZVN0cixcbiAgICByZW1vdmVDb2xsZWN0aW9uUHJvcCxcbiAgICBvbWl0LFxuICAgIGlzT2JqZWN0LFxuICAgIHBhcnNlSFRNTCxcbiAgICBlc2NhcGVIVE1MLFxuICAgIGV4dGVuZCxcbiAgICBjb25jYXRXaXRob3V0RHVwcyxcbiAgICBnZXRVSUQsXG4gICAgaXNOb2RlVGFnXG4gIH0sXG4gIGN1c3RvbUV2ZW50c0xpc3Q6IFsnY2hhbmdlJywgJ2FkZCcsICdyZW1vdmUnLCAnaW52YWxpZCcsICdpbnB1dCcsICdjbGljaycsICdrZXlkb3duJywgJ2ZvY3VzJywgJ2JsdXInLCAnZWRpdDppbnB1dCcsICdlZGl0OmJlZm9yZVVwZGF0ZScsICdlZGl0OnVwZGF0ZWQnLCAnZWRpdDpzdGFydCcsICdlZGl0OmtleWRvd24nLCAnZHJvcGRvd246c2hvdycsICdkcm9wZG93bjpoaWRlJywgJ2Ryb3Bkb3duOnNlbGVjdCcsICdkcm9wZG93bjp1cGRhdGVkJywgJ2Ryb3Bkb3duOm5vTWF0Y2gnLCAnZHJvcGRvd246c2Nyb2xsJ10sXG4gIGRhdGFQcm9wczogWydfX2lzVmFsaWQnLCAnX19yZW1vdmVkJywgJ19fb3JpZ2luYWxEYXRhJywgJ19fb3JpZ2luYWxIVE1MJywgJ19fdGFnSWQnXSxcbiAgLy8gaW50ZXJuYWwtdWFzZ2UgcHJvcHNcblxuICB0cmltKHRleHQpIHtcbiAgICByZXR1cm4gdGhpcy5zZXR0aW5ncy50cmltICYmIHRleHQgJiYgdHlwZW9mIHRleHQgPT0gXCJzdHJpbmdcIiA/IHRleHQudHJpbSgpIDogdGV4dDtcbiAgfSxcbiAgLy8gZXhwb3NlIHRoaXMgaGFuZHkgdXRpbGl0eSBmdW5jdGlvblxuICBwYXJzZUhUTUwsXG4gIHRlbXBsYXRlcyxcbiAgcGFyc2VUZW1wbGF0ZSh0ZW1wbGF0ZSwgZGF0YSkge1xuICAgIHRlbXBsYXRlID0gdGhpcy5zZXR0aW5ncy50ZW1wbGF0ZXNbdGVtcGxhdGVdIHx8IHRlbXBsYXRlO1xuICAgIHJldHVybiBwYXJzZUhUTUwodGVtcGxhdGUuYXBwbHkodGhpcywgZGF0YSkpO1xuICB9LFxuICBzZXQgd2hpdGVsaXN0KGFycikge1xuICAgIGNvbnN0IGlzQXJyYXkgPSBhcnIgJiYgQXJyYXkuaXNBcnJheShhcnIpO1xuICAgIHRoaXMuc2V0dGluZ3Mud2hpdGVsaXN0ID0gaXNBcnJheSA/IGFyciA6IFtdO1xuICAgIHRoaXMuc2V0UGVyc2lzdGVkRGF0YShpc0FycmF5ID8gYXJyIDogW10sICd3aGl0ZWxpc3QnKTtcbiAgfSxcbiAgZ2V0IHdoaXRlbGlzdCgpIHtcbiAgICByZXR1cm4gdGhpcy5zZXR0aW5ncy53aGl0ZWxpc3Q7XG4gIH0sXG4gIGdlbmVyYXRlQ2xhc3NTZWxlY3RvcnMoY2xhc3NOYW1lcykge1xuICAgIGZvciAobGV0IG5hbWUgaW4gY2xhc3NOYW1lcykge1xuICAgICAgbGV0IGN1cnJlbnROYW1lID0gbmFtZTtcbiAgICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShjbGFzc05hbWVzLCBjdXJyZW50TmFtZSArIFwiU2VsZWN0b3JcIiwge1xuICAgICAgICBnZXQoKSB7XG4gICAgICAgICAgcmV0dXJuIFwiLlwiICsgdGhpc1tjdXJyZW50TmFtZV0uc3BsaXQoXCIgXCIpWzBdO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9XG4gIH0sXG4gIGFwcGx5U2V0dGluZ3MoaW5wdXQsIHNldHRpbmdzKSB7XG4gICAgREVGQVVMVFMudGVtcGxhdGVzID0gdGhpcy50ZW1wbGF0ZXM7XG4gICAgdmFyIG1peE1vZGVEZWZhdWx0cyA9IHtcbiAgICAgIGRyb3Bkb3duOiB7XG4gICAgICAgIHBvc2l0aW9uOiBcInRleHRcIlxuICAgICAgfVxuICAgIH07XG4gICAgdmFyIG1lcmdlZERlZmF1bHRzID0gZXh0ZW5kKHt9LCBERUZBVUxUUywgc2V0dGluZ3MubW9kZSA9PSAnbWl4JyA/IG1peE1vZGVEZWZhdWx0cyA6IHt9KTtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzID0gZXh0ZW5kKHt9LCBtZXJnZWREZWZhdWx0cywgc2V0dGluZ3MpO1xuICAgIF9zLmRpc2FibGVkID0gaW5wdXQuaGFzQXR0cmlidXRlKCdkaXNhYmxlZCcpO1xuICAgIF9zLnJlYWRvbmx5ID0gX3MucmVhZG9ubHkgfHwgaW5wdXQuaGFzQXR0cmlidXRlKCdyZWFkb25seScpO1xuICAgIF9zLnBsYWNlaG9sZGVyID0gZXNjYXBlSFRNTChpbnB1dC5nZXRBdHRyaWJ1dGUoJ3BsYWNlaG9sZGVyJykgfHwgX3MucGxhY2Vob2xkZXIgfHwgXCJcIik7XG4gICAgX3MucmVxdWlyZWQgPSBpbnB1dC5oYXNBdHRyaWJ1dGUoJ3JlcXVpcmVkJyk7XG4gICAgdGhpcy5nZW5lcmF0ZUNsYXNzU2VsZWN0b3JzKF9zLmNsYXNzTmFtZXMpO1xuICAgIGlmIChfcy5kcm9wZG93bi5pbmNsdWRlU2VsZWN0ZWRUYWdzID09PSB1bmRlZmluZWQpIF9zLmRyb3Bkb3duLmluY2x1ZGVTZWxlY3RlZFRhZ3MgPSBfcy5kdXBsaWNhdGVzO1xuICAgIGlmICh0aGlzLmlzSUUpIF9zLmF1dG9Db21wbGV0ZSA9IGZhbHNlOyAvLyBJRSBnb2VzIGNyYXp5IGlmIHRoaXMgaXNuJ3QgZmFsc2VcblxuICAgIFtcIndoaXRlbGlzdFwiLCBcImJsYWNrbGlzdFwiXS5mb3JFYWNoKG5hbWUgPT4ge1xuICAgICAgdmFyIGF0dHJWYWwgPSBpbnB1dC5nZXRBdHRyaWJ1dGUoJ2RhdGEtJyArIG5hbWUpO1xuICAgICAgaWYgKGF0dHJWYWwpIHtcbiAgICAgICAgYXR0clZhbCA9IGF0dHJWYWwuc3BsaXQoX3MuZGVsaW1pdGVycyk7XG4gICAgICAgIGlmIChhdHRyVmFsIGluc3RhbmNlb2YgQXJyYXkpIF9zW25hbWVdID0gYXR0clZhbDtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIGJhY2t3YXJkLWNvbXBhdGliaWxpdHkgZm9yIG9sZCB2ZXJzaW9uIG9mIFwiYXV0b0NvbXBsZXRlXCIgc2V0dGluZzpcbiAgICBpZiAoXCJhdXRvQ29tcGxldGVcIiBpbiBzZXR0aW5ncyAmJiAhaXNPYmplY3Qoc2V0dGluZ3MuYXV0b0NvbXBsZXRlKSkge1xuICAgICAgX3MuYXV0b0NvbXBsZXRlID0gREVGQVVMVFMuYXV0b0NvbXBsZXRlO1xuICAgICAgX3MuYXV0b0NvbXBsZXRlLmVuYWJsZWQgPSBzZXR0aW5ncy5hdXRvQ29tcGxldGU7XG4gICAgfVxuICAgIGlmIChfcy5tb2RlID09ICdtaXgnKSB7XG4gICAgICBfcy5wYXR0ZXJuID0gX3MucGF0dGVybiB8fCAvQC87XG4gICAgICBfcy5hdXRvQ29tcGxldGUucmlnaHRLZXkgPSB0cnVlO1xuICAgICAgX3MuZGVsaW1pdGVycyA9IHNldHRpbmdzLmRlbGltaXRlcnMgfHwgbnVsbDsgLy8gZGVmYXVsdCBkbGltaXRlcnMgaW4gbWl4LW1vZGUgbXVzdCBiZSBOVUxMXG5cbiAgICAgIC8vIG5lZWRlZCBmb3IgXCJmaWx0ZXJMaXN0SXRlbXNcIi4gVGhpcyBhc3N1bWVzIHRoZSB1c2VyIG1pZ2h0IGhhdmUgZm9yZ290dGVuIHRvIG1hbnVhbGx5XG4gICAgICAvLyBkZWZpbmUgdGhlIHNhbWUgdGVybSBpbiBcImRyb3Bkb3duLnNlYXJjaEtleXNcIiBhcyBkZWZpbmVkIGluIFwidGFnVGV4dFByb3BcIiBzZXR0aW5nLCBzb1xuICAgICAgLy8gYnkgYXV0b21hdGljYWxseSBhZGRpbmcgaXQsIHRhZ2lmeSBpcyBcImhlbHBpbmdcIiBvdXQsIGd1ZXNzaW5nIHRoZSBpbnRlc250aW9ucyBvZiB0aGUgZGV2ZWxvcGVyLlxuICAgICAgaWYgKF9zLnRhZ1RleHRQcm9wICYmICFfcy5kcm9wZG93bi5zZWFyY2hLZXlzLmluY2x1ZGVzKF9zLnRhZ1RleHRQcm9wKSkgX3MuZHJvcGRvd24uc2VhcmNoS2V5cy5wdXNoKF9zLnRhZ1RleHRQcm9wKTtcbiAgICB9XG4gICAgaWYgKGlucHV0LnBhdHRlcm4pIHRyeSB7XG4gICAgICBfcy5wYXR0ZXJuID0gbmV3IFJlZ0V4cChpbnB1dC5wYXR0ZXJuKTtcbiAgICB9IGNhdGNoIChlKSB7fVxuXG4gICAgLy8gQ29udmVydCB0aGUgXCJkZWxpbWl0ZXJzXCIgc2V0dGluZyBpbnRvIGEgUkVHRVggb2JqZWN0XG4gICAgaWYgKF9zLmRlbGltaXRlcnMpIHtcbiAgICAgIF9zLl9kZWxpbWl0ZXJzID0gX3MuZGVsaW1pdGVycztcbiAgICAgIHRyeSB7XG4gICAgICAgIF9zLmRlbGltaXRlcnMgPSBuZXcgUmVnRXhwKHRoaXMuc2V0dGluZ3MuZGVsaW1pdGVycywgXCJnXCIpO1xuICAgICAgfSBjYXRjaCAoZSkge31cbiAgICB9XG4gICAgaWYgKF9zLmRpc2FibGVkKSBfcy51c2VySW5wdXQgPSBmYWxzZTtcbiAgICB0aGlzLlRFWFRTID0gX29iamVjdFNwcmVhZDIoX29iamVjdFNwcmVhZDIoe30sIFRFWFRTKSwgX3MudGV4dHMgfHwge30pO1xuXG4gICAgLy8gbWFrZSBzdXJlIHRoZSBkcm9wZG93biB3aWxsIGJlIHNob3duIG9uIFwiZm9jdXNcIiBhbmQgbm90IG9ubHkgYWZ0ZXIgdHlwaW5nIHNvbWV0aGluZyAoaW4gXCJzZWxlY3RcIiBtb2RlKVxuICAgIGlmIChfcy5tb2RlID09ICdzZWxlY3QnICYmICFzZXR0aW5ncy5kcm9wZG93bj8uZW5hYmxlZCB8fCAhX3MudXNlcklucHV0KSB7XG4gICAgICBfcy5kcm9wZG93bi5lbmFibGVkID0gMDtcbiAgICB9XG4gICAgX3MuZHJvcGRvd24uYXBwZW5kVGFyZ2V0ID0gc2V0dGluZ3MuZHJvcGRvd24/LmFwcGVuZFRhcmdldCB8fCBkb2N1bWVudC5ib2R5O1xuXG4gICAgLy8gZ2V0ICYgbWVyZ2UgcGVyc2lzdGVkIGRhdGEgd2l0aCBjdXJyZW50IGRhdGFcbiAgICBsZXQgcGVyc2lzdGVkV2hpdGVsaXN0ID0gdGhpcy5nZXRQZXJzaXN0ZWREYXRhKCd3aGl0ZWxpc3QnKTtcbiAgICBpZiAoQXJyYXkuaXNBcnJheShwZXJzaXN0ZWRXaGl0ZWxpc3QpKSB0aGlzLndoaXRlbGlzdCA9IEFycmF5LmlzQXJyYXkoX3Mud2hpdGVsaXN0KSA/IGNvbmNhdFdpdGhvdXREdXBzKF9zLndoaXRlbGlzdCwgcGVyc2lzdGVkV2hpdGVsaXN0KSA6IHBlcnNpc3RlZFdoaXRlbGlzdDtcbiAgfSxcbiAgLyoqXHJcbiAgICogUmV0dXJucyBhIHN0cmluZyBvZiBIVE1MIGVsZW1lbnQgYXR0cmlidXRlc1xyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIFtUYWcgZGF0YV1cclxuICAgKi9cbiAgZ2V0QXR0cmlidXRlcyhkYXRhKSB7XG4gICAgdmFyIGF0dHJzID0gdGhpcy5nZXRDdXN0b21BdHRyaWJ1dGVzKGRhdGEpLFxuICAgICAgcyA9ICcnLFxuICAgICAgaztcbiAgICBmb3IgKGsgaW4gYXR0cnMpIHMgKz0gXCIgXCIgKyBrICsgKGRhdGFba10gIT09IHVuZGVmaW5lZCA/IGA9XCIke2F0dHJzW2tdfVwiYCA6IFwiXCIpO1xuICAgIHJldHVybiBzO1xuICB9LFxuICAvKipcclxuICAgKiBSZXR1cm5zIGFuIG9iamVjdCBvZiBhdHRyaWJ1dGVzIHRvIGJlIHVzZWQgZm9yIHRoZSB0ZW1wbGF0ZXNcclxuICAgKi9cbiAgZ2V0Q3VzdG9tQXR0cmlidXRlcyhkYXRhKSB7XG4gICAgLy8gb25seSBpdGVtcyB3aGljaCBhcmUgb2JqZWN0cyBoYXZlIHByb3BlcnRpZXMgd2hpY2ggY2FuIGJlIHVzZWQgYXMgYXR0cmlidXRlc1xuICAgIGlmICghaXNPYmplY3QoZGF0YSkpIHJldHVybiAnJztcbiAgICB2YXIgb3V0cHV0ID0ge30sXG4gICAgICBwcm9wTmFtZTtcbiAgICBmb3IgKHByb3BOYW1lIGluIGRhdGEpIHtcbiAgICAgIGlmIChwcm9wTmFtZS5zbGljZSgwLCAyKSAhPSAnX18nICYmIHByb3BOYW1lICE9ICdjbGFzcycgJiYgZGF0YS5oYXNPd25Qcm9wZXJ0eShwcm9wTmFtZSkgJiYgZGF0YVtwcm9wTmFtZV0gIT09IHVuZGVmaW5lZCkgb3V0cHV0W3Byb3BOYW1lXSA9IGVzY2FwZUhUTUwoZGF0YVtwcm9wTmFtZV0pO1xuICAgIH1cbiAgICByZXR1cm4gb3V0cHV0O1xuICB9LFxuICBzZXRTdGF0ZVNlbGVjdGlvbigpIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuXG4gICAgLy8gc2F2ZSBsYXN0IHNlbGVjdGlvbiBwbGFjZSB0byBiZSBhYmxlIHRvIGluamVjdCBhbnl0aGluZyBmcm9tIG91dHNpZGUgdG8gdGhhdCBzcGVjaWZpYyBwbGFjZVxuICAgIHZhciBzZWwgPSB7XG4gICAgICBhbmNob3JPZmZzZXQ6IHNlbGVjdGlvbi5hbmNob3JPZmZzZXQsXG4gICAgICBhbmNob3JOb2RlOiBzZWxlY3Rpb24uYW5jaG9yTm9kZSxcbiAgICAgIHJhbmdlOiBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCAmJiBzZWxlY3Rpb24ucmFuZ2VDb3VudCAmJiBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKVxuICAgIH07XG4gICAgdGhpcy5zdGF0ZS5zZWxlY3Rpb24gPSBzZWw7XG4gICAgcmV0dXJuIHNlbDtcbiAgfSxcbiAgLyoqXHJcbiAgICogR2V0IHNwZWNpZmljIENTUyB2YXJpYWJsZXMgd2hpY2ggYXJlIHJlbGV2YW50IHRvIHRoaXMgc2NyaXB0IGFuZCBwYXJzZSB0aGVtIGFzIG5lZWRlZC5cclxuICAgKiBUaGUgcmVzdWx0IGlzIHNhdmVkIG9uIHRoZSBpbnN0YW5jZSBpbiBcInRoaXMuQ1NTVmFyc1wiXHJcbiAgICovXG4gIGdldENTU1ZhcnMoKSB7XG4gICAgdmFyIGNvbXBTdHlsZSA9IGdldENvbXB1dGVkU3R5bGUodGhpcy5ET00uc2NvcGUsIG51bGwpO1xuICAgIGNvbnN0IGdldFByb3AgPSBuYW1lID0+IGNvbXBTdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCctLScgKyBuYW1lKTtcbiAgICBmdW5jdGlvbiBzZXByYXRlVW5pdEZyb21WYWx1ZShhKSB7XG4gICAgICBpZiAoIWEpIHJldHVybiB7fTtcbiAgICAgIGEgPSBhLnRyaW0oKS5zcGxpdCgnICcpWzBdO1xuICAgICAgdmFyIHVuaXQgPSBhLnNwbGl0KC9cXGQrL2cpLmZpbHRlcihuID0+IG4pLnBvcCgpLnRyaW0oKSxcbiAgICAgICAgdmFsdWUgPSArYS5zcGxpdCh1bml0KS5maWx0ZXIobiA9PiBuKVswXS50cmltKCk7XG4gICAgICByZXR1cm4ge1xuICAgICAgICB2YWx1ZSxcbiAgICAgICAgdW5pdFxuICAgICAgfTtcbiAgICB9XG4gICAgdGhpcy5DU1NWYXJzID0ge1xuICAgICAgdGFnSGlkZVRyYW5zaXRpb246IChfcmVmID0+IHtcbiAgICAgICAgbGV0IHZhbHVlID0gX3JlZi52YWx1ZSxcbiAgICAgICAgICB1bml0ID0gX3JlZi51bml0O1xuICAgICAgICByZXR1cm4gdW5pdCA9PSAncycgPyB2YWx1ZSAqIDEwMDAgOiB2YWx1ZTtcbiAgICAgIH0pKHNlcHJhdGVVbml0RnJvbVZhbHVlKGdldFByb3AoJ3RhZy1oaWRlLXRyYW5zaXRpb24nKSkpXG4gICAgfTtcbiAgfSxcbiAgLyoqXHJcbiAgICogYnVpbGRzIHRoZSBIVE1MIG9mIHRoaXMgY29tcG9uZW50XHJcbiAgICogQHBhcmFtICB7T2JqZWN0fSBpbnB1dCBbRE9NIGVsZW1lbnQgd2hpY2ggd291bGQgYmUgXCJ0cmFuc2Zvcm1lZFwiIGludG8gXCJUYWdzXCJdXHJcbiAgICovXG4gIGJ1aWxkKGlucHV0KSB7XG4gICAgdmFyIERPTSA9IHRoaXMuRE9NO1xuICAgIGlmICh0aGlzLnNldHRpbmdzLm1peE1vZGUuaW50ZWdyYXRlZCkge1xuICAgICAgRE9NLm9yaWdpbmFsSW5wdXQgPSBudWxsO1xuICAgICAgRE9NLnNjb3BlID0gaW5wdXQ7XG4gICAgICBET00uaW5wdXQgPSBpbnB1dDtcbiAgICB9IGVsc2Uge1xuICAgICAgRE9NLm9yaWdpbmFsSW5wdXQgPSBpbnB1dDtcbiAgICAgIERPTS5vcmlnaW5hbElucHV0X3RhYkluZGV4ID0gaW5wdXQudGFiSW5kZXg7XG4gICAgICBET00uc2NvcGUgPSB0aGlzLnBhcnNlVGVtcGxhdGUoJ3dyYXBwZXInLCBbaW5wdXQsIHRoaXMuc2V0dGluZ3NdKTtcbiAgICAgIERPTS5pbnB1dCA9IERPTS5zY29wZS5xdWVyeVNlbGVjdG9yKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5pbnB1dFNlbGVjdG9yKTtcbiAgICAgIGlucHV0LnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKERPTS5zY29wZSwgaW5wdXQpO1xuICAgICAgaW5wdXQudGFiSW5kZXggPSAtMTsgLy8gZG8gbm90IGFsbG93IGZvY3VzIG9yIHR5cGluZyBkaXJlY3RseSwgb25jZSB0YWdpZmllZFxuICAgIH1cbiAgfSxcblxuICAvKipcclxuICAgKiByZXZlcnQgYW55IGNoYW5nZXMgbWFkZSBieSB0aGlzIGNvbXBvbmVudFxyXG4gICAqL1xuICBkZXN0cm95KCkge1xuICAgIHRoaXMuZXZlbnRzLnVuYmluZEdsb2JhbC5jYWxsKHRoaXMpO1xuICAgIHRoaXMuRE9NLnNjb3BlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGhpcy5ET00uc2NvcGUpO1xuICAgIHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQudGFiSW5kZXggPSB0aGlzLkRPTS5vcmlnaW5hbElucHV0X3RhYkluZGV4O1xuICAgIGRlbGV0ZSB0aGlzLkRPTS5vcmlnaW5hbElucHV0Ll9fdGFnaWZ5O1xuICAgIHRoaXMuZHJvcGRvd24uaGlkZSh0cnVlKTtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5kcm9wZG93bkhpZGVfX2JpbmRFdmVudHNUaW1lb3V0KTtcbiAgICBjbGVhckludGVydmFsKHRoaXMubGlzdGVuZXJzLm1haW4ub3JpZ2luYWxJbnB1dFZhbHVlT2JzZXJ2ZXJJbnRlcnZhbCk7XG4gIH0sXG4gIC8qKlxyXG4gICAqIGlmIHRoZSBvcmlnaW5hbCBpbnB1dCBoYXMgYW55IHZhbHVlcywgYWRkIHRoZW0gYXMgdGFnc1xyXG4gICAqL1xuICBsb2FkT3JpZ2luYWxWYWx1ZXModmFsdWUpIHtcbiAgICB2YXIgbGFzdENoaWxkLFxuICAgICAgX3MgPSB0aGlzLnNldHRpbmdzO1xuXG4gICAgLy8gdGVtcG9yYXJpbHkgYmxvY2sgZmlyaW5nIHRoZSBcImNoYW5nZVwiIGV2ZW50IG9uIHRoZSBvcmlnaW5hbCBpbnB1dCB1bnRpbFxuICAgIC8vIHRoaXMgbWV0aG9kIGZpbmlzaCByZW1vdmluZyBjdXJyZW50IHZhbHVlIGFuZCBhZGRpbmcgYSBuZXcgb25lXG4gICAgdGhpcy5zdGF0ZS5ibG9ja0NoYW5nZUV2ZW50ID0gdHJ1ZTtcbiAgICBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgcGVyc2lzdGVkT3JpZ2luYWxWYWx1ZSA9IHRoaXMuZ2V0UGVyc2lzdGVkRGF0YSgndmFsdWUnKTtcblxuICAgICAgLy8gaWYgdGhlIGZpZWxkIGFscmVhZHkgaGFzIGEgZmllbGQsIHRydXN0IGl0cyB0aGUgZGVzaXJlZFxuICAgICAgLy8gb25lIHRvIGJlIHJlbmRlcmVkIGFuZCBkbyBub3QgdXNlIHRoZSBwZXJzaXN0ZWQgb25lXG4gICAgICBpZiAocGVyc2lzdGVkT3JpZ2luYWxWYWx1ZSAmJiAhdGhpcy5ET00ub3JpZ2luYWxJbnB1dC52YWx1ZSkgdmFsdWUgPSBwZXJzaXN0ZWRPcmlnaW5hbFZhbHVlO2Vsc2UgdmFsdWUgPSBfcy5taXhNb2RlLmludGVncmF0ZWQgPyB0aGlzLkRPTS5pbnB1dC50ZXh0Q29udGVudCA6IHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQudmFsdWU7XG4gICAgfVxuICAgIHRoaXMucmVtb3ZlQWxsVGFncygpO1xuICAgIGlmICh2YWx1ZSkge1xuICAgICAgaWYgKF9zLm1vZGUgPT0gJ21peCcpIHtcbiAgICAgICAgdGhpcy5wYXJzZU1peFRhZ3ModmFsdWUpO1xuICAgICAgICBsYXN0Q2hpbGQgPSB0aGlzLkRPTS5pbnB1dC5sYXN0Q2hpbGQ7XG5cbiAgICAgICAgLy8gZml4ZXMgYSBDaHJvbWUgYnVnLCB3aGVuIHRoZSBsYXN0IG5vZGUgaW4gYG1peC1tb2RlYCBpcyBhIHRhZywgdGhlIGNhcmV0IGFwcGVhcnMgYXQgdGhlIGZhci10b3AtdG9wLCBvdXRzaWRlIHRoZSBmaWVsZFxuICAgICAgICBpZiAoIWxhc3RDaGlsZCB8fCBsYXN0Q2hpbGQudGFnTmFtZSAhPSAnQlInKSB0aGlzLkRPTS5pbnB1dC5pbnNlcnRBZGphY2VudEhUTUwoJ2JlZm9yZWVuZCcsICc8YnI+Jyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGlmIChKU09OLnBhcnNlKHZhbHVlKSBpbnN0YW5jZW9mIEFycmF5KSB2YWx1ZSA9IEpTT04ucGFyc2UodmFsdWUpO1xuICAgICAgICB9IGNhdGNoIChlcnIpIHt9XG4gICAgICAgIHRoaXMuYWRkVGFncyh2YWx1ZSwgdHJ1ZSkuZm9yRWFjaCh0YWcgPT4gdGFnICYmIHRhZy5jbGFzc0xpc3QuYWRkKF9zLmNsYXNzTmFtZXMudGFnTm9BbmltYXRpb24pKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgdGhpcy5wb3N0VXBkYXRlKCk7XG4gICAgdGhpcy5zdGF0ZS5sYXN0T3JpZ2luYWxWYWx1ZVJlcG9ydGVkID0gX3MubWl4TW9kZS5pbnRlZ3JhdGVkID8gJycgOiB0aGlzLkRPTS5vcmlnaW5hbElucHV0LnZhbHVlO1xuICB9LFxuICBjbG9uZUV2ZW50KGUpIHtcbiAgICB2YXIgY2xvbmVkRXZlbnQgPSB7fTtcbiAgICBmb3IgKHZhciB2IGluIGUpIGlmICh2ICE9ICdwYXRoJykgY2xvbmVkRXZlbnRbdl0gPSBlW3ZdO1xuICAgIHJldHVybiBjbG9uZWRFdmVudDtcbiAgfSxcbiAgLyoqXHJcbiAgICogVG9vZ2xlIGdsb2JhbCBsb2FkaW5nIHN0YXRlIG9uL29mZlxyXG4gICAqIFVzZWZ1bCB3aGVuIGZldGNoaW5nIGFzeW5jIHdoaXRlbGlzdCB3aGlsZSB1c2VyIGlzIHR5cGluZ1xyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNMb2FkaW5nXHJcbiAgICovXG4gIGxvYWRpbmcoaXNMb2FkaW5nKSB7XG4gICAgdGhpcy5zdGF0ZS5pc0xvYWRpbmcgPSBpc0xvYWRpbmc7XG4gICAgLy8gSUUxMSBkb2Vzbid0IHN1cHBvcnQgdG9nZ2xlIHdpdGggc2Vjb25kIHBhcmFtZXRlclxuICAgIHRoaXMuRE9NLnNjb3BlLmNsYXNzTGlzdFtpc0xvYWRpbmcgPyBcImFkZFwiIDogXCJyZW1vdmVcIl0odGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnNjb3BlTG9hZGluZyk7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH0sXG4gIC8qKlxyXG4gICAqIFRvb2dsZSBhIHRhZyBsb2FkaW5nIHN0YXRlIG9uL29mZlxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gaXNMb2FkaW5nXHJcbiAgICovXG4gIHRhZ0xvYWRpbmcodGFnRWxtLCBpc0xvYWRpbmcpIHtcbiAgICBpZiAodGFnRWxtKVxuICAgICAgLy8gSUUxMSBkb2Vzbid0IHN1cHBvcnQgdG9nZ2xlIHdpdGggc2Vjb25kIHBhcmFtZXRlclxuICAgICAgdGFnRWxtLmNsYXNzTGlzdFtpc0xvYWRpbmcgPyBcImFkZFwiIDogXCJyZW1vdmVcIl0odGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ0xvYWRpbmcpO1xuICAgIHJldHVybiB0aGlzO1xuICB9LFxuICAvKipcclxuICAgKiBUb2dnbGVzIGNsYXNzIG9uIHRoZSBtYWluIHRhZ2lmeSBjb250YWluZXIgKFwic2NvcGVcIilcclxuICAgKiBAcGFyYW0ge1N0cmluZ30gY2xhc3NOYW1lXHJcbiAgICogQHBhcmFtIHtCb29sZWFufSBmb3JjZVxyXG4gICAqL1xuICB0b2dnbGVDbGFzcyhjbGFzc05hbWUsIGZvcmNlKSB7XG4gICAgaWYgKHR5cGVvZiBjbGFzc05hbWUgPT0gJ3N0cmluZycpIHRoaXMuRE9NLnNjb3BlLmNsYXNzTGlzdC50b2dnbGUoY2xhc3NOYW1lLCBmb3JjZSk7XG4gIH0sXG4gIHRvZ2dsZVNjb3BlVmFsaWRhdGlvbih2YWxpZGF0aW9uKSB7XG4gICAgdmFyIGlzVmFsaWQgPSB2YWxpZGF0aW9uID09PSB0cnVlIHx8IHZhbGlkYXRpb24gPT09IHVuZGVmaW5lZDsgLy8gaW5pdGlhbGx5IGl0IGlzIHVuZGVmaW5lZFxuXG4gICAgaWYgKCF0aGlzLnNldHRpbmdzLnJlcXVpcmVkICYmIHZhbGlkYXRpb24gJiYgdmFsaWRhdGlvbiA9PT0gdGhpcy5URVhUUy5lbXB0eSkgaXNWYWxpZCA9IHRydWU7XG4gICAgdGhpcy50b2dnbGVDbGFzcyh0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMudGFnSW52YWxpZCwgIWlzVmFsaWQpO1xuICAgIHRoaXMuRE9NLnNjb3BlLnRpdGxlID0gaXNWYWxpZCA/ICcnIDogdmFsaWRhdGlvbjtcbiAgfSxcbiAgdG9nZ2xlRm9jdXNDbGFzcyhmb3JjZSkge1xuICAgIHRoaXMudG9nZ2xlQ2xhc3ModGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLmZvY3VzLCAhIWZvcmNlKTtcbiAgfSxcbiAgdHJpZ2dlckNoYW5nZUV2ZW50LFxuICBldmVudHMsXG4gIGZpeEZpcmVmb3hMYXN0VGFnTm9DYXJldCgpIHtcbiAgICByZXR1cm47IC8vIHNlZW1zIHRvIGJlIGZpeGVkIGluIG5ld2VyIHZlcnNpb24gb2YgRkYsIHNvIHJldGlyaW5nIGJlbG93IGNvZGUgKGZvciBub3cpXG4gICAgLy8gdmFyIGlucHV0RWxtID0gdGhpcy5ET00uaW5wdXRcblxuICAgIC8vIGlmKCB0aGlzLmlzRmlyZWZveCAmJiBpbnB1dEVsbS5jaGlsZE5vZGVzLmxlbmd0aCAmJiBpbnB1dEVsbS5sYXN0Q2hpbGQubm9kZVR5cGUgPT0gMSApe1xuICAgIC8vICAgICBpbnB1dEVsbS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIlxcdTIwMGJcIikpXG4gICAgLy8gICAgIHRoaXMuc2V0UmFuZ2VBdFN0YXJ0RW5kKHRydWUsIGlucHV0RWxtKVxuICAgIC8vICAgICByZXR1cm4gdHJ1ZVxuICAgIC8vIH1cbiAgfSxcblxuICAvKiogaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9hLzU5MTU2ODcyLzEwNDM4MFxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gc3RhcnQgaW5kaWNhdGluZyB3aGVyZSB0byBwbGFjZSBpdCAoc3RhcnQgb3IgZW5kIG9mIHRoZSBub2RlKVxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSAgbm9kZSAgRE9NIG5vZGUgdG8gcGxhY2UgdGhlIGNhcmV0IGF0XHJcbiAgICovXG4gIHNldFJhbmdlQXRTdGFydEVuZChzdGFydCwgbm9kZSkge1xuICAgIGlmICghbm9kZSkgcmV0dXJuO1xuICAgIHN0YXJ0ID0gdHlwZW9mIHN0YXJ0ID09ICdudW1iZXInID8gc3RhcnQgOiAhIXN0YXJ0O1xuICAgIG5vZGUgPSBub2RlLmxhc3RDaGlsZCB8fCBub2RlO1xuICAgIHZhciBzZWwgPSBkb2N1bWVudC5nZXRTZWxlY3Rpb24oKTtcblxuICAgIC8vIGRvIG5vdCBmb3JjZSBjYXJldCBwbGFjZW1lbnQgaWYgdGhlIGN1cnJlbnQgc2VsZWN0aW9uIChmb2N1cykgaXMgb24gYW5vdGhlciBlbGVtZW50IChub3QgdGhpcyB0YWdpZnkgaW5zdGFuY2UpXG4gICAgaWYgKHNlbC5mb2N1c05vZGUgaW5zdGFuY2VvZiBFbGVtZW50ICYmICF0aGlzLkRPTS5pbnB1dC5jb250YWlucyhzZWwuZm9jdXNOb2RlKSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICBpZiAoc2VsLnJhbmdlQ291bnQgPj0gMSkge1xuICAgICAgICBbJ1N0YXJ0JywgJ0VuZCddLmZvckVhY2gocG9zID0+IHNlbC5nZXRSYW5nZUF0KDApW1wic2V0XCIgKyBwb3NdKG5vZGUsIHN0YXJ0ID8gc3RhcnQgOiBub2RlLmxlbmd0aCkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gY29uc29sZS53YXJuKFwiVGFnaWZ5OiBcIiwgZXJyKVxuICAgIH1cbiAgfSxcbiAgcGxhY2VDYXJldEFmdGVyTm9kZShub2RlKSB7XG4gICAgaWYgKCFub2RlIHx8ICFub2RlLnBhcmVudE5vZGUpIHJldHVybjtcbiAgICB2YXIgbmV4dFNpYmxpbmcgPSBub2RlLFxuICAgICAgc2VsID0gd2luZG93LmdldFNlbGVjdGlvbigpLFxuICAgICAgcmFuZ2UgPSBzZWwuZ2V0UmFuZ2VBdCgwKTtcbiAgICBpZiAoc2VsLnJhbmdlQ291bnQpIHtcbiAgICAgIHJhbmdlLnNldFN0YXJ0QWZ0ZXIobmV4dFNpYmxpbmcpO1xuICAgICAgcmFuZ2UuY29sbGFwc2UodHJ1ZSk7XG4gICAgICAvLyByYW5nZS5zZXRFbmRCZWZvcmUobmV4dFNpYmxpbmcgfHwgbm9kZSk7XG4gICAgICBzZWwucmVtb3ZlQWxsUmFuZ2VzKCk7XG4gICAgICBzZWwuYWRkUmFuZ2UocmFuZ2UpO1xuICAgIH1cbiAgfSxcbiAgaW5zZXJ0QWZ0ZXJUYWcodGFnRWxtLCBuZXdOb2RlKSB7XG4gICAgbmV3Tm9kZSA9IG5ld05vZGUgfHwgdGhpcy5zZXR0aW5ncy5taXhNb2RlLmluc2VydEFmdGVyVGFnO1xuICAgIGlmICghdGFnRWxtIHx8ICF0YWdFbG0ucGFyZW50Tm9kZSB8fCAhbmV3Tm9kZSkgcmV0dXJuO1xuICAgIG5ld05vZGUgPSB0eXBlb2YgbmV3Tm9kZSA9PSAnc3RyaW5nJyA/IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKG5ld05vZGUpIDogbmV3Tm9kZTtcbiAgICB0YWdFbG0ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUobmV3Tm9kZSwgdGFnRWxtLm5leHRTaWJsaW5nKTtcbiAgICByZXR1cm4gbmV3Tm9kZTtcbiAgfSxcbiAgLy8gY29tcGFyZXMgYWxsIFwiX19vcmlnaW5hbERhdGFcIiBwcm9wZXJ0eSB2YWx1ZXMgd2l0aCB0aGUgY3VycmVudCBcInRhZ0RhdGFcIiBwcm9wZXJ0aWVzXG4gIC8vIGFuZCByZXR1cm5zIFwidHJ1ZVwiIGlmIHNvbWV0aGluZyBjaGFuZ2VkLlxuICBlZGl0VGFnQ2hhbmdlRGV0ZWN0ZWQodGFnRGF0YSkge1xuICAgIHZhciBvcmlnaW5hbERhdGEgPSB0YWdEYXRhLl9fb3JpZ2luYWxEYXRhO1xuICAgIGZvciAodmFyIHByb3AgaW4gb3JpZ2luYWxEYXRhKSBpZiAoIXRoaXMuZGF0YVByb3BzLmluY2x1ZGVzKHByb3ApICYmIHRhZ0RhdGFbcHJvcF0gIT0gb3JpZ2luYWxEYXRhW3Byb3BdKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7IC8vIG5vdCBjaGFuZ2VkXG4gIH0sXG5cbiAgLy8gcmV0dXJucyB0aGUgbm9kZSB3aGljaCBoYXMgdGhlIGFjdHVhbCB0YWcncyBjb250ZW50XG4gIGdldFRhZ1RleHROb2RlKHRhZ0VsbSkge1xuICAgIHJldHVybiB0YWdFbG0ucXVlcnlTZWxlY3Rvcih0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMudGFnVGV4dFNlbGVjdG9yKTtcbiAgfSxcbiAgLy8gc2V0cyB0aGUgdGV4dCBvZiBhIHRhZ1xuICBzZXRUYWdUZXh0Tm9kZSh0YWdFbG0sIEhUTUwpIHtcbiAgICB0aGlzLmdldFRhZ1RleHROb2RlKHRhZ0VsbSkuaW5uZXJIVE1MID0gZXNjYXBlSFRNTChIVE1MKTtcbiAgfSxcbiAgLyoqXHJcbiAgICogRW50ZXJzIGEgdGFnIGludG8gXCJlZGl0XCIgbW9kZVxyXG4gICAqIEBwYXJhbSB7Tm9kZX0gdGFnRWxtIHRoZSB0YWcgZWxlbWVudCB0byBlZGl0LiBpZiBub3RoaW5nIHNwZWNpZmllZCwgdXNlIGxhc3QgbGFzdFxyXG4gICAqL1xuICBlZGl0VGFnKHRhZ0VsbSwgb3B0cykge1xuICAgIHRhZ0VsbSA9IHRhZ0VsbSB8fCB0aGlzLmdldExhc3RUYWcoKTtcbiAgICBvcHRzID0gb3B0cyB8fCB7fTtcbiAgICB0aGlzLmRyb3Bkb3duLmhpZGUoKTtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgZWRpdGFibGVFbG0gPSB0aGlzLmdldFRhZ1RleHROb2RlKHRhZ0VsbSksXG4gICAgICB0YWdJZHggPSB0aGlzLmdldE5vZGVJbmRleCh0YWdFbG0pLFxuICAgICAgdGFnRGF0YSA9IGdldFNldFRhZ0RhdGEodGFnRWxtKSxcbiAgICAgIF9DQiA9IHRoaXMuZXZlbnRzLmNhbGxiYWNrcyxcbiAgICAgIHRoYXQgPSB0aGlzLFxuICAgICAgaXNWYWxpZCA9IHRydWUsXG4gICAgICBkZWxheWVkX29uRWRpdFRhZ0JsdXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNldFRpbWVvdXQoKCkgPT4gX0NCLm9uRWRpdFRhZ0JsdXIuY2FsbCh0aGF0LCB0aGF0LmdldFRhZ1RleHROb2RlKHRhZ0VsbSkpKTtcbiAgICAgIH07XG4gICAgaWYgKCFlZGl0YWJsZUVsbSkge1xuICAgICAgY29uc29sZS53YXJuKCdDYW5ub3QgZmluZCBlbGVtZW50IGluIFRhZyB0ZW1wbGF0ZTogLicsIF9zLmNsYXNzTmFtZXMudGFnVGV4dFNlbGVjdG9yKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaWYgKHRhZ0RhdGEgaW5zdGFuY2VvZiBPYmplY3QgJiYgXCJlZGl0YWJsZVwiIGluIHRhZ0RhdGEgJiYgIXRhZ0RhdGEuZWRpdGFibGUpIHJldHVybjtcblxuICAgIC8vIGNhY2hlIHRoZSBvcmlnaW5hbCBkYXRhLCBvbiB0aGUgRE9NIG5vZGUsIGJlZm9yZSBhbnkgbW9kaWZpY2F0aW9uIG9jdXJzLCBmb3IgcG9zc2libGUgcmV2ZXJ0XG4gICAgdGFnRGF0YSA9IGdldFNldFRhZ0RhdGEodGFnRWxtLCB7XG4gICAgICBfX29yaWdpbmFsRGF0YTogZXh0ZW5kKHt9LCB0YWdEYXRhKSxcbiAgICAgIF9fb3JpZ2luYWxIVE1MOiB0YWdFbG0uY2xvbmVOb2RlKHRydWUpXG4gICAgfSk7XG4gICAgLy8gcmUtc2V0IHRoZSB0YWdpZnkgY3VzdG9tLXByb3Agb24gdGhlIGNsb25lcyBlbGVtZW50IChiZWNhdXNlIGNsb25pbmcgcmVtb3ZlZCBpdClcbiAgICBnZXRTZXRUYWdEYXRhKHRhZ0RhdGEuX19vcmlnaW5hbEhUTUwsIHRhZ0RhdGEuX19vcmlnaW5hbERhdGEpO1xuICAgIGVkaXRhYmxlRWxtLnNldEF0dHJpYnV0ZSgnY29udGVudGVkaXRhYmxlJywgdHJ1ZSk7XG4gICAgdGFnRWxtLmNsYXNzTGlzdC5hZGQoX3MuY2xhc3NOYW1lcy50YWdFZGl0aW5nKTtcbiAgICBlZGl0YWJsZUVsbS5hZGRFdmVudExpc3RlbmVyKCdmb2N1cycsIF9DQi5vbkVkaXRUYWdGb2N1cy5iaW5kKHRoaXMsIHRhZ0VsbSkpO1xuICAgIGVkaXRhYmxlRWxtLmFkZEV2ZW50TGlzdGVuZXIoJ2JsdXInLCBkZWxheWVkX29uRWRpdFRhZ0JsdXIpO1xuICAgIGVkaXRhYmxlRWxtLmFkZEV2ZW50TGlzdGVuZXIoJ2lucHV0JywgX0NCLm9uRWRpdFRhZ0lucHV0LmJpbmQodGhpcywgZWRpdGFibGVFbG0pKTtcbiAgICBlZGl0YWJsZUVsbS5hZGRFdmVudExpc3RlbmVyKCdwYXN0ZScsIF9DQi5vbkVkaXRUYWdQYXN0ZS5iaW5kKHRoaXMsIGVkaXRhYmxlRWxtKSk7XG4gICAgZWRpdGFibGVFbG0uYWRkRXZlbnRMaXN0ZW5lcigna2V5ZG93bicsIGUgPT4gX0NCLm9uRWRpdFRhZ2tleWRvd24uY2FsbCh0aGlzLCBlLCB0YWdFbG0pKTtcbiAgICBlZGl0YWJsZUVsbS5hZGRFdmVudExpc3RlbmVyKCdjb21wb3NpdGlvbnN0YXJ0JywgX0NCLm9uQ29tcG9zaXRpb25TdGFydC5iaW5kKHRoaXMpKTtcbiAgICBlZGl0YWJsZUVsbS5hZGRFdmVudExpc3RlbmVyKCdjb21wb3NpdGlvbmVuZCcsIF9DQi5vbkNvbXBvc2l0aW9uRW5kLmJpbmQodGhpcykpO1xuICAgIGlmICghb3B0cy5za2lwVmFsaWRhdGlvbikgaXNWYWxpZCA9IHRoaXMuZWRpdFRhZ1RvZ2dsZVZhbGlkaXR5KHRhZ0VsbSk7XG4gICAgZWRpdGFibGVFbG0ub3JpZ2luYWxJc1ZhbGlkID0gaXNWYWxpZDtcbiAgICB0aGlzLnRyaWdnZXIoXCJlZGl0OnN0YXJ0XCIsIHtcbiAgICAgIHRhZzogdGFnRWxtLFxuICAgICAgaW5kZXg6IHRhZ0lkeCxcbiAgICAgIGRhdGE6IHRhZ0RhdGEsXG4gICAgICBpc1ZhbGlkXG4gICAgfSk7XG4gICAgZWRpdGFibGVFbG0uZm9jdXMoKTtcbiAgICB0aGlzLnNldFJhbmdlQXRTdGFydEVuZChmYWxzZSwgZWRpdGFibGVFbG0pOyAvLyBwbGFjZSB0aGUgY2FyZXQgYXQgdGhlIEVORCBvZiB0aGUgZWRpdGFibGUgdGFnIHRleHRcblxuICAgIHJldHVybiB0aGlzO1xuICB9LFxuICAvKipcclxuICAgKiBJZiBhIHRhZyBpcyBpbnZhbGlkLCBmb3IgYW55IHJlYXNvbiwgc2V0IGl0cyBjbGFzcyB0byBcIm5vdCBhbGxvd2VkXCIgKHNlZSBkZWZhdWx0cyBmaWxlKVxyXG4gICAqIEBwYXJhbSB7Tm9kZX0gdGFnRWxtIHJlcXVpcmVkXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0RhdGEgb3B0aW9uYWxcclxuICAgKiBAcmV0dXJucyB0cnVlIGlmIHZhbGlkLCBhIHN0cmluZyAocmVhc29uKSBpZiBub3RcclxuICAgKi9cbiAgZWRpdFRhZ1RvZ2dsZVZhbGlkaXR5KHRhZ0VsbSwgdGFnRGF0YSkge1xuICAgIHZhciB0YWdEYXRhID0gdGFnRGF0YSB8fCBnZXRTZXRUYWdEYXRhKHRhZ0VsbSksXG4gICAgICBpc1ZhbGlkO1xuICAgIGlmICghdGFnRGF0YSkge1xuICAgICAgY29uc29sZS53YXJuKFwidGFnIGhhcyBubyBkYXRhOiBcIiwgdGFnRWxtLCB0YWdEYXRhKTtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgaXNWYWxpZCA9ICEoXCJfX2lzVmFsaWRcIiBpbiB0YWdEYXRhKSB8fCB0YWdEYXRhLl9faXNWYWxpZCA9PT0gdHJ1ZTtcbiAgICBpZiAoIWlzVmFsaWQpIHtcbiAgICAgIHRoaXMucmVtb3ZlVGFnc0Zyb21WYWx1ZSh0YWdFbG0pO1xuICAgIH1cbiAgICB0aGlzLnVwZGF0ZSgpO1xuXG4gICAgLy90aGlzLnZhbGlkYXRlVGFnKHRhZ0RhdGEpO1xuXG4gICAgdGFnRWxtLmNsYXNzTGlzdC50b2dnbGUodGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ05vdEFsbG93ZWQsICFpc1ZhbGlkKTtcbiAgICByZXR1cm4gdGFnRGF0YS5fX2lzVmFsaWQ7XG4gIH0sXG4gIG9uRWRpdFRhZ0RvbmUodGFnRWxtLCB0YWdEYXRhKSB7XG4gICAgdGFnRWxtID0gdGFnRWxtIHx8IHRoaXMuc3RhdGUuZWRpdGluZy5zY29wZTtcbiAgICB0YWdEYXRhID0gdGFnRGF0YSB8fCB7fTtcbiAgICB2YXIgZXZlbnREYXRhID0ge1xuICAgICAgdGFnOiB0YWdFbG0sXG4gICAgICBpbmRleDogdGhpcy5nZXROb2RlSW5kZXgodGFnRWxtKSxcbiAgICAgIHByZXZpb3VzRGF0YTogZ2V0U2V0VGFnRGF0YSh0YWdFbG0pLFxuICAgICAgZGF0YTogdGFnRGF0YVxuICAgIH07XG4gICAgdGhpcy50cmlnZ2VyKFwiZWRpdDpiZWZvcmVVcGRhdGVcIiwgZXZlbnREYXRhLCB7XG4gICAgICBjbG9uZURhdGE6IGZhbHNlXG4gICAgfSk7XG4gICAgdGhpcy5zdGF0ZS5lZGl0aW5nID0gZmFsc2U7XG4gICAgZGVsZXRlIHRhZ0RhdGEuX19vcmlnaW5hbERhdGE7XG4gICAgZGVsZXRlIHRhZ0RhdGEuX19vcmlnaW5hbEhUTUw7XG4gICAgaWYgKHRhZ0VsbSAmJiB0YWdEYXRhW3RoaXMuc2V0dGluZ3MudGFnVGV4dFByb3BdKSB7XG4gICAgICB0YWdFbG0gPSB0aGlzLnJlcGxhY2VUYWcodGFnRWxtLCB0YWdEYXRhKTtcbiAgICAgIHRoaXMuZWRpdFRhZ1RvZ2dsZVZhbGlkaXR5KHRhZ0VsbSwgdGFnRGF0YSk7XG4gICAgICBpZiAodGhpcy5zZXR0aW5ncy5hMTF5LmZvY3VzYWJsZVRhZ3MpIHRhZ0VsbS5mb2N1cygpO2Vsc2VcbiAgICAgICAgLy8gcGxhY2UgY2FyZXQgYWZ0ZXIgZWRpdGVkIHRhZ1xuICAgICAgICB0aGlzLnBsYWNlQ2FyZXRBZnRlck5vZGUodGFnRWxtKTtcbiAgICB9IGVsc2UgaWYgKHRhZ0VsbSkgdGhpcy5yZW1vdmVUYWdzKHRhZ0VsbSk7XG4gICAgdGhpcy50cmlnZ2VyKFwiZWRpdDp1cGRhdGVkXCIsIGV2ZW50RGF0YSk7XG4gICAgdGhpcy5kcm9wZG93bi5oaWRlKCk7XG5cbiAgICAvLyBjaGVjayBpZiBhbnkgb2YgdGhlIGN1cnJlbnQgdGFncyB3aGljaCBtaWdodCBoYXZlIGJlZW4gbWFya2VkIGFzIFwiZHVwbGljYXRlXCIgc2hvdWxkIGJlIG5vdyB1bi1tYXJrZWRcbiAgICBpZiAodGhpcy5zZXR0aW5ncy5rZWVwSW52YWxpZFRhZ3MpIHRoaXMucmVDaGVja0ludmFsaWRUYWdzKCk7XG4gIH0sXG4gIC8qKlxyXG4gICAqIFJlcGxhY2VzIGFuIGV4aXNpdG5nIHRhZyB3aXRoIGEgbmV3IG9uZS4gVXNlZCBmb3IgdXBkYXRpbmcgYSB0YWcncyBkYXRhXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0VsbSAgW0RPTSBub2RlIHRvIHJlcGxhY2VdXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0RhdGEgW2RhdGEgdG8gY3JlYXRlIG5ldyB0YWcgZnJvbV1cclxuICAgKi9cbiAgcmVwbGFjZVRhZyh0YWdFbG0sIHRhZ0RhdGEpIHtcbiAgICBpZiAoIXRhZ0RhdGEgfHwgIXRhZ0RhdGEudmFsdWUpIHRhZ0RhdGEgPSB0YWdFbG0uX190YWdpZnlUYWdEYXRhO1xuXG4gICAgLy8gaWYgdGFnIGlzIGludmFsaWQsIG1ha2UgdGhlIGFjY29yZGluZyBjaGFuZ2VzIGluIHRoZSBuZXdseSBjcmVhdGVkIGVsZW1lbnRcbiAgICBpZiAodGFnRGF0YS5fX2lzVmFsaWQgJiYgdGFnRGF0YS5fX2lzVmFsaWQgIT0gdHJ1ZSkgZXh0ZW5kKHRhZ0RhdGEsIHRoaXMuZ2V0SW52YWxpZFRhZ0F0dHJzKHRhZ0RhdGEsIHRhZ0RhdGEuX19pc1ZhbGlkKSk7XG4gICAgdmFyIG5ld1RhZ0VsbSA9IHRoaXMuY3JlYXRlVGFnRWxlbSh0YWdEYXRhKTtcblxuICAgIC8vIHVwZGF0ZSBET01cbiAgICB0YWdFbG0ucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobmV3VGFnRWxtLCB0YWdFbG0pO1xuICAgIHRoaXMudXBkYXRlVmFsdWVCeURPTVRhZ3MoKTtcbiAgICByZXR1cm4gbmV3VGFnRWxtO1xuICB9LFxuICAvKipcclxuICAgKiB1cGRhdGUgXCJ2YWx1ZVwiIChBcnJheSBvZiBPYmplY3RzKSBieSB0cmF2ZXJzaW5nIGFsbCB2YWxpZCB0YWdzXHJcbiAgICovXG4gIHVwZGF0ZVZhbHVlQnlET01UYWdzKCkge1xuICAgIHRoaXMudmFsdWUubGVuZ3RoID0gMDtcbiAgICBbXS5mb3JFYWNoLmNhbGwodGhpcy5nZXRUYWdFbG1zKCksIG5vZGUgPT4ge1xuICAgICAgaWYgKG5vZGUuY2xhc3NMaXN0LmNvbnRhaW5zKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy50YWdOb3RBbGxvd2VkLnNwbGl0KCcgJylbMF0pKSByZXR1cm47XG4gICAgICB0aGlzLnZhbHVlLnB1c2goZ2V0U2V0VGFnRGF0YShub2RlKSk7XG4gICAgfSk7XG4gICAgdGhpcy51cGRhdGUoKTtcbiAgfSxcbiAgLyoqXHJcbiAgICogaW5qZWN0cyBub2Rlcy90ZXh0IGF0IGNhcmV0IHBvc2l0aW9uLCB3aGljaCBpcyBzYXZlZCBvbiB0aGUgXCJzdGF0ZVwiIHdoZW4gXCJibHVyXCIgZXZlbnQgZ2V0cyB0cmlnZ2VyZWRcclxuICAgKiBAcGFyYW0ge05vZGV9IGluamVjdGVkTm9kZSBbdGhlIG5vZGUgdG8gaW5qZWN0IGF0IHRoZSBjYXJldCBwb3NpdGlvbl1cclxuICAgKiBAcGFyYW0ge09iamVjdH0gc2VsZWN0aW9uIFtvcHRpb25hbCByYW5nZSBPYmplY3QuIG11c3QgaGF2ZSBcImFuY2hvck5vZGVcIiAmIFwiYW5jaG9yT2Zmc2V0XCJdXHJcbiAgICovXG4gIGluamVjdEF0Q2FyZXQoaW5qZWN0ZWROb2RlLCByYW5nZSkge1xuICAgIHJhbmdlID0gcmFuZ2UgfHwgdGhpcy5zdGF0ZS5zZWxlY3Rpb24/LnJhbmdlO1xuICAgIGlmICghcmFuZ2UgJiYgaW5qZWN0ZWROb2RlKSB7XG4gICAgICB0aGlzLmFwcGVuZE1peFRhZ3MoaW5qZWN0ZWROb2RlKTtcbiAgICAgIHJldHVybiB0aGlzO1xuICAgIH1cbiAgICBpbmplY3RBdENhcmV0KGluamVjdGVkTm9kZSwgcmFuZ2UpO1xuICAgIHRoaXMuc2V0UmFuZ2VBdFN0YXJ0RW5kKGZhbHNlLCBpbmplY3RlZE5vZGUpO1xuICAgIHRoaXMudXBkYXRlVmFsdWVCeURPTVRhZ3MoKTsgLy8gdXBkYXRlcyBpbnRlcm5hbCBcInRoaXMudmFsdWVcIlxuICAgIHRoaXMudXBkYXRlKCk7IC8vIHVwZGF0ZXMgb3JpZ2luYWwgaW5wdXQvdGV4dGFyZWFcblxuICAgIHJldHVybiB0aGlzO1xuICB9LFxuICAvKipcclxuICAgKiBpbnB1dCBicmlkZ2UgZm9yIGFjY2Vzc2luZyAmIHNldHRpbmdcclxuICAgKiBAdHlwZSB7T2JqZWN0fVxyXG4gICAqL1xuICBpbnB1dDoge1xuICAgIHNldCgpIHtcbiAgICAgIGxldCBzID0gYXJndW1lbnRzLmxlbmd0aCA+IDAgJiYgYXJndW1lbnRzWzBdICE9PSB1bmRlZmluZWQgPyBhcmd1bWVudHNbMF0gOiAnJztcbiAgICAgIGxldCB1cGRhdGVET00gPSBhcmd1bWVudHMubGVuZ3RoID4gMSAmJiBhcmd1bWVudHNbMV0gIT09IHVuZGVmaW5lZCA/IGFyZ3VtZW50c1sxXSA6IHRydWU7XG4gICAgICB2YXIgaGlkZURyb3Bkb3duID0gdGhpcy5zZXR0aW5ncy5kcm9wZG93bi5jbG9zZU9uU2VsZWN0O1xuICAgICAgdGhpcy5zdGF0ZS5pbnB1dFRleHQgPSBzO1xuICAgICAgaWYgKHVwZGF0ZURPTSkgdGhpcy5ET00uaW5wdXQuaW5uZXJIVE1MID0gZXNjYXBlSFRNTChcIlwiICsgcyk7XG4gICAgICBpZiAoIXMgJiYgaGlkZURyb3Bkb3duKSB0aGlzLmRyb3Bkb3duLmhpZGUuYmluZCh0aGlzKTtcbiAgICAgIHRoaXMuaW5wdXQuYXV0b2NvbXBsZXRlLnN1Z2dlc3QuY2FsbCh0aGlzKTtcbiAgICAgIHRoaXMuaW5wdXQudmFsaWRhdGUuY2FsbCh0aGlzKTtcbiAgICB9LFxuICAgIHJhdygpIHtcbiAgICAgIHJldHVybiB0aGlzLkRPTS5pbnB1dC50ZXh0Q29udGVudDtcbiAgICB9LFxuICAgIC8qKlxyXG4gICAgICogTWFya3MgdGhlIHRhZ2lmeSdzIGlucHV0IGFzIFwiaW52YWxpZFwiIGlmIHRoZSB2YWx1ZSBkaWQgbm90IHBhc3MgXCJ2YWxpZGF0ZVRhZygpXCJcclxuICAgICAqL1xuICAgIHZhbGlkYXRlKCkge1xuICAgICAgdmFyIGlzVmFsaWQgPSAhdGhpcy5zdGF0ZS5pbnB1dFRleHQgfHwgdGhpcy52YWxpZGF0ZVRhZyh7XG4gICAgICAgIHZhbHVlOiB0aGlzLnN0YXRlLmlucHV0VGV4dFxuICAgICAgfSkgPT09IHRydWU7XG4gICAgICB0aGlzLkRPTS5pbnB1dC5jbGFzc0xpc3QudG9nZ2xlKHRoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy5pbnB1dEludmFsaWQsICFpc1ZhbGlkKTtcbiAgICAgIHJldHVybiBpc1ZhbGlkO1xuICAgIH0sXG4gICAgLy8gcmVtb3ZlIGFueSBjaGlsZCBET00gZWxlbWVudHMgdGhhdCBhcmVuJ3Qgb2YgdHlwZSBURVhUIChsaWtlIDxicj4pXG4gICAgbm9ybWFsaXplKG5vZGUpIHtcbiAgICAgIHZhciBjbG9uZSA9IG5vZGUgfHwgdGhpcy5ET00uaW5wdXQsXG4gICAgICAgIC8vLmNsb25lTm9kZSh0cnVlKSxcbiAgICAgICAgdiA9IFtdO1xuXG4gICAgICAvLyB3aGVuIGEgdGV4dCB3YXMgcGFzdGVkIGluIEZGLCB0aGUgXCJ0aGlzLkRPTS5pbnB1dFwiIGVsZW1lbnQgd2lsbCBoYXZlIDxicj4gYnV0IG5vIG5ld2xpbmUgc3ltYm9scyAoXFxuKSwgYW5kIHRoaXMgd2lsbFxuICAgICAgLy8gcmVzdWx0IGluIHRhZ3Mgbm90IGJlaW5nIHByb3Blcmx5IGNyZWF0ZWQgaWYgb25lIHdpc2hlcyB0byBjcmVhdGUgYSBzZXBhcmF0ZSB0YWcgcGVyIG5ld2xpbmUuXG4gICAgICBjbG9uZS5jaGlsZE5vZGVzLmZvckVhY2gobiA9PiBuLm5vZGVUeXBlID09IDMgJiYgdi5wdXNoKG4ubm9kZVZhbHVlKSk7XG4gICAgICB2ID0gdi5qb2luKFwiXFxuXCIpO1xuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gXCJkZWxpbWl0ZXJzXCIgbWlnaHQgYmUgb2YgYSBub24tcmVnZXggdmFsdWUsIHdoZXJlIHRoaXMgd2lsbCBmYWlsIChcIlRhZ3MgV2l0aCBQcm9wZXJ0aWVzXCIgZXhhbXBsZSBpbiBkZW1vIHBhZ2UpOlxuICAgICAgICB2ID0gdi5yZXBsYWNlKC8oPzpcXHJcXG58XFxyfFxcbikvZywgdGhpcy5zZXR0aW5ncy5kZWxpbWl0ZXJzLnNvdXJjZS5jaGFyQXQoMCkpO1xuICAgICAgfSBjYXRjaCAoZXJyKSB7fVxuICAgICAgdiA9IHYucmVwbGFjZSgvXFxzL2csICcgJyk7IC8vIHJlcGxhY2UgTkJTUHMgd2l0aCBzcGFjZXMgY2hhcmFjdGVyc1xuXG4gICAgICByZXR1cm4gdGhpcy50cmltKHYpO1xuICAgIH0sXG4gICAgLyoqXHJcbiAgICAgKiBzdWdnZXN0IHRoZSByZXN0IG9mIHRoZSBpbnB1dCdzIHZhbHVlICh2aWEgQ1NTIFwiOjphZnRlclwiIHVzaW5nIFwiY29udGVudDphdHRyKC4uLilcIilcclxuICAgICAqIEBwYXJhbSAge1N0cmluZ30gcyBbZGVzY3JpcHRpb25dXHJcbiAgICAgKi9cbiAgICBhdXRvY29tcGxldGU6IHtcbiAgICAgIHN1Z2dlc3QoZGF0YSkge1xuICAgICAgICBpZiAoIXRoaXMuc2V0dGluZ3MuYXV0b0NvbXBsZXRlLmVuYWJsZWQpIHJldHVybjtcbiAgICAgICAgZGF0YSA9IGRhdGEgfHwge1xuICAgICAgICAgIHZhbHVlOiAnJ1xuICAgICAgICB9O1xuICAgICAgICBpZiAodHlwZW9mIGRhdGEgPT0gJ3N0cmluZycpIGRhdGEgPSB7XG4gICAgICAgICAgdmFsdWU6IGRhdGFcbiAgICAgICAgfTtcbiAgICAgICAgdmFyIHN1Z2dlc3RlZFRleHQgPSB0aGlzLmRyb3Bkb3duLmdldE1hcHBlZFZhbHVlKGRhdGEpO1xuICAgICAgICBpZiAodHlwZW9mIHN1Z2dlc3RlZFRleHQgPT09ICdudW1iZXInKSByZXR1cm47XG4gICAgICAgIHZhciBzdWdnZXN0aW9uU3RhcnQgPSBzdWdnZXN0ZWRUZXh0LnN1YnN0cigwLCB0aGlzLnN0YXRlLmlucHV0VGV4dC5sZW5ndGgpLnRvTG93ZXJDYXNlKCksXG4gICAgICAgICAgc3VnZ2VzdGlvblRyaW1tZWQgPSBzdWdnZXN0ZWRUZXh0LnN1YnN0cmluZyh0aGlzLnN0YXRlLmlucHV0VGV4dC5sZW5ndGgpO1xuICAgICAgICBpZiAoIXN1Z2dlc3RlZFRleHQgfHwgIXRoaXMuc3RhdGUuaW5wdXRUZXh0IHx8IHN1Z2dlc3Rpb25TdGFydCAhPSB0aGlzLnN0YXRlLmlucHV0VGV4dC50b0xvd2VyQ2FzZSgpKSB7XG4gICAgICAgICAgdGhpcy5ET00uaW5wdXQucmVtb3ZlQXR0cmlidXRlKFwiZGF0YS1zdWdnZXN0XCIpO1xuICAgICAgICAgIGRlbGV0ZSB0aGlzLnN0YXRlLmlucHV0U3VnZ2VzdGlvbjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB0aGlzLkRPTS5pbnB1dC5zZXRBdHRyaWJ1dGUoXCJkYXRhLXN1Z2dlc3RcIiwgc3VnZ2VzdGlvblRyaW1tZWQpO1xuICAgICAgICAgIHRoaXMuc3RhdGUuaW5wdXRTdWdnZXN0aW9uID0gZGF0YTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIC8qKlxyXG4gICAgICAgKiBzZXRzIHRoZSBzdWdnZXN0ZWQgdGV4dCBhcyB0aGUgaW5wdXQncyB2YWx1ZSAmIGNsZWFudXAgdGhlIHN1Z2dlc3Rpb24gYXV0b2NvbXBsZXRlLlxyXG4gICAgICAgKiBAcGFyYW0ge1N0cmluZ30gcyBbdGV4dF1cclxuICAgICAgICovXG4gICAgICBzZXQocykge1xuICAgICAgICB2YXIgZGF0YVN1Z2dlc3QgPSB0aGlzLkRPTS5pbnB1dC5nZXRBdHRyaWJ1dGUoJ2RhdGEtc3VnZ2VzdCcpLFxuICAgICAgICAgIHN1Z2dlc3Rpb24gPSBzIHx8IChkYXRhU3VnZ2VzdCA/IHRoaXMuc3RhdGUuaW5wdXRUZXh0ICsgZGF0YVN1Z2dlc3QgOiBudWxsKTtcbiAgICAgICAgaWYgKHN1Z2dlc3Rpb24pIHtcbiAgICAgICAgICBpZiAodGhpcy5zZXR0aW5ncy5tb2RlID09ICdtaXgnKSB7XG4gICAgICAgICAgICB0aGlzLnJlcGxhY2VUZXh0V2l0aE5vZGUoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUodGhpcy5zdGF0ZS50YWcucHJlZml4ICsgc3VnZ2VzdGlvbikpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmlucHV0LnNldC5jYWxsKHRoaXMsIHN1Z2dlc3Rpb24pO1xuICAgICAgICAgICAgdGhpcy5zZXRSYW5nZUF0U3RhcnRFbmQoZmFsc2UsIHRoaXMuRE9NLmlucHV0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgdGhpcy5pbnB1dC5hdXRvY29tcGxldGUuc3VnZ2VzdC5jYWxsKHRoaXMpO1xuICAgICAgICAgIHRoaXMuZHJvcGRvd24uaGlkZSgpO1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIC8qKlxyXG4gICAqIHJldHVybnMgdGhlIGluZGV4IG9mIHRoZSB0aGUgdGFnRGF0YSB3aXRoaW4gdGhlIFwidGhpcy52YWx1ZVwiIGFycmF5IGNvbGxlY3Rpb24uXHJcbiAgICogc2luY2UgdmFsdWVzIHNob3VsZCBiZSB1bmlxdWUsIGl0IGlzIHN1ZmZpY2UgdG8gb25seSBzZWFyY2ggYnkgXCJ2YWx1ZVwiIHByb3BlcnR5XHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0RhdGFcclxuICAgKi9cbiAgZ2V0VGFnSWR4KHRhZ0RhdGEpIHtcbiAgICByZXR1cm4gdGhpcy52YWx1ZS5maW5kSW5kZXgoaXRlbSA9PiBpdGVtLl9fdGFnSWQgPT0gKHRhZ0RhdGEgfHwge30pLl9fdGFnSWQpO1xuICB9LFxuICBnZXROb2RlSW5kZXgobm9kZSkge1xuICAgIHZhciBpbmRleCA9IDA7XG4gICAgaWYgKG5vZGUpIHdoaWxlIChub2RlID0gbm9kZS5wcmV2aW91c0VsZW1lbnRTaWJsaW5nKSBpbmRleCsrO1xuICAgIHJldHVybiBpbmRleDtcbiAgfSxcbiAgZ2V0VGFnRWxtcygpIHtcbiAgICBmb3IgKHZhciBfbGVuID0gYXJndW1lbnRzLmxlbmd0aCwgY2xhc3Nlc3MgPSBuZXcgQXJyYXkoX2xlbiksIF9rZXkgPSAwOyBfa2V5IDwgX2xlbjsgX2tleSsrKSB7XG4gICAgICBjbGFzc2Vzc1tfa2V5XSA9IGFyZ3VtZW50c1tfa2V5XTtcbiAgICB9XG4gICAgdmFyIGNsYXNzbmFtZSA9ICcuJyArIFsuLi50aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMudGFnLnNwbGl0KCcgJyksIC4uLmNsYXNzZXNzXS5qb2luKCcuJyk7XG4gICAgcmV0dXJuIFtdLnNsaWNlLmNhbGwodGhpcy5ET00uc2NvcGUucXVlcnlTZWxlY3RvckFsbChjbGFzc25hbWUpKTsgLy8gY29udmVydCBub2RlTGlzdCB0byBBcnJheSAtIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zMTk5NjI3LzEwNDM4MFxuICB9LFxuXG4gIC8qKlxyXG4gICAqIGdldHMgdGhlIGxhc3Qgbm9uLXJlYWRvbmx5LCBub3QtaW4tdGhlLXByb2NjZXNzLW9mLXJlbW92YWwgdGFnXHJcbiAgICovXG4gIGdldExhc3RUYWcoKSB7XG4gICAgdmFyIGxhc3RUYWcgPSB0aGlzLkRPTS5zY29wZS5xdWVyeVNlbGVjdG9yQWxsKGAke3RoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy50YWdTZWxlY3Rvcn06bm90KC4ke3RoaXMuc2V0dGluZ3MuY2xhc3NOYW1lcy50YWdIaWRlfSk6bm90KFtyZWFkb25seV0pYCk7XG4gICAgcmV0dXJuIGxhc3RUYWdbbGFzdFRhZy5sZW5ndGggLSAxXTtcbiAgfSxcbiAgLyoqXHJcbiAgICogU2VhcmNoZXMgaWYgYW55IHRhZyB3aXRoIGEgY2VydGFpbiB2YWx1ZSBhbHJlYWR5IGV4aXNcclxuICAgKiBAcGFyYW0gIHtTdHJpbmcvT2JqZWN0fSB2YWx1ZSBbdGV4dCB2YWx1ZSAvIHRhZyBkYXRhIG9iamVjdF1cclxuICAgKiBAcGFyYW0gIHtCb29sZWFufSBjYXNlU2Vuc2l0aXZlXHJcbiAgICogQHJldHVybiB7TnVtYmVyfVxyXG4gICAqL1xuICBpc1RhZ0R1cGxpY2F0ZSh2YWx1ZSwgY2FzZVNlbnNpdGl2ZSwgdGFnSWQpIHtcbiAgICB2YXIgZHVwc0NvdW50ID0gMCxcbiAgICAgIF9zID0gdGhpcy5zZXR0aW5ncztcblxuICAgIC8vIGR1cGxpY2F0aW9ucyBhcmUgaXJyZWxldmFudCBmb3IgdGhpcyBzY2VuYXJpb1xuICAgIGlmIChfcy5tb2RlID09ICdzZWxlY3QnKSByZXR1cm4gZmFsc2U7XG4gICAgZm9yIChsZXQgaXRlbSBvZiB0aGlzLnZhbHVlKSB7XG4gICAgICBsZXQgaXNTYW1lU3RyID0gc2FtZVN0cih0aGlzLnRyaW0oXCJcIiArIHZhbHVlKSwgaXRlbS52YWx1ZSwgY2FzZVNlbnNpdGl2ZSk7XG4gICAgICBpZiAoaXNTYW1lU3RyICYmIHRhZ0lkICE9IGl0ZW0uX190YWdJZCkgZHVwc0NvdW50Kys7XG4gICAgfVxuICAgIHJldHVybiBkdXBzQ291bnQ7XG4gIH0sXG4gIGdldFRhZ0luZGV4QnlWYWx1ZSh2YWx1ZSkge1xuICAgIHZhciBpbmRpY2VzID0gW107XG4gICAgdGhpcy5nZXRUYWdFbG1zKCkuZm9yRWFjaCgodGFnRWxtLCBpKSA9PiB7XG4gICAgICBpZiAoc2FtZVN0cih0aGlzLnRyaW0odGFnRWxtLnRleHRDb250ZW50KSwgdmFsdWUsIHRoaXMuc2V0dGluZ3MuZHJvcGRvd24uY2FzZVNlbnNpdGl2ZSkpIGluZGljZXMucHVzaChpKTtcbiAgICB9KTtcbiAgICByZXR1cm4gaW5kaWNlcztcbiAgfSxcbiAgZ2V0VGFnRWxtQnlWYWx1ZSh2YWx1ZSkge1xuICAgIHZhciB0YWdJZHggPSB0aGlzLmdldFRhZ0luZGV4QnlWYWx1ZSh2YWx1ZSlbMF07XG4gICAgcmV0dXJuIHRoaXMuZ2V0VGFnRWxtcygpW3RhZ0lkeF07XG4gIH0sXG4gIC8qKlxyXG4gICAqIFRlbXBvcmFyaWx5IG1hcmtzIGEgdGFnIGVsZW1lbnQgKGJ5IHZhbHVlIG9yIE5vZGUgYXJndW1lbnQpXHJcbiAgICogQHBhcmFtICB7T2JqZWN0fSB0YWdFbG0gW2Egc3BlY2lmaWMgXCJ0YWdcIiBlbGVtZW50IHRvIGNvbXBhcmUgdG8gdGhlIG90aGVyIHRhZyBlbGVtZW50cyBzaWJsaW5nc11cclxuICAgKi9cbiAgZmxhc2hUYWcodGFnRWxtKSB7XG4gICAgaWYgKHRhZ0VsbSkge1xuICAgICAgdGFnRWxtLmNsYXNzTGlzdC5hZGQodGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ0ZsYXNoKTtcbiAgICAgIHNldFRpbWVvdXQoKCkgPT4ge1xuICAgICAgICB0YWdFbG0uY2xhc3NMaXN0LnJlbW92ZSh0aGlzLnNldHRpbmdzLmNsYXNzTmFtZXMudGFnRmxhc2gpO1xuICAgICAgfSwgMTAwKTtcbiAgICB9XG4gIH0sXG4gIC8qKlxyXG4gICAqIGNoZWNrcyBpZiB0ZXh0IGlzIGluIHRoZSBibGFja2xpc3RcclxuICAgKi9cbiAgaXNUYWdCbGFja2xpc3RlZCh2KSB7XG4gICAgdiA9IHRoaXMudHJpbSh2LnRvTG93ZXJDYXNlKCkpO1xuICAgIHJldHVybiB0aGlzLnNldHRpbmdzLmJsYWNrbGlzdC5maWx0ZXIoeCA9PiAoXCJcIiArIHgpLnRvTG93ZXJDYXNlKCkgPT0gdikubGVuZ3RoO1xuICB9LFxuICAvKipcclxuICAgKiBjaGVja3MgaWYgdGV4dCBpcyBpbiB0aGUgd2hpdGVsaXN0XHJcbiAgICovXG4gIGlzVGFnV2hpdGVsaXN0ZWQodikge1xuICAgIHJldHVybiAhIXRoaXMuZ2V0V2hpdGVsaXN0SXRlbSh2KTtcbiAgICAvKlxyXG4gICAgcmV0dXJuIHRoaXMuc2V0dGluZ3Mud2hpdGVsaXN0LnNvbWUoaXRlbSA9PlxyXG4gICAgICAgIHR5cGVvZiB2ID09ICdzdHJpbmcnXHJcbiAgICAgICAgICAgID8gc2FtZVN0cih0aGlzLnRyaW0odiksIChpdGVtLnZhbHVlIHx8IGl0ZW0pKVxyXG4gICAgICAgICAgICA6IHNhbWVTdHIoSlNPTi5zdHJpbmdpZnkoaXRlbSksIEpTT04uc3RyaW5naWZ5KHYpKVxyXG4gICAgKVxyXG4gICAgKi9cbiAgfSxcblxuICAvKipcclxuICAgKiBSZXR1cm5zIHRoZSBmaXJzdCB3aGl0ZWxpc3QgaXRlbSBtYXRjaGVkLCBieSB2YWx1ZSAoaWYgbWF0Y2ggZm91bmQpXHJcbiAgICogQHBhcmFtIHtTdHJpbmd9IHZhbHVlIFt0ZXh0IHRvIG1hdGNoIGJ5XVxyXG4gICAqL1xuICBnZXRXaGl0ZWxpc3RJdGVtKHZhbHVlLCBwcm9wLCB3aGl0ZWxpc3QpIHtcbiAgICB2YXIgcmVzdWx0LFxuICAgICAgcHJvcCA9IHByb3AgfHwgJ3ZhbHVlJyxcbiAgICAgIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgIHdoaXRlbGlzdCA9IHdoaXRlbGlzdCB8fCBfcy53aGl0ZWxpc3Q7XG4gICAgd2hpdGVsaXN0LnNvbWUoX3dpID0+IHtcbiAgICAgIHZhciBfd2l2ID0gdHlwZW9mIF93aSA9PSAnc3RyaW5nJyA/IF93aSA6IF93aVtwcm9wXSB8fCBfd2kudmFsdWUsXG4gICAgICAgIGlzU2FtZVN0ciA9IHNhbWVTdHIoX3dpdiwgdmFsdWUsIF9zLmRyb3Bkb3duLmNhc2VTZW5zaXRpdmUsIF9zLnRyaW0pO1xuICAgICAgaWYgKGlzU2FtZVN0cikge1xuICAgICAgICByZXN1bHQgPSB0eXBlb2YgX3dpID09ICdzdHJpbmcnID8ge1xuICAgICAgICAgIHZhbHVlOiBfd2lcbiAgICAgICAgfSA6IF93aTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBmaXJzdCBpdGVyYXRlIHRoZSB3aGl0ZWxpc3QsIHRyeSBmaW5kIG1hdGNoZXMgYnkgXCJ2YWx1ZVwiIGFuZCBpZiB0aGF0IGZhaWxzXG4gICAgLy8gYW5kIGEgXCJ0YWdUZXh0UHJvcFwiIGlzIHNldCB0byBiZSBvdGhlciB0aGFuIFwidmFsdWVcIiwgdHJ5IHRoYXQgYWxzb1xuICAgIGlmICghcmVzdWx0ICYmIHByb3AgPT0gJ3ZhbHVlJyAmJiBfcy50YWdUZXh0UHJvcCAhPSAndmFsdWUnKSB7XG4gICAgICAvLyBpZiBmb3VuZCwgYWRkcyB0aGUgZmlyc3Qgd2hpY2ggbWF0Y2hlc1xuICAgICAgcmVzdWx0ID0gdGhpcy5nZXRXaGl0ZWxpc3RJdGVtKHZhbHVlLCBfcy50YWdUZXh0UHJvcCwgd2hpdGVsaXN0KTtcbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSxcbiAgLyoqXHJcbiAgICogdmFsaWRhdGUgYSB0YWcgb2JqZWN0IEJFRk9SRSB0aGUgYWN0dWFsIHRhZyB3aWxsIGJlIGNyZWF0ZWQgJiBhcHBlbmVkZWRcclxuICAgKiBAcGFyYW0gIHtTdHJpbmd9IHNcclxuICAgKiBAcGFyYW0gIHtTdHJpbmd9IHVpZCAgICAgIFt1bmlxdWUgSUQsIHRvIG5vdCBpbmNsdWUgb3duIHRhZyB3aGVuIGNoZWtpbmcgZm9yIGR1cGxpY2F0ZXNdXHJcbiAgICogQHJldHVybiB7Qm9vbGVhbi9TdHJpbmd9ICBbXCJ0cnVlXCIgaWYgdmFsaWRhdGlvbiBoYXMgcGFzc2VkLCBTdHJpbmcgZm9yIGEgZmFpbF1cclxuICAgKi9cbiAgdmFsaWRhdGVUYWcodGFnRGF0YSkge1xuICAgIHZhciBfcyA9IHRoaXMuc2V0dGluZ3MsXG4gICAgICAvLyB3aGVuIHZhbGlkYXRpbmcgYSB0YWcgaW4gZWRpdC1tb2RlLCBuZWVkIHRvIHRha2UgXCJ0YWdUZXh0UHJvcFwiIGludG8gY29uc2lkZXJhdGlvblxuICAgICAgcHJvcCA9IFwidmFsdWVcIiBpbiB0YWdEYXRhID8gXCJ2YWx1ZVwiIDogX3MudGFnVGV4dFByb3AsXG4gICAgICB2ID0gdGhpcy50cmltKHRhZ0RhdGFbcHJvcF0gKyBcIlwiKTtcblxuICAgIC8vIGNoZWNrIGZvciBkZWZpbml0aXZlIGVtcHR5IHZhbHVlXG4gICAgaWYgKCEodGFnRGF0YVtwcm9wXSArIFwiXCIpLnRyaW0oKSkgcmV0dXJuIHRoaXMuVEVYVFMuZW1wdHk7XG5cbiAgICAvLyBjaGVjayBpZiBwYXR0ZXJuIHNob3VsZCBiZSB1c2VkIGFuZCBpZiBzbywgdXNlIGl0IHRvIHRlc3QgdGhlIHZhbHVlXG4gICAgaWYgKF9zLnBhdHRlcm4gJiYgX3MucGF0dGVybiBpbnN0YW5jZW9mIFJlZ0V4cCAmJiAhX3MucGF0dGVybi50ZXN0KHYpKSByZXR1cm4gdGhpcy5URVhUUy5wYXR0ZXJuO1xuXG4gICAgLy8gY2hlY2sgZm9yIGR1cGxpY2F0ZXNcbiAgICBpZiAoIV9zLmR1cGxpY2F0ZXMgJiYgdGhpcy5pc1RhZ0R1cGxpY2F0ZSh2LCBfcy5kcm9wZG93bi5jYXNlU2Vuc2l0aXZlLCB0YWdEYXRhLl9fdGFnSWQpKSByZXR1cm4gdGhpcy5URVhUUy5kdXBsaWNhdGU7XG4gICAgaWYgKHRoaXMuaXNUYWdCbGFja2xpc3RlZCh2KSB8fCBfcy5lbmZvcmNlV2hpdGVsaXN0ICYmICF0aGlzLmlzVGFnV2hpdGVsaXN0ZWQodikpIHJldHVybiB0aGlzLlRFWFRTLm5vdEFsbG93ZWQ7XG4gICAgaWYgKF9zLnZhbGlkYXRlKSByZXR1cm4gX3MudmFsaWRhdGUodGFnRGF0YSk7XG4gICAgcmV0dXJuIHRydWU7XG4gIH0sXG4gIGdldEludmFsaWRUYWdBdHRycyh0YWdEYXRhLCB2YWxpZGF0aW9uKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIFwiYXJpYS1pbnZhbGlkXCI6IHRydWUsXG4gICAgICBcImNsYXNzXCI6IGAke3RhZ0RhdGEuY2xhc3MgfHwgJyd9ICR7dGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ05vdEFsbG93ZWR9YC50cmltKCksXG4gICAgICBcInRpdGxlXCI6IHZhbGlkYXRpb25cbiAgICB9O1xuICB9LFxuICBoYXNNYXhUYWdzKCkge1xuICAgIHJldHVybiB0aGlzLnZhbHVlLmxlbmd0aCA+PSB0aGlzLnNldHRpbmdzLm1heFRhZ3MgPyB0aGlzLlRFWFRTLmV4Y2VlZCA6IGZhbHNlO1xuICB9LFxuICBzZXRSZWFkb25seSh0b2dnbGUsIGF0dHJyaWJ1dGUpIHtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzO1xuICAgIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQuYmx1cigpOyAvLyBleGl0IHBvc3NpYmxlIGVkaXQtbW9kZVxuICAgIF9zW2F0dHJyaWJ1dGUgfHwgJ3JlYWRvbmx5J10gPSB0b2dnbGU7XG4gICAgdGhpcy5ET00uc2NvcGVbKHRvZ2dsZSA/ICdzZXQnIDogJ3JlbW92ZScpICsgJ0F0dHJpYnV0ZSddKGF0dHJyaWJ1dGUgfHwgJ3JlYWRvbmx5JywgdHJ1ZSk7XG4gICAgdGhpcy5zZXRDb250ZW50RWRpdGFibGUoIXRvZ2dsZSk7XG4gIH0sXG4gIHNldENvbnRlbnRFZGl0YWJsZShzdGF0ZSkge1xuICAgIGlmICghdGhpcy5zZXR0aW5ncy51c2VySW5wdXQpIHJldHVybjtcbiAgICB0aGlzLkRPTS5pbnB1dC5jb250ZW50RWRpdGFibGUgPSBzdGF0ZTtcbiAgICB0aGlzLkRPTS5pbnB1dC50YWJJbmRleCA9ICEhc3RhdGUgPyAwIDogLTE7XG4gIH0sXG4gIHNldERpc2FibGVkKGlzRGlzYWJsZWQpIHtcbiAgICB0aGlzLnNldFJlYWRvbmx5KGlzRGlzYWJsZWQsICdkaXNhYmxlZCcpO1xuICB9LFxuICAvKipcclxuICAgKiBwcmUtcHJvY2Nlc3MgdGhlIHRhZ3NJdGVtcywgd2hpY2ggY2FuIGJlIGEgY29tcGxleCB0YWdzSXRlbXMgbGlrZSBhbiBBcnJheSBvZiBPYmplY3RzIG9yIGEgc3RyaW5nIGNvbXByaXNlZCBvZiBtdWx0aXBsZSB3b3Jkc1xyXG4gICAqIHNvIGVhY2ggaXRlbSBzaG91bGQgYmUgaXRlcmF0ZWQgb24gYW5kIGEgdGFnIGNyZWF0ZWQgZm9yLlxyXG4gICAqIEByZXR1cm4ge0FycmF5fSBbQXJyYXkgb2YgT2JqZWN0c11cclxuICAgKi9cbiAgbm9ybWFsaXplVGFncyh0YWdzSXRlbXMpIHtcbiAgICB2YXIgX3RoaXMkc2V0dGluZ3MgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgd2hpdGVsaXN0ID0gX3RoaXMkc2V0dGluZ3Mud2hpdGVsaXN0LFxuICAgICAgZGVsaW1pdGVycyA9IF90aGlzJHNldHRpbmdzLmRlbGltaXRlcnMsXG4gICAgICBtb2RlID0gX3RoaXMkc2V0dGluZ3MubW9kZSxcbiAgICAgIHRhZ1RleHRQcm9wID0gX3RoaXMkc2V0dGluZ3MudGFnVGV4dFByb3AsXG4gICAgICB3aGl0ZWxpc3RNYXRjaGVzID0gW10sXG4gICAgICB3aGl0ZWxpc3RXaXRoUHJvcHMgPSB3aGl0ZWxpc3QgPyB3aGl0ZWxpc3RbMF0gaW5zdGFuY2VvZiBPYmplY3QgOiBmYWxzZSxcbiAgICAgIGlzQXJyYXkgPSBBcnJheS5pc0FycmF5KHRhZ3NJdGVtcyksXG4gICAgICBpc0NvbGxlY3Rpb24gPSBpc0FycmF5ICYmIHRhZ3NJdGVtc1swXS52YWx1ZSxcbiAgICAgIG1hcFN0cmluZ1RvQ29sbGVjdGlvbiA9IHMgPT4gKHMgKyBcIlwiKS5zcGxpdChkZWxpbWl0ZXJzKS5maWx0ZXIobiA9PiBuKS5tYXAodiA9PiAoe1xuICAgICAgICBbdGFnVGV4dFByb3BdOiB0aGlzLnRyaW0odiksXG4gICAgICAgIHZhbHVlOiB0aGlzLnRyaW0odilcbiAgICAgIH0pKTtcbiAgICBpZiAodHlwZW9mIHRhZ3NJdGVtcyA9PSAnbnVtYmVyJykgdGFnc0l0ZW1zID0gdGFnc0l0ZW1zLnRvU3RyaW5nKCk7XG5cbiAgICAvLyBpZiB0aGUgYXJndW1lbnQgaXMgYSBcInNpbXBsZVwiIFN0cmluZywgZXg6IFwiYWFhLCBiYmIsIGNjY1wiXG4gICAgaWYgKHR5cGVvZiB0YWdzSXRlbXMgPT0gJ3N0cmluZycpIHtcbiAgICAgIGlmICghdGFnc0l0ZW1zLnRyaW0oKSkgcmV0dXJuIFtdO1xuXG4gICAgICAvLyBnbyBvdmVyIGVhY2ggdGFnIGFuZCBhZGQgaXQgKGlmIHRoZXJlIHdlcmUgbXVsdGlwbGUgb25lcylcbiAgICAgIHRhZ3NJdGVtcyA9IG1hcFN0cmluZ1RvQ29sbGVjdGlvbih0YWdzSXRlbXMpO1xuICAgIH1cblxuICAgIC8vIGlmIGlzIGFuIEFycmF5IG9mIFN0cmluZ3MsIGNvbnZlcnQgdG8gYW4gQXJyYXkgb2YgT2JqZWN0c1xuICAgIGVsc2UgaWYgKGlzQXJyYXkpIHtcbiAgICAgIC8vIGZsYXR0ZW4gdGhlIDJEIGFycmF5XG4gICAgICB0YWdzSXRlbXMgPSBbXS5jb25jYXQoLi4udGFnc0l0ZW1zLm1hcChpdGVtID0+IGl0ZW0udmFsdWUgIT0gdW5kZWZpbmVkID8gaXRlbSAvLyBtYXBTdHJpbmdUb0NvbGxlY3Rpb24oaXRlbS52YWx1ZSkubWFwKG5ld0l0ZW0gPT4gKHsuLi5pdGVtLC4uLm5ld0l0ZW19KSlcbiAgICAgIDogbWFwU3RyaW5nVG9Db2xsZWN0aW9uKGl0ZW0pKSk7XG4gICAgfVxuXG4gICAgLy8gc2VhcmNoIGlmIHRoZSB0YWcgZXhpc3RzIGluIHRoZSB3aGl0ZWxpc3QgYXMgYW4gT2JqZWN0IChoYXMgcHJvcHMpLFxuICAgIC8vIHRvIGJlIGFibGUgdG8gdXNlIGl0cyBwcm9wZXJ0aWVzLlxuICAgIC8vIHNraXAgbWF0Y2hpbmcgY29sbGVjdGlvbnMgd2l0aCB3aGl0ZWxpc3QgaXRlbXMgYXMgdGhleSBhcmUgY29uc2lkZXJlZCBcIndob2xlXCJcbiAgICBpZiAod2hpdGVsaXN0V2l0aFByb3BzICYmICFpc0NvbGxlY3Rpb24pIHtcbiAgICAgIHRhZ3NJdGVtcy5mb3JFYWNoKGl0ZW0gPT4ge1xuICAgICAgICB2YXIgd2hpdGVsaXN0TWF0Y2hlc1ZhbHVlcyA9IHdoaXRlbGlzdE1hdGNoZXMubWFwKGEgPT4gYS52YWx1ZSk7XG5cbiAgICAgICAgLy8gaWYgc3VnZ2VzdGlvbnMgYXJlIHNob3duLCB0aGV5IGFyZSBhbHJlYWR5IGZpbHRlcmVkLCBzbyBpdCdzIGVhc2llciB0byB1c2UgdGhlbSxcbiAgICAgICAgLy8gYmVjYXVzZSB0aGUgd2hpdGVsaXN0IG1pZ2h0IGFsc28gaW5jbHVkZSBpdGVtcyB3aGljaCBoYXZlIGFscmVhZHkgYmVlbiBhZGRlZFxuICAgICAgICB2YXIgZmlsdGVyZWRMaXN0ID0gdGhpcy5kcm9wZG93bi5maWx0ZXJMaXN0SXRlbXMuY2FsbCh0aGlzLCBpdGVtW3RhZ1RleHRQcm9wXSwge1xuICAgICAgICAgIGV4YWN0OiB0cnVlXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoIXRoaXMuc2V0dGluZ3MuZHVwbGljYXRlcylcbiAgICAgICAgICAvLyBhbHNvIGZpbHRlciBvdXQgaXRlbXMgd2hpY2ggaGF2ZSBhbHJlYWR5IGJlZW4gbWF0Y2hlZCBpbiBwcmV2aW91cyBpdGVyYXRpb25zXG4gICAgICAgICAgZmlsdGVyZWRMaXN0ID0gZmlsdGVyZWRMaXN0LmZpbHRlcihmaWx0ZXJlZEl0ZW0gPT4gIXdoaXRlbGlzdE1hdGNoZXNWYWx1ZXMuaW5jbHVkZXMoZmlsdGVyZWRJdGVtLnZhbHVlKSk7XG5cbiAgICAgICAgLy8gZ2V0IHRoZSBiZXN0IG1hdGNoIG91dCBvZiBsaXN0IG9mIHBvc3NpYmxlIG1hdGNoZXMuXG4gICAgICAgIC8vIGlmIHRoZXJlIHdhcyBhIHNpbmdsZSBpdGVtIGluIHRoZSBmaWx0ZXJlZCBsaXN0LCB1c2UgdGhhdCBvbmVcbiAgICAgICAgdmFyIG1hdGNoT2JqID0gZmlsdGVyZWRMaXN0Lmxlbmd0aCA+IDEgPyB0aGlzLmdldFdoaXRlbGlzdEl0ZW0oaXRlbVt0YWdUZXh0UHJvcF0sIHRhZ1RleHRQcm9wLCBmaWx0ZXJlZExpc3QpIDogZmlsdGVyZWRMaXN0WzBdO1xuICAgICAgICBpZiAobWF0Y2hPYmogJiYgbWF0Y2hPYmogaW5zdGFuY2VvZiBPYmplY3QpIHtcbiAgICAgICAgICB3aGl0ZWxpc3RNYXRjaGVzLnB1c2gobWF0Y2hPYmopOyAvLyBzZXQgdGhlIEFycmF5ICh3aXRoIHRoZSBmb3VuZCBPYmplY3QpIGFzIHRoZSBuZXcgdmFsdWVcbiAgICAgICAgfSBlbHNlIGlmIChtb2RlICE9ICdtaXgnKSB7XG4gICAgICAgICAgaWYgKGl0ZW0udmFsdWUgPT0gdW5kZWZpbmVkKSBpdGVtLnZhbHVlID0gaXRlbVt0YWdUZXh0UHJvcF07XG4gICAgICAgICAgd2hpdGVsaXN0TWF0Y2hlcy5wdXNoKGl0ZW0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICAgIGlmICh3aGl0ZWxpc3RNYXRjaGVzLmxlbmd0aCkgdGFnc0l0ZW1zID0gd2hpdGVsaXN0TWF0Y2hlcztcbiAgICB9XG4gICAgcmV0dXJuIHRhZ3NJdGVtcztcbiAgfSxcbiAgLyoqXHJcbiAgICogUGFyc2UgdGhlIGluaXRpYWwgdmFsdWUgb2YgYSB0ZXh0YXJlYSAob3IgaW5wdXQpIGVsZW1lbnQgYW5kIGdlbmVyYXRlIG1peGVkIHRleHQgdy8gdGFnc1xyXG4gICAqIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS81NzU5ODg5Mi8xMDQzODBcclxuICAgKiBAcGFyYW0ge1N0cmluZ30gc1xyXG4gICAqL1xuICBwYXJzZU1peFRhZ3Mocykge1xuICAgIHZhciBfdGhpcyRzZXR0aW5nczIgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgbWl4VGFnc0ludGVycG9sYXRvciA9IF90aGlzJHNldHRpbmdzMi5taXhUYWdzSW50ZXJwb2xhdG9yLFxuICAgICAgZHVwbGljYXRlcyA9IF90aGlzJHNldHRpbmdzMi5kdXBsaWNhdGVzLFxuICAgICAgdHJhbnNmb3JtVGFnID0gX3RoaXMkc2V0dGluZ3MyLnRyYW5zZm9ybVRhZyxcbiAgICAgIGVuZm9yY2VXaGl0ZWxpc3QgPSBfdGhpcyRzZXR0aW5nczIuZW5mb3JjZVdoaXRlbGlzdCxcbiAgICAgIG1heFRhZ3MgPSBfdGhpcyRzZXR0aW5nczIubWF4VGFncyxcbiAgICAgIHRhZ1RleHRQcm9wID0gX3RoaXMkc2V0dGluZ3MyLnRhZ1RleHRQcm9wLFxuICAgICAgdGFnc0RhdGFTZXQgPSBbXTtcbiAgICBzID0gcy5zcGxpdChtaXhUYWdzSW50ZXJwb2xhdG9yWzBdKS5tYXAoKHMxLCBpKSA9PiB7XG4gICAgICB2YXIgczIgPSBzMS5zcGxpdChtaXhUYWdzSW50ZXJwb2xhdG9yWzFdKSxcbiAgICAgICAgcHJlSW50ZXJwb2xhdGVkID0gczJbMF0sXG4gICAgICAgIG1heFRhZ3NSZWFjaGVkID0gdGFnc0RhdGFTZXQubGVuZ3RoID09IG1heFRhZ3MsXG4gICAgICAgIHRleHRQcm9wLFxuICAgICAgICB0YWdEYXRhLFxuICAgICAgICB0YWdFbG07XG4gICAgICB0cnkge1xuICAgICAgICAvLyBza2lwIG51bWJlcnMgYW5kIGdvIHN0cmFpZ2h0IHRvIHRoZSBcImNhdGNoXCIgc3RhdGVtZW50XG4gICAgICAgIGlmIChwcmVJbnRlcnBvbGF0ZWQgPT0gK3ByZUludGVycG9sYXRlZCkgdGhyb3cgRXJyb3I7XG4gICAgICAgIHRhZ0RhdGEgPSBKU09OLnBhcnNlKHByZUludGVycG9sYXRlZCk7XG4gICAgICB9IGNhdGNoIChlcnIpIHtcbiAgICAgICAgdGFnRGF0YSA9IHRoaXMubm9ybWFsaXplVGFncyhwcmVJbnRlcnBvbGF0ZWQpWzBdIHx8IHtcbiAgICAgICAgICB2YWx1ZTogcHJlSW50ZXJwb2xhdGVkXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICB0cmFuc2Zvcm1UYWcuY2FsbCh0aGlzLCB0YWdEYXRhKTtcbiAgICAgIGlmICghbWF4VGFnc1JlYWNoZWQgJiYgczIubGVuZ3RoID4gMSAmJiAoIWVuZm9yY2VXaGl0ZWxpc3QgfHwgdGhpcy5pc1RhZ1doaXRlbGlzdGVkKHRhZ0RhdGEudmFsdWUpKSAmJiAhKCFkdXBsaWNhdGVzICYmIHRoaXMuaXNUYWdEdXBsaWNhdGUodGFnRGF0YS52YWx1ZSkpKSB7XG4gICAgICAgIC8vIGluIGNhc2UgXCJ0YWdUZXh0UHJvcFwiIHNldHRpbmcgaXMgc2V0IHRvIG90aGVyIHRoYW4gXCJ2YWx1ZVwiIGFuZCB0aGlzIHRhZyBkb2VzIG5vdCBoYXZlIHRoaXMgcHJvcFxuICAgICAgICB0ZXh0UHJvcCA9IHRhZ0RhdGFbdGFnVGV4dFByb3BdID8gdGFnVGV4dFByb3AgOiAndmFsdWUnO1xuICAgICAgICB0YWdEYXRhW3RleHRQcm9wXSA9IHRoaXMudHJpbSh0YWdEYXRhW3RleHRQcm9wXSk7XG4gICAgICAgIHRhZ0VsbSA9IHRoaXMuY3JlYXRlVGFnRWxlbSh0YWdEYXRhKTtcbiAgICAgICAgdGFnc0RhdGFTZXQucHVzaCh0YWdEYXRhKTtcbiAgICAgICAgdGFnRWxtLmNsYXNzTGlzdC5hZGQodGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ05vQW5pbWF0aW9uKTtcbiAgICAgICAgczJbMF0gPSB0YWdFbG0ub3V0ZXJIVE1MOyAvLysgXCImIzgyODg7XCIgIC8vIHB1dCBhIHplcm8tc3BhY2UgYXQgdGhlIGVuZCBzbyB0aGUgY2FyZXQgd29uJ3QganVtcCBiYWNrIHRvIHRoZSBzdGFydCAod2hlbiB0aGUgbGFzdCBpbnB1dCdzIGNoaWxkIGVsZW1lbnQgaXMgYSB0YWcpXG4gICAgICAgIHRoaXMudmFsdWUucHVzaCh0YWdEYXRhKTtcbiAgICAgIH0gZWxzZSBpZiAoczEpIHJldHVybiBpID8gbWl4VGFnc0ludGVycG9sYXRvclswXSArIHMxIDogczE7XG4gICAgICByZXR1cm4gczIuam9pbignJyk7XG4gICAgfSkuam9pbignJyk7XG4gICAgdGhpcy5ET00uaW5wdXQuaW5uZXJIVE1MID0gcztcbiAgICB0aGlzLkRPTS5pbnB1dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnJykpO1xuICAgIHRoaXMuRE9NLmlucHV0Lm5vcm1hbGl6ZSgpO1xuICAgIHRoaXMuZ2V0VGFnRWxtcygpLmZvckVhY2goKGVsbSwgaWR4KSA9PiBnZXRTZXRUYWdEYXRhKGVsbSwgdGFnc0RhdGFTZXRbaWR4XSkpO1xuICAgIHRoaXMudXBkYXRlKHtcbiAgICAgIHdpdGhvdXRDaGFuZ2VFdmVudDogdHJ1ZVxuICAgIH0pO1xuICAgIHJldHVybiBzO1xuICB9LFxuICAvKipcclxuICAgKiBGb3IgbWl4ZWQtbW9kZTogcmVwbGFjZXMgYSB0ZXh0IHN0YXJ0aW5nIHdpdGggYSBwcmVmaXggd2l0aCBhIHdyYXBwZXIgZWxlbWVudCAodGFnIG9yIHNvbWV0aGluZylcclxuICAgKiBGaXJzdCB0aGVyZSAqaGFzKiB0byBiZSBhIFwidGhpcy5zdGF0ZS50YWdcIiB3aGljaCBpcyBhIHN0cmluZyB0aGF0IHdhcyBqdXN0IHR5cGVkIGFuZCBpcyBzdGFyaW5nIHdpdGggYSBwcmVmaXhcclxuICAgKi9cbiAgcmVwbGFjZVRleHRXaXRoTm9kZShuZXdXcmFwcGVyTm9kZSwgc3RyVG9SZXBsYWNlKSB7XG4gICAgaWYgKCF0aGlzLnN0YXRlLnRhZyAmJiAhc3RyVG9SZXBsYWNlKSByZXR1cm47XG4gICAgc3RyVG9SZXBsYWNlID0gc3RyVG9SZXBsYWNlIHx8IHRoaXMuc3RhdGUudGFnLnByZWZpeCArIHRoaXMuc3RhdGUudGFnLnZhbHVlO1xuICAgIHZhciBpZHgsXG4gICAgICBub2RlVG9SZXBsYWNlLFxuICAgICAgc2VsZWN0aW9uID0gdGhpcy5zdGF0ZS5zZWxlY3Rpb24gfHwgd2luZG93LmdldFNlbGVjdGlvbigpLFxuICAgICAgbm9kZUF0Q2FyZXQgPSBzZWxlY3Rpb24uYW5jaG9yTm9kZSxcbiAgICAgIGZpcnN0U3BsaXRPZmZzZXQgPSB0aGlzLnN0YXRlLnRhZy5kZWxpbWl0ZXJzID8gdGhpcy5zdGF0ZS50YWcuZGVsaW1pdGVycy5sZW5ndGggOiAwO1xuXG4gICAgLy8gU1RFUCAxOiBleC4gcmVwbGFjZSAjYmEgd2l0aCB0aGUgdGFnIFwiYmFydFwiIHdoZXJlIFwifFwiIGlzIHdoZXJlIHRoZSBjYXJldCBpczpcbiAgICAvLyBDVVJSRU5UIFNUQVRFOiBcImZvbyAjYmEgI2JhfCAjYmFcIlxuXG4gICAgLy8gc3BsaXQgdGhlIHRleHQgbm9kZSBhdCB0aGUgaW5kZXggb2YgdGhlIGNhcmV0XG4gICAgbm9kZUF0Q2FyZXQuc3BsaXRUZXh0KHNlbGVjdGlvbi5hbmNob3JPZmZzZXQgLSBmaXJzdFNwbGl0T2Zmc2V0KTtcblxuICAgIC8vIG5vZGUgMDogXCJmb28gI2JhICNiYXxcIlxuICAgIC8vIG5vZGUgMTogXCIgI2JhXCJcblxuICAgIC8vIGdldCBpbmRleCBvZiBMQVNUIG9jY3VyZW5jZSBvZiBcIiNiYVwiXG4gICAgaWR4ID0gbm9kZUF0Q2FyZXQubm9kZVZhbHVlLmxhc3RJbmRleE9mKHN0clRvUmVwbGFjZSk7XG4gICAgaWYgKGlkeCA9PSAtMSkgcmV0dXJuIHRydWU7XG4gICAgbm9kZVRvUmVwbGFjZSA9IG5vZGVBdENhcmV0LnNwbGl0VGV4dChpZHgpO1xuXG4gICAgLy8gbm9kZSAwOiBcImZvbyAjYmEgXCJcbiAgICAvLyBub2RlIDE6IFwiI2JhXCIgICAgPC0gbm9kZVRvUmVwbGFjZVxuXG4gICAgbmV3V3JhcHBlck5vZGUgJiYgbm9kZUF0Q2FyZXQucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobmV3V3JhcHBlck5vZGUsIG5vZGVUb1JlcGxhY2UpO1xuXG4gICAgLy8gbXVzdCBOT1Qgbm9ybWFsaXplIGNvbnRlbnRlZGl0YWJsZSBvciBpdCB3aWxsIGNhdXNlIHVud2FudGVkIGlzc3VlczpcbiAgICAvLyBodHRwczovL21vbm9zbmFwLmNvbS9maWxlL1pEVm1SdnE1dXBZa2lkaUZlZHZyd3pTc3dlZ1drN1xuICAgIC8vIG5vZGVBdENhcmV0LnBhcmVudE5vZGUubm9ybWFsaXplKClcblxuICAgIHJldHVybiB0cnVlO1xuICB9LFxuICAvKipcclxuICAgKiBGb3Igc2VsZWN0aW5nIGEgc2luZ2xlIG9wdGlvbiAobm90IHVzZWQgZm9yIG11bHRpcGxlIHRhZ3MsIGJ1dCBmb3IgXCJtb2RlOnNlbGVjdFwiIG9ubHkpXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHRhZ0VsbSAgIFRhZyBET00gbm9kZVxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB0YWdEYXRhICBUYWcgZGF0YVxyXG4gICAqL1xuICBzZWxlY3RUYWcodGFnRWxtLCB0YWdEYXRhKSB7XG4gICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncztcbiAgICBpZiAoX3MuZW5mb3JjZVdoaXRlbGlzdCAmJiAhdGhpcy5pc1RhZ1doaXRlbGlzdGVkKHRhZ0RhdGEudmFsdWUpKSByZXR1cm47XG4gICAgdGhpcy5pbnB1dC5zZXQuY2FsbCh0aGlzLCB0YWdEYXRhW19zLnRhZ1RleHRQcm9wXSB8fCB0YWdEYXRhLnZhbHVlLCB0cnVlKTtcblxuICAgIC8vIHBsYWNlIHRoZSBjYXJldCBhdCB0aGUgZW5kIG9mIHRoZSBpbnB1dCwgb25seSBpZiBhIGRyb3Bkb3duIG9wdGlvbiB3YXMgc2VsZWN0ZWQgKGFuZCBub3QgYnkgbWFudWFsbHkgdHlwaW5nIGFub3RoZXIgdmFsdWUgYW5kIGNsaWNraW5nIFwiVEFCXCIpXG4gICAgaWYgKHRoaXMuc3RhdGUuYWN0aW9ucy5zZWxlY3RPcHRpb24pIHNldFRpbWVvdXQoKCkgPT4gdGhpcy5zZXRSYW5nZUF0U3RhcnRFbmQoZmFsc2UsIHRoaXMuRE9NLmlucHV0KSk7XG4gICAgdmFyIGxhc3RUYWdFbG0gPSB0aGlzLmdldExhc3RUYWcoKTtcbiAgICBpZiAobGFzdFRhZ0VsbSkgdGhpcy5yZXBsYWNlVGFnKGxhc3RUYWdFbG0sIHRhZ0RhdGEpO2Vsc2UgdGhpcy5hcHBlbmRUYWcodGFnRWxtKTtcblxuICAgIC8vIGlmKCBfcy5lbmZvcmNlV2hpdGVsaXN0IClcbiAgICAvLyAgICAgdGhpcy5zZXRDb250ZW50RWRpdGFibGUoZmFsc2UpO1xuXG4gICAgdGhpcy52YWx1ZVswXSA9IHRhZ0RhdGE7XG4gICAgdGhpcy51cGRhdGUoKTtcbiAgICB0aGlzLnRyaWdnZXIoJ2FkZCcsIHtcbiAgICAgIHRhZzogdGFnRWxtLFxuICAgICAgZGF0YTogdGFnRGF0YVxuICAgIH0pO1xuICAgIHJldHVybiBbdGFnRWxtXTtcbiAgfSxcbiAgLyoqXHJcbiAgICogYWRkIGFuIGVtcHR5IFwidGFnXCIgZWxlbWVudCBpbiBhbiBlZGl0YWJsZSBzdGF0ZVxyXG4gICAqL1xuICBhZGRFbXB0eVRhZyhpbml0aWFsRGF0YSkge1xuICAgIHZhciB0YWdEYXRhID0gZXh0ZW5kKHtcbiAgICAgICAgdmFsdWU6IFwiXCJcbiAgICAgIH0sIGluaXRpYWxEYXRhIHx8IHt9KSxcbiAgICAgIHRhZ0VsbSA9IHRoaXMuY3JlYXRlVGFnRWxlbSh0YWdEYXRhKTtcbiAgICBnZXRTZXRUYWdEYXRhKHRhZ0VsbSwgdGFnRGF0YSk7XG5cbiAgICAvLyBhZGQgdGhlIHRhZyB0byB0aGUgY29tcG9uZW50J3MgRE9NXG4gICAgdGhpcy5hcHBlbmRUYWcodGFnRWxtKTtcbiAgICB0aGlzLmVkaXRUYWcodGFnRWxtLCB7XG4gICAgICBza2lwVmFsaWRhdGlvbjogdHJ1ZVxuICAgIH0pO1xuICB9LFxuICAvKipcclxuICAgKiBhZGQgYSBcInRhZ1wiIGVsZW1lbnQgdG8gdGhlIFwidGFnc1wiIGNvbXBvbmVudFxyXG4gICAqIEBwYXJhbSB7U3RyaW5nL0FycmF5fSB0YWdzSXRlbXMgICBbQSBzdHJpbmcgKHNpbmdsZSBvciBtdWx0aXBsZSB2YWx1ZXMgd2l0aCBhIGRlbGltaXRlciksIG9yIGFuIEFycmF5IG9mIE9iamVjdHMgb3IganVzdCBBcnJheSBvZiBTdHJpbmdzXVxyXG4gICAqIEBwYXJhbSB7Qm9vbGVhbn0gICAgICBjbGVhcklucHV0ICBbZmxhZyBpZiB0aGUgaW5wdXQncyB2YWx1ZSBzaG91bGQgYmUgY2xlYXJlZCBhZnRlciBhZGRpbmcgdGFnc11cclxuICAgKiBAcGFyYW0ge0Jvb2xlYW59ICAgICAgc2tpcEludmFsaWQgW2RvIG5vdCBhZGQsIG1hcmsgJiByZW1vdmUgaW52YWxpZCB0YWdzXVxyXG4gICAqIEByZXR1cm4ge0FycmF5fSBBcnJheSBvZiBET00gZWxlbWVudHMgKHRhZ3MpXHJcbiAgICovXG4gIGFkZFRhZ3ModGFnc0l0ZW1zLCBjbGVhcklucHV0LCBza2lwSW52YWxpZCkge1xuICAgIHZhciB0YWdFbGVtcyA9IFtdLFxuICAgICAgX3MgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgYWdncmVnYXRlZGludmFsaWRJbnB1dCA9IFtdLFxuICAgICAgZnJhZyA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBza2lwSW52YWxpZCA9IHNraXBJbnZhbGlkIHx8IF9zLnNraXBJbnZhbGlkO1xuICAgIGlmICghdGFnc0l0ZW1zIHx8IHRhZ3NJdGVtcy5sZW5ndGggPT0gMCkge1xuICAgICAgcmV0dXJuIHRhZ0VsZW1zO1xuICAgIH1cblxuICAgIC8vIGNvbnZlcnRzIEFycmF5L1N0cmluZy9PYmplY3QgdG8gYW4gQXJyYXkgb2YgT2JqZWN0c1xuICAgIHRhZ3NJdGVtcyA9IHRoaXMubm9ybWFsaXplVGFncyh0YWdzSXRlbXMpO1xuICAgIHN3aXRjaCAoX3MubW9kZSkge1xuICAgICAgY2FzZSAnbWl4JzpcbiAgICAgICAgcmV0dXJuIHRoaXMuYWRkTWl4VGFncyh0YWdzSXRlbXMpO1xuICAgICAgY2FzZSAnc2VsZWN0JzpcbiAgICAgICAge1xuICAgICAgICAgIGNsZWFySW5wdXQgPSBmYWxzZTtcbiAgICAgICAgICB0aGlzLnJlbW92ZUFsbFRhZ3MoKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aGlzLkRPTS5pbnB1dC5yZW1vdmVBdHRyaWJ1dGUoJ3N0eWxlJyk7XG4gICAgdGFnc0l0ZW1zLmZvckVhY2godGFnRGF0YSA9PiB7XG4gICAgICB2YXIgdGFnRWxtLFxuICAgICAgICB0YWdFbG1QYXJhbXMgPSB7fSxcbiAgICAgICAgb3JpZ2luYWxEYXRhID0gT2JqZWN0LmFzc2lnbih7fSwgdGFnRGF0YSwge1xuICAgICAgICAgIHZhbHVlOiB0YWdEYXRhLnZhbHVlICsgXCJcIlxuICAgICAgICB9KTtcblxuICAgICAgLy8gc2hhbGxvdy1jbG9uZSB0YWdEYXRhIHNvIGxhdGVyIG1vZGlmaWNhdGlvbnMgd2lsbCBub3QgYXBwbHkgdG8gdGhlIHNvdXJjZVxuICAgICAgdGFnRGF0YSA9IE9iamVjdC5hc3NpZ24oe30sIG9yaWdpbmFsRGF0YSk7XG4gICAgICBfcy50cmFuc2Zvcm1UYWcuY2FsbCh0aGlzLCB0YWdEYXRhKTtcbiAgICAgIHRhZ0RhdGEuX19pc1ZhbGlkID0gdGhpcy5oYXNNYXhUYWdzKCkgfHwgdGhpcy52YWxpZGF0ZVRhZyh0YWdEYXRhKTtcbiAgICAgIGlmICh0YWdEYXRhLl9faXNWYWxpZCAhPT0gdHJ1ZSkge1xuICAgICAgICBpZiAoc2tpcEludmFsaWQpIHJldHVybjtcblxuICAgICAgICAvLyBvcmlnaW5hbERhdGEgaXMga2VwdCBiZWNhdXNlIGl0IG1pZ2h0IGJlIHRoYXQgdGhpcyB0YWcgaXMgaW52YWxpZCBiZWNhdXNlIGl0IGlzIGEgZHVwbGljYXRlIG9mIGFub3RoZXIsXG4gICAgICAgIC8vIGFuZCBpZiB0aGF0IG90aGVyIHRhZ3MgaXMgZWRpdGVkL2RlbGV0ZWQsIHRoaXMgb25lIHNob3VsZCBiZSByZS12YWxpZGF0ZWQgYW5kIGlmIGlzIG5vIG1vcmUgYSBkdXBsaWNhdGUgLSByZXN0b3JlZFxuICAgICAgICBleHRlbmQodGFnRWxtUGFyYW1zLCB0aGlzLmdldEludmFsaWRUYWdBdHRycyh0YWdEYXRhLCB0YWdEYXRhLl9faXNWYWxpZCksIHtcbiAgICAgICAgICBfX3ByZUludmFsaWREYXRhOiBvcmlnaW5hbERhdGFcbiAgICAgICAgfSk7XG4gICAgICAgIGlmICh0YWdEYXRhLl9faXNWYWxpZCA9PSB0aGlzLlRFWFRTLmR1cGxpY2F0ZSlcbiAgICAgICAgICAvLyBtYXJrLCBmb3IgYSBicmllZiBtb21lbnQsIHRoZSB0YWcgKHRoaXMgdGhpcyBvbmUpIHdoaWNoIFRISVMgQ1VSUkVOVCB0YWcgaXMgYSBkdXBsY2F0ZSBvZlxuICAgICAgICAgIHRoaXMuZmxhc2hUYWcodGhpcy5nZXRUYWdFbG1CeVZhbHVlKHRhZ0RhdGEudmFsdWUpKTtcbiAgICAgICAgaWYgKCFfcy5jcmVhdGVJbnZhbGlkVGFncykge1xuICAgICAgICAgIGFnZ3JlZ2F0ZWRpbnZhbGlkSW5wdXQucHVzaCh0YWdEYXRhLnZhbHVlKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmICgncmVhZG9ubHknIGluIHRhZ0RhdGEpIHtcbiAgICAgICAgaWYgKHRhZ0RhdGEucmVhZG9ubHkpIHRhZ0VsbVBhcmFtc1tcImFyaWEtcmVhZG9ubHlcIl0gPSB0cnVlO1xuICAgICAgICAvLyBpZiBcInJlYWRvbmx5XCIgaXMgXCJmYWxzZVwiLCByZW1vdmUgaXQgZnJvbSB0aGUgdGFnRGF0YSBzbyBpdCB3b24ndCBiZSBhZGRlZCBhcyBhbiBhdHRyaWJ1dGUgaW4gdGhlIHRlbXBsYXRlXG4gICAgICAgIGVsc2UgZGVsZXRlIHRhZ0RhdGEucmVhZG9ubHk7XG4gICAgICB9XG5cbiAgICAgIC8vIENyZWF0ZSB0YWcgSFRNTCBlbGVtZW50XG4gICAgICB0YWdFbG0gPSB0aGlzLmNyZWF0ZVRhZ0VsZW0odGFnRGF0YSwgdGFnRWxtUGFyYW1zKTtcbiAgICAgIHRhZ0VsZW1zLnB1c2godGFnRWxtKTtcblxuICAgICAgLy8gbW9kZS1zZWxlY3Qgb3ZlcnJpZGVzXG4gICAgICBpZiAoX3MubW9kZSA9PSAnc2VsZWN0Jykge1xuICAgICAgICByZXR1cm4gdGhpcy5zZWxlY3RUYWcodGFnRWxtLCB0YWdEYXRhKTtcbiAgICAgIH1cblxuICAgICAgLy8gYWRkIHRoZSB0YWcgdG8gdGhlIGNvbXBvbmVudCdzIERPTVxuICAgICAgLy8gdGhpcy5hcHBlbmRUYWcodGFnRWxtKVxuICAgICAgZnJhZy5hcHBlbmRDaGlsZCh0YWdFbG0pO1xuICAgICAgaWYgKHRhZ0RhdGEuX19pc1ZhbGlkICYmIHRhZ0RhdGEuX19pc1ZhbGlkID09PSB0cnVlKSB7XG4gICAgICAgIC8vIHVwZGF0ZSBzdGF0ZVxuICAgICAgICB0aGlzLnZhbHVlLnB1c2godGFnRGF0YSk7XG4gICAgICAgIHRoaXMudHJpZ2dlcignYWRkJywge1xuICAgICAgICAgIHRhZzogdGFnRWxtLFxuICAgICAgICAgIGluZGV4OiB0aGlzLnZhbHVlLmxlbmd0aCAtIDEsXG4gICAgICAgICAgZGF0YTogdGFnRGF0YVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMudHJpZ2dlcihcImludmFsaWRcIiwge1xuICAgICAgICAgIGRhdGE6IHRhZ0RhdGEsXG4gICAgICAgICAgaW5kZXg6IHRoaXMudmFsdWUubGVuZ3RoLFxuICAgICAgICAgIHRhZzogdGFnRWxtLFxuICAgICAgICAgIG1lc3NhZ2U6IHRhZ0RhdGEuX19pc1ZhbGlkXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoIV9zLmtlZXBJbnZhbGlkVGFncylcbiAgICAgICAgICAvLyByZW1vdmUgaW52YWxpZCB0YWdzIChpZiBcImtlZXBJbnZhbGlkVGFnc1wiIGlzIHNldCB0byBcImZhbHNlXCIpXG4gICAgICAgICAgc2V0VGltZW91dCgoKSA9PiB0aGlzLnJlbW92ZVRhZ3ModGFnRWxtLCB0cnVlKSwgMTAwMCk7XG4gICAgICB9XG4gICAgICB0aGlzLmRyb3Bkb3duLnBvc2l0aW9uKCk7IC8vIHJlcG9zaXRpb24gdGhlIGRyb3Bkb3duIGJlY2F1c2UgdGhlIGp1c3QtYWRkZWQgdGFnIG1pZ2h0IGNhdXNlIGEgbmV3LWxpbmVcbiAgICB9KTtcblxuICAgIHRoaXMuYXBwZW5kVGFnKGZyYWcpO1xuICAgIHRoaXMudXBkYXRlKCk7XG4gICAgaWYgKHRhZ3NJdGVtcy5sZW5ndGggJiYgY2xlYXJJbnB1dCkge1xuICAgICAgdGhpcy5pbnB1dC5zZXQuY2FsbCh0aGlzLCBfcy5jcmVhdGVJbnZhbGlkVGFncyA/ICcnIDogYWdncmVnYXRlZGludmFsaWRJbnB1dC5qb2luKF9zLl9kZWxpbWl0ZXJzKSk7XG4gICAgICB0aGlzLnNldFJhbmdlQXRTdGFydEVuZChmYWxzZSwgdGhpcy5ET00uaW5wdXQpO1xuICAgIH1cbiAgICBfcy5kcm9wZG93bi5lbmFibGVkICYmIHRoaXMuZHJvcGRvd24ucmVmaWx0ZXIoKTtcbiAgICByZXR1cm4gdGFnRWxlbXM7XG4gIH0sXG4gIC8qKlxyXG4gICAqIEFkZHMgYSBtaXgtY29udGVudCB0YWdcclxuICAgKiBAcGFyYW0ge1N0cmluZy9BcnJheX0gdGFnRGF0YSAgICBBIHN0cmluZyAoc2luZ2xlIG9yIG11bHRpcGxlIHZhbHVlcyB3aXRoIGEgZGVsaW1pdGVyKSwgb3IgYW4gQXJyYXkgb2YgT2JqZWN0cyBvciBqdXN0IEFycmF5IG9mIFN0cmluZ3NcclxuICAgKi9cbiAgYWRkTWl4VGFncyh0YWdzRGF0YSkge1xuICAgIHRhZ3NEYXRhID0gdGhpcy5ub3JtYWxpemVUYWdzKHRhZ3NEYXRhKTtcbiAgICBpZiAodGFnc0RhdGFbMF0ucHJlZml4IHx8IHRoaXMuc3RhdGUudGFnKSB7XG4gICAgICByZXR1cm4gdGhpcy5wcmVmaXhlZFRleHRUb1RhZyh0YWdzRGF0YVswXSk7XG4gICAgfVxuICAgIHZhciBmcmFnID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuICAgIHRhZ3NEYXRhLmZvckVhY2godGFnRGF0YSA9PiB7XG4gICAgICB2YXIgdGFnRWxtID0gdGhpcy5jcmVhdGVUYWdFbGVtKHRhZ0RhdGEpO1xuICAgICAgZnJhZy5hcHBlbmRDaGlsZCh0YWdFbG0pO1xuICAgIH0pO1xuICAgIHRoaXMuYXBwZW5kTWl4VGFncyhmcmFnKTtcbiAgICByZXR1cm4gZnJhZztcbiAgfSxcbiAgYXBwZW5kTWl4VGFncyhub2RlKSB7XG4gICAgdmFyIHNlbGVjdGlvbiA9ICEhdGhpcy5zdGF0ZS5zZWxlY3Rpb247XG5cbiAgICAvLyBpZiBcInNlbGVjdGlvblwiIGV4aXN0cywgYXNzdW1lcyBpbnRlbnRpb24gb2YgaW5lY3RpbmcgdGhlIG5ldyB0YWcgYXQgdGhlIGxhc3RcbiAgICAvLyBzYXZlZCBsb2NhdGlvbiBvZiB0aGUgY2FyZXQgaW5zaWRlIFwidGhpcy5ET00uaW5wdXRcIlxuICAgIGlmIChzZWxlY3Rpb24pIHtcbiAgICAgIHRoaXMuaW5qZWN0QXRDYXJldChub2RlKTtcbiAgICB9XG4gICAgLy8gZWxzZSwgY3JlYXRlIGEgcmFuZ2UgYW5kIGluamVjdCB0aGUgbmV3IHRhZyBhcyB0aGUgbGFzdCBjaGlsZCBvZiBcInRoaXMuRE9NLmlucHV0XCJcbiAgICBlbHNlIHtcbiAgICAgIHRoaXMuRE9NLmlucHV0LmZvY3VzKCk7XG4gICAgICBzZWxlY3Rpb24gPSB0aGlzLnNldFN0YXRlU2VsZWN0aW9uKCk7XG4gICAgICBzZWxlY3Rpb24ucmFuZ2Uuc2V0U3RhcnQodGhpcy5ET00uaW5wdXQsIHNlbGVjdGlvbi5yYW5nZS5lbmRPZmZzZXQpO1xuICAgICAgc2VsZWN0aW9uLnJhbmdlLnNldEVuZCh0aGlzLkRPTS5pbnB1dCwgc2VsZWN0aW9uLnJhbmdlLmVuZE9mZnNldCk7XG4gICAgICB0aGlzLkRPTS5pbnB1dC5hcHBlbmRDaGlsZChub2RlKTtcbiAgICAgIHRoaXMudXBkYXRlVmFsdWVCeURPTVRhZ3MoKTsgLy8gdXBkYXRlcyBpbnRlcm5hbCBcInRoaXMudmFsdWVcIlxuICAgICAgdGhpcy51cGRhdGUoKTsgLy8gdXBkYXRlcyBvcmlnaW5hbCBpbnB1dC90ZXh0YXJlYVxuICAgIH1cbiAgfSxcblxuICAvKipcclxuICAgKiBBZGRzIGEgdGFnIHdoaWNoIHdhcyBhY3Rpdmx5IHR5cGVkIGJ5IHRoZSB1c2VyXHJcbiAgICogQHBhcmFtIHtTdHJpbmcvQXJyYXl9IHRhZ0l0ZW0gICBbQSBzdHJpbmcgKHNpbmdsZSBvciBtdWx0aXBsZSB2YWx1ZXMgd2l0aCBhIGRlbGltaXRlciksIG9yIGFuIEFycmF5IG9mIE9iamVjdHMgb3IganVzdCBBcnJheSBvZiBTdHJpbmdzXVxyXG4gICAqL1xuICBwcmVmaXhlZFRleHRUb1RhZyh0YWdJdGVtKSB7XG4gICAgdmFyIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgIHRhZ0VsbSxcbiAgICAgIGNyZWF0ZWRGcm9tRGVsaW1pdGVycyA9IHRoaXMuc3RhdGUudGFnLmRlbGltaXRlcnM7XG4gICAgX3MudHJhbnNmb3JtVGFnLmNhbGwodGhpcywgdGFnSXRlbSk7XG4gICAgdGFnSXRlbS5wcmVmaXggPSB0YWdJdGVtLnByZWZpeCB8fCB0aGlzLnN0YXRlLnRhZyA/IHRoaXMuc3RhdGUudGFnLnByZWZpeCA6IChfcy5wYXR0ZXJuLnNvdXJjZSB8fCBfcy5wYXR0ZXJuKVswXTtcblxuICAgIC8vIFRPRE86IHNob3VsZCBjaGVjayBpZiB0aGUgdGFnIGlzIHZhbGlkXG4gICAgdGFnRWxtID0gdGhpcy5jcmVhdGVUYWdFbGVtKHRhZ0l0ZW0pO1xuXG4gICAgLy8gdHJpZXMgdG8gcmVwbGFjZSBhIHRhZ2VkIHRleHROb2RlIHdpdGggYSB0YWdFbG0sIGFuZCBpZiBub3QgYWJsZSxcbiAgICAvLyBpbnNlcnQgdGhlIG5ldyB0YWcgdG8gdGhlIEVORCBpZiBcImFkZFRhZ3NcIiB3YXMgY2FsbGVkIGZyb20gb3V0c2lkZVxuICAgIGlmICghdGhpcy5yZXBsYWNlVGV4dFdpdGhOb2RlKHRhZ0VsbSkpIHtcbiAgICAgIHRoaXMuRE9NLmlucHV0LmFwcGVuZENoaWxkKHRhZ0VsbSk7XG4gICAgfVxuICAgIHNldFRpbWVvdXQoKCkgPT4gdGFnRWxtLmNsYXNzTGlzdC5hZGQodGhpcy5zZXR0aW5ncy5jbGFzc05hbWVzLnRhZ05vQW5pbWF0aW9uKSwgMzAwKTtcbiAgICB0aGlzLnZhbHVlLnB1c2godGFnSXRlbSk7XG4gICAgdGhpcy51cGRhdGUoKTtcbiAgICBpZiAoIWNyZWF0ZWRGcm9tRGVsaW1pdGVycykge1xuICAgICAgdmFyIGVsbSA9IHRoaXMuaW5zZXJ0QWZ0ZXJUYWcodGFnRWxtKSB8fCB0YWdFbG07XG4gICAgICAvLyBhIHRpbWVvdXQgaXMgbmVlZGVkIHdoZW4gc2VsZWN0aW5nIGEgdGFnIGZyb20gdGhlIHN1Z2dlc3Rpb25zIHZpYSBtb3VzZS5cbiAgICAgIC8vIFdpdGhvdXQgaXQsIGl0IHNlZW1zIHRoZSBjYXJldCBpcyBwbGFjZWQgcmlnaHQgYWZ0ZXIgdGhlIHRhZyBhbmQgbm90IGFmdGVyIHRoZVxuICAgICAgLy8gbm9kZSB3aGljaCB3YXMgaW5zZXJ0ZWQgYWZ0ZXIgdGhlIHRhZyAod2hpdGVzcGFjZSBieSBkZWZhdWx0KVxuICAgICAgc2V0VGltZW91dCh0aGlzLnBsYWNlQ2FyZXRBZnRlck5vZGUsIDAsIGVsbSk7XG4gICAgfVxuICAgIHRoaXMuc3RhdGUudGFnID0gbnVsbDtcbiAgICB0aGlzLnRyaWdnZXIoJ2FkZCcsIGV4dGVuZCh7fSwge1xuICAgICAgdGFnOiB0YWdFbG1cbiAgICB9LCB7XG4gICAgICBkYXRhOiB0YWdJdGVtXG4gICAgfSkpO1xuICAgIHJldHVybiB0YWdFbG07XG4gIH0sXG4gIC8qKlxyXG4gICAqIGFwcGVuZWQgKHZhbGlkYXRlZCkgdGFnIHRvIHRoZSBjb21wb25lbnQncyBET00gc2NvcGVcclxuICAgKi9cbiAgYXBwZW5kVGFnKHRhZ0VsbSkge1xuICAgIHZhciBET00gPSB0aGlzLkRPTSxcbiAgICAgIGluc2VydEJlZm9yZU5vZGUgPSBET00uaW5wdXQ7XG5cbiAgICAvL2lmKCBpbnNlcnRCZWZvcmVOb2RlID09PSBET00uaW5wdXQgKVxuICAgIERPTS5zY29wZS5pbnNlcnRCZWZvcmUodGFnRWxtLCBpbnNlcnRCZWZvcmVOb2RlKTtcbiAgICAvL2Vsc2VcbiAgICAvLyAgICBET00uc2NvcGUuYXBwZW5kQ2hpbGQodGFnRWxtKVxuICB9LFxuXG4gIC8qKlxyXG4gICAqIGNyZWF0ZXMgYSBET00gdGFnIGVsZW1lbnQgYW5kIGluamVjdHMgaXQgaW50byB0aGUgY29tcG9uZW50ICh0aGlzLkRPTS5zY29wZSlcclxuICAgKiBAcGFyYW0gIHtPYmplY3R9ICB0YWdEYXRhIFt0ZXh0IHZhbHVlICYgcHJvcGVydGllcyBmb3IgdGhlIGNyZWF0ZWQgdGFnXVxyXG4gICAqIEBwYXJhbSAge09iamVjdH0gIGV4dHJhRGF0YSBbcHJvcGVydGllcyB3aGljaCBhcmUgZm9yIHRoZSBIVE1MIHRlbXBsYXRlIG9ubHldXHJcbiAgICogQHJldHVybiB7T2JqZWN0fSBbRE9NIGVsZW1lbnRdXHJcbiAgICovXG4gIGNyZWF0ZVRhZ0VsZW0odGFnRGF0YSwgZXh0cmFEYXRhKSB7XG4gICAgdGFnRGF0YS5fX3RhZ0lkID0gZ2V0VUlEKCk7XG4gICAgdmFyIHRhZ0VsbSxcbiAgICAgIHRlbXBsYXRlRGF0YSA9IGV4dGVuZCh7fSwgdGFnRGF0YSwgX29iamVjdFNwcmVhZDIoe1xuICAgICAgICB2YWx1ZTogZXNjYXBlSFRNTCh0YWdEYXRhLnZhbHVlICsgXCJcIilcbiAgICAgIH0sIGV4dHJhRGF0YSkpO1xuXG4gICAgLy8gaWYoIHRoaXMuc2V0dGluZ3MucmVhZG9ubHkgKVxuICAgIC8vICAgICB0YWdEYXRhLnJlYWRvbmx5ID0gdHJ1ZVxuXG4gICAgdGFnRWxtID0gdGhpcy5wYXJzZVRlbXBsYXRlKCd0YWcnLCBbdGVtcGxhdGVEYXRhLCB0aGlzXSk7XG5cbiAgICAvLyBjcnVjaWFsIGZvciBwcm9wZXIgY2FyZXQgcGxhY2VtZW50IHdoZW4gZGVsZXRpbmcgY29udGVudC4gaWYgdGV4dE5vZGVzIGFyZSBhbGxvd2VkIGFzIGNoaWxkcmVuIG9mIGEgdGFnIGVsZW1lbnQsXG4gICAgLy8gYSBicm93c2VyIGJ1ZyBjYXN1ZXMgdGhlIGNhcmV0IHRvIGJlIG1pc3BsYWNlZCBpbnNpZGUgdGhlIHRhZyBlbGVtZW50IChlc3BlY2lhbGx5IGFmZmVjdHMgXCJyZWFkb25seVwiIHRhZ3MpXG4gICAgcmVtb3ZlVGV4dENoaWxkTm9kZXModGFnRWxtKTtcbiAgICAvLyB3aGlsZSggdGFnRWxtLmxhc3RDaGlsZC5ub2RlVHlwZSA9PSAzIClcbiAgICAvLyAgICAgdGFnRWxtLmxhc3RDaGlsZC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKHRhZ0VsbS5sYXN0Q2hpbGQpXG5cbiAgICBnZXRTZXRUYWdEYXRhKHRhZ0VsbSwgdGFnRGF0YSk7XG4gICAgcmV0dXJuIHRhZ0VsbTtcbiAgfSxcbiAgLyoqXHJcbiAgICogcmUtY2hlY2sgYWxsIGludmFsaWQgdGFncy5cclxuICAgKiBjYWxsZWQgYWZ0ZXIgYSB0YWcgd2FzIGVkaXRlZCBvciByZW1vdmVkXHJcbiAgICovXG4gIHJlQ2hlY2tJbnZhbGlkVGFncygpIHtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzO1xuICAgIHRoaXMuZ2V0VGFnRWxtcyhfcy5jbGFzc05hbWVzLnRhZ05vdEFsbG93ZWQpLmZvckVhY2goKHRhZ0VsbSwgaSkgPT4ge1xuICAgICAgdmFyIHRhZ0RhdGEgPSBnZXRTZXRUYWdEYXRhKHRhZ0VsbSksXG4gICAgICAgIGhhc01heFRhZ3MgPSB0aGlzLmhhc01heFRhZ3MoKSxcbiAgICAgICAgdGFnVmFsaWRhdGlvbiA9IHRoaXMudmFsaWRhdGVUYWcodGFnRGF0YSksXG4gICAgICAgIGlzVmFsaWQgPSB0YWdWYWxpZGF0aW9uID09PSB0cnVlICYmICFoYXNNYXhUYWdzO1xuICAgICAgaWYgKF9zLm1vZGUgPT0gJ3NlbGVjdCcpIHRoaXMudG9nZ2xlU2NvcGVWYWxpZGF0aW9uKHRhZ1ZhbGlkYXRpb24pO1xuXG4gICAgICAvLyBpZiB0aGUgdGFnIGhhcyBiZWNvbWUgdmFsaWRcbiAgICAgIGlmIChpc1ZhbGlkKSB7XG4gICAgICAgIHRhZ0RhdGEgPSB0YWdEYXRhLl9fcHJlSW52YWxpZERhdGEgPyB0YWdEYXRhLl9fcHJlSW52YWxpZERhdGEgOiB7XG4gICAgICAgICAgdmFsdWU6IHRhZ0RhdGEudmFsdWVcbiAgICAgICAgfTtcbiAgICAgICAgcmV0dXJuIHRoaXMucmVwbGFjZVRhZyh0YWdFbG0sIHRhZ0RhdGEpO1xuICAgICAgfVxuXG4gICAgICAvLyBpZiB0aGUgdGFnIGlzIHN0aWxsIGludmFpbGQsIHNldCBpdHMgdGl0bGUgYXMgc3VjaCAocmVzb24gb2YgaW52YWxpZCBtaWdodCBoYXZlIGNoYW5nZWQpXG4gICAgICB0YWdFbG0udGl0bGUgPSBoYXNNYXhUYWdzIHx8IHRhZ1ZhbGlkYXRpb247XG4gICAgfSk7XG4gIH0sXG4gIC8qKlxyXG4gICAqIFJlbW92ZXMgYSB0YWdcclxuICAgKiBAcGFyYW0gIHtBcnJheXxOb2RlfFN0cmluZ30gIHRhZ0VsbXMgICAgICAgICBbRE9NIGVsZW1lbnQocykgb3IgYSBTdHJpbmcgdmFsdWUuIGlmIHVuZGVmaW5lZCBvciBudWxsLCByZW1vdmUgbGFzdCBhZGRlZCB0YWddXHJcbiAgICogQHBhcmFtICB7Qm9vbGVhbn0gICAgICAgICAgICBzaWxlbnQgICAgICAgICAgW0EgZmxhZywgd2hpY2ggd2hlbiB0dXJuZWQgb24sIGRvZXMgbm90IHJlbW92ZSBhbnkgdmFsdWUgYW5kIGRvZXMgbm90IHVwZGF0ZSB0aGUgb3JpZ2luYWwgaW5wdXQgdmFsdWUgYnV0IHNpbXBseSByZW1vdmVzIHRoZSB0YWcgZnJvbSB0YWdpZnldXHJcbiAgICogQHBhcmFtICB7TnVtYmVyfSAgICAgICAgICAgICB0cmFuRHVyYXRpb24gICAgW1RyYW5zaXRpb24gZHVyYXRpb24gaW4gTVNdXHJcbiAgICogVE9ETzogQWxsb3cgbXVsdGlwbGUgdGFncyB0byBiZSByZW1vdmVkIGF0LW9uY2VcclxuICAgKi9cbiAgcmVtb3ZlVGFncyh0YWdFbG1zLCBzaWxlbnQsIHRyYW5EdXJhdGlvbikge1xuICAgIHZhciB0YWdzVG9SZW1vdmUsXG4gICAgICBfcyA9IHRoaXMuc2V0dGluZ3M7XG4gICAgdGFnRWxtcyA9IHRhZ0VsbXMgJiYgdGFnRWxtcyBpbnN0YW5jZW9mIEhUTUxFbGVtZW50ID8gW3RhZ0VsbXNdIDogdGFnRWxtcyBpbnN0YW5jZW9mIEFycmF5ID8gdGFnRWxtcyA6IHRhZ0VsbXMgPyBbdGFnRWxtc10gOiBbdGhpcy5nZXRMYXN0VGFnKCldO1xuXG4gICAgLy8gbm9ybWFsaXplIHRhZ0VsbXMgYXJyYXkgdmFsdWVzOlxuICAgIC8vIDEuIHJlbW92aW5nIGludmFsaWQgaXRlbXNcbiAgICAvLyAyLCBpZiBhbiBpdGVtIGlzIFN0cmluZyB0cnkgdG8gZ2V0IHRoZSBtYXRjaGluZyBUYWcgSFRNTCBub2RlXG4gICAgLy8gMy4gZ2V0IHRoZSB0YWcgZGF0YVxuICAgIC8vIDQuIHJldHVybiBhIGNvbGxlY3Rpb24gb2YgT2JqZWN0c1xuICAgIHRhZ3NUb1JlbW92ZSA9IHRhZ0VsbXMucmVkdWNlKChlbG1zLCB0YWdFbG0pID0+IHtcbiAgICAgIGlmICh0YWdFbG0gJiYgdHlwZW9mIHRhZ0VsbSA9PSAnc3RyaW5nJykgdGFnRWxtID0gdGhpcy5nZXRUYWdFbG1CeVZhbHVlKHRhZ0VsbSk7XG4gICAgICB2YXIgdGFnRGF0YSA9IGdldFNldFRhZ0RhdGEodGFnRWxtKTtcbiAgICAgIGlmICh0YWdFbG0gJiYgdGFnRGF0YSAmJiAhdGFnRGF0YS5yZWFkb25seSlcbiAgICAgICAgLy8gbWFrZSBzdXJlIGl0J3MgYSB0YWcgYW5kIG5vdCBzb21lIG90aGVyIG5vZGVcbiAgICAgICAgLy8gYmVjYXVzZSB0aGUgRE9NIG5vZGUgbWlnaHQgYmUgcmVtb3ZlZCBieSBhc3luYyBhbmltYXRpb24sIHRoZSBzdGF0ZSB3aWxsIGJlIHVwZGF0ZWQgd2hpbGVcbiAgICAgICAgLy8gdGhlIG5vZGUgbWlnaHQgc3RpbGwgYmUgaW4gdGhlIERPTSwgc28gdGhlIFwidXBkYXRlXCIgbWV0aG9kIHNob3VsZCBrbm93IHdoaWNoIG5vZGVzIHRvIGlnbm9yZVxuICAgICAgICBlbG1zLnB1c2goe1xuICAgICAgICAgIG5vZGU6IHRhZ0VsbSxcbiAgICAgICAgICBpZHg6IHRoaXMuZ2V0VGFnSWR4KHRhZ0RhdGEpLFxuICAgICAgICAgIC8vIHRoaXMuZ2V0Tm9kZUluZGV4KHRhZ0VsbSk7IC8vIHRoaXMuZ2V0VGFnSW5kZXhCeVZhbHVlKHRhZ0VsbS50ZXh0Q29udGVudClcbiAgICAgICAgICBkYXRhOiBnZXRTZXRUYWdEYXRhKHRhZ0VsbSwge1xuICAgICAgICAgICAgJ19fcmVtb3ZlZCc6IHRydWVcbiAgICAgICAgICB9KVxuICAgICAgICB9KTtcbiAgICAgIHJldHVybiBlbG1zO1xuICAgIH0sIFtdKTtcbiAgICB0cmFuRHVyYXRpb24gPSB0eXBlb2YgdHJhbkR1cmF0aW9uID09IFwibnVtYmVyXCIgPyB0cmFuRHVyYXRpb24gOiB0aGlzLkNTU1ZhcnMudGFnSGlkZVRyYW5zaXRpb247XG4gICAgaWYgKF9zLm1vZGUgPT0gJ3NlbGVjdCcpIHtcbiAgICAgIHRyYW5EdXJhdGlvbiA9IDA7XG4gICAgICB0aGlzLmlucHV0LnNldC5jYWxsKHRoaXMpO1xuICAgIH1cblxuICAgIC8vIGlmIG9ubHkgYSBzaW5nbGUgdGFnIGlzIHRvIGJlIHJlbW92ZWQuXG4gICAgLy8gc2tpcCBcInNlbGVjdFwiIG1vZGUgYmVjYXVzZSBpbnZhbGlkIHRhZ3MgYXJlIGFjdHVhbGx5IHNldCB0byBgdGhpcy52YWx1ZWBcbiAgICBpZiAodGFnc1RvUmVtb3ZlLmxlbmd0aCA9PSAxICYmIF9zLm1vZGUgIT0gJ3NlbGVjdCcpIHtcbiAgICAgIGlmICh0YWdzVG9SZW1vdmVbMF0ubm9kZS5jbGFzc0xpc3QuY29udGFpbnMoX3MuY2xhc3NOYW1lcy50YWdOb3RBbGxvd2VkKSkgc2lsZW50ID0gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKCF0YWdzVG9SZW1vdmUubGVuZ3RoKSByZXR1cm47XG4gICAgcmV0dXJuIF9zLmhvb2tzLmJlZm9yZVJlbW92ZVRhZyh0YWdzVG9SZW1vdmUsIHtcbiAgICAgIHRhZ2lmeTogdGhpc1xuICAgIH0pLnRoZW4oKCkgPT4ge1xuICAgICAgZnVuY3Rpb24gcmVtb3ZlTm9kZSh0YWcpIHtcbiAgICAgICAgaWYgKCF0YWcubm9kZS5wYXJlbnROb2RlKSByZXR1cm47XG4gICAgICAgIHRhZy5ub2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodGFnLm5vZGUpO1xuICAgICAgICBpZiAoIXNpbGVudCkge1xuICAgICAgICAgIC8vIHRoaXMucmVtb3ZlVmFsdWVCeUlkKHRhZ0RhdGEuX191aWQpXG4gICAgICAgICAgdGhpcy50cmlnZ2VyKCdyZW1vdmUnLCB7XG4gICAgICAgICAgICB0YWc6IHRhZy5ub2RlLFxuICAgICAgICAgICAgaW5kZXg6IHRhZy5pZHgsXG4gICAgICAgICAgICBkYXRhOiB0YWcuZGF0YVxuICAgICAgICAgIH0pO1xuICAgICAgICAgIHRoaXMuZHJvcGRvd24ucmVmaWx0ZXIoKTtcbiAgICAgICAgICB0aGlzLmRyb3Bkb3duLnBvc2l0aW9uKCk7XG4gICAgICAgICAgdGhpcy5ET00uaW5wdXQubm9ybWFsaXplKCk7IC8vIGJlc3QtcHJhY3RpY2Ugd2hlbiBpbiBtaXgtbW9kZSAoc2FmZSB0byBkbyBhbHdheXMgYW55d2F5cylcblxuICAgICAgICAgIC8vIGNoZWNrIGlmIGFueSBvZiB0aGUgY3VycmVudCB0YWdzIHdoaWNoIG1pZ2h0IGhhdmUgYmVlbiBtYXJrZWQgYXMgXCJkdXBsaWNhdGVcIiBzaG91bGQgYmUgdW4tbWFya2VkXG4gICAgICAgICAgaWYgKF9zLmtlZXBJbnZhbGlkVGFncykgdGhpcy5yZUNoZWNrSW52YWxpZFRhZ3MoKTtcblxuICAgICAgICAgIC8vIGJlbG93IGNvZGUgaXMgdW5maW5pc2hlZC4gaXQgc2hvdWxkIGl0ZXJhdGUgYWxsIGN1cnJlbnRseSBpbnZhbGlkIGVkaXRlZCB0YWdzLCB3aGljaCB0aGVpciBlZGl0cyBoYXZlIG5vdFxuICAgICAgICAgIC8vIGNoYW5nZWQgdGhlIHZhbHVlIHlldCwgYW5kIHNob3VsZCByZS10cmlnZ2VyIHRoZSBjaGVjaywgYnV0IHNpbmNlIG5vdGhpbmcgaGFzIGNoYW5nZWQsIGl0IGRvZXMgbm90IHdvcmsuLi5cbiAgICAgICAgICAvLyB0aGlzLmdldFRhZ0VsbXMoX3MuY2xhc3NOYW1lcy50YWdFZGl0aW5nKS5mb3JFYWNoKCB0aGlzLmV2ZW50cy5jYWxsYmFja3Mub25FZGl0VGFnQmx1ci5iaW5kIClcbiAgICAgICAgfSBlbHNlIGlmIChfcy5rZWVwSW52YWxpZFRhZ3MpIHRoaXMudHJpZ2dlcigncmVtb3ZlJywge1xuICAgICAgICAgIHRhZzogdGFnLm5vZGUsXG4gICAgICAgICAgaW5kZXg6IHRhZy5pZHhcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICBmdW5jdGlvbiBhbmltYXRpb24odGFnKSB7XG4gICAgICAgIHRhZy5ub2RlLnN0eWxlLndpZHRoID0gcGFyc2VGbG9hdCh3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSh0YWcubm9kZSkud2lkdGgpICsgJ3B4JztcbiAgICAgICAgZG9jdW1lbnQuYm9keS5jbGllbnRUb3A7IC8vIGZvcmNlIHJlcGFpbnQgZm9yIHRoZSB3aWR0aCB0byB0YWtlIGFmZmVjdCBiZWZvcmUgdGhlIFwiaGlkZVwiIGNsYXNzIGJlbG93XG4gICAgICAgIHRhZy5ub2RlLmNsYXNzTGlzdC5hZGQoX3MuY2xhc3NOYW1lcy50YWdIaWRlKTtcblxuICAgICAgICAvLyBtYW51YWwgdGltZW91dCAoaGFjaywgc2luY2UgdHJhbnNpdGlvbmVuZCBjYW5ub3QgYmUgdXNlZCBiZWNhdXNlIG9mIGhvdmVyKVxuICAgICAgICBzZXRUaW1lb3V0KHJlbW92ZU5vZGUuYmluZCh0aGlzKSwgdHJhbkR1cmF0aW9uLCB0YWcpO1xuICAgICAgfVxuICAgICAgaWYgKHRyYW5EdXJhdGlvbiAmJiB0cmFuRHVyYXRpb24gPiAxMCAmJiB0YWdzVG9SZW1vdmUubGVuZ3RoID09IDEpIGFuaW1hdGlvbi5jYWxsKHRoaXMsIHRhZ3NUb1JlbW92ZVswXSk7ZWxzZSB0YWdzVG9SZW1vdmUuZm9yRWFjaChyZW1vdmVOb2RlLmJpbmQodGhpcykpO1xuXG4gICAgICAvLyB1cGRhdGUgc3RhdGUgcmVnYXJkbGVzcyBvZiBhbmltYXRpb25cbiAgICAgIGlmICghc2lsZW50KSB7XG4gICAgICAgIHRoaXMucmVtb3ZlVGFnc0Zyb21WYWx1ZSh0YWdzVG9SZW1vdmUubWFwKHRhZyA9PiB0YWcubm9kZSkpO1xuICAgICAgICB0aGlzLnVwZGF0ZSgpOyAvLyB1cGRhdGUgdGhlIG9yaWdpbmFsIGlucHV0IHdpdGggdGhlIGN1cnJlbnQgdmFsdWVcblxuICAgICAgICBpZiAoX3MubW9kZSA9PSAnc2VsZWN0JykgdGhpcy5zZXRDb250ZW50RWRpdGFibGUodHJ1ZSk7XG4gICAgICB9XG4gICAgfSkuY2F0Y2gocmVhc29uID0+IHt9KTtcbiAgfSxcbiAgcmVtb3ZlVGFnc0Zyb21ET00oKSB7XG4gICAgW10uc2xpY2UuY2FsbCh0aGlzLmdldFRhZ0VsbXMoKSkuZm9yRWFjaChlbG0gPT4gZWxtLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZWxtKSk7XG4gIH0sXG4gIC8qKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkvTm9kZX0gdGFncyB0byBiZSByZW1vdmVkIGZyb20gdGhlIHRoaXMudmFsdWUgYXJyYXlcclxuICAgKi9cbiAgcmVtb3ZlVGFnc0Zyb21WYWx1ZSh0YWdzKSB7XG4gICAgdGFncyA9IEFycmF5LmlzQXJyYXkodGFncykgPyB0YWdzIDogW3RhZ3NdO1xuICAgIHRhZ3MuZm9yRWFjaCh0YWcgPT4ge1xuICAgICAgdmFyIHRhZ0RhdGEgPSBnZXRTZXRUYWdEYXRhKHRhZyksXG4gICAgICAgIHRhZ0lkeCA9IHRoaXMuZ2V0VGFnSWR4KHRhZ0RhdGEpO1xuXG4gICAgICAvLyAgZGVsZXRlIHRhZ0RhdGEuX19yZW1vdmVkXG5cbiAgICAgIGlmICh0YWdJZHggPiAtMSkgdGhpcy52YWx1ZS5zcGxpY2UodGFnSWR4LCAxKTtcbiAgICB9KTtcbiAgfSxcbiAgcmVtb3ZlQWxsVGFncyhvcHRzKSB7XG4gICAgb3B0cyA9IG9wdHMgfHwge307XG4gICAgdGhpcy52YWx1ZSA9IFtdO1xuICAgIGlmICh0aGlzLnNldHRpbmdzLm1vZGUgPT0gJ21peCcpIHRoaXMuRE9NLmlucHV0LmlubmVySFRNTCA9ICcnO2Vsc2UgdGhpcy5yZW1vdmVUYWdzRnJvbURPTSgpO1xuICAgIHRoaXMuZHJvcGRvd24ucmVmaWx0ZXIoKTtcbiAgICB0aGlzLmRyb3Bkb3duLnBvc2l0aW9uKCk7XG4gICAgaWYgKHRoaXMuc3RhdGUuZHJvcGRvd24udmlzaWJsZSkgc2V0VGltZW91dCgoKSA9PiB7XG4gICAgICB0aGlzLkRPTS5pbnB1dC5mb2N1cygpO1xuICAgIH0pO1xuICAgIGlmICh0aGlzLnNldHRpbmdzLm1vZGUgPT0gJ3NlbGVjdCcpIHtcbiAgICAgIHRoaXMuaW5wdXQuc2V0LmNhbGwodGhpcyk7XG4gICAgICB0aGlzLnNldENvbnRlbnRFZGl0YWJsZSh0cnVlKTtcbiAgICB9XG5cbiAgICAvLyB0ZWNobmljYWxseSBmb3Igbm93IG9ubHkgXCJ3aXRob3V0Q2hhbmdlRXZlbnRcIiBleGlzdHMgaW4gdGhlIG9wdHMuXG4gICAgLy8gaWYgbW9yZSBwcm9wZXJ0aWVzIHdpbGwgYmUgYWRkZWQgbGF0ZXIsIG9ubHkgcGFzcyB3aGF0J3MgbmVlZGVkIHRvIFwidXBkYXRlXCJcbiAgICB0aGlzLnVwZGF0ZShvcHRzKTtcbiAgfSxcbiAgcG9zdFVwZGF0ZSgpIHtcbiAgICB0aGlzLnN0YXRlLmJsb2NrQ2hhbmdlRXZlbnQgPSBmYWxzZTtcbiAgICB2YXIgX3MgPSB0aGlzLnNldHRpbmdzLFxuICAgICAgY2xhc3NOYW1lcyA9IF9zLmNsYXNzTmFtZXMsXG4gICAgICBoYXNWYWx1ZSA9IF9zLm1vZGUgPT0gJ21peCcgPyBfcy5taXhNb2RlLmludGVncmF0ZWQgPyB0aGlzLkRPTS5pbnB1dC50ZXh0Q29udGVudCA6IHRoaXMuRE9NLm9yaWdpbmFsSW5wdXQudmFsdWUudHJpbSgpIDogdGhpcy52YWx1ZS5sZW5ndGggKyB0aGlzLmlucHV0LnJhdy5jYWxsKHRoaXMpLmxlbmd0aDtcbiAgICB0aGlzLnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuaGFzTWF4VGFncywgdGhpcy52YWx1ZS5sZW5ndGggPj0gX3MubWF4VGFncyk7XG4gICAgdGhpcy50b2dnbGVDbGFzcyhjbGFzc05hbWVzLmhhc05vVGFncywgIXRoaXMudmFsdWUubGVuZ3RoKTtcbiAgICB0aGlzLnRvZ2dsZUNsYXNzKGNsYXNzTmFtZXMuZW1wdHksICFoYXNWYWx1ZSk7XG5cbiAgICAvLyBzcGVjaWZpY2FsbHkgdGhlIFwic2VsZWN0IG1vZGVcIiBtaWdodCBoYXZlIHRoZSBcImludmFsaWRcIiBjbGFzc25hbWUgc2V0IHdoZW4gdGhlIGZpZWxkIGlzIGNoYW5nZWQsIHNvIGl0IG11c3QgYmUgdG9nZ2xlZCBvbiBhZGQvcmVtb3ZlL2VkaXRcbiAgICBpZiAoX3MubW9kZSA9PSAnc2VsZWN0Jykge1xuICAgICAgdGhpcy50b2dnbGVTY29wZVZhbGlkYXRpb24odGhpcy52YWx1ZT8uWzBdPy5fX2lzVmFsaWQpO1xuICAgIH1cbiAgfSxcbiAgc2V0T3JpZ2luYWxJbnB1dFZhbHVlKHYpIHtcbiAgICB2YXIgaW5wdXRFbG0gPSB0aGlzLkRPTS5vcmlnaW5hbElucHV0O1xuICAgIGlmICghdGhpcy5zZXR0aW5ncy5taXhNb2RlLmludGVncmF0ZWQpIHtcbiAgICAgIGlucHV0RWxtLnZhbHVlID0gdjtcbiAgICAgIGlucHV0RWxtLnRhZ2lmeVZhbHVlID0gaW5wdXRFbG0udmFsdWU7IC8vIG11c3Qgc2V0IHRvIFwiaW5wdXRFbG0udmFsdWVcIiBhbmQgbm90IGFnYWluIHRvIFwiaW5wdXRWYWx1ZVwiIGJlY2F1c2UgZm9yIHNvbWUgcmVhc29uIHRoZSBicm93c2VyIGNoYW5nZXMgdGhlIHN0cmluZyBhZnRlcndhcmRzIGEgYml0LlxuICAgICAgdGhpcy5zZXRQZXJzaXN0ZWREYXRhKHYsICd2YWx1ZScpO1xuICAgIH1cbiAgfSxcbiAgLyoqXHJcbiAgICogdXBkYXRlIHRoZSBvcmlnaWFubCAoaGlkZGVuKSBpbnB1dCBmaWVsZCdzIHZhbHVlXHJcbiAgICogc2VlIC0gaHR0cHM6Ly9zdGFja292ZXJmbG93LmNvbS9xLzUwOTU3ODQxLzEwNDM4MFxyXG4gICAqL1xuICB1cGRhdGUoYXJncykge1xuICAgIGNvbnN0IFVQREFURV9ERUxBWSA9IDEwMDtcbiAgICBjbGVhclRpbWVvdXQodGhpcy5kZWJvdW5jZWRVcGRhdGVUaW1lb3V0KTtcbiAgICB0aGlzLmRlYm91bmNlZFVwZGF0ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KHJlYWxseVVwZGF0ZS5iaW5kKHRoaXMpLCBVUERBVEVfREVMQVkpO1xuICAgIGZ1bmN0aW9uIHJlYWxseVVwZGF0ZSgpIHtcbiAgICAgIHZhciBpbnB1dFZhbHVlID0gdGhpcy5nZXRJbnB1dFZhbHVlKCk7XG4gICAgICB0aGlzLnNldE9yaWdpbmFsSW5wdXRWYWx1ZShpbnB1dFZhbHVlKTtcbiAgICAgIGlmICgoIXRoaXMuc2V0dGluZ3Mub25DaGFuZ2VBZnRlckJsdXIgfHwgIShhcmdzIHx8IHt9KS53aXRob3V0Q2hhbmdlRXZlbnQpICYmICF0aGlzLnN0YXRlLmJsb2NrQ2hhbmdlRXZlbnQpIHRoaXMudHJpZ2dlckNoYW5nZUV2ZW50KCk7XG4gICAgICB0aGlzLnBvc3RVcGRhdGUoKTtcbiAgICB9XG4gIH0sXG4gIGdldElucHV0VmFsdWUoKSB7XG4gICAgdmFyIHZhbHVlID0gdGhpcy5nZXRDbGVhblZhbHVlKCk7XG4gICAgcmV0dXJuIHRoaXMuc2V0dGluZ3MubW9kZSA9PSAnbWl4JyA/IHRoaXMuZ2V0TWl4ZWRUYWdzQXNTdHJpbmcodmFsdWUpIDogdmFsdWUubGVuZ3RoID8gdGhpcy5zZXR0aW5ncy5vcmlnaW5hbElucHV0VmFsdWVGb3JtYXQgPyB0aGlzLnNldHRpbmdzLm9yaWdpbmFsSW5wdXRWYWx1ZUZvcm1hdCh2YWx1ZSkgOiBKU09OLnN0cmluZ2lmeSh2YWx1ZSkgOiBcIlwiO1xuICB9LFxuICAvKipcclxuICAgKiByZW1vdmVzIHByb3BlcnRpZXMgZnJvbSBgdGhpcy52YWx1ZWAgd2hpY2ggYXJlIG9ubHkgdXNlZCBpbnRlcm5hbGx5XHJcbiAgICovXG4gIGdldENsZWFuVmFsdWUodikge1xuICAgIHJldHVybiByZW1vdmVDb2xsZWN0aW9uUHJvcCh2IHx8IHRoaXMudmFsdWUsIHRoaXMuZGF0YVByb3BzKTtcbiAgfSxcbiAgZ2V0TWl4ZWRUYWdzQXNTdHJpbmcoKSB7XG4gICAgdmFyIHJlc3VsdCA9IFwiXCIsXG4gICAgICB0aGF0ID0gdGhpcyxcbiAgICAgIF9zID0gdGhpcy5zZXR0aW5ncyxcbiAgICAgIG9yaWdpbmFsSW5wdXRWYWx1ZUZvcm1hdCA9IF9zLm9yaWdpbmFsSW5wdXRWYWx1ZUZvcm1hdCB8fCBKU09OLnN0cmluZ2lmeSxcbiAgICAgIF9pbnRlcnBvbGF0b3IgPSBfcy5taXhUYWdzSW50ZXJwb2xhdG9yO1xuICAgIGZ1bmN0aW9uIGl0ZXJhdGVDaGlsZHJlbihyb290Tm9kZSkge1xuICAgICAgcm9vdE5vZGUuY2hpbGROb2Rlcy5mb3JFYWNoKG5vZGUgPT4ge1xuICAgICAgICBpZiAobm9kZS5ub2RlVHlwZSA9PSAxKSB7XG4gICAgICAgICAgY29uc3QgdGFnRGF0YSA9IGdldFNldFRhZ0RhdGEobm9kZSk7XG4gICAgICAgICAgaWYgKG5vZGUudGFnTmFtZSA9PSAnQlInKSB7XG4gICAgICAgICAgICByZXN1bHQgKz0gXCJcXHJcXG5cIjtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHRhZ0RhdGEgJiYgaXNOb2RlVGFnLmNhbGwodGhhdCwgbm9kZSkpIHtcbiAgICAgICAgICAgIGlmICh0YWdEYXRhLl9fcmVtb3ZlZCkgcmV0dXJuO2Vsc2UgcmVzdWx0ICs9IF9pbnRlcnBvbGF0b3JbMF0gKyBvcmlnaW5hbElucHV0VmFsdWVGb3JtYXQob21pdCh0YWdEYXRhLCB0aGF0LmRhdGFQcm9wcykpICsgX2ludGVycG9sYXRvclsxXTtcbiAgICAgICAgICB9IGVsc2UgaWYgKG5vZGUuZ2V0QXR0cmlidXRlKCdzdHlsZScpIHx8IFsnQicsICdJJywgJ1UnXS5pbmNsdWRlcyhub2RlLnRhZ05hbWUpKSByZXN1bHQgKz0gbm9kZS50ZXh0Q29udGVudDtlbHNlIGlmIChub2RlLnRhZ05hbWUgPT0gJ0RJVicgfHwgbm9kZS50YWdOYW1lID09ICdQJykge1xuICAgICAgICAgICAgcmVzdWx0ICs9IFwiXFxyXFxuXCI7XG4gICAgICAgICAgICAvLyAgaWYoICFub2RlLmNoaWxkcmVuLmxlbmd0aCAmJiBub2RlLnRleHRDb250ZW50IClcbiAgICAgICAgICAgIC8vICByZXN1bHQgKz0gbm9kZS50ZXh0Q29udGVudDtcbiAgICAgICAgICAgIGl0ZXJhdGVDaGlsZHJlbihub2RlKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSByZXN1bHQgKz0gbm9kZS50ZXh0Q29udGVudDtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBpdGVyYXRlQ2hpbGRyZW4odGhpcy5ET00uaW5wdXQpO1xuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cbn07XG5cbi8vIGxlZ2FjeSBzdXBwb3J0IGZvciBjaGFuZ2VkIG1ldGhvZHMgbmFtZXNcblRhZ2lmeS5wcm90b3R5cGUucmVtb3ZlVGFnID0gVGFnaWZ5LnByb3RvdHlwZS5yZW1vdmVUYWdzO1xuXG5leHBvcnQgeyBUYWdpZnkgYXMgZGVmYXVsdCB9O1xuIl0sIm5hbWVzIjpbIm93bktleXMiLCJvYmplY3QiLCJlbnVtZXJhYmxlT25seSIsImtleXMiLCJPYmplY3QiLCJnZXRPd25Qcm9wZXJ0eVN5bWJvbHMiLCJzeW1ib2xzIiwiZmlsdGVyIiwic3ltIiwiZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yIiwiZW51bWVyYWJsZSIsInB1c2giLCJhcHBseSIsIl9vYmplY3RTcHJlYWQyIiwidGFyZ2V0IiwiaSIsImFyZ3VtZW50cyIsImxlbmd0aCIsInNvdXJjZSIsImZvckVhY2giLCJrZXkiLCJfZGVmaW5lUHJvcGVydHkiLCJnZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3JzIiwiZGVmaW5lUHJvcGVydGllcyIsImRlZmluZVByb3BlcnR5Iiwib2JqIiwidmFsdWUiLCJfdG9Qcm9wZXJ0eUtleSIsImNvbmZpZ3VyYWJsZSIsIndyaXRhYmxlIiwiX3RvUHJpbWl0aXZlIiwiaW5wdXQiLCJoaW50IiwiX3R5cGVvZiIsInByaW0iLCJTeW1ib2wiLCJ0b1ByaW1pdGl2ZSIsInVuZGVmaW5lZCIsInJlcyIsImNhbGwiLCJUeXBlRXJyb3IiLCJTdHJpbmciLCJOdW1iZXIiLCJhcmciLCJzYW1lU3RyIiwiczEiLCJzMiIsImNhc2VTZW5zaXRpdmUiLCJ0cmltIiwidG9Mb3dlckNhc2UiLCJyZW1vdmVDb2xsZWN0aW9uUHJvcCIsImNvbGxlY3Rpb24iLCJ1bndhbnRlZFByb3BzIiwiQXJyYXkiLCJpc0FycmF5IiwibWFwIiwidiIsIm9taXQiLCJwcm9wcyIsIm5ld09iaiIsInAiLCJpbmRleE9mIiwiZGVjb2RlIiwicyIsImVsIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwicmVwbGFjZSIsImVuYyIsImlubmVySFRNTCIsImlubmVyVGV4dCIsInBhcnNlSFRNTCIsInBhcnNlciIsIkRPTVBhcnNlciIsIm5vZGUiLCJwYXJzZUZyb21TdHJpbmciLCJib2R5IiwiZmlyc3RFbGVtZW50Q2hpbGQiLCJtaW5pZnkiLCJtIiwiJDEiLCJyZW1vdmVUZXh0Q2hpbGROb2RlcyIsImVsbSIsIml0ZXIiLCJjcmVhdGVOb2RlSXRlcmF0b3IiLCJOb2RlRmlsdGVyIiwiU0hPV19URVhUIiwidGV4dG5vZGUiLCJuZXh0Tm9kZSIsInRleHRDb250ZW50IiwicGFyZW50Tm9kZSIsInJlbW92ZUNoaWxkIiwiZ2V0Zmlyc3RUZXh0Tm9kZSIsImFjdGlvbiIsIm5vZGVUeXBlIiwiZXNjYXBlSFRNTCIsImlzT2JqZWN0IiwidHlwZSIsInByb3RvdHlwZSIsInRvU3RyaW5nIiwic3BsaXQiLCJzbGljZSIsImV4dGVuZCIsIm8iLCJvMSIsIm8yIiwiY29weSIsImEiLCJiIiwiaGFzT3duUHJvcGVydHkiLCJhc3NpZ24iLCJjb25jYXRXaXRob3V0RHVwcyIsIm5ld0FyciIsImV4aXN0aW5nT2JqIiwiX2l0ZXJhdG9yIiwiX2NyZWF0ZUZvck9mSXRlcmF0b3JIZWxwZXIiLCJfc3RlcCIsIm4iLCJkb25lIiwiYXJyIiwiX2l0ZXJhdG9yMiIsIl9zdGVwMiIsIml0ZW0iLCJpbmNsdWRlcyIsImVyciIsImUiLCJmIiwidW5hY2NlbnQiLCJub3JtYWxpemUiLCJnZXROb2RlSGVpZ2h0IiwiaGVpZ2h0IiwiY2xvbmUiLCJjbG9uZU5vZGUiLCJzdHlsZSIsImNzc1RleHQiLCJhcHBlbmRDaGlsZCIsImNsaWVudEhlaWdodCIsImlzQ2hyb21lQW5kcm9pZEJyb3dzZXIiLCJ0ZXN0IiwibmF2aWdhdG9yIiwidXNlckFnZW50IiwiZ2V0VUlEIiwiYyIsImNyeXB0byIsImdldFJhbmRvbVZhbHVlcyIsIlVpbnQ4QXJyYXkiLCJpc05vZGVUYWciLCJjbGFzc0xpc3QiLCJjb250YWlucyIsInNldHRpbmdzIiwiY2xhc3NOYW1lcyIsInRhZyIsImdldENhcmV0R2xvYmFsUG9zaXRpb24iLCJzZWwiLCJnZXRTZWxlY3Rpb24iLCJyYW5nZUNvdW50IiwiciIsImdldFJhbmdlQXQiLCJzdGFydENvbnRhaW5lciIsIm9mZnNldCIsInN0YXJ0T2Zmc2V0IiwicmVjdCIsInIyIiwiY3JlYXRlUmFuZ2UiLCJzZXRTdGFydCIsInNldEVuZCIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsImxlZnQiLCJyaWdodCIsInRvcCIsImJvdHRvbSIsImluamVjdEF0Q2FyZXQiLCJjb250ZW50IiwicmFuZ2UiLCJzZWxlY3Rpb24iLCJ3aW5kb3ciLCJjcmVhdGVUZXh0Tm9kZSIsImRlbGV0ZUNvbnRlbnRzIiwiaW5zZXJ0Tm9kZSIsImdldFNldFRhZ0RhdGEiLCJ0YWdFbG0iLCJkYXRhIiwib3ZlcnJpZGUiLCJjb25zb2xlIiwid2FybiIsIl9fdGFnaWZ5VGFnRGF0YSIsIkRFRkFVTFRTIiwiZGVsaW1pdGVycyIsInBhdHRlcm4iLCJ0YWdUZXh0UHJvcCIsIm1heFRhZ3MiLCJJbmZpbml0eSIsImNhbGxiYWNrcyIsImFkZFRhZ09uQmx1ciIsIm9uQ2hhbmdlQWZ0ZXJCbHVyIiwiZHVwbGljYXRlcyIsIndoaXRlbGlzdCIsImJsYWNrbGlzdCIsImVuZm9yY2VXaGl0ZWxpc3QiLCJ1c2VySW5wdXQiLCJrZWVwSW52YWxpZFRhZ3MiLCJjcmVhdGVJbnZhbGlkVGFncyIsIm1peFRhZ3NBbGxvd2VkQWZ0ZXIiLCJtaXhUYWdzSW50ZXJwb2xhdG9yIiwiYmFja3NwYWNlIiwic2tpcEludmFsaWQiLCJwYXN0ZUFzVGFncyIsImVkaXRUYWdzIiwiY2xpY2tzIiwia2VlcEludmFsaWQiLCJ0cmFuc2Zvcm1UYWciLCJhMTF5IiwiZm9jdXNhYmxlVGFncyIsIm1peE1vZGUiLCJpbnNlcnRBZnRlclRhZyIsImF1dG9Db21wbGV0ZSIsImVuYWJsZWQiLCJyaWdodEtleSIsIm5hbWVzcGFjZSIsInNlbGVjdE1vZGUiLCJmb2N1cyIsInRhZ05vQW5pbWF0aW9uIiwidGFnSW52YWxpZCIsInRhZ05vdEFsbG93ZWQiLCJzY29wZUxvYWRpbmciLCJoYXNNYXhUYWdzIiwiaGFzTm9UYWdzIiwiZW1wdHkiLCJpbnB1dEludmFsaWQiLCJkcm9wZG93biIsImRyb3Bkb3duV3JhcHBlciIsImRyb3Bkb3duSGVhZGVyIiwiZHJvcGRvd25Gb290ZXIiLCJkcm9wZG93bkl0ZW0iLCJkcm9wZG93bkl0ZW1BY3RpdmUiLCJkcm9wZG93bkl0ZW1IaWRkZW4iLCJkcm9wZG93bkluaXRhbCIsInRhZ1RleHQiLCJ0YWdYIiwidGFnTG9hZGluZyIsInRhZ0VkaXRpbmciLCJ0YWdGbGFzaCIsInRhZ0hpZGUiLCJjbGFzc25hbWUiLCJtYXhJdGVtcyIsInNlYXJjaEtleXMiLCJmdXp6eVNlYXJjaCIsImFjY2VudGVkU2VhcmNoIiwiaW5jbHVkZVNlbGVjdGVkVGFncyIsImhpZ2hsaWdodEZpcnN0IiwiY2xvc2VPblNlbGVjdCIsImNsZWFyT25TZWxlY3QiLCJwb3NpdGlvbiIsImFwcGVuZFRhcmdldCIsImhvb2tzIiwiYmVmb3JlUmVtb3ZlVGFnIiwiUHJvbWlzZSIsInJlc29sdmUiLCJiZWZvcmVQYXN0ZSIsInN1Z2dlc3Rpb25DbGljayIsImluaXREcm9wZG93biIsIl9kcm9wZG93biIsImJpbmQiLCJyZWZzIiwiRE9NIiwicGFyc2VUZW1wbGF0ZSIsInF1ZXJ5U2VsZWN0b3IiLCJnZXRIZWFkZXJSZWYiLCJnZXRGb290ZXJSZWYiLCJnZXRBbGxTdWdnZXN0aW9uc1JlZnMiLCJfdG9Db25zdW1hYmxlQXJyYXkiLCJxdWVyeVNlbGVjdG9yQWxsIiwiZHJvcGRvd25JdGVtU2VsZWN0b3IiLCJzaG93IiwiX3RoaXMyIiwiX3MiLCJmaXJzdExpc3RJdGVtIiwiZmlyc3RMaXN0SXRlbVZhbHVlIiwiYWxsb3dOZXdUYWdzIiwibW9kZSIsIm5vV2hpdGVsaXN0Iiwibm9NYXRjaExpc3RJdGVtIiwiaXNNYW51YWwiLCJzdGF0ZSIsImlucHV0VGV4dCIsInRlbXBsYXRlcyIsImRyb3Bkb3duSXRlbU5vTWF0Y2giLCJlbmFibGUiLCJpc0xvYWRpbmciLCJyZWFkb25seSIsImNsZWFyVGltZW91dCIsImRyb3Bkb3duSGlkZV9fYmluZEV2ZW50c1RpbWVvdXQiLCJzdWdnZXN0ZWRMaXN0SXRlbXMiLCJmaWx0ZXJMaXN0SXRlbXMiLCJ0cmlnZ2VyIiwiZWRpdGluZyIsInNjb3BlIiwidW5zaGlmdCIsImF1dG9jb21wbGV0ZSIsInN1Z2dlc3QiLCJoaWRlIiwiZmlsbCIsImhpZ2hsaWdodE9wdGlvbiIsInZpc2libGUiLCJzZXRUaW1lb3V0IiwiZXZlbnRzIiwiYmluZGluZyIsInF1ZXJ5Iiwic2V0U3RhdGVTZWxlY3Rpb24iLCJyZW5kZXIiLCJvdmVycmlkZU1hbnVhbCIsIl90aGlzMyIsIl90aGlzJERPTSIsInJlbW92ZUV2ZW50TGlzdGVuZXIiLCJzZXRBdHRyaWJ1dGUiLCJkZEl0ZW1EYXRhIiwiZGRJdGVtRWxtIiwiZmxhZ2dlZFRhZ3MiLCJiYXNlT2Zmc2V0IiwidG9nZ2xlIiwiX3RoaXM0IiwiZGRIZWlnaHQiLCJhZGQiLCJyZW1vdmUiLCJIVE1MQ29udGVudCIsImNyZWF0ZUxpc3RIVE1MIiwiZHJvcGRvd25Db250ZW50IiwiZmlsbEhlYWRlckZvb3RlciIsInN1Z2dlc3Rpb25zIiwibmV3SGVhZGVyRWxlbSIsIm5ld0Zvb3RlckVsZW0iLCJoZWFkZXJSZWYiLCJmb290ZXJSZWYiLCJyZXBsYWNlQ2hpbGQiLCJyZWZpbHRlciIsIl9zZCIsIndpZHRoIiwicGFyZW50c1Bvc2l0aW9ucyIsImRkRWxtIiwicGxhY2VBYm92ZSIsImlzRGVmYXVsdEFwcGVuZFRhcmdldCIsImFwcGVuZFRhcmdldFNjcm9sbFRvcCIsInBhZ2VZT2Zmc2V0Iiwic2Nyb2xsVG9wIiwicm9vdCIsImZ1bGxzY3JlZW5FbGVtZW50Iiwid2Via2l0RnVsbHNjcmVlbkVsZW1lbnQiLCJkb2N1bWVudEVsZW1lbnQiLCJ2aWV3cG9ydEhlaWdodCIsInZpZXdwb3J0V2lkdGgiLCJNYXRoIiwibWF4IiwiY2xpZW50V2lkdGgiLCJpbm5lcldpZHRoIiwicG9zaXRpb25UbyIsImRkVGFyZ2V0IiwiZ2V0UGFyZW50c1Bvc2l0aW9ucyIsIm9mZnNldExlZnQiLCJvZmZzZXRUb3AiLCJnZXRBY2N1bXVsYXRlZEFuY2VzdG9yc1Njcm9sbFRvcCIsImFjY3VtdWxhdGVkQW5jZXN0b3JzU2Nyb2xsVG9wIiwiZmxvb3IiLCJjZWlsIiwicGFnZVhPZmZzZXQiLCJiaW5kVW5iaW5kIiwiX0NCIiwiX0NCUiIsImxpc3RlbmVycyIsIm9uS2V5RG93biIsIm9uTW91c2VPdmVyIiwib25Nb3VzZUxlYXZlIiwib25DbGljayIsIm9uU2Nyb2xsIiwiX3RoaXM1IiwiaGFzRm9jdXMiLCJjb21wb3NpbmciLCJzZWxlY3RlZEVsbSIsImRyb3Bkb3duSXRlbUFjdGl2ZVNlbGVjdG9yIiwic2VsZWN0ZWRFbG1EYXRhIiwiZ2V0U3VnZ2VzdGlvbkRhdGFCeU5vZGUiLCJwcmV2ZW50RGVmYXVsdCIsImRyb3Bkb3duSXRlbXMiLCJhY3Rpb25VcCIsImdldE5leHRPclByZXZPcHRpb24iLCJtYXRjaGVzIiwiYWN0aW9ucyIsIkFycm93TGVmdCIsImdldE1hcHBlZFZhbHVlIiwic2V0IiwidGFnaWZ5IiwidGFnRGF0YSIsInN1Z2dlc3Rpb25FbG0iLCJ0aGVuIiwic2VsZWN0T3B0aW9uIiwiYWRkVGFncyIsImNhdGNoIiwicmF3IiwiY2hhckNvZGVBdCIsInJlbW92ZVRhZ3MiLCJlZGl0VGFnIiwiZGRJdGVtIiwiY2xvc2VzdCIsIl90aGlzNiIsImJ1dHRvbiIsInBvcyIsInNjcm9sbEhlaWdodCIsInBlcmNlbnRhZ2UiLCJyb3VuZCIsImdldEF0dHJpYnV0ZSIsImZpbmQiLCJzZWxlY3RlZCIsIm5leHQiLCJzZWxlY3RlZElkeCIsImZpbmRJbmRleCIsImFkanVzdFNjcm9sbCIsImNsYXNzTmFtZSIsIml0ZW1EYXRhIiwicmVtb3ZlQXR0cmlidXRlIiwiZXZlbnQiLCJfdGhpczciLCJfdGhpcyRzZXR0aW5ncyRkcm9wZG8iLCJpc05vTWF0Y2giLCJfaXRlbSR2YWx1ZSIsIm9uRWRpdFRhZ0RvbmUiLCJfX2lzVmFsaWQiLCJub3JtYWxpemVUYWdzIiwidG9nZ2xlRm9jdXNDbGFzcyIsImFkZEV2ZW50TGlzdGVuZXIiLCJvbmNlIiwic2VsZWN0QWxsIiwib25seVJlbmRlcmVkIiwidGFnc1RvQWRkIiwib3B0aW9ucyIsIl90aGlzOCIsImxpc3QiLCJleGFjdE1hdGNoZXNMaXN0Iiwic3VnZ2VzdGlvbnNDb3VudCIsIndoaXRlbGlzdEl0ZW0iLCJ2YWx1ZUlzSW5XaGl0ZWxpc3QiLCJzZWFyY2hCeSIsImlzRHVwbGljYXRlIiwibmlkZGxlIiwiaXNUYWdEdXBsaWNhdGUiLCJzdHJpbmdIYXNBbGwiLCJldmVyeSIsInEiLCJfbG9vcCIsInN0YXJ0c1dpdGhNYXRjaCIsImV4YWN0TWF0Y2giLCJpdGVtV2l0aG91dFNlYXJjaEtleXMiLCJzb21lIiwiayIsIl9zZWFyY2hLZXlzIiwiZXhhY3QiLCJyZWR1Y2UiLCJ2YWx1ZXMiLCJzb3J0YnkiLCJjb25jYXQiLCJtYXBWYWx1ZVRvIiwic3VnZWdzdGlvbnNMaXN0IiwiX3RoaXM5Iiwic3VnZ2VzdGlvbiIsImlkeCIsIm1hcHBlZFZhbHVlIiwiam9pbiIsIlZFUlNJT04iLCJTVE9SRV9LRVkiLCJnZXRQZXJzaXN0ZWREYXRhIiwiaWQiLCJjdXN0b21LZXkiLCJwZXJzaXN0ZWREYXRhIiwidmVyc2lvbk1hdGNoIiwibG9jYWxTdG9yYWdlIiwiZ2V0SXRlbSIsIkpTT04iLCJwYXJzZSIsInNldFBlcnNpc3RlZERhdGEiLCJzZXRJdGVtIiwic3RyaW5naWZ5IiwiZGlzcGF0Y2hFdmVudCIsIkV2ZW50IiwiY2xlYXJQZXJzaXN0ZWREYXRhIiwiYmFzZSIsInJlbW92ZUl0ZW0iLCJURVhUUyIsImV4Y2VlZCIsImR1cGxpY2F0ZSIsIm5vdEFsbG93ZWQiLCJ3cmFwcGVyIiwiZGlzYWJsZWQiLCJyZXF1aXJlZCIsInBsYWNlaG9sZGVyIiwiX3JlZiIsInRpdGxlIiwiY2xhc3MiLCJnZXRBdHRyaWJ1dGVzIiwiaGFzTW9yZSIsIkV2ZW50RGlzcGF0Y2hlciIsImluc3RhbmNlIiwiYWRkUmVtb3ZlIiwib3AiLCJjYiIsIm5hbWUiLCJvZmYiLCJvbiIsImV2ZW50TmFtZSIsIm9wdHMiLCJjbG9uZURhdGEiLCJpc0pRdWVyeVBsdWdpbiIsImpRdWVyeSIsIm9yaWdpbmFsSW5wdXQiLCJ0cmlnZ2VySGFuZGxlciIsImV2ZW50RGF0YSIsImNsb25lRXZlbnQiLCJwcm9wIiwiSFRNTEVsZW1lbnQiLCJDdXN0b21FdmVudCIsImRlbGV0ZUJhY2tzcGFjZVRpbWVvdXQiLCJ0cmlnZ2VyQ2hhbmdlRXZlbnQiLCJpbnRlZ3JhdGVkIiwiaW5wdXRFbG0iLCJjaGFuZ2VkIiwibGFzdE9yaWdpbmFsVmFsdWVSZXBvcnRlZCIsImJ1YmJsZXMiLCJzaW11bGF0ZWQiLCJfdmFsdWVUcmFja2VyIiwic2V0VmFsdWUiLCJyYW5kb20iLCJjdXN0b21CaW5kaW5nIiwiX3RoaXMxMCIsImN1c3RvbUV2ZW50c0xpc3QiLCJtYWluRXZlbnRzIiwibWFpbiIsImJpbmRHbG9iYWwiLCJyZW1vdmVBbGxUYWdzIiwib25Gb2N1c0JsdXIiLCJrZXlkb3duIiwib25LZXlkb3duIiwiY2xpY2siLCJvbkNsaWNrU2NvcGUiLCJkYmxjbGljayIsIm9uRG91YmxlQ2xpY2tTY29wZSIsInBhc3RlIiwib25QYXN0ZSIsImRyb3AiLCJvbkRyb3AiLCJjb21wb3NpdGlvbnN0YXJ0Iiwib25Db21wb3NpdGlvblN0YXJ0IiwiY29tcG9zaXRpb25lbmQiLCJvbkNvbXBvc2l0aW9uRW5kIiwiY2xlYXJJbnRlcnZhbCIsIm9yaWdpbmFsSW5wdXRWYWx1ZU9ic2VydmVySW50ZXJ2YWwiLCJzZXRJbnRlcnZhbCIsIm9ic2VydmVPcmlnaW5hbElucHV0VmFsdWUiLCJpbnB1dE11dGF0aW9uT2JzZXJ2ZXIiLCJNdXRhdGlvbk9ic2VydmVyIiwib25JbnB1dERPTUNoYW5nZSIsImRpc2Nvbm5lY3QiLCJvYnNlcnZlIiwiY2hpbGRMaXN0IiwidW5iaW5kIiwiZ2xvYmFsIiwiaXNJRSIsIm9uV2luZG93S2V5RG93biIsIm9uQ2xpY2tBbnl3aGVyZSIsIl9pdGVyYXRvcjMiLCJfc3RlcDMiLCJ1bmJpbmRHbG9iYWwiLCJfdGhpcyR2YWx1ZSIsInRleHQiLCJjdXJyZW50RGlzcGxheVZhbHVlIiwiZGRFbmFibGVkIiwicmVsYXRlZFRhcmdldCIsImlzVGFyZ2V0U2VsZWN0T3B0aW9uIiwiaXNUYXJnZXRBZGROZXdCdG4iLCJhZGROZXciLCJpc1JlbGF0ZWRUYXJnZXRYIiwic2hvdWxkQWRkVGFncyIsInBvc3RVcGRhdGUiLCJEYXRlIiwibG9hZGluZyIsImZvY3VzZWRFbG0iLCJhY3RpdmVFbGVtZW50IiwiaXNUYWciLCJpc0JlbG9uZyIsImlzUmVhZHlPbmx5VGFnIiwiaGFzQXR0cmlidXRlIiwibmV4dFRhZyIsIm5leHRFbGVtZW50U2libGluZyIsIl90aGlzMTEiLCJkZWxldGVLZXlUYWdEZXRlY3RlZCIsImFuY2hvck9mZnNldCIsImFuY2hvck5vZGUiLCJwcmV2QW5jaG9yU2libGluZyIsInByZXZpb3VzU2libGluZyIsImlzQ2FyZXRBZnRlclRhZyIsImxhc3RUYWdFbGVtcyIsImdldFRhZ0VsbXMiLCJ0YWdCZWZvcmVDYXJldCIsInRhZ0VsbVRvQmVEZWxldGVkIiwiZmlyc3RUZXh0Tm9kZUJlZm9yZVRhZyIsInByZXZpb3VzRWxlbWVudFNpYmxpbmciLCJFbGVtZW50IiwicGxhY2VDYXJldEFmdGVyTm9kZSIsIm5vZGVOYW1lIiwibWluIiwibm9kZVZhbHVlIiwibm9kZUlkeCIsImluZGV4IiwiYmx1ciIsImlucHV0U3VnZ2VzdGlvbiIsIm9uSW5wdXQiLCJvbk1peFRhZ3NJbnB1dCIsInNob3dTdWdnZXN0aW9ucyIsInZhbGlkYXRpb24iLCJ2YWxpZGF0ZVRhZyIsInRvZ2dsZVNjb3BlVmFsaWRhdGlvbiIsImlzVmFsaWQiLCJzZWFyY2giLCJfdGhpczEyIiwicmFuZ2VUZXh0IiwibWF0Y2giLCJtYXRjaGVkUGF0dGVybkNvdW50IiwibGFzdFRhZ3NDb3VudCIsIm1hdGNoRmxhZ2dlZFRhZyIsIm1hdGNoRGVsaW1pdGVycyIsInRhZ3NFbGVtcyIsImZyYWdtZW50IiwiY3JlYXRlRG9jdW1lbnRGcmFnbWVudCIsInJlbWFpbmluZ1RhZ3NWYWx1ZXMiLCJpbnB1dFR5cGUiLCJjcmVhdGVUYWdFbGVtIiwiY2hpbGROb2RlcyIsInNldFJhbmdlQXRTdGFydEVuZCIsImxhc3RDaGlsZCIsInVwZGF0ZSIsIndpdGhvdXRDaGFuZ2VFdmVudCIsImNsb25lUmFuZ2UiLCJjb2xsYXBzZSIsImZvY3VzTm9kZSIsImVuZE9mZnNldCIsImxhc3RJbmRleE9mIiwicHJlZml4Iiwib25JbnB1dElFIiwiX3RoaXMiLCJkZXN0cm95IiwidGFnaWZ5VmFsdWUiLCJsb2FkT3JpZ2luYWxWYWx1ZXMiLCJ0aW1lRGlmZkZvY3VzIiwiZ2V0Tm9kZUluZGV4IiwiZml4RmlyZWZveExhc3RUYWdOb0NhcmV0IiwiX3RoaXMxMyIsInNlbGVjdE1vZGVXaXRob3V0SW5wdXQiLCJjbGlwYm9hcmREYXRhIiwicGFzdGVkVGV4dCIsImdldERhdGEiLCJyZXN1bHQiLCJvbkVkaXRUYWdJbnB1dCIsImVkaXRhYmxlRWxtIiwidGFnRWxtSWR4IiwidGV4dFZhbHVlIiwiZGF0YUZvckNoYW5nZWRQcm9wIiwiX2RlZmluZVByb3BlcnR5MiIsIl9fdGFnSWQiLCJoYXNDaGFuZ2VkIiwiZWRpdFRhZ0NoYW5nZURldGVjdGVkIiwib3JpZ2luYWxJc1ZhbGlkIiwibmV3VmFsdWUiLCJvbkVkaXRUYWdQYXN0ZSIsIm5ld05vZGUiLCJvbkVkaXRUYWdGb2N1cyIsIm9uRWRpdFRhZ0JsdXIiLCJvcmlnaW5hbERhdGEiLCJfX29yaWdpbmFsRGF0YSIsIm5ld1RhZ0RhdGEiLCJtZXNzYWdlIiwib25FZGl0VGFna2V5ZG93biIsIl9fb3JpZ2luYWxIVE1MIiwiaXNFZGl0aW5nVGFnIiwiZWRpdGFibGUiLCJfdGhpczE0IiwicmVjb3JkIiwiYWRkZWROb2RlcyIsImFkZGVkTm9kZSIsIm91dGVySFRNTCIsInJlcGxhY2VXaXRoIiwidGFnU2VsZWN0b3IiLCJuZXdsaW5lVGV4dCIsIl9hZGRlZE5vZGUkcHJldmlvdXNTaSIsIm5leHRTaWJsaW5nIiwiYW55dGhpbmdBZnRlck5vZGUiLCJyZW1vdmVkTm9kZXMiLCJyZW1vdmVkTm9kZSIsImxhc3RJbnB1dENoaWxkIiwiVGFnaWZ5IiwibW9ja0luc3RhbmNlIiwiUHJveHkiLCJnZXQiLCJfX3RhZ2lmeSIsImlzRmlyZWZveCIsImRvY3VtZW50TW9kZSIsImFwcGx5U2V0dGluZ3MiLCJidWlsZCIsImdldENTU1ZhcnMiLCJhdXRvZm9jdXMiLCJoZWxwZXJzIiwiZGF0YVByb3BzIiwidGVtcGxhdGUiLCJnZW5lcmF0ZUNsYXNzU2VsZWN0b3JzIiwiX2xvb3AyIiwiY3VycmVudE5hbWUiLCJfc2V0dGluZ3MkZHJvcGRvd24iLCJfc2V0dGluZ3MkZHJvcGRvd24yIiwibWl4TW9kZURlZmF1bHRzIiwibWVyZ2VkRGVmYXVsdHMiLCJhdHRyVmFsIiwiUmVnRXhwIiwiX2RlbGltaXRlcnMiLCJ0ZXh0cyIsInBlcnNpc3RlZFdoaXRlbGlzdCIsImF0dHJzIiwiZ2V0Q3VzdG9tQXR0cmlidXRlcyIsIm91dHB1dCIsInByb3BOYW1lIiwiY29tcFN0eWxlIiwiZ2V0Q29tcHV0ZWRTdHlsZSIsImdldFByb3AiLCJnZXRQcm9wZXJ0eVZhbHVlIiwic2VwcmF0ZVVuaXRGcm9tVmFsdWUiLCJ1bml0IiwicG9wIiwiQ1NTVmFycyIsInRhZ0hpZGVUcmFuc2l0aW9uIiwib3JpZ2luYWxJbnB1dF90YWJJbmRleCIsInRhYkluZGV4IiwiaW5wdXRTZWxlY3RvciIsImluc2VydEJlZm9yZSIsImJsb2NrQ2hhbmdlRXZlbnQiLCJwZXJzaXN0ZWRPcmlnaW5hbFZhbHVlIiwicGFyc2VNaXhUYWdzIiwidGFnTmFtZSIsImluc2VydEFkamFjZW50SFRNTCIsImNsb25lZEV2ZW50IiwidG9nZ2xlQ2xhc3MiLCJmb3JjZSIsInN0YXJ0Iiwic2V0U3RhcnRBZnRlciIsInJlbW92ZUFsbFJhbmdlcyIsImFkZFJhbmdlIiwiZ2V0VGFnVGV4dE5vZGUiLCJ0YWdUZXh0U2VsZWN0b3IiLCJzZXRUYWdUZXh0Tm9kZSIsIkhUTUwiLCJfdGhpczE1IiwiZ2V0TGFzdFRhZyIsInRhZ0lkeCIsInRoYXQiLCJkZWxheWVkX29uRWRpdFRhZ0JsdXIiLCJza2lwVmFsaWRhdGlvbiIsImVkaXRUYWdUb2dnbGVWYWxpZGl0eSIsInJlbW92ZVRhZ3NGcm9tVmFsdWUiLCJwcmV2aW91c0RhdGEiLCJyZXBsYWNlVGFnIiwicmVDaGVja0ludmFsaWRUYWdzIiwiZ2V0SW52YWxpZFRhZ0F0dHJzIiwibmV3VGFnRWxtIiwidXBkYXRlVmFsdWVCeURPTVRhZ3MiLCJfdGhpczE2IiwiaW5qZWN0ZWROb2RlIiwiX3RoaXMkc3RhdGUkc2VsZWN0aW9uIiwiYXBwZW5kTWl4VGFncyIsInVwZGF0ZURPTSIsImhpZGVEcm9wZG93biIsInZhbGlkYXRlIiwiY2hhckF0Iiwic3VnZ2VzdGVkVGV4dCIsInN1Z2dlc3Rpb25TdGFydCIsInN1YnN0ciIsInN1Z2dlc3Rpb25UcmltbWVkIiwic3Vic3RyaW5nIiwiZGF0YVN1Z2dlc3QiLCJyZXBsYWNlVGV4dFdpdGhOb2RlIiwiZ2V0VGFnSWR4IiwiX2xlbiIsImNsYXNzZXNzIiwiX2tleSIsImxhc3RUYWciLCJ0YWdJZCIsImR1cHNDb3VudCIsIl9pdGVyYXRvcjQiLCJfc3RlcDQiLCJpc1NhbWVTdHIiLCJnZXRUYWdJbmRleEJ5VmFsdWUiLCJfdGhpczE3IiwiaW5kaWNlcyIsImdldFRhZ0VsbUJ5VmFsdWUiLCJmbGFzaFRhZyIsIl90aGlzMTgiLCJpc1RhZ0JsYWNrbGlzdGVkIiwieCIsImlzVGFnV2hpdGVsaXN0ZWQiLCJnZXRXaGl0ZWxpc3RJdGVtIiwiX3dpIiwiX3dpdiIsInNldFJlYWRvbmx5IiwiYXR0cnJpYnV0ZSIsInNldENvbnRlbnRFZGl0YWJsZSIsImNvbnRlbnRFZGl0YWJsZSIsInNldERpc2FibGVkIiwiaXNEaXNhYmxlZCIsInRhZ3NJdGVtcyIsIl90aGlzMTkiLCJfdGhpcyRzZXR0aW5ncyIsIndoaXRlbGlzdE1hdGNoZXMiLCJ3aGl0ZWxpc3RXaXRoUHJvcHMiLCJpc0NvbGxlY3Rpb24iLCJtYXBTdHJpbmdUb0NvbGxlY3Rpb24iLCJfcmVmMyIsIndoaXRlbGlzdE1hdGNoZXNWYWx1ZXMiLCJmaWx0ZXJlZExpc3QiLCJmaWx0ZXJlZEl0ZW0iLCJtYXRjaE9iaiIsIl90aGlzMjAiLCJfdGhpcyRzZXR0aW5nczIiLCJ0YWdzRGF0YVNldCIsInByZUludGVycG9sYXRlZCIsIm1heFRhZ3NSZWFjaGVkIiwidGV4dFByb3AiLCJFcnJvciIsIm5ld1dyYXBwZXJOb2RlIiwic3RyVG9SZXBsYWNlIiwibm9kZVRvUmVwbGFjZSIsIm5vZGVBdENhcmV0IiwiZmlyc3RTcGxpdE9mZnNldCIsInNwbGl0VGV4dCIsInNlbGVjdFRhZyIsIl90aGlzMjEiLCJsYXN0VGFnRWxtIiwiYXBwZW5kVGFnIiwiYWRkRW1wdHlUYWciLCJpbml0aWFsRGF0YSIsImNsZWFySW5wdXQiLCJfdGhpczIyIiwidGFnRWxlbXMiLCJhZ2dyZWdhdGVkaW52YWxpZElucHV0IiwiZnJhZyIsImFkZE1peFRhZ3MiLCJ0YWdFbG1QYXJhbXMiLCJfX3ByZUludmFsaWREYXRhIiwidGFnc0RhdGEiLCJfdGhpczIzIiwicHJlZml4ZWRUZXh0VG9UYWciLCJ0YWdJdGVtIiwiX3RoaXMyNCIsImNyZWF0ZWRGcm9tRGVsaW1pdGVycyIsImluc2VydEJlZm9yZU5vZGUiLCJleHRyYURhdGEiLCJ0ZW1wbGF0ZURhdGEiLCJfdGhpczI1IiwidGFnVmFsaWRhdGlvbiIsInRhZ0VsbXMiLCJzaWxlbnQiLCJ0cmFuRHVyYXRpb24iLCJfdGhpczI2IiwidGFnc1RvUmVtb3ZlIiwiZWxtcyIsInJlbW92ZU5vZGUiLCJhbmltYXRpb24iLCJwYXJzZUZsb2F0IiwiY2xpZW50VG9wIiwicmVhc29uIiwicmVtb3ZlVGFnc0Zyb21ET00iLCJ0YWdzIiwiX3RoaXMyNyIsInNwbGljZSIsIl90aGlzMjgiLCJoYXNWYWx1ZSIsIl90aGlzJHZhbHVlMiIsInNldE9yaWdpbmFsSW5wdXRWYWx1ZSIsImFyZ3MiLCJVUERBVEVfREVMQVkiLCJkZWJvdW5jZWRVcGRhdGVUaW1lb3V0IiwicmVhbGx5VXBkYXRlIiwiaW5wdXRWYWx1ZSIsImdldElucHV0VmFsdWUiLCJnZXRDbGVhblZhbHVlIiwiZ2V0TWl4ZWRUYWdzQXNTdHJpbmciLCJvcmlnaW5hbElucHV0VmFsdWVGb3JtYXQiLCJfaW50ZXJwb2xhdG9yIiwiaXRlcmF0ZUNoaWxkcmVuIiwicm9vdE5vZGUiLCJfX3JlbW92ZWQiLCJyZW1vdmVUYWciLCJkZWZhdWx0Il0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///./lib/tagify/tagify.esm.js\n"); + +/***/ }) + +/******/ }); +/************************************************************************/ +/******/ // The module cache +/******/ var __webpack_module_cache__ = {}; +/******/ +/******/ // The require function +/******/ function __webpack_require__(moduleId) { +/******/ // Check if module is in cache +/******/ var cachedModule = __webpack_module_cache__[moduleId]; +/******/ if (cachedModule !== undefined) { +/******/ return cachedModule.exports; +/******/ } +/******/ // Create a new module (and put it into the cache) +/******/ var module = __webpack_module_cache__[moduleId] = { +/******/ // no module.id needed +/******/ // no module.loaded needed +/******/ exports: {} +/******/ }; +/******/ +/******/ // Execute the module function +/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__); +/******/ +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } +/******/ +/************************************************************************/ +/******/ /* webpack/runtime/compat get default export */ +/******/ !function() { +/******/ // getDefaultExport function for compatibility with non-harmony modules +/******/ __webpack_require__.n = function(module) { +/******/ var getter = module && module.__esModule ? +/******/ function() { return module['default']; } : +/******/ function() { return module; }; +/******/ __webpack_require__.d(getter, { a: getter }); +/******/ return getter; +/******/ }; +/******/ }(); +/******/ +/******/ /* webpack/runtime/define property getters */ +/******/ !function() { +/******/ // define getter functions for harmony exports +/******/ __webpack_require__.d = function(exports, definition) { +/******/ for(var key in definition) { +/******/ if(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) { +/******/ Object.defineProperty(exports, key, { enumerable: true, get: definition[key] }); +/******/ } +/******/ } +/******/ }; +/******/ }(); +/******/ +/******/ /* webpack/runtime/hasOwnProperty shorthand */ +/******/ !function() { +/******/ __webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); } +/******/ }(); +/******/ +/******/ /* webpack/runtime/make namespace object */ +/******/ !function() { +/******/ // define __esModule on exports +/******/ __webpack_require__.r = function(exports) { +/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { +/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); +/******/ } +/******/ Object.defineProperty(exports, '__esModule', { value: true }); +/******/ }; +/******/ }(); +/******/ +/************************************************************************/ +/******/ +/******/ // startup +/******/ // Load entry module and return exports +/******/ // This entry module can't be inlined because the eval-source-map devtool is used. +/******/ var __webpack_exports__ = __webpack_require__("./ts/blades.ts"); +/******/ +/******/ })() +; \ No newline at end of file diff --git a/module/classes/BladesChat.js b/module/classes/BladesChat.js deleted file mode 100644 index 2a131bc9..00000000 --- a/module/classes/BladesChat.js +++ /dev/null @@ -1,179 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region IMPORTS ~ -import { ApplyTooltipAnimations } from "../core/gsap.js"; -import C, { RollType, Position, RollResult } from "../core/constants.js"; -import U from "../core/utilities.js"; -import BladesRoll from "./BladesRoll.js"; -import BladesConsequence from "./BladesConsequence.js"; -class BladesChat extends ChatMessage { - static Initialize() { - Hooks.on("renderChatMessage", (msg, html) => { - ApplyTooltipAnimations(html); - const { rollData } = msg.flagData; - if (rollData) { - BladesConsequence.ApplyChatListeners(msg); - } - html.addClass("display-ok"); - }); - return loadTemplates([ - "systems/eunos-blades/templates/chat/roll-result/action.hbs", - "systems/eunos-blades/templates/chat/roll-result/action-clock.hbs", - "systems/eunos-blades/templates/chat/roll-result/action-acquireasset.hbs", - "systems/eunos-blades/templates/chat/roll-result/action-reduceheat.hbs", - "systems/eunos-blades/templates/chat/roll-result/action-clock-recover.hbs", - "systems/eunos-blades/templates/chat/roll-result/action-gatherinfo.hbs", - "systems/eunos-blades/templates/chat/roll-result/fortune.hbs", - "systems/eunos-blades/templates/chat/roll-result/fortune-clock.hbs", - "systems/eunos-blades/templates/chat/roll-result/fortune-gatherinfo.hbs", - "systems/eunos-blades/templates/chat/roll-result/fortune-incarceration.hbs", - "systems/eunos-blades/templates/chat/roll-result/fortune-engagement.hbs", - "systems/eunos-blades/templates/chat/roll-result/indulgevice.hbs", - "systems/eunos-blades/templates/chat/roll-result/resistance.hbs", - "systems/eunos-blades/templates/chat/components/inline-resistance.hbs", - "systems/eunos-blades/templates/chat/components/die.hbs" - ]); - } - // static async ConstructRollOutput(rollInst: BladesRoll): Promise { - // const rollData = { - // ...rollInst.data, - // rollTraitVerb: rollInst.rollTraitVerb ?? "", - // rollTraitPastVerb: rollInst.rollTraitPastVerb ?? rollInst.rollTraitVerb ?? "" - // }; - // return await BladesChat.create({ - // speaker: rollInst.getSpeaker(BladesChat.getSpeaker()), - // content: await renderTemplate(rollInst.template, rollData), - // type: CONST.CHAT_MESSAGE_TYPES.ROLL, - // flags: { - // "eunos-blades": { - // template: rollInst.template, - // rollData - // } - // } - // }) as BladesChat; - // } - static IsNewestRollResult(rollInst) { - const lastRollResultID = $("#chat-log .chat-message .blades-roll:not(.inline-roll)") - .last() - .attr("id"); - return typeof lastRollResultID === "string" - && lastRollResultID === rollInst.id; - } - get flagData() { - return this.flags["eunos-blades"]; - } - get rollData() { return this.flagData.rollData; } - async setFlagVal(scope, key, val) { - return await this.setFlag(C.SYSTEM_ID, `${scope}.${key}`, val); - } - get allRollConsequences() { - const returnData = { - [Position.controlled]: { - [RollResult.critical]: {}, - [RollResult.success]: {}, - [RollResult.partial]: {}, - [RollResult.fail]: {} - }, - [Position.risky]: { - [RollResult.critical]: {}, - [RollResult.success]: {}, - [RollResult.partial]: {}, - [RollResult.fail]: {} - }, - [Position.desperate]: { - [RollResult.critical]: {}, - [RollResult.success]: {}, - [RollResult.partial]: {}, - [RollResult.fail]: {} - } - }; - const { consequenceData } = this.flagData.rollData ?? {}; - if (!consequenceData) { - return returnData; - } - Object.entries(consequenceData) - .forEach(([position, positionData]) => { - Object.entries(positionData) - .forEach(([rollResult, csqDataSet]) => { - returnData[position][rollResult] = Object.fromEntries(Object.entries(csqDataSet) - .filter(([id, cData]) => cData.id) - .map(([id, cData]) => [ - id, - game.eunoblades.Consequences.get(cData.id) ?? new BladesConsequence(cData) - ])); - }); - }); - return returnData; - } - get rollConsequences() { - if (!this.parentRoll) { - return []; - } - const { rollPositionFinal, rollResult, consequenceData } = this.parentRoll.data; - if (!rollPositionFinal || !rollResult || !consequenceData) { - return []; - } - if (typeof rollResult !== "string" || ![RollResult.partial, RollResult.fail].includes(rollResult)) { - return []; - } - const activeConsequences = consequenceData?.[rollPositionFinal]?.[rollResult] ?? {}; - return Object.values(activeConsequences) - .map((cData) => game.eunoblades.Consequences.get(cData.id) ?? new BladesConsequence(cData)); - } - get elem$() { - return $("#chat-log") - .find(`.chat-message[data-message-id="${this.id}"]`); - } - get elem() { return this.elem$[0]; } - get isRollResult() { return "rollData" in this.flagData; } - get parentRoll() { - if (!this.isRollResult) { - return undefined; - } - const { rollData } = this.flagData; - if (!rollData) { - return undefined; - } - return game.eunoblades.Rolls.get(rollData.id ?? "") ?? new BladesRoll({ - ...rollData, - isScopingById: false - }); - } - get roll$() { - return this.parentRoll ? this.elem$.find(`#${this.parentRoll.id}`) : undefined; - } - async regenerateFromFlags() { - if (this.isRollResult) { - await this.update({ content: await renderTemplate(this.flagData.template, this) }); - } - } - async render(force) { - await super.render(force); - await this.activateListeners(); - } - async activateListeners() { - if (!this.elem$) { - eLog.error("BladesChat", `No BladesChat.elem found for id ${this.id}.`); - return; - } - ApplyTooltipAnimations(this.elem$); - BladesConsequence.ApplyChatListeners(this); - if (this.parentRoll) { - this.elem$.addClass(`${this.parentRoll.rollType.toLowerCase()}-roll`); - if (this.parentRoll.rollType === RollType.Action && this.rollConsequences.some((csq) => !csq.isAccepted)) { - this.elem$.addClass("unresolved-action-roll"); - } - else { - this.elem$.removeClass("unresolved-action-roll"); - } - if (BladesChat.IsNewestRollResult(this.parentRoll)) { - $("#chat-log .chat-message").removeClass("active-chat-roll"); - this.elem$.addClass("active-chat-roll"); - } - else { - this.elem$.removeClass("active-chat-roll"); - } - } - U.gsap.to(this.elem$, { autoAlpha: 1, duration: 0.15, ease: "none" }); - } -} -export default BladesChat; diff --git a/module/classes/BladesClock.js b/module/classes/BladesClock.js deleted file mode 100644 index 7c535e49..00000000 --- a/module/classes/BladesClock.js +++ /dev/null @@ -1,686 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { BladesActorType, BladesItemType, ClockColor, ClockKeyDisplayMode } from "../core/constants.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -import U from "../core/utilities.js"; -import { BladesActor } from "../documents/BladesActorProxy.js"; -import { BladesItem } from "../documents/BladesItemProxy.js"; -class BladesClockKey extends BladesTargetLink { - // #region STATIC METHODS ~ - static Initialize() { - game.items?.contents - .filter((item) => BladesItem.IsType(item, BladesItemType.clock_keeper, BladesItemType.project, BladesItemType.cohort_gang, BladesItemType.cohort_expert, BladesItemType.ritual, BladesItemType.design, BladesItemType.location, BladesItemType.score)) - .forEach((item) => { - Object.values(item.system.clocksData?.keys ?? {}) - .forEach((keyData) => new BladesClockKey(keyData)); - Object.values(item.system.clocksData?.clocks ?? {}) - .forEach((clockData) => new BladesClock(clockData)); - }); - game.actors?.contents - .filter((actor) => BladesActor.IsType(actor, BladesActorType.pc, BladesActorType.faction)) - .forEach((actor) => { - Object.values(actor.system.clocksData?.keys ?? {}) - .forEach((keyData) => new BladesClockKey(keyData)); - Object.values(actor.system.clocksData?.clocks ?? {}) - .forEach((clockData) => new BladesClock(clockData)); - }); - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - return { - name: "", - isVisible: false, - isActive: false, - isNameVisible: false, - isShowingControls: true, - clocksData: {}, - sceneID: false, - displayMode: ClockKeyDisplayMode.full, - oneKeyIndex: U.gsap.utils.random(1, 5, 1), - ...schemaData - }; - } - static async Create(config, clockConfigs = []) { - // Create and initialize the target link - const clockKey = (await super.Create(config)); - // Confirm at least one, but no more than six, clockConfigs provided: - if (clockConfigs.length > 6) { - // If too many clock keys, alert user and discard excess. - eLog.error("BladesClockKey", "[BladesClockKey.Create] Too many clock configs! (Max 6.) Eliminating extras.", clockConfigs); - clockConfigs = clockConfigs.slice(0, 6); - } - else if (clockConfigs.length === 0) { - // If no clocks provided, add one default clock. - clockConfigs.push({}); - } - // Convert clock configs to full clock data objects. - const clocksData = Object.fromEntries(clockConfigs.map((clockConfig, i) => { - clockConfig.index = i; - const cData = clockKey.parseClockConfig(clockConfig); - return [cData.id, cData]; - })); - // Update the clock key with the new clock data - await clockKey.updateTarget("clocksData", clocksData); - return clockKey; - } - // #endregion - // #region GETTERS & SETTERS ~ - // #region -- Shortcut Schema Getters ~ - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { this.updateTarget("name", val); } - get isVisible() { return this.data.isVisible; } - set isVisible(val) { this.updateTarget("isVisible", U.pBool(val)); } - get isActive() { return this.data.isActive; } - set isActive(val) { this.updateTarget("isActive", U.pBool(val)); } - get isNameVisible() { return this.data.isNameVisible; } - set isNameVisible(val) { this.updateTarget("isNameVisible", U.pBool(val)); } - get isShowingControls() { return this.data.isShowingControls; } - set isShowingControls(val) { this.updateTarget("isShowingControls", U.pBool(val)); } - get clocksData() { return this.data.clocksData; } - get displayMode() { - if (game.user.isGM && this.isShowingControls) { - return ClockKeyDisplayMode.full; - } - return this.data.displayMode; - } - get oneKeyIndex() { return this.data.oneKeyIndex; } - get sceneID() { return this.data.sceneID; } - get overlayPosition() { - return undefined; - } - // #endregion - get clocks() { - return new Collection(Object.entries(this.clocksData) - .sort((a, b) => a[1].index - b[1].index) - .map(([id, data]) => [ - id, - game.eunoblades.Clocks.get(id) ?? new BladesClock(data) - ])); - } - get size() { return Object.keys(this.clocksData).length; } - get isComplete() { - return Array.from(this.clocks).every((clock) => clock.isComplete); - } - get currentClockIndex() { - return U.pInt(this.currentClock?.index); - } - get currentClock() { - return this.clocks.find((clock) => !clock.isComplete); - } - get displaySelectOptions() { - const options = [ - { value: ClockKeyDisplayMode.full, display: "Full Key" }, - { value: ClockKeyDisplayMode.clocks, display: "Clocks" }, - { value: ClockKeyDisplayMode.currentClock, display: "Current Clock" }, - { value: ClockKeyDisplayMode.presentCurrentClock, display: "Present Current Clock" } - ]; - for (let i = 0; i < this.size; i++) { - options.push(...[ - { value: i, display: `Clock #${i}` }, - { value: `present${i}`, display: `Present Clock #${i}` } - ]); - } - return options; - } - // #endregion - // #region ~~~ CONSTRUCTOR & CLOCK CONFIG PARSER ~~~ - constructor(data) { - super(data); - game.eunoblades.ClockKeys.set(this.id, this); - } - parseClockConfig(config, indexOverride) { - // Remove target so it doesn't conflict with key's targetID - delete config.target; - // Derive clock's targetID and targetKey/targetFlagKey from key's values - config.targetID = this.targetID; - if (this.targetKey) { - config.targetKey = `${this.targetKey}.${this.id}.clocksData`; - delete config.targetFlagKey; - } - else if (this.targetFlagKey) { - config.targetFlagKey = `${this.targetFlagKey}.${this.id}.clocksData`; - delete config.targetKey; - } - // Assign 'parentKeyID' and 'index' - config.parentKeyID = this.id; - config.index = indexOverride ?? this.clocks.size; - // Parse config to full data object - const cData = BladesClock.ParseConfig(config); - return cData; - } - // #endregion - // #region HTML INTERACTION ~ - async getHTML() { - return await renderTemplate("systems/eunos-blades/templates/overlays/clock-key.hbs", this); - } - get elem() { - return $(`#${this.id}`)[0]; - } - async toggleActive() { - return await this.updateTarget("isActive", !this.isActive); - } - get elements() { - const elemData = {}; - if (!this.elem) { - return elemData; - } - elemData.key = this.elem; - elemData.keyContainer = $(this.elem).closest(".clock-key-container")[0]; - for (const clock of Array.from(this.clocks)) { - if (!clock.elem) { - return elemData; - } - const { index, elem } = clock; - elemData[`clock ${index}`] = elem; - elemData[`clock ${index} Container`] = $(elem).closest(".clock-container")[0]; - } - return elemData; - } - // Initializes clock key with proper position and scale before displaying via autoAlpha - async initClockKeyElem(displayMode) { - displayMode = this.displayMode; - if (!this.elem) { - return new Promise((resolve) => { - setTimeout(async () => resolve(await this.initClockKeyElem(displayMode)), 1000); - }); - } - const { elem } = this; - const { keyTweenVars, keyContTweenVars } = this.getDisplayMode(displayMode); - const keyImgContainer = $(this.elem).find(".key-image-container")[0]; - return new Promise((resolve) => { - U.gsap.timeline() - .set(keyImgContainer, keyContTweenVars) - .set(elem, keyTweenVars) - .to(elem, { - autoAlpha: 1, - duration: 0.5 - }).then(() => { resolve(); }); - }); - } - // Given a display mode ("full", "clocks", or a clock index number), will return a GSAP effects - // config object to be plugged into any of the 'clockKey' effects. - // Can optionally provide config values to be included in a second parameter. - getDisplayMode(displayMode, configOptions = {}) { - if (!this.elem) { - return configOptions; - } - if (!this.isActive) { - displayMode = ClockKeyDisplayMode.full; - } - configOptions.duration ??= 1; - configOptions.ease ??= "power2"; - configOptions.autoAlpha ??= 1; - const keyTweenVars = { ...configOptions }; - const keyContTweenVars = { ...configOptions }; - // Get key data - const keyPosData = U.objClone(C.ClockKeyPositions[this.size]); - // Are we presenting? If so, flag it true and parse displayMode to standard clock reference - let isPresenting = false; - if (/^present/.exec(`${displayMode}`)) { - isPresenting = true; - const suffix = `${displayMode}`.substring(7); - if (!isNaN(Number(suffix))) { - displayMode = U.pInt(suffix); - } - else { - displayMode = ClockKeyDisplayMode.currentClock; - } - } - if (!isNaN(Number(displayMode))) { - displayMode = U.pInt(displayMode); - } - // Get position and area dimensions of clock key area focused on by displayMode - let focusArea; - let focusPos; - const activeClockSide = this.currentClock?.getActiveSide(0); - switch (displayMode) { - case ClockKeyDisplayMode.full: { - focusPos = keyPosData.keyCenter; - focusArea = keyPosData.keyDimensions; - break; - } - case ClockKeyDisplayMode.clocks: { - focusPos = keyPosData.clocksCenter; - focusArea = keyPosData.clocksCenterDimensions; - break; - } - case ClockKeyDisplayMode.currentClock: { - displayMode = this.currentClockIndex; - } - // falls through - default: { - if (typeof displayMode === "number") { - if (displayMode in keyPosData.clocks) { - focusPos = keyPosData.clocks[displayMode]; - focusArea = { width: 110, height: 110 }; - if (isPresenting) { - focusArea = { width: 55, height: 110 }; - if (activeClockSide === "left") { - focusPos.x -= 30; - focusPos.z = -50; - } - else if (activeClockSide === "right") { - focusPos.x += 35; - // focusPos.z = 1350; - } - } - break; - } - } - throw new Error(`[BladesClockKey.getDisplayMode] Error display key '${this.id}' in mode '${displayMode}'.`); - } - } - // Get height and width of clock key container - const keyContainer = $(this.elem).closest(".clock-key-container")[0]; - const keyContainerDimensions = { - width: U.gsap.getProperty(keyContainer, "width"), - height: U.gsap.getProperty(keyContainer, "height") - }; - // If not isActive, adjust 'width' to account for CSS styles - if (!this.isActive) { - keyContainerDimensions.width *= 2; - } - // Determine scale factor necessary to fit focusArea inside keyContainer - keyTweenVars.scale = Math.min(keyContainerDimensions.height / focusArea.height, keyContainerDimensions.width / focusArea.width); - // If not isActive, adjust 'scale' to account for CSS styles - if (!this.isActive) { - // keyTweenVars.scale *= 2; - } - // Determine top and left values for key-image-container, accounting for x/yPercent -50 - keyContTweenVars.top = (0.5 * 100) - focusPos.y; - keyContTweenVars.left = (0.5 * 100) - focusPos.x; - // Set transfer origin of key-image-container to same position, for further animation - keyContTweenVars.transformOrigin = `${focusPos.x}px ${focusPos.y}px`; - // Set initial y-rotation to turn clock half towards camera if 'isPresenting' - if (isPresenting) { - if (activeClockSide === "left") { - keyContTweenVars.rotateY = 30; - } - else if (activeClockSide === "right") { - keyContTweenVars.rotateY = -30; - } - } - // If not isActive, adjust 'width' and 'scale' to account for CSS styles - return { keyTweenVars, keyContTweenVars }; - } - async switchToMode(displayMode, configOptions = {}, isLocalOnly = false) { - const self = this; - const { elem } = self; - if (!elem) { - return new Promise((resolve) => { - setTimeout(async () => resolve(await this.switchToMode(displayMode, configOptions, isLocalOnly)), 1000); - }); - } - const { keyTweenVars, keyContTweenVars } = self.getDisplayMode(displayMode, configOptions); - const keyImgContainer = $(elem).find(".key-image-container")[0]; - return new Promise((resolve) => { - U.gsap.timeline({ - onComplete() { - if (!isLocalOnly) { - self.updateTarget("displayMode", displayMode) - .then(() => resolve()); - } - } - }) - .to(elem, keyTweenVars, 0) - .to(keyImgContainer, keyContTweenVars, 0); - }); - } - // #endregion - // #region Adding & Removing Clocks ~ - async updateClockIndices() { - await this.updateTarget("clocksData", Object.fromEntries(Object.entries(this.clocksData) - .map(([id, data], index) => [id, { ...data, index }]))); - return this.clocks; - } - async addClock(clockConfig = {}) { - // Derive clock data from config - const clockData = this.parseClockConfig(clockConfig); - // Write to state - await this.updateTarget(`clocksData.${clockData.id}`, clockData); - } - async deleteClock(clockID) { - if (this.size <= 1) { - throw new Error("[BladesClockKey.deleteClock()] Cannot reduce number of clocks below 1!"); - } - clockID ??= Array.from(this.clocks).pop()?.id; - await game.eunoblades.Clocks.get(clockID ?? "")?.delete(); - await this.updateClockIndices(); - } -} -class BladesClock extends BladesTargetLink { - // #region STATIC METHODS ~ - static ApplySchemaDefaults(schemaData) { - const namedValueMax = { - name: schemaData.name ?? "", - value: schemaData.value ?? 0, - max: schemaData.max ?? 8 - }; - return { - index: 0, - color: ClockColor.white, - isVisible: true, - isNameVisible: true, - isHighlighted: false, - isActive: true, - isShowingControls: game.user.isGM, - sceneID: false, - ...schemaData, - ...namedValueMax - }; - } - // #endregion - // #region GETTERS & SETTERS ~ - get canEdit() { - // return true if user has edit permissions on parent document, and clock is - // visible and active. - console.log("NOTE: All Clocks currently Editable; see line 71 of BladesClock.ts"); - return this.isVisible && this.isActive; - } - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { this.updateTarget("name", val); } - get value() { return U.pInt(this.data.value); } - set value(val) { this.updateTarget("value", U.pInt(val)); } - get max() { return U.pInt(this.data.max); } - set max(val) { this.updateTarget("max", U.pInt(val)); } - get color() { return this.data.color ?? ClockColor.white; } - set color(val) { this.updateTarget("color", val); } - get isActive() { return U.pBool(this.data.isActive); } - set isActive(val) { this.updateTarget("isActive", U.pBool(val)); } - get parentKey() { return game.eunoblades.ClockKeys.get(this.data.parentKeyID); } - get isShowingControls() { - if (this.parentKey && !this.parentKey.isShowingControls) { - return false; - } - return U.pBool(this.data.isShowingControls); - } - set isShowingControls(val) { this.updateTarget("isShowingControls", U.pBool(val)); } - get isNameVisible() { return U.pBool(this.data.isNameVisible); } - set isNameVisible(val) { this.updateTarget("isNameVisible", U.pBool(val)); } - get isVisible() { return U.pBool(this.data.isVisible); } - set isVisible(val) { this.updateTarget("isVisible", U.pBool(val)); } - get isHighlighted() { return U.pBool(this.data.isHighlighted); } - set isHighlighted(val) { this.updateTarget("isHighlighted", U.pBool(val)); } - get index() { return U.pInt(this.data.index); } - set index(val) { this.updateTarget("index", U.pInt(val)); } - get tooltip() { return this.data.tooltip; } - set tooltip(val) { this.updateTarget("tooltip", val); } - get sceneID() { return this.data.sceneID; } - set sceneID(val) { this.updateTarget("sceneID", val); } - get isEmpty() { return this.value === 0; } - get isComplete() { return this.value >= this.max; } - get rollOppClock() { return this; } - get rollOppName() { return this.name; } - get rollOppType() { return "clock"; } - get colorSelectOptions() { - return [ - { value: ClockColor.white, display: "🔘" }, - { value: ClockColor.yellow, display: "📀" }, - { value: ClockColor.cyan, display: "🔵" }, - { value: ClockColor.red, display: "🔴" } - ]; - } - get maxSelectOptions() { - return [ - { value: 2, display: 2 }, - { value: 3, display: 3 }, - { value: 4, display: 4 }, - { value: 5, display: 5 }, - { value: 6, display: 6 }, - { value: 8, display: 8 }, - { value: 10, display: 10 }, - { value: 12, display: 12 } - ]; - } - get valueSelectOptions() { - const returnVals = []; - for (let i = 0; i <= this.max; i++) { - returnVals.push({ value: i, display: i }); - } - return returnVals; - } - // #region ~~ CONSTRUCTOR ~~ - constructor(data) { - super(data); - game.eunoblades.Clocks.set(this.id, this); - } - // #endregion - // #region HTML INTERACTION ~ - get elem() { - return $(`[data-id="${this.id}"`)[0]; - } - async getHTML() { - return await renderTemplate("systems/eunos-blades/templates/components/clock.hbs", this); - } - // Returns which hemisphere of the clock will show the final change if segmentDelta segments are added/removed. - getActiveSide(segmentDelta) { - const finalClockValue = Math.min(this.max, Math.max(0, this.value + segmentDelta)); - const halfClockValue = this.max / 2; - if (finalClockValue > halfClockValue) { - return "left"; - } - return "right"; - } - // #endregion - // #region Adding/Removing Clock Segments - // Returns number of segments beyond max (or 0, if max not met) - async fillSegments(count) { - // Amount added beyond max: - const clockOverflow = Math.max(0, this.value + count - this.max); - // Clamp count to max: - count = Math.min(this.value + count, this.max) - this.value; - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value + count); - return clockOverflow; - } - // Returns (positive) number of segments removed - // in excess of the number of segments in the clock - async clearSegments(count) { - // Amount removed beyond 0: - const clockOverflow = Math.max(0, count - this.value); - // Clamp count to min: - count = Math.min(this.value, count); - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value - count); - return clockOverflow; - } - async delete() { - await super.delete(); - this.parentKey?.updateClockIndices(); - } -} -export const ApplyClockListeners = async (html, namespace) => { - eLog.checkLog3("ApplyListeners", "ApplyClockListeners", { html, find: html.find(".clock") }); - // Step One: Find any clock keys and initialize them - await Promise.all(Array.from(html.find(".clock-key")) - .map(async (keyElem) => { - const key = game.eunoblades.ClockKeys.get(keyElem.id); - if (key) { - return await key.initClockKeyElem(); - } - return undefined; - })); - // Utility functions - async function toggleTarget(el, source) { - if (!source) { - return; - } - const prop = $(el).data("prop"); - eLog.checkLog3("clockControls", "Toggle Event", { source, el, prop, curVal: source.getTargetProp(prop) }); - await source.updateTarget(prop, !source.getTargetProp(prop)); - if (prop === "isShowingControls") { - if (source instanceof BladesClockKey) { - const key = source; - const { isShowingControls } = key; - if (isShowingControls) { - // If controls have been enabled, switch display mode of key to full for user (GM) only. - key.switchToMode(ClockKeyDisplayMode.full, undefined, true); - } - else { - // Otherwise, re-initialize key for GM. - key.initClockKeyElem(); - } - } - } - } - async function setTarget(val, el, source) { - if (!source) { - return; - } - const prop = $(el).data("prop"); - eLog.checkLog3("clockControls", "Set Event", { val, source, prop, curVal: source.getTargetProp(prop) }); - source.updateTarget(prop, val); - } - // Add listeners and animation timelines to clock keys - U.toArray(html.find(".clock-key-container")).forEach((keyContainerElem) => { - const keyID = $(keyContainerElem).find(".clock-key")[0].id; - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - throw new Error("Too early for key: no KEY!"); - } - const { elem } = key ?? {}; - if (!elem) { - throw new Error("Too early for key: no ELEMENT!"); - } - // Apply listeners to GM control elements - if (game.user.isGM) { - $(keyContainerElem).find("[data-action='key-toggle']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .off(`.${namespace}`) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, key); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(keyContainerElem).find("input.clock-key-controls-name") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, key); - } - }); - $(keyContainerElem).find("select.key-select") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, key); - } - }); - $(keyContainerElem).find("[data-action='add-clock']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - key.addClock(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(keyContainerElem).find("[data-action='delete-key']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el, { color: "#FF0000" })); }) - .on({ - [`contextmenu.${namespace}`]: (event) => { - event.preventDefault(); - key.delete(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - } - }); - // Add listeners to clocks - html.find(".clock-container").each((_, clockContainerElem) => { - const clockID = $(clockContainerElem).find(".clock")[0].id; - const clock = game.eunoblades.Clocks.get(clockID); - if (!clock) { - throw new Error("Too early for clock: no CLOCK!"); - } - const { elem } = clock ?? {}; - if (!elem) { - throw new Error("Too early for clock: no ELEMENT!"); - } - // Apply listeners to GM control elements - if (game.user.isGM) { - if (clock.isShowingControls) { - $(clockContainerElem).find("[data-action='clock-toggle']") - .each((__, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, clock); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(clockContainerElem).find("input.clock-controls-name") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, clock); - } - }); - $(clockContainerElem).find("select.clock-select") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, clock); - } - }); - $(clockContainerElem).find("[data-action='delete-clock']") - .each((__, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el, { color: "#FF0000" })); }) - .on({ - [`contextmenu.${namespace}`]: (event) => { - event.preventDefault(); - clock.delete(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - } - else { - $(clockContainerElem).find("[data-action='clock-toggle'][data-prop='isShowingControls']") - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, clock); - } - }); - $(clockContainerElem).find(".clock") - .on({ - [`click.${namespace}`]: () => { clock.updateTarget("isShowingControls", true); }, - [`contextmenu.${namespace}`]: () => { clock.isVisible = !clock.isVisible; }, - [`wheel.${namespace}`]: (event) => { - if (!(event.originalEvent instanceof WheelEvent)) { - return; - } - event.preventDefault(); - if (event.originalEvent.deltaY < 0) { - clock.fillSegments(1); - } - else { - clock.clearSegments(1); - } - } - }); - } - } - else if (clock.canEdit && !clock.isShowingControls) { - // Apply listeners for non-GM users - $(clockContainerElem).find(".clock") - .on({ - [`click.${namespace}`]: () => clock.fillSegments(1), - [`contextmenu.${namespace}`]: () => clock.clearSegments(1) - }); - } - }); -}; -export default BladesClock; -export { BladesClockKey }; diff --git a/module/classes/BladesClockKey.js b/module/classes/BladesClockKey.js deleted file mode 100644 index c600e5c1..00000000 --- a/module/classes/BladesClockKey.js +++ /dev/null @@ -1,1534 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { ClockKey_SVGDATA, ClockDisplayContext, BladesActorType, BladesItemType, ClockColor, ClockKeyDisplayMode } from "../core/constants.js"; -import { Dragger } from "../core/gsap.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -import U from "../core/utilities.js"; -import { BladesActor, BladesFaction } from "../documents/BladesActorProxy.js"; -import { BladesItem, BladesClockKeeper, BladesProject, BladesScore } from "../documents/BladesItemProxy.js"; -function isElemPosData(obj) { - return U.isList(obj) - && typeof obj.x === "number" - && typeof obj.y === "number" - && typeof obj.width === "number" - && typeof obj.height === "number"; -} -class BladesClockKey extends BladesTargetLink { - // #region STATIC METHODS ~ - static Initialize() { - function registerClockKeys(doc) { - if ("clocksData" in doc.system) { - Object.values(doc.system.clocksData ?? {}) - .forEach((keyData) => { - try { - new BladesClockKey(keyData); - } - catch (err) { - eLog.error("BladesClockKey", "[BladesClockKey.Initialize] Error initializing clock key.", err, keyData); - } - }); - } - } - game.items.contents - .filter((item) => BladesItem.IsType(item, BladesItemType.clock_keeper, BladesItemType.project, BladesItemType.cohort_gang, BladesItemType.cohort_expert, BladesItemType.ritual, BladesItemType.design, BladesItemType.location, BladesItemType.score)) - .forEach(registerClockKeys); - game.actors.contents - .filter((actor) => BladesActor.IsType(actor, BladesActorType.pc, BladesActorType.faction)) - .forEach(registerClockKeys); - return loadTemplates([ - "systems/eunos-blades/templates/components/clock-key.hbs", - "systems/eunos-blades/templates/components/clock.hbs" - ]); - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - return { - name: "", - isVisible: false, - isNameVisible: false, - isSpotlit: false, - clocksData: {}, - sceneIDs: [], - displayMode: ClockKeyDisplayMode.full, - oneKeyIndex: U.gsap.utils.random(0, 4, 1), - ...schemaData - }; - } - static async Create(config, _parentLinkData, clocksInitialData = []) { - // Confirm at least one, but no more than six, clockConfigs provided: - if (clocksInitialData.length > 6) { - // If too many clock keys, alert user and discard excess. - eLog.error("BladesClockKey", "[BladesClockKey.Create] Too many clock configs! (Max 6.) Eliminating extras.", clocksInitialData); - clocksInitialData = clocksInitialData.slice(0, 6); - } - else if (clocksInitialData.length === 0) { - // If no clocks provided, add one default clock. - clocksInitialData.push({}); - } - // Generate a local-only TargetLink instance, to assist in deriving values for the clocks data - const tempLink = new BladesTargetLink(config); - // Generate the targetKey or targetFlagKey for each clockData - if (tempLink.targetKeyPrefix) { - config.clocksData = Object.fromEntries(clocksInitialData - .map((cSchema, i) => { - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(cSchema), - index: i, - targetID: tempLink.targetID, - targetKey: `${tempLink.targetKeyPrefix}.clocksData`, - isScopingById: true - }); - return [ - cData.id, - cData - ]; - })); - } - else if (tempLink.targetFlagKeyPrefix) { - config.clocksData = Object.fromEntries(clocksInitialData - .map((cSchema, i) => { - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(cSchema), - targetID: tempLink.targetID, - targetFlagKey: `${tempLink.targetFlagKeyPrefix}.clocksData`, - isScopingById: true - }); - return [ - cData.id, - cData - ]; - })); - } - else { - throw new Error("BladesClockKey.Create: No targetKey or targetFlagKey provided."); - } - // Create and initialize the target link - const clockKeyLink = await super.Create(tempLink.data); - // Instantiate the ClockKey - const clockKey = new BladesClockKey(clockKeyLink.data); - // Render the clock key - clockKey.renderTargetAndKeeper(); - return clockKey; - } - static GetFromElement(elem) { - const keyElem$ = $(elem).closest(".clock-key-container").find(".clock-key"); - if (keyElem$.length === 0) { - return undefined; - } - const clockKeyID = keyElem$.attr("id"); - if (!clockKeyID) { - return undefined; - } - return game.eunoblades.ClockKeys.get(clockKeyID); - } - // #endregion - // #region GETTERS & SETTERS ~ - // #region -- Shortcut Schema Getters ~ - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { - this.updateTarget("name", val) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isVisible() { return this.data.isVisible; } - set isVisible(val) { - this.updateTarget("isVisible", U.pBool(val)) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isNameVisible() { return this.data.isNameVisible; } - set isNameVisible(val) { - this.updateTarget("isNameVisible", U.pBool(val)) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isSpotlit() { return this.data.isSpotlit; } - set isSpotlit(val) { - this.updateTarget("isSpotlit", val) - .then(() => { this.renderTargetAndKeeper(); }); - } - get clocksData() { return this.data.clocksData; } - get displayMode() { return this.data.displayMode; } - get oneKeyIndex() { - let { oneKeyIndex } = this.data; - if (!oneKeyIndex) { - oneKeyIndex = U.gsap.utils.random(0, 4, 1); - this.updateTarget("oneKeyIndex", oneKeyIndex) - .then(() => { this.renderTargetAndKeeper(); }); - } - return oneKeyIndex; - } - get sceneIDs() { return this.data.sceneIDs ?? []; } - get overlayPosition() { return this.data.overlayPosition?.[game.scenes.current.id]; } - set overlayPosition(val) { - if (val) { - this.updateTarget(`overlayPosition.${game.scenes.current.id}`, val) - .then(() => { this.renderTargetAndKeeper(); }); - } - else { - this.updateTarget(`overlayPosition.-=${game.scenes.current.id}`, null) - .then(() => { this.renderTargetAndKeeper(); }); - } - } - // #endregion - get clocks() { - return new Collection(Object.entries(this.clocksData) - .sort((a, b) => a[1].index - b[1].index) - .map(([id, data]) => { - return [id, new BladesClock(data)]; - })); - } - getClockByID(clockID) { - return this.clocks.get(clockID); - } - getClockByIndex(index) { - return this.clocks.find((clock) => clock.index === index); - } - get size() { return this.clocks.size; } - get isComplete() { - return Array.from(this.clocks).every((clock) => clock.isComplete); - } - get isClockKeeperKey() { - return this.target instanceof BladesClockKeeper; - } - get isFactionKey() { - return this.target instanceof BladesFaction; - } - get isProjectKey() { - return this.target instanceof BladesProject; - } - get isScoreKey() { - return this.target instanceof BladesScore; - } - get visibleClocks() { - return this.clocks.filter((clock) => clock.isVisible); - } - get activeClocks() { - return this.visibleClocks.filter((clock) => clock.isActive); - } - get inProgressClocks() { - return this.visibleClocks.filter((clock) => !clock.isComplete && clock.value > 0); - } - get unstartedClocks() { - return this.visibleClocks.filter((clock) => clock.value === 0); - } - get completedClocks() { - return this.visibleClocks.filter((clock) => clock.isComplete); - } - get currentClock() { - // If there are visible, active clocks that are not complete, return the earliest (by index property) - // active clock that is not complete. - if (this.activeClocks.length > 0) { - return this.getEarliestClock(this.activeClocks); - } - // Otherwise, if there are any visible, completed clocks, return the latest visible, completed clock - if (this.completedClocks.length > 0) { - return this.getLatestClock(this.completedClocks); - } - // Otherwise, if there are any visible clocks, return the earliest visible clock. - if (this.visibleClocks.length > 0) { - return this.getEarliestClock(this.visibleClocks); - } - // Finally, if all clocks are hidden, return the clock at index 0 - return this.getEarliestClock(Array.from(this.clocks)); - } - get fullDisplayPosData() { - const x = this.svgData.width / 2; - const y = this.svgData.height / 2; - return { - x, y, width: this.svgData.width, height: this.svgData.height - }; - } - get clocksDisplayPosData() { - return this.getClocksBoundingBox(Array.from(this.clocks)); - } - get visibleClocksDisplayPosData() { - return this.getClocksBoundingBox(this.visibleClocks); - } - get activeClocksDisplayPosData() { - return this.getClocksBoundingBox(this.activeClocks); - } - getClocksBoundingBox(clocks) { - const { size, ...allClocksPosData } = this.svgData.clocks; - // Filter 'allClocksPosData' to include only those entries with index properties of elements in 'clocks' - const clocksPosData = Object.fromEntries(Object.entries(allClocksPosData) - .filter(([index]) => clocks.map((clock) => clock.index).includes(U.pInt(index))) - .map(([index, posData]) => [U.pInt(index), posData])); - // Sort the values of clocksPosData by their positions - const clockWidthPosData = Object.values(clocksPosData).sort((a, b) => a.x - b.x); - const clockHeightPosData = Object.values(clocksPosData).sort((a, b) => a.y - b.y); - // Get the highest and lowest values for each set of positions - const xLowest = clockWidthPosData[0].x; - const xHighest = clockWidthPosData[clockWidthPosData.length - 1].x; - const yLowest = clockHeightPosData[0].y; - const yHighest = clockHeightPosData[clockHeightPosData.length - 1].y; - return { - // Determine the center point in both x and y axes - x: (xLowest + xHighest) / 2, - y: (yLowest + yHighest) / 2, - // Determine height and width of bounding box, accounting for clock size - width: xHighest - xLowest + size, - height: yHighest - yLowest + size - }; - } - /** This function accepts any number of arrays of BladesClock, then returns an array - * containing those BladesClock instances that appear in ALL provided arrays. - */ - getClocksIn(...clockArrays) { - if (clockArrays.length === 0) - return []; - return clockArrays.reduce((acc, currentArray) => { - return acc.filter((clock) => currentArray.includes(clock)); - }); - } - /** This function accepts an array of BladesClock, and returns the BladesClock - * instance with the lowest index property. - */ - getEarliestClock(clockArray) { - if (clockArray.length) { - return clockArray.sort((a, b) => a.index - b.index)[0]; - } - return undefined; - } - /** This function accepts an array of BladesClock, and returns the BladesClock - * instance with the highest index property. - */ - getLatestClock(clockArray) { - if (clockArray.length) { - return clockArray.sort((a, b) => b.index - a.index)[0]; - } - return undefined; - } - isInScene(sceneID = game.scenes.current.id) { - return this.sceneIDs.includes(sceneID); - } - get isInCurrentScene() { - return this.isInScene(game.scenes.current.id); - } - get displaySelectOptions() { - const options = [ - { value: ClockKeyDisplayMode.full, display: "Full Key" }, - { value: ClockKeyDisplayMode.clocks, display: "Clocks" }, - { value: ClockKeyDisplayMode.activeClocks, display: "Active Clocks" } - ]; - for (let i = 0; i < this.size; i++) { - options.push(...[ - { value: i, display: `Clock #${i}` }, - { value: `present${i}`, display: `Present Clock #${i}` } - ]); - } - return options; - } - constructor(dataOrConfig) { - super(dataOrConfig); - game.eunoblades.ClockKeys.set(this.id, this); - Object.values(dataOrConfig.clocksData ?? {}).forEach((clockData) => new BladesClock(clockData)); - } - // parseClockConfig(config: BladesClock.Config, indexOverride?: ClockIndex): BladesClock.Data { - // if (this.size === 6) {throw new Error("Cannot add a clock to a clock key with 6 clocks.");} - // if (indexOverride !== undefined && indexOverride < 0) {throw new Error("Cannot add a clock with a negative index.");} - // // Remove target so it doesn't conflict with key's targetID - // // delete config.target; - // const {target, targetID, targetKey, targetFlagKey, ...partialSchema} = config; - // const linkData: BladesTargetLink.LinkData = this.targetKey - // ? { - // targetID: this.targetID, - // targetKey: `${this.targetKeyPrefix}.clocksData` as TargetKey - // } - // : { - // targetID: this.targetID, - // targetFlagKey: `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey - // }; - // // Derive clock's targetID and targetKey/targetFlagKey from key's values - // data.targetID = this.targetID; - // if (this.targetKey) { - // data.targetKey = `${this.targetKeyPrefix}.clocksData` as TargetKey; - // } else if (this.targetFlagKey) { - // data.targetFlagKey = `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey; - // } - // // Assign 'parentKeyID' and 'index' - // config.parentKeyID = this.id; - // config.index = indexOverride ?? this.size; - // // Parse config to full data object - // return BladesClock.ApplySchemaDefaults( - // BladesClock.ParseConfigToData(config as BladesClock.Config) - // ); - // } - // #endregion - // #region HTML INTERACTION ~ - // #region Get Elements$ ~ - getElemFromDisplayContext(displayContext) { - let elem$; - const DOM$ = $(".vtt.game.system-eunos-blades"); - switch (displayContext) { - case ClockDisplayContext.overlay: { - elem$ = DOM$.find(`#blades-overlay #${this.id}`); - break; - } - case ClockDisplayContext.pcSheet: { - elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`); - break; - } - case ClockDisplayContext.factionSheet: { - elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`); - break; - } - case ClockDisplayContext.projectSheet: { - elem$ = DOM$.find(`.item.sheet .project #${this.id}`); - break; - } - case ClockDisplayContext.scoreSheet: { - elem$ = DOM$.find(`.item.sheet .score #${this.id}`); - break; - } - case ClockDisplayContext.rollCollab: { - elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`); - break; - } - case ClockDisplayContext.chatMessage: { - elem$ = DOM$.find(`#chat #${this.id}`); - break; - } - } - if (!elem$.length) { - throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`); - } - return elem$; - } - getElements$(displayContext) { - let elem$; - if (typeof displayContext === "string") { - displayContext = this.getElemFromDisplayContext(displayContext); - } - elem$ = $(displayContext).find(`#${this.id}`); - if (!elem$.length) { - elem$ = $(displayContext).closest(`#${this.id}`); - } - if (!elem$?.length) { - throw new Error(`[BladesClockKey.getElements$] Cannot find elements for display context '${displayContext}' of clockKey '${this.id}'.`); - } - // Using elem$ as a reference, locate relevant clock key elements and return them in a dictionary. - const keyElems$ = { - elem$ - }; - // Get elements that will be there regardless of context, throwing errors if not found. - // const container$ = elem$.closest(".clock-key-container"); - if (!elem$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error '.clock-key-container' not found for key '${this.id}'.`); - } - keyElems$.container$ = elem$.closest(".clock-key-container"); - const imgContainer$ = elem$.find(".key-image-container"); - if (!imgContainer$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error '.key-image-container' not found for key '${this.id}'.`); - } - keyElems$.imgContainer$ = imgContainer$; - const label$ = elem$.find(".key-label"); - if (!label$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error label$ not found for key '${this.id}'.`); - } - keyElems$.label$ = label$; - // Check for optional elements and silently exclude them from dictionary if not found. - const factionLabel$ = elem$.find(".faction-label"); - if (factionLabel$.length) { - keyElems$.factionLabel$ = factionLabel$; - } - const projectLabel$ = elem$.find(".project-label"); - if (projectLabel$.length) { - keyElems$.projectLabel$ = projectLabel$; - } - const scoreLabel$ = elem$.find(".score-label"); - if (scoreLabel$.length) { - keyElems$.scoreLabel$ = scoreLabel$; - } - // Register each clock under its id, retrieving the elements for each. - this.clocks.forEach((clock) => { - keyElems$.clocks ??= {}; - keyElems$.clocks[clock.id] = clock.getElements$(displayContext); - }); - eLog.checkLog3("BladesClockKey", "Clock Key Elements", keyElems$); - return keyElems$; - } - // #endregion - // #region Initial Rendering ~ - async renderTo(parentElem) { - const parent$ = $(parentElem); - if (!parent$.length) { - throw new Error(`[BladesClockKey.renderClockKeyTo] Error parent element not provided for key '${this.id}'.`); - } - // Render clock key template and append it to parent element - const clockKeyHTML = await renderTemplate("systems/eunos-blades/templates/components/clock-key.hbs", this); - $(clockKeyHTML).appendTo(parent$); - } - /** - * This function generates a partial GSAP.TweenVars object that will display the key in a given mode within the bounds of a provided container. - * - * @param {ClockKeyDisplayMode | number} [displayMode="full"] - The display mode. Options include: - * - "full" - displays the entire clock key - * - "clocks" - zooms in to display only the clocks - * - "activeClocks" - zooms in to the active clocks - * - "presentN" (where N is a clock index number) - zooms in to the clock at index N, and presents whichever side has the next available segment towards the camera. - * - A clock index number - zooms in to the clock at index N - * - * @param {HTMLElement | JQuery | {x: number, y: number, width: number, height: number}} [container$] - The container within which the key will be displayed. - * This can be: - * - An HTMLElement - * - A JQuery - * - A {x, y, width, height} position definition - * If not provided, it defaults to the clock key's container element (only if the key is already rendered in the DOM). - * - * @returns {gsap.TweenVars} - A partial GSAP.TweenVars object that describes how to display the key in the given mode within the bounds of the provided container. The returned object may include the following properties: - * - 'scale' (number): A multiple to be applied to scale at "full" display mode. - * - 'top' (number): A delta vertical shift from "full.js" display mode position. - * - 'left' (number): A delta horizontal shift from "full.js" display mode position. - * - 'transformOrigin': An absolute value. - * - 'rotationZ': An absolute value for the keySwing axis. - * - 'rotationY': An absolute value for rotation in/out of the screen. - * Any variables left undefined default to "full" display mode. - */ - getVarsForDisplayMode(keyElems$, displayMode = ClockKeyDisplayMode.full, container$) { - const keyTweenVars = {}; - const keyImgContTweenVars = {}; - container$ ??= keyElems$.container$; - // === TARGET CONTAINER ELEMENT === - // container$ refers to the element that the desired clocks will be made to fit within, and can be either an - // HTMLElement (or JQuery reference to such), or an Element Position object ({x, y, height, width}). - // We first convert any HTMLElements or JQuerys to an Element Position object: - let targetPosData; - if (container$ instanceof HTMLElement || container$ instanceof jQuery) { - const containerPosData = U.gsap.getProperty($(container$)[0]); - targetPosData = { - x: containerPosData("x"), - y: containerPosData("y"), - width: containerPosData("width"), - height: containerPosData("height") - }; - } - else if (isElemPosData(container$)) { - targetPosData = container$; - } - else { - throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error container$ '${container$}' is not a valid type.`); - } - // === TARGET FOCUS AREA === - // The focus area is the area of the key that we want to display in the container. - // This area is determined by the display mode, and may be the full key, the clocks, the active clocks, or a single clock. - // We will use this area to determine the scale and position of the key within the container. - let presentingClock; - let focusPosData; - switch (displayMode) { - case ClockKeyDisplayMode.full: { - focusPosData = { - x: this.svgData.width / 2, - y: this.svgData.height / 2, - width: this.svgData.width, - height: this.svgData.height - }; - break; - } - case ClockKeyDisplayMode.clocks: { - focusPosData = this.getClocksBoundingBox(Array.from(this.clocks)); - break; - } - case ClockKeyDisplayMode.activeClocks: { - focusPosData = this.getClocksBoundingBox(this.getClocksIn(this.activeClocks, this.visibleClocks)); - break; - } - case ClockKeyDisplayMode.presentCurrentClock: { - presentingClock = this.currentClock; - displayMode = presentingClock.index; - } - // falls through - default: { - if (typeof displayMode === "string" && displayMode.startsWith("present")) { - displayMode = U.pInt(displayMode.toString().slice(7)); - presentingClock = this.getClockByIndex(displayMode); - } - // Confirm that displayMode is an integer between 0 and this.size - if (!U.isInt(displayMode) || displayMode < 0 || displayMode >= this.size) { - throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error display mode '${displayMode}' is not a valid clock index for key '${this.id}'.`); - } - // Set focusPosData to the center of the clock, with width and height equal to size - const focusClockData = this.svgData.clocks[displayMode]; - focusPosData = { - x: focusClockData.x, - y: focusClockData.y, - width: this.svgData.clocks.size, - height: this.svgData.clocks.size - }; - break; - } - } - // === FIT FOCUS AREA INSIDE TARGET CONTAINER === - // Determine scale factor necessary to fit focusArea inside keyContainer - keyTweenVars.scale = Math.min(targetPosData.height / focusPosData.height, targetPosData.width / focusPosData.width); - // Determine top and left values for key-image-container, accounting for x/yPercent -50 - keyImgContTweenVars.top = (0.5 * C.ClockKeySquareSize) - focusPosData.y; - keyImgContTweenVars.left = (0.5 * C.ClockKeySquareSize) - focusPosData.x; - // Set transfer origin of key-image-container to same position, for further animation - keyImgContTweenVars.transformOrigin = `${focusPosData.x}px ${focusPosData.y}px`; - // Initialize rotation of key to 0 - keyImgContTweenVars.rotateY = 0; - // If 'isPresenting', - // ... rotate clock slightly towards camera - // ... increase scale of key - // ... shift key image container horizontally - if (presentingClock) { - keyTweenVars.scale *= 2; - if (presentingClock.getActiveSide() === "left") { - keyImgContTweenVars.rotateY = 30; - keyImgContTweenVars.left += this.size === 1 ? 45 : 25; - } - else if (presentingClock.getActiveSide() === "right") { - keyImgContTweenVars.rotateY = -30; - keyImgContTweenVars.left -= this.size === 1 ? 45 : 25; - } - } - return { keyTweenVars, keyImgContTweenVars }; - } - // public fitKeyToContainer( - // keyElems$: ClockKeyElems$, - // posOverrides?: Partial - // ) { - // const {container$, elem$, imgContainer$} = keyElems$; - // // Get position data for the container$ element (x, y, width, height) - // const keyPosition: ElemPosData = { - // x: U.gsap.getProperty(container$[0], "x") as number, - // y: U.gsap.getProperty(container$[0], "y") as number, - // width: U.gsap.getProperty(container$[0], "width") as number, - // height: U.gsap.getProperty(container$[0], "height") as number - // }; - // const {xShift, yShift, scaleMult, ...focusPosOverrides} = posOverrides ?? {}; - // const focusPosition: ElemPosData = { - // ...this.fullDisplayPosData, - // ...focusPosOverrides - // }; - // eLog.checkLog3("BladesClockKey", "[BladesClockKey] Key Positions", { - // keyPosition, - // focusPosition, - // widthScale: keyPosition.width / focusPosition.width, - // heightScale: keyPosition.height / focusPosition.height - // }); - // // Apply scale factor to elem$ to fit default key position inside container$ - // U.gsap.set(elem$, { - // scale: Math.min( - // keyPosition.width / focusPosition.width, - // keyPosition.height / focusPosition.height - // ) * (scaleMult ?? 1) - // }); - // // Apply top, left and transformOrigin value to keyImgContainer, accounting for x/yPercent -50 - // U.gsap.set(imgContainer$, { - // top: (0.5 * C.ClockKeySquareSize) - focusPosition.y + (yShift ?? 0), - // left: (0.5 * C.ClockKeySquareSize) - focusPosition.x + (xShift ?? 0), - // transformOrigin: `${focusPosition.x + (xShift ?? 0)}px ${focusPosition.y + (yShift ?? 0)}px` - // }); - // } - formatLabels(keyElems$) { - const { label$, clocks, factionLabel$, projectLabel$, scoreLabel$ } = keyElems$; - // Collect relevant label elements, desired aspect ratio, and maximum line count, then apply adjustments to the label container for a pleasing aspect ratio - [ - [label$, 2, 4], - factionLabel$ ? [factionLabel$, 2, 2] : undefined, - projectLabel$ ? [projectLabel$, 2, 2] : undefined, - scoreLabel$ ? [scoreLabel$, 2, 2] : undefined, - ...this.clocks.map((clock) => [clocks[clock.id].clockLabel$, 2.5, 3]) - ].filter(Boolean).forEach(([labelElem$, aspectRatio, maxLines]) => { - U.adjustTextContainerAspectRatio(labelElem$, aspectRatio, maxLines); - }); - } - setToDisplayMode(keyElems$, displayMode, isUpdatingTarget = true) { - const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode); - U.gsap.set(keyElems$.elem$, keyTweenVars); - U.gsap.set(keyElems$.imgContainer$, keyImgContTweenVars); - if (isUpdatingTarget && displayMode !== this.displayMode) { - this.updateTarget("displayMode", displayMode); - } - } - initElementsInContext(html, displayMode, isUpdatingTarget = true) { - const keyElems$ = this.getElements$(html); - displayMode ??= this.displayMode; - this.setToDisplayMode(keyElems$, displayMode, isUpdatingTarget); - this.formatLabels(keyElems$); - // If displayMode starts with 'present' or is an integer, fade out all label elements - if (displayMode.toString().startsWith("present") || Number.isInteger(displayMode)) { - U.gsap.to(keyElems$.container$.find(".clock-label, .clock-key-label"), { autoAlpha: 0, duration: 0 }); - } - return keyElems$; - } - // #endregion - async addToScene(sceneID = game.scenes.current.id) { - if (this.isInScene(sceneID)) { - return; - } - const { sceneIDs } = this; - sceneIDs.push(sceneID); - await this.updateTarget({ - isVisible: false, - sceneIDs - }); - this.renderTargetAndKeeper(); - } - async removeFromScene(sceneID = game.scenes.current.id) { - if (!this.isInScene(sceneID)) { - return; - } - const { sceneIDs } = this; - U.remove(sceneIDs, sceneID); - await this.updateTarget("sceneIDs", sceneIDs); - this.renderTargetAndKeeper(); - } - closeClockKey({ container$ }) { - container$.remove(); - } - get svgData() { - if (this.size === 0) { - throw new Error("[BladesClockKey.svgData] Error size is 0."); - } - const keyData = ClockKey_SVGDATA[this.size]; - let path; - if (this.size === 1 && keyData.paths) { - path = keyData.paths[this.oneKeyIndex]; - } - else if (keyData.path) { - path = keyData.path; - } - else { - throw new Error("[BladesClockKey.svgData] Error path is not defined."); - } - return { - width: keyData.width, - height: keyData.height, - path, - clocks: keyData.clocks - }; - } - isInOverlay(elem) { - return $(elem).hasClass(".overlay-section") || $(elem).closest(".overlay-section").length > 0; - } - get keyHeight() { return this.svgData.height; } - get keyWidth() { return this.svgData.width; } - get keyViewbox() { return `0 0 ${this.svgData.width} ${this.svgData.height}`; } - get keyPath() { return this.svgData.path; } - get clockSize() { return this.svgData.clocks.size; } - getClockPosition(clockIndex = 0) { - if (clockIndex > this.size) { - throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is greater than key size '${this.size}'.`); - } - if (clockIndex < 0) { - throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is less than 0.`); - } - return this.svgData.clocks[clockIndex]; - } - positionDragger; - removePositionDragger() { - this.positionDragger?.target.remove(); - this.positionDragger?.kill(); - delete this.positionDragger; - } - spawnPositionDragger(containerElem$ = game.eunoblades.Director.clockKeySection$) { - const self = this; - if (this.positionDragger) { - this.removePositionDragger(); - } - const dragElem$ = $(`
`) - .appendTo(containerElem$); - if (this.overlayPosition) { - dragElem$.css({ - left: this.overlayPosition.x, - top: this.overlayPosition.y - }); - } - this.positionDragger = new Dragger(dragElem$, { - type: "top,left", - onDragStart() { - $(this.target).css("background", "rgba(255, 255, 0, 0.25)"); - $(this.target).css("outlineColor", "rgba(255, 255, 0, 1)"); - }, - onDragEnd() { - $(this.target).css("background", "rgba(255, 0, 255, 0.25)"); - $(this.target).css("outlineColor", "rgba(255, 0, 255, 1)"); - self.overlayPosition = { x: this.endX, y: this.endY }; - } - }); - } - switchToMode(keyElems$, displayMode, extendKeyVars = {}, extendKeyContainerVars = {}, isUpdatingTarget = true, callback) { - const { elem$, imgContainer$ } = keyElems$; - const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode); - const currentDisplayMode = this.displayMode; - const randomID = U.gsap.utils.random(1, 1000, 1); - return U.gsap.timeline({ - callbackScope: this, - paused: true, - onStart() { - eLog.checkLog2("BladesClockKey", `switchToMode #${randomID} - START`, { key: this, keyElems$, displayMode }); - }, - onComplete() { - eLog.checkLog3("BladesClockKey", `switchToMode #${randomID} - COMPLETE`, { key: this, keyElems$, displayMode }); - if (isUpdatingTarget && displayMode !== this.currentDisplayMode) { - this.updateTarget("displayMode", displayMode) - .then(() => callback?.()); - } - else { - callback?.(); - } - }, - onReverseComplete() { - eLog.checkLog3("BladesClockKey", `switchToMode #${randomID} - REVERSE COMPLETE`, { key: this, keyElems$, displayMode }); - if (isUpdatingTarget) { - this.updateTarget("displayMode", currentDisplayMode); - } - } - }) - .to(elem$, { ...keyTweenVars, ...extendKeyVars }, 0) - .to(imgContainer$, { ...keyImgContTweenVars, ...extendKeyContainerVars }, 0); - } - // #endregion - // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls) - // #region > SOCKET CALLS: _SocketCall / static _SocketResponse / _Animation - fadeInName_Animation(keyElems$) { - if (!this.name) { - return undefined; - } - return U.gsap.effects.blurReveal(keyElems$.label$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeInName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeInName_SocketCall", displayContext, this.id); - } - static fadeInName_SocketResponse(displayContext, keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - key.fadeInName_Animation(key.getElements$(displayContext)); - } - fadeOutName_Animation(keyElems$) { - if (!this.name) { - return undefined; - } - return U.gsap.effects.blurRemove(keyElems$.label$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeOutName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - this.fadeOutName_Animation(this.getElements$(displayContext)); - socketlib.system.executeForOthers("fadeOutName_SocketCall", displayContext, this.id); - } - static fadeOutName_SocketResponse(displayContext, keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - key.fadeOutName_Animation(key.getElements$(displayContext)); - } - // #endregion - // #endregion - // #region Adding & Removing Clocks ~ - async updateClockIndices() { - await this.updateTarget("clocksData", Object.fromEntries(Object.entries(this.clocksData) - .map(([id, data], index) => [id, { ...data, index }]))); - return this.clocks; - } - async addClock(clockSchema = {}) { - // Derive clock data from config - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(clockSchema), - index: this.size, - targetID: this.targetID, - targetKey: `${this.targetKeyPrefix}.clocksData`, - isScopingById: true - }); - // const clockData = this.parseClockConfig(clockConfig); - // Write to state - await this.updateTarget(`clocksData.${cData.id}`, cData); - // Regnerate clocks collection - void this.clocks; - this.renderTargetAndKeeper(); - } - async deleteClock(clockID) { - if (this.size <= 1) { - throw new Error("[BladesClockKey.deleteClock()] Cannot reduce number of clocks below 1!"); - } - clockID ??= Array.from(this.clocks).pop()?.id; - if (!clockID) { - return; - } - await this.getClockByID(clockID)?.delete(); - await this.updateClockIndices(); - // Regenerate clocks collection - void this.clocks; - } - // #endregion - // #region OVERRIDES: Async Update Methods - renderTargetAndKeeper() { - this.renderTarget(); - game.eunoblades.ClockKeeper.sheet?.render(); - } - renderTarget() { - this.target.sheet?.render(); - } -} -class BladesClock extends BladesTargetLink { - // #region STATIC METHODS ~ - static ApplySchemaDefaults(schemaData) { - const namedValueMax = { - name: schemaData.name ?? "", - value: schemaData.value ?? 0, - max: schemaData.max ?? 8 - }; - return { - index: 0, - color: ClockColor.white, - isVisible: !U.isInt(schemaData.index) || schemaData.index === 0, - isNameVisible: false, - isHighlighted: false, - isActive: !U.isInt(schemaData.index) || schemaData.index === 0, - ...schemaData, - ...namedValueMax - }; - } - // #endregion - // #region GETTERS & SETTERS ~ - get canEdit() { - // return true if user has edit permissions on parent document, and clock is - // visible and active. - console.log("NOTE: All Clocks currently Editable; see line 71 of BladesClock.ts"); - return this.isVisible && this.isActive; - } - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { - this.updateTarget("name", val) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get value() { return U.pInt(this.data.value); } - set value(val) { - this.updateTarget("value", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get max() { return U.pInt(this.data.max); } - set max(val) { - this.updateTarget("max", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get color() { return this.data.color ?? ClockColor.white; } - set color(val) { - this.updateTarget("color", val) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isActive() { return U.pBool(this.data.isActive); } - set isActive(val) { - this.updateTarget("isActive", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get parentKey() { - const pKey = game.eunoblades.ClockKeys.get(this.data.parentKeyID); - if (!pKey) { - throw new Error(`[BladesClockKey.parentKey] No parent key found for clock ${this.id}`); - } - return pKey; - } - get isNameVisible() { return U.pBool(this.data.isNameVisible); } - set isNameVisible(val) { - this.updateTarget("isNameVisible", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isVisible() { return U.pBool(this.data.isVisible); } - set isVisible(val) { - this.updateTarget("isVisible", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isHighlighted() { return U.pBool(this.data.isHighlighted); } - set isHighlighted(val) { - this.updateTarget("isHighlighted", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get index() { return U.pInt(this.data.index); } - set index(val) { - this.updateTarget("index", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isEmpty() { return this.value === 0; } - get isComplete() { return this.value >= this.max; } - get rollOppClock() { return this; } - get rollOppName() { return this.name; } - get rollOppType() { return "clock"; } - get colorSelectOptions() { - return [ - { value: ClockColor.white, display: "🔘" }, - { value: ClockColor.yellow, display: "📀" }, - { value: ClockColor.cyan, display: "🔵" }, - { value: ClockColor.red, display: "🔴" } - ]; - } - get maxSelectOptions() { - return [ - { value: 2, display: 2 }, - { value: 3, display: 3 }, - { value: 4, display: 4 }, - { value: 5, display: 5 }, - { value: 6, display: 6 }, - { value: 8, display: 8 }, - { value: 10, display: 10 }, - { value: 12, display: 12 } - ]; - } - get valueSelectOptions() { - const returnVals = []; - for (let i = 0; i <= this.max; i++) { - returnVals.push({ value: i, display: i }); - } - return returnVals; - } - // Returns which hemisphere of the clock will show the final change if segmentDelta segments are added/removed. - getActiveSide(segmentDelta = 0) { - const finalClockValue = Math.min(this.max, Math.max(0, this.value + segmentDelta)); - const halfClockValue = this.max / 2; - if (segmentDelta === 0) { - return finalClockValue >= halfClockValue - ? "left" - : "right"; - } - return finalClockValue > halfClockValue - ? "left" - : "right"; - } - // #endregion - // #region HTML INTERACTION ~ - getElemFromDisplayContext(displayContext) { - let elem$; - const DOM$ = $(".vtt.game.system-eunos-blades"); - switch (displayContext) { - case ClockDisplayContext.overlay: { - elem$ = DOM$.find(`#blades-overlay #${this.id}`); - break; - } - case ClockDisplayContext.pcSheet: { - elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`); - break; - } - case ClockDisplayContext.factionSheet: { - elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`); - break; - } - case ClockDisplayContext.projectSheet: { - elem$ = DOM$.find(`.item.sheet .project #${this.id}`); - break; - } - case ClockDisplayContext.scoreSheet: { - elem$ = DOM$.find(`.item.sheet .score #${this.id}`); - break; - } - case ClockDisplayContext.rollCollab: { - elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`); - break; - } - case ClockDisplayContext.chatMessage: { - elem$ = DOM$.find(`#chat #${this.id}`); - break; - } - } - if (!elem$.length) { - throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`); - } - return elem$; - } - getElements$(displayContext) { - let elem$; - if (typeof displayContext === "string") { - displayContext = this.getElemFromDisplayContext(displayContext); - } - elem$ = $(displayContext).find(`#${this.id}`); - if (!elem$.length) { - elem$ = $(displayContext).closest(`#${this.id}`); - } - if (!elem$?.length) { - throw new Error(`[BladesClock.getElements$] Cannot find elements for display context '${displayContext}' of clock '${this.id}' of key '${this.parentKey.id}'.`); - } - // Using elem$ as a reference, locate relevant clock elements and return them in a dictionary. - const clockElems$ = { - clockElem$: elem$ - }; - // Get elements that will be there regardless of context, throwing errors if not found. - const container$ = elem$.closest(".clock-container"); - if (!container$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-container' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.clockContainer$ = container$; - const label$ = elem$.find(".clock-label"); - if (!label$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-label' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.clockLabel$ = label$; - const bg$ = elem$.find(".clock-bg"); - if (!bg$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-bg' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.bg$ = bg$; - const frame$ = elem$.find(".clock-frame"); - if (!frame$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-frame' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.frame$ = frame$; - const fill$ = elem$.find(".clock-fill"); - if (!fill$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-fill' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.fill$ = fill$; - const glow$ = elem$.find(".clock-glow"); - if (!glow$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-glow' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.glow$ = glow$; - const cover$ = elem$.find(".clock-cover"); - if (!cover$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-cover' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.cover$ = cover$; - const oneSegments$ = elem$.find(".clock-one-segment"); - if (oneSegments$.length !== 3) { - throw new Error(`[BladesClock.getElements$] Error '.clock-one-segment' elements not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.oneSegments$ = oneSegments$; - return clockElems$; - } - // #endregion - // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls) - reveal_Animation(clockElems$, callback) { - // Identify elements for fading in - const fadeInElements = [ - clockElems$.frame$, - clockElems$.fill$ - ].filter((el$) => el$ !== undefined); - // Construct timeline for revealing clock - const tl = U.gsap.timeline({ - callbackScope: this, - onComplete() { - callback?.(); - } - }); - // Fade out cover hiding clock - tl.to(clockElems$.cover$, { scale: 2, autoAlpha: 0, duration: 0.5, ease: "power2" }); - // Fade in clock elements - tl.fromTo(fadeInElements, { - autoAlpha: 0, - scale: 2 - }, { - autoAlpha: 1, - scale: 1, - duration: 0.5, - stagger: 0.2, - ease: "power2" - }); - // Fade in name, if name is visible. - if (this.name && this.isNameVisible) { - tl.blurReveal(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }, "<+0.05"); - } - // Fade in glow, if highlighted - if (this.isHighlighted) { - tl.scaleUpReveal(clockElems$.glow$, { - scale: 3, - duration: 0.5 - }, "<+0.05"); - } - if (this.isActive) { - tl.add(() => this.activate_Animation(clockElems$), "<+0.05"); - } - else { - tl.add(() => this.deactivate_Animation(clockElems$), "<+0.05"); - } - return tl; - } - async reveal_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("reveal_SocketCall", displayContext, this.parentKey.id, this.index); - } - static reveal_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - const clockElems$ = clock.getElements$(displayContext); - clock.reveal_Animation(clockElems$); - } - hide_Animation(clockElems$, callback) { - // Identify elements for fading out - const fadeOutElements = [ - clockElems$.frame$, - clockElems$.fill$ - ].filter((el$) => el$ !== undefined); - // Construct timeline for hiding clock - const tl = U.gsap.timeline({ - callbackScope: this, - onComplete() { - callback?.(); - } - }); - // Fade out clock elements - tl.to(fadeOutElements, { - autoAlpha: 0, - scale: 2, - duration: 0.5, - stagger: 0.2, - ease: "power2" - }); - // Fade out name, if name visible - if (this.name && this.isNameVisible) { - tl.blurRemove(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }, "<+0.05"); - } - // Fade out glow, if highlighted - if (this.isHighlighted) { - tl.scaleDownRemove(clockElems$.glow$, { - scale: 3, - duration: 0.5 - }, "<+0.05"); - } - // Fade in cover element - tl.to(clockElems$.cover$, { scale: 1, autoAlpha: 1, duration: 0.5, ease: "power2" }); - return tl; - } - async hide_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("hide_SocketCall", displayContext, this.parentKey.id, this.index); - } - static hide_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - const clockElems$ = clock.getElements$(displayContext); - clock.hide_Animation(clockElems$); - } - activate_Animation(clockElems$, callback) { - U.gsap.to(clockElems$.bg$, { autoAlpha: 1, duration: 0.5, ease: "power2" }); - U.gsap.to(clockElems$.frame$, { - filter: "brightness(0.5)", - duration: 0.5, - ease: "power2", - onComplete: callback - }); - } - async activate_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("activate_SocketCall", displayContext, this.parentKey.id, this.index); - } - static activate_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.activate_Animation(clock.getElements$(displayContext)); - } - deactivate_Animation(clockElems$, callback) { - U.gsap.to(clockElems$.bg$, { autoAlpha: 0, duration: 0.5, ease: "power2" }); - U.gsap.to(clockElems$.frame$, { - filter: "brightness(1) blur(5px)", - duration: 0.5, - ease: "power2", - onComplete: callback - }); - } - async deactivate_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("deactivate_SocketCall", displayContext, this.parentKey.id, this.index); - } - static deactivate_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.deactivate_Animation(clock.getElements$(displayContext)); - } - fadeInClockName_Animation(clockElems$) { - U.gsap.effects.blurReveal(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeInClockName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeInClockName_SocketCall", displayContext, this.parentKey.id, this.index); - } - static fadeInClockName_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.fadeInClockName_Animation(clock.getElements$(displayContext)); - } - fadeOutClockName_Animation(clockElems$) { - U.gsap.effects.blurRemove(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeOutClockName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeOutClockName_SocketCall", displayContext, this.parentKey.id, this.index); - } - static fadeOutClockName_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.fadeOutClockName_Animation(clock.getElements$(displayContext)); - } - highlight_Animation(clockElems$) { - U.gsap.effects.scaleUpReveal(clockElems$.glow$, { - duration: 0.5, - scale: 3 - }); - } - async highlight_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("highlight_SocketCall", displayContext, this.parentKey.id, this.index); - } - static highlight_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.highlight_Animation(clock.getElements$(displayContext)); - } - unhighlight_Animation(clockElems$) { - U.gsap.effects.scaleDownRemove(clockElems$.glow$, { - duration: 0.5, - scale: 3 - }); - } - async unhighlight_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("unhighlight_SocketCall", displayContext, this.parentKey.id, this.index); - } - static unhighlight_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.unhighlight_Animation(clock.getElements$(displayContext)); - } - getRotationOfSegment(segment) { - const stepSize = 360 / this.max; - return stepSize * (segment - 1); - } - initOneSegments(clockElems$, segmentNums, isReversing) { - if (segmentNums.length > 3) { - throw new Error(`Too many segments: [${segmentNums.join(", ")}]`); - } - // For each segment number, initialize a one-segment to that position, - // and initialize its autoAlpha depending on isReversing. - const oneSegs = [...clockElems$.oneSegments$]; - const oneSegsToAnimate = Array.from(clockElems$.oneSegments$).slice(0, segmentNums.length); - for (const segmentNum of segmentNums) { - const oneSegment = oneSegs.shift(); - U.gsap.set(oneSegment, { - rotation: this.getRotationOfSegment(segmentNum), - autoAlpha: isReversing ? 1 : 0 - }); - } - // If reversing, set clock element's value to the final value for proper clipping. - if (isReversing) { - clockElems$.clockElem$.attr("data-value", U.getLast(segmentNums) - 1); - } - return oneSegsToAnimate; - } - changeSegments_Animation(clockElems$, startVal, endVal, callback) { - startVal = U.gsap.utils.clamp(0, this.max, startVal); - endVal = U.gsap.utils.clamp(0, this.max, endVal); - let delta = endVal - startVal; - if (delta === 0) { - return; - } - // Determine position and sequence of one-segments - const segmentNums = []; - if (delta < 0) { - while (Math.abs(delta) > startVal) { - delta++; - } - for (let i = startVal; i > endVal; i--) { - segmentNums.push(i); - } - } - else { - while (endVal > this.max) { - delta--; - } - for (let i = startVal + 1; i <= endVal; i++) { - segmentNums.push(i); - } - } - // Initialize oneSegments at determined positions - const segmentsToAnimate = this.initOneSegments(clockElems$, segmentNums, startVal > endVal); - eLog.checkLog3("BladesClock", "changeSegments_Animation", { clockElems$, delta, segmentNums, startVal, endVal, segmentsToAnimate }); - // Initialize master timeline - const tl = U.gsap.timeline(); - // Enlarge clock key and focus clock - // const clockFocusTimeline: gsap.core.Timeline = this.parentKey.getClockFocusTimeline(this.index); - // tl.add(clockFocusTimeline); - // Animate one-segments - if (delta > 0) { - tl.fromTo(segmentsToAnimate, { - autoAlpha: 0, - scale: 2 - }, { - autoAlpha: 1, - scale: 1, - duration: 0.5, - stagger: 0.2, - ease: "power2", - callbackScope: this, - onComplete() { - clockElems$.clockElem$.attr("data-value", endVal); - U.gsap.to(segmentsToAnimate, { - autoAlpha: 0, - duration: 0.5, - stagger: 0.2 - // onComplete() { - // // Return clock key to original size and focus - // clockFocusTimeline.reverse(); - // } - }); - } - }); - } - else { - tl.fromTo(segmentsToAnimate, { - autoAlpha: 1, - scale: 1 - }, { - autoAlpha: 0, - scale: 2, - duration: 0.5, - stagger: 0.2, - ease: "power2" - // onComplete() { - // // Return clock key to original size and focus - // clockFocusTimeline.reverse(); - // } - }); - } - return tl; - } - async changeSegments_SocketCall(displayContext, startVal, endVal) { - if (!game.user.isGM) { - return; - } - startVal = U.gsap.utils.clamp(0, this.max, startVal); - endVal = U.gsap.utils.clamp(0, this.max, endVal); - socketlib.system.executeForEveryone("changeSegments_SocketCall", displayContext, this.parentKey.id, this.index, startVal, endVal); - } - static changeSegments_SocketResponse(displayContext, keyID, index, startVal, endVal) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.changeSegments_Animation(clock.getElements$(displayContext), startVal, endVal); - } - // #endregion - // #region Adding/Removing Clock Segments ~ - // Returns number of segments beyond max (or 0, if max not met) - async fillSegments(count, isSilent = false) { - // Amount added beyond max: - const clockOverflow = Math.max(0, this.value + count - this.max); - // Clamp count to max: - count = Math.min(this.value + count, this.max) - this.value; - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value + count); - if (!isSilent) { - this.parentKey.renderTargetAndKeeper(); - } - return clockOverflow; - } - // Returns (positive) number of segments removed - // in excess of the number of segments in the clock - async clearSegments(count, isSilent = false) { - // Amount removed beyond 0: - const clockOverflow = Math.max(0, count - this.value); - // Clamp count to min: - count = Math.min(this.value, count); - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value - count); - if (!isSilent) { - this.parentKey.renderTargetAndKeeper(); - } - return clockOverflow; - } - async delete() { - const { parentKey } = this; - await super.delete(false); - parentKey.updateClockIndices(); - } -} -export default BladesClockKey; -export { BladesClock }; diff --git a/module/classes/BladesClocks.js b/module/classes/BladesClocks.js deleted file mode 100644 index c600e5c1..00000000 --- a/module/classes/BladesClocks.js +++ /dev/null @@ -1,1534 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { ClockKey_SVGDATA, ClockDisplayContext, BladesActorType, BladesItemType, ClockColor, ClockKeyDisplayMode } from "../core/constants.js"; -import { Dragger } from "../core/gsap.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -import U from "../core/utilities.js"; -import { BladesActor, BladesFaction } from "../documents/BladesActorProxy.js"; -import { BladesItem, BladesClockKeeper, BladesProject, BladesScore } from "../documents/BladesItemProxy.js"; -function isElemPosData(obj) { - return U.isList(obj) - && typeof obj.x === "number" - && typeof obj.y === "number" - && typeof obj.width === "number" - && typeof obj.height === "number"; -} -class BladesClockKey extends BladesTargetLink { - // #region STATIC METHODS ~ - static Initialize() { - function registerClockKeys(doc) { - if ("clocksData" in doc.system) { - Object.values(doc.system.clocksData ?? {}) - .forEach((keyData) => { - try { - new BladesClockKey(keyData); - } - catch (err) { - eLog.error("BladesClockKey", "[BladesClockKey.Initialize] Error initializing clock key.", err, keyData); - } - }); - } - } - game.items.contents - .filter((item) => BladesItem.IsType(item, BladesItemType.clock_keeper, BladesItemType.project, BladesItemType.cohort_gang, BladesItemType.cohort_expert, BladesItemType.ritual, BladesItemType.design, BladesItemType.location, BladesItemType.score)) - .forEach(registerClockKeys); - game.actors.contents - .filter((actor) => BladesActor.IsType(actor, BladesActorType.pc, BladesActorType.faction)) - .forEach(registerClockKeys); - return loadTemplates([ - "systems/eunos-blades/templates/components/clock-key.hbs", - "systems/eunos-blades/templates/components/clock.hbs" - ]); - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - return { - name: "", - isVisible: false, - isNameVisible: false, - isSpotlit: false, - clocksData: {}, - sceneIDs: [], - displayMode: ClockKeyDisplayMode.full, - oneKeyIndex: U.gsap.utils.random(0, 4, 1), - ...schemaData - }; - } - static async Create(config, _parentLinkData, clocksInitialData = []) { - // Confirm at least one, but no more than six, clockConfigs provided: - if (clocksInitialData.length > 6) { - // If too many clock keys, alert user and discard excess. - eLog.error("BladesClockKey", "[BladesClockKey.Create] Too many clock configs! (Max 6.) Eliminating extras.", clocksInitialData); - clocksInitialData = clocksInitialData.slice(0, 6); - } - else if (clocksInitialData.length === 0) { - // If no clocks provided, add one default clock. - clocksInitialData.push({}); - } - // Generate a local-only TargetLink instance, to assist in deriving values for the clocks data - const tempLink = new BladesTargetLink(config); - // Generate the targetKey or targetFlagKey for each clockData - if (tempLink.targetKeyPrefix) { - config.clocksData = Object.fromEntries(clocksInitialData - .map((cSchema, i) => { - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(cSchema), - index: i, - targetID: tempLink.targetID, - targetKey: `${tempLink.targetKeyPrefix}.clocksData`, - isScopingById: true - }); - return [ - cData.id, - cData - ]; - })); - } - else if (tempLink.targetFlagKeyPrefix) { - config.clocksData = Object.fromEntries(clocksInitialData - .map((cSchema, i) => { - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(cSchema), - targetID: tempLink.targetID, - targetFlagKey: `${tempLink.targetFlagKeyPrefix}.clocksData`, - isScopingById: true - }); - return [ - cData.id, - cData - ]; - })); - } - else { - throw new Error("BladesClockKey.Create: No targetKey or targetFlagKey provided."); - } - // Create and initialize the target link - const clockKeyLink = await super.Create(tempLink.data); - // Instantiate the ClockKey - const clockKey = new BladesClockKey(clockKeyLink.data); - // Render the clock key - clockKey.renderTargetAndKeeper(); - return clockKey; - } - static GetFromElement(elem) { - const keyElem$ = $(elem).closest(".clock-key-container").find(".clock-key"); - if (keyElem$.length === 0) { - return undefined; - } - const clockKeyID = keyElem$.attr("id"); - if (!clockKeyID) { - return undefined; - } - return game.eunoblades.ClockKeys.get(clockKeyID); - } - // #endregion - // #region GETTERS & SETTERS ~ - // #region -- Shortcut Schema Getters ~ - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { - this.updateTarget("name", val) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isVisible() { return this.data.isVisible; } - set isVisible(val) { - this.updateTarget("isVisible", U.pBool(val)) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isNameVisible() { return this.data.isNameVisible; } - set isNameVisible(val) { - this.updateTarget("isNameVisible", U.pBool(val)) - .then(() => { this.renderTargetAndKeeper(); }); - } - get isSpotlit() { return this.data.isSpotlit; } - set isSpotlit(val) { - this.updateTarget("isSpotlit", val) - .then(() => { this.renderTargetAndKeeper(); }); - } - get clocksData() { return this.data.clocksData; } - get displayMode() { return this.data.displayMode; } - get oneKeyIndex() { - let { oneKeyIndex } = this.data; - if (!oneKeyIndex) { - oneKeyIndex = U.gsap.utils.random(0, 4, 1); - this.updateTarget("oneKeyIndex", oneKeyIndex) - .then(() => { this.renderTargetAndKeeper(); }); - } - return oneKeyIndex; - } - get sceneIDs() { return this.data.sceneIDs ?? []; } - get overlayPosition() { return this.data.overlayPosition?.[game.scenes.current.id]; } - set overlayPosition(val) { - if (val) { - this.updateTarget(`overlayPosition.${game.scenes.current.id}`, val) - .then(() => { this.renderTargetAndKeeper(); }); - } - else { - this.updateTarget(`overlayPosition.-=${game.scenes.current.id}`, null) - .then(() => { this.renderTargetAndKeeper(); }); - } - } - // #endregion - get clocks() { - return new Collection(Object.entries(this.clocksData) - .sort((a, b) => a[1].index - b[1].index) - .map(([id, data]) => { - return [id, new BladesClock(data)]; - })); - } - getClockByID(clockID) { - return this.clocks.get(clockID); - } - getClockByIndex(index) { - return this.clocks.find((clock) => clock.index === index); - } - get size() { return this.clocks.size; } - get isComplete() { - return Array.from(this.clocks).every((clock) => clock.isComplete); - } - get isClockKeeperKey() { - return this.target instanceof BladesClockKeeper; - } - get isFactionKey() { - return this.target instanceof BladesFaction; - } - get isProjectKey() { - return this.target instanceof BladesProject; - } - get isScoreKey() { - return this.target instanceof BladesScore; - } - get visibleClocks() { - return this.clocks.filter((clock) => clock.isVisible); - } - get activeClocks() { - return this.visibleClocks.filter((clock) => clock.isActive); - } - get inProgressClocks() { - return this.visibleClocks.filter((clock) => !clock.isComplete && clock.value > 0); - } - get unstartedClocks() { - return this.visibleClocks.filter((clock) => clock.value === 0); - } - get completedClocks() { - return this.visibleClocks.filter((clock) => clock.isComplete); - } - get currentClock() { - // If there are visible, active clocks that are not complete, return the earliest (by index property) - // active clock that is not complete. - if (this.activeClocks.length > 0) { - return this.getEarliestClock(this.activeClocks); - } - // Otherwise, if there are any visible, completed clocks, return the latest visible, completed clock - if (this.completedClocks.length > 0) { - return this.getLatestClock(this.completedClocks); - } - // Otherwise, if there are any visible clocks, return the earliest visible clock. - if (this.visibleClocks.length > 0) { - return this.getEarliestClock(this.visibleClocks); - } - // Finally, if all clocks are hidden, return the clock at index 0 - return this.getEarliestClock(Array.from(this.clocks)); - } - get fullDisplayPosData() { - const x = this.svgData.width / 2; - const y = this.svgData.height / 2; - return { - x, y, width: this.svgData.width, height: this.svgData.height - }; - } - get clocksDisplayPosData() { - return this.getClocksBoundingBox(Array.from(this.clocks)); - } - get visibleClocksDisplayPosData() { - return this.getClocksBoundingBox(this.visibleClocks); - } - get activeClocksDisplayPosData() { - return this.getClocksBoundingBox(this.activeClocks); - } - getClocksBoundingBox(clocks) { - const { size, ...allClocksPosData } = this.svgData.clocks; - // Filter 'allClocksPosData' to include only those entries with index properties of elements in 'clocks' - const clocksPosData = Object.fromEntries(Object.entries(allClocksPosData) - .filter(([index]) => clocks.map((clock) => clock.index).includes(U.pInt(index))) - .map(([index, posData]) => [U.pInt(index), posData])); - // Sort the values of clocksPosData by their positions - const clockWidthPosData = Object.values(clocksPosData).sort((a, b) => a.x - b.x); - const clockHeightPosData = Object.values(clocksPosData).sort((a, b) => a.y - b.y); - // Get the highest and lowest values for each set of positions - const xLowest = clockWidthPosData[0].x; - const xHighest = clockWidthPosData[clockWidthPosData.length - 1].x; - const yLowest = clockHeightPosData[0].y; - const yHighest = clockHeightPosData[clockHeightPosData.length - 1].y; - return { - // Determine the center point in both x and y axes - x: (xLowest + xHighest) / 2, - y: (yLowest + yHighest) / 2, - // Determine height and width of bounding box, accounting for clock size - width: xHighest - xLowest + size, - height: yHighest - yLowest + size - }; - } - /** This function accepts any number of arrays of BladesClock, then returns an array - * containing those BladesClock instances that appear in ALL provided arrays. - */ - getClocksIn(...clockArrays) { - if (clockArrays.length === 0) - return []; - return clockArrays.reduce((acc, currentArray) => { - return acc.filter((clock) => currentArray.includes(clock)); - }); - } - /** This function accepts an array of BladesClock, and returns the BladesClock - * instance with the lowest index property. - */ - getEarliestClock(clockArray) { - if (clockArray.length) { - return clockArray.sort((a, b) => a.index - b.index)[0]; - } - return undefined; - } - /** This function accepts an array of BladesClock, and returns the BladesClock - * instance with the highest index property. - */ - getLatestClock(clockArray) { - if (clockArray.length) { - return clockArray.sort((a, b) => b.index - a.index)[0]; - } - return undefined; - } - isInScene(sceneID = game.scenes.current.id) { - return this.sceneIDs.includes(sceneID); - } - get isInCurrentScene() { - return this.isInScene(game.scenes.current.id); - } - get displaySelectOptions() { - const options = [ - { value: ClockKeyDisplayMode.full, display: "Full Key" }, - { value: ClockKeyDisplayMode.clocks, display: "Clocks" }, - { value: ClockKeyDisplayMode.activeClocks, display: "Active Clocks" } - ]; - for (let i = 0; i < this.size; i++) { - options.push(...[ - { value: i, display: `Clock #${i}` }, - { value: `present${i}`, display: `Present Clock #${i}` } - ]); - } - return options; - } - constructor(dataOrConfig) { - super(dataOrConfig); - game.eunoblades.ClockKeys.set(this.id, this); - Object.values(dataOrConfig.clocksData ?? {}).forEach((clockData) => new BladesClock(clockData)); - } - // parseClockConfig(config: BladesClock.Config, indexOverride?: ClockIndex): BladesClock.Data { - // if (this.size === 6) {throw new Error("Cannot add a clock to a clock key with 6 clocks.");} - // if (indexOverride !== undefined && indexOverride < 0) {throw new Error("Cannot add a clock with a negative index.");} - // // Remove target so it doesn't conflict with key's targetID - // // delete config.target; - // const {target, targetID, targetKey, targetFlagKey, ...partialSchema} = config; - // const linkData: BladesTargetLink.LinkData = this.targetKey - // ? { - // targetID: this.targetID, - // targetKey: `${this.targetKeyPrefix}.clocksData` as TargetKey - // } - // : { - // targetID: this.targetID, - // targetFlagKey: `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey - // }; - // // Derive clock's targetID and targetKey/targetFlagKey from key's values - // data.targetID = this.targetID; - // if (this.targetKey) { - // data.targetKey = `${this.targetKeyPrefix}.clocksData` as TargetKey; - // } else if (this.targetFlagKey) { - // data.targetFlagKey = `${this.targetFlagKeyPrefix}.clocksData` as TargetFlagKey; - // } - // // Assign 'parentKeyID' and 'index' - // config.parentKeyID = this.id; - // config.index = indexOverride ?? this.size; - // // Parse config to full data object - // return BladesClock.ApplySchemaDefaults( - // BladesClock.ParseConfigToData(config as BladesClock.Config) - // ); - // } - // #endregion - // #region HTML INTERACTION ~ - // #region Get Elements$ ~ - getElemFromDisplayContext(displayContext) { - let elem$; - const DOM$ = $(".vtt.game.system-eunos-blades"); - switch (displayContext) { - case ClockDisplayContext.overlay: { - elem$ = DOM$.find(`#blades-overlay #${this.id}`); - break; - } - case ClockDisplayContext.pcSheet: { - elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`); - break; - } - case ClockDisplayContext.factionSheet: { - elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`); - break; - } - case ClockDisplayContext.projectSheet: { - elem$ = DOM$.find(`.item.sheet .project #${this.id}`); - break; - } - case ClockDisplayContext.scoreSheet: { - elem$ = DOM$.find(`.item.sheet .score #${this.id}`); - break; - } - case ClockDisplayContext.rollCollab: { - elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`); - break; - } - case ClockDisplayContext.chatMessage: { - elem$ = DOM$.find(`#chat #${this.id}`); - break; - } - } - if (!elem$.length) { - throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`); - } - return elem$; - } - getElements$(displayContext) { - let elem$; - if (typeof displayContext === "string") { - displayContext = this.getElemFromDisplayContext(displayContext); - } - elem$ = $(displayContext).find(`#${this.id}`); - if (!elem$.length) { - elem$ = $(displayContext).closest(`#${this.id}`); - } - if (!elem$?.length) { - throw new Error(`[BladesClockKey.getElements$] Cannot find elements for display context '${displayContext}' of clockKey '${this.id}'.`); - } - // Using elem$ as a reference, locate relevant clock key elements and return them in a dictionary. - const keyElems$ = { - elem$ - }; - // Get elements that will be there regardless of context, throwing errors if not found. - // const container$ = elem$.closest(".clock-key-container"); - if (!elem$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error '.clock-key-container' not found for key '${this.id}'.`); - } - keyElems$.container$ = elem$.closest(".clock-key-container"); - const imgContainer$ = elem$.find(".key-image-container"); - if (!imgContainer$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error '.key-image-container' not found for key '${this.id}'.`); - } - keyElems$.imgContainer$ = imgContainer$; - const label$ = elem$.find(".key-label"); - if (!label$.length) { - throw new Error(`[BladesClockKey.renderClockKey] Error label$ not found for key '${this.id}'.`); - } - keyElems$.label$ = label$; - // Check for optional elements and silently exclude them from dictionary if not found. - const factionLabel$ = elem$.find(".faction-label"); - if (factionLabel$.length) { - keyElems$.factionLabel$ = factionLabel$; - } - const projectLabel$ = elem$.find(".project-label"); - if (projectLabel$.length) { - keyElems$.projectLabel$ = projectLabel$; - } - const scoreLabel$ = elem$.find(".score-label"); - if (scoreLabel$.length) { - keyElems$.scoreLabel$ = scoreLabel$; - } - // Register each clock under its id, retrieving the elements for each. - this.clocks.forEach((clock) => { - keyElems$.clocks ??= {}; - keyElems$.clocks[clock.id] = clock.getElements$(displayContext); - }); - eLog.checkLog3("BladesClockKey", "Clock Key Elements", keyElems$); - return keyElems$; - } - // #endregion - // #region Initial Rendering ~ - async renderTo(parentElem) { - const parent$ = $(parentElem); - if (!parent$.length) { - throw new Error(`[BladesClockKey.renderClockKeyTo] Error parent element not provided for key '${this.id}'.`); - } - // Render clock key template and append it to parent element - const clockKeyHTML = await renderTemplate("systems/eunos-blades/templates/components/clock-key.hbs", this); - $(clockKeyHTML).appendTo(parent$); - } - /** - * This function generates a partial GSAP.TweenVars object that will display the key in a given mode within the bounds of a provided container. - * - * @param {ClockKeyDisplayMode | number} [displayMode="full"] - The display mode. Options include: - * - "full" - displays the entire clock key - * - "clocks" - zooms in to display only the clocks - * - "activeClocks" - zooms in to the active clocks - * - "presentN" (where N is a clock index number) - zooms in to the clock at index N, and presents whichever side has the next available segment towards the camera. - * - A clock index number - zooms in to the clock at index N - * - * @param {HTMLElement | JQuery | {x: number, y: number, width: number, height: number}} [container$] - The container within which the key will be displayed. - * This can be: - * - An HTMLElement - * - A JQuery - * - A {x, y, width, height} position definition - * If not provided, it defaults to the clock key's container element (only if the key is already rendered in the DOM). - * - * @returns {gsap.TweenVars} - A partial GSAP.TweenVars object that describes how to display the key in the given mode within the bounds of the provided container. The returned object may include the following properties: - * - 'scale' (number): A multiple to be applied to scale at "full" display mode. - * - 'top' (number): A delta vertical shift from "full.js" display mode position. - * - 'left' (number): A delta horizontal shift from "full.js" display mode position. - * - 'transformOrigin': An absolute value. - * - 'rotationZ': An absolute value for the keySwing axis. - * - 'rotationY': An absolute value for rotation in/out of the screen. - * Any variables left undefined default to "full" display mode. - */ - getVarsForDisplayMode(keyElems$, displayMode = ClockKeyDisplayMode.full, container$) { - const keyTweenVars = {}; - const keyImgContTweenVars = {}; - container$ ??= keyElems$.container$; - // === TARGET CONTAINER ELEMENT === - // container$ refers to the element that the desired clocks will be made to fit within, and can be either an - // HTMLElement (or JQuery reference to such), or an Element Position object ({x, y, height, width}). - // We first convert any HTMLElements or JQuerys to an Element Position object: - let targetPosData; - if (container$ instanceof HTMLElement || container$ instanceof jQuery) { - const containerPosData = U.gsap.getProperty($(container$)[0]); - targetPosData = { - x: containerPosData("x"), - y: containerPosData("y"), - width: containerPosData("width"), - height: containerPosData("height") - }; - } - else if (isElemPosData(container$)) { - targetPosData = container$; - } - else { - throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error container$ '${container$}' is not a valid type.`); - } - // === TARGET FOCUS AREA === - // The focus area is the area of the key that we want to display in the container. - // This area is determined by the display mode, and may be the full key, the clocks, the active clocks, or a single clock. - // We will use this area to determine the scale and position of the key within the container. - let presentingClock; - let focusPosData; - switch (displayMode) { - case ClockKeyDisplayMode.full: { - focusPosData = { - x: this.svgData.width / 2, - y: this.svgData.height / 2, - width: this.svgData.width, - height: this.svgData.height - }; - break; - } - case ClockKeyDisplayMode.clocks: { - focusPosData = this.getClocksBoundingBox(Array.from(this.clocks)); - break; - } - case ClockKeyDisplayMode.activeClocks: { - focusPosData = this.getClocksBoundingBox(this.getClocksIn(this.activeClocks, this.visibleClocks)); - break; - } - case ClockKeyDisplayMode.presentCurrentClock: { - presentingClock = this.currentClock; - displayMode = presentingClock.index; - } - // falls through - default: { - if (typeof displayMode === "string" && displayMode.startsWith("present")) { - displayMode = U.pInt(displayMode.toString().slice(7)); - presentingClock = this.getClockByIndex(displayMode); - } - // Confirm that displayMode is an integer between 0 and this.size - if (!U.isInt(displayMode) || displayMode < 0 || displayMode >= this.size) { - throw new Error(`[BladesClockKey.getVarsForDisplayMode] Error display mode '${displayMode}' is not a valid clock index for key '${this.id}'.`); - } - // Set focusPosData to the center of the clock, with width and height equal to size - const focusClockData = this.svgData.clocks[displayMode]; - focusPosData = { - x: focusClockData.x, - y: focusClockData.y, - width: this.svgData.clocks.size, - height: this.svgData.clocks.size - }; - break; - } - } - // === FIT FOCUS AREA INSIDE TARGET CONTAINER === - // Determine scale factor necessary to fit focusArea inside keyContainer - keyTweenVars.scale = Math.min(targetPosData.height / focusPosData.height, targetPosData.width / focusPosData.width); - // Determine top and left values for key-image-container, accounting for x/yPercent -50 - keyImgContTweenVars.top = (0.5 * C.ClockKeySquareSize) - focusPosData.y; - keyImgContTweenVars.left = (0.5 * C.ClockKeySquareSize) - focusPosData.x; - // Set transfer origin of key-image-container to same position, for further animation - keyImgContTweenVars.transformOrigin = `${focusPosData.x}px ${focusPosData.y}px`; - // Initialize rotation of key to 0 - keyImgContTweenVars.rotateY = 0; - // If 'isPresenting', - // ... rotate clock slightly towards camera - // ... increase scale of key - // ... shift key image container horizontally - if (presentingClock) { - keyTweenVars.scale *= 2; - if (presentingClock.getActiveSide() === "left") { - keyImgContTweenVars.rotateY = 30; - keyImgContTweenVars.left += this.size === 1 ? 45 : 25; - } - else if (presentingClock.getActiveSide() === "right") { - keyImgContTweenVars.rotateY = -30; - keyImgContTweenVars.left -= this.size === 1 ? 45 : 25; - } - } - return { keyTweenVars, keyImgContTweenVars }; - } - // public fitKeyToContainer( - // keyElems$: ClockKeyElems$, - // posOverrides?: Partial - // ) { - // const {container$, elem$, imgContainer$} = keyElems$; - // // Get position data for the container$ element (x, y, width, height) - // const keyPosition: ElemPosData = { - // x: U.gsap.getProperty(container$[0], "x") as number, - // y: U.gsap.getProperty(container$[0], "y") as number, - // width: U.gsap.getProperty(container$[0], "width") as number, - // height: U.gsap.getProperty(container$[0], "height") as number - // }; - // const {xShift, yShift, scaleMult, ...focusPosOverrides} = posOverrides ?? {}; - // const focusPosition: ElemPosData = { - // ...this.fullDisplayPosData, - // ...focusPosOverrides - // }; - // eLog.checkLog3("BladesClockKey", "[BladesClockKey] Key Positions", { - // keyPosition, - // focusPosition, - // widthScale: keyPosition.width / focusPosition.width, - // heightScale: keyPosition.height / focusPosition.height - // }); - // // Apply scale factor to elem$ to fit default key position inside container$ - // U.gsap.set(elem$, { - // scale: Math.min( - // keyPosition.width / focusPosition.width, - // keyPosition.height / focusPosition.height - // ) * (scaleMult ?? 1) - // }); - // // Apply top, left and transformOrigin value to keyImgContainer, accounting for x/yPercent -50 - // U.gsap.set(imgContainer$, { - // top: (0.5 * C.ClockKeySquareSize) - focusPosition.y + (yShift ?? 0), - // left: (0.5 * C.ClockKeySquareSize) - focusPosition.x + (xShift ?? 0), - // transformOrigin: `${focusPosition.x + (xShift ?? 0)}px ${focusPosition.y + (yShift ?? 0)}px` - // }); - // } - formatLabels(keyElems$) { - const { label$, clocks, factionLabel$, projectLabel$, scoreLabel$ } = keyElems$; - // Collect relevant label elements, desired aspect ratio, and maximum line count, then apply adjustments to the label container for a pleasing aspect ratio - [ - [label$, 2, 4], - factionLabel$ ? [factionLabel$, 2, 2] : undefined, - projectLabel$ ? [projectLabel$, 2, 2] : undefined, - scoreLabel$ ? [scoreLabel$, 2, 2] : undefined, - ...this.clocks.map((clock) => [clocks[clock.id].clockLabel$, 2.5, 3]) - ].filter(Boolean).forEach(([labelElem$, aspectRatio, maxLines]) => { - U.adjustTextContainerAspectRatio(labelElem$, aspectRatio, maxLines); - }); - } - setToDisplayMode(keyElems$, displayMode, isUpdatingTarget = true) { - const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode); - U.gsap.set(keyElems$.elem$, keyTweenVars); - U.gsap.set(keyElems$.imgContainer$, keyImgContTweenVars); - if (isUpdatingTarget && displayMode !== this.displayMode) { - this.updateTarget("displayMode", displayMode); - } - } - initElementsInContext(html, displayMode, isUpdatingTarget = true) { - const keyElems$ = this.getElements$(html); - displayMode ??= this.displayMode; - this.setToDisplayMode(keyElems$, displayMode, isUpdatingTarget); - this.formatLabels(keyElems$); - // If displayMode starts with 'present' or is an integer, fade out all label elements - if (displayMode.toString().startsWith("present") || Number.isInteger(displayMode)) { - U.gsap.to(keyElems$.container$.find(".clock-label, .clock-key-label"), { autoAlpha: 0, duration: 0 }); - } - return keyElems$; - } - // #endregion - async addToScene(sceneID = game.scenes.current.id) { - if (this.isInScene(sceneID)) { - return; - } - const { sceneIDs } = this; - sceneIDs.push(sceneID); - await this.updateTarget({ - isVisible: false, - sceneIDs - }); - this.renderTargetAndKeeper(); - } - async removeFromScene(sceneID = game.scenes.current.id) { - if (!this.isInScene(sceneID)) { - return; - } - const { sceneIDs } = this; - U.remove(sceneIDs, sceneID); - await this.updateTarget("sceneIDs", sceneIDs); - this.renderTargetAndKeeper(); - } - closeClockKey({ container$ }) { - container$.remove(); - } - get svgData() { - if (this.size === 0) { - throw new Error("[BladesClockKey.svgData] Error size is 0."); - } - const keyData = ClockKey_SVGDATA[this.size]; - let path; - if (this.size === 1 && keyData.paths) { - path = keyData.paths[this.oneKeyIndex]; - } - else if (keyData.path) { - path = keyData.path; - } - else { - throw new Error("[BladesClockKey.svgData] Error path is not defined."); - } - return { - width: keyData.width, - height: keyData.height, - path, - clocks: keyData.clocks - }; - } - isInOverlay(elem) { - return $(elem).hasClass(".overlay-section") || $(elem).closest(".overlay-section").length > 0; - } - get keyHeight() { return this.svgData.height; } - get keyWidth() { return this.svgData.width; } - get keyViewbox() { return `0 0 ${this.svgData.width} ${this.svgData.height}`; } - get keyPath() { return this.svgData.path; } - get clockSize() { return this.svgData.clocks.size; } - getClockPosition(clockIndex = 0) { - if (clockIndex > this.size) { - throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is greater than key size '${this.size}'.`); - } - if (clockIndex < 0) { - throw new Error(`[BladesClockKey.getClockPosition] Error clockIndex '${clockIndex}' is less than 0.`); - } - return this.svgData.clocks[clockIndex]; - } - positionDragger; - removePositionDragger() { - this.positionDragger?.target.remove(); - this.positionDragger?.kill(); - delete this.positionDragger; - } - spawnPositionDragger(containerElem$ = game.eunoblades.Director.clockKeySection$) { - const self = this; - if (this.positionDragger) { - this.removePositionDragger(); - } - const dragElem$ = $(`
`) - .appendTo(containerElem$); - if (this.overlayPosition) { - dragElem$.css({ - left: this.overlayPosition.x, - top: this.overlayPosition.y - }); - } - this.positionDragger = new Dragger(dragElem$, { - type: "top,left", - onDragStart() { - $(this.target).css("background", "rgba(255, 255, 0, 0.25)"); - $(this.target).css("outlineColor", "rgba(255, 255, 0, 1)"); - }, - onDragEnd() { - $(this.target).css("background", "rgba(255, 0, 255, 0.25)"); - $(this.target).css("outlineColor", "rgba(255, 0, 255, 1)"); - self.overlayPosition = { x: this.endX, y: this.endY }; - } - }); - } - switchToMode(keyElems$, displayMode, extendKeyVars = {}, extendKeyContainerVars = {}, isUpdatingTarget = true, callback) { - const { elem$, imgContainer$ } = keyElems$; - const { keyTweenVars, keyImgContTweenVars } = this.getVarsForDisplayMode(keyElems$, displayMode); - const currentDisplayMode = this.displayMode; - const randomID = U.gsap.utils.random(1, 1000, 1); - return U.gsap.timeline({ - callbackScope: this, - paused: true, - onStart() { - eLog.checkLog2("BladesClockKey", `switchToMode #${randomID} - START`, { key: this, keyElems$, displayMode }); - }, - onComplete() { - eLog.checkLog3("BladesClockKey", `switchToMode #${randomID} - COMPLETE`, { key: this, keyElems$, displayMode }); - if (isUpdatingTarget && displayMode !== this.currentDisplayMode) { - this.updateTarget("displayMode", displayMode) - .then(() => callback?.()); - } - else { - callback?.(); - } - }, - onReverseComplete() { - eLog.checkLog3("BladesClockKey", `switchToMode #${randomID} - REVERSE COMPLETE`, { key: this, keyElems$, displayMode }); - if (isUpdatingTarget) { - this.updateTarget("displayMode", currentDisplayMode); - } - } - }) - .to(elem$, { ...keyTweenVars, ...extendKeyVars }, 0) - .to(imgContainer$, { ...keyImgContTweenVars, ...extendKeyContainerVars }, 0); - } - // #endregion - // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls) - // #region > SOCKET CALLS: _SocketCall / static _SocketResponse / _Animation - fadeInName_Animation(keyElems$) { - if (!this.name) { - return undefined; - } - return U.gsap.effects.blurReveal(keyElems$.label$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeInName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeInName_SocketCall", displayContext, this.id); - } - static fadeInName_SocketResponse(displayContext, keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - key.fadeInName_Animation(key.getElements$(displayContext)); - } - fadeOutName_Animation(keyElems$) { - if (!this.name) { - return undefined; - } - return U.gsap.effects.blurRemove(keyElems$.label$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeOutName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - this.fadeOutName_Animation(this.getElements$(displayContext)); - socketlib.system.executeForOthers("fadeOutName_SocketCall", displayContext, this.id); - } - static fadeOutName_SocketResponse(displayContext, keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - key.fadeOutName_Animation(key.getElements$(displayContext)); - } - // #endregion - // #endregion - // #region Adding & Removing Clocks ~ - async updateClockIndices() { - await this.updateTarget("clocksData", Object.fromEntries(Object.entries(this.clocksData) - .map(([id, data], index) => [id, { ...data, index }]))); - return this.clocks; - } - async addClock(clockSchema = {}) { - // Derive clock data from config - const cData = BladesClock.ParseConfigToData({ - ...BladesClock.ApplySchemaDefaults(clockSchema), - index: this.size, - targetID: this.targetID, - targetKey: `${this.targetKeyPrefix}.clocksData`, - isScopingById: true - }); - // const clockData = this.parseClockConfig(clockConfig); - // Write to state - await this.updateTarget(`clocksData.${cData.id}`, cData); - // Regnerate clocks collection - void this.clocks; - this.renderTargetAndKeeper(); - } - async deleteClock(clockID) { - if (this.size <= 1) { - throw new Error("[BladesClockKey.deleteClock()] Cannot reduce number of clocks below 1!"); - } - clockID ??= Array.from(this.clocks).pop()?.id; - if (!clockID) { - return; - } - await this.getClockByID(clockID)?.delete(); - await this.updateClockIndices(); - // Regenerate clocks collection - void this.clocks; - } - // #endregion - // #region OVERRIDES: Async Update Methods - renderTargetAndKeeper() { - this.renderTarget(); - game.eunoblades.ClockKeeper.sheet?.render(); - } - renderTarget() { - this.target.sheet?.render(); - } -} -class BladesClock extends BladesTargetLink { - // #region STATIC METHODS ~ - static ApplySchemaDefaults(schemaData) { - const namedValueMax = { - name: schemaData.name ?? "", - value: schemaData.value ?? 0, - max: schemaData.max ?? 8 - }; - return { - index: 0, - color: ClockColor.white, - isVisible: !U.isInt(schemaData.index) || schemaData.index === 0, - isNameVisible: false, - isHighlighted: false, - isActive: !U.isInt(schemaData.index) || schemaData.index === 0, - ...schemaData, - ...namedValueMax - }; - } - // #endregion - // #region GETTERS & SETTERS ~ - get canEdit() { - // return true if user has edit permissions on parent document, and clock is - // visible and active. - console.log("NOTE: All Clocks currently Editable; see line 71 of BladesClock.ts"); - return this.isVisible && this.isActive; - } - get data() { return this.linkData; } - get name() { return this.data.name; } - set name(val) { - this.updateTarget("name", val) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get value() { return U.pInt(this.data.value); } - set value(val) { - this.updateTarget("value", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get max() { return U.pInt(this.data.max); } - set max(val) { - this.updateTarget("max", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get color() { return this.data.color ?? ClockColor.white; } - set color(val) { - this.updateTarget("color", val) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isActive() { return U.pBool(this.data.isActive); } - set isActive(val) { - this.updateTarget("isActive", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get parentKey() { - const pKey = game.eunoblades.ClockKeys.get(this.data.parentKeyID); - if (!pKey) { - throw new Error(`[BladesClockKey.parentKey] No parent key found for clock ${this.id}`); - } - return pKey; - } - get isNameVisible() { return U.pBool(this.data.isNameVisible); } - set isNameVisible(val) { - this.updateTarget("isNameVisible", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isVisible() { return U.pBool(this.data.isVisible); } - set isVisible(val) { - this.updateTarget("isVisible", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isHighlighted() { return U.pBool(this.data.isHighlighted); } - set isHighlighted(val) { - this.updateTarget("isHighlighted", U.pBool(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get index() { return U.pInt(this.data.index); } - set index(val) { - this.updateTarget("index", U.pInt(val)) - .then(() => { this.parentKey.renderTargetAndKeeper(); }); - } - get isEmpty() { return this.value === 0; } - get isComplete() { return this.value >= this.max; } - get rollOppClock() { return this; } - get rollOppName() { return this.name; } - get rollOppType() { return "clock"; } - get colorSelectOptions() { - return [ - { value: ClockColor.white, display: "🔘" }, - { value: ClockColor.yellow, display: "📀" }, - { value: ClockColor.cyan, display: "🔵" }, - { value: ClockColor.red, display: "🔴" } - ]; - } - get maxSelectOptions() { - return [ - { value: 2, display: 2 }, - { value: 3, display: 3 }, - { value: 4, display: 4 }, - { value: 5, display: 5 }, - { value: 6, display: 6 }, - { value: 8, display: 8 }, - { value: 10, display: 10 }, - { value: 12, display: 12 } - ]; - } - get valueSelectOptions() { - const returnVals = []; - for (let i = 0; i <= this.max; i++) { - returnVals.push({ value: i, display: i }); - } - return returnVals; - } - // Returns which hemisphere of the clock will show the final change if segmentDelta segments are added/removed. - getActiveSide(segmentDelta = 0) { - const finalClockValue = Math.min(this.max, Math.max(0, this.value + segmentDelta)); - const halfClockValue = this.max / 2; - if (segmentDelta === 0) { - return finalClockValue >= halfClockValue - ? "left" - : "right"; - } - return finalClockValue > halfClockValue - ? "left" - : "right"; - } - // #endregion - // #region HTML INTERACTION ~ - getElemFromDisplayContext(displayContext) { - let elem$; - const DOM$ = $(".vtt.game.system-eunos-blades"); - switch (displayContext) { - case ClockDisplayContext.overlay: { - elem$ = DOM$.find(`#blades-overlay #${this.id}`); - break; - } - case ClockDisplayContext.pcSheet: { - elem$ = DOM$.find(`.actor.sheet .pc #${this.id}`); - break; - } - case ClockDisplayContext.factionSheet: { - elem$ = DOM$.find(`.actor.sheet .faction #${this.id}`); - break; - } - case ClockDisplayContext.projectSheet: { - elem$ = DOM$.find(`.item.sheet .project #${this.id}`); - break; - } - case ClockDisplayContext.scoreSheet: { - elem$ = DOM$.find(`.item.sheet .score #${this.id}`); - break; - } - case ClockDisplayContext.rollCollab: { - elem$ = DOM$.find(`.roll-collab-sheet #${this.id}`); - break; - } - case ClockDisplayContext.chatMessage: { - elem$ = DOM$.find(`#chat #${this.id}`); - break; - } - } - if (!elem$.length) { - throw new Error(`[BladesClockKey.getElemFromDisplayContext] Error elem$ not found for key '${this.id}' for display context '${displayContext}'.`); - } - return elem$; - } - getElements$(displayContext) { - let elem$; - if (typeof displayContext === "string") { - displayContext = this.getElemFromDisplayContext(displayContext); - } - elem$ = $(displayContext).find(`#${this.id}`); - if (!elem$.length) { - elem$ = $(displayContext).closest(`#${this.id}`); - } - if (!elem$?.length) { - throw new Error(`[BladesClock.getElements$] Cannot find elements for display context '${displayContext}' of clock '${this.id}' of key '${this.parentKey.id}'.`); - } - // Using elem$ as a reference, locate relevant clock elements and return them in a dictionary. - const clockElems$ = { - clockElem$: elem$ - }; - // Get elements that will be there regardless of context, throwing errors if not found. - const container$ = elem$.closest(".clock-container"); - if (!container$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-container' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.clockContainer$ = container$; - const label$ = elem$.find(".clock-label"); - if (!label$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-label' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.clockLabel$ = label$; - const bg$ = elem$.find(".clock-bg"); - if (!bg$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-bg' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.bg$ = bg$; - const frame$ = elem$.find(".clock-frame"); - if (!frame$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-frame' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.frame$ = frame$; - const fill$ = elem$.find(".clock-fill"); - if (!fill$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-fill' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.fill$ = fill$; - const glow$ = elem$.find(".clock-glow"); - if (!glow$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-glow' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.glow$ = glow$; - const cover$ = elem$.find(".clock-cover"); - if (!cover$.length) { - throw new Error(`[BladesClock.getElements$] Error '.clock-cover' not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.cover$ = cover$; - const oneSegments$ = elem$.find(".clock-one-segment"); - if (oneSegments$.length !== 3) { - throw new Error(`[BladesClock.getElements$] Error '.clock-one-segment' elements not found for clock '${this.id}' of key '${this.parentKey.id}'.`); - } - clockElems$.oneSegments$ = oneSegments$; - return clockElems$; - } - // #endregion - // #region ANIMATED UPDATES (Both GM-Only AND Socket Calls) - reveal_Animation(clockElems$, callback) { - // Identify elements for fading in - const fadeInElements = [ - clockElems$.frame$, - clockElems$.fill$ - ].filter((el$) => el$ !== undefined); - // Construct timeline for revealing clock - const tl = U.gsap.timeline({ - callbackScope: this, - onComplete() { - callback?.(); - } - }); - // Fade out cover hiding clock - tl.to(clockElems$.cover$, { scale: 2, autoAlpha: 0, duration: 0.5, ease: "power2" }); - // Fade in clock elements - tl.fromTo(fadeInElements, { - autoAlpha: 0, - scale: 2 - }, { - autoAlpha: 1, - scale: 1, - duration: 0.5, - stagger: 0.2, - ease: "power2" - }); - // Fade in name, if name is visible. - if (this.name && this.isNameVisible) { - tl.blurReveal(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }, "<+0.05"); - } - // Fade in glow, if highlighted - if (this.isHighlighted) { - tl.scaleUpReveal(clockElems$.glow$, { - scale: 3, - duration: 0.5 - }, "<+0.05"); - } - if (this.isActive) { - tl.add(() => this.activate_Animation(clockElems$), "<+0.05"); - } - else { - tl.add(() => this.deactivate_Animation(clockElems$), "<+0.05"); - } - return tl; - } - async reveal_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("reveal_SocketCall", displayContext, this.parentKey.id, this.index); - } - static reveal_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - const clockElems$ = clock.getElements$(displayContext); - clock.reveal_Animation(clockElems$); - } - hide_Animation(clockElems$, callback) { - // Identify elements for fading out - const fadeOutElements = [ - clockElems$.frame$, - clockElems$.fill$ - ].filter((el$) => el$ !== undefined); - // Construct timeline for hiding clock - const tl = U.gsap.timeline({ - callbackScope: this, - onComplete() { - callback?.(); - } - }); - // Fade out clock elements - tl.to(fadeOutElements, { - autoAlpha: 0, - scale: 2, - duration: 0.5, - stagger: 0.2, - ease: "power2" - }); - // Fade out name, if name visible - if (this.name && this.isNameVisible) { - tl.blurRemove(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }, "<+0.05"); - } - // Fade out glow, if highlighted - if (this.isHighlighted) { - tl.scaleDownRemove(clockElems$.glow$, { - scale: 3, - duration: 0.5 - }, "<+0.05"); - } - // Fade in cover element - tl.to(clockElems$.cover$, { scale: 1, autoAlpha: 1, duration: 0.5, ease: "power2" }); - return tl; - } - async hide_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("hide_SocketCall", displayContext, this.parentKey.id, this.index); - } - static hide_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - const clockElems$ = clock.getElements$(displayContext); - clock.hide_Animation(clockElems$); - } - activate_Animation(clockElems$, callback) { - U.gsap.to(clockElems$.bg$, { autoAlpha: 1, duration: 0.5, ease: "power2" }); - U.gsap.to(clockElems$.frame$, { - filter: "brightness(0.5)", - duration: 0.5, - ease: "power2", - onComplete: callback - }); - } - async activate_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("activate_SocketCall", displayContext, this.parentKey.id, this.index); - } - static activate_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.activate_Animation(clock.getElements$(displayContext)); - } - deactivate_Animation(clockElems$, callback) { - U.gsap.to(clockElems$.bg$, { autoAlpha: 0, duration: 0.5, ease: "power2" }); - U.gsap.to(clockElems$.frame$, { - filter: "brightness(1) blur(5px)", - duration: 0.5, - ease: "power2", - onComplete: callback - }); - } - async deactivate_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("deactivate_SocketCall", displayContext, this.parentKey.id, this.index); - } - static deactivate_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.deactivate_Animation(clock.getElements$(displayContext)); - } - fadeInClockName_Animation(clockElems$) { - U.gsap.effects.blurReveal(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeInClockName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeInClockName_SocketCall", displayContext, this.parentKey.id, this.index); - } - static fadeInClockName_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.fadeInClockName_Animation(clock.getElements$(displayContext)); - } - fadeOutClockName_Animation(clockElems$) { - U.gsap.effects.blurRemove(clockElems$.clockLabel$, { - ignoreMargin: true, - duration: 0.75 - }); - } - async fadeOutClockName_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("fadeOutClockName_SocketCall", displayContext, this.parentKey.id, this.index); - } - static fadeOutClockName_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.fadeOutClockName_Animation(clock.getElements$(displayContext)); - } - highlight_Animation(clockElems$) { - U.gsap.effects.scaleUpReveal(clockElems$.glow$, { - duration: 0.5, - scale: 3 - }); - } - async highlight_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("highlight_SocketCall", displayContext, this.parentKey.id, this.index); - } - static highlight_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.highlight_Animation(clock.getElements$(displayContext)); - } - unhighlight_Animation(clockElems$) { - U.gsap.effects.scaleDownRemove(clockElems$.glow$, { - duration: 0.5, - scale: 3 - }); - } - async unhighlight_SocketCall(displayContext) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("unhighlight_SocketCall", displayContext, this.parentKey.id, this.index); - } - static unhighlight_SocketResponse(displayContext, keyID, index) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.unhighlight_Animation(clock.getElements$(displayContext)); - } - getRotationOfSegment(segment) { - const stepSize = 360 / this.max; - return stepSize * (segment - 1); - } - initOneSegments(clockElems$, segmentNums, isReversing) { - if (segmentNums.length > 3) { - throw new Error(`Too many segments: [${segmentNums.join(", ")}]`); - } - // For each segment number, initialize a one-segment to that position, - // and initialize its autoAlpha depending on isReversing. - const oneSegs = [...clockElems$.oneSegments$]; - const oneSegsToAnimate = Array.from(clockElems$.oneSegments$).slice(0, segmentNums.length); - for (const segmentNum of segmentNums) { - const oneSegment = oneSegs.shift(); - U.gsap.set(oneSegment, { - rotation: this.getRotationOfSegment(segmentNum), - autoAlpha: isReversing ? 1 : 0 - }); - } - // If reversing, set clock element's value to the final value for proper clipping. - if (isReversing) { - clockElems$.clockElem$.attr("data-value", U.getLast(segmentNums) - 1); - } - return oneSegsToAnimate; - } - changeSegments_Animation(clockElems$, startVal, endVal, callback) { - startVal = U.gsap.utils.clamp(0, this.max, startVal); - endVal = U.gsap.utils.clamp(0, this.max, endVal); - let delta = endVal - startVal; - if (delta === 0) { - return; - } - // Determine position and sequence of one-segments - const segmentNums = []; - if (delta < 0) { - while (Math.abs(delta) > startVal) { - delta++; - } - for (let i = startVal; i > endVal; i--) { - segmentNums.push(i); - } - } - else { - while (endVal > this.max) { - delta--; - } - for (let i = startVal + 1; i <= endVal; i++) { - segmentNums.push(i); - } - } - // Initialize oneSegments at determined positions - const segmentsToAnimate = this.initOneSegments(clockElems$, segmentNums, startVal > endVal); - eLog.checkLog3("BladesClock", "changeSegments_Animation", { clockElems$, delta, segmentNums, startVal, endVal, segmentsToAnimate }); - // Initialize master timeline - const tl = U.gsap.timeline(); - // Enlarge clock key and focus clock - // const clockFocusTimeline: gsap.core.Timeline = this.parentKey.getClockFocusTimeline(this.index); - // tl.add(clockFocusTimeline); - // Animate one-segments - if (delta > 0) { - tl.fromTo(segmentsToAnimate, { - autoAlpha: 0, - scale: 2 - }, { - autoAlpha: 1, - scale: 1, - duration: 0.5, - stagger: 0.2, - ease: "power2", - callbackScope: this, - onComplete() { - clockElems$.clockElem$.attr("data-value", endVal); - U.gsap.to(segmentsToAnimate, { - autoAlpha: 0, - duration: 0.5, - stagger: 0.2 - // onComplete() { - // // Return clock key to original size and focus - // clockFocusTimeline.reverse(); - // } - }); - } - }); - } - else { - tl.fromTo(segmentsToAnimate, { - autoAlpha: 1, - scale: 1 - }, { - autoAlpha: 0, - scale: 2, - duration: 0.5, - stagger: 0.2, - ease: "power2" - // onComplete() { - // // Return clock key to original size and focus - // clockFocusTimeline.reverse(); - // } - }); - } - return tl; - } - async changeSegments_SocketCall(displayContext, startVal, endVal) { - if (!game.user.isGM) { - return; - } - startVal = U.gsap.utils.clamp(0, this.max, startVal); - endVal = U.gsap.utils.clamp(0, this.max, endVal); - socketlib.system.executeForEveryone("changeSegments_SocketCall", displayContext, this.parentKey.id, this.index, startVal, endVal); - } - static changeSegments_SocketResponse(displayContext, keyID, index, startVal, endVal) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key?.isVisible) { - return; - } - const clock = key.getClockByIndex(index); - if (!clock) { - return; - } - clock.changeSegments_Animation(clock.getElements$(displayContext), startVal, endVal); - } - // #endregion - // #region Adding/Removing Clock Segments ~ - // Returns number of segments beyond max (or 0, if max not met) - async fillSegments(count, isSilent = false) { - // Amount added beyond max: - const clockOverflow = Math.max(0, this.value + count - this.max); - // Clamp count to max: - count = Math.min(this.value + count, this.max) - this.value; - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value + count); - if (!isSilent) { - this.parentKey.renderTargetAndKeeper(); - } - return clockOverflow; - } - // Returns (positive) number of segments removed - // in excess of the number of segments in the clock - async clearSegments(count, isSilent = false) { - // Amount removed beyond 0: - const clockOverflow = Math.max(0, count - this.value); - // Clamp count to min: - count = Math.min(this.value, count); - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value - count); - if (!isSilent) { - this.parentKey.renderTargetAndKeeper(); - } - return clockOverflow; - } - async delete() { - const { parentKey } = this; - await super.delete(false); - parentKey.updateClockIndices(); - } -} -export default BladesClockKey; -export { BladesClock }; diff --git a/module/classes/BladesConsequence.js b/module/classes/BladesConsequence.js deleted file mode 100644 index 22226b8f..00000000 --- a/module/classes/BladesConsequence.js +++ /dev/null @@ -1,557 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { AttributeTrait, ConsequenceType, Position, Effect } from "../core/constants.js"; -import U from "../core/utilities.js"; -import BladesRoll, { BladesRollPrimary } from "./BladesRoll.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -import { BladesPC } from "../documents/BladesActorProxy.js"; -/* eslint-enable @typescript-eslint/no-unused-vars */ -class BladesConsequence extends BladesTargetLink { - // #region Static Methods ~ - static async Initialize() { - if (!game.messages) { - throw new Error("[BladesConsequence] Messages Not Ready!"); - } - return (await Promise.all(game.messages.contents - .map(async (msg) => msg.rollConsequences))) - .flat(); - } - /** - * Checks if the given value is valid consequence data for a Resistance Roll. - * @param val The value to check. - * @param isCheckingResistedTo If the check is being recursively applied to the 'resistTo' value. - * @returns True if the val is valid BladesConsequence.Data, false otherwise. - */ - static IsValidConsequenceData(val, isCheckingResistedTo = false) { - if (!U.isList(val)) { - return false; - } - if (typeof val.type !== "string" || !(val.type in ConsequenceType)) { - return false; - } - if (typeof val.name !== "string") { - return false; - } - if (isCheckingResistedTo) { - return true; - } - if (val.attribute && (typeof val.attribute !== "string" || !(val.attribute in AttributeTrait))) { - return false; - } - if (!this.IsValidConsequenceData(val.resistTo, true)) { - return false; - } - return true; - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - if (!schemaData.primaryID) { - throw new Error("A primaryID is required for BladesConsequence.Schema"); - } - if (typeof schemaData.name === "string" && (!schemaData.name && schemaData.type !== ConsequenceType.None)) { - throw new Error(`A name must be provided for non-None-type consequences (${schemaData.name}).`); - } - return { - name: "", - type: ConsequenceType.None, - ...schemaData - }; - } - static GetCsqTypeValue(cType, rollData) { - if (cType === ConsequenceType.WorsePosition) { - // Requires position data to resolve. - if (!rollData) { - throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data.`); - } - let position; - if ("rollPositionFinal" in rollData) { - position = rollData.rollPositionFinal; - } - else if ("position" in rollData) { - position = rollData.position; - } - if (!position) { - throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data that includes final position data.`); - } - return { - [Position.controlled]: 1, - [Position.risky]: 2, - [Position.desperate]: 0 - }[position]; - } - if (cType === ConsequenceType.ReducedEffect) { - // Requires effect data to resolve. - if (!rollData) { - throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data.`); - } - let effect; - if ("rollEffectFinal" in rollData) { - effect = rollData.rollEffectFinal; - } - else if ("effect" in rollData) { - effect = rollData.effect; - } - if (!effect) { - throw new Error(`Cannot resolve consequence type value for '${cType}' without roll data that includes final effect data.`); - } - return { - [Effect.extreme]: 1, - [Effect.great]: 1, - [Effect.standard]: 1, - [Effect.limited]: 2, - [Effect.zero]: 0 - }[effect]; - } - // All other values are constant for each consequence type. - return C.ConsequenceValues[cType]; - } - // #endregion - // #region *** GETTERS *** ~ - // #region Getters (Target Data) ~ - get primaryID() { return this.data.primaryID ?? this.parentConsequence?.primaryID; } - get parentCsqID() { return this.data.parentCsqID; } - get name() { return this.data.name; } - get type() { return this.data.type; } - get attribute() { return this.data.attribute ?? this.parentConsequence?.attribute; } - get attributeVal() { return this.data.attributeVal ?? this.parentConsequence?.attributeVal; } - get specialFooterMsg() { - return this.data.specialFooterMsg ?? this.parentConsequence?.specialFooterMsg; - } - // #endregion - // #region Getters (Derived Data) ~ - get primary() { - const primary = fromUuidSync(this.primaryID); - if (!BladesRollPrimary.IsDoc(primary)) { - throw new Error(`Could not find primary with UUID '${this.primaryID}'`); - } - if (this.roll) { - return new BladesRollPrimary(this.roll, primary); - } - return new BladesRollPrimary(primary); - } - get parentConsequence() { - if (!this.parentCsqID) { - return undefined; - } - const parentCsq = game.eunoblades.Consequences.get(this.parentCsqID); - if (!parentCsq) { - throw new Error(`Error locating parent consequence with id '${this.parentCsqID}'`); - } - return parentCsq; - } - get typeDisplay() { return C.ConsequenceDisplay[this.type]; } - get icon() { return C.ConsequenceIcons[this.type]; } - get value() { return BladesConsequence.GetCsqTypeValue(this.type, this); } - // #endregion - // #region Getters (Resolved Roll Data that Applied This Consequence) ~ - get rollData() { - return this.data.actionRollData ?? this.parentConsequence?.rollData; - } - get roll() { - if (!this.rollData) { - return undefined; - } - return game.eunoblades.Rolls.get(this.rollData.id) ?? new BladesRoll({ - ...this.rollData, - isScopingById: false - }); - } - get position() { return this.roll?.rollPositionFinal; } - get effect() { return this.roll?.rollEffectFinal; } - get result() { return this.roll?.rollResultFinal; } - // #endregion - // #region Getters (Resistibility & Acceptance Status) ~ - isResistible() { - return Boolean(this.type !== ConsequenceType.None && !this.isAccepted && this.data.resistSchema); - } - get resistanceModes() { return this.data.resistanceModes ?? []; } - get wasResisted() { return Boolean(this.resistanceModes.length); } - get wasResistedByRoll() { return this.resistanceModes.includes("resist"); } - get wasResistedByArmor() { return this.resistanceModes.includes("armor"); } - get wasResistedBySpecialArmor() { return this.resistanceModes?.includes("special"); } - get canResistWithRoll() { - if (!this.isResistible()) { - return false; - } - // Only PCs can roll to resist consequences. - if (!BladesPC.IsType(this.primary.rollPrimaryDoc)) { - return false; - } - // A consequence can only be resisted by roll once. - if (this.wasResistedByRoll) { - return false; - } - // Otherwise, a consequence can ALWAYS be resisted by roll once by a PC. - return true; - } - get canResistWithArmor() { - if (!this.isResistible()) { - return false; - } - // The consequence must be explicitly flagged as resistable by armor. - if (!this.data.canResistWithArmor) { - return false; - } - // Unlike resistance rolls, a Primary could conceivably resist twice using multiple armor boxes. - // So, a resistanceMode previously set to "armor" does not disqualify another resist, if the - // Primary has armor to spare. - return this.primary.availableArmorCount > 0; - } - get canResistWithSpecial() { - if (!this.isResistible()) { - return false; - } - // The consequence must be explicitly flagged as resistable by special armor. - if (!this.data.canResistWithSpecial) { - return false; - } - // Only PCs can resist consequences with special armor. - if (!BladesPC.IsType(this.primary.rollPrimaryDoc)) { - return false; - } - // A consequence can only be resisted by special armor once. - if (this.wasResistedBySpecialArmor) { - return false; - } - // Otherwise, the PC can resist if they have special armor to spare. - return this.primary.hasSpecialArmor; - } - get resistWithRollNegates() { - if (!this.canResistWithRoll) { - return false; - } - // If this is the second resistance, it automatically negates. - if (this.wasResisted) { - return true; - } - // Otherwise, it negates if explicitly flagged to do so. - return Boolean(this.data.resistWithRollNegates); - } - get resistWithArmorNegates() { - if (!this.canResistWithArmor) { - return false; - } - // If this is the second resistance, it automatically negates. - if (this.wasResisted) { - return true; - } - // Otherwise, it negates if explicitly flagged to do so. - return Boolean(this.data.resistWithArmorNegates); - } - get resistWithSpecialNegates() { - if (!this.canResistWithSpecial) { - return false; - } - // If this is the second resistance, it automatically negates. - if (this.wasResisted) { - return true; - } - // Otherwise, it negates if explicitly flagged to do so. - return Boolean(this.data.resistWithSpecialNegates); - } - get isAccepted() { return "acceptanceMode" in this.data; } - get acceptanceMode() { - return this.data.acceptanceMode; - } - // #endregion - // #endregion - // #region *** RESISTING CONSEQUENCES *** - // #region Constructing Resistable Consequence Schema - get noneSchema() { - return { - name: "", - type: ConsequenceType.None, - primaryID: this.primaryID - }; - } - get resistSchema() { - // If this consequence can't be resisted, return undefined. - if (!this.isResistible()) { - return undefined; - } - // Expand the resistSchema into a full BladesConsequence.Schema object - const resSchema = { - name: this.data.resistSchema.name, - type: this.data.resistSchema.type, - primaryID: this.primaryID, - resistSchema: { - name: "", - type: ConsequenceType.None - }, - resistanceModes: this.resistanceModes, - resistWithRollNegates: true, - attribute: this.attribute, - attributeVal: this.attributeVal, - canResistWithArmor: this.canResistWithArmor, - resistWithArmorNegates: true, - canResistWithSpecial: this.canResistWithSpecial, - resistWithSpecialNegates: true, - specialFooterMsg: this.specialFooterMsg - }; - // If this consequence has already been resisted once, convert the resistSchema to a None-type schema. - if (this.wasResisted) { - resSchema.name = ""; - resSchema.type = ConsequenceType.None; - delete resSchema.resistSchema; - resSchema.canResistWithArmor = false; - resSchema.canResistWithSpecial = false; - } - return resSchema; - } - // #endregion - async resistConsequence(resistMode, rollInstance) { - if (!this.isResistible()) { - throw new Error("Cannot resist a consequence that is not resistible."); - } - const updateData = { - resistanceModes: this.resistanceModes, - ...this.resistSchema - }; - updateData.resistanceModes.push(resistMode); - updateData.parentCsqID = undefined; - if (resistMode === "resist") { - if (!rollInstance?.isResolved) { - throw new Error("Cannot transform to resisted consequence without a resolved resistance roll instance."); - } - updateData.resistanceRollData = rollInstance.data; - } - // Now check updated schema to see whether this consequence should be automatically accepted: - // ... if this is the second time the consequence has been resisted = verify None-type and accept - // ... if the resulting resisted consequence is None-type = verify None-type and accept - // ... if resistMode = "resist" and csq can't be resisted with armor or special = transform and accept - // ... (all other cases are already caught by "second time" check above) - if (this.wasResisted || updateData.type === ConsequenceType.None) { - updateData.acceptanceMode = "base"; // Use 'base' for None-type consequences so they appear faded out - } - else if (resistMode === "resist" && !this.canResistWithArmor && !this.canResistWithSpecial) { - updateData.acceptanceMode = resistMode; - } - await this.updateTargetData(updateData); - if (updateData.acceptanceMode) { - socketlib.system.executeForEveryone("acceptConsequence_SocketCall", this.id); - } - else { - socketlib.system.executeForEveryone("resistConsequence_SocketCall", this.id); - } - } - // #endregion - // #region *** ACCEPTING CONSEQUENCES *** - async acceptConsequence() { - if (this.isAccepted) { - return; - } - await this.updateTarget("acceptanceMode", U.getLast(this.resistanceModes) ?? "accept"); - socketlib.system.executeForEveryone("acceptConsequence_SocketCall", this.id); - } - async applyConsequenceEffects() { - // If HARM -> Apply harm to actor. - if (/Harm/.test(this.type)) { - this.primary.applyHarm(U.pInt(this.type.substring(this.type.length - 1)), this.name); - // If WORSE POSITION -> Add flag to user to be checked on next Action roll, then cleared - } - else if (this.type === ConsequenceType.WorsePosition) { - this.primary.applyWorsePosition(); - // If REDUCED EFFECT -> Update chat message flag to reduced effect level. - } - else if (this.type === ConsequenceType.ReducedEffect) { - const curIndex = Object.values(Effect) - .findIndex((val) => val === this.effect); - if (curIndex >= 1) { - const newEffect = Object.values(Effect)[curIndex - 1]; - await this.updateTarget("rollData.rollEffectFinal", newEffect); - } - } - // If COMPLICATION -> No change. - // If LOST OPPORTUNITY -> No change. - } - // #endregion - // #region === CONSTRUCTOR === ~ - // constructor( - // config: BladesConsequence.Config, - // parentCsq?: BladesConsequence.Data - // ) - // constructor( - // data: BladesConsequence.Data - // ) - // constructor( - // schema: Partial, - // parentCsq: BladesConsequence.Data - // ) - // constructor( - // dataConfigOrSchema: BladesConsequence.Config | BladesConsequence.Data | Partial, - // parentCsq?: BladesConsequence.Data - // ) { - // // If a parentCsq is provided... - // if (parentCsq) { - // super({ - // ...BladesTargetLink.BuildLinkConfig(parentCsq), - // ...dataConfigOrSchema - // }); - // } else { - // super(dataConfigOrSchema as BladesConsequence.Config | BladesConsequence.Data); - // } - // } - // #endregion - // #region *** HTML INTERACTION *** - // #region *** BladesDialog *** ~ - // #endregion - // #region *** BladesChat *** ~ - static ApplyChatListeners(message) { - /** - * TIMELINES - * .comp.consequence-display-container:mouseenter - * = fade in grey interaction buttons - * ...:mouseleave = reverse - * - * .consequence-accept-button-container:mouseenter - * = turn type line white, text shadow - * slide out .consequence-accept-button-bg from left - * turn .consequence-accept-button i black, and scale - * turn .consequence-accept-button-label black, add letter spacing, bold - * ...:mouseleave = reverse - * - * .consequence-resist-button-container:mouseenter - * = slide in .consequence-type-bg.base-consequence to left - * fade out all .base-consequence:not(.consequence-type-bg) - * slide out .consequence-type.resist-consequence from left - * slide out .consequence-resist-button-bg from right - * slide out .consequence-footer-bg.resist-consequence from left - * slide out .consequence-resist-attribute from left - * slide out .consequence-name.resist-consequence from left - * fade in .consequence-icon-circle.resist-consequence - * ...:mouseleave = reverse - * --> IF resistTo.type === "None", blurRemove the base_consequence name and type instead of sliding them in, - * and don't slide the resistance ones out at all. - * */ - const html$ = message.elem$; - html$ - .find(".comp.consequence-display-container") - .each((_i, csqContainer) => { - if (!$(csqContainer).hasClass("consequence-accepted")) { - const iconContainer$ = $(csqContainer).find(".consequence-icon-container"); - const rightInteractionPad$ = $(csqContainer).find(".interaction-pad-right"); - const leftInteractionPad$ = $(csqContainer).find(".interaction-pad-left"); - const resistInteractionPad$ = $(csqContainer).find(".interaction-pad-left-resist"); - const armorInteractionPad$ = $(csqContainer).find(".interaction-pad-left-armor"); - const specialInteractionPad$ = $(csqContainer).find(".interaction-pad-left-special"); - // Apply master on-enter hover timeline to consequence container. - $(csqContainer).data("hoverTimeline", U.gsap.effects.csqEnter(csqContainer)); - $(csqContainer).on({ - mouseenter: function () { - $(csqContainer).css("z-index", 10); - $(csqContainer).data("hoverTimeline").play(); - }, - mouseleave: function () { - if (!(iconContainer$.data("isToggled") || iconContainer$.data("isTogglingOn")) || iconContainer$.data("isTogglingOff")) { - $(csqContainer).data("hoverTimeline").reverse().then(() => { - $(csqContainer).css("z-index", ""); - }); - } - } - }); - // Apply click timeline to icon circle - iconContainer$.data("clickTimeline", U.gsap.effects.csqClickIcon(iconContainer$[0])); - iconContainer$.on({ - click: function () { - if (iconContainer$.data("isToggled") || iconContainer$.data("isTogglingOn")) { - iconContainer$.data("isTogglingOn", false); - iconContainer$.data("isTogglingOff", true); - iconContainer$.data("clickTimeline").reverse().then(() => { - iconContainer$.data("isTogglingOff", false); - iconContainer$.data("isToggled", false); - }); - } - else { - iconContainer$.data("isTogglingOn", true); - iconContainer$.data("isTogglingOff", false); - // Find any siblings with toggled-on iconContainers, and toggle them off - Array.from($(csqContainer).siblings(".consequence-display-container")) - .forEach((containerElem) => { - const iContainer$ = $(containerElem).find(".consequence-icon-container"); - if (iContainer$?.data("isToggled") || iContainer$?.data("isTogglingOn")) { - iContainer$.data("isTogglingOn", false); - iContainer$.data("isTogglingOff", true); - iContainer$.data("clickTimeline").reverse().then(() => { - iContainer$.data("isTogglingOff", false); - iContainer$.data("isToggled", false); - $(containerElem).data("hoverTimeline").reverse().then(() => { - $(containerElem).css("z-index", ""); - }); - }); - } - }); - iconContainer$.data("clickTimeline").play().then(() => { - iconContainer$.data("isTogglingOn", false); - iconContainer$.data("isToggled", true); - }); - } - } - }); - // Apply hover timelines to right (accept) interaction pad - rightInteractionPad$.data("hoverTimeline", U.gsap.effects.csqEnterRight(csqContainer)); - rightInteractionPad$.on({ - mouseenter: function () { - if (iconContainer$.data("isToggled")) { - rightInteractionPad$.data("hoverTimeline").play(); - } - }, - mouseleave: function () { - rightInteractionPad$.data("hoverTimeline").reverse(); - } - }); - // Apply hover timeline to left (resist/armor/special) interaction pad - leftInteractionPad$.data("hoverTimeline", U.gsap.effects.csqEnterLeft(csqContainer)); - leftInteractionPad$.on({ - mouseenter: function () { - if (iconContainer$.data("isToggled")) { - leftInteractionPad$.data("hoverTimeline").play(); - } - }, - mouseleave: function () { - leftInteractionPad$.data("hoverTimeline").reverse(); - } - }); - // Apply hover timelines to specific left interaction pads - resistInteractionPad$.data("hoverTimeline", U.gsap.effects.csqEnterSubLeft(csqContainer, { type: "resist" })); - resistInteractionPad$.on({ - mouseenter: function () { - if (iconContainer$.data("isToggled")) { - resistInteractionPad$.data("hoverTimeline").play(); - } - }, - mouseleave: function () { - if (iconContainer$.data("isToggled")) { - resistInteractionPad$.data("hoverTimeline").reverse(); - } - } - }); - armorInteractionPad$.data("hoverTimeline", U.gsap.effects.csqEnterSubLeft(csqContainer, { type: "armor" })); - armorInteractionPad$.on({ - mouseenter: function () { - if (iconContainer$.data("isToggled")) { - armorInteractionPad$.data("hoverTimeline").play(); - } - }, - mouseleave: function () { - if (iconContainer$.data("isToggled")) { - armorInteractionPad$.data("hoverTimeline").reverse(); - } - } - }); - specialInteractionPad$.data("hoverTimeline", U.gsap.effects.csqEnterSubLeft(csqContainer, { type: "special" })); - specialInteractionPad$.on({ - mouseenter: function () { - if (iconContainer$.data("isToggled")) { - specialInteractionPad$.data("hoverTimeline").play(); - } - }, - mouseleave: function () { - if (iconContainer$.data("isToggled")) { - specialInteractionPad$.data("hoverTimeline").reverse(); - } - } - }); - } - }); - } -} -export default BladesConsequence; diff --git a/module/classes/BladesDialog.js b/module/classes/BladesDialog.js deleted file mode 100644 index 101c8b64..00000000 --- a/module/classes/BladesDialog.js +++ /dev/null @@ -1,647 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { ApplyTooltipAnimations } from "../core/gsap.js"; -import U from "../core/utilities.js"; -import { BladesActor } from "../documents/BladesActorProxy.js"; -import BladesItem from "../BladesItem.js"; -import BladesRoll from "./BladesRoll.js"; -export var SelectionCategory; -(function (SelectionCategory) { - SelectionCategory["Heritage"] = "Heritage"; - SelectionCategory["Background"] = "Background"; - SelectionCategory["Vice"] = "Vice"; - SelectionCategory["Playbook"] = "Playbook"; - SelectionCategory["Reputation"] = "Reputation"; - SelectionCategory["Preferred_Op"] = "Preferred_Op"; - SelectionCategory["Gear"] = "Gear"; - SelectionCategory["Ability"] = "Ability"; - SelectionCategory["Faction"] = "Faction"; - SelectionCategory["Upgrade"] = "Upgrade"; - SelectionCategory["Cohort_Gang"] = "Cohort_Gang"; - SelectionCategory["Cohort_Expert"] = "Cohort_Expert"; - SelectionCategory["Feature"] = "Feature"; - SelectionCategory["Stricture"] = "Stricture"; - SelectionCategory["VicePurveyor"] = "VicePurveyor"; - SelectionCategory["Acquaintance"] = "Acquaintance"; - SelectionCategory["Friend"] = "Friend"; - SelectionCategory["Rival"] = "Rival"; - SelectionCategory["Crew"] = "Crew"; - SelectionCategory["Member"] = "Member"; - SelectionCategory["Contact"] = "Contact"; -})(SelectionCategory || (SelectionCategory = {})); -export var BladesDialogType; -(function (BladesDialogType) { - BladesDialogType["Input"] = "Input"; - BladesDialogType["Selection"] = "Selection"; - BladesDialogType["Consequence"] = "Consequence"; -})(BladesDialogType || (BladesDialogType = {})); -class BladesDialog extends Dialog { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "dialog"], - width: "auto", - height: "auto", - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "front" }] - }); - } - static Initialize() { - return loadTemplates([ - "systems/eunos-blades/templates/dialog-selection.hbs", - "systems/eunos-blades/templates/dialog-consequence.hbs", - "systems/eunos-blades/templates/dialog-input.hbs", - "systems/eunos-blades/templates/parts/dialog-consequence-block.hbs" - ]); - } - static async DisplaySimpleInputDialog(parent, prompt, target, flagTarget) { - const app = new BladesDialog({ - parent, - title: parent instanceof BladesRoll ? "Roll Input" : `${parent.name}: Input`, - dialogType: BladesDialogType.Input, - content: "", - prompt, - target, - flagTarget, - buttons: { - apply: { - icon: '', - label: "Apply", - callback: (html) => app - // .writeToRollInstance(html as JQuery) - }, - cancel: { - icon: '', - label: game.i18n.localize("Cancel"), - callback: (html) => { - eLog.checkLog3("dialog", "Callback Scope", { this: app, html }); - return false; - } - } - }, - default: "apply" - }, { classes: ["eunos-blades", "sheet", "dialog", "simple-input-dialog"] }); - return app._render(true, { width: app.width }).then(() => eLog.checkLog3("dialog", "Input Dialog Instance", { this: app })); - } - static async DisplaySelectionDialog(parent, title, docType, tabs, tags) { - const app = new BladesDialog({ - parent, - title, - docType, - tabs, - tags: tags?.filter((tag) => tag !== ""), - content: "", - buttons: { - cancel: { - icon: '', - label: game.i18n.localize("Cancel"), - callback: (html) => { - eLog.checkLog3("dialog", "Callback Scope", { this: this, html }); - return false; - } - } - }, - default: "cancel" - }); - return app.hasItems ? app.render(true, { width: app.width }) : undefined; - } - // static async DisplayRollConsequenceDialog(rollInst: BladesRoll) { - // const app: BladesDialog = new BladesDialog({ - // parent: rollInst, - // title: "Consequences", - // dialogType: BladesDialogType.Consequence, - // content: "", - // buttons: { - // apply: { - // icon: '', - // label: "Apply", - // callback: (html: HTMLElement|JQuery) => (app as BladesDialog) - // .writeToRollInstance(html as JQuery) - // }, - // cancel: { - // icon: '', - // label: game.i18n.localize("Cancel"), - // callback: (html: JQuery|HTMLElement) => { - // eLog.checkLog3("dialog", "Callback Scope", {this: app, html}); - // return false; - // } - // } - // }, - // default: "apply" - // }, {classes: ["eunos-blades", "sheet", "dialog", "consequence-dialog"]}); - // return app._render(true, {width: app.width}).then(() => eLog.checkLog3("dialog", "Dialog Instance", {this: app})); - // } - get template() { return `systems/eunos-blades/templates/dialog-${U.lCase(this.dialogType)}.hbs`; } - get hasItems() { - return Object.values(this.tabs ?? []).some((tabItems) => tabItems.length > 0); - } - parent; - tabs; - dialogType; - tags = []; - width; - docType; - // csqData?: Record< - // Position, - // Record< - // RollResult.partial|RollResult.fail, - // Record< - // string, - // BladesRoll.ConsequenceData - // > - // > - // >; - prompt; - target; - flagTarget; - constructor(data, options) { - super(data, options); - this.dialogType = data.dialogType ?? BladesDialogType.Selection; - this.parent = data.parent; - this.width = options?.width ?? 500; - this.prompt = data.prompt; - this.target = data.target; - this.flagTarget = data.flagTarget; - switch (this.dialogType) { - case BladesDialogType.Input: return; - case BladesDialogType.Selection: - this.constructSelectionData(data /* , options */); - return; - // case BladesDialogType.Consequence: this.csqData = this.constructConsequenceData(data/* , options */); return; - default: throw new Error(`Unrecognized type for BladesDialog constructor: '${this.dialogType}'`); - } - } - constructSelectionData(data /* , options?: Partial */) { - const validTabs = []; - if (!data.tabs) { - return; - } - for (const [tabName, tabItems] of Object.entries(data.tabs)) { - if (tabItems.length === 0) { - delete data.tabs[tabName]; - } - else { - validTabs.push(tabName); - } - } - if (validTabs.length === 1 && !("Main" in data.tabs)) { - data.tabs.Main = [...data.tabs[validTabs[0]]]; - delete data.tabs[validTabs[0]]; - } - this.docType = data.docType; - this.tabs = data.tabs; - this.tags = data.tags ?? []; - this.width = 150 * Math.ceil(Math.sqrt(Object.values(data.tabs)[0].length)); - } - // constructConsequenceData(data: BladesDialog.Data/* , options?: Partial */) { - // eLog.checkLog3("dialog", "constructConsequenceData", {incoming: {...data}}); - // if (!(this.parent instanceof BladesRoll)) { throw new Error("Cannot call 'constructConsequenceData' without a rollInst parent!"); } - // // Get existing consequence data, if any, on roll instance - // const rollCsqData = this.parent.data.consequenceData ?? {}; - // // Extend consequence data by applying new blank consequence instances, - // // so at least three csq entries are available for each position/result combination - // (Object.values(Position) as Position[]).forEach((rollPos: Position) => { - // rollCsqData[rollPos] ??= { - // [RollResult.partial]: {}, - // [RollResult.fail]: {} - // }; - // ([RollResult.partial, RollResult.fail] as const).forEach((rollResult: RollResult.partial|RollResult.fail) => { - // rollCsqData[rollPos] ??= {}; - // rollCsqData[rollPos][rollResult] ??= {}; - // while (Object.values(rollCsqData[rollPos][rollResult as RollResult.partial|RollResult.fail]).length < 3) { - // const blankCsqData: BladesConsequence.Data = { - // id: randomID() as IDString, - // name: "", - // type: "", - // attribute: "" - // }; - // rollCsqData[rollPos][rollResult as RollResult.partial|RollResult.fail][blankCsqData.id] = blankCsqData; - // } - // }); - // }); - // this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster); - // return rollCsqData; - // } - getData() { - const data = super.getData(); - switch (this.dialogType) { - case BladesDialogType.Input: return this.prepareInputData(data); - case BladesDialogType.Selection: return this.prepareSelectionData(data); - // case BladesDialogType.Consequence: return this.prepareConsequenceData(data); - default: return null; - } - } - prepareInputData(data) { - data.prompt = this.prompt; - data.target = this.target; - data.flagTarget = this.flagTarget; - return data; - } - prepareSelectionData(data) { - data.title = this.title; - data.tabs = this.tabs; - data.docType = this.docType; - data.tags = this.tags; - return data; - } - // prepareConsequenceData(data: BladesDialog.Data) { - // eLog.checkLog3("dialog", "prepareConsequenceData this.csqData", {...this.csqData}); - // eLog.checkLog3("dialog", "prepareConsequenceData", {incoming: {...data}}); - // data.consequenceData = this.csqData; - // data.consequenceTypeOptions = this.consequenceTypeOptions; - // data.consequenceTypeOptionsAll = Object.keys(C.ConsequenceDisplay) - // .map((cType) => ({value: cType, display: cType})); - // data.consequenceAttributeOptions = [ - // {value: AttributeTrait.insight, display: "Insight"}, - // {value: AttributeTrait.prowess, display: "Prowess"}, - // {value: AttributeTrait.resolve, display: "Resolve"} - // ]; - // eLog.checkLog3("dialog", "prepareConsequenceData", {outgoing: {...data}}); - // return data; - // } - // get consequenceTypeOptions(): Record< - // Position, - // Record< - // RollResult.partial|RollResult.fail, - // Array> - // > - // > { - // if (this.parent instanceof BladesRoll) { - // const returnData: Partial> - // > - // >> = {}; - // [Position.controlled, Position.risky, Position.desperate].forEach((pos) => { - // returnData[pos] = { - // [RollResult.partial]: C.Consequences[pos][RollResult.partial] - // .map((cType) => ({value: cType, display: cType})), - // [RollResult.fail]: C.Consequences[pos][RollResult.fail] - // .map((cType) => ({value: cType, display: cType})) - // }; - // }); - // return returnData as Record< - // Position, - // Record< - // RollResult.partial|RollResult.fail, - // Array> - // > - // >; - // } - // return {} as never; - // } - updateInputText(inputElem$) { - const value = inputElem$.val(); - if (this.parent instanceof BladesRoll) { - const flagTarget = inputElem$.data("flagTarget"); - eLog.checkLog3("dialog", "updateInputText", { value, flagTarget }); - this.parent.updateTarget(flagTarget, value) - .then(() => this.parent.renderRollCollab_SocketCall()); - } - else if (this.parent instanceof BladesItem || this.parent instanceof BladesActor) { - this.parent.update({ [inputElem$.data("target")]: inputElem$.val() }); - } - } - // updateConsequenceType(csqElem$: JQuery, cData: BladesConsequence.Data) { - // const type$ = csqElem$.find(".roll-consequence-type-select") as JQuery; - // const typeVal = type$.val() as string|undefined; - // if (typeVal && typeVal in ConsequenceType) { - // cData.type = typeVal as ConsequenceType; - // cData.icon = C.ConsequenceIcons[cData.type]; - // cData.typeDisplay = C.ConsequenceDisplay[cData.type]; - // } - // } - // updateConsequenceAttribute(csqElem$: JQuery, cData: BladesConsequence.Data) { - // if (/Insight/.exec(cData.type)) { cData.attribute = AttributeTrait.insight; } - // else if (/Prowess/.exec(cData.type)) { cData.attribute = AttributeTrait.prowess; } - // else if (/Resolve/.exec(cData.type)) { cData.attribute = AttributeTrait.resolve; } - // else { - // const attribute$ = csqElem$.find(".roll-consequence-attribute-select") as JQuery; - // const attrVal = attribute$.val() as AttributeTrait|undefined; - // if (attrVal) { - // cData.attribute = attrVal; - // } - // } - // } - // updateConsequenceAttributeVal(cData: BladesConsequence.Data) { - // if (this.parent.rollPrimaryDoc instanceof BladesPC) { - // cData.attributeVal = this.parent.rollPrimaryDoc.attributes[cData.attribute as AttributeTrait]; - // } else if (this.parent.rollPrimaryDoc?.parent instanceof BladesPC) { - // cData.attributeVal = this.parent.rollPrimaryDoc.parent.attributes[cData.attribute as AttributeTrait]; - // } else { - // eLog.error(`Unable to get attribute from rollPrimaryDoc '${this.parent.rollPrimaryDoc?.name}' of type '${this.parent.rollPrimaryDoc?.rollPrimaryType}' (may need to log via flags if either of the previous show 'undefined'.`); - // } - // } - // getSelectedResistOption(cData: BladesConsequence.Data): BladesConsequence|false { - // return cData.resistTo - // ? new BladesConsequence(cData.resistTo) - // : false; - // } - // updateConsequenceResist(csqElem$: JQuery, cData: BladesConsequence.Data) { - // const resistOptions: Record = cData.resistOptions ?? {}; - // // If consequence is already minimal, toggle resistNegates to true and set 'resistTo' to None-type - // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - // .map(([csqType]) => csqType as ConsequenceType); - // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) { - // cData.resistNegates = true; - // const noneCsq = BladesConsequence.None; - // cData.resistOptions = {[noneCsq.id]: noneCsq}; - // cData.resistTo = noneCsq; - // return; - // } else { - // // Clear 'resistTo' (will be redetermined below) - // delete cData.resistTo; - // delete cData.resistNegates; - // csqElem$.find(".consequence-resist-option").each((_, elem) => { - // const resCsqID = $(elem).data("csq-id"); - // resistOptions[resCsqID] ??= {id: resCsqID, name: "", type: undefined, isSelected: false}; - // // Update Resistance Option Type - // const resType$ = $(elem).find(".roll-consequence-type-select") as JQuery; - // const resTypeVal = resType$.val() as string|undefined; - // if (resTypeVal && resTypeVal in ConsequenceType) { - // resistOptions[resCsqID].type = resTypeVal as ConsequenceType; - // resistOptions[resCsqID].icon = C.ConsequenceIcons[resistOptions[resCsqID].type as ConsequenceType]; - // resistOptions[resCsqID].typeDisplay = C.ConsequenceDisplay[resistOptions[resCsqID].type as ConsequenceType]; - // } - // // Update Resistance Option Name - // const resName$ = $(elem).find(".consequence-name") as JQuery; - // const resNameVal = resName$.val(); - // resistOptions[resCsqID].name = resNameVal ?? ""; - // // If this is selected, update 'resistTo' data as well - // if (resistOptions[resCsqID].isSelected) { - // cData.resistTo = resistOptions[resCsqID]; - // } - // }); - // } - // cData.resistOptions = resistOptions; - // } - // updateConsequenceArmorResist(_csqElem$: JQuery, cData: BladesConsequence.Data) { - // // If consequence is already minimal, toggle armorNegates to true and set 'armorTo' to None-type - // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - // .map(([csqType]) => csqType as ConsequenceType); - // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) { - // cData.armorNegates = true; - // cData.armorTo = BladesConsequence.None; - // } else { - // delete cData.armorNegates; - // cData.armorTo = this.getSelectedResistOption(cData); - // } - // } - // updateConsequenceSpecialArmorResist(_csqElem$: JQuery, cData: BladesConsequence.Data) { - // // If consequence is already minimal, toggle specialArmorNegates to true and set 'specialTo' to None-type - // const minimalCsqTypes = Object.entries(C.ResistedConsequenceTypes) - // .filter(([_, rCsqType]) => rCsqType === ConsequenceType.None) - // .map(([csqType]) => csqType as ConsequenceType); - // if (minimalCsqTypes.includes(cData.type as ConsequenceType)) { - // cData.specialArmorNegates = true; - // cData.specialTo = BladesConsequence.None; - // } else { - // delete cData.specialArmorNegates; - // cData.specialArmorNegates ??= false; - // cData.specialTo = this.getSelectedResistOption(cData); - // } - // } - // updateConsequenceData( - // html: JQuery, - // cData: BladesConsequence.Data - // ) { - // const csqElem$ = html.find(`.roll-consequence-row[data-csq-id='${cData.id}']`); - // // Update Type - // this.updateConsequenceType(csqElem$, cData); - // // Update Name - // if (cData.type === ConsequenceType.None) { - // cData.name = ""; - // } else { - // const name$ = csqElem$.find(".consequence-name") as JQuery; - // const nameVal = name$.val(); - // cData.name = nameVal ?? ""; - // } - // // Update Resistance Attribute - // this.updateConsequenceAttribute(csqElem$, cData); - // this.updateConsequenceAttributeVal(cData); - // // Update Resistance Options - // this.updateConsequenceResist(csqElem$, cData); - // // Update Armor Options - // if (( this.parent).canResistWithArmor(cData)) { - // cData.isDisplayingArmorToggle = true; - // this.updateConsequenceArmorResist(csqElem$, cData); - // } else { - // cData.isDisplayingArmorToggle = false; - // } - // // Update Special Armor Options - // if (( this.parent).canResistWithSpecialArmor(cData)) { - // cData.isDisplayingSpecialArmorToggle = true; - // this.updateConsequenceSpecialArmorResist(csqElem$, cData); - // } else { - // cData.isDisplayingSpecialArmorToggle = false; - // } - // return cData; - // } - // updateConsequenceDialog(html: JQuery, isRendering = true) { - // if (!(this.parent instanceof BladesRoll)) { return; } - // if (!this.csqData) { return; } - // eLog.checkLog3("dialog", "updateConsequenceDialog() this.csqData INCOMING", {...this.csqData}); - // const {csqData} = this; - // const {rollPrimaryDoc} = this.parent; - // if (!(rollPrimaryDoc instanceof BladesPC)) { return; } - // (Object.keys(csqData) as Position[]).forEach((rollPos) => { - // const positionCsqData = csqData[rollPos]; - // (Object.keys(csqData[rollPos]) as [RollResult.partial, RollResult.fail]).forEach((rollResult) => { - // positionCsqData[rollResult] = U.objMap( - // positionCsqData[rollResult], - // (cData: BladesConsequence.Data) => this.updateConsequenceData(html, cData) - // ); - // }); - // csqData[rollPos] = positionCsqData; - // }); - // this.csqData = csqData; - // eLog.checkLog3("dialog", "updateConsequenceDialog() this.csqData OUTGOING", {...this.csqData}); - // if (isRendering) { - // this.render(); - // } - // } - // async writeToRollInstance(html: JQuery) { - // if (this.parent instanceof BladesRoll) { - // this.updateConsequenceDialog(html, false); - // await this.parent.updateTarget("consequenceData", this.csqData); - // } - // } - // _consequenceAI?: BladesAI; - // getCsqDataFromElem(elem: HTMLElement, paramCount = 3): string[] { - // const dataAction = elem.dataset.action; - // if (dataAction) { - // const params = dataAction.split(/-/).reverse().slice(0, paramCount); - // return params.reverse(); - // } - // return []; - // } - // async queryAI(event: ClickEvent) { - // if (!this.csqData) { return; } - // // If the AI generator has not been initialized, do so. - // if (!this._consequenceAI) { - // this._consequenceAI = new BladesAI(AGENTS.ConsequenceAdjuster); - // } - // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - // const csqName: string|undefined = - // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]?.name; - // if (csqName) { - // const response = await this._consequenceAI?.query(csqName, csqName); - // if (response) { - // this.refreshResistanceOptions(rollPosition as Position, rollResult as RollResult.partial|RollResult.fail, csqID, response.split("|")); - // } - // } - // } - // async spawnBlankResistOption(event: ClickEvent) { - // if (!this.csqData) { return; } - // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - // const rCsqID = randomID() as IDString; - // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID] - // .resistOptions = { - // [rCsqID]: { - // id: rCsqID, - // name: "", - // type: undefined, - // isSelected: true - // } - // }; - // this.render(); - // } - // async setFlagVal(target: string, value: unknown) { - // if (this.parent instanceof BladesRoll) { - // await this.parent.updateTarget(target, value); - // } - // } - // async refreshResistanceOptions(rollPosition: Position, rollResult: RollResult, cID: string, rOptions: string[]) { - // if (!this.csqData) { return; } - // const cData = this.csqData[rollPosition][rollResult as RollResult.partial|RollResult.fail][cID]; - // if (!cData) { return; } - // const cType = cData.type as keyof typeof C["ResistedConsequenceTypes"]; - // const rType = C.ResistedConsequenceTypes[cType] ?? undefined; - // const resistOptions: Record = {}; - // for (let i = 0; i < rOptions.length; i++) { - // const rID = randomID() as IDString; - // resistOptions[rID] = { - // id: rID, - // name: rOptions[i], - // isSelected: false - // }; - // if (rType) { - // resistOptions[rID].type = rType; - // resistOptions[rID].typeDisplay = C.ConsequenceDisplay[rType]; - // resistOptions[rID].icon = C.ConsequenceIcons[rType]; - // } - // } - // this.csqData[rollPosition][rollResult as RollResult.partial|RollResult.fail][cID].resistOptions = resistOptions; - // eLog.checkLog3("dialog", "addResistanceOptions() this.csqData", {...this.csqData}); - // this.render(); - // } - // async selectResistOption(event: ClickEvent) { - // if (!this.csqData) { return; } - // const [rollPosition, rollResult, csqID, resID] = this.getCsqDataFromElem(event.currentTarget, 4); - // eLog.checkLog3("dialog", "... Action Passed", {rollResult, csqIndex: csqID, resIndex: resID}); - // // Get consequence data - // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]; - // cData.resistOptions ??= {}; - // // Toggle clicked resistance option - // cData.resistOptions[resID].isSelected = !cData.resistOptions[resID].isSelected; - // // If resistance option is now selected... - // if (cData.resistOptions[resID].isSelected) { - // // ... deselect & hide other options - // Object.keys(cData.resistOptions) - // .filter((key) => key !== resID) - // .forEach((key) => { - // Object.assign(cData.resistOptions?.[key] ?? {}, {isSelected: false, isVisible: false}); - // }); - // // ... and set 'resistTo' to this consequence. - // cData.resistTo = cData.resistOptions[resID]; - // } else { - // // Otherwise, set 'resistTo' to false... - // cData.resistTo = false; - // // ... and unhide other options. - // Object.keys(cData.resistOptions) - // .filter((key) => key !== resID) - // .forEach((key) => { - // Object.assign(cData.resistOptions?.[key] ?? {}, {isVisible: true}); - // }); - // } - // // Assign new cData instance. - // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID] = cData; - // this.render(); - // } - // async clearResistOptions(event: ContextMenuEvent) { - // if (!this.csqData) { return; } - // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - // this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID].resistOptions = {}; - // this.render(); - // } - // async toggleArmor(event: ClickEvent) { - // if (!this.csqData) { return; } - // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]; - // cData.canArmor = !cData.canArmor; - // this.render(); - // } - // async toggleSpecialArmor(event: ClickEvent) { - // if (!this.csqData) { return; } - // const [rollPosition, rollResult, csqID] = this.getCsqDataFromElem(event.currentTarget); - // const cData = this.csqData[rollPosition as Position][rollResult as RollResult.partial|RollResult.fail][csqID]; - // cData.canSpecialArmor = !cData.canSpecialArmor; - // this.render(); - // } - activateListeners(html) { - super.activateListeners(html); - // ~ Tooltips - ApplyTooltipAnimations(html); - switch (this.dialogType) { - case BladesDialogType.Input: - this.activateInputListeners(html); - break; - case BladesDialogType.Selection: - this.activateSelectionListeners(html); - break; - // case BladesDialogType.Consequence: { - // this.activateConsequenceListeners(html); - // Select --> updateConsequenceDialog -> updateConsequenceData(each csq) - // break; - // } - } - } - activateInputListeners(html) { - html.find("textarea").on({ change: (event) => this.updateInputText($(event.currentTarget)) }); - } - activateSelectionListeners(html) { - const self = this; - // ~ Changing Width on Tab Change Depending on Number of Items - html.find(".nav-tabs .tab-selector").on("click", (event) => { - const tabIndex = U.pInt($(event.currentTarget).data("tab")); - const numItems = Object.values(self.tabs ?? [])[tabIndex].length; - const width = U.pInt(150 * Math.ceil(Math.sqrt(numItems))); - eLog.checkLog3("nav", "Nav Tab Size Recalculation", { tabIndex, numItems, width }); - this.render(false, { width }); - }); - // ~ Item Control - html.find("[data-item-id]").on("click", function () { - if ($(this).parent().hasClass("locked")) { - return; - } - const docId = $(this).data("itemId"); - const docType = $(this).data("docType"); - eLog.checkLog("dialog", "[BladesDialog] on Click", { elem: this, docId, docType, parent: self.parent }); - if (self.parent instanceof BladesActor) { - if (docType === "Actor") { - self.parent.addSubActor(docId, self.tags); - } - else if (docType === "Item") { - self.parent.addSubItem(docId); - } - } - self.close(); - }); - } - async close() { - $("#eunos-blades-tooltips > *").remove(); - super.close(); - } -} -export default BladesDialog; diff --git a/module/classes/BladesDirector.js b/module/classes/BladesDirector.js deleted file mode 100644 index 4ed299f5..00000000 --- a/module/classes/BladesDirector.js +++ /dev/null @@ -1,682 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import U from "../core/utilities.js"; -import C, { ClockKey_SVGDATA, BladesPhase, ClockKeyDisplayMode } from "../core/constants.js"; -import BladesClockKey, { BladesClock } from "./BladesClockKey.js"; -class BladesDirector { - // #region INITIALIZATION ~ - // #region >> Single-Instance Factory Construction ~ - static instance; - _id; - constructor() { - this._id = randomID(); - } - static getInstance() { - return (BladesDirector.instance ??= new BladesDirector()); - } - // #endregion - static async Initialize() { - // Define hook that re-renders overlay on scene change. - Hooks.on("renderApplication", async () => { - game.eunoblades.Director.initClockKeySection(true); - if (game.user.isGM) { - await game.eunoblades.ClockKeeper.update({ "system.targetScene": game.scenes.current.id }); - game.eunoblades.ClockKeeper.render(); - } - }); - // game.eunoblades.Director.renderOverlay_SocketResponse(); - // Return asynchronous template loading. - return loadTemplates([ - "systems/eunos-blades/templates/overlay/blades-overlay.hbs", - "systems/eunos-blades/templates/overlay/location.hbs", - "systems/eunos-blades/templates/overlay/score-panel.hbs", - "systems/eunos-blades/templates/overlay/npc-portrait.hbs", - "systems/eunos-blades/templates/overlay/pc-portrait.hbs", - "systems/eunos-blades/templates/overlay/cohort-portrait.hbs", - "systems/eunos-blades/templates/overlay/crew-status-bar.hbs", - "systems/eunos-blades/templates/overlay/game-phase-bar.hbs", - "systems/eunos-blades/templates/overlay/notices/push.hbs" - ]); - } - // #region >> Sockets ~ - static InitSockets() { - const director = BladesDirector.getInstance(); - socketlib.system.register("renderOverlay_SocketCall", director.renderOverlay_SocketResponse.bind(director)); - director.initClockSockets(); - director.initScorePanelSockets(); - director.initLocationSockets(); - director.initNPCSockets(); - director.initPCSockets(); - director.initCohortSockets(); - director.initCrewSockets(); - director.initNotificationSockets(); - director.initTransitionSockets(); - } - // #endregion - // #endregion - // #region OVERLAY ~ - // #region >> Overlay Elements$ ~ - _overlayContainer; - _overlayContainer$; - get overlayContainer() { - if (!this._overlayContainer) { - [this._overlayContainer] = $("#blades-overlay"); - } - if (!this._overlayContainer) { - $("body.vtt").append("
"); - [this._overlayContainer] = $("#blades-overlay"); - } - return this._overlayContainer; - } - get overlayContainer$() { - if (!this._overlayContainer$) { - this._overlayContainer$ = $(this.overlayContainer); - } - return this._overlayContainer$; - } - get clockKeySection$() { - return this.overlayContainer$.find(".overlay-section-clock-keys"); - } - get locationSection$() { - return this.overlayContainer$.find(".overlay-section-location"); - } - get scorePanelSection$() { - return this.overlayContainer$.find(".overlay-section-score-panel"); - } - get npcSection$() { - return this.overlayContainer$.find(".overlay-section-npcs"); - } - get playerSection$() { - return this.overlayContainer$.find(".overlay-section-players"); - } - get crewSection$() { - return this.overlayContainer$.find(".overlay-section-crew"); - } - get notificationSection$() { - return this.overlayContainer$.find(".overlay-section-notifications"); - } - get transitionSection$() { - return this.overlayContainer$.find(".overlay-section-transitions"); - } - get tooltipSection$() { - return this.overlayContainer$.find(".overlay-section-tooltips"); - } - get svgData() { return ClockKey_SVGDATA; } - // #endregion - // #region >> Rendering ~ - renderOverlay_SocketCall() { - if (!game.user.isGM) { - return; - } - if (!this.overlayContainer) { - return; - } - socketlib.system.executeForEveryone("renderOverlay_SocketCall"); - } - async renderOverlay_SocketResponse() { - // Render the overlay element - const overlayContent = await renderTemplate("systems/eunos-blades/templates/overlay/blades-overlay.hbs", this); - this.overlayContainer$.empty().append(overlayContent); - // Initialize clock key section - this.initClockKeySection(); - // Initialize tooltip section - this.initTooltipSection(); - } - // #endregion - // #endregion - // #region CLOCKS & CLOCK KEYS ~ - // #region >> INITIALIZATION ~ - initClockKeySection(isResetting = false) { - if (isResetting) { - this.clockKeySection$.empty(); - } - // Render keys that are visible - const visibleSceneKeys = U.shuffle(this.sceneKeys.filter((key) => key.isVisible)); - let staggerDelay = 0; - while (visibleSceneKeys.length) { - const key = visibleSceneKeys.shift(); - if (key) { - setTimeout(() => this.renderClockKey(key), staggerDelay * 1000); - staggerDelay += 0.5; - } - } - // Apply item dragger - setTimeout(() => { - // Create dragger instance for dragging clocks & clock keys onto, e.g, rolls - }, staggerDelay * 1000); - } - initClockSockets() { - socketlib.system.register("renderClockKey_SocketCall", BladesDirector.renderClockKey_SocketResponse.bind(BladesDirector)); - socketlib.system.register("pullKey_SocketCall", BladesDirector.pullKey_SocketResponse.bind(BladesDirector)); - socketlib.system.register("fadeInName_SocketCall", BladesClockKey.fadeInName_SocketResponse.bind(BladesClockKey)); - socketlib.system.register("fadeOutName_SocketCall", BladesClockKey.fadeOutName_SocketResponse.bind(BladesClockKey)); - socketlib.system.register("reveal_SocketCall", BladesClock.reveal_SocketResponse.bind(BladesClock)); - socketlib.system.register("hide_SocketCall", BladesClock.hide_SocketResponse.bind(BladesClock)); - socketlib.system.register("activate_SocketCall", BladesClock.activate_SocketResponse.bind(BladesClock)); - socketlib.system.register("deactivate_SocketCall", BladesClock.deactivate_SocketResponse.bind(BladesClock)); - socketlib.system.register("fadeInClockName_SocketCall", BladesClock.fadeInClockName_SocketResponse.bind(BladesClock)); - socketlib.system.register("fadeOutClockName_SocketCall", BladesClock.fadeOutClockName_SocketResponse.bind(BladesClock)); - socketlib.system.register("highlight_SocketCall", BladesClock.highlight_SocketResponse.bind(BladesClock)); - socketlib.system.register("unhighlight_SocketCall", BladesClock.unhighlight_SocketResponse.bind(BladesClock)); - socketlib.system.register("changeSegments_SocketCall", BladesClock.changeSegments_SocketResponse.bind(BladesClock)); - } - // #endregion - get sceneKeys() { return game.eunoblades.ClockKeeper.getSceneKeys(game.scenes.current.id); } - // #region >> Rendering (Dropping) Clock Keys ~ - dropKey_Animation(key, keyElems$) { - const { container$, label$, imgContainer$, clocks } = keyElems$ ?? key.getElements$(game.eunoblades.Director.clockKeySection$); - const keySwingTimeline = imgContainer$.data("keySwingTimeline"); - // Construct timeline for revealing clock key - const tl = U.gsap.timeline() - .call(() => { keySwingTimeline.seek("NEUTRAL").play(); }) - .from(container$, { - y: -800, - ease: "bounce", - duration: 1 - }, 0) - .to(container$, { autoAlpha: 1, duration: 0.5, ease: "power2" }, 0); - // Reveal visible clocks - key.visibleClocks.forEach((clock, i) => { - tl.add(() => { clock.reveal_Animation(clocks[clock.id]); }, i === 0 ? ">" : "<+0.15"); - }); - // Reveal key label, if visible - if (key.name && key.isNameVisible) { - tl.blurReveal(label$, { - ignoreMargin: true, - duration: 0.75 - }, "<+0.05"); - } - } - prepareClockKeyTimelines(key, keyElems$) { - const { container$, imgContainer$, elem$, label$, clocks } = keyElems$; - // Initialize element starting properties - U.gsap.set(container$, { pointerEvents: "auto" }); - U.gsap.set(elem$, { filter: "brightness(1)" }); - U.gsap.set(imgContainer$, { transformOrigin: "50% 10%" }); - // Retrieve element starting properties - const keyElemScale = U.gsap.getProperty(container$[0], "scale"); - // Timeline: Swinging key timeline - imgContainer$.data("keySwingTimeline", U.gsap.timeline({ paused: true, repeat: -1, yoyo: true }) - .fromTo(imgContainer$, { rotateZ: -1 }, { rotateZ: 1, duration: 3, ease: "sine.inOut" }) - .addLabel("NEUTRAL", 1.5) - .seek("NEUTRAL")); - // Timeline: Hover over clock key - container$.data("hoverOverTimeline", U.gsap.timeline({ - paused: true, - data: { key, imgContainer$, label$, isNameRevealed: false }, - onStart() { - this.data.imgContainer$.data("keySwingTimeline") - .tweenTo("NEUTRAL", { - duration: 0.25, - ease: "back.out(1.5)" - }); - if (this.data.key.name && !this.data.key.isNameVisible) { - this.data.isNameRevealed = true; - U.gsap.effects.blurReveal(this.data.label$, { - ignoreMargin: true, - duration: 0.5 - }); - } - }, - onReverseComplete() { - this.data.imgContainer$.data("keySwingTimeline") - .seek("NEUTRAL") - .play(); - if (this.data.isNameRevealed) { - this.data.isNameRevealed = false; - U.gsap.effects.blurRemove(this.data.label$, { - ignoreMargin: true, - duration: 0.5 - }); - } - } - }) - .to(elem$, { filter: "brightness(1.5)", scale: keyElemScale * 1.25, duration: 0.5, ease: "sine" })); - // Timelines: Hover over clocks - key.clocks.forEach((clock) => { - const { clockContainer$, clockLabel$, clockElem$ } = clocks[clock.id]; - if (!clockContainer$?.length) { - throw new Error(`[BladesDirector.prepareClockKeyTimelines] Error clockContainer$ not found for clock '${clock.id}' of key '${key.id}'.`); - } - U.gsap.set(clockContainer$, { pointerEvents: "auto" }); - clockContainer$.data("hoverOverTimeline", U.gsap.timeline({ - paused: true, - data: { clock, clockLabel$, isNameRevealed: false }, - onStart() { - if (this.data.clock.name && !this.data.clock.isNameVisible) { - this.data.isNameRevealed = true; - U.gsap.effects.blurReveal(this.data.clockLabel$, { - ignoreMargin: true, - duration: 0.5 - }); - } - }, - onReverseComplete() { - if (this.data.isNameRevealed) { - this.data.isNameRevealed = false; - U.gsap.effects.blurRemove(this.data.clockLabel$, { - ignoreMargin: true, - duration: 0.5 - }); - } - } - }) - .to(clockElem$, { filter: "brightness(1.5)", scale: 1.25, duration: 0.25, ease: "sine" })); - }); - } - async activateClockKeyListeners(key, keyElems$) { - const { container$, clocks } = keyElems$; - if (game.user.isGM) { - // === GM-ONLY LISTENERS === - // Double-Click a Clock Key = Open ClockKeeper sheet - container$.on("dblclick", async () => { - game.eunoblades.ClockKeeper.sheet?.render(true); - }); - // Right-Click a Clock Key = Pull it - container$.on("contextmenu", async () => { - this.pullKey_SocketCall(key.id); - key.updateTarget("isVisible", false); - }); - } - else { - // === PLAYER-ONLY LISTENERS === - // Add listeners to container for mouseenter and mouseleave, that play and reverse timeline attached to element - container$.on("mouseenter", () => { - container$.data("hoverOverTimeline").play(); - }).on("mouseleave", () => { - container$.data("hoverOverTimeline").reverse(); - }); - // Now repeat this for each clock in the clock key - key.clocks.forEach((clock) => { - const { clockContainer$ } = clocks[clock.id]; - // Add listeners to clock for mouseenter and mouseleave, that play and reverse timeline attached to element - clockContainer$.on("mouseenter", () => { - if (clock.isVisible) { - clockContainer$.data("hoverOverTimeline").play(); - } - }).on("mouseleave", () => { - if (clock.isVisible) { - clockContainer$.data("hoverOverTimeline").reverse(); - } - }); - }); - } - } - async renderClockKey(key) { - await key.renderTo(this.clockKeySection$); - // If a position-dragger is present, remove it. - if (key.positionDragger) { - key.removePositionDragger(); - } - // Initialize clock key elements to overlay context - const keyElems$ = key.initElementsInContext(this.clockKeySection$, ClockKeyDisplayMode.full); - // If an overlayPosition has been set, apply to the container element: - if (key.overlayPosition) { - U.gsap.set(keyElems$.container$, { - left: key.overlayPosition.x, - top: key.overlayPosition.y - }); - } - // Prepare animation timelines & attach them to rendered elements - this.prepareClockKeyTimelines(key, keyElems$); - // Activate listeners for the rendered key - this.activateClockKeyListeners(key, keyElems$); - // Animate the key dropping into the overlay - this.dropKey_Animation(key, keyElems$); - } - async renderClockKey_SocketCall(keyID) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("renderClockKey_SocketCall", keyID); - } - static async renderClockKey_SocketResponse(keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - game.eunoblades.Director.renderClockKey(key); - } - // #endregion - // #region >> Un-Rendering (Pulling) Clock Keys ~ - pullKey_Animation(key) { - const { container$ } = key.getElements$(game.eunoblades.Director.clockKeySection$); - U.gsap.timeline() - .to(container$, { - y: -800, - ease: "back.in(1)", - duration: 0.75 - }) - .to(container$, { - opacity: 0, - ease: "power2.out", - duration: 0.25 - }, 0.75) - .call(() => { container$.remove(); }); - } - async pullKey_SocketCall(keyID) { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForEveryone("pullKey_SocketCall", keyID); - } - static pullKey_SocketResponse(keyID) { - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - game.eunoblades.Director.pullKey_Animation(key); - } - // #endregion - // #endregion - // #region SCORE PANEL ~ - // #region >> INITIALIZATION ~ - initScorePanelSockets() { - // tbd... - } - // #endregion - // ## Score Details - // - Small panel overlapping corner of Location - // - Engagement roll result - // - Plan & Detail - // - Target tier - activateScorePanelListeners() { - // tbd... - } - // #endregion - // #region LOCATIONS ~ - // #region >> INITIALIZATION ~ - initLocationSockets() { - // tbd... - } - // #endregion - // ## Locations - // - District wrapper/header - // - Faction wrapper/footer - // - Location main - // - Slide-scroll of sublocations - activateLocationListeners() { - // tbd... - } - // #endregion - // #region NPCs ~ - // #region >> INITIALIZATION ~ - initNPCSockets() { - // tbd... - } - // #endregion// ## NPCs - // - Linked to a location: When location is displayed, so are they. *(Can be linked to District wrapper, main Location, or sublocations)* - // - Portrait images close to the central location display, hover-over popups provide more detailed information from sheet or `BladesScore` instance - activateNPCListeners() { - // tbd... - } - // #endregion - // #region PCs, COHORTs, CREW ~ - // #region >> INITIALIZATION ~ - initPCSockets() { - // tbd... - } - initCohortSockets() { - // tbd... - } - initCrewSockets() { - // tbd... - } - // #endregion - // ## PCs - // - Display panels along bottom - // - Signal lights - activatePCListeners() { - // tbd... - } - // ## Cohorts - // - Smaller panels alongside the PCs - activateCohortListeners() { - // tbd... - } - // ## Crew - // - Limited information displayed, maybe bar beneath PCs showing Heat, Wanted Level… - activateCrewListeners() { - // tbd... - } - // #endregion - // #region NOTIFICATIONS ~ - // #region >> INITIALIZATION ~ - initNotificationSockets() { - socketlib.system.register("pushNotice_SocketCall", BladesDirector.pushNotice_SocketResponse.bind(BladesDirector)); - } - // #endregion - pushNotice_SocketCall(targets, config) { - const pushID = randomID(); - if (typeof targets === "string") { - if (targets === "ALL") { - return socketlib.system.executeForEveryone("pushNotice_SocketCall", pushID, config); - } - else if (targets === "GM") { - return socketlib.system.executeForAllGMs("pushNotice_SocketCall", pushID, config); - } - else { - targets = game.users.filter((user) => user.id === targets - || user.name === targets - || user.character?.id === targets - || user.character?.name === targets - || game.user.isGM).map((user) => user.id); - } - } - if (targets.length > 0) { - return socketlib.system.executeForUsers("pushNotice_SocketCall", targets, pushID, config); - } - return undefined; - } - static async pushNotice_SocketResponse(pushID, config) { - const director = game.eunoblades.Director; - const pushElem$ = $(await renderTemplate("systems/eunos-blades/templates/overlay/notices/push.hbs", { - id: pushID, - ...config - })) - .appendTo(director.notificationSection$) - .on("click", (event) => { director.$removePush(event.currentTarget); }) - .on("contextmenu", (event) => { director.$removeAndClear(event.currentTarget); }); - U.gsap.fromTo(pushElem$, { - x: 200, - skewX: 20, - autoAlpha: 0, - filter: "blur(10px)" - }, { - x: 0, - skewX: 0, - autoAlpha: 1, - filter: "blur(0px)", - duration: 0.5, - ease: "back" - }); - } - async $removePush(target) { - U.gsap.to(target, { - x: "+=200", - autoAlpha: 0, - ease: "power2", - duration: 0.5, - onComplete: function () { - $(target).remove(); - } - }); - } - async $removeAndClear(target) { - const targets = $(target).prevAll().get().reverse(); - targets.unshift(target); - U.gsap.to(targets, { - x: "+=200", - autoAlpha: 0, - ease: "power2", - duration: 0.5, - stagger: { - each: 0.5, - from: "start", - ease: "power1.inOut" - }, - onComplete: function () { - targets.forEach((targ) => $(targ).remove()); - } - }); - } - // #endregion - // #region TRANSITIONS ~ - // #region >> INITIALIZATION ~ - initTransitionSockets() { - // tbd... - } - // #endregion - // ## Transitions - async advanceGamePhase(phase) { - const nextPhase = U.gsap.utils.wrap(Object.values(BladesPhase), Object.values(BladesPhase).indexOf(phase ?? game.eunoblades.Tracker?.phase ?? BladesPhase.Freeplay) + 1); - } - // - As with notifications: placeholder animation until something more final can be coded. - // #endregion - // #region TOOLTIPS ~ - _tooltipObserver; - _tooltipElems = new Map(); - _displayedTooltipID; - /** - * Adjusts the tooltip's position to ensure it remains within its parent container using jQuery methods. - * @param tooltip - The tooltip element, which can be either an HTMLElement or a JQuery. - */ - adjustTooltipPosition(tooltip$) { - // Validate tooltip position style - if (tooltip$.css("position") !== "absolute") { - throw new Error("Tooltip position must be 'absolute'."); - } - // Calculate bounds and directly apply necessary shifts to the tooltip element - const tooltipRect = tooltip$[0].getBoundingClientRect(); - const containerRect = this.tooltipSection$[0].getBoundingClientRect(); - // Initial position of the tooltip - const currentTop = tooltip$.position().top; - const currentLeft = tooltip$.position().left; - // Check for right overflow and adjust left position if necessary - if (tooltipRect.right > containerRect.right) { - const xShift = containerRect.right - tooltipRect.right; - tooltip$.css("left", `${currentLeft + xShift}px`); - } - // Check for left overflow and adjust left position if necessary - else if (tooltipRect.left < containerRect.left) { - const xShift = containerRect.left - tooltipRect.left; - tooltip$.css("left", `${currentLeft + xShift}px`); - } - // Check for bottom overflow and adjust top position if necessary - if (tooltipRect.bottom > containerRect.bottom) { - const yShift = containerRect.bottom - tooltipRect.bottom; - tooltip$.css("top", `${currentTop + yShift}px`); - } - // Check for top overflow and adjust top position if necessary - else if (tooltipRect.top < containerRect.top) { - const yShift = containerRect.top - tooltipRect.top; - tooltip$.css("top", `${currentTop + yShift}px`); - } - } - displayTooltip(tooltip) { - if (!tooltip.id) { - throw new Error("Tooltip must have an ID to be cloned to the overlay."); - } - this._displayedTooltipID = tooltip.id; - const self = this; - // Clear out any other tooltips in the overlay. - game.eunoblades.Director.clearTooltips(); - if (!this._tooltipElems.has(tooltip.id)) { - // Create cloned tooltip and attach it to the tooltip overlay. - const ttClone$ = $(U.changeContainer(tooltip, game.eunoblades.Director.tooltipSection$[0], true)); - // Adjust the tooltip's position so it does not overflow the tooltip container - this.adjustTooltipPosition(ttClone$); - // Generate the reveal timeline and attach it to the cloned tooltip element. - const revealTimeline = U.gsap.effects.blurRevealTooltip(ttClone$[0], { - onReverseComplete() { - if (ttClone$.attr("id") === self._displayedTooltipID) { - delete self._displayedTooltipID; - } - game.eunoblades.Director._tooltipElems.delete(ttClone$.attr("id")); - game.eunoblades.Director.tooltipSection$.find(`#${ttClone$.attr("id")}`).remove(); - game.eunoblades.Director.tooltipSection$.children("[style*='opacity: 0'], [style*='opacity:0']").each(function () { - const id = this.id; // Get the ID of the current element - if (id === self._displayedTooltipID) { - return; - } - if (id) { - game.eunoblades.Director._tooltipElems.delete(id); // Remove from the map if the ID exists - } - $(this).remove(); // Remove the element from the DOM - }); - } - }); - ttClone$.data("revealTimeline", revealTimeline); - // Register the cloned tooltip element to the master map - this._tooltipElems.set(tooltip.id, ttClone$); - } - // Play the timeline. - this._tooltipElems.get(tooltip.id)?.data("revealTimeline")?.play(); - } - clearTooltip(tooltipID, isClearingIfTweening = true) { - if (tooltipID === this._displayedTooltipID) { - delete this._displayedTooltipID; - } - const ttElem = game.eunoblades.Director._tooltipElems.get(tooltipID); - if (!ttElem) { - return; - } - const ttTimeline = ttElem.data("revealTimeline"); - if (ttTimeline.isActive() && !isClearingIfTweening) { - return; - } - ttTimeline.reverse(); - } - clearTooltips() { - eLog.checkLog3("Observer", "Observer Triggered!"); - // Look for tooltip elements in the overlay container, and remove them. - game.eunoblades.Director._tooltipElems.forEach((ttElem) => { - if (ttElem.attr("id") === this._displayedTooltipID) { - return; - } - game.eunoblades.Director.clearTooltip(ttElem.attr("id"), true); - }); - } - initTooltipSection() { - const self = this; - this.clearTooltips(); - // Reset tooltip observer - this._tooltipObserver?.kill(); - // Simplified throttle function that takes a function with Observer parameter - const throttle = (func, limit) => { - let lastFunc; - let lastRan; - return function (obs) { - const now = Date.now(); - if (!lastRan || now - lastRan >= limit) { - func(obs); - lastRan = now; - } - else { - clearTimeout(lastFunc); - lastFunc = window.setTimeout(() => { - if (now - lastRan >= limit) { - func(obs); - lastRan = now; - } - }, limit - (now - lastRan)); - } - }; - }; - // Throttled onMove callback - const throttledOnMove = throttle((obs) => { - // Calculate the absolute magnitude of velocity independent of direction - const magnitudeOfVelocity = Math.sqrt((obs.velocityX ** 2) + (obs.velocityY ** 2)); - if (magnitudeOfVelocity >= C.MIN_MOUSE_MOVEMENT_THRESHOLD) { - self.clearTooltips(); - } - }, 200); // Adjust 200ms to your preferred throttling limit - this._tooltipObserver = Observer.create({ - type: "touch,pointer", - // onMove: throttledOnMove, - onClick() { - self.clearTooltips(); - } - }); - } -} -export default BladesDirector; diff --git a/module/classes/BladesPushAlert.js b/module/classes/BladesPushAlert.js deleted file mode 100644 index d3901dc2..00000000 --- a/module/classes/BladesPushAlert.js +++ /dev/null @@ -1,87 +0,0 @@ -import U from "../core/utilities.js"; -import C from "../core/constants.js"; -export default class BladesPushAlert { - static Get() { - if (!game.eunoblades.PushController) { - throw new Error("Attempt to Get BladesPushAlert before 'ready' hook."); - } - return game.eunoblades.PushController; - } - static isInitialized = false; - static Initialize() { - Hooks.once("ready", async () => { - let pushController = game.eunoblades.PushController; - if (!(pushController instanceof BladesPushAlert)) { - pushController = new BladesPushAlert(); - } - game.eunoblades.PushController = pushController; - pushController.initOverlay(); - }); - Hooks.on("canvasReady", async () => { game.eunoblades.PushController?.initOverlay(); }); - } - static InitSockets() { - if (game.eunoblades.PushController) { - socketlib.system.register("pushNotice", game.eunoblades.PushController.push); - return true; - } - return false; - } - initOverlay() { - $("#sidebar").append($("
")); - BladesPushAlert.isInitialized = true; - } - get elem$() { return $("#blades-push-notifications"); } - get elem() { return this.elem$[0]; } - activeNotifications = {}; - push(blockClass, charName, titleText, bodyText) { - const pushController = BladesPushAlert.Get(); - const pushID = randomID(); - const pushLines = [ - `
` - ]; - if (charName !== "GM") { - pushLines.push(`
${charName}
`); - } - if (titleText) { - pushLines.push(`
${titleText}
`); - } - if (bodyText) { - pushLines.push(`
${bodyText}
`); - } - pushLines.push("
"); - const pushElem$ = $(pushLines.join("\n")); - pushController.elem$.append(pushElem$); - pushElem$.on("click", () => pushController.removePush(pushElem$[0])); - U.gsap.from(pushElem$[0], { - x: "-=200", - scale: 1.25, - duration: 1, - ease: "power2" - }); - U.gsap.from(pushElem$[0], { - background: C.Colors.bGOLD, - borderColor: C.Colors.WHITE, - duration: 10, - ease: "power2" - }); - } - removePush(pushElem) { - U.gsap.effects.slideUp(pushElem) - .then(() => $(pushElem).remove()); - } - pushToAll(charName, titleText, bodyText, blockClass) { - socketlib.system.executeForEveryone("pushNotice", blockClass ?? "", charName, titleText, bodyText); - } - pushToSome(...args) { - const users = (args.pop() ?? []) - .filter((user) => Boolean(user?.id)); - if (!users || users.length === 0) { - return; - } - const pushArgs = args.slice(0, 3); - socketlib.system.executeForUsers("pushNotice", users.map((user) => user.id), "", ...pushArgs); - } - pushToGM(...args) { - socketlib.system.executeForAllGMs("pushNotice", "to-gm-notice", ...args); - } -} diff --git a/module/classes/BladesRoll.js b/module/classes/BladesRoll.js deleted file mode 100644 index e10d4997..00000000 --- a/module/classes/BladesRoll.js +++ /dev/null @@ -1,3908 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region IMPORTS ~ -import U from "../core/utilities.js"; -import C, { BladesActorType, BladesItemType, RollPermissions, RollType, RollSubType, RollModType, RollModStatus, RollModSection, ActionTrait, DowntimeAction, AttributeTrait, Position, Effect, Factor, RollResult, RollPhase, ConsequenceType, Tag } from "../core/constants.js"; -import { BladesActor, BladesPC, BladesCrew } from "../documents/BladesActorProxy.js"; -import { BladesItem, BladesGMTracker } from "../documents/BladesItemProxy.js"; -import { ApplyTooltipAnimations, Dragger } from "../core/gsap.js"; -import BladesConsequence from "./BladesConsequence.js"; -import BladesDialog from "./BladesDialog.js"; -import BladesChat from "./BladesChat.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -// #endregion -// #region Types & Type Checking ~ -/** - * Checks if the given string is a RollType. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollType, false otherwise. - */ -function isRollType(str) { - return typeof str === "string" && str in RollType; -} -/** - * Checks if the given trait is an ActionTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an ActionTrait, false otherwise. - */ -function isAction(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in ActionTrait); -} -/** - * Checks if the given trait is an AttributeTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an AttributeTrait, false otherwise. - */ -function isAttribute(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in AttributeTrait); -} -/** - * Checks if the given trait is a Factor. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is a Factor, false otherwise. - */ -function isFactor(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in Factor); -} -/** - * Checks if the given string is a RollModStatus. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollModStatus, false otherwise. - */ -function isModStatus(str) { - return typeof str === "string" && str in RollModStatus; -} -/** - * Checks if the given section can contain BladesRollParticipant documents. - * @param {RollModSection} section - */ -function isParticipantSection(section) { - return [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].includes(section); -} -/** - * Checks if the given subSection can hold BladesRollParticipant documents. - * @param {string} subSection - */ -function isParticipantSubSection(subSection) { - if (subSection.startsWith("Group_")) { - return true; - } - if (["Assist", "Setup"].includes(subSection)) { - return true; - } - return false; -} -// #endregion -// #region Utility Functions ~ -// #endregion -class BladesRollMod extends BladesTargetLink { - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - if (!schemaData.name) { - throw new Error("name is required for BladesRollMod.Schema"); - } - return { - key: `${schemaData.name}-positive-roll`, - modType: RollModType.general, - section: RollModSection.roll, - posNeg: "positive", - base_status: RollModStatus.Hidden, - value: 1, - tooltip: "", - ...schemaData - }; - } - static get GMOnlyModStatuses() { - return [RollModStatus.ForcedOn, RollModStatus.ForcedOff, RollModStatus.Hidden]; - } - static getSchemaFromStrings(mStrings) { - const nameString = U.pullElement(mStrings, (v) => typeof v === "string" && /^na/i.test(v)); - const nameVal = (typeof nameString === "string" && nameString.replace(/^.*:/, "")); - if (!nameVal) { - throw new Error(`RollMod Missing Name: '${mStrings.join("@")}'`); - } - const catString = U.pullElement(mStrings, (v) => typeof v === "string" && /^cat/i.test(v)); - const catVal = (typeof catString === "string" && catString.replace(/^.*:/, "")); - if (!catVal || !(catVal in RollModSection)) { - throw new Error(`RollMod Missing Category: '${mStrings.join("@")}'`); - } - const posNegString = (U.pullElement(mStrings, (v) => typeof v === "string" && /^p/i.test(v)) || "posNeg:positive"); - const posNegVal = posNegString.replace(/^.*:/, ""); - return { - key: `${nameVal}-${posNegVal}-${catVal}`, - name: nameVal, - section: catVal, - posNeg: posNegVal, - base_status: RollModStatus.ToggledOff, - modType: RollModType.general, - tooltip: "", - value: 1, - ...Object.fromEntries(mStrings.map(getModParameterKeyVal)) - }; - function getModParameterKeyVal(mString) { - const [keyString, valString] = mString.split(/:/); - let val = /\|/.test(valString) ? valString.split(/\|/) : valString; - let key; - if (/^stat/i.test(keyString)) { - key = "base_status"; - } - else if (/^val/i.test(keyString)) { - key = "value"; - } - else if (/^eff|^ekey/i.test(keyString)) { - key = "effectKeys"; - } - else if (/^side|^ss/i.test(keyString)) { - key = "sideString"; - } - else if (/^s.*ame/i.test(keyString)) { - key = "source_name"; - } - else if (/^tool|^tip/i.test(keyString)) { - key = "tooltip"; - } - else if (/^ty/i.test(keyString)) { - key = "modType"; - } - else if (/^c.{0,10}r?.{0,3}ty/i.test(keyString)) { - key = "conditionalRollTypes"; - } - else if (/^a.{0,3}r?.{0,3}y/i.test(keyString)) { - key = "autoRollTypes"; - } - else if (/^p.{0,10}r?.{0,3}y/i.test(keyString)) { - key = "participantRollTypes"; - } - else if (/^c.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "conditionalRollTraits"; - } - else if (/^a.{0,3}r?.{0,3}tr/i.test(keyString)) { - key = "autoRollTraits"; - } - else if (/^p.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "participantRollTypes"; - } - else { - throw new Error(`Bad Roll Mod Key: ${keyString}`); - } - if (key === "base_status" && val === "Conditional") { - val = RollModStatus.Hidden; - } - let valProcessed; - if (["value"].includes(key)) { - valProcessed = U.pInt(val); - } - else if (["effectKeys", "conditionalRollTypes", "autoRollTypes", "conditionalRollTraits", "autoRollTraits"].includes(key)) { - valProcessed = [val].flat(); - } - else { - valProcessed = val.replace(/%COLON%/g, ":"); - } - return [key, valProcessed]; - } - } - static ParseDocModsToSchemaSet(doc) { - if (doc instanceof BladesChat) { - throw new Error("BladesRollMod.ParseDocRollMods cannot be called on a BladesChat document."); - } - const { roll_mods } = doc.system; - if (!roll_mods || roll_mods.length === 0) { - return []; - } - return roll_mods - .filter((elem) => Boolean(elem && typeof elem === "string")) - .map((modString) => { - return this.getSchemaFromStrings(modString.split(/@/)); - }); - } - isRerendering = false; - get status() { - // USER STATUS of "ForcedOn", "ForcedOff", or "Hidden" trumps all other status values. - if (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)) { - return this.userStatus; - } - // HELD STATUS of "ToggledOff" or "ToggledOn" can be overridden by User Status - if (this.heldStatus && [RollModStatus.ToggledOff, RollModStatus.ToggledOn].includes(this.heldStatus)) { - return this.userStatus ?? this.heldStatus; - } - // Otherwise, return the first status that is set out of held, user, and base. - return this.heldStatus ?? this.userStatus ?? this.baseStatus; - } - get isActive() { return [RollModStatus.ToggledOn, RollModStatus.ForcedOn].includes(this.status); } - get isVisible() { return this.status !== RollModStatus.Hidden; } - // get flagParams() { - // return [C.SYSTEM_ID, `rollCollab.rollModsData.${this.id}`] as const;} - // async setUserStatusFlag(val: RollModStatus | undefined) { - // } - get isConditional() { - return [ - ...this.conditionalRollTraits, - ...this.autoRollTraits, - ...this.participantRollTraits, - ...this.conditionalRollTypes, - ...this.autoRollTypes, - ...this.participantRollTypes - ].length > 0; - } - get isInInactiveBlock() { - if (game.user.isGM) { - return [RollModStatus.Hidden, RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - return [RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - get isPush() { - return Boolean(U.lCase(this.name) === "push" - || this.effectKeys.find((eKey) => eKey === "Is-Push")); - } - get isBasicPush() { return U.lCase(this.name) === "push"; } - get stressCost() { - const costKeys = this.effectKeys.filter((key) => key.startsWith("Cost-Stress")); - if (costKeys.length === 0) { - return 0; - } - let stressCost = 0; - costKeys.forEach((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [_, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - stressCost += U.pInt(valStr); - }); - return stressCost; - } - isValidForRollType() { - switch (this.rollInstance.rollType) { - case RollType.Action: { - return true; - } - case RollType.Resistance: - case RollType.Fortune: - case RollType.IndulgeVice: { - if (this.isPush - || ["bargain", "setup", "assist", "potency"].includes(U.lCase(this.name))) { - return false; - } - return true; - } - default: return false; - } - } - /** - * Checks if any types or traits apply to the roll instance. - * @param {AnyRollType[]} types The types to check. - * @param {RollTrait[]} traits The traits to check. - * @returns {boolean} - Returns true if any types or traits apply, false otherwise. - */ - checkTypesOrTraits(types, traits) { - const rollTypes = [this.rollInstance.rollType, this.rollInstance.rollSubType, this.rollInstance.rollDowntimeAction] - .filter((rType) => Boolean(rType)); - const typesApply = (!this.rollInstance.isParticipantRoll && types.length === 0) - || rollTypes.some((rType) => types.includes(rType)); - const traitsApply = (!this.rollInstance.isParticipantRoll && traits.length === 0) - || (this.rollInstance.rollTrait && traits.includes(this.rollInstance.rollTrait)); - return Boolean(typesApply && traitsApply); - } - /** - * Sets the conditional status of the roll mod instance. - * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden. - */ - setConditionalStatus() { - // If the roll mod instance is not conditional, return false - if (!this.isConditional) { - return false; - } - // If any auto-Types apply, set status to ForcedOn and return false - if (this.autoRollTypes.includes(this.rollInstance.rollType) - || (this.rollInstance.rollSubType && this.autoRollTypes.includes(this.rollInstance.rollSubType)) - || (this.rollInstance.rollDowntimeAction && this.autoRollTypes.includes(this.rollInstance.rollDowntimeAction))) { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - // If any auto-Traits apply, set status to ForcedOn and return false - if (this.rollInstance.rollTrait && this.autoRollTraits.includes(this.rollInstance.rollTrait)) { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - // If any conditionalTypes or conditionalTraits apply, set status to ToggledOff and return false - if (this.checkTypesOrTraits(this.conditionalRollTypes, this.conditionalRollTraits)) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If this is a participant roll - // AND any participantTypes or participantTraits apply, - // ... set status to ToggledOff and return false - if (this.rollInstance.isParticipantRoll - && this.checkTypesOrTraits(this.participantRollTypes, this.participantRollTraits)) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If none of the above conditions apply, set status to Hidden and return true - this.heldStatus = RollModStatus.Hidden; - return true; - } - /** - * Sets the auto-reveal/enable status of the roll mod instance. - * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden. - */ - setAutoStatus() { - // Check for AutoRevealOn and AutoEnableOn - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Auto")); - if (holdKeys.length === 0) { - return false; - } - for (const key of holdKeys) { - const [thisKey, thisParam] = key.split(/-/) ?? []; - if (U.lCase(thisParam) in Position && this.rollInstance.rollPositionFinal === U.lCase(thisParam)) { - if (thisKey === "AutoRevealOn") { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - else if (thisKey === "AutoEnableOn") { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - } - } - this.heldStatus = RollModStatus.Hidden; - return true; - } - /** - * Sets the relevancy status of the roll mod instance (i.e. hides irrelevant rollMods). - * @returns {boolean} - Returns true if mod is irrelevant and status is Hidden, false otherwise. - */ - setRelevancyStatus() { - const holdKeys = this.effectKeys.filter((key) => /^Negate|^Increase/.test(key)); - if (holdKeys.length === 0) { - return false; - } - const relevantKeys = holdKeys - .filter((key) => { - const [thisKey, thisParam] = key.split(/-/) ?? []; - if (thisKey === "Negate") { - const negateOperations = { - PushCost: () => this.rollInstance.isPushed(), - QualityPenalty: () => this.rollInstance.isTraitRelevant(Factor.quality) - && (this.rollInstance.rollFactors.source[Factor.quality]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.quality]?.value ?? 0), - ScalePenalty: () => this.rollInstance.isTraitRelevant(Factor.scale) - && (this.rollInstance.rollFactors.source[Factor.scale]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.scale]?.value ?? 0), - TierPenalty: () => this.rollInstance.isTraitRelevant(Factor.tier) - && (this.rollInstance.rollFactors.source[Factor.tier]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.tier]?.value ?? 0) - }; - if (Object.hasOwn(negateOperations, thisParam)) { - return negateOperations[thisParam](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${thisParam}`); - } - } - else if (thisKey === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(thisParam) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${thisKey}`); - } - }); - if (relevantKeys.length === 0) { - this.heldStatus = RollModStatus.Hidden; - return true; - } - return false; - } - /** - * Sets the payable status of the roll mod instance (i.e. forces off rollMods the primary can't pay for). - * @returns {boolean} - Returns true if mod is unpayable and status is ForcedOff, false otherwise. - */ - setPayableStatus() { - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return false; - } - const payableKeys = holdKeys - .filter((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - const { rollPrimaryDoc } = this.rollInstance.rollPrimary ?? {}; - if (!BladesRollPrimary.IsDoc(rollPrimaryDoc)) { - return false; - } - switch (traitStr) { - case "SpecialArmor": { - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.armor.active.special - && !rollPrimaryDoc.system.armor.checked.special; - } - case "Stress": { - const val = U.pInt(valStr); - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.stress.max - rollPrimaryDoc.system.stress.value >= val; - } - case "Heat": { - return (BladesPC.IsType(rollPrimaryDoc) && BladesCrew.IsType(rollPrimaryDoc.crew)) - || BladesCrew.IsType(rollPrimaryDoc); - } - default: throw new Error(`Unrecognize Payable Key: ${traitStr}`); - } - }); - if (payableKeys.length === 0) { - this.heldStatus = RollModStatus.ForcedOff; - return true; - } - return false; - } - applyRollModEffectKeys() { - if (!this.isActive) { - return; - } - const holdKeyParams = this.effectKeys - .filter((key) => /^Negate|^Increase/.test(key)) - .map((key) => key.split(/-/)); - if (holdKeyParams.length === 0) { - return; - } - holdKeyParams.forEach(([key, param]) => { - if (key === "Negate") { - const negateOperations = { - PushCost: () => { - this.rollInstance.negatePushCost(); - }, - QualityPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.quality); - }, - ScalePenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.scale); - }, - TierPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.tier); - } - }; - if (Object.hasOwn(negateOperations, param)) { - return negateOperations[param](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${param}`); - } - } - else if (key === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(param) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${key} (key: ${key})`); - } - }); - } - get selectOptions() { - if (this.modType !== RollModType.teamwork) { - return null; - } - if (this.name === "Assist" || this.name === "Setup") { - return this.rollInstance.rollParticipantSelectOptions[this.name]; - } - else if (this.name.startsWith("Group_")) { - return this.rollInstance.rollParticipantSelectOptions.Group; - } - return null; - } - get selectedParticipant() { - if (this.modType !== RollModType.teamwork) { - return null; - } - return this.rollInstance.getRollParticipant(this.section, this.name); - } - get allFlagData() { - return this.rollInstance.data; - } - get costs() { - if (!this.isActive) { - return undefined; - } - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return undefined; - } - return holdKeys.map((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - let label = this.name; - if (this.isBasicPush) { - if (this.posNeg === "negative") { - label = `${this.name} (To Act)`; - } - else { - const effect = this.section === RollModSection.roll ? "+1d" : "+1 effect"; - label = `${this.name} (${effect})`; - } - } - return { - id: this.id, - label, - costType: traitStr, - costAmount: valStr ? U.pInt(valStr) : 1 - }; - }); - } - _rollInstance; - constructor(modData, rollInstance) { - super(modData); - this._rollInstance = rollInstance; - } - get rollInstance() { return this._rollInstance; } - get name() { return this.data.name; } - get modType() { return this.data.modType; } - get sourceName() { return this.data.source_name ?? this.data.name; } - get section() { return this.data.section; } - get posNeg() { return this.data.posNeg; } - get userStatus() { return this.data.user_status; } - set userStatus(val) { - if (val === this.userStatus) { - return; - } - const { isRerendering } = this; - if (!val || val === this.baseStatus) { - this.updateTarget("user_status", null) - .then(() => { - if (isRerendering) { - this.rollInstance.renderRollCollab_SocketCall(); - } - }); - } - else { - if (!game.user.isGM - && (BladesRollMod.GMOnlyModStatuses.includes(val) - || (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)))) { - return; - } - this.updateTarget("user_status", val) - .then(() => { - if (isRerendering) { - this.rollInstance.renderRollCollab_SocketCall(); - } - }); - } - } - get baseStatus() { return this.data.base_status; } - get heldStatus() { return this.data.held_status; } - set heldStatus(val) { - if (val === this.heldStatus) { - return; - } - const { isRerendering } = this; - if (!val) { - this.updateTarget("held_status", null) - .then(() => { - if (isRerendering) { - this.rollInstance.renderRollCollab_SocketCall(); - } - }); - } - else { - this.updateTarget("held_status", val) - .then(() => { - if (isRerendering) { - this.rollInstance.renderRollCollab_SocketCall(); - } - }); - } - } - get value() { return this.data.value; } - get effectKeys() { return this.data.effectKeys ?? []; } - get sideString() { - if (this.data.sideString) { - return this.data.sideString; - } - if (this.selectedParticipant) { - return this.selectedParticipant.rollParticipantName; - } - return undefined; - } - get tooltip() { - let parsedTooltip = this.data.tooltip.replace(/%COLON%/g, ":"); - if (parsedTooltip.includes("%DOC_NAME%")) { - parsedTooltip = parsedTooltip.replace(/%DOC_NAME%/g, this.selectedParticipant - ? this.selectedParticipant.rollParticipantName - : "an Ally"); - } - if (parsedTooltip.includes("@OPPOSITION_NAME@")) { - parsedTooltip = parsedTooltip.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition - ? this.rollInstance.rollOpposition.rollOppName - : "Your Opposition"); - } - return parsedTooltip; - } - get conditionalRollTypes() { - return this.data.conditionalRollTypes ?? []; - } - get autoRollTypes() { - return this.data.autoRollTypes ?? []; - } - get participantRollTypes() { - return this.data.participantRollTypes ?? []; - } - get conditionalRollTraits() { - return this.data.conditionalRollTraits ?? []; - } - get autoRollTraits() { - return this.data.autoRollTraits ?? []; - } - get participantRollTraits() { - return this.data.participantRollTraits ?? []; - } -} -class BladesRollPrimary { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollPrimary.IsDoc(data)) { - return false; - } - return U.isList(data) - && typeof data.rollPrimaryName === "string" - && typeof data.rollPrimaryType === "string" - && typeof data.rollPrimaryImg === "string" - && Array.isArray(data.rollPrimaryModsSchemaSet) - && U.isList(data.rollFactors) - && (!data.rollPrimaryID || typeof data.rollPrimaryID === "string") - && (!data.rollPrimaryDoc || BladesRollPrimary.IsDoc(data.rollPrimaryDoc)); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - return BladesRollPrimary.IsDoc(doc) && doc; - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - static GetDataFromDoc(doc) { - return { - rollPrimaryID: doc.id, - rollPrimaryName: doc.name, - rollPrimaryType: doc.type, - rollPrimaryImg: doc.img, - rollPrimaryModsSchemaSet: doc.rollPrimaryModsSchemaSet, - rollFactors: doc.rollFactors - }; - } - static BuildData(config) { - if (BladesRollPrimary.IsValidData(config.rollPrimaryData)) { - return config.rollPrimaryData; - } - let rollPrimary; - const rollUser = game.users.get(config.rollUserID ?? game.user.id); - if ("target" in config && BladesRollPrimary.IsDoc(config.target)) { - rollPrimary = config.target; - } - else if (rollUser && BladesRollPrimary.IsDoc(rollUser.character)) { - rollPrimary = rollUser.character; - } - else { - throw new Error("[BladesRollPrimary.BuildData()] A valid source of PrimaryData must be provided to construct a roll."); - } - return { - rollPrimaryID: rollPrimary.rollPrimaryID, - rollPrimaryName: rollPrimary.rollPrimaryName, - rollPrimaryType: rollPrimary.rollPrimaryType, - rollPrimaryImg: rollPrimary.rollPrimaryImg, - rollPrimaryModsSchemaSet: rollPrimary.rollPrimaryModsSchemaSet, - rollFactors: rollPrimary.rollFactors - }; - } - static Build(config) { - return new BladesRollPrimary(this.BuildData(config)); - } - // #endregion - rollInstance; - rollPrimaryID; - _rollPrimaryDoc; - get rollPrimaryDoc() { - if (!this._rollPrimaryDoc) { - let doc; - if (this.rollPrimaryID) { - doc = game.items.get(this.rollPrimaryID) - ?? game.actors.get(this.rollPrimaryID); - } - if (!doc && this.rollPrimaryName) { - doc = game.items.getName(this.rollPrimaryName) - ?? game.actors.getName(this.rollPrimaryName); - } - if (BladesRollPrimary.IsDoc(doc)) { - this._rollPrimaryDoc = doc; - } - } - return this._rollPrimaryDoc; - } - rollPrimaryName; - rollPrimaryType; - rollPrimaryImg; - rollPrimaryModsSchemaSet; - rollFactors; - get data() { - return { - rollPrimaryID: this.rollPrimaryID, - rollPrimaryName: this.rollPrimaryName, - rollPrimaryType: this.rollPrimaryType, - rollPrimaryImg: this.rollPrimaryImg, - rollPrimaryModsSchemaSet: this.rollPrimaryModsSchemaSet, - rollFactors: this.rollFactors - }; - } - get isWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.getFlag("eunos-blades", "isWorsePosition") === true; - } - return false; - } - async applyHarm(amount, name) { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyHarm(amount, name); - } - } - async applyWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyWorsePosition(); - } - } - get hasSpecialArmor() { - return BladesPC.IsType(this.rollPrimaryDoc) && this.rollPrimaryDoc.isSpecialArmorAvailable; - } - get availableArmorCount() { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - return this.rollPrimaryDoc.availableArmor.length; - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return this.rollPrimaryDoc.system.armor.max - this.rollPrimaryDoc.system.armor.value; - } - return 0; - } - async spendArmor(count) { - if (!this.rollPrimaryDoc) { - throw new Error("[BladesRollPrimary.spendArmor()] Cannot spend armor when rollPrimaryDoc is not defined."); - } - if (count > this.availableArmorCount) { - throw new Error(`[BladesRollPrimary.spendArmor()] Cannot spend more armor (${count}) than ${this.rollPrimaryDoc?.name} has (${this.availableArmorCount}).`); - } - if (BladesPC.IsType(this.rollPrimaryDoc)) { - const armorToSpend = this.rollPrimaryDoc.availableArmor.slice(0, count); - const updateData = {}; - if (armorToSpend.includes("Light Armor")) { - updateData["system.armor.active.light"] = true; - updateData["system.armor.checked.light"] = true; - } - if (armorToSpend.includes("Heavy Armor")) { - updateData["system.armor.active.heavy"] = true; - updateData["system.armor.checked.heavy"] = true; - } - await this.rollPrimaryDoc.update(updateData); - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - await this.rollPrimaryDoc.update({ "system.armor.value": this.rollPrimaryDoc.system.armor.value + count }); - } - } - constructor(...args) { - let primaryData = false; - let primaryDoc = false; - if (args[0] instanceof BladesRoll) { - this.rollInstance = args[0]; - args.shift(); - } - if (BladesRollPrimary.IsDoc(args[0])) { - primaryDoc = args[0]; - } - else if (BladesRollPrimary.IsValidData(args[0])) { - primaryData = args[0]; - } - else if (U.isList(args[0])) { - if ("rollPrimaryID" in args[0]) { - primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryID); - } - else if ("rollPrimaryName" in args[0]) { - primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryName); - } - } - if (primaryDoc && !BladesRollPrimary.IsValidData(primaryData)) { - primaryData = { - rollPrimaryID: primaryDoc.rollPrimaryID, - rollPrimaryName: primaryDoc.rollPrimaryName, - rollPrimaryType: primaryDoc.rollPrimaryType, - rollPrimaryImg: primaryDoc.rollPrimaryImg, - rollPrimaryModsSchemaSet: primaryDoc.rollPrimaryModsSchemaSet, - rollFactors: primaryDoc.rollFactors - }; - } - if (!BladesRollPrimary.IsValidData(primaryData) && !BladesRollPrimary.IsDoc(primaryDoc) && this.rollInstance) { - primaryData = this.rollInstance.rollPrimary.data; - } - if (!BladesRollPrimary.IsValidData(primaryData)) { - throw new Error(`[BladesRoll.constructor] Failed to resolve primary data from provided arguments: ${JSON.stringify(args)}`); - } - const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryImg, rollPrimaryModsSchemaSet, rollFactors } = primaryData; - this.rollPrimaryID = rollPrimaryID; - if (!rollPrimaryName) { - throw new Error("Must include a rollPrimaryName when constructing a BladesRollPrimary object."); - } - if (!rollPrimaryImg) { - throw new Error("Must include a rollPrimaryImg when constructing a BladesRollPrimary object."); - } - if (!rollPrimaryType) { - throw new Error("Must include a rollPrimaryType when constructing a BladesRollPrimary object."); - } - if (!rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollPrimary object."); - } - this.rollPrimaryName = rollPrimaryName; - this.rollPrimaryType = rollPrimaryType; - this.rollPrimaryImg = rollPrimaryImg; - this.rollFactors = rollFactors; - this.rollPrimaryModsSchemaSet = rollPrimaryModsSchemaSet ?? []; - } -} -class BladesRollOpposition { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollOpposition.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollOppName === "string" - && typeof data.rollOppType === "string" - && typeof data.rollOppImg === "string" - && (!data.rollOppSubName || typeof data.rollOppSubName === "string") - && (!data.rollOppModsSchemaSet || Array.isArray(data.rollOppModsSchemaSet)) - && U.isList(data.rollFactors) - && (!data.rollOppID || typeof data.rollOppID === "string"); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollOpposition.IsDoc(doc)) { - return doc; - } - return false; - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.npc, BladesActorType.faction) || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang); - } - static GetDataFromDoc(doc) { - return { - rollOppID: doc.id, - rollOppName: doc.name, - rollOppType: doc.type, - rollOppImg: doc.img, - rollOppModsSchemaSet: doc.rollOppModsSchemaSet, - rollFactors: doc.rollFactors - }; - } - // #endregion - rollInstance; - rollOppID; - rollOppDoc; - rollOppName; - rollOppSubName; - rollOppType; - rollOppImg; - rollOppModsSchemaSet; - rollFactors; - // #region Constructor ~ - constructor(rollInstance, { rollOppID, rollOppName, rollOppSubName, rollOppType, rollOppImg, rollOppModsSchemaSet, rollFactors } = {}) { - this.rollInstance = rollInstance; - // Attempt to fetch an associated BladesActor or BladesItem document - const doc = BladesRollOpposition.GetDoc(rollOppID ?? rollOppName); - if (doc) { - // Derive settings from valid Actor/Item document, unless explicitly set in constructor. - this.rollOppDoc = doc; - rollOppID = doc.rollOppID; - rollOppName ??= doc.rollOppName; - rollOppSubName ??= doc.rollOppSubName; - rollOppType ??= doc.rollOppType; - rollOppImg ??= doc.rollOppImg; - rollOppModsSchemaSet = [ - ...rollOppModsSchemaSet ?? [], - ...doc.rollOppModsSchemaSet ?? [] - ]; - rollFactors = { - ...doc.rollFactors, - ...rollFactors ?? {} - }; - } - // Confirm required settings - if (!rollOppName) { - throw new Error("Must include a rollOppName when constructing a BladesRollOpposition object."); - } - if (!rollOppType) { - throw new Error("Must include a rollOppType when constructing a BladesRollOpposition object."); - } - if (!rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollOpposition object."); - } - // Initialize properties - this.rollOppID = rollOppID; - this.rollOppName = rollOppName; - this.rollOppSubName = rollOppSubName; - this.rollOppType = rollOppType; - this.rollOppImg = rollOppImg ?? ""; - this.rollOppModsSchemaSet = rollOppModsSchemaSet ?? []; - this.rollFactors = rollFactors; - } - // #endregion - get data() { - return { - rollOppID: this.rollOppID, - rollOppName: this.rollOppName, - rollOppSubName: this.rollOppSubName, - rollOppType: this.rollOppType, - rollOppImg: this.rollOppImg, - rollOppModsSchemaSet: this.rollOppModsSchemaSet, - rollFactors: this.rollFactors - }; - } - async updateRollFlags() { - if (!this.rollInstance) { - return; - } - await this.rollInstance.updateTarget("rollOppData", this.data); - if (this.rollInstance.isRendered) { - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.rollInstance.id); - } - } - refresh() { - if (!this.rollInstance) { - return; - } - const rollOppFlags = this.rollInstance.data.rollOppData; - if (rollOppFlags) { - this.rollOppID = rollOppFlags.rollOppID; - this.rollOppName = rollOppFlags.rollOppName; - this.rollOppSubName = rollOppFlags.rollOppSubName; - this.rollOppType = rollOppFlags.rollOppType; - this.rollOppImg = rollOppFlags.rollOppImg; - this.rollOppModsSchemaSet = rollOppFlags.rollOppModsSchemaSet ?? []; - this.rollFactors = rollOppFlags.rollFactors; - } - return this; - } -} -class BladesRollParticipant { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollParticipant.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollParticipantName === "string" - && typeof data.rollParticipantType === "string" - && typeof data.rollParticipantIcon === "string" - && (!data.rollParticipantModsSchemaSet || Array.isArray(data.rollParticipantModsSchemaSet)) - && U.isList(data.rollFactors) - && (!data.rollParticipantID || typeof data.rollParticipantID === "string") - && (!data.rollParticipantDoc || BladesRollParticipant.IsDoc(data.rollParticipantDoc)); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollParticipant.IsDoc(doc)) { - return doc; - } - return false; - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew, BladesActorType.npc) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - // #endregion - rollInstance; - rollParticipantID; - rollParticipantDoc; - rollParticipantName; - rollParticipantType; - rollParticipantIcon; - rollParticipantSection; - rollParticipantSubSection; - rollParticipantModsSchemaSet; // As applied to MAIN roll when this participant involved - rollFactors; - constructor(rollInstance, section, subSection, rollParticipantDataOrDoc) { - this.rollInstance = rollInstance; - if (!section) { - throw new Error("Must include a rollParticipantSection when constructing a BladesRollParticipant object."); - } - if (!subSection) { - throw new Error("Must include a rollParticipantSubSection when constructing a BladesRollParticipant object."); - } - this.rollParticipantSection = section; - this.rollParticipantSubSection = subSection; - // Attempt to fetch an associated BladesActor or BladesItem document - const doc = BladesRollParticipant.IsDoc(rollParticipantDataOrDoc) - ? rollParticipantDataOrDoc - : BladesRollParticipant.GetDoc(rollParticipantDataOrDoc.rollParticipantID ?? rollParticipantDataOrDoc.rollParticipantName); - if (doc) { - rollParticipantDataOrDoc = doc; - } - // Confirm required settings - if (!rollParticipantDataOrDoc.rollParticipantName) { - throw new Error("Must include a rollParticipantName when constructing a BladesRollParticipant object."); - } - if (!rollParticipantDataOrDoc.rollParticipantType) { - throw new Error("Must include a rollParticipantType when constructing a BladesRollParticipant object."); - } - if (!rollParticipantDataOrDoc.rollFactors) { - throw new Error("Must include a rollFactors when constructing a BladesRollParticipant object."); - } - // Initialize properties - this.rollParticipantID = rollParticipantDataOrDoc.rollParticipantID; - this.rollParticipantName = rollParticipantDataOrDoc.rollParticipantName; - this.rollParticipantType = rollParticipantDataOrDoc.rollParticipantType; - this.rollParticipantIcon = rollParticipantDataOrDoc.rollParticipantIcon ?? ""; - this.rollParticipantModsSchemaSet = rollParticipantDataOrDoc.rollParticipantModsSchemaSet ?? []; - this.rollFactors = rollParticipantDataOrDoc.rollFactors; - } - // #endregion - get data() { - return { - rollParticipantID: this.rollParticipantID, - rollParticipantName: this.rollParticipantName, - rollParticipantType: this.rollParticipantType, - rollParticipantIcon: this.rollParticipantIcon, - rollParticipantModsSchemaSet: this.rollParticipantModsSchemaSet, - rollFactors: this.rollFactors - }; - } - async updateRollFlags() { - await this.rollInstance.updateTarget(`rollParticipantData.${this.rollParticipantSection}.${this.rollParticipantSubSection}`, this.data); - if (this.rollInstance.isRendered) { - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.rollInstance.id); - } - } - refresh() { - const rollParticipantFlagData = this.rollInstance.data.rollParticipantData?.[this.rollParticipantSection]; - if (rollParticipantFlagData && this.rollParticipantSubSection in rollParticipantFlagData) { - const rollParticipantFlags = rollParticipantFlagData[this.rollParticipantSubSection]; - if (rollParticipantFlags) { - this.rollParticipantID = rollParticipantFlags.rollParticipantID; - this.rollParticipantName = rollParticipantFlags.rollParticipantName; - this.rollParticipantType = rollParticipantFlags.rollParticipantType; - this.rollParticipantIcon = rollParticipantFlags.rollParticipantIcon; - this.rollParticipantModsSchemaSet = rollParticipantFlags.rollParticipantModsSchemaSet ?? []; - this.rollFactors = rollParticipantFlags.rollFactors; - } - } - return this; - } -} -class BladesRoll extends BladesTargetLink { - static Debug = { - modWatch: false, - watchRollMod(name) { - if (typeof name === "string") { - BladesRoll.Debug.modWatch = new RegExp(name, "g"); - } - else { - BladesRoll.Debug.modWatch = false; - } - } - }; - // #region STATIC METHODS: INITIALIZATION & DEFAULTS ~ - static Initialize() { - return loadTemplates([ - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-number-line.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-select-doc.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-factor-control.hbs", - "systems/eunos-blades/templates/roll/roll-collab-action.hbs", - "systems/eunos-blades/templates/roll/roll-collab-action-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-resistance.hbs", - "systems/eunos-blades/templates/roll/roll-collab-resistance-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-fortune.hbs", - "systems/eunos-blades/templates/roll/roll-collab-fortune-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-indulgevice.hbs", - "systems/eunos-blades/templates/roll/roll-collab-indulgevice-gm.hbs" - ]); - } - static InitSockets() { - socketlib.system.register("constructRollCollab_SocketCall", BladesRoll.constructRollCollab_SocketResponse.bind(BladesRoll)); - socketlib.system.register("renderRollCollab_SocketCall", BladesRoll.renderRollCollab_SocketResponse.bind(BladesRoll)); - socketlib.system.register("closeRollCollab_SocketCall", BladesRoll.closeRollCollab_SocketResponse.bind(BladesRoll)); - } - static ParseConfigToData(data, parentRollData) { - const parentRollInst = game.eunoblades.Rolls.get(parentRollData.id); - if (!parentRollInst) { - throw new Error(`[BladesRoll.ParseConfigToData] No BladesRoll instance found with id ${parentRollData.id}.`); - } - if (data.rollPrimaryData instanceof BladesRollPrimary) { - data.rollPrimaryData = data.rollPrimaryData.data; - } - if (data.rollOppData instanceof BladesRollOpposition) { - data.rollOppData = data.rollOppData.data; - } - if (data.rollParticipantData) { - if (data.rollParticipantData[RollModSection.roll]) { - Object.keys(data.rollParticipantData[RollModSection.roll]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.roll]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - data.rollParticipantData[RollModSection.roll][key] = thisParticipant.data; - } - }); - } - if (data.rollParticipantData[RollModSection.position]) { - Object.keys(data.rollParticipantData[RollModSection.position]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.position]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - data.rollParticipantData[RollModSection.position][key] = thisParticipant.data; - } - }); - } - if (data.rollParticipantData[RollModSection.effect]) { - Object.keys(data.rollParticipantData[RollModSection.effect]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.effect]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - data.rollParticipantData[RollModSection.effect][key] = thisParticipant.data; - } - }); - } - } - return super.ParseConfigToData(data); - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - if (!schemaData.rollType) { - throw new Error("Must include a rollType when constructing a BladesRoll object."); - } - schemaData.rollPhase ??= RollPhase.Collaboration; - schemaData.GMBoosts = { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0, - ...schemaData.GMBoosts ?? {} - }; - schemaData.GMOppBoosts = { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0, - ...schemaData.GMOppBoosts ?? {} - }; - schemaData.GMOverrides ??= {}; - schemaData.userPermissions ??= {}; - if (schemaData.rollPrimaryData instanceof BladesRollPrimary) { - schemaData.rollPrimaryData = schemaData.rollPrimaryData.data; - } - if (schemaData.rollOppData instanceof BladesRollOpposition) { - schemaData.rollOppData = schemaData.rollOppData.data; - } - return schemaData; - } - // static override get defaultOptions() { - // return foundry.utils.mergeObject(super.defaultOptions, { - // classes: ["eunos-blades", "sheet", "roll-collab", game.user.isGM ? "gm-roll-collab" : ""], - // template: `systems/eunos-blades/templates/roll/roll-collab${game.user.isGM ? "-gm" : ""}.hbs`, - // submitOnChange: true, - // width: 500, - // dragDrop: [ - // {dragSelector: null, dropSelector: "[data-action='gm-drop-opposition'"} - // ] - // // Height: 500 - // }); - // } - static get DefaultRollModSchemaSet() { - /* Subclass overrides determine default roll mods. */ - return []; - } - static GetDieClass(rollType, rollResult, dieVal, dieIndex) { - switch (rollType) { - case RollType.Resistance: { - if (dieVal === 6 && dieIndex <= 1 && rollResult === -1) { - return "blades-die-critical"; - } - if (dieIndex === 0) { - return "blades-die-resistance"; - } - return "blades-die-fail"; - } - case RollType.IndulgeVice: { - if (dieIndex === 0) { - return "blades-die-indulge-vice"; - } - return "blades-die-fail"; - } - default: break; - } - if (dieVal === 6 && dieIndex <= 1 && rollResult === RollResult.critical) { - dieVal++; - } - return [ - "", - "blades-die-fail", - "blades-die-fail", - "blades-die-fail", - "blades-die-partial", - "blades-die-partial", - "blades-die-success", - "blades-die-critical" - ][dieVal]; - } - static GetDieImage(rollType, rollResult, dieVal, dieIndex, isGhost = false, isCritical = false) { - let imgPath = "systems/eunos-blades/assets/dice/image/"; - if (isGhost) { - imgPath += "ghost-"; - } - else if ([RollType.Resistance, RollType.IndulgeVice].includes(rollType)) { - imgPath += "grad-"; - } - imgPath += dieVal; - if (!isGhost && dieVal === 6 && dieIndex <= 1 && isCritical) { - imgPath += "-crit"; - } - imgPath += ".webp"; - return imgPath; - } - static get Active() { - return U.getLast(game.eunoblades.Rolls.filter((roll) => roll.isActive)); - } - // #endregion - // #region STATIC METHODS: New Roll Creation ~ - // static Current: Record = {}; - // static _Active?: BladesRoll; - // static get Active(): BladesRoll | undefined { - // if (BladesRoll._Active) {return BladesRoll._Active;} - // if (U.objSize(BladesRoll.Current) > 0) {return U.getLast(Object.values(BladesRoll.Current));} - // return undefined; - // } - // static set Active(val: BladesRoll | undefined) { - // BladesRoll._Active = val; - // } - static GetUserPermissions(config) { - if (!config.rollPrimaryData) { - throw new Error("[BladesRoll.GetUserPermissions()] Missing rollPrimaryData."); - } - // === ONE === GET USER IDS - // Get user ID of GM - const GMUserID = game.users.find((user) => user.isGM)?.id; - if (!GMUserID) { - throw new Error("[BladesRoll.GetUserPermissions()] No GM found!"); - } - // Get user IDs of players - const playerUserIDs = game.users - .filter((user) => BladesPC.IsType(user.character) && !user.isGM && typeof user.id === "string") - .map((user) => user.id); - // Prepare user ID permissions object - const userIDs = { - [RollPermissions.GM]: [GMUserID], - [RollPermissions.Primary]: [], - [RollPermissions.Participant]: [], - [RollPermissions.Observer]: [] - }; - // === TWO === DETERMINE PRIMARY USER(S) - // Check RollPrimaryDoc to determine how to assign primary users - const { rollPrimaryDoc } = (new BladesRollPrimary(config.rollPrimaryData)); - if (BladesPC.IsType(rollPrimaryDoc) - && U.pullElement(playerUserIDs, rollPrimaryDoc.primaryUser?.id)) { - userIDs[RollPermissions.Primary].push(rollPrimaryDoc.primaryUser?.id); - } - else if (BladesCrew.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else if (BladesItem.IsType(rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - if (config.rollUserID === GMUserID) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else if (BladesPC.IsType(rollPrimaryDoc.parent) - && rollPrimaryDoc.parent.primaryUser?.id) { - userIDs[RollPermissions.Primary].push(rollPrimaryDoc.parent.primaryUser.id); - } - } - else if (BladesGMTracker.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(GMUserID); - } - // === THREE === DETERMINE ROLL PARTICIPANT USER(S) - // Check config.rollParticipantData to determine if roll starts with any participants - if (config.rollParticipantData) { - userIDs[RollPermissions.Participant].push(...getParticipantDocUserIDs(config.rollParticipantData, playerUserIDs)); - } - // === FOUR === ASSIGN ROLL OBSERVERS - // Add remaining players as observers. - userIDs[RollPermissions.Observer] = playerUserIDs - .filter((uID) => !userIDs[RollPermissions.Participant].includes(uID)); - // === FIVE === PARSE INTO {ID: PERMISSION} FORMAT - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - return userFlagData; - /** - * Generates BladesRollParticipant documents from the provided schema data. - * @param {BladesRoll.RollParticipantDataSet} participantData - */ - function getParticipantDocs(participantData) { - return Object.values(flattenObject(participantData)) - .map((pData) => { - if (BladesRollParticipant.IsDoc(pData)) { - return pData; - } - if (BladesRollParticipant.IsValidData(pData)) { - if (typeof pData.rollParticipantID === "string") { - const pDoc = game.actors.get(pData.rollParticipantID) ?? game.items.get(pData.rollParticipantID); - if (BladesRollParticipant.IsDoc(pDoc)) { - return pDoc; - } - } - } - // Throw an error with sufficient debug data if pData does not match any expected types - throw new Error(`[getParticipantDocs] Invalid participant data encountered. Data: ${JSON.stringify(pData)}, Expected: "BladesRollParticipant or valid participant data", Function Context: "getParticipantDocs", Participant Data: ${JSON.stringify(participantData)}`); - }); - } - /** - * Returns the user ids of potential BladesRollParticipants defined in the provided data schema. - * @param {BladesRoll.RollParticipantDataSet} participantData - * @param {IDString[]} unassignedIDs - */ - function getParticipantDocUserIDs(participantData, unassignedIDs) { - return getParticipantDocs(participantData) - .map((pDoc) => { - if (BladesPC.IsType(pDoc) && typeof pDoc.primaryUser?.id === "string") { - return pDoc.primaryUser.id; - } - else if (BladesCrew.IsType(pDoc) - || BladesItem.IsType(pDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return unassignedIDs; - } - return null; - }) - .flat() - .filter((pUser) => pUser !== null && !userIDs[RollPermissions.Primary].includes(pUser)); - } - } - static BuildLinkConfig(config) { - // Prepare partial target link config - const partialLinkConfig = {}; - if ("targetKey" in config && config.targetKey) { - partialLinkConfig.targetKey = config.targetKey; - } - else if ("targetFlagKey" in config && config.targetFlagKey) { - partialLinkConfig.targetFlagKey = config.targetFlagKey; - } - if ("target" in config) { - if (U.isDocUUID(config.target)) { - partialLinkConfig.targetID = config.target; - } - else if (U.isDocID(config.target)) { - const confTarget = game.actors.get(config.target) - ?? game.items.get(config.target) - ?? game.messages.get(config.target) - ?? game.users.get(config.target); - if (confTarget) { - partialLinkConfig.targetID = confTarget.uuid; - } - else { - throw new Error(`[BladesRoll.BuildLinkConfig] No target found with id ${config.target}.`); - } - } - else { - partialLinkConfig.targetID = config.target.uuid; - } - } - else if ("targetID" in config) { - partialLinkConfig.targetID = config.targetID; - } - else { - throw new Error("[BladesRoll.BuildLinkConfig] You must provide a valid target or targetID in the config object."); - } - // If neither targetKey nor targetFlagKey are provided, set targetFlagKey to 'rollCollab'. - if (!partialLinkConfig.targetKey && !partialLinkConfig.targetFlagKey) { - partialLinkConfig.targetFlagKey = "rollCollab"; - } - // Build target link config - if (BladesTargetLink.IsValidConfig(partialLinkConfig)) { - return BladesTargetLink.BuildLinkConfig(partialLinkConfig); - } - throw new Error("[BladesRoll.BuildLinkConfig] Invalid link config."); - } - /** - * Asynchronously creates a new instance of `BladesRoll` or its subclasses. - * - * This generic static method is designed to facilitate the creation of roll instances with - * configurations specific to the type of roll being created. It ensures that the correct type - * of roll instance is returned based on the class it's called on, allowing for a flexible and - * type-safe creation process that can be extended to subclasses of `BladesRoll`. - * - * @template C The class on which `New` is called. This class must extend `BladesRoll` and - * must be constructible with a configuration object that is either a `BladesRoll.Config` or - * a combination of `BladesTargetLink.Data` and a partial `BladesRoll.Schema`. This ensures - * that any subclass of `BladesRoll` can use this method to create instances of itself while - * applying any class-specific configurations or behaviors. - * - * @param {BladesRoll.Config} config The configuration object for creating a new roll instance. - * This configuration includes all necessary data to initialize the roll, such as user permissions, - * roll type, and any modifications or additional data required for the roll's operation. - * - * @returns {Promise>} A promise that resolves to an instance of the class - * from which `New` was called. This allows for the dynamic creation of roll instances based - * on the subclass calling the method, ensuring that the returned instance is of the correct type. - * - * @example - * // Assuming `MyCustomRoll` is a subclass of `BladesRoll` - * MyCustomRoll.New(myConfig).then(instance => { - * // `instance` is of type `MyCustomRoll` - * }); - * - * @remarks - * - The method performs several key operations as part of the roll instance creation process: - * 1. Builds link configuration based on the provided config. - * 2. Prepares roll user flag data to determine permissions for different users. - * 3. Validates that a roll type is defined in the config, throwing an error if not. - * 4. Logs the roll data for debugging or auditing purposes. - * 5. Constructs and initializes the roll instance, including setting up roll modifications - * and sending out socket calls to inform all users about the roll. - * - This method is central to the dynamic and flexible creation of roll instances within the - * system, allowing for easy extension and customization in subclasses of `BladesRoll`. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - // Prepare roll user flag data - config.userPermissions = this.GetUserPermissions(config); - // Ensure rollType is defined - if (!config.rollType) { - throw new Error("rollType must be defined in config"); - } - // Log the roll data - eLog.checkLog3("bladesRoll", "BladesRoll.NewRoll()", { config }); - // Construct and initialize the BladesRoll/BladesTargetLink instance - const rollInst = await this.Create({ ...config, ...linkConfig }); - if (!rollInst.isInitPromiseResolved) { - eLog.checkLog3("bladesRoll", "BladesRoll Init Promise NOT Resolved After Awaiting Create"); - await U.waitFor(rollInst.initPromise); - } - else { - eLog.checkLog3("bladesRoll", "BladesRoll Init Promise Resolved After Awaiting Create"); - } - // Send out socket calls to all users to see the roll. - rollInst.constructRollCollab_SocketCall(rollInst.linkData); - return rollInst; - } - async initTargetLink() { - this.initialSchema.rollModsData = this.rollModsDataSet; - super.initTargetLink(); - } - get rollModsSchemaSets() { - const compiledModSchemaSets = []; - // Add roll mods on rollPrimary - if (this.rollPrimary) { - compiledModSchemaSets.push(...this.rollPrimary.rollPrimaryModsSchemaSet - .filter((pSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== pSchema.key))); - } - // Add roll mods on rollOpposition - if (this.rollOpposition?.rollOppModsSchemaSet) { - compiledModSchemaSets.push(...this.rollOpposition.rollOppModsSchemaSet - .filter((oSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== oSchema.key))); - } - // Add default roll mods - compiledModSchemaSets.push(...this.constructor.DefaultRollModSchemaSet - .filter((dSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== dSchema.key))); - // If this is a downtime action roll, add default downtime action roll mods - if (this.rollDowntimeAction) { - compiledModSchemaSets.push({ - key: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }); - if (this.rollDowntimeAction !== DowntimeAction.IndulgeVice) { - compiledModSchemaSets.push({ - key: "CanBuyResultLevel-positive-after", - name: "Buying Result Level", - section: RollModSection.after, - base_status: RollModStatus.ForcedOn, - posNeg: "positive", - modType: RollModType.general, - value: 0, - effectKeys: [], - tooltip: "

Buying Result Level

After your roll, you can increase the result level by one for each Coin you spend.

" - }); - } - if (this.rollDowntimeAction === DowntimeAction.AcquireAsset) { - compiledModSchemaSets.push({ - key: "RepeatPurchase-positive-roll", - name: "Repeat Purchase", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Repeat Purchase Bonus

Add +1d if you have previously acquired this asset or service with a Acquire Asset Downtime activity.

" - }, { - key: "RestrictedItem-negative-after", - name: "Restricted", - section: RollModSection.after, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 0, - effectKeys: ["Cost-Heat2"], - tooltip: "

Restricted

Whether contraband goods or dangerous materials, this Acquire Asset Downtime activity will add +2 Heat to your crew.

" - }); - } - } - return compiledModSchemaSets; - } - get rollModsDataSet() { - const { linkData } = this; - const modLinkConfig = { - targetID: linkData.targetID, - isScopingById: true, - ...("targetKey" in linkData - ? { targetKey: `${this.targetKeyPrefix}.rollModsData` } - : {}), - ...("targetFlagKey" in linkData - ? { targetFlagKey: `${this.targetFlagKeyPrefix}.rollModsData` } - : {}) - }; - return Object.fromEntries(this.rollModsSchemaSets - .map((modSchema) => { - const modData = BladesTargetLink.ParseConfigToData({ - ...BladesRollMod.ApplySchemaDefaults(modSchema), - ...modLinkConfig - }); - return [modData.id, modData]; - })); - } - // #endregion - // #region SOCKET CALLS & RESPONSES ~ - static GetRollSubClass(linkData) { - const targetLink = new BladesTargetLink(linkData); - switch (targetLink.data.rollType) { - case RollType.Action: return BladesActionRoll; - case RollType.Fortune: { - if (targetLink.data.rollSubType === RollSubType.Engagement) { - return BladesEngagementRoll; - } - else if (targetLink.data.rollSubType === RollSubType.Incarceration) { - return BladesIncarcerationRoll; - } - return BladesFortuneRoll; - } - case RollType.Resistance: { - if (targetLink.data.isInlineResistanceRoll) { - return BladesInlineResistanceRoll; - } - return BladesResistanceRoll; - } - case RollType.IndulgeVice: return BladesIndulgeViceRoll; - } - } - constructRollCollab_SocketCall(linkData) { - socketlib.system.executeForEveryone("constructRollCollab_SocketCall", linkData); - } - static constructRollCollab_SocketResponse(linkData) { - const rollInst = new (this.GetRollSubClass(linkData))(linkData); - eLog.checkLog3("rollCollab", "constructRollCollab_SocketResponse()", { params: { linkData }, rollInst }); - this.renderRollCollab_SocketResponse(rollInst.id); - } - renderRollCollab_SocketCall() { - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - static renderRollCollab_SocketResponse(id) { - const rollInst = game.eunoblades.Rolls.get(id); - if (!rollInst) { - throw new Error(`[BladesRoll.renderRollCollab_SocketResponse] No roll found with id ${id}.`); - } - rollInst.renderRollCollab(); - } - closeRollCollab_Animation() { - return U.gsap.effects.blurRemove(this.elem$, { ignoreMargins: true }); - } - async closeRollCollab_SocketCall() { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForOthers("closeRollCollab_SocketCall", this.id); - await U.waitFor(this.closeRollCollab_Animation()); - } - static closeRollCollab_SocketResponse(id) { - game.eunoblades.Rolls.get(id)?.closeRollCollab_Animation(); - } - // #endregion - // #region *** CONSTRUCTOR *** ~ - rollPermission; - _rollPrimary; - _rollOpposition; - _rollParticipants; - projectSelectOptions; - constructor(dataOrConfig) { - super(dataOrConfig); - this.rollPermission = this.data.userPermissions[game.user.id]; - this._rollPrimary = new BladesRollPrimary(this, this.data.rollPrimaryData); - if (this.data.rollOppData) { - this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData); - } - else if (this.data.rollDowntimeAction === DowntimeAction.LongTermProject) { - this.projectSelectOptions = Array.from(game.items) - .filter((item) => BladesItem.IsType(item, BladesItemType.project)) - .map((project) => ({ value: project.id ?? "", display: project.name })); - } - if (this.data.rollParticipantData) { - this._rollParticipants = {}; - for (const [rollSection, rollParticipantList] of Object.entries(this.data.rollParticipantData)) { - if ([RollModSection.roll, RollModSection.position, RollModSection.effect] - .includes(rollSection) && !U.isEmpty(rollParticipantList)) { - const sectionParticipants = {}; - for (const [participantType, participantData] of Object.entries(rollParticipantList)) { - sectionParticipants[participantType] = new BladesRollParticipant(this, rollSection, participantType, participantData); - } - this._rollParticipants[rollSection] = sectionParticipants; - } - } - } - game.eunoblades.Rolls.set(this.id, this); - } - // #endregion - // #region Roll Participation & User Permissions - async addRollParticipant(participantRef, rollSection, rollSubSection) { - if (!rollSubSection) { - /* Insert logic to determine from rollSection and number of existing Group_X members */ - rollSubSection = "Assist"; - } - const participantData = typeof participantRef === "string" - ? game.actors.get(participantRef) - ?? game.actors.getName(participantRef) - ?? game.items.get(participantRef) - ?? game.items.getName(participantRef) - : participantRef; - if (!BladesRollParticipant.IsValidData(participantData)) { - throw new Error("Bad data."); - } - const rollParticipant = new BladesRollParticipant(this, rollSection, rollSubSection, participantData); - await rollParticipant.updateRollFlags(); - if (this.isRendered) { - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - } - async removeRollParticipant(rollSection, rollSubSection) { - await this.updateTarget(`rollParticipantData.${rollSection}.${rollSubSection}`, null); - } - async updateUserPermission(_user, _permission) { - /* Force-render roll with new permissions */ - } - // #endregion - // #region Basic User Flag Getters/Setters ~ - // get data(): BladesRoll.FlagData { - // if (!this.document.getFlag(C.SYSTEM_ID, "rollCollab")) { - // throw new Error("[get flags()] No RollCollab Flags Found on User Document"); - // } - // return this.document.getFlag(C.SYSTEM_ID, "rollCollab") as BladesRoll.FlagData; - // } - get rollPrimary() { - return this._rollPrimary; - } - get rollPrimaryDoc() { - return this.rollPrimary.rollPrimaryDoc; - } - get rollOpposition() { - if (!this._rollOpposition && BladesRollOpposition.IsValidData(this.data.rollOppData)) { - this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData); - } - return this._rollOpposition?.refresh(); - } - set rollOpposition(val) { - if (val === undefined) { - this._rollOpposition = undefined; - } - else { - this._rollOpposition = val; - val.updateRollFlags(); - } - } - get rollClockKey() { - return this.data.rollClockKey - ? game.eunoblades.ClockKeys.get(this.data.rollClockKey) - : undefined; - } - set rollClockKey(val) { - this.updateTarget("rollClockKeyID", val ?? null); - } - /** - * This method prepares the roll participant data. - * It iterates over the roll sections (roll, position, effect) and for each section, - * it creates a new BladesRollParticipant instance for each participant in that section. - * The created instances are stored in the rollParticipants object. - */ - prepareRollParticipantData() { - const participantFlagData = this.data.rollParticipantData; - if (!participantFlagData) { - return; - } - const rollParticipants = {}; - [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].forEach((rollSection) => { - const sectionFlagData = participantFlagData[rollSection]; - if (sectionFlagData) { - const sectionParticipants = {}; - Object.entries(sectionFlagData).forEach(([subSection, subSectionFlagData]) => { - if (subSectionFlagData) { - sectionParticipants[subSection] = - new BladesRollParticipant(this, rollSection, subSection, subSectionFlagData); - } - }); - rollParticipants[rollSection] = sectionParticipants; - } - }); - this._rollParticipants = rollParticipants; - } - get rollParticipants() { - return this._rollParticipants; - } - getRollParticipant(section, subSection) { - if (isParticipantSection(section) && isParticipantSubSection(subSection)) { - const sectionData = this.rollParticipants?.[section]; - if (sectionData) { - return sectionData[subSection] ?? null; - } - } - return null; - } - get rollParticipantSelectOptions() { - const nonPrimaryPCs = BladesPC.All - .filter((actor) => actor.hasTag(Tag.PC.ActivePC) && actor.id !== this.rollPrimary.rollPrimaryID) - .map((actor) => ({ value: actor.id, display: actor.name })); - return { - Assist: nonPrimaryPCs, - Setup: nonPrimaryPCs, - Group: nonPrimaryPCs - }; - } - get rollType() { return this.data.rollType; } - get rollSubType() { return this.data.rollSubType; } - set rollSubType(val) { - this.updateTarget("rollSubType", val ?? null); - } - get rollPhase() { - return this.data.rollPhase ?? RollPhase.Collaboration; - } - get rollDowntimeAction() { return this.data.rollDowntimeAction; } - get rollTrait() { return this.data.rollTrait; } - get rollTraitVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionVerbs)) { - return undefined; - } - return C.ActionVerbs[this.rollTrait]; - } - get rollTraitPastVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionPastVerbs)) { - return undefined; - } - return C.ActionPastVerbs[this.rollTrait]; - } - _rollTraitValOverride; - get rollTraitValOverride() { return this._rollTraitValOverride; } - set rollTraitValOverride(val) { this._rollTraitValOverride = val; } - get rollTraitData() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipActions, - gmTooltip: C.ActionTooltipsGM[this.rollTrait] - }; - } - if (isAttribute(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipAttributes, - gmTooltip: C.AttributeTooltips[this.rollTrait] - }; - } - } - if (U.isInt(this.rollTrait)) { - return { - name: `+${this.rollTraitValOverride ?? this.rollTrait}`, - value: this.rollTraitValOverride ?? this.rollTrait, - max: this.rollTraitValOverride ?? this.rollTrait - }; - } - if (isFactor(this.rollTrait)) { - return { - name: U.tCase(this.rollTrait), - value: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.value ?? 0, - max: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.max ?? 10 - }; - } - throw new Error(`[get rollTraitData] Invalid rollTrait: '${this.rollTrait}'`); - } - get rollTraitOptions() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return Object.values(ActionTrait) - .map((action) => ({ - name: U.uCase(action), - value: action - })); - } - if (isAttribute(this.rollTrait)) { - return Object.values(AttributeTrait) - .map((attribute) => ({ - name: U.uCase(attribute), - value: attribute - })); - } - } - if (U.isInt(this.rollTrait)) { - return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - .map((num) => ({ - name: `+${num}`, - value: num - })); - } - if (isFactor(this.rollTrait)) { - return []; - } - throw new Error(`[get rollTraitOptions] Invalid rollTrait: '${this.rollTrait}'`); - } - get posEffectTrade() { - return this.data?.rollPosEffectTrade ?? false; - } - // getFlagVal(flagKey?: string): T | undefined { - // if (flagKey) { - // return this.document.getFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")) as T | undefined; - // } - // return this.document.getFlag(C.SYSTEM_ID, "rollCollab") as T | undefined; - // } - // async setFlagVal(flagKey: string, flagVal: unknown, isRerendering = true) { - // await this.document.setFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab."), flagVal); - // if (isRerendering) { - // socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - // } - // } - // async clearFlagVal(flagKey: string, isRerendering = true) { - // await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")); - // if (isRerendering) { - // socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - // } - // } - get initialPosition() { - return this.data.rollPositionInitial ?? Position.risky; - } - set initialPosition(val) { - this.updateTarget("rollPositionInitial", val ?? Position.risky); - } - get initialEffect() { - return this.data.rollEffectInitial ?? Effect.standard; - } - set initialEffect(val) { - this.updateTarget("rollEffectInitial", val ?? Effect.standard); - } - get isApplyingConsequences() { - if (this.rollType !== RollType.Action) { - return false; - } - if (!this.rollResult) { - return false; - } - if (![RollResult.partial, RollResult.fail].includes(this.rollResult)) { - return false; - } - return true; - } - // Get rollConsequence() --> For resistance rolls. - get rollConsequence() { - const { consequence } = this.data.resistanceData ?? {}; - if (!consequence?.id) { - return undefined; - } - return game.eunoblades.Consequences.get(consequence.id) - ?? new BladesConsequence(consequence); - } - // #endregion - // #region GETTERS: DERIVED DATA ~ - get rollPositionFinal() { - return Object.values(Position)[U.clampNum(Object.values(Position).indexOf(this.initialPosition) - + this.getModsDelta(RollModSection.position) - + (this.posEffectTrade === "position" ? 1 : 0) - + (this.posEffectTrade === "effect" ? -1 : 0), [0, 2])]; - } - get rollEffectFinal() { - return Object.values(Effect)[U.clampNum(Object.values(Effect).indexOf(this.initialEffect) - + this.getModsDelta(RollModSection.effect) - + (this.posEffectTrade === "effect" ? 1 : 0) - + (this.posEffectTrade === "position" ? -1 : 0), [0, 4])]; - } - get rollResultDelta() { - return this.getModsDelta(RollModSection.result) - + (this.data?.GMBoosts.Result ?? 0) - + (this.tempGMBoosts.Result ?? 0); - } - get rollResultFinal() { - if (this.rollResult === false) { - return false; - } - if (this.rollResultDelta === 0) { - return this.rollResult; - } - switch (this.rollType) { - case RollType.Action: - case RollType.Fortune: { - return Object.values(RollResult).toReversed()[U.clampNum(Object.values(RollResult).toReversed().indexOf(this.rollResult) - + this.rollResultDelta, [0, 3])]; - } - case RollType.Resistance: { // Return stress cost of resisting - if (this.isCritical) { - return -1; - } - return U.clampNum(6 - this.highestDieVal - this.rollResultDelta, [-1, Infinity]); - } - case RollType.IndulgeVice: { // Return stress cleared from indulging - return U.clampNum(this.highestDieVal + this.rollResultDelta, [0, Infinity]); - } - } - return false; - } - get finalDicePool() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.data.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)); - } - get isRollingZero() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.data.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)) <= 0; - } - _roll; - get roll() { - this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {}); - return this._roll; - } - get rollFactors() { - const defaultFactors = { - [Factor.tier]: { - name: "Tier", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: true, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.quality]: { - name: "Quality", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.scale]: { - name: "Scale", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.magnitude]: { - name: "Magnitude", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - } - }; - const mergedSourceFactors = U.objMerge(U.objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.source, { isMutatingOk: false }); - const mergedOppFactors = this.rollOpposition - ? U.objMerge(U.objMerge(defaultFactors, this.rollOpposition.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.opposition, { isMutatingOk: false }) - : {}; - return { - source: Object.fromEntries(Object.entries(mergedSourceFactors) - .map(([factor, factorData]) => { - factorData.value += - (this.data.GMBoosts[factor] ?? 0) - + (this.tempGMBoosts[factor] ?? 0); - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })), - opposition: Object.fromEntries(Object.entries(mergedOppFactors) - .map(([factor, factorData]) => { - factorData.value += this.data.GMOppBoosts[factor] ?? 0; - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })) - }; - } - // #endregion - // #region ROLL MODS: Getters & Update Method ~ - initRollMods() { - // Reset override values previously enabled by rollmods - this.rollTraitValOverride = undefined; - this.rollFactorPenaltiesNegated = {}; - this.tempGMBoosts = {}; - // ESLINT DISABLE: Dev Code. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const initReport = {}; - let initReportCount = 0; - const watchMod = (label) => { - if (BladesRoll.Debug.modWatch === false) { - return; - } - const reportLabel = `(${initReportCount}) == ${label}`; - const rollMod = this.rollMods - .find((mod) => BladesRoll.Debug.modWatch && BladesRoll.Debug.modWatch.exec(mod.name)); - if (rollMod) { - initReport[`${reportLabel} : ${rollMod.status}`] = { - inst: rollMod, - data: { ...rollMod.data }, - sourceName: rollMod.sourceName, - status: { - ALL: rollMod.status, - base: rollMod.baseStatus, - held: rollMod.heldStatus, - user: rollMod.userStatus - }, - is: { - active: rollMod.isActive, - visible: rollMod.isVisible, - conditional: rollMod.isConditional, - inInactiveBlock: rollMod.isInInactiveBlock, - isPush: rollMod.isPush, - isBasicPush: rollMod.isBasicPush - } - }; - } - else { - initReport[reportLabel] = "MOD NOT FOUND"; - } - initReportCount++; - }; - watchMod("INITIAL"); - /* *** PASS ZERO: ROLLTYPE VALIDATION PASS *** */ - this._rollMods = this.rollMods.filter((rollMod) => rollMod.isValidForRollType()); - watchMod("ROLLTYPE VALIDATION"); - /* *** PASS ONE: DISABLE PASS *** */ - // ... Conditional Status Pass - const conditionalDisablePass = this.rollMods.filter((rollMod) => !rollMod.setConditionalStatus()); - watchMod("DISABLE - CONDITIONAL"); - // ... AutoReveal/AutoEnable Pass - const autoRevealDisablePass = conditionalDisablePass.filter((rollMod) => !rollMod.setAutoStatus()); - watchMod("DISABLE - AUTO-REVEAL/ENABLE"); - // ... Payable Pass - autoRevealDisablePass.forEach((rollMod) => { rollMod.setPayableStatus(); }); - watchMod("DISABLE - PAYABLE"); - /* *** PASS TWO: FORCE-ON PASS *** */ - const parseForceOnKeys = (mod) => { - const holdKeys = mod.effectKeys.filter((key) => key.startsWith("ForceOn")); - if (holdKeys.length === 0) { - return; - } - while (holdKeys.length) { - const thisTarget = holdKeys.pop()?.split(/-/)?.pop(); - if (thisTarget === "BestAction") { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollTraitValOverride = Math.max(...Object.values(this.rollPrimaryDoc.actions)); - } - } - else { - const [targetName, targetCat, targetPosNeg] = thisTarget?.split(/,/) ?? []; - if (!targetName) { - throw new Error(`No targetName found in thisTarget: ${thisTarget}.`); - } - let targetMod = this.getRollModByName(targetName) - ?? this.getRollModByName(targetName, targetCat ?? mod.section); - if (!targetMod && targetName === "Push") { - [targetMod] = [ - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "negative").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getInactiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOff) - ]; - } - targetMod ??= this.getRollModByName(targetName, targetCat ?? mod.section, targetPosNeg ?? mod.posNeg); - if (!targetMod) { - throw new Error(`No mod found matching ${targetName}/${targetCat}/${targetPosNeg}`); - } - if (!targetMod.isActive) { - targetMod.heldStatus = RollModStatus.ForcedOn; - parseForceOnKeys(targetMod); - } - else { - targetMod.heldStatus = RollModStatus.ForcedOn; - } - } - } - }; - this.getActiveRollMods().forEach((rollMod) => parseForceOnKeys(rollMod)); - watchMod("FORCE-ON PASS"); - /* *** PASS THREE: PUSH-CHECK PASS *** */ - // IF ROLL FORCED ... - if (this.isForcePushed()) { - // ... Force Off _ALL_ visible, inactive "Is-Push" mods. - this.getInactivePushMods() - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("PUSH-CHECK: FORCE-OFF IS-PUSH"); - } - // ... BY CATEGORY ... - [RollModSection.roll, RollModSection.effect].forEach((cat) => { - if (this.isPushed(cat)) { - // ... if pushed by positive mod, Force Off any visible Bargain - if (cat === RollModSection.roll && this.isPushed(cat, "positive")) { - const bargainMod = this.getRollModByKey("Bargain-positive-roll"); - if (bargainMod?.isVisible) { - bargainMod.heldStatus = RollModStatus.ForcedOff; - } - } - watchMod("PUSH-CHECK: FORCE OFF BARGAIN"); - } - else { - // Otherwise, hide all Is-Push mods - this.getInactivePushMods(cat) - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.Hidden; }); - watchMod("PUSH-CHECK: HIDE IS-PUSH"); - } - }); - /* *** PASS FOUR: Relevancy Pass *** */ - this.getVisibleRollMods() - .forEach((mod) => { mod.setRelevancyStatus(); }); - watchMod("RELEVANCY PASS"); - /* *** PASS FIVE: Overpayment Pass *** */ - // ... If 'Cost-SpecialArmor' active, ForceOff other visible Cost-SpecialArmor mods - const activeArmorCostMod = this.getActiveRollMods().find((mod) => mod.effectKeys.includes("Cost-SpecialArmor")); - if (activeArmorCostMod) { - this.getVisibleRollMods() - .filter((mod) => !mod.isActive && mod.effectKeys.includes("Cost-SpecialArmor")) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("OVERPAYMENT PASS"); - } - eLog.checkLog2("rollMods", "*** initRollMods() PASS ***", initReport); - } - isTraitRelevant(trait) { - if (trait in Factor) { - const { source, opposition } = this.rollFactors; - return Boolean(trait in source && trait in opposition && source[trait]?.isActive); - } - return false; - } - get isParticipantRoll() { - return (this.rollType === RollType.Fortune && !game.user.isGM) - || (this.rollSubType === RollSubType.GroupParticipant); - } - negatePushCost() { - const costlyPushMod = this.getActiveRollMods() - .find((mod) => mod.isPush && mod.stressCost > 0); - if (costlyPushMod) { - U.pullElement(costlyPushMod.effectKeys, (k) => k.startsWith("Cost-Stress")); - } - } - rollFactorPenaltiesNegated = {}; - negateFactorPenalty(factor) { - this.rollFactorPenaltiesNegated[factor] = true; - } - tempGMBoosts = {}; - isPushed(cat, posNeg) { return this.getActiveBasicPushMods(cat, posNeg).length > 0; } - hasOpenPush(cat, posNeg) { return this.isPushed(cat) && this.getOpenPushMods(cat, posNeg).length > 0; } - isForcePushed(cat, posNeg) { return this.isPushed(cat) && this.getForcedPushMods(cat, posNeg).length > 0; } - get rollCosts() { - if (!this.isPushed) { - return 0; - } - const harmPush = this.getRollModByKey("Push-negative-roll"); - const rollPush = this.getRollModByKey("Push-positive-roll"); - const effectPush = this.getRollModByKey("Push-positive-effect"); - const negatePushCostMods = this.getActiveRollMods(RollModSection.after, "positive") - .filter((mod) => mod.effectKeys.includes("Negate-PushCost")); - return ((harmPush?.isActive && harmPush?.stressCost) || 0) - + ((rollPush?.isActive && rollPush?.stressCost) || 0) - + ((effectPush?.isActive && effectPush?.stressCost) || 0) - - (negatePushCostMods.length * 2); - } - get rollCostData() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs ?? []) - .flat(); - } - getRollModByID(id) { return this.rollMods.find((rollMod) => rollMod.id === id); } - getRollModByName(name, cat, posNeg) { - const modMatches = this.rollMods.filter((rollMod) => { - if (U.lCase(rollMod.name) !== U.lCase(name)) { - return false; - } - if (cat && rollMod.section !== cat) { - return false; - } - if (posNeg && rollMod.posNeg !== posNeg) { - return false; - } - return true; - }); - if (modMatches.length === 0) { - return undefined; - } - if (modMatches.length > 1) { - return undefined; - } - return modMatches[0]; - } - getRollModByKey(key) { return this.rollMods.find((rollMod) => rollMod.data.key === key); } - getRollMods(cat, posNeg) { - return this.rollMods.filter((rollMod) => (!cat || rollMod.section === cat) - && (!posNeg || rollMod.posNeg === posNeg)); - } - getVisibleRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActiveRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getVisibleInactiveRollMods(cat, posNeg) { - return this.getVisibleRollMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getPushMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isPush); - } - getVisiblePushMods(cat, posNeg) { - return this.getPushMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getActiveBasicPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getInactivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getInactiveBasicPushMods(cat, posNeg) { - return this.getInactivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getForcedPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ForcedOn); - } - getOpenPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ToggledOn); - } - getModsDelta = (cat) => { - return U.sum([ - ...this.getActiveRollMods(cat, "positive").map((mod) => mod.value), - ...this.getActiveRollMods(cat, "negative").map((mod) => -mod.value) - ]); - }; - _rollMods; - /** - * Compare function for sorting roll mods. - * @param {BladesRollMod} modA First mod to compare. - * @param {BladesRollMod} modB Second mod to compare. - * @returns {number} - Comparison result. - */ - compareMods(modA, modB) { - // Define the order of mod names for sorting - const modOrder = ["Bargain", "Assist", "Setup"]; - // Check for basic push - if (modA.isBasicPush) { - return -1; - } - if (modB.isBasicPush) { - return 1; - } - // Check for active Bargain - if (modA.name === "Bargain" && modA.isActive) { - return -1; - } - if (modB.name === "Bargain" && modB.isActive) { - return 1; - } - // Check for push - if (modA.isPush) { - return -1; - } - if (modB.isPush) { - return 1; - } - // Check for mod name order - const modAIndex = modOrder.indexOf(modA.name); - const modBIndex = modOrder.indexOf(modB.name); - if (modAIndex !== -1 && modBIndex !== -1) { - return modAIndex - modBIndex; - } - // Default to alphabetical order - return modA.name.localeCompare(modB.name); - } - get rollMods() { - if (!this._rollMods) { - this._rollMods = Object.values(this.data.rollModsData).map((modData) => new BladesRollMod(modData, this)); - } - return [...this._rollMods].sort((modA, modB) => this.compareMods(modA, modB)); - } - // #endregion - // #region CONSEQUENCES: Getting, Accepting, Resisting - get consequences() { - const csqDataSet = this.data.consequenceData?.[this.rollPositionFinal]?.[this.rollResult]; - if (csqDataSet) { - return Object.values(csqDataSet).map((csqData) => new BladesConsequence(csqData)); - } - return []; - } - getConsequenceByID(csqID) { - return this.consequences.find((csq) => csq.id === csqID) ?? false; - } - get acceptedConsequences() { - if ([RollPhase.AwaitingConsequences, RollPhase.Complete].includes(this.rollPhase)) { - return this.consequences.filter((csq) => csq.isAccepted === true); - } - return []; - } - get unacceptedConsequences() { - if (this.rollPhase === RollPhase.AwaitingConsequences) { - return this.consequences.filter((csq) => csq.isAccepted !== true); - } - return []; - } - // #endregion - // #region *** ROLL COLLAB HTML INTERACTION *** ~ - /** - * Retrieve the data for rendering the base RollCollab sheet. - * @returns {Promise} The data which can be used to render the HTML of the sheet. - */ - get context() { - this.initRollMods(); - this.rollMods.forEach((rollMod) => rollMod.applyRollModEffectKeys()); - return this.getTemplateContext(); - } - /** - * Determines if the user is a game master. - * @returns {boolean} Whether the user is a GM. - */ - getIsGM() { - return game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM; - } - /** - * Gets the roll costs. - * @returns {BladesRoll.CostData[]} The roll costs. - */ - getRollCosts() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs) - .flat() - .filter((costData) => costData !== undefined); - } - /** - * Constructs the sheet data. - * @param {boolean} isGM If the user is a GM. - * @param {BladesRoll.CostData[]} rollCosts The roll costs. - * @returns {BladesRoll.Context} The constructed sheet data. - */ - getTemplateContext() { - const { data: rData, rollPrimary, rollTraitData, rollTraitOptions, rollClockKey, finalDicePool, rollPositionFinal, rollEffectFinal, rollResultDelta, rollResultFinal, rollMods, rollFactors } = this; - if (!rollPrimary) { - throw new Error("A primary roll source is required for BladesRoll."); - } - const baseData = { - ...this.data, - cssClass: "roll-collab", - isGM: this.isGM, - system: this.rollPrimaryDoc?.system, - rollMods, - rollPrimary, - rollTraitData, - rollTraitOptions, - diceTotal: finalDicePool, - rollOpposition: this.rollOpposition, - rollParticipants: this.rollParticipants, - rollParticipantOptions: this.rollParticipantSelectOptions, - rollEffects: Object.values(Effect), - rollTraitValOverride: this.rollTraitValOverride, - rollFactorPenaltiesNegated: this.rollFactorPenaltiesNegated, - posRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "positive")])), - negRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "negative")])), - hasInactiveConditionals: this.calculateHasInactiveConditionalsData(), - rollFactors, - ...this.calculateOddsHTML(finalDicePool, rollResultDelta) - }; - const GMBoostsData = this.calculateGMBoostsData(rData); - const positionEffectTradeData = this.calculatePositionEffectTradeData(); - const stressCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "Stress") - .map((costData) => [costData.label, costData.costAmount]); - const availableArmor = []; - if (this.rollPrimaryDoc instanceof BladesPC) { - availableArmor.push(...this.rollPrimaryDoc.availableArmor); - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - // Gang or Expert Cohort - for (let index = 0; index < this.rollPrimaryDoc.system.armor.value; index++) { - availableArmor.push("Armor"); - } - } - const armorCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "Armor") - .map((costData, index) => [costData.label, availableArmor[index]]) - .filter(([_label, armorType]) => armorType !== undefined); - const specialArmorCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "SpecialArmor") - .map((costData) => costData.label); - const userPermission = baseData.userPermissions[game.user.id] ?? RollPermissions.Observer; - // const downtimeData = this.processDowntimeActions(); - return { - ...baseData, - rollPrimary: this.rollPrimary, - rollPositionFinal, - rollEffectFinal, - rollResultFinal, - rollPositions: Object.values(Position), - rollEffects: Object.values(Effect), - rollResultDelta, - isAffectingResult: rollResultDelta !== 0 - || this.getVisibleRollMods(RollModSection.result).length > 0 - || (this.isGM && this.getRollMods(RollModSection.result).length > 0), - isAffectingAfter: this.getVisibleRollMods(RollModSection.after).length > 0 - || (this.isGM && this.getRollMods(RollModSection.after).length > 0), - ...GMBoostsData, - ...positionEffectTradeData, - rollClockKey: this.rollClockKey, - totalStressCost: stressCostDataSet.reduce((acc, [_label, amount]) => acc + amount, 0), - totalArmorCost: armorCostDataSet.length, - stressCosts: stressCostDataSet.length > 0 - ? Object.fromEntries(stressCostDataSet) - : undefined, - armorCosts: armorCostDataSet.length > 0 - ? Object.fromEntries(armorCostDataSet) - : undefined, - specArmorCost: specialArmorCostDataSet[0], - userPermission, - editable: userPermission === RollPermissions.Primary || userPermission === RollPermissions.GM, - gamePhase: game.eunoblades.Tracker.phase - }; - } - // type BladesSelectOption = { - // value: valueType, - // display: displayType - // }; - // protected processDowntimeActions() { - // const downtimeData: Record; - // if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - // downtimeData.canDoDowntimeActions = true; - // downtimeData.downtimeActionsRemaining = this.rollPrimaryDoc.remainingDowntimeActions; - // const availableDowntimeActions: DowntimeAction[] = []; - // if (this.rollType === RollType.Action) { - // availableDowntimeActions.push(...[ - // DowntimeAction.AcquireAsset, - // DowntimeAction.LongTermProject, - // DowntimeAction.Recover, - // DowntimeAction.ReduceHeat - // ]); - // } else if (this.rollType === RollType.Fortune) { - // availableDowntimeActions.push(...[ - // DowntimeAction. - // ]) - // } - // downtimeData.downtimeActionOptions = - // downtimeActionOptions?: Array - // } - calculateGMBoostsData(data) { - return { - GMBoosts: { - Dice: data.GMBoosts.Dice ?? 0, - [Factor.tier]: data.GMBoosts[Factor.tier] ?? 0, - [Factor.quality]: data.GMBoosts[Factor.quality] ?? 0, - [Factor.scale]: data.GMBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: data.GMBoosts[Factor.magnitude] ?? 0, - Result: data.GMBoosts.Result ?? 0 - }, - GMOppBoosts: { - [Factor.tier]: data.GMOppBoosts[Factor.tier] ?? 0, - [Factor.quality]: data.GMOppBoosts[Factor.quality] ?? 0, - [Factor.scale]: data.GMOppBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: data.GMOppBoosts[Factor.magnitude] ?? 0 - } - }; - } - calculateOddsHTML(diceTotal, rollResultDelta) { - if (this.rollType === RollType.Resistance) { - return this.calculateOddsHTML_Resistance(diceTotal); - } - return this.calculateOddsHTML_Standard(diceTotal, rollResultDelta); - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @param {number} rollResultDelta - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Standard(diceTotal, rollResultDelta) { - const oddsColors = { - crit: "var(--blades-gold)", - success: "var(--blades-white-bright)", - partial: "var(--blades-grey)", - fail: "var(--blades-black-dark)" - }; - const odds = { ...C.DiceOddsStandard[diceTotal] }; - if (rollResultDelta < 0) { - for (let i = rollResultDelta; i < 0; i++) { - oddsColors.crit = oddsColors.success; - oddsColors.success = oddsColors.partial; - oddsColors.partial = oddsColors.fail; - } - } - else if (rollResultDelta > 0) { - for (let i = 0; i < rollResultDelta; i++) { - oddsColors.fail = oddsColors.partial; - oddsColors.partial = oddsColors.success; - oddsColors.success = oddsColors.crit; - } - } - const resultElements = []; - Object.entries(odds).reverse().forEach(([result, chance]) => { - if (chance === 0) { - return; - } - resultElements.push(`
 
`); - }); - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Resistance(diceTotal) { - // Const oddsColors = [ - // "var(--blades-gold)", // -1 - // "var(--blades-white)", // 0 - // "var(--blades-red-bright)", // 1 - // "var(--blades-red-dark)", // 2 - // "var(--blades-red-bright)", // 3 - // "var(--blades-red-dark)", // 4 - // "var(--blades-red-bright)" // 5 - // ].reverse(); - const oddsColors = [ - "var(--blades-gold)", // -1 - "var(--blades-white)", // 0 - "var(--blades-red)", // 1 - "var(--blades-red)", // 2 - "var(--blades-red)", // 3 - "var(--blades-red)", // 4 - "var(--blades-red)" // 5 - ].reverse(); - const oddsFilters = [ - "none", - "none", - "brightness(0.2)", - "brightness(0.4)", - "brightness(0.6)", - "brightness(0.8)", - "none" - ].reverse(); - const odds = [...C.DiceOddsResistance[diceTotal]].reverse(); - const resultElements = []; - for (let index = 0; index < odds.length; index++) { - const chance = odds[index]; - if (chance > 0) { - const color = oddsColors[index]; - const filter = oddsFilters[index]; - resultElements.push(...[ - `
 
` - ]); - } - } - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate data for position and effect trade. - * @returns {{canTradePosition: boolean, canTradeEffect: boolean}} - */ - calculatePositionEffectTradeData() { - const canTradePosition = this.posEffectTrade === "position" || (this.posEffectTrade === false - && this.rollPositionFinal !== Position.desperate - && this.rollEffectFinal !== Effect.extreme); - const canTradeEffect = this.posEffectTrade === "effect" || (this.posEffectTrade === false - && this.rollPositionFinal !== Position.controlled - && this.rollEffectFinal !== Effect.zero); - return { canTradePosition, canTradeEffect }; - } - /** - * Calculate data on whether there are any inactive conditionals. - * @returns {Record} - Data on inactive conditionals. - */ - calculateHasInactiveConditionalsData() { - const hasInactive = {}; - for (const section of Object.values(RollModSection)) { - hasInactive[section] = this.getRollMods(section).filter((mod) => mod.isInInactiveBlock).length > 0; - } - return hasInactive; - } - // #endregion - // #region *** EVALUATING ROLL *** ~ - // #region DICE ~ - _dieVals; - get dieVals() { - return this.roll.terms[0].results - .map((result) => result.result) - .sort() - .reverse(); - // return this._dieVals; - } - // Accounts for rolling zero dice by removing highest. - get finalDieVals() { - return this.isRollingZero ? this.dieVals.slice(1) : this.dieVals; - } - get finalDiceData() { - eLog.checkLog3("rollCollab", "[get finalDiceData()]", { roll: this, dieVals: this.dieVals }); - const dieVals = [...this.dieVals]; - const ghostNum = this.isRollingZero ? dieVals.shift() : null; - const isCritical = dieVals.filter((val) => val === 6).length >= 2; - const diceData = dieVals.map((val, i) => ({ - value: val, - dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i), - dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical) - })); - if (ghostNum) { - diceData.push({ - value: ghostNum, - dieClass: "blades-die-ghost", - dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false) - }); - } - return diceData; - } - // get dieValsHTML(): string { - // eLog.checkLog3("rollCollab", "[get dieValsHTML()]", {roll: this, dieVals: this.dieVals}); - // const dieVals = [...this.dieVals]; - // const ghostNum = this.isRollingZero ? dieVals.shift() : null; - // const isCritical = dieVals.filter((val) => val === 6).length >= 2; - // const diceData = dieVals.map((val, i) => ({ - // value: val, - // dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i), - // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical) - // })); - // if (ghostNum) { - // diceData.push({ - // value: ghostNum, - // dieClass: "blades-die-ghost", - // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false) - // }); - // } - // return [ - // ...dieVals.map((val, i) => ``), - // ghostNum ? `` : null - // ] - // .filter((val): val is string => typeof val === "string") - // .join(""); - // } - // #endregion - // #region RESULT GETTERS ~ - get isCritical() { - return this.finalDieVals.filter((val) => val === 6).length >= 2; - } - get isSuccess() { - return Boolean(!this.isCritical && this.finalDieVals.find((val) => val === 6)); - } - get isPartial() { - return Boolean(!this.isCritical && !this.isSuccess && this.finalDieVals.find((val) => val && val >= 4)); - } - get isFail() { - return !this.isCritical && !this.isSuccess && !this.isPartial; - } - get highestDieVal() { - return this.finalDieVals[0]; - } - get rollResult() { - /* Subclass overrides determine how roll result is communicated. */ - throw new Error("[BladesRoll.rollResult] Unimplemented by Subclass."); - } - // #endregion - get isResolved() { return this.roll.total !== undefined; } - async evaluateRoll() { - // If this command is called on an already-resolved roll, close the roll collab element and return. - if (this.isResolved) { - this.closeRollCollab_Animation(); - return this.data; - } - this.closeRollCollab_SocketCall(); - eLog.checkLog3("rollCollab", "[resolveRoll()] Before Evaluation", { roll: this, rollData: { ...this.data } }); - await this.roll.evaluate({ async: true }); - return await this.updateTargetData({ - ...this.data, - rollPositionFinal: this.rollPositionFinal, - rollEffectFinal: this.rollEffectFinal, - rollResult: this.rollResult, - rollTraitVerb: this.rollTraitVerb, - rollTraitPastVerb: this.rollTraitPastVerb, - finalDiceData: this.finalDiceData, - rollPhase: this.isApplyingConsequences - ? RollPhase.AwaitingConsequences - : RollPhase.Complete - }); - } - async resolveRollResult() { - /* Subclass overrides determine how result affects roll participants */ - throw new Error("[BladesRoll.resolveRollResult] Unimplemented by Subclass."); - } - async outputRollToChat() { - await BladesChat.create({ - speaker: this.getSpeaker(BladesChat.getSpeaker()), - content: await renderTemplate(this.chatTemplate, this.data), - type: CONST.CHAT_MESSAGE_TYPES.ROLL, - flags: { - "eunos-blades": { rollData: this.data } - } - }); - } - async resolveRoll() { - await this.evaluateRoll(); - this.resolveRollResult(); - await this.outputRollToChat(); - } - // #endregion - // #region *** INTERFACING WITH BLADESCHAT *** - getSpeaker(chatSpeaker) { - // Compare against rollPrimary and modify accordingly. - const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryDoc } = this.rollPrimary; - chatSpeaker.alias = rollPrimaryName; - if ([BladesItemType.cohort_gang, BladesItemType.cohort_expert].includes(rollPrimaryType)) { - chatSpeaker.actor = rollPrimaryDoc?.parent?.id ?? chatSpeaker.actor; - if (rollPrimaryDoc?.parent instanceof BladesPC) { - chatSpeaker.alias = `${chatSpeaker.alias} (${rollPrimaryDoc.parent.name})`; - } - } - else if ([BladesItemType.gm_tracker, BladesItemType.score].includes(rollPrimaryType)) { - chatSpeaker.actor = null; - chatSpeaker.alias = "The Gamemaster"; - } - else if (rollPrimaryID) { - chatSpeaker.actor = rollPrimaryID; - } - // chatSpeaker.alias = `${chatSpeaker.alias} Rolls ...`; - return chatSpeaker; - } - // #endregion - // #region *** ROLL COLLAB HTML ELEMENT *** - _elem$; - _overlayPosition = { x: 200, y: 200 }; - get overlayPosition() { return this._overlayPosition; } - set overlayPosition(val) { this._overlayPosition = val; } - get elem$() { - if (this._elem$) { - return this._elem$; - } - const elem$ = $(`#${this.id}`); - if (elem$.length) { - this._elem$ = elem$; - } - else { - this._elem$ = $(`
`).appendTo("body"); - this._elem$.css({ - left: `${this.overlayPosition.x}px`, - top: `${this.overlayPosition.y}px` - }); - } - return this._elem$; - } - async renderRollCollab() { - this.prepareRollParticipantData(); - const html = await renderTemplate(this.collabTemplate, this.context); - this.elem$.html(html); - this.activateListeners(); - } - get isRendered() { - return Boolean(this._elem$?.length); - } - get collabTemplate() { - /* Subclass overrides determine template against which data is parsed */ - throw new Error("[BladesRoll.collabTemplate] Unimplemented by Subclass."); - } - get chatTemplate() { - /* Subclass overrides determine template against which data is parsed */ - throw new Error("[BladesRoll.chatTemplate] Unimplemented by Subclass."); - } - // #region LISTENER FUNCTIONS ~ - // async _handleConsequenceClick(event: ClickEvent) { - // const clickTarget$ = $(event.currentTarget); - // const csqParent$ = clickTarget$.closest(".comp.consequence-display-container"); - // const csqID = csqParent$.data("csq-id"); - // const chatElem$ = csqParent$.closest(".blades-roll"); - // const chatMessage$ = chatElem$.closest(".chat-message"); - // const chatID = chatMessage$.data("messageId") as IDString; - // const chatMessage = game.messages.get(chatID); - // if (!chatMessage) {return;} - // const csqs = await BladesConsequence.GetFromChatMessage(chatMessage); - // const thisCsq = csqs.find((csq) => csq.id === csqID); - // if (!thisCsq) {return;} - // switch (clickTarget$.data("action")) { - // case "accept-consequence": return thisCsq.resolveAccept(); - // case "resist-consequence": return thisCsq.resistConsequence(); - // case "armor-consequence": return thisCsq.resistArmorConsequence(); - // case "special-consequence": return thisCsq.resistSpecialArmorConsequence(); - // } - // return undefined as never; - // } - _toggleRollModClick(event) { - event.preventDefault(); - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const rollMod = this.getRollModByID(id); - if (!rollMod) { - throw new Error(`Unable to find roll mod with id '${id}'`); - } - rollMod.isRerendering = true; - switch (rollMod.status) { - case RollModStatus.Hidden: - rollMod.userStatus = RollModStatus.ForcedOff; - break; - case RollModStatus.ForcedOff: - rollMod.userStatus = RollModStatus.ToggledOff; - break; - case RollModStatus.ToggledOff: - rollMod.userStatus = RollModStatus.ToggledOn; - break; - case RollModStatus.ToggledOn: - rollMod.userStatus = game.user.isGM - ? RollModStatus.ForcedOn - : RollModStatus.ToggledOff; - break; - case RollModStatus.ForcedOn: - rollMod.userStatus = RollModStatus.Hidden; - break; - default: throw new Error(`Unrecognized RollModStatus: ${rollMod.status}`); - } - rollMod.isRerendering = false; - } - /** - * Handles setting of rollMod status via GM pop-out controls - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSet(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const status = elem$.data("status"); - if (!isModStatus(status) && status !== "Reset") { - return; - } - const rollMod = this.getRollModByID(id); - if (rollMod) { - rollMod.userStatus = status === "Reset" ? undefined : status; - } - } - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlSetTargetToValue(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target").replace(/flags\.eunos-blades\./, ""); - const value = elem$.data("value"); - await this.updateTarget(target, value); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _gmControlCycleTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const flagTarget = elem$.data("flagTarget"); - const curVal = elem$.data("curVal"); - const cycleVals = elem$.data("vals")?.split(/\|/); - if (!cycleVals) { - throw new Error(`Unable to parse cycle values from data-vals = ${elem$.data("vals")}`); - } - const curValIndex = cycleVals.indexOf(curVal); - if (curValIndex === -1) { - throw new Error(`Unable to find current value '${curVal}' in cycle values '${elem$.data("vals")}'`); - } - let newValIndex = curValIndex + 1; - if (newValIndex >= cycleVals.length) { - newValIndex = 0; - } - const newVal = cycleVals[newValIndex]; - eLog.checkLog3("gmControlCycleTarget", "gmControlCycleTarget", { flagTarget, curVal, cycleVals, curValIndex, newValIndex, newVal }); - await this.updateTarget(flagTarget, newVal); - } - /** - * Handles resetting value associated with GM number line on a right-click. - * @param {ClickEvent} event JQuery context menu event sent to listener. - */ - async _gmControlResetTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - await this.updateTarget($(event.currentTarget).data("target"), undefined); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetPosition(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const position = elem$.data("status"); - this.initialPosition = position; - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetEffect(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const effect = elem$.data("status"); - this.initialEffect = effect; - } - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlToggleFactor(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target"); - const value = !elem$.data("value"); - eLog.checkLog3("toggleFactor", "_gmControlToggleFactor", { event, target, value }); - const factorToggleData = this.data.rollFactorToggles; - const [thisSource, thisFactor, thisToggle] = target.split(/\./).slice(-3); - // If thisToggle is unrecognized, just toggle whatever value target points at - if (!["isActive", "isPrimary", "isDominant", "highFavorsPC"].includes(thisToggle)) { - await this.updateTarget(target, value); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - // Otherwise, first toggle targeted factor to new value - factorToggleData[thisSource][thisFactor] = { - ...factorToggleData[thisSource][thisFactor] ?? { display: "" }, - [thisToggle]: value - }; - // Then perform specific logic depending on toggle targeted: - switch (thisToggle) { - case "isDominant": - case "isPrimary": { - // Only one factor per sourceType can be declared Primary or Dominant: - // If one is being activated, must toggle off the others. - if (value === true) { - Object.values(Factor) - .filter((factor) => factor !== thisFactor) - .forEach((factor) => { - if (factorToggleData[thisSource][factor]?.[thisToggle] === true) { - factorToggleData[thisSource][factor] = { - ...factorToggleData[thisSource][factor], - [thisToggle]: false - }; - } - }); - } - break; - } - case "isActive": { - // 'isActive' should be synchronized when 1) value is true, and 2) the other value is false - if (value === true) { - const otherSource = thisSource === "source" ? "opposition" : "source"; - factorToggleData[otherSource][thisFactor] = { - ...factorToggleData[otherSource][thisFactor] ?? { display: "" }, - isActive: value - }; - } - break; - } - default: break; - } - await this.updateTarget("rollFactorToggles", factorToggleData); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _onSelectChange(event) { - event.preventDefault(); - const elem = event.currentTarget; - const { docType } = elem.dataset; - if (elem.value !== "" && docType?.startsWith("BladesRollParticipant")) { - const [_, section, subSection] = docType.split("."); - await this.addRollParticipant(elem.value, section, subSection); - } - else { - await U.EventHandlers.onSelectChange(this, event); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - } - async _onTextInputBlur(event) { - await U.EventHandlers.onTextInputBlur(this, event); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _onGMPopupClick(event) { - /** - * { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.updateTarget("rollPosEffectTrade", "effect") - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - else { - this.updateTarget("rollPosEffectTrade", false) - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - } - }); - this.elem$.find("[data-action='tradeEffect']").on({ - click: (event) => { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.updateTarget("rollPosEffectTrade", "position") - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - else { - this.updateTarget("rollPosEffectTrade", false) - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - } - }); - this.elem$.find("[data-action='roll']").on({ - click: () => this.resolveRoll() - }); - this.elem$ - .find("select[data-action='player-select']") - .on({ change: this._onSelectChange.bind(this) }); - if (!game.user.isGM) { - return; - } - /** - * Handles setting of rollMod status via GM pop-out controls - */ - this.elem$.find(".controls-toggle").on({ - click: (event) => { - event.preventDefault(); - $(event.currentTarget).parents(".controls-panel").toggleClass("active"); - } - }); - this.elem$.find("[data-action=\"gm-set\"]").on({ - click: this._gmControlSet.bind(this) - }); - /** - * Handles setting of baseline rollPosition via GM button line - */ - this.elem$.find("[data-action=\"gm-set-position\"]").on({ - click: this._gmControlSetPosition.bind(this) - }); - /** - * Handles setting of baseline rollEffect via GM button line - */ - this.elem$.find("[data-action=\"gm-set-effect\"]").on({ - click: this._gmControlSetEffect.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - this.elem$.find("[data-action=\"gm-set-target\"]").on({ - click: this._gmControlSetTargetToValue.bind(this), - contextmenu: this._gmControlResetTarget.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - this.elem$.find("[data-action=\"gm-cycle-target\"]").on({ - click: this._gmControlCycleTarget.bind(this) - }); - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - */ - this.elem$.find("[data-action=\"gm-toggle-factor\"]").on({ - click: this._gmControlToggleFactor.bind(this) - }); - this.elem$ - .find("select[data-action='gm-select']") - .on({ change: this._onSelectChange.bind(this) }); - // this.elem$ - // .find("[data-action=\"gm-edit-consequences\"]") - // .on({click: () => BladesDialog.DisplayRollConsequenceDialog(this)}); - this.elem$ - .find("[data-action=\"gm-text-popup\"]") - .on({ click: this._onGMPopupClick.bind(this) }); - this.elem$ - .find("[data-action='gm-text-input']") - .on({ blur: this._onTextInputBlur.bind(this) }); - } - // #endregion - // #endregion - // #region OVERRIDES: _canDragDrop, _onDrop, _onSubmit, close, render ~ - // override _canDragDrop() { - // return game.user.isGM; - // } - // override _onDrop(event: DragEvent) { - // const {uuid} = TextEditor.getDragEventData(event) as {uuid: UUIDString}; - // const dropDoc = fromUuidSync(uuid); - // if (BladesRollOpposition.IsDoc(dropDoc)) { - // this.rollOpposition = new BladesRollOpposition(this, {rollOppDoc: dropDoc}); - // } else if (dropDoc instanceof BladesProject && dropDoc.clockKey) { - // // Project dropped on roll: Assign project's clock key to roll. - // this.rollClockKey = dropDoc.clockKey; - // } - // } - async submitChange(prop, val) { - await this.updateTarget(prop, val); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } -} -class BladesActionRoll extends BladesRoll { - /* Not much -- most action roll things will extend to other rolls, but split out things like Position, Effect, default Mods */ - static ApplySchemaDefaults(schemaData) { - schemaData.rollType = RollType.Action; - if (!schemaData.rollPrimaryData) { - throw new Error("Must include a rollPrimaryData when constructing a BladesActionRoll object."); - } - // Validate the rollTrait - if (!(schemaData.rollTrait === "" || U.isInt(schemaData.rollTrait) || U.lCase(schemaData.rollTrait) in { ...ActionTrait, ...Factor })) { - throw new Error(`[BladesActionRoll.ApplySchemaDefaults()] Bad RollTrait for Action Roll: ${schemaData.rollTrait}`); - } - const fullSchema = super.ApplySchemaDefaults(schemaData); - const rollPrimary = BladesRollPrimary.Build(fullSchema); - // Modify Config object depending on downtime action where necessary. - switch (fullSchema.rollDowntimeAction) { // Remember: Can be done outside of Downtime during Flashbacks! - case DowntimeAction.AcquireAsset: { - fullSchema.rollTrait = Factor.tier; - break; - } - case DowntimeAction.LongTermProject: { - // Validate that rollOppData points to a project item - if (!BladesRollOpposition.IsValidData(fullSchema.rollOppData)) { - throw new Error("No rollOppData provided for LongTermProject roll."); - } - if (![ - BladesItemType.project, - BladesItemType.design - ].includes(fullSchema.rollOppData.rollOppType)) { - throw new Error("rollOppType must be 'project' or 'design' for LongTermProject roll."); - } - break; - } - case DowntimeAction.Recover: { - // Validate that rollPrimary is an NPC or a PC with Physiker. - if (BladesPC.IsType(rollPrimary.rollPrimaryDoc)) { - if (!rollPrimary.rollPrimaryDoc.abilities.find((ability) => ability.name === "Physiker")) { - throw new Error("A PC rollPrimary on a Recovery roll must have the Physiker ability."); - } - fullSchema.rollTrait = ActionTrait.tinker; - } - else if (rollPrimary.rollPrimaryDoc?.rollPrimaryType === BladesActorType.npc) { - fullSchema.rollTrait = Factor.quality; - } - else { - throw new Error("Only a PC with Physiker or an NPC can be rollPrimary on a Recover roll."); - } - break; - } - case DowntimeAction.ReduceHeat: { - // rollPrimary must be a cohort with a parent PC or Crew, - // and PC must be member of a crew - // and Crew must not have zero Heat. - let parentCrew = undefined; - if (rollPrimary.rollPrimaryDoc) { - const { parent } = rollPrimary.rollPrimaryDoc; - if (BladesCrew.IsType(parent)) { - parentCrew = parent; - } - else if (BladesPC.IsType(parent) && BladesCrew.IsType(parent.crew)) { - parentCrew = parent.crew; - } - } - if (!BladesCrew.IsType(parentCrew)) { - throw new Error(`Could not find crew for rollPrimary '${rollPrimary.rollPrimaryDoc?.rollPrimaryName}'`); - } - if (parentCrew.system.heat.value === 0) { - throw new Error("Attempt to Reduce Heat for a Crew with no Heat."); - } - break; - } - case undefined: break; - default: throw new Error(`Unrecognized Roll Downtime Action: ${fullSchema.rollDowntimeAction}`); - } - return { - rollPositionInitial: Position.risky, - rollEffectInitial: Effect.standard, - rollPosEffectTrade: false, - GMBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOppBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOverrides: {}, - rollFactorToggles: { - source: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - }, - opposition: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - } - }, - ...fullSchema, - rollPrimaryData: rollPrimary.data, - rollOppData: fullSchema.rollOppData instanceof BladesRollOpposition - ? fullSchema.rollOppData.data - : fullSchema.rollOppData - }; - } - static get DefaultRollModSchemaSet() { - return [ - { - key: "Push-positive-roll", - name: "PUSH", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["ForceOff-Bargain", "Cost-Stress2"], - tooltip: "

Push for +1d

For 2 Stress, add 1 die to your pool.

(You cannot also accept a Devil's Bargain to increase your dice pool: It's one or the other.)

" - }, - { - key: "Bargain-positive-roll", - name: "Bargain", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Devil's Bargain

The GM has offered you a Devil's Bargain.

Accept the terms to add 1 die to your pool.

(You cannot also Push for +1d to increase your dice pool: It's one or the other.)

" - }, - { - key: "Assist-positive-roll", - name: "Assist", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Assists

%DOC_NAME% is Assisting your efforts, adding 1 die to your pool.

" - }, - { - key: "Setup-positive-position", - name: "Setup", - section: RollModSection.position, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Position by one level.

" - }, - { - key: "Push-positive-effect", - name: "PUSH", - section: RollModSection.effect, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["Cost-Stress2"], - tooltip: "

Push for Effect

For 2 Stress, increase your Effect by one level.

" - }, - { - key: "Setup-positive-effect", - name: "Setup", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Effect by one level.

" - }, - { - key: "Potency-positive-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, you have Potency in this action, increasing your Effect by one level.

" - }, - { - key: "Potency-negative-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, @OPPOSITION_NAME@ has Potency against you, reducing your Effect by one level." - } - ]; - } - /** - * Asynchronously creates a new instance of this subclass of `BladesRoll`. - * - * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations - * to the instance creation process. It ensures that the returned instance is correctly typed - * and configured for this subclass. - * - * @param {BladesRoll.Config} config The configuration object for creating a new roll instance, - * extended with any subclass-specific configurations or requirements. - * - * @returns {Promise>} A promise that resolves to an instance of this subclass. - * - * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process - * for roll instances. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - // Call super.New and cast the result appropriately. - // The cast to InstanceType is safe here because C is constrained to typeof BladesActionRoll. - const rollInst = await super.New(parsedConfig); - return rollInst; - } - get rollModsSchemaSets() { - const rollModSchemaSets = super.rollModsSchemaSets; - // Add additional conditional roll mods based on effects of previous consequences. - if (this.rollPrimary.isWorsePosition) { - rollModSchemaSets.push({ - key: "WorsePosition-negative-position", - name: "Worse Position", - section: RollModSection.position, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Worse Position

A Consequence on a previous roll has worsened your Position.

" - }); - } - if (this.acceptedConsequences.some((csq) => csq.type === ConsequenceType.ReducedEffect)) { - rollModSchemaSets.push({ - key: "ReducedEffect-negative-effect", - name: "Reduced Effect", - section: RollModSection.effect, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Reduced Effect

A Consequence has worsened your Effect.

" - }); - } - return rollModSchemaSets; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-action${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - const templateParts = [ - "systems/eunos-blades/templates/chat/roll-result/action", - this.rollClockKey ? "-clock" : "" - ]; - if (this.rollDowntimeAction && [ - DowntimeAction.AcquireAsset, // action-acquireasset - DowntimeAction.ReduceHeat, // action-reduceheat - DowntimeAction.Recover // action-clock-recover - ].includes(this.rollDowntimeAction)) { - templateParts.push(`-${U.lCase(this.rollDowntimeAction)}`); - } - else if (this.rollSubType && [ - RollSubType.GatherInfo // action-gatherinfo - ].includes(this.rollSubType)) { - templateParts.push(`-${U.lCase(this.rollSubType)}`); - } - templateParts.push(".hbs"); - return templateParts.join(""); - } - get rollResult() { - if (!this.isResolved) { - return false; - } - if (this.isCritical) { - return RollResult.critical; - } - if (this.isSuccess) { - return RollResult.success; - } - if (this.isPartial) { - return RollResult.partial; - } - return RollResult.fail; - } - async resolveRollResult() { - eLog.checkLog2("bladesRoll", "[BladesActionRoll] Costs", this.getRollCosts()); - const armorCost = this.getRollCosts() - .filter((costData) => costData.costType === "Armor") - .length; - if (this.rollPrimaryDoc instanceof BladesPC) { - const stressCost = this.getRollCosts() - .filter((costData) => costData.costType === "Stress") - .reduce((acc, costData) => acc + costData.costAmount, 0); - if (stressCost !== 0) { - this.rollPrimaryDoc.adjustStress(stressCost); - } - const specArmorCost = this.getRollCosts() - .filter((costData) => costData.costType === "SpecialArmor") - .length; - if (specArmorCost !== 0) { - this.rollPrimaryDoc.spendSpecialArmor(); - } - } - if (armorCost !== 0) { - this.rollPrimary.spendArmor(armorCost); - } - if (this.getRollModByKey("WorsePosition-negative-position")?.isActive) { - this.rollPrimaryDoc?.unsetFlag("eunos-blades", "isWorsePosition"); - } - } -} -class BladesResistanceRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate consequenceData - if (!config.resistanceData || !BladesConsequence.IsValidConsequenceData(config.resistanceData?.consequence)) { - eLog.error("rollCollab", "[PrepareResistanceRoll] Bad Roll Consequence Data.", config); - throw new Error("[PrepareResistanceRoll()] Bad Consequence Data for Resistance Roll"); - } - // Set rollTrait - config.rollTrait = config.resistanceData.consequence.attribute; - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [1]", { config }); - return config; - } - /** - * Asynchronously creates a new instance of this subclass of `BladesRoll`. - * - * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations - * to the instance creation process. It ensures that the returned instance is correctly typed - * and configured for this subclass. - * - * @param {BladesRoll.Config} config The configuration object for creating a new roll instance, - * extended with any subclass-specific configurations or requirements. - * - * @returns {Promise>} A promise that resolves to an instance of this subclass. - * - * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process - * for roll instances. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - // Call super.New and cast the result appropriately. - // The cast to InstanceType is safe here because C is constrained to typeof BladesResistanceRoll. - const rollInst = await super.New(parsedConfig); - return rollInst; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-resistance${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/resistance.hbs"; - } - get stressCost() { - if (!this.isResolved) { - return 0; - } - const dieVals = [...this.finalDieVals]; - if (this.isCritical) { - return -1; - } - return 6 - (dieVals.shift() ?? 0); - } - get rollResult() { - if (!this.isResolved) { - return false; - } - return this.stressCost; - } - async resolveRollResult() { - if (this.rollPrimaryDoc instanceof BladesPC && this.stressCost !== 0) { - this.rollPrimaryDoc.adjustStress(this.stressCost); - } - } -} -class BladesInlineResistanceRoll extends BladesResistanceRoll { - get chatTemplate() { - return "systems/eunos-blades/templates/chat/components/inline-resistance.hbs"; - } -} -class BladesFortuneRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate the rollTrait - if (!(U.isInt(config.rollTrait) || U.lCase(config.rollTrait) in { ...ActionTrait, ...AttributeTrait, ...Factor })) { - throw new Error(`[PrepareFortuneRoll()] Bad RollTrait for Fortune Roll: ${config.rollTrait}`); - } - return config; - } - /** - * Asynchronously creates a new instance of this subclass of `BladesRoll`. - * - * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations - * to the instance creation process. It ensures that the returned instance is correctly typed - * and configured for this subclass. - * - * @param {BladesRoll.Config} config The configuration object for creating a new roll instance, - * extended with any subclass-specific configurations or requirements. - * - * @returns {Promise>} A promise that resolves to an instance of this subclass. - * - * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process - * for roll instances. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - // Call super.New and cast the result appropriately. - // The cast to InstanceType is safe here because C is constrained to typeof BladesFortuneRoll. - const rollInst = await super.New(parsedConfig); - return rollInst; - } -} -class BladesIndulgeViceRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate rollPrimary - const rollPrimaryDoc = BladesRollPrimary.GetDoc(config.rollPrimaryData?.rollPrimaryID); - if (!rollPrimaryDoc || !BladesPC.IsType(rollPrimaryDoc)) { - throw new Error("[BladesRoll.PrepareIndulgeViceRollConfig] RollPrimary must be a PC for Indulge Vice rolls."); - } - // Set rollTrait - const { attributes } = rollPrimaryDoc; - const minAttrVal = Math.min(...Object.values(attributes)); - config.rollTrait = U.sample(Object.values(AttributeTrait).filter((attr) => attributes[attr] === minAttrVal))[0]; - // Set other known config values - config.rollDowntimeAction = DowntimeAction.IndulgeVice; - return config; - } - /** - * Asynchronously creates a new instance of this subclass of `BladesRoll`. - * - * Overrides the `New` static method from `BladesRoll`, applying subclass-specific configurations - * to the instance creation process. It ensures that the returned instance is correctly typed - * and configured for this subclass. - * - * @param {BladesRoll.Config} config The configuration object for creating a new roll instance, - * extended with any subclass-specific configurations or requirements. - * - * @returns {Promise>} A promise that resolves to an instance of this subclass. - * - * @see {@link BladesRoll.New} for the base method's functionality and the generic creation process - * for roll instances. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - // Call super.New and cast the result appropriately. - // The cast to InstanceType is safe here because C is constrained to typeof BladesIndulgeViceRoll. - const rollInst = await super.New(parsedConfig); - return rollInst; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-indulgevice${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/indulgevice.hbs"; - } - get rollResult() { - if (!this.isResolved) { - return false; - } - return this.highestDieVal; - } - async resolveRollResult() { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollPrimaryDoc.indulgeStress(this.highestDieVal); - } - } -} -class BladesEngagementRoll extends BladesFortuneRoll { - static get DefaultRollModSchemaSet() { - return [ - { - key: "BoldPlan-positive-roll", - name: "Bold Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }, - { - key: "ComplexPlan-negative-roll", - name: "Complex Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }, - { - key: "ExploitWeakness-positive-roll", - name: "Exploiting a Weakness", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }, - { - key: "WellDefended-negative-roll", - name: "Well-Defended", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }, - { - key: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }, - { - key: "EnemyInterference-negative-roll", - name: "Enemy Interference", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - } - ]; - } - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/fortune-engagement.hbs"; - } -} -class BladesIncarcerationRoll extends BladesFortuneRoll { - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/fortune-incarceration.hbs"; - } -} -// #region EXPORTS ~ -export { BladesRollMod, BladesRollPrimary, BladesRollOpposition, BladesRollParticipant }; -export default BladesRoll; -export { BladesActionRoll, BladesResistanceRoll, BladesInlineResistanceRoll, BladesFortuneRoll, BladesIndulgeViceRoll, BladesEngagementRoll, BladesIncarcerationRoll }; -// #endregion diff --git a/module/classes/BladesRollTemp.js b/module/classes/BladesRollTemp.js deleted file mode 100644 index b8b6b9fe..00000000 --- a/module/classes/BladesRollTemp.js +++ /dev/null @@ -1,3653 +0,0 @@ -// @ts-nocheck -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region IMPORTS ~ -import U from "../core/utilities.js"; -import C, { BladesActorType, BladesItemType, RollPermissions, RollType, RollSubType, RollModType, RollModStatus, RollModSection, ActionTrait, DowntimeAction, AttributeTrait, Position, Effect, Factor, RollResult, RollPhase, ConsequenceType, Tag } from "../core/constants.js"; -import { BladesActor, BladesPC, BladesCrew } from "../documents/BladesActorProxy.js"; -import { BladesItem, BladesGMTracker } from "../documents/BladesItemProxy.js"; -import { ApplyTooltipAnimations, ApplyConsequenceAnimations } from "../core/gsap.js"; -import BladesConsequence from "./BladesConsequence.js"; -import BladesDialog from "./BladesDialog.js"; -import BladesChat from "./BladesChat.js"; -import BladesTargetLink from "./BladesTargetLink.js"; -// #endregion -// #region Types & Type Checking ~ -/** - * Checks if the given string is a RollType. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollType, false otherwise. - */ -function isRollType(str) { - return typeof str === "string" && str in RollType; -} -/** - * Checks if the given trait is an ActionTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an ActionTrait, false otherwise. - */ -function isAction(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in ActionTrait); -} -/** - * Checks if the given trait is an AttributeTrait. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is an AttributeTrait, false otherwise. - */ -function isAttribute(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in AttributeTrait); -} -/** - * Checks if the given trait is a Factor. - * @param {unknown} trait The trait to check. - * @returns {boolean} True if the trait is a Factor, false otherwise. - */ -function isFactor(trait) { - return Boolean(trait && typeof trait === "string" && U.lCase(trait) in Factor); -} -/** - * Checks if the given string is a RollModStatus. - * @param {unknown} str The string to check. - * @returns {boolean} True if the string is a RollModStatus, false otherwise. - */ -function isModStatus(str) { - return typeof str === "string" && str in RollModStatus; -} -/** - * Checks if the given section can contain BladesRollParticipant documents. - * @param {RollModSection} section - */ -function isParticipantSection(section) { - return [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].includes(section); -} -/** - * Checks if the given subSection can hold BladesRollParticipant documents. - * @param {string} subSection - */ -function isParticipantSubSection(subSection) { - if (subSection.startsWith("Group_")) { - return true; - } - if (["Assist", "Setup"].includes(subSection)) { - return true; - } - return false; -} -// #endregion -// #region Utility Functions ~ -// #endregion -class BladesRollMod extends BladesTargetLink { - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - if (!schemaData.name) { - throw new Error("name is required for BladesRollMod.Schema"); - } - return { - key: `${schemaData.name}-positive-roll`, - modType: RollModType.general, - section: RollModSection.roll, - posNeg: "positive", - base_status: RollModStatus.Hidden, - value: 1, - tooltip: "", - ...schemaData - }; - } - static get GMOnlyModStatuses() { - return [RollModStatus.ForcedOn, RollModStatus.ForcedOff, RollModStatus.Hidden]; - } - static getSchemaFromStrings(mStrings) { - const nameString = U.pullElement(mStrings, (v) => typeof v === "string" && /^na/i.test(v)); - const nameVal = (typeof nameString === "string" && nameString.replace(/^.*:/, "")); - if (!nameVal) { - throw new Error(`RollMod Missing Name: '${mStrings.join("@")}'`); - } - const catString = U.pullElement(mStrings, (v) => typeof v === "string" && /^cat/i.test(v)); - const catVal = (typeof catString === "string" && catString.replace(/^.*:/, "")); - if (!catVal || !(catVal in RollModSection)) { - throw new Error(`RollMod Missing Category: '${mStrings.join("@")}'`); - } - const posNegString = (U.pullElement(mStrings, (v) => typeof v === "string" && /^p/i.test(v)) || "posNeg:positive"); - const posNegVal = posNegString.replace(/^.*:/, ""); - return { - key: `${nameVal}-${posNegVal}-${catVal}`, - name: nameVal, - section: catVal, - posNeg: posNegVal, - base_status: RollModStatus.ToggledOff, - modType: RollModType.general, - tooltip: "", - value: 1, - ...Object.fromEntries(mStrings.map(getModParameterKeyVal)) - }; - function getModParameterKeyVal(mString) { - const [keyString, valString] = mString.split(/:/); - let val = /\|/.test(valString) ? valString.split(/\|/) : valString; - let key; - if (/^stat/i.test(keyString)) { - key = "base_status"; - } - else if (/^val/i.test(keyString)) { - key = "value"; - } - else if (/^eff|^ekey/i.test(keyString)) { - key = "effectKeys"; - } - else if (/^side|^ss/i.test(keyString)) { - key = "sideString"; - } - else if (/^s.*ame/i.test(keyString)) { - key = "source_name"; - } - else if (/^tool|^tip/i.test(keyString)) { - key = "tooltip"; - } - else if (/^ty/i.test(keyString)) { - key = "modType"; - } - else if (/^c.{0,10}r?.{0,3}ty/i.test(keyString)) { - key = "conditionalRollTypes"; - } - else if (/^a.{0,3}r?.{0,3}y/i.test(keyString)) { - key = "autoRollTypes"; - } - else if (/^p.{0,10}r?.{0,3}y/i.test(keyString)) { - key = "participantRollTypes"; - } - else if (/^c.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "conditionalRollTraits"; - } - else if (/^a.{0,3}r?.{0,3}tr/i.test(keyString)) { - key = "autoRollTraits"; - } - else if (/^p.{0,10}r?.{0,3}tr/i.test(keyString)) { - key = "participantRollTypes"; - } - else { - throw new Error(`Bad Roll Mod Key: ${keyString}`); - } - if (key === "base_status" && val === "Conditional") { - val = RollModStatus.Hidden; - } - let valProcessed; - if (["value"].includes(key)) { - valProcessed = U.pInt(val); - } - else if (["effectKeys", "conditionalRollTypes", "autoRollTypes", "conditionalRollTraits", "autoRollTraits"].includes(key)) { - valProcessed = [val].flat(); - } - else { - valProcessed = val.replace(/%COLON%/g, ":"); - } - return [key, valProcessed]; - } - } - static ParseDocModsToSchemaSet(doc) { - if (doc instanceof BladesChat) { - throw new Error("BladesRollMod.ParseDocRollMods cannot be called on a BladesChat document."); - } - const { roll_mods } = doc.system; - if (!roll_mods || roll_mods.length === 0) { - return []; - } - return roll_mods - .filter((elem) => Boolean(elem && typeof elem === "string")) - .map((modString) => { - return this.getSchemaFromStrings(modString.split(/@/)); - }); - } - get status() { - // USER STATUS of "ForcedOn", "ForcedOff", or "Hidden" trumps all other status values. - if (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)) { - return this.userStatus; - } - // HELD STATUS of "ToggledOff" or "ToggledOn" can be overridden by User Status - if (this.heldStatus && [RollModStatus.ToggledOff, RollModStatus.ToggledOn].includes(this.heldStatus)) { - return this.userStatus ?? this.heldStatus; - } - // Otherwise, return the first status that is set out of held, user, and base. - return this.heldStatus ?? this.userStatus ?? this.baseStatus; - } - get isActive() { return [RollModStatus.ToggledOn, RollModStatus.ForcedOn].includes(this.status); } - get isVisible() { return this.status !== RollModStatus.Hidden; } - // get flagParams() { - // return [C.SYSTEM_ID, `rollCollab.rollModsData.${this.id}`] as const;} - // async setUserStatusFlag(val: RollModStatus | undefined) { - // } - get isConditional() { - return [ - ...this.conditionalRollTraits, - ...this.autoRollTraits, - ...this.participantRollTraits, - ...this.conditionalRollTypes, - ...this.autoRollTypes, - ...this.participantRollTypes - ].length > 0; - } - get isInInactiveBlock() { - if (game.user.isGM) { - return [RollModStatus.Hidden, RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - return [RollModStatus.ForcedOff, RollModStatus.ToggledOff].includes(this.status) - && (this.isConditional || this.modType === RollModType.ability); - } - get isPush() { - return Boolean(U.lCase(this.name) === "push" - || this.effectKeys.find((eKey) => eKey === "Is-Push")); - } - get isBasicPush() { return U.lCase(this.name) === "push"; } - get stressCost() { - const costKeys = this.effectKeys.filter((key) => key.startsWith("Cost-Stress")); - if (costKeys.length === 0) { - return 0; - } - let stressCost = 0; - costKeys.forEach((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [_, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - stressCost += U.pInt(valStr); - }); - return stressCost; - } - isValidForRollType() { - switch (this.rollInstance.rollType) { - case RollType.Action: { - return true; - } - case RollType.Resistance: - case RollType.Fortune: - case RollType.IndulgeVice: { - if (this.isPush - || ["bargain", "setup", "assist", "potency"].includes(U.lCase(this.name))) { - return false; - } - return true; - } - default: return false; - } - } - /** - * Checks if any types or traits apply to the roll instance. - * @param {AnyRollType[]} types The types to check. - * @param {RollTrait[]} traits The traits to check. - * @returns {boolean} - Returns true if any types or traits apply, false otherwise. - */ - checkTypesOrTraits(types, traits) { - const rollTypes = [this.rollInstance.rollType, this.rollInstance.rollSubType, this.rollInstance.rollDowntimeAction] - .filter((rType) => Boolean(rType)); - const typesApply = (!this.rollInstance.isParticipantRoll && types.length === 0) - || rollTypes.some((rType) => types.includes(rType)); - const traitsApply = (!this.rollInstance.isParticipantRoll && traits.length === 0) - || (this.rollInstance.rollTrait && traits.includes(this.rollInstance.rollTrait)); - return Boolean(typesApply && traitsApply); - } - /** - * Sets the conditional status of the roll mod instance. - * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden. - */ - setConditionalStatus() { - // If the roll mod instance is not conditional, return false - if (!this.isConditional) { - return false; - } - // If any auto-Types apply, set status to ForcedOn and return false - if (this.autoRollTypes.includes(this.rollInstance.rollType) - || (this.rollInstance.rollSubType && this.autoRollTypes.includes(this.rollInstance.rollSubType)) - || (this.rollInstance.rollDowntimeAction && this.autoRollTypes.includes(this.rollInstance.rollDowntimeAction))) { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - // If any auto-Traits apply, set status to ForcedOn and return false - if (this.rollInstance.rollTrait && this.autoRollTraits.includes(this.rollInstance.rollTrait)) { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - // If any conditionalTypes or conditionalTraits apply, set status to ToggledOff and return false - if (this.checkTypesOrTraits(this.conditionalRollTypes, this.conditionalRollTraits)) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If this is a participant roll - // AND any participantTypes or participantTraits apply, - // ... set status to ToggledOff and return false - if (this.rollInstance.isParticipantRoll - && this.checkTypesOrTraits(this.participantRollTypes, this.participantRollTraits)) { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - // If none of the above conditions apply, set status to Hidden and return true - this.heldStatus = RollModStatus.Hidden; - return true; - } - /** - * Sets the auto-reveal/enable status of the roll mod instance. - * @returns {boolean} - Returns false if the status is ForcedOn or ToggledOff, true if the status is Hidden. - */ - setAutoStatus() { - // Check for AutoRevealOn and AutoEnableOn - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Auto")); - if (holdKeys.length === 0) { - return false; - } - for (const key of holdKeys) { - const [thisKey, thisParam] = key.split(/-/) ?? []; - if (U.lCase(thisParam) in Position && this.rollInstance.rollPositionFinal === U.lCase(thisParam)) { - if (thisKey === "AutoRevealOn") { - this.heldStatus = RollModStatus.ToggledOff; - return false; - } - else if (thisKey === "AutoEnableOn") { - this.heldStatus = RollModStatus.ForcedOn; - return false; - } - } - } - this.heldStatus = RollModStatus.Hidden; - return true; - } - /** - * Sets the relevancy status of the roll mod instance (i.e. hides irrelevant rollMods). - * @returns {boolean} - Returns true if mod is irrelevant and status is Hidden, false otherwise. - */ - setRelevancyStatus() { - const holdKeys = this.effectKeys.filter((key) => /^Negate|^Increase/.test(key)); - if (holdKeys.length === 0) { - return false; - } - const relevantKeys = holdKeys - .filter((key) => { - const [thisKey, thisParam] = key.split(/-/) ?? []; - if (thisKey === "Negate") { - const negateOperations = { - PushCost: () => this.rollInstance.isPushed(), - QualityPenalty: () => this.rollInstance.isTraitRelevant(Factor.quality) - && (this.rollInstance.rollFactors.source[Factor.quality]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.quality]?.value ?? 0), - ScalePenalty: () => this.rollInstance.isTraitRelevant(Factor.scale) - && (this.rollInstance.rollFactors.source[Factor.scale]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.scale]?.value ?? 0), - TierPenalty: () => this.rollInstance.isTraitRelevant(Factor.tier) - && (this.rollInstance.rollFactors.source[Factor.tier]?.value ?? 0) - < (this.rollInstance.rollFactors.opposition[Factor.tier]?.value ?? 0) - }; - if (Object.hasOwn(negateOperations, thisParam)) { - return negateOperations[thisParam](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${thisParam}`); - } - } - else if (thisKey === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(thisParam) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${thisKey}`); - } - }); - if (relevantKeys.length === 0) { - this.heldStatus = RollModStatus.Hidden; - return true; - } - return false; - } - /** - * Sets the payable status of the roll mod instance (i.e. forces off rollMods the primary can't pay for). - * @returns {boolean} - Returns true if mod is unpayable and status is ForcedOff, false otherwise. - */ - setPayableStatus() { - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return false; - } - const payableKeys = holdKeys - .filter((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - const { rollPrimaryDoc } = this.rollInstance.rollPrimary ?? {}; - if (!BladesRollPrimary.IsDoc(rollPrimaryDoc)) { - return false; - } - switch (traitStr) { - case "SpecialArmor": { - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.armor.active.special - && !rollPrimaryDoc.system.armor.checked.special; - } - case "Stress": { - const val = U.pInt(valStr); - return BladesActor.IsType(rollPrimaryDoc, BladesActorType.pc) - && rollPrimaryDoc.system.stress.max - rollPrimaryDoc.system.stress.value >= val; - } - case "Heat": { - return (BladesPC.IsType(rollPrimaryDoc) && BladesCrew.IsType(rollPrimaryDoc.crew)) - || BladesCrew.IsType(rollPrimaryDoc); - } - default: throw new Error(`Unrecognize Payable Key: ${traitStr}`); - } - }); - if (payableKeys.length === 0) { - this.heldStatus = RollModStatus.ForcedOff; - return true; - } - return false; - } - applyRollModEffectKeys() { - if (!this.isActive) { - return; - } - const holdKeyParams = this.effectKeys - .filter((key) => /^Negate|^Increase/.test(key)) - .map((key) => key.split(/-/)); - if (holdKeyParams.length === 0) { - return; - } - holdKeyParams.forEach(([key, param]) => { - if (key === "Negate") { - const negateOperations = { - PushCost: () => { - this.rollInstance.negatePushCost(); - }, - QualityPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.quality); - }, - ScalePenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.scale); - }, - TierPenalty: () => { - this.rollInstance.negateFactorPenalty(Factor.tier); - } - }; - if (Object.hasOwn(negateOperations, param)) { - return negateOperations[param](); - } - else { - throw new Error(`Unrecognized Negate parameter: ${param}`); - } - } - else if (key === "Increase") { - const [_, traitStr] = /(\w+)\d+/.exec(param) ?? []; - return this.rollInstance.isTraitRelevant(traitStr); - } - else { - throw new Error(`Unrecognized Function Key: ${key} (key: ${key})`); - } - }); - } - get selectOptions() { - if (this.modType !== RollModType.teamwork) { - return null; - } - if (this.name === "Assist" || this.name === "Setup") { - return this.rollInstance.rollParticipantSelectOptions[this.name]; - } - else if (this.name.startsWith("Group_")) { - return this.rollInstance.rollParticipantSelectOptions.Group; - } - return null; - } - get selectedParticipant() { - if (this.modType !== RollModType.teamwork) { - return null; - } - return this.rollInstance.getRollParticipant(this.section, this.name); - } - get allFlagData() { - return this.rollInstance.data; - } - get costs() { - if (!this.isActive) { - return undefined; - } - const holdKeys = this.effectKeys.filter((key) => key.startsWith("Cost")); - if (holdKeys.length === 0) { - return undefined; - } - return holdKeys.map((key) => { - const [thisParam] = (key.split(/-/) ?? []).slice(1); - const [traitStr, valStr] = (/([A-Za-z]+)(\d*)/.exec(thisParam) ?? []).slice(1); - let label = this.name; - if (this.isBasicPush) { - if (this.posNeg === "negative") { - label = `${this.name} (To Act)`; - } - else { - const effect = this.section === RollModSection.roll ? "+1d" : "+1 effect"; - label = `${this.name} (${effect})`; - } - } - return { - id: this.id, - label, - costType: traitStr, - costAmount: valStr ? U.pInt(valStr) : 1 - }; - }); - } - _rollInstance; - constructor(modData, rollInstance) { - super(modData); - this._rollInstance = rollInstance; - } - get rollInstance() { return this._rollInstance; } - get name() { return this.data.name; } - get modType() { return this.data.modType; } - get sourceName() { return this.data.source_name ?? this.data.name; } - get section() { return this.data.section; } - get posNeg() { return this.data.posNeg; } - get userStatus() { return this.data.user_status; } - set userStatus(val) { - if (val === this.userStatus) { - return; - } - if (!val || val === this.baseStatus) { - this.updateTarget("user_status", null) - .then(this.rollInstance.renderRollCollab_SocketCall.bind(this.rollInstance)); - } - else { - if (!game.user.isGM - && (BladesRollMod.GMOnlyModStatuses.includes(val) - || (this.userStatus && BladesRollMod.GMOnlyModStatuses.includes(this.userStatus)))) { - return; - } - this.updateTarget("user_status", val) - .then(this.rollInstance.renderRollCollab_SocketCall.bind(this.rollInstance)); - } - } - get baseStatus() { return this.data.base_status; } - get heldStatus() { return this.data.held_status; } - set heldStatus(val) { - if (val === this.heldStatus) { - return; - } - if (!val) { - this.updateTarget("held_status", null) - .then(this.rollInstance.renderRollCollab_SocketCall.bind(this.rollInstance)); - } - else { - this.updateTarget("held_status", val) - .then(this.rollInstance.renderRollCollab_SocketCall.bind(this.rollInstance)); - } - } - get value() { return this.data.value; } - get effectKeys() { return this.data.effectKeys ?? []; } - get sideString() { - if (this.data.sideString) { - return this.data.sideString; - } - if (this.selectedParticipant) { - return this.selectedParticipant.rollParticipantName; - } - return undefined; - } - get tooltip() { - let parsedTooltip = this.data.tooltip.replace(/%COLON%/g, ":"); - if (parsedTooltip.includes("%DOC_NAME%")) { - parsedTooltip = parsedTooltip.replace(/%DOC_NAME%/g, this.selectedParticipant - ? this.selectedParticipant.rollParticipantName - : "an Ally"); - } - if (parsedTooltip.includes("@OPPOSITION_NAME@")) { - parsedTooltip = parsedTooltip.replace(/@OPPOSITION_NAME@/g, this.rollInstance.rollOpposition - ? this.rollInstance.rollOpposition.rollOppName - : "Your Opposition"); - } - return parsedTooltip; - } - get conditionalRollTypes() { - return this.data.conditionalRollTypes ?? []; - } - get autoRollTypes() { - return this.data.autoRollTypes ?? []; - } - get participantRollTypes() { - return this.data.participantRollTypes ?? []; - } - get conditionalRollTraits() { - return this.data.conditionalRollTraits ?? []; - } - get autoRollTraits() { - return this.data.autoRollTraits ?? []; - } - get participantRollTraits() { - return this.data.participantRollTraits ?? []; - } -} -class BladesRollPrimary { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollPrimary.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollPrimaryName === "string" - && typeof data.rollPrimaryType === "string" - && typeof data.rollPrimaryImg === "string" - && Array.isArray(data.rollModsData) - && U.isList(data.rollFactors) - && (!data.rollPrimaryID || typeof data.rollPrimaryID === "string"); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollPrimary.IsDoc(doc)) { - return doc; - } - throw new Error(`[BladesRollPrimary.GetDoc] Unable to resolve document reference. Provided reference: ${JSON.stringify(docRef)}`); - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - static #buildData(config) { - if (BladesRollPrimary.IsValidData(config.rollPrimaryData)) { - return config.rollPrimaryData; - } - let rollPrimary; - const rollUser = game.users.get(config.rollUserID ?? game.user.id); - if ("target" in config && BladesRollPrimary.IsDoc(config.target)) { - rollPrimary = config.target; - } - else if (BladesRollPrimary.IsDoc(rollUser?.character)) { - rollPrimary = rollUser.character; - } - else { - throw new Error("[BladesRollPrimary.BuildData()] A valid source of PrimaryData must be provided to construct a roll."); - } - return { - rollPrimaryID: rollPrimary.rollPrimaryID, - rollPrimaryName: rollPrimary.rollPrimaryName, - rollPrimaryType: rollPrimary.rollPrimaryType, - rollPrimaryImg: rollPrimary.rollPrimaryImg, - rollPrimaryModsSchemaSet: rollPrimary.rollPrimaryModsSchemaSet, - rollFactors: rollPrimary.rollFactors - }; - } - static Build(config) { - return new BladesRollPrimary(this.#buildData(config)); - } - // #endregion - rollInstance; - rollPrimaryID; - _rollPrimaryDoc; - get rollPrimaryDoc() { - return (this._rollPrimaryDoc ??= BladesRollPrimary.GetDoc(this.rollPrimaryID)); - } - get rollPrimaryName() { return this.rollPrimaryDoc.rollPrimaryName; } - get rollPrimaryType() { return this.rollPrimaryDoc.rollPrimaryType; } - get rollPrimaryImg() { return this.rollPrimaryDoc.rollPrimaryImg; } - get rollPrimaryModsSchemaSet() { return this.rollPrimaryDoc.rollPrimaryModsSchemaSet; } - get rollFactors() { return this.rollPrimaryDoc.rollFactors; } - get isWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.getFlag("eunos-blades", "isWorsePosition") === true; - } - return false; - } - async applyHarm(amount, name) { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyHarm(amount, name); - } - } - async applyWorsePosition() { - if (this.rollPrimaryDoc) { - return this.rollPrimaryDoc.applyWorsePosition(); - } - } - get hasArmor() { - if (!this.rollPrimaryDoc) { - return false; - } - if (this.rollPrimaryType === BladesActorType.pc) { - const rollPrimaryDoc = this.rollPrimaryDoc; - // Can PC spend normal armor? - if (!rollPrimaryDoc.system.armor.checked.light - && (rollPrimaryDoc.system.armor.active.light - || rollPrimaryDoc.remainingLoad >= 2)) { - return true; - } - // Otherwise, can PC spend heavy armor? - if (!rollPrimaryDoc.system.armor.checked.heavy - && (rollPrimaryDoc.system.armor.active.heavy - || rollPrimaryDoc.remainingLoad >= 3)) { - return true; - } - } - if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - const { value, max } = this.rollPrimaryDoc.system.armor; - return max - value > 1; - } - return false; - } - get hasSpecialArmor() { - if (!this.rollPrimaryDoc) { - return false; - } - if (!BladesPC.IsType(this.rollPrimaryDoc)) { - return false; - } - if (!this.rollPrimaryDoc.system.armor.active.special) { - return false; - } - if (this.rollPrimaryDoc.system.armor.checked.special) { - return false; - } - return true; - } - async spendArmor(count) { - if (this.hasArmor) { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - const updateData = { - "system.armor.checked.heavy": this.rollPrimaryDoc.system.armor.checked.heavy, - "system.armor.checked.light": this.rollPrimaryDoc.system.armor.checked.light - }; - while (count > 0) { - if (updateData["system.armor.checked.light"]) { - if (updateData["system.armor.checked.heavy"]) { - throw new Error(`[BladesRollPrimary.spendArmor()] Cannot spend more armor (${count}) than PC has.`); - } - updateData["system.armor.checked.heavy"] = true; - } - else { - updateData["system.armor.checked.light"] = true; - } - count--; - } - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - await this.rollPrimaryDoc.update({ "system.armor.value": this.rollPrimaryDoc.system.armor.value + count }); - } - } - } - constructor(...args) { - let primaryDoc = false; - if (args[0] instanceof BladesRoll) { - this.rollInstance = args[0]; - args.shift(); - } - if (BladesRollPrimary.IsDoc(args[0])) { - primaryDoc = args[0]; - } - else if (U.isList(args[0])) { - if ("rollPrimaryID" in args[0]) { - primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryID); - } - else if ("rollPrimaryName" in args[0]) { - primaryDoc = BladesRollPrimary.GetDoc(args[0].rollPrimaryName); - } - } - else if (this.rollInstance) { - primaryDoc = this.rollInstance.rollPrimary.rollPrimaryDoc ?? false; - } - if (!primaryDoc) { - throw new Error(`[BladesRollPrimary.constructor] Failed to resolve primary document or data from provided arguments: ${JSON.stringify(args)}`); - } - this.rollPrimaryID = primaryDoc.rollPrimaryID; - this._rollPrimaryDoc = primaryDoc; - } -} -class BladesRollOpposition { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollOpposition.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollOppName === "string" - && typeof data.rollOppType === "string" - && typeof data.rollOppImg === "string" - && (!data.rollOppSubName || typeof data.rollOppSubName === "string") - && (!data.rollOppModsSchemaSet || Array.isArray(data.rollOppModsSchemaSet)) - && U.isList(data.rollFactors) - && (!data.rollOppID || typeof data.rollOppID === "string"); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollOpposition.IsDoc(doc)) { - return doc; - } - throw new Error(`[BladesRollOpposition.GetDoc] Unable to resolve document reference. Provided reference: ${JSON.stringify(docRef)}`); - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.npc, BladesActorType.faction) || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang); - } - // #endregion - rollInstance; - rollOppID; - _rollOppDoc; - get rollOppDoc() { - return (this._rollOppDoc ??= BladesRollOpposition.GetDoc(this.rollOppID)); - } - get rollOppName() { return this.rollOppDoc.rollOppName; } - get rollOppSubName() { return this.rollOppDoc.rollOppSubName; } - get rollOppType() { return this.rollOppDoc.rollOppType; } - get rollOppImg() { return this.rollOppDoc.rollOppImg; } - get rollOppModsSchemaSet() { return this.rollOppDoc.rollOppModsSchemaSet; } - get rollFactors() { return this.rollOppDoc.rollFactors; } - constructor(...args) { - let oppDoc = false; - if (args[0] instanceof BladesRoll) { - this.rollInstance = args[0]; - args.shift(); - } - else { - throw new Error(`[BladesRollOpp.constructor] First argument is not an instance of BladesRoll. Received arguments: ${JSON.stringify(args)}`); - } - if (BladesRollOpposition.IsDoc(args[0])) { - oppDoc = args[0]; - } - else if (U.isList(args[0])) { - if ("rollOppID" in args[0]) { - oppDoc = BladesRollOpposition.GetDoc(args[0].rollOppID); - } - else if ("rollOppName" in args[0]) { - oppDoc = BladesRollOpposition.GetDoc(args[0].rollOppName); - } - } - else if (this.rollInstance) { - oppDoc = this.rollInstance.rollOpposition?.rollOppDoc ?? false; - } - if (!oppDoc) { - throw new Error(`[BladesRollOpp.constructor] Failed to resolve Opp document or data from provided arguments: ${JSON.stringify(args)}`); - } - this.rollOppID = oppDoc.rollOppID; - this._rollOppDoc = oppDoc; - } - // #endregion - async updateRollFlags() { - if (!this.rollInstance) { - return; - } - await this.rollInstance.updateTarget("rollOppData", this); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.rollInstance.id); - } -} -class BladesRollParticipant { - // #region Static Methods ~ - static IsValidData(data) { - if (BladesRollParticipant.IsDoc(data)) { - return true; - } - return U.isList(data) - && typeof data.rollParticipantName === "string" - && typeof data.rollParticipantType === "string" - && typeof data.rollParticipantIcon === "string" - && (!data.rollParticipantModsSchemaSet || Array.isArray(data.rollParticipantModsSchemaSet)) - && U.isList(data.rollFactors) - && (!data.rollParticipantID || typeof data.rollParticipantID === "string") - && (!data.rollParticipantDoc || BladesRollParticipant.IsDoc(data.rollParticipantDoc)); - } - static GetDoc(docRef) { - let doc = docRef; - if (typeof docRef === "string") { - doc = game.actors.get(docRef) - ?? game.items.get(docRef) - ?? game.actors.getName(docRef) - ?? game.items.getName(docRef); - } - if (BladesRollParticipant.IsDoc(doc)) { - return doc; - } - throw new Error(`[BladesRollParticipant.GetDoc] Unable to resolve document reference. Provided reference: ${JSON.stringify(docRef)}`); - } - static IsDoc(doc) { - return BladesActor.IsType(doc, BladesActorType.pc, BladesActorType.crew, BladesActorType.npc) - || BladesItem.IsType(doc, BladesItemType.cohort_expert, BladesItemType.cohort_gang, BladesItemType.gm_tracker); - } - // #endregion - rollInstance; - rollParticipantID; - rollParticipantSection; - rollParticipantSubSection; - _rollParticipantDoc; - get rollParticipantDoc() { - return (this._rollParticipantDoc ??= BladesRollParticipant.GetDoc(this.rollParticipantID)); - } - get rollParticipantName() { return this.rollParticipantDoc.rollParticipantName; } - get rollParticipantType() { return this.rollParticipantDoc.rollParticipantType; } - get rollParticipantIcon() { return this.rollParticipantDoc.rollParticipantIcon; } - get rollParticipantModsSchemaSet() { return this.rollParticipantDoc.rollParticipantModsSchemaSet; } - get rollFactors() { return this.rollParticipantDoc.rollFactors; } - get data() { - return { - rollParticipantID: this.rollParticipantID, - rollParticipantName: this.rollParticipantName, - rollParticipantType: this.rollParticipantType, - rollParticipantIcon: this.rollParticipantIcon, - rollParticipantModsSchemaSet: this.rollParticipantModsSchemaSet, - rollFactors: this.rollFactors - }; - } - constructor(rollInstance, section, subSection, rollParticipantDataOrDoc) { - this.rollInstance = rollInstance; - this.rollParticipantSection = section; - this.rollParticipantSubSection = subSection; - let participantDoc = false; - if (BladesRollParticipant.IsDoc(rollParticipantDataOrDoc)) { - participantDoc = rollParticipantDataOrDoc; - } - else if (U.isList(rollParticipantDataOrDoc)) { - if ("rollParticipantID" in rollParticipantDataOrDoc) { - participantDoc = BladesRollParticipant.GetDoc(rollParticipantDataOrDoc.rollParticipantID); - } - else if ("rollParticipantName" in rollParticipantDataOrDoc) { - participantDoc = BladesRollParticipant.GetDoc(rollParticipantDataOrDoc.rollParticipantName); - } - } - else if (this.rollInstance - && this.rollInstance.rollParticipants - && section in this.rollInstance.rollParticipants - && this.rollInstance.rollParticipants[section] - && subSection in (this.rollInstance.rollParticipants[section] ?? {})) { - const participants = this.rollInstance.rollParticipants[section]; - participantDoc = participants[subSection].rollParticipantDoc ?? false; - } - if (!participantDoc) { - throw new Error(`[BladesRollParticipant.constructor] Failed to resolve Participant document or data from provided arguments: ${JSON.stringify({ - rollInstance, section, subSection, rollParticipantDataOrDoc - })}`); - } - this.rollParticipantID = participantDoc.rollParticipantID; - this._rollParticipantDoc = participantDoc; - } - // #endregion - async updateRollFlags() { - await this.rollInstance.updateTarget(`rollParticipantData.${this.rollParticipantSection}.${this.rollParticipantSubSection}`, this); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.rollInstance.id); - } -} -class BladesRoll extends BladesTargetLink { - static Debug = { - modWatch: false, - watchRollMod(name) { - if (typeof name === "string") { - BladesRoll.Debug.modWatch = new RegExp(name, "g"); - } - else { - BladesRoll.Debug.modWatch = false; - } - } - }; - // #region STATIC METHODS: INITIALIZATION & DEFAULTS ~ - static Initialize() { - return loadTemplates([ - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-number-line.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-select-doc.hbs", - "systems/eunos-blades/templates/roll/partials/roll-collab-gm-factor-control.hbs", - "systems/eunos-blades/templates/roll/roll-collab-action.hbs", - "systems/eunos-blades/templates/roll/roll-collab-action-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-resistance.hbs", - "systems/eunos-blades/templates/roll/roll-collab-resistance-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-fortune.hbs", - "systems/eunos-blades/templates/roll/roll-collab-fortune-gm.hbs", - "systems/eunos-blades/templates/roll/roll-collab-indulgevice.hbs", - "systems/eunos-blades/templates/roll/roll-collab-indulgevice-gm.hbs" - ]); - } - static InitSockets() { - socketlib.system.register("constructRollCollab_SocketCall", BladesRoll.constructRollCollab_SocketResponse.bind(BladesRoll)); - socketlib.system.register("renderRollCollab_SocketCall", BladesRoll.renderRollCollab_SocketResponse.bind(BladesRoll)); - socketlib.system.register("closeRollCollab_SocketCall", BladesRoll.closeRollCollab_SocketResponse.bind(BladesRoll)); - } - static ParseConfigToData(data, parentRoll) { - if (data.rollPrimaryData instanceof BladesRollPrimary) { - data.rollPrimaryData = data.rollPrimaryData.data; - } - if (data.rollOppData instanceof BladesRollOpposition) { - data.rollOppData = data.rollOppData.data; - } - if (data.rollParticipantData) { - if (data.rollParticipantData[RollModSection.roll]) { - Object.keys(data.rollParticipantData[RollModSection.roll]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.roll]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - data.rollParticipantData[RollModSection.roll][key] = thisParticipant.data; - } - }); - } - if (data.rollParticipantData[RollModSection.position]) { - Object.keys(data.rollParticipantData[RollModSection.position]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.position]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - data.rollParticipantData[RollModSection.position][key] = thisParticipant.data; - } - }); - } - if (data.rollParticipantData[RollModSection.effect]) { - Object.keys(data.rollParticipantData[RollModSection.effect]).forEach((key) => { - const thisParticipant = data.rollParticipantData?.[RollModSection.effect]?.[key]; - if (thisParticipant instanceof BladesRollParticipant) { - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - data.rollParticipantData[RollModSection.effect][key] = thisParticipant.data; - } - }); - } - } - data.rollModsData = this.GetRollModsDataSet(parentRoll, Object.values(data.rollModsData ?? {})); - return BladesTargetLink.ParseConfigToData(data); - } - static ApplySchemaDefaults(schemaData) { - // Ensure all properties of Schema are provided - if (!schemaData.rollType) { - throw new Error("Must include a rollType when constructing a BladesRoll object."); - } - schemaData.rollPhase ??= RollPhase.Collaboration; - schemaData.GMBoosts = { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0, - ...schemaData.GMBoosts ?? {} - }; - schemaData.GMOppBoosts = { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0, - ...schemaData.GMOppBoosts ?? {} - }; - schemaData.GMOverrides ??= {}; - schemaData.userPermissions ??= {}; - if (schemaData.rollPrimaryData instanceof BladesRollPrimary) { - schemaData.rollPrimaryData = schemaData.rollPrimaryData.data; - } - if (schemaData.rollOppData instanceof BladesRollOpposition) { - schemaData.rollOppData = schemaData.rollOppData.data; - } - return schemaData; - } - // static override get defaultOptions() { - // return foundry.utils.mergeObject(super.defaultOptions, { - // classes: ["eunos-blades", "sheet", "roll-collab", game.user.isGM ? "gm-roll-collab" : ""], - // template: `systems/eunos-blades/templates/roll/roll-collab${game.user.isGM ? "-gm" : ""}.hbs`, - // submitOnChange: true, - // width: 500, - // dragDrop: [ - // {dragSelector: null, dropSelector: "[data-action='gm-drop-opposition'"} - // ] - // // Height: 500 - // }); - // } - static get DefaultRollModSchemaSet() { - /* Subclass overrides determine default roll mods. */ - return []; - } - static GetRollModsDataSet(rollInst, rollModsSchemaSet) { - const { linkData } = rollInst; - const modLinkConfig = { - targetID: linkData.targetID, - targetKey: "targetKey" in linkData - ? "rollModsData" - : undefined, - targetFlagKey: "targetFlagKey" in linkData - ? "rollModsData" - : undefined, - isScopingById: true - }; - const compiledModSchemaSets = [...rollModsSchemaSet]; - // Add roll mods on rollPrimary - if (rollInst.rollPrimary) { - compiledModSchemaSets.push(...rollInst.rollPrimary.rollPrimaryModsSchemaSet - .filter((pSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== pSchema.key))); - } - // Add roll mods on rollOpposition - if (rollInst.rollOpposition?.rollOppModsSchemaSet) { - compiledModSchemaSets.push(...rollInst.rollOpposition.rollOppModsSchemaSet - .filter((oSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== oSchema.key))); - } - // Add default roll mods - compiledModSchemaSets.push(...this.DefaultRollModSchemaSet - .filter((dSchema) => compiledModSchemaSets.every((mSchema) => mSchema.key !== dSchema.key))); - return Object.fromEntries(compiledModSchemaSets - .map((modSchema) => { - const modData = BladesTargetLink.ParseConfigToData({ - ...BladesRollMod.ApplySchemaDefaults(modSchema), - ...modLinkConfig - }); - return [modData.id, modData]; - })); - } - static GetDieClass(rollType, rollResult, dieVal, dieIndex) { - switch (rollType) { - case RollType.Resistance: { - if (dieVal === 6 && dieIndex <= 1 && rollResult === -1) { - return "blades-die-critical"; - } - if (dieIndex === 0) { - return "blades-die-resistance"; - } - return "blades-die-fail"; - } - case RollType.IndulgeVice: { - if (dieIndex === 0) { - return "blades-die-indulge-vice"; - } - return "blades-die-fail"; - } - default: break; - } - if (dieVal === 6 && dieIndex <= 1 && rollResult === RollResult.critical) { - dieVal++; - } - return [ - "", - "blades-die-fail", - "blades-die-fail", - "blades-die-fail", - "blades-die-partial", - "blades-die-partial", - "blades-die-success", - "blades-die-critical" - ][dieVal]; - } - static GetDieImage(rollType, rollResult, dieVal, dieIndex, isGhost = false, isCritical = false) { - let imgPath = "systems/eunos-blades/assets/dice/image/"; - if (isGhost) { - imgPath += "ghost-"; - } - else if ([RollType.Resistance, RollType.IndulgeVice].includes(rollType)) { - imgPath += "grad-"; - } - imgPath += dieVal; - if (!isGhost && dieVal === 6 && dieIndex <= 1 && isCritical) { - imgPath += "-crit"; - } - imgPath += ".webp"; - return imgPath; - } - static get Active() { - return U.getLast(game.eunoblades.Rolls.filter((roll) => roll.isActive)); - } - // #endregion - // #region STATIC METHODS: New Roll Creation ~ - // static Current: Record = {}; - // static _Active?: BladesRoll; - // static get Active(): BladesRoll | undefined { - // if (BladesRoll._Active) {return BladesRoll._Active;} - // if (U.objSize(BladesRoll.Current) > 0) {return U.getLast(Object.values(BladesRoll.Current));} - // return undefined; - // } - // static set Active(val: BladesRoll | undefined) { - // BladesRoll._Active = val; - // } - static GetUserPermissions(config) { - if (!config.rollPrimaryData) { - throw new Error("[BladesRoll.GetUserPermissions()] Missing rollPrimaryData."); - } - // === ONE === GET USER IDS - // Get user ID of GM - const GMUserID = game.users.find((user) => user.isGM)?.id; - if (!GMUserID) { - throw new Error("[BladesRoll.GetUserPermissions()] No GM found!"); - } - // Get user IDs of players - const playerUserIDs = game.users - .filter((user) => BladesPC.IsType(user.character) && !user.isGM && typeof user.id === "string") - .map((user) => user.id); - // Prepare user ID permissions object - const userIDs = { - [RollPermissions.GM]: [GMUserID], - [RollPermissions.Primary]: [], - [RollPermissions.Participant]: [], - [RollPermissions.Observer]: [] - }; - // === TWO === DETERMINE PRIMARY USER(S) - // Check RollPrimaryDoc to determine how to assign primary users - const { rollPrimaryDoc } = config.rollPrimaryData; - if (BladesPC.IsType(rollPrimaryDoc) - && U.pullElement(playerUserIDs, rollPrimaryDoc.primaryUser?.id)) { - userIDs[RollPermissions.Primary].push(rollPrimaryDoc.primaryUser?.id); - } - else if (BladesCrew.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else if (BladesItem.IsType(rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - if (config.rollUserID === GMUserID) { - userIDs[RollPermissions.Primary].push(...playerUserIDs); - } - else if (BladesPC.IsType(rollPrimaryDoc.parent) - && rollPrimaryDoc.parent.primaryUser?.id) { - userIDs[RollPermissions.Primary].push(rollPrimaryDoc.parent.primaryUser.id); - } - } - else if (BladesGMTracker.IsType(rollPrimaryDoc)) { - userIDs[RollPermissions.Primary].push(GMUserID); - } - // === THREE === DETERMINE ROLL PARTICIPANT USER(S) - // Check config.rollParticipantData to determine if roll starts with any participants - if (config.rollParticipantData) { - userIDs[RollPermissions.Participant].push(...getParticipantDocUserIDs(config.rollParticipantData, playerUserIDs)); - } - // === FOUR === ASSIGN ROLL OBSERVERS - // Add remaining players as observers. - userIDs[RollPermissions.Observer] = playerUserIDs - .filter((uID) => !userIDs[RollPermissions.Participant].includes(uID)); - // === FIVE === PARSE INTO {ID: PERMISSION} FORMAT - const userFlagData = {}; - Object.entries(userIDs) - .forEach(([rollPermission, idsArray]) => { - for (const id of idsArray) { - userFlagData[id] = rollPermission; - } - }); - return userFlagData; - /** - * Generates BladesRollParticipant documents from the provided schema data. - * @param {BladesRoll.RollParticipantDataSet} participantData - */ - function getParticipantDocs(participantData) { - return Object.values(flattenObject(participantData)) - .map((pData) => { - if (BladesRollParticipant.IsDoc(pData)) { - return pData; - } - if (BladesRollParticipant.IsValidData(pData)) { - if (BladesRollParticipant.IsDoc(pData.rollParticipantDoc)) { - return pData.rollParticipantDoc; - } - else if (typeof pData.rollParticipantID === "string") { - const pDoc = game.actors.get(pData.rollParticipantID) ?? game.items.get(pData.rollParticipantID); - if (BladesRollParticipant.IsDoc(pDoc)) { - return pDoc; - } - } - } - return null; - }); - } - /** - * Returns the user ids of potential BladesRollParticipants defined in the provided data schema. - * @param {BladesRoll.RollParticipantDataSet} participantData - * @param {IDString[]} unassignedIDs - */ - function getParticipantDocUserIDs(participantData, unassignedIDs) { - return getParticipantDocs(participantData) - .map((pDoc) => { - if (BladesPC.IsType(pDoc) && typeof pDoc.primaryUser?.id === "string") { - return pDoc.primaryUser.id; - } - else if (BladesCrew.IsType(pDoc) - || BladesItem.IsType(pDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return unassignedIDs; - } - return null; - }) - .flat() - .filter((pUser) => pUser !== null && !userIDs[RollPermissions.Primary].includes(pUser)); - } - } - static BuildLinkConfig(config) { - // Prepare partial target link config - const partialLinkConfig = { - target: "target" in config ? config.target : undefined, - targetID: "targetID" in config ? config.targetID : undefined, - targetKey: "targetKey" in config ? config.targetKey : undefined, - targetFlagKey: "targetFlagKey" in config ? config.targetFlagKey : undefined - }; - // If neither target nor targetID are provided, set target to rollUser or currentUser - if (!partialLinkConfig.target && !partialLinkConfig.targetID) { - const rollUser = game.users.get(config.rollUserID ?? game.user.id); - if (!rollUser) { - throw new Error("[BladesRoll.NewRoll()] You must provide a valid rollUserID, target, or targetID in the config object."); - } - partialLinkConfig.target = rollUser; - } - // If neither targetKey nor targetFlagKey are provided, set targetFlagKey to 'rollCollab'. - if (!partialLinkConfig.targetKey && !partialLinkConfig.targetFlagKey) { - partialLinkConfig.targetFlagKey = "rollCollab"; - } - // Build target link config - return BladesTargetLink.BuildLinkConfig(partialLinkConfig); - } - /** - * This static method accepts a partial version of the config options required - * to build a BladesRoll instance, sets the requisite flags on the storage - * document, then sends out a socket call to the relevant users to construct - * and display the roll instance. - * - * @param {BladesRoll.Config} config The configuration object for the new roll. - */ - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - // Prepare roll user flag data - config.userPermissions = this.GetUserPermissions(config); - // Ensure rollType is defined - if (!config.rollType) { - throw new Error("rollType must be defined in config"); - } - // Log the roll data - eLog.checkLog3("bladesRoll", "BladesRoll.NewRoll()", { config }); - // Construct and initialize the BladesRoll/BladesTargetLink instance - const rollInst = await BladesRoll.Create({ ...config, ...linkConfig }); - // Send out socket calls to all users to see the roll. - rollInst.constructRollCollab_SocketCall(rollInst.linkData); - return rollInst; - } - // #endregion - // #region SOCKET CALLS & RESPONSES ~ - constructRollCollab_SocketCall(linkData) { - socketlib.system.executeForEveryone("constructRollCollab_SocketCall", linkData); - } - static constructRollCollab_SocketResponse(linkData) { - const rollInst = new BladesRoll(linkData); - eLog.checkLog3("rollCollab", "constructRollCollab_SocketResponse()", { params: { linkData }, rollInst }); - this.renderRollCollab_SocketResponse(rollInst.id); - } - _elem$; - get elem$() { - if (this._elem$) { - return this._elem$; - } - this._elem$ = $(`#${this.id}`) ?? $(`
`).appendTo("body"); - return this._elem$; - } - async renderRollCollab() { - this.prepareRollParticipantData(); - const html = await renderTemplate("systems/eunoblades/templates/rolls/roll-collab.hbs", this.context); - this.elem$.html(html); - this.activateListeners(); - } - renderRollCollab_SocketCall() { - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - static renderRollCollab_SocketResponse(id) { - const rollInst = game.eunoblades.Rolls.get(id); - if (!rollInst) { - throw new Error(`[BladesRoll.renderRollCollab_SocketResponse] No roll found with id ${id}.`); - } - rollInst.renderRollCollab(); - } - closeRollCollab_Animation() { - return U.gsap.effects.blurRemove(this.elem$, { ignoreMargins: true }); - } - async closeRollCollab_SocketCall() { - if (!game.user.isGM) { - return; - } - socketlib.system.executeForOthers("closeRollCollab_SocketCall", this.id); - await U.waitFor(this.closeRollCollab_Animation()); - } - static closeRollCollab_SocketResponse(id) { - game.eunoblades.Rolls.get(id)?.closeRollCollab_Animation(); - } - // #endregion - // #region *** CONSTRUCTOR *** ~ - rollPermission; - _rollPrimary; - _rollOpposition; - _rollParticipants; - projectSelectOptions; - constructor(dataOrConfig) { - super(dataOrConfig); - this.rollPermission = this.data.userPermissions[game.user.id]; - this._rollPrimary = new BladesRollPrimary(this, this.data.rollPrimaryData); - if (this.data.rollOppData) { - this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData); - } - else if (this.data.rollDowntimeAction === DowntimeAction.LongTermProject) { - this.projectSelectOptions = Array.from(game.items) - .filter((item) => BladesItem.IsType(item, BladesItemType.project)) - .map((project) => ({ value: project.id ?? "", display: project.name })); - } - if (this.data.rollParticipantData) { - this._rollParticipants = {}; - for (const [rollSection, rollParticipantList] of Object.entries(this.data.rollParticipantData)) { - if ([RollModSection.roll, RollModSection.position, RollModSection.effect] - .includes(rollSection) && !U.isEmpty(rollParticipantList)) { - const sectionParticipants = {}; - for (const [participantType, participantData] of Object.entries(rollParticipantList)) { - sectionParticipants[participantType] = new BladesRollParticipant(this, participantData); - } - this._rollParticipants[rollSection] = sectionParticipants; - } - } - } - game.eunoblades.Rolls.set(this.id, this); - } - // #endregion - // #region Roll Participation & User Permissions - async addRollParticipant(participantRef, rollSection, rollSubSection) { - if (!rollSubSection) { - /* Insert logic to determine from rollSection and number of existing Group_X members */ - rollSubSection = "Assist"; - } - const participantData = typeof participantRef === "string" - ? game.actors.get(participantRef) - ?? game.actors.getName(participantRef) - ?? game.items.get(participantRef) - ?? game.items.getName(participantRef) - : participantRef; - if (!BladesRollParticipant.IsValidData(participantData)) { - throw new Error("Bad data."); - } - const rollParticipant = new BladesRollParticipant(this, { - rollParticipantSection: rollSection, - rollParticipantSubSection: rollSubSection, - rollParticipantID: participantData.rollParticipantID - }); - await rollParticipant.updateRollFlags(); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async removeRollParticipant(rollSection, rollSubSection) { - await this.updateTarget(`rollParticipantData.${rollSection}.${rollSubSection}`, null); - } - async updateUserPermission(_user, _permission) { - /* Force-render roll with new permissions */ - } - // #endregion - // #region Basic User Flag Getters/Setters ~ - // get data(): BladesRoll.FlagData { - // if (!this.document.getFlag(C.SYSTEM_ID, "rollCollab")) { - // throw new Error("[get flags()] No RollCollab Flags Found on User Document"); - // } - // return this.document.getFlag(C.SYSTEM_ID, "rollCollab") as BladesRoll.FlagData; - // } - get rollPrimary() { - return this._rollPrimary; - } - get rollPrimaryDoc() { - if (BladesRollPrimary.IsDoc(this.rollPrimaryDoc)) { - return this.rollPrimaryDoc; - } - if (BladesRollPrimary.IsDoc(this.rollPrimary)) { - return this.rollPrimary; - } - return undefined; - } - get rollOpposition() { - if (!this._rollOpposition && BladesRollOpposition.IsValidData(this.data.rollOppData)) { - this._rollOpposition = new BladesRollOpposition(this, this.data.rollOppData); - } - return this._rollOpposition; - } - set rollOpposition(val) { - if (val === undefined) { - this._rollOpposition = undefined; - } - else { - this._rollOpposition = val; - val.updateRollFlags(); - } - } - get rollOppClockKey() { - return this.rollOpposition?.rollOppClockKey; - } - get rollClockKey() { - return this.data.rollClockKeyID - ? game.eunoblades.ClockKeys.get(this.data.rollClockKeyID) - : undefined; - } - set rollClockKey(val) { - this.updateTarget("rollClockKeyID", val ?? null); - } - /** - * This method prepares the roll participant data. - * It iterates over the roll sections (roll, position, effect) and for each section, - * it creates a new BladesRollParticipant instance for each participant in that section. - * The created instances are stored in the rollParticipants object. - */ - prepareRollParticipantData() { - const participantFlagData = this.data.rollParticipantData; - if (!participantFlagData) { - return; - } - const rollParticipants = {}; - [ - RollModSection.roll, - RollModSection.position, - RollModSection.effect - ].forEach((rollSection) => { - const sectionFlagData = participantFlagData[rollSection]; - if (sectionFlagData) { - const sectionParticipants = {}; - Object.entries(sectionFlagData).forEach(([subSection, subSectionFlagData]) => { - if (subSectionFlagData) { - sectionParticipants[subSection] = - new BladesRollParticipant(this, { - ...subSectionFlagData, - rollParticipantSection: rollSection, - rollParticipantSubSection: subSection - }); - } - }); - rollParticipants[rollSection] = sectionParticipants; - } - }); - this._rollParticipants = rollParticipants; - } - get rollParticipants() { - return this._rollParticipants; - } - getRollParticipant(section, subSection) { - if (isParticipantSection(section) && isParticipantSubSection(subSection)) { - const sectionData = this.rollParticipants?.[section]; - if (sectionData) { - return sectionData[subSection] ?? null; - } - } - return null; - } - get rollParticipantSelectOptions() { - const nonPrimaryPCs = BladesPC.All - .filter((actor) => actor.hasTag(Tag.PC.ActivePC) && actor.id !== this.rollPrimary.rollPrimaryID) - .map((actor) => ({ value: actor.id, display: actor.name })); - return { - Assist: nonPrimaryPCs, - Setup: nonPrimaryPCs, - Group: nonPrimaryPCs - }; - } - get rollType() { return this.data.rollType; } - get rollSubType() { return this.data.rollSubType; } - set rollSubType(val) { - this.updateTarget("rollSubType", val ?? null); - } - get rollPhase() { - return this.data.rollPhase ?? RollPhase.Collaboration; - } - get rollDowntimeAction() { return this.data.rollDowntimeAction; } - get rollTrait() { return this.data.rollTrait; } - get rollTraitVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionVerbs)) { - return undefined; - } - return C.ActionVerbs[this.rollTrait]; - } - get rollTraitPastVerb() { - if (!this.rollTrait) { - return undefined; - } - if (!(this.rollTrait in C.ActionPastVerbs)) { - return undefined; - } - return C.ActionPastVerbs[this.rollTrait]; - } - _rollTraitValOverride; - get rollTraitValOverride() { return this._rollTraitValOverride; } - set rollTraitValOverride(val) { this._rollTraitValOverride = val; } - get rollTraitData() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.actions[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipActions, - gmTooltip: C.ActionTooltipsGM[this.rollTrait] - }; - } - if (isAttribute(this.rollTrait)) { - return { - name: this.rollTrait, - value: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - max: this.rollTraitValOverride ?? this.rollPrimaryDoc.attributes[this.rollTrait], - pcTooltip: this.rollPrimaryDoc.rollTraitPCTooltipAttributes, - gmTooltip: C.AttributeTooltips[this.rollTrait] - }; - } - } - if (U.isInt(this.rollTrait)) { - return { - name: `+${this.rollTraitValOverride ?? this.rollTrait}`, - value: this.rollTraitValOverride ?? this.rollTrait, - max: this.rollTraitValOverride ?? this.rollTrait - }; - } - if (isFactor(this.rollTrait)) { - return { - name: U.tCase(this.rollTrait), - value: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.value ?? 0, - max: this.rollTraitValOverride ?? this.rollPrimary.rollFactors[this.rollTrait]?.max ?? 10 - }; - } - throw new Error(`[get rollTraitData] Invalid rollTrait: '${this.rollTrait}'`); - } - get rollTraitOptions() { - if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - if (isAction(this.rollTrait)) { - return Object.values(ActionTrait) - .map((action) => ({ - name: U.uCase(action), - value: action - })); - } - if (isAttribute(this.rollTrait)) { - return Object.values(AttributeTrait) - .map((attribute) => ({ - name: U.uCase(attribute), - value: attribute - })); - } - } - if (U.isInt(this.rollTrait)) { - return [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] - .map((num) => ({ - name: `+${num}`, - value: num - })); - } - if (isFactor(this.rollTrait)) { - return []; - } - throw new Error(`[get rollTraitOptions] Invalid rollTrait: '${this.rollTrait}'`); - } - get posEffectTrade() { - return this.data?.rollPosEffectTrade ?? false; - } - // getFlagVal(flagKey?: string): T | undefined { - // if (flagKey) { - // return this.document.getFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")) as T | undefined; - // } - // return this.document.getFlag(C.SYSTEM_ID, "rollCollab") as T | undefined; - // } - // async setFlagVal(flagKey: string, flagVal: unknown, isRerendering = true) { - // await this.document.setFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab."), flagVal); - // if (isRerendering) { - // socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - // } - // } - // async clearFlagVal(flagKey: string, isRerendering = true) { - // await this.document.unsetFlag(C.SYSTEM_ID, `rollCollab.${flagKey}`.replace(/(rollCollab\.)+/g, "rollCollab.")); - // if (isRerendering) { - // socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - // } - // } - get initialPosition() { - return this.data.rollPositionInitial ?? Position.risky; - } - set initialPosition(val) { - this.updateTarget("rollPositionInitial", val ?? Position.risky); - } - get initialEffect() { - return this.data.rollEffectInitial ?? Effect.standard; - } - set initialEffect(val) { - this.updateTarget("rollEffectInitial", val ?? Effect.standard); - } - get isApplyingConsequences() { - if (this.rollType !== RollType.Action) { - return false; - } - if (!this.rollResult) { - return false; - } - if (![RollResult.partial, RollResult.fail].includes(this.rollResult)) { - return false; - } - return true; - } - // Get rollConsequence() --> For resistance rolls. - get rollConsequence() { - const { consequence } = this.data.resistanceData ?? {}; - if (!consequence?.id) { - return undefined; - } - return game.eunoblades.Consequences.get(consequence.id) - ?? new BladesConsequence(consequence); - } - // #endregion - // #region GETTERS: DERIVED DATA ~ - get rollPositionFinal() { - return Object.values(Position)[U.clampNum(Object.values(Position).indexOf(this.initialPosition) - + this.getModsDelta(RollModSection.position) - + (this.posEffectTrade === "position" ? 1 : 0) - + (this.posEffectTrade === "effect" ? -1 : 0), [0, 2])]; - } - get rollEffectFinal() { - return Object.values(Effect)[U.clampNum(Object.values(Effect).indexOf(this.initialEffect) - + this.getModsDelta(RollModSection.effect) - + (this.posEffectTrade === "effect" ? 1 : 0) - + (this.posEffectTrade === "position" ? -1 : 0), [0, 4])]; - } - get rollResultDelta() { - return this.getModsDelta(RollModSection.result) - + (this.data?.GMBoosts.Result ?? 0) - + (this.tempGMBoosts.Result ?? 0); - } - get rollResultFinal() { - if (this.rollResult === false) { - return false; - } - if (this.rollResultDelta === 0) { - return this.rollResult; - } - switch (this.rollType) { - case RollType.Action: - case RollType.Fortune: { - return Object.values(RollResult).toReversed()[U.clampNum(Object.values(RollResult).toReversed().indexOf(this.rollResult) - + this.rollResultDelta, [0, 3])]; - } - case RollType.Resistance: { // Return stress cost of resisting - if (this.isCritical) { - return -1; - } - return U.clampNum(6 - this.highestDieVal - this.rollResultDelta, [-1, Infinity]); - } - case RollType.IndulgeVice: { // Return stress cleared from indulging - return U.clampNum(this.highestDieVal + this.rollResultDelta, [0, Infinity]); - } - } - return false; - } - get finalDicePool() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.data.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)); - } - get isRollingZero() { - return Math.max(0, this.rollTraitData.value - + this.getModsDelta(RollModSection.roll) - + (this.data.GMBoosts.Dice ?? 0) - + (this.tempGMBoosts.Dice ?? 0)) <= 0; - } - _roll; - get roll() { - this._roll ??= new Roll(`${this.isRollingZero ? 2 : this.finalDicePool}d6`, {}); - return this._roll; - } - get rollFactors() { - const defaultFactors = { - [Factor.tier]: { - name: "Tier", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: true, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.quality]: { - name: "Quality", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.scale]: { - name: "Scale", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - }, - [Factor.magnitude]: { - name: "Magnitude", - value: 0, - max: 0, - baseVal: 0, - display: "?", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold" - } - }; - const mergedSourceFactors = U.objMerge(U.objMerge(defaultFactors, this.rollPrimary.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.source, { isMutatingOk: false }); - const mergedOppFactors = this.rollOpposition - ? U.objMerge(U.objMerge(defaultFactors, this.rollOpposition.rollFactors, { isMutatingOk: false }), this.data.rollFactorToggles.opposition, { isMutatingOk: false }) - : {}; - return { - source: Object.fromEntries(Object.entries(mergedSourceFactors) - .map(([factor, factorData]) => { - factorData.value += - (this.data.GMBoosts[factor] ?? 0) - + (this.tempGMBoosts[factor] ?? 0); - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })), - opposition: Object.fromEntries(Object.entries(mergedOppFactors) - .map(([factor, factorData]) => { - factorData.value += this.data.GMOppBoosts[factor] ?? 0; - if (factor === Factor.tier) { - factorData.display = U.romanizeNum(factorData.value); - } - else { - factorData.display = `${factorData.value}`; - } - return [factor, factorData]; - })) - }; - } - // #endregion - // #region ROLL MODS: Getters & Update Method ~ - initRollMods() { - // Reset override values previously enabled by rollmods - this.rollTraitValOverride = undefined; - this.rollFactorPenaltiesNegated = {}; - this.tempGMBoosts = {}; - this.rollMods = Object.values(this.data.rollModsData).map((modData) => new BladesRollMod(modData, this)); - // ESLINT DISABLE: Dev Code. - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const initReport = {}; - let initReportCount = 0; - const watchMod = (label) => { - if (BladesRoll.Debug.modWatch === false) { - return; - } - const reportLabel = `(${initReportCount}) == ${label}`; - const rollMod = this.rollMods - .find((mod) => BladesRoll.Debug.modWatch && BladesRoll.Debug.modWatch.exec(mod.name)); - if (rollMod) { - initReport[`${reportLabel} : ${rollMod.status}`] = { - inst: rollMod, - data: { ...rollMod.data }, - sourceName: rollMod.sourceName, - status: { - ALL: rollMod.status, - base: rollMod.baseStatus, - held: rollMod.heldStatus, - user: rollMod.userStatus - }, - is: { - active: rollMod.isActive, - visible: rollMod.isVisible, - conditional: rollMod.isConditional, - inInactiveBlock: rollMod.isInInactiveBlock, - isPush: rollMod.isPush, - isBasicPush: rollMod.isBasicPush - } - }; - } - else { - initReport[reportLabel] = "MOD NOT FOUND"; - } - initReportCount++; - }; - watchMod("INITIAL"); - /* *** PASS ZERO: ROLLTYPE VALIDATION PASS *** */ - this.rollMods = this.rollMods.filter((rollMod) => rollMod.isValidForRollType()); - watchMod("ROLLTYPE VALIDATION"); - /* *** PASS ONE: DISABLE PASS *** */ - // ... Conditional Status Pass - const conditionalDisablePass = this.rollMods.filter((rollMod) => !rollMod.setConditionalStatus()); - watchMod("DISABLE - CONDITIONAL"); - // ... AutoReveal/AutoEnable Pass - const autoRevealDisablePass = conditionalDisablePass.filter((rollMod) => !rollMod.setAutoStatus()); - watchMod("DISABLE - AUTO-REVEAL/ENABLE"); - // ... Payable Pass - autoRevealDisablePass.forEach((rollMod) => { rollMod.setPayableStatus(); }); - watchMod("DISABLE - PAYABLE"); - /* *** PASS TWO: FORCE-ON PASS *** */ - const parseForceOnKeys = (mod) => { - const holdKeys = mod.effectKeys.filter((key) => key.startsWith("ForceOn")); - if (holdKeys.length === 0) { - return; - } - while (holdKeys.length) { - const thisTarget = holdKeys.pop()?.split(/-/)?.pop(); - if (thisTarget === "BestAction") { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollTraitValOverride = Math.max(...Object.values(this.rollPrimaryDoc.actions)); - } - } - else { - const [targetName, targetCat, targetPosNeg] = thisTarget?.split(/,/) ?? []; - if (!targetName) { - throw new Error(`No targetName found in thisTarget: ${thisTarget}.`); - } - let targetMod = this.getRollModByName(targetName) - ?? this.getRollModByName(targetName, targetCat ?? mod.section); - if (!targetMod && targetName === "Push") { - [targetMod] = [ - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "negative").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getActiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOn), - ...this.getInactiveBasicPushMods(targetCat ?? mod.section, "positive").filter((m) => m.status === RollModStatus.ToggledOff) - ]; - } - targetMod ??= this.getRollModByName(targetName, targetCat ?? mod.section, targetPosNeg ?? mod.posNeg); - if (!targetMod) { - throw new Error(`No mod found matching ${targetName}/${targetCat}/${targetPosNeg}`); - } - if (!targetMod.isActive) { - targetMod.heldStatus = RollModStatus.ForcedOn; - parseForceOnKeys(targetMod); - } - else { - targetMod.heldStatus = RollModStatus.ForcedOn; - } - } - } - }; - this.getActiveRollMods().forEach((rollMod) => parseForceOnKeys(rollMod)); - watchMod("FORCE-ON PASS"); - /* *** PASS THREE: PUSH-CHECK PASS *** */ - // IF ROLL FORCED ... - if (this.isForcePushed()) { - // ... Force Off _ALL_ visible, inactive "Is-Push" mods. - this.getInactivePushMods() - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("PUSH-CHECK: FORCE-OFF IS-PUSH"); - } - // ... BY CATEGORY ... - [RollModSection.roll, RollModSection.effect].forEach((cat) => { - if (this.isPushed(cat)) { - // ... if pushed by positive mod, Force Off any visible Bargain - if (cat === RollModSection.roll && this.isPushed(cat, "positive")) { - const bargainMod = this.getRollModByID("Bargain-positive-roll"); - if (bargainMod?.isVisible) { - bargainMod.heldStatus = RollModStatus.ForcedOff; - } - } - watchMod("PUSH-CHECK: FORCE OFF BARGAIN"); - } - else { - // Otherwise, hide all Is-Push mods - this.getInactivePushMods(cat) - .filter((mod) => !mod.isBasicPush) - .forEach((mod) => { mod.heldStatus = RollModStatus.Hidden; }); - watchMod("PUSH-CHECK: HIDE IS-PUSH"); - } - }); - /* *** PASS FOUR: Relevancy Pass *** */ - this.getVisibleRollMods() - .forEach((mod) => { mod.setRelevancyStatus(); }); - watchMod("RELEVANCY PASS"); - /* *** PASS FIVE: Overpayment Pass *** */ - // ... If 'Cost-SpecialArmor' active, ForceOff other visible Cost-SpecialArmor mods - const activeArmorCostMod = this.getActiveRollMods().find((mod) => mod.effectKeys.includes("Cost-SpecialArmor")); - if (activeArmorCostMod) { - this.getVisibleRollMods() - .filter((mod) => !mod.isActive && mod.effectKeys.includes("Cost-SpecialArmor")) - .forEach((mod) => { mod.heldStatus = RollModStatus.ForcedOff; }); - watchMod("OVERPAYMENT PASS"); - } - eLog.checkLog2("rollMods", "*** initRollMods() PASS ***", initReport); - } - isTraitRelevant(trait) { - if (trait in Factor) { - const { source, opposition } = this.rollFactors; - return Boolean(trait in source && trait in opposition && source[trait]?.isActive); - } - return false; - } - get isParticipantRoll() { - return (this.rollType === RollType.Fortune && !game.user.isGM) - || (this.rollSubType === RollSubType.GroupParticipant); - } - negatePushCost() { - const costlyPushMod = this.getActiveRollMods() - .find((mod) => mod.isPush && mod.stressCost > 0); - if (costlyPushMod) { - U.pullElement(costlyPushMod.effectKeys, (k) => k.startsWith("Cost-Stress")); - } - } - rollFactorPenaltiesNegated = {}; - negateFactorPenalty(factor) { - this.rollFactorPenaltiesNegated[factor] = true; - } - tempGMBoosts = {}; - isPushed(cat, posNeg) { return this.getActiveBasicPushMods(cat, posNeg).length > 0; } - hasOpenPush(cat, posNeg) { return this.isPushed(cat) && this.getOpenPushMods(cat, posNeg).length > 0; } - isForcePushed(cat, posNeg) { return this.isPushed(cat) && this.getForcedPushMods(cat, posNeg).length > 0; } - get rollCosts() { - if (!this.isPushed) { - return 0; - } - const harmPush = this.getRollModByID("Push-negative-roll"); - const rollPush = this.getRollModByID("Push-positive-roll"); - const effectPush = this.getRollModByID("Push-positive-effect"); - const negatePushCostMods = this.getActiveRollMods(RollModSection.after, "positive") - .filter((mod) => mod.effectKeys.includes("Negate-PushCost")); - return ((harmPush?.isActive && harmPush?.stressCost) || 0) - + ((rollPush?.isActive && rollPush?.stressCost) || 0) - + ((effectPush?.isActive && effectPush?.stressCost) || 0) - - (negatePushCostMods.length * 2); - } - get rollCostData() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs ?? []) - .flat(); - } - getRollModByName(name, cat, posNeg) { - const modMatches = this.rollMods.filter((rollMod) => { - if (U.lCase(rollMod.name) !== U.lCase(name)) { - return false; - } - if (cat && rollMod.section !== cat) { - return false; - } - if (posNeg && rollMod.posNeg !== posNeg) { - return false; - } - return true; - }); - if (modMatches.length === 0) { - return undefined; - } - if (modMatches.length > 1) { - return undefined; - } - return modMatches[0]; - } - getRollModByID(id) { return this.rollMods.find((rollMod) => rollMod.id === id); } - getRollMods(cat, posNeg) { - return this.rollMods.filter((rollMod) => (!cat || rollMod.section === cat) - && (!posNeg || rollMod.posNeg === posNeg)); - } - getVisibleRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActiveRollMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getVisibleInactiveRollMods(cat, posNeg) { - return this.getVisibleRollMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getPushMods(cat, posNeg) { - return this.getRollMods(cat, posNeg).filter((rollMod) => rollMod.isPush); - } - getVisiblePushMods(cat, posNeg) { - return this.getPushMods(cat, posNeg).filter((rollMod) => rollMod.isVisible); - } - getActivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => rollMod.isActive); - } - getActiveBasicPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getInactivePushMods(cat, posNeg) { - return this.getVisiblePushMods(cat, posNeg).filter((rollMod) => !rollMod.isActive); - } - getInactiveBasicPushMods(cat, posNeg) { - return this.getInactivePushMods(cat, posNeg).filter((rollMod) => rollMod.isBasicPush); - } - getForcedPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ForcedOn); - } - getOpenPushMods(cat, posNeg) { - return this.getActivePushMods(cat, posNeg) - .filter((rollMod) => rollMod.isBasicPush - && rollMod.status === RollModStatus.ToggledOn); - } - getModsDelta = (cat) => { - return U.sum([ - ...this.getActiveRollMods(cat, "positive").map((mod) => mod.value), - ...this.getActiveRollMods(cat, "negative").map((mod) => -mod.value) - ]); - }; - _rollMods; - /** - * Compare function for sorting roll mods. - * @param {BladesRollMod} modA First mod to compare. - * @param {BladesRollMod} modB Second mod to compare. - * @returns {number} - Comparison result. - */ - compareMods(modA, modB) { - // Define the order of mod names for sorting - const modOrder = ["Bargain", "Assist", "Setup"]; - // Check for basic push - if (modA.isBasicPush) { - return -1; - } - if (modB.isBasicPush) { - return 1; - } - // Check for active Bargain - if (modA.name === "Bargain" && modA.isActive) { - return -1; - } - if (modB.name === "Bargain" && modB.isActive) { - return 1; - } - // Check for push - if (modA.isPush) { - return -1; - } - if (modB.isPush) { - return 1; - } - // Check for mod name order - const modAIndex = modOrder.indexOf(modA.name); - const modBIndex = modOrder.indexOf(modB.name); - if (modAIndex !== -1 && modBIndex !== -1) { - return modAIndex - modBIndex; - } - // Default to alphabetical order - return modA.name.localeCompare(modB.name); - } - get rollMods() { - if (!this._rollMods) { - throw new Error("[get rollMods] No roll mods found!"); - } - return [...this._rollMods].sort((modA, modB) => this.compareMods(modA, modB)); - } - set rollMods(val) { this._rollMods = val; } - canResistWithArmor(csq) { - if (!this.rollPrimary.hasArmor) { - return false; - } - return csq.attribute === AttributeTrait.prowess; - } - canResistWithSpecialArmor(csq) { - if (!BladesPC.IsType(this.rollPrimaryDoc)) { - return false; - } - return this.rollPrimaryDoc.isSpecialArmorAvailable; - } - // #endregion - // #region CONSEQUENCES: Getting, Accepting, Resisting - get consequences() { - const csqDataSet = this.data.consequenceData?.[this.rollPositionFinal]?.[this.rollResult]; - if (csqDataSet) { - return Object.values(csqDataSet).map((csqData) => new BladesConsequence(csqData)); - } - return []; - } - getConsequenceByID(csqID) { - return this.consequences.find((csq) => csq.id === csqID) ?? false; - } - get acceptedConsequences() { - if ([RollPhase.AwaitingConsequences, RollPhase.Complete].includes(this.rollPhase)) { - return this.consequences.filter((csq) => csq.isAccepted === true); - } - return []; - } - get unacceptedConsequences() { - if (this.rollPhase === RollPhase.AwaitingConsequences) { - return this.consequences.filter((csq) => csq.isAccepted !== true); - } - return []; - } - // #endregion - // #region *** ROLL COLLAB CONTEXT *** ~ - /** - * Retrieve the data for rendering the base RollCollab sheet. - * @returns {Promise} The data which can be used to render the HTML of the sheet. - */ - get context() { - this.initRollMods(); - this.rollMods.forEach((rollMod) => rollMod.applyRollModEffectKeys()); - return this.getTemplateContext(); - } - getFortuneRollModsSchemaSet() { - const modsData = []; - if (this.rollSubType === RollSubType.Engagement) { - modsData.push({ - key: "BoldPlan-positive-roll", - name: "Bold Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - key: "ComplexPlan-negative-roll", - name: "Complex Plan", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - key: "ExploitWeakness-positive-roll", - name: "Exploiting a Weakness", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - key: "WellDefended-negative-roll", - name: "Well-Defended", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - modsData.push({ - key: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }); - modsData.push({ - key: "EnemyInterference-negative-roll", - name: "Enemy Interference", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }); - } - return modsData; - } - getDowntimeActionRollModsSchemaSet() { - const modsData = []; - modsData.push({ - key: "HelpFromFriend-positive-roll", - name: "Help From a Friend", - section: RollModSection.position, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Help From a Friend

Add +1d if you enlist the help of a friend or contact.

" - }); - if (this.rollDowntimeAction !== DowntimeAction.IndulgeVice) { - modsData.push({ - key: "CanBuyResultLevel-positive-after", - name: "Buying Result Level", - section: RollModSection.after, - base_status: RollModStatus.ForcedOn, - posNeg: "positive", - modType: RollModType.general, - value: 0, - effectKeys: [], - tooltip: "

Buying Result Level

After your roll, you can increase the result level by one for each Coin you spend.

" - }); - } - switch (this.rollDowntimeAction) { - case DowntimeAction.AcquireAsset: { - modsData.push({ - key: "RepeatPurchase-positive-roll", - name: "Repeat Purchase", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Repeat Purchase Bonus

Add +1d if you have previously acquired this asset or service with a Acquire Asset Downtime activity.

" - }); - modsData.push({ - key: "RestrictedItem-negative-after", - name: "Restricted", - section: RollModSection.after, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 0, - effectKeys: ["Cost-Heat2"], - tooltip: "

Restricted

Whether contraband goods or dangerous materials, this Acquire Asset Downtime activity will add +2 Heat to your crew.

" - }); - break; - } - default: break; - } - /* - modsData.push({ - id: "--", - name: "", - section: RollModSection, - base_status: RollModStatus, - posNeg: "", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

" - }) - */ - return modsData; - } - /** - * Gets the roll modifications data. - * @returns {BladesRollMod.Data[]} The roll modifications data. - */ - getRollModsData() { - const defaultMods = []; - if (this.rollType === RollType.Fortune) { - defaultMods.push(...this.getFortuneRollModsSchemaSet()); - } - if (this.rollDowntimeAction) { - defaultMods.push(...this.getDowntimeActionRollModsSchemaSet()); - } - if (this.rollType === RollType.Action) { - if (this.rollPrimary.isWorsePosition) { - defaultMods.push({ - key: "WorsePosition-negative-position", - name: "Worse Position", - section: RollModSection.position, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Worse Position

A Consequence on a previous roll has worsened your Position.

" - }); - } - } - if (this.rollType === RollType.Action - && this.acceptedConsequences.some((csq) => csq.type === ConsequenceType.ReducedEffect)) { - defaultMods.push({ - key: "ReducedEffect-negative-effect", - name: "Reduced Effect", - section: RollModSection.effect, - base_status: RollModStatus.ForcedOn, - posNeg: "negative", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Reduced Effect

A Consequence has worsened your Effect.

" - }); - } - return Object.values(BladesRoll.GetRollModsDataSet(this, [ - ...defaultMods, - ...this.rollOpposition?.rollOppModsSchemaSet ?? [] - ])); - } - /** - * Determines if the user is a game master. - * @returns {boolean} Whether the user is a GM. - */ - getIsGM() { - return game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM; - } - /** - * Gets the roll costs. - * @returns {BladesRoll.CostData[]} The roll costs. - */ - getRollCosts() { - return this.getActiveRollMods() - .map((rollMod) => rollMod.costs) - .flat() - .filter((costData) => costData !== undefined); - } - /** - * Constructs the sheet data. - * @param {boolean} isGM If the user is a GM. - * @param {BladesRoll.CostData[]} rollCosts The roll costs. - * @returns {BladesRoll.Context} The constructed sheet data. - */ - getTemplateContext() { - const { data: rData, rollPrimary, rollTraitData, rollTraitOptions, rollOppClockKey, rollClockKey, finalDicePool, rollPositionFinal, rollEffectFinal, rollResultDelta, rollResultFinal, rollMods, rollFactors } = this; - if (!rollPrimary) { - throw new Error("A primary roll source is required for BladesRoll."); - } - const baseData = { - ...this.data, - cssClass: "roll-collab", - isGM: this.isGM, - system: this.rollPrimaryDoc?.system, - rollMods, - rollPrimary, - rollTraitData, - rollTraitOptions, - diceTotal: finalDicePool, - rollOpposition: this.rollOpposition, - rollParticipants: this.rollParticipants, - rollParticipantOptions: this.rollParticipantSelectOptions, - rollEffects: Object.values(Effect), - rollTraitValOverride: this.rollTraitValOverride, - rollFactorPenaltiesNegated: this.rollFactorPenaltiesNegated, - posRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "positive")])), - negRollMods: Object.fromEntries(Object.values(RollModSection) - .map((cat) => [cat, this.getRollMods(cat, "negative")])), - hasInactiveConditionals: this.calculateHasInactiveConditionalsData(), - rollFactors, - ...this.calculateOddsHTML(finalDicePool, rollResultDelta) - }; - const GMBoostsData = this.calculateGMBoostsData(rData); - const positionEffectTradeData = this.calculatePositionEffectTradeData(); - const stressCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "Stress") - .map((costData) => [costData.label, costData.costAmount]); - const availableArmor = []; - if (this.rollPrimaryDoc instanceof BladesPC) { - availableArmor.push(...this.rollPrimaryDoc.availableArmor); - } - else if (BladesItem.IsType(this.rollPrimaryDoc, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - // Gang or Expert Cohort - for (let index = 0; index < this.rollPrimaryDoc.system.armor.value; index++) { - availableArmor.push("Armor"); - } - } - const armorCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "Armor") - .map((costData, index) => [costData.label, availableArmor[index]]) - .filter(([_label, armorType]) => armorType !== undefined); - const specialArmorCostDataSet = this.getRollCosts() - .filter((costData) => costData.costType === "SpecialArmor") - .map((costData) => costData.label); - const userPermission = baseData.userPermissions[game.user.id] ?? RollPermissions.Observer; - // const downtimeData = this.processDowntimeActions(); - return { - ...baseData, - ...(this.rollPrimaryDoc ? { rollPrimary: this.rollPrimaryDoc } : {}), - rollPositionFinal, - rollEffectFinal, - rollResultFinal, - rollPositions: Object.values(Position), - rollEffects: Object.values(Effect), - rollResultDelta, - isAffectingResult: rollResultDelta !== 0 - || this.getVisibleRollMods(RollModSection.result).length > 0 - || (this.isGM && this.getRollMods(RollModSection.result).length > 0), - isAffectingAfter: this.getVisibleRollMods(RollModSection.after).length > 0 - || (this.isGM && this.getRollMods(RollModSection.after).length > 0), - ...GMBoostsData, - ...positionEffectTradeData, - ...(rollOppClockKey ? { rollClockKey: rollOppClockKey } : {}), - ...(rollClockKey ? { rollClockKey } : {}), - totalStressCost: stressCostDataSet.reduce((acc, [_label, amount]) => acc + amount, 0), - totalArmorCost: armorCostDataSet.length, - stressCosts: stressCostDataSet.length > 0 - ? Object.fromEntries(stressCostDataSet) - : undefined, - armorCosts: armorCostDataSet.length > 0 - ? Object.fromEntries(armorCostDataSet) - : undefined, - specArmorCost: specialArmorCostDataSet[0], - userPermission, - editable: userPermission === RollPermissions.Primary || userPermission === RollPermissions.GM, - gamePhase: game.eunoblades.Tracker.phase - }; - } - // type BladesSelectOption = { - // value: valueType, - // display: displayType - // }; - // protected processDowntimeActions() { - // const downtimeData: Record; - // if (BladesActor.IsType(this.rollPrimaryDoc, BladesActorType.pc)) { - // downtimeData.canDoDowntimeActions = true; - // downtimeData.downtimeActionsRemaining = this.rollPrimaryDoc.remainingDowntimeActions; - // const availableDowntimeActions: DowntimeAction[] = []; - // if (this.rollType === RollType.Action) { - // availableDowntimeActions.push(...[ - // DowntimeAction.AcquireAsset, - // DowntimeAction.LongTermProject, - // DowntimeAction.Recover, - // DowntimeAction.ReduceHeat - // ]); - // } else if (this.rollType === RollType.Fortune) { - // availableDowntimeActions.push(...[ - // DowntimeAction. - // ]) - // } - // downtimeData.downtimeActionOptions = - // downtimeActionOptions?: Array - // } - calculateGMBoostsData(data) { - return { - GMBoosts: { - Dice: data.GMBoosts.Dice ?? 0, - [Factor.tier]: data.GMBoosts[Factor.tier] ?? 0, - [Factor.quality]: data.GMBoosts[Factor.quality] ?? 0, - [Factor.scale]: data.GMBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: data.GMBoosts[Factor.magnitude] ?? 0, - Result: data.GMBoosts.Result ?? 0 - }, - GMOppBoosts: { - [Factor.tier]: data.GMOppBoosts[Factor.tier] ?? 0, - [Factor.quality]: data.GMOppBoosts[Factor.quality] ?? 0, - [Factor.scale]: data.GMOppBoosts[Factor.scale] ?? 0, - [Factor.magnitude]: data.GMOppBoosts[Factor.magnitude] ?? 0 - } - }; - } - calculateOddsHTML(diceTotal, rollResultDelta) { - if (this.rollType === RollType.Resistance) { - return this.calculateOddsHTML_Resistance(diceTotal); - } - return this.calculateOddsHTML_Standard(diceTotal, rollResultDelta); - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @param {number} rollResultDelta - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Standard(diceTotal, rollResultDelta) { - const oddsColors = { - crit: "var(--blades-gold)", - success: "var(--blades-white-bright)", - partial: "var(--blades-grey)", - fail: "var(--blades-black-dark)" - }; - const odds = { ...C.DiceOddsStandard[diceTotal] }; - if (rollResultDelta < 0) { - for (let i = rollResultDelta; i < 0; i++) { - oddsColors.crit = oddsColors.success; - oddsColors.success = oddsColors.partial; - oddsColors.partial = oddsColors.fail; - } - } - else if (rollResultDelta > 0) { - for (let i = 0; i < rollResultDelta; i++) { - oddsColors.fail = oddsColors.partial; - oddsColors.partial = oddsColors.success; - oddsColors.success = oddsColors.crit; - } - } - const resultElements = []; - Object.entries(odds).reverse().forEach(([result, chance]) => { - if (chance === 0) { - return; - } - resultElements.push(`
 
`); - }); - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate odds starting & ending HTML based on given dice total. - * @param {number} diceTotal Total number of dice. - * @returns {{oddsHTMLStart: string, oddsHTMLStop: string}} Opening & Closing HTML for odds bar display - */ - calculateOddsHTML_Resistance(diceTotal) { - // Const oddsColors = [ - // "var(--blades-gold)", // -1 - // "var(--blades-white)", // 0 - // "var(--blades-red-bright)", // 1 - // "var(--blades-red-dark)", // 2 - // "var(--blades-red-bright)", // 3 - // "var(--blades-red-dark)", // 4 - // "var(--blades-red-bright)" // 5 - // ].reverse(); - const oddsColors = [ - "var(--blades-gold)", // -1 - "var(--blades-white)", // 0 - "var(--blades-red)", // 1 - "var(--blades-red)", // 2 - "var(--blades-red)", // 3 - "var(--blades-red)", // 4 - "var(--blades-red)" // 5 - ].reverse(); - const oddsFilters = [ - "none", - "none", - "brightness(0.2)", - "brightness(0.4)", - "brightness(0.6)", - "brightness(0.8)", - "none" - ].reverse(); - const odds = [...C.DiceOddsResistance[diceTotal]].reverse(); - const resultElements = []; - for (let index = 0; index < odds.length; index++) { - const chance = odds[index]; - if (chance > 0) { - const color = oddsColors[index]; - const filter = oddsFilters[index]; - resultElements.push(...[ - `
 
` - ]); - } - } - return { - oddsHTMLStart: [ - "
", - ...resultElements - ].join("\n"), - oddsHTMLStop: "
" - }; - } - /** - * Calculate data for position and effect trade. - * @returns {{canTradePosition: boolean, canTradeEffect: boolean}} - */ - calculatePositionEffectTradeData() { - const canTradePosition = this.posEffectTrade === "position" || (this.posEffectTrade === false - && this.rollPositionFinal !== Position.desperate - && this.rollEffectFinal !== Effect.extreme); - const canTradeEffect = this.posEffectTrade === "effect" || (this.posEffectTrade === false - && this.rollPositionFinal !== Position.controlled - && this.rollEffectFinal !== Effect.zero); - return { canTradePosition, canTradeEffect }; - } - /** - * Calculate data on whether there are any inactive conditionals. - * @returns {Record} - Data on inactive conditionals. - */ - calculateHasInactiveConditionalsData() { - const hasInactive = {}; - for (const section of Object.values(RollModSection)) { - hasInactive[section] = this.getRollMods(section).filter((mod) => mod.isInInactiveBlock).length > 0; - } - return hasInactive; - } - // #endregion - // #region *** EVALUATING ROLL *** ~ - // #region DICE ~ - _dieVals; - get dieVals() { - return this.roll.terms[0].results - .map((result) => result.result) - .sort() - .reverse(); - // return this._dieVals; - } - // Accounts for rolling zero dice by removing highest. - get finalDieVals() { - return this.isRollingZero ? this.dieVals.slice(1) : this.dieVals; - } - get finalDiceData() { - eLog.checkLog3("rollCollab", "[get finalDiceData()]", { roll: this, dieVals: this.dieVals }); - const dieVals = [...this.dieVals]; - const ghostNum = this.isRollingZero ? dieVals.shift() : null; - const isCritical = dieVals.filter((val) => val === 6).length >= 2; - const diceData = dieVals.map((val, i) => ({ - value: val, - dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i), - dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical) - })); - if (ghostNum) { - diceData.push({ - value: ghostNum, - dieClass: "blades-die-ghost", - dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false) - }); - } - return diceData; - } - // get dieValsHTML(): string { - // eLog.checkLog3("rollCollab", "[get dieValsHTML()]", {roll: this, dieVals: this.dieVals}); - // const dieVals = [...this.dieVals]; - // const ghostNum = this.isRollingZero ? dieVals.shift() : null; - // const isCritical = dieVals.filter((val) => val === 6).length >= 2; - // const diceData = dieVals.map((val, i) => ({ - // value: val, - // dieClass: BladesRoll.GetDieClass(this.rollType, this.rollResult, val, i), - // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, val, i, false, isCritical) - // })); - // if (ghostNum) { - // diceData.push({ - // value: ghostNum, - // dieClass: "blades-die-ghost", - // dieImage: BladesRoll.GetDieImage(this.rollType, this.rollResult, ghostNum, diceData.length, true, false) - // }); - // } - // return [ - // ...dieVals.map((val, i) => ``), - // ghostNum ? `` : null - // ] - // .filter((val): val is string => typeof val === "string") - // .join(""); - // } - // #endregion - // #region RESULT GETTERS ~ - get isCritical() { - return this.finalDieVals.filter((val) => val === 6).length >= 2; - } - get isSuccess() { - return Boolean(!this.isCritical && this.finalDieVals.find((val) => val === 6)); - } - get isPartial() { - return Boolean(!this.isCritical && !this.isSuccess && this.finalDieVals.find((val) => val && val >= 4)); - } - get isFail() { - return !this.isCritical && !this.isSuccess && !this.isPartial; - } - get highestDieVal() { - return this.finalDieVals[0]; - } - get rollResult() { - /* Subclass overrides determine how roll result is communicated. */ - throw new Error("[BladesRoll.rollResult] Unimplemented by Subclass."); - } - // #endregion - get isResolved() { return this.roll.total !== undefined; } - async evaluateRoll() { - // If this command is called on an already-resolved roll, close the roll collab element and return. - if (this.isResolved) { - this.closeRollCollab_Animation(); - return this.data; - } - this.closeRollCollab_SocketCall(); - eLog.checkLog3("rollCollab", "[resolveRoll()] Before Evaluation", { roll: this, rollData: { ...this.data } }); - await this.roll.evaluate({ async: true }); - return await this.updateTargetData({ - ...this.data, - rollPositionFinal: this.rollPositionFinal, - rollEffectFinal: this.rollEffectFinal, - rollResult: this.rollResult, - rollTraitVerb: this.rollTraitVerb, - rollTraitPastVerb: this.rollTraitPastVerb, - finalDiceData: this.finalDiceData, - rollPhase: this.isApplyingConsequences - ? RollPhase.AwaitingConsequences - : RollPhase.Complete - }); - } - async resolveRollResult() { - /* Subclass overrides determine how result affects roll participants */ - throw new Error("[BladesRoll.resolveRollResult] Unimplemented by Subclass."); - } - async outputRollToChat() { - await BladesChat.create({ - speaker: this.getSpeaker(BladesChat.getSpeaker()), - content: await renderTemplate(this.chatTemplate, this.data), - type: CONST.CHAT_MESSAGE_TYPES.ROLL, - flags: { - "eunos-blades": { rollData: this.data } - } - }); - } - async resolveRoll() { - await this.evaluateRoll(); - this.resolveRollResult(); - await this.outputRollToChat(); - } - // #endregion - // #region *** INTERFACING WITH BLADESCHAT *** - getSpeaker(chatSpeaker) { - // Compare against rollPrimary and modify accordingly. - const { rollPrimaryID, rollPrimaryName, rollPrimaryType, rollPrimaryDoc } = this.rollPrimary; - chatSpeaker.alias = rollPrimaryName; - if ([BladesItemType.cohort_gang, BladesItemType.cohort_expert].includes(rollPrimaryType)) { - chatSpeaker.actor = rollPrimaryDoc?.parent?.id ?? chatSpeaker.actor; - if (rollPrimaryDoc?.parent instanceof BladesPC) { - chatSpeaker.alias = `${chatSpeaker.alias} (${rollPrimaryDoc.parent.name})`; - } - } - else if ([BladesItemType.gm_tracker, BladesItemType.score].includes(rollPrimaryType)) { - chatSpeaker.actor = null; - chatSpeaker.alias = "The Gamemaster"; - } - else if (rollPrimaryID) { - chatSpeaker.actor = rollPrimaryID; - } - // chatSpeaker.alias = `${chatSpeaker.alias} Rolls ...`; - return chatSpeaker; - } - // #endregion - // #region *** ROLL COLLAB HTML ELEMENT *** - get collabTemplate() { - /* Subclass overrides determine template against which data is parsed */ - throw new Error("[BladesRoll.collabTemplate] Unimplemented by Subclass."); - } - get chatTemplate() { - /* Subclass overrides determine template against which data is parsed */ - throw new Error("[BladesRoll.chatTemplate] Unimplemented by Subclass."); - } - // #region LISTENER FUNCTIONS ~ - // async _handleConsequenceClick(event: ClickEvent) { - // const clickTarget$ = $(event.currentTarget); - // const csqParent$ = clickTarget$.closest(".comp.consequence-display-container"); - // const csqID = csqParent$.data("csq-id"); - // const chatElem$ = csqParent$.closest(".blades-roll"); - // const chatMessage$ = chatElem$.closest(".chat-message"); - // const chatID = chatMessage$.data("messageId") as IDString; - // const chatMessage = game.messages.get(chatID); - // if (!chatMessage) {return;} - // const csqs = await BladesConsequence.GetFromChatMessage(chatMessage); - // const thisCsq = csqs.find((csq) => csq.id === csqID); - // if (!thisCsq) {return;} - // switch (clickTarget$.data("action")) { - // case "accept-consequence": return thisCsq.resolveAccept(); - // case "resist-consequence": return thisCsq.resistConsequence(); - // case "armor-consequence": return thisCsq.resistArmorConsequence(); - // case "special-consequence": return thisCsq.resistSpecialArmorConsequence(); - // } - // return undefined as never; - // } - _toggleRollModClick(event) { - event.preventDefault(); - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const rollMod = this.getRollModByID(id); - if (!rollMod) { - throw new Error(`Unable to find roll mod with id '${id}'`); - } - switch (rollMod.status) { - case RollModStatus.Hidden: - rollMod.userStatus = RollModStatus.ForcedOff; - return; - case RollModStatus.ForcedOff: - rollMod.userStatus = RollModStatus.ToggledOff; - return; - case RollModStatus.ToggledOff: - rollMod.userStatus = RollModStatus.ToggledOn; - return; - case RollModStatus.ToggledOn: - rollMod.userStatus = game.user.isGM - ? RollModStatus.ForcedOn - : RollModStatus.ToggledOff; - return; - case RollModStatus.ForcedOn: - rollMod.userStatus = RollModStatus.Hidden; - return; - default: throw new Error(`Unrecognized RollModStatus: ${rollMod.status}`); - } - } - /** - * Handles setting of rollMod status via GM pop-out controls - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSet(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const id = elem$.data("id"); - const status = elem$.data("status"); - if (!isModStatus(status) && status !== "Reset") { - return; - } - const rollMod = this.getRollModByID(id); - if (rollMod) { - rollMod.userStatus = status === "Reset" ? undefined : status; - } - } - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlSetTargetToValue(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target").replace(/flags\.eunos-blades\./, ""); - const value = elem$.data("value"); - await this.updateTarget(target, value); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _gmControlCycleTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const flagTarget = elem$.data("flagTarget"); - const curVal = elem$.data("curVal"); - const cycleVals = elem$.data("vals")?.split(/\|/); - if (!cycleVals) { - throw new Error(`Unable to parse cycle values from data-vals = ${elem$.data("vals")}`); - } - const curValIndex = cycleVals.indexOf(curVal); - if (curValIndex === -1) { - throw new Error(`Unable to find current value '${curVal}' in cycle values '${elem$.data("vals")}'`); - } - let newValIndex = curValIndex + 1; - if (newValIndex >= cycleVals.length) { - newValIndex = 0; - } - const newVal = cycleVals[newValIndex]; - eLog.checkLog3("gmControlCycleTarget", "gmControlCycleTarget", { flagTarget, curVal, cycleVals, curValIndex, newValIndex, newVal }); - await this.updateTarget(flagTarget, newVal); - } - /** - * Handles resetting value associated with GM number line on a right-click. - * @param {ClickEvent} event JQuery context menu event sent to listener. - */ - async _gmControlResetTarget(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - await this.updateTarget($(event.currentTarget).data("target"), undefined); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetPosition(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const position = elem$.data("status"); - this.initialPosition = position; - } - /** - * Handles setting of baseline rollPosition via GM button line - * @param {ClickEvent} event JQuery click event sent to listener. - */ - _gmControlSetEffect(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const effect = elem$.data("status"); - this.initialEffect = effect; - } - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - * @param {ClickEvent} event JQuery click event sent to listener. - */ - async _gmControlToggleFactor(event) { - event.preventDefault(); - if (!game.user.isGM) { - return; - } - const elem$ = $(event.currentTarget); - const target = elem$.data("target"); - const value = !elem$.data("value"); - eLog.checkLog3("toggleFactor", "_gmControlToggleFactor", { event, target, value }); - const factorToggleData = this.data.rollFactorToggles; - const [thisSource, thisFactor, thisToggle] = target.split(/\./).slice(-3); - // If thisToggle is unrecognized, just toggle whatever value target points at - if (!["isActive", "isPrimary", "isDominant", "highFavorsPC"].includes(thisToggle)) { - await this.updateTarget(target, value); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - // Otherwise, first toggle targeted factor to new value - factorToggleData[thisSource][thisFactor] = { - ...factorToggleData[thisSource][thisFactor] ?? { display: "" }, - [thisToggle]: value - }; - // Then perform specific logic depending on toggle targeted: - switch (thisToggle) { - case "isDominant": - case "isPrimary": { - // Only one factor per sourceType can be declared Primary or Dominant: - // If one is being activated, must toggle off the others. - if (value === true) { - Object.values(Factor) - .filter((factor) => factor !== thisFactor) - .forEach((factor) => { - if (factorToggleData[thisSource][factor]?.[thisToggle] === true) { - factorToggleData[thisSource][factor] = { - ...factorToggleData[thisSource][factor], - [thisToggle]: false - }; - } - }); - } - break; - } - case "isActive": { - // 'isActive' should be synchronized when 1) value is true, and 2) the other value is false - if (value === true) { - const otherSource = thisSource === "source" ? "opposition" : "source"; - factorToggleData[otherSource][thisFactor] = { - ...factorToggleData[otherSource][thisFactor] ?? { display: "" }, - isActive: value - }; - } - break; - } - default: break; - } - await this.updateTarget("rollFactorToggles", factorToggleData); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _onSelectChange(event) { - event.preventDefault(); - const elem = event.currentTarget; - const { docType } = elem.dataset; - if (elem.value !== "" && docType?.startsWith("BladesRollParticipant")) { - const [_, section, subSection] = docType.split("."); - await this.addRollParticipant(elem.value, section, subSection); - } - else { - await U.EventHandlers.onSelectChange(this, event); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - } - async _onTextInputBlur(event) { - await U.EventHandlers.onTextInputBlur(this, event); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } - async _onGMPopupClick(event) { - /** - * { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.updateTarget("rollPosEffectTrade", "effect") - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - else { - this.updateTarget("rollPosEffectTrade", false) - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - } - }); - this.elem$.find("[data-action='tradeEffect']").on({ - click: (event) => { - const curVal = `${$(event.currentTarget).data("value")}`; - if (curVal === "false") { - this.updateTarget("rollPosEffectTrade", "position") - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - else { - this.updateTarget("rollPosEffectTrade", false) - .then(() => socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id)); - } - } - }); - this.elem$.find("[data-action='roll']").on({ - click: () => this.resolveRoll() - }); - this.elem$ - .find("select[data-action='player-select']") - .on({ change: this._onSelectChange.bind(this) }); - if (!game.user.isGM) { - return; - } - /** - * Handles setting of rollMod status via GM pop-out controls - */ - this.elem$.find(".controls-toggle").on({ - click: (event) => { - event.preventDefault(); - $(event.currentTarget).parents(".controls-panel").toggleClass("active"); - } - }); - this.elem$.find("[data-action=\"gm-set\"]").on({ - click: this._gmControlSet.bind(this) - }); - /** - * Handles setting of baseline rollPosition via GM button line - */ - this.elem$.find("[data-action=\"gm-set-position\"]").on({ - click: this._gmControlSetPosition.bind(this) - }); - /** - * Handles setting of baseline rollEffect via GM button line - */ - this.elem$.find("[data-action=\"gm-set-effect\"]").on({ - click: this._gmControlSetEffect.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - this.elem$.find("[data-action=\"gm-set-target\"]").on({ - click: this._gmControlSetTargetToValue.bind(this), - contextmenu: this._gmControlResetTarget.bind(this) - }); - /** - * Handles setting values via GM number line (e.g. roll factor boosts/modifications). - * Handles resetting value associated with GM number line on a right-click. - */ - this.elem$.find("[data-action=\"gm-cycle-target\"]").on({ - click: this._gmControlCycleTarget.bind(this) - }); - /** - * Handles setting of Factor toggles: isActive, isPrimary, highFavorsPC, isDominant - */ - this.elem$.find("[data-action=\"gm-toggle-factor\"]").on({ - click: this._gmControlToggleFactor.bind(this) - }); - this.elem$ - .find("select[data-action='gm-select']") - .on({ change: this._onSelectChange.bind(this) }); - this.elem$ - .find("[data-action=\"gm-edit-consequences\"]") - .on({ click: () => BladesDialog.DisplayRollConsequenceDialog(this) }); - this.elem$ - .find("[data-action=\"gm-text-popup\"]") - .on({ click: this._onGMPopupClick.bind(this) }); - this.elem$ - .find("[data-action='gm-text-input']") - .on({ blur: this._onTextInputBlur.bind(this) }); - } - // #endregion - // #endregion - // #region OVERRIDES: _canDragDrop, _onDrop, _onSubmit, close, render ~ - // override _canDragDrop() { - // return game.user.isGM; - // } - // override _onDrop(event: DragEvent) { - // const {uuid} = TextEditor.getDragEventData(event) as {uuid: UUIDString}; - // const dropDoc = fromUuidSync(uuid); - // if (BladesRollOpposition.IsDoc(dropDoc)) { - // this.rollOpposition = new BladesRollOpposition(this, {rollOppDoc: dropDoc}); - // } else if (dropDoc instanceof BladesProject && dropDoc.clockKey) { - // // Project dropped on roll: Assign project's clock key to roll. - // this.rollClockKey = dropDoc.clockKey; - // } - // } - async submitChange(prop, val) { - await this.updateTarget(prop, val); - socketlib.system.executeForEveryone("renderRollCollab_SocketCall", this.id); - } -} -class BladesActionRoll extends BladesRoll { - /* Not much -- most action roll things will extend to other rolls, but split out things like Position, Effect, default Mods */ - static ApplySchemaDefaults(schemaData) { - schemaData.rollType = RollType.Action; - if (!schemaData.rollPrimaryData) { - throw new Error("Must include a rollPrimaryData when constructing a BladesActionRoll object."); - } - // Validate the rollTrait - if (!(schemaData.rollTrait === "" || U.isInt(schemaData.rollTrait) || U.lCase(schemaData.rollTrait) in { ...ActionTrait, ...Factor })) { - throw new Error(`[BladesActionRoll.ApplySchemaDefaults()] Bad RollTrait for Action Roll: ${schemaData.rollTrait}`); - } - schemaData = super.ApplySchemaDefaults(schemaData); - const rollPrimary = BladesRollPrimary.Build(schemaData); - // Modify Config object depending on downtime action where necessary. - switch (schemaData.rollDowntimeAction) { // Remember: Can be done outside of Downtime during Flashbacks! - case DowntimeAction.AcquireAsset: { - schemaData.rollTrait = Factor.tier; - break; - } - case DowntimeAction.LongTermProject: { - // Validate that rollOppData points to a project item - if (!BladesRollOpposition.IsValidData(schemaData.rollOppData)) { - throw new Error("No rollOppData provided for LongTermProject roll."); - } - const rollOpp = new BladesRollOpposition(undefined, schemaData.rollOppData); - if (![ - BladesItemType.project, - BladesItemType.design - ].includes(rollOpp.rollOppType)) { - throw new Error("rollOppType must be 'project' or 'design' for LongTermProject roll."); - } - break; - } - case DowntimeAction.Recover: { - // Validate that rollPrimary is an NPC or a PC with Physiker. - if (BladesPC.IsType(rollPrimary.rollPrimaryDoc)) { - if (!rollPrimary.rollPrimaryDoc.abilities.find((ability) => ability.name === "Physiker")) { - throw new Error("A PC rollPrimary on a Recovery roll must have the Physiker ability."); - } - schemaData.rollTrait = ActionTrait.tinker; - } - else if (rollPrimary.rollPrimaryDoc?.rollPrimaryType === BladesActorType.npc) { - schemaData.rollTrait = Factor.quality; - } - else { - throw new Error("Only a PC with Physiker or an NPC can be rollPrimary on a Recover roll."); - } - break; - } - case DowntimeAction.ReduceHeat: { - // rollPrimary must be a cohort with a parent PC or Crew, - // and PC must be member of a crew - // and Crew must not have zero Heat. - let parentCrew = undefined; - if (rollPrimary.rollPrimaryDoc) { - const { parent } = rollPrimary.rollPrimaryDoc; - if (BladesCrew.IsType(parent)) { - parentCrew = parent; - } - else if (BladesPC.IsType(parent) && BladesCrew.IsType(parent.crew)) { - parentCrew = parent.crew; - } - } - if (!BladesCrew.IsType(parentCrew)) { - throw new Error(`Could not find crew for rollPrimary '${rollPrimary.rollPrimaryDoc?.rollPrimaryName}'`); - } - if (parentCrew.system.heat.value === 0) { - throw new Error("Attempt to Reduce Heat for a Crew with no Heat."); - } - break; - } - case undefined: break; - default: throw new Error(`Unrecognized Roll Downtime Action: ${schemaData.rollDowntimeAction}`); - } - return { - rollPositionInitial: Position.risky, - rollEffectInitial: Effect.standard, - rollPosEffectTrade: false, - GMBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOppBoosts: { - [Factor.tier]: 0, - [Factor.quality]: 0, - [Factor.scale]: 0, - [Factor.magnitude]: 0 - }, - GMOverrides: {}, - rollFactorToggles: { - source: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - }, - opposition: { - [Factor.tier]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.quality]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.scale]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }, - [Factor.magnitude]: { - display: "", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - } - } - }, - ...schemaData, - rollPrimaryData: rollPrimary.data, - rollOppData: schemaData.rollOppData instanceof BladesRollOpposition - ? schemaData.rollOppData.data - : schemaData.rollOppData - }; - } - static get DefaultRollModSchemaSet() { - return [ - { - key: "Push-positive-roll", - name: "PUSH", - section: RollModSection.roll, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["ForceOff-Bargain", "Cost-Stress2"], - tooltip: "

Push for +1d

For 2 Stress, add 1 die to your pool.

(You cannot also accept a Devil's Bargain to increase your dice pool: It's one or the other.)

" - }, - { - key: "Bargain-positive-roll", - name: "Bargain", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: [], - tooltip: "

Devil's Bargain

The GM has offered you a Devil's Bargain.

Accept the terms to add 1 die to your pool.

(You cannot also Push for +1d to increase your dice pool: It's one or the other.)

" - }, - { - key: "Assist-positive-roll", - name: "Assist", - section: RollModSection.roll, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Assists

%DOC_NAME% is Assisting your efforts, adding 1 die to your pool.

" - }, - { - key: "Setup-positive-position", - name: "Setup", - section: RollModSection.position, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Position by one level.

" - }, - { - key: "Push-positive-effect", - name: "PUSH", - section: RollModSection.effect, - base_status: RollModStatus.ToggledOff, - posNeg: "positive", - modType: RollModType.general, - value: 1, - effectKeys: ["Cost-Stress2"], - tooltip: "

Push for Effect

For 2 Stress, increase your Effect by one level.

" - }, - { - key: "Setup-positive-effect", - name: "Setup", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.teamwork, - value: 1, - tooltip: "

%DOC_NAME% Sets You Up

%DOC_NAME% has set you up for success with a preceding Setup action, increasing your Effect by one level.

" - }, - { - key: "Potency-positive-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "positive", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, you have Potency in this action, increasing your Effect by one level.

" - }, - { - key: "Potency-negative-effect", - name: "Potency", - section: RollModSection.effect, - base_status: RollModStatus.Hidden, - posNeg: "negative", - modType: RollModType.general, - value: 1, - tooltip: "

Potency

By circumstance or advantage, @OPPOSITION_NAME@ has Potency against you, reducing your Effect by one level." - } - ]; - } - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - const rollInst = await this.Create(parsedConfig); - return rollInst; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-action${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - const templateParts = [ - "systems/eunos-blades/templates/chat/roll-result/action", - this.rollClockKey ? "-clock" : "" - ]; - if (this.rollDowntimeAction && [ - DowntimeAction.AcquireAsset, // action-acquireasset - DowntimeAction.ReduceHeat, // action-reduceheat - DowntimeAction.Recover // action-clock-recover - ].includes(this.rollDowntimeAction)) { - templateParts.push(`-${U.lCase(this.rollDowntimeAction)}`); - } - else if (this.rollSubType && [ - RollSubType.GatherInfo // action-gatherinfo - ].includes(this.rollSubType)) { - templateParts.push(`-${U.lCase(this.rollSubType)}`); - } - templateParts.push(".hbs"); - return templateParts.join(""); - } - get rollResult() { - if (!this.isResolved) { - return false; - } - if (this.isCritical) { - return RollResult.critical; - } - if (this.isSuccess) { - return RollResult.success; - } - if (this.isPartial) { - return RollResult.partial; - } - return RollResult.fail; - } - async resolveRollResult() { - eLog.checkLog2("bladesRoll", "[BladesActionRoll] Costs", this.getRollCosts()); - const armorCost = this.getRollCosts() - .filter((costData) => costData.costType === "Armor") - .length; - if (this.rollPrimaryDoc instanceof BladesPC) { - const stressCost = this.getRollCosts() - .filter((costData) => costData.costType === "Stress") - .reduce((acc, costData) => acc + costData.costAmount, 0); - if (stressCost !== 0) { - this.rollPrimaryDoc.adjustStress(stressCost); - } - const specArmorCost = this.getRollCosts() - .filter((costData) => costData.costType === "SpecialArmor") - .length; - if (specArmorCost !== 0) { - this.rollPrimaryDoc.spendSpecialArmor(); - } - } - if (armorCost !== 0) { - this.rollPrimary.spendArmor(armorCost); - } - this.rollPrimaryDoc?.unsetFlag("eunos-blades", "isWorsePosition"); - } -} -class BladesResistanceRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate consequenceData - if (!config.resistanceData || !BladesConsequence.IsValidConsequenceData(config.resistanceData?.consequence)) { - eLog.error("rollCollab", "[PrepareResistanceRoll] Bad Roll Consequence Data.", config); - throw new Error("[PrepareResistanceRoll()] Bad Consequence Data for Resistance Roll"); - } - // Set rollTrait - config.rollTrait = config.resistanceData.consequence.attribute; - eLog.checkLog3("bladesRoll", "BladesRoll.PrepareResistanceRoll() [1]", { config }); - return config; - } - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - const rollInst = await this.Create(parsedConfig); - return rollInst; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-resistance${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/resistance.hbs"; - } - get stressCost() { - if (!this.isResolved) { - return 0; - } - const dieVals = [...this.finalDieVals]; - if (this.isCritical) { - return -1; - } - return 6 - (dieVals.shift() ?? 0); - } - get rollResult() { - if (!this.isResolved) { - return false; - } - return this.stressCost; - } - async resolveRollResult() { - if (this.rollPrimaryDoc instanceof BladesPC && this.stressCost !== 0) { - this.rollPrimaryDoc.adjustStress(this.stressCost); - } - } -} -class BladesInlineResistanceRoll extends BladesResistanceRoll { - get chatTemplate() { - return "systems/eunos-blades/templates/chat/components/inline-resistance.hbs"; - } -} -class BladesFortuneRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate the rollTrait - if (!(U.isInt(config.rollTrait) || U.lCase(config.rollTrait) in { ...ActionTrait, ...AttributeTrait, ...Factor })) { - throw new Error(`[PrepareFortuneRoll()] Bad RollTrait for Fortune Roll: ${config.rollTrait}`); - } - return config; - } - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - const rollInst = await this.Create(parsedConfig); - return rollInst; - } -} -class BladesIndulgeViceRoll extends BladesRoll { - static ApplySchemaDefaults(config) { - // Validate rollPrimary - if (!config.rollPrimaryData || !BladesPC.IsType(config.rollPrimaryData.rollPrimaryDoc)) { - throw new Error("[BladesRoll.PrepareIndulgeViceRollConfig] RollPrimary must be a PC for Indulge Vice rolls."); - } - // Set rollTrait - const { attributes } = config.rollPrimaryData.rollPrimaryDoc; - const minAttrVal = Math.min(...Object.values(attributes)); - config.rollTrait = U.sample(Object.values(AttributeTrait).filter((attr) => attributes[attr] === minAttrVal))[0]; - // Set other known config values - config.rollDowntimeAction = DowntimeAction.IndulgeVice; - return config; - } - static async New(config) { - // Build link config - const linkConfig = this.BuildLinkConfig(config); - const parsedConfig = { - ...config, - ...linkConfig - }; - const rollInst = await this.Create(parsedConfig); - return rollInst; - } - get collabTemplate() { - return `systems/eunos-blades/templates/roll/roll-collab-indulgevice${game.user.isGM ? "-gm" : ""}.hbs`; - } - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/indulgevice.hbs"; - } - get rollResult() { - if (!this.isResolved) { - return false; - } - return this.highestDieVal; - } - async resolveRollResult() { - if (BladesPC.IsType(this.rollPrimaryDoc)) { - this.rollPrimaryDoc.indulgeStress(this.highestDieVal); - } - } -} -class BladesEngagementRoll extends BladesFortuneRoll { - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/fortune-engagement.hbs"; - } -} -class BladesIncarcerationRoll extends BladesFortuneRoll { - get chatTemplate() { - return "systems/eunos-blades/templates/chat/roll-result/fortune-incarceration.hbs"; - } -} -// #region EXPORTS ~ -export { BladesRollMod, BladesRollPrimary, BladesRollOpposition, BladesRollParticipant }; -export default BladesRoll; -export { BladesActionRoll, BladesResistanceRoll, BladesInlineResistanceRoll, BladesFortuneRoll, BladesIndulgeViceRoll, BladesEngagementRoll, BladesIncarcerationRoll }; -// #endregion diff --git a/module/classes/BladesScene.js b/module/classes/BladesScene.js deleted file mode 100644 index c17765f3..00000000 --- a/module/classes/BladesScene.js +++ /dev/null @@ -1,14 +0,0 @@ -class BladesScene extends Scene { - async registerClockKey(clockKey) { - this.update({ [`clockKeys.${clockKey.id}`]: true }); - } - async unregisterClockKey(clockKey) { - if (typeof clockKey === "string") { - this.update({ [`clockKeys.-=${clockKey}`]: null }); - } - else { - this.update({ [`clockKeys.-=${clockKey.id}`]: null }); - } - } -} -export default BladesScene; diff --git a/module/classes/BladesTargetLink.js b/module/classes/BladesTargetLink.js deleted file mode 100644 index 4aded4ae..00000000 --- a/module/classes/BladesTargetLink.js +++ /dev/null @@ -1,535 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import U from "../core/utilities.js"; -import C from "../core/constants.js"; -import { BladesActor } from "../documents/BladesActorProxy.js"; -import { BladesItem } from "../documents/BladesItemProxy.js"; -import BladesChat from "./BladesChat.js"; -class BladesTargetLink { - // #region STATIC METHODS ~ - static get ValidTargetClasses() { - return [ - BladesActor, - BladesItem, - BladesChat, - User - ]; - } - static IsValidConfig(ref) { - return U.isSimpleObj(ref) - && (U.isDocID(ref.target) - || U.isDocUUID(ref.target) - || U.isDocID(ref.targetID) - || U.isDocUUID(ref.targetID) - || this.ValidTargetClasses.some((cls) => ref.target instanceof cls)) - && (U.isTargetKey(ref.targetKey) || U.isTargetFlagKey(ref.targetFlagKey)) - && !(U.isTargetKey(ref.targetKey) && U.isTargetFlagKey(ref.targetFlagKey)); - } - static IsValidData(ref) { - return U.isSimpleObj(ref) - && U.isDocID(ref.id) - && U.isDocUUID(ref.targetID) - && (U.isTargetKey(ref.targetKey) || U.isTargetFlagKey(ref.targetFlagKey)) - && !(U.isTargetKey(ref.targetKey) && U.isTargetFlagKey(ref.targetFlagKey)); - // && (typeof ref.isScopingById === "boolean"); - } - static #ParseChildLinkData(childData, parentLinkData) { - if (!parentLinkData) { - return childData; - } - const keyPrefixParts = "targetKey" in parentLinkData - ? [parentLinkData.targetKey] - : [parentLinkData.targetFlagKey]; - if (parentLinkData.isScopingById) { - keyPrefixParts.push(parentLinkData.id); - } - const keyPrefix = keyPrefixParts.join("."); - if ("targetKey" in childData && "targetKey" in parentLinkData) { - if (childData.targetKey.startsWith(`${keyPrefix}.`)) { - // Remove the keyPrefix and the following dot from childData.targetKey - childData.targetKey = childData.targetKey.slice(keyPrefix.length + 1); - } - childData.targetKey = [ - parentLinkData.targetKey, - parentLinkData.isScopingById ? parentLinkData.id : undefined, - childData.targetKey - ].filter(Boolean).join("."); - } - else if ("targetFlagKey" in childData && "targetFlagKey" in parentLinkData) { - if (childData.targetFlagKey.startsWith(`${keyPrefix}.`)) { - // Remove the keyPrefix and the following dot from childData.targetFlagKey - childData.targetFlagKey = childData.targetFlagKey.slice(keyPrefix.length + 1); - } - childData.targetFlagKey = [ - parentLinkData.targetFlagKey, - parentLinkData.isScopingById ? parentLinkData.id : undefined, - childData.targetFlagKey - ].filter(Boolean).join("."); - } - else { - throw new Error("[BladesTargetLink.ParseChildLinkData] targetKey/targetFlagKey mismatch between provided partialConfig and parentLinkData."); - } - return childData; - } - static BuildLinkConfig(partialConfig) { - // const {target, targetID, targetKey, targetFlagKey, isScopingById} = partialConfig; - if ("target" in partialConfig) { - if ("targetKey" in partialConfig) { - return { - target: partialConfig.target, - targetKey: partialConfig.targetKey, - isScopingById: partialConfig.isScopingById - }; - } - else if ("targetFlagKey" in partialConfig) { - return { - target: partialConfig.target, - targetFlagKey: partialConfig.targetFlagKey, - isScopingById: partialConfig.isScopingById - }; - } - throw new Error("[BladesTargetLink.BuildConfig] Must provide a targetKey or targetFlagKey."); - } - else if ("targetID" in partialConfig) { - if ("targetKey" in partialConfig) { - return { - targetID: partialConfig.targetID, - targetKey: partialConfig.targetKey, - isScopingById: partialConfig.isScopingById - }; - } - else if ("targetFlagKey" in partialConfig) { - return { - targetID: partialConfig.targetID, - targetFlagKey: partialConfig.targetFlagKey, - isScopingById: partialConfig.isScopingById - }; - } - throw new Error("[BladesTargetLink.BuildConfig] Must provide a targetKey or targetFlagKey."); - } - throw new Error("[BladesTargetLink.BuildConfig] Must provide a target or targetID."); - } - /** - * This private static method is used to transform a configuration object into a data object for BladesTargetLink. - * It checks if the provided configuration object is already valid data, and if so, returns it directly. - * Otherwise, it partitions the configuration object into link-specific configuration and additional schema data, - * constructs a full link configuration, and then creates a data object with a new random ID and the target UUID. - * The method ensures that either 'targetKey' or 'targetFlagKey' is present and throws an error if the configuration is invalid. - * - * @template Schema - The additional schema data required by the subclass. - * @param {BladesTargetLink.Config | BladesTargetLink.Data & Partial} config - The configuration object that may contain BladesTargetLink properties and any subclass-specific schema data. - * @returns {BladesTargetLink.Data & Partial} - The fully constructed data object with necessary properties for BladesTargetLink. - * @throws {Error} - Throws an error if the configuration object is invalid, lacks a target reference, or if both 'targetKey' and 'targetFlagKey' are provided. - */ - static #ParseConfigToData(config, parentLinkData) { - if (this.IsValidData(config)) { - return this.ParseConfigToData(config, parentLinkData); - } - const { linkConfig, partialSchema } = this.PartitionSchemaData(config); - const fullConfig = this.BuildLinkConfig(linkConfig); - // === CONVERT CONFIG TO DATA OBJECT === - // - Send through public ParseConfigToData method, so subclasses can include their own logic. - if ("targetKey" in fullConfig) { - return this.ParseConfigToData({ - id: randomID(), - ...partialSchema, - targetID: U.parseDocRefToUUID("target" in fullConfig ? fullConfig.target : fullConfig.targetID), - targetKey: fullConfig.targetKey - }, parentLinkData); - } - return this.ParseConfigToData({ - id: randomID(), - ...partialSchema, - targetID: U.parseDocRefToUUID("target" in fullConfig ? fullConfig.target : fullConfig.targetID), - targetFlagKey: fullConfig.targetFlagKey - }, parentLinkData); - } - /** - * This static method parses the provided data into a format suitable for BladesTargetLink. - * Subclasses can override this method to include their own parse logic. - * If the provided data is already valid, it is returned as is. - * Otherwise, the data is passed to the private #ParseConfig method for further processing. - * Note: The 'id' property is defined at the return step, within #ParseConfig: Subclass - * functionality that depends on the id property should be placed after the super call to this method. - * - * @template Schema - The data schema required by the subclass. - * @param {(BladesTargetLink.Config | BladesTargetLink.Data) & Partial} data - The data to be parsed. - * @returns {BladesTargetLink.Data & Partial} - The parsed data, suitable for BladesTargetLink. - */ - static ParseConfigToData(data, parentLinkData) { - if (this.IsValidData(data)) { - return this.#ParseChildLinkData(data, parentLinkData); - } - return this.#ParseConfigToData(data, parentLinkData); - } - static PartitionSchemaData(dataOrConfig) { - const { id, target, targetID, targetKey, targetFlagKey, isScopingById, ...schemaData } = dataOrConfig; - const partialSchema = schemaData; - if (U.isDocID(id)) { - // A Data object was submitted. - if (!this.IsValidData({ id, targetID, targetKey, targetFlagKey, isScopingById })) { - eLog.error("BladesTargetLink", "Bad Constructor DATA", { dataOrConfig }); - throw new Error("[new BladesTargetLink()] Bad Constructor DATA (see log)"); - } - let linkData; - if (targetKey) { - linkData = { id, targetID: targetID, targetKey, isScopingById: isScopingById ?? true }; - } - else if (targetFlagKey) { - linkData = { id, targetID: targetID, targetFlagKey, isScopingById: isScopingById ?? true }; - } - else { - eLog.error("BladesTargetLink", "Bad Constructor DATA", { dataOrConfig }); - throw new Error("[BladesTargetLink.PartitionSchemaData] Bad Constructor DATA (see log)"); - } - return { - linkData, - partialSchema - }; - } - // A Config object was submitted. - return { - linkConfig: this.BuildLinkConfig({ - ...{ isScopingById: isScopingById ?? true }, - ...("targetID" in dataOrConfig - ? { targetID: dataOrConfig.targetID } - : { target: dataOrConfig.target }), - ...("targetKey" in dataOrConfig - ? { targetKey: dataOrConfig.targetKey } - : { targetFlagKey: dataOrConfig.targetFlagKey }) - }), - partialSchema - }; - } - static _ApplySchemaDefaults(schemaData) { - return this.ApplySchemaDefaults(schemaData); - } - /** - * This static method applies defaults to any values missing from the class' data Schema. - * 'Schema' is defined by subclasses to BladesTargetLink. - * Subclasses must override this method to apply their own defaults. - * - * @template Schema - The data schema required by the subclass. - * @param {Partial} schemaData - Schema data overriding the defaults. - * @returns {Schema} - The schema data with defaults applied. - * @throws {Error} - Throws an error if this method is not overridden in a subclass. - */ - static ApplySchemaDefaults(schemaData) { - throw new Error("[BladesTargetLink.ApplySchemaDefaults] Static Method ApplySchemaDefaults must be overridden in subclass"); - } - /** - * Creates a new instance of BladesTargetLink and initializes it with the provided configuration. - * The configuration is parsed into a data object which is then used to initialize the target link. - * The function logs the parsed data for debugging purposes. - * - * @template Schema - The schema type parameter that extends the data structure. - * @param {BladesTargetLink.Config & Partial} config - The configuration object containing both the target link configuration and the schema configuration. - * - * @returns {Promise & BladesTargetLink.Subclass>} - A promise that resolves to a new instance of BladesTargetLink, initialized with the provided data. - * - * @throws {Error} - Throws an error if the initialization of the target link fails. - */ - static async Create(config, parentLinkData) { - const tLink = new this(config, parentLinkData); - await tLink.initTargetLink(); - return tLink; - } - // #endregion - // #region GETTERS ~ - get isGM() { return game.user.isGM; } - _id; - _targetID; - _targetKey; - _targetFlagKey; - _isScopingById = true; - _initialSchema; - get id() { return this._id; } - get targetID() { return this._targetID; } - get targetKey() { return this._targetKey; } - get targetFlagKey() { return this._targetFlagKey; } - get isScopingById() { return this._isScopingById; } - get initialSchema() { return this._initialSchema; } - get targetKeyPrefix() { - if (!this.targetKey) { - return undefined; - } - if (!this.isScopingById) { - return this.targetKey; - } - return this.targetKey - ? `${this.targetKey}.${this.id}` - : undefined; - } - get targetKeyNullPrefix() { - if (!this.targetKey) { - return undefined; - } - if (this.isScopingById) { - return `${this.targetKey}.-=${this.id}`; - } - if (/^.+\..+$/g.test(this.targetKey)) { - return this.targetKey.replace(/\.([^.]+)$/, ".-=$1"); - } - throw new Error(`[BladesTargetLink.targetKeyNullPrefix] Can't Nullify TargetKey '${this.targetKey}'`); - } - get targetFlagKeyPrefix() { - if (!this.targetFlagKey) { - return undefined; - } - if (!this.isScopingById) { - return this.targetFlagKey; - } - return this.targetFlagKey - ? `${this.targetFlagKey}.${this.id}` - : undefined; - } - get isLinkInitialized() { return this.isInitPromiseResolved; } - get linkData() { - if (this.targetKey) { - return { - id: this.id, - targetID: this.targetID, - targetKey: this.targetKey, - isScopingById: this.isScopingById - }; - } - if (this.targetFlagKey) { - return { - id: this.id, - targetID: this.targetID, - targetFlagKey: this.targetFlagKey, - isScopingById: this.isScopingById - }; - } - throw new Error(`[BladesTargetLink.linkData] Missing targetKey and targetFlagKey for '${this.id}'`); - } - _target; - get target() { return this._target; } - get localData() { - return { - ...this.initialSchema, - ...this.linkData - }; - } - get data() { - if (this.isLinkInitialized) { - let data; - if (this.targetFlagKeyPrefix) { - data = this.target.getFlag(C.SYSTEM_ID, this.targetFlagKeyPrefix); - } - else if (this.targetKeyPrefix) { - data = getProperty(this.target, this.targetKeyPrefix); - } - if (!data) { - throw new Error("[BladesTargetLink.data] Error retrieving data."); - } - return data; - } - else { - eLog.warn("BladesTargetLink", "Attempt to access data of uninitiated BladesTargetLink: Returning local data only.", { bladesTargetLink: this, localData: this.localData }); - return this.localData; - } - } - constructor(dataOrConfig, parentLinkData) { - let linkData; - let schema; - const subclassConstructor = this.constructor; - // First, we construct the link data from the config or data object. - if (subclassConstructor.IsValidData(dataOrConfig)) { - // If a simple link data object was provided, acquire the schema from the source document - ({ linkData } = subclassConstructor.PartitionSchemaData(dataOrConfig)); - const target = fromUuidSync(linkData.targetID); - if (!target) { - throw new Error(`[new BladesTargetLink()] Unable to resolve target from uuid '${linkData.targetID}'`); - } - if ("targetKey" in linkData) { - schema = getProperty(target, `${linkData.targetKey}.${linkData.id}`); - } - else { - schema = target.getFlag(C.SYSTEM_ID, `${linkData.targetFlagKey}.${linkData.id}`); - } - // Set the isInitPromiseResolved flag to true - this.isInitPromiseResolved = true; - } - else { - // Otherwise, we have to parse the config into a data object, and extract any schema data - // First we convert the config object to a BladesTargetLink.Data & Partial object. - const parsedData = BladesTargetLink.#ParseConfigToData(dataOrConfig, parentLinkData); - // Next we separate the linkData and the schemaData from the parsedData object. - let partialSchema; - ({ linkData, partialSchema } = subclassConstructor.PartitionSchemaData(parsedData)); - // And apply any schema defaults to the provided schema data. - schema = subclassConstructor._ApplySchemaDefaults(partialSchema); - } - this._id = linkData.id; - this._targetID = linkData.targetID; - if ("targetKey" in linkData) { - this._targetKey = linkData.targetKey; - } - else { - this._targetFlagKey = linkData.targetFlagKey; - } - const target = fromUuidSync(this.targetID); - if (!target) { - throw new Error(`[new BladesTargetLink()] Unable to resolve target from uuid '${this._targetID}'`); - } - this._target = target; - this._initialSchema = schema; - } - // #endregion - // #region ASYNC UPDATE & DELETE METHODS ~ - getDotKeyToProp(prop, isNullifying = false) { - if (this.targetKeyPrefix) { - if (prop === undefined) { - return isNullifying ? this.targetKeyNullPrefix : this.targetKeyPrefix; - } - return `${this.targetKeyPrefix}.${isNullifying ? "-=" : ""}${prop}`; - } - if (this.targetFlagKeyPrefix) { - if (prop === undefined) { - return this.targetFlagKeyPrefix; - } - return `${this.targetFlagKeyPrefix}.${prop}`; - } - throw new Error("[BladesTargetLink.getDotKeyToProp()] Missing 'targetKeyPrefix' and 'targetFlagKeyPrefix'"); - } - getFlagParamsToProp(prop) { - return [C.SYSTEM_ID, this.getDotKeyToProp(prop)]; - } - async updateTargetFlag(prop, val) { - if (!this.targetFlagKeyPrefix) { - return; - } - if (val === null) { - await this.target.unsetFlag(...this.getFlagParamsToProp(prop)); - } - else if (this.target instanceof BladesActor) { - await this.target.setFlag(...this.getFlagParamsToProp(prop), val); - } - else if (this.target instanceof BladesItem) { - await this.target.setFlag(...this.getFlagParamsToProp(prop), val); - } - else if (this.target instanceof User) { - await this.target.setFlag(...this.getFlagParamsToProp(prop), val); - } - else if (this.target instanceof BladesChat) { - await this.target.setFlag(...this.getFlagParamsToProp(prop), val); - } - } - async updateTargetKey(prop, val) { - if (!this.targetKeyPrefix) { - return; - } - await this.target.update({ [this.getDotKeyToProp(prop, val === null)]: val }, { render: false }); - } - initPromise; - isInitPromiseResolved = false; - /** - * Initializes a target link by updating the target's data with the provided data object. - * If a targetKey is provided, the data is updated directly on the target. - * If a targetFlagKey is provided, the data is set as a flag on the target. - * - * This method need only be run once, when the document is first created and its data must be written to server storage. - * External functions can synchronously check the status of initialization via the isInitPromiseResolved property, while - * asynchronous functions can await the initPromise property. - * - * TargetLink documents whose data already exists in server storage can be constructed directly (i.e. new BladesTargetLink(data)) - * without needing to call this method. - * - * @param {BladesTargetLink.Data & Schema} data - The combined data object containing both the target link data and the schema data. - * @returns {Promise} - A promise that resolves when the server update is complete. - */ - async initTargetLink() { - this.isInitPromiseResolved = false; - // Construct data object - const data = { - ...this.linkData, - ...this.initialSchema - }; - this.initPromise = new Promise((resolve, reject) => { - if (this.targetKeyPrefix) { - const updateData = mergeObject((getProperty(this.target, this.targetKeyPrefix) ?? {}), data); - this.target.update({ [this.targetKeyPrefix]: updateData }, { render: false }).then(() => { - this.isInitPromiseResolved = true; - resolve(); - }).catch(reject); - } - else if (this.targetFlagKeyPrefix) { - const updateData = mergeObject((this.target.getFlag(C.SYSTEM_ID, this.targetFlagKeyPrefix) ?? {}), data); - this.target.setFlag(C.SYSTEM_ID, this.targetFlagKeyPrefix, updateData).then(() => { - this.isInitPromiseResolved = true; - resolve(); - }).catch(reject); - } - else { - reject(); - } - }); - return this.initPromise; - } - async #updateTargetViaMerge(updateData, waitFor) { - await U.waitFor(waitFor); - if (this.targetKeyPrefix) { - // First, prepend targetKeyPrefix or targetFlagKeyPrefix (as appropriate) to each key of updateData - updateData = U.objMap(updateData, false, (key) => `${this.targetKeyPrefix || this.targetFlagKeyPrefix}.${key}`); - return this.target.update(updateData, { render: false }); - } - else if (this.targetFlagKeyPrefix) { - // We must retrieve the existing flag data, flattenObject it, then merge it with updateData - const existingFlagData = this.target.getFlag(C.SYSTEM_ID, this.targetFlagKeyPrefix) ?? {}; - const flattenedFlagData = flattenObject(existingFlagData); - const mergedFlagData = mergeObject(flattenedFlagData, updateData); - return this.target.setFlag(C.SYSTEM_ID, this.targetFlagKeyPrefix, mergedFlagData); - } - else { - throw new Error(`[BladesTargetLink.#updateTargetViaMerge] Unable to update target data for BladesTargetLink id '${this.id}': Missing both 'targetKeyPrefix' and 'targetFlagKeyPrefix'`); - } - } - async #updateTargetPropVal(prop, val, waitFor) { - await U.waitFor(waitFor); - if (this.targetKeyPrefix) { - return this.target.update({ [`${this.targetKeyPrefix}.${prop}`]: val }); - } - else if (this.targetFlagKeyPrefix) { - return this.updateTargetFlag(prop, val); - } - } - async updateTarget(propOrData, valOrWaitFor, waitFor) { - // If the provided data is an object, we assume it is a full data object and we update the target with it. - if (typeof propOrData === "string") { - if (getProperty(this.data, propOrData) === valOrWaitFor) { - return; - } - return this.#updateTargetPropVal(propOrData, valOrWaitFor, waitFor); - } - if (typeof propOrData === "object") { - return this.#updateTargetViaMerge(propOrData, valOrWaitFor); - } - else { - throw new Error(`[BladesTargetLink.updateTarget()] Bad updateData for id '${this.id}': ${propOrData}`); - } - } - async updateTargetData(val, waitFor) { - if (val) { - // Add BladesTargetLink.Data to provided schema - val = { - ...val, - ...this.linkData - }; - } - await U.waitFor([this.initPromise, waitFor]); - if (this.targetFlagKeyPrefix) { - await this.updateTargetFlag(undefined, val); - } - else { - await this.updateTargetKey(undefined, val); - } - } - async delete(collection, waitFor) { - if (collection) { - collection.delete(this.id); - } - await U.waitFor([this.initPromise, waitFor]); - await this.updateTargetData(null); - } -} -export default BladesTargetLink; diff --git a/module/core/ai.js b/module/core/ai.js deleted file mode 100644 index 12f27c21..00000000 --- a/module/core/ai.js +++ /dev/null @@ -1,421 +0,0 @@ -import C from "./constants.js"; -import U from "./utilities.js"; -export var OpenAITool; -(function (OpenAITool) { - OpenAITool["code_interpreter"] = "code_interpreter"; - OpenAITool["retrieval"] = "retrieval"; - OpenAITool["function"] = "function"; -})(OpenAITool || (OpenAITool = {})); -export var OpenAIModel; -(function (OpenAIModel) { - OpenAIModel["ada"] = "ada"; - OpenAIModel["ada-code-search-code"] = "ada-code-search-code"; - OpenAIModel["ada-code-search-text"] = "ada-code-search-text"; - OpenAIModel["ada-search-document"] = "ada-search-document"; - OpenAIModel["ada-search-query"] = "ada-search-query"; - OpenAIModel["ada-similarity"] = "ada-similarity"; - OpenAIModel["babbage"] = "babbage"; - OpenAIModel["babbage-002"] = "babbage-002"; - OpenAIModel["babbage-code-search-code"] = "babbage-code-search-code"; - OpenAIModel["babbage-code-search-text"] = "babbage-code-search-text"; - OpenAIModel["babbage-search-document"] = "babbage-search-document"; - OpenAIModel["babbage-search-query"] = "babbage-search-query"; - OpenAIModel["babbage-similarity"] = "babbage-similarity"; - OpenAIModel["canary-tts"] = "canary-tts"; - OpenAIModel["canary-whisper"] = "canary-whisper"; - OpenAIModel["code-davinci-edit-001"] = "code-davinci-edit-001"; - OpenAIModel["code-search-ada-code-001"] = "code-search-ada-code-001"; - OpenAIModel["code-search-ada-text-001"] = "code-search-ada-text-001"; - OpenAIModel["code-search-babbage-code-001"] = "code-search-babbage-code-001"; - OpenAIModel["code-search-babbage-text-001"] = "code-search-babbage-text-001"; - OpenAIModel["curie"] = "curie"; - OpenAIModel["curie-instruct-beta"] = "curie-instruct-beta"; - OpenAIModel["curie-search-document"] = "curie-search-document"; - OpenAIModel["curie-search-query"] = "curie-search-query"; - OpenAIModel["curie-similarity"] = "curie-similarity"; - OpenAIModel["dall-e-2"] = "dall-e-2"; - OpenAIModel["davinci"] = "davinci"; - OpenAIModel["davinci-002"] = "davinci-002"; - OpenAIModel["davinci-instruct-beta"] = "davinci-instruct-beta"; - OpenAIModel["davinci-search-document"] = "davinci-search-document"; - OpenAIModel["davinci-search-query"] = "davinci-search-query"; - OpenAIModel["davinci-similarity"] = "davinci-similarity"; - OpenAIModel["gpt-3.5-turbo"] = "gpt-3.5-turbo"; - OpenAIModel["gpt-3.5-turbo-0301"] = "gpt-3.5-turbo-0301"; - OpenAIModel["gpt-3.5-turbo-0613"] = "gpt-3.5-turbo-0613"; - OpenAIModel["gpt-3.5-turbo-1106"] = "gpt-3.5-turbo-1106"; - OpenAIModel["gpt-3.5-turbo-16k"] = "gpt-3.5-turbo-16k"; - OpenAIModel["gpt-3.5-turbo-16k-0613"] = "gpt-3.5-turbo-16k-0613"; - OpenAIModel["gpt-3.5-turbo-instruct"] = "gpt-3.5-turbo-instruct"; - OpenAIModel["gpt-3.5-turbo-instruct-0914"] = "gpt-3.5-turbo-instruct-0914"; - OpenAIModel["gpt-4"] = "gpt-4"; - OpenAIModel["gpt-4-0314"] = "gpt-4-0314"; - OpenAIModel["gpt-4-0613"] = "gpt-4-0613"; - OpenAIModel["gpt-4-1106-preview"] = "gpt-4-1106-preview"; - OpenAIModel["gpt-4-vision-preview"] = "gpt-4-vision-preview"; - OpenAIModel["text-ada-001"] = "text-ada-001"; - OpenAIModel["text-babbage-001"] = "text-babbage-001"; - OpenAIModel["text-curie-001"] = "text-curie-001"; - OpenAIModel["text-davinci-001"] = "text-davinci-001"; - OpenAIModel["text-davinci-002"] = "text-davinci-002"; - OpenAIModel["text-davinci-003"] = "text-davinci-003"; - OpenAIModel["text-davinci-edit-001"] = "text-davinci-edit-001"; - OpenAIModel["text-embedding-ada-002"] = "text-embedding-ada-002"; - OpenAIModel["text-search-ada-doc-001"] = "text-search-ada-doc-001"; - OpenAIModel["text-search-ada-query-001"] = "text-search-ada-query-001"; - OpenAIModel["text-search-babbage-doc-001"] = "text-search-babbage-doc-001"; - OpenAIModel["text-search-babbage-query-001"] = "text-search-babbage-query-001"; - OpenAIModel["text-search-curie-doc-001"] = "text-search-curie-doc-001"; - OpenAIModel["text-search-curie-query-001"] = "text-search-curie-query-001"; - OpenAIModel["text-search-davinci-doc-001"] = "text-search-davinci-doc-001"; - OpenAIModel["text-search-davinci-query-001"] = "text-search-davinci-query-001"; - OpenAIModel["text-similarity-ada-001"] = "text-similarity-ada-001"; - OpenAIModel["text-similarity-babbage-001"] = "text-similarity-babbage-001"; - OpenAIModel["text-similarity-curie-001"] = "text-similarity-curie-001"; - OpenAIModel["text-similarity-davinci-001"] = "text-similarity-davinci-001"; - OpenAIModel["tts-1"] = "tts-1"; - OpenAIModel["tts-1-1106"] = "tts-1-1106"; - OpenAIModel["tts-1-hd"] = "tts-1-hd"; - OpenAIModel["tts-1-hd-1106"] = "tts-1-hd-1106"; - OpenAIModel["whisper-1"] = "whisper-1"; -})(OpenAIModel || (OpenAIModel = {})); -class AIAssistant { - #apiKey; - #id; - #name; - get name() { return this.#name; } - #instructions; - #tools; - #model; - #fileIDs; - #metadata; - constructor(nameOrID, instructions, model = OpenAIModel["gpt-4-1106-preview"], { isUsingRetrieval, functionTools, file_ids, metadata } = {}) { - // Initialize private properties so TypeScript doesn't yell at me. - this.#id = ""; - this.#name = ""; - this.#instructions = instructions ?? ""; - this.#tools = []; - this.#model = model; - this.#fileIDs = file_ids ?? []; - this.#metadata = metadata ?? {}; - // Retrieve API key - const apiKey = U.getSetting("openAPIKey"); - if (!apiKey) { - throw new Error("API Key required in Settings to use AI features."); - } - this.#apiKey = apiKey; - // If instructions sent, we're creating a new Assistant. - if (instructions) { - this.#name = nameOrID; - if (isUsingRetrieval) { - this.#tools.push({ type: "retrieval" }); - } - if (functionTools && functionTools.length) { - this.#tools.push(...functionTools); - } - this.createAssistant(); - } - else { - // Otherwise, assume an ID was passed, and fetch the existing assistant. - this.#id = nameOrID; - this.retrieveAssistant(); - } - } - async createAssistant() { - // curl https://api.openai.com/v1/assistants \ - // -H "Content-Type: application/json" \ - // -H "Authorization: Bearer $OPENAI_API_KEY" \ - // -H "OpenAI-Beta: assistants=v1" \ - // -d '{ - // "instructions": "You are an HR bot, and you have access to files to answer employee questions about company policies.", - // "tools": [{"type": "retrieval"}], - // "model": "gpt-4", - // "file_ids": ["file-abc123"] - // }' - const fetchRequest = { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${this.#apiKey}`, - "OpenAI-Beta": "assistants=v1" - }, - body: JSON.stringify({ - name: this.#name, - instructions: this.#instructions, - tools: this.#tools, - model: this.#model, - file_ids: this.#fileIDs - }) - }; - eLog.checkLog3("BladesAssistant", "Fetch Request", fetchRequest); - // Send a POST request to the OpenAI API - const response = await fetch("https://api.openai.com/v1/assistants", fetchRequest); - // Check if the response status is not 200 (OK) - if (!response.ok) { - console.log("Failed AI Request:", JSON.parse(fetchRequest.body)); - // Throw an error with the status code - throw new Error(`OpenAI API request failed with status ${response.status}`); - } - // Parse the response body as JSON - const data = await response.json(); - fetchRequest.body = JSON.parse(fetchRequest.body); - eLog.checkLog3("BladesAI", "AI Query", { prompt: fetchRequest, response: data }); - this.#id = data.id; - } - async retrieveAssistant() { - // curl https://api.openai.com/v1/assistants/asst_abc123 \ - // -H "Content-Type: application/json" \ - // -H "Authorization: Bearer $OPENAI_API_KEY" \ - // -H "OpenAI-Beta: assistants=v1" - const fetchRequest = { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${this.#apiKey}`, - "OpenAI-Beta": "assistants=v1" - } - }; - // Send a POST request to the OpenAI API - const response = await fetch(`https://api.openai.com/v1/assistants/${this.#id}`, fetchRequest); - // Check if the response status is not 200 (OK) - if (!response.ok) { - // Throw an error with the status code - throw new Error(`OpenAI API request failed with status ${response.status}`); - } - // Parse the response body as JSON - const data = await response.json(); - eLog.checkLog3("BladesAI", "AI Query", { prompt: fetchRequest, response: data }); - this.#name = data.name; - this.#instructions = data.instructions; - this.#tools = data.tools; - this.#model = data.model; - this.#fileIDs = data.file_ids; - this.#metadata = data.metadata; - } -} -/** - * AI class for querying OpenAI API - */ -class BladesAI { - static async GetModels(isVerbose = false) { - const apiKey = U.getSetting("openAPIKey"); - if (!apiKey) { - throw new Error("You must configure your OpenAI API Key in Settings to use AI features."); - } - const fetchRequest = { - method: "GET", - headers: { - Authorization: `Bearer ${apiKey}` - } - }; - // Send a POST request to the OpenAI API - const response = await fetch("https://api.openai.com/v1/models", fetchRequest); - // Check if the response status is not 200 (OK) - if (!response.ok) { - // Throw an error with the status code - throw new Error(`OpenAI API request failed with status ${response.status}`); - } - // Parse the response body as JSON - const data = await response.json(); - // const modelKeys = data.map(({id}: {id: string}) => id); - // const modelData = data.map(({id: _id, ...mData}: Record) => mData); - const dataList = Object.fromEntries(data.map(({ id, ...mData }) => [id, mData])); - if (isVerbose) { - eLog.checkLog3("BladesAI", "Available Models", { dataList }); - } - } - apiKey; - model; - temperature = 0.5; - frequency_penalty = 0.8; - presence_penalty = 0.8; - systemMessage; - examplePrompts; - /** - * AI class constructor - * @param {BladesAI.Config} [config] Configuration settings for the API - */ - constructor(config) { - const apiKey = U.getSetting("openAPIKey"); - if (!apiKey) { - throw new Error("You must configure your OpenAI API Key in Settings to use AI features."); - } - this.model = U.getSetting("openAPIModelLevel"); - if (typeof this.model !== "number") { - eLog.error("BladesAI", "Set base AI quality in settings. Defaulting to lowest."); - this.model = 0; - } - this.apiKey = apiKey; - this.systemMessage = config.systemMessage; - this.examplePrompts = config.examplePrompts; - this.temperature = config.temperature ?? this.temperature; - this.frequency_penalty = config.frequency_penalty ?? this.frequency_penalty; - this.presence_penalty = config.presence_penalty ?? this.presence_penalty; - } - _initialMessages = []; - get initialMessages() { - if (this._initialMessages.length === 0) { - this._initialMessages.push({ - role: "system", - content: this.systemMessage - }); - for (const { human, ai } of this.examplePrompts) { - this._initialMessages.push({ - role: "user", - content: human - }); - this._initialMessages.push({ - role: "assistant", - content: ai - }); - } - } - return this._initialMessages; - } - prompts = {}; - responses = {}; - getResponse(queryID) { - return this.responses[queryID] ?? null; - } - hasQueried(queryID) { - return this.prompts[queryID] !== undefined; - } - /** - * Query OpenAI API - * @param {string} queryID A label for later retrieval of the query data - * @param {string} prompt The prompt to send to the API - * @param {number} [modelMod] Optional modifier to the base model level. - * If provided, the final model quality will be adjusted by this number. - * @param {boolean} [extendedContext=false] Optional flag to indicate whether to use extended context models. - * If true, extended context models are used; otherwise, base context models are used. - * @returns {Promise} The API response - */ - async query(queryID, prompt, modelMod, extendedContext = false) { - if (!prompt) { - return; - } - this.responses[queryID] = null; - const modelNum = typeof modelMod === "number" - ? U.clampNum(this.model + modelMod, [0, 2]) - : this.model; - const model = extendedContext - ? C.AI_MODELS.extendedContext[modelNum] - : C.AI_MODELS.baseContext[modelNum]; - const fetchRequest = { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${this.apiKey}` - }, - body: JSON.stringify({ - model, - temperature: this.temperature, - frequency_penalty: this.frequency_penalty, - presence_penalty: this.presence_penalty, - messages: [ - ...this.initialMessages, - { - role: "user", - content: prompt - } - ] - }) - }; - // EeLog.checkLog3("BladesAI", "Fetch Request", fetchRequest); - // Send a POST request to the OpenAI API - const response = await fetch("https://api.openai.com/v1/chat/completions", fetchRequest); - // { - // method: "POST", - // headers: { - // // The content type of the request - // "Content-Type": "application/json", - // // The authorization header with the API key - // Authorization: `Bearer ${this.apiKey}` - // }, - // body: JSON.stringify({ - // model, - // messages: [ - // ...this.initialMessages, - // { - // role: "user", - // content: prompt - // } - // ], - // // Maximum number of tokens in the output. Min: 1, Max: 4096 - // // max_tokens: 60, - // // Controls randomness. Higher values mean the model will take more risks. - // temperature: 0.5, // 0 to 2.0 - // /* The 'top_p' parameter is an alternative to 'temperature' for controlling the randomness of - // the AI's responses. It represents the cumulative probability and its value ranges from 0 to 1. - // A lower value makes the AI's responses more deterministic, while a higher value makes them - // more diverse and unpredictable. */ - // // top_p: 1, // 0 to 1 - // /* The 'frequency_penalty' parameter is used to penalize new tokens based on their frequency in - // the training set. Its value ranges from 0 to 1. A higher value means the AI is less likely to - // use common phrases from its training set, leading to more unique responses. A lower value - // means the AI is more likely to use common phrases, leading to more predictable responses. */ - // frequency_penalty: 0.8, // -2.0 to 2.0 - // /* The 'presence_penalty' parameter is used to penalize tokens (words or phrases) that are out - // of context. Its value ranges from 0 to 1. A higher value means the AI is less likely to - // include out-of-context tokens in its responses, leading to more coherent and contextually - // appropriate responses. A lower value means the AI is more likely to include out-of-context - // tokens, which can lead to more creative but potentially less coherent responses. */ - // presence_penalty: 0.8 // -2.0 to 2.0 - // }) - // } - // ); - // Check if the response status is not 200 (OK) - if (!response.ok) { - console.log("Failed AI Request:", JSON.parse(fetchRequest.body)); - // Throw an error with the status code - throw new Error(`OpenAI API request failed with status ${response.status}`); - } - // Parse the response body as JSON - const data = await response.json(); - fetchRequest.body = JSON.parse(fetchRequest.body); - eLog.checkLog3("BladesAI", "AI Query", { prompt: fetchRequest, response: data }); - this.responses[queryID] = data.choices[0].message.content; - return this.responses[queryID]; - } -} -export const AGENTS = { - GeneralContentGenerator: { - systemMessage: "You will act as a creative content generator for a game of Blades In The Dark set in the city of Duskvol. You will be prompted with some element of the game world (a location, a character, an event, a faction, a dilemma) in the form of a JSON object. Your job is to analyze the JSON object and replace any values that equal \"\" with original content of your own creation. Original content must meet these requirements: (A) it should align with and be consistent with the provided contextual information, as well as your broader understanding of the game's themes. (B) It should be presented in a format that matches (in length and in style) other entries for that particular value, examples of which will also be provided. (C) It should be creative, interesting, and daring: Be bold with your creativity. Specific context for this prompt is as follows:", - examplePrompts: [] - }, - NPCGenerator: { - systemMessage: "You will play the role of a \"creative content generator\" for random NPCs generated for the Blades In The Dark roleplaying system. When prompted with a description of a subject (an NPC, a category of NPCs, a faction, or a group of NPCs), you will respond with a pipe-delimited list of sixteen items, divided into four categories, prefacing each category with the associated header in square brackets: [5 KEYWORDS] Five one-word keywords describing the subject. [5 PHRASES] Five evocative phrases that could be used by a GM directly when narrating the subject during play. These should be extremely well-worded, very original, and packed with drama and evocative imagery. Be bold with your responses here. [3 QUIRKS/MOTIFFS] Three phrases describing potential quirks or motiffs that a GM could employ in a scene involving the subject. [3 PLOT HOOKS] Three plot hooks that could directly and specifically involve one or more of the PCs. The PCs are: (1) Alistair, full name Lord Alistair Bram Chesterfield, the crew's boss, a Spider with connections among the nobility; (2) High-Flyer, a former noble himself, now serving as the crew's Slide; (3) Jax, a stoic and laconic Hound with ties to the disenfranchised of Duskvol; (4) Ollie, the youngest of the crew at barely nineteen, a prodigy Leech with knowledge of alchemy and spark-craft, who grew up as an orphan in Duskvol's underground; (5) Wraith, the mysterious Lurk of the crew, who never speaks for reasons unknown; and (6) Spencer, the bookish Whisper of the crew, who harbors a secret fascination for demons and all things related to them.", - examplePrompts: [ - { - human: "The Billhooks, a hack-and-slash gang of toughened thugs. The Billhooks have a bloody reputation, often leaving the butchered corpses of their victims strewn about in a grisly display. Many wonder why the Bluecoats turn a blind eye to their savagery. Based out of their butcher shop headquarters, they are led by Tarvul, who is currently serving life in prison.", - ai: "[5 KEYWORDS]brutal|unrelenting|savage|fierce|unhinged|[5 PHRASES]blood-flecked, yellowed teeth|eyes that want to flay your skin from your bones|crooked leer like he's looking at his Judas goat|reek like a charnel house|gobbets of a meaty lunch still in his beard|[3 QUIRKS/MOTIFFS]always ready to wreck, vandalize or destroy something|relish in instilling fear in others|have a twisted sense of loyalty|[3 PLOT HOOKS]Tarvul hires the crew to start a war among his most promising underlings, intending to make whoever survives his successor|the Billhooks kidnap a member of High-Flyer's noble family|a Demon of Shadows promises Spencer the answer to three questions, in exchange for an artifact recently stolen by the Billhooks" - }, - { - human: "The hooded proprietor of a half-flooded grotto tavern near the docks. 'Strange passageways lead to stranger chambers beyond.' Vice Purveyor - Weird.", - ai: "[5 KEYWORDS]mysterious|cryptic|enigmatic|peculiar|shrouded|[5 PHRASES]a voice like wet burlap sliding over gravel|the flicker of torchlight dancing on the flooded floor|the scent of brackish water and old spices|a smile that hinted at a thousand secrets hidden in the shadows|hands gnarled as driftwood, eternally damp|[3 QUIRKS/MOTIFFS]has an uncanny knack for knowing patrons' darkest secrets without them telling him|never seems to sleep or leave the tavern, always there no matter what time you visit|always seen with a strange, luminescent creature that lives in one of the flooded chambers behind the bar|[3 PLOT HOOKS]Alistair hears rumors that this tavern is actually a front for a powerful secret society - perhaps they could be useful allies...or dangerous enemies.|The proprietor offers Ollie a rare alchemical ingredient - but it's not for sale. He'll only trade it for something equally valuable.|Wraith overhears whispers about a hidden chamber beneath the tavern where unimaginable treasures are kept." - }, - { - human: "Setarra, a Demon. Patient, Defiant, Ruthless, Cold", - ai: "[5 KEYWORDS]shadowy|sinister|unfathomable|enigmatic|tempting|[5 PHRASES]whispers that crawl under your skin|always watching, always plotting|in tones of silk and venom|intoxicating presence that draws you closer, despite your instincts urging you to run|eyes like black holes, swallowing all light around them|[3 QUIRKS/MOTIFFS]a disorienting mist clings to her form, obscuring her true shape|casually discusses the devastating acts of capricious revenge she has taken on those who crossed her|never forgets a slight or betrayal, no matter how small or insignificant it may seem at the time|[3 PLOT HOOKS]seeks revenge against Alistair for meddling in her affairs years ago|makes Ollie an offer he can't refuse: unlimited access to forbidden alchemical knowledge in exchange for a single favor, to be called in at some future time|tempts Spencer with forbidden knowledge about demons, promising answers to all their questions if they perform a dangerous ritual" - } - /* - "brutish,merciless,terrifying,savage,loyal, - bloody tools,hulking figures,blood-soaked alleys,grimy aprons,grisly displays, - never clean their tools,relishes the terror they inspire,occasional laughter among them, - recruiting a PC to perform a job for them from prison, - the gang blames one of the PCs for Tarvul's imprisonment and they're out for revenge" */ - ] - }, - ConsequenceAdjuster: { - systemMessage: "You will act as a \"Setback Adjuster\" for a game of Blades In The Dark. You will be prompted with a short phrase describing an injury, lasting consequence or other setback. Your job is to respond with a pipe-delimited list of three possible alternative consequences that are less severe by one level, using the following scale as a rough guide: Level 1 = Lesser (e.g. 'Battered', 'Drained', 'Distracted', 'Scared', 'Confused'), Level 2 = Moderate (e.g. 'Exhausted', 'Deep Cut to Arm', 'Concussion', 'Panicked', 'Seduced'), Level 3 = Severe (e.g. 'Impaled', 'Broken Leg', 'Shot In Chest', 'Badly Burned', 'Terrified'), Level 4 = Fatal or Ruinous (e.g. 'Impaled Through Heart', 'Electrocuted', 'Headquarters Burned to the Ground'). So, if you determine that the consequence described in the prompt is severity level 3, you should respond with three narratively similar consequences that are severity level 2. Your three suggestions should be different from each other, but they should all logically follow from the initial harm described: You should not introduce new facts or make assumptions that are not indicated in the initial prompt. The consequences you suggest should always describe a NEGATIVE setback or complication, just one that is less severe than the one described in the prompt.", - examplePrompts: [ - { human: "Shattered Right Leg", ai: "Fractured Right Ankle|Dislocated Knee|Broken Foot" }, - { human: "Soul Destroyed", ai: "Fully Corrupted|Lost In Darkness|Spirit Broken" }, - { human: "Humiliated", ai: "Embarrassed|Momentarily Off-Balance|Enraged" }, - { human: "She Escapes!", ai: "She Spots a Means of Escape|She Puts More Distance Between You|She Stops to Gloat" }, - { human: "The fire spreads to the hostages.", ai: "The fire approaches the hostages.|The hostages must be evacuated.|The fire billows choking black smoke." } - ] - } -}; -export default BladesAI; -export { AIAssistant }; diff --git a/module/core/constants.js b/module/core/constants.js deleted file mode 100644 index e40b906b..00000000 --- a/module/core/constants.js +++ /dev/null @@ -1,4786 +0,0 @@ -// #region ENUMS ~ -export var BladesPermissions; -(function (BladesPermissions) { - BladesPermissions[BladesPermissions["NONE"] = CONST.DOCUMENT_PERMISSION_LEVELS.NONE] = "NONE"; - BladesPermissions[BladesPermissions["BASIC"] = CONST.DOCUMENT_PERMISSION_LEVELS.LIMITED] = "BASIC"; - BladesPermissions[BladesPermissions["FULL"] = CONST.DOCUMENT_PERMISSION_LEVELS.OBSERVER] = "FULL"; - BladesPermissions[BladesPermissions["OWNER"] = CONST.DOCUMENT_PERMISSION_LEVELS.OWNER] = "OWNER"; -})(BladesPermissions || (BladesPermissions = {})); -export var BladesActorType; -(function (BladesActorType) { - BladesActorType["pc"] = "pc"; - BladesActorType["npc"] = "npc"; - BladesActorType["crew"] = "crew"; - BladesActorType["faction"] = "faction"; -})(BladesActorType || (BladesActorType = {})); -export var BladesItemType; -(function (BladesItemType) { - BladesItemType["ability"] = "ability"; - BladesItemType["background"] = "background"; - BladesItemType["clock_keeper"] = "clock_keeper"; - BladesItemType["cohort_gang"] = "cohort_gang"; - BladesItemType["cohort_expert"] = "cohort_expert"; - BladesItemType["crew_ability"] = "crew_ability"; - BladesItemType["crew_reputation"] = "crew_reputation"; - BladesItemType["crew_playbook"] = "crew_playbook"; - BladesItemType["crew_upgrade"] = "crew_upgrade"; - BladesItemType["feature"] = "feature"; - BladesItemType["gm_tracker"] = "gm_tracker"; - BladesItemType["heritage"] = "heritage"; - BladesItemType["gear"] = "gear"; - BladesItemType["playbook"] = "playbook"; - BladesItemType["preferred_op"] = "preferred_op"; - BladesItemType["stricture"] = "stricture"; - BladesItemType["vice"] = "vice"; - BladesItemType["project"] = "project"; - BladesItemType["ritual"] = "ritual"; - BladesItemType["design"] = "design"; - BladesItemType["location"] = "location"; - BladesItemType["score"] = "score"; -})(BladesItemType || (BladesItemType = {})); -export var PrereqType; -(function (PrereqType) { - PrereqType["HasActiveItem"] = "HasActiveItem"; - PrereqType["HasActiveItemsByTag"] = "HasActiveItemByTag"; - PrereqType["AdvancedPlaybook"] = "AdvancedPlaybook"; - PrereqType["HasAllTags"] = "HasAllTags"; - PrereqType["HasAnyTag"] = "HasAnyTag"; - PrereqType["Not_HasActiveItem"] = "Not_HasActiveItem"; - PrereqType["Not_HasActiveItemsByTag"] = "Not_HasActiveItemsByTag"; - PrereqType["Not_AdvancedPlaybook"] = "Not_AdvancedPlaybook"; - PrereqType["Not_HasAllTags"] = "Not_HasAllTags"; - PrereqType["Not_HasAnyTag"] = "Not_HasAnyTag"; -})(PrereqType || (PrereqType = {})); -export var ClockColor; -(function (ClockColor) { - ClockColor["yellow"] = "yellow"; - ClockColor["red"] = "red"; - ClockColor["white"] = "white"; - ClockColor["cyan"] = "cyan"; -})(ClockColor || (ClockColor = {})); -export var ClockDisplayContext; -(function (ClockDisplayContext) { - ClockDisplayContext["overlay"] = "overlay"; - ClockDisplayContext["pcSheet"] = "pcSheet"; - ClockDisplayContext["factionSheet"] = "factionSheet"; - ClockDisplayContext["projectSheet"] = "projectSheet"; - ClockDisplayContext["scoreSheet"] = "scoreSheet"; - ClockDisplayContext["rollCollab"] = "rollCollab"; - ClockDisplayContext["chatMessage"] = "chatMessage"; -})(ClockDisplayContext || (ClockDisplayContext = {})); -export var ClockKeyUpdateAction; -(function (ClockKeyUpdateAction) { - ClockKeyUpdateAction["RenderAll"] = "RenderAll"; - ClockKeyUpdateAction["RenderNonClockKeeper"] = "RenderNonClockKeeper"; - ClockKeyUpdateAction["RenderNone"] = "RenderNone"; -})(ClockKeyUpdateAction || (ClockKeyUpdateAction = {})); -export var ClockKeyDisplayMode; -(function (ClockKeyDisplayMode) { - ClockKeyDisplayMode["full"] = "full"; - ClockKeyDisplayMode["clocks"] = "clocks"; - ClockKeyDisplayMode["activeClocks"] = "activeClocks"; - ClockKeyDisplayMode["presentCurrentClock"] = "presentCurrentClock"; - ClockKeyDisplayMode["present0"] = "present0"; - ClockKeyDisplayMode["present1"] = "present1"; - ClockKeyDisplayMode["present2"] = "present2"; - ClockKeyDisplayMode["present3"] = "present3"; - ClockKeyDisplayMode["present4"] = "present4"; - ClockKeyDisplayMode["present5"] = "present5"; -})(ClockKeyDisplayMode || (ClockKeyDisplayMode = {})); -export var BladesNoticeType; -(function (BladesNoticeType) { - BladesNoticeType["push"] = "push"; -})(BladesNoticeType || (BladesNoticeType = {})); -export var District; -(function (District) { - District["Barrowcleft"] = "Barrowcleft"; - District["Brightstone"] = "Brightstone"; - District["Charhollow"] = "Charhollow"; - District["Charterhall"] = "Charterhall"; - District["Coalridge"] = "Coalridge"; - District["Crows Foot"] = "Crows Foot"; - District["The Docks"] = "The Docks"; - District["Dunslough"] = "Dunslough"; - District["Nightmarket"] = "Nightmarket"; - District["Silkshore"] = "Silkshore"; - District["Six Towers"] = "Six Towers"; - District["Whitecrown"] = "Whitecrown"; - District["Gaddoc Station"] = "Gaddoc Station"; - District["The Lost District"] = "The Lost District"; - District["The Void Sea"] = "The Void Sea"; - District["Ironhook Prison"] = "Ironhook Prison"; - District["Old North Port"] = "Old North Port"; - District["Deathlands"] = "Deathlands"; -})(District || (District = {})); -export var MainDistrict; -(function (MainDistrict) { - MainDistrict["Barrowcleft"] = "Barrowcleft"; - MainDistrict["Brightstone"] = "Brightstone"; - MainDistrict["Charhollow"] = "Charhollow"; - MainDistrict["Charterhall"] = "Charterhall"; - MainDistrict["Coalridge"] = "Coalridge"; - MainDistrict["Crows Foot"] = "Crows Foot"; - MainDistrict["The Docks"] = "The Docks"; - MainDistrict["Dunslough"] = "Dunslough"; - MainDistrict["Nightmarket"] = "Nightmarket"; - MainDistrict["Silkshore"] = "Silkshore"; - MainDistrict["Six Towers"] = "Six Towers"; - MainDistrict["Whitecrown"] = "Whitecrown"; -})(MainDistrict || (MainDistrict = {})); -export var OtherDistrict; -(function (OtherDistrict) { - OtherDistrict["Gaddoc Station"] = "Gaddoc Station"; - OtherDistrict["The Lost District"] = "The Lost District"; - OtherDistrict["The Void Sea"] = "The Void Sea"; - OtherDistrict["Ironhook Prison"] = "Ironhook Prison"; - OtherDistrict["Old North Port"] = "Old North Port"; - OtherDistrict["Deathlands"] = "Deathlands"; -})(OtherDistrict || (OtherDistrict = {})); -export var AttributeTrait; -(function (AttributeTrait) { - AttributeTrait["insight"] = "insight"; - AttributeTrait["prowess"] = "prowess"; - AttributeTrait["resolve"] = "resolve"; -})(AttributeTrait || (AttributeTrait = {})); -export var InsightActions; -(function (InsightActions) { - InsightActions["hunt"] = "hunt"; - InsightActions["study"] = "study"; - InsightActions["survey"] = "survey"; - InsightActions["tinker"] = "tinker"; -})(InsightActions || (InsightActions = {})); -export var ProwessActions; -(function (ProwessActions) { - ProwessActions["finesse"] = "finesse"; - ProwessActions["prowl"] = "prowl"; - ProwessActions["skirmish"] = "skirmish"; - ProwessActions["wreck"] = "wreck"; -})(ProwessActions || (ProwessActions = {})); -export var ResolveActions; -(function (ResolveActions) { - ResolveActions["attune"] = "attune"; - ResolveActions["command"] = "command"; - ResolveActions["consort"] = "consort"; - ResolveActions["sway"] = "sway"; -})(ResolveActions || (ResolveActions = {})); -export var ActionTrait; -(function (ActionTrait) { - ActionTrait["hunt"] = "hunt"; - ActionTrait["study"] = "study"; - ActionTrait["survey"] = "survey"; - ActionTrait["tinker"] = "tinker"; - ActionTrait["finesse"] = "finesse"; - ActionTrait["prowl"] = "prowl"; - ActionTrait["skirmish"] = "skirmish"; - ActionTrait["wreck"] = "wreck"; - ActionTrait["attune"] = "attune"; - ActionTrait["command"] = "command"; - ActionTrait["consort"] = "consort"; - ActionTrait["sway"] = "sway"; -})(ActionTrait || (ActionTrait = {})); -export var DowntimeAction; -(function (DowntimeAction) { - DowntimeAction["AcquireAsset"] = "AcquireAsset"; - DowntimeAction["IndulgeVice"] = "IndulgeVice"; - DowntimeAction["LongTermProject"] = "LongTermProject"; - DowntimeAction["Recover"] = "Recover"; - DowntimeAction["ReduceHeat"] = "ReduceHeat"; - DowntimeAction["Train"] = "Train"; -})(DowntimeAction || (DowntimeAction = {})); -export var RollPermissions; -(function (RollPermissions) { - RollPermissions["Primary"] = "Primary"; - RollPermissions["Observer"] = "Observer"; - RollPermissions["GM"] = "GM"; - RollPermissions["Participant"] = "Participant"; -})(RollPermissions || (RollPermissions = {})); -export var RollType; -(function (RollType) { - RollType["Action"] = "Action"; - RollType["Resistance"] = "Resistance"; - RollType["Fortune"] = "Fortune"; - RollType["IndulgeVice"] = "IndulgeVice"; -})(RollType || (RollType = {})); -export var RollSubType; -(function (RollSubType) { - RollSubType["Incarceration"] = "Incarceration"; - RollSubType["Engagement"] = "Engagement"; - RollSubType["GatherInfo"] = "GatherInfo"; - RollSubType["GroupLead"] = "GroupLead"; - RollSubType["GroupParticipant"] = "GroupParticipant"; -})(RollSubType || (RollSubType = {})); -export var RollModType; -(function (RollModType) { - RollModType["general"] = "general"; - RollModType["harm"] = "harm"; - RollModType["teamwork"] = "teamwork"; - RollModType["ability"] = "ability"; - RollModType["gear"] = "gear"; - RollModType["crew_ability"] = "crew_ability"; - RollModType["crew_upgrade"] = "crew_upgrade"; - RollModType["advantage"] = "advantage"; - RollModType["disadvantage"] = "disadvantage"; -})(RollModType || (RollModType = {})); -export var ConsequenceType; -(function (ConsequenceType) { - ConsequenceType["ReducedEffect"] = "ReducedEffect"; - ConsequenceType["ComplicationMinor"] = "ComplicationMinor"; - ConsequenceType["ComplicationMajor"] = "ComplicationMajor"; - ConsequenceType["ComplicationSerious"] = "ComplicationSerious"; - ConsequenceType["LostOpportunity"] = "LostOpportunity"; - ConsequenceType["WorsePosition"] = "WorsePosition"; - ConsequenceType["InsightHarm1"] = "InsightHarm1"; - ConsequenceType["InsightHarm2"] = "InsightHarm2"; - ConsequenceType["InsightHarm3"] = "InsightHarm3"; - ConsequenceType["InsightHarm4"] = "InsightHarm4"; - ConsequenceType["ProwessHarm1"] = "ProwessHarm1"; - ConsequenceType["ProwessHarm2"] = "ProwessHarm2"; - ConsequenceType["ProwessHarm3"] = "ProwessHarm3"; - ConsequenceType["ProwessHarm4"] = "ProwessHarm4"; - ConsequenceType["ResolveHarm1"] = "ResolveHarm1"; - ConsequenceType["ResolveHarm2"] = "ResolveHarm2"; - ConsequenceType["ResolveHarm3"] = "ResolveHarm3"; - ConsequenceType["ResolveHarm4"] = "ResolveHarm4"; - ConsequenceType["None"] = "None"; -})(ConsequenceType || (ConsequenceType = {})); -export var RollModStatus; -(function (RollModStatus) { - RollModStatus["Hidden"] = "Hidden"; - RollModStatus["ForcedOff"] = "ForcedOff"; - RollModStatus["ToggledOff"] = "ToggledOff"; - RollModStatus["ToggledOn"] = "ToggledOn"; - RollModStatus["ForcedOn"] = "ForcedOn"; - RollModStatus["Dominant"] = "Dominant"; -})(RollModStatus || (RollModStatus = {})); -export var RollModSection; -(function (RollModSection) { - RollModSection["roll"] = "roll"; - RollModSection["position"] = "position"; - RollModSection["effect"] = "effect"; - RollModSection["result"] = "result"; - RollModSection["after"] = "after"; -})(RollModSection || (RollModSection = {})); -export var Position; -(function (Position) { - Position["desperate"] = "desperate"; - Position["risky"] = "risky"; - Position["controlled"] = "controlled"; -})(Position || (Position = {})); -export var Effect; -(function (Effect) { - Effect["zero"] = "zero"; - Effect["limited"] = "limited"; - Effect["standard"] = "standard"; - Effect["great"] = "great"; - Effect["extreme"] = "extreme"; -})(Effect || (Effect = {})); -export var Factor; -(function (Factor) { - Factor["tier"] = "tier"; - Factor["quality"] = "quality"; - Factor["scale"] = "scale"; - Factor["magnitude"] = "magnitude"; -})(Factor || (Factor = {})); -export var RollResult; -(function (RollResult) { - RollResult["critical"] = "critical"; - RollResult["success"] = "success"; - RollResult["partial"] = "partial"; - RollResult["fail"] = "fail"; -})(RollResult || (RollResult = {})); -export var RollPhase; -(function (RollPhase) { - // Collaboration: Before GM toggles "Roll" button for player to click. - RollPhase["Collaboration"] = "Collaboration"; - // AwaitingRoll: Waiting for player to click "ROLL" - RollPhase["AwaitingRoll"] = "AwaitingRoll"; - // AwaitingConsequences: Waiting for player to resist or accept consequences - // in chat. Only moves to 'Complete' when all consequences - // have been accepted or negated. (Resisted consequences - // must still be accepted, since player could elect to use armor.) - RollPhase["AwaitingConsequences"] = "AwaitingConsequences"; - // Complete: Roll finished. - RollPhase["Complete"] = "Complete"; -})(RollPhase || (RollPhase = {})); -export var Harm; -(function (Harm) { - Harm["Weakened"] = "Weakened"; - Harm["Impaired"] = "Impaired"; - Harm["Broken"] = "Broken"; - Harm["Dead"] = "Dead"; -})(Harm || (Harm = {})); -export var Vice; -(function (Vice) { - Vice["Faith"] = "Faith"; - Vice["Gambling"] = "Gambling"; - Vice["Luxury"] = "Luxury"; - Vice["Obligation"] = "Obligation"; - Vice["Pleasure"] = "Pleasure"; - Vice["Stupor"] = "Stupor"; - Vice["Weird"] = "Weird"; - Vice["Worship"] = "Worship"; - Vice["Life_Essence"] = "Life_Essence"; - Vice["Living_Essence"] = "Living_Essence"; - Vice["Electroplasmic_Power"] = "Electroplasmic_Power"; - Vice["Servitude"] = "Servitude"; -})(Vice || (Vice = {})); -export var Playbook; -(function (Playbook) { - Playbook["Cutter"] = "Cutter"; - Playbook["Hound"] = "Hound"; - Playbook["Leech"] = "Leech"; - Playbook["Lurk"] = "Lurk"; - Playbook["Slide"] = "Slide"; - Playbook["Spider"] = "Spider"; - Playbook["Whisper"] = "Whisper"; - Playbook["Vampire"] = "Vampire"; - Playbook["Hull"] = "Hull"; - Playbook["Ghost"] = "Ghost"; - Playbook["Assassins"] = "Assassins"; - Playbook["Bravos"] = "Bravos"; - Playbook["Cult"] = "Cult"; - Playbook["Hawkers"] = "Hawkers"; - Playbook["Shadows"] = "Shadows"; - Playbook["Smugglers"] = "Smugglers"; - Playbook["Vigilantes"] = "Vigilantes"; -})(Playbook || (Playbook = {})); -export var AdvancementPoint; -(function (AdvancementPoint) { - AdvancementPoint["UpgradeOrAbility"] = "UpgradeOrAbility"; - AdvancementPoint["Ability"] = "Ability"; - AdvancementPoint["Upgrade"] = "Upgrade"; - AdvancementPoint["Cohort"] = "Cohort"; - AdvancementPoint["CohortType"] = "CohortType"; - AdvancementPoint["GeneralAction"] = "GeneralAction"; - AdvancementPoint["GeneralInsight"] = "GeneralInsight"; - AdvancementPoint["GeneralProwess"] = "GeneralProwess"; - AdvancementPoint["GeneralResolve"] = "GeneralResolve"; - AdvancementPoint["hunt"] = "hunt"; - AdvancementPoint["study"] = "study"; - AdvancementPoint["survey"] = "survey"; - AdvancementPoint["tinker"] = "tinker"; - AdvancementPoint["finesse"] = "finesse"; - AdvancementPoint["prowl"] = "prowl"; - AdvancementPoint["skirmish"] = "skirmish"; - AdvancementPoint["wreck"] = "wreck"; - AdvancementPoint["attune"] = "attune"; - AdvancementPoint["command"] = "command"; - AdvancementPoint["consort"] = "consort"; - AdvancementPoint["sway"] = "sway"; -})(AdvancementPoint || (AdvancementPoint = {})); -export var BladesPhase; -(function (BladesPhase) { - BladesPhase["CharGen"] = "CharGen"; - BladesPhase["Freeplay"] = "Freeplay"; - BladesPhase["Score"] = "Score"; - BladesPhase["Downtime"] = "Downtime"; -})(BladesPhase || (BladesPhase = {})); -export var Tag; -(function (Tag) { - let System; - (function (System) { - System["Archived"] = "Archived"; - System["Featured"] = "Featured"; - System["Hidden"] = "Hidden"; - System["MultiplesOK"] = "MultiplesOK"; - })(System = Tag.System || (Tag.System = {})); - let Gear; - (function (Gear) { - Gear["Fine"] = "Fine"; - Gear["General"] = "General"; - Gear["Advanced"] = "Advanced"; - Gear["Upgraded"] = "Upgraded"; - })(Gear = Tag.Gear || (Tag.Gear = {})); - let PC; - (function (PC) { - PC["Member"] = "Member"; - PC["CharacterCrew"] = "CharacterCrew"; - PC["ActivePC"] = "ActivePC"; - PC["Small"] = "Small"; - PC["Medium"] = "Medium"; - PC["Large"] = "Large"; - PC["CanHeal"] = "CanHeal"; - })(PC = Tag.PC || (Tag.PC = {})); - let Invention; - (function (Invention) { - Invention["Arcane"] = "Arcane"; - Invention["SparkCraft"] = "SparkCraft"; - Invention["Alchemical"] = "Alchemical"; - Invention["Mundane"] = "Mundane"; - Invention["Ritual"] = "Ritual"; // Rituals - })(Invention = Tag.Invention || (Tag.Invention = {})); - let GearCategory; - (function (GearCategory) { - GearCategory["ArcaneImplement"] = "ArcaneImplement"; - GearCategory["Document"] = "Document"; - GearCategory["GearKit"] = "GearKit"; - GearCategory["SubterfugeSupplies"] = "SubterfugeSupplies"; - GearCategory["Tool"] = "Tool"; - GearCategory["Weapon"] = "Weapon"; - })(GearCategory = Tag.GearCategory || (Tag.GearCategory = {})); - let NPC; - (function (NPC) { - NPC["Acquaintance"] = "Acquaintance"; - NPC["VicePurveyor"] = "VicePurveyor"; - NPC["CanHeal"] = "CanHeal"; - })(NPC = Tag.NPC || (Tag.NPC = {})); - let GangType; - (function (GangType) { - GangType["Thugs"] = "Thugs"; - GangType["Rooks"] = "Rooks"; - GangType["Adepts"] = "Adepts"; - GangType["Rovers"] = "Rovers"; - GangType["Skulks"] = "Skulks"; - GangType["Vehicle"] = "Vehicle"; - })(GangType = Tag.GangType || (Tag.GangType = {})); -})(Tag || (Tag = {})); -// #endregion -// #region 'C' CONSTANTS DEFINITIONS ~ -const C = { - SYSTEM_ID: "eunos-blades", - SYSTEM_NAME: "Euno's Blades", - SYSTEM_FULL_NAME: "Euno's Blades In The Dark", - TEMPLATE_ROOT: "systems/eunos-blades/templates", - AI_MODELS: { - baseContext: [ - "babbage-002", - "gpt-3.5-turbo", - "gpt-4" - ], - extendedContext: [ - "gpt-3.5-turbo-16k", - "gpt-3.5-turbo-16k", - "gpt-4-32k" - ] - }, - MIN_MOUSE_MOVEMENT_THRESHOLD: 2000, - AI_FILE_IDS: { - BladesPDF: "file-n72HTTNwt051piPbswQ8isUa" - }, - ClockKeySquareSize: 100, - DowntimeActionDisplay: { - [DowntimeAction.AcquireAsset]: "Acquire an Asset", - [DowntimeAction.IndulgeVice]: "Indulge Your Vice", - [DowntimeAction.LongTermProject]: "Work on a Project", - [DowntimeAction.Recover]: "Heal", - [DowntimeAction.ReduceHeat]: "Reduce the Crew's Heat", - [DowntimeAction.Train]: "Train" - }, - ConsequenceValues: { - [ConsequenceType.ReducedEffect]: undefined, - [ConsequenceType.LostOpportunity]: 2, - [ConsequenceType.WorsePosition]: undefined, - [ConsequenceType.None]: 0, - [ConsequenceType.InsightHarm4]: 4, - [ConsequenceType.InsightHarm3]: 3, - [ConsequenceType.InsightHarm2]: 2, - [ConsequenceType.InsightHarm1]: 1, - [ConsequenceType.ProwessHarm4]: 4, - [ConsequenceType.ProwessHarm3]: 3, - [ConsequenceType.ProwessHarm2]: 2, - [ConsequenceType.ProwessHarm1]: 1, - [ConsequenceType.ResolveHarm4]: 4, - [ConsequenceType.ResolveHarm3]: 3, - [ConsequenceType.ResolveHarm2]: 2, - [ConsequenceType.ResolveHarm1]: 1, - [ConsequenceType.ComplicationSerious]: 3, - [ConsequenceType.ComplicationMajor]: 2, - [ConsequenceType.ComplicationMinor]: 1 - }, - ResistedConsequenceTypes: { - [ConsequenceType.None]: [], - [ConsequenceType.InsightHarm4]: [ConsequenceType.InsightHarm3], - [ConsequenceType.InsightHarm3]: [ConsequenceType.InsightHarm2], - [ConsequenceType.InsightHarm2]: [ConsequenceType.InsightHarm1], - [ConsequenceType.InsightHarm1]: [ConsequenceType.None], - [ConsequenceType.ProwessHarm4]: [ConsequenceType.ProwessHarm3], - [ConsequenceType.ProwessHarm3]: [ConsequenceType.ProwessHarm2], - [ConsequenceType.ProwessHarm2]: [ConsequenceType.ProwessHarm1], - [ConsequenceType.ProwessHarm1]: [ConsequenceType.None], - [ConsequenceType.ResolveHarm4]: [ConsequenceType.ResolveHarm3], - [ConsequenceType.ResolveHarm3]: [ConsequenceType.ResolveHarm2], - [ConsequenceType.ResolveHarm2]: [ConsequenceType.ResolveHarm1], - [ConsequenceType.ResolveHarm1]: [ConsequenceType.None], - [ConsequenceType.ComplicationSerious]: [ConsequenceType.ComplicationMajor], - [ConsequenceType.ComplicationMajor]: [ConsequenceType.ComplicationMinor], - [ConsequenceType.ComplicationMinor]: [ConsequenceType.None] - }, - ConsequenceDisplay: { - [ConsequenceType.ReducedEffect]: "Reduced Effect", - [ConsequenceType.ComplicationMinor]: "Minor Complication", - [ConsequenceType.ComplicationMajor]: "Major Complication", - [ConsequenceType.ComplicationSerious]: "Serious Complication", - [ConsequenceType.LostOpportunity]: "Lost Opportunity", - [ConsequenceType.WorsePosition]: "Worse Position", - [ConsequenceType.InsightHarm1]: "Level 1 Harm (Lesser)", - [ConsequenceType.InsightHarm2]: "Level 2 Harm (Moderate)", - [ConsequenceType.InsightHarm3]: "Level 3 Harm (Severe)", - [ConsequenceType.InsightHarm4]: "Level 4 Harm (FATAL)", - [ConsequenceType.ProwessHarm1]: "Level 1 Harm (Lesser)", - [ConsequenceType.ProwessHarm2]: "Level 2 Harm (Moderate)", - [ConsequenceType.ProwessHarm3]: "Level 3 Harm (Severe)", - [ConsequenceType.ProwessHarm4]: "Level 4 Harm (FATAL)", - [ConsequenceType.ResolveHarm1]: "Level 1 Harm (Lesser)", - [ConsequenceType.ResolveHarm2]: "Level 2 Harm (Moderate)", - [ConsequenceType.ResolveHarm3]: "Level 3 Harm (Severe)", - [ConsequenceType.ResolveHarm4]: "Level 4 Harm (FATAL)", - [ConsequenceType.None]: "None" - }, - ConsequenceIcons: { - [ConsequenceType.ReducedEffect]: "reduced-effect", - [ConsequenceType.ComplicationMinor]: "complication-minor", - [ConsequenceType.ComplicationMajor]: "complication-major", - [ConsequenceType.ComplicationSerious]: "complication-serious", - [ConsequenceType.LostOpportunity]: "lost-opportunity", - [ConsequenceType.WorsePosition]: "worse-position", - [ConsequenceType.InsightHarm1]: "harm-insight-1", - [ConsequenceType.InsightHarm2]: "harm-insight-2", - [ConsequenceType.InsightHarm3]: "harm-insight-3", - [ConsequenceType.InsightHarm4]: "harm-insight-4", - [ConsequenceType.ProwessHarm1]: "harm-prowess-1", - [ConsequenceType.ProwessHarm2]: "harm-prowess-2", - [ConsequenceType.ProwessHarm3]: "harm-prowess-3", - [ConsequenceType.ProwessHarm4]: "harm-prowess-4", - [ConsequenceType.ResolveHarm1]: "harm-resolve-1", - [ConsequenceType.ResolveHarm2]: "harm-resolve-2", - [ConsequenceType.ResolveHarm3]: "harm-resolve-3", - [ConsequenceType.ResolveHarm4]: "harm-resolve-4", - [ConsequenceType.None]: "" - }, - RollResultDescriptions: { - [Position.controlled]: { - [RollResult.critical]: "You critically succeed from a controlled position!", - [RollResult.success]: "You fully succeed from a controlled position!", - [RollResult.partial]: "You partially succeed from a controlled position!", - [RollResult.fail]: "You fail from a controlled position!" - }, - [Position.risky]: { - [RollResult.critical]: "You critically succeed from a risky position!", - [RollResult.success]: "You fully succeed from a risky position!", - [RollResult.partial]: "You partially succeed from a risky position!", - [RollResult.fail]: "You fail from a risky position!" - }, - [Position.desperate]: { - [RollResult.critical]: "You critically succeed from a desperate position!", - [RollResult.success]: "You fully succeed from a desperate position!", - [RollResult.partial]: "You partially succeed from a desperate position!", - [RollResult.fail]: "You fail from a desperate position!" - } - }, - // - Colors: { - bWHITE: "rgba(255, 255, 255, 1)", - WHITE: "rgba(200, 200, 200, 1)", - bGREY: "rgba(170, 170, 170, 1)", - GREY: "rgba(119, 119, 119, 1)", - dGREY: "rgba(68, 68, 68, 1)", - BLACK: "rgba(32, 32, 32, 1)", - dBLACK: "rgba(0, 0, 0, 1)", - bGOLD: "rgba(255,216, 44, 1)", - GOLD: "rgba(215,175, 0, 1)", - dGOLD: "rgba(165,134, 0, 1)", - ddGOLD: "rgba(103, 83, 0, 1)", - bRED: "rgba(255, 0, 0, 1)", - RED: "rgba(200, 0, 0, 1)", - dRED: "rgba(150, 0, 0, 1)", - ddRED: "rgba(50, 0, 0, 1)", - bBLUE: "rgba( 0,224,224, 1)", - BLUE: "rgba(52,213,213, 1)", - dBLUE: "rgba(0,118,118, 1)", - ddBLUE: "rgba(0, 77, 77, 1)" - }, - // ClockKeyPositions: { - // elemSquareSize: 100, - // 0: { - // keyDimensions: {width: 0, height: 0}, - // keyCenter: {x: 0, y: 0}, - // clocksCenter: {x: 0, y: 0}, - // clocksCenterDimensions: {width: 0, height: 0}, - // clocks: {} - // }, - // 1: { - // keyDimensions: {width: 230, height: 836}, - // keyCenter: {x: 115, y: 418}, - // clocksCenter: {x: 111.011, y: 108.5}, - // clocksCenterDimensions: {width: 169, height: 169}, - // clocks: { - // 0: {x: 111.011, y: 108.5, size: 169} - // } - // }, - // 2: { - // keyDimensions: {width: 202, height: 625}, - // keyCenter: {x: 101, y: 312}, - // clocksCenter: {x: 101, y: 189}, - // clocksCenterDimensions: {width: 110, height: 290}, - // clocks: { - // 0: {x: 101, y: 99, size: 108}, - // 1: {x: 101, y: 279, size: 108} - // } - // }, - // 3: { - // keyDimensions: {width: 280, height: 915}, - // keyCenter: {x: 140, y: 457}, - // clocksCenter: {x: 140, y: 169}, - // clocksCenterDimensions: {width: 242, height: 222}, - // clocks: { - // 0: {x: 140, y: 99, size: 108}, - // 1: {x: 74, y: 211, size: 108}, - // 2: {x: 206, y: 211, size: 108} - // } - // }, - // 4: { - // keyDimensions: {width: 376, height: 1140}, - // keyCenter: {x: 188, y: 570}, - // clocksCenter: {x: 188, y: 185}, - // clocksCenterDimensions: {width: 284, height: 282}, - // clocks: { - // 0: {x: 188, y: 99, size: 108}, // yTop = 45 - // 1: {x: 101, y: 185, size: 108}, - // 2: {x: 275, y: 185, size: 108}, - // 3: {x: 188, y: 273, size: 108} // yBottom = 327 - // } - // }, - // 5: { - // keyDimensions: {width: 376, height: 1140}, - // keyCenter: {x: 188, y: 570}, - // clocksCenter: {x: 188, y: 185}, - // clocksCenterDimensions: {width: 284, height: 384}, - // clocks: { - // 0: {x: 188, y: 99, size: 108}, // yTop = 45 - // 1: {x: 101, y: 185, size: 108}, - // 2: {x: 275, y: 185, size: 108}, - // 3: {x: 188, y: 273, size: 108}, - // 4: {x: 188, y: 452, size: 108} // yBottom = 506 - // } - // }, - // 6: { - // keyDimensions: {width: 376, height: 1140}, - // keyCenter: {x: 188, y: 570}, - // clocksCenter: {x: 188, y: 391}, - // clocksCenterDimensions: {width: 284, height: 692}, - // clocks: { - // 0: {x: 188, y: 99, size: 108}, // yTop = 45 - // 1: {x: 101, y: 185, size: 108}, - // 2: {x: 275, y: 185, size: 108}, - // 3: {x: 188, y: 273, size: 108}, - // 4: {x: 188, y: 452, size: 108}, - // 5: {x: 188, y: 683, size: 108} // yBottom = 737 - // } - // } - // }, - Loadout: { - selections: [ - { value: "Light", display: "Light" }, - { value: "Normal", display: "Normal" }, - { value: "Heavy", display: "Heavy" } - ], - levels: ["BITD.Light", "BITD.Normal", "BITD.Heavy", "BITD.Encumbered", "BITD.OverMax"] - }, - AttributeTooltips: { - [AttributeTrait.insight]: "

Resists consequences from deception or understanding

", - [AttributeTrait.prowess]: "

Resists consequences from physical strain or injury

", - [AttributeTrait.resolve]: "

Resists consequences from mental strain or willpower

" - }, - ShortAttributeTooltips: { - [AttributeTrait.insight]: "vs. deception or (mis)understanding", - [AttributeTrait.prowess]: "vs. physical strain or injury", - [AttributeTrait.resolve]: "vs. mental strain or willpower" - }, - ShortActionTooltips: { - [ActionTrait.hunt]: "carefully track a target", - [ActionTrait.study]: "scrutinize details and interpret evidence", - [ActionTrait.survey]: "observe the situation and anticipate outcomes", - [ActionTrait.tinker]: "fiddle with devices and mechanisms", - [ActionTrait.finesse]: "employ dexterity or subtle misdirection", - [ActionTrait.prowl]: "traverse skillfully and quietly", - [ActionTrait.skirmish]: "entangle a target in melee so they can't escape", - [ActionTrait.wreck]: "unleash savage force", - [ActionTrait.attune]: "open your mind to the ghost field or channel nearby electroplasmic energy through your body", - [ActionTrait.command]: "compel swift obedience", - [ActionTrait.consort]: "socialize with friends and contacts", - [ActionTrait.sway]: "influence someone with guile, charm, or argument" - }, - ActionTooltips: { - [ActionTrait.hunt]: "

When you Hunt, you carefully track a target.

  • You might follow a person or discover their location.
  • You might arrange an ambush.
  • You might attack with precision shooting from a distance.
  • You could try to wield your guns in a melee (but Skirmishing might be better).
", - [ActionTrait.study]: "

When you Study, you scrutinize details and interpret evidence.

  • You might gather information from documents, newspapers, and books.
  • You might do research on an esoteric topic.
  • You might closely analyze a person to detect lies or true feelings.
  • You could try to understand a pressing situation (but Surveying might be better).
", - [ActionTrait.survey]: "

When you Survey, you observe the situation and anticipate outcomes.

  • You might spot telltale signs of trouble before it happens.
  • You might uncover opportunities or weaknesses.
  • You might detect a person's motives or intentions (but Studying might be better).
  • You could try to spot a good ambush point (but Hunting might be better).
", - [ActionTrait.tinker]: "

When you Tinker, you fiddle with devices and mechanisms.

  • You might create a new gadget or alter an existing item.
  • You might pick a lock or crack a safe.
  • You might disable an alarm or trap.
  • You might turn the sparkcraft and electroplasmic devices around the city to your advantage.
  • You could try to control a vehicle with your tech-savvy (but Finessing might be better).
", - [ActionTrait.finesse]: "

When you Finesse, you employ dexterity or subtle misdirection.

  • You might pick someone's pocket.
  • You might handle the controls of a vehicle or direct a mount.
  • You might formally duel an opponent with graceful fighting arts.
  • You could try to leverage agility in a melee (but Skirmishing might be better).
  • You could try to pick a lock (but Tinkering might be better).
", - [ActionTrait.prowl]: "

When you Prowl, you traverse skillfully and quietly.

  • You might sneak past a guard or hide in the shadows.
  • You might run and leap across the rooftops.
  • You might attack someone from hiding with a back-stab or blackjack.
  • You could try to waylay a victim during combat (but Skirmishing might be better).
", - [ActionTrait.skirmish]: "

When you Skirmish, you entangle a target in melee so they can't escape.

  • You might brawl or wrestle with them.
  • You might hack and slash.
  • You might seize or hold a position in battle.
  • You could try to fight in a formal duel (but Finessing might be better).
", - [ActionTrait.wreck]: "

When you Wreck, you unleash savage force.

  • You might smash down a door or wall with a sledgehammer.
  • You might use an explosive to do the same.
  • You might use chaos or sabotage to create distractions or overcome obstacles.
  • You could try to overwhelm an enemy with sheer force in battle (but Skirmishing might be better).
", - [ActionTrait.attune]: "

When you Attune, you open your mind to the ghost field or channel nearby electroplasmic energy through your body.

  • You might communicate with a ghost or understand aspects of spectrology.
  • You might peer into the echo of Doskvol in the ghost field.
  • You could try to perceive beyond sight in order to better understand your situation (but Surveying might be better).
", - [ActionTrait.command]: "

When you Command, you compel swift obedience.

  • You might intimidate or threaten to get what you want.
  • You might lead a gang in a group action.
  • You could try to persuade people by giving orders (but Consorting might be better).
", - [ActionTrait.consort]: "

When you Consort, you socialize with friends and contacts.

  • You might gain access to resources, information, people, or places.
  • You might make a good impression or win someone over with charm and style.
  • You might make new friends or connect with your heritage or background.
  • You could try to direct allies with social pressure (but Commanding might be better).
", - [ActionTrait.sway]: "

When you Sway, you influence someone with guile, charm, or argument.

  • You might lie convincingly.
  • You might persuade someone to do what you want.
  • You might argue a case that leaves no clear rebuttal.
  • You could try to trick people into affection or obedience (but Consorting or Commanding might be better).
" - }, - ActionTooltipsGM: { - [ActionTrait.hunt]: "

When you Hunt, you carefully track a target.

  • You might follow a person or discover their location.
  • You might arrange an ambush.
  • You might attack with precision shooting from a distance.
  • You could try to wield your guns in a melee (but Skirmishing might be better).

  • How do you hunt them down?
  • What methods do you use?
  • What do you hope to achieve?
", - [ActionTrait.study]: "

When you Study, you scrutinize details and interpret evidence.

  • You might gather information from documents, newspapers, and books.
  • You might do research on an esoteric topic.
  • You might closely analyze a person to detect lies or true feelings.
  • You could try to understand a pressing situation (but Surveying might be better).

  • What do you study?
  • What details or evidence do you scrutinize?
  • What do you hope to understand?
", - [ActionTrait.survey]: "

When you Survey, you observe the situation and anticipate outcomes.

  • You might spot telltale signs of trouble before it happens.
  • You might uncover opportunities or weaknesses.
  • You might detect a person's motives or intentions (but Studying might be better).
  • You could try to spot a good ambush point (but Hunting might be better).

  • How do you survey the situation?
  • Is there anything special you're looking out for?
  • What do you hope to understand?
", - [ActionTrait.tinker]: "

When you Tinker, you fiddle with devices and mechanisms.

  • You might create a new gadget or alter an existing item.
  • You might pick a lock or crack a safe.
  • You might disable an alarm or trap.
  • You might turn the sparkcraft and electroplasmic devices around the city to your advantage.
  • You could try to control a vehicle with your tech-savvy (but Finessing might be better).

  • What do you tinker with?
  • What do you hope to accomplish?
", - [ActionTrait.finesse]: "

When you Finesse, you employ dexterity or subtle misdirection.

  • You might pick someone's pocket.
  • You might handle the controls of a vehicle or direct a mount.
  • You might formally duel an opponent with graceful fighting arts.
  • You could try to leverage agility in a melee (but Skirmishing might be better).
  • You could try to pick a lock (but Tinkering might be better).

  • What do you finesse?
  • What's graceful or subtle about this?
  • What do you hope to achieve?
", - [ActionTrait.prowl]: "

When you Prowl, you traverse skillfully and quietly.

  • You might sneak past a guard or hide in the shadows.
  • You might run and leap across the rooftops.
  • You might attack someone from hiding with a back-stab or blackjack.
  • You could try to waylay a victim during combat (but Skirmishing might be better).

  • How do you prowl?
  • How do you use the environment around you?
  • What do you hope to achieve?
", - [ActionTrait.skirmish]: "

When you Skirmish, you entangle a target in melee so they can't escape.

  • You might brawl or wrestle with them.
  • You might hack and slash.
  • You might seize or hold a position in battle.
  • You could try to fight in a formal duel (but Finessing might be better).

  • How do you skirmish with them?
  • What combat methods do you use?
  • What do you hope to achieve?
", - [ActionTrait.wreck]: "

When you Wreck, you unleash savage force.

  • You might smash down a door or wall with a sledgehammer.
  • You might use an explosive to do the same.
  • You might use chaos or sabotage to create distractions or overcome obstacles.
  • You could try to overwhelm an enemy with sheer force in battle (but Skirmishing might be better).

  • What do you wreck?
  • What force do you bring to bear?
  • What do you hope to accomplish?
", - [ActionTrait.attune]: "

When you Attune, you open your mind to the ghost field or channel nearby electroplasmic energy through your body.

  • You might communicate with a ghost or understand aspects of spectrology.
  • You might peer into the echo of Doskvol in the ghost field.
  • You could try to perceive beyond sight in order to better understand your situation (but Surveying might be better).

  • How do you open your mind to the ghost field?
  • What does that look like?
  • What energy are you attuning to?
  • How are you channeling that energy?
  • What do you hope the energy will do?
", - [ActionTrait.command]: "

When you Command, you compel swift obedience.

  • You might intimidate or threaten to get what you want.
  • You might lead a gang in a group action.
  • You could try to persuade people by giving orders (but Consorting might be better).

  • Who do you command?
  • How do you do it—what's your leverage here?
  • What do you hope they'll do?
", - [ActionTrait.consort]: "

When you Consort, you socialize with friends and contacts.

  • You might gain access to resources, information, people, or places.
  • You might make a good impression or win someone over with charm and style.
  • You might make new friends or connect with your heritage or background.
  • You could try to direct allies with social pressure (but Commanding might be better).

  • Who do you consort with?
  • Where do you meet?
  • What do you talk about?
  • What do you hope to achieve?
", - [ActionTrait.sway]: "

When you Sway, you influence someone with guile, charm, or argument.

  • You might lie convincingly.
  • You might persuade someone to do what you want.
  • You might argue a case that leaves no clear rebuttal.
  • You could try to trick people into affection or obedience (but Consorting or Commanding might be better).

  • Who do you sway?
  • What kind of leverage do you have here?
  • What do you hope they'll do?
" - }, - ActionVerbs: { - [ActionTrait.hunt]: "hunts", - [ActionTrait.study]: "studies", - [ActionTrait.survey]: "surveys", - [ActionTrait.tinker]: "tinkers", - [ActionTrait.finesse]: "finesses", - [ActionTrait.prowl]: "prowls", - [ActionTrait.skirmish]: "skirmishes", - [ActionTrait.wreck]: "wrecks", - [ActionTrait.attune]: "attunes", - [ActionTrait.command]: "commands", - [ActionTrait.consort]: "consorts", - [ActionTrait.sway]: "sways" - }, - ActionPastVerbs: { - [ActionTrait.hunt]: "hunted", - [ActionTrait.study]: "studied", - [ActionTrait.survey]: "surveyed", - [ActionTrait.tinker]: "tinkered", - [ActionTrait.finesse]: "finessed", - [ActionTrait.prowl]: "prowled", - [ActionTrait.skirmish]: "skirmished", - [ActionTrait.wreck]: "wrecked", - [ActionTrait.attune]: "attuned", - [ActionTrait.command]: "commanded", - [ActionTrait.consort]: "consorted", - [ActionTrait.sway]: "swayed" - }, - TraumaTooltips: { - Cold: "You're not moved by emotional appeals or social bonds.", - Haunted: "You're often lost in reverie, reliving past horrors, seeing things.", - Obsessed: "You're enthralled by one thing: an activity, a person, an ideology.", - Paranoid: "You imagine danger everywhere; you can't trust others.", - Reckless: "You have little regard for your own safety or best interests.", - Soft: "You lose your edge; you become sentimental, passive, gentle.", - Unstable: "Your emotional state is volatile. You can instantly rage, or fall into despair, act impulsively, or freeze up.", - Vicious: "You seek out opportunities to hurt people, even for no good reason.", - Chaotic: "You've become so detached from the living that inhibitions fall away, leaving you impulsive and unpredictable.", - Destructive: "You are easily angered by reminders of all you've lost, and can lash out violently against the trappings of the living world.", - Furious: "Your ravaged soul is fertile kindling for rage, and your fury is easily ignited.", - Obsessive: "Your wants and desires become fixations and compulsions, driving you to achieve them at any cost.", - Territorial: "You see some place as yours: Trespassers are dealt with, and even guests must respect your claim.", - Savage: "When moved to anger or violence, you act with cruelty and feral malevolence.", - Clanking: "Your frame has developed a persistent metallic clang with each step, making stealth difficult.", - Leaking: "You continuously leak oil, leviathan blood, distilled electroplasm or some other potentially-dangerous substance.", - Fixated: "You have become fixated on a function of your choice, and lose all memory of your humanity when you pursue it.", - Smoking: "Your frame exudes a constant miasma of acrid, foul-smelling smoke.", - Sparking: "Electroplasmic energy erupts in arcing sparks from joints and junctions throughout your frame.", - Ruthless: "You lose any sense of humanity when indulging your Vice or pursuing your most important goal.", - Secretive: "Knowledge has become so precious to you, that even your closest allies are on a need-to-know basis." - }, - EdgeTooltips: { - Fearsome: "

The cohort is terrifying in aspect and reputation.

", - Independent: "

The cohort can be trusted to make good decisions and act on their own initiative in the absence of direct orders.

", - Loyal: "

The cohort can't be bribed or turned against you.

", - Tenacious: "

The cohort won't be deterred from a task.

", - Nimble: "

The vehicle handles easily. Consider this an assist for tricky maneuvers.

", - Simple: "

The vehicle is easy to repair. Remove all of its Harm during downtime

", - Sturdy: "

The vehicle keeps operating even when Broken.

", - "Arrow-Swift": "

Your pet gains Potency when tracking or fighting the supernatural.

It can move extremely quickly, outpacing any other creature or vehicle.

", - "Ghost Form": "

Your pet gains Potency when tracking or fighting the supernatural.

It can transform into electroplasmic vapor as if it were a spirit.

", - "Mind Link": "

Your pet gains Potency when tracking or fighting the supernatural.

You and your pet can share senses and thoughts telepathically.

" - }, - FlawTooltips: { - Principled: "

The cohort has an ethic or values that it won't betray.

", - Savage: "

The cohort is excessively violent and cruel.

", - Unreliable: "

The cohort isn't always available, due to other obligations, stupefaction from their vices, etc.

", - Wild: "

The cohort is drunken, debauched, and loud-mouthed.

", - Costly: "

The vehicle costs 1 Coin per downtime to keep it in operation.

", - Distinct: "

The vehicle has memorable features. Take +1 Heat when you use it on a score.

", - Finicky: "

The vehicle has quirks that only one person understands. When operated without them, it has -1 Quality.

" - }, - QualityDescriptors: [ - "Poor", - "Adequate", - "Good", - "Excellent", - "Superior", - "Impeccable", - "Legendary" - ], - ForceDescriptors: [ - "Weak", - "Moderate", - "Strong", - "Serious", - "Powerful", - "Overwhelming", - "Devastating" - ], - VehicleDescriptors: [ - "A Vehicle?", - "A Vehicle", - "A Respectable Vehicle", - "A Respected Vehicle", - "A Precision-Built Vehicle", - "A Powerful, Advanced Vehicle", - "A Uniquely Strong, Extremely Advanced Vehicle" - ], - PetDescriptors: [ - "A Weak Hunting Pet", - "A Hunting Pet", - "A Strong Hunting Pet", - "A Serious Hunting Pet", - "A Powerful Hunting Pet", - "An Overwhelmingly Powerful Hunting Pet", - "A Devastating Hunting Pet" - ], - AreaExamples: [ - "a closet", - "a small room", - "a large room", - "several rooms", - "a small building", - "a large building", - "a city block" - ], - ScaleExamples: [ - "(1 or 2 members)", - "(3 - 6 members)", - "(~12 members)", - "(~20 members)", - "(~40 members)", - "(~80 members)", - "(~160 members)" - ], - ScaleSizes: [ - "A Few ", - "A Small Gang of ", - "A Gang of ", - "A Large Gang of ", - "A Small Army of ", - "An Army of ", - "A Massive Army of " - ], - DiceOddsStandard: [ - { crit: 0, success: 2.8, partial: 22.2, fail: 75 }, - { crit: 0, success: 16.7, partial: 33.3, fail: 50 }, - { crit: 2.8, success: 27.8, partial: 44.4, fail: 25 }, - { crit: 7.4, success: 34.7, partial: 45.4, fail: 12.5 }, - { crit: 13.2, success: 38.6, partial: 42, fail: 6.3 }, - { crit: 19.6, success: 40.2, partial: 37.1, fail: 3.1 }, - { crit: 26.3, success: 40.2, partial: 31.9, fail: 1.6 }, - { crit: 33, success: 39.1, partial: 27.1, fail: 0.8 }, - { crit: 39.5, success: 37.2, partial: 22.9, fail: 0.4 }, - { crit: 45.7, success: 34.9, partial: 19.2, fail: 0.2 }, - { crit: 51.5, success: 32.3, partial: 16.1, fail: 0.1 }, - { crit: 56.9, success: 29.6, partial: 13.4, fail: 0 }, - { crit: 61.9, success: 26.9, partial: 11.2, fail: 0 }, - { crit: 66.3, success: 24.3, partial: 9.3, fail: 0 }, - { crit: 70.4, success: 21.8, partial: 7.8, fail: 0 }, - { crit: 74, success: 19.5, partial: 6.5, fail: 0 }, - { crit: 77.3, success: 17.3, partial: 5.4, fail: 0 }, - { crit: 80.2, success: 15.3, partial: 4.5, fail: 0 }, - { crit: 82.7, success: 13.5, partial: 3.8, fail: 0 }, - { crit: 85, success: 11.9, partial: 3.1, fail: 0 }, - { crit: 87, success: 10.4, partial: 2.6, fail: 0 } - ], - DiceOddsResistance: [ - [0, 2.8, 8.3, 13.9, 19.4, 25, 30.6], - [0, 16.7, 16.7, 16.7, 16.6, 16.7, 16.7], - [2.8, 27.8, 25, 19.4, 13.9, 8.3, 2.8], - [7.4, 34.7, 28.3, 17.1, 8.8, 3.2, 0.5], - [13.2, 38.6, 28.5, 13.5, 5, 1.2, 0.1], - [19.6, 40.2, 27, 10.1, 2.7, 0.4, 0], - [26.3, 40.2, 24.7, 7.2, 1.4, 0.1, 0] - ], - ExperienceClues: { - Scoundrel: [ - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - Crew: [ - "You contended with challenges above your current station.", - "You bolstered your crew's reputation, or developed a new one.", - "You expressed the goals, drives, inner conflict, or essential nature of the crew." - ] - }, - GatherInfoQuestions: { - Cutter: [ - "How can I hurt them?", - "Who's most afraid of me?", - "Who's most dangerous here?", - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What's really going on here?" - ], - Hound: [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "Where are they vulnerable?", - "Where did [X] go?", - "How can I find [X]?", - "What's really going on here?" - ], - Leech: [ - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What can I tinker with here?", - "What might happen if I [X]?", - "How can I find [X]?", - "What's really going on here?" - ], - Lurk: [ - "What do they intend to do?", - "How can I get them to [X]?", - "What should I look out for?", - "What's the best way in?", - "Where can I hide here?", - "How can I find [X]?", - "What's really going on here?" - ], - Slide: [ - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What are they really feeling?", - "What do they really care about?", - "How can I blend in here?", - "What's really going on here?" - ], - Spider: [ - "What do they want most?", - "What should I look out for?", - "Where's the leverage here?", - "How can I discover [X]?", - "What do they intend to do?", - "How can I get them to [X]?", - "What's really going on here?" - ], - Whisper: [ - "What is arcane or weird here?", - "What echoes in the ghost field?", - "What is hidden or lost here?", - "What do they intend to do?", - "What drives them to do this?", - "How can I reveal [X]?", - "What's really going on here?" - ], - Ghost: [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ], - Hull: [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really doing?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ], - Vampire: [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ] - }, - Playbooks: { - Cutter: { - "system.experience_clues": [ - "You addressed a challenge with violence or coercion.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "How can I hurt them?", - "Who's most afraid of me?", - "Who's most dangerous here?", - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What's really going on here?" - ], - "system.suggested_ability": "Battleborn" - }, - Hound: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/hound-trans.svg", - "system.tagline": "A Deadly Sharpshooter & Tracker", - // "system.acquaintances_name": "Deadly Friends & Rivals", - "system.friends_name": "Deadly Friends", - "system.rivals_name": "Deadlier Rivals", - "system.starting_stats.chargen": { - "system.attributes.insight.hunt.value": 2, - "system.attributes.insight.survey.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with tracking or violence.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "Where are they vulnerable?", - "Where did [X] go?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.suggested_ability": "Sharpshooter" - }, - Leech: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/leech-trans.svg", - "system.tagline": "A Saboteur & Technician", - // "system.acquaintances_name": "Clever Friends & Rivals", - "system.friends_name": "Clever Friends", - "system.rivals_name": "Cleverer Rivals", - "system.starting_stats.chargen": { - "system.attributes.insight.tinker.value": 2, - "system.attributes.prowess.wreck.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with technical skill or mayhem.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What can I tinker with here?", - "What might happen if I [X]?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.suggested_ability": "Alchemist" - }, - Lurk: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/lurk-trans.svg", - "system.tagline": "A Stealthy Infiltrator & Burglar", - // "system.acquaintances_name": "Shady Friends & Rivals", - "system.friends_name": "Shady Friends", - "system.rivals_name": "Shadier Rivals", - "system.starting_stats.chargen": { - "system.attributes.prowess.prowl.value": 2, - "system.attributes.prowess.finesse.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with stealth or evasion.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "What should I look out for?", - "What's the best way in?", - "Where can I hide here?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.suggested_ability": "Infiltrator" - }, - Slide: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/slide-trans.svg", - "system.tagline": "A Subtle Manipulator & Spy", - // "system.acquaintances_name": "Sly Friends & Rivals", - "system.friends_name": "Sly Friends", - "system.rivals_name": "Slyer Rivals", - "system.starting_stats.chargen": { - "system.attributes.resolve.sway.value": 2, - "system.attributes.resolve.consort.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with deception or influence.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "Are they telling the truth?", - "What are they really feeling?", - "What do they really care about?", - "How can I blend in here?", - "What's really going on here?" - ], - "system.suggested_ability": "Rook's Gambit" - }, - Spider: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/spider-trans.svg", - "system.tagline": "A Devious Mastermind", - // "system.acquaintances_name": "Shrewd Friends & Rivals", - "system.friends_name": "Shrewd Friends", - "system.rivals_name": "Very Shrewd Rivals", - "system.starting_stats.chargen": { - "system.attributes.resolve.consort.value": 2, - "system.attributes.insight.study.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with calculation or conspiracy.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they want most?", - "What should I look out for?", - "Where's the leverage here?", - "How can I discover [X]?", - "What do they intend to do?", - "How can I get them to [X]?", - "What's really going on here?" - ], - "system.suggested_ability": "Foresight" - }, - Whisper: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/whisper-trans.svg", - "system.tagline": "An Arcane Adept & Channeler", - // "system.acquaintances_name": "Strange Friends & Rivals", - "system.friends_name": "Strange Friends", - "system.rivals_name": "Stranger Rivals", - "system.starting_stats.chargen": { - "system.attributes.resolve.attune.value": 2, - "system.attributes.insight.study.value": 1 - }, - "system.experience_clues": [ - "You addressed a challenge with knowledge or arcane power.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice or traumas during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Reckless", "Soft", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What is arcane or weird here?", - "What echoes in the ghost field?", - "What is hidden or lost here?", - "What do they intend to do?", - "What drives them to do this?", - "How can I reveal [X]?", - "What's really going on here?" - ], - "system.suggested_ability": "Compel" - }, - Ghost: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/ghost-trans.svg", - "system.tagline": "A Vengeful Disembodied Spirit", - "system.acquaintances_name": "Enemies & Rivals", - "system.starting_stats.add": { - "system.attributes.insight.hunt.value": 1, - "system.attributes.prowess.prowl.value": 1, - "system.attributes.resolve.attune.value": 1 - }, - "system.experience_clues": [ - "You exacted vengeance upon those whom you deem deserving.", - "You expressed your outrage or anger, or settled scores from your heritage, or background.", - "You struggled with issues from your need or glooms during the session." - ], - "system.trauma_conditions": ["Chaotic", "Destructive", "Furious", "Obsessive", "Territorial", "Savage"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.auto_abilities": ["Ghost Form"] - }, - Hull: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/hull-trans.svg", - "system.tagline": "An Animated Spark-Craft Frame", - "system.acquaintances_name": "Master", - "system.starting_stats.add": { - "system.attributes.prowess.skirmish.value": 1, - "system.attributes.resolve.attune.value": 1 - }, - "system.experience_clues": [ - "You fulfilled your functions despite difficulty or danger.", - "You suppressed or ignored your former human beliefs, drives, heritage, or background.", - "You struggled with issues from your wear during the session." - ], - "system.trauma_conditions": ["Clanking", "Leaking", "Fixated", "Smoking", "Sparking", "Unstable"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really doing?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.auto_abilities": ["Automaton"] - }, - Vampire: { - "system.bgImg": "systems/eunos-blades/assets/icons/class-icons/vampire-trans.svg", - "system.tagline": "An Animated Undead Body", - "system.acquaintances_name": "Dark Servants", - "system.starting_stats.add": { - "system.attributes.insight.hunt.value": 1, - "system.attributes.prowess.prowl.value": 1, - "system.attributes.prowess.skirmish.value": 1, - "system.attributes.resolve.attune.value": 1, - "system.attributes.resolve.command.value": 1, - "system.attributes.resolve.sway.value": 1 - }, - "system.experience_clues": [ - "You displayed your dominance or slayed without mercy.", - "You expressed your beliefs, drives, heritage, or background.", - "You struggled with issues from your vice, traumas, or strictures during the session." - ], - "system.trauma_conditions": ["Cold", "Haunted", "Obsessed", "Paranoid", "Ruthless", "Secretive", "Unstable", "Vicious"], - "system.gather_info_questions": [ - "What do they intend to do?", - "How can I get them to [X]?", - "What are they really feeling?", - "What should I lookout for?", - "Where's the weakness here?", - "How can I find [X]?", - "What's really going on here?" - ], - "system.auto_abilities": ["Undead"] - } - }, - ClockSizes: [1, 2, 3, 4, 5, 6, 8, 10, 12], - ActorTypes: [ - BladesActorType.pc, - BladesActorType.npc, - BladesActorType.crew, - BladesActorType.faction - ], - ItemTypes: [ - BladesItemType.ability, - BladesItemType.background, - BladesItemType.clock_keeper, - BladesItemType.cohort_gang, - BladesItemType.cohort_expert, - BladesItemType.crew_ability, - BladesItemType.crew_reputation, - BladesItemType.crew_playbook, - BladesItemType.crew_upgrade, - BladesItemType.feature, - BladesItemType.gm_tracker, - BladesItemType.heritage, - BladesItemType.gear, - BladesItemType.playbook, - BladesItemType.preferred_op, - BladesItemType.stricture, - BladesItemType.vice, - BladesItemType.project, - BladesItemType.ritual, - BladesItemType.design, - BladesItemType.location, - BladesItemType.score - ], - SimpleItemTypes: [ - BladesItemType.background, - BladesItemType.crew_reputation, - BladesItemType.feature, - BladesItemType.heritage, - BladesItemType.preferred_op, - BladesItemType.stricture - ], - Attribute: [ - AttributeTrait.insight, - AttributeTrait.prowess, - AttributeTrait.resolve - ], - Action: { - [AttributeTrait.insight]: [ActionTrait.hunt, ActionTrait.study, ActionTrait.survey, ActionTrait.tinker], - [AttributeTrait.prowess]: [ActionTrait.finesse, ActionTrait.prowl, ActionTrait.skirmish, ActionTrait.wreck], - [AttributeTrait.resolve]: [ActionTrait.attune, ActionTrait.command, ActionTrait.consort, ActionTrait.sway] - }, - Vices: [ - Vice.Faith, - Vice.Gambling, - Vice.Luxury, - Vice.Obligation, - Vice.Pleasure, - Vice.Stupor, - Vice.Weird, - Vice.Worship, - Vice.Living_Essence, - Vice.Life_Essence, - Vice.Electroplasmic_Power - ] -}; -// #endregion -// #region RANDOMIZER DATA -export const Randomizers = { - NPC: { - heritage: [ - "Akorosi", - "Akorosi", - "Akorosi", - "Akorosi", - "Akorosi", - "Akorosi", - "Dagger Islander", - "Iruvian", - "Severosi", - "Skovlander", - "Skovlander", - "Tycherosi" - ], - background: [ - "Academic", - "Academic", - "Academic", - "Labor", - "Labor", - "Labor", - "Labor", - "Law", - "Law", - "Law", - "Military", - "Military", - "Military", - "Military", - "Military", - "New Money", - "New Money", - "Old Money", - "Old Money", - "Politics", - "Politics", - "Trade", - "Trade", - "Trade", - "Underworld", - "Underworld", - "Underworld", - "Underworld", - "Underworld", - "Weird" - ], - gender: [ - "M", - "M", - "M", - "M", - "F", - "F", - "F", - "U", - "X" - ], - appearance: [ - "Athletic", - "Beard", - "Bony", - "Chiseled", - "Crippled / Prosthetic", - "Cute", - "Dark", - "Delicate", - "Disfigured / Maimed", - "Elegant", - "Fair", - "Glasses / Monocle", - "Handsome", - "Large", - "Long Hair", - "Lovely", - "Old", - "Plain", - "Plump", - "Rough", - "Scarred", - "Sexy", - "Shaved Bald", - "Short", - "Slim", - "Stooped", - "Stout", - "Strange", - "Striking", - "Stylish", - "Tall", - "Tattooed", - "Weathered", - "Wig", - "Wild", - "Wiry", - "Worn", - "Young" - ], - goal: [ - "Achievement", - "Authority", - "Change", - "Chaos / Destruction", - "Control", - "Cooperation", - "Freedom", - "Happiness", - "Infamy / Fear", - "Justice", - "Knowledge", - "Love", - "Pleasure", - "Power", - "Prestige / Fame", - "Respect", - "Revenge", - "Wealth" - ], - method: [ - "Alchemy", - "Arcane", - "Blackmail", - "Chaos", - "Commerce", - "Espionage", - "Hard Work", - "Law / Politics", - "Manipulation", - "Negotiation", - "Sabotage", - "Strategy", - "Study", - "Subterfuge", - "Teamwork", - "Theft", - "Threats", - "Violence" - ], - profession: [ - "Advocate", - "Apiarist", - "Architect", - "Artist", - "Author", - "Bailiff", - "Baker", - "Baker", - "Baker", - "Banker", - "Barber", - "Barber", - "Barber", - "Blacksmith", - "Blacksmith", - "Blacksmith", - "Bounty Hunter", - "Brewer", - "Brewer", - "Brewer", - "Butcher", - "Butcher", - "Butcher", - "Captain", - "Carpenter", - "Carpenter", - "Carpenter", - "Cartwright", - "Cartwright", - "Cartwright", - "Chandler", - "Chandler", - "Chandler", - "Clerk", - "Clerk", - "Clerk", - "Clockmaker", - "Cobbler", - "Cobbler", - "Cobbler", - "Composer", - "Cooper", - "Cooper", - "Cooper", - "Courtesan", - "Criminal", - "Criminal", - "Criminal", - "Cultivator", - "Cultivator", - "Cultivator", - "Diplomat", - "Driver", - "Driver", - "Driver", - "Dyer", - "Dyer", - "Dyer", - "Embroiderer", - "Embroiderer", - "Embroiderer", - "Explorer", - "Fishmonger", - "Fishmonger", - "Fishmonger", - "Furrier", - "Glass Blower", - "Goat Herd", - "Goat Herd", - "Goat Herd", - "Gondolier", - "Gondolier", - "Gondolier", - "Guard", - "Guard", - "Guard", - "Jailer", - "Jeweler", - "Journalist", - "Leatherworker", - "Leatherworker", - "Leatherworker", - "Leech", - "Locksmith", - "Magistrate", - "Mason", - "Mason", - "Mason", - "Merchant", - "Merchant", - "Merchant", - "Messenger", - "Messenger", - "Messenger", - "Musician", - "Physicker", - "Plumber", - "Printer", - "Rail Jack", - "Roofer", - "Roofer", - "Roofer", - "Ropemaker", - "Ropemaker", - "Ropemaker", - "Rug Maker", - "Rug Maker", - "Rug Maker", - "Sailor", - "Sailor", - "Sailor", - "Scholar", - "Scribe", - "Servant", - "Servant", - "Servant", - "Shipwright", - "Shipwright", - "Shipwright", - "Soldier", - "Sparkwright", - "Spirit Warden", - "Steward", - "Tailor", - "Tailor", - "Tailor", - "Tanner", - "Tanner", - "Tanner", - "Tax Collector", - "Tinkerer", - "Tinkerer", - "Tinkerer", - "Treasurer", - "Vendor", - "Vendor", - "Vendor", - "Weaver", - "Weaver", - "Weaver", - "Whisper", - "Woodworker", - "Woodworker", - "Woodworker" - ], - trait: [ - "Arcane", - "Arrogant", - "Artistic", - "Bold", - "Brash", - "Brave", - "Calculating", - "Calm", - "Candid", - "Careless", - "Cautious", - "Cavalier", - "Charming", - "Cold", - "Commanding", - "Compassionate", - "Confident", - "Connected", - "Cooperative", - "Creative", - "Cruel", - "Cultured", - "Daring", - "Defiant", - "Dishonest", - "Dramatic", - "Elitist", - "Enigmatic", - "Enthusiastic", - "Erudite", - "Experienced", - "Fierce", - "Flexible", - "Friendly", - "Gracious", - "Greedy", - "Haunted", - "Insightful", - "Kind", - "Melancholy", - "Moody", - "Obsessive", - "Paranoid", - "Patient", - "Popular", - "Principled", - "Proud", - "Quiet", - "Reckless", - "Respected", - "Ruthless", - "Sadistic", - "Savage", - "Secretive", - "Shrewd", - "Sincere", - "Sneaky", - "Sophisticated", - "Strange", - "Stylish", - "Subtle", - "Suspicious", - "Tough", - "Vain", - "Vengeful", - "Vicious", - "Visionary", - "Volatile", - "Weird", - "Wise" - ], - interests: [ - "Alchemy, medicine", - "Antiques, artifacts, curios", - "Arcane books, rituals", - "Architecture, furnishings", - "Church of Ecstasy", - "Cooking, gardening", - "Craft (leatherwork, etc.)", - "Demon lore, legends", - "Drugs, essences, tobacco", - "Essences, alchemy", - "Exploration, adventure", - "Fine arts, opera, theater", - "Fine clothes, jewelry, furs", - "Fine food, restaurants", - "Fine whiskey, wine, beer", - "Forgotten gods", - "Gadgets, new technology", - "Gambling, cards, dice", - "History, legends", - "Horses, riding", - "Hunting, shooting", - "Lovers, romance, trysts", - "Music, instruments, dance", - "Natural philosophy", - "Painting, drawing, sculpture", - "Parties, social events", - "Path of Echoes", - "Pets (birds, dogs, cats)", - "Pit-fighting, duels", - "Poetry, novels, writing", - "Politics, journalism", - "Pre-cataclysm legends", - "Ships, boating", - "Spectrology, electroplasm", - "Weapons collector", - "Weeping Lady, charity" - ], - quirk: [ - "A fraud. Some important aspect is fabricated.", - "Bigoted against culture / belief / social class.", - "Black sheep / outcast from family or organization.", - "Blind to flaws in friends, allies, family, etc.", - "Celebrity. Popularized in print / song / theater.", - "Concerned with appearances, gossip, peers.", - "Cursed, haunted, harassed by spirits or demon.", - "Deeply traditional. Opposed to new ideas.", - "Devoted to their family.", - "Drug / alcohol abuser. Often impaired by their vice.", - "Extensive education on every scholarly subject.", - "Has chronic illness that requires frequent care.", - "Holds their position due to blackmail.", - "Holds their position to spy for another faction.", - "In prison or under noble's house arrest.", - "Inherited their position. May not deserve / want it.", - "Intense, unreasonable phobia or loathing.", - "Involved with war crimes from the Unity War.", - "Is blindly faithful to an ideal, group, or tradition.", - "Keeps detailed journals, notes, records, ledgers.", - "Leads a double life using cover identity.", - "Married into important / powerful family.", - "Massive debts (to banks / criminals / family)", - "Once hollowed, then restored. Immune to spirits.", - "Proud of heritage, traditions, native language.", - "Reclusive. Prefers to interact via messengers.", - "Relies on council to make decisions.", - "Revolutionary. Plots against the Imperium.", - "Scandalous reputation (deserved or not).", - "Secretly (openly?) controlled by possessing spirit.", - "Serves a demon's agenda (knowingly or not).", - "Spotless reputation. Highly regarded.", - "Superstitious. Believes in signs, magic numbers.", - "Surrounded by sycophants, supplicants, toadies.", - "Visionary. Holds radical views for future.", - "Well-traveled. Connections outside Doskvol." - ], - style: { - male: [ - "Apron", - "Cane", - "Collared Shirt", - "Crutches", - "Eelskin Bodysuit", - "Face Mask", - "Fitted Leggings", - "Heavy Cloak", - "Heavy Gloves", - "Hide & Furs", - "Hood & Veil", - "Hooded Coat", - "Knit Cap", - "Leathers", - "Long Coat", - "Long Scarf", - "Loose Silks", - "Mask & Robes", - "Rough Tunic", - "Sharp Trousers", - "Short Cloak", - "Slim Jacket", - "Soft Boots", - "Suit & Vest", - "Suspenders", - "Tall Boots", - "Tatters", - "Thick Greatcoat", - "Tool Belt", - "Tricorn Hat", - "Uniform", - "Waxed Coat", - "Wheelchair", - "Wide Belt", - "Work Boots" - ], - female: [ - "Apron", - "Cane", - "Crutches", - "Eelskin Bodysuit", - "Face Mask", - "Fitted Dress", - "Fitted Leggings", - "Heavy Cloak", - "Heavy Gloves", - "Hide & Furs", - "Hood & Veil", - "Hooded Coat", - "Knit Cap", - "Leathers", - "Long Coat", - "Long Scarf", - "Loose Silks", - "Mask & Robes", - "Rough Tunic", - "Sharp Trousers", - "Short Cloak", - "Skirt & Blouse", - "Slim Jacket", - "Soft Boots", - "Suspenders", - "Tall Boots", - "Tatters", - "Thick Greatcoat", - "Tool Belt", - "Uniform", - "Waxed Coat", - "Wheelchair", - "Wide Belt", - "Work Boots" - ] - }, - name_title: [ - "Adept", - "Archivist", - "Captain", - "Charter", - "Scrivener" - ], - name_first: { - male: [ - "Abel", - "Abenthy", - "Adric", - "Airic", - "Alabaster", - "Alastair", - "Aldo", - "Alen", - "Aleph", - "Ambrose", - "Amosen", - "Andal", - "Andrel", - "Anton", - "Aquilla", - "Aradan", - "Aram", - "Archibald", - "Archie", - "Arden", - "Arliden", - "Arlyn", - "Armand", - "Arquo", - "Arrell", - "Arvus", - "Asher", - "Aurelio", - "Benedict", - "Bolster", - "Brace", - "Bran", - "Brance", - "Branon", - "Bricks", - "Brock", - "Brutus", - "Caius", - "Carro", - "Casian", - "Cato", - "Cavelle", - "Cedric", - "Chance", - "Chauncey", - "Cid", - "Clave", - "Cliff", - "Cornelius", - "Cross", - "Crowl", - "Cym", - "Cyrus", - "Declan", - "Del", - "Drav", - "Drazhan", - "Drem", - "Edlun", - "Edmund", - "Edrom", - "Edwin", - "Elan", - "Elend", - "Elias", - "Elodin", - "Ephrim", - "Erasmus", - "Eremon", - "Ethan", - "Everitt", - "Feldspar", - "Fero", - "Finn", - "Fisher", - "Galen", - "Gallahad", - "Garner", - "Gilbert", - "Glint", - "Gnik", - "Gregalos", - "Grey", - "Greyson", - "Grifter", - "Grine", - "Gristofer", - "Hadrian", - "Hagran", - "Hammond", - "Hix", - "Holtz", - "Hugo", - "Iden", - "Irton", - "Isaac", - "Ivellios", - "Jabari", - "Jericho", - "Jerod", - "Kazimir", - "Kellan", - "Kelvyn", - "Kelyr", - "Khafra", - "Kobb", - "Kristov", - "Kyrilu", - "Lael", - "Lafayette", - "Laudius", - "Lawrence", - "Leif", - "Lem", - "Lenny", - "Logan", - "Lucas", - "Lucius", - "Lysander", - "Milos", - "Mord", - "Morketh", - "Morlan", - "Myre", - "Narcus", - "Nehi", - "Noggs", - "Norton", - "Obel", - "Obelas", - "Octavius", - "Odelay", - "Orem", - "Orlan", - "Orth", - "Orton", - "Pavel", - "Perceval", - "Percival", - "Peregrine", - "Phin", - "Phineas", - "Porto", - "Preston", - "Primo", - "Quess", - "Quill", - "Rafe", - "Rasmus", - "Raul", - "Resh", - "Rias", - "Ring", - "Rivallo", - "Rodmund", - "Roethe", - "Roose", - "Roric", - "Sethla", - "Silas", - "Sindri", - "Snitch", - "Sol", - "Solomon", - "Sprig", - "Stavrul", - "Stellan", - "Stev", - "Sym", - "Tacitus", - "Tarn", - "Taylor", - "Thackeray", - "Thaddeus", - "Thane", - "Thelian", - "Theo", - "Theron", - "Thurston", - "Timoth", - "Tisk", - "Tocker", - "Tristero", - "Ulric", - "Vask", - "Veleris", - "Ventaro", - "Virgil", - "Vond", - "Wax", - "Wayne", - "Weaver", - "Wester", - "Winsley" - ], - female: [ - "Adaire", - "Adelaide", - "Adella", - "Adroit", - "Ailen", - "Aina", - "Akilah", - "Albinia", - "Althaea", - "Alyosha", - "Ansa", - "Arabella", - "Arwyl", - "Ashlyn", - "Avora", - "Brena", - "Brenna", - "Calienthe", - "Camilla", - "Candor", - "Candra", - "Carissa", - "Cascabel", - "Casslyn", - "Castille", - "Celeste", - "Chen", - "Claret", - "Clementine", - "Constance", - "Cordelia", - "Corille", - "Corsica", - "Cyrene", - "Dahlia", - "Daphnia", - "Delia", - "Dena", - "Denna", - "Desmona", - "Dolores", - "Drenna", - "Edie", - "Eira", - "Elsie", - "Emeline", - "Etta", - "Fela", - "Felicity", - "Galenica", - "Galina", - "Gitta", - "Gloria", - "Gwen", - "Hedy", - "Hella", - "Helles", - "Henrietta", - "Iduna", - "Iona", - "Isa", - "Isabella", - "Iskra", - "Isolde", - "Jasna", - "Jaxi", - "Joan", - "Juno", - "Kamelin", - "Kari", - "Koli", - "Lauria", - "Lenia", - "Leona", - "Leyva", - "Lieu", - "Lilith", - "Lin", - "Lizete", - "Lorette", - "Lucella", - "Lynthia", - "Lyra", - "Maia", - "Maiathah", - "Maie", - "Mara", - "Marasi", - "Marielda", - "Marisol", - "Marris", - "Mira", - "Naria", - "Nasha", - "Octavia", - "Odrienne", - "Olivia", - "Ora", - "Ordenna", - "Oressia", - "Orsella", - "Pardenna", - "Penelope", - "Penny", - "Phoebe", - "Polonia", - "Pravda", - "Prudence", - "Quelenna", - "Raisa", - "Redji", - "Remira", - "Rey", - "Riven", - "Runa", - "Sabina", - "Sabinia", - "Sabrina", - "Sadeh", - "Sahar", - "Selma", - "Sesereth", - "Severea", - "Silaqui", - "Skannon", - "Sprig", - "Stabitha", - "Syra", - "Tabitha", - "Talitha", - "Tamsyn", - "Tasi", - "Terra", - "Tesslyn", - "Thava", - "Thena", - "Tiff", - "Una", - "Vaurin", - "Veretta", - "Vesna", - "Vestine", - "Vey", - "Victoria", - "Vin", - "Vita", - "Volette", - "Vorka", - "Wander", - "Ylva", - "Zahra", - "Zaida", - "Zamira", - "Zarya" - ] - }, - name_surname: [ - "Abberwick", - "Adelbury", - "Adleton", - "Aloro", - "Alsa", - "Ankhayat", - "Arran", - "Ashton", - "Ashweather", - "Athanoch", - "Axelrod", - "Backworth", - "Barrow", - "Basran", - "Black", - "Blackford", - "Blackpool", - "Blackthorne", - "Bluff", - "Boden", - "Booker", - "Boulder", - "Bowman", - "Braeside", - "Bramble", - "Braum", - "Bray", - "Breakiron", - "Bristle", - "Brocken", - "Brogan", - "Bromley", - "Burnsides", - "Caebrek", - "Cartwright", - "Carver", - "Childermass", - "Claw", - "Clelland", - "Clemont", - "Clermont", - "Cobblecarver", - "Coleburn", - "Combe", - "Comber", - "Crofty", - "Cunningham", - "Daava", - "Dal", - "Dalmore", - "Danfield", - "Drawlight", - "Drigg", - "Dunvil", - "Elmore", - "Eveningeyes", - "Evensteps", - "Eventide", - "Everpenny", - "Fairplay", - "Farros", - "Fellwater", - "Fogg", - "Gatcombe", - "Glasseye", - "Goldsworth", - "Grave", - "Graythwaite", - "Greysteel", - "Grine", - "Haig", - "Half-Off", - "Havelton", - "Havenhorst", - "Hectares", - "Helker", - "Helles", - "Hellyers", - "Hemme", - "Hightower", - "Hightown", - "Highwater", - "Hill", - "Hitchcock", - "Innerwick", - "Jayan", - "Jeduin", - "Kardera", - "Karstas", - "Keel", - "Kempt", - "Kessarin", - "Kinclaith", - "King", - "Lake", - "Larriston", - "Leake", - "Lomond", - "Longstaff", - "Lorewood", - "Maroden", - "Mayson", - "Merriweather", - "Michter", - "Mindwell", - "Morcombe", - "Morriston", - "Mortimer", - "Netherton", - "Night", - "Nighteyre", - "Nightly", - "Noctoft", - "Notherhome", - "Orchard", - "Orchid", - "Path", - "Peak", - "Pegg", - "Penderyn", - "Pond", - "Pool", - "Prichard", - "Raines", - "Ravenglass", - "Ravenwood", - "Reigns", - "Reyes", - "Reynes", - "Rhodes", - "Riverford", - "Robel", - "Rowan", - "Sable", - "Sage", - "Salkara", - "Salos", - "Sevoy", - "Shilbottle", - "Shillmoor", - "Shook", - "Skelkallan", - "Skora", - "Slane", - "Song", - "Steadystep", - "Stoutale", - "Stovestoker", - "Strange", - "Strangford", - "Strathmill", - "Sunder", - "Sunderland", - "Swiftwhistle", - "Tailor", - "Tallfellow", - "Templeton", - "Tenpenny", - "Tevilton", - "Thistle", - "Thrysus", - "Thurston", - "Tinmouth", - "Tower", - "Tristé", - "Tyrconnell", - "Vale", - "Valentine", - "Veldaire", - "Venture", - "Walund", - "Warren", - "Waters", - "Wecker", - "Welker", - "Wend", - "Wharver", - "Whythe", - "Woodall" - ], - name_alias: [ - "Bell", - "Birch", - "Bird", - "Bliss", - "Bricks", - "Bug", - "Chime", - "Coil", - "Cricket", - "Cross", - "Crow", - "Echo", - "Flint", - "Frog", - "Frost", - "Goods", - "Grip", - "Gunner", - "Hammer", - "Hook", - "Ink", - "Junker", - "Mist", - "Moon", - "Nail", - "Needle", - "Ogre", - "Pool", - "Ring", - "Ruby", - "Silver", - "Skinner", - "Song", - "Spur", - "Tackle", - "Thistle", - "Thorn", - "Tick", - "Tick-Tock", - "Tock", - "Trick", - "Twelves", - "Vixen", - "Whip", - "Wicker" - ], - name_suffix: [ - "Jr.", - "Sr.", - "III", - "IV" - ] - }, - GM: { - Bargains: [ - { name: "Infected Wound", category: "Character Effect", effect: "The next time you Recover from Harm, your Physicker is at -1d." }, - { name: "Infected Wound", category: "Character Effect", effect: "The next time you Recover from Harm, your Physicker is at -1d." }, - { name: "Infected Wound", category: "Character Effect", effect: "The next time you Recover from Harm, your Physicker is at -1d." }, - { name: "It's Mine Now", category: "Character Effect", effect: "You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?" }, - { name: "It's Mine Now", category: "Character Effect", effect: "You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?" }, - { name: "It's Mine Now", category: "Character Effect", effect: "You discover a small item that belongs to a rival. What is it? Who used to own it? How does this change things for you?" }, - { name: "Mine By Blood", category: "Character Effect", effect: "You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?" }, - { name: "Mine By Blood", category: "Character Effect", effect: "You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?" }, - { name: "Mine By Blood", category: "Character Effect", effect: "You discover evidence of the death of a family member during the Score. Who is it? How did they die? How does this change things for your character?" }, - { name: "Mine By Name", category: "Character Effect", effect: "You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?" }, - { name: "Mine By Name", category: "Character Effect", effect: "You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?" }, - { name: "Mine By Name", category: "Character Effect", effect: "You discover an envelope addressed to you during the Score. What is in it? Who left it here for you to find? How does this change things for your character?" }, - { name: "Mine By Rights", category: "Character Effect", effect: "You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?" }, - { name: "Mine By Rights", category: "Character Effect", effect: "You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?" }, - { name: "Mine By Rights", category: "Character Effect", effect: "You discover a small item from your past during the Score. What is it? What does it mean that it's here? Does this change things for your character?" }, - { name: "Not Paying Attention", category: "Character Effect", effect: "Uncheck one of the XP triggers already marked for your character for this Score." }, - { name: "Not Paying Attention", category: "Character Effect", effect: "Uncheck one of the XP triggers already marked for your character for this Score." }, - { name: "Shadow From the Past", category: "Character Effect", effect: "Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?" }, - { name: "Shadow From the Past", category: "Character Effect", effect: "Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?" }, - { name: "Shadow From the Past", category: "Character Effect", effect: "Your intel missed that someone from your past is associated with the target of the Score. Who is it, and how does that change things for you?" }, - { name: "Thicker than Blood", category: "Character Effect", effect: "Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?" }, - { name: "Thicker than Blood", category: "Character Effect", effect: "Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?" }, - { name: "Thicker than Blood", category: "Character Effect", effect: "Your intel missed that one of your family members is associated with the target of the Score. How does that change things for you?" }, - { name: "Why'd It Have To Be...", category: "Character Effect", effect: "The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress." }, - { name: "Why'd It Have To Be...", category: "Character Effect", effect: "The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress." }, - { name: "Why'd It Have To Be...", category: "Character Effect", effect: "The room you're in triggers a phobia that the Crew didn't know about before. Describe the phobia and take 2 Stress." }, - { name: "Demonic Guest", category: "Crew Effect", effect: "A demonic presence has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Demonic Guest", category: "Crew Effect", effect: "A demonic presence has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Fracturing Faction", category: "Crew Effect", effect: "If your Hold is Strong, reduce it to Weak. If your Hold is Weak, reduce your Rep to zero." }, - { name: "Lesson Not Learned", category: "Crew Effect", effect: "Uncheck one of the XP triggers already marked for your crew for this Score." }, - { name: "Lesson Not Learned", category: "Crew Effect", effect: "Uncheck one of the XP triggers already marked for your crew for this Score." }, - { name: "Otherworldly Guest", category: "Crew Effect", effect: "A scion of one of the Old Gods has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Otherworldly Guest", category: "Crew Effect", effect: "A scion of one of the Old Gods has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Rebellious Faction", category: "Crew Effect", effect: "A new crew has taken possession of one of your Claims, and will have to be dealt with in Free Play." }, - { name: "Spectral Guest", category: "Crew Effect", effect: "A ghostly presence has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Spectral Guest", category: "Crew Effect", effect: "A ghostly presence has appeared in your Lair and will need to be dealt with during Free Play." }, - { name: "Turncoat", category: "Crew Effect", effect: "One of your Cohorts leaves your crew and joins a rival." }, - { name: "Double-Crossed", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Flipped result." }, - { name: "Double-Crossed", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Flipped result." }, - { name: "Double-Crossed", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Flipped result." }, - { name: "Easily Identified", category: "Downtime Effect", effect: "You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep." }, - { name: "Easily Identified", category: "Downtime Effect", effect: "You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep." }, - { name: "Easily Identified", category: "Downtime Effect", effect: "You left something behind that is easily traced to you. Choose either +2 Heat and −2 Rep, or +1 Heat and −1 Rep." }, - { name: "High Profile", category: "Downtime Effect", effect: "This Score gains +2 Heat." }, - { name: "High Profile", category: "Downtime Effect", effect: "This Score gains +2 Heat." }, - { name: "High Profile", category: "Downtime Effect", effect: "This Score gains +2 Heat." }, - { name: "Most Wanted", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, you are the target of an additional Arrest result." }, - { name: "Most Wanted", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, you are the target of an additional Arrest result." }, - { name: "Project Setback", category: "Downtime Effect", effect: "Mark one less Clock segment the first time you work on a Long-Term Project." }, - { name: "Project Setback", category: "Downtime Effect", effect: "Mark one less Clock segment the first time you work on a Long-Term Project." }, - { name: "Project Setback", category: "Downtime Effect", effect: "Mark one less Clock segment the first time you work on a Long-Term Project." }, - { name: "Quelle Horreur!", category: "Downtime Effect", effect: "You suffer nightmares for a week. −1d to all Downtime Actions after this Score." }, - { name: "Quelle Horreur!", category: "Downtime Effect", effect: "You suffer nightmares for a week. −1d to all Downtime Actions after this Score." }, - { name: "Shortchanged", category: "Downtime Effect", effect: "This Score's payoff is −2 Coin." }, - { name: "Shortchanged", category: "Downtime Effect", effect: "This Score's payoff is −2 Coin." }, - { name: "Shortchanged", category: "Downtime Effect", effect: "This Score's payoff is −2 Coin." }, - { name: "Supply Challenges", category: "Downtime Effect", effect: "The next time you pay Coin for an Acquire Asset roll, you must pay 3 instead of 2 Coin per Tier." }, - { name: "Supply Challenges", category: "Downtime Effect", effect: "The next time you pay Coin for an Acquire Asset roll, you must pay 3 instead of 2 Coin per Tier." }, - { name: "Supply Delays", category: "Downtime Effect", effect: "Suffer -1d to your next Acquire Asset roll." }, - { name: "Supply Delays", category: "Downtime Effect", effect: "Suffer -1d to your next Acquire Asset roll." }, - { name: "Supply Delays", category: "Downtime Effect", effect: "Suffer -1d to your next Acquire Asset roll." }, - { name: "Tastes Like Ashes", category: "Downtime Effect", effect: "The next time you indulge your Vice, only clear half as much Stress (rounded down) as normal." }, - { name: "Tastes Like Ashes", category: "Downtime Effect", effect: "The next time you indulge your Vice, only clear half as much Stress (rounded down) as normal." }, - { name: "Thrice-Named", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result." }, - { name: "Thrice-Named", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result." }, - { name: "Thrice-Named", category: "Downtime Effect", effect: "After the normal Entanglement roll and result, your Crew takes an additional Demonic Notice result." }, - { name: "Warden's Attention", category: "Downtime Effect", effect: "+4 Heat (instead of the normal +2 Heat) if there is a death during this Score." }, - { name: "Warden's Attention", category: "Downtime Effect", effect: "+4 Heat (instead of the normal +2 Heat) if there is a death during this Score." }, - { name: "We Want a Bigger Take!", category: "Downtime Effect", effect: "The gang wants a bigger piece of the action. −2 Coin to Payoff for each Cohort used in this Score." }, - { name: "We Want a Bigger Take!", category: "Downtime Effect", effect: "The gang wants a bigger piece of the action. −2 Coin to Payoff for each Cohort used in this Score." }, - { name: "Weekend Getaway", category: "Downtime Effect", effect: "If you indulge your Vice after this Score, you automatically overindulge." }, - { name: "Weekend Getaway", category: "Downtime Effect", effect: "If you indulge your Vice after this Score, you automatically overindulge." }, - { name: "Weekend Getaway", category: "Downtime Effect", effect: "If you indulge your Vice after this Score, you automatically overindulge." }, - { name: "What's Our Take?", category: "Downtime Effect", effect: "The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score." }, - { name: "What's Our Take?", category: "Downtime Effect", effect: "The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score." }, - { name: "What's Our Take?", category: "Downtime Effect", effect: "The gang wants a bigger piece of the action. −1 Coin to Payoff for each Cohort used in this Score." }, - { name: "Accelerating Plans", category: "Faction Relationship Effect", effect: "A rival faction advances one of its Clocks by two before your next Score." }, - { name: "Accelerating Plans", category: "Faction Relationship Effect", effect: "A rival faction advances one of its Clocks by two before your next Score." }, - { name: "Accelerating Plans", category: "Faction Relationship Effect", effect: "A rival faction advances one of its Clocks by two before your next Score." }, - { name: "Escalating Tensions", category: "Faction Relationship Effect", effect: "A faction of your choice that is unfriendly to your crew moves one step towards War." }, - { name: "Escalating Tensions", category: "Faction Relationship Effect", effect: "A faction of your choice that is unfriendly to your crew moves one step towards War." }, - { name: "Forgiveness or Vengeance?", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship." }, - { name: "Forgiveness or Vengeance?", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship." }, - { name: "Forgiveness or Vengeance?", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts got in a fight with an neutral Cohort. Choose −2 Rep and +1 faction relationship, or +2 Rep and −1 faction relationship." }, - { name: "Hot-Headed Cohort", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship." }, - { name: "Hot-Headed Cohort", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship." }, - { name: "Hot-Headed Cohort", category: "Faction Relationship Effect", effect: "During the Score, one of your Cohorts picked a fight with an allied Cohort. Pay 2 Coin, lose 2 Rep, or −1 faction relationship." }, - { name: "Mixed Messages", category: "Faction Relationship Effect", effect: "A faction of your choice that is friendly to your crew moves one step towards Neutral." }, - { name: "Mixed Messages", category: "Faction Relationship Effect", effect: "A faction of your choice that is friendly to your crew moves one step towards Neutral." }, - { name: "Mutual Defense", category: "Faction Relationship Effect", effect: "A friendly Faction goes to War with a neutral Faction. Either join their War, or they move to −1 on the relationship chart." }, - { name: "Mutual Defense", category: "Faction Relationship Effect", effect: "A friendly Faction goes to War with a neutral Faction. Either join their War, or they move to −1 on the relationship chart." }, - { name: "Tensions Spread", category: "Faction Relationship Effect", effect: "One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally." }, - { name: "Tensions Spread", category: "Faction Relationship Effect", effect: "One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally." }, - { name: "Tensions Spread", category: "Faction Relationship Effect", effect: "One Neutral Faction moves a step towards War, and another Neutral Faction moves a step towards Ally." }, - { name: "The Walls Have Ears", category: "Faction Relationship Effect", effect: "A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating." }, - { name: "The Walls Have Ears", category: "Faction Relationship Effect", effect: "A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating." }, - { name: "The Walls Have Ears", category: "Faction Relationship Effect", effect: "A friendly faction hears you did a Score against their ally. −1 to that faction's relationship rating." }, - { name: "The Walls Have Eyes", category: "Faction Relationship Effect", effect: "A friendly faction hears you did a Score against their ally. −1 to both factions' relationship ratings." }, - { name: "The Walls Have Eyes", category: "Faction Relationship Effect", effect: "A friendly faction hears you did a Score against their ally. −1 to both factions' relationship ratings." }, - { name: "...and Into the Fire", category: "Immediate Effect", effect: "You are ambushed by an assassin or bounty hunter. Start a 4-Clock, 'Elite Ambusher' to overcome this new foe." }, - { name: "...and Into the Fire", category: "Immediate Effect", effect: "You are ambushed by an assassin or bounty hunter. Start a 4-Clock, 'Elite Ambusher' to overcome this new foe." }, - { name: "A Familiar Face", category: "Immediate Effect", effect: "You recognize a contact of your choice among the rivals you are running the Score against." }, - { name: "A Familiar Face", category: "Immediate Effect", effect: "You recognize a contact of your choice among the rivals you are running the Score against." }, - { name: "A Familiar Face", category: "Immediate Effect", effect: "You recognize a contact of your choice among the rivals you are running the Score against." }, - { name: "Accidental Discharge", category: "Immediate Effect", effect: "A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used." }, - { name: "Accidental Discharge", category: "Immediate Effect", effect: "A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used." }, - { name: "Accidental Discharge", category: "Immediate Effect", effect: "A weapon or item you are carrying loudly discharges and needs to be reloaded before it can be used." }, - { name: "All or Nothing", category: "Immediate Effect", effect: "If you fail this roll, you cannot resist the effects of that failure." }, - { name: "All or Nothing", category: "Immediate Effect", effect: "If you fail this roll, you cannot resist the effects of that failure." }, - { name: "All or Nothing", category: "Immediate Effect", effect: "If you fail this roll, you cannot resist the effects of that failure." }, - { name: "Bishop's Gambit", category: "Immediate Effect", effect: "If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Bishop's Gambit", category: "Immediate Effect", effect: "If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Bishop's Gambit", category: "Immediate Effect", effect: "If you are not in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Brute Force Method", category: "Immediate Effect", effect: "You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action." }, - { name: "Brute Force Method", category: "Immediate Effect", effect: "You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action." }, - { name: "Brute Force Method", category: "Immediate Effect", effect: "You noisily break a weapon of your choice while attempting this Action, even if it is not a combat Action." }, - { name: "Clear the Board", category: "Immediate Effect", effect: "If you succeed at this roll, clear or fill a Score Clock of your choice. If you fail the roll, you Trauma out of the scene." }, - { name: "Clear the Board", category: "Immediate Effect", effect: "If you succeed at this roll, clear or fill a Score Clock of your choice. If you fail the roll, you Trauma out of the scene." }, - { name: "Devil's Exchange", category: "Immediate Effect", effect: "You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it." }, - { name: "Devil's Exchange", category: "Immediate Effect", effect: "You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it." }, - { name: "Devil's Exchange", category: "Immediate Effect", effect: "You gain the normal +1d to this roll, but suffer −1d to your next Action, and cannot take a Devil's Bargain to offset it." }, - { name: "Ghostly Attention", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you." }, - { name: "Ghostly Attention", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you." }, - { name: "Ghostly Attention", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, a ghost in the area notices you and begins stalking you." }, - { name: "Gimcrack Gear", category: "Immediate Effect", effect: "Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not." }, - { name: "Gimcrack Gear", category: "Immediate Effect", effect: "Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not." }, - { name: "Gimcrack Gear", category: "Immediate Effect", effect: "Whatever weapon or tool you are using is cheaply made and breaks whether the roll succeeds or not." }, - { name: "Gone Rogue", category: "Immediate Effect", effect: "You cannot accept an Assist for the rest of this Score." }, - { name: "Gone Rogue", category: "Immediate Effect", effect: "You cannot accept an Assist for the rest of this Score." }, - { name: "Hunter Becomes Hunted", category: "Immediate Effect", effect: "You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you." }, - { name: "Hunter Becomes Hunted", category: "Immediate Effect", effect: "You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you." }, - { name: "Hunter Becomes Hunted", category: "Immediate Effect", effect: "You've been so preoccupied with the obstacles in front of you that you didn't notice the rival lining up a shot behind you." }, - { name: "I Know I Packed It!", category: "Immediate Effect", effect: "You must immediately check off 1 Load to no effect, representing equipment you've misplaced." }, - { name: "I Know I Packed It!", category: "Immediate Effect", effect: "You must immediately check off 1 Load to no effect, representing equipment you've misplaced." }, - { name: "I Know I Packed It!", category: "Immediate Effect", effect: "You must immediately check off 1 Load to no effect, representing equipment you've misplaced." }, - { name: "I Know I Packed Them!", category: "Immediate Effect", effect: "You must immediately check off 2 Load to no effect, representing equipment you've misplaced." }, - { name: "I Know I Packed Them!", category: "Immediate Effect", effect: "You must immediately check off 2 Load to no effect, representing equipment you've misplaced." }, - { name: "I Know I Packed Them!", category: "Immediate Effect", effect: "You must immediately check off 2 Load to no effect, representing equipment you've misplaced." }, - { name: "Jangled Nerves", category: "Immediate Effect", effect: "For the rest of the Score, all rolls to Resist generate +1 Stress." }, - { name: "Jangled Nerves", category: "Immediate Effect", effect: "For the rest of the Score, all rolls to Resist generate +1 Stress." }, - { name: "Jangled Nerves", category: "Immediate Effect", effect: "For the rest of the Score, all rolls to Resist generate +1 Stress." }, - { name: "Just a Little Spark", category: "Immediate Effect", effect: "A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'." }, - { name: "Just a Little Spark", category: "Immediate Effect", effect: "A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'." }, - { name: "Just a Little Spark", category: "Immediate Effect", effect: "A lamp or candle gets knocked over, catching a curtain or rug on fire. Start a Clock: 'Building is on Fire'." }, - { name: "King's Gambit", category: "Immediate Effect", effect: "If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action." }, - { name: "King's Gambit", category: "Immediate Effect", effect: "If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action." }, - { name: "King's Gambit", category: "Immediate Effect", effect: "If you fail at this roll, you are immune to any Harm; but you have a zero rating to your next Action." }, - { name: "Knight's Gambit", category: "Immediate Effect", effect: "If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Knight's Gambit", category: "Immediate Effect", effect: "If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Knight's Gambit", category: "Immediate Effect", effect: "If you are in combat, gain +2d for this roll instead of the standard +1d; but you can roll no more than 1d for your next Action." }, - { name: "Knuckle Buster", category: "Immediate Effect", effect: "Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'" }, - { name: "Knuckle Buster", category: "Immediate Effect", effect: "Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'" }, - { name: "Knuckle Buster", category: "Immediate Effect", effect: "Whether this Action succeeds or not, you accidentally inflict level 1 Harm on your hand, 'Busted Knuckles.'" }, - { name: "Now or Never", category: "Immediate Effect", effect: "If you fail this roll, you lose this opportunity and cannot retry it for this Score." }, - { name: "Now or Never", category: "Immediate Effect", effect: "If you fail this roll, you lose this opportunity and cannot retry it for this Score." }, - { name: "Now or Never", category: "Immediate Effect", effect: "If you fail this roll, you lose this opportunity and cannot retry it for this Score." }, - { name: "Out of the Frying Pan...", category: "Immediate Effect", effect: "Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'." }, - { name: "Out of the Frying Pan...", category: "Immediate Effect", effect: "Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'." }, - { name: "Out of the Frying Pan...", category: "Immediate Effect", effect: "Things are about to go from bad to worse. Start a 4-Clock, 'Surprise Reinforcements'." }, - { name: "Overextended", category: "Immediate Effect", effect: "Your next Action automatically has reduced Effect." }, - { name: "Overextended", category: "Immediate Effect", effect: "Your next Action automatically has reduced Effect." }, - { name: "Overextended", category: "Immediate Effect", effect: "Your next Action automatically has reduced Effect." }, - { name: "Pawn's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor." }, - { name: "Pawn's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor." }, - { name: "Pawn's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Armor during this Score. You cannot accept this bargain if you already have used Load for Armor." }, - { name: "Plan C...", category: "Immediate Effect", effect: "Things are not going according to plan. Flashbacks cost +1 Stress for the rest of the Score." }, - { name: "Plan C...", category: "Immediate Effect", effect: "Things are not going according to plan. Flashbacks cost +1 Stress for the rest of the Score." }, - { name: "Queen's Gambit", category: "Immediate Effect", effect: "You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action." }, - { name: "Queen's Gambit", category: "Immediate Effect", effect: "You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action." }, - { name: "Queen's Gambit", category: "Immediate Effect", effect: "You automatically succeed at this Action as if you rolled a 6; but you have a zero rating to your next Action." }, - { name: "Quicksilver Poisoning", category: "Immediate Effect", effect: "Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal." }, - { name: "Quicksilver Poisoning", category: "Immediate Effect", effect: "Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal." }, - { name: "Quicksilver Poisoning", category: "Immediate Effect", effect: "Used in electroplasmic containers and devices, you get a noseful of quicksilver vapor, suffering level 1 Harm, 'Silverlung' which starts a 4-Clock Project to heal." }, - { name: "Rook's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these." }, - { name: "Rook's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these." }, - { name: "Rook's Gambit", category: "Immediate Effect", effect: "You cannot use Load for Unusual or Scary Weapons this Score. You cannot accept this bargain if you already have used Load for these." }, - { name: "Shot Nerves", category: "Immediate Effect", effect: "For the rest of the Score, all rolls to Resist generate +2 Stress." }, - { name: "Shot Nerves", category: "Immediate Effect", effect: "For the rest of the Score, all rolls to Resist generate +2 Stress." }, - { name: "Turned Around", category: "Immediate Effect", effect: "You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them." }, - { name: "Turned Around", category: "Immediate Effect", effect: "You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them." }, - { name: "Turned Around", category: "Immediate Effect", effect: "You lose track of your position. Start a 4-Clock, 'Where Am I?' You must use Actions looking for your Crew to rejoin them." }, - { name: "Unsure Footing", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, you loose your footing and fall prone after this Action." }, - { name: "Unsure Footing", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, you loose your footing and fall prone after this Action." }, - { name: "Unsure Footing", category: "Immediate Effect", effect: "Whether you succeed in this roll or not, you loose your footing and fall prone after this Action." }, - { name: "Worse than We thought", category: "Immediate Effect", effect: "A Clock of your choice that is running for this Score is either advanced or set back by two segments (whichever is worse for the Crew)." }, - { name: "Worse than We thought", category: "Immediate Effect", effect: "A Clock of your choice that is running for this Score is either advanced or set back by two segments (whichever is worse for the Crew)." }, - { name: "You're All On Your Own", category: "Immediate Effect", effect: "After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score." }, - { name: "You're All On Your Own", category: "Immediate Effect", effect: "After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score." }, - { name: "You're All On Your Own", category: "Immediate Effect", effect: "After this roll, you cannot offer to Assist on anyone else's roll for the rest of the Score." }, - { name: "Death Will Not Stop Me", category: "Long-Term Effect", effect: "The ghost of someone you killed is driven to take you with it. Start a 12-Clock, 'Spectral Vengence'" }, - { name: "That's Enough of That", category: "Long-Term Effect", effect: "Someone whose goals are affected by this Score is going to focus on you now. Start a 8-Clock, 'Cold Vengence'" }, - { name: "That's Enough of That", category: "Long-Term Effect", effect: "Someone whose goals are affected by this Score is going to focus on you now. Start a 8-Clock, 'Cold Vengence'" }, - { name: "The Last Straw", category: "Long-Term Effect", effect: "You've royally pissed off someone with real clout in the city. Start a 12-Clock, 'Furious Vengence'" }, - { name: "You'll Pay For This", category: "Long-Term Effect", effect: "Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'" }, - { name: "You'll Pay For This", category: "Long-Term Effect", effect: "Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'" }, - { name: "You'll Pay For This", category: "Long-Term Effect", effect: "Someone hurt by this Score will come back to collect what's owed. Start a 6-Clock, 'Petty Vengence'" }, - { name: "Dalgomur, the Heart of the Storm", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 12-Clock labeled 'The Heart of the Storm' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Dalgomur, the Heart of the Storm", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 12-Clock labeled 'The Heart of the Storm' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Ulf Ironborn, the Skovlan Agitator", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 4-Clock labeled 'Skovlander Uprising' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Ulf Ironborn, the Skovlan Agitator", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 4-Clock labeled 'Skovlander Uprising' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Urumbar, the Closed Eye", category: "Mandatory Effect", effect: "If one is not already active for the crew, start an 8-Clock labeled 'The Closed Eye' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Urumbar, the Closed Eye", category: "Mandatory Effect", effect: "If one is not already active for the crew, start an 8-Clock labeled 'The Closed Eye' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Vaskani, the Crossroads Demon", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 6-Clock labeled 'The Crossroads Demon' and set it to one. If the Clock is already active, advance it by one." }, - { name: "Vaskani, the Crossroads Demon", category: "Mandatory Effect", effect: "If one is not already active for the crew, start a 6-Clock labeled 'The Crossroads Demon' and set it to one. If the Clock is already active, advance it by one." } - ], - Obstacles: [ - { - name: "Centipedes", - category: "Animal Guards", - desc: "Centipedes the length of a forearm are almost noiseless. If they bite, their toxin causes living flesh to blacken and die, leading to amputation if the poison isn't countered. People tend to scream when bit.", - questions: [ - "Were the centipedes brought in as guardians, or are they a local nuisance?", - "There are many different breeds, how will you describe the appearance of yours?", - "Do they have a nasty local nickname?" - ], - modsHarder: [ - "When one attacks it releases a scent that enrages others nearby, so they tend to swarm.", - "They are excellent swimmers, and they hunt in bog-like areas under the surface." - ], - modsEasier: [ - "They are bright yellow and red, and hiss before striking, giving all the warning possible.", - "All the guardians and neighbors carry the antidote, the local apothecary knows what you need." - ] - }, - { - name: "Great Cats", - category: "Animal Guards", - desc: "One or more great cats slink through the shadows. They like to attack from high places. Their fur mottles to match the colors and tones and textures around them.", - questions: [ - "Did the current owners bring them in, or are they inherited from a previous owner?", - "Do they stay on the estate, or go hunting in the local neighborhood?" - ], - modsHarder: [ - "The cats are trained to alert guards (or wear charm jewelry to alert supernatural guardians) when they detect intruders with their keen senses.", - "Massive old trees draped with moss, or many ledges and overlooks, provide the cats cover." - ], - modsEasier: [ - "There is only one, with a regular feeding time and place.", - "The cats are well fed and lazy, mostly for show unless provoked." - ] - }, - { - name: "Hunting Spiders", - category: "Animal Guards", - desc: "These lightning-fast nightmares are about twenty pounds and three feet across, built like jumping spiders and loaded with paralytic venom.", - questions: [ - "Were these spiders bred for a decadent aristocrat, or warped to this impossible size by an insane whisper?", - "Can they survive away from a spirit well?", - "What noise do they make?", - "How do they smell?" - ], - modsHarder: [ - "They are mostly trained, their handler using a slide whistle to give orders to hunt, attack, withdraw, or guard.", - "The color of the stone, the shape of the underbrush, the leaf litter--everything matches the spider color scheme and hides its movement." - ], - modsEasier: [ - "Little lasting harm at first; paralyzed prey is dragged back to a lair and webbed up. You have a day or so to rescue the prey before the spider injects acid into the web bundle so it can drink its victim.", - "The poison is weak and easy to resist, requiring several successful bites to put a human down." - ] - }, - { - name: "Mastiff Pack", - category: "Animal Guards", - desc: "A pack of mastiffs have run of the guarded area when it is not in more public use. They only respond to their masters, who have special tunics, whistles, and gloves. They kill anyone or anything else.", - questions: [ - "What is their heraldry?", - "How many mastiffs are in the pack?", - "Are they trained well enough to ignore poisoned meat or live animal distractions?" - ], - modsHarder: [ - "Each one is precious to the site owner, who will tirelessly seek vengeance if they are hurt.", - "The pack masters are elite veterans with firearms and excellent tracking and hunting skills." - ], - modsEasier: [ - "The equipment is properly installed, its vulnerable parts behind the energy curtain, directly guarding what needs protecting.", - "The lightning walls attract loose spirits, intruders may also have to contend with confused ghosts." - ] - }, - { - name: "Venomous Snakes", - category: "Animal Guards", - desc: "Venomous snakes have lairs prepared for them in the guarded area.", - questions: [ - "How fast acting is their venom?", - "How aggressive are they?", - "Is their hide camouflage for hunting, or bright to warn away predators?", - "Are there only a few big ones, or many small snakes?", - "Do the site guardians feed them, or can they find enough vermin on their own?" - ], - modsHarder: [ - "Knee-deep plants and elevation shifts intentionally make it difficult to see snakes.", - "Other guardians have a side business in selling venom and meat and hides. They have venom blowdarts and poisoned daggers." - ], - modsEasier: [ - "The snakes dislike a certain whistle tone. Let out a blast occasionally and they'll stay away.", - "A former employee knows how guardians got around the site with minimal risk of snakes." - ] - }, - { - name: "Armor Hosts", - category: "Ghostly Guards", - desc: "Guardian spirits are able to inhabit a crystal melded to each suit of armor in a guarded area. When melded, the spirit can control the armor. Spirits use the armor to attack intruders.", - questions: [ - "Were the suits of armor built for this purpose, or retrofitted by a spirit trafficker?", - "Are the guardian spirits loyal, or were they stripped of their will by a ritual or other power?", - "Are the suits visibly paranormal?" - ], - modsHarder: [ - "A single powerful (relatively sane) spirit can flit from armor to armor, backed up by two slave spirits. The guardian can form an electroplasmic face in the helmet to sneer at intruders.", - "A swarm of spirits are eager to take their turn in armor. When one tires another drops in.", - "Ceaseless patrol." - ], - modsEasier: [ - "The ghost(s) that animate the armor are murderous and difficult to control.", - "The guardians can play a chime to recall them to a restraining prism.", - "The suits of armor are old, battered, and prone to physical failure." - ] - }, - { - name: "Coldrooms", - category: "Ghostly Guards", - desc: "The defended area is kept cold. Body heat registers like a plume of blood in the water. Ghosts flood living meat with cold, gorging on body heat, becoming more visible as their outlines swirl with life-blood.", - questions: [ - "Were they created by ritually starving victims to death in the defended space?", - "Were they stolen from the site of a massive horrific disaster?", - "Does a spirit trafficker maintain the wards on the space?" - ], - modsHarder: [ - "A dead whisper leads them, countering defensive charms and magic, sniffing out breath even if heat is concealed, dueling any supernatural defense.", - "The guarded area is powerfully warded and underground where temperature is easy to maintain." - ], - modsEasier: [ - "The guarded area is vulnerable to weather conditions. It is sharp in the cold, but almost dormant in the heat.", - "A relatively simple spirit bane charm can keep them at bay if created in tune with the site." - ] - }, - { - name: "Cursed Treasure", - category: "Ghostly Guards", - desc: "Treasures are infused with a haunting spirit. Anyone touching the treasure will be cursed, dreaming the crimes of the ghost and attracting anger and distaste from strangers. Friends become uncomfortable and suspicious around the cursed scoundrel.", - questions: [ - "Were those sacrificed to make the haunts loyal, serving past death, or punished by undeath?", - "Is the treasure marked as cursed?" - ], - modsHarder: [ - "The haunting is so deadly that it drives most victims to suicide within a week. Resourceful scoundrels with access to spirit traffickers have days to somehow break the hold. Others are doomed.", - "Electroplasmic poisoning begins, and within a week the scoundrel will become a vampire." - ], - modsEasier: [ - "All the bad luck waiting in the wings (unfinished clocks from foes, poorly protected stashes, jilted lovers, false identities) go wrong in quick succession. Then the curse is over.", - "A competent occultist can break the curse as a down time project with a four segment clock." - ] - }, - { - name: "Darkrooms", - category: "Ghostly Guards", - desc: "The defended area is dark. The ragged ghosts hate light. They shriek horribly as they attack light sources with slapping leathery hands, like bat wings. Intruders may glimpse their luminous fangs.", - questions: [ - "Were these ghosts placed here intentionally, or are they the result of some horror that left a print in the Ghost Field?", - "Is this defense maintained, or passive?" - ], - modsHarder: [ - "Another guardian lurks in the dark and takes advantage of the distraction to steal from intruders, perhaps killing them too.", - "The ghosts are aggressive, pushing intruders. Surroundings include long drops, spikes, mazes, or other hazards difficult to navigate in darkness." - ], - modsEasier: [ - "While annoying, they do no real damage, and forewarned scoundrels may prepare unbreakable light sources or supernatural dark vision.", - "There is enough ambient light to see." - ] - }, - { - name: "Dynastic Hive", - category: "Ghostly Guards", - desc: "Ancestors have been ritually infused into the defense site, it is a dynastic holding. The spirits are old, and insane, but strategically placed to act out their madness in the most damaging way.", - questions: [ - "Did the family get special permission to harbor ghosts?", - "Do they have connections to limmers?", - "Are spirits tied to leviathan bone shards?", - "Are they moving pictures, or conversationalists with clues?" - ], - modsHarder: [ - "The ghosts are legally protected, like landmarks or artwork. Damaging them is a serious crime.", - "Some of the more powerful or canny ghosts are still somewhat sane collaborators with the site owners." - ], - modsEasier: [ - "They are out of control, and few dare to enter the site now (or it is abandoned.)", - "They will not harm family members (but may not react well to hostages.)" - ] - }, - { - name: "Hunting Ghostpack", - category: "Ghostly Guards", - desc: "A group of weaponized ghosts haunts the defended area. They are capable of scouting to find intruders, descending on them with lethal force.", - questions: [ - "Do they appear as a pack with a mounted hunter, spectral hounds, and a ghostly horn call?", - "Or an armored warband?", - "Shapeless lethal electroplasmic stalkers?", - "Are the wounds they inflict bloody cuts, or hard frostbite?", - "Is their area surrounded with runes that let them see into the material world?" - ], - modsHarder: [ - "The ghost leader feels all life force in its hunting ground, knowing its location.", - "The hunt can only rise when certain conditions like anniversaries, moon phases, etc. are met. However, they have a treasure that can only be taken from them when they manifest." - ], - modsEasier: [ - "The attack is purely psychological, killing with supernatural fear. The effect can be resisted.", - "They are summoned and directed by a command artifact like a hunting horn or special weapon. If someone else tunes to the weapon, control (and its obligations) may shift to a new bearer." - ] - }, - { - name: "Possession Gate", - category: "Ghostly Guards", - desc: "If an intruder breaks a clearly marked seal, the intruder is attacked by a possessing spirit that takes on the traits of the most strong-willed, brutal person the seal-breaker ever killed. The possessing spirit and the seal-breaker struggle for control. This counts as a harm.", - questions: [ - "Is the possessing spirit a ghost, or a shape-shifting construct made by an expert that makes a shape out of something in the target?", - "If an innocent triggers the trap, what form does the spirit take then?" - ], - modsHarder: [ - "The only way to be free is to die, undergo electroplasmic surgery while dead, and be revived. Otherwise the curse is protected by the victim's life force.", - "The haunting spirit tries to take possession once a day or so, sending the host into a blackout and acting out vicious crimes against allies, loved ones, and bluecoats." - ], - modsEasier: [ - "The condition can be reduced with a resist roll, but still is likely a 6 segment clock to clear.", - "The curse haunt would rather have a host ally than kill its victim, and may bargain for shared control." - ] - }, - { - name: "Spirit-Infused Art", - category: "Ghostly Guards", - desc: "Art works are haunted by spirits that are capable of spying. They observe their area, and may be able to murmur about what they see to a guardian.", - questions: [ - "Was art repurposed to host spirits, or was it created for them and around them?", - "Is the art mosaics, portraits, statues, or some other form?", - "How sane and coherent are the spirits?", - "How loyal are they?", - "Do they have the power to attack intruders?" - ], - modsHarder: [ - "One or more guardians has a signet ring tuned to the haunted art pieces, and can hear what they whisper as they spy.", - "The ghosts inhabiting the art can move from one piece to another, following intruders or retreating to report." - ], - modsEasier: [ - "One spirit per art piece, and each spirit has its own unbalanced personality.", - "Unhinged art is violent, so it has to be shrouded or restrained when guardians go through the defended area." - ] - }, - { - name: "Starving Fog", - category: "Ghostly Guards", - desc: "The guarded area is in a clinging cold fog. Fog draws energy from those breathing in it until it manifests shadows that increase target fear, which feeds it more. Eventually it can manifest a killing shape.", - questions: [ - "What do intruders in the fog see when it reflects their fears?", - "Are there sound effects, smells, and sounds, or just fleeting glimpses and silhouettes?", - "Does it project hallucinations or trigger memories?" - ], - modsHarder: [ - "The fog strengthens the Ghost Field, making ghosts within it more powerful.", - "The fog can move, summoned or controlled by other guardians to provide backup or help search." - ], - modsEasier: [ - "The fog is generated by an artifact. If the artifact is neutralized so is the fog.", - "Those with the proper energy keyed amulet or other trinket are invisible to the fog." - ] - }, - { - name: "Sweat Nectar", - category: "Ghostly Guards", - desc: "The defended area is kept hot. Sweat tastes like nectar to swarming ghosts, who dehydrate targets into mummies. The stolen life force and moisture flows to prepared corpses, so ghosts can ride them again.", - questions: [ - "Were they created by dehydrating sacrifices to death in the defended space?", - "Were they gathered from outside the lightning walls to stand guard here?", - "Does a spirit trafficker maintain the wards on the space?" - ], - modsHarder: [ - "Many prepared corpses are stashed in unexpected places, bursting into combat when rejuvenated.", - "Once they rise, the desiccated spirit-ridden corpses will chase intruders until they can't." - ], - modsEasier: [ - "Only a few corpses are left to revive.", - "The site is difficult to keep hot enough to extract the necessary sweat from intruders." - ] - }, - { - name: "Dartus Weed", - category: "Supernatural Plants", - desc: "When something moves near a tangled bank of dartus weed, the vines flex, flicking barbed tips towards the source of motion within arm's reach. The darts are paralytic; a target will pass out for about an hour.", - questions: [ - "Do they have a distinctive flower or smell?", - "What is the aftertaste of the poison's effect?" - ], - modsHarder: [ - "Hounds with chemically toughened hides patrol the weed banks, brutally killing intruders.", - "Weed banks are cultivated strategically, flanking important doorways or draped over arborwalks, straggling along verges." - ], - modsEasier: [ - "The weeds are young. Darts can be stopped with thick leather.", - "Weed banks are out of the way of defended valuables, but too close to very annoyed neighbors who may hold a grudge." - ] - }, - { - name: "Dreamspore Shrooms", - category: "Supernatural Plants", - desc: "Placed on the ceiling, they drizzle sandy spores when they sense motion below. Victims hallucinate, heightening subconscious emotion (so they are very mellow, or super anxious, or filled with rage, etc.).", - questions: [ - "Were these intended to be a site defense?", - "Did they instead serve a religious or recreational function?", - "Are there special techniques for harvesting them, perhaps selling them to alchemists?" - ], - modsHarder: [ - "A more intense strain, these can knock out those who succumb, and give them vivid dreams for several hours.", - "They are placed near other guardians as well as hazards like a steep drop or running water." - ], - modsEasier: [ - "Other guardians come here recreationally, their effectiveness reduced.", - "The spores are weak and easier to resist." - ] - }, - { - name: "Floormesh", - category: "Supernatural Plants", - desc: "Flat vines grow together to make flooring. Connected below is the bulb, covered in venomous spikes. Anyone heavier than a child will fall through. Blood and rot feed the floormesh.", - questions: [ - "Have site defenders put carpet over the flat vines to further hide the threat?", - "What colors, textures, and patterns does this version have?", - "How dangerous is the venom?" - ], - modsHarder: [ - "The building's architecture assumes use of floormesh, the carpets are woven to look like floormesh so the guardians don't have to cover the actual pits.", - "The mesh itself has venomous thorns in it, so stepping on it or falling through poisons the target." - ], - modsEasier: [ - "The pit is not cleaned, the area near it stinks heavily of corpserot. The mesh sags visibly.", - "Floormesh is mostly hung like tapestries, living decorations, rather than forming pit traps." - ] - }, - { - name: "Ghost Crystal Topiary", - category: "Supernatural Plants", - desc: "Ghost crystals are worked into the roots of fancifully trimmed bushes. Ghosts may be able to inhabit the bushes and make them move. This gardening curiosity can be weaponized.", - questions: [ - "Is this a currently maintained garden, or one that is overgrown and abandoned?", - "Who provides the necessary skilled care to create or maintain the topiary?", - "Is there a theme to the sculptures?" - ], - modsHarder: [ - "Certain of the most powerful bushes can uproot and move around like living green golems driven by electroplasmic energy.", - "The bushes hardly move, but the powerful energies of the crystals make ghosts much more coherent and powerful in the garden." - ], - modsEasier: [ - "Left unprotected at one point, the garden was raided by thieves after the ghost crystals. Few crystals are left in the shaggy bushes.", - "Incompetent handling has drained most of the power from the crystals." - ] - }, - { - name: "Keenshrooms", - category: "Supernatural Plants", - desc: "These fist-sized mushrooms let out a keening wail when light comes within about thirty feet.", - questions: [ - "What do they look like?", - "Is their smell distinctive?", - "Are they good eating?" - ], - modsHarder: [ - "They are strategically placed to surprise intruders; inside doors, on ceilings, in alcoves, behind statues.", - "Masses of keenshrooms have been allowed to coat walls or fill rooms, and their keen is strong enough to deafen or kill." - ], - modsEasier: [ - "The keenshrooms were placed too close to trafficked paths inside or outside the defended site. Constant false alarms dull vigilance.", - "Too far from site defenders, their keens are seldom investigated." - ] - }, - { - name: "Murder Tree", - category: "Supernatural Plants", - desc: "The willow tree grew around bones wired to it, spirit crystals studded in its bark, and leviathan blood at its roots. lt is dimly self-aware. It senses and hates life, whipping and clubbing any who approach.", - questions: [ - "How do guardians move around the tree?", - "Suggestions include knowing passwords, having enchanted amulets, or attuning to its blind spots. How many guard the site?", - "Who had the expertise to cultivate this living weapon, how long ago?" - ], - modsHarder: [ - "The chorus of semi-aware spirits that fuel the tree are enslaved by one domineering will. The tree is as coherent as a person.", - "Multiple murder trees are connected by roots and share knowledge with each other (and any other site guardians.)" - ], - modsEasier: [ - "No one can communicate with the murder tree, or control it, so it is isolated from other defenses.", - "The tree sleeps most of the time, and it is difficult to rouse it to fighting fury." - ] - }, - { - name: "Snatchweed", - category: "Supernatural Plants", - desc: "It grows in fresh water, lengthening its long winding tendrils almost to the surface. When touched, it snatches and pulls, coiling down to the bottom and holding for a few minutes before relaxing back up.", - questions: [ - "Is their growth boosted supernaturally, and can you see faces reflecting from the Ghost Field beneath their fronds?", - "Are the locals aware of the threat, willing to talk about it?" - ], - modsHarder: [ - "Snatchweed is cultivated in areas where intruders must enter the water to get past other obstacles.", - "The bottom of the water has two foot spikes, victims are pulled down onto them." - ], - modsEasier: [ - "A sign warns of the hazard, as required by law.", - "This particular breed of snatchweed recoils from salt; put enough on the surface and tendrils recoil." - ] - }, - { - name: "Thirstclimber", - category: "Supernatural Plants", - desc: "The vines are red, and when flesh touches them (even through leather) the vine draws blood to the surface in alarming quantities. The vines are slippery, and almost impossible to grasp with wet hands.", - questions: [ - "Are the vines clearly visible to those who can see in the Ghost Field?", - "Do the vines cause damage that must be healed, or does the blood only flow when they are nearby?" - ], - modsHarder: [ - "The site has guard creatures that track by scent and are drawn to attack things that smell bloody.", - "Thirstclimber is cultivated at the mid-point of a really difficult climb." - ], - modsEasier: [ - "Annoyed locals keep it trimmed back on outside walls periodically in spite of the guardian's threats.", - "Guards know the ingredients to make a special paste, and the symbol to paint on skin with it, to protect from the plant's effects. A former guard might share the secret." - ] - }, - { - name: "Thirsty Thorns", - category: "Supernatural Plants", - desc: "Strategically placed thornbushes grow on walls and serve as decorations. They live on blood. They only flower if something dies on them; the bigger the life, the more impressive the bloom.", - questions: [ - "Do they feed on radiant light?", - "Are they along the interior walls, lining the walks, and climbing walls outside?", - "Are there thorns inside, along windows or protecting secret doors?" - ], - modsHarder: [ - "The thorns are poisonous, inflicting some condition on those who fail to resist.", - "Possibilities include sleep, death by choking, blinding blood from the eyes, or paralysis.", - "The thorns are considered a gardening achievement, with some fame and support as local culture." - ], - modsEasier: [ - "A custom amulet tuned to their life energy turns the thorns away, allowing its bearer to push through them unharmed. A site defender may have one, or one could be made.", - "They are old and brittle, dying by inches and neglected." - ] - }, - { - name: "Vine Curtains", - category: "Supernatural Plants", - desc: "Curtains of vines connect back to a radiant root that has grown semi­aware, fed on rogue spirits. If touched, the vines slither and writhe to entangle, hoist, and bundle the target for a guardian to find.", - questions: [ - "What do the vines look like?", - "Do they use their scent to attract or repel?", - "Where is the root relative to the curtain?" - ], - modsHarder: [ - "Many curtains and roots of different sizes (some quite big) connect back to a central bulb somewhere in the defense site.", - "The vines also have a contact poison that makes their target go limp for 10-60 minutes." - ], - modsEasier: [ - "The site owner does not have legal permission to have the vine curtains, so they are only used inside.", - "The vine curtains grow wild and the lazy site owner does not keep them trimmed back, so other guards must stay away from them." - ] - }, - { - name: "Caul Piercers", - category: "Traps", - desc: "Piercers are designed to puncture whoever touches them. They pierce the energy caul of the character's life force in the Ghost Field. This causes a harm condition that worsens or costs stress every down time cycle until the caul can be mended (6 segment project.) Interpret as needed.", - questions: [ - "Do the piercers resemble knives, nails, or thorn-like carvings?", - "What sadistic expert crafted these dire traps?", - "If pried out of their settings, how long do they retain potency?" - ], - modsHarder: [ - "Those affected will trail life energy like a wounded fish bleeding in the water; demons and ghosts alike will investigate the scent.", - "They are worked into important doorknobs, strategic ledges, and concealed flooring." - ], - modsEasier: [ - "They all look alike and are similarly placed, relying on surprise to be effective.", - "They are only on the main treasure." - ] - }, - { - name: "Collapsing Ceilings", - category: "Traps", - desc: "If triggered, this trap drops a mass of stone. That seals off the threatened area, and crushes anyone tampering with its defenses.", - questions: [ - "Who put valuables behind a trap that could seal them away for good?", - "How old is this defense, and who takes care of it?", - "What warning signs tip off an intruder that continuing is dangerous?" - ], - modsHarder: [ - "Hidden mechanisms can raise the block back up to the ceiling, so the trap can be reused (or defeated remotely.)", - "More than one block falls; the first one cuts off escape, then death seems inevitable." - ], - modsEasier: [ - "The stone dropped long ago. Site guardians or intruders have developed ways to climb over it or get past it. Other blocks may still be untriggered, but some of them are no longer dangerous.", - "More like a mine collapse, difficult to control and possible to tunnel past." - ] - }, - { - name: "Combination or Trick", - category: "Traps", - desc: "Various portals and defenses of the site are protected by combination locks or riddles to solve. Lockpicks will not work against them, though finesse may solve them eventually.", - questions: [ - "Are there a series of combination locks expressing a religious or eccentric worldview?", - "Are there picture arranging puzzles, or unusual keys to go in sculpture locks?", - "Are the locks mechanical or supernatural?" - ], - modsHarder: [ - "Powerful runic work or enslaved ghosts make the obstacle difficult to smash or trick--the right combination or object must be used to bypass it.", - "Clues and needed items are spread across a large estate, or multiple estates." - ], - modsEasier: [ - "The combination or solution to the puzzle is in a scholarly work, and can be found or bought ahead of time.", - "The solutions are painfully obvious to someone with the right upbringing and background." - ] - }, - { - name: "Contact Needles", - category: "Traps", - desc: "Small needles are worked into contact surfaces and poisoned, to deter intruders. They may be on doorknobs, seat backs or cushions, doorframes, stair treads, ledges, beds—anywhere, really.", - questions: [ - "Are the needles easily visible if you look for them, or camouflaged?", - "Are they retractable if you know what you're doing?", - "What kind of poison is on them?", - "Will the victim sleep, freeze, die, or hallucinate?" - ], - modsHarder: [ - "The needles are only corporeal to those who touch them without wearing a certain amulet. Important site guardians are immune to the needles.", - "Anything important or at an unguarded entry point is going to be festooned with needles." - ], - modsEasier: [ - "They are not well maintained. Many have snapped off, and few retain much poison.", - "They are only on the most important objects or the most useful trap objects (like a chair for guests.)" - ] - }, - { - name: "Excellent Locks", - category: "Traps", - desc: "Beyond simple security, these locks are works of art. They are higher potency than they would normally be. Also, they are equipped with poison needle traps, or pick breakers, or redundancies.", - questions: [ - "Who put in these superior locks, and for what reason?", - "Are the locks designed to defeat entry, or actively punish intruders?", - "Do the specialized keys have a distinctive look, like two flanges?", - "Is there a master key?" - ], - modsHarder: [ - "Everything is locked, and all the locks are good. Somebody had a real lock problem.", - "The locks involve supernatural components, like hidden keyholes or paralyzing energy." - ], - modsEasier: [ - "The locks are in poor repair, of variable quality after indifferent maintenance and many intrusion attempts.", - "Very fancy locks, but they are padlocks, and bolt cutters can circumvent the problem." - ] - }, - { - name: "Murder Holes", - category: "Traps", - desc: "Intruders go past one door, into a hallway or small room, and the door closes behind them. Arrow slits open in the walls, and slots in the ceiling allow boiling oil to be poured down. Intruders are trapped and vulnerable. These are often in doors through defenses.", - questions: [ - "Was the original site builder often under siege?", - "Are the murder holes obvious or concealed?" - ], - modsHarder: [ - "Murder holes are automated with self- slamming doors and pre-boiling oil, so a few defenders can trap and/or kill many intruders.", - "The whole layout is built with many murder hole areas to deter invasion." - ], - modsEasier: [ - "The walls are wooden, and determined captives can break through to face their attackers.", - "This area does not have enough staff to monitor intruders and make best use of murder holes." - ] - }, - { - name: "Pit Traps", - category: "Traps", - desc: "The defended site has pit traps in strategic places. They are between 10 and 40 feet deep.", - questions: [ - "Do they have slick sides?", - "Are there spikes at the bottom?", - "Are the covers mechanized, or flimsy boards and carpets, grass turf, or leaves over canvas?", - "Are the sides stone, earth, or clay?" - ], - modsHarder: [ - "Fist sized tunnels connect pits. Predatory creatures (crabs, snakes, spiders, rats) scurry to devour victims.", - "Once someone falls into the pit the covers close again, and will not open until unlocked." - ], - modsEasier: [ - "The pits drop into a lower area, mostly abandoned except for predators. It is possible to find a way out.", - "The pits are mostly open and filled with junk." - ] - }, - { - name: "Retractable Spikes", - category: "Traps", - desc: "Spring-loaded spears or racks of spears launch at intruders. They can come from the side, behind, ahead, below, or above.", - questions: [ - "Are the defenses standardized to protect guardians, or random to confuse intruders?", - "Are they in an area that site defenders use, or in an isolated off-limits area?", - "How long have they been in use, and how often are they maintained?" - ], - modsHarder: [ - "After doing their killing work, they retract, and the launch points are not obvious.", - "The spears are slathered with some toxin, further affecting the victim." - ], - modsEasier: [ - "The mechanisms are not well maintained. Sometimes they don't work, and when they do, there is a screech and they are a bit slow.", - "The spears are designed to pin an intruder in place, to be interrogated and punished, rather than to kill outright." - ] - }, - { - name: "Secret Doors & Spyholes", - category: "Traps", - desc: "Guardians are well trained in the use of numerous secret doors and hidden passages with spyholes. They can attack from unexpected directions, escape without a trace, and watch intruders unobserved.", - questions: [ - "Was this site built by a spy, or a cult, or a paranoid aristocrat?", - "Are there consistent tells, a code built into the decor and architecture, or must all secrets be known individually?" - ], - modsHarder: [ - "Ongoing rearrangement and construction means old information from plans or people ages out fast.", - "Supernatural locks and keys mean that triggers and spyholes and seams may not be visible in the material world at all." - ], - modsEasier: [ - "Frequent use has made secret doors easier to spot. Poor baffling of lights may reveal spyholes in use.", - "Current residents are only aware of some secrets; intruders may use back ways to elude security." - ] - }, - { - name: "Shock Grips", - category: "Traps", - desc: "One or more contact points are connected to energy so they will badly shock anyone who touches them. These could be doorknobs, chest lids, floor plates, ladders, and so on.", - questions: [ - "Are they powered by batteries or enslaved ghosts?", - "Does the site have legal permission to use them?", - "How loud is the shock?", - "How do site guardians avoid getting shocked?" - ], - modsHarder: [ - "The shock grips are numerous and concealed, connected to their energy source through the Ghost Field.", - "The shock is designed to stop the heart and kill the victim (possibly setting hair on fire.)" - ], - modsEasier: [ - "The shock grips are connected to control boxes and energy sources by cables.", - "Shock grips are marked by a rune, and shiny, and also give out a palpable hum of energy. They are easy to detect." - ] - }, - { - name: "Brutal Sadists", - category: "Twisted Guards", - desc: "Only brutal sadists are hired on as guards. They have permission to play with captured intruders.", - questions: [ - "Is the owner of the protected property aware of this cultural rule, or are guards hired by an employee?", - "Do they share cultural roots (slaughterhouse workers, leviathan hunters, soldiers, city guards, etc)?", - "How do the neighbors feel about their occasional scandals?" - ], - modsHarder: [ - "Several of them are skilled in both torture and interrogation; they extract secrets from intruders. A side business in blackmail helps them avoid legal trouble.", - "They are hardened veterans, exceptionally tough and dangerous. They aim to incapacitate." - ], - modsEasier: [ - "Their ugly tactics and poorly chosen victims have earned them (and their employer) enemies in lots of unexpected places.", - "They really, really like to drink." - ] - }, - { - name: "Close-Knit Guard Network", - category: "Twisted Guards", - desc: "Guards are only hired by referral. Failure results in punishment for both the guard and the sponsor. Their loyalty is tested many ways before and after they are hired.", - questions: [ - "Do they favor bastards of the employer?", - "Are they connected to one military unit?", - "Are they refugees from another place?", - "Do they come from a single neighborhood?", - "Does punishment extend to their families?" - ], - modsHarder: [ - "They are connected to a larger sponsoring organization that would seek vengeance if they are attacked or insulted, and also offer them favors.", - "They speak in code and have passwords that include safewords and warnings." - ], - modsEasier: [ - "Nepotism has pulled in some really incompetent guards.", - "Endless drama from working with family and friends." - ] - }, - { - name: "Compulsive Detail Focus", - category: "Twisted Guards", - desc: "Only a certain type is hired; a type that checks every lock and every dark corner. Schedules are strict, thoroughness is a guarantee, and they seem unable to cut corners or skip steps. Everything is by the book.", - questions: [ - "Are they altered to be like this, or just screened for a mindset?", - "What are the detailed parts of the defended site that need this kind of attention?", - "How does their gear reflect this fussy attention to detail?" - ], - modsHarder: [ - "There are other elements of the defended site that require their focus, like a pattern of stepping over tiles to avoid triggering traps or complex combination locks or dozens of cells with dangerous prisoners.", - "They are trusted with specialty items like firearms or charms because they are responsible with them." - ], - modsEasier: [ - "Everyone knows that they fall apart if things deviate from the pattern, like distractions or chaos.", - "The locals pick on them when they are off duty, teasing them for their compulsions. They have enemies, and could use friends." - ] - }, - { - name: "Convict Public Service", - category: "Twisted Guards", - desc: "Due to prison overcrowding, some criminals are sentenced to indentured service to a noble to work off their debt to society. This site's guardian uses criminals as guards, under the stern eye of professionals.", - questions: [ - "Are casualties high due to danger from intruders or other site defenses?", - "Is the patron benevolent and trying to rehabilitate criminals, or using them as disposable fodder?", - "How do the convicts like this place?" - ], - modsHarder: [ - "Serving here is a known post among criminals, both a resume builder and networking site.", - "Angering these guards could bring consequences from unexpected directions in the criminal underworld.", - "Hand picked as the hardest and deadliest, these criminal guards are canny and tough." - ], - modsEasier: [ - "Convicts are eager to assist anyone with enough Coin or pull to secure their pardon and freedom.", - "The convicts are bullied and sullen, as much a hindrance to defenders as a defense themselves." - ] - }, - { - name: "Demonic Mutations", - category: "Twisted Guards", - desc: "About a quarter of the guards have been mutated by contact with demonic essence. They are strong, and their senses are sharp.", - questions: [ - "Do they share one demon patron?", - "Did they become guards to gain this power?", - "Are they worshippers or mercenaries?", - "Did they volunteer or are they victims?", - "What element is their demonic affinity?" - ], - modsHarder: [ - "They share a supernatural connection and can sense when other demonic guards are in trouble.", - "They are highly resistant to normal damage. They may be vulnerable to supernatural attacks or a specific allergy (silver, garlic, salt, etc.) Or, they may be resistant to supernatural attacks instead." - ], - modsEasier: [ - "They become physically impressive, but their minds are lost to incoherent lusts and fury.", - "The rest of the staff resent or fear the demonic guards. Loyalty and morale are low among mundane employees." - ] - }, - { - name: "Enchanted Prosthetics", - category: "Twisted Guards", - desc: "Guards are all amputees with at least one prosthetic. Each prosthetic tunes to its owner. The prosthetics can stun on contact.", - questions: [ - "Are the false limbs the work of one genius?", - "Are they part of a collection?", - "Were they made for this use?", - "Is a ghost bound to each?", - "Are they scientific, with batteries?", - "Are they powered by the bearer's life force?" - ], - modsHarder: [ - "All guards have some adept training and spirit bane charms, alert against supernatural forces.", - "Veteran guards have learned to tune to their prosthetics to get an additional effect, like life detection or firing energy blasts." - ], - modsEasier: [ - "Only one use between recharges.", - "The guards are mostly old or broken, relying on reputation and supernatural energy to be effective." - ] - }, - { - name: "Feral Pen", - category: "Twisted Guards", - desc: "Some areas of the defended site have free-range maniacs. Destitute and wretched beggars are treated as guard dogs, expected to attack intruders and draw attention to anything unusual.", - questions: [ - "Does the guarded site pretend to be charitable, or a madhouse, or a prison?", - "What philosophy leads to treating people this way?", - "How do the city authorities feel about the site?", - "Religious authorities?", - "Does the site feed into the Ghost Field in an unusual way?" - ], - modsHarder: [ - "Most of the feral guards are killers, possibly haunted, and extremely dangerous.", - "This pet project is as much art and religion as defense, and has support from a variety of decadent aristocrats in positions of power." - ], - modsEasier: [ - "The rest of the site guards hate the feral pen and ignore it as best they can.", - "It is as much prison hospice as guard dog kennel. Its victims are weak, sick, and starving." - ] - }, - { - name: "Fighting School", - category: "Twisted Guards", - desc: "An onsite training school focuses on the lifestyle and skill of a school of fighting. Site defenders are part of a group identity with specialty training.", - questions: [ - "Is the school's focus on dueling, a martial art, commando training, or something else?", - "What is their crest, uniform, motto, and lore?", - "What sort of training space do they have?" - ], - modsHarder: [ - "The school itself is an impressive fortress or defense.", - "The school has an impressive alumni network that visits occasionally and would avenge wrongs to the honor of the school." - ], - modsEasier: [ - "This is an off-site shrine or expansion, where they send troublemakers and those they can't eject for political or financial reasons.", - "Leadership is riddled with rivalries and power struggles. Outsiders know some details." - ] - }, - { - name: "Performance Enhancers", - category: "Twisted Guards", - desc: "Guards have ready access to drugs. Some of the drugs enhance performance.", - questions: [ - "Do the drugs give them a burst of combat effectiveness?", - "Are the drugs recreational, making them popular with a customer base that pays well and owes favors?", - "Who provides them with drugs?" - ], - modsHarder: [ - "As dealers, the guards are difficult to bribe or intimidate, as they have money and prestige.", - "Guards can medicate flexibly, with concoctions to enhance perception (even to see the supernatural,) gain combat prowess, or heal." - ], - modsEasier: [ - "Their peddling of illegal drugs has made enemies among bluecoats and inspectors.", - "The guards are junkies. Their employer uses addiction to control them, keeping them near the edge. They are often distractible or unconscious." - ] - }, - { - name: "Zealots", - category: "Twisted Guards", - desc: "Guards share a religion that binds them together and makes them resistant to intimidation or corruption.", - questions: [ - "Do they worship one of the Forgotten Gods? The Church of the Ecstasy of the Flesh? Weeping Lady?", - "Have they sworn oaths?", - "What does religion require them to hate, or to love?" - ], - modsHarder: [ - "The defended site includes a shrine or temple. Violating the site angers offended worshippers.", - "Serving as a site guardian is part of a religious duty. Unexpectedly seasoned warriors or important people may serve as lowly guards for a time." - ], - modsEasier: [ - "Mandatory prayer times, unclean objects or places left uninspected, and restricted areas may create holes in security.", - "Enemies of their religion may offer help to embarrass, discredit, or injure the zealots." - ] - }, - { - name: "Ghostport Lock", - category: "Weird Tech", - desc: "Keys are tuned to locks that cannot be picked by normal means, or bypassed without whisper expertise. Their access point is in the Ghost Field until the key is present.", - questions: [ - "Are these locks modem scientific triumphs, or old arcane defenses?", - "Does he key look like a key, or does it look like a missing decoration, or a gem?", - "Is the key physical, or energy, like living blood of the right family?" - ], - modsHarder: [ - "The locks are hidden and trapped. Messing with the lock could hollow the intruder (tearing the spirit out of the body) or other unpleasantness.", - "The precise location of the lock must be known, and it is not near what it is locking." - ], - modsEasier: [ - "The ghostport lock has been a fad several times in Duskwall. Each time, there was some mass production, and a key to a similar lock might work with a little help.", - "The owner may have stiffed a whisper locksmith on the fee, or otherwise offended the expert, who is knowledgeable and disgruntled." - ] - }, - { - name: "Lightning Walls", - category: "Weird Tech", - desc: "Runic energy twisting technology can make pylons that project a curtain of energy between them. The glowing walls are transparent, but crippling to touch and lethal to pass through. They stop projectiles.", - questions: [ - "Does the site have the technology legally, or is it stolen?", - "Maybe cobbled together from leftovers by a mad alchemist?", - "Is it on all the time (expensive to fuel) or only if the alarm is raised?", - "Where are the fuel cells kept?" - ], - modsHarder: [ - "The equipment is properly installed, its vulnerable parts behind the energy curtain, directly guarding what needs protecting.", - "The lightning walls attract loose spirits, intruders may also have to contend with confused ghosts." - ], - modsEasier: [ - "The walls guard a few key access points, but there are multiple ways around.", - "The walls are installed poorly, so their machinery is vulnerable from the outside while it is on. If no other guards are present, they can be wrecked." - ] - }, - { - name: "Panopticon", - category: "Weird Tech", - desc: "Special crystal lenses transmit their sight through the Ghost Field to mirrors in a central location. From one place, a guardian can monitor views all over the defended site.", - questions: [ - "Is this new industrial alchemical technology, or an ancient enchanted construction?", - "Does the current owner know how to get the most functionality out of it?", - "Who maintains the system?" - ], - modsHarder: [ - "The lenses are hidden in mirror frames, statues, and other decor. They are difficult to spot.", - "The lenses can see into the Ghost Field as well, observing ghosts or occult work, and life force." - ], - modsEasier: [ - "The guardians watching the mirrors are somewhat lax.", - "Over time, many lenses have not been replaced or repaired. Views are limited." - ] - }, - { - name: "Shadow Lanterns", - category: "Weird Tech", - desc: "Guards are equipped with lanterns that detect shadows of recent life force as well as shedding light.", - questions: [ - "Are the lanterns traditional lantern shape, or a glowing ball, or something else?", - "Does an expert keep the guardians supplied, or is their supply jealously guarded?", - "Does it cost the guards something to activate the lanterns?", - "Will the lanterns work if taken off-site?" - ], - modsHarder: [ - "Guards are trained to tune into the life force energy to also hear conversations of the life shadows. Guards can tune into the life force energy to know the owner's current location, if in the defended area.", - "Untended lanterns can be set to transmit detection of a life force to a nearby guardian." - ], - modsEasier: [ - "The lanterns can be rendered blind by properly tuning a spiritbane charm while near one.", - "Every sunrise wipes all traces of past life forces, and they only work at night." - ] - }, - { - name: "Shadow Rooms", - category: "Weird Tech", - desc: "The Ghost Field sometimes remembers rooms or entire neighborhoods that no longer exist in the material world. Some defended sites hide treasures in these spaces that can only be accessed if you knowhow.", - questions: [ - "How are colors different in these shadow rooms?", - "Is there a smell or sound that lingers?", - "How does it feel to step out of the material world?", - "What natural laws work differently here, like fire not flickering?" - ], - modsHarder: [ - "The access point to the shadow rooms is an enchanted lock, its location is known and guarded.", - "The shadow rooms are only connected to the material world a few times a year, or less." - ], - modsEasier: [ - "Transitioning from the material world to the shadow rooms involves certain proscribed movements; cross the courtyard three times, then back down stairs with eyes closed (for example.) Too many people know the formula.", - "The current site owners do not know these rooms exist." - ] - } - ], - NPCs: [ - { - name: "Arturo Montastic", - type: "npc", - concept: "Addicted Gambler", - arena: "New Money", - description: "He is impossibly lucky. He wins enough at games of chance to pay for his addictions, and to treat the consequences (transfusions, transplants, cutting-edge treatments.) His relationships are intense but brief. He often loses everything, but then wins it all back and more. He has owned epic treasures many times.", - notes: "Risk-averse collectors cannot bear his cavalier attitude on winning and losing priceless art. He does not truly appreciate his treasures, and should not be trusted with them. Losers can take their losses hard." - }, - { - name: "Baron Kelyr Strathmill", - type: "npc", - concept: "Hardened Industrialist", - arena: "Old Money", - description: "His family has controlled the docks for many generations. They quietly destroy competition, and get lucrative city contracts to re-develop blighted areas if the money slows down. Graceful, educated, and pleasant, he is ruthless as barbed steel under a cultured veneer. He is proud of his estate's gardens.", - notes: "Competition doesn't like being crippled. He often hires outsiders for the dirtiest work, and his victims often hire outsiders to get revenge." - }, - { - name: "Baroness Thena Hellyers", - type: "npc", - concept: "Hazy Art Patron", - arena: "Old Money", - description: "Thena is one of the least emotionally scarred survivors in her weird family. She is a leading light in the art world. She is patron to many artists and her criticism and evaluation drives a significant element of Duskwall's art scene. Whispers have noted she has an unusual connection to the Ghost Field.", - notes: "Sometimes she hires outsiders to sort out one of her artists' problems. She has a private gallery that she updates with her current trending tastes—those in the art market need to know what's in it." - }, - { - name: "Calvin Dannos", - type: "npc", - concept: "Eerie Assassin", - arena: "Underworld", - description: "The Inkvein was a cabal of seven anonymous assassins, named for their maps of the canals. If one of them was identified as a member, the other six were sworn to kill the outed assassin. Dannos was outed a decade ago, and he killed the other members and their undying founder. Now he IS Inkvein.", - notes: "Easily bored, he prefers interesting challenges to high paying or easy kills. Of course, many bereaved or power hungry individuals want him dead." - }, - { - name: "Commissioner Naria Haig", - type: "npc", - concept: "Political Matchmaker", - arena: "City Law", - description: "She exudes a plump grandmotherly innocence, but she is one of the sharpest politicians in Duskwall. She supervises over the merging of unexpected allies and the schism of monolithic interests. She cares about one thing—the good of Duskwall as a whole. She is Chair of the Ethics Oversight Committee.", - notes: "Always playing a bigger game, she uses outsiders to manage errands whose purpose they cannot see. Those she outmaneuvers tend to want to get back at her with violence." - }, - { - name: "Doc Sarnin", - type: "npc", - concept: "Lecherous Leech", - arena: "Underworld", - description: "Doc can keep life in you if you're alive (or recently dead) when you get to him. His extreme methods are often horrifying. Still, his concoctions can crush ghosts, re-attach limbs, and more. The Crows, a tough crew, protect him. They give him victims for his \"needs,\" which are emotional, physical, and scientific.", - notes: "Sometimes the Crows hire outsiders to go after rare components or victims for Doc. He has many, many enemies who want to either steal him and force him to serve them, or punish him." - }, - { - name: "Doctor Ixit Crichelle", - type: "npc", - concept: "Elegant Spook", - arena: "Old Money", - description: "Crechelle calls himself an Oneiric Master. He interprets dreams for a fee. He enters them, alters them, and moves through veils to understand truths and secrets the dreamer may not grasp. If he touches a target, or one of their possessions, he may enter their dreams. He appears feeble, but his mind is deadly.", - notes: "Aristocratic patrons invite him to parties. He needs a person's possession to see into their dreams; he pays for objects to visit some people's dreams. Victims will pay to free themselves ." - }, - { - name: "Dr. Hansel Kryvanntic", - type: "npc", - concept: "Brilliant Scientist", - arena: "Foreign", - description: "He is Severosi, bow-legged and wild-haired. His work on electroplasmic poisoning and mutation in animals and humans is ground-breaking. Fleeing persecution because of his ethically questionable methods back in Severos, he found a more open-minded scientific community in Duskwall.", - notes: "His research has applications in art, medicine, and war. Those with sufficient resources to further his studies want to control him. He has hurt a lot of people, over time, so he has many enemies." - }, - { - name: "Dr. Yerial Crabbskidditch", - type: "npc", - concept: "Sleazy Lawyer", - arena: "New Money", - description: "He firmly believes those who are wealthy should not be pestered with the law. No matter what you do, if you have means you can arrange for an alternate story that favors you. Deaths, frauds, robberies, and other crimes can be reduced to a few fines. He throws money at problems until they disappear.", - notes: "He routinely hires outsiders to destroy evidence, intimidate witnesses, compel confessions, and so forth. He has countless enemies, both those seeking justice and former clients who ran out of money." - }, - { - name: "Duvrel the Snake", - type: "npc", - concept: "Cunning Smuggler", - arena: "Foreign", - description: "She is Tycherosian, with the eyes and horns of a goat. Snake tattoos coil around her arms. Exotic drugs from the Dagger Isles flow through her distribution network in Duskwall. She hires outsiders to remove stubborn people while she has an alibi, or to retrieve drugs misplaced at incriminating locations.", - notes: "Inspectors have orders from the Spirit Wardens to take her alive, to study her uncanny ability to flex with the Ghost Field for supernatural stealth." - }, - { - name: "Dylayzia Finchester", - type: "npc", - concept: "Fashionable Whisper", - arena: "New Money", - description: "Her exotic looks, tattoos, and bright green eyes draw attention. She popularized thigh-high buckled leather boots and spirit bane chokers. Her opinions echo in drawing rooms across the city. People enjoy her feud with the Church of the Ecstasy of the Flesh.", - notes: "Wealthy figures in the fashion world pay top win for sneak peeks at her clothing designs. Her opinions inflame many enemies­-especially the Church. She hires outsiders to get rare components for her rituals." - }, - { - name: "Emeline Coleburn", - type: "npc", - concept: "Weary Regulator", - arena: "City Law", - description: "She inspects buildings and reports to the Duskwall Council whether they are sound, and whether they serve the purpose listed on the owner's taxation form. She is front-line in the tug-of-war between criminals, politicians, and nobles. She no longer cares about the greater good. Now it's about kickbacks.", - notes: "She takes the path of least resistance in her evaluations, so people pay to make their preference easier and other roads harder. She hires outsiders for off-the-books communication with pushy customers." - }, - { - name: "Eric the White", - type: "npc", - concept: "Vigilante Rebel", - arena: "Foreign", - description: "The War of Skovlan Unity is over, but this slender maniac with a brushy beard can't let it go. He plans to destroy the government and turn Duskwall into a Skovlan colony to punish them for the destructive war. He wants to discredit and disrupt the government at every turn.", - notes: "He targets gavernment officials as high up as he can reach, hoping to cause enough trouble to make the government vulnerable to change. He has gathered zealots, and he uses outsiders for disposable work." - }, - { - name: "Gi Aniru Ga of Sultha", - type: "npc", - concept: "Sacrificing Cultist", - arena: "Supernatural", - description: "She worships the Gaping Maw, the Runnel of Life, the Cosmic Thirst. She builds a cult, teaching them to hunt and conduct rituals. Then she moves on. Witnesses uneasily describe her supernatural abilities, including shapeshifting, flight, killing people by attacking their shadows, and so on.", - notes: "Bereaved relatives, rival cultists, and law enforcers all want her stopped. She hires outsiders to threaten, misdirect, or kill law enforcement. Determined inspectors crush cults she trained, need help to catch her." - }, - { - name: "Holtz Clermont", - type: "npc", - concept: "Reformed Clerk", - arena: "City Law", - description: "He used to be a forger. After he served stint in prison, some respectable family friends got him a position as City Clerk for the whole district. He manages correspondence for permit requests and official notices. When corrupt people inside and outside the system need to adjust evidence, they come to him.", - notes: "Jilted clients can be threatening, leading him to take steps to adjust their attitude by hiring outside help. He's smarter than he looks, and knows how to back people off. He also might know too much." - }, - { - name: "Inspector Lorette Salkha", - type: "npc", - concept: "Crusading Inspector", - arena: "City Law", - description: "She needs allies in her hopeless quest to clean up the city. Corruption is everywhere, crime runs rampant, and the bluecoats serve the powerful (on both sides of the law.) Some tragedy in her past propels her into a suicidal effort to restore \"rule of law.” Her peers muse it is a shame she will die young.", - notes: "She could be helpful if she focuses on the right bad guys—your enemies. She can't be bought, so maybe someone needs her killed (or otherwise neutralized.)" - }, - { - name: "Jemma Dropkick", - type: "npc", - concept: "Feminist Vigilante", - arena: "Underworld", - description: "She is a legend in the Seven Shallows neighborhood. She attacks men who abuse women. She survives because she has friends—a few bluecoats, a gang of thugs, and a grateful public. She carefully plans attacks to hurt abusers. Lf her victims abuse again, they are mutilated, packed like luggage, and shipped out of town.", - notes: "Many powerful men would pay for revenge on Jemma. Sometimes she hires outsiders to help out." - }, - { - name: "Kheldaria Whinnich", - type: "npc", - concept: "Implacable Developer", - arena: "New Money", - description: "She has a vision for developing the Crow's Foot district. It will be divided between businesses, estates, and parks. To realize her vision, she has been selectively buying real estate all around the city, bartering for land in Crow's Foot, and using whatever persuasion is needed to convince owners to sell to her.", - notes: "She has an estate where she stores induce­ments of all sorts, a variety of treasure designed to persuade owners to sell in exchange for what they want most. They say you could find almost anything there." - }, - { - name: "Lady Ashlyn Tyrconnel", - type: "npc", - concept: "Decadent Duelist", - description: "For centuries, aristocrats of Duskwall have learned the Tyrconnel Method of swordplay and self defense. The Tyrconnel family produces countless public servants and warriors—but also a share of scoundrels. Ashlyn's trademark suite of moves is to duel, win, bed someone, and drink to unconsciousness.", - notes: "You're hired to join the spy game in the Tyrconnel family. Or, someone is targeting her. Either way. Watch your back. Outsiders in the games of nobles are uniformly expendable." - }, - { - name: "Lady Candra Dunvil", - type: "npc", - concept: "Corrupt Fixer", - arena: "Old Money", - description: "Her family built Ironhook Prison. Her wealth is built on generations of shady deals with incarcerated aristocrats and business owners. She sees the world as a rigged game and has contempt for anyone who finds corruption shocking or fixable. She is vain, practical, and ruthless.", - notes: "She hires outsiders to carry out promises she made to inmates. Her family has casually wrecked reputations and lives over centuries, and that leaves a trail of vengeance seekers." - }, - { - name: "Lady Polonia Brogan", - type: "npc", - concept: "Desirable Dowry", - arena: "Old Money", - description: "She's ugly, smelly, stupid, and rude--and also the key to the Brogan fortune. Her lucky spouse will have access to massive wealth and infrastructure among professional builders and shipwrights of Duskwall. Only her aunt, CECILIA DURWITHE, looks out for her best interests with sharp disapproval.", - notes: "Brogan hires outsiders to punish those who slight her, or to investigate potential partners. She collects fake wills rogues have planted during assassination attempts, trying to leave her fortune to usurpers ." - }, - { - name: "Lord Branon Kinclaith", - type: "npc", - concept: "Romantic Horseman", - arena: "Old Money", - description: "Branon looks like a hero from a legendary story. He manages the family's stables, the finest horses in Duskwall (where horses are a rare luxury.) His tumultuous trysts with both men and women are common knowledge. Business suffers from his impulsive romantic gestures, but benefits from his charm.", - notes: "Branon sometimes refuses to sell horses, or breed them, if he dislikes the buyer. Some buyers want access to horseflesh anyway. If his horses are attacked, he hires outsiders to get revenge." - }, - { - name: "Lord Bulward Skinnester", - type: "npc", - concept: "Greedy Banker", - arena: "New Money", - description: "This portly curmudgeon does a brisk trade in real estate titles, both lending and foreclosing. He is acutely aware of the value of properties and how neighbors affect value. He takes particular glee in foreclosing on aristocracy and setting up the newly rich in ancient estates.", - notes: "Sometimes he hires outsiders to solve problems that his hired bluecoats and bribed councilmen cannot manage. He collects sculpture by Duskwall artists. He has ruined the lives of many formerly influential people." - }, - { - name: "Lord Orlan Booker", - type: "npc", - concept: "Insulated Mastermind", - arena: "Old Money", - description: "Ennui is a danger to the wealthy. Booker fills his days by gathering intelligence and planning heists, then selling the plans to ambitious gangs that lack his patience, experience, resources, and insight. Twice a month he goes to the opera, and meets those who have arranged to purchase a score.", - notes: "Sometimes things go wrong, and it is natural to blame the planner and want revenge. Sometimes a target wants to punish those who acted against them, even if the act was planning." - }, - { - name: "Master Slen Dallicore", - type: "npc", - concept: "Protective Guilder", - arena: "New Money", - description: "Master Dallicore is the Guildmaster for the Docker's Guild. They move all cargo on and off ships, boats, and gondolas. Their role is protected by law, as are the fees they charge. The guild uses low-level violence to discourage non-guild laborers and smugglers. However, some challenges require proper scoundrels.", - notes: "Dallicore is not above hiring outsiders to punish powerful patrons of smugglers or illegal dock workers. His position of power also gives him access to rare antiquities, both purchased and acquired." - }, - { - name: "Minister Fourteen", - type: "npc", - concept: "Grungy Fixer", - arena: "Underworld", - description: "The blind Skovlander holds court on the docks, moving from one basement to another. He favors baggy shirts, stained vests, shiny jewelry, and fraying lace. He often acts through his massive bodyguard Severen and his weedy messenger Torok.", - notes: "He is connected in the Skovlander refugee community, and in Skovlan. For a price (either wealth or an errand) he will share information about Skovlanders. He often hires outsiders to handle sensitive tasks." - }, - { - name: "Moonslider the Third", - type: "npc", - concept: "Eccentric Artist", - arena: "New Money", - description: "She feels moon phases. Her family put her in an asylum for a decade. Later, she won her freedom and inherited the family bootmaking fortune. She makes art. She tries to communicate her moon feelings. She uses oil paint, glass blowing, sculpture, song, and dance in multimedia recitals and art pieces.", - notes: "Her family bought nice things before they all died and she inherited them; she ignores most of it. She needs expensive equipment and supplies for her bizarre art shows." - }, - { - name: "Officer Milos Penderyn", - type: "npc", - concept: "Corrupt Bailiff", - arena: "City Law", - description: "Milos has access to trial evidence, and to prisoners awaiting trial. He can't get people out, but he can silence them. He has a network of corrupt peers, judges, bluecoats, and others so he can trade favors to accomplish the impossible. Huge and greasy, he is built like a bull and he enjoys the scent of fear.", - notes: "Controlling Milos could mean protecting or killing someone in bluecoat custody. An endless stream of people want revenge on him, and a more select group would like to control or use him." - }, - { - name: "Officer Veleris Walund", - type: "npc", - concept: "Heroic Bluecoat", - description: "There are actually songs about him. He is very popular. Veleris is a skilled orator (though he retreats into modesty) and a canny judge of character and situations. (He insists he just tries to do the right thing.) His opinion is influential in his district. He is trusted to guard valuables. His moustaches are his pride and joy.", - notes: "He has no family, and he seems to be an idealist. Some try to persuade him, others try to threaten him. Threats don't seem to work. He has been known to quietly hire outsiders to get justice." - }, - { - name: "Pebbler", - type: "npc", - concept: "Demon Spy", - arena: "Supernatural", - description: "This earth demon looks like a fat man built around a boulder gut, leaking sand from joints. It is able to see and hear through sand, earth, and stone within a range of miles. It works with non-cultists voluntarily, selling information in exchange for raids into the rare areas protected from its prying.", - notes: "Dozens of powerful people want Pebbler banished or robbed. However, the demon is a peerless information exchange, valuable even if it is difficult to control." - }, - { - name: "Saithernon", - type: "npc", - concept: "Exotic Fence", - arena: "Underworld", - description: "He drapes his python, DELGRAAZ, around his neck. He wears a turban with a jewel on it. He is willing to buy almost anything, no matter how strange. He also knows what you need, sometimes before you know you need it. His bazaar unfurls below the Kennington market in an abandoned gondola dock.", - notes: "He pays people to get things for him, then sells them at tremendously inflated prices to those desperate to have them. This can cause hurt feelings among the desperate." - }, - { - name: "Serlevica the Brander", - type: "npc", - concept: "Spy Whisper", - arena: "Underworld", - description: "Gaunt and frizzed, this foul-smelling Whisper has a secret ritual that allows her to control and see through rats she brands. She sells her services as a spy or site guardian. She has survived by retreating into slums and sewers when threatened, and striking from the shadows until it is safe to emerge again.", - notes: "She is closely tied to the information marketplace, buying and selling secrets. She often hires outsiders to deal with her enemies through theft or violence, and she is in turn a frequent target." - }, - { - name: "Sir Mournseller", - type: "npc", - concept: "Anarchist Ghost", - arena: "Supernatural", - description: "This ghost possesses old men from the Draymach Asylum, breaking them out to find and hire scoundrels for obscure tasks with no independent purpose. Examples include killing an insignificant chandler or stealing a specific stone from a wall in a noble's estate. Payment is the location of hidden treasure.", - notes: "A decade ago, an astute inspector began picking out the connection between errands, seeing a very long and very dangerous game to unseat the city's rulers emerging." - }, - { - name: "Sir Olen Llanwold", - type: "npc", - concept: "Piratical Industrialist", - arena: "New Money", - description: "He is thin and nervous, easy to underestimate. He specializes in stripping foes of their assets and taking over their operations. His father was a butler, and he grew up hating aristocrats. He understands power structures and corrupts retainers. His top agent, Ellsfielder, is a beautiful and ruthless woman.", - notes: "Many ruined aristocrats (and their allies) hate Danwold passionately. He does not hesitate to use his assets, legal and otherwise, to defend himself and cripple his foes. He hires outsiders through proxies." - }, - { - name: "Sir Tocker Farros", - type: "npc", - concept: "Pragmatic Councilman", - arena: "City Law", - description: "Sometimes the law works, and sometimes it doesn't. Regardless, the Council must rule and there must be order. Sir Farros ensures the districts he serves do not get too far out of hand before lawless elements are curbed. One way or another. He looks like an affable grandfather, but he has a dark past.", - notes: "Sir Farros uses inspectors or scoundrels, politicians or housemaids—anyone who will get the job done. He has an endless list of enemies who feel he wronged them, and want revenge. His agents are disposable." - }, - { - name: "SLOPSPATTER", - type: "npc", - concept: "Canal Hull", - arena: "Supernatural", - description: "This hull learned to consume spirits and bolster its strength with theirs. It cannibalizes machinery and rummages in wrecked boats for parts. It has gondola prow shoulder guards and helm, and strange banded armor made of water-logged wood over intricate mechanical parts. It fears destruction.", - notes: "It assassinates targets, with its body or by possessing machines near them. It hunts whispers, leeches, and scholars, stealing their knowledge and killing them. Their allies want revenge." - }, - { - name: "Syla DuTorrivestria", - type: "npc", - concept: "Famous Connoisseur", - arena: "Foreign", - description: "This mysterious Iruvian hides behind a veil. For years, she has been the final word on Duskwall delicacies. She specializes in evaluating high-end cuisine (including spore wines and cooking with leviathan blood.) She stays in the public eye with racy politics and a string of scandalous romances.", - notes: "She must keep any real competitors for her fame weakened and embarrassed, and she has countless enemies. Everyone \"knows\" she is an Iruvian spy." - }, - { - name: "The Honorable Telia Cray", - type: "npc", - concept: "Stern Prosecutor", - arena: "City Law", - description: "She's old, she's sour, and she has a reputation for jailing Duskwall's criminals. As thin and hard as an iron poker, she relentlessly pursues her cases, bending the law with a passionate hatred of scoundrels. She runs a special unit of Inspectors dedicated to investigating her cases, run by INSPECTOR ULEK.", - notes: "If she is taking a case personally ( as she often does) she may hire outsiders to acquire or create evidence. She also conduds a brutal war of counter-intelligence against rogues looking to free their associates." - }, - { - name: "The Wooden Judge", - type: "npc", - concept: "Haunted Puppet", - arena: "Underworld", - description: "This knee-high ventriloquist dummy looks like a caricature of a grim Judge. It is supernaturally animated. The puppet appears unexpectedly, interrupting a scoundrel's routine by offering jobs in a squeaky voice. He pays by revealing the location of hidden caches of ancient coin.", - notes: "Many angry victims want to know who pulls the strings of the Wooden Judge. The puppet often hires fresh talent for dubious work." - }, - { - name: "Theodore Lysander", - type: "npc", - concept: "Bard Pimp", - arena: "Underworld", - description: "Elegant and charismatic, this well-dressed man runs the Tenpenny Court Network. He manages prostitutes and their customers, his personal connections and charm monetized. He is also a skilled composer and performer, often seen at the Worldsedge Theater in Crow's Foot.", - notes: "He is a skilled networker. He takes the safety of his friends seriously, and is protedive of his employees, to the point of using blackmail to force powerful patrons to back off." - }, - { - name: "Chief Prichard", - type: "npc", - description: "The head Overseer of the Ministry of Provisions in Duskwall. Manages the workers and food allotments for the city districts.", - district: "Barrowcleft", - traits: [ - "calculating", - "confident", - "calm" - ] - }, - { - name: "Lord Strangford", - type: "npc", - description: "Operates one of the largest leviathan hunter fleets, serves on the City Council and is a high-ranking member of the secret order within the Church of Ecstasy.", - district: "Brightstone", - traits: [ - "secretive", - "calculating", - "arrogant" - ] - }, - { - name: "Hutton", - type: "npc", - description: "A Skovlander refugee and former soldier, now the leader of an anarchist revolutionary movement, bent on forcing the government to acknowledge Skovlander rights in the Empire.", - district: "Charhollow", - traits: [ - "brave", - "compassionate", - "wise" - ] - }, - { - name: "Lady Drake", - type: "npc", - description: "A magistrate who is \"reasonable\" when it comes to street crime, so long as the offender's purse is sufficient.", - district: "Charterhall", - traits: [ - "flexible", - "shrewd", - "subtle" - ] - }, - { - name: "Master Slane", - type: "npc", - description: "A notorious factory foreman known for excessive and cruel punishments for the smallest infractions. Many attempts have been made on his life, but all have failed. Some say he's a devil.", - district: "Coalridge", - traits: [ - "cold", - "cruel", - "sadistic" - ] - }, - { - name: "Sergeant Lochlan", - type: "npc", - description: "The senior Bluecoat squad leader in the district, reporting to Captain Dunvil. Lochlan is flexible and reasonable, taking bribes and payoffs when she can; enforcing the law and making examples when necessary.", - district: "Crow's Foot", - traits: [ - "shrewd", - "tough", - "commanding" - ] - }, - { - name: "Chief Helker", - type: "npc", - description: "One of the most influential senior Dockers. Helker has a lot of sway at the docks, and if you cross him, you might find your cargo tossed into the drink—and possibly you along with it.", - district: "The Docks", - traits: [ - "cautious", - "greedy", - "vengeful" - ] - }, - { - name: "Master Krocket", - type: "npc", - description: "An unsavory, greasy-haired, scarecrow of a man who runs the snarling pack of vicious dogs used by Ironhook to track down escapees and sniff out contraband and tunnels. His dog-handlers can be found around the labor camp and all about Dunslough, using their status with the prison for favors and bribes.", - district: "Dunslough", - traits: [ - "cruel", - "greedy", - "ruthless" - ] - }, - { - name: "Jira", - type: "npc", - description: "A dealer of fine weapons from the Dagger Isles. Greatly respected by many street toughs in The Dusk—a \"jira blade\" is a status symbol that many aspire to.", - district: "Nightmarket", - traits: [ - "bold", - "tough", - "confident" - ] - }, - { - name: "Levyra", - type: "npc", - description: "A medium who invites clients to bring ghosts in bottles to posses her so they can share a few final words before the ghost is \"freed\" (Levyra hands it off to the waiting Spirit Wardens nearby).", - district: "Silkshore", - traits: [ - "weird", - "daring", - "dishonest", - "" - ] - }, - { - name: "Mother Narya", - type: "npc", - description: "Runs the Arms of the Weeping Lady charity house.", - district: "Six Towers", - traits: [ - "kind", - "patient", - "gracious" - ] - }, - { - name: "Maestro Helleren", - type: "npc", - description: "Senior composer and conductor of the Spiregarden Theater, premiere performance venue for the elite of the city.", - district: "Whitecrown", - traits: [ - "sincere", - "dramatic", - "vain" - ] - }, - { - name: "Hester Vale", - type: "npc", - description: "Matriarch of the oldest farm family. The living embodiment of \"tough but fair.\"", - district: "Barrowcleft", - traits: [ - "proud", - "fierce", - "suspicious" - ] - }, - { - name: "Commander Bowmore", - type: "npc", - description: "Chief Officer of the Watch in Brightstone. Bowmore's family financed Bowmore Bridge centuries ago and now holds many positions of power.", - district: "Brightstone", - traits: [ - "proud", - "principled", - "connected" - ] - }, - { - name: "Briggs", - type: "npc", - description: "The owner of a merchant stall at Charhollow market, cover for a network of gossips, spies, and code-smiths among the working class people of the district, selling their services to those who need them.", - district: "Charhollow", - traits: [ - "secretive", - "sneaky", - "cautious" - ] - }, - { - name: "Lord Penderyn", - type: "npc", - description: "Chief Scholar of the Archive of Echoes, authorized by the Emperor to keep a collection of ancient ghosts trapped in spirit bottles, to be consulted in cases where knowledge from the distant past would benefit the operation of the Imperial government. Lord Penderyn also consults the spirits on his own volition, forming the rebellious Path of Echoes society for other elites and nobles who seek communion with the spectral realm.", - district: "Charterhall", - traits: [ - "reckless", - "strange", - "obsessive" - ] - }, - { - name: "Belle Brogan", - type: "npc", - description: "A Skovlander factory worker who's been gaining popularity as a potential union organizer. It's only a matter of time before a factory boss tries make an example of her.", - district: "Coalridge", - traits: [ - "charming", - "confident", - "bold" - ] - }, - { - name: "Lewit, Jol, Myra, Reyf", - type: "npc", - description: "Bluecoat constables; run an extortion racket.", - district: "Crow's Foot", - traits: [ - "arrogant", - "vain", - "volatile" - ] - }, - { - name: "Tris", - type: "npc", - description: "A legendary tattooist who only inks those that have looked upon a leviathan and lived to tell the tale. Getting a tattoo from Tris is a rite of passage for everyone who hunts the demons of the void sea.", - district: "The Docks", - traits: [ - "artistic", - "popular", - "insightful" - ] - }, - { - name: "Vandra", - type: "npc", - description: "A deathlands scavenger that survived six runs and was pardoned. She knows the landscape beyond the barrier very well—but few can make sense of her haunted mumblings.", - district: "Dunslough", - traits: [ - "haunted", - "wise", - "daring" - ] - }, - { - name: "Leclure", - type: "npc", - description: "A purveyor of personal luxuries (soaps, hair oils, perfume, fine silks) who dabbles in fortune telling. Some say her that drowned lover is a ghost that whispers secrets in her ear.", - district: "Nightmarket", - traits: [ - "shrewd", - "tough", - "commanding" - ] - }, - { - name: "Helene", - type: "npc", - description: "The elegant and mysterious proprietor of the Silver Stag Casino. People say she would have been a queen of Severos had she lived in the old days before the Empire.", - district: "Silkshore", - traits: [ - "cultured", - "charming", - "secretive" - ] - }, - { - name: "Chef Roselle", - type: "npc", - description: "One of the best cooks in the city, still operating the legendary Golden Plum restaurant—worth the trip into the haunted streets of Six Towers.", - district: "Six Towers", - traits: [ - "creative", - "insightful", - "friendly" - ] - }, - { - name: "Lady Freyla", - type: "npc", - description: "Regarded by some as the finest sommelier in the Empire. She serves only the most deserving at the Emperor's Cask.", - district: "Whitecrown", - traits: [ - "erudite", - "cultured", - "charming" - ] - }, - { - name: "Mara Keel", - type: "npc", - description: "A former smuggler who's gone into hiding among the farm laborers of Barrowcleft.", - district: "Barrowcleft", - traits: [ - "quiet", - "secretive", - "patient" - ] - }, - { - name: "Rolan Wott", - type: "npc", - description: "An influential magistrate who handles property, endowments, and financial cases. Famous for his extravagant parties.", - district: "Brightstone", - traits: [ - "stylish", - "elitist", - "shrewd" - ] - }, - { - name: "Corben", - type: "npc", - description: "An ex-military Skovlander on the lam for crimes against the empire.", - district: "Charhollow", - traits: [ - "tough", - "reckless", - "candid" - ] - }, - { - name: "Hopper", - type: "npc", - description: "A drug addict, whisper, and all-around weirdo who perches on rooftops in the district. Hopper claims to see \"ghost rails\" and \"spirit trains\" originating deep beneath Coalridge, stretching beyond the horizon.", - district: "Coalridge", - traits: [ - "weird", - "visionary", - "enthusiastic" - ] - }, - { - name: "Mardin Gull", - type: "npc", - description: "Owner and operator of the Leaky Bucket public house. Mardin was the leader of the Crows many years ago, before Roric and Lyssa, and now enjoys a comfortable retirement out of the scoundrel life.", - district: "Crow's Foot", - traits: [ - "charming", - "experienced", - "respected" - ] - }, - { - name: "Mordis", - type: "npc", - description: "A strange merchant which hides its true appearance beneath many layers of robes and hoods. Also fences occult and arcane stolen goods, no questions asked.", - district: "Nightmarket", - traits: [ - "secretive", - "insightful", - "arcane" - ] - }, - { - name: "Madame Tesslyn", - type: "npc", - description: "Operates the Red Lamp brothel, the oldest and most respected institution of its sort in the city.", - district: "Silkshore", - traits: [ - "confident", - "insightful", - "enthusiastic" - ] - }, - { - name: "Flint", - type: "npc", - description: "A spirit trafficker who trades out of a condemned manor house.", - district: "Six Towers", - traits: [ - "weird", - "calculating", - "suspicious" - ] - } - ], - Scores: [ - { - name: "Accidental Death", - category: "Secret Dirty Work", - desc: "Not only must the target die, the target must not know how death came. If by some misfortune the ghost of the victim is interrogated, it must not have any special knowledge. There is a ritual and an amulet for the assassins to ensure secrecy. No one living or dead can know who did this deed.", - narrative: "By the time the crew knows the job, there is a better than even chance their knowledge is too much risk and their employer plans to kill them. They might want some leverage." - }, - { - name: "Bayer's Train Heist", - category: "Misplaced Fortune", - desc: "Bayer was a rail jack fired for being drunk. Over years, he built a crew with one mission in mind--robbing a train. When lruvia completed negotiations with Akoros to buy an unprecedented mass of leviathan blood to pour into industrialization, Bayer's crew hit the train carrying the payment, sabotaging a bridge. Rescuers found the train in the canyon, but no gold--an impossible feat. Bayer's crew vanished.", - narrative: "An Iruvian ingot stamped with the year \"802\" will attract attention." - }, - { - name: "Bellweather Architectural Plans", - category: "Historical Curiosity", - desc: "The Duskwall Archives have the sanitized blueprints of the Bellweather Crematorium on file. The original plans were drawn by a Spirit Warden driven mad by an internal rift, so he haunted himself. He drew peculiar plans with occult underpinnings, and those original drawings were interpreted by architects.", - narrative: "Are there coded secrets in the original plans that reveal a repellant secret or ominous threat? Or are the plans the scribbling of a madman? Either way, some people would pay top coin to get a good look." - }, - { - name: "Book of Walls", - category: "Historical Curiosity", - desc: "Long ago, a nameless rogue cultivated a mass of bloodworms in a wall. He wrote a book with their blood. The words were nonsense, but strangely affecting; if the reader tuned in to them, and held the book, the reader could walk through a wall. Spirit Wardens ruined the book with holy smoke.", - narrative: "A legend, or is there truth to it? Walking through walls is a neat trick, and the book may hold the key to learning it. It is sought by a wide variety of the curious—scholars, collectors, and scoundrels." - }, - { - name: "Censer Mace of Udoch", - category: "Religious Object", - desc: "The head of this ornately carved mace opens on hinges so incense can be put inside to wisp as the mace swings. The haft has a recipe carved into it, instructions to make special incense out of bone and rare sap and unguents. If that incense bums in the mace, it can destroy ghosts or demons with a single hit.", - narrative: "This was a founding artifact of the Church of the Ecstasy of the Flesh. If it were returned, they would gain a fresh following from critics who feel the church cannot protect against supernatural threats." - }, - { - name: "Charter of Crows", - category: "Historical Curiosity", - desc: "This gauntlet is made out of crow beaks. Each beak is carved with arcane symbols. Consulting Whispers officially report it does not have any power in the Ghost Field. It was made by the Spirit Warden who first tamed the deathseeker crows; he claimed it was a treaty that guaranteed their service.", - narrative: "Spirit Wardens lost this gauntlet decades ago, but they want it back. The idea it is a treaty with the deathseeker crows is probably nonsense. They can't take that chance." - }, - { - name: "Combination Harpsichord", - category: "Weird Scholarship", - desc: "TARNALI was a Whisper composer who built a special harpsichord. When two tones are played, often a third \"ghost\" tone can be heard. By attaching the tuning pegs to crystals and runes, Tarnali built a harpsichord that could interact with the Ghost Field through calculated progressions of played tones.", - narrative: "This effort is intensely interesting to those who want to find doors hidden in the Ghost Field, draw or repel what lurks Behind the Mirror, or develop more portable tonal energies for non-Whispers ." - }, - { - name: "Dyvik's Chaser Mask", - category: "Weird Artifact", - desc: "This silvery face mask has the word “Elekthiaron” etched along its inner edge. When the word is spoken, the personality of the one touching the mask is pulled into it. The personality that was in the mask goes in the body. If the one in the body doesn't touch the mask once a week, madness threatens.", - narrative: "Has someone been using the mask to pose as someone else? How long has that been going on? Is there someone in the mask that needs rescuing? Was the mask used to cheat biological death?" - }, - { - name: "Evardian's Song Folios", - category: "Weird Scholarship", - desc: "Four leather-bound volumes, full of musical notation with heavily annotated margins. The \"music\" is supposed to be transcribed and translated leviathan song. Legend suggests if the music is played correctly, it can drive humans insane with visions of the demon-haunted deep.", - narrative: "Aristocrats will collect anything. Scholars go to great lengths for research material. Cultists may find religious significance in the folios. (Owning the folios is against the law.)" - }, - { - name: "Falheim's Prod", - category: "Historical Curiosity", - desc: "This ragged pole with a spear and a silver-cable loop was the first prototype of what became the lightning hook. It doesn't work very well, but it was the first historically known charged object that could consistently interact with the Ghost Field.", - narrative: "Apparently this bit of history is an important prestige piece in the turbulent intrigues of a number of underground cults led by Whispers. The city government would also like to display it in a museum." - }, - { - name: "Fang of Ibiria", - category: "Religious Object", - desc: "This brutal stiletto has a green stone in the pommel, and a runic symbol on the blade. The blade transforms electroplasm into a mutagen. The longer the blade is in a victim, the more monstrous the victim becomes. A cut gives nightmares, minutes give mutations, hours or days create a real monster.", - narrative: "Cultists want this blade so they can make or become monsters." - }, - { - name: "Goblet of Eletrachtian", - category: "Weird Artifact", - desc: "The silver and gold cup is big enough to hold with two hands, crusted with obsidian stones. The owner puts a drop of a demon's blood in the goblet with certain other liquids, and conducts a ritual. For days afterwards (maybe longer) the owner can see anything the demon uses remote vision to view, just by watching the surface's illusory reflections.", - narrative: "There are many legends about the creation of the goblet, and the fate of the Whisper who first energized it. Rumor suggests the Duskwall Council entrusted the goblet to a certain family for safekeeping." - }, - { - name: "Hollow Shroud", - category: "Religious Object", - desc: "The Church of the Ecstasy of the Flesh clergy wrapped the funeral shroud around a heretic, then conducted a ritual that severed the heretic's connection to the body, cutting the spirit loose as a ghost. The shroud transferred the spirit of a faithful but sickly member into the heretic's body. New life!", - narrative: "The Shroud was stolen almost twenty years ago, and rumors suggest it has been used in debased rituals to summon demons or enflesh echoes of the Forgotten Gods." - }, - { - name: "Idol of the Sleeping Lion", - category: "Religious Object", - desc: "The hefty iron statue depicts a devilfish-headed humanoid, cloaked in wings. Its presence influences human dreams, so they drift through the ink-black sea but can perceive their surroundings. Sacrificing to the statue gives a cultist a cosmic infection, involving psychic ability and mutations.", - narrative: "The statue has been retrieved by officers of the law several times, and destroyed several times more. Again and again, it emerges in the heart of fresh tragedy, baleful and singular." - }, - { - name: "Ink Fleece", - category: "Family Heirloom", - desc: "Long ago, Captain Manarill claimed he could prove that leviathans had fur, or fleece. He brought back a swatch of curling fur as big as a bedspread. He claimed to have harvested it from a leviathan's skin. The mantle served as a symbol of the Manarill family's heritage of exploration and danger. But it was stolen.", - narrative: "Does it do more than represent heritage? What dreams might one have while wrapped in it? Might a wealthy Whisper pay more for it than the family that owned it? Who took it?" - }, - { - name: "Kasavaraya Tea Set", - category: "Family Heirloom", - desc: "When the Immortal Emperor visited Akoros four centuries ago, he used this tea set with the patriarch of the Kasavaraya family. They are still one of the most decorated and entrenched military families in Duskwall. Their tea set is a symbol of Duskwall's prominence. However, a saucer and a cup are missing.", - narrative: "This stuff is priceless, literally, so negotiating a price for its return is tricky. If you could find the missing pieces, or forge them adequately, they would be great hostages to ajfed the family's behavior." - }, - { - name: "Kidnap The Heir", - category: "Secret Dirty Work", - desc: "People are keys that fit into estate locks. They can be turned to open the way to lots of money. You might be taking a child to ransom back to the guardian, or you might be getting someone out of the way so a more distant heir can inherit. This is about controlling where the money goes.", - narrative: "How harsh does the employer want this to be? Kid gloves treatment, or is the plan to kill the heir when it is all over? How much input will the employer accept from the hired help? Is the plan already in place?" - }, - { - name: "Krogs Broken Heart", - category: "Misplaced Fortune", - desc: "Krog was a savage from the Dagger Isles, pressed into service on a hunting ship. He eventually owned a small fleet. He was old when he fell in love with a young woman who robbed him. Heartbroken, he took the rest of his treasure aboard his last hunting ship, Heartsong, and scuttled her in the harbor.", - narrative: "Whispers like to brag they found a way under the waves to find the wealth. Gracmaas the Pirate claimed to have recovered it all to his hidden lair—before he was killed." - }, - { - name: "Limptwitch's Stash", - category: "Misplaced Fortune", - desc: "Limptwitch was a Whisper who interrogated ghosts to find the location of hidden treasure. He was famous for his Grotto, the place where he stored all his salvaged wealth. Many factions tried to get his treasure, but he never gave up the secret. Then he was jailed and hanged. The Grotto was never found.", - narrative: "Did a cellmate in prison hear muttered hints as to its location? Maybe a Whisper has clues based on where he left his mark in the sewers. Has someone finally found a real lead?" - }, - { - name: "Mark of the Void", - category: "Religious Object", - desc: "It is an eerie black disk of leviathan bone, about the size of a dinner plate but five times as thick. The bone is carved with a strange circular pattern with rays cutting through it. The primitive artwork was polished, and silver inlaid in the pattern, by a decadent nobleman.", - narrative: "Impressionable people admit the disk whispers to them, they hear the Back of the Mirror when it the disk is near. Many cults see this disk as a conduit to clearer communication with their supernatural patrons." - }, - { - name: "Naladicha's Cartography", - category: "Historical Curiosity", - desc: "The famous cartographer Naladicha died, and his ghost was woven into a spirit anchor connected to a pen on a wire. The drooping pen scribbled nonstop, dipping to indicate a page turn. Two books were filled with scribbles before the pen stilled. These lines and shapes may be maps of the Ghost Field.", - narrative: "One consulting Whisper reported that when she attuned to the books using an expensive and difficult ritual, the maps became luminous and four dimensional, revealing lost secrets in Duskwall." - }, - { - name: "Norscye's Lament", - category: "Famous Jewel", - desc: "This ruby has been set in a series of weapons for the last three centuries. One estimate was that the gem had participated in upwards of a thousand deaths. Legend suggests that the ruby can hold a single ghost, surviving the destruction of the body, bound to the gem until it chooses another guest.", - narrative: "While the gemstone is priceless because of its unnatural clarity, it is also possible that an important ghost might be inside, and might choose to speak to a Whisper or a blood relative." - }, - { - name: "Orb Of Sellivas", - category: "Weird Artifact", - desc: "This fist-sized golden orb tunes to one bearer at a time, though it may respond to others. If commanded, it can release a steady light that radiates in the material world and the Ghost Field, revealing what is hidden. The radiation can also draw or repel ghosts and demons.", - narrative: "The Sellivas order of witches wrote their research journals in an ink that can only be read by the light of the Orb. If someone had the Orb and the \"blank\" book, they could crack ancient secrets." - }, - { - name: "Plant Evidence", - category: "Secret Dirty Work", - desc: "Someone needs to be found guilty of doing something. For that to work out, you need evidence, put in the wrong place at the wrong time. To manage that, you need proper scoundrels.", - narrative: "Do you know what the target will be accused of doing? Are you to lead the authorities to the evidence? Must someone be seduced before a hidden witness? Are the scoundrels making evidence, or using what they're given? What if they could do better? Must the evidence fool a court, or a powerful individual?" - }, - { - name: "Plasmic Blade Flail", - category: "Weird Artifact", - desc: "This weapon can slay ghosts and demons. It appears to be a gladius stitched with runes. Once the bearer attunes to the weapon, it can disconnect into vertebrate-like wedges connected by a steely central cable. The blade-whip is flexible and simmering with energy. It can reform into a straight blade at will.", - narrative: "Only five of these flails ever existed. One is carried by the Spirit Warden assigned to the Immortal Emperor's defense. The rest are the stuff of legends." - }, - { - name: "Remote Writer", - category: "Weird Artifact", - desc: "This little book has a peculiar occult symbol on the cover. If an object is placed between the covers for a full 24 hours, then the book will transcribe any conversation happening in earshot of the object until reset. When the book reaches the end, the writing starts over on the first page, clearing pages as it goes.", - narrative: "The book provides remote reading, eavesdropping of a sort. A target's favorite pen or lucky coin can become the broadcaster, and determined spies can copy the magic book writing so they don't lose it." - }, - { - name: "Rylaria's Shield", - category: "Family Heirloom", - desc: "Rylaria Graefwold was a soldier who gained title and wealth. She wrote her life's story on the back of the shield she used to save a general. Later generations added to the family story. The shield represents the family's honor. It was lost at sea when their first leviathan hunting ship was wrecked. Or was it?", - narrative: "Now the family is wealthy, and this artifact would be important to them. Does it have a secret in code?" - }, - { - name: "Skovlan Scrip", - category: "Misplaced Fortune", - desc: "A dense lockbox filled with paper money issued by the Akorosian government to pay soldiers quelling the Skovlander Insurrection. The scrip can be exchanged for coins or services in Duskwall. Scrip is basically untraceable.", - narrative: "Some of the military supply that got lost during the war. Does the stashs location implicate a corrupt official or other thief?" - }, - { - name: "Sonurian Ghost Key", - category: "Family Heirloom", - desc: "The Sonuria family had mansions in the area that is now the Seven Shallows slum. They created a vault for the protected dead, and for their mundane treasures. The only way in is for a family member to present the Sonurian Ghost Key before the hidden location of the vault in the Ghost Field. The key has been lost for decades.", - narrative: "That key could be hidden anywhere. If it were found, either a family member could be recruited to open the door, or the key could be sold to the family. What does the key look like? What is inside the vault?" - }, - { - name: "Soultrap Carnelian", - category: "Famous Jewel", - desc: "This semi-precious stone was carved by the Whisper Ichralia. She suffocated people with hot wax and bound their fresh ghosts in wax seals on scrolls or letters with the Soultrap. When the seal was broken, the insane ghost attacked the opener and anyone nearby.", - narrative: "The Spirit Wardens destroyed this object decades ago. Didn't they? Maybe someone else made another one, or maybe the original survived." - }, - { - name: "Steal Blackmail", - category: "Secret Dirty Work", - desc: "Secrets must be protected. If they come out, people can get hurt, ruined, killed, and so on. You are hired to adjust the circle of people who can prove something. Will it be bigger? Or smaller?", - narrative: "Do you know what information you're after, or is that secret from you? If you have a chance, will you peek at it? Are you targeting a blackmailer to remove their hold, or getting evidence to give a blackmailer? Is the evidence to be destroyed? Do you plan to do as you are told?" - }, - { - name: "Terrorize", - category: "Secret Dirty Work", - desc: "People can be stubborn, to the point where only fear can unseat their decision. Maybe they feel independent and need to reminded that they need protection. Maybe they feel safe and need to be reminded they are not untouchable.", - narrative: "Are you supposed to be someone in particular, like a random street thug or rival's employee or bluecoat? How far can the terror go? Do you need to trash a home, or maybe converse with a loved one?" - }, - { - name: "The Emerald Well", - category: "Famous Jewel", - desc: "This depthless gem is a chilly pinhole between the material world and the Ghost Field. It provides energy to Whispers and attracts ghosts. The Emerald Well was protected by the Church of the Ecstasy of the Flesh, but a thief stole it decades ago. It is a hotspot for supernatural activity. Disaster flows in its wake.", - narrative: "This is one of the few objects pursued by demons, Whispers, inspectors, clergy, and collectors. Scholars suggest demons may be able to turn it inside out, creating a fresh gate to incarnate more demons." - }, - { - name: "The Hellwhisper Ring", - category: "Weird Scholarship", - desc: "The ring is made of tiny bits of bone wired together. It must be worn for at least a day per year of the bearer's life before it begins to work. When placed on a source of information, the ring sifts it until the ring speaks the information's \"language.\" The bearer can see through riddles, read arcane texts, and break code with ease.", - narrative: "Legend says 32 demons voluntarily gave some of their bone to be part of this ring, and it was released among humans to cause chaos through greater understanding." - }, - { - name: "The Helsman Inheritance", - category: "Misplaced Fortune", - desc: "The final will and testament of the clan's patriarch included a 24 hour locked-house condition. Survivors would split the inheritance. Darayl Helsman left the house at the end of the time with a small bag. Explorers found nothing but corpses in the house, the inheritance was gone. Darayl was found dead the next day, the bag gone. The city locked the house and guards against trespassers.", - narrative: "Surely Darayl hid the inheritance in the Ghost Field. Find the ghost key and lock in the house, and get it all! Or, did someone else already get it?" - }, - { - name: "The Key Lens", - category: "Weird Scholarship", - desc: "The round frame has forty special lenses hinged on its rim. The lenses can layer over each other, flip out past the frame, rotate to take advantage of the angles inside the ground crystal, and take translucent colored filters. Their inventor, VLAS HALDAK, said he had found \"the key.\" He died of shock, the lens on his work table.", - narrative: "Legends vary. It can see into the Ghost Field, it can see into people, it allows reading demonic texts, it can see the way into ghost neighborhoods, etc. Needs a Whisper to use properly." - }, - { - name: "The Leviathan's Eye", - category: "Famous Jewel", - desc: "This sapphire turns impossibly black if dipped in leviathan blood. If the still-bloody stone is pressed against a seer's forehead, the sensitive can see what the ocean sees, looking above the waves or probing the deeps. The gem used to be passed around between leviathan hunter captains, but has since been lost.", - narrative: "One expert said using the Eye was as close as a human could get to a demon seeing through its elemental affinity, and that it began a slow change in the individual who was exposed to its power." - }, - { - name: "The Tabissera Diary", - category: "Weird Scholarship", - desc: "Warden Khalana Uress was the Head Confessor of the Spirit Wardens. She recorded secrets that were only for the use of the order using a book code, coordinates that pointed to words in a specific book. Without that book, the code cannot be cracked. Daring thieves took the book, then lost it.", - narrative: "Fakes come on the market all the time. Only the Spirit Warden leadership know what the book looked like, and they aren't telling. What is the Diary about?" - }, - { - name: "The Thousand Facet Diamond", - category: "Famous Jewel", - desc: "This gem is the elegant centerpiece on the back of a peculiar clockwork gauntlet. A seer can use the gauntlet to travel into the Ghost Field while retaining physical presence, or possibly even other dimensions. Each use burns out some of the diamond facets. The device is reported to have a mind of its own.", - narrative: "Ever since its theft from the Adelairde family, the gauntlet has surfaced only in rumors of especially daring heists or mind-shattering experiments." - }, - { - name: "Whitecrown Signet Ring", - category: "Family Heirloom", - desc: "The Whitecrown family schismed in the wake of the theft of the matriarch's signet ring over two centuries ago. They fell from being players in the intrigues around the throne to bickering over dwindling family holdings. Their wealth and influence is low, but not beyond recall.", - narrative: "If the ring resurfaced, elements of the feud might put aside their differences and reunite. Besides, legends suggest a ghost matriarch is bound to the ring, and she knows their secrets." - } - ] - } -}; -export const ClockKey_SVGDATA = { - 1: { - height: 836, - width: 230, - paths: [ - "M217.017,123.52c-1.6-0.8-2.84-1.44-4.1-2.04c-1.12-0.53-2.26-1.04-3.42-1.51 c-1.05-0.43-2.18-0.68-3.18-1.19c-0.89-0.45-1.23-1.23-1.2-2.36c0.09-4.48-0.07-8.97,0.05-13.45c0.08-3.31-0.83-6.47-1.14-9.72 c-0.01-0.14-0.09-0.28-0.14-0.42c-0.57-2.01-1.2-4.01-1.69-6.04c-0.45-1.85-0.75-3.74-1.11-5.61 c-0.012-0.043-0.023-0.085-0.035-0.127c-0.6-1.69-1.348-3.353-1.825-5.083c-0.46-1.66-0.68-3.38-1.03-5.07 c-0.04-0.24-0.16-0.47-0.25-0.7c-0.49-1.32-0.98-2.65-1.47-3.97c-0.55-1.44-0.93-2.97-1.69-4.28c-0.79-1.35-0.65-3.03,0.61-4.19 c0.43-0.39,0.85-0.85,1.08-1.36c0.57-1.3,1.35-2.62,1.44-3.97c0.08-1.11-0.46-3.08-1.14-3.29c-1.58-0.47-3.49-0.42-5.1,0.03 c-1.41,0.4-2.59,1.63-4.07,2.62c-1.15-1.18-2.43-2.41-3.6-3.75c-0.41-0.47-0.43-1.29-0.82-1.78c-0.67-0.84-1.56-1.5-2.23-2.33 c-0.18-0.22-0.08-0.9,0.13-1.16c0.85-1.02,1.78-1.97,2.71-2.92c2.18-2.22,4.37-4.45,6.57-6.65c0.85-0.86,1.78-1.64,2.63-2.5 c1.16-1.17,2.38-2.29,3.37-3.59c0.66-0.88,0.89-2.07,1.42-3.06c0.86-1.63,0.01-3.02-0.68-4.31c-0.23-0.43-1.4-0.4-2.15-0.48 c-0.69-0.08-1.4,0.02-2.09-0.02c-1.71-0.11-3.14,0.17-4.52,1.47c-1.22,1.14-2.96,1.74-4.44,2.62c-0.98,0.59-1.89,1.31-2.88,1.88 c-2.02,1.17-4.2,2.11-6.07,3.47c-1.12,0.81-2.16,1.18-3.49,1.4c-1.28,0.22-2.44,1.1-3.7,1.59c-0.58,0.23-1.72,0.49-1.82,0.3 c-0.91-1.63-2.75-1.79-4.03-2.77c-0.33-0.25-0.58-0.62-0.93-0.82c-1.11-0.64-2.26-1.22-3.38-1.85c-1.48-0.83-2.94-1.7-4.42-2.53 c-0.93-0.53-1.83-1.24-2.84-1.5c-1.37-0.35-2.24-1.96-3.89-1.5c-0.08,0.03-0.19-0.02-0.29-0.04c-1.97-0.58-3.94-1.16-5.91-1.73 c-0.28-0.08-0.76-0.02-0.84-0.18c-0.89-1.7-2.8-1.2-4.1-1.6c-2.83-0.87-5.94-0.87-8.94-1.22c-0.39-0.04-1.05,0.06-1.14-0.13 c-0.79-1.56-2.21-1.01-3.4-1.05c-2.09-0.08-2.68-0.62-2.72-2.65c-0.01-0.84-0.1-1.69-0.24-2.51c-0.16-0.88-0.54-1.72-0.62-2.59 c-0.13-1.24-0.03-2.49-0.11-3.73c-0.06-0.88-0.61-1.45-1.5-1.13c-0.79,0.28-1.59,0.72-2.21,1.28c-1.48,1.36-2.85,2.84-4.29,4.25 c-1.1,1.08-2.08,2.06-3.81,2.55c-1.54,0.44-2.99,1.69-4.63,2.42c-1.79,0.8-3.28,2.25-5.44,2.13c-0.44-0.02-1.16-0.02-1.28,0.22 c-0.7,1.36-1.94,0.82-2.98,0.97c-0.49,0.07-0.99,0.11-1.47,0.24c-1.92,0.49-3.84,0.98-5.75,1.52c-1.74,0.49-3.51,0.95-5.19,1.61 c-1.92,0.74-3.67,1.99-5.63,2.46c-1.64,0.38-3.01,1.13-4.51,1.72c-0.99,0.39-2.52,0.38-3.43-0.13c-1.93-1.09-4.28-1.09-6.03-2.54 c-0.22-0.19-0.67-0.12-1.02-0.13c-0.9-0.02-1.79-0.02-2.69-0.02c-1.37,0.01-2.19,0.72-2.36,2.15c-0.09,0.78-0.06,1.59-0.09,2.38 c-0.01,0.35,0.11,0.87-0.06,1.02c-1.68,1.35-0.89,3.24-1.18,4.9c-0.16,0.88-0.56,1.8-1.1,2.51c-0.75,0.99-1.76,1.79-2.61,2.72 c-1.02,1.1-1.99,2.26-2.99,3.39c-1.49,1.67-2.96,3.37-4.5,5c-1.36,1.45-2.81,2.83-4.2,4.25c-0.16,0.17-0.19,0.46-0.31,0.67 c-0.74,1.29-1.39,2.64-2.25,3.84c-0.89,1.25-2.63,1.86-2.72,3.75c-0.02,0.38-0.57,0.73-0.86,1.11c-0.37,0.49-0.79,0.96-1.07,1.5 c-0.73,1.39-1.26,2.89-2.1,4.21c-1.08,1.71-2.25,3.34-2.65,5.38c-0.07,0.32-0.39,0.6-0.57,0.91c-0.21,0.34-0.45,0.67-0.59,1.05 c-0.43,1.21-0.72,2.48-1.24,3.65c-0.79,1.76-1.75,3.45-2.6,5.19c-1.27,2.6-2.74,5.13-3.69,7.85c-0.5,1.45-0.18,3.23-0.08,4.85 c0.05,0.7,0.68,1.37,0.69,2.06c0.06,6.07,0.06,12.15,0.01,18.23c0,0.71-0.37,1.44-0.63,2.13c-0.35,0.95-1.04,1.85-1.09,2.8 c-0.07,1.31-1.04,1.92-1.62,2.82c-0.91,1.43-2.71,1.9-3.59,3.51c-1.01,1.85-0.94,3.91,0.46,5.41c1.17,1.24,2.59,0.75,3.93,0.97 c1.41,0.22,3.01,0.26,4.12,0.99c1.11,0.74,1.87,2.16,2.5,3.43c0.77,1.56,1.35,3.24,1.8,4.92c0.67,2.5,0.94,5.12,2.32,7.4 c0.56,0.92,1.03,1.9,1.52,2.87c0.51,1.03,0.96,2.09,1.48,3.11c0.56,1.09,1.13,2.18,1.77,3.22c0.29,0.48,0.84,0.8,1.16,1.26 c0.61,0.87,1.11,1.82,1.71,2.69c0.32,0.47,0.83,0.81,1.16,1.27c0.93,1.3,1.79,2.65,2.73,3.95c0.31,0.43,0.83,0.69,1.15,1.11 c0.52,0.69,0.89,1.51,1.44,2.16c0.41,0.48,1.1,0.72,1.54,1.18c1.57,1.66,3,3.46,4.65,5.03c1.3,1.26,2.91,2.18,4.25,3.4 c1.99,1.84,3.82,3.85,5.81,5.7c0.51,0.47,1.42,0.47,1.99,0.9c0.95,0.71,1.78,1.59,2.88,2.59c-0.72,0.66-1.63,1.5-2.55,2.33 c-0.78,0.7-1.61,1.34-2.34,2.07c-1.54,1.55-3.05,3.13-4.54,4.73c-1.24,1.32-2.6,2.56-3.6,4.05c-0.6,0.91-1.1,1.85-1.89,2.63 c-1.23,1.21-1.21,4.03,0.24,4.66c1.03,0.45,2.61,0.53,3.57,0.03c1.41-0.72,2.76-0.5,4.14-0.57c1.93-0.09,3.89,0.02,5.8-0.21 c1.19-0.14,2.33-0.75,3.46-1.2c0.49-0.19,0.89-0.6,1.38-0.76c0.46-0.16,1.13,0.06,1.45-0.21c2.19-1.82,5.18-1.79,7.53-3.48 c1.41-1.01,3.25-2.21,5.36-2.06c0.28,0.02,0.58-0.29,0.88-0.44c0.42-0.22,0.85-0.61,1.29-0.62c3.43-0.04,6.86,0,10.3,0.03 c0.38,0,0.99-0.01,1.11,0.21c0.64,1.13,1.69,0.85,2.63,0.91c1.1,0.06,2.24-0.13,3.27,0.14c2.96,0.79,5.9,1.59,9,1.58 c6.02-0.03,12.05,0.27,18.01-0.93c0.82-0.17,1.69-0.08,2.52-0.24c1.04-0.2,2.05-0.52,3.14-0.81c0.13,0.6,0.21,0.79,0.21,0.98 c0.01,8.226,0.03,16.462,0.01,24.699c-0.001,0.368-0.217,0.882-0.515,1.099c-0.676,0.493-1.572,0.71-2.176,1.273 c-1.37,1.26-2.6,2.68-3.92,4c-0.73,0.73-1.61,1.32-2.31,2.08c-0.98,1.06-0.96,2.42-0.9,3.78c0.07,1.95,0.64,2.62,2.59,2.67 c1.712,0.061,3.434,0.019,5.146,0.03c1.112,0.007,2.014,0.908,2.024,2.02c0.06,6.72,0.08,13.44,0.15,20.16 c0.019,1.205-0.537,1.936-1.437,2.533c-0.23,0.153-0.451,0.318-0.644,0.516c-1.605,1.643-3.165,3.308-4.789,4.931 c-0.63,0.64-1.57,1.05-2.01,1.79c-1.29,2.14-3.22,3.55-5.3,4.69c-2.51,1.38-2.76,1.58-2.61,4.33c0.09,1.65,1.84,3.48,3.41,3.17 c1.82-0.35,3.74-0.85,5.26-1.85c0.77-0.51,1.38-0.68,2.16-0.71c0.95-0.04,1.9-0.01,2.84-0.01c2.59,0.01,3.03,0.46,3.03,3.1 c-0.01,31.18-0.02,62.36-0.04,93.55c0,2.88-0.13,5.78,0.03,8.66c0.16,2.8,0.67,5.58,0.91,8.39c0.15,1.83,0.08,3.68,0.15,5.52 c0.02,0.42,0.14,0.85,0.29,1.25c0.23,0.58,0.66,1.12,0.75,1.72c0.13,0.93-0.34,2.21,0.13,2.78c1.82,2.18-0.35,4.04-0.21,6.04 c0.01,0.2-0.21,0.41-0.31,0.62c-0.53,1.08-1.43,2.14-1.49,3.24c-0.21,4.27-0.19,8.56-0.19,12.84 c-0.01,51.9,0.01,103.81-0.05,155.71c0,4.36-0.54,8.71-0.84,13.06c-0.03,0.34-0.19,0.66-0.31,0.98c-0.25,0.69-0.73,1.36-0.74,2.05 c-0.12,5.68-0.07,11.36-0.23,17.03c-0.11,3.65-0.78,7.31-0.68,10.95c0.12,4.59-0.27,9.16,0.58,13.82 c0.85,4.63,0.19,9.53,0.21,14.31c0.01,1-0.27,2.32,0.24,2.92c1.2,1.39,0.69,2.89,0.79,4.35c0.03,0.33-0.22,0.7-0.37,1.03 c-0.25,0.55-0.55,1.06-0.76,1.62c-0.17,0.44-0.2,0.93-0.36,1.38c-0.47,1.36-0.97,2.72-1.45,4.08c-0.11,0.31-0.11,0.7-0.3,0.94 c-1.58,2-2.33,4.36-2.52,6.8c-0.23,3.07-0.06,6.17-0.08,9.26c-0.02,3.62,0.05,7.24,0.93,10.78c0.07,0.3,0.39,0.56,0.42,0.86 c0.13,1.29,0.2,2.59,0.29,3.88c-0.91,0.05-1.84,0.23-2.72,0.09c-0.66-0.1-1.24-0.71-1.91-0.9c-1.83-0.53-3.81,1.69-3.74,3.17 c0.1,2.16,0.3,4.33,1.59,6.15c1.14,1.6,2.44,3.09,3.73,4.57c1.18,1.36,2.64,2.45,2.25,4.66c-0.47,2.6-0.66,5.25-1.01,8.26 c-4.52,0.25-8.9,0.65-13.3,0.72c-8.65,0.13-17.32,0.08-25.98,0.13c-0.58,0-1.24-0.02-1.74,0.22c-1.03,0.49-1.92,1.28-2.97,1.7 c-1.85,0.75-3.77,1.31-5.65,1.96c-0.22,0.07-0.42,0.22-0.63,0.32c-1.16,0.57-2.28,1.38-3.51,1.64c-1.03,0.21-1.79,0.61-2.49,1.28 c-0.2,0.19-0.4,0.5-0.62,0.51c-1.14,0.08-2.03,0.39-2.85,1.34c-0.63,0.73-1.75,1.04-2.67,1.49c-1.72,0.84-3.48,1.61-5.18,2.49 c-1.48,0.77-3.04,1.49-4.33,2.53c-1.49,1.21-2.68,2.8-4.09,4.14c-0.84,0.79-1.75,1.75-2.79,2.02c-1.46,0.39-2.97,0.34-4.52,0.83 c-2.05,0.64-4.39,0.08-6.57,0.95c-1.38,0.54-3.25-0.48-4.4,1.21c-0.07,0.1-0.38,0.03-0.58,0.05c-2.5,0.25-4.95-0.04-7.53,0.73 c-3.19,0.97-6.74,0.74-10.14,1.08c-0.59,0.06-1.36,0.23-1.7,0.63c-0.83,1.02-0.42,3.75,0.69,4.4c0.91,0.54,2,0.82,3.05,1.07 c0.66,0.15,1.4-0.06,2.08,0.05c1.68,0.29,3.67-0.91,5.01,1.05c0.07,0.1,0.38,0.06,0.58,0.07c4.87,0.2,9.72,0.09,14.61,0.8 c4.38,0.64,8.94-0.01,13.42,0.18c3.03,0.13,5.86-0.88,8.82-1.09c0.14-0.01,0.35-0.06,0.4-0.15c0.61-1.3,1.84-0.85,2.85-1.06 c0.57-0.11,1.2-0.3,1.65-0.65c0.83-0.64,1.45-1.63,2.35-2.1c2.5-1.32,4.56-3.31,7.19-4.45c1-0.43,1.58-0.43,2.51,0.04 c0.62,0.31,1.68,0.25,2.33-0.08c1.06-0.53,1.88-0.64,2.74,0.22c0.76,0.76,1.53,1.51,2.34,2.23c1.14,1.02,2.41,1.91,3.46,3.02 c1.04,1.08,1.85,2.38,2.78,3.56c1.11,1.4,4.49,1.72,5.94,0.58c1.29-1.01,1.57-2.52,1.85-3.97c0.24-1.24,0.03-2.49,0.68-3.78 c0.9-1.75,1.39-2.39,3.41-2.36c2.29,0.02,4.58,0.1,6.87,0.11c1.04,0.01,1.62,0.52,1.84,1.5c0.31,1.31,0.45,2.68,0.96,3.9 c0.36,0.85,1.11,1.71,1.91,2.16c1.23,0.7,4.69-0.66,5.09-2.01c0.53-1.73,1.15-3.6,1-5.35c-0.24-2.82,1.44-4.54,2.89-6.43 c0.3-0.39,1.44-0.68,1.72-0.45c1.45,1.23,3.45,2.17,3.18,4.62c-0.06,0.64,0.09,1.3,0.02,1.94c-0.31,3.01-0.68,6.01-0.98,9.02 c-0.08,0.86-0.01,1.74-0.01,2.77c1.08-0.07,1.88-0.05,2.64-0.18c1.12-0.2,2.2-0.62,3.32-0.73c1.38-0.13,2.78-0.05,4.18-0.04 c1.86,0.01,2.13,0.24,1.82,2.07c-0.17,1-0.42,2.39-1.12,2.8c-1.1,0.65-0.86,1.44-0.87,2.24c-0.05,2.1-0.03,4.19-0.01,6.28 c0.01,0.44,0,1.19,0.2,1.26c1.41,0.53,0.81,1.71,0.98,2.64c0.17,0.9,0.34,1.81,0.64,2.66c0.39,1.08-0.23,3.51-1.19,3.75 c-1.67,0.43-3.39,0.66-5.09,0.99c-1.84,0.36-3.67,0.72-5.5,1.11c-0.22,0.05-0.4,0.28-0.61,0.39c-0.43,0.23-0.85,0.56-1.3,0.63 c-0.594,0.081-1.208,0.05-1.82,0.036c-1.386-0.033-2.643-0.905-3.075-2.222c-0.613-1.87-0.822-3.704-0.936-5.614 c-0.03-0.33-0.6-0.59-0.79-0.96c-0.43-0.85-1.13-1.77-1.07-2.62c0.07-0.98,1.05-1.44,2.19-1.38c0.81,0.04,1.64-0.21,2.44-0.43 c0.59-0.16,1.12-0.55,1.72-0.69c0.52-0.12,1.09-0.06,1.63-0.02c1.25,0.08,1.8-0.43,1.76-1.72c-0.05-1.89,0.01-3.78-0.01-5.68 c-0.01-1.66-0.83-2.55-2.56-2.57c-3.84-0.04-7.67-0.02-11.5,0.02c-1.16,0.01-1.74,0.7-1.85,1.83c-0.05,0.54-0.08,1.09-0.24,1.6 c-0.48,1.6-1.38,3.17-1.45,4.78c-0.08,1.83-0.74,3.01-2.08,4.1c-0.83,0.67-1.56,0.79-2.23,0.04c-1.08-1.22-2.09-2.51-3.04-3.83 c-1.06-1.48-1.88-3.17-3.08-4.51c-0.91-1.03-1.92-2.41-3.7-1.84c-0.51,0.17-0.93,0.69-1.44,0.79c-2.58,0.46-4.33,2.33-6.35,3.7 c-2.13,1.45-4.2,2.53-6.93,2.33c-3.17-0.24-6.37-0.07-9.55-0.09c-0.4,0-0.93,0.1-1.16-0.1c-1.75-1.51-4.32-2.07-5.29-4.5 c-0.06-0.13-0.33-0.24-0.5-0.25c-2.1-0.1-3.95-1.56-6.16-1.07c-0.31,0.07-0.68-0.08-1.02-0.17c-0.9-0.25-1.8-0.73-2.71-0.75 c-4.62-0.08-9.25-0.03-13.88-0.05c-0.46,0-0.94-0.13-1.38-0.29c-0.63-0.24-1.23-0.8-1.85-0.81c-6.97-0.06-13.94-0.01-20.91-0.06 c-1.47-0.01-2.4,0.9-3.11,1.81c-1.58,2.02,0.43,5.8,3.19,6.29c1.71,0.31,3.41,0.64,5.12,0.96c0.19,0.04,0.49,0.05,0.55,0.17 c0.65,1.18,1.78,0.83,2.77,0.94c2.9,0.31,5.78,0.66,8.67,1c0.103,0.019,0.206,0.038,0.308,0.057c2.154,0.545,4.296,1.193,6.481,1.6 c1.241,0.232,2.507,0.15,3.769,0.183c0.284,0.007,0.568,0.119,0.821,0.24c0.62,0.28,1.22,0.6,1.83,0.9 c1.33,0.65,2.68,1.25,3.98,1.96c0.4,0.22,0.6,0.76,0.96,1.06c1.45,1.23,2.93,2.41,4.37,3.64c0.97,0.82,1.92,1.67,2.84,2.54 c1.98,1.86,3.98,3.71,5.89,5.64c1.72,1.72,3.46,3.45,4.97,5.36c1.54,1.93,3.34,2.52,5.79,2.51c18.47-0.08,36.94-0.01,55.4,0.02 c2.17,0,4.19,0.14,5.7-2.14c1.09-1.64,2.99-2.73,4.39-4.2c0.74-0.77,1.1-1.87,1.77-2.73c0.68-0.88,1.47-1.69,2.3-2.45 c1.56-1.45,2.81-3.12,3.91-4.94c0.46-0.76,1.51-1.22,1.86-2.01c0.76-1.74,1.56-3.38,3.08-4.61c0.42-0.34,0.88-0.97,0.86-1.44 c-0.08-1.47,0.99-2.28,1.57-3.39c0.75-1.42,1.61-2.73,1.52-4.59c-0.21-4.42-0.08-8.86-0.05-13.29c0-0.61,0.19-1.23,0.35-1.83 c0.14-0.49,0.55-0.98,0.49-1.43c-0.39-3,0.95-5.77,1.1-8.7c0.01-0.2,0.23-0.39,0.34-0.59c0.26-0.47,0.56-0.92,0.78-1.41 c0.59-1.37,1.1-2.77,1.75-4.11c0.19-0.39,0.85-0.54,1.1-0.93c1.25-1.87,2.56-3.71,3.58-5.7c0.73-1.41,1.8-2.83,1.37-4.6 c-0.1-0.41-0.44-1.03-0.73-1.07c-2.3-0.28-4.43-1.46-6.87-1.09c-1.41,0.21-2.88,0.03-4.32,0.03c-2.22,0-2.56-0.51-2.76-2.74 c-0.2-2.19,1.03-4.66-1.1-6.53c-0.08-0.07-0.02-0.29-0.04-0.44c-0.26-2.65,0.17-5.27-0.75-7.99c-0.82-2.44,0.02-5.23-0.93-7.92 c-0.87-2.51,0.15-5.31-1.06-8.11c-1.14-2.64-0.76-5.92-1.16-8.91c-0.31-2.31,0.38-4.77-0.96-6.94c-0.31-0.5-0.91-0.93-1-1.46 c-0.41-2.24-0.68-4.5-1.01-6.76c-0.32-2.2-0.65-4.4-0.99-6.6c-0.03-0.19-0.09-0.47-0.23-0.53c-1.21-0.55-0.86-1.61-0.88-2.55 c-0.25-12.95,0.26-25.89-0.76-38.84c-0.645-8.159-0.207-16.407-0.21-24.606c0-0.326,0.03-0.655,0.132-0.964 c0.498-1.505,1.628-2.909,1.808-4.439c0.32-2.74,0.57-5.52,0.82-8.26c0.521-5.744,0.168-11.569,0.15-17.363 c-0.001-0.411-0.054-0.823-0.201-1.207c-0.519-1.358-1.356-2.643-1.619-4.039c-0.5-2.67-0.7-5.39-1.02-8.09 c-0.04-0.39-0.08-0.79-0.07-1.19c0.07-3.15-0.3-6.32,0.69-9.42c0.41-1.29-0.17-2.87,1.22-3.88c0.1-0.07,0.06-0.37,0.06-0.57 c0.04-8.32,0.08-16.64,0.08-24.96c0-0.43-0.28-0.88-0.45-1.31c-0.19-0.46-0.56-0.9-0.58-1.36c-0.48-11.05,0.53-22.1-0.75-33.17 c-0.77-6.68-0.15-13.52-0.19-20.29c-0.02-4.13-0.15-8.26-0.15-12.39c-0.01-44.063-0.01-88.115,0-132.178 c0-0.883,0.011-1.77,0.117-2.647c0.323-2.687-0.394-5.417,0.813-8.095c0.54-1.2,0.09-2.85,0.14-4.29c0.01-0.42,0.12-0.86,0.28-1.25 c0.26-0.62,0.63-1.2,0.88-1.82c0.14-0.36,0.1-0.78,0.19-1.16c0.48-2.02,1-4.03,1.44-6.05c0.25-1.17-0.47-2.63,1.09-3.39 c0.11-0.05,0.1-0.36,0.11-0.56c0.28-4.51,0.31-9,0.88-13.53c0.7-5.49,0.44-11.15,0.13-16.71c-0.31-5.55,1.18-10.95,0.94-16.46 c-0.02-0.62,0-1.25,0-1.92c0.98-0.1,1.74-0.1,2.45-0.27c0.7-0.17,1.35-0.53,2.03-0.75c1.92-0.62,2.45-1.33,2.42-3.39 c0-0.43-0.07-0.86-0.12-1.48h-4.97c-1.98-0.01-2.64-0.7-2.65-2.73c-0.01-0.75,0.05-1.5-0.01-2.25c-0.53-6.86,1.3-13.97-2.06-20.55 c0.49-2.24-1.35-4.79,0.96-6.8c1.23-1.08,2.27-2.42,3.62-3.33c1.23-0.83,2.52-1.47,3.3-2.84c0.8-1.42,2.89-2.31,4.31-1.95 c1.05,0.28,2.12,0.53,3.13,0.92c2.26,0.86,4.46,1.89,6.75,2.65c0.94,0.32,2.23,0.47,3.05,0.06c1.77-0.89,2.89-2.77,3.34-4.51 c0.76-2.92,0-5.91-1.12-8.69c-0.5-1.24-0.4-1.92,0.76-2.43c1.71-0.75,3.37-1.59,5.07-2.37c2.07-0.95,3.93-2.43,6.34-2.56 c0.29-0.02,0.55-0.33,0.84-0.5c0.37-0.23,0.78-0.65,1.14-0.63c1.59,0.13,3.06-0.23,4.74,0.92c1.61,1.11,4.13,0.99,6.27,1.19 c1.93,0.17,2.82-0.82,3-2.78c0.04-0.43,0.26-0.88,0.47-1.28c0.39-0.75,1.16-1.46,1.2-2.22c0.07-1.42,0.75-3-1.6-3.85 c-1.72-0.61-2.93-2.52-4.52-3.62c-1.38-0.96-2.98-1.6-4.73-2.51c0.24-0.6,0.46-1.24,0.75-1.85c0.82-1.72,1.67-3.42,2.49-5.13 c0.34-0.73,0.5-1.6,1.01-2.17c1.42-1.63,1.98-3.64,2.79-5.55c0.36-0.87,0.45-1.99,1.06-2.59c1.09-1.06,1.52-2.34,1.98-3.69 c0.29-0.85,0.66-1.68,1.09-2.46c0.51-0.93,1.33-1.73,1.67-2.7c0.81-2.39,2.14-3.18,4.45-2.38c0.31,0.1,0.7,0.11,1.03,0.04 c1.17-0.22,2.36-0.41,3.5-0.76c1.24-0.38,2.44-0.9,3.62-1.43c0.21-0.08,0.37-0.5,0.37-0.77 C217.026,126.28,217.017,124.66,217.017,123.52z M143.507,186.1c-0.82,0.65-1.72,0.95-2.7,1.06c-9.15,3.4-19.04,5.26-29.37,5.26 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,143.31,174.167,173.48,143.507,186.1z", - "M214.327,133.65c-1.07-0.77-2.58-1.24-3.21-2.27c-2.25-3.6-6.31-7.65-5.88-11.05 c1.52-12.04-0.33-23.52-2.8-35.1c-1.17-5.49-2.18-10.99,4.72-14.06c1.08-0.48,1.88-3.13,1.63-4.57c-0.19-1.07-2.16-2.19-3.55-2.64 c-6.7-2.14-12.98-4.88-17.4-10.69c-8.86-11.65-19.24-21.69-32.64-27.85c-6.64-3.05-11.86-6.24-11.09-14.54 c0.07-0.78-0.31-1.64-0.64-2.4c-1.25-2.84-2.56-5.66-3.84-8.48c-2.09,2.6-4.15,5.23-6.27,7.81c-1.41,1.73-2.68,4.5-4.41,4.85 c-5.32,1.1-10.85,1.76-16.28,1.67c-10.63-0.18-20.99,1.14-30.97,4.67c-7.85,2.78-15.14,3.77-22.72-1.31 c-3.42-2.29-8.09-2.69-13.48-4.35c1.1,3.41,1.68,5.25,2.3,7.08c2.66,7.87,2.9,14.94-4.11,21.28c-9.76,8.83-16.78,19.74-21.74,31.96 c-3.43,8.43-7.09,16.77-10.4,25.25c-0.69,1.77-0.76,4.07-0.31,5.93c1.61,6.58,3.4,13.13,5.43,19.59c3.09,9.77,5.6,19.86,9.93,29.08 c3.68,7.83,9.58,14.63,14.68,22.14c-0.79,0.96-2.1,2.1-2.8,3.53c-1.36,2.82-2.37,5.81-3.53,8.72c3.12,0.11,6.55,1.11,9.29,0.15 c8.09-2.86,14.4-0.35,20.54,4.73c2.39,1.98,2.05,3.36,0.46,5.32c-5.83,7.15-10.71,15.15-18.99,20.06 c-0.98,0.57-0.82,3.05-1.18,4.65c1.4,0.24,3.08,1.12,4.16,0.63c10.45-4.67,20.76-9.67,31.2-14.38c6.31-2.84,12.43-5.88,19.84-5.85 c10.42,0.05,20.84-1.07,31.26-1.7c1.76-0.11,3.51-0.28,5.42-0.43c0.16,1.54,0.36,2.51,0.36,3.49 c-0.02,59.51,0.09,119.02-0.28,178.52c-0.04,6.76-2.01,13.66-6.63,19.46c-5.78,7.26-11.13,14.88-16.46,22.49 c-0.72,1.03-0.2,2.93-0.26,4.43c1.3-0.02,2.66,0.24,3.87-0.09c5.76-1.56,11.47-3.28,18.14-5.22c0.62,6.25,1.49,10.98,1.5,15.73 c0.13,47,0.21,94.01,0.09,141.01c-0.02,9.45-0.81,18.9-1.43,28.34c-0.51,7.62-1.87,15.22-1.81,22.82 c0.09,11.27,1.35,22.52,1.59,33.8c0.11,4.87-1.07,9.77-1.69,14.65c-0.95,7.5-2.36,14.98-2.73,22.51c-0.3,6.1,1.55,12.38,0.78,18.37 c-0.97,7.49-5.01,14.53-11.46,18.32c-5.29,3.13-12.04,4.52-18.29,5.09c-7.23,0.66-14.61-0.47-21.92-0.75 c-7.56-0.29-13.36-5.01-15.18-12.31c-0.24-0.97-0.97-2.04-1.79-2.6c-3.54-2.44-7.19-4.7-11.02-7.17 c-6.83,8.88-7.82,11.33-7.65,21.13c0.27,15.78,1.28,31.58,0.87,47.34c-0.19,7.12-0.36,13.84,2.91,20.27 c0.57,1.13,1.4,2.86,2.29,2.97c6.4,0.82,12.69,3.55,19.18-1.16c3.35-2.42,8.23-3.21,12.54-3.72c7.41-0.88,14.92-0.84,22.37-1.43 c4.08-0.32,7.49-1.9,7.64-6.78c0.16-4.95,2.49-7.46,7.41-7.25c1.26,3.22,2.35,6.35,3.73,9.34c0.48,1.05,1.56,2.34,2.55,2.54 c3.24,0.62,6.57,0.74,9.86,1.16c3.38,0.42,5.09-0.92,6.01-4.3c1.78-6.56,3.92-13.02,6.08-19.47c1.92-5.71,2.31-11.28-0.26-16.93 c-0.69-1.51-0.6-3.37-1.02-5.99c2.46,0.64,3.97,1.18,5.52,1.41c2.3,0.33,4.62,0.44,6.93,0.65c-0.07-2.7,0.5-5.64-0.37-8.06 c-1.39-3.88-4.05-7.3-5.6-11.14c-2.34-5.79-5.86-11.75-5.96-17.69c-0.58-35.66-0.34-71.34-0.33-107.01c0-1.81,0.12-3.68,0.57-5.42 c3.38-13.1,3.56-26.5,1.68-39.63c-1.53-10.75-1.54-20.97,1.15-31.44c1.09-4.23,1.29-8.84,1.02-13.23 c-1.21-19.88-3.7-39.73-3.94-59.61c-0.62-50.99-0.29-102-0.34-153.01c0-1.66-0.07-3.35,0.18-4.98c1.91-12.43,4.96-24.78,5.62-37.26 c1.28-24.01,3.36-48.15-1.87-72.06c-0.27-1.25,0.73-3.34,1.8-4.23c9.73-8.05,9.78-8,20.31-1.11c0.7,0.46,1.39,1.05,2.17,1.23 c2.36,0.55,6.51,1.85,6.85,1.21c1.35-2.54,2.6-5.99,1.92-8.6c-2.38-9.22-2.43-17.78,3.82-25.59c2.88-3.6,5.07-8.11,8.66-10.71 c4.75-3.45,10.65-5.28,15.88-8.13c2.41-1.3,5.32-2.92,6.4-5.17C220.707,136.36,216.637,135.31,214.327,133.65z M111.437,192.42 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z", - "M216.086,109.69c-0.08-0.48,0.02-1-0.02-1.5c-0.07-0.95,0.16-2.22-0.36-2.76 c-0.73-0.76-2.03-0.97-3.07-1.46c-0.63-0.3-1.24-0.67-1.83-1.05c-0.53-0.33-1.08-0.65-1.53-1.07c-0.8-0.74-1.92-0.81-2.57-2.09 c-1.13-2.22-0.49-4.7-1.75-6.94c-1-1.8,0.07-4.32-0.91-6.51c-0.3-0.67,0.89-2,1.37-3.04c0.65-1.39,2.31-2.03,2.57-3.75 c0.12-0.81,0.64-1.61,1.15-2.28c1.78-2.38,1.16-5.33-1.31-6.02c-1.49-0.42-2.55-1.16-3.72-2.06c-1.21-0.92-2.77-1.49-4.25-1.92 c-1.54-0.44-2.15-1.61-2.84-2.79c-0.59-1.02-1.09-2.11-1.76-3.08c-0.71-1.02-1.59-1.93-2.47-2.98c0.35-0.13,0.74-0.16,0.86-0.35 c1.27-2.02,3.25-2,5.28-1.95c1.15,0.02,2.4,0.21,3.44-0.16c1.28-0.45,2.71-1.16,3.49-2.19c1.24-1.65-0.42-4.48-2.46-4.74 c-1.98-0.25-3.94-0.58-5.91-0.89c-0.18-0.03-0.34-0.15-0.51-0.22c-0.77-0.33-1.52-0.72-2.32-0.95c-0.57-0.16-1.22,0.01-1.79-0.13 c-2.14-0.53-4.24-1.43-6.41-1.61c-1.69-0.14-2.87-0.66-4.02-1.8c-1.28-1.26-2.82-2.26-4.1-3.52c-0.3-0.29-0.23-1.24,0-1.73 c0.44-0.91,1.54-0.97,2.32-1.44c1.74-1.05,3.29-2.45,4.89-3.74c0.52-0.42,1.31-0.9,1.38-1.42c0.19-1.46,0.06-2.96,0.06-4.5 c-2.54-0.33-4.95-0.67-7.38-0.94c-0.89-0.1-1.81-0.01-2.71-0.03c-0.34-0.01-0.68-0.07-1.01-0.16c-0.89-0.23-1.76-0.69-2.64-0.7 c-4.02-0.08-8.04-0.03-12.07-0.05c-0.42,0-1.11,0-1.23-0.23c-1.12-2.09-3.02-1.96-4.92-1.88c-1.14,0.04-1.8-0.46-2.06-1.62 c-0.27-1.22-0.34-2.76-1.12-3.54c-1.17-1.16-0.68-2.45-1.05-3.64c-0.33-1.08-0.81-2.76-1.52-2.93c-2.01-0.5-4.21-0.87-6.23,0.31 c-0.93,0.54-1.88,1.05-2.87,1.44c-1.21,0.48-2.61,0.61-3.7,1.27c-1.77,1.08-3.79,0.89-5.3,0.34c-1.38-0.5-2.66-0.56-4-0.68 c-0.75-0.06-1.5-0.02-2.23-0.16c-0.94-0.18-1.87-0.77-2.76-0.69c-1.9,0.18-3.03-0.91-3.97-2.14c-1.29-1.72-2.14-3.79-3.53-5.41 c-1.31-1.54-1.8-3.71-3.74-4.73c-0.49-0.26-0.96-0.67-1.48-0.73c-0.94-0.12-1.92-0.14-2.85,0c-0.59,0.08-1.26,0.41-1.66,0.85 c-0.55,0.59-0.75,1.49-1.3,2.07c-1.44,1.55-2.99,3-4.48,4.5c-0.13,0.12-0.12,0.38-0.22,0.55c-0.46,0.75-0.9,1.52-1.42,2.22 c-0.5,0.67-1.12,1.24-1.62,1.91c-0.48,0.62-0.79,1.38-1.31,1.96c-1.39,1.54-3.54,0.54-5.35,1.73c-2.13,1.39-5.14,1.6-7.81,1.92 c-2.43,0.29-4.97,0.32-7.37-0.06c-1.44-0.23-2.84-1.32-4.04-2.3c-1.44-1.18-2.57-2.71-4.77-2.47c-0.61,0.06-1.27-0.43-2.23-0.78 c-0.27,0.91-0.79,1.91-0.83,2.92c-0.13,3.22-0.1,6.44-0.1,9.66c0,0.72-0.13,1.16-0.84,1.66c-1.79,1.24-3.39,2.74-5.12,4.08 c-0.33,0.26-0.9,0.26-1.36,0.33c-0.69,0.1-1.75-0.09-2.02,0.28c-0.84,1.21-1.97,0.84-3.05,0.96c-0.53,0.06-1.05,0.27-1.56,0.43 c-1.41,0.44-2.79,0.98-4.23,1.32c-1.4,0.33-3.13-0.6-4.16,1.16c-0.06,0.1-0.38,0.07-0.58,0.08c-1.15,0.07-2.3,0.17-3.45,0.2 c-2.18,0.07-2.94,0.91-2.47,2.97c0.12,0.55,0.55,1.09,0.97,1.51c0.85,0.82,1.83,1.51,2.67,2.35c1.09,1.09,2.1,2.27,2.99,3.24 c-0.99,1.5-1.8,2.84-2.73,4.09c-0.62,0.83-1.51,1.47-2.09,2.32c-1.11,1.6-2.09,3.3-3.12,4.96c-0.31,0.5-0.73,0.96-0.93,1.51 c-0.5,1.33-2.38,2.73-3.8,2.76c-1.15,0.03-2.49-0.24-3.4,0.26c-1.3,0.71-2.55,0.65-3.86,0.66c-2.14,0.01-4.03,0.57-5.36,2.35 c-0.3,0.41-0.32,1.02-0.56,1.48c-0.7,1.31-0.46,3.54,0.67,4.44c0.88,0.71,1.97,1.17,2.86,1.87c0.75,0.58,1.24,1.6,2.06,1.97 c1.26,0.57,1.85,1.38,1.54,2.64c-0.41,1.68,0.4,3.44-0.77,5.14c-0.67,1,0.34,2.85-1.26,3.76c-0.08,0.04-0.05,0.28-0.06,0.43 c-0.07,1.2-0.32,2.3-0.72,3.49c-0.69,2.08-1.06,4.24-2.44,6.06c-1.06,1.41-1.99,2.97-2.99,4.37c-1.47,2.05-3.91,3.38-5.93,5.04 c-0.77,0.63-1.44,1.4-2.26,1.94c-2.24,1.47-2.4,4.44-0.52,6.31c1.02,1.02,2.11,0.63,3.19,0.81c0.52,0.08,1.08,0.08,1.56,0.28 c1.37,0.58,2.71,1.21,4.05,1.87c0.66,0.33,1.54,0.63,1.86,1.2c0.54,0.99,0.73,2.18,1.06,3.29c0.11,0.38,0.15,0.8,0.33,1.14 c0.54,0.96,1.26,1.84,1.67,2.85c1.1,2.69,0.84,5.73,2.18,8.41c0.66,1.31,0.76,2.91,1.15,4.37c0.3,1.13,0.34,2.53,1.05,3.3 c0.9,0.97,0.77,1.95,0.91,3c0.09,0.63,0.37,1.24,0.6,1.95c-0.55,0.45-1.38,0.87-1.82,1.55c-0.96,1.47-1.52,3.18-2.98,4.34 c-1.33,1.06-0.8,2.64-0.82,4.03c-0.02,1.27,1.61,3.18,2.84,3.32c3.02,0.36,6.04,0.64,9.06,0.96c0.33,0.04,0.81,0.04,0.95,0.24 c1,1.45,2.98,2.44,2.17,4.75c-0.11,0.31,0.39,0.78,0.39,1.18c0.02,1.32,0.11,2.68-0.17,3.95c-0.22,1.01-1.1,1.86-1.41,2.87 c-0.54,1.71,0.41,3.02,1.55,4.15c1.28,1.27,1.94,1.24,3.66,0.26c0.96-0.55,1.99-1.12,3.06-1.32c1.94-0.35,3.1,1.4,4.64,2.13 c1.17,0.55,2.17,1.43,3.34,1.98c1.51,0.72,3.1,1.19,4.05,2.8c0.33,0.57,1.26,0.78,1.9,1.19c0.6,0.38,1.4,0.7,1.69,1.26 c0.51,1.03,0.69,2.23,1.05,3.34c0.14,0.4,0.35,0.83,0.65,1.11c0.69,0.66,0.82,3.4,0.13,4.02c-1.03,0.92-1,1.59,0.01,2.49 c0.82,0.73,1.45,1.79,2.39,2.23c0.75,0.36,1.85,0.05,2.78-0.07c0.31-0.04,0.58-0.53,0.9-0.55c3.1-0.24,5.89-1.34,8.58-2.84 c0.3-0.16,0.95-0.17,1.14,0.03c0.76,0.82,2.02,1.28,1.69,2.88c-0.33,1.67,0.2,3.38-1.17,4.99c-1.23,1.45-2.01,3.39-2.64,5.23 c-0.38,1.12-0.54,2.67-0.05,3.67c1.2,2.45,4.7,2.61,6.65,0.57c0.81-0.86,1.69-1.67,2.6-2.42c0.67-0.55,1.47-0.95,2.18-1.46 c0.32-0.22,0.58-0.52,0.85-0.79c0.92-0.91,1.79-1.88,3.23-1.91c0.07-0.01,0.12-0.25,0.21-0.36c0.47-0.55,0.87-1.23,1.45-1.62 c1.52-1.02,3.11-1.93,4.71-2.83c0.26-0.15,0.74-0.13,1.03,0.01c0.92,0.44,2.1,0.77,2.65,1.53c1.27,1.72,2.45,3.58,3.25,5.55 c0.83,2.06,3.35,3.48,5.17,2.57c1.67-0.83,2.63-2.52,4.53-3.18c1.48-0.51,2.62-2,3.93-3.03c0.29-0.22,0.64-0.44,0.98-0.49 c2.46-0.4,4.93-0.75,7.39-1.13c0.2-0.03,0.4-0.06,0.58-0.14c2.21-1.02,3.32-0.31,3.32,2.12c0,14.19-0.05,28.38,0.05,42.57 c0.01,1.86-0.96,2.7-2.18,3.62c-1.74,1.29-3.51,2.55-5.17,3.94c-1.03,0.85-1.73,2.36-2.86,2.77c-2.07,0.74-3.5,2.3-5.3,3.36 c-0.78,0.46-2.38,1.3-1.52,2.46c0.73,0.98,1.51,2.42,3.29,2.29c1.75-0.12,3.52-0.01,5.28,0.04c0.36,0.01,0.79,0.11,1.07,0.32 c0.62,0.47,1.08,1.3,1.76,1.51c2.45,0.76,2.94,2.75,3.4,4.84c0.09,0.38,0.22,0.9,0.49,1.05c1.71,0.98,1.74,2.53,1.65,4.2 c-0.06,1.3,0.03,2.61,0.03,3.92c0,29.84,0.04,59.67-0.06,89.5c-0.01,2.31,0.88,4.73-0.96,7.07c-0.87,1.09-0.54,3.2-0.94,4.86 c-0.58,2.45-0.57,4.95-2.05,7.23c-0.78,1.21-0.76,2.94-1.11,4.44c-0.34,1.49-0.68,2.98-1.03,4.46c-0.03,0.13-0.14,0.34-0.23,0.35 c-1.15,0.18-0.88,1.09-0.84,1.76c0.05,0.94-0.27,1.83,0.87,2.72c0.82,0.63,0.83,2.35,1.12,3.6c0.4,1.74,0.73,3.51,1.09,5.26 c0.03,0.15,0.05,0.32,0.13,0.42c1.29,1.52,1.66,3.35,1.96,5.25c0.2,1.27,0.59,2.51,0.92,3.76c0.03,0.12,0.2,0.2,0.26,0.33 c0.28,0.55,0.77,1.11,0.79,1.68c0.09,3.17,0.09,6.34,0.08,9.51c-0.01,53.22-0.02,106.45-0.08,159.68c0,1.51,0.78,3.34-1.06,4.47 c-0.08,0.05-0.06,0.29-0.07,0.43c-0.29,3.58-0.58,7.16-0.86,10.73c-0.32,4.15-0.63,8.3-0.97,12.45c-0.03,0.37-0.26,0.73-0.4,1.09 c-0.22,0.55-0.64,1.11-0.63,1.66c0.01,2.21,0.17,4.31,0.9,6.56c0.95,2.95,0.48,6.31,0.89,9.51c0.6,4.76,0.19,9.64,0.22,14.47 c0,0.5-0.1,1.11,0.14,1.48c1.42,2.19,0.48,4.57,0.54,6.84c0.04,1.47-0.44,2.98-0.84,4.43c-0.28,0.99-0.67,2.02-1.29,2.82 c-0.83,1.08-1.77,2.01-1.64,3.52c0.05,0.49,0.15,1.21-0.11,1.46c-1.13,1.09-0.65,2.44-0.83,3.69c-0.31,2.06,0.16,4.04-0.82,6.24 c-0.96,2.19-0.26,5.14-0.16,7.75c0.02,0.5,0.87,0.95,0.93,1.47c0.29,2.77-0.03,5.53,0.85,8.32c0.65,2.07,0.26,4.49,0.21,6.75 c-0.04,2.22,0.51,4.38,0.15,6.66c-0.41,2.56-0.2,5.21-0.29,7.83c-0.01,0.43-0.02,1.12-0.27,1.26c-1.4,0.77-2.83,1.57-4.34,2.04 c-1.7,0.53-3.51,0.72-5.26,1.07c-0.15,0.02-0.35,0.06-0.42,0.16c-1.05,1.6-2.96,1.06-4.42,1.69c-1.82,0.79-3.98,0.8-5.99,1.16 c-0.29,0.05-0.67,0.1-0.83,0.3c-1.07,1.37-2.9,1.4-4.18,1.54c-2.35,0.25-4.8-0.49-7.21-0.82c-0.14-0.02-0.32-0.1-0.39-0.21 c-1.13-1.76-2.78-0.72-4.19-0.71c-0.45,0-0.86,0.75-1.36,0.9c-1.49,0.44-3.02,0.74-4.53,1.14c-0.22,0.06-0.35,0.43-0.57,0.58 c-0.67,0.47-1.36,1.26-2.06,1.29c-3.56,0.13-7.14,0.07-10.71,0.04c-0.34,0-0.71-0.21-1.04-0.37c-0.54-0.26-1.05-0.56-1.58-0.84 c-0.82-0.43-1.69-0.79-2.43-1.32c-0.47-0.34-0.64-1.1-1.12-1.39c-1.87-1.14-3.1-2.75-4.11-4.66c-0.29-0.55-1.05-1.17-1.64-1.22 c-2.71-0.22-5.54-0.58-7.69,1.72c-0.83,0.9-1.8,1.06-2.92,1.04c-0.38,0-0.87,0.04-1.14,0.26c-1.57,1.29-3.5,1.51-5.38,1.82 c-2.39,0.39-4.78,0.67-7.17,1.02c-0.22,0.03-0.39,0.29-0.61,0.39c-1.11,0.5-2.2,1.26-3.35,1.41c-2.09,0.25-3.01,0.98-2.64,3.04 c0.19,1.07,0.64,2.49,1.43,2.95c1.21,0.72,2.83,0.7,4.26,1.06c1.65,0.43,3.28,0.93,4.92,1.42c1.01,0.3,2.01,0.63,3.03,0.92 c1.88,0.54,3.74,1.35,5.66,1.53c3.04,0.28,6.13,0.18,9.19,0.18c13.52,0.02,27.05,0,40.57,0.04c1.41,0.01,3.03-0.62,4.13,0.94 c0.1,0.14,0.48,0.07,0.73,0.09c5.48,0.4,11.03-0.61,16.46,0.99c1.95,0.58,4.05,0.68,6.11,1c0.07,1.26,0.61,2.47-0.7,3.3 c-0.85,0.54-1.65,1.22-2.57,1.58c-2.2,0.85-4.44,1.57-6.68,2.32c-0.99,0.34-2.02,0.59-3.01,0.94c-1.67,0.58-3.32,1.21-4.98,1.82 c-0.23,0.09-0.44,0.21-0.66,0.31c-0.53,0.24-1.04,0.64-1.58,0.69c-5.18,0.48-10.35-0.17-15.61,0.68 c-5.76,0.93-11.79-0.18-17.64,1.1c-0.82,0.18-1.73-0.09-2.55,0.08c-1.8,0.37-3.61,0.77-5.32,1.42c-0.58,0.21-1.08,1.13-1.26,1.82 c-0.66,2.45,1.02,5.29,4.03,5.07c1.83-0.13,3.72,0.54,5.59,0.87c0.12,0.02,0.22,0.18,0.34,0.24c0.72,0.31,1.43,0.85,2.17,0.88 c2.51,0.11,5.03,0.09,7.54,0.03c1.18-0.03,2.56,0.41,3.33-1.08c0.07-0.15,0.56-0.11,0.86-0.11c5.22,0.01,10.44,0.02,15.66,0.05 c0.34,0,0.79,0,1,0.19c1.32,1.25,2.86,1.82,4.67,1.79c1.63-0.02,3.26,0.01,4.6,1.25c0.06,0.99-0.12,1.83-1.41,1.95 c-0.23,0.02-0.46,0.31-0.66,0.5c-1.32,1.33-2.56,2.77-3.99,3.98c-1.06,0.89-2.34,2.07-3.56,2.12c-2.5,0.1-4.06,2.03-6.3,2.6 c-1.31,0.34-2.46,1.45-3.98,1.52c-0.29,0.01-0.67,0.07-0.83,0.26c-1.11,1.31-2.62,1.66-4.2,1.76c-1.8,0.12-3.76-0.26-5.37,0.33 c-1.58,0.59-3.07,0.54-4.61,0.59c-1.96,0.05-3.92,0.02-5.88,0c-0.39,0-0.79-0.07-1.16-0.17c-0.83-0.22-1.64-0.59-2.48-0.71 c-2.61-0.36-5.24-0.64-7.85-0.96c-0.15-0.02-0.38-0.06-0.41-0.14c-0.54-1.36-1.74-0.98-2.71-0.99c-4.02-0.06-8.04-0.04-12.07-0.05 c-0.4,0-0.81,0-1.19-0.08c-1.18-0.25-2.34-0.57-3.51-0.81c-0.49-0.09-1.19,0.17-1.47-0.09c-1.49-1.32-3.25-0.64-4.88-0.82 c-0.45-0.05-1.2,0.06-1.3-0.14c-0.68-1.42-1.93-1.03-3.02-1.06c-2.06-0.05-5.27-2.58-6.24-4.39c-0.87-1.64-2.23-3.05-3.48-4.46 c-1.04-1.17-2.36-2.08-3.33-3.29c-0.87-1.07-1.16-2.84-2.21-3.49c-1.93-1.2-2.76-3.77-5.53-3.92c-0.11,0.08-0.58,0.28-0.75,0.63 c-0.28,0.54-0.63,1.29-0.45,1.77c0.48,1.3,1.57,2.45,1.78,3.76c0.36,2.21,2.01,3.73,2.59,5.88c0.45,1.67,1.26,3.48,2.41,5.08 c1.14,1.56,1.41,3.74,2.13,5.63c0.43,1.16,0.89,2.33,1.51,3.4c0.36,0.63,1.01,1.13,1.61,1.59c0.67,0.5,1.52,0.79,2.13,1.35 c0.78,0.7,1.25,1.83,2.11,2.32c1.81,1.02,4.06,1.07,5.77,2.38c0.07,0.06,0.21,0.06,0.3,0.04c2.43-0.53,4.36,1.08,6.06,2.12 c2,1.24,4.52,2.12,5.74,4.61c0.47,0.95,1.67,1.55,3.12,0.54c0.9-0.62,2.18-0.69,3.18-1.48c1.15-0.91,2.59-1.45,3.89-2.16 c0.34-0.18,0.65-0.55,0.97-0.56c2.21-0.07,4.53-0.5,6.59,0.05c1.65,0.44,3.29,0.44,4.91,0.75c3.34,0.63,6.68,1.23,10.11,1.01 c0.19-0.02,0.47-0.04,0.58,0.07c1.69,1.69,4.5-0.27,6.04,1.88c2.64-0.06,5.21,0.33,7.75,1.05c1.35,0.38,2.74,0.65,4.1,0.98 c0.13,0.03,0.21,0.2,0.34,0.27c1.18,0.58,2.33,1.28,3.57,1.7c1.36,0.47,2.81,0.68,4.22,1.01c0.12,0.03,0.22,0.16,0.34,0.24 c0.93,0.58,1.82,1.22,2.8,1.71c1.03,0.51,2.68,0.57,3.1,1.35c1.03,1.92,2.93,2.76,4.5,3.64c1.3,0.73,3.45,0.26,5.09-0.18 c0.46-0.12,0.44-2.05,0.6-3.16c0.06-0.34-0.03-0.71,0.02-1.05c0.29-1.88-1.12-3-1.84-4.46c-0.7-1.42-2.24-1.12-3.03-2.13 c-0.57-0.71-1.11-1.52-1.85-1.99c-1.99-1.26-4.2-2.07-5.98-3.79c-1.42-1.38-3.36-2.21-5.05-3.33c-0.53-0.36-0.97-0.86-1.6-1.43 c1.59-0.28,2.79-0.38,3.91-0.73c1.33-0.42,2.56-1.15,3.88-1.59c1.23-0.41,2.52-0.08,3.86-0.73c1.07-0.51,2.44-1.28,3.54-1.27 c4.9,0.06,9.87-1.42,14.74,0.77c1.85,0.84,4.1,0.89,6.19,1.08c2.2,0.2,4.42,0.08,6.63,0.19c1.39,0.07,2.87-0.36,3.15-1.52 c0.35-1.43-0.11-3.07-0.31-4.61c-0.05-0.35-0.43-0.86-0.75-0.94c-1.89-0.45-3.03-2.61-5.28-2.29c-0.29,0.05-0.76-0.44-0.98-0.79 c-0.55-0.87-1.04-1.78-1.46-2.72c-0.72-1.58-1.07-3.47-2.15-4.72c-1.03-1.21-1.01-2.65-1.64-3.91c-0.95-1.9,1.19-4.82,3.55-5.51 c1.64-0.47,2.56-1.92,3.11-3.23c0.56-1.3,1.48-2.16,2.47-2.65c1.95-1,3.13-2.23,2.85-4.48c-0.15-1.19,0.35-1.95,1.04-2.38 c1,0.29,1.75,0.57,2.54,0.71c0.68,0.12,1.65-0.21,2.05,0.15c1.42,1.25,3.06,0.73,4.59,0.79c1.64,0.07,2.82-1.17,2.72-2.83 c-0.14-2.32,0.71-4.76-1.17-6.9c-1.23-1.41-2.02-3.2-3.05-4.79c-0.22-0.34-0.72-0.52-0.87-0.87c-0.46-1.06-0.77-2.19-1.23-3.25 c-0.29-0.71-0.68-1.39-1.13-2.01c-1.1-1.56-2.04-3.14-1.53-5.37c1.49-0.04,2.78-0.09,3.89-1.32c1.1-1.21,1.2-2.49,1.25-3.92 c0.01-0.23,0.11-0.48,0.24-0.67c1.24-1.84,0.48-3.88,0.58-5.83c0.01-0.15-0.29-0.35-0.49-0.46c-1-0.56-2.03-1.05-3-1.64 c-0.5-0.3-0.84-0.89-1.35-1.13c-1-0.46-2.14-0.66-3.09-1.2c-0.51-0.28-0.94-1-1.07-1.59c-0.43-2.04-0.69-4.12-1.08-6.17 c-0.08-0.39-0.55-0.7-0.63-1.08c-0.19-0.93-0.56-2-0.26-2.78c0.2-0.56,1.73-1.24,2.07-1c1.34,0.91,2.76,0.55,4.13,0.75 c0.3,0.04,0.57,0.28,0.87,0.41c0.5,0.23,0.99,0.58,1.52,0.65c3.46,0.48,6.98-0.42,10.48,0.84c1.88,0.67,4.18,0.23,6.29,0.19 c0.47-0.01,1.28-0.37,1.34-0.69c0.2-1.06,0.29-2.2,0.09-3.25c-0.08-0.41-1.04-0.65-1.59-1c-0.18-0.12-0.3-0.34-0.49-0.47 c-1.59-1.12-3.47-1.86-4.58-3.59c-0.05-0.07-0.2-0.06-0.28-0.11c-0.71-0.43-1.45-0.81-2.11-1.31c-0.61-0.47-1.1-1.11-1.72-1.57 c-0.68-0.5-1.49-0.82-2.16-1.33c-0.65-0.49-1.14-1.21-1.81-1.67c-1.57-1.08-3.21-2.06-4.83-3.08c-0.55-0.35-1.1-0.73-1.69-1.01 c-0.82-0.38-1.8-0.53-2.49-1.06c-0.53-0.41-0.95-1.22-1.04-1.91c-0.29-2.18,0.44-4.47-0.96-6.53c-0.53-0.79-1.11-1.77-1.11-2.66 c-0.06-20.73-0.05-41.46-0.03-62.18c0-0.42,0.15-0.86,0.31-1.25c0.21-0.5,0.64-0.94,0.74-1.45c0.29-1.62,0.18-3.22,0.78-4.9 c0.83-2.34,0.88-4.99,1.09-7.52c0.17-1.95,0.05-3.92,0.11-5.88c0.01-0.47,0.2-0.93,0.37-1.38c0.2-0.51,0.68-0.99,0.69-1.49 c0.05-4.08,0.04-8.15,0.01-12.23c0-0.48-0.04-1.25-0.32-1.39c-0.99-0.49-0.7-1.33-0.78-2.08c-0.35-3.05-0.31-6.21-1.2-9.09 c-0.7-2.29-0.69-4.49-0.62-6.72c0.12-3.64-0.46-7.31,0.67-10.95c0.71-2.26,0.78-4.71,1.14-7.07c0.04-0.24,0.05-0.53,0.19-0.72 c1.27-1.67,1.08-3.79,1.66-5.67c0.44-1.39,0.1-3,0.26-4.5c0.1-0.93,0.2-2.16,0.8-2.68c1.42-1.23,1.05-2.71,1.11-4.18 c0.02-0.75,0.08-1.5,0.08-2.26c0-7.94,0-15.89-0.03-23.84c0-0.4-0.25-0.81-0.42-1.2c-0.21-0.5-0.6-0.97-0.64-1.48 c-0.1-1.3,0.06-2.63-0.09-3.92c-0.13-1.03-0.9-2.06-0.78-3.02c0.31-2.47-0.9-4.62-1.12-6.95c-0.02-0.22-0.23-0.41-0.33-0.63 c-0.25-0.52-0.62-1.03-0.7-1.58c-0.19-1.34,0.04-2.8-0.39-4.03c-0.8-2.24-1.62-4.42-1.62-6.84c0.01-17.65,0.01-35.31,0.01-52.97 c0-0.35,0.01-0.7,0-1.05c-0.02-1.05,0.41-1.5,1.54-1.48c2.96,0.07,5.93,0.14,8.89-0.02c1.36-0.08,2.79-0.5,3.99-1.12 c0.75-0.39,1.46-1.39,1.62-2.23c0.27-1.36,0.17-2.82,0.01-4.2c-0.06-0.53-0.66-1.12-1.16-1.45c-0.95-0.62-2-1.08-3.02-1.6 c-0.99-0.5-1.96-1.06-2.98-1.47c-1.78-0.73-3.61-1.35-5.4-2.06c-0.43-0.18-0.73-0.7-1.16-0.84c-2.24-0.68-2.37-0.81-2.37-3.03 c0.01-25.61,0-51.21,0.02-76.82c0-3.07,0.14-6.13,0.21-9.2c0.01-0.24,0.02-0.5,0.07-0.74c0.27-1.22,0.63-2.42,0.81-3.66 c0.37-2.55,0.64-5.13,0.97-7.69c0.02-0.18,0.12-0.4,0.26-0.51c1.25-1.01,1.6-2.31,1.7-3.89c0.22-3.29,0.67-6.56,1.04-9.84 c0.02-0.18,0.11-0.47,0.23-0.51c1.12-0.39,0.81-1.36,0.9-2.16c0.05-0.55-0.08-1.13,0.06-1.65c0.48-1.75,1.32-3.45,1.53-5.23 c0.29-2.37,0.65-4.96-0.01-7.16c-0.63-2.1-0.45-4.08-0.64-6.11c-0.06-0.75,0.14-1.67-0.22-2.22c-1.07-1.62-0.53-3.36-0.68-5.04 c-0.04-0.45,0-0.91,0-1.36c-0.04-11.77-0.07-23.54-0.12-35.32c0-0.74,0.31-1.64-0.76-2.05c-0.18-0.07-0.26-0.51-0.3-0.79 c-0.28-1.71-0.53-3.42-0.79-5.13c-0.02-0.14-0.04-0.34,0.04-0.43c0.85-1.09,1.42-2.52,3.18-2.48c0.48,0.01,1.01-0.1,1.45-0.3 c1.93-0.87,3.83-1.82,5.76-2.7c0.91-0.41,1.88-0.69,2.8-1.06c0.79-0.32,1.87-0.46,2.28-1.06c1.04-1.51,2.94-0.65,4.08-1.75 c0.2-0.2,0.94-0.09,1.27,0.13c1.02,0.68,1.91,1.57,2.95,2.21c0.97,0.6,2.05,1.01,3.11,1.45c0.77,0.32,1.57,0.54,2.6,0.88 c0.08-0.06,0.43-0.5,0.88-0.68c1.99-0.8,2.28-1.19,2.32-3.33c0.02-0.8-0.16-2.05,0.24-2.3c1.05-0.65,0.8-1.53,0.84-2.37 c0.1-1.85,0.1-3.71,0.2-5.57c0.02-0.46,0.14-1,0.42-1.35c1.19-1.48,2.43-2.92,3.72-4.33c1.85-2.02,3.76-3.98,5.62-5.99 c1.2-1.3,2.41-2.58,3.51-3.96c0.91-1.15,2.34-1.82,2.73-3.48c0.22-0.96,1.04-1.77,1.58-2.66c1.01-1.68,2.08-3.34,2.99-5.07 c0.86-1.63,1.53-3.36,2.33-5.01c0.12-0.24,0.55-0.48,0.82-0.47c0.85,0.06,1.7,0.23,2.56,0.36c1.64-0.37,3.34-0.64,5.04-0.61 c2.2,0.04,4.18-0.16,5.25-2.55c-0.42-0.66-0.75-1.53-1.37-2.07c-1.26-1.13-2.64-2.08-2.54-4.07c0.02-0.43-0.29-0.97-0.6-1.32 c-0.98-1.09-1.88-2.23-2.27-3.68c-0.25-0.92-0.45-1.85-0.7-2.92c0.1-0.16,0.47-0.49,0.53-0.87c0.41-2.81,0.64-5.66,1.19-8.44 c0.36-1.78,1.14-3.48,1.81-5.19c0.13-0.33,0.58-0.58,0.92-0.78c1.21-0.7,2.72-1.11,3.58-2.1c0.87-1,1.89-1.43,2.93-2.05 C215.346,112.2,216.377,111.28,216.086,109.69z M111.437,192.42c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31 c46.56,0,84.31,37.75,84.31,84.31C195.747,154.67,157.997,192.42,111.437,192.42z", - "M220.041,157.85c-0.55-1.59-1.99-2.91-3.19-4.22c-1.44-1.55-3.06-2.93-4.54-4.44 c-0.94-0.97-2.09-1.91-2.57-3.1c-0.71-1.75-2.03-2.69-3.39-3.77c-0.82-0.65-1.45-1.6-2.05-2.48c-0.5-0.74-0.65-1.96-1.31-2.31 c-1.12-0.62-0.92-1.41-0.84-2.26c0.08-0.9-0.07-2.1,0.44-2.6c0.78-0.78,0.7-1.59,0.82-2.45c0.08-0.56-0.1-1.25,0.16-1.69 c1.35-2.35-0.12-5.35,1.81-7.52c0.27-4.36,0.77-8.72,0.74-13.07c-0.02-4.6-0.55-9.19-0.86-13.78c-0.02-0.23-0.04-0.6-0.18-0.67 c-1.2-0.58-0.74-1.69-0.88-2.62c-0.3-2.03-0.62-4.06-0.94-6.09c-0.03-0.17-0.16-0.32-0.24-0.49c-0.24-0.54-0.6-1.06-0.69-1.62 c-0.13-0.75,0.01-1.54-0.06-2.3c-0.14-1.56,0.39-3.22-0.79-4.65c-0.22-0.28-0.2-1.14,0.05-1.36c1.19-1.08,1.96-2.58,3.68-3.18 c0.9-0.32,1.87-1.42,2.11-2.35c0.36-1.38,0.09-2.92,0.09-4.59c-1.73,0-3.3,0.02-4.87,0c-0.36-0.01-0.98-0.02-1.05-0.2 c-0.46-1.09-1.43-0.72-2.21-0.93c-0.6-0.16-1.47-0.3-1.69-0.73c-0.65-1.26-1.95-1.91-2.51-3.35c-0.54-1.39-1.94-2.48-3.06-3.6 c-1.57-1.58-3.29-3.01-4.82-4.63c-0.9-0.96-1.45-2.23-2.3-3.24c-1.37-1.63-3.13-2.84-3.93-5.04c-0.75-2.04-0.93-2.28,0.91-3.34 c1.13-0.65,2.46-1.26,3.14-2.27c0.61-0.91,1.38-1.33,2.18-1.58c1.22-0.36,1.87-1.27,2.04-2.22c0.26-1.52,0.07-3.12,0.07-4.65 c-0.7-0.18-1.53-0.16-1.73-0.5c-0.54-0.93-1.34-0.88-2.1-0.8c-2.26,0.22-4.43-0.1-6.81,0.91c-2.5,1.06-5.7,0.06-8.58,0.97 c-1.39,0.44-3.04,0.01-4.63-0.49c-1.72-0.54-3.23-1.39-4.81-2.12c-0.53-0.24-0.86-0.92-1.39-1.21c-1.65-0.91-3.34-1.75-5.03-2.58 c-1.13-0.55-2.27-1.12-3.46-1.5c-1.3-0.42-2.67-0.64-4.01-0.96c-0.12-0.03-0.2-0.18-0.32-0.25c-0.49-0.28-0.96-0.69-1.5-0.81 c-1.58-0.38-3.18-0.64-4.78-0.96c-0.14-0.02-0.31-0.04-0.39-0.13c-1.28-1.53-3.33-0.93-4.88-1.77c-0.54-0.3-1.16-0.25-1.76-0.8 c-0.74-0.69-1.95-0.86-2.95-1.27c-0.31-0.13-0.57-0.36-0.88-0.52c-1.82-0.91-2.44-3.41-4.85-3.63c-0.37-0.03-0.84-0.97-0.93-1.54 c-0.16-0.97-0.04-2-0.04-2.77c-1.29-1.4-2.71-1.66-4.31-1.5c-1.04,0.1-3.26,1.89-3.77,2.79c-0.68,1.21-0.49,3.06-2.5,3.4 c-0.54,0.1-1.02,0.85-1.41,1.39c-0.58,0.82-1.24,1.27-2.3,1.24c-2.01-0.06-4.03-0.04-6.04,0.02c-0.52,0.02-1.03,0.31-1.53,0.51 c-0.4,0.16-0.75,0.5-1.15,0.55c-3.09,0.4-6.2,0.74-9.3,1.11c-0.14,0.02-0.31,0.01-0.41,0.1c-1.74,1.46-4.05,1.26-6.01,1.52 c-2.02,0.27-3.57,1.32-5.4,1.82c-1.27,0.35-2.45,1.02-3.69,1.51c-2.06,0.82-4.13,1.61-6.2,2.4c-0.64,0.24-1.35,0.37-1.91,0.73 c-1.46,0.94-2.83,2.01-4.28,2.97c-1.07,0.72-2.2,1.37-3.31,2.04c-0.98,0.59-1.98,1.14-2.94,1.76c-0.49,0.32-0.89,0.79-1.38,1.11 c-0.56,0.35-1.41,0.47-1.71,0.95c-0.49,0.79-1.09,1.06-1.92,1.26c-0.56,0.14-1.09,0.61-1.52,1.04c-0.91,0.91-1.7,1.92-2.6,2.84 c-1.47,1.52-3.01,2.96-4.47,4.49c-1.04,1.1-1.94,2.34-2.99,3.42c-1.05,1.07-2.23,2.02-3.34,3.03c-0.16,0.15-0.42,0.34-0.42,0.49 c0.1,1.74-2.06,1.97-2.29,3.47c-1.95,0.29-1.67,2.42-2.79,3.49c-1.16,1.11-1.61,2.94-2.39,4.45c-0.36,0.68-0.62,1.51-1.17,1.98 c-0.96,0.81-1.45,1.74-1.52,2.96c-0.02,0.38-0.02,0.81-0.2,1.11c-0.84,1.45-1.74,2.87-2.62,4.29c-0.4,0.63-1.03,1.22-1.16,1.9 c-0.25,1.29-0.94,1.6-2.14,1.73c-2.53,0.27-5.17-0.85-7.62,0.97c-0.78,0.57-1.29,0.9-1.28,1.82c0.02,1.15,0.04,2.3,0.09,3.45 c0.01,0.28,0.02,0.64,0.18,0.82c0.91,1.01,1.87,1.99,2.82,2.97c0.3,0.31,0.66,0.56,0.92,0.89c0.54,0.7,0.91,1.58,1.57,2.11 c1.32,1.05,1.76,2.7,0.91,4.16c-0.19,0.32-0.31,0.7-0.37,1.07c-0.33,2.36-0.19,4.68-0.93,7.12c-1.04,3.39-0.76,7.19-0.99,10.82 c-0.084,1.3-0.028,2.609-0.004,3.91c0.006,0.347,0.042,0.913,0.113,1.253c0.215,1.031,0.607,2.038,0.712,3.077 c0.13,1.18,0.02,2.39,0.08,3.59c0.02,0.39,0.24,0.77,0.39,1.15c0.19,0.5,0.5,0.97,0.6,1.49c0.36,1.88,0.66,3.78,0.98,5.67 c0.02,0.14,0.04,0.36,0.12,0.39c1.31,0.58,0.79,1.78,0.95,2.74c0.08,0.47-0.04,1.09,0.21,1.4c1.07,1.27,0.76,2.98,1.64,4.41 c0.92,1.49,0.83,3.53,1.95,5.15c1.07,1.53,1.11,3.52,2.09,5.23c1.14,2,1.76,4.33,3.12,6.29c0.99,1.43,1.86,2.94,2.81,4.39 c0.43,0.64,1.05,1.17,1.38,1.86c0.32,0.66,0.52,1.46,0.46,2.17c-0.02,0.21-1.11,0.37-1.72,0.47c-0.89,0.14-2.03-0.1-2.64,0.37 c-1.27,0.99-2.58,1.6-4.16,1.75c-0.27,0.02-0.66,0.12-0.78,0.31c-0.74,1.2-2.18,0.94-3.19,1.62c-0.9,0.6-1.97,0.95-2.95,1.45 c-0.13,0.06-0.15,0.33-0.22,0.5c-0.29,0.61-0.57,1.22-0.88,1.88c0.22,0.14,0.66,0.26,0.73,0.49c0.44,1.56,1.62,1.71,2.95,1.69 c6-0.1,12,0.28,17.98-0.6c2.02-0.3,2.35-0.04,2.27,1.87c-0.01,0.33,0.33,0.65,0.42,1c0.28,1.08,0.93,2.18-0.3,3.18 c-0.72,0.59-1.28,1.39-1.97,2.04c-0.57,0.55-1.16,1.13-1.84,1.51c-1.53,0.85-3.29,1.33-4.37,2.87c-0.11,0.16-0.38,0.21-0.57,0.32 c-1.53,0.89-3.3,1.54-4.54,2.74c-1.67,1.63-4.03,1.83-5.72,3.3c-0.62,0.53-1.4,0.9-2.1,1.34c-0.35,0.22-0.68,0.57-1.05,0.64 c-1.67,0.33-2.61,1.81-2.12,3.47c0.38,1.29,2.05,1.63,3.29,1.08c1.5-0.67,2.83-2,4.72-1.6c0.23,0.05,0.48-0.03,0.71,0.01 c3.29,0.59,6.38-0.81,9.6-0.9c0.14,0,0.37-0.02,0.4-0.09c0.59-1.47,1.9-0.82,2.92-1.07c1.08-0.27,2.31-0.48,3.12-1.14 c1.34-1.1,3.01-1.42,4.43-1.52c2.07-0.14,3.55-1.64,5.54-1.71c0.53-0.02,1.04-0.3,1.55-0.46c0.45-0.14,0.92-0.22,1.33-0.43 c0.95-0.49,1.87-1.48,2.8-1.47c2.17,0.03,4.33,0.51,6.5,0.83c0.1,0.02,0.16,0.24,0.27,0.29c0.56,0.28,1.11,0.61,1.7,0.78 c1.28,0.37,2.98,0.25,3.8,1.06c1.41,1.37,3.24,0.88,4.73,1.73c0.92,0.53,2.42-0.25,3.25,1.05c0.11,0.17,0.55,0.21,0.82,0.18 c3.28-0.45,5.4,2.03,8.05,3.18c1.02,0.44,1.9,1.2,2.94,1.6c2.28,0.87,4.77,0.75,7.12,1.85c2.1,0.99,4.76,1.09,7.16,1.03 c6.72-0.19,13.49,0.95,20.17-0.71c1.13-0.28,2.39-0.08,3.58-0.17c0.39-0.02,0.78-0.21,1.15-0.37c0.47-0.21,0.91-0.6,1.39-0.67 c1.14-0.15,2.49,0.21,3.39-0.3c1.52-0.84,2.91-0.42,4.47-0.47c0.03,0.81,0.09,1.47,0.09,2.13v170.39c0,1.92,0.01,3.84-0.01,5.76 c0,0.42,0.03,1.13-0.17,1.22c-1.48,0.66-0.88,1.94-0.93,2.97c-0.1,1.67-0.15,3.36-0.02,5.03c0.14,1.95-0.76,4.1,1,5.79 c0.14,0.13,0.07,0.46,0.13,0.69c0.32,1.16,0.64,2.31,1,3.45c0.05,0.18,0.32,0.33,0.52,0.42c1.35,0.57,1.68,1.45,1.02,2.81 c-0.14,0.29-0.42,0.71-0.31,0.88c1.11,1.81,0.69,3.83,0.63,5.73c-0.1,2.98-0.59,5.94-0.76,8.93c-0.14,2.43-0.03,4.89-0.08,7.33 c-0.01,0.6,0.23,1.41-0.8,1.57c-0.12,0.02-0.28,0.37-0.29,0.57c-0.16,3.08-0.36,6.15-0.72,9.24c-0.59,4.97-0.21,10.05-0.21,15.09 c0,44.18,0.01,88.36,0,132.54c0,6.23-0.02,12.47-0.12,18.7c-0.03,1.37,0.13,2.67-0.79,4.12c-0.92,1.43-0.93,3.56-1.02,5.39 c-0.16,3.11-0.07,6.24-0.11,9.36c-0.01,0.51-0.02,1.4-0.24,1.47c-1.21,0.4-0.8,1.35-0.89,2.13c-0.08,0.62-0.03,1.28-0.26,1.84 c-1.03,2.54-0.86,5.31-0.25,7.71c0.44,1.74,0.41,3.39,0.61,5.08c0.09,0.71-0.17,1.75,0.22,2.08c1.12,0.97,0.85,2.16,0.86,3.3 c0.05,10.08,0.08,20.15,0.07,30.22c0,1.21,0.33,2.59-1.03,3.45c-0.18,0.11-0.18,0.53-0.24,0.8c-0.3,1.45-0.59,2.91-0.92,4.36 c-0.04,0.18-0.32,0.29-0.45,0.47c-0.23,0.34-0.53,0.68-0.61,1.06c-0.36,1.69-0.64,3.38-0.96,5.08c-0.02,0.13-0.03,0.36-0.11,0.39 c-1.37,0.57-0.82,1.77-0.87,2.73c-0.07,1.48,0.09,2.98-0.06,4.45c-0.07,0.64-0.56,1.58-1.07,1.74c-1.53,0.48-3.39-0.22-4.66,1.28 c-6.11,0.05-12.2-0.04-18.29,0.83c-3.57,0.51-7.27,0.09-10.91,0.11c-0.52,0-1.34-0.08-1.52,0.2c-0.88,1.4-2.2,0.79-3.34,0.85 c-1.68,0.09-3.36,0.01-5.03,0.03c-2.22,0.03-2.87,0.61-2.88,2.52c-0.01,1.74,1.56,3.66,3.06,3.67c2.44,0.02,4.89-0.03,7.33,0.03 c0.54,0.01,1.1,0.29,1.59,0.56c0.66,0.35,1.23,1.13,1.88,1.17c2.77,0.19,5.5,0.3,8.27,0.8c3.4,0.62,6.97,0.26,10.46,0.39 c1.31,0.04,2.77-0.51,3.81,0.86c0.13,0.16,0.55,0.11,0.83,0.16c1.98,0.31,3.97,0.57,5.93,0.94c1.09,0.21,2.13,0.61,3.19,0.93 c0.13,0.04,0.23,0.15,0.35,0.21c0.62,0.31,1.25,0.59,1.87,0.9c0.71,0.37,1.79,0.59,2.05,1.17c0.56,1.23,0.85,2.64,0.96,4.01 c0.19,2.53,0.15,5.07,0.25,7.61c0.01,0.38,0.22,0.77,0.39,1.12c0.21,0.43,0.67,0.83,0.68,1.24c0.06,2.54,0.03,5.08,0.03,8.02 c-1.66,0.18-3.24,0.45-4.82,0.5c-2.92,0.07-5.85,0-8.77,0.03c-0.79,0-1.59,0.13-2.49,0.22c0.04,1.62-0.73,3.04,0.83,4.49 c1.37,1.26,2.42,2.7,4.52,2.55c0.429-0.031,0.861,0.057,1.262,0.211c2.119,0.81,4.149,1.889,6.518,1.859 c2.647-0.022,3.007,0.673,2.932,3.776c-0.017,0.708,0.025,1.415,0.061,2.122c0.065,1.295-0.44,1.831-1.823,1.812 c-3.69-0.07-7.38-0.03-11.07,0c-0.56,0.01-1.42-0.02-1.62,0.29c-0.74,1.16-1.8,0.84-2.78,0.84c-2.78,0.02-5.56,0.01-8.34,0.01 c-2.64,0-5.27,0.06-7.9-0.01c-1.15-0.03-2.08,0.55-2.33,1.39c-0.7,2.4,0.27,5.56,3.59,5.63c1.2,0.02,2.77-0.38,3.51,0.22 c1.4,1.15,2.84,0.75,4.28,0.95c1.97,0.27,3.93,0.57,5.9,0.89c0.17,0.03,0.3,0.3,0.46,0.45c0.91,0.82,1.76,1.71,3.21,1.47 c0.49-0.09,1.07,0.16,1.57,0.35c0.51,0.19,0.95,0.66,1.45,0.73c3.2,0.43,6.4,0.78,9.69,1.16c0.04,0.17,0.13,0.39,0.14,0.62 c0.03,1.82,0.03,3.65,0.06,5.47c0.01,0.76-0.1,1.57,0.11,2.28c0.5,1.64,0.12,2.28-1.61,2.28c-4.12,0-8.24-0.01-12.36,0.02 c-0.7,0.01-1.77,0-2.02,0.4c-0.59,0.96-1.36,0.7-2.11,0.73c-1.81,0.07-3.64,0.04-5.44,0.19c-1.13,0.1-2.23,0.64-3.35,0.64 c-8.67,0.06-17.35,0.03-26.02,0.05c-0.66,0-1.71-0.04-1.89,0.3c-0.55,1.03-1.38,0.79-2.18,0.88c-1.31,0.17-2.07,1-2.12,2.29 c-0.1,2.71,1.38,4.42,4.05,4.64c0.66,0.06,1.34,0.06,2.01,0.06c11.59,0,23.19-0.04,34.79,0.04c2.11,0.01,4.23,0.53,6.34,0.84 c0.16,0.02,0.3,0.17,0.46,0.26c0.46,0.24,0.9,0.61,1.38,0.7c2.05,0.38,4.12,0.68,6.18,1.02c0.17,0.02,0.32,0.14,0.49,0.22 c0.59,0.27,1.16,0.71,1.77,0.77c1.78,0.18,2.26,0.55,2.18,2.39c-0.13,2.89,0.3,5.79-0.56,8.69c-0.54,1.82,0.44,4.02-1.28,5.61 c-1.07,0.99-1.03,2.72-2.45,3.52c-0.6,0.33-1.11,0.94-1.49,1.53c-0.84,1.31-1.52,2.72-2.37,4.02c-0.39,0.59-1.08,0.97-1.53,1.53 c-0.82,1.05-1.77,2.07-2.29,3.27c-0.73,1.7,0.72,3.6,2.56,3.61c1.2,0,2.39-0.07,3.59-0.14c0.28-0.01,0.76-0.06,0.79-0.18 c0.37-1.48,1.9-1.22,2.79-1.6c1.47-0.63,2.91-1.2,4.18-2.2c0.6-0.47,1.56-0.65,1.91-1.24c0.65-1.1,0.98-2.39,1.44-3.6 c0.17-0.43,0.37-0.84,0.5-1.28c0.4-1.41,0.82-2.81,1.14-4.24c0.15-0.69,0.22-1.46,0.08-2.14c-0.28-1.36,0.93-1.72,1.44-2.55 c0.84-1.38,1.53-1.33,2.36-0.08c0.04,0.06,0.18,0.09,0.27,0.09h5.12c-0.27-2.27,0.54-4.2-0.94-6.39c-1.18-1.72-2.35-3.95-2.25-6.37 c0.02-0.28-0.07-0.57-0.13-0.85c-0.31-1.36-0.62-2.72-0.98-4.33c4.5,0,8.43-0.01,12.35,0.02c0.27,0,0.59,0.24,0.78,0.46 c0.82,0.96,1.75,1.44,3.09,1.4c2.73-0.08,5.46,0.06,8.19,0.06c14.24,0.01,28.47,0,42.7,0c0.67,0,1.35,0.02,2.01-0.07 c0.32-0.05,0.75-0.28,0.88-0.55c0.69-1.38,1.24-2.78,1.07-4.42c-0.22-2-0.91-2.79-2.91-2.81c-2.59-0.03-5.17,0-7.76-0.03 c-0.4,0-0.82-0.09-1.21-0.22c-0.79-0.28-1.56-0.86-2.35-0.87c-4.08-0.1-8.15-0.05-12.22-0.06c-0.39,0-0.91,0.14-1.13-0.05 c-1.49-1.3-3.27-0.63-4.92-0.82c-1.42-0.16-3.03,0.59-4.17-0.93c-0.17-0.22-0.72-0.18-1.1-0.18c-1.29-0.03-2.58-0.02-3.86-0.03 c-0.63,0-1.49,0.23-1.83-0.09c-1.49-1.41-3.58-0.43-5.29-1.62c-1.47-1.03-3.79-0.13-5.71-1.05c-1.26-0.6-2.87,0.1-4.29-1.07 c-1.64-1.35-3.9-1.12-5.98-1.07c-1.17,0.02-1.96-0.78-2.01-1.96c-0.02-0.61,0-1.22,0-1.93c0.7-0.04,1.27-0.05,1.83-0.12 c0.31-0.04,0.62-0.16,0.9-0.3c0.48-0.24,0.93-0.73,1.42-0.78c3.66-0.32,7.33-0.56,10.99-0.82c0.05-0.01,0.1-0.01,0.15-0.01 c1.17-0.12,2.41-1.19,2.51-2.35c0.1-1.23,0.02-2.47,0.02-3.7c-1.73-0.36-3.3-0.9-4.9-0.98c-3.01-0.13-6.03,0-9.05,0.03 c-0.43,0-0.99-0.06-1.25,0.17c-1.07,0.95-2.32,0.59-3.51,0.66c-1.57,0.08-2.62-0.97-2.97-2.16c-0.34-1.18-0.19-2.67,0.24-3.85 c0.41-1.13,3.21-1.2,4.42-0.44c0.97,0.61,2.01,1.16,3.09,1.52c0.79,0.26,1.7,0.21,2.56,0.22c2.42,0.05,3.28-0.79,3.32-3.21 c0.02-1.15,0.11-2.31-0.02-3.45c-0.11-0.94-0.49-1.85-0.77-2.77c-0.35-1.1-0.72-2.18-1.14-3.45c0.69-0.05,0.96-0.09,1.24-0.09 c4.31-0.08,8.62-0.14,12.93-0.23c0.51-0.01,1.03-0.12,1.52-0.26c0.68-0.19,1.33-0.66,1.99-0.67c6.85-0.05,13.71-0.02,20.56-0.04 c0.71,0,1.61,0.13,2.1-0.23c1.18-0.87,2.44-0.56,3.67-0.62c1.29-0.05,2.6,0.05,3.87-0.13c0.76-0.11,1.42-0.83,2.18-0.93 c2.31-0.3,4.64,0.04,6.98-0.78c1.36-0.48,1.89-0.92,1.89-2.21c-0.01-1.05,0-2.09,0-3.07c-1.98-0.4-3.74-0.82-5.52-1.07 c-1.03-0.15-2.1-0.02-3.15-0.04c-0.33,0-0.87,0.04-0.95-0.13c-0.68-1.28-1.88-0.93-2.9-0.94c-4.36-0.05-8.72-0.02-13.08-0.03 c-0.42,0-0.84-0.06-1.25-0.16c-0.85-0.21-1.69-0.65-2.53-0.66c-3.74-0.08-7.48-0.04-11.22-0.07c-0.39,0-0.81-0.11-1.19-0.25 c-0.65-0.26-1.27-0.76-1.93-0.82c-1.661-0.151-3.335-0.019-5.007-0.073c-0.629-0.021-1.638-0.204-2.243-0.375 c-0.66-0.186-1.321-0.376-1.99-0.432c-1.57-0.13-3.16-0.02-4.74-0.05c-0.36,0-0.73-0.1-1.06-0.22c-0.75-0.28-1.46-0.83-2.21-0.87 c-2.29-0.12-4.62,0.13-6.89-0.13c-1-0.11-2.34-0.9-2.73-1.74c-0.4-0.87-0.13-2.37,0.4-3.27c0.641-1.095,1.837-1.878,2.791-2.802 c0.176-0.17,0.314-0.377,0.406-0.604c0.418-1.034,0.692-2.09,1.883-2.644c0.49-0.22,0.73-0.96,1.09-1.46 c0.58-0.8,1.01-1.83,1.79-2.34c1.34-0.86,2.7-1.8,4.39-2.05c0.94-0.14,2.19-0.41,2.65-1.07c0.83-1.21,2.16-0.98,3.16-1.63 c1.45-0.94,3.1-1.57,4.65-2.39c0.2-0.1,0.36-0.48,0.37-0.73c0.03-1.66,0.02-3.32,0.02-5.1c-1.93,0-3.73-0.2-5.46,0.05 c-1.77,0.26-3.54,0.82-5.19,1.53c-0.95,0.41-1.55,0.46-2.52,0.01c-1.67-0.76-3.21-2.09-5.31-1.62c-0.77,0.17-1.62,0.05-2.43,0.02 c-1.31-0.03-2.01-0.77-2.04-2.07c-0.03-1.1,0.24-2.39-0.24-3.26c-0.82-1.47-0.5-2.93-0.57-4.4c-0.07-1.35,0.57-1.94,1.93-1.96 c1.81-0.04,3.65,0.03,5.45-0.16c1.45-0.15,2.85-0.78,4.3-0.91c2.1-0.2,4.21-0.09,6.32-0.19c5.64-0.27,11.27-0.58,16.91-0.89 c0.29-0.01,0.59-0.18,0.87-0.31c0.46-0.22,0.9-0.66,1.36-0.68c2.87-0.12,5.74-0.18,8.61-0.21c1.86-0.01,3.49-0.46,4.72-1.98 c0.73-0.91,0.33-3.4-0.5-3.95c-1.54-1.02-3.21-0.87-4.89-0.91c-0.4-0.01-0.81-0.11-1.19-0.25c-0.76-0.27-1.48-0.83-2.23-0.85 c-3.214-0.102-6.428-0.038-9.642-0.061c-0.354-0.003-0.711-0.029-1.053-0.122c-0.859-0.234-1.683-0.63-2.544-0.697 c-1.48-0.12-2.97-0.01-4.46-0.04c-0.35,0-0.72-0.1-1.05-0.23c-0.7-0.28-1.36-0.79-2.07-0.87c-1.37-0.14-2.78,0.05-4.16-0.06 c-4.36-0.36-8.78,0.74-13.14-0.72c-1.01-0.34-1.88-0.84-2.7-1.35c-0.51-0.31-0.85-1.41-0.73-2.06c0.1-0.55,0.9-1.24,1.51-1.38 c1.69-0.39,3.52,0.23,5.11-1.2c0.68-0.6,1.73-0.79,2.03-1.87c0.46-1.59,0.03-3.2-1.02-4.15c-1.15-1.05-2.8-1.57-4.3-2.17 c-0.95-0.37-1.49-0.84-1.48-1.89c0.03-1.58,0.02-3.17-0.01-4.75c-0.01-0.57,0.08-1.42-0.24-1.65c-1.34-0.97-1.03-2.35-1.03-3.6 c-0.03-12.57-0.2-25.14,0.09-37.7c0.09-4.05-0.94-8.2,0.93-12.27c0.93-2.02,0.71-4.58,1.03-6.89c0.16-1.24-0.47-2.69,1-3.6 c0.14-0.09,0.09-0.54,0.09-0.83c0-4.12,0.01-8.25-0.02-12.37c0-0.41-0.16-0.82-0.29-1.22c-0.19-0.59-0.54-1.16-0.6-1.77 c-0.36-3.45-0.65-6.9-0.98-10.35c-0.03-0.31-0.24-0.6-0.38-0.89c-0.22-0.51-0.58-1-0.66-1.53c-0.24-1.69,0.47-3.51-0.81-5.07 c-0.19-0.23-0.19-0.89,0-1.1c1.13-1.21,0.66-2.69,0.81-4.07c0.03-0.33-0.01-0.85,0.17-0.94c1.18-0.61,0.78-1.71,0.9-2.64 c0.31-2.41,0.6-4.82,0.92-7.23c0.02-0.17,0.16-0.32,0.24-0.48c0.28-0.64,0.56-1.28,0.85-1.91c0.32-0.7,0.59-1.93,1-1.98 c1.63-0.19,2.43-1.42,3.43-2.35c1.11-1.02,1.99-2.29,3.34-3.88c1.88-0.27,4.43-0.62,6.97-0.99c0.244-0.035,0.634-0.127,0.864-0.214 c1.441-0.546,2.865-1.399,4.326-1.486c2.42-0.16,3.88-1.4,5.1-3.21c0.42-0.63,0.74-1.32,1.14-1.95c0.73-1.13,0.46-2.45-0.7-3.13 c-1.06-0.64-2.14-1.26-3.22-1.86c-0.79-0.43-1.66-0.72-2.39-1.23c-1.235-0.87-2.388-1.874-3.593-2.814 c-0.497-0.388-1.371-0.934-1.933-1.221c-0.971-0.497-1.952-0.974-2.934-1.465c-1-0.5-2.02-0.97-3.01-1.5 c-1.6-0.84-3.21-1.67-4.75-2.6c-0.37-0.23-0.71-0.84-0.72-1.29c-0.12-4.45-0.14-8.91-0.24-13.37c-0.01-0.63-0.24-1.27-0.47-1.87 c-0.4-1.04-1.01-2.01-1.27-3.07c-0.41-1.62-0.52-3.32-0.9-4.95c-0.19-0.8-1.03-1.52-1.04-2.28c-0.03-2.59-1.5-4.95-1.05-7.62 c0.23-1.35,0.07-2.78,0.01-4.17c-0.02-0.49-0.22-0.99-0.41-1.46c-0.18-0.47-0.63-0.91-0.64-1.37c-0.1-5.89-0.19-11.79-0.2-17.69 c-0.01-43.36-0.01-86.72,0.01-130.09c0-3.59,0.1-7.19,0.18-10.78c0-0.35,0.13-0.72,0.28-1.04c0.23-0.52,0.69-0.98,0.75-1.51 c0.14-1.13-0.01-2.31,0.15-3.44c0.21-1.41,0.24-3.06,1.01-4.12c1.23-1.69,0.93-3.66,1.6-5.44c0.86-2.26-0.54-4.93,1.14-7.29 c1.15-1.62,1.74-3.65,2.56-5.5c0.27-0.59,0.41-1.24,0.72-1.81c0.54-1.02,1.19-1.98,1.75-2.99c0.58-1.04,1.14-2.09,1.63-3.17 c0.67-1.52,2.22-1.88,3.43-2.66c0.92-0.59,2.03-0.89,3.04-1.36c1.51-0.69,3.02-1.38,4.5-2.12c0.5-0.26,1.18-0.59,1.33-1.04 c0.46-1.4,0.79-2.85,1.02-4.31c0.13-0.82-0.4-1.39-1.27-1.39c-3.26,0-6.51,0.03-9.77,0.06c-0.24,0-0.51,0-0.7,0.11 c-2.29,1.29-4.7,0.26-7.06,0.66c-0.05-0.53-0.1-0.81-0.1-1.1c0-8.53,0.13-17.08-0.04-25.61c-0.18-8.49,0.86-17.02-0.84-25.46 c-0.17-0.87-0.26-1.75-0.48-2.61c-0.13-0.53-0.56-0.99-0.63-1.51c-0.16-1.28,0.11-2.69-0.33-3.83c-0.93-2.37-0.35-3.87,2.08-4.61 c1.47-0.44,2.09-2.42,3.94-2.27c0.03,0,0.06-0.17,0.13-0.23c0.85-0.86,1.58-2.12,2.61-2.47c1.65-0.55,2.44-1.96,3.72-2.84 c0.98-0.67,1.86-1.5,2.82-2.2c0.62-0.46,1.31-0.81,1.96-1.23c0.66-0.42,1.31-0.86,1.95-1.31c0.27-0.2,0.49-0.46,0.76-0.67 c0.8-0.63,1.65-1.2,2.4-1.88c1.08-0.97,2.05-2.05,3.13-3.03c1.21-1.1,2.77-1.94,3.64-3.25c1.25-1.87,2.53-3.64,4.13-5.24 c1.47-1.47,2.88-3.08,3.97-4.84c0.72-1.18,2.37-1.65,2.4-3.29c0-0.06,0.14-0.14,0.22-0.16c1.32-0.35,2.61-0.84,3.95-1 c1.36-0.16,2.93-0.39,3.93,0.85c1.2,1.51,2.76,0.97,4.22,1.05c0.96,0.06,1.93,0.15,2.88,0.04c2.29-0.27,4.18,0.69,6.06,1.78 c0.68,0.4,1.4,0.75,2.09,1.13c0.92,0.51,1.83,1.03,2.85,1.6c0-0.01,0.07-0.17,0.19-0.27c0.97-0.86,2.45-1.54,2.79-2.6 C220.411,161.37,220.561,159.38,220.041,157.85z M111.437,192.42c-43.96,0-80.06-33.63-83.96-76.57c-0.27-0.72-0.3-1.53-0.18-2.4 c-0.12-1.77-0.18-3.55-0.18-5.35c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z", - "M230.071,128.64c-0.15-1.08-0.7-2.04-2.08-2.04c-0.28,0-0.57-0.25-0.84-0.39 c-0.47-0.25-0.92-0.61-1.42-0.73c-1.45-0.36-2.93-0.61-4.39-0.92c-0.12-0.03-0.22-0.18-0.34-0.23c-0.69-0.31-1.37-0.67-2.09-0.89 c-0.5-0.15-1.09,0.01-1.58-0.15c-1.59-0.49-3.12-1.21-4.73-1.56c-0.84-0.18-1.56-0.25-1.9-1.1c-0.26-0.64-0.44-1.3-0.58-1.71 c-0.72-0.61-1.66-1-1.81-1.59c-0.47-1.97-0.84-4-0.92-6.01c-0.17-4.38-0.13-8.76-0.19-13.14c0-0.39,0.08-0.98-0.12-1.13 c-1.52-1.11-0.88-2.72-1.05-4.13c-0.09-0.72-0.04-1.47-0.24-2.16c-0.52-1.81-1.24-3.58-1.68-5.41c-0.47-1.99-0.71-4.03-1.05-6.05 c-0.02-0.15-0.03-0.35-0.12-0.41c-1.51-0.98-1.28-2.82-1.53-4.12c-0.44-2.32-1.97-4.02-2.61-6.16c-0.4-1.34-1.17-2.57-1.71-3.87 c-0.68-1.62-1.18-3.32-1.99-4.86c-0.81-1.54-2.08-2.85-2.84-4.42c-0.66-1.35-0.85-2.94-2.05-4.04c-0.1-0.09-0.05-0.51,0.07-0.66 c0.56-0.66,1.05-1.5,1.78-1.88c1.3-0.68,1.3-1.76,1.31-2.91c0.01-1.17-0.04-2.34,0.01-3.51c0.07-1.48-0.62-2.06-2.07-2.04 c-3.26,0.04-6.52,0.06-9.78-0.01c-0.7-0.02-1.46-0.33-2.05-0.72c-1.1-0.72-2.12-1.56-3.13-2.4c-0.54-0.45-0.96-1.03-1.48-1.5 c-0.43-0.39-0.99-0.65-1.4-1.06c-1.1-1.08-2.85-1.27-3.64-2.8c-0.26-0.51-0.8-0.93-1.31-1.26c-1.904-1.241-3.992-2.242-5.711-3.712 c-0.881-0.754-1.89-1.335-2.86-1.97c-0.607-0.397-1.054-1.111-1.699-1.348c-2.2-0.8-3.28-2.91-5.09-4.15 c-1.33-0.92-1.84-2.72-3.74-3.11c-0.83-0.18-1.88-1.09-2.14-1.89c-0.88-2.71-2.14-5.37-1.84-8.36c0.05-0.48,0.01-0.96,0.01-1.34 c-1.25-1.09-2.38-0.97-3.36,0.1c-0.89,0.97-1.57,2.15-2.54,3.02c-1.43,1.29-2.97,2.51-4.61,3.52c-0.69,0.42-1.38,0.67-2.02,1.31 c-0.9,0.89-2.2,1.64-3.43,1.85c-1.8,0.3-3.69,0.07-5.53,0.05c-0.18,0-0.48-0.07-0.53-0.18c-0.47-1.14-1.47-0.93-2.36-0.94 c-6.56-0.01-13.14-0.04-19.7,0.04c-1.54,0.02-3.04-0.25-4.58,0.97c-1.14,0.9-3.14,0.73-4.76,1.02c-2.09,0.36-4.19,0.69-6.29,1.07 c-0.19,0.03-0.33,0.28-0.53,0.39c-0.37,0.22-0.74,0.54-1.14,0.59c-2.19,0.29-4.26,0.71-6.23,1.94c-1.53,0.96-3.44,1.68-5.22,1.77 c-1.75,0.09-2.67,1.41-4.14,1.82c-1.55,0.42-2.99,0.65-4.48-0.1c-0.81-0.405-1.626-0.816-2.452-1.201 c-0.68-0.317-1.835-0.735-2.558-0.934c-1.54-0.425-3.106-0.796-4.66-1.225c-0.36-0.1-0.75-0.28-1-0.54 c-1.13-1.22-3.97-1.95-5.53-1.35c-0.17,0.06-0.44,0.21-0.43,0.31c0.02,1.69-0.44,3.69,0.31,4.96c0.62,1.05,0.67,1.93,0.85,2.94 c0.3,1.71,0.65,3.4,0.99,5.1c0.03,0.13,0.11,0.31,0.22,0.36c1.21,0.52,0.68,1.35,0.48,2.21c-2.65,0-5.23,0-7.8-0.01 c-0.24,0-0.59,0.01-0.69-0.13c-1.25-1.66-3.02-0.97-4.53-0.83c-0.67,0.07-1.56,1.09-1.79,1.86c-0.3,0.97-0.07,2.11,0.02,3.18 c0.03,0.3,0.32,0.68,0.6,0.85c0.79,0.49,1.63,0.88,2.41,1.29c0,1.61-0.25,3.18,0.06,4.61c0.44,1.98-0.79,3.3-1.41,4.84 c-0.37,0.91-1.12,1.68-1.74,2.48c-0.65,0.86-1.47,1.62-1.97,2.56c-1.056,1.961-2.123,3.875-3.665,5.518 c-0.045,0.048-0.085,0.103-0.115,0.162c-0.62,1.2-1.26,2.38-1.81,3.61c-0.52,1.15-0.65,2.41-1.51,3.5c-0.8,1-1.09,2.41-1.63,3.63 c-0.4,0.91-0.89,1.79-1.23,2.73c-0.65,1.77-0.53,3.74-1.91,5.36c-0.96,1.12-1.31,2.75-2.03,4.1c-0.74,1.37-1.69,2.45-3.49,2.5 c-1.86,0.04-3.37,1.92-3.6,3.77c-0.44,3.62,2.49,5.16,4.33,7.38c0.29,0.36,0.73,0.77,0.74,1.17c0.06,1.95,0,3.9-0.04,5.84 c0,0.27-0.16,0.53-0.27,0.79c-0.22,0.58-0.62,1.14-0.66,1.73c-0.1,1.31-0.05,2.63-0.02,3.94c0,0.38,0.07,0.77,0.19,1.13 c0.27,0.77,0.78,1.51,0.84,2.29c0.15,1.79,0.08,3.6,0.11,5.4c0.01,0.78-0.28,1.79,0.1,2.29c1.42,1.91,0.12,4.44,1.72,6.36 c0.72,0.86,0.64,2.41,0.9,3.65c0.5,2.35,1.18,4.66,1.83,6.96c0.68,2.41,2.51,4.36,2.52,7.02c0,0.81,0.91,1.59,1.32,2.43 c0.52,1.07,0.95,2.19,1.43,3.28c0.11,0.24,0.28,0.45,0.41,0.68c0.56,1,1.12,1.99,1.67,2.99c0.32,0.59,0.48,1.5,0.98,1.75 c1.39,0.69,1.07,2.22,1.83,3.18c0.47,0.6,0.82,1.29,1.25,1.92c0.26,0.37,0.56,0.71,0.83,1.08c0.52,0.72,1.09,1.41,1.54,2.17 c0.52,0.89,1.47,2.02,1.24,2.71c-0.31,0.91-1.5,1.63-2.46,2.18c-1.59,0.9-3.29,1.6-4.94,2.38c-0.45,0.21-0.9,0.41-1.35,0.63 c-0.95,0.47-1.92,0.92-2.85,1.45c-0.71,0.42-1.35,0.98-2.05,1.42c-0.99,0.63-2.06,1.14-3,1.82c-0.81,0.58-1.46,1.39-2.27,1.98 c-0.53,0.4-1.41,0.43-1.81,0.9c-0.87,1.04-1.78,2-2.43,3.31c-0.93,1.85-0.62,3.28,0.36,4.67c0.71,1,1.81,1.7,3.22,1.44 c2.79-0.51,5.68,0.59,8.47-0.8c1.08-0.54,2.59-0.18,3.9-0.27c0.42-0.02,1.09-0.02,1.21-0.26c0.52-1.03,1.44-0.76,2.26-0.9 c1.76-0.28,3.52-0.6,5.28-0.92c0.13-0.02,0.33-0.1,0.37-0.21c0.43-1.07,1.39-0.83,2.22-0.9c0.63-0.06,1.27-0.03,1.88-0.15 c2.21-0.43,4.39-1,6.61-1.36c1.77-0.29,3.57-0.02,5.09,0.93c1.33,0.83,2.43,2.06,4.19,1.92c0.07,0,0.14,0.24,0.25,0.32 c0.96,0.71,1.94,1.41,3.11,2.26c-0.03,0.78,0.72,2.01-0.9,2.62c-0.11,0.05-0.12,0.35-0.21,0.52c-0.68,1.31-1.35,2.63-2.06,3.93 c-0.41,0.75-0.86,1.47-1.32,2.17c-0.52,0.79-1.16,1.5-1.6,2.33c-0.46,0.86-0.7,1.84-1.11,2.73c-0.56,1.22-1.46,2.35-1.74,3.63 c-0.31,1.34-0.12,2.81-0.03,4.22c0.08,1.17,0.87,1.95,2,2.03c1.38,0.09,2.83,0.58,4.1-0.64c0.75-0.73,1.82-1.11,2.66-1.76 c0.66-0.5,1.45-1.08,1.73-1.8c0.87-2.3,2.93-3.51,4.48-5.18c0.47-0.51,1.29-0.68,1.83-1.15c1.39-1.22,2.56-2.77,4.1-3.71 c1.46-0.88,3.26-1.31,4.97-1.65c1.24-0.24,2.38,0.18,3.64,0.89c2.31,1.31,5.28,0.57,7.75,2.06c1.12,0.68,2.84,0.67,4.2,0.82 c2.23,0.25,4.29,0.73,6.53,1.79c-0.24,0.43-0.46,0.94-0.77,1.4c-0.4,0.57-0.99,1.05-1.28,1.67c-0.79,1.67-1.35,3.39-1.07,5.31 c0.19,1.25,2.23,3.39,3.42,3.12c1.23-0.27,2.54-0.81,3.48-1.62c1.48-1.28,2.63-2.93,4.01-4.33c1.1-1.12,2.36-2.08,3.53-3.12 c0.71-0.64,1.3-1.64,2.12-1.89c1.76-0.52,3.64-0.61,5.45-0.97c1.79-0.35,3.55,0.17,5.46-0.91c1.89-1.06,4.51-0.98,6.82-1.09 c2.82-0.13,2.63-0.62,2.63,2.59c0,57.42,0.02,114.83-0.06,172.25c0,4.23,0.83,8.54-0.79,12.73c-0.62,1.6-0.25,3.38-1,5.17 c-0.81,1.94-0.89,4.43-1.01,6.62c-0.34,6.56-0.12,13.14-0.11,19.72c0,0.48-0.12,1.18,0.15,1.41c1.43,1.27-0.05,3.62,1.8,4.67 c0.34,3.04,0.98,6.08,0.99,9.12c0.06,52.79,0.04,105.58,0.04,158.37c0,3.16,0,6.33-0.03,9.49c0,0.57-0.12,1.14-0.26,1.69 c-0.19,0.72-0.64,1.41-0.66,2.11c-0.11,3.56-0.11,7.11-0.16,10.67c-0.01,0.42-0.1,0.85-0.21,1.27c-0.2,0.8-0.52,1.58-0.66,2.4 c-0.17,0.95-0.16,1.93-0.31,2.89c-0.16,1.01-0.64,2.01-0.6,2.99c0.16,3.93,0.47,7.84,0.73,11.76c0.01,0.09,0.01,0.19,0.03,0.29 c0.02,0.09,0.03,0.25,0.09,0.26c1.53,0.52,1.01,1.83,1.01,2.84c0.04,8.82,0.12,17.63-0.03,26.45c-0.05,2.65,0.87,5.42-0.97,8.02 c-0.8,1.12-0.72,2.87-1.05,4.32c-0.05,0.23-0.17,0.43-0.26,0.64c-0.55,1.3-1.35,2.55-1.59,3.9c-0.47,2.59-1.33,5.12-1.07,7.86 c0.22,2.37-0.05,4.78,0.08,7.16c0.1,1.83,0.58,3.64,0.72,5.47c0.11,1.56-0.68,2.28-2.23,2.29c-2.87,0.02-5.74-0.01-8.61,0.03 c-0.6,0.01-1.54,0.04-1.74,0.4c-0.54,0.93-1.29,0.71-2.03,0.74c-1.89,0.09-3.92-0.26-5.63,0.33c-1.64,0.56-3.18,0.44-4.77,0.55 c-0.77,0.05-1.56,0-2.33,0.04c-0.39,0.03-0.99,0.03-1.1,0.25c-0.72,1.33-1.93,0.77-2.95,0.89c-0.68,0.07-1.56-0.12-1.99,0.24 c-1.51,1.3-3.91-0.13-5.14,1.79c-2.12-0.02-4.15,0.22-6.23,0.82c-1.96,0.56-2.12,0.32-2.18,2.44c-0.01,0.34-0.01,0.69,0,1.03 c0.06,1.68,2.24,2.98,3.84,2.46c2.01-0.65,4.08-1.5,6.15-1.56c7.1-0.21,14.21-0.12,21.31-0.12c0.47-0.01,0.99,0.07,1.4,0.28 c1.67,0.85,3.32,1.62,5.27,1.47c0.64-0.05,1.32,0.15,1.95,0.35c0.64,0.19,1.22,0.71,1.84,0.75c3.19,0.16,3.22,0.16,3.33,3.45 c0.02,0.47,0.05,1.22,0.31,1.34c2.07,0.98,1.89,2.8,1.64,4.51c-0.1,0.64-0.81,1.33-1.41,1.69c-0.29,0.17-1-0.36-1.53-0.56 c-0.43-0.16-0.87-0.4-1.32-0.42c-1.21-0.07-2.43-0.01-3.65-0.06c-0.4-0.01-0.97-0.03-1.18-0.29c-1.01-1.21-2.46-2.07-2.96-3.72 c-0.12-0.39-0.73-0.77-1.18-0.88c-0.64-0.15-1.36,0-2.03-0.08c-3.01-0.39-4.31,2.14-4.4,4.43c-0.18,4.77-0.13,9.54-0.14,14.31 c-0.01,2.82,2.03,4.69,4.86,4.52c0.33-0.03,0.71,0,1-0.14c0.39-0.2,0.79-0.49,1.05-0.84c0.57-0.81,0.87-2.08,1.62-2.43 c1.73-0.79,3.65-1.22,5.52-1.65c1.12-0.26,2.33-0.11,3.44-0.37c0.5-0.12,0.83-1.12,1.47-0.21c0.36,0.51,0.86,1.02,0.95,1.59 c0.16,0.95,0.03,1.94,0.06,2.91c0.02,0.73-0.3,1.6,0.72,2.02c0.1,0.04,0.07,0.87-0.06,0.92c-0.9,0.37-1.84,0.86-2.77,0.87 c-4.38,0.09-8.76-0.08-13.14,0.08c-4.25,0.15-8.48,0.6-12.73,0.93c-0.14,0.01-0.29,0.04-0.42,0.1c-0.18,0.06-0.46,0.13-0.49,0.24 c-0.27,1.05-1.1,0.74-1.78,0.78c-1.26,0.07-2.71-0.25-3.73,0.27c-1.56,0.79-3.07,0.49-4.61,0.6c-0.83,0.06-1.66-0.02-2.48,0.05 c-0.46,0.04-0.92,0.23-1.36,0.4c-0.57,0.22-1.11,0.68-1.66,0.69c-5.74,0.12-11.48,0.25-17.22,0.19c-2.94-0.03-5.8,0.32-8.66,0.89 c-1.92,0.38-3.87,0.56-5.81,0.84c-0.14,0.02-0.37,0.03-0.41,0.11c-0.64,1.38-1.89,0.79-2.91,0.91c-0.67,0.07-1.58-0.17-1.99,0.19 c-1.16,1-2.45,0.58-3.69,0.69c-0.83,0.07-1.68,0-2.47,0.2c-0.46,0.12-0.79,0.86-1.24,0.91c-2.91,0.37-5.84,0.62-8.76,0.91 c-0.15,0.01-0.35-0.02-0.43,0.06c-0.65,0.68-1.53,1.29-1.85,2.11c-0.31,0.78,0.21,1.51,0.84,2.36c1.3,1.76,2.87,2,4.54,1.69 c2.76-0.49,5.54,0.64,8.38-0.92c1.96-1.08,4.67-0.8,7.06-1.06c1.06-0.12,2.14-0.03,3.21-0.09c0.36-0.02,0.71-0.16,1.05-0.3 c0.57-0.23,1.13-0.71,1.7-0.71c7.2-0.09,14.42,0.25,21.57-0.98c0.95-0.16,1.86-0.79,2.8-0.8c8.27-0.06,16.54-0.03,24.81-0.02 c0.44,0,1.03-0.11,1.28,0.12c1.16,1.09,2.55,0.69,3.86,0.72c2.62,0.06,5.26-0.04,7.88,0.09c3.92,0.2,7.83,0.57,11.75,0.79 c0.98,0.06,1.1,0.61,1.1,1.33c0.03,2.39,0.05,4.78,0.05,7.16c-0.01,2.02-1.87,3.14-3.77,2.39c-0.95-0.37-1.99-0.7-2.98-0.7 c-10.76-0.06-21.51-0.02-32.27-0.07c-1.58-0.01-3.37,0.66-4.65-0.97c-0.08-0.09-0.27-0.11-0.41-0.13 c-2.93-0.32-5.86-0.62-8.79-0.95c-0.4-0.04-0.8-0.18-1.18-0.33c-0.57-0.24-1.13-0.77-1.69-0.77c-7.35-0.03-14.69,0-22.04,0.04 c-0.95,0-2.27,1.35-2.31,2.29c-0.03,0.86-0.1,1.62,1.01,2.08c0.65,0.27,0.96,1.53,1.59,1.68c1.92,0.48,3.91,0.63,5.87,0.93 c1.04,0.15,2.37-0.55,2.94,1.01c0.04,0.1,0.36,0.11,0.55,0.12c3.51,0.33,7.01,0.67,10.52,0.95c1.16,0.1,2.34,0.02,3.5,0.08 c0.4,0.02,0.79,0.25,1.19,0.39c0.5,0.18,1.01,0.52,1.52,0.53c2.43,0.06,4.86,0.01,7.3,0.06c0.65,0.01,1.3,0.23,1.94,0.4 c0.48,0.13,0.93,0.46,1.4,0.46c7.84,0.09,15.67,0.05,23.5,0.23c5.81,0.13,11.61,0.48,17.4,0.86c0.64,0.05,1.54,0.85,1.76,1.49 c0.49,1.43,1.55,2.76,1.15,4.45c-0.06,0.27,0.33,0.63,0.48,0.97c0.55,1.25,1.09,2.51,1.63,3.77c-0.137,0.184-0.17,0.23-0.307,0.414 c-0.944-0.093-1.899-0.132-2.823-0.294c-0.59-0.1-1.13-0.53-1.7-0.54c-6.96-0.1-13.91-0.14-20.87-0.22 c-1.08-0.01-2.29,0.4-3.09-0.88c-0.16-0.27-0.9-0.25-1.38-0.26c-1.6-0.03-3.21-0.01-4.82-0.01c-0.33-0.01-0.83,0.09-0.99-0.09 c-0.91-1.09-2.14-0.72-3.26-0.77c-1.26-0.05-2.53,0.01-3.79-0.02c-0.36-0.01-0.72-0.14-1.05-0.29c-0.58-0.25-1.11-0.75-1.7-0.82 c-2.88-0.32-5.74-0.13-8.66-0.74c-3.27-0.68-6.78-0.21-10.19-0.18c-0.48,0-1.14,0.2-1.4,0.55c-0.9,1.21,0.09,4.17,1.51,4.44 c2.01,0.39,4.05,0.6,6.08,0.87c0.72,0.1,1.84-0.1,2.09,0.29c0.78,1.21,1.85,0.74,2.83,0.84c0.92,0.1,2.04-0.16,2.7,0.29 c1.05,0.71,2.08,0.6,3.16,0.65c1.06,0.05,2.18-0.07,3.19,0.21c1.63,0.45,3.16,1.3,4.8,1.72c1.71,0.45,3.48,0.08,5.27,1.06 c1.43,0.78,3.44,0.32,5.23,0.91c2.13,0.71,4.5-0.02,6.83,0.88c2.46,0.95,5.22,0.01,8.01,1.07c3.13,1.19,6.86,0.81,10.33,1.12 c0.57,0.05,1.18,0.03,1.68,0.26c0.64,0.3,1.17,0.82,1.75,1.24c0.15-0.02,0.31-0.05,0.46-0.08c-0.1,1.18,0.17,2.59-0.39,3.5 c-0.86,1.38-2.53,1.97-4.19,2.02c-3.25,0.08-6.51,0.02-9.76,0.07c-1.86,0.03-2.68,0.94-2.66,2.81c0.01,0.93,1.47,3.14,2.4,3.36 c1.65,0.4,3.33,0.82,5.01,0.9c3.06,0.14,6.13,0.03,9.19,0.05c1.58,0,2.3,0.73,2.31,2.34c0.02,3.12,0.22,6.25-0.07,9.34 c-0.2,2.13,1.22,2.97,2.27,4.19c0.09,0.1,0.56,0.01,0.73-0.14c0.99-0.82,1.37-1.83,1.28-3.18c-0.06-1.03,0.45-2.08,0.6-3.13 c0.26-1.95-0.25-4.06,1.26-5.73c0.28-5.74,0.56-11.48,0.85-17.22c0.04-0.83,0.14-1.66,0.12-2.48c-0.08-3.46,0.65-6.86,0.83-10.28 c0.13-2.46-0.51-4.96-0.75-7.44c-0.12-1.26,0.28-2.76-0.28-3.74c-0.87-1.54-0.47-3.05-0.63-4.58c-0.05-0.53,0.01-1.07-0.06-1.6 c-0.05-0.37-0.12-0.96-0.36-1.06c-0.97-0.44-0.73-1.24-0.75-1.98c-0.04-1.8,0.39-3.78-0.24-5.34c-0.66-1.64-0.54-3.17-0.62-4.76 c-0.07-1.22-0.02-2.44-0.04-3.65c-0.01-0.44,0.04-1.1-0.2-1.26c-1.41-0.94-0.74-2.36-0.95-3.57c-0.24-1.44-0.63-2.87-0.69-4.32 c-0.07-1.59-0.67-3.32,0.58-4.74c0.21-0.24,0.92-0.42,1-0.32c0.42,0.54,0.88,1.15,1.01,1.8c0.31,1.52-0.14,3.06,1.03,4.58 c1.02,1.3,1.22,3.22,1.85,4.85c0.34,0.86,0.86,1.64,1.25,2.49c0.27,0.58,0.43,1.22,0.69,1.82c0.46,1.07,0.96,2.13,1.45,3.19 c0.52,1.12,1.04,2.24,1.56,3.35c0.41,0.87,1.05,1.69,1.2,2.59c0.41,2.58,0.73,5.18,0.87,7.78c0.17,3.21,0.12,6.43,0.19,9.64 c0.01,0.43-0.01,1.08,0.24,1.23c1.04,0.66,0.84,1.66,0.91,2.6c0.27,3.54-0.37,7.08,0.66,10.64c0.5,1.72,1.74,2.57,2.66,3.79 c0.16,0.21,0.75,0.19,1.12,0.12c0.62-0.12,2.42-2.53,2.46-3.18c0.51-8.75-0.35-17.53,0.71-26.29c0.41-3.38-0.31-6.91-0.58-10.36 c-0.09-1.15,0.49-2.57-1.1-3.24c-0.11-0.04-0.11-0.35-0.13-0.54c-0.3-2.81-0.59-5.62-0.9-8.42c-0.05-0.47-0.11-1.21-0.38-1.33 c-1.02-0.43-0.73-1.26-0.78-1.97c-0.08-1.11,0.3-2.53-0.25-3.27c-0.83-1.1-0.52-2.02-0.49-3.05c1.99-0.43,3.75-1.81,5.74-0.95 c0.39,2.88,0.85,5.69,1.14,8.52c0.23,2.29,1.01,4.26,2.89,5.63c0.45,0.33,1.22,0.47,1.77,0.35c0.76-0.15,1.45-0.63,2.3-1.03 c0-2.53-0.02-5.15,0.02-7.78c0.01-0.86-0.14-1.96,0.31-2.53c0.91-1.16,0.53-1.98-0.12-2.77c0.48-1.75,1.76-1.6,3.07-1.64 c6.71-0.25,13.42-0.57,20.13-0.87c0.19,0,0.39-0.03,0.58-0.06c2.915-0.587,5.795-1.362,8.816-1.146 c1.388,0.099,2.779,0.185,4.166,0.067c1.583-0.135,3.2,0.101,4.658-0.921c0.97-0.68,1.69-1.88,1.18-3.28 c-0.25-0.68-1.16-1.55-1.81-1.58c-5.95-0.3-11.92-0.12-17.83-1.11c-0.37-0.06-0.98-0.04-1.06-0.23c-0.47-1.12-1.42-0.85-2.25-0.88 c-1.79-0.07-3.78,0.4-5.34-0.22c-1.54-0.62-2.97-0.51-4.46-0.69c-4.45-0.53-9.09,1.2-13.37-1.14c-0.57-0.31-1.22-0.55-1.66-0.99 c-1.16-1.18-2.18-2.5-3.35-3.68c-1.89-1.9-3.88-3.71-5.77-5.62c-1.11-1.1-1.9-2.74-3.21-3.36c-1.71-0.81-2.94-1.96-4.27-3.2 c-1.45-1.36-3.25-2.35-5.13-3.67v-1.37c2.39,0.23,4.78-0.38,6.81,1.6c0.74,0.73,2.1,1.17,3.17,1.15c2.07-0.06,2.81-1.1,2.83-3.22 c0.012-1.029,0.105-2.072-0.135-3.065c-0.126-0.522-0.594-1.242-0.983-1.612c-0.994-0.944-2.204-1.718-2.982-2.803 c-1.18-1.62-2.71-2.7-4.3-3.8c-0.66-0.45-1.27-1.04-1.77-1.68c-0.62-0.77-1.01-1.75-1.67-2.48c-0.7-0.79-1.07-1.55-1.07-2.66 c0.04-25.52,0.02-51.03,0.09-76.55c0.01-2.45,0.54-4.89,0.86-7.33c0.02-0.2,0.28-0.36,0.38-0.56c0.51-1.02,1.37-2.03,1.42-3.07 c0.2-4.67,0.37-9.36,0.15-14.02c-0.23-4.6,0.89-9.24-0.91-13.86c-0.97-2.5-0.76-5.45-1.08-8.2c-0.06-0.53-0.12-1.06-0.22-1.59 c-0.17-0.92-0.53-1.84-0.54-2.75c0-1.6-0.1-3.16,0.52-4.8c0.54-1.42,0.41-3.2,0.21-4.77c-0.37-2.8,0.82-5.35,0.97-8.05 c0.01-0.14,0.05-0.36,0.14-0.4c1.26-0.61,0.84-1.8,0.99-2.79c0.06-0.43-0.11-1.04,0.12-1.27c1.46-1.45,0.73-3.5,1.61-5.25 c1.1-2.2-0.12-5.19,1.07-7.68c0.04-9.5,0.1-18.99,0.12-28.49c0-1.74,0.34-3.72-0.35-5.18c-0.85-1.83-0.55-3.56-0.74-5.33 c-0.04-0.36-0.16-0.73-0.31-1.07c-0.25-0.56-0.68-1.08-0.79-1.67c-0.37-2.01-0.64-4.05-0.95-6.07 c-0.018-0.064-0.035-0.126-0.053-0.19c-0.547-1.29-1.442-2.513-1.707-3.87c-0.47-2.46-0.88-4.98-0.88-7.47 c-0.04-51.72-0.02-103.44-0.05-155.15c0-2.24,0.68-3.89,2.54-5.13c0.81-0.53,1.5-1.26,2.19-1.96c1.11-1.12,2.13-2.32,3.27-3.39 c0.39-0.36,1.19-0.28,1.57-0.64c1.32-1.26,2.51-2.66,3.81-3.95c1.03-1.02,2.18-1.94,3.2-2.97c1.34-1.36,2.58-2.82,3.92-4.18 c1.21-1.22,2.62-2.26,3.72-3.58c1.17-1.4,2.28-2.77,4.14-3.27c0.14-0.04,0.24-0.28,0.35-0.43c1.26-1.87,1.11-3.98,0.97-6.07 c-0.02-0.38-0.44-0.97-0.78-1.06c-2.42-0.64-4.68,0.12-6.93,0.92c-0.29,1.52-1.89,1.12-2.8,1.7c-1.15,0.74-2.85,0.01-4.3,1.16 c-0.88,0.7-2.61,0.58-3.96,0.92c-1.74,0.44-3.32,1.03-4.92,2.07c-0.1-0.55-0.25-1.01-0.25-1.47c0-2.48-0.03-4.97,0.07-7.45 c0.23-5.62,0.14-11.24,0.73-16.88c0.56-5.39-0.01-10.89-0.04-16.34c-0.03-6.04,0.03-12.08-0.03-18.12 c-0.03-2.15,0.05-4.26-0.48-6.46c-0.76-3.17-0.78-6.51-1.2-9.77c-0.11-0.84-0.54-1.64-0.8-2.46c-0.06-0.22-0.15-0.54-0.04-0.67 c0.72-0.89,1.46-1.75,2.24-2.59c1.82-1.97,3.8-3.81,5.45-5.92c1.33-1.69,2.58-3.28,4.76-3.9c0.76-0.21,1.55-0.62,2.13-1.15 c1.19-1.11,2.12-2.36,3.81-3.06c1.74-0.72,3.12-2.32,4.64-3.56c0.41-0.33,0.73-0.78,1.16-1.07c2.04-1.42,4.11-2.79,6.15-4.21 c0.29-0.2,0.44-0.61,0.73-0.8c1.46-0.91,3.01-1.69,4.41-2.68c1.16-0.81,2.17-1.83,3.2-2.8c0.46-0.44,0.86-0.97,1.18-1.51 c0.4-0.68,0.54-1.55,1.06-2.09c1.159-1.21,1.822-2.544,1.82-4.222c0-0.258,0.046-0.516,0.159-0.747c0.97-1.97,2.06-3.9,2.95-5.92 c1.15-2.6,2.08-5.3,3.24-7.89c1.04-2.33,2.44-4.52,3.34-6.89c0.61-1.59,1.59-2.02,3.03-2.03c3.99-0.03,7.99-0.22,11.96,0.02 c2.25,0.14,3.79-1.49,5.85-1.66c0.717-0.051,1.424-0.522,2.077-0.886c0.846-0.472,1.672-0.976,2.476-1.516 c0.646-0.434,1.381-0.838,1.917-1.398C230.441,131.98,230.311,130.27,230.071,128.64z M111.437,192.42 c-46.57,0-84.32-37.75-84.32-84.32c0-46.56,37.75-84.31,84.32-84.31c46.56,0,84.31,37.75,84.31,84.31 C195.747,154.67,157.997,192.42,111.437,192.42z" - ], - clocks: { - size: 169, - 0: { x: 111.011, y: 108.5 } - } - }, - 2: { - height: 625.438, - width: 197.009, - path: "M193.86,271.21c-2.234-2.626-5.64-4.792-8.929-5.835c-6.793-2.153-11.841,2.196-17.463,7.369 c-5.009-25.727-17.583-43.987-38.477-54.246l-18.909-21.56v-12l20.773-23.686c19.55-10.446,31.402-28.304,36.229-53.096 c5.622,5.174,10.67,9.523,17.463,7.369c3.289-1.043,6.695-3.208,8.929-5.835c4.877-5.734,3.879-14.302-1.542-19.605 c-6.442-6.301-13.569-5.549-24.852,3.382c-4.816-25.231-17.183-43.587-38.409-54.031h0.158c-1.506-0.732-3.056-1.394-4.625-2.025 c-2.997-1.25-6.144-2.365-9.463-3.327c0,0-0.527-0.089-1.457-0.217c-2.421-0.731-4.757-2.02-7.743-3.273 c2.103-2.282,3.255-3.455,4.321-4.703c5.176-6.057,4.821-14.978-0.792-20.538c-5.647-5.594-14.543-5.829-20.352-0.539 c-6.101,5.556-6.808,14.49-1.648,20.831c4.153,5.103,3.905,5.403-2.49,8.055c-1.793,0.744-3.604,1.465-5.417,2.187 c-10.281,3.032-16.092,6.929-22.875,12.001c-12.415,9.284-19.739,22.385-23.521,37.515c-0.673,2.693-2.08,5.2-3.437,8.492 c-2.262-2.122-3.424-3.284-4.661-4.36c-6.003-5.222-14.845-4.864-20.356,0.799c-5.544,5.698-5.778,14.673-0.534,20.534 c5.507,6.156,14.361,6.869,20.646,1.662c5.058-4.19,5.355-3.94,7.984,2.512c3.394,8.33,6.292,17.054,10.972,24.62 c6.032,9.752,14.303,16.873,24.096,21.915l21.601,23.357v12l-20.223,21.867c-10.232,5.068-18.855,12.348-25.091,22.43 c-4.68,7.566-7.578,16.29-10.972,24.62c-2.629,6.452-2.926,6.702-7.984,2.512c-6.285-5.206-15.139-4.493-20.646,1.662 c-5.243,5.861-5.01,14.837,0.534,20.534c5.511,5.663,14.352,6.021,20.356,0.799c1.237-1.076,2.399-2.238,4.661-4.36 c1.356,3.292,2.764,5.799,3.437,8.492c3.782,15.13,11.106,28.232,23.521,37.515c7.877,5.89,14.425,10.198,28.206,13.404 c1.38,0.321,2.787,0.579,4.201,0.789c0.031,27.796,0.06,69.604,0.085,105.236c0.009,13.829,0.018,26.73,0.026,37.518 c0,0.826-0.08,1.652-0.121,2.436c-3.447,0.597-4.58-0.495-4.682-4.511c-0.072-2.822-0.002-5.649-0.016-8.473 c-0.024-4.802-0.891-5.97-4.609-5.976c-14.432-0.022-28.864-0.01-43.295-0.009c-4.627,0-9.255,0.084-13.881-0.022 c-3.054-0.07-4.428,1.698-4.326,5.623c0.079,3.039,0.085,6.08-0.001,9.119c-0.111,3.933,1.27,5.674,4.317,5.646 c8.372-0.076,16.745-0.038,25.118-0.024c4.14,0.007,4.933,1.055,4.947,6.397c0.024,9.702,0.024,9.702-7.67,9.702 c-7.381-0.001-14.762-0.025-22.143,0.006c-3.558,0.015-4.54,1.209-4.551,5.611c-0.035,13.947-0.943,13.109,10.004,13.035 c6.61-0.045,13.22-0.032,19.83,0.002c3.528,0.018,4.463,1.226,4.534,5.638c0.17,10.455,0.17,10.455-8.056,10.455 c-7.271,0-14.542-0.024-21.813,0.01c-3.492,0.016-4.48,1.263-4.503,5.672c-0.067,12.642-0.701,12.243,9.397,12.129 c6.83-0.077,13.661-0.04,20.491-0.004c3.466,0.018,4.419,1.281,4.484,5.702c0.154,10.39,0.154,10.39-8.106,10.39 c-7.271,0-14.542-0.026-21.813,0.01c-3.447,0.017-4.439,1.296-4.452,5.736c-0.039,13.671-0.908,12.955,9.772,12.916 c17.076-0.063,34.152-0.012,51.227-0.02c4.329-0.002,5.098-1.02,5.1-6.63c0.001-1.977-0.037-3.956,0.007-5.931 c0.094-4.282,1.178-5.371,4.197-4.937c1.031,10.07,1.909,19.99,3.129,29.842c0.425,3.429,1.312,6.98,2.695,9.93 c1.2,2.56,3.388,5.993,5.16,6.013c1.744,0.02,4.469-3.383,5.098-5.954c2.029-8.292,4.037-16.802,4.667-25.395 c0.85-11.612,0.501-23.379,0.517-35.079c0.042-30.977,0.078-68.798,0.115-106.572c0.037-37.246,0.075-74.445,0.121-104.988 c3.105-0.304,5.045-0.635,5.045-0.635c29.872-8.658,46.55-29.062,52.338-59.383c11.283,8.931,18.409,9.683,24.852,3.382 C197.739,285.512,198.737,276.945,193.86,271.21z M44.186,100.381c0-29.823,24.177-54,54-54s54,24.177,54,54 c0,29.823-24.177,54-54,54S44.186,130.205,44.186,100.381z M98.186,334.381c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 s54,24.177,54,54C152.186,310.205,128.009,334.381,98.186,334.381z", - clocks: { - size: 108, - 0: { x: 98.579, y: 280 }, - 1: { x: 98.579, y: 100 } - } - }, - 3: { - height: 915.936, - width: 277.634, - path: "M263.752,257.836c-13.719,1.508,3.345-15.515,3.955-23.109l-0.113,0.113 c8.127-22.574,2.75-46.079-10.802-65.608c14.365-1.735,19.981-6.287,20.122-15.339c0.118-7.617-5.228-14.388-12.762-14.963 c-3.451-0.263-7.412,0.636-10.496,2.245c-6.369,3.324-6.896,10.001-7.248,17.67c-12.146-8.157-24.329-12.988-36.575-14.34 c-2.94-2.54-4.264-6.236-3.879-10.997c0.451-5.587,0.239-11.066-0.572-16.359c0.828-2.872,1.549-5.847,2.156-8.934 c5.672,5.174,10.766,9.523,17.62,7.369c3.319-1.043,6.755-3.208,9.009-5.835c4.921-5.734,3.914-14.302-1.556-19.605 c-6.5-6.301-13.69-5.549-25.075,3.382c-5.055-30.578-25.967-51.62-54.619-60.047c-2.447-0.732-4.807-2.023-7.825-3.278 c2.125-2.286,3.29-3.461,4.367-4.71c11.938-14.551-7.15-33.181-21.367-21.111c-6.165,5.565-6.879,14.513-1.665,20.864 c4.197,5.111,3.946,5.411-2.516,8.068c-1.812,0.745-3.642,1.467-5.474,2.19c-24.645,7.648-40.948,25.21-46.886,49.595 c-0.68,2.698-2.102,5.208-3.473,8.505c-2.286-2.125-3.461-3.29-4.71-4.367c-14.552-11.938-33.18,7.152-21.111,21.367 c5.565,6.165,14.513,6.879,20.864,1.665c4.71-3.867,5.338-3.944,7.487,1.123c-1.309,6.465-1.74,13.174-1.396,20.102 c0.3,6.03-1.497,10.097-5.356,12.617c-8.889,2.044-17.148,6.132-25.567,9.656c-6.448,2.691-6.837,2.656-7.484-3.926 c-0.804-8.178-7.636-14-15.931-13.576c-18.581,1.516-18.918,28.187-0.181,30.036c1.645,0.122,3.299,0.129,6.419,0.243 c-1.366,3.319-2.113,5.992-3.558,8.47c-3.428,5.74-6.123,11.683-7.912,17.811c-4.722,16.154-2.533,34.602,5.996,50.411 c1.801,5.691,8.569,13.392-1.603,12.903c-40,12.971,18.416,54.114,16.704,9.691c34.782,3.225,46.692,41.92,80.447,49.674 c7.963,2.791,11.179,6.671,12.046,13.724c0.012,3.241,0.01,6.503,0,9.829h-0.223c0,2.086,0,5.309,0,5.309s0.065,0.184-0.069,0.268 c-7.211-0.002-14.005-0.041-20.79,0.015c-4.483,0.037-6.154,1.09-6.592,4.667c-0.352,4.638-0.043,9.45-0.131,14.122 c0.062,5.274,1.49,6.69,6.861,6.724c6.999,0.045,13.998,0.011,21.721,0.011v5.671c-7.723,0-14.722-0.034-21.721,0.011 c-5.372,0.035-6.799,1.45-6.861,6.724c0.087,4.671-0.221,9.484,0.131,14.122c0.438,3.577,2.109,4.63,6.592,4.667 c6.785,0.056,13.579,0.017,20.79,0.015c0.134,0.084,0.279,0.175,0.069,0.268v5.406h0.599c0.031,3.784,0.031,7.619,0,12h-0.599 v4.809c0,0,0.065,0.184-0.069,0.268c-7.211-0.002-14.005-0.041-20.79,0.015c-4.483,0.037-6.154,1.09-6.592,4.667 c-0.352,4.638-0.043,9.45-0.131,14.122c0.062,5.274,1.49,6.69,6.861,6.724c6.999,0.045,13.998,0.011,21.721,0.011v5.671 c-7.723,0-14.722-0.034-21.721,0.011c-5.372,0.035-6.799,1.45-6.861,6.724c0.087,4.671-0.221,9.484,0.131,14.122 c0.438,3.577,2.109,4.63,6.592,4.667c6.785,0.056,13.579,0.017,20.79,0.015c0.134,0.084,0.279,0.175,0.069,0.268v4.906h0.599 c0.031,4.284,0.031,8.119,0,12h-0.599v5.309c0.211,0.092,0.065,0.184-0.069,0.268c-7.211-0.002-14.005-0.041-20.79,0.015 c-4.483,0.037-6.154,1.09-6.592,4.667c-0.352,4.638-0.043,9.45-0.131,14.122c0.062,5.274,1.49,6.69,6.861,6.724 c6.999,0.045,21.721,0.011,21.721,0.011v5.671c0,0-14.722-0.034-21.721,0.011c-5.372,0.035-6.799,1.45-6.861,6.724 c0.087,4.671-0.221,9.484,0.131,14.122c0.438,3.577,2.109,4.63,6.592,4.667c6.785,0.056,13.579,0.017,20.79,0.015 c0.134,0.084,0.279,0.175,0.457,0.268c0,1.594,4.559,168.228,4.51,209.286c-0.005,4.1,0.442,9.128,0.442,10.259 c-3.396,0-6.234,0.133-9.054-0.034c-3.499-0.206-5.37,1.456-6.735,4.558c-1.281,2.913-2.803,5.866-4.843,8.27 c-6.58,7.751-16.578,7.84-23.206,0.144c-2.209-2.565-3.736-5.81-5.169-8.932c-1.239-2.699-2.939-4.083-5.916-4.024 c-3.712,0.073-7.428,0.078-11.14-0.009c-3.163-0.074-4.936,1.432-6.143,4.306c-1.141,2.716-2.476,5.469-4.285,7.764 c-8.725,11.281-23.01,6.923-27.966-5.357c-1.496-5.628-5.039-7.274-10.521-6.767c-4.485,0.415-6.285,1.937-6.286,6.612 c-0.001,15.755-0.002,31.511-0.003,47.266c-0.001,16.376-0.012,32.752,0.006,49.127c0.004,3.646,2.039,5.706,5.586,5.765 c4.244-0.151,7.724,1.078,9.747-3.72c1.63-3.566,3.31-7.297,5.811-10.239c5.927-6.969,15.25-7.396,21.596-0.827 c2.91,3.012,4.885,7.078,6.716,10.936c1.245,2.623,2.748,3.896,5.573,3.857c3.96-0.055,7.925-0.102,11.882,0.027 c3.041,0.099,4.629-1.359,5.914-4.011c1.386-2.861,3.016-5.766,5.166-8.063c10.107-10.412,22.254-3.718,27.139,8.037 c1.337,2.907,3.18,4.141,6.281,4.034c3.442-0.119,6.891-0.027,10.523-0.027c1.065,5.652,2.167,11.021,3.856,16.453 c1.228,3.675,2.407,8.536,7.056,8.594c4.923,0.061,6.042-4.987,7.307-8.743c1.456-4.322,2.867-8.847,3.125-13.35 c0.728-12.721,1.152-25.477,1.174-38.219c0.19-111.404,0.292,50.177,0.366-61.227c0.003-5.129,0.201-18.49,0.201-22.46 c0-41.693,4.098-203.286,4.098-209.558c8.112,0,15.82-0.053,23.528,0.021c5.544,0.13,6.64-3.323,6.288-8.201 c0.033-3.547,0.038-7.095-0.007-10.642c-0.066-5.278-1.476-6.669-6.885-6.701c-7.529-0.044-23.121-0.011-23.121-0.011v-5.671 c0,0,15.592,0.033,23.121-0.011c5.408-0.032,6.819-1.423,6.885-6.701c0.044-3.547,0.04-7.095,0.007-10.642 c0.351-4.882-0.742-8.33-6.288-8.201c-7.707,0.073-15.416,0.021-22.724,0.021v-22.76c7.308,0,15.017-0.053,22.724,0.021 c5.544,0.13,6.64-3.323,6.288-8.201c0.033-3.547,0.038-7.095-0.007-10.642c-0.066-5.278-1.476-6.669-6.885-6.701 c-7.529-0.044-15.059-0.011-23.121-0.011v-5.671c8.062,0,15.592,0.033,23.121-0.011c5.408-0.032,6.819-1.423,6.885-6.701 c0.044-3.547,0.04-7.095,0.007-10.642c0.351-4.882-0.742-8.33-6.288-8.201c-7.707,0.073-15.416,0.021-22.724,0.021v-22.76 c7.308,0,15.017-0.053,22.724,0.021c5.544,0.13,6.64-3.323,6.288-8.201c0.033-3.547,0.038-7.095-0.007-10.642 c-0.066-5.278-1.476-6.669-6.885-6.701c-7.529-0.044-15.059-0.011-23.121-0.011v-5.671c8.062,0,15.592,0.033,23.121-0.011 c5.408-0.032,6.819-1.423,6.885-6.701c0.044-3.547,0.04-7.095,0.007-10.642c0.351-4.882-0.742-8.33-6.288-8.201 c-7.707,0.073-15.416,0.021-22.724,0.021v-13.831c0.379-7.638,5.186-13.149,13.162-15.825 c28.456-7.104,41.808-33.352,64.888-48.287c17.492-10.743,9.354,22.937,28.518,19.129 C282.127,286.309,282.455,259.681,263.752,257.836z M105.697,839.074c0.498,2.38,0.15,4.934-3.302,4.884 c-2.295-0.033-3.176,1.042-3.702,3.217c-0.26,1.076-1.713,2.383-2.793,2.559c-0.723,0.118-2.36-1.479-2.505-2.467 c-0.409-2.804-2.004-3.344-4.385-3.299c-3.709,0.07-7.424,0.116-11.131-0.006c-3.83-0.126-3.945,2.278-3.981,5.13 c-0.038,2.976,0.755,4.826,4.142,4.589c1.477-0.103,2.968,0.015,4.451-0.025c2.202-0.059,4.543-0.006,4.579,2.901 c0.039,3.187-2.477,3.119-4.78,3.068c-1.36-0.03-2.728,0.082-4.08-0.025c-3.258-0.257-4.5,1.312-4.272,4.425 c-0.041,4.353,1.027,8.028-4.883,7.506c-7.022,0.039-7.951,0.802-7.543-7.405c0.169-3.39-1.192-4.855-4.554-4.524 c-0.857,0.085-1.922,0.329-2.555-0.056c-1.2-0.729-2.156-1.861-3.213-2.825c1.006-1.017,1.944-2.121,3.057-3.004 c0.38-0.301,1.199-0.042,1.817-0.044c5.007-0.022,7.131-2.986,5.196-7.646c-0.392-0.945-1.974-1.785-3.11-1.944 c-3.651-0.437-7.442,0.158-11.117-0.121c-3.786-0.387-5.894,0.721-5.698,5.061c0.045,0.996-1.78,2.077-2.744,3.119 c-0.848-1.038-2.451-2.105-2.412-3.108c0.153-3.932-1.445-5.27-5.269-5.225c-1.017,0.012-2.491-1.899-2.973-3.215 c-0.52-1.421-0.127-3.18-0.126-4.791c0-5.24-0.002-5.268,5.3-5.954c2.366-0.306,3.023-1.787,2.927-3.889 c-0.098-2.143,0.268-4.425,2.848-4.073c1.034,0.141,2.342,2.528,2.49,3.998c0.282,2.788,1.314,4.039,4.131,3.976 c3.956-0.088,7.919-0.125,11.873,0.011c3.063,0.105,4.168-1.204,4.13-4.212c-0.036-2.816-0.326-5.041-3.916-4.755 c-2.559,0.203-4.468-0.474-4.367-3.527c0.095-2.865,2.016-3.344,4.358-3.173c2.898,0.212,3.849-1.243,3.979-4.019 c0.085-1.821,0.73-5.002,1.563-5.153c3.046-0.553,6.308-0.31,9.408,0.165c0.646,0.099,1.284,2.453,1.345,3.795 c0.224,4.967,0.374,5.207,5.401,5.214c1.361,0.002,2.929-0.422,4.027,0.116c1.271,0.623,2.94,2.09,2.942,3.194 c0.002,1.125-1.621,2.815-2.876,3.241c-1.665,0.565-3.667,0.223-5.518,0.132c-3.18-0.157-3.971,1.57-3.952,4.398 c0.019,2.703,0.495,4.64,3.783,4.569c3.956-0.085,7.916-0.055,11.873-0.012c2.165,0.024,3.322-0.763,3.826-3.068 c0.241-1.105,1.771-1.927,2.718-2.877c0.905,0.971,2.333,1.814,2.605,2.939c0.545,2.256,1.757,2.7,3.843,3.111 C108.401,831.102,105.035,835.914,105.697,839.074z M139.108,46c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54 s-54-24.177-54-54C85.108,70.176,109.285,46,139.108,46z M19.108,212c0-29.823,24.177-54,54-54s54,24.177,54,54 c0,29.823-24.177,54-54,54S19.108,241.823,19.108,212z M144.944,857.898c-2.09,2.578-1.865,5.176-1.942,7.953 c-0.024,0.854,0.131,1.914-0.302,2.509c-2.403,3.147-3.159,2.809-5.436-0.185c-0.264-0.306-0.178-0.948-0.184-1.437 c-0.041-3.271,0.536-6.657-2.369-9.253c-0.531-0.475-0.479-1.605-0.957-3.425c1.21-1.271,2.47-3.306,4.294-4.333 c2.379-1.339,5.236-0.58,6.441,1.819C145.405,853.367,145.95,856.658,144.944,857.898z M144.996,807.941 c-2.224,2.677-1.877,5.438-1.992,8.318c-0.086,2.146-0.2,4.578-2.99,4.544c-2.765-0.034-2.874-2.475-2.933-4.614 c-0.08-2.895,0.543-5.919-2.179-8.193c-0.631-0.527-0.645-1.797-1.234-3.633c1.265-1.382,2.48-3.465,4.292-4.5 c2.341-1.338,5.233-0.649,6.476,1.731C145.382,803.404,145.991,806.744,144.996,807.941z M80.062,279.694 c17.171-3.582,56.234-25.446,59.296-50.487c5.518,22.114,30,48.729,61,48.729C162.77,319.773,120.431,321.28,80.062,279.694z M205.108,266c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54C259.108,241.823,234.932,266,205.108,266z", - clocks: { - size: 108, - 0: { x: 138.892, y: 100 }, - 1: { x: 72.892, y: 212 }, - 2: { x: 204.892, y: 212 } - } - }, - 4: { - height: 1041, - width: 368.697, - path: "M365.949,178.882c-2.159-2.705-5.464-5.038-8.725-6.201c-7.211-2.57-12.634,1.794-18.155,7.261 c-1.008-3.182-1.811-5.292-2.346-7.468c-7.207-29.311-25.676-46.993-55.052-53.142c-3.565-0.746-4.337-2.365-5.721-5.525 c-10.917-24.928-15.917-32.928-31.863-49.408c-1.625-1.679-3.453-3.192-5.144-4.761c-15.909-14.758-20.909-17.758-43.492-26.71 c-1.882-0.746-3.781-1.782-6.866-3.302c2.349-1.876,3.694-2.659,4.662-3.772c4.695-5.397,4.837-13.436,0.452-19.014 c-5.3-6.742-15-7.806-21.456-2.354c-6.714,5.67-7.304,15.417-1.328,21.919c3.617,3.935,3.297,5.361-1.725,7.153 c-2.044,0.73-4.17,1.226-6.237,1.896c-12.766,4.137-23.255,11.604-31.918,21.798c-2.372,2.791-4.778,5.622-7.539,8.002 c-15.564,13.413-26.166,29.895-31.108,49.904c-0.68,2.752-1.741,4.084-4.825,4.54c-29.053,4.299-51.461,25.809-57.16,54.556 c-0.307,1.549-0.792,3.062-1.25,4.806c-11.35-8.302-18-8.998-24.401-2.862c-5.321,5.101-6.467,13.398-1.935,19.203 c2.036,2.608,5.192,4.836,8.302,6.005c7.137,2.683,12.59-1.579,17.735-6.353c0.583,1.299,1.01,1.874,1.096,2.496 c4.046,29.315,27.997,53.277,57.825,57.393c2.223,0.307,4.062,1.874,4.644,4.041c1.308,4.861,2.891,9.682,4.787,14.345 c9.432,23.198,28.811,38.203,45.823,55.084c5.104,5.065,11.204,9.197,17.156,13.308c5.563,3.842,7.792,8.391,7.788,15.456 c-0.129,188.254-0.004,308.508,0.065,496.762c0,0.102-0.005,0.205-0.006,0.307v41.241c-2.701,0.026-5.102,0.092-7.461-0.047 c-3.499-0.206-5.37,1.456-6.735,4.558c-1.282,2.913-2.803,5.866-4.844,8.27c-6.581,7.751-16.578,7.84-23.206,0.144 c-2.254-2.617-3.797-5.94-5.255-9.119c-1.087-2.369-3.472-3.882-6.078-3.833c-3.63,0.068-7.263,0.071-10.893-0.013 c-3.163-0.074-4.936,1.432-6.143,4.306c-1.141,2.716-2.476,5.469-4.285,7.764c-8.725,11.281-23.01,6.923-27.966-5.357 c-1.496-5.628-5.039-7.274-10.521-6.767c-4.485,0.415-6.285,1.937-6.286,6.612c-0.001,15.755-0.002,31.511-0.003,47.266 c-0.001,16.376-0.012,32.752,0.006,49.127c0.004,3.646,2.039,5.706,5.586,5.765c4.244-0.151,7.724,1.078,9.747-3.72 c1.63-3.566,3.31-7.297,5.811-10.239c5.927-6.969,15.25-7.396,21.596-0.827c2.91,3.012,4.885,7.078,6.716,10.936 c1.457,3.071,3.269,4.292,7.14,3.723c2.897-0.426,5.844-0.506,8.73-0.009c4.108,0.708,6.007-0.762,7.499-3.84 c1.386-2.861,3.016-5.766,5.166-8.063c10.107-10.412,22.254-3.718,27.139,8.037c1.337,2.907,3.181,4.141,6.281,4.034 c2.715-0.094,5.446-0.058,8.257-0.038v2.091c0.319,0.001,0.631,0.004,0.951,0.004c0.362,2.11,0.473,3.786,0.947,5.352 c2.41,7.972,4.19,16.244,7.596,23.773c3.168,7.005,9.289,6.901,12.709-0.011c2.932-5.925,5.134-12.395,6.525-18.868 c4.01-18.662,2.675-37.664,2.696-56.567c0.133-118.853,0.314,0.295,0.392-118.558c0.068-103.934,0.013-377.867,0.064-481.801 c0.001-2.781-0.281-6.125,1.073-8.24c4.886-7.634,8.978-15.851,18.168-20.058c5.139-2.352,9.257-7.045,13.652-10.893 c4.267-3.736,8.16-7.904,12.459-11.599c15.452-13.278,26.023-29.619,30.885-49.451c0.909-3.707,2.926-4.598,6.161-5.73 c8.764-3.067,17.943-5.775,25.742-10.598c14.82-9.164,23.822-23.162,28.263-40.071c0.703-2.678,1.909-5.223,2.991-8.122 c11.076,8.596,18.006,9.328,24.489,3.223C369.187,192.953,370.464,184.538,365.949,178.882z M146.765,952.539 c0.498,2.38,0.15,4.934-3.302,4.884c-2.294-0.033-3.176,1.042-3.702,3.217c-0.26,1.076-1.713,2.383-2.793,2.559 c-0.723,0.118-2.36-1.479-2.504-2.467c-0.409-2.804-2.004-3.344-4.384-3.299c-3.709,0.07-7.424,0.116-11.131-0.006 c-3.83-0.126-3.945,2.278-3.981,5.13c-0.038,2.976,0.755,4.826,4.142,4.589c1.477-0.103,2.968,0.015,4.451-0.025 c2.202-0.059,4.543-0.006,4.579,2.901c0.04,3.187-2.477,3.119-4.78,3.068c-1.36-0.03-2.728,0.082-4.08-0.025 c-3.258-0.257-4.5,1.312-4.272,4.425c-0.041,4.353,1.027,8.028-4.883,7.506c-7.022,0.039-7.951,0.802-7.542-7.405 c0.168-3.39-1.192-4.855-4.555-4.524c-0.857,0.085-1.922,0.329-2.555-0.056c-1.2-0.729-2.156-1.861-3.213-2.825 c1.006-1.017,1.944-2.121,3.057-3.004c0.379-0.301,1.199-0.042,1.817-0.044c5.007-0.022,7.131-2.986,5.197-7.646 c-0.393-0.945-1.975-1.785-3.11-1.944c-3.651-0.437-7.442,0.158-11.117-0.121c-3.786-0.387-5.894,0.721-5.698,5.061 c0.045,0.996-1.78,2.077-2.744,3.119c-0.848-1.038-2.451-2.105-2.412-3.108c0.153-3.932-1.445-5.27-5.269-5.225 c-1.017,0.012-2.491-1.899-2.973-3.215c-0.52-1.422-0.127-3.18-0.126-4.791c0.001-5.24-0.002-5.268,5.3-5.954 c2.366-0.306,3.023-1.787,2.927-3.889c-0.098-2.143,0.268-4.425,2.848-4.073c1.034,0.141,2.342,2.528,2.49,3.998 c0.282,2.788,1.314,4.039,4.131,3.976c3.956-0.088,7.919-0.125,11.872,0.011c3.063,0.105,4.168-1.204,4.13-4.212 c-0.035-2.816-0.326-5.041-3.916-4.755c-2.559,0.203-4.468-0.474-4.367-3.527c0.095-2.865,2.016-3.344,4.358-3.173 c2.898,0.212,3.849-1.243,3.979-4.019c0.085-1.821,0.73-5.002,1.563-5.153c3.046-0.553,6.308-0.31,9.408,0.165 c0.646,0.099,1.284,2.453,1.345,3.795c0.224,4.967,0.375,5.207,5.402,5.214c1.361,0.002,2.928-0.423,4.027,0.116 c1.272,0.623,2.94,2.09,2.943,3.194c0.002,1.125-1.621,2.815-2.876,3.241c-1.666,0.565-3.668,0.223-5.518,0.132 c-3.18-0.157-3.971,1.57-3.952,4.398c0.019,2.703,0.495,4.64,3.783,4.569c3.957-0.085,7.916-0.055,11.874-0.012 c2.166,0.024,3.322-0.763,3.826-3.068c0.242-1.105,1.771-1.927,2.718-2.877c0.905,0.971,2.333,1.814,2.605,2.939 c0.545,2.256,1.757,2.7,3.843,3.111C149.469,944.566,146.104,949.379,146.765,952.539z M252.621,98.898 c0.287-0.167,0.574-0.334,0.861-0.502c2.841,6.521,5.683,13.042,8.739,20.056c-4.719,1.002-8.414,1.787-12.443,2.642 C250.758,113.446,251.689,106.172,252.621,98.898z M184.136,46.188c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54 s-54-24.177-54-54C130.136,70.365,154.313,46.188,184.136,46.188z M162.097,165.903c14.218,3.796,27.946,4.565,42.414-0.072 c-3.942,14.414-4.001,28.063,0.302,42.583c-14.189-3.96-27.779-4.487-42.527-0.062C166.547,193.78,166.444,180.286,162.097,165.903 z M114.049,99.643c0.292,0.134,0.583,0.269,0.875,0.403c1.095,7.133,2.19,14.267,3.378,22.01 c-3.852-0.843-7.747-1.695-12.458-2.726C108.69,112.502,111.369,106.072,114.049,99.643z M114.09,275.17 c-2.992-7.299-5.446-13.283-8.044-19.622c4.192-0.951,7.557-1.714,11.303-2.564C116.293,260.174,115.314,266.84,114.09,275.17z M97.136,240.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C151.136,216.012,126.96,240.188,97.136,240.188z M190.317,961.816c-2.889,3.631-2.59,7.316-2.675,11.229 c-0.063,2.929-0.301,6.185-4.102,6.083c-3.718-0.099-3.92-3.373-3.912-6.266c0.01-3.961,0.532-7.956-2.966-11.069 c-0.843-0.75-0.86-2.433-1.653-4.938c1.737-1.842,3.427-4.577,5.876-5.996c3.218-1.864,7.078-0.801,8.743,2.361 C190.908,955.651,191.666,960.12,190.317,961.816z M190.377,894.286c-2.75,3.639-2.754,7.277-2.731,11.231 c0.017,2.954-0.303,6.162-3.967,6.219c-3.722,0.058-4.036-3.156-4.069-6.118c-0.044-3.915,0.729-7.982-2.898-11.07 c-0.855-0.728-0.902-2.408-1.792-5.047c1.877-1.885,3.726-5.163,6.313-5.925c2.41-0.711,6.606,0.411,8.177,2.279 C190.999,887.744,191.681,892.56,190.377,894.286z M190.399,830.196c-3.107,3.329-2.592,6.926-2.795,10.682 c-0.086,1.597-0.323,3.33-1.04,4.717c-1.41,2.725-4.298,2.744-5.822,0.114c-0.63-1.087-1.04-2.453-1.075-3.706 c-0.125-4.43,0.653-9.009-3.304-12.472c-0.62-0.543-0.572-1.852-0.833-2.806c-0.315-0.34-0.629-0.679-0.944-1.019 c2.103-2.244,3.85-5.571,6.413-6.415c2.391-0.788,6.184,0.324,8.392,1.933C192.319,823.355,192.864,827.555,190.399,830.196z M184.136,328.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C238.136,304.012,213.96,328.188,184.136,328.188z M252.789,277.752c-0.265-0.133-0.531-0.265-0.796-0.398 c-1.015-8.257-2.029-16.515-3.086-25.115c4.167,0.862,8.324,1.721,13.585,2.809C259.162,262.841,255.975,270.297,252.789,277.752z M271.136,240.188c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54c29.823,0,54,24.177,54,54 C325.137,216.012,300.96,240.188,271.136,240.188z", - clocks: { - size: 108, - 0: { x: 184.245, y: 100 }, - 1: { x: 97.245, y: 186 }, - 2: { x: 271.245, y: 186 }, - 3: { x: 184.245, y: 274 } - } - }, - 5: { - height: 1148.657, - width: 368.698, - path: "M364.919,177.185c-5.856-6.593-15.147-6.888-21.897-0.694c-3.717,3.411-4.299,3.242-5.541-1.587 c-0.25-0.972-0.571-1.926-0.803-2.901c-6.223-26.032-22.396-42.736-47.523-51.238c-2.474-0.837-4.808-2.72-6.666-4.641 c-6.618-6.844-12.426-14.598-19.638-20.709c-7.25-6.144-14.426-11.753-15.964-21.863c-0.145-0.952-0.81-1.83-1.262-2.728 c-10.14-20.142-26.293-32.5-48.2-37.503c-2.572-0.587-5.014-1.743-8.025-2.817c1.316-1.702,1.86-2.531,2.526-3.247 c6.502-6.986,6.698-15.783,0.465-21.94c-5.785-5.714-15.027-5.762-20.84-0.11c-6.368,6.191-6.436,15.084,0.239,21.857 c2.991,3.035,1.728,4.561-1.167,5.98c-1.334,0.654-2.844,0.952-4.281,1.387c-24.857,7.514-40.936,23.712-48.399,48.654 c-0.748,2.499-2.69,4.83-4.561,6.77c-8.684,9.004-17.485,17.897-26.377,26.695c-1.782,1.764-3.95,3.591-6.269,4.287 c-27.272,8.186-44.245,25.906-50.386,53.864c-0.306,1.391-0.752,2.75-1.182,4.299c-11.942-8.326-18.43-8.891-24.733-2.424 c-5.16,5.294-6.085,13.716-1.351,19.24c2.253,2.629,5.655,4.841,8.962,5.874c6.77,2.115,12.009-1.8,16.717-6.757 c0.647,1.364,1.068,1.923,1.182,2.539c5.495,29.672,22.939,48.289,51.806,56.504c1.891,0.538,3.666,2.056,5.112,3.503 c8.725,8.731,17.397,17.519,25.942,26.426c1.755,1.83,3.532,4.061,4.227,6.423c5.507,18.702,16.574,32.696,33.076,43.228 c6.667,4.255,11.428,11.52,16.987,17.48c0.5,0.535,0.688,1.544,0.692,2.334c0.044,10.877,0.03,21.753,0.03,32.638 c-1.577,0.516-2.845,0.932-4.113,1.346c-17.135,5.597-30.511,16.033-39.024,31.952c-3.426,6.407-5.333,13.646-7.754,20.57 c-1.76,5.033-3.129,5.54-6.907,2.08c-2.706-2.478-6.172-4.068-9.837-4.235c-8.598-0.392-15.176,6.223-15.67,13.97 c-0.384,6.021,2.865,11.744,8.198,14.44c5.638,2.851,12.01,2.021,16.818-2.189c2.562-2.243,5.668-1.656,6.923,1.51 c1.187,2.993,1.799,6.229,3.124,9.149c2.549,5.62,4.886,11.444,8.247,16.568c9.497,14.478,39.422,28.018,39.422,28.018v28.542 c0,0-0.496,0.466-0.788,0.469c-5.522,0.049-11.045,0.088-16.568,0.095c-9.805,0.013-10.191,0.382-10.188,9.959 c0.001,2.347-0.002,4.695,0,7.042c0.008,7.059,1.061,8.147,7.942,8.157c6.643,0.01,13.286,0.002,20.223,0.002 c-0.115,2.368-0.198,4.098-0.292,6.035c-7.528,0-14.546,0.054-21.562-0.02c-3.56-0.037-6.383,2.854-6.323,6.415 c0.064,3.826-0.011,7.654,0.01,11.481c0.033,5.918,1.364,7.248,7.324,7.269c6.815,0.024,21.22,0.006,21.22,0.006v7.044 c0,0-14.435-0.017-21.108,0.005c-6.069,0.02-7.373,1.289-7.434,7.19c-0.028,2.682,0.18,5.38-0.039,8.044 c-0.443,5.389,0.07,10.039,6.912,10.524c-3.015,31.457-2.572,62.398,2.234,93.196c2.98,19.097,7.19,37.854,16.599,55.063 c1.443,2.639,2.397,5.924,2.406,8.914c0.209,63.543,0.251,127.087,0.325,190.631c0.002,1.795,0,3.59,0,5.442 c-5.238,0.679-7.397-1.369-7.347-5.986c0.035-3.185,0.024-6.371,0.006-9.557c-0.034-5.945-1.325-7.274-7.309-7.285 c-17.074-0.032-34.148-0.022-51.222-0.026c-11.718-0.003-23.435-0.029-35.153,0.013c-5.235,0.019-6.699,1.54-6.756,6.814 c-0.038,3.521-0.04,7.042,0.004,10.563c0.066,5.255,1.516,6.725,6.823,6.744c11.215,0.04,22.431,0.01,33.646,0.013 c11.868,0.003,11.868,0.005,11.75,11.912c-0.059,5.922-1.3,7.16-7.407,7.176c-12.22,0.031-24.439,0.018-36.659,0.029 c-7.054,0.006-8.155,1.08-8.167,7.935c-0.004,2.18-0.006,4.359,0.001,6.539c0.021,6.383,1.222,7.644,7.439,7.655 c11.048,0.02,22.096,0.002,33.144,0.006c11.791,0.005,11.791,0.008,11.648,12.012c-0.067,5.703-1.367,7.062-7.047,7.083 c-10.378,0.04-20.758,0.096-31.135-0.002c-15.122-0.144-14.146-0.478-14.047,14.132c0.038,5.646,1.377,6.992,7.074,7.008 c11.048,0.031,22.096,0.007,33.144,0.01c12.19,0.003,12.19,0.005,12.011,12.153c-0.083,5.597-1.413,6.924-7.187,6.944 c-10.211,0.034-20.423,0.089-30.633-0.001c-15.773-0.139-14.465-0.577-14.406,14.774c0.024,6.173,1.313,7.37,7.73,7.375 c13.726,0.011,27.452,0.005,41.179,0.003c14.898-0.002,29.796,0.018,44.694-0.027c5.339-0.016,6.767-1.487,6.831-6.742 c0.033-2.682-0.046-5.366,0.02-8.047c0.126-5.106,1.839-6.469,8.044-5.697c0,5.722-0.455,11.611,0.097,17.404 c1.078,11.308,2.634,22.631,8.667,32.623c3.709,6.143,9.563,5.816,12.753-0.612c2.984-6.015,5.833-12.625,6.409-19.174 c1.579-17.969,2.543-36.045,2.614-54.083c0.36-91.878,0.35-183.757,0.553-275.636c0.005-2.049,0.733-4.214,1.576-6.124 c3.369-7.639,7.748-14.934,10.257-22.833c11.421-35.946,13.433-72.997,11.755-110.391c-0.269-5.99-0.801-11.968-1.209-17.909 c7.452-1.534,7.775-1.945,7.779-9.588c0.001-2.515,0.011-5.03,0.007-7.545c-0.013-7.75-0.894-8.656-8.46-8.663 c-7.141-0.007-22.406-0.001-22.406-0.001v-7.045c0,0,16.742-0.048,24.561,0.019c4.359,0.038,6.392-2,6.312-6.351 c-0.071-3.855,0.016-7.712-0.019-11.568c-0.053-5.938-1.345-7.219-7.35-7.242c-7.485-0.029-22.504-0.007-22.504-0.007v-6.035 c0,0,15.454,0.033,22.967-0.011c5.362-0.031,6.803-1.454,6.876-6.683c0.049-3.52,0.028-7.042,0.018-10.563 c-0.019-6.708-1.157-7.881-7.7-7.895c-7.319-0.016-21.161-0.004-21.161-0.004v-28.963c0,0,51.319-18.506,51.418-58.803 c13.274,8.8,19.828,9.143,25.982,1.96c4.843-5.653,4.919-13.758,0.181-19.362c-6.121-7.24-12.687-6.904-26.259,1.909 c-5.709-30.27-22.672-50.541-52.587-59.137c0-11.198-0.038-22.249,0.053-33.298c0.01-1.247,0.394-2.826,1.206-3.677 c5.143-5.394,9.736-11.741,15.851-15.695c15.582-10.074,26.618-23.168,32.069-40.997c0.628-2.052,2.154-4.251,3.897-5.472 c12.064-8.448,22.297-18.658,30.858-30.639c1.235-1.728,3.009-3,5.027-3.661c25.276-8.284,41.218-25.241,47.865-51.029 c0.549-2.129,1.536-4.145,2.62-7.008c2.028,1.88,3.182,3.03,4.418,4.083c5.813,4.951,14.202,4.893,19.761-0.107 C369.847,192.788,370.428,183.388,364.919,177.185z M252.394,107.492c4.098,3.415,7.887,6.574,11.677,9.733 c-0.404,0.395-0.807,0.791-1.211,1.186c-4.169,0.785-8.338,1.57-13.15,2.476C250.666,116.112,251.516,111.872,252.394,107.492z M184.406,46c29.823,0,54,24.177,54,54c0,29.823-24.177,54-54,54s-54-24.177-54-54C130.406,70.177,154.583,46,184.406,46z M162.373,165.581c14.357,4.18,28.096,4.578,42.513,0.199c-4.092,14.47-3.946,28.113,0.227,42.523 c-14.26-4.037-27.868-4.509-42.273-0.152C166.659,193.831,166.896,180.189,162.373,165.581z M115.827,107.593 c1.197,5.466,2.101,9.598,3.149,14.382c-4.547-0.964-8.521-1.806-13.675-2.899C108.835,115.221,111.958,111.814,115.827,107.593z M43.406,186c0-29.823,24.177-54,54-54s54,24.177,54,54c0,29.823-24.177,54-54,54S43.406,215.823,43.406,186z M115.278,265.909 c-3.402-3.626-6.248-6.661-9.67-10.309c4.662-1.06,8.192-1.862,12.324-2.801C117.071,257.051,116.27,261.011,115.278,265.909z M238.406,453c0,29.823-24.177,54-54,54s-54-24.177-54-54s24.177-54,54-54S238.406,423.177,238.406,453z M184.406,328 c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54C238.406,303.823,214.23,328,184.406,328z M251.958,267.927 c-1.167-5.669-2.154-10.46-3.262-15.84c5.154,0.97,9.935,1.87,14.716,2.77c0.446,0.541,0.892,1.082,1.338,1.623 C260.673,260.129,256.595,263.778,251.958,267.927z M271.406,240c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 c29.823,0,54,24.177,54,54C325.406,215.823,301.23,240,271.406,240z", - clocks: { - size: 108, - 0: { x: 184.245, y: 100 }, - 1: { x: 97.245, y: 186 }, - 2: { x: 271.245, y: 186 }, - 3: { x: 184.245, y: 274 }, - 4: { x: 184.245, y: 453 } - } - }, - 6: { - height: 1148.98, - width: 370.141, - path: "M365.84,176.489c-5.689-5.831-14.774-6.109-20.983-0.642c-4.677,4.118-4.976,4.085-6.414-2.269 c-6.187-27.333-22.732-44.97-49.412-53.347c-1.887-0.593-3.769-2.168-4.983-3.788c-8.33-11.115-18.008-20.785-29.318-28.894 c-1.84-1.32-3.239-3.825-3.948-6.065c-8.013-25.306-24.804-41.278-50.453-47.985c-1.299-0.34-2.628-0.562-3.93-0.89 c-6.029-1.519-6.346-2.456-2.44-7.102c5.378-6.396,4.93-15.201-1.065-20.921c-5.702-5.442-14.806-5.447-20.582-0.013 c-6.006,5.651-6.507,14.545-1.066,20.88c0.962,1.12,2.36,1.865,5.102,3.969c-3.997,1.969-6.466,3.647-9.192,4.455 c-21.058,6.239-37.094,18.816-44.941,39.357c-3.899,10.207-9.562,17.625-17.758,24.394c-6.646,5.489-11.704,12.883-17.615,19.294 c-1.38,1.497-3.203,3.002-5.097,3.546c-28.343,8.127-45.563,26.507-51.567,55.389c-0.195,0.941-0.595,1.84-1.211,3.697 c-4.56-5.357-9.738-8.928-16.367-7.261c-3.226,0.811-6.599,2.778-8.897,5.184c-5.104,5.343-4.779,13.776,0.038,19.336 c6.068,7.004,12.02,6.721,25.619-1.458c0.72,3.007,1.322,5.896,2.106,8.735c7.133,25.831,23.797,42.127,49.404,49.659 c2.498,0.735,4.874,2.61,6.784,4.488c8.593,8.445,17.053,17.028,25.427,25.692c1.767,1.828,3.636,4.007,4.323,6.356 c5.597,19.138,16.997,33.318,33.994,43.913c6.567,4.094,11.118,11.439,16.51,17.374c0.48,0.528,0.534,1.578,0.536,2.386 c0.033,10.743,0.022,21.486,0.022,30.697c-9.552,5.427-18.816,9.569-26.776,15.469c-12.547,9.299-19.949,22.422-23.771,37.578 c-0.68,2.698-2.102,5.208-3.473,8.506c-2.286-2.126-3.461-3.29-4.711-4.367c-6.067-5.231-15.003-4.872-20.573,0.801 c-5.603,5.707-5.839,14.698-0.54,20.569c5.565,6.166,14.515,6.88,20.866,1.665c5.112-4.197,5.412-3.946,8.069,2.516 c3.43,8.344,6.359,17.082,11.089,24.661c8.379,13.426,21.019,21.894,36.078,26.785c1.434,0.466,3.551,2,3.587,3.097 c0.294,8.853,0.165,17.72,0.165,27.124c-7.476,0-14.485-0.043-21.493,0.014c-5.306,0.044-6.687,1.494-6.735,6.878 c-0.033,3.697-0.03,7.394-0.004,11.091c0.042,5.943,1.284,7.157,7.436,7.185c6.702,0.031,13.405,0.007,20.448,0.007 c0,2.034,0,5.598,0,5.598s-13.784-0.034-20.783,0.011c-5.372,0.035-6.799,1.45-6.861,6.724c-0.047,4.026,0.044,8.054-0.023,12.079 c-0.072,4.325,1.898,6.385,6.299,6.345c6.876-0.063,13.753,0.049,20.629,0.113c0.289,0.003,1.739,0.534,1.739,0.534v6.407 c0,0-14.692-0.032-21.682,0.01c-5.652,0.034-7.334,1.395-6.872,7.119c0.694,8.601-1.289,15.249-8.006,21.638 c-8.605,8.185-13.036,19.34-15.463,31.089c-1.309,6.335-2.096,6.555-6.889,2.398c-6.287-5.453-15.195-5.103-20.871,0.819 c-5.657,5.902-5.624,15.003,0.076,20.896c5.702,5.895,14.51,6.153,20.855,0.613c1.117-0.975,2.238-1.945,4.238-3.682 c1.129,2.807,2.274,4.924,2.843,7.186c4.769,18.938,15.137,33.728,31.864,44.051c1.736,1.072,3.27,3.377,3.775,5.392 c3.397,13.548,7.363,26.834,14.685,38.904c0.804,1.325,1.03,3.177,1.033,4.786c0.118,64.926,0.18,129.852,0.239,194.778 c0.001,0.981-0.122,1.963-0.184,2.894c-5.249,0.709-6.974-0.588-7.13-5.358c-0.109-3.352-0.003-6.71-0.024-10.065 c-0.036-5.705-1.357-7.092-7.019-7.099c-21.978-0.026-43.956-0.012-65.933-0.011c-7.046,0-14.094,0.1-21.138-0.026 c-4.635-0.083-6.728,2.003-6.589,6.633c0.109,3.639,0.121,7.278-0.002,10.917c-0.157,4.646,1.947,6.703,6.575,6.67 c12.75-0.09,25.501-0.045,38.251-0.028c6.305,0.008,7.513,1.253,7.533,7.599c0.038,11.525,0.038,11.526-11.68,11.525 c-11.24-0.001-22.481-0.03-33.722,0.007c-5.418,0.018-6.914,1.437-6.931,6.666c-0.053,16.568-1.437,15.572,15.235,15.484 c10.066-0.053,20.132-0.038,30.198,0.002c5.373,0.021,6.796,1.457,6.905,6.697c0.259,12.419,0.259,12.42-12.268,12.419 c-11.073,0-22.146-0.028-33.218,0.011c-5.319,0.019-6.822,1.501-6.857,6.738c-0.102,15.018-1.068,14.544,14.31,14.408 c10.401-0.092,20.803-0.047,31.205-0.005c5.279,0.022,6.729,1.522,6.828,6.773c0.234,12.342,0.234,12.342-12.345,12.342 c-11.073,0-22.146-0.031-33.218,0.012c-5.25,0.02-6.76,1.539-6.779,6.814c-0.06,16.24-1.382,15.39,14.882,15.343 c26.004-0.075,52.009-0.015,78.013-0.024c6.592-0.002,7.763-1.211,7.767-7.876c0.001-2.349-0.056-4.699,0.01-7.046 c0.144-5.087,1.794-6.38,6.391-5.865c1.57,11.962,2.907,23.747,4.765,35.449c0.647,4.073,1.998,8.292,4.104,11.797 c1.828,3.041,5.159,7.119,7.859,7.143c2.656,0.024,6.805-4.019,7.763-7.073c3.09-9.85,6.148-19.959,7.106-30.167 c1.295-13.794,0.763-27.772,0.787-41.671c0.158-91.433,0.238-182.866,0.46-274.299c0.006-2.499,0.844-5.29,2.131-7.444 c7.151-11.972,11.314-25.021,14.283-38.502c0.767-3.483,2.275-5.895,5.318-7.958c14.472-9.809,23.801-23.321,28.184-40.279 c0.711-2.753,1.981-5.361,3.281-8.798c2.096,1.947,3.257,3.114,4.508,4.173c6.274,5.312,15.319,4.747,20.867-1.276 c5.371-5.83,5.28-14.718-0.209-20.541c-5.593-5.933-14.657-6.313-20.861-0.875c-4.91,4.304-5.502,4.183-6.871-2.32 c-2.843-13.501-9.129-25.091-18.636-35.051c-1.059-1.109-1.624-3.064-1.703-4.662c-0.225-4.519-0.177-9.058-0.049-13.584 c0.13-4.584-1.863-6.712-6.52-6.641c-7.688,0.117-23.46,0.032-23.46,0.032v-7.081c0,0,15.513,0.035,23.187-0.012 c5.264-0.032,6.699-1.51,6.757-6.834c0.042-3.858,0.047-7.718-0.001-11.576c-0.066-5.278-1.476-6.669-6.885-6.701 c-7.529-0.044-22.059-0.011-22.059-0.011v-6.073c0,0,14.421,0.036,22.088-0.012c5.373-0.034,6.792-1.451,6.855-6.73 c0.048-4.026-0.055-8.054,0.028-12.079c0.089-4.361-1.944-6.374-6.308-6.332c-7.707,0.073-23.662,0.021-23.662,0.021 s0-18.743,0-28.6c29.397-8.459,46.462-28.621,52.535-59.535c5.681,5.182,10.784,9.539,17.649,7.382 c3.324-1.045,6.767-3.214,9.025-5.845c4.929-5.744,3.921-14.326-1.559-19.637c-6.511-6.312-13.714-5.558-25.117,3.388 c-5.85-30.371-22.706-50.809-52.896-59.482c0-11.328-1.021-22.855,0.356-34.088c0.927-7.564,7.385-13.291,13.943-17.092 c17.546-10.17,29.776-24.263,35.419-43.925c0.495-1.726,2.182-3.403,3.745-4.482c12.023-8.304,22.113-18.494,30.667-30.315 c1.255-1.734,3.402-3.24,5.446-3.923c25.095-8.384,41.101-25.168,47.682-50.873c0.553-2.159,1.517-4.212,2.638-7.26 c1.992,1.814,3.143,2.911,4.345,3.949c6.307,5.446,15.194,5.081,20.928-0.844C371.579,191.607,371.538,182.33,365.84,176.489z M253.55,107.072c4.157,3.613,7.747,6.732,11.337,9.852c-0.326,0.501-0.652,1.003-0.979,1.504 c-4.182,0.798-8.365,1.596-13.163,2.512C251.718,116.132,252.577,111.882,253.55,107.072z M185.289,45.98c29.823,0,54,24.177,54,54 c0,29.823-24.177,54-54,54s-54-24.177-54-54C131.289,70.157,155.466,45.98,185.289,45.98z M164.151,165.773 c13.581,4.334,27.363,4.22,41.777,0.199c-4.474,14.48-3.87,28.139,0.027,42.429c-14.232-4.098-27.748-4.399-41.531-0.444 c0.777-7.312,2.093-14.066,2.044-20.809C166.419,180.244,165.032,173.349,164.151,165.773z M116.538,107.809 c1.209,5.322,2.145,9.436,3.252,14.311c-4.762-1.06-8.731-1.943-13.791-3.07C109.65,115.157,112.775,111.823,116.538,107.809z M98.289,239.98c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54s54,24.177,54,54 C152.289,215.804,128.113,239.98,98.289,239.98z M115.949,265.97c-3.407-3.594-6.205-6.546-9.77-10.308 c5.012-1.059,8.587-1.815,12.604-2.664C117.803,257.484,116.976,261.266,115.949,265.97z M239.289,683.98c0,29.823-24.177,54-54,54 s-54-24.177-54-54s24.177-54,54-54S239.289,654.157,239.289,683.98z M239.289,452.98c0,29.823-24.177,54-54,54s-54-24.177-54-54 s24.177-54,54-54S239.289,423.157,239.289,452.98z M185.289,327.98c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54 s54,24.177,54,54C239.289,303.804,215.113,327.98,185.289,327.98z M253.079,268.69c-1.271-6.405-2.241-11.297-3.279-16.525 c5.356,1.047,10.057,1.966,16.634,3.251C261.644,260.177,257.764,264.034,253.079,268.69z M272.289,239.98 c-29.823,0-54-24.177-54-54c0-29.823,24.177-54,54-54c29.823,0,54,24.177,54,54C326.289,215.804,302.113,239.98,272.289,239.98z", - clocks: { - size: 108, - 0: { x: 185.128, y: 100 }, - 1: { x: 98.128, y: 186 }, - 2: { x: 272.128, y: 186 }, - 3: { x: 185.128, y: 274 }, - 4: { x: 185.128, y: 453 }, - 5: { x: 185.128, y: 684 } - } - } -}; -export const SVGDATA = { - teeth: { - tall: { - viewBox: "0 0 512 1540", - paths: { - frame: "M0,0v1540l512-244.2V0H0z M451,1263.5l-390,186V61h390V1263.5z", - half: "M0,0v748l512-244.2V0H0z", - full: "M0,0v1540l512-244.2V0H0z" - } - }, - med: { - viewBox: "0 0 512 1540", - paths: { - frame: "M0,0v1388l512-395.6V0H0z M458,965.7L54,1278V53h404V965.7z", - full: "M0,0v1540l512-244.2V0H0z" - } - }, - short: { - viewBox: "0 0 512 1540", - paths: { - frame: "M0,0v991l511.4-247L512,0H0z M470.5,715.2L41,922.6V40h430L470.5,715.2z", - full: "M0,0v991l511.4-247L512,0H0z" - } - } - }, - armor: { - viewBox: "0 0 512 512", - paths: { - heavy: "M157.5,80.7c-20.6,13.7-46,22.5-69.4,26c6.8,48.9,26.1,84.1,46,97.8 c10.5,7.3,20.4,9,30.4,5.6c8.9-3.1,18.6-11,27.8-25.6C165.3,154.3,160.6,113.5,157.5,80.7L157.5,80.7z M354.5,80.8 c-3.1,32.8-7.8,73.6-34.7,103.8c9.1,14.6,18.9,22.5,27.8,25.6c10,3.4,19.8,1.7,30.4-5.6c19.8-13.7,39.1-48.8,45.9-97.7 C399.3,103.7,376,95.5,354.5,80.8L354.5,80.8z M254.4,67.9c-37.1,0-69.8,8.3-89.6,21c1.2,6.5,2.6,13,4.2,19.3 c19.2-8.2,50.3-16.7,85.4-16.7c35.2,0,66.3,8.5,85.4,16.7c1.7-6.3,3.1-12.8,4.2-19.3C324.2,76.2,291.5,67.9,254.4,67.9z M64.9,127.9l-47.7,45.5c29.8,37.2,63,56.8,86.5,58.7c1.1,0.1,2.3,0.1,3.3,0.2c1.8-7.6,4-15.1,6.5-22.3 C91.7,194.9,74.4,166.1,64.9,127.9L64.9,127.9z M447.1,127.9c-9.6,38.3-26.9,67-48.6,82c0,0-0.1,0-0.1,0.1 c2.5,7.3,4.7,14.7,6.5,22.3c1.1,0,2.2-0.1,3.4-0.2c23.4-1.9,56.8-21.5,86.5-58.7L447.1,127.9L447.1,127.9z M176,139.4 c5.7,12.2,13.1,23.3,22.9,32.8l6.4,6.2l-4.3,7.8c-2.3,4.1-4.6,8-7,11.7c40.8,15,85,14,124-0.2c-2.4-3.6-4.6-7.4-6.9-11.4l-4.3-7.8 l6.4-6.2c9.4-9.1,16.7-19.9,22.3-31.5C280.8,153.8,228.5,151.3,176,139.4L176,139.4z M401.7,243.6c0,0-3.7,38.1-22.9,76.1 l-121.7-32.7l-1.8-0.4l-1.8,0.4l-120.3,32.7c-19-38-22.7-76.1-22.7-76.1s12,3.8,19.5-18.7c10.7,3.2,22,3.3,32.8-0.4 c9.2-3.2,17.8-8.8,25.8-16.9c21.6,8.9,44.2,13.1,66.7,13.1c22.7,0,45.6-4.2,67.4-13.1c8,8,16.8,13.7,26.1,16.9 c10.9,3.7,22.3,3.6,33.1,0.4C389.6,247.4,401.7,243.6,401.7,243.6z M486.1,210.7c-25.4,24.2-52.1,38-76.2,40c-0.4,0-0.9,0-1.3,0.1 c1.2,8.1,2,16.2,2.3,24.4c22.8,3.8,54.7,0.1,90-14.3L486.1,210.7L486.1,210.7z M25.9,210.8l-14.8,50.1c35.3,14.4,67.2,18.1,90,14.3 c0.3-8.2,1.1-16.3,2.3-24.4c-0.4,0-0.9,0-1.3-0.1C78,248.7,51.3,234.9,25.9,210.8L25.9,210.8z M256,305.2l-114.8,28.1 c1.9,7.7,10.1,17.6,15.4,23.8c31.8-7.3,59.3-11.4,94.7-11.6c2.6,0,5.3,0,7.9,0c38.2,0.3,64.9,4.3,95.9,11.6 c5.1-6.2,15.2-15.8,16.8-23.6L256,305.2L256,305.2z M254.1,347.8l-79.3,22.1c5.8,4.8,16,8.5,23.2,13.3c18-5,33.5-7.8,53.5-7.9 c1.5,0,3,0,4.5,0c21.6,0.2,36.6,3,54.1,7.9c9.9-1.8,16.8-6.8,25.5-12.3L254.1,347.8L254.1,347.8z M373.3,377.7 c-68.3,55.6-166.9,55.7-235.3,0.3l-1.8,35.9c4.7,7.9,18.3,17,38,23c21,6.4,48,9.9,75.6,10.2c27.6,0.3,55.8-2.6,79.4-8.7 c21.6-5.6,39.3-14.2,48.8-23.9L373.3,377.7L373.3,377.7z", - light: "M254.9,88c-23.1,0-44.1,2.8-59.8,8.8c-7.9,3-14.5,6.8-19.5,11.9c-5,5.1-8.4,12.1-8.4,19.9 c0,3.2,0.5,6.2,1.5,9.1c2,37.1-20.9,83.9-46,107.5c5.9,35.9,19.4,72.7,39.6,106.3c23.8,23,54.6,35.4,85.9,37.1v-24 c-9.6-0.1-19-0.5-26.5-1.1l0.8-13.2c7.1,0.6,16.2,1,25.7,1.1v-28.3c-9.1,0.4-17.9,1.8-24.4,4.2l-3.3-12.7 c8.1-2.9,17.8-4.6,27.7-5.1v-23.8c-2.9,0.2-5.8,0.5-8.7,1c-17.2,1-31.8,3.6-45.2,7.5l-0.1-0.2c16.7-14.8,38.1-22.2,59.6-22.2 c21.4,0,42.9,7.4,59.6,22.2l-0.1,0.1c-13.4-3.9-28.1-6.5-45.4-7.5c-2.8-0.5-5.7-0.8-8.5-1v23.8c10,0.5,19.7,2.1,27.7,5.1l-3.3,12.7 c-6.6-2.4-15.4-3.8-24.5-4.2v28.3c9.4-0.1,18.6-0.4,25.7-1.1l0.8,13.2c-7.5,0.7-16.9,1-26.5,1.1v24.1c32.4-0.8,64.6-13,89.4-36.5 c21.1-33.6,34.9-69.9,40.8-105.3c-26.2-23.2-50.7-72.5-47.8-110.7c0.7-2.5,1-5,1-7.7c0-7.8-3.4-14.8-8.4-19.9 c-5-5.1-11.7-8.9-19.6-11.9C298.9,90.8,278,88,254.9,88L254.9,88z M254.9,101.3c22.3,0,42.5,2.9,56.4,8.2c7,2.7,12.4,6,15.7,9.3 c3.3,3.4,4.5,6.3,4.5,9.9c0,1.8-0.3,3.6-1.1,5.5c-21.9-11.9-49.3-17.9-76.7-17.9c-26.6,0-53.2,5.6-74.7,16.8 c-0.5-1.5-0.7-2.9-0.7-4.4c0-3.5,1.2-6.5,4.5-9.9c3.3-3.4,8.7-6.7,15.7-9.3C212.4,104.1,232.6,101.3,254.9,101.3L254.9,101.3z M253.7,130c24.6,0,49.2,4.8,68.6,14.3c-3.1,2.6-6.9,5.1-11.4,7.3c-13.9,7-33.9,11.5-56,11.5s-42-4.5-56-11.5 c-4.9-2.4-9-5.2-12.2-8C205.8,134.5,229.7,130,253.7,130z M232.3,174.9c3.7,0.5,7.5,0.9,11.4,1.2c0.5,3.6,1,7.5,1.6,11.8 c1.6,13,3.3,27.9,3.3,37.5c0,10.8-3.5,20.6-9.5,28.1c-6.1,7.5-14.5,13-24.6,16.5c-11.2,3.9-24.5,5.6-39.3,4.8 c-14.2-2.5-25.1-9.3-35.7-19.6c29.1,8.3,54.5,8.2,71.9,2.1c8.7-3.1,15.4-7.6,19.7-13c4.3-5.4,6.5-11.4,6.5-18.9 c0-7.7-1.6-22.8-3.1-35.6C233.6,184.1,232.9,179,232.3,174.9L232.3,174.9z M275,175.2c-0.6,4-1.3,9-2,14.6 c-1.6,12.7-3.1,27.9-3.1,35.6c0,7.5,2.1,13.6,6.5,18.9c4.3,5.4,11,9.9,19.7,13c17.3,6.1,42.6,6.2,71.6-2.1 c-10.6,10.3-21.5,17.1-35.7,19.6c-14.8,0.8-28-0.9-39.1-4.8c-10.1-3.5-18.5-9-24.6-16.5s-9.5-17.3-9.5-28.1 c0-9.7,1.7-24.6,3.3-37.5c0.5-4.3,1.1-8.2,1.5-11.7C267.4,176,271.2,175.7,275,175.2L275,175.2z M347.1,370.2 c-52.9,43.1-129.3,43.2-182.3,0.3l-1.4,27.8c3.6,6.1,14.2,13.2,29.4,17.8c16.3,4.9,37.2,7.7,58.5,7.9c21.4,0.2,43.2-2,61.5-6.7 c16.8-4.3,30.4-11,37.8-18.5L347.1,370.2L347.1,370.2z", - special: "M256,14.2c-65.6,98.3-131.1,90.2-196.7,106.5c0,262.3,65.6,327.8,196.7,377 c131.1-49.2,196.7-114.7,196.7-377C387.1,104.4,321.6,112.6,256,14.2z M256,47c5.1,0,9.2,4.1,9.2,9.2s-4.1,9.2-9.2,9.2 s-9.2-4.1-9.2-9.2S250.9,47,256,47z M70.6,138.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2s-4.1,9.2-9.2,9.2S70.6,143.3,70.6,138.2z M92.1,301.1c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2C101.3,296.9,97.2,301.1,92.1,301.1z M157.7,432.2 c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2C166.9,428.1,162.7,432.2,157.7,432.2z M256,483.4 c-5.1,0-9.2-4.1-9.2-9.2s4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2S261.1,483.4,256,483.4z M354.3,432.2c-5.1,0-9.2-4.1-9.2-9.2 c0-5.1,4.1-9.2,9.2-9.2c5.1,0,9.2,4.1,9.2,9.2C363.6,428.1,359.4,432.2,354.3,432.2z M314.4,426.7c-15.8,11.1-33.7,18.7-51.1,26.8 c-6.7,4.7-14-0.5-20.7-2.5c-44.7-18.3-86.5-49.8-107.6-94.5c-29.8-63.5-33.8-135-36.7-204.3c58.8-9,115.3-28.5,156.2-72.1l1.9-2.1 c4.5,5,9.3,9.8,14.2,14.5c35.8,36.3,85,47,133.9,57.8c2.8,1.2,6.8,0.5,9.1,2c-2.7,66.4-5.7,134.9-33.1,196.4 C367.3,380.9,343.2,407.7,314.4,426.7z M419.9,301.1c-5.1,0-9.2-4.1-9.2-9.2c0-5.1,4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2 C429.1,296.9,425,301.1,419.9,301.1z M432.2,147.4c-5.1,0-9.2-4.1-9.2-9.2s4.1-9.2,9.2-9.2s9.2,4.1,9.2,9.2 S437.3,147.4,432.2,147.4z M301.1,154.9c0.2,23.3,0.3,46.6,0.5,69.9c0,1,0.4,2.2,0.9,3.1c4.9,8.4,9.8,16.9,15,25.1 c1.6,2.6,0.8,5.1,0.6,7.6c-0.7,9.5-1.7,19-2.6,28.5c-1,10.5-2,21-3,31.6c-0.8,9-1.6,17.9-2.4,26.9c-0.8,9-1.7,17.9-2.5,26.9 c-0.7,7.3-1.3,14.6-2,22c-0.1,1.2-0.6,2.7-1.4,3.6c-12,12-24.1,23.9-36.2,35.9c-0.2,0.2-0.5,0.5-1.1,1c0-1.1,0-1.8,0-2.5 c0.1-66.5,0.3-133,0.5-199.5c0-1.5,0.8-3.2,1.7-4.4c2.2-2.9,2.8-6,2.8-9.6c0-28.5,0.1-57.1,0.2-85.6c0-0.7,0-1.5,0-2.5 c0.8,0,1.5-0.1,2.3-0.1c13.9,0.1,27.8,0.1,41.7,0.1c1.2,0,1.9,0.3,2.3,1.5c0.8,2.2,1.7,4.3,2.7,6.6c-6.2,3.9-12.2,7.6-18.2,11.3 C301.6,152.6,301.1,153.4,301.1,154.9z M245.2,433.7c0,0.9,0,1.7,0,2.6c-0.2,0.1-0.4,0.2-0.6,0.3c-1.4-1.5-2.8-3.1-4.3-4.5 c-10.7-10.6-21.5-21.2-32.2-31.9c-0.9-0.9-1.6-2.5-1.7-3.9c-1-9.2-1.8-18.4-2.6-27.5c-0.7-7.2-1.3-14.3-2-21.5 c-0.8-9.2-1.7-18.4-2.6-27.5c-0.7-7.1-1.3-14.2-1.9-21.3c-0.9-9.3-1.7-18.5-2.6-27.8c-0.5-4.9-1-9.9-1.3-14.8 c-0.1-0.7,0.4-1.6,0.8-2.2c5.1-8.6,10.2-17.1,15.2-25.7c0.5-0.9,0.9-2.1,0.9-3.1c0.2-23.2,0.3-46.4,0.5-69.6c0-1.6-0.5-2.5-1.9-3.4 c-6-3.6-11.9-7.3-18-11.2c1-2.5,2-4.9,3.1-7.4c0.2-0.3,0.8-0.6,1.2-0.6c14.6-0.1,29.3-0.1,43.9-0.1c0.1,0,0.3,0.1,0.6,0.3 c0,0.7,0.1,1.5,0.1,2.3c0.1,29.2,0.2,58.4,0.3,87.7c0,2.1,0.3,4,1.7,5.6c2.5,2.9,3,6.2,3,10C244.9,303.4,245.1,368.5,245.2,433.7z", - specialBg: "M316.9,432.4c-16.5,11.6-35,19.4-53.1,27.8c-7,4.9-14.6-0.5-21.6-2.6 c-46.5-19-90-51.8-111.9-98.3c-31-66.1-35.1-140.5-38.2-212.4c61.2-9.4,119.9-29.6,162.4-75l2-2.1c4.7,5.2,9.6,10.2,14.7,15.1 c37.2,37.7,88.4,48.9,139.2,60.1c2.9,1.3,7.1,0.5,9.4,2.1c-2.9,69.1-5.9,140.3-34.4,204.3C372,384.8,346.8,412.7,316.9,432.4z" - } - }, - [ConsequenceType.ReducedEffect]: { - viewBox: "0 0 512 512", - paths: { - main: "M260.7,487.55C133,487.55,28.39,382.92,28.39,255.23S133,24.45,260.7,24.45A230.5,230.5,0,0,1,491.49,255.23c0,127.69-103.1,232.32-230.78,232.32Zm-1.06-82L377,287.58l-23.94-25.1-65.41,37.94V128a167.28,167.28,0,0,1,103.6,268.91,193.71,193.71,0,0,0,61.22-141.63A191.18,191.18,0,0,0,260.7,63.45c-106.39,0-193.31,85.39-193.31,191.78A192.9,192.9,0,0,0,128,395.55,167.3,167.3,0,0,1,231,128.2V296.92l-62.5-35.62-25.09,26.28Z" - }, - classes: { - main: "fill-linear" - } - }, - [ConsequenceType.ComplicationMinor]: { - viewBox: "0 0 512 512", - paths: { - main: "M345.58,263.18l39.74-8.31,73.29-15.3,22.83-4.79,2.81-.58,9.56-2V213.1l-6.33,1.33-79.55,16.62-26.49,5.54-55.93,11.69c-13-11.18-20-24.73-27.16-39.89l-1.67-3.53,34.18-46.76,57.87-79.18,3-4.1,41.19-56.33H409.77L375.26,65.7l-4.09,5.59-60.51,82.78-32.91,45c-15.06-6.36-26.14-17.76-38.57-30.33l-2.34-2.37-4.59-30.28L216.72,33.5l-1-6.47-1.29-8.54h-18.9l2.84,18.75-.11-4.41,15.2,104.1,5.59,37c-11.18,7.5-24.44,12.15-39,15.49l-22.9-28.89L93.8,80.58,44.58,18.49H20.74l53,66.83,4.18,5.26,66.54,84,19.15,24.16-.08.7c-1.93,17.37-8.88,29.63-16.65,43.07L115.3,234.2,25.49,210.61,23.08,210l-4.31-1.14v19.32l2.56.67L112,252.65l27.61,7.25.56,1.4c6.1,15.15,5.39,31.77,2.9,49.71l-30.31,14.2L23.15,367.14l-4.38,2.06v20.62l9.18-4.3,67.92-31.77,17.13-8,28.92-13.54,1.52,1.53c5.85,5.86,10,10.29,11.22,20.75l-31.14,31.3L56.27,453.39l-37.5,37.69v2.43h24l20.91-21h0l77.94-78.36,24.11-24.24,1-.23c23.75-5.79,59.86-6.75,80.11-6.78,4,0,6.81,0,9.35.08l10.4,32.29L293,477.73l1.54,4.78,3.54,11h19.63l-5.19-16.14-2.24-6.95-25.77-80.06-11-34.32c3.55-3.17,8.73-7.63,15-12.42,11.42-8.73,26.21-17.7,35.68-19.62l4.24-.87,25.37,10L442,368.08l4.18,1.66,47.6,18.83V368.48l-37.78-15-5.21-2-82.75-32.74-36.59-14.48c0-13.16,1.4-22.85,9.12-33.93Zm-61.35-41.29c5.12,10.41,11.11,21.1,19.66,30.91l-31.15,6.52a39.69,39.69,0,0,0-6.93-12.22Zm-62.13-28,6,39.74a39.25,39.25,0,0,0-10.25,3.48l-25.18-31.77A132,132,0,0,0,222.1,193.9Zm-43.39,23.92,24.91,31.43a38.6,38.6,0,0,0-4.08,7.07l-33.92-8.92C170.58,238.65,175.45,229.15,178.71,217.82Zm17.49,56.93a39.32,39.32,0,0,0,2.08,10.45L163,301.7c1.05-11.91.92-24.05-2-36.2ZM160,324.27l.09-.55,47.15-22.07h0L169.55,339.5A54.79,54.79,0,0,0,160,324.27Zm28.37,22.85,36.61-36.8a39.43,39.43,0,0,0,10.6,1.45,35.54,35.54,0,0,0,4-.2L250,344.11C236.7,344,212.41,344.2,188.33,347.12ZM250.78,236a35.39,35.39,0,0,0-3.61-1.32L241.46,197a109.45,109.45,0,0,0,25.15,17.38Zm26.37,92.76c-3.9,3-7.1,5.61-9.88,8l-10.1-31.4a39.81,39.81,0,0,0,8.16-7.16l36.5,14.44A169,169,0,0,0,277.15,328.76Zm36-31.76L273.9,281.47c.26-1.14.47-2.29.64-3.44l45.58-9.53C315.5,277.93,313.74,287.39,313.17,297Z" - }, - classes: { - main: "fill-radial" - } - }, - [ConsequenceType.ComplicationMajor]: { - viewBox: "0 0 512 512", - paths: { - main: "M458.26,239.57l22.83-4.78,2.81-.59,9.56-2v-19.1l-6.33,1.33-79.55,16.62-26.49,5.54-55.93,11.69c-13-11.18-20-24.73-27.16-39.89l-1.67-3.53,34.18-46.76.58-.79c9.76,28.37,24.84,58.48,51.36,78.35l24.6-5,1.83-.54L407.07,229c-37.27-19.15-50.45-51.64-61.94-88.83l-.44-1.43,43.69-59.78,3-4.1,41.19-56.34H409.42L374.91,65.7l-4.09,5.6-46.71,63.9c-34.73.23-70.42-3-95.76-22.5l-12-79.19-1-6.47-1.29-8.55H195.2L198,37.24l-.11-4.4,12.18,83.44c-17,16.89-39.15,28.73-67.39,26.48L93.45,80.59,44.23,18.49H20.39l53,66.83,4.18,5.27L129,155.51c-3.16,27.24-16.63,53.33-32.88,73.74l-71-18.63L22.73,210l-4.31-1.13v19.32l2.56.67,71.38,18.74c8.29,26.73,6.3,57.28,2.12,86L22.8,367.15l-4.38,2.05v20.63l9.18-4.3,67.92-31.78,1.09-.51A190.52,190.52,0,0,1,104.47,382c1.33,7.25,2.58,14.68,3.19,19.36l-51.74,52-37.5,37.69v2.43H42.37l20.91-21h0l58.27-58.57c10.1-.83,33.7-2.28,59.06-3.17,7.9-.28,16.15-.45,24.46-.47,23.47-.05,49.4,1.12,67.34,4.45l20.27,63,1.54,4.79,3.54,11h19.63l-5.19-16.14L310,470.43,291.2,412.17c23.43-27.05,48.62-54.87,86-69.58l64.45,25.5,4.18,1.65,47.6,18.84v-20.1l-37.78-15-5.21-2.06-62.74-24.82c-3.11-24.21,8.64-50.64,20.2-76.57ZM266.92,336.72l-10.1-31.4a39.76,39.76,0,0,0,8.16-7.15l36.5,14.44a169,169,0,0,0-24.68,16.16C272.9,331.76,269.7,334.38,266.92,336.72Zm-71.07-62a39.17,39.17,0,0,0,2.08,10.44l-35.27,16.5c1.05-11.9.92-24-2-36.19Zm-30.58-27.35c5-8.75,9.83-18.25,13.09-29.59l24.91,31.43a39.28,39.28,0,0,0-4.08,7.07Zm41.58,54.25h0L169.2,339.51a54.79,54.79,0,0,0-9.59-15.23l.09-.56Zm17.74,8.67a39.43,39.43,0,0,0,10.6,1.45,38,38,0,0,0,4-.2l10.47,32.54c-13.32-.16-37.61.08-61.69,3Zm22.23-75.64L241.11,197a109.17,109.17,0,0,0,25.15,17.39L250.43,236A37.88,37.88,0,0,0,246.82,234.69Zm26.73,46.78c.26-1.13.47-2.28.64-3.43l45.58-9.53c-4.62,9.43-6.38,18.89-6.95,28.5Zm30-28.66-31.15,6.51a39.53,39.53,0,0,0-6.93-12.21l18.42-25.21C289,232.31,295,243,303.54,252.81ZM232.78,136.13c23.18,13.26,50.47,17.92,77,18.68l-32.37,44.3c-15.06-6.37-26.14-17.76-38.57-30.33l-2.34-2.37-4.59-30.28,0-.12Zm-5,97.52a39.25,39.25,0,0,0-10.25,3.48l-25.18-31.77a132,132,0,0,0,29.42-11.45Zm-14.52-96,5.48,36.25c-11.18,7.5-24.44,12.15-39.05,15.49l-22.46-28.34C178.25,159.21,198.58,149.44,213.24,137.65Zm-69.67,36.28.5.63,19.15,24.15-.08.71c-1.93,17.37-8.88,29.63-16.65,43.06L115,234.2l-.07,0C127,217.56,138.38,195.1,143.57,173.93ZM123.4,385.56c-.42-2.17-1.06-4.9-1.43-6.92-1.84-10-4.7-23.39-8.85-33.12l28.45-13.32,1.52,1.53c5.85,5.87,10,10.3,11.22,20.75Zm15.89-125.65.56,1.4c6.1,15.14,5.39,31.77,2.9,49.71l-29,13.58c2.87-22.76,3.42-48.28-2.06-71.93h0Zm72.18,131.64h-6.55c-8.5.05-16.9.25-25,.53-15.57.55-28,1.33-37.85,2.07l.07-.07a7.94,7.94,0,0,1-.82-.06l24-24.11,1-.23c23.75-5.79,59.86-6.75,80.11-6.78,4,0,6.81,0,9.35.07l10.29,32C249.77,392.55,229.58,391.66,211.47,391.55Zm73.59-1.18-.71.53-.17-.53-11-34.32c3.55-3.17,8.73-7.63,15-12.42,11.42-8.73,26.21-17.7,35.68-19.63l4.24-.86,25.37,10C324.89,348,303.58,369.47,285.06,390.37ZM368.49,319l-.77-.31-36.59-14.48c0-13.15,1.4-22.84,9.12-33.92l5-7.14L385,254.88l.12,0C376.44,274.07,368.18,297,368.49,319Z" - }, - classes: { - main: "fill-radial" - } - }, - [ConsequenceType.ComplicationSerious]: { - viewBox: "0 0 512 512", - paths: { - main: "M21.42,17.34,78.56,89.45c-2.73,48.59-23.75,85.79-52.39,120l-6.72-1.76V227l2.56.67C37.36,272.78,31.1,318.54,23.83,366l-4.38,2.05v20.63l9.18-4.29c6.52,10.7,13.66,27,19.06,41.33,4.29,11.33,7.48,21,9.26,26.53l-37.5,37.69v2.43h24L72,463.67c9.27-.36,41.77-1.47,82.7-.75,46.74.83,102.61,4.3,139,13.67l5.08,15.78h19.63L311,469.28c35.94-41.51,71.91-80.52,131.73-102.34l51.78,20.49v-20.1l-43-17c-6.37-39.21,12.76-76.67,30.62-116.68l12.37-2.59V212l-6.33,1.32-5.45-2.8c-56.09-28.83-76.33-78-93.3-132.7L433.6,17.34H410.45l-38.6,52.81c-58.28,1.26-112.48-2.46-154.45-37.79l-2.27-15h-18.9l2.83,18.75c-27.13,29-57.56,48-104.58,43.36L45.26,17.34Zm199.92,41c40.6,26.3,88.49,30.89,136.75,30.63L325,134.32c-36.59.39-69.86-3-95.85-24.64l-7.76-51.33Zm-18.84.44,8.29,54.77c-17.81,18.62-37.29,30.18-68,26.86L109.72,98.68c38.59-.74,68.36-17.15,92.78-39.89ZM375.83,96.38c15.53,47,37.05,92.69,84.55,122.72l-51.77,10.82-.82-.42c-37.27-19.14-50.44-51.64-61.93-88.83l-.72-2.31,30.68-42ZM95.09,110.3l34.39,43.39c-2.52,29.59-15.41,52.66-33.14,74.21L45.93,214.67c23.72-29.78,42.64-63.39,49.16-104.37ZM232.93,135c23.94,13.69,51.05,17.4,78.41,17.94l-32.91,45c-15.06-6.36-26.14-17.75-38.57-30.32l-2.35-2.37L232.93,135Zm-18.77.81,5.59,36.95c-11.18,7.5-24.44,12.15-39.05,15.49l-22.9-28.89c22.71-1.4,41.09-10.68,56.36-23.55ZM331.54,157c9.74,29.15,23.14,58,50.58,78.49l-55.93,11.69c-13-11.18-20-24.74-27.16-39.89l-1.67-3.53ZM145.1,173.41l19.15,24.16-.08.71c-1.93,17.36-8.88,29.63-16.65,43.06L116,233.06c13.21-17.36,23.94-36.83,29.12-59.65Zm77.68,19.35,6,39.75A38.88,38.88,0,0,0,218.54,236l-25.18-31.77a132.49,132.49,0,0,0,29.42-11.45Zm19.36,3.05a109.17,109.17,0,0,0,25.15,17.39l-15.83,21.66c-1.18-.49-2.38-.94-3.61-1.32l-5.71-37.73Zm-62.75,20.86L204.3,248.1a39.37,39.37,0,0,0-4.08,7.07l-33.92-8.9c5-8.76,9.83-18.25,13.09-29.6Zm105.52,4.08c5.12,10.42,11.11,21.1,19.66,30.92l-31.15,6.5A39.64,39.64,0,0,0,266.49,246l18.42-25.21ZM43.14,233.26,92,246.09c9.23,28.21,5.8,57.08,1.2,87.45l-49.07,23c6-40.15,10.29-81.42-1-123.24Zm416.14,5.16c-14.93,32.63-30.11,66.73-27.43,104.13l-43.74-17.31c-3.6-25,8.78-49.44,20.72-76.28l50.45-10.54Zm-346.57,13.1,27.61,7.25.56,1.4c6.1,15.13,5.39,31.77,2.9,49.71l-30.32,14.18c3.22-23.51,5-47.81-.75-72.54ZM386,253.74c-9,19.81-17.8,40.8-17.25,63.84l-36.59-14.47c0-13.15,1.4-22.84,9.12-33.92l5-7.15,39.74-8.3ZM161.64,264.36l35.24,9.26A39.33,39.33,0,0,0,199,284.06l-35.27,16.5c1.05-11.9.92-24.05-2.05-36.2Zm159.16,3c-4.62,9.44-6.38,18.89-6.95,28.5l-39.27-15.54c.26-1.12.47-2.27.64-3.43l45.58-9.53ZM266,297l36.5,14.44a169,169,0,0,0-24.68,16.16c-3.9,3-7.1,5.6-9.88,7.94l-10.11-31.4A39.76,39.76,0,0,0,266,297Zm-58.12,3.48-37.66,37.86a54.85,54.85,0,0,0-9.59-15.24l.09-.55,47.15-22.07Zm17.73,8.67a39.43,39.43,0,0,0,10.6,1.46c1.35,0,2.69-.07,4-.2L250.7,343c-13.32-.16-37.62.07-61.7,3l36.61-36.81ZM329.1,322l25.36,10c-29.4,14.92-50.37,35.89-69.25,57.2l-11-34.32c3.55-3.18,8.73-7.63,15-12.43,11.42-8.73,26.21-17.7,35.68-19.63l4.24-.86Zm-186.5,9.07,1.52,1.52c5.85,5.88,10,10.31,11.22,20.75L124.2,384.64c-.35-2.27-.74-4.63-1.2-7.14-2-10.95-4.45-22.94-9.32-32.9l28.92-13.54Zm235.93,10.49,39.22,15.52c-49.42,22.5-82.92,56.68-113.45,91.47l-12.44-38.65c24.11-27.84,47.68-53.61,86.67-68.34Zm-282,11.06c3,6.84,6.22,18.17,8.07,28.26,1.58,8.61,2.5,16.08,3,20.45L71.72,437.4c-1.68-5-3.78-11-6.55-18.29-5.37-14.22-12-30-19.61-42.64l51-23.86Zm150.86,9.15c4,0,6.81,0,9.35.06l10.39,32.3c-26.25-4.15-58.63-4.19-87-3.18-15.58.55-28,1.32-37.86,2.06l24.11-24.24,1-.23C191,362.74,227.16,361.79,247.41,361.76Zm-42.19,47.39c24.92-.06,50.36,1.26,68.41,5.1L287.06,456c-38.71-8.23-89-11-132.09-11.74-27.22-.48-49.23-.19-63.87.17l30.8-31c7.77-.76,30.71-2.84,58.86-3.84,7.9-.28,16.15-.45,24.46-.47Z" - }, - classes: { - main: "fill-radial" - } - }, - [ConsequenceType.LostOpportunity]: { - viewBox: "0 0 512 512", - paths: { - main: "M373.33,52.76A234.57,234.57,0,0,0,52.77,138.67C-12,250.93,26.41,394.41,138.67,459.23s255.75,26.36,320.56-85.91S485.59,117.58,373.33,52.76Zm-211.87,367A189.1,189.1,0,0,1,81,184.37L327.62,431A188.73,188.73,0,0,1,161.46,419.76Zm211.18-14.87L107.14,139.38a187.3,187.3,0,0,1,32.24-32.29L404.89,372.6A187.71,187.71,0,0,1,372.64,404.89ZM431,327.6,184.41,81A189.12,189.12,0,0,1,431,327.6Z" - }, - classes: { - main: "fill-linear" - } - }, - [ConsequenceType.WorsePosition]: { - viewBox: "0 0 512 512", - paths: { - horizon: "M18.36,227.8v18.68h86.37a98.45,98.45,0,0,0-4.43-18.68Zm379.4,0a110.51,110.51,0,0,1,9.44,18.68h86.44V227.8H397.76Z", - boot: "M218.67,18.73a162.14,162.14,0,0,0-20,1.32C164,24.39,123.5,39.4,91.23,67.36L124.7,257.55l.35,10.12c42.26,15.79,100.82,24.55,152.87,24.25,27.19-.15,52.64-2.74,73-7.78s35.2-12.82,41.81-20.94l.44.35a113,113,0,0,0-6.53-17.06h.19a95.88,95.88,0,0,0-4.85-8.66c-.09-.14-.16-.3-.25-.44l-.31-.47c-21.46-34.89-63.5-55.87-124.28-29.37l-.16.06a215.37,215.37,0,0,0-34,20.19h-.81c11-15.72,23.26-28.12,35.91-37.28l1.12-11.16c-14.68-4-38.08-4.06-53.53-.09L201,161.14a130.33,130.33,0,0,1,30.34-3.84c1.5,0,3,0,4.5,0a117.66,117.66,0,0,1,25.25,3.12l3.19-32c-21.06-8.07-42.12-6.6-64.57-1.59l-4.06-18.25A170.07,170.07,0,0,1,231,104.17c1.72,0,3.44,0,5.16.07a107,107,0,0,1,30.06,5.12l3.16-31.47c-25.6-7.69-51-8.1-76.91-2.78l-3.78-18.28A188.53,188.53,0,0,1,221.52,53c1.14,0,2.29-.05,3.43-.06A167.36,167.36,0,0,1,271.23,59l.47-4.6c5-23.31-18.75-35.71-53-35.65ZM397.26,284.45c-10.84,8.13-25.26,13.7-41.87,17.82-22.37,5.54-49.07,8.18-77.38,8.34a526.46,526.46,0,0,1-65.09-3.75L225.36,329c80.16,9.44,141.5-1.19,172-21.78a113.13,113.13,0,0,0-.13-22.75ZM125.7,287.77l1,30.47,58.6,8.43,9.59-22.31c-24.55-3.82-48.21-9.37-69.19-16.59Z", - ice: "M92.61,309.3C82.3,312.37,74,315.76,68,319.36l-.21.12L37.58,334.2,18.36,322v22.16L32,352.8l4.41,2.81,4.72-2.31,22-10.72c11.71,9.8,40.46,18.23,79.4,23.87l-60,28.25,26.63,21L18.36,454.23v39H145.14L188.86,447l51,46.28h27.84L159.11,394.8l35.06-23c20,1.37,41.34,2.15,63.56,2.15,20.7,0,40.66-.67,59.44-1.87l39.06,24.69-66.9,35.71,62.28,60.75H475.52L385,440.64l51.32-39.78-71.5-33.28c45.88-6,79.18-15.67,89.81-27l18,6.43,21.06,22.57V342.17l-8.94-9.56L483.17,331l-2.15-.78L439.8,315.42a141.57,141.57,0,0,0-16.66-6c5.37,3.24,8.28,6.7,8.28,10.28,0,18.59-77.73,33.66-173.62,33.66S84.14,338.29,84.14,319.7c0-3.63,3-7.13,8.47-10.4Z" - }, - classes: { - horizon: "fill-dark", - boot: "fill-bright", - ice: "fill-radial" - } - }, - [ConsequenceType.InsightHarm1]: { - viewBox: "0 0 512 512", - paths: { - eye: "M406.09,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,409.07,204h45.2C435.64,222.23,417,244.72,406.09,282.69ZM494.83,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-89-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,82.64,223.9C74.76,216.85,66,208.81,57.89,200c-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C241.41-14.68,416.3,37.68,494.83,158.8Zm-29.17-.36C373.78,11.86,140.41,12.08,57.19,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C324.81,246.14,397.81,215.94,465.66,158.44Z", - iris: "M303.7,99.51a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Zm45.4-68.13a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Zm45.4-68.13a65,65,0,0,0-45-18h0a65.26,65.26,0,1,0,45,18Zm-45.4,68.13a23.4,23.4,0,1,1,23.39-23.41A23.42,23.42,0,0,1,258.3,167.64Z" - }, - classes: { - eye: "fill-dark", - iris: "fill-med" - } - }, - [ConsequenceType.InsightHarm2]: { - viewBox: "0 0 512 512", - paths: { - eye: "M305.51,89.71A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Zm54.8-82.26A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Zm54.8-82.26A78.5,78.5,0,0,0,251.22,68h0a78.81,78.81,0,1,0,54.29,21.71ZM250.71,172a28.25,28.25,0,1,1,28.23-28.27A28.28,28.28,0,0,1,250.71,172Z", - iris: "M398.59,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,401.57,204h45.2C428.14,222.23,409.46,244.72,398.59,282.69Zm-264-17.94A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86,11.79,18.34,22,39.48,27.42,60.27v50c-4.76,10.14-12.06,17.21-12.06,28.41,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-11.36-7.31-17.81-11.87-27V278.22C103,265.1,117.78,261.12,134.61,264.75ZM487.33,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-88.95-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C233.91-14.68,408.8,37.68,487.33,158.8Zm-29.17-.36C366.28,11.86,132.91,12.08,49.69,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C317.31,246.14,390.31,215.94,458.16,158.44Z" - }, - classes: { - eye: "fill-med", - iris: "fill-med" - } - }, - [ConsequenceType.InsightHarm3]: { - viewBox: "0 0 512 512", - paths: { - eye: "M398.31,282.69V352.6c4.19,8.54,8.53,16.73,8.53,27.56,0,13.24-8.75,22.78-18.09,22.78-9.13,0-18.69-10-18.69-23.94,0-12.22,5.1-20.64,9.56-29.59V289.63c-6.51-19.32-16.22-25.45-26.54-21.72V226.24A401.64,401.64,0,0,0,401.29,204h45.2C427.86,222.23,409.18,244.72,398.31,282.69Zm-264-17.94A239.65,239.65,0,0,1,74.86,223.9C67,216.85,58.19,208.81,50.11,200c11.79,18.34,22,39.48,27.42,60.27v50c-4.76,10.14-12.06,17.21-12.06,28.41,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-11.36-7.31-17.81-11.87-27V278.22C102.75,265.1,117.5,261.12,134.33,264.75Zm114.3,24.56a256.33,256.33,0,0,1-88.95-14,109.79,109.79,0,0,1,42.38,48.58v80.59c-6.36,10.47-13.62,16.95-13.62,28.87,0,17.89,11.76,24.5,23.93,24.5,11.91,0,21.6-5.66,21.6-24.5,0-9.3-7.44-16.63-13.22-31.06V324.1C227.16,309.18,237.5,294.45,248.63,289.31ZM487.05,158.8c-33,49.83-80.77,87.12-134,108.82a291.28,291.28,0,0,1-90,21.07q-7.2.51-14.42.62a256.33,256.33,0,0,1-88.95-14,239,239,0,0,1-25.35-10.52A239.65,239.65,0,0,1,74.86,223.9C67,216.85,58.19,208.81,50.11,200c-11.54-12.52-21.66-26.51-25.72-41.23,20.19-37.74,48.7-69.38,84.66-92.29C233.63-14.68,408.52,37.68,487.05,158.8Zm-29.17-.36C366,11.86,132.63,12.08,49.41,160.28l.46.39-.46.39a353,353,0,0,0,54.67,42.55c45.21,28.32,92.77,42.1,140.82,42.29h.22C317,246.14,390,215.94,457.88,158.44Z", - iris: "M314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25ZM314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25ZM314.46,80a91.84,91.84,0,0,0-63.52-25.39h0A92.2,92.2,0,1,0,314.46,80Zm-64.12,96.24a33.05,33.05,0,1,1,33-33.07A33.08,33.08,0,0,1,250.34,176.25Z" - }, - classes: { - eye: "fill-med", - iris: "fill-bright" - } - }, - [ConsequenceType.InsightHarm4]: { - viewBox: "0 0 512 512", - paths: { - eye: "M244,27.44c-46.86,0-93.53,12.25-134.7,39.08-36,22.91-64.47,54.55-84.66,92.29,4.06,14.72,14.18,28.71,25.72,41.23,8.08,8.77,16.87,16.81,24.75,23.86a239.65,239.65,0,0,0,59.47,40.85A239,239,0,0,0,160,275.27a256.33,256.33,0,0,0,88.95,14q7.22-.1,14.42-.62a291.28,291.28,0,0,0,90-21.07A299.94,299.94,0,0,0,430.12,222a286.46,286.46,0,0,0,57.21-63.16C434.75,77.71,339,27.44,244,27.44ZM245.4,245.9h-.22c-48.05-.19-95.61-14-140.82-42.29a353,353,0,0,1-54.67-42.55l.46-.39-.46-.39c83.22-148.2,316.59-148.42,408.47-1.84C390.31,215.94,317.31,246.14,245.4,245.9Zm17.93,42.79c7.16,3,14.11,11.57,20,28.08,3.54,9.85,6.71,22.54,9.33,38.58v74.84C287.27,440.69,281,449.64,281,462.5s10,22.19,21,22.19c10.74,0,22.18-9.73,22.18-23.34,0-14.45-7.09-23.42-12.81-34.57V342.22h-.22a223.26,223.26,0,0,1,7.48-25.45c9.57-26.37,22.57-44.47,34.73-48.86v-.29A291.28,291.28,0,0,1,263.33,288.69Zm-38.82,28.08c6.37-12.19,15.11-23.17,24.4-27.46a256.33,256.33,0,0,1-88.95-14,109.62,109.62,0,0,1,38.91,41.5q1.84,3.45,3.47,7.08v80.59c-6.36,10.47-13.62,16.95-13.62,28.87,0,17.89,11.76,24.5,23.93,24.5,11.91,0,21.6-5.66,21.6-24.5,0-9.3-7.44-16.63-13.22-31.06V324.1C222.09,321.64,223.26,319.18,224.51,316.77Zm-89.9-52A239.65,239.65,0,0,1,75.14,223.9c-7.88-7.05-16.67-15.09-24.75-23.86,11.79,18.34,22,39.48,27.42,60.27v50c-1.08,2.29-2.28,4.43-3.51,6.49-4.18,7.06-8.55,13.25-8.55,21.92,0,9.09,11.63,18.09,21,18.09,9.2,0,21.6-9.67,21.59-19.25,0-8.63-4.22-14.43-8.25-20.76a67,67,0,0,1-3.62-6.27V278.22C103,265.1,117.78,261.12,134.61,264.75Zm267-60.78a401.64,401.64,0,0,1-48.21,22.27v41.67c10.32-3.73,20,2.4,26.54,21.72v59.78c-4.46,8.95-9.56,17.37-9.56,29.59,0,13.94,9.56,23.94,18.69,23.94,9.34,0,18.09-9.54,18.09-22.78,0-10.83-4.34-19-8.53-27.56V282.69c7.59-26.52,19-45.48,31.53-60.73a225.7,225.7,0,0,1,16.65-18Z", - iris: "M326.5,67.65a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Zm76-114.06a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Zm76-114.06a108.84,108.84,0,0,0-75.28-30.08h0A109.22,109.22,0,1,0,326.5,67.65Zm-76,114.06a39.17,39.17,0,1,1,39.15-39.19A39.2,39.2,0,0,1,250.51,181.71Z" - }, - classes: { - eye: "fill-bright", - iris: "fill-med" - } - }, - [ConsequenceType.ProwessHarm1]: { - viewBox: "0 0 512 512", - paths: { - scar: "M443.44,434.53Q408.7,409.87,376,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L237.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L167.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q91.79,90.29,68.44,58.49q43,32.32,83.86,67.06L188.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L266,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L319.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q412.66,394.28,443.44,434.53Z" - }, - classes: { - scar: "fill-dark" - } - }, - [ConsequenceType.ProwessHarm2]: { - viewBox: "0 0 512 512", - paths: { - scarTissue: "M399,355.08c-15-32.31-18.67-65.87-6.23-94.7-47.19,58.41-76.14,4.41-4.09-70.72-101.67,62.7-147.78,31.47-14-88.26-103,54.66-182.49,69.22-130.93,15.19-37.19,10.63-58.21,5.21-76-2.43A643.42,643.42,0,0,0,55.28,58.49a789.14,789.14,0,0,0,47,77.56c7,18.27,3,38.71-31.46,63.44,124.85-33.45,88.52,47-9.36,104.92,166.21-61.68,207.52-47.41,100.64,78,84-61.07,150.14-44.57,122.89,31.29,31.63-24.51,57.9-29.74,78-20.87q43.39,30.7,90.32,59C436.25,418.27,418.25,386,399,355.08ZM352.11,362c-16.61-9.9-26.17.25-36.79,14,7.32-15.11,11.12-30.72,2.69-42.28l-3.7-3.19L277,301.11l-39.68,22,14.29-21.06c6.08-10.31,2.85-22.58-4.7-34.2q-13.6-13.56-26.78-27.46c-1.38-1-2.75-2-4.11-2.91l-55.23,15.68,18.09-21.41c8.78-14.64,0-34.57-8.18-46.3q-7-8.15-13.82-16.42l-36.3,6.06c15.32-6.06,26.08-18.6,14-33.28l-1.89-2.13c.69.72,1.31,1.42,1.89,2.13l1.71,1.94q-20.43-25.65-39.84-52.09,35.76,26.88,69.71,55.75l30.44-7.93-18.38,18.27q19.44,16.88,38.31,34.41l59.73-25.32L260.68,191l.25-.2c-17.91,22.9,15.6,71.52,38.24,65.19l26.52-14.71-20.6,30.37,30.65,43.82.66.74c11.34,10.39,26,1.42,35.79-12.07L355.9,339q26.72,31.78,52.3,65.24Q379.31,383.76,352.11,362Z" - }, - classes: { - scarTissue: "fill-med" - } - }, - [ConsequenceType.ProwessHarm3]: { - viewBox: "0 0 512 512", - paths: { - scar: "M447.44,434.53Q412.7,409.87,380,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L241.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L171.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q95.79,90.29,72.44,58.49q43,32.32,83.86,67.06L192.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L270,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L323.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q416.66,394.28,447.44,434.53Z", - scarTissue: "M436.33,375.37c-18.07-38.87-22.46-79.24-7.49-113.92-56.77,70.27-91.6,5.3-4.93-85.08C301.61,251.8,246.13,214.23,407,70.19,283.18,136,187.5,153.46,249.53,88.47c-44.75,12.79-70,6.27-91.47-2.93a773.7,773.7,0,0,0-135.18-67,949.58,949.58,0,0,0,56.49,93.31c8.39,22,3.6,46.57-37.84,76.32C191.72,148,148,244.71,30.26,314.42c200-74.2,249.65-57,121.08,93.78C252.42,334.73,332,354.59,299.17,445.84c38.06-29.48,69.66-35.77,93.87-25.1q52.21,36.94,108.66,70.93C481.19,451.39,459.54,412.52,436.33,375.37ZM380,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L241.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L171.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40L116,116.26c.83.86,1.57,1.71,2.27,2.56l2.06,2.33Q95.79,90.29,72.44,58.49q43,32.32,83.86,67.06L192.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L270,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L323.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42q32.13,38.23,62.91,78.49Q412.7,409.87,380,383.64Z" - }, - classes: { - scar: "fill-dark", - scarTissue: "fill-med" - } - }, - [ConsequenceType.ProwessHarm4]: { - viewBox: "0 0 512 512", - paths: { - scar: "M441.44,434.53Q406.7,409.87,374,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L235.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L165.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40l2.06,2.33Q89.79,90.29,66.44,58.49q43,32.32,83.86,67.06L186.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L264,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L317.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42Q410.66,394.28,441.44,434.53Z", - scarTissue: "M430.33,375.37c-18.07-38.87-22.46-79.24-7.49-113.92-56.77,70.27-91.6,5.3-4.93-85.08C295.61,251.8,240.13,214.23,401,70.19,277.18,136,181.5,153.46,243.53,88.47c-44.75,12.79-70,6.27-91.47-2.93a773.7,773.7,0,0,0-135.18-67,949.58,949.58,0,0,0,56.49,93.31c8.39,22,3.6,46.57-37.84,76.32C185.72,148,142,244.71,24.26,314.42c200-74.2,249.65-57,121.08,93.78C246.42,334.73,326,354.59,293.17,445.84c38.06-29.48,69.66-35.77,93.87-25.1q52.21,36.94,108.66,70.93C475.19,451.39,453.54,412.52,430.33,375.37ZM374,383.64c-20-11.91-31.49.3-44.26,16.86,8.8-18.17,13.38-36.95,3.24-50.86l-4.46-3.84-44.85-35.35L235.9,336.93l17.19-25.34c7.31-12.4,3.43-27.17-5.65-41.14q-16.37-16.32-32.22-33c-1.66-1.23-3.31-2.38-4.95-3.5l-66.44,18.87L165.59,227c10.57-17.62,0-41.59-9.84-55.7q-8.4-9.81-16.62-19.75l-43.67,7.29c18.43-7.3,31.37-22.38,16.85-40L110,116.26c.83.86,1.57,1.71,2.27,2.56l2.06,2.33Q89.79,90.29,66.44,58.49q43,32.32,83.86,67.06L186.92,116l-22.11,22q23.38,20.3,46.09,41.39l71.86-30.46L264,178l.3-.24c-21.55,27.54,18.77,86,46,78.42l31.91-17.7L317.4,275l36.88,52.71c.26.3.53.59.79.9,13.64,12.5,31.23,1.71,43.05-14.53l-19.59,42q32.13,38.23,62.91,78.49Q406.7,409.87,374,383.64Z", - welts: "M414.13,84.19a39.5,39.5,0,1,0,39.57,39.5,39.2,39.2,0,0,0-39.57-39.5ZM308.33,29.83A28.66,28.66,0,1,0,337,58.51a28.51,28.51,0,0,0-28.67-28.68ZM90.17,322.56a49.51,49.51,0,1,0,49.53,49.52A49.36,49.36,0,0,0,90.17,322.56Zm258-171.24A22.79,22.79,0,1,0,371,174.11a22.61,22.61,0,0,0-22.83-22.79ZM261.49,89.88a16.72,16.72,0,1,0,16.73,16.73,16.63,16.63,0,0,0-16.73-16.73ZM91.15,187.65a21.18,21.18,0,1,0,21.18,21.18,21,21,0,0,0-21.18-21.18Zm77.51,94.54a32.09,32.09,0,1,0,32.07,32.1,32,32,0,0,0-32.07-32.1ZM391.6,243.05a16.51,16.51,0,1,0,16.49,16.52,16.41,16.41,0,0,0-16.49-16.52ZM238.11,374.85a48.43,48.43,0,1,0,48.44,48.45A48.29,48.29,0,0,0,238.11,374.85Zm137,59.88A22.86,22.86,0,1,0,398,457.59a22.69,22.69,0,0,0-22.86-22.86Z" - }, - classes: { - scar: "fill-bright", - scarTissue: "fill-dark", - welts: "fill-bright" - } - }, - [ConsequenceType.ResolveHarm1]: { - viewBox: "0 0 512 512", - paths: { - spikes: "M256.09,19.1A237.5,237.5,0,0,0,197,27.22C70.63,61.08-4.36,191,29.5,317.31,62.59,440.8,187.39,515.21,311,486.92A132.35,132.35,0,0,1,279.74,475,207,207,0,0,1,122,417.49l-13.48-14.55L94.89,385.42a205.62,205.62,0,0,1-24-47.36l-7.2-17.33L60.71,296.5a205.83,205.83,0,0,1-.18-54.37l3-24.36,7.67-19.51a208.28,208.28,0,0,1,29.16-53.84l105,60.61-68.63-98a205.85,205.85,0,0,1,63.68-34.49l27.24-8.18,23.18-1.89q6.46-.48,12.89-.54a205.54,205.54,0,0,1,61.66,8.84l23.65,11,22,9.09A207.05,207.05,0,0,1,428.2,140.9l13.1,14.44L448.93,173a208,208,0,0,1,16.41,42.22,205.89,205.89,0,0,1,2.52,96.73,133,133,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C458.51,88.09,361.59,18.05,256.09,19.1Z", - eyeball: "M344.58,242.53a45.61,45.61,0,0,1,8.95,6.95c12.22,12.21,16.07,29.9,13.26,47.35S354.74,332,340,346.82s-32.54,24-50,26.83-35.13-1-47.35-13.26a48,48,0,0,1-13-24.74,114.74,114.74,0,1,0,114.92-93.12Z", - iris: "M316.24,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.56,9.39-39.76,21.59S249.91,303,247.81,316s.75,23.89,8,31.16S274,357.3,287,355.2s27.56-9.39,39.76-21.59,19.5-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.49,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.38,5.23-5.16-22,5.22-32.38c6.17-6.16,13.78-9.49,20.52-9.6Z" - }, - classes: { - spikes: "fill-dark", - eyeball: "fill-dark", - iris: "fill-med" - } - }, - [ConsequenceType.ResolveHarm2]: { - viewBox: "0 0 512 512", - paths: { - spikes: "M261.25,19.1a237.64,237.64,0,0,0-59.11,8.12C75.79,61.08.8,191,34.66,317.31,67.75,440.8,192.55,515.21,316.15,486.92A132.59,132.59,0,0,1,284.89,475a207,207,0,0,1-157.72-57.52l-11.44-12.15-15.68-19.92a205.62,205.62,0,0,1-24-47.36l-7.32-17.33L65.87,296.5a205.41,205.41,0,0,1-.18-54.37l91.84,19.32L76.38,198.26a208,208,0,0,1,29.16-53.84L259.93,252.78,141.87,107a205.79,205.79,0,0,1,63.67-34.49L263.45,141,256,62.45q6.46-.48,12.89-.54a205.54,205.54,0,0,1,61.66,8.84l22.84,8.32,22.83,11.78a207,207,0,0,1,57.17,50.05l13.41,16.85L454.08,173a207.52,207.52,0,0,1,18.93,139,132.67,132.67,0,0,1,7.75,38.31,235.92,235.92,0,0,0,11.48-155.53C463.67,88.09,366.74,18.05,261.25,19.1Z", - eyeball: "M349.74,242.53a45.61,45.61,0,0,1,8.95,6.95c12.21,12.21,16.07,29.9,13.26,47.35s-12.05,35.21-26.83,50-32.54,24-50,26.83-35.14-1-47.35-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z", - iris: "M321.4,254a50.42,50.42,0,0,0-7.08.66c-13,2.09-27.56,9.39-39.76,21.59S255.06,303,253,316s.75,23.89,8,31.16,18.16,10.12,31.16,8,27.56-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.46-5.45-13-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.85,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.87,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.52-9.6Z" - }, - classes: { - spikes: "fill-med", - eyeball: "fill-dark", - iris: "fill-bright" - } - }, - [ConsequenceType.ResolveHarm3]: { - viewBox: "0 0 512 512", - paths: { - spikes: "M261.31,19.1a237.51,237.51,0,0,0-59.11,8.12C75.84,61.08.86,191,34.71,317.31,67.8,440.8,192.61,515.21,316.2,486.92A132.35,132.35,0,0,1,285,475a207,207,0,0,1-157.72-57.52l-13.81-16.37-13.31-15.7a206,206,0,0,1-24.06-47.36l83.63-17.33L65.93,296.5a205.41,205.41,0,0,1-.18-54.37l164.66,47.21-154-91.08a208,208,0,0,1,29.15-53.84L260,252.78,141.92,107A205.85,205.85,0,0,1,205.6,72.52l95.49,158.21L256,62.45q6.47-.48,12.9-.54a205.43,205.43,0,0,1,61.65,8.84L353.08,169l23.17-78.14a206.76,206.76,0,0,1,57.16,50.05l13.08,22.41,7.65,9.67a207.52,207.52,0,0,1,18.93,139,132.33,132.33,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C463.73,88.09,366.8,18.05,261.31,19.1Z", - eyeball: "M349.79,242.53a45.38,45.38,0,0,1,9,6.95c12.21,12.21,16.07,29.9,13.25,47.35s-12,35.21-26.82,50-32.54,24-50,26.83-35.13-1-47.34-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z", - iris: "M321.45,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.55,9.39-39.75,21.59S255.12,303,253,316s.75,23.89,8,31.16,18.16,10.12,31.16,8,27.56-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.51-9.6Z" - }, - classes: { - spikes: "fill-bright", - eyeball: "fill-med", - iris: "fill-bright" - } - }, - [ConsequenceType.ResolveHarm4]: { - viewBox: "0 0 512 512", - paths: { - spikes: "M261.14,19.1A237.51,237.51,0,0,0,202,27.22C75.67,61.08.69,191,34.54,317.31,67.63,440.8,192.44,515.21,316,486.92A132.35,132.35,0,0,1,284.78,475a207,207,0,0,1-157.72-57.52l89.22-30-116.34-2a206,206,0,0,1-24.06-47.36L214,333.21,65.76,296.5a205.41,205.41,0,0,1-.18-54.37l164.66,47.21-154-91.08a208,208,0,0,1,29.15-53.84l154.4,108.36L141.75,107a205.85,205.85,0,0,1,63.68-34.49l95.49,158.21L255.85,62.45q6.47-.48,12.9-.54a205.43,205.43,0,0,1,61.65,8.84L359.77,223.5,376.08,90.85a206.76,206.76,0,0,1,57.16,50.05L415.61,243.13,454,173a207.52,207.52,0,0,1,18.93,139,132.33,132.33,0,0,1,7.74,38.31,235.8,235.8,0,0,0,11.48-155.53C463.55,88.09,366.63,18.05,261.14,19.1Z", - eyeball: "M349.62,242.53a45.38,45.38,0,0,1,9,6.95c12.21,12.21,16.07,29.9,13.25,47.35s-12,35.21-26.82,50-32.55,24-50,26.83-35.13-1-47.34-13.26a48,48,0,0,1-13-24.74,116.19,116.19,0,0,0-2,21.58,114.73,114.73,0,1,0,117-114.7Z", - iris: "M321.28,254a50.56,50.56,0,0,0-7.08.66c-13,2.09-27.55,9.39-39.75,21.59S255,303,252.86,316s.75,23.89,8,31.16S279,357.3,292,355.2s27.55-9.39,39.76-21.59,19.49-26.76,21.59-39.76-.75-23.89-8-31.16c-5.45-5.45-12.94-8.42-21.83-8.68-.74,0-1.49,0-2.25,0Zm-13.81,20.35a16,16,0,0,1,11.86,4.38c7.5,7.5,5.16,22-5.22,32.37s-24.88,12.72-32.37,5.23-5.16-22,5.22-32.38c6.16-6.16,13.78-9.49,20.51-9.6Z" - }, - classes: { - spikes: "fill-bright", - eyeball: "fill-bright", - iris: "fill-bright" - } - } -}; -// #endregion -export default C; diff --git a/module/core/debug.js b/module/core/debug.js deleted file mode 100644 index ee033b40..00000000 --- a/module/core/debug.js +++ /dev/null @@ -1,75 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~ -import { RollPermissions, ActionTrait, RollPhase, Effect, RollType, Position } from "../core/constants.js"; -import { BladesPC, BladesNPC, BladesFaction } from "../documents/BladesActorProxy.js"; -import { BladesRollPrimary, BladesRollOpposition } from "../classes/BladesRoll.js"; -class BladesDebug { - static async GetSampleSchemas(docNames = {}) { - // Documents - const SAMPLE_USER_NAME = docNames.user || "Alistair"; - const SAMPLE_PC_NAME = docNames.pc || "Alistair"; - const SAMPLE_NPC_NAME = docNames.npc || "Setarra"; - const SAMPLE_FACTION_NAME = docNames.faction || "the Bluecoats"; - const sampleUser = game.users.getName(SAMPLE_USER_NAME); - if (!sampleUser) { - throw new Error(`Sample user with name "${SAMPLE_USER_NAME}" not found.`); - } - const samplePC = game.actors.getName(SAMPLE_PC_NAME); - if (!BladesPC.IsType(samplePC)) { - throw new Error(`Sample BladesPC with name "${SAMPLE_PC_NAME}" not found.`); - } - const sampleNPC = game.actors.getName(SAMPLE_NPC_NAME); - if (!BladesNPC.IsType(sampleNPC)) { - throw new Error(`Sample BladesNPC with name "${SAMPLE_NPC_NAME}" not found or is not a valid BladesNPC.`); - } - const sampleFaction = game.actors.getName(SAMPLE_FACTION_NAME); - if (!BladesFaction.IsType(sampleFaction)) { - throw new Error(`Sample BladesFaction with name "${SAMPLE_FACTION_NAME}" not found or is not a valid BladesFaction.`); - } - // BladesActionRoll - const BladesActionRoll_Schema = { - rollType: RollType.Action, - // rollSubType: RollSubType.GatherInfo, - // rollPrompt: "Gathering Information", - rollTrait: ActionTrait.skirmish, - // rollUserID: sampleUser.id, - // rollDowntimeAction: DowntimeAction.AcquireAsset, - // rollClockKey: U.getLast(game.eunoblades.ClockKeys.contents)?.id, - rollPrimaryData: BladesRollPrimary.GetDataFromDoc(samplePC), - rollOppData: BladesRollOpposition.GetDataFromDoc(sampleFaction), - // rollParticipantData: {}, - // consequenceData: {}, - // resistanceData: { - // consequence: {} - // }, - rollModsData: {}, - rollPositionInitial: Position.risky, - rollEffectInitial: Effect.standard, - rollPosEffectTrade: false, - rollPhase: RollPhase.Collaboration, - GMBoosts: {}, - GMOppBoosts: {}, - GMOverrides: {}, - rollFactorToggles: { - source: {}, - opposition: {} - }, - userPermissions: { - [sampleUser.id]: RollPermissions.Primary - } - // rollPositionFinal: Position.risky, - // rollEffectFinal: Effect.standard, - // rollResult: RollResult.success, - // rollResultDelta: 0, - // rollResultFinal: RollResult.success, - // rollTraitVerb: "skirmishes", - // rollTraitPastVerb: "skirmished", - // finalDiceData: [], - // isInlineResistanceRoll: false - }; - return { - BladesActionRoll_Schema - }; - } -} -export default BladesDebug; diff --git a/module/core/gsap.js b/module/core/gsap.js deleted file mode 100644 index 3c33f39d..00000000 --- a/module/core/gsap.js +++ /dev/null @@ -1,837 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import U from "./utilities.js"; -import C from "./constants.js"; -// eslint-disable-next-line import/no-unresolved -import { TextPlugin, Flip, Draggable as Dragger, MotionPathPlugin, SplitText, Observer, CustomEase, CustomWiggle, CustomBounce, EasePack } from "/scripts/greensock/esm/all.js"; -const gsapPlugins = [ - TextPlugin, - Flip, - MotionPathPlugin, - Dragger, - SplitText, - Observer, - CustomEase, - CustomWiggle, - CustomBounce, - EasePack -]; -export const gsapEffects = { - // #region CLOCK KEYS - keyDrop: { - effect: (clockKey, config) => { - const [keyContainer] = $(clockKey).closest(".clock-key-container"); - return U.gsap.timeline({ - onComplete() { - if (config.callback) { - config.callback(); - } - } - }) - .fromTo(keyContainer, { - y: config.yShift - }, { - y: 0, - autoAlpha: 1, - ease: "bounce", - duration: config.duration - }); - }, - defaults: { - duration: 1, - yShift: -800 - }, - extendTimeline: true - }, - keyPull: { - effect: (clockKey, config) => { - const [keyContainer] = $(clockKey).closest(".clock-key-container"); - return U.gsap.timeline({ - onComplete() { - if (config.callback) { - config.callback(); - } - } - }) - .to(keyContainer, { - y: config.yDelta, - ease: config.ease, - duration: 0.75 * config.duration - }) - .to(keyContainer, { - opacity: 0, - ease: "power2.out", - duration: 0.25 * config.duration - }, 0.75 * config.duration); - }, - defaults: { - yDelta: -800, - duration: 1, - ease: "back.in(1)" - }, - extendTimeline: true - }, - keyControlPanelFlip: { - effect: (target, config) => { - return U.gsap.timeline({ - delay: config.delay, - onStart() { - if (target) { - const target$ = $(target); - // Get the next sibling of the target element if it has the class "clock-control" - const nextSibling$ = target$.next(".clock-control-flipper"); - // Check if the nextSibling element exists - if (nextSibling$.length) { - U.gsap.effects.keyControlPanelFlip(nextSibling$[0], { - ...config, - delay: 0.15 - }); - } - } - } - }) - .to(target, { - rotateX: config.angle, - duration: 0.5, - ease: "back.inOut(2)" - }); - }, - defaults: { - angle: 180, - delay: 0 - }, - extendTimeline: true - }, - // #endregion - // #region CHAT CONSEQUENCE EFFECTS - csqEnter: { - effect: (csqContainer, config) => { - const csqRoot = U.gsap.utils.selector(csqContainer); - // ELog.checkLog3("gsap", "gsapEffects.consequenceEnter -> THIS", {this: this, csqRoot}); - const csqIconCircle = csqRoot(".consequence-icon-circle.base-consequence"); - // const csqBaseElems = csqRoot(".base-consequence:not(.consequence-icon-circle)"); - const csqBaseTypeElem = csqRoot(".consequence-type.base-consequence"); - const csqAcceptTypeElem = csqRoot(".consequence-type.accept-consequence"); - const csqBaseNameElem = csqRoot(".consequence-name.base-consequence"); - const csqAcceptNameElem = csqRoot(".consequence-name.accept-consequence"); - // const csqAcceptElems = csqRoot(".accept-consequence:not(.consequence-icon-circle):not(.consequence-button-container)"); - const tl = U.gsap.timeline({ paused: true, defaults: {} }); - // Initialize name and type opacities. - if (csqAcceptTypeElem.length > 0) { - tl.set(csqAcceptTypeElem, { opacity: 0 }, 0); - } - if (csqAcceptNameElem.length > 0) { - tl.set(csqAcceptNameElem, { opacity: 0 }, 0); - } - // Crossfade base/accept type lines - if (csqBaseTypeElem.length > 0) { - tl.fromTo(csqBaseTypeElem, { - opacity: 1 - }, { - opacity: 0, - duration: 0.25, - ease: "sine" - }, 0); - } - if (csqAcceptTypeElem.length > 0) { - tl.fromTo(csqAcceptTypeElem, { - opacity: 0 - }, { - opacity: 1, - duration: 0.25, - ease: "sine" - }, 0); - } - // Crossfade base/accept name lines - if (csqBaseNameElem.length > 0) { - tl.fromTo(csqBaseNameElem, { - opacity: 1 - }, { - opacity: 0, - duration: 0.25, - ease: "sine" - }, 0); - } - if (csqAcceptNameElem.length > 0) { - tl.fromTo(csqAcceptNameElem, { - opacity: 0 - }, { - opacity: 1, - duration: 0.25, - ease: "sine" - }, 0); - } - // Brighten the entire container slightly - if (csqContainer) { - tl.fromTo(csqContainer, { - filter: "brightness(1)" - }, { - filter: `brightness(${config.brightness})`, - duration: config.duration / 3, - ease: "none" - }, 0); - } - // Enlarge the icon circle, add stroke - if (csqIconCircle.length > 0) { - tl.fromTo(csqIconCircle, { - scale: 0.75, - outlineColor: C.Colors.dBLACK, - outlineWidth: 0 - }, { - scale: 0.85, - outlineColor: C.Colors.GREY, - outlineWidth: 1, - duration: 0.55, - ease: "sine.out" - }, 0); - } - return tl; - }, - defaults: { - brightness: 1.5, - duration: 0.5, - scale: 1.5, - stagger: 0.05, - ease: "sine", - easeStrength: 1.5 - } - }, - csqClickIcon: { - effect: (csqIconContainer, config) => { - const csqContainer = $(csqIconContainer).closest(".comp.consequence-display-container"); - const csqRoot = U.gsap.utils.selector(csqContainer[0]); - const iconRoot = U.gsap.utils.selector(csqIconContainer); - const csqBackgroundImg = csqRoot(".consequence-bg-image"); - const csqInteractionPads = csqRoot(".consequence-interaction-pad"); - const csqIconCircleBase = iconRoot(".consequence-icon-circle.base-consequence"); - const csqIconCircleAccept = iconRoot(".consequence-icon-circle.accept-consequence"); - const csqButtonContainers = iconRoot(".consequence-button-container"); - const tl = U.gsap.timeline({ - paused: true, - onComplete: function () { - $(csqInteractionPads).css("pointerEvents", "auto"); - }, - onReverseComplete: function () { - $(csqInteractionPads).css("pointerEvents", "none"); - } - }); - // Slide out the background - if (csqBackgroundImg.length) { - tl.fromTo(csqBackgroundImg, { - xPercent: 110, - yPercent: -50 - }, { - xPercent: -60, - yPercent: -50, - duration: 0.5, - ease: "back" - }, 0); - } - // Fade out the base consequence icon circle - if (csqIconCircleBase.length > 0) { - tl.fromTo(csqIconCircleBase, { - opacity: 1 - }, { - opacity: 0, - duration: 0.25, - ease: "sine.out" - }, 0); - } - // Fade in the accept consequence icon circle, enlarging the stroke - if (csqIconCircleAccept.length > 0) { - tl.fromTo(csqIconCircleAccept, { - opacity: 0 - }, { - opacity: 1, - duration: 0.15, - ease: "sine" - }, 0) - .fromTo(csqIconCircleAccept, { - outlineWidth: 1, - scale: 0.85 - }, { - outlineWidth: 2, - scale: 1, - duration: 0.25, - ease: "sine" - }, 0.175); - } - // Scale and fade in the button containers - if (csqButtonContainers.length > 0) { - tl.fromTo(csqButtonContainers, { - scale: config.scale, - opacity: 0, - filter: "blur(25px)" - }, { - scale: 1, - opacity: 1, - filter: "blur(0px)", - stagger: config.stagger, - duration: config.duration, - ease: `${config.ease}.inOut(${config.easeStrength})` - }, 0); - } - return tl; - }, - defaults: { - duration: 0.5, - scale: 1.5, - stagger: 0.05, - ease: "sine", - easeStrength: 1.5 - } - }, - csqEnterRight: { - effect: (csqContainer) => { - const csqRoot = U.gsap.utils.selector(csqContainer); - const typeLine = csqRoot(".consequence-type-container .consequence-type.accept-consequence"); - const typeLineBg = csqRoot(".consequence-type-container .consequence-type-bg.accept-consequence"); - const buttonRoot = U.gsap.utils.selector(csqRoot(".consequence-button-container.consequence-accept-button-container")); - const buttonBg = buttonRoot(".consequence-button-bg"); - const buttonIcon = buttonRoot(".button-icon i"); - const buttonLabel = buttonRoot(".consequence-button-label"); - const tl = U.gsap.timeline({ paused: true, defaults: {} }); - // Turn type line white - if (typeLine.length > 0) { - tl.fromTo(typeLine, { - color: C.Colors.RED - }, { - color: C.Colors.WHITE, - duration: 0.5, - ease: "sine.inOut" - }, 0); - } - // Slide type line background out from under icon - if (typeLineBg.length > 0) { - tl.fromTo(typeLineBg, { - x: 5, - scaleX: 0, - color: C.Colors.RED, - skewX: 0 - }, { - scaleX: 1, - skewX: -45, - color: C.Colors.RED, - duration: 0.5, - ease: "back.out" - }, 0); - } - // Slide accept button background out from under icon - if (buttonBg.length > 0) { - tl.fromTo(buttonBg, { - scaleX: 0, - color: C.Colors.RED, - skewX: 0 - }, { - x: 0, - scaleX: 1, - skewX: -45, - color: C.Colors.RED, - duration: 0.25, - ease: "back.out" - }, 0); - } - // Turn button icon black and scale - if (buttonIcon.length > 0) { - tl.fromTo(buttonIcon, { - color: C.Colors.GREY, - opacity: 0.75, - scale: 1 - }, { - color: C.Colors.dBLACK, - scale: 1.25, - opacity: 1, - duration: 0.5, - ease: "sine" - }, 0); - } - // Turn button label black, add letter-spacing, bold - if (buttonLabel.length > 0) { - tl.fromTo(buttonLabel, { - color: C.Colors.GREY, - fontWeight: 400, - scale: 1 - }, { - color: C.Colors.dBLACK, - fontWeight: 800, - duration: 0.75, - ease: "sine" - }, 0); - } - return tl; - }, - defaults: {} - }, - csqEnterLeft: { - effect: (csqContainer) => { - const csqRoot = U.gsap.utils.selector(csqContainer); - const typeLine = csqRoot(".consequence-type-container .consequence-type.accept-consequence"); - const nameLine = csqRoot(".consequence-name-container .consequence-name.accept-consequence"); - const acceptIconCircle = csqRoot(".consequence-icon-circle.accept-consequence"); - const acceptButton = csqRoot(".consequence-button-container.consequence-accept-button-container"); - const tl = U.gsap.timeline({ paused: true, defaults: {} }); - // Fade out type line - if (typeLine.length > 0) { - tl.to(typeLine, { - opacity: 0, - duration: 0.15, - ease: "sine.inOut" - }, 0); - } - // Fade out name - if (nameLine.length > 0) { - tl.to(nameLine, { - opacity: 0, - duration: 0.15, - ease: "sine.inOut" - }, 0); - } - // Fade out icon - if (acceptIconCircle.length > 0) { - tl.to(acceptIconCircle, { - opacity: 0, - duration: 0.15, - ease: "sine.inOut" - }, 0); - } - // Fade out accept button - if (acceptButton.length > 0) { - tl.fromTo(acceptButton, { - opacity: 1 - }, { - opacity: 0, - duration: 0.25, - ease: "sine.inOut" - }, 0); - } - return tl; - }, - defaults: {} - }, - csqEnterSubLeft: { - effect: (csqContainer, config) => { - const csqRoot = U.gsap.utils.selector(csqContainer); - const iconCircle = csqRoot(`.consequence-icon-circle.${config.type}-consequence`); - const typeLine = csqRoot(`.consequence-type-container .consequence-type.${config.type}-consequence`); - const nameLine = csqRoot(`.consequence-name.${config.type}-consequence`); - const footerBg = csqRoot(`.consequence-footer-container .consequence-footer-bg.${config.type}-consequence`); - const specialFooterMsg = csqRoot(`.consequence-footer-container .consequence-footer-message.${config.type}-consequence`); - const tl = U.gsap.timeline({ paused: true, defaults: {} }); - // Fade in icon circle - if (iconCircle.length > 0) { - tl.fromTo(iconCircle, { - opacity: 0 - }, { - opacity: 1, - duration: 0.5, - ease: "back.out" - }, 0); - } - // Fade in typeLine - if (typeLine.length > 0) { - tl.fromTo(typeLine, { - opacity: 0 - }, { - opacity: 1, - duration: 0.5, - ease: "back.out" - }, 0); - } - // Slide out nameLine from left - if (nameLine.length > 0) { - tl.fromTo(nameLine, { - scaleX: 0 - }, { - scaleX: 1, - duration: 0.5, - ease: "back.inOut" - }, 0); - } - // Slide out footer background from left - if (footerBg.length > 0) { - tl.fromTo(footerBg, { - scaleX: 0, - skewX: 0, - opacity: 1 - }, { - scaleX: 1, - skewX: -45, - opacity: 1, - duration: 0.5, - ease: "back.inOut" - }, 0); - } - // Slide out attribute from left - if (specialFooterMsg.length > 0) { - tl.fromTo(specialFooterMsg, { - scaleX: 0, - opacity: 1 - }, { - scaleX: 1, - opacity: 1, - duration: 0.5, - ease: "back.inOut" - }, 0); - } - if (csqRoot(`.consequence-button-container.consequence-${config.type}-button-container`).length > 0) { - const buttonRoot = U.gsap.utils.selector(csqRoot(`.consequence-button-container.consequence-${config.type}-button-container`)); - const buttonBg = buttonRoot(".consequence-button-bg"); - const buttonIcon = buttonRoot(".button-icon i"); - const buttonLabel = buttonRoot(".consequence-button-label"); - // Slide out button background from right - if (buttonBg.length > 0) { - tl.fromTo(buttonBg, { - scaleX: 0, - skewX: 0, - opacity: 1 - }, { - scaleX: 1, - skewX: -45, - opacity: 1, - duration: 0.5, - ease: "back.inOut" - }, 0); - } - // Turn button icon black and scale - if (buttonIcon.length > 0) { - tl.fromTo(buttonIcon, { - color: C.Colors.GREY, - opacity: 0.75, - scale: 1 - }, { - color: C.Colors.dBLACK, - scale: 1.25, - opacity: 1, - duration: 0.5, - ease: "sine" - }, 0); - } - // Turn button label black, bold - if (buttonLabel.length > 0) { - tl.fromTo(buttonLabel, { - color: C.Colors.GREY, - fontWeight: 400, - scale: 1 - }, { - color: C.Colors.dBLACK, - fontWeight: 800, - duration: 0.75, - ease: "sine" - }, 0); - } - } - return tl; - }, - defaults: {} - }, - // #endregion - // #region CHARACTER SHEET EFFECTS - fillCoins: { - effect: (targets, config) => { - // Targets will be all coins from zero to where fill currently is - // Some will already be full, others not. - // Stagger in timeline - // Pulse in size and color - // Shimmer as they shrink back ? - return U.gsap.to(targets, { - duration: config.duration / 2, - scale: config.scale, - filter: config.filter, - ease: config.ease, - stagger: { - amount: 0.25, - from: "start", - repeat: 1, - yoyo: true - } - }); - }, - defaults: { - duration: 1, - scale: 1, - filter: "saturate(1) brightness(2)", - ease: "power2.in" - }, - extendTimeline: true - }, - // #endregion - // #region GENERAL: 'blurRemove', 'hoverTooltip', 'textJitter' - blurRemove: { - effect: (targets, config) => U.gsap.timeline({ stagger: config.stagger }) - .to(targets, { - skewX: config.skewX, - duration: config.duration / 2, - ease: "power4.out" - }) - .to(targets, { - x: config.x, - marginBottom: config.ignoreMargin - ? undefined - : function (i, target) { - return U.get(target, "height") * -1; - }, - marginRight: config.ignoreMargin - ? undefined - : function (i, target) { - return U.get(target, "width") * -1; - }, - scale: config.scale, - filter: `blur(${config.blur}px)`, - duration: (3 / 4) * config.duration - }, config.duration / 4) - .to(targets, { - autoAlpha: 0, - duration: config.duration / 2, - ease: "power3.in" - }, config.duration / 2), - defaults: { - ignoreMargin: false, - skewX: -20, - duration: 0.5, - x: "+=300", - scale: 1.5, - blur: 10, - stagger: 0 - }, - extendTimeline: true - }, - blurReveal: { - effect: (targets, config) => U.gsap.timeline() - .fromTo(targets, { - x: config.x, - marginBottom: config.ignoreMargin - ? undefined - : function (i, target) { - return U.get(target, "height") * -1; - }, - marginRight: config.ignoreMargin - ? undefined - : function (i, target) { - return U.get(target, "width") * -1; - }, - scale: config.scale, - filter: `blur(${config.blur}px)` - }, { - x: 0, - marginBottom: 0, - marginRight: 0, - scale: 1, - filter: "blur(0px)", - duration: (3 / 4) * config.duration - }, 0) - .fromTo(targets, { - autoAlpha: 0 - }, { - autoAlpha: 1, - duration: config.duration / 2, - ease: "power3.in" - }, 0) - .fromTo(targets, { - skewX: config.skewX - }, { - skewX: 0, - duration: config.duration / 2, - ease: "power4.out" - }, config.duration / 2), - defaults: { - ignoreMargin: false, - skewX: -20, - duration: 0.5, - x: "+=300", - scale: 1.5, - blur: 10 - }, - extendTimeline: true - }, - scaleUpReveal: { - effect: (target, config) => { - const tl = U.gsap.timeline() - .fromTo(target, { - autoAlpha: 0, - scale: 0.5 * config.scale - }, { - autoAlpha: 1, - scale: config.scale, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - scale: 1, - duration: 0.5, - ease: "power2" - }, - extendTimeline: true - }, - scaleDownRemove: { - effect: (target, config) => { - const tl = U.gsap.timeline() - .to(target, { - autoAlpha: 0, - scale: 0.5 * config.scale, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - scale: 1, - duration: 0.5, - ease: "power2" - }, - extendTimeline: true - }, - blurRevealTooltip: { - effect: (target, config) => { - if (!target) { - throw new Error(`blurRevealTooltip effect: tooltip element is ${target === null ? "null" : typeof target}`); - } - const tooltip$ = $(target); - return U.gsap.timeline({ - paused: true, - onReverseComplete: config.onReverseComplete - }) - .fromTo(tooltip$, { - filter: `blur(${config.blurStrength}px)`, - autoAlpha: 0, - xPercent: 50, - yPercent: -200, - scale: config.scale - }, { - filter: "blur(0px)", - autoAlpha: 1, - xPercent: -50, - yPercent: -100, - scale: 1, - ease: config.ease, - duration: config.duration - }); - }, - defaults: { - scale: 1.5, - blurStrength: 15, - ease: "back.out", - duration: 0.25, - onReverseComplete: undefined - }, - extendTimeline: true - }, - textJitter: { - effect: (target, config) => { - const [targetElem] = $(target); - if (!targetElem) { - throw new Error("textJitter effect: target not found"); - } - const split = new SplitText(targetElem, { type: "chars" }); - return U.gsap.timeline() - .to(targetElem, { - autoAlpha: 1, - duration: config.duration, - ease: "none" - }) - .fromTo(split.chars, { - y: -config.yAmp - }, { - y: config.yAmp, - duration: config.duration, - ease: "sine.inOut", - stagger: { - repeat: -1, - yoyo: true, - from: "random", - each: config.stagger - } - }, 0) - .fromTo(split.chars, { - rotateZ: -config.rotateAmp - }, { - rotateZ: config.rotateAmp, - duration: config.duration, - ease: CustomWiggle.create("myWiggle", { wiggles: 10, type: "random" }), - stagger: { - repeat: -1, - from: "random", - yoyo: true, - each: config.stagger - } - }, 0); - }, - defaults: { - yAmp: 2, - rotateAmp: 2, - duration: 1, - stagger: 0.05 - }, - extendTimeline: true - } - // #endregion -}; -/** - * Registers relevant GSAP plugins and effects. - */ -export function Initialize() { - if (gsapPlugins.length) { - U.gsap.config({ - nullTargetWarn: true - }); - U.gsap.registerPlugin(...gsapPlugins); - Object.assign(globalThis, { - TextPlugin, - Flip, - MotionPathPlugin, - Dragger, - SplitText, - Observer, - CustomEase, - CustomWiggle, - CustomBounce, - EasePack - }); - } - Object.entries(gsapEffects).forEach(([name, effect]) => { - U.gsap.registerEffect(Object.assign(effect, { name })); - }); -} -/** - * Applies listeners to '.tooltip-trigger' elements in the document. - * @param {JQuery} html The document to be searched. - */ -export function ApplyTooltipAnimations(html) { - html.find(".tooltip-trigger").each((_, el) => { - const tooltipElem = $(el).find(".tooltip")[0] ?? $(el).next(".tooltip")[0]; - if (!tooltipElem) { - return; - } - const tooltip$ = $(tooltipElem); - /** - * Use the .tooltip-trigger element as the definitive positioning element for the tooltip itself. - * If the tooltip-trigger's absolute position relative to the viewport is, e.g., near the top, - * then the tooltip should appear beneath, etc - */ - // Find the tooltip's parent container. If its position isn't relative or absolute, set it to relative. - const tooltipContainer$ = tooltip$.parent(); - if (tooltipContainer$.css("position") !== "relative" - && tooltipContainer$.css("position") !== "absolute") { - tooltipContainer$.css("position", "relative"); - } - // Set the tooltip itself to absolute positioning - tooltip$.css("position", "absolute"); - // Assign a unique ID to the tooltip element - const tooltipID = `tooltip-${randomID()}`; - tooltip$.attr("id", tooltipID); - // For .tooltip-wide tooltips, adjust the aspect ratio accordingly - if (tooltip$.hasClass("tooltip-wide")) { - U.adjustTextContainerAspectRatio(tooltipElem, 6); - } - $(el).on({ - mouseenter: function () { - game.eunoblades.Director.displayTooltip(tooltipElem); - }, - mouseleave: function () { - game.eunoblades.Director.clearTooltip(tooltipID); - } - }); - }); -} -export { TextPlugin, Flip, MotionPathPlugin, Dragger, SplitText, Observer, CustomEase, CustomWiggle, CustomBounce, EasePack }; -export default U.gsap; diff --git a/module/core/gsapBROKEN.js b/module/core/gsapBROKEN.js deleted file mode 100644 index b07afc37..00000000 --- a/module/core/gsapBROKEN.js +++ /dev/null @@ -1,582 +0,0 @@ -import U from "./utilities.js"; -import C from "./constants.js"; -// eslint-disable-next-line import/no-unresolved -import { TextPlugin } from "/scripts/greensock/esm/all.js"; -const gsapPlugins = [ - TextPlugin -]; -const gsapEffects = { - /* Basic Element Effects */ - fadeOut: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .to(targets, { - autoAlpha: 0, - duration: config.duration, - ease: config.ease - }); - // if (config.reversed) { - // tl.seek(config.duration); - // } - return tl; - }, - defaults: { - paused: false, - reversed: false, - duration: 0.5, - ease: "power4.out" - } - }, - blurOut: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .to(targets, { - skewX: config.skewX, - duration: 0.5 * config.duration, - ease: "power4.out" - }) - .to(targets, { - x: `+=${config.rangeX}`, - marginBottom(i, target) { - return U.get(target, "height") * -1; - }, - marginRight(i, target) { - return U.get(target, "width") * -1; - }, - scale: config.scale, - filter: `blur(${config.blurStrength}px)`, - duration: 0.75 * config.duration - }, 0.25 * config.duration) - .to(targets, { - autoAlpha: 0, - duration: 0.5 * config.duration, - ease: "power3.in" - }, 0.5 * config.duration); - // if (config.reversed) { - // tl.seek(config.duration); - // } - return tl; - }, - defaults: { - paused: false, - reversed: false, - duration: 0.5, - skewX: -20, - rangeX: 300, - scale: 1.5, - blurStrength: 10 - } - }, - slideOut: { - effect: (targets, config) => { - const scaleKey = ["up", "down"].includes(config.dir) ? "scaleY" : "scaleX"; - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .to(targets, { - [scaleKey]: 0, - duration: config.duration, - ease: config.ease - }); - // if (config.reversed) { - // tl.seek(config.duration); - // } - return tl; - }, - defaults: { - paused: false, - reversed: false, - duration: 0.5, - ease: "back.out(3)" - } - }, - brighten: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .fromTo(targets, { - filter: `brightness(${config.startStrength})` - }, { - filter: `brightness(${config.strength})`, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - paused: false, - reversed: false, - initialStrength: 1, - strength: 1.5, - duration: 0.5, - ease: "none" - } - }, - enlarge: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .fromTo(targets, { - scale: config.startScale - }, { - scale: config.scale, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - paused: false, - reversed: false, - startScale: 1, - scale: 1.5, - duration: 0.5, - ease: "sine.out" - } - }, - changeColor: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .to(targets, { - color: config.color, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - paused: false, - reversed: false, - color: C.Colors.bWHITE, - duration: 0.5, - ease: "sine" - } - }, - skewX: { - effect: (targets, config) => { - const tl = U.gsap.timeline({ - paused: config.paused, - runBackwards: config.reversed - }) - .to(targets, { - skewX: config.angle, - duration: config.duration, - ease: config.ease - }); - return tl; - }, - defaults: { - paused: false, - reversed: false, - angle: -45, - duration: 0.5, - ease: "sine" - } - }, - blurRemove: { - effect: (targets, config) => U.gsap.timeline() - .to(targets, { - skewX: config.skewX, - duration: config.duration / 2, - ease: "power4.out" - }) - .to(targets, { - x: config.x, - marginBottom(i, target) { - return U.get(target, "height") * -1; - }, - marginRight(i, target) { - return U.get(target, "width") * -1; - }, - scale: config.scale, - filter: config.filter, - duration: (3 / 4) * config.duration - }, config.duration / 4) - .to(targets, { - opacity: 0, - duration: config.duration / 2, - ease: "power3.in" - }, config.duration / 2), - defaults: { - skewX: -20, - duration: 0.5, - x: "+=300", - scale: 1.5, - filter: "blur(10px)" - } - }, - slideUp: { - effect: (targets) => U.gsap.to(targets, { - height: 0, - // PaddingTop: 0, - // paddingBottom: 0, - duration: 0.5, - ease: "power3" - }), - defaults: {} - }, - pulse: { - effect: (targets, config) => U.gsap.to(targets, { - repeat: config.repCount, - yoyo: true, - duration: config.duration / config.repCount, - ease: config.ease, - opacity: 0.25 - }), - defaults: { - repCount: 3, - duration: 5, - ease: "sine.inOut" - } - }, - throb: { - effect: (targets, config) => U.gsap.to(targets, { - repeat: config.stagger ? undefined : 1, - yoyo: config.stagger ? undefined : true, - duration: config.duration / 2, - scale: config.scale, - filter: config.filter, - ease: config.ease, - stagger: config.stagger - ? { - ...config.stagger, - repeat: 1, - yoyo: true - } - : {} - }), - defaults: { - duration: 1, - scale: 1, - filter: "saturate(1) brightness(2)", - ease: "power2.in" - }, - extendTimeline: true - }, - pulseClockWedges: { - effect: () => U.gsap.timeline({ duration: 0 }), - defaults: {} - }, - reversePulseClockWedges: { - effect: () => U.gsap.timeline({ duration: 0 }), - defaults: {} - }, - fillCoins: { - effect: (targets, config) => { - // Targets will be all coins from zero to where fill currently is - // Some will already be full, others not. - // Stagger in timeline - // Pulse in size and color - // Shimmer as they shrink back ? - return U.gsap.effects.throb(targets, { stagger: { - amount: 0.25, - from: "start", - repeat: 1, - yoyo: true - }, ...config ?? {} }); - }, - defaults: {} - }, - hoverTooltip: { - effect: (tooltip, config) => { - const tl = U.gsap.timeline({ paused: true, defaults: {} }); - if (!tooltip) { - return tl; - } - // Tooltip = $(tooltip); - if (config.scalingElems.length > 0) { - tl.to(config.scalingElems, { - scale: "+=0.2", - filter: "none", - color: C.Colors.WHITE, - opacity: 1, - duration: 0.125, - ease: "back" - }, 0.5); - } - if (tooltip) { - tl.fromTo(tooltip, { - filter: "blur(50px)", - opacity: 0, - scale: 2 * config.tooltipScale - }, { - filter: "none", - opacity: 1, - scale: config.tooltipScale, - x: config.xMotion, - duration: 0.25, - ease: "power2" - }, 1); - } - return tl; - }, - defaults: { - xMotion: "+=200", - tooltipScale: 1.25 - } - } -}; -/** - * Registers relevant GSAP plugins and effects. - */ -export function Initialize() { - if (gsapPlugins.length) { - U.gsap.registerPlugin(...gsapPlugins); - } - Object.entries(gsapEffects).forEach(([name, effect]) => { - U.gsap.registerEffect(Object.assign(effect, { name, extendTimeline: true })); - }); -} -/** - * Applies listeners to '.tooltip-trigger' elements in the document. - * @param {JQuery} html The document to be searched. - */ -export function ApplyTooltipAnimations(html) { - html.find(".tooltip-trigger").each((_, el) => { - const tooltipElem = $(el).find(".tooltip")[0] ?? $(el).next(".tooltip")[0]; - if (!tooltipElem) { - return; - } - $(el).data("hoverTimeline", U.gsap.effects.hoverTooltip(tooltipElem, { - scalingElems: [...$(el).find(".tooltip-scaling-elem")].filter((elem) => Boolean(elem)), - xMotion: $(tooltipElem).hasClass("tooltip-left") ? "-=250" : "+=200", - tooltipScale: $(tooltipElem).hasClass("tooltip-small") ? 1 : 1.2 - })); - $(el).on({ - mouseenter: function () { - $(el).css("z-index", 10); - $(el).data("hoverTimeline").play(); - }, - mouseleave: function () { - $(el).data("hoverTimeline").reverse().then(() => { - $(el).css("z-index", ""); - }); - } - }); - }); -} -/** - * Applies listeners to .consequence-display-container and children found in document. - * @param {JQuery} html The document to be searched. - */ -export function ApplyConsequenceAnimations(html) { - /** - * TIMELINES - * .comp.consequence-display-container:mouseenter - * = fade in grey interaction buttons - * ...:mouseleave = reverse - * - * .consequence-accept-button-container:mouseenter - * = turn type line white, text shadow - * slide out .consequence-accept-button-bg from left - * turn .consequence-accept-button i black, and scale - * turn .consequence-accept-button-label black, add letter spacing, bold - * ...:mouseleave = reverse - * - * .consequence-resist-button-container:mouseenter - * = slide in .consequence-type-bg.base-consequence to left - * fade out all .base-consequence:not(.consequence-type-bg) - * slide out .consequence-type.resist-consequence from left - * slide out .consequence-resist-button-bg from right - * slide out .consequence-footer-bg.resist-consequence from left - * slide out .consequence-resist-attribute from left - * slide out .consequence-name.resist-consequence from left - * fade in .consequence-icon-circle.resist-consequence - * ...:mouseleave = reverse - * --> IF resistTo.type === "None", blurRemove the base_consequence name and type instead of sliding them in, - * and don't slide the resistance ones out at all. - * */ - html - .find(".comp.consequence-display-container") - .each((_i, csqContainer) => { - if (!$(csqContainer).hasClass("consequence-accepted")) { - const csqRoot = U.gsap.utils.selector(csqContainer); - const csqBgImg = csqRoot(".consequence-bg-image"); - const [iconContainer] = csqRoot(".consequence-icon-container"); - const iconRoot = U.gsap.utils.selector(iconContainer); - const typeRoot = U.gsap.utils.selector(csqRoot(".consequence-type-container")[0]); - const nameRoot = U.gsap.utils.selector(csqRoot(".consequence-name-container")[0]); - const footerRoot = U.gsap.utils.selector(csqRoot(".consequence-footer-container")[0]); - const csqOptions = ["base", "accept"]; - ["resist", "armor", "special"].forEach((csqOpt) => { - if (iconRoot(`.${csqOpt}-consequence`).length) { - csqOptions.push(csqOpt); - } - }); - const interactionPads = {}; - const iconCircles = {}; - const buttonContainers = {}; - const buttonBGs = {}; - const buttonIcons = {}; - const buttonLabels = {}; - const typeLabels = {}; - const typeBGs = {}; - const nameLabels = {}; - const nameBGs = {}; - const footerLabels = {}; - const footerBGs = {}; - ["right", "left", "left-resist", "left-armor", "left-special"].forEach((iPadOpt) => { - [interactionPads[iPadOpt]] = csqRoot(`.consequence-interaction-pad.interaction-pad-${iPadOpt}`); - }); - ["base", "accept", "resist", "armor", "special"].forEach((csqOpt) => { - [iconCircles[csqOpt]] = iconRoot(`.consequence-icon-circle.${csqOpt}-consequence`); - [buttonContainers[csqOpt]] = iconRoot(`.consequence-button-container.${csqOpt}-consequence`); - [buttonBGs[csqOpt]] = iconRoot(`.consequence-button-container.${csqOpt}-consequence .consequence-button-bg`); - [buttonIcons[csqOpt]] = iconRoot(`.consequence-button-container.${csqOpt}-consequence .button-icon i`); - [buttonLabels[csqOpt]] = iconRoot(`.consequence-button-container.${csqOpt}-consequence .consequence-button-label`); - [typeLabels[csqOpt]] = typeRoot(`.consequence-type.${csqOpt}-consequence`); - if (csqOpt === "accept") { - [typeBGs[csqOpt]] = typeRoot(`.consequence-type-bg.${csqOpt}-consequence`); - } - [nameLabels[csqOpt]] = nameRoot(`.consequence-name.${csqOpt}-consequence`); - [nameBGs[csqOpt]] = nameRoot(`.consequence-name-bg.${csqOpt}-consequence`); - [footerLabels[csqOpt]] = footerRoot(`.consequence-footer-message.${csqOpt}-consequence`); - [footerBGs[csqOpt]] = footerRoot(`.consequence-footer-bg.${csqOpt}-consequence`); - }); - [ - interactionPads, - iconCircles, - buttonContainers, buttonBGs, buttonIcons, buttonLabels, - typeLabels, typeBGs, - nameLabels, nameBGs, - footerLabels, footerBGs - ] - .forEach((elemRecord) => U.objCompact(elemRecord, [undefined, null, false], true)); - // Apply master on-enter hover timeline to consequence container. - $(csqContainer).data("hoverTimelines", [ - U.gsap.effects.fadeOut([typeLabels.base, nameLabels.base], { paused: true, duration: 0.5 }), - U.gsap.effects.fadeOut([typeLabels.accept, nameLabels.accept], { paused: true, reversed: true, duration: 0.25 }), - U.gsap.effects.brighten([csqContainer], { paused: true, duration: 0.5 }), - U.gsap.effects.enlarge([iconCircles.base], { paused: true, duration: 0.75, startScale: 0.75, scale: 0.85 }) - ]); - $(csqContainer).on({ - mouseenter: function () { - $(csqContainer).css("z-index", 10); - $(csqContainer).data("hoverTimelines").forEach((tl) => tl.play()); - }, - mouseleave: function () { - if (!($(iconContainer).data("isToggled"))) { - $(csqContainer).css("z-index", ""); - $(csqContainer).data("hoverTimelines").forEach((tl) => tl.reverse()); - } - } - }); - // Apply click timeline to icon circle - $(iconContainer).data("clickTimelines", [ - U.gsap.timeline({ paused: true }) - .fromTo([csqBgImg], { - xPercent: 110, - yPercent: -50 - }, { - xPercent: -60, - yPercent: -50, - duration: 0.5, - ease: "back" - }), - U.gsap.effects.fadeOut([iconCircles.base], { paused: true }), - U.gsap.effects.fadeOut([iconCircles.accept], { paused: true, reversed: true }), - U.gsap.effects.blurOut([buttonContainers], { paused: true, reversed: true }) - ]); - $(iconContainer).on({ - click: function () { - if ($(iconContainer).data("isToggled")) { - $(iconContainer).data("isToggled", false); - $(iconContainer).data("clickTimelines").forEach((tl) => tl.reverse()); - } - else { - $(iconContainer).data("isToggled", true); - $(iconContainer).data("clickTimelines").forEach((tl) => tl.play()); - // Find any siblings with toggled-on iconContainers, and toggle them off - Array.from($(csqContainer).siblings(".consequence-display-container")) - .forEach((containerElem) => { - const iContainer$ = $(containerElem).find(".consequence-icon-container"); - if (iContainer$?.data("isToggled")) { - iContainer$.data("isToggled", false); - $(containerElem).css("z-index", ""); - [ - ...iContainer$.data("clickTimelines"), - ...$(containerElem).data("hoverTimelines") - ].forEach((tl) => tl.reverse()); - } - }); - } - } - }); - // Apply hover timelines to right (accept) interaction pad - $(interactionPads.right).data("hoverTimelines", [ - U.gsap.effects.changeColor([typeLabels.accept], { paused: true, color: C.Colors.WHITE }), - U.gsap.effects.slideOut([typeBGs.accept, buttonBGs.accept], { paused: true, reversed: true, dir: "left" }), - U.gsap.effects.skewX([typeBGs.accept, buttonBGs.accept], { paused: true, angle: -45 }), - U.gsap.effects.changeColor([buttonIcons.accept, buttonLabels.accept], { paused: true, color: C.Colors.dBLACK }), - U.gsap.effects.enlarge([buttonIcons.accept], { paused: true, scale: 1.25 }) - ]); - $(interactionPads.right).on({ - mouseenter: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads.right).data("hoverTimelines").forEach((tl) => tl.play()); - } - }, - mouseleave: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads.right).data("hoverTimelines").forEach((tl) => tl.reverse()); - } - } - }); - // Apply hover timeline to left (resist/armor/special) interaction pad - $(interactionPads.left).data("hoverTimelines", [ - U.gsap.effects.fadeOut([typeLabels.accept, nameLabels.accept, iconCircles.accept, buttonContainers.accept], { paused: true, duration: 0.25 }) - ]); - $(interactionPads.left).on({ - mouseenter: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads.left).data("hoverTimelines").forEach((tl) => tl.play()); - } - }, - mouseleave: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads.left).data("hoverTimelines").forEach((tl) => tl.reverse()); - } - } - }); - // Apply hover timelines to specific left interaction pads where they exist - ["resist", "armor", "special"].forEach((csqOpt) => { - if (interactionPads[`left-${csqOpt}`]) { - $(interactionPads[`left-${csqOpt}`]).data("hoverTimelines", [ - U.gsap.effects.fadeOut([iconCircles[csqOpt], typeLabels[csqOpt]], { paused: true, reversed: true }), - U.gsap.effects.slideOut([buttonBGs[csqOpt], nameLabels[csqOpt], footerBGs[csqOpt], footerLabels[csqOpt]], { paused: true, reversed: true, dir: "left" }), - U.gsap.effects.skewX([buttonBGs[csqOpt], nameLabels[csqOpt], footerBGs[csqOpt], footerLabels[csqOpt]], { paused: true, angle: -45 }), - U.gsap.effects.changeColor([buttonIcons[csqOpt], buttonLabels[csqOpt]], { paused: true, color: C.Colors.dBLACK }), - U.gsap.effects.enlarge([buttonIcons[csqOpt]], { paused: true, scale: 1.25 }) - ]); - $(interactionPads[`left-${csqOpt}`]).on({ - mouseenter: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads[`left-${csqOpt}`]).data("hoverTimelines").forEach((tl) => tl.play()); - } - }, - mouseleave: function () { - if ($(iconContainer).data("isToggled")) { - $(interactionPads[`left-${csqOpt}`]).data("hoverTimelines").forEach((tl) => tl.reverse()); - } - } - }); - } - }); - } - }); -} -export default U.gsap; diff --git a/module/core/helpers.js b/module/core/helpers.js deleted file mode 100644 index 7c786d2e..00000000 --- a/module/core/helpers.js +++ /dev/null @@ -1,300 +0,0 @@ -// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~ -import U from "./utilities.js"; -// #endregion ▮▮▮▮[IMPORTS]▮▮▮▮ -// #region ░░░░░░░[Templates]░░░░ Preload Partials, Components & Overlay Templates ░░░░░░░ ~ -/** - * Define a set of template paths to pre-load - * Pre-loaded templates are compiled and cached for fast access when rendering - */ -export async function preloadHandlebarsTemplates() { - // Define template paths to load - const templatePaths = [ - // General Components - "systems/eunos-blades/templates/components/toggle-icon.hbs", - "systems/eunos-blades/templates/components/button-icon.hbs", - "systems/eunos-blades/templates/components/dotline.hbs", - "systems/eunos-blades/templates/components/armor.hbs", - "systems/eunos-blades/templates/components/comp.hbs", - "systems/eunos-blades/templates/components/select.hbs", - "systems/eunos-blades/templates/components/portrait.hbs", - "systems/eunos-blades/templates/components/clock.hbs", - "systems/eunos-blades/templates/components/roll-collab-mod.hbs", - "systems/eunos-blades/templates/components/slide-out-controls.hbs", - "systems/eunos-blades/templates/components/consequence.hbs", - "systems/eunos-blades/templates/components/consequence-accepted.hbs", - // Partials - "systems/eunos-blades/templates/parts/tier-block.hbs", - "systems/eunos-blades/templates/parts/turf-list.hbs", - "systems/eunos-blades/templates/parts/cohort-block.hbs", - "systems/eunos-blades/templates/parts/roll-opposition-creator.hbs", - "systems/eunos-blades/templates/parts/active-effects.hbs", - "systems/eunos-blades/templates/parts/gm-pc-summary.hbs", - "systems/eunos-blades/templates/components/clock-key.hbs" - ]; - // Load the template parts - return loadTemplates(templatePaths); -} -// #endregion ░░░░[Preload Templates]░░░░ -// #region ████████ Handlebars: Handlebar Helpers Definitions ████████ ~ -const handlebarHelpers = { - randString(param1 = 10) { - return U.randString(param1); - }, - test(param1, operator, param2) { - const stringMap = { - true: true, - false: false, - null: null, - undefined - }; - if (["!", "not", "=??"].includes(String(param1))) { - [operator, param1] = [String(param1), operator]; - } - if (typeof param1 === "string" && param1 in stringMap) { - param1 = stringMap[param1]; - } - if (typeof param2 === "string" && param2 in stringMap) { - param2 = stringMap[param2]; - } - switch (operator) { - case "!": - case "not": { - return !param1; - } - case "=??": { - return [undefined, null].includes(param1); - } - case "&&": { - return param1 && param2; - } - case "||": { - return param1 || param2; - } - case "==": { - return U.areFuzzyEqual(param1, param2); - } - case "===": { - return param1 === param2; - } - case "!=": - case "!==": { - return param1 !== param2; - } - case ">": { - return typeof param1 === "number" && typeof param2 === "number" && param1 > param2; - } - case "<": { - return typeof param1 === "number" && typeof param2 === "number" && param1 < param2; - } - case ">=": { - return typeof param1 === "number" && typeof param2 === "number" && param1 >= param2; - } - case "<=": { - return typeof param1 === "number" && typeof param2 === "number" && param1 <= param2; - } - case "??": { - return param1 ?? param2; - } - case "includes": { - return Array.isArray(param1) && param1.includes(param2); - } - case "in": { - if (Array.isArray(param2)) { - return param2.includes(param1); - } - if (U.isList(param2) && (typeof param1 === "number" || typeof param1 === "string")) { - return param1 in param2; - } - if (typeof param2 === "string") { - return new RegExp(String(param1), "gu").test(String(param2)); - } - return false; - } - default: { - return false; - } - } - }, - calc(...params) { - const calcs = { - "+": (p1, p2) => U.pInt(p1) + U.pInt(p2), - "-": (p1, p2) => U.pInt(p1) - U.pInt(p2), - "*": (p1, p2) => U.pInt(p1) * U.pInt(p2), - "/": (p1, p2) => U.pInt(p1) / U.pInt(p2), - "%": (p1, p2) => U.pInt(p1) % U.pInt(p2), - max: (p1, p2) => Math.max(U.pInt(p1), U.pInt(p2)), - min: (p1, p2) => Math.min(U.pInt(p1), U.pInt(p2)), - ceil: (p1) => Math.ceil(U.pFloat(p1)), - floor: (p1) => Math.floor(U.pFloat(p1)) - }; - const [param1, operator, param2] = typeof params[0] === "string" && params[0] in calcs - ? [params[1], params[0]] - : params; - return calcs[operator](param1, param2); - }, - isIn(...args) { - const [testStr, ...contents] = args; - return contents.includes(testStr); - }, - case(mode, str) { - switch (mode) { - case "upper": return U.uCase(str); - case "lower": return U.lCase(str); - case "sentence": return U.sCase(str); - case "title": return U.tCase(str); - default: return str; - } - }, - romanize(val) { - return U.romanizeNum(U.pInt(val)); - }, - count(param) { - if (Array.isArray(param) || U.isList(param)) { - return Object.values(param).filter((val) => val !== null && val !== undefined).length; - } - else if (typeof param === "string") { - return param.length; - } - return param ? 1 : 0; - }, - // Concat helper - // Usage: (concat 'first 'second') - concat(...args) { - let outStr = ""; - for (const arg of args) { - if (typeof arg === "string" || typeof arg === "number") { - outStr += arg; - } - } - return outStr; - }, - // Merge helper - To merge additional properties into a template's context - merge(context, ...args) { - args.pop(); - return args.reduce((acc, val) => Object.assign(acc, val), context); - }, - // For loop: {{#for [from = 0, to, stepSize = 1]}}{{/for}} - for: (...args) => { - const options = args.pop(); - let [from, to, stepSize] = args; - from = U.pInt(from); - to = U.pInt(to); - stepSize = U.pInt(stepSize) || 1; - if (from > to) { - return ""; - } - let html = ""; - for (let i = parseInt(from || 0, 10); i <= parseInt(to || 0, 10); i += stepSize) { - html += options.fn(i); - } - return html; - }, - signNum(num) { - return U.signNum(num); - }, - compileSvg(...args) { - const [svgDotKey, svgPaths] = args; - return U.getSvgCode(svgDotKey, svgPaths); - }, - eLog(...args) { - args.pop(); - let dbLevel = 3; - if ([0, 1, 2, 3, 4, 5].includes(args[0])) { - dbLevel = args.shift(); - } - eLog.hbsLog(...args, dbLevel); - }, - // Does the name of this turf block represent a standard 'Turf' claim? - isTurfBlock: (name) => U.fuzzyMatch(name, "Turf"), - // Which other connection does this connector overlap with? - getConnectorPartner: (index, direction) => { - index = parseInt(`${index}`, 10); - const partners = { - 1: { right: 2, bottom: 6 }, - 2: { left: 1, right: 3, bottom: 7 }, - 3: { left: 2, right: 4, bottom: 8 }, - 4: { left: 3, right: 5, bottom: 9 }, - 5: { left: 4, bottom: 10 }, - 6: { top: 1, right: 7, bottom: 11 }, - 7: { top: 2, left: 6, right: 8, bottom: 12 }, - 8: { top: 3, left: 7, right: 9, bottom: 13 }, - 9: { top: 4, left: 8, right: 10, bottom: 14 }, - 10: { top: 5, left: 9, bottom: 15 }, - 11: { top: 6, right: 12 }, - 12: { top: 7, left: 11, right: 13 }, - 13: { top: 8, left: 12, right: 14 }, - 14: { top: 9, left: 13, right: 15 }, - 15: { top: 10, left: 14 } - }; - const partnerDir = { left: "right", right: "left", top: "bottom", bottom: "top" }[direction]; - const partnerNum = partners[index][direction] ?? 0; - if (partnerNum) { - return `${partnerNum}-${partnerDir}`; - } - return null; - }, - // Is the value Turf side. - isTurfOnEdge: (index, direction) => { - index = parseInt(`${index}`, 10); - const edges = { - 1: ["top", "left"], - 2: ["top"], - 3: ["top"], - 4: ["top"], - 5: ["top", "right"], - 6: ["left"], - 7: [], - 8: [], - 9: [], - 10: ["right"], - 11: ["left", "bottom"], - 12: ["bottom"], - 13: ["bottom"], - 14: ["bottom"], - 15: ["right", "bottom"] - }; - if (!(index in edges)) { - return true; - } - return edges[index].includes(direction); - }, - // Multiboxes - multiboxes(selected, options) { - let html = options.fn(this); - selected = [selected].flat(1); - selected.forEach((selectedVal) => { - if (selectedVal !== false) { - const escapedValue = RegExp.escape(Handlebars.escapeExpression(String(selectedVal))); - const rgx = new RegExp(` value="${escapedValue}"`); - html = html.replace(rgx, "$& checked=\"checked\""); - } - }); - return html; - }, - repturf: (turfsAmount, options) => { - let html = options.fn(this); - let turfsAmountInt = parseInt(turfsAmount, 10); - // Can't be more than 6. - if (turfsAmountInt > 6) { - turfsAmountInt = 6; - } - for (let i = 13 - turfsAmountInt; i <= 12; i++) { - const rgx = new RegExp(` value="${i}"`); - html = html.replace(rgx, "$& disabled=\"disabled\""); - } - return html; - } -}; -handlebarHelpers.eLog1 = function (...args) { handlebarHelpers.eLog(...[1, ...args.slice(0, 7)]); }; -handlebarHelpers.eLog2 = function (...args) { handlebarHelpers.eLog(...[2, ...args.slice(0, 7)]); }; -handlebarHelpers.eLog3 = function (...args) { handlebarHelpers.eLog(...[3, ...args.slice(0, 7)]); }; -handlebarHelpers.eLog4 = function (...args) { handlebarHelpers.eLog(...[4, ...args.slice(0, 7)]); }; -handlebarHelpers.eLog5 = function (...args) { handlebarHelpers.eLog(...[5, ...args.slice(0, 7)]); }; -Object.assign(handlebarHelpers); -/** - * - */ -export function registerHandlebarHelpers() { - Object.entries(handlebarHelpers).forEach(([name, func]) => Handlebars.registerHelper(name, func)); -} -// #endregion ▄▄▄▄▄ Handlebars ▄▄▄▄▄ diff --git a/module/core/logger.js b/module/core/logger.js deleted file mode 100644 index 6ce6384f..00000000 --- a/module/core/logger.js +++ /dev/null @@ -1,185 +0,0 @@ -import U from "./utilities.js"; -import C from "./constants.js"; -const LOGGERCONFIG = { - fullName: "eLogger", - aliases: ["dbLog"], - stackTraceExclusions: { - handlebars: [/scripts\/handlebars/] // From internal Handlebars module - } -}; -const STYLES = { - base: { - background: C.Colors.BLACK, - color: C.Colors.dGOLD, - "font-family": "Pragmata Pro", - padding: "0 25px", - "margin-right": "25px" - }, - log0: { - background: C.Colors.dGOLD, - color: C.Colors.dBLACK, - "font-size": "16px" - }, - log1: { - background: C.Colors.dBLACK, - color: C.Colors.bGOLD, - "font-size": "16px" - }, - log2: { - background: C.Colors.dBLACK, - color: C.Colors.dGOLD, - "font-size": "16px" - }, - log3: { - "font-size": "14px" - }, - log4: { - "font-size": "12px" - }, - log5: { - background: C.Colors.dGREY, - color: C.Colors.bGREY, - "font-size": "10px" - }, - display: { - color: C.Colors.bGOLD, - "font-family": "Kirsty", - "font-size": "16px", - "margin-left": "-100px", - padding: "0 100px" - }, - warn: { - color: C.Colors.dBLACK, - background: C.Colors.dGOLD, - "font-weight": 500 - }, - error: { - color: C.Colors.bRED, - background: C.Colors.ddRED, - "font-weight": 500 - }, - handlebars: { - background: C.Colors.GREY, - color: C.Colors.BLUE, - "font-family": "Pragmata Pro", - padding: "0", - "margin-right": "25px" - }, - stack: { - color: C.Colors.GOLD, - "font-weight": 100, - "font-size": "10px", - "font-family": "Pragmata Pro" - } -}; -const { base: baseStyles, ...typeStyles } = STYLES; -const STYLELINES = Object.fromEntries(Object.entries(typeStyles) - .map(([styleName, styles]) => [ - styleName, - Object.entries({ ...baseStyles, ...styles }) - .map(([prop, val]) => `${prop}: ${val};`).join(" ") -])); -const eLogger = (type = "base", ...content) => { - if (!(["error", "display"].includes(type) || CONFIG.debug.logging)) { - return; - } - const lastElem = U.getLast(content); - let dbLevel = typeof lastElem === "number" && [0, 1, 2, 3, 4, 5].includes(lastElem) - ? content.pop() - : 3; - let key = false; - if (type === "checkLog") { - key = content.shift(); - type = `log${dbLevel}`; - } - const [message, ...data] = content; - if (key) { - const blacklist = (U.getSetting("blacklist") ?? "").split(/,/).map((pat) => new RegExp(`\\b${pat.trim()}\\b`, "igu")); - const whitelist = (U.getSetting("whitelist") ?? "").split(/,/).map((pat) => new RegExp(`\\b${pat.trim()}\\b`, "igu")); - const isBlack = blacklist.some((pat) => pat.test(key)); - const isWhite = whitelist.some((pat) => pat.test(key)); - if (isBlack && !isWhite) { - dbLevel = Math.max(4, Math.min(5, dbLevel + 2)); - } - if (isWhite && !isBlack) { - dbLevel = Math.min(3, Math.max(1, dbLevel - 2)); - } - } - if ((U.getSetting("debug") ?? 5) < dbLevel) { - return; - } - if (type === "log") { - type = `${type}${dbLevel}`; - } - const stackTrace = type === "display" - ? null - : getStackTrace(LOGGERCONFIG.stackTraceExclusions[type] ?? []); - let logFunc; - if (stackTrace) { - logFunc = console.groupCollapsed; - } - else if (data.length <= 1) { - logFunc = console.log; - } - else { - logFunc = console.group; - } - if (data.length === 0) { - if (typeof message === "string") { - logFunc(`%c${message}`, STYLELINES[type]); - } - else { - logFunc("%o", message); - } - } - else { - logFunc(`%c${message}${typeof data[0] === "string" ? "" : " %o"}`, STYLELINES[type], data.shift()); - data.forEach((line) => { - if (typeof line === "string") { - console.log(line); - } - else { - console.log("%o", line); - } - }); - } - if (stackTrace) { - console.group("%cSTACK TRACE", `color: ${C.Colors.dGOLD}; font-family: "Pragmata Pro"; font-size: 12px; background: ${C.Colors.BLACK}; font-weight: bold; padding: 0 10px;`); - console.log(`%c${stackTrace}`, Object.entries(STYLES.stack).map(([prop, val]) => `${prop}: ${val};`).join(" ")); - console.groupEnd(); - } - console.groupEnd(); - /** - * - * @param regExpFilters - */ - function getStackTrace(regExpFilters = []) { - regExpFilters.push(new RegExp(`at (getStackTrace|${LOGGERCONFIG.fullName}|${LOGGERCONFIG.aliases.map(String).join("|")}|Object\\.(log|display|hbsLog|error))`), /^Error/); - return ((new Error()).stack ?? "") - .split(/\n/) - .map((sLine) => sLine.trim()) - .filter((sLine) => !regExpFilters.some((rTest) => rTest.test(sLine))) - .join("\n"); - } -}; -const logger = { - display: (...content) => eLogger("display", ...content), - log0: (...content) => eLogger("log", ...content, 0), - log1: (...content) => eLogger("log", ...content, 1), - log2: (...content) => eLogger("log", ...content, 2), - log: (...content) => eLogger("log", ...content, 3), - log3: (...content) => eLogger("log", ...content, 3), - log4: (...content) => eLogger("log", ...content, 4), - log5: (...content) => eLogger("log", ...content, 5), - checkLog0: (...content) => eLogger("checkLog", ...content, 0), - checkLog1: (...content) => eLogger("checkLog", ...content, 1), - checkLog2: (...content) => eLogger("checkLog", ...content, 2), - checkLog: (...content) => eLogger("checkLog", ...content, 3), - checkLog3: (...content) => eLogger("checkLog", ...content, 3), - checkLog4: (...content) => eLogger("checkLog", ...content, 4), - checkLog5: (...content) => eLogger("checkLog", ...content, 5), - warn: (...content) => eLogger("warn", ...content), - error: (...content) => eLogger("error", ...content), - hbsLog: (...content) => eLogger("handlebars", ...content) -}; -export default logger; diff --git a/module/core/settings.js b/module/core/settings.js deleted file mode 100644 index 1e7eae55..00000000 --- a/module/core/settings.js +++ /dev/null @@ -1,206 +0,0 @@ -import U from "./utilities.js"; -import C from "./constants.js"; -const registerSettings = function () { - game.settings.register("eunos-blades", "debug", { - name: "Debug Level", - hint: "The verbosity of the debug messages to console.", - scope: "client", // This specifies a world-level setting - config: true, // This specifies that the setting appears in the configuration view - type: Number, - range: { - min: 0, - max: 5, - step: 1 - }, - default: 3 // The default value for the setting - }); - game.settings.register("eunos-blades", "debugHooks", { - name: "Debug HOOKS", - hint: "Whether all Hooks are logged to the console.", - scope: "client", - config: true, - type: Boolean, - default: false - }); - game.settings.register("eunos-blades", "openAPIModelLevel", { - name: "AI Base Quality", - hint: "Lower values are cheaper to run, at the cost of quality.", - scope: "client", // This specifies a world-level setting - config: true, // This specifies that the setting appears in the configuration view - type: Number, - range: { - min: 0, - max: 2, - step: 1 - } - }); - game.settings.register("eunos-blades", "blacklist", { - name: "Debug Blacklist", - hint: "Comma-delimited list of categories of debug messages to silence.", - scope: "client", // This specifies a world-level setting - config: true, // This specifies that the setting appears in the configuration view - type: String, - default: "" // The default value for the setting - }); - game.settings.register("eunos-blades", "openAPIKey", { - name: "OpenAI API Key", - hint: "Your personal OpenAI API Key (necessary to enable AI functionality)", - scope: "client", // This specifies a world-level setting - config: true, // This specifies that the setting appears in the configuration view - type: String, - default: "" // The default value for the setting - }); - game.settings.register("eunos-blades", "whitelist", { - name: "Debug Whitelist", - hint: "Comma-delimited list of categories of debug messages to promote.", - scope: "client", // This specifies a world-level setting - config: true, // This specifies that the setting appears in the configuration view - type: String, - default: "" // The default value for the setting - }); - /** - * Track the system version upon which point a migration was last applied - */ - game.settings.register("eunos-blades", "systemMigrationVersion", { - name: "System Migration Version", - scope: "world", - config: false, - type: Number, - default: 0 - }); -}; -/** - * - */ -export function initTinyMCEStyles() { - CONFIG.TinyMCE = { - ...CONFIG.TinyMCE, - ...{ - skin: "skin", - skin_url: "systems/eunos-blades/css/tinymce/skin", - content_css: `systems/eunos-blades/css/tinymce/content.css?${new Date().getTime()}`, - font_css: "systems/eunos-blades/css/fonts.css", - max_height: 500, - min_height: 40, - autoresize_overflow_padding: 0, - autoresize_bottom_margin: 0, // 25, - menubar: false, - statusbar: false, // True, - elementPath: true, - branding: false, - resize: false, - plugins: "lists image table code save autoresize searchreplace quickbars template", - save_enablewhendirty: false, - // Table_default_styles: {}, - style_formats: [ - { - title: "Headings", - items: [ - { title: "Heading 1", block: "h1", wrapper: false }, - { title: "Heading 2", block: "h2", wrapper: false }, - { title: "Heading 3", block: "h3", wrapper: false }, - { title: "Heading 4", block: "h4", wrapper: false } - ] - }, - { - title: "Blocks", - items: [ - { title: "Paragraph", block: "p", wrapper: false }, - { title: "Block Quote", block: "blockquote", wrapper: true } - // {title: "Secret", block: "span", classes: "text-secret", attributes: {"data-is-secret": "true"}, wrapper: false} - ] - }, - { - title: "Inline", - items: [ - { title: "Bold", inline: "b", wrapper: false }, - { title: "Italics", inline: "i", wrapper: false }, - { title: "Underline", inline: "u", wrapper: false }, - { title: "Secret", inline: "span", classes: "text-secret", attributes: { "data-is-secret": "true" }, wrapper: false } - ] - } - ], - style_formats_merge: false, - toolbar: "styles | searchreplace | formatting alignment lists elements | removeformat | code | save", - toolbar_groups: { - formatting: { - icon: "color-picker", - tooltip: "Formatting", - items: "bold italic underline" - }, - alignment: { - icon: "align-left", - tooltip: "Alignment", - items: "alignleft aligncenter alignright alignjustify | outdent indent" - }, - lists: { - icon: "unordered-list", - tooltip: "Lists", - items: "bullist numlist" - }, - elements: { - icon: "duplicate", - tooltip: "Insert Element", - items: "tableinsertdialog image hr | template" - } - }, - toolbar_mode: "floating", - quickbars_link_toolbar: false, - quickbars_selection_toolbar: "styles | bold italic underline", - quickbars_insert_toolbar: "hr image table", - quickbars_table_toolbar: "tableprops tabledelete | tableinsertrowbefore tableinsertrowafter tabledeleterow | tableinsertcolbefore tableinsertcolafter tabledeletecol" - } - }; -} -/** - * - */ -export function initCanvasStyles() { - CONFIG.canvasTextStyle = new PIXI.TextStyle({ - align: "center", - dropShadow: true, - dropShadowAngle: U.degToRad(45), - dropShadowBlur: 8, - dropShadowColor: C.Colors.BLACK, - dropShadowDistance: 4, - fill: [ - C.Colors.bWHITE, - C.Colors.bGREY - ], - fillGradientType: 1, - fillGradientStops: [ - 0, - 0.3 - ], - fontFamily: "Kirsty", - fontSize: 32, - letterSpacing: 2, - lineHeight: 32, - lineJoin: "round", - padding: 4, - stroke: C.Colors.dBLACK, - strokeThickness: 3, - trim: true, - whiteSpace: "normal", - wordWrap: true, - wordWrapWidth: 0.1 - }); -} -export function initDOMStyles() { - // Create a full-screen background gradient that resembles the gradient described in CONFIG-canvasTextStyles - // This will serve as a fallback background when the canvas has been disabled or is not available - $("body.vtt.game.system-eunos-blades") - .append(`
`); - // Append lightning-barrier background to #sidebar - $("#interface") - .append(`
-
`); /* - - - - - - - `); */ -} -export default registerSettings; diff --git a/module/core/tags.js b/module/core/tags.js deleted file mode 100644 index 84f396e3..00000000 --- a/module/core/tags.js +++ /dev/null @@ -1,116 +0,0 @@ -import Tagify from "../../lib/tagify/tagify.esm.js"; -import { Tag, MainDistrict, OtherDistrict, Vice, Playbook, BladesActorType } from "./constants.js"; -import U from "./utilities.js"; -const _onTagifyChange = (event, doc, targetKey) => { - const tagString = event.target.value; - if (tagString) { - const tags = JSON.parse(tagString).map(({ value }) => value); - doc.update({ [targetKey]: tags }); - } - else { - doc.update({ [targetKey]: [] }); - } -}; -const Tags = { - InitListeners: (html, doc) => { - /** - * Applies tags and Tagify functionality to a specified HTML element. - * @param {HTMLElement} elem The element to tagify. - * @param {Record} tags The tags, sorted into groups, to apply. - */ - function makeTagInput(elem, tags) { - // Create tagify instance; populate dropdown list with tags - const tagify = new Tagify(elem, { - enforceWhitelist: true, - editTags: false, - whitelist: Object.entries(tags) - .map(([dataGroup, tagList]) => tagList - .map((tag) => ({ - value: (new Handlebars.SafeString(tag)).toString(), - "data-group": dataGroup - }))) - .flat(), - dropdown: { - enabled: 0, - maxItems: 10000, - placeAbove: false, - appendTarget: html[0] - } - }); - tagify.dropdown.createListHTML = (optionsArr) => { - const map = {}; - return structuredClone(optionsArr) - .map((suggestion, idx) => { - const value = tagify.dropdown.getMappedValue.call(tagify, suggestion); - let tagHTMLString = ""; - if (!map[suggestion["data-group"]]) { - map[suggestion["data-group"]] = true; - if (Object.keys(map).length) { - tagHTMLString += ""; - } - tagHTMLString += ` -
-

${suggestion["data-group"]}

- `; - } - suggestion.value = - value && typeof value === "string" ? U.escapeHTML(value) : value; - tagHTMLString += tagify.settings.templates.dropdownItem.apply(tagify, [suggestion, idx]); - return tagHTMLString; - }) - .join(""); - }; - /** - * Returns the tag group to which a tag belongs, or false if no group found. - * @param {BladesTag|string} tag - * @returns {string|false} Either the group containing the given tag, or false if no group found. - */ - function findDataGroup(tag) { - for (const [group, tagList] of Object.entries(tags)) { - if (tagList.includes(tag)) { - return group; - } - } - return false; - } - // Check if element specifies an alternate schema target from doc.tags - const targetKey = $(elem).data("tagTarget") ?? "system.tags"; - const curTags = [getProperty(doc, targetKey) ?? []].flat().filter(Boolean); - tagify.addTags(curTags - .filter(findDataGroup) - .map((tag) => ({ - value: (new Handlebars.SafeString(tag)).toString(), - "data-group": findDataGroup(tag) - })), true, true); - // Add event listener for tag changes, setting defined target - // Wait briefly, so other tag elements' tags can be set before listener initializes - setTimeout(() => elem.addEventListener("change", (event) => { _onTagifyChange(event, doc, targetKey); }), 1000); - } - const systemTags = { - "System Tags": Object.values(Tag.System), - "Gear Tags": [ - ...Object.values(Tag.Gear), - ...Object.values(Tag.GearCategory) - ], - "Actor Tags": [ - ...Object.values(Tag.PC), - ...Object.values(Tag.NPC) - ], - Vices: Object.values(Vice), - Playbooks: Object.values(Playbook), - Inventions: Object.values(Tag.Invention), - "Gang Types": Object.values(Tag.GangType) - }; - const districtTags = { - "City Districts": Object.values(MainDistrict), - "Other Districts": Object.values(OtherDistrict) - }; - const factionTags = { Factions: game.actors - .filter((actor) => actor.type === BladesActorType.faction && actor.name !== null) - .map((faction) => faction.name) }; - $(html).find(".tags-gm").each((_, e) => makeTagInput(e, systemTags)); - $(html).find(".tags-district").each((_, e) => makeTagInput(e, districtTags)); - $(html).find(".tags-faction").each((_, e) => makeTagInput(e, factionTags)); - } -}; -export default Tags; diff --git a/module/core/utilities.js b/module/core/utilities.js deleted file mode 100644 index 055eb1b1..00000000 --- a/module/core/utilities.js +++ /dev/null @@ -1,2011 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// /// -// #region ▮▮▮▮▮▮▮ IMPORTS ▮▮▮▮▮▮▮ ~ -import C, { SVGDATA } from "./constants.js"; -// eslint-disable-next-line import/no-unresolved -import { gsap, TextPlugin, Flip, MotionPathPlugin } from "/scripts/greensock/esm/all.js"; -gsap.registerPlugin(MotionPathPlugin); -// #endregion ▮▮▮▮ IMPORTS ▮▮▮▮ -// #region ▮▮▮▮▮▮▮ [HELPERS] Internal Functions, Data & References Used by Utility Functions ▮▮▮▮▮▮▮ ~ -// _noCapWords -- Patterns matching words that should NOT be capitalized when converting to TITLE case. -const _noCapWords = "a|above|after|an|and|at|below|but|by|down|for|for|from|in|nor|of|off|on|onto|or|out|so|the|to|under|up|with|yet" - .split("|") - .map((word) => new RegExp(`\\b${word}\\b`, "gui")); -// _capWords -- Patterns matching words that should ALWAYS be capitalized when converting to SENTENCE case. -const _capWords = [ - "I", /[^a-z]{3,}|[.0-9]/gu -].map((word) => (/RegExp/.test(Object.prototype.toString.call(word)) ? word : new RegExp(`\\b${word}\\b`, "gui"))); -// _loremIpsumText -- Boilerplate lorem ipsum -const _loremIpsumText = `Lorem ipsum dolor sit amet, consectetur adipiscing elit. Suspendisse ultricies -nibh sed massa euismod lacinia. Aliquam nec est ac nunc ultricies scelerisque porta vulputate odio. -Integer gravida mattis odio, semper volutpat tellus. Ut elit leo, auctor eget fermentum hendrerit, -aliquet ac nunc. Suspendisse porta turpis vitae mi posuere molestie. Cras lectus lacus, vulputate a -vestibulum in, mattis vel mi. Mauris quis semper mauris. Praesent blandit nec diam eget tincidunt. Nunc -aliquet consequat massa ac lacinia. Ut posuere velit sagittis, vehicula nisl eget, fringilla nibh. Duis -volutpat mattis libero, a porttitor sapien viverra ut. Phasellus vulputate imperdiet ligula, eget -eleifend metus tempor nec. Nam eget sapien risus. Praesent id suscipit elit. Sed pellentesque ligula -diam, non aliquet magna feugiat vitae. Pellentesque ut tortor id erat placerat dignissim. Pellentesque -ut dui vel leo laoreet sodales nec ac tellus. In hac habitasse platea dictumst. Proin sed ex sed augue -sollicitudin interdum. Sed id lacus porttitor nisi vestibulum tincidunt. Nulla facilisi. Vestibulum -feugiat finibus magna in pretium. Proin consectetur lectus nisi, non commodo lectus tempor et. Cras -viverra, mi in consequat aliquet, justo mauris fringilla tellus, at accumsan magna metus in eros. Sed -vehicula, diam ut sagittis semper, purus massa mattis dolor, in posuere.`; -// _randomWords -- A collection of random words for various debugging purposes. -const _randomWords = ` -aboveboard|account|achiever|acoustics|act|action|activity|actor|addition|adjustment|advertisement|advice|afterglow|afterimage|afterlife|aftermath|afternoon|afterthought|agreement -air|aircraft|airfield|airlift|airline|airmen|airplane|airport|airtime|alarm|allover|allspice|alongside|also|amount|amusement|anger|angle|animal|another|ants|anyhow|anymore -anyone|anyplace|anytime|anywhere|apparatus|apparel|appliance|approval|arch|argument|arithmetic|arm|army|around|art|ashtray|attack|attraction|aunt|authority|babies|baby|babysitter -back|backache|backbone|backbreaker|backdrop|backfire|background|backhand|backlash|backlog|backpack|backside|backslap|backslide|backspace|backspin|backstroke|backtrack|backward -badge|bag|bait|balance|ball|ballroom|bankbook|bankroll|base|baseball|basin|basket|basketball|bat|bath|battle|beachcomb|bead|bear|because|become|bed|bedrock|bedroll|bedroom -beds|bee|beef|beginner|behavior|belief|believe|bell|bellboy|bellhop|bells|below|berry|bike|bikes|bird|birds|birth|birthday|bit|bite|blackball|blackberries|blackbird|blackboard -blackjack|blacklist|blackmail|blackout|blacksmith|blacktop|blade|blood|blow|blowgun|bluebell|blueberry|bluebird|bluefish|bluegrass|blueprint|board|boardwalk|boat|bodyguard -bomb|bone|book|bookcase|bookend|bookkeeper|bookmark|bookmobile|books|bookseller|bookshelf|bookworm|boot|border|bottle|boundary|bowlegs|bowtie|box|boy|brainchild|brake|branch -brass|breath|brick|bridge|brother|bubble|bucket|bugspray|building|bulb|burst|bushes|business|butter|butterball|buttercup|butterfingers|buttermilk|butternut|butterscotch|button -bypass|cabbage|cabdriver|cable|cactus|cake|cakes|calculator|calendar|camera|camp|can|cancan|candlelight|candlestick|cannon|cannot|canvas|cap|caption|car|card|cardsharp|care -carefree|careworn|carfare|carload|carpenter|carpool|carport|carriage|cars|carsick|cart|cartwheel|cast|cat|cats|cattle|catwalk|cause|cave|caveman|celery|cellar|cemetery|cent -centercut|chalk|chance|change|channel|cheese|cheeseburger|cherries|cherry|chess|chicken|chickens|children|chin|church|circle|clam|class|clockwise|cloth|clover|club|coach|coal -coast|coat|cobweb|coffeemaker|coil|collar|color|comeback|committee|commonplace|commonwealth|company|comparison|competition|condition|connection|control|cook|copper|corn|cornmeal -cough|country|courthouse|cover|cow|cows|crack|cracker|crate|crayon|cream|creator|creature|credit|crewcut|crib|crime|crook|crossbow|crossbreed|crosscut|crossover|crosswalk -crow|crowd|crown|cub|cup|current|curtain|curve|cushion|dad|dairymaid|daisywheel|daughter|day|daybed|daybook|daybreak|daydream|daylight|daytime|deadend|deadline|death|debt -decision|deer|degree|design|desire|desk|destruction|detail|development|digestion|dime|dinner|dinosaurs|direction|dirt|discovery|discussion|dishcloth|dishpan|dishwasher|dishwater -diskdrive|distance|distribution|division|dock|doctor|dog|dogs|doll|dolls|donkey|door|doorstop|downtown|downunder|drain|drawbridge|drawer|dress|drink|driveway|driving|drop -duck|duckbill|duckpin|ducks|dust|ear|earache|earring|earth|earthquake|earthward|earthworm|edge|education|effect|egg|egghead|eggnog|eggs|eggshell|elbow|end|engine|error|event -everything|example|exchange|existence|expansion|experience|expert|eye|eyeballs|eyecatching|eyeglasses|eyelash|eyelid|eyes|eyesight|eyewitness|face|fact|fairies|fall|fang|farm -fatherland|fear|feeling|field|finger|fire|fireball|fireboat|firebomb|firebreak|firecracker|firefighter|firehouse|fireman|fireproof|fireworks|fish|fishbowl|fisherman|fisheye -fishhook|fishmonger|fishnet|fishpond|fishtail|flag|flame|flavor|flesh|flight|flock|floor|flower|flowers|fly|fog|fold|food|foot|football|foothill|footlights|footlocker|footprints -forbearer|force|forearm|forebear|forebrain|forecast|foreclose|foreclosure|foredoom|forefather|forefeet|forefinger|forefoot|forego|foregone|forehand|forehead|foreknowledge -foreleg|foreman|forepaws|foresee|foreshadow|forestall|forethought|foretold|forever|forewarn|foreword|forget|fork|forklift|form|fowl|frame|friction|friend|friends|frog|frogs -front|fruit|fruitcup|fuel|furniture|gate|gearshift|geese|ghost|giants|giraffe|girl|girls|glass|glassmaking|glove|gold|goodbye|goodnight|government|governor|grade|grain|grandaunt -granddaughter|grandfather|grandmaster|grandmother|grandnephew|grandparent|grandson|grandstand|granduncle|grape|grass|grassland|graveyard|grip|ground|group|growth|guide|guitar -gumball|gun|hair|haircut|hall|hamburger|hammer|hand|handbook|handgun|handmade|handout|hands|harbor|harmony|hat|hate|head|headache|headlight|headline|headquarters|health|heat -hereafter|hereby|herein|hereupon|highchair|highland|highway|hill|himself|history|hobbies|hole|holiday|home|homemade|hometown|honey|honeybee|honeydew|honeysuckle|hook|hookup -hope|horn|horse|horseback|horsefly|horsehair|horseman|horseplay|horsepower|horseradish|horses|hose|hospital|hot|hour|house|houseboat|household|housekeeper|houses|housetop -however|humor|hydrant|ice|icicle|idea|impulse|income|increase|industry|ink|insect|inside|instrument|insurance|intake|interest|invention|iron|island|itself|jail|jailbait|jam -jar|jeans|jelly|jellybean|jellyfish|jetliner|jetport|jewel|join|judge|juice|jump|jumpshot|kettle|key|keyboard|keyhole|keynote|keypad|keypunch|keystone|keystroke|keyword|kick -kiss|kittens|kitty|knee|knife|knot|knowledge|laborer|lace|ladybug|lake|lamp|land|language|laugh|leather|leg|legs|letter|letters|lettuce|level|library|lifeblood|lifeguard|lifelike -lifeline|lifelong|lifetime|lifework|limelight|limestone|limit|line|linen|lip|liquid|loaf|lock|locket|longhand|look|loss|love|low|lukewarm|lumber|lunch|lunchroom|machine|magic -maid|mailbox|mainline|man|marble|mark|market|mask|mass|match|matchbox|meal|meantime|meanwhile|measure|meat|meeting|memory|men|metal|mice|middle|milk|mind|mine|minister|mint -minute|mist|mitten|mom|money|monkey|month|moon|moonbeam|moonlight|moonlit|moonscape|moonshine|moonstruck|moonwalk|moreover|morning|mother|motion|motorcycle|mountain|mouth -move|muscle|name|nation|nearby|neck|need|needle|nerve|nest|nevermore|newsboy|newsbreak|newscaster|newsdealer|newsletter|newsman|newspaper|newsprint|newsreel|newsroom|night -nightfall|nobody|noise|noisemaker|north|northeast|nose|note|notebook|nowhere|number|nursemaid|nut|nutcracker|oatmeal|observation|ocean|offer|office|oil|oneself|onetime|orange -oranges|order|oven|overboard|overcoat|overflow|overland|pacemaker|page|pail|pan|pancake|paper|parcel|part|partner|party|passbook|passenger|passkey|Passover|passport|payment -peace|pear|pen|pencil|peppermint|person|pest|pet|pets|pickle|pickup|picture|pie|pies|pig|pigs|pin|pinhole|pinstripe|pinup|pinwheel|pipe|pizzas|place|plane|planes|plant|plantation -plants|plastic|plate|play|playback|playground|playhouse|playthings|pleasure|plot|plough|pocket|point|poison|pollution|ponytail|popcorn|porter|position|postcard|pot|potato -powder|power|price|produce|profit|property|prose|protest|pull|pump|punishment|purpose|push|quarter|quartz|queen|question|quicksand|quiet|quill|quilt|quince|quiver|rabbit|rabbits -racquetball|rail|railroad|railway|rain|raincheck|raincoat|rainstorm|rainwater|rake|range|rat|rate|rattlesnake|rattletrap|ray|reaction|reading|reason|receipt|recess|record -regret|relation|religion|repairman|representative|request|respect|rest|reward|rhythm|rice|riddle|rifle|ring|rings|river|riverbanks|road|robin|rock|rod|roll|roof|room|root -rose|route|rub|rubberband|rule|run|sack|sail|sailboat|salesclerk|salt|sand|sandlot|sandstone|saucepan|scale|scapegoat|scarecrow|scarf|scene|scent|school|schoolbook|schoolboy -schoolbus|schoolhouse|science|scissors|screw|sea|seashore|seat|secretary|seed|selection|self|sense|servant|shade|shadyside|shake|shame|shape|sharecropper|sharpshooter|sheep -sheepskin|sheet|shelf|ship|shirt|shock|shoe|shoelace|shoemaker|shoes|shop|shortbread|show|showoff|showplace|side|sidekick|sidewalk|sign|silk|silver|silversmith|sink|sister -sisterhood|sisters|sixfold|size|skate|skateboard|skin|skintight|skirt|sky|skylark|skylight|slave|sleep|sleet|slip|slope|slowdown|slumlord|smash|smell|smile|smoke|snail|snails -snake|snakes|snakeskin|sneeze|snow|snowball|snowbank|snowbird|snowdrift|snowshovel|soap|society|sock|soda|sofa|softball|somebody|someday|somehow|someone|someplace|something -sometimes|somewhat|somewhere|son|song|songs|sort|sound|soundproof|soup|southeast|southwest|soybean|space|spacewalk|spade|spark|spearmint|spiders|spillway|spokesperson|sponge -spoon|spot|spring|spy|square|squirrel|stage|stagehand|stamp|standby|standoff|standout|standpoint|star|starfish|start|statement|station|steam|steamship|steel|stem|step|stepson -stew|stick|sticks|stitch|stocking|stockroom|stomach|stone|stop|stoplight|stopwatch|store|story|stove|stranger|straw|stream|street|stretch|string|stronghold|structure|substance -subway|sugar|suggestion|suit|summer|sun|sunbaked|sunbathe|sundial|sundown|sunfish|sunflower|sunglasses|sunlit|sunray|sunroof|sunup|supercargo|supercharge|supercool|superego -superfine|supergiant|superhero|superhighways|superhuman|superimpose|supermarket|supermen|supernatural|superpower|superscript|supersensitive|supersonic|superstar|superstrong -superstructure|supertanker|superweapon|superwoman|support|surprise|sweater|sweetheart|sweetmeat|swim|swing|system|table|tablecloth|tablespoon|tabletop|tableware|tail|tailcoat -tailgate|taillight|taillike|tailpiece|tailspin|takeoff|takeout|takeover|talebearer|taleteller|talk|tank|tapeworm|taproom|taproot|target|taskmaster|taste|tax|taxicab|taxpayer -teaching|teacup|team|teammate|teamwork|teapot|teaspoon|teenager|teeth|telltale|temper|tendency|tenderfoot|tenfold|tent|territory|test|textbook|texture|theory|therefore|thing -things|thought|thread|thrill|throat|throne|throwaway|throwback|thumb|thunder|thunderbird|thunderstorm|ticket|tiger|time|timekeeper|timesaving|timeshare|timetable|tin|title -toad|toe|toes|together|tomatoes|tongue|toolbox|tooth|toothbrush|toothpaste|toothpick|top|touch|touchdown|town|township|toy|toys|trade|trail|train|trains|tramp|transport|tray -treatment|tree|trees|trick|trip|trouble|trousers|truck|trucks|tub|turkey|turn|turnabout|turnaround|turnbuckle|turndown|turnkey|turnoff|turntable|twig|twist|typewriter|umbrella -uncle|underachieve|underage|underarm|underbelly|underbid|undercharge|underclothes|undercover|undercut|underdevelop|underestimate|underexpose|underfoot|underground|underwear -unit|upbeat|upbringing|upcoming|update|upend|upgrade|upheaval|uphill|uphold|upkeep|upland|uplift|upload|upmarket|upon|uppercase|upperclassman|uppercut|uproar|uproot|upset -upshot|upside|upstage|upstairs|upstanding|upstart|upstate|upstream|uptake|upthrust|uptight|uptime|uptown|upward|upwind|use|vacation|value|van|vase|vegetable|veil|vein|verse -vessel|vest|view|visitor|voice|volcano|volleyball|voyage|waistline|walk|walkways|wall|walleyed|wallpaper|war|wardroom|warfare|warmblooded|warpath|wash|washbowl|washcloth|washhouse -washout|washrag|washroom|washstand|washtub|waste|wastebasket|wasteland|wastepaper|wastewater|watch|watchband|watchdog|watchmaker|watchman|watchtower|watchword|water|watercolor -watercooler|watercraft|waterfall|waterfront|waterline|waterlog|watermelon|waterpower|waterproof|waterscape|watershed|waterside|waterspout|watertight|wave|wavelike|waves|wax -waxwork|way|waybill|wayfarer|waylaid|wayside|wayward|wealth|weather|weathercock|weatherman|weatherproof|week|weekday|weekend|weeknight|weight|whatever|whatsoever|wheel|wheelchair -wheelhouse|whip|whistle|whitecap|whitefish|whitewall|whitewash|widespread|wilderness|wind|window|wine|wing|winter|wipeout|wire|wish|without|woman|women|wood|woodshop|wool -word|work|worm|wound|wren|wrench|wrist|writer|writing|yak|yam|yard|yarn|year|yoke|zebra|zephyr|zinc|zipper|zoo -`.split("|"); -const _numberWords = { - ones: [ - "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", - "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", "sixteen", "seventeen", "eighteen", "nineteen", - "twenty" - ], - tens: ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"], - tiers: ["", "thousand", "million", "billion", "trillion", "quadrillion", "quintillion", "sextillion", "septillion", "octillion", "nonillion"], - bigPrefixes: ["", "un", "duo", "tre", "quattuor", "quin", "sex", "octo", "novem"], - bigSuffixes: ["", "decillion", "vigintillion", "trigintillion", "quadragintillion", "quinquagintillion", "sexagintillion", "septuagintillion", "octogintillion", "nonagintillion", "centillion"] -}; -const _ordinals = { - zero: "zeroeth", one: "first", two: "second", three: "third", four: "fourth", five: "fifth", eight: "eighth", nine: "ninth", twelve: "twelfth", - twenty: "twentieth", thirty: "thirtieth", forty: "fortieth", fifty: "fiftieth", sixty: "sixtieth", seventy: "seventieth", eighty: "eightieth", ninety: "ninetieth" -}; -const _romanNumerals = { - grouped: [ - ["", "Ⅰ", "Ⅱ", "Ⅲ", "Ⅳ", "Ⅴ", "Ⅵ", "Ⅶ", "Ⅷ", "Ⅸ"], - ["", "Ⅹ", "ⅩⅩ", "ⅩⅩⅩ", "ⅩⅬ", "Ⅼ", "ⅬⅩ", "ⅬⅩⅩ", "ⅬⅩⅩⅩ", "ⅩⅭ"], - ["", "Ⅽ", "ⅭⅭ", "ⅭⅭⅭ", "ⅭⅮ", "Ⅾ", "ⅮⅭ", "ⅮⅭⅭ", "ⅮⅭⅭⅭ", "ⅭⅯ"], - ["", "Ⅿ", "ⅯⅯ", "ⅯⅯⅯ", "Ⅿↁ", "ↁ", "ↁⅯ", "ↁⅯⅯ", "ↁⅯⅯⅯ", "ↁↂ"], - ["", "ↂ", "ↂↂ", "ↂↂↂ", "ↂↇ", "ↇ", "ↇↂ", "ↇↂↂ", "ↇↂↂↂ", "ↇↈ"], - ["", "ↈ", "ↈↈ", "ↈↈↈ"] - ], - ungrouped: [ - ["", "Ⅰ", "ⅠⅠ", "ⅠⅠⅠ", "ⅠⅤ", "Ⅴ", "ⅤⅠ", "ⅤⅠⅠ", "ⅤⅠⅠⅠ", "ⅠⅩ"], - ["", "Ⅹ", "ⅩⅩ", "ⅩⅩⅩ", "ⅩⅬ", "Ⅼ", "ⅬⅩ", "ⅬⅩⅩ", "ⅬⅩⅩⅩ", "ⅩⅭ"], - ["", "Ⅽ", "ⅭⅭ", "ⅭⅭⅭ", "ⅭⅮ", "Ⅾ", "ⅮⅭ", "ⅮⅭⅭ", "ⅮⅭⅭⅭ", "ⅭⅯ"], - ["", "Ⅿ", "ⅯⅯ", "ⅯⅯⅯ", "Ⅿↁ", "ↁ", "ↁⅯ", "ↁⅯⅯ", "ↁⅯⅯⅯ", "ↁↂ"], - ["", "ↂ", "ↂↂ", "ↂↂↂ", "ↂↇ", "ↇ", "ↇↂ", "ↇↂↂ", "ↇↂↂↂ", "ↇↈ"], - ["", "ↈ", "ↈↈ", "ↈↈↈ"] - ] -}; -const UUIDLOG = []; -// #endregion ▮▮▮▮[HELPERS]▮▮▮▮ -// #region ████████ GETTERS: Basic Data Lookup & Retrieval ████████ ~ -// @ts-expect-error Leauge of foundry developers is wrong about user not being on game. -const GMID = () => game?.user?.find((user) => user.isGM)?.id ?? false; -// #endregion ▄▄▄▄▄ GETTERS ▄▄▄▄▄ -// #region ████████ TYPES: Type Checking, Validation, Conversion, Casting ████████ ~ -const isNumber = (ref) => typeof ref === "number" && !isNaN(ref); -const isNumString = (ref) => typeof ref === "string" - && !isNaN(parseFloat(ref)) - && isFinite(parseFloat(ref)); -const isBooleanString = (ref) => typeof ref === "string" - && (ref === "true" || ref === "false"); -const isArray = (ref) => Array.isArray(ref); -const isSimpleObj = (ref) => ref === Object(ref) && !isArray(ref); -const isList = (ref) => ref === Object(ref) && !isArray(ref); -const isFunc = (ref) => typeof ref === "function"; -const isInt = (ref) => isNumber(ref) && Math.round(ref) === ref; -const isFloat = (ref) => isNumber(ref) && /\./.test(`${ref}`); -const isPosInt = (ref) => isInt(ref) && ref >= 0; -const isIndex = (ref) => isList(ref) || isArray(ref); -const isIterable = (ref) => typeof ref === "object" && ref !== null && Symbol.iterator in ref; -const isHTMLCode = (ref) => typeof ref === "string" && /^<.*>$/u.test(ref); -const isHexColor = (ref) => typeof ref === "string" && /^#(([0-9a-fA-F]{2}){3,4}|[0-9a-fA-F]{3,4})$/.test(ref); -const isRGBColor = (ref) => typeof ref === "string" && /^rgba?\((\d{1,3},\s*){1,2}?\d{1,3},\s*\d{1,3}(\.\d+)?\)$/.test(ref); -const isUndefined = (ref) => ref === undefined; -const isDefined = (ref) => !isUndefined(ref); -const isEmpty = (ref) => Object.keys(ref).length === 0; -const hasItems = (ref) => !isEmpty(ref); -const isInstance = (classRef, ref) => ref instanceof classRef; -const isNullish = (ref) => isUndefined(ref) || ref === null; -/** - * Asserts that a given value is of a specified type. - * Throws an error if the value is not of the expected type. - * - * @template T The expected type of the value. - * @param {unknown} val The value to check. - * @param {(new(...args: unknown[]) => T) | string} type The expected type of the value. - * @throws {Error} If the value is not of the expected type. - */ -function assertNonNullType(val, type) { - let valStr; - // Attempt to convert the value to a string for error messaging. - try { - valStr = JSON.stringify(val); - } - catch { - valStr = String(val); - } - // Check if the value is undefined - if (val === undefined) { - throw new Error(`Value ${valStr} is undefined!`); - } - // If the type is a string, compare the typeof the value to the type string. - if (typeof type === "string") { - // eslint-disable-next-line valid-typeof - if (typeof val !== type) { - throw new Error(`Value ${valStr} is not a ${type}!`); - } - } - else if (!(val instanceof type)) { - // If the type is a function (constructor), check if the value is an instance of the type. - throw new Error(`Value ${valStr} is not a ${type.name}!`); - } -} -/** - * Checks if two values are "fuzzy" equal, simulating the behavior of the "==" operator. - * This function does not use the "==" operator directly to comply with linting rules. - * - * @param {unknown} val1 The first value to compare. - * @param {unknown} val2 The second value to compare. - * @returns {boolean} True if the values are "fuzzy" equal, false otherwise. - */ -const areFuzzyEqual = (val1, val2) => { - // If both values are null or undefined, they are considered equal - if ([null, undefined].includes(val1) - && [null, undefined].includes(val2)) { - return true; - } - // If only one of the values is null or undefined, they are not equal - if ([null, undefined].includes(val1) - || [null, undefined].includes(val2)) { - return false; - } - // If both values are numbers, they are considered equal if they are numerically equal - if (typeof val1 === "number" && typeof val2 === "number") { - return val1 === val2; - } - // If both values are booleans, they are considered equal if they are both true or both false - if (typeof val1 === "boolean" && typeof val2 === "boolean") { - return val1 === val2; - } - // If both values are strings, they are considered equal if they are identical - if (typeof val1 === "string" && typeof val2 === "string") { - return val1 === val2; - } - // If one value is a number and the other is a string, they are considered - // equal if the string can be converted to the number - if (typeof val1 === "number" && typeof val2 === "string") { - return val1 === Number(val2); - } - if (typeof val1 === "string" && typeof val2 === "number") { - return Number(val1) === val2; - } - // If one value is a boolean and the other is a non-null object, they are not equal - if (typeof val1 === "boolean" && typeof val2 === "object") { - return false; - } - if (typeof val1 === "object" && typeof val2 === "boolean") { - return false; - } - // If one value is a boolean and the other is a string, they are considered equal ID: - // ... the boolean is true and the string is not empty, or - // ... the boolean is false and the string is empty - if (typeof val1 === "boolean" - && typeof val2 === "string") { - return (val1 && val2 !== "") || (!val1 && val2 === ""); - } - if (typeof val1 === "string" - && typeof val2 === "boolean") { - return (val2 && val1 !== "") || (!val2 && val1 === ""); - } - // If one value is a number or a string and the other is an object, they are not equal - if ((typeof val1 === "number" || typeof val1 === "string") && typeof val2 === "object") { - return false; - } - if (typeof val1 === "object" && (typeof val2 === "number" || typeof val2 === "string")) { - return false; - } - // If both values are objects, they are considered equal if they are identical - if (typeof val1 === "object" && typeof val2 === "object") { - return val1 === val2; - } - // If none of the above conditions are met, the values are not equal - return false; -}; -const areEqual = (...refs) => { - do { - const ref = refs.pop(); - if (refs.length && !areFuzzyEqual(ref, refs[0])) { - return false; - } - } while (refs.length); - return true; -}; -const pFloat = (ref, sigDigits, isStrict = false) => { - if (typeof ref === "string") { - ref = parseFloat(ref); - } - if (typeof ref === "number") { - if (isNaN(ref)) { - return isStrict ? NaN : 0; - } - if (isUndefined(sigDigits)) { - return ref; - } - return Math.round(ref * (10 ** sigDigits)) / (10 ** sigDigits); - } - return isStrict ? NaN : 0; -}; -const pInt = (ref, isStrictOrIndex, _arr) => { - let isStrict = false; - if (typeof isStrictOrIndex === "boolean") { - isStrict = isStrictOrIndex; - } - return (isNaN(pFloat(ref, 0, isStrict)) ? NaN : Math.round(pFloat(ref, 0, isStrict))); -}; -const pBool = (ref) => { - if (typeof ref === "boolean") { - return ref; - } - if ([0, null, undefined, ""].includes(ref)) { - return false; - } - if (typeof ref === "string") { - return !["0", "false", "null", "undefined", ""].includes(ref); - } - if (isArray(ref) && ref.length === 0) { - return false; - } - if (isList(ref) && isEmpty(ref)) { - return false; - } - return true; -}; -const radToDeg = (rad, isConstrained = true) => { - rad = isConstrained ? rad % (2 * Math.PI) : rad; - rad *= 180 / Math.PI; - return rad; -}; -const degToRad = (deg, isConstrained = true) => { - deg = isConstrained ? deg % 360 : deg; - deg *= Math.PI / 180; - return deg; -}; -const getKey = (key, obj) => { - if (key in obj) { - return obj[key]; - } - return null; -}; -const FILTERS = { - IsInstance: ((classRef) => ((item) => typeof classRef === "function" && item instanceof classRef)) -}; -// #endregion ▄▄▄▄▄ TYPES ▄▄▄▄▄ -// #region ████████ STRINGS: String Parsing, Manipulation, Conversion, Regular Expressions ████████ -// #region ░░░░░░░[Case Conversion]░░░░ Upper, Lower, Sentence & Title Case ░░░░░░░ ~ -const uCase = (str) => String(str).toUpperCase(); -const lCase = (str) => String(str).toLowerCase(); -const sCase = (str) => { - let [first, ...rest] = `${str ?? ""}`.split(/\s+/); - first = testRegExp(first, _capWords) ? first : `${uCase(first.charAt(0))}${lCase(first.slice(1))}`; - if (hasItems(rest)) { - rest = rest.map((word) => (testRegExp(word, _capWords) ? word : lCase(word))); - } - return [first, ...rest].join(" ").trim(); -}; -const tCase = (str) => String(str).split(/\s/) - .map((word, i) => (i && testRegExp(word, _noCapWords) ? lCase(word) : sCase(word))) - .join(" ").trim(); -// #endregion ░░░░[Case Conversion]░░░░ -// #region ░░░░░░░[RegExp]░░░░ Regular Expressions ░░░░░░░ ~ -const testRegExp = (str, patterns = [], flags = "gui", isTestingAll = false) => patterns - .map((pattern) => (pattern instanceof RegExp - ? pattern - : new RegExp(`\\b${pattern}\\b`, flags)))[isTestingAll ? "every" : "some"]((pattern) => pattern.test(`${str}`)); -const regExtract = (ref, pattern, flags) => { - /* Wrapper around String.match() that removes the need to worry about match()'s different handling of the 'g' flag. - - IF your pattern contains unescaped parentheses -> Returns Array of all matching groups. - - OTHERWISE -> Returns string that matches the provided pattern. */ - const splitFlags = []; - [...(flags ?? "").replace(/g/g, ""), "u"].forEach((flag) => { - if (flag && !splitFlags.includes(flag)) { - splitFlags.push(flag); - } - }); - const isGrouping = /[)(]/.test(pattern.toString().replace(/\\\)|\\\(/g, "")); - if (isGrouping) { - splitFlags.push("g"); - } - flags = splitFlags.join(""); - pattern = new RegExp(pattern, flags); - const matches = `${ref}`.match(pattern) || []; - return isGrouping ? Array.from(matches) : matches.pop(); -}; -// #endregion ░░░░[RegExp]░░░░ -// #region ░░░░░░░[Formatting]░░░░ Hyphenation, Pluralization, "a"/"an" Fixing ░░░░░░░ ~ -// const hyphenate = (str: unknown) => (/^<|\u00AD|\u200B/.test(`${str}`) ? `${str}` : _hyph(`${str}`)); -const unhyphenate = (str) => `${str}`.replace(/[\u00AD\u200B]/gu, ""); -const parseArticles = (str) => `${str}`.replace(/\b([aA])\s([aeiouAEIOU])/gu, "$1n $2"); -const pluralize = (singular, num = 2, plural) => { - if (pFloat(num) === 1) { - return singular; - } - return plural ?? `${singular.replace(/y$/, "ie").replace(/s$/, "se")}s`; -}; -const oxfordize = (items, useOxfordComma = true, andString = "and") => { - if (items.length === 0) { - return ""; - } - if (items.length === 1) { - return `${items[0]}`; - } - const lastItem = items.pop(); - return [ - items.join(", "), - useOxfordComma ? "," : "", - ` ${andString} `, - lastItem - ].join(""); -}; -const ellipsize = (text, maxLength) => { - const str = String(text); - return str.length > maxLength ? `${str.slice(0, maxLength - 3)}…` : str; -}; -const pad = (text, minLength, delim = " ") => { - const str = `${text}`; - if (str.length < minLength) { - return `${delim.repeat(minLength - str.length)}${str}`; - } - return str; -}; -const toKey = (text) => (text ?? "").toLowerCase().replace(/ /g, "-").replace(/default/, "DEFAULT"); -// #region ========== Numbers: Formatting Numbers Into Strings =========== ~ -const signNum = (num, delim = "", zeroSign = "+") => { - let sign; - const parsedNum = pFloat(num); - if (parsedNum < 0) { - sign = "-"; - } - else if (parsedNum === 0) { - sign = zeroSign; - } - else { - sign = "+"; - } - return `${sign}${delim}${Math.abs(parsedNum)}`; -}; -const padNum = (num, numDecDigits, includePlus = false) => { - const prefix = (includePlus && num >= 0) ? "+" : ""; - const [leftDigits, rightDigits] = `${pFloat(num)}`.split(/\./); - if (getType(rightDigits) === "int") { - if (rightDigits.length > numDecDigits) { - return `${prefix}${pFloat(num, numDecDigits)}`; - } - else if (rightDigits.length < numDecDigits) { - return `${prefix}${leftDigits}.${rightDigits}${"0".repeat(numDecDigits - rightDigits.length)}`; - } - else { - return `${prefix}${pFloat(num)}`; - } - } - return `${prefix}${leftDigits}.${"0".repeat(numDecDigits)}`; -}; -const stringifyNum = (num) => { - // Can take string representations of numbers, either in standard or scientific/engineering notation. - // Returns a string representation of the number in standard notation. - if (pFloat(num) === 0) { - return "0"; - } - const stringyNum = lCase(num).replace(/[^\d.e+-]/g, ""); - const base = regExtract(stringyNum, /^-?[\d.]+/); - const exp = pInt(regExtract(stringyNum, /e([+-]?\d+)$/)); - if (typeof base === "string" && typeof exp === "string") { - let baseInts = regExtract(base, /^-?(\d+)/); - let baseDecs = regExtract(base, /\.(\d+)/); - if (isArray(baseInts) && isArray(baseDecs)) { - baseInts = baseInts.pop()?.replace(/^0+/, ""); - baseDecs = lCase(baseDecs?.pop()).replace(/0+$/, ""); - if (!isUndefined(baseInts) && !isUndefined(baseDecs)) { - const numFinalInts = Math.max(0, baseInts.length + exp); - const numFinalDecs = Math.max(0, baseDecs.length - exp); - const finalInts = [ - baseInts.slice(0, numFinalInts), - baseDecs.slice(0, Math.max(0, exp)) - ].join("") || "0"; - const finalDecs = [ - baseInts.length - numFinalInts > 0 - ? baseInts.slice(baseInts.length - numFinalInts - 1) - : "", - baseDecs.slice(baseDecs.length - numFinalDecs) - ].join(""); - return [ - stringyNum.charAt(0) === "-" ? "-" : "", - finalInts, - "0".repeat(Math.max(0, numFinalInts - finalInts.length)), - finalDecs.length ? "." : "", - "0".repeat(Math.max(0, numFinalDecs - finalDecs.length)), - finalDecs - ].join(""); - } - } - } - return `${num}`; -}; -const verbalizeNum = (num) => { - // Converts a float with absolute magnitude <= 9.99e303 into words. - num = stringifyNum(num); - const getTier = (trioNum) => { - if (trioNum < _numberWords.tiers.length) { - return _numberWords.tiers[trioNum]; - } - return [ - _numberWords.bigPrefixes[(trioNum % 10) - 1], - _numberWords.bigSuffixes[Math.floor(trioNum / 10)] - ].join(""); - }; - const parseThreeDigits = (trio) => { - if (pInt(trio) === 0) { - return ""; - } - const digits = `${trio}`.split("").map((digit) => pInt(digit)); - let result = ""; - if (digits.length === 3) { - const hundreds = digits.shift(); - if (isUndefined(hundreds)) { - throw new Error(`[U.verbalizeNum] Undefined digit in trio '${digits.join("")}'.`); - } - result += hundreds > 0 ? `${_numberWords.ones[hundreds]} hundred` : ""; - if (hundreds && (digits[0] || digits[1])) { - result += " and "; - } - } - if (pInt(digits.join("")) <= _numberWords.ones.length) { - result += _numberWords.ones[pInt(digits.join(""))]; - } - else { - const tens = _numberWords.tens[pInt(digits.shift())]; - const ones = pInt(digits[0]) > 0 ? `-${_numberWords.ones[pInt(digits[0])]}` : ""; - result += `${tens}${ones}`; - } - return result; - }; - const numWords = []; - if (num.charAt(0) === "-") { - numWords.push("negative"); - } - const [integers, decimals] = num.replace(/[,\s-]/g, "").split("."); - const intArray = [...integers.split("")].reverse().join("") - .match(/.{1,3}/g) - ?.map((v) => [...v.split("")].reverse().join("")) ?? []; - const intStrings = []; - while (intArray.length) { - const thisTrio = intArray.pop(); - if (thisTrio) { - const theseWords = parseThreeDigits(thisTrio); - if (theseWords) { - intStrings.push(`${theseWords} ${getTier(intArray.length)}`); - } - } - } - numWords.push(intStrings.join(", ").trim()); - if (getType(decimals) === "int") { - if (integers === "0") { - numWords.push("zero"); - } - numWords.push("point"); - for (const digit of decimals.split("")) { - numWords.push(_numberWords.ones[pInt(digit)]); - } - } - return numWords.join(" "); -}; -const ordinalizeNum = (num, isReturningWords = false) => { - if (isReturningWords) { - const [numText, suffix] = lCase(verbalizeNum(num)).match(/.*?[-\s]?(\w*)$/i) ?? ["", ""]; - return numText.replace(new RegExp(`${suffix}$`), suffix in _ordinals ? _ordinals[suffix] : `${suffix}th`); - } - if (/(\.)|(1[1-3]$)/.test(`${num}`)) { - return `${num}th`; - } - return `${num}${["th", "st", "nd", "rd", "th", "th", "th", "th", "th", "th"][pInt(`${num}`.charAt(`${num}`.length - 1))]}`; -}; -const romanizeNum = (num, isUsingGroupedChars = true) => { - if (isFloat(num)) { - throw new Error(`Error: Can't Romanize Floats (${num})`); - } - if (num >= 400000) { - throw new Error(`Error: Can't Romanize >= 400,000 (${num})`); - } - if (num < 0) { - throw new Error(`Error: Can't Romanize Negative Numbers (${num})`); - } - if (num === 0) { - return "0"; - } - const romanRef = _romanNumerals[isUsingGroupedChars ? "grouped" : "ungrouped"]; - const romanNum = [...stringifyNum(num).split("")] - .reverse() - .map((digit, i) => romanRef[i][pInt(digit)]) - .reverse() - .join(""); - return isUsingGroupedChars - ? romanNum.replace(/ⅩⅠ/gu, "Ⅺ").replace(/ⅩⅡ/gu, "Ⅻ") - : romanNum; -}; -// #endregion _______ Numbers _______ -// #endregion ░░░░[Formatting]░░░░ -// #region ░░░░░░░[Content]░░░░ Lorem Ipsum, Random Content Generation, Randum UUID ░░░░░░░ ~ -const loremIpsum = (numWords = 200) => { - const lrWordList = _loremIpsumText.split(/\n?\s+/g); - const words = [...lrWordList[randNum(0, lrWordList.length - 1)]]; - while (words.length < numWords) { - words.push(...lrWordList); - } - words.length = numWords; - return `${sCase(words.join(" ")).trim().replace(/[^a-z\s]*$/ui, "")}.`; -}; -const randString = (length = 5) => Array.from({ length }) - .map(() => String.fromCharCode(randInt(...["a", "z"].map((char) => char.charCodeAt(0))))) - .join(""); -const randWord = (numWords = 1, wordList = _randomWords) => Array.from({ length: numWords }).map(() => randElem([...wordList])).join(" "); -const getUID = (id) => { - const indexNum = Math.max(0, ...UUIDLOG.filter(([genericID]) => genericID.startsWith(id)).map(([, , num]) => num)) + 1; - const uuid = indexNum === 1 ? id : `${id}_${indexNum}`; - UUIDLOG.push([id, uuid, indexNum]); - eLog.log(`UUIDify(${id}) --> [${uuid}, ${indexNum}]`); - Object.assign(globalThis, { UUIDLOG }); - return uuid; -}; -// #endregion ░░░░[Content]░░░░ -// #endregion ▄▄▄▄▄ STRINGS ▄▄▄▄▄ -// #region ████████ SEARCHING: Searching Various Data Types w/ Fuzzy Matching ████████ ~ -const fuzzyMatch = (val1, val2) => { - const [str1, str2] = [val1, val2].map((val) => lCase(String(val).replace(/[^a-zA-Z0-9.+-]/g, "").trim())); - return str1.length > 0 && str1 === str2; -}; -const isIn = (needle, haystack = [], fuzziness = 0) => { - // Looks for needle in haystack using fuzzy matching, then returns value as it appears in haystack. - // STEP ONE: POPULATE SEARCH TESTS ACCORDING TO FUZZINESS SETTING - const SearchTests = [ - (ndl, item) => new RegExp(`^${ndl}$`, "gu").test(`${item}`), - (ndl, item) => new RegExp(`^${ndl}$`, "gui").test(`${item}`) - ]; - if (fuzziness >= 1) { - const fuzzyTests = [ - (ndl, item) => new RegExp(`^${ndl}`, "gui").test(`${item}`), - (ndl, item) => new RegExp(`${ndl}$`, "gui").test(`${item}`), - (ndl, item) => new RegExp(`${ndl}`, "gui").test(`${item}`), - (ndl, item) => new RegExp(`${item}`, "gui").test(`${ndl}`) - ]; - SearchTests.push(...fuzzyTests); - if (fuzziness >= 2) { - SearchTests.push(...fuzzyTests - .map((func) => (ndl, item) => func(`${ndl}`.replace(/\W/g, ""), `${item}`.replace(/\W/gu, "")))); - if (fuzziness >= 3) { - SearchTests.push(() => false); // Have to implement Fuse matching - } - } - } - // STEP TWO: PARSE NEEDLE & CONSTRUCT SEARCHABLE HAYSTACK. - const searchNeedle = `${needle}`; - const searchStack = (() => { - if (isArray(haystack)) { - return [...haystack]; - } - if (isList(haystack)) { - return Object.keys(haystack); - } - try { - return Array.from(haystack); - } - catch { - throw new Error(`Haystack type must be [list, array], not ${typeof haystack}: ${JSON.stringify(haystack)}`); - } - })(); - if (!isArray(searchStack)) { - return false; - } - // STEP THREE: SEARCH HAY FOR NEEDLE USING PROGRESSIVELY MORE FUZZY SEARCH TESTS - let matchIndex = -1; - while (!isPosInt(matchIndex)) { - const testFunc = SearchTests.shift(); - if (!testFunc) { - return false; - } - matchIndex = searchStack.findIndex((item) => testFunc(searchNeedle, `${item}`)); - } - if (isPosInt(matchIndex)) { - return isList(haystack) ? Object.values(haystack)[matchIndex] : haystack[matchIndex]; - } - return false; -}; -const isInExact = (needle, haystack) => isIn(needle, haystack, 0); -// #endregion ▄▄▄▄▄ SEARCHING ▄▄▄▄▄ -// #region ████████ NUMBERS: Number Casting, Mathematics, Conversion ████████ ~ -const randNum = (min, max, snap = 0) => gsap.utils.random(min, max, snap); -const randInt = (min, max) => randNum(min, max, 1); -const coinFlip = () => randNum(0, 1, 1) === 1; -const cycleNum = (num, [min = 0, max = Infinity] = []) => gsap.utils.wrap(min, max, num); -const clampNum = (num, [min = 0, max = Infinity] = []) => gsap.utils.clamp(min, max, num); -const cycleAngle = (angle, range = [0, 360]) => cycleNum(angle, range); -const roundNum = (num, sigDigits = 0) => (sigDigits === 0 ? pInt(num) : pFloat(num, sigDigits)); -const sum = (...nums) => Object.values(nums.flat()).reduce((num, tot) => tot + num, 0); -const average = (...nums) => sum(...nums) / nums.flat().length; -// #region ░░░░░░░[Positioning]░░░░ Relationships On 2D Cartesian Plane ░░░░░░░ ~ -const getDistance = ({ x: x1, y: y1 }, { x: x2, y: y2 }) => (((x1 - x2) ** 2) + ((y1 - y2) ** 2)) ** 0.5; -const getAngle = ({ x: x1, y: y1 }, { x: x2, y: y2 }, { x: xO, y: yO } = { x: 0, y: 0 }, range = [0, 360]) => { - x1 -= xO; - y1 -= yO; - x2 -= xO; - y2 -= yO; - return cycleAngle(radToDeg(Math.atan2(y2 - y1, x2 - x1)), range); -}; -const getAngleDelta = (angleStart, angleEnd, range = [0, 360]) => cycleAngle(angleEnd - angleStart, range); -/** - * Function to calculate the smallest rectangle that can contain all the given shapes. - * @param arrayOfShapes - Array of objects, each describing a shape's position and size. - * @returns An object describing the position (center) and size of the smallest rectangle that can contain all the shapes. - */ -const getBoundingRectangle = (arrayOfShapes) => { - // Initialize the minimum and maximum x and y coordinates. - let minX = Infinity; - let minY = Infinity; - let maxX = -Infinity; - let maxY = -Infinity; - // Iterate over the array of shapes. - for (const shape of arrayOfShapes) { - // Calculate the minimum and maximum x and y coordinates for the current shape. - let shapeMinX; - let shapeMinY; - let shapeMaxX; - let shapeMaxY; - if (shape.radius !== undefined) { - // The shape is a circle. - shapeMinX = shape.x - shape.radius; - shapeMinY = shape.y - shape.radius; - shapeMaxX = shape.x + shape.radius; - shapeMaxY = shape.y + shape.radius; - } - else if (shape.size !== undefined) { - // The shape is a square. - shapeMinX = (shape.x - shape.size) / 2; - shapeMinY = (shape.y - shape.size) / 2; - shapeMaxX = (shape.x + shape.size) / 2; - shapeMaxY = (shape.y + shape.size) / 2; - } - else if (shape.width !== undefined || shape.height !== undefined) { - // The shape is a rectangle (or possibly a square). - shape.width ??= shape.height; - shape.height ??= shape.width; - shapeMinX = (shape.x - shape.width) / 2; - shapeMinY = (shape.y - shape.height) / 2; - shapeMaxX = (shape.x + shape.width) / 2; - shapeMaxY = (shape.y + shape.height) / 2; - } - else { - throw new Error(`[getBoundingRectangle] Error: shape must be a circle, square, or rectangle, not ${JSON.stringify(shape)}`); - } - // Update the overall minimum and maximum x and y coordinates. - minX = Math.min(minX, shapeMinX); - minY = Math.min(minY, shapeMinY); - maxX = Math.max(maxX, shapeMaxX); - maxY = Math.max(maxY, shapeMaxY); - } - // Calculate the width and height of the smallest rectangle. - const width = maxX - minX; - const height = maxY - minY; - // Calculate the center of the rectangle. - const x = (minX + width) / 2; - const y = (minY + height) / 2; - // Return the position (center) and size of the smallest rectangle. - return { x, y, width, height }; -}; -// #endregion ░░░░[Positioning]░░░░ -// #endregion ▄▄▄▄▄ NUMBERS ▄▄▄▄▄ -// #region ████████ ARRAYS: Array Manipulation ████████ ~ -const randElem = (array) => gsap.utils.random(array); -const randIndex = (array) => randInt(0, array.length - 1); -const makeIntRange = (min, max) => { - const intRange = []; - for (let i = min; i <= max; i++) { - intRange.push(i); - } - return intRange; -}; -const makeCycler = (array, index = 0) => { - // Given an array and a starting index, returns a generator function that can be used - // to iterate over the array indefinitely, or wrap out-of-bounds index values - const wrapper = gsap.utils.wrap(array); - index--; - return (function* () { - while (true) { - index++; - yield wrapper(index); - } - })(); -}; -/** - * Returns the last element of an array, or the last value of an object literal. - * - * @param {Index} array An array or object literal - * @returns {Type|undefined} The last element, or undefined if empty. - */ -function getLast(array) { - array = Object.values(array); - if (array.length === 0) { - throw new Error("Cannot get last element of an empty array."); - } - return array[array.length - 1]; -} -// Const getLast = (array: Type[]): typeof array extends [] ? undefined : Type => ; -const unique = (array) => { - const returnArray = []; - array.forEach((item) => { if (!returnArray.includes(item)) { - returnArray.push(item); - } }); - return returnArray; -}; -const group = (array, key) => { - const returnObj = {}; - array.forEach((item) => { - const returnKey = item[key]; - let returnVal = returnObj[returnKey]; - if (!returnVal) { - returnVal = []; - returnObj[returnKey] = returnVal; - } - returnVal.push(item); - }); - return returnObj; -}; -const sample = (array, numElems = 1, isUniqueOnly = true, uniqueTestFunc = (e, a) => !a.includes(e)) => { - const elems = []; - let overloadCounter = 0; - while (elems.length < numElems && overloadCounter < 1000000) { - const randomElem = randElem(array); - if (isUniqueOnly && uniqueTestFunc(randomElem, elems)) { - elems.push(randomElem); - } - overloadCounter++; - } - return elems; -}; -const removeFirst = (array, element) => array.splice(array.findIndex((v) => v === element)); -/** - * This function removes and returns the first element in an array that equals the provided value - * or satisfies the provided testing function. - * If no elements satisfy the testing function, the function will return undefined. - * - * @param {T[]} array The array to be searched. - * @param {(T|((_v: T, _i?: number, _a?: T[]) => boolean))} checkFunc The testing function or value to be searched for. - * @returns {T | undefined} The first element in the array that passes the test. - * If no elements pass the test, return undefined. - */ -function pullElement(array, checkFunc) { - // Define the test function - let testFunction; - // If checkFunc is not a function, create a function that checks for equality with checkFunc - if (typeof checkFunc !== "function") { - testFunction = (_v) => _v === checkFunc; - } - else { - testFunction = checkFunc; - } - // Find the index of the first element that passes the test - const index = array.findIndex((v, i, a) => testFunction(v, i, a)); - // If no element passes the test, return undefined - if (index === -1) { - return undefined; - } - // Remove the element from the array and return it - return array.splice(index, 1).pop(); -} -const pullIndex = (array, index) => pullElement(array, (_, i) => i === index); -const subGroup = (array, groupSize) => { - const subArrays = []; - while (array.length > groupSize) { - const subArray = []; - while (subArray.length < groupSize) { - subArray.push(array.shift()); - } - subArrays.push(subArray); - } - subArrays.push(array); - return subArrays; -}; -const shuffle = (array) => { - let currentIndex = array.length; - let randomIndex; - // While there remain elements to shuffle. - while (currentIndex !== 0) { - // Pick a remaining element. - randomIndex = Math.floor(Math.random() * currentIndex); - currentIndex--; - // And swap it with the current element. - [array[currentIndex], array[randomIndex]] = [ - array[randomIndex], array[currentIndex] - ]; - } - return array; -}; -const toArray = (target) => { - return gsap.utils.toArray(target); -}; -// #endregion ▄▄▄▄▄ ARRAYS ▄▄▄▄▄ -// #region ████████ OBJECTS: Manipulation of Simple Key/Val Objects ████████ ~ -const checkVal = ({ k, v }, checkTest) => { - if (typeof checkTest === "function") { - if (isDefined(v)) { - return checkTest(v, k); - } - return checkTest(k); - } - if (typeof checkTest === "number") { - checkTest = `${checkTest}`; - } - return (new RegExp(checkTest)).test(`${v}`); -}; -/** - * Given an array or list and a search function, will remove the first matching element and return it. - * @param {Index} obj The array or list to be searched. - * @param {testFunc | number | string} checkTest The search function. - * @returns {unknown | false} - The removed element or false if no element was found. - */ -const remove = (obj, checkTest) => { - if (isArray(obj)) { - const index = obj.findIndex((v) => checkVal({ v }, checkTest)); - if (index >= 0) { - return removeElementFromArray(obj, index); - } - } - else if (isList(obj)) { - const [remKey] = Object.entries(obj).find(([k, v]) => checkVal({ k, v }, checkTest)) ?? []; - if (remKey) { - return removeElementFromList(obj, remKey); - } - } - return false; -}; -/** - * Removes an element from an array at a given index and returns it. - * @param {unknown[]} array The array to remove the element from. - * @param {number} index The index of the element to remove. - * @returns {unknown} - The removed element. - */ -const removeElementFromArray = (array, index) => { - let remVal; - for (let i = 0; i <= array.length; i++) { - if (i === index) { - remVal = array.shift(); - } - else { - array.push(array.shift()); - } - } - return remVal; -}; -/** - * Removes an element from a list at a given key and returns it. - * @param {List} list The list to remove the element from. - * @param {string} key The key of the element to remove. - * @returns {unknown} - The removed element. - */ -const removeElementFromList = (list, key) => { - const remVal = list[key]; - delete list[key]; - return remVal; -}; -const replace = (obj, checkTest, repVal) => { - // As remove, except instead replaces the element with the provided value. - // Returns true/false to indicate whether the replace action succeeded. - let repKey; - if (isList(obj)) { - [repKey] = Object.entries(obj).find((v) => checkVal({ v }, checkTest)) || [false]; - if (repKey === false) { - return false; - } - } - else if (isArray(obj)) { - repKey = obj.findIndex((v) => checkVal({ v }, checkTest)); - if (repKey === -1) { - return false; - } - } - if (typeof repKey !== "number") { - repKey = `${repKey}`; - } - if (typeof repVal === "function") { - // @ts-expect-error Need to figure out how to properly define testFunc (keyFunc/valFunc types?) - obj[repKey] = repVal(obj[repKey], repKey); - } - else { - // @ts-expect-error Need to figure out how to properly define testFunc (keyFunc/valFunc types?) - obj[repKey] = repVal; - } - return true; -}; -/** - * Cleans an object or value by removing specified values recursively. - * - * @template T - The type of the input object or value. - * @param {T} data The object or value to be cleaned. - * @param {Array} [remVals] An array of values to be removed during the cleaning process. - * @returns {T | Partial | "KILL"} - The cleaned version of the input object or value. - * If marked for removal, returns "KILL". - */ -const objClean = (data, remVals = [undefined, null, "", {}, []]) => { - const remStrings = remVals.map((rVal) => JSON.stringify(rVal)); - if (remStrings.includes(JSON.stringify(data)) || remVals.includes(data)) { - return "KILL"; - } - if (Array.isArray(data)) { - const newData = data.map((elem) => objClean(elem, remVals)) - .filter((elem) => elem !== "KILL"); - return Array.isArray(newData) && newData.length ? newData : "KILL"; - } - if (data && typeof data === "object" && JSON.stringify(data).startsWith("{")) { - const newData = Object.entries(data) - .map(([key, val]) => [key, objClean(val, remVals)]) - .filter(([, val]) => val !== "KILL"); - return newData.length ? Object.fromEntries(newData) : "KILL"; - } - return data; -}; -// Given an object and a predicate function, returns array of two objects: -// one with entries that pass, one with entries that fail. -const partition = (obj, predicate = () => true) => [ - objFilter(obj, predicate), - objFilter(obj, (v, k) => !predicate(v, k)) -]; -/** - * Zips two arrays into an object. - * - * @template T - The type of the keys. - * @template U - The type of the values. - * @param {T[]} keys - The array of keys. - * @param {U[]} values - The array of values. - * @returns {Record} - The resulting object. - * @throws {Error} - Throws an error if the arrays are not of equal length, if the keys are not unique, or if the keys are not of a type that can be used as object keys. - */ -const zip = (keys, values) => { - // Check that the arrays are of equal length - if (keys.length !== values.length) { - throw new Error("The arrays must be of equal length."); - } - // Check that the keys are unique - if (new Set(keys).size !== keys.length) { - throw new Error("The keys must be unique."); - } - // Zip the arrays into an object - const result = {}; - keys.forEach((key, i) => { - result[key] = values[i]; - }); - return result; -}; -function objMap(obj, keyFunc, valFunc) { - let valFuncTyped = valFunc; - let keyFuncTyped = keyFunc; - if (!valFuncTyped) { - valFuncTyped = keyFunc; - keyFuncTyped = false; - } - if (!keyFuncTyped) { - keyFuncTyped = ((k) => k); - } - if (Array.isArray(obj)) { - return obj.map(valFuncTyped); - } - return Object.fromEntries(Object.entries(obj).map(([key, val]) => { - assertNonNullType(valFuncTyped, "function"); - return [keyFuncTyped(key, val), valFuncTyped(val, key)]; - })); -} -/** - * This function returns the 'size' of any reference passed into it, following these rules: - * - object: the number of enumerable keys - * - array: the number of elements - * - false/null/undefined: 0 - * - anything else: 1 - */ -const objSize = (obj) => { - if (isSimpleObj(obj)) { - return Object.keys(obj).length; - } - if (isArray(obj)) { - return obj.length; - } - if (obj === false || obj === null || obj === undefined) { - return 0; - } - return 1; -}; -/** - * This function is an object-equivalent of Array.findIndex() function. - * It accepts check functions for both keys and/or values. - * If only one function is provided, it's assumed to be searching via values and will receive (v, k) args. - * - * @param {Type} obj The object to be searched. - * @param {testFunc | testFunc | false} keyFunc The testing function for keys. - * @param {testFunc} valFunc The testing function for values. - * @returns {KeyOf | false} The key of the first entry that passes the test. - * If no entries pass the test, return false. - */ -function objFindKey(obj, keyFunc, valFunc) { - // If valFunc is not provided, assume keyFunc is meant to be valFunc - if (!valFunc) { - valFunc = keyFunc; - keyFunc = false; - } - // If keyFunc is not provided, create a function that returns the key - if (!keyFunc) { - keyFunc = ((k) => k); - } - // If obj is an array, find the index of the first element that passes the test - if (isArray(obj)) { - return obj.findIndex(valFunc); - } - // Define the testing functions for keys and values - const kFunc = keyFunc || (() => true); - const vFunc = valFunc || (() => true); - // Find the first entry that passes the test - const validEntry = Object.entries(obj).find(([k, v]) => kFunc(k, v) && vFunc(v, k)); - // If an entry passes the test, return its key - if (validEntry) { - return validEntry[0]; - } - // If no entries pass the test, return false - return false; -} -/** - * An object-equivalent Array.filter() function, which accepts filter functions for both keys and/or values. - * If only one function is provided, it's assumed to be mapping the values and will receive (v, k) args. - * - * @param {Type} obj The object to be searched. - * @param {testFunc | testFunc | false} keyFunc The testing function for keys. - * @param {testFunc} [valFunc] The testing function for values. - * @returns {Type} The filtered object. - */ -const objFilter = (obj, keyFunc, valFunc, isMutating = false) => { - // - if (!valFunc) { - valFunc = keyFunc; - keyFunc = false; - } - if (!keyFunc) { - keyFunc = ((k) => k); - } - if (isArray(obj)) { - const keptValues = obj.filter(valFunc); - if (isMutating) { - obj.splice(0, obj.length, ...keptValues); - return obj; - } - return keptValues; - } - const kFunc = keyFunc || (() => true); - const vFunc = valFunc || (() => true); - if (isMutating) { - const entriesToRemove = Object.entries(obj) - .filter(([key, val]) => !(kFunc(key, val) && vFunc(val, key))); - for (const [key] of entriesToRemove) { - delete obj[key]; - } - return obj; - } - return Object.fromEntries(Object.entries(obj) - .filter(([key, val]) => kFunc(key, val) && vFunc(val, key))); -}; -const objForEach = (obj, func) => { - // An object-equivalent Array.forEach() function, which accepts one function(val, key) to perform for each member. - if (isArray(obj)) { - obj.forEach(func); - } - else { - Object.entries(obj).forEach(([key, val]) => func(val, key)); - } -}; -// Prunes an object of given set of values, [undefined, null] default -const objCompact = (obj, removeWhiteList = [undefined, null], isMutating = false) => objFilter(obj, (val) => !removeWhiteList.includes(val), undefined, isMutating); -const objClone = (obj, isStrictlySafe = false) => { - const cloneArray = (arr) => [...arr]; - const cloneObject = (o) => ({ ...o }); - try { - return JSON.parse(JSON.stringify(obj)); - } - catch (err) { - if (isStrictlySafe) { - throw err; - } - if (Array.isArray(obj)) { - return cloneArray(obj); - } - if (typeof obj === "object") { - return cloneObject(obj); - } - } - return obj; -}; -/** - * Returns a deep merge of source into target. Does not mutate target unless isMutatingOk = true. - * @param {Tx} target The target object to be merged. - * @param {Ty} source The source object to be merged. - * @param {object} options An object containing various options for the merge operation. - * @param {boolean} options.isMutatingOk - * @param {boolean} options.isStrictlySafe - * @param {boolean} options.isConcatenatingArrays - * @param {boolean} options.isReplacingArrays - * @returns {Tx & Ty} - The merged object. - */ -function objMerge(target, source, { isMutatingOk = false, isStrictlySafe = false, isConcatenatingArrays = true, isReplacingArrays = false } = {}) { - // Clone the target if mutation is not allowed - target = isMutatingOk ? target : objClone(target, isStrictlySafe); - // If source is an instance of or target is undefined, return source - if ((source && typeof source === "object" && "id" in source && isDocID(source.id)) || isUndefined(target)) { - return source; - } - // If source is undefined, return target - if (isUndefined(source)) { - return target; - } - // If source is not an index, return target - if (!isIndex(source)) { - return target; - } - // Iterate over each entry in the source object - for (const [key, val] of Object.entries(source)) { - const targetVal = target[key]; - // If replacing arrays is enabled and both target and source values are - // arrays, replace target value with source value - if (isReplacingArrays && isArray(targetVal) && isArray(val)) { - target[key] = val; - } - else if (isConcatenatingArrays && isArray(targetVal) && isArray(val)) { - // If concatenating arrays is enabled and both target and source values - // are arrays, concatenate source value to target value - target[key].push(...val); - } - else if (val !== null && typeof val === "object") { - // If source value is an object and not null, merge it into target value - if (isUndefined(targetVal) && !(val instanceof Application)) { - target[key] = new (Object.getPrototypeOf(val).constructor)(); - } - target[key] = objMerge(target[key], val, { isMutatingOk: true, isStrictlySafe }); - } - else { - // For all other cases, assign source value to target - target[key] = val; - } - } - // Return the merged target - return target; -} -/** - * Deep-compares two objects and returns an object containing only the keys and values - * in the second object that differ from the first. - * If the second object is missing a key or value contained in the first, it sets the - * value in the returned object to null, and prefixes the key with "-=". - * @param {Tx} obj1 The first object to be compared. - * @param {Ty} obj2 The second object to be compared. - * @returns {Record} - An object containing the differences between the two input objects. - */ -function objDiff(obj1, obj2) { - const diff = {}; - const bothObj1AndObj2Keys = Object.keys(obj2).filter((key) => Object.hasOwn(obj2, key) && Object.hasOwn(obj1, key)); - const onlyObj2Keys = Object.keys(obj2).filter((key) => Object.hasOwn(obj2, key) && !Object.hasOwn(obj1, key)); - for (const key of bothObj1AndObj2Keys) { - // If both values are non-array objects, recursively compare them - if (typeof obj1[key] === "object" && typeof obj2[key] === "object" && !Array.isArray(obj1[key]) && !Array.isArray(obj2[key])) { - const nestedDiff = objDiff(obj1[key], obj2[key]); - if (Object.keys(nestedDiff).length > 0) { - diff[key] = nestedDiff; - } - } - else if (Array.isArray(obj1[key]) && Array.isArray(obj2[key])) { - const array1 = obj1[key]; - const array2 = obj2[key]; - if (array1.toString() !== array2.toString()) { - // If both values are arrays and they are not equal, add the second array to the diff - diff[key] = obj2[key]; - } - } - else if (obj1[key] !== obj2[key]) { - // If the values are not equal, add the second value to the diff - diff[key] = obj2[key]; - } - } - for (const key of onlyObj2Keys) { - // If the second object has a key that the first does not, add it to the diff with a "-=" prefix - diff[`-=${key}`] = obj2[key]; - } - return diff; -} -const objExpand = (obj) => { - const expObj = {}; - for (const [key, val] of Object.entries(obj)) { - if (isList(val)) { - const expandedVal = objExpand(val); - setProperty(expObj, key, expandedVal); - } - else { - setProperty(expObj, key, val); - } - } - // Iterate through expanded Object, converting object literals to arrays where it makes sense - /** - * - * @param o - */ - function arrayify(o) { - if (isList(o)) { - if (/^\d+$/.test(Object.keys(o).join(""))) { - return Object.values(o).map(arrayify); - } - return objMap(o, (v) => arrayify(v)); - } - if (isArray(o)) { - return o.map(arrayify); - } - return o; - } - return arrayify(expObj); -}; -const objFlatten = (obj) => { - const flatObj = {}; - for (const [key, val] of Object.entries(obj)) { - if ((isArray(val) || isList(val)) && hasItems(val)) { - for (const [subKey, subVal] of Object.entries(objFlatten(val))) { - flatObj[`${key}.${subKey}`] = subVal; - } - } - else { - flatObj[key] = val; - } - } - return flatObj; -}; -/** - * - * @param obj - */ -function objNullify(obj) { - // Check if the input is an object or an array - if (!isIndex(obj)) { - return obj; - } - // If the input is an array, nullify all its elements - if (Array.isArray(obj)) { - obj.forEach((_, i) => { - obj[i] = null; - }); - return obj; - } - // If the input is an object, nullify all its properties - Object.keys(obj).forEach((objKey) => { - obj[objKey] = null; - }); - return obj; -} -/** - * This function freezes the properties of an object based on a provided schema or keys. - * If a property is missing, it throws an error. - * @param {Partial} data The object whose properties are to be frozen. - * @param {...Array | [T]} keysOrSchema The keys or schema to freeze the properties. - * @returns {T} - The object with frozen properties. - * @throws {Error} - Throws an error if a property is missing. - */ -function objFreezeProps(data, ...keysOrSchema) { - const firstArg = keysOrSchema[0]; - // If the first argument is an object and not an array, treat it as a schema - if (firstArg instanceof Object && !Array.isArray(firstArg)) { - const schema = firstArg; - for (const key in schema) { - if (data[key] === undefined) { - throw new Error(`Missing value for ${key}`); - } - } - } - else { - // If the first argument is not an object or is an array, treat it as an array of keys - for (const key of keysOrSchema) { - if (data[key] === undefined) { - throw new Error(`Missing value for ${String(key)}`); - } - } - } - // Return the data as type T - return data; -} -// #endregion ▄▄▄▄▄ OBJECTS ▄▄▄▄▄ -// #region ████████ FUNCTIONS: Function Wrapping, Queuing, Manipulation ████████ ~ -const getDynamicFunc = (funcName, func, context) => { - if (typeof func === "function") { - const dFunc = { [funcName](...args) { return func(...args); } }[funcName]; - return context ? dFunc.bind(context) : dFunc; - } - return false; -}; -const withLog = (fn) => { - return (...args) => { - console.log(`calling ${fn.name}`); - return fn(...args); - }; -}; -// #endregion ▄▄▄▄▄ FUNCTIONS ▄▄▄▄▄ -// #region ████████ HTML: Parsing HTML Code, Manipulating DOM Objects ████████ ~ -const changeContainer = (elem, container, isCloning = false) => { - elem = $(elem)[0]; - container = $(container)[0]; - // Get the element's current container, which defines its current coordinate space. - const curContainer = $(elem).parent()[0]; - // Get the element's current position in its current coordinate space. - const curPosition = { - x: gsap.getProperty(elem, "x"), - y: gsap.getProperty(elem, "y") - }; - // Convert the element's position in its current space, to the equivalent position in the target space. - const relPos = MotionPathPlugin.convertCoordinates(curContainer, container, curPosition); - eLog.checkLog3("changeContainer", "Target Element", { elem, container, curContainer, curPosition, relPos }); - // Clone the element, if indicated - if (isCloning) { - elem = $(elem).clone()[0]; - } - // Append the element to the new container, and set its new position - $(elem).appendTo($(container)); - gsap.set(elem, relPos); - return elem; -}; -/** - * Adjusts the aspect ratio of a text container to match a target ratio by modifying its font size and line height. - * This function recursively adjusts the font size and line height until the container's aspect ratio or maximum dimensions are met. - * - * @param {HTMLElement|JQuery} textContainer - The text container element or jQuery object to adjust. - * @param {number} targetRatio - The target aspect ratio (width / height) to achieve. - * @param {number} [maxHeight] - Optional maximum height for the text container. - * @param {number} [maxWidth] - Optional maximum width for the text container. - * @param {number} [minFontSize=8] - Optional minimum font size to prevent the text from becoming too small. - * @returns {void} - */ -const adjustTextContainerAspectRatio = (textContainer, targetRatio, maxHeight, maxWidth, minFontSize = 8) => { - // Ensure textContainer is an HTMLElement - textContainer = $(textContainer)[0]; - // If no maxWidth is provided, initialize textContainer's width to maximum possible - if (!maxWidth) { - textContainer.style.setProperty("width", "max-content", "important"); - } - else { - textContainer.style.setProperty("width", `${maxWidth}px`, "important"); - } - /** - * Recursively adjusts the font size and line height of the text container. - * This function is called if the current adjustments do not meet the target aspect ratio or maximum dimensions. - * - * @returns {boolean} - Returns false if the new font size is below the minimum font size, indicating no further adjustments should be made. - */ - function recurAdjustment() { - // Ensure textContainer is an HTMLElement for each recursive call - textContainer = $(textContainer)[0]; - // Calculate new font size and line height as 80% of their current values - const newFontSize = parseFloat(style.fontSize) * 0.8; - const newLineHeight = parseFloat(style.lineHeight) * 0.8; - // Stop recursion if the new font size is below the minimum - if (newFontSize < minFontSize) { - return false; - } - // Apply the new font size and line height - textContainer.style.fontSize = `${newFontSize}px`; - textContainer.style.lineHeight = `${newLineHeight}px`; - // Recursively call adjustTextContainerAspectRatio with updated parameters - return adjustTextContainerAspectRatio(textContainer, targetRatio, lineCount ?? maxHeight, maxWidth, minFontSize); - } - // Get computed styles of the text container - const style = window.getComputedStyle(textContainer); - const lineHeight = parseFloat(style.lineHeight); - // Initialize lineCount as undefined - let lineCount = undefined; - // If maxHeight is provided and is an integer less than lineHeight, calculate lineCount - if (isInt(maxHeight) && maxHeight < lineHeight) { - lineCount = maxHeight; - } - // Get the initial width of the text container - const initialWidth = parseFloat(style.width); - // Initialize bestWidth with the initial width - let bestWidth = initialWidth; - // Flag to indicate if the maximum line count has been reached - let isAtMaxLineCount = false; - // Loop to find the best width that matches the target aspect ratio - for (let lines = 1;; lines++) { - const expectedHeight = lineHeight * lines; - const expectedWidth = initialWidth / lines; - const expectedRatio = expectedWidth / expectedHeight; - // Break the loop if the expected ratio is less than the target ratio - if (expectedRatio < targetRatio) { - break; - } - // Handle cases where lineCount is defined - if (isInt(lineCount)) { - if (lines > lineCount) { - if (recurAdjustment()) { - return; - } - break; - } - } - else if (maxHeight && expectedHeight > maxHeight) { - // Handle cases where maxHeight is exceeded - if (recurAdjustment()) { - return; - } - break; - } - // Update bestWidth with the expected width - bestWidth = expectedWidth; - // Check if the current line count matches the maximum line count - if (isInt(lineCount) && lines === lineCount) { - isAtMaxLineCount = true; - break; - } - } - // If the best width exceeds maxWidth, attempt to adjust font size and line height - if (!isAtMaxLineCount && maxWidth && bestWidth > maxWidth) { - if (recurAdjustment()) { - return; - } - } - // Apply the best width to the text container - textContainer.style.setProperty("width", `${bestWidth}px`, "important"); -}; -const getSvgCode = (svgDotKey, svgPathKeys) => { - const svgData = getProperty(SVGDATA, svgDotKey); - // eLog.checkLog3("compileSvg", {svgDotKey, svgPaths, svgData}); - if (!svgData) { - return ""; - } - const { viewBox, paths, classes } = svgData; - svgPathKeys ??= Object.keys(paths).join("|"); - if (typeof svgPathKeys === "string") { - svgPathKeys = svgPathKeys.split("|"); - } - return [ - ``, - ...svgPathKeys - .map((path) => ``), - "" - ].join("\n"); -}; -// #region ░░░░░░░[SVG]░░░░ SVG Generation & Manipulation ░░░░░░░ ~ -const getRawCirclePath = (r, { x: xO, y: yO } = { x: 0, y: 0 }) => { - [r, xO, yO] = [r, xO, yO].map((val) => roundNum(val, 2)); - const [b1, b2] = [0.4475 * r, (1 - 0.4475) * r]; - const [xT, yT] = [xO, yO - r]; - return [[ - ...[xT, yT], - ...[b2, 0, r, b1, r, r], - ...[0, b2, -b1, r, -r, r], - ...[-b2, 0, -r, -b1, -r, -r], - ...[0, -b2, b1, -r, r, -r] - ]]; -}; -const drawCirclePath = (radius, origin) => { - const [[xT, yT, ...segments]] = getRawCirclePath(radius, origin); - const path = [`m ${xT} ${yT}`]; - segments.forEach((coord, i) => { - if (i % 6 === 0) { - path.push("c"); - } - path.push(coord); - }); - path.push("z"); - return path.join(" "); -}; -// #endregion ░░░░[SVG]░░░░ -// #region ░░░░░░░[Colors]░░░░ Color Manipulation ░░░░░░░ ~ -const getColorVals = (red, green, blue, alpha) => { - if (isRGBColor(red)) { - [red, green, blue, alpha] = red - .replace(/[^\d.,]/g, "") - .split(/,/) - .map((color) => (isUndefined(color) ? undefined : parseFloat(color))); - } - if (isHexColor(red)) { - if ([4, 5].includes(red.length)) { - red = red.replace(/([^#])/g, "$1$1"); - } - [red, green, blue, alpha] = red - .match(/[^#]{2}/g) - ?.map((val) => parseInt(val, 16)) ?? []; - } - if ([red, green, blue].every((color) => /^\d+$/.test(`${color}`))) { - return [red, green, blue, alpha] - .filter((color) => /^[\d.]+$/.test(`${color}`)); - } - return null; -}; -const getRGBString = (red, green, blue, alpha) => { - if (isRGBColor(red) || isHexColor(red)) { - [red, green, blue, alpha] = getColorVals(red) ?? []; - } - if ([red, green, blue].every((color) => /^[.\d]+$/.test(`${color}`))) { - let colorString = "rgb"; - const colors = [red, green, blue]; - if (/^[.\d]+$/.test(`${alpha}`)) { - colors.push(alpha >= 1 ? pInt(alpha) : pFloat(alpha, 2)); - colorString += "a"; - } - return `${colorString}(${colors.join(", ")})`; - } - return null; -}; -const getHEXString = (red, green, blue) => { - function componentToHex(c) { - const hex = c.toString(16); - return hex.length === 1 ? `0${hex}` : hex; - } - if (isHexColor(red)) { - return red; - } - if (isRGBColor(red)) { - [red, green, blue] = getColorVals(red) ?? []; - } - if (isDefined(red) && isDefined(green) && isDefined(blue) && [red, green, blue].every((color) => /^[.\d]+$/.test(`${color}`))) { - return `#${componentToHex(red ?? 0)}${componentToHex(green ?? 0)}${componentToHex(blue ?? 0)}`; - } - return null; -}; -const getContrastingColor = (...colorVals) => { - const [red, green, blue] = getColorVals(...colorVals) ?? []; - if ([red, green, blue].every(isNumber)) { - const YIQ = ((red * 299) + (green * 587) + (blue * 114)) / 1000; - return (YIQ >= 128) ? "rgba(0, 0, 0, 1)" : "rgba(255, 255, 255, 0.8)"; - } - return null; -}; -const getRandomColor = () => getRGBString(gsap.utils.random(0, 255, 1), gsap.utils.random(0, 255, 1), gsap.utils.random(0, 255, 1)); -// #endregion ░░░░[Colors]░░░░ -// #region ░░░░░░░[DOM]░░░░ DOM Manipulation ░░░░░░░ ~ -const getSiblings = (elem) => { - const siblings = []; - // If no parent, return no sibling - if (!elem.parentNode) { - return siblings; - } - Array.from(elem.parentNode.children).forEach((sibling) => { - if (sibling !== elem) { - siblings.push(sibling); - } - }); - return siblings; -}; -// #endregion ░░░░[DOM]░░░░ -const escapeHTML = (str) => (typeof str === "string" - ? str - .replace(/&/g, "&") - .replace(//g, ">") - .replace(/"/g, """) - .replace(/[`']/g, "'") - : str); -// #region ████████ PERFORMANCE: Performance Testing & Metrics ████████ -/** - * Test the performance of a function (synchronous or asynchronous). - * The function will be called repeatedly for 10 seconds, and the total and average execution times will be logged. - * @param func - The function to test. Can be synchronous or asynchronous. - * @param params - The parameters to pass to the function. - */ -const testFuncPerformance = (func, ...params) => { - const start = performance.now(); // Start the timer - let tally = 0; // Keep track of how many times the function is called - // This function will be called each time 'func' finishes executing - const handleResult = () => { - // Check if 10 seconds have passed - if (performance.now() - start < 10000) { - runFunc(); // If not, call 'func' again - tally++; // And increment the tally - } - else { - // If 10 seconds have passed, calculate the total and average time and log them - const elapsedTime = performance.now() - start; - const timePerCall = roundNum(elapsedTime / tally / 4000, 4); - eLog.checkLog3("performance", `[TestPerformance] Function Ran ${tally} Times in ${roundNum(elapsedTime / 1000, 4)}s, Averaging ${timePerCall}s per Call`); - } - }; - // This function calls 'func' and handles its result, whether it's a Promise or not - const runFunc = () => { - const result = func(...params); // Call 'func' with the provided parameters - if (result instanceof Promise) { - // If 'func' is asynchronous, wait for the Promise to resolve before handling the result - result.then(handleResult); - } - else { - // If 'func' is synchronous, handle the result immediately - handleResult(); - } - }; - runFunc(); // Start the first call to 'func' -}; -// #endregion -// #region ░░░░░░░[GreenSock]░░░░ Wrappers for GreenSock Functions ░░░░░░░ ~ -const set = (targets, vars) => gsap.set(targets, vars); -/** - * - * @param target - * @param property - * @param unit - */ -function get(target, property, unit) { - if (unit) { - const propVal = regExtract(gsap.getProperty(target, property, unit), /[\d.]+/); - if (typeof propVal === "string") { - return pFloat(propVal); - } - throw new Error(`Unable to extract property '${property}' in '${unit}' units from ${target}`); - } - return gsap.getProperty(target, property); -} -const getGSAngleDelta = (startAngle, endAngle) => signNum(roundNum(getAngleDelta(startAngle, endAngle), 2)).replace(/^(.)/, "$1="); -const getNearestLabel = (tl, matchTest) => { - if (!tl) { - return undefined; - } - if (!objSize(tl.labels)) { - return undefined; - } - if (typeof matchTest === "string") { - matchTest = new RegExp(matchTest); - } - // Filter the labels against the matchTest, if one provided, and sort by time in ascending order. - const labelTimes = Object.entries(tl.labels) - .filter(([label]) => { - return matchTest instanceof RegExp - ? matchTest.test(label) - : true; - }) - .sort((a, b) => a[1] - b[1]); - // Snap the current time of the timeline to the values in labelTimes - const nearestTime = gsap.utils.snap(labelTimes.map(([_label, time]) => time), tl.time()); - // Get the associated label for the nearest time - const [nearestLabel] = labelTimes.find(([_label, time]) => time === nearestTime); - return nearestLabel; -}; -const reverseRepeatingTimeline = (tl) => { - // FIRST: Determine if timeline itself is repeating, or if most-recent child tween of timeline is repeating - if (tl.repeat() === -1) { - // Timeline itself is repeating. Set totalTime equal to time, reverse. - tl.totalTime(tl.time()); - } - else { - // Get currently-running child tween, check if that is repeating. - const [tw] = tl.getChildren(false, true, true, tl.time()); - if (tw && tw.repeat() === -1) { - // Child tween is repeating. Set totalTime of TWEEN equal to time, reverse TIMELINE. - tw.totalTime(tw.time()); - } - tl.reverse(); - } - return tl; -}; -// #endregion ░░░░[GreenSock]░░░░ -// #endregion ▄▄▄▄▄ HTML ▄▄▄▄▄ -// #region ████████ ASYNC: Async Functions, Asynchronous Flow Control ████████ ~ -const sleep = (duration) => new Promise((resolve) => { - setTimeout(resolve, duration >= 100 ? duration : duration * 1000); -}); -function waitFor(waitForTarget) { - return new Promise((resolve, reject) => { - if (waitForTarget instanceof Promise - || waitForTarget instanceof gsap.core.Animation) { - waitForTarget.then(() => resolve()).catch(reject); - } - else if (Array.isArray(waitForTarget)) { - Promise.all(waitForTarget.map((target) => waitFor(target))).then(() => resolve()).catch(reject); - } - else { - resolve(); - } - }); -} -// #endregion ▄▄▄▄▄ ASYNC ▄▄▄▄▄ -const EventHandlers = { - onTextInputBlur: async (inst, event) => { - const elem = event.target; - const { action, target, flagTarget } = elem.dataset; - if (!action) { - throw new Error("Input text elements require a data-action attribute."); - } - if (!target && !flagTarget) { - throw new Error("Input text elements require a 'data-target' or 'data-flag-target' attribute."); - } - if (target) { - await inst.document.update({ [target]: elem.value }); - } - else if (flagTarget) { - if (elem.value === "") { - await inst.document.unsetFlag(C.SYSTEM_ID, flagTarget); - } - else { - await inst.document.setFlag(C.SYSTEM_ID, flagTarget, elem.value); - } - } - }, - onSelectChange: async (inst, event) => { - const elem = event.currentTarget; - const { action, dtype, target, flagTarget } = elem.dataset; - if (!action) { - throw new Error("Select elements require a data-action attribute."); - } - if (!target && !flagTarget) { - throw new Error("Select elements require a 'data-target' or 'data-flag-target' attribute."); - } - const dataType = lCase(dtype); - let value; - switch (dataType) { - case "number": - value = pFloat(elem.value); - break; - case "boolean": - value = lCase(`${elem.value}`) === "true"; - break; - case "string": - value = `${elem.value}`; - break; - default: { - if (isNumString(value)) { - throw new Error("You must set 'data-dtype=\"Number\"' for elements with boolean values."); - } - value = `${elem.value}`; - break; - } - } - if (target) { - await inst.document.update({ [target]: value }); - } - else if (flagTarget) { - if (elem.value === "") { - await inst.document.unsetFlag(C.SYSTEM_ID, flagTarget); - } - else { - await inst.document.setFlag(C.SYSTEM_ID, flagTarget, value); - } - } - } -}; -// #region ████████ FOUNDRY: Requires Configuration of System ID in constants.ts ████████ ~ -const isDocID = (ref) => { - return typeof ref === "string" && /^[A-Za-z0-9]{16}$/.test(ref); -}; -const isDocUUID = (ref) => { - if (typeof ref !== "string") { - return false; - } - const [docName, docID] = ref.split(/\./); - if (!isDocID(docID)) { - return false; - } - return game.collections.has(docName); -}; -const isDotKey = (ref) => { - return typeof ref === "string"; -}; -const isTargetKey = (ref) => { - if (!isDotKey(ref)) { - return false; - } - if (["name", "img", "id", "_id"].includes(ref)) { - return true; - } - if (ref.startsWith("system")) { - return true; - } - if (ref.startsWith("flag")) { - return true; - } - return false; -}; -const isTargetFlagKey = (ref) => { - if (!isDotKey(ref)) { - return false; - } - if (isTargetKey(ref)) { - return false; - } - return true; -}; -const parseDocRefToUUID = (ref) => { - if (isDocUUID(ref)) { - return ref; - } - else if (isDocID(ref)) { - const doc = game.collections.find((collection) => collection.has(ref))?.get(ref); - if (doc && "uuid" in doc) { - return doc.uuid; - } - throw new Error(`[U.parseDocRefToUUID] Unable to find document with id '${ref}'`); - } - else if (ref && typeof ref === "object" && "uuid" in ref && typeof ref.uuid === "string") { - return ref.uuid; - } - throw new Error(`[U.parseDocRefToUUID] Unrecognized reference: '${ref}'`); -}; -const loc = (locRef, formatDict = {}) => { - if (/[a-z]/.test(locRef)) { // Reference contains lower-case characters: add system ID namespacing to dot notation - locRef = locRef.replace(new RegExp(`^(${C.SYSTEM_ID}.)*`), `${C.SYSTEM_ID}.`); - } - if (typeof game.i18n.localize(locRef) === "string") { - for (const [key, val] of Object.entries(formatDict)) { - formatDict[key] = loc(val); - } - return game.i18n.format(locRef, formatDict) || game.i18n.localize(locRef) || locRef; - } - return locRef; -}; -const getSetting = (setting) => { - if (game.settings.settings.has(`${C.SYSTEM_ID}.${setting}`)) { - return game.settings.get(C.SYSTEM_ID, setting); - } - return undefined; -}; -/** - * - * @param subFolder - * @param fileName - */ -function getTemplatePath(subFolder, fileName) { - if (typeof fileName === "string") { - return `${C.TEMPLATE_ROOT}/${subFolder}/${fileName.replace(/\..*$/, "")}.hbs`; - } - return fileName.map((fName) => getTemplatePath(subFolder, fName)); -} -// DisplayImageSelector: Displays a file selector in tiles mode at the indicated path root. -/** - * - * @param callback - * @param pathRoot - * @param position - * @param position.top - * @param position.left - */ -function displayImageSelector(callback, pathRoot = `systems/${C.SYSTEM_ID}/assets`, position = { top: 200, left: 200 }) { - const fp = new FilePicker({ - type: "image", - activeSource: "public", - displayMode: "tiles", - callback, - top: position.top ?? 200 + 40, - left: position.left ?? 200 + 10 - }); - return fp.browse(pathRoot); -} -// #endregion ▄▄▄▄▄ FOUNDRY ▄▄▄▄▄ -export default { - // ████████ GETTERS: Basic Data Lookup & Retrieval ████████ - GMID, getUID, - // ████████ TYPES: Type Checking, Validation, Conversion, Casting ████████ - isNumber, isNumString, isBooleanString, isSimpleObj, isList, isArray, isFunc, isInt, isFloat, isPosInt, isIterable, - isHTMLCode, isRGBColor, isHexColor, - isUndefined, isDefined, isEmpty, hasItems, isInstance, isNullish, - areEqual, areFuzzyEqual, - pFloat, pInt, pBool, radToDeg, degToRad, - getKey, - assertNonNullType, - FILTERS, - // ████████ REGEXP: Regular Expressions, Replacing, Matching ████████ - testRegExp, - regExtract, - // ████████ STRINGS: String Parsing, Manipulation, Conversion ████████ - // ░░░░░░░ Case Conversion ░░░░░░░ - uCase, lCase, sCase, tCase, - // ░░░░░░░ Formatting ░░░░░░░ - /* hyphenate, */ unhyphenate, pluralize, oxfordize, ellipsize, pad, - toKey, - parseArticles, - signNum, padNum, stringifyNum, verbalizeNum, ordinalizeNum, romanizeNum, - // ░░░░░░░ Content ░░░░░░░ - loremIpsum, randString, randWord, - // ████████ SEARCHING: Searching Various Data Types w/ Fuzzy Matching ████████ - fuzzyMatch, isIn, isInExact, - // ████████ NUMBERS: Number Casting, Mathematics, Conversion ████████ - randNum, randInt, - coinFlip, - cycleNum, cycleAngle, roundNum, clampNum, - sum, average, - // ░░░░░░░ Positioning ░░░░░░░ - getDistance, - getAngle, getAngleDelta, - getBoundingRectangle, - // ████████ ARRAYS: Array Manipulation ████████ - randElem, randIndex, - makeIntRange, - makeCycler, - unique, group, sample, - getLast, removeFirst, pullElement, pullIndex, - subGroup, shuffle, - toArray, - // ████████ OBJECTS: Manipulation of Simple Key/Val Objects ████████ - remove, replace, partition, zip, - objClean, objSize, objMap, objFindKey, objFilter, objForEach, objCompact, - objClone, objMerge, objDiff, objExpand, objFlatten, objNullify, - objFreezeProps, - // ████████ FUNCTIONS: Function Wrapping, Queuing, Manipulation ████████ - getDynamicFunc, withLog, - // ████████ HTML: Parsing HTML Code, Manipulating DOM Objects ████████ - getSvgCode, - changeContainer, adjustTextContainerAspectRatio, - getRawCirclePath, drawCirclePath, - getColorVals, getRGBString, getHEXString, getContrastingColor, getRandomColor, - getSiblings, - escapeHTML, - // ████████ PERFORMANCE: Performance Testing & Metrics ████████ - testFuncPerformance, - // ░░░░░░░ GreenSock ░░░░░░░ - gsap, get, set, getGSAngleDelta, getNearestLabel, reverseRepeatingTimeline, /* to, from, fromTo, */ - TextPlugin, Flip, MotionPathPlugin, - // ████████ ASYNC: Async Functions, Asynchronous Flow Control ████████ - sleep, waitFor, - // EVENT HANDLERS - EventHandlers, - // ░░░░░░░ SYSTEM: System-Specific Functions (Requires Configuration of System ID in constants.js) ░░░░░░░ - isDocID, isDocUUID, isDotKey, isTargetKey, isTargetFlagKey, - parseDocRefToUUID, - loc, getSetting, getTemplatePath, displayImageSelector -}; -// #endregion ▄▄▄▄▄ EXPORTS ▄▄▄▄▄ diff --git a/module/data-import/data-import.js b/module/data-import/data-import.js deleted file mode 100644 index 81e72af4..00000000 --- a/module/data-import/data-import.js +++ /dev/null @@ -1,3628 +0,0 @@ -"use strict"; -// import {BladesActorType, BladesItemType, Playbook} from "../core/constants.js"; -// import U from "../core/utilities.js"; -// import {BladesNPC, BladesFaction} from "../documents/BladesActorProxy.js"; -// import {BladesItem} from "../documents/BladesItemProxy.js"; -// import BladesActiveEffect from "../BladesActiveEffect.js"; -// import type {EffectChangeData} from "@league-of-foundry-developers/foundry-vtt-types/src/foundry/common/data/data.mjs/effectChangeData.js"; -// type CrewObject = { -// type: string; -// playbook: string; -// name: string; -// description?: string; -// rules?: string; -// flavor?: string; -// hints?: string[]; -// }; -// type FactionData = Partial & { -// name: string, -// clocksArray?: Array & {display: string, value: number, max: number}>, -// npcsData?: Array>, -// turfStrings?: string[], -// assetStrings?: string[], -// alliesStrings?: string[], -// enemiesStrings?: string[] -// }; -// type EffectData = { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: string -// }; -// type BLADES_IMPORT_DATA = { -// FACTIONS: Record, -// CREW_OBJECTS: CrewObject[], -// ABILITIES: { -// Descriptions: Record, -// RollMods: Record> -// }, -// CREW_ABILITIES: { -// Descriptions: Record, -// RollMods: Record> -// }, -// CREW_UPGRADES: { -// Descriptions: Record, -// RollMods: Record> -// } -// }; -// const JSONDATA: BLADES_IMPORT_DATA = { -// FACTIONS: { -// "the Billhooks": { -// name: "the Billhooks", -// subtitle: "a Hack-and-Slash Gang of Toughened Thugs", -// concept: "A tough gang of thugs who prefer hatchets, meat hooks, and pole arms.", -// description: "The Billhooks have a bloody reputation, often leaving the butchered corpses of their victims strewn about in a grisly display. Many wonder why the Bluecoats turn a blind eye to their savagery. Based out of their butcher shop headquarters, they are led by Tarvul, who is currently serving life in prison.", -// gm_notes: "Erin and Coran both want to take control of the Billhooks gang, either when Tarvul gets too old (which will be soon) or by taking the position by force. There is no love lost between Erin and Corran and they'll have no qualms about fighting a family member for leadership. Meanwhile, the rest of the gang wants to continue their reign of terror to pressure a magistrate to pardon Tarvul and other gang members and release them from Ironhook.", -// clocksArray: [ -// { -// display: "Terrorize magistrates to pardon members in prison", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Tarvul", -// gender: "m", -// keyPhrases: [ -// "Savage", -// "Arrogant", -// "Family Man" -// ], -// other: "Leader of the Billhooks, currently serving life in prison." -// }, -// { -// name: "Erin", -// gender: "f", -// keyPhrases: [ -// "Confident", -// "Deadly", -// "Ambitious" -// ], -// other: "Billhooks Captain, sister to Tarvul." -// }, -// { -// name: "Coran", -// gender: "m", -// keyPhrases: [ -// "Fierce", -// "Loyal", -// "Quiet" -// ], -// other: "Billhooks thug, Tarvul's son." -// } -// ], -// turfStrings: [ -// "a butcher shop (HQ), stockyard & slaughterhouse", -// "animal fighting pits", -// "gambling dens", -// "several terrified merchants & businesses (which they extort)" -// ], -// assetStrings: [ -// "a large gang of bloodthirsty butchers", -// "a pack of death-dogs" -// ], -// alliesStrings: [ -// "the Bluecoats", -// "the Ministry of Preservation" -// ], -// enemiesStrings: [ -// "Citizens of Crow's Foot", -// "Citizens of the Docks", -// "Ulf Ironborn", -// "the Lost" -// ] -// }, -// "the Bluecoats": { -// name: "the Bluecoats", -// subtitle: "the Corrupt City Watch of Duskvol", -// concept: "The City Watch of Duskwall. Known as the meanest gang in the city. Corrupt, violent, and cruel.", -// description: "The Bluecoats claim the whole city as their turf, but find their influence severely limited in Whitecrown, where the Imperial Military garrison holds sway under command of the Lord Governor. They are divided into companies by district, and have fierce rivalries, often good-natured, but sometimes violent.", -// gm_notes: "The Bluecoats have become jealous of the elite hardware and vehicles used by the Imperial Military. They want to refit their watch-guards in heavy armor and weapons, to better strike fear into those they prey upon.", -// clocksArray: [ -// { -// display: "Procure bigger budget, military arms & equipment", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Commander Clelland", -// gender: "m", -// keyPhrases: [ -// "Corrupt", -// "Cruel", -// "Arrogant" -// ], -// other: "Chief commissioner of the City Watch." -// }, -// { -// name: "Captain Michter", -// gender: "m", -// keyPhrases: [ -// "Ambitious", -// "Fierce", -// "Confident" -// ], -// other: "Chief instructor." -// }, -// { -// name: "Captain Vale", -// gender: "m", -// keyPhrases: [ -// "Loyal", -// "Insightful", -// "Quiet" -// ], -// other: "Quartermaster." -// } -// ], -// turfStrings: [ -// "The whole city, except Whitecrown" -// ], -// assetStrings: [ -// "Many large gangs of vicious thugs in uniform", -// "Armored coaches and canal patrol boats", -// "Public punishment sites (pillories, stocks, hanging cages)" -// ], -// alliesStrings: [ -// "Ironhook Prison", -// "Lord Scurlock", -// "the Billhooks", -// "the City Council", -// "the Crows", -// "the Unseen" -// ], -// enemiesStrings: [ -// "the Imperial Military" -// ] -// }, -// "the Church of Ecstasy": { -// name: "the Church of Ecstasy", -// subtitle: "the State Religion Honoring Life and Abhorring Spirits", -// concept: "The “state religion” honors the life of the body and abhors the corrupted spirit world. Essentially a secret society.", -// description: "The Church of Ecstasy, the state religion, venerates the sanctity of the physical body while condemning the tainted realm of spirits. Operating as a clandestine organization, zealous believers occasionally volunteer to be hollowed to 'become purified'. This practice was once common among the ancient cult of the Empty Vessel, which preceded the Church.", -// gm_notes: "According to the Church's secret teachings, the purest entities are those devoid of spirits: the demons. These demons, immortal and uncorrupted by the madness that afflicts rogue human spirits and vampires, are perceived as the epitome of perfection. The Church's most devout followers aspire to emulate these demons, seeking the elusive secret of ascension. To this end, they conduct numerous sinister experiments and rituals involving hulls, hollows, vampires, and the occasional demon, all within the maze-like dungeons beneath the Church's primary cathedral in Brightstone.", -// clocksArray: [ -// { -// display: "Unlock the secret of ascension", -// value: 0, -// max: 12 -// }, -// { -// display: "Eliminate the Reconciled", -// value: 0, -// max: 12 -// } -// ], -// npcsData: [ -// { -// name: "Elder Rowan", -// gender: "m", -// keyPhrases: [ -// "Devout", -// "Resolute", -// "Visionary" -// ], -// other: "Leader of the Church of Ecstasy." -// }, -// { -// name: "Preceptor Dunvil", -// gender: "m", -// keyPhrases: [ -// "Unorthodox", -// "Obsessive", -// "Enigmatic" -// ], -// other: "Arcane researcher for the Church." -// } -// ], -// turfStrings: [ -// "The Sanctorium grand cathedral in Brightstone", -// "Many other smaller temples across the city" -// ], -// assetStrings: [ -// "A large treasury of tithes from citizens", -// "Extensive arcane and occult libraries, workspaces, and artifacts", -// "Many cohorts of acolytes and hollows who enforce the will of the Church's leadership" -// ], -// alliesStrings: [ -// "the City Council", -// "the Leviathan Hunters", -// "the Spirit Wardens" -// ], -// enemiesStrings: [ -// "the Path of Echoes", -// "the Reconciled" -// ] -// }, -// "the Circle of Flame": { -// name: "the Circle of Flame", -// subtitle: "a Refined Secret Society with Unknown Intentions", -// concept: "A refined secret society of antiquarians and scholars; cover for extortion, graft, vice, and murder.", -// description: "The Circle of Flame operates under the guise of a scholarly society, but in reality, they engage in extortion, graft, vice, and murder. With a vast treasury funded by their wealthy membership, they possess an impressive collection of ancient artifacts, maps, and ephemera. Their operations are protected by a highly trained and discreet private security force. They have a particular interest in the arcane artifacts and treasures of the Lost District.", -// gm_notes: "Of special interest to the Circle are the remains of 'Kotar', a legendary sorcerer, demon, or hero who was mummified before the cataclysm. The Eye, Hand and Heart of Kotar are said to possess great power for those bold enough to risk their use. Additionally, one of 'The Seven' is actually a demon in disguise.", -// clocksArray: [ -// { -// display: "Acquire all the ancient artifacts of Kotar", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Elstera Avrathi", -// gender: "f", -// keyPhrases: [ -// "Secretive", -// "Gracious" -// ], -// other: "Iruvian diplomat and member of 'The Seven', the leadership council of the Circle" -// }, -// { -// name: "Lady Drake", -// gender: "f", -// keyPhrases: [ -// "Cunning", -// "Ruthless" -// ], -// other: "Magistrate and member of 'The Seven'" -// }, -// { -// name: "Raffello", -// gender: "m", -// keyPhrases: [ -// "Visionary", -// "Obsessive" -// ], -// other: "Painter and member of 'The Seven'" -// }, -// { -// name: "Lord Mora", -// gender: "m", -// keyPhrases: [ -// "Cold", -// "Suspicious" -// ], -// other: "Noble and member of 'The Seven'" -// }, -// { -// name: "Lady Penderyn", -// gender: "f", -// keyPhrases: [ -// "Charming", -// "Patient" -// ], -// other: "Noble and member of 'The Seven'" -// }, -// { -// name: "Madame Tesslyn", -// gender: "f", -// keyPhrases: [ -// "Sophisticated", -// "Subtle" -// ], -// other: "Vice purveyor and member of 'The Seven'" -// }, -// { -// name: "Harvale Brogan", -// gender: "m", -// keyPhrases: [ -// "Shrewd", -// "Quiet" -// ], -// other: "Vice purveyor and member of 'The Seven'" -// } -// ], -// turfStrings: [ -// "The Centuralia club, Six Towers (HQ)" -// ], -// assetStrings: [ -// "Vast treasury provided by wealthy membership", -// "Impressive collection of ancient artifacts, maps, and ephemera", -// "Highly trained and discreet private security force" -// ], -// alliesStrings: [ -// "the City Council", -// "the Forgotten Gods", -// "the Foundation", -// "the Path of Echoes" -// ], -// enemiesStrings: [ -// "the Hive", -// "the Silver Nails" -// ] -// }, -// "the City Council": { -// name: "the City Council", -// subtitle: "the Elite Nobility Governing Duskvol", -// concept: "The elite nobility who run the city government, its treasury, magistrates, and public works.", -// description: "The City Council is composed of the scions of the six most powerful noble families in Doskvol. They oversee the city's government, treasury, magistrates, and public works. The council chambers are located in Charterhall, which also houses the government offices and the impregnable city treasury vaults. The council holds ownership of all public spaces in the city, including streets, docks, and waterways.", -// gm_notes: "The members of the Council are all high-ranking adepts in the Church of the Ecstasy of the Flesh. Some of them are also secretly initiates in the Path of Echoes. Three of the councilors (Bowmore, Clelland, Rowan) have aligned against Strangford and are maneuvering to remove the house from the council. Dunvil and Penderyn have not taken sides so far.", -// clocksArray: [ -// { -// display: "Strangford eliminates threats", -// value: 0, -// max: 8 -// }, -// { -// display: "Strangford is removed from council", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Bowmore", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Bowmore family." -// }, -// { -// name: "Clelland", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Clelland family." -// }, -// { -// name: "Dunvil", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Dunvil family." -// }, -// { -// name: "Penderyn", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Penderyn family." -// }, -// { -// name: "Rowan", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Rowan family." -// }, -// { -// name: "Strangford", -// gender: "", -// keyPhrases: [], -// other: "Noble head of the esteemed Strangford family." -// } -// ], -// turfStrings: [ -// "The city council chambers in Charterhall", -// "Government offices", -// "Impregnable city treasury vaults", -// "Ownership of all public spaces in the city, including streets, docks, and waterways" -// ], -// assetStrings: [ -// "A massive treasury of coin and valuable goods", -// "Many officials, barristers, clerks, and officials", -// "The public coaches operated by the Cabbies" -// ], -// alliesStrings: [ -// "Lord Scurlock", -// "the Bluecoats", -// "the Brigade", -// "the Cabbies", -// "the Church of Ecstasy", -// "the Circle of Flame", -// "the Foundation", -// "the Sparkwrights" -// ], -// enemiesStrings: [ -// "the Imperial Military", -// "the Inspectors", -// "the Ministry of Preservation", -// "the Reconciled" -// ] -// }, -// "the Crows": { -// name: "the Crows", -// subtitle: "an Old Gang with New Leadership", -// concept: "An old gang known for running illegal games of chance and extortion rackets.", -// description: "The Crows claim all of Crow's Foot as their turf, with everyone in the district paying up the chain to them. Their headquarters is in an abandoned City Watch tower, and they operate gambling dens in Crow's Foot and extortion rackets at the Docks. Led by Lyssa, they are known for their veteran gang of thugs and killers. They also possess a number of small boats and a fortified HQ.", -// gm_notes: "Lyssa murdered the former boss of the Crows, Roric. His vengeful ghost is now at large in the city. As the power-play continues, the Crows' hold on the district might slip away due to some members' loyalty to Roric.", -// clocksArray: [ -// { -// display: "Reestablish control of Crow's Foot", -// value: 0, -// max: 6 -// }, -// { -// display: "Rise in Tier", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Lyssa", -// gender: "f", -// keyPhrases: [ -// "Brash", -// "Killer", -// "Noble Family" -// ], -// other: "Leader of The Crows." -// }, -// { -// name: "Bell", -// gender: "f", -// keyPhrases: [ -// "Loyal" -// ], -// other: "Second-in-command of The Crows." -// } -// ], -// turfStrings: [ -// "Claims all of Crow's Foot", -// "HQ in an abandoned City Watch tower", -// "Operates gambling dens in Crow's Foot", -// "Extortion rackets at the Docks" -// ], -// assetStrings: [ -// "A veteran gang of thugs and killers", -// "A number of small boats", -// "A fortified HQ" -// ], -// alliesStrings: [ -// "Citizens of Crow's Foot", -// "Sailors", -// "the Bluecoats", -// "the Lost" -// ], -// enemiesStrings: [ -// "the Dockers", -// "the Hive", -// "the Inspectors" -// ] -// }, -// "Deathlands Scavengers": { -// name: "Deathlands Scavengers", -// subtitle: "Explorers of the Wastelands Beyond the Lightning Barriers", -// concept: "Convicts from Ironhook and desperate freelancers who roam the wasteland beyond the lightning barriers.", -// description: "The Deathlands Scavengers are a group of convicts and freelancers who have chosen to roam the perilous wastelands beyond Duskvol's lightning barriers. These wastelands, known as the deathlands, are treacherous and filled with spirits and other dangers. The scavengers are led by Lady Thorn, a brave and caring leader who is haunted by her past. They search for lost artifacts and treasures in the wastes, which they sell or trade in the city. Some even manage to gather enough to buy a pardon and return to life within the barriers.", -// gm_notes: "Condemned prisoners are sometimes given “mercy” and sent into the deathlands rather than being executed at Ironhook. A few survive, thanks to Lady Thorn and her deathlands scavengers, who take them in and train them in the ways of deathlands hunting and survival.", -// clocksArray: [ -// { -// display: "Obtain pardons (repeating)", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Lady Thorn", -// gender: "f", -// keyPhrases: [ -// "Haunted", -// "Brave", -// "Caring" -// ], -// other: "Leader of the Deathlands Scavengers." -// }, -// { -// name: "Richter", -// gender: "m", -// keyPhrases: [ -// "Patient", -// "Quiet", -// "Deadly" -// ], -// other: "A skilled hunter in the wastelands." -// } -// ], -// turfStrings: [ -// "A few precious hold-fasts in the deathlands, secured by ancient rites against spirits.", -// "Hunting grounds to feed on the few strange animals that survived the cataclysm." -// ], -// assetStrings: [ -// "Generators, lightning hooks, gas-masks, air tanks, and other essentials of deathlands survival.", -// "A secret ancient book of ritual sorcery." -// ], -// alliesStrings: [ -// "the Forgotten Gods", -// "the Gondoliers", -// "the Spirit Wardens" -// ], -// enemiesStrings: [ -// "Ironhook Prison" -// ] -// }, -// "the Dimmer Sisters": { -// name: "the Dimmer Sisters", -// subtitle: "Reclusive Mystics of the Occult", -// concept: "House-bound recluses with an occult reputation.", -// description: "The Dimmer Sisters are enigmatic figures who reside in a fine old manor house, along with the ancient temple ruin and subterranean canal beneath it. They have a reputation in the occult circles of Duskvol, and their true names and exact number remain a mystery. Some believe they are an ancient family of possessing spirits, while others whisper that they might be vampires. One thing is certain: those who enter their house are never seen again. They are served by apothecaries and witches, and their dealings are mostly kept secret from the outside world.", -// gm_notes: "The Sisters have been slowly and secretly consolidating the trade of captured spirits and spirit essences in Doskvol for several decades. Only a few remaining rivals stand between them and domination of the market.", -// clocksArray: [ -// { -// display: "Dominate the spirit trade", -// value: 0, -// max: 6 -// }, -// { -// display: "Obtain arcane secrets (repeating)", -// value: 0, -// max: 4 -// } -// ], -// npcsData: [ -// { -// name: "Roslyn", -// gender: "f", -// keyPhrases: [ -// "Patient", -// "Loyal", -// "Arcane" -// ], -// other: "Deals with contacts outside the house." -// }, -// { -// name: "Irelen", -// gender: "f", -// keyPhrases: [ -// "Loyal", -// "Enigmatic", -// "Obsessive" -// ], -// other: "A sparkcraft tinkerer." -// } -// ], -// turfStrings: [ -// "Fine old manor house and grounds (HQ)", -// "Ancient temple ruin and subterranean canal beneath", -// "Apothecaries and witches in their service" -// ], -// assetStrings: [ -// "A private electroplasmic generator, lightning barriers, and spirit containment vessels", -// "Many spirits bound to service" -// ], -// alliesStrings: [ -// "the Forgotten Gods", -// "the Foundation" -// ], -// enemiesStrings: [ -// "the Reconciled", -// "the Spirit Wardens" -// ] -// }, -// "the Fog Hounds": { -// name: "the Fog Hounds", -// subtitle: "a Rough Gang of Smugglers Seeking Patronage", -// concept: "A crew of rough smugglers looking for a patron.", -// description: "Led by Margette Vale, The Fog Hounds are a crew of hard-bitten, tough sailors, all former Void Sea transport haulers. These sailors have been put out of work by the new cargo rail lines and are well-worn from years of harrowing work on the Void Sea. The crew is insular and clannish, often skeptical of outsiders. However, once trust is earned, their loyalty is unbreakable. They currently aim to dominate the Northern smuggling routes in and out of Duskwall, hoping to eliminate any rivals and secure a steady patron.", -// gm_notes: "Vale and her crew are working to absorb or eliminate the remaining rivals in their territory. Their ultimate goal is to establish a consistent relationship with a patron who requires a regular flow of contraband.", -// clocksArray: [ -// { -// display: "Eliminate rival smugglers", -// value: 0, -// max: 8 -// }, -// { -// display: "Obtain a regular patron", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Margette Vale", -// gender: "f", -// keyPhrases: [ -// "Quiet", -// "Cold", -// "Fearless" -// ], -// other: "Leader of The Fog Hounds." -// }, -// { -// name: "Bear", -// gender: "m", -// keyPhrases: [ -// "Fierce", -// "Moody", -// "Brash" -// ], -// other: "Second in command." -// }, -// { -// name: "Goldie", -// gender: "f", -// keyPhrases: [ -// "Calculating", -// "Patient", -// "Confident" -// ], -// other: "Navigator for the crew." -// } -// ], -// turfStrings: [ -// "Underground canal dock (HQ)", -// "North and East city canal routes", -// "Northern Void Sea routes", -// "Old North Port supply caches" -// ], -// assetStrings: [ -// "Medium steamship, Fog Hound", -// "A crew of hard-bitten, tough, expert sailors", -// "A wide array of Imperial transport and cargo documents, some forged, some legit" -// ], -// alliesStrings: [ -// "the Dockers", -// "the Lampblacks" -// ], -// enemiesStrings: [ -// "the Bluecoats" -// ] -// }, -// "the Gondoliers": { -// name: "the Gondoliers", -// subtitle: "Canal Boat Operators with Occult Knowledge", -// concept: "The canal boat operators. Venerated by ancient tradition. Said to know occult secrets.", -// description: "The Gondoliers are the canal boat operators of Doskvol, venerated by ancient tradition and believed to possess occult knowledge. They are beloved by most citizens, who often turn to them for assistance with supernatural problems rather than the Spirit Wardens. The Gondoliers have been protecting citizens from rogue spirits and other supernatural threats since ancient times, long before the Spirit Wardens were established.", -// gm_notes: "Recently, ritually disfigured hollows have been discovered in the canals, prompting an investigation by the Gondoliers. The Spirit Wardens are deliberately ignoring this situation. All Gondoliers are granted the Whisper's Compel special ability.", -// clocksArray: [ -// { -// display: "Investigate desecrated hollows", -// value: 0, -// max: 8 -// }, -// { -// display: "Destroy spirit wells (repeating)", -// value: 0, -// max: 4 -// } -// ], -// npcsData: [ -// { -// name: "Eisele", -// gender: "f", -// keyPhrases: [ -// "Serene", -// "Knowledgeable", -// "Fearless" -// ], -// other: "Leader of the Gondoliers." -// }, -// { -// name: "Griggs", -// gender: "m", -// keyPhrases: [ -// "Strange", -// "Ruthless", -// "Haunted" -// ], -// other: "Chief Whisper for the Gondoliers." -// } -// ], -// turfStrings: [ -// "The canals of Doskvol" -// ], -// assetStrings: [ -// "Fleet of gondolas and other water-craft", -// "Map of known spirit wells and arcane sites across the city", -// "A dedicated cohort of Adepts" -// ], -// alliesStrings: [ -// "Citizens of Barrowcleft", -// "Citizens of Brightstone", -// "Citizens of Charhollow", -// "Citizens of Charterhall", -// "Citizens of Coalridge", -// "Citizens of Crow's Foot", -// "Citizens of Dunslough", -// "Citizens of Nightmarket", -// "Citizens of Silkshore", -// "Citizens of Six Towers", -// "Citizens of Whitecrown", -// "Citizens of the Docks", -// "the Lampblacks" -// ], -// enemiesStrings: [ -// "the Red Sashes", -// "the Spirit Wardens" -// ] -// }, -// "the Gray Cloaks": { -// name: "the Gray Cloaks", -// subtitle: "Former Bluecoats Turned Criminals", -// concept: "A crew of former Bluecoats turned to crime after being framed and expelled from the City Watch.", -// description: "The Gray Cloaks are a group of former Bluecoats who were unjustly framed for a crime they didn't commit. While they were involved in some minor corrupt activities, they were not responsible for burning down the Watch station or destroying evidence against Lord Strangford. Now, having turned to crime, they operate out of the basement of the burned-down City Watch station and have taken over several apartments in Six Towers. They also run a pit-fighting arena and gambling den.", -// gm_notes: "The Gray Cloaks were framed by their Watch station commander for a crime that implicated Lord Strangford of the Leviathan Hunters. Some inspectors know the truth but lack evidence. Lord Strangford would pay handsomely to eliminate these threats.", -// clocksArray: [ -// { -// display: "Secure Six Towers as their turf", -// value: 0, -// max: 8 -// }, -// { -// display: "Avenge their expulsion", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Nessa", -// gender: "f", -// keyPhrases: [ -// "Scrupulous", -// "Daring" -// ], -// other: "Leader of the Gray Cloaks." -// }, -// { -// name: "Hutch", -// gender: "m", -// keyPhrases: [ -// "Brash", -// "Fierce" -// ], -// other: "Second in command." -// } -// ], -// turfStrings: [ -// "The basement of a burned-down City Watch station (HQ)", -// "Several apartments above a tobacconist in Six Towers", -// "A pit-fighting arena and gambling den" -// ], -// assetStrings: [ -// "A sizeable gang of trained enforcers", -// "Old uniforms and badges used to impersonate the City Watch" -// ], -// alliesStrings: [ -// "the Inspectors" -// ], -// enemiesStrings: [ -// "the Bluecoats", -// "the Leviathan Hunters" -// ] -// }, -// "the Grinders": { -// name: "the Grinders", -// subtitle: "Vicious Former Dockers and Refinery Workers", -// concept: "A vicious gang of former dockers and leviathan blood refinery workers.", -// description: "The Grinders are a group of dockers and refinery workers from Lockport, a city to the North in Skovlan. They have come to Doskvol with a mission to raise an army, secure a warship, and take control of Lockport. Their goal is to destroy the Empire's refineries. To fund their mission, they've turned to criminal activities, especially looting and hijacking cargo barges across Doskvol.", -// gm_notes: "The city of Lockport processes 90% of the demon blood siphoned by the leviathan hunter ships of Doskvol. The refineries in Lockport have poisoned the city with toxic fumes and acid rain. The Grinders, affected by this, have come to Doskvol to raise an army and secure a warship to take control of Lockport and destroy the Empire's refineries.", -// clocksArray: [ -// { -// display: "Raise a crew, steal a war ship", -// value: 0, -// max: 12 -// }, -// { -// display: "Fill war treasury", -// value: 0, -// max: 12 -// } -// ], -// npcsData: [ -// { -// name: "Hutton", -// gender: "m", -// keyPhrases: [ -// "Confident", -// "Volatile" -// ], -// other: "Leader of the Grinders." -// }, -// { -// name: "Sercy", -// gender: "m", -// keyPhrases: [ -// "Crippled", -// "Defiant" -// ], -// other: "Second in command." -// }, -// { -// name: "Derret", -// gender: "m", -// keyPhrases: [ -// "Huge", -// "Shrewd" -// ], -// other: "Toughest gang member." -// } -// ], -// turfStrings: [ -// "Abandoned dock warehouse (HQ)", -// "Underground canal dock" -// ], -// assetStrings: [ -// "A few small canal boats", -// "Wrecking tools and explosives" -// ], -// alliesStrings: [ -// "Ulf Ironborn", -// "the Dockers" -// ], -// enemiesStrings: [ -// "Sailors", -// "the Bluecoats", -// "the Imperial Military", -// "the Leviathan Hunters", -// "the Silver Nails" -// ] -// }, -// "the Hive": { -// name: "the Hive", -// subtitle: "a Secretive Guild of Contraband Merchants", -// concept: "A guild of legitimate merchants who secretly trade in contraband. Named for their symbol, a golden bee.", -// description: "The Hive, symbolized by a golden bee, is a guild of merchants that operates legitimately on the surface but secretly trades in contraband. They have a vast presence across Doskvol, owning many shops, taverns, cafes, warehouses, and other mercantile establishments. The Hive is known to avoid business with any occult or arcane groups, and many of its members are followers of the Church of Ecstasy, rejecting the superstitions of the past.", -// gm_notes: "Djera Maha, the leader of The Hive, was once an urchin in the Dagger Isles. She climbed the ranks of every gang along the trade routes to Doskvol, establishing her acquisition and distribution network in the city. She is now poised to dominate all contraband markets. Djera had a close (possibly romantic) relationship with Roric, the leader of the Crows, who was recently murdered.", -// clocksArray: [ -// { -// display: "Dominate contraband market", -// value: 0, -// max: 8 -// }, -// { -// display: "Avenge Roric's murder", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Djera Maha", -// gender: "f", -// keyPhrases: [ -// "Bold", -// "Strategic", -// "Confident" -// ], -// other: "Leader of The Hive." -// }, -// { -// name: "Karth Orris", -// gender: "m", -// keyPhrases: [ -// "Ruthless", -// "Insightful", -// "Jealous" -// ], -// other: "Mercenary commander for The Hive." -// } -// ], -// turfStrings: [ -// "Many shops, taverns, cafes, warehouses, and other mercantile establishments all across the city." -// ], -// assetStrings: [ -// "A massive treasury", -// "Elite mercenaries on retainer", -// "A fleet of transport ships, carriages, wagons, and private trains" -// ], -// alliesStrings: [ -// "the Dagger Isles Consulate", -// "the Ministry of Preservation" -// ], -// enemiesStrings: [ -// "the Circle of Flame", -// "the Crows", -// "the Unseen", -// "the Wraiths" -// ] -// }, -// "the Lampblacks": { -// name: "the Lampblacks", -// subtitle: "the Former Lamp-Lighter Guild Turned Criminal", -// concept: "The former lamp-lighter guild, turned to crime when their services were replaced by electric lights.", -// description: "The Lampblacks, once a guild of lamp-lighters, turned to criminal activities after their services became obsolete due to the advent of electric lights. They now operate out of a coal warehouse in Crow's Foot and run several brothels and cheap drug dens across the district. Led by the charismatic Bazso Baz, they are seen by the working class as 'lovable rogues' standing up against the establishment. The gang is currently at war with the Red Sashes over turf and vengeance for past transgressions.", -// gm_notes: "Bazso Baz is a member of a secret society, the forgotten gods cult named 'The Empty Vessel', and sometimes prioritizes the needs of that group over his gang. The Lampblacks and the Red Sashes are in a turf war, and Bazso is recruiting aggressively, making it clear that one is either with them or against them.", -// clocksArray: [ -// { -// display: "Destroy the Red Sashes", -// value: 0, -// max: 8 -// }, -// { -// display: "Become ward boss of Crow's Foot", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Bazso Baz", -// gender: "m", -// keyPhrases: [ -// "Charming", -// "Open", -// "Ruthless", -// "Whiskey Connoisseur" -// ], -// other: "Leader of The Lampblacks." -// }, -// { -// name: "Pickett", -// gender: "m", -// keyPhrases: [ -// "Shrewd", -// "Conniving", -// "Suspicious" -// ], -// other: "Second in command." -// }, -// { -// name: "Henner", -// gender: "m", -// keyPhrases: [ -// "Loyal", -// "Reckless" -// ], -// other: "A thug in the gang." -// } -// ], -// turfStrings: [ -// "HQ in the office of a coal warehouse", -// "Operates a handful of brothels and cheap drug dens across Crow's Foot" -// ], -// assetStrings: [ -// "A fearsome gang of leg-breakers and mayhem-makers", -// "A number of smugglers on the payroll who run their drugs" -// ], -// alliesStrings: [ -// "Ironhook Prison", -// "the Fog Hounds", -// "the Gondoliers" -// ], -// enemiesStrings: [ -// "the Bluecoats", -// "the Cabbies", -// "the Red Sashes" -// ] -// }, -// "the Leviathan Hunters": { -// name: "the Leviathan Hunters", -// subtitle: "the Captains and Crews who Hunt the Leviathans of the Void Sea", -// concept: "The captains and crews that grapple with titanic demons of the Void Sea to drain their blood for processing into electroplasm.", -// description: "The Leviathan Hunters are renowned for their daring ventures into the Void Sea, where they grapple with immense demons to extract their blood. This blood is then processed into electroplasm, a vital resource for the city of Doskvol. The hunters operate a fleet of vessels, each owned by a noble house that commands it. They have numerous expert sailors, spark-craft technicians, demonologist Whispers, and void-touched navigators. Additionally, they maintain companies of marines to safeguard their ships and their precious cargo both at sea and in port.", -// gm_notes: "The captains harbor a terrible secret: the known hunting grounds for leviathans are becoming barren. The once-reliable movements of these immortal creatures in the Void Sea have changed, and they are migrating elsewhere. New hunting grounds must be discovered before the surplus of leviathan blood runs out, threatening the lightning barriers and the survival of humanity.", -// clocksArray: [ -// { -// display: "Discover new hunting grounds", -// value: 0, -// max: 12 -// }, -// { -// display: "Surplus runs dry", -// value: 0, -// max: 12 -// } -// ], -// npcsData: [ -// { -// name: "Lord Strangford", -// gender: "m", -// keyPhrases: [ -// "Ruthless", -// "Arrogant", -// "Tainted" -// ], -// other: "A captain of the Leviathan Hunters." -// }, -// { -// name: "Lady Clave", -// gender: "f", -// keyPhrases: [ -// "Daring", -// "Cruel", -// "Accomplished" -// ], -// other: "Another captain in the fleet." -// }, -// { -// name: "Lady Ankhayat", -// gender: "f", -// keyPhrases: [ -// "Confident", -// "Charming", -// "Scoundrel" -// ], -// other: "An Iruvian captain of the Leviathan Hunters." -// } -// ], -// turfStrings: [ -// "The massive metal docks for the huge hunter ships", -// "Construction and repair facilities", -// "Several small private leviathan blood processing facilities for the captains' personal shares" -// ], -// assetStrings: [ -// "The leviathan hunter fleet", -// "Many cohorts of expert sailors, spark-craft technicians, demonologist Whispers, and void-touched navigators", -// "Companies of marines" -// ], -// alliesStrings: [ -// "Sailors", -// "the Church of Ecstasy", -// "the City Council", -// "the Dockers", -// "the Sparkwrights" -// ], -// enemiesStrings: [ -// "the Grinders", -// "the Ministry of Preservation", -// "the Path of Echoes" -// ] -// }, -// "the Lost": { -// name: "the Lost", -// subtitle: "Protectors of the Downtrodden", -// concept: "A group of street-toughs and ex-soldiers dedicated to protecting the downtrodden and the hopeless.", -// description: "The Lost is a group of former thugs, killers, and Imperial soldiers who have turned their efforts towards protecting the vulnerable. Operating primarily in the districts of Coalridge and Dunslough, they have recently been focusing on sabotaging and attacking the notoriously cruel workhouse foremen in Coalridge. Their actions have emboldened union organizing efforts in the district, leading to increased tensions with local Bluecoat patrols.", -// gm_notes: "The Lost are driven by a need for atonement. Each member keeps a pile of stones under their bed, with each stone representing a sin they've committed. They believe that by performing just deeds, they can balance out these sins. The Coalridge foremen are offering a significant reward to anyone who can eliminate The Lost.", -// clocksArray: [ -// { -// display: "Destroy cruel workhouses (repeating)", -// value: 0, -// max: 4 -// } -// ], -// npcsData: [ -// { -// name: "Cortland", -// gender: "m", -// keyPhrases: [ -// "Idealist", -// "Candid", -// "Cavalier" -// ], -// other: "The leader of The Lost." -// } -// ], -// turfStrings: [ -// "Converted rail car (HQ)", -// "The poverty-stricken streets of Coalridge and Dunslough" -// ], -// assetStrings: [ -// "A very experienced gang of formerly vicious thugs, killers, and Imperial soldiers" -// ], -// alliesStrings: [ -// "Citizens of Coalridge", -// "Citizens of Dunslough", -// "Laborers", -// "the Crows" -// ], -// enemiesStrings: [ -// "Laborers", -// "the Billhooks", -// "the Bluecoats" -// ] -// }, -// "the Ministry of Preservation": { -// name: "the Ministry of Preservation", -// subtitle: "Overseers of Vital Resources and Transport", -// concept: "Oversees transportation between cities and the disbursement of food and other vital resources.", -// description: "The Ministry of Preservation is responsible for overseeing transportation between cities and managing the distribution of essential resources. They control the electro-rail train lines of the Imperium and have a significant influence over radiant energy farms, eeleries, and other food-growing enterprises throughout the city. The Ministry has a fleet of cargo ships, armed escorts, and the Rail Jacks who work the train lines. They also maintain a private mercenary company that answers only to the ministry.", -// gm_notes: "The Ministry leadership believes that the leviathan hunters are too vital to the public well-being to be controlled by the noble houses. They are taking covert actions to seize control of the hunters and bring them under Ministry control.", -// clocksArray: [ -// { -// display: "Seize control of Leviathan Hunters", -// value: 0, -// max: 12 -// } -// ], -// npcsData: [ -// { -// name: "Lord Dalmore", -// gender: "m", -// keyPhrases: [ -// "Commanding", -// "Intelligent" -// ], -// other: "Executive officer in Doskvol." -// }, -// { -// name: "Lady Slane", -// gender: "f", -// keyPhrases: [ -// "Insightful", -// "Subtle", -// "Effective" -// ], -// other: "Chief of operations." -// }, -// { -// name: "Captain Lannock", -// gender: "m", -// keyPhrases: [ -// "Shrewd", -// "Ruthless" -// ], -// other: "Mercenary commander." -// } -// ], -// turfStrings: [ -// "The electro-rail train lines of the Imperium", -// "Radiant energy farms, eeleries, and other food-growing enterprises throughout the city" -// ], -// assetStrings: [ -// "A fleet of cargo ships and their armed escorts", -// "A significant treasury from taxation and transportation licensing", -// "The Rail Jacks who work the train lines", -// "A private mercenary company" -// ], -// alliesStrings: [ -// "the Billhooks", -// "the Imperial Military", -// "the Rail Jacks", -// "the Sparkwrights" -// ], -// enemiesStrings: [ -// "the Leviathan Hunters" -// ] -// }, -// "the Reconciled": { -// name: "the Reconciled", -// subtitle: "Ancient Spirits Seeking Order", -// concept: "An association of ancient spirits who have not gone feral with the passage of time.", -// description: "The Reconciled is a unique association of ancient spirits that, unlike most spirits, have not gone feral over time. They do not have a specific turf within the city. These spirits can possess victims indefinitely without causing any harm, and they have several hidden spirit wells across the city and in the deathlands, which provide them with the arcane energy they need to survive.", -// gm_notes: "The Reconciled view themselves as the rightful rulers of Duskwall. Some members of the City Council have become initiates in the Path of Echoes and will soon be vulnerable to possession by the Reconciled. These councilors are also high-ranking members of the Church of the Ecstasy of the Flesh, providing an opportunity for infiltration.", -// clocksArray: [ -// { -// display: "Infiltrate the City Council", -// value: 0, -// max: 8 -// }, -// { -// display: "Infiltrate the Church of Ecstasy", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [], -// turfStrings: [], -// assetStrings: [ -// "Several secret and hidden spirit wells across the city and in the deathlands" -// ], -// alliesStrings: [ -// "the City Council", -// "the Gondoliers" -// ], -// enemiesStrings: [ -// "the Church of Ecstasy", -// "the Sparkwrights", -// "the Spirit Wardens" -// ] -// }, -// "the Red Sashes": { -// name: "the Red Sashes", -// subtitle: "Ancient Iruvian Swordsmen Turned Criminals", -// concept: "Originally a school of ancient Iruvian sword arts, since expanded into criminal endeavors.", -// description: "The Red Sashes started as a school teaching ancient Iruvian sword arts. They have since expanded their operations into the criminal world. They operate out of their sword-fighting school which also serves as their headquarters. They have a strong presence in Crow's Foot and the Docks, where they run high-end drug dens. Several members of the Red Sashes are from noble Iruvian families, and their connections to powerful families in Doskvol make them a force to be reckoned with.", -// gm_notes: "The Red Sashes and the Lampblacks are currently at war over turf and for revenge. Mylera is recruiting aggressively, making it clear that neutrality is not an option. The Red Sashes have connections with former sword students in various influential positions.", -// clocksArray: [ -// { -// display: "Destroy the Lampblacks", -// value: 0, -// max: 8 -// }, -// { -// display: "Become ward boss of Crow's Foot", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Mylera Klev", -// gender: "f", -// keyPhrases: [ -// "Shrewd", -// "Ruthless", -// "Educated", -// "Art Collector" -// ], -// other: "Leader of the Red Sashes." -// } -// ], -// turfStrings: [ -// "HQ in their sword-fighting school/temple", -// "Several high-end drug dens across Crow's Foot and the Docks" -// ], -// assetStrings: [ -// "Small contingent of master sword-fighters", -// "Master alchemist; many potent potions and essences" -// ], -// alliesStrings: [ -// "the Cabbies", -// "the Dockers", -// "the Inspectors", -// "the Iruvian Consulate", -// "the Path of Echoes" -// ], -// enemiesStrings: [ -// "the Bluecoats", -// "the Gondoliers", -// "the Lampblacks" -// ] -// }, -// "Lord Scurlock": { -// name: "Lord Scurlock", -// subtitle: "a Mysterious Noble with Dark Secrets", -// concept: "An ancient noble, rumored to be immortal like the Emperor. Possibly a vampire or sorcerer. Obsessed with the occult.", -// description: "Lord Scurlock is an enigmatic figure in Doskvol, known for his cold demeanor and arcane interests. Rumors suggest he might be immortal, drawing comparisons with the Emperor. Some even whisper that he could be a vampire or a sorcerer. He owns a dilapidated manor house in Six Towers, which hides catacombs beneath. Across the city, he has an array of business holdings and cult shrines, all seemingly connected to a mysterious purpose.", -// gm_notes: "Lord Scurlock is a vampire bound by ancient magic to the demon Setarra. Their roles as master and servant have shifted over time. Currently, Scurlock owes a debt: Setarra has discovered sea demons in the harbor, trapped in stone since the cataclysm. She wishes to free them, and Scurlock must assist or face dire consequences.", -// clocksArray: [ -// { -// display: "Fulfill debt to Setarra", -// value: 0, -// max: 12 -// }, -// { -// display: "Obtain arcane secrets (repeating)", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Lord Scurlock", -// gender: "m", -// keyPhrases: [ -// "Enigmatic", -// "Cold", -// "Arcane", -// "Old-fashioned" -// ], -// other: "An individual so powerful he's considered a faction on his own. In combat, his personal scale is Tier III, equivalent to a large gang. Immune to spirits and moves silently. Difficult to look at directly." -// } -// ], -// turfStrings: [ -// "A secret lair outside the city", -// "A dilapidated manor house in Six Towers and the catacombs beneath", -// "Various business holdings and cult shrines across the city" -// ], -// assetStrings: [ -// "An impressive collection of occult and arcane curios, books, and ephemera", -// "An ancient demonic temple" -// ], -// alliesStrings: [ -// "the Bluecoats", -// "the City Council", -// "the Forgotten Gods", -// "the Inspectors" -// ], -// enemiesStrings: [ -// "the Immortal Emperor", -// "the Spirit Wardens" -// ] -// }, -// "the Silver Nails": { -// name: "the Silver Nails", -// subtitle: "Severosi Mercenaries and Ghost Killers", -// concept: "A company of Severosi mercenaries who fought for the Empire in the Unity War. Renowned ghost killers.", -// description: "The Silver Nails are a company of Severosi mercenaries known for their prowess in the Unity War. They are especially renowned as ghost killers. Based in Duskvol, they have their sights set on the Lost District, a forbidden area outside the city's lightning barrier. They aim to drive out or destroy the fierce ghosts that inhabit this district and seize control to uncover the hidden treasures and artifacts within. Their expertise from the deathlands of Severos makes them uniquely qualified for this task.", -// gm_notes: "The Silver Nails are looking to explore the Lost District, which is currently under the control of the Spirit Wardens. The Wardens are doing everything in their power to keep the Silver Nails and others out. Each member wears a ring fashioned from a silver nail, which protects against possession. They are all trained in the Ghost Fighter special ability.", -// clocksArray: [ -// { -// display: "Destroy spirits in the Lost District", -// value: 0, -// max: 8 -// }, -// { -// display: "Control the Lost District", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Seresh", -// gender: "m", -// keyPhrases: [ -// "Bold", -// "Brash", -// "Defiant" -// ], -// other: "Leader of The Silver Nails." -// }, -// { -// name: "Tuhan", -// gender: "m", -// keyPhrases: [ -// "Bold", -// "Cunning", -// "Charming" -// ], -// other: "Lead scout for The Silver Nails." -// } -// ], -// turfStrings: [ -// "A large inn (The Mustang) and its fine stables (HQ)" -// ], -// assetStrings: [ -// "A contingent of exquisite Severosian cavalry horses—fearless, swift, and trained to hunt and battle spirits", -// "Arcane lances" -// ], -// alliesStrings: [ -// "Sailors", -// "the Imperial Military", -// "the Severosi Consulate" -// ], -// enemiesStrings: [ -// "Skovlander Refugees", -// "the Circle of Flame", -// "the Grinders", -// "the Skovlan Consulate", -// "the Spirit Wardens" -// ] -// }, -// "the Sparkwrights": { -// name: "the Sparkwrights", -// subtitle: "Engineers of the Lightning Barriers and Pioneers of Spark-Craft", -// concept: "The engineers who maintain the lightning barriers. Also pioneers of spark-craft technology, indulging in dangerous research.", -// description: "The Sparkwrights are the engineers responsible for maintaining Duskvol's lightning barriers. Beyond this crucial role, they are also at the forefront of spark-craft technology. They constantly push the boundaries with their dangerous research, seeking innovations that could revolutionize the city's defenses and power sources.", -// gm_notes: "For centuries, the Sparkwrights have been working secretly to develop an alternative fuel that could replace leviathan blood, which powers the lightning barriers. Some researchers have come close, but mysterious 'accidents' have thwarted their progress. These accidents are likely orchestrated by the nobility who control leviathan hunting.", -// clocksArray: [ -// { -// display: "Develop alternative fuel", -// value: 0, -// max: 12 -// } -// ], -// npcsData: [ -// { -// name: "Una Farros", -// gender: "f", -// keyPhrases: [ -// "Curious", -// "Vain", -// "Famous" -// ], -// other: "Instructor at Charterhall University." -// } -// ], -// turfStrings: [ -// "Massive workshop, factory, and design facility in Coalridge" -// ], -// assetStrings: [ -// "The electroplasmic generators, city lights, lightning barriers and associated facilities and systems across the city" -// ], -// alliesStrings: [ -// "the City Council", -// "the Leviathan Hunters", -// "the Ministry of Preservation" -// ], -// enemiesStrings: [ -// "the Foundation", -// "the Path of Echoes", -// "the Reconciled" -// ] -// }, -// "the Spirit Wardens": { -// name: "the Spirit Wardens", -// subtitle: "Bronze-Masked Hunters of Rogue Spirits", -// concept: "The bronze-masked hunters who destroy rogue spirits. Also run Bellweather Crematorium to properly dispose of corpses.", -// description: "The Spirit Wardens are the enigmatic bronze-masked hunters responsible for destroying rogue spirits in the city. They operate the Bellweather Crematorium, ensuring the proper disposal of corpses to prevent the rise of these spirits. The Wardens maintain complete anonymity, with members cutting all personal ties and living solely for their duty. They utilize advanced equipment, including spirit-hunter hulls, and have the support of many expert Whispers. Their operations are so secretive that even their allies and enemies are often left guessing their next moves.", -// gm_notes: "The Spirit Wardens are aware of an enemy trying to infiltrate their ranks, though they are unaware that this enemy is the Unseen. They are currently setting a trap to identify and eliminate this threat.", -// clocksArray: [ -// { -// display: "Uncover the infiltrators", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "Bakoros", -// gender: "unknown", -// keyPhrases: [], -// other: "A Warden who may be several individuals and sometimes lectures at the College of Immortal studies at Doskvol Academy." -// } -// ], -// turfStrings: [ -// "Bellweather Crematorium", -// "The Master Warden's estate in Whitecrown" -// ], -// assetStrings: [ -// "The death bells that ring whenever someone dies in the city", -// "The deathseeker crows that find the body", -// "Many cohorts of expert Whispers", -// "The most advanced spectrological and spark-craft equipment, including several spirit-hunter hulls" -// ], -// alliesStrings: [ -// "Deathlands Scavengers", -// "the Church of Ecstasy" -// ], -// enemiesStrings: [ -// "Lord Scurlock", -// "the Dimmer Sisters", -// "the Gondoliers", -// "the Path of Echoes", -// "the Reconciled", -// "the Silver Nails", -// "the Unseen" -// ] -// }, -// "Ulf Ironborn": { -// name: "Ulf Ironborn", -// subtitle: "a Brutal Skovlander Fighting for Turf", -// concept: "A brutal Skovlander, newly arrived in the Dusk, fighting everyone for turf.", -// description: "Ulf Ironborn is a fierce Skovlander who has recently come to Doskvol. He is aggressively trying to establish his territory in the city, leading his gang in ruthless smash & grab operations. As more Skovlander war refugees come to the city, tensions rise, especially with the appearance of 'NO SKOVS' signs. Ulf's strong distrust for the local Akorosi and anyone loyal to the Imperial government makes him a volatile figure, but those of Skovlander blood can easily earn his trust.", -// gm_notes: "Ulf's anger is on a hair-trigger, especially with the rising bigotry against Skovlanders. He is likely to lead his gang into war against any 'true Duskers' who challenge him.", -// clocksArray: [ -// { -// display: "Carve out gang territory", -// value: 0, -// max: 6 -// }, -// { -// display: "Rise in Tier", -// value: 0, -// max: 4 -// } -// ], -// npcsData: [ -// { -// name: "Ulf Ironborn", -// gender: "m", -// keyPhrases: [ -// "Ruthless", -// "Savage", -// "Bold" -// ], -// other: "Leader of his gang, a brutal Skovlander." -// }, -// { -// name: "Havid", -// gender: "m", -// keyPhrases: [ -// "Ruthless", -// "Volatile", -// "Shrewd" -// ], -// other: "Ulf's second in command." -// } -// ], -// turfStrings: [ -// "Rooms, workshop, and stable at The Old Forge tavern (HQ)", -// "A gambling den" -// ], -// assetStrings: [ -// "A small but powerfully savage gang of thugs" -// ], -// alliesStrings: [ -// "the Grinders" -// ], -// enemiesStrings: [ -// "Citizens of Coalridge", -// "the Billhooks" -// ] -// }, -// "the Unseen": { -// name: "the Unseen", -// subtitle: "an Insidious Criminal Enterprise with Hidden Membership", -// concept: "An insidious criminal enterprise with secret membership. Thought to pull the strings of the entire underworld.", -// description: "The Unseen are believed to control much of the underworld from the shadows. They have a multitude of vice dens and extortion rackets across the city, with few realizing they are paying up to this secretive group. Their perfect secrecy is maintained through arcane rituals, allowing core members to recognize each other with a special second sight. Anyone outside the group who learns the identity of a member soon forgets due to a ritual that erases that memory.", -// gm_notes: "The Unseen are attempting to infiltrate the Spirit Wardens, a group whose secret membership has resisted their advances. The Tower and The Star, key figures within the Unseen, are plotting to place their own operatives among the Wardens to take control from the inside.", -// clocksArray: [ -// { -// display: "Infiltrate the Spirit Wardens", -// value: 0, -// max: 8 -// }, -// { -// display: "Expand into other cities", -// value: 0, -// max: 8 -// } -// ], -// npcsData: [ -// { -// name: "The Tower", -// gender: "m", -// keyPhrases: [], -// other: "Leader of the Unseen." -// }, -// { -// name: "The Star", -// gender: "m", -// keyPhrases: [], -// other: "Captain of the Unseen." -// }, -// { -// name: "Grull", -// gender: "m", -// keyPhrases: [], -// other: "Mid-level thug undercover as a coach driver." -// } -// ], -// turfStrings: [ -// "A multitude of vice dens and extortion rackets across the city", -// "Several opulent townhouses used as safe houses" -// ], -// assetStrings: [ -// "A legion of thugs, thieves, and killers on-call to their secret masters." -// ], -// alliesStrings: [ -// "Ironhook Prison", -// "the Bluecoats", -// "the Cyphers", -// "the Forgotten Gods" -// ], -// enemiesStrings: [ -// "the Hive", -// "the Ink Rakes", -// "the Spirit Wardens" -// ] -// }, -// "the Wraiths": { -// name: "the Wraiths", -// subtitle: "a Mysterious Crew of Masked Thieves and Spies", -// concept: "A mysterious crew of masked thieves and spies.", -// description: "The Wraiths operate primarily in Silkshore and Nightmarket, specializing in the theft of luxury items and intelligence gathering. Their operations often serve clients who use the stolen information for blackmail. Each member of the Wraiths wears a mask and goes by an alias, communicating with others using a private sign language. They have a secret lair in a tower in Silkshore and are equipped with all manner of thieves' gear for burglary.", -// gm_notes: "The Wraiths recently stole a private map book from a luxury brothel in Nightmarket. This map book reveals the secret hunting grounds of leviathan sites that will be used by the ship Storm Palace in the upcoming season. While the map is of no use to the Wraiths, it's highly valuable to another leviathan hunter. The Wraiths are now trying to discreetly arrange its sale.", -// clocksArray: [ -// { -// display: "Recruit expert thieves", -// value: 0, -// max: 8 -// }, -// { -// display: "Secure an arcane ally", -// value: 0, -// max: 6 -// } -// ], -// npcsData: [ -// { -// name: "Slate", -// gender: "m", -// keyPhrases: [ -// "Sophisticated", -// "Daring", -// "Secretive" -// ], -// other: "Leader of the Wraiths." -// }, -// { -// name: "Loop", -// gender: "m", -// keyPhrases: [ -// "Obsessive", -// "Moody", -// "Secretive" -// ], -// other: "Appraisal expert for the Wraiths." -// } -// ], -// turfStrings: [ -// "Silkshore and Nightmarket as primary hunting grounds", -// "A scattered collection of secret rooftop shelters", -// "A secret lair in a tower in Silkshore" -// ], -// assetStrings: [ -// "All manner of thieves' gear for burglary" -// ], -// alliesStrings: [ -// "the Cabbies" -// ], -// enemiesStrings: [ -// "the Bluecoats", -// "the Hive", -// "the Inspectors" -// ] -// } -// }, -// CREW_OBJECTS: [ -// { -// type: "contact", -// playbook: "Bravos", -// name: "Meg", -// description: "a pit-fighter", -// hints: [ -// "Perhaps a trainer", -// "or perhaps a fellow extortion artist?" -// ] -// }, -// { -// type: "contact", -// playbook: "Bravos", -// name: "Conway", -// description: "a Bluecoat", -// hints: [ -// "Perhaps an informant within the City Watch?" -// ] -// }, -// { -// type: "contact", -// playbook: "Bravos", -// name: "Keller", -// description: "a blacksmith", -// hints: [ -// "Perhaps a source for armaments?" -// ] -// }, -// { -// type: "contact", -// playbook: "Bravos", -// name: "Tomas", -// description: "a physicker", -// hints: [ -// "Perhaps a former thug turned doctor?" -// ] -// }, -// { -// type: "contact", -// playbook: "Bravos", -// name: "Walker", -// description: "a ward boss", -// hints: [ -// "Perhaps an employer who often needs violent work?" -// ] -// }, -// { -// type: "contact", -// playbook: "Bravos", -// name: "Lutes", -// description: "a tavern owner", -// hints: [ -// "Perhaps a good source of news and gossip?" -// ] -// }, -// { -// type: "favoredOperation", -// playbook: "Bravos", -// name: "Battle", -// description: "Defeat an enemy with overwhelming force." -// }, -// { -// type: "favoredOperation", -// playbook: "Bravos", -// name: "Extortion", -// description: "Threaten violence unless you’re paid off." -// }, -// { -// type: "favoredOperation", -// playbook: "Bravos", -// name: "Sabotage", -// description: "Hurt an opponent by destroying something." -// }, -// { -// type: "favoredOperation", -// playbook: "Bravos", -// name: "Smash & Grab", -// description: "A fast and violent armed robbery." -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Gagan", -// description: "an academic" -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Adikin", -// description: "an occultist" -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Hutchins", -// description: "an antiquarian" -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Moriya", -// description: "a spirit trafficker" -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Mateas Kline", -// description: "a noble" -// }, -// { -// type: "contact", -// playbook: "Cult", -// name: "Bennett", -// description: "an astronomer" -// }, -// { -// type: "favoredOperation", -// playbook: "Cult", -// name: "Acquisition", -// description: "Procure an arcane artifact and attune it to your god." -// }, -// { -// type: "favoredOperation", -// playbook: "Cult", -// name: "Augury", -// description: "Do what you must to attract the god’s attention and counsel." -// }, -// { -// type: "favoredOperation", -// playbook: "Cult", -// name: "Consecration", -// description: "Anoint a place for your deity." -// }, -// { -// type: "favoredOperation", -// playbook: "Cult", -// name: "Sacrifice", -// description: "Destroy what is valuable or good in honor of your god." -// }, -// { -// type: "favoredOperation", -// playbook: "Hawkers", -// name: "Sale", -// description: "A significant transaction with a special buyer of illicit product." -// }, -// { -// type: "favoredOperation", -// playbook: "Hawkers", -// name: "Supply", -// description: "A transaction to acquire new product or establish a new supplier." -// }, -// { -// type: "favoredOperation", -// playbook: "Hawkers", -// name: "Show of Force", -// description: "Make an example of an enemy to dominate territory." -// }, -// { -// type: "favoredOperation", -// playbook: "Hawkers", -// name: "Socialize", -// description: "Improve customer and/or supplier relations with a social event." -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Rolan Wott", -// description: "a magistrate", -// hints: [ -// "Perhaps with a feckless son in Doskvol Academy, always in need of rescuing?" -// ] -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Laroze", -// description: "a Bluecoat", -// hints: [ -// "Perhaps an informant within the City Watch?" -// ] -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Lydra", -// description: "a deal broker", -// hints: [ -// "Perhaps known for her vicious retribution on those who don’t hold up their end?" -// ] -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Hoxley", -// description: "a smuggler", -// hints: [ -// "Perhaps a friend of powerful ship captains?" -// ] -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Anya", -// description: "a dilettante", -// hints: [ -// "Perhaps a well-connected socialite?" -// ] -// }, -// { -// type: "contact", -// playbook: "Hawkers", -// name: "Marlo", -// description: "a gang boss", -// hints: [ -// "Perhaps a good partner with a gang of tough thugs?" -// ] -// }, -// { -// type: "favoredOperation", -// playbook: "Shadows", -// name: "Burglary", -// description: "Theft by breaking and entering." -// }, -// { -// type: "favoredOperation", -// playbook: "Shadows", -// name: "Espionage", -// description: "Obtain secret information by covert or clandestine means." -// }, -// { -// type: "favoredOperation", -// playbook: "Shadows", -// name: "Robbery", -// description: "Theft by force or threats." -// }, -// { -// type: "favoredOperation", -// playbook: "Shadows", -// name: "Sabotage", -// description: "Hurt an opponent by destroying something." -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Dowler", -// description: "an explorer", -// hints: [ -// "Perhaps one of the rare deathlands scavengers that survived his sentence?" -// ] -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Laroze", -// description: "a Bluecoat", -// hints: [ -// "Perhaps an informant within the City Watch?" -// ] -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Amancio", -// description: "a deal broker", -// hints: [ -// "Perhaps a well-connected underworld figure, famous for their neutrality?" -// ] -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Fitz", -// description: "a collector", -// hints: [ -// "Perhaps an aficionado of strange artifacts?" -// ] -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Adelaide Phroaig", -// description: "a noble", -// hints: [ -// "Perhaps a source for scores among the elite?" -// ] -// }, -// { -// type: "contact", -// playbook: "Shadows", -// name: "Rigney", -// description: "a tavern owner", -// hints: [ -// "Perhaps a good source of news and gossip?" -// ] -// }, -// { -// type: "favoredOperation", -// playbook: "Smugglers", -// name: "Arcane/Weird", -// description: "Spirit essences, ghosts, cult materials." -// }, -// { -// type: "favoredOperation", -// playbook: "Smugglers", -// name: "Arms", -// description: "Restricted military weapons, heavy ordnance, explosives." -// }, -// { -// type: "favoredOperation", -// playbook: "Smugglers", -// name: "Contraband", -// description: "High-tax luxuries, drugs, banned art, etc." -// }, -// { -// type: "favoredOperation", -// playbook: "Smugglers", -// name: "Passengers", -// description: "People or livestock traveling in secret." -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Elynn", -// description: "a dock worker", -// hints: [ -// "Perhaps a friend who can help with the infernal paperwork of the Empire?" -// ] -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Rolan", -// description: "a drug dealer", -// hints: [ -// "Perhaps a client with strong underworld ties?" -// ] -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Sera", -// description: "an arms dealer", -// hints: [ -// "Perhaps a supplier with military access?" -// ] -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Nyelle", -// description: "a spirit trafficker", -// hints: [ -// "Perhaps a supplier for the strangest of cargo?" -// ] -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Decker", -// description: "an anarchist", -// hints: [ -// "Perhaps a client in need of the illegal tools of revolution?" -// ] -// }, -// { -// type: "contact", -// playbook: "Smugglers", -// name: "Esme", -// description: "a tavern owner", -// hints: [ -// "Perhaps a good source of news and gossip?" -// ] -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Ancient Altar", -// rules: "You get +1d to the engagement roll for occult plans.", -// flavor: "Its blessing is with you." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Ancient Gate", -// rules: "Safe passage in the deathlands. When you leave the city through this gate, the spirits of the deathlands will not molest you unless directly provoked.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Ancient Obelisk", -// rules: "-1 stress cost for all arcane powers and rituals. This effect applies to all cultists, everywhere—so long as the deity is well-pleased. You don’t have to be on-site at the obelisk to benefit from its power.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Ancient Tower", -// rules: "You get +1d to Consort with arcane entities on-site.", -// flavor: "This tower was prepared by sorcery from the pre-cataclysm and acts as an arcane lens to focus eldritch energy across the black mirror into the void." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Cloister", -// rules: "Your Adept cohorts get +1 scale.", -// flavor: "More room for hopeful novices desperate to pledge their service." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Offertory", -// rules: "You get +2 coin in your payoff for scores that involve occult operations.", -// flavor: "The frightened locals offer you tribute when you perform your dark practices. They don’t want to be next." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Sanctuary", -// rules: "+1d to Command and Sway rolls on-site. Your sanctuary maintains its effect as long as your deity is well-pleased with your service.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Spirit Well", -// rules: "You get +1d to Attune rolls on-site.", -// flavor: "A spirit well draws ghosts and other things to its power, which you harness to aid your arts." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Sacred Nexus", -// rules: "You get +1d to healing treatment rolls.", -// flavor: "Ancient arcane energy seeps into the wounded here, speeding their recovery, and marking them consecrated by its power." -// }, -// { -// type: "claim", -// playbook: "Cult", -// name: "Vice Den", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Barracks", -// rules: "Your Thug cohorts get +1 scale.", -// flavor: "Extra room means more gang members." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Bluecoat Confederates", -// rules: "You get +1d to the engagement roll for assault plans.", -// flavor: "The street patrol around here helps you out now." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Bluecoat Intimidation", -// rules: "You get -2 heat per score.", -// flavor: "The law doesn’t want any trouble from you; they look the other way." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Fighting Pits", -// rules: "During downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "The locals love to gamble away their hard-won coin on the bloodsports you host." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Infirmary", -// rules: "You get +1d to healing treatment rolls. The infirmary also has beds for long-term convalescence.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Informants", -// rules: "You get +1d to gather information for a score.", -// flavor: "Your eyes and ears on the streets are always on the lookout for new targets." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Protection Racket", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "Some of the locals are terrified of you and will gladly pay for “protection.”" -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Street Fence", -// rules: "You get +2 coin in your payoff for scores that involve lower-class targets.", -// flavor: "An expert can find the treasure amid the trash you loot from your poorer victims." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Terrorized Citizens", -// rules: "You get +2 coin in your payoff for scores that involve battle or extortion.", -// flavor: "The frightened locals offer you tribute whenever you lash out. They don’t want to be next." -// }, -// { -// type: "claim", -// playbook: "Bravos", -// name: "Warehouses", -// rules: "You get +1d to acquire asset rolls.", -// flavor: "You have space to hold all the various spoils you end up with after your battles. It can be useful on its own or for barter when you need it." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Cover Identities", -// rules: "You get +1d to the engagement roll for deception and social plans.", -// flavor: "False identities help confuse the opposition." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Cover Operation", -// rules: "You get -2 heat per score.", -// flavor: "The cover of a legitimate operation helps deflect some of the heat from law enforcement." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Foreign Market", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "Some of your product makes its way out of the city." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Informants", -// rules: "You get +1d to gather information for a score.", -// flavor: "Your eyes and ears on the streets are always on the lookout for new clients." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Local Graft", -// rules: "You get +2 coin in payoff for scores that involve a show of force or socializing.", -// flavor: "A few city officials share bribe money with those who show that they’re players on the scene." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Lookouts", -// rules: "You get +1d to Hunt or Survey on your turf.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Luxury Venue", -// rules: "+1d to Consort and Sway rolls on-site.", -// flavor: "Silks, paintings, and crystal impress the clientele." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Personal Clothier", -// rules: "You get +1d to the engagement roll for social plans.", -// flavor: "You always arrive on the scene in the most current and alluring fashion." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Surplus Cache", -// rules: "You get +2 coin in payoff for scores that involve product sale or supply.", -// flavor: "You have an abundance of product, which pads your pockets every now and then." -// }, -// { -// type: "claim", -// playbook: "Hawkers", -// name: "Vice Den", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "Is this claim a den you’ve overtaken from another purveyor, or a new establishment replacing something else?" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Covert Drop", -// rules: "You get +2 coin in payoff for scores that involve espionage or sabotage.", -// flavor: "The perfect hidden exchange point is worth the extra coin to discerning clientele." -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Drug Den", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "What’s the drug of choice?" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Gambling Den", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "Cards, dice, or something more unusual on offer?" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Hagfish Farm", -// rules: "When you use the reduce heat downtime activity after a score that involves killing, you get +1d to the roll and quiet, convenient disposal of any corpses you left on the job.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Infirmary", -// rules: "You get +1d to healing treatment rolls. The infirmary also has beds for long-term convalescence.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Informants", -// rules: "You get +1d to gather information for a score.", -// flavor: "Your eyes and ears on the streets are always on the lookout for new targets." -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Interrogation Chamber", -// rules: "You get +1d to Command and Sway on-site.", -// flavor: "Grisly business, but effective." -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Lookouts", -// rules: "You get +1d to Hunt or Survey on your turf.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Loyal Fence", -// rules: "You get +2 coin in payoff for scores that involve burglary or robbery.", -// flavor: "It requires a skilled eye and good contacts to move stolen goods." -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Secret Pathways", -// rules: "You get +1d to the engagement roll for stealth plans.", -// flavor: "You might have access to long-forgotten underground canals, rooftop walkways, or some other route of your choosing." -// }, -// { -// type: "claim", -// playbook: "Shadows", -// name: "Tavern", -// rules: "You get +1d to Consort and Sway rolls on-site.", -// flavor: "Some booze and friendly conversation can go a long way." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Ancient Gate", -// rules: "Safe passage in the deathlands.", -// flavor: "When you leave the city through this gate, spirits in the deathlands will not molest you unless directly provoked." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Cover Operation", -// rules: "You get -2 heat per score.", -// flavor: "What’s your cover? Who did you seize it from?" -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Fleet", -// rules: "Your cohorts have their own vehicles. Each cohort has a common vehicle, with quality equal to your Tier.", -// flavor: "" -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Informants", -// rules: "You get +1d to gather information for a score.", -// flavor: "Your eyes and ears on the streets are always on the lookout for new clients." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Luxury Fence", -// rules: "You get +2 coin in payoff for scores that involve high-class targets.", -// flavor: "It requires a skilled eye and good contacts to move hot luxury goods." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Secret Routes", -// rules: "You get +1d to the engagement roll for transport plans.", -// flavor: "You might have access to long-forgotten underground canals, dark streets normally hidden behind debris, or some other route of your choosing." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Side Business", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "What kind of legitimate business is this? How do you get paid in secret?" -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Tavern", -// rules: "You get +1d to Consort and Sway rolls on-site.", -// flavor: "Some booze and friendly conversation can go a long way." -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Vice Den", -// rules: "Any time during downtime, roll dice equal to your Tier. You earn coin equal to the highest result, minus your heat.", -// flavor: "Perhaps you sell some of the contraband you smuggle here? Or do you not mix your operations?" -// }, -// { -// type: "claim", -// playbook: "Smugglers", -// name: "Warehouses", -// rules: "You get +1d to acquire asset rolls.", -// flavor: "You have space to hold all the various items and supplies you end up with from your smuggling runs. They can be useful on their own or for barter when you need it." -// } -// ], -// ABILITIES: { -// Descriptions: { -// "Battleborn": "

If you 'reduce harm' that means the level of harm you're facing right now is reduced by one.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Bodyguard": "

The protect teamwork maneuver lets you face a consequence for a teammate.

If you choose to resist that consequence, this ability gives you +1d to your resistance roll.

Also, when you read a situation to gather information about hidden dangers or potential attackers, you get +1 effect—which means more detailed information.

", -// "Ghost Fighter": "

When you're imbued, you can strongly interact with ghosts and spirit-stuff, rather than weakly interact.

When you imbue yourself with spirit energy, how do you do it? What does it look like when the energy manifests?

", -// "Leader": "

This ability makes your cohorts more effective in battle and also allows them to resist harm by using armor.

While you lead your cohorts, they won't stop fighting until they take fatal harm (level 4) or you order them to cease.

What do you do to inspire such bravery in battle?

", -// "Mule": "

This ability is great if you want to wear heavy armor and pack a heavy weapon without attracting lots of attention. Since your exact gear is determined on-the-fly during an operation, having more load also gives you more options to get creative with when dealing with problems during a score.

", -// "Not to Be Trifled With": "

When you push yourself to activate this ability, you still get one of the normal benefits of pushing yourself (+1d, +1 effect, etc.) in addition to the special ability.

If you perform a feat that verges on the superhuman, you might break a metal weapon with your bare hands, tackle a galloping horse, lift a huge weight, etc.

If you engage a small gang on equal footing, you don't suffer reduced effect due to scale against a small gang (up to six people).

", -// "Savage": "

You instill fear in those around you when you get violent. How they react depends on the person. Some people will flee from you, some will be impressed, some will get violent in return. The GM judges the response of a given NPC.

In addition, when you Command someone who's affected by fear (from this ability or otherwise), take +1d to your roll.

", -// "Vigorous": "

Your healing clock becomes a 3-clock, and you get a bonus die when you recover.

", -// "Sharpshooter": "

When you push yourself to activate this ability, you still get one of the normal benefits of pushing yourself (+1d, +1 effect, etc.) in addition to the special ability.

The first use of this ability allows you to attempt long-range sniper shots that would otherwise be impossible with the rudimentary firearms of Duskwall.

The second use allows you to keep up a steady rate of fire in a battle (enough to 'suppress' a small gang up to six people), rather than stopping for a slow reload or discarding a gun after each shot. When an enemy is suppressed, they're reluctant to maneuver or attack (usually calling for a fortune roll to see if they can manage it).

", -// "Focused": "

If you 'resist a consequence' of the appropriate type, you avoid it completely.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Ghost Hunter (Arrow-Swift)": "

Your pet functions as a cohort (Expert: Hunter).

This ability gives them potency against supernatural targets and the arcane ability to move extremely quickly, out-pacing any other creature or vehicle.

", -// "Ghost Hunter (Ghost Form)": "

Your pet functions as a cohort (Expert: Hunter).

This ability gives them potency against supernatural targets and the arcane ability to transform into electroplasmic vapor as if it were a spirit.

", -// "Ghost Hunter (Mind Link)": "

Your pet functions as a cohort (Expert: Hunter).

This ability gives them potency against supernatural targets and the arcane ability to share senses and thoughts telepathically with their master.

", -// "Scout": "

A 'target' can be a person, a destination, a good ambush spot, an item, etc.

", -// "Survivor": "

This ability gives you an additional stress box, so you have 10 instead of 9. The maximum number of stress boxes a PC can have (from any number of additional special abilities or upgrades) is 12.

", -// "Tough As Nails": "

With this ability, level 3 harm doesn't incapacitate you; instead you take -1d to your rolls (as if it were level 2 harm). Level 2 harm affects you as if it were level 1 (less effect). Level 1 harm has no effect on you (but you still write it on your sheet, and must recover to heal it). Record the harm at its original level—for healing purposes, the original harm level applies.

", -// "Alchemist": "

Follow the Inventing procedure with the GM (page 224) to define your first special alchemical formula.

", -// "Artificer": "

Follow the Inventing procedure with the GM (page 224) to define your first spark-craft design.

", -// "Fortitude": "

If you 'resist a consequence' of the appropriate type, you avoid it completely.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Ghost Ward": "

If you make an area anathema to spirits, they will do everything they can to avoid it, and will suffer torment if forced inside the area.

If you make an area enticing to spirits, they will seek it out and linger in the area, and will suffer torment if forced to leave.

This effect lasts for several days over an area the size of a small room.

Particularly powerful or prepared spirits may roll their quality or arcane magnitude to see how well they're able to resist the effect.

", -// "Physicker": "

Knowledge of anatomy and healing is a rare and esoteric thing in Duskwall. Without this ability, any attempts at treatment are likely to fail or make things worse.

You can use this ability to give first aid (rolling Tinker) to allow your patient to ignore a harm penalty for an hour or two.

", -// "Saboteur": "

You can drill holes in things, melt stuff with acid, even use a muffled explosive, and it will all be very quiet and extremely hard to notice.

", -// "Venomous": "

You choose the type of drug or poison when you get this ability. Only a single drug or poison may be chosen—you can't become immune to any essences, oils, or other alchemical substances.

You may change the drug or poison by completing a long-term project.

When you push yourself to activate this ability, you still get one of the normal benefits of pushing yourself (+1d, +1 effect, etc.) if you're making a roll, in addition to the special ability.

", -// "Infiltrator": "

This ability lets you contend with higher-Tier enemies on equal footing. When you're cracking a safe, picking a lock, or sneaking past elite guards, your effect level is never reduced due to superior Tier or quality level of your opposition.

Are you a renowned safe cracker? Do people tell stories of how you slipped under the noses of two Chief Inspectors, or are your exceptional talents yet to be discovered?

", -// "Ambush": "

This ability benefits from preparation— so don't forget you can do that in a flashback.

", -// "Daredevil": "

This special ability is a bit of a gamble. The bonus die helps you, but if you suffer consequences, they'll probably be more costly to resist. But hey, you're a daredevil, so no big deal, right?

", -// "The Devil's Footsteps": "

When you push yourself to activate this ability, you still get one of the normal benefits of pushing yourself (+1d, +1 effect, etc.) if you're making a roll, in addition to the special ability.

If you perform an athletic feat (running, tumbling, balance, climbing, etc.) that verges on the superhuman, you might climb a sheer surface that lacks good hand-holds, tumble safely out of a three-story fall, leap a shocking distance, etc.

If you maneuver to confuse your enemies, they attack each other for a moment before they realize their mistake. The GM might make a fortune roll to see how badly they harm or interfere with each other.

", -// "Expertise": "

This special ability is good for covering for your team. If they're all terrible at your favored action, you don't have to worry about suffering a lot of stress when you lead their group action.

", -// "Ghost Veil": "

This ability transforms you into an intangible shadow for a few moments. If you spend additional stress, you can extend the effect for additional benefits, which may improve your position or effect for action rolls, depending on the circumstances, as usual.

", -// "Reflexes": "

This ability gives you the initiative in most situations. Some specially trained NPCs (and some demons and spirits) might also have reflexes, but otherwise, you're always the first to act, and can interrupt anyone else who tries to beat you to the punch.

This ability usually doesn't negate the need to make an action roll that you would otherwise have to make, but it may improve your position or effect.

", -// "Shadow": "

If you 'resist a consequence' of the appropriate type, you avoid it completely.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Rook's Gambit": "

This is the 'jack-of-all-trades' ability. If you want to attempt lots of different sorts of actions and still have a good dice pool to roll, this is the special ability for you.

", -// "Cloak & Dagger": "

This ability gives you the chance to more easily get out of trouble if a covert operation goes haywire. Also, don't forget your fine disguise kit gear, which boosts the effect of your covert deception methods.

", -// "Ghost Voice": "

The first part of this ability gives you permission to do something that is normally impossible: when you speak to a spirit, it always listens and understands you, even if it would otherwise be too bestial or insane to do so.

The second part of the ability increases your effect when you use social actions with the supernatural.

", -// "Like Looking Into a Mirror": "

This ability works in all situations without restriction. It is very powerful, but also a bit of a curse. You see though every lie, even the kind ones.

", -// "A Little Something on the Side": "

Since this money comes at the end of downtime, after all downtime actions are resolved, you can't remove it from your stash and spend it on extra activities until your next downtime phase.

", -// "Mesmerism": "

The victims' memory 'glosses over' the missing time, so it's not suspicious that they've forgotten something.

When you next interact with the victim, they remember everything clearly, including the strange effect of this ability.

", -// "Subterfuge": "

If you 'resist a consequence' of the appropriate type, you avoid it completely.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Trust in Me": "

This ability isn't just for social interactions. Any action can get the bonus. 'Intimate' is for you and the group to define, it need not exclusively mean romantic intimacy.

", -// "Foresight": "

You can narrate an event in the past that helps your teammate now, or you might explain how you expected this situation and planned a helpful contingency that you reveal now.

", -// "Calculating": "

If you forget to use this ability during downtime, you can still activate it during the score and flashback to the previous downtime when the extra activity happened.

", -// "Connected": "

Your array of underworld connections can be leveraged to loan assets, pressure a vendor to give you a better deal, intimidate witnesses, etc.

", -// "Functioning Vice": "

If you indulged your vice and rolled a 4, you could increase the result to 5 or 6, or you could reduce the result to 3 or 2 (perhaps to avoid overindulgence).

Allies that join you don't need to have the same vice as you, just one that could be indulged alongside yours somehow.

", -// "Ghost Contract": "

The mark of the oath is obvious to anyone who sees it (perhaps a magical rune appears on the skin).

When you suffer 'Cursed' harm, you're incapacitated by withering: enfeebled muscles, hair falling out, bleeding from the eyes and ears, etc., until you either fulfill the deal or discover a way to heal the curse.

", -// "Jail Bird": "

Zero is the minimum wanted level; this ability can't make your wanted level negative.

", -// "Mastermind": "

If you protect a teammate, this ability negates or reduces the severity of a consequence or harm that your teammate is facing. You don't have to be present to use this ability—say how you prepared for this situation in the past.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

", -// "Weaving the Web": "

Your network of underworld connections can always be leveraged to gain insight for a job—even when your contacts aren't aware that they're helping you.

", -// "Compel": "

The GM will tell you if you sense any ghosts nearby. If you don't, you can gather information (maybe Attune, Survey, or Study) to attempt to locate one.

By default, a ghost wants to satisfy its need for life essence and to exact vengeance. When you compel it, you can give it a general or specific command, but the more general it is (like 'Protect me') the more the ghost will interpret it according to its own desires.

Your control over the ghost lasts until the command is fulfilled, or until a day has passed, whichever comes first.

", -// "Iron Will": "

With this ability, you do not freeze up or flee when confronted by any kind of supernatural entity or strange occult event.

", -// "Occultist": "

Consorting with a given entity may require special preparations or travel to a specific place. The GM will tell you about any requirements.

You get the bonus die to your Command rolls because you can demonstrate a secret knowledge of or influence over the entity when you interact with cultists.

", -// "Ritual": "

Without this special ability, the study and practice of rituals leaves you utterly vulnerable to the powers you supplicate. Such endeavors are not recommended.

", -// "Strange Methods": "

Follow the Inventing procedure with the GM (page 224) to define your first arcane design.

", -// "Tempest": "

When you push yourself to activate this ability, you still get one of the normal benefits of pushing yourself (+1d, +1 effect, etc.) if you're making a roll, in addition to the special ability.

When you unleash lightning as a weapon, the GM will describe its effect level and significant collateral damage. If you unleash it in combat against an enemy who's threatening you, you'll still make an action roll in the fight (usually with Attune).

When you summon a storm, the GM will describe its effect level. If you're using this power as cover or distraction, it's probably a setup teamwork maneuver, using Attune.

", -// "Warded": "

If you resist a consequence, this ability negates it completely.

If you use this ability to push yourself, you get one of the benefits (+1d, +1 effect, act despite severe harm) but you don't take 2 stress.

Your special armor is restored at the beginning of downtime.

" -// }, -// RollMods: { -// "Battleborn": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Battleborn@cat:after@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune|command@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Battleborn

You may expend your special armor instead of paying 2 stress to Push yourself during a fight.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Battleborn@cat:roll@type:ability@cTypes:Resistance@val:0@eKey:Cost-SpecialArmor|Negate-HarmLevel@status:Hidden@tooltip:

Battleborn

You may expend your special armor to reduce the level of harm you are resisting by one.

" -// } -// ], -// "Bodyguard": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Bodyguard@cat:roll@type:ability@cTypes:Resistance@status:Hidden@tooltip:

Bodyguard

When you protect a teammate, take +1d to your resistance roll.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Bodyguard@cat:effect@type:ability@status:Hidden@tooltip:

Bodyguard

When you gather information to anticipate possible threats in the current situation, you get +1 effect.

" -// } -// ], -// "Ghost Fighter": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Ghost Fighter@cat:effect@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune|command@val:0@eKey:ForceOn-Potency@status:Hidden@tooltip:

Ghost Fighter

You may imbue your hands, melee weapons, or tools with spirit energy, giving you Potency in combat vs. the supernatural.

You may also grapple with spirits to restrain and capture them.

" -// } -// ], -// "Leader": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Leader@cat:effect@type:ability@cTypes:Action@cTraits:command@status:Hidden@tooltip:

Leader

When a Leader Commands this cohort in combat, it gains +1 effect.

" -// } -// ], -// "Not to Be Trifled With": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Superhuman Feat@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|command@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Not to Be Trifled With@status:Hidden@tooltip:

Not to Be Trifled With — Superhuman Feat

You can Push yourself to perform a feat of physical force that verges on the superhuman (you might break a metal weapon with your bare hands, tackle a galloping horse, lift a huge weight, etc.).

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Superhuman Feat@cat:effect@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|command@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Not to Be Trifled With@status:Hidden@tooltip:

Not to Be Trifled With — Superhuman Feat

You can Push yourself to perform a feat of physical force that verges on the superhuman (you might break a metal weapon with your bare hands, tackle a galloping horse, lift a huge weight, etc.).

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Engage Gang@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune|command@val:0@eKey:Is-Push|ForceOn-Push|Negate-ScalePenalty@sourceName:Not to Be Trifled With@status:Hidden@tooltip:

Not to Be Trifled With — Engage Gang

You can Push yourself to engage a gang of up to six members on equal footing (negating any Scale penalties).

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Engage Gang@cat:effect@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune|command@val:0@eKey:Is-Push|ForceOn-Push|Negate-ScalePenalty@sourceName:Not to Be Trifled With@status:Hidden@tooltip:

Not to Be Trifled With — Engage Gang

You can Push yourself to engage a gang of up to six members on equal footing (negating any Scale penalties).

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// } -// ], -// "Savage": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Savage@cat:roll@type:ability@cTypes:Action@cTraits:command@status:Hidden@tooltip:

Savage

When you Command a fightened target, gain +1d to your roll.

" -// } -// ], -// "Vigorous": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Vigorous@cat:roll@type:ability@cTypes:Downtime@aTypes:Engagement|Recover@status:Hidden@tooltip:

Vigorous

You gain +1d to healing treatment rolls.

" -// } -// ], -// "Sharpshooter": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Extreme Range@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Sharpshooter@status:Hidden@tooltip:

Sharpshooter — Extreme Range

You can Push yourself to make a ranged attack at extreme distance, one that would otherwise be impossible with the rudimentary firearms of Duskwall.

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Extreme Range@cat:effect@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Sharpshooter@status:Hidden@tooltip:

Sharpshooter — Extreme Range

You can Push yourself to make a ranged attack at extreme distance, one that would otherwise be impossible with the rudimentary firearms of Duskwall.

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Suppression Fire@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Sharpshooter@status:Hidden@tooltip:

Sharpshooter — Suppression Fire

You can Push yourself to maintain a steady rate of suppression fire during a battle, enough to suppress a small gang of up to six members. (When an enemy is suppressed, they're reluctant to maneuver or attack, usually calling for a fortune roll to see if they can manage it.)

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Suppression Fire@cat:effect@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Sharpshooter@status:Hidden@tooltip:

Sharpshooter — Suppression Fire

You can Push yourself to maintain a steady rate of suppression fire during a battle, enough to suppress a small gang of up to six members. When an enemy is suppressed, they're reluctant to maneuver or attack, usually calling for a fortune roll to see if they can manage it.

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// } -// ], -// "Focused": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Focused@cat:roll@type:ability@cTypes:Resistance@cTraits:Insight|Resolve@val:0@eKey:Cost-SpecialArmor|Negate-Consequence@status:Hidden@tooltip:

Focused

You may expend your special armor to completely negate a consequence of surprise or mental harm.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Focused@cat:after@type:ability@cTypes:Action@cTraits:hunt|study|survey|finesse|prowl|skirmish|wreck@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Focused

You may expend your special armor instead of paying 2 stress to Push yourself for ranged combat or tracking.

" -// } -// ], -// "Ghost Hunter (Arrow-Swift)": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Ghost Hunter (Arrow-Swift)@cat:effect@type:ability@cTypes:Action@cTraits:quality@val:0@eKey:ForceOn-Potency@status:Hidden@tooltip:

Ghost Hunter (Arrow-Swift)

This cohort is imbued with spirit energy, granting it Potency against the supernatural.

" -// } -// ], -// "Ghost Hunter (Ghost Form)": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Ghost Hunter (Ghost Form)@cat:effect@type:ability@cTypes:Action@cTraits:quality@val:0@eKey:ForceOn-Potency@status:Hidden@tooltip:

Ghost Hunter (Ghost Form)

This cohort is imbued with spirit energy, granting it Potency against the supernatural.

" -// } -// ], -// "Ghost Hunter (Mind Link)": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Ghost Hunter (Mind Link)@cat:effect@type:ability@cTypes:Action@cTraits:quality@val:0@eKey:ForceOn-Potency@status:Hidden@tooltip:

Ghost Hunter (Mind Link)

This cohort is imbued with spirit energy, granting it Potency against the supernatural.

" -// } -// ], -// "Scout": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Scout@cat:effect@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:hunt|study|survey|attune|consort|sway@status:Hidden@tooltip:

Scout

When you gather information to discover the location of a target (a person, a destination, a good ambush spot, etc), you gain +1 effect.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Scout@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl@status:Hidden@tooltip:

Scout

When you hide in a prepared position or use camouflage, you get +1d to rolls to avoid detection.

" -// } -// ], -// "Alchemist": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Alchemist@cat:result@type:ability@cTypes:Downtime|LongTermProject@status:Hidden@tooltip:

Alchemist

When you invent or craft a creation with alchemical features, you gain +1 result level to your roll.

" -// } -// ], -// "Artificer": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Artificer@cat:result@type:ability@cTypes:Downtime|LongTermProject@cTraits:study|tinker@status:Hidden@tooltip:

Artificer

When you invent or craft a creation with spark-craft features, you gain +1 result level to your roll.

" -// } -// ], -// "Fortitude": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Fortitude@cat:roll@type:ability@cTypes:Resistance@val:0@eKey:Cost-SpecialArmor|Negate-Consequence@status:Hidden@tooltip:

Fortitude

You may expend your special armor to completely negate a consequence of fatigue, weakness, or chemical effects.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Fortitude@cat:after@type:ability@cTypes:Action@cTraits:study|survey|tinker|finesse|skirmish|wreck@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Fortitude

You may expend your special armor instead of paying 2 stress to Push yourself when working with technical skill or handling alchemicals.

" -// } -// ], -// "Ghost Ward": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Ghost Ward@cat:after@type:ability@cTypes:Action@cTraits:wreck@val:0@status:Hidden@tooltip:

Ghost Ward

When you Wreck an area with arcane substances, ruining it for any other use, it becomes anathema or enticing to spirits (your choice).

" -// } -// ], -// "Physicker": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Physicker@cat:roll@type:ability@cTypes:Downtime@aTypes:Engagement|Recover@status:Hidden@tooltip:

Physicker

You gain +1d to your healing treatment rolls.

" -// } -// ], -// "Saboteur": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Saboteur@cat:after@type:ability@cTypes:Action|Downtime|LongTermProject@aTraits:wreck@val:0@status:Hidden@tooltip:

Saboteur

When you Wreck, your work is much quieter than it should be and the damage is very well-hidden from casual inspection.

" -// } -// ], -// "Venomous": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Venomous@cat:roll@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@status:Hidden@tooltip:

Venomous

You can Push yourself to secrete your chosen drug or poison through your skin or saliva, or exhale it as a vapor.

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Venomous@cat:effect@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@status:Hidden@tooltip:

Venomous

You can Push yourself to secrete your chosen drug or poison through your skin or saliva, or exhale it as a vapor.

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// } -// ], -// "Infiltrator": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Infiltrator@cat:effect@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:tinker|finesse|wreck|attune@val:0@eKey:Negate-QualityPenalty|Negate-TierPenalty@status:Hidden@tooltip:

Infiltrator

You are not affected by low Quality or Tier when you bypass security measures.

" -// } -// ], -// "Ambush": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Ambush@cat:roll@type:ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune@status:Hidden@tooltip:

Ambush

When you attack from hiding or spring a trap, you get +1d to your roll.

" -// } -// ], -// "Daredevil": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Daredevil@cat:roll@type:ability@eKey:AutoRevealOn-Desperate|ForceOn-(Daredevil),after@status:ToggledOff@tooltip:

Daredevil

When you make a desperate action roll, you may gain +1d to your roll, if you also take −1d to resistance rolls against any consequences.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Daredevil@cat:roll@posNeg:negative@type:ability@cTypes:Resistance@status:Hidden@tooltip:

Daredevil

By choosing to gain +1d to your desperate action roll, you suffer −1d to resistance rolls against the consequences of that action.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:(Daredevil)@cat:after@posNeg:negative@type:ability@val:0@sourceName:Daredevil@status:Hidden@tooltip:

Daredevil

You will suffer −1d to resistance rolls against any consequences of this action roll.

" -// } -// ], -// "The Devil's Footsteps": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Superhuman Feat@cat:roll@type:ability@val:0@eKey:Is-Push|ForceOn-Push@sourceName:The Devil's Footsteps@status:ToggledOff@tooltip:

The Devil's Footsteps — Superhuman Feat

You can Push yourself to perform a feat of physical force that verges on the superhuman (you might climb a sheer surface that lacks good hand-holds, tumble safely out of a three-story fall, leap a shocking distance, etc.).

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Superhuman Feat@cat:effect@type:ability@val:0@eKey:Is-Push|ForceOn-Push@sourceName:The Devil's Footsteps@status:ToggledOff@tooltip:

The Devil's Footsteps — Superhuman Feat

You can Push yourself to perform a feat of physical force that verges on the superhuman (you might climb a sheer surface that lacks good hand-holds, tumble safely out of a three-story fall, leap a shocking distance, etc.).

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Sow Confusion@cat:roll@type:ability@val:0@eKey:Is-Push|ForceOn-Push@sourceName:The Devil's Footsteps@status:ToggledOff@tooltip:

The Devil's Footsteps — Sow Confusion

You can Push yourself to maneuver to confuse your enemies so they mistakenly attack each other. (They attack each other for a moment before they realize their mistake. The GM might make a fortune roll to see how badly they harm or interfere with each other.).

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Sow Confusion@cat:effect@type:ability@val:0@eKey:Is-Push|ForceOn-Push@sourceName:The Devil's Footsteps@status:ToggledOff@tooltip:

The Devil's Footsteps — Sow Confusion

You can Push yourself to maneuver to confuse your enemies so they mistakenly attack each other. (They attack each other for a moment before they realize their mistake. The GM might make a fortune roll to see how badly they harm or interfere with each other.).

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// } -// ], -// "Shadow": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Shadow@cat:after@type:ability@cTypes:Action@cTraits:hunt|study|survey|tinker|finesse|prowl|skirmish|wreck@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Shadow

You may expend your special armor instead of paying 2 stress to Push yourself for a feat of athletics or stealth.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Shadow@cat:roll@type:ability@cTypes:Resistance@val:0@eKey:Cost-SpecialArmor|Negate-HarmLevel@status:Hidden@tooltip:

Shadow

You may expend your special armor to completely negate a consequence of detection or security measures.

" -// } -// ], -// "Rook's Gambit": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Rook's Gambit@cat:roll@type:ability@cTypes:Action|Downtime|AcquireAsset|LongTermProject@val:0@eKey:ForceOn-BestAction|Cost-Stress2@status:Hidden@tooltip:

Rook's Gambit

Take 2 stress to roll your best action rating while performing a different action.

(Describe how you adapt your skill to this use.)

" -// } -// ], -// "Cloak & Dagger": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Cloak & Dagger@cat:roll@type:ability@cTypes:Action|Resistance@cTraits:finesse|prowl|attune|command|consort|sway|Insight@status:Hidden@tooltip:

Cloak & Dagger

When you use a disguise or other form of covert misdirection, you get +1d to rolls to confuse or deflect suspicion.

" -// } -// ], -// "Ghost Voice": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Ghost Voice@cat:effect@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:attune|command|consort|sway@val:0@eKey:ForceOn-Potency@status:Hidden@tooltip:

Ghost Voice

You gain Potency when communicating with the supernatural.

" -// } -// ], -// "Mesmerism": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Mesmerism@cat:after@type:ability@cTypes:Action@cTraits:sway@val:0@status:Hidden@tooltip:

Mesmerism

When you Sway someone, you may cause them to forget that it's happened until they next interact with you.

" -// } -// ], -// "Subterfuge": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Subterfuge@cat:roll@type:ability@cTypes:Resistance@cTraits:Insight@val:0@eKey:Cost-SpecialArmor|Negate-Consequence@status:Hidden@tooltip:

Subterfuge

You may expend your special armor to completely negate a consequence of suspicion or persuasion.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Subterfuge@cat:after@type:ability@cTypes:Action@cTraits:finesse|attune|consort|sway@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Subterfuge

You may expend your special armor instead of paying 2 stress to Push yourself for subterfuge.

" -// } -// ], -// "Trust in Me": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Trust in Me@cat:roll@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:hunt|study|survey|tinker|finesse|prowl|skirmish|wreck|attune|command|consort|sway|Insight|Prowess|Resolve|tier|quality|magnitude|number@status:Hidden@tooltip:

Trust in Me

You gain +1d to rolls opposed by a target with whom you have an intimate relationship.

" -// } -// ], -// "Connected": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Connected@cat:result@type:ability@cTypes:Downtime@aTypes:AcquireAsset|ReduceHeat@status:Hidden@tooltip:

Connected

When you acquire an asset or reduce heat, you get +1 result level.

" -// } -// ], -// "Jail Bird": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Jail Bird@cat:effect@type:ability@cTypes:Downtime@aTypes:Incarceration@eKey:Increase-Tier1@status:Hidden@tooltip:

Jail Bird

You gain +1 Tier while incarcerated.

" -// } -// ], -// "Mastermind": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Mastermind@cat:after@type:ability@cTypes:Action|Downtime|LongTermProject@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Mastermind

You may expend your special armor instead of paying 2 stress to Push yourself when you gather information or work on a long-term project.

" -// } -// ], -// "Weaving the Web": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Weaving the Web@cat:roll@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:consort@status:Hidden@tooltip:

Weaving the Web

You gain +1d to Consort when you gather information on a target for a score.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Weaving the Web@cat:roll@type:ability@cTypes:GatherInfo@status:Hidden@tooltip:

Weaving the Web

You gain +1d to the engagement roll for the targeted score.

" -// } -// ], -// "Ghost Mind": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Ghost Mind@cat:roll@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:hunt|study|survey|tinker|prowl|attune|command|consort|sway@status:Hidden@tooltip:

Ghost Mind

You gain +1d to rolls to gather information about the supernatural by any means.

" -// } -// ], -// "Iron Will": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Iron Will@cat:roll@type:ability@cTypes:Resistance@aTraits:Resolve@status:Hidden@tooltip:

Iron Will

You gain +1d to Resolve resistance rolls.

" -// } -// ], -// "Occultist": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Occultist@cat:roll@type:ability@cTypes:Action|Downtime|LongTermProject@cTraits:command@status:Hidden@tooltip:

Occultist

You gain +1d to rolls to Command cultists following ancient powers, forgotten gods or demons with whom you have previously Consorted

" -// } -// ], -// "Strange Methods": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Strange Methods@cat:result@type:ability@cTypes:Downtime|LongTermProject@status:Hidden@tooltip:

Strange Methods

When you invent or craft a creation with arcane features, you gain +1 result level to your roll.

" -// } -// ], -// "Tempest": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Throw Lightning@cat:roll@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Tempest@status:Hidden@tooltip:

Tempest — Throw Lightning

You can Push yourself to unleash a stroke of lightning as a weapon. The GM will describe its effect level and significant collateral damage.

If you unleash it in combat against an enemy who's threatening you, you'll still make an action roll in the fight (usually with Attune).

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Throw Lightning@cat:effect@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Tempest@status:Hidden@tooltip:

Tempest — Throw Lightning

You can Push yourself to unleash a stroke of lightning as a weapon. The GM will describe its effect level and significant collateral damage.

If you unleash it in combat against an enemy who's threatening you, you'll still make an action roll in the fight (usually with Attune).

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Summon Storm@cat:roll@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Tempest@status:Hidden@tooltip:

Tempest — Summon Storm

You can Push yourself to summon a storm in your immediate vicinity (torrential rain, roaring winds, heavy fog, chilling frost and snow, etc.). The GM will describe its effect level.

If you're using this power as cover or distraction, it's probably a Setup teamwork maneuver, using Attune.

You still gain +1d to your roll at the cost of 2 stress, as normal for a Push.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Summon Storm@cat:effect@type:ability@cTypes:Action@val:0@eKey:Is-Push|ForceOn-Push@sourceName:Tempest@status:Hidden@tooltip:

Tempest — Summon Storm

You can Push yourself to summon a storm in your immediate vicinity (torrential rain, roaring winds, heavy fog, chilling frost and snow, etc.). The GM will describe its effect level.

If you're using this power as cover or distraction, it's probably a Setup teamwork maneuver, using Attune.

You still gain +1 effect at the cost of 2 stress, as normal for a Push.

" -// } -// ], -// "Warded": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Warded@cat:roll@type:ability@cTypes:Resistance@val:0@eKey:Cost-SpecialArmor|Negate-Consequence@status:Hidden@tooltip:

Warded

You may expend your special armor to completely negate a consequence of supernatural origin.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Warded@cat:after@type:ability@cTypes:Action@eKey:Negate-PushCost|Cost-SpecialArmor@status:Hidden@tooltip:

Warded

You may expend your special armor instead of paying 2 stress to Push yourself when you contend with or employ arcane forces.

" -// } -// ] -// } -// }, -// CREW_ABILITIES: { -// Descriptions: { -// "Deadly": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

", -// "Crow's Veil": "

The bells don't ring at the crematorium when a member of your crew kills someone. Do you have a 'membership ritual' now that conveys this talent?

", -// "Emberdeath": "

This ability activates at the moment of the target's death (spend 3 stress then or lose the opportunity to use it). It can only be triggered by a killing blow. Some particularly powerful supernatural entities or specially protected targets may be resistant or immune to this ability.

", -// "No Traces": "

There are many clients who value quiet operations. This ability rewards you for keeping a low profile.

", -// "Patron": "

Who is your patron? Why do they help you?

", -// "Predators": "

This ability applies when the goal is murder. It doesn't apply to other stealth or deception operations you attempt that happen to involve killing.

", -// "Vipers": "

The poison immunity lasts for the entire score, until you next have downtime.

", -// "Dangerous": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

", -// "Blood Brothers": "

If you have the Elite Thugs upgrade, it stacks with this ability. So, if you had an Adepts gang cohort, and the Elite Thugs upgrade, and then took Blood Brothers, your Adepts would add the Thugs type and also get +1d to rolls when they did Thug-type actions.

This ability may result in a gang with three types, surpassing the normal limit of two.

", -// "Door Kickers": "

This ability applies when the goal is to attack an enemy. It doesn't apply to other operations you attempt that happen to involve fighting.

", -// "Fiends": "

The maximum wanted level is 4. Regardless of how much turf you hold (from this ability or otherwise) the minimum rep cost to advance your Tier is always 6.

", -// "Forged In The Fire": "

This ability applies to PCs in the crew. It doesn't confer any special toughness to your cohorts.

", -// "Chosen": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

", -// "Bound in Darkness": "

By what occult means does your teamwork manifest over distance? How is it strange or disturbing? By what ritualistic method are cult members initiated into this ability?

", -// "Conviction": "

What sort of sacrifice does your deity find pleasing?

", -// "Silver Tongues": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

", -// "Accord": "

If your status changes, you lose the turf until it becomes +3 again. Regardless of how much turf you hold (from this ability or otherwise) the minimum rep cost to advance your Tier is always 6.

", -// "Ghost Market": "

They do not pay in coin. What do they pay with?

The GM will certainly have an idea about how your strange new clients pay, but jump in with your own ideas, too! This ability is usually a big shift in the game, so talk it out and come up with something that everyone is excited about. If it's a bit mysterious and uncertain, that's good. You have more to explore that way.

", -// "The Good Stuff": "

The quality of your product might be used for a fortune roll to find out how impressed a potential client is, to find out how enthralled or incapacitated a user is in their indulgence of it, to discover if a strange variation has side-effects, etc.

", -// "Everyone Steals": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

", -// "Ghost Echoes": "

You might explore the echo of an ancient building, crumbled to dust in the real world, but still present in the ghost field; or discern the electroplasmic glow of treasures lost in the depths of the canals; or use a sorcerous ghost door from the pre-cataclysm to infiltrate an otherwise secure location; etc.

The GM will tell you what echoes persist nearby when you gather information about them. You might also undertake investigations to discover particular echoes you hope to find.

", -// "Pack Rats": "

This ability might mean that you actually have the item you need in your pile of stuff, or it could mean you have extra odds and ends to barter with.

", -// "Slippery": "

The GM might sometimes want to choose an entanglement instead of rolling. In that case, they'll choose two and you can pick between them.

", -// "Synchronized": "

For example, Lyric leads a group action to Attune to the ghost field to overcome a magical ward on the Dimmer Sisters' door. Emily, Lyric's player, rolls and gets a 6, and so does Matt! Because the crew has Synchronized, their two separate 6s count as a critical success on the roll.

", -// "Ghost Passage": "

What do you do to 'carry' a spirit? Must the spirit consent, or can you use this ability to trap an unwilling spirit within?

", -// "Reavers": "

If your vehicle already has armor, this ability gives an additional armor box.

", -// "Renegades": "

Each player may choose the action they prefer (you don't all have to choose the same one).

If you take this ability during initial character and crew creation, it supersedes the normal starting limit for action ratings.

" -// }, -// RollMods: { -// "Predators": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Predators@cat:roll@type:crew_ability@cTypes:GatherInfo@status:Hidden@tooltip:

Predators

When you use a stealth or deception plan to commit murder, take +1d to the engagement roll.

" -// } -// ], -// "Vipers": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Vipers (Crew Ability)@cat:result@type:crew_ability@cTypes:Downtime|AcquireAsset|LongTermProject@sourceName:Vipers@status:Hidden@tooltip:

Vipers (Crew Ability)

When you acquire or craft poisons, you get +1 result level to your roll.

" -// } -// ], -// "Blood Brothers": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Blood Brothers (Crew Ability)@cat:roll@type:crew_ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck|attune|command@sourceName:Blood Brothers@status:Hidden@tooltip:

Blood Brothers (Crew Ability)

When fighting alongside crew members in combat, gain +1d for assist, setup and group teamwork actions.

" -// } -// ], -// "Door Kickers": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Door Kickers@cat:roll@type:crew_ability@cTypes:GatherInfo@status:Hidden@tooltip:

Door Kickers

When you use an assault plan, take +1d to the engagement roll.

" -// } -// ], -// "Anointed": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Anointed (Crew Ability)@cat:roll@type:crew_ability@cTypes:Resistance@sourceName:Anointed@status:Hidden@tooltip:

Anointed (Crew Ability)

Gain +1d to resistance rolls against supernatural threats.

" -// }, -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Anointed (Crew Ability)@cat:roll@type:crew_ability@cTypes:Downtime|Engagement|Recover@sourceName:Anointed@status:Hidden@tooltip:

Anointed (Crew Ability)

Gain +1d to healing treatment rolls when you have supernatural harm.

" -// } -// ], -// "Conviction": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Conviction (Crew Ability)@cat:roll@type:crew_ability@cTypes:Action@sourceName:Conviction@status:Hidden@tooltip:

Conviction (Crew Ability)

You may call upon your deity to assist any one action roll you make.

You cannot use this ability again until you indulge your Worship vice.

" -// } -// ], -// "Zealotry": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isCohort: true, -// value: "name:Zealotry (Crew Ability)@cat:roll@type:crew_ability@cTypes:Action|Downtime@sourceName:Zealotry@status:Hidden@tooltip:

Zealotry (Crew Ability)

Gain +1d when acting against enemies of the faith.

" -// } -// ], -// "The Good Stuff": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:The Good Stuff (Crew Ability)@cat:effect@type:crew_ability@cTypes:Action|Downtime@val:0@eKey:Increase-Quality2@sourceName:The Good Stuff@status:Hidden@tooltip:

The Good Stuff (Crew Ability)

The quality of your product is equal to your Tier +2.

" -// } -// ], -// "High Society": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:High Society (Crew Ability)@cat:roll@type:crew_ability@sourceName:High Society@status:Hidden@tooltip:

High Society (Crew Ability)

Gain +1d to gather information about the city's elite.

" -// } -// ], -// "Pack Rats": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Pack Rats (Crew Ability)@cat:roll@type:crew_ability@aTypes:AcquireAsset@sourceName:Pack Rats@status:Hidden@tooltip:

Pack Rats (Crew Ability)

Gain +1d to acquire an asset.

" -// } -// ], -// "Second Story": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// value: "name:Second Story@cat:roll@type:crew_ability@cTypes:GatherInfo@status:Hidden@tooltip:

Second Story

When you execute a clandestine infiltration plan, gain +1d to the engagement roll.

" -// } -// ], -// "Slippery": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Slippery (Crew Ability)@cat:roll@type:crew_ability@cTypes:Downtime@aTypes:ReduceHeat@sourceName:Slippery@status:Hidden@tooltip:

Slippery (Crew Ability)

Gain +1d to reduce heat rolls.

" -// } -// ], -// "Synchronized": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// isCohort: true, -// value: "name:Synchronized (Crew Ability)@cat:after@type:crew_ability@cTypes:Action@sourceName:Synchronized@status:Hidden@tooltip:

Synchronized (Crew Ability)

When you perform a group teamwork action, you may count multiple 6s from different rolls as a critical success.

" -// } -// ], -// "Just Passing Through": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Just Passing Through (Crew Ability)@cat:roll@type:crew_ability@cTypes:Action|Downtime@cTraits:finesse|prowl|consort|sway@sourceName:Just Passing Through@status:Hidden@tooltip:

Just Passing Through (Crew Ability)

When your heat is 4 or less, gain +1d to rolls to deceive people when you pass yourself off as ordinary citizens.

" -// } -// ], -// "Reavers": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Reavers (Crew Ability)@cat:effect@type:crew_ability@cTypes:Action@cTraits:hunt|finesse|prowl|skirmish|wreck@sourceName:Reavers@status:Hidden@tooltip:

Reavers (Crew Ability)

When you go into conflict aboard a vehicle, gain +1 effect for vehicle damage and speed.

" -// } -// ] -// } -// }, -// CREW_UPGRADES: { -// Descriptions: {}, -// RollMods: { -// "Ironhook Contacts": [ -// { -// key: "system.roll_mods", -// mode: 2, -// priority: null, -// isMember: true, -// value: "name:Ironhook Contacts (Crew Upgrade)@cat:roll@type:crew_upgrade@cTypes:Downtime@aTypes:Incarceration@eKey:Increase-Tier1@sourceName:Ironhook Contacts@status:Hidden@tooltip:

Ironhook Contacts (Crew Upgrade)

Gain +1 Tier while in prison, including the incarceration roll.

" -// } -// ] -// } -// } -// }; -// const problemLog: string[] = []; -// function parseColumnItem(item: string, isFaction = false) { -// if (isFaction) { -// const faction = game.actors.getName(item); -// if (!faction) { -// problemLog.push(item); -// } else { -// return ``; -// } -// } -// return `

${item}

`; -// } -// function formatSplitColumnsWithHeader(col1: {header: string, elements: string[]}, col2: {header: string, elements: string[]}, isFactionList = false) { -// return [ -// "
", -// "
", -// `

${col1.header}

`, -// ...col1.elements.map((elem) => parseColumnItem(elem, isFactionList)), -// "
", -// "
", -// `

${col2.header}

`, -// ...col2.elements.map((elem) => parseColumnItem(elem, isFactionList)), -// "
", -// "
" -// ].join(""); -// } -// function formatSplitColumns(elements?: string[], isFactionList = false) { -// if (!elements) { return "" } -// return [ -// "
", -// ...elements.map((elem) => parseColumnItem(elem, isFactionList)), -// "
" -// ].join(""); -// } -// const {claim, favoredOperation, contact} = U.group(JSONDATA.CREW_OBJECTS, "type"); -// export const updateClaims = async () => { -// const errorReport: string[] = []; -// const playbookUpdateData: Partial>> = {}; -// (claim ?? []).forEach((cl) => { -// const playbookObj = game.items.getName(cl.playbook); -// if (!playbookObj || playbookObj.type !== BladesItemType.crew_playbook) { -// errorReport.push(`Claim ${cl.name} has invalid playbook ${cl.playbook}`); -// return; -// } -// const [turfNum] = Object.entries(playbookObj.system.turfs ?? {}).find(([_, tData]: [unknown, BladesClaimData]) => tData.name === cl.name) ?? []; -// if (!turfNum) { -// errorReport.push(`Claim ${cl.name} has invalid turf name ${cl.name} for playbook ${cl.playbook}`); -// return; -// } -// const playbookName = playbookObj.name as Playbook; -// const playbookData = playbookUpdateData[playbookName] ?? {}; -// playbookData[`system.turfs.${turfNum}.description`] = cl.rules ?? ""; -// if (cl.flavor) { -// playbookData[`system.turfs.${turfNum}.flavor`] = cl.flavor; -// } -// playbookUpdateData[playbookName] = playbookData; -// }); -// await Promise.all(Object.entries(playbookUpdateData).map(async ([playbook, data]) => game.items.getName(playbook) -// ?.update(data) -// .then((item) => item?.addTag(playbook)))); -// console.log(errorReport); -// }; -// export const updateOps = async () => { -// const errorReport: string[] = []; -// await Promise.all((favoredOperation ?? []).map(async (op) => { -// const playbookObj = game.items.getName(op.playbook); -// if (!playbookObj || playbookObj.type !== BladesItemType.crew_playbook) { -// errorReport.push(`Favored Op ${op.name} has invalid playbook ${op.playbook}`); -// return undefined; -// } -// const item = await BladesItem.create({ -// name: op.name, -// type: BladesItemType.preferred_op, -// img: playbookObj.img, -// system: { -// description: op.description -// } -// }) as BladesItemOfType; -// if (BladesItem.IsType(item, BladesItemType.preferred_op)) { -// return item.addTag(playbookObj.name as Playbook); -// } -// return undefined; -// })); -// console.log(errorReport); -// }; -// export const updateContacts = async () => { -// const errorReport: string[] = []; -// await Promise.all((contact ?? []).map(async (ct) => { -// const playbookObj = game.items.getName(ct.playbook); -// if (!BladesItem.IsType(playbookObj, BladesItemType.crew_playbook)) { -// errorReport.push(`Contact ${ct.name} has invalid playbook ${ct.playbook}`); -// return undefined; -// } -// const actor: BladesNPC = await Actor.create({ -// name: ct.name, -// type: BladesActorType.npc, -// system: { -// description: ct.description, -// prompts: ct.hints?.join(" ") -// } as Partial -// }) as BladesNPC; -// return actor.addTag(playbookObj.name as Playbook); -// })); -// console.log(errorReport); -// }; -// const updateFactionData = async (factionData: FactionData) => { -// const faction = game.actors.getName(factionData.name) as BladesFaction|undefined; -// const updateData: Record = {}; -// if (faction) { -// updateData["system.subtitle"] = factionData.subtitle ?? ""; -// updateData["system.concept"] = factionData.concept ?? ""; -// updateData["system.description"] = [ -// `

${factionData.description}

`, -// formatSplitColumnsWithHeader( -// { -// header: "Allied Factions", -// elements: factionData.alliesStrings ?? [] -// }, -// { -// header: "Opposing Factions", -// elements: factionData.enemiesStrings ?? [] -// }, -// true -// ) -// ].join(""); -// updateData["system.situation"] = `

${factionData.gm_notes}

`; -// updateData["system.assets"] = formatSplitColumns(factionData.assetStrings); -// updateData["system.turf"] = formatSplitColumns(factionData.turfStrings); -// updateData["system.-=clocks"] = null; -// updateData["system.-=status"] = null; -// updateData["system.-=goal_1"] = null; -// updateData["system.-=goal_2"] = null; -// updateData["system.-=quirks"] = null; -// updateData["system.-=notables"] = null; -// updateData["system.-=allies"] = null; -// updateData["system.-=enemies"] = null; -// updateData["system.-=goal_clock"] = null; -// updateData["system.-=type"] = null; -// updateData["system.-=goal_1_clock_value"] = null; -// updateData["system.-=goal_1_clock_max"] = null; -// updateData["system.-=goal_2_clock_value"] = null; -// updateData["system.-=goal_2_clock_max"] = null; -// updateData["system.-=tier_bonus"] = null; -// await faction.update(updateData); -// factionData.clocksArray?.forEach((clockData: {display: string, value: number, max: number}, i: number) => { -// let color = "white"; -// if (i > 0) { color = "yellow" } -// if (clockData.max > 8) { color = "red" } -// if (/\(repeating\)/.test(clockData.display)) { color = "cyan" } -// faction.addClock({ -// display: clockData.display, -// value: clockData.value, -// max: clockData.max, -// isVisible: true, -// color -// }); -// }); -// } else { -// problemLog.push(`Unable to find faction "${factionData.name}"`); -// } -// }; -// export const updateFactions = async () => { -// await Promise.all(Object.values(JSONDATA.FACTIONS).map(async (factionData) => updateFactionData(factionData))); -// console.log(problemLog); -// }; -// export const updateRollMods = async () => { -// await Promise.all([ -// ...Object.entries(JSONDATA.ABILITIES.RollMods) -// .map(async ([abilityName, eData]) => { -// // Get ability doc -// const abilityDoc = game.items.getName(abilityName); -// if (!abilityDoc) { -// eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} Not Found.`); -// return undefined; -// } -// // Get active effects on abilityDoc -// const abilityEffects = Array.from(abilityDoc.effects ?? []) as BladesActiveEffect[]; -// // Separate out 'APPLYTOMEMBERS' and 'APPLYTOCOHORTS' ActiveEffects -// const toMemberEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOMEMBERS")); -// const toCohortEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOCOHORTS")); -// const standardEffects = abilityEffects.filter((effect) => effect.changes.every((change) => !["APPLYTOMEMBERS", "APPLYTOCOHORTS"].includes(change.key))); -// // Confirm eData.isMember and eData.isCohort are consistent across all changes. -// const testChange = eData[0]; -// if ( -// (testChange.isMember && eData.some((change) => !change.isMember)) -// || (!testChange.isMember && eData.some((change) => change.isMember)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} has inconsistent 'isMember' entries.`); -// } -// if ( -// (testChange.isCohort && eData.some((change) => !change.isCohort)) -// || (!testChange.isCohort && eData.some((change) => change.isCohort)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} has inconsistent 'isCohort' entries.`); -// } -// // If eData.isMember or eData.isCohort, first see if there already is such an effect on the doc -// if (testChange.isMember) { -// if (toMemberEffects.length > 1) { -// return eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} Has Multiple 'APPLYTOMEMBERS' Active Effects`); -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: abilityName, -// icon: abilityDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isMember; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toMemberEffects.length === 1) { -// const abilityEffect = toMemberEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOMEMBERS", -// mode: 0, -// priority: null, -// value: `${abilityName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Scoundrel Ability)` -// }); -// } -// // Create new ActiveEffect -// return abilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else if (testChange.isCohort) { -// if (toCohortEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} Has Multiple 'APPLYTOCOHORTS' Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: abilityName, -// icon: abilityDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isCohort; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toCohortEffects.length === 1) { -// const abilityEffect = toCohortEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOCOHORTS", -// mode: 0, -// priority: null, -// value: `${abilityName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Scoundrel Ability)` -// }); -// } -// // Create new ActiveEffect -// return abilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else { -// if (standardEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Ability ${abilityName} Has Multiple Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: abilityName, -// icon: abilityDoc.img ?? "", -// changes: eData -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (standardEffects.length === 1) { -// const abilityEffect = standardEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } -// // Create new ActiveEffect -// return abilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } -// }), -// ...Object.entries(JSONDATA.CREW_ABILITIES.RollMods) -// .map(async ([aName, eData]) => { -// // Get crew ability doc -// const crewAbilityDoc = game.items.getName(aName); -// if (!crewAbilityDoc) { -// eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} Not Found.`); -// return undefined; -// } -// // Get active effects on crewAbilityDoc -// const abilityEffects = Array.from(crewAbilityDoc.effects ?? []) as BladesActiveEffect[]; -// // Separate out 'APPLYTOMEMBERS' and 'APPLYTOCOHORTS' ActiveEffects -// const toMemberEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOMEMBERS")); -// const toCohortEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOCOHORTS")); -// const standardEffects = abilityEffects.filter((effect) => effect.changes.every((change) => !["APPLYTOMEMBERS", "APPLYTOCOHORTS"].includes(change.key))); -// // Confirm eData.isMember and eData.isCohort are consistent across all changes. -// const testChange = eData[0]; -// if ( -// (testChange.isMember && eData.some((change) => !change.isMember)) -// || (!testChange.isMember && eData.some((change) => change.isMember)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} has inconsistent 'isMember' entries.`); -// } -// if ( -// (testChange.isCohort && eData.some((change) => !change.isCohort)) -// || (!testChange.isCohort && eData.some((change) => change.isCohort)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} has inconsistent 'isCohort' entries.`); -// } -// // If eData.isMember or eData.isCohort, first see if there already is such an effect on the doc -// if (testChange.isMember) { -// if (toMemberEffects.length > 1) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} Has Multiple 'APPLYTOMEMBERS' Active Effects`); -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewAbilityDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isMember; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toMemberEffects.length === 1) { -// const abilityEffect = toMemberEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOMEMBERS", -// mode: 0, -// priority: null, -// value: `${aName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Crew Ability)` -// }); -// } -// // Create new ActiveEffect -// return crewAbilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else if (testChange.isCohort) { -// if (toCohortEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} Has Multiple 'APPLYTOCOHORTS' Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewAbilityDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isCohort; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toCohortEffects.length === 1) { -// const abilityEffect = toCohortEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOCOHORTS", -// mode: 0, -// priority: null, -// value: `${aName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Crew Ability)` -// }); -// } -// // Create new ActiveEffect -// return crewAbilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else { -// if (standardEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Crew Ability ${aName} Has Multiple Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewAbilityDoc.img ?? "", -// changes: eData -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (standardEffects.length === 1) { -// const abilityEffect = standardEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } -// // Create new ActiveEffect -// return crewAbilityDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } -// }), -// ...Object.entries(JSONDATA.CREW_UPGRADES.RollMods) -// .map(async ([aName, eData]) => { -// // Get crew upgrade doc -// const crewUpgradeDoc = game.items.getName(aName); -// if (!crewUpgradeDoc) { -// eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} Not Found.`); -// return undefined; -// } -// // Get active effects on crewUpgradeDoc -// const abilityEffects = Array.from(crewUpgradeDoc.effects ?? []) as BladesActiveEffect[]; -// // Separate out 'APPLYTOMEMBERS' and 'APPLYTOCOHORTS' ActiveEffects -// const toMemberEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOMEMBERS")); -// const toCohortEffects = abilityEffects.filter((effect) => effect.changes.some((change) => change.key === "APPLYTOCOHORTS")); -// const standardEffects = abilityEffects.filter((effect) => effect.changes.every((change) => !["APPLYTOMEMBERS", "APPLYTOCOHORTS"].includes(change.key))); -// // Confirm eData.isMember and eData.isCohort are consistent across all changes. -// const testChange = eData[0]; -// if ( -// (testChange.isMember && eData.some((change) => !change.isMember)) -// || (!testChange.isMember && eData.some((change) => change.isMember)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} has inconsistent 'isMember' entries.`); -// } -// if ( -// (testChange.isCohort && eData.some((change) => !change.isCohort)) -// || (!testChange.isCohort && eData.some((change) => change.isCohort)) -// ) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} has inconsistent 'isCohort' entries.`); -// } -// // If eData.isMember or eData.isCohort, first see if there already is such an effect on the doc -// if (testChange.isMember) { -// if (toMemberEffects.length > 1) { -// return eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} Has Multiple 'APPLYTOMEMBERS' Active Effects`); -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewUpgradeDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isMember; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toMemberEffects.length === 1) { -// const abilityEffect = toMemberEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOMEMBERS", -// mode: 0, -// priority: null, -// value: `${aName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Crew Upgrade)` -// }); -// } -// // Create new ActiveEffect -// return crewUpgradeDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else if (testChange.isCohort) { -// if (toCohortEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} Has Multiple 'APPLYTOCOHORTS' Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewUpgradeDoc.img ?? "", -// changes: eData.map((change) => { -// delete change.isCohort; -// return change; -// }) -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (toCohortEffects.length === 1) { -// const abilityEffect = toCohortEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } else { -// effectData.changes.unshift({ -// key: "APPLYTOCOHORTS", -// mode: 0, -// priority: null, -// value: `${aName.replace(/\s*\([^()]*? (Ability|Upgrade)\)\s*$/, "")} (Crew Upgrade)` -// }); -// } -// // Create new ActiveEffect -// return crewUpgradeDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } else { -// if (standardEffects.length > 1) { -// eLog.error("updateRollMods", `updateRollMods: Crew Upgrade ${aName} Has Multiple Active Effects`); -// return undefined; -// } -// // Initialize new effect data -// const effectData: { -// name: string, -// icon: string, -// changes: Array> -// } = { -// name: aName, -// icon: crewUpgradeDoc.img ?? "", -// changes: eData -// }; -// // Derive new effect data from existing effect, if any, then delete existing effect -// if (standardEffects.length === 1) { -// const abilityEffect = standardEffects[0] ; -// effectData.name = abilityEffect.name ?? effectData.name; -// effectData.icon = abilityEffect.icon ?? effectData.icon; -// effectData.changes.unshift(...abilityEffect.changes.filter((change) => change.key !== "system.roll_mods")); -// await abilityEffect.delete(); -// } -// // Create new ActiveEffect -// return crewUpgradeDoc.createEmbeddedDocuments("ActiveEffect", [effectData]); -// } -// }) -// ]); -// }; -// export const updateDescriptions = async () => { -// return Promise.all(Object.entries({ -// ...JSONDATA.ABILITIES.Descriptions, -// ...JSONDATA.CREW_ABILITIES.Descriptions, -// ...JSONDATA.CREW_UPGRADES.Descriptions -// }) -// .map(async ([aName, desc]) => { -// const itemDoc = game.items.getName(aName); -// if (!itemDoc) { -// eLog.error("applyRollEffects", `ApplyDescriptions: Item Doc ${aName} Not Found.`); -// return undefined; -// } -// // Update system.notes -// return itemDoc.update({"system.notes": desc}); -// })); -// }; diff --git a/module/documents/BladesActiveEffect.js b/module/documents/BladesActiveEffect.js deleted file mode 100644 index d5b8b35a..00000000 --- a/module/documents/BladesActiveEffect.js +++ /dev/null @@ -1,371 +0,0 @@ -import BladesActor from "../BladesActor.js"; -import U from "../core/utilities.js"; -import { Tag, BladesPhase, BladesActorType } from "../core/constants.js"; -const FUNCQUEUE = {}; -// {type: "ability", name: "rX:/^(?!Ghost)/"} -const CUSTOMFUNCS = { - addItem: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "addItem", { actor, funcData, isReversing }); - if (actor.hasActiveSubItemOf(funcData)) { - if (isReversing) { - return actor.remSubItem(funcData); - } - } - else if (!isReversing) { - return actor.addSubItem(funcData); - } - return undefined; - }, - addIfChargen: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "addIfChargen", { actor, funcData, isReversing }); - if (!isReversing && game.eunoblades.Tracker?.system.phase !== BladesPhase.CharGen) { - return; - } - const [target, qty] = funcData.split(/:/); - if (isReversing) { - await actor.update({ [target]: U.pInt(getProperty(actor, target)) - U.pInt(qty) }); - return; - } - await actor.update({ [target]: U.pInt(getProperty(actor, target)) + U.pInt(qty) }); - }, - upgradeIfChargen: async (actor, funcData, _, isReversing = false) => { - eLog.checkLog("activeEffects", "upgradeIfChargen", { actor, funcData, isReversing }); - if (!isReversing && game.eunoblades.Tracker?.system.phase !== BladesPhase.CharGen) { - return; - } - const [target, qty] = funcData.split(/:/); - if (getProperty(actor, target) < U.pInt(qty)) { - await actor.update({ [target]: U.pInt(qty) }); - } - }, - APPLYTOMEMBERS: async () => undefined, - APPLYTOCOHORTS: async () => undefined, - remItem: async (actor, funcData, _, isReversing = false) => { - function testString(targetString, testDef) { - if (testDef.startsWith("rX")) { - const pat = new RegExp(testDef.replace(/^rX:\/(.*?)\//, "$1")); - return pat.test(targetString); - } - return targetString === testDef; - } - if (funcData.startsWith("{")) { - if (isReversing) { - console.error("Cannot reverse a 'remItem' custom effect that was defined with a JSON object."); - return undefined; - } - const { type, tags, name } = JSON.parse(funcData); - let activeSubItems = actor.activeSubItems; - if (activeSubItems.length === 0) { - return undefined; - } - if (name) { - activeSubItems = activeSubItems.filter((item) => testString(item.name, name)); - } - if (activeSubItems.length === 0) { - return undefined; - } - if (type) { - activeSubItems = activeSubItems.filter((item) => testString(item.type, type)); - } - if (activeSubItems.length === 0) { - return undefined; - } - if (tags) { - activeSubItems = activeSubItems.filter((item) => item.hasTag(...tags)); - } - if (activeSubItems.length === 0) { - return undefined; - } - eLog.checkLog("activeEffects", "remItem - JSON OBJECT", { actor, funcData: JSON.parse(funcData), isReversing, activeSubItems }); - activeSubItems.forEach((item) => actor.remSubItem(item)); - } - eLog.checkLog("activeEffects", "remItem", { actor, funcData, isReversing }); - if (actor.hasActiveSubItemOf(funcData)) { - return actor.remSubItem(funcData); - } - if (isReversing) { - return actor.addSubItem(funcData); - } - return undefined; - } -}; -var EffectMode; -(function (EffectMode) { - EffectMode[EffectMode["Custom"] = 0] = "Custom"; - EffectMode[EffectMode["Multiply"] = 1] = "Multiply"; - EffectMode[EffectMode["Add"] = 2] = "Add"; - EffectMode[EffectMode["Downgrade"] = 3] = "Downgrade"; - EffectMode[EffectMode["Upgrade"] = 4] = "Upgrade"; - EffectMode[EffectMode["Override"] = 5] = "Override"; -})(EffectMode || (EffectMode = {})); -class BladesActiveEffect extends ActiveEffect { - static Initialize() { - CONFIG.ActiveEffect.documentClass = BladesActiveEffect; - Hooks.on("preCreateActiveEffect", async (effect) => { - eLog.checkLog3("effect", "PRECREATE ActiveEffect", { effect, parent: effect.parent?.name }); - if (!(effect.parent instanceof BladesActor)) { - return; - } - // Does this effect have an "APPLYTOMEMBERS" or "APPLYTOCOHORTS" CUSTOM effect? - if (effect.changes.some((change) => change.key === "APPLYTOMEMBERS")) { - if (BladesActor.IsType(effect.parent, BladesActorType.pc) - && BladesActor.IsType(effect.parent.crew, BladesActorType.crew)) { - const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id); - if (otherMembers.length > 0) { - // If PC & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key, leave PC's effect unchanged. - effect.changes = effect.changes.filter((change) => change.key !== "APPLYTOMEMBERS"); - await Promise.all(otherMembers.map(async (member) => member.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - // Set flag with effect's data on member, so future members can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `memberEffects.${effect.id}`, { - appliedTo: otherMembers.map((member) => member.id), - effect: effect.toJSON() - }); - } - } - else if (BladesActor.IsType(effect.parent, BladesActorType.crew)) { - const changeKey = U.pullElement(effect.changes, (change) => change.key === "APPLYTOMEMBERS"); - if (!changeKey) { - return; - } - if (effect.parent.members.length > 0) { - // If Crew & APPLYTOMEMBERS --> Create effect on members MINUS the 'APPLYTOMEMBERS' key - await Promise.all(effect.parent.members.map(async (member) => member.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - } - // Set flag with effect's data on crew, so future members can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `memberEffects.${effect.id}`, { - appliedTo: effect.parent.members.map((member) => member.id), - effect - }); - // Update effect on crew-parent to only include 'APPLYTOMEMBERS' change - await effect.updateSource({ changes: [changeKey] }); - } - } - else if (effect.changes.some((change) => change.key === "APPLYTOCOHORTS") - && (BladesActor.IsType(effect.parent, BladesActorType.pc) - || BladesActor.IsType(effect.parent, BladesActorType.crew))) { - if (effect.parent.cohorts.length > 0) { - // If APPLYTOCOHORTS --> Create effect on cohorts - await Promise.all(effect.parent.cohorts.map(async (cohort) => cohort.createEmbeddedDocuments("ActiveEffect", [effect.toJSON()]))); - } - // Set flag with effect's data on parent, so future cohorts can have effect applied to them. - await effect.parent.setFlag("eunos-blades", `cohortEffects.${effect.id}`, { - appliedTo: effect.parent.cohorts.map((cohort) => cohort.id), - effect - }); - // Update effect on parent to only include 'APPLYTOCOHORTS' change - await effect.updateSource({ changes: effect.changes.filter((change) => change.key === "APPLYTOCOHORTS") }); - } - // Partition effect.changes into permanent and non-permanent changes: - const [permChanges, changes] = U.partition(effect.changes, (change) => change.key.startsWith("perm")); - await effect.updateSource({ changes }); - for (const permChange of permChanges) { - const { key, value } = permChange; - const permFuncName = key.replace(/^perm/, ""); - if (permFuncName in CUSTOMFUNCS) { - const funcData = { - funcName: permFuncName, - funcData: value, - isReversing: false, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - } - else if (permFuncName === "Add") { - const [target, qty] = value.split(/:/); - effect.parent.update({ [target]: U.pInt(getProperty(effect.parent, target)) + U.pInt(qty) }); - } - } - }); - Hooks.on("applyActiveEffect", (actor, changeData) => { - if (!(actor instanceof BladesActor)) { - return; - } - if (changeData.key in CUSTOMFUNCS) { - const funcData = { - funcName: changeData.key, - funcData: changeData.value, - isReversing: false, - effect: changeData.effect - }; - BladesActiveEffect.ThrottleCustomFunc(actor, funcData); - } - }); - Hooks.on("updateActiveEffect", (effect, { disabled }) => { - if (!(effect.parent instanceof BladesActor)) { - return; - } - const customEffects = effect.changes.filter((changes) => changes.mode === 0); - customEffects.forEach(({ key, value }) => { - const funcData = { - funcName: key, - funcData: value, - isReversing: disabled, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - }); - }); - Hooks.on("deleteActiveEffect", async (effect) => { - if (!(effect.parent instanceof BladesActor)) { - return; - } - // Does this effect have an "APPLYTOMEMBERS" or "APPLYTOCOHORTS" CUSTOM effect? - if (effect.changes.some((change) => change.key === "APPLYTOMEMBERS")) { - if (BladesActor.IsType(effect.parent, BladesActorType.pc) - && BladesActor.IsType(effect.parent.crew, BladesActorType.crew)) { - const otherMembers = effect.parent.crew.members.filter((member) => member.id !== effect.parent?.id); - if (otherMembers.length > 0) { - // If PC & APPLYTOMEMBERS --> Delete effect on all other members. - await Promise.all(otherMembers - .map(async (member) => Promise.all(member.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `memberEffects.${effect.id}`); - } - else if (BladesActor.IsType(effect.parent, BladesActorType.crew)) { - if (effect.parent.members.length > 0) { - // If CREW & APPLYTOMEMBERS --> Delete effect on all other members. - await Promise.all(effect.parent.members - .map(async (member) => Promise.all(member.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `memberEffects.${effect.id}`); - } - } - else if (effect.changes.some((change) => change.key === "APPLYTOCOHORTS") - && (BladesActor.IsType(effect.parent, BladesActorType.pc, BladesActorType.crew))) { - if (effect.parent.cohorts.length > 0) { - // If APPLYTOCOHORTS --> Delete effect on cohorts. - await Promise.all(effect.parent.cohorts - .map(async (cohort) => Promise.all(cohort.effects - .filter((e) => e.name === effect.name) - .map(async (e) => e.delete())))); - } - // Clear flag from parent - await effect.parent.unsetFlag("eunos-blades", `cohortEffects.${effect.id}`); - } - const customEffects = effect.changes.filter((changes) => changes.mode === 0); - customEffects.forEach(({ key, value }) => { - const funcData = { - funcName: key, - funcData: value, - isReversing: true, - effect - }; - BladesActiveEffect.ThrottleCustomFunc(effect.parent, funcData); - }); - }); - } - static async AddActiveEffect(doc, name, eChanges, icon = "systems/eunos-blades/assets/icons/effect-icons/default.png") { - const changes = [eChanges].flat(); - await doc.createEmbeddedDocuments("ActiveEffect", [{ name, icon, changes }]); - } - static ThrottleCustomFunc(actor, data) { - const { funcName, funcData, isReversing, effect } = data; - if (!actor.id) { - return; - } - eLog.checkLog3("activeEffect", `Throttling Func: ${funcName}(${funcData}, ${isReversing})`); - // Is there a currently-running function for this actor? - if (actor.id && actor.id in FUNCQUEUE) { - // Is this a duplicate of a function already queued? - const matchingQueue = FUNCQUEUE[actor.id].queue - .find((fData) => JSON.stringify(fData) === JSON.stringify(data)); - eLog.checkLog("activeEffects", "... Checking Queue", { data, FUNCQUEUE: FUNCQUEUE[actor.id], matchingQueue }); - if (matchingQueue) { - eLog.error("... Function ALREADY QUEUED, SKIPPING"); - return; - } - FUNCQUEUE[actor.id].queue.push(data); - return; - } - // If not, create FUNCQUEUE entry and run first function. - eLog.checkLog3("activeEffect", "... Creating New FUNCQUEUE, RUNNING:"); - FUNCQUEUE[actor.id] = { - curFunc: BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing)), - queue: [] - }; - } - static async RunCustomFunc(actor, funcPromise) { - if (!actor.id) { - return; - } - eLog.checkLog("activeEffects", "... Running Func ..."); - await funcPromise; - eLog.checkLog("activeEffects", "... Function Complete!"); - if (FUNCQUEUE[actor.id].queue.length) { - const { funcName, funcData, isReversing, effect } = FUNCQUEUE[actor.id].queue.shift() ?? {}; - if (!funcName || !(funcName in CUSTOMFUNCS)) { - return; - } - if (!funcData) { - return; - } - eLog.checkLog3("activeEffect", `Progressing Queue: ${funcName}(${funcData}, ${isReversing}) -- ${FUNCQUEUE[actor.id].queue.length} remaining funcs.`); - FUNCQUEUE[actor.id].curFunc = BladesActiveEffect.RunCustomFunc(actor, CUSTOMFUNCS[funcName](actor, funcData, effect, isReversing)); - } - else { - eLog.checkLog3("activeEffect", "Function Queue Complete! Deleting."); - delete FUNCQUEUE[actor.id]; - } - } - /** - * Manage Active Effect instances through the Actor Sheet via effect control buttons. - * @param {MouseEvent} event The left-click event on the effect control - * @param {Actor|Item} owner The owning entity which manages this effect - */ - static onManageActiveEffect(event, owner) { - event.preventDefault(); - const a = event.currentTarget; - if (a.dataset.action === "create") { - return owner.createEmbeddedDocuments("ActiveEffect", [{ - name: owner.name, - icon: owner.img, - origin: owner.uuid - }]); - } - const selector = a.closest("tr"); - if (selector === null) { - return null; - } - const effect = selector.dataset.effectId - ? owner.effects.get(selector.dataset.effectId) - : null; - if (!effect) { - return null; - } - switch (a.dataset.action) { - case "edit": - return effect.sheet?.render(true); - case "delete": - eLog.checkLog("activeEffects", "delete effect"); - return effect.delete(); - case "toggle": - return effect.update({ disabled: !effect.disabled }); - default: return null; - } - } - async _preCreate(data, options, user) { - eLog.checkLog3("effect", "ActiveEffect._preCreate()", { data, options, user }); - await super._preCreate(data, options, user); - } - _onDelete(options, userID) { - eLog.checkLog3("effect", "ActiveEffect._onDelete()", { options, userID }); - super._onDelete(options, userID); - } - get isSuppressed() { - // Get source item from "origin.js" field -- of form 'Actor..Item.' - if (!/Actor.*Item/.test(this.origin)) { - return super.isSuppressed; - } - const [actorID, itemID] = this.origin.replace(/Actor\.|Item\./g, "").split("."); - const actor = game.actors.get(actorID); - const item = actor.items.get(itemID); - return super.isSuppressed || item?.hasTag(Tag.System.Archived); - } -} -export default BladesActiveEffect; diff --git a/module/documents/BladesActorProxy.js b/module/documents/BladesActorProxy.js deleted file mode 100644 index 6ef840f3..00000000 --- a/module/documents/BladesActorProxy.js +++ /dev/null @@ -1,51 +0,0 @@ -import U from "../core/utilities.js"; -import { BladesActorType } from "../core/constants.js"; -import BladesActor from "../BladesActor.js"; -import BladesPC from "./actors/BladesPC.js"; -import BladesNPC from "./actors/BladesNPC.js"; -import BladesFaction from "./actors/BladesFaction.js"; -import BladesCrew from "./actors/BladesCrew.js"; -const ActorsMap = { - [BladesActorType.pc]: BladesPC, - [BladesActorType.npc]: BladesNPC, - [BladesActorType.faction]: BladesFaction, - [BladesActorType.crew]: BladesCrew -}; -// eslint-disable-next-line @typescript-eslint/no-empty-function -const BladesActorProxy = new Proxy(function () { }, { - construct(_, args) { - const [{ type }] = args; - if (!type) { - throw new Error(`Invalid Actor Type: ${String(type)}`); - } - const MappedConstructor = ActorsMap[type]; - if (!MappedConstructor) { - return new BladesActor(...args); - } - return new MappedConstructor(...args); - }, - get(_, prop) { - switch (prop) { - case "create": - case "createDocuments": - return function (data, options = {}) { - if (U.isArray(data)) { - return data.map((i) => CONFIG.Actor.documentClass.create(i, options)); - } - const MappedConstructor = ActorsMap[data.type]; - if (!MappedConstructor) { - return BladesActor.create(data, options); - } - return MappedConstructor.create(data, options); - }; - case Symbol.hasInstance: - return function (instance) { - return Object.values(ActorsMap).some((i) => instance instanceof i); - }; - default: - return BladesActor[prop]; - } - } -}); -export default BladesActorProxy; -export { BladesActor, BladesPC, BladesCrew, BladesNPC, BladesFaction }; diff --git a/module/documents/BladesItemProxy.js b/module/documents/BladesItemProxy.js deleted file mode 100644 index 5064c5e4..00000000 --- a/module/documents/BladesItemProxy.js +++ /dev/null @@ -1,53 +0,0 @@ -import U from "../core/utilities.js"; -import { BladesItemType } from "../core/constants.js"; -import BladesItem from "../BladesItem.js"; -import BladesProject from "./items/BladesProject.js"; -import BladesLocation from "./items/BladesLocation.js"; -import BladesClockKeeper from "./items/BladesClockKeeper.js"; -import BladesGMTracker from "./items/BladesGMTracker.js"; -import BladesScore from "./items/BladesScore.js"; -const ItemsMap = { - [BladesItemType.clock_keeper]: BladesClockKeeper, - [BladesItemType.gm_tracker]: BladesGMTracker, - [BladesItemType.location]: BladesLocation, - [BladesItemType.project]: BladesProject, - [BladesItemType.score]: BladesScore -}; -// eslint-disable-next-line @typescript-eslint/no-empty-function -const BladesItemProxy = new Proxy(function () { }, { - construct(_, args) { - const [{ type }] = args; - if (!type) { - throw new Error(`Invalid Item Type: ${String(type)}`); - } - const MappedConstructor = ItemsMap[type]; - if (!MappedConstructor) { - return new BladesItem(...args); - } - return new MappedConstructor(...args); - }, - get(_, prop) { - switch (prop) { - case "create": - case "createDocuments": - return function (data, options = {}) { - if (U.isArray(data)) { - return data.map((i) => CONFIG.Item.documentClass.create(i, options)); - } - const MappedConstructor = ItemsMap[data.type]; - if (!MappedConstructor) { - return BladesItem.create(data, options); - } - return MappedConstructor.create(data, options); - }; - case Symbol.hasInstance: - return function (instance) { - return Object.values(ItemsMap).some((i) => instance instanceof i); - }; - default: - return BladesItem[prop]; - } - } -}); -export default BladesItemProxy; -export { BladesItem, BladesClockKeeper, BladesGMTracker, BladesLocation, BladesProject, BladesScore }; diff --git a/module/documents/actors/BladesCrew.js b/module/documents/actors/BladesCrew.js deleted file mode 100644 index 36eb8503..00000000 --- a/module/documents/actors/BladesCrew.js +++ /dev/null @@ -1,160 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BladesActorType, BladesItemType, Tag } from "../../core/constants.js"; -import { BladesActor, BladesPC } from "../BladesActorProxy.js"; -import BladesCrewSheet from "../../sheets/actor/BladesCrewSheet.js"; -import { BladesItem } from "../BladesItemProxy.js"; -import { SelectionCategory } from "../../classes/BladesDialog.js"; -class BladesCrew extends BladesActor { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesCrew, BladesCrewSheet }); - Actors.registerSheet("blades", BladesCrewSheet, { types: ["crew"], makeDefault: true }); - return loadTemplates(["systems/eunos-blades/templates/crew-sheet.hbs"]); - } - // #endregion - // #region Static Overrides: Create ~ - // static override IsType(doc: unknown): doc is BladesActorOfType { - // return super.IsType(doc, BladesActorType.crew); - // } - static IsType(doc) { - return super.IsType(doc, BladesActorType.crew); - } - static GetFromUser(userRef) { - const actor = BladesPC.GetFromUser(userRef); - if (!actor) { - return undefined; - } - return actor.crew; - } - static GetFromPC(pcRef) { - let actor; - if (typeof pcRef === "string") { - actor = game.actors.get(pcRef) ?? game.actors.getName(pcRef); - } - else if (pcRef instanceof BladesPC) { - actor = pcRef; - } - else { - actor ??= BladesPC.GetFromUser(pcRef); - } - if (!BladesPC.IsType(actor)) { - throw new Error(`Unable to find BladesPC from "${pcRef}.js"`); - } - return actor.crew; - } - static async create(data, options = {}) { - data.token = data.token || {}; - data.system = data.system ?? {}; - eLog.checkLog2("actor", "BladesActor.create(data,options)", { data, options }); - // ~ For Crew and PC set the Token to sync with charsheet. - data.token.actorLink = true; - // ~ Create world_name - data.system.world_name = data.system.world_name ?? data.name.replace(/[^A-Za-z_0-9 ]/g, "").trim().replace(/ /g, "_"); - // ~ Initialize generic experience clues. - data.system.experience = { - playbook: { value: 0, max: 8 }, - clues: [], - ...data.system.experience ?? {} - }; - return super.create(data, options); - } - // #endregion - // #region BladesCrew Implementation - getDialogItems(category) { - const dialogData = {}; - const { playbookName } = this; - if (category === SelectionCategory.Playbook) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.crew_playbook)); - } - else if (category === SelectionCategory.Reputation) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.crew_reputation)); - } - else if (category === SelectionCategory.Preferred_Op && playbookName !== null) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.preferred_op, playbookName)); - } - else if (category === SelectionCategory.Ability) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.crew_ability, this.playbookName)); - } - else if (category === SelectionCategory.Upgrade && playbookName !== null) { - dialogData[playbookName] = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.crew_upgrade, playbookName)); - dialogData.General = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.crew_upgrade, Tag.Gear.General)); - } - return dialogData; - } - get members() { - if (!BladesActor.IsType(this, BladesActorType.crew)) { - return []; - } - const self = this; - return BladesActor.GetTypeWithTags(BladesActorType.pc).filter((actor) => actor.isMember(self)); - } - get contacts() { - if (!BladesActor.IsType(this, BladesActorType.crew) || !this.playbook) { - return []; - } - const self = this; - return this.activeSubActors.filter((actor) => actor.hasTag(self.playbookName)); - } - get claims() { - if (!BladesActor.IsType(this, BladesActorType.crew) || !this.playbook) { - return {}; - } - return this.playbook.system.turfs; - } - get turfCount() { - if (!BladesActor.IsType(this, BladesActorType.crew) || !this.playbook) { - return 0; - } - return Object.values(this.playbook.system.turfs) - .filter((claim) => claim.isTurf && claim.value).length; - } - get upgrades() { - if (!BladesActor.IsType(this, BladesActorType.crew) || !this.playbook) { - return []; - } - return this.activeSubItems - .filter((item) => item.type === BladesItemType.crew_upgrade); - } - get cohorts() { - return this.activeSubItems - .filter((item) => [BladesItemType.cohort_gang, BladesItemType.cohort_expert].includes(item.type)); - } - getTaggedItemBonuses(tags) { - // Given a list of item tags, will return the total bonuses to that item - // Won't return a number, but an object literal that includes things like extra load space or concealability - // Check ACTIVE EFFECTS supplied by upgrade/ability against submitted tags? - return tags.length; // Placeholder to avoid linter error - } - // #endregion - // #region BladesRoll Implementation - // #region BladesRoll.ParticipantDoc Implementation - get rollParticipantID() { return this.id; } - get rollParticipantDoc() { return this; } - get rollParticipantIcon() { return this.playbook?.img ?? this.img; } - get rollParticipantName() { return this.name; } - get rollParticipantType() { return this.type; } - get rollParticipantModsSchemaSet() { return []; } - async applyHarm(_amount, _name) { - console.error("Attempt to apply harm directly to a Crew document."); - } - async applyWorsePosition() { - console.error("Attempt to apply worse position directly to a Crew document."); - } - // #endregion - // #endregion - get abilities() { - if (!this.playbook) { - return []; - } - return this.activeSubItems - .filter((item) => [BladesItemType.ability, BladesItemType.crew_ability].includes(item.type)); - } - get playbookName() { - return this.playbook?.name; - } - get playbook() { - return this.activeSubItems - .find((item) => item.type === BladesItemType.crew_playbook); - } -} -export default BladesCrew; diff --git a/module/documents/actors/BladesFaction.js b/module/documents/actors/BladesFaction.js deleted file mode 100644 index 54b34389..00000000 --- a/module/documents/actors/BladesFaction.js +++ /dev/null @@ -1,52 +0,0 @@ -import { BladesActorType } from "../../core/constants.js"; -import { BladesActor } from "../BladesActorProxy.js"; -import BladesFactionSheet from "../../sheets/actor/BladesFactionSheet.js"; -import BladesClockKey from "../../classes/BladesClockKey.js"; -class BladesFaction extends BladesActor { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesFaction, BladesFactionSheet }); - Actors.registerSheet("blades", BladesFactionSheet, { types: ["faction"], makeDefault: true }); - return loadTemplates(["systems/eunos-blades/templates/faction-sheet.hbs"]); - } - // #endregion - static get All() { - return new Collection(super.GetTypeWithTags(BladesActorType.faction) - .map((faction) => [faction.id, faction])); - } - static IsType(doc) { - return super.IsType(doc, BladesActorType.faction); - } - // #region BladesRoll Implementation - // #region BladesRoll.OppositionDoc Implementation - get rollOppID() { return this.id; } - get rollOppDoc() { return this; } - get rollOppImg() { return this.img ?? ""; } - get rollOppName() { return this.name ?? ""; } - get rollOppSubName() { return this.system.subtitle || this.system.concept || " "; } - get rollOppType() { return this.type; } - get rollOppModsSchemaSet() { return []; } - // #endregion - // #endregion - // _clocks: Collection = new Collection(); - // get clocks(): Collection = { - // return new Collection() - // } - get clocks() { - return new Collection(Object.entries(this.system.clocksData ?? {}) - .map(([id, data]) => [ - id, - game.eunoblades.ClockKeys.get(id) ?? new BladesClockKey(data) - ])); - } - async addClock() { - return await BladesClockKey.Create({ - target: this, - targetKey: "system.clocksData" - }); - } - async deleteClock(clockKeyID) { - await game.eunoblades.ClockKeys.get(clockKeyID)?.delete(game.eunoblades.ClockKeys); - } -} -export default BladesFaction; diff --git a/module/documents/actors/BladesNPC.js b/module/documents/actors/BladesNPC.js deleted file mode 100644 index c6723631..00000000 --- a/module/documents/actors/BladesNPC.js +++ /dev/null @@ -1,60 +0,0 @@ -import { BladesActorType, Factor } from "../../core/constants.js"; -import BladesActor from "../../BladesActor.js"; -import BladesNPCSheet from "../../sheets/actor/BladesNPCSheet.js"; -class BladesNPC extends BladesActor { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesNPC, BladesNPCSheet }); - Actors.registerSheet("blades", BladesNPCSheet, { types: ["npc"], makeDefault: true }); - return loadTemplates(["systems/eunos-blades/templates/npc-sheet.hbs"]); - } - // #endregion - static IsType(doc) { - return super.IsType(doc, BladesActorType.npc); - } - // #region BladesRoll Implementation - get rollFactors() { - const factorData = super.rollFactors; - factorData[Factor.scale] = { - name: Factor.scale, - display: "Scale", - value: this.getFactorTotal(Factor.scale), - max: this.getFactorTotal(Factor.scale), - baseVal: this.getFactorTotal(Factor.scale), - cssClasses: "factor-grey", - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }; - factorData[Factor.magnitude] = { - name: Factor.magnitude, - display: "Magnitude", - value: this.getFactorTotal(Factor.magnitude), - max: this.getFactorTotal(Factor.magnitude), - baseVal: this.getFactorTotal(Factor.magnitude), - isActive: false, - isPrimary: false, - isDominant: false, - highFavorsPC: true - }; - return factorData; - } - // #region BladesRoll.OppositionDoc Implementation - get rollOppID() { return this.id; } - get rollOppDoc() { return this; } - get rollOppImg() { return this.img; } - get rollOppName() { return this.name; } - get rollOppSubName() { return this.system.subtitle || this.system.concept || " "; } - get rollOppType() { return this.type; } - get rollOppModsSchemaSet() { return []; } - // #endregion - // #region BladesRoll.ParticipantDoc Implementation - get rollParticipantID() { return this.id; } - get rollParticipantDoc() { return this; } - get rollParticipantIcon() { return this.img; } - get rollParticipantName() { return this.name; } - get rollParticipantType() { return this.type; } - get rollParticipantModsSchemaSet() { return []; } -} -export default BladesNPC; diff --git a/module/documents/actors/BladesPC.js b/module/documents/actors/BladesPC.js deleted file mode 100644 index 0fd0d4dc..00000000 --- a/module/documents/actors/BladesPC.js +++ /dev/null @@ -1,613 +0,0 @@ -import C, { BladesNoticeType, ClockColor, AttributeTrait, Harm, BladesActorType, BladesItemType, Tag, RollModType, RollModSection, RollModStatus } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import { BladesActor } from "../BladesActorProxy.js"; -import BladesPCSheet from "../../sheets/actor/BladesPCSheet.js"; -import { BladesItem } from "../BladesItemProxy.js"; -import BladesClockKey from "../../classes/BladesClockKey.js"; -import BladesDirector from "../../classes/BladesDirector.js"; -import { SelectionCategory } from "../../classes/BladesDialog.js"; -class BladesPC extends BladesActor { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesPC, BladesPCSheet }); - Actors.registerSheet("blades", BladesPCSheet, { types: ["pc"], makeDefault: true }); - Hooks.on("dropActorSheetData", async (parentActor, _, { uuid }) => { - const doc = fromUuidSync(uuid); - if (doc instanceof BladesActor) { - if (parentActor.type === BladesActorType.crew && doc.type === BladesActorType.pc) { - // Dropping a PC onto a Crew Sheet: Add Crew to PC - doc.addSubActor(parentActor); - } - else if (parentActor.type === BladesActorType.pc && doc.type === BladesActorType.crew) { - // Dropping a Crew onto a PC Sheet: Add - parentActor.addSubActor(doc); - } - } - }); - return loadTemplates(["systems/eunos-blades/templates/actor-sheet.hbs"]); - } - // #endregion - // #region Static Overrides: Create, get All ~ - // static override IsType(doc: unknown): doc is BladesActorOfType { - // return super.IsType(doc, BladesActorType.pc); - // } - static IsType(doc) { - return super.IsType(doc, BladesActorType.pc); - } - static GetUser(userRef) { - let user; - if (typeof userRef === "string") { - user = game.users.get(userRef) ?? game.users.getName(userRef); - } - else if (userRef instanceof User) { - user = userRef; - } - return user; - } - static GetFromUser(userRef) { - const user = BladesPC.GetUser(userRef); - if (!user) { - throw new Error(`Unable to find user '${userRef}'`); - } - const actor = game.actors.get(user.character?.id ?? ""); - if (BladesPC.IsType(actor)) { - return actor; - } - return undefined; - } - static async create(data, options = {}) { - data.token = data.token || {}; - data.system = data.system ?? {}; - eLog.checkLog2("actor", "BladesPC.create(data,options)", { data, options }); - // ~ Set the Token to sync with charsheet. - data.token.actorLink = true; - // ~ Initialize generic experience clues. - data.system.experience = { - playbook: { value: 0, max: 8 }, - insight: { value: 0, max: 6 }, - prowess: { value: 0, max: 6 }, - resolve: { value: 0, max: 6 }, - clues: [], - ...data.system.experience ?? {} - }; - const pc = (await super.create(data, options)); - await BladesClockKey.Create({ - name: "", - target: pc, - targetKey: "system.clocksData", - isVisible: true, - isNameVisible: false, - isSpotlit: false - }, undefined, [ - { - color: ClockColor.white, - value: 0, - max: 4, - index: 0, - isVisible: true, - isActive: true, - isNameVisible: false, - isHighlighted: false - } - ]); - return pc; - } - static get All() { - return new Collection(super.GetTypeWithTags(BladesActorType.pc) - .map((pc) => [pc.id, pc])); - } - // #endregion - constructor(data) { - super(data); - eLog.checkLog3("pcConstructor", "new BladesPC()", { data }); - } - // #region BladesPrimaryActor Implementation ~ - get primaryUser() { - return game.users?.find((user) => user.character?.id === this?.id) || null; - } - async clearLoadout() { - await this.update({ "system.loadout.selected": "" }); - this.updateEmbeddedDocuments("Item", [ - ...this.activeSubItems - .filter((item) => BladesItem.IsType(item, BladesItemType.gear) - && !item.hasTag(Tag.System.Archived)) - .map((item) => ({ - _id: item.id, - "system.tags": [...item.tags, Tag.System.Archived], - "system.uses_per_score.value": 0 - })), - ...this.activeSubItems - .filter((item) => BladesItem.IsType(item, BladesItemType.ability) - && item.system.uses_per_score.max) - .map((item) => ({ - _id: item.id, - "system.uses_per_score.value": 0 - })) - ]); - } - // #endregion - getSubActor(actorRef) { - const actor = super.getSubActor(actorRef); - if (!actor) { - return undefined; - } - if (this.primaryUser?.id) { - actor.ownership[this.primaryUser.id] = CONST.DOCUMENT_PERMISSION_LEVELS.OWNER; - } - return actor; - } - get isLightArmorEquipped() { return this.system.armor.active.light; } - get isLightArmorEquippable() { return !this.isLightArmorEquipped && this.remainingLoad >= 2; } - get isLightArmorUsed() { return this.system.armor.checked.light; } - get isLightArmorAvailable() { - return (this.isLightArmorEquipped || this.isLightArmorEquippable) - && !this.isLightArmorUsed; - } - get isHeavyArmorEquipped() { return this.system.armor.active.heavy; } - get isHeavyArmorEquippable() { - if (this.isHeavyArmorEquipped) { - return false; - } - if (this.isLightArmorEquipped) { - return this.remainingLoad >= 3; - } - return this.remainingLoad >= 5; - } - get isHeavyArmorUsed() { return this.system.armor.checked.heavy; } - get isHeavyArmorAvailable() { - return (this.isHeavyArmorEquipped || this.isHeavyArmorEquippable) - && !this.isHeavyArmorUsed; - } - get availableArmor() { - const armor = []; - if (this.isLightArmorAvailable) { - armor.push("Light Armor"); - } - if (this.isHeavyArmorAvailable) { - armor.push("Heavy Armor"); - } - return armor; - } - get isSpecialArmorAvailable() { - return this.system.armor.active.special && !this.system.armor.checked.special; - } - // #region BladesScoundrel Implementation ~ - isMember(crew) { return this.crew?.id === crew.id; } - get vice() { - if (this.type !== BladesActorType.pc) { - return undefined; - } - return this.activeSubItems.find((item) => item.type === BladesItemType.vice); - } - get crew() { - return this.activeSubActors - .find((subActor) => BladesActor.IsType(subActor, BladesActorType.crew)); - } - get abilities() { - if (!this.playbook) { - return []; - } - return this.activeSubItems - .filter((item) => [BladesItemType.ability, BladesItemType.crew_ability].includes(item.type)); - } - get cohorts() { - return this.activeSubItems - .filter((item) => BladesItem.IsType(item, BladesItemType.cohort_gang, BladesItemType.cohort_expert)); - } - get playbookName() { - return this.playbook?.name; - } - get playbook() { - return this.activeSubItems - .find((item) => item.type === BladesItemType.playbook); - } - get attributes() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return undefined; - } - return { - insight: Object.values(this.system.attributes.insight) - .filter(({ value }) => value > 0).length - + this.system.resistance_bonus.insight, - prowess: Object.values(this.system.attributes.prowess) - .filter(({ value }) => value > 0).length - + this.system.resistance_bonus.prowess, - resolve: Object.values(this.system.attributes.resolve) - .filter(({ value }) => value > 0).length - + this.system.resistance_bonus.resolve - }; - } - get actions() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return undefined; - } - return U.objMap({ - ...this.system.attributes.insight, - ...this.system.attributes.prowess, - ...this.system.attributes.resolve - }, ({ value, max }) => U.gsap.utils.clamp(0, max, value)); - } - get rollable() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return undefined; - } - return { - ...this.attributes, - ...this.actions - }; - } - get stress() { - return this.system.stress.value; - } - get stressMax() { - return this.system.stress.max; - } - get isHealingClockReady() { - const [clockKeyID] = Object.keys(this.system.clocksData); - return game.eunoblades.ClockKeys.has(clockKeyID ?? ""); - } - get healingClock() { - if (!this.isHealingClockReady) { - return undefined; - } - const [clockKeyID] = Object.keys(this.system.clocksData); - const clockKey = game.eunoblades.ClockKeys.get(clockKeyID ?? ""); - return clockKey; - } - get harmLevel() { - if (this.system.harm.severe.one.length > 1) { - return 3; - } - if ((this.system.harm.moderate.one.length + this.system.harm.moderate.two.length) > 0) { - return 2; - } - if ((this.system.harm.lesser.one.length + this.system.harm.lesser.two.length) > 0) { - return 1; - } - return 0; - } - get trauma() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return 0; - } - return Object.keys(this.system.trauma.checked) - .filter((traumaName) => - // @ts-ignore Compiler linter mismatch. - this.system.trauma.active[traumaName] && this.system.trauma.checked[traumaName]) - .length; - } - get traumaList() { - // @ts-ignore Compiler linter mismatch. - return BladesActor.IsType(this, BladesActorType.pc) - ? Object.keys(this.system.trauma.active).filter((key) => this.system.trauma.active[key]) - : []; - } - get activeTraumaConditions() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return {}; - } - return U.objFilter(this.system.trauma.checked, - // @ts-ignore Compiler linter mismatch. - (_v, traumaName) => Boolean(traumaName in this.system.trauma.active - && this.system.trauma.active[traumaName])); - } - get currentLoad() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return 0; - } - const activeLoadItems = this.activeSubItems.filter((item) => item.type === BladesItemType.gear); - return U.gsap.utils.clamp(0, 10, activeLoadItems.reduce((tot, i) => tot + U.pInt(i.system.load), 0)); - } - get remainingLoad() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return 0; - } - if (!this.system.loadout.selected) { - return 0; - } - const maxLoad = this.system.loadout.levels[game.i18n.localize(this.system.loadout.selected.toString()) - .toLowerCase()]; - return Math.max(0, maxLoad - this.currentLoad); - } - async addStash(amount) { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return; - } - await this.update({ "system.stash.value": Math.min(this.system.stash.value + amount, this.system.stash.max) }); - } - get projects() { - return this.getSubItemsOfType(BladesItemType.project); - } - get remainingDowntimeActions() { - if (!BladesActor.IsType(this, BladesActorType.pc)) { - return 0; - } - return this.system.downtime_actions.max + this.system.downtime_action_bonus - this.system.downtime_actions.value; - } - _processAbilityDialogItems(dialogData) { - if (!this.playbookName) { - return; - } - dialogData[this.playbookName] = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.ability, this.playbookName)); - dialogData.Veteran = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.ability)) - .filter((item) => !item.hasTag(this.playbookName)) - // Remove featured class from Veteran items - .map((item) => { - if (item.dialogCSSClasses) { - item.dialogCSSClasses = item.dialogCSSClasses.replace(/featured-item\s?/g, ""); - } - return item; - }) - // Re-sort by world_name - .sort((a, b) => { - if (a.system.world_name > b.system.world_name) { - return 1; - } - if (a.system.world_name < b.system.world_name) { - return -1; - } - return 0; - }); - } - processGearDialogItems(dialogData) { - if (this.playbookName === null) { - return; - } - const gearItems = this._processEmbeddedItemMatches([ - ...BladesItem.GetTypeWithTags(BladesItemType.gear, this.playbookName), - ...BladesItem.GetTypeWithTags(BladesItemType.gear, Tag.Gear.General) - ]) - .filter((item) => this.remainingLoad >= item.system.load); - // Two tabs, one for playbook and the other for general items - dialogData[this.playbookName] = gearItems.filter((item) => item.hasTag(this.playbookName)); - dialogData.General = gearItems - .filter((item) => item.hasTag(Tag.Gear.General)) - // Remove featured class from General items - .map((item) => { - if (item.dialogCSSClasses) { - item.dialogCSSClasses = item.dialogCSSClasses.replace(/featured-item\s?/g, ""); - } - return item; - }) - // Re-sort by world_name - .sort((a, b) => { - if (a.system.world_name > b.system.world_name) { - return 1; - } - if (a.system.world_name < b.system.world_name) { - return -1; - } - return 0; - }); - } - getDialogItems(category) { - const dialogData = {}; - const { playbookName } = this; - if (category === SelectionCategory.Heritage) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.heritage)); - } - else if (category === SelectionCategory.Background) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.background)); - } - else if (category === SelectionCategory.Vice && playbookName !== null) { - dialogData.Main = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.vice, playbookName)); - } - else if (category === SelectionCategory.Playbook) { - dialogData.Basic = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.playbook) - .filter((item) => !item.hasTag(Tag.Gear.Advanced))); - dialogData.Advanced = this._processEmbeddedItemMatches(BladesItem.GetTypeWithTags(BladesItemType.playbook, Tag.Gear.Advanced)); - } - else if (category === SelectionCategory.Gear) { - this.processGearDialogItems(dialogData); - } - else if (category === SelectionCategory.Ability) { - this._processAbilityDialogItems(dialogData); - } - return dialogData; - } - getTaggedItemBonuses(tags) { - // Given a list of item tags, will return the total bonuses to that item - // Won't return a number, but an object literal that includes things like extra load space or concealability - // Check ACTIVE EFFECTS supplied by ability against submitted tags? - // Should INCLUDE bonuses from crew. - return tags.length; // Placeholder to avoid linter error - } - // #endregion - // #region BladesRoll.PrimaryDoc Implementation - get rollPrimaryModsSchemaSet() { - const rollModsSchemaSet = super.rollPrimaryModsSchemaSet; - // Add roll mods from harm - [ - [/1d/, RollModSection.roll], - [/Less Effect/, RollModSection.effect] - ].forEach(([effectPat, effectCat]) => { - const { one: harmConditionOne, two: harmConditionTwo } = Object.values(this.system.harm) - .find((harmData) => effectPat.test(harmData.effect)) ?? {}; - const harmString = U.objCompact([harmConditionOne, harmConditionTwo === "" ? null : harmConditionTwo]).join(" & "); - if (harmString.length > 0) { - rollModsSchemaSet.push({ - key: `Harm-negative-${effectCat}`, - name: harmString, - section: effectCat, - posNeg: "negative", - base_status: RollModStatus.ToggledOn, - modType: RollModType.harm, - value: 1, - tooltip: [ - `

${effectCat === RollModSection.roll ? Harm.Impaired : Harm.Weakened} (Harm)

`, - `

${harmString}

`, - effectCat === RollModSection.roll - ? "

If your injuries apply to the situation at hand, you suffer −1d to your roll.

" - : "

If your injuries apply to the situation at hand, you suffer −1 effect." - ].join("") - }); - } - }); - const { one: harmCondition } = Object.values(this.system.harm) - .find((harmData) => /Need Help/.test(harmData.effect)) ?? {}; - if (harmCondition && harmCondition.trim() !== "") { - rollModsSchemaSet.push({ - key: "Push-negative-roll", - name: "PUSH", - sideString: harmCondition.trim(), - section: RollModSection.roll, - posNeg: "negative", - base_status: RollModStatus.ToggledOn, - modType: RollModType.harm, - value: 0, - effectKeys: ["Cost-Stress2"], - tooltip: [ - "

Broken (Harm)

", - `

${harmCondition.trim()}

`, - "

If your injuries apply to the situation at hand, you must Push to act.

" - ].join("") - }); - } - return rollModsSchemaSet; - } - async applyHarm(num, name) { - if (num === 4) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} Suffers FATAL Harm: ${name}`, - body: `${this.name}, will you continue as a Ghost, or create a new character?`, - type: BladesNoticeType.push, - cssClasses: "harm-alert fatal-harm-alert" - }); - return; - } - // Construct sequence of harm keys to check, starting with given harm level. - const harmSequence = [ - [["lesser", "one"], ["lesser", "two"]], - [["moderate", "one"], ["moderate", "two"]], - [["severe", "one"]] - ].slice(num - 1).flat(1); - while (harmSequence.length) { - const theseHarmKeys = harmSequence.shift(); - if (!theseHarmKeys) { - break; - } - const [thisHarmLevel, thisHarmKey] = theseHarmKeys; - const thisHarmVal = this.system.harm[thisHarmLevel][thisHarmKey]; - if (!thisHarmVal) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} Suffers ${U.tCase(thisHarmLevel)} Harm: ${name}`, - type: BladesNoticeType.push, - cssClasses: "harm-alert" - }); - await this.update({ [`system.harm.${thisHarmLevel}.${thisHarmKey}`]: name }); - return; - } - } - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} Suffers a Catastrophic, Permanent Injury!`, - body: `${this.name}, you're out of the action - either left for dead, or otherwise dropped from the action. You can choose to return at the beginning of the next Phase with a permanent injury, or die.`, - type: BladesNoticeType.push, - cssClasses: "harm-alert fatal-harm-alert" - }); - } - async applyWorsePosition() { - this.setFlag("eunos-blades", "isWorsePosition", true); - } - // #endregion - // #region BladesRoll.ParticipantDoc Implementation - get rollParticipantID() { return this.id; } - get rollParticipantDoc() { return this; } - get rollParticipantIcon() { return this.playbook?.img ?? this.img; } - get rollParticipantName() { return this.name ?? ""; } - get rollParticipantType() { return this.type; } - get rollParticipantModsSchemaSet() { return []; } - // #endregion - async adjustStress(deltaStress) { - const newStress = Math.min(this.stressMax, Math.max(0, this.stress + deltaStress)); - if (newStress === this.stressMax) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} breaks under the stress!`, - body: `${this.name}: Select a Trauma Condition on your sheet. You are taken out of action and will no longer participate in this score. Narrate what happens.`, - type: BladesNoticeType.push, - cssClasses: "stress-alert" - }); - await this.update({ "system.stress.value": 0 }); - return; - } - await this.update({ "system.stress.value": newStress }); - } - async indulgeStress(deltaStress) { - if (deltaStress > this.stress) { - BladesDirector.getInstance().pushNotice_SocketCall("ALL", { - title: `${this.name} Overindulges!`, - body: `${this.name}: Select an option from the list below, and narrate how overindulging your vice led to this result:
  • Attract Trouble: Roll for an Entanglement.
  • Brag About Your Exploits: +2 Heat
  • Go AWOL Vanish for a few weeks. (You will play a different character until the next Downtime Phase, at which point you will return with all Harm healed.)
  • Tapped: Your current Vice Purveyor cuts you off. (Until you find a new source for your vice, you will be unable to Indulge Vice during Downtime.)
`, - type: BladesNoticeType.push, - cssClasses: "stress-alert" - }); - } - await this.update({ "system.stress.value": this.stress - deltaStress }); - } - async spendArmor(amount) { - const updateData = {}; - while (amount > 0) { - if (this.isLightArmorAvailable) { - if (!this.isLightArmorEquipped) { - updateData["system.armor.active.light"] = true; - } - updateData["system.armor.checked.light"] = true; - } - else if (this.isHeavyArmorAvailable) { - if (!this.isHeavyArmorEquipped) { - updateData["system.armor.active.heavy"] = true; - } - updateData["system.armor.checked.heavy"] = true; - } - else { - throw new Error("No armor available to spend"); - } - amount--; - } - this.update(updateData); - } - async spendSpecialArmor() { - if (this.system.armor.active.special && !this.system.armor.checked.special) { - await this.update({ "system.armor.checked.special": true }); - } - } - get rollTraitPCTooltipActions() { - const tooltipStrings = [""]; - const actionRatings = this.actions; - Object.values(AttributeTrait).forEach((attribute) => { - C.Action[attribute].forEach((action) => { - tooltipStrings.push([ - "", - ``, - ``, - ``, - "" - ].join("")); - }); - }); - tooltipStrings.push("
${U.uCase(action)}${"⚪".repeat(actionRatings[action])}(${C.ShortActionTooltips[action]})
"); - return tooltipStrings.join(""); - } - get rollTraitPCTooltipAttributes() { - const tooltipStrings = [""]; - const attributeRatings = this.attributes; - Object.values(AttributeTrait).forEach((attribute) => { - tooltipStrings.push([ - "", - ``, - ``, - ``, - "" - ].join("")); - }); - tooltipStrings.push("
${U.uCase(attribute)}${"⚪".repeat(attributeRatings[attribute])}(${C.ShortAttributeTooltips[attribute]})
"); - return tooltipStrings.join(""); - } - // #endregion - render(force) { - if (!this.isHealingClockReady) { - setTimeout(() => this.render(force), 1000); - return; - } - super.render(force); - } -} -export default BladesPC; diff --git a/module/documents/items/BladesClock copy.js b/module/documents/items/BladesClock copy.js deleted file mode 100644 index f8a72e7f..00000000 --- a/module/documents/items/BladesClock copy.js +++ /dev/null @@ -1,46 +0,0 @@ -import BladesItem from "../../BladesItem.js"; -import { BladesActorType, Factor } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import BladesActor from "../../BladesActor.js"; -class BladesClock extends BladesItem { - get value() { return this.system.value; } - get max() { return this.system.max; } - get color() { return this.system.color; } - get rollFactors() { - const factorData = {}; - [ - Factor.tier, - Factor.quality - ].forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: factor === Factor.tier ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.system.tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - // no default - } - return 0; - } - get rollOppImg() { return ""; } - // #region OVERRIDES: _onUpdate - async _onUpdate(...args) { - await super.callOnUpdate(...args); - BladesActor.GetTypeWithTags(BladesActorType.pc).forEach((actor) => actor.render()); - } -} -export default BladesClock; diff --git a/module/documents/items/BladesClock.js b/module/documents/items/BladesClock.js deleted file mode 100644 index 8307374f..00000000 --- a/module/documents/items/BladesClock.js +++ /dev/null @@ -1,890 +0,0 @@ -import C, { ClockColor, ClockKeyDisplayMode, Factor } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -class BladesTargetLink { - static validateConfig(ref) { - // Check if 'ref' is a simple object literal - if (!U.isSimpleObj(ref)) { - return false; - } - // Confirm a target key or flag key has been provided. - if (!ref.targetKey && !ref.targetFlagKey) { - return false; - } - // Confirm a target has been provided, and that it can be resolved to a Document entity. - if (!ref.target) { - return false; - } - if (U.isDocID(ref.target)) { - // Convert string id of target to target Document - ref.target = game.actors.get(ref.target) ?? game.items.get(ref.target); - } - if (!(ref.target instanceof Actor || ref.target instanceof Item)) { - return false; - } - // Create a random ID if one not provided. - if (!ref.id) { - ref.id = randomID(); - } - return true; - } - _id; - _targetID; - get targetID() { return this._targetID; } - _target; - get target() { return this._target; } - _targetKey = "system"; - get targetKey() { return this._targetKey; } - _targetFlagKey; - get targetFlagKey() { return this._targetFlagKey; } - constructor(config) { - if (!BladesTargetLink.validateConfig(config)) { - eLog.error("[new BladesTargetLink] Bad Config File.", config); - throw new Error("See log."); - } - const { id, target, targetKey, targetFlagKey } = config; - this._id = id; - this._target = target; - this._targetID = this.target.id; - this._targetKey = targetKey ?? "system"; - this._targetFlagKey = targetFlagKey; - } - getSystemData() { - if (this.targetFlagKey) { - return this.target.getFlag("eunos-blades", `${this.targetFlagKey}.${this._id}`); - } - return getProperty(this.target, `${this.targetKey}.${this._id}`) ?? {}; - } - get id() { return this._id; } - get name() { return this.getSystemData().name; } - getTargetProp(prop) { - return this.getSystemData()[prop]; - } - async updateTarget(prop, val) { - if (this.targetFlagKey) { - this.target.setFlag("eunos-blades", `${this.targetFlagKey}.${this._id}.${prop}`, val); - } - else { - this.target.update({ [`${this.targetKey}.${this._id}.${prop}`]: val }); - } - } - async updateTargetData(val) { - if (this.targetFlagKey) { - if (val === null) { - return this.target.unsetFlag("eunos-blades", `${this.targetFlagKey}.${this._id}`); - } - else { - return this.target.setFlag("eunos-blades", `${this.targetFlagKey}.${this._id}`, val); - } - } - else if (val === null) { - return this.target.update({ [`${this.targetKey}.-=${this._id}`]: null }); - } - else { - return this.target.update({ [`${this.targetKey}.${this._id}`]: val }); - } - } - async delete() { - return this.updateTargetData(null); - } -} -class BladesClockKey extends BladesTargetLink { - // #region STATIC METHODS ~ - static get DefaultSchema() { - return { - name: "", - isVisible: true, - isActive: false, - isNameVisible: false, - isShowingControls: game.user.isGM, - clocksData: {}, - oneKeyIndex: U.gsap.utils.random(1, 5, 1) - }; - } - static applyConfigDefaults(clockKeyConfig) { - const keyData = { - ...this.DefaultSchema, - ...clockKeyConfig - }; - if (keyData.target instanceof Actor || keyData.target instanceof Item) { - keyData.target = keyData.target.id; - } - return keyData; - } - static async Create(clockKeyConfig, clockConfig = {}) { - if (!this.validateConfig(clockKeyConfig)) { - eLog.error("[BladesClockKey.Create()] Invalid Config", clockKeyConfig); - throw new Error("See log."); - } - eLog.checkLog3("[BladesClockKey.Create()] Config", clockKeyConfig); - // Create the clock key instance, supplying the config. - // BladesClockKey constructor will apply defaults for missing values. - const clockKey = new BladesClockKey(clockKeyConfig); - // Wait for clockKey data to be written to target - await clockKey.initialize(); - // If key created without clock data, initialize with a single clock - if (clockKey.size === 0) { - await clockKey.addClock(clockConfig); - } - return clockKey; - } - // #endregion - // tl.revert(); tl.kill(); - // var key = Array.from(game.eunoblades.ClockKeeper.keys)[0]; - // var keyElem = $(key.elem).find(".key-image-container.one-key-image-container")[0]; - // var tl = U.gsap.timeline({paused: true}); - // tl.fromTo(keyElem, {rotateZ: -0.5, transformOrigin: "50% 0px"}, {rotateZ: 0.5, duration: 3, ease: "sine.inOut", repeat: -1, yoyo: true}, 0); - // tl.to(keyElem, {y: 15, duration: 6, ease: "sine.inOut", repeat: -1, yoyo: true}, 0); - // tl.fromTo(keyElem, {scale: 0.9, filter: "blur(3px) brightness(0.8)"}, {scale: 1.1, filter: "blur(0px) brightness(1.2)", duration: 12, ease: "sine.inOut", repeat: -1, yoyo: true}, 0); - // tl.play(); - // #region GETTERS & SETTERS ~ - get clocksData() { return this.getSystemData().clocksData ?? {}; } - get clocks() { - return new Collection(Object.entries(this.clocksData ?? {}) - .sort((a, b) => a[1].index - b[1].index) - .map(([id, data]) => [ - id, - game.eunoblades.Clocks.get(id) ?? new BladesClock(data) - ])); - } - get isGM() { return game.user.isGM; } - get isVisible() { return U.pBool(this.getSystemData().isVisible); } - get oneKeyIndex() { return U.pInt(this.getSystemData().oneKeyIndex); } - get displayMode() { - if (this.isGM && this.isShowingControls) { - return ClockKeyDisplayMode.full; - } - return this.getSystemData().displayMode ?? ClockKeyDisplayMode.full; - } - get setDisplayMode() { - return this.getSystemData().displayMode ?? ClockKeyDisplayMode.full; - } - get sceneID() { return this.getSystemData().sceneID; } - get isActive() { return U.pBool(this.getSystemData().isActive); } - get isNameVisible() { return U.pBool(this.getSystemData().isNameVisible); } - get size() { return Object.keys(this.clocksData).length; } - get rollOppName() { return this.name; } - get rollOppType() { return "clock_key"; } - get rollFactors() { - const factorData = {}; - [ - Factor.tier, - Factor.quality - ].forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: factor === Factor.tier ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.getSystemData().tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - // no default - } - return 0; - } - get rollOppImg() { return ""; } - get isComplete() { - return Array.from(this.clocks).every((clock) => clock.isComplete); - } - get currentClockIndex() { - return U.pInt(this.currentClock?.index); - } - get currentClock() { - return this.clocks.find((clock) => !clock.isComplete); - } - get displaySelectOptions() { - const options = [ - { value: ClockKeyDisplayMode.full, display: "Full Key" }, - { value: ClockKeyDisplayMode.clocks, display: "Clocks" }, - { value: ClockKeyDisplayMode.currentClock, display: "Current Clock" }, - { value: ClockKeyDisplayMode.presentCurrentClock, display: "Present Current Clock" } - ]; - for (let i = 0; i < this.size; i++) { - options.push(...[ - { value: i, display: `Clock #${i}` }, - { value: `present${i}`, display: `Present Clock #${i}` } - ]); - } - return options; - } - // #endregion - // #region ~~~ CONSTRUCTOR & INITIALIZATION ~~~ - _initData; - constructor(data) { - if (!BladesClockKey.validateConfig(data)) { - eLog.error("[BladesClockKey Constructor] Invalid Config", data); - throw new Error("See log."); - } - eLog.checkLog3("[BladesClockKey Constructor] Valid Config", data); - super(data); - data.id = this.id; - this._initData = BladesClockKey.applyConfigDefaults(data); - game.eunoblades.ClockKeys.set(this.id, this); - } - async initialize() { - await this.updateTargetData(this._initData); - } - // #endregion - // #region HTML INTERACTION ~ - async getHTML() { - return await renderTemplate("systems/eunos-blades/templates/overlays/clock-key.hbs", this); - } - get elem() { - return $(`#${this.id}`)[0]; - } - get isShowingControls() { - return U.pBool(this.getSystemData().isShowingControls); - } - set isShowingControls(val) { - this.updateTarget("isShowingControls", U.pBool(val)); - } - async toggleActive() { - return await this.updateTarget("isActive", !this.isActive); - } - get elements() { - const elemData = {}; - if (!this.elem) { - return elemData; - } - elemData.key = this.elem; - elemData.keyContainer = $(this.elem).closest(".clock-key-container")[0]; - for (const clock of Array.from(this.clocks)) { - if (!clock.elem) { - return elemData; - } - const { index, elem } = clock; - elemData[`clock ${index}`] = elem; - elemData[`clock ${index} Container`] = $(elem).closest(".clock-container")[0]; - } - return elemData; - } - // Initializes clock key with proper position and scale before displaying via autoAlpha - async initClockKeyElem(displayMode) { - displayMode = this.displayMode; - if (!this.elem) { - return new Promise((resolve) => { - setTimeout(async () => resolve(await this.initClockKeyElem(displayMode)), 1000); - }); - } - const { elem } = this; - const { keyTweenVars, keyContTweenVars } = this.getDisplayMode(displayMode); - const keyImgContainer = $(this.elem).find(".key-image-container")[0]; - return new Promise((resolve) => { - U.gsap.timeline() - .set(keyImgContainer, keyContTweenVars) - .set(elem, keyTweenVars) - .to(elem, { - autoAlpha: 1, - duration: 0.5 - }).then(() => { resolve(); }); - }); - } - // Given a display mode ("full", "clocks", or a clock index number), will return a GSAP effects - // config object to be plugged into any of the 'clockKey' effects. - // Can optionally provide config values to be included in a second parameter. - getDisplayMode(displayMode, configOptions = {}) { - if (!this.elem) { - return configOptions; - } - if (!this.isActive) { - displayMode = ClockKeyDisplayMode.full; - } - configOptions.duration ??= 1; - configOptions.ease ??= "power2"; - configOptions.autoAlpha ??= 1; - const keyTweenVars = { ...configOptions }; - const keyContTweenVars = { ...configOptions }; - // Get key data - const keyPosData = U.objClone(C.ClockKeyPositions[this.size]); - // Are we presenting? If so, flag it true and parse displayMode to standard clock reference - let isPresenting = false; - if (/^present/.exec(`${displayMode}`)) { - isPresenting = true; - const suffix = `${displayMode}`.substring(7); - if (!isNaN(Number(suffix))) { - displayMode = U.pInt(suffix); - } - else { - displayMode = ClockKeyDisplayMode.currentClock; - } - } - if (!isNaN(Number(displayMode))) { - displayMode = U.pInt(displayMode); - } - // Get position and area dimensions of clock key area focused on by displayMode - let focusArea; - let focusPos; - const activeClockSide = this.currentClock?.getActiveSide(0); - switch (displayMode) { - case ClockKeyDisplayMode.full: { - focusPos = keyPosData.keyCenter; - focusArea = keyPosData.keyDimensions; - break; - } - case ClockKeyDisplayMode.clocks: { - focusPos = keyPosData.clocksCenter; - focusArea = keyPosData.clocksCenterDimensions; - break; - } - case ClockKeyDisplayMode.currentClock: { - displayMode = this.currentClockIndex; - } - // falls through - default: { - if (typeof displayMode === "number") { - if (displayMode in keyPosData.clocks) { - focusPos = keyPosData.clocks[displayMode]; - focusArea = { width: 110, height: 110 }; - if (isPresenting) { - focusArea = { width: 55, height: 110 }; - if (activeClockSide === "left") { - focusPos.x -= 30; - focusPos.z = -50; - } - else if (activeClockSide === "right") { - focusPos.x += 35; - // focusPos.z = 1350; - } - } - break; - } - } - throw new Error(`[BladesClockKey.getDisplayMode] Error display key '${this.id}' in mode '${displayMode}'.`); - } - } - // Get height and width of clock key container - const keyContainer = $(this.elem).closest(".clock-key-container")[0]; - const keyContainerDimensions = { - width: U.gsap.getProperty(keyContainer, "width"), - height: U.gsap.getProperty(keyContainer, "height") - }; - // If not isActive, adjust 'width' to account for CSS styles - if (!this.isActive) { - keyContainerDimensions.width *= 2; - } - // Determine scale factor necessary to fit focusArea inside keyContainer - keyTweenVars.scale = Math.min(keyContainerDimensions.height / focusArea.height, keyContainerDimensions.width / focusArea.width); - // If not isActive, adjust 'scale' to account for CSS styles - if (!this.isActive) { - // keyTweenVars.scale *= 2; - } - // Determine top and left values for key-image-container, accounting for x/yPercent -50 - keyContTweenVars.top = (0.5 * 100) - focusPos.y; - keyContTweenVars.left = (0.5 * 100) - focusPos.x; - // Set transfer origin of key-image-container to same position, for further animation - keyContTweenVars.transformOrigin = `${focusPos.x}px ${focusPos.y}px`; - // Set initial y-rotation to turn clock half towards camera if 'isPresenting' - if (isPresenting) { - if (activeClockSide === "left") { - keyContTweenVars.rotateY = 30; - } - else if (activeClockSide === "right") { - keyContTweenVars.rotateY = -30; - } - } - // If not isActive, adjust 'width' and 'scale' to account for CSS styles - return { keyTweenVars, keyContTweenVars }; - } - async switchToMode(displayMode, configOptions = {}, isLocalOnly = false) { - const self = this; - const { elem } = self; - if (!elem) { - return new Promise((resolve) => { - setTimeout(async () => resolve(await this.switchToMode(displayMode, configOptions, isLocalOnly)), 1000); - }); - } - const { keyTweenVars, keyContTweenVars } = self.getDisplayMode(displayMode, configOptions); - const keyImgContainer = $(elem).find(".key-image-container")[0]; - return new Promise((resolve) => { - U.gsap.timeline({ - onComplete() { - if (!isLocalOnly) { - self.updateTarget("displayMode", displayMode) - .then(() => resolve()); - } - } - }) - .to(elem, keyTweenVars, 0) - .to(keyImgContainer, keyContTweenVars, 0); - }); - } - // #endregion - // #region Adding & Removing Clocks ~ - async updateClockIndices() { - await this.updateTarget("clocksData", Object.fromEntries(Object.entries(this.clocksData) - .map(([id, data], index) => [id, { ...data, index }]))); - return this.clocks; - } - async addClock(clockData = {}) { - await this.updateClockIndices(); - eLog.checkLog3("bladesClock", "[BladesClockKey.addClock]", { - passedData: clockData, - derivedData: { - target: this.target, - targetKey: this.targetKey ? `${this.targetKey}.${this.id}.clocksData` : undefined, - targetFlagKey: this._targetFlagKey ? `${this.targetFlagKey}.${this.id}.clocksData` : undefined, - index: this.clocks.size - }, - createData: { - target: this.target, - targetKey: this.targetKey ? `${this.targetKey}.${this.id}.clocksData` : undefined, - targetFlagKey: this._targetFlagKey ? `${this.targetFlagKey}.${this.id}.clocksData` : undefined, - index: this.clocks.size, - ...clockData - } - }); - return await BladesClock.Create({ - target: this.target, - targetKey: this.targetKey ? `${this.targetKey}.${this.id}.clocksData` : undefined, - targetFlagKey: this._targetFlagKey ? `${this.targetFlagKey}.${this.id}.clocksData` : undefined, - index: this.clocks.size, - ...clockData - }); - } - async deleteClock(clockID) { - if (this.size <= 1) { - throw new Error("[BladesClockKey.deleteClock()] Cannot reduce number of clocks below 1!"); - } - clockID ??= Array.from(this.clocks).pop()?.id; - await game.eunoblades.Clocks.get(clockID ?? "")?.delete(); - await this.updateClockIndices(); - } -} -class BladesClock extends BladesTargetLink { - // #region STATIC METHODS ~ - static get DefaultSchema() { - return { - name: "", - index: 0, - value: 0, - max: 8, - color: ClockColor.white, - isVisible: true, - isNameVisible: true, - isHighlighted: false, - isActive: true, - isShowingControls: game.user.isGM - }; - } - static applyConfigDefaults(clockConfig) { - if (clockConfig.target instanceof Actor || clockConfig.target instanceof Item) { - clockConfig.target = clockConfig.target.id; - } - const clockData = { - ...this.DefaultSchema, - ...clockConfig - }; - return clockData; - } - static async Create(clockConfig) { - if (!this.validateConfig(clockConfig)) { - eLog.error("[BladesClock.Create()] Invalid Config", clockConfig); - throw new Error("See log."); - } - eLog.checkLog3("[BladesClock.Create()] Config", clockConfig); - // Create the clock instance, supplying the config. - // BladesClock constructor will apply defaults for missing values. - const clock = new BladesClock(clockConfig); - // Wait for clock data to be written to target - await clock.initialize(); - return clock; - } - // #endregion - // #region GETTERS & SETTERS ~ - get canEdit() { - // return true if user has edit permissions on parent document, and clock is - // visible and active. - console.log("NOTE: All Clocks currently Editable; see line 71 of BladesClock.ts"); - return this.isVisible && this.isActive; - } - get isGM() { return game.user.isGM; } - get value() { return U.pInt(this.getSystemData().value); } - set value(val) { this.updateTarget("value", U.pInt(val)); } - get max() { return U.pInt(this.getSystemData().max); } - set max(val) { this.updateTarget("max", U.pInt(val)); } - get color() { return this.getSystemData().color ?? ClockColor.white; } - set color(val) { this.updateTarget("color", val); } - get isActive() { return U.pBool(this.getSystemData().isActive); } - set isActive(val) { this.updateTarget("isActive", U.pBool(val)); } - get parentKey() { - const keyID = this.targetKey.match(/\.keys\.([^.]+)/)?.[1]; - if (!keyID) { - return undefined; - } - return game.eunoblades.ClockKeys.get(keyID); - } - get isShowingControls() { - if (this.parentKey && !this.parentKey.isShowingControls) { - return false; - } - return U.pBool(this.getSystemData().isShowingControls); - } - set isShowingControls(val) { this.updateTarget("isShowingControls", U.pBool(val)); } - get isNameVisible() { return U.pBool(this.getSystemData().isNameVisible); } - set isNameVisible(val) { this.updateTarget("isNameVisible", U.pBool(val)); } - get isVisible() { return U.pBool(this.getSystemData().isVisible); } - set isVisible(val) { this.updateTarget("isVisible", U.pBool(val)); } - get isHighlighted() { return U.pBool(this.getSystemData().isHighlighted); } - set isHighlighted(val) { this.updateTarget("isHighlighted", U.pBool(val)); } - get index() { return U.pInt(this.getSystemData().index); } - set index(val) { this.updateTarget("index", U.pInt(val)); } - get display() { return this.getSystemData().display ?? {}; } - set display(val) { this.updateTarget("display", val); } - get tooltip() { return this.getSystemData().tooltip; } - set tooltip(val) { this.updateTarget("tooltip", val); } - get sceneID() { return this.getSystemData().sceneID; } - set sceneID(val) { this.updateTarget("sceneID", val); } - get isEmpty() { return this.value === 0; } - get isComplete() { return this.value >= this.max; } - get rollOppClock() { return this; } - get rollOppName() { return this.name; } - get rollOppType() { return "clock"; } - get colorSelectOptions() { - return [ - { value: ClockColor.white, display: "🔘" }, - { value: ClockColor.yellow, display: "📀" }, - { value: ClockColor.cyan, display: "🔵" }, - { value: ClockColor.red, display: "🔴" } - ]; - } - get maxSelectOptions() { - return [ - { value: 2, display: 2 }, - { value: 3, display: 3 }, - { value: 4, display: 4 }, - { value: 5, display: 5 }, - { value: 6, display: 6 }, - { value: 8, display: 8 }, - { value: 10, display: 10 }, - { value: 12, display: 12 } - ]; - } - get valueSelectOptions() { - const returnVals = []; - for (let i = 0; i <= this.max; i++) { - returnVals.push({ value: i, display: i }); - } - return returnVals; - } - get rollFactors() { - const factorData = {}; - [ - Factor.tier, - Factor.quality - ].forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: factor === Factor.tier ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.getSystemData().tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - // no default - } - return 0; - } - get rollOppImg() { return ""; } - // #endregion - // #region ~~ CONSTRUCTOR ~~ - _initData; - constructor(data) { - function isHTML(testData) { - return testData instanceof HTMLElement || testData instanceof jQuery; - } - let configData; - let targetLinkData; - if (isHTML(data)) { - data = $(data); - targetLinkData = { - id: data.data("id"), - target: data.data("targetId"), - targetFlagKey: data.data("targetFlagKey") || undefined, - targetKey: data.data("targetKey") - }; - configData = targetLinkData; - } - else { - const dataAsConfig = data; - targetLinkData = { - id: data.id, - target: typeof dataAsConfig.target === "string" ? dataAsConfig.target : dataAsConfig.target.id, - targetFlagKey: dataAsConfig.targetFlagKey || undefined, - targetKey: dataAsConfig.targetKey || undefined - }; - configData = { - ...data, - ...targetLinkData - }; - } - super(targetLinkData); - configData.id = this.id; - this._initData = BladesClock.applyConfigDefaults(configData); - game.eunoblades.Clocks.set(this.id, this); - } - async initialize() { - return this.updateTargetData(this._initData); - } - // #endregion - // #region HTML INTERACTION ~ - get elem() { - return $(`[data-id="${this.id}"`)[0]; - } - async getHTML() { - return await renderTemplate("systems/eunos-blades/templates/components/clock.hbs", this); - } - // Returns which hemisphere of the clock will show the final change if segmentDelta segments are added/removed. - getActiveSide(segmentDelta) { - const finalClockValue = Math.min(this.max, Math.max(0, this.value + segmentDelta)); - const halfClockValue = this.max / 2; - if (finalClockValue > halfClockValue) { - return "left"; - } - return "right"; - } - // #endregion - // #region Adding/Removing Clock Segments - // Returns number of segments beyond max (or 0, if max not met) - async fillSegments(count) { - // Amount added beyond max: - const clockOverflow = Math.max(0, this.value + count - this.max); - // Clamp count to max: - count = Math.min(this.value + count, this.max) - this.value; - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value + count); - return clockOverflow; - } - // Returns (positive) number of segments removed - // in excess of the number of segments in the clock - async clearSegments(count) { - // Amount removed beyond 0: - const clockOverflow = Math.max(0, count - this.value); - // Clamp count to min: - count = Math.min(this.value, count); - if (count === 0) { - return clockOverflow; - } - await this.updateTarget("value", this.value - count); - return clockOverflow; - } - async delete() { - await super.delete(); - return this.parentKey?.updateClockIndices(); - } -} -export const ApplyClockListeners = async (html, namespace) => { - eLog.checkLog3("ApplyListeners", "ApplyClockListeners", { html, find: html.find(".clock") }); - // Step One: Find any clock keys and initialize them - await Promise.all(Array.from(html.find(".clock-key")) - .map(async (keyElem) => { - const key = game.eunoblades.ClockKeys.get(keyElem.id); - if (key) { - return await key.initClockKeyElem(); - } - return undefined; - })); - // Utility functions - async function toggleTarget(el, source) { - if (!source) { - return; - } - const prop = $(el).data("prop"); - eLog.checkLog3("clockControls", "Toggle Event", { source, el, prop, curVal: source.getTargetProp(prop) }); - await source.updateTarget(prop, !source.getTargetProp(prop)); - if (prop === "isShowingControls") { - if (source instanceof BladesClockKey) { - const key = source; - const { isShowingControls } = key; - if (isShowingControls) { - // If controls have been enabled, switch display mode of key to full for user (GM) only. - key.switchToMode(ClockKeyDisplayMode.full, undefined, true); - } - else { - // Otherwise, re-initialize key for GM. - key.initClockKeyElem(); - } - } - } - } - async function setTarget(val, el, source) { - if (!source) { - return; - } - const prop = $(el).data("prop"); - eLog.checkLog3("clockControls", "Set Event", { val, source, prop, curVal: source.getTargetProp(prop) }); - source.updateTarget(prop, val); - } - // Add listeners and animation timelines to clock keys - U.toArray(html.find(".clock-key-container")).forEach((keyContainerElem) => { - const keyID = $(keyContainerElem).find(".clock-key")[0].id; - const key = game.eunoblades.ClockKeys.get(keyID); - if (!key) { - throw new Error("Too early for key: no KEY!"); - } - const { elem } = key ?? {}; - if (!elem) { - throw new Error("Too early for key: no ELEMENT!"); - } - // Apply listeners to GM control elements - if (game.user.isGM) { - $(keyContainerElem).find("[data-action='key-toggle']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .off(`.${namespace}`) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, key); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(keyContainerElem).find("input.clock-key-controls-name") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, key); - } - }); - $(keyContainerElem).find("select.key-select") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, key); - } - }); - $(keyContainerElem).find("[data-action='add-clock']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - key.addClock(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(keyContainerElem).find("[data-action='delete-key']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el, { color: "#FF0000" })); }) - .on({ - [`contextmenu.${namespace}`]: (event) => { - event.preventDefault(); - key.delete(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - } - }); - // Add listeners to clocks - html.find(".clock-container").each((_, clockContainerElem) => { - const clockID = $(clockContainerElem).find(".clock")[0].id; - const clock = game.eunoblades.Clocks.get(clockID); - if (!clock) { - throw new Error("Too early for clock: no CLOCK!"); - } - const { elem } = clock ?? {}; - if (!elem) { - throw new Error("Too early for clock: no ELEMENT!"); - } - // Apply listeners to GM control elements - if (game.user.isGM) { - if (clock.isShowingControls) { - $(clockContainerElem).find("[data-action='clock-toggle']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el)); }) - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, clock); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - $(clockContainerElem).find("input.clock-controls-name") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, clock); - } - }); - $(clockContainerElem).find("select.clock-select") - .on({ - [`change.${namespace}`]: (event) => { - event.preventDefault(); - setTarget($(event.target).val(), event.target, clock); - } - }); - $(clockContainerElem).find("[data-action='delete-clock']") - .each((_, el) => { $(el).data("hoverTimeline", U.gsap.effects.hoverButton(el, { color: "#FF0000" })); }) - .on({ - [`contextmenu.${namespace}`]: (event) => { - event.preventDefault(); - clock.delete(); - }, - [`mouseenter.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").play(), - [`mouseleave.${namespace}`]: (event) => $(event.currentTarget).data("hoverTimeline").reverse() - }); - } - else { - $(clockContainerElem).find("[data-action='clock-toggle'][data-prop='isShowingControls']") - .on({ - [`click.${namespace}`]: (event) => { - event.preventDefault(); - toggleTarget(event.currentTarget, clock); - } - }); - $(clockContainerElem).find(".clock") - .on({ - [`click.${namespace}`]: () => { clock.updateTarget("isShowingControls", true); }, - [`contextmenu.${namespace}`]: () => { clock.isVisible = !clock.isVisible; }, - [`wheel.${namespace}`]: (event) => { - if (!(event.originalEvent instanceof WheelEvent)) { - return; - } - event.preventDefault(); - if (event.originalEvent.deltaY < 0) { - clock.fillSegments(1); - } - else { - clock.clearSegments(1); - } - } - }); - } - } - else if (clock.canEdit && !clock.isShowingControls) { - // Apply listeners for non-GM users - $(clockContainerElem).find(".clock") - .on({ - [`click.${namespace}`]: () => clock.fillSegments(1), - [`contextmenu.${namespace}`]: () => clock.clearSegments(1) - }); - } - }); -}; -export default BladesClock; -export { BladesClockKey }; diff --git a/module/documents/items/BladesClockKeeper.js b/module/documents/items/BladesClockKeeper.js deleted file mode 100644 index 08dbc232..00000000 --- a/module/documents/items/BladesClockKeeper.js +++ /dev/null @@ -1,90 +0,0 @@ -import { BladesItem } from "../BladesItemProxy.js"; -import BladesClockKey from "../../classes/BladesClockKey.js"; -class BladesClockKeeper extends BladesItem { - static async Initialize() { - const clockKeeper = game.items.find((item) => item.type === "clock_keeper"); - if (!clockKeeper) { - game.eunoblades.ClockKeeper = (await BladesClockKeeper.create({ - name: "Clock Keeper", - type: "clock_keeper", - img: "systems/eunos-blades/assets/icons/misc-icons/clock-keeper.svg" - })); - } - else { - game.eunoblades.ClockKeeper = clockKeeper; - } - return loadTemplates([ - "systems/eunos-blades/templates/parts/clock-sheet-key-controls.hbs", - "systems/eunos-blades/templates/parts/clock-sheet-clock-controls.hbs" - ]); - } - showClockKeyControls(keyID) { - if (this.sheet?.element) { - // Find the key controls row, flip it over to controls row. - } - } - hideClockKeyControls(keyID) { - if (this.sheet?.element) { - // Find the key controls row, flip it back to minimal summary - } - } - // #region CLOCKS OVERLAY - get clockKeys() { return this.getSceneKeys(); } - get currentScene() { return game.scenes?.current?.id; } - get currentSceneID() { - if (!game.scenes?.current) { - throw new Error("[BladesClockKeeper.currentScene] Error retrieving 'game.scenes.current'."); - } - return game.scenes.current.id; - } - get targetSceneID() { return this.system.targetScene ?? this.currentSceneID; } - get keys() { - return new Collection(Object.entries(this.system.clocksData ?? {}) - .map(([id, data]) => [ - id, - game.eunoblades.ClockKeys.get(id) ?? new BladesClockKey(data) - ])); - } - getSceneKeys(sceneID) { - sceneID ??= this.targetSceneID; - return new Collection(Array.from(game.eunoblades.ClockKeys) - .filter((clockKey) => clockKey.sceneIDs.includes(sceneID)) - .map((clockKey) => [clockKey.id, clockKey])); - } - async addClockKey(clockKeyConfig = {}) { - if (!clockKeyConfig.sceneIDs?.length) { - clockKeyConfig.sceneIDs = [this.targetSceneID]; - } - const key = await BladesClockKey.Create({ - target: this, - targetKey: "system.clocksData", - ...clockKeyConfig - }); - // super.update({}); - return key; - } - async deleteClockKey(keyID) { - await game.eunoblades.ClockKeys.get(keyID)?.delete(game.eunoblades.ClockKeys); - } - async addClockToKey(keyID, clockData) { - const key = await game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - await key.addClock(clockData); - } - async deleteClockFromKey(keyID, clockID) { - const key = await game.eunoblades.ClockKeys.get(keyID); - if (!key) { - return; - } - await key.deleteClock(clockID); - } - // #endregion - // #region OVERRIDES: prepareDerivedData, _onUpdate - prepareDerivedData() { - super.prepareDerivedData(); - this.system.targetScene ??= game.scenes.current?.id || null; - } -} -export default BladesClockKeeper; diff --git a/module/documents/items/BladesGMTracker.js b/module/documents/items/BladesGMTracker.js deleted file mode 100644 index 32cef57e..00000000 --- a/module/documents/items/BladesGMTracker.js +++ /dev/null @@ -1,32 +0,0 @@ -import BladesItem from "../../BladesItem.js"; -import { BladesActorType, BladesItemType, BladesPhase } from "../../core/constants.js"; -import BladesActor from "../../BladesActor.js"; -class BladesGMTracker extends BladesItem { - static async Initialize() { - const tracker = game.items - .find((item) => BladesItem.IsType(item, BladesItemType.gm_tracker)); - if (tracker) { - game.eunoblades.Tracker = tracker; - } - else { - game.eunoblades.Tracker = (await BladesGMTracker.create({ - name: "GM Tracker", - type: "gm_tracker", - img: "systems/eunos-blades/assets/icons/misc-icons/gm-tracker.svg" - })); - } - } - get phase() { return this.system.phase ?? BladesPhase.Freeplay; } - set phase(phase) { - this.update({ "system.phase": phase }); - } - prepareDerivedData() { - this.system.phases = Object.values(BladesPhase); - } - // #region OVERRIDES: prepareDerivedData, _onUpdate - async _onUpdate(...args) { - await super.callOnUpdate(...args); - BladesActor.GetTypeWithTags(BladesActorType.pc).forEach((actor) => actor.render()); - } -} -export default BladesGMTracker; diff --git a/module/documents/items/BladesLocation.js b/module/documents/items/BladesLocation.js deleted file mode 100644 index 0c350121..00000000 --- a/module/documents/items/BladesLocation.js +++ /dev/null @@ -1,40 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import BladesItem from "../../BladesItem.js"; -import { Factor } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -class BladesLocation extends BladesItem { - get rollFactors() { - const factorData = {}; - [ - Factor.tier, - Factor.quality, - Factor.scale - ].forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: factor === Factor.tier ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.system.tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - case Factor.scale: return this.system.scale; - // no default - } - return 0; - } - get rollOppImg() { return this.img ?? ""; } -} -export default BladesLocation; diff --git a/module/documents/items/BladesProject.js b/module/documents/items/BladesProject.js deleted file mode 100644 index 74e633e5..00000000 --- a/module/documents/items/BladesProject.js +++ /dev/null @@ -1,142 +0,0 @@ -import { BladesItemType, Factor, ClockColor, ClockKeyDisplayMode } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import { BladesItem } from "../BladesItemProxy.js"; -import BladesProjectSheet from "../../sheets/item/BladesProjectSheet.js"; -import BladesClockKey from "../../classes/BladesClockKey.js"; -class BladesProject extends BladesItem { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesProject, BladesProjectSheet }); - Items.registerSheet("blades", BladesProjectSheet, { types: ["project"], makeDefault: true }); - return loadTemplates(["systems/eunos-blades/templates/items/project-sheet.hbs"]); - } - // #endregion - static IsType(doc) { - return super.IsType(doc, BladesItemType.project); - } - static async create(data, options = {}) { - const project = (await super.create(data, { ...options, renderSheet: false })); - if (!project._clockKey) { - project._clockKey = await BladesClockKey.Create({ - name: project.name, - target: project, - targetKey: "system.clocksData", - isNameVisible: false, - isSpotlit: false, - isVisible: true, - displayMode: ClockKeyDisplayMode.clocks - // oneKeyIndex: U.gsap.utils.random(0, 4, 1) as OneKeyImgIndex - }, undefined, [{ - name: "", - index: 0, - color: ClockColor.yellow, - value: 0, - max: 8, - isVisible: true, - isActive: true, - isNameVisible: false, - isHighlighted: false - }]); - } - return project; - } - _clockKey; - get clockKey() { - if (this._clockKey) { - return this._clockKey; - } - const keysData = Object.values(this.system.clocksData); - if (keysData.length === 0) { - throw new Error(`ClockKey not initialized for Project ${this.name}`); - } - let keyID; - if (keysData.length === 1) { - keyID = keysData[0].id; - } - else if (this.isEmbedded) { - // Find the key data with a targetID that includes the parent document's id - keyID = keysData.find((keyData) => keyData.targetID.includes(this.parent?.id))?.id; - if (!keyID) { - throw new Error(`ClockKey not initialized for Project ${this.name} embedded in document '${this.parent?.name}'.`); - } - } - else { - // Find the key of form 'Item.' in the ClockKeys collection - keyID = keysData.find((keyData) => /^Item\.[^.]{16}$/.exec(keyData.targetID))?.id; - if (!keyID) { - throw new Error(`ClockKey not initialized for Project ${this.name}.`); - } - } - this._clockKey = game.eunoblades.ClockKeys.get(keyID) ?? new BladesClockKey(this.system.clocksData[keyID]); - if (!this._clockKey) { - throw new Error(`ClockKey not initialized for Project ${this.name}`); - } - return this._clockKey; - } - get ownerName() { - if (this.parent) { - return this.parent.name; - } - return undefined; - } - get currentClock() { - return this.clockKey.currentClock; - } - get isComplete() { - return this.clockKey.isComplete; - } - get rollOppClock() { return this.currentClock?.data; } - async advanceClock(segments = 1) { - if (!this.currentClock) { - return undefined; - } - return this.currentClock.fillSegments(segments); - } - get rollFactors() { - const factorData = {}; - [ - Factor.tier, - Factor.quality - ].forEach((factor, i) => { - const factorTotal = this.getFactorTotal(factor); - factorData[factor] = { - name: factor, - value: factorTotal, - max: factorTotal, - baseVal: factorTotal, - display: factor === Factor.tier ? U.romanizeNum(factorTotal) : `${factorTotal}`, - isActive: i === 0, - isPrimary: i === 0, - isDominant: false, - highFavorsPC: true, - cssClasses: `factor-gold${i === 0 ? " factor-main" : ""}` - }; - }); - return factorData; - } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.system.tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - // no default - } - return 0; - } - get rollOppImg() { return ""; } - get keyElem() { - if (!this.clockKey) { - return undefined; - } - return $(`#${this.clockKey.id}`)[0]; - } - get currentClockElem() { - if (!this.keyElem) { - return undefined; - } - if (!this.currentClock) { - return undefined; - } - return $(this.keyElem).find(`.clock[data-id="${this.currentClock.id}"]`)[0]; - } -} -export default BladesProject; diff --git a/module/documents/items/BladesScore.js b/module/documents/items/BladesScore.js deleted file mode 100644 index 7dfde970..00000000 --- a/module/documents/items/BladesScore.js +++ /dev/null @@ -1,61 +0,0 @@ -import BladesItem from "../../BladesItem.js"; -import { BladesActorType, BladesItemType, Factor } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import BladesActor from "../../BladesActor.js"; -import BladesScoreSheet from "../../sheets/item/BladesScoreSheet.js"; -class BladesScore extends BladesItem { - // #region INITIALIZATION ~ - static async Initialize() { - Object.assign(globalThis, { BladesScore, BladesScoreSheet }); - Items.registerSheet("blades", BladesScoreSheet, { types: ["score"], makeDefault: true }); - return loadTemplates(["systems/eunos-blades/templates/items/score-sheet.hbs"]); - } - // #endregion - static get Active() { - return BladesItem.GetTypeWithTags(BladesItemType.score).find((score) => score.system.isActive); - } - static set Active(val) { - BladesItem.GetTypeWithTags(BladesItemType.score) - .find((score) => score.system.isActive)?.update({ "system.isActive": false }) - .then(() => { - if (val) { - val.update({ "system.isActive": true }); - } - }); - } - // #region BladesRoll.OppositionData Implementation - get rollFactors() { - const tierTotal = this.getFactorTotal(Factor.tier); - return { - [Factor.tier]: { - name: "Tier", - value: tierTotal, - max: tierTotal, - baseVal: tierTotal, - display: U.romanizeNum(tierTotal), - isActive: true, - isPrimary: true, - isDominant: false, - highFavorsPC: true, - cssClasses: "factor-gold factor-main" - } - }; - } - get rollOppImg() { return this.img ?? ""; } - getFactorTotal(factor) { - switch (factor) { - case Factor.tier: return this.system.tier.value; - case Factor.quality: return this.getFactorTotal(Factor.tier); - case Factor.scale: return 0; - case Factor.magnitude: return 0; - default: return 0; - } - } - // #endregion - // #region OVERRIDES: _onUpdate - async _onUpdate(changed, options, userId) { - super._onUpdate(changed, options, userId); - BladesActor.GetTypeWithTags(BladesActorType.pc).forEach((actor) => actor.render()); - } -} -export default BladesScore; diff --git a/module/sheets/actor/BladesActorSheet.js b/module/sheets/actor/BladesActorSheet.js deleted file mode 100644 index 981300a4..00000000 --- a/module/sheets/actor/BladesActorSheet.js +++ /dev/null @@ -1,556 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -// #region IMPORTS~ -import U from "../../core/utilities.js"; -import G, { ApplyTooltipAnimations } from "../../core/gsap.js"; -import C, { BladesActorType, BladesPhase, BladesItemType, DowntimeAction, AttributeTrait, Tag, ActionTrait, Factor, RollType } from "../../core/constants.js"; -import Tags from "../../core/tags.js"; -import { BladesActor, BladesPC, BladesCrew } from "../../documents/BladesActorProxy.js"; -import { BladesItem, BladesProject } from "../../documents/BladesItemProxy.js"; -import BladesDialog from "../../classes/BladesDialog.js"; -import BladesActiveEffect from "../../documents/BladesActiveEffect.js"; -import { BladesRollPrimary, BladesRollOpposition, BladesActionRoll, BladesFortuneRoll, BladesIndulgeViceRoll } from "../../classes/BladesRoll.js"; -// #endregion -class BladesActorSheet extends ActorSheet { - /** - * Override the default getData method to provide additional data for the actor sheet. - * This includes: cssClass, editable, isGM, actor, system, tierTotal, rollData, activeEffects, - * hasFullVision, hasLimitedVision, hasControl, preparedItems. - * @returns {BladesActorSheetData} The data object for the actor sheet. - */ - getData() { - // Get the base data context from the parent class. - const context = super.getData(); - // Prepare additional data specific to this actor's sheet. - const sheetData = { - // Basic actor data. - cssClass: this.actor.type, - editable: this.options.editable, - isGM: game.eunoblades.Tracker?.system.is_spoofing_player ? false : game.user.isGM, - actor: this.actor, - system: this.actor.system, - gamePhase: game.eunoblades.Tracker?.phase || BladesPhase.Freeplay, - tierTotal: this.actor.getFactorTotal(Factor.tier) > 0 ? U.romanizeNum(this.actor.getFactorTotal(Factor.tier)) : "0", - rollData: this.actor.getRollData(), - activeEffects: Array.from(this.actor.effects), - hasFullVision: game.user.isGM - || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OBSERVER), - hasLimitedVision: game.user.isGM - || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.LIMITED), - hasControl: game.user.isGM || this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER) - }; - if (BladesPC.IsType(this.actor) || BladesCrew.IsType(this.actor)) { - // Prepare items for display on the actor sheet. - sheetData.preparedItems = { - abilities: [], - loadout: [], - cohorts: { - gang: this.actor.cohorts - .filter((item) => item.type === BladesItemType.cohort_gang) - .map((item) => { - // Prepare gang cohort items. - const subtypes = U.unique(Object.values(item.system.subtypes) - .map((subtype) => subtype.trim()) - .filter((subtype) => /[A-Za-z]/.test(subtype))); - const eliteSubtypes = [ - ...Object.values(item.system.elite_subtypes) - ]; - if (BladesCrew.IsType(item.parent)) { - eliteSubtypes.push(...(item.parent.upgrades ?? []) - .map((upgrade) => (upgrade.name ?? "").trim().replace(/^Elite /, ""))); - } - // Prepare images for gang cohort items. - const imgTypes = [...U.unique(eliteSubtypes.map((subtype) => subtype.trim()) - .filter((subtype) => /[A-Za-z]/ - .test(subtype) && subtypes.includes(subtype)))]; - if (imgTypes.length < 2) { - imgTypes.push(...subtypes.filter((subtype) => !imgTypes.includes(subtype))); - } - if (U.unique(imgTypes).length === 1) { - item.system.image = Object.values(item.system.elite_subtypes).includes(imgTypes[0]) ? `elite-${U.lCase(imgTypes[0])}.svg` : `${U.lCase(imgTypes[0])}.svg`; - } - else if (U.unique(imgTypes).length > 1) { - const [rightType, leftType] = imgTypes; - item.system.imageLeft = Object.values(item.system.elite_subtypes).includes(leftType) ? `elite-${U.lCase(leftType)}.svg` : `${U.lCase(leftType)}.svg`; - item.system.imageRight = Object.values(item.system.elite_subtypes).includes(rightType) ? `elite-${U.lCase(rightType)}.svg` : `${U.lCase(rightType)}.svg`; - } - // Prepare additional data for gang cohort items. - Object.assign(item.system, { - tierTotal: item.getFactorTotal(Factor.tier) > 0 ? U.romanizeNum(item.getFactorTotal(Factor.tier)) : "0", - cohortRollData: [ - { mode: "untrained", label: "Untrained", color: "transparent", tooltip: "

Roll Untrained

" } - ], - edgeData: Object.fromEntries(Object.values(item.system.edges ?? []) - .filter((edge) => /[A-Za-z]/.test(edge)) - .map((edge) => [edge.trim(), C.EdgeTooltips[edge]])), - flawData: Object.fromEntries(Object.values(item.system.flaws ?? []) - .filter((flaw) => /[A-Za-z]/.test(flaw)) - .map((flaw) => [flaw.trim(), C.FlawTooltips[flaw]])) - }); - return item; - }), - expert: this.actor.activeSubItems - .filter((item) => item.type === BladesItemType.cohort_expert) - .map((item) => { - // Prepare expert cohort items. - Object.assign(item.system, { - tierTotal: item.getFactorTotal(Factor.tier) > 0 ? U.romanizeNum(item.getFactorTotal(Factor.tier)) : "0", - cohortRollData: [ - { mode: "untrained", label: "Untrained", tooltip: "

Roll Untrained

" } - ], - edgeData: Object.fromEntries(Object.values(item.system.edges ?? []) - .filter((edge) => /[A-Za-z]/.test(edge)) - .map((edge) => [edge.trim(), C.EdgeTooltips[edge]])), - flawData: Object.fromEntries(Object.values(item.system.flaws ?? []) - .filter((flaw) => /[A-Za-z]/.test(flaw)) - .map((flaw) => [flaw.trim(), C.FlawTooltips[flaw]])) - }); - return item; - }) - }, - projects: [] - }; - } - // Prepare additional data for PC and Crew actors. - if (BladesActor.IsType(this.actor, BladesActorType.pc) || BladesActor.IsType(this.actor, BladesActorType.crew)) { - sheetData.playbookData = { - dotline: { - data: this.actor.system.experience.playbook, - dotlineClass: "xp-playbook", - target: "system.experience.playbook.value", - svgKey: "teeth.tall", - svgFull: "full|frame", - svgEmpty: "full|half|frame", - advanceButton: "advance-playbook" - } - }; - if (this.actor.system.experience.playbook.value !== this.actor.system.experience.playbook.max) { - sheetData.playbookData.tooltip = (new Handlebars.SafeString([ - "

At the End of the Session, Gain XP If ...

", - "
    ", - ...Object.values(this.actor.system.experience.clues ?? []).map((line) => `
  • ${line.replace(/^Y/, "... y")}
  • `) ?? [], - "
" - ].join(""))).toString(); - } - sheetData.coinsData = { - dotline: { - data: this.actor.system.coins, - target: "system.coins.value", - iconEmpty: "coin-full.svg", - iconFull: "coin-full.svg" - } - }; - } - // Return the combined data context for the actor sheet. - return { - ...context, - ...sheetData - }; - } - // #region LISTENERS & EVENT HANDLERS - activateListeners(html) { - super.activateListeners(html); - // Handle removal or revealing of secret information content. - if (game.user.isGM) { - html.attr("style", "--secret-text-display: initial"); - } - else { - html.find('.editor:not(.tinymce) [data-is-secret="true"]').remove(); - } - // ~ Tooltips - ApplyTooltipAnimations(html); - Tags.InitListeners(html, this.actor); - // Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - // Add dotline functionality - html.find(".dotline").each((__, elem) => { - if ($(elem).hasClass("locked")) { - return; - } - let targetDoc = this.actor; - let targetField = $(elem).data("target"); - const comp$ = $(elem).closest("comp"); - if (targetField.startsWith("item")) { - targetField = targetField.replace(/^item\./, ""); - const itemId = $(elem).closest("[data-comp-id]").data("compId"); - if (!itemId) { - return; - } - const item = this.actor.items.get(itemId); - if (!item) { - return; - } - targetDoc = item; - } - const curValue = U.pInt($(elem).data("value")); - $(elem) - .find(".dot") - .each((_, dot) => { - $(dot).on("click", (event) => { - event.preventDefault(); - const thisValue = U.pInt($(dot).data("value")); - if (thisValue !== curValue) { - if (comp$.hasClass("comp-coins") - || comp$.hasClass("comp-stash")) { - G.effects - .fillCoins($(dot).prevAll(".dot")) - .then(() => targetDoc.update({ [targetField]: thisValue })); - } - else { - targetDoc.update({ [targetField]: thisValue }); - } - } - }); - $(dot).on("contextmenu", (event) => { - event.preventDefault(); - const thisValue = U.pInt($(dot).data("value")) - 1; - if (thisValue !== curValue) { - targetDoc.update({ [targetField]: thisValue }); - } - }); - }); - }); - // Component Functionality: Open, Add (via SelectorDialog), Archive, Delete, Toggle, Select - html - .find("[data-comp-id]") - .find(".comp-title") - .on({ click: this._onItemOpenClick.bind(this) }); - html - .find(".comp-control.comp-add") - .on({ click: this._onItemAddClick.bind(this) }); - html - .find(".comp-control.comp-delete") - .on({ click: this._onItemRemoveClick.bind(this) }); - html - .find(".comp-control.comp-delete-full") - .on({ click: this._onItemFullRemoveClick.bind(this) }); - html - .find(".comp-control.comp-toggle") - .on({ click: this._onItemToggleClick.bind(this) }); - html - .find(` - select[data-action='player-select'], - select[data-action='gm-select'] - `) - .on({ change: this._onSelectChange.bind(this) }); - html - .find("[data-action='toggle-value'") - .on({ click: this._onToggleValueClick.bind(this) }); - html - .find(".advance-button") - .on({ click: this._onAdvanceClick.bind(this) }); - // Active Effects Functionality - html - .find(".effect-control") - .on({ click: this._onActiveEffectControlClick.bind(this) }); - // Roll Functionality - html - .find("[data-roll-trait]") - .on({ click: this._onRollTraitClick.bind(this) }); - // Downtime Actions - html - .find("[data-action*='downtime-action-']") - .on({ click: this._onDowntimeActionClick.bind(this) }); - // This is a workaround until is being fixed in FoundryVTT. - if (this.options.submitOnChange) { - html.on("change", "textarea", this._onChangeInput.bind(this)); // Use delegated listener on the form - } - } - async _onSubmit(event, params = {}) { - if (!game.user.isGM && !this.actor.testUserPermission(game.user, CONST.DOCUMENT_PERMISSION_LEVELS.OWNER)) { - eLog.checkLog("actorSheetTrigger", "User does not have permission to edit this actor", { user: game.user, actor: this.actor }); - return {}; - } - return super._onSubmit(event, params); - } - async close(options) { - if (this.actor.type === BladesActorType.pc) { - return super.close(options).then(() => this.actor.clearSubActors()); - } - else if (this.actor.type === BladesActorType.npc && this.actor.parentActor) { - return super.close(options).then(() => this.actor.clearParentActor(false)); - } - return super.close(options); - } - // #region Component Handlers - _getCompData(event) { - const elem$ = $(event.currentTarget).closest(".comp"); - const compData = { - elem$, - docID: elem$.data("compId"), - docCat: elem$.data("compCat"), - docType: elem$.data("compType"), - docTags: (elem$.data("compTags") ?? "").split(/\s+/g) - }; - eLog.checkLog2("dialog", "Component Data", { elem: elem$, ...compData }); - if (compData.docID && compData.docType) { - compData.doc = { - Actor: this.actor.getSubActor(compData.docID), - Item: this.actor.getSubItem(compData.docID) - }[compData.docType]; - } - if (compData.docCat && compData.docType && (BladesPC.IsType(this.actor) || BladesCrew.IsType(this.actor))) { - compData.dialogDocs = { - Actor: this.actor.getDialogActors(compData.docCat), - Item: this.actor.getDialogItems(compData.docCat) - }[compData.docType]; - } - return compData; - } - _onItemOpenClick(event) { - event.preventDefault(); - const { doc } = this._getCompData(event); - if (!doc) { - return; - } - doc.sheet?.render(true); - } - async _onItemAddClick(event) { - event.preventDefault(); - const addType = $(event.currentTarget).closest(".comp").data("addType"); - if (addType && addType in BladesItemType) { - await this.actor.createEmbeddedDocuments("Item", [ - { - name: { - [BladesItemType.cohort_gang]: "A Gang", - [BladesItemType.cohort_expert]: "An Expert" - }[addType] ?? randomID(), - type: addType - } - ]); - return; - } - const { docCat, docType, dialogDocs, docTags } = this._getCompData(event); - if (!dialogDocs || !docCat || !docType) { - return; - } - await BladesDialog.DisplaySelectionDialog(this.actor, U.tCase(`Add ${docCat.replace(/_/g, " ")}`), docType, dialogDocs, docTags); - } - async _onItemRemoveClick(event) { - event.preventDefault(); - const { elem$, doc } = this._getCompData(event); - if (!doc) { - return; - } - await G.effects.blurRemove(elem$).then(async () => { - if (doc instanceof BladesItem) { - await this.actor.remSubItem(doc); - } - else { - await this.actor.remSubActor(doc); - } - }); - } - async _onItemFullRemoveClick(event) { - event.preventDefault(); - const { elem$, doc } = this._getCompData(event); - if (!doc) { - return; - } - await G.effects.blurRemove(elem$).then(async () => await doc.delete()); - } - async _onItemToggleClick(event) { - event.preventDefault(); - const target = $(event.currentTarget).data("target"); - await this.actor.update({ - [target]: !getProperty(this.actor, target) - }); - } - async _onSelectChange(event) { - event.preventDefault(); - await U.EventHandlers.onSelectChange(this, event); - } - async _onToggleValueClick(event) { - event.preventDefault(); - const elem$ = $(event.currentTarget); - const targetKey = elem$.data("target"); - const toggleOnVal = elem$.data("toggleOnVal") || ""; - const toggleOffVal = elem$.data("toggleOffVal") || ""; - if (getProperty(this.actor, targetKey) === toggleOnVal) { - await this.actor.update({ [targetKey]: toggleOffVal }); - } - else { - await this.actor.update({ [targetKey]: toggleOnVal }); - } - } - async _onAdvanceClick(event) { - event.preventDefault(); - if ($(event.currentTarget).data("action") === "advance-playbook") { - await this.actor.advancePlaybook(); - } - } - // #endregion - // #region Roll Handlers - async _onRollTraitClick(event) { - const traitName = $(event.currentTarget).data("rollTrait"); - const rollType = $(event.currentTarget).data("rollType"); - const rollData = { - target: this.actor, - targetFlagKey: "rollCollab" - }; - if (U.lCase(traitName) in { ...ActionTrait, ...AttributeTrait, ...Factor }) { - rollData.rollTrait = U.lCase(traitName); - } - else if (U.isInt(traitName)) { - rollData.rollTrait = U.pInt(traitName); - } - if (U.tCase(rollType) in RollType) { - rollData.rollType = U.tCase(rollType); - } - else if (typeof rollData.rollTrait === "string") { - if (rollData.rollTrait in AttributeTrait) { - rollData.rollType = RollType.Resistance; - } - else if (rollData.rollTrait in ActionTrait) { - rollData.rollType = RollType.Action; - } - } - if (game.user.isGM) { - if (BladesRollPrimary.IsDoc(this.actor)) { - rollData.rollPrimaryData = this.actor; - } - else if (BladesRollOpposition.IsDoc(this.actor)) { - rollData.rollOppData = this.actor; - } - } - await BladesActionRoll.New(rollData); - } - // Returns TRUE if can proceed, FALSE if action should stop (i.e. panel revealed for another user click) - async _validateOrRevealSubData(downtimeAction, actionSubData) { - switch (downtimeAction) { - case DowntimeAction.LongTermProject: { - // actionSubData must be "NewProject" or an id string to a project owned by this actor. - if (actionSubData === "NewProject") { - // Create new blank project owned by this.actor and render it for actor to edit. - return false; - } - const projectItem = game.items.get(actionSubData ?? ""); - if (BladesProject.IsType(projectItem)) { - return true; - } - // actionSubData isn't provided, which means this was the basic "Project" action button and sub-buttons must be revealed. - // Record Flip state of Downtime mid-bar - // Construct sub-button container, append it to Downtime mid-bar - // Construct "NewProject" button, append it to sub-button container - // Construct buttons for each owned project, append to sub-button container - // Run Flip.from animation - return false; - } - case DowntimeAction.Recover: { - // actionSubData must be a valid actor ID, who will become rollPrimary. - const healerActor = game.actors.get(actionSubData ?? ""); - if (healerActor instanceof BladesActor && healerActor.hasTag(Tag.NPC.CanHeal)) { - return true; - } - // actionSubData isn't provided, which means this was the basic "Recover" action button and sub-buttons must be revealed. - // Record Flip state of Downtime mid-bar - // Construct sub-button container, append it to Downtime mid-bar - // Compile list of PC characters with CanHeal tag. - // Compile list of _visible_ NPC characters with CanHeal tag. - // Append buttons to sub-button container - // Run Flip.from animation - return false; - } - case DowntimeAction.Train: { - // actionSubData must be of form 'playbook:2' - return Boolean(/^[a-z]+:\d$/.exec(actionSubData ?? "")); - } - // Other actions do not need subData validation and can always proceed: - default: return true; - } - } - async _onDowntimeActionClick(event) { - const elem$ = $(event.currentTarget); - // Extract the downtimeAction -- the substring of elem$.data("action") following the last hyphen (-) - const downtimeAction = elem$.data("action").substring(elem$.data("action").lastIndexOf("-") + 1); - // Extract the subData attribute - const actionSubData = elem$.data("actionSubData"); - // Validate subData: If invalid, subData buttons will be revealed -- return and wait for one to be clicked. - if (!(await this._validateOrRevealSubData(downtimeAction, actionSubData))) { - $("#eunos-blades-tooltips").children(".tooltip").remove(); - await this.actor.update({ "system.downtime_actions_open_submenu": downtimeAction }); - $("#eunos-blades-tooltips").children(".tooltip").remove(); - return; - } - const config = { - target: this.actor, - targetFlagKey: "rollCollab", - rollDowntimeAction: downtimeAction - }; - // Set necessary fields on roll construction config object, depending on downtime action - switch (downtimeAction) { - case DowntimeAction.AcquireAsset: - case DowntimeAction.LongTermProject: - case DowntimeAction.ReduceHeat: { - config.rollType = RollType.Action; - break; - } - case DowntimeAction.Recover: { - config.rollType = RollType.Action; - if (BladesPC.IsType(this.actor) && this.actor.healingClock) { - config.rollClockKey = this.actor.healingClock.id; - } - // rollOpposition = user character's healing clock - // rollPrimary = this.actor is NPC? - break; - } - case DowntimeAction.IndulgeVice: { - config.rollType = RollType.IndulgeVice; - break; - } - case DowntimeAction.Train: { - const [attr, value] = actionSubData.split(/:/); - if (attr === "playbook") { - this.actor.update({ [`system.experience.${attr}.value`]: U.pInt((this.actor.system.experience?.playbook?.value ?? 0)) + U.pInt(value) }); - } - else if (BladesPC.IsType(this.actor)) { - this.actor.update({ [`system.experience.${attr}.value`]: U.pInt(this.actor.system.experience[attr].value) + U.pInt(value) }); - } - // Increase track XP: If above max, set rollover value - break; - } - default: { - // This is for custom downtime actions added by, e.g., ActiveEffects. - break; - } - } - // Clear any open submenus, and add one to downtime actions used. - await this.actor.update({ - "system.downtime_actions_open_submenu": "", - "system.downtime_actions.value": (this.actor.system.downtime_actions?.value ?? 0) + 1 - }); - if ("rollType" in config) { - if (downtimeAction === DowntimeAction.IndulgeVice) { - BladesIndulgeViceRoll.New(config); - } - else { - BladesActionRoll.New(config); - } - } - } - async _onGatherInfoClick(event) { - const elem$ = $(event.currentTarget); - if (elem$.data("isFortuneRoll")) { - BladesFortuneRoll.New({ - target: this.actor, - targetFlagKey: "rollCollab", - rollType: RollType.Fortune - }); - } - else { - BladesActionRoll.New({ - target: this.actor, - targetFlagKey: "rollCollab", - rollType: RollType.Action, - rollTrait: "" - }); - } - } - // #endregion - // #region Active Effect Handlers - _onActiveEffectControlClick(event) { - BladesActiveEffect.onManageActiveEffect(event, this.actor); - } -} -export default BladesActorSheet; diff --git a/module/sheets/actor/BladesCrewSheet.js b/module/sheets/actor/BladesCrewSheet.js deleted file mode 100644 index d1230dd8..00000000 --- a/module/sheets/actor/BladesCrewSheet.js +++ /dev/null @@ -1,156 +0,0 @@ -import BladesActorSheet from "./BladesActorSheet.js"; -import { BladesItemType } from "../../core/constants.js"; -class BladesCrewSheet extends BladesActorSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "actor", "crew"], - template: "systems/eunos-blades/templates/crew-sheet.hbs", - width: 940, - height: 820, - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "claims" }] - }); - } - getData() { - const context = super.getData(); - eLog.checkLog("actor", "[BladesCrewSheet] super.getData()", { ...context }); - const { activeSubItems } = this.actor; - const sheetData = {}; - // ~ Assemble embedded actors and items - sheetData.preparedItems = Object.assign(context.preparedItems ?? {}, { - abilities: activeSubItems - .filter((item) => item.type === BladesItemType.crew_ability), - playbook: this.actor.playbook, - reputation: activeSubItems - .find((item) => item.type === BladesItemType.crew_reputation), - upgrades: activeSubItems - .filter((item) => item.type === BladesItemType.crew_upgrade), - preferredOp: activeSubItems - .find((item) => item.type === BladesItemType.preferred_op) - }); - sheetData.preparedActors = { - members: this.actor.members, - contacts: this.actor.contacts - }; - sheetData.tierData = { - label: "Tier", - dotline: { - data: this.actor.system.tier, - target: "system.tier.value", - iconEmpty: "dot-empty.svg", - iconEmptyHover: "dot-empty-hover.svg", - iconFull: "dot-full.svg", - iconFullHover: "dot-full-hover.svg" - } - }; - sheetData.upgradeData = { - dotline: { - dotlineClass: "dotline-right", - data: { - value: this.actor.availableUpgradePoints, - max: this.actor.availableUpgradePoints - }, - dotlineLabel: "Available Upgrade Points", - isLocked: true, - iconFull: "dot-full.svg" - } - }; - sheetData.abilityData = { - dotline: { - dotlineClass: "dotline-right", - data: { - value: this.actor.availableAbilityPoints, - max: this.actor.availableAbilityPoints - }, - dotlineLabel: "Available Ability Points", - isLocked: true, - iconFull: "dot-full.svg" - } - }; - sheetData.cohortData = { - dotline: { - dotlineClass: "dotline-right", - data: { - value: this.actor.availableCohortPoints, - max: this.actor.availableCohortPoints - }, - dotlineLabel: "Available Cohort Points", - isLocked: true, - iconFull: "dot-full.svg" - } - }; - sheetData.repData = { - label: "Rep", - dotlines: [ - { - data: { - value: Math.min(this.actor.system.rep.value, this.actor.system.rep.max - this.actor.turfCount), - max: this.actor.system.rep.max - this.actor.turfCount - }, - target: "system.rep.value", - svgKey: "teeth.tall", - svgFull: "full|half|frame", - svgEmpty: "full|half|frame" - }, - { - data: { - value: this.actor.turfCount, - max: this.actor.turfCount - }, - target: "none", - svgKey: "teeth.tall", - svgFull: "full|half|frame", - svgEmpty: "full|half|frame", - dotlineClass: "flex-row-reverse", - isLocked: true - } - ] - }; - sheetData.heatData = { - label: "Heat", - dotline: { - data: this.actor.system.heat, - target: "system.heat.value", - svgKey: "teeth.tall", - svgFull: "full|half|frame", - svgEmpty: "full|half|frame" - } - }; - sheetData.wantedData = { - label: "Wanted", - dotline: { - data: this.actor.system.wanted, - target: "system.wanted.value", - svgKey: "teeth.short", - svgFull: "full|frame", - svgEmpty: "frame" - } - }; - eLog.checkLog("actor", "[BladesCrewSheet] return getData()", { ...context, ...sheetData }); - return { ...context, ...sheetData }; - } - activateListeners(html) { - super.activateListeners(html); - // Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - // Update Inventory Item - html.find(".item-sheet-open").on("click", (event) => { - const element = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(element.data("itemId")); - item?.sheet?.render(true); - }); - // Toggle Hold - html.find(".hold-toggle").on("click", () => { - this.actor.update({ "system.hold": this.actor.system.hold === "weak" ? "strong" : "weak" }); - }); - // Toggle Turf - html.find(".turf-select").on("click", async (event) => { - const turf_id = $(event.currentTarget).data("turfId"); - const turf_current_status = $(event.currentTarget).data("turfStatus"); - this.actor.playbook?.update({ [`system.turfs.${turf_id}.value`]: !turf_current_status }) - .then(() => this.render(false)); - }); - } -} -export default BladesCrewSheet; diff --git a/module/sheets/actor/BladesFactionSheet.js b/module/sheets/actor/BladesFactionSheet.js deleted file mode 100644 index 3c06c794..00000000 --- a/module/sheets/actor/BladesFactionSheet.js +++ /dev/null @@ -1,71 +0,0 @@ -import BladesActor from "../../BladesActor.js"; -import BladesActorSheet from "./BladesActorSheet.js"; -import { BladesActorType } from "../../core/constants.js"; -class BladesFactionSheet extends BladesActorSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "actor", "faction"], - template: "systems/eunos-blades/templates/faction-sheet.hbs", - width: 900, - height: "auto", - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "overview" }] - }); - } - getData() { - const context = super.getData(); - if (!BladesActor.IsType(this.actor, BladesActorType.faction)) { - return context; - } - const sheetData = { - tierData: { - class: "comp-tier comp-vertical comp-teeth", - label: "Tier", - labelClass: "filled-label full-width", - dotline: { - data: this.actor.system.tier, - target: "system.tier.value", - svgKey: "teeth.tall", - svgFull: "full|half|frame", - svgEmpty: "full|half|frame" - } - }, - clockKeys: this.actor.clocks - }; - return { - ...context, - ...sheetData - }; - } - async _onClockAddClick(event) { - event.preventDefault(); - this.actor.addClock(); - } - async _onClockDeleteClick(event) { - event.preventDefault(); - const clockID = $(event.currentTarget).data("clockId"); - if (!clockID) { - return; - } - this.actor.deleteClock(clockID); - } - activateListeners(html) { - super.activateListeners(html); - // Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - // Update Inventory Item - html.find(".item-body").on("click", (event) => { - const element = $(event.currentTarget).parents(".item"); - const item = this.actor.items.get(element.data("itemId")); - item?.sheet?.render(true); - }); - html - .find(".comp-control.comp-add-clock") - .on("click", this._onClockAddClick.bind(this)); - html - .find(".comp-control.comp-delete-clock") - .on("click", this._onClockDeleteClick.bind(this)); - } -} -export default BladesFactionSheet; diff --git a/module/sheets/actor/BladesNPCSheet.js b/module/sheets/actor/BladesNPCSheet.js deleted file mode 100644 index a8372915..00000000 --- a/module/sheets/actor/BladesNPCSheet.js +++ /dev/null @@ -1,91 +0,0 @@ -import BladesActorSheet from "./BladesActorSheet.js"; -import U from "../../core/utilities.js"; -class BladesNPCSheet extends BladesActorSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "actor", "npc"], - template: "systems/eunos-blades/templates/npc-sheet.hbs", - width: 500, - height: 400, - // height: "auto", - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "description" }] - }); - } - getData() { - const context = super.getData(); - context.isSubActor = context.actor.isSubActor; - context.parentActor = context.actor.parentActor; - context.persona = context.actor.system.persona; - context.random = context.actor.system.random; - context.secret = context.actor.system.secret; - const rStatus = { - name: { size: 3, label: "Name" }, - gender: { size: "half", label: "Gender" }, - heritage: { size: "third", label: "Heritage" }, - background: { size: "third", label: "Background" }, - profession: { size: "third", label: "Profession" }, - appearance: { size: 2, label: "Appearance" }, - style: { size: 2, label: "Style" }, - quirk: { size: 4, label: "Quirk" }, - goal: { size: 2, label: "Goal" }, - method: { size: 2, label: "Method" }, - interests: { size: 4, label: "Interests" }, - trait: { size: "half", label: "Trait" }, - trait1: { size: "half", label: null }, - trait2: { size: "half", label: null }, - trait3: { size: "half", label: null } - }; - for (const cat of ["persona", "random", "secret"]) { - for (const [key] of Object.entries(context[cat])) { - if (key in rStatus) { - Object.assign(context[cat][key], rStatus[key]); - } - } - } - console.log({ persona: context.persona, random: context.random, secret: context.secret }); - return context; - } - activateListeners(html) { - super.activateListeners(html); - // Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - html.find(".gm-alert-header").on("click", async (event) => { - event.preventDefault(); - this.actor.clearParentActor(); - }); - // ~ Configure Tagify input elements - // const inputElement = document.querySelector('input[name="system.harm.severe.one"]'); - // if (inputElement instanceof HTMLInputElement) { new Tagify(inputElement, {}) } else { console.log("Not an HTMLInputElement")} - // ~ Enable Randomize Button for NPCs - html.find("[data-action=\"randomize\"").on("click", () => { - this.actor.updateRandomizers(); - }); - // ~ Enable status toggles for NPC subactors - html.find(".comp-status-toggle") - .on("click", () => { - const { tags } = this.actor; - if (this.actor.system.status === 1) { - U.remove(tags, "Friend"); - tags.push("Rival"); - this.actor.update({ - "system.status": -1, - "system.tags": U.unique(tags) - }); - } - else { - U.remove(tags, "Rival"); - tags.push("Friend"); - this.actor.update({ - "system.status": 1, - "system.tags": U.unique(tags) - }); - } - }) - .on("contextmenu", () => { - this.actor.update({ "system.status": 0 }); - }); - } -} -export default BladesNPCSheet; diff --git a/module/sheets/actor/BladesPCSheet.js b/module/sheets/actor/BladesPCSheet.js deleted file mode 100644 index 09d30ce3..00000000 --- a/module/sheets/actor/BladesPCSheet.js +++ /dev/null @@ -1,492 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { BladesActorType, BladesItemType, AttributeTrait, Tag, DowntimeAction, BladesPhase } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import BladesActorSheet from "./BladesActorSheet.js"; -import { BladesActor, BladesPC, BladesNPC } from "../../documents/BladesActorProxy.js"; -class BladesPCSheet extends BladesActorSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "actor", "pc"], - template: "systems/eunos-blades/templates/actor-sheet.hbs", - width: 775, - height: 775, - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "abilities" }] - }); - } - getData() { - const context = super.getData(); - const { activeSubItems, activeSubActors } = this.actor; - const sheetData = {}; - // ~ Assemble embedded actors and items - sheetData.preparedItems = Object.assign(context.preparedItems ?? {}, { - abilities: activeSubItems - .filter((item) => item.type === BladesItemType.ability) - .map((item) => { - // ~ Assign dotlines to abilities with usage data - if (item.system.uses_per_score.max) { - Object.assign(item, { - inRuleDotline: { - data: item.system.uses_per_score, - dotlineLabel: "Uses", - target: "item.system.uses_per_score.value", - iconEmpty: "dot-empty.svg", - iconEmptyHover: "dot-empty-hover.svg", - iconFull: "dot-full.svg", - iconFullHover: "dot-full-hover.svg" - } - }); - } - return item; - }), - background: activeSubItems.find((item) => item.type === BladesItemType.background), - heritage: activeSubItems.find((item) => item.type === BladesItemType.heritage), - vice: activeSubItems.find((item) => item.type === BladesItemType.vice), - loadout: activeSubItems - .filter((item) => item.type === BladesItemType.gear) - .map((item) => { - // Assign load and usage data to gear - if (item.system.load) { - Object.assign(item, { - numberCircle: item.system.load, - numberCircleClass: "item-load" - }); - } - if (item.system.uses_per_score.max) { - Object.assign(item, { - inRuleDotline: { - data: item.system.uses_per_score, - dotlineLabel: "Uses", - target: "item.system.uses_per_score.value", - iconEmpty: "dot-empty.svg", - iconEmptyHover: "dot-empty-hover.svg", - iconFull: "dot-full.svg", - iconFullHover: "dot-full-hover.svg" - } - }); - } - return item; - }), - playbook: this.actor.playbook, - projects: activeSubItems.filter((item) => item.type === BladesItemType.project), - cohorts: context.preparedItems?.cohorts - }); - sheetData.preparedActors = { - crew: activeSubActors - .find((actor) => actor.type === BladesActorType.crew), - vice_purveyor: activeSubActors - .find((actor) => actor.hasTag(Tag.NPC.VicePurveyor)), - acquaintances: activeSubActors - .filter((actor) => actor.hasTag(Tag.NPC.Acquaintance)) - }; - sheetData.hasVicePurveyor = Boolean(this.actor.playbook?.hasTag(Tag.Gear.Advanced) === false - && activeSubItems.find((item) => item.type === BladesItemType.vice)); - sheetData.healing_clock = this.actor.healingClock; - sheetData.stashData = { - label: "Stash:", - dotline: { - data: this.actor.system.stash, - target: "system.stash.value", - iconEmpty: "coin-empty.svg", - iconEmptyHover: "coin-empty-hover.svg", - iconFull: "coin-full.svg", - iconFullHover: "coin-full-hover.svg", - altIconFull: "coin-ten.svg", - altIconFullHover: "coin-ten-hover.svg", - altIconStep: 10 - } - }; - sheetData.stressData = { - label: this.actor.system.stress.name, - dotline: { - data: this.actor.system.stress, - dotlineClass: this.actor.system.stress.max >= 13 ? "narrow-stress" : "", - target: "system.stress.value", - svgKey: "teeth.tall", - svgFull: "full|half|frame", - svgEmpty: "full|half|frame" - } - }; - if (BladesActor.IsType(this.actor, BladesActorType.pc)) { - sheetData.traumaData = { - label: this.actor.system.trauma.name, - dotline: { - data: { value: this.actor.trauma, max: this.actor.system.trauma.max }, - svgKey: "teeth.short", - svgFull: "full|frame", - svgEmpty: "frame", - isLocked: true - }, - compContainer: { - class: "comp-trauma-conditions comp-vertical full-width", - blocks: [ - this.actor.traumaList.slice(0, Math.ceil(this.actor.traumaList.length / 2)) - .map((tName) => ({ - checkLabel: tName, - checkClasses: { - active: "comp-toggle-red", - inactive: "comp-toggle-grey" - }, - checkTarget: `system.trauma.checked.${tName}`, - checkValue: this.actor.system.trauma.checked[tName] ?? false, - tooltip: C.TraumaTooltips[tName], - tooltipClass: "tooltip-trauma" - })), - this.actor.traumaList.slice(Math.ceil(this.actor.traumaList.length / 2)) - .map((tName) => ({ - checkLabel: tName, - checkClasses: { - active: "comp-toggle-red", - inactive: "comp-toggle-grey" - }, - checkTarget: `system.trauma.checked.${tName}`, - checkValue: this.actor.system.trauma.checked[tName] ?? false, - tooltip: C.TraumaTooltips[tName], - tooltipClass: "tooltip-trauma" - })) - ] - } - }; - } - sheetData.abilityData = { - dotline: { - dotlineClass: "dotline-right dotline-glow", - data: { - value: this.actor.getAvailableAdvancements("Ability"), - max: this.actor.getAvailableAdvancements("Ability") - }, - dotlineLabel: "Available Abilities", - isLocked: true, - iconFull: "dot-full.svg" - } - }; - sheetData.loadData = { - curLoad: this.actor.currentLoad, - selLoadCount: this.actor.system.loadout.levels[U.lCase(this.actor.system.loadout.selected)], - options: C.Loadout.selections, - selected: this.actor.system.loadout.selected ?? "" - }; - sheetData.armor = Object.fromEntries(Object.entries(this.actor.system.armor.active) - .filter(([, isActive]) => isActive) - .map(([armor]) => [ - armor, - this.actor.system.armor.checked[armor] - ])); - sheetData.attributeData = {}; - const attrEntries = Object.entries(this.actor.system.attributes); - for (const [attribute, attrData] of attrEntries) { - sheetData.attributeData[attribute] = { - tooltip: C.AttributeTooltips[attribute], - actions: {} - }; - const actionEntries = Object.entries(attrData); - for (const [action, actionData] of actionEntries) { - sheetData.attributeData[attribute].actions[action] = { - tooltip: C.ActionTooltips[action], - value: actionData.value, - max: game.eunoblades.Tracker.phase === BladesPhase.CharGen - ? 2 - : this.actor.system.attributes[attribute][action].max - }; - } - } - if (game.eunoblades.Tracker?.phase === BladesPhase.Downtime) { - const actionsList = { - [DowntimeAction.AcquireAsset]: "Acquire Asset", - [DowntimeAction.IndulgeVice]: "Indulge Vice", - [DowntimeAction.LongTermProject]: "Project", - [DowntimeAction.Recover]: "Recover", - [DowntimeAction.ReduceHeat]: "Reduce Heat", - [DowntimeAction.Train]: "Train" - }; - // Get PCs, NPCs capable of rolling for the Recover action - const healCapableDocs = [ - ...BladesActor.GetTypeWithTags(BladesActorType.pc, Tag.PC.CanHeal), - ...BladesActor.GetTypeWithTags(BladesActorType.npc, Tag.NPC.CanHeal) - /* ALSO NEED TO INCLUDE EXPERT COHORTS WITH CANHEAL TAG */ - ]; - // delete any Actions that aren't applicable - if (this.actor.stress === 0) { - delete actionsList[DowntimeAction.IndulgeVice]; - } - if (this.actor.harmLevel === 0 || healCapableDocs.length === 0) { - delete actionsList[DowntimeAction.Recover]; - } - if (!this.actor.crew || this.actor.crew.system.heat.value === 0) { - delete actionsList[DowntimeAction.ReduceHeat]; - } - let actionsSubmenuData = undefined; - switch (this.actor.system.downtime_actions_open_submenu) { - case DowntimeAction.LongTermProject: { - actionsSubmenuData = [ - { - actionSubData: "NewProject", - display: "New Project" - } - ]; - // ... and add one for each Project on the PC. - break; - } - case DowntimeAction.Recover: { - actionsSubmenuData = []; - healCapableDocs.forEach((hDoc) => { - if (hDoc.id === this.actor.id) { - actionsSubmenuData?.unshift({ - actionSubData: this.actor.id, - display: "Heal Self" - }); - } - else if (BladesPC.IsType(hDoc)) { - actionsSubmenuData?.push({ - actionSubData: hDoc.id, - display: U.uCase(hDoc.name) - }); - } - else if (BladesNPC.IsType(hDoc)) { - actionsSubmenuData?.push({ - actionSubData: hDoc.id, - display: hDoc.name - }); - } /* NEED CHECK FOR COHORT HEALERS TOO */ - }); - break; - } - case DowntimeAction.Train: { - const crewTrainingUpgrades = (this.actor.crew?.upgrades - .filter((upgrade) => /^Training_/.exec(upgrade.system.world_name)) - .map((upgrade) => U.lCase(upgrade.system.world_name.split(/_/)[1])) ?? []); - actionsSubmenuData = [ - { - actionSubData: `playbook:${crewTrainingUpgrades.includes("playbook") ? 2 : 1}`, - display: `${crewTrainingUpgrades.includes("playbook") ? 2 : 1} Playbook XP` - }, - { - actionSubData: `insight:${crewTrainingUpgrades.includes(AttributeTrait.insight) ? 2 : 1}`, - display: `${crewTrainingUpgrades.includes(AttributeTrait.insight) ? 2 : 1} Insight XP` - }, - { - actionSubData: `prowess:${crewTrainingUpgrades.includes(AttributeTrait.prowess) ? 2 : 1}`, - display: `${crewTrainingUpgrades.includes(AttributeTrait.prowess) ? 2 : 1} Prowess XP` - }, - { - actionSubData: `resolve:${crewTrainingUpgrades.includes(AttributeTrait.resolve) ? 2 : 1}`, - display: `${crewTrainingUpgrades.includes(AttributeTrait.resolve) ? 2 : 1} Resolve XP` - } - ]; - break; - } - } - const actionsTooltips = { - [DowntimeAction.AcquireAsset]: `

Acquire an Asset

-

Roll your Tier to acquire temporary use of an asset or service.

-

The Quality of the acquired asset depends on the result of your roll:

-
    -
  • Critical SuccessTier + 2
  • -
  • SuccessTier + 2
  • -
  • Partial SuccessTier
  • -
  • FailTier − 1
  • -
`, - [DowntimeAction.IndulgeVice]: `

Indulge Your Vice

-

Roll your lowest Attribute. Clear Stress equal to the highest die result.

-

Warning: If you clear more Stress than you have, you will overindulge.

`, - [DowntimeAction.LongTermProject]: `

Work on a Long-Term Project

-

Work to advance the clock of one of your existing Long-Term Projects, or begin a new one.

-

Roll the Action most appropriate to the work you are doing. The results of your roll determine how far you will advance the clock:

-
    -
  • Critical SuccessFive Segments
  • -
  • SuccessThree Segments
  • -
  • Partial SuccessTwo Segments
  • -
  • FailOne Segment
  • -
`, - [DowntimeAction.Recover]: `

Recover from Harm

-

Make a healing treatment roll using the appropriate trait of the character healing you:

-
    -
  • A PC with 'Physicker'Tinker. (You can heal yourself this way, but suffer 2 Stress for doing so.)
  • -
  • An NPCQuality
  • -
-

The results of your roll determine how far you will Advance your healing clock:

-
    -
  • Critical SuccessFive Segments
  • -
  • SuccessThree Segments
  • -
  • Partial SuccessTwo Segments
  • -
  • FailOne Segment
  • -
-

When your healing clock is filled, reduce each Harm by one level of severity.

`, - [DowntimeAction.ReduceHeat]: `

Reduce Heat

-

Work to reduce the Heat on your Crew.

-

Roll the Action most appropriate to the measures you are taking. The results of your roll determine how much Heat you clear:

-
    -
  • Critical SuccessFive Heat
  • -
  • SuccessThree Heat
  • -
  • Partial SuccessTwo Heat
  • -
  • FailOne Heat
  • -
`, - [DowntimeAction.Train]: `

Train

-

Select an Experience Track (i.e. Insight, Prowess, Resolve, or your Playbook). Gain 1 XP in that track, or 2 XP if your Crew has the corresponding Training Upgrade.

` - }; - const actionsRemaining = this.actor.system.downtime_actions.max - + this.actor.system.downtime_action_bonus - - this.actor.system.downtime_actions.value - - (this.actor.isAtWar ? 1 : 0); - const canPayCoin = Boolean(this.actor.system.coins.value >= 1 - || this.actor.system.stash.value >= 2); - const canPayRep = Boolean(this.actor.crew - && this.actor.crew.system.rep.value >= 1); - const isDisplayingCosts = actionsRemaining <= 0; - const isDisplayingActions = actionsRemaining > 0 - || (canPayCoin && this.actor.system.downtime_action_selected_cost === "Coin") - || (canPayRep && this.actor.system.downtime_action_selected_cost === "Rep"); - sheetData.downtimeData = { - actionsList, - actionsTooltips, - actionsRemaining, - actionsSubmenuData, - canPayCoin, - canPayRep, - isDisplayingCosts, - isDisplayingActions, - dotline: { - dotlineClass: "dotline-right dotline-glow", - data: { - value: actionsRemaining, - max: actionsRemaining - }, - dotlineLabel: "Actions Remaining", - isLocked: true, - iconFull: "dot-full.svg" - } - }; - } - sheetData.gatherInfoTooltip = (new Handlebars.SafeString([ - "

Gathering Information

", - "

Questions to Consider

", - "
    ", - ...Object.values(this.actor.system.gather_info ?? []).map((line) => `
  • ${line}
  • `) ?? [], - "
" - ].join(""))).toString(); - eLog.checkLog("Attribute", "[BladesPCSheet] attributeData", { attributeData: sheetData.attributeData }); - eLog.checkLog("actor", "[BladesPCSheet] getData()", { ...context, ...sheetData }); - return { ...context, ...sheetData }; - } - get activeArmor() { - return Object.keys(U.objFilter(this.actor.system.armor.active, (val) => val === true)); - } - get checkedArmor() { - return Object.keys(U.objFilter(this.actor.system.armor.checked, (val, key) => val === true - && this.actor.system.armor.active[key] === true)); - } - get uncheckedArmor() { - return Object.keys(U.objFilter(this.actor.system.armor.active, (val, key) => val === true - && this.actor.system.armor.checked[key] === false)); - } - _getHoverArmor() { - if (!this.activeArmor.length) { - return false; - } - if (this.activeArmor.includes("heavy")) { - return this.checkedArmor.includes("heavy") ? "light" : "heavy"; - } - else if (this.activeArmor.includes("light")) { - return "light"; - } - return "special"; - } - _getClickArmor() { - if (!this.uncheckedArmor.length) { - return false; - } - if (this.uncheckedArmor.includes("heavy")) { - return "heavy"; - } - if (this.uncheckedArmor.includes("light")) { - return "light"; - } - return "special"; - } - _getContextMenuArmor() { - if (!this.checkedArmor.length) { - return false; - } - if (this.checkedArmor.includes("light")) { - return "light"; - } - if (this.checkedArmor.includes("heavy")) { - return "heavy"; - } - return "special"; - } - async _onAdvanceClick(event) { - event.preventDefault(); - super._onAdvanceClick(event); - const action = $(event.currentTarget).data("action").replace(/^advance-/, ""); - if (action in AttributeTrait) { - await this.actor.advanceAttribute(action); - } - } - activateListeners(html) { - super.activateListeners(html); - // ~ Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - const self = this; - // ~ Armor Control - html.find(".main-armor-control").on({ - click() { - const targetArmor = self._getClickArmor(); - if (!targetArmor) { - return; - } - self.actor.update({ [`system.armor.checked.${targetArmor}`]: true }); - }, - contextmenu() { - const targetArmor = self._getContextMenuArmor(); - if (!targetArmor) { - return; - } - self.actor.update({ [`system.armor.checked.${targetArmor}`]: false }); - }, - mouseenter() { - const targetArmor = self._getHoverArmor(); - eLog.log4("Mouse Enter", targetArmor, this, $(this), $(this).next()); - if (!targetArmor) { - return; - } - $(this).siblings(`.svg-armor.armor-${targetArmor}`).addClass("hover-over"); - }, - mouseleave() { - const targetArmor = self._getHoverArmor(); - if (!targetArmor) { - return; - } - $(this).siblings(`.svg-armor.armor-${targetArmor}`).removeClass("hover-over"); - } - }); - html.find(".special-control").on({ - click() { - if (!self.activeArmor.includes("special")) { - return; - } - self.actor.update({ "system.armor.checked.special": self.uncheckedArmor.includes("special") }); - }, - contextmenu() { - if (!self.activeArmor.includes("special")) { - return; - } - self.actor.update({ "system.armor.checked.special": self.uncheckedArmor.includes("special") }); - }, - mouseenter() { - if (!self.activeArmor.includes("special") || self.activeArmor.length === 1) { - return; - } - $(this).siblings(".svg-armor.armor-special").addClass("hover-over"); - }, - mouseleave() { - if (!self.activeArmor.includes("special") || self.activeArmor.length === 1) { - return; - } - $(this).siblings(".svg-armor.armor-special").removeClass("hover-over"); - } - }); - } -} -export default BladesPCSheet; diff --git a/module/sheets/item/BladesClockKeeperSheet.js b/module/sheets/item/BladesClockKeeperSheet.js deleted file mode 100644 index dd996840..00000000 --- a/module/sheets/item/BladesClockKeeperSheet.js +++ /dev/null @@ -1,461 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import U from "../../core/utilities.js"; -import BladesItemSheet from "./BladesItemSheet.js"; -// import U from "../../core/utilities.js"; -import { ClockColor, ClockDisplayContext } from "../../core/constants.js"; -import { BladesPC, BladesFaction } from "../../documents/BladesActorProxy.js"; -class BladesClockKeeperSheet extends BladesItemSheet { - // static Get() { return game.eunoblades.ClockKeeper as BladesClockKeeper; } - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "item", "clock-keeper"], - template: "systems/eunos-blades/templates/items/clock_keeper-sheet.hbs", - width: 700, - height: 970, - // submitOnChange: false, - tabs: [{ navSelector: ".nav-tabs", contentSelector: ".tab-content", initial: "scene-keys" }] - }); - } - static async Initialize() { - Items.registerSheet("blades", BladesClockKeeperSheet, { types: ["clock_keeper"], makeDefault: true }); - return loadTemplates([ - "systems/eunos-blades/templates/items/clock_keeper-sheet.hbs" - ]); - } - getData() { - const context = super.getData(); - const sheetData = { - currentScene: game.scenes.current.id, - targetScene: this.item.targetSceneID, - sceneOptions: Array.from(game.scenes), - sceneKeys: this.item.getSceneKeys(this.item.system.targetScene ?? game.scenes.current.id), - pcsWithProjects: BladesPC.All.filter((pc) => pc.projects.length > 0), - factions: Array.from(BladesFaction.All) - }; - return { ...context, ...sheetData }; - } - addKey(event) { - event.preventDefault(); - this.item.addClockKey(); - } - deleteKey(event) { - event.preventDefault(); - const keyID = event.currentTarget.dataset.id; - if (keyID) { - this.item.deleteClockKey(keyID); - } - } - setSelectColor(select$, value) { - value ??= select$.data("value"); - switch (value) { - case ClockColor.yellow: { - U.gsap.set(select$, { - color: "var(--blades-black)", - background: "var(--blades-gold-bright)", - textShadow: "none" - }); - break; - } - case ClockColor.red: { - U.gsap.set(select$, { - color: "var(--blades-white)", - background: "var(--blades-red)" - }); - break; - } - case ClockColor.cyan: { - U.gsap.set(select$, { - color: "var(--blades-black)", - background: "var(--blades-blue-bright)", - textShadow: "none" - }); - break; - } - case ClockColor.white: { - U.gsap.set(select$, { - color: "var(--blades-black)", - background: "var(--blades-white)", - textShadow: "none" - }); - break; - } - default: break; - } - } - async activateListeners(html) { - await super.activateListeners(html); - // *** CREATE CLOCK KEY *** ~ - html.find("[data-action=\"create-clock-key\"").on({ - click: async (event) => { - event.preventDefault(); - await this.item.addClockKey(); - // Notify GM - } - }); - // #region Helper Functions to Retrieve Clock Keys & Clocks ~ - function getClockKeyFromEvent(event) { - const id = $(event.currentTarget).data("keyId") - || $(event.currentTarget).closest(".control-flipper").data("clockKeyId"); - if (!id) { - throw new Error("No id found on element"); - } - const clockKey = game.eunoblades.ClockKeys.get(id); - if (!clockKey) { - throw new Error(`Clock key with id ${id} not found`); - } - return clockKey; - } - function getClockFromEvent(event) { - const clockKey = getClockKeyFromEvent(event); - const clockID = $(event.currentTarget).data("clockId") - || $(event.currentTarget).closest(".control-flipper").data("clockId"); - if (!clockID) { - throw new Error("No clockID found on element"); - } - const clock = clockKey.getClockByID(clockID); - if (!clock) { - throw new Error(`Clock with id ${clockID} not found`); - } - return [clockKey, clock]; - } - // #endregion - // #region Initializing Flip Control Panels ~ - // const flipControls$ = html.find(".control-flipper"); - // setTimeout(() => { - // U.gsap.set(flipControls$.find(".controls-back"), { - // translateZ: -2, - // rotateX: 180, - // autoAlpha: 1 - // }); - // U.gsap.set(flipControls$.find(".controls-front"), { - // translateZ: 2, - // autoAlpha: 1 - // }); - // U.gsap.set(html.find(".control-flipper.controls-flipped"), { - // rotateX: 180 - // }); - // }, 500); - // #endregion - // #region *** CLOCK KEYS *** ~ - const clockKeyControls$ = html.find(".clock-key-control-flipper"); - // #region isOnDisplay === TRUE OR FALSE (Conditional Animation Checks Required) ~ - clockKeyControls$.find("[data-action=\"toggle-name-visibility\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-key-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const clockKey = getClockKeyFromEvent(event); - const isNameVisible = !clockKey.isNameVisible; - clockKey.updateTarget("isNameVisible", isNameVisible); - // If clockKey is on display (in scene & visible), sent out animation socket calls - if (clockKey.isInScene() && clockKey.isVisible) { - if (isNameVisible) { - clockKey.fadeInName_SocketCall(ClockDisplayContext.overlay); - } - else { - clockKey.fadeOutName_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-name-visibility\"] i") - .toggleClass("fa-signature") - .toggleClass("fa-signature-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - clockKeyControls$.find("[data-action=\"toggle-spotlight\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-key-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const clockKey = getClockKeyFromEvent(event); - const isSpotlit = !clockKey.isSpotlit; - clockKey.updateTarget("isSpotlit", isSpotlit); - // If clockKey is on display (in scene & visible), sent out animation socket calls - if (clockKey.isInScene() && clockKey.isVisible) { - if (isSpotlit) { - // clockKey.unspotlight_SocketCall(ClockDisplayContext.overlay); - } - else { - // clockKey.spotlight_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-spotlight\"] i") - .toggleClass("fa-message") - .toggleClass("fa-message-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - // #endregion - // #region isOnDisplay === TRUE ~ - clockKeyControls$.find("[data-action=\"pull-clock-key\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-key-control-flipper"); - elem$.on({ - click: (event) => { - event.preventDefault(); - U.gsap.effects.keyControlPanelFlip(control$, { angle: 180 }); - const clockKey = getClockKeyFromEvent(event); - clockKey.updateTarget("isVisible", false); - game.eunoblades.Director.pullKey_SocketCall(clockKey.id); - } - }); - }); - // #endregion - // #region isOnDisplay === FALSE ~ - clockKeyControls$.find("[data-action=\"drop-clock-key\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-key-control-flipper"); - elem$.on({ - click: (event) => { - event.preventDefault(); - U.gsap.effects.keyControlPanelFlip(control$, { angle: 0 }); - const clockKey = getClockKeyFromEvent(event); - clockKey.updateTarget("isVisible", true); - game.eunoblades.Director.renderClockKey_SocketCall(clockKey.id); - } - }); - }); - clockKeyControls$.find("[data-action=\"spawn-position-dragger\"]").on({ - click: async (event) => { - event.preventDefault(); - const clockKey = getClockKeyFromEvent(event); - clockKey.spawnPositionDragger(game.eunoblades.Director.clockKeySection$); - } - }); - clockKeyControls$.find("[data-action=\"delete-clock-key\"]").on({ - click: async (event) => { - event.preventDefault(); - await getClockKeyFromEvent(event).delete(game.eunoblades.ClockKeys); - } - }); - clockKeyControls$.find("[data-action=\"add-key-to-scene\"]").on({ - click: async (event) => { - event.preventDefault(); - await getClockKeyFromEvent(event).addToScene(this.document.targetSceneID); - } - }); - clockKeyControls$.find("[data-action=\"remove-key-from-scene\"]").on({ - click: async (event) => { - event.preventDefault(); - await getClockKeyFromEvent(event).removeFromScene(this.document.targetSceneID); - } - }); - clockKeyControls$.find("[data-action=\"add-clock-to-key\"]").on({ - click: async (event) => { - event.preventDefault(); - await getClockKeyFromEvent(event).addClock(); - } - }); - clockKeyControls$.find("input.clock-key-input:not([readonly])").on({ - change: async (event) => { - event.preventDefault(); - const input$ = $(event.currentTarget); - const inputVal = input$.val(); - if (typeof inputVal === "string") { - getClockKeyFromEvent(event).updateTarget(input$.data("targetProp"), inputVal); - clockKeyControls$.find("input.clock-key-input").val(inputVal); - } - } - }); - // #endregion - // #endregion - // #region *** CLOCKS *** ~ - const clockControls$ = html.find(".clock-control-flipper"); - // #region isOnDisplay === TRUE OR FALSE (Conditional Animation Checks Required) ~ - clockControls$.find("[data-action=\"toggle-visible\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const [clockKey, clock] = getClockFromEvent(event); - const isVisible = !clock.isVisible; - clock.updateTarget("isVisible", isVisible); - // If clock key is on display (in scene & visible), sent out animation socket calls - if (clockKey.isInScene() && clockKey.isVisible) { - if (isVisible) { - clock.reveal_SocketCall(ClockDisplayContext.overlay); - } - else { - clock.hide_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-visible\"] i") - .toggleClass("fa-eye") - .toggleClass("fa-eye-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - clockControls$.find("[data-action=\"toggle-active\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const [clockKey, clock] = getClockFromEvent(event); - const isActive = !clock.isActive; - clock.updateTarget("isActive", isActive); - // If clock AND clock key is on display (in scene & visible), sent out animation socket calls - if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) { - if (isActive) { - clock.activate_SocketCall(ClockDisplayContext.overlay); - } - else { - clock.deactivate_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-active\"] i") - .toggleClass("fa-bolt") - .toggleClass("fa-bolt-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - clockControls$.find("[data-action=\"toggle-name-visibility\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const clock = getClockFromEvent(event)[1]; - const isNameVisible = !clock.isNameVisible; - clock.updateTarget("isNameVisible", isNameVisible); - // If clock is on display (in scene & visible), sent out animation socket calls - if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) { - if (isNameVisible) { - clock.fadeInClockName_SocketCall(ClockDisplayContext.overlay); - } - else { - clock.fadeOutClockName_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-name-visibility\"] i") - .toggleClass("fa-signature") - .toggleClass("fa-signature-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - clockControls$.find("[data-action=\"toggle-highlight\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const [clockKey, clock] = getClockFromEvent(event); - const isHighlighted = !clock.isHighlighted; - clock.updateTarget("isHighlighted", isHighlighted); - // If clock is on display (in scene & visible), sent out animation socket calls - if (clock.parentKey.isInScene() && clock.parentKey.isVisible && clock.isVisible) { - if (isHighlighted) { - clock.highlight_SocketCall(ClockDisplayContext.overlay); - } - else { - clock.unhighlight_SocketCall(ClockDisplayContext.overlay); - } - } - // Toggle class names on icon - control$.find("[data-action=\"toggle-highlight\"] i") - .toggleClass("fa-lightbulb") - .toggleClass("fa-lightbulb-slash") - .toggleClass("fa-solid") - .toggleClass("fa-regular"); - } - }); - }); - // #endregion - // #region isOnDisplay === TRUE ~ - clockControls$.find("[data-action=\"change-segments\"]") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - click: async (event) => { - event.preventDefault(); - const [clockKey, clock] = getClockFromEvent(event); - const delta = U.pInt($(event.currentTarget).data("value")); - const finalVal = U.gsap.utils.clamp(0, clock.max, clock.value + delta); - if (delta > 0) { - clock.fillSegments(delta, true); - } - else { - clock.clearSegments(Math.abs(delta), true); - } - control$.find("select.clock-select-value").val(finalVal); - clock.changeSegments_SocketCall(ClockDisplayContext.overlay, clock.value, finalVal); - } - }); - }); - // #endregion - // #region isOnDisplay === FALSE ~ - clockControls$.find("select.clock-control-select") - .each((i, elem) => { - const elem$ = $(elem); - if (elem$.hasClass("clock-select-color")) { - // this.setSelectColor(elem$); - } - }) - .on({ - change: (event) => { - event.preventDefault(); - const select$ = $(event.currentTarget); - const value = select$.data("dtype") === "number" - ? U.pInt(select$.val()) - : select$.val(); - const prop = select$.data("targetProp"); - getClockFromEvent(event)[1].updateTarget(prop, value); - if (prop === "color" && typeof value === "string" && value in ClockColor) { - this.setSelectColor(select$, value); - } - } - }); - clockControls$.find("input.clock-input:not([readonly])") - .each((i, elem) => { - const elem$ = $(elem); - const control$ = elem$.closest(".clock-control-flipper"); - elem$.on({ - change: (event) => { - event.preventDefault(); - const input$ = $(event.currentTarget); - const inputVal = input$.val(); - if (typeof inputVal === "string") { - getClockFromEvent(event)[1].updateTarget(input$.data("targetProp"), inputVal); - control$.find("input.clock-input").val(inputVal); - } - } - }); - }); - clockControls$.find("[data-action=\"delete-clock\"]").on({ - click: async (event) => { - event.preventDefault(); - await getClockFromEvent(event)[1].delete(); - } - }); - // #endregion - // #endregion - } -} -export default BladesClockKeeperSheet; diff --git a/module/sheets/item/BladesGMTrackerSheet.js b/module/sheets/item/BladesGMTrackerSheet.js deleted file mode 100644 index b8521ea2..00000000 --- a/module/sheets/item/BladesGMTrackerSheet.js +++ /dev/null @@ -1,111 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import { BladesActorType, BladesPhase } from "../../core/constants.js"; -import BladesItemSheet from "./BladesItemSheet.js"; -import BladesActor from "../../BladesActor.js"; -import BladesPC from "../../documents/actors/BladesPC.js"; -export var BladesTipContext; -(function (BladesTipContext) { - BladesTipContext["DiceRoll"] = "DiceRoll"; - BladesTipContext["Combat"] = "Combat"; - BladesTipContext["General"] = "General"; -})(BladesTipContext || (BladesTipContext = {})); -class BladesTipGenerator { - static Test(pcActor) { - if (BladesActor.IsType(pcActor, BladesActorType.pc)) { - return pcActor; - } - return undefined; - } - testActor = new BladesPC({ name: "blah", type: "pc" }); - static get Tips() { - return { - [BladesTipContext.DiceRoll]: [], - [BladesTipContext.Combat]: [ - "Every combat encounter should advance the main plot, or else it's filler.", - "Inject dialogue into combat encounters, especially from important adversaries.", - "Combat encounters should be a challenge, but not a slog. Don't be afraid to end them early.", - "Infiltrate/Rescue/Destroy: Use these as additional/secondary goals in combat encounters.", - "Tell the next player in the initiative order that they're on deck.", - "Don't trigger combats automatically: Use alternate objectives to incite the players to fight, giving them agency.", - "Add another layer by drawing focus to collateral effects of the combat: a fire, a hostage, a collapsing building, innocents in danger" - ], - [BladesTipContext.General]: [ - "Rolling the dice always means SOMETHING happens.", - "Jump straight to the action; don't waste time on establishing scenes or filler.", - "Invoke elements of characters' backstories or beliefs to make any scene more personal." - ] - }; - } - tipContext; - constructor(tipContext) { - this.tipContext = tipContext; - } -} -class BladesGMTrackerSheet extends BladesItemSheet { - // static Get() { return game.eunoblades.Tracker as BladesGMTracker; } - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "item", "gm-tracker"], - template: "systems/eunos-blades/templates/items/gm_tracker-sheet.hbs", - width: 700, - height: 970 - }); - } - static async Initialize() { - Items.registerSheet("blades", BladesGMTrackerSheet, { types: ["gm_tracker"], makeDefault: true }); - return loadTemplates([ - "systems/eunos-blades/templates/items/gm_tracker-sheet.hbs" - ]); - } - async activateListeners(html) { - super.activateListeners(html); - } - async _onSubmit(event, params = {}) { - const prevPhase = this.item.system.phase; - const submitData = await super._onSubmit(event, params); - const newPhase = this.item.system.phase; - let isForcingRender = true; - if (prevPhase !== newPhase) { - switch (prevPhase) { - case BladesPhase.CharGen: { - break; - } - case BladesPhase.Freeplay: { - break; - } - case BladesPhase.Score: { - isForcingRender = false; - game.actors.filter((actor) => BladesActor.IsType(actor, BladesActorType.pc)) - .forEach((actor) => actor.clearLoadout()); - break; - } - case BladesPhase.Downtime: { - break; - } - default: break; - } - switch (newPhase) { - case BladesPhase.CharGen: { - break; - } - case BladesPhase.Freeplay: { - break; - } - case BladesPhase.Score: { - break; - } - case BladesPhase.Downtime: { - break; - } - default: break; - } - } - if (isForcingRender) { - game.actors.filter((actor) => actor.type === BladesActorType.pc) - .forEach((actor) => actor.sheet?.render()); - } - return submitData; - } -} -export default BladesGMTrackerSheet; -export { BladesTipGenerator }; diff --git a/module/sheets/item/BladesItemSheet.js b/module/sheets/item/BladesItemSheet.js deleted file mode 100644 index 750d1cec..00000000 --- a/module/sheets/item/BladesItemSheet.js +++ /dev/null @@ -1,417 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import C, { BladesItemType, BladesPhase, Factor } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import G, { ApplyTooltipAnimations } from "../../core/gsap.js"; -import BladesItem from "../../BladesItem.js"; -import BladesActiveEffect from "../../documents/BladesActiveEffect.js"; -// import {ApplyClockListeners} from "../../classes/BladesClocks.js"; -/* eslint-enable @typescript-eslint/no-unused-vars */ -import Tags from "../../core/tags.js"; -class BladesItemSheet extends ItemSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "item"], - width: 560, - height: 500, - tabs: [{ navSelector: ".sheet-tabs", contentSelector: ".sheet-body", initial: "description" }] - }); - } - /* -------------------------------------------- */ - // constructor(item: BladesItem, options: Partial = {}) { - // options.classes = [...options.classes ?? [], "eunos-blades", "sheet", "item", item.type]; - // super(item, options); - // } - // override async getData() { - getData() { - const context = super.getData(); - const sheetData = { - cssClass: this.item.type, - editable: this.options.editable, - isGM: (game.eunoblades.Tracker?.system.is_spoofing_player ? false : Boolean(game.user.isGM)), - isEmbeddedItem: Boolean(this.item.parent), - item: this.item, - system: this.item.system, - tierTotal: this.item.getFactorTotal(Factor.tier) > 0 ? U.romanizeNum(this.item.getFactorTotal(Factor.tier)) : "0", - activeEffects: Array.from(this.item.effects) - }; - const typedItemData = this._getTypedItemData[this.item.type]; - if (typedItemData) { - return typedItemData({ ...context, ...sheetData }); - } - return { - ...context, - ...sheetData - }; - } - _getTypedItemData = { - [BladesItemType.ability]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.ability)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.background]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.background)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.clock_keeper]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.clock_keeper)) { - return undefined; - } - const sheetData = { - phases: Object.values(BladesPhase) - }; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.cohort_gang]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.cohort_gang, BladesItemType.cohort_expert)) { - return undefined; - } - context.tierTotal = this.item.system.quality > 0 ? U.romanizeNum(this.item.system.quality) : "0"; - context.system.subtypes ??= {}; - context.system.elite_subtypes ??= {}; - const sheetData = { - tierData: { - class: "comp-tier comp-vertical comp-teeth", - dotline: { - data: this.item.system.tier, - target: "system.tier.value", - iconEmpty: "dot-empty.svg", - iconEmptyHover: "dot-empty-hover.svg", - iconFull: "dot-full.svg", - iconFullHover: "dot-full-hover.svg" - } - } - }; - sheetData.edgeData = Object.fromEntries(Object.values(context.system.edges ?? []) - .filter((edge) => /[A-Za-z]/.test(edge)) - .map((edge) => [edge.trim(), C.EdgeTooltips[edge]])); - sheetData.flawData = Object.fromEntries(Object.values(context.system.flaws ?? []) - .filter((flaw) => /[A-Za-z]/.test(flaw)) - .map((flaw) => [flaw.trim(), C.FlawTooltips[flaw]])); - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.cohort_expert]: (context) => { - const typedItemData = this._getTypedItemData[BladesItemType.cohort_gang]; - if (!typedItemData) { - throw new Error(`No data for type ${this.item.type}`); - } - return typedItemData(context); - }, - [BladesItemType.crew_ability]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.crew_ability)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.crew_reputation]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.crew_reputation)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.crew_playbook]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.crew_playbook)) { - return undefined; - } - if (context.isGM) { - const expClueData = {}; - [...Object.values(context.system.experience_clues ?? []).filter((clue) => /[A-Za-z]/.test(clue)), " "].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; }); - context.system.experience_clues = expClueData; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.crew_upgrade]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.crew_upgrade)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.feature]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.feature)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.gm_tracker]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.gm_tracker)) { - return undefined; - } - const sheetData = { - phase: this.item.system.phase, - phases: Object.values(BladesPhase) - }; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.heritage]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.heritage)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.gear]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.gear)) { - return undefined; - } - const sheetData = { - tierData: { - class: "comp-tier comp-vertical comp-teeth", - label: "Quality", - labelClass: "filled-label full-width", - dotline: { - data: this.item.system.tier, - target: "system.tier.value", - iconEmpty: "dot-empty.svg", - iconEmptyHover: "dot-empty-hover.svg", - iconFull: "dot-full.svg", - iconFullHover: "dot-full-hover.svg" - } - } - }; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.playbook]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.playbook)) { - return undefined; - } - if (context.isGM) { - const expClueData = {}; - [...Object.values(context.system.experience_clues ?? []).filter((clue) => /[A-Za-z]/.test(clue)), " "].forEach((clue, i) => { expClueData[(i + 1).toString()] = clue; }); - context.system.experience_clues = expClueData; - const gatherInfoData = {}; - [...Object.values(context.system.gather_info_questions ?? []).filter((question) => /[A-Za-z]/.test(question)), " "].forEach((question, i) => { gatherInfoData[(i + 1).toString()] = question; }); - context.system.gather_info_questions = gatherInfoData; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.preferred_op]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.preferred_op)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.stricture]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.stricture)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.vice]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.vice)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.ritual]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.ritual)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.design]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.design)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.location]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.location)) { - return undefined; - } - const sheetData = {}; - return { - ...context, - ...sheetData - }; - }, - [BladesItemType.score]: (context) => { - if (!BladesItem.IsType(this.item, BladesItemType.score)) { - return undefined; - } - return context; - } - }; - get template() { - const pathComps = [ - "systems/eunos-blades/templates/items" - ]; - if (C.SimpleItemTypes.includes(this.item.type)) { - pathComps.push("simple-sheet.hbs"); - } - else { - pathComps.push(`${this.item.type}-sheet.hbs`); - } - return pathComps.join("/"); - } - /* -------------------------------------------- */ - addDotlineListeners(html) { - html.find(".dotline").each((__, elem) => { - if ($(elem).hasClass("locked")) { - return; - } - const targetDoc = this.item; - const targetField = $(elem).data("target"); - const comp$ = $(elem).closest("comp"); - const curValue = U.pInt($(elem).data("value")); - $(elem) - .find(".dot") - .each((_, dot) => { - $(dot).on("click", (event) => { - event.preventDefault(); - const thisValue = U.pInt($(dot).data("value")); - if (thisValue !== curValue) { - if (comp$.hasClass("comp-coins") - || comp$.hasClass("comp-stash")) { - G.effects - .fillCoins($(dot).prevAll(".dot")) - .then(() => targetDoc.update({ [targetField]: thisValue })); - } - else { - targetDoc.update({ [targetField]: thisValue }); - } - } - }); - $(dot).on("contextmenu", (event) => { - event.preventDefault(); - const thisValue = U.pInt($(dot).data("value")) - 1; - if (thisValue !== curValue) { - targetDoc.update({ [targetField]: thisValue }); - } - }); - }); - }); - } - async activateListeners(html) { - await super.activateListeners(html); - const self = this; - Tags.InitListeners(html, this.item); - ApplyTooltipAnimations(html); - // Everything below here is only needed if the sheet is editable - if (!this.options.editable) { - return; - } - // Add dotline functionality - this.addDotlineListeners(html); - // Harm Bar Functionality for Cohorts - if (BladesItem.IsType(this.item, BladesItemType.cohort_expert, BladesItemType.cohort_gang)) { - html.find("[data-harm-click]").on({ - click: (event) => { - event.preventDefault(); - const harmLevel = U.pInt($(event.currentTarget).data("harmClick")); - if (this.item.system.harm?.value !== harmLevel) { - this.item.update({ "system.harm.value": harmLevel }); - } - }, - contextmenu: (event) => { - event.preventDefault(); - const harmLevel = Math.max(0, U.pInt($(event.currentTarget).data("harmClick")) - 1); - if (this.item.system.harm?.value !== harmLevel) { - this.item.update({ "system.harm.value": harmLevel }); - } - } - }); - } - // This is a workaround until is being fixed in FoundryVTT. - if (this.options.submitOnChange) { - html.on("change", "textarea", this._onChangeInput.bind(this)); // Use delegated listener on the form - } - html.find(".effect-control").on("click", (ev) => { - if (self.item.isOwned) { - ui.notifications?.warn(game.i18n.localize("BITD.EffectWarning")); - return; - } - BladesActiveEffect.onManageActiveEffect(ev, self.item); - }); - html.find("[data-action=\"toggle-turf-connection\"").on("click", this.toggleTurfConnection.bind(this)); - } - toggleTurfConnection(event) { - const button$ = $(event.currentTarget); - const connector$ = button$.parent(); - const turfNum = parseInt(connector$.data("index") ?? 0, 10); - const turfDir = connector$.data("dir"); - if (!turfNum || !turfDir) { - return; - } - const toggleState = connector$.hasClass("no-connect"); - const updateData = { - [`system.turfs.${turfNum}.connects.${turfDir}`]: toggleState - }; - const partner = connector$.data("partner"); - if (typeof partner === "string" && /-/.test(partner)) { - const [partnerNum, partnerDir] = partner.split("-"); - updateData[`system.turfs.${partnerNum}.connects.${partnerDir}`] = toggleState; - } - this.item.update(updateData); - } -} -export default BladesItemSheet; diff --git a/module/sheets/item/BladesProjectSheet.js b/module/sheets/item/BladesProjectSheet.js deleted file mode 100644 index 3baf3f9b..00000000 --- a/module/sheets/item/BladesProjectSheet.js +++ /dev/null @@ -1,150 +0,0 @@ -/* eslint-disable @typescript-eslint/no-unused-vars */ -import U from "../../core/utilities.js"; -import { ClockKeyDisplayMode } from "../../core/constants.js"; -import BladesItemSheet from "./BladesItemSheet.js"; -class BladesProjectSheet extends BladesItemSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "item", "project-sheet"], - template: "systems/eunos-blades/templates/items/project-sheet.hbs" - }); - } - getData() { - const context = super.getData(); - const sheetData = {}; - sheetData.presentingClock = this.presentedClock; - return { - ...context, - ...sheetData - }; - } - get presentedClock() { - const { clockKey } = this.document; - if (!clockKey) { - throw new Error(`ClockKey not initialized for Project ${this.document.name}`); - } - let focusedClockIndex; - if (U.isInt(clockKey.displayMode)) { - focusedClockIndex = clockKey.displayMode; - } - else if (clockKey.displayMode === ClockKeyDisplayMode.presentCurrentClock) { - focusedClockIndex = this.document.currentClock.index; - } - else if (clockKey.displayMode.startsWith("present")) { - focusedClockIndex = U.pInt(clockKey.displayMode.slice(7)); - } - else { - return false; - } - return this.document.clockKey.getClockByIndex(focusedClockIndex) ?? false; - } - getClockKeyComponents(html) { - const { clockKey } = this.document; - if (!clockKey) { - throw new Error(`ClockKey not initialized for Project ${this.document.name}`); - } - return { - clockKey, - keyElems$: clockKey.getElements$(html.find(".clock-key-panel")) - }; - } - switchToPresentAllClocks(clockKey, keyElems$) { - const { clocks } = keyElems$; - const timeline = clockKey.switchToMode(keyElems$, ClockKeyDisplayMode.clocks); - // If there are multiple clocks, reveal labels of visible clocks - if (clockKey.size > 1) { - clockKey.visibleClocks.forEach((clock, i) => { - const { clockLabel$ } = clocks[clock.id]; - timeline.blurReveal(clockLabel$, i === 0 - ? ">" - : "<+0.05"); - }); - } - timeline.play().then(() => { - // Change subtitle element to name of current clock - if (this._htmlContext && this.document.currentClock) { - this._htmlContext.find(".sheet-subtitle") - .attr("data-action", "current-clock-name") - .val(this.document.currentClock.name); - } - }); - } - switchToPresentClock(clockRef, clockKey, keyElems$) { - const timeline = clockKey.switchToMode(keyElems$, clockRef === ClockKeyDisplayMode.presentCurrentClock - ? clockRef - : (`present${clockRef}`), undefined, undefined, true, () => { - eLog.checkLog3("BladesProject", "Clock Switch", { clockRef, clockKey, keyElems$, htmlContext: this._htmlContext, presentedClock: this.presentedClock }); - // Change subtitle element to name of presented clock - if (this._htmlContext && this.presentedClock) { - this._htmlContext.find(".sheet-subtitle") - .attr("data-action", "presented-clock-name") - .val(this.presentedClock.name); - } - }); - // Fade out any visible label elements - timeline.to(keyElems$.container$.find(".clock-label, .clock-key-label"), { autoAlpha: 0, duration: 0.5, ease: "sine" }, 0); - timeline.play().then(); - } - activateClockKeyListeners(clockKey, keyElems$) { - eLog.checkLog2("BladesProject", "Clock Key Data", { clockKey, keyElems$ }); - const { container$ } = keyElems$; - // Activate pointer events on the container element - container$.css("pointer-events", "auto"); - container$.on("contextmenu", () => { - this.switchToPresentAllClocks(clockKey, keyElems$); - }); - // Add click listeners for player interaction to clock elements - Object.entries(keyElems$.clocks).forEach(([clockId, clockElems$]) => { - clockElems$.clockContainer$.css("pointer-events", "auto"); - clockElems$.clockContainer$.on("click", () => { - this.switchToPresentClock(clockKey.clocks.get(clockId)?.index ?? ClockKeyDisplayMode.presentCurrentClock, clockKey, keyElems$); - }); - }); - } - _htmlContext; - async activateListeners(html) { - this._htmlContext = html; - await super.activateListeners(html); - // Get clock key and rendered clock key elements - const { clockKey, keyElems$ } = this.getClockKeyComponents(html); - // Add listener for contextual clock name depending on display mode - html.find("input.sheet-subtitle") - .on({ - change: (event) => { - event.preventDefault(); - const action = $(event.currentTarget).data("action"); - eLog.checkLog3("BladesProject", "Clock Name Change", { action, value: $(event.currentTarget).val() }); - if (action === "presented-clock-name" && this.presentedClock) { - this.presentedClock.updateTarget("name", $(event.currentTarget).val()); - keyElems$.clocks[this.presentedClock.id].clockLabel$ - .text($(event.currentTarget).val()); - } - else if (action === "current-clock-name") { - this.document.clockKey.currentClock.updateTarget("name", $(event.currentTarget).val()); - keyElems$.clocks[this.document.clockKey.currentClock.id].clockLabel$ - .text($(event.currentTarget).val()); - } - clockKey.formatLabels(keyElems$); - } - }); - // Initialize clock key elements - clockKey.initElementsInContext(html); - // Activate listeners for the rendered key - this.activateClockKeyListeners(clockKey, keyElems$); - // Reveal & activate clocks - await Promise.all([ - ...clockKey.visibleClocks.map((clock) => new Promise((resolve) => { - const clockElems$ = keyElems$.clocks[clock.id]; - clock.reveal_Animation(clockElems$, () => { resolve(); }); - })), - ...clockKey.activeClocks.map((clock) => new Promise((resolve) => { - const clockElems$ = keyElems$.clocks[clock.id]; - clock.activate_Animation(clockElems$, () => { resolve(); }); - })) - ]); - // // Animate to present the currently-active clock - // clockKey.switchToMode(keyElems$, `present${this.document.currentClock.index}` as ClockKeyDisplayMode) - // .play(); - } -} -export default BladesProjectSheet; diff --git a/module/sheets/item/BladesScoreSheet.js b/module/sheets/item/BladesScoreSheet.js deleted file mode 100644 index 6605cd68..00000000 --- a/module/sheets/item/BladesScoreSheet.js +++ /dev/null @@ -1,295 +0,0 @@ -import U from "../../core/utilities.js"; -import { BladesActorType, BladesPhase, Tag, Randomizers } from "../../core/constants.js"; -import BladesItemSheet from "./BladesItemSheet.js"; -import { BladesActor } from "../../documents/BladesActorProxy.js"; -import { BladesScore } from "../../documents/BladesItemProxy.js"; -import BladesRoll, { BladesRollOpposition } from "../../classes/BladesRoll.js"; -/* #region BladesTipGenerator */ -export var BladesTipContext; -(function (BladesTipContext) { - BladesTipContext["DiceRoll"] = "DiceRoll"; - BladesTipContext["Combat"] = "Combat"; - BladesTipContext["General"] = "General"; -})(BladesTipContext || (BladesTipContext = {})); -class BladesTipGenerator { - static get Tips() { - return { - [BladesTipContext.DiceRoll]: [], - [BladesTipContext.Combat]: [ - "Every combat encounter should advance the main plot, or else it's filler.", - "Inject dialogue into combat encounters, especially from important adversaries.", - "Combat encounters should be a challenge, but not a slog. Don't be afraid to end them early.", - "Infiltrate/Rescue/Destroy: Use these as additional/secondary goals in combat encounters.", - "Tell the next player in the initiative order that they're on deck.", - "Don't trigger combats automatically: Use alternate objectives to incite the players to fight, giving them agency.", - "Add another layer by drawing focus to collateral effects of the combat: a fire, a hostage, a collapsing building, innocents in danger" - ], - [BladesTipContext.General]: [ - "Rolling the dice always means SOMETHING happens.", - "Jump straight to the action; don't waste time on establishing scenes or filler.", - "Invoke elements of characters' backstories or beliefs to make any scene more personal." - ] - }; - } - tipContext; - constructor(tipContext) { - this.tipContext = tipContext; - } -} -/* #endregion */ -class BladesScoreSheet extends BladesItemSheet { - static get defaultOptions() { - return foundry.utils.mergeObject(super.defaultOptions, { - classes: ["eunos-blades", "sheet", "item", "score-sheet"], - template: "systems/eunos-blades/templates/items/score-sheet.hbs", - width: 900, - submitOnChange: false, - height: 970 - }); - } - async generateRandomizerData(category) { - // Generate full set of random data. - const randomData = { - Bargains: Object.fromEntries(Object.entries(U.sample(Randomizers.GM.Bargains - .filter((bData) => !Object.values(this.document.system.randomizers.Bargains) - .some((_bData) => _bData.name === bData.name || _bData.effect === bData.effect)), 3, true, (e, a) => a - .filter((_e) => e.category === _e.category).length === 0)) - .map(([k, v]) => { - k = `${k}`; - Object.assign(v, { notes: "" }); - return [k, v]; - })), - Obstacles: Object.fromEntries(Object.entries(U.sample(Randomizers.GM.Obstacles - .filter((bData) => !Object.values(this.document.system.randomizers.Obstacles) - .some((_bData) => _bData.name === bData.name || _bData.desc === bData.desc)), 3, true, (e, a) => a - .filter((_e) => e.category === _e.category).length === 0)) - .map(([k, v]) => { - k = `${k}`; - Object.assign(v, { notes: "" }); - return [k, v]; - })), - NPCs: Object.fromEntries(Object.entries(U.sample(Randomizers.GM.NPCs - .filter((bData) => !Object.values(this.document.system.randomizers.NPCs) - .some((_bData) => _bData.name === bData.name - || _bData.description === bData.description)), 3, true, (e, a) => a - .filter((_e) => e.arena === _e.arena).length === 0)) - .map(([k, v]) => { - k = `${k}`; - Object.assign(v, { notes: "" }); - return [k, v]; - })), - Scores: Object.fromEntries(Object.entries(U.sample(Randomizers.GM.Scores - .filter((bData) => !Object.values(this.document.system.randomizers.Scores) - .some((_bData) => _bData.name === bData.name || _bData.desc === bData.desc)), 3, true, (e, a) => a - .filter((_e) => e.category === _e.category).length === 0)) - .map(([k, v]) => { - k = `${k}`; - Object.assign(v, { notes: "" }); - return [k, v]; - })) - }; - // If category specified, replace all other categories with stored data - if (category) { - Object.keys(randomData) - .filter((cat) => cat !== category) - .forEach((cat) => { - const _cat = cat; - randomData[_cat] = this.document.system.randomizers[_cat]; - }); - } - // Combine locked data stored in system with randomly-generated data - const finalRandomData = { - Bargains: {}, - Obstacles: {}, - NPCs: {}, - Scores: {} - }; - // Iterate through all randomizer categories. If system entry isLocked, use that, or use newly-generated data - Object.keys(randomData).forEach((cat) => { - const _cat = cat; - Object.keys(randomData[_cat]).forEach((index) => { - if (this.document.system.randomizers?.[_cat][index].isLocked) { - finalRandomData[_cat][index] = this.document.system.randomizers[_cat][index]; - } - else { - finalRandomData[_cat][index] = randomData[_cat][index]; - } - }); - }); - // Overwrite stored data with newly generated & merged randomizer data - await this.document.update({ "system.randomizers": finalRandomData }); - } - getData() { - const context = super.getData(); - const sheetData = {}; - // Get player characters, assign simplified actionData that I probably should have coded them with from the start - sheetData.playerCharacters = BladesActor.GetTypeWithTags(BladesActorType.pc, Tag.PC.ActivePC) - .map((pc) => { - return Object.assign(pc, { - actionData: Object.fromEntries(Object.entries(pc.system.attributes) - .map(([attrName, attrData]) => { - return [ - attrName, - Object.fromEntries(Object.entries(attrData) - .map(([actionName, actionData]) => { - return [ - U.uCase(actionName).slice(0, 3), - actionData - ]; - })) - ]; - })) - }); - }); - // Prune system data for blank/empty opposition entries - const validOppositions = {}; - for (const [id, data] of Object.entries(context.system.oppositions)) { - if (!data.rollOppName && !data.rollOppSubName) { - continue; - } - validOppositions[id] = data; - } - context.system.oppositions = validOppositions; - return { - ...context, - ...sheetData - }; - } - _toggleRandomizerLock(event) { - const elem$ = $(event.currentTarget); - const elemCat = elem$.data("category"); - const elemIndex = `${elem$.data("index")}`; - const elemValue = elem$.data("value"); - if (`${elemValue}` === "true") { - this.document.update({ [`system.randomizers.${elemCat}.${elemIndex}.isLocked`]: false }); - } - else { - this.document.update({ [`system.randomizers.${elemCat}.${elemIndex}.isLocked`]: true }); - } - } - _selectImage(event) { - const elem$ = $(event.currentTarget); - const imageNum = elem$.data("imgNum"); - this.document.update({ "system.imageSelected": imageNum }); - } - _deselectOrDeleteImage(event) { - const elem$ = $(event.currentTarget); - const imageNum = elem$.data("imgNum"); - if (this.document.system.imageSelected === imageNum) { - this.document.update({ "system.-=imageSelected": null }); - return; - } - const images = { ...this.document.system.images }; - this.document.update({ "system.-=images": null }).then(() => this.document.update({ - "system.images": Object.fromEntries(Object.entries(Object.values(images) - .filter((_, i) => U.pInt(imageNum) !== i))) - })); - } - _addImage() { - U.displayImageSelector((path) => { - const imgIndex = U.objSize(this.document.system.images); - return this.document.update({ [`system.images.${imgIndex}`]: path }); - }, "systems/eunos-blades/assets", this.position); - } - _selectRollOpposition(event) { - eLog.checkLog3("Select Roll Opposition", { event }); - const elem$ = $(event.currentTarget); - const oppId = elem$.data("oppId"); - this.document.update({ "system.oppositionSelected": oppId }); - if (BladesScore.Active?.id === this.document.id && BladesRoll.Active) { - BladesRoll.Active.rollOpposition = new BladesRollOpposition(BladesRoll.Active, this.document.system.oppositions[oppId]); - } - } - _triggerRandomize(event) { - const elem$ = $(event.currentTarget); - const category = elem$.data("category"); - if (category && category in Randomizers.GM) { - this.generateRandomizerData(category); - } - else { - this.generateRandomizerData(); - } - } - async _updateGMNotesOnPC(event) { - const elem$ = $(event.currentTarget); - const actor = BladesActor.Get(elem$.data("id")); - if (!actor) { - throw new Error(`Unable to retrieve actor with id '${elem$.data("id")}'`); - } - const updateText = event.currentTarget.innerHTML; - eLog.checkLog3("scoreSheet", "Retrieved Text, Updating ...", { updateText }); - await actor.update({ "system.gm_notes": updateText }); - eLog.checkLog3("scoreSheet", "Updated!", { gm_notes: actor.system.gm_notes }); - } - async activateListeners(html) { - super.activateListeners(html); - html.find("[data-action='select-image']").on({ - click: this._selectImage.bind(this), - contextmenu: this._deselectOrDeleteImage.bind(this) - }); - html.find("[data-action='add-image']").on({ - click: this._addImage.bind(this) - }); - html.find(".roll-opposition-name").on({ - dblclick: this._selectRollOpposition.bind(this) - }); - html.find(".toggle-lock").on({ - click: this._toggleRandomizerLock.bind(this) - }); - html.find("[data-action='randomize'").on({ - click: this._triggerRandomize.bind(this) - }); - html.find("textarea.pc-summary-notes-body").on({ - change: this._updateGMNotesOnPC.bind(this) - }); - } - async _onSubmit(event, params = {}) { - // eLog.checkLog3("scoreSheet", "_onSubmit()", {event, params, elemText: event.currentTarget.innerHTML}); - let isForcingRender = true; - const prevPhase = this.item.system.phase; - const submitData = await super._onSubmit(event, params); - const newPhase = this.item.system.phase; - if (prevPhase !== newPhase) { - switch (prevPhase) { - case BladesPhase.CharGen: { - break; - } - case BladesPhase.Freeplay: { - break; - } - case BladesPhase.Score: { - isForcingRender = false; - game.actors.filter((actor) => BladesActor.IsType(actor, BladesActorType.pc)) - .forEach((actor) => actor.clearLoadout()); - break; - } - case BladesPhase.Downtime: { - break; - } - // No default - } - switch (newPhase) { - case BladesPhase.CharGen: { - break; - } - case BladesPhase.Freeplay: { - break; - } - case BladesPhase.Score: { - break; - } - case BladesPhase.Downtime: { - break; - } - // No default - } - } - if (isForcingRender) { - game.actors.filter((actor) => actor.type === BladesActorType.pc) - .forEach((actor) => actor.sheet?.render()); - } - return submitData; - } -} -export { BladesTipGenerator }; -export default BladesScoreSheet; diff --git a/module/sheets/roll/BladesConsequence.js b/module/sheets/roll/BladesConsequence.js deleted file mode 100644 index 6f40b58a..00000000 --- a/module/sheets/roll/BladesConsequence.js +++ /dev/null @@ -1,527 +0,0 @@ -/* no-dupe-class-members */ -import C, { BladesActorType, AttributeTrait, ConsequenceType, RollResult, RollType, Position, Effect, RollPhase } from "../../core/constants.js"; -import U from "../../core/utilities.js"; -import BladesRoll, { BladesRollPrimary } from "../../BladesRoll.js"; -class BladesConsequence { - static get None() { - return { - id: randomID(), - name: "", - type: ConsequenceType.None, - isSelected: true, - isVisible: true - }; - } - static GetActiveRollChatID() { - return Array.from(game.messages).filter((msg) => $(msg.content ?? "").data("chat-id")).pop()?.id ?? undefined; - } - static ApplyChatListeners(html) { - const html$ = $(html); - const roll$ = html$.find(".blades-roll"); - if (!roll$[0]) { - return; - } - // Add classes to the top chat message defining the roll type - if (roll$.hasClass("roll-type-action")) { - roll$.closest(".chat-message").addClass("action-roll"); - } - else if (roll$.hasClass("roll-type-resistance")) { - roll$.closest(".chat-message").addClass("resistance-roll"); - } - else if (roll$.hasClass("roll-type-fortune")) { - roll$.closest(".chat-message").addClass("fortune-roll"); - } - else if (roll$.hasClass("roll-type-indulgevice")) { - roll$.closest(".chat-message").addClass("indulgevice-roll"); - } - // If this message is an action roll result AND there are unresolved consequences, add 'unresolved-action-roll' class. - if (roll$.hasClass("roll-type-action") - && Array.from(roll$.find(".comp.consequence-display-container:not(.consequence-accepted)")).length >= 1) { - roll$.closest(".chat-message").addClass("unresolved-action-roll"); - } - else { - roll$.closest(".chat-message").removeClass("unresolved-action-roll"); - } - // If this message is the last one, add 'active-chat-roll' class and remove it from all others - if (BladesConsequence.GetActiveRollChatID() === roll$.data("chatId")) { - $(document).find(".chat-message").removeClass("active-chat-roll"); - roll$.closest(".chat-message").addClass("active-chat-roll"); - } - else { - roll$.closest(".chat-message").removeClass("active-chat-roll"); - } - const rollPhase = roll$.data("rollPhase"); - if (rollPhase !== RollPhase.AwaitingConsequences) { - return; - } - html$.find("[data-action*='-consequence']").on({ - click: async (event) => { - const csqElem$ = $(event.currentTarget); - const action = csqElem$.data("action"); - const csq = BladesConsequence.GetFromCsqElem(csqElem$); - switch (action) { - case "accept-consequence": { - await csq.acceptConsequence(); - break; - } - case "resist-consequence": { - await csq.resistConsequence(); - break; - } - case "armor-consequence": { - await csq.resistArmorConsequence(); - break; - } - case "special-consequence": { - await csq.resistSpecialArmorConsequence(); - break; - } - default: - } - } - }); - } - static async GetFromID(msgID, csqID) { - const chatMessage = game.messages.get(msgID); - if (chatMessage) { - if (csqID) { - return BladesConsequence.GetFromChatMessage(chatMessage, csqID); - } - return BladesConsequence.GetFromChatMessage(chatMessage); - } - return undefined; - } - static GetFromCsqElem(csqElem) { - csqElem = $(csqElem); - const csq$ = csqElem.closest(".comp.consequence-display-container"); - const chatRoll$ = csq$.closest(".blades-roll"); - const chatID = chatRoll$.data("chat-id"); - const rollID = chatRoll$.data("roll-id"); - const userID = chatRoll$.data("user-id"); - const primaryID = chatRoll$.data("primary-id"); - const primaryType = chatRoll$.data("primary-type"); - const position = chatRoll$.data("position"); - const effect = chatRoll$.data("effect"); - const result = chatRoll$.data("result"); - function getBaseData(c$) { - const id = c$.data("csq-id"); - const name = c$.find(".consequence-name.base-consequence").text(); - const type = c$.data("csq-type") ?? ConsequenceType.None; - return { id, name, type }; - } - function getResistableData(c$, csqClass) { - // There will only ever be three possible resistable consequences, all marked out similarly - // For chained resistances, a dialog popup should appear to the GM when the roll is sent to chat. - // First, check for consequence's existence by looking for its button - const rCsqButton$ = c$.find(`.consequence-button-container.${csqClass}`); - if (!rCsqButton$[0]) { - return {}; - } - const [rCsqRef] = csqClass.split(/-/); - const baseData = getBaseData(c$); - const resistData = { - id: rCsqButton$.data("csq-id"), - chatID, userID, rollID, primaryID, primaryType, - position, effect, result, - name: c$.find(`.consequence-name.${csqClass}`).text(), - type: c$.data(`${rCsqRef}-type`) ?? ConsequenceType.None - }; - // If we're looking for a 'resist-consequence', we need an attribute trait and value - if (csqClass.startsWith("resist")) { - const attrMsg$ = c$.find(".consequence-resist-attribute.resist-consequence"); - return { - ...baseData, - chatID, userID, rollID, primaryID, primaryType, - position, effect, result, - resistTo: resistData, - attribute: attrMsg$.text().trim().toLowerCase(), - attributeVal: Array.from(attrMsg$.find(".full-dot")).length - }; - } - else if (csqClass.startsWith("special")) { - return { - ...baseData, - chatID, userID, rollID, primaryID, primaryType, - position, effect, result, - specialTo: resistData, - footerMsg: c$.find(`.consequence-footer-container .${csqClass}`)?.text() - }; - } - else if (csqClass.startsWith("armor")) { - return { - ...baseData, - chatID, userID, rollID, primaryID, primaryType, - position, effect, result, - armorTo: resistData - }; - } - return {}; - } - return new BladesConsequence({ - ...getBaseData(csq$), - ...getResistableData(csq$, "resist-consequence"), - ...getResistableData(csq$, "armor-consequence"), - ...getResistableData(csq$, "special-consequence"), - isAccepted: csq$.hasClass("consequence-accepted") - }); - } - static async GetFromChatMessage(message, csqID) { - const html$ = $(await message.getHTML()); - const bCsqs = []; - html$.find(".blades-roll .consequence-container .comp.consequence-display-container:not(.consequence-accepted)").each((_, elem) => { - bCsqs.push(BladesConsequence.GetFromCsqElem(elem)); - }); - if (csqID) { - return bCsqs.find((csq) => csq.id === csqID); - } - return bCsqs; - } - _id; - get id() { return this._id; } - _rollID; - _primaryID; - _primaryType; - _primaryDoc; - _chatMessage; - _user; - _name; - get name() { return this._name; } - _type; - get type() { return this._type; } - get typeDisplay() { return C.ConsequenceDisplay[this.type]; } - get icon() { return C.ConsequenceIcons[this.type]; } - _position; - _effect; - _result; - _resistTo; - get resistToData() { - if (!this._resistTo) { - return undefined; - } - return { - id: this._resistTo.id, - chatID: this._chatMessage.id, - userID: this._user.id, - rollID: this._rollID, - primaryID: this._primaryID, - primaryType: this._primaryType, - position: this._position, - effect: this._effect, - result: this._result, - name: this._resistTo.name, - type: this._resistTo.type, - typeDisplay: this._resistTo.typeDisplay, - icon: this._resistTo.icon - }; - } - _attribute; - get attribute() { return this._attribute; } - _attributeVal; - get attributeVal() { return this._attributeVal; } - _armorTo; - _specialTo; - _isAccepted; - constructor(data) { - const { id, chatID, userID, rollID, primaryID, primaryType, name, type, position, effect, result, attribute, attributeVal, resistTo, armorTo, specialTo, isAccepted } = data; - eLog.checkLog3("bladesConsequence", "[new BladesConsequence]", { - id, chatID, userID, rollID, primaryID, primaryType, - name, - type, - position, effect, result, - attribute, attributeVal, resistTo, - armorTo, - specialTo, - isAccepted - }); - if (typeof id !== "string") { - throw new Error("[new BladesConsequence] Missing 'id' in constructor data object."); - } - if (typeof rollID !== "string") { - throw new Error("[new BladesConsequence] Missing 'rollID' in constructor data object."); - } - if (typeof chatID !== "string") { - throw new Error("[new BladesConsequence] Missing 'chatID' in constructor data object."); - } - const chatMessage = game.messages.get(chatID); - if (!(chatMessage instanceof ChatMessage)) { - throw new Error(`[new BladesConsequence] No chat message with id '${chatID}' found.`); - } - if (typeof userID !== "string") { - throw new Error("[new BladesConsequence] Missing 'userID' in constructor data object."); - } - const user = game.users.get(userID); - if (!(user instanceof User)) { - throw new Error(`[new BladesConsequence] No user with id '${userID}' found.`); - } - if (typeof primaryID !== "string") { - throw new Error("[new BladesConsequence] Missing 'primaryID' in constructor data object."); - } - if (typeof primaryType !== "string") { - throw new Error("[new BladesConsequence] Missing 'primaryType' in constructor data object."); - } - const primaryCollection = primaryType in BladesActorType ? game.actors : game.items; - const primaryDoc = primaryCollection.get(primaryID); - if (!(BladesRollPrimary.IsDoc(primaryDoc))) { - throw new Error(`[new BladesConsequence] No primary document with id '${primaryID}' of type '${primaryType}' found.`); - } - if (typeof name !== "string") { - throw new Error("[new BladesConsequence] Missing 'name' in constructor data object."); - } - if (!(typeof type === "string" && type in ConsequenceType)) { - throw new Error("[new BladesConsequence] Missing 'type' in constructor data object."); - } - if (!(typeof position === "string" && position in Position)) { - throw new Error("[new BladesConsequence] Missing 'position' in constructor data object."); - } - if (!(typeof effect === "string")) { - throw new Error("[new BladesConsequence] Missing 'effect' in constructor data object."); - } - if (!(typeof result === "string" && [RollResult.partial, RollResult.fail].includes(result))) { - throw new Error("[new BladesConsequence] Missing 'result' in constructor data object."); - } - this._id = id; - this._rollID = rollID; - this._chatMessage = chatMessage; - this._user = user; - this._name = name; - this._primaryID = primaryID; - this._primaryType = primaryType; - this._primaryDoc = new BladesRollPrimary(undefined, primaryDoc); - this._type = type; - this._position = position; - this._effect = effect; - this._result = result; - this._isAccepted = Boolean(isAccepted); - if (resistTo) { - if (!(typeof attribute === "string" && attribute in AttributeTrait)) { - throw new Error("[new BladesConsequence] Missing 'attribute' in constructor data object."); - } - this._attribute = attribute; - if (typeof attributeVal !== "number") { - throw new Error("[new BladesConsequence] Missing 'attributeVal' in constructor data object."); - } - this._attributeVal = attributeVal; - if (!resistTo.id) { - throw new Error("[new BladesConsequence] Missing 'resistTo.id' in constructor data object."); - } - if (!resistTo.type) { - throw new Error("[new BladesConsequence] Missing 'resistTo.type' in constructor data object."); - } - if (!resistTo.name && resistTo.type !== ConsequenceType.None) { - throw new Error("[new BladesConsequence] Missing 'resistTo.name' in constructor data object."); - } - this._resistTo = new BladesConsequence(resistTo); - } - if (armorTo) { - if (!armorTo.id) { - throw new Error("[new BladesConsequence] Missing 'armorTo.id' in constructor data object."); - } - if (!armorTo.type) { - throw new Error("[new BladesConsequence] Missing 'armorTo.type' in constructor data object."); - } - if (!armorTo.name && armorTo.type !== ConsequenceType.None) { - throw new Error("[new BladesConsequence] Missing 'armorTo.name' in constructor data object."); - } - this._armorTo = new BladesConsequence(armorTo); - } - if (specialTo) { - if (!specialTo.id) { - throw new Error("[new BladesConsequence] Missing 'specialTo.id' in constructor data object."); - } - if (!specialTo.type) { - throw new Error("[new BladesConsequence] Missing 'specialTo.type' in constructor data object."); - } - if (!specialTo.name && specialTo.type !== ConsequenceType.None) { - throw new Error("[new BladesConsequence] Missing 'specialTo.name' in constructor data object."); - } - this._specialTo = new BladesConsequence(specialTo); - } - game.eunoblades.Consequences.set(this.id, this); - } - async applyConsequenceToPrimary() { - // If HARM -> Apply harm to actor. - if (/Harm/.exec(this._type)) { - await this._primaryDoc.applyHarm(U.pInt(this._type.substring(this._type.length - 1)), this._name); - // If WORSE POSITION -> Add flag to user to be checked on next Action roll, then cleared - } - else if (this._type === ConsequenceType.WorsePosition) { - await this._primaryDoc.applyWorsePosition(); - } - // If REDUCED EFFECT -> No change to rollPrimary. - // If COMPLICATION -> No change to rollPrimary. - // If LOST OPPORTUNITY -> No change to rollPrimary. - } - async transformToConsequence(typeRef, rollHTML) { - const transformRecord = {}; - // Create HTML for accepted version of this consequence - let csqAcceptedHTML = await renderTemplate("systems/eunos-blades/templates/components/consequence-accepted.hbs", Object.assign(this, { blockClass: "consequence-resisted" })); - transformRecord["1) csqAcceptedHTML"] = csqAcceptedHTML; - // Get the resisted consequence data according to typeRef - const rCsq = { - resist: this._resistTo, - armor: this._armorTo, - special: this._specialTo - }[typeRef]; - if (!rCsq) { - return; - } - // Get HTML for the consequence it resisted to - let csqResistedHTML = await renderTemplate("systems/eunos-blades/templates/components/consequence-accepted.hbs", rCsq); - // Add a class, identifying this ".comp.comp-consequence-display-container" as a 'sub-consequence' that resulted from resisting a worse consequence - csqResistedHTML = $(csqResistedHTML) - .addClass("sub-consequence-resisted")[0].outerHTML; - transformRecord["2) csqResistedHTML"] = csqResistedHTML; - // If roll HTML provided, extract attribute, icon, dice roll strip and stress cost message, and prepend them to sub-consequence container - /** - *
-
-
- -
-
- RESOLVE: -
-
-
-

Alistair Recovers 1 Stress

-
-
-
-
- */ - if (rollHTML) { - const rollHTML$ = $(rollHTML); - const rollDetailContainer$ = $("
").appendTo($(csqResistedHTML)); - // rollHTML$.find(".consequence-icon-img").addClass("csq-resisted").appendTo(csqHTML$); - rollHTML$.find(".trait-label").addClass("csq-resisted").appendTo(rollDetailContainer$); - rollHTML$.find(".dice-roll-strip").addClass("csq-resisted").appendTo(rollDetailContainer$); - rollHTML$.find(".resistance-cost-row").addClass("csq-resisted").appendTo(rollDetailContainer$); - csqResistedHTML = rollDetailContainer$.parent()[0].outerHTML; - transformRecord["2.2) csqResistedHTML + rollHTML"] = csqResistedHTML; - } - // Add the roll overlay - csqResistedHTML = $(csqResistedHTML).prepend($(` -
- -
`))[0].outerHTML; - transformRecord["2.3) csqResistedHTML + overlay"] = csqResistedHTML; - // Prepend the resisted consequence HTML to the accepted consequence HTML - csqAcceptedHTML = $(csqAcceptedHTML).prepend($(csqResistedHTML))[0].outerHTML; - transformRecord["3) csqAcceptedHTML + csqResistedHTML"] = csqAcceptedHTML; - // Get message HTML - const message$ = $(await this._chatMessage.getHTML()); - transformRecord["4) message$ before Replace"] = message$[0].outerHTML; - // Replace consequence with new data - message$.find(`.comp.consequence-display-container[data-csq-id='${this._id}']`) - .replaceWith(csqAcceptedHTML); - transformRecord["4.5) message$ after Replace"] = message$[0].outerHTML; - transformRecord["5) message$.find(.blades-roll) = CONTENT"] = message$.find(".blades-roll")[0].outerHTML; - await this._chatMessage.update({ content: message$.find(".blades-roll")[0].outerHTML }); - eLog.checkLog2("transformConsequence", "Transform Record", transformRecord); - } - async acceptConsequence() { - await this.applyConsequenceToPrimary(); - const message$ = $(await this._chatMessage.getHTML()).find(".blades-roll"); - eLog.checkLog2("csqAccept", "Initial Message Code", { message$, message: message$[0], outerHTML: message$[0].outerHTML }); - // If this is a Reduced Effect consequence, edit the chat message roll effect accordingly. - if (this._type === ConsequenceType.ReducedEffect) { - const curIndex = Object.values(Effect).findIndex((val) => val === this._effect); - if (curIndex >= 1) { - const newEffect = Object.values(Effect)[curIndex - 1]; - message$.find(".roll-outcome-container .roll-state-container .roll-state-effect") - .removeClass(`roll-state-effect-${this._effect}`) - .addClass(`roll-state-effect-${newEffect}`) - .text(U.tCase(newEffect)); - } - } - // Locate consequence HTML - message$.find(`.comp.consequence-display-container[data-csq-id='${this._id}']`) - // Add class to consequence container - .addClass("consequence-accepted"); - eLog.checkLog2("csqAccept", "Class Added Message Code", { message$, message: message$[0], outerHTML: message$[0].outerHTML }); - // Strip all unnecessary elements for an accepted consequence - message$.find(`.comp.consequence-display-container[data-csq-id='${this._id}']`).remove(` - .consequence-bg-image, - .consequence-interaction-pad, - .accept-consequence, - .resist-consequence, - .armor-consequence, - .special-consequence, - .consequence-footer-container - `); - eLog.checkLog2("csqAccept", "Code Stripped Message Code", { message$, message: message$[0], outerHTML: message$[0].outerHTML }); - this._isAccepted = true; - await this._chatMessage.update({ content: message$[0].outerHTML }); - } - get rollFlagData() { - // Get rollPrimaryData from archived roll flags on user document. - let rollFlagData = this._user.getFlag(C.SYSTEM_ID, "rollCollab"); - if (rollFlagData.rollID !== this._rollID) { - rollFlagData = this._user.getFlag(C.SYSTEM_ID, `rollCollabArchive.${this._rollID}`); - } - if (!rollFlagData) { - throw new Error(`Unable to locate flag data for roll id '${this._rollID}'`); - } - return rollFlagData; - } - async resistConsequence() { - eLog.checkLog3("rollCollab", `Resisting Consequence id ${this._id}`); - if (!this._resistTo || !this.resistToData) { - throw new Error(`Cannot find resistTo for resistance roll for csq id '${this._id}' in message '${this._chatMessage.id}'`); - } - // Get rollPrimaryData from archived roll flags on user document. - const rollFlagData = this.rollFlagData; - const resistConfig = { - rollType: RollType.Resistance, - rollUserID: this._user.id, - rollPrimaryData: rollFlagData.rollPrimaryData, - resistanceData: { - consequence: { - id: this.id, - name: this.name, - type: this.type, - icon: this.icon, - typeDisplay: this.typeDisplay, - attribute: this.attribute, - attributeVal: this.attributeVal, - resistTo: this.resistToData - } - } - }; - BladesRoll.NewRoll(resistConfig); - } - async applyResistedConsequence(resistType, rollHTML) { - const rCsq = { - resist: this._resistTo, - armor: this._armorTo, - special: this._specialTo - }[resistType]; - if (rCsq) { - await rCsq.applyConsequenceToPrimary(); - } - await this.transformToConsequence(resistType, rollHTML); - } - async resistArmorConsequence() { - if (this._armorTo) { - this._primaryDoc.spendArmor(); - this.applyResistedConsequence("armor", await renderTemplate("systems/eunos-blades/templates/components/consequence-accepted.hbs", Object.assign(this._armorTo, { isArmorResist: true }))); - } - } - async resistSpecialArmorConsequence() { - if (this._specialTo) { - this._primaryDoc.spendSpecialArmor(); - this.applyResistedConsequence("special", await renderTemplate("systems/eunos-blades/templates/components/consequence-accepted.hbs", Object.assign(this._specialTo, { isSpecialArmorResist: true }))); - } - } -} -export default BladesConsequence; diff --git a/package-lock.json b/package-lock.json index 5902f206..18185557 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,51 +7,58 @@ "": { "name": "eunos-blades", "version": "0.1.0", - "hasInstallScript": true, "dependencies": { "@types/yaireo__tagify": "^4.17.0", "axios": "^1.5.1", "form-data": "^4.0.0", "openai": "^4.20.0", - "tinymce": "^6.2.0", + "tinymce": "^6.7.1", "yargs": "^17.7.2" }, "devDependencies": { + "@babel/core": "^7.23.9", + "@babel/preset-env": "^7.23.9", + "@babel/preset-typescript": "^7.23.3", "@league-of-foundry-developers/foundry-vtt-types": "^9.280.0", + "@tsconfig/node21": "^21.0.1", "@types/babel__core": "^7.20.5", - "@types/jquery": "^3.5.27", - "@types/node": "^18.11.4", + "@types/jquery": "^3.5.29", + "@types/node": "^20.11.20", "@typescript-eslint/eslint-plugin": "^7.0.2", "@typescript-eslint/parser": "^7.0.2", "@yaireo/tagify": "^4.17.8", "autoprefixer": "^10.4.17", + "babel-loader": "^9.1.3", "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^12.0.2", "css-loader": "^6.10.0", + "css-minimizer-webpack-plugin": "^6.0.0", "eslint": "^8.57.0", "eslint-import-resolver-node": "^0.3.9", "eslint-plugin-etc": "^2.0.3", - "eslint-plugin-import": "^2.26", - "eslint-plugin-jsdoc": "^46.9.0", - "handlebars": "^4.7", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsdoc": "^48.2.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "handlebars": "^4.7.7", "mini-css-extract-plugin": "^2.8.0", - "postcss": "^8.4.18", + "postcss": "^8.4.35", "postcss-loader": "^8.1.0", - "postcss-scss": "^4.0.5", - "prettier": "2.7.1", + "postcss-scss": "^4.0.9", + "prettier": "^3.2.5", "sass-loader": "^14.1.1", "style-loader": "^3.3.4", - "stylelint": "^14.14.0", - "stylelint-config-prettier": "^9.0.3", - "stylelint-config-prettier-scss": "^0.0.1", - "stylelint-config-recess-order": "^3.0.0", - "stylelint-config-standard": "^29.0.0", - "stylelint-config-standard-scss": "^5.0.0", + "stylelint": "^16.2.1", + "stylelint-config-prettier-scss": "^1.0.0", + "stylelint-config-recess-order": "^4.6.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-config-standard-scss": "^13.0.0", + "terser-webpack-plugin": "^5.3.10", "ts-loader": "^9.5.1", - "ts-node": "^10.9.1", "typescript": "^5.3.3", "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.2" + "webpack-dev-server": "^5.0.2", + "webpack-merge": "^5.10.0" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -63,6 +70,19 @@ "node": ">=0.10.0" } }, + "node_modules/@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@babel/code-frame": { "version": "7.23.5", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", @@ -147,6 +167,387 @@ "node": ">=4" } }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.23.10", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.10.tgz", + "integrity": "sha512-2XpP2XhkXzgxecPNEEK8Vz8Asj9aRxt08oKOqtiZoqV2UGZ5T+EkyP9sXQ9nwMxBIG34a7jmasVqoMop7VdPUw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz", + "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz", + "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.22.15", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/helper-string-parser": { "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", @@ -165,6 +566,43 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dev": true, + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz", + "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==", + "dev": true, + "dependencies": { + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/highlight": { "version": "7.23.4", "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", @@ -262,46 +700,1426 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/types": { - "version": "7.23.9", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", - "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.23.3.tgz", + "integrity": "sha512-iRkKcCqb7iGnq9+3G6rZ+Ciz5VywC4XNRHe57lKM+jOeYAoR0lVqdeeDRfh0tQcTfw/+vBhHn926FmQhLtlFLQ==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.23.4", - "@babel/helper-validator-identifier": "^7.22.20", - "to-fast-properties": "^2.0.0" + "@babel/helper-plugin-utils": "^7.22.5" }, "engines": { "node": ">=6.9.0" - } + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.23.3.tgz", + "integrity": "sha512-WwlxbfMNdVEpQjZmK5mhm7oSwD3dS6eU+Iwsi4Knl9wAletWem7kaRsGOG+8UEbRyqxY4SS5zvtfXwX+jMxUwQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.23.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.23.7.tgz", + "integrity": "sha512-LlRT7HgaifEpQA1ZgLVOIJZZFVPWN5iReq/7/JixwBtwcoeVGDBD53ZV28rrsLYOZs1Y/EHhA8N/Z6aazHR8cw==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.23.3.tgz", + "integrity": "sha512-lPgDSU+SJLK3xmFDTV2ZRQAiM7UuUjGidwBywFavObCiZc1BeAAcMtHJKUya92hPHO+at63JJPLygilZard8jw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.23.3.tgz", + "integrity": "sha512-pawnE0P9g10xgoP7yKr6CK63K2FMsTE+FZidZO/1PwRdzmAPVs+HS1mAURUsgaoxammTJvULUdIkEK0gOcU2tA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.23.3.tgz", + "integrity": "sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.23.3.tgz", + "integrity": "sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.23.3.tgz", + "integrity": "sha512-NzQcQrzaQPkaEwoTm4Mhyl8jI1huEL/WWIEvudjTCMJ9aBZNpsJbMASx7EQECtQQPS/DcnFpo0FIh3LvEO9cxQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dev": true, + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.23.3.tgz", + "integrity": "sha512-vI+0sIaPIO6CNuM9Kk5VmXcMVRiOpDh7w2zZt9GXzmE/9KD70CUEVhvPR/etAeNK/FAEkhxQtXOzVF3EuRL41A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.23.4.tgz", + "integrity": "sha512-0QqbP6B6HOh7/8iNR4CQU2Th/bbRtBp4KS9vcaZd1fZ0wSh5Fyssg0UCIHwxh+ka+pNDREbVLQnHCMHKZfPwfw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.23.3.tgz", + "integrity": "sha512-uM+AN8yCIjDPccsKGlw271xjJtGii+xQIF/uMPS8H15L12jZTsLfF4o5vNO7d/oUguOyfdikHGc/yi9ge4SGIg==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.23.4.tgz", + "integrity": "sha512-nsWu/1M+ggti1SOALj3hfx5FXzAY06fwPJsUZD4/A5e1bWi46VUIWtD+kOX6/IdhXGsXBWllLFDSnqSCdUNydQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.23.8", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.23.8.tgz", + "integrity": "sha512-yAYslGsY1bX6Knmg46RjiCiNSwJKv2IUC8qOdYKqMMr0491SXFhcHqOdRDeCRohOOIzwN/90C6mQ9qAKgrP7dg==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-classes/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.23.3.tgz", + "integrity": "sha512-dTj83UVTLw/+nbiHqQSFdwO9CbTtwq1DsDqm3CUEtDrZNET5rT5E6bIdTlOftDTDLMYxvxHNEYO4B9SLl8SLZw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/template": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.23.3.tgz", + "integrity": "sha512-n225npDqjDIr967cMScVKHXJs7rout1q+tt50inyBCPkyZ8KxeI6d+GIbSBTT/w/9WdlWDOej3V9HE5Lgk57gw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.23.3.tgz", + "integrity": "sha512-vgnFYDHAKzFaTVp+mneDsIEbnJ2Np/9ng9iviHw3P/KVcgONxpNULEW/51Z/BaFojG2GI2GwwXck5uV1+1NOYQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.23.3.tgz", + "integrity": "sha512-RrqQ+BQmU3Oyav3J+7/myfvRCq7Tbz+kKLLshUmMwNlDHExbGL7ARhajvoBJEvc+fCguPPu887N+3RRXBVKZUA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.23.4.tgz", + "integrity": "sha512-V6jIbLhdJK86MaLh4Jpghi8ho5fGzt3imHOBu/x0jlBaPYqDoWz4RDXjmMOfnh+JWNaQleEAByZLV0QzBT4YQQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.23.3.tgz", + "integrity": "sha512-5fhCsl1odX96u7ILKHBj4/Y8vipoqwsJMh4csSA8qFfxrZDEA4Ssku2DyNvMJSmZNOEBT750LfFPbtrnTP90BQ==", + "dev": true, + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.23.4.tgz", + "integrity": "sha512-GzuSBcKkx62dGzZI1WVgTWvkkz84FZO5TC5T8dl/Tht/rAla6Dg/Mz9Yhypg+ezVACf/rgDuQt3kbWEv7LdUDQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.23.6.tgz", + "integrity": "sha512-aYH4ytZ0qSuBbpfhuofbg/e96oQ7U2w1Aw/UQmKT+1l39uEhUPoFS3fHevDc1G0OvewyDudfMKY1OulczHzWIw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.23.3.tgz", + "integrity": "sha512-I1QXp1LxIvt8yLaib49dRW5Okt7Q4oaxao6tFVKS/anCdEOMtYwWVKoiOA1p34GOWIZjUK0E+zCp7+l1pfQyiw==", + "dev": true, + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.23.4.tgz", + "integrity": "sha512-81nTOqM1dMwZ/aRXQ59zVubN9wHGqk6UtqRK+/q+ciXmRy8fSolhGVvG09HHRGo4l6fr/c4ZhXUQH0uFW7PZbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.23.3.tgz", + "integrity": "sha512-wZ0PIXRxnwZvl9AYpqNUxpZ5BiTGrYt7kueGQ+N5FiQ7RCOD4cm8iShd6S6ggfVIWaJf2EMk8eRzAh52RfP4rQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.23.4.tgz", + "integrity": "sha512-Mc/ALf1rmZTP4JKKEhUwiORU+vcfarFVLfcFiolKUo6sewoxSEgl36ak5t+4WamRsNr6nzjZXQjM35WsU+9vbg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.23.3.tgz", + "integrity": "sha512-sC3LdDBDi5x96LA+Ytekz2ZPk8i/Ck+DEuDbRAll5rknJ5XRTSaPKEYwomLcs1AA8wg9b3KjIQRsnApj+q51Ag==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.23.3.tgz", + "integrity": "sha512-vJYQGxeKM4t8hYCKVBlZX/gtIY2I7mRGFNcm85sgXGMTBcoV3QdVtdpbcWEbzbfUIUZKwvgFT82mRvaQIebZzw==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.23.3.tgz", + "integrity": "sha512-aVS0F65LKsdNOtcz6FRCpE4OgsP2OFnW46qNxNIX9h3wuzaNcSQsJysuMwqSibC98HPrf2vCgtxKNwS0DAlgcA==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.23.9.tgz", + "integrity": "sha512-KDlPRM6sLo4o1FkiSlXoAa8edLXFsKKIda779fbLrvmeuc3itnjCtaO6RrtoaANsIJANj+Vk1zqbZIMhkCAHVw==", + "dev": true, + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.23.3.tgz", + "integrity": "sha512-zHsy9iXX2nIsCBFPud3jKn1IRPWg3Ing1qOZgeKV39m1ZgIdpJqvlWVeiHBZC6ITRG0MfskhYe9cLgntfSFPIg==", + "dev": true, + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.23.3.tgz", + "integrity": "sha512-YJ3xKqtJMAT5/TIZnpAR3I+K+WaDowYbN3xyxI8zxx/Gsypwf9B9h0VB+1Nh6ACAAPRS5NSRje0uVv5i79HYGQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.23.4.tgz", + "integrity": "sha512-jHE9EVVqHKAQx+VePv5LLGHjmHSJR76vawFPTdlxR/LVJPfOEGxREQwQfjuZEOPTwG92X3LINSh3M40Rv4zpVA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.23.4.tgz", + "integrity": "sha512-mps6auzgwjRrwKEZA05cOwuDc9FAzoyFS4ZsG/8F43bTLf/TgkJg7QXOrPO1JO599iA3qgK9MXdMGOEC8O1h6Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.23.4.tgz", + "integrity": "sha512-9x9K1YyeQVw0iOXJlIzwm8ltobIIv7j2iLyP2jIhEbqPRQ7ScNgwQufU2I0Gq11VjyG4gI4yMXt2VFags+1N3g==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.3", + "@babel/helper-compilation-targets": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.23.3.tgz", + "integrity": "sha512-BwQ8q0x2JG+3lxCVFohg+KbQM7plfpBwThdW9A6TMtWwLsbDA01Ek2Zb/AgDN39BiZsExm4qrXxjk+P1/fzGrA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-replace-supers": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.23.4.tgz", + "integrity": "sha512-XIq8t0rJPHf6Wvmbn9nFxU6ao4c7WhghTR5WyV8SrJfUFzyxhCm4nhC+iAp3HFhbAKLfYpgzhJ6t4XCtVwqO5A==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.23.4.tgz", + "integrity": "sha512-ZU8y5zWOfjM5vZ+asjgAPwDaBjJzgufjES89Rs4Lpq63O300R/kOz30WCLo6BxxX6QVEilwSlpClnG5cZaikTA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.23.3.tgz", + "integrity": "sha512-09lMt6UsUb3/34BbECKVbVwrT9bO6lILWln237z7sLaWnMsTi7Yc9fhX5DLpkJzAGfaReXI22wP41SZmnAA3Vw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.23.3.tgz", + "integrity": "sha512-UzqRcRtWsDMTLrRWFvUBDwmw06tCQH9Rl1uAjfh6ijMSmGYQ+fpdB+cnqRC8EMh5tuuxSv0/TejGL+7vyj+50g==", + "dev": true, + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz", + "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.23.3.tgz", + "integrity": "sha512-jR3Jn3y7cZp4oEWPFAlRsSWjxKe4PZILGBSd4nis1TsC5qeSpb+nrtihJuDhNI7QHiVbUaiXa0X2RZY3/TI6Nw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.23.3.tgz", + "integrity": "sha512-KP+75h0KghBMcVpuKisx3XTu9Ncut8Q8TuvGO4IhY+9D5DFEckQefOuIsB/gQ2tG71lCke4NMrtIPS8pOj18BQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.23.3.tgz", + "integrity": "sha512-QnNTazY54YqgGxwIexMZva9gqbPa15t/x9VS+0fsEFWplwVpXYZivtgl43Z1vMpc1bdPP2PP8siFeVcnFvA3Cg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.23.3.tgz", + "integrity": "sha512-ED2fgqZLmexWiN+YNFX26fx4gh5qHDhn1O2gvEhreLW2iI63Sqm4llRLCXALKrCnbN4Jy0VcMQZl/SAzqug/jg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } }, - "node_modules/@cspotcode/source-map-support": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", - "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "node_modules/@babel/plugin-transform-spread": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.23.3.tgz", + "integrity": "sha512-VvfVYlrlBVu+77xVTOAoxQ6mZbnIq5FM0aGBSFEcIh03qHf+zNqA4DC/3XMUozTg7bZV3e3mZQ0i13VB6v5yUg==", "dev": true, "dependencies": { - "@jridgewell/trace-mapping": "0.3.9" + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" }, "engines": { - "node": ">=12" + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@csstools/selector-specificity": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-2.2.0.tgz", - "integrity": "sha512-+OJ9konv95ClSTOJCmMZqpd5+YGsB2S+x6w3E1oaM8UuR5j8nTNHYSz8c9BEPGDOCMQYIEEGlVPj/VY64iTbGw==", + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.23.3.tgz", + "integrity": "sha512-HZOyN9g+rtvnOU3Yh7kSxXrKbzgrm5X4GncPY1QOquu7epga5MxKHVpYu2hvQnry/H+JjckSYRb93iNfsioAGg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.23.3.tgz", + "integrity": "sha512-Flok06AYNp7GV2oJPZZcP9vZdszev6vPBkHLwxwSpaIqx75wn6mUd3UFWsSsA0l8nXAKkyCmL/sR02m8RYGeHg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.23.3.tgz", + "integrity": "sha512-4t15ViVnaFdrPC74be1gXBSMzXk3B4Us9lP7uLRQHTFpV5Dvt33pn+2MyyNxmN3VTTm3oTrZVMUmuw3oBnQ2oQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.23.6.tgz", + "integrity": "sha512-6cBG5mBvUu4VUD04OHKnYzbuHNP8huDsD3EDqqpIpsswTDoqHCjLoHb6+QgsV1WsT2nipRqCPgxD3LXnEO7XfA==", + "dev": true, + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/plugin-syntax-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.23.3.tgz", + "integrity": "sha512-OMCUx/bU6ChE3r4+ZdylEqAjaQgHAgipgW8nsCfu5pGqDcFytVd91AwRvUJSBZDz0exPGgnjoqhgRYLRjFZc9Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.23.3.tgz", + "integrity": "sha512-KcLIm+pDZkWZQAFJ9pdfmh89EwVfmNovFBcXko8szpBeF8z68kWIPeKlmSOkT9BXJxs2C0uk+5LxoxIv62MROA==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.23.3.tgz", + "integrity": "sha512-wMHpNA4x2cIA32b/ci3AfwNgheiva2W0WUKWTK7vBHBhDKfPsc5cFGNWm69WBqpwd86u1qwZ9PWevKqm1A3yAw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.23.3.tgz", + "integrity": "sha512-W7lliA/v9bNR83Qc3q1ip9CQMZ09CcHDbHfbLRDNuAhn1Mvkr1ZNF7hPmztMQvtTGVLJ9m8IZqWsTkXOml8dbw==", + "dev": true, + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.23.9.tgz", + "integrity": "sha512-3kBGTNBBk9DQiPoXYS0g0BYlwTQYUTifqgKTjxUwEUkduRT2QOa0FPGBJ+NROQhGyYO5BuTJwGvBnqKDykac6A==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.23.4", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/preset-typescript": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.23.3.tgz", + "integrity": "sha512-17oIGVlqz6CchO9RFYn5U6ZpWRZIngayYCtrPRSgANSwC2V1Jb+iP74nVxzzXJte8b8BYxrL1yY96xfhTBrNNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-validator-option": "^7.22.15", + "@babel/plugin-syntax-jsx": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-typescript": "^7.23.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==", + "dev": true + }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz", + "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz", + "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.9", + "@babel/types": "^7.23.9", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz", + "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.0.tgz", + "integrity": "sha512-YfEHq0eRH98ffb5/EsrrDspVWAuph6gDggAE74ZtjecsmyyWpW768hOyiONa8zwWGbIWYfa2Xp4tRTrpQQ00CQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], "engines": { "node": "^14 || ^16 || >=18" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/csstools" + "peerDependencies": { + "@csstools/css-tokenizer": "^2.2.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.3.tgz", + "integrity": "sha512-pp//EvZ9dUmGuGtG1p+n17gTHEOqu9jO+FiCUjNN3BDmyhdA2Jq9QsVeR7K8/2QCK17HSsioPlTW9ZkzoWb3Lg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + } + }, + "node_modules/@csstools/media-query-list-parser": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.8.tgz", + "integrity": "sha512-DiD3vG5ciNzeuTEoh74S+JMjQDs50R3zlxHnBnfd04YYfA/kh2KiBCGhzqLxlJcNq+7yNQ3stuZZYLX6wK/U2g==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^2.6.0", + "@csstools/css-tokenizer": "^2.2.3" + } + }, + "node_modules/@csstools/selector-specificity": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.2.tgz", + "integrity": "sha512-RpHaZ1h9LE7aALeQXmXrJkRG84ZxIsctEN2biEUmFyKpzFM3zZ35eUMcIzZFsw/2olQE6v69+esEqU2f1MKycg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "engines": { + "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "postcss-selector-parser": "^6.0.10" + "postcss-selector-parser": "^6.0.13" } }, "node_modules/@discoveryjs/json-ext": { @@ -314,9 +2132,9 @@ } }, "node_modules/@es-joy/jsdoccomment": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.41.0.tgz", - "integrity": "sha512-aKUhyn1QI5Ksbqcr3fFJj16p99QdjUxXAEuFst1Z47DRyoiMwivIH9MV/ARcJOCXVjPfjITciej8ZD2O/6qUmw==", + "version": "0.42.0", + "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.42.0.tgz", + "integrity": "sha512-R1w57YlVA6+YE01wch3GPYn6bCsrOV3YW/5oGGE2tmX6JcL9Nr+b5IikrjMPF+v9CV3ay+obImEdsDhovhJrzw==", "dev": true, "dependencies": { "comment-parser": "1.4.1", @@ -374,6 +2192,28 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "8.57.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", @@ -397,6 +2237,28 @@ "node": ">=10.10.0" } }, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@humanwhocodes/module-importer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", @@ -512,6 +2374,35 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.4", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.4.tgz", @@ -561,13 +2452,13 @@ "dev": true }, "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", - "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", + "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, "node_modules/@league-of-foundry-developers/foundry-vtt-types": { @@ -607,12 +2498,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/@league-of-foundry-developers/foundry-vtt-types/node_modules/tinymce": { - "version": "5.10.1", - "resolved": "https://registry.npmjs.org/tinymce/-/tinymce-5.10.1.tgz", - "integrity": "sha512-aIsFTYiuESpoYkCgkoojpVtPwrSvYBxp4mMEGsj20CnUruLCWosywkbYHDII+j7KlQZZn3p+xK89f5gT3QyuGw==", - "dev": true - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -2803,34 +4688,43 @@ "node": ">=14" } }, - "node_modules/@socket.io/component-emitter": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", - "integrity": "sha512-2pTGuibAXJswAPJjaKisthqS/NOK5ypG4LYT6tEAV0S/mxW0zOIvYvGK0V8w8+SHxAm6vRMSjqSalFXeBAqs+Q==", + "node_modules/@sinclair/typebox": { + "version": "0.27.8", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, - "node_modules/@tsconfig/node10": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", - "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", - "dev": true + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/@tsconfig/node12": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", - "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", "dev": true }, - "node_modules/@tsconfig/node14": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", - "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", - "dev": true + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } }, - "node_modules/@tsconfig/node16": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", - "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "node_modules/@tsconfig/node21": { + "version": "21.0.1", + "resolved": "https://registry.npmjs.org/@tsconfig/node21/-/node21-21.0.1.tgz", + "integrity": "sha512-2Khg79N+z2Qkb9SjLzOi8cz2PSa/oUpHIeQm1YWzmWXkoFcPXFZSHgs+Z8iPCDjIoXFqMNYntiTXxfLYQMcRhw==", "dev": true }, "node_modules/@types/babel__core": { @@ -2994,6 +4888,30 @@ "@types/node": "*" } }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/jquery": { "version": "3.5.29", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-3.5.29.tgz", @@ -3022,21 +4940,15 @@ "dev": true }, "node_modules/@types/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", - "dev": true - }, - "node_modules/@types/minimist": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.5.tgz", - "integrity": "sha512-hov8bUuiLiyFPGyFPE1lwWhmzYbirOXQNNo40+y3zow8aFVTeyn3VWL0VFFfdNddA8S4Vf0Tc062rzyNr7Paag==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", "dev": true }, "node_modules/@types/node": { - "version": "18.19.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.18.tgz", - "integrity": "sha512-80CP7B8y4PzZF0GWx15/gVWRrB5y/bIjNI84NK3cmQJu0WZwvmj2WMA5LcofQFVfLqqCSp545+U2LsrVzX36Zg==", + "version": "20.11.20", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.20.tgz", + "integrity": "sha512-7/rR21OS+fq8IyHTgtLkDK949uzsa6n8BkziAKtPVpugIkO6D+/ooXMvzXxDnZrmtXVfjb1bKQafYpb8s89LOg==", "dependencies": { "undici-types": "~5.26.4" } @@ -3059,12 +4971,6 @@ "@types/node": "*" } }, - "node_modules/@types/normalize-package-data": { - "version": "2.4.4", - "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", - "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", - "dev": true - }, "node_modules/@types/offscreencanvas": { "version": "2019.7.3", "resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.3.tgz", @@ -3072,12 +4978,6 @@ "dev": true, "peer": true }, - "node_modules/@types/parse-json": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", - "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", - "dev": true - }, "node_modules/@types/prop-types": { "version": "15.7.11", "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz", @@ -3243,137 +5143,68 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", - "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", - "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", - "dev": true, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/typescript-estree": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", - "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", + "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "@typescript-eslint/utils": "5.62.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", - "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", - "semver": "^7.5.4" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", - "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.2", - "eslint-visitor-keys": "^3.4.1" - }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/experimental-utils": { + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/typescript-estree": { "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.62.0.tgz", - "integrity": "sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", "dev": true, "dependencies": { - "@typescript-eslint/utils": "5.62.0" + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" }, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -3382,8 +5213,10 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/utils": { @@ -3412,100 +5245,56 @@ "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", - "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.0.2", - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/typescript-estree": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2", - "debug": "^4.3.4" + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.56.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", - "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2" + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" }, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=8.0.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/types": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", - "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", + "node_modules/@typescript-eslint/experimental-utils/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "node": ">=4.0" } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/parser": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", - "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.0.2.tgz", + "integrity": "sha512-GdwfDglCxSmU+QTS9vhz2Sop46ebNCXpPPvsByK7hu0rFGRHL+AusKQJ7SoN+LbLh6APFpQwHKmDSwN35Z700Q==", "dev": true, "dependencies": { + "@typescript-eslint/scope-manager": "7.0.2", "@typescript-eslint/types": "7.0.2", + "@typescript-eslint/typescript-estree": "7.0.2", "@typescript-eslint/visitor-keys": "7.0.2", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "debug": "^4.3.4" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3514,20 +5303,23 @@ "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, + "peerDependencies": { + "eslint": "^8.56.0" + }, "peerDependenciesMeta": { "typescript": { "optional": true } } }, - "node_modules/@typescript-eslint/parser/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/scope-manager": { "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", - "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", + "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", "dev": true, "dependencies": { "@typescript-eslint/types": "7.0.2", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/visitor-keys": "7.0.2" }, "engines": { "node": "^16.0.0 || >=18.0.0" @@ -3537,47 +5329,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/parser/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/parser/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", - "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@typescript-eslint/type-utils": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.0.2.tgz", @@ -3605,24 +5356,7 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/scope-manager": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.0.2.tgz", - "integrity": "sha512-l6sa2jF3h+qgN2qUMjVR3uCNGjWw4ahGfzIYsCtFrQJCjhbrDPdiihYT8FnnqFwsWX+20hK592yX9I2rxKTP4g==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "7.0.2", - "@typescript-eslint/visitor-keys": "7.0.2" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": { + "node_modules/@typescript-eslint/types": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.0.2.tgz", "integrity": "sha512-ZzcCQHj4JaXFjdOql6adYV4B/oFOFjPOC9XYwCaZFRvqN8Llfvv4gSxrkQkd2u4Ci62i2c6W6gkDwQJDaRc4nA==", @@ -3635,7 +5369,7 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": { + "node_modules/@typescript-eslint/typescript-estree": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.0.2.tgz", "integrity": "sha512-3AMc8khTcELFWcKcPc0xiLviEvvfzATpdPj/DXuOGIdQIIFybf4DMT1vKRbuAEOFMwhWt7NFLXRkbjsvKZQyvw==", @@ -3663,7 +5397,7 @@ } } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "node_modules/@typescript-eslint/utils": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.0.2.tgz", "integrity": "sha512-PZPIONBIB/X684bhT1XlrkjNZJIEevwkKDsdwfiu1WeqBxYEEdIgVDgm8/bbKHVu+6YOpeRqcfImTdImx/4Bsw==", @@ -3688,7 +5422,7 @@ "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": { + "node_modules/@typescript-eslint/visitor-keys": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.0.2.tgz", "integrity": "sha512-8Y+YiBmqPighbm5xA2k4wKTxRzx9EkBu7Rlw+WHqMvRJ3RPz/BMBO9b2ru0LUNmXg120PHUXD5+SWFy2R8DqlQ==", @@ -3705,87 +5439,6 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@typescript-eslint/type-utils/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/type-utils/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@typescript-eslint/types": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", - "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", - "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "@typescript-eslint/visitor-keys": "5.62.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "semver": "^7.3.7", - "tsutils": "^3.21.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "5.62.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", - "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", - "dev": true, - "dependencies": { - "@typescript-eslint/types": "5.62.0", - "eslint-visitor-keys": "^3.3.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", @@ -4061,15 +5714,6 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, - "node_modules/acorn-walk": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.2.tgz", - "integrity": "sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==", - "dev": true, - "engines": { - "node": ">=0.4.0" - } - }, "node_modules/agentkeepalive": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", @@ -4192,18 +5836,6 @@ "node": ">= 8" } }, - "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/are-docs-informative": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/are-docs-informative/-/are-docs-informative-0.0.2.tgz", @@ -4213,12 +5845,6 @@ "node": ">=14" } }, - "node_modules/arg": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", - "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", - "dev": true - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -4380,15 +6006,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/astral-regex": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", @@ -4465,11 +6082,70 @@ "proxy-from-env": "^1.1.0" } }, - "node_modules/backo2": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", - "integrity": "sha512-zj6Z6M7Eq+PBZ7PQxl5NT665MvJdAkzp0f60nAJ+sLaSCBPMwVak5ZegFbgVCzFcCJTKFoMizvM5Ld7+JrRJHA==", - "dev": true + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dev": true, + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.8", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.8.tgz", + "integrity": "sha512-OtIuQfafSzpo/LhnJaykc0R/MMnuLSSVjVYy9mHArIZ9qTCSZ6TpWCuEKZYVoN//t8HqBNScHrOtCrIK5IaGLg==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.5.0", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dev": true, + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } }, "node_modules/balanced-match": { "version": "1.0.2", @@ -4570,14 +6246,19 @@ "multicast-dns": "^7.2.5" } }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true + }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -4685,39 +6366,25 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "dev": true, "engines": { "node": ">=6" } }, - "node_modules/camelcase-keys": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", - "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "node_modules/caniuse-api": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz", + "integrity": "sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==", "dev": true, "dependencies": { - "camelcase": "^5.3.1", - "map-obj": "^4.0.0", - "quick-lru": "^4.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "browserslist": "^4.0.0", + "caniuse-lite": "^1.0.0", + "lodash.memoize": "^4.1.2", + "lodash.uniq": "^4.5.0" } }, "node_modules/caniuse-lite": { @@ -4740,6 +6407,22 @@ } ] }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/charenc": { "version": "0.0.2", "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz", @@ -4793,6 +6476,21 @@ "node": ">=6.0" } }, + "node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, "node_modules/clean-webpack-plugin": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/clean-webpack-plugin/-/clean-webpack-plugin-4.0.0.tgz", @@ -4847,15 +6545,6 @@ "node": ">=0.10.0" } }, - "node_modules/clone-deep/node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", @@ -4895,6 +6584,12 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -4904,6 +6599,12 @@ "node": ">= 12.0.0" } }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==", + "dev": true + }, "node_modules/compressible": { "version": "2.0.18", "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", @@ -4991,6 +6692,12 @@ "node": ">= 0.6" } }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, "node_modules/cookie": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", @@ -5006,6 +6713,87 @@ "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==", "dev": true }, + "node_modules/copy-webpack-plugin": { + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-12.0.2.tgz", + "integrity": "sha512-SNwdBeHyII+rWvee/bTnAYyO8vfVdcSTud4EIb6jcZ8inLeWucJE0DnxXQBjlQ5zlteuuvooGQy3LIyGxhvlOA==", + "dev": true, + "dependencies": { + "fast-glob": "^3.3.2", + "glob-parent": "^6.0.1", + "globby": "^14.0.0", + "normalize-path": "^3.0.0", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/globby": { + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.0.1.tgz", + "integrity": "sha512-jOMLD2Z7MAhyG8aJpNOpmziMOP4rPLcc95oQPKXBazW82z+CEgPFBQvEpRUa1KeIMUJo4Wsm+q6uzO/Q/4BksQ==", + "dev": true, + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.2", + "ignore": "^5.2.4", + "path-type": "^5.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/path-type": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", + "integrity": "sha512-5HviZNaZcfqP95rwpv+1HDgUamezbqdSYTyzjTvwtJSnIH+3vnbmWsItli8OFEndS984VT55M3jduxZbX351gg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/copy-webpack-plugin/node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.0", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.0.tgz", + "integrity": "sha512-iV9Pd/PsgjNWBXeq8XRtWVSgz2tKAfhfvBs7qxYty+RlRd+OCksaWmOnc4JKrTc1cToXL1N0s3l/vwlxPtdElw==", + "dev": true, + "dependencies": { + "browserslist": "^4.22.3" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", @@ -5013,27 +6801,31 @@ "dev": true }, "node_modules/cosmiconfig": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", - "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", "dev": true, "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" }, "engines": { - "node": ">=10" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/create-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", - "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", - "dev": true - }, "node_modules/cross-spawn": { "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", @@ -5056,62 +6848,297 @@ "node": "*" } }, + "node_modules/css-declaration-sorter": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-7.1.1.tgz", + "integrity": "sha512-dZ3bVTEEc1vxr3Bek9vGwfB5Z6ESPULhcRvO472mfjVnj8jRcTnKO8/JTczlvxM10Myb+wBM++1MtdO76eWcaQ==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18" + }, + "peerDependencies": { + "postcss": "^8.0.9" + } + }, "node_modules/css-functions-list": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/css-functions-list/-/css-functions-list-3.2.1.tgz", "integrity": "sha512-Nj5YcaGgBtuUmn1D7oHqPW0c9iui7xsTsj5lIX8ZgevdfhmjFfKB3r8moHJtNJnctnYXJyYX5I1pp90HM4TPgQ==", "dev": true, "engines": { - "node": ">=12 || >=16" + "node": ">=12 || >=16" + } + }, + "node_modules/css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "dev": true, + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/css-minimizer-webpack-plugin/-/css-minimizer-webpack-plugin-6.0.0.tgz", + "integrity": "sha512-BLpR9CCDkKvhO3i0oZQgad6v9pCxUuhSc5RT6iUEy9M8hBXi4TJb5vqF2GQ2deqYHmRi3O6IR9hgAZQWg0EBwA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.21", + "cssnano": "^6.0.3", + "jest-worker": "^29.7.0", + "postcss": "^8.4.33", + "schema-utils": "^4.2.0", + "serialize-javascript": "^6.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@parcel/css": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "lightningcss": { + "optional": true + } + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/css-minimizer-webpack-plugin/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "dev": true, + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" } }, - "node_modules/css-loader": { - "version": "6.10.0", - "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", - "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "node_modules/cssnano": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-6.0.5.tgz", + "integrity": "sha512-tpTp/ukgrElwu3ESFY4IvWnGn8eTt8cJhC2aAbtA3lvUlxp6t6UPv8YCLjNnEGiFreT1O0LiOM1U3QyTBVFl2A==", "dev": true, "dependencies": { - "icss-utils": "^5.1.0", - "postcss": "^8.4.33", - "postcss-modules-extract-imports": "^3.0.0", - "postcss-modules-local-by-default": "^4.0.4", - "postcss-modules-scope": "^3.1.1", - "postcss-modules-values": "^4.0.0", - "postcss-value-parser": "^4.2.0", - "semver": "^7.5.4" + "cssnano-preset-default": "^6.0.5", + "lilconfig": "^3.1.1" }, "engines": { - "node": ">= 12.13.0" + "node": "^14 || ^16 || >=18.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/cssnano" }, "peerDependencies": { - "@rspack/core": "0.x || 1.x", - "webpack": "^5.0.0" + "postcss": "^8.4.31" + } + }, + "node_modules/cssnano-preset-default": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-6.0.5.tgz", + "integrity": "sha512-M+qRDEr5QZrfNl0B2ySdbTLGyNb8kBcSjuwR7WBamYBOEREH9t2efnB/nblekqhdGLZdkf4oZNetykG2JWRdZQ==", + "dev": true, + "dependencies": { + "css-declaration-sorter": "^7.1.1", + "cssnano-utils": "^4.0.1", + "postcss-calc": "^9.0.1", + "postcss-colormin": "^6.0.3", + "postcss-convert-values": "^6.0.4", + "postcss-discard-comments": "^6.0.1", + "postcss-discard-duplicates": "^6.0.2", + "postcss-discard-empty": "^6.0.2", + "postcss-discard-overridden": "^6.0.1", + "postcss-merge-longhand": "^6.0.3", + "postcss-merge-rules": "^6.0.4", + "postcss-minify-font-values": "^6.0.2", + "postcss-minify-gradients": "^6.0.2", + "postcss-minify-params": "^6.0.3", + "postcss-minify-selectors": "^6.0.2", + "postcss-normalize-charset": "^6.0.1", + "postcss-normalize-display-values": "^6.0.1", + "postcss-normalize-positions": "^6.0.1", + "postcss-normalize-repeat-style": "^6.0.1", + "postcss-normalize-string": "^6.0.1", + "postcss-normalize-timing-functions": "^6.0.1", + "postcss-normalize-unicode": "^6.0.3", + "postcss-normalize-url": "^6.0.1", + "postcss-normalize-whitespace": "^6.0.1", + "postcss-ordered-values": "^6.0.1", + "postcss-reduce-initial": "^6.0.3", + "postcss-reduce-transforms": "^6.0.1", + "postcss-svgo": "^6.0.2", + "postcss-unique-selectors": "^6.0.2" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" }, - "peerDependenciesMeta": { - "@rspack/core": { - "optional": true - }, - "webpack": { - "optional": true - } + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "node_modules/cssnano-utils": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-4.0.1.tgz", + "integrity": "sha512-6qQuYDqsGoiXssZ3zct6dcMxiqfT6epy7x4R0TQJadd4LWO3sPR6JH6ZByOvVLoZ6EdwPGgd7+DR1EmX3tiXQQ==", "dev": true, - "bin": { - "cssesc": "bin/cssesc" + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" }, "engines": { - "node": ">=4" + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" } }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/csstype": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", @@ -5134,46 +7161,21 @@ } } }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/decamelize-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.1.tgz", - "integrity": "sha512-WiPxgEirIV0/eIOMcnFBA3/IJZAZqKnwAwWyvvdi4lsr1WCN22nhdf/3db3DoZcUjTV2SqfzIwNyp6y2xs3nmg==", - "dev": true, - "dependencies": { - "decamelize": "^1.1.0", - "map-obj": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/decamelize-keys/node_modules/map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-browser": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", @@ -5290,26 +7292,6 @@ "node": ">=0.10.0" } }, - "node_modules/del/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/del/node_modules/globby": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-6.1.0.tgz", @@ -5335,18 +7317,6 @@ "node": ">=0.10.0" } }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -5380,15 +7350,6 @@ "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==", "dev": true }, - "node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/digest-fetch": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/digest-fetch/-/digest-fetch-1.3.0.tgz", @@ -5434,6 +7395,61 @@ "node": ">=6.0.0" } }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/earcut": { "version": "2.2.4", "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.4.tgz", @@ -5473,26 +7489,22 @@ } }, "node_modules/engine.io-client": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.0.3.tgz", - "integrity": "sha512-IH8ZhDIwiLv0d/wXVzmjfV9Y82hbJIDhCGSVUV8o1kcpDe2I6Y3bZA3ZbJy4Ls7k7IVmcy/qn4k9RKWFhUGf5w==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1", - "engine.io-parser": "~5.0.0", - "has-cors": "1.1.0", - "parseqs": "0.0.6", - "parseuri": "0.0.6", - "ws": "~8.2.3", - "xmlhttprequest-ssl": "~2.0.0", - "yeast": "0.1.2" + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" } }, "node_modules/engine.io-parser": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.0.7.tgz", - "integrity": "sha512-P+jDFbvK6lE3n1OL+q9KuzdOFWkkZ/cMV9gol/SbVfpyqfvrfrFTOFJ6fQm2VC3PZHlU3QPhVwmbsCnauHF2MQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", "dev": true, "engines": { "node": ">=10.0.0" @@ -5511,6 +7523,18 @@ "node": ">=10.13.0" } }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, "node_modules/env-paths": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", @@ -5866,6 +7890,16 @@ "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" } }, + "node_modules/eslint-plugin-import/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint-plugin-import/node_modules/debug": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", @@ -5887,171 +7921,98 @@ "node": ">=0.10.0" } }, - "node_modules/eslint-plugin-import/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "46.10.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-46.10.1.tgz", - "integrity": "sha512-x8wxIpv00Y50NyweDUpa+58ffgSAI5sqe+zcZh33xphD0AVh+1kqr1ombaTRb7Fhpove1zfUuujlX9DWWBP5ag==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.41.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.5.0", - "is-builtin-module": "^3.2.1", - "semver": "^7.5.4", - "spdx-expression-parse": "^4.0.0" - }, - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/eslint/node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "*" } }, - "node_modules/eslint/node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true, - "engines": { - "node": ">=8" + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/eslint/node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "node_modules/eslint-plugin-jsdoc": { + "version": "48.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-48.2.0.tgz", + "integrity": "sha512-O2B1XLBJnUCRkggFzUQ+PBYJDit8iAgXdlu8ucolqGrbmOWPvttZQZX8d1sC0MbqDMSLs8SHSQxaNPRY1RQREg==", "dev": true, "dependencies": { - "p-locate": "^5.0.0" + "@es-joy/jsdoccomment": "~0.42.0", + "are-docs-informative": "^0.0.2", + "comment-parser": "1.4.1", + "debug": "^4.3.4", + "escape-string-regexp": "^4.0.0", + "esquery": "^1.5.0", + "is-builtin-module": "^3.2.1", + "semver": "^7.6.0", + "spdx-expression-parse": "^4.0.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, - "node_modules/eslint/node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", "dev": true, "dependencies": { - "yocto-queue": "^0.1.0" + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "dev": true, - "dependencies": { - "p-limit": "^3.0.2" - }, "engines": { - "node": ">=10" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/eslint/node_modules/yocto-queue": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, - "engines": { - "node": ">=10" + "dependencies": { + "brace-expansion": "^1.1.7" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "*" } }, "node_modules/espree": { @@ -6373,6 +8334,135 @@ "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dev": true, + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dev": true, + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/find-cache-dir/node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dev": true, + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-cache-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/flat": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", @@ -6396,6 +8486,21 @@ "node": "^10.12.0 || >=12.0.0" } }, + "node_modules/flat-cache/node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", @@ -6413,49 +8518,155 @@ } ], "engines": { - "node": ">=4.0" + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/fork-ts-checker-webpack-plugin": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-9.0.2.tgz", + "integrity": "sha512-Uochze2R8peoN1XqlSi/rGUkDQpRogtLFocP9+PGu68zk1BDAKXfdeCdyVZpgTk8V8WFVQXdEz426VKjXLO1Gg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.16.7", + "chalk": "^4.1.2", + "chokidar": "^3.5.3", + "cosmiconfig": "^8.2.0", + "deepmerge": "^4.2.2", + "fs-extra": "^10.0.0", + "memfs": "^3.4.1", + "minimatch": "^3.0.4", + "node-abort-controller": "^3.0.1", + "schema-utils": "^3.1.1", + "semver": "^7.3.5", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">=12.13.0", + "yarn": ">=1.0.0" + }, + "peerDependencies": { + "typescript": ">3.6.0", + "webpack": "^5.11.0" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/cosmiconfig": { + "version": "8.3.6", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.3.6.tgz", + "integrity": "sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==", + "dev": true, + "dependencies": { + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0", + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" }, "peerDependenciesMeta": { - "debug": { + "typescript": { "optional": true } } }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", "dev": true, "dependencies": { - "is-callable": "^1.1.3" + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" } }, - "node_modules/foreground-child": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", - "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", "dev": true, "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": "*" } }, - "node_modules/foreground-child/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, "engines": { - "node": ">=14" + "node": ">= 10.13.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, "node_modules/form-data": { @@ -6527,6 +8738,26 @@ "node": ">= 0.6" } }, + "node_modules/fs-extra": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.1.0.tgz", + "integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==", + "dev": true + }, "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", @@ -6583,6 +8814,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -6639,6 +8879,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -6657,6 +8917,28 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -6745,15 +9027,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby/node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/globjoin": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/globjoin/-/globjoin-0.1.4.tgz", @@ -6811,15 +9084,6 @@ "uglify-js": "^3.1.4" } }, - "node_modules/hard-rejection": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", - "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -6829,12 +9093,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-cors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", - "integrity": "sha512-g5VNKdkFuUuVCP9gYfDJHjK2nqdQJ7aDLTnycnc2+RvsOQbuLdF5pm7vuE5J76SEBIQjs4kQY/BWq74JUmjbXA==", - "dev": true - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6907,18 +9165,6 @@ "node": ">= 0.4" } }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/hpack.js": { "version": "2.1.6", "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", @@ -6931,6 +9177,12 @@ "wbuf": "^1.1.0" } }, + "node_modules/hpack.js/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, "node_modules/hpack.js/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", @@ -7055,18 +9307,6 @@ } } }, - "node_modules/http-proxy-middleware/node_modules/is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/http-proxy/node_modules/eventemitter3": { "version": "4.0.7", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", @@ -7139,15 +9379,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/import-lazy": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/import-lazy/-/import-lazy-4.0.0.tgz", - "integrity": "sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/import-local": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", @@ -7482,7 +9713,7 @@ "node": ">=6" } }, - "node_modules/is-path-inside": { + "node_modules/is-path-in-cwd/node_modules/is-path-inside": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-2.1.0.tgz", "integrity": "sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==", @@ -7494,13 +9725,25 @@ "node": ">=6" } }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/is-plain-obj": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", - "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true, "engines": { - "node": ">=0.10.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-plain-object": { @@ -7628,9 +9871,9 @@ } }, "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", "dev": true }, "node_modules/isexe": { @@ -7645,6 +9888,15 @@ "integrity": "sha512-VaFW53yt8QO61k2WJui0dHf4SlL8lxBofUuUmwBo0ljPk0Drz2TiuDW4jo3wDcv41qy/SxrJ+VAzJ/qYqsmzRw==", "dev": true }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/jackspeak": { "version": "2.3.6", "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", @@ -7663,6 +9915,23 @@ "@pkgjs/parseargs": "^0.11.0" } }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -7728,6 +9997,18 @@ "node": ">=12.0.0" } }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", @@ -7764,6 +10045,18 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -7783,9 +10076,9 @@ } }, "node_modules/known-css-properties": { - "version": "0.26.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.26.0.tgz", - "integrity": "sha512-5FZRzrZzNTBruuurWpvZnvP9pum+fe0HcK8z/ooo+U+Hmp4vtbyp1/QDsqmufirXy4egGzbaH/y2uCZf+6W5Kg==", + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.29.0.tgz", + "integrity": "sha512-Ne7wqW7/9Cz54PDt4I3tcV+hAyat8ypyOGzYRJQfdxnnjeWsTxt1cy8pjvvKeI5kfXuyvULyeeAvwvvtAX3ayQ==", "dev": true }, "node_modules/launch-editor": { @@ -7811,6 +10104,18 @@ "node": ">= 0.8.0" } }, + "node_modules/lilconfig": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" + } + }, "node_modules/lines-and-columns": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", @@ -7826,6 +10131,33 @@ "node": ">=6.11.5" } }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -7838,6 +10170,12 @@ "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", "dev": true }, + "node_modules/lodash.uniq": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz", + "integrity": "sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==", + "dev": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -7859,26 +10197,8 @@ "dependencies": { "yallist": "^4.0.0" }, - "engines": { - "node": ">=10" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true - }, - "node_modules/map-obj": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", - "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10" } }, "node_modules/mathml-tag-names": { @@ -7901,6 +10221,12 @@ "is-buffer": "~1.1.6" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -7927,38 +10253,12 @@ } }, "node_modules/meow": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", - "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", - "dev": true, - "dependencies": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize": "^1.2.0", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/meow/node_modules/type-fest": { - "version": "0.18.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", - "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-13.2.0.tgz", + "integrity": "sha512-pxQJQzB6djGPXh08dacEloMFopsOqGVRKFPYvPOt9XDZ1HasbgDZA74CJGreSU4G3Ak7EFJGoiH2auq+yXISgA==", "dev": true, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -8007,18 +10307,6 @@ "node": ">=8.6" } }, - "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -8059,15 +10347,6 @@ "node": ">=6" } }, - "node_modules/min-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", - "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", - "dev": true, - "engines": { - "node": ">=4" - } - }, "node_modules/mini-css-extract-plugin": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.0.tgz", @@ -8088,59 +10367,6 @@ "webpack": "^5.0.0" } }, - "node_modules/mini-css-extract-plugin/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/mini-css-extract-plugin/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/mini-css-extract-plugin/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/mini-signals": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mini-signals/-/mini-signals-1.2.0.tgz", @@ -8154,15 +10380,18 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dev": true, "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -8174,20 +10403,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/minimist-options": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", - "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", - "dev": true, - "dependencies": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/minipass": { "version": "7.0.4", "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", @@ -8254,6 +10469,12 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", "dev": true }, + "node_modules/node-abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/node-abort-controller/-/node-abort-controller-3.1.1.tgz", + "integrity": "sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==", + "dev": true + }, "node_modules/node-domexception": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", @@ -8306,21 +10527,6 @@ "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", "dev": true }, - "node_modules/normalize-package-data": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", - "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/normalize-path": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", @@ -8351,6 +10557,18 @@ "node": ">=8" } }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -8531,6 +10749,14 @@ "openai": "bin/cli" } }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.18.tgz", + "integrity": "sha512-80CP7B8y4PzZF0GWx15/gVWRrB5y/bIjNI84NK3cmQJu0WZwvmj2WMA5LcofQFVfLqqCSp545+U2LsrVzX36Zg==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/optionator": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", @@ -8548,6 +10774,36 @@ "node": ">= 0.8.0" } }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/p-map": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz", @@ -8574,15 +10830,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", @@ -8631,18 +10878,6 @@ "node": ">= 0.10" } }, - "node_modules/parseqs": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", - "integrity": "sha512-jeAGzMDbfSHHA091hr0r31eYfTig+29g3GKKE/PPbEQ65X0lmMwlEoqmhzu0iztID5uJpZsFlUPDP8ThPL7M8w==", - "dev": true - }, - "node_modules/parseuri": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.6.tgz", - "integrity": "sha512-AUjen8sAkGgao7UyCX6Ahv0gIK2fABKmYjvP4xmy5JaKvcbTRueIqIPHLAfq30xJddqSE033IOMUSOMCcK3Sow==", - "dev": true - }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -8652,6 +10887,15 @@ "node": ">= 0.8" } }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -8728,6 +10972,18 @@ "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", "dev": true }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/pify": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", @@ -8977,56 +11233,145 @@ "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "dependencies": { - "p-limit": "^2.2.0" + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/possible-typed-array-names": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", + "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-calc": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-9.0.1.tgz", + "integrity": "sha512-TipgjGyzP5QzEhsOZUaIkeO5mKeMFpebWzRogWG/ysonUlnHcq5aJe0jOjpfzUU8PeSaBQnrE8ehR0QA5vs8PQ==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.11", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.2.2" + } + }, + "node_modules/postcss-colormin": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-6.0.3.tgz", + "integrity": "sha512-ECpkS+UZRyAtu/kjive2/1mihP+GNtgC8kcdU8ueWZi1ZVxMNnRziCLdhrWECJhEtSWijfX2Cl9XTTCK/hjGaA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "colord": "^2.9.3", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-convert-values": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-6.0.4.tgz", + "integrity": "sha512-YT2yrGzPXoQD3YeA2kBo/696qNwn7vI+15AOS2puXWEvSWqdCqlOyDWRy5GNnOc9ACRGOkuQ4ESQEqPJBWt/GA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" }, "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "node_modules/postcss-discard-comments": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-6.0.1.tgz", + "integrity": "sha512-f1KYNPtqYLUeZGCHQPKzzFtsHaRuECe6jLakf/RjSRqvF5XHLZnM2+fXLhb8Qh/HBFHs3M4cSLb1k3B899RYIg==", "dev": true, "engines": { - "node": ">=8" + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/possible-typed-array-names": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", - "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==", + "node_modules/postcss-discard-duplicates": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-6.0.2.tgz", + "integrity": "sha512-U2rsj4w6pAGROCCcD13LP2eBIi1whUsXs4kgE6xkIuGfkbxCBSKhkCTWyowFd66WdVlLv0uM1euJKIgmdmZObg==", "dev": true, "engines": { - "node": ">= 0.4" + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/postcss": { - "version": "8.4.35", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", - "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "node_modules/postcss-discard-empty": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-6.0.2.tgz", + "integrity": "sha512-rj6pVC2dVCJrP0Y2RkYTQEbYaCf4HEm+R/2StQgJqGHxAa3+KcYslNQhcRqjLHtl/4wpzipJluaJLqBj6d5eDQ==", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "dependencies": { - "nanoid": "^3.3.7", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "engines": { + "node": "^14 || ^16 || >=18.0" }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-discard-overridden": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-6.0.1.tgz", + "integrity": "sha512-qs0ehZMMZpSESbRkw1+inkf51kak6OOzNRaoLd/U7Fatp0aN2HQ1rxGOrJvYcRAN9VpX8kUF13R2ofn8OlvFVA==", + "dev": true, "engines": { - "node": "^10 || ^12 || >=14" + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, "node_modules/postcss-loader": { @@ -9060,37 +11405,109 @@ } } }, - "node_modules/postcss-loader/node_modules/cosmiconfig": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", - "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", + "dev": true + }, + "node_modules/postcss-merge-longhand": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-6.0.3.tgz", + "integrity": "sha512-kF/y3DU8CRt+SX3tP/aG+2gkZI2Z7OXDsPU7FgxIJmuyhQQ1EHceIYcsp/alvzCm2P4c37Sfdu8nNrHc+YeyLg==", "dev": true, "dependencies": { - "env-paths": "^2.2.1", - "import-fresh": "^3.3.0", - "js-yaml": "^4.1.0", - "parse-json": "^5.2.0" + "postcss-value-parser": "^4.2.0", + "stylehacks": "^6.0.3" }, "engines": { - "node": ">=14" + "node": "^14 || ^16 || >=18.0" }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-merge-rules": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-6.0.4.tgz", + "integrity": "sha512-97iF3UJ5v8N1BWy38y+0l+Z8o5/9uGlEgtWic2PJPzoRrLB6Gxg8TVG93O0EK52jcLeMsywre26AUlX1YAYeHA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0", + "cssnano-utils": "^4.0.1", + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" }, "peerDependencies": { - "typescript": ">=4.9.5" + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-font-values": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-6.0.2.tgz", + "integrity": "sha512-IedzbVMoX0a7VZWjSYr5qJ6C37rws8kl8diPBeMZLJfWKkgXuMFY5R/OxPegn/q9tK9ztd0XRH3aR0u2t+A7uQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" } }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true + "node_modules/postcss-minify-gradients": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-6.0.2.tgz", + "integrity": "sha512-vP5mF7iI6/5fcpv+rSfwWQekOE+8I1i7/7RjZPGuIjj6eUaZVeG4XZYZrroFuw1WQd51u2V32wyQFZ+oYdE7CA==", + "dev": true, + "dependencies": { + "colord": "^2.9.3", + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-params": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-6.0.3.tgz", + "integrity": "sha512-j4S74d3AAeCK5eGdQndXSrkxusV2ekOxbXGnlnZthMyZBBvSDiU34CihTASbJxuVB3bugudmwolS7+Dgs5OyOQ==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-minify-selectors": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-6.0.2.tgz", + "integrity": "sha512-0b+m+w7OAvZejPQdN2GjsXLv5o0jqYHX3aoV0e7RBKPCsB7TYG5KKWBFhGnB/iP3213Ts8c5H4wLPLMm7z28Sg==", + "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } }, "node_modules/postcss-modules-extract-imports": { "version": "3.0.0", @@ -9151,6 +11568,186 @@ "postcss": "^8.1.0" } }, + "node_modules/postcss-normalize-charset": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-6.0.1.tgz", + "integrity": "sha512-aW5LbMNRZ+oDV57PF9K+WI1Z8MPnF+A8qbajg/T8PP126YrGX1f9IQx21GI2OlGz7XFJi/fNi0GTbY948XJtXg==", + "dev": true, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-display-values": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-6.0.1.tgz", + "integrity": "sha512-mc3vxp2bEuCb4LgCcmG1y6lKJu1Co8T+rKHrcbShJwUmKJiEl761qb/QQCfFwlrvSeET3jksolCR/RZuMURudw==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-positions": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-6.0.1.tgz", + "integrity": "sha512-HRsq8u/0unKNvm0cvwxcOUEcakFXqZ41fv3FOdPn916XFUrympjr+03oaLkuZENz3HE9RrQE9yU0Xv43ThWjQg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-repeat-style": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-6.0.1.tgz", + "integrity": "sha512-Gbb2nmCy6tTiA7Sh2MBs3fj9W8swonk6lw+dFFeQT68B0Pzwp1kvisJQkdV6rbbMSd9brMlS8I8ts52tAGWmGQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-string": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-6.0.1.tgz", + "integrity": "sha512-5Fhx/+xzALJD9EI26Aq23hXwmv97Zfy2VFrt5PLT8lAhnBIZvmaT5pQk+NuJ/GWj/QWaKSKbnoKDGLbV6qnhXg==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-timing-functions": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-6.0.1.tgz", + "integrity": "sha512-4zcczzHqmCU7L5dqTB9rzeqPWRMc0K2HoR+Bfl+FSMbqGBUcP5LRfgcH4BdRtLuzVQK1/FHdFoGT3F7rkEnY+g==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-unicode": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-6.0.3.tgz", + "integrity": "sha512-T2Bb3gXz0ASgc3ori2dzjv6j/P2IantreaC6fT8tWjqYUiqMAh5jGIkdPwEV2FaucjQlCLeFJDJh2BeSugE1ig==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-url": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-6.0.1.tgz", + "integrity": "sha512-jEXL15tXSvbjm0yzUV7FBiEXwhIa9H88JOXDGQzmcWoB4mSjZIsmtto066s2iW9FYuIrIF4k04HA2BKAOpbsaQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-normalize-whitespace": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-6.0.1.tgz", + "integrity": "sha512-76i3NpWf6bB8UHlVuLRxG4zW2YykF9CTEcq/9LGAiz2qBuX5cBStadkk0jSkg9a9TCIXbMQz7yzrygKoCW9JuA==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-ordered-values": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-6.0.1.tgz", + "integrity": "sha512-XXbb1O/MW9HdEhnBxitZpPFbIvDgbo9NK4c/5bOfiKpnIGZDoL2xd7/e6jW5DYLsWxBbs+1nZEnVgnjnlFViaA==", + "dev": true, + "dependencies": { + "cssnano-utils": "^4.0.1", + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-initial": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-6.0.3.tgz", + "integrity": "sha512-w4QIR9pEa1N4xMx3k30T1vLZl6udVK2RmNqrDXhBXX9L0mBj2a8ADs8zkbaEH7eUy1m30Wyr5EBgHN31Yq1JvA==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-api": "^3.0.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-reduce-transforms": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-6.0.1.tgz", + "integrity": "sha512-fUbV81OkUe75JM+VYO1gr/IoA2b/dRiH6HvMwhrIBSUrxq3jNZQZitSnugcTLDi1KkQh1eR/zi+iyxviUNBkcQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, "node_modules/postcss-resolve-nested-selector": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz", @@ -9158,19 +11755,29 @@ "dev": true }, "node_modules/postcss-safe-parser": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-6.0.0.tgz", - "integrity": "sha512-FARHN8pwH+WiS2OPCxJI8FuRJpTVnn6ZNFiqAM2aeW2LwTHWWmWgIyKC6cUo0L8aeKiF/14MNvnpls6R2PBeMQ==", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.0.tgz", + "integrity": "sha512-ovehqRNVCpuFzbXoTb4qLtyzK3xn3t/CUBxOs8LsnQjQrShaB4lKiHoVqY8ANaC0hBMHq5QVWk77rwGklFUDrg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" + "node": ">=18.0" }, "peerDependencies": { - "postcss": "^8.3.3" + "postcss": "^8.4.31" } }, "node_modules/postcss-scss": { @@ -9213,12 +11820,43 @@ } }, "node_modules/postcss-sorting": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-7.0.1.tgz", - "integrity": "sha512-iLBFYz6VRYyLJEJsBJ8M3TCqNcckVzz4wFounSc5Oez35ogE/X+aoC5fFu103Ot7NyvjU3/xqIXn93Gp3kJk4g==", + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/postcss-sorting/-/postcss-sorting-8.0.2.tgz", + "integrity": "sha512-M9dkSrmU00t/jK7rF6BZSZauA5MAaBW4i5EnJXspMwt4iqTh/L9j6fgMnbElEOfyRyfLfVbIHj/R52zHzAPe1Q==", + "dev": true, + "peerDependencies": { + "postcss": "^8.4.20" + } + }, + "node_modules/postcss-svgo": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-6.0.2.tgz", + "integrity": "sha512-IH5R9SjkTkh0kfFOQDImyy1+mTCb+E830+9SV1O+AaDcoHTvfsvt6WwJeo7KwcHbFnevZVCsXhDmjFiGVuwqFQ==", + "dev": true, + "dependencies": { + "postcss-value-parser": "^4.2.0", + "svgo": "^3.2.0" + }, + "engines": { + "node": "^14 || ^16 || >= 18" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-unique-selectors": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-6.0.2.tgz", + "integrity": "sha512-8IZGQ94nechdG7Y9Sh9FlIY2b4uS8/k8kdKRX040XHsS3B6d1HrJAkXrBSsSu4SuARruSsUjW3nlSw8BHkaAYQ==", "dev": true, + "dependencies": { + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, "peerDependencies": { - "postcss": "^8.3.9" + "postcss": "^8.4.31" } }, "node_modules/postcss-value-parser": { @@ -9237,15 +11875,15 @@ } }, "node_modules/prettier": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz", - "integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==", + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", "dev": true, "bin": { - "prettier": "bin-prettier.js" + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">=10.13.0" + "node": ">=14" }, "funding": { "url": "https://github.com/prettier/prettier?sponsor=1" @@ -9340,15 +11978,6 @@ } ] }, - "node_modules/quick-lru": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", - "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/randombytes": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", @@ -9398,144 +12027,6 @@ "dev": true, "peer": true }, - "node_modules/read-pkg": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", - "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", - "dev": true, - "dependencies": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", - "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", - "dev": true, - "dependencies": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/read-pkg-up/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg-up/node_modules/type-fest": { - "version": "0.8.1", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", - "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", - "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", - "dev": true - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/read-pkg/node_modules/type-fest": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", - "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/readable-stream": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", @@ -9562,18 +12053,6 @@ "node": ">=8.10.0" } }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -9586,26 +12065,37 @@ "node": ">= 10.13.0" } }, - "node_modules/redent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", - "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "regenerate": "^1.4.2" }, "engines": { - "node": ">=8" + "node": ">=4" } }, - "node_modules/redent/node_modules/indent-string": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", - "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, - "engines": { - "node": ">=8" + "dependencies": { + "@babel/runtime": "^7.8.4" } }, "node_modules/regexp.prototype.flags": { @@ -9626,6 +12116,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dev": true, + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dev": true, + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -9715,6 +12243,15 @@ "parse-uri": "^1.0.0" } }, + "node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/reusify": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", @@ -9726,38 +12263,15 @@ } }, "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, "dependencies": { "glob": "^7.1.3" }, "bin": { "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" } }, "node_modules/run-applescript": { @@ -9813,12 +12327,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/safe-array-concat/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9903,23 +12411,58 @@ } }, "node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", "dev": true, "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" }, "engines": { - "node": ">= 10.13.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "peerDependencies": { + "ajv": "^8.8.2" } }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true + }, "node_modules/select-hose": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", @@ -10205,6 +12748,15 @@ "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", "dev": true }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/slice-ansi": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", @@ -10223,29 +12775,27 @@ } }, "node_modules/socket.io-client": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.3.2.tgz", - "integrity": "sha512-2B9LqSunN60yV8F7S84CCEEcgbYNfrn7ejIInZtLZ7ppWtiX8rGZAjvdCvbnC8bqo/9RlCNOUsORLyskxSFP1g==", + "version": "4.7.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.4.tgz", + "integrity": "sha512-wh+OkeF0rAVCrABWQBaEjLfb7DVPotMbu0cgWgyR0v6eA4EoVnAwcIeIbcdTE3GT/H3kbdLl7OoH2+asoDRIIg==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.0.0", - "backo2": "~1.0.2", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.2", - "engine.io-client": "~6.0.1", - "parseuri": "0.0.6", - "socket.io-parser": "~4.1.1" + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" }, "engines": { "node": ">=10.0.0" } }, "node_modules/socket.io-parser": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.1.2.tgz", - "integrity": "sha512-j3kk71QLJuyQ/hh5F/L2t1goqzdTL0gvDzuhTuNSwihfuFUrcSji0qFZmJJPtG6Rmug153eOPsUizeirf1IIog==", + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.0.0", + "@socket.io/component-emitter": "~3.1.0", "debug": "~4.3.1" }, "engines": { @@ -10291,26 +12841,6 @@ "source-map": "^0.6.0" } }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", - "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/spdx-exceptions": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", @@ -10496,18 +13026,6 @@ "node": ">=6" } }, - "node_modules/strip-indent": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", - "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", - "dev": true, - "dependencies": { - "min-indent": "^1.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -10536,219 +13054,220 @@ "webpack": "^5.0.0" } }, - "node_modules/style-search": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/style-search/-/style-search-0.1.0.tgz", - "integrity": "sha512-Dj1Okke1C3uKKwQcetra4jSuk0DqbzbYtXipzFlFMZtowbF1x7BKJwB9AayVMyFARvU8EDrZdcax4At/452cAg==", - "dev": true + "node_modules/stylehacks": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/stylehacks/-/stylehacks-6.0.3.tgz", + "integrity": "sha512-KzBqjnqktc8/I0ERCb+lGq06giF/JxDbw2r9kEVhen9noHeIDRtMWUp9r62sOk+/2bbX6sFG1GhsS7ToXG0PEg==", + "dev": true, + "dependencies": { + "browserslist": "^4.23.0", + "postcss-selector-parser": "^6.0.15" + }, + "engines": { + "node": "^14 || ^16 || >=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } }, "node_modules/stylelint": { - "version": "14.16.1", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-14.16.1.tgz", - "integrity": "sha512-ErlzR/T3hhbV+a925/gbfc3f3Fep9/bnspMiJPorfGEmcBbXdS+oo6LrVtoUZ/w9fqD6o6k7PtUlCOsCRdjX/A==", + "version": "16.2.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.2.1.tgz", + "integrity": "sha512-SfIMGFK+4n7XVAyv50CpVfcGYWG4v41y6xG7PqOgQSY8M/PgdK0SQbjWFblxjJZlN9jNq879mB4BCZHJRIJ1hA==", "dev": true, "dependencies": { - "@csstools/selector-specificity": "^2.0.2", + "@csstools/css-parser-algorithms": "^2.5.0", + "@csstools/css-tokenizer": "^2.2.3", + "@csstools/media-query-list-parser": "^2.1.7", + "@csstools/selector-specificity": "^3.0.1", "balanced-match": "^2.0.0", "colord": "^2.9.3", - "cosmiconfig": "^7.1.0", - "css-functions-list": "^3.1.0", + "cosmiconfig": "^9.0.0", + "css-functions-list": "^3.2.1", + "css-tree": "^2.3.1", "debug": "^4.3.4", - "fast-glob": "^3.2.12", + "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^6.0.1", + "file-entry-cache": "^8.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", - "html-tags": "^3.2.0", - "ignore": "^5.2.1", - "import-lazy": "^4.0.0", + "html-tags": "^3.3.1", + "ignore": "^5.3.0", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.26.0", + "known-css-properties": "^0.29.0", "mathml-tag-names": "^2.1.3", - "meow": "^9.0.0", + "meow": "^13.1.0", "micromatch": "^4.0.5", "normalize-path": "^3.0.0", "picocolors": "^1.0.0", - "postcss": "^8.4.19", - "postcss-media-query-parser": "^0.2.3", + "postcss": "^8.4.33", "postcss-resolve-nested-selector": "^0.1.1", - "postcss-safe-parser": "^6.0.0", - "postcss-selector-parser": "^6.0.11", + "postcss-safe-parser": "^7.0.0", + "postcss-selector-parser": "^6.0.15", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "style-search": "^0.1.0", - "supports-hyperlinks": "^2.3.0", + "strip-ansi": "^7.1.0", + "supports-hyperlinks": "^3.0.0", "svg-tags": "^1.0.0", "table": "^6.8.1", - "v8-compile-cache": "^2.3.0", - "write-file-atomic": "^4.0.2" + "write-file-atomic": "^5.0.1" }, "bin": { - "stylelint": "bin/stylelint.js" + "stylelint": "bin/stylelint.mjs" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18.12.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/stylelint" } }, - "node_modules/stylelint-config-prettier": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/stylelint-config-prettier/-/stylelint-config-prettier-9.0.5.tgz", - "integrity": "sha512-U44lELgLZhbAD/xy/vncZ2Pq8sh2TnpiPvo38Ifg9+zeioR+LAkHu0i6YORIOxFafZoVg0xqQwex6e6F25S5XA==", - "dev": true, - "bin": { - "stylelint-config-prettier": "bin/check.js", - "stylelint-config-prettier-check": "bin/check.js" - }, - "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "stylelint": ">= 11.x < 15" - } - }, "node_modules/stylelint-config-prettier-scss": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/stylelint-config-prettier-scss/-/stylelint-config-prettier-scss-0.0.1.tgz", - "integrity": "sha512-lBAYG9xYOh2LeWEPC/64xeUxwOTnQ8nDyBijQoWoJb10/bMGrUwnokpt8jegGck2Vbtxh6XGwH63z5qBcVHreQ==", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-prettier-scss/-/stylelint-config-prettier-scss-1.0.0.tgz", + "integrity": "sha512-Gr2qLiyvJGKeDk0E/+awNTrZB/UtNVPLqCDOr07na/sLekZwm26Br6yYIeBYz3ulsEcQgs5j+2IIMXCC+wsaQA==", "dev": true, - "dependencies": { - "stylelint-config-prettier": ">=9.0.3" - }, "bin": { "stylelint-config-prettier-scss": "bin/check.js", "stylelint-config-prettier-scss-check": "bin/check.js" }, "engines": { - "node": ">= 12" + "node": "14.* || 16.* || >= 18" }, "peerDependencies": { - "stylelint": ">=11.0.0" + "stylelint": ">=15.0.0" } }, "node_modules/stylelint-config-recess-order": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-3.1.0.tgz", - "integrity": "sha512-LXR6zD5O9cS1a9gbLbuKvWLs7qmHj4xm5MQ5KhhwZPMhtQP9da3F6Jsp/NAUdsAwDQEnT1ShU16YVdgN6p4a/w==", + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recess-order/-/stylelint-config-recess-order-4.6.0.tgz", + "integrity": "sha512-V76fhv3YtcNXh/hyAuAdSzi5FmcrG54Mp2AThJ3D/PTMTSYzUPd7GIhP6z9mTqnRhmkk6YTfcu/JWB8h+Yrcaw==", "dev": true, "dependencies": { - "stylelint-order": "5.x" + "stylelint-order": "6.x" }, "peerDependencies": { - "stylelint": ">=14" + "stylelint": ">=15" } }, "node_modules/stylelint-config-recommended": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-9.0.0.tgz", - "integrity": "sha512-9YQSrJq4NvvRuTbzDsWX3rrFOzOlYBmZP+o513BJN/yfEmGSr0AxdvrWs0P/ilSpVV/wisamAHu5XSk8Rcf4CQ==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz", + "integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==", "dev": true, + "engines": { + "node": ">=18.12.0" + }, "peerDependencies": { - "stylelint": "^14.10.0" + "stylelint": "^16.0.0" } }, "node_modules/stylelint-config-recommended-scss": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-7.0.0.tgz", - "integrity": "sha512-rGz1J4rMAyJkvoJW4hZasuQBB7y9KIrShb20l9DVEKKZSEi1HAy0vuNlR8HyCKy/jveb/BdaQFcoiYnmx4HoiA==", + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended-scss/-/stylelint-config-recommended-scss-14.0.0.tgz", + "integrity": "sha512-HDvpoOAQ1RpF+sPbDOT2Q2/YrBDEJDnUymmVmZ7mMCeNiFSdhRdyGEimBkz06wsN+HaFwUh249gDR+I9JR7Onw==", "dev": true, "dependencies": { - "postcss-scss": "^4.0.2", - "stylelint-config-recommended": "^8.0.0", - "stylelint-scss": "^4.0.0" + "postcss-scss": "^4.0.9", + "stylelint-config-recommended": "^14.0.0", + "stylelint-scss": "^6.0.0" + }, + "engines": { + "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^14.4.0" - } - }, - "node_modules/stylelint-config-recommended-scss/node_modules/stylelint-config-recommended": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", - "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", - "dev": true, - "peerDependencies": { - "stylelint": "^14.8.0" + "postcss": "^8.3.3", + "stylelint": "^16.0.2" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, "node_modules/stylelint-config-standard": { - "version": "29.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-29.0.0.tgz", - "integrity": "sha512-uy8tZLbfq6ZrXy4JKu3W+7lYLgRQBxYTUUB88vPgQ+ZzAxdrvcaSUW9hOMNLYBnwH+9Kkj19M2DHdZ4gKwI7tg==", + "version": "36.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-36.0.0.tgz", + "integrity": "sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==", "dev": true, "dependencies": { - "stylelint-config-recommended": "^9.0.0" + "stylelint-config-recommended": "^14.0.0" + }, + "engines": { + "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^14.14.0" + "stylelint": "^16.1.0" } }, "node_modules/stylelint-config-standard-scss": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-5.0.0.tgz", - "integrity": "sha512-zoXLibojHZYPFjtkc4STZtAJ2yGTq3Bb4MYO0oiyO6f/vNxDKRcSDZYoqN260Gv2eD5niQIr1/kr5SXlFj9kcQ==", + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/stylelint-config-standard-scss/-/stylelint-config-standard-scss-13.0.0.tgz", + "integrity": "sha512-WaLvkP689qSYUpJQPCo30TFJSSc3VzvvoWnrgp+7PpVby5o8fRUY1cZcP0sePZfjrFl9T8caGhcKg0GO34VDiQ==", "dev": true, "dependencies": { - "stylelint-config-recommended-scss": "^7.0.0", - "stylelint-config-standard": "^26.0.0" + "stylelint-config-recommended-scss": "^14.0.0", + "stylelint-config-standard": "^36.0.0" }, - "peerDependencies": { - "stylelint": "^14.9.0" - } - }, - "node_modules/stylelint-config-standard-scss/node_modules/stylelint-config-recommended": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-8.0.0.tgz", - "integrity": "sha512-IK6dWvE000+xBv9jbnHOnBq01gt6HGVB2ZTsot+QsMpe82doDQ9hvplxfv4YnpEuUwVGGd9y6nbaAnhrjcxhZQ==", - "dev": true, - "peerDependencies": { - "stylelint": "^14.8.0" - } - }, - "node_modules/stylelint-config-standard-scss/node_modules/stylelint-config-standard": { - "version": "26.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-26.0.0.tgz", - "integrity": "sha512-hUuB7LaaqM8abvkOO84wh5oYSkpXgTzHu2Zza6e7mY+aOmpNTjoFBRxSLlzY0uAOMWEFx0OMKzr+reG1BUtcqQ==", - "dev": true, - "dependencies": { - "stylelint-config-recommended": "^8.0.0" + "engines": { + "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^14.9.0" + "postcss": "^8.3.3", + "stylelint": "^16.1.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + } } }, "node_modules/stylelint-order": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-5.0.0.tgz", - "integrity": "sha512-OWQ7pmicXufDw5BlRqzdz3fkGKJPgLyDwD1rFY3AIEfIH/LQY38Vu/85v8/up0I+VPiuGRwbc2Hg3zLAsJaiyw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/stylelint-order/-/stylelint-order-6.0.4.tgz", + "integrity": "sha512-0UuKo4+s1hgQ/uAxlYU4h0o0HS4NiQDud0NAUNI0aa8FJdmYHA5ZZTFHiV5FpmE3071e9pZx5j0QpVJW5zOCUA==", "dev": true, "dependencies": { - "postcss": "^8.3.11", - "postcss-sorting": "^7.0.1" + "postcss": "^8.4.32", + "postcss-sorting": "^8.0.2" }, "peerDependencies": { - "stylelint": "^14.0.0" + "stylelint": "^14.0.0 || ^15.0.0 || ^16.0.1" } }, "node_modules/stylelint-scss": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-4.7.0.tgz", - "integrity": "sha512-TSUgIeS0H3jqDZnby1UO1Qv3poi1N8wUYIJY6D1tuUq2MN3lwp/rITVo0wD+1SWTmRm0tNmGO0b7nKInnqF6Hg==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/stylelint-scss/-/stylelint-scss-6.1.0.tgz", + "integrity": "sha512-kCfK8TQzthGwb4vaZniZgxRsVbCM4ZckmT1b/H5m4FU3I8Dz0id9llKsy1NMp3XXqC8+OPD4rVKtUbSxXlJb5g==", "dev": true, "dependencies": { + "known-css-properties": "^0.29.0", "postcss-media-query-parser": "^0.2.3", "postcss-resolve-nested-selector": "^0.1.1", - "postcss-selector-parser": "^6.0.11", + "postcss-selector-parser": "^6.0.15", "postcss-value-parser": "^4.2.0" }, + "engines": { + "node": ">=18.12.0" + }, "peerDependencies": { - "stylelint": "^14.5.1 || ^15.0.0" + "stylelint": "^16.0.2" + } + }, + "node_modules/stylelint/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/stylelint/node_modules/balanced-match": { @@ -10757,6 +13276,54 @@ "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", "dev": true }, + "node_modules/stylelint/node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/stylelint/node_modules/flat-cache": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.0.tgz", + "integrity": "sha512-EryKbCE/wxpxKniQlyas6PY1I9vwtF3uCBweX+N8KYTCn3Y12RTGtQAJ/bd5pl7kxUAc8v/R3Ake/N17OZiFqA==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4", + "rimraf": "^5.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/stylelint/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dev": true, + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/stylelint/node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -10766,6 +13333,39 @@ "node": ">=8" } }, + "node_modules/stylelint/node_modules/rimraf": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", + "integrity": "sha512-CqDakW+hMe/Bz202FPEymy68P+G50RfMQK+Qo5YUqc9SPipvbGjCGKd0RSKEelbsfQuw3g5NZDSrlZZAJurH1A==", + "dev": true, + "dependencies": { + "glob": "^10.3.7" + }, + "bin": { + "rimraf": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/stylelint/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dev": true, + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -10779,16 +13379,16 @@ } }, "node_modules/supports-hyperlinks": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.3.0.tgz", - "integrity": "sha512-RpsAZlpWcDwOPQA22aCH4J0t7L8JmAvsCxfOSEwm7cQs3LshN36QaTkwd70DnBOXDWGssw2eUoc8CaRWT0XunA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.0.0.tgz", + "integrity": "sha512-QBDPHyPQDRTy9ku4URNGY5Lah8PAaXs6tAAwp55sL5WCsSW7GIfdf6W5ixfziW+t7wh3GVvHyHHyQ1ESsoRvaA==", "dev": true, "dependencies": { "has-flag": "^4.0.0", "supports-color": "^7.0.0" }, "engines": { - "node": ">=8" + "node": ">=14.18" } }, "node_modules/supports-preserve-symlinks-flag": { @@ -10809,6 +13409,40 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "node_modules/svgo": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.2.0.tgz", + "integrity": "sha512-4PP6CMW/V7l/GmKRKzsLR8xxjdHTV4IMvhTnpuHwwBazSIlw5W/5SmPjN8Dwyt7lKbSJrRDgp4t9ph0HgChFBQ==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, "node_modules/table": { "version": "6.8.1", "resolved": "https://registry.npmjs.org/table/-/table-6.8.1.tgz", @@ -10908,22 +13542,24 @@ } } }, - "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { - "version": "0.3.23", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.23.tgz", - "integrity": "sha512-9/4foRoUKp8s96tSkh8DlAAc5A0Ty8vLXld+l9gjKKY6ckwI8G15f0hskGmuLZu78ZlGa1vtsfOa+lnB4vG6Jg==", + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", "dev": true, "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -10976,15 +13612,6 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", - "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, "node_modules/ts-api-utils": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", @@ -11006,31 +13633,15 @@ "chalk": "^4.1.0", "enhanced-resolve": "^5.0.0", "micromatch": "^4.0.0", - "semver": "^7.3.4", - "source-map": "^0.7.4" - }, - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "typescript": "*", - "webpack": "^5.0.0" - } - }, - "node_modules/ts-loader/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "semver": "^7.3.4", + "source-map": "^0.7.4" }, "engines": { - "node": ">=10" + "node": ">=12.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "peerDependencies": { + "typescript": "*", + "webpack": "^5.0.0" } }, "node_modules/ts-loader/node_modules/source-map": { @@ -11042,49 +13653,6 @@ "node": ">= 8" } }, - "node_modules/ts-node": { - "version": "10.9.2", - "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", - "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", - "dev": true, - "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } - } - }, "node_modules/tsconfig-paths": { "version": "3.15.0", "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", @@ -11298,6 +13866,67 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -11386,38 +14015,6 @@ "uuid": "dist/bin/uuid" } }, - "node_modules/v8-compile-cache": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.4.0.tgz", - "integrity": "sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", - "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", - "dev": true - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", - "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, "node_modules/vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -11591,59 +14188,6 @@ } } }, - "node_modules/webpack-dev-middleware/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-middleware/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-middleware/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-middleware/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-dev-server": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.0.2.tgz", @@ -11703,43 +14247,6 @@ } } }, - "node_modules/webpack-dev-server/node_modules/ajv": { - "version": "8.12.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", - "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/webpack-dev-server/node_modules/ajv-keywords": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", - "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.3" - }, - "peerDependencies": { - "ajv": "^8.8.2" - } - }, - "node_modules/webpack-dev-server/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/webpack-dev-server/node_modules/glob": { "version": "10.3.10", "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", @@ -11762,27 +14269,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "dev": true - }, - "node_modules/webpack-dev-server/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/webpack-dev-server/node_modules/rimraf": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-5.0.5.tgz", @@ -11801,25 +14287,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webpack-dev-server/node_modules/schema-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", - "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, - "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, "node_modules/webpack-dev-server/node_modules/ws": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", @@ -11886,6 +14353,24 @@ "node": ">=4.0" } }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", @@ -12021,22 +14506,34 @@ "dev": true }, "node_modules/write-file-atomic": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", - "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", + "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, "dependencies": { "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.7" + "signal-exit": "^4.0.1" }, "engines": { - "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/write-file-atomic/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/ws": { - "version": "8.2.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.2.3.tgz", - "integrity": "sha512-wBuoj1BDpC6ZQ1B7DWQBYVLphPWkm8i9Y0/3YdHjHKHiohOJ1ws+3OccDWtH+PoC9DZD5WOTrJvNbWvjS6JWaA==", + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", "dev": true, "engines": { "node": ">=10.0.0" @@ -12077,15 +14574,6 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, - "node_modules/yaml": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", - "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -12104,15 +14592,6 @@ } }, "node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs/node_modules/yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", @@ -12120,19 +14599,16 @@ "node": ">=12" } }, - "node_modules/yeast": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", - "integrity": "sha512-8HFIh676uyGYP6wP13R/j6OJ/1HwJ46snpvzE7aHAN3Ryqh2yX6Xox2B4CUmTwwOIzlG3Bs7ocsP5dZH/R1Qbg==", - "dev": true - }, - "node_modules/yn": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", - "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "dev": true, "engines": { - "node": ">=6" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } } } diff --git a/package.json b/package.json index da323e5e..39e6b6c8 100644 --- a/package.json +++ b/package.json @@ -2,9 +2,11 @@ "name": "eunos-blades", "version": "0.1.0", "description": "An implementation of Kult: Divinity Lost (4th Edition), based on the original Kult 4E Foundry system by Tom LaPorta.", - "scripts": { - "preinstall": "npx npm-force-resolutions" - }, + "scripts": { + "webpack:watch": "webpack --config webpack.dev.js --watch", + "foundry:serve": "node 'D:/LTSC Programs/FoundryVTT/Foundry Virtual Tabletop/resources/app/main.js' --world=city-of-knives --dataPath='D:/Users/Ryan/Documents/Projects/.CODING/FoundryVTT/FoundryDevData' --hotReload" + }, + "type": "module", "browserslist": [ "last 3 versions" ], @@ -12,50 +14,61 @@ "license": "", "private": true, "devDependencies": { + "@babel/core": "^7.23.9", + "@babel/preset-env": "^7.23.9", + "@babel/preset-typescript": "^7.23.3", "@league-of-foundry-developers/foundry-vtt-types": "^9.280.0", "@types/babel__core": "^7.20.5", - "@types/jquery": "^3.5.27", - "@types/node": "^18.11.4", + "@types/jquery": "^3.5.29", + "@types/node": "^20.11.20", "@typescript-eslint/eslint-plugin": "^7.0.2", "@typescript-eslint/parser": "^7.0.2", "@yaireo/tagify": "^4.17.8", "autoprefixer": "^10.4.17", + "babel-loader": "^9.1.3", "clean-webpack-plugin": "^4.0.0", + "copy-webpack-plugin": "^12.0.2", "css-loader": "^6.10.0", + "css-minimizer-webpack-plugin": "^6.0.0", "eslint": "^8.57.0", "eslint-import-resolver-node": "^0.3.9", "eslint-plugin-etc": "^2.0.3", - "eslint-plugin-import": "^2.26", - "eslint-plugin-jsdoc": "^46.9.0", - "handlebars": "^4.7", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-jsdoc": "^48.2.0", + "fork-ts-checker-webpack-plugin": "^9.0.2", + "handlebars": "^4.7.7", "mini-css-extract-plugin": "^2.8.0", - "postcss": "^8.4.18", + "postcss": "^8.4.35", "postcss-loader": "^8.1.0", - "postcss-scss": "^4.0.5", - "prettier": "2.7.1", + "postcss-scss": "^4.0.9", + "prettier": "^3.2.5", "sass-loader": "^14.1.1", "style-loader": "^3.3.4", - "stylelint": "^14.14.0", - "stylelint-config-prettier": "^9.0.3", - "stylelint-config-prettier-scss": "^0.0.1", - "stylelint-config-recess-order": "^3.0.0", - "stylelint-config-standard": "^29.0.0", - "stylelint-config-standard-scss": "^5.0.0", + "stylelint": "^16.2.1", + "stylelint-config-prettier-scss": "^1.0.0", + "stylelint-config-recess-order": "^4.6.0", + "stylelint-config-standard": "^36.0.0", + "stylelint-config-standard-scss": "^13.0.0", + "terser-webpack-plugin": "^5.3.10", "ts-loader": "^9.5.1", - "ts-node": "^10.9.1", "typescript": "^5.3.3", "webpack": "^5.90.3", "webpack-cli": "^5.1.4", - "webpack-dev-server": "^5.0.2" + "webpack-dev-server": "^5.0.2", + "webpack-merge": "^5.10.0" }, "dependencies": { "@types/yaireo__tagify": "^4.17.0", "axios": "^1.5.1", "form-data": "^4.0.0", "openai": "^4.20.0", - "tinymce": "^6.2.0", + "tinymce": "^6.7.1", "yargs": "^17.7.2" }, + "overrides": { + "tinymce": "^6.7.1", + "socket.io-client": "^4.6.1" + }, "repository": { "url": "" } diff --git a/run-webpack.js b/run-webpack.js new file mode 100644 index 00000000..bedb0c7b --- /dev/null +++ b/run-webpack.js @@ -0,0 +1,106 @@ +import webpack from "webpack"; +import { exec } from "child_process"; +import webpackDevConfig from "./webpack.dev.js"; +import webpackProdConfigPromise from "./webpack.prod.js"; + +// Determine the mode based on the command-line argument +const mode = process.argv.includes("--prod") ? "production" : "development"; + +// Function to asynchronously select and load the appropriate Webpack configuration +async function selectConfig() { + if (mode === "production") { + // Await the resolution of the webpackProdConfig promise + return await webpackProdConfigPromise; + } else { + // Directly return the development config if not in production mode + return webpackDevConfig; + } +} + +// Wrap the Webpack build process in a promise to handle it asynchronously +async function runWebpackBuild() { + const config = await selectConfig(); + return new Promise((resolve, reject) => { + webpack(config, (err, stats) => { + if (err) { + console.error("[runWebpackBuild] Webpack build error:", err); + reject(err); + return; + } + console.log("[runWebpackBuild] Webpack build stats:", stats.toString({ colors: true })); // Output build stats + resolve(); + }); + }); +} + +// Function to start the Foundry server using Node's child_process.exec +function startFoundryServer() { + return new Promise((resolve, reject) => { + const serverProcess = exec("node \"D:/LTSC Programs/FoundryVTT/Foundry Virtual Tabletop/resources/app/main.js\" --world=city-of-knives --dataPath=\"D:/Users/Ryan/Documents/Projects/.CODING/FoundryVTT/FoundryDevData\" --hotReload", + (error, stdout, stderr) => { + if (error) { + console.error(`[startFoundryServer] exec error: ${error}`); + reject(error); + return; + } + // Log any output received directly from the exec call + if (stdout) console.log(`[startFoundryServer] stdout: ${stdout}`); + if (stderr) console.error(`[startFoundryServer] stderr: ${stderr}`); + }); + + serverProcess.stdout.on("data", (data) => { + console.log(data); + if (data.includes("Server started and listening")) { + console.log("[startFoundryServer] RESOLVING!"); + resolve(); + } + }); + + // Handle any errors that occur during the process execution + serverProcess.on("error", (error) => { + console.error(`[startFoundryServer] exec error: ${error}`); + reject(error); + }); + }); +} + + + +// Function to open Chrome in debug mode +function openChromeDebugSession() { + exec("cmd /c start \"\" \"C:\\Program Files\\Google\\Chrome\\Application\\chrome.exe\" --remote-debugging-port=9222 --auto-open-devtools-for-tabs --user-data-dir='C:/temp/chrome_dev_test' http://localhost:30000", + (error, stdout, stderr) => { + if (error) { + console.error("[openChromeDebugSession] exec error:", error); + } else { + console.log("[openChromeDebugSession] stdout:", stdout); + console.error("[openChromeDebugSession] stderr:", stderr); + } + }); +// exec("cmd /c start chrome --start-maximized --remote-debugging-port=9222 --auto-open-devtools-for-tabs --user-data-dir='C:/temp/chrome_dev_test' http://localhost:30000 http://localhost:30000", +// (error, stdout, stderr) => { +// if (error) { +// console.error("[openChromeDebugSession] exec error:", error); +// return; +// } +// console.log("[openChromeDebugSession] stdout:", stdout); +// console.error("[openChromeDebugSession] stderr:", stderr); +// }); +} + +// Orchestrating the sequence +async function runProcess() { + try { + await runWebpackBuild(); + if (mode === "development") { + // Only run these in development mode + await startFoundryServer(); + console.log("[runProcess] Awaited Foundry Server, Calling openChromeDebugSession()"); + openChromeDebugSession(); + } + } catch(error) { + console.error("[runProcess] An error occurred during the development process:", error); + } +} + +runProcess().catch((error) => console.error("[runProcess] Failed to run the process:", error)); diff --git a/ts/@types/blades-item.d.ts b/ts/@types/blades-item.d.ts index a8971387..5265f0d5 100644 --- a/ts/@types/blades-item.d.ts +++ b/ts/@types/blades-item.d.ts @@ -1,14 +1,14 @@ import { BladesItemType, ClockColor, District, BladesPhase, Randomizers } from "../core/constants"; import BladesItem from "../BladesItem"; -import BladesPC from "../documents/actors/BladesPC.js"; -import BladesCrew from "../documents/actors/BladesCrew.js"; -import BladesNPC from "../documents/actors/BladesNPC.js"; -import BladesFaction from "../documents/actors/BladesFaction.js"; +import BladesPC from "../documents/actors/BladesPC"; +import BladesCrew from "../documents/actors/BladesCrew"; +import BladesNPC from "../documents/actors/BladesNPC"; +import BladesFaction from "../documents/actors/BladesFaction"; import BladesClockKeeper from '../documents/items/BladesClockKeeper.js'; import BladesGMTracker from '../documents/items/BladesGMTracker.js'; -import BladesLocation from "../documents/items/BladesLocation.js"; -import BladesScore from "../documents/items/BladesScore.js"; -import BladesProject from "../documents/items/BladesProject.js"; +import BladesLocation from "../documents/items/BladesLocation"; +import BladesScore from "../documents/items/BladesScore"; +import BladesProject from "../documents/items/BladesProject"; declare global { diff --git a/ts/core/constants.ts b/ts/core/constants.ts index b26ffb61..0efe5268 100644 --- a/ts/core/constants.ts +++ b/ts/core/constants.ts @@ -552,7 +552,7 @@ const C = { [RollResult.fail]: "You fail from a desperate position!" } }, - // + Colors: { /* IMPORT FROM CSS via css-loader */ bWHITE: "rgba(255, 255, 255, 1)", WHITE: "rgba(200, 200, 200, 1)", diff --git a/ts/core/tags.ts b/ts/core/tags.ts index 388ad1cc..0fef3c97 100644 --- a/ts/core/tags.ts +++ b/ts/core/tags.ts @@ -1,4 +1,4 @@ -import Tagify from "../../lib/tagify/tagify.esm.js"; +import Tagify from "../../lib/tagify/tagify.esm"; import {Tag, MainDistrict, OtherDistrict, Vice, Playbook, BladesActorType} from "./constants"; import U from "./utilities"; diff --git a/webpack.common.js b/webpack.common.js new file mode 100644 index 00000000..09a29ce9 --- /dev/null +++ b/webpack.common.js @@ -0,0 +1,11 @@ + +export default { + // Entry point for your application + entry: "./ts/blades.ts", // Adjust this path to your main JavaScript file + resolve: { + extensions: [".ts", ".js"] + }, + externals: { + "gsap/all": "gsap" + } +}; diff --git a/webpack.config.js b/webpack.config.js deleted file mode 100644 index 5f61c5c1..00000000 --- a/webpack.config.js +++ /dev/null @@ -1,87 +0,0 @@ -import path from "path"; -import { fileURLToPath } from "url"; -import { readdir, stat } from "fs/promises"; -import HtmlWebpackPlugin from "html-webpack-plugin"; -import { CleanWebpackPlugin } from "clean-webpack-plugin"; - -// Convert __dirname in CommonJS to work with ES Modules -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// Async function to recursively find all .ts files in a directory -async function findModules(dir, modules = {}) { - const files = await readdir(dir); - - for (const file of files) { - const fullPath = path.join(dir, file); - const fileStat = await stat(fullPath); - - if (fileStat.isDirectory()) { - await findModules(fullPath, modules); - } else if (file.endsWith(".ts") && !file.endsWith(".d.ts")) { - // Assuming the module's entry file has the same name as its directory - const moduleName = path.basename(path.dirname(fullPath)); - // Key: module name, Value: path to the .ts file - modules[moduleName] = fullPath; - } - } - - return modules; -} - -// Self-invoking async function to generate entry points -const entryPoints = (async () => { - const entries = await findModules(path.resolve(__dirname, "src")); - return entries; -})(); - -export default (async () => ({ - // Entry points for the application - where webpack starts bundling, derived from src folder structure - entry: await entryPoints, - // Output configuration - where to output the bundled files - output: { - filename: "[name]/[name].js", // Output each module to its own directory - path: path.resolve(__dirname, "dist"), - }, - // Mode - affects built-in optimizations; "development" for readable output, "production" for minification - mode: "development", - // Devtool - controls how source maps are generated, if at all. Useful for debugging. - devtool: "source-map", - // Module - configure how modules are treated - module: { - rules: [ - { - // Test for TypeScript files using a regex - test: /\.ts$/, - // Use the ts-loader for transpiling TypeScript files - use: "ts-loader", - // Exclude node_modules directory from transpilation - exclude: /node_modules/, - }, - { - // Test for CSS files - test: /\.css$/, - // Use style-loader and css-loader for injecting CSS into the DOM and understanding CSS imports - use: ["style-loader", "css-loader"], - }, - // Add more loaders here for other file types - ], - }, - // Resolve - configure how modules are resolved - resolve: { - // Automatically resolve these extensions - allows importing without specifying these extensions - extensions: [".ts", ".js"], - }, - optimization: { - minimize: false, // Explicitly disable code minimization - }, - // Plugins - add additional functionality to the compilation process - plugins: [ - // CleanWebpackPlugin - cleans the output directory before each build - new CleanWebpackPlugin(), - // HtmlWebpackPlugin - generates an HTML file, injects scripts into it, and outputs it to the dist directory - new HtmlWebpackPlugin({ - template: "./src/index.html", // Path to the HTML template - }) - ], -}))(); \ No newline at end of file diff --git a/webpack.dev.js b/webpack.dev.js new file mode 100644 index 00000000..af3d2ca1 --- /dev/null +++ b/webpack.dev.js @@ -0,0 +1,74 @@ +// Import necessary Node.js path module for path operations +import path from "path"; +import { fileURLToPath } from "url"; +// Import the function to merge webpack configurations +import { merge } from "webpack-merge"; +// Import the common webpack configuration +import common from "./webpack.common.js"; +// Import the plugin for running TypeScript type checking in a separate process +import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin"; + +// Convert the URL to a path +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default merge(common, { + // Set the mode to development to enable webpack's built-in optimizations for development + mode: "development", + + // Configure how the output files are named and where they are stored + output: { + filename: "blades.js", // Name of the generated JavaScript bundle + path: path.resolve(__dirname, "module") // Output directory for the bundle + }, + + // Define rules for how different types of modules (files) will be treated + module: { + rules: [ + { + test: /\.ts$/, // Apply this rule to files ending in .ts + use: [ + { + loader: "ts-loader", // Use ts-loader to transpile TypeScript files + options: { + transpileOnly: true // Skip type checking for faster builds + } + } + ], + exclude: /node_modules/ // Do not apply this rule to files in node_modules + }, + { + test: /\.js$/, // Apply this rule to files ending in .js + exclude: /node_modules/, // Do not apply this rule to files in node_modules + use: { + loader: "babel-loader", // Use babel-loader to transpile JavaScript files + options: { + presets: ["@babel/preset-env"] // Use @babel/preset-env for transpiling modern JavaScript to compatible JavaScript + } + } + }, + { + test: /\.scss$/, // Apply this rule to files ending in .scss + use: [ + "style-loader", // Injects CSS into the DOM via a