From 14a13766c517750b9e9370e0e7dd5d1494d3cb1a Mon Sep 17 00:00:00 2001 From: PaulDalek Date: Sun, 5 Jan 2025 23:19:59 +0100 Subject: [PATCH] Built scripts. --- dist/index.cjs | 4 ++-- dist/index.esm.js | 2 +- dist/index.esm.js.map | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/dist/index.cjs b/dist/index.cjs index 40d941e..d1dafa2 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,2 +1,2 @@ -"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const v={array:e=>zod.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),boolean:()=>zod.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),enum:e=>zod.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),string:()=>zod.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),positiveNum:()=>zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),nonNegativeNum:()=>zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0))},Config=zod.z.object({PUPPETEER_ARGS:v.string(),HIGHCHARTS_VERSION:zod.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:zod.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_FORCE_FETCH:v.boolean(),HIGHCHARTS_CACHE_PATH:v.string(),HIGHCHARTS_ADMIN_TOKEN:v.string(),HIGHCHARTS_CORE_SCRIPTS:v.array(defaultConfig.highcharts.coreScripts.value),HIGHCHARTS_MODULE_SCRIPTS:v.array(defaultConfig.highcharts.moduleScripts.value),HIGHCHARTS_INDICATOR_SCRIPTS:v.array(defaultConfig.highcharts.indicatorScripts.value),HIGHCHARTS_CUSTOM_SCRIPTS:v.array(defaultConfig.highcharts.customScripts.value),EXPORT_INFILE:v.string(),EXPORT_INSTR:v.string(),EXPORT_OPTIONS:v.string(),EXPORT_SVG:v.string(),EXPORT_BATCH:v.string(),EXPORT_OUTFILE:v.string(),EXPORT_TYPE:v.enum(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:v.enum(["chart","stockChart","mapChart","ganttChart"]),EXPORT_B64:v.boolean(),EXPORT_NO_DOWNLOAD:v.boolean(),EXPORT_HEIGHT:v.positiveNum(),EXPORT_WIDTH:v.positiveNum(),EXPORT_SCALE:v.positiveNum(),EXPORT_DEFAULT_HEIGHT:v.positiveNum(),EXPORT_DEFAULT_WIDTH:v.positiveNum(),EXPORT_DEFAULT_SCALE:v.positiveNum(),EXPORT_GLOBAL_OPTIONS:v.string(),EXPORT_THEME_OPTIONS:v.string(),EXPORT_RASTERIZATION_TIMEOUT:v.nonNegativeNum(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:v.boolean(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:v.boolean(),CUSTOM_LOGIC_CUSTOM_CODE:v.string(),CUSTOM_LOGIC_CALLBACK:v.string(),CUSTOM_LOGIC_RESOURCES:v.string(),CUSTOM_LOGIC_LOAD_CONFIG:v.string(),CUSTOM_LOGIC_CREATE_CONFIG:v.string(),SERVER_ENABLE:v.boolean(),SERVER_HOST:v.string(),SERVER_PORT:v.positiveNum(),SERVER_UPLOAD_LIMIT:v.positiveNum(),SERVER_BENCHMARKING:v.boolean(),SERVER_PROXY_HOST:v.string(),SERVER_PROXY_PORT:v.positiveNum(),SERVER_PROXY_TIMEOUT:v.nonNegativeNum(),SERVER_RATE_LIMITING_ENABLE:v.boolean(),SERVER_RATE_LIMITING_MAX_REQUESTS:v.nonNegativeNum(),SERVER_RATE_LIMITING_WINDOW:v.nonNegativeNum(),SERVER_RATE_LIMITING_DELAY:v.nonNegativeNum(),SERVER_RATE_LIMITING_TRUST_PROXY:v.boolean(),SERVER_RATE_LIMITING_SKIP_KEY:v.string(),SERVER_RATE_LIMITING_SKIP_TOKEN:v.string(),SERVER_SSL_ENABLE:v.boolean(),SERVER_SSL_FORCE:v.boolean(),SERVER_SSL_PORT:v.positiveNum(),SERVER_SSL_CERT_PATH:v.string(),POOL_MIN_WORKERS:v.nonNegativeNum(),POOL_MAX_WORKERS:v.nonNegativeNum(),POOL_WORK_LIMIT:v.positiveNum(),POOL_ACQUIRE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_TIMEOUT:v.nonNegativeNum(),POOL_DESTROY_TIMEOUT:v.nonNegativeNum(),POOL_IDLE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_RETRY_INTERVAL:v.nonNegativeNum(),POOL_REAPER_INTERVAL:v.nonNegativeNum(),POOL_BENCHMARKING:v.boolean(),LOGGING_LEVEL:zod.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:v.string(),LOGGING_DEST:v.string(),LOGGING_TO_CONSOLE:v.boolean(),LOGGING_TO_FILE:v.boolean(),UI_ENABLE:v.boolean(),UI_ROUTE:v.string(),OTHER_NODE_ENV:v.enum(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:v.boolean(),OTHER_NO_LOGO:v.boolean(),OTHER_HARD_RESET_PAGE:v.boolean(),OTHER_BROWSER_SHELL_MODE:v.boolean(),DEBUG_ENABLE:v.boolean(),DEBUG_HEADLESS:v.boolean(),DEBUG_DEVTOOLS:v.boolean(),DEBUG_LISTEN_TO_CONSOLE:v.boolean(),DEBUG_DUMPIO:v.boolean(),DEBUG_SLOW_MO:v.nonNegativeNum(),DEBUG_DEBUGGING_PORT:v.positiveNum()}),envs=Config.partial().parse(process.env),globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};t.length&&(r=_loadConfigFile(t),n=_pairArgumentValue(nestedProps,t));const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(fs.readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:path.join(__dirname$1,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=e;else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=e}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);return e.validatedOptions={_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL2VudnMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9yZXNvdXJjZVJlbGVhc2UuanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdXRpbGl0eSBtb2R1bGUgcHJvdmlkZXNcclxuICogYSBjb21wcmVoZW5zaXZlIHNldCBvZiBoZWxwZXIgZnVuY3Rpb25zIGFuZCBjb25zdGFudHMgZGVzaWduZWQgdG8gc3RyZWFtbGluZVxyXG4gKiBhbmQgZW5oYW5jZSB2YXJpb3VzIG9wZXJhdGlvbnMgcmVxdWlyZWQgZm9yIEhpZ2hjaGFydHMgZXhwb3J0IHRhc2tzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgaXNBYnNvbHV0ZSwgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgMC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIG51bGwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4VHlwZSh0eXBlLCBvdXRmaWxlID0gbnVsbCkge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBHZXQgZm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBPYmplY3QudmFsdWVzKG1pbWVUeXBlcyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIC8vIFN1cHBvcnQgdGhlIEpQRyB0eXBlXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBwYXRoIGlzIHJlbGF0aXZlIG9yIGFic29sdXRlIGFuZCByZXR1cm5zIHRoZSBjb3JyZWN0ZWQsXHJcbiAqIGFic29sdXRlIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0Fic29sdXRlUGF0aFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIGJlIGNoZWNrZWQgb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhYnNvbHV0ZSBwYXRoLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFic29sdXRlUGF0aChwYXRoKSB7XHJcbiAgcmV0dXJuIGlzQWJzb2x1dGUocGF0aCkgPyBwYXRoIDogam9pbihfX2Rpcm5hbWUsIHBhdGgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgaW5wdXQgZGF0YSB0byBhIEJhc2U2NCBzdHJpbmcgYmFzZWQgb24gdGhlIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QmFzZTY0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCB0byBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEJhc2U2NCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2U2NChpbnB1dCwgdHlwZSkge1xyXG4gIC8vIEZvciBwZGYgYW5kIHN2ZyB0eXBlcyB0aGUgaW5wdXQgbXVzdCBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZnJvbSBhIGJ1ZmZlclxyXG4gIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oaW5wdXQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gRm9yIHBuZyBhbmQganBlZyBpbnB1dCBpcyBhbHJlYWR5IGEgQmFzZTY0IHN0cmluZ1xyXG4gIHJldHVybiBpbnB1dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgc3RyaW5naWZpZWQgZGF0ZSB3aXRob3V0IHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlKCkge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0b3JlZCB0aW1lIHZhbHVlIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWUoKSB7XHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KGl0ZW0pIHtcclxuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGl0ZW0pID09PSAnW29iamVjdCBPYmplY3RdJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RFbXB0eVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHkoaXRlbSkge1xyXG4gIHJldHVybiAoXHJcbiAgICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAgICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgICBpdGVtICE9PSBudWxsICYmXHJcbiAgICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDBcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGl0ZW0pIHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgYHByb2Nlc3MuaHJ0aW1lKClgIG1ldGhvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lYXN1cmVUaW1lXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVhc3VyZVRpbWUoKSB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHJvdW5kTnVtYmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiByb3VuZE51bWJlcih2YWx1ZSwgcHJlY2lzaW9uID0gMSkge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdG9Cb29sZWFuXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRvQm9vbGVhbihpdGVtKSB7XHJcbiAgcmV0dXJuIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG59XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB3cmFwQXJvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzQ2FsbGJhY2s9ZmFsc2VdIC0gRmxhZyB0aGF0IGluZGljYXRlcyB0aGUgcmV0dXJuZWQgY29kZVxyXG4gKiBtdXN0IGJlIGluIGEgY2FsbGJhY2sgZm9ybWF0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KHN0cmluZ3xudWxsKX0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgbnVsbCBpZiB3cmFwcGluZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB3cmFwQXJvdW5kKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcywgaXNDYWxsYmFjayA9IGZhbHNlKSB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIC8vIExvYWQgYSBmaWxlIGlmIHRoZSBmaWxlIHJlc291cmNlcyBhcmUgYWxsb3dlZFxyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGN1c3RvbUNvZGUpLCAndXRmOCcpLFxyXG4gICAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICAgIGlzQ2FsbGJhY2tcclxuICAgICAgICAgIClcclxuICAgICAgICA6IG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAhaXNDYWxsYmFjayAmJlxyXG4gICAgICAoY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBUcmVhdCBhIGZ1bmN0aW9uIGFzIGEgc2VsZi1pbnZva2luZyBleHByZXNzaW9uXHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9yIHJldHVybiBhcyBhIHN0cmluZ2lmaWVkIGNvZGVcclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhDb25zdHIsXHJcbiAgZml4T3V0ZmlsZSxcclxuICBmaXhUeXBlLFxyXG4gIGdldEFic29sdXRlUGF0aCxcclxuICBnZXRCYXNlNjQsXHJcbiAgZ2V0TmV3RGF0ZSxcclxuICBnZXROZXdEYXRlVGltZSxcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgbWVhc3VyZVRpbWUsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEEgbW9kdWxlIGZvciBtYW5hZ2luZyBsb2dnaW5nIGZ1bmN0aW9uYWxpdHkgd2l0aCBjdXN0b21pemFibGVcclxuICogbG9nIGxldmVscywgY29uc29sZSBhbmQgZmlsZSBsb2dnaW5nIG9wdGlvbnMsIGFuZCBlcnJvciBoYW5kbGluZyBzdXBwb3J0LlxyXG4gKiBUaGUgbW9kdWxlIGFsc28gZW5zdXJlcyB0aGF0IGZpbGUtYmFzZWQgbG9ncyBhcmUgc3RvcmVkIGluIGEgc3RydWN0dXJlZFxyXG4gKiBkaXJlY3RvcnksIGNyZWF0aW5nIHRoZSBuZWNlc3NhcnkgcGF0aHMgYXV0b21hdGljYWxseSBpZiB0aGV5IGRvIG5vdCBleGlzdC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEFic29sdXRlUGF0aCwgZ2V0TmV3RGF0ZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxuY29uc3QgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gRnVsbCBwYXRoIHRvIHRoZSBsb2cgZmlsZVxyXG4gIHBhdGhUb0xvZzogJycsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIHRoZSBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGBjb25zb2xlLmxvZ2AsIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2coLi4uYXJncykge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsc0Rlc2MsIGxldmVsIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgaXQgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nV2l0aFN0YWNrXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWRcclxuICogYWxvbmcgd2l0aCB0aGUgZXJyb3IuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dXaXRoU3RhY2sobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpbml0TG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZ09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgbG9nZ2luZ2Agb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpbml0TG9nZ2luZyhsb2dnaW5nT3B0aW9ucykge1xyXG4gIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIGBsb2dnaW5nT3B0aW9uc2Agb2JqZWN0XHJcbiAgY29uc3QgeyBsZXZlbCwgZGVzdCwgZmlsZSwgdG9Db25zb2xlLCB0b0ZpbGUgfSA9IGxvZ2dpbmdPcHRpb25zO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZ2dpbmcgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsZXZlbCk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29uc29sZSBsb2dnaW5nXHJcbiAgZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBmaWxlIGxvZ2dpbmdcclxuICBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcclxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2UsIG9yIDUgPSBiZW5jaG1hcmspLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0TG9nTGV2ZWxcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0TG9nTGV2ZWwobGV2ZWwpIHtcclxuICBpZiAobGV2ZWwgPj0gMCAmJiBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbGV2ZWw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBjb25zb2xlIGxvZ2dpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvQ29uc29sZSAtIFRoZSBmbGFnIGZvciBzZXR0aW5nIHRoZSBsb2dnaW5nIHRvIHRoZSBjb25zb2xlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSkge1xyXG4gIC8vIFVwZGF0ZSBvcHRpb25zIGZvciB0aGUgY29uc29sZSBsb2dnaW5nXHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSB0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGRlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIFRoZSBmbGFnIGZvciBzZXR0aW5nIHRoZSBsb2dnaW5nIHRvIGEgZmlsZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZyhkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAvLyBVcGRhdGUgb3B0aW9ucyBmb3IgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGxvZ2dpbmcudG9GaWxlID0gdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9ubHkgaWYgdGhlIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkXHJcbiAgaWYgKHRvRmlsZSkge1xyXG4gICAgbG9nZ2luZy5kZXN0ID0gZGVzdDtcclxuICAgIGxvZ2dpbmcuZmlsZSA9IGZpbGU7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kc1xyXG4gKiB0aGUgY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2dUb0ZpbGVcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpIHtcclxuICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxyXG4gICAgIWV4aXN0c1N5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpICYmXHJcbiAgICAgIG1rZGlyU3luYyhnZXRBYnNvbHV0ZVBhdGgobG9nZ2luZy5kZXN0KSk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBmdWxsIHBhdGhcclxuICAgIGxvZ2dpbmcucGF0aFRvTG9nID0gZ2V0QWJzb2x1dGVQYXRoKGpvaW4obG9nZ2luZy5kZXN0LCBsb2dnaW5nLmZpbGUpKTtcclxuXHJcbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cclxuICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xyXG4gIH1cclxuXHJcbiAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxyXG4gIGFwcGVuZEZpbGUoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyxcclxuICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXHJcbiAgICAoZXJyb3IpID0+IHtcclxuICAgICAgaWYgKGVycm9yICYmIGxvZ2dpbmcudG9GaWxlICYmIGxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xyXG4gICAgICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBpbml0TG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29uZmlndXJhdGlvbiBtYW5hZ2VtZW50IG1vZHVsZSBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci5cclxuICogUHJvdmlkZXMgZGVmYXVsdCBjb25maWd1cmF0aW9ucyB0aGF0IHN1cHBvcnQgZW52aXJvbm1lbnQgdmFyaWFibGVzLCBDTElcclxuICogYXJndW1lbnRzLCBhbmQgaW50ZXJhY3RpdmUgcHJvbXB0cyBmb3IgY3VzdG9taXphdGlvbiBvZiBvcHRpb25zIGFuZCBmZWF0dXJlcy5cclxuICogQWRkaXRpb25hbGx5LCBpdCBtYXBzIGxlZ2FjeSBvcHRpb25zIHRvIG1vZGVybiBzdHJ1Y3R1cmVzLCBnZW5lcmF0ZXMgbmVzdGVkXHJcbiAqIGFyZ3VtZW50IG1hcHBpbmdzLCBhbmQgZGlzcGxheXMgQ0xJIHVzYWdlIGluZm9ybWF0aW9uLlxyXG4gKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBhbGwgYXZhaWxhYmxlIG9wdGlvbnMsIG9yZ2FuaXplZFxyXG4gKiBieSBzZWN0aW9ucy5cclxuICpcclxuICogVGhpcyBvYmplY3QgaW5jbHVkZXM6XHJcbiAqIC0gRGVmYXVsdCB2YWx1ZXMgZm9yIGVhY2ggb3B0aW9uXHJcbiAqIC0gRGF0YSB0eXBlcyBmb3IgdmFsaWRhdGlvblxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzXHJcbiAqIC0gRGVzY3JpcHRpb25zIG9mIGVhY2ggcHJvcGVydHlcclxuICogLSBJbmZvcm1hdGlvbiB1c2VkIGZvciBwcm9tcHRzIGluIGludGVyYWN0aXZlIGNvbmZpZ3VyYXRpb25cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2VcclxuICogLSBbT3B0aW9uYWxdIExlZ2FjeSBuYW1lcyBmcm9tIHRoZSBwcmV2aW91cyBQaGFudG9tSlMtYmFzZWQgc2VydmVyXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZGVmYXVsdENvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IHtcclxuICAgIGFyZ3M6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxyXG4gICAgICAgICctLWFzaC1uby1udWRnZXMnLFxyXG4gICAgICAgICctLWF1dG9wbGF5LXBvbGljeT11c2VyLWdlc3R1cmUtcmVxdWlyZWQnLFxyXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYWNjZWxlcmF0ZWQtMmQtY2FudmFzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtbmV0d29ya2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZGluZy1vY2NsdWRlZC13aW5kb3dzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJyZWFrcGFkJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jbGllbnQtc2lkZS1waGlzaGluZy1kZXRlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LWV4dGVuc2lvbnMtd2l0aC1iYWNrZ3JvdW5kLXBhZ2VzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGVmYXVsdC1hcHBzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRldi1zaG0tdXNhZ2UnLFxyXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcclxuICAgICAgICAnLS1kaXNhYmxlLWV4dGVuc2lvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZmVhdHVyZXM9Q2FsY3VsYXRlTmF0aXZlV2luT2NjbHVzaW9uLEludGVyZXN0RmVlZENvbnRlbnRTdWdnZXN0aW9ucyxXZWJPVFAnLFxyXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWlwYy1mbG9vZGluZy1wcm90ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWxvZ2dpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1vZmZlci1zdG9yZS11bm1hc2tlZC13YWxsZXQtY2FyZHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtcG9wdXAtYmxvY2tpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcm9tcHQtb24tcmVwb3N0JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXJlbmRlcmVyLWJhY2tncm91bmRpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlc3Npb24tY3Jhc2hlZC1idWJibGUnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2V0dWlkLXNhbmRib3gnLFxyXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNwZWVjaC1hcGknLFxyXG4gICAgICAgICctLWRpc2FibGUtc3luYycsXHJcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxyXG4gICAgICAgICctLWhpZGUtY3Jhc2gtcmVzdG9yZS1idWJibGUnLFxyXG4gICAgICAgICctLWhpZGUtc2Nyb2xsYmFycycsXHJcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXHJcbiAgICAgICAgJy0tbXV0ZS1hdWRpbycsXHJcbiAgICAgICAgJy0tbm8tZGVmYXVsdC1icm93c2VyLWNoZWNrJyxcclxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxyXG4gICAgICAgICctLW5vLXBpbmdzJyxcclxuICAgICAgICAnLS1uby1zYW5kYm94JyxcclxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXHJcbiAgICAgICAgJy0tbm8tenlnb3RlJyxcclxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXHJcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcclxuICAgICAgICAnLS11c2UtbW9jay1rZXljaGFpbidcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ1BVUFBFVEVFUl9BUkdTJyxcclxuICAgICAgY2xpTmFtZTogJ3B1cHBldGVlckFyZ3MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FycmF5IG9mIFB1cHBldGVlciBhcmd1bWVudHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGhpZ2hjaGFydHM6IHtcclxuICAgIHZlcnNpb246IHtcclxuICAgICAgdmFsdWU6ICdsYXRlc3QnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfVkVSU0lPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2RuVXJsOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NETl9VUkwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0NETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGbGFnIHRvIHJlZmV0Y2ggc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY2FjaGVQYXRoOiB7XHJcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NBQ0hFX1BBVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RpcmVjdG9yeSBwYXRoIGZvciBjYWNoZWQgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY29yZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DT1JFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ3N0b2NrJyxcclxuICAgICAgICAnbWFwJyxcclxuICAgICAgICAnZ2FudHQnLFxyXG4gICAgICAgICdleHBvcnRpbmcnLFxyXG4gICAgICAgICdwYXJhbGxlbC1jb29yZGluYXRlcycsXHJcbiAgICAgICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgICAgIC8vICdhbm5vdGF0aW9ucy1hZHZhbmNlZCcsXHJcbiAgICAgICAgJ2Jvb3N0LWNhbnZhcycsXHJcbiAgICAgICAgJ2Jvb3N0JyxcclxuICAgICAgICAnZGF0YScsXHJcbiAgICAgICAgJ2RhdGEtdG9vbHMnLFxyXG4gICAgICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICAgICAnc3RhdGljLXNjYWxlJyxcclxuICAgICAgICAnYnJva2VuLWF4aXMnLFxyXG4gICAgICAgICdoZWF0bWFwJyxcclxuICAgICAgICAndGlsZW1hcCcsXHJcbiAgICAgICAgJ3RpbGVkd2VibWFwJyxcclxuICAgICAgICAndGltZWxpbmUnLFxyXG4gICAgICAgICd0cmVlbWFwJyxcclxuICAgICAgICAndHJlZWdyYXBoJyxcclxuICAgICAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgICAgICdkcmlsbGRvd24nLFxyXG4gICAgICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcclxuICAgICAgICAnYnVsbGV0JyxcclxuICAgICAgICAnZnVubmVsJyxcclxuICAgICAgICAnZnVubmVsM2QnLFxyXG4gICAgICAgICdnZW9oZWF0bWFwJyxcclxuICAgICAgICAncHlyYW1pZDNkJyxcclxuICAgICAgICAnbmV0d29ya2dyYXBoJyxcclxuICAgICAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAgICAgJ3BhcmV0bycsXHJcbiAgICAgICAgJ3BhdHRlcm4tZmlsbCcsXHJcbiAgICAgICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAgICAgJ3ByaWNlLWluZGljYXRvcicsXHJcbiAgICAgICAgJ3NhbmtleScsXHJcbiAgICAgICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICAgICAnZGVwZW5kZW5jeS13aGVlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1sYWJlbCcsXHJcbiAgICAgICAgJ3Nlcmllcy1vbi1wb2ludCcsXHJcbiAgICAgICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgICAgICAvLyAnc3RvY2stdG9vbHMnLFxyXG4gICAgICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAgICAgJ3N1bmJ1cnN0JyxcclxuICAgICAgICAndmFyaWFibGUtcGllJyxcclxuICAgICAgICAndmFyaXdpZGUnLFxyXG4gICAgICAgICd2ZWN0b3InLFxyXG4gICAgICAgICd2ZW5uJyxcclxuICAgICAgICAnd2luZGJhcmInLFxyXG4gICAgICAgICd3b3JkY2xvdWQnLFxyXG4gICAgICAgICd4cmFuZ2UnLFxyXG4gICAgICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgICAgICdkcmFnLXBhbmVzJyxcclxuICAgICAgICAnZGVidWdnZXInLFxyXG4gICAgICAgICdkdW1iYmVsbCcsXHJcbiAgICAgICAgJ2xvbGxpcG9wJyxcclxuICAgICAgICAnY3lsaW5kZXInLFxyXG4gICAgICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgICAgICdkb3RwbG90JyxcclxuICAgICAgICAnbWFya2VyLWNsdXN0ZXJzJyxcclxuICAgICAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgICAgICdoZWlraW5hc2hpJyxcclxuICAgICAgICAnZmxvd21hcCcsXHJcbiAgICAgICAgJ2V4cG9ydC1kYXRhJyxcclxuICAgICAgICAnbmF2aWdhdG9yJyxcclxuICAgICAgICAndGV4dHBhdGgnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIG1vZHVsZSBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbmRpY2F0b3JTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2luZGljYXRvcnMtYWxsJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGluZGljYXRvciBzY3JpcHRzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjMwLjEvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuNDUvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NVU1RPTV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBZGRpdGlvbmFsIGN1c3RvbSBzY3JpcHRzIG9yIGRlcGVuZGVuY2llcyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5GSUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0lucHV0IGZpbGVuYW1lIHdpdGggdHlwZSwgZm9ybWF0dGVkIGNvcnJlY3RseSBhcyBKU09OIG9yIFNWRycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lOU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ092ZXJyaWRlcyB0aGUgYGluZmlsZWAgd2l0aCBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBTVkcgaW5wdXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRQcm9wcyA9IF9jcmVhdGVOZXN0ZWRQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8vIFByb3BlcnRpZXMgbmFtZXMgdGhhdCBzaG91bGQgbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IF9jcmVhdGVBYnNvbHV0ZVByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdlbmVyYXRlcyBhIG1hcHBpbmcgb2YgbmVzdGVkIGFyZ3VtZW50IGNoYWlucyBmcm9tIGEgbmVzdGVkXHJcbiAqIGNvbmZpZyBvYmplY3QuIFRoaXMgZnVuY3Rpb24gdHJhdmVyc2VzIGEgbmVzdGVkIG9iamVjdCBhbmQgY3JlYXRlcyBhIG1hcHBpbmdcclxuICogd2hlcmUgZWFjaCBrZXkgaXMgYW4gYXJndW1lbnQgbmFtZSAoZWl0aGVyIGZyb20gYGNsaU5hbWVgLCBgbGVnYWN5TmFtZWAsXHJcbiAqIG9yIHRoZSBvcmlnaW5hbCBrZXkpIGFuZCBlYWNoIHZhbHVlIGlzIGEgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgY2hhaW5cclxuICogb2YgbmVzdGVkIHByb3BlcnRpZXMgbGVhZGluZyB0byB0aGF0IGFyZ3VtZW50LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbbmVzdGVkUHJvcHM9e31dIC0gVGhlIGFjY3VtdWxhdG9yIG9iamVjdCBmb3Igc3RvcmluZ1xyXG4gKiB0aGUgcmVzdWx0aW5nIGFyZ3VtZW50cyBjaGFpbnMuICBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcHJvcENoYWluPScnXSAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzLFxyXG4gKiB1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbi4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIGNhbiBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbYWJzb2x1dGVQcm9wcz1bXV0gLSBBbiBhcnJheSB0byBjb2xsZWN0IHRoZSBuYW1lc1xyXG4gKiBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBhcnJheS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5LjxzdHJpbmc+fSBBbiBhcnJheSBjb250YWluaW5nIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZVxyXG4gKiBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZUFic29sdXRlUHJvcHMoY29uZmlnLCBhYnNvbHV0ZVByb3BzID0gW10pIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudHlwZXMgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzXHJcbiAgICAgIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGVudHJ5LCBhYnNvbHV0ZVByb3BzKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIHRoZSBvcHRpb24gY2FuIGJlIGFuIG9iamVjdCwgc2F2ZSBpdHMgdHlwZSBpbiB0aGUgYXJyYXlcclxuICAgICAgaWYgKGVudHJ5LnR5cGVzLmluY2x1ZGVzKCdPYmplY3QnKSkge1xyXG4gICAgICAgIGFic29sdXRlUHJvcHMucHVzaChrZXkpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgYXJyYXkgd2l0aCB0aGUgbmFtZXMgb2YgYWJzb2x1dGUgcHJvcGVydGllc1xyXG4gIHJldHVybiBhYnNvbHV0ZVByb3BzO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRQcm9wcyxcclxuICBhYnNvbHV0ZVByb3BzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG4gKiB3aXRoIHRoZSAnem9kJyBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZFxyXG4gKiB0byBiZSB1c2VkIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBgZW52c2AuIFdlIHNob3VsZCBub3QgdXNlIHRoZSBgcHJvY2Vzcy5lbnZgXHJcbiAqIGRpcmVjdGx5IGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxyXG4gKlxyXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxyXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcclxuICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZSksXHJcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShcclxuICAgIGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXHJcbiAgKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KFxyXG4gICAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICApLFxyXG4gIEhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFM6IHYuYXJyYXkoXHJcbiAgICBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZVxyXG4gICksXHJcblxyXG4gIC8vIGV4cG9ydFxyXG4gIEVYUE9SVF9JTkZJTEU6IHYuc3RyaW5nKCksXHJcbiAgRVhQT1JUX0lOU1RSOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9TVkc6IHYuc3RyaW5nKCksXHJcbiAgRVhQT1JUX0JBVENIOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9PVVRGSUxFOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxyXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcclxuICBFWFBPUlRfQjY0OiB2LmJvb2xlYW4oKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHYuYm9vbGVhbigpLFxyXG4gIEVYUE9SVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0dMT0JBTF9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9USEVNRV9PUFRJT05TOiB2LnN0cmluZygpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdi5zdHJpbmcoKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHYuc3RyaW5nKCksXHJcbiAgQ1VTVE9NX0xPR0lDX1JFU09VUkNFUzogdi5zdHJpbmcoKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHYuc3RyaW5nKCksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIHNlcnZlclxyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1VQTE9BRF9MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgTE9HR0lOR19UT19GSUxFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgTWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGJ5IGxvYWRpbmdcclxuICogYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgZGVmYXVsdCBzZXR0aW5ncyxcclxuICogZW52aXJvbm1lbnQgdmFyaWFibGVzLCB1c2VyLXByb3ZpZGVkIG9wdGlvbnMsIGFuZCBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKiBFbnN1cmVzIHRoZSBnbG9iYWwgb3B0aW9ucyBhcmUgdXAtdG8tZGF0ZSB3aXRoIHRoZSBoaWdoZXN0IHByaW9yaXR5IHZhbHVlcy5cclxuICogUHJvdmlkZXMgZnVuY3Rpb25zIGZvciBhY2Nlc3NpbmcgYW5kIHVwZGF0aW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgaXNPYmplY3QsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZywgbmVzdGVkUHJvcHMsIGFic29sdXRlUHJvcHMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIHdpdGggaW5pdGlhbCB2YWx1ZXMgZnJvbSB0aGUgZGVmYXVsdCBjb25maWdcclxuY29uc3QgZ2xvYmFsT3B0aW9ucyA9IF9pbml0R2xvYmFsT3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0XHJcbiAqIG9yIGl0cyBjb3B5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtnZXRSZWZlcmVuY2U9dHJ1ZV0gLSBPcHRpb25hbCBwYXJhbWV0ZXIgdG8gZGVjaWRlIHdoZXRoZXJcclxuICogdG8gcmV0dXJuIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0XHJcbiAqIG9yIHJldHVybiBhIGNvcHkgb2YgaXQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRydWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2VcclxuICogb2JqZWN0IG9yIGl0cyBjb3B5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE9wdGlvbnMoZ2V0UmVmZXJlbmNlID0gdHJ1ZSkge1xyXG4gIHJldHVybiBnZXRSZWZlcmVuY2UgPyBnbG9iYWxPcHRpb25zIDogZGVlcENvcHkoZ2xvYmFsT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBnbG9iYWwgb3B0aW9ucyBvZiB0aGUgZXhwb3J0IHNlcnZlciBpbnN0YW5jZSwga2VlcGluZyB0aGUgcHJpbmNpcGxlXHJcbiAqIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkgZnJvbSBhbGwgYXZhaWxhYmxlIHNvdXJjZXMuIEl0IGFjY2VwdHMgb3B0aW9uYWxcclxuICogYGN1c3RvbU9wdGlvbnNgIG9iamVjdCBhbmQgYGNsaUFyZ3NgIGFycmF5IHdpdGggYXJndW1lbnRzIGZyb20gdGhlIENMSS4gVGhlc2VcclxuICogb3B0aW9ucyB3aWxsIGJlIHZhbGlkYXRlZCBhbmQgYXBwbGllZCBpZiBwcm92aWRlZC5cclxuICpcclxuICogVGhlIHByaW9yaXR5IG9yZGVyIG9mIHNldHRpbmcgdmFsdWVzIGlzOlxyXG4gKlxyXG4gKiAxLiBPcHRpb25zIGZyb20gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgKGRlZmF1bHQgdmFsdWVzKS5cclxuICogMi4gT3B0aW9ucyBmcm9tIGEgY3VzdG9tIEpTT04gZmlsZSAobG9hZGVkIGJ5IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICogMy4gT3B0aW9ucyBmcm9tIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHRoZSBgLmVudmAgZmlsZSkuXHJcbiAqIDQuIE9wdGlvbnMgZnJvbSB0aGUgZmlyc3QgcGFyYW1ldGVyIChieSBkZWZhdWx0IGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIDUuIE9wdGlvbnMgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2N1c3RvbU9wdGlvbnM9e31dIC0gT3B0aW9uYWwgY3VzdG9tIG9wdGlvbnMgZm9yIGFkZGl0aW9uYWxcclxuICogY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbY2xpQXJncz1bXV0gLSBPcHRpb25hbCBjb21tYW5kIGxpbmUgYXJndW1lbnRzXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFttb2RpZnlHbG9iYWw9ZmFsc2VdIC0gT3B0aW9uYWwgcGFyYW1ldGVyIHRvIGRlY2lkZVxyXG4gKiB3aGV0aGVyIHRvIHVwZGF0ZSBhbmQgcmV0dXJuIHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9mIHRoZSBzZXJ2ZXIgaW5zdGFuY2Ugb2JqZWN0IG9yIHJldHVybiBhIGNvcHkgb2YgaXQuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LCByZWZsZWN0aW5nIHRoZSBtZXJnZWRcclxuICogY29uZmlndXJhdGlvbiBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRPcHRpb25zKFxyXG4gIGN1c3RvbU9wdGlvbnMgPSB7fSxcclxuICBjbGlBcmdzID0gW10sXHJcbiAgbW9kaWZ5R2xvYmFsID0gZmFsc2VcclxuKSB7XHJcbiAgLy8gT2JqZWN0IGZvciBvcHRpb25zIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb25cclxuICBsZXQgY29uZmlnT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBPYmplY3QgZm9yIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgbGV0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChjbGlBcmdzLmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYGxvYWRDb25maWdgXHJcbiAgICBjb25maWdPcHRpb25zID0gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpO1xyXG5cclxuICAgIC8vIEdldCBvcHRpb25zIGZyb20gdGhlIENMSVxyXG4gICAgY2xpT3B0aW9ucyA9IF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncyk7XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IG9yIGEgY29weSBvZiB0aGUgb2JqZWN0XHJcbiAgY29uc3QgZ2VuZXJhbE9wdGlvbnMgPSBnZXRPcHRpb25zKG1vZGlmeUdsb2JhbCk7XHJcblxyXG4gIC8vIFVwZGF0ZSB2YWx1ZXMgb2YgdGhlIGdlbmVyYWwgb3B0aW9ucyB3aXRoIHZhbHVlcyBmcm9tIGVhY2ggc291cmNlIHBvc3NpYmxlXHJcbiAgX3VwZGF0ZU9wdGlvbnMoXHJcbiAgICBkZWZhdWx0Q29uZmlnLFxyXG4gICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICBjb25maWdPcHRpb25zLFxyXG4gICAgY3VzdG9tT3B0aW9ucyxcclxuICAgIGNsaU9wdGlvbnNcclxuICApO1xyXG5cclxuICAvLyBSZXR1cm4gb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZXJnZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9yaWdpbmFsT3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zLCBuZXdPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBuZXdPcHRpb25zYCBpcyBhIGNvcnJlY3Qgb2JqZWN0XHJcbiAgaWYgKGlzT2JqZWN0KG5ld09wdGlvbnMpKSB7XHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xyXG4gICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSA9XHJcbiAgICAgICAgaXNPYmplY3QodmFsdWUpICYmXHJcbiAgICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9uc1trZXldLCB2YWx1ZSlcclxuICAgICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICAgIDogb3JpZ2luYWxPcHRpb25zW2tleV07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgY29uZmlndXJhdGlvbiBvcHRpb25zIChQaGFudG9tSlMpIHRvIGEgbmV3IGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS4gVGhpcyBmdW5jdGlvbiBjb252ZXJ0cyBmbGF0LCBvbGQtc3RydWN0dXJlZCBvcHRpb25zIGludG9cclxuICogYSBuZXcsIG5lc3RlZCBjb25maWd1cmF0aW9uIGZvcm1hdCBiYXNlZCBvbiBhIHByZWRlZmluZWQgbWFwcGluZ1xyXG4gKiAoYG5lc3RlZFByb3BzYCkuIFRoZSBuZXcgZm9ybWF0IGlzIHVzZWQgZm9yIFB1cHBldGVlciwgd2hpbGUgdGhlIG9sZCBmb3JtYXRcclxuICogd2FzIHVzZWQgZm9yIFBoYW50b21KUy5cclxuICpcclxuICogQGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIFRoZSBvbGQsIGZsYXQgY29uZmlndXJhdGlvbiBvcHRpb25zXHJcbiAqIHRvIGJlIGNvbnZlcnRlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQSBuZXcgb2JqZWN0IGNvbnRhaW5pbmcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGFjY29yZGluZ1xyXG4gKiB0byB0aGUgbWFwcGluZyBkZWZpbmVkIGluIGBuZXN0ZWRQcm9wc2Agb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBwcm92aWRlZFxyXG4gKiBgb2xkT3B0aW9uc2AgaXMgbm90IGEgY29ycmVjdCBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zKG9sZE9wdGlvbnMpIHtcclxuICAvLyBBbiBvYmplY3QgZm9yIHRoZSBuZXcgc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCB2YWx1ZSBpcyBhIGNvcnJlY3Qgb2JqZWN0XHJcbiAgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChvbGRPcHRpb25zKSA9PT0gJ1tvYmplY3QgT2JqZWN0XScpIHtcclxuICAgIC8vIEl0ZXJhdGUgb3ZlciBlYWNoIGtleS12YWx1ZSBwYWlyIGluIHRoZSBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgICAvLyBJZiB0aGVyZSBpcyBhIG5lc3RlZCBtYXBwaW5nLCBzcGxpdCBpdCBpbnRvIGEgcHJvcGVydGllcyBjaGFpblxyXG4gICAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1trZXldXHJcbiAgICAgICAgPyBuZXN0ZWRQcm9wc1trZXldLnNwbGl0KCcuJylcclxuICAgICAgICA6IFtdO1xyXG5cclxuICAgICAgLy8gSWYgaXQgaXMgdGhlIGxhc3QgcHJvcGVydHkgaW4gdGhlIGNoYWluLCBhc3NpZ24gdGhlIHZhbHVlLCBvdGhlcndpc2UsXHJcbiAgICAgIC8vIGNyZWF0ZSBvciByZXVzZSB0aGUgbmVzdGVkIG9iamVjdFxyXG4gICAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxyXG4gICAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcclxuICAgICAgICBuZXdPcHRpb25zXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIG5ldywgc3RydWN0dXJlZCBvcHRpb25zIG9iamVjdFxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2FsbG93RnVuY3Rpb25zPWZhbHNlXSAtIFdoZXRoZXIgdG8gYWxsb3cgZnVuY3Rpb25zXHJcbiAqIGluIHRoZSBwYXJzZWQgY29uZmlnLiBJZiB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZC4gT3RoZXJ3aXNlLCB3aGVuXHJcbiAqIGEgZnVuY3Rpb24gaXMgZm91bmQsIG51bGwgaXMgcmV0dXJuZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFJldHVybnMgYSBwYXJzZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0LFxyXG4gKiBhIHN0cmluZ2lmaWVkIHNldCBvZiBvcHRpb25zIG9iamVjdCBpZiB0aGUgYHRvU3RyaW5nYCBpcyB0cnVlLCBhbmQgbnVsbFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gbnVsbCBpZiBhbnkgb3RoZXIgdHlwZVxyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIG9iamVjdCByZXByZXNlbnRhdGlvbiBvZiB0aGUgb3JpZ2luYWwgY29uZmlnXHJcbiAgICBjb25zdCBvYmplY3RDb25maWcgPVxyXG4gICAgICB0eXBlb2YgY29uZmlnID09PSAnc3RyaW5nJ1xyXG4gICAgICAgID8gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gZXZhbChgKCR7Y29uZmlnfSlgKVxyXG4gICAgICAgICAgOiBKU09OLnBhcnNlKGNvbmZpZylcclxuICAgICAgICA6IGNvbmZpZztcclxuXHJcbiAgICAvLyBQcmVzZXJ2ZSBvciByZW1vdmUgcG90ZW50aWFsIGZ1bmN0aW9ucyBiYXNlZCBvbiB0aGUgYGFsbG93RnVuY3Rpb25zYCBmbGFnXHJcbiAgICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBfb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgb2JqZWN0Q29uZmlnLFxyXG4gICAgICBhbGxvd0Z1bmN0aW9ucyxcclxuICAgICAgZmFsc2VcclxuICAgICk7XHJcblxyXG4gICAgLy8gUGFyc2UgdGhlIGNvbmZpZyB0byBjaGVjayBpZiBpdCBpcyB2YWxpZCBzZXQgb2Ygb3B0aW9uc1xyXG4gICAgY29uc3QgcGFyc2VkT3B0aW9ucyA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgID8gSlNPTi5wYXJzZShcclxuICAgICAgICAgIF9vcHRpb25zU3RyaW5naWZ5KG9iamVjdENvbmZpZywgYWxsb3dGdW5jdGlvbnMsIHRydWUpLFxyXG4gICAgICAgICAgKF8sIHZhbHVlKSA9PlxyXG4gICAgICAgICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICYmIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJylcclxuICAgICAgICAgICAgICA/IGV2YWwoYCgke3ZhbHVlfSlgKVxyXG4gICAgICAgICAgICAgIDogdmFsdWVcclxuICAgICAgICApXHJcbiAgICAgIDogSlNPTi5wYXJzZShzdHJpbmdpZmllZE9wdGlvbnMpO1xyXG5cclxuICAgIC8vIFJldHVybiBzdHJpbmdpZmllZCBvciBvYmplY3Qgb3B0aW9ucyBiYXNlZCBvbiB0aGUgYHRvU3RyaW5nYCBmbGFnXHJcbiAgICByZXR1cm4gdG9TdHJpbmcgPyBzdHJpbmdpZmllZE9wdGlvbnMgOiBwYXJzZWRPcHRpb25zO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBSZXR1cm4gbnVsbCBpZiBwYXJzaW5nIGZhaWxzXHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvLCB2ZXJzaW9uLCBhbmQgbGljZW5zZSBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50TGljZW5zZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50TGljZW5zZSgpIHtcclxuICAvLyBQcmludCB0aGUgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvblxyXG4gIHByaW50VmVyc2lvbigpO1xyXG5cclxuICAvLyBQcmludCB0aGUgbGljZW5zZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1RoaXMgc29mdHdhcmUgcmVxdWlyZXMgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgZm9yIGNvbW1lcmNpYWwgdXNlLlxcbidcclxuICAgICAgLnllbGxvdyxcclxuICAgICdcXG5Gb3IgYSBmdWxsIGxpc3Qgb2YgQ0xJIG9wdGlvbnMsIHR5cGU6JyxcclxuICAgICdcXG5oaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIgLS1oZWxwXFxuJy5ncmVlbixcclxuICAgICdcXG5JZiB5b3UgZG8gbm90IGhhdmUgYSBsaWNlbnNlLCBvbmUgY2FuIGJlIG9idGFpbmVkIGhlcmU6JyxcclxuICAgICdcXG5odHRwczovL3Nob3AuaGlnaHNvZnQuY29tL1xcbicuZ3JlZW4sXHJcbiAgICAnXFxuVG8gY3VzdG9taXplIHlvdXIgaW5zdGFsbGF0aW9uLCBwbGVhc2UgcmVmZXIgdG8gdGhlIFJFQURNRSBmaWxlIGF0OicsXHJcbiAgICAnXFxuaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZVxcbicuZ3JlZW5cclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLCBkaXNwbGF5aW5nIGF2YWlsYWJsZSBvcHRpb25zXHJcbiAqIGFuZCB0aGVpciBkZXNjcmlwdGlvbnMuIEl0IGNhbiBsaXN0IHByb3BlcnRpZXMgcmVjdXJzaXZlbHkgaWYgY2F0ZWdvcmllc1xyXG4gKiBjb250YWluIG5lc3RlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRVc2FnZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgLy8gRGlzcGxheSBSRUFETUUgYW5kIGdlbmVyYWwgdXNhZ2UgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSBSRUFETUUgZmlsZSBhdDogJHsnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZScuZ3JlZW59LlxcbmBcclxuICApO1xyXG5cclxuICAvLyBJdGVyYXRlIHRocm91Z2ggZWFjaCBjYXRlZ29yeSBpbiB0aGUgYGRlZmF1bHRDb25maWdgIGFuZCBkaXNwbGF5IHVzYWdlIGluZm9cclxuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xyXG4gICAgY29uc29sZS5sb2coYCR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLmJvbGQucmVkKTtcclxuICAgIF9jeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xyXG4gICAgY29uc29sZS5sb2coJycpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBvciB0ZXh0IHdpdGggdGhlIHZlcnNpb25cclxuICogaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBbbm9Mb2dvPWZhbHNlXSAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHRleHQgd2l0aCB0aGUgdmVyc2lvblxyXG4gKiBpbmZvcm1hdGlvbiwgd2l0aG91dCB0aGUgbG9nby4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRWZXJzaW9uKG5vTG9nbyA9IGZhbHNlKSB7XHJcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBgLmVudmAgb3IgZnJvbSBgcGFja2FnZS5qc29uYFxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn1gKTtcclxuICB9IGVsc2Uge1xyXG4gICAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICAgIGNvbnNvbGUubG9nKFxyXG4gICAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdtc2cnLCAnc3RhcnR1cC5tc2cnKSkudG9TdHJpbmcoKS5ib2xkXHJcbiAgICAgICAgLnllbGxvdyxcclxuICAgICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgcmV0dXJucyBnbG9iYWwgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9pbml0R2xvYmFsT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIGJlIHVzZWQgZm9yIGluaXRpYWxpemluZ1xyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIF9pbml0R2xvYmFsT3B0aW9ucyhjb25maWcpIHtcclxuICBjb25zdCBvcHRpb25zID0ge307XHJcblxyXG4gIC8vIFN0YXJ0IGluaXRpYWxpemluZyB0aGUgYG9wdGlvbnNgIG9iamVjdCByZWN1cnNpdmVseVxyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGNvbmZpZykpIHtcclxuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcclxuICAgICAgPyBpdGVtLnZhbHVlXHJcbiAgICAgIDogX2luaXRHbG9iYWxPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBjcmVhdGVkIGBvcHRpb25zYCBvYmplY3RcclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsIGZvbGxvd2luZyBhIHNwZWNpZmljXHJcbiAqIHByaW9yaXRpemF0aW9uIG9yZGVyLiBUaGUgZnVuY3Rpb24gY2hlY2tzIGZvciB2YWx1ZXMgaW4gdGhlIGZvbGxvd2luZyBvcmRlclxyXG4gKiBvZiBwcmVjZWRlbmNlOiB0aGUgYGxvYWRDb25maWdgIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgZW52aXJvbm1lbnQgdmFyaWFibGVzLFxyXG4gKiBjdXN0b20gb3B0aW9ucywgYW5kIENMSSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCwgd2hpY2ggaW5jbHVkZXMgdGhlIGluaXRpYWxcclxuICogc2V0dGluZ3MgYW5kIG1ldGFkYXRhIGZvciBlYWNoIG9wdGlvbi4gVGhpcyBvYmplY3QgaXMgdXNlZCB0byBkZXRlcm1pbmVcclxuICogdGhlIHN0cnVjdHVyZSBhbmQgZGVmYXVsdCB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0aGF0IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHZhbHVlc1xyXG4gKiBmcm9tIG90aGVyIHNvdXJjZXMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHQgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCwgbG9hZGVkIHdpdGhcclxuICogdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24sIHdoaWNoIG1heSBwcm92aWRlIHZhbHVlcyB0byBvdmVycmlkZSBkZWZhdWx0cy5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9wdCAtIFRoZSBjdXN0b20gb3B0aW9ucyBvYmplY3QsIHR5cGljYWxseSBjb250YWluaW5nXHJcbiAqIGFkZGl0aW9uYWwgYW5kIHVzZXItZGVmaW5lZCB2YWx1ZXMsIHdoaWNoIG1heSBvdmVycmlkZSBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlPcHQgLSBUaGUgQ0xJIG9wdGlvbnMgb2JqZWN0LCB3aGljaCBtYXkgaW5jbHVkZSB2YWx1ZXNcclxuICogcHJvdmlkZWQgdGhyb3VnaCBjb21tYW5kLWxpbmUgYXJndW1lbnRzIGFuZCBoYXMgdGhlIGhpZ2hlc3QgcHJlY2VkZW5jZSBhbW9uZ1xyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX3VwZGF0ZU9wdGlvbnMoY29uZmlnLCBvcHRpb25zLCBjb25maWdPcHQsIGN1c3RvbU9wdCwgY2xpT3B0KSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgY29uZmlnIGVudHJ5IG9mIGEgc3BlY2lmaWMgb3B0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIEdhdGhlciB2YWx1ZXMgZm9yIHRoZSBvcHRpb25zIGZyb20gZXZlcnkgcG9zc2libGUgc291cmNlLCBpZiBleGlzdHNcclxuICAgIGNvbnN0IGNvbmZpZ1ZhbCA9IGNvbmZpZ09wdCAmJiBjb25maWdPcHRba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbCA9IGN1c3RvbU9wdCAmJiBjdXN0b21PcHRba2V5XTtcclxuICAgIGNvbnN0IGNsaVZhbCA9IGNsaU9wdCAmJiBjbGlPcHRba2V5XTtcclxuXHJcbiAgICAvLyBJZiB0aGUgdmFsdWUgbm90IGZvdW5kLCBuZWVkIHRvIGdvIGRlZXBlclxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgX3VwZGF0ZU9wdGlvbnMoZW50cnksIG9wdGlvbnNba2V5XSwgY29uZmlnVmFsLCBjdXN0b21WYWwsIGNsaVZhbCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gY3VzdG9tIEpTT04gb3B0aW9ucyBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY29uZmlnVmFsICE9PSB1bmRlZmluZWQgJiYgY29uZmlnVmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gY29uZmlnVmFsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gZW52aXJvbm1lbnQgdmFyaWFibGVzIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGNvbnN0IGVudlZhbCA9IGVudnNbZW50cnkuZW52TGlua107XHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52VmFsICE9PSB1bmRlZmluZWQgJiYgZW52VmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gZW52VmFsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gdXNlciBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWwgIT09IHVuZGVmaW5lZCAmJiBjdXN0b21WYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjdXN0b21WYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBDTEkgb3B0aW9ucyBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoY2xpVmFsICE9PSB1bmRlZmluZWQgJiYgY2xpVmFsICE9PSBudWxsKSB7XHJcbiAgICAgICAgb3B0aW9uc1trZXldID0gY2xpVmFsO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmdcclxuICogd2l0aCB0aGUgb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy4gSW4gb3JkZXIgZm9yIGEgZnVuY3Rpb25cclxuICogdG8gYmUgcHJlc2VydmVkLCBpdCBuZWVkcyB0byBmb2xsb3cgdGhlIGZvcm1hdCBgZnVuY3Rpb24gKC4uLikgey4uLn1gLlxyXG4gKiBTdWNoIGEgZnVuY3Rpb24gY2FuIGFsc28gYmUgc3RyaW5naWZpZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBzYXZlZFxyXG4gKiBhcyBzdHJpbmdzLiBUaGUgYGFsbG93RnVuY3Rpb25zYCBtdXN0IGJlIHNldCB0byB0cnVlIGFzIHdlbGwgZm9yIHRoaXMgdG8gdGFrZVxyXG4gKiBhbiBlZmZlY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgd2hlbiBmdW5jdGlvbnMgYXJlIG5vdCBhbGxvd2VkIGJ1dCBhcmVcclxuICogZm91bmQgaW4gcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgdmFsdWUgaXMgYSBmdW5jdGlvbiBvciBzdHJpbmdpZmllZCBmdW5jdGlvblxyXG4gICAgaWYgKFxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicgfHxcclxuICAgICAgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbicpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXHJcbiAgICAgIGlmIChhbGxvd0Z1bmN0aW9ucykge1xyXG4gICAgICAgIC8vIEJhc2VkIG9uIHRoZSBgc3RyaW5naWZ5RnVuY3Rpb25zYCBvcHRpb25zLCBzZXQgZnVuY3Rpb24gdmFsdWVzXHJcbiAgICAgICAgcmV0dXJuIHN0cmluZ2lmeUZ1bmN0aW9uc1xyXG4gICAgICAgICAgPyAvLyBBcyBzdHJpbmdpZmllZCBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYFwiRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOXCJgXHJcbiAgICAgICAgICA6IC8vIEFzIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xccysvZywgJyAnKX1FWFBfRlVOYDtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBUaHJvdyBhbiBlcnJvciBvdGhlcndpc2VcclxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEluIGFsbCBvdGhlciBjYXNlcywgc2ltcGx5IHJldHVybiB0aGUgdmFsdWVcclxuICAgIHJldHVybiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIHN0cmluZ2lmeUZ1bmN0aW9ucyA/IC9cXFxcXCJFWFBfRlVOfEVYUF9GVU5cXFxcXCIvZyA6IC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHByb3ZpZGVkIHZpYVxyXG4gKiB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiBpbiB0aGUgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBzZWFyY2hcclxuICogZm9yIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIGFuZCB0aGUgY29ycmVzcG9uZGluZyBmaWxlIHBhdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZFxyXG4gKiBmaWxlLCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIGZpbGUgaXMgbm90IGZvdW5kLCBpbnZhbGlkLCBvciBhbiBlcnJvclxyXG4gKiBvY2N1cnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbG9hZENvbmZpZ0ZpbGUoY2xpQXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIHZhbHVlXHJcbiAgY29uc3QgY29uZmlnRmlsZU5hbWUgPSBjb25maWdJbmRleCA+IC0xICYmIGNsaUFyZ3NbY29uZmlnSW5kZXggKyAxXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBpcyBwcmVzZW50IGFuZCBoYXMgYSBjb3JyZWN0IHZhbHVlXHJcbiAgaWYgKGNvbmZpZ0ZpbGVOYW1lKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXHJcbiAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY29uZmlnRmlsZU5hbWUpKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogUGFyc2VzIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIHBhaXJzIGVhY2ggYXJndW1lbnQgd2l0aCBpdHMgY29ycmVzcG9uZGluZ1xyXG4gKiBvcHRpb24gaW4gdGhlIGNvbmZpZ3VyYXRpb24uIFRoZSB2YWx1ZXMgYXJlIHN0cnVjdHVyZWQgaW50byBhIG5lc3RlZCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gcHJlZGVmaW5lZCBtYXBwaW5ncy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBuZXN0ZWRQcm9wcyAtIEFuIGFycmF5IG9mIG5lc3RpbmcgbGV2ZWwgZm9yIGFsbFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZC1saW5lIGFyZ3VtZW50c1xyXG4gKiBjb250YWluaW5nIG9wdGlvbnMgYW5kIHRoZWlyIGFzc29jaWF0ZWQgdmFsdWVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0IHdoZXJlIGVhY2ggb3B0aW9uIGZyb21cclxuICogdGhlIGNvbW1hbmQtbGluZSBpcyBwYWlyZWQgd2l0aCBpdHMgdmFsdWUsIHN0cnVjdHVyZWQgaW50byBuZXN0ZWQgb2JqZWN0c1xyXG4gKiBhcyBkZWZpbmVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlKG5lc3RlZFByb3BzLCBjbGlBcmdzKSB7XHJcbiAgLy8gQW4gZW1wdHkgb2JqZWN0IHRvIGNvbGxlY3QgYW5kIHN0cnVjdHVyaXplIGRhdGEgZnJvbSB0aGUgYXJnc1xyXG4gIGNvbnN0IGNsaU9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBhbGwgQ0xJIGFyZ3MgYW5kIGZpbHRlciB0aGVtXHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBjbGlBcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBjbGlBcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRQcm9wc1tvcHRpb25dXHJcbiAgICAgID8gbmVzdGVkUHJvcHNbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIG9wdGlvbnMgb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gQ0xJIGZvciBsYXRlciBwYXJzaW5nIGFuZCBtZXJnaW5nXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBjb25zdCB2YWx1ZSA9IGNsaUFyZ3NbKytpXTtcclxuICAgICAgICBpZiAoIXZhbHVlKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgQ0xJICctLSR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIG9ialtwcm9wXSA9IHZhbHVlIHx8IG51bGw7XHJcbiAgICAgIH0gZWxzZSBpZiAob2JqW3Byb3BdID09PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBvYmpbcHJvcF0gPSB7fTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgY2xpT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcGFyc2VkIENMSSBvcHRpb25zXHJcbiAgcmV0dXJuIGNsaU9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB0cmF2ZXJzZXMgdGhlIG9wdGlvbnMgb2JqZWN0IHRvIHByaW50IHRoZSB1c2FnZSBpbmZvcm1hdGlvblxyXG4gKiBmb3IgZWFjaCBvcHRpb24gY2F0ZWdvcnkgYW5kIGluZGl2aWR1YWwgb3B0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIENMSSBvcHRpb25zLlxyXG4gKiBJdCBtYXkgaW5jbHVkZSBuZXN0ZWQgY2F0ZWdvcmllcyBhbmQgaW5kaXZpZHVhbCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N5Y2xlQ2F0ZWdvcmllcyhvcHRpb25zKSB7XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xyXG4gICAgLy8gSWYgdGhlIGN1cnJlbnQgZW50cnkgaXMgYSBjYXRlZ29yeSBhbmQgbm90IGEgbGVhZiBvcHRpb24sIHJlY3Vyc2UgaW50byBpdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xyXG4gICAgICBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBQcmVwYXJlIGRlc2NyaXB0aW9uXHJcbiAgICAgIGNvbnN0IGRlc2NOYW1lID0gYCAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX1gO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB2YWx1ZVxyXG4gICAgICBsZXQgb3B0aW9uVmFsdWUgPSBvcHRpb24udmFsdWU7XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYXJyYXkgb2Ygc3RyaW5nc1xyXG4gICAgICBpZiAob3B0aW9uVmFsdWUgIT09IG51bGwgJiYgb3B0aW9uLnR5cGVzLmluY2x1ZGVzKCdzdHJpbmdbXScpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPVxyXG4gICAgICAgICAgJ1snICsgb3B0aW9uVmFsdWUubWFwKChpdGVtKSA9PiBgJyR7aXRlbX0nYCkuam9pbignLCAnKSArICddJztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gUHJlcGFyZSB2YWx1ZSBmb3Igb3B0aW9uIHRoYXQgaXMgbm90IG51bGwgYW5kIGlzIGEgc3RyaW5nXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZycpKSB7XHJcbiAgICAgICAgb3B0aW9uVmFsdWUgPSBgJyR7b3B0aW9uVmFsdWV9J2A7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgZGVzY05hbWUuZ3JlZW4sXHJcbiAgICAgICAgYCR7KCc8JyArIG9wdGlvbi50eXBlcy5qb2luKCd8JykgKyAnPicpLnllbGxvd31gLFxyXG4gICAgICAgIGAke1N0cmluZyhvcHRpb25WYWx1ZSkuYm9sZH1gLmJsdWUsXHJcbiAgICAgICAgYC0gJHtvcHRpb24uZGVzY3JpcHRpb259LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWVyZ2VPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICBpc0FsbG93ZWRDb25maWcsXHJcbiAgcHJpbnRMaWNlbnNlLFxyXG4gIHByaW50VXNhZ2UsXHJcbiAgcHJpbnRWZXJzaW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGZldGNoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IFtyZXF1ZXN0T3B0aW9ucz17fV0gLSBPcHRpb25zIGZvciB0aGUgSFRUUC9IVFRQUyByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBIVFRQL0hUVFBTIHJlc3BvbnNlXHJcbiAqIG9iamVjdCB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIXJlc3BvbnNlRGF0YSkge1xyXG4gICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxyXG4gICAgICB7XHJcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXHJcbiAgICAgICAgaGVhZGVyczoge1xyXG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcclxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICByZXF1ZXN0T3B0aW9uc1xyXG4gICAgKTtcclxuXHJcbiAgICBjb25zdCByZXF1ZXN0ID0gX2dldFByb3RvY29sTW9kdWxlKHVybClcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzcG9uc2UpID0+IHtcclxuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XHJcblxyXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZFxyXG4gICAgICAgIHJlc3BvbnNlLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlc3BvbnNlKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3RcclxuICAgIHJlcXVlc3Qud3JpdGUoZGF0YSk7XHJcbiAgICByZXF1ZXN0LmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9nZXRQcm90b2NvbE1vZHVsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxyXG4gKi9cclxuZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlKHVybCkge1xyXG4gIHJldHVybiB1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cDtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGZldGNoLFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQSBjdXN0b20gZXJyb3IgY2xhc3MgZm9yIGhhbmRsaW5nIGV4cG9ydC1yZWxhdGVkIGVycm9ycy4gRXh0ZW5kcyB0aGUgbmF0aXZlXHJcbiAqIGBFcnJvcmAgY2xhc3MgdG8gaW5jbHVkZSBhZGRpdGlvbmFsIHByb3BlcnRpZXMgbGlrZSBzdGF0dXMgY29kZSBhbmQgc3RhY2tcclxuICogdHJhY2UgZGV0YWlscy5cclxuICovXHJcbmNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIoKTtcclxuXHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG5cclxuICAgIGlmIChzdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIGFkZGl0aW9uYWwgZXJyb3IgZGV0YWlscyBiYXNlZCBvbiBhbiBleGlzdGluZyBlcnJvciBvYmplY3QuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIEFuIGVycm9yIG9iamVjdCBjb250YWluaW5nIGRldGFpbHMgdG8gcG9wdWxhdGVcclxuICAgKiB0aGUgYEV4cG9ydEVycm9yYCBpbnN0YW5jZS5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtFeHBvcnRFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBFeHBvcnRFcnJvcmAgY2xhc3MuXHJcbiAgICovXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgRXhwb3J0RXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgY2FjaGUgbWFuYWdlciBpcyByZXNwb25zaWJsZSBmb3IgaGFuZGxpbmcgYW5kIG1hbmFnaW5nXHJcbiAqIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYWxvbmcgd2l0aCBpdHMgZGVwZW5kZW5jaWVzLiBJdCBlbnN1cmVzIHRoYXQgdGhlc2VcclxuICogcmVzb3VyY2VzIGFyZSBzdG9yZWQgYW5kIHJldHJpZXZlZCBlZmZpY2llbnRseSB0byBvcHRpbWl6ZSBwZXJmb3JtYW5jZVxyXG4gKiBhbmQgcmVkdWNlIHJlZHVuZGFudCBuZXR3b3JrIHJlcXVlc3RzLiBUaGUgY2FjaGUgaXMgc3RvcmVkIGluIHRoZSBgLmNhY2hlYFxyXG4gKiBkaXJlY3RvcnkgYnkgZGVmYXVsdCwgd2hpY2ggc2VydmVzIGFzIGEgZGVkaWNhdGVkIGZvbGRlciBmb3Iga2VlcGluZyBjYWNoZWRcclxuICogZmlsZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgaW5pdGlhbCBjYWNoZSB0ZW1wbGF0ZVxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5Vcmw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcclxuICBzb3VyY2VzOiAnJyxcclxuICBoY1ZlcnNpb246ICcnXHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQW5kVXBkYXRlQ2FjaGUoXHJcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zXHJcbikge1xyXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcclxuXHJcbiAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgY29uc3QgY2FjaGVQYXRoID0gZ2V0Q2FjaGVQYXRoKCk7XHJcblxyXG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgdGhlIGBtYW5pZmVzdC5qc29uYCBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBgZm9yY2VGZXRjaGAgb3B0aW9uIGlzIGVuYWJsZWRcclxuICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgc291cmNlUGF0aFxyXG4gICAgKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBSZWFkIHRoZSBtYW5pZmVzdCBKU09OXHJcbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZSBtb2R1bGVzIGlzIGFuIGFycmF5LCBpZiBzbywgd2UgcmV3cml0ZSBpdCB0byBhIG1hcCB0byBtYWtlXHJcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxyXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xyXG4gICAgICBjb25zdCBtb2R1bGVNYXAgPSB7fTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHNPcHRpb25zO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICApO1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xyXG4gICAgICByZXF1ZXN0VXBkYXRlID0gKG1vZHVsZVNjcmlwdHMgfHwgW10pLnNvbWUoKG1vZHVsZU5hbWUpID0+IHtcclxuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBhd2FpdCBfdXBkYXRlQ2FjaGUoXHJcbiAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICAgIHNvdXJjZVBhdGhcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XHJcblxyXG4gICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcclxuXHJcbiAgICAgIC8vIEdldCBjdXJyZW50IG1vZHVsZXMgbWFwXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgIC8vIEV4dHJhY3QgYW5kIHNhdmUgdmVyc2lvbiBvZiBjdXJyZW50bHkgdXNlZCBIaWdoY2hhcnRzXHJcbiAgICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXHJcbiAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgYXdhaXQgX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSB2ZXJzaW9uIG9mIEhpZ2hjaGFydHMgZnJvbSB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpIHtcclxuICByZXR1cm4gY2FjaGUuaGNWZXJzaW9uO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xyXG4gKiB0aGUgY2FjaGUgZm9yIHRoZSBuZXcgdmVyc2lvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24obmV3VmVyc2lvbikge1xyXG4gIC8vIEdldCB0aGUgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyB0byB1cGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRvIHRoZSBuZXcgdmVyc2lvblxyXG4gIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgY2FjaGUncyBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjYWNoZVNvdXJjZXMgLSBUaGUgY2FjaGUgc291cmNlcyBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgc2NyaXB0UGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpOyAvLyAjNTYyXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgYGZldGNoZWRNb2R1bGVzYCBhY2NvcmRpbmdseS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtzaG91bGRUaHJvd0Vycm9yPWZhbHNlXSAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3JcclxuICogc2hvdWxkIGJlIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLiBUaGUgZGVmYXVsdFxyXG4gKiB2YWx1ZSBpcyBmYWxzZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcclxuXHJcbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxyXG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICAvLyBCYXNlZCBvbiB0aGUgYHNob3VsZFRocm93RXJyb3JgIGZsYWcsIGRlY2lkZSBob3cgdG8gc2VydmUgZXJyb3IgbWVzc2FnZVxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gLFxyXG4gICAgICA0MDRcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0KGhpZ2hjaGFydHNPcHRpb25zLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uLFxyXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXNcclxuICB9O1xyXG5cclxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xyXG4gIGNhY2hlLmFjdGl2ZU1hbmlmZXN0ID0gbmV3TWFuaWZlc3Q7XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBgc2NyaXB0c2AgYW5kIGBjdXN0b21TY3JpcHRzYCBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaFNjcmlwdHNcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY29yZVNjcmlwdHMgLSBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gbW9kdWxlU2NyaXB0cyAtIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gY3VzdG9tU2NyaXB0cyAtIEN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2ggKGZ1bGxcclxuICogVVJMcykuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGZldGNoZWQgc2NyaXB0c1xyXG4gKiBjb250ZW50IGpvaW5lZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiBzZXR0aW5nIGFuIEhUVFAgQWdlbnQgZm9yIHByb3h5LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoU2NyaXB0cyhcclxuICBjb3JlU2NyaXB0cyxcclxuICBtb2R1bGVTY3JpcHRzLFxyXG4gIGN1c3RvbVNjcmlwdHMsXHJcbiAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzXHJcbikge1xyXG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcclxuICBsZXQgcHJveHlBZ2VudDtcclxuICBjb25zdCBwcm94eUhvc3QgPSBzZXJ2ZXJQcm94eU9wdGlvbnMuaG9zdDtcclxuICBjb25zdCBwcm94eVBvcnQgPSBzZXJ2ZXJQcm94eU9wdGlvbnMucG9ydDtcclxuXHJcbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XHJcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogc2VydmVyUHJveHlPcHRpb25zLnRpbWVvdXRcclxuICAgICAgfVxyXG4gICAgOiB7fTtcclxuXHJcbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcclxuICAgIC4uLmNvcmVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMsIHRydWUpXHJcbiAgICApLFxyXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxyXG4gICAgKVxyXG4gIF07XHJcblxyXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XHJcbiAgcmV0dXJuIGZldGNoZWRTY3JpcHRzLmpvaW4oJztcXG4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlQ2FjaGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGhpZ2hjaGFydHNPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGhpZ2hjaGFydHNgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJQcm94eU9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgc2VydmVyLnByb3h5YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc291cmNlUGF0aCAtIFRoZSBwYXRoIHRvIHRoZSBzb3VyY2UgZmlsZSBpbiB0aGUgY2FjaGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXHJcbiAqIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3VwZGF0ZUNhY2hlKGhpZ2hjaGFydHNPcHRpb25zLCBzZXJ2ZXJQcm94eU9wdGlvbnMsIHNvdXJjZVBhdGgpIHtcclxuICAvLyBHZXQgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgaGNWZXJzaW9uID1cclxuICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgID8gbnVsbFxyXG4gICAgICA6IGAke2hpZ2hjaGFydHNPcHRpb25zLnZlcnNpb259YDtcclxuXHJcbiAgLy8gR2V0IHRoZSBDRE4gdXJsIGZvciBzY3JpcHRzXHJcbiAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBfZmV0Y2hTY3JpcHRzKFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjfWAgOiBgJHtjZG5Vcmx9LyR7Y31gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBbXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XHJcbiAgICAgICAgICBtID09PSAnbWFwJ1xyXG4gICAgICAgICAgICA/IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vbW9kdWxlcy8ke219YFxyXG4gICAgICAgICAgICAgIDogYCR7Y2RuVXJsfS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgKSxcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaSkgPT5cclxuICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICA/IGAke2NkblVybH0vc3RvY2svJHtoY1ZlcnNpb259L2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L3N0b2NrL2luZGljYXRvcnMvJHtpfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXHJcbiAgICAgIHNlcnZlclByb3h5T3B0aW9ucyxcclxuICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXHJcbiAgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sXHJcbiAgZXh0cmFjdFZlcnNpb24sXHJcbiAgZXh0cmFjdE1vZHVsZU5hbWUsXHJcbiAgZ2V0Q2FjaGUsXHJcbiAgZ2V0Q2FjaGVQYXRoXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtZXRob2RzIGZvciBpbml0aWFsaXppbmcgSGlnaGNoYXJ0cyB3aXRoIGN1c3RvbWl6ZWRcclxuICogYW5pbWF0aW9uIHNldHRpbmdzIGFuZCB0cmlnZ2VyaW5nIHRoZSBjcmVhdGlvbiBvZiBIaWdoY2hhcnRzIGNoYXJ0cyB3aXRoXHJcbiAqIGV4cG9ydC1zcGVjaWZpYyBjb25maWd1cmF0aW9ucyBpbiB0aGUgcGFnZSBjb250ZXh0LiBTdXBwb3J0cyBkeW5hbWljIG9wdGlvblxyXG4gKiBtZXJnaW5nLCBjdXN0b20gbG9naWMgaW5qZWN0aW9uLCBhbmQgY29udHJvbCBvdmVyIHJlbmRlcmluZyBiZWhhdmlvcnMuIFVzZWRcclxuICogYnkgdGhlIFB1cHBldGVlciBwYWdlLlxyXG4gKi9cclxuXHJcbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXHJcblxyXG4vKipcclxuICogU2V0dGluZyB0aGUgYEhpZ2hjaGFydHMuYW5pbU9iamVjdGAgZnVuY3Rpb24uIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XHJcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xyXG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcclxuICB9O1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIEhpZ2hjaGFydHMgY2hhcnQgb24gYSBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGVDaGFydChvcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxyXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcclxuICAgICAgICAqL1xyXG4gICAgICB0b29sdGlwOiB7fVxyXG4gICAgfSk7XHJcblxyXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XHJcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cclxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xyXG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xyXG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XHJcbiAgfSk7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcclxuICB9KTtcclxuXHJcbiAgLy8gU29tZSBtYW5kYXRvcnkgYWRkaXRpb25hbCBgY2hhcnRgIGFuZCBgZXhwb3J0aW5nYCBvcHRpb25zXHJcbiAgY29uc3QgYWRkaXRpb25hbE9wdGlvbnMgPSB7XHJcbiAgICBjaGFydDoge1xyXG4gICAgICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxyXG4gICAgICBhbmltYXRpb246IGZhbHNlLFxyXG4gICAgICAvLyBHZXQgdGhlIHJpZ2h0IHNpemUgdmFsdWVzXHJcbiAgICAgIGhlaWdodDogb3B0aW9ucy5leHBvcnQuaGVpZ2h0LFxyXG4gICAgICB3aWR0aDogb3B0aW9ucy5leHBvcnQud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5pbnN0cn1gKSgpO1xyXG5cclxuICAvLyBHZXQgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IHRoZW1lT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oXHJcbiAgICBgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9uc31gXHJcbiAgKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxyXG4gICAgOiBudWxsO1xyXG5cclxuICAvLyBUcmlnZ2VyIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgb3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSh1c2VyT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbb3B0aW9ucy5leHBvcnQuY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSByZXNvdXJjZXMsXHJcbiAqIGFuZCBzZXR0aW5nIHVwIEhpZ2hjaGFydHMgZm9yIHNlcnZlci1zaWRlIHJlbmRlcmluZy4gVGhlIG1vZHVsZSBlbnN1cmVzXHJcbiAqIHRoYXQgcmVzb3VyY2VzIGFyZSBjb3JyZWN0bHkgbWFuYWdlZCBhbmQgY2FuIGhhbmRsZSBmYWlsdXJlcyBkdXJpbmdcclxuICogb3BlcmF0aW9ucyBsaWtlIGxhdW5jaGluZyB0aGUgYnJvd3NlciBvciBjcmVhdGluZyBuZXcgcGFnZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgcGFnZXNcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHB1cHBldGVlckFyZ3MgLSBBZGRpdGlvbmFsIGFyZ3VtZW50cyBmb3IgUHVwcGV0ZWVyXHJcbiAqIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIExhdW5jaCB0aGUgYnJvd3NlclxyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuXHJcbiAgICAgICAgICAvLyBXYWl0IGZvciBhIDQgc2Vjb25kcyBiZWZvcmUgdHJ5aW5nIGFnYWluXHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuXHJcbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJywgNTAwKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgaW5zdGFuY2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsb3NlQnJvd3NlclxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlQnJvd3NlcigpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5lY3RlZFxyXG4gIGlmIChicm93c2VyICYmIGJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGJyb3dzZXIgPSBudWxsO1xyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIHBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiB0aGUgYF9zZXRQYWdlQ29udGVudCgpYCwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gbmV3UGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBgaWRgLFxyXG4gKiBgd29ya0NvdW50YCwgYW5kIGBwYWdlYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG5vIHZhbGlkIGJyb3dzZXJcclxuICogaGFzIGJlZW4gY29ubmVjdGVkIG9yIGlmIGEgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKHBvb2xSZXNvdXJjZSkge1xyXG4gIC8vIEVycm9yIGluIGNhc2Ugb2Ygbm8gY29ubmVjdGVkIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIgfHwgIWJyb3dzZXIuY29ubmVjdGVkKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFticm93c2VyXSBCcm93c2VyIGlzIG5vdCB5ZXQgY29ubmVjdGVkLmAsIDUwMCk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBwYWdlXHJcbiAgcG9vbFJlc291cmNlLnBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIF9zZXRQYWdlRXZlbnRzKHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIHBhZ2UgaXMgY29ycmVjdGx5IGNyZWF0ZWRcclxuICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlIHx8IHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIFRoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLiBMb2dzXHJcbiAqIHRocm93biBlcnJvciBpZiBjbGVhcmluZyBvZiBhIHBhZ2UncyBjb250ZW50IGZhaWxzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250YWlucyBwYWdlIGFuZCBpZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbaGFyZFJlc2V0PWZhbHNlXSAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXHJcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxyXG4gKiBzdHJ1Y3R1cmUuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGZhbHNlIHdoZW4gaXQgaXMgbm90LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwb29sUmVzb3VyY2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XHJcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYGFib3V0OmJsYW5rYFxyXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmdvdG8oJ2Fib3V0OmJsYW5rJywge1xyXG4gICAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxyXG4gICAgICAgIGF3YWl0IF9zZXRQYWdlQ29udGVudChwb29sUmVzb3VyY2UucGFnZSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2xlYXIgYm9keSBjb250ZW50XHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxyXG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb250ZW50IG9mIHRoZSBwYWdlIGNvdWxkIG5vdCBiZSBjbGVhcmVkLmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBnZXRPcHRpb25zKCkucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gIH1cclxuICByZXR1cm4gZmFsc2U7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBhZGRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgY3VzdG9tTG9naWNgXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5LjxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHJlc291cmNlc1xyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChmaWxlKSwgJ3V0ZjgnKVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgOiB7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGZpbGVcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgcGF0aDogam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICAgYFticm93c2VyXSBUaGUgQ1NTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcclxuICAgIH1cclxuICB9XHJcbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYGFkZFNjcmlwdFRhZ2AgYW5kIGBhZGRTdHlsZVRhZ2AuXHJcbiAqIFJlbW92ZXMgaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS5cclxuICogQWRkaXRpb25hbGx5LCBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheS48T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBqb2luKGdldENhY2hlUGF0aCgpLCAnc291cmNlcy5qcycpIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGluaXRpYWwgYGFuaW1PYmplY3RgIGZvciBIaWdoY2hhcnRzXHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyAobGlrZSBgcGFnZWVycm9yYCBhbmQgYGNvbnNvbGVgKSBmb3IgYSBQdXBwZXRlZXIgUGFnZSBpbiBvcmRlclxyXG4gKiB0byBjYXRjaCBhbmQgZGlzcGxheSBlcnJvcnMgYW5kIGNvbnNvbGUgbG9ncyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgbGlzdGVuZXJzXHJcbiAqIGFyZSBiZWluZyBzZXQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc2V0UGFnZUV2ZW50cyhwYWdlKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgcGFnZWVycm9yYCBsaXN0ZW5lclxyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jICgpID0+IHtcclxuICAgIC8vIEl0IHdvdWxkIHNlZW0gbGlrZSB0aGlzIG1heSBmaXJlIGF0IHRoZSBzYW1lIHRpbWUgb3Igc2hvcnRseSBiZWZvcmVcclxuICAgIC8vIGEgcGFnZSBpcyBjbG9zZWQuXHJcbiAgICBpZiAocGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgY29uc29sZWAgbGlzdGVuZXIsIGlmIG5lZWRlZFxyXG4gIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XHJcbiAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcclxuICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcclxuICAgIH0pO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldEJyb3dzZXIsXHJcbiAgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgYWRkUGFnZVJlc291cmNlcyxcclxuICBjbGVhclBhZ2VSZXNvdXJjZXNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogVGhlIENTUyB0byBiZSB1c2VkIG9uIHRoZSBleHBvcnRlZCBwYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQ1NTIGNvbmZpZ3VyYXRpb24uXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoKSA9PiBgXHJcblxyXG5odG1sLCBib2R5IHtcclxuICBtYXJnaW46IDA7XHJcbiAgcGFkZGluZzogMDtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG59XHJcblxyXG4jdGFibGUtZGl2LCAjc2xpZGVycywgI2RhdGF0YWJsZSwgI2NvbnRyb2xzLCAubGQtcm93IHtcclxuICBkaXNwbGF5OiBub25lO1xyXG4gIGhlaWdodDogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciB7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxuICBtYXJnaW46IDA7XHJcbiAgb3ZlcmZsb3c6IGF1dG87XHJcbiAgZm9udC1zaXplOiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyID4gZmlndXJlLCBkaXYge1xyXG4gIG1hcmdpbi10b3A6IDAgIWltcG9ydGFudDtcclxuICBtYXJnaW4tYm90dG9tOiAwICFpbXBvcnRhbnQ7XHJcbn1cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBUaGUgU1ZHIHRlbXBsYXRlIHRvIHVzZSB3aGVuIGxvYWRpbmcgU1ZHIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIGlucHV0IGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBTVkcgdGVtcGxhdGUuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoc3ZnKSA9PiBgXHJcbjwhRE9DVFlQRSBodG1sPlxyXG48aHRtbCBsYW5nPSdlbi1VUyc+XHJcbiAgPGhlYWQ+XHJcbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxyXG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cclxuICA8L2hlYWQ+XHJcbiAgPHN0eWxlPlxyXG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxyXG4gIDwvc3R5bGU+XHJcbiAgPGJvZHk+XHJcbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XHJcbiAgICAgICR7c3ZnfVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgaGFuZGxlcyBjaGFydCBleHBvcnQgZnVuY3Rpb25hbGl0eSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqIEl0IHN1cHBvcnRzIGV4cG9ydGluZyBjaGFydHMgYXMgU1ZHLCBQTkcsIEpQRUcsIGFuZCBQREYgZm9ybWF0cy4gVGhlIG1vZHVsZVxyXG4gKiBtYW5hZ2VzIHBhZ2UgcmVzb3VyY2VzLCBzZXRzIHVwIHRoZSBleHBvcnQgZW52aXJvbm1lbnQsIGFuZCBwcm9jZXNzZXMgY2hhcnRcclxuICogY29uZmlndXJhdGlvbnMgb3IgU1ZHIGlucHV0cyBmb3IgcmVuZGVyaW5nLiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2VcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGNyZWF0ZUNoYXJ0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KHN0cmluZ3xCdWZmZXJ8RXhwb3J0RXJyb3IpPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXNcclxuICogdG8gdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gYEV4cG9ydEVycm9yYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGV4cG9ydCB0byBhbiB1bnN1cHBvcnRlZFxyXG4gKiBvdXRwdXQgZm9ybWF0IG9jY3Vycy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwdXBwZXRlZXJFeHBvcnQocGFnZSwgb3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGBleHBvcnRgIG9wdGlvbnNcclxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICBsZXQgaXNTVkcgPSBmYWxzZTtcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBgdHlwZWAgaXMgYWxzbyBTVkcsIHJldHVybiB0aGUgaW5wdXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gZXhwb3J0T3B0aW9ucy5zdmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1hcmsgYXMgU1ZHIGV4cG9ydCBmb3IgdGhlIGxhdGVyIHNpemUgY29ycmVjdGlvbnNcclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydFxyXG4gICAgICBhd2FpdCBfc2V0QXNTdmcocGFnZSwgZXhwb3J0T3B0aW9ucy5zdmcpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBKU09OIGNvbmZpZy4nKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0XHJcbiAgICAgIGF3YWl0IF9zZXRBc09wdGlvbnMocGFnZSwgb3B0aW9ucyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXHJcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xyXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXHJcbiAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKFxyXG4gICAgICAuLi4oYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zLmN1c3RvbUxvZ2ljKSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxyXG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXHJcbiAgICAgID8gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoc2NhbGUpID0+IHtcclxuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxyXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICAgICk7XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxyXG4gICAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHkgYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXNcclxuICAgICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXHJcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IF9nZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgaGVpZ2h0YCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYHdpZHRoYCBmb3Igdmlld3BvcnRcclxuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgcmVzdWx0O1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBzd2l0Y2ggKGV4cG9ydE9wdGlvbnMudHlwZSkge1xyXG4gICAgICBjYXNlICdzdmcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVTVkcocGFnZSk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BuZyc6XHJcbiAgICAgIGNhc2UgJ2pwZWcnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVJbWFnZShcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgICB4LFxyXG4gICAgICAgICAgICB5XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGNhc2UgJ3BkZic6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVBERihcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgZGVmYXVsdDpcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdDogJHtleHBvcnRPcHRpb25zLnR5cGV9LmAsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gcmVzdWx0O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBwYWdlJ3MgY29udGVudCB3aXRoIHByb3ZpZGVkIGV4cG9ydCBpbnB1dCB3aXRoaW5cclxuICogdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHRoZSBgcGFnZS5zZXRDb250ZW50YCBmdW5jdGlvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0QXNTdmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIGlucHV0IGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgY29udGVudCBpcyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0QXNTdmcocGFnZSwgc3ZnKSB7XHJcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKHN2ZyksIHtcclxuICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBvcHRpb25zIHdpdGggc3BlY2lmaWVkIGV4cG9ydCBpbnB1dCBhbmQgc2l6ZXMgYXMgY29uZmlndXJhdGlvbiBpbnRvXHJcbiAqIHRoZSBgY3JlYXRlQ2hhcnRgIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmdcclxuICogdGhlIGBwYWdlLmV2YWx1YXRlYCBmdW5jdGlvbi5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0QXNPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgY29uZmlndXJhdGlvblxyXG4gKiBpcyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0QXNPcHRpb25zKHBhZ2UsIG9wdGlvbnMpIHtcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKGNyZWF0ZUNoYXJ0LCBvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50XHJcbiAqIHdpdGggdGhlICdjaGFydC1jb250YWluZXInIGlkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgeGAsIGB5YCwgYHdpZHRoYCwgYW5kIGBoZWlnaHRgIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvbihwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY3JlYXRlQnJvd3NlciwgY2xvc2VCcm93c2VyLCBuZXdQYWdlLCBjbGVhclBhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3Bvb2xPcHRpb25zPWdldE9wdGlvbnMoKS5wb29sXSAtIE9iamVjdCBjb250YWluaW5nIGBwb29sYFxyXG4gKiBvcHRpb25zLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgZ2xvYmFsIHBvb2wgb3B0aW9ucyBvZiB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gW3B1cHBldGVlckFyZ3M9W11dIC0gQWRkaXRpb25hbCBhcmd1bWVudHNcclxuICogZm9yIFB1cHBldGVlciBsYXVuY2guIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gZW5kaW5nIHRoZSBmdW5jdGlvblxyXG4gKiBleGVjdXRpb24gd2hlbiBhbiBhbHJlYWR5IGluaXRpYWxpemVkIHBvb2wgb2YgcmVzb3VyY2VzIGlzIGZvdW5kLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbFxyXG4gKiBvZiB3b3JrZXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRQb29sKFxyXG4gIHBvb2xPcHRpb25zID0gZ2V0T3B0aW9ucygpLnBvb2wsXHJcbiAgcHVwcGV0ZWVyQXJncyA9IFtdXHJcbikge1xyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xyXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sT3B0aW9ucy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbE9wdGlvbnMubWF4V29ya2Vyc30uYFxyXG4gICAgKTtcclxuXHJcbiAgICBpZiAocG9vbCkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xyXG4gICAgICApO1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gS2VlcCBhbiBleWUgb24gYSBjb3JyZWN0IG1pbiBhbmQgbWF4IHdvcmtlcnMgbnVtYmVyXHJcbiAgICBpZiAocG9vbE9wdGlvbnMubWluV29ya2VycyA+IHBvb2xPcHRpb25zLm1heFdvcmtlcnMpIHtcclxuICAgICAgcG9vbE9wdGlvbnMubWluV29ya2VycyA9IHBvb2xPcHRpb25zLm1heFdvcmtlcnM7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGBjcmVhdGVgLCBgdmFsaWRhdGVgLCBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5fZmFjdG9yeShwb29sT3B0aW9ucyksXHJcbiAgICAgIG1pbjogcG9vbE9wdGlvbnMubWluV29ya2VycyxcclxuICAgICAgbWF4OiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzLFxyXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5kZXN0cm95VGltZW91dCxcclxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xPcHRpb25zLnJlYXBlckludGVydmFsLFxyXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBldmVudHNcclxuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gQ2xlYXIgcGFnZVxyXG4gICAgICBjb25zdCBjbGVhclN0YXR1cyA9IGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZSwgZmFsc2UpO1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cmVzb3VyY2UuaWR9XSAtIFJlbGVhc2luZyBhIHdvcmtlci4gQ2xlYXIgcGFnZSBzdGF0dXM6ICR7Y2xlYXJTdGF0dXN9LmBcclxuICAgICAgKTtcclxuICAgIH0pO1xyXG5cclxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKF9ldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cmVzb3VyY2UuaWR9XSAtIERlc3Ryb3llZCBhIHdvcmtlciBzdWNjZXNzZnVsbHkuYFxyXG4gICAgICApO1xyXG4gICAgICByZXNvdXJjZS5wYWdlID0gbnVsbDtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbE9wdGlvbnMubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gICAgcG9vbCA9IG51bGw7XHJcbiAgfVxyXG5cclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGF3YWl0IGNsb3NlQnJvd3NlcigpO1xyXG59XHJcblxyXG4vKipcclxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xyXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHBvc3RXb3JrXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGV4cG9ydCByZXN1bHRcclxuICogYW5kIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwb3N0V29yayhvcHRpb25zKSB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gQW4gZXhwb3J0IGF0dGVtcHQgY291bnRlZFxyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0F0dGVtcHRlZDtcclxuXHJcbiAgICAvLyBEaXNwbGF5IHRoZSBwb29sIGluZm9ybWF0aW9uIGlmIG5lZWRlZFxyXG4gICAgaWYgKGdldE9wdGlvbnMoKS5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2YgbGFja2luZyB0aGUgcG9vbCBpbnN0YW5jZVxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjcXVpcmUgY291bnRlclxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFRyeSB0byBhY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQsIHdvcmtzIGNvdW50IGFuZCBwYWdlXHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgICAgLy8gQWNxdWlyZSBhIHBvb2wgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMuX3JlcXVlc3RJZFxyXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXSAnLFxyXG4gICAgICAgICAgYEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUgdG9vayAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdICcgK1xyXG4gICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xyXG4gICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3Bvb2xdIFJlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgY29uc3Qgd29ya1N0YXJ0ID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHt3b3JrZXJIYW5kbGUuaWR9XSAtIFN0YXJ0aW5nIHdvcmsgb24gdGhpcyBwb29sIGVudHJ5LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxyXG4gICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxyXG4gICAgICAvLyB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXHJcbiAgICAgIC8vIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcclxuICAgICAgLy8gYW5kIHBhZ2UgY29uc2lzdGVuY3kuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIE5PVEU6XHJcbiAgICAgIC8vIE9ubHkgcGFnZS5zY3JlZW5zaG90IHdpbGwgdGhyb3cgdGhpcywgdGltZW91dHMgZm9yIFBERidzIGFyZVxyXG4gICAgICAvLyBoYW5kbGVkIGJ5IHRoZSBwYWdlLnBkZiBmdW5jdGlvbiBpdHNlbGYuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIC4uLnllcywgdGhpcyBpcyB1Z2x5LlxyXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XHJcbiAgICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gb3B0aW9ucy5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBudWxsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmVzdWx0Lm5hbWUgPT09ICdUaW1lb3V0RXJyb3InIHx8XHJcbiAgICAgICAgcmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnXHJcbiAgICAgICkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbcG9vbF0gJyArXHJcbiAgICAgICAgICAgIChvcHRpb25zLl9yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLl9yZXF1ZXN0SWR9XSAtIGAgOiAnJykgK1xyXG4gICAgICAgICAgICAnUmFzdGVyaXphdGlvbiB0aW1lb3V0OiB5b3VyIGNoYXJ0IG1heSBiZSB0b28gY29tcGxleCBvciBsYXJnZSwgYW5kIGZhaWxlZCB0byByZW5kZXIgd2l0aGluIHRoZSBhbGxvdHRlZCB0aW1lLidcclxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1twb29sXSAnICtcclxuICAgICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxyXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNSxcclxuICAgICAgICBvcHRpb25zLl9yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgXHJcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXSAnLFxyXG4gICAgICAgIGBFeHBvcnRpbmcgYSBjaGFydCBzdWNlc3NmdWxseSB0b29rICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcclxuXHJcbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXHJcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXHJcbiAgICBjb25zdCB3b3JrRW5kID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG5cclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfW1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzRHJvcHBlZDtcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sKCkge1xyXG4gIHJldHVybiBwb29sO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgc3RhdGlzdGljIG9mIGEgcG9vbCBpbnN0YWNlIGFib3V0IGV4cG9ydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sU3RhdHNcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGN1cnJlbnQgcG9vbCBzdGF0aXN0aWNzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xTdGF0cygpIHtcclxuICByZXR1cm4gcG9vbFN0YXRzO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvSlNPTigpIHtcclxuICByZXR1cm4ge1xyXG4gICAgbWluOiBwb29sLm1pbixcclxuICAgIG1heDogcG9vbC5tYXgsXHJcbiAgICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICAgIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXHJcbiAgICBhbGxDcmVhdGVkOiBwb29sLm51bVVzZWQoKSArIHBvb2wubnVtRnJlZSgpLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXM6IHBvb2wubnVtUGVuZGluZ0NyZWF0ZXMoKSxcclxuICAgIHBlbmRpbmdWYWxpZGF0aW9uczogcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSxcclxuICAgIHBlbmRpbmdEZXN0cm95czogcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoLFxyXG4gICAgYWJzb2x1dGVBbGw6XHJcbiAgICAgIHBvb2wubnVtVXNlZCgpICtcclxuICAgICAgcG9vbC5udW1GcmVlKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpICtcclxuICAgICAgcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSArXHJcbiAgICAgIHBvb2wucGVuZGluZ0Rlc3Ryb3lzLmxlbmd0aFxyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cclxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXHJcbiAqIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCxcclxuICogYW5kIGBkZXN0cm95YCBmdW5jdGlvbnMgZm9yIHRoZSBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2ZhY3RvcnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYHBvb2xgIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmFjdG9yeShwb29sT3B0aW9ucykge1xyXG4gIHJldHVybiB7XHJcbiAgICAvKipcclxuICAgICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBjcmVhdGVcclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3RcclxuICAgICAqIGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWxcclxuICAgICAqIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGFuIGVycm9yIGR1cmluZ1xyXG4gICAgICogdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXcgcGFnZS5cclxuICAgICAqL1xyXG4gICAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICAgIC8vIEluaXQgdGhlIHJlc291cmNlIHdpdGggdW5pcXVlIGlkIGFuZCB3b3JrIGNvdW50XHJcbiAgICAgIGNvbnN0IHBvb2xSZXNvdXJjZSA9IHtcclxuICAgICAgICBpZDogdXVpZCgpLFxyXG4gICAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sT3B0aW9ucy53b3JrTGltaXQgLyAyKSlcclxuICAgICAgfTtcclxuXHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gU3RhcnQgbWVhc3VyaW5nIGEgcGFnZSBjcmVhdGlvbiB0aW1lXHJcbiAgICAgICAgY29uc3Qgc3RhcnREYXRlID0gZ2V0TmV3RGF0ZVRpbWUoKTtcclxuXHJcbiAgICAgICAgLy8gQ3JlYXRlIGEgbmV3IHBhZ2VcclxuICAgICAgICBhd2FpdCBuZXdQYWdlKHBvb2xSZXNvdXJjZSk7XHJcblxyXG4gICAgICAgIC8vIE1lYXN1cmUgdGhlIHRpbWUgb2YgZnVsbCBjcmVhdGlvbiBhbmQgY29uZmlndXJhdGlvbiBvZiBhIHBhZ2VcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIsIHRvb2sgJHtcclxuICAgICAgICAgICAgZ2V0TmV3RGF0ZVRpbWUoKSAtIHN0YXJ0RGF0ZVxyXG4gICAgICAgICAgfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXR1cm4gcmVhZHkgcG9vbCByZXNvdXJjZVxyXG4gICAgICAgIHJldHVybiBwb29sUmVzb3VyY2U7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIEVycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiB2YWxpZGF0ZVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKlxyXG4gICAgICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgaWYgdGhlIHdvcmtlclxyXG4gICAgICogaXMgdmFsaWQgYW5kIHdpdGhpbiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCB0byBmYWxzZS5cclxuICAgICAqL1xyXG4gICAgdmFsaWRhdGU6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSW4gY2VydGFpbiBjYXNlcyBhY3F1aXJpbmcgdGhyb3dzIGEgVGFyZ2V0Q2xvc2VFcnJvciwgd2hpY2ggbWF5XHJcbiAgICAgIC8vIGJlIGNhdXNlZCBieSB0d28gdGhpbmdzOlxyXG4gICAgICAvLyAtIFRoZSBwYWdlIGlzIGNsb3NlZCBhbmQgYXR0ZW1wdGVkIHRvIGJlIHJldXNlZC5cclxuICAgICAgLy8gLSBMb3N0IGNvbnRhY3Qgd2l0aCB0aGUgYnJvd3Nlci5cclxuICAgICAgLy9cclxuICAgICAgLy8gV2hhdCB3ZSdyZSBzZWVpbmcgaW4gbG9ncyBpcyB0aGF0IHN1Y2Nlc3NpdmUgZXhwb3J0cyB0eXBpY2FsbHlcclxuICAgICAgLy8gc3VjY2VlZHMsIGFuZCB0aGUgc2VydmVyIHJlY292ZXJzLCBpbmRpY2F0aW5nIHRoYXQgaXQncyBsaWtlbHlcclxuICAgICAgLy8gdGhlIGZpcnN0IGNhc2UuIFRoaXMgaXMgYW4gYXR0ZW1wdCBhdCBhbGxpZXZhdGluZyB0aGUgaXNzdWUgYnlcclxuICAgICAgLy8gc2ltcGx5IG5vdCB2YWxpZGF0aW5nIHRoZSB3b3JrZXIgaWYgdGhlIHBhZ2UgaXMgbnVsbCBvciBjbG9zZWQuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFRoZSBhY3R1YWwgcmVzdWx0IGZyb20gd2hlbiB0aGlzIGhhcHBlbmVkLCB3YXMgdGhhdCBhIHdvcmtlciB3b3VsZFxyXG4gICAgICAvLyBiZSBjb21wbGV0ZWx5IGxvY2tlZCwgc3RvcHBpbmcgaXQgZnJvbSBiZWluZyBhY3F1aXJlZCB1bnRpbFxyXG4gICAgICAvLyBpdHMgd29yayBjb3VudCByZWFjaGVkIHRoZSBsaW1pdC5cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgdmFsaWRcclxuICAgICAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAobm8gdmFsaWQgcGFnZSBpcyBmb3VuZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIGNsb3NlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSBpcyBjbG9zZWQgb3IgaW52YWxpZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYG1haW5GcmFtZWAgaXMgZGV0YWNoZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLm1haW5GcmFtZSgpLmRldGFjaGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlJ3MgZnJhbWUgaXMgZGV0YWNoZWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGB3b3JrTGltaXRgIGlzIGV4Y2VlZGVkXHJcbiAgICAgIGlmIChcclxuICAgICAgICBwb29sT3B0aW9ucy53b3JrTGltaXQgJiZcclxuICAgICAgICArK3Bvb2xSZXNvdXJjZS53b3JrQ291bnQgPiBwb29sT3B0aW9ucy53b3JrTGltaXRcclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChleGNlZWRlZCB0aGUgJHtwb29sT3B0aW9ucy53b3JrTGltaXR9IHdvcmtzIHBlciByZXNvdXJjZSBsaW1pdCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBUaGUgYHBvb2xSZXNvdXJjZWAgaXMgdmFsaWRhdGVkXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfSxcclxuXHJcbiAgICAvKipcclxuICAgICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGRlc3Ryb3lcclxuICAgICAqXHJcbiAgICAgKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICAgKiB0aGUgd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAgICovXHJcbiAgICBkZXN0cm95OiBhc3luYyAocG9vbFJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIERlc3Ryb3lpbmcgYSB3b3JrZXIuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFJlbW92ZSBhbGwgYXR0YWNoZWQgZXZlbnQgbGlzdGVuZXJzIGZyb20gdGhlIHJlc291cmNlXHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ3BhZ2VlcnJvcicpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdjb25zb2xlJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2ZyYW1lZGV0YWNoZWQnKTtcclxuXHJcbiAgICAgICAgICAvLyBXZSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5jbG9zZSgpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFBhZ2UgY291bGQgbm90IGJlIGNsb3NlZCB1cG9uIGRlc3Ryb3lpbmcuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xTdGF0cyxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT05cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcblxyXG4vKipcclxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy4gVGhpcyBmdW5jdGlvbiB1c2VzXHJcbiAqIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGwgb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD48L3NjcmlwdD5cclxuICogdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzYW5pdGl6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgLSBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XHJcbiAgLy8gR2V0IHRoZSB2aXJ0dWFsIERPTVxyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG5cclxuICAvLyBDcmVhdGUgYSBwdXJpZnlpbmcgaW5zdGFuY2VcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuXHJcbiAgLy8gUmV0dXJuIHNhbml0aXplZCBpbnB1dFxyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2FuaXRpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyB0byBwcmVwYXJlIGZvciB0aGUgZXhwb3J0aW5nIGNoYXJ0c1xyXG4gKiBpbnRvIHZhcmlvdXMgaW1hZ2Ugb3V0cHV0IGZvcm1hdHMgc3VjaCBhcyBKUEVHLCBQTkcsIFBERiwgYW5kIFNWR3MuXHJcbiAqIEl0IHN1cHBvcnRzIHNpbmdsZSBhbmQgYmF0Y2ggZXhwb3J0IG9wZXJhdGlvbnMgYW5kIGFsbG93cyBjdXN0b21pemF0aW9uXHJcbiAqIHRocm91Z2ggb3B0aW9ucyBwYXNzZWQgZnJvbSBjb25maWd1cmF0aW9ucyBvciBBUElzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlT3B0aW9ucywgaXNBbGxvd2VkQ29uZmlnIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBnZXRQb29sU3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeE91dGZpbGUsXHJcbiAgZml4VHlwZSxcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgZ2xvYmFsIGZsYWcgZm9yIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zIGFuZCBzYXZlc1xyXG4gKiB0aGUgaW1hZ2UgaW4gdGhlIHByb3ZpZGVkIG91dGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIG1heSBiZSBhIHBhcnRpYWxcclxuICogb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMuIEl0IG11c3QgY29udGFpbiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZ1xyXG4gKiBwcm9wZXJ0aWVzOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaW5nbGVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCkge1xyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnRcclxuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcclxuICAgICAgICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIHdoaWxlIHNhdmluZyBhIGNoYXJ0LicsXHJcbiAgICAgICAgICA1MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XHJcbiAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICB9KTtcclxuICB9IGVsc2Uge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NoYXJ0XSBObyBleHBlY3RlZCBgZXhwb3J0YCBvcHRpb25zIHdlcmUgZm91bmQuIFBsZWFzZSBwcm92aWRlIG9uZSBvZiB0aGUgZm9sbG93aW5nIG9wdGlvbnM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuJyxcclxuICAgICAgNDAwXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXHJcbiAqIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XHJcbiAqIFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzIGFyZSBzYXZlZFxyXG4gKiBpbiBwcm92aWRlZCBvdXRmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXkgYmUgYSBwYXJ0aWFsXHJcbiAqIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlXHJcbiAqIHZhbGlkIGltYWdlcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGJhdGNoIGV4cG9ydFxyXG4gKiBwcm9jZXNzZXMgYXJlIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBiYXRjaEV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0ICYmIG9wdGlvbnMuZXhwb3J0LmJhdGNoKSB7XHJcbiAgICAvLyBBbiBhcnJheSBmb3IgY29sbGVjdGluZyBiYXRjaCBleHBvcnRzXHJcbiAgICBjb25zdCBiYXRjaEZ1bmN0aW9ucyA9IFtdO1xyXG5cclxuICAgIC8vIFNwbGl0IGFuZCBwYWlyIHRoZSBgYmF0Y2hgIGFyZ3VtZW50c1xyXG4gICAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpIHx8IFtdKSB7XHJcbiAgICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XHJcbiAgICAgIGlmIChwYWlyLmxlbmd0aCA9PT0gMikge1xyXG4gICAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgICBzdGFydEV4cG9ydChcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgY3VzdG9tT3B0aW9uc2AgcGFyYW1ldGVyIGlzIGFuIG9iamVjdCB0aGF0XHJcbiAqIG1heSBiZSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBUaGUgYGVuZENhbGxiYWNrYCBpcyBjYWxsZWQgd2hlblxyXG4gKiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCB0aGUgYGVycm9yYCBvYmplY3QgYXMgdGhlIGZpcnN0IGFyZ3VtZW50XHJcbiAqIGFuZCB0aGUgYGRhdGFgIG9iamVjdCBhcyB0aGUgc2Vjb25kLCB3aGljaCBjb250YWlucyB0aGUgQmFzZTY0IHJlcHJlc2VudGF0aW9uXHJcbiAqIG9mIHRoZSBjaGFydCBpbiB0aGUgYHJlc3VsdGAgcHJvcGVydHkgYW5kIHRoZSBmdWxsIHNldCBvZiBleHBvcnQgb3B0aW9uc1xyXG4gKiBpbiB0aGUgYG9wdGlvbnNgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PcHRpb25zIC0gVGhlIGBjdXN0b21PcHRpb25zYCBvYmplY3QsIHdoaWNoIG1heVxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMuIElmIHRoZSBwcm92aWRlZCBvcHRpb25zIGFyZSBwYXJ0aWFsLFxyXG4gKiBtaXNzaW5nIHZhbHVlcyB3aWxsIGJlIG1lcmdlZCB3aXRoIHRoZSBkZWZhdWx0IGdlbmVyYWwgb3B0aW9ucywgcmV0cmlldmVkXHJcbiAqIHVzaW5nIHRoZSBgZ2V0T3B0aW9uc2AgZnVuY3Rpb24uXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLiBUaGUgZmlyc3RcclxuICogYXJndW1lbnQgaXMgYGVycm9yYCBvYmplY3QgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIHRoYXQgY29udGFpbnNcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5IGFuZCB0aGUgZnVsbFxyXG4gKiBzZXQgb2YgZXhwb3J0IG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGN1c3RvbU9wdGlvbnMsIGVuZENhbGxiYWNrKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gTWVyZ2UgdGhlIGN1c3RvbSBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VPcHRpb25zKGdldE9wdGlvbnMoZmFsc2UpLCBjdXN0b21PcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gZmlsZUNvbnRlbnQ7XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IGZpbGVDb250ZW50O1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0XHJcbiAqIGNoYXJ0IG9wdGlvbnMgaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnMoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGZyb20gb3B0aW9ucy4nKTtcclxuXHJcbiAgLy8gVHJ5IHRvIGNoZWNrLCB2YWxpZGF0ZSBhbmQgcGFyc2UgdG8gc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgIGlucHV0VG9FeHBvcnQsXHJcbiAgICB0cnVlLFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiBhIGNvcnJlY3Qgc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGlmIChcclxuICAgIHN0cmluZ2lmaWVkT3B0aW9ucyA9PT0gbnVsbCB8fFxyXG4gICAgdHlwZW9mIHN0cmluZ2lmaWVkT3B0aW9ucyAhPT0gJ3N0cmluZycgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuc3RhcnRzV2l0aCgneycpIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLmVuZHNXaXRoKCd9JylcclxuICApIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gT25seSBvcHRpb25zIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9ucyBzZXQgdG8gdHJ1ZS4nLFxyXG4gICAgICA0MDNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHN0cmluZ2lmaWVkT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuc3ZnID0gbnVsbDtcclxuXHJcbiAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIE5vdGlmeSBhYm91dCB0aGUgY3VzdG9tIGxvZ2ljIHVzYWdlIHN0YXR1c1xyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VzdG9tIGxvZ2ljIGlzICR7Y3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA/ICdhbGxvd2VkJyA6ICdkaXNhbGxvd2VkJ30uYFxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIChgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgKVxyXG4gIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4uZXhwb3J0T3B0aW9ucyxcclxuICAgIC4uLl9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gUG9zdCB0aGUgd29yayB0byB0aGUgcG9vbFxyXG4gIHJldHVybiBwb3N0V29yayhvcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmluZENoYXJ0U2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBgaGVpZ2h0YCwgYHdpZHRoYFxyXG4gKiBhbmQgYHNjYWxlYCB2YWx1ZXMgZm9yIHRoZSBjaGFydCBleHBvcnQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZmluZENoYXJ0U2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5vcHRpb25zIHx8IGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLmluc3RyKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IGdsb2JhbE9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBnbG9iYWxPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBgdGhlbWVPcHRpb25zYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IHRoZW1lT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IHRoZW1lT3B0aW9uc0V4cG9ydGluZyB9ID1cclxuICAgIGlzQWxsb3dlZENvbmZpZyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykgfHwgZmFsc2U7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBzY2FsZWAgdmFsdWU6XHJcbiAgLy8gLSBJdCBjYW5ub3QgYmUgbG93ZXIgdGhhbiAwLjFcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBoaWdoZXIgdGhhbiA1LjBcclxuICAvLyAtIEl0IG11c3QgYmUgcm91bmRlZCB0byAyIGRlY2ltYWwgcGxhY2VzIChlLmcuIDAuMjMyMzQgLT4gMC4yMylcclxuICBjb25zdCBzY2FsZSA9IHJvdW5kTnVtYmVyKFxyXG4gICAgTWF0aC5tYXgoXHJcbiAgICAgIDAuMSxcclxuICAgICAgTWF0aC5taW4oXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5zY2FsZSB8fFxyXG4gICAgICAgICAgb3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRTY2FsZSB8fFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICA1LjBcclxuICAgICAgKVxyXG4gICAgKSxcclxuICAgIDJcclxuICApO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgaGVpZ2h0YCB2YWx1ZVxyXG4gIGNvbnN0IGhlaWdodCA9XHJcbiAgICBleHBvcnRPcHRpb25zLmhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdEhlaWdodCB8fFxyXG4gICAgNDAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgd2lkdGhgIHZhbHVlXHJcbiAgY29uc3Qgd2lkdGggPVxyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCB8fFxyXG4gICAgb3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIG9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFdpZHRoIHx8XHJcbiAgICA2MDA7XHJcblxyXG4gIC8vIEdhdGhlciBgaGVpZ2h0YCwgYHdpZHRoYCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiBvbmUgb2JqZWN0XHJcbiAgY29uc3Qgc2l6ZSA9IHsgaGVpZ2h0LCB3aWR0aCwgc2NhbGUgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgYHB4YCBhbmQgYCVgXHJcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcclxuICAgIHNpemVbcGFyYW1dID1cclxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgc2l6ZSBvYmplY3RcclxuICByZXR1cm4gc2l6ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4ZWN1dGlvbiBvZiBjdXN0b20gbG9naWMgb3B0aW9ucywgaW5jbHVkaW5nIGxvYWRpbmcgYHJlc291cmNlc2AsXHJcbiAqIGBjdXN0b21Db2RlYCwgYW5kIGBjYWxsYmFja2AuIElmIGNvZGUgZXhlY3V0aW9uIGlzIGFsbG93ZWQsIGl0IHByb2Nlc3Nlc1xyXG4gKiB0aGUgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYWNjb3JkaW5nbHkuIElmIGNvZGUgZXhlY3V0aW9uIGlzIG5vdCBhbGxvd2VkLFxyXG4gKiBpdCBkaXNhYmxlcyB0aGUgdXNhZ2Ugb2YgcmVzb3VyY2VzLCBjdXN0b20gY29kZSBhbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlQ3VzdG9tTG9naWNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbUxvZ2ljT3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgY3VzdG9tTG9naWNgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY29kZSBleGVjdXRpb25cclxuICogaXMgbm90IGFsbG93ZWQgYnV0IGN1c3RvbSBsb2dpYyBvcHRpb25zIGFyZSBzdGlsbCBwcm92aWRlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgcmVzb3VyY2VzYCBvcHRpb25cclxuICAgIGlmICh0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gQ3VzdG9tIHN0cmluZ2lmaWVkIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIExvYWQgdGhlIGRlZmF1bHQgb25lXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IF9oYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKCdyZXNvdXJjZXMuanNvbicpLCAndXRmOCcpLFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgIHRydWVcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCBgcmVzb3VyY2VzLmpzb25gIGZpbGUuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY3VzdG9tQ29kZWAgb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gbG9hZCBjdXN0b20gY29kZSBhbmQgd3JhcCBhcm91bmQgaXQgaW4gYSBzZWxmIGludm9raW5nIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY3VzdG9tQ29kZWAgY2Fubm90IGJlIGxvYWRlZC4nKTtcclxuXHJcbiAgICAgIC8vIEluIGNhc2Ugb2YgYW4gZXJyb3IsIHNldCB0aGUgb3B0aW9uIHdpdGggbnVsbFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGNhbGxiYWNrIGZ1bmN0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgbnVsbC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGxvYWRpbmdcclxuICogcmVzb3VyY2VzIGZyb20gZmlsZXMgaXMgYWxsb3dlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgbnVsbCBpZiBubyB2YWxpZCByZXNvdXJjZXNcclxuICogYXJlIGZvdW5kLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlcyhcclxuICByZXNvdXJjZXMgPSBudWxsLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gTGlzdCBvZiBhbGxvd2VkIHNlY3Rpb25zIGluIHRoZSByZXNvdXJjZXMgSlNPTlxyXG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XHJcblxyXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgocmVzb3VyY2VzKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2gge1xyXG4gICAgICByZXR1cm4gbnVsbDtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNBbGxvd2VkQ29uZmlnKHJlc291cmNlcywgZmFsc2UsIGFsbG93Q29kZUV4ZWN1dGlvbik7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXHJcbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xyXG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXHJcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBsb2FkaW5nIGFuZCB2YWxpZGF0aW9uIG9mIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgXHJcbiAqIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSWYgdGhlIG9wdGlvbiBpcyBhIHN0cmluZyBhbmQgcmVmZXJlbmNlcyBhIEpTT04gZmlsZVxyXG4gKiAod2hlbiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgaXMgdHJ1ZSksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLiBJZiB0aGVyZSBpcyBhbiBlcnJvclxyXG4gKiBsb2FkaW5nIG9yIHBhcnNpbmcgdGhlIGBnbG9iYWxPcHRpb25zYCBvciBgdGhlbWVPcHRpb25zYCwgdGhlIGVycm9yIGlzIGxvZ2dlZFxyXG4gKiBhbmQgdGhlIG9wdGlvbiBpcyBzZXQgdG8gbnVsbC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICovXHJcbmZ1bmN0aW9uIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShcclxuICBleHBvcnRPcHRpb25zLFxyXG4gIGFsbG93RmlsZVJlc291cmNlcyxcclxuICBhbGxvd0NvZGVFeGVjdXRpb25cclxuKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG9wdGlvbiBleGlzdHNcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgaWYgaXQgaXMgYSBzdHJpbmcgYW5kIGEgZmlsZSBuYW1lIHdpdGggdGhlIGAuanNvbmAgZXh0ZW5zaW9uXHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzICYmXHJcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXS5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICAgICAgICkge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGZpbGUgY29udGVudCBjYW4gYmUgYSBjb25maWcsIGFuZCBzYXZlIGl0IGFzIGEgc3RyaW5nXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIHZhbHVlIGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjaGFydF0gVGhlIFxcYCR7b3B0aW9uc05hbWV9XFxgIGNhbm5vdCBiZSBsb2FkZWQuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gbnVsbDtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBnbG9iYWxPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHRoZW1lT3B0aW9uc2AgcHJlc2VudFxyXG4gIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9ucykpIHtcclxuICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGludGVydmFsc1xyXG4gKiBhbmQgdGltZW91dHMgaW4gYSBjZW50cmFsaXplZCBtYW5uZXIuIEl0IG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGFsbCBhY3RpdmVcclxuICogdGltZXJzIGFuZCBhbGxvd3MgZm9yIHRoZWlyIGVmZmljaWVudCBjbGVhbnVwIHdoZW4gbmVlZGVkLiBUaGlzIGNhbiBiZSB1c2VmdWxcclxuICogaW4gYXBwbGljYXRpb25zIHdoZXJlIHByb3BlciByZXNvdXJjZSBtYW5hZ2VtZW50IGFuZCBjbGVhbiBzaHV0ZG93biBvZiB0aW1lcnNcclxuICogYXJlIGNyaXRpY2FsIHRvIGF2b2lkIG1lbW9yeSBsZWFrcyBvciB1bmludGVuZGVkIGJlaGF2aW9yLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHNcclxuY29uc3QgdGltZXJJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIHRoZSBgc2V0SW50ZXJ2YWxgIG9yIGBzZXRUaW1lb3V0YCBhbmQgdG8gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBhZGRUaW1lclxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsIG9yIGEgdGltZW91dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBhZGRUaW1lcihpZCkge1xyXG4gIHRpbWVySWRzLnB1c2goaWQpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBhbmQgdGltZW91dHMgYnkgaWRzIGdhdGhlcmVkXHJcbiAqIGluIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhckFsbFRpbWVycygpIHtcclxuICBsb2coNCwgYFt0aW1lcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cy5gKTtcclxuICBmb3IgKGNvbnN0IGlkIG9mIHRpbWVySWRzKSB7XHJcbiAgICBjbGVhckludGVydmFsKGlkKTtcclxuICAgIGNsZWFyVGltZW91dChpZCk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgYWRkVGltZXIsXHJcbiAgY2xlYXJBbGxUaW1lcnNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlc1xyXG4gKiBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2VzIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbiB3aXRoXHJcbiAqIHRoZSBwYXNzZWQgZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiBsb2dFcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGdldE9wdGlvbnMoKS5vdGhlci5ub2RlRW52ICE9PSAnZGV2ZWxvcG1lbnQnKSB7XHJcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBgcmV0dXJuRXJyb3JNaWRkbGV3YXJlYCBtaWRkbGV3YXJlXHJcbiAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG59XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmUoZXJyb3IsIHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcclxuICBjb25zdCB7IG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuXHJcbiAgLy8gVXNlIHRoZSBlcnJvcidzIHN0YXR1cyBjb2RlIG9yIHRoZSBkZWZhdWx0IDQwMFxyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlIHx8IDQwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXNwb25zZS5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgZXJyb3IgbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBlcnJvck1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciBjb25maWd1cmluZyBhbmQgZW5hYmxpbmcgcmF0ZVxyXG4gKiBsaW1pdGluZyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IFtyYXRlTGltaXRpbmdPcHRpb25zPWdldE9wdGlvbnMoKS5zZXJ2ZXIucmF0ZUxpbWl0aW5nXSAtXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGByYXRlTGltaXRpbmdgIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWxcclxuICogcmF0ZSBsaW1pdGluZyBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKFxyXG4gIGFwcCxcclxuICByYXRlTGltaXRpbmdPcHRpb25zID0gZ2V0T3B0aW9ucygpLnNlcnZlci5yYXRlTGltaXRpbmdcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIENoZWNrIGlmIHRoZSByYXRlIGxpbWl0aW5nIGlzIGVuYWJsZWRcclxuICAgIGlmIChyYXRlTGltaXRpbmdPcHRpb25zLmVuYWJsZSkge1xyXG4gICAgICBjb25zdCBtc2cgPVxyXG4gICAgICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgICAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XHJcbiAgICAgICAgbWF4OiByYXRlTGltaXRpbmdPcHRpb25zLm1heFJlcXVlc3RzIHx8IDMwLFxyXG4gICAgICAgIHdpbmRvdzogcmF0ZUxpbWl0aW5nT3B0aW9ucy53aW5kb3cgfHwgMSxcclxuICAgICAgICBkZWxheTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5kZWxheSB8fCAwLFxyXG4gICAgICAgIHRydXN0UHJveHk6IHJhdGVMaW1pdGluZ09wdGlvbnMudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwS2V5OiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBLZXkgfHwgZmFsc2UsXHJcbiAgICAgICAgc2tpcFRva2VuOiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBUb2tlbiB8fCBmYWxzZVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgICAgIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XHJcbiAgICAgICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ3JlYXRlIGEgbGltaXRlclxyXG4gICAgICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgICAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xyXG4gICAgICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICAgICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICAgICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcclxuICAgICAgICAgIGlmIChcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICAgICApIHtcclxuICAgICAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICAgICAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tyYXRlIGxpbWl0aW5nXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXQgdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBIGN1c3RvbSBIVFRQIGVycm9yIGNsYXNzIHRoYXQgZXh0ZW5kcyB0aGUgYEV4cG9ydEVycm9yYC4gVXNlZCB0byBoYW5kbGVcclxuICogZXJyb3JzIHdpdGggSFRUUCBzdGF0dXMgY29kZXMuXHJcbiAqL1xyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB0aGUgYEh0dHBFcnJvcmAuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIFRoZSBlcnJvciBtZXNzYWdlIHRvIGJlIGRpc3BsYXllZC5cclxuICAgKiBAcGFyYW0ge251bWJlcn0gc3RhdHVzQ29kZSAtIE9wdGlvbmFsIEhUVFAgc3RhdHVzIGNvZGUgYXNzb2NpYXRlZFxyXG4gICAqIHdpdGggdGhlIGVycm9yIChlLmcuLCA0MDAsIDUwMCkuXHJcbiAgICovXHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzQ29kZSkge1xyXG4gICAgc3VwZXIobWVzc2FnZSwgc3RhdHVzQ29kZSk7XHJcbiAgfVxyXG5cclxuICAvKipcclxuICAgKiBTZXRzIG9yIHVwZGF0ZXMgdGhlIEhUVFAgc3RhdHVzIGNvZGUgZm9yIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gVGhlIEhUVFAgc3RhdHVzIGNvZGUgdG8gYXNzaWduIHRvIHRoZSBlcnJvci5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtIdHRwRXJyb3J9IFRoZSB1cGRhdGVkIGluc3RhbmNlIG9mIHRoZSBgSHR0cEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRTdGF0dXMoc3RhdHVzQ29kZSkge1xyXG4gICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1pZGRsZXdhcmUgZnVuY3Rpb25zIGZvciB2YWxpZGF0aW5nIGluY29taW5nIEhUVFAgcmVxdWVzdHNcclxuICogaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi4gVGhpcyBtb2R1bGUgZW5zdXJlcyB0aGF0IHJlcXVlc3RzIGNvbnRhaW5cclxuICogYXBwcm9wcmlhdGUgY29udGVudCB0eXBlcyBhbmQgdmFsaWQgcmVxdWVzdCBib2RpZXMsIGluY2x1ZGluZyBwcm9wZXIgSlNPTlxyXG4gKiBzdHJ1Y3R1cmVzIGFuZCBjaGFydCBkYXRhIGZvciBleHBvcnRzLiBJdCBjaGVja3MgZm9yIHBvdGVudGlhbCBpc3N1ZXMgc3VjaFxyXG4gKiBhcyBtaXNzaW5nIG9yIG1hbGZvcm1lZCBkYXRhLCBwcml2YXRlIHJhbmdlIFVSTHMgaW4gU1ZHIHBheWxvYWRzLCBhbmQgYWxsb3dzXHJcbiAqIGZvciBmbGV4aWJsZSBvcHRpb25zIHZhbGlkYXRpb24uIFRoZSBtaWRkbGV3YXJlIGxvZ3MgZGV0YWlsZWQgaW5mb3JtYXRpb25cclxuICogYW5kIGhhbmRsZXMgZXJyb3JzIHJlbGF0ZWQgdG8gaW5jb3JyZWN0IHBheWxvYWRzLCBjaGFydCBkYXRhLCBhbmQgcHJpdmF0ZSBVUkxcclxuICogdXNhZ2UuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uIH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeENvbnN0cixcclxuICBmaXhUeXBlLFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZFxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtIdHRwRXJyb3J9IFRocm93cyBhbiBgSHR0cEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZSB1cmxcclxuICogZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24gZm9yIHRoZSBzZXJ2ZXJcclxuICAgIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpO1xyXG5cclxuICAgIC8vIEZpbmQgYSBjb3JyZWN0IGNoYXJ0IG9wdGlvbnNcclxuICAgIGNvbnN0IGluc3RyID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAvLyBVc2Ugb25lIG9mIHRoZSBiZWxvd1xyXG4gICAgICBib2R5Lmluc3RyIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmluZmlsZSB8fCBib2R5LmRhdGEsXHJcbiAgICAgIC8vIFN0cmluZ2lmeSBvcHRpb25zXHJcbiAgICAgIHRydWUsXHJcbiAgICAgIC8vIEFsbG93IG9yIGRpc2FsbG93IGZ1bmN0aW9uc1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBjaGFydCBkYXRhXHJcbiAgICBpZiAoaW5zdHIgPT09IG51bGwgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgbWlzc2luZyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm9yIGV4cG9ydDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRlc3Qgb2YgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkcgZmFpbHNcclxuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGJvZHkuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiW3ZhbGlkYXRpb25dIFNWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluICd4bGluazpocmVmJyBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBib2R5IGFuZCBzdG9yZSBwYXJzZWQgc3RydWN0dXJlIGluIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnMgPSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY3JlYXRlZCBJRCBhcyBhIGBfcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgdmFsaWRhdGVkIG9wdGlvbnNcclxuICAgICAgX3JlcXVlc3RJZDogcmVxdWVzdElkLFxyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgIG91dGZpbGU6XHJcbiAgICAgICAgICBib2R5Lm91dGZpbGUgfHxcclxuICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Zml4VHlwZShib2R5LnR5cGUpfWAsXHJcbiAgICAgICAgdHlwZTogZml4VHlwZShib2R5LnR5cGUsIGJvZHkub3V0ZmlsZSksXHJcbiAgICAgICAgY29uc3RyOiBmaXhDb25zdHIoYm9keS5jb25zdHIpLFxyXG4gICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUsXHJcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICBib2R5LnRoZW1lT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgbmV4dCBtaWRkbGV3YXJlXHJcbiAgICByZXR1cm4gbmV4dCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBjb250ZW50IHR5cGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgY29udGVudFR5cGVNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHJlcXVlc3QgYm9keSByZXF1ZXN0IHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIHJlcXVlc3RCb2R5TWlkZGxld2FyZSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgdGhlIGV4cG9ydCByb3V0ZXMgYW5kIGxvZ2ljIGZvciBoYW5kbGluZyBjaGFydCBleHBvcnRcclxuICogcmVxdWVzdHMgaW4gYW4gRXhwcmVzcyBzZXJ2ZXIuIFRoaXMgbW9kdWxlIHByb2Nlc3NlcyBpbmNvbWluZyByZXF1ZXN0c1xyXG4gKiB0byBleHBvcnQgY2hhcnRzIGluIHZhcmlvdXMgZm9ybWF0cyAoZS5nLiBKUEVHLCBQTkcsIFBERiwgU1ZHKS4gSXQgaW50ZWdyYXRlc1xyXG4gKiB3aXRoIEhpZ2hjaGFydHMnIGNvcmUgZnVuY3Rpb25hbGl0aWVzIGFuZCBzdXBwb3J0cyBib3RoIGltbWVkaWF0ZSBkb3dubG9hZFxyXG4gKiByZXNwb25zZXMgYW5kIEJhc2U2NC1lbmNvZGVkIGNvbnRlbnQgcmV0dXJucy4gVGhlIGNvZGUgYWxzbyBmZWF0dXJlc1xyXG4gKiBiZW5jaG1hcmtpbmcgZm9yIHBlcmZvcm1hbmNlIG1vbml0b3JpbmcuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldEJhc2U2NCwgbWVhc3VyZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiByZXF1ZXN0RXhwb3J0KHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWUgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xyXG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XHJcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIG9wdGlvbnMgcHJldmlvdXNseSB2YWxpZGF0ZWQgaW4gdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGlkXHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByZXF1ZXN0T3B0aW9ucy5fcmVxdWVzdElkO1xyXG5cclxuICAgIC8vIEluZm8gYWJvdXQgYW4gaW5jb21pbmcgcmVxdWVzdCB3aXRoIGNvcnJlY3QgZGF0YVxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHtyZXF1ZXN0SWR9LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQocmVxdWVzdE9wdGlvbnMsIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxyXG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XHJcblxyXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXHJcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm47XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghZGF0YSB8fCAhZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBSZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fFxyXG4gICAgICAgICAgICByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCByZXN1bHQgaXMgJHtkYXRhLnJlc3VsdH0uYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW2V4cG9ydF0gVW5leHBlY3RlZCByZXR1cm4gb2YgdGhlIGV4cG9ydCByZXN1bHQgZnJvbSB0aGUgY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBSZXR1cm4gdGhlIHJlc3VsdCBpbiBhbiBhcHByb3ByaWF0ZSBmb3JtYXRcclxuICAgICAgaWYgKGRhdGEucmVzdWx0KSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzIHRvb2sgJHtyZXF1ZXN0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIGB0eXBlYCwgYGI2NGAsIGBub0Rvd25sb2FkYCwgYW5kIGBvdXRmaWxlYCBmcm9tIG9wdGlvbnNcclxuICAgICAgICBjb25zdCB7IHR5cGUsIGI2NCwgbm9Eb3dubG9hZCwgb3V0ZmlsZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgLy8gSWYgb25seSBCYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXHJcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xyXG5cclxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxyXG4gICAgICAgIGlmICghbm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChvdXRmaWxlKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnQsIG90aGVyd2lzZSBhIGI2NCBzdHJpbmcgZnJvbSBhIGJ1ZmZlclxyXG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xyXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGRhdGEucmVzdWx0KVxyXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JykpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBleHBvcnRgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGV4cG9ydFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGV4cG9ydFJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3RcclxuICAgKiBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIHJlcXVlc3RFeHBvcnQpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvOmZpbGVuYW1lJyAtIEEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIHJlcXVlc3RFeHBvcnQpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZlciBoZWFsdGggbW9uaXRvcmluZywgaW5jbHVkaW5nXHJcbiAqIHVwdGltZSwgc3VjY2VzcyByYXRlcywgYW5kIG90aGVyIHNlcnZlciBzdGF0aXN0aWNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0SGlnaGNoYXJ0c1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xTdGF0cywgZ2V0UG9vbEluZm9KU09OIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG5cclxuICAgICAgICAvLyBFeHBvcnRzXHJcbiAgICAgICAgYXZlcmFnZUV4cG9ydFRpbWU6IHN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UsXHJcbiAgICAgICAgYXR0ZW1wdGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCxcclxuICAgICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzUGVyZm9ybWVkLFxyXG4gICAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNEcm9wcGVkLFxyXG4gICAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCAvIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQpICogMTAwLFxyXG5cclxuICAgICAgICAvLyBQb29sXHJcbiAgICAgICAgcG9vbDogZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAgIC8vIE1vdmluZyBhdmVyYWdlXHJcbiAgICAgICAgcGVyaW9kLFxyXG4gICAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgICAgbWVzc2FnZTpcclxuICAgICAgICAgIGlzTmFOKG1vdmluZ0F2ZXJhZ2UpIHx8ICFzdWNjZXNzUmF0ZXMubGVuZ3RoXHJcbiAgICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xyXG4gICAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXHJcblxyXG4gICAgICAgIC8vIFNWRyBhbmQgSlNPTiBleHBvcnRzXHJcbiAgICAgICAgc3ZnRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21TdmcsXHJcbiAgICAgICAganNvbkV4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9ucyxcclxuICAgICAgICBzdmdFeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnQXR0ZW1wdHMsXHJcbiAgICAgICAganNvbkV4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHNcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmluZyB0aGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIHdoZW4gZW5hYmxlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB1aWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdWlSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB1aVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy8nIC0gQSByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldChnZXRPcHRpb25zKCkudWkucm91dGUgfHwgJy8nLCAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3IgdXBkYXRpbmcgdGhlIEhpZ2hjaGFydHMgdmVyc2lvblxyXG4gKiBvbiB0aGUgc2VydmVyLCB3aXRoIGF1dGhlbnRpY2F0aW9uIGFuZCB2YWxpZGF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uLCBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdmVyc2lvbl9jaGFuZ2VgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicgLSBBIHJvdXRlIGZvciBjaGFuZ2luZ1xyXG4gICAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJywgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGRpcmVjdGx5IGZyb20gZW52c1xyXG4gICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cclxuICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIFRoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBmcm9tIHRoZSBoYy1hdXRoIGhlYWRlclxyXG4gICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cclxuICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIEludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgIDQwMVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFVwZGF0ZSB2ZXJzaW9uXHJcbiAgICAgICAgICBhd2FpdCB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgYFt2ZXJzaW9uXSBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgIDQwMFxyXG4gICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICBoaWdoY2hhcnRzVmVyc2lvbjogZ2V0SGlnaGNoYXJ0c1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignW3ZlcnNpb25dIE5vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgdGhhdCBzZXRzIHVwIGFuZCBtYW5hZ2VzIEhUVFAgYW5kIEhUVFBTIHNlcnZlcnNcclxuICogZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IGhhbmRsZXMgc2VydmVyIGluaXRpYWxpemF0aW9uLFxyXG4gKiBjb25maWd1cmF0aW9uLCBlcnJvciBoYW5kbGluZywgbWlkZGxld2FyZSBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGUgfSBmcm9tICdmcy9wcm9taXNlcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xyXG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IGVycm9yTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL2Vycm9yLmpzJztcclxuaW1wb3J0IHJhdGVMaW1pdGluZ01pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9yYXRlTGltaXRpbmcuanMnO1xyXG5pbXBvcnQgdmFsaWRhdGlvbk1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlcyBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xyXG5pbXBvcnQgdWlSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xyXG5pbXBvcnQgdmVyc2lvbkNoYW5nZVJvdXRlcyBmcm9tICcuL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vKipcclxuICogU3RhcnRzIEhUVFAgb3IvYW5kIEhUVFBTIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi5cclxuICogVGhlIGBzZXJ2ZXJPcHRpb25zYCBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZVxyXG4gKiB0aGUgYHNlcnZlcmAgc2VjdGlvbiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbc2VydmVyT3B0aW9ucz1nZXRPcHRpb25zKCkuc2VydmVyXSAtIE9iamVjdCBjb250YWluaW5nXHJcbiAqIGBzZXJ2ZXJgIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWwgc2VydmVyIG9wdGlvbnNcclxuICogb2YgdGhlIGV4cG9ydCBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIHRoZSBzZXJ2ZXIgc2hvdWxkIG5vdCBiZSBlbmFibGVkIG9yIHdoZW4gbm8gdmFsaWQgRXhwcmVzcyBhcHBcclxuICogaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMgPSBnZXRPcHRpb25zKCkuc2VydmVyKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcclxuICAgIGlmICghc2VydmVyT3B0aW9ucy5lbmFibGUgfHwgIWFwcCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tzZXJ2ZXJdIFNlcnZlciBjYW5ub3QgYmUgc3RhcnRlZCAobm90IGVuYWJsZWQgb3Igbm8gY29ycmVjdCBFeHByZXNzIGFwcCBmb3VuZCkuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUb28gYmlnIGxpbWl0cyBsZWFkIHRvIHRpbWVvdXRzIGluIHRoZSBleHBvcnQgcHJvY2VzcyB3aGVuXHJcbiAgICAvLyB0aGUgcmFzdGVyaXphdGlvbiB0aW1lb3V0IGlzIHNldCB0b28gbG93XHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gc2VydmVyT3B0aW9ucy51cGxvYWRMaW1pdCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAgIC8vIE1lbW9yeSBzdG9yYWdlIGZvciBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XHJcblxyXG4gICAgLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBtdWx0ZXIgcGFja2FnZVxyXG4gICAgY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICAgICAgc3RvcmFnZSxcclxuICAgICAgbGltaXRzOiB7XHJcbiAgICAgICAgZmllbGRTaXplOiB1cGxvYWRMaW1pdEJ5dGVzXHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcclxuICAgIGFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbiAgICAvLyBFbmFibGUgQ09SUyBzdXBwb3J0XHJcbiAgICBhcHAudXNlKFxyXG4gICAgICBjb3JzKHtcclxuICAgICAgICBtZXRob2RzOiBbJ1BPU1QnLCAnR0VUJywgJ09QVElPTlMnXVxyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXR0aW5nIGEgbG90IG9mIGBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3JgIGV4Y2VwdGlvbnMgKGV2ZW4gdGhvdWdoIHRoaXNcclxuICAgIC8vIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlKVxyXG4gICAgYXBwLnVzZSgocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgcmVzcG9uc2Uuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcclxuICAgICAgbmV4dCgpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBKU09OIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MuanNvbih7XHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyIGZvciBVUkwtZW5jb2RlZCBmb3JtIGRhdGFcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGV4cHJlc3MudXJsZW5jb2RlZCh7XHJcbiAgICAgICAgZXh0ZW5kZWQ6IHRydWUsXHJcbiAgICAgICAgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfSlcclxuICAgICk7XHJcblxyXG4gICAgLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbiAgICBhcHAudXNlKHVwbG9hZC5ub25lKCkpO1xyXG5cclxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcclxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLnNzbC5mb3JjZSkge1xyXG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcclxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XHJcblxyXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgLy8gTGlzdGVuXHJcbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMucG9ydH0uYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcclxuICAgIGlmIChzZXJ2ZXJPcHRpb25zLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCByZWFkRmlsZShcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmNydCcpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAvLyBMaXN0ZW5cclxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgc2VydmVyT3B0aW9ucy5ob3N0LCAoKSA9PiB7XHJcbiAgICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXHJcbiAgICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5zc2wucG9ydH0uYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgc2VydmVyT3B0aW9ucy5yYXRlTGltaXRpbmcpO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgdmFsaWRhdGlvbiBoYW5kbGVyXHJcbiAgICB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCByb3V0ZXNcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XHJcbiAgICB1aVJvdXRlcyhhcHApO1xyXG4gICAgdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApO1xyXG5cclxuICAgIC8vIFNldCB1cCB0aGUgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxyXG4gICAgZXJyb3JNaWRkbGV3YXJlKGFwcCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJyxcclxuICAgICAgNTAwXHJcbiAgICApLnNldEVycm9yKGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xvc2VTZXJ2ZXJzKCkge1xyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGFyZSBzZXJ2ZXJzIHdvcmtpbmdcclxuICBpZiAoYWN0aXZlU2VydmVycy5zaXplID4gMCkge1xyXG4gICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xyXG5cclxuICAgIC8vIENsb3NlIGVhY2ggb25lIG9mIHNlcnZlcnNcclxuICAgIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xyXG4gICAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xyXG4gICAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0U2VydmVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPE9iamVjdD59IFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZlcnMoKSB7XHJcbiAgcmV0dXJuIGFjdGl2ZVNlcnZlcnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRFeHByZXNzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFeHByZXNzKCkge1xyXG4gIHJldHVybiBleHByZXNzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFwcFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwcCgpIHtcclxuICByZXR1cm4gYXBwO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgcmF0ZUxpbWl0aW5nYFxyXG4gKiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZyhyYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHJhdGVMaW1pdGluZ09wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1c2VcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHVzZShwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXHJcbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb24ocykgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVyc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhodHRwLlNlcnZlcnxodHRwcy5TZXJ2ZXIpfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhzZXJ2ZXIpIHtcclxuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMSxcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcclxuICAgICk7XHJcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICB9KTtcclxuXHJcbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xyXG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcclxuICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZ2V0RXhwcmVzcyxcclxuICBnZXRBcHAsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgSGFuZGxlcyBncmFjZWZ1bCBzaHV0ZG93biBvZiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLCBlbnN1cmluZ1xyXG4gKiBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXMgc3VjaCBhcyBicm93c2VyLCBwYWdlcywgc2VydmVycywgYW5kIHRpbWVycy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsZWFyQWxsVGltZXJzIH0gZnJvbSAnLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW5zIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWxcclxuICogc2h1dGRvd24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXBcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgYHByb2Nlc3MuZXhpdCgpYCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzaHV0ZG93bkNsZWFuVXAoZXhpdENvZGUpIHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbFRpbWVycygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIGFuIGFjdGl2ZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgICBraWxsUG9vbCgpXHJcbiAgXSk7XHJcblxyXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXHJcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQ29yZSBtb2R1bGUgZm9yIGluaXRpYWxpemluZyBhbmQgbWFuYWdpbmcgdGhlIEhpZ2hjaGFydHMgRXhwb3J0XHJcbiAqIFNlcnZlci4gUHJvdmlkZXMgZnVuY3Rpb25hbGl0aWVzIGZvciBjb25maWd1cmluZyBleHBvcnRzLCBzZXR0aW5nIHVwIHNlcnZlclxyXG4gKiBvcGVyYXRpb25zLCBsb2dnaW5nLCBzY3JpcHRzIGNhY2hpbmcsIHJlc291cmNlIHBvb2xpbmcsIGFuZCBncmFjZWZ1bCBwcm9jZXNzXHJcbiAqIGNsZWFudXAuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWVyZ2VPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9uc1xyXG59IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoY3VzdG9tT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGNvcHkgYW5kIGV4dGVuZCBpdCB3aXRoIHRoZSBpbmNvbWluZyBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gQ2FjaGVcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxyXG5cclxuICAvLyBVdGlsc1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZml4Q29uc3RyIiwiY29uc3RyIiwiZml4ZWRDb25zdHIiLCJ0b0xvd2VyQ2FzZSIsInJlcGxhY2UiLCJpbmNsdWRlcyIsImZpeE91dGZpbGUiLCJ0eXBlIiwib3V0ZmlsZSIsImdldEFic29sdXRlUGF0aCIsInNwbGl0Iiwic2hpZnQiLCJmaXhUeXBlIiwibWltZVR5cGVzIiwiZm9ybWF0cyIsInZhbHVlcyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsInBhdGgiLCJpc0Fic29sdXRlIiwiam9pbiIsImdldEJhc2U2NCIsImlucHV0IiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJ0cmltIiwiZ2V0TmV3RGF0ZVRpbWUiLCJnZXRUaW1lIiwiaXNPYmplY3QiLCJpdGVtIiwiaXNPYmplY3RFbXB0eSIsImtleXMiLCJsZW5ndGgiLCJpc1ByaXZhdGVSYW5nZVVybEZvdW5kIiwic29tZSIsInBhdHRlcm4iLCJ0ZXN0IiwibWVhc3VyZVRpbWUiLCJzdGFydCIsInByb2Nlc3MiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJyb3VuZE51bWJlciIsInZhbHVlIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsIk1hdGgiLCJwb3ciLCJyb3VuZCIsIndyYXBBcm91bmQiLCJjdXN0b21Db2RlIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiaXNDYWxsYmFjayIsImVuZHNXaXRoIiwicmVhZEZpbGVTeW5jIiwic3RhcnRzV2l0aCIsImNvbG9ycyIsImxvZ2dpbmciLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsInBhdGhUb0xvZyIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibG9nIiwiYXJncyIsIm5ld0xldmVsIiwidGV4dHMiLCJsZXZlbCIsInByZWZpeCIsIl9sb2dUb0ZpbGUiLCJjb25zb2xlIiwiYXBwbHkiLCJ1bmRlZmluZWQiLCJjb25jYXQiLCJsb2dXaXRoU3RhY2siLCJlcnJvciIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsIm1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInB1c2giLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJjb25maWciLCJwcm9wQ2hhaW4iLCJmb3JFYWNoIiwiZW50cnkiLCJzdWJzdHJpbmciLCJkb3RlbnYiLCJ2IiwiYXJyYXkiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJtYXAiLCJmaWx0ZXIiLCJib29sZWFuIiwiZW51bSIsInJlZmluZSIsInBvc2l0aXZlTnVtIiwiaXNOYU4iLCJwYXJzZUZsb2F0Iiwibm9uTmVnYXRpdmVOdW0iLCJDb25maWciLCJvYmplY3QiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFydGlhbCIsInBhcnNlIiwiZW52IiwiX2luaXRHbG9iYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsImdldFJlZmVyZW5jZSIsInNldE9wdGlvbnMiLCJjdXN0b21PcHRpb25zIiwiY2xpQXJncyIsIm1vZGlmeUdsb2JhbCIsImNvbmZpZ09wdGlvbnMiLCJjbGlPcHRpb25zIiwiX2xvYWRDb25maWdGaWxlIiwiX3BhaXJBcmd1bWVudFZhbHVlIiwiZ2VuZXJhbE9wdGlvbnMiLCJfdXBkYXRlT3B0aW9ucyIsIm1lcmdlT3B0aW9ucyIsIm9yaWdpbmFsT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJlbnRyaWVzIiwibWFwVG9OZXdPcHRpb25zIiwib2xkT3B0aW9ucyIsInByb3BlcnRpZXNDaGFpbiIsInJlZHVjZSIsIm9iaiIsInByb3AiLCJpbmRleCIsImlzQWxsb3dlZENvbmZpZyIsImFsbG93RnVuY3Rpb25zIiwib2JqZWN0Q29uZmlnIiwiZXZhbCIsIkpTT04iLCJzdHJpbmdpZmllZE9wdGlvbnMiLCJfb3B0aW9uc1N0cmluZ2lmeSIsInBhcnNlZE9wdGlvbnMiLCJfIiwibmFtZSIsImNvbmZpZ09wdCIsImN1c3RvbU9wdCIsImNsaU9wdCIsImNvbmZpZ1ZhbCIsImN1c3RvbVZhbCIsImNsaVZhbCIsImVudlZhbCIsInN0cmluZ2lmeUZ1bmN0aW9ucyIsInN0cmluZ2lmeSIsInJlcGxhY2VBbGwiLCJFcnJvciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiY29uZmlnRmlsZU5hbWUiLCJpIiwib3B0aW9uIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJfZ2V0UHJvdG9jb2xNb2R1bGUiLCJnZXQiLCJyZXNwb25zZSIsInJlc3BvbnNlRGF0YSIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiaHR0cHMiLCJodHRwIiwiRXhwb3J0RXJyb3IiLCJjb25zdHJ1Y3RvciIsInN0YXR1c0NvZGUiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImluZGV4T2YiLCJleHRyYWN0TW9kdWxlTmFtZSIsInNjcmlwdFBhdGgiLCJfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0Iiwic2hvdWxkVGhyb3dFcnJvciIsIm5ld01hbmlmZXN0Iiwid3JpdGVGaWxlU3luYyIsIl9mZXRjaFNjcmlwdHMiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiYyIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJjcmVhdGVDaGFydCIsIm1lcmdlIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsImFuaW1hdGlvbiIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiY2hhcnQiLCJhZGRpdGlvbmFsT3B0aW9ucyIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwidGVtcGxhdGUiLCJicm93c2VyIiwiY3JlYXRlQnJvd3NlciIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwic2V0VGltZW91dCIsImNsb3NlQnJvd3NlciIsImNvbm5lY3RlZCIsImNsb3NlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJfc2V0UGFnZUNvbnRlbnQiLCJfc2V0UGFnZUV2ZW50cyIsImlzQ2xvc2VkIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsIndhaXRVbnRpbCIsImV2YWx1YXRlIiwiYm9keSIsImlubmVySFRNTCIsImlkIiwid29ya0NvdW50IiwiYWRkUGFnZVJlc291cmNlcyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImluamVjdGVkUmVzb3VyY2VzIiwiaW5qZWN0ZWRKcyIsImpzIiwiY29udGVudCIsImZpbGVzIiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJhZGRTY3JpcHRUYWciLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwic2V0Q29udGVudCIsImNzc1RlbXBsYXRlIiwic3ZnVGVtcGxhdGUiLCJwdXBwZXRlZXJFeHBvcnQiLCJleHBvcnRPcHRpb25zIiwiaXNTVkciLCJfc2V0QXNTdmciLCJfc2V0QXNPcHRpb25zIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJfcmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFRpbWUiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJ1dWlkIiwicmFuZG9tIiwic3RhcnREYXRlIiwidmFsaWRhdGUiLCJtYWluRnJhbWUiLCJkZXRhY2hlZCIsInJlbW92ZUFsbExpc3RlbmVycyIsInNhbml0aXplIiwiSlNET00iLCJET01QdXJpZnkiLCJBRERfVEFHUyIsInNpbmdsZUV4cG9ydCIsInN0YXJ0RXhwb3J0IiwiZGF0YSIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImVuZENhbGxiYWNrIiwiZmlsZUNvbnRlbnQiLCJfZXhwb3J0RnJvbVN2ZyIsIl9leHBvcnRGcm9tT3B0aW9ucyIsImdldEFsbG93Q29kZUV4ZWN1dGlvbiIsInNldEFsbG93Q29kZUV4ZWN1dGlvbiIsImlucHV0VG9FeHBvcnQiLCJfcHJlcGFyZUV4cG9ydCIsIl9oYW5kbGVDdXN0b21Mb2dpYyIsIl9oYW5kbGVHbG9iYWxBbmRUaGVtZSIsIl9maW5kQ2hhcnRTaXplIiwib3B0aW9uc0NoYXJ0Iiwib3B0aW9uc0V4cG9ydGluZyIsImdsb2JhbE9wdGlvbnNDaGFydCIsImdsb2JhbE9wdGlvbnNFeHBvcnRpbmciLCJ0aGVtZU9wdGlvbnNDaGFydCIsInRoZW1lT3B0aW9uc0V4cG9ydGluZyIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJfaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJwcm9wTmFtZSIsIm9wdGlvbnNOYW1lIiwidGltZXJJZHMiLCJhZGRUaW1lciIsImNsZWFyQWxsVGltZXJzIiwiY2xlYXJJbnRlcnZhbCIsImNsZWFyVGltZW91dCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcXVlc3QiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RhdHVzIiwianNvbiIsImVycm9yTWlkZGxld2FyZSIsImFwcCIsInVzZSIsInJhdGVMaW1pdGluZ01pZGRsZXdhcmUiLCJyYXRlTGltaXRpbmdPcHRpb25zIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwicmF0ZUxpbWl0Iiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwiY29udGVudFR5cGVNaWRkbGV3YXJlIiwiY29udGVudFR5cGUiLCJoZWFkZXJzIiwicmVxdWVzdEJvZHlNaWRkbGV3YXJlIiwicmVxdWVzdElkIiwiY29ubmVjdGlvbiIsInJlbW90ZUFkZHJlc3MiLCJ2YWxpZGF0ZWRPcHRpb25zIiwicGFyYW1zIiwiZmlsZW5hbWUiLCJ2YWxpZGF0aW9uTWlkZGxld2FyZSIsInBvc3QiLCJyZXZlcnNlZE1pbWUiLCJwbmciLCJqcGVnIiwiZ2lmIiwicmVxdWVzdEV4cG9ydCIsInJlcXVlc3RDb3VudGVyIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJoYWRFcnJvcnMiLCJoZWFkZXIiLCJhdHRhY2htZW50IiwiZXhwb3J0Um91dGVzIiwic2VydmVyU3RhcnRUaW1lIiwicGFja2FnZUZpbGUiLCJzdWNjZXNzUmF0ZXMiLCJyZWNvcmRJbnRlcnZhbCIsIndpbmRvd1NpemUiLCJfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSIsImEiLCJiIiwiX3N0YXJ0U3VjY2Vzc1JhdGUiLCJzZXRJbnRlcnZhbCIsInN0YXRzIiwic3VjY2Vzc1JhdGlvIiwiaGVhbHRoUm91dGVzIiwicGVyaW9kIiwibW92aW5nQXZlcmFnZSIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJzZXJ2ZXJWZXJzaW9uIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlRXhwb3J0VGltZSIsImF0dGVtcHRlZEV4cG9ydHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwidG9GaXhlZCIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsImFkbWluVG9rZW4iLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsImVuYWJsZVJhdGVMaW1pdGluZyIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyIsImNvZGUiXSwibWFwcGluZ3MiOiJ3bkJBMkJPLE1BQU1BLFlBQVlDLElBQWFBLGNBQUMsSUFBSUMsSUFBSSxPQUFRLG9CQUFBQyxTQUFBQyxRQUFBLE9BQUFDLGNBQUFDLFlBQUFDLEtBQUFDLHdCQUFBLFdBQUFBLHVCQUFBQyxRQUFBQyxlQUFBRix1QkFBQUcsS0FBQSxJQUFBVCxJQUFBLFlBQUFDLFNBQUFTLFNBQUFMLE9BK0JoRCxTQUFTTSxTQUFTQyxHQUV2QixHQUFlLE9BQVhBLEdBQXFDLGlCQUFYQSxFQUM1QixPQUFPQSxFQUlULE1BQU1DLEVBQWFDLE1BQU1DLFFBQVFILEdBQVUsR0FBSyxHQUdoRCxJQUFLLE1BQU1JLEtBQU9KLEVBQ1pLLE9BQU9DLFVBQVVDLGVBQWVDLEtBQUtSLEVBQVFJLEtBQy9DSCxFQUFXRyxHQUFPTCxTQUFTQyxFQUFPSSxLQUt0QyxPQUFPSCxDQUNULENBMkRPLFNBQVNRLFVBQVVDLEdBQ3hCLElBRUUs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 +"use strict";Object.defineProperty(exports,"__esModule",{value:!0}),require("colors");var fs=require("fs"),path=require("path"),httpsProxyAgent=require("https-proxy-agent"),url=require("url"),dotenv=require("dotenv"),zod=require("zod"),http=require("http"),https=require("https"),tarn=require("tarn"),uuid=require("uuid"),puppeteer=require("puppeteer"),DOMPurify=require("dompurify"),jsdom=require("jsdom"),promises=require("fs/promises"),cors=require("cors"),express=require("express"),multer=require("multer"),rateLimit=require("express-rate-limit"),_documentCurrentScript="undefined"!=typeof document?document.currentScript:null;const __dirname$1=url.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:_documentCurrentScript&&"SCRIPT"===_documentCurrentScript.tagName.toUpperCase()&&_documentCurrentScript.src||new URL("index.cjs",document.baseURI).href));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return path.isAbsolute(e)?e:path.join(__dirname$1,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!fs.existsSync(getAbsolutePath(logging.dest))&&fs.mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(path.join(logging.dest,logging.file)),logging.pathCreated=!0),fs.appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;zod.z.setErrorMap(_customErrorMap);const v={boolean:e=>e?zod.z.boolean():zod.z.union([zod.z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),zod.z.boolean()]).nullable(),string:e=>e?zod.z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):zod.z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?zod.z.enum([...e]):zod.z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const r=zod.z.string().trim().array(),n=zod.z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(i):zod.z.union([n,r]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?zod.z.number().positive():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().positive()]).nullable(),nonNegativeNum:e=>e?zod.z.number().nonnegative():zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):zod.z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>zod.z.union([zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable(),additionalOptions:()=>zod.z.union([zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),zod.z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):zod.z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>zod.z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():zod.z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?zod.z.number().gte(.1).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=zod.z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),r=zod.z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?zod.z.union([t,o]).nullable():zod.z.union([t,r]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?zod.z.number().int().gte(0).lte(5):zod.z.union([zod.z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),zod.z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>zod.z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>zod.z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>zod.z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=zod.z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=zod.z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===zod.z.ZodIssueCode.invalid_type)return e.received===zod.z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===zod.z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===zod.z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${r} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};if(t.length)try{r=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{n=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(fs.readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=path.join(r,"manifest.json"),i=path.join(r,"sources.js");if(!fs.existsSync(r)&&fs.mkdirSync(r,{recursive:!0}),!fs.existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(fs.readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=fs.readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new httpsProxyAgent.HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),fs.writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=fs.readFileSync(path.join(__dirname$1,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:fs.readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:path.join(__dirname$1,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:path.join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new tarn.Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:uuid.v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new jsdom.JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?fs.writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):fs.writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=fs.readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))try{r.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{r.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(fs.readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=uuid.v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);try{e.validatedOptions=looseValidate({_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new HttpError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(fs.readFileSync(path.join(__dirname$1,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(path.join(__dirname$1,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(path.join(__dirname$1,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await promises.readFile(path.join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};exports.default=index,exports.initExport=initExport; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL2Vycm9ycy9IdHRwRXJyb3IuanMiLCIuLi9saWIvc2VydmVyL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9leHBvcnQuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy9oZWFsdGguanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMiLCIuLi9saWIvc2VydmVyL3NlcnZlci5qcyIsIi4uL2xpYi9yZXNvdXJjZVJlbGVhc2UuanMiLCIuLi9saWIvaW5kZXguanMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdXRpbGl0eSBtb2R1bGUgcHJvdmlkZXNcclxuICogYSBjb21wcmVoZW5zaXZlIHNldCBvZiBoZWxwZXIgZnVuY3Rpb25zIGFuZCBjb25zdGFudHMgZGVzaWduZWQgdG8gc3RyZWFtbGluZVxyXG4gKiBhbmQgZW5oYW5jZSB2YXJpb3VzIG9wZXJhdGlvbnMgcmVxdWlyZWQgZm9yIEhpZ2hjaGFydHMgZXhwb3J0IHRhc2tzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgaXNBYnNvbHV0ZSwgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbi8vIFRoZSBkaXJlY3RvcnkgcGF0aFxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhclRleHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyB0aGUgJy9cXHNcXHMrL2cnIFJlZ0V4cC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyB0aGUgJyAnIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyVGV4dCh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpIHtcclxuICByZXR1cm4gdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBkZWVwQ29weVxyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8QXJyYXkpfSBvYmpBcnIgLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fEFycmF5KX0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGRlZXBDb3B5KG9iakFycikge1xyXG4gIC8vIElmIHRoZSBgb2JqQXJyYCBpcyBudWxsIG9yIG5vdCBvZiB0aGUgYG9iamVjdGAgdHlwZSwgcmV0dXJuIGl0XHJcbiAgaWYgKG9iakFyciA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqQXJyICE9PSAnb2JqZWN0Jykge1xyXG4gICAgcmV0dXJuIG9iakFycjtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZWl0aGVyIGEgbmV3IGFycmF5IG9yIGEgbmV3IG9iamVjdFxyXG4gIGNvbnN0IG9iakFyckNvcHkgPSBBcnJheS5pc0FycmF5KG9iakFycikgPyBbXSA6IHt9O1xyXG5cclxuICAvLyBSZWN1cnNpdmVseSBjb3B5IGVhY2ggcHJvcGVydHlcclxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmpBcnIpIHtcclxuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqQXJyLCBrZXkpKSB7XHJcbiAgICAgIG9iakFyckNvcHlba2V5XSA9IGRlZXBDb3B5KG9iakFycltrZXldKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgY29waWVkIG9iamVjdFxyXG4gIHJldHVybiBvYmpBcnJDb3B5O1xyXG59XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZXhwQmFja29mZlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgMC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkanVzdHMgdGhlIGNvbnN0cnVjdG9yIG5hbWUgYnkgdHJhbnNmb3JtaW5nIGFuZCBub3JtYWxpemluZyBpdCBiYXNlZFxyXG4gKiBvbiBjb21tb24gY2hhcnQgdHlwZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGZpeGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRml4ZXMgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGZpeE91dGZpbGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIG91dGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGV9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBmaXhUeXBlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW291dGZpbGU9bnVsbF0gLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIG51bGwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZml4VHlwZSh0eXBlLCBvdXRmaWxlID0gbnVsbCkge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBHZXQgZm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBPYmplY3QudmFsdWVzKG1pbWVUeXBlcyk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxyXG4gIGlmIChvdXRmaWxlKSB7XHJcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xyXG5cclxuICAgIC8vIFN1cHBvcnQgdGhlIEpQRyB0eXBlXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBwYXRoIGlzIHJlbGF0aXZlIG9yIGFic29sdXRlIGFuZCByZXR1cm5zIHRoZSBjb3JyZWN0ZWQsXHJcbiAqIGFic29sdXRlIHBhdGguXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0Fic29sdXRlUGF0aFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIGJlIGNoZWNrZWQgb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBhYnNvbHV0ZSBwYXRoLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFic29sdXRlUGF0aChwYXRoKSB7XHJcbiAgcmV0dXJuIGlzQWJzb2x1dGUocGF0aCkgPyBwYXRoIDogam9pbihfX2Rpcm5hbWUsIHBhdGgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ29udmVydHMgaW5wdXQgZGF0YSB0byBhIEJhc2U2NCBzdHJpbmcgYmFzZWQgb24gdGhlIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QmFzZTY0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBpbnB1dCB0byBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEJhc2U2NCBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJhc2U2NChpbnB1dCwgdHlwZSkge1xyXG4gIC8vIEZvciBwZGYgYW5kIHN2ZyB0eXBlcyB0aGUgaW5wdXQgbXVzdCBiZSB0cmFuc2Zvcm1lZCB0byBCYXNlNjQgZnJvbSBhIGJ1ZmZlclxyXG4gIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICByZXR1cm4gQnVmZmVyLmZyb20oaW5wdXQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpO1xyXG4gIH1cclxuXHJcbiAgLy8gRm9yIHBuZyBhbmQganBlZyBpbnB1dCBpcyBhbHJlYWR5IGEgQmFzZTY0IHN0cmluZ1xyXG4gIHJldHVybiBpbnB1dDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgc3RyaW5naWZpZWQgZGF0ZSB3aXRob3V0IHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlKCkge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIHN0b3JlZCB0aW1lIHZhbHVlIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldE5ld0RhdGVUaW1lXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWUoKSB7XHJcbiAgcmV0dXJuIG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzT2JqZWN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0KGl0ZW0pIHtcclxuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGl0ZW0pID09PSAnW29iamVjdCBPYmplY3RdJztcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RFbXB0eVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGlzT2JqZWN0RW1wdHkoaXRlbSkge1xyXG4gIHJldHVybiAoXHJcbiAgICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcclxuICAgICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgICBpdGVtICE9PSBudWxsICYmXHJcbiAgICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDBcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtib29sZWFufSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKGl0ZW0pIHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgYHByb2Nlc3MuaHJ0aW1lKClgIG1ldGhvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lYXN1cmVUaW1lXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtGdW5jdGlvbn0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZSBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbWVhc3VyZVRpbWUoKSB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHJvdW5kTnVtYmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiByb3VuZE51bWJlcih2YWx1ZSwgcHJlY2lzaW9uID0gMSkge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdG9Cb29sZWFuXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHRvQm9vbGVhbihpdGVtKSB7XHJcbiAgcmV0dXJuIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG59XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB3cmFwQXJvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2lzQ2FsbGJhY2s9ZmFsc2VdIC0gRmxhZyB0aGF0IGluZGljYXRlcyB0aGUgcmV0dXJuZWQgY29kZVxyXG4gKiBtdXN0IGJlIGluIGEgY2FsbGJhY2sgZm9ybWF0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KHN0cmluZ3xudWxsKX0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgbnVsbCBpZiB3cmFwcGluZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB3cmFwQXJvdW5kKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcywgaXNDYWxsYmFjayA9IGZhbHNlKSB7XHJcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XHJcblxyXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICAgIC8vIExvYWQgYSBmaWxlIGlmIHRoZSBmaWxlIHJlc291cmNlcyBhcmUgYWxsb3dlZFxyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGN1c3RvbUNvZGUpLCAndXRmOCcpLFxyXG4gICAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgICAgIGlzQ2FsbGJhY2tcclxuICAgICAgICAgIClcclxuICAgICAgICA6IG51bGw7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAhaXNDYWxsYmFjayAmJlxyXG4gICAgICAoY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKSlcclxuICAgICkge1xyXG4gICAgICAvLyBUcmVhdCBhIGZ1bmN0aW9uIGFzIGEgc2VsZi1pbnZva2luZyBleHByZXNzaW9uXHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE9yIHJldHVybiBhcyBhIHN0cmluZ2lmaWVkIGNvZGVcclxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhDb25zdHIsXHJcbiAgZml4T3V0ZmlsZSxcclxuICBmaXhUeXBlLFxyXG4gIGdldEFic29sdXRlUGF0aCxcclxuICBnZXRCYXNlNjQsXHJcbiAgZ2V0TmV3RGF0ZSxcclxuICBnZXROZXdEYXRlVGltZSxcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgbWVhc3VyZVRpbWUsXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEEgbW9kdWxlIGZvciBtYW5hZ2luZyBsb2dnaW5nIGZ1bmN0aW9uYWxpdHkgd2l0aCBjdXN0b21pemFibGVcclxuICogbG9nIGxldmVscywgY29uc29sZSBhbmQgZmlsZSBsb2dnaW5nIG9wdGlvbnMsIGFuZCBlcnJvciBoYW5kbGluZyBzdXBwb3J0LlxyXG4gKiBUaGUgbW9kdWxlIGFsc28gZW5zdXJlcyB0aGF0IGZpbGUtYmFzZWQgbG9ncyBhcmUgc3RvcmVkIGluIGEgc3RydWN0dXJlZFxyXG4gKiBkaXJlY3RvcnksIGNyZWF0aW5nIHRoZSBuZWNlc3NhcnkgcGF0aHMgYXV0b21hdGljYWxseSBpZiB0aGV5IGRvIG5vdCBleGlzdC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldEFic29sdXRlUGF0aCwgZ2V0TmV3RGF0ZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcclxuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xyXG5cclxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcclxuY29uc3QgbG9nZ2luZyA9IHtcclxuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcclxuICB0b0NvbnNvbGU6IHRydWUsXHJcbiAgdG9GaWxlOiBmYWxzZSxcclxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXHJcbiAgLy8gRnVsbCBwYXRoIHRvIHRoZSBsb2cgZmlsZVxyXG4gIHBhdGhUb0xvZzogJycsXHJcbiAgLy8gTG9nIGxldmVsc1xyXG4gIGxldmVsc0Rlc2M6IFtcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdlcnJvcicsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1syXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1szXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzRdXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIHRoZSBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGBjb25zb2xlLmxvZ2AsIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2coLi4uYXJncykge1xyXG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsc0Rlc2MsIGxldmVsIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgaXQgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcclxuICogY2FuIGJlIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nV2l0aFN0YWNrXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWRcclxuICogYWxvbmcgd2l0aCB0aGUgZXJyb3IuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt2b2lkfSBFbmRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gd2hlbiBhdHRlbXB0aW5nIHRvIGxvZ1xyXG4gKiBpbmZvcm1hdGlvbiBhdCBhIGhpZ2hlciBsZXZlbCB0aGFuIHdoYXQgaXMgYWxsb3dlZC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dXaXRoU3RhY2sobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcclxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XHJcbiAgY29uc3QgcHJlZml4ID0gYCR7Z2V0TmV3RGF0ZSgpfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQWRkIHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXHJcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID0gZXJyb3Iuc3RhY2s7XHJcblxyXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2UsIGlmIGV4aXN0c1xyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlXTtcclxuICBpZiAoc3RhY2tNZXNzYWdlKSB7XHJcbiAgICB0ZXh0cy5wdXNoKCdcXG4nLCBzdGFja01lc3NhZ2UpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIF9sb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbiAgfVxyXG5cclxuICAvLyBMb2cgdG8gY29uc29sZVxyXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xyXG4gICAgY29uc29sZS5sb2cuYXBwbHkoXHJcbiAgICAgIHVuZGVmaW5lZCxcclxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcclxuICAgICAgICB0ZXh0cy5zaGlmdCgpW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcclxuICAgICAgICAuLi50ZXh0c1xyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2UgYWJvdXQgWm9kIGlzc3VlcyB3aXRoIHRoZSB2YWxpZGF0aW9uLiBPcHRpb25hbGx5LFxyXG4gKiBhIGN1c3RvbSBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIFRoZSBhcnJheSBvZiBab2QgaXNzdWVzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZFxyXG4gKiBhbG9uZyB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBsb2dab2RJc3N1ZXMobmV3TGV2ZWwsIGlzc3VlcyA9IFtdLCBjdXN0b21NZXNzYWdlKSB7XHJcbiAgbG9nV2l0aFN0YWNrKFxyXG4gICAgbmV3TGV2ZWwsXHJcbiAgICBudWxsLFxyXG4gICAgW1xyXG4gICAgICBgJHtjdXN0b21NZXNzYWdlfSAtIHRoZSBmb2xsb3dpbmcgWm9kIGlzc3VlcyBvY2N1cmVkOmAsXHJcbiAgICAgIC4uLmlzc3Vlcy5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gU2V0IHRoZSBsb2dnaW5nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobGV2ZWwpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nKHRvQ29uc29sZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgZmlsZSBsb2dnaW5nXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXHJcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlLCBvciA1ID0gYmVuY2htYXJrKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldExvZ0xldmVsXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldExvZ0xldmVsKGxldmVsKSB7XHJcbiAgaWYgKGxldmVsID49IDAgJiYgbGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgbG9nZ2luZy5sZXZlbCA9IGxldmVsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgY29uc29sZSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB0b0NvbnNvbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byB0aGUgY29uc29sZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpIHtcclxuICAvLyBVcGRhdGUgb3B0aW9ucyBmb3IgdGhlIGNvbnNvbGUgbG9nZ2luZ1xyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gdG9Db25zb2xlO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBkZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIHRoZSBsb2cgZmlsZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IGZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICogQHBhcmFtIHtib29sZWFufSB0b0ZpbGUgLSBUaGUgZmxhZyBmb3Igc2V0dGluZyB0aGUgbG9nZ2luZyB0byBhIGZpbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlRmlsZUxvZ2dpbmcoZGVzdCwgZmlsZSwgdG9GaWxlKSB7XHJcbiAgLy8gVXBkYXRlIG9wdGlvbnMgZm9yIHRoZSBmaWxlIGxvZ2dpbmdcclxuICBsb2dnaW5nLnRvRmlsZSA9IHRvRmlsZTtcclxuXHJcbiAgLy8gU2V0IHRoZSBgZGVzdGAgYW5kIGBmaWxlYCBvbmx5IGlmIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZFxyXG4gIGlmICh0b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3Q7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcclxuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHNcclxuICogdGhlIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbG9nVG9GaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBQcm92aWRlcyBkZWZhdWx0IGNvbmZpZ3VyYXRpb25zIHRoYXQgc3VwcG9ydCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIENMSVxyXG4gKiBhcmd1bWVudHMsIGFuZCBpbnRlcmFjdGl2ZSBwcm9tcHRzIGZvciBjdXN0b21pemF0aW9uIG9mIG9wdGlvbnMgYW5kIGZlYXR1cmVzLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IG1hcHMgbGVnYWN5IG9wdGlvbnMgdG8gbW9kZXJuIHN0cnVjdHVyZXMsIGdlbmVyYXRlcyBuZXN0ZWRcclxuICogYXJndW1lbnQgbWFwcGluZ3MsIGFuZCBkaXNwbGF5cyBDTEkgdXNhZ2UgaW5mb3JtYXRpb24uXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGFsbCBhdmFpbGFibGUgb3B0aW9ucywgb3JnYW5pemVkXHJcbiAqIGJ5IHNlY3Rpb25zLlxyXG4gKlxyXG4gKiBUaGlzIG9iamVjdCBpbmNsdWRlczpcclxuICogLSBEZWZhdWx0IHZhbHVlcyBmb3IgZWFjaCBvcHRpb25cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uXHJcbiAqIC0gTmFtZXMgb2YgY29ycmVzcG9uZGluZyBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuICogLSBEZXNjcmlwdGlvbnMgb2YgZWFjaCBwcm9wZXJ0eVxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvblxyXG4gKiAtIFtPcHRpb25hbF0gQ29ycmVzcG9uZGluZyBDTEkgYXJndW1lbnQgbmFtZXMgZm9yIENMSSB1c2FnZVxyXG4gKiAtIFtPcHRpb25hbF0gTGVnYWN5IG5hbWVzIGZyb20gdGhlIHByZXZpb3VzIFBoYW50b21KUy1iYXNlZCBzZXJ2ZXJcclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnUFVQUEVURUVSX0FSR1MnLFxyXG4gICAgICBjbGlOYW1lOiAncHVwcGV0ZWVyQXJncycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJyYXkgb2YgUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgICAgc2VwYXJhdG9yOiAnOydcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjZG5Vcmw6IHtcclxuICAgICAgdmFsdWU6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20nLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZsYWcgdG8gcmVmZXRjaCBzY3JpcHRzIGFmdGVyIGVhY2ggc2VydmVyIHJlcnVuJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWNoZVBhdGg6IHtcclxuICAgICAgdmFsdWU6ICcuY2FjaGUnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlyZWN0b3J5IHBhdGggZm9yIGNhY2hlZCBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydoaWdoY2hhcnRzJywgJ2hpZ2hjaGFydHMtbW9yZScsICdoaWdoY2hhcnRzLTNkJ10sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnc3RvY2snLFxyXG4gICAgICAgICdtYXAnLFxyXG4gICAgICAgICdnYW50dCcsXHJcbiAgICAgICAgJ2V4cG9ydGluZycsXHJcbiAgICAgICAgJ3BhcmFsbGVsLWNvb3JkaW5hdGVzJyxcclxuICAgICAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAgICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICAgICAnYm9vc3QtY2FudmFzJyxcclxuICAgICAgICAnYm9vc3QnLFxyXG4gICAgICAgICdkYXRhJyxcclxuICAgICAgICAnZGF0YS10b29scycsXHJcbiAgICAgICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgICAgICdicm9rZW4tYXhpcycsXHJcbiAgICAgICAgJ2hlYXRtYXAnLFxyXG4gICAgICAgICd0aWxlbWFwJyxcclxuICAgICAgICAndGlsZWR3ZWJtYXAnLFxyXG4gICAgICAgICd0aW1lbGluZScsXHJcbiAgICAgICAgJ3RyZWVtYXAnLFxyXG4gICAgICAgICd0cmVlZ3JhcGgnLFxyXG4gICAgICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAgICAgJ2RyaWxsZG93bicsXHJcbiAgICAgICAgJ2hpc3RvZ3JhbS1iZWxsY3VydmUnLFxyXG4gICAgICAgICdidWxsZXQnLFxyXG4gICAgICAgICdmdW5uZWwnLFxyXG4gICAgICAgICdmdW5uZWwzZCcsXHJcbiAgICAgICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgICAgICdweXJhbWlkM2QnLFxyXG4gICAgICAgICduZXR3b3JrZ3JhcGgnLFxyXG4gICAgICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICAgICAncGFyZXRvJyxcclxuICAgICAgICAncGF0dGVybi1maWxsJyxcclxuICAgICAgICAncGljdG9yaWFsJyxcclxuICAgICAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICAgICAnc2Fua2V5JyxcclxuICAgICAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICAgICAnc2VyaWVzLWxhYmVsJyxcclxuICAgICAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICAgICAnc29saWQtZ2F1Z2UnLFxyXG4gICAgICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAgICAgJ3N0cmVhbWdyYXBoJyxcclxuICAgICAgICAnc3VuYnVyc3QnLFxyXG4gICAgICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgICAgICd2YXJpd2lkZScsXHJcbiAgICAgICAgJ3ZlY3RvcicsXHJcbiAgICAgICAgJ3Zlbm4nLFxyXG4gICAgICAgICd3aW5kYmFyYicsXHJcbiAgICAgICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAgICAgJ3hyYW5nZScsXHJcbiAgICAgICAgJ25vLWRhdGEtdG8tZGlzcGxheScsXHJcbiAgICAgICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgICAgICdkZWJ1Z2dlcicsXHJcbiAgICAgICAgJ2R1bWJiZWxsJyxcclxuICAgICAgICAnbG9sbGlwb3AnLFxyXG4gICAgICAgICdjeWxpbmRlcicsXHJcbiAgICAgICAgJ29yZ2FuaXphdGlvbicsXHJcbiAgICAgICAgJ2RvdHBsb3QnLFxyXG4gICAgICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgICAgICdob2xsb3djYW5kbGVzdGljaycsXHJcbiAgICAgICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgICAgICdmbG93bWFwJyxcclxuICAgICAgICAnZXhwb3J0LWRhdGEnLFxyXG4gICAgICAgICduYXZpZ2F0b3InLFxyXG4gICAgICAgICd0ZXh0cGF0aCdcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgbW9kdWxlIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IFtcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LmpzLzIuMzAuMS9tb21lbnQubWluLmpzJyxcclxuICAgICAgICAnaHR0cHM6Ly9jZG5qcy5jbG91ZGZsYXJlLmNvbS9hamF4L2xpYnMvbW9tZW50LXRpbWV6b25lLzAuNS40NS9tb21lbnQtdGltZXpvbmUtd2l0aC1kYXRhLm1pbi5qcydcclxuICAgICAgXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9JTkZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5wdXQgZmlsZW5hbWUgd2l0aCB0eXBlLCBmb3JtYXR0ZWQgY29ycmVjdGx5IGFzIEpTT04gb3IgU1ZHJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWxpYXMgZm9yIHRoZSBgaW5zdHJgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHN2Zzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TVkcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1NWRyBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IHRvIHJlbmRlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0JBVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0JhdGNoIGpvYiBzdHJpbmcgd2l0aCBpbnB1dC9vdXRwdXQgcGFpcnM6IFwiaW49b3V0O2luPW91dDsuLi5cIicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG91dGZpbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfT1VURklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdPdXRwdXQgZmlsZW5hbWUgd2l0aCB0eXBlLiBDYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2ZyBhbmQgaWdub3JlcyBgdHlwZWAgb3B0aW9uJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdHlwZToge1xyXG4gICAgICB2YWx1ZTogJ3BuZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RZUEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0ZpbGUgZXhwb3J0IGZvcm1hdC4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgICAgaGludDogJ0RlZmF1bHQ6IHBuZycsXHJcbiAgICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvbnN0cjoge1xyXG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfQ09OU1RSJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NoYXJ0IGNvbnN0cnVjdG9yLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBjaGFydCcsXHJcbiAgICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYjY0OiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0I2NCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byB0aGUgY2hhcnQgc2hvdWxkIGJlIHJlY2VpdmVkIGluIEJhc2U2NCBmb3JtYXQgaW5zdGVhZCBvZiBiaW5hcnknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vRG93bmxvYWQ6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfTk9fRE9XTkxPQUQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gaW5jbHVkZSBvciBleGNsdWRlIGF0dGFjaG1lbnQgaGVhZGVycyBpbiB0aGUgcmVzcG9uc2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgd2lkdGg6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfV0lEVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1dpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGVzIGNoYXJ0IHNldHRpbmdzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRXaWR0aDoge1xyXG4gICAgICB2YWx1ZTogNjAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWZhdWx0IHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0U2NhbGU6IHtcclxuICAgICAgdmFsdWU6IDEsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldC4gUmFuZ2VzIGZyb20gMC4xIHRvIDUuMCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBtaW46IDAuMSxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0dMT0JBTF9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCBnbG9iYWwgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9USEVNRV9PUFRJT05TJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0pTT04sIHN0cmluZ2lmaWVkIEpTT04gb3IgZmlsZW5hbWUgd2l0aCB0aGVtZSBvcHRpb25zIGZvciBIaWdoY2hhcnRzLnNldE9wdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaWxsaXNlY29uZHMgdG8gd2FpdCBmb3Igd2VicGFnZSByZW5kZXJpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgY3VzdG9tTG9naWM6IHtcclxuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBbGxvd3Mgb3IgZGlzYWxsb3dzIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBkdXJpbmcgZXhwb3J0aW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBpbmplY3Rpb24gb2YgZmlsZXN5c3RlbSByZXNvdXJjZXMgKGRpc2FibGVkIGluIHNlcnZlciBtb2RlKScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DVVNUT01fQ09ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDdXN0b20gY29kZSB0byBleGVjdXRlIGJlZm9yZSBjaGFydCBpbml0aWFsaXphdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24sIGNvZGUgd3JhcHBlZCBpbiBhIGZ1bmN0aW9uLCBvciBhIC5qcyBmaWxlbmFtZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhbGxiYWNrOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0NBTExCQUNLJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gQ2FuIGJlIGEgZnVuY3Rpb24gb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlcyBhcyBKU09OLCBzdHJpbmdpZmllZCBKU09OLCBvciBmaWxlbmFtZSwgY29udGFpbmluZyBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsb2FkQ29uZmlnOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIHdpdGggYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZUNvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Byb21wdC1iYXNlZCBvcHRpb24gc2V0dGluZywgc2F2ZWQgdG8gYSBwcm92aWRlZCBjb25maWcgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgd2hlbiB0cnVlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hvc3RuYW1lIG9mIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA3ODAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG51bWJlciBmb3IgdGhlIHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdXBsb2FkTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDMsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1VQTE9BRF9MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSByZXF1ZXN0IGJvZHkgc2l6ZSBpbiBNQicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGlzcGxheXMgb3Igbm90IGFjdGlvbiBkdXJhdGlvbnMgaW4gbWlsbGlzZWNvbmRzIGR1cmluZyBzZXJ2ZXIgcmVxdWVzdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdIb3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgb2YgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRpbWVvdXQ6IHtcclxuICAgICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzZXJ2ZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHdpbmRvdzoge1xyXG4gICAgICAgIHZhbHVlOiAxLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGltZSB3aW5kb3cgaW4gbWludXRlcyBmb3IgcmF0ZSBsaW1pdGluZycsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdEZWxheSBkdXJhdGlvbiBiZXR3ZWVuIHN1Y2Nlc3NpdmUgcmVxdWVzdHMgYmVmb3JlIHJlYWNoaW5nIHRoZSBsaW1pdCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBza2lwS2V5OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnS2V5IHRvIGJ5cGFzcyB0aGUgcmF0ZSBsaW1pdGVyLCB1c2VkIHdpdGggYHNraXBUb2tlbmAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcFRva2VuOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUb2tlbiB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwS2V5YCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgU1NMIHByb3RvY29sJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgZm9yY2U6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0ZvcmNlcyB0aGUgc2VydmVyIHRvIHVzZSBIVFRQUyBvbmx5IHdoZW4gdHJ1ZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogNDQzLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgZm9yIHRoZSBTU0wgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbENlcnRQYXRoJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNaW5pbXVtIGFuZCBpbml0aWFsIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG1heFdvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDgsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiBwb29sIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdvcmtMaW1pdDoge1xyXG4gICAgICB2YWx1ZTogNDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdOdW1iZXIgb2YgdGFza3MgYSB3b3JrZXIgY2FuIGhhbmRsZSBiZWZvcmUgcmVzdGFydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3JlYXRlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGlkbGVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAzMDAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGRlc3Ryb3lpbmcgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDIwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYmVmb3JlIHJldHJ5aW5nIHJlc291cmNlIGNyZWF0aW9uIG9uIGZhaWx1cmUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0ludGVydmFsIGluIG1pbGxpc2Vjb25kcyB0byBjaGVjayBhbmQgZGVzdHJveSBpZGxlIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU2hvd3Mgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0xvZ2dpbmcgdmVyYm9zaXR5IGxldmVsJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIHJvdW5kOiAwLFxyXG4gICAgICAgIG1pbjogMCxcclxuICAgICAgICBtYXg6IDVcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdMb2cgZmlsZSBuYW1lLiBSZXF1aXJlcyBgbG9nVG9GaWxlYCBhbmQgYGxvZ0Rlc3RgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Q6IHtcclxuICAgICAgdmFsdWU6ICdsb2cnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgdG8gYmUgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0NPTlNPTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9Db25zb2xlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGNvbnNvbGUgbG9nZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdG9GaWxlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nVG9GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGxvZ2dpbmcgdG8gYSBmaWxlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcm91dGU6IHtcclxuICAgICAgdmFsdWU6ICcvJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdVSV9ST1VURScsXHJcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZW5kcG9pbnQgcm91dGUgZm9yIHRoZSBVSScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgb3RoZXI6IHtcclxuICAgIG5vZGVFbnY6IHtcclxuICAgICAgdmFsdWU6ICdwcm9kdWN0aW9uJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT0RFX0VOVicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIE5vZGUuanMgZW52aXJvbm1lbnQgdHlwZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbm9Mb2dvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGlzcGxheSBvciBza2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHJlc2V0IHRoZSBwYWdlIGNvbnRlbnQgZW50aXJlbHknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBzaGVsbCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19IRUFETEVTUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGV0aGVyIG9yIG5vdCB0byBzZXQgdGhlIGJyb3dzZXIgdG8gcnVuIGluIGhlYWRsZXNzIG1vZGUgZHVyaW5nIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBEZXZUb29scyBpbiBoZWFkZnVsIG1vZGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGxpc3RlblRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgbGlzdGVuaW5nIHRvIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBvciBub3QgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEZWxheXMgUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcclxuICAgICAgdmFsdWU6IDkyMjIsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1BvcnQgdXNlZCBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBQcm9wZXJ0aWVzIG5lc3RpbmcgbGV2ZWwgb2YgYWxsIG9wdGlvbnNcclxuZXhwb3J0IGNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gX2NyZWF0ZUFic29sdXRlUHJvcHMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtwcm9wQ2hhaW49JyddIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXMsXHJcbiAqIHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uLiAgVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgc3RyaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgbWFwcGluZyBhcmd1bWVudCBuYW1lcyB0byB0aGVpciBjb3JyZXNwb25kaW5nXHJcbiAqIG5lc3RlZCBwcm9wZXJ0eSBjaGFpbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHMoY29uZmlnLCBuZXN0ZWRQcm9wcyA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHMgb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBfY3JlYXRlTmVzdGVkUHJvcHMoZW50cnksIG5lc3RlZFByb3BzLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXHJcbiAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmNsaU5hbWUgfHwga2V5XSA9IGAke3Byb3BDaGFpbn0uJHtrZXl9YC5zdWJzdHJpbmcoMSk7XHJcblxyXG4gICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgbmVzdGVkUHJvcHNbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFJldHVybiB0aGUgb2JqZWN0IHdpdGggbmVzdGVkIGFyZ3VtZW50IGNoYWluc1xyXG4gIHJldHVybiBuZXN0ZWRQcm9wcztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGdhdGhlcnMgdGhlIG5hbWVzIG9mIHByb3BlcnRpZXMgZnJvbSBhIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRoYXRcclxuICogY2FuIGJlIHRyZWF0ZWQgYXMgYWJzb2x1dGUgcHJvcGVydGllcy4gVGhlc2UgcHJvcGVydGllcyBoYXZlIHZhbHVlcyB0aGF0XHJcbiAqIGFyZSBvYmplY3RzIGFuZCBkbyBub3QgY29udGFpbiBmdXJ0aGVyIG5lc3RlZCBkZXB0aCB3aGVuIG1lcmdpbmcgYW4gb2JqZWN0XHJcbiAqIGNvbnRhaW5pbmcgdGhlc2Ugb3B0aW9ucy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXkuPHN0cmluZz59IEFuIGFycmF5IGNvbnRhaW5pbmcgdGhlIG5hbWVzIG9mIGFic29sdXRlXHJcbiAqIHByb3BlcnRpZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wcyhjb25maWcsIGFic29sdXRlUHJvcHMgPSBbXSkge1xyXG4gIE9iamVjdC5rZXlzKGNvbmZpZykuZm9yRWFjaCgoa2V5KSA9PiB7XHJcbiAgICAvLyBHZXQgdGhlIHNwZWNpZmljIHNlY3Rpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgc3RpbGwgbW9yZSBkZXB0aCB0byB0cmF2ZXJzZVxyXG4gICAgaWYgKHR5cGVvZiBlbnRyeS50eXBlcyA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgLy8gUmVjdXJzZSBpbnRvIGRlZXBlciBsZXZlbHNcclxuICAgICAgX2NyZWF0ZUFic29sdXRlUHJvcHMoZW50cnksIGFic29sdXRlUHJvcHMpO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgdGhlIG9wdGlvbiBjYW4gYmUgYW4gb2JqZWN0LCBzYXZlIGl0cyB0eXBlIGluIHRoZSBhcnJheVxyXG4gICAgICBpZiAoZW50cnkudHlwZXMuaW5jbHVkZXMoJ09iamVjdCcpKSB7XHJcbiAgICAgICAgYWJzb2x1dGVQcm9wcy5wdXNoKGtleSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBhcnJheSB3aXRoIHRoZSBuYW1lcyBvZiBhYnNvbHV0ZSBwcm9wZXJ0aWVzXHJcbiAgcmV0dXJuIGFic29sdXRlUHJvcHM7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBkZWZhdWx0Q29uZmlnLFxyXG4gIG5lc3RlZFByb3BzLFxyXG4gIGFic29sdXRlUHJvcHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgdGhlIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gR2V0IHNjcmlwdHMgbmFtZXMgb2YgZWFjaCBjYXRlZ29yeSBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPVxyXG4gIGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cztcclxuXHJcbi8vIFNldHMgdGhlIGN1c3RvbSBlcnJvciBtYXAgZ2xvYmFsbHlcclxuei5zZXRFcnJvck1hcChfY3VzdG9tRXJyb3JNYXApO1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBnZW5lcmFsIHZhbGlkYXRvcnMgYW5kIHBhcnNlcnMgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4gKiBpbiBzY2hlbWEgb2JqZWN0cy4gQWxsIHZhbGlkYXRvcnMgYXBwbHkgdG8gdmFsdWVzIGZyb20gdmFyaW91cyBzb3VyY2VzLFxyXG4gKiBpbmNsdWRpbmcgdGhlIGRlZmF1bHQgY29uZmlnIGZpbGUsIGEgY3VzdG9tIEpTT04gZmlsZSBsb2FkZWQgd2l0aCB0aGUgb3B0aW9uXHJcbiAqIGNhbGxlZCBgbG9hZENvbmZpZ2AsIHRoZSAuZW52IGZpbGUsIENMSSBhcmd1bWVudHMsIGFuZCB0aGUgcmVxdWVzdCBwYXlsb2FkLlxyXG4gKiBUaGUgYHN0cmljdENoZWNrYCBmbGFnIGVuYWJsZXMgc3RyaWN0ZXIgdmFsaWRhdGlvbiBhbmQgcGFyc2luZyBydWxlcy4gVGhpc1xyXG4gKiBmbGFnIGlzIHNldCB0byBmYWxzZSBmb3IgdmFsdWVzIHRoYXQgY29tZSBmcm9tIHRoZSAuZW52IGZpbGUgb3IgQ0xJIGFyZ3VtZW50c1xyXG4gKiBiZWNhdXNlIHRoZXkgYXJlIHByb3ZpZGVkIGFzIHN0cmluZ3MgYW5kIG5lZWQgdG8gYmUgcGFyc2VkIGFjY29yZGluZ2x5IGZpcnN0LlxyXG4gKi9cclxuY29uc3QgdiA9IHtcclxuICAvKipcclxuICAgKiBUaGUgYGJvb2xlYW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWVcclxuICAgKiBhbmQgZmFsc2UgYW5kIHRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBkZWZhdWx0IGJvb2xlYW5cclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB2YWx1ZXMgYXJlIHRydWUsXHJcbiAgICogZmFsc2UsIG51bGwsICd0cnVlJywgJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLiBUaGUgc3RyaW5nc1xyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsIHRoZSBzdHJpbmcgJ3RydWUnXHJcbiAgICogd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLCBhbmQgJ2ZhbHNlJyB3aWxsXHJcbiAgICogYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXSlcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IHZhbHVlID09PSAndHJ1ZSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWVgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlYFxyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmVgXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgneycpICYmIHZhbHVlLmVuZHNXaXRoKCd9JykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCcgb3Igc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ30nYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAnLmpzb24nIG9yIHN0YXJ0cyB3aXRoICd7JyBhbmQgZW5kcyB3aXRoICd9J2BcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgICksXHJcbiAgICAgICAgei5vYmplY3Qoe30pLnBhc3N0aHJvdWdoKClcclxuICAgICAgXSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIE9iamVjdCBjb250YWluaW5nIGN1c3RvbSBjb25maWcgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCBjb25maWcgPSB7XHJcbiAgLyoqXHJcbiAgICogVGhlIGBhcmdzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYXJnc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYXJnc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYXJncyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnOycsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdmVyc2lvbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgYXJlIGEgUmVnRXhwLWJhc2VkIHRoYXQgYWxsb3dzIHRvIGJlICdsYXRlc3QnLCBvciBpbiB0aGUgZm9ybWF0IFhYLFxyXG4gICAqIFhYLllZLCBvciBYWC5ZWS5aWiwgd2hlcmUgWFgsIFlZLCBhbmQgWlogYXJlIG51bWVyaWMgZm9yIHRoZSBIaWdoY2hhcnRzXHJcbiAgICogdmVyc2lvbiBvcHRpb24uXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhbHNvIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycgYW5kIGluIGFsbCBjYXNlcyB0aGUgc2NoZW1hIHdpbGwgdHJhbnNmb3JtIHRoZW1cclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHZlcnNpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHZlcnNpb25gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHZlcnNpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZSgodmFsdWUpID0+IC9eKGxhdGVzdHxcXGR7MSwyfShcXC5cXGR7MSwyfSl7MCwyfSkkLy50ZXN0KHZhbHVlKSwge1xyXG4gICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICBcIlRoZSB2YWx1ZSBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaXCJcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY2RuVXJsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0YXJ0c1dpdGhgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjZG5VcmxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNkblVybGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2RuVXJsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdGFydHNXaXRoKFsnaHR0cDovLycsICdodHRwczovLyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBmb3JjZUZldGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBmb3JjZUZldGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBmb3JjZUZldGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBmb3JjZUZldGNoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhY2hlUGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWNoZVBhdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNhY2hlUGF0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FjaGVQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWRtaW5Ub2tlbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhZG1pblRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBhZG1pblRva2VuYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBhZG1pblRva2VuKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY29yZVNjcmlwdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nQXJyYXlgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjb3JlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29yZVNjcmlwdHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmdBcnJheShcclxuICAgICAgKHZhbHVlKSA9PiBjb3JlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtb2R1bGVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbW9kdWxlU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBtb2R1bGVTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gbW9kdWxlU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmRpY2F0b3JTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5kaWNhdG9yU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpbmRpY2F0b3JTY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gaW5kaWNhdG9yU2NyaXB0cy52YWx1ZS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21TY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tU2NyaXB0c1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjdXN0b21TY3JpcHRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJyksXHJcbiAgICAgICcsJyxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbmZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanNvbicgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZ1xyXG4gICAqIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpbmZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5maWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnYFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGluc3RyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5zdHJcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGluc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBpbnN0cigpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBvcHRpb25zYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3B0aW9uc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmNoYXJ0Q29uZmlnKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzdmdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG9iamVjdCB2YWx1ZXNcclxuICAgKiBvciB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjb250YWluICc8c3ZnJyBvciAnPD94bWwnIGVsZW1lbnRzIGFuZCBudWxsLlxyXG4gICAqIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzdmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHN2Z2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIHN2ZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzw/eG1sJykgPj0gMCB8fFxyXG4gICAgICAgICAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgY29udGFpbnMgJzxzdmcnIG9yICc8P3htbCdgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApXHJcbiAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3V0ZmlsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24sIG9yIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGVuZCB3aXRoICcuanBlZycsICcuanBnJywgJy5wbmcnLCAnLnBkZicsIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkXHJcbiAgICogdmFsdWUgaXMgbnVsbCwgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gb3V0ZmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgb3V0ZmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgb3V0ZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpwZWcnKSkgfHxcclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDUgJiZcclxuICAgICAgICAgICAgICAgICh2YWx1ZS5lbmRzV2l0aCgnLmpwZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucG5nJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wZGYnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSkgfHxcclxuICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpwZWcsIC5qcGcsIC5wbmcsIC5wZGYsIG9yIC5zdmdgXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHR5cGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHR5cGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHR5cGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHR5cGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydqcGVnJywgJ2pwZycsICdwbmcnLCAncGRmJywgJ3N2ZyddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjb25zdHJgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNvbnN0clxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY29uc3RyYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb25zdHIoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oXHJcbiAgICAgIFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10sXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYjY0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBiNjRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGI2NGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGI2NChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0Rvd25sb2FkYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0Rvd25sb2FkXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBub0Rvd25sb2FkYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0Rvd25sb2FkKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRIZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0SGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlZmF1bHRIZWlnaHRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0SGVpZ2h0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0V2lkdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0V2lkdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFdpZHRoYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWZhdWx0U2NhbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzIHRoYXRcclxuICAgKiBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHN0cmluZ2lmaWVkIG51bWJlciB2YWx1ZXMgdGhhdCBhcmUgYmV0d2VlbiAwLjEgYW5kIDUgKGluY2x1c2l2ZSksIG51bGwsXHJcbiAgICogJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWZhdWx0U2NhbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdFNjYWxlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6Lm51bWJlcigpLmd0ZSgwLjEpLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlcih2YWx1ZSkgPj0gMC4xICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA8PSA1KSB8fFxyXG4gICAgICAgICAgICAgICAgICBbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgd2l0aGluIGEgMC4xIGFuZCA1LjAgcmFuZ2UnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgICAgICBdKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBoZWlnaHRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIGEgbnVsbGFibGUgYGRlZmF1bHRIZWlnaHRgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhlaWdodFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVpZ2h0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBoZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3aWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFdpZHRoYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgd2lkdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHdpZHRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdFNjYWxlYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc2NhbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNjYWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdGhpcy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBnbG9iYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBhZGRpdGlvbmFsT3B0aW9uc2BcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZ2xvYmFsT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBnbG9iYWxPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZ2xvYmFsT3B0aW9ucygpIHtcclxuICAgIHJldHVybiB2LmFkZGl0aW9uYWxPcHRpb25zKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB0aGVtZU9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB0aGVtZU9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgdGhlbWVPcHRpb25zYCBvcHRpb24uXHJcbiAgICovXHJcbiAgdGhlbWVPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGJhdGNoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGJhdGNoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBiYXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYmF0Y2goc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmFzdGVyaXphdGlvblRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICByYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFsbG93RmlsZVJlc291cmNlc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGFsbG93RmlsZVJlc291cmNlc2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFsbG93RmlsZVJlc291cmNlcyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjdXN0b21Db2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbUNvZGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGN1c3RvbUNvZGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbUNvZGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWxsYmFja2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjYWxsYmFja1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY2FsbGJhY2tgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhbGxiYWNrKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYSBwYXJ0aWFsIG9iamVjdFxyXG4gICAqIHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZSBlYWNoIG9mIHRoZSBhbGxvd2VkXHJcbiAgICogcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5naWZpZWQgdmVyc2lvbiBvZiB0aGUgb2JqZWN0LCBzdHJpbmcgdGhhdCBlbmRzXHJcbiAgICogd2l0aCB0aGUgJy5qc29uJywgYW5kIG51bGwuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHN0cmluZ2lmaWVkIHZlcnNpb25cclxuICAgKiBvZiBhIHBhcnRpYWwgb2JqZWN0IHdpdGggYWxsb3dlZCBwcm9wZXJ0aWVzIGBqc2AsIGBjc3NgLCBhbmQgYGZpbGVzYCB3aGVyZVxyXG4gICAqIGVhY2ggb2YgdGhlIGFsbG93ZWQgcHJvcGVydGllcyBjYW4gYmUgbnVsbCwgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIHRoZVxyXG4gICAqICcuanNvbicsIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzICd1bmRlZmluZWQnLCAnbnVsbCdcclxuICAgKiBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlc291cmNlc2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICBjb25zdCBvYmplY3RTY2hlbWEgPSB6XHJcbiAgICAgIC5vYmplY3Qoe1xyXG4gICAgICAgIGpzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgY3NzOiB2LnN0cmluZyhmYWxzZSksXHJcbiAgICAgICAgZmlsZXM6IHZcclxuICAgICAgICAgIC5zdHJpbmdBcnJheShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICcsJyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKClcclxuICAgICAgfSlcclxuICAgICAgLnBhcnRpYWwoKTtcclxuXHJcbiAgICBjb25zdCBzdHJpbmdTY2hlbWExID0gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCd7JykgJiYgdmFsdWUuZW5kc1dpdGgoJ30nKSkgfHxcclxuICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgc3RhcnRzIHdpdGggJ3snIGFuZCBlbmRzIHdpdGggJ31gXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbidgXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICApO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoudW5pb24oW29iamVjdFNjaGVtYSwgc3RyaW5nU2NoZW1hMV0pLm51bGxhYmxlKClcclxuICAgICAgOiB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTJdKS5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKiBBZGRpdGlvbmFsbHksIGl0IG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2FkQ29uZmlnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2FkQ29uZmlnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNiAmJiB2YWx1ZS5lbmRzV2l0aCgnLmpzb24nKSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uIGBcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5sb2cnYFxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0Rlc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nRGVzdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nRGVzdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nRGVzdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ1RvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9nVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxvZ1RvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ1RvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvRmlsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9nVG9GaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0ZpbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlVWlgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGVuYWJsZVVpXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVVaWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlVWkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdWlSb3V0ZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdWlSb3V0ZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdWlSb3V0ZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdWlSb3V0ZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJy8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9kZUVudmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbm9kZUVudlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9kZUVudmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9kZUVudihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddLCBzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsaXN0ZW5Ub1Byb2Nlc3NFeGl0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Qcm9jZXNzRXhpdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIG9wdGlvbi5cclxuICAgKi9cclxuICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBub0xvZ29gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vTG9nb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbm9Mb2dvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBub0xvZ28oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaGFyZFJlc2V0UGFnZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGFyZFJlc2V0UGFnZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBoYXJkUmVzZXRQYWdlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBicm93c2VyU2hlbGxNb2RlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBicm93c2VyU2hlbGxNb2RlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGJyb3dzZXJTaGVsbE1vZGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBicm93c2VyU2hlbGxNb2RlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIChcclxuICAgICAgelxyXG4gICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgIC8vLyBUTyBETzogQ29ycmVjdFxyXG4gICAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwdXBwZXRlZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFB1cHBldGVlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgYXJnczogY29uZmlnLmFyZ3Moc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIGhpZ2hjaGFydHMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEhpZ2hjaGFydHNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiBjb25maWcuY2RuVXJsKHN0cmljdENoZWNrKSxcclxuICAgICAgZm9yY2VGZXRjaDogY29uZmlnLmZvcmNlRmV0Y2goc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjYWNoZVBhdGg6IGNvbmZpZy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogY29uZmlnLmNvcmVTY3JpcHRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbW9kdWxlU2NyaXB0czogY29uZmlnLm1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbmRpY2F0b3JTY3JpcHRzOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IGNvbmZpZy5jdXN0b21TY3JpcHRzKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBleHBvcnQgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEV4cG9ydFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaW5maWxlOiBjb25maWcuaW5maWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaW5zdHI6IGNvbmZpZy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiBjb25maWcub3B0aW9ucygpLFxyXG4gICAgICBzdmc6IGNvbmZpZy5zdmcoKSxcclxuICAgICAgb3V0ZmlsZTogY29uZmlnLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiBjb25maWcudHlwZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGNvbnN0cjogY29uZmlnLmNvbnN0cihzdHJpY3RDaGVjayksXHJcbiAgICAgIGI2NDogY29uZmlnLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IGNvbmZpZy5ub0Rvd25sb2FkKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVmYXVsdEhlaWdodDogY29uZmlnLmRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0V2lkdGg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IGNvbmZpZy5kZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWlnaHQ6IGNvbmZpZy5oZWlnaHQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aWR0aDogY29uZmlnLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IGNvbmZpZy5zY2FsZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGdsb2JhbE9wdGlvbnM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgICAgIHRoZW1lT3B0aW9uczogY29uZmlnLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogY29uZmlnLmJhdGNoKGZhbHNlKSxcclxuICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IGNvbmZpZy5yYXN0ZXJpemF0aW9uVGltZW91dChzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgY3VzdG9tTG9naWMgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IEN1c3RvbUxvZ2ljU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGNvbmZpZy5hbGxvd0ZpbGVSZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjdXN0b21Db2RlOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgICAgIGNhbGxiYWNrOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IGNvbmZpZy5yZXNvdXJjZXMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsb2FkQ29uZmlnOiBjb25maWcubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgICAgIGNyZWF0ZUNvbmZpZzogY29uZmlnLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogY29uZmlnLnByb3h5SG9zdChmYWxzZSksXHJcbiAgICAgIHBvcnQ6IGNvbmZpZy5wcm94eVBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0aW1lb3V0OiBjb25maWcucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1heFJlcXVlc3RzOiBjb25maWcubWF4UmVxdWVzdHMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3aW5kb3c6IGNvbmZpZy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogY29uZmlnLmRlbGF5KHN0cmljdENoZWNrKSxcclxuICAgICAgdHJ1c3RQcm94eTogY29uZmlnLnRydXN0UHJveHkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBza2lwS2V5OiBjb25maWcuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogY29uZmlnLnNraXBUb2tlbihmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnNzbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU3NsU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTc2woc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmb3JjZTogY29uZmlnLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogY29uZmlnLnNzbFBvcnQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjZXJ0UGF0aDogY29uZmlnLnNzbENlcnRQYXRoKGZhbHNlKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNlcnZlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6Lm9iamVjdCh7XHJcbiAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiBjb25maWcuaG9zdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHBvcnQ6IGNvbmZpZy5wb3J0KHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgYmVuY2htYXJraW5nOiBjb25maWcuc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcHJveHk6IFByb3h5U2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpLFxyXG4gICAgcmF0ZUxpbWl0aW5nOiBSYXRlTGltaXRpbmdTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBzc2w6IFNzbFNjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKVxyXG4gIH0pO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcG9vbCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgUG9vbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbWluV29ya2VyczogY29uZmlnLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiBjb25maWcubWF4V29ya2VycyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdvcmtMaW1pdDogY29uZmlnLndvcmtMaW1pdChzdHJpY3RDaGVjayksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0OiBjb25maWcuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiBjb25maWcuY3JlYXRlVGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0OiBjb25maWcuZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpZGxlVGltZW91dDogY29uZmlnLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogY29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByZWFwZXJJbnRlcnZhbDogY29uZmlnLnJlYXBlckludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgYmVuY2htYXJraW5nOiBjb25maWcucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IGNvbmZpZy5sb2dMZXZlbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZpbGU6IGNvbmZpZy5sb2dGaWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVzdDogY29uZmlnLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IGNvbmZpZy5sb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0ZpbGU6IGNvbmZpZy5sb2dUb0ZpbGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHVpIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBVaVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiBjb25maWcuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogY29uZmlnLnVpUm91dGUoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIG90aGVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBPdGhlclNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbm9kZUVudjogY29uZmlnLm5vZGVFbnYoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czogY29uZmlnLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiBjb25maWcubm9Mb2dvKHN0cmljdENoZWNrKSxcclxuICAgICAgaGFyZFJlc2V0UGFnZTogY29uZmlnLmhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBicm93c2VyU2hlbGxNb2RlOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IGNvbmZpZy5lbmFibGVEZWJ1ZyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhlYWRsZXNzOiBjb25maWcuaGVhZGxlc3Moc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXZ0b29sczogY29uZmlnLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiBjb25maWcubGlzdGVuVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgZHVtcGlvOiBjb25maWcuZHVtcGlvKHN0cmljdENoZWNrKSxcclxuICAgICAgc2xvd01vOiBjb25maWcuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogY29uZmlnLmRlYnVnZ2luZ1BvcnQoc3RyaWN0Q2hlY2spXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vLy9cclxuLy8gLy8gU2NoZW1hIGZvciB0aGUgcGF5bG9hZCBzZWN0aW9uIG9mIG9wdGlvbnNcclxuLy8gY29uc3QgUGF5bG9hZFNjaGVtYSA9ICgpID0+XHJcbi8vICAgelxyXG4vLyAgICAgLm9iamVjdCh7XHJcbi8vICAgICAgIHJlcXVlc3RJZDogY29uZmlnLnJlcXVlc3RJZCgpXHJcbi8vICAgICB9KVxyXG4vLyAgICAgLnBhcnRpYWwoKTtcclxuLy8vL1xyXG5cclxuLy8gU3RyaWN0IHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgU3RyaWN0Q29uZmlnU2NoZW1hID0gei5vYmplY3Qoe1xyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG4gIC8vLy8gcGF5bG9hZDogUGF5bG9hZFNjaGVtYSgpXHJcbn0pO1xyXG5cclxuLy8gTG9vc2Ugc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBMb29zZUNvbmZpZ1NjaGVtYSA9IHoub2JqZWN0KHtcclxuICBwdXBwZXRlZXI6IFB1cHBldGVlclNjaGVtYShmYWxzZSksXHJcbiAgaGlnaGNoYXJ0czogSGlnaGNoYXJ0c1NjaGVtYShmYWxzZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEoZmFsc2UpLFxyXG4gIGN1c3RvbUxvZ2ljOiBDdXN0b21Mb2dpY1NjaGVtYShmYWxzZSksXHJcbiAgc2VydmVyOiBTZXJ2ZXJTY2hlbWEoZmFsc2UpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEoZmFsc2UpLFxyXG4gIGxvZ2dpbmc6IExvZ2dpbmdTY2hlbWEoZmFsc2UpLFxyXG4gIHVpOiBVaVNjaGVtYShmYWxzZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKGZhbHNlKSxcclxuICBkZWJ1ZzogRGVidWdTY2hlbWEoZmFsc2UpXHJcbiAgLy8vLyBwYXlsb2FkOiBQYXlsb2FkU2NoZW1hKClcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IGNvbmZpZy5hcmdzKGZhbHNlKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogY29uZmlnLnZlcnNpb24oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogY29uZmlnLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogY29uZmlnLmZvcmNlRmV0Y2goZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogY29uZmlnLmNhY2hlUGF0aChmYWxzZSksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogY29uZmlnLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiBjb25maWcuY29yZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IGNvbmZpZy5tb2R1bGVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiBjb25maWcuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogY29uZmlnLmN1c3RvbVNjcmlwdHMoZmFsc2UpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfSU5GSUxFOiBjb25maWcuaW5maWxlKGZhbHNlKSxcclxuICBFWFBPUlRfSU5TVFI6IGNvbmZpZy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiBjb25maWcub3B0aW9ucygpLFxyXG4gIEVYUE9SVF9TVkc6IGNvbmZpZy5zdmcoKSxcclxuICBFWFBPUlRfQkFUQ0g6IGNvbmZpZy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IGNvbmZpZy5vdXRmaWxlKGZhbHNlKSxcclxuICBFWFBPUlRfVFlQRTogY29uZmlnLnR5cGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9DT05TVFI6IGNvbmZpZy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IGNvbmZpZy5iNjQoZmFsc2UpLFxyXG4gIEVYUE9SVF9OT19ET1dOTE9BRDogY29uZmlnLm5vRG93bmxvYWQoZmFsc2UpLFxyXG4gIEVYUE9SVF9IRUlHSFQ6IGNvbmZpZy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogY29uZmlnLndpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfU0NBTEU6IGNvbmZpZy5zY2FsZShmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiBjb25maWcuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IGNvbmZpZy5kZWZhdWx0V2lkdGgoZmFsc2UpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiBjb25maWcuZGVmYXVsdFNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfR0xPQkFMX09QVElPTlM6IGNvbmZpZy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IGNvbmZpZy50aGVtZU9wdGlvbnMoKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiBjb25maWcucmFzdGVyaXphdGlvblRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBjdXN0b21cclxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IGNvbmZpZy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogY29uZmlnLmFsbG93RmlsZVJlc291cmNlcyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NVU1RPTV9DT0RFOiBjb25maWcuY3VzdG9tQ29kZShmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NBTExCQUNLOiBjb25maWcuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IGNvbmZpZy5yZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRzogY29uZmlnLmxvYWRDb25maWcoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DUkVBVEVfQ09ORklHOiBjb25maWcuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogY29uZmlnLmVuYWJsZVNlcnZlcihmYWxzZSksXHJcbiAgU0VSVkVSX0hPU1Q6IGNvbmZpZy5ob3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUE9SVDogY29uZmlnLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IGNvbmZpZy51cGxvYWRMaW1pdChmYWxzZSksXHJcbiAgU0VSVkVSX0JFTkNITUFSS0lORzogY29uZmlnLnNlcnZlckJlbmNobWFya2luZyhmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciBwcm94eVxyXG4gIFNFUlZFUl9QUk9YWV9IT1NUOiBjb25maWcucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogY29uZmlnLnByb3h5UG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IGNvbmZpZy5wcm94eVRpbWVvdXQoZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogY29uZmlnLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiBjb25maWcubWF4UmVxdWVzdHMoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogY29uZmlnLndpbmRvdyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IGNvbmZpZy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IGNvbmZpZy50cnVzdFByb3h5KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogY29uZmlnLnNraXBLZXkoZmFsc2UpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IGNvbmZpZy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IGNvbmZpZy5lbmFibGVTc2woZmFsc2UpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IGNvbmZpZy5zc2xGb3JjZShmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9QT1JUOiBjb25maWcuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IGNvbmZpZy5zc2xDZXJ0UGF0aChmYWxzZSksXHJcblxyXG4gIC8vIHBvb2xcclxuICBQT09MX01JTl9XT1JLRVJTOiBjb25maWcubWluV29ya2VycyhmYWxzZSksXHJcbiAgUE9PTF9NQVhfV09SS0VSUzogY29uZmlnLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogY29uZmlnLndvcmtMaW1pdChmYWxzZSksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IGNvbmZpZy5hY3F1aXJlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogY29uZmlnLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiBjb25maWcuZGVzdHJveVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiBjb25maWcuaWRsZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiBjb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IGNvbmZpZy5yZWFwZXJJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9CRU5DSE1BUktJTkc6IGNvbmZpZy5wb29sQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gbG9nZ2luZ1xyXG4gIExPR0dJTkdfTEVWRUw6IGNvbmZpZy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiBjb25maWcubG9nRmlsZShmYWxzZSksXHJcbiAgTE9HR0lOR19ERVNUOiBjb25maWcubG9nRGVzdChmYWxzZSksXHJcbiAgTE9HR0lOR19UT19DT05TT0xFOiBjb25maWcubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IGNvbmZpZy5sb2dUb0ZpbGUoZmFsc2UpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogY29uZmlnLmVuYWJsZVVpKGZhbHNlKSxcclxuICBVSV9ST1VURTogY29uZmlnLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiBjb25maWcubm9kZUVudihmYWxzZSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IGNvbmZpZy5saXN0ZW5Ub1Byb2Nlc3NFeGl0cyhmYWxzZSksXHJcbiAgT1RIRVJfTk9fTE9HTzogY29uZmlnLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiBjb25maWcuaGFyZFJlc2V0UGFnZShmYWxzZSksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiBjb25maWcuYnJvd3NlclNoZWxsTW9kZShmYWxzZSksXHJcblxyXG4gIC8vIGRlYnVnZ2VyXHJcbiAgREVCVUdfRU5BQkxFOiBjb25maWcuZW5hYmxlRGVidWcoZmFsc2UpLFxyXG4gIERFQlVHX0hFQURMRVNTOiBjb25maWcuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiBjb25maWcuZGV2dG9vbHMoZmFsc2UpLFxyXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiBjb25maWcubGlzdGVuVG9Db25zb2xlKGZhbHNlKSxcclxuICBERUJVR19EVU1QSU86IGNvbmZpZy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IGNvbmZpZy5zbG93TW8oZmFsc2UpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiBjb25maWcuZGVidWdnaW5nUG9ydChmYWxzZSlcclxufSk7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgb3B0aW9ucyB1c2luZyB0aGUgRW52U2NoZW1hLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcHJvY2Vzcy5lbnYgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIGZyb20gZW52aXJvbm1lbnRcclxuICogdmFyaWFibGVzIGZpbGUgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZW52cyA9IEVudlNjaGVtYS5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgU3RyaWN0Q29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIFN0cmljdENvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB1c2luZyB0aGUgYExvb3NlQ29uZmlnU2NoZW1hYC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucykge1xyXG4gIHJldHVybiBMb29zZUNvbmZpZ1NjaGVtYS5wYXJ0aWFsKCkucGFyc2UoY29uZmlnT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYSBwcm92aWRlZCBvcHRpb24gdXNpbmcgdGhlIHNwZWNpZmljIHZhbGlkYXRvciBmcm9tIHRoZSBjb25maWdcclxuICogb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IG5hbWUgLSBUaGUgbmFtZSBvZiBhbiBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBvcHRpb24gLSBUaGUgb3B0aW9uIHRvIHZhbGlkYXRlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gKiBiZSBhcHBsaWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb3B0aW9uIHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHZhbGlkYXRlT3B0aW9uKG5hbWUsIG9wdGlvbiwgc3RyaWN0Q2hlY2spIHtcclxuICByZXR1cm4gY29uZmlnW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShvcHRpb24pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3VzdG9tIGVycm9yIG1hcHBpbmcgZnVuY3Rpb24gZm9yIFpvZCBzY2hlbWEgdmFsaWRhdGlvbi5cclxuICpcclxuICogVGhpcyBmdW5jdGlvbiBjdXN0b21pemVzIHRoZSBlcnJvciBtZXNzYWdlcyBwcm9kdWNlZCBieSBab2Qgc2NoZW1hXHJcbiAqIHZhbGlkYXRpb24sIHByb3ZpZGluZyBtb3JlIHNwZWNpZmljIGFuZCB1c2VyLWZyaWVuZGx5IGZlZWRiYWNrIGJhc2VkIG9uIHRoZVxyXG4gKiBpc3N1ZSB0eXBlIGFuZCBjb250ZXh0LlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gbW9kaWZpZXMgdGhlIGVycm9yIG1lc3NhZ2VzIGFzIGZvbGxvd3M6XHJcbiAqXHJcbiAqIC0gRm9yIG1pc3NpbmcgcmVxdWlyZWQgdmFsdWVzICh1bmRlZmluZWQpLCBpdCByZXR1cm5zIGEgbWVzc2FnZSBpbmRpY2F0aW5nXHJcbiAqIHRoYXQgbm8gdmFsdWUgd2FzIHByb3ZpZGVkIGZvciB0aGUgc3BlY2lmaWMgcHJvcGVydHkuXHJcbiAqXHJcbiAqIC0gRm9yIGN1c3RvbSB2YWxpZGF0aW9uIGVycm9ycywgaWYgYSBjdXN0b20gZXJyb3IgbWVzc2FnZSBpcyBwcm92aWRlZCBpbiB0aGVcclxuICogaXNzdWUgcGFyYW1ldGVycywgaXQgaW5jbHVkZXMgdGhpcyBtZXNzYWdlIGFsb25nIHdpdGggdGhlIGludmFsaWQgZGF0YVxyXG4gKiByZWNlaXZlZC5cclxuICpcclxuICogLSBGb3IgYWxsIG90aGVyIGVycm9ycywgaXQgYXBwZW5kcyBwcm9wZXJ0eS1zcGVjaWZpYyBpbmZvcm1hdGlvbiB0byB0aGVcclxuICogZGVmYXVsdCBlcnJvciBtZXNzYWdlIHByb3ZpZGVkIGJ5IFpvZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcFxyXG4gKlxyXG4gKiBAcGFyYW0ge3ouWm9kSXNzdWV9IGlzc3VlIC0gVGhlIGlzc3VlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIHZhbGlkYXRpb25cclxuICogZXJyb3IuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb250ZXh0IC0gVGhlIGNvbnRleHQgb2JqZWN0IHByb3ZpZGluZyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uXHJcbiAqIGFib3V0IHRoZSB2YWxpZGF0aW9uIGVycm9yLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY3VzdG9taXplZCBlcnJvciBtZXNzYWdlLlxyXG4gKi9cclxuZnVuY3Rpb24gX2N1c3RvbUVycm9yTWFwKGlzc3VlLCBjb250ZXh0KSB7XHJcbiAgLy8gR2V0IHRoZSBjaGFpbiBvZiBwcm9wZXJ0aWVzIHdoaWNoIGVycm9yIGRpcmVjdGx5IHJlZmVycyB0b1xyXG4gIGNvbnN0IHByb3BlcnR5TmFtZSA9IGlzc3VlLnBhdGguam9pbignLicpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGZpcnN0IHBhcnQgb2YgdGhlIG1lc3NhZ2UgYWJvdXQgdGhlIHByb3BlcnR5IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgcHJvcGVydHlJbmZvID0gYEludmFsaWQgdmFsdWUgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX1gO1xyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgaW52YWxpZCB0eXBlXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdHlwZSkge1xyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHJlcXVpcmVkIHZhbHVlc1xyXG4gICAgaWYgKGlzc3VlLnJlY2VpdmVkID09PSB6LlpvZFBhcnNlZFR5cGUudW5kZWZpbmVkKSB7XHJcbiAgICAgIHJldHVybiB7XHJcbiAgICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIE5vIHZhbHVlIHdhcyBwcm92aWRlZC5gXHJcbiAgICAgIH07XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIHNwZWNpZmljIGludmFsaWQgdHlwZSB3aGVuIHZhbHVlcyBleGlzdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgbWVzc2FnZTogYCR7cHJvcGVydHlJbmZvfSAtIEludmFsaWQgdHlwZS4gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gICAgfTtcclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBjdXN0b20gdmFsaWRhdGlvblxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5jdXN0b20pIHtcclxuICAgIC8vIElmIHRoZSBjdXN0b20gbWVzc2FnZSBmb3IgZXJyb3IgZXhpc3QsIGluY2x1ZGUgaXRcclxuICAgIGlmIChpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZSkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2lzc3VlLnBhcmFtcz8uZXJyb3JNZXNzYWdlfSwgcmVjZWl2ZWQgJyR7Y29udGV4dC5kYXRhfScuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuaW52YWxpZF91bmlvbikge1xyXG4gICAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBtdWx0aXBsZSBlcnJvcnNcclxuICAgIGxldCBtZXNzYWdlID0gYE11bHRpcGxlIGVycm9ycyBvY2N1cnJlZCBmb3IgdGhlICR7cHJvcGVydHlOYW1lfTpcXG5gO1xyXG5cclxuICAgIC8vIEN5Y2xlIHRocm91Z2ggYWxsIGVycm9ycyBhbmQgY3JlYXRlIGEgY29ycmVjdCBtZXNzYWdlXHJcbiAgICBpc3N1ZS51bmlvbkVycm9ycy5mb3JFYWNoKCh2YWx1ZSkgPT4ge1xyXG4gICAgICBjb25zdCBpbmRleCA9IHZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlLmluZGV4T2YoJy0nKTtcclxuICAgICAgbWVzc2FnZSArPVxyXG4gICAgICAgIGluZGV4ICE9PSAtMVxyXG4gICAgICAgICAgPyBgJHt2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZX1cXG5gLnN1YnN0cmluZyhpbmRleClcclxuICAgICAgICAgIDogYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYDtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIFJldHVybiB0aGUgZmluYWwgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdW5pb24gZXJyb3JcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2VcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSwgZXh0ZW5kZWQgYnkgdGhlIGluZm8gYWJvdXQgdGhlIHByb3BlcnR5XHJcbiAgcmV0dXJuIHtcclxuICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSAke2NvbnRleHQuZGVmYXVsdEVycm9yfS5gXHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHZhbGlkYXRlT3B0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBNYW5hZ2VzIGNvbmZpZ3VyYXRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgYnkgbG9hZGluZ1xyXG4gKiBhbmQgbWVyZ2luZyBvcHRpb25zIGZyb20gbXVsdGlwbGUgc291cmNlcywgc3VjaCBhcyBkZWZhdWx0IHNldHRpbmdzLFxyXG4gKiBlbnZpcm9ubWVudCB2YXJpYWJsZXMsIHVzZXItcHJvdmlkZWQgb3B0aW9ucywgYW5kIGNvbW1hbmQtbGluZSBhcmd1bWVudHMuXHJcbiAqIEVuc3VyZXMgdGhlIGdsb2JhbCBvcHRpb25zIGFyZSB1cC10by1kYXRlIHdpdGggdGhlIGhpZ2hlc3QgcHJpb3JpdHkgdmFsdWVzLlxyXG4gKiBQcm92aWRlcyBmdW5jdGlvbnMgZm9yIGFjY2Vzc2luZyBhbmQgdXBkYXRpbmcgY29uZmlndXJhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgaXNPYmplY3QsIGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgZW52cywgbG9vc2VWYWxpZGF0ZSwgc3RyaWN0VmFsaWRhdGUgfSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnLCBuZXN0ZWRQcm9wcywgYWJzb2x1dGVQcm9wcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRHbG9iYWxPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3RcclxuICogb3IgaXRzIGNvcHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldFJlZmVyZW5jZT10cnVlXSAtIE9wdGlvbmFsIHBhcmFtZXRlciB0byBkZWNpZGUgd2hldGhlclxyXG4gKiB0byByZXR1cm4gdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3RcclxuICogb3IgcmV0dXJuIGEgY29weSBvZiBpdC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdHJ1ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnMgb2YgdGhlIHNlcnZlciBpbnN0YW5jZVxyXG4gKiBvYmplY3Qgb3IgaXRzIGNvcHkuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0T3B0aW9ucyhnZXRSZWZlcmVuY2UgPSB0cnVlKSB7XHJcbiAgcmV0dXJuIGdldFJlZmVyZW5jZSA/IGdsb2JhbE9wdGlvbnMgOiBkZWVwQ29weShnbG9iYWxPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGdsb2JhbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyIGluc3RhbmNlLCBrZWVwaW5nIHRoZSBwcmluY2lwbGVcclxuICogb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eSBmcm9tIGFsbCBhdmFpbGFibGUgc291cmNlcy4gSXQgYWNjZXB0cyBvcHRpb25hbFxyXG4gKiBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0IGFuZCBgY2xpQXJnc2AgYXJyYXkgd2l0aCBhcmd1bWVudHMgZnJvbSB0aGUgQ0xJLiBUaGVzZVxyXG4gKiBvcHRpb25zIHdpbGwgYmUgdmFsaWRhdGVkIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgcHJpb3JpdHkgb3JkZXIgb2Ygc2V0dGluZyB2YWx1ZXMgaXM6XHJcbiAqXHJcbiAqIDEuIE9wdGlvbnMgZnJvbSB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSAoZGVmYXVsdCB2YWx1ZXMpLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gYSBjdXN0b20gSlNPTiBmaWxlIChsb2FkZWQgYnkgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24pLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyAodGhlIGAuZW52YCBmaWxlKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSBmaXJzdCBwYXJhbWV0ZXIgKGJ5IGRlZmF1bHQgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogNS4gT3B0aW9ucyBmcm9tIHRoZSBDTEkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbY3VzdG9tT3B0aW9ucz17fV0gLSBPcHRpb25hbCBjdXN0b20gb3B0aW9ucyBmb3IgYWRkaXRpb25hbFxyXG4gKiBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IFtjbGlBcmdzPVtdXSAtIE9wdGlvbmFsIGNvbW1hbmQgbGluZSBhcmd1bWVudHNcclxuICogZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW21vZGlmeUdsb2JhbD1mYWxzZV0gLSBPcHRpb25hbCBwYXJhbWV0ZXIgdG8gZGVjaWRlXHJcbiAqIHdoZXRoZXIgdG8gdXBkYXRlIGFuZCByZXR1cm4gdGhlIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb2YgdGhlIHNlcnZlciBpbnN0YW5jZSBvYmplY3Qgb3IgcmV0dXJuIGEgY29weSBvZiBpdC4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QsIHJlZmxlY3RpbmcgdGhlIG1lcmdlZFxyXG4gKiBjb25maWd1cmF0aW9uIGZyb20gYWxsIGF2YWlsYWJsZSBzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldE9wdGlvbnMoXHJcbiAgY3VzdG9tT3B0aW9ucyA9IHt9LFxyXG4gIGNsaUFyZ3MgPSBbXSxcclxuICBtb2RpZnlHbG9iYWwgPSBmYWxzZVxyXG4pIHtcclxuICAvLyBPYmplY3QgZm9yIG9wdGlvbnMgbG9hZGVkIHZpYSB0aGUgYGxvYWRDb25maWdgIG9wdGlvblxyXG4gIGxldCBjb25maWdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIE9iamVjdCBmb3Igb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICBsZXQgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MubGVuZ3RoKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBWYWxpZGF0ZSBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGxvYWRlZCB2aWEgdGhlIGBsb2FkQ29uZmlnYFxyXG4gICAgICBjb25maWdPcHRpb25zID0gc3RyaWN0VmFsaWRhdGUoX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW2NvbmZpZ10gQ3VzdG9tIEpTT04gb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQXBwbHkgY3VzdG9tIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmIChjdXN0b21PcHRpb25zICYmIE9iamVjdC5rZXlzKGN1c3RvbU9wdGlvbnMpLmxlbmd0aCAhPT0gMCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVmFsaWRhdGUgY3VzdG9tIG9wdGlvbnMgcHJvdmlkZWQgYnkgdGhlIHVzZXJcclxuICAgICAgY3VzdG9tT3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKGN1c3RvbU9wdGlvbnMpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIEN1c3RvbSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoY2xpQXJncy5sZW5ndGgpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgQ0xJXHJcbiAgICAgIGNsaU9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKF9wYWlyQXJndW1lbnRWYWx1ZShuZXN0ZWRQcm9wcywgY2xpQXJncykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nWm9kSXNzdWVzKDEsIGVycm9yLmlzc3VlcywgJ1tjb25maWddIENMSSBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgcmVmZXJlbmNlIHRvIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYSBjb3B5IG9mIHRoZSBvYmplY3RcclxuICBjb25zdCBnZW5lcmFsT3B0aW9ucyA9IGdldE9wdGlvbnMobW9kaWZ5R2xvYmFsKTtcclxuXHJcbiAgLy8gVXBkYXRlIHZhbHVlcyBvZiB0aGUgZ2VuZXJhbCBvcHRpb25zIHdpdGggdmFsdWVzIGZyb20gZWFjaCBzb3VyY2UgcG9zc2libGVcclxuICBfdXBkYXRlT3B0aW9ucyhcclxuICAgIGRlZmF1bHRDb25maWcsXHJcbiAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgIGNvbmZpZ09wdGlvbnMsXHJcbiAgICBjdXN0b21PcHRpb25zLFxyXG4gICAgY2xpT3B0aW9uc1xyXG4gICk7XHJcblxyXG4gIC8vIFJldHVybiBvcHRpb25zXHJcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cclxuICpcclxuICogQGZ1bmN0aW9uIG1lcmdlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3JpZ2luYWxPcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lcmdlT3B0aW9ucyhvcmlnaW5hbE9wdGlvbnMsIG5ld09wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgYG5ld09wdGlvbnNgIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoaXNPYmplY3QobmV3T3B0aW9ucykpIHtcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICAgIG9yaWdpbmFsT3B0aW9uc1trZXldID1cclxuICAgICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgICAgPyBtZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgcmVzdWx0IG9wdGlvbnNcclxuICByZXR1cm4gb3JpZ2luYWxPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUykgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXIpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nXHJcbiAqIChgbmVzdGVkUHJvcHNgKS4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZSB0aGUgb2xkIGZvcm1hdFxyXG4gKiB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gYG5lc3RlZFByb3BzYCBvciBhbiBlbXB0eSBvYmplY3QgaWYgdGhlIHByb3ZpZGVkXHJcbiAqIGBvbGRPcHRpb25zYCBpcyBub3QgYSBjb3JyZWN0IG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBtYXBUb05ld09wdGlvbnMob2xkT3B0aW9ucykge1xyXG4gIC8vIEFuIG9iamVjdCBmb3IgdGhlIG5ldyBzdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIHZhbHVlIGlzIGEgY29ycmVjdCBvYmplY3RcclxuICBpZiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9sZE9wdGlvbnMpID09PSAnW29iamVjdCBPYmplY3RdJykge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiB0aGUgbmV3LCBzdHJ1Y3R1cmVkIG9wdGlvbnMgb2JqZWN0XHJcbiAgcmV0dXJuIG5ld09wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMsIHBhcnNlcywgYW5kIGNoZWNrcyBpZiB0aGUgcHJvdmlkZWQgY29uZmlnIGlzIGFsbG93ZWQgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc0FsbG93ZWRDb25maWdcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBjb25maWcgLSBUaGUgY29uZmlnIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkIGFzIGEgc2V0XHJcbiAqIG9mIG9wdGlvbnMuIE11c3QgYmUgZWl0aGVyIGFuIG9iamVjdCBvciBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBbdG9TdHJpbmc9ZmFsc2VdIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCB2ZXJzaW9uXHJcbiAqIG9mIHRoZSBwYXJzZWQgY29uZmlnLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBmYWxzZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkLiBPdGhlcndpc2UsIHdoZW5cclxuICogYSBmdW5jdGlvbiBpcyBmb3VuZCwgbnVsbCBpcyByZXR1cm5lZC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gUmV0dXJucyBhIHBhcnNlZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QsXHJcbiAqIGEgc3RyaW5naWZpZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0IGlmIHRoZSBgdG9TdHJpbmdgIGlzIHRydWUsIGFuZCBudWxsXHJcbiAqIGlmIHRoZSBjb25maWcgaXMgbm90IGEgdmFsaWQgc2V0IG9mIG9wdGlvbnMgb3IgcGFyc2luZyBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0FsbG93ZWRDb25maWcoXHJcbiAgY29uZmlnLFxyXG4gIHRvU3RyaW5nID0gZmFsc2UsXHJcbiAgYWxsb3dGdW5jdGlvbnMgPSBmYWxzZVxyXG4pIHtcclxuICB0cnkge1xyXG4gICAgLy8gQWNjZXB0IG9ubHkgb2JqZWN0cyBhbmQgc3RyaW5nc1xyXG4gICAgaWYgKCFpc09iamVjdChjb25maWcpICYmIHR5cGVvZiBjb25maWcgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFJldHVybiBudWxsIGlmIGFueSBvdGhlciB0eXBlXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBvcmlnaW5hbCBjb25maWdcclxuICAgIGNvbnN0IG9iamVjdENvbmZpZyA9XHJcbiAgICAgIHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBldmFsKGAoJHtjb25maWd9KWApXHJcbiAgICAgICAgICA6IEpTT04ucGFyc2UoY29uZmlnKVxyXG4gICAgICAgIDogY29uZmlnO1xyXG5cclxuICAgIC8vIFByZXNlcnZlIG9yIHJlbW92ZSBwb3RlbnRpYWwgZnVuY3Rpb25zIGJhc2VkIG9uIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGZsYWdcclxuICAgIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IF9vcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICBvYmplY3RDb25maWcsXHJcbiAgICAgIGFsbG93RnVuY3Rpb25zLFxyXG4gICAgICBmYWxzZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgY29uZmlnIHRvIGNoZWNrIGlmIGl0IGlzIHZhbGlkIHNldCBvZiBvcHRpb25zXHJcbiAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgPyBKU09OLnBhcnNlKFxyXG4gICAgICAgICAgX29wdGlvbnNTdHJpbmdpZnkob2JqZWN0Q29uZmlnLCBhbGxvd0Z1bmN0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgICAoXywgdmFsdWUpID0+XHJcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKVxyXG4gICAgICAgICAgICAgID8gZXZhbChgKCR7dmFsdWV9KWApXHJcbiAgICAgICAgICAgICAgOiB2YWx1ZVxyXG4gICAgICAgIClcclxuICAgICAgOiBKU09OLnBhcnNlKHN0cmluZ2lmaWVkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHN0cmluZ2lmaWVkIG9yIG9iamVjdCBvcHRpb25zIGJhc2VkIG9uIHRoZSBgdG9TdHJpbmdgIGZsYWdcclxuICAgIHJldHVybiB0b1N0cmluZyA/IHN0cmluZ2lmaWVkT3B0aW9ucyA6IHBhcnNlZE9wdGlvbnM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIFJldHVybiBudWxsIGlmIHBhcnNpbmcgZmFpbHNcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28sIHZlcnNpb24sIGFuZCBsaWNlbnNlIGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcHJpbnRMaWNlbnNlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRMaWNlbnNlKCkge1xyXG4gIC8vIFByaW50IHRoZSBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uXHJcbiAgcHJpbnRWZXJzaW9uKCk7XHJcblxyXG4gIC8vIFByaW50IHRoZSBsaWNlbnNlIGluZm9ybWF0aW9uXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICAnVGhpcyBzb2Z0d2FyZSByZXF1aXJlcyBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBmb3IgY29tbWVyY2lhbCB1c2UuXFxuJ1xyXG4gICAgICAueWVsbG93LFxyXG4gICAgJ1xcbkZvciBhIGZ1bGwgbGlzdCBvZiBDTEkgb3B0aW9ucywgdHlwZTonLFxyXG4gICAgJ1xcbmhpZ2hjaGFydHMtZXhwb3J0LXNlcnZlciAtLWhlbHBcXG4nLmdyZWVuLFxyXG4gICAgJ1xcbklmIHlvdSBkbyBub3QgaGF2ZSBhIGxpY2Vuc2UsIG9uZSBjYW4gYmUgb2J0YWluZWQgaGVyZTonLFxyXG4gICAgJ1xcbmh0dHBzOi8vc2hvcC5oaWdoc29mdC5jb20vXFxuJy5ncmVlbixcclxuICAgICdcXG5UbyBjdXN0b21pemUgeW91ciBpbnN0YWxsYXRpb24sIHBsZWFzZSByZWZlciB0byB0aGUgUkVBRE1FIGZpbGUgYXQ6JyxcclxuICAgICdcXG5odHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lXFxuJy5ncmVlblxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMsIGRpc3BsYXlpbmcgYXZhaWxhYmxlIG9wdGlvbnNcclxuICogYW5kIHRoZWlyIGRlc2NyaXB0aW9ucy4gSXQgY2FuIGxpc3QgcHJvcGVydGllcyByZWN1cnNpdmVseSBpZiBjYXRlZ29yaWVzXHJcbiAqIGNvbnRhaW4gbmVzdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBwcmludFVzYWdlXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcclxuICAvLyBEaXNwbGF5IFJFQURNRSBhbmQgZ2VuZXJhbCB1c2FnZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tJyxcclxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIFJFQURNRSBmaWxlIGF0OiAkeydodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJy5ncmVlbn0uXFxuYFxyXG4gICk7XHJcblxyXG4gIC8vIEl0ZXJhdGUgdGhyb3VnaCBlYWNoIGNhdGVnb3J5IGluIHRoZSBgZGVmYXVsdENvbmZpZ2AgYW5kIGRpc3BsYXkgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICBjb25zb2xlLmxvZyhgJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAuYm9sZC5yZWQpO1xyXG4gICAgX2N5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICBjb25zb2xlLmxvZygnJyk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIG9yIHRleHQgd2l0aCB0aGUgdmVyc2lvblxyXG4gKiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHByaW50VmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtub0xvZ289ZmFsc2VdIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdGV4dCB3aXRoIHRoZSB2ZXJzaW9uXHJcbiAqIGluZm9ybWF0aW9uLCB3aXRob3V0IHRoZSBsb2dvLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBmYWxzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFZlcnNpb24obm9Mb2dvID0gZmFsc2UpIHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGAuZW52YCBvciBmcm9tIGBwYWNrYWdlLmpzb25gXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufWApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBQcmludCB0aGUgbG9nb1xyXG4gICAgY29uc29sZS5sb2coXHJcbiAgICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ21zZycsICdzdGFydHVwLm1zZycpKS50b1N0cmluZygpLmJvbGRcclxuICAgICAgICAueWVsbG93LFxyXG4gICAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCByZXR1cm5zIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZFxyXG4gKiBjb25maWd1cmF0aW9uLCBzZXR0aW5nIHZhbHVlcyBmcm9tIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2luaXRHbG9iYWxPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gX2luaXRHbG9iYWxPcHRpb25zKGNvbmZpZykge1xyXG4gIGNvbnN0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gU3RhcnQgaW5pdGlhbGl6aW5nIHRoZSBgb3B0aW9uc2Agb2JqZWN0IHJlY3Vyc2l2ZWx5XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoY29uZmlnKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBfaW5pdEdsb2JhbE9wdGlvbnMoaXRlbSk7XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcywgZm9sbG93aW5nIGEgc3BlY2lmaWNcclxuICogcHJpb3JpdGl6YXRpb24gb3JkZXIuIFRoZSBmdW5jdGlvbiBjaGVja3MgZm9yIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyXHJcbiAqIG9mIHByZWNlZGVuY2U6IHRoZSBgbG9hZENvbmZpZ2AgY29uZmlndXJhdGlvbiBvcHRpb25zLCBlbnZpcm9ubWVudCB2YXJpYWJsZXMsXHJcbiAqIGN1c3RvbSBvcHRpb25zLCBhbmQgQ0xJIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LCB3aGljaCBpbmNsdWRlcyB0aGUgaW5pdGlhbFxyXG4gKiBzZXR0aW5ncyBhbmQgbWV0YWRhdGEgZm9yIGVhY2ggb3B0aW9uLiBUaGlzIG9iamVjdCBpcyB1c2VkIHRvIGRldGVybWluZVxyXG4gKiB0aGUgc3RydWN0dXJlIGFuZCBkZWZhdWx0IHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRoYXQgd2lsbCBiZSB1cGRhdGVkIHdpdGggdmFsdWVzXHJcbiAqIGZyb20gb3RoZXIgc291cmNlcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdCAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0LCBsb2FkZWQgd2l0aFxyXG4gKiB0aGUgYGxvYWRDb25maWdgIG9wdGlvbiwgd2hpY2ggbWF5IHByb3ZpZGUgdmFsdWVzIHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0IC0gVGhlIGN1c3RvbSBvcHRpb25zIG9iamVjdCwgdHlwaWNhbGx5IGNvbnRhaW5pbmdcclxuICogYWRkaXRpb25hbCBhbmQgdXNlci1kZWZpbmVkIHZhbHVlcywgd2hpY2ggbWF5IG92ZXJyaWRlIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaU9wdCAtIFRoZSBDTEkgb3B0aW9ucyBvYmplY3QsIHdoaWNoIG1heSBpbmNsdWRlIHZhbHVlc1xyXG4gKiBwcm92aWRlZCB0aHJvdWdoIGNvbW1hbmQtbGluZSBhcmd1bWVudHMgYW5kIGhhcyB0aGUgaGlnaGVzdCBwcmVjZWRlbmNlIGFtb25nXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfdXBkYXRlT3B0aW9ucyhjb25maWcsIG9wdGlvbnMsIGNvbmZpZ09wdCwgY3VzdG9tT3B0LCBjbGlPcHQpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBjb25maWcgZW50cnkgb2YgYSBzcGVjaWZpYyBvcHRpb25cclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnW2tleV07XHJcblxyXG4gICAgLy8gR2F0aGVyIHZhbHVlcyBmb3IgdGhlIG9wdGlvbnMgZnJvbSBldmVyeSBwb3NzaWJsZSBzb3VyY2UsIGlmIGV4aXN0c1xyXG4gICAgY29uc3QgY29uZmlnVmFsID0gY29uZmlnT3B0ICYmIGNvbmZpZ09wdFtrZXldO1xyXG4gICAgY29uc3QgY3VzdG9tVmFsID0gY3VzdG9tT3B0ICYmIGN1c3RvbU9wdFtrZXldO1xyXG4gICAgY29uc3QgY2xpVmFsID0gY2xpT3B0ICYmIGNsaU9wdFtrZXldO1xyXG5cclxuICAgIC8vIElmIHRoZSB2YWx1ZSBub3QgZm91bmQsIG5lZWQgdG8gZ28gZGVlcGVyXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICBfdXBkYXRlT3B0aW9ucyhlbnRyeSwgb3B0aW9uc1trZXldLCBjb25maWdWYWwsIGN1c3RvbVZhbCwgY2xpVmFsKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBjdXN0b20gSlNPTiBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjb25maWdWYWwgIT09IHVuZGVmaW5lZCAmJiBjb25maWdWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjb25maWdWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgY29uc3QgZW52VmFsID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZWYWwgIT09IHVuZGVmaW5lZCAmJiBlbnZWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBlbnZWYWw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSB1c2VyIG9wdGlvbnMgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbCAhPT0gdW5kZWZpbmVkICYmIGN1c3RvbVZhbCAhPT0gbnVsbCkge1xyXG4gICAgICAgIG9wdGlvbnNba2V5XSA9IGN1c3RvbVZhbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIENMSSBvcHRpb25zIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjbGlWYWwgIT09IHVuZGVmaW5lZCAmJiBjbGlWYWwgIT09IG51bGwpIHtcclxuICAgICAgICBvcHRpb25zW2tleV0gPSBjbGlWYWw7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZ1xyXG4gKiB3aXRoIHRoZSBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLiBJbiBvcmRlciBmb3IgYSBmdW5jdGlvblxyXG4gKiB0byBiZSBwcmVzZXJ2ZWQsIGl0IG5lZWRzIHRvIGZvbGxvdyB0aGUgZm9ybWF0IGBmdW5jdGlvbiAoLi4uKSB7Li4ufWAuXHJcbiAqIFN1Y2ggYSBmdW5jdGlvbiBjYW4gYWxzbyBiZSBzdHJpbmdpZmllZC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9vcHRpb25zU3RyaW5naWZ5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LiBPdGhlcndpc2UgYW4gZXJyb3IgaXMgdGhyb3duLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmluZ2lmeUZ1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIHRydWUgYXMgd2VsbCBmb3IgdGhpcyB0byB0YWtlXHJcbiAqIGFuIGVmZmVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0Vycm9yfSBUaHJvd3MgYW4gYEVycm9yYCB3aGVuIGZ1bmN0aW9ucyBhcmUgbm90IGFsbG93ZWQgYnV0IGFyZVxyXG4gKiBmb3VuZCBpbiBwcm92aWRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBfb3B0aW9uc1N0cmluZ2lmeShvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucywgc3RyaW5naWZ5RnVuY3Rpb25zKSB7XHJcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChfLCB2YWx1ZSkgPT4ge1xyXG4gICAgLy8gVHJpbSBzdHJpbmcgdmFsdWVzXHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBJZiB2YWx1ZSBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKGFsbG93RnVuY3Rpb25zKSB7XHJcbiAgICAgICAgLy8gQmFzZWQgb24gdGhlIGBzdHJpbmdpZnlGdW5jdGlvbnNgIG9wdGlvbnMsIHNldCBmdW5jdGlvbiB2YWx1ZXNcclxuICAgICAgICByZXR1cm4gc3RyaW5naWZ5RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IC8vIEFzIHN0cmluZ2lmaWVkIGZ1bmN0aW9uc1xyXG4gICAgICAgICAgICBgXCJFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5cImBcclxuICAgICAgICAgIDogLy8gQXMgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxzKy9nLCAnICcpfUVYUF9GVU5gO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRocm93IGFuIGVycm9yIG90aGVyd2lzZVxyXG4gICAgICAgIHRocm93IG5ldyBFcnJvcigpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSW4gYWxsIG90aGVyIGNhc2VzLCBzaW1wbHkgcmV0dXJuIHRoZSB2YWx1ZVxyXG4gICAgcmV0dXJuIHZhbHVlO1xyXG4gIH07XHJcblxyXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xyXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxyXG4gICAgc3RyaW5naWZ5RnVuY3Rpb25zID8gL1xcXFxcIkVYUF9GVU58RVhQX0ZVTlxcXFxcIi9nIDogL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcclxuICAgICcnXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgcHJvdmlkZWQgdmlhXHJcbiAqIHRoZSBgbG9hZENvbmZpZ2Agb3B0aW9uIGluIHRoZSBjb21tYW5kLWxpbmUgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gYW5kIHRoZSBjb3JyZXNwb25kaW5nIGZpbGUgcGF0aC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkXHJcbiAqIGZpbGUsIG9yIGFuIGVtcHR5IG9iamVjdCBpZiB0aGUgZmlsZSBpcyBub3QgZm91bmQsIGludmFsaWQsIG9yIGFuIGVycm9yXHJcbiAqIG9jY3Vycy5cclxuICovXHJcbmZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gd2FzIHVzZWRcclxuICBjb25zdCBjb25maWdJbmRleCA9IGNsaUFyZ3MuZmluZEluZGV4KFxyXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGBsb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYGxvYWRDb25maWdgIGlzIHByZXNlbnQgYW5kIGhhcyBhIGNvcnJlY3QgdmFsdWVcclxuICBpZiAoY29uZmlnRmlsZU5hbWUpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChjb25maWdGaWxlTmFtZSkpKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3BhaXJBcmd1bWVudFZhbHVlXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IG5lc3RlZFByb3BzIC0gQW4gYXJyYXkgb2YgbmVzdGluZyBsZXZlbCBmb3IgYWxsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUobmVzdGVkUHJvcHMsIGNsaUFyZ3MpIHtcclxuICAvLyBBbiBlbXB0eSBvYmplY3QgdG8gY29sbGVjdCBhbmQgc3RydWN0dXJpemUgZGF0YSBmcm9tIHRoZSBhcmdzXHJcbiAgY29uc3QgY2xpT3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBDTEkgYXJncyBhbmQgZmlsdGVyIHRoZW1cclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGNsaUFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGNsaUFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRQcm9wc1tvcHRpb25dLnNwbGl0KCcuJylcclxuICAgICAgOiBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBDTEkgZm9yIGxhdGVyIHBhcnNpbmcgYW5kIG1lcmdpbmdcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGNvbnN0IHZhbHVlID0gY2xpQXJnc1srK2ldO1xyXG4gICAgICAgIGlmICghdmFsdWUpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSBDTEkgJy0tJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgb2JqW3Byb3BdID0gdmFsdWUgfHwgbnVsbDtcclxuICAgICAgfSBlbHNlIGlmIChvYmpbcHJvcF0gPT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG9ialtwcm9wXSA9IHt9O1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBjbGlPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBwYXJzZWQgQ0xJIG9wdGlvbnNcclxuICByZXR1cm4gY2xpT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IHRyYXZlcnNlcyB0aGUgb3B0aW9ucyBvYmplY3QgdG8gcHJpbnQgdGhlIHVzYWdlIGluZm9ybWF0aW9uXHJcbiAqIGZvciBlYWNoIG9wdGlvbiBjYXRlZ29yeSBhbmQgaW5kaXZpZHVhbCBvcHRpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgQ0xJIG9wdGlvbnMuXHJcbiAqIEl0IG1heSBpbmNsdWRlIG5lc3RlZCBjYXRlZ29yaWVzIGFuZCBpbmRpdmlkdWFsIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY3ljbGVDYXRlZ29yaWVzKG9wdGlvbnMpIHtcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VycmVudCBlbnRyeSBpcyBhIGNhdGVnb3J5IGFuZCBub3QgYSBsZWFmIG9wdGlvbiwgcmVjdXJzZSBpbnRvIGl0XHJcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgIF9jeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIFByZXBhcmUgZGVzY3JpcHRpb25cclxuICAgICAgY29uc3QgZGVzY05hbWUgPSBgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfWA7XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHZhbHVlXHJcbiAgICAgIGxldCBvcHRpb25WYWx1ZSA9IG9wdGlvbi52YWx1ZTtcclxuXHJcbiAgICAgIC8vIFByZXBhcmUgdmFsdWUgZm9yIG9wdGlvbiB0aGF0IGlzIG5vdCBudWxsIGFuZCBpcyBhcnJheSBvZiBzdHJpbmdzXHJcbiAgICAgIGlmIChvcHRpb25WYWx1ZSAhPT0gbnVsbCAmJiBvcHRpb24udHlwZXMuaW5jbHVkZXMoJ3N0cmluZ1tdJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9XHJcbiAgICAgICAgICAnWycgKyBvcHRpb25WYWx1ZS5tYXAoKGl0ZW0pID0+IGAnJHtpdGVtfSdgKS5qb2luKCcsICcpICsgJ10nO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBQcmVwYXJlIHZhbHVlIGZvciBvcHRpb24gdGhhdCBpcyBub3QgbnVsbCBhbmQgaXMgYSBzdHJpbmdcclxuICAgICAgaWYgKG9wdGlvblZhbHVlICE9PSBudWxsICYmIG9wdGlvbi50eXBlcy5pbmNsdWRlcygnc3RyaW5nJykpIHtcclxuICAgICAgICBvcHRpb25WYWx1ZSA9IGAnJHtvcHRpb25WYWx1ZX0nYDtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xyXG4gICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICBkZXNjTmFtZS5ncmVlbixcclxuICAgICAgICBgJHsoJzwnICsgb3B0aW9uLnR5cGVzLmpvaW4oJ3wnKSArICc+JykueWVsbG93fWAsXHJcbiAgICAgICAgYCR7U3RyaW5nKG9wdGlvblZhbHVlKS5ib2xkfWAuYmx1ZSxcclxuICAgICAgICBgLSAke29wdGlvbi5kZXNjcmlwdGlvbn0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIGlzQWxsb3dlZENvbmZpZyxcclxuICBwcmludExpY2Vuc2UsXHJcbiAgcHJpbnRVc2FnZSxcclxuICBwcmludFZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IEhUVFAgdXRpbGl0eSBtb2R1bGUgZm9yIGZldGNoaW5nIGFuZCBwb3N0aW5nIGRhdGEuIFN1cHBvcnRzIGJvdGhcclxuICogSFRUUCBhbmQgSFRUUFMgcHJvdG9jb2xzLCBwcm92aWRpbmcgbWV0aG9kcyB0byBtYWtlIEdFVCBhbmQgUE9TVCByZXF1ZXN0c1xyXG4gKiB3aXRoIGN1c3RvbWl6YWJsZSBvcHRpb25zLiBJbmNsdWRlcyBwcm90b2NvbCBkZXRlcm1pbmF0aW9uIGJhc2VkIG9uIFVSTFxyXG4gKiBhbmQgYXVnbWVudHMgcmVzcG9uc2Ugb2JqZWN0cyB3aXRoIGEgJ3RleHQnIHByb3BlcnR5IGZvciBlYXNpZXIgZGF0YSBhY2Nlc3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZmV0Y2hcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXNwb25zZS50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0pXHJcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICB9KTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xyXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IFtib2R5PXt9XSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0LlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlc3BvbnNlLnRleHQgPSByZXNwb25zZURhdGE7XHJcbiAgICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC53cml0ZShkYXRhKTtcclxuICAgIHJlcXVlc3QuZW5kKCk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2dldFByb3RvY29sTW9kdWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZmV0Y2gsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBBIGN1c3RvbSBlcnJvciBjbGFzcyBmb3IgaGFuZGxpbmcgZXhwb3J0LXJlbGF0ZWQgZXJyb3JzLiBFeHRlbmRzIHRoZSBuYXRpdmVcclxuICogYEVycm9yYCBjbGFzcyB0byBpbmNsdWRlIGFkZGl0aW9uYWwgcHJvcGVydGllcyBsaWtlIHN0YXR1cyBjb2RlIGFuZCBzdGFja1xyXG4gKiB0cmFjZSBkZXRhaWxzLlxyXG4gKi9cclxuY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gT3B0aW9uYWwgSFRUUCBzdGF0dXMgY29kZSBhc3NvY2lhdGVkXHJcbiAgICogd2l0aCB0aGUgZXJyb3IgKGUuZy4sIDQwMCwgNTAwKS5cclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXNDb2RlKSB7XHJcbiAgICBzdXBlcigpO1xyXG5cclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcblxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG5cclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBpbml0aWFsIGNhY2hlIHRlbXBsYXRlXHJcbmNvbnN0IGNhY2hlID0ge1xyXG4gIGNkblVybDogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxyXG4gKiBhbmQgbG9hZHMgdGhlIHNvdXJjZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2hlY2tBbmRVcGRhdGVDYWNoZShcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnNcclxuKSB7XHJcbiAgbGV0IGZldGNoZWRNb2R1bGVzO1xyXG5cclxuICAvLyBHZXQgdGhlIGNhY2hlIHBhdGhcclxuICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSBjYWNoZSBmb2xkZXJcclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcclxuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XHJcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcclxuXHJcbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgLy8gb3IgaWYgdGhlIGBmb3JjZUZldGNoYCBvcHRpb24gaXMgZW5hYmxlZFxyXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHNPcHRpb25zLmZvcmNlRmV0Y2gpIHtcclxuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICBzb3VyY2VQYXRoXHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXHJcbiAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xyXG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gR2V0IHRoZSBhY3R1YWwgbnVtYmVyIG9mIHNjcmlwdHMgdG8gYmUgZmV0Y2hlZFxyXG4gICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID0gaGlnaGNoYXJ0c09wdGlvbnM7XHJcbiAgICBjb25zdCBudW1iZXJPZk1vZHVsZXMgPVxyXG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgIC8vIENvbXBhcmUgdGhlIGxvYWRlZCBoaWdoY2hhcnRzIGNvbmZpZyB3aXRoIHRoZSBjb250ZW50cyBpbiBjYWNoZS5cclxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXHJcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgaWYgKG1hbmlmZXN0LnZlcnNpb24gIT09IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBVcGRhdGUgY2FjaGUgaWYgbmVlZGVkXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcclxuXHJcbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcclxuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcclxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xyXG5cclxuICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjYWNoZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEhpZ2hjaGFydHNWZXJzaW9uKCkge1xyXG4gIHJldHVybiBjYWNoZS5oY1ZlcnNpb247XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gaW4gdGhlIGFwcGxpZWQgY29uZmlndXJhdGlvbiBhbmQgY2hlY2tzXHJcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbihuZXdWZXJzaW9uKSB7XHJcbiAgLy8gR2V0IHRoZSByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zIHRvIHVwZGF0ZSB0byB0aGUgbmV3IHZlcnNpb25cclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgb3B0aW9ucy5oaWdoY2hhcnRzLnZlcnNpb24gPSBuZXdWZXJzaW9uO1xyXG5cclxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXHJcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zLmhpZ2hjaGFydHMsIG9wdGlvbnMuc2VydmVyLnByb3h5KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBjYWNoZSdzIHNvdXJjZXMgc3RyaW5nLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdFZlcnNpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNhY2hlU291cmNlcyAtIFRoZSBjYWNoZSBzb3VyY2VzIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZXh0cmFjdFZlcnNpb24oY2FjaGVTb3VyY2VzKSB7XHJcbiAgcmV0dXJuIGNhY2hlU291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZVNvdXJjZXMuaW5kZXhPZignKi8nKSlcclxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxyXG4gICAgLnJlcGxhY2UoJyovJywgJycpXHJcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxyXG4gICAgLnRyaW0oKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXh0cmFjdE1vZHVsZU5hbWVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdFBhdGggLSBUaGUgcGF0aCBvZiB0aGUgc2NyaXB0IGZyb20gd2hpY2ggdGhlIG1vZHVsZVxyXG4gKiBuYW1lIHdpbGwgYmUgZXh0cmFjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIG1vZHVsZSBuYW1lLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdFBhdGgpIHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgY2FjaGUgb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0Q2FjaGVcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGNhY2hlIG9iamVjdCBjb250YWluaW5nIHZhcmlvdXMgY2FjaGVkIGRhdGEuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0Q2FjaGUoKSB7XHJcbiAgcmV0dXJuIGNhY2hlO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0cyB0aGUgY2FjaGUgcGF0aCBmb3IgSGlnaGNoYXJ0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlUGF0aFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgYWJzb2x1dGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5IGZvciBIaWdoY2hhcnRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlUGF0aCgpIHtcclxuICByZXR1cm4gZ2V0QWJzb2x1dGVQYXRoKGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBgZmV0Y2hlZE1vZHVsZXNgIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxyXG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3Nob3VsZFRocm93RXJyb3I9ZmFsc2VdIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvclxyXG4gKiBzaG91bGQgYmUgdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuIFRoZSBkZWZhdWx0XHJcbiAqIHZhbHVlIGlzIGZhbHNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW1cclxuICogd2l0aCBmZXRjaGluZyB0aGUgc2NyaXB0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIC8vIEJhc2VkIG9uIHRoZSBgc2hvdWxkVGhyb3dFcnJvcmAgZmxhZywgZGVjaWRlIGhvdyB0byBzZXJ2ZSBlcnJvciBtZXNzYWdlXHJcbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmAsXHJcbiAgICAgIDQwNFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2ZldGNoZWRNb2R1bGVzPXt9XSAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eSBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGVcclxuICogd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMsIGZldGNoZWRNb2R1bGVzID0ge30pIHtcclxuICBjb25zdCBuZXdNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb246IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIGBzY3JpcHRzYCBhbmQgYGN1c3RvbVNjcmlwdHNgIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0c1xyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjb3JlU2NyaXB0cyAtIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBtb2R1bGVTY3JpcHRzIC0gSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBjdXN0b21TY3JpcHRzIC0gQ3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaCAoZnVsbFxyXG4gKiBVUkxzKS5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZmV0Y2hlZCBzY3JpcHRzXHJcbiAqIGNvbnRlbnQgam9pbmVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlXHJcbiAqIHNldHRpbmcgYW4gSFRUUCBBZ2VudCBmb3IgcHJveHkuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZmV0Y2hTY3JpcHRzKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHByb3h5SG9zdCA9IHNlcnZlclByb3h5T3B0aW9ucy5ob3N0O1xyXG4gIGNvbnN0IHByb3h5UG9ydCA9IHNlcnZlclByb3h5T3B0aW9ucy5wb3J0O1xyXG5cclxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcclxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xyXG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcclxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcclxuICAgICAgfSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1tjYWNoZV0gQ291bGQgbm90IGNyZWF0ZSBhIFByb3h5IEFnZW50LicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXHJcbiAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBwcm94eUFnZW50XHJcbiAgICA/IHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIF9mZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcclxuICAgICksXHJcbiAgICAuLi5tb2R1bGVTY3JpcHRzLm1hcCgoc2NyaXB0KSA9PlxyXG4gICAgICBfZmV0Y2hBbmRQcm9jZXNzU2NyaXB0KGAke3NjcmlwdH1gLCByZXF1ZXN0T3B0aW9ucywgZmV0Y2hlZE1vZHVsZXMpXHJcbiAgICApLFxyXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cclxuICAgICAgX2ZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgbG9jYWwgY2FjaGUgd2l0aCBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIHRoZWlyIHZlcnNpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF91cGRhdGVDYWNoZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaGlnaGNoYXJ0c09wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgaGlnaGNoYXJ0c2Agb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGBzZXJ2ZXIucHJveHlgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xyXG4gKiB0aGUgZmV0Y2hlZCBtb2R1bGVzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcclxuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucywgc291cmNlUGF0aCkge1xyXG4gIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICBjb25zdCBoY1ZlcnNpb24gPVxyXG4gICAgaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiA9PT0gJ2xhdGVzdCdcclxuICAgICAgPyBudWxsXHJcbiAgICAgIDogYCR7aGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbn1gO1xyXG5cclxuICAvLyBHZXQgdGhlIENETiB1cmwgZm9yIHNjcmlwdHNcclxuICBjb25zdCBjZG5VcmwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VcmwgfHwgY2FjaGUuY2RuVXJsO1xyXG5cclxuICB0cnkge1xyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcclxuICAgICk7XHJcblxyXG4gICAgY2FjaGUuc291cmNlcyA9IGF3YWl0IF9mZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+XHJcbiAgICAgICAgICBoY1ZlcnNpb24gPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS8ke2N9YCA6IGAke2NkblVybH0vJHtjfWBcclxuICAgICAgICApXHJcbiAgICAgIF0sXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5tb2R1bGVTY3JpcHRzLm1hcCgobSkgPT5cclxuICAgICAgICAgIG0gPT09ICdtYXAnXHJcbiAgICAgICAgICAgID8gaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9L21hcHMvJHtoY1ZlcnNpb259L21vZHVsZXMvJHttfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vbWFwcy9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogaGNWZXJzaW9uXHJcbiAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKChpKSA9PlxyXG4gICAgICAgICAgaGNWZXJzaW9uXHJcbiAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2l9YFxyXG4gICAgICAgIClcclxuICAgICAgXSxcclxuICAgICAgaGlnaGNoYXJ0c09wdGlvbnMuY3VzdG9tU2NyaXB0cyxcclxuICAgICAgc2VydmVyUHJveHlPcHRpb25zLFxyXG4gICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFeHRyYWN0IGFuZCBzYXZlIHZlcnNpb24gb2YgY3VycmVudGx5IHVzZWQgSGlnaGNoYXJ0c1xyXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxyXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRIaWdoY2hhcnRzVmVyc2lvbixcclxuICB1cGRhdGVIaWdoY2hhcnRzVmVyc2lvbixcclxuICBleHRyYWN0VmVyc2lvbixcclxuICBleHRyYWN0TW9kdWxlTmFtZSxcclxuICBnZXRDYWNoZSxcclxuICBnZXRDYWNoZVBhdGhcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFByb3ZpZGVzIG1ldGhvZHMgZm9yIGluaXRpYWxpemluZyBIaWdoY2hhcnRzIHdpdGggY3VzdG9taXplZFxyXG4gKiBhbmltYXRpb24gc2V0dGluZ3MgYW5kIHRyaWdnZXJpbmcgdGhlIGNyZWF0aW9uIG9mIEhpZ2hjaGFydHMgY2hhcnRzIHdpdGhcclxuICogZXhwb3J0LXNwZWNpZmljIGNvbmZpZ3VyYXRpb25zIGluIHRoZSBwYWdlIGNvbnRleHQuIFN1cHBvcnRzIGR5bmFtaWMgb3B0aW9uXHJcbiAqIG1lcmdpbmcsIGN1c3RvbSBsb2dpYyBpbmplY3Rpb24sIGFuZCBjb250cm9sIG92ZXIgcmVuZGVyaW5nIGJlaGF2aW9ycy4gVXNlZFxyXG4gKiBieSB0aGUgUHVwcGV0ZWVyIHBhZ2UuXHJcbiAqL1xyXG5cclxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cclxuXHJcbi8qKlxyXG4gKiBTZXR0aW5nIHRoZSBgSGlnaGNoYXJ0cy5hbmltT2JqZWN0YCBmdW5jdGlvbi4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0c1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcclxuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XHJcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xyXG4gIH07XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgSGlnaGNoYXJ0cyBjaGFydCBvbiBhIHBhZ2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY3JlYXRlQ2hhcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUNoYXJ0KG9wdGlvbnMpIHtcclxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXHJcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBtZXJnZSwgc2V0T3B0aW9ucywgd3JhcCB9ID0gSGlnaGNoYXJ0cztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBgc2V0T3B0aW9uc2AgdXNhZ2VzIGluIG9yZGVyXHJcbiAgLy8gdG8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBvcHRpb25zLmV4cG9ydC5oZWlnaHQsXHJcbiAgICAgIHdpZHRoOiBvcHRpb25zLmV4cG9ydC53aWR0aFxyXG4gICAgfSxcclxuICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAvLyBObyBuZWVkIGZvciB0aGUgZXhwb3J0aW5nIGJ1dHRvblxyXG4gICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgfVxyXG4gIH07XHJcblxyXG4gIC8vIEdldCB0aGUgaW5wdXQgdG8gZXhwb3J0IGZyb20gdGhlIGBpbnN0cmAgb3B0aW9uXHJcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuZXhwb3J0Lmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnN9YCkoKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgZ2xvYmFsT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IG5ldyBGdW5jdGlvbihcclxuICAgIGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zfWBcclxuICApKCk7XHJcblxyXG4gIC8vIE1lcmdlIHRoZSBmb2xsb3dpbmcgb3B0aW9ucyBvYmplY3RzIHRvIGNyZWF0ZSBmaW5hbCBvcHRpb25zXHJcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXHJcbiAgICBmYWxzZSxcclxuICAgIHRoZW1lT3B0aW9ucyxcclxuICAgIHVzZXJPcHRpb25zLFxyXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xyXG4gICAgYWRkaXRpb25hbE9wdGlvbnNcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IG51bGw7XHJcblxyXG4gIC8vIFRyaWdnZXIgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24oJ29wdGlvbnMnLCBvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGNoYXJ0IGNyZWF0aW9uXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBgc2V0T3B0aW9uc2Agd2FzIHVzZWQgaW4gdGhlIGBjdXN0b21Db2RlYClcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNldHVwSGlnaGNoYXJ0cyxcclxuICBjcmVhdGVDaGFydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSwgY3JlYXRpbmcgYW5kIGNsZWFyaW5nIHBhZ2VzLCBpbmplY3RpbmcgY3VzdG9tIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCByZXNvdXJjZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzIGR1cmluZ1xyXG4gKiBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCB0ZW1wbGF0ZSA9IHJlYWRGaWxlU3luYyhcclxuICBqb2luKF9fZGlybmFtZSwgJ3RlbXBsYXRlcycsICd0ZW1wbGF0ZS5odG1sJyksXHJcbiAgJ3V0ZjgnXHJcbik7XHJcblxyXG4vLyBUbyBzYXZlIHRoZSBicm93c2VyXHJcbmxldCBicm93c2VyID0gbnVsbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QnJvd3NlclxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QnJvd3NlcigpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nLCA1MDApO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXJcclxuICpcclxuICogQHBhcmFtIHtBcnJheS48c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgY3JlYXRlZCBQdXBwZXRlZXJcclxuICogYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIG1heCByZXRyaWVzIHRvIG9wZW5cclxuICogYSBicm93c2VyIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyXHJcbiAqIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IGBkZWJ1Z2AgYW5kIGBvdGhlcmAgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWdPcHRpb25zIH0gPSBkZWJ1ZztcclxuXHJcbiAgLy8gTGF1bmNoIG9wdGlvbnMgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcclxuICAgIGhlYWRsZXNzOiBvdGhlci5icm93c2VyU2hlbGxNb2RlID8gJ3NoZWxsJyA6IHRydWUsXHJcbiAgICB1c2VyRGF0YURpcjogJ3RtcCcsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzIHx8IFtdLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAvLyBBIGNvdW50ZXIgZm9yIHRoZSBicm93c2VyJ3MgbGF1bmNoIHJldHJpZXNcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nLCA1MDApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBpbnN0YW5jZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xvc2VCcm93c2VyXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2VCcm93c2VyKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubmVjdGVkXHJcbiAgaWYgKGJyb3dzZXIgJiYgYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgYnJvd3NlciA9IG51bGw7XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgcGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHRoZSBgX3NldFBhZ2VDb250ZW50KClgLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBuZXdQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIGBpZGAsXHJcbiAqIGB3b3JrQ291bnRgLCBhbmQgYHBhZ2VgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjb25uZWN0ZWQgb3IgaWYgYSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UocG9vbFJlc291cmNlKSB7XHJcbiAgLy8gRXJyb3IgaW4gY2FzZSBvZiBubyBjb25uZWN0ZWQgYnJvd3NlclxyXG4gIGlmICghYnJvd3NlciB8fCAhYnJvd3Nlci5jb25uZWN0ZWQpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW2Jyb3dzZXJdIEJyb3dzZXIgaXMgbm90IHlldCBjb25uZWN0ZWQuYCwgNTAwKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBwb29sUmVzb3VyY2UucGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xyXG5cclxuICAvLyBEaXNhYmxlIGNhY2hlXHJcbiAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuXHJcbiAgLy8gU2V0IHBhZ2UgZXZlbnRzXHJcbiAgX3NldFBhZ2VFdmVudHMocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgcGFnZSBpcyBjb3JyZWN0bHkgY3JlYXRlZFxyXG4gIGlmICghcG9vbFJlc291cmNlLnBhZ2UgfHwgcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuIExvZ3NcclxuICogdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIG9mIGEgcGFnZSdzIGNvbnRlbnQgZmFpbHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRhaW5zIHBhZ2UgYW5kIGlkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtoYXJkUmVzZXQ9ZmFsc2VdIC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gYGFib3V0OmJsYW5rYCBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgZmFsc2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIHdoZW4gcGFnZVxyXG4gKiBpcyBjb3JyZWN0bHkgY2xlYXJlZCBhbmQgZmFsc2Ugd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBjdXN0b21Mb2dpY2BcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXkuPE9iamVjdD4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBhcnJheVxyXG4gKiBvZiBpbmplY3RlZCByZXNvdXJjZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcztcclxuICBpZiAocmVzb3VyY2VzKSB7XHJcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XHJcblxyXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxyXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xyXG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXHJcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcclxuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcclxuXHJcbiAgICAvLyBMb2FkIENTU1xyXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcclxuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XHJcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBqb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBgYWRkU2NyaXB0VGFnYCBhbmQgYGFkZFN0eWxlVGFnYC5cclxuICogUmVtb3ZlcyBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLlxyXG4gKiBBZGRpdGlvbmFsbHksIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxyXG4gKiBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIHdoZW4gZG9pbmcgU1ZHIGV4cG9ydHNcclxuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xyXG5cclxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcclxuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xyXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcclxuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcclxuXHJcbiAgICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXHJcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcclxuICAgICAgXSkge1xyXG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcclxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRQYWdlQ29udGVudChwYWdlKSB7XHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIHBhZ2UgY29udGVudFxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcclxuXHJcbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcclxuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGpvaW4oZ2V0Q2FjaGVQYXRoKCksICdzb3VyY2VzLmpzJykgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBgYW5pbU9iamVjdGAgZm9yIEhpZ2hjaGFydHNcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgZXZlbnRzIChsaWtlIGBwYWdlZXJyb3JgIGFuZCBgY29uc29sZWApIGZvciBhIFB1cHBldGVlciBQYWdlIGluIG9yZGVyXHJcbiAqIHRvIGNhdGNoIGFuZCBkaXNwbGF5IGVycm9ycyBhbmQgY29uc29sZSBsb2dzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VFdmVudHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHRoZSBsaXN0ZW5lcnNcclxuICogYXJlIGJlaW5nIHNldC5cclxuICovXHJcbmZ1bmN0aW9uIF9zZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgYGRlYnVnYCBvcHRpb25zXHJcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBwYWdlZXJyb3JgIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKCkgPT4ge1xyXG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxyXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cclxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBTZXQgdGhlIGBjb25zb2xlYCBsaXN0ZW5lciwgaWYgbmVlZGVkXHJcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcclxuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xyXG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0QnJvd3NlcixcclxuICBjcmVhdGVCcm93c2VyLFxyXG4gIGNsb3NlQnJvd3NlcixcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBUaGUgQ1NTIHRvIGJlIHVzZWQgb24gdGhlIGV4cG9ydGVkIHBhZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBDU1MgY29uZmlndXJhdGlvbi5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0ICgpID0+IGBcclxuXHJcbmh0bWwsIGJvZHkge1xyXG4gIG1hcmdpbjogMDtcclxuICBwYWRkaW5nOiAwO1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbn1cclxuXHJcbiN0YWJsZS1kaXYsICNzbGlkZXJzLCAjZGF0YXRhYmxlLCAjY29udHJvbHMsIC5sZC1yb3cge1xyXG4gIGRpc3BsYXk6IG5vbmU7XHJcbiAgaGVpZ2h0OiAwO1xyXG59XHJcblxyXG4jY2hhcnQtY29udGFpbmVyIHtcclxuICBib3gtc2l6aW5nOiBib3JkZXItYm94O1xyXG4gIG1hcmdpbjogMDtcclxuICBvdmVyZmxvdzogYXV0bztcclxuICBmb250LXNpemU6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIgPiBmaWd1cmUsIGRpdiB7XHJcbiAgbWFyZ2luLXRvcDogMCAhaW1wb3J0YW50O1xyXG4gIG1hcmdpbi1ib3R0b206IDAgIWltcG9ydGFudDtcclxufVxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xyXG5cclxuLyoqXHJcbiAqIFRoZSBTVkcgdGVtcGxhdGUgdG8gdXNlIHdoZW4gbG9hZGluZyBTVkcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIFNWRyB0ZW1wbGF0ZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChzdmcpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtzdmd9XHJcbiAgICA8L2Rpdj5cclxuICA8L2JvZHk+XHJcbjwvaHRtbD5cclxuXHJcbmA7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBoYW5kbGVzIGNoYXJ0IGV4cG9ydCBmdW5jdGlvbmFsaXR5IHVzaW5nIFB1cHBldGVlci5cclxuICogSXQgc3VwcG9ydHMgZXhwb3J0aW5nIGNoYXJ0cyBhcyBTVkcsIFBORywgSlBFRywgYW5kIFBERiBmb3JtYXRzLiBUaGUgbW9kdWxlXHJcbiAqIG1hbmFnZXMgcGFnZSByZXNvdXJjZXMsIHNldHMgdXAgdGhlIGV4cG9ydCBlbnZpcm9ubWVudCwgYW5kIHByb2Nlc3NlcyBjaGFydFxyXG4gKiBjb25maWd1cmF0aW9ucyBvciBTVkcgaW5wdXRzIGZvciByZW5kZXJpbmcuIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZVxyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHsgY3JlYXRlQ2hhcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi4vdGVtcGxhdGVzL3N2Z0V4cG9ydC9zdmdFeHBvcnQuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwoc3RyaW5nfEJ1ZmZlcnxFeHBvcnRFcnJvcik+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlc1xyXG4gKiB0byB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgZXhwb3J0IHRvIGFuIHVuc3VwcG9ydGVkXHJcbiAqIG91dHB1dCBmb3JtYXQgb2NjdXJzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHB1cHBldGVlckV4cG9ydChwYWdlLCBvcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIGxldCBpc1NWRyA9IGZhbHNlO1xyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gSWYgdGhlIGB0eXBlYCBpcyBhbHNvIFNWRywgcmV0dXJuIHRoZSBpbnB1dFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAgIHJldHVybiBleHBvcnRPcHRpb25zLnN2ZztcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gTWFyayBhcyBTVkcgZXhwb3J0IGZvciB0aGUgbGF0ZXIgc2l6ZSBjb3JyZWN0aW9uc1xyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0XHJcbiAgICAgIGF3YWl0IF9zZXRBc1N2ZyhwYWdlLCBleHBvcnRPcHRpb25zLnN2Zyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIEpTT04gY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRcclxuICAgICAgYXdhaXQgX3NldEFzT3B0aW9ucyhwYWdlLCBvcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgIC4uLihhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMuY3VzdG9tTG9naWMpKVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcclxuXHJcbiAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgICAgY2hhcnRXaWR0aFxyXG4gICAgICAgICAgfTtcclxuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxyXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XHJcblxyXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgICAgLy8gb2YgZXhwb3J0cy4gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgX2dldENsaXBSZWdpb24ocGFnZSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGBoZWlnaHRgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcclxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBgd2lkdGhgIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCByZXN1bHQ7XHJcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcclxuICAgIHN3aXRjaCAoZXhwb3J0T3B0aW9ucy50eXBlKSB7XHJcbiAgICAgIGNhc2UgJ3N2Zyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZVNWRyhwYWdlKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncG5nJzpcclxuICAgICAgY2FzZSAnanBlZyc6XHJcbiAgICAgICAgcmVzdWx0ID0gYXdhaXQgX2NyZWF0ZUltYWdlKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIHgsXHJcbiAgICAgICAgICAgIHlcclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICAgKTtcclxuICAgICAgICBicmVhaztcclxuICAgICAgY2FzZSAncGRmJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlUERGKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBkZWZhdWx0OlxyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0OiAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiByZXN1bHQ7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU2V0cyB0aGUgc3BlY2lmaWVkIHBhZ2UncyBjb250ZW50IHdpdGggcHJvdmlkZWQgZXhwb3J0IGlucHV0IHdpdGhpblxyXG4gKiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgdGhlIGBwYWdlLnNldENvbnRlbnRgIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zZXRBc1N2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgaW5wdXQgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBjb250ZW50IGlzIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRBc1N2ZyhwYWdlLCBzdmcpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoc3ZnKSwge1xyXG4gICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIG9wdGlvbnMgd2l0aCBzcGVjaWZpZWQgZXhwb3J0IGlucHV0IGFuZCBzaXplcyBhcyBjb25maWd1cmF0aW9uIGludG9cclxuICogdGhlIGBjcmVhdGVDaGFydGAgZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZ1xyXG4gKiB0aGUgYHBhZ2UuZXZhbHVhdGVgIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9zZXRBc09wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uXHJcbiAqIGlzIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zZXRBc09wdGlvbnMocGFnZSwgb3B0aW9ucykge1xyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoY3JlYXRlQ2hhcnQsIG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnRcclxuICogd2l0aCB0aGUgJ2NoYXJ0LWNvbnRhaW5lcicgaWQuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2dldENsaXBSZWdpb25cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGB4YCwgYHlgLCBgd2lkdGhgLCBhbmQgYGhlaWdodGAgcHJvcGVydGllcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDbGlwUmVnaW9uKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XHJcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICB4LFxyXG4gICAgICB5LFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXHJcbiAgICB9O1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBTVkcgYnkgZXZhbHVhdGluZyB0aGUgYG91dGVySFRNTGAgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVNWR1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlU1ZHKHBhZ2UpIHtcclxuICByZXR1cm4gcGFnZS4kZXZhbChcclxuICAgICcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJyxcclxuICAgIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTFxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgYHNjcmVlbnNob3RgIGZ1bmN0aW9uYWxpdHkgd2l0aFxyXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlSW1hZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgaW1hZ2UgYnVmZmVyXHJcbiAqIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlSW1hZ2UocGFnZSwgdHlwZSwgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpIHtcclxuICByZXR1cm4gUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGNsaXAsXHJcbiAgICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxyXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuICAgICAgLy8gQWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGUgZm9ybWF0IGlzIFBOR1xyXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJyAvLyAjNDQ3LCAjNDYzXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcsIDQwOCkpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBwZGZgIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlUERGXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfY3JlYXRlUERGKHBhZ2UsIGhlaWdodCwgd2lkdGgsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuICByZXR1cm4gcGFnZS5wZGYoe1xyXG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXHJcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXHJcbiAgICB3aWR0aCxcclxuICAgIGVuY29kaW5nOiAnYmFzZTY0JyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHB1cHBldGVlckV4cG9ydFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgYSB3b3JrZXIgcG9vbCBpbXBsZW1lbnRhdGlvbiBmb3IgbWFuYWdpbmdcclxuICogdGhlIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHBhZ2VzLCBzcGVjaWZpY2FsbHkgZGVzaWduZWQgZm9yIHVzZSB3aXRoXHJcbiAqIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIuIEl0IG9wdGltaXplcyByZXNvdXJjZXMgdXNhZ2UgYW5kIHBlcmZvcm1hbmNlXHJcbiAqIGJ5IG1haW50YWluaW5nIGEgcG9vbCBvZiB3b3JrZXJzIHRoYXQgY2FuIGhhbmRsZSBjb25jdXJyZW50IGV4cG9ydCB0YXNrc1xyXG4gKiB1c2luZyBQdXBwZXRlZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UsIGNsZWFyUGFnZSB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IHB1cHBldGVlckV4cG9ydCB9IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldE5ld0RhdGVUaW1lLCBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gbnVsbDtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5jb25zdCBwb29sU3RhdHMgPSB7XHJcbiAgZXhwb3J0c0F0dGVtcHRlZDogMCxcclxuICBleHBvcnRzUGVyZm9ybWVkOiAwLFxyXG4gIGV4cG9ydHNEcm9wcGVkOiAwLFxyXG4gIGV4cG9ydHNGcm9tU3ZnOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uczogMCxcclxuICBleHBvcnRzRnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIGV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICB0aW1lU3BlbnRBdmVyYWdlOiAwXHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGluaXRQb29sXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcG9vbE9wdGlvbnM9Z2V0T3B0aW9ucygpLnBvb2xdIC0gT2JqZWN0IGNvbnRhaW5pbmcgYHBvb2xgXHJcbiAqIG9wdGlvbnMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRoZSBnbG9iYWwgcG9vbCBvcHRpb25zIG9mIHRoZSBleHBvcnQgc2VydmVyXHJcbiAqIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSBbcHVwcGV0ZWVyQXJncz1bXV0gLSBBZGRpdGlvbmFsIGFyZ3VtZW50c1xyXG4gKiBmb3IgUHVwcGV0ZWVyIGxhdW5jaC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2woXHJcbiAgcG9vbE9wdGlvbnMgPSBnZXRPcHRpb25zKCkucG9vbCxcclxuICBwdXBwZXRlZXJBcmdzID0gW11cclxuKSB7XHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3NlcihwdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xPcHRpb25zLm1pbldvcmtlcnN9LCBtYXggJHtwb29sT3B0aW9ucy5tYXhXb3JrZXJzfS5gXHJcbiAgICApO1xyXG5cclxuICAgIGlmIChwb29sKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwIGFuIGV5ZSBvbiBhIGNvcnJlY3QgbWluIGFuZCBtYXggd29ya2VycyBudW1iZXJcclxuICAgIGlmIChwb29sT3B0aW9ucy5taW5Xb3JrZXJzID4gcG9vbE9wdGlvbnMubWF4V29ya2Vycykge1xyXG4gICAgICBwb29sT3B0aW9ucy5taW5Xb3JrZXJzID0gcG9vbE9wdGlvbnMubWF4V29ya2VycztcclxuICAgIH1cclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgYGNyZWF0ZWAsIGB2YWxpZGF0ZWAsIGFuZCBgZGVzdHJveWAgZnVuY3Rpb25zXHJcbiAgICAgIC4uLl9mYWN0b3J5KHBvb2xPcHRpb25zKSxcclxuICAgICAgbWluOiBwb29sT3B0aW9ucy5taW5Xb3JrZXJzLFxyXG4gICAgICBtYXg6IHBvb2xPcHRpb25zLm1heFdvcmtlcnMsXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5hY3F1aXJlVGltZW91dCxcclxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuaWRsZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xPcHRpb25zLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGNvbnN0IGNsZWFyU3RhdHVzID0gYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLCBmYWxzZSk7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gUmVsZWFzaW5nIGEgd29ya2VyLiBDbGVhciBwYWdlIHN0YXR1czogJHtjbGVhclN0YXR1c30uYFxyXG4gICAgICApO1xyXG4gICAgfSk7XHJcblxyXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoX2V2ZW50SWQsIHJlc291cmNlKSA9PiB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA0LFxyXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtyZXNvdXJjZS5pZH1dIC0gRGVzdHJveWVkIGEgd29ya2VyIHN1Y2Nlc3NmdWxseS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJlc291cmNlLnBhZ2UgPSBudWxsO1xyXG4gICAgfSk7XHJcblxyXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xyXG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sT3B0aW9ucy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBraWxsUG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXHJcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xyXG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XHJcblxyXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxyXG4gIGlmIChwb29sKSB7XHJcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXHJcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcclxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcclxuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XHJcbiAgICB9XHJcbiAgICBwb29sID0gbnVsbDtcclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFdvcmtcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAoZ2V0T3B0aW9ucygpLnBvb2wuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaW4gY2FzZSBvZiBsYWNraW5nIHRoZSBwb29sIGluc3RhbmNlXHJcbiAgICBpZiAoIXBvb2wpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyxcclxuICAgICAgICA1MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaGUgYWNxdWlyZSBjb3VudGVyXHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gVHJ5IHRvIGFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCwgd29ya3MgY291bnQgYW5kIHBhZ2VcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XHJcblxyXG4gICAgICAvLyBBY3F1aXJlIGEgcG9vbCByZXNvdXJjZVxyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5fcmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdICcsXHJcbiAgICAgICAgICBgQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZSB0b29rICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gJyArXHJcbiAgICAgICAgICAob3B0aW9ucy5fcmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBvcHRpb25zLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbcG9vbF0gUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXHJcbiAgICBjb25zdCB3b3JrU3RhcnQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3dvcmtlckhhbmRsZS5pZH1dIC0gU3RhcnRpbmcgd29yayBvbiB0aGlzIHBvb2wgZW50cnkuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJZiB0aGVyZSdzIGEgcmFzdGVyaXphdGlvbiB0aW1lb3V0LCB3ZSB3YW50IG5lZWQgdG8gZmx1c2ggdGhlIHBhZ2UuXHJcbiAgICAgIC8vIFRoaXMgaXMgYmVjYXVzZSB0aGUgcGFnZSBtYXkgYmUgaW4gYSBzdGF0ZSB3aGVyZSBpdCdzIHdhaXRpbmcgZm9yXHJcbiAgICAgIC8vIHRoZSBzY3JlZW5zaG90IHRvIGZpbmlzaCBldmVuIHRob3VnaCB0aGUgdGltZW91dCBoYXMgb2NjdXJlZC5cclxuICAgICAgLy8gV2hpY2ggb2YgY291cnNlIGNhdXNlcyBhIGxvdCBvZiBpc3N1ZXMgd2l0aCB0aGUgZXZlbnQgc3lzdGVtLFxyXG4gICAgICAvLyBhbmQgcGFnZSBjb25zaXN0ZW5jeS5cclxuICAgICAgLy9cclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gT25seSBwYWdlLnNjcmVlbnNob3Qgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIHBhZ2UucGRmIGZ1bmN0aW9uIGl0c2VsZi5cclxuICAgICAgLy9cclxuICAgICAgLy8gLi4ueWVzLCB0aGlzIGlzIHVnbHkuXHJcbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcclxuICAgICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBvcHRpb25zLnBvb2wud29ya0xpbWl0ICsgMTtcclxuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IG51bGw7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChcclxuICAgICAgICByZXN1bHQubmFtZSA9PT0gJ1RpbWVvdXRFcnJvcicgfHxcclxuICAgICAgICByZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCdcclxuICAgICAgKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1twb29sXSAnICtcclxuICAgICAgICAgICAgKG9wdGlvbnMuX3JlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMuX3JlcXVlc3RJZH1dIC0gYCA6ICcnKSArXHJcbiAgICAgICAgICAgICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQ6IHlvdXIgY2hhcnQgbWF5IGJlIHRvbyBjb21wbGV4IG9yIGxhcmdlLCBhbmQgZmFpbGVkIHRvIHJlbmRlciB3aXRoaW4gdGhlIGFsbG90dGVkIHRpbWUuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3Bvb2xdICcgK1xyXG4gICAgICAgICAgICAob3B0aW9ucy5fcmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5fcmVxdWVzdElkfV0gLSBgIDogJycpICtcclxuICAgICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcclxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMuX3JlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCBbJHtvcHRpb25zLl9yZXF1ZXN0SWR9XSAtIGBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdICcsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBnZXROZXdEYXRlVGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcblxyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xyXG4gICAgcG9vbFN0YXRzLnRpbWVTcGVudEF2ZXJhZ2UgPVxyXG4gICAgICBwb29sU3RhdHMudGltZVNwZW50IC8gKytwb29sU3RhdHMuZXhwb3J0c1BlcmZvcm1lZDtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgIH07XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICsrcG9vbFN0YXRzLmV4cG9ydHNEcm9wcGVkO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgZXJyb3I7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fG51bGwpfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRQb29sSW5mb1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xyXG4gIGNvbnN0IHtcclxuICAgIG1pbixcclxuICAgIG1heCxcclxuICAgIHVzZWQsXHJcbiAgICBhdmFpbGFibGUsXHJcbiAgICBhbGxDcmVhdGVkLFxyXG4gICAgcGVuZGluZ0FjcXVpcmVzLFxyXG4gICAgcGVuZGluZ0NyZWF0ZXMsXHJcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXHJcbiAgICBwZW5kaW5nRGVzdHJveXMsXHJcbiAgICBhYnNvbHV0ZUFsbFxyXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcclxuXHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgdXNlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBmcmVlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgKHVzZWQgYW5kIGZyZWUpIHJlc291cmNlczogJHthbGxDcmVhdGVkfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBjcmVhdGVkOiAke3BlbmRpbmdDcmVhdGVzfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIHZhbGlkYXRlZDogJHtwZW5kaW5nVmFsaWRhdGlvbnN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxyXG4gICk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgcmVzb3VyY2VzOiAke2Fic29sdXRlQWxsfS5gKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEZhY3RvcnkgZnVuY3Rpb24gdGhhdCByZXR1cm5zIGFuIG9iamVjdCB3aXRoIGBjcmVhdGVgLCBgdmFsaWRhdGVgLFxyXG4gKiBhbmQgYGRlc3Ryb3lgIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBgcG9vbGAgb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgICAgLy8gYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XHJcbiAgICAgIC8vIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxyXG4gICAgICAvLyAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxyXG4gICAgICAvLyBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxyXG4gICAgICAvLyB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgICAvLyBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cclxuICAgICAgLy9cclxuICAgICAgLy8gVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAgIC8vIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXHJcbiAgICAgIC8vIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyB2YWxpZFxyXG4gICAgICBpZiAoIXBvb2xSZXNvdXJjZS5wYWdlKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChubyB2YWxpZCBwYWdlIGlzIGZvdW5kKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChwYWdlIGlzIGNsb3NlZCBvciBpbnZhbGlkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgbWFpbkZyYW1lYCBpcyBkZXRhY2hlZFxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCkuZGV0YWNoZWQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UncyBmcmFtZSBpcyBkZXRhY2hlZCkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHdvcmtMaW1pdGAgaXMgZXhjZWVkZWRcclxuICAgICAgaWYgKFxyXG4gICAgICAgIHBvb2xPcHRpb25zLndvcmtMaW1pdCAmJlxyXG4gICAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xPcHRpb25zLndvcmtMaW1pdFxyXG4gICAgICApIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKGV4Y2VlZGVkIHRoZSAke3Bvb2xPcHRpb25zLndvcmtMaW1pdH0gd29ya3MgcGVyIHJlc291cmNlIGxpbWl0KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSBgcG9vbFJlc291cmNlYCBpcyB2YWxpZGF0ZWRcclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICAgKlxyXG4gICAgICogQGFzeW5jXHJcbiAgICAgKiBAZnVuY3Rpb24gZGVzdHJveVxyXG4gICAgICpcclxuICAgICAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcclxuICAgICAqIHRoZSB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXHJcbiAgICAgKi9cclxuICAgIGRlc3Ryb3k6IGFzeW5jIChwb29sUmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRGVzdHJveWluZyBhIHdvcmtlci5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UgJiYgIXBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcmVzb3VyY2VcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XHJcbiAgICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2NvbnNvbGUnKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnZnJhbWVkZXRhY2hlZCcpO1xyXG5cclxuICAgICAgICAgIC8vIFdlIG5lZWQgdG8gd2FpdCBhcm91bmQgZm9yIHRoaXNcclxuICAgICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gUGFnZSBjb3VsZCBub3QgYmUgY2xvc2VkIHVwb24gZGVzdHJveWluZy5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG4gIHBvc3RXb3JrLFxyXG4gIGdldFBvb2wsXHJcbiAgZ2V0UG9vbFN0YXRzLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTlxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxyXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXHJcbiAqL1xyXG5cclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLiBUaGlzIGZ1bmN0aW9uIHVzZXNcclxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbCBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pjwvc2NyaXB0PlxyXG4gKiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNhbml0aXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCAtIFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICAvLyBHZXQgdGhlIHZpcnR1YWwgRE9NXHJcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHB1cmlmeWluZyBpbnN0YW5jZVxyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG5cclxuICAvLyBSZXR1cm4gc2FuaXRpemVkIGlucHV0XHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRvIHByZXBhcmUgZm9yIHRoZSBleHBvcnRpbmcgY2hhcnRzXHJcbiAqIGludG8gdmFyaW91cyBpbWFnZSBvdXRwdXQgZm9ybWF0cyBzdWNoIGFzIEpQRUcsIFBORywgUERGLCBhbmQgU1ZHcy5cclxuICogSXQgc3VwcG9ydHMgc2luZ2xlIGFuZCBiYXRjaCBleHBvcnQgb3BlcmF0aW9ucyBhbmQgYWxsb3dzIGN1c3RvbWl6YXRpb25cclxuICogdGhyb3VnaCBvcHRpb25zIHBhc3NlZCBmcm9tIGNvbmZpZ3VyYXRpb25zIG9yIEFQSXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VPcHRpb25zLCBpc0FsbG93ZWRDb25maWcgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhPdXRmaWxlLFxyXG4gIGZpeFR5cGUsXHJcbiAgZ2V0QWJzb2x1dGVQYXRoLFxyXG4gIGdldEJhc2U2NCxcclxuICByb3VuZE51bWJlcixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHN0cmljdFZhbGlkYXRlLCB2YWxpZGF0ZU9wdGlvbiB9IGZyb20gJy4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIGltYWdlIGluIHRoZSBwcm92aWRlZCBvdXRmaWxlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHNpbmdsZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXkgYmUgYSBwYXJ0aWFsXHJcbiAqIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJdCBtdXN0IGNvbnRhaW4gYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmdcclxuICogcHJvcGVydGllczogYGluZmlsZWAsIGBpbnN0cmAsIGBvcHRpb25zYCwgb3IgYHN2Z2AgdG8gZ2VuZXJhdGUgYSB2YWxpZCBpbWFnZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcclxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2luZ2xlRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQpIHtcclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0XHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCBhc3luYyAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgb3V0ZmlsZSB8fCBgY2hhcnQuJHt0eXBlfWAsXHJcbiAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgNTAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxyXG4gKiBpbiB0aGUgYGJhdGNoYCBvcHRpb24uIFRoZSBgYmF0Y2hgIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIi4gUmVzdWx0cyBhcmUgc2F2ZWRcclxuICogaW4gcHJvdmlkZWQgb3V0ZmlsZXMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gYmF0Y2hFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgYG9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5IGJlIGEgcGFydGlhbFxyXG4gKiBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSXQgbXVzdCBjb250YWluIHRoZSBgYmF0Y2hgIG9wdGlvbiB0byBnZW5lcmF0ZVxyXG4gKiB2YWxpZCBpbWFnZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcclxuICogcHJvY2Vzc2VzIGFyZSBjb21wbGV0ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYmF0Y2hFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBleHBvcnQgbWFrZXMgc2Vuc2VcclxuICBpZiAob3B0aW9ucyAmJiBvcHRpb25zLmV4cG9ydCAmJiBvcHRpb25zLmV4cG9ydC5iYXRjaCkge1xyXG4gICAgLy8gQW4gYXJyYXkgZm9yIGNvbGxlY3RpbmcgYmF0Y2ggZXhwb3J0c1xyXG4gICAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgYGJhdGNoYCBhcmd1bWVudHNcclxuICAgIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSB8fCBbXSkge1xyXG4gICAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcclxuICAgICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxyXG4gICAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAuLi5vcHRpb25zLFxyXG4gICAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXHJcbiAgICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAoZXJyb3IsIGRhdGEpID0+IHtcclxuICAgICAgICAgICAgICAvLyBFeGl0IHByb2Nlc3Mgd2hlbiBlcnJvciBleGlzdHNcclxuICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gR2V0IHRoZSBgYjY0YCwgYG91dGZpbGVgLCBhbmQgYHR5cGVgIGZvciBhIGNoYXJ0XHJcbiAgICAgICAgICAgICAgY29uc3QgeyBiNjQsIG91dGZpbGUsIHR5cGUgfSA9IGRhdGEub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgICAgICAgICAgIC8vIFNhdmUgdGhlIHJlc3VsdFxyXG4gICAgICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgICAgICBpZiAoYjY0KSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgQmFzZTY0IHN0cmluZyB0byBhIHR4dCBmaWxlXHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgYCR7b3V0ZmlsZS5zcGxpdCgnLicpLnNoaWZ0KCkgfHwgJ2NoYXJ0J30udHh0YCxcclxuICAgICAgICAgICAgICAgICAgICBnZXRCYXNlNjQoZGF0YS5yZXN1bHQsIHR5cGUpXHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgICAvLyBBcyBhIGNvcnJlY3QgaW1hZ2UgZm9ybWF0XHJcbiAgICAgICAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgICAgICAgb3V0ZmlsZSxcclxuICAgICAgICAgICAgICAgICAgICB0eXBlICE9PSAnc3ZnJ1xyXG4gICAgICAgICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShkYXRhLnJlc3VsdCwgJ2Jhc2U2NCcpXHJcbiAgICAgICAgICAgICAgICAgICAgICA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIGxvZygyLCAnW2NoYXJ0XSBObyBjb3JyZWN0IHBhaXIgZm91bmQgZm9yIHRoZSBiYXRjaCBleHBvcnQuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgY29uc3QgYmF0Y2hSZXN1bHRzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKGJhdGNoRnVuY3Rpb25zKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxyXG4gICAgYXdhaXQga2lsbFBvb2woKTtcclxuXHJcbiAgICAvLyBMb2cgZXJyb3JzIGlmIGZvdW5kXHJcbiAgICBiYXRjaFJlc3VsdHMuZm9yRWFjaCgocmVzdWx0LCBpbmRleCkgPT4ge1xyXG4gICAgICAvLyBMb2cgdGhlIGVycm9yIHdpdGggc3RhY2sgYWJvdXQgdGhlIHNwZWNpZmljIGJhdGNoIGV4cG9ydFxyXG4gICAgICBpZiAocmVzdWx0LnJlYXNvbikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICByZXN1bHQucmVhc29uLFxyXG4gICAgICAgICAgYFtjaGFydF0gQmF0Y2ggZXhwb3J0IG51bWJlciAke2luZGV4ICsgMX0gY291bGQgbm90IGJlIGNvcnJlY3RseSBjb21wbGV0ZWQuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIE5vIGV4cGVjdGVkIGBleHBvcnRgIG9wdGlvbnMgd2VyZSBmb3VuZC4gUGxlYXNlIHByb3ZpZGUgdGhlIGBiYXRjaGAgb3B0aW9uIHRvIGdlbmVyYXRlIHZhbGlkIGltYWdlcy4nLFxyXG4gICAgICA0MDBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYGN1c3RvbU9wdGlvbnNgIHBhcmFtZXRlciBpcyBhbiBvYmplY3QgdGhhdFxyXG4gKiBtYXkgYmUgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gVGhlIGBlbmRDYWxsYmFja2AgaXMgY2FsbGVkIHdoZW5cclxuICogdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggdGhlIGBlcnJvcmAgb2JqZWN0IGFzIHRoZSBmaXJzdCBhcmd1bWVudFxyXG4gKiBhbmQgdGhlIGBkYXRhYCBvYmplY3QgYXMgdGhlIHNlY29uZCwgd2hpY2ggY29udGFpbnMgdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5IGFuZCB0aGUgZnVsbCBzZXQgb2YgZXhwb3J0IG9wdGlvbnNcclxuICogaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIGBlcnJvcmAgb2JqZWN0IGFuZCB0aGUgYGRhdGFgIG9iamVjdCBpcyB0aGUgc2Vjb25kLCB0aGF0IGNvbnRhaW5zXHJcbiAqIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YCBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGxcclxuICogc2V0IG9mIGV4cG9ydCBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2AgcHJvcGVydHkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5LlxyXG4gKiBJbnN0ZWFkLCBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGBlbmRDYWxsYmFja2AuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxyXG4gKiBwcm9jZXNzaW5nIGlucHV0IG9mIGFueSB0eXBlLiBUaGUgZXJyb3IgaXMgcGFzc2VkIGludG8gdGhlIGBlbmRDYWxsYmFja2BcclxuICogZnVuY3Rpb24gYW5kIHByb2Nlc3NlZCB0aGVyZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBzdGFydEV4cG9ydChjdXN0b21PcHRpb25zLCBlbmRDYWxsYmFjaykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xyXG5cclxuICAgIC8vIE1lcmdlIHRoZSBjdXN0b20gb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGUgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIGZpbGUgaW5wdXQuJyk7XHJcblxyXG4gICAgICBsZXQgZmlsZUNvbnRlbnQ7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgICAgICBmaWxlQ29udGVudCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGdldEFic29sdXRlUGF0aChleHBvcnRPcHRpb25zLmluZmlsZSksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEVycm9yIGxvYWRpbmcgY29udGVudCBmcm9tIGEgZmlsZSBpbnB1dC4nLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBmaWxlJ3MgZXh0ZW5zaW9uXHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLnN2ZycpKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIC8vIFNldCB0byB0aGUgYHN2Z2Agb3B0aW9uXHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zLnN2ZyA9IHZhbGlkYXRlT3B0aW9uKCdzdmcnLCBmaWxlQ29udGVudCwgZmFsc2UpO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICBsb2dab2RJc3N1ZXMoXHJcbiAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAgICAgJ1tjb25maWddIFRoZSBgc3ZnYCBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcidcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gU2V0IHRvIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciA9IHZhbGlkYXRlT3B0aW9uKCdpbnN0cicsIGZpbGVDb250ZW50LCBmYWxzZSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAgICAgMSxcclxuICAgICAgICAgICAgZXJyb3IuaXNzdWVzLFxyXG4gICAgICAgICAgICAnW2NvbmZpZ10gVGhlIGBpbnN0cmAgb3B0aW9uIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBhc3NpZ25lZCB0byB0aGUgZ2xvYmFsXHJcbiAqIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb24odmFsdWUpIHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB2YWx1ZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgZnJvbSBhbiBTVkcgYmFzZWQgaW5wdXQgd2l0aCB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZXhwb3J0RnJvbVN2Z1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBTVkcgYmFzZWQgaW5wdXQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5pbmcgY29tcGxldGUgc2V0XHJcbiAqIG9mIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBub3QgYSBjb3JyZWN0XHJcbiAqIGNoYXJ0IG9wdGlvbnMgaW5wdXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfZXhwb3J0RnJvbU9wdGlvbnMoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGZyb20gb3B0aW9ucy4nKTtcclxuXHJcbiAgLy8gVHJ5IHRvIGNoZWNrLCB2YWxpZGF0ZSBhbmQgcGFyc2UgdG8gc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgIGlucHV0VG9FeHBvcnQsXHJcbiAgICB0cnVlLFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBDaGVjayBpZiBhIGNvcnJlY3Qgc3RyaW5naWZpZWQgb3B0aW9uc1xyXG4gIGlmIChcclxuICAgIHN0cmluZ2lmaWVkT3B0aW9ucyA9PT0gbnVsbCB8fFxyXG4gICAgdHlwZW9mIHN0cmluZ2lmaWVkT3B0aW9ucyAhPT0gJ3N0cmluZycgfHxcclxuICAgICFzdHJpbmdpZmllZE9wdGlvbnMuc3RhcnRzV2l0aCgneycpIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLmVuZHNXaXRoKCd9JylcclxuICApIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gT25seSBvcHRpb25zIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9ucyBzZXQgdG8gdHJ1ZS4nLFxyXG4gICAgICA0MDNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGV4cG9ydCBpbnB1dCBhcyBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHN0cmluZ2lmaWVkT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgdGhlIHJlc3Qgb2YgdGhlIGV4cG9ydCBpbnB1dCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuc3ZnID0gbnVsbDtcclxuXHJcbiAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhIHN0cmluZ2lmaWVkIGNoYXJ0IG9wdGlvbnNcclxuICByZXR1cm4gX3ByZXBhcmVFeHBvcnQob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9ucyBiZWZvcmUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpIHtcclxuICBjb25zdCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYHR5cGVgIG9wdGlvblxyXG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gZml4T3V0ZmlsZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcblxyXG4gIC8vIE5vdGlmeSBhYm91dCB0aGUgY3VzdG9tIGxvZ2ljIHVzYWdlIHN0YXR1c1xyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2NoYXJ0XSBUaGUgY3VzdG9tIGxvZ2ljIGlzICR7Y3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA/ICdhbGxvd2VkJyA6ICdkaXNhbGxvd2VkJ30uYFxyXG4gICk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIChgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgKVxyXG4gIF9oYW5kbGVDdXN0b21Mb2dpYyhjdXN0b21Mb2dpY09wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgZ2xvYmFsT3B0aW9uc2AgYW5kIGB0aGVtZU9wdGlvbnNgIG9wdGlvbnNcclxuICBfaGFuZGxlR2xvYmFsQW5kVGhlbWUoXHJcbiAgICBleHBvcnRPcHRpb25zLFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xyXG4gICAgLi4uZXhwb3J0T3B0aW9ucyxcclxuICAgIC4uLl9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gVGhlIGxhc3Qgc3RyaWN0IHZhbGlkYXRpb24gb2Ygb3B0aW9ucyByaWdodCBiZWZvcmUgZXhwb3J0aW5nIHByb2Nlc3NcclxuICB0cnkge1xyXG4gICAgLy8gVmFsaWRhdGUgZmluYWwgb3B0aW9uc1xyXG4gICAgb3B0aW9ucyA9IHN0cmljdFZhbGlkYXRlKG9wdGlvbnMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW2NvbmZpZ10gRmluYWwgb3B0aW9ucyB2YWxpZGF0aW9uIGVycm9yJyk7XHJcbiAgfVxyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgcmV0dXJuIHBvc3RXb3JrKG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyB0aGUgYGhlaWdodGAsIGB3aWR0aGAgYW5kIGBzY2FsZWAgZm9yIGNoYXJ0IGV4cG9ydHMgYmFzZWRcclxuICogb24gdGhlIHByb3ZpZGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqIDEuIFRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYHNjYWxlYCBmcm9tIHRoZSBgZXhwb3J0T3B0aW9uc2AuXHJcbiAqIDIuIE9wdGlvbnMgZnJvbSB0aGUgY2hhcnQgY29uZmlndXJhdGlvbiAoZnJvbSBgZXhwb3J0aW5nYCBhbmQgYGNoYXJ0YCkuXHJcbiAqIDMuIE9wdGlvbnMgZnJvbSB0aGUgZ2xvYmFsIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiA0LiBPcHRpb25zIGZyb20gdGhlIHRoZW1lIG9wdGlvbnMgKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGAgc2VjdGlvbnMpLlxyXG4gKiA1LiBGYWxsYmFjayBkZWZhdWx0IHZhbHVlcyAoYGhlaWdodCA9IDQwMGAsIGB3aWR0aCA9IDYwMGAsIGBzY2FsZSA9IDFgKS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGBoZWlnaHRgLCBgd2lkdGhgXHJcbiAqIGFuZCBgc2NhbGVgIHZhbHVlcyBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmZ1bmN0aW9uIF9maW5kQ2hhcnRTaXplKGV4cG9ydE9wdGlvbnMpIHtcclxuICAvLyBDaGVjayB0aGUgYG9wdGlvbnNgIGFuZCBgaW5zdHJgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogb3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IG9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBleHBvcnRPcHRpb25zLm9wdGlvbnMgfHwgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHNjYWxlYCB2YWx1ZTpcclxuICAvLyAtIEl0IGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMVxyXG4gIC8vIC0gSXQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxyXG4gIC8vIC0gSXQgbXVzdCBiZSByb3VuZGVkIHRvIDIgZGVjaW1hbCBwbGFjZXMgKGUuZy4gMC4yMzIzNCAtPiAwLjIzKVxyXG4gIGNvbnN0IHNjYWxlID0gcm91bmROdW1iZXIoXHJcbiAgICBNYXRoLm1heChcclxuICAgICAgMC4xLFxyXG4gICAgICBNYXRoLm1pbihcclxuICAgICAgICBleHBvcnRPcHRpb25zLnNjYWxlIHx8XHJcbiAgICAgICAgICBvcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc2NhbGUgfHxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMuZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgIDUuMFxyXG4gICAgICApXHJcbiAgICApLFxyXG4gICAgMlxyXG4gICk7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGBoZWlnaHRgIHZhbHVlXHJcbiAgY29uc3QgaGVpZ2h0ID1cclxuICAgIGV4cG9ydE9wdGlvbnMuaGVpZ2h0IHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIG9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LmhlaWdodCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0SGVpZ2h0IHx8XHJcbiAgICA0MDA7XHJcblxyXG4gIC8vIEZpbmQgdGhlIGB3aWR0aGAgdmFsdWVcclxuICBjb25zdCB3aWR0aCA9XHJcbiAgICBleHBvcnRPcHRpb25zLndpZHRoIHx8XHJcbiAgICBvcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIGdsb2JhbE9wdGlvbnNDaGFydD8ud2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlV2lkdGggfHxcclxuICAgIHRoZW1lT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0V2lkdGggfHxcclxuICAgIDYwMDtcclxuXHJcbiAgLy8gR2F0aGVyIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGluZm9ybWF0aW9uIGluIG9uZSBvYmplY3RcclxuICBjb25zdCBzaXplID0geyBoZWlnaHQsIHdpZHRoLCBzY2FsZSB9O1xyXG5cclxuICAvLyBHZXQgcmlkIG9mIHBvdGVudGlhbCBgcHhgIGFuZCBgJWBcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBzaXplIG9iamVjdFxyXG4gIHJldHVybiBzaXplO1xyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBsb2dpYyBvcHRpb25zLCBpbmNsdWRpbmcgbG9hZGluZyBgcmVzb3VyY2VzYCxcclxuICogYGN1c3RvbUNvZGVgLCBhbmQgYGNhbGxiYWNrYC4gSWYgY29kZSBleGVjdXRpb24gaXMgYWxsb3dlZCwgaXQgcHJvY2Vzc2VzXHJcbiAqIHRoZSBjdXN0b20gbG9naWMgb3B0aW9ucyBhY2NvcmRpbmdseS4gSWYgY29kZSBleGVjdXRpb24gaXMgbm90IGFsbG93ZWQsXHJcbiAqIGl0IGRpc2FibGVzIHRoZSB1c2FnZSBvZiByZXNvdXJjZXMsIGN1c3RvbSBjb2RlIGFuZCBjYWxsYmFjay5cclxuICpcclxuICogQGZ1bmN0aW9uIF9oYW5kbGVDdXN0b21Mb2dpY1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBjdXN0b21Mb2dpY2BcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0NvZGVFeGVjdXRpb24gLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIGNvZGVcclxuICogZXhlY3V0aW9uIGlzIGFsbG93ZWQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucywgYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgLy8gSW4gY2FzZSBvZiBhbGxvd2luZyBjb2RlIGV4ZWN1dGlvblxyXG4gIGlmIChhbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIC8vIFByb2Nlc3MgdGhlIGByZXNvdXJjZXNgIG9wdGlvblxyXG4gICAgaWYgKHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBDdXN0b20gc3RyaW5naWZpZWQgcmVzb3VyY2VzXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgLy8gTG9hZCB0aGUgZGVmYXVsdCBvbmVcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoJ3Jlc291cmNlcy5qc29uJyksICd1dGY4JyksXHJcbiAgICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IGByZXNvdXJjZXMuanNvbmAgZmlsZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFByb2Nlc3MgdGhlIGBjdXN0b21Db2RlYCBvcHRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBsb2FkIGN1c3RvbSBjb2RlIGFuZCB3cmFwIGFyb3VuZCBpdCBpbiBhIHNlbGYgaW52b2tpbmcgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjdXN0b21Db2RlYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY2FsbGJhY2sgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICB0cnVlXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbY2hhcnRdIFRoZSBgY2FsbGJhY2tgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGN1c3RvbUNvZGVgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGNhbGxiYWNrYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgY2FsbGJhY2tgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYHJlc291cmNlc2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gSWYgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIGZsYWcgaXMgc2V0IHRvIGZhbHNlLCB3ZSBzaG91bGQgcmVmdXNlXHJcbiAgICAvLyB0aGUgdXNhZ2Ugb2YgdGhlIGBjYWxsYmFja2AsIGByZXNvdXJjZXNgLCBhbmQgYGN1c3RvbUNvZGVgIG9wdGlvbnMuXHJcbiAgICAvLyBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbCByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LlxyXG4gICAgaWYgKFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFJlc2V0IGFsbCBjdXN0b20gY29kZSBvcHRpb25zXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IG51bGw7XHJcblxyXG4gICAgICAvLyBTZW5kIGEgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydCB0aGVzZSBzZXR0aW5nc1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnLCBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gLFxyXG4gICAgICAgIDQwM1xyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZnJvbSB0aGUgYHJlc291cmNlc2Agb3B0aW9uIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KE9iamVjdHxzdHJpbmd8bnVsbCl9IFtyZXNvdXJjZXM9bnVsbF0gLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuXHJcbiAqIENhbiBiZSBlaXRoZXIgYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiwgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLFxyXG4gKiBvciBudWxsLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBudWxsLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICAgIGZhbHNlLFxyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCB7XHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGxvYWRpbmcgYW5kIHZhbGlkYXRpb24gb2YgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2BcclxuICogaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJZiB0aGUgb3B0aW9uIGlzIGEgc3RyaW5nIGFuZCByZWZlcmVuY2VzIGEgSlNPTiBmaWxlXHJcbiAqICh3aGVuIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBpcyB0cnVlKSwgaXQgcmVhZHMgYW5kIHBhcnNlcyB0aGUgZmlsZS5cclxuICogT3RoZXJ3aXNlLCBpdCBhdHRlbXB0cyB0byBwYXJzZSB0aGUgc3RyaW5nIG9yIG9iamVjdCBhcyBKU09OLiBJZiBhbnkgZXJyb3JzXHJcbiAqIG9jY3VyIGR1cmluZyB0aGlzIHByb2Nlc3MsIHRoZSBvcHRpb24gaXMgc2V0IHRvIG51bGwuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBudWxsLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gVGhlIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBsb2FkaW5nXHJcbiAqIHJlc291cmNlcyBmcm9tIGZpbGVzIGlzIGFsbG93ZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dDb2RlRXhlY3V0aW9uIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciBjb2RlXHJcbiAqIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKFxyXG4gIGV4cG9ydE9wdGlvbnMsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIG1vZHVsZSBwcm92aWRlcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgaW50ZXJ2YWxzXHJcbiAqIGFuZCB0aW1lb3V0cyBpbiBhIGNlbnRyYWxpemVkIG1hbm5lci4gSXQgbWFpbnRhaW5zIGEgcmVnaXN0cnkgb2YgYWxsIGFjdGl2ZVxyXG4gKiB0aW1lcnMgYW5kIGFsbG93cyBmb3IgdGhlaXIgZWZmaWNpZW50IGNsZWFudXAgd2hlbiBuZWVkZWQuIFRoaXMgY2FuIGJlIHVzZWZ1bFxyXG4gKiBpbiBhcHBsaWNhdGlvbnMgd2hlcmUgcHJvcGVyIHJlc291cmNlIG1hbmFnZW1lbnQgYW5kIGNsZWFuIHNodXRkb3duIG9mIHRpbWVyc1xyXG4gKiBhcmUgY3JpdGljYWwgdG8gYXZvaWQgbWVtb3J5IGxlYWtzIG9yIHVuaW50ZW5kZWQgYmVoYXZpb3IuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0c1xyXG5jb25zdCB0aW1lcklkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgdGhlIGBzZXRJbnRlcnZhbGAgb3IgYHNldFRpbWVvdXRgIGFuZCB0byB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGFkZFRpbWVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwgb3IgYSB0aW1lb3V0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGFkZFRpbWVyKGlkKSB7XHJcbiAgdGltZXJJZHMucHVzaChpZCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGFuZCB0aW1lb3V0cyBieSBpZHMgZ2F0aGVyZWRcclxuICogaW4gdGhlIGB0aW1lcklkc2AgYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbGVhckFsbFRpbWVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzKCkge1xyXG4gIGxvZyg0LCBgW3RpbWVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgdGltZXJJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gICAgY2xlYXJUaW1lb3V0KGlkKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRUaW1lcixcclxuICBjbGVhckFsbFRpbWVyc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2VzXHJcbiAqIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZXMgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uIHdpdGhcclxuICogdGhlIHBhc3NlZCBlcnJvci5cclxuICovXHJcbmZ1bmN0aW9uIGxvZ0Vycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZ2V0T3B0aW9ucygpLm90aGVyLm5vZGVFbnYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIGByZXR1cm5FcnJvck1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICByZXR1cm4gbmV4dChlcnJvcik7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByZXR1cm5FcnJvck1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZShlcnJvciwgcmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG5cclxuICAvLyBVc2UgdGhlIGVycm9yJ3Mgc3RhdHVzIGNvZGUgb3IgdGhlIGRlZmF1bHQgNDAwXHJcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGUgfHwgNDAwO1xyXG5cclxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxyXG4gIHJlc3BvbnNlLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBlcnJvciBtaWRkbGV3YXJlcyB0byB0aGUgcGFzc2VkIGV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGVycm9yTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIGNvbmZpZ3VyaW5nIGFuZCBlbmFibGluZyByYXRlXHJcbiAqIGxpbWl0aW5nIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JhdGVMaW1pdGluZ09wdGlvbnM9Z2V0T3B0aW9ucygpLnNlcnZlci5yYXRlTGltaXRpbmddIC1cclxuICogT2JqZWN0IGNvbnRhaW5pbmcgYHJhdGVMaW1pdGluZ2Agb3B0aW9ucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlIGdsb2JhbFxyXG4gKiByYXRlIGxpbWl0aW5nIG9wdGlvbnMgb2YgdGhlIGV4cG9ydCBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY29uZmlndXJlIGFuZCBzZXRcclxuICogdGhlIHJhdGUgbGltaXRpbmcgb3B0aW9ucy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoXHJcbiAgYXBwLFxyXG4gIHJhdGVMaW1pdGluZ09wdGlvbnMgPSBnZXRPcHRpb25zKCkuc2VydmVyLnJhdGVMaW1pdGluZ1xyXG4pIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgdGhlIHJhdGUgbGltaXRpbmcgaXMgZW5hYmxlZFxyXG4gICAgaWYgKHJhdGVMaW1pdGluZ09wdGlvbnMuZW5hYmxlKSB7XHJcbiAgICAgIGNvbnN0IG1zZyA9XHJcbiAgICAgICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgICAgICBtYXg6IHJhdGVMaW1pdGluZ09wdGlvbnMubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICAgICAgd2luZG93OiByYXRlTGltaXRpbmdPcHRpb25zLndpbmRvdyB8fCAxLFxyXG4gICAgICAgIGRlbGF5OiByYXRlTGltaXRpbmdPcHRpb25zLmRlbGF5IHx8IDAsXHJcbiAgICAgICAgdHJ1c3RQcm94eTogcmF0ZUxpbWl0aW5nT3B0aW9ucy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgICAgIHNraXBLZXk6IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwVG9rZW46IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgICAgIH07XHJcblxyXG4gICAgICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICAgICAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgICAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xyXG4gICAgICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAgICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICAgICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXHJcbiAgICAgICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgICAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgICAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xyXG4gICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXHJcbiAgICAgICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgICAgICkge1xyXG4gICAgICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XHJcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxyXG4gICAgICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3JhdGUgbGltaXRpbmddIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIEhUVFAgZXJyb3IgY2xhc3MgdGhhdCBleHRlbmRzIHRoZSBgRXhwb3J0RXJyb3JgLiBVc2VkIHRvIGhhbmRsZVxyXG4gKiBlcnJvcnMgd2l0aCBIVFRQIHN0YXR1cyBjb2Rlcy5cclxuICovXHJcbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgSHR0cEVycm9yYC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gVGhlIGVycm9yIG1lc3NhZ2UgdG8gYmUgZGlzcGxheWVkLlxyXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBzdGF0dXNDb2RlIC0gT3B0aW9uYWwgSFRUUCBzdGF0dXMgY29kZSBhc3NvY2lhdGVkXHJcbiAgICogd2l0aCB0aGUgZXJyb3IgKGUuZy4sIDQwMCwgNTAwKS5cclxuICAgKi9cclxuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXNDb2RlKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlLCBzdGF0dXNDb2RlKTtcclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgb3IgdXBkYXRlcyB0aGUgSFRUUCBzdGF0dXMgY29kZSBmb3IgdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBUaGUgSFRUUCBzdGF0dXMgY29kZSB0byBhc3NpZ24gdG8gdGhlIGVycm9yLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0h0dHBFcnJvcn0gVGhlIHVwZGF0ZWQgaW5zdGFuY2Ugb2YgdGhlIGBIdHRwRXJyb3JgIGNsYXNzLlxyXG4gICAqL1xyXG4gIHNldFN0YXR1cyhzdGF0dXNDb2RlKSB7XHJcbiAgICB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXNDb2RlO1xyXG5cclxuICAgIHJldHVybiB0aGlzO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWlkZGxld2FyZSBmdW5jdGlvbnMgZm9yIHZhbGlkYXRpbmcgaW5jb21pbmcgSFRUUCByZXF1ZXN0c1xyXG4gKiBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLiBUaGlzIG1vZHVsZSBlbnN1cmVzIHRoYXQgcmVxdWVzdHMgY29udGFpblxyXG4gKiBhcHByb3ByaWF0ZSBjb250ZW50IHR5cGVzIGFuZCB2YWxpZCByZXF1ZXN0IGJvZGllcywgaW5jbHVkaW5nIHByb3BlciBKU09OXHJcbiAqIHN0cnVjdHVyZXMgYW5kIGNoYXJ0IGRhdGEgZm9yIGV4cG9ydHMuIEl0IGNoZWNrcyBmb3IgcG90ZW50aWFsIGlzc3VlcyBzdWNoXHJcbiAqIGFzIG1pc3Npbmcgb3IgbWFsZm9ybWVkIGRhdGEsIHByaXZhdGUgcmFuZ2UgVVJMcyBpbiBTVkcgcGF5bG9hZHMsIGFuZCBhbGxvd3NcclxuICogZm9yIGZsZXhpYmxlIG9wdGlvbnMgdmFsaWRhdGlvbi4gVGhlIG1pZGRsZXdhcmUgbG9ncyBkZXRhaWxlZCBpbmZvcm1hdGlvblxyXG4gKiBhbmQgaGFuZGxlcyBlcnJvcnMgcmVsYXRlZCB0byBpbmNvcnJlY3QgcGF5bG9hZHMsIGNoYXJ0IGRhdGEsIGFuZCBwcml2YXRlIFVSTFxyXG4gKiB1c2FnZS5cclxuICovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24gfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IGlzQWxsb3dlZENvbmZpZyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nWm9kSXNzdWVzIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhDb25zdHIsXHJcbiAgZml4VHlwZSxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmRcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IGxvb3NlVmFsaWRhdGUgfSBmcm9tICcuLi8uLi92YWxpZGF0aW9uLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgdmFsaWRhdGluZyB0aGUgY29udGVudC10eXBlIGhlYWRlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNvbnRlbnQtdHlwZVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICovXHJcbmZ1bmN0aW9uIGNvbnRlbnRUeXBlTWlkZGxld2FyZShyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIGNvbnRlbnQgdHlwZSBoZWFkZXJcclxuICAgIGNvbnN0IGNvbnRlbnRUeXBlID0gcmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXSB8fCAnJztcclxuXHJcbiAgICAvLyBBbGxvdyBvbmx5IEpTT04sIFVSTC1lbmNvZGVkIGFuZCBmb3JtIGRhdGEgd2l0aG91dCBmaWxlcyB0eXBlcyBvZiBkYXRhXHJcbiAgICBpZiAoXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24vanNvbicpICYmXHJcbiAgICAgICFjb250ZW50VHlwZS5pbmNsdWRlcygnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdtdWx0aXBhcnQvZm9ybS1kYXRhJylcclxuICAgICkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdbdmFsaWRhdGlvbl0gQ29udGVudC1UeXBlIG11c3QgYmUgYXBwbGljYXRpb24vanNvbiwgYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkLCBvciBtdWx0aXBhcnQvZm9ybS1kYXRhLicsXHJcbiAgICAgICAgNDE1XHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYHJlcXVlc3RCb2R5TWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIHJlcXVlc3QncyBib2R5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dW5kZWZpbmVkfSBUaGUgY2FsbCB0byB0aGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtIdHRwRXJyb3J9IFRocm93cyBhbiBgSHR0cEVycm9yYCBpZiB0aGUgYm9keSBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7SHR0cEVycm9yfSBUaHJvd3MgYW4gYEh0dHBFcnJvcmAgaW4gY2FzZSBvZiB0aGUgcHJpdmF0ZSByYW5nZSB1cmxcclxuICogZXJyb3IuXHJcbiAqL1xyXG5mdW5jdGlvbiByZXF1ZXN0Qm9keU1pZGRsZXdhcmUocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gR2V0IHRoZSByZXF1ZXN0IGJvZHlcclxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBbdmFsaWRhdGlvbl0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFRoZSByZXF1ZXN0IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHBheWxvYWQgaXMgZW1wdHkuYFxyXG4gICAgICApO1xyXG5cclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICBcIlt2YWxpZGF0aW9uXSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbiBmb3IgdGhlIHNlcnZlclxyXG4gICAgY29uc3QgYWxsb3dDb2RlRXhlY3V0aW9uID0gZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCk7XHJcblxyXG4gICAgLy8gRmluZCBhIGNvcnJlY3QgY2hhcnQgb3B0aW9uc1xyXG4gICAgY29uc3QgaW5zdHIgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgIC8vIFVzZSBvbmUgb2YgdGhlIGJlbG93XHJcbiAgICAgIGJvZHkuaW5zdHIgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuaW5maWxlIHx8IGJvZHkuZGF0YSxcclxuICAgICAgLy8gU3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgdHJ1ZSxcclxuICAgICAgLy8gQWxsb3cgb3IgZGlzYWxsb3cgZnVuY3Rpb25zXHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpZiB0aGVyZSBpcyBubyBjb3JyZWN0IGNoYXJ0IGRhdGFcclxuICAgIGlmIChpbnN0ciA9PT0gbnVsbCAmJiAhYm9keS5zdmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgYFt2YWxpZGF0aW9uXSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIHJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xyXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUmVjZWl2ZWQgcGF5bG9hZCBpcyBtaXNzaW5nIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3IgZXhwb3J0OiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiW3ZhbGlkYXRpb25dIE5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGVzdCBvZiB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWRyBmYWlsc1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoYm9keS5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJbdmFsaWRhdGlvbl0gU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4gJ3hsaW5rOmhyZWYnIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFZhbGlkYXRlIG9wdGlvbnMgZnJvbSB0aGUgYm9keSBhbmQgc3RvcmUgcGFyc2VkIHN0cnVjdHVyZSBpbiB0aGUgcmVxdWVzdFxyXG4gICAgICByZXF1ZXN0LnZhbGlkYXRlZE9wdGlvbnMgPSBsb29zZVZhbGlkYXRlKHtcclxuICAgICAgICAvLyBTZXQgdGhlIGNyZWF0ZWQgSUQgYXMgYSBgX3JlcXVlc3RJZGAgcHJvcGVydHkgaW4gdGhlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICAgICAgX3JlcXVlc3RJZDogcmVxdWVzdElkLFxyXG4gICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgICBzdmc6IGJvZHkuc3ZnLFxyXG4gICAgICAgICAgb3V0ZmlsZTpcclxuICAgICAgICAgICAgYm9keS5vdXRmaWxlIHx8XHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7Zml4VHlwZShib2R5LnR5cGUpfWAsXHJcbiAgICAgICAgICB0eXBlOiBmaXhUeXBlKGJvZHkudHlwZSwgYm9keS5vdXRmaWxlKSxcclxuICAgICAgICAgIGNvbnN0cjogZml4Q29uc3RyKGJvZHkuY29uc3RyKSxcclxuICAgICAgICAgIGI2NDogYm9keS5iNjQsXHJcbiAgICAgICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQsXHJcbiAgICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgICBzY2FsZTogYm9keS5zY2FsZSxcclxuICAgICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgYm9keS5nbG9iYWxPcHRpb25zLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICksXHJcbiAgICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgICAgYm9keS50aGVtZU9wdGlvbnMsXHJcbiAgICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICAgICAgKVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IHtcclxuICAgICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbixcclxuICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXHJcbiAgICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGUsXHJcbiAgICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICAgIHJlc291cmNlczogaXNBbGxvd2VkQ29uZmlnKGJvZHkucmVzb3VyY2VzLCB0cnVlLCBhbGxvd0NvZGVFeGVjdXRpb24pXHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1pvZElzc3VlcyhcclxuICAgICAgICAxLFxyXG4gICAgICAgIGVycm9yLmlzc3VlcyxcclxuICAgICAgICAnW2NvbmZpZ10gUmVxdWVzdCBvcHRpb25zIHZhbGlkYXRpb24gZXJyb3InXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdUaGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgbm90IGNvcnJlY3QuIFBsZWFzZSBjaGVjayBpZiB5b3VyIGRhdGEgaXMgb2YgdGhlIGNvcnJlY3QgdHlwZXMuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIHRoZSBuZXh0IG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKSB7XHJcbiAgLy8gQWRkIGNvbnRlbnQgdHlwZSB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCBjb250ZW50VHlwZU1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgcmVxdWVzdCBib2R5IHJlcXVlc3QgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgYXBwLnBvc3QoWycvJywgJy86ZmlsZW5hbWUnXSwgcmVxdWVzdEJvZHlNaWRkbGV3YXJlKTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyB0aGUgZXhwb3J0IHJvdXRlcyBhbmQgbG9naWMgZm9yIGhhbmRsaW5nIGNoYXJ0IGV4cG9ydFxyXG4gKiByZXF1ZXN0cyBpbiBhbiBFeHByZXNzIHNlcnZlci4gVGhpcyBtb2R1bGUgcHJvY2Vzc2VzIGluY29taW5nIHJlcXVlc3RzXHJcbiAqIHRvIGV4cG9ydCBjaGFydHMgaW4gdmFyaW91cyBmb3JtYXRzIChlLmcuIEpQRUcsIFBORywgUERGLCBTVkcpLiBJdCBpbnRlZ3JhdGVzXHJcbiAqIHdpdGggSGlnaGNoYXJ0cycgY29yZSBmdW5jdGlvbmFsaXRpZXMgYW5kIHN1cHBvcnRzIGJvdGggaW1tZWRpYXRlIGRvd25sb2FkXHJcbiAqIHJlc3BvbnNlcyBhbmQgQmFzZTY0LWVuY29kZWQgY29udGVudCByZXR1cm5zLiBUaGUgY29kZSBhbHNvIGZlYXR1cmVzXHJcbiAqIGJlbmNobWFya2luZyBmb3IgcGVyZm9ybWFuY2UgbW9uaXRvcmluZy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QmFzZTY0LCBtZWFzdXJlVGltZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHJlcXVlc3QudmFsaWRhdGVkT3B0aW9ucztcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlcXVlc3QgaWRcclxuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHJlcXVlc3RPcHRpb25zLl9yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3JlcXVlc3RJZH0uYCk7XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChyZXF1ZXN0T3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbZXhwb3J0XSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuJyxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIaWdoY2hhcnRzVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBnZXRQb29sSW5mb0pTT04gfSBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgYWRkVGltZXIgfSBmcm9tICcuLi8uLi90aW1lci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSwgZ2V0TmV3RGF0ZVRpbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vLyBTZXQgdGhlIHN0YXJ0IGRhdGUgb2YgdGhlIHNlcnZlclxyXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xyXG5cclxuLy8gR2V0IHRoZSBgcGFja2FnZS5qc29uYCBjb250ZW50XHJcbmNvbnN0IHBhY2thZ2VGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuLy8gQW4gYXJyYXkgZm9yIHN1Y2Nlc3MgcmF0ZSByYXRpb3NcclxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XHJcblxyXG4vLyBSZWNvcmQgZXZlcnkgbWludXRlXHJcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwO1xyXG5cclxuLy8gMzAgbWludXRlc1xyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7XHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgYHN1Y2Nlc3NSYXRlc2BcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cclxuICovXHJcbmZ1bmN0aW9uIF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIHJldHVybiBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCkgLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG59XHJcblxyXG4vKipcclxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cclxuICogYW5kIGNvbGxlY3RzIHJlY29yZHMgdG8gdGhlIGBzdWNjZXNzUmF0ZXNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX3N0YXJ0U3VjY2Vzc1JhdGVcclxuICpcclxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlKCkge1xyXG4gIHJldHVybiBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IGdldFBvb2xTdGF0cygpO1xyXG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cclxuICAgICAgc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGBoZWFsdGhgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIGhlYWx0aFJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGhlYWx0aFJvdXRlcyhhcHApIHtcclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGBhZGRUaW1lcmAgZnVudGlvblxyXG4gIGFkZFRpbWVyKF9zdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBHRVQgJy9oZWFsdGgnIC0gQSByb3V0ZSBmb3IgZ2V0dGluZyB0aGUgYmFzaWMgc3RhdHMgb2YgdGhlIHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1toZWFsdGhdIFJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IF9jYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgICAvLyBTZW5kIHRoZSBzZXJ2ZXIncyBzdGF0aXN0aWNzXHJcbiAgICAgIHJlc3BvbnNlLnNlbmQoe1xyXG4gICAgICAgIC8vIFN0YXR1cyBhbmQgdGltZXNcclxuICAgICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcclxuICAgICAgICB1cHRpbWU6IGAke01hdGguZmxvb3IoKGdldE5ld0RhdGVUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MCl9IG1pbnV0ZXNgLFxyXG5cclxuICAgICAgICAvLyBWZXJzaW9uc1xyXG4gICAgICAgIHNlcnZlclZlcnNpb246IHBhY2thZ2VGaWxlLnZlcnNpb24sXHJcbiAgICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IGdldEhpZ2hjaGFydHNWZXJzaW9uKCksXHJcblxyXG4gICAgICAgIC8vIEV4cG9ydHNcclxuICAgICAgICBhdmVyYWdlRXhwb3J0VGltZTogc3RhdHMudGltZVNwZW50QXZlcmFnZSxcclxuICAgICAgICBhdHRlbXB0ZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkLFxyXG4gICAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQsXHJcbiAgICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZXhwb3J0c0Ryb3BwZWQsXHJcbiAgICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDAsXHJcblxyXG4gICAgICAgIC8vIFBvb2xcclxuICAgICAgICBwb29sOiBnZXRQb29sSW5mb0pTT04oKSxcclxuXHJcbiAgICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgICBwZXJpb2QsXHJcbiAgICAgICAgbW92aW5nQXZlcmFnZSxcclxuICAgICAgICBtZXNzYWdlOlxyXG4gICAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXHJcbiAgICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcclxuXHJcbiAgICAgICAgLy8gU1ZHIGFuZCBKU09OIGV4cG9ydHNcclxuICAgICAgICBzdmdFeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbVN2ZyxcclxuICAgICAgICBqc29uRXhwb3J0czogc3RhdHMuZXhwb3J0c0Zyb21PcHRpb25zLFxyXG4gICAgICAgIHN2Z0V4cG9ydHNBdHRlbXB0czogc3RhdHMuZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyxcclxuICAgICAgICBqc29uRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0c1xyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciBzZXJ2aW5nIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXJcclxuICogd2hlbiBlbmFibGVkLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHVpYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB1aVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHVpUm91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIEdFVCAnLycgLSBBIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cclxuICAgKi9cclxuICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpLCB7XHJcbiAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgIH1cclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgRGVmaW5lcyBhbiBFeHByZXNzIHJvdXRlIGZvciB1cGRhdGluZyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uXHJcbiAqIG9uIHRoZSBzZXJ2ZXIsIHdpdGggYXV0aGVudGljYXRpb24gYW5kIHZhbGlkYXRpb24uXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlSGlnaGNoYXJ0c1ZlcnNpb24sIGdldEhpZ2hjaGFydHNWZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGB2ZXJzaW9uX2NoYW5nZWAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKSB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAnL3ZlcnNpb25fY2hhbmdlLzpuZXdWZXJzaW9uJyAtIEEgcm91dGUgZm9yIGNoYW5naW5nXHJcbiAgICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nLCBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIEdldCB0aGUgdG9rZW4gZGlyZWN0bHkgZnJvbSBlbnZzXHJcbiAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICdbdmVyc2lvbl0gSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgNDAxXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgLy8gVXBkYXRlIHZlcnNpb25cclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uKG5ld1ZlcnNpb24pO1xyXG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgNDAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIaWdoY2hhcnRzVmVyc2lvbigpLFxyXG4gICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlIHNldHVwLCByb3V0ZSBkZWZpbml0aW9uLCBhbmQgcmF0ZVxyXG4gKiBsaW1pdGluZy4gVGhlIG1vZHVsZSBleHBvcnRzIGZ1bmN0aW9ucyB0byBzdGFydCwgc3RvcCwgYW5kIG1hbmFnZSBzZXJ2ZXJcclxuICogaW5zdGFuY2VzLCBhcyB3ZWxsIGFzIHV0aWxpdHkgZnVuY3Rpb25zIGZvciBkZWZpbmluZyByb3V0ZXMgYW5kIGF0dGFjaGluZ1xyXG4gKiBtaWRkbGV3YXJlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZSB9IGZyb20gJ2ZzL3Byb21pc2VzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XHJcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xyXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcclxuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcclxuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgZXJyb3JNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3JhdGVMaW1pdGluZy5qcyc7XHJcbmltcG9ydCB2YWxpZGF0aW9uTWlkZGxld2FyZSBmcm9tICcuL21pZGRsZXdhcmVzL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xyXG5pbXBvcnQgaGVhbHRoUm91dGVzIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlcyBmcm9tICcuL3JvdXRlcy91aS5qcyc7XHJcbmltcG9ydCB2ZXJzaW9uQ2hhbmdlUm91dGVzIGZyb20gJy4vcm91dGVzL3ZlcnNpb25DaGFuZ2UuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xyXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xyXG5cclxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXHJcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgSFRUUCBvci9hbmQgSFRUUFMgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLlxyXG4gKiBUaGUgYHNlcnZlck9wdGlvbnNgIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlXHJcbiAqIHRoZSBgc2VydmVyYCBzZWN0aW9uIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc3RhcnRTZXJ2ZXJcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IFtzZXJ2ZXJPcHRpb25zPWdldE9wdGlvbnMoKS5zZXJ2ZXJdIC0gT2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlcmAgb3B0aW9ucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlIGdsb2JhbCBzZXJ2ZXIgb3B0aW9uc1xyXG4gKiBvZiB0aGUgZXhwb3J0IHNlcnZlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGVuZGluZyB0aGUgZnVuY3Rpb25cclxuICogZXhlY3V0aW9uIHdoZW4gdGhlIHNlcnZlciBzaG91bGQgbm90IGJlIGVuYWJsZWQgb3Igd2hlbiBubyB2YWxpZCBFeHByZXNzIGFwcFxyXG4gKiBpcyBmb3VuZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBzZXJ2ZXIgY2Fubm90XHJcbiAqIGJlIGNvbmZpZ3VyZWQgYW5kIHN0YXJ0ZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRTZXJ2ZXIoc2VydmVyT3B0aW9ucyA9IGdldE9wdGlvbnMoKS5zZXJ2ZXIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IGF3YWl0IHJlYWRGaWxlKFxyXG4gICAgICAgICAgam9pbihnZXRBYnNvbHV0ZVBhdGgoc2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGgpLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgcmVhZEZpbGUoXHJcbiAgICAgICAgICBqb2luKGdldEFic29sdXRlUGF0aChzZXJ2ZXJPcHRpb25zLnNzbC5jZXJ0UGF0aCksICdzZXJ2ZXIuY3J0JyksXHJcbiAgICAgICAgICAndXRmOCdcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XHJcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxyXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XHJcblxyXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgICBfYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcclxuICAgICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgICBsb2coXHJcbiAgICAgICAgICAgIDMsXHJcbiAgICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlck9wdGlvbnMuaG9zdH06JHtzZXJ2ZXJPcHRpb25zLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSByYXRlIGxpbWl0ZXJcclxuICAgIHJhdGVMaW1pdGluZ01pZGRsZXdhcmUoYXBwLCBzZXJ2ZXJPcHRpb25zLnJhdGVMaW1pdGluZyk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSB2YWxpZGF0aW9uIGhhbmRsZXJcclxuICAgIHZhbGlkYXRpb25NaWRkbGV3YXJlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGVzKGFwcCk7XHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIHVpUm91dGVzKGFwcCk7XHJcbiAgICB2ZXJzaW9uQ2hhbmdlUm91dGVzKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHRoZSBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXHJcbiAgICBlcnJvck1pZGRsZXdhcmUoYXBwKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjbG9zZVNlcnZlcnNcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbG9zZVNlcnZlcnMoKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlcmUgYXJlIHNlcnZlcnMgd29ya2luZ1xyXG4gIGlmIChhY3RpdmVTZXJ2ZXJzLnNpemUgPiAwKSB7XHJcbiAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcblxyXG4gICAgLy8gQ2xvc2UgZWFjaCBvbmUgb2Ygc2VydmVyc1xyXG4gICAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XHJcbiAgICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XHJcbiAgICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICAgIH0pO1xyXG4gICAgfVxyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRTZXJ2ZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtBcnJheS48T2JqZWN0Pn0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0U2VydmVycygpIHtcclxuICByZXR1cm4gYWN0aXZlU2VydmVycztcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEV4cHJlc3NcclxuICpcclxuICogQHJldHVybnMge0V4cHJlc3N9IFRoZSBFeHByZXNzIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEV4cHJlc3MoKSB7XHJcbiAgcmV0dXJuIGV4cHJlc3M7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QXBwXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QXBwKCkge1xyXG4gIHJldHVybiBhcHA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmF0ZUxpbWl0aW5nT3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGByYXRlTGltaXRpbmdgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nKHJhdGVMaW1pdGluZ09wdGlvbnMpIHtcclxuICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIHVzZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KGh0dHAuU2VydmVyfGh0dHBzLlNlcnZlcil9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKHNlcnZlcikge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIYW5kbGVzIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIsIGVuc3VyaW5nXHJcbiAqIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlcyBzdWNoIGFzIGJyb3dzZXIsIHBhZ2VzLCBzZXJ2ZXJzLCBhbmQgdGltZXJzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVyLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBDbGVhbnMgdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bFxyXG4gKiBzaHV0ZG93bi5cclxuICpcclxuICogQGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBgcHJvY2Vzcy5leGl0KClgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcChleGl0Q29kZSkge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgYW4gYWN0aXZlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb3JlIG1vZHVsZSBmb3IgaW5pdGlhbGl6aW5nIGFuZCBtYW5hZ2luZyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnRcclxuICogU2VydmVyLiBQcm92aWRlcyBmdW5jdGlvbmFsaXRpZXMgZm9yIGNvbmZpZ3VyaW5nIGV4cG9ydHMsIHNldHRpbmcgdXAgc2VydmVyXHJcbiAqIG9wZXJhdGlvbnMsIGxvZ2dpbmcsIHNjcmlwdHMgY2FjaGluZywgcmVzb3VyY2UgcG9vbGluZywgYW5kIGdyYWNlZnVsIHByb2Nlc3NcclxuICogY2xlYW51cC5cclxuICovXHJcblxyXG5pbXBvcnQgJ2NvbG9ycyc7XHJcblxyXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7XHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59IGZyb20gJy4vY2hhcnQuanMnO1xyXG5pbXBvcnQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zXHJcbn0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlUmVsZWFzZS5qcyc7XHJcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT3B0aW9ucyAtIFRoZSBgY3VzdG9tT3B0aW9uc2Agb2JqZWN0LCB3aGljaCBtYXlcclxuICogYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlIHNldCBvZiBvcHRpb25zLiBJZiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhcmUgcGFydGlhbCxcclxuICogbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgZGVmYXVsdCBnZW5lcmFsIG9wdGlvbnMsIHJldHJpZXZlZFxyXG4gKiB1c2luZyB0aGUgYGdldE9wdGlvbnNgIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoY3VzdG9tT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IGNvcHkgYW5kIGV4dGVuZCBpdCB3aXRoIHRoZSBpbmNvbWluZyBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlT3B0aW9ucyhnZXRPcHRpb25zKGZhbHNlKSwgY3VzdG9tT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24pO1xyXG5cclxuICAvLyBJbml0IHRoZSBsb2dnaW5nXHJcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcclxuXHJcbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXHJcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcclxuICAgIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJ1xyXG4gKiBhbmQgJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnNcclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpIHtcclxuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcclxuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgW3Byb2Nlc3NdIFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gT3B0aW9uc1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgc2V0T3B0aW9ucyxcclxuICBtZXJnZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gQ2FjaGVcclxuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxyXG5cclxuICAvLyBQb29sXHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBzaHV0ZG93bkNsZWFuVXBcclxufTtcclxuIl0sIm5hbWVzIjpbIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImRlZXBDb3B5Iiwib2JqQXJyIiwib2JqQXJyQ29weSIsIkFycmF5IiwiaXNBcnJheSIsImtleSIsIk9iamVjdCIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsImZpeENvbnN0ciIsImNvbnN0ciIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJyZXBsYWNlIiwiaW5jbHVkZXMiLCJmaXhPdXRmaWxlIiwidHlwZSIsIm91dGZpbGUiLCJnZXRBYnNvbHV0ZVBhdGgiLCJzcGxpdCIsInNoaWZ0IiwiZml4VHlwZSIsIm1pbWVUeXBlcyIsImZvcm1hdHMiLCJ2YWx1ZXMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJwYXRoIiwiaXNBYnNvbHV0ZSIsImpvaW4iLCJnZXRCYXNlNjQiLCJpbnB1dCIsIkJ1ZmZlciIsImZyb20iLCJ0b1N0cmluZyIsImdldE5ld0RhdGUiLCJEYXRlIiwidHJpbSIsImdldE5ld0RhdGVUaW1lIiwiZ2V0VGltZSIsImlzT2JqZWN0IiwiaXRlbSIsImlzT2JqZWN0RW1wdHkiLCJrZXlzIiwibGVuZ3RoIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsInNvbWUiLCJwYXR0ZXJuIiwidGVzdCIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJwcm9jZXNzIiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwicm91bmROdW1iZXIiLCJ2YWx1ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJNYXRoIiwicG93Iiwicm91bmQiLCJ3cmFwQXJvdW5kIiwiY3VzdG9tQ29kZSIsImFsbG93RmlsZVJlc291cmNlcyIsImlzQ2FsbGJhY2siLCJlbmRzV2l0aCIsInJlYWRGaWxlU3luYyIsInN0YXJ0c1dpdGgiLCJjb2xvcnMiLCJsb2dnaW5nIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJwYXRoVG9Mb2ciLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxvZyIsImFyZ3MiLCJuZXdMZXZlbCIsInRleHRzIiwibGV2ZWwiLCJwcmVmaXgiLCJfbG9nVG9GaWxlIiwiY29uc29sZSIsImFwcGx5IiwidW5kZWZpbmVkIiwiY29uY2F0IiwibG9nV2l0aFN0YWNrIiwiZXJyb3IiLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJtZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJwdXNoIiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJpbml0TG9nZ2luZyIsImxvZ2dpbmdPcHRpb25zIiwiZGVzdCIsImZpbGUiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUNvbnNvbGVMb2dnaW5nIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJ0eXBlcyIsImVudkxpbmsiLCJjbGlOYW1lIiwiZGVzY3JpcHRpb24iLCJwcm9tcHRPcHRpb25zIiwic2VwYXJhdG9yIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJjZG5VcmwiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiY29yZVNjcmlwdHMiLCJpbnN0cnVjdGlvbnMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJzdmciLCJiYXRjaCIsImhpbnQiLCJjaG9pY2VzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwibWluIiwibWF4IiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJjb25maWciLCJwcm9wQ2hhaW4iLCJmb3JFYWNoIiwiZW50cnkiLCJzdWJzdHJpbmciLCJkb3RlbnYiLCJ6Iiwic2V0RXJyb3JNYXAiLCJfY3VzdG9tRXJyb3JNYXAiLCJ2IiwiYm9vbGVhbiIsInN0cmljdENoZWNrIiwidW5pb24iLCJlbnVtIiwidHJhbnNmb3JtIiwibnVsbGFibGUiLCJzdHJpbmciLCJyZWZpbmUiLCJwYXJhbXMiLCJlcnJvck1lc3NhZ2UiLCJzdHJpbmdBcnJheSIsImZpbHRlckNhbGxiYWNrIiwiYXJyYXlTY2hlbWEiLCJhcnJheSIsInN0cmluZ1NjaGVtYSIsInNsaWNlIiwidHJhbnNmb3JtQ2FsbGJhY2siLCJmaWx0ZXIiLCJwb3NpdGl2ZU51bSIsIm51bWJlciIsInBvc2l0aXZlIiwiaXNOYU4iLCJub25OZWdhdGl2ZU51bSIsIm5vbm5lZ2F0aXZlIiwicHJlZml4ZXMiLCJjaGFydENvbmZpZyIsImluZGV4T2YiLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwiYWRtaW5Ub2tlbiIsImd0ZSIsImx0ZSIsInRoaXMiLCJvYmplY3RTY2hlbWEiLCJqcyIsImNzcyIsImZpbGVzIiwicGFydGlhbCIsInN0cmluZ1NjaGVtYTEiLCJzdHJpbmdTY2hlbWEyIiwiZW5hYmxlU2VydmVyIiwic2VydmVyQmVuY2htYXJraW5nIiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwicHJveHlUaW1lb3V0IiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZW5hYmxlU3NsIiwic3NsRm9yY2UiLCJzc2xQb3J0Iiwic3NsQ2VydFBhdGgiLCJwb29sQmVuY2htYXJraW5nIiwicmVzb3VyY2VzSW50ZXJ2YWwiLCJsb2dMZXZlbCIsImludCIsImlzSW50ZWdlciIsImxvZ0ZpbGUiLCJsb2dEZXN0IiwibG9nVG9Db25zb2xlIiwibG9nVG9GaWxlIiwiZW5hYmxlVWkiLCJ1aVJvdXRlIiwiZW5hYmxlRGVidWciLCJyZXF1ZXN0SWQiLCJ1dWlkIiwiUHVwcGV0ZWVyU2NoZW1hIiwiSGlnaGNoYXJ0c1NjaGVtYSIsIkV4cG9ydFNjaGVtYSIsIkN1c3RvbUxvZ2ljU2NoZW1hIiwiUHJveHlTY2hlbWEiLCJSYXRlTGltaXRpbmdTY2hlbWEiLCJTc2xTY2hlbWEiLCJTZXJ2ZXJTY2hlbWEiLCJvcHRpb25hbCIsIlBvb2xTY2hlbWEiLCJMb2dnaW5nU2NoZW1hIiwiVWlTY2hlbWEiLCJPdGhlclNjaGVtYSIsIkRlYnVnU2NoZW1hIiwiU3RyaWN0Q29uZmlnU2NoZW1hIiwiTG9vc2VDb25maWdTY2hlbWEiLCJFbnZTY2hlbWEiLCJQVVBQRVRFRVJfQVJHUyIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsIkhJR0hDSEFSVFNfQ0ROX1VSTCIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfQ1VTVE9NX1NDUklQVFMiLCJFWFBPUlRfSU5GSUxFIiwiRVhQT1JUX0lOU1RSIiwiRVhQT1JUX09QVElPTlMiLCJFWFBPUlRfU1ZHIiwiRVhQT1JUX0JBVENIIiwiRVhQT1JUX09VVEZJTEUiLCJFWFBPUlRfVFlQRSIsIkVYUE9SVF9DT05TVFIiLCJFWFBPUlRfQjY0IiwiRVhQT1JUX05PX0RPV05MT0FEIiwiRVhQT1JUX0hFSUdIVCIsIkVYUE9SVF9XSURUSCIsIkVYUE9SVF9TQ0FMRSIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfR0xPQkFMX09QVElPTlMiLCJFWFBPUlRfVEhFTUVfT1BUSU9OUyIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUiLCJDVVNUT01fTE9HSUNfQ0FMTEJBQ0siLCJDVVNUT01fTE9HSUNfUkVTT1VSQ0VTIiwiQ1VTVE9NX0xPR0lDX0xPQURfQ09ORklHIiwiQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUciLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9VUExPQURfTElNSVQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwidmFsaWRhdGVPcHRpb24iLCJuYW1lIiwib3B0aW9uIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiaW5kZXgiLCJfaW5pdEdsb2JhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwiZ2V0UmVmZXJlbmNlIiwic2V0T3B0aW9ucyIsImN1c3RvbU9wdGlvbnMiLCJjbGlBcmdzIiwibW9kaWZ5R2xvYmFsIiwiY2xpT3B0aW9ucyIsIl9sb2FkQ29uZmlnRmlsZSIsIl9wYWlyQXJndW1lbnRWYWx1ZSIsImdlbmVyYWxPcHRpb25zIiwiX3VwZGF0ZU9wdGlvbnMiLCJtZXJnZU9wdGlvbnMiLCJvcmlnaW5hbE9wdGlvbnMiLCJuZXdPcHRpb25zIiwiZW50cmllcyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJyZWR1Y2UiLCJvYmoiLCJwcm9wIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJjb25maWdPcHQiLCJjdXN0b21PcHQiLCJjbGlPcHQiLCJjb25maWdWYWwiLCJjdXN0b21WYWwiLCJjbGlWYWwiLCJlbnZWYWwiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwiRXJyb3IiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImNvbmZpZ0ZpbGVOYW1lIiwiaSIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwiX2dldFByb3RvY29sTW9kdWxlIiwiZ2V0IiwicmVzcG9uc2UiLCJyZXNwb25zZURhdGEiLCJvbiIsImNodW5rIiwidGV4dCIsImh0dHBzIiwiaHR0cCIsIkV4cG9ydEVycm9yIiwiY29uc3RydWN0b3IiLCJzdGF0dXNDb2RlIiwic3VwZXIiLCJzZXRFcnJvciIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImhpZ2hjaGFydHNPcHRpb25zIiwic2VydmVyUHJveHlPcHRpb25zIiwiZmV0Y2hlZE1vZHVsZXMiLCJnZXRDYWNoZVBhdGgiLCJtYW5pZmVzdFBhdGgiLCJzb3VyY2VQYXRoIiwicmVjdXJzaXZlIiwiX3VwZGF0ZUNhY2hlIiwicmVxdWVzdFVwZGF0ZSIsIm1hbmlmZXN0IiwibW9kdWxlcyIsIm1vZHVsZU1hcCIsIm0iLCJudW1iZXJPZk1vZHVsZXMiLCJtb2R1bGVOYW1lIiwiZXh0cmFjdFZlcnNpb24iLCJfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRIaWdoY2hhcnRzVmVyc2lvbiIsInVwZGF0ZUhpZ2hjaGFydHNWZXJzaW9uIiwibmV3VmVyc2lvbiIsImNhY2hlU291cmNlcyIsImV4dHJhY3RNb2R1bGVOYW1lIiwic2NyaXB0UGF0aCIsIl9mZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJzaG91bGRUaHJvd0Vycm9yIiwibmV3TWFuaWZlc3QiLCJ3cml0ZUZpbGVTeW5jIiwiX2ZldGNoU2NyaXB0cyIsInByb3h5QWdlbnQiLCJIdHRwc1Byb3h5QWdlbnQiLCJhZ2VudCIsImFsbEZldGNoUHJvbWlzZXMiLCJhbGwiLCJjIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwibWVyZ2UiLCJ3cmFwIiwic2V0T3B0aW9uc09iaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwiYW5pbWF0aW9uIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJjaGFydCIsIkZ1bmN0aW9uIiwiZmluYWxPcHRpb25zIiwiZmluYWxDYWxsYmFjayIsImRlZmF1bHRPcHRpb25zIiwidGVtcGxhdGUiLCJicm93c2VyIiwiY3JlYXRlQnJvd3NlciIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwic2V0VGltZW91dCIsImNsb3NlQnJvd3NlciIsImNvbm5lY3RlZCIsImNsb3NlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJfc2V0UGFnZUNvbnRlbnQiLCJfc2V0UGFnZUV2ZW50cyIsImlzQ2xvc2VkIiwiY2xlYXJQYWdlIiwiaGFyZFJlc2V0IiwiZ290byIsIndhaXRVbnRpbCIsImV2YWx1YXRlIiwiYm9keSIsImlubmVySFRNTCIsImlkIiwid29ya0NvdW50IiwiYWRkUGFnZVJlc291cmNlcyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImluamVjdGVkUmVzb3VyY2VzIiwiaW5qZWN0ZWRKcyIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImFkZFNjcmlwdFRhZyIsImluamVjdGVkQ3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJjbGVhclBhZ2VSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsImVsZW1lbnQiLCJyZW1vdmUiLCJzZXRDb250ZW50IiwiY3NzVGVtcGxhdGUiLCJzdmdUZW1wbGF0ZSIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJpc1NWRyIsIl9zZXRBc1N2ZyIsIl9zZXRBc09wdGlvbnMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwicGFyc2VGbG9hdCIsIngiLCJ5IiwiX2dldENsaXBSZWdpb24iLCJ2aWV3cG9ydEhlaWdodCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwicmVzdWx0Iiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsIm91dGVySFRNTCIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImVuY29kaW5nIiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwicG9vbFN0YXRzIiwiZXhwb3J0c0F0dGVtcHRlZCIsImV4cG9ydHNQZXJmb3JtZWQiLCJleHBvcnRzRHJvcHBlZCIsImV4cG9ydHNGcm9tU3ZnIiwiZXhwb3J0c0Zyb21PcHRpb25zIiwiZXhwb3J0c0Zyb21TdmdBdHRlbXB0cyIsImV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzIiwidGltZVNwZW50IiwidGltZVNwZW50QXZlcmFnZSIsImluaXRQb29sIiwicG9vbE9wdGlvbnMiLCJQb29sIiwiX2ZhY3RvcnkiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiY2xlYXJTdGF0dXMiLCJfZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJfcmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFRpbWUiLCJnZXRQb29sU3RhdHMiLCJnZXRQb29sSW5mb0pTT04iLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwibnVtRnJlZSIsImFsbENyZWF0ZWQiLCJwZW5kaW5nQWNxdWlyZXMiLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwZW5kaW5nQ3JlYXRlcyIsIm51bVBlbmRpbmdDcmVhdGVzIiwicGVuZGluZ1ZhbGlkYXRpb25zIiwibnVtUGVuZGluZ1ZhbGlkYXRpb25zIiwicGVuZGluZ0Rlc3Ryb3lzIiwiYWJzb2x1dGVBbGwiLCJjcmVhdGUiLCJyYW5kb20iLCJzdGFydERhdGUiLCJ2YWxpZGF0ZSIsIm1haW5GcmFtZSIsImRldGFjaGVkIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwic2FuaXRpemUiLCJKU0RPTSIsIkRPTVB1cmlmeSIsIkFERF9UQUdTIiwic2luZ2xlRXhwb3J0Iiwic3RhcnRFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImJhdGNoUmVzdWx0cyIsImFsbFNldHRsZWQiLCJyZWFzb24iLCJlbmRDYWxsYmFjayIsImZpbGVDb250ZW50IiwiX2V4cG9ydEZyb21TdmciLCJfZXhwb3J0RnJvbU9wdGlvbnMiLCJnZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJzZXRBbGxvd0NvZGVFeGVjdXRpb24iLCJpbnB1dFRvRXhwb3J0IiwiX3ByZXBhcmVFeHBvcnQiLCJfaGFuZGxlQ3VzdG9tTG9naWMiLCJfaGFuZGxlR2xvYmFsQW5kVGhlbWUiLCJfZmluZENoYXJ0U2l6ZSIsIm9wdGlvbnNDaGFydCIsIm9wdGlvbnNFeHBvcnRpbmciLCJnbG9iYWxPcHRpb25zQ2hhcnQiLCJnbG9iYWxPcHRpb25zRXhwb3J0aW5nIiwidGhlbWVPcHRpb25zQ2hhcnQiLCJ0aGVtZU9wdGlvbnNFeHBvcnRpbmciLCJzb3VyY2VIZWlnaHQiLCJzb3VyY2VXaWR0aCIsInBhcmFtIiwiX2hhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwicHJvcE5hbWUiLCJvcHRpb25zTmFtZSIsInRpbWVySWRzIiwiYWRkVGltZXIiLCJjbGVhckFsbFRpbWVycyIsImNsZWFySW50ZXJ2YWwiLCJjbGVhclRpbWVvdXQiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXF1ZXN0IiwibmV4dCIsInJldHVybkVycm9yTWlkZGxld2FyZSIsInN0YXR1cyIsImpzb24iLCJlcnJvck1pZGRsZXdhcmUiLCJhcHAiLCJ1c2UiLCJyYXRlTGltaXRpbmdNaWRkbGV3YXJlIiwicmF0ZUxpbWl0aW5nT3B0aW9ucyIsIm1zZyIsInJhdGVPcHRpb25zIiwibGltaXRlciIsInJhdGVMaW1pdCIsIndpbmRvd01zIiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRzIiwianNvbkV4cG9ydHMiLCJzdmdFeHBvcnRzQXR0ZW1wdHMiLCJqc29uRXhwb3J0c0F0dGVtcHRzIiwidWlSb3V0ZXMiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInZlcnNpb25DaGFuZ2VSb3V0ZXMiLCJ0b2tlbiIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJPcHRpb25zIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwiZGlzYWJsZSIsImNvcnMiLCJtZXRob2RzIiwic2V0IiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsInJlYWRGaWxlIiwiaHR0cHNTZXJ2ZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJleGl0IiwiaW5pdEV4cG9ydCIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6InduQkEyQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 4d431f2..da49e7b 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},r=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return o[e]||r.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:r,level:n}=logging;if(5!==t&&(0===t||t>n||n>r.length))return;const i=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t.message,{level:n,levelsDesc:i}=logging;if(0===e||e>n||n>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[r];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:n,toFile:i}=e;setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const n=e[r];void 0===n.value?_createNestedProps(n,t,`${o}.${r}`):(t[n.cliName||r]=`${o}.${r}`.substring(1),void 0!==n.legacyName&&(t[n.legacyName]=`${o}.${r}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const r=e[o];void 0===r.types?_createAbsoluteProps(r,t):r.types.includes("Object")&&t.push(o)})),t}dotenv.config();const v={array:e=>z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),boolean:()=>z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),enum:e=>z.enum([...e,""]).transform((e=>""!==e?e:void 0)),string:()=>z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),positiveNum:()=>z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),nonNegativeNum:()=>z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0))},Config=z.object({PUPPETEER_ARGS:v.string(),HIGHCHARTS_VERSION:z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_FORCE_FETCH:v.boolean(),HIGHCHARTS_CACHE_PATH:v.string(),HIGHCHARTS_ADMIN_TOKEN:v.string(),HIGHCHARTS_CORE_SCRIPTS:v.array(defaultConfig.highcharts.coreScripts.value),HIGHCHARTS_MODULE_SCRIPTS:v.array(defaultConfig.highcharts.moduleScripts.value),HIGHCHARTS_INDICATOR_SCRIPTS:v.array(defaultConfig.highcharts.indicatorScripts.value),HIGHCHARTS_CUSTOM_SCRIPTS:v.array(defaultConfig.highcharts.customScripts.value),EXPORT_INFILE:v.string(),EXPORT_INSTR:v.string(),EXPORT_OPTIONS:v.string(),EXPORT_SVG:v.string(),EXPORT_BATCH:v.string(),EXPORT_OUTFILE:v.string(),EXPORT_TYPE:v.enum(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:v.enum(["chart","stockChart","mapChart","ganttChart"]),EXPORT_B64:v.boolean(),EXPORT_NO_DOWNLOAD:v.boolean(),EXPORT_HEIGHT:v.positiveNum(),EXPORT_WIDTH:v.positiveNum(),EXPORT_SCALE:v.positiveNum(),EXPORT_DEFAULT_HEIGHT:v.positiveNum(),EXPORT_DEFAULT_WIDTH:v.positiveNum(),EXPORT_DEFAULT_SCALE:v.positiveNum(),EXPORT_GLOBAL_OPTIONS:v.string(),EXPORT_THEME_OPTIONS:v.string(),EXPORT_RASTERIZATION_TIMEOUT:v.nonNegativeNum(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:v.boolean(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:v.boolean(),CUSTOM_LOGIC_CUSTOM_CODE:v.string(),CUSTOM_LOGIC_CALLBACK:v.string(),CUSTOM_LOGIC_RESOURCES:v.string(),CUSTOM_LOGIC_LOAD_CONFIG:v.string(),CUSTOM_LOGIC_CREATE_CONFIG:v.string(),SERVER_ENABLE:v.boolean(),SERVER_HOST:v.string(),SERVER_PORT:v.positiveNum(),SERVER_UPLOAD_LIMIT:v.positiveNum(),SERVER_BENCHMARKING:v.boolean(),SERVER_PROXY_HOST:v.string(),SERVER_PROXY_PORT:v.positiveNum(),SERVER_PROXY_TIMEOUT:v.nonNegativeNum(),SERVER_RATE_LIMITING_ENABLE:v.boolean(),SERVER_RATE_LIMITING_MAX_REQUESTS:v.nonNegativeNum(),SERVER_RATE_LIMITING_WINDOW:v.nonNegativeNum(),SERVER_RATE_LIMITING_DELAY:v.nonNegativeNum(),SERVER_RATE_LIMITING_TRUST_PROXY:v.boolean(),SERVER_RATE_LIMITING_SKIP_KEY:v.string(),SERVER_RATE_LIMITING_SKIP_TOKEN:v.string(),SERVER_SSL_ENABLE:v.boolean(),SERVER_SSL_FORCE:v.boolean(),SERVER_SSL_PORT:v.positiveNum(),SERVER_SSL_CERT_PATH:v.string(),POOL_MIN_WORKERS:v.nonNegativeNum(),POOL_MAX_WORKERS:v.nonNegativeNum(),POOL_WORK_LIMIT:v.positiveNum(),POOL_ACQUIRE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_TIMEOUT:v.nonNegativeNum(),POOL_DESTROY_TIMEOUT:v.nonNegativeNum(),POOL_IDLE_TIMEOUT:v.nonNegativeNum(),POOL_CREATE_RETRY_INTERVAL:v.nonNegativeNum(),POOL_REAPER_INTERVAL:v.nonNegativeNum(),POOL_BENCHMARKING:v.boolean(),LOGGING_LEVEL:z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:v.string(),LOGGING_DEST:v.string(),LOGGING_TO_CONSOLE:v.boolean(),LOGGING_TO_FILE:v.boolean(),UI_ENABLE:v.boolean(),UI_ROUTE:v.string(),OTHER_NODE_ENV:v.enum(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:v.boolean(),OTHER_NO_LOGO:v.boolean(),OTHER_HARD_RESET_PAGE:v.boolean(),OTHER_BROWSER_SHELL_MODE:v.boolean(),DEBUG_ENABLE:v.boolean(),DEBUG_HEADLESS:v.boolean(),DEBUG_DEVTOOLS:v.boolean(),DEBUG_LISTEN_TO_CONSOLE:v.boolean(),DEBUG_DUMPIO:v.boolean(),DEBUG_SLOW_MO:v.nonNegativeNum(),DEBUG_DEBUGGING_PORT:v.positiveNum()}),envs=Config.partial().parse(process.env),globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let r={},n={};t.length&&(r=_loadConfigFile(t),n=_pairArgumentValue(nestedProps,t));const i=getOptions(o);return _updateOptions(defaultConfig,i,r,e,n),i}function mergeOptions(e,t){if(isObject(t))for(const[o,r]of Object.entries(t))e[o]=isObject(r)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],r):void 0!==r?r:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,n)=>t[o]=e.length-1===n?r:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:_initGlobalOptions(r);return t}function _updateOptions(e,t,o,r,n){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=r&&r[i],c=n&&n[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,r)=>{if("string"==typeof r&&(r=r.trim()),"function"==typeof r||"string"==typeof r&&r.startsWith("function")&&r.endsWith("}")){if(t)return o?`"EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(r+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return r})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let r=0;r{if(i.length-1===s){const i=t[++r];i||log(2,`[config] Missing value for the CLI '--${n}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,r)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const r=getCachePath(),n=join(r,"manifest.json"),i=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(n)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let r=!1;const s=JSON.parse(readFileSync(n));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),r=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),r=!0):r=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),r?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const n=await fetch(`${e}.js`,t);if(200===n.statusCode&&"string"==typeof n.text){if(o){o[extractModuleName(e)]=1}return n.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${n.statusCode}).`,404).setError(n);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,r,n){let i;const s=r.host,a=r.port;if(s&&a)try{i=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:r.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,n,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,n))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const r="latest"===e.version?null:`${e.version}`,n=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>r?`${n}/${r}/${e}`:`${n}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`)),...e.indicatorScripts.map((e=>r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:r,wrap:n}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,r){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,r])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&r(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...n}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&n};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),r&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],r=t.resources;if(r){const n=[];if(r.js&&n.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");n.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of n)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}n.length=0;const i=[];if(r.css){let n=r.css.match(/@import\s*([^;]*);/g);if(n)for(let e of n)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:join(__dirname,e)}));i.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const r of[...e,...t,...o])r.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const r=t.export;let n=!1;if(r.svg){if(log(4,"[export] Treating as SVG input."),"svg"===r.type)return r.svg;n=!0,await _setAsSvg(e,r.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=n?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,r=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:r}}),parseFloat(r.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||r.height)),c=Math.abs(Math.ceil(i.chartWidth||r.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(r.scale)}),r.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,r.type,{width:c,height:l,x:s,y:a},r.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,r.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${r.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:n}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(n>1?n:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,r){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),r||1500)))])}async function _createPDF(e,t,o,r){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:r||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const r=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const n=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${n()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${n()}ms.`),pool.release(t);const s=getNewDateTime()-r;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:r,allCreated:n,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${r}.`),log(5,`[pool] The number of all created (used and free) resources: ${n}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):writeFileSync(r||`chart.${n}`,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:n}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,n)):writeFileSync(r,"svg"!==n?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),r=o.export;if(null!==r.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(r.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(r.infile.endsWith(".svg"))r.svg=e;else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=e}}if(null!==r.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(r.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==r.instr||null!==r.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(r.instr||r.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)},postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const r=["js","css","files"];let n=e,i=!1;if(t&&e.endsWith(".json"))try{n=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else n=isAllowedConfig(e,!1,o),n&&!t&&delete n.files;for(const e in n)r.includes(e)?i||(i=!0):delete n[e];return i?(n.files&&(n.files=n.files.map((e=>e.trim())),(!n.files||n.files.length<=0)&&delete n.files),n):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((r=>{try{e[r]&&(t&&"string"==typeof e[r]&&e[r].endsWith(".json")?e[r]=isAllowedConfig(readFileSync(getAbsolutePath(e[r]),"utf8"),!0,o):e[r]=isAllowedConfig(e[r],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${r}\` cannot be loaded.`),e[r]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,r){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,r(e)}function returnErrorMiddleware(e,t,o,r){const{message:n,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:n,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(n),log(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,r=v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const n=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,n);if(null===i&&!t.svg)throw log(2,`[validation] Request [${r}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);return e.validatedOptions={_requestId:r,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,n),themeOptions:isAllowedConfig(t.themeOptions,!0,n)},customLogic:{allowCodeExecution:n,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,n)}},o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let r=!1;e.socket.on("close",(e=>{e&&(r=!0)}));const n=e.validatedOptions,i=n._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(n,((n,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(n)throw n;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:n,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),n||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,r=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:r,message:isNaN(r)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${r.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(n)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),r=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(r.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(r),r.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,r),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};export{index as default,initExport}; +import"colors";import{readFileSync,existsSync,mkdirSync,appendFile,writeFileSync}from"fs";import{isAbsolute,join}from"path";import{HttpsProxyAgent}from"https-proxy-agent";import{fileURLToPath}from"url";import dotenv from"dotenv";import{z}from"zod";import http from"http";import https from"https";import{Pool}from"tarn";import{v4}from"uuid";import puppeteer from"puppeteer";import DOMPurify from"dompurify";import{JSDOM}from"jsdom";import{readFile}from"fs/promises";import cors from"cors";import express from"express";import multer from"multer";import rateLimit from"express-rate-limit";const __dirname=fileURLToPath(new URL("../.",import.meta.url));function deepCopy(e){if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const o in e)Object.prototype.hasOwnProperty.call(e,o)&&(t[o]=deepCopy(e[o]));return t}function fixConstr(e){try{const t=`${e.toLowerCase().replace("chart","")}Chart`;return"Chart"===t&&t.toLowerCase(),["chart","stockChart","mapChart","ganttChart"].includes(t)?t:"chart"}catch{return"chart"}}function fixOutfile(e,t){return`${getAbsolutePath(t||"chart").split(".").shift()}.${e}`}function fixType(e,t=null){const o={"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"},n=Object.values(o);if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":n.includes(o)&&e!==o&&(e=o)}return o[e]||n.find((t=>t===e))||"png"}function getAbsolutePath(e){return isAbsolute(e)?e:join(__dirname,e)}function getBase64(e,t){return"pdf"===t||"svg"==t?Buffer.from(e,"utf8").toString("base64"):e}function getNewDate(){return(new Date).toString().split("(")[0].trim()}function getNewDateTime(){return(new Date).getTime()}function isObject(e){return"[object Object]"===Object.prototype.toString.call(e)}function isObjectEmpty(e){return"object"==typeof e&&!Array.isArray(e)&&null!==e&&0===Object.keys(e).length}function isPrivateRangeUrlFound(e){return[/xlink:href="(?:http:\/\/|https:\/\/)?localhost\b/,/xlink:href="(?:http:\/\/|https:\/\/)?10\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?127\.\d{1,3}\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?172\.(1[6-9]|2[0-9]|3[0-1])\.\d{1,3}\.\d{1,3}\b/,/xlink:href="(?:http:\/\/|https:\/\/)?192\.168\.\d{1,3}\.\d{1,3}\b/].some((t=>t.test(e)))}function measureTime(){const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6}function roundNumber(e,t=1){const o=Math.pow(10,t||0);return Math.round(+e*o)/o}function wrapAround(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?wrapAround(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}const colors=["red","yellow","blue","gray","green"],logging={toConsole:!0,toFile:!1,pathCreated:!1,pathToLog:"",levelsDesc:[{title:"error",color:colors[0]},{title:"warning",color:colors[1]},{title:"notice",color:colors[2]},{title:"verbose",color:colors[3]},{title:"benchmark",color:colors[4]}]};function log(...e){const[t,...o]=e,{levelsDesc:n,level:r}=logging;if(5!==t&&(0===t||t>r||r>n.length))return;const i=`${getNewDate()} [${n[t-1].title}] -`;logging.toFile&&_logToFile(o,i),logging.toConsole&&console.log.apply(void 0,[i.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const n=o||t.message,{level:r,levelsDesc:i}=logging;if(0===e||e>r||r>i.length)return;const s=`${getNewDate()} [${i[e-1].title}] -`,a=t.stack,l=[n];a&&l.push("\n",a),logging.toFile&&_logToFile(l,s),logging.toConsole&&console.log.apply(void 0,[s.toString()[logging.levelsDesc[e-1].color]].concat([l.shift()[colors[e-1]],...l]))}function logZodIssues(e,t=[],o){logWithStack(e,null,[`${o} - the following Zod issues occured:`,...t.map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:n,toConsole:r,toFile:i}=e;setLogLevel(t),enableConsoleLogging(r),enableFileLogging(o,n,i)}function setLogLevel(e){e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=e}function enableFileLogging(e,t,o){logging.toFile=o,o&&(logging.dest=e,logging.file=t)}function _logToFile(e,t){logging.pathCreated||(!existsSync(getAbsolutePath(logging.dest))&&mkdirSync(getAbsolutePath(logging.dest)),logging.pathToLog=getAbsolutePath(join(logging.dest,logging.file)),logging.pathCreated=!0),appendFile(logging.pathToLog,[t].concat(e).join(" ")+"\n",(e=>{e&&logging.toFile&&logging.pathCreated&&(logging.toFile=!1,logging.pathCreated=!1,logWithStack(2,e,"[logger] Unable to write to log file."))}))}const defaultConfig={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],types:["string[]"],envLink:"PUPPETEER_ARGS",cliName:"puppeteerArgs",description:"Array of Puppeteer arguments",promptOptions:{type:"list",separator:";"}}},highcharts:{version:{value:"latest",types:["string"],envLink:"HIGHCHARTS_VERSION",description:"Highcharts version",promptOptions:{type:"text"}},cdnUrl:{value:"https://code.highcharts.com",types:["string"],envLink:"HIGHCHARTS_CDN_URL",description:"CDN URL for Highcharts scripts",promptOptions:{type:"text"}},forceFetch:{value:!1,types:["boolean"],envLink:"HIGHCHARTS_FORCE_FETCH",description:"Flag to refetch scripts after each server rerun",promptOptions:{type:"toggle"}},cachePath:{value:".cache",types:["string"],envLink:"HIGHCHARTS_CACHE_PATH",description:"Directory path for cached Highcharts scripts",promptOptions:{type:"text"}},coreScripts:{value:["highcharts","highcharts-more","highcharts-3d"],types:["string[]"],envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"Highcharts core scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},moduleScripts:{value:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],types:["string[]"],envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"Highcharts module scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},indicatorScripts:{value:["indicators-all"],types:["string[]"],envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"Highcharts indicator scripts to fetch",promptOptions:{type:"multiselect",instructions:"Space: Select specific, A: Select all, Enter: Confirm"}},customScripts:{value:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"],types:["string[]"],envLink:"HIGHCHARTS_CUSTOM_SCRIPTS",description:"Additional custom scripts or dependencies to fetch",promptOptions:{type:"list",separator:";"}}},export:{infile:{value:null,types:["string","null"],envLink:"EXPORT_INFILE",description:"Input filename with type, formatted correctly as JSON or SVG",promptOptions:{type:"text"}},instr:{value:null,types:["string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","null"],envLink:"EXPORT_OPTIONS",description:"Alias for the `instr` option",promptOptions:{type:"text"}},svg:{value:null,types:["string","null"],envLink:"EXPORT_SVG",description:"SVG string representation of the chart to render",promptOptions:{type:"text"}},batch:{value:null,types:["string","null"],envLink:"EXPORT_BATCH",description:'Batch job string with input/output pairs: "in=out;in=out;..."',promptOptions:{type:"text"}},outfile:{value:null,types:["string","null"],envLink:"EXPORT_OUTFILE",description:"Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option",promptOptions:{type:"text"}},type:{value:"png",types:["string"],envLink:"EXPORT_TYPE",description:"File export format. Can be jpeg, png, pdf, or svg",promptOptions:{type:"select",hint:"Default: png",choices:["png","jpeg","pdf","svg"]}},constr:{value:"chart",types:["string"],envLink:"EXPORT_CONSTR",description:"Chart constructor. Can be chart, stockChart, mapChart, or ganttChart",promptOptions:{type:"select",hint:"Default: chart",choices:["chart","stockChart","mapChart","ganttChart"]}},b64:{value:!1,types:["boolean"],envLink:"EXPORT_B64",description:"Whether or not to the chart should be received in Base64 format instead of binary",promptOptions:{type:"toggle"}},noDownload:{value:!1,types:["boolean"],envLink:"EXPORT_NO_DOWNLOAD",description:"Whether or not to include or exclude attachment headers in the response",promptOptions:{type:"toggle"}},height:{value:null,types:["number","null"],envLink:"EXPORT_HEIGHT",description:"Height of the exported chart, overrides chart settings",promptOptions:{type:"number"}},width:{value:null,types:["number","null"],envLink:"EXPORT_WIDTH",description:"Width of the exported chart, overrides chart settings",promptOptions:{type:"number"}},scale:{value:null,types:["number","null"],envLink:"EXPORT_SCALE",description:"Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0",promptOptions:{type:"number"}},defaultHeight:{value:400,types:["number"],envLink:"EXPORT_DEFAULT_HEIGHT",description:"Default height of the exported chart if not set",promptOptions:{type:"number"}},defaultWidth:{value:600,types:["number"],envLink:"EXPORT_DEFAULT_WIDTH",description:"Default width of the exported chart if not set",promptOptions:{type:"number"}},defaultScale:{value:1,types:["number"],envLink:"EXPORT_DEFAULT_SCALE",description:"Default scale of the exported chart if not set. Ranges from 0.1 to 5.0",promptOptions:{type:"number",min:.1,max:5}},globalOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_GLOBAL_OPTIONS",description:"JSON, stringified JSON or filename with global options for Highcharts.setOptions",promptOptions:{type:"text"}},themeOptions:{value:null,types:["Object","string","null"],envLink:"EXPORT_THEME_OPTIONS",description:"JSON, stringified JSON or filename with theme options for Highcharts.setOptions",promptOptions:{type:"text"}},rasterizationTimeout:{value:1500,types:["number"],envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"Milliseconds to wait for webpage rendering",promptOptions:{type:"number"}}},customLogic:{allowCodeExecution:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Allows or disallows execution of arbitrary code during exporting",promptOptions:{type:"toggle"}},allowFileResources:{value:!1,types:["boolean"],envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Allows or disallows injection of filesystem resources (disabled in server mode)",promptOptions:{type:"toggle"}},customCode:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CUSTOM_CODE",description:"Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename",promptOptions:{type:"text"}},callback:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CALLBACK",description:"JavaScript code to run during construction. Can be a function or a .js filename",promptOptions:{type:"text"}},resources:{value:null,types:["Object","string","null"],envLink:"CUSTOM_LOGIC_RESOURCES",description:"Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections",promptOptions:{type:"text"}},loadConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_LOAD_CONFIG",legacyName:"fromFile",description:"File with a pre-defined configuration to use",promptOptions:{type:"text"}},createConfig:{value:null,types:["string","null"],envLink:"CUSTOM_LOGIC_CREATE_CONFIG",description:"Prompt-based option setting, saved to a provided config file",promptOptions:{type:"text"}}},server:{enable:{value:!1,types:["boolean"],envLink:"SERVER_ENABLE",cliName:"enableServer",description:"Starts the server when true",promptOptions:{type:"toggle"}},host:{value:"0.0.0.0",types:["string"],envLink:"SERVER_HOST",description:"Hostname of the server",promptOptions:{type:"text"}},port:{value:7801,types:["number"],envLink:"SERVER_PORT",description:"Port number for the server",promptOptions:{type:"number"}},uploadLimit:{value:3,types:["number"],envLink:"SERVER_UPLOAD_LIMIT",description:"Maximum request body size in MB",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Displays or not action durations in milliseconds during server requests",promptOptions:{type:"toggle"}},proxy:{host:{value:null,types:["string","null"],envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"Host of the proxy server, if applicable",promptOptions:{type:"text"}},port:{value:null,types:["number","null"],envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"Port of the proxy server, if applicable",promptOptions:{type:"number"}},timeout:{value:5e3,types:["number"],envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"Timeout in milliseconds for the proxy server, if applicable",promptOptions:{type:"number"}}},rateLimiting:{enable:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables or disables rate limiting on the server",promptOptions:{type:"toggle"}},maxRequests:{value:10,types:["number"],envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"Maximum number of requests allowed per minute",promptOptions:{type:"number"}},window:{value:1,types:["number"],envLink:"SERVER_RATE_LIMITING_WINDOW",description:"Time window in minutes for rate limiting",promptOptions:{type:"number"}},delay:{value:0,types:["number"],envLink:"SERVER_RATE_LIMITING_DELAY",description:"Delay duration between successive requests before reaching the limit",promptOptions:{type:"number"}},trustProxy:{value:!1,types:["boolean"],envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set to true if the server is behind a load balancer",promptOptions:{type:"toggle"}},skipKey:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Key to bypass the rate limiter, used with `skipToken`",promptOptions:{type:"text"}},skipToken:{value:null,types:["string","null"],envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Token to bypass the rate limiter, used with `skipKey`",promptOptions:{type:"text"}}},ssl:{enable:{value:!1,types:["boolean"],envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables SSL protocol",promptOptions:{type:"toggle"}},force:{value:!1,types:["boolean"],envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"Forces the server to use HTTPS only when true",promptOptions:{type:"toggle"}},port:{value:443,types:["number"],envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"Port for the SSL server",promptOptions:{type:"number"}},certPath:{value:null,types:["string","null"],envLink:"SERVER_SSL_CERT_PATH",cliName:"sslCertPath",legacyName:"sslPath",description:"Path to the SSL certificate/key file",promptOptions:{type:"text"}}}},pool:{minWorkers:{value:4,types:["number"],envLink:"POOL_MIN_WORKERS",description:"Minimum and initial number of pool workers to spawn",promptOptions:{type:"number"}},maxWorkers:{value:8,types:["number"],envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"Maximum number of pool workers to spawn",promptOptions:{type:"number"}},workLimit:{value:40,types:["number"],envLink:"POOL_WORK_LIMIT",description:"Number of tasks a worker can handle before restarting",promptOptions:{type:"number"}},acquireTimeout:{value:5e3,types:["number"],envLink:"POOL_ACQUIRE_TIMEOUT",description:"Timeout in milliseconds for acquiring a resource",promptOptions:{type:"number"}},createTimeout:{value:5e3,types:["number"],envLink:"POOL_CREATE_TIMEOUT",description:"Timeout in milliseconds for creating a resource",promptOptions:{type:"number"}},destroyTimeout:{value:5e3,types:["number"],envLink:"POOL_DESTROY_TIMEOUT",description:"Timeout in milliseconds for destroying a resource",promptOptions:{type:"number"}},idleTimeout:{value:3e4,types:["number"],envLink:"POOL_IDLE_TIMEOUT",description:"Timeout in milliseconds for destroying idle resources",promptOptions:{type:"number"}},createRetryInterval:{value:200,types:["number"],envLink:"POOL_CREATE_RETRY_INTERVAL",description:"Interval in milliseconds before retrying resource creation on failure",promptOptions:{type:"number"}},reaperInterval:{value:1e3,types:["number"],envLink:"POOL_REAPER_INTERVAL",description:"Interval in milliseconds to check and destroy idle resources",promptOptions:{type:"number"}},benchmarking:{value:!1,types:["boolean"],envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Shows statistics for the pool of resources",promptOptions:{type:"toggle"}}},logging:{level:{value:4,types:["number"],envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"Logging verbosity level",promptOptions:{type:"number",round:0,min:0,max:5}},file:{value:"highcharts-export-server.log",types:["string"],envLink:"LOGGING_FILE",cliName:"logFile",description:"Log file name. Requires `logToFile` and `logDest` to be set",promptOptions:{type:"text"}},dest:{value:"log",types:["string"],envLink:"LOGGING_DEST",cliName:"logDest",description:"Path to store log files. Requires `logToFile` to be set",promptOptions:{type:"text"}},toConsole:{value:!0,types:["boolean"],envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables console logging",promptOptions:{type:"toggle"}},toFile:{value:!0,types:["boolean"],envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables logging to a file",promptOptions:{type:"toggle"}}},ui:{enable:{value:!1,types:["boolean"],envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the UI for the export server",promptOptions:{type:"toggle"}},route:{value:"/",types:["string"],envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route for the UI",promptOptions:{type:"text"}}},other:{nodeEnv:{value:"production",types:["string"],envLink:"OTHER_NODE_ENV",description:"The Node.js environment type",promptOptions:{type:"text"}},listenToProcessExits:{value:!0,types:["boolean"],envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Whether or not to attach process.exit handlers",promptOptions:{type:"toggle"}},noLogo:{value:!1,types:["boolean"],envLink:"OTHER_NO_LOGO",description:"Display or skip printing the logo on startup",promptOptions:{type:"toggle"}},hardResetPage:{value:!1,types:["boolean"],envLink:"OTHER_HARD_RESET_PAGE",description:"Whether or not to reset the page content entirely",promptOptions:{type:"toggle"}},browserShellMode:{value:!0,types:["boolean"],envLink:"OTHER_BROWSER_SHELL_MODE",description:"Whether or not to set the browser to run in shell mode",promptOptions:{type:"toggle"}}},debug:{enable:{value:!1,types:["boolean"],envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser",promptOptions:{type:"toggle"}},headless:{value:!1,types:["boolean"],envLink:"DEBUG_HEADLESS",description:"Whether or not to set the browser to run in headless mode during debugging",promptOptions:{type:"toggle"}},devtools:{value:!1,types:["boolean"],envLink:"DEBUG_DEVTOOLS",description:"Enables or disables DevTools in headful mode",promptOptions:{type:"toggle"}},listenToConsole:{value:!1,types:["boolean"],envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Enables or disables listening to console messages from the browser",promptOptions:{type:"toggle"}},dumpio:{value:!1,types:["boolean"],envLink:"DEBUG_DUMPIO",description:"Redirects or not browser stdout and stderr to process.stdout and process.stderr",promptOptions:{type:"toggle"}},slowMo:{value:0,types:["number"],envLink:"DEBUG_SLOW_MO",description:"Delays Puppeteer operations by the specified milliseconds",promptOptions:{type:"number"}},debuggingPort:{value:9222,types:["number"],envLink:"DEBUG_DEBUGGING_PORT",description:"Port used for debugging",promptOptions:{type:"number"}}}},nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((n=>{const r=e[n];void 0===r.value?_createNestedProps(r,t,`${o}.${n}`):(t[r.cliName||n]=`${o}.${n}`.substring(1),void 0!==r.legacyName&&(t[r.legacyName]=`${o}.${n}`.substring(1)))})),t}function _createAbsoluteProps(e,t=[]){return Object.keys(e).forEach((o=>{const n=e[o];void 0===n.types?_createAbsoluteProps(n,t):n.types.includes("Object")&&t.push(o)})),t}dotenv.config();const{coreScripts:coreScripts,moduleScripts:moduleScripts,indicatorScripts:indicatorScripts}=defaultConfig.highcharts;z.setErrorMap(_customErrorMap);const v={boolean:e=>e?z.boolean():z.union([z.enum(["true","false","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e)),z.boolean()]).nullable(),string:e=>e?z.string().trim().refine((e=>!["false","undefined","null",""].includes(e)),{params:{errorMessage:"The string contains a forbidden value"}}):z.string().trim().transform((e=>["false","undefined","null",""].includes(e)?null:e)).nullable(),enum:(e,t)=>t?z.enum([...e]):z.enum([...e,"undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),stringArray(e,t,o){const n=z.string().trim().array(),r=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),i=t=>t.map((e=>e.trim())).filter(e);return o?n.transform(i):z.union([r,n]).transform(i).transform((e=>e.length?e:null)).nullable()},positiveNum:e=>e?z.number().positive():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and positive"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().positive()]).nullable(),nonNegativeNum:e=>e?z.number().nonnegative():z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&Number(e)>=0||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be numeric and non-negative"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().nonnegative()]).nullable(),startsWith:(e,t)=>t?z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}):z.string().trim().refine((t=>e.some((e=>t.startsWith(e)))||["undefined","null",""].includes(t)),{params:{errorMessage:`The value must be a string that starts with ${e.join(", ")}`}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),chartConfig:()=>z.union([z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable(),additionalOptions:()=>z.union([z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json' or starts with '{' and ends with '}'"}}).transform((e=>["undefined","null",""].includes(e)?null:e)),z.object({}).passthrough()]).nullable()},config={args:e=>v.stringArray((e=>!["false","undefined","null",""].includes(e)),";",e),version:e=>e?z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}):z.string().trim().refine((e=>/^(latest|\d{1,2}(\.\d{1,2}){0,2})$/.test(e)||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be 'latest', a major version, or in the form XX.YY.ZZ"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),cdnUrl:e=>v.startsWith(["http://","https://"],e),forceFetch:e=>v.boolean(e),cachePath:e=>v.string(e),adminToken:e=>v.string(e),coreScripts:e=>v.stringArray((e=>coreScripts.value.includes(e)),",",e),moduleScripts:e=>v.stringArray((e=>moduleScripts.value.includes(e)),",",e),indicatorScripts:e=>v.stringArray((e=>indicatorScripts.value.includes(e)),",",e),customScripts:e=>v.stringArray((e=>e.startsWith("https://")||e.startsWith("http://")),",",e),infile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".json")||e.length>=5&&e.endsWith(".svg")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .json or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),instr:()=>v.chartConfig(),options:()=>v.chartConfig(),svg:()=>z.string().trim().refine((e=>e.indexOf("=0||e.indexOf("=0||["false","undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that contains '["false","undefined","null",""].includes(e)?null:e)).nullable(),outfile:e=>e?z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).nullable():z.string().trim().refine((e=>e.length>=6&&e.endsWith(".jpeg")||e.length>=5&&(e.endsWith(".jpg")||e.endsWith(".png")||e.endsWith(".pdf")||e.endsWith(".svg"))||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg"}}).transform((e=>["undefined","null",""].includes(e)?null:e)).nullable(),type:e=>v.enum(["jpeg","jpg","png","pdf","svg"],e),constr:e=>v.enum(["chart","stockChart","mapChart","ganttChart"],e),b64:e=>v.boolean(e),noDownload:e=>v.boolean(e),defaultHeight:e=>v.positiveNum(e),defaultWidth:e=>v.positiveNum(e),defaultScale:e=>e?z.number().gte(.1).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number(e)>=.1&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0.1 and 5.0 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().gte(.1).lte(5)]).nullable(),height(e){return this.defaultHeight(e).nullable()},width(e){return this.defaultWidth(e).nullable()},scale(e){return this.defaultScale(e).nullable()},globalOptions:()=>v.additionalOptions(),themeOptions:()=>v.additionalOptions(),batch:e=>v.string(e),rasterizationTimeout:e=>v.nonNegativeNum(e),allowCodeExecution:e=>v.boolean(e),allowFileResources:e=>v.boolean(e),customCode:e=>v.string(e),callback:e=>v.string(e),resources(e){const t=z.object({js:v.string(!1),css:v.string(!1),files:v.stringArray((e=>!["undefined","null",""].includes(e)),",",!0).nullable()}).partial(),o=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}"}}),n=z.string().trim().refine((e=>e.startsWith("{")&&e.endsWith("}")||e.length>=6&&e.endsWith(".json")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that ends with '.json'"}}).transform((e=>["undefined","null",""].includes(e)?null:e));return e?z.union([t,o]).nullable():z.union([t,n]).nullable()},loadConfig:e=>v.string(e).refine((e=>null===e||e.length>=6&&e.endsWith(".json")),{params:{errorMessage:"The value must be a string that ends with .json "}}),createConfig(e){return this.loadConfig(e)},enableServer:e=>v.boolean(e),host:e=>v.string(e),port:e=>v.nonNegativeNum(e),uploadLimit:e=>v.positiveNum(e),serverBenchmarking:e=>v.boolean(e),proxyHost:e=>v.string(e),proxyPort:e=>v.nonNegativeNum(e).nullable(),proxyTimeout:e=>v.nonNegativeNum(e),enableRateLimiting:e=>v.boolean(e),maxRequests:e=>v.nonNegativeNum(e),window:e=>v.nonNegativeNum(e),delay:e=>v.nonNegativeNum(e),trustProxy:e=>v.boolean(e),skipKey:e=>v.string(e),skipToken:e=>v.string(e),enableSsl:e=>v.boolean(e),sslForce:e=>v.boolean(e),sslPort:e=>v.nonNegativeNum(e),sslCertPath:e=>v.string(e),minWorkers:e=>v.positiveNum(e),maxWorkers:e=>v.positiveNum(e),workLimit:e=>v.positiveNum(e),acquireTimeout:e=>v.nonNegativeNum(e),createTimeout:e=>v.nonNegativeNum(e),destroyTimeout:e=>v.nonNegativeNum(e),idleTimeout:e=>v.nonNegativeNum(e),createRetryInterval:e=>v.nonNegativeNum(e),reaperInterval:e=>v.nonNegativeNum(e),poolBenchmarking:e=>v.boolean(e),resourcesInterval:e=>v.nonNegativeNum(e),logLevel:e=>e?z.number().int().gte(0).lte(5):z.union([z.string().trim().refine((e=>!isNaN(Number(e))&&!0!==e&&!e.startsWith("[")&&Number.isInteger(Number(e))&&Number(e)>=0&&Number(e)<=5||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be within a 0 and 5 range"}}).transform((e=>["undefined","null",""].includes(e)?null:Number(e))),z.number().int().gte(0).lte(5)]).nullable(),logFile:e=>v.string(e).refine((e=>null===e||e.length>=5&&e.endsWith(".log")),{params:{errorMessage:"The value must be a string that ends with '.log'"}}),logDest:e=>v.string(e),logToConsole:e=>v.boolean(e),logToFile:e=>v.boolean(e),enableUi:e=>v.boolean(e),uiRoute:e=>v.startsWith(["/"],e),nodeEnv:e=>v.enum(["development","production","test"],e),listenToProcessExits:e=>v.boolean(e),noLogo:e=>v.boolean(e),hardResetPage:e=>v.boolean(e),browserShellMode:e=>v.boolean(e),enableDebug:e=>v.boolean(e),headless:e=>v.boolean(e),devtools:e=>v.boolean(e),listenToConsole:e=>v.boolean(e),dumpio:e=>v.boolean(e),slowMo:e=>v.nonNegativeNum(e),debuggingPort:e=>v.nonNegativeNum(e),requestId:()=>z.string().uuid({message:"The value must be a stringified UUID"}).nullable()},PuppeteerSchema=e=>z.object({args:config.args(e)}).partial(),HighchartsSchema=e=>z.object({version:config.version(e),cdnUrl:config.cdnUrl(e),forceFetch:config.forceFetch(e),cachePath:config.cachePath(e),coreScripts:config.coreScripts(e),moduleScripts:config.moduleScripts(e),indicatorScripts:config.indicatorScripts(e),customScripts:config.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:config.infile(e),instr:config.instr(),options:config.options(),svg:config.svg(),outfile:config.outfile(e),type:config.type(e),constr:config.constr(e),b64:config.b64(e),noDownload:config.noDownload(e),defaultHeight:config.defaultHeight(e),defaultWidth:config.defaultWidth(e),defaultScale:config.defaultScale(e),height:config.height(e),width:config.width(e),scale:config.scale(e),globalOptions:config.globalOptions(),themeOptions:config.themeOptions(),batch:config.batch(!1),rasterizationTimeout:config.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:config.allowCodeExecution(e),allowFileResources:config.allowFileResources(e),customCode:config.customCode(!1),callback:config.callback(!1),resources:config.resources(e),loadConfig:config.loadConfig(!1),createConfig:config.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:config.proxyHost(!1),port:config.proxyPort(e),timeout:config.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:config.enableRateLimiting(e),maxRequests:config.maxRequests(e),window:config.window(e),delay:config.delay(e),trustProxy:config.trustProxy(e),skipKey:config.skipKey(!1),skipToken:config.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:config.enableSsl(e),force:config.sslForce(e),port:config.sslPort(e),certPath:config.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:config.enableServer(e).optional(),host:config.host(e).optional(),port:config.port(e).optional(),benchmarking:config.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:config.minWorkers(e),maxWorkers:config.maxWorkers(e),workLimit:config.workLimit(e),acquireTimeout:config.acquireTimeout(e),createTimeout:config.createTimeout(e),destroyTimeout:config.destroyTimeout(e),idleTimeout:config.idleTimeout(e),createRetryInterval:config.createRetryInterval(e),reaperInterval:config.reaperInterval(e),benchmarking:config.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:config.logLevel(e),file:config.logFile(e),dest:config.logDest(e),toConsole:config.logToConsole(e),toFile:config.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:config.enableUi(e),route:config.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:config.nodeEnv(e),listenToProcessExits:config.listenToProcessExits(e),noLogo:config.noLogo(e),hardResetPage:config.hardResetPage(e),browserShellMode:config.browserShellMode(e)}).partial(),DebugSchema=e=>z.object({enable:config.enableDebug(e),headless:config.headless(e),devtools:config.devtools(e),listenToConsole:config.listenToConsole(e),dumpio:config.dumpio(e),slowMo:config.slowMo(e),debuggingPort:config.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({puppeteer:PuppeteerSchema(!0),highcharts:HighchartsSchema(!0),export:ExportSchema(!0),customLogic:CustomLogicSchema(!0),server:ServerSchema(!0),pool:PoolSchema(!0),logging:LoggingSchema(!0),ui:UiSchema(!0),other:OtherSchema(!0),debug:DebugSchema(!0)}),LooseConfigSchema=z.object({puppeteer:PuppeteerSchema(!1),highcharts:HighchartsSchema(!1),export:ExportSchema(!1),customLogic:CustomLogicSchema(!1),server:ServerSchema(!1),pool:PoolSchema(!1),logging:LoggingSchema(!1),ui:UiSchema(!1),other:OtherSchema(!1),debug:DebugSchema(!1)}),EnvSchema=z.object({PUPPETEER_ARGS:config.args(!1),HIGHCHARTS_VERSION:config.version(!1),HIGHCHARTS_CDN_URL:config.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:config.forceFetch(!1),HIGHCHARTS_CACHE_PATH:config.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:config.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:config.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:config.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:config.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:config.customScripts(!1),EXPORT_INFILE:config.infile(!1),EXPORT_INSTR:config.instr(),EXPORT_OPTIONS:config.options(),EXPORT_SVG:config.svg(),EXPORT_BATCH:config.batch(!1),EXPORT_OUTFILE:config.outfile(!1),EXPORT_TYPE:config.type(!1),EXPORT_CONSTR:config.constr(!1),EXPORT_B64:config.b64(!1),EXPORT_NO_DOWNLOAD:config.noDownload(!1),EXPORT_HEIGHT:config.height(!1),EXPORT_WIDTH:config.width(!1),EXPORT_SCALE:config.scale(!1),EXPORT_DEFAULT_HEIGHT:config.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:config.defaultWidth(!1),EXPORT_DEFAULT_SCALE:config.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:config.globalOptions(),EXPORT_THEME_OPTIONS:config.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:config.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:config.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:config.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:config.customCode(!1),CUSTOM_LOGIC_CALLBACK:config.callback(!1),CUSTOM_LOGIC_RESOURCES:config.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:config.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:config.createConfig(!1),SERVER_ENABLE:config.enableServer(!1),SERVER_HOST:config.host(!1),SERVER_PORT:config.port(!1),SERVER_UPLOAD_LIMIT:config.uploadLimit(!1),SERVER_BENCHMARKING:config.serverBenchmarking(!1),SERVER_PROXY_HOST:config.proxyHost(!1),SERVER_PROXY_PORT:config.proxyPort(!1),SERVER_PROXY_TIMEOUT:config.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:config.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:config.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:config.window(!1),SERVER_RATE_LIMITING_DELAY:config.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:config.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:config.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:config.skipToken(!1),SERVER_SSL_ENABLE:config.enableSsl(!1),SERVER_SSL_FORCE:config.sslForce(!1),SERVER_SSL_PORT:config.sslPort(!1),SERVER_SSL_CERT_PATH:config.sslCertPath(!1),POOL_MIN_WORKERS:config.minWorkers(!1),POOL_MAX_WORKERS:config.maxWorkers(!1),POOL_WORK_LIMIT:config.workLimit(!1),POOL_ACQUIRE_TIMEOUT:config.acquireTimeout(!1),POOL_CREATE_TIMEOUT:config.createTimeout(!1),POOL_DESTROY_TIMEOUT:config.destroyTimeout(!1),POOL_IDLE_TIMEOUT:config.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:config.createRetryInterval(!1),POOL_REAPER_INTERVAL:config.reaperInterval(!1),POOL_BENCHMARKING:config.poolBenchmarking(!1),LOGGING_LEVEL:config.logLevel(!1),LOGGING_FILE:config.logFile(!1),LOGGING_DEST:config.logDest(!1),LOGGING_TO_CONSOLE:config.logToConsole(!1),LOGGING_TO_FILE:config.logToFile(!1),UI_ENABLE:config.enableUi(!1),UI_ROUTE:config.uiRoute(!1),OTHER_NODE_ENV:config.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:config.listenToProcessExits(!1),OTHER_NO_LOGO:config.noLogo(!1),OTHER_HARD_RESET_PAGE:config.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:config.browserShellMode(!1),DEBUG_ENABLE:config.enableDebug(!1),DEBUG_HEADLESS:config.headless(!1),DEBUG_DEVTOOLS:config.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:config.listenToConsole(!1),DEBUG_DUMPIO:config.dumpio(!1),DEBUG_SLOW_MO:config.slowMo(!1),DEBUG_DEBUGGING_PORT:config.debuggingPort(!1)}),envs=EnvSchema.partial().parse(process.env);function strictValidate(e){return StrictConfigSchema.partial().parse(e)}function looseValidate(e){return LooseConfigSchema.partial().parse(e)}function validateOption(e,t,o){return config[e](o).parse(t)}function _customErrorMap(e,t){const o=e.path.join("."),n=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${n} - No value was provided.`}:{message:`${n} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${n} - ${e.params?.errorMessage}, received '${t.data}'.`};if(e.code===z.ZodIssueCode.invalid_union){let t=`Multiple errors occurred for the ${o}:\n`;return e.unionErrors.forEach((e=>{const o=e.issues[0].message.indexOf("-");t+=-1!==o?`${e.issues[0].message}\n`.substring(o):`${e.issues[0].message}\n`})),{message:t}}return{message:`${n} - ${t.defaultError}.`}}const globalOptions=_initGlobalOptions(defaultConfig);function getOptions(e=!0){return e?globalOptions:deepCopy(globalOptions)}function setOptions(e={},t=[],o=!1){let n={},r={};if(t.length)try{n=strictValidate(_loadConfigFile(t))}catch(e){logZodIssues(1,e.issues,"[config] Custom JSON options validation error")}if(e&&0!==Object.keys(e).length)try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Custom options validation error")}if(t.length)try{r=looseValidate(_pairArgumentValue(nestedProps,t))}catch(e){logZodIssues(1,e.issues,"[config] CLI options validation error")}const i=getOptions(o);return _updateOptions(defaultConfig,i,n,e,r),i}function mergeOptions(e,t){if(isObject(t))for(const[o,n]of Object.entries(t))e[o]=isObject(n)&&!absoluteProps.includes(o)&&void 0!==e[o]?mergeOptions(e[o],n):void 0!==n?n:e[o];return e}function mapToNewOptions(e){const t={};if("[object Object]"===Object.prototype.toString.call(e))for(const[o,n]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,r)=>t[o]=e.length-1===r?n:t[o]||{}),t)}return t}function isAllowedConfig(config,toString=!1,allowFunctions=!1){try{if(!isObject(config)&&"string"!=typeof config)return null;const objectConfig="string"==typeof config?allowFunctions?eval(`(${config})`):JSON.parse(config):config,stringifiedOptions=_optionsStringify(objectConfig,allowFunctions,!1),parsedOptions=allowFunctions?JSON.parse(_optionsStringify(objectConfig,allowFunctions,!0),((_,value)=>"string"==typeof value&&value.startsWith("function")?eval(`(${value})`):value)):JSON.parse(stringifiedOptions);return toString?stringifiedOptions:parsedOptions}catch(e){return null}}function _initGlobalOptions(e){const t={};for(const[o,n]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(n,"value")?n.value:_initGlobalOptions(n);return t}function _updateOptions(e,t,o,n,r){Object.keys(e).forEach((i=>{const s=e[i],a=o&&o[i],l=n&&n[i],c=r&&r[i];if(void 0===s.value)_updateOptions(s,t[i],a,l,c);else{null!=a&&(t[i]=a);const e=envs[s.envLink];s.envLink in envs&&null!=e&&(t[i]=e),null!=l&&(t[i]=l),null!=c&&(t[i]=c)}}))}function _optionsStringify(e,t,o){return JSON.stringify(e,((e,n)=>{if("string"==typeof n&&(n=n.trim()),"function"==typeof n||"string"==typeof n&&n.startsWith("function")&&n.endsWith("}")){if(t)return o?`"EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN"`:`EXP_FUN${(n+"").replaceAll(/\s+/g," ")}EXP_FUN`;throw new Error}return n})).replaceAll(o?/\\"EXP_FUN|EXP_FUN\\"/g:/"EXP_FUN|EXP_FUN"/g,"")}function _loadConfigFile(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,""))),o=t>-1&&e[t+1];if(o)try{return JSON.parse(readFileSync(getAbsolutePath(o)))}catch(e){logWithStack(2,e,`[config] Unable to load the configuration from the ${o} file.`)}return{}}function _pairArgumentValue(e,t){const o={};for(let n=0;n{if(i.length-1===s){const i=t[++n];i||log(2,`[config] Missing value for the CLI '--${r}' argument. Using the default value.`),e[o]=i||null}else void 0===e[o]&&(e[o]={});return e[o]}),o)}return o}async function fetch(e,t={}){return new Promise(((o,n)=>{_getProtocolModule(e).get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||n("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{n(e)}))}))}function _getProtocolModule(e){return e.startsWith("https")?https:http}class ExportError extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.statusCode=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkAndUpdateCache(e,t){let o;const n=getCachePath(),r=join(n,"manifest.json"),i=join(n,"sources.js");if(!existsSync(n)&&mkdirSync(n,{recursive:!0}),!existsSync(r)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,i);else{let n=!1;const s=JSON.parse(readFileSync(r));if(s.modules&&Array.isArray(s.modules)){const e={};s.modules.forEach((t=>e[t]=1)),s.modules=e}const{coreScripts:a,moduleScripts:l,indicatorScripts:c}=e,p=a.length+l.length+c.length;s.version!==e.version?(log(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),n=!0):Object.keys(s.modules||{}).length!==p?(log(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),n=!0):n=(l||[]).some((e=>{if(!s.modules[e])return log(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),n?o=await _updateCache(e,t,i):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(i,"utf8"),o=s.modules,cache.hcVersion=extractVersion(cache.sources))}await _saveConfigToManifest(e,o)}function getHighchartsVersion(){return cache.hcVersion}async function updateHighchartsVersion(e){const t=getOptions();t.highcharts.version=e,await checkAndUpdateCache(t.highcharts,t.server.proxy)}function extractVersion(e){return e.substring(0,e.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim()}function extractModuleName(e){return e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _fetchAndProcessScript(e,t,o,n=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const r=await fetch(`${e}.js`,t);if(200===r.statusCode&&"string"==typeof r.text){if(o){o[extractModuleName(e)]=1}return r.text}if(n)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${r.statusCode}).`,404).setError(r);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}async function _saveConfigToManifest(e,t={}){const o={version:e.version,modules:t};cache.activeManifest=o,log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _fetchScripts(e,t,o,n,r){let i;const s=n.host,a=n.port;if(s&&a)try{i=new HttpsProxyAgent({host:s,port:a})}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}const l=i?{agent:i,timeout:n.timeout}:{},c=[...e.map((e=>_fetchAndProcessScript(`${e}`,l,r,!0))),...t.map((e=>_fetchAndProcessScript(`${e}`,l,r))),...o.map((e=>_fetchAndProcessScript(`${e}`,l)))];return(await Promise.all(c)).join(";\n")}async function _updateCache(e,t,o){const n="latest"===e.version?null:`${e.version}`,r=e.cdnUrl||cache.cdnUrl;try{const i={};return log(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`),cache.sources=await _fetchScripts([...e.coreScripts.map((e=>n?`${r}/${n}/${e}`:`${r}/${e}`))],[...e.moduleScripts.map((e=>"map"===e?n?`${r}/maps/${n}/modules/${e}`:`${r}/maps/modules/${e}`:n?`${r}/${n}/modules/${e}`:`${r}/modules/${e}`)),...e.indicatorScripts.map((e=>n?`${r}/stock/${n}/indicators/${e}`:`${r}/stock/indicators/${e}`))],e.customScripts,t,i),cache.hcVersion=extractVersion(cache.sources),writeFileSync(o,cache.sources),i}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}function setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e){const{getOptions:t,merge:o,setOptions:n,wrap:r}=Highcharts;Highcharts.setOptionsObj=o(!1,{},t()),window.isRenderComplete=!1,r(Highcharts.Chart.prototype,"init",(function(e,t,n){((t=o(t,{exporting:{enabled:!1},plotOptions:{series:{label:{enabled:!1}}},tooltip:{}})).series||[]).forEach((function(e){e.animation=!1})),window.onHighchartsRender||(window.onHighchartsRender=Highcharts.addEvent(this,"render",(()=>{window.isRenderComplete=!0}))),e.apply(this,[t,n])})),r(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const i={chart:{animation:!1,height:e.export.height,width:e.export.width},exporting:{enabled:!1}},s=new Function(`return ${e.export.instr}`)(),a=new Function(`return ${e.export.themeOptions}`)(),l=new Function(`return ${e.export.globalOptions}`)(),c=o(!1,a,s,i),p=e.customLogic.callback?new Function(`return ${e.customLogic.callback}`)():null;e.customLogic.customCode&&new Function("options",e.customLogic.customCode)(s),l&&n(l),Highcharts[e.export.constr]("container",c,p);const u=t();for(const e in u)"function"!=typeof u[e]&&delete u[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const template=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:n,...r}=t,i={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...n&&r};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to get a browser instance (try ${++e}).`),browser=await puppeteer.launch(i)}catch(o){if(logWithStack(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;log(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===i.headless&&log(3,"[browser] Launched browser in shell mode."),n&&log(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ExportError("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!browser)throw new ExportError("[browser] Cannot find a browser to open.",500)}return browser}async function closeBrowser(){browser&&browser.connected&&await browser.close(),browser=null,log(4,"[browser] Closed the browser.")}async function newPage(e){if(!browser||!browser.connected)throw new ExportError("[browser] Browser is not yet connected.",500);if(e.page=await browser.newPage(),await e.page.setCacheEnabled(!1),await _setPageContent(e.page),_setPageEvents(e.page),!e.page||e.page.isClosed())throw new ExportError("[browser] The page is invalid or closed.",400)}async function clearPage(e,t=!1){try{if(e.page&&!e.page.isClosed())return t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _setPageContent(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(t){logWithStack(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=getOptions().pool.workLimit+1}return!1}async function addPageResources(e,t){const o=[],n=t.resources;if(n){const r=[];if(n.js&&r.push({content:n.js}),n.files)for(const e of n.files){const t=!e.startsWith("http");r.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of r)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}r.length=0;const i=[];if(n.css){let r=n.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?i.push({url:e}):t.allowFileResources&&i.push({path:join(__dirname,e)}));i.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of i)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}i.length=0}}return o}async function clearPageResources(e,t){try{for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...o]=document.getElementsByTagName("link");for(const n of[...e,...t,...o])n.remove()}))}catch(e){logWithStack(2,e,"[browser] Could not clear page's resources.")}}async function _setPageContent(e){await e.setContent(template,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:join(getCachePath(),"sources.js")}),await e.evaluate(setupHighcharts)}function _setPageEvents(e){const{debug:t}=getOptions();e.on("pageerror",(async()=>{e.isClosed()})),t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}))}var cssTemplate=()=>"\n\nhtml, body {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n}\n\n#table-div, #sliders, #datatable, #controls, .ld-row {\n display: none;\n height: 0;\n}\n\n#chart-container {\n box-sizing: border-box;\n margin: 0;\n overflow: auto;\n font-size: 0;\n}\n\n#chart-container > figure, div {\n margin-top: 0 !important;\n margin-bottom: 0 !important;\n}\n\n",svgTemplate=e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`;async function puppeteerExport(e,t){const o=[];try{const n=t.export;let r=!1;if(n.svg){if(log(4,"[export] Treating as SVG input."),"svg"===n.type)return n.svg;r=!0,await _setAsSvg(e,n.svg)}else log(4,"[export] Treating as JSON config."),await _setAsOptions(e,t);o.push(...await addPageResources(e,t.customLogic));const i=r?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),o=t.height.baseVal.value*e,n=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:o,chartWidth:n}}),parseFloat(n.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||n.height)),c=Math.abs(Math.ceil(i.chartWidth||n.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:r?1:parseFloat(n.scale)}),n.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,n.type,{width:c,height:l,x:s,y:a},n.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,n.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${n.type}.`,400)}return await clearPageResources(e,o),p}catch(t){return await clearPageResources(e,o),t}}async function _setAsSvg(e,t){await e.setContent(svgTemplate(t),{waitUntil:"domcontentloaded"})}async function _setAsOptions(e,t){await e.evaluate(createChart,t)}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:n,height:r}=e.getBoundingClientRect();return{x:t,y:o,width:n,height:Math.trunc(r>1?r:500)}}))}async function _createSVG(e){return e.$eval("#container svg:first-of-type",(e=>e.outerHTML))}async function _createImage(e,t,o,n){return Promise.race([e.screenshot({type:t,clip:o,encoding:"base64",fullPage:!1,optimizeForSpeed:!0,captureBeyondViewport:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new ExportError("Rasterization timeout",408))),n||1500)))])}async function _createPDF(e,t,o,n){return await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:"base64",timeout:n||1500})}let pool=null;const poolStats={exportsAttempted:0,exportsPerformed:0,exportsDropped:0,exportsFromSvg:0,exportsFromOptions:0,exportsFromSvgAttempts:0,exportsFromOptionsAttempts:0,timeSpent:0,timeSpentAverage:0};async function initPool(e=getOptions().pool,t=[]){await createBrowser(t);try{if(log(3,`[pool] Initializing pool with workers: min ${e.minWorkers}, max ${e.maxWorkers}.`),pool)return void log(4,"[pool] Already initialized, please kill it before creating a new one.");e.minWorkers>e.maxWorkers&&(e.minWorkers=e.maxWorkers),pool=new Pool({..._factory(e),min:e.minWorkers,max:e.maxWorkers,acquireTimeoutMillis:e.acquireTimeout,createTimeoutMillis:e.createTimeout,destroyTimeoutMillis:e.destroyTimeout,idleTimeoutMillis:e.idleTimeout,createRetryIntervalMillis:e.createRetryInterval,reapIntervalMillis:e.reaperInterval,propagateCreateError:!1}),pool.on("release",(async e=>{const t=await clearPage(e,!1);log(4,`[pool] Pool resource [${e.id}] - Releasing a worker. Clear page status: ${t}.`)})),pool.on("destroySuccess",((e,t)=>{log(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const t=[];for(let o=0;o{pool.release(e)})),log(3,"[pool] The pool is ready"+(t.length?` with ${t.length} initial resources waiting.`:"."))}catch(e){throw new ExportError("[pool] Could not configure and create the pool of workers.",500).setError(e)}}async function killPool(){if(log(3,"[pool] Killing pool with all workers and closing browser."),pool){for(const e of pool.used)pool.release(e.resource);pool.destroyed||(await pool.destroy(),log(4,"[pool] Destroyed the pool of resources.")),pool=null}await closeBrowser()}async function postWork(e){let t;try{if(log(4,"[pool] Work received, starting to process."),++poolStats.exportsAttempted,getOptions().pool.benchmarking&&getPoolInfo(),!pool)throw new ExportError("[pool] Work received, but pool has not been started.",500);const o=measureTime();try{log(4,"[pool] Acquiring a worker handle."),t=await pool.acquire().promise,e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Acquiring a worker handle took ${o()}ms.`)}catch(t){throw new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`,400).setError(t)}if(log(4,"[pool] Acquired a worker handle."),!t.page)throw t.workCount=e.pool.workLimit+1,new ExportError("[pool] Resolved worker page is invalid: the pool setup is wonky.",400);const n=getNewDateTime();log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e);if(i instanceof Error)throw"Rasterization timeout"===i.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===i.name||"Rasterization timeout"===i.message?new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+"Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(i):new ExportError("[pool] "+(e._requestId?`Request [${e._requestId}] - `:"")+`Error encountered during export: ${r()}ms.`).setError(i);e.server.benchmarking&&log(5,e._requestId?`[benchmark] Request [${e._requestId}] - `:"[benchmark] ",`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t);const s=getNewDateTime()-n;return poolStats.timeSpent+=s,poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${s}ms.`),{result:i,options:e}}catch(e){throw++poolStats.exportsDropped,t&&pool.release(t),e}}function getPoolStats(){return poolStats}function getPoolInfoJSON(){return{min:pool.min,max:pool.max,used:pool.numUsed(),available:pool.numFree(),allCreated:pool.numUsed()+pool.numFree(),pendingAcquires:pool.numPendingAcquires(),pendingCreates:pool.numPendingCreates(),pendingValidations:pool.numPendingValidations(),pendingDestroys:pool.pendingDestroys.length,absoluteAll:pool.numUsed()+pool.numFree()+pool.numPendingAcquires()+pool.numPendingCreates()+pool.numPendingValidations()+pool.pendingDestroys.length}}function getPoolInfo(){const{min:e,max:t,used:o,available:n,allCreated:r,pendingAcquires:i,pendingCreates:s,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=getPoolInfoJSON();log(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),log(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),log(5,`[pool] The number of used resources: ${o}.`),log(5,`[pool] The number of free resources: ${n}.`),log(5,`[pool] The number of all created (used and free) resources: ${r}.`),log(5,`[pool] The number of resources waiting to be acquired: ${i}.`),log(5,`[pool] The number of resources waiting to be created: ${s}.`),log(5,`[pool] The number of resources waiting to be validated: ${a}.`),log(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),log(5,`[pool] The number of all resources: ${c}.`)}function _factory(e){return{create:async()=>{const t={id:v4(),workCount:Math.round(Math.random()*(e.workLimit/2))};try{const e=getNewDateTime();return await newPage(t),log(3,`[pool] Pool resource [${t.id}] - Successfully created a worker, took ${getNewDateTime()-e}ms.`),t}catch(e){throw log(3,`[pool] Pool resource [${t.id}] - Error encountered when creating a new page.`),e}},validate:async t=>t.page?t.page.isClosed()?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page is closed or invalid).`),!1):t.page.mainFrame().detached?(log(3,`[pool] Pool resource [${t.id}] - Validation failed (page's frame is detached).`),!1):!(e.workLimit&&++t.workCount>e.workLimit)||(log(3,`[pool] Pool resource [${t.id}] - Validation failed (exceeded the ${e.workLimit} works per resource limit).`),!1):(log(3,`[pool] Pool resource [${t.id}] - Validation failed (no valid page is found).`),!1),destroy:async e=>{if(log(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page&&!e.page.isClosed())try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){throw log(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`),t}}}}function sanitize(e){const t=new JSDOM("").window;return DOMPurify(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}let allowCodeExecution=!1;async function singleExport(e){if(!e||!e.export)throw new ExportError("[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.",400);await startExport(e,(async(e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}await killPool()}))}async function batchExport(e){if(!(e&&e.export&&e.export.batch))throw new ExportError("[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.",400);{const t=[];for(let o of e.export.batch.split(";")||[])o=o.split("="),2===o.length?t.push(startExport({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;const{b64:o,outfile:n,type:r}=t.options.export;try{o?writeFileSync(`${n.split(".").shift()||"chart"}.txt`,getBase64(t.result,r)):writeFileSync(n,"svg"!==r?Buffer.from(t.result,"base64"):t.result)}catch(e){throw new ExportError("[chart] Error while saving a chart.",500).setError(e)}}))):log(2,"[chart] No correct pair found for the batch export.");const o=await Promise.allSettled(t);await killPool(),o.forEach(((e,t)=>{e.reason&&logWithStack(1,e.reason,`[chart] Batch export number ${t+1} could not be correctly completed.`)}))}}async function startExport(e,t){try{log(4,"[chart] Starting the exporting process.");const o=mergeOptions(getOptions(!1),e),n=o.export;if(null!==n.infile){let e;log(4,"[chart] Attempting to export from a file input.");try{e=readFileSync(getAbsolutePath(n.infile),"utf8")}catch(e){throw new ExportError("[chart] Error loading content from a file input.",400).setError(e)}if(n.infile.endsWith(".svg"))try{n.svg=validateOption("svg",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `svg` option validation error"),e}else{if(!n.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);try{n.instr=validateOption("instr",e,!1)}catch(e){throw logZodIssues(1,e.issues,"[config] The `instr` option validation error"),e}}}if(null!==n.svg){log(4,"[chart] Attempting to export from an SVG input."),++getPoolStats().exportsFromSvgAttempts;const e=await _exportFromSvg(sanitize(n.svg),o);return++getPoolStats().exportsFromSvg,t(null,e)}if(null!==n.instr||null!==n.options){log(4,"[chart] Attempting to export from options input."),++getPoolStats().exportsFromOptionsAttempts;const e=await _exportFromOptions(n.instr||n.options,o);return++getPoolStats().exportsFromOptions,t(null,e)}return t(new ExportError("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))}catch(e){return t(e)}}function getAllowCodeExecution(){return allowCodeExecution}function setAllowCodeExecution(e){allowCodeExecution=e}async function _exportFromSvg(e,t){if("string"==typeof e&&(e.indexOf("=0||e.indexOf("=0))return log(4,"[chart] Parsing input as SVG."),t.export.svg=e,t.export.instr=null,t.export.options=null,_prepareExport(t);throw new ExportError("[chart] Not a correct SVG input.",400)}async function _exportFromOptions(e,t){log(4,"[chart] Parsing input from options.");const o=isAllowedConfig(e,!0,t.customLogic.allowCodeExecution);if(null===o||"string"!=typeof o||!o.startsWith("{")||!o.endsWith("}"))throw new ExportError("[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.",403);return t.export.instr=o,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;t.type=fixType(t.type,t.outfile),t.outfile=fixOutfile(t.type,t.outfile),log(3,`[chart] The custom logic is ${o.allowCodeExecution?"allowed":"disallowed"}.`),_handleCustomLogic(o,o.allowCodeExecution),_handleGlobalAndTheme(t,o.allowFileResources,o.allowCodeExecution),e.export={...t,..._findChartSize(t)};try{e=strictValidate(e)}catch(e){logZodIssues(1,e.issues,"[config] Final options validation error")}return postWork(e)}function _findChartSize(e){const{chart:t,exporting:o}=e.options||isAllowedConfig(e.instr)||!1,{chart:n,exporting:r}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||r?.scale||s?.scale||e.defaultScale||1,5)),2),l={height:e.height||o?.sourceHeight||t?.height||r?.sourceHeight||n?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,width:e.width||o?.sourceWidth||t?.width||r?.sourceWidth||n?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,scale:a};for(let[e,t]of Object.entries(l))l[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return l}function _handleCustomLogic(e,t){if(t){if("string"==typeof e.resources)e.resources=_handleResources(e.resources,e.allowFileResources,!0);else if(!e.resources)try{e.resources=_handleResources(readFileSync(getAbsolutePath("resources.json"),"utf8"),e.allowFileResources,!0)}catch(e){log(2,"[chart] Unable to load the default `resources.json` file.")}try{e.customCode=wrapAround(e.customCode,e.allowFileResources)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=wrapAround(e.callback,e.allowFileResources,!0)}catch(t){logWithStack(2,t,"[chart] The `callback` cannot be loaded."),e.callback=null}[null,void 0].includes(e.customCode)&&log(3,"[chart] No value for the `customCode` option found."),[null,void 0].includes(e.callback)&&log(3,"[chart] No value for the `callback` option found."),[null,void 0].includes(e.resources)&&log(3,"[chart] No value for the `resources` option found.")}else if(e.callback||e.resources||e.customCode)throw e.callback=null,e.resources=null,e.customCode=null,new ExportError("[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.",403)}function _handleResources(e=null,t,o){const n=["js","css","files"];let r=e,i=!1;if(t&&e.endsWith(".json"))try{r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o)}catch{return null}else r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files;for(const e in r)n.includes(e)?i||(i=!0):delete r[e];return i?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleGlobalAndTheme(e,t,o){["globalOptions","themeOptions"].forEach((n=>{try{e[n]&&(t&&"string"==typeof e[n]&&e[n].endsWith(".json")?e[n]=isAllowedConfig(readFileSync(getAbsolutePath(e[n]),"utf8"),!0,o):e[n]=isAllowedConfig(e[n],!0,o))}catch(t){logWithStack(2,t,`[chart] The \`${n}\` cannot be loaded.`),e[n]=null}})),[null,void 0].includes(e.globalOptions)&&log(3,"[chart] No value for the `globalOptions` option found."),[null,void 0].includes(e.themeOptions)&&log(3,"[chart] No value for the `themeOptions` option found.")}const timerIds=[];function addTimer(e){timerIds.push(e)}function clearAllTimers(){log(4,"[timer] Clearing all registered intervals and timeouts.");for(const e of timerIds)clearInterval(e),clearTimeout(e)}function logErrorMiddleware(e,t,o,n){return logWithStack(1,e),"development"!==getOptions().other.nodeEnv&&delete e.stack,n(e)}function returnErrorMiddleware(e,t,o,n){const{message:r,stack:i}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:r,stack:i})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t=getOptions().server.rateLimiting){try{if(t.enable){const o="Too many requests, you have been rate limited. Please try again later.",n={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};n.trustProxy&&e.enable("trust proxy");const r=rateLimit({windowMs:60*n.window*1e3,max:n.max,delayMs:n.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==n.skipKey&&!1!==n.skipToken&&e.query.key===n.skipKey&&e.query.access_token===n.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(r),log(3,`[rate limiting] Enabled rate limiting with ${n.max} requests per ${n.window} minute for each IP, trusting proxy: ${n.trustProxy}.`)}}catch(e){throw new ExportError("[rate limiting] Could not configure and set the rate limiting options.",500).setError(e)}}class HttpError extends ExportError{constructor(e,t){super(e,t)}setStatus(e){return this.statusCode=e,this}}function contentTypeMiddleware(e,t,o){try{const t=e.headers["content-type"]||"";if(!t.includes("application/json")&&!t.includes("application/x-www-form-urlencoded")&&!t.includes("multipart/form-data"))throw new HttpError("[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.",415);return o()}catch(e){return o(e)}}function requestBodyMiddleware(e,t,o){try{const t=e.body,n=v4().replace(/-/g,"");if(!t||isObjectEmpty(t))throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is empty.`),new HttpError("[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.",400);const r=getAllowCodeExecution(),i=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,r);if(null===i&&!t.svg)throw log(2,`[validation] Request [${n}] - The request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(t)}.`),new HttpError("[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);if(t.svg&&isPrivateRangeUrlFound(t.svg))throw new HttpError("[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);try{e.validatedOptions=looseValidate({_requestId:n,export:{instr:i,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${fixType(t.type)}`,type:fixType(t.type,t.outfile),constr:fixConstr(t.constr),b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,r),themeOptions:isAllowedConfig(t.themeOptions,!0,r)},customLogic:{allowCodeExecution:r,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,r)}})}catch(e){throw logZodIssues(1,e.issues,"[config] Request options validation error"),new HttpError("The provided options are not correct. Please check if your data is of the correct types.",400)}return o()}catch(e){return o(e)}}function validationMiddleware(e){e.post(["/","/:filename"],contentTypeMiddleware),e.post(["/","/:filename"],requestBodyMiddleware)}const reversedMime={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};async function requestExport(e,t,o){try{const o=measureTime();let n=!1;e.socket.on("close",(e=>{e&&(n=!0)}));const r=e.validatedOptions,i=r._requestId;log(4,`[export] Got an incoming HTTP request with ID ${i}.`),await startExport(r,((r,s)=>{if(e.socket.removeAllListeners("close"),n)log(3,`[export] Request [${i}] - The client closed the connection before the chart finished processing.`);else{if(r)throw r;if(!s||!s.result)throw log(2,`[export] Request [${i}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new HttpError("[export] Unexpected return of the export result from the chart generation. Please check your request data.",400);if(s.result){log(3,`[export] Request [${i}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:n,noDownload:r,outfile:a}=s.options.export;return n?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),r||t.attachment(a),"svg"===e?t.send(s.result):t.send(Buffer.from(s.result,"base64")))}}}))}catch(e){return o(e)}}function exportRoutes(e){e.post("/",requestExport),e.post("/:filename",requestExport)}const serverStartTime=new Date,packageFile=JSON.parse(readFileSync(join(__dirname,"package.json"))),successRates=[],recordInterval=6e4,windowSize=30;function _calculateMovingAverage(){return successRates.reduce(((e,t)=>e+t),0)/successRates.length}function _startSuccessRate(){return setInterval((()=>{const e=getPoolStats(),t=0===e.exportsAttempted?1:e.exportsPerformed/e.exportsAttempted*100;successRates.push(t),successRates.length>windowSize&&successRates.shift()}),recordInterval)}function healthRoutes(e){addTimer(_startSuccessRate()),e.get("/health",((e,t,o)=>{try{log(4,"[health] Returning server health.");const e=getPoolStats(),o=successRates.length,n=_calculateMovingAverage();t.send({status:"OK",bootTime:serverStartTime,uptime:`${Math.floor((getNewDateTime()-serverStartTime.getTime())/1e3/60)} minutes`,serverVersion:packageFile.version,highchartsVersion:getHighchartsVersion(),averageExportTime:e.timeSpentAverage,attemptedExports:e.exportsAttempted,performedExports:e.exportsPerformed,failedExports:e.exportsDropped,sucessRatio:e.exportsPerformed/e.exportsAttempted*100,pool:getPoolInfoJSON(),period:o,movingAverage:n,message:isNaN(n)||!successRates.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${n.toFixed(2)}%.`,svgExports:e.exportsFromSvg,jsonExports:e.exportsFromOptions,svgExportsAttempts:e.exportsFromSvgAttempts,jsonExportsAttempts:e.exportsFromOptionsAttempts})}catch(e){return o(e)}}))}function uiRoutes(e){e.get(getOptions().ui.route||"/",((e,t,o)=>{try{t.sendFile(join(__dirname,"public","index.html"),{acceptRanges:!1})}catch(e){return o(e)}}))}function versionChangeRoutes(e){e.post("/version_change/:newVersion",(async(e,t,o)=>{try{const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new HttpError("[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const n=e.get("hc-auth");if(!n||n!==o)throw new HttpError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const r=e.params.newVersion;if(!r)throw new HttpError("[version] No new version supplied.",400);try{await updateHighchartsVersion(r)}catch(e){throw new HttpError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHighchartsVersion(),message:`Successfully updated Highcharts to version: ${r}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e=getOptions().server){try{if(!e.enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const t=1024*e.uploadLimit*1024,o=multer.memoryStorage(),n=multer({storage:o,limits:{fieldSize:t}});if(app.disable("x-powered-by"),app.use(cors({methods:["POST","GET","OPTIONS"]})),app.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()})),app.use(express.json({limit:t})),app.use(express.urlencoded({extended:!0,limit:t})),app.use(n.none()),app.use(express.static(join(__dirname,"public"))),!e.ssl.force){const t=http.createServer(app);_attachServerErrorHandlers(t),t.listen(e.port,e.host,(()=>{activeServers.set(e.port,t),log(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}))}if(e.ssl.enable){let t,o;try{t=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=await readFile(join(getAbsolutePath(e.ssl.certPath),"server.crt"),"utf8")}catch(t){log(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const n=https.createServer({key:t,cert:o},app);_attachServerErrorHandlers(n),n.listen(e.ssl.port,e.host,(()=>{activeServers.set(e.ssl.port,n),log(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}))}}rateLimitingMiddleware(app,e.rateLimiting),validationMiddleware(app),healthRoutes(app),exportRoutes(app),uiRoutes(app),versionChangeRoutes(app),errorMiddleware(app)}catch(e){throw new ExportError("[server] Could not configure and start the server.",500).setError(e)}}function closeServers(){if(activeServers.size>0){log(4,"[server] Closing all servers.");for(const[e,t]of activeServers)t.close((()=>{activeServers.delete(e),log(4,`[server] Closed server on port: ${e}.`)}))}}function getServers(){return activeServers}function getExpress(){return express}function getApp(){return app}function enableRateLimiting(e){rateLimitingMiddleware(app,e)}function use(e,...t){app.use(e,...t)}function get(e,...t){app.get(e,...t)}function post(e,...t){app.post(e,...t)}function _attachServerErrorHandlers(e){e.on("clientError",((e,t)=>{logWithStack(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{logWithStack(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{logWithStack(1,e,`[server] Socket error: ${e.message}`)}))}))}var server={startServer:startServer,closeServers:closeServers,getServers:getServers,getExpress:getExpress,getApp:getApp,enableRateLimiting:enableRateLimiting,use:use,get:get,post:post};async function shutdownCleanUp(e){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e){const t=mergeOptions(getOptions(!1),e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkAndUpdateCache(t.highcharts,t.server.proxy),await initPool(t.pool,t.puppeteer.args)}function _attachProcessExitListeners(){log(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{log(4,`[process] Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp(0)})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={server:server,startServer:startServer,getOptions:getOptions,setOptions:setOptions,mergeOptions:mergeOptions,mapToNewOptions:mapToNewOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,checkAndUpdateCache:checkAndUpdateCache,initPool:initPool,killPool:killPool,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:setLogLevel,enableConsoleLogging:enableConsoleLogging,enableFileLogging:enableFileLogging,shutdownCleanUp:shutdownCleanUp};export{index as default,initExport}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 6ba656d..7540835 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/envs.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/errors/HttpError.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is 0.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is null.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * the `level` will be passed directly to `console.log`, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the rest are strings to build a message with.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - Object containing `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose, or 5 = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (level >= 0 && level <= logging.levelsDesc.length) {\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update options for the console logging\r\n logging.toConsole = toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path for the log file.\r\n * @param {string} file - The log file name.\r\n * @param {boolean} toFile - The flag for setting the logging to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update options for the file logging\r\n logging.toFile = toFile;\r\n\r\n // Set the `dest` and `file` only if the file logging is enabled\r\n if (toFile) {\r\n logging.dest = dest;\r\n logging.file = file;\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file is responsible for parsing the environment variables\r\n * with the 'zod' library. The parsed environment variables are then exported\r\n * to be used in the application as `envs`. We should not use the `process.env`\r\n * directly in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: v.string(),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(defaultConfig.highcharts.coreScripts.value),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(\r\n defaultConfig.highcharts.moduleScripts.value\r\n ),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(\r\n defaultConfig.highcharts.indicatorScripts.value\r\n ),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: v.array(\r\n defaultConfig.highcharts.customScripts.value\r\n ),\r\n\r\n // export\r\n EXPORT_INFILE: v.string(),\r\n EXPORT_INSTR: v.string(),\r\n EXPORT_OPTIONS: v.string(),\r\n EXPORT_SVG: v.string(),\r\n EXPORT_BATCH: v.string(),\r\n EXPORT_OUTFILE: v.string(),\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_B64: v.boolean(),\r\n EXPORT_NO_DOWNLOAD: v.boolean(),\r\n EXPORT_HEIGHT: v.positiveNum(),\r\n EXPORT_WIDTH: v.positiveNum(),\r\n EXPORT_SCALE: v.positiveNum(),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_GLOBAL_OPTIONS: v.string(),\r\n EXPORT_THEME_OPTIONS: v.string(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n CUSTOM_LOGIC_CUSTOM_CODE: v.string(),\r\n CUSTOM_LOGIC_CALLBACK: v.string(),\r\n CUSTOM_LOGIC_RESOURCES: v.string(),\r\n CUSTOM_LOGIC_LOAD_CONFIG: v.string(),\r\n CUSTOM_LOGIC_CREATE_CONFIG: v.string(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_UPLOAD_LIMIT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n LOGGING_TO_CONSOLE: v.boolean(),\r\n LOGGING_TO_FILE: v.boolean(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack } from './logger.js';\r\nimport { envs } from './envs.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n/**\r\n * Gets the reference to the global options of the server instance object\r\n * or its copy.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getReference=true] - Optional parameter to decide whether\r\n * to return the reference to the global options of the server instance object\r\n * or return a copy of it. The default value is true.\r\n *\r\n * @returns {Object} The reference to the global options of the server instance\r\n * object or its copy.\r\n */\r\nexport function getOptions(getReference = true) {\r\n return getReference ? globalOptions : deepCopy(globalOptions);\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server instance, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the first parameter (by default an empty object).\r\n * 5. Options from the CLI.\r\n *\r\n * @function setOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n * @param {boolean} [modifyGlobal=false] - Optional parameter to decide\r\n * whether to update and return the reference to the global options\r\n * of the server instance object or return a copy of it. The default value\r\n * is false.\r\n *\r\n * @returns {Object} The updated general options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setOptions(\r\n customOptions = {},\r\n cliArgs = [],\r\n modifyGlobal = false\r\n) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n // Get options from the custom JSON loaded via the `loadConfig`\r\n configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Get options from the CLI\r\n cliOptions = _pairArgumentValue(nestedProps, cliArgs);\r\n }\r\n\r\n // Get the reference to the global options object or a copy of the object\r\n const generalOptions = getOptions(modifyGlobal);\r\n\r\n // Update values of the general options with values from each source possible\r\n _updateOptions(\r\n defaultConfig,\r\n generalOptions,\r\n configOptions,\r\n customOptions,\r\n cliOptions\r\n );\r\n\r\n // Return options\r\n return generalOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `newOptions` is a correct object\r\n if (isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key];\r\n }\r\n }\r\n\r\n // Return the result options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (Object.prototype.toString.call(oldOptions) === '[object Object]') {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is false.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is false.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is false.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg')).toString().bold\r\n .yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : _initGlobalOptions(item);\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates options object with values from various sources, following a specific\r\n * prioritization order. The function checks for values in the following order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The options object that will be updated with values\r\n * from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which may override configuration options.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateOptions(config, options, configOpt, customOpt, cliOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateOptions(entry, options[key], configVal, customVal, cliVal);\r\n } else {\r\n // If a value from custom JSON options exists, it take precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it take precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from user options exists, it take precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n\r\n // If a value from CLI options exists, it take precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(getAbsolutePath(configFileName)));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options.\r\n * It may include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } = highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n */\r\nexport async function createChart(options) {\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: options.export.height,\r\n width: options.export.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${options.export.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${options.export.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(\r\n `return ${options.export.globalOptions}`\r\n )();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (options.customLogic.customCode) {\r\n new Function('options', options.customLogic.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[options.export.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, options) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n let isSVG = false;\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await _setAsSvg(page, exportOptions.svg);\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await _setAsOptions(page, options);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, options.customLogic))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Sets the specified page's content with provided export input within\r\n * the window context using the `page.setContent` function.\r\n *\r\n * @async\r\n * @function _setAsSvg\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {Promise} A Promise that resolves after the content is set.\r\n */\r\nasync function _setAsSvg(page, svg) {\r\n await page.setContent(svgTemplate(svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n}\r\n\r\n/**\r\n * Sets the options with specified export input and sizes as configuration into\r\n * the `createChart` function within the window context using\r\n * the `page.evaluate` function.\r\n *\r\n * @async\r\n * @function _setAsOptions\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves after the configuration\r\n * is set.\r\n */\r\nasync function _setAsOptions(page, options) {\r\n await page.evaluate(createChart, options);\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} [poolOptions=getOptions().pool] - Object containing `pool`\r\n * options. The default value is the global pool options of the export server\r\n * instance.\r\n * @param {Array.} [puppeteerArgs=[]] - Additional arguments\r\n * for Puppeteer launch. The default value is an empty array.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(\r\n poolOptions = getOptions().pool,\r\n puppeteerArgs = []\r\n) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (getOptions().pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - Object containing `pool` options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, mergeOptions, isAllowedConfig } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, getPoolStats } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the image in the provided outfile.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain at least one of the following\r\n * properties: `infile`, `instr`, `options`, or `svg` to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(options, async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the `batch` option. The `batch` is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results are saved\r\n * in provided outfiles.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain the `batch` option to generate\r\n * valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `customOptions` parameter is an object that\r\n * may be partial or complete set of options. The `endCallback` is called when\r\n * the export is completed, with the `error` object as the first argument\r\n * and the `data` object as the second, which contains the Base64 representation\r\n * of the chart in the `result` property and the full set of export options\r\n * in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process. The first\r\n * argument is `error` object and the `data` object is the second, that contains\r\n * the Base64 representation of the chart in the `result` property and the full\r\n * set of export options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(customOptions, endCallback) {\r\n try {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Merge the custom options into default ones\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n // Set to the `svg` option\r\n exportOptions.svg = fileContent;\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = fileContent;\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n *\r\n * @returns {Object} An object containing the calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is null.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n startExport,\r\n singleExport,\r\n batchExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} [rateLimitingOptions=getOptions().server.rateLimiting] -\r\n * Object containing `rateLimiting` options. The default value is the global\r\n * rate limiting options of the export server instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(\r\n app,\r\n rateLimitingOptions = getOptions().server.rateLimiting\r\n) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: rateLimitingOptions.maxRequests || 30,\r\n window: rateLimitingOptions.window || 1,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || false,\r\n skipToken: rateLimitingOptions.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport ExportError from './ExportError.js';\r\n\r\n/**\r\n * A custom HTTP error class that extends the `ExportError`. Used to handle\r\n * errors with HTTP status codes.\r\n */\r\nclass HttpError extends ExportError {\r\n /**\r\n * Creates an instance of the `HttpError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super(message, statusCode);\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {HttpError} The updated instance of the `HttpError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new HttpError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the body is not correct.\r\n * @throws {HttpError} Throws an `HttpError` if the chart data from the body\r\n * is not correct.\r\n * @throws {HttpError} Throws an `HttpError` in case of the private range url\r\n * error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid().replace(/-/g, '');\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get the allowCodeExecution option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new HttpError(\r\n \"[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get options from the body and store parsed structure in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `_requestId` property in the validated options\r\n _requestId: requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${fixType(body.type)}`,\r\n type: fixType(body.type, body.outfile),\r\n constr: fixConstr(body.constr),\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n };\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions._requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Got an incoming HTTP request with ID ${requestId}.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new HttpError(\r\n '[export] Unexpected return of the export result from the chart generation. Please check your request data.',\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(readFileSync(join(__dirname, 'package.json')));\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts HTTP or/and HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains all server related properties (see\r\n * the `server` section in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions=getOptions().server] - Object containing\r\n * `server` options. The default value is the global server options\r\n * of the export server instance.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when the server should not be enabled or when no valid Express app\r\n * is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions = getOptions().server) {\r\n try {\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n healthRoutes(app);\r\n exportRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - Object containing `rateLimiting`\r\n * options.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n rateLimitingMiddleware(app, rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Cleans up function to trigger before ending process for the graceful\r\n * shutdown.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} exitCode - An exit code for the `process.exit()` function.\r\n */\r\nexport async function shutdownCleanUp(exitCode) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\nimport server, { startServer } from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage. This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n */\r\nexport async function initExport(customOptions) {\r\n // Get the global options object copy and extend it with the incoming options\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Options\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Cache\r\n checkAndUpdateCache,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n\r\n // Utils\r\n shutdownCleanUp\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","v","array","filterArray","z","string","transform","map","filter","boolean","enum","refine","positiveNum","isNaN","parseFloat","nonNegativeNum","Config","object","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","partial","parse","env","_initGlobalOptions","getOptions","getReference","setOptions","customOptions","cliArgs","modifyGlobal","configOptions","cliOptions","_loadConfigFile","_pairArgumentValue","generalOptions","_updateOptions","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","index","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","name","configOpt","customOpt","cliOpt","configVal","customVal","cliVal","envVal","stringifyFunctions","stringify","replaceAll","Error","configIndex","findIndex","arg","configFileName","i","option","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","ExportError","constructor","statusCode","super","this","setError","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","indexOf","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","additionalOptions","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","customLogicOptions","injectedResources","injectedJs","js","content","files","isLocal","jsResource","addScriptTag","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","exportOptions","isSVG","_setAsSvg","_setAsOptions","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","_requestId","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","uuid","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","data","batchExport","batchFunctions","pair","batchResults","allSettled","reason","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","msg","rateOptions","limiter","rateLimit","windowMs","delayMs","handler","format","send","default","skip","query","access_token","HttpError","setStatus","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","requestId","connection","remoteAddress","validatedOptions","params","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","adminToken","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","limit","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","enableRateLimiting","middlewares","shutdownCleanUp","exitCode","exit","initExport","_attachProcessExitListeners","code"],"mappings":"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B,GAGP,CCrOO,MAAMiB,cAAgB,CAC3BC,UAAW,CACT7B,KAAM,CACJvB,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFqD,MAAO,CAAC,YACRC,QAAS,iBACTC,QAAS,gBACTC,YAAa,+BACbC,cAAe,CACbnG,KAAM,OACNoG,UAAW,OAIjBC,WAAY,CACVC,QAAS,CACP5D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,qBACbC,cAAe,CACbnG,KAAM,SAGVuG,OAAQ,CACN7D,MAAO,8BACPqD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,iCACbC,cAAe,CACbnG,KAAM,SAGVwG,WAAY,CACV9D,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbnG,KAAM,WAGVyG,UAAW,CACT/D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbnG,KAAM,SAGV0G,YAAa,CACXhE,MAAO,CAAC,aAAc,kBAAmB,iBACzCqD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbnG,KAAM,cACN2G,aAAc,0DAGlBC,cAAe,CACblE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,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"} \ No newline at end of file +{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../templates/svgExport/css.js","../templates/svgExport/svgExport.js","../lib/export.js","../lib/pool.js","../lib/sanitize.js","../lib/chart.js","../lib/timer.js","../lib/server/middlewares/error.js","../lib/server/middlewares/rateLimiting.js","../lib/errors/HttpError.js","../lib/server/middlewares/validation.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/routes/ui.js","../lib/server/routes/versionChange.js","../lib/server/server.js","../lib/resourceRelease.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The Highcharts Export Server utility module provides\r\n * a comprehensive set of helper functions and constants designed to streamline\r\n * and enhance various operations required for Highcharts export tasks.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { isAbsolute, join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\n// The directory path\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @function clearText\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters. The default value\r\n * is the '/\\s\\s+/g' RegExp.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters. The default value is the ' ' string.\r\n *\r\n * @returns {string} The cleared and standardized text.\r\n */\r\nexport function clearText(text, rule = /\\s\\s+/g, replacer = ' ') {\r\n return text.replaceAll(rule, replacer).trim();\r\n}\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @function deepCopy\r\n *\r\n * @param {(Object|Array)} objArr - The object or array to be deeply copied.\r\n *\r\n * @returns {(Object|Array)} The deep copy of the provided object or array.\r\n */\r\nexport function deepCopy(objArr) {\r\n // If the `objArr` is null or not of the `object` type, return it\r\n if (objArr === null || typeof objArr !== 'object') {\r\n return objArr;\r\n }\r\n\r\n // Prepare either a new array or a new object\r\n const objArrCopy = Array.isArray(objArr) ? [] : {};\r\n\r\n // Recursively copy each property\r\n for (const key in objArr) {\r\n if (Object.prototype.hasOwnProperty.call(objArr, key)) {\r\n objArrCopy[key] = deepCopy(objArr[key]);\r\n }\r\n }\r\n\r\n // Return the copied object\r\n return objArrCopy;\r\n}\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @async\r\n * @function expBackoff\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number. The default value\r\n * is 0.\r\n * @param {...unknown} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} A Promise that resolves to the result\r\n * of the function if successful.\r\n *\r\n * @throws {Error} Throws an `Error` if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport async function expBackoff(fn, attempt = 0, ...args) {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of repeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n\r\n /// TO DO: Correct\r\n // // Information about the resource timeout\r\n // log(\r\n // 3,\r\n // `[utils] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.`\r\n // );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n}\r\n\r\n/**\r\n * Adjusts the constructor name by transforming and normalizing it based\r\n * on common chart types.\r\n *\r\n * @function fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be fixed.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nexport function fixConstr(constr) {\r\n try {\r\n // Fix the constructor by lowering casing\r\n const fixedConstr = `${constr.toLowerCase().replace('chart', '')}Chart`;\r\n\r\n // Handle the case where the result is just 'Chart'\r\n if (fixedConstr === 'Chart') {\r\n fixedConstr.toLowerCase();\r\n }\r\n\r\n // Return the corrected constructor, otherwise default to 'chart'\r\n return ['chart', 'stockChart', 'mapChart', 'ganttChart'].includes(\r\n fixedConstr\r\n )\r\n ? fixedConstr\r\n : 'chart';\r\n } catch {\r\n // Default to 'chart' in case of any error\r\n return 'chart';\r\n }\r\n}\r\n\r\n/**\r\n * Fixes the outfile based on provided type.\r\n *\r\n * @function fixOutfile\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} The corrected outfile.\r\n */\r\nexport function fixOutfile(type, outfile) {\r\n // Get the file name from the `outfile` option\r\n const fileName = getAbsolutePath(outfile || 'chart')\r\n .split('.')\r\n .shift();\r\n\r\n // Return a correct outfile\r\n return `${fileName}.${type}`;\r\n}\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @function fixType\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} [outfile=null] - The file path or name. The default value\r\n * is null.\r\n *\r\n * @returns {string} The corrected export type.\r\n */\r\nexport function fixType(type, outfile = null) {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Get formats\r\n const formats = Object.values(mimeTypes);\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n // Support the JPG type\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n}\r\n\r\n/**\r\n * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function isAbsolutePath\r\n *\r\n * @param {string} path - The path to be checked on.\r\n *\r\n * @returns {string} The absolute path.\r\n */\r\nexport function getAbsolutePath(path) {\r\n return isAbsolute(path) ? path : join(__dirname, path);\r\n}\r\n\r\n/**\r\n * Converts input data to a Base64 string based on the export type.\r\n *\r\n * @function getBase64\r\n *\r\n * @param {string} input - The input to be transformed to Base64 format.\r\n * @param {string} type - The original export type.\r\n *\r\n * @returns {string} The Base64 string representation of the input.\r\n */\r\nexport function getBase64(input, type) {\r\n // For pdf and svg types the input must be transformed to Base64 from a buffer\r\n if (type === 'pdf' || type == 'svg') {\r\n return Buffer.from(input, 'utf8').toString('base64');\r\n }\r\n\r\n // For png and jpeg input is already a Base64 string\r\n return input;\r\n}\r\n\r\n/**\r\n * Returns stringified date without the GMT text information.\r\n *\r\n * @function getNewDate\r\n */\r\nexport function getNewDate() {\r\n // Get rid of the GMT text information\r\n return new Date().toString().split('(')[0].trim();\r\n}\r\n\r\n/**\r\n * Returns the stored time value in milliseconds.\r\n *\r\n * @function getNewDateTime\r\n */\r\nexport function getNewDateTime() {\r\n return new Date().getTime();\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @function isObject\r\n *\r\n * @param {unknown} item - The item to be checked.\r\n *\r\n * @returns {boolean} True if the item is an object, false otherwise.\r\n */\r\nexport function isObject(item) {\r\n return Object.prototype.toString.call(item) === '[object Object]';\r\n}\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @function isObjectEmpty\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} True if the object is empty, false otherwise.\r\n */\r\nexport function isObjectEmpty(item) {\r\n return (\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0\r\n );\r\n}\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @function isPrivateRangeUrlFound\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} True if a private IP range URL is found, false otherwise.\r\n */\r\nexport function isPrivateRangeUrlFound(item) {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n}\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js `process.hrtime()` method.\r\n *\r\n * @function measureTime\r\n *\r\n * @returns {Function} A function to calculate the elapsed time in milliseconds.\r\n */\r\nexport function measureTime() {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @function roundNumber\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} The rounded number.\r\n */\r\nexport function roundNumber(value, precision = 1) {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n}\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @function toBoolean\r\n *\r\n * @param {unknown} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} The boolean representation of the input value.\r\n */\r\nexport function toBoolean(item) {\r\n return ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n}\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @function wrapAround\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n * @param {boolean} [isCallback=false] - Flag that indicates the returned code\r\n * must be in a callback format.\r\n *\r\n * @returns {(string|null)} The wrapped custom code or null if wrapping fails.\r\n */\r\nexport function wrapAround(customCode, allowFileResources, isCallback = false) {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n // Load a file if the file resources are allowed\r\n return allowFileResources\r\n ? wrapAround(\r\n readFileSync(getAbsolutePath(customCode), 'utf8'),\r\n allowFileResources,\r\n isCallback\r\n )\r\n : null;\r\n } else if (\r\n !isCallback &&\r\n (customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>'))\r\n ) {\r\n // Treat a function as a self-invoking expression\r\n return `(${customCode})()`;\r\n }\r\n\r\n // Or return as a stringified code\r\n return customCode.replace(/;$/, '');\r\n }\r\n}\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\r\n fixConstr,\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n getNewDate,\r\n getNewDateTime,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n measureTime,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module for managing logging functionality with customizable\r\n * log levels, console and file logging options, and error handling support.\r\n * The module also ensures that file-based logs are stored in a structured\r\n * directory, creating the necessary paths automatically if they do not exist.\r\n */\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getAbsolutePath, getNewDate } from './utils.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nconst logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Full path to the log file\r\n pathToLog: '',\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ]\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * the `level` will be passed directly to `console.log`, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @function log\r\n *\r\n * @param {...unknown} args - An array of arguments where the first is the log\r\n * level and the rest are strings to build a message with.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function log(...args) {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if the log level is within a correct range or is it a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @function logWithStack\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n *\r\n * @returns {void} Ends the function execution when attempting to log\r\n * information at a higher level than what is allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if the log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Create a message's prefix\r\n const prefix = `${getNewDate()} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Add the whole stack message\r\n const stackMessage = error.stack;\r\n\r\n // Combine custom message or error message with error stack message, if exists\r\n const texts = [mainMessage];\r\n if (stackMessage) {\r\n texts.push('\\n', stackMessage);\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n _logToFile(texts, prefix);\r\n }\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n texts.shift()[colors[newLevel - 1]],\r\n ...texts\r\n ])\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Logs an error message about Zod issues with the validation. Optionally,\r\n * a custom message can be provided.\r\n *\r\n * @function logZodIssues\r\n *\r\n * @param {number} newLevel - The log level.\r\n * @param {Error[]} issues - The array of Zod issues.\r\n * @param {string} customMessage - An optional custom message to be logged\r\n * along with the error.\r\n */\r\nexport function logZodIssues(newLevel, issues = [], customMessage) {\r\n logWithStack(\r\n newLevel,\r\n null,\r\n [\r\n `${customMessage} - the following Zod issues occured:`,\r\n ...issues.map((issue) => `- ${issue.message}`)\r\n ].join('\\n')\r\n );\r\n}\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @function initLogging\r\n *\r\n * @param {Object} loggingOptions - Object containing `logging` options.\r\n */\r\nexport function initLogging(loggingOptions) {\r\n // Get options from the `loggingOptions` object\r\n const { level, dest, file, toConsole, toFile } = loggingOptions;\r\n\r\n // Set the logging level\r\n setLogLevel(level);\r\n\r\n // Set the console logging\r\n enableConsoleLogging(toConsole);\r\n\r\n // Set the file logging\r\n enableFileLogging(dest, file, toFile);\r\n}\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose, or 5 = benchmark).\r\n *\r\n * @function setLogLevel\r\n *\r\n * @param {number} level - The log level to be set.\r\n */\r\nexport function setLogLevel(level) {\r\n if (level >= 0 && level <= logging.levelsDesc.length) {\r\n logging.level = level;\r\n }\r\n}\r\n\r\n/**\r\n * Enables console logging.\r\n *\r\n * @function enableConsoleLogging\r\n *\r\n * @param {boolean} toConsole - The flag for setting the logging to the console.\r\n */\r\nexport function enableConsoleLogging(toConsole) {\r\n // Update options for the console logging\r\n logging.toConsole = toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path for the log file.\r\n * @param {string} file - The log file name.\r\n * @param {boolean} toFile - The flag for setting the logging to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update options for the file logging\r\n logging.toFile = toFile;\r\n\r\n // Set the `dest` and `file` only if the file logging is enabled\r\n if (toFile) {\r\n logging.dest = dest;\r\n logging.file = file;\r\n }\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends\r\n * the content, including an optional prefix, to the specified log file.\r\n *\r\n * @function _logToFile\r\n *\r\n * @param {Array.} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nfunction _logToFile(texts, prefix) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(getAbsolutePath(logging.dest)) &&\r\n mkdirSync(getAbsolutePath(logging.dest));\r\n\r\n // Create the full path\r\n logging.pathToLog = getAbsolutePath(join(logging.dest, logging.file));\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n logging.pathToLog,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error && logging.toFile && logging.pathCreated) {\r\n logging.toFile = false;\r\n logging.pathCreated = false;\r\n logWithStack(2, error, `[logger] Unable to write to log file.`);\r\n }\r\n }\r\n );\r\n}\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Configuration management module for the Highcharts Export Server.\r\n * Provides default configurations that support environment variables, CLI\r\n * arguments, and interactive prompts for customization of options and features.\r\n * Additionally, it maps legacy options to modern structures, generates nested\r\n * argument mappings, and displays CLI usage information.\r\n */\r\n\r\n/**\r\n * The configuration object containing all available options, organized\r\n * by sections.\r\n *\r\n * This object includes:\r\n * - Default values for each option\r\n * - Data types for validation\r\n * - Names of corresponding environment variables\r\n * - Descriptions of each property\r\n * - Information used for prompts in interactive configuration\r\n * - [Optional] Corresponding CLI argument names for CLI usage\r\n * - [Optional] Legacy names from the previous PhantomJS-based server\r\n */\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'PUPPETEER_ARGS',\r\n cliName: 'puppeteerArgs',\r\n description: 'Array of Puppeteer arguments',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'Highcharts version',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n cdnUrl: {\r\n value: 'https://code.highcharts.com',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'CDN URL for Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n forceFetch: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description: 'Flag to refetch scripts after each server rerun',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n types: ['string'],\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description: 'Directory path for cached Highcharts scripts',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n coreScripts: {\r\n value: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'Highcharts core scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n moduleScripts: {\r\n value: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'Highcharts module scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n indicatorScripts: {\r\n value: ['indicators-all'],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'Highcharts indicator scripts to fetch',\r\n promptOptions: {\r\n type: 'multiselect',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm'\r\n }\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ],\r\n types: ['string[]'],\r\n envLink: 'HIGHCHARTS_CUSTOM_SCRIPTS',\r\n description: 'Additional custom scripts or dependencies to fetch',\r\n promptOptions: {\r\n type: 'list',\r\n separator: ';'\r\n }\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INFILE',\r\n description:\r\n 'Input filename with type, formatted correctly as JSON or SVG',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n instr: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_INSTR',\r\n description:\r\n 'Overrides the `infile` with JSON, stringified JSON, or SVG input',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n options: {\r\n value: null,\r\n types: ['Object', 'null'],\r\n envLink: 'EXPORT_OPTIONS',\r\n description: 'Alias for the `instr` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n svg: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_SVG',\r\n description: 'SVG string representation of the chart to render',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n batch: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_BATCH',\r\n description:\r\n 'Batch job string with input/output pairs: \"in=out;in=out;...\"',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n outfile: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'EXPORT_OUTFILE',\r\n description:\r\n 'Output filename with type. Can be jpeg, png, pdf, or svg and ignores `type` option',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n type: {\r\n value: 'png',\r\n types: ['string'],\r\n envLink: 'EXPORT_TYPE',\r\n description: 'File export format. Can be jpeg, png, pdf, or svg',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: png',\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n }\r\n },\r\n constr: {\r\n value: 'chart',\r\n types: ['string'],\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'Chart constructor. Can be chart, stockChart, mapChart, or ganttChart',\r\n promptOptions: {\r\n type: 'select',\r\n hint: 'Default: chart',\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n }\r\n },\r\n b64: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_B64',\r\n description:\r\n 'Whether or not to the chart should be received in Base64 format instead of binary',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noDownload: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'EXPORT_NO_DOWNLOAD',\r\n description:\r\n 'Whether or not to include or exclude attachment headers in the response',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n height: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_HEIGHT',\r\n description: 'Height of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n width: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_WIDTH',\r\n description: 'Width of the exported chart, overrides chart settings',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n scale: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'EXPORT_SCALE',\r\n description:\r\n 'Scale of the exported chart, overrides chart settings. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description: 'Default height of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description: 'Default width of the exported chart if not set',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n defaultScale: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'Default scale of the exported chart if not set. Ranges from 0.1 to 5.0',\r\n promptOptions: {\r\n type: 'number',\r\n min: 0.1,\r\n max: 5\r\n }\r\n },\r\n globalOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_GLOBAL_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with global options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n themeOptions: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'EXPORT_THEME_OPTIONS',\r\n description:\r\n 'JSON, stringified JSON or filename with theme options for Highcharts.setOptions',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n types: ['number'],\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description: 'Milliseconds to wait for webpage rendering',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Allows or disallows execution of arbitrary code during exporting',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n allowFileResources: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Allows or disallows injection of filesystem resources (disabled in server mode)',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n customCode: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CUSTOM_CODE',\r\n description:\r\n 'Custom code to execute before chart initialization. Can be a function, code wrapped in a function, or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n callback: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CALLBACK',\r\n description:\r\n 'JavaScript code to run during construction. Can be a function or a .js filename',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n resources: {\r\n value: null,\r\n types: ['Object', 'string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_RESOURCES',\r\n description:\r\n 'Additional resources as JSON, stringified JSON, or filename, containing files, js, and css sections',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n loadConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_LOAD_CONFIG',\r\n legacyName: 'fromFile',\r\n description: 'File with a pre-defined configuration to use',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n createConfig: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'CUSTOM_LOGIC_CREATE_CONFIG',\r\n description:\r\n 'Prompt-based option setting, saved to a provided config file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description: 'Starts the server when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n types: ['string'],\r\n envLink: 'SERVER_HOST',\r\n description: 'Hostname of the server',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: 7801,\r\n types: ['number'],\r\n envLink: 'SERVER_PORT',\r\n description: 'Port number for the server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n uploadLimit: {\r\n value: 3,\r\n types: ['number'],\r\n envLink: 'SERVER_UPLOAD_LIMIT',\r\n description: 'Maximum request body size in MB',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Displays or not action durations in milliseconds during server requests',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n proxy: {\r\n host: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'Host of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n port: {\r\n value: null,\r\n types: ['number', 'null'],\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'Port of the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n timeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description:\r\n 'Timeout in milliseconds for the proxy server, if applicable',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables or disables rate limiting on the server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n maxRequests: {\r\n value: 10,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'Maximum number of requests allowed per minute',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n window: {\r\n value: 1,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'Time window in minutes for rate limiting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n delay: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'Delay duration between successive requests before reaching the limit',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n trustProxy: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set to true if the server is behind a load balancer',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n skipKey: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description: 'Key to bypass the rate limiter, used with `skipToken`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n skipToken: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description: 'Token to bypass the rate limiter, used with `skipKey`',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables SSL protocol',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n force: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description: 'Forces the server to use HTTPS only when true',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n port: {\r\n value: 443,\r\n types: ['number'],\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'Port for the SSL server',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n certPath: {\r\n value: null,\r\n types: ['string', 'null'],\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n cliName: 'sslCertPath',\r\n legacyName: 'sslPath',\r\n description: 'Path to the SSL certificate/key file',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'Minimum and initial number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n types: ['number'],\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'Maximum number of pool workers to spawn',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n workLimit: {\r\n value: 40,\r\n types: ['number'],\r\n envLink: 'POOL_WORK_LIMIT',\r\n description: 'Number of tasks a worker can handle before restarting',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description: 'Timeout in milliseconds for acquiring a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description: 'Timeout in milliseconds for creating a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n types: ['number'],\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying a resource',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n types: ['number'],\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description: 'Timeout in milliseconds for destroying idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n types: ['number'],\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'Interval in milliseconds before retrying resource creation on failure',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n types: ['number'],\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'Interval in milliseconds to check and destroy idle resources',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n benchmarking: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description: 'Shows statistics for the pool of resources',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n types: ['number'],\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'Logging verbosity level',\r\n promptOptions: {\r\n type: 'number',\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n }\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n types: ['string'],\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'Log file name. Requires `logToFile` and `logDest` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n dest: {\r\n value: 'log',\r\n types: ['string'],\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description: 'Path to store log files. Requires `logToFile` to be set',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n toConsole: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables console logging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n toFile: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description: 'Enables or disables logging to a file',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description: 'Enables or disables the UI for the export server',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n route: {\r\n value: '/',\r\n types: ['string'],\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description: 'The endpoint route for the UI',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n types: ['string'],\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The Node.js environment type',\r\n promptOptions: {\r\n type: 'text'\r\n }\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Whether or not to attach process.exit handlers',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n noLogo: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_NO_LOGO',\r\n description: 'Display or skip printing the logo on startup',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n hardResetPage: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Whether or not to reset the page content entirely',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n browserShellMode: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Whether or not to set the browser to run in shell mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n headless: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Whether or not to set the browser to run in headless mode during debugging',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n devtools: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description: 'Enables or disables DevTools in headful mode',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n listenToConsole: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Enables or disables listening to console messages from the browser',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n dumpio: {\r\n value: false,\r\n types: ['boolean'],\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects or not browser stdout and stderr to process.stdout and process.stderr',\r\n promptOptions: {\r\n type: 'toggle'\r\n }\r\n },\r\n slowMo: {\r\n value: 0,\r\n types: ['number'],\r\n envLink: 'DEBUG_SLOW_MO',\r\n description: 'Delays Puppeteer operations by the specified milliseconds',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n types: ['number'],\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Port used for debugging',\r\n promptOptions: {\r\n type: 'number'\r\n }\r\n }\r\n }\r\n};\r\n\r\n// Properties nesting level of all options\r\nexport const nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nexport const absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Recursively generates a mapping of nested argument chains from a nested\r\n * config object. This function traverses a nested object and creates a mapping\r\n * where each key is an argument name (either from `cliName`, `legacyName`,\r\n * or the original key) and each value is a string representing the chain\r\n * of nested properties leading to that argument.\r\n *\r\n * @function _createNestedProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Object} [nestedProps={}] - The accumulator object for storing\r\n * the resulting arguments chains. The default value is an empty object.\r\n * @param {string} [propChain=''] - The current chain of nested properties,\r\n * used internally during recursion. The default value is an empty string.\r\n *\r\n * @returns {Object} An object mapping argument names to their corresponding\r\n * nested property chains.\r\n */\r\nfunction _createNestedProps(config, nestedProps = {}, propChain = '') {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.value === 'undefined') {\r\n // Recurse into deeper levels of nested arguments\r\n _createNestedProps(entry, nestedProps, `${propChain}.${key}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedProps[entry.cliName || key] = `${propChain}.${key}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedProps[entry.legacyName] = `${propChain}.${key}`.substring(1);\r\n }\r\n }\r\n });\r\n\r\n // Return the object with nested argument chains\r\n return nestedProps;\r\n}\r\n\r\n/**\r\n * Recursively gathers the names of properties from a configuration object that\r\n * can be treated as absolute properties. These properties have values that\r\n * are objects and do not contain further nested depth when merging an object\r\n * containing these options.\r\n *\r\n * @function _createAbsoluteProps\r\n *\r\n * @param {Object} config - The configuration object.\r\n * @param {Array.} [absoluteProps=[]] - An array to collect the names\r\n * of absolute properties. The default value is an empty array.\r\n *\r\n * @returns {Array.} An array containing the names of absolute\r\n * properties.\r\n */\r\nfunction _createAbsoluteProps(config, absoluteProps = []) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the specific section\r\n const entry = config[key];\r\n\r\n // Check if there is still more depth to traverse\r\n if (typeof entry.types === 'undefined') {\r\n // Recurse into deeper levels\r\n _createAbsoluteProps(entry, absoluteProps);\r\n } else {\r\n // If the option can be an object, save its type in the array\r\n if (entry.types.includes('Object')) {\r\n absoluteProps.push(key);\r\n }\r\n }\r\n });\r\n\r\n // Return the array with the names of absolute properties\r\n return absoluteProps;\r\n}\r\n\r\nexport default {\r\n defaultConfig,\r\n nestedProps,\r\n absoluteProps\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This file handles parsing and validating options from multiple\r\n * sources (the config file, custom JSON, environment variables, CLI arguments,\r\n * and request payload) using the 'zod' library.\r\n *\r\n * Environment variables are parsed and validated only once at application\r\n * startup, and the validated results are exported as `envs` for use throughout\r\n * the application.\r\n *\r\n * Options from other sources, however, are parsed and validated on demand,\r\n * each time an export is attempted.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// Load the .env into environment variables\r\ndotenv.config();\r\n\r\n// Get scripts names of each category from the default config\r\nconst { coreScripts, moduleScripts, indicatorScripts } =\r\n defaultConfig.highcharts;\r\n\r\n// Sets the custom error map globally\r\nz.setErrorMap(_customErrorMap);\r\n\r\n/**\r\n * Object containing custom general validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst v = {\r\n /**\r\n * The `boolean` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept values are true\r\n * and false and the schema will validate against the default boolean\r\n * validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept values are true,\r\n * false, null, 'true', 'false', 'undefined', 'null', and ''. The strings\r\n * 'undefined', 'null', and '' will be transformed to null, the string 'true'\r\n * will be transformed to the boolean value true, and 'false' will\r\n * be transformed to the boolean value false.\r\n *\r\n * @function boolean\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating boolean values.\r\n */\r\n boolean(strictCheck) {\r\n return strictCheck\r\n ? z.boolean()\r\n : z\r\n .union([\r\n z\r\n .enum(['true', 'false', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true'\r\n : null\r\n ),\r\n z.boolean()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `string` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed strings except\r\n * the forbidden values: 'false', 'undefined', 'null', and ''.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed strings\r\n * and null. The forbidden values: 'false', 'undefined', 'null', and '' will\r\n * be transformed to null.\r\n *\r\n * @function string\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating string values.\r\n */\r\n string(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The string contains a forbidden value`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .transform((value) =>\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `enum` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `values` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will validate against the `values`\r\n * array with the default enum validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', and '', which will be transformed to null.\r\n *\r\n * @function enum\r\n *\r\n * @param {Array.} values - An array of valid string values\r\n * for the enum.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating enum values.\r\n */\r\n enum(values, strictCheck) {\r\n return strictCheck\r\n ? z.enum([...values])\r\n : z\r\n .enum([...values, 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `stringArray` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept an array of trimmed\r\n * string values filtered by the logic provided through the `filterCallback`.\r\n *\r\n * - When `strictCheck` is false, the schema will accept null and trimmed\r\n * string values which will be splitted into an array of strings and filtered\r\n * from the '[' and ']' characters and by the logic provided through\r\n * the `filterCallback`. If the array is empty, it will be transformed\r\n * to null.\r\n *\r\n * @function stringArray\r\n *\r\n * @param {function} filterCallback - The filter callback.\r\n * @param {string} separator - The separator for spliting a string.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating array of string\r\n * values.\r\n */\r\n stringArray(filterCallback, separator, strictCheck) {\r\n const arraySchema = z.string().trim().array();\r\n const stringSchema = z\r\n .string()\r\n .trim()\r\n .transform((value) => {\r\n if (value.startsWith('[')) {\r\n value = value.slice(1);\r\n }\r\n if (value.endsWith(']')) {\r\n value = value.slice(0, -1);\r\n }\r\n return value.split(separator);\r\n });\r\n\r\n const transformCallback = (value) =>\r\n value.map((value) => value.trim()).filter(filterCallback);\r\n\r\n return strictCheck\r\n ? arraySchema.transform(transformCallback)\r\n : z\r\n .union([stringSchema, arraySchema])\r\n .transform(transformCallback)\r\n .transform((value) => (value.length ? value : null))\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `positiveNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept positive number values\r\n * and validate against the default positive number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept positive number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a positive number. It will transform the string\r\n * to a positive number, or to null if it is 'undefined', 'null', or ''.\r\n *\r\n * @function positiveNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating positive number\r\n * values.\r\n */\r\n positiveNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().positive()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) > 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and positive`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().positive()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `nonNegativeNum` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept non-negative number\r\n * values and validate against the default non-negative number validator.\r\n *\r\n * - When `strictCheck` is false, the schema will accept non-negative number\r\n * values, null, and trimmed string values that can either be 'undefined',\r\n * 'null', '', or represent a non-negative number. It will transform\r\n * the string to a non-negative number, or to null if it is 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function nonNegativeNum\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating non-negative\r\n * number values.\r\n */\r\n nonNegativeNum(strictCheck) {\r\n return strictCheck\r\n ? z.number().nonnegative()\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) && Number(value) >= 0) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be numeric and non-negative`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().nonnegative()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `startsWith` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The schema will validate against the provided `prefixes` array to check\r\n * whether a string value starts with any of the values provided\r\n * in the `prefixes` array.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that start with values from the prefixes array.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that start with values from the prefixes array, null, 'undefined', 'null',\r\n * and '' where the schema will transform them to null.\r\n *\r\n * @function startsWith\r\n *\r\n * @param {Array.} prefixes - An array of prefixes to validate\r\n * the string against.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating strings that\r\n * starts with values.\r\n */\r\n startsWith(prefixes, strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => prefixes.some((prefix) => value.startsWith(prefix)),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n prefixes.some((prefix) => value.startsWith(prefix)) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with ${prefixes.join(', ')}`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `chartConfig` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `additionalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that end with '.json' and are at least one\r\n * character long excluding the extension, start with the '{' and end\r\n * with the '}', and null. The 'undefined', 'null', and '' values will\r\n * be transformed to null.\r\n *\r\n * @function additionalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating additional chart\r\n * options value.\r\n */\r\n additionalOptions() {\r\n return z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json' or starts with '{' and ends with '}'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n ),\r\n z.object({}).passthrough()\r\n ])\r\n .nullable();\r\n }\r\n};\r\n\r\n/**\r\n * Object containing custom config validators and parsers to avoid repetition\r\n * in schema objects. All validators apply to values from various sources,\r\n * including the default config file, a custom JSON file loaded with the option\r\n * called `loadConfig`, the .env file, CLI arguments, and the request payload.\r\n * The `strictCheck` flag enables stricter validation and parsing rules. This\r\n * flag is set to false for values that come from the .env file or CLI arguments\r\n * because they are provided as strings and need to be parsed accordingly first.\r\n */\r\nconst config = {\r\n /**\r\n * The `args` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function args\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `args`\r\n * option.\r\n */\r\n args(strictCheck) {\r\n return v.stringArray(\r\n (value) => !['false', 'undefined', 'null', ''].includes(value),\r\n ';',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `version` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that are a RegExp-based that allows to be 'latest', or in the format XX,\r\n * XX.YY, or XX.YY.ZZ, where XX, YY, and ZZ are numeric for the Highcharts\r\n * version option.\r\n *\r\n * - When `strictCheck` is false, the schema will accept also null,\r\n * 'undefined', 'null', or '' and in all cases the schema will transform them\r\n * to null.\r\n *\r\n * @function version\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `version`\r\n * option.\r\n */\r\n version(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine((value) => /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value), {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n })\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n /^(latest|\\d{1,2}(\\.\\d{1,2}){0,2})$/.test(value) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be 'latest', a major version, or in the form XX.YY.ZZ\"\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `cdnUrl` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function cdnUrl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cdnUrl`\r\n * option.\r\n */\r\n cdnUrl(strictCheck) {\r\n return v.startsWith(['http://', 'https://'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `forceFetch` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function forceFetch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `forceFetch`\r\n * option.\r\n */\r\n forceFetch(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `cachePath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function cachePath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `cachePath`\r\n * option.\r\n */\r\n cachePath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `adminToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function adminToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `adminToken`\r\n * option.\r\n */\r\n adminToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `coreScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function coreScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `coreScripts`\r\n * option.\r\n */\r\n coreScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => coreScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `moduleScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function moduleScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `moduleScripts` option.\r\n */\r\n moduleScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => moduleScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `indicatorScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function indicatorScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `indicatorScripts` option.\r\n */\r\n indicatorScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => indicatorScripts.value.includes(value),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `customScripts` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `stringArray` validator.\r\n *\r\n * @function customScripts\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `customScripts` option.\r\n */\r\n customScripts(strictCheck) {\r\n return v.stringArray(\r\n (value) => value.startsWith('https://') || value.startsWith('http://'),\r\n ',',\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `infile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.json' or '.svg', are at least one character long excluding\r\n * the extension and will be null if the provided value is null, 'undefined',\r\n * 'null', or ''.\r\n *\r\n * @function infile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `infile`\r\n * option.\r\n */\r\n infile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n (value.length >= 5 && value.endsWith('.svg')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `instr` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function instr\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `instr`\r\n * option.\r\n */\r\n instr() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `options` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `options` validator.\r\n *\r\n * @function options\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `options`\r\n * option.\r\n */\r\n options() {\r\n return v.chartConfig();\r\n },\r\n\r\n /**\r\n * The `svg` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures that the schema will accept object values\r\n * or trimmed string values that contain '\r\n value.indexOf('= 0 ||\r\n value.indexOf('= 0 ||\r\n ['false', 'undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that contains '\r\n !['false', 'undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `outfile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension, or null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept trimmed string values\r\n * that end with '.jpeg', '.jpg', '.png', '.pdf', or '.svg', are at least one\r\n * character long excluding the extension and will be null if the provided\r\n * value is null, 'undefined', 'null', or ''.\r\n *\r\n * @function outfile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `outfile`\r\n * option.\r\n */\r\n outfile(strictCheck) {\r\n return strictCheck\r\n ? z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .nullable()\r\n : z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.length >= 6 && value.endsWith('.jpeg')) ||\r\n (value.length >= 5 &&\r\n (value.endsWith('.jpg') ||\r\n value.endsWith('.png') ||\r\n value.endsWith('.pdf') ||\r\n value.endsWith('.svg'))) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .jpeg, .jpg, .png, .pdf, or .svg`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n )\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `type` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function type\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `type`\r\n * option.\r\n */\r\n type(strictCheck) {\r\n return v.enum(['jpeg', 'jpg', 'png', 'pdf', 'svg'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `constr` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function constr\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `constr`\r\n * option.\r\n */\r\n constr(strictCheck) {\r\n return v.enum(\r\n ['chart', 'stockChart', 'mapChart', 'ganttChart'],\r\n strictCheck\r\n );\r\n },\r\n\r\n /**\r\n * The `b64` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function b64\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `b64` option.\r\n */\r\n b64(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noDownload` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noDownload\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noDownload`\r\n * option.\r\n */\r\n noDownload(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultHeight` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultHeight\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultHeight` option.\r\n */\r\n defaultHeight(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultWidth` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function defaultWidth\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultWidth` option.\r\n */\r\n defaultWidth(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `defaultScale` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept number values that\r\n * are between 0.1 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept number values\r\n * and stringified number values that are between 0.1 and 5 (inclusive), null,\r\n * 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function defaultScale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `defaultScale` option.\r\n */\r\n defaultScale(strictCheck) {\r\n return strictCheck\r\n ? z.number().gte(0.1).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number(value) >= 0.1 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0.1 and 5.0 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().gte(0.1).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `height` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultHeight`\r\n * validator.\r\n *\r\n * @function height\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `height`\r\n * option.\r\n */\r\n height(strictCheck) {\r\n return this.defaultHeight(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `width` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultWidth`\r\n * validator.\r\n *\r\n * @function width\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `width`\r\n * option.\r\n */\r\n width(strictCheck) {\r\n return this.defaultWidth(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `scale` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `defaultScale`\r\n * validator.\r\n *\r\n * @function scale\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `scale`\r\n * option.\r\n */\r\n scale(strictCheck) {\r\n return this.defaultScale(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `globalOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function globalOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `globalOptions` option.\r\n */\r\n globalOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `themeOptions` validator that returns a Zod schema.\r\n *\r\n * The validation schema ensures the same work as the `additionalOptions`\r\n * validator.\r\n *\r\n * @function themeOptions\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `themeOptions` option.\r\n */\r\n themeOptions() {\r\n return v.additionalOptions();\r\n },\r\n\r\n /**\r\n * The `batch` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function batch\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `batch`\r\n * option.\r\n */\r\n batch(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `rasterizationTimeout` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function rasterizationTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `rasterizationTimeout` option.\r\n */\r\n rasterizationTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowCodeExecution` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowCodeExecution\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowCodeExecution` option.\r\n */\r\n allowCodeExecution(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `allowFileResources` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function allowFileResources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `allowFileResources` option.\r\n */\r\n allowFileResources(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `customCode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function customCode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `customCode`\r\n * option.\r\n */\r\n customCode(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `callback` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function callback\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `callback`\r\n * option.\r\n */\r\n callback(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resources` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept a partial object\r\n * with allowed properties `js`, `css`, and `files` where each of the allowed\r\n * properties can be null, stringified version of the object, string that ends\r\n * with the '.json', and null.\r\n *\r\n * - When `strictCheck` is false, the schema will accept a stringified version\r\n * of a partial object with allowed properties `js`, `css`, and `files` where\r\n * each of the allowed properties can be null, string that ends with the\r\n * '.json', and will be null if the provided value is 'undefined', 'null'\r\n * or ''.\r\n *\r\n * @function resources\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `resources`\r\n * option.\r\n */\r\n resources(strictCheck) {\r\n const objectSchema = z\r\n .object({\r\n js: v.string(false),\r\n css: v.string(false),\r\n files: v\r\n .stringArray(\r\n (value) => !['undefined', 'null', ''].includes(value),\r\n ',',\r\n true\r\n )\r\n .nullable()\r\n })\r\n .partial();\r\n\r\n const stringSchema1 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that starts with '{' and ends with '}`\r\n }\r\n }\r\n );\r\n\r\n const stringSchema2 = z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (value.startsWith('{') && value.endsWith('}')) ||\r\n (value.length >= 6 && value.endsWith('.json')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.json'`\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value) ? value : null\r\n );\r\n\r\n return strictCheck\r\n ? z.union([objectSchema, stringSchema1]).nullable()\r\n : z.union([objectSchema, stringSchema2]).nullable();\r\n },\r\n\r\n /**\r\n * The `loadConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.json'.\r\n *\r\n * @function loadConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `loadConfig`\r\n * option.\r\n */\r\n loadConfig(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 6 && value.endsWith('.json')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with .json `\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `createConfig` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `loadConfig` validator.\r\n *\r\n * @function createConfig\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createConfig` option.\r\n */\r\n createConfig(strictCheck) {\r\n return this.loadConfig(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableServer` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableServer\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableServer` option.\r\n */\r\n enableServer(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `host` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function host\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `host`\r\n * option.\r\n */\r\n host(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `port` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function port\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `port`\r\n * option.\r\n */\r\n port(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uploadLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function uploadLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uploadLimit`\r\n * option.\r\n */\r\n uploadLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `serverBenchmarking` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function serverBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `serverBenchmarking` option.\r\n */\r\n serverBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyHost` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function proxyHost\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyHost`\r\n * option.\r\n */\r\n proxyHost(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `proxyPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as a nullable `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `proxyPort`\r\n * option.\r\n */\r\n proxyPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck).nullable();\r\n },\r\n\r\n /**\r\n * The `proxyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function proxyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `proxyTimeout` option.\r\n */\r\n proxyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableRateLimiting` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `enableRateLimiting` option.\r\n */\r\n enableRateLimiting(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxRequests` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function maxRequests\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxRequests`\r\n * option.\r\n */\r\n maxRequests(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `window` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function window\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `window`\r\n * option.\r\n */\r\n window(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `delay` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function delay\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `delay`\r\n * option.\r\n */\r\n delay(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `trustProxy` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function trustProxy\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `trustProxy`\r\n * option.\r\n */\r\n trustProxy(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipKey` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipKey\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipKey`\r\n * option.\r\n */\r\n skipKey(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `skipToken` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function skipToken\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `skipToken`\r\n * option.\r\n */\r\n skipToken(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableSsl` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableSsl\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableSsl`\r\n * option.\r\n */\r\n enableSsl(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslForce` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function sslForce\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslForce`\r\n * option.\r\n */\r\n sslForce(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslPort` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function sslPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslPort`\r\n * option.\r\n */\r\n sslPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `sslCertPath` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function sslCertPath\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `sslCertPath`\r\n * option.\r\n */\r\n sslCertPath(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `minWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function minWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `minWorkers`\r\n * option.\r\n */\r\n minWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `maxWorkers` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function maxWorkers\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `maxWorkers`\r\n * option.\r\n */\r\n maxWorkers(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `workLimit` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `positiveNum` validator.\r\n *\r\n * @function workLimit\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `workLimit`\r\n * option.\r\n */\r\n workLimit(strictCheck) {\r\n return v.positiveNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `acquireTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function acquireTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `acquireTimeout` option.\r\n */\r\n acquireTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createTimeout` option.\r\n */\r\n createTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `destroyTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function destroyTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `destroyTimeout` option.\r\n */\r\n destroyTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `idleTimeout` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function idleTimeout\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `idleTimeout` option.\r\n */\r\n idleTimeout(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `createRetryInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function createRetryInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `createRetryInterval` option.\r\n */\r\n createRetryInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `reaperInterval` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function reaperInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `reaperInterval` option.\r\n */\r\n reaperInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `poolBenchmarking` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function poolBenchmarking\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `poolBenchmarking` option.\r\n */\r\n poolBenchmarking(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `resourcesInterval` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function resourcesInterval\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `resourcesInterval` option.\r\n */\r\n resourcesInterval(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logLevel` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures that:\r\n *\r\n * - When `strictCheck` is true, the schema will accept integer number values\r\n * that are between 0 and 5 (inclusive).\r\n *\r\n * - When `strictCheck` is false, the schema will accept integer number values\r\n * and stringified integer number values that are between 1 and 5 (inclusive),\r\n * null, 'undefined', 'null', and '' which will be transformed to null.\r\n *\r\n * @function logLevel\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logLevel`\r\n * option.\r\n */\r\n logLevel(strictCheck) {\r\n return strictCheck\r\n ? z.number().int().gte(0).lte(5)\r\n : z\r\n .union([\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n (!isNaN(Number(value)) &&\r\n value !== true &&\r\n !value.startsWith('[') &&\r\n Number.isInteger(Number(value)) &&\r\n Number(value) >= 0 &&\r\n Number(value) <= 5) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage: 'The value must be within a 0 and 5 range'\r\n }\r\n }\r\n )\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? Number(value)\r\n : null\r\n ),\r\n z.number().int().gte(0).lte(5)\r\n ])\r\n .nullable();\r\n },\r\n\r\n /**\r\n * The `logFile` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a string that ends with '.log'.\r\n *\r\n * @function logFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logFile`\r\n * option.\r\n */\r\n logFile(strictCheck) {\r\n return v\r\n .string(strictCheck)\r\n .refine(\r\n (value) =>\r\n value === null || (value.length >= 5 && value.endsWith('.log')),\r\n {\r\n params: {\r\n errorMessage: `The value must be a string that ends with '.log'`\r\n }\r\n }\r\n );\r\n },\r\n\r\n /**\r\n * The `logDest` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n *\r\n * @function logDest\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logDest`\r\n * option.\r\n */\r\n logDest(strictCheck) {\r\n return v.string(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `logToConsole` option.\r\n */\r\n logToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `logToFile` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function logToFile\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `logToFile`\r\n * option.\r\n */\r\n logToFile(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableUi` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableUi\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableUi`\r\n * option.\r\n */\r\n enableUi(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `uiRoute` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `startsWith` validator.\r\n *\r\n * @function uiRoute\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `uiRoute`\r\n * option.\r\n */\r\n uiRoute(strictCheck) {\r\n return v.startsWith(['/'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `nodeEnv` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `enum` validator.\r\n *\r\n * @function nodeEnv\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `nodeEnv`\r\n * option.\r\n */\r\n nodeEnv(strictCheck) {\r\n return v.enum(['development', 'production', 'test'], strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToProcessExits` validator that returns a Zod schema with\r\n * an optional stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToProcessExits\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToProcessExits` option.\r\n */\r\n listenToProcessExits(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `noLogo` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function noLogo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `noLogo`\r\n * option.\r\n */\r\n noLogo(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `hardResetPage` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function hardResetPage\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `hardResetPage` option.\r\n */\r\n hardResetPage(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `browserShellMode` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function browserShellMode\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `browserShellMode` option.\r\n */\r\n browserShellMode(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `enableDebug` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function enableDebug\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `enableDebug`\r\n * option.\r\n */\r\n enableDebug(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `headless` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function headless\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `headless`\r\n * option.\r\n */\r\n headless(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `devtools` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function devtools\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `devtools`\r\n * option.\r\n */\r\n devtools(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `listenToConsole` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function listenToConsole\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `listenToConsole` option.\r\n */\r\n listenToConsole(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `dumpio` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `boolean` validator.\r\n *\r\n * @function dumpio\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `dumpio`\r\n * option.\r\n */\r\n dumpio(strictCheck) {\r\n return v.boolean(strictCheck);\r\n },\r\n\r\n /**\r\n * The `slowMo` validator that returns a Zod schema with an optional stricter\r\n * check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function slowMo\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `slowMo`\r\n * option.\r\n */\r\n slowMo(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `debuggingPort` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `nonNegativeNum`\r\n * validator.\r\n *\r\n * @function debuggingPort\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating\r\n * the `debuggingPort` option.\r\n */\r\n debuggingPort(strictCheck) {\r\n return v.nonNegativeNum(strictCheck);\r\n },\r\n\r\n /**\r\n * The `requestId` validator that returns a Zod schema with an optional\r\n * stricter check based on the `strictCheck` parameter.\r\n *\r\n * The validation schema ensures the same work as the `string` validator.\r\n * Additionally, it must be a stringified UUID or can be null.\r\n *\r\n * @function requestId\r\n *\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {z.ZodSchema} A Zod schema object for validating the `requestId`\r\n * option.\r\n */\r\n requestId() {\r\n return (\r\n z\r\n .string()\r\n /// TO DO: Correct\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable()\r\n );\r\n }\r\n};\r\n\r\n// Schema for the puppeteer section of options\r\nconst PuppeteerSchema = (strictCheck) =>\r\n z\r\n .object({\r\n args: config.args(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the highcharts section of options\r\nconst HighchartsSchema = (strictCheck) =>\r\n z\r\n .object({\r\n version: config.version(strictCheck),\r\n cdnUrl: config.cdnUrl(strictCheck),\r\n forceFetch: config.forceFetch(strictCheck),\r\n cachePath: config.cachePath(strictCheck),\r\n coreScripts: config.coreScripts(strictCheck),\r\n moduleScripts: config.moduleScripts(strictCheck),\r\n indicatorScripts: config.indicatorScripts(strictCheck),\r\n customScripts: config.customScripts(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the export section of options\r\nconst ExportSchema = (strictCheck) =>\r\n z\r\n .object({\r\n infile: config.infile(strictCheck),\r\n instr: config.instr(),\r\n options: config.options(),\r\n svg: config.svg(),\r\n outfile: config.outfile(strictCheck),\r\n type: config.type(strictCheck),\r\n constr: config.constr(strictCheck),\r\n b64: config.b64(strictCheck),\r\n noDownload: config.noDownload(strictCheck),\r\n defaultHeight: config.defaultHeight(strictCheck),\r\n defaultWidth: config.defaultWidth(strictCheck),\r\n defaultScale: config.defaultScale(strictCheck),\r\n height: config.height(strictCheck),\r\n width: config.width(strictCheck),\r\n scale: config.scale(strictCheck),\r\n globalOptions: config.globalOptions(),\r\n themeOptions: config.themeOptions(),\r\n batch: config.batch(false),\r\n rasterizationTimeout: config.rasterizationTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the customLogic section of options\r\nconst CustomLogicSchema = (strictCheck) =>\r\n z\r\n .object({\r\n allowCodeExecution: config.allowCodeExecution(strictCheck),\r\n allowFileResources: config.allowFileResources(strictCheck),\r\n customCode: config.customCode(false),\r\n callback: config.callback(false),\r\n resources: config.resources(strictCheck),\r\n loadConfig: config.loadConfig(false),\r\n createConfig: config.createConfig(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.proxy section of options\r\nconst ProxySchema = (strictCheck) =>\r\n z\r\n .object({\r\n host: config.proxyHost(false),\r\n port: config.proxyPort(strictCheck),\r\n timeout: config.proxyTimeout(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.rateLimiting section of options\r\nconst RateLimitingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableRateLimiting(strictCheck),\r\n maxRequests: config.maxRequests(strictCheck),\r\n window: config.window(strictCheck),\r\n delay: config.delay(strictCheck),\r\n trustProxy: config.trustProxy(strictCheck),\r\n skipKey: config.skipKey(false),\r\n skipToken: config.skipToken(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server.ssl section of options\r\nconst SslSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableSsl(strictCheck),\r\n force: config.sslForce(strictCheck),\r\n port: config.sslPort(strictCheck),\r\n certPath: config.sslCertPath(false)\r\n })\r\n .partial();\r\n\r\n// Schema for the server section of options\r\nconst ServerSchema = (strictCheck) =>\r\n z.object({\r\n enable: config.enableServer(strictCheck).optional(),\r\n host: config.host(strictCheck).optional(),\r\n port: config.port(strictCheck).optional(),\r\n benchmarking: config.serverBenchmarking(strictCheck).optional(),\r\n proxy: ProxySchema(strictCheck).optional(),\r\n rateLimiting: RateLimitingSchema(strictCheck).optional(),\r\n ssl: SslSchema(strictCheck).optional()\r\n });\r\n\r\n// Schema for the pool section of options\r\nconst PoolSchema = (strictCheck) =>\r\n z\r\n .object({\r\n minWorkers: config.minWorkers(strictCheck),\r\n maxWorkers: config.maxWorkers(strictCheck),\r\n workLimit: config.workLimit(strictCheck),\r\n acquireTimeout: config.acquireTimeout(strictCheck),\r\n createTimeout: config.createTimeout(strictCheck),\r\n destroyTimeout: config.destroyTimeout(strictCheck),\r\n idleTimeout: config.idleTimeout(strictCheck),\r\n createRetryInterval: config.createRetryInterval(strictCheck),\r\n reaperInterval: config.reaperInterval(strictCheck),\r\n benchmarking: config.poolBenchmarking(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the logging section of options\r\nconst LoggingSchema = (strictCheck) =>\r\n z\r\n .object({\r\n level: config.logLevel(strictCheck),\r\n file: config.logFile(strictCheck),\r\n dest: config.logDest(strictCheck),\r\n toConsole: config.logToConsole(strictCheck),\r\n toFile: config.logToFile(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the ui section of options\r\nconst UiSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableUi(strictCheck),\r\n route: config.uiRoute(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the other section of options\r\nconst OtherSchema = (strictCheck) =>\r\n z\r\n .object({\r\n nodeEnv: config.nodeEnv(strictCheck),\r\n listenToProcessExits: config.listenToProcessExits(strictCheck),\r\n noLogo: config.noLogo(strictCheck),\r\n hardResetPage: config.hardResetPage(strictCheck),\r\n browserShellMode: config.browserShellMode(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Schema for the debug section of options\r\nconst DebugSchema = (strictCheck) =>\r\n z\r\n .object({\r\n enable: config.enableDebug(strictCheck),\r\n headless: config.headless(strictCheck),\r\n devtools: config.devtools(strictCheck),\r\n listenToConsole: config.listenToConsole(strictCheck),\r\n dumpio: config.dumpio(strictCheck),\r\n slowMo: config.slowMo(strictCheck),\r\n debuggingPort: config.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n////\r\n// // Schema for the payload section of options\r\n// const PayloadSchema = () =>\r\n// z\r\n// .object({\r\n// requestId: config.requestId()\r\n// })\r\n// .partial();\r\n////\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(true),\r\n highcharts: HighchartsSchema(true),\r\n export: ExportSchema(true),\r\n customLogic: CustomLogicSchema(true),\r\n server: ServerSchema(true),\r\n pool: PoolSchema(true),\r\n logging: LoggingSchema(true),\r\n ui: UiSchema(true),\r\n other: OtherSchema(true),\r\n debug: DebugSchema(true)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n puppeteer: PuppeteerSchema(false),\r\n highcharts: HighchartsSchema(false),\r\n export: ExportSchema(false),\r\n customLogic: CustomLogicSchema(false),\r\n server: ServerSchema(false),\r\n pool: PoolSchema(false),\r\n logging: LoggingSchema(false),\r\n ui: UiSchema(false),\r\n other: OtherSchema(false),\r\n debug: DebugSchema(false)\r\n //// payload: PayloadSchema()\r\n});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: config.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: config.version(false),\r\n HIGHCHARTS_CDN_URL: config.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: config.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: config.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: config.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: config.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: config.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: config.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: config.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: config.infile(false),\r\n EXPORT_INSTR: config.instr(),\r\n EXPORT_OPTIONS: config.options(),\r\n EXPORT_SVG: config.svg(),\r\n EXPORT_BATCH: config.batch(false),\r\n EXPORT_OUTFILE: config.outfile(false),\r\n EXPORT_TYPE: config.type(false),\r\n EXPORT_CONSTR: config.constr(false),\r\n EXPORT_B64: config.b64(false),\r\n EXPORT_NO_DOWNLOAD: config.noDownload(false),\r\n EXPORT_HEIGHT: config.height(false),\r\n EXPORT_WIDTH: config.width(false),\r\n EXPORT_SCALE: config.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: config.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: config.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: config.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: config.globalOptions(),\r\n EXPORT_THEME_OPTIONS: config.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: config.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: config.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: config.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: config.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: config.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: config.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: config.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: config.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: config.enableServer(false),\r\n SERVER_HOST: config.host(false),\r\n SERVER_PORT: config.port(false),\r\n SERVER_UPLOAD_LIMIT: config.uploadLimit(false),\r\n SERVER_BENCHMARKING: config.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: config.proxyHost(false),\r\n SERVER_PROXY_PORT: config.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: config.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: config.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: config.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: config.window(false),\r\n SERVER_RATE_LIMITING_DELAY: config.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: config.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: config.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: config.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: config.enableSsl(false),\r\n SERVER_SSL_FORCE: config.sslForce(false),\r\n SERVER_SSL_PORT: config.sslPort(false),\r\n SERVER_SSL_CERT_PATH: config.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: config.minWorkers(false),\r\n POOL_MAX_WORKERS: config.maxWorkers(false),\r\n POOL_WORK_LIMIT: config.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: config.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: config.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: config.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: config.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: config.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: config.reaperInterval(false),\r\n POOL_BENCHMARKING: config.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: config.logLevel(false),\r\n LOGGING_FILE: config.logFile(false),\r\n LOGGING_DEST: config.logDest(false),\r\n LOGGING_TO_CONSOLE: config.logToConsole(false),\r\n LOGGING_TO_FILE: config.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: config.enableUi(false),\r\n UI_ROUTE: config.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: config.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: config.listenToProcessExits(false),\r\n OTHER_NO_LOGO: config.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: config.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: config.browserShellMode(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: config.enableDebug(false),\r\n DEBUG_HEADLESS: config.headless(false),\r\n DEBUG_DEVTOOLS: config.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: config.listenToConsole(false),\r\n DEBUG_DUMPIO: config.dumpio(false),\r\n DEBUG_SLOW_MO: config.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: config.debuggingPort(false)\r\n});\r\n\r\n/**\r\n * Validates the environment variables options using the EnvSchema.\r\n *\r\n * @param {Object} process.env - The configuration options from environment\r\n * variables file to validate.\r\n *\r\n * @returns {Object} The parsed and validated environment variables.\r\n */\r\nexport const envs = EnvSchema.partial().parse(process.env);\r\n\r\n/**\r\n * Validates the configuration options using the `StrictConfigSchema`.\r\n *\r\n * @function strictValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function strictValidate(configOptions) {\r\n return StrictConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates the configuration options using the `LooseConfigSchema`.\r\n *\r\n * @function looseValidate\r\n *\r\n * @param {Object} configOptions - The configuration options to validate.\r\n *\r\n * @returns {Object} The parsed and validated configuration options.\r\n */\r\nexport function looseValidate(configOptions) {\r\n return LooseConfigSchema.partial().parse(configOptions);\r\n}\r\n\r\n/**\r\n * Validates a provided option using the specific validator from the config\r\n * object.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of an option to validate.\r\n * @param {any} option - The option to validate.\r\n * @param {boolean} strictCheck - Determines if stricter validation should\r\n * be applied.\r\n *\r\n * @returns {any} The parsed and validated option value.\r\n */\r\nexport function validateOption(name, option, strictCheck) {\r\n return config[name](strictCheck).parse(option);\r\n}\r\n\r\n/**\r\n * Custom error mapping function for Zod schema validation.\r\n *\r\n * This function customizes the error messages produced by Zod schema\r\n * validation, providing more specific and user-friendly feedback based on the\r\n * issue type and context.\r\n *\r\n * The function modifies the error messages as follows:\r\n *\r\n * - For missing required values (undefined), it returns a message indicating\r\n * that no value was provided for the specific property.\r\n *\r\n * - For custom validation errors, if a custom error message is provided in the\r\n * issue parameters, it includes this message along with the invalid data\r\n * received.\r\n *\r\n * - For all other errors, it appends property-specific information to the\r\n * default error message provided by Zod.\r\n *\r\n * @function _customErrorMap\r\n *\r\n * @param {z.ZodIssue} issue - The issue object representing the validation\r\n * error.\r\n * @param {Object} context - The context object providing additional information\r\n * about the validation error.\r\n *\r\n * @returns {Object} An object containing the customized error message.\r\n */\r\nfunction _customErrorMap(issue, context) {\r\n // Get the chain of properties which error directly refers to\r\n const propertyName = issue.path.join('.');\r\n\r\n // Create the first part of the message about the property information\r\n const propertyInfo = `Invalid value for the ${propertyName}`;\r\n\r\n // Modified message for the invalid type\r\n if (issue.code === z.ZodIssueCode.invalid_type) {\r\n // Modified message for the required values\r\n if (issue.received === z.ZodParsedType.undefined) {\r\n return {\r\n message: `${propertyInfo} - No value was provided.`\r\n };\r\n }\r\n\r\n // Modified message for the specific invalid type when values exist\r\n return {\r\n message: `${propertyInfo} - Invalid type. ${context.defaultError}.`\r\n };\r\n }\r\n\r\n // Modified message for the custom validation\r\n if (issue.code === z.ZodIssueCode.custom) {\r\n // If the custom message for error exist, include it\r\n if (issue.params?.errorMessage) {\r\n return {\r\n message: `${propertyInfo} - ${issue.params?.errorMessage}, received '${context.data}'.`\r\n };\r\n }\r\n }\r\n\r\n // Modified message for the invalid union error\r\n if (issue.code === z.ZodIssueCode.invalid_union) {\r\n // Create the first part of the message about the multiple errors\r\n let message = `Multiple errors occurred for the ${propertyName}:\\n`;\r\n\r\n // Cycle through all errors and create a correct message\r\n issue.unionErrors.forEach((value) => {\r\n const index = value.issues[0].message.indexOf('-');\r\n message +=\r\n index !== -1\r\n ? `${value.issues[0].message}\\n`.substring(index)\r\n : `${value.issues[0].message}\\n`;\r\n });\r\n\r\n // Return the final message for the invalid union error\r\n return {\r\n message\r\n };\r\n }\r\n\r\n // Return the default error message, extended by the info about the property\r\n return {\r\n message: `${propertyInfo} - ${context.defaultError}.`\r\n };\r\n}\r\n\r\nexport default {\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate,\r\n validateOption\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Manages configuration for the Highcharts Export Server by loading\r\n * and merging options from multiple sources, such as default settings,\r\n * environment variables, user-provided options, and command-line arguments.\r\n * Ensures the global options are up-to-date with the highest priority values.\r\n * Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { __dirname, isObject, deepCopy, getAbsolutePath } from './utils.js';\r\nimport { envs, looseValidate, strictValidate } from './validation.js';\r\nimport { defaultConfig, nestedProps, absoluteProps } from './schemas/config.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initGlobalOptions(defaultConfig);\r\n\r\n/**\r\n * Gets the reference to the global options of the server instance object\r\n * or its copy.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getReference=true] - Optional parameter to decide whether\r\n * to return the reference to the global options of the server instance object\r\n * or return a copy of it. The default value is true.\r\n *\r\n * @returns {Object} The reference to the global options of the server instance\r\n * object or its copy.\r\n */\r\nexport function getOptions(getReference = true) {\r\n return getReference ? globalOptions : deepCopy(globalOptions);\r\n}\r\n\r\n/**\r\n * Sets the global options of the export server instance, keeping the principle\r\n * of the options load priority from all available sources. It accepts optional\r\n * `customOptions` object and `cliArgs` array with arguments from the CLI. These\r\n * options will be validated and applied if provided.\r\n *\r\n * The priority order of setting values is:\r\n *\r\n * 1. Options from the `lib/schemas/config.js` file (default values).\r\n * 2. Options from a custom JSON file (loaded by the `loadConfig` option).\r\n * 3. Options from the environment variables (the `.env` file).\r\n * 4. Options from the first parameter (by default an empty object).\r\n * 5. Options from the CLI.\r\n *\r\n * @function setOptions\r\n *\r\n * @param {Object} [customOptions={}] - Optional custom options for additional\r\n * configuration. The default value is an empty object.\r\n * @param {Array.} [cliArgs=[]] - Optional command line arguments\r\n * for additional configuration. The default value is an empty array.\r\n * @param {boolean} [modifyGlobal=false] - Optional parameter to decide\r\n * whether to update and return the reference to the global options\r\n * of the server instance object or return a copy of it. The default value\r\n * is false.\r\n *\r\n * @returns {Object} The updated general options object, reflecting the merged\r\n * configuration from all available sources.\r\n */\r\nexport function setOptions(\r\n customOptions = {},\r\n cliArgs = [],\r\n modifyGlobal = false\r\n) {\r\n // Object for options loaded via the `loadConfig` option\r\n let configOptions = {};\r\n\r\n // Object for options from the CLI\r\n let cliOptions = {};\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the custom JSON loaded via the `loadConfig`\r\n configOptions = strictValidate(_loadConfigFile(cliArgs));\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Custom JSON options validation error'\r\n );\r\n }\r\n }\r\n\r\n // Apply custom options if there are any\r\n if (customOptions && Object.keys(customOptions).length !== 0) {\r\n try {\r\n // Validate custom options provided by the user\r\n customOptions = strictValidate(customOptions);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Custom options validation error');\r\n }\r\n }\r\n\r\n // Only for the CLI usage\r\n if (cliArgs.length) {\r\n try {\r\n // Validate options from the CLI\r\n cliOptions = looseValidate(_pairArgumentValue(nestedProps, cliArgs));\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] CLI options validation error');\r\n }\r\n }\r\n\r\n // Get the reference to the global options object or a copy of the object\r\n const generalOptions = getOptions(modifyGlobal);\r\n\r\n // Update values of the general options with values from each source possible\r\n _updateOptions(\r\n defaultConfig,\r\n generalOptions,\r\n configOptions,\r\n customOptions,\r\n cliOptions\r\n );\r\n\r\n // Return options\r\n return generalOptions;\r\n}\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @function mergeOptions\r\n *\r\n * @param {Object} originalOptions - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport function mergeOptions(originalOptions, newOptions) {\r\n // Check if the `newOptions` is a correct object\r\n if (isObject(newOptions)) {\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n originalOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n originalOptions[key] !== undefined\r\n ? mergeOptions(originalOptions[key], value)\r\n : value !== undefined\r\n ? value\r\n : originalOptions[key];\r\n }\r\n }\r\n\r\n // Return the result options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS) to a new format\r\n * (Puppeteer). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping\r\n * (`nestedProps`). The new format is used for Puppeteer, while the old format\r\n * was used for PhantomJS.\r\n *\r\n * @function mapToNewOptions\r\n *\r\n * @param {Object} oldOptions - The old, flat configuration options\r\n * to be converted.\r\n *\r\n * @returns {Object} A new object containing options structured according\r\n * to the mapping defined in `nestedProps` or an empty object if the provided\r\n * `oldOptions` is not a correct object.\r\n */\r\nexport function mapToNewOptions(oldOptions) {\r\n // An object for the new structured options\r\n const newOptions = {};\r\n\r\n // Check if provided value is a correct object\r\n if (Object.prototype.toString.call(oldOptions) === '[object Object]') {\r\n // Iterate over each key-value pair in the old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n // If there is a nested mapping, split it into a properties chain\r\n const propertiesChain = nestedProps[key]\r\n ? nestedProps[key].split('.')\r\n : [];\r\n\r\n // If it is the last property in the chain, assign the value, otherwise,\r\n // create or reuse the nested object\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n }\r\n\r\n // Return the new, structured options object\r\n return newOptions;\r\n}\r\n\r\n/**\r\n * Validates, parses, and checks if the provided config is allowed set\r\n * of options.\r\n *\r\n * @function isAllowedConfig\r\n *\r\n * @param {unknown} config - The config to be validated and parsed as a set\r\n * of options. Must be either an object or a string.\r\n * @param {boolean} [toString=false] - Whether to return a stringified version\r\n * of the parsed config. The default value is false.\r\n * @param {boolean} [allowFunctions=false] - Whether to allow functions\r\n * in the parsed config. If true, functions are preserved. Otherwise, when\r\n * a function is found, null is returned. The default value is false.\r\n *\r\n * @returns {(Object|string|null)} Returns a parsed set of options object,\r\n * a stringified set of options object if the `toString` is true, and null\r\n * if the config is not a valid set of options or parsing fails.\r\n */\r\nexport function isAllowedConfig(\r\n config,\r\n toString = false,\r\n allowFunctions = false\r\n) {\r\n try {\r\n // Accept only objects and strings\r\n if (!isObject(config) && typeof config !== 'string') {\r\n // Return null if any other type\r\n return null;\r\n }\r\n\r\n // Get the object representation of the original config\r\n const objectConfig =\r\n typeof config === 'string'\r\n ? allowFunctions\r\n ? eval(`(${config})`)\r\n : JSON.parse(config)\r\n : config;\r\n\r\n // Preserve or remove potential functions based on the `allowFunctions` flag\r\n const stringifiedOptions = _optionsStringify(\r\n objectConfig,\r\n allowFunctions,\r\n false\r\n );\r\n\r\n // Parse the config to check if it is valid set of options\r\n const parsedOptions = allowFunctions\r\n ? JSON.parse(\r\n _optionsStringify(objectConfig, allowFunctions, true),\r\n (_, value) =>\r\n typeof value === 'string' && value.startsWith('function')\r\n ? eval(`(${value})`)\r\n : value\r\n )\r\n : JSON.parse(stringifiedOptions);\r\n\r\n // Return stringified or object options based on the `toString` flag\r\n return toString ? stringifiedOptions : parsedOptions;\r\n } catch (error) {\r\n // Return null if parsing fails\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo, version, and license information.\r\n *\r\n * @function printLicense\r\n */\r\nexport function printLicense() {\r\n // Print the logo and version information\r\n printVersion();\r\n\r\n // Print the license information\r\n console.log(\r\n 'This software requires a valid Highcharts license for commercial use.\\n'\r\n .yellow,\r\n '\\nFor a full list of CLI options, type:',\r\n '\\nhighcharts-export-server --help\\n'.green,\r\n '\\nIf you do not have a license, one can be obtained here:',\r\n '\\nhttps://shop.highsoft.com/\\n'.green,\r\n '\\nTo customize your installation, please refer to the README file at:',\r\n '\\nhttps://github.com/highcharts/node-export-server#readme\\n'.green\r\n );\r\n}\r\n\r\n/**\r\n * Prints usage information for CLI arguments, displaying available options\r\n * and their descriptions. It can list properties recursively if categories\r\n * contain nested options.\r\n *\r\n * @function printUsage\r\n */\r\nexport function printUsage() {\r\n // Display README and general usage information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n-----------------------',\r\n `\\nFor more detailed information, visit the README file at: ${'https://github.com/highcharts/node-export-server#readme'.green}.\\n`\r\n );\r\n\r\n // Iterate through each category in the `defaultConfig` and display usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n console.log(`${category.toUpperCase()}`.bold.red);\r\n _cycleCategories(defaultConfig[category]);\r\n console.log('');\r\n });\r\n}\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo or text with the version\r\n * information.\r\n *\r\n * @function printVersion\r\n *\r\n * @param {boolean} [noLogo=false] - If true, only prints text with the version\r\n * information, without the logo. The default value is false.\r\n */\r\nexport function printVersion(noLogo = false) {\r\n // Get package version either from `.env` or from `package.json`\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Highcharts Export Server v${packageVersion}`);\r\n } else {\r\n // Print the logo\r\n console.log(\r\n readFileSync(join(__dirname, 'msg', 'startup.msg')).toString().bold\r\n .yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Initializes and returns global options object based on provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * @function _initGlobalOptions\r\n *\r\n * @param {Object} config - The configuration object to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction _initGlobalOptions(config) {\r\n const options = {};\r\n\r\n // Start initializing the `options` object recursively\r\n for (const [name, item] of Object.entries(config)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : _initGlobalOptions(item);\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Updates options object with values from various sources, following a specific\r\n * prioritization order. The function checks for values in the following order\r\n * of precedence: the `loadConfig` configuration options, environment variables,\r\n * custom options, and CLI options.\r\n *\r\n * @function _updateOptions\r\n *\r\n * @param {Object} config - The configuration object, which includes the initial\r\n * settings and metadata for each option. This object is used to determine\r\n * the structure and default values for the options.\r\n * @param {Object} options - The options object that will be updated with values\r\n * from other sources.\r\n * @param {Object} configOpt - The configuration options object, loaded with\r\n * the `loadConfig` option, which may provide values to override defaults.\r\n * @param {Object} customOpt - The custom options object, typically containing\r\n * additional and user-defined values, which may override configuration options.\r\n * @param {Object} cliOpt - The CLI options object, which may include values\r\n * provided through command-line arguments and has the highest precedence among\r\n * options.\r\n */\r\nfunction _updateOptions(config, options, configOpt, customOpt, cliOpt) {\r\n Object.keys(config).forEach((key) => {\r\n // Get the config entry of a specific option\r\n const entry = config[key];\r\n\r\n // Gather values for the options from every possible source, if exists\r\n const configVal = configOpt && configOpt[key];\r\n const customVal = customOpt && customOpt[key];\r\n const cliVal = cliOpt && cliOpt[key];\r\n\r\n // If the value not found, need to go deeper\r\n if (typeof entry.value === 'undefined') {\r\n _updateOptions(entry, options[key], configVal, customVal, cliVal);\r\n } else {\r\n // If a value from custom JSON options exists, it take precedence\r\n if (configVal !== undefined && configVal !== null) {\r\n options[key] = configVal;\r\n }\r\n\r\n // If a value from environment variables exists, it take precedence\r\n const envVal = envs[entry.envLink];\r\n if (entry.envLink in envs && envVal !== undefined && envVal !== null) {\r\n options[key] = envVal;\r\n }\r\n\r\n // If a value from user options exists, it take precedence\r\n if (customVal !== undefined && customVal !== null) {\r\n options[key] = customVal;\r\n }\r\n\r\n // If a value from CLI options exists, it take precedence\r\n if (cliVal !== undefined && cliVal !== null) {\r\n options[key] = cliVal;\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string\r\n * with the option to preserve functions. In order for a function\r\n * to be preserved, it needs to follow the format `function (...) {...}`.\r\n * Such a function can also be stringified.\r\n *\r\n * @function _optionsStringify\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output. Otherwise an error is thrown.\r\n * @param {boolean} stringifyFunctions - If set to true, functions are saved\r\n * as strings. The `allowFunctions` must be set to true as well for this to take\r\n * an effect.\r\n *\r\n * @returns {string} The JSON-formatted string representing the options.\r\n *\r\n * @throws {Error} Throws an `Error` when functions are not allowed but are\r\n * found in provided options object.\r\n */\r\nexport function _optionsStringify(options, allowFunctions, stringifyFunctions) {\r\n const replacerCallback = (_, value) => {\r\n // Trim string values\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n }\r\n\r\n // If value is a function or stringified function\r\n if (\r\n typeof value === 'function' ||\r\n (typeof value === 'string' &&\r\n value.startsWith('function') &&\r\n value.endsWith('}'))\r\n ) {\r\n // If allowFunctions is set to true, preserve functions\r\n if (allowFunctions) {\r\n // Based on the `stringifyFunctions` options, set function values\r\n return stringifyFunctions\r\n ? // As stringified functions\r\n `\"EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN\"`\r\n : // As functions\r\n `EXP_FUN${(value + '').replaceAll(/\\s+/g, ' ')}EXP_FUN`;\r\n } else {\r\n // Throw an error otherwise\r\n throw new Error();\r\n }\r\n }\r\n\r\n // In all other cases, simply return the value\r\n return value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n stringifyFunctions ? /\\\\\"EXP_FUN|EXP_FUN\\\\\"/g : /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Loads additional configuration from a specified file provided via\r\n * the `loadConfig` option in the command-line arguments.\r\n *\r\n * @function _loadConfigFile\r\n *\r\n * @param {Array.} cliArgs - Command-line arguments to search\r\n * for the `loadConfig` option and the corresponding file path.\r\n *\r\n * @returns {Object} The additional configuration loaded from the specified\r\n * file, or an empty object if the file is not found, invalid, or an error\r\n * occurs.\r\n */\r\nfunction _loadConfigFile(cliArgs) {\r\n // Check if the `loadConfig` option was used\r\n const configIndex = cliArgs.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Get the `loadConfig` option value\r\n const configFileName = configIndex > -1 && cliArgs[configIndex + 1];\r\n\r\n // Check if the `loadConfig` is present and has a correct value\r\n if (configFileName) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(getAbsolutePath(configFileName)));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${configFileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Parses command-line arguments and pairs each argument with its corresponding\r\n * option in the configuration. The values are structured into a nested options\r\n * object, based on predefined mappings.\r\n *\r\n * @function _pairArgumentValue\r\n *\r\n * @param {Array.} nestedProps - An array of nesting level for all\r\n * options.\r\n * @param {Array.} cliArgs - An array of command-line arguments\r\n * containing options and their associated values.\r\n *\r\n * @returns {Object} An updated options object where each option from\r\n * the command-line is paired with its value, structured into nested objects\r\n * as defined.\r\n */\r\nfunction _pairArgumentValue(nestedProps, cliArgs) {\r\n // An empty object to collect and structurize data from the args\r\n const cliOptions = {};\r\n\r\n // Cycle through all CLI args and filter them\r\n for (let i = 0; i < cliArgs.length; i++) {\r\n const option = cliArgs[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedProps[option]\r\n ? nestedProps[option].split('.')\r\n : [];\r\n\r\n // Create options object with values from CLI for later parsing and merging\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n const value = cliArgs[++i];\r\n if (!value) {\r\n log(\r\n 2,\r\n `[config] Missing value for the CLI '--${option}' argument. Using the default value.`\r\n );\r\n }\r\n obj[prop] = value || null;\r\n } else if (obj[prop] === undefined) {\r\n obj[prop] = {};\r\n }\r\n return obj[prop];\r\n }, cliOptions);\r\n }\r\n\r\n // Return parsed CLI options\r\n return cliOptions;\r\n}\r\n\r\n/**\r\n * Recursively traverses the options object to print the usage information\r\n * for each option category and individual option.\r\n *\r\n * @function _cycleCategories\r\n *\r\n * @param {Object} options - The options object containing CLI options.\r\n * It may include nested categories and individual options.\r\n */\r\nfunction _cycleCategories(options) {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If the current entry is a category and not a leaf option, recurse into it\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n _cycleCategories(option);\r\n } else {\r\n // Prepare description\r\n const descName = ` --${option.cliName || name}`;\r\n\r\n // Get the value\r\n let optionValue = option.value;\r\n\r\n // Prepare value for option that is not null and is array of strings\r\n if (optionValue !== null && option.types.includes('string[]')) {\r\n optionValue =\r\n '[' + optionValue.map((item) => `'${item}'`).join(', ') + ']';\r\n }\r\n\r\n // Prepare value for option that is not null and is a string\r\n if (optionValue !== null && option.types.includes('string')) {\r\n optionValue = `'${optionValue}'`;\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName.green,\r\n `${('<' + option.types.join('|') + '>').yellow}`,\r\n `${String(optionValue).bold}`.blue,\r\n `- ${option.description}.`\r\n );\r\n }\r\n }\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n isAllowedConfig,\r\n printLicense,\r\n printUsage,\r\n printVersion\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview HTTP utility module for fetching and posting data. Supports both\r\n * HTTP and HTTPS protocols, providing methods to make GET and POST requests\r\n * with customizable options. Includes protocol determination based on URL\r\n * and augments response objects with a 'text' property for easier data access.\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function fetch\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n _getProtocolModule(url)\r\n .get(url, requestOptions, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n if (!responseData) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n response.text = responseData;\r\n resolve(response);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function post\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} [body={}] - The JSON body to include in the POST request.\r\n * The default value is an empty object.\r\n * @param {Object} [requestOptions={}] - Options for the HTTP/HTTPS request.\r\n * The default value is an empty object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the HTTP/HTTPS response\r\n * object with added 'text' property or rejecting with an error.\r\n */\r\nexport async function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const request = _getProtocolModule(url)\r\n .request(url, options, (response) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received\r\n response.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received\r\n response.on('end', () => {\r\n try {\r\n response.text = responseData;\r\n resolve(response);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request\r\n request.write(data);\r\n request.end();\r\n });\r\n}\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @function _getProtocolModule\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nfunction _getProtocolModule(url) {\r\n return url.startsWith('https') ? https : http;\r\n}\r\n\r\nexport default {\r\n fetch,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * A custom error class for handling export-related errors. Extends the native\r\n * `Error` class to include additional properties like status code and stack\r\n * trace details.\r\n */\r\nclass ExportError extends Error {\r\n /**\r\n * Creates an instance of the `ExportError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super();\r\n\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n if (statusCode) {\r\n this.statusCode = statusCode;\r\n }\r\n }\r\n\r\n /**\r\n * Sets additional error details based on an existing error object.\r\n *\r\n * @param {Error} error - An error object containing details to populate\r\n * the `ExportError` instance.\r\n *\r\n * @returns {ExportError} The updated instance of the `ExportError` class.\r\n */\r\n setError(error) {\r\n this.error = error;\r\n\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview The cache manager is responsible for handling and managing\r\n * the Highcharts library along with its dependencies. It ensures that these\r\n * resources are stored and retrieved efficiently to optimize performance\r\n * and reduce redundant network requests. The cache is stored in the `.cache`\r\n * directory by default, which serves as a dedicated folder for keeping cached\r\n * files.\r\n */\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The initial cache template\r\nconst cache = {\r\n cdnUrl: 'https://code.highcharts.com',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @async\r\n * @function checkAndUpdateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n */\r\nexport async function checkAndUpdateCache(\r\n highchartsOptions,\r\n serverProxyOptions\r\n) {\r\n let fetchedModules;\r\n\r\n // Get the cache path\r\n const cachePath = getCachePath();\r\n\r\n // Prepare paths to manifest and sources from the cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true });\r\n\r\n // Fetch all the scripts either if the `manifest.json` does not exist\r\n // or if the `forceFetch` option is enabled\r\n if (!existsSync(manifestPath) || highchartsOptions.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n // Get the actual number of scripts to be fetched\r\n const { coreScripts, moduleScripts, indicatorScripts } = highchartsOptions;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highchartsOptions.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n // Update cache if needed\r\n if (requestUpdate) {\r\n fetchedModules = await _updateCache(\r\n highchartsOptions,\r\n serverProxyOptions,\r\n sourcePath\r\n );\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await _saveConfigToManifest(highchartsOptions, fetchedModules);\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHighchartsVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHighchartsVersion() {\r\n return cache.hcVersion;\r\n}\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @async\r\n * @function updateHighchartsVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHighchartsVersion(newVersion) {\r\n // Get the reference to the global options to update to the new version\r\n const options = getOptions();\r\n\r\n // Set to the new version\r\n options.highcharts.version = newVersion;\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function extractVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport function extractVersion(cacheSources) {\r\n return cacheSources\r\n .substring(0, cacheSources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n}\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n *\r\n * @function extractModuleName\r\n *\r\n * @param {string} scriptPath - The path of the script from which the module\r\n * name will be extracted.\r\n *\r\n * @returns {string} The extracted module name.\r\n */\r\nexport function extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\n/**\r\n * Retrieves the current cache object.\r\n *\r\n * @function getCache\r\n *\r\n * @returns {Object} The cache object containing various cached data.\r\n */\r\nexport function getCache() {\r\n return cache;\r\n}\r\n\r\n/**\r\n * Gets the cache path for Highcharts.\r\n *\r\n * @function getCachePath\r\n *\r\n * @returns {string} The absolute path to the cache directory for Highcharts.\r\n */\r\nexport function getCachePath() {\r\n return getAbsolutePath(getOptions().highcharts.cachePath); // #562\r\n}\r\n\r\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchAndProcessScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} [shouldThrowError=false] - A flag to indicate if the error\r\n * should be thrown. This should be used only for the core scripts. The default\r\n * value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem\r\n * with fetching the script.\r\n */\r\nasync function _fetchAndProcessScript(\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n return response.text;\r\n }\r\n\r\n // Based on the `shouldThrowError` flag, decide how to serve error message\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`,\r\n 404\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @async\r\n * @function _saveConfigToManifest\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which Highcharts\r\n * modules have been fetched. The default value is an empty object.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * writing the cache manifest.\r\n */\r\nasync function _saveConfigToManifest(highchartsOptions, fetchedModules = {}) {\r\n const newManifest = {\r\n version: highchartsOptions.version,\r\n modules: fetchedModules\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(getCachePath(), 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Error writing the cache manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Fetches Highcharts `scripts` and `customScripts` from the given CDNs.\r\n *\r\n * @async\r\n * @function _fetchScripts\r\n *\r\n * @param {Array.} coreScripts - Highcharts core scripts to fetch.\r\n * @param {Array.} moduleScripts - Highcharts modules to fetch.\r\n * @param {Array.} customScripts - Custom script paths to fetch (full\r\n * URLs).\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} A Promise that resolves to the fetched scripts\r\n * content joined.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs while\r\n * setting an HTTP Agent for proxy.\r\n */\r\nasync function _fetchScripts(\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n) {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = serverProxyOptions.host;\r\n const proxyPort = serverProxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not create a Proxy Agent.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n _fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n}\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - Object containing `highcharts` options.\r\n * @param {Object} serverProxyOptions - Object containing `server.proxy`\r\n * options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nasync function _updateCache(highchartsOptions, serverProxyOptions, sourcePath) {\r\n // Get Highcharts version for scripts\r\n const hcVersion =\r\n highchartsOptions.version === 'latest'\r\n ? null\r\n : `${highchartsOptions.version}`;\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n try {\r\n const fetchedModules = {};\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n cache.sources = await _fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) =>\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${c}` : `${cdnUrl}/${c}`\r\n )\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/maps/modules/${m}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${m}`\r\n : `${cdnUrl}/modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map((i) =>\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${i}`\r\n : `${cdnUrl}/stock/indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n serverProxyOptions,\r\n fetchedModules\r\n );\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = extractVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getHighchartsVersion,\r\n updateHighchartsVersion,\r\n extractVersion,\r\n extractModuleName,\r\n getCache,\r\n getCachePath\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides methods for initializing Highcharts with customized\r\n * animation settings and triggering the creation of Highcharts charts with\r\n * export-specific configurations in the page context. Supports dynamic option\r\n * merging, custom logic injection, and control over rendering behaviors. Used\r\n * by the Puppeteer page.\r\n */\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the `Highcharts.animObject` function. Called when initing the page.\r\n *\r\n * @function setupHighcharts\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual Highcharts chart on a page.\r\n *\r\n * @async\r\n * @function createChart\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n */\r\nexport async function createChart(options) {\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential `setOptions` usages in order\r\n // to prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Some mandatory additional `chart` and `exporting` options\r\n const additionalOptions = {\r\n chart: {\r\n // By default animation is disabled\r\n animation: false,\r\n // Get the right size values\r\n height: options.export.height,\r\n width: options.export.width\r\n },\r\n exporting: {\r\n // No need for the exporting button\r\n enabled: false\r\n }\r\n };\r\n\r\n // Get the input to export from the `instr` option\r\n const userOptions = new Function(`return ${options.export.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${options.export.themeOptions}`)();\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(\r\n `return ${options.export.globalOptions}`\r\n )();\r\n\r\n // Merge the following options objects to create final options\r\n const finalOptions = merge(\r\n false,\r\n themeOptions,\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n additionalOptions\r\n );\r\n\r\n // Prepare the `callback` option\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (options.customLogic.customCode) {\r\n new Function('options', options.customLogic.customCode)(userOptions);\r\n }\r\n\r\n // Set the global options if exist\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n // Call the chart creation\r\n Highcharts[options.export.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the `setOptions` was used in the `customCode`)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n\r\nexport default {\r\n setupHighcharts,\r\n createChart\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions for managing Puppeteer browser\r\n * instance, creating and clearing pages, injecting custom resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that resources are correctly managed and can handle failures during\r\n * operations like launching the browser or creating new pages.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname, getAbsolutePath } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for pages\r\nconst template = readFileSync(\r\n join(__dirname, 'templates', 'template.html'),\r\n 'utf8'\r\n);\r\n\r\n// To save the browser\r\nlet browser = null;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @function getBrowser\r\n *\r\n * @returns {Object} The Puppeteer browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been created.\r\n */\r\nexport function getBrowser() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.', 500);\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @async\r\n * @function createBrowser\r\n *\r\n * @param {Array.} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\r\n *\r\n * @returns {Promise} A Promise that resolves to the created Puppeteer\r\n * browser instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if max retries to open\r\n * a browser instance are reached, or if no browser instance is found after\r\n * retries.\r\n */\r\nexport async function createBrowser(puppeteerArgs) {\r\n // Get `debug` and `other` options\r\n const { debug, other } = getOptions();\r\n\r\n // Get the `debug` options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n // Launch options for the browser instance\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: 'tmp',\r\n args: puppeteerArgs || [],\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n // A counter for the browser's launch retries\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n\r\n // Launch the browser\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n\r\n // Wait for a 4 seconds before trying again\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\r\n }\r\n }\r\n\r\n // Return a browser instance\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @async\r\n * @function closeBrowser\r\n */\r\nexport async function closeBrowser() {\r\n // Close the browser when connected\r\n if (browser && browser.connected) {\r\n await browser.close();\r\n }\r\n browser = null;\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer page within an existing browser instance.\r\n * The function creates a new page, disables caching, sets content using\r\n * the `_setPageContent()`, and returns the created Puppeteer page.\r\n *\r\n * @async\r\n * @function newPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains `id`,\r\n * `workCount`, and `page`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if no valid browser\r\n * has been connected or if a page is invalid or closed.\r\n */\r\nexport async function newPage(poolResource) {\r\n // Error in case of no connected browser\r\n if (!browser || !browser.connected) {\r\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\r\n }\r\n\r\n // Create a page\r\n poolResource.page = await browser.newPage();\r\n\r\n // Disable cache\r\n await poolResource.page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await _setPageContent(poolResource.page);\r\n\r\n // Set page events\r\n _setPageEvents(poolResource.page);\r\n\r\n // Check if the page is correctly created\r\n if (!poolResource.page || poolResource.page.isClosed()) {\r\n throw new ExportError('[browser] The page is invalid or closed.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode. Logs\r\n * thrown error if clearing of a page's content fails.\r\n *\r\n * @async\r\n * @function clearPage\r\n *\r\n * @param {Object} poolResource - The pool resource that contains page and id.\r\n * @param {boolean} [hardReset=false] - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to `about:blank` and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure. The default value is false.\r\n *\r\n * @returns {Promise} A Promise that resolves to true when page\r\n * is correctly cleared and false when it is not.\r\n */\r\nexport async function clearPage(poolResource, hardReset = false) {\r\n try {\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to `about:blank`\r\n await poolResource.page.goto('about:blank', {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n\r\n // Set the content and and scripts again\r\n await _setPageContent(poolResource.page);\r\n } else {\r\n // Clear body content\r\n await poolResource.page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\r\n );\r\n\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n poolResource.workCount = getOptions().pool.workLimit + 1;\r\n }\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @async\r\n * @function addPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object to which resources will\r\n * be added.\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n *\r\n * @returns {Promise>} A Promise that resolves to an array\r\n * of injected resources.\r\n */\r\nexport async function addPageResources(page, customLogicOptions) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = customLogicOptions.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(getAbsolutePath(file), 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (customLogicOptions.allowFileResources) {\r\n injectedCss.push({\r\n path: join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[browser] The CSS resource cannot be loaded.`\r\n );\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with `addScriptTag` and `addStyleTag`.\r\n * Removes injected resources and resets CSS and script tags on the page.\r\n * Additionally, it destroys previously existing charts.\r\n *\r\n * @async\r\n * @function clearPageResources\r\n *\r\n * @param {Object} page - The Puppeteer page object from which resources will\r\n * be cleared.\r\n * @param {Array.} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, when doing SVG exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts.\r\n *\r\n * @async\r\n * @function _setPageContent\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the content\r\n * is being set.\r\n */\r\nasync function _setPageContent(page) {\r\n // Set the initial page content\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: join(getCachePath(), 'sources.js') });\r\n\r\n // Set the initial `animObject` for Highcharts\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events (like `pageerror` and `console`) for a Puppeteer Page in order\r\n * to catch and display errors and console logs from the window context.\r\n *\r\n * @function _setPageEvents\r\n *\r\n * @param {Object} page - The Puppeteer page object to which the listeners\r\n * are being set.\r\n */\r\nfunction _setPageEvents(page) {\r\n // Get `debug` options\r\n const { debug } = getOptions();\r\n\r\n // Set the `pageerror` listener\r\n page.on('pageerror', async () => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n });\r\n\r\n // Set the `console` listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n}\r\n\r\nexport default {\r\n getBrowser,\r\n createBrowser,\r\n closeBrowser,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * The CSS to be used on the exported page.\r\n *\r\n * @returns {string} The CSS configuration.\r\n */\r\nexport default () => `\r\n\r\nhtml, body {\r\n margin: 0;\r\n padding: 0;\r\n box-sizing: border-box;\r\n}\r\n\r\n#table-div, #sliders, #datatable, #controls, .ld-row {\r\n display: none;\r\n height: 0;\r\n}\r\n\r\n#chart-container {\r\n box-sizing: border-box;\r\n margin: 0;\r\n overflow: auto;\r\n font-size: 0;\r\n}\r\n\r\n#chart-container > figure, div {\r\n margin-top: 0 !important;\r\n margin-bottom: 0 !important;\r\n}\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\n/**\r\n * The SVG template to use when loading SVG content to be exported.\r\n *\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {string} The SVG template.\r\n */\r\nexport default (svg) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${svg}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module handles chart export functionality using Puppeteer.\r\n * It supports exporting charts as SVG, PNG, JPEG, and PDF formats. The module\r\n * manages page resources, sets up the export environment, and processes chart\r\n * configurations or SVG inputs for rendering. Exports to a chart from a page\r\n * using Puppeteer.\r\n */\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { createChart } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from '../templates/svgExport/svgExport.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @async\r\n * @function puppeteerExport\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise<(string|Buffer|ExportError)>} A Promise that resolves\r\n * to the exported data or rejecting with an `ExportError`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if export to an unsupported\r\n * output format occurs.\r\n */\r\nexport async function puppeteerExport(page, options) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n let isSVG = false;\r\n if (exportOptions.svg) {\r\n log(4, '[export] Treating as SVG input.');\r\n\r\n // If the `type` is also SVG, return the input\r\n if (exportOptions.type === 'svg') {\r\n return exportOptions.svg;\r\n }\r\n\r\n // Mark as SVG export for the later size corrections\r\n isSVG = true;\r\n\r\n // SVG export\r\n await _setAsSvg(page, exportOptions.svg);\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await _setAsOptions(page, options);\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources.push(\r\n ...(await addPageResources(page, options.customLogic))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types\r\n // of exports. Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await _getClipRegion(page);\r\n\r\n // Set final `height` for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n\r\n // Set final `width` for viewport\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let result;\r\n // Rasterization process\r\n switch (exportOptions.type) {\r\n case 'svg':\r\n result = await _createSVG(page);\r\n break;\r\n case 'png':\r\n case 'jpeg':\r\n result = await _createImage(\r\n page,\r\n exportOptions.type,\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n case 'pdf':\r\n result = await _createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n exportOptions.rasterizationTimeout\r\n );\r\n break;\r\n default:\r\n throw new ExportError(\r\n `[export] Unsupported output format: ${exportOptions.type}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return result;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n}\r\n\r\n/**\r\n * Sets the specified page's content with provided export input within\r\n * the window context using the `page.setContent` function.\r\n *\r\n * @async\r\n * @function _setAsSvg\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} svg - The SVG input content to be exported.\r\n *\r\n * @returns {Promise} A Promise that resolves after the content is set.\r\n */\r\nasync function _setAsSvg(page, svg) {\r\n await page.setContent(svgTemplate(svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n}\r\n\r\n/**\r\n * Sets the options with specified export input and sizes as configuration into\r\n * the `createChart` function within the window context using\r\n * the `page.evaluate` function.\r\n *\r\n * @async\r\n * @function _setAsOptions\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves after the configuration\r\n * is set.\r\n */\r\nasync function _setAsOptions(page, options) {\r\n await page.evaluate(createChart, options);\r\n}\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element\r\n * with the 'chart-container' id.\r\n *\r\n * @async\r\n * @function _getClipRegion\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * `x`, `y`, `width`, and `height` properties.\r\n */\r\nasync function _getClipRegion(page) {\r\n return page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n}\r\n\r\n/**\r\n * Creates an SVG by evaluating the `outerHTML` of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @async\r\n * @function _createSVG\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} A Promise that resolves to the SVG string.\r\n */\r\nasync function _createSVG(page) {\r\n return page.$eval(\r\n '#container svg:first-of-type',\r\n (element) => element.outerHTML\r\n );\r\n}\r\n\r\n/**\r\n * Creates an image using Puppeteer's page `screenshot` functionality with\r\n * specified options.\r\n *\r\n * @async\r\n * @function _createImage\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the image buffer\r\n * or rejecting with an `ExportError` for timeout.\r\n */\r\nasync function _createImage(page, type, clip, rasterizationTimeout) {\r\n return Promise.race([\r\n page.screenshot({\r\n type,\r\n clip,\r\n encoding: 'base64',\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n captureBeyondViewport: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n // Always render on a transparent page if the expected type format is PNG\r\n omitBackground: type == 'png' // #447, #463\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout', 408)),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n}\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page `pdf` functionality with specified\r\n * options.\r\n *\r\n * @async\r\n * @function _createPDF\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} A Promise that resolves to the PDF buffer.\r\n */\r\nasync function _createPDF(page, height, width, rasterizationTimeout) {\r\n await page.emulateMediaType('screen');\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding: 'base64',\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n}\r\n\r\nexport default {\r\n puppeteerExport\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides a worker pool implementation for managing\r\n * the browser instance and pages, specifically designed for use with\r\n * the Highcharts Export Server. It optimizes resources usage and performance\r\n * by maintaining a pool of workers that can handle concurrent export tasks\r\n * using Puppeteer.\r\n */\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { createBrowser, closeBrowser, newPage, clearPage } from './browser.js';\r\nimport { getOptions } from './config.js';\r\nimport { puppeteerExport } from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getNewDateTime, measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = null;\r\n\r\n// Pool statistics\r\nconst poolStats = {\r\n exportsAttempted: 0,\r\n exportsPerformed: 0,\r\n exportsDropped: 0,\r\n exportsFromSvg: 0,\r\n exportsFromOptions: 0,\r\n exportsFromSvgAttempts: 0,\r\n exportsFromOptionsAttempts: 0,\r\n timeSpent: 0,\r\n timeSpentAverage: 0\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @async\r\n * @function initPool\r\n *\r\n * @param {Object} [poolOptions=getOptions().pool] - Object containing `pool`\r\n * options. The default value is the global pool options of the export server\r\n * instance.\r\n * @param {Array.} [puppeteerArgs=[]] - Additional arguments\r\n * for Puppeteer launch. The default value is an empty array.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when an already initialized pool of resources is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not create the pool\r\n * of workers.\r\n */\r\nexport async function initPool(\r\n poolOptions = getOptions().pool,\r\n puppeteerArgs = []\r\n) {\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(puppeteerArgs);\r\n\r\n try {\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolOptions.minWorkers}, max ${poolOptions.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n return;\r\n }\r\n\r\n // Keep an eye on a correct min and max workers number\r\n if (poolOptions.minWorkers > poolOptions.maxWorkers) {\r\n poolOptions.minWorkers = poolOptions.maxWorkers;\r\n }\r\n\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the `create`, `validate`, and `destroy` functions\r\n ..._factory(poolOptions),\r\n min: poolOptions.minWorkers,\r\n max: poolOptions.maxWorkers,\r\n acquireTimeoutMillis: poolOptions.acquireTimeout,\r\n createTimeoutMillis: poolOptions.createTimeout,\r\n destroyTimeoutMillis: poolOptions.destroyTimeout,\r\n idleTimeoutMillis: poolOptions.idleTimeout,\r\n createRetryIntervalMillis: poolOptions.createRetryInterval,\r\n reapIntervalMillis: poolOptions.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const clearStatus = await clearPage(resource, false);\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Releasing a worker. Clear page status: ${clearStatus}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (_eventId, resource) => {\r\n log(\r\n 4,\r\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\r\n );\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolOptions.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not configure and create the pool of workers.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @async\r\n * @function killPool\r\n *\r\n * @returns {Promise} A Promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[pool] Destroyed the pool of resources.');\r\n }\r\n pool = null;\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @async\r\n * @function postWork\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to the export result\r\n * and options.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the export process.\r\n */\r\nexport async function postWork(options) {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n // An export attempt counted\r\n ++poolStats.exportsAttempted;\r\n\r\n // Display the pool information if needed\r\n if (getOptions().pool.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n // Throw an error in case of lacking the pool instance\r\n if (!pool) {\r\n throw new ExportError(\r\n '[pool] Work received, but pool has not been started.',\r\n 500\r\n );\r\n }\r\n\r\n // The acquire counter\r\n const acquireCounter = measureTime();\r\n\r\n // Try to acquire the worker along with the id, works count and page\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n\r\n // Acquire a pool resource\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Acquiring a worker handle took ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`,\r\n 400\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n throw new ExportError(\r\n '[pool] Resolved worker page is invalid: the pool setup is wonky.',\r\n 400\r\n );\r\n }\r\n\r\n // Save the start time\r\n const workStart = getNewDateTime();\r\n\r\n log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE:\r\n // If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE:\r\n // Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n // Set the `workLimit` to exceeded in order to recreate the resource\r\n workerHandle.workCount = options.pool.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n '[pool] ' +\r\n (options._requestId ? `Request [${options._requestId}] - ` : '') +\r\n `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options._requestId\r\n ? `[benchmark] Request [${options._requestId}] - `\r\n : '[benchmark] ',\r\n `Exporting a chart sucessfully took ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = getNewDateTime();\r\n const exportTime = workEnd - workStart;\r\n\r\n poolStats.timeSpent += exportTime;\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportTime}ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw error;\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @function getPool\r\n *\r\n * @returns {(Object|null)} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport function getPool() {\r\n return pool;\r\n}\r\n\r\n/**\r\n * Gets the statistic of a pool instace about exports.\r\n *\r\n * @function getPoolStats\r\n *\r\n * @returns {Object} The current pool statistics.\r\n */\r\nexport function getPoolStats() {\r\n return poolStats;\r\n}\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @function getPoolInfoJSON\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport function getPoolInfoJSON() {\r\n return {\r\n min: pool.min,\r\n max: pool.max,\r\n used: pool.numUsed(),\r\n available: pool.numFree(),\r\n allCreated: pool.numUsed() + pool.numFree(),\r\n pendingAcquires: pool.numPendingAcquires(),\r\n pendingCreates: pool.numPendingCreates(),\r\n pendingValidations: pool.numPendingValidations(),\r\n pendingDestroys: pool.pendingDestroys.length,\r\n absoluteAll:\r\n pool.numUsed() +\r\n pool.numFree() +\r\n pool.numPendingAcquires() +\r\n pool.numPendingCreates() +\r\n pool.numPendingValidations() +\r\n pool.pendingDestroys.length\r\n };\r\n}\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n *\r\n * @function getPoolInfo\r\n */\r\nexport function getPoolInfo() {\r\n const {\r\n min,\r\n max,\r\n used,\r\n available,\r\n allCreated,\r\n pendingAcquires,\r\n pendingCreates,\r\n pendingValidations,\r\n pendingDestroys,\r\n absoluteAll\r\n } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of used resources: ${used}.`);\r\n log(5, `[pool] The number of free resources: ${available}.`);\r\n log(\r\n 5,\r\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\r\n );\r\n log(\r\n 5,\r\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\r\n );\r\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\r\n}\r\n\r\n/**\r\n * Factory function that returns an object with `create`, `validate`,\r\n * and `destroy` functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - Object containing `pool` options.\r\n */\r\nfunction _factory(poolOptions) {\r\n return {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @async\r\n * @function create\r\n *\r\n * @returns {Promise} A Promise that resolves to an object\r\n * containing the worker ID, a reference to the browser page, and initial\r\n * work count.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is an error during\r\n * the creation of the new page.\r\n */\r\n create: async () => {\r\n // Init the resource with unique id and work count\r\n const poolResource = {\r\n id: uuid(),\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolOptions.workLimit / 2))\r\n };\r\n\r\n try {\r\n // Start measuring a page creation time\r\n const startDate = getNewDateTime();\r\n\r\n // Create a new page\r\n await newPage(poolResource);\r\n\r\n // Measure the time of full creation and configuration of a page\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\r\n getNewDateTime() - startDate\r\n }ms.`\r\n );\r\n\r\n // Return ready pool resource\r\n return poolResource;\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Error encountered when creating a new page.`\r\n );\r\n throw error;\r\n }\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @async\r\n * @function validate\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {Promise} A Promise that resolves to true if the worker\r\n * is valid and within the work limit; otherwise, to false.\r\n */\r\n validate: async (poolResource) => {\r\n // NOTE:\r\n // In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser.\r\n //\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n\r\n // Check if the `page` is valid\r\n if (!poolResource.page) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (no valid page is found).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `page` is closed\r\n if (poolResource.page.isClosed()) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `mainFrame` is detached\r\n if (poolResource.page.mainFrame().detached) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\r\n );\r\n return false;\r\n }\r\n\r\n // Check if the `workLimit` is exceeded\r\n if (\r\n poolOptions.workLimit &&\r\n ++poolResource.workCount > poolOptions.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolOptions.workLimit} works per resource limit).`\r\n );\r\n return false;\r\n }\r\n\r\n // The `poolResource` is validated\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @async\r\n * @function destroy\r\n *\r\n * @param {Object} poolResource - The handle to the worker, containing\r\n * the worker's ID, a reference to the browser page, and work count.\r\n */\r\n destroy: async (poolResource) => {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`\r\n );\r\n\r\n if (poolResource.page && !poolResource.page.isClosed()) {\r\n try {\r\n // Remove all attached event listeners from the resource\r\n poolResource.page.removeAllListeners('pageerror');\r\n poolResource.page.removeAllListeners('console');\r\n poolResource.page.removeAllListeners('framedetached');\r\n\r\n // We need to wait around for this\r\n await poolResource.page.close();\r\n } catch (error) {\r\n log(\r\n 3,\r\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\r\n );\r\n throw error;\r\n }\r\n }\r\n }\r\n };\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolStats,\r\n getPoolInfo,\r\n getPoolInfoJSON\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n */\r\n\r\nimport DOMPurify from 'dompurify';\r\nimport { JSDOM } from 'jsdom';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing \r\n * tags and any content within them.\r\n *\r\n * @function sanitize\r\n *\r\n * @param {string} input - The HTML string to be sanitized.\r\n *\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n // Get the virtual DOM\r\n const window = new JSDOM('').window;\r\n\r\n // Create a purifying instance\r\n const purify = DOMPurify(window);\r\n\r\n // Return sanitized input\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default {\r\n sanitize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides functions to prepare for the exporting charts\r\n * into various image output formats such as JPEG, PNG, PDF, and SVGs.\r\n * It supports single and batch export operations and allows customization\r\n * through options passed from configurations or APIs.\r\n */\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, mergeOptions, isAllowedConfig } from './config.js';\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { killPool, postWork, getPoolStats } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport {\r\n fixOutfile,\r\n fixType,\r\n getAbsolutePath,\r\n getBase64,\r\n roundNumber,\r\n wrapAround\r\n} from './utils.js';\r\nimport { strictValidate, validateOption } from './validation.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The global flag for the code execution permission\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts a single export process based on the specified options and saves\r\n * the image in the provided outfile.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain at least one of the following\r\n * properties: `infile`, `instr`, `options`, or `svg` to generate a valid image.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * the single export process.\r\n */\r\nexport async function singleExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export) {\r\n // Perform an export\r\n await startExport(options, async (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(data.result, 'base64') : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide one of the following options: `infile`, `instr`, `options`, or `svg` to generate a valid image.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the `batch` option. The `batch` is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results are saved\r\n * in provided outfiles.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which may be a partial\r\n * or complete set of options. It must contain the `batch` option to generate\r\n * valid images.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * processes are completed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport async function batchExport(options) {\r\n // Check if the export makes sense\r\n if (options && options.export && options.export.batch) {\r\n // An array for collecting batch exports\r\n const batchFunctions = [];\r\n\r\n // Split and pair the `batch` arguments\r\n for (let pair of options.export.batch.split(';') || []) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, data) => {\r\n // Exit process when error exists\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Get the `b64`, `outfile`, and `type` for a chart\r\n const { b64, outfile, type } = data.options.export;\r\n\r\n // Save the result\r\n try {\r\n if (b64) {\r\n // As a Base64 string to a txt file\r\n writeFileSync(\r\n `${outfile.split('.').shift() || 'chart'}.txt`,\r\n getBase64(data.result, type)\r\n );\r\n } else {\r\n // As a correct image format\r\n writeFileSync(\r\n outfile,\r\n type !== 'svg'\r\n ? Buffer.from(data.result, 'base64')\r\n : data.result\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error while saving a chart.',\r\n 500\r\n ).setError(error);\r\n }\r\n }\r\n )\r\n );\r\n } else {\r\n log(2, '[chart] No correct pair found for the batch export.');\r\n }\r\n }\r\n\r\n // Await all exports are done\r\n const batchResults = await Promise.allSettled(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n\r\n // Log errors if found\r\n batchResults.forEach((result, index) => {\r\n // Log the error with stack about the specific batch export\r\n if (result.reason) {\r\n logWithStack(\r\n 1,\r\n result.reason,\r\n `[chart] Batch export number ${index + 1} could not be correctly completed.`\r\n );\r\n }\r\n });\r\n } else {\r\n throw new ExportError(\r\n '[chart] No expected `export` options were found. Please provide the `batch` option to generate valid images.',\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Starts an export process. The `customOptions` parameter is an object that\r\n * may be partial or complete set of options. The `endCallback` is called when\r\n * the export is completed, with the `error` object as the first argument\r\n * and the `data` object as the second, which contains the Base64 representation\r\n * of the chart in the `result` property and the full set of export options\r\n * in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process. The first\r\n * argument is `error` object and the `data` object is the second, that contains\r\n * the Base64 representation of the chart in the `result` property and the full\r\n * set of export options in the `options` property.\r\n *\r\n * @returns {Promise} This function does not return a value directly.\r\n * Instead, it communicates results via the `endCallback`.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is a problem with\r\n * processing input of any type. The error is passed into the `endCallback`\r\n * function and processed there.\r\n */\r\nexport async function startExport(customOptions, endCallback) {\r\n try {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Merge the custom options into default ones\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // Export using options from the file as an input\r\n if (exportOptions.infile !== null) {\r\n log(4, '[chart] Attempting to export from a file input.');\r\n\r\n let fileContent;\r\n try {\r\n // Try to read the file to get the string representation\r\n fileContent = readFileSync(\r\n getAbsolutePath(exportOptions.infile),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error loading content from a file input.',\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Check the file's extension\r\n if (exportOptions.infile.endsWith('.svg')) {\r\n try {\r\n // Set to the `svg` option\r\n exportOptions.svg = validateOption('svg', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `svg` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n try {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('instr', fileContent, false);\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] The `instr` option validation error'\r\n );\r\n throw error;\r\n }\r\n } else {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the `infile` option.',\r\n 400\r\n );\r\n }\r\n }\r\n\r\n // Export using SVG as an input\r\n if (exportOptions.svg !== null) {\r\n log(4, '[chart] Attempting to export from an SVG input.');\r\n\r\n // SVG exports attempts counter\r\n ++getPoolStats().exportsFromSvgAttempts;\r\n\r\n // Export from an SVG string\r\n const result = await _exportFromSvg(\r\n sanitize(exportOptions.svg), // #209\r\n options\r\n );\r\n\r\n // SVG exports counter\r\n ++getPoolStats().exportsFromSvg;\r\n\r\n // Pass SVG export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // Export using options as an input\r\n if (exportOptions.instr !== null || exportOptions.options !== null) {\r\n log(4, '[chart] Attempting to export from options input.');\r\n\r\n // Options exports attempts counter\r\n ++getPoolStats().exportsFromOptionsAttempts;\r\n\r\n // Export from options\r\n const result = await _exportFromOptions(\r\n exportOptions.instr || exportOptions.options,\r\n options\r\n );\r\n\r\n // Options exports counter\r\n ++getPoolStats().exportsFromOptions;\r\n\r\n // Pass options export result to the end callback\r\n return endCallback(null, result);\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`,\r\n 400\r\n )\r\n );\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves and returns the current status of the code execution permission.\r\n *\r\n * @function getAllowCodeExecution\r\n *\r\n * @returns {boolean} The value of the global `allowCodeExecution` option.\r\n */\r\nexport function getAllowCodeExecution() {\r\n return allowCodeExecution;\r\n}\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @function setAllowCodeExecution\r\n *\r\n * @param {boolean} value - The value to be assigned to the global\r\n * `allowCodeExecution` option.\r\n */\r\nexport function setAllowCodeExecution(value) {\r\n allowCodeExecution = value;\r\n}\r\n\r\n/**\r\n * Exports from an SVG based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromSvg\r\n *\r\n * @param {string} inputToExport - The SVG based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct SVG\r\n * input.\r\n */\r\nasync function _exportFromSvg(inputToExport, options) {\r\n // Check if it is SVG\r\n if (\r\n typeof inputToExport === 'string' &&\r\n (inputToExport.indexOf('= 0 || inputToExport.indexOf('= 0)\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n\r\n // Set the export input as SVG\r\n options.export.svg = inputToExport;\r\n\r\n // Reset the rest of the export input options\r\n options.export.instr = null;\r\n options.export.options = null;\r\n\r\n // Call the function with an SVG string as an export input\r\n return _prepareExport(options);\r\n } else {\r\n throw new ExportError('[chart] Not a correct SVG input.', 400);\r\n }\r\n}\r\n\r\n/**\r\n * Exports from an options based input with the provided options.\r\n *\r\n * @async\r\n * @function _exportFromOptions\r\n *\r\n * @param {string} inputToExport - The options based input to be exported.\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if there is not a correct\r\n * chart options input.\r\n */\r\nasync function _exportFromOptions(inputToExport, options) {\r\n log(4, '[chart] Parsing input from options.');\r\n\r\n // Try to check, validate and parse to stringified options\r\n const stringifiedOptions = isAllowedConfig(\r\n inputToExport,\r\n true,\r\n options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Check if a correct stringified options\r\n if (\r\n stringifiedOptions === null ||\r\n typeof stringifiedOptions !== 'string' ||\r\n !stringifiedOptions.startsWith('{') ||\r\n !stringifiedOptions.endsWith('}')\r\n ) {\r\n throw new ExportError(\r\n '[chart] Invalid configuration provided - Only options configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the `allowCodeExecution` options set to true.',\r\n 403\r\n );\r\n }\r\n\r\n // Set the export input as a stringified chart options\r\n options.export.instr = stringifiedOptions;\r\n\r\n // Reset the rest of the export input options\r\n options.export.svg = null;\r\n\r\n // Call the function with a stringified chart options\r\n return _prepareExport(options);\r\n}\r\n\r\n/**\r\n * Function for finalizing options and configurations before export.\r\n *\r\n * @async\r\n * @function _prepareExport\r\n *\r\n * @param {Object} options - The `options` object containing complete set\r\n * of options.\r\n *\r\n * @returns {Promise} A Promise that resolves to a result of the export\r\n * process.\r\n */\r\nasync function _prepareExport(options) {\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `type` option\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n\r\n // Prepare the `outfile` option\r\n exportOptions.outfile = fixOutfile(exportOptions.type, exportOptions.outfile);\r\n\r\n // Notify about the custom logic usage status\r\n log(\r\n 3,\r\n `[chart] The custom logic is ${customLogicOptions.allowCodeExecution ? 'allowed' : 'disallowed'}.`\r\n );\r\n\r\n // Prepare the custom logic options (`customCode`, `callback`, `resources`)\r\n _handleCustomLogic(customLogicOptions, customLogicOptions.allowCodeExecution);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(\r\n exportOptions,\r\n customLogicOptions.allowFileResources,\r\n customLogicOptions.allowCodeExecution\r\n );\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n options.export = {\r\n ...exportOptions,\r\n ..._findChartSize(exportOptions)\r\n };\r\n\r\n // The last strict validation of options right before exporting process\r\n try {\r\n // Validate final options\r\n options = strictValidate(options);\r\n } catch (error) {\r\n logZodIssues(1, error.issues, '[config] Final options validation error');\r\n }\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Calculates the `height`, `width` and `scale` for chart exports based\r\n * on the provided export options.\r\n *\r\n * The function prioritizes values in the following order:\r\n * 1. The `height`, `width`, `scale` from the `exportOptions`.\r\n * 2. Options from the chart configuration (from `exporting` and `chart`).\r\n * 3. Options from the global options (from `exporting` and `chart`).\r\n * 4. Options from the theme options (from `exporting` and `chart` sections).\r\n * 5. Fallback default values (`height = 400`, `width = 600`, `scale = 1`).\r\n *\r\n * @function _findChartSize\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n *\r\n * @returns {Object} An object containing the calculated `height`, `width`\r\n * and `scale` values for the chart export.\r\n */\r\nfunction _findChartSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n exportOptions.options || isAllowedConfig(exportOptions.instr) || false;\r\n\r\n // Check the `globalOptions` for chart and exporting sections\r\n const { chart: globalOptionsChart, exporting: globalOptionsExporting } =\r\n isAllowedConfig(exportOptions.globalOptions) || false;\r\n\r\n // Check the `themeOptions` for chart and exporting sections\r\n const { chart: themeOptionsChart, exporting: themeOptionsExporting } =\r\n isAllowedConfig(exportOptions.themeOptions) || false;\r\n\r\n // Find the `scale` value:\r\n // - It cannot be lower than 0.1\r\n // - It cannot be higher than 5.0\r\n // - It must be rounded to 2 decimal places (e.g. 0.23234 -> 0.23)\r\n const scale = roundNumber(\r\n Math.max(\r\n 0.1,\r\n Math.min(\r\n exportOptions.scale ||\r\n optionsExporting?.scale ||\r\n globalOptionsExporting?.scale ||\r\n themeOptionsExporting?.scale ||\r\n exportOptions.defaultScale ||\r\n 1,\r\n 5.0\r\n )\r\n ),\r\n 2\r\n );\r\n\r\n // Find the `height` value\r\n const height =\r\n exportOptions.height ||\r\n optionsExporting?.sourceHeight ||\r\n optionsChart?.height ||\r\n globalOptionsExporting?.sourceHeight ||\r\n globalOptionsChart?.height ||\r\n themeOptionsExporting?.sourceHeight ||\r\n themeOptionsChart?.height ||\r\n exportOptions.defaultHeight ||\r\n 400;\r\n\r\n // Find the `width` value\r\n const width =\r\n exportOptions.width ||\r\n optionsExporting?.sourceWidth ||\r\n optionsChart?.width ||\r\n globalOptionsExporting?.sourceWidth ||\r\n globalOptionsChart?.width ||\r\n themeOptionsExporting?.sourceWidth ||\r\n themeOptionsChart?.width ||\r\n exportOptions.defaultWidth ||\r\n 600;\r\n\r\n // Gather `height`, `width` and `scale` information in one object\r\n const size = { height, width, scale };\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n\r\n // Return the size object\r\n return size;\r\n}\r\n\r\n/**\r\n * Handles the execution of custom logic options, including loading `resources`,\r\n * `customCode`, and `callback`. If code execution is allowed, it processes\r\n * the custom logic options accordingly. If code execution is not allowed,\r\n * it disables the usage of resources, custom code and callback.\r\n *\r\n * @function _handleCustomLogic\r\n *\r\n * @param {Object} customLogicOptions - The object containing `customLogic`\r\n * options.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if code execution\r\n * is not allowed but custom logic options are still provided.\r\n */\r\nfunction _handleCustomLogic(customLogicOptions, allowCodeExecution) {\r\n // In case of allowing code execution\r\n if (allowCodeExecution) {\r\n // Process the `resources` option\r\n if (typeof customLogicOptions.resources === 'string') {\r\n // Custom stringified resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } else if (!customLogicOptions.resources) {\r\n try {\r\n // Load the default one\r\n customLogicOptions.resources = _handleResources(\r\n readFileSync(getAbsolutePath('resources.json'), 'utf8'),\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n log(2, '[chart] Unable to load the default `resources.json` file.');\r\n }\r\n }\r\n\r\n // Process the `customCode` option\r\n try {\r\n // Try to load custom code and wrap around it in a self invoking function\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `customCode` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.customCode = null;\r\n }\r\n\r\n // Process the `callback` option\r\n try {\r\n // Try to load callback function\r\n customLogicOptions.callback = wrapAround(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, '[chart] The `callback` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.callback = null;\r\n }\r\n\r\n // Check if there is the `customCode` present\r\n if ([null, undefined].includes(customLogicOptions.customCode)) {\r\n log(3, '[chart] No value for the `customCode` option found.');\r\n }\r\n\r\n // Check if there is the `callback` present\r\n if ([null, undefined].includes(customLogicOptions.callback)) {\r\n log(3, '[chart] No value for the `callback` option found.');\r\n }\r\n\r\n // Check if there is the `resources` present\r\n if ([null, undefined].includes(customLogicOptions.resources)) {\r\n log(3, '[chart] No value for the `resources` option found.');\r\n }\r\n } else {\r\n // If the `allowCodeExecution` flag is set to false, we should refuse\r\n // the usage of the `callback`, `resources`, and `customCode` options.\r\n // Additionally, the worker will refuse to run arbitrary JavaScript.\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Reset all custom code options\r\n customLogicOptions.callback = null;\r\n customLogicOptions.resources = null;\r\n customLogicOptions.customCode = null;\r\n\r\n // Send a message saying that the exporter does not support these settings\r\n throw new ExportError(\r\n `[chart] The 'callback', 'resources', and 'customCode' options have been disabled for this server.`,\r\n 403\r\n );\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Handles and validates resources from the `resources` option for export.\r\n *\r\n * @function _handleResources\r\n *\r\n * @param {(Object|string|null)} [resources=null] - The resources to be handled.\r\n * Can be either a JSON object, stringified JSON, a path to a JSON file,\r\n * or null. The default value is null.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n *\r\n * @returns {(Object|null)} The handled resources or null if no valid resources\r\n * are found.\r\n */\r\nfunction _handleResources(\r\n resources = null,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\r\n } catch {\r\n return null;\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isAllowedConfig(resources, false, allowCodeExecution);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return null;\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n}\r\n\r\n/**\r\n * Handles the loading and validation of the `globalOptions` and `themeOptions`\r\n * in the export options. If the option is a string and references a JSON file\r\n * (when the `allowFileResources` is true), it reads and parses the file.\r\n * Otherwise, it attempts to parse the string or object as JSON. If any errors\r\n * occur during this process, the option is set to null. If there is an error\r\n * loading or parsing the `globalOptions` or `themeOptions`, the error is logged\r\n * and the option is set to null.\r\n *\r\n * @function _handleGlobalAndTheme\r\n *\r\n * @param {Object} exportOptions - The object containing `export` options.\r\n * @param {boolean} allowFileResources - A flag indicating whether loading\r\n * resources from files is allowed.\r\n * @param {boolean} allowCodeExecution - A flag indicating whether code\r\n * execution is allowed.\r\n */\r\nfunction _handleGlobalAndTheme(\r\n exportOptions,\r\n allowFileResources,\r\n allowCodeExecution\r\n) {\r\n // Check the `globalOptions` and `themeOptions` options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n // Check if the option exists\r\n if (exportOptions[optionsName]) {\r\n // Check if it is a string and a file name with the `.json` extension\r\n if (\r\n allowFileResources &&\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n // Check if the file content can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n readFileSync(getAbsolutePath(exportOptions[optionsName]), 'utf8'),\r\n true,\r\n allowCodeExecution\r\n );\r\n } else {\r\n // Check if the value can be a config, and save it as a string\r\n exportOptions[optionsName] = isAllowedConfig(\r\n exportOptions[optionsName],\r\n true,\r\n allowCodeExecution\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] The \\`${optionsName}\\` cannot be loaded.`\r\n );\r\n\r\n // In case of an error, set the option with null\r\n exportOptions[optionsName] = null;\r\n }\r\n });\r\n\r\n // Check if there is the `globalOptions` present\r\n if ([null, undefined].includes(exportOptions.globalOptions)) {\r\n log(3, '[chart] No value for the `globalOptions` option found.');\r\n }\r\n\r\n // Check if there is the `themeOptions` present\r\n if ([null, undefined].includes(exportOptions.themeOptions)) {\r\n log(3, '[chart] No value for the `themeOptions` option found.');\r\n }\r\n}\r\n\r\nexport default {\r\n startExport,\r\n singleExport,\r\n batchExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview This module provides utility functions for managing intervals\r\n * and timeouts in a centralized manner. It maintains a registry of all active\r\n * timers and allows for their efficient cleanup when needed. This can be useful\r\n * in applications where proper resource management and clean shutdown of timers\r\n * are critical to avoid memory leaks or unintended behavior.\r\n */\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals and timeouts\r\nconst timerIds = [];\r\n\r\n/**\r\n * Adds id of the `setInterval` or `setTimeout` and to the `timerIds` array.\r\n *\r\n * @function addTimer\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval or a timeout.\r\n */\r\nexport function addTimer(id) {\r\n timerIds.push(id);\r\n}\r\n\r\n/**\r\n * Clears all of ongoing intervals and timeouts by ids gathered\r\n * in the `timerIds` array.\r\n *\r\n * @function clearAllTimers\r\n */\r\nexport function clearAllTimers() {\r\n log(4, `[timer] Clearing all registered intervals and timeouts.`);\r\n for (const id of timerIds) {\r\n clearInterval(id);\r\n clearTimeout(id);\r\n }\r\n}\r\n\r\nexport default {\r\n addTimer,\r\n clearAllTimers\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for logging errors with stack traces\r\n * and handling error responses in an Express application.\r\n */\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { logWithStack } from '../../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @function logErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function with\r\n * the passed error.\r\n */\r\nfunction logErrorMiddleware(error, request, response, next) {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (getOptions().other.nodeEnv !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the `returnErrorMiddleware` middleware\r\n return next(error);\r\n}\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @function returnErrorMiddleware\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nfunction returnErrorMiddleware(error, request, response, next) {\r\n // Gather all requied information for the response\r\n const { message, stack } = error;\r\n\r\n // Use the error's status code or the default 400\r\n const statusCode = error.statusCode || 400;\r\n\r\n // Set and return response\r\n response.status(statusCode).json({ statusCode, message, stack });\r\n}\r\n\r\n/**\r\n * Adds the error middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function errorMiddleware(app) {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for configuring and enabling rate\r\n * limiting in an Express application.\r\n */\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\n\r\nimport ExportError from '../../errors/ExportError.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n *\r\n * @param {Object} [rateLimitingOptions=getOptions().server.rateLimiting] -\r\n * Object containing `rateLimiting` options. The default value is the global\r\n * rate limiting options of the export server instance.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if could not configure and set\r\n * the rate limiting options.\r\n */\r\nexport default function rateLimitingMiddleware(\r\n app,\r\n rateLimitingOptions = getOptions().server.rateLimiting\r\n) {\r\n try {\r\n // Check if the rate limiting is enabled\r\n if (rateLimitingOptions.enable) {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: rateLimitingOptions.maxRequests || 30,\r\n window: rateLimitingOptions.window || 1,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || false,\r\n skipToken: rateLimitingOptions.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[rate limiting] Could not configure and set the rate limiting options.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport ExportError from './ExportError.js';\r\n\r\n/**\r\n * A custom HTTP error class that extends the `ExportError`. Used to handle\r\n * errors with HTTP status codes.\r\n */\r\nclass HttpError extends ExportError {\r\n /**\r\n * Creates an instance of the `HttpError`.\r\n *\r\n * @param {string} message - The error message to be displayed.\r\n * @param {number} statusCode - Optional HTTP status code associated\r\n * with the error (e.g., 400, 500).\r\n */\r\n constructor(message, statusCode) {\r\n super(message, statusCode);\r\n }\r\n\r\n /**\r\n * Sets or updates the HTTP status code for the error.\r\n *\r\n * @param {number} statusCode - The HTTP status code to assign to the error.\r\n *\r\n * @returns {HttpError} The updated instance of the `HttpError` class.\r\n */\r\n setStatus(statusCode) {\r\n this.statusCode = statusCode;\r\n\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Provides middleware functions for validating incoming HTTP requests\r\n * in an Express application. This module ensures that requests contain\r\n * appropriate content types and valid request bodies, including proper JSON\r\n * structures and chart data for exports. It checks for potential issues such\r\n * as missing or malformed data, private range URLs in SVG payloads, and allows\r\n * for flexible options validation. The middleware logs detailed information\r\n * and handles errors related to incorrect payloads, chart data, and private URL\r\n * usage.\r\n */\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution } from '../../chart.js';\r\nimport { isAllowedConfig } from '../../config.js';\r\nimport { log, logZodIssues } from '../../logger.js';\r\nimport {\r\n fixConstr,\r\n fixType,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound\r\n} from '../../utils.js';\r\nimport { looseValidate } from '../../validation.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Middleware for validating the content-type header.\r\n *\r\n * @function contentTypeMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the content-type\r\n * is not correct.\r\n */\r\nfunction contentTypeMiddleware(request, response, next) {\r\n try {\r\n // Get the content type header\r\n const contentType = request.headers['content-type'] || '';\r\n\r\n // Allow only JSON, URL-encoded and form data without files types of data\r\n if (\r\n !contentType.includes('application/json') &&\r\n !contentType.includes('application/x-www-form-urlencoded') &&\r\n !contentType.includes('multipart/form-data')\r\n ) {\r\n throw new HttpError(\r\n '[validation] Content-Type must be application/json, application/x-www-form-urlencoded, or multipart/form-data.',\r\n 415\r\n );\r\n }\r\n\r\n // Call the `requestBodyMiddleware` middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Middleware for validating the request's body.\r\n *\r\n * @function requestBodyMiddleware\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {undefined} The call to the next middleware function.\r\n *\r\n * @throws {HttpError} Throws an `HttpError` if the body is not correct.\r\n * @throws {HttpError} Throws an `HttpError` if the chart data from the body\r\n * is not correct.\r\n * @throws {HttpError} Throws an `HttpError` in case of the private range url\r\n * error.\r\n */\r\nfunction requestBodyMiddleware(request, response, next) {\r\n try {\r\n // Get the request body\r\n const body = request.body;\r\n\r\n // Create a unique ID for a request\r\n const requestId = uuid().replace(/-/g, '');\r\n\r\n // Throw an error if there is no correct body\r\n if (!body || isObjectEmpty(body)) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is empty.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] The request body is required. Please ensure that your Content-Type header is correct. Accepted types are 'application/json' and 'multipart/form-data'.\",\r\n 400\r\n );\r\n }\r\n\r\n // Get the `allowCodeExecution` option for the server\r\n const allowCodeExecution = getAllowCodeExecution();\r\n\r\n // Find a correct chart options\r\n const instr = isAllowedConfig(\r\n // Use one of the below\r\n body.instr || body.options || body.infile || body.data,\r\n // Stringify options\r\n true,\r\n // Allow or disallow functions\r\n allowCodeExecution\r\n );\r\n\r\n // Throw an error if there is no correct chart data\r\n if (instr === null && !body.svg) {\r\n log(\r\n 2,\r\n `[validation] Request [${requestId}] - The request from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Received payload is missing correct chart data for export: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"[validation] No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n // Throw an error if test of xlink:href elements from payload's SVG fails\r\n if (body.svg && isPrivateRangeUrlFound(body.svg)) {\r\n throw new HttpError(\r\n \"[validation] SVG potentially contain at least one forbidden URL in 'xlink:href' element. Please review the SVG content and ensure that all referenced URLs comply with security policies.\",\r\n 400\r\n );\r\n }\r\n\r\n try {\r\n // Validate options from the body and store parsed structure in the request\r\n request.validatedOptions = looseValidate({\r\n // Set the created ID as a `_requestId` property in the validated options\r\n _requestId: requestId,\r\n export: {\r\n instr,\r\n svg: body.svg,\r\n outfile:\r\n body.outfile ||\r\n `${request.params.filename || 'chart'}.${fixType(body.type)}`,\r\n type: fixType(body.type, body.outfile),\r\n constr: fixConstr(body.constr),\r\n b64: body.b64,\r\n noDownload: body.noDownload,\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale,\r\n globalOptions: isAllowedConfig(\r\n body.globalOptions,\r\n true,\r\n allowCodeExecution\r\n ),\r\n themeOptions: isAllowedConfig(\r\n body.themeOptions,\r\n true,\r\n allowCodeExecution\r\n )\r\n },\r\n customLogic: {\r\n allowCodeExecution,\r\n allowFileResources: false,\r\n customCode: body.customCode,\r\n callback: body.callback,\r\n resources: isAllowedConfig(body.resources, true, allowCodeExecution)\r\n }\r\n });\r\n } catch (error) {\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n '[config] Request options validation error'\r\n );\r\n\r\n throw new HttpError(\r\n 'The provided options are not correct. Please check if your data is of the correct types.',\r\n 400\r\n );\r\n }\r\n\r\n // Call the next middleware\r\n return next();\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the validation middlewares to the passed express app instance.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function validationMiddleware(app) {\r\n // Add content type validation middleware\r\n app.post(['/', '/:filename'], contentTypeMiddleware);\r\n\r\n // Add request body request validation middleware\r\n app.post(['/', '/:filename'], requestBodyMiddleware);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines the export routes and logic for handling chart export\r\n * requests in an Express server. This module processes incoming requests\r\n * to export charts in various formats (e.g. JPEG, PNG, PDF, SVG). It integrates\r\n * with Highcharts' core functionalities and supports both immediate download\r\n * responses and Base64-encoded content returns. The code also features\r\n * benchmarking for performance monitoring.\r\n */\r\n\r\nimport { startExport } from '../../chart.js';\r\nimport { log } from '../../logger.js';\r\nimport { getBase64, measureTime } from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @async\r\n * @function requestExport\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is complete.\r\n */\r\nasync function requestExport(request, response, next) {\r\n try {\r\n // Start counting time for a request\r\n const requestCounter = measureTime();\r\n\r\n // In case the connection is closed, force to abort further actions\r\n let connectionAborted = false;\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n // Get the options previously validated in the validation middleware\r\n const requestOptions = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = requestOptions._requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Got an incoming HTTP request with ID ${requestId}.`);\r\n\r\n // Start the export process\r\n await startExport(requestOptions, (error, data) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The client closed the connection before the chart finished processing.`\r\n );\r\n return;\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!data || !data.result) {\r\n log(\r\n 2,\r\n `[export] Request [${requestId}] - Request from ${\r\n request.headers['x-forwarded-for'] ||\r\n request.connection.remoteAddress\r\n } was incorrect. Received result is ${data.result}.`\r\n );\r\n\r\n throw new HttpError(\r\n '[export] Unexpected return of the export result from the chart generation. Please check your request data.',\r\n 400\r\n );\r\n }\r\n\r\n // Return the result in an appropriate format\r\n if (data.result) {\r\n log(\r\n 3,\r\n `[export] Request [${requestId}] - The whole exporting process took ${requestCounter()}ms.`\r\n );\r\n\r\n // Get the `type`, `b64`, `noDownload`, and `outfile` from options\r\n const { type, b64, noDownload, outfile } = data.options.export;\r\n\r\n // If only Base64 is required, return it\r\n if (b64) {\r\n return response.send(getBase64(data.result, type));\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!noDownload) {\r\n response.attachment(outfile);\r\n }\r\n\r\n // If SVG, return plain content, otherwise a b64 string from a buffer\r\n return type === 'svg'\r\n ? response.send(data.result)\r\n : response.send(Buffer.from(data.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n}\r\n\r\n/**\r\n * Adds the `export` routes.\r\n *\r\n * @function exportRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function exportRoutes(app) {\r\n /**\r\n * Adds the POST '/' - A route for handling POST requests at the root\r\n * endpoint.\r\n */\r\n app.post('/', requestExport);\r\n\r\n /**\r\n * Adds the POST '/:filename' - A route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', requestExport);\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for server health monitoring, including\r\n * uptime, success rates, and other server statistics.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { getHighchartsVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolStats, getPoolInfoJSON } from '../../pool.js';\r\nimport { addTimer } from '../../timer.js';\r\nimport { __dirname, getNewDateTime } from '../../utils.js';\r\n\r\n// Set the start date of the server\r\nconst serverStartTime = new Date();\r\n\r\n// Get the `package.json` content\r\nconst packageFile = JSON.parse(readFileSync(join(__dirname, 'package.json')));\r\n\r\n// An array for success rate ratios\r\nconst successRates = [];\r\n\r\n// Record every minute\r\nconst recordInterval = 60 * 1000;\r\n\r\n// 30 minutes\r\nconst windowSize = 30;\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the `successRates`\r\n * array.\r\n *\r\n * @function _calculateMovingAverage\r\n *\r\n * @returns {number} A moving average for success ratio of the server exports.\r\n */\r\nfunction _calculateMovingAverage() {\r\n return successRates.reduce((a, b) => a + b, 0) / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and collects records to the `successRates` array.\r\n *\r\n * @function _startSuccessRate\r\n *\r\n * @returns {NodeJS.Timeout} Id of an interval.\r\n */\r\nfunction _startSuccessRate() {\r\n return setInterval(() => {\r\n const stats = getPoolStats();\r\n const successRatio =\r\n stats.exportsAttempted === 0\r\n ? 1\r\n : (stats.exportsPerformed / stats.exportsAttempted) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n}\r\n\r\n/**\r\n * Adds the `health` routes.\r\n *\r\n * @function healthRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function healthRoutes(app) {\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected `addTimer` funtion\r\n addTimer(_startSuccessRate());\r\n\r\n /**\r\n * Adds the GET '/health' - A route for getting the basic stats of the server.\r\n */\r\n app.get('/health', (request, response, next) => {\r\n try {\r\n log(4, '[health] Returning server health.');\r\n\r\n const stats = getPoolStats();\r\n const period = successRates.length;\r\n const movingAverage = _calculateMovingAverage();\r\n\r\n // Send the server's statistics\r\n response.send({\r\n // Status and times\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime: `${Math.floor((getNewDateTime() - serverStartTime.getTime()) / 1000 / 60)} minutes`,\r\n\r\n // Versions\r\n serverVersion: packageFile.version,\r\n highchartsVersion: getHighchartsVersion(),\r\n\r\n // Exports\r\n averageExportTime: stats.timeSpentAverage,\r\n attemptedExports: stats.exportsAttempted,\r\n performedExports: stats.exportsPerformed,\r\n failedExports: stats.exportsDropped,\r\n sucessRatio: (stats.exportsPerformed / stats.exportsAttempted) * 100,\r\n\r\n // Pool\r\n pool: getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG and JSON exports\r\n svgExports: stats.exportsFromSvg,\r\n jsonExports: stats.exportsFromOptions,\r\n svgExportsAttempts: stats.exportsFromSvgAttempts,\r\n jsonExportsAttempts: stats.exportsFromOptionsAttempts\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for serving the UI for the export server\r\n * when enabled.\r\n */\r\n\r\nimport { join } from 'path';\r\n\r\nimport { getOptions } from '../../config.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the `ui` routes.\r\n *\r\n * @function uiRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function uiRoutes(app) {\r\n /**\r\n * Adds the GET '/' - A route for a UI when enabled on the export server.\r\n */\r\n app.get(getOptions().ui.route || '/', (request, response, next) => {\r\n try {\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Defines an Express route for updating the Highcharts version\r\n * on the server, with authentication and validation.\r\n */\r\n\r\nimport { updateHighchartsVersion, getHighchartsVersion } from '../../cache.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the `version_change` routes.\r\n *\r\n * @function versionChangeRoutes\r\n *\r\n * @param {Express} app - The Express app instance.\r\n */\r\nexport default function versionChangeRoutes(app) {\r\n /**\r\n * Adds the POST '/version_change/:newVersion' - A route for changing\r\n * the Highcharts version on the server.\r\n */\r\n app.post('/version_change/:newVersion', async (request, response, next) => {\r\n try {\r\n // Get the token directly from envs\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n '[version] The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Get the token from the hc-auth header\r\n const token = request.get('hc-auth');\r\n\r\n // Check if the hc-auth header contain a correct token\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n '[version] Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // Update version\r\n await updateHighchartsVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `[version] Version change: ${error.message}`,\r\n 400\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n highchartsVersion: getHighchartsVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('[version] No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n return next(error);\r\n }\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview A module that sets up and manages HTTP and HTTPS servers\r\n * for the Highcharts Export Server. It handles server initialization,\r\n * configuration, error handling, middleware setup, route definition, and rate\r\n * limiting. The module exports functions to start, stop, and manage server\r\n * instances, as well as utility functions for defining routes and attaching\r\n * middlewares.\r\n */\r\n\r\nimport { readFile } from 'fs/promises';\r\nimport { join } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport { getOptions } from '../config.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname, getAbsolutePath } from '../utils.js';\r\n\r\nimport errorMiddleware from './middlewares/error.js';\r\nimport rateLimitingMiddleware from './middlewares/rateLimiting.js';\r\nimport validationMiddleware from './middlewares/validation.js';\r\n\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoutes from './routes/health.js';\r\nimport uiRoutes from './routes/ui.js';\r\nimport versionChangeRoutes from './routes/versionChange.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n/**\r\n * Starts HTTP or/and HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains all server related properties (see\r\n * the `server` section in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions=getOptions().server] - Object containing\r\n * `server` options. The default value is the global server options\r\n * of the export server instance.\r\n *\r\n * @returns {Promise} A Promise that resolves to ending the function\r\n * execution when the server should not be enabled or when no valid Express app\r\n * is found.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the server cannot\r\n * be configured and started.\r\n */\r\nexport async function startServer(serverOptions = getOptions().server) {\r\n try {\r\n // Stop if not enabled\r\n if (!serverOptions.enable || !app) {\r\n throw new ExportError(\r\n '[server] Server cannot be started (not enabled or no correct Express app found).',\r\n 500\r\n );\r\n }\r\n\r\n // Too big limits lead to timeouts in the export process when\r\n // the rasterization timeout is set too low\r\n const uploadLimitBytes = serverOptions.uploadLimit * 1024 * 1024;\r\n\r\n // Memory storage for multer package\r\n const storage = multer.memoryStorage();\r\n\r\n // Enable parsing of form data (files) with multer package\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Disable the X-Powered-By header\r\n app.disable('x-powered-by');\r\n\r\n // Enable CORS support\r\n app.use(\r\n cors({\r\n methods: ['POST', 'GET', 'OPTIONS']\r\n })\r\n );\r\n\r\n // Getting a lot of `RangeNotSatisfiableError` exceptions (even though this\r\n // is a deprecated options, let's try to set it to false)\r\n app.use((request, response, next) => {\r\n response.set('Accept-Ranges', 'none');\r\n next();\r\n });\r\n\r\n // Enable body parser for JSON data\r\n app.use(\r\n express.json({\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Enable body parser for URL-encoded form data\r\n app.use(\r\n express.urlencoded({\r\n extended: true,\r\n limit: uploadLimitBytes\r\n })\r\n );\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Set up static folder's route\r\n app.use(express.static(join(__dirname, 'public')));\r\n\r\n // Listen HTTP server\r\n if (!serverOptions.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverOptions.port, serverOptions.host, () => {\r\n // Save the reference to HTTP server\r\n activeServers.set(serverOptions.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverOptions.host}:${serverOptions.port}.`\r\n );\r\n });\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverOptions.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await readFile(\r\n join(getAbsolutePath(serverOptions.ssl.certPath), 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverOptions.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n _attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverOptions.ssl.port, serverOptions.host, () => {\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverOptions.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverOptions.host}:${serverOptions.ssl.port}.`\r\n );\r\n });\r\n }\r\n }\r\n\r\n // Set up the rate limiter\r\n rateLimitingMiddleware(app, serverOptions.rateLimiting);\r\n\r\n // Set up the validation handler\r\n validationMiddleware(app);\r\n\r\n // Set up routes\r\n healthRoutes(app);\r\n exportRoutes(app);\r\n uiRoutes(app);\r\n versionChangeRoutes(app);\r\n\r\n // Set up the centralized error handler\r\n errorMiddleware(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n *\r\n * @function closeServers\r\n */\r\nexport function closeServers() {\r\n // Check if there are servers working\r\n if (activeServers.size > 0) {\r\n log(4, `[server] Closing all servers.`);\r\n\r\n // Close each one of servers\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n }\r\n}\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @function getServers\r\n *\r\n * @returns {Array.} Servers associated with Express app instance.\r\n */\r\nexport function getServers() {\r\n return activeServers;\r\n}\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @function getExpress\r\n *\r\n * @returns {Express} The Express instance.\r\n */\r\nexport function getExpress() {\r\n return express;\r\n}\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @function getApp\r\n *\r\n * @returns {Express} The Express app instance.\r\n */\r\nexport function getApp() {\r\n return app;\r\n}\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @function enableRateLimiting\r\n *\r\n * @param {Object} rateLimitingOptions - Object containing `rateLimiting`\r\n * options.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n rateLimitingMiddleware(app, rateLimitingOptions);\r\n}\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @function use\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function use(path, ...middlewares) {\r\n app.use(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @function get\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function get(path, ...middlewares) {\r\n app.get(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @function post\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware function(s) to be applied.\r\n */\r\nexport function post(path, ...middlewares) {\r\n app.post(path, ...middlewares);\r\n}\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @function _attachServerErrorHandlers\r\n *\r\n * @param {(http.Server|https.Server)} server - The HTTP/HTTPS server instance.\r\n */\r\nfunction _attachServerErrorHandlers(server) {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n}\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n getExpress,\r\n getApp,\r\n enableRateLimiting,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Handles graceful shutdown of the Highcharts Export Server, ensuring\r\n * proper cleanup of resources such as browser, pages, servers, and timers.\r\n */\r\n\r\nimport { killPool } from './pool.js';\r\nimport { clearAllTimers } from './timer.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Cleans up function to trigger before ending process for the graceful\r\n * shutdown.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} exitCode - An exit code for the `process.exit()` function.\r\n */\r\nexport async function shutdownCleanUp(exitCode) {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllTimers(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close an active pool along with its workers and the browser instance\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n}\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2025, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Core module for initializing and managing the Highcharts Export\r\n * Server. Provides functionalities for configuring exports, setting up server\r\n * operations, logging, scripts caching, resource pooling, and graceful process\r\n * cleanup.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\nimport server, { startServer } from './server/server.js';\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * the cache and sources, and initializing the resource pool occur during this\r\n * stage. This function must be called before attempting to export charts or set\r\n * up a server.\r\n *\r\n * @async\r\n * @function initExport\r\n *\r\n * @param {Object} customOptions - The `customOptions` object, which may\r\n * be a partial or complete set of options. If the provided options are partial,\r\n * missing values will be merged with the default general options, retrieved\r\n * using the `getOptions` function.\r\n */\r\nexport async function initExport(customOptions) {\r\n // Get the global options object copy and extend it with the incoming options\r\n const options = mergeOptions(getOptions(false), customOptions);\r\n\r\n // Set the `allowCodeExecution` per export module scope\r\n setAllowCodeExecution(options.customLogic.allowCodeExecution);\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n _attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options.highcharts, options.server.proxy);\r\n\r\n // Init the pool\r\n await initPool(options.pool, options.puppeteer.args);\r\n}\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM'\r\n * and 'uncaughtException' events.\r\n *\r\n * @function _attachProcessExitListeners\r\n */\r\nfunction _attachProcessExitListeners() {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `[process] Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `[process] The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `[process] The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n}\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Options\r\n getOptions,\r\n setOptions,\r\n mergeOptions,\r\n mapToNewOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Cache\r\n checkAndUpdateCache,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n\r\n // Utils\r\n shutdownCleanUp\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","fixConstr","constr","fixedConstr","toLowerCase","replace","includes","fixOutfile","type","outfile","getAbsolutePath","split","shift","fixType","mimeTypes","formats","values","outType","pop","find","t","path","isAbsolute","join","getBase64","input","Buffer","from","toString","getNewDate","Date","trim","getNewDateTime","getTime","isObject","item","isObjectEmpty","keys","length","isPrivateRangeUrlFound","some","pattern","test","measureTime","start","process","hrtime","bigint","Number","roundNumber","value","precision","multiplier","Math","pow","round","wrapAround","customCode","allowFileResources","isCallback","endsWith","readFileSync","startsWith","colors","logging","toConsole","toFile","pathCreated","pathToLog","levelsDesc","title","color","log","args","newLevel","texts","level","prefix","_logToFile","console","apply","undefined","concat","logWithStack","error","customMessage","mainMessage","message","stackMessage","stack","push","logZodIssues","issues","map","issue","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","existsSync","mkdirSync","appendFile","defaultConfig","puppeteer","types","envLink","cliName","description","promptOptions","separator","highcharts","version","cdnUrl","forceFetch","cachePath","coreScripts","instructions","moduleScripts","indicatorScripts","customScripts","export","infile","instr","options","svg","batch","hint","choices","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","callback","resources","loadConfig","legacyName","createConfig","server","enable","host","port","uploadLimit","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","config","propChain","forEach","entry","substring","dotenv","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","nullable","string","refine","params","errorMessage","stringArray","filterCallback","arraySchema","array","stringSchema","slice","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","indexOf","object","passthrough","additionalOptions","adminToken","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","isInteger","logFile","logDest","logToConsole","logToFile","enableUi","uiRoute","enableDebug","requestId","uuid","PuppeteerSchema","HighchartsSchema","ExportSchema","CustomLogicSchema","ProxySchema","RateLimitingSchema","SslSchema","ServerSchema","optional","PoolSchema","LoggingSchema","UiSchema","OtherSchema","DebugSchema","StrictConfigSchema","LooseConfigSchema","EnvSchema","PUPPETEER_ARGS","HIGHCHARTS_VERSION","HIGHCHARTS_CDN_URL","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_CUSTOM_SCRIPTS","EXPORT_INFILE","EXPORT_INSTR","EXPORT_OPTIONS","EXPORT_SVG","EXPORT_BATCH","EXPORT_OUTFILE","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_B64","EXPORT_NO_DOWNLOAD","EXPORT_HEIGHT","EXPORT_WIDTH","EXPORT_SCALE","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_GLOBAL_OPTIONS","EXPORT_THEME_OPTIONS","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","CUSTOM_LOGIC_CUSTOM_CODE","CUSTOM_LOGIC_CALLBACK","CUSTOM_LOGIC_RESOURCES","CUSTOM_LOGIC_LOAD_CONFIG","CUSTOM_LOGIC_CREATE_CONFIG","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_UPLOAD_LIMIT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","validateOption","name","option","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","index","_initGlobalOptions","getOptions","getReference","setOptions","customOptions","cliArgs","modifyGlobal","cliOptions","_loadConfigFile","_pairArgumentValue","generalOptions","_updateOptions","mergeOptions","originalOptions","newOptions","entries","mapToNewOptions","oldOptions","propertiesChain","reduce","obj","prop","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","configOpt","customOpt","cliOpt","configVal","customVal","cliVal","envVal","stringifyFunctions","stringify","replaceAll","Error","configIndex","findIndex","arg","configFileName","i","async","fetch","requestOptions","Promise","resolve","reject","_getProtocolModule","get","response","responseData","on","chunk","text","https","http","ExportError","constructor","statusCode","super","setError","cache","activeManifest","sources","hcVersion","checkAndUpdateCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","modules","moduleMap","m","numberOfModules","moduleName","extractVersion","_saveConfigToManifest","getHighchartsVersion","updateHighchartsVersion","newVersion","cacheSources","extractModuleName","scriptPath","_fetchAndProcessScript","script","shouldThrowError","newManifest","writeFileSync","_fetchScripts","proxyAgent","HttpsProxyAgent","agent","allFetchPromises","all","c","setupHighcharts","Highcharts","animObject","duration","createChart","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","defaultOptions","template","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","setTimeout","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","document","body","innerHTML","id","workCount","addPageResources","customLogicOptions","injectedResources","injectedJs","content","isLocal","jsResource","addScriptTag","injectedCss","cssImports","match","cssImportPath","cssResource","addStyleTag","clearPageResources","resource","dispose","oldCharts","charts","oldChart","destroy","scriptsToRemove","getElementsByTagName","stylesToRemove","linksToRemove","element","remove","setContent","cssTemplate","svgTemplate","puppeteerExport","exportOptions","isSVG","_setAsSvg","_setAsOptions","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","style","zoom","margin","parseFloat","x","y","_getClipRegion","viewportHeight","abs","ceil","viewportWidth","result","setViewport","deviceScaleFactor","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","outerHTML","clip","race","screenshot","encoding","fullPage","optimizeForSpeed","captureBeyondViewport","quality","omitBackground","_resolve","emulateMediaType","pdf","poolStats","exportsAttempted","exportsPerformed","exportsDropped","exportsFromSvg","exportsFromOptions","exportsFromSvgAttempts","exportsFromOptionsAttempts","timeSpent","timeSpentAverage","initPool","poolOptions","Pool","_factory","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","clearStatus","_eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","getPoolInfo","acquireCounter","_requestId","workStart","exportCounter","exportTime","getPoolStats","getPoolInfoJSON","numUsed","available","numFree","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","numPendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","create","random","startDate","validate","mainFrame","detached","removeAllListeners","sanitize","JSDOM","DOMPurify","ADD_TAGS","singleExport","startExport","batchExport","batchFunctions","pair","batchResults","allSettled","reason","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_handleCustomLogic","_handleGlobalAndTheme","_findChartSize","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","allowedProps","handledResources","correctResources","propName","optionsName","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","msg","rateOptions","limiter","rateLimit","windowMs","delayMs","handler","format","send","default","skip","query","access_token","HttpError","setStatus","contentTypeMiddleware","contentType","headers","requestBodyMiddleware","connection","remoteAddress","validatedOptions","filename","validationMiddleware","post","reversedMime","png","jpeg","gif","requestExport","requestCounter","connectionAborted","socket","hadErrors","header","attachment","exportRoutes","serverStartTime","packageFile","successRates","recordInterval","windowSize","_calculateMovingAverage","a","b","_startSuccessRate","setInterval","stats","successRatio","healthRoutes","period","movingAverage","bootTime","uptime","floor","serverVersion","highchartsVersion","averageExportTime","attemptedExports","performedExports","failedExports","sucessRatio","toFixed","svgExports","jsonExports","svgExportsAttempts","jsonExportsAttempts","uiRoutes","sendFile","acceptRanges","versionChangeRoutes","token","activeServers","Map","express","startServer","serverOptions","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","disable","cors","methods","set","limit","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","readFile","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","_attachProcessExitListeners"],"mappings":"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AOP,GAAOpD,KAAK,KAAO,MAClC6D,IACKA,GAASpB,QAAQE,QAAUF,QAAQG,cACrCH,QAAQE,QAAS,EACjBF,QAAQG,aAAc,EACtBgB,aAAa,EAAGC,EAAO,yCACxB,GAGP,CC3PO,MAAMqB,cAAgB,CAC3BC,UAAW,CACTjC,KAAM,CACJvB,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFyD,MAAO,CAAC,YACRC,QAAS,iBACTC,QAAS,gBACTC,YAAa,+BACbC,cAAe,CACbvG,KAAM,OACNwG,UAAW,OAIjBC,WAAY,CACVC,QAAS,CACPhE,MAAO,SACPyD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,qBACbC,cAAe,CACbvG,KAAM,SAGV2G,OAAQ,CACNjE,MAAO,8BACPyD,MAAO,CAAC,UACRC,QAAS,qBACTE,YAAa,iCACbC,cAAe,CACbvG,KAAM,SAGV4G,WAAY,CACVlE,OAAO,EACPyD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbvG,KAAM,WAGV6G,UAAW,CACTnE,MAAO,SACPyD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbvG,KAAM,SAGV8G,YAAa,CACXpE,MAAO,CAAC,aAAc,kBAAmB,iBACzCyD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbvG,KAAM,cACN+G,aAAc,0DAGlBC,cAAe,CACbtE,MAAO,CACL,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,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"} \ No newline at end of file