UNPKG

gitlab-ci-local

Version:

Tired of pushing to test your .gitlab-ci.yml?

393 lines 59.7 kB
import "./global.js"; import { RE2JS } from "re2js"; import chalk from "chalk"; import { Job } from "./job.js"; import fs from "fs-extra"; import checksum from "checksum"; import base64url from "base64url"; import execa from "execa"; import assert from "assert"; import { GitData } from "./git-data.js"; import globby from "globby"; import micromatch from "micromatch"; import axios from "axios"; import path from "path"; export class Utils { static bashMulti(scripts, cwd = process.cwd()) { return execa(scripts.join(" && \\"), { shell: "bash", cwd }); } static bash(shellScript, cwd = process.cwd()) { return execa(shellScript, { shell: "bash", cwd }); } static spawn(cmdArgs, cwd = process.cwd()) { return execa(cmdArgs[0], cmdArgs.slice(1), { cwd }); } static syncSpawn(cmdArgs, cwd = process.cwd()) { return execa.sync(cmdArgs[0], cmdArgs.slice(1), { cwd }); } static fsUrl(url) { return url.replace(/^https:\/\//g, "").replace(/^http:\/\//g, ""); } static safeDockerString(jobName) { return jobName.replace(/[^\w-]+/g, (match) => { return base64url.encode(match); }); } static safeBashString(s) { return `'${s.replace(/'/g, "'\"'\"'")}'`; // replaces `'` with `'"'"'` } static forEachRealJob(gitlabData, callback) { for (const [jobName, jobData] of Object.entries(gitlabData)) { if (Job.illegalJobNames.has(jobName) || jobName[0].startsWith(".")) { continue; } callback(jobName, jobData); } } static getJobNamesFromPreviousStages(jobs, stages, currentJob) { const jobNames = []; const currentStageIndex = stages.indexOf(currentJob.stage); jobs.forEach(job => { const stageIndex = stages.indexOf(job.stage); if (stageIndex < currentStageIndex) { jobNames.push(job.name); } }); return jobNames; } static async getCoveragePercent(cwd, stateDir, coverageRegex, jobName) { const content = await fs.readFile(`${cwd}/${stateDir}/output/${jobName}.log`, "utf8"); const regex = RE2JS.compile(coverageRegex .replace(/^\//, "") .replace(/\/$/, ""), RE2JS.MULTILINE); const matches = Array.from(content.matchAllRE2JS(regex)); if (matches.length === 0) return "0"; const lastMatch = matches[matches.length - 1]; const digits = /\d+(?:\.\d+)?/.exec(lastMatch[1] ?? lastMatch[0]); if (!digits) return "0"; return digits[0] ?? "0"; } static printJobNames(stream, job, i, arr) { if (i === arr.length - 1) { stream(chalk `{blueBright ${job.name}}`); } else { stream(chalk `{blueBright ${job.name}}, `); } } static expandTextWith(text, expandWith) { if (typeof text !== "string") { return text; } return text.replace(/(\$\$)|\$\{([a-zA-Z_]\w*)}|\$([a-zA-Z_]\w*)/g, // https://regexr.com/7s4ka (_match, escape, var1, var2) => { if (typeof escape !== "undefined") { return expandWith.unescape; } else { const name = var1 || var2; assert(name, "unexpected unset capture group"); return `${expandWith.variable(name)}`; } }); } static expandText(text, envs) { return this.expandTextWith(text, { unescape: "$", variable: (name) => envs[name] ?? "", }); } static expandVariables(variables) { const _variables = { ...variables }; // copy by value to prevent mutating the original input let expandedAnyVariables, i = 0; do { assert(i < 100, "Recursive variable expansion reached 100 iterations"); expandedAnyVariables = false; for (const [k, v] of Object.entries(_variables)) { const envsWithoutSelf = { ..._variables }; delete envsWithoutSelf[k]; // If the $$'s are converted to single $'s now, then the next // iteration, they might be interpreted as _variables, even // though they were *explicitly* escaped. To work around this, // leave the '$$'s as the same value, then only unescape them at // the very end. _variables[k] = Utils.expandTextWith(v, { unescape: "$$", variable: (name) => envsWithoutSelf[name] ?? "", }); expandedAnyVariables ||= _variables[k] !== v; } i++; } while (expandedAnyVariables); return _variables; } static unscape$$Variables(variables) { for (const [k, v] of Object.entries(variables)) { variables[k] = Utils.expandText(v, {}); } return variables; } static findEnvMatchedVariables(variables, fileVariablesDir, environment) { const envMatchedVariables = {}; for (const [k, v] of Object.entries(variables)) { for (const entry of v.environments) { if (environment?.name.match(entry.regexp) || entry.regexp.source === ".*") { if (fileVariablesDir != null && v.type === "file" && !entry.fileSource) { envMatchedVariables[k] = `${fileVariablesDir}/${k}`; fs.mkdirpSync(`${fileVariablesDir}`); fs.writeFileSync(`${fileVariablesDir}/${k}`, entry.content); } else if (fileVariablesDir != null && v.type === "file" && entry.fileSource) { envMatchedVariables[k] = `${fileVariablesDir}/${k}`; fs.mkdirpSync(`${fileVariablesDir}`); fs.copyFileSync(entry.fileSource, `${fileVariablesDir}/${k}`); } else { envMatchedVariables[k] = entry.content; } break; } } } return envMatchedVariables; } static getRulesResult(opt, gitData, jobWhen = "on_success", jobAllowFailure = false) { let when = "never"; const { evaluateRuleChanges } = opt.argv; // optional manual jobs allowFailure defaults to true https://docs.gitlab.com/ee/ci/jobs/job_control.html#types-of-manual-jobs let allowFailure = jobWhen === "manual" ? true : jobAllowFailure; let ruleVariable; for (const rule of opt.rules) { if (!Utils.evaluateRuleIf(rule.if, opt.variables)) continue; if (!Utils.evaluateRuleExist(opt.cwd, rule.exists)) continue; if (evaluateRuleChanges && !Utils.evaluateRuleChanges(gitData.branches.default, rule.changes, opt.cwd)) continue; when = rule.when ? rule.when : jobWhen; allowFailure = rule.allow_failure ?? allowFailure; ruleVariable = rule.variables; break; // Early return, will not evaluate the remaining rules } return { when, allowFailure, variables: ruleVariable }; } static evaluateRuleIf(ruleIf, envs) { if (ruleIf === undefined) return true; let evalStr = ruleIf; const flagsToBinary = (flags) => { let binary = 0; if (flags.includes("i")) { binary |= RE2JS.CASE_INSENSITIVE; } if (flags.includes("s")) { binary |= RE2JS.DOTALL; } if (flags.includes("m")) { binary |= RE2JS.MULTILINE; } return binary; }; // Expand all variables evalStr = this.expandTextWith(evalStr, { unescape: JSON.stringify("$"), variable: (name) => JSON.stringify(envs[name] ?? null).replaceAll("\\\\", "\\"), }); const expandedEvalStr = evalStr; // Scenario when RHS is a <regex> // https://regexr.com/85sjo const pattern1 = /\s*(?<operator>(?:=~)|(?:!~))\s*\/(?<rhs>.*?)\/(?<flags>[igmsuy]*)(\s|$|\))/g; evalStr = evalStr.replace(pattern1, (_, operator, rhs, flags, remainingTokens) => { let _operator; switch (operator) { case "=~": _operator = "!="; break; case "!~": _operator = "=="; break; default: throw operator; } const _rhs = JSON.stringify(rhs); // JSON.stringify for escaping `"` const containsNonEscapedSlash = /(?<!\\)\//.test(_rhs); const assertMsg = [ "Error attempting to evaluate the following rules:", " rules:", ` - if: '${expandedEvalStr}'`, "as rhs contains unescaped quote", ]; assert(!containsNonEscapedSlash, assertMsg.join("\n")); const flagsBinary = flagsToBinary(flags); return `.matchRE2JS(RE2JS.compile(${_rhs}, ${flagsBinary})) ${_operator} null${remainingTokens}`; }); // Scenario when RHS is surrounded by single/double-quotes // https://regexr.com/85t0g const pattern2 = /\s*(?<operator>=~|!~)\s*(["'])(?<rhs>(?:\\.|[^\\])*?)\2/g; evalStr = evalStr.replace(pattern2, (_, operator, __, rhs) => { let _operator; switch (operator) { case "=~": _operator = "!="; break; case "!~": _operator = "=="; break; default: throw operator; } const assertMsg = [ "RHS (${rhs}) must be a regex pattern. Do not rely on this behavior!", "Refer to https://docs.gitlab.com/ee/ci/jobs/job_rules.html#unexpected-behavior-from-regular-expression-matching-with- for more info...", ]; assert((/\/(.*)\/(\w*)/.test(rhs)), assertMsg.join("\n")); const regex = /\/(?<pattern>.*)\/(?<flags>[igmsuy]*)/; const _rhs = rhs.replace(regex, (_, pattern, flags) => { const flagsBinary = flagsToBinary(flags); return `RE2JS.compile("${pattern}", ${flagsBinary})`; }); return `.matchRE2JS(${_rhs}) ${_operator} null`; }); // Convert all null.match functions to false evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*!=\s*null/g, "false"); evalStr = evalStr.replace(/null.matchRE2JS\(.+?\)\s*==\s*null/g, "false"); evalStr = evalStr.trim(); let res; try { global.RE2JS = RE2JS; // Assign RE2JS to the global object res = (0, eval)(evalStr); // https://esbuild.github.io/content-types/#direct-eval delete global.RE2JS; // Cleanup } catch { const assertMsg = [ "Error attempting to evaluate the following rules:", " rules:", ` - if: '${expandedEvalStr}'`, "as", "```javascript", `${evalStr}`, "```", ]; assert(false, assertMsg.join("\n")); } return Boolean(res); } static evaluateRuleExist(cwd, ruleExists) { if (ruleExists === undefined) return true; // Normalize rules:exists:paths to rules:exists if (!Array.isArray(ruleExists)) ruleExists = ruleExists.paths; for (const pattern of ruleExists) { if (pattern == "") { continue; } if (globby.sync(pattern, { dot: true, cwd }).length > 0) { return true; } } return false; } static evaluateRuleChanges(defaultBranch, ruleChanges, cwd) { if (ruleChanges === undefined) return true; // Normalize rules:changes:paths to rules:changes if (!Array.isArray(ruleChanges)) ruleChanges = ruleChanges.paths; // NOTE: https://docs.gitlab.com/ee/ci/yaml/#ruleschanges // Glob patterns are interpreted with Ruby's [File.fnmatch](https://docs.ruby-lang.org/en/master/File.html#method-c-fnmatch) // with the flags File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB. return micromatch.some(GitData.changedFiles(`origin/${defaultBranch}`, cwd), ruleChanges, { nonegate: true, noextglob: true, posix: false, dot: true, }); } static isSubpath(lhs, rhs, cwd = process.cwd()) { let absLhs = ""; if (path.isAbsolute(lhs)) { absLhs = lhs; } else { absLhs = path.resolve(cwd, lhs); } let absRhs = ""; if (path.isAbsolute(rhs)) { absRhs = rhs; } else { absRhs = path.resolve(cwd, rhs); } const relative = path.relative(absRhs, absLhs); return !relative.startsWith(".."); } static async rsyncTrackedFiles(cwd, stateDir, target) { const time = process.hrtime(); await fs.mkdirp(`${cwd}/${stateDir}/builds/${target}`); await Utils.bash(`rsync -a --delete-excluded --delete --exclude-from=<(git ls-files -o --directory | awk '{print "/"$0}') --exclude ${stateDir}/ ./ ${stateDir}/builds/${target}/`, cwd); return { hrdeltatime: process.hrtime(time) }; } static async checksumFiles(cwd, files) { const promises = []; files.forEach((file) => { promises.push(new Promise((resolve, reject) => { if (!fs.pathExistsSync(file)) resolve(path.relative(cwd, file)); // must use relative path here, so that checksum can be deterministic when running the unit tests checksum.file(file, (err, hash) => { if (err) { return reject(err); } resolve(hash); }); })); }); const result = await Promise.all(promises); return checksum(result.join("")); } static isObject(v) { return Object.getPrototypeOf(v) === Object.prototype; } static async remoteFileExist(cwd, file, ref, domain, projectPath, protocol, port) { switch (protocol) { case "ssh": case "git": try { await Utils.spawn(`git archive --remote=ssh://git@${domain}:${port}/${projectPath}.git ${ref} ${file}`.split(" "), cwd); return true; } catch (e) { if (!e.stderr.includes(`remote: fatal: pathspec '${file}' did not match any files`)) throw new Error(e); return false; } case "http": case "https": { try { const { status } = await axios.get(`${protocol}://${domain}:${port}/${projectPath}/-/raw/${ref}/${file}`); return (status === 200); } catch { return false; } } default: { Utils.switchStatementExhaustiveCheck(protocol); } } } static switchStatementExhaustiveCheck(param) { // https://dev.to/babak/exhaustive-type-checking-with-typescript-4l3f throw new Error(`Unhandled case ${param}`); } static async getTrackedFiles(cwd) { const lsFilesRes = await Utils.bash("git ls-files --deduplicate", cwd); if (lsFilesRes.exitCode != 0) { throw new Error(`Failed to list tracked files in ${cwd}: ${lsFilesRes.stderr}`); } return lsFilesRes.stdout.split("\n"); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXRpbHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyJ1dGlscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLGFBQWEsQ0FBQztBQUNyQixPQUFPLEVBQUMsS0FBSyxFQUFDLE1BQU0sT0FBTyxDQUFDO0FBQzVCLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLEVBQUMsR0FBRyxFQUFVLE1BQU0sVUFBVSxDQUFDO0FBQ3RDLE9BQU8sRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUMxQixPQUFPLFFBQVEsTUFBTSxVQUFVLENBQUM7QUFDaEMsT0FBTyxTQUFTLE1BQU0sV0FBVyxDQUFDO0FBQ2xDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFFNUIsT0FBTyxFQUFDLE9BQU8sRUFBWSxNQUFNLGVBQWUsQ0FBQztBQUNqRCxPQUFPLE1BQU0sTUFBTSxRQUFRLENBQUM7QUFDNUIsT0FBTyxVQUFVLE1BQU0sWUFBWSxDQUFDO0FBQ3BDLE9BQU8sS0FBSyxNQUFNLE9BQU8sQ0FBQztBQUMxQixPQUFPLElBQUksTUFBTSxNQUFNLENBQUM7QUFleEIsTUFBTSxPQUFPLEtBQUs7SUFDZCxNQUFNLENBQUMsU0FBUyxDQUFFLE9BQWlCLEVBQUUsR0FBRyxHQUFHLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDcEQsT0FBTyxLQUFLLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsRUFBRSxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQztJQUMvRCxDQUFDO0lBRUQsTUFBTSxDQUFDLElBQUksQ0FBRSxXQUFtQixFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ2pELE9BQU8sS0FBSyxDQUFDLFdBQVcsRUFBRSxFQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQztJQUNwRCxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBRSxPQUFpQixFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ2hELE9BQU8sS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsRUFBRSxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUMsR0FBRyxFQUFDLENBQUMsQ0FBQztJQUN0RCxDQUFDO0lBRUQsTUFBTSxDQUFDLFNBQVMsQ0FBRSxPQUFpQixFQUFFLEdBQUcsR0FBRyxPQUFPLENBQUMsR0FBRyxFQUFFO1FBQ3BELE9BQU8sS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLEVBQUUsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFDLEdBQUcsRUFBQyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUUsR0FBVztRQUNyQixPQUFPLEdBQUcsQ0FBQyxPQUFPLENBQUMsY0FBYyxFQUFFLEVBQUUsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxhQUFhLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDdEUsQ0FBQztJQUVELE1BQU0sQ0FBQyxnQkFBZ0IsQ0FBRSxPQUFlO1FBQ3BDLE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxVQUFVLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUN6QyxPQUFPLFNBQVMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbkMsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBRSxDQUFTO1FBQzVCLE9BQU8sSUFBSSxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksRUFBRSxTQUFTLENBQUMsR0FBRyxDQUFDLENBQUMsNEJBQTRCO0lBQzFFLENBQUM7SUFFRCxNQUFNLENBQUMsY0FBYyxDQUFFLFVBQWUsRUFBRSxRQUFpRDtRQUNyRixLQUFLLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBTSxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQy9ELElBQUksR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNqRSxTQUFTO1lBQ2IsQ0FBQztZQUNELFFBQVEsQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDL0IsQ0FBQztJQUNMLENBQUM7SUFFRCxNQUFNLENBQUMsNkJBQTZCLENBQUUsSUFBd0IsRUFBRSxNQUF5QixFQUFFLFVBQWU7UUFDdEcsTUFBTSxRQUFRLEdBQWEsRUFBRSxDQUFDO1FBQzlCLE1BQU0saUJBQWlCLEdBQUcsTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDM0QsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsRUFBRTtZQUNmLE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQzdDLElBQUksVUFBVSxHQUFHLGlCQUFpQixFQUFFLENBQUM7Z0JBQ2pDLFFBQVEsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzVCLENBQUM7UUFDTCxDQUFDLENBQUMsQ0FBQztRQUNILE9BQU8sUUFBUSxDQUFDO0lBQ3BCLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLGtCQUFrQixDQUFFLEdBQVcsRUFBRSxRQUFnQixFQUFFLGFBQXFCLEVBQUUsT0FBZTtRQUNsRyxNQUFNLE9BQU8sR0FBRyxNQUFNLEVBQUUsQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLElBQUksUUFBUSxXQUFXLE9BQU8sTUFBTSxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRXRGLE1BQU0sS0FBSyxHQUFHLEtBQUssQ0FBQyxPQUFPLENBQ3ZCLGFBQWE7YUFDUixPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQzthQUNsQixPQUFPLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxFQUN2QixLQUFLLENBQUMsU0FBUyxDQUNsQixDQUFDO1FBQ0YsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7UUFDekQsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLENBQUM7WUFBRSxPQUFPLEdBQUcsQ0FBQztRQUVyQyxNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQztRQUM5QyxNQUFNLE1BQU0sR0FBRyxlQUFlLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxDQUFDLENBQUMsSUFBSSxTQUFTLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsTUFBTTtZQUFFLE9BQU8sR0FBRyxDQUFDO1FBQ3hCLE9BQU8sTUFBTSxDQUFDLENBQUMsQ0FBQyxJQUFJLEdBQUcsQ0FBQztJQUM1QixDQUFDO0lBRUQsTUFBTSxDQUFDLGFBQWEsQ0FBRSxNQUE2QixFQUFFLEdBQW1CLEVBQUUsQ0FBUyxFQUFFLEdBQXFCO1FBQ3RHLElBQUksQ0FBQyxLQUFLLEdBQUcsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDdkIsTUFBTSxDQUFDLEtBQUssQ0FBQSxlQUFlLEdBQUcsQ0FBQyxJQUFJLEdBQUcsQ0FBQyxDQUFDO1FBQzVDLENBQUM7YUFBTSxDQUFDO1lBQ0osTUFBTSxDQUFDLEtBQUssQ0FBQSxlQUFlLEdBQUcsQ0FBQyxJQUFJLEtBQUssQ0FBQyxDQUFDO1FBQzlDLENBQUM7SUFDTCxDQUFDO0lBRU8sTUFBTSxDQUFDLGNBQWMsQ0FBRSxJQUFTLEVBQUUsVUFBc0I7UUFDNUQsSUFBSSxPQUFPLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUMzQixPQUFPLElBQUksQ0FBQztRQUNoQixDQUFDO1FBRUQsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUNmLDhDQUE4QyxFQUFFLDJCQUEyQjtRQUMzRSxDQUFDLE1BQU0sRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxFQUFFO1lBQzNCLElBQUksT0FBTyxNQUFNLEtBQUssV0FBVyxFQUFFLENBQUM7Z0JBQ2hDLE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQztZQUMvQixDQUFDO2lCQUFNLENBQUM7Z0JBQ0osTUFBTSxJQUFJLEdBQUcsSUFBSSxJQUFJLElBQUksQ0FBQztnQkFDMUIsTUFBTSxDQUFDLElBQUksRUFBRSxnQ0FBZ0MsQ0FBQyxDQUFDO2dCQUMvQyxPQUFPLEdBQUcsVUFBVSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzFDLENBQUM7UUFDTCxDQUFDLENBQ0osQ0FBQztJQUNOLENBQUM7SUFFRCxNQUFNLENBQUMsVUFBVSxDQUFFLElBQVMsRUFBRSxJQUE2QjtRQUN2RCxPQUFPLElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxFQUFFO1lBQzdCLFFBQVEsRUFBRSxHQUFHO1lBQ2IsUUFBUSxFQUFFLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRTtTQUN2QyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsTUFBTSxDQUFDLGVBQWUsQ0FBRSxTQUFrQztRQUN0RCxNQUFNLFVBQVUsR0FBRyxFQUFDLEdBQUcsU0FBUyxFQUFDLENBQUMsQ0FBQyx1REFBdUQ7UUFDMUYsSUFBSSxvQkFBb0IsRUFBRSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQ2hDLEdBQUcsQ0FBQztZQUNBLE1BQU0sQ0FBQyxDQUFDLEdBQUcsR0FBRyxFQUFFLHFEQUFxRCxDQUFDLENBQUM7WUFDdkUsb0JBQW9CLEdBQUcsS0FBSyxDQUFDO1lBQzdCLEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7Z0JBQzlDLE1BQU0sZUFBZSxHQUFHLEVBQUMsR0FBRyxVQUFVLEVBQUMsQ0FBQztnQkFDeEMsT0FBTyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7Z0JBQzFCLDZEQUE2RDtnQkFDN0QsMkRBQTJEO2dCQUMzRCw4REFBOEQ7Z0JBQzlELGdFQUFnRTtnQkFDaEUsZ0JBQWdCO2dCQUNoQixVQUFVLENBQUMsQ0FBQyxDQUFDLEdBQUcsS0FBSyxDQUFDLGNBQWMsQ0FBQyxDQUFDLEVBQUU7b0JBQ3BDLFFBQVEsRUFBRSxJQUFJO29CQUNkLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUU7aUJBQ2xELENBQUMsQ0FBQztnQkFDSCxvQkFBb0IsS0FBSyxVQUFVLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ2pELENBQUM7WUFDRCxDQUFDLEVBQUUsQ0FBQztRQUNSLENBQUMsUUFBUSxvQkFBb0IsRUFBRTtRQUUvQixPQUFPLFVBQVUsQ0FBQztJQUN0QixDQUFDO0lBRUQsTUFBTSxDQUFDLGtCQUFrQixDQUFFLFNBQWtDO1FBQ3pELEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDN0MsU0FBUyxDQUFDLENBQUMsQ0FBQyxHQUFHLEtBQUssQ0FBQyxVQUFVLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQzNDLENBQUM7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNyQixDQUFDO0lBRUQsTUFBTSxDQUFDLHVCQUF1QixDQUFFLFNBQXlDLEVBQUUsZ0JBQXlCLEVBQUUsV0FBNEI7UUFDOUgsTUFBTSxtQkFBbUIsR0FBNEIsRUFBRSxDQUFDO1FBQ3hELEtBQUssTUFBTSxDQUFDLENBQUMsRUFBRSxDQUFDLENBQUMsSUFBSSxNQUFNLENBQUMsT0FBTyxDQUFDLFNBQVMsQ0FBQyxFQUFFLENBQUM7WUFDN0MsS0FBSyxNQUFNLEtBQUssSUFBSSxDQUFDLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ2pDLElBQUksV0FBVyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxLQUFLLElBQUksRUFBRSxDQUFDO29CQUN4RSxJQUFJLGdCQUFnQixJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsQ0FBQzt3QkFDckUsbUJBQW1CLENBQUMsQ0FBQyxDQUFDLEdBQUcsR0FBRyxnQkFBZ0IsSUFBSSxDQUFDLEVBQUUsQ0FBQzt3QkFDcEQsRUFBRSxDQUFDLFVBQVUsQ0FBQyxHQUFHLGdCQUFnQixFQUFFLENBQUMsQ0FBQzt3QkFDckMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxHQUFHLGdCQUFnQixJQUFJLENBQUMsRUFBRSxFQUFFLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDaEUsQ0FBQzt5QkFBTSxJQUFJLGdCQUFnQixJQUFJLElBQUksSUFBSSxDQUFDLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxLQUFLLENBQUMsVUFBVSxFQUFFLENBQUM7d0JBQzNFLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxHQUFHLEdBQUcsZ0JBQWdCLElBQUksQ0FBQyxFQUFFLENBQUM7d0JBQ3BELEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxnQkFBZ0IsRUFBRSxDQUFDLENBQUM7d0JBQ3JDLEVBQUUsQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLFVBQVUsRUFBRSxHQUFHLGdCQUFnQixJQUFJLENBQUMsRUFBRSxDQUFDLENBQUM7b0JBQ2xFLENBQUM7eUJBQU0sQ0FBQzt3QkFDSixtQkFBbUIsQ0FBQyxDQUFDLENBQUMsR0FBRyxLQUFLLENBQUMsT0FBTyxDQUFDO29CQUMzQyxDQUFDO29CQUNELE1BQU07Z0JBQ1YsQ0FBQztZQUNMLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxtQkFBbUIsQ0FBQztJQUMvQixDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBRSxHQUFrQixFQUFFLE9BQWdCLEVBQUUsVUFBa0IsWUFBWSxFQUFFLGtCQUE2RCxLQUFLO1FBQzNKLElBQUksSUFBSSxHQUFHLE9BQU8sQ0FBQztRQUNuQixNQUFNLEVBQUMsbUJBQW1CLEVBQUMsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDO1FBRXZDLDhIQUE4SDtRQUM5SCxJQUFJLFlBQVksR0FBRyxPQUFPLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLGVBQWUsQ0FBQztRQUNqRSxJQUFJLFlBQWtELENBQUM7UUFFdkQsS0FBSyxNQUFNLElBQUksSUFBSSxHQUFHLENBQUMsS0FBSyxFQUFFLENBQUM7WUFDM0IsSUFBSSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxHQUFHLENBQUMsU0FBUyxDQUFDO2dCQUFFLFNBQVM7WUFDNUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxNQUFNLENBQUM7Z0JBQUUsU0FBUztZQUM3RCxJQUFJLG1CQUFtQixJQUFJLENBQUMsS0FBSyxDQUFDLG1CQUFtQixDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsT0FBTyxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsR0FBRyxDQUFDLEdBQUcsQ0FBQztnQkFBRSxTQUFTO1lBRWpILElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUM7WUFDdkMsWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLElBQUksWUFBWSxDQUFDO1lBQ2xELFlBQVksR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO1lBRTlCLE1BQU0sQ0FBQyxzREFBc0Q7UUFDakUsQ0FBQztRQUVELE9BQU8sRUFBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLFNBQVMsRUFBRSxZQUFZLEVBQUMsQ0FBQztJQUN6RCxDQUFDO0lBRUQsTUFBTSxDQUFDLGNBQWMsQ0FBRSxNQUEwQixFQUFFLElBQTZCO1FBQzVFLElBQUksTUFBTSxLQUFLLFNBQVM7WUFBRSxPQUFPLElBQUksQ0FBQztRQUN0QyxJQUFJLE9BQU8sR0FBRyxNQUFNLENBQUM7UUFFckIsTUFBTSxhQUFhLEdBQUcsQ0FBQyxLQUFhLEVBQVUsRUFBRTtZQUM1QyxJQUFJLE1BQU0sR0FBRyxDQUFDLENBQUM7WUFDZixJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQkFBZ0IsQ0FBQztZQUNyQyxDQUFDO1lBQ0QsSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3RCLE1BQU0sSUFBSSxLQUFLLENBQUMsTUFBTSxDQUFDO1lBQzNCLENBQUM7WUFDRCxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsTUFBTSxJQUFJLEtBQUssQ0FBQyxTQUFTLENBQUM7WUFDOUIsQ0FBQztZQUNELE9BQU8sTUFBTSxDQUFDO1FBQ2xCLENBQUMsQ0FBQztRQUVGLHVCQUF1QjtRQUN2QixPQUFPLEdBQUcsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUU7WUFDbkMsUUFBUSxFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsR0FBRyxDQUFDO1lBQzdCLFFBQVEsRUFBRSxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksSUFBSSxDQUFDLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxJQUFJLENBQUM7U0FDbEYsQ0FBQyxDQUFDO1FBQ0gsTUFBTSxlQUFlLEdBQUcsT0FBTyxDQUFDO1FBRWhDLGlDQUFpQztRQUNqQywyQkFBMkI7UUFDM0IsTUFBTSxRQUFRLEdBQUcsOEVBQThFLENBQUM7UUFDaEcsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FBQyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsS0FBSyxFQUFFLGVBQWUsRUFBRSxFQUFFO1lBQzdFLElBQUksU0FBUyxDQUFDO1lBQ2QsUUFBUSxRQUFRLEVBQUUsQ0FBQztnQkFDZixLQUFLLElBQUk7b0JBQ0wsU0FBUyxHQUFHLElBQUksQ0FBQztvQkFDakIsTUFBTTtnQkFDVixLQUFLLElBQUk7b0JBQ0wsU0FBUyxHQUFHLElBQUksQ0FBQztvQkFDakIsTUFBTTtnQkFDVjtvQkFDSSxNQUFNLFFBQVEsQ0FBQztZQUN2QixDQUFDO1lBQ0QsTUFBTSxJQUFJLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsQ0FBQyxDQUFDLGtDQUFrQztZQUNwRSxNQUFNLHVCQUF1QixHQUFHLFdBQVcsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDdkQsTUFBTSxTQUFTLEdBQUc7Z0JBQ2QsbURBQW1EO2dCQUNuRCxVQUFVO2dCQUNWLGNBQWMsZUFBZSxHQUFHO2dCQUNoQyxpQ0FBaUM7YUFDcEMsQ0FBQztZQUNGLE1BQU0sQ0FBQyxDQUFDLHVCQUF1QixFQUFFLFNBQVMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztZQUN2RCxNQUFNLFdBQVcsR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDekMsT0FBTyw2QkFBNkIsSUFBSSxLQUFLLFdBQVcsTUFBTSxTQUFTLFFBQVEsZUFBZSxFQUFFLENBQUM7UUFDckcsQ0FBQyxDQUFDLENBQUM7UUFFSCwwREFBMEQ7UUFDMUQsMkJBQTJCO1FBQzNCLE1BQU0sUUFBUSxHQUFHLDBEQUEwRCxDQUFDO1FBQzVFLE9BQU8sR0FBRyxPQUFPLENBQUMsT0FBTyxDQUFDLFFBQVEsRUFBRSxDQUFDLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLEdBQUcsRUFBRSxFQUFFO1lBQ3pELElBQUksU0FBUyxDQUFDO1lBQ2QsUUFBUSxRQUFRLEVBQUUsQ0FBQztnQkFDZixLQUFLLElBQUk7b0JBQ0wsU0FBUyxHQUFHLElBQUksQ0FBQztvQkFDakIsTUFBTTtnQkFDVixLQUFLLElBQUk7b0JBQ0wsU0FBUyxHQUFHLElBQUksQ0FBQztvQkFDakIsTUFBTTtnQkFDVjtvQkFDSSxNQUFNLFFBQVEsQ0FBQztZQUN2QixDQUFDO1lBRUQsTUFBTSxTQUFTLEdBQUc7Z0JBQ2QscUVBQXFFO2dCQUNyRSx3SUFBd0k7YUFDM0ksQ0FBQztZQUNGLE1BQU0sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7WUFFMUQsTUFBTSxLQUFLLEdBQUcsdUNBQXVDLENBQUM7WUFDdEQsTUFBTSxJQUFJLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQyxLQUFLLEVBQUUsQ0FBQyxDQUFTLEVBQUUsT0FBZSxFQUFFLEtBQWEsRUFBRSxFQUFFO2dCQUMxRSxNQUFNLFdBQVcsR0FBRyxhQUFhLENBQUMsS0FBSyxDQUFDLENBQUM7Z0JBQ3pDLE9BQU8sa0JBQWtCLE9BQU8sTUFBTSxXQUFXLEdBQUcsQ0FBQztZQUN6RCxDQUFDLENBQUMsQ0FBQztZQUNILE9BQU8sZUFBZSxJQUFJLEtBQUssU0FBUyxPQUFPLENBQUM7UUFDcEQsQ0FBQyxDQUFDLENBQUM7UUFFSCw0Q0FBNEM7UUFDNUMsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUNBQXFDLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFDMUUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxPQUFPLENBQUMscUNBQXFDLEVBQUUsT0FBTyxDQUFDLENBQUM7UUFFMUUsT0FBTyxHQUFHLE9BQU8sQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUV6QixJQUFJLEdBQUcsQ0FBQztRQUNSLElBQUksQ0FBQztZQUNBLE1BQWMsQ0FBQyxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsb0NBQW9DO1lBQ25FLEdBQUcsR0FBRyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLHVEQUF1RDtZQUNqRixPQUFRLE1BQWMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxVQUFVO1FBQzVDLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDTCxNQUFNLFNBQVMsR0FBRztnQkFDZCxtREFBbUQ7Z0JBQ25ELFVBQVU7Z0JBQ1YsY0FBYyxlQUFlLEdBQUc7Z0JBQ2hDLElBQUk7Z0JBQ0osZUFBZTtnQkFDZixHQUFHLE9BQU8sRUFBRTtnQkFDWixLQUFLO2FBQ1IsQ0FBQztZQUNGLE1BQU0sQ0FBQyxLQUFLLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3hDLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUN4QixDQUFDO0lBRUQsTUFBTSxDQUFDLGlCQUFpQixDQUFFLEdBQVcsRUFBRSxVQUFvRDtRQUN2RixJQUFJLFVBQVUsS0FBSyxTQUFTO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFMUMsK0NBQStDO1FBQy9DLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFVBQVUsQ0FBQztZQUFFLFVBQVUsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBRTlELEtBQUssTUFBTSxPQUFPLElBQUksVUFBVSxFQUFFLENBQUM7WUFDL0IsSUFBSSxPQUFPLElBQUksRUFBRSxFQUFFLENBQUM7Z0JBQ2hCLFNBQVM7WUFDYixDQUFDO1lBQ0QsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxFQUFDLEdBQUcsRUFBRSxJQUFJLEVBQUUsR0FBRyxFQUFDLENBQUMsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ3BELE9BQU8sSUFBSSxDQUFDO1lBQ2hCLENBQUM7UUFDTCxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDakIsQ0FBQztJQUVELE1BQU0sQ0FBQyxtQkFBbUIsQ0FBRSxhQUFxQixFQUFFLFdBQXFELEVBQUUsR0FBVztRQUNqSCxJQUFJLFdBQVcsS0FBSyxTQUFTO1lBQUUsT0FBTyxJQUFJLENBQUM7UUFFM0MsaURBQWlEO1FBQ2pELElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLFdBQVcsQ0FBQztZQUFFLFdBQVcsR0FBRyxXQUFXLENBQUMsS0FBSyxDQUFDO1FBRWpFLHlEQUF5RDtRQUN6RCw4SEFBOEg7UUFDOUgsZ0ZBQWdGO1FBQ2hGLE9BQU8sVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsWUFBWSxDQUFDLFVBQVUsYUFBYSxFQUFFLEVBQUUsR0FBRyxDQUFDLEVBQUUsV0FBVyxFQUFFO1lBQ3RGLFFBQVEsRUFBRSxJQUFJO1lBQ2QsU0FBUyxFQUFFLElBQUk7WUFDZixLQUFLLEVBQUUsS0FBSztZQUNaLEdBQUcsRUFBRSxJQUFJO1NBQ1osQ0FBQyxDQUFDO0lBQ1AsQ0FBQztJQUVELE1BQU0sQ0FBQyxTQUFTLENBQUUsR0FBVyxFQUFFLEdBQVcsRUFBRSxNQUFjLE9BQU8sQ0FBQyxHQUFHLEVBQUU7UUFDbkUsSUFBSSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ2hCLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3ZCLE1BQU0sR0FBRyxHQUFHLENBQUM7UUFDakIsQ0FBQzthQUFNLENBQUM7WUFDSixNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLENBQUM7UUFDcEMsQ0FBQztRQUVELElBQUksTUFBTSxHQUFHLEVBQUUsQ0FBQztRQUNoQixJQUFJLElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUN2QixNQUFNLEdBQUcsR0FBRyxDQUFDO1FBQ2pCLENBQUM7YUFBTSxDQUFDO1lBQ0osTUFBTSxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3BDLENBQUM7UUFFRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMvQyxPQUFPLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQztJQUN0QyxDQUFDO0lBRUQsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBRSxHQUFXLEVBQUUsUUFBZ0IsRUFBRSxNQUFjO1FBQ3pFLE1BQU0sSUFBSSxHQUFHLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUM5QixNQUFNLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxHQUFHLElBQUksUUFBUSxXQUFXLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDdkQsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLHFIQUFxSCxRQUFRLFFBQVEsUUFBUSxXQUFXLE1BQU0sR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3pMLE9BQU8sRUFBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsRUFBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBRSxHQUFXLEVBQUUsS0FBZTtRQUNwRCxNQUFNLFFBQVEsR0FBc0IsRUFBRSxDQUFDO1FBRXZDLEtBQUssQ0FBQyxPQUFPLENBQUMsQ0FBQyxJQUFJLEVBQUUsRUFBRTtZQUNuQixRQUFRLENBQUMsSUFBSSxDQUFDLElBQUksT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUMxQyxJQUFJLENBQUUsRUFBRSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUM7b0JBQUUsT0FBTyxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUMsQ0FBQyxpR0FBaUc7Z0JBQ25LLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO29CQUM5QixJQUFJLEdBQUcsRUFBRSxDQUFDO3dCQUNOLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUN2QixDQUFDO29CQUNELE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztnQkFDbEIsQ0FBQyxDQUFDLENBQUM7WUFDUCxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ1IsQ0FBQyxDQUFDLENBQUM7UUFFSCxNQUFNLE1BQU0sR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7UUFDM0MsT0FBTyxRQUFRLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFFRCxNQUFNLENBQUMsUUFBUSxDQUFFLENBQU07UUFDbkIsT0FBTyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FBQyxLQUFLLE1BQU0sQ0FBQyxTQUFTLENBQUM7SUFDekQsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFFLEdBQVcsRUFBRSxJQUFZLEVBQUUsR0FBVyxFQUFFLE1BQWMsRUFBRSxXQUFtQixFQUFFLFFBQW1CLEVBQUUsSUFBWTtRQUN4SSxRQUFRLFFBQVEsRUFBRSxDQUFDO1lBQ2YsS0FBSyxLQUFLLENBQUM7WUFDWCxLQUFLLEtBQUs7Z0JBQ04sSUFBSSxDQUFDO29CQUNELE1BQU0sS0FBSyxDQUFDLEtBQUssQ0FBQyxrQ0FBa0MsTUFBTSxJQUFJLElBQUksSUFBSSxXQUFXLFFBQVEsR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsRUFBRSxHQUFHLENBQUMsQ0FBQztvQkFDeEgsT0FBTyxJQUFJLENBQUM7Z0JBQ2hCLENBQUM7Z0JBQUMsT0FBTyxDQUFNLEVBQUUsQ0FBQztvQkFDZCxJQUFJLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsNEJBQTRCLElBQUksMkJBQTJCLENBQUM7d0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQztvQkFDeEcsT0FBTyxLQUFLLENBQUM7Z0JBQ2pCLENBQUM7WUFFTCxLQUFLLE1BQU0sQ0FBQztZQUNaLEtBQUssT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDWCxJQUFJLENBQUM7b0JBQ0QsTUFBTSxFQUFDLE1BQU0sRUFBQyxHQUFHLE1BQU0sS0FBSyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsTUFBTSxNQUFNLElBQUksSUFBSSxJQUFJLFdBQVcsVUFBVSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDeEcsT0FBTyxDQUFDLE1BQU0sS0FBSyxHQUFHLENBQUMsQ0FBQztnQkFDNUIsQ0FBQztnQkFBQyxNQUFNLENBQUM7b0JBQ0wsT0FBTyxLQUFLLENBQUM7Z0JBQ2pCLENBQUM7WUFDTCxDQUFDO1lBQ0QsT0FBTyxDQUFDLENBQUMsQ0FBQztnQkFDTixLQUFLLENBQUMsOEJBQThCLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbkQsQ0FBQztRQUNMLENBQUM7SUFDTCxDQUFDO0lBRUQsTUFBTSxDQUFDLDhCQUE4QixDQUFFLEtBQVk7UUFDL0MscUVBQXFFO1FBQ3JFLE1BQU0sSUFBSSxLQUFLLENBQUMsa0JBQWtCLEtBQUssRUFBRSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVELE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxDQUFFLEdBQVc7UUFDckMsTUFBTSxVQUFVLEdBQUcsTUFBTSxLQUFLLENBQUMsSUFBSSxDQUFDLDRCQUE0QixFQUFFLEdBQUcsQ0FBQyxDQUFDO1FBQ3ZFLElBQUksVUFBVSxDQUFDLFFBQVEsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMzQixNQUFNLElBQUksS0FBSyxDQUFDLG1DQUFtQyxHQUFHLEtBQUssVUFBVSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDcEYsQ0FBQztRQUNELE9BQU8sVUFBVSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDekMsQ0FBQztDQUNKIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IFwiLi9nbG9iYWwuanNcIjtcbmltcG9ydCB7UkUySlN9IGZyb20gXCJyZTJqc1wiO1xuaW1wb3J0IGNoYWxrIGZyb20gXCJjaGFsa1wiO1xuaW1wb3J0IHtKb2IsIEpvYlJ1bGV9IGZyb20gXCIuL2pvYi5qc1wiO1xuaW1wb3J0IGZzIGZyb20gXCJmcy1leHRyYVwiO1xuaW1wb3J0IGNoZWNrc3VtIGZyb20gXCJjaGVja3N1bVwiO1xuaW1wb3J0IGJhc2U2NHVybCBmcm9tIFwiYmFzZTY0dXJsXCI7XG5pbXBvcnQgZXhlY2EgZnJvbSBcImV4ZWNhXCI7XG5pbXBvcnQgYXNzZXJ0IGZyb20gXCJhc3NlcnRcIjtcbmltcG9ydCB7Q0lDRFZhcmlhYmxlfSBmcm9tIFwiLi92YXJpYWJsZXMtZnJvbS1maWxlcy5qc1wiO1xuaW1wb3J0IHtHaXREYXRhLCBHaXRTY2hlbWF9IGZyb20gXCIuL2dpdC1kYXRhLmpzXCI7XG5pbXBvcnQgZ2xvYmJ5IGZyb20gXCJnbG9iYnlcIjtcbmltcG9ydCBtaWNyb21hdGNoIGZyb20gXCJtaWNyb21hdGNoXCI7XG5pbXBvcnQgYXhpb3MgZnJvbSBcImF4aW9zXCI7XG5pbXBvcnQgcGF0aCBmcm9tIFwicGF0aFwiO1xuaW1wb3J0IHtBcmd2fSBmcm9tIFwiLi9hcmd2LmpzXCI7XG5cbnR5cGUgUnVsZVJlc3VsdE9wdCA9IHtcbiAgICBhcmd2OiBBcmd2O1xuICAgIGN3ZDogc3RyaW5nO1xuICAgIHJ1bGVzOiBKb2JSdWxlW107XG4gICAgdmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfTtcbn07XG5cbnR5cGUgRXhwYW5kV2l0aCA9IHtcbiAgICB1bmVzY2FwZTogc3RyaW5nO1xuICAgIHZhcmlhYmxlOiAobmFtZTogc3RyaW5nKSA9PiBzdHJpbmc7XG59O1xuXG5leHBvcnQgY2xhc3MgVXRpbHMge1xuICAgIHN0YXRpYyBiYXNoTXVsdGkgKHNjcmlwdHM6IHN0cmluZ1tdLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2NyaXB0cy5qb2luKFwiICYmIFxcXFxcIiksIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBiYXNoIChzaGVsbFNjcmlwdDogc3RyaW5nLCBjd2QgPSBwcm9jZXNzLmN3ZCgpKTogUHJvbWlzZTx7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nOyBleGl0Q29kZTogbnVtYmVyfT4ge1xuICAgICAgICByZXR1cm4gZXhlY2Eoc2hlbGxTY3JpcHQsIHtzaGVsbDogXCJiYXNoXCIsIGN3ZH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBzcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiBQcm9taXNlPHtzdGRvdXQ6IHN0cmluZzsgc3RkZXJyOiBzdHJpbmd9PiB7XG4gICAgICAgIHJldHVybiBleGVjYShjbWRBcmdzWzBdLCBjbWRBcmdzLnNsaWNlKDEpLCB7Y3dkfSk7XG4gICAgfVxuXG4gICAgc3RhdGljIHN5bmNTcGF3biAoY21kQXJnczogc3RyaW5nW10sIGN3ZCA9IHByb2Nlc3MuY3dkKCkpOiB7c3Rkb3V0OiBzdHJpbmc7IHN0ZGVycjogc3RyaW5nfSB7XG4gICAgICAgIHJldHVybiBleGVjYS5zeW5jKGNtZEFyZ3NbMF0sIGNtZEFyZ3Muc2xpY2UoMSksIHtjd2R9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgZnNVcmwgKHVybDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICAgICAgcmV0dXJuIHVybC5yZXBsYWNlKC9eaHR0cHM6XFwvXFwvL2csIFwiXCIpLnJlcGxhY2UoL15odHRwOlxcL1xcLy9nLCBcIlwiKTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2FmZURvY2tlclN0cmluZyAoam9iTmFtZTogc3RyaW5nKSB7XG4gICAgICAgIHJldHVybiBqb2JOYW1lLnJlcGxhY2UoL1teXFx3LV0rL2csIChtYXRjaCkgPT4ge1xuICAgICAgICAgICAgcmV0dXJuIGJhc2U2NHVybC5lbmNvZGUobWF0Y2gpO1xuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzdGF0aWMgc2FmZUJhc2hTdHJpbmcgKHM6IHN0cmluZykge1xuICAgICAgICByZXR1cm4gYCcke3MucmVwbGFjZSgvJy9nLCBcIidcXFwiJ1xcXCInXCIpfSdgOyAvLyByZXBsYWNlcyBgJ2Agd2l0aCBgJ1wiJ1wiJ2BcbiAgICB9XG5cbiAgICBzdGF0aWMgZm9yRWFjaFJlYWxKb2IgKGdpdGxhYkRhdGE6IGFueSwgY2FsbGJhY2s6IChqb2JOYW1lOiBzdHJpbmcsIGpvYkRhdGE6IGFueSkgPT4gdm9pZCkge1xuICAgICAgICBmb3IgKGNvbnN0IFtqb2JOYW1lLCBqb2JEYXRhXSBvZiBPYmplY3QuZW50cmllczxhbnk+KGdpdGxhYkRhdGEpKSB7XG4gICAgICAgICAgICBpZiAoSm9iLmlsbGVnYWxKb2JOYW1lcy5oYXMoam9iTmFtZSkgfHwgam9iTmFtZVswXS5zdGFydHNXaXRoKFwiLlwiKSkge1xuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2FsbGJhY2soam9iTmFtZSwgam9iRGF0YSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0Sm9iTmFtZXNGcm9tUHJldmlvdXNTdGFnZXMgKGpvYnM6IFJlYWRvbmx5QXJyYXk8Sm9iPiwgc3RhZ2VzOiByZWFkb25seSBzdHJpbmdbXSwgY3VycmVudEpvYjogSm9iKSB7XG4gICAgICAgIGNvbnN0IGpvYk5hbWVzOiBzdHJpbmdbXSA9IFtdO1xuICAgICAgICBjb25zdCBjdXJyZW50U3RhZ2VJbmRleCA9IHN0YWdlcy5pbmRleE9mKGN1cnJlbnRKb2Iuc3RhZ2UpO1xuICAgICAgICBqb2JzLmZvckVhY2goam9iID0+IHtcbiAgICAgICAgICAgIGNvbnN0IHN0YWdlSW5kZXggPSBzdGFnZXMuaW5kZXhPZihqb2Iuc3RhZ2UpO1xuICAgICAgICAgICAgaWYgKHN0YWdlSW5kZXggPCBjdXJyZW50U3RhZ2VJbmRleCkge1xuICAgICAgICAgICAgICAgIGpvYk5hbWVzLnB1c2goam9iLm5hbWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgcmV0dXJuIGpvYk5hbWVzO1xuICAgIH1cblxuICAgIHN0YXRpYyBhc3luYyBnZXRDb3ZlcmFnZVBlcmNlbnQgKGN3ZDogc3RyaW5nLCBzdGF0ZURpcjogc3RyaW5nLCBjb3ZlcmFnZVJlZ2V4OiBzdHJpbmcsIGpvYk5hbWU6IHN0cmluZykge1xuICAgICAgICBjb25zdCBjb250ZW50ID0gYXdhaXQgZnMucmVhZEZpbGUoYCR7Y3dkfS8ke3N0YXRlRGlyfS9vdXRwdXQvJHtqb2JOYW1lfS5sb2dgLCBcInV0ZjhcIik7XG5cbiAgICAgICAgY29uc3QgcmVnZXggPSBSRTJKUy5jb21waWxlKFxuICAgICAgICAgICAgY292ZXJhZ2VSZWdleFxuICAgICAgICAgICAgICAgIC5yZXBsYWNlKC9eXFwvLywgXCJcIilcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFwvJC8sIFwiXCIpLFxuICAgICAgICAgICAgUkUySlMuTVVMVElMSU5FLFxuICAgICAgICApO1xuICAgICAgICBjb25zdCBtYXRjaGVzID0gQXJyYXkuZnJvbShjb250ZW50Lm1hdGNoQWxsUkUySlMocmVnZXgpKTtcbiAgICAgICAgaWYgKG1hdGNoZXMubGVuZ3RoID09PSAwKSByZXR1cm4gXCIwXCI7XG5cbiAgICAgICAgY29uc3QgbGFzdE1hdGNoID0gbWF0Y2hlc1ttYXRjaGVzLmxlbmd0aCAtIDFdO1xuICAgICAgICBjb25zdCBkaWdpdHMgPSAvXFxkKyg/OlxcLlxcZCspPy8uZXhlYyhsYXN0TWF0Y2hbMV0gPz8gbGFzdE1hdGNoWzBdKTtcbiAgICAgICAgaWYgKCFkaWdpdHMpIHJldHVybiBcIjBcIjtcbiAgICAgICAgcmV0dXJuIGRpZ2l0c1swXSA/PyBcIjBcIjtcbiAgICB9XG5cbiAgICBzdGF0aWMgcHJpbnRKb2JOYW1lcyAoc3RyZWFtOiAodHh0OiBzdHJpbmcpID0+IHZvaWQsIGpvYjoge25hbWU6IHN0cmluZ30sIGk6IG51bWJlciwgYXJyOiB7bmFtZTogc3RyaW5nfVtdKSB7XG4gICAgICAgIGlmIChpID09PSBhcnIubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgc3RyZWFtKGNoYWxrYHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fWApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgc3RyZWFtKGNoYWxrYHtibHVlQnJpZ2h0ICR7am9iLm5hbWV9fSwgYCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBwcml2YXRlIHN0YXRpYyBleHBhbmRUZXh0V2l0aCAodGV4dDogYW55LCBleHBhbmRXaXRoOiBFeHBhbmRXaXRoKSB7XG4gICAgICAgIGlmICh0eXBlb2YgdGV4dCAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgcmV0dXJuIHRleHQ7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGV4dC5yZXBsYWNlKFxuICAgICAgICAgICAgLyhcXCRcXCQpfFxcJFxceyhbYS16QS1aX11cXHcqKX18XFwkKFthLXpBLVpfXVxcdyopL2csIC8vIGh0dHBzOi8vcmVnZXhyLmNvbS83czRrYVxuICAgICAgICAgICAgKF9tYXRjaCwgZXNjYXBlLCB2YXIxLCB2YXIyKSA9PiB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBlc2NhcGUgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV4cGFuZFdpdGgudW5lc2NhcGU7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc3QgbmFtZSA9IHZhcjEgfHwgdmFyMjtcbiAgICAgICAgICAgICAgICAgICAgYXNzZXJ0KG5hbWUsIFwidW5leHBlY3RlZCB1bnNldCBjYXB0dXJlIGdyb3VwXCIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYCR7ZXhwYW5kV2l0aC52YXJpYWJsZShuYW1lKX1gO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgc3RhdGljIGV4cGFuZFRleHQgKHRleHQ6IGFueSwgZW52czoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZXhwYW5kVGV4dFdpdGgodGV4dCwge1xuICAgICAgICAgICAgdW5lc2NhcGU6IFwiJFwiLFxuICAgICAgICAgICAgdmFyaWFibGU6IChuYW1lKSA9PiBlbnZzW25hbWVdID8/IFwiXCIsXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHN0YXRpYyBleHBhbmRWYXJpYWJsZXMgKHZhcmlhYmxlczoge1trZXk6IHN0cmluZ106IHN0cmluZ30pIHtcbiAgICAgICAgY29uc3QgX3ZhcmlhYmxlcyA9IHsuLi52YXJpYWJsZXN9OyAvLyBjb3B5IGJ5IHZhbHVlIHRvIHByZXZlbnQgbXV0YXRpbmcgdGhlIG9yaWdpbmFsIGlucHV0XG4gICAgICAgIGxldCBleHBhbmRlZEFueVZhcmlhYmxlcywgaSA9IDA7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAgIGFzc2VydChpIDwgMTAwLCBcIlJlY3Vyc2l2ZSB2YXJpYWJsZSBleHBhbnNpb24gcmVhY2hlZCAxMDAgaXRlcmF0aW9uc1wiKTtcbiAgICAgICAgICAgIGV4cGFuZGVkQW55VmFyaWFibGVzID0gZmFsc2U7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyhfdmFyaWFibGVzKSkge1xuICAgICAgICAgICAgICAgIGNvbnN0IGVudnNXaXRob3V0U2VsZiA9IHsuLi5fdmFyaWFibGVzfTtcbiAgICAgICAgICAgICAgICBkZWxldGUgZW52c1dpdGhvdXRTZWxmW2tdO1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSAkJCdzIGFyZSBjb252ZXJ0ZWQgdG8gc2luZ2xlICQncyBub3csIHRoZW4gdGhlIG5leHRcbiAgICAgICAgICAgICAgICAvLyBpdGVyYXRpb24sIHRoZXkgbWlnaHQgYmUgaW50ZXJwcmV0ZWQgYXMgX3ZhcmlhYmxlcywgZXZlblxuICAgICAgICAgICAgICAgIC8vIHRob3VnaCB0aGV5IHdlcmUgKmV4cGxpY2l0bHkqIGVzY2FwZWQuIFRvIHdvcmsgYXJvdW5kIHRoaXMsXG4gICAgICAgICAgICAgICAgLy8gbGVhdmUgdGhlICckJCdzIGFzIHRoZSBzYW1lIHZhbHVlLCB0aGVuIG9ubHkgdW5lc2NhcGUgdGhlbSBhdFxuICAgICAgICAgICAgICAgIC8vIHRoZSB2ZXJ5IGVuZC5cbiAgICAgICAgICAgICAgICBfdmFyaWFibGVzW2tdID0gVXRpbHMuZXhwYW5kVGV4dFdpdGgodiwge1xuICAgICAgICAgICAgICAgICAgICB1bmVzY2FwZTogXCIkJFwiLFxuICAgICAgICAgICAgICAgICAgICB2YXJpYWJsZTogKG5hbWUpID0+IGVudnNXaXRob3V0U2VsZltuYW1lXSA/PyBcIlwiLFxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGV4cGFuZGVkQW55VmFyaWFibGVzIHx8PSBfdmFyaWFibGVzW2tdICE9PSB2O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaSsrO1xuICAgICAgICB9IHdoaWxlIChleHBhbmRlZEFueVZhcmlhYmxlcyk7XG5cbiAgICAgICAgcmV0dXJuIF92YXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIHVuc2NhcGUkJFZhcmlhYmxlcyAodmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSkge1xuICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YXJpYWJsZXMpKSB7XG4gICAgICAgICAgICB2YXJpYWJsZXNba10gPSBVdGlscy5leHBhbmRUZXh0KHYsIHt9KTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB2YXJpYWJsZXM7XG4gICAgfVxuXG4gICAgc3RhdGljIGZpbmRFbnZNYXRjaGVkVmFyaWFibGVzICh2YXJpYWJsZXM6IHtbbmFtZTogc3RyaW5nXTogQ0lDRFZhcmlhYmxlfSwgZmlsZVZhcmlhYmxlc0Rpcj86IHN0cmluZywgZW52aXJvbm1lbnQ/OiB7bmFtZTogc3RyaW5nfSkge1xuICAgICAgICBjb25zdCBlbnZNYXRjaGVkVmFyaWFibGVzOiB7W2tleTogc3RyaW5nXTogc3RyaW5nfSA9IHt9O1xuICAgICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YXJpYWJsZXMpKSB7XG4gICAgICAgICAgICBmb3IgKGNvbnN0IGVudHJ5IG9mIHYuZW52aXJvbm1lbnRzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVudmlyb25tZW50Py5uYW1lLm1hdGNoKGVudHJ5LnJlZ2V4cCkgfHwgZW50cnkucmVnZXhwLnNvdXJjZSA9PT0gXCIuKlwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChmaWxlVmFyaWFibGVzRGlyICE9IG51bGwgJiYgdi50eXBlID09PSBcImZpbGVcIiAmJiAhZW50cnkuZmlsZVNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW52TWF0Y2hlZFZhcmlhYmxlc1trXSA9IGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMubWtkaXJwU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMud3JpdGVGaWxlU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfS8ke2t9YCwgZW50cnkuY29udGVudCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoZmlsZVZhcmlhYmxlc0RpciAhPSBudWxsICYmIHYudHlwZSA9PT0gXCJmaWxlXCIgJiYgZW50cnkuZmlsZVNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZW52TWF0Y2hlZFZhcmlhYmxlc1trXSA9IGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMubWtkaXJwU3luYyhgJHtmaWxlVmFyaWFibGVzRGlyfWApO1xuICAgICAgICAgICAgICAgICAgICAgICAgZnMuY29weUZpbGVTeW5jKGVudHJ5LmZpbGVTb3VyY2UsIGAke2ZpbGVWYXJpYWJsZXNEaXJ9LyR7a31gKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVudk1hdGNoZWRWYXJpYWJsZXNba10gPSBlbnRyeS5jb250ZW50O1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZW52TWF0Y2hlZFZhcmlhYmxlcztcbiAgICB9XG5cbiAgICBzdGF0aWMgZ2V0UnVsZXNSZXN1bHQgKG9wdDogUnVsZVJlc3VsdE9wdCwgZ2l0RGF0YTogR2l0RGF0YSwgam9iV2hlbjogc3RyaW5nID0gXCJvbl9zdWNjZXNzXCIsIGpvYkFsbG93RmFpbHVyZTogYm9vbGVhbiB8IHtleGl0X2NvZGVzOiBudW1iZXIgfCBudW1iZXJbXX0gPSBmYWxzZSk6IHt3aGVuOiBzdHJpbmc7IGFsbG93RmFpbHVyZTogYm9vbGVhbiB8IHtleGl0X2NvZGVzOiBudW1iZXIgfCBudW1iZXJbXX07IHZhcmlhYmxlcz86IHtbbmFtZTogc3RyaW5nXTogc3RyaW5nfX0ge1xuICAgICAgICBsZXQgd2hlbiA9IFwibmV2ZXJcIjtcbiAgICAgICAgY29uc3Qge2V2YWx1YXRlUnVsZUNoYW5nZXN9ID0gb3B0LmFyZ3Y7XG5cbiAgICAgICAgLy8gb3B0aW9uYWwgbWFudWFsIGpvYnMgYWxsb3dGYWlsdXJlIGRlZmF1bHRzIHRvIHRydWUgaHR0cHM6Ly9kb2NzLmdpdGxhYi5jb20vZWUvY2kvam9icy9qb2JfY29udHJvbC5odG1sI3R5cGVzLW9mLW1hbnVhbC1qb2JzXG4gICAgICAgIGxldCBhbGxvd0ZhaWx1cmUgPSBqb2JXaGVuID09PSBcIm1hbnVhbFwiID8gdHJ1ZSA6IGpvYkFsbG93RmFpbHVyZTtcbiAgICAgICAgbGV0IHJ1bGVWYXJpYWJsZToge1tuYW1lOiBzdHJpbmddOiBzdHJpbmd9IHwgdW5kZWZpbmVkO1xuXG4gICAgICAgIGZvciAoY29uc3QgcnVsZSBvZiBvcHQucnVsZXMpIHtcbiAgICAgICAgICAgIGlmICghVXRpbHMuZXZhbHVhdGVSdWxlSWYocnVsZS5pZiwgb3B0LnZhcmlhYmxlcykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKCFVdGlscy5ldmFsdWF0ZVJ1bGVFeGlzdChvcHQuY3dkLCBydWxlLmV4aXN0cykpIGNvbnRpbnVlO1xuICAgICAgICAgICAgaWYgKGV2YWx1YXRlUnVsZUNoYW5nZXMgJiYgIVV0aWxzLmV2YWx1YXRlUnVsZUNoYW5nZXMoZ2l0RGF0YS5icmFuY2hlcy5kZWZhdWx0LCBydWxlLmNoYW5nZXMsIG9wdC5jd2QpKSBjb250aW51ZTtcblxuICAgICAgICAgICAgd2hlbiA9IHJ1bGUud2hlbiA/IHJ1bGUud2hlbiA6IGpvYldoZW47XG4gICAgICAgICAgICBhbGxvd0ZhaWx1cmUgPSBydWxlLmFsbG93X2ZhaWx1cmUgPz8gYWxsb3dGYWlsdXJlO1xuICAgICAgICAgICAgcnVsZVZhcmlhYmxlID0gcnVsZS52YXJpYWJsZXM7XG5cbiAgICAgICAgICAgIGJyZWFrOyAvLyBFYXJseSByZXR1cm4sIHdpbGwgbm90IGV2YWx1YXRlIHRoZSByZW1haW5pbmcgcnVsZXNcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB7d2hlbiwgYWxsb3dGYWlsdXJlLCB2YXJpYWJsZXM6IHJ1bGVWYXJpYWJsZX07XG4gICAgfVxuXG4gICAgc3RhdGljIGV2YWx1YXRlUnVsZUlmIChydWxlSWY6IHN0cmluZyB8IHVuZGVmaW5lZCwgZW52czoge1trZXk6IHN0cmluZ106IHN0cmluZ30pOiBib29sZWFuIHtcbiAgICAgICAgaWYgKHJ1bGVJZiA9PT0gdW5kZWZpbmVkKSByZXR1cm4gdHJ1ZTtcbiAgICAgICAgbGV0IGV2YWxTdHIgPSBydWxlSWY7XG5cbiAgICAgICAgY29uc3QgZmxhZ3NUb0JpbmFyeSA9IChmbGFnczogc3RyaW5nKTogbnVtYmVyID0+IHtcbiAgICAgICAgICAgIGxldCBiaW5hcnkgPSAwO1xuICAgICAgICAgICAgaWYgKGZsYWdzLmluY2x1ZGVzKFwiaVwiKSkge1xuICAgICAgICAgICAgICAgIGJpbmFyeSB8PSBSRTJKUy5DQVNFX0lOU0VOU0lUSVZFO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZsYWdzLmluY2x1ZGVzKFwic1wiKSkge1xuICAgICAgICAgICAgICAgIGJpbmFyeSB8PSBSRTJKUy5ET1RBTEw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmxhZ3MuaW5jbHVkZXMoXCJtXCIpKSB7XG4gICAgICAgICAgICAgICAgYmluYXJ5IHw9IFJFMkpTLk1VTFRJTElORTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBiaW5hcnk7XG4gICAgICAgIH07XG5cbiAgICAgICAgLy8gRXhwYW5kIGFsbCB2YXJpYWJsZXNcbiAgICAgICAgZXZhbFN0ciA9IHRoaXMuZXhwYW5kVGV4dFdpdGgoZXZhbFN0ciwge1xuICAgICAgICAgICAgdW5lc2NhcGU6IEpTT04uc3RyaW5naWZ5KFwiJFwiKSxcbiAgICAgICAgICAgIHZhcmlhYmxlOiAobmFtZSkgPT4gSlNPTi5zdHJpbmdpZnkoZW52c1tuYW1lXSA/PyBudWxsKS5yZXBsYWNlQWxsKFwiXFxcXFxcXFxcIiwgXCJcXFxcXCIpLFxuICAgICAgICB9KTtcbiAgICAgICAgY29uc3QgZXhwYW5kZWRFdmFsU3RyID0gZXZhbFN0cjtcblxuICAgICAgICAvLyBTY2VuYXJpbyB3aGVuIFJIUyBpcyBhIDxyZWdleD5cbiAgICAgICAgLy8gaHR0cHM6Ly9yZWdleHIuY29tLzg1c2pvXG4gICAgICAgIGNvbnN0IHBhdHRlcm4xID0gL1xccyooPzxvcGVyYXRvcj4oPzo9fil8KD86IX4pKVxccypcXC8oPzxyaHM+Lio/KVxcLyg/PGZsYWdzPltpZ21zdXldKikoXFxzfCR8XFwpKS9nO1xuICAgICAgICBldmFsU3RyID0gZXZhbFN0ci5yZXBsYWNlKHBhdHRlcm4xLCAoXywgb3BlcmF0b3IsIHJocywgZmxhZ3MsIHJlbWFpbmluZ1Rva2VucykgPT4ge1xuICAgICAgICAgICAgbGV0IF9vcGVyYXRvcjtcbiAgICAgICAgICAgIHN3aXRjaCAob3BlcmF0b3IpIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwiPX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCIhPVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIFwiIX5cIjpcbiAgICAgICAgICAgICAgICAgICAgX29wZXJhdG9yID0gXCI9PVwiO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgICAgICB0aHJvdyBvcGVyYXRvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNvbnN0IF9yaHMgPSBKU09OLnN0cmluZ2lmeShyaHMpOyAvLyBKU09OLnN0cmluZ2lmeSBmb3IgZXNjYXBpbmcgYFwiYFxuICAgICAgICAgICAgY29uc3QgY29udGFpbnNOb25Fc2NhcGVkU2xhc2ggPSAvKD88IVxcXFwpXFwvLy50ZXN0KF9yaHMpO1xuICAgICAgICAgICAgY29uc3QgYXNzZXJ0TXNnID0gW1xuICAgICAgICAgICAgICAgIFwiRXJyb3IgYXR0ZW1wdGluZyB0byBldmFsdWF0ZSB0aGUgZm9sbG93aW5nIHJ1bGVzOlwiLFxuICAgICAgICAgICAgICAgIFwiICBydWxlczpcIixcbiAgICAgICAgICAgICAgICBgICAgIC0gaWY6ICcke2V4cGFuZGVkRXZhbFN0cn0nYCxcbiAgICAgICAgICAgICAgICBcImFzIHJocyBjb250YWlucyB1bmVzY2FwZWQgcXVvdGVcIixcbiAgICAgICAgICAgIF07XG4gICAgICAgICAgICBhc3NlcnQoIWNvbnRhaW5zTm9uRXNjYXBlZFNsYXNoLCBhc3NlcnRNc2cuam9pbihcIlxcblwiKSk7XG4gICAgICAgICAgICBjb25zdCBmbGFnc0JpbmFyeSA9IGZsYWdzVG9CaW5hcnkoZmxhZ3MpO1xuICAgICAgICAgICAgcmV0dXJuIGAubWF0Y2hSRTJKUyhSRTJKUy5jb21waWxlKCR7X3Joc30sICR7ZmxhZ3NCaW5hcnl9KSkgJHtfb3BlcmF0b3J9IG51bGwke3JlbWFpbmluZ1Rva2Vuc31gO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBTY2VuYXJpbyB3aGVuIFJIUyBpcyBzdXJyb3VuZGVkIGJ5IHNpbmdsZS9kb3VibGUtcXVvdGVzXG4gICAgICAgIC8vIGh0dHBzOi8vc